← Index
Performance Profile   « block view • line view • sub view »
For /wise/base/deliv/dev/bin/getfix
  Run on Thu May 20 15:30:03 2010
Reported on Thu May 20 16:25:31 2010

File/wise/base/deliv/dev/lib/perl/WISE/DB/FrameIndex.pm
Statements Executed2122
Total Time0.0138030000000001 seconds

Subroutines — ordered by exclusive time
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
1110.004690.27702WISE::DB::FrameIndex::_neighbor_hp
1110.004210.00421WISE::DB::FrameIndex::_optimize_in_clause
1110.001740.28391WISE::DB::FrameIndex::search
1110.000170.00017WISE::DB::FrameIndex::_prune_args
00000WISE::DB::FrameIndex::BEGIN
00000WISE::DB::FrameIndex::_check_action
00000WISE::DB::FrameIndex::_check_type
00000WISE::DB::FrameIndex::_utcs_params
00000WISE::DB::FrameIndex::add
00000WISE::DB::FrameIndex::add_frame
00000WISE::DB::FrameIndex::add_frameset
00000WISE::DB::FrameIndex::add_scan
00000WISE::DB::FrameIndex::copy
00000WISE::DB::FrameIndex::create
00000WISE::DB::FrameIndex::disconnect
00000WISE::DB::FrameIndex::frame
00000WISE::DB::FrameIndex::frameset
00000WISE::DB::FrameIndex::remove
00000WISE::DB::FrameIndex::remove_frame
00000WISE::DB::FrameIndex::remove_frameset
00000WISE::DB::FrameIndex::remove_scan
00000WISE::DB::FrameIndex::replace
00000WISE::DB::FrameIndex::scan
00000WISE::DB::FrameIndex::search_coord
00000WISE::DB::FrameIndex::search_utcs

