File Coverage

lib/CXC/PDL/Bin1D.pd
Criterion Covered Total %
statement 20 20 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 27 27 100.0


line stmt bran cond sub pod time code
1             #!perl
2              
3             # --8<--8<--8<--8<--
4             #
5             # Copyright (C) 2014 Smithsonian Astrophysical Observatory
6             #
7             # This file is part of CXC::PDL::Bin1D
8             #
9             # CXC::PDL::Bin1D is free software: you can redistribute it and/or modify
10             # it under the terms of the GNU General Public License as published by
11             # the Free Software Foundation, either version 3 of the License, or
12             # (at your option) any later version.
13             #
14             # This program is distributed in the hope that it will be useful,
15             # but WITHOUT ANY WARRANTY; without even the implied warranty of
16             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17             # GNU General Public License for more details.
18             #
19             # You should have received a copy of the GNU General Public License
20             # along with this program. If not, see .
21             #
22             # -->8-->8-->8-->8--
23              
24             use v5.10;
25              
26             use strict;
27             use warnings;
28             use version;
29              
30             use IO::File;
31             use File::Spec::Functions qw[ catfile ];
32              
33             use lib 'lib';
34              
35             use CXC::PDL::Bin1D::Utils '_bitflags';
36             use PDL ();
37             use PDL::Bad;
38              
39             use File::Basename qw[ fileparse ];
40              
41             # this file is executed directly by Perl, so $0 will be our filename,
42             # which allows us to find the parent directory.
43             use constant LIBDIR => ( fileparse( $0 ) )[1];
44              
45             use PDL::Types qw[ typefld ];
46              
47              
48             # later versions of PDL define index types:
49             # 'PDL_Indx' (as a C typedef) and 'indx' for signatures
50             # for backwards compatibility, support long as well as the others
51              
52             my ( $IndexParsType, $IndexCType ) = do {
53              
54             my $type = eval { typefld( 'PDL_IND', 'ctype' ); 1 } ? 'PDL_IND' : 'PDL_L';
55              
56             map { typefld( $type, $_ ) } qw( ppforcetype ctype );
57             };
58              
59             our $VERSION = '0.28';
60             pp_setversion( $VERSION );
61              
62             {
63             package CXC::PDL::Bin1D;
64              
65             use Text::Template::LocalVars;
66             use File::Spec::Functions qw[ catfile ];
67              
68             use Exporter 'import';
69             ## no critic (Modules::ProhibitAutomaticExportation)
70             our @EXPORT = qw< fill_in fill_in_string >;
71              
72             # this code must be compiled in the template variable package
73             sub init_fill_package {
74              
75             Text::Template::LocalVars->new(
76             type => 'string',
77             delimiters => [qw( <% %> )],
78             source => <<'EOS',
79             *fill_in = \&<% $PACKAGE %>::fill_in;
80             *fill_in_string = \&<% $PACKAGE %>::fill_in_string;
81             EOS
82             )->fill_in( hash => { PACKAGE => __PACKAGE__ } );
83              
84             }
85              
86             # fill in templates using Text::Template::LocalVars. This routine
87             # is also imported into all of the template fragments.
88             sub fill_in {
89              
90             my ( $type, $src ) = ( shift, shift );
91              
92             $src = catfile( ::LIBDIR, $src )
93             if lc $type eq 'file' && $src !~ m{^[./]}s;
94              
95             my $tpl = Text::Template::LocalVars->new(
96             type => $type,
97             source => $src,
98             delimiters => [qw( <% %> )],
99             broken => sub { my %args = @_; die $args{error}; },
100             prepend => init_fill_package(),
101             );
102              
103             die $Text::Template::ERROR unless defined $tpl;
104              
105             # by default, localize the variable packages, and insert the last one
106             # in the call chain if not explicitly specified.
107             my %args = ( localize => 1, trackpkgvars => 1, @_ );
108              
109             my $hash = $args{hash} ||= {};
110             $hash->{PDL_Indx} = $IndexCType;
111              
112             my $txt;
113             eval {
114             $txt = $tpl->fill_in( %args );
115             die unless defined $txt;
116             1;
117             }
118             or die defined $Text::Template::LocalVars::ERROR
119             ? $Text::Template::LocalVars::ERROR
120             : $@;
121              
122             return $txt;
123             }
124              
125             sub fill_in_string {
126              
127             unshift @_, 'string';
128             goto \&fill_in;
129              
130             }
131              
132             }
133              
134             CXC::PDL::Bin1D->import;
135              
136              
137             my %CONSTANTS = (
138             BIN_ARG => {
139             _bitflags( qw[
140             BIN_ARG_HAVE_ERROR
141             BIN_ARG_HAVE_WEIGHT
142             BIN_ARG_SET_BAD
143             BIN_ARG_FOLD
144             BIN_ARG_HAVE_WIDTH
145             BIN_ARG_ERROR_SDEV
146             BIN_ARG_ERROR_POISSON
147             BIN_ARG_ERROR_RSS
148             BIN_ARG_HAVE_SIGNAL
149             BIN_ARG_SAVE_OOB_START_END
150             BIN_ARG_SAVE_OOB_START_NBINS
151             BIN_ARG_SAVE_OOB_END
152             BIN_ARG_SAVE_OOB_NBINS
153             BIN_ARG_WANT_EXTREMA
154             BIN_ARG_WANT_SUM_WEIGHT
155             BIN_ARG_WANT_SUM_WEIGHT2
156             ],
157             ),
158             },
159             BIN_RC => {
160             _bitflags( qw[
161             BIN_RC_OK
162             BIN_RC_GEWMAX
163             BIN_RC_GENMAX
164             BIN_RC_FOLDED
165             BIN_RC_GTMINSN
166             ],
167             ),
168              
169             },
170             );
171              
172             {
173             $CONSTANTS{BIN_ARG}{BIN_ARG_SAVE_OOB} = 0;
174             $CONSTANTS{BIN_ARG}{BIN_ARG_SAVE_OOB} |= $CONSTANTS{BIN_ARG}{$_}
175             for grep { /BIN_ARG_SAVE_OOB/ } keys %{ $CONSTANTS{BIN_ARG} };
176              
177             $CONSTANTS{BIN_ARG}{BIN_ARG_SHIFT_IMIN} = $CONSTANTS{BIN_ARG}{BIN_ARG_SAVE_OOB_START_END}
178             | $CONSTANTS{BIN_ARG}{BIN_ARG_SAVE_OOB_START_NBINS};
179             }
180              
181              
182             # convert hash into [key => value] tuples, sorted by group, then value in group
183             ## no critic (BuiltinFunctions::ProhibitComplexMappings)
184             my @CONSTANTS = map {
185             my $h = $_;
186             map { [ $_, $h->{$_} ] } sort { $h->{$a} <=> $h->{$b} } keys %$h;
187             } values %CONSTANTS;
188              
189             my @CONSTANT_NAMES = ( map { keys %$_ } values %CONSTANTS );
190             my @EXPORT_OK;
191              
192             sub slurp {
193             my $file = catfile( LIBDIR, shift );
194             local $/ = undef;
195             ( IO::File->new( $file, 'r' ) or die( "can't slurp $file" ) )->getline;
196             }
197              
198              
199             pp_core_importList( '()' );
200              
201             pp_bless( 'CXC::PDL::Bin1D' );
202              
203             pp_addpm( { At => 'Top' }, <<'EOD' );
204 4     4   84 use v5.10;
  4         40  
