IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

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

updates from trunk

Location:
branches/simmosaic_branches
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/simmosaic_branches

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

    r24831 r27839  
    1616                    locate_images
    1717                    resolve_project
     18                    getCamRunByCamID
    1819                    );
    1920our %EXPORT_TAGS = (standard => [@EXPORT_OK]);
    2021
    2122
     23use PS::IPP::PStamp::RequestFile qw( :standard );
     24
    2225use IPC::Cmd 0.36 qw( can_run run );
    23 
    2426use PS::IPP::Metadata::List qw( parse_md_list );
    2527use PS::IPP::Config qw( :standard );
    26 
    27 ### my @images = locate_images($image_db, $req_type, $img_type, $id, $component,
    28 ###            $mjd_min, $mjd_max, $filter);
     28use Carp;
     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
    35     my $id       = shift;   # required unless req_type eq bycoord
     55    my $id       = shift;   # required unless req_type eq bycoord or byskycell
     56    my $tess_id  = shift;
    3657    my $component= shift;   # class_id or skycell_id
    37     my $x        = shift;
    38     my $y        = shift;
     58    my $option_mask  = shift;
     59    my $need_magic = shift;
    3960    my $mjd_min  = shift;
    4061    my $mjd_max  = shift;
    4162    my $filter   = shift;
     63    my $data_group = shift;
    4264    my $verbose  = shift;
    4365
    4466    # we die in response to bad data in request files
    45     die "Unknown req_type: $req_type" if ($req_type ne "byid") and ($req_type ne "byexp")
    46                                         and ($req_type ne "bycoord") and ($req_type ne "bydiff");
     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)
     70        if ($req_type ne "byid") and
     71           ($req_type ne "byexp") and
     72           ($req_type ne "bycoord") and
     73           ($req_type ne "bydiff") and
     74           ($req_type ne "byskycell");
     75
     76
     77    my $dateobs_begin;
     78    my $dateobs_end;
     79    if (!iszero($mjd_min)) {
     80        $dateobs_begin = mjd_to_dateobs($mjd_min);
     81    }
     82    if (!iszero($mjd_max)) {
     83        $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;
     103    }
     104
    47105    if (($req_type eq "byid") and ($img_type eq "diff")) {
    48106        # lookups of all of the information for diff images requires a two level lookup to
     
    50108        # in one place
    51109        $req_type = "bydiff";
    52     }
     110        my $results = lookup_diff($ipprc, $rowList, $imagedb, $id, $component, 1, $option_mask, $img_type, $verbose);
     111        return $results;
     112    }
     113
    53114    if ($req_type eq "bydiff") {
    54         my $results = lookup_bydiff($ipprc, $image_db, $id, $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);
    55118        if (!$results) {
    56119            return undef;
    57120        }
    58         if (($img_type eq "warp") or ($img_type eq "diff")) {
    59             # lookup_bydiff has done all of the work
    60             return [$results];
    61         } elsif (($img_type eq "raw") or ($img_type eq "chip")) {
    62             $req_type = "byexp";
    63             $id = $results->{exp_name};
     121        if ($img_type eq "diff") {
     122            # lookup_diff has done all of the work
     123            return $results;
     124        }
     125
     126        my $image = $results->[0];
     127        if ($img_type eq "raw") {
     128            $req_type = "byid";
     129            $id = $image->{exp_id};
    64130            return undef if !$id;
    65             # fall through and lookup byexp
    66 #        } elsif ($img_type eq "warp") {
    67 #            $req_type = "byid";
    68 #            $id = $results->{warp_id};
    69 #            $component = $results->{skycell_id};
    70 #            return undef if !$id;
    71 #            # fall through and lookup by warp_id
     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
     137        } elsif ($img_type eq "warp") {
     138            $req_type = "byid";
     139            $id = $image->{warp_id};
     140            $component = $image->{skycell_id};
     141            return undef if !$id;
     142            # fall through and lookup by warp_id
    72143        } elsif ($img_type eq "stack") {
    73144            $req_type = "byid";
    74             $id = $results->{stack_id};
     145            $id = $image->{stack_id};
    75146            return undef if !$id;
    76             # fall though and lookup by stack id
     147            # fall though and lookup by stack_id
    77148        } else {
    78             # shouldn't I check this elsewhere?
     149            # This is checked this elsewhere?
    79150            print STDERR "Error: $img_type is an unknown image type\n";
    80151            return undef;
    81152        }
    82 
    83     } elsif ($req_type eq "bycoord") {
    84 
    85         # run
    86         # regtool -dbname $image_db -processedimfile -time_begin $mjd_min -time_end = $mjd_max -filter $filter
    87         #
    88         my $results = lookup_bycoord($ipprc, $image_db, $x, $y, $mjd_min, $mjd_max, $filter, $verbose);
    89 
    90         # now take the results and lookup byexp
    91         # XXX: This needs work. What stops results from returning multiple images????
    92         # We should loop over the set of images returned building up the full results array
    93         $req_type = "byexp";
    94         $id = $results->{exp_name};
    95     }
    96 
    97     my $results = lookup($ipprc, $image_db, $req_type, $img_type, $id, $component, $verbose);
     153    } elsif ($req_type eq "byskycell") {
     154        if (($img_type eq "raw") or ($img_type eq "chip")) {
     155            print STDERR "REQ_TYPE byskycell not supported for IMG_TYPE raw or chip\n";
     156            return undef;
     157        }
     158        if (!$tess_id or !$component) {
     159            print STDERR "component and tess_id are required for REQ_TYPE byskycell\n";
     160            return undef;
     161        }
     162    }
     163
     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);
    98166
    99167    return $results;
    100168}
    101169
    102 sub lookup {
     170# The subroutine lookup handles byexp, byid, and byskycell lookups including lookups that are
     171# triggered by a bydiff request
     172
     173sub lookup
     174{
    103175    my $ipprc    = shift;
    104     my $image_db = shift;
     176    my $rowList    = shift;
     177    my $imagedb = shift;
    105178    my $req_type = shift;
    106     my $img_type = shift;
     179    my $stage = shift;
    107180    my $id       = shift;
     181    my $tess_id  = shift;
    108182    my $component= shift;
     183    my $need_magic = shift;
     184    my $dateobs_begin = shift;
     185    my $dateobs_end   = shift;
     186    my $filter = shift;
     187    my $data_group = shift;
     188    my $option_mask = shift;
    109189    my $verbose  = shift;
    110190
    111     my $missing_tools;
    112     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    113     my $chiptool = can_run('chiptool') or (warn "Can't find chiptool" and $missing_tools = 1);
    114     my $warptool = can_run('warptool') or (warn "Can't find warptool" and $missing_tools = 1);
    115     my $difftool = can_run('difftool') or (warn "Can't find difftool" and $missing_tools = 1);
    116     my $stacktool = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
    117     if ($missing_tools) {
    118         warn("Can't find required tools.");
    119         exit ($PS_EXIT_CONFIG_ERROR);
    120     }
     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
    121195    my $command;
    122196    my $id_opt;     # option for the lookup
     197    my $image_name;
    123198    my $mask_name;
    124199    my $weight_name;
     200    my $cmf_name;
     201    my $psf_name;
     202    my $backmdl_name;
    125203    my $base_name;
    126204    my $want_astrom;
     
    129207    my $skycell_id;
    130208
    131     # special class_id value "null" means ignore
    132     if ($component eq "null") {
     209    if (isnull($component)) {
    133210        $component = undef;
    134211    }
    135212
    136     if ($img_type eq "raw") {
     213    # note $magic_arg may be cleared below depending on $req_type
     214    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
     219    my $component_args;
     220    my $choose_components = 0;
     221    if ($stage eq "raw") {
    137222        $class_id = $component;
    138         $command = "$regtool -processedimfile -dbname $image_db";
    139         $id_opt = "-exp_id";
    140         $command .= " -class_id $class_id" if $component;
     223        $command = "$regtool -processedimfile -dbname $imagedb";
     224        # XXX: for now restrict lookups to type object
     225        # are stamps of detrend exposures interesting?
     226        $command .= " -exp_type object";
     227        $id_opt = $use_imfile_id ? "-raw_imfile_id" : "-exp_id";
     228        $component_args = " -class_id $class_id" if $component;
    141229        $want_astrom = 1;
    142230        $set_class_id = 1;
    143     } elsif ($img_type eq "chip") {
     231    } elsif ($stage eq "chip") {
    144232        $class_id = $component;
    145         $command = "$chiptool -processedimfile -dbname $image_db";
    146         $command .= " -class_id $class_id" if $class_id;
    147         $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.
     247        $image_name   = "PPIMAGE.CHIP";
    148248        $mask_name    = "PPIMAGE.CHIP.MASK";
    149249        $weight_name  = "PPIMAGE.CHIP.VARIANCE";
     250        $cmf_name     = "PSPHOT.OUTPUT";
     251        $psf_name     = "PSPHOT.PSF.SAVE";
     252        $backmdl_name = "PSPHOT.BACKMDL";
    150253        $base_name    = "path_base"; # name of the field for the chiptool output
    151254        $want_astrom  = 1;
    152255        $set_class_id = 1;
    153     } elsif ($img_type eq "warp") {
     256    } elsif ($stage eq "warp") {
    154257        $skycell_id = $component;
    155         $command = "$warptool -warped -dbname $image_db";
    156         $command .= " -skycell_id $skycell_id" if $skycell_id;
    157         $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";
     266        $image_name   = "PSWARP.OUTPUT";
    158267        $mask_name    = "PSWARP.OUTPUT.MASK";
    159268        $weight_name  = "PSWARP.OUTPUT.VARIANCE";
     269        $cmf_name     = "PSWARP.OUTPUT.SOURCES";
     270        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    160271        $base_name    = "path_base"; # name of the field for the warptool output
    161     } elsif ($img_type eq "diff") {
     272    } elsif ($stage eq "diff") {
    162273        $skycell_id = $component;
    163         $command = "$difftool -diffskyfile -dbname $image_db";
    164         $command .= " -skycell_id $skycell_id" if $skycell_id;
    165         $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";
     282        $image_name  = "PPSUB.OUTPUT";
    166283        $mask_name   = "PPSUB.OUTPUT.MASK";
    167284        $weight_name = "PPSUB.OUTPUT.VARIANCE";
     285        $cmf_name    = "PPSUB.OUTPUT.SOURCES";
     286        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    168287        $base_name   = "path_base";
    169     } elsif ($img_type eq "stack") {
    170         $command = "$stacktool -sumskyfile -dbname $image_db";
     288    } elsif ($stage eq "stack") {
     289        $skycell_id = $component;
     290        $command = "$stacktool -sumskyfile -dbname $imagedb";
    171291        $id_opt = "-stack_id";
    172 
    173         $mask_name   = "PPSTACK.OUTPUT.MASK";
    174         $weight_name = "PPSTACK.OUTPUT.VARIANCE";
     292        $component_args = " -skycell_id $skycell_id" if $skycell_id;
     293
     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";
    175308        $base_name   = "path_base";
    176309    } else {
    177         die "Unknown img_type supplied: $img_type";
    178     }
    179 
     310        die "Unknown IMG_TYPe supplied: $stage";
     311    }
     312
     313    my $filter_runs = 0;
    180314    if ($req_type eq "byid") {
    181315        $command .= " $id_opt $id";
     316        $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 = "";
    182321    } elsif ($req_type eq "byexp") {
    183322        $command .= " -exp_name $id";
     323        $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;
     329    } elsif ($req_type eq "byskycell") {
     330        die "tess_id and component are required for byskycell" if !$tess_id or ! $skycell_id;
     331        $command .= " -tess_id $tess_id -skycell_id $skycell_id";
    184332    } else {
    185         die "Unknown req_type supplied: $req_type";
    186     }
    187 
    188     # run the tool and parse the output
     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") {
     338        $command .= $magic_arg;
     339        $command .= " -dateobs_begin $dateobs_begin" if $dateobs_begin;
     340        $command .= " -dateobs_end $dateobs_end" if $dateobs_end;
     341    }
     342
     343    $command .= " -filter $filter" if !isnull($filter);
     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) {
     349        return undef;
     350    }
     351
     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;
     368    my $output = [];
     369    foreach my $image (@$images) {
     370        my $base;
     371
     372        next if $image->{fault};
     373        next if ($stage ne "raw") and $image->{quality};
     374
     375        if ($base_name) {
     376            $base = $image->{$base_name};
     377            # if base is undef then the output pruducts for this image are incomplete
     378            # This may only happen for warps. (Actually the test for ignored that I added
     379            # just above probably solved the problem I was trying to solve with this test)
     380            next if !$base;
     381        } else {
     382            # raw images don't have path_base yet. Manufacture one
     383            my $uri = $image->{uri};
     384            my $path_base = $uri =~ s/\.fits//g;
     385            $image->{$path_base} = $path_base;
     386        }
     387        if (!$camera) {
     388            # This assumes that all images have the same camera
     389            $camera = $image->{camera};
     390            $ipprc->define_camera($camera);
     391        }
     392        my $out = $image;
     393
     394        # if uri is nil this will get overridded below
     395        # (we do this here for raw stage)
     396        $out->{image}  = $image->{uri};
     397
     398        if ($set_class_id) {
     399            $class_id = $image->{class_id};
     400            $out->{component} = $class_id;
     401        } else {
     402            $out->{component} = $image->{skycell_id};
     403        }
     404        my $stage_id;
     405        if ($stage eq "raw") {
     406            $stage_id = $image->{exp_id};
     407        } elsif ($stage eq "chip") {
     408            $stage_id = $image->{chip_id};
     409        } elsif ($stage eq "warp") {
     410            $stage_id = $image->{warp_id};
     411        } elsif ($stage eq "diff") {
     412            $stage_id = $image->{diff_id};
     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") {
     420            $stage_id = $image->{stack_id};
     421        }
     422        $out->{stage_id} = $stage_id;
     423        $out->{stage}    = $stage;
     424        $out->{imagedb} = $imagedb;
     425
     426        if ($base) {
     427            $out->{image}  = $ipprc->filename($image_name,  $base, $class_id) if $image_name;
     428            $out->{mask}   = $ipprc->filename($mask_name,   $base, $class_id) if $mask_name;
     429            $out->{weight} = $ipprc->filename($weight_name, $base, $class_id) if $weight_name;
     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        }
     437
     438        push @$output, $out;
     439    }
     440
     441    return $output;
     442}
     443
     444sub lookup_diff {
     445    my $ipprc    = shift;
     446    my $rowList  = shift;
     447    my $imagedb = shift;
     448    my $id       = shift;
     449    my $skycell_id = shift;
     450    my $byid     = shift;
     451    my $option_mask  = shift;
     452    my $img_type = shift;
     453    my $verbose = shift;
     454
     455    my $inverse = $option_mask & $PSTAMP_SELECT_INVERSE;
     456
     457    my $command = "$difftool -dbname $imagedb";
     458   
     459    if ($byid) {
     460        $command .= " -listrun -diff_id $id";
     461    } else {
     462        $command .= " -diffskyfile -diff_skyfile_id $id";
     463    }
     464    $command .= " -skycell_id $skycell_id" if $skycell_id;
     465
     466    my $output = runToolAndParse($command, $verbose);
     467
     468    my $n = @$output;
     469    if (!$byid && ($n > 1)) {
     470        die ("difftool returned an unexpected number of diffskyfiles: $n");
     471    } elsif ($n == 0) {
     472        return undef;
     473    }
     474
     475    my $images;
     476    if ($byid) {
     477        $images = selectComponents($ipprc, $imagedb, 'byid', 'diff', $rowList, $output, $verbose);
     478    } else {
     479        $images = $output;
     480    }
     481
     482    my @results;
     483    foreach my $image (@$images) {
     484        my $skycell_id = $image->{skycell_id};
     485
     486        if ($image->{fault}) {
     487            print STDERR "selected difference image $id $image->{diff_id} $skycell_id has fault: $image->{fault}\n";
     488            next;
     489        }
     490
     491        # The standard way to do a diff is warp - stack
     492        # so we interpret the requested image in that way
     493
     494        # XXX difftool currently returns max long long for null
     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            }
     519            $image->{stack_id} = $stack_id;
     520        } else {
     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
     558        if ($img_type eq "diff") {
     559            my @imageList = ($image);
     560
     561            setRowRefs($rowList, \@imageList);
     562            # the $image is going to be returned directly in this case so we need to duplicate
     563            # some of processing that lookup does for other img_types
     564            if ($image->{camera}) {
     565                $ipprc->define_camera($image->{camera});
     566                my $filerule_base = $inverse ? "PPSUB.INVERSE" : "PPSUB.OUTPUT";
     567                $image->{image}  = $ipprc->filename($filerule_base, $image->{path_base});
     568                $image->{mask}   = $ipprc->filename($filerule_base . ".MASK", $image->{path_base});
     569                $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};
     576            } else {
     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";
     579                next;
     580            }
     581        }
     582        push @results, $image;
     583    }
     584    return \@results;
     585}
     586
     587sub lookup_bycoord {
     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;
     597    my $dateobs_begin  = shift;
     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) {
     678        return undef;
     679    }
     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
    1891232    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    1901233                run(command => $command, verbose => $verbose);
     
    1951238    }
    1961239
     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
    1971244    my $buf = join "", @$stdout_buf;
    1981245    if (!$buf) {
    199         return;
    200     }
     1246        return undef;
     1247    }
     1248
     1249    my $start_parse = DateTime->now->mjd;
    2011250
    2021251    my $mdcParser = PS::IPP::Metadata::Config->new;
    203     my $images = parse_md_fast($mdcParser, $buf)
     1252    my $results = parse_md_fast($mdcParser, $buf)
    2041253        or die ("Unable to parse metadata config doc");
    2051254
    206     my $output = [];
    207 
    208     my $camera;
    209     foreach my $image (@$images) {
    210         my $base;
    211 
    212         next if $image->{fault};
    213         next if ($img_type ne "raw") and $image->{quality};
    214 
    215         if ($base_name) {
    216             $base = $image->{$base_name};
    217             # if base is undef then the output pruducts for this image are incomplete
    218             # This may only happen for warps. (Actually the test for ignored that I added
    219             # just above probably solved the problem I was trying to solve with this test)
    220             next if !$base;
    221         }
    222         if (!$camera) {
    223             # This assumes that all images have the same camera
    224             $camera = $image->{camera};
    225             $ipprc->define_camera($camera);
    226         }
    227         my $out = {};
    228         $out->{exp_id} = $image->{exp_id};
    229         $out->{exp_name} = $image->{exp_name};
    230         $out->{image}  = $image->{uri};
    231         $out->{state}  = $image->{state}; # state is undef for rawExp, but that's ok
    232         if ($set_class_id) {
    233             $class_id = $image->{class_id};
    234             $out->{class_id} = $class_id;
    235         }
    236 
    237         # find the mask and weight images
    238         if ($base) {
    239             $out->{mask}   = $ipprc->filename($mask_name,   $base, $class_id) if $mask_name;
    240             $out->{weight} = $ipprc->filename($weight_name, $base, $class_id) if $weight_name;
    241         }
    242         $out->{camera} = $camera;
    243 
    244         $out->{astrom} = find_astrometry($ipprc, $image_db, $image, $verbose) if $want_astrom;
    245 
    246         push @$output, $out;
    247     }
    248 
    249     return $output;
    250 }
    251 sub lookup_bydiff {
    252     my $ipprc    = shift;
    253     my $image_db = shift;
    254     my $id       = shift;
    255     my $img_type = shift;
    256     my $verbose = shift;
     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);
    2571263
    2581264    my $missing_tools;
    259     my $difftool = can_run('difftool') or (warn "Can't find difftool" 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);
    2601276    if ($missing_tools) {
    2611277        warn("Can't find required tools.");
    2621278        exit ($PS_EXIT_CONFIG_ERROR);
    2631279    }
    264 
    265     my $command = "$difftool -diffskyfile -diff_image_id $id -dbname $image_db";
    266 
    267     # run the tool and parse the output
    268     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    269                 run(command => $command, verbose => $verbose);
    270     unless ($success) {
    271         # not sure if we should die here
    272         print STDERR @$stderr_buf;
    273         return undef;
    274     }
    275 
    276     my $buf = join "", @$stdout_buf;
    277     if (!$buf) {
    278         return undef;
    279     }
    280 
    281     my $mdcParser = PS::IPP::Metadata::Config->new;
    282     my $images = parse_md_fast($mdcParser, $buf)
    283         or die ("Unable to parse metadata config doc");
    284 
    285     my $n = @$images;
    286     if ($n > 1) {
    287         die ("difftool returned an unexpected number of diffskyfiles: $n");
    288     } elsif ($n == 0) {
    289         return undef;
    290     }
    291 
    292     my $image = $images->[0];
    293 
    294     my $skycell_id = $image->{skycell_id};
    295 
    296     if ($image->{fault}) {
    297         print STDERR "selected difference image $id $image->{diff_id} $skycell_id has fault: $image->{fault}\n";
    298         return undef;
    299     }
    300 
    301     # The standard way to do a diff is warp - stack
    302     # so we interpret the requested image in that way
    303 
    304     my $stack_id = $image->{stack2};
    305     # XXX difftool currently returns max long long for null
    306     # this line is ready if we switch the code to return zero for null
    307     if ($stack_id and ($stack_id != 9223372036854775807)) {
    308         $image->{stack_id} = $stack_id;
    309     }
    310 
    311     my $warp_id =  $image->{warp1};
    312     # XXX difftool currently returns max long long for null
    313     # this line is ready if we switch the code to return zero for null
    314     if ($warp_id and ($warp_id != 9223372036854775807)) {
    315         $image->{warp_id} = $warp_id;
    316 
    317         ## now use the warp and go get the exposure information
    318         $command = "warptool -warped -warp_id $warp_id -skycell_id $skycell_id -dbname $image_db -limit 1";
    319         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    320                     run(command => $command, verbose => $verbose);
    321         unless ($success) {
    322             # not sure if we should die here
    323             print STDERR @$stderr_buf;
    324             return undef;
    325         }
    326 
    327         my $buf = join "", @$stdout_buf;
    328         if (!$buf) {
    329             return undef;
    330         }
    331 
    332         my $mdcParser = PS::IPP::Metadata::Config->new;
    333         my $warps = parse_md_fast($mdcParser, $buf)
    334             or die ("Unable to parse metadata config doc");
    335         my $warp = $warps->[0];
    336 
    337         if ($img_type eq "warp") {
    338             $image = $warp;
    339         } else {
    340             $image->{exp_id} = $warp->{exp_id};
    341             $image->{exp_name} = $warp->{exp_name};
    342             $image->{camera} = $warp->{camera};
    343         }
    344     }
    345 
    346     if (($img_type eq "diff") or ($img_type eq "warp")) {
    347         # the $image is going to be returned directly in this case so we need to duplicate
    348         # some of processing that lookup does for other img_types
    349         $image->{image} = $image->{uri};
    350         if ($image->{camera}) {
    351             $ipprc->define_camera($image->{camera});
    352             if ($img_type eq "diff") {
    353                 $image->{mask}   = $ipprc->filename("PPSUB.OUTPUT.MASK", $image->{path_base});
    354                 $image->{weight} = $ipprc->filename("PPSUB.OUTPUT.VARIANCE", $image->{path_base});
    355             } else {
    356                 $image->{mask}   = $ipprc->filename("PSWARP.OUTPUT.MASK",   $image->{path_base});
    357                 $image->{weight} = $ipprc->filename("PSWARP.OUTPUT.VARIANCE", $image->{path_base});
    358             }
    359         } else {
    360             # XXX this will only happen if the minuend is not a warp
    361             print STDERR "WARNING: cannot resolve camera so cannot get weight and mask images\n";
    362         }
    363     }
    364 
    365     return $image;
    366 }
    367 
    368 sub lookup_bycoord {
    369     my $ipprc    = shift;
    370     my $image_db = shift;
    371     my $x        = shift;
    372     my $y        = shift;
    373     my $mjd_min  = shift;
    374     my $mjd_max  = shift;
    375     my $filter   = shift;
    376     my $verbose  = shift;
    377 
    378     my $missing_tools;
    379     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    380     if ($missing_tools) {
    381         warn("Can't find required tools.");
    382         exit ($PS_EXIT_CONFIG_ERROR);
    383     }
    384 
    385     # XXX TODO:
    386     # Full lookups by coordinate require looking at the DVO database. However,
    387     # dateobs and filter which is all that MOPS has asked for.
    388 
    389     my $args;
    390     if ($mjd_min) {
    391         my $dateobs_min = mjd_to_dateobs($mjd_min);
    392         $args .= " -dateobs_begin $dateobs_min";
    393     }
    394     if ($mjd_max) {
    395         my $dateobs_max = mjd_to_dateobs($mjd_max);
    396         $args .= " -dateobs_end $dateobs_max";
    397     }
    398     if ($filter) {
    399         $args .= " -filter $filter";
    400     }
    401 
    402     if (!$args) {
    403         # avoid returning every exposure in the DB
    404         print STDERR "no query arguments provided for bycoord\n";
    405         return undef;
    406     }
    407 
    408     # XXX TODO: This query doesn't work Something appears to be out of
    409     # sync about the times I'm passing and what regtool and or the DB expect
    410     # the query I used in the C version of locateimages used
    411     # WHERE dateobs >= FROM_UNIXTIME(%ld) AND dateobs <= FROM_UNIXTIME(%ld + exp_time)
    412 
    413     my $command = "$regtool -processedexp -dbname $image_db $args";
    414 
    415     # run the tool and parse the output
    416     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    417                 run(command => $command, verbose => $verbose);
    418     unless ($success) {
    419         # not sure if we should die here
    420         print STDERR @$stderr_buf;
    421         return undef;
    422     }
    423     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    424 
    425     my $output = join "", @$stdout_buf;
    426     if (!$output) {
    427         print STDERR "no output returned from $command\n" if $verbose;
    428         return undef;
    429     }
    430     my $images = parse_md_fast($mdcParser, $output) or die ("Unable to parse metadata config doc");
    431 
    432     return $images;
    433 }
    434 
    435 # find the astrometry file for a given exposure
    436 # return undef if no completed camRun exists
    437 sub find_astrometry {
    438     my $ipprc = shift;
    439     my $image_db = shift;
    440     my $image = shift;      # hashref to output of the lookup tool
    441     my $verbose = shift;
    442 
    443     my $missing_tools;
    444     my $camtool = can_run("camtool") or (warn "Can't find camtool" and $missing_tools = 1);
    445     my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
    446     if ($missing_tools) {
    447         warn("Can't find required tools.");
    448         exit ($PS_EXIT_CONFIG_ERROR);
    449     }
    450 
    451     my $command = "$camtool -dbname $image_db -processedexp -exp_id $image->{exp_id}";
    452     # run the tool and parse the output
    453     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    454                 run(command => $command, verbose => $verbose);
    455     unless ($success) {
    456         print STDERR @$stderr_buf;
    457         return undef;
    458     }
    459 
    460     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    461 
    462     my $output = join "", @$stdout_buf;
    463     if (!$output) {
    464         print STDERR "no output returned from $command\n" if $verbose;
    465         return undef;
    466     }
    467     my $camruns = parse_md_fast($mdcParser, $output);
    468     if (!$camruns) {
    469         return undef;
    470     }
    471 
    472     # If there are multiple cam runs for this exposure, take the last one
    473     # assuming that it has the best astrometry
    474     my $camdata = pop @$camruns;
    475     if (!$camdata) {
    476         # no cam runs for this exposure id therefore best astrometry is whatever is in the header
    477         return undef;
    478     }
    479     my $camRoot = $camdata->{path_base};
    480     my $camera = $image->{camera};
    481     my $astromSource;
    482     {
    483        my $command = "$ppConfigDump -camera $camera -dump-recipe PSWARP -";
    484         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    485             run(command => $command, verbose => $verbose);
    486         unless ($success) {
    487             $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
    488             die("Unable to perform ppConfigDump: $error_code");
    489         }
    490         my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
    491             die("Unable to parse metadata config doc");
    492         $astromSource = metadataLookupStr($metadata, 'ASTROM.SOURCE');
    493     }
    494 
    495     my $astromFile = $ipprc->filename($astromSource, $camRoot);
    496 
    497     return $astromFile;
    498 }
    499 
    500 # splits meta data config input stream into single units to work around the pathalogically
    501 # slow parser. This is similar to and adapted from code in various ippScripts.
    502 sub parse_md_fast {
    503     my $mdcParser = shift;
    504     my $input = shift;
    505     my $output = ();
    506 
    507     my @whole = split /\n/, $input;
    508     my @single = ();
    509 
    510     my $n;
    511     while ( ($n = @whole) > 0) {
    512         my $value = shift @whole;
    513         push @single, $value;
    514         if ($value =~ /^\s*END\s*$/) {
    515             push @single, "\n";
    516 
    517             my $list = parse_md_list( $mdcParser->parse( join("\n", @single ) ) ) or
    518                 print STDERR "Unable to parse metdata config doc" and return undef;
    519 #            my $num = @$list;
    520 #            print STDERR "list has $num elments\n";
    521             push @$output, $list->[0];
    522 
    523             @single = ();
    524         }
    525     }
    526     return $output;
    527 }
    528 
    529 sub mjd_to_dateobs {
    530     my $mjd = shift;
    531 
    532     my $ticks = ($mjd - 40587.0) * 86400;
    533 
    534     my ($sec, $min, $hr, $day, $mon, $year) = gmtime($ticks);
    535 
    536     return sprintf "'%4d-%02d-%02d %02d:%02d:%02d'", $year+1900, $mon+1, $day, $hr, $min, $sec;
    537 }
    538 
    539 # resolve_project()
    540 # get project specific information
    541 sub resolve_project {
    542     my $ipprc = shift;
    543     my $project_name = shift;
    544     my $dbname = shift;
    545     my $dbserver = shift;
    546     die "project is not defined" if !$project_name;
    547 
    548     my $verbose = 0;
    549 
    550     my $missing_tools;
    551     my $pstamptool = can_run("pstamptool") or (warn "Can't find pstamptool" and $missing_tools = 1);
    552     if ($missing_tools) {
    553         warn("Can't find required tools.");
    554         exit ($PS_EXIT_CONFIG_ERROR);
    555     }
    556 
    557     my $command = "$pstamptool -project -name $project_name";
    558     $command .= " -dbname $dbname" if defined $dbname;
    559     $command .= " -dbserver $dbserver" if defined $dbserver;
    560     # run the tool and parse the output
    561     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    562                 run(command => $command, verbose => $verbose);
    563     unless ($success) {
    564         print STDERR @$stderr_buf;
    565         return undef;
    566     }
    567 
    568     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    569 
    570     my $output = join "", @$stdout_buf;
    571     if (!$output) {
    572         print STDERR "no output returned from $command\n" if $verbose;
    573         return undef;
    574     }
    575     my $proj_hash = parse_md_fast($mdcParser, $output);
    576 
    577     return $proj_hash->[0];
     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;
    5781306}
    57913071;
Note: See TracChangeset for help on using the changeset viewer.