IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

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

updates from trunk

Location:
branches/simtest_nebulous_branches
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/simtest_nebulous_branches

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

    r24968 r27840  
    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 );
    2628use Carp;
    27 
    28 ### my @images = locate_images($image_db, $req_type, $img_type, $id, $component,
    29 ###            $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);
    3048
    3149sub locate_images {
    3250    my $ipprc    = shift;   # required
    33     my $image_db = shift;   # required
     51    my $imagedb = shift;   # required
     52    my $rowList  = shift;   # required
    3453    my $req_type = shift;   # required
    3554    my $img_type = shift;   # required
    36     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;
    3757    my $component= shift;   # class_id or skycell_id
    38     my $x        = shift;
    39     my $y        = shift;
     58    my $option_mask  = shift;
     59    my $need_magic = shift;
    4060    my $mjd_min  = shift;
    4161    my $mjd_max  = shift;
    4262    my $filter   = shift;
     63    my $data_group = shift;
    4364    my $verbose  = shift;
    4465
    4566    # we die in response to bad data in request files
    46     die "Unknown req_type: $req_type" if ($req_type ne "byid") and ($req_type ne "byexp")
    47                                         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
    48105    if (($req_type eq "byid") and ($img_type eq "diff")) {
    49106        # lookups of all of the information for diff images requires a two level lookup to
     
    51108        # in one place
    52109        $req_type = "bydiff";
    53     }
     110        my $results = lookup_diff($ipprc, $rowList, $imagedb, $id, $component, 1, $option_mask, $img_type, $verbose);
     111        return $results;
     112    }
     113
    54114    if ($req_type eq "bydiff") {
    55         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);
    56118        if (!$results) {
    57119            return undef;
    58120        }
    59         if (($img_type eq "warp") or ($img_type eq "diff")) {
    60             # lookup_bydiff has done all of the work
    61             return [$results];
    62         } elsif (($img_type eq "raw") or ($img_type eq "chip")) {
    63             $req_type = "byexp";
    64             $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};
    65130            return undef if !$id;
    66             # fall through and lookup byexp
    67 #        } elsif ($img_type eq "warp") {
    68 #            $req_type = "byid";
    69 #            $id = $results->{warp_id};
    70 #            $component = $results->{skycell_id};
    71 #            return undef if !$id;
    72 #            # 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
    73143        } elsif ($img_type eq "stack") {
    74144            $req_type = "byid";
    75             $id = $results->{stack_id};
     145            $id = $image->{stack_id};
    76146            return undef if !$id;
    77             # fall though and lookup by stack id
     147            # fall though and lookup by stack_id
    78148        } else {
    79             # shouldn't I check this elsewhere?
     149            # This is checked this elsewhere?
    80150            print STDERR "Error: $img_type is an unknown image type\n";
    81151            return undef;
    82152        }
    83 
    84     } elsif ($req_type eq "bycoord") {
    85 
    86         # run
    87         # regtool -dbname $image_db -processedimfile -time_begin $mjd_min -time_end = $mjd_max -filter $filter
    88         #
    89         my $results = lookup_bycoord($ipprc, $image_db, $x, $y, $mjd_min, $mjd_max, $filter, $verbose);
    90 
    91         # now take the results and lookup byexp
    92         # XXX: This needs work. What stops results from returning multiple images????
    93         # We should loop over the set of images returned building up the full results array
    94         $req_type = "byexp";
    95         $id = $results->{exp_name};
    96     }
    97 
    98     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);
    99166
    100167    return $results;
    101168}
    102169
    103 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{
    104175    my $ipprc    = shift;
    105     my $image_db = shift;
     176    my $rowList    = shift;
     177    my $imagedb = shift;
    106178    my $req_type = shift;
    107     my $img_type = shift;
     179    my $stage = shift;
    108180    my $id       = shift;
     181    my $tess_id  = shift;
    109182    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;
    110189    my $verbose  = shift;
    111190
    112     my $missing_tools;
    113     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    114     my $chiptool = can_run('chiptool') or (warn "Can't find chiptool" and $missing_tools = 1);
    115     my $warptool = can_run('warptool') or (warn "Can't find warptool" and $missing_tools = 1);
    116     my $difftool = can_run('difftool') or (warn "Can't find difftool" and $missing_tools = 1);
    117     my $stacktool = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
    118     if ($missing_tools) {
    119         warn("Can't find required tools.");
    120         exit ($PS_EXIT_CONFIG_ERROR);
    121     }
     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
    122195    my $command;
    123196    my $id_opt;     # option for the lookup
     
    125198    my $mask_name;
    126199    my $weight_name;
     200    my $cmf_name;
     201    my $psf_name;
     202    my $backmdl_name;
    127203    my $base_name;
    128204    my $want_astrom;
     
    131207    my $skycell_id;
    132208
    133     # special class_id value "null" means ignore
    134     if ($component and ($component eq "null")) {
     209    if (isnull($component)) {
    135210        $component = undef;
    136211    }
    137212
    138     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") {
    139222        $class_id = $component;
    140         $command = "$regtool -processedimfile -dbname $image_db";
    141         $id_opt = "-exp_id";
    142         $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;
    143229        $want_astrom = 1;
    144230        $set_class_id = 1;
    145     } elsif ($img_type eq "chip") {
     231    } elsif ($stage eq "chip") {
    146232        $class_id = $component;
    147         $command = "$chiptool -processedimfile -dbname $image_db";
    148         $command .= " -class_id $class_id" if $class_id;
    149         $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.
    150247        $image_name   = "PPIMAGE.CHIP";
    151248        $mask_name    = "PPIMAGE.CHIP.MASK";
    152249        $weight_name  = "PPIMAGE.CHIP.VARIANCE";
     250        $cmf_name     = "PSPHOT.OUTPUT";
     251        $psf_name     = "PSPHOT.PSF.SAVE";
     252        $backmdl_name = "PSPHOT.BACKMDL";
    153253        $base_name    = "path_base"; # name of the field for the chiptool output
    154254        $want_astrom  = 1;
    155255        $set_class_id = 1;
    156     } elsif ($img_type eq "warp") {
     256    } elsif ($stage eq "warp") {
    157257        $skycell_id = $component;
    158         $command = "$warptool -warped -dbname $image_db";
    159         $command .= " -skycell_id $skycell_id" if $skycell_id;
    160         $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";
    161266        $image_name   = "PSWARP.OUTPUT";
    162267        $mask_name    = "PSWARP.OUTPUT.MASK";
    163268        $weight_name  = "PSWARP.OUTPUT.VARIANCE";
     269        $cmf_name     = "PSWARP.OUTPUT.SOURCES";
     270        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    164271        $base_name    = "path_base"; # name of the field for the warptool output
    165     } elsif ($img_type eq "diff") {
     272    } elsif ($stage eq "diff") {
    166273        $skycell_id = $component;
    167         $command = "$difftool -diffskyfile -dbname $image_db";
    168         $command .= " -skycell_id $skycell_id" if $skycell_id;
    169         $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";
    170282        $image_name  = "PPSUB.OUTPUT";
    171283        $mask_name   = "PPSUB.OUTPUT.MASK";
    172284        $weight_name = "PPSUB.OUTPUT.VARIANCE";
     285        $cmf_name    = "PPSUB.OUTPUT.SOURCES";
     286        $psf_name     = "PSPHOT.PSF.SKY.SAVE";
    173287        $base_name   = "path_base";
    174     } elsif ($img_type eq "stack") {
    175         $command = "$stacktool -sumskyfile -dbname $image_db";
     288    } elsif ($stage eq "stack") {
     289        $skycell_id = $component;
     290        $command = "$stacktool -sumskyfile -dbname $imagedb";
    176291        $id_opt = "-stack_id";
    177 
    178         $image_name  = "PPSTACK.OUTPUT";
    179         $mask_name   = "PPSTACK.OUTPUT.MASK";
    180         $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";
    181308        $base_name   = "path_base";
    182309    } else {
    183         die "Unknown img_type supplied: $img_type";
    184     }
    185 
     310        die "Unknown IMG_TYPe supplied: $stage";
     311    }
     312
     313    my $filter_runs = 0;
    186314    if ($req_type eq "byid") {
    187315        $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 = "";
    188321    } elsif ($req_type eq "byexp") {
    189322        $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";
    190332    } else {
    191         die "Unknown req_type supplied: $req_type";
    192     }
    193 
    194     # 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
    1951232    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    1961233                run(command => $command, verbose => $verbose);
     
    2011238    }
    2021239
     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
    2031244    my $buf = join "", @$stdout_buf;
    2041245    if (!$buf) {
    205         return;
    206     }
     1246        return undef;
     1247    }
     1248
     1249    my $start_parse = DateTime->now->mjd;
    2071250
    2081251    my $mdcParser = PS::IPP::Metadata::Config->new;
    209     my $images = parse_md_fast($mdcParser, $buf)
     1252    my $results = parse_md_fast($mdcParser, $buf)
    2101253        or die ("Unable to parse metadata config doc");
    2111254
    212     my $output = [];
    213 
    214     my $camera;
    215     foreach my $image (@$images) {
    216         my $base;
    217 
    218         next if $image->{fault};
    219         next if ($img_type ne "raw") and $image->{quality};
    220 
    221         if ($base_name) {
    222             $base = $image->{$base_name};
    223             # if base is undef then the output pruducts for this image are incomplete
    224             # This may only happen for warps. (Actually the test for ignored that I added
    225             # just above probably solved the problem I was trying to solve with this test)
    226             next if !$base;
    227         }
    228         if (!$camera) {
    229             # This assumes that all images have the same camera
    230             $camera = $image->{camera};
    231             $ipprc->define_camera($camera);
    232         }
    233         my $out = $image;
    234 
    235         # if uri is nil this will get overridded below
    236         # (this is for raw stage)
    237         $out->{image}  = $image->{uri};
    238         if ($set_class_id) {
    239             $class_id = $image->{class_id};
    240             $out->{component} = $class_id;
    241         }
    242 
    243         # find the mask and weight images
    244         if ($base) {
    245             $out->{image}  = $ipprc->filename($image_name,   $base, $class_id) if $image_name;
    246             $out->{mask}   = $ipprc->filename($mask_name,   $base, $class_id) if $mask_name;
    247             $out->{weight} = $ipprc->filename($weight_name, $base, $class_id) if $weight_name;
    248         }
    249         $out->{astrom} = find_astrometry($ipprc, $image_db, $image, $verbose) if $want_astrom;
    250 
    251         push @$output, $out;
    252     }
    253 
    254     return $output;
    255 }
    256 sub lookup_bydiff {
    257     my $ipprc    = shift;
    258     my $image_db = shift;
    259     my $id       = shift;
    260     my $img_type = shift;
    261     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);
    2621263
    2631264    my $missing_tools;
    264     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);
    2651276    if ($missing_tools) {
    2661277        warn("Can't find required tools.");
    2671278        exit ($PS_EXIT_CONFIG_ERROR);
    2681279    }
    269 
    270     my $command = "$difftool -diffskyfile -diff_image_id $id -dbname $image_db";
    271 
    272     # run the tool and parse the output
    273     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    274                 run(command => $command, verbose => $verbose);
    275     unless ($success) {
    276         # not sure if we should die here
    277         print STDERR @$stderr_buf;
    278         return undef;
    279     }
    280 
    281     my $buf = join "", @$stdout_buf;
    282     if (!$buf) {
    283         return undef;
    284     }
    285 
    286     my $mdcParser = PS::IPP::Metadata::Config->new;
    287     my $images = parse_md_fast($mdcParser, $buf)
    288         or die ("Unable to parse metadata config doc");
    289 
    290     my $n = @$images;
    291     if ($n > 1) {
    292         die ("difftool returned an unexpected number of diffskyfiles: $n");
    293     } elsif ($n == 0) {
    294         return undef;
    295     }
    296 
    297     my $image = $images->[0];
    298 
    299     my $skycell_id = $image->{skycell_id};
    300 
    301     if ($image->{fault}) {
    302         print STDERR "selected difference image $id $image->{diff_id} $skycell_id has fault: $image->{fault}\n";
    303         return undef;
    304     }
    305 
    306     # The standard way to do a diff is warp - stack
    307     # so we interpret the requested image in that way
    308 
    309     my $stack_id = $image->{stack2};
    310     # XXX difftool currently returns max long long for null
    311     # this line is ready if we switch the code to return zero for null
    312     if ($stack_id and ($stack_id != 9223372036854775807)) {
    313         $image->{stack_id} = $stack_id;
    314     }
    315 
    316     my $warp_id =  $image->{warp1};
    317     # XXX difftool currently returns max long long for null
    318     # this line is ready if we switch the code to return zero for null
    319     if ($warp_id and ($warp_id != 9223372036854775807)) {
    320         $image->{warp_id} = $warp_id;
    321 
    322         ## now use the warp and go get the exposure information
    323         $command = "warptool -warped -warp_id $warp_id -skycell_id $skycell_id -dbname $image_db -limit 1";
    324         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    325                     run(command => $command, verbose => $verbose);
    326         unless ($success) {
    327             # not sure if we should die here
    328             print STDERR @$stderr_buf;
    329             return undef;
    330         }
    331 
    332         my $buf = join "", @$stdout_buf;
    333         if (!$buf) {
    334             return undef;
    335         }
    336 
    337         my $mdcParser = PS::IPP::Metadata::Config->new;
    338         my $warps = parse_md_fast($mdcParser, $buf)
    339             or die ("Unable to parse metadata config doc");
    340         my $warp = $warps->[0];
    341 
    342         if ($img_type eq "warp") {
    343             $image = $warp;
    344         } else {
    345             $image->{exp_id} = $warp->{exp_id};
    346             $image->{exp_name} = $warp->{exp_name};
    347             $image->{camera} = $warp->{camera};
    348         }
    349     }
    350 
    351     if (($img_type eq "diff") or ($img_type eq "warp")) {
    352         # the $image is going to be returned directly in this case so we need to duplicate
    353         # some of processing that lookup does for other img_types
    354         $image->{image} = $image->{uri};
    355         if ($image->{camera}) {
    356             $ipprc->define_camera($image->{camera});
    357             if ($img_type eq "diff") {
    358                 $image->{mask}   = $ipprc->filename("PPSUB.OUTPUT.MASK", $image->{path_base});
    359                 $image->{weight} = $ipprc->filename("PPSUB.OUTPUT.VARIANCE", $image->{path_base});
    360             } else {
    361                 $image->{mask}   = $ipprc->filename("PSWARP.OUTPUT.MASK",   $image->{path_base});
    362                 $image->{weight} = $ipprc->filename("PSWARP.OUTPUT.VARIANCE", $image->{path_base});
    363             }
    364         } else {
    365             # XXX this will only happen if the minuend is not a warp
    366             print STDERR "WARNING: cannot resolve camera so cannot get weight and mask images\n";
    367         }
    368     }
    369 
    370     return $image;
    371 }
    372 
    373 sub lookup_bycoord {
    374     my $ipprc    = shift;
    375     my $image_db = shift;
    376     my $x        = shift;
    377     my $y        = shift;
    378     my $mjd_min  = shift;
    379     my $mjd_max  = shift;
    380     my $filter   = shift;
    381     my $verbose  = shift;
    382 
    383     my $missing_tools;
    384     my $regtool = can_run('regtool') or (warn "Can't find regtool" and $missing_tools = 1);
    385     if ($missing_tools) {
    386         warn("Can't find required tools.");
    387         exit ($PS_EXIT_CONFIG_ERROR);
    388     }
    389 
    390     # XXX TODO:
    391     # Full lookups by coordinate require looking at the DVO database. However,
    392     # dateobs and filter which is all that MOPS has asked for.
    393 
    394     my $args;
    395     if ($mjd_min) {
    396         my $dateobs_min = mjd_to_dateobs($mjd_min);
    397         $args .= " -dateobs_begin $dateobs_min";
    398     }
    399     if ($mjd_max) {
    400         my $dateobs_max = mjd_to_dateobs($mjd_max);
    401         $args .= " -dateobs_end $dateobs_max";
    402     }
    403     if ($filter) {
    404         $args .= " -filter $filter";
    405     }
    406 
    407     if (!$args) {
    408         # avoid returning every exposure in the DB
    409         print STDERR "no query arguments provided for bycoord\n";
    410         return undef;
    411     }
    412 
    413     # XXX TODO: This query doesn't work Something appears to be out of
    414     # sync about the times I'm passing and what regtool and or the DB expect
    415     # the query I used in the C version of locateimages used
    416     # WHERE dateobs >= FROM_UNIXTIME(%ld) AND dateobs <= FROM_UNIXTIME(%ld + exp_time)
    417 
    418     my $command = "$regtool -processedexp -dbname $image_db $args";
    419 
    420     # run the tool and parse the output
    421     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    422                 run(command => $command, verbose => $verbose);
    423     unless ($success) {
    424         # not sure if we should die here
    425         print STDERR @$stderr_buf;
    426         return undef;
    427     }
    428     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    429 
    430     my $output = join "", @$stdout_buf;
    431     if (!$output) {
    432         print STDERR "no output returned from $command\n" if $verbose;
    433         return undef;
    434     }
    435     my $images = parse_md_fast($mdcParser, $output) or die ("Unable to parse metadata config doc");
    436 
    437     return $images;
    438 }
    439 
    440 # cache of results of ppConfigDump
    441 my %astromSources;
    442 my $last_exp_id = 0;
    443 my $lastAstromFile;
    444 
    445 # find the astrometry file for a given exposure
    446 # return undef if no completed camRun exists
    447 sub find_astrometry {
    448     my $ipprc = shift;
    449     my $image_db = shift;
    450     my $image = shift;      # hashref to output of the lookup tool
    451     my $verbose = shift;
    452 
    453     my $exp_id = $image->{exp_id};
    454     if (($exp_id eq $last_exp_id) and $lastAstromFile) {
    455         # running camtool 60 times is really expensive when the answer is the same
    456         return $lastAstromFile;
    457     }
    458     $last_exp_id = 0;
    459     $lastAstromFile = undef;
    460 
    461     my $missing_tools;
    462     my $camtool = can_run("camtool") or (warn "Can't find camtool" and $missing_tools = 1);
    463     my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
    464     if ($missing_tools) {
    465         warn("Can't find required tools.");
    466         exit ($PS_EXIT_CONFIG_ERROR);
    467     }
    468 
    469     my $command = "$camtool -dbname $image_db -processedexp -exp_id $exp_id";
    470     # run the tool and parse the output
    471     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    472                 run(command => $command, verbose => $verbose);
    473     unless ($success) {
    474         print STDERR @$stderr_buf;
    475         return undef;
    476     }
    477 
    478     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    479 
    480     my $output = join "", @$stdout_buf;
    481     if (!$output) {
    482         print STDERR "no output returned from $command\n" if $verbose;
    483         return undef;
    484     }
    485     my $camruns = parse_md_fast($mdcParser, $output);
    486     if (!$camruns) {
    487         return undef;
    488     }
    489 
    490     # If there are multiple cam runs for this exposure, take the last one
    491     # assuming that it has the best astrometry
    492     my $camdata = pop @$camruns;
    493     if (!$camdata) {
    494         # no cam runs for this exposure id therefore best astrometry is whatever is in the header
    495         return undef;
    496     }
    497     my $camRoot = $camdata->{path_base};
    498     my $camera = $image->{camera};
    499     my $astromSource = $astromSources{$camera};
    500     if (!$astromSource) {
    501        my $command = "$ppConfigDump -camera $camera -dump-recipe PSWARP -";
    502         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    503             run(command => $command, verbose => $verbose);
    504         unless ($success) {
    505             $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
    506             die("Unable to perform ppConfigDump: $error_code");
    507         }
    508         my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
    509             die("Unable to parse metadata config doc");
    510         $astromSource = metadataLookupStr($metadata, 'ASTROM.SOURCE');
    511         $astromSources{$camera} = $astromSource;
    512     }
    513 
    514     my $astromFile = $ipprc->filename($astromSource, $camRoot);
    515     if ($astromFile) {
    516         $lastAstromFile = $astromFile;
    517         $last_exp_id = $exp_id;
    518     }
    519 
    520     return $astromFile;
    521 }
    522 
    523 # splits meta data config input stream into single units to work around the pathalogically
    524 # slow parser. This is similar to and adapted from code in various ippScripts.
    525 sub parse_md_fast {
    526     my $mdcParser = shift;
    527     my $input = shift;
    528     my $output = ();
    529 
    530     my @whole = split /\n/, $input;
    531     my @single = ();
    532 
    533     my $n;
    534     while ( ($n = @whole) > 0) {
    535         my $value = shift @whole;
    536         push @single, $value;
    537         if ($value =~ /^\s*END\s*$/) {
    538             push @single, "\n";
    539 
    540             my $list = parse_md_list( $mdcParser->parse( join("\n", @single ) ) ) or
    541                 print STDERR "Unable to parse metdata config doc" and return undef;
    542 #            my $num = @$list;
    543 #            print STDERR "list has $num elments\n";
    544             push @$output, $list->[0];
    545 
    546             @single = ();
    547         }
    548     }
    549     return $output;
    550 }
    551 
    552 sub mjd_to_dateobs {
    553     my $mjd = shift;
    554 
    555     my $ticks = ($mjd - 40587.0) * 86400;
    556 
    557     my ($sec, $min, $hr, $day, $mon, $year) = gmtime($ticks);
    558 
    559     return sprintf "'%4d-%02d-%02d %02d:%02d:%02d'", $year+1900, $mon+1, $day, $hr, $min, $sec;
    560 }
    561 
    562 # resolve_project()
    563 # get project specific information
    564 my $last_project = "";
    565 sub resolve_project {
    566     my $ipprc = shift;
    567     my $project_name = shift;
    568 
    569     if (!$project_name) {
    570         carp ("project is not defined");
    571         return undef;
    572     }
    573 
    574     if ($project_name eq $last_project) {
    575         return $last_project;
    576     }
    577 
    578     my $dbname = shift;
    579     my $dbserver = shift;
    580 
    581     my $verbose = 0;
    582 
    583     my $missing_tools;
    584     my $pstamptool = can_run("pstamptool") or (warn "Can't find pstamptool" and $missing_tools = 1);
    585     if ($missing_tools) {
    586         warn("Can't find required tools.");
    587         exit ($PS_EXIT_CONFIG_ERROR);
    588     }
    589 
    590     my $command = "$pstamptool -project -name $project_name";
    591     $command .= " -dbname $dbname" if defined $dbname;
    592     $command .= " -dbserver $dbserver" if defined $dbserver;
    593     # run the tool and parse the output
    594     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    595                 run(command => $command, verbose => $verbose);
    596     unless ($success) {
    597         print STDERR @$stderr_buf;
    598         return undef;
    599     }
    600 
    601     my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
    602 
    603     my $output = join "", @$stdout_buf;
    604     if (!$output) {
    605         print STDERR "no output returned from $command\n" if $verbose;
    606         return undef;
    607     }
    608     my $proj_hash = parse_md_fast($mdcParser, $output);
    609 
    610     $last_project = $proj_hash->[0];
    611 
    612     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;
    6131306}
    61413071;
Note: See TracChangeset for help on using the changeset viewer.