205 4     4   23 use strict;
  4         7  
  4         105  
206 4     4   16 use warnings;
  4         34  
  4         281  
207 4     4   2589 no namespace::clean;
  4         77437  
  4         47  
208 4     4   2618 use CXC::PDL::Bin1D::Utils;
  4         16  
  4         212  
209 4     4   33 use namespace::clean;
  4         7  
  4         54  
210              
211             EOD
212              
213             if ( version->parse( PDL->VERSION ) < version->parse( '2.030' ) ) {
214             pp_addpm( { At => 'Top' }, <<'EOD' );
215             our @EXPORT_OK;
216             our %EXPORT_TAGS;
217             EOD
218             }
219              
220             pp_addpm(
221             { At => 'Top' },
222             join( "\n", 'use constant {', ( map { "$_->[0] => $_->[1]," } @CONSTANTS ), '};', q{} ),
223 4         2985 );
224              
225             pp_addpm(
226             { At => 'Top' },
227             join( "\n", '=for Pod::Coverage', ( map { "$_->[0]" } @CONSTANTS ), q{}, '=cut', q{} ),
228             );
229              
230             pp_addpm( { At => 'Top' }, <<'EOD' );
231             my %MapErrorAlgo = (
232              
233             sdev => BIN_ARG_ERROR_SDEV,
234             rss => BIN_ARG_ERROR_RSS,
235             poisson => BIN_ARG_ERROR_POISSON,
236             );
237             EOD
238              
239             pp_addpm( { At => 'Top' }, <<'EOD' );
240             =for Pod::Coverage
241             set_boundscheck
242             set_debugging
243              
244             =for stopwords
245             merchantability
246 4     4   958  
  4         10  