LineStmts.Exclusive
Time
Avg.Code
1package WISE::DB::FrameIndex;
2# $Id: FrameIndex.pm 7412 2010-02-20 01:58:56Z heidi $
3
4100our ($VERSION,$ID);
5
6100$VERSION = 1.56;
711.0e-61.0e-6$ID = '$Id: FrameIndex.pm 7412 2010-02-20 01:58:56Z heidi $';
8
933.3e-51.1e-5use strict;
# spent 12µs making 1 call to strict::import
1033.4e-51.1e-5use Carp;
# spent 59µs making 1 call to Exporter::import
1136.9e-52.3e-5use base qw/DBIx::Class::Schema DBIx::Class::ResultSet/;
# spent 61.5ms making 1 call to base::import
12
13
14
15=head1 NAME
16
17WISE::DB::FrameIndex - Frame Index and Operations Database for WISE
18
19=head1 SYNOPSIS
20
21 use WISE::DB::FrameIndex;
22
23 my $db = WISE::DB::FrameIndex->create( dbname => "dbi:SQLite:mytestdb" );
24
25 $db->add( 'scan', { scan => '00123a',
26 delivery => '454545'} );
27
28 my $frameset = $db->find( { scan => '00123a',
29 frame => 30 } );
30
31 $frameset->update( { pipe_status => 9 } );
32
33=cut
34
35
3611.9e-51.9e-5__PACKAGE__->load_classes( { 'WISE::DB::FrameIndex' => [ qw/ Scan Frame HouseKeeping MissionPlan Tile / ] } );
# spent 73.7ms making 1 call to DBIx::Class::Schema::load_classes
37
3830.002070.00069use WISE::CHealPix;
# spent 40µs making 1 call to Exporter::import
39
40=head1 DESCRIPTION
41
42WISE::DB::FrameIndex provides basic create, add, remove, update functionality for the WISE operations
43database. Packages within the WISE::DB::FrameIndex namespace utilize L<DBIx::Class> to provide an
44object mapping to the backend relational database. The backend was prototyped with
45SQLite.
46
47=cut
48
49########################################################################################
50########################################################################################
51
52# utility methods for this class. not for outside use
53
54# TODO need something to check whether the passed in column args
55# match what we have in our schema. or, equivalently, an exception class for DBIx::Class
56# to use in such a case
57
58# get rid of everything in arguments hash that isn't a defined column in the schema
59# TODO, base this on the defined columns
60
# spent 174µs within WISE::DB::FrameIndex::_prune_args which was called # once (174µs+0) by WISE::DB::FrameIndex::search at line 483
sub _prune_args {
6131.3e-54.3e-6 my $self = shift;
62 my @prunes = qw / ra dec radius utcs_start utcs_stop utcs_span num_frames/ ;
63 foreach my $p (@prunes) {
64340.000144.1e-6 if( grep {/^$p$/} keys %{$_[0]} ) {
65 delete $_[0]->{$p};
66 }
67 }
68}
69
70########################################################################################
71########################################################################################
72
73=head1 METHODS
74
75=head2 Database Utility Routines
76
77=over 4
78
79=item create()
80
81
82my $db = WISE::DB::FrameIndex->create( dbname => 'dbi:SQLite:testdb');
83
84Takes a database name with included driver and engine specification expected by L<DBIx::Class>.
85Uses SQL::Abstract to deploy the schema defined by packages in WISE::DB::FrameIndex namespace. Also sets up
86the Healpix spatial tiling and initializes the tiling table with Healpix parameters.
87
88The tiling is currently hardcoded. In the future it will be configurable via arguments to create().
89
90=cut
91
92sub create {
93 my $class = shift;
94 my %args = @_;
95
96 # TODO: allow arguments to giving tiling
97
98 my $schema = WISE::DB::FrameIndex->connect($args{dbname});
99 if(defined $schema) {
100 $schema->deploy;
101 my $nside = WISE::CHealPix::side2nsides_deg((47/60) - 2*(4/60));
102 $schema->resultset('Tile')->create( { side => (47/60),
103 overlap => (4/60),
104 dist => (47/60) - 2*(4/60),
105 nside => $nside,
106 npix => WISE::CHealPix::nside2npix($nside), } );
107 } else {
108 carp __PACKAGE__." create: Couldn't connect to database (name=$args{dbname})\n";
109 }
110 return $schema;
111}
112
113=item copy()
114
115Stub only, not implemented
116
117=cut
118
119sub copy {
120 #my $db = shift; # this is DBIx::Class::Schema object
121 my $targetfile = shift;
122 #$new = $db->clone;
123 # TODO
124}
125
126=item replace()
127
128Stub only, not implemented
129
130=cut
131
132sub replace {
133
134}
135
136=item disconnect()
137
138$db->disconnect;
139
140Disconnect from the database. This is a convenience routine which generally should not be called,
141as the database will disconnect on object destruction (usually at scope exit). Note DBIx::Class will
142take care of rolling back transactions (as long as autocommit => 1).
143
144=back
145
146=cut
147
148sub disconnect {
149 my $db = shift;
150 $db->storage->disconnect;
151}
152
153
154########################################################################################
155########################################################################################
156
157# these subroutines implement a generic interface for adding and removing.
158# the specific routines ('add_frameset', 'remove_scan, etc) are defined below
159
16013.0e-63.0e-6my @types_ok = qw/ frame frameset scan /;
16112.0e-62.0e-6my @actions_ok = qw/ add remove search /;
162
163sub _check_type {
164 my ($self, $type) = @_;
165 return grep {/$type/} @types_ok;
166}
167
168sub _check_action {
169 my ($self, $action) = @_;
170 return grep {/$action/} @actions_ok;
171}
172
173=head2 Adding Data
174
175=over 4
176
177=item add()
178
179 $db->add( I<type>, { I<column values> } );
180
181 $db->add( 'scan', { scan => '00123c', delivery => '454545', num_frames => 30 } );
182 $db->add( 'frame', { scan => '00456d', delivery => '454545', frame => '098', band => 1,
183 l0_file => 'testframe', scan_end => 0, ra_raw => 15.0, dec_raw => 45.0,
184 utcs => 1, } );
185
186Valid types are I<frame>, I<frameset>, and I<scan>. When adding a scan, the num_frames
187parameter can be given to insert a non-standard size scan; by default, adding
188a scan means inserting 250 framesets.
189
190=back
191
192=cut
193
194sub add {
195 my ($self, $type, $args) = @_;
196 if($self->_check_type($type)) {
197 my $sub = "add_$type";
198 return $self->$sub(%$args);
199 } else {
200 carp "Unknown type $type\n";
201 }
202 return;
203}
204
205=head2 Removing Data
206
207=over 4
208
209=item remove()
210
211 $db->remove( I<type>, { I<column values> } );
212
213 $db->remove( 'scan', { scan => '00123c' } );
214 $db->remove( 'frameset', { scan => '00456d', frame => 99 } );
215 $db->remove( 'frame', { scan => '00456d', frame => 98, band => 1 } )
216
217Valid types are I<frame>, I<frameset>, and I<scan>.
218
219=back
220
221=cut
222
223sub remove {
224 my ($self, $type, $args) = @_;
225 if($self->_check_type($type)) {
226 my $sub = "remove_$type";
227 return $self->$sub(%$args);
228 } else {
229 carp "Unknown type $type\n";
230 }
231}
232
233=head2 Aliases for add() and remove()
234
235=over 4
236
237=item frame()
238
239 $db->frame( I<action>, { I<column values> } );
240
241 $db->frame( 'add', { scan => '00456d', delivery => '454545', frame => '098', band => 1,
242 l0_file => 'testframe', scan_end => 0, ra_raw => 15.0, dec_raw => 45.0,
243 utcs => 1, } );
244 $db->frame( 'remove', { frame => '00456d', frame => 98, band => 1 } );
245
246Valid actions are I<add> and I<remove>.
247
248=cut
249
250sub frame {
251 my ($self, $action, $args) = @_;
252 if($self->_check_action($action)) {
253 my $sub = $action.'_frame';
254 return $self->$sub(%$args);
255 } else {
256 carp "Unknown action $action";
257 }
258 return;
259}
260
261
262=item frameset()
263
264 $db->frameset( I<action>, { I<column values> } );
265
266 $db->frameset( 'add', { scan => '00456d', frame => 99 } );
267 $db->frameset( 'remove', { scan => '00456d', frame => 99 });
268
269Valid actions are I<add> and I<remove>.
270
271=cut
272
273sub frameset {
274 my ($self, $action, $args) = @_;
275 if($self->_check_action($action)) {
276 my $sub = $action.'_frameset';
277 return $self->$sub(%$args);
278 } else {
279 carp "Unknown action $action";
280 }
281 return;
282}
283
284=item scan()
285
286 $db->scan( I<action>, { I<column values> } );
287
288 $db->scan( 'add', { scan => '00123c', delivery => '454545', num_frames => 30 } );
289 $db->scan( 'remove', { scan => '00123c' } );
290
291Valid actions are I<add> and I<remove>.
292
293=back
294
295=cut
296
297
298sub scan {
299 my ($self, $action, $args) = @_;
300 if($self->_check_action($action)) {
301 my $sub = $action.'_scan';
302 return $self->$sub(%$args);
303 } else {
304 carp "Unknown action $action";
305 }
306 return;
307}
308
309
310########################################################################################
311########################################################################################
312
313# Specific add, remove implementations.
314
315sub add_frame {
316 my $self = shift;
317 my %args = @_;
318
319 my $hptile;
320 if(defined $args{ra_raw} && defined $args{dec_raw} && ! defined $args{hp_raw}) {
321 $args{hp_raw} = WISE::CHealPix::ang2pix_ring($self->resultset('Tile')->first->nside,
322 $args{ra_raw},
323 $args{dec_raw}
324 );
325 }
326 $self->resultset('Frame')->create( { %args } );
327
328}
329
330sub remove_frame {
331 my $self = shift;
332 my %args = @_;
333 my $fr = $self->resultset('Frame')->search( { %args } );
334 $fr->delete;
335}
336
337sub add_frameset {
338 my $self = shift;
339 my %args = @_;
340 # this could be more efficient using $schema->popluate('Frame', ...);
341 # even more so for the whole scan ...
342 if(defined $args{raw_raw} && defined $args{dec_raw} && ! defined $args{hp_raw}) {
343 $args{hp_raw} = WISE::CHealPix::ang2pix_ring($self->resultset('Tile')->first->nside,
344 $args{ra_raw},
345 $args{dec_raw}
346 );
347 }
348 foreach my $band ( qw/1 2 3 4/ ) {
349 $self->add_frame( %args, band => $band );
350 }
351}
352
353sub remove_frameset {
354 my $self = shift;
355 my %args = @_;
356 # don't run a cascaded delete
357 my $fs = $self->resultset('Frame')->search( {scan => $args{scan},
358 frame => $args{frame} } );
359 $fs->delete;
360}
361
362sub add_scan {
363 my $self = shift;
364 my %args = @_;
365 my $nframes = $args{num_frames} || 250;
366 delete $args{num_frames};
367
368 for my $framenum ( 1 .. $nframes ) {
369 $args{scan_end} = 1 if($framenum == $nframes);
370 $self->add_frameset ( %args, frame => $framenum );
371 }
372
373}
374
375sub remove_scan {
376 my $self = shift;
377 my %args = @_;
378 my $scan = $self->resultset('Frame')->search( { scan => $args{scan} } );
379 $scan->delete;
380}
381
382
383########################################################################################
384########################################################################################
385
386=head2 Searching and Updating
387
388$db->search( { I<column values> } );
389
390Most searching functionality is provided by L<DBIx::Class> resultsource objects. It's
391worth reading L<DBIx::Class::Manual::Intro> for an introduction to resultsources and
392resultsets. Generally speaking, a resultsource is a database table, with a bunch of
393added features that you've always wanted, like search. When you search on a resultsource,
394you get back a resultset (in scalar context) or a list of row objects.
395
396A few examples:
397
398=over 4
399
400 # This gives you a resultset
401 my $frameset = $db->search( {scan => '00123c', frame => 13 } );
402
403 # and this gives you an array of frames
404 my @frameset = $db->search( {scan => '00123c', frame => 13 } );
405
406 # If you wanted to update the pipeline status for these frames, you could
407 foreach my $frame (@frames) {
408 $frame->update( { pipe_status => $status++ } );
409 }
410
411 # but if you wanted to update them to the same status, it is more efficient to
412 $framset->update( { pipe_status => $stat } );
413
414=back
415
416The resultset has many useful function - see L<DBIx::Class::ResultSet> for
417more information. Row functionality is more limited and for the API user it
418mainly provides access and updates to individual frames.
419
420An example of more complicated search: find all the framesets within 1 degree of (15, 45)
421taken in the last 4 days that haven't been coadded:
422
423 my (@framesets) = $db->search( { ra => 15, dec => 45, coadd_status => 0,
424 utcs_start => $start, utcs_span => (4 * 24 * 3600) } );
425
426=over
427
428=item search_utcs()
429
430$db->search_utcs( { utcs_start => I<begin_time>, utcs_stop => I<end_time>, utcs_span => I<length> } );
431
432You may call the time search directly. You must provide enough parameters to fully specify where
433and how long in time to search. So it is enough to prove a start or stop time and a span, or a start
434and stop, but no span. If start and stop are both ommitted, the stop time is assumed to be
435current time. If stop and span are omitted, stop time is assumed to be current time.
436
437=item search_coord()
438
439$db->search_coord( { ra => I<ra>, dec => I<dec>, radius => I<radius> } );
440
441You may call the coordindate search directly. All units are degrees. The current coordinate search simply reaturns frames
442(or a resultset) within I<radius> of I<(ra,dec)>.
443
444=back
445
446=cut
447
448
# spent 284ms (1.74+282) within WISE::DB::FrameIndex::search which was called # once (1.74ms+282ms) at line 677 of /wise/base/deliv/dev/bin/getfix
sub search {
449127.6e-56.3e-6 my $self = shift;
450 my $cond = shift || {};
451 my $attr = shift;
452
453 # i have some code below to handle the "special" searches. right now, this means
454 # utcs time span searches, and ra/dec searches. this code shouldn't be here; i
455 # think the functionality needs to be pushed into the result source class, but
456 # am unsure how to implement that. also, the utcs search span can probably be
457 # done in the usual way, if the API users bother to structure the search args
458 # correctly. which brings up the larger problem of the search arguments, which do
459 # not currently match the resultsource search arguments.
460
461 # anyway, this works for non-fancy stuff at the moment.
462 my ($utcs, $coord);
463 foreach my $p (qw / ra dec radius/ ) {
46486.3e-57.9e-6 if( grep {/^$p$/ && defined $cond->{$p}} keys %$cond) {
465 $coord = 1; last;
466 }
467 }
468 foreach my $p (qw / utcs_start utcs_stop utcs_span / ) {
469186.2e-53.4e-6 if( grep {/^$p$/} keys %$cond) {
470 $utcs = 1; last;
471 }
472 }
473
47430.001580.00053 if( $coord ) {
475 my @tiles = $self->_neighbor_hp($cond->{ra}, $cond->{dec}, $cond->{radius});
# spent 277ms making 1 call to WISE::DB::FrameIndex::_neighbor_hp
476 my @query = _optimize_in_clause('hp_raw',\@tiles);
# spent 4.21ms making 1 call to WISE::DB::FrameIndex::_optimize_in_clause
477 %$cond = (%$cond, @query);
478 }
479 if( $utcs ) {
480 $cond->{utcs} = _utcs_params($cond->{utcs_start}, $cond->{utcs_stop}, $cond->{utcs_span});
481 }
482
483 $self->_prune_args( $cond );
# spent 174µs making 1 call to WISE::DB::FrameIndex::_prune_args
484
485 if( wantarray ) {
486 return $self->resultset('Frame')->search($cond, $attr);
487 }
488 my $rs = $self->resultset('Frame')->search($cond, $attr);
# spent 450µs making 1 call to DBIx::Class::Schema::resultset # spent 319µs making 1 call to DBIx::Class::ResultSet::search
489 #return bless $rs, __PACKAGE__;
490 return $rs; # !!! Experiment
491 #return $self->resultset('Frame')->search($cond, $attr);
492}
493
49430.000710.00024use vars qw/&find/;
# spent 34µs making 1 call to vars::import
495
496# find is an alias to search
49717.0e-67.0e-6*find = \&search;
498
499
# spent 277ms (4.69+272) within WISE::DB::FrameIndex::_neighbor_hp which was called # once (4.69ms+272ms) by WISE::DB::FrameIndex::search at line 475
sub _neighbor_hp {
500120.001068.8e-5 my ($self, $ras, $decs, $radius) = @_;
501 $radius = (10/3600) unless defined $radius;
502 my $nside= $self->resultset('Tile')->first->nside;
50312.2e-52.2e-5 my $side = WISE::CHealPix::c2cdist_deg($nside);
# spent 26µs making 1 call to WISE::CHealPix::c2cdist_deg
504 $radius += $side*sqrt(2)*1.01; # Account for pixel sie and some slop
505 my @ras = ref($ras) ? @$ras : $ras;
506 my @decs = ref($decs) ? @$decs : $decs;
507 my @pix;
508 my %seen1;
509 my %seen2;
510 for my $i (0..$#ras) {
51160.003630.00060 my ($ra,$dec) = ($ras[$i],$decs[$i]);
512 next if ! defined $ra || ! defined $dec;
513 #print "--- $i,$ra,$dec,$radius,$nside\n";
514 my $hpix = WISE::CHealPix::ang2pix_ring($nside, $ra, $dec);
# spent 40µs making 1 call to WISE::CHealPix::ang2pix_ring
515 next if $seen1{$hpix}++;
516 # this can't get you a stripe of constant ra or a strip of constant dec
517 # and this code doesn't check for those kind of requests
518 my @new = (grep {! $seen2{$_}++}
# spent 246ms making 1 call to WISE::CHealPix::pix_withinr_ring
519 WISE::CHealPix::pix_withinr_ring($nside, $hpix, $radius));
520 push @pix, @new;
521 #print "--- $hpix => @new\n";
522 }
523 return sort {$a<=>$b} @pix;
524}
525
526sub search_coord {
527 my $self = shift;
528 my %args = @_;
529 my @tiles = $self->_neighbor_hp($args{ra}, $args{dec}, $args{radius});
530 if(@tiles) {
531 $self->_prune_args( \%args );
532 my @query = _optimize_in_clause('hp_raw',\@tiles);
533 %args = (%args, @query);
534 if( wantarray ) {
535 return $self->resultset('Frame')->search( {%args}, );
536 }
537 my $rs = $self->resultset('Frame')->search( {%args}, );
538 #return bless $rs, __PACKAGE__;
539 return $rs;
540 #return $self->resultset('Frame')->search( {%args}, );
541 }
542 return;
543}
544
545sub _utcs_params {
546 my ($begin, $end, $span) = @_;
547 if($span && $begin && !$end) {
548 $end = $begin + $span;
549 } elsif($span && !$begin && $end) {
550 $begin = $end - $span;
551 } elsif($span && !$begin && !$end) {
552 $end = time();
553 $begin = $end - $span;
554 }
555 return { '<=' => $end,
556 '>=' => $begin, };
557}
558
559
# spent 4.21ms within WISE::DB::FrameIndex::_optimize_in_clause which was called # once (4.21ms+0) by WISE::DB::FrameIndex::search at line 476
sub _optimize_in_clause {
560 # Look for long sequential runs in the list and pull them out
561110.001200.00011 my $col = shift;
562 my $list = shift;
563 my @list = sort {$a <=> $b} @$list;
564 my @ranges; # Ranges, queried by 'between' clauses
565 my @new; # New list of discontinuous segments
566 my @run; # Runs as they build
567 for (@list) {
56819910.002981.5e-6 if(@run && $_ == $run[-1]+1) { # Continuous. Build run.
569 push @run, $_;
570 } else { # Discontinuity. End run (if any).
571 if(@run > 5) { # Long enough
572 push @ranges,{$col => {-between => [$run[0], $run[-1]]}};
573 } elsif(@run) { # Too short
574 push @new,@run;
575 }
576 @run = ($_);
577 }
578 }
579 if(@run > 5) {
580 push @ranges,{$col => {-between => [$run[0], $run[-1]]}};
581 } elsif(@run) {
582 push @new,@run;
583 }
584
585 my @query = ((@new ? ($col => {-in => \@new}) : ()),
586 (@ranges ? (-nest => [-or => \@ranges]) : ()));
587
588 if(@new && @ranges) {
589 @query = (-or => [@query]);
590 }
591
592 #use WISE;
593 #print Dumper \@list,\@query;
594
595 return @query;
596}
597
598sub search_utcs {
599 my $self = shift;
600 my %args = @_;
601 $args{utcs} = _utcs_params($args{utcs_start}, $args{utcs_stop}, $args{utcs_span});
602 $self->_prune_args( \%args );
603 if( wantarray ) {
604 return $self->resultset('Frame')->search( {%args} );
605 }
606 my $rs = $self->resultset('Frame')->search( {%args} );
607 #return bless $rs, __PACKAGE__;
608 return $rs;
609 #return $self->resultset('Frame')->search( { %args } );
610}
611
612
613#=head1 VERSIONING AND SCHEMA DEPLOYMENT
614
615#=head1 TESTING
616
617#=head1 DATABASE SIZE
618
619#=head1 PERFORMANCE AND THROUGHPUT
620
621#=cut
622
62311.7e-51.7e-51;