IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:41:49 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/tap_branches
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm

    r25793 r27838  
    1616                    locate_images
    1717                    resolve_project
     18                    getCamRunByCamID
    1819                    );
    1920our %EXPORT_TAGS = (standard => [@EXPORT_OK]);
    2021
     22
     23use PS::IPP::PStamp::RequestFile qw( :standard );
    2124
    2225use IPC::Cmd 0.36 qw( can_run run );
     
    2427use PS::IPP::Config qw( :standard );
    2528use Carp;
    26 
    27 ### my @images = locate_images($image_db, $req_type, $img_type, $id, $component,
    28 ###            $mjd_min, $mjd_max, $filter);
     29use DateTime;
     30use File::Temp qw(tempfile);
     31use File::Basename;
     32use POSIX;
     33
     34my $dvo_verbose = 0;
     35my $save_temps = 0;
     36
     37# caches of camProcessedExp objects.
     38# Key is $exp_id
     39my %camRunByExpIDCache;
     40# Key is $cam_id
     41my %camRunByCamIDCache;
     42
     43# cache of last project looked up
     44my $last_project = "";
     45
     46my ($regtool, $chiptool, $camtool, $warptool, $stacktool, $difftool);
     47my ($pstamptool, $dvoImagesAtCoords, $whichimage, $ppConfigDump);
    2948
    3049sub locate_images {
    3150    my $ipprc    = shift;   # required
    32     my $image_db = shift;   # required
     51    my $imagedb = shift;   # required
     52    my $rowList  = shift;   # required
    3353    my $req_type = shift;   # required
    3454    my $img_type = shift;   # required
     
    3656    my $tess_id  = shift;
    3757    my $component= shift;   # class_id or skycell_id
    38     my $inverse  = shift;
     58    my $option_mask  = shift;
    3959    my $need_magic = shift;
    40     my $x        = shift;
    41     my $y        = shift;
    4260    my $mjd_min  = shift;
    4361    my $mjd_max  = shift;
    4462    my $filter   = shift;
    45     my $label    = shift;
     63    my $data_group = shift;
    4664    my $verbose  = shift;
    4765
    48 
    4966    # we die in response to bad data in request files
    50     die "Unknown req_type: $req_type"
     67    # The caller is responsible for updating the database
     68    # pstampparse.pl error checks now so this shouldn't happen
     69    &my_die("Unknown req_type: $req_type", $PS_EXIT_PROG_ERROR)
    5170        if ($req_type ne "byid") and
    5271           ($req_type ne "byexp") and
     
    5574           ($req_type ne "byskycell");
    5675
     76
    5777    my $dateobs_begin;
    5878    my $dateobs_end;
     
    6282    if (!iszero($mjd_max)) {
    6383        $dateobs_end = mjd_to_dateobs($mjd_max);
     84    }
     85    if (isnull($tess_id)) {
     86        $tess_id = undef;
     87    }
     88    if (isnull($data_group)) {
     89        $data_group = undef;
     90    }
     91    if (isnull($filter)) {
     92        $filter = undef;
     93    }
     94
     95    if ($req_type eq "bycoord") {
     96        my $num_rows = scalar @$rowList;
     97        die "Unexpected number of rows found in rowList: $num_rows" if $num_rows != 1;
     98        my $row = $rowList->[0];
     99        my $x = $row->{CENTER_X};
     100        my $y = $row->{CENTER_Y};
     101        my $results = lookup_bycoord($ipprc, $rowList, $imagedb, $img_type, $tess_id, $component, $need_magic, $x, $y, $dateobs_begin, $dateobs_end, $filter, $data_group, $option_mask, $verbose);
     102        return $results;
    64103    }
    65104
     
    69108        # in one place
    70109        $req_type = "bydiff";
    71         my $results = lookup_diff($ipprc, $image_db, $id, $component, 1, $inverse, $img_type, $verbose);
     110        my $results = lookup_diff($ipprc, $rowList, $imagedb, $id, $component, 1, $option_mask, $img_type, $verbose);
    72111        return $results;
    73112    }
    74113
    75114    if ($req_type eq "bydiff") {
    76         my $results = lookup_diff($ipprc, $image_db, $id, $component, 0, $inverse, $img_type, $verbose);
     115        # for bydiff reuqests we go look up the diffRun to obtain exp_id, chip_id, warp_id, stack_id, or
     116        # the image from the diffRun
     117        my $results = lookup_diff($ipprc, $rowList, $imagedb, $id, $component, 0, $option_mask, $img_type, $verbose);
    77118        if (!$results) {
    78119            return undef;
     
    84125
    85126        my $image = $results->[0];
    86         if (($img_type eq "raw") or ($img_type eq "chip")) {
    87             $req_type = "byexp";
    88             $id = $image->{exp_name};
     127        if ($img_type eq "raw") {
     128            $req_type = "byid";
     129            $id = $image->{exp_id};
    89130            return undef if !$id;
    90             # fall through and lookup byexp
     131            # fall through and lookup byid
     132        } elsif ($img_type eq "chip") {
     133            $req_type = "byid";
     134            $id = $image->{chip_id};
     135            return undef if !$id;
     136            # fall through and lookup byid
    91137        } elsif ($img_type eq "warp") {
    92138            $req_type = "byid";
     
    101147            # fall though and lookup by stack_id
    102148        } else {
    103             # shouldn't I check this elsewhere?
     149            # This is checked this elsewhere?
    104150            print STDERR "Error: $img_type is an unknown image type\n";
    105             return undef;
    106         }
    107 
    108     } elsif ($req_type eq "bycoord") {
    109 
    110         if ($img_type eq "stack") {
    111             print STDERR "Error bycoord lookup not implemented for stage stack yet\n";
    112151            return undef;
    113152        }
     
    123162    }
    124163
    125     my $results = lookup($ipprc, $image_db, $req_type, $img_type, $id, $tess_id, $component, $need_magic, $x, $y, $dateobs_begin, $dateobs_end, $filter, $label, $verbose);
     164    my $results = lookup($ipprc, $rowList, $imagedb, $req_type, $img_type, $id, $tess_id, $component,
     165        $need_magic, $dateobs_begin, $dateobs_end, $filter, $data_group, $option_mask, $verbose);
    126166
    127167    return $results;
    128168}
     169
     170# The subroutine lookup handles byexp, byid, and byskycell lookups including lookups that are
     171# triggered by a bydiff request
    129172
    130173sub lookup
    131174{
    132175    my $ipprc    = shift;
    133     my $image_db = shift;
     176    my $rowList    = shift;
     177    my $imagedb = shift;
    134178    my $req_type = shift;
    135     my $img_type = shift;
     179    my $stage = shift;
    136180    my $id       = shift;
    137181    my $tess_id  = shift;
    138182    my $component= shift;
    139183    my $need_magic = shift;
    140     my $x        = shift;
    141     my $y        = shift;
    142184    my $dateobs_begin = shift;
    143185    my $dateobs_end   = shift;
    144186    my $filter = shift;
    145     my $label = shift;
     187    my $data_group = shift;
     188    my $option_mask = shift;
    146189    my $verbose  = shift;
    147190
    148     my $missing_tools;
    149     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    150     my $chiptool = can_run('chiptool') or (warn "Can't find chiptool" and $missing_tools = 1);
    151     my $warptool = can_run('warptool') or (warn "Can't find warptool" and $missing_tools = 1);
    152     my $difftool = can_run('difftool') or (warn "Can't find difftool" and $missing_tools = 1);
    153     my $stacktool = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
    154     if ($missing_tools) {
    155         warn("Can't find required tools.");
    156         exit ($PS_EXIT_CONFIG_ERROR);
    157     }
     191    my $inverse = $option_mask & $PSTAMP_SELECT_INVERSE;
     192    my $unconvolved = $option_mask & $PSTAMP_SELECT_UNCONV;
     193    my $use_imfile_id = ($req_type eq "byid") && ($option_mask & $PSTAMP_USE_IMFILE_ID);
     194
    158195    my $command;
    159196    my $id_opt;     # option for the lookup
     
    161198    my $mask_name;
    162199    my $weight_name;
     200    my $cmf_name;
     201    my $psf_name;
     202    my $backmdl_name;
    163203    my $base_name;
    164204    my $want_astrom;
     
    171211    }
    172212
     213    # note $magic_arg may be cleared below depending on $req_type
    173214    my $magic_arg = $need_magic ? " -destreaked" : "";
     215
     216    # all rows have the same center type
     217    my $skycenter = ! ($rowList->[0]->{COORD_MASK} & $PSTAMP_CENTER_IN_PIXELS);
     218
    174219    my $component_args;
    175     if ($img_type eq "raw") {
     220    my $choose_components = 0;
     221    if ($stage eq "raw") {
    176222        $class_id = $component;
    177         $command = "$regtool -processedimfile -dbname $image_db";
     223        $command = "$regtool -processedimfile -dbname $imagedb";
    178224        # XXX: for now restrict lookups to type object
    179225        # are stamps of detrend exposures interesting?
    180226        $command .= " -exp_type object";
    181         $id_opt = "-exp_id";
     227        $id_opt = $use_imfile_id ? "-raw_imfile_id" : "-exp_id";
    182228        $component_args = " -class_id $class_id" if $component;
    183229        $want_astrom = 1;
    184230        $set_class_id = 1;
    185     } elsif ($img_type eq "chip") {
     231    } elsif ($stage eq "chip") {
    186232        $class_id = $component;
    187         $command = "$chiptool -processedimfile -dbname $image_db";
    188         $component_args = " -class_id $class_id" if $class_id;
    189         $id_opt = "-chip_id";
     233        # if the request is such that it will yield a single image per "run" or the
     234        # center is specified in pixel coordinates
     235        # use chiptool -processsedimfile. Otherwise use chiptool -listrun and then
     236        # choose the chips containing the center pixel by calling selectComponets() below
     237        if ($class_id or $use_imfile_id or !$skycenter) {
     238            $command = "$chiptool -processedimfile -dbname $imagedb";
     239            $component_args = " -class_id $class_id" if $class_id;
     240        } else {
     241            $command = "$chiptool -listrun -pstamp_order -dbname $imagedb";
     242            $choose_components = 1;
     243        }
     244        $id_opt = $use_imfile_id ? "-chip_imfile_id" : "-chip_id";
     245        # XXX: perhaps we should stop resolving images to this level here and do it at job run time.
     246        # With the mdc file it has all of the information that it needs.
    190247        $image_name   = "PPIMAGE.CHIP";
    191248        $mask_name    = "PPIMAGE.CHIP.MASK";
    192249        $weight_name  = "PPIMAGE.CHIP.VARIANCE";
     250        $cmf_name     = "PSPHOT.OUTPUT";
     251        $psf_name     = "PSPHOT.PSF.SAVE";
     252        $backmdl_name = "PSPHOT.BACKMDL";
    193253        $base_name    = "path_base"; # name of the field for the chiptool output
    194254        $want_astrom  = 1;
    195255        $set_class_id = 1;
    196     } elsif ($img_type eq "warp") {
     256    } elsif ($stage eq "warp") {
    197257        $skycell_id = $component;
    198         $command = "$warptool -warped -dbname $image_db";
    199         $component_args = " -skycell_id $skycell_id" if $skycell_id;
    200         $id_opt = "-warp_id";
     258        if ($skycell_id or $use_imfile_id or !$skycenter) {
     259            $command = "$warptool -warped -dbname $imagedb";
     260            $component_args = " -skycell_id $skycell_id" if $skycell_id;
     261        } else {
     262            $command = "$warptool -listrun -pstamp_order -dbname $imagedb";
     263            $choose_components = 1;
     264        }
     265        $id_opt = $use_imfile_id ? "-warp_skyfile_id" : "-warp_id";
    201266        $image_name   = "PSWARP.OUTPUT";
    202267        $mask_name    = "PSWARP.OUTPUT.MASK";
    203268        $weight_name  = "PSWARP.OUTPUT.VARIANCE";
     269        $cmf_name     = "PSWARP.OUTPUT.SOURCES";
     270        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    204271        $base_name    = "path_base"; # name of the field for the warptool output
    205     } elsif ($img_type eq "diff") {
     272    } elsif ($stage eq "diff") {
    206273        $skycell_id = $component;
    207         $command = "$difftool -diffskyfile -dbname $image_db";
    208         $component_args = " -skycell_id $skycell_id" if $skycell_id;
    209         $id_opt = "-diff_id";
     274        if ($skycell_id or $use_imfile_id or !$skycenter) {
     275            $command = "$difftool -diffskyfile -dbname $imagedb";
     276            $component_args = " -skycell_id $skycell_id" if $skycell_id;
     277        } else {
     278            $command = "$difftool -listrun -pstamp_order -dbname $imagedb";
     279            $choose_components = 1;
     280        }
     281        $id_opt = $use_imfile_id ? "-diff_skyfile_id" : "-diff_id";
    210282        $image_name  = "PPSUB.OUTPUT";
    211283        $mask_name   = "PPSUB.OUTPUT.MASK";
    212284        $weight_name = "PPSUB.OUTPUT.VARIANCE";
     285        $cmf_name    = "PPSUB.OUTPUT.SOURCES";
     286        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    213287        $base_name   = "path_base";
    214     } elsif ($img_type eq "stack") {
     288    } elsif ($stage eq "stack") {
    215289        $skycell_id = $component;
    216         $command = "$stacktool -sumskyfile -dbname $image_db";
     290        $command = "$stacktool -sumskyfile -dbname $imagedb";
    217291        $id_opt = "-stack_id";
    218292        $component_args = " -skycell_id $skycell_id" if $skycell_id;
    219293
    220         $image_name  = "PPSTACK.OUTPUT";
    221         $mask_name   = "PPSTACK.OUTPUT.MASK";
    222         $weight_name = "PPSTACK.OUTPUT.VARIANCE";
     294        if (!$unconvolved) {
     295            $image_name  = "PPSTACK.OUTPUT";
     296            $mask_name   = "PPSTACK.OUTPUT.MASK";
     297            $weight_name = "PPSTACK.OUTPUT.VARIANCE";
     298        } else {
     299            $image_name  = "PPSTACK.UNCONV";
     300            $mask_name   = "PPSTACK.UNCONV.MASK";
     301            $weight_name = "PPSTACK.UNCONV.VARIANCE";
     302        }
     303        # this is wrong but gets the right answer. Need to figure out how to find the
     304        # rule properly
     305        #$cmf_name    = "PSPHOT.OUTPUT";    # this puts .fpa. in the name
     306        $cmf_name     = "PSWARP.OUTPUT.SOURCES";
     307        $psf_name    = "PPSTACK.TARGET.PSF";
    223308        $base_name   = "path_base";
    224309    } else {
    225         die "Unknown img_type supplied: $img_type";
    226     }
    227 
     310        die "Unknown IMG_TYPe supplied: $stage";
     311    }
     312
     313    my $filter_runs = 0;
    228314    if ($req_type eq "byid") {
    229315        $command .= " $id_opt $id";
    230316        $command .= $component_args if $component_args;
     317        # don't include -destreaked if lookup is byid. Let pstampparse check so that the
     318        # error code returned to the client for a given component is 'not destreaked'
     319        # instead of 'not found'
     320        $magic_arg = "";
    231321    } elsif ($req_type eq "byexp") {
    232322        $command .= " -exp_name $id";
    233323        $command .= $component_args if $component_args;
     324        # don't include -destreaked if lookup is byexp. Let pstampparse check so that the error code gives
     325        # the reason as 'not destreaked'
     326        $magic_arg = "";
     327        # remove duplicate runs for the same exposure.
     328        $filter_runs = 1;
    234329    } elsif ($req_type eq "byskycell") {
    235330        die "tess_id and component are required for byskycell" if !$tess_id or ! $skycell_id;
    236331        $command .= " -tess_id $tess_id -skycell_id $skycell_id";
    237     } elsif ($req_type eq "bycoord") {
    238         $command .= " -radius 3.0 -ra $x -decl $y";
    239332    } else {
    240         die "Unknown req_type supplied: $req_type";
    241     }
    242 
    243     if ($img_type ne "stack") {
     333        # this should be caught by caller
     334        &my_die("Unexpected req_type supplied: $req_type", $PS_EXIT_PROG_ERROR);
     335    }
     336
     337    if ($stage ne "stack") {
    244338        $command .= $magic_arg;
    245339        $command .= " -dateobs_begin $dateobs_begin" if $dateobs_begin;
     
    248342
    249343    $command .= " -filter $filter" if !isnull($filter);
    250     $command .= " -label $label" if !isnull($label);
    251 
    252     # run the tool and parse the output
    253     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    254                 run(command => $command, verbose => $verbose);
    255     unless ($success) {
    256         # not sure if we should die here
    257         print STDERR @$stderr_buf;
     344    $command .= " -data_group $data_group" if !isnull($data_group);
     345
     346    my $images = runToolAndParse($command, $verbose);
     347
     348    if (!$images or scalar @$images == 0) {
    258349        return undef;
    259350    }
    260351
    261     my $buf = join "", @$stdout_buf;
    262     if (!$buf) {
    263         return;
    264     }
    265 
    266     my $mdcParser = PS::IPP::Metadata::Config->new;
    267     my $images = parse_md_fast($mdcParser, $buf)
    268         or die ("Unable to parse metadata config doc");
    269 
     352    if ($filter_runs) {
     353        # The image selectors are such that multiple runs my have be returned for the same exposure.
     354        # Return only the latest one.
     355        $images = filterRuns($stage, $need_magic, $images, $verbose);
     356    }
     357    if ($choose_components) {
     358        # the list of "images" is actually a list of "Runs"
     359        # match the coords in the rows to the components in the runs
     360        # returns an actual list of images
     361        $images = selectComponents($ipprc, $imagedb, $req_type, $stage, $rowList, $images, $verbose);
     362    } else {
     363        # put each of the rows into all of the the images
     364        setRowRefs($rowList, $images);
     365    }
     366
     367    my $camera;
    270368    my $output = [];
    271 
    272     my $camera;
    273369    foreach my $image (@$images) {
    274370        my $base;
    275371
    276372        next if $image->{fault};
    277         next if ($img_type ne "raw") and $image->{quality};
     373        next if ($stage ne "raw") and $image->{quality};
    278374
    279375        if ($base_name) {
     
    299395        # (we do this here for raw stage)
    300396        $out->{image}  = $image->{uri};
     397
    301398        if ($set_class_id) {
    302399            $class_id = $image->{class_id};
    303400            $out->{component} = $class_id;
     401        } else {
     402            $out->{component} = $image->{skycell_id};
    304403        }
    305404        my $stage_id;
    306         if ($img_type eq "raw") {
     405        if ($stage eq "raw") {
    307406            $stage_id = $image->{exp_id};
    308         } elsif ($img_type eq "chip") {
    309             $stage_id = $image->{chip};
    310         } elsif ($img_type eq "warp") {
     407        } elsif ($stage eq "chip") {
     408            $stage_id = $image->{chip_id};
     409        } elsif ($stage eq "warp") {
    311410            $stage_id = $image->{warp_id};
    312         } elsif ($img_type eq "diff") {
     411        } elsif ($stage eq "diff") {
    313412            $stage_id = $image->{diff_id};
    314         } elsif ($img_type eq "stack") {
     413            if ($inverse && $image->{bothways}) {
     414                $image_name  = "PPSUB.INVERSE";
     415                $mask_name   = "PPSUB.INVERSE.MASK";
     416                $weight_name = "PPSUB.INVERSE.VARIANCE";
     417                $cmf_name    = "PPSUB.INVERSE.SOURCES";
     418            }
     419        } elsif ($stage eq "stack") {
    315420            $stage_id = $image->{stack_id};
    316421        }
    317         $image->{stage_id} = $stage_id;
    318         $image->{stage}    = $img_type;
    319         $image->{image_db} = $image_db;
    320 
    321         # find the mask and weight images
     422        $out->{stage_id} = $stage_id;
     423        $out->{stage}    = $stage;
     424        $out->{imagedb} = $imagedb;
     425
    322426        if ($base) {
    323427            $out->{image}  = $ipprc->filename($image_name,  $base, $class_id) if $image_name;
    324428            $out->{mask}   = $ipprc->filename($mask_name,   $base, $class_id) if $mask_name;
    325429            $out->{weight} = $ipprc->filename($weight_name, $base, $class_id) if $weight_name;
    326         }
    327         $out->{astrom} = find_astrometry($ipprc, $image_db, $image, $verbose) if $want_astrom;
     430            $out->{cmf}    = $ipprc->filename($cmf_name, $base, $class_id) if $cmf_name;
     431            $out->{psf}    = $ipprc->filename($psf_name, $base, $class_id) if $psf_name;
     432            $out->{backmdl}= $ipprc->filename($backmdl_name, $base, $class_id) if $backmdl_name;
     433        }
     434        if ($want_astrom and ! defined $out->{astrom}) {
     435            $out->{astrom} = find_astrometry($ipprc, $imagedb, $image, $verbose);
     436        }
    328437
    329438        push @$output, $out;
     
    332441    return $output;
    333442}
     443
    334444sub lookup_diff {
    335445    my $ipprc    = shift;
    336     my $image_db = shift;
     446    my $rowList  = shift;
     447    my $imagedb = shift;
    337448    my $id       = shift;
    338449    my $skycell_id = shift;
    339450    my $byid     = shift;
    340     my $inverse  = shift;
     451    my $option_mask  = shift;
    341452    my $img_type = shift;
    342453    my $verbose = shift;
    343454
    344     my $missing_tools;
    345     my $difftool = can_run('difftool') or (warn "Can't find difftool" and $missing_tools = 1);
    346     if ($missing_tools) {
    347         warn("Can't find required tools.");
    348         exit ($PS_EXIT_CONFIG_ERROR);
    349     }
    350 
    351     my $command = "$difftool -diffskyfile -dbname $image_db";
     455    my $inverse = $option_mask & $PSTAMP_SELECT_INVERSE;
     456
     457    my $command = "$difftool -dbname $imagedb";
    352458   
    353459    if ($byid) {
    354         $command .= " -diff_id $id";
     460        $command .= " -listrun -diff_id $id";
    355461    } else {
    356         $command .= " -diff_skyfile_id $id";
     462        $command .= " -diffskyfile -diff_skyfile_id $id";
    357463    }
    358464    $command .= " -skycell_id $skycell_id" if $skycell_id;
    359465
    360     # run the tool and parse the output
    361     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    362                 run(command => $command, verbose => $verbose);
    363     unless ($success) {
    364         # not sure if we should die here
    365         print STDERR @$stderr_buf;
    366         return undef;
    367     }
    368 
    369     my $buf = join "", @$stdout_buf;
    370     if (!$buf) {
    371         return undef;
    372     }
    373 
    374     my $mdcParser = PS::IPP::Metadata::Config->new;
    375     my $images = parse_md_fast($mdcParser, $buf)
    376         or die ("Unable to parse metadata config doc");
    377 
    378     my $n = @$images;
     466    my $output = runToolAndParse($command, $verbose);
     467
     468    my $n = @$output;
    379469    if (!$byid && ($n > 1)) {
    380470        die ("difftool returned an unexpected number of diffskyfiles: $n");
     
    383473    }
    384474
     475    my $images;
     476    if ($byid) {
     477        $images = selectComponents($ipprc, $imagedb, 'byid', 'diff', $rowList, $output, $verbose);
     478    } else {
     479        $images = $output;
     480    }
     481
    385482    my @results;
    386483    foreach my $image (@$images) {
     
    395492        # so we interpret the requested image in that way
    396493
    397         my $stack_id = $image->{stack2};
    398494        # XXX difftool currently returns max long long for null
    399         # this line is ready if we switch the code to return zero for null
    400         if ($stack_id and ($stack_id != 9223372036854775807)) {
     495        # these checks are ready if we switch the code to return zero for null
     496        my $stack1 = $image->{stack1};
     497        if (($stack1 == 0) or ($stack1 == 9223372036854775807)) {
     498            $stack1 = undef
     499        }
     500        my $stack2 = $image->{stack2};
     501        if (($stack2 == 0) or ($stack2 == 9223372036854775807)) {
     502            $stack2 = undef
     503        }
     504        my $stack_id;
     505        if ($stack1 and $stack2) {
     506            # we have a stack - stack diff (well it might be stack - warp....)
     507            # but at any rate we only handle image type diff and stack
     508            if (($img_type ne "diff") and ($img_type ne "stack")) {
     509                print STDERR "lookup_diff: cannot lookup IMG_TYPE $img_type bydiff from a stack stack diff run\n";
     510                next;
     511            }
     512            # stack-stack diff
     513            # XXX: define another flag for this
     514            if (! $inverse) {
     515                $stack_id = $stack1;
     516            } else {
     517                $stack_id = $stack2;
     518            }
    401519            $image->{stack_id} = $stack_id;
    402         }
    403 
    404         my ($warp_id, $exp_id, $exp_name);
    405         if ($inverse and !$image->{bothways}) {
    406             print STDERR "Inverse images requested for diffRun that is not bothways. Ignoring.\n";
    407             $inverse = 0;
    408         }
    409         if ($inverse) {
    410             $warp_id =  $image->{warp2};
    411             $exp_id = $image->{exp_id_2};
    412             $exp_name = $image->{exp_name_2};
    413520        } else {
    414             $warp_id =  $image->{warp1};
    415             $exp_id = $image->{exp_id_1};
    416             $exp_name = $image->{exp_name_1};
    417         }
    418         # XXX difftool currently returns max long long for null
    419         # this line is ready if we switch the code to return zero for null
    420         if ($warp_id and ($warp_id != 9223372036854775807)) {
    421             $image->{warp_id} = $warp_id;
    422             $image->{exp_id} = $exp_id;
    423             $image->{exp_name} = $exp_name;
    424         } else {
    425             print STDERR "unexpected result warp_id not defined\n";
    426             next;
    427         }
     521            my ($warp_id, $exp_id, $exp_name, $chip_id, $cam_id);
     522            if ($inverse and !$image->{bothways}) {
     523                print STDERR "Inverse images requested for diffRun that is not bothways. Ignoring inverse.\n";
     524                $inverse = 0;
     525            }
     526            if ($inverse) {
     527                $warp_id =  $image->{warp2};
     528                $exp_id = $image->{exp_id_2};
     529                $exp_name = $image->{exp_name_2};
     530                $chip_id = $image->{chip_id_2};
     531                $cam_id = $image->{cam_id_2};
     532            } else {
     533                $warp_id =  $image->{warp1};
     534                $exp_id = $image->{exp_id_1};
     535                $exp_name = $image->{exp_name_1};
     536                $chip_id = $image->{chip_id_1};
     537                $cam_id = $image->{cam_id_1};
     538            }
     539            # XXX difftool currently returns max long long for null
     540            # this line is ready if we switch the code to return zero for null
     541            if ($warp_id and ($warp_id != 9223372036854775807)) {
     542                $image->{warp_id} = $warp_id;
     543                $image->{exp_id} = $exp_id;
     544                $image->{exp_name} = $exp_name;
     545                $image->{chip_id} = $chip_id;
     546                $image->{cam_id} = $cam_id;
     547            }
     548        }
     549
     550        # XXX: If difftool doesn't return a camera insert it here
     551        if (!$image->{camera}) {
     552            $image->{camera} = "GPC1";
     553            # lie about the magicked status since stack stack diffs don't require destreaking
     554            # we can remove this once diff_mode gets included
     555            $image->{magicked} = 42;
     556        }
     557
    428558        if ($img_type eq "diff") {
     559            my @imageList = ($image);
     560
     561            setRowRefs($rowList, \@imageList);
    429562            # the $image is going to be returned directly in this case so we need to duplicate
    430563            # some of processing that lookup does for other img_types
     
    435568                $image->{mask}   = $ipprc->filename($filerule_base . ".MASK", $image->{path_base});
    436569                $image->{weight} = $ipprc->filename($filerule_base . ".VARIANCE", $image->{path_base});
     570                $image->{cmf}    = $ipprc->filename($filerule_base . ".SOURCES", $image->{path_base});
     571                $image->{psf}    = $ipprc->filename("PSPHOT.PSF.SKY.SAVE", $image->{path_base});
     572                $image->{stage_id} = $image->{diff_id};
     573                $image->{stage}    = "diff";
     574                $image->{imagedb} = $imagedb;
     575                $image->{component} = $image->{skycell_id};
    437576            } else {
    438                 # XXX this will only happen if the minuend is not a warp
    439                 print STDERR "WARNING: cannot resolve camera so cannot get weight and mask images\n";
     577                # XXX this will only happen if the minuend is not a warp. See hack above
     578                print STDERR "WARNING: cannot resolve camera so cannot get resolve file rules\n";
    440579                next;
    441580            }
     
    447586
    448587sub lookup_bycoord {
    449     my $ipprc    = shift;
    450     my $image_db = shift;
    451     my $x        = shift;
    452     my $y        = shift;
     588    my $ipprc      = shift;
     589    my $rowList    = shift;
     590    my $imagedb    = shift;
     591    my $img_type   = shift;
     592    my $tess_id    = shift;
     593    my $component  = shift;
     594    my $need_magic = shift;
     595    my $ra         = shift;
     596    my $dec        = shift;
    453597    my $dateobs_begin  = shift;
    454     my $dateobs_end  = shift;
    455     my $filter   = shift;
    456     my $verbose  = shift;
    457 
    458     my $missing_tools;
    459     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    460     if ($missing_tools) {
    461         warn("Can't find required tools.");
    462         exit ($PS_EXIT_CONFIG_ERROR);
    463     }
    464 
    465     # XXX TODO:
    466     # Full lookups by coordinate require looking at the DVO database. However,
    467     # dateobs and filter which is all that MOPS has asked for.
    468 
    469     my $args;
    470     if (!isnull($dateobs_begin)) {
    471         $args .= " -dateobs_begin $dateobs_begin";
    472     }
    473     if (!isnull($dateobs_end)) {
    474         $args .= " -dateobs_end $dateobs_end";
    475     }
    476     if (!isnull($filter)) {
    477         $args .= " -filter $filter";
    478     }
    479 
    480     if (!$args) {
    481         # avoid returning every exposure in the DB
    482         print STDERR "no query arguments provided for bycoord\n";
     598    my $dateobs_end    = shift;
     599    my $filter     = shift;
     600    my $data_group = shift;
     601    my $option_mask = shift;
     602    my $verbose    = shift;
     603
     604    my $results = ();
     605    if (($img_type eq "raw") or ($img_type eq "chip")) {
     606
     607        my $runs = lookup_runs_by_cam_id_and_coords($ipprc, $imagedb, $img_type,
     608            $ra, $dec, $need_magic, $dateobs_begin, $dateobs_end, $filter, $data_group, $verbose);
     609
     610        # lookup is going to filter these we don't need to do it here
     611#        $runs = filterRuns($img_type, $need_magic, $runs, $verbose);
     612        foreach my $run (@$runs) {
     613            next if $component and ($run->{component} ne $component);
     614            my $these_results = lookup($ipprc, $rowList, $imagedb, "byid", $img_type, $run->{id},
     615                $tess_id, $run->{component}, $need_magic,
     616                $dateobs_begin, $dateobs_end, $filter, $data_group, $option_mask, $verbose);
     617
     618            next if !$these_results;
     619            push @$results, @$these_results;
     620        }
     621       
     622    } else {
     623        # this should be checked elsewhere
     624        die "unexpected image type $img_type" if ($img_type ne "warp")
     625                                              and ($img_type ne "stack") and ($img_type ne "diff");
     626
     627        my $skycells = lookup_skycell_by_coords($ipprc, $tess_id, $component, $ra, $dec, $verbose);
     628
     629        foreach my $skycell (@$skycells) {
     630            my $these_results = lookup($ipprc, $rowList, $imagedb, "byskycell", $img_type, undef,
     631                $skycell->{tess_id}, $skycell->{component}, $need_magic,
     632                $dateobs_begin, $dateobs_end, $filter, $data_group, $option_mask, $verbose);
     633
     634            next if !$these_results;
     635            push @$results, @$these_results;
     636        }
     637    }
     638
     639    return $results;
     640}
     641
     642# lookup_runs_by_cam_id_and_coords
     643# given an ra, dec, and optionally other paramters, find camera runs for exposures
     644# that are within some distance of the coordinates
     645sub lookup_runs_by_cam_id_and_coords {
     646    my $ipprc      = shift;
     647    my $imagedb   = shift;
     648    my $img_type   = shift;
     649    my $ra         = shift;
     650    my $dec        = shift;
     651    my $need_magic = shift;
     652    my $dateobs_begin  = shift;
     653    my $dateobs_end = shift;
     654    my $filter     = shift;
     655    my $data_group = shift;
     656    my $verbose    = shift;
     657
     658    my $camruns;
     659
     660    {
     661        my $command = "$camtool -dbname $imagedb -processedexp -pstamp_order";
     662           $command .= " -ra $ra -decl $dec -radius 1.6";
     663           $command .= " -dateobs_begin $dateobs_begin" if $dateobs_begin;
     664           $command .= " -dateobs_end   $dateobs_end"   if $dateobs_end  ;
     665           $command .= " -filter $filter" if $filter;
     666           # NOTE: we are applying the data_group to the camera run.
     667           # If we're looking for chip stage images there is no guarentee that
     668           # chipRun.data_group = camRun.data_group. In practice this is almost
     669           # always the case. If this turns out to be a problem we can defer
     670           # the data_group test to when we look up the chipProcessedImfiles
     671           $command .= " -data_group $data_group" if $data_group;
     672           $command .= " -destreaked" if $need_magic;
     673
     674        # run the tool and parse the output
     675        $camruns = runToolAndParse($command, $verbose);
     676    }
     677    if (!$camruns) {
    483678        return undef;
    484679    }
    485 
    486     # XXX TODO: This query doesn't work Something appears to be out of
    487     # sync about the times I'm passing and what regtool and or the DB expect
    488     # the query I used in the C version of locateimages used
    489     # WHERE dateobs >= FROM_UNIXTIME(%ld) AND dateobs <= FROM_UNIXTIME(%ld + exp_time)
    490 
    491     my $command = "$regtool -processedexp -dbname $image_db $args";
    492 
    493     # run the tool and parse the output
     680    my $runs;
     681    my $last_exp_id = 0;
     682    foreach my $camRun (@$camruns) {
     683        my $cam_id = $camRun->{cam_id};
     684        my $exp_id = $camRun->{exp_id};
     685
     686        next if $exp_id eq $last_exp_id;
     687
     688        next if $camRun->{quality};
     689        next if $camRun->{fault};
     690
     691        updateCamRunCache($camRun);
     692
     693        $last_exp_id = $exp_id;
     694
     695        # XXX Use file rule
     696        my $astrom = $camRun->{path_base} . ".smf";
     697        my $astrom_resolved = $ipprc->file_resolve($astrom);
     698        next if !$astrom_resolved;
     699
     700        my $start_dvo = DateTime->now->mjd;
     701        my $command = "$dvoImagesAtCoords -astrom $astrom_resolved $ra $dec";
     702        # run the tool and parse the output
     703        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     704                    run(command => $command, verbose => $dvo_verbose);
     705        my $dtime_dvo = (DateTime->now->mjd - $start_dvo)* 86400.;
     706#        print "Time to run dvoImagesAtCoords: $dtime_dvo\n";
     707        unless ($success) {
     708            my $result_code = $error_code >> 8;
     709            if ($result_code == $PSTAMP_NO_OVERLAP) {
     710                print "no overlap for $astrom\n" if $verbose;
     711                next;
     712            }
     713            # unexpected result code
     714            die "unexpected result code: $result_code from $command\n";
     715        }
     716
     717        my $output = join "", @$stdout_buf;
     718        if (!$output) {
     719            # this shouldn't happen when dvoImagesAtCoord exits with zero status
     720            die "no output returned from $command\n";
     721        }
     722
     723        # dvoImagesAtCoords should return a single line
     724        # rownum ra dec class_id
     725        my @lines = split "\n", $output;
     726        my $n = scalar @lines;
     727        if ($n != 1) {
     728            print STDERR "unexpected number of lines returned by dvoImagesAtCoords: $n\n";
     729
     730            # XXX: There is a bug in dvo where each component is listed twice
     731            # When that gets fixed remove the conditional and just die
     732            die "unexpected number lines returned by dvoImagesAtCoords: $n"
     733                if ($n != 2) or ($lines[0] ne $lines[1]);
     734        }
     735
     736        my (undef, $ra_out, $dec_out, $class_id) = split " ", $lines[0];
     737        if (!$class_id) {
     738            die "unexpected output from dvoImagesAtCoords: $lines[0]";
     739        }
     740
     741        print "cam_id $cam_id exp_id $camRun->{exp_id} chip_id $camRun->{chip_id} $class_id\n";
     742
     743        # build the hash to return
     744        my $run = {
     745            exp_id    => $camRun->{exp_id},
     746            exp_name  => $camRun->{exp_name},
     747            chip_id   => $camRun->{chip_id},
     748            cam_id    => $camRun->{cam_id},
     749            astrom    => $astrom_resolved,
     750            class_id  => $class_id,
     751            component => $class_id
     752        };
     753        if ($img_type eq "chip") {
     754            $run->{id} = $camRun->{chip_id};
     755            $run->{state} = $camRun->{chip_state};
     756            $run->{magicked} = $camRun->{chip_magicked};
     757        } else {
     758            $run->{id} = $camRun->{exp_id};
     759            $run->{state} = 'full';
     760            $run->{magicked} = $camRun->{raw_magicked};
     761        }
     762        push @$runs, $run;
     763    }
     764
     765    return $runs;
     766}
     767
     768sub lookup_skycell_by_coords {
     769    my $ipprc      = shift;
     770    my $requested_tess_id    = shift;
     771    my $requested_skycell  = shift;
     772    my $ra         = shift;
     773    my $dec        = shift;
     774    my $verbose    = shift;
     775
     776    $requested_tess_id = "" if isnull($requested_tess_id);
     777    $requested_skycell = "" if isnull($requested_skycell);
     778
     779    my @lines;
     780    {
     781        my $command = "$whichimage $ra $dec";
     782        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     783                    run(command => $command, verbose => $verbose);
     784        unless ($success) {
     785            print STDERR @$stderr_buf;
     786            return undef;
     787        }
     788
     789        my $output = join "", @$stdout_buf;
     790        if (!$output) {
     791            print STDERR "no output returned from $command\n" if $verbose;
     792            return undef;
     793        }
     794        @lines = split "\n", $output;
     795        if (!scalar @lines) {
     796            # can this happen? if $output is not null?
     797            print STDERR "no output returned from $command\n" if $verbose;
     798            return undef;
     799        }
     800    }
     801    my $runs;
     802    foreach my $line (@lines) {
     803        my ($ra_out, $dec_out, $tess_id, $skycell_id) = split " ", $line;
     804        die "unexpected output from whichimage" if !$tess_id or !$skycell_id;
     805
     806        if ($requested_tess_id) {
     807            next if ($requested_tess_id ne $tess_id);
     808        } else {
     809            # skip these obsolete tesselations unless they were explicitly asked for
     810            # should I do this?
     811            next if $tess_id eq "FIXNS";
     812            next if $tess_id eq "ALLSKY";
     813        }
     814        next if $requested_skycell and ($skycell_id ne $requested_skycell);
     815
     816        # build the hash to return
     817        my $run = {
     818            tess_id   => $tess_id,
     819            component => $skycell_id,
     820        };
     821        push @$runs, $run;
     822    }
     823
     824    return $runs;
     825}
     826
     827# cache of results of ppConfigDump
     828my %astromSources;
     829my $last_exp_id = 0;
     830my $lastAstromFile;
     831
     832# find the astrometry file for a given exposure
     833# return undef if no completed camRun exists
     834sub find_astrometry {
     835    my $ipprc = shift;
     836    my $imagedb = shift;
     837    my $image = shift;      # hashref to output of the lookup tool
     838    my $verbose = shift;
     839
     840    my $mdcParser;
     841
     842    my $exp_id = $image->{exp_id};
     843    if (($exp_id eq $last_exp_id) and $lastAstromFile) {
     844        # running camtool 60 times is really expensive when the answer is the same every time
     845        return $lastAstromFile;
     846    }
     847    $last_exp_id = 0;
     848    $lastAstromFile = undef;
     849
     850    my $camRun = getCamRunByExpID($exp_id);
     851    if (!$camRun) {
     852        my $command = "$camtool -dbname $imagedb -processedexp -exp_id $exp_id -pstamp_order";
     853        # run the tool and parse the output
     854        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     855                    run(command => $command, verbose => $verbose);
     856        unless ($success) {
     857            print STDERR @$stderr_buf;
     858            return undef;
     859        }
     860
     861        $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
     862
     863        my $output = join "", @$stdout_buf;
     864        if (!$output) {
     865            print STDERR "no output returned from $command\n" if $verbose;
     866            return undef;
     867        }
     868        my $camruns = parse_md_fast($mdcParser, $output);
     869        if (!$camruns) {
     870            return undef;
     871        }
     872
     873        # If there are multiple cam runs for this exposure, take the last completed one with good quality
     874        # on the assumption that it has the best astrometry.
     875        foreach $camRun (@$camruns) {
     876            last if (($camRun->{state} eq 'full') and ($camRun->{quality} eq 0) and ($camRun->{fault} eq 0));
     877        }
     878        # XXX: this looks like a bug at least if ASTROM.SOURCE eq PSASTRO.OUTPUT
     879        if (!$camRun) {
     880            # no cam runs for this exposure id therefore best astrometry is whatever is in the header
     881            return undef;
     882        }
     883        updateCamRunCache($camRun);
     884    }
     885    my $camRoot = $camRun->{path_base};
     886    my $camera = $image->{camera};
     887    my $astromSource = $astromSources{$camera};
     888    if (!$astromSource) {
     889        if ($camera eq "GPC1") {
     890            # CHEATER !
     891            $astromSource = "PSASTRO.OUTPUT";
     892        } else {
     893            my $command = "$ppConfigDump -camera $camera -dump-recipe PSWARP -";
     894            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     895                run(command => $command, verbose => $verbose);
     896            unless ($success) {
     897                $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
     898                die("Unable to perform ppConfigDump: $error_code");
     899            }
     900            $mdcParser = PS::IPP::Metadata::Config->new if !$mdcParser; # Parser for metadata config files
     901            my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
     902                die("Unable to parse metadata config doc");
     903            $astromSource = metadataLookupStr($metadata, 'ASTROM.SOURCE');
     904        }
     905        $astromSources{$camera} = $astromSource;
     906    }
     907
     908    # XXX: Is this code correct if ASTROM.SOURCE ne "PSASTRO.OUTPUT"
     909    my $astromFile = $ipprc->filename($astromSource, $camRoot);
     910    if ($astromFile) {
     911        $lastAstromFile = $astromFile;
     912        $last_exp_id = $exp_id;
     913    }
     914
     915    return $astromFile;
     916}
     917
     918# splits meta data config input stream into single units to work around the pathalogically
     919# slow parser. This is similar to and adapted from code in various ippScripts.
     920sub parse_md_fast {
     921    my $mdcParser = shift;
     922    my $input = shift;
     923    my $output = ();
     924
     925    my @whole = split /\n/, $input;
     926    my @single = ();
     927
     928    my $n;
     929    while ( ($n = @whole) > 0) {
     930        my $value = shift @whole;
     931        push @single, $value;
     932        if ($value =~ /^\s*END\s*$/) {
     933            push @single, "\n";
     934
     935            my $list = parse_md_list( $mdcParser->parse( join("\n", @single ) ) ) or
     936                print STDERR "Unable to parse metdata config doc" and return undef;
     937#            my $num = @$list;
     938#            print STDERR "list has $num elments\n";
     939            push @$output, $list->[0];
     940
     941            @single = ();
     942        }
     943    }
     944    return $output;
     945}
     946
     947sub mjd_to_dateobs {
     948    my $mjd = shift;
     949
     950    my $ticks = ($mjd - 40587.0) * 86400;
     951
     952    my ($sec, $min, $hr, $day, $mon, $year) = gmtime($ticks);
     953
     954    return sprintf "'%4d-%02d-%02dT%02d:%02d:%02dZ'", $year+1900, $mon+1, $day, $hr, $min, $sec;
     955}
     956
     957sub isnull {
     958    my $val = shift;
     959
     960    return (!defined($val) or ($val eq "") or (lc($val) eq "null"));
     961}
     962
     963sub iszero {
     964    my $val = shift;
     965    return (!defined($val) or ($val == 0));
     966}
     967
     968# resolve_project()
     969# get project specific information
     970sub resolve_project {
     971    my $ipprc = shift;
     972    my $project_name = shift;
     973
     974    findTools();
     975
     976    if (!$project_name) {
     977        carp ("project is not defined");
     978        return undef;
     979    }
     980
     981    if ($last_project and ($project_name eq ($last_project->{name}))) {
     982        return $last_project;
     983    }
     984
     985    my $dbname = shift;
     986    my $dbserver = shift;
     987
     988    my $verbose = 0;
     989
     990    my $command = "$pstamptool -project -name $project_name";
     991    $command .= " -dbname $dbname" if defined $dbname;
     992    $command .= " -dbserver $dbserver" if defined $dbserver;
     993
     994    my $proj_hash = runToolAndParse($command, $verbose);
     995    if (!$proj_hash or scalar @$proj_hash == 0) {
     996        print STDERR "Project $project_name not found\n";
     997        return undef;
     998    }
     999
     1000    $last_project = $proj_hash->[0];
     1001
     1002    return $last_project;
     1003}
     1004
     1005sub updateCamRunCache {
     1006    my $camRun = shift;
     1007    die "updateCamRunCache: camRun is nil" if !$camRun;
     1008
     1009    my $exp_id = $camRun->{exp_id};
     1010    die "updateCamRunCache: exp_id is nil" if !$exp_id;
     1011
     1012    my $cam_id = $camRun->{cam_id};
     1013    die "updateCamRunCache: cam_id is nil" if !$cam_id;
     1014
     1015    $camRunByCamIDCache{$cam_id} = $camRun;
     1016
     1017    # if this camRun is newer than previous update the cache.
     1018    # This assumes that the newest has the "best" astrometry
     1019    my $previous = $camRunByExpIDCache{$exp_id};
     1020    if ($previous) {
     1021        my $previous_cam_id = $previous->{cam_id};
     1022        return if $cam_id < $previous_cam_id;
     1023    }
     1024
     1025    $camRunByExpIDCache{$exp_id} = $camRun;
     1026}
     1027
     1028sub getCamRunByExpID {
     1029    my $exp_id = shift;
     1030    &my_die ("getCamRun: exp_id is nil", $PS_EXIT_PROG_ERROR) if !$exp_id;
     1031
     1032    return $camRunByExpIDCache{$exp_id};
     1033}
     1034
     1035sub getCamRunByCamID {
     1036    my $cam_id = shift;
     1037    &my_die ("getCamRun: cam_id is nil", $PS_EXIT_PROG_ERROR) if !$cam_id;
     1038
     1039    return $camRunByCamIDCache{$cam_id};
     1040}
     1041
     1042sub selectComponents {
     1043    my $ipprc = shift;
     1044    my $imagedb = shift;
     1045    my $req_type = shift;
     1046    my $stage  = shift;
     1047    my $rowList = shift;
     1048    my $runList = shift;
     1049    my $verbose = shift;
     1050    my $results = [];
     1051   
     1052    my ($pointsList, $pointsListName) = tempfile ("/tmp/pointsList.XXXX", UNLINK => !$save_temps);
     1053    my $npoints = 0;
     1054    foreach my $row (@$rowList) {
     1055        print $pointsList "$npoints $row->{CENTER_X} $row->{CENTER_Y}\n";
     1056        $npoints++;
     1057    }
     1058    close $pointsList;
     1059
     1060    # XXX: need to loop over these
     1061    # my $run = $runList->[0];
     1062    if (($req_type eq "byid") or ($req_type eq "byexp")) {
     1063        my ($last_tess_id, $tess_dir_abs, $astrom_file) = ("", "", "");
     1064        foreach my $run (@$runList) {
     1065            my $command = "$dvoImagesAtCoords -coords $pointsListName";
     1066            if (($stage eq "chip") or ($stage eq "raw")) {
     1067                # XXX: use file rule and handle cameras where the astrometry is solved at
     1068                # the chip stage.
     1069                $astrom_file = $run->{cam_path_base} . ".smf";
     1070                my $astrom_file_resolved = $ipprc->file_resolve($astrom_file);
     1071                $command .= " -astrom $astrom_file_resolved";
     1072            } else {
     1073                my $tess_id = $run->{tess_id};
     1074                if ($tess_id ne $last_tess_id) {
     1075                    $tess_dir_abs = $ipprc->tessellation_catdir( $tess_id );
     1076                    $tess_dir_abs = $ipprc->convert_filename_absolute( $tess_dir_abs );
     1077                    $last_tess_id = $tess_id;
     1078                }
     1079                $command .= " -D CATDIR $tess_dir_abs"
     1080            }
     1081            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     1082                 run(command => $command, verbose => $dvo_verbose);
     1083            unless ($success) {
     1084                # don't fail if the program exited normally and exit status was PSTAMP_NO_OVERLAP
     1085                #                     # That just means that the coordinate didn't match any image/skycell
     1086                if (!WIFEXITED($error_code) || (WEXITSTATUS($error_code) ne $PSTAMP_NO_OVERLAP)) {
     1087                    print STDERR @$stderr_buf;
     1088                    my $rc = WIFEXITED($error_code) ? WEXITSTATUS($error_code) : $PS_EXIT_SYS_ERROR;
     1089                    &my_die( "dvoImagesAtCoords failed: $rc", $rc);
     1090                }
     1091            }
     1092            my %components;
     1093            my @lines = split "\n", join "", @$stdout_buf;
     1094            foreach my $line (@lines) {
     1095                my ($ptnum, undef, undef, $component) = split " ", $line;
     1096                my $ref = $components{$component};
     1097                if (!$ref) {
     1098                    $ref = $components{$component} = [];
     1099                }
     1100                push @$ref, $ptnum;
     1101            }
     1102            if ($verbose) {
     1103                foreach my $c (keys %components) {
     1104                    my $ref = $components{$c};
     1105                    print "component $c contains: ";
     1106                    foreach my $i (@$ref) {
     1107                        print "$i ";
     1108                    }
     1109                    print "\n";
     1110                }
     1111            }
     1112            # now find the images for this run
     1113            foreach my $c (keys %components) {
     1114                my $command;
     1115                my $stage_id;
     1116                if ($stage eq 'raw') {
     1117                    $stage_id = $run->{exp_id};
     1118                    $command = "$regtool -processedimfile -exp_id $stage_id -class_id $c";
     1119                } elsif ($stage eq 'chip') {
     1120                    $stage_id = $run->{chip_id};
     1121                    $command = "$chiptool -processedimfile -chip_id $stage_id -class_id $c";
     1122                } elsif ($stage eq 'warp') {
     1123                    $stage_id = $run->{warp_id};
     1124                    $command = "$warptool -warped -warp_id $stage_id -skycell_id $c";
     1125                } elsif ($stage eq 'diff') {
     1126                    $stage_id = $run->{diff_id};
     1127                    $command = "$difftool -diffskyfile -diff_id $stage_id -skycell_id $c";
     1128                }
     1129                $command .= " -dbname $imagedb";
     1130                my $images = runToolAndParse($command, $verbose);
     1131                if (!defined $images) {
     1132                    # XXX: need to get the set error_code to $PSTAMP_NO_OVERLAP
     1133                    print "No components containing coordinates found for ${stage}_id $stage_id\n";
     1134                    foreach my $row (@$rowList) {
     1135                        $row->{error_code} = $PSTAMP_NO_OVERLAP;
     1136                    }
     1137                    next;
     1138                }
     1139                if (scalar @$images != 1) {
     1140                    my $num_images = scalar @$images;
     1141                    &my_die ("unexpected number of images returned: $num_images\n", $PS_EXIT_PROG_ERROR);
     1142                }
     1143                my $image = $images->[0];
     1144                   
     1145                my $ref = $components{$c};
     1146                $image->{row_index} = $ref;
     1147                if (($stage eq "raw") or ($stage eq 'chip')) {
     1148                    $image->{astrom} = $astrom_file;
     1149                    $image->{cam_id} = $run->{cam_id};
     1150                    $image->{cam_path_base} = $run->{cam_path_base};
     1151                }
     1152                push @$results, $image;
     1153            }
     1154        }
     1155    } else {
     1156        &my_die ("sorry not done with $req_type\n", $PS_EXIT_PROG_ERROR);
     1157    }
     1158    return $results;
     1159}
     1160
     1161sub filterRuns {
     1162    my $stage      = shift;
     1163    my $need_magic = shift;
     1164    my $inputs     = shift;
     1165    my $verbose    = shift;
     1166
     1167    if ($inputs and (scalar @$inputs) == 1)  {
     1168        # one run nothing to do
     1169        return $inputs;
     1170    }
     1171
     1172    my $output = [];
     1173
     1174    return $output if (!$inputs or scalar @$inputs == 0);
     1175
     1176    my $id_name = $stage . "_id";
     1177
     1178    # input list is "order by exp_id, run_id DESC"   run_id is one of (chip_id, warp_id, diff_id)
     1179    print "Starting filterRuns\n";
     1180    my $last_exp_id = 0;
     1181    my $last_run_id = 0;
     1182    my $printed = 0;
     1183    foreach my $input (@$inputs) {
     1184        my $exp_id = $input->{exp_id};
     1185        my $run_id = $input->{$id_name};
     1186        my $magicked = $input->{magicked};  # this will be either stageRun.magicked or stage%file.magicked
     1187        my $state = $input->{state};
     1188
     1189        # can't process run in these states
     1190        if (($state eq 'new') or ($state eq 'purged') or ($state eq 'scrubbed')) {
     1191            print "skipping ${stage}Run $run_id for exp_id $exp_id in state $state\n";
     1192            next;
     1193        }
     1194
     1195        $printed = 1 if (($exp_id == $last_exp_id) and ($run_id == $last_run_id));
     1196
     1197        # skip if we need magicked run and this one has never been magicked
     1198        if ($need_magic and !$magicked) {
     1199            print "skipping ${stage}Run $run_id for exp_id $exp_id not magicked\n" if !$printed;
     1200            next;
     1201        }
     1202
     1203        if (($exp_id == $last_exp_id) and ($run_id != $last_run_id)) {
     1204            print "Skipping duplicate ${stage}Run $run_id for $exp_id\n" if !$printed;
     1205            next;
     1206        }
     1207        print "Keeping ${stage}Run $run_id for $exp_id\n";
     1208        push @$output, $input;
     1209        $last_exp_id = $exp_id;
     1210        $last_run_id = $run_id;
     1211        $printed = 0;
     1212    }
     1213
     1214    my $num_runs = scalar @$output;
     1215    print "filterRuns returning $num_runs ${stage}Run\n";
     1216
     1217    return $output;
     1218}
     1219
     1220# run a command that produces metadata output and parse the results into an array of objects
     1221sub runToolAndParse {
     1222    my $command = shift;
     1223    my $verbose = shift;
     1224
     1225    my ($program) = split " ", $command;
     1226    $program = basename($program);
     1227
     1228    print "Running $command\n" if !$verbose;
     1229    my $start_tool = DateTime->now->mjd;
     1230    # run the command and parse the output
     1231
    4941232    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    4951233                run(command => $command, verbose => $verbose);
     
    4991237        return undef;
    5001238    }
    501     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    502 
    503     my $output = join "", @$stdout_buf;
    504     if (!$output) {
    505         print STDERR "no output returned from $command\n" if $verbose;
     1239
     1240    my $now = DateTime->now->mjd;
     1241    my $dtime_tool = (DateTime->now->mjd - $start_tool) * 86400.;
     1242    print "Time to run $program: $dtime_tool\n";
     1243
     1244    my $buf = join "", @$stdout_buf;
     1245    if (!$buf) {
    5061246        return undef;
    5071247    }
    508     my $images = parse_md_fast($mdcParser, $output) or die ("Unable to parse metadata config doc");
    509 
    510     return $images;
    511 }
    512 
    513 # cache of results of ppConfigDump
    514 my %astromSources;
    515 my $last_exp_id = 0;
    516 my $lastAstromFile;
    517 
    518 # find the astrometry file for a given exposure
    519 # return undef if no completed camRun exists
    520 sub find_astrometry {
    521     my $ipprc = shift;
    522     my $image_db = shift;
    523     my $image = shift;      # hashref to output of the lookup tool
    524     my $verbose = shift;
    525 
    526     my $exp_id = $image->{exp_id};
    527     if (($exp_id eq $last_exp_id) and $lastAstromFile) {
    528         # running camtool 60 times is really expensive when the answer is the same
    529         return $lastAstromFile;
    530     }
    531     $last_exp_id = 0;
    532     $lastAstromFile = undef;
     1248
     1249    my $start_parse = DateTime->now->mjd;
     1250
     1251    my $mdcParser = PS::IPP::Metadata::Config->new;
     1252    my $results = parse_md_fast($mdcParser, $buf)
     1253        or die ("Unable to parse metadata config doc");
     1254
     1255    my $dtime_parse = (DateTime->now->mjd - $start_parse) * 86400.;
     1256    print "Time to parse results from $program: $dtime_parse\n";
     1257
     1258    return $results;
     1259}
     1260
     1261sub findTools {
     1262    return if ($regtool);
    5331263
    5341264    my $missing_tools;
    535     my $camtool = can_run("camtool") or (warn "Can't find camtool" and $missing_tools = 1);
    536     my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
     1265    $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
     1266    $chiptool = can_run('chiptool') or (warn "Can't find chiptool" and $missing_tools = 1);
     1267    $camtool = can_run('camtool') or (warn "Can't find camtool" and $missing_tools = 1);
     1268    $warptool = can_run('warptool') or (warn "Can't find warptool" and $missing_tools = 1);
     1269    $difftool = can_run('difftool') or (warn "Can't find difftool" and $missing_tools = 1);
     1270    $stacktool = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
     1271    $pstamptool = can_run('pstamptool') or (warn "Can't find pstamptool" and $missing_tools = 1);
     1272    $dvoImagesAtCoords = can_run('dvoImagesAtCoords') or (warn "Can't find dvoImagesAtCoords"
     1273                                                                and $missing_tools = 1);
     1274    $whichimage = can_run('whichimage') or (warn "Can't find whichimage" and $missing_tools = 1);
     1275    $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
    5371276    if ($missing_tools) {
    5381277        warn("Can't find required tools.");
    5391278        exit ($PS_EXIT_CONFIG_ERROR);
    5401279    }
    541 
    542     my $command = "$camtool -dbname $image_db -processedexp -exp_id $exp_id";
    543     # run the tool and parse the output
    544     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    545                 run(command => $command, verbose => $verbose);
    546     unless ($success) {
    547         print STDERR @$stderr_buf;
    548         return undef;
    549     }
    550 
    551     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    552 
    553     my $output = join "", @$stdout_buf;
    554     if (!$output) {
    555         print STDERR "no output returned from $command\n" if $verbose;
    556         return undef;
    557     }
    558     my $camruns = parse_md_fast($mdcParser, $output);
    559     if (!$camruns) {
    560         return undef;
    561     }
    562 
    563     # If there are multiple cam runs for this exposure, take the last one
    564     # assuming that it has the best astrometry
    565     my $camdata = pop @$camruns;
    566     if (!$camdata) {
    567         # no cam runs for this exposure id therefore best astrometry is whatever is in the header
    568         return undef;
    569     }
    570     my $camRoot = $camdata->{path_base};
    571     my $camera = $image->{camera};
    572     my $astromSource = $astromSources{$camera};
    573     if (!$astromSource) {
    574        my $command = "$ppConfigDump -camera $camera -dump-recipe PSWARP -";
    575         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    576             run(command => $command, verbose => $verbose);
    577         unless ($success) {
    578             $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
    579             die("Unable to perform ppConfigDump: $error_code");
    580         }
    581         my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
    582             die("Unable to parse metadata config doc");
    583         $astromSource = metadataLookupStr($metadata, 'ASTROM.SOURCE');
    584         $astromSources{$camera} = $astromSource;
    585     }
    586 
    587     my $astromFile = $ipprc->filename($astromSource, $camRoot);
    588     if ($astromFile) {
    589         $lastAstromFile = $astromFile;
    590         $last_exp_id = $exp_id;
    591     }
    592 
    593     return $astromFile;
    594 }
    595 
    596 # splits meta data config input stream into single units to work around the pathalogically
    597 # slow parser. This is similar to and adapted from code in various ippScripts.
    598 sub parse_md_fast {
    599     my $mdcParser = shift;
    600     my $input = shift;
    601     my $output = ();
    602 
    603     my @whole = split /\n/, $input;
    604     my @single = ();
    605 
    606     my $n;
    607     while ( ($n = @whole) > 0) {
    608         my $value = shift @whole;
    609         push @single, $value;
    610         if ($value =~ /^\s*END\s*$/) {
    611             push @single, "\n";
    612 
    613             my $list = parse_md_list( $mdcParser->parse( join("\n", @single ) ) ) or
    614                 print STDERR "Unable to parse metdata config doc" and return undef;
    615 #            my $num = @$list;
    616 #            print STDERR "list has $num elments\n";
    617             push @$output, $list->[0];
    618 
    619             @single = ();
    620         }
    621     }
    622     return $output;
    623 }
    624 
    625 sub mjd_to_dateobs {
    626     my $mjd = shift;
    627 
    628     my $ticks = ($mjd - 40587.0) * 86400;
    629 
    630     my ($sec, $min, $hr, $day, $mon, $year) = gmtime($ticks);
    631 
    632     return sprintf "'%4d-%02d-%02dT%02d:%02d:%02dZ'", $year+1900, $mon+1, $day, $hr, $min, $sec;
    633 }
    634 
    635 sub isnull {
    636     my $val = shift;
    637 
    638     return (!defined($val) or (lc($val) eq "null"));
    639 }
    640 
    641 sub iszero {
    642     my $val = shift;
    643     return (!defined($val) or ($val == 0));
    644 }
    645 
    646 # resolve_project()
    647 # get project specific information
    648 my $last_project = "";
    649 sub resolve_project {
    650     my $ipprc = shift;
    651     my $project_name = shift;
    652 
    653     if (!$project_name) {
    654         carp ("project is not defined");
    655         return undef;
    656     }
    657 
    658     if ($project_name eq $last_project) {
    659         return $last_project;
    660     }
    661 
    662     my $dbname = shift;
    663     my $dbserver = shift;
    664 
    665     my $verbose = 0;
    666 
    667     my $missing_tools;
    668     my $pstamptool = can_run("pstamptool") or (warn "Can't find pstamptool" and $missing_tools = 1);
    669     if ($missing_tools) {
    670         warn("Can't find required tools.");
    671         exit ($PS_EXIT_CONFIG_ERROR);
    672     }
    673 
    674     my $command = "$pstamptool -project -name $project_name";
    675     $command .= " -dbname $dbname" if defined $dbname;
    676     $command .= " -dbserver $dbserver" if defined $dbserver;
    677     # run the tool and parse the output
    678     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    679                 run(command => $command, verbose => $verbose);
    680     unless ($success) {
    681         print STDERR @$stderr_buf;
    682         return undef;
    683     }
    684 
    685     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    686 
    687     my $output = join "", @$stdout_buf;
    688     if (!$output) {
    689         print STDERR "no output returned from $command\n" if $verbose;
    690         return undef;
    691     }
    692     my $proj_hash = parse_md_fast($mdcParser, $output);
    693 
    694     $last_project = $proj_hash->[0];
    695 
    696     return $last_project;
     1280}
     1281
     1282# add a row_index array to a set of images with entries for each of the rows in a list
     1283sub setRowRefs {
     1284    my $rowList = shift;
     1285    my $images  = shift;
     1286
     1287    my $row_index = [];
     1288    for (my $i = 0; $i < scalar @$rowList; $i++) {
     1289        push @$row_index, $i;
     1290    }
     1291    foreach my $image (@$images) {
     1292        $image->{row_index} = $row_index;
     1293    }
     1294}
     1295
     1296sub my_die
     1297{
     1298    my $msg = shift;
     1299    my $fault = shift;
     1300
     1301    carp $msg;
     1302
     1303    # we don't fault the request here pstamp_parser_run.pl handles that if necessary
     1304
     1305    return $fault;
    6971306}
    69813071;
Note: See TracChangeset for help on using the changeset viewer.