247             =cut
248              
249             =head1 NAME
250              
251             CXC::PDL::Bin1D - one dimensional binning functions
252              
253             =head1 SYNOPSIS
254              
255             use PDL;
256             use CXC::PDL::Bin1D;
257              
258             =head1 DESCRIPTION
259              
260             One dimensional binning functions,
261              
262             =over
263              
264             =item *
265              
266             binning up to a given S/N
267              
268             =item *
269              
270             optimized one-pass robust statistics
271              
272             =back
273              
274             All functions are made available in the B namespace.
275              
276             =head1 SUBROUTINES
277              
278             =cut
279             EOD
280              
281             pp_addhdr(
282             join( "\n",
283             '#include ',
284             '#include ',
285             map { "#define $_->[0] $_->[1]" } @CONSTANTS )
286             . "\n",
287             );
288              
289              
290             push @EXPORT_OK, 'bin_adaptive_snr';
291             pp_def(
292             'bin_adaptive_snr',
293             Pars => join(
294             q{;},
295             'signal(n)', # piddle containing signal to bin
296             'error(n)', # error piddle if flags && HAVE_ERROR or HAVE_ERROR2
297             'width(n)', # optional width for each signal datum
298             "$IndexParsType [o] index(n)", # output index
299             "$IndexParsType [o] nbins()",
300             "$IndexParsType [o] nelem(n)",
301             'double [o] b_signal(n)',
302             'double [o] b_error(n)',
303             'double [o] b_mean(n)',
304             'double [o] b_snr(n)',
305             'double [o] b_width(nwidth)',
306             "$IndexParsType [o] ifirst(n)",
307             "$IndexParsType [o] ilast(n)",
308             'int [o] rc(n)',
309             'double [t] b_error2(nrss)',
310             'double [t] b_signal2(nsdev)',
311             'double [t] b_m2(nsdev)',
312             'double [t] b_weight(nweight)', # use only for SDEV (with or without errors) & RSS
313             'double [t] b_weight_sig(nwsdev)',
314             'double [t] b_weight_sig2(nwsdev)',
315             ),
316             RedoDimsCode => fill_in_string(
317             <<'EOS'
318             PDL_Indx n = $PDL(signal)->dims[0];
319             $SIZE(nrss) = $COMP(optflags) & BIN_ARG_ERROR_RSS ? n : 0 ;
320             $SIZE(nwidth) = $COMP(optflags) & BIN_ARG_HAVE_WIDTH ? n : 0 ;
321             $SIZE(nsdev) = $COMP(optflags) & BIN_ARG_ERROR_SDEV ? n : 0 ;
322             $SIZE(nwsdev) = $COMP(optflags) & (BIN_ARG_ERROR_SDEV | BIN_ARG_HAVE_ERROR )
323             == (BIN_ARG_ERROR_SDEV | BIN_ARG_HAVE_ERROR ) ? n : 0 ;
324             $SIZE(nweight) = $COMP(optflags) & (BIN_ARG_ERROR_SDEV | BIN_ARG_ERROR_RSS) ? n : 0 ;
325             EOS
326             ),
327             OtherPars => fill_in_string(
328             join(
329             q{;},
330             'unsigned long optflags'
331             , # can't call it flags; clashes with PDL internals
332             'double min_snr',
333             'PDL_Indx min_nelem',
334             'PDL_Indx max_nelem',
335             'double min_width',
336             'double max_width',
337             ),
338             ),
339             Code => fill_in(
340             file => 'bin_adaptive_snr.c',
341             package => 'bin_adaptive_snr',
342             ),
343             HandleBad => 1,
344             BadCode => fill_in(
345             file => 'bin_adaptive_snr.c',
346             package => 'bin_adaptive_snr_bad',
347             hash => { PDL_BAD_CODE => 1 },
348             ),
349             PMCode => slurp( 'bin_adaptive_snr.pl' ),
350             PMFunc => q{},
351             Doc => undef,
352             );
353              
354             push @EXPORT_OK, 'bin_on_index';
355             pp_def(
356             'bin_on_index',
357             Pars => join(
358             q{;},
359              
360             # inputs
361             'data(n)', # piddle containing data to bin
362             "$IndexParsType index(n)", # input index
363             'weight(n)', # populated if flags && HAVE_WEIGHT
364             "$IndexParsType imin(nt)", # minimum index value to consider
365             "$IndexParsType nbins(nt)", # number of bins
366              
367             # outputs
368             "$IndexParsType [o] b_count(nb)", # number of data values
369             'double [o] b_data(nb)', # sum of the data
370             'double [o] b_weight(nb)',
371             'double [o] b_weight2(nb)',
372             'double [o] b_mean(nb)',
373             'double [o] b_dmin(nb)',
374             'double [o] b_dmax(nb)',
375             'double [o] b_dev2(nb)',
376              
377             # temporaries
378             'double [t] b_data_error(nb)',
379             'double [t] b_weight_error(nb)',
380             'double [t] b_weight2_error(nb)',
381             ),
382             OtherPars => fill_in_string(
383             join(
384             q{;},
385             'unsigned long optflags', # can't call it flags; clashes with PDL internals
386             'PDL_Indx nbins_max', # maximum number of bins
387             ),
388             ),
389             RedoDimsCode =>
390             q/ $SIZE(nb) = $COMP(nbins_max) + ($COMP(optflags) & BIN_ARG_SAVE_OOB ? 2 : 0 ); /,
391             Code => fill_in(
392             file => 'bin_on_index.c',
393             package => 'bin_on_index',
394             ),
395             HandleBad => 1,
396             BadCode => fill_in(
397             file => 'bin_on_index.c',
398             package => 'bin_on_index_bad',
399             hash => { PDL_BAD_CODE => 1 },
400             ),
401             PMCode => slurp( 'bin_on_index.pl' ),
402             PMFunc => q{},
403             Doc => undef,
404             );
405              
406              
407              
408             pp_addpm( { At => 'Bot' }, <<'EOD' );
409              
410             =head1 BUGS AND LIMITATIONS
411              
412             No bugs have been reported.
413              
414             =head1 AUTHOR
415              
416             Diab Jerius, Edjerius@cpan.orgE
417              
418             =head1 COPYRIGHT AND LICENSE
419              
420             Copyright 2008 Smithsonian Astrophysical Observatory
421              
422             CXC::PDL::Bin1D is free software: you can redistribute it and/or modify
423             it under the terms of the GNU General Public License as published by
424             the Free Software Foundation, either version 3 of the License, or (at
425             your option) any later version.
426              
427             This program is distributed in the hope that it will be useful,
428             but without any warranty; without even the implied warranty of
429             merchantability or fitness for a particular purpose. See the
430             GNU General Public License for more details.
431              
432             You should have received a copy of the GNU General Public License
433             along with this program. If not, see L.
434              
435             =cut
436             EOD
437              
438              
439             pp_export_nothing();
440              
441             pp_addpm( { At => 'Top' },
442             qq[\$EXPORT_TAGS{constants} = [ qw(\n@{[ join "\n", @CONSTANT_NAMES ]}\n)];\n] );
443             pp_addpm( { At => 'Top' }, qq[\$EXPORT_TAGS{Func} = [ qw(\n@{[ join "\n", @EXPORT_OK ]}\n)];\n] );
444             pp_addpm( { At => 'Top' }, q[@EXPORT_OK = map { @{$_} } values %EXPORT_TAGS] . ";\n" );
445              
446             pp_done();
447              
448             1;