IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25256


Ignore:
Timestamp:
Sep 2, 2009, 2:36:52 PM (17 years ago)
Author:
Paul Price
Message:

Merging branches/pap_mops into trunk. ppMops now merges multiple skycells, and these get published for MOPS as a single file per exposure. Tested and works.

Location:
trunk
Files:
1 deleted
24 edited
5 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/dbconfig/changes.txt

    r25014 r25256  
    12061206ALTER TABLE magicDSRun ADD COLUMN inv_magic_id BIGINT AFTER magic_id;
    12071207ALTER TABLE magicDSRun ADD FOREIGN KEY (inv_magic_id) REFERENCES magicRun(magic_id);
     1208
     1209-- Adding columns for debugging publishing problems
     1210
     1211ALTER TABLE publishDone ADD COLUMN hostname VARCHAR(64) AFTER path_base;
     1212ALTER TABLE publishDone ADD COLUMN dtime_script FLOAT AFTER hostname;
  • trunk/dbconfig/publish.md

    r24512 r25256  
    11# Tables for publishing data to a science client
    22
    3 publishClient   METADATA
    4     client_id   S64         0       # Primary Key AUTO_INCREMENT
    5     product     STR         64
    6     stage       STR         64
    7     workdir     STR         255
    8     comment     STR         255
     3publishClient    METADATA
     4    client_id    S64         0       # Primary Key AUTO_INCREMENT
     5    product      STR         64
     6    stage        STR         64
     7    workdir      STR         255
     8    comment      STR         255
     9END             
     10                 
     11publishRun       METADATA
     12    pub_id       S64         0       # Primary Key AUTO_INCREMENT
     13    client_id    S64         0
     14    stage_id     S64         0
     15    label        STR         64
     16    state        STR         64
     17END             
     18                 
     19publishDone      METADATA
     20    pub_id       S64         0       # Primary Key
     21    path_base    STR         255
     22    hostname     STR         64
     23    dtime_script F32         0.0
     24    fault        S16         0
    925END
    10 
    11 publishRun      METADATA
    12     pub_id      S64         0       # Primary Key AUTO_INCREMENT
    13     client_id   S64         0
    14     stage_id    S64         0
    15     label       STR         64
    16     state       STR         64
    17 END
    18 
    19 publishDone     METADATA
    20     pub_id      S64         0       # Primary Key
    21     path_base   STR         255
    22     fault       S16         0
    23 END
  • trunk/doc/misc/docgen.pl

    • Property svn:mergeinfo changed (with no actual effect on merging)
  • trunk/ippScripts/scripts/magic_destreak_revert.pl

  • trunk/ippScripts/scripts/publish_file.pl

    r25100 r25256  
    3939
    4040# Parse the command-line arguments
    41 my ( $pub_id, $camera, $stage, $stage_id, $format, $product, $workdir );
    42 my ( $dbname, $verbose, $no_update, $save_temps, $redirect );
     41my ( $pub_id, $camera, $stage, $stage_id, $fileset, $format, $product, $workdir );
     42my ( $dbname, $verbose, $no_update, $no_op, $save_temps, $redirect );
    4343
    4444GetOptions(
     
    4848    'stage_id=s'        => \$stage_id,    # Stage identifier
    4949    'product=s'         => \$product,     # Datastore product name
     50    'fileset=s'         => \$fileset,     # Fileset name
    5051    'workdir=s'         => \$workdir,     # Working directory
    5152    'dbname=s'          => \$dbname,    # Database name
    5253    'verbose'           => \$verbose,   # Print to stdout
    5354    'no-update'         => \$no_update, # Don't update the database?
     55    'no-op'             => \$no_op, # Don't do any operations
    5456    'save-temps'        => \$save_temps, # Save temporary files?
    5557    'redirect-output'   => \$redirect,   # Redirect output to log file?
     
    7779my $mdcParser = PS::IPP::Metadata::Config->new;
    7880
    79 
    80 # Retrieve file name of interest
    81 my %files;                      # Input filenames
    82 my %zp;                         # Zero points
    83 my %exp_id;                     # Exposure identifiers
    84 my %exp_name;                   # Exposure names
    85 my %direction;                  # Direction of subtraction
    86 {
    87     my $command;                # Command to run
    88 
    89     if ($stage eq 'diff') {
    90         $command =  "difftool -diffskyfile -diff_id $stage_id";
    91     } elsif ($stage eq 'camera') {
    92         $command =  "camtool -processedexp -cam_id $stage_id";
    93     } else {
    94         &my_die( "Unrecognised stage: $stage", $pub_id, $PS_EXIT_CONFIG_ERROR );
    95     }
     81my ($dsFile, $dsFileName) = tempfile("/tmp/publish.$pub_id.ds.XXXX", UNLINK => !$save_temps );
     82
     83if ($stage eq 'camera') {
     84    my $command =  "camtool -processedexp -cam_id $stage_id";
    9685    $command .= " -dbname $dbname" if defined $dbname;
    97 
    9886    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    9987        run(command => $command, verbose => $verbose);
     
    10694        &my_die("Unable to parse metadata list", $pub_id, $PS_EXIT_PROG_ERROR);
    10795
     96    &my_die("More than one entry for cam_id $stage_id", $pub_id, $PS_EXIT_PROG_ERROR) if scalar @$components > 1;
     97
     98    my $comp = $$components[0]; # Component of interest
     99    my $path_base = $comp->{path_base}; # Base name for file
     100    my $file = $ipprc->filename( "PSASTRO.OUTPUT", $path_base );
     101    $file = $ipprc->file_resolve($file);
     102    my $cam_id = $comp->{cam_id};
     103    my $name = "cam_$cam_id";
     104    print $dsFile "$file|||$product|$name|\n";
     105} elsif ($stage eq 'diff') {
     106    my $command =  "difftool -diffskyfile -diff_id $stage_id";
     107    $command .= " -dbname $dbname" if defined $dbname;
     108    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     109        run(command => $command, verbose => $verbose);
     110    &my_die( "Unable to retrieve filename", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
     111
     112    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
     113        &my_die("Unable to parse metadata config", $pub_id, $PS_EXIT_PROG_ERROR);
     114
     115    my $components = parse_md_list($metadata) or
     116        &my_die("Unable to parse metadata list", $pub_id, $PS_EXIT_PROG_ERROR);
     117
     118    my ($mopsPositiveFile, $mopsPositiveFileName) = tempfile("/tmp/publish.$pub_id.mops.pos.XXXX", UNLINK => !$save_temps ) if $product eq 'IPP-MOPS';
     119    my ($mopsNegativeFile, $mopsNegativeFileName) = tempfile("/tmp/publish.$pub_id.mops.neg.XXXX", UNLINK => !$save_temps ) if $product eq 'IPP-MOPS';
     120
     121    my %positive;               # Data for positive diff detections
     122    my %negative;               # Data for negative diff detections
    108123    foreach my $comp ( @$components ) {
    109124        my $path_base = $comp->{path_base}; # Base name for file
     
    112127        (carp "Bad zpt_obs or exp_time for component" and next) if not defined $comp->{zpt_obs} or not defined $comp->{exp_time};
    113128        my $zp = $comp->{zpt_obs} + 2.5 * log($comp->{exp_time}) / log(10);
    114 
    115         if ($stage eq 'diff') {
    116             my $skycell_id = $comp->{skycell_id};
    117 
    118             # Positive direction
    119             $files{"$skycell_id.pos"} = $ipprc->filename( "PPSUB.OUTPUT.SOURCES", $path_base );
    120             $zp{"$skycell_id.pos"} = $zp;
    121             $exp_id{"$skycell_id.pos"} = $comp->{exp_id_1};
    122             $exp_name{"$skycell_id.pos"} = $comp->{exp_name_1};
    123             $direction{"$skycell_id.pos"} = 1;
    124 
    125             # Negative direction
    126             if (defined $comp->{bothways} and $comp->{bothways}) {
    127                 $files{"$skycell_id.neg"} = $ipprc->filename( "PPSUB.INVERSE.SOURCES", $path_base );
    128                 $zp{"$skycell_id.neg"} = $zp;
    129                 $exp_id{"$skycell_id.neg"} = $comp->{exp_id_2};
    130                 $direction{"$skycell_id.neg"} = 0;
    131                 $exp_name{"$skycell_id.neg"} = $comp->{exp_name_2};
     129        my $astrom = sqrt($comp->{sigma_ra_1}**2 + $comp->{sigma_dec_1}**2);
     130
     131        my $skycell_id = $comp->{skycell_id};
     132        my $filename = $ipprc->filename( "PPSUB.OUTPUT.SOURCES", $path_base );
     133        $filename = $ipprc->file_resolve($filename);
     134
     135        my $data = { zp => $zp,
     136                     zp_err => $comp->{zpt_stdev},
     137                     astrom => sqrt($comp->{sigma_ra_1}**2 + $comp->{sigma_dec_1}**2),
     138                     exp_name => $comp->{exp_name_1},
     139                     exp_id => $comp->{exp_id_1},
     140                     chip_id => $comp->{chip_id_1},
     141                     cam_id => $comp->{cam_id_1},
     142                     fake_id => $comp->{fake_id_1},
     143                     warp_id => $comp->{warp1},
     144                     diff_id => $comp->{diff_id},
     145                     direction => 1,
     146        };
     147
     148        diff_check(\%positive, $data, "positive");
     149
     150        if ($product eq 'IPP-MOPS') {
     151            print $mopsPositiveFile "$filename\n";
     152        } else {
     153            print $dsFile "$filename|||$product|${skycell_id}.pos|\n";
     154        }
     155
     156        # Negative direction
     157        if (defined $comp->{bothways} and $comp->{bothways}) {
     158            my $filename = $ipprc->filename( "PPSUB.INVERSE.SOURCES", $path_base );
     159            $filename = $ipprc->file_resolve($filename);
     160
     161            my $data = { zp => $zp,
     162                         zp_err => $comp->{zpt_stdev},
     163                         astrom => sqrt($comp->{sigma_ra_2}**2 + $comp->{sigma_dec_2}**2),
     164                         exp_name => $comp->{exp_name_2},
     165                         exp_id => $comp->{exp_id_2},
     166                         chip_id => $comp->{chip_id_2},
     167                         cam_id => $comp->{cam_id_2},
     168                         fake_id => $comp->{fake_id_2},
     169                         warp_id => $comp->{warp2},
     170                         diff_id => $comp->{diff_id},
     171                         direction => 0,
     172            };
     173
     174            diff_check(\%negative, $data, "negative");
     175
     176            if ($product eq 'IPP-MOPS') {
     177                print $mopsNegativeFile "$filename\n";
     178            } else {
     179                print $dsFile "$filename|||$product|${skycell_id}.neg|\n";
    132180            }
    133 
    134         } elsif ($stage eq 'camera') {
    135             my $cam_id = $comp->{cam_id};
    136             $files{$cam_id} = $ipprc->filename( "PSASTRO.OUTPUT", $path_base );
    137             $zp{$cam_id} = $zp;
    138             $exp_id{$cam_id} = $comp->{exp_id};
    139             $exp_name{$cam_id} = $comp->{exp_name};
    140             $direction{$cam_id} = 1;
    141181        }
    142182    }
    143 }
    144 
    145 # Prepare for data store input
    146 my ($listFile, $listFileName) = tempfile("/tmp/publish.$pub_id.list.XXXX", UNLINK => !$save_temps );
    147 
    148 # Process each file
    149 foreach my $comp ( keys %files ) {
    150     my $file = $ipprc->file_resolve( $files{$comp} ) or
    151         &my_die("Unable to resolve file $files{$comp}", $pub_id, $PS_EXIT_SYS_ERROR);
    152     my_die("Unable to find file $file", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $file );
    153 
    154     my $zp = $zp{$comp};
    155     my $exp_id = $exp_id{$comp};
    156     my $exp_name = $exp_name{$comp};
    157     my $direction = $direction{$comp};
    158     if ($product eq "IPP-MOPS") {
    159         my $outuri = "$outroot.$comp.fits";
    160         my $out = $ipprc->file_resolve( $outuri, 'create' ) or
    161             &my_die( "Unable to resolve output file $outuri", $pub_id, $PS_EXIT_SYS_ERROR);
    162 
    163         my $command = "$ppMops $file $zp $exp_id $exp_name $direction $out";
    164         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
    165             run(command => $command, verbose => $verbose);
    166         &my_die( "Unable to translate $file", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
    167         &my_die( "Unable to find translated file $out", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $out );
    168         $file = $out;
     183
     184    close $mopsPositiveFile;
     185    close $mopsNegativeFile;
     186
     187    if ($product eq 'IPP-MOPS') {
     188        if (scalar keys %positive > 0) {
     189            my $output = mops_combine(\%positive, "$outroot.pos.mops", $mopsPositiveFileName);
     190            print $dsFile "$output|||$product|positive|\n";
     191        }
     192        if (scalar keys %negative > 0) {
     193            my $output = mops_combine(\%negative, "$outroot.neg.mops", $mopsNegativeFileName);
     194            print $dsFile "$output|||$product|negative|\n";
     195        }
    169196    }
    170 
    171     # format: filename|filesize|md5sum|filetype|
    172     # note: since we omit filesize and md5sum, dsreg will calculate them
    173     print $listFile "$file|||$product|$comp|\n";
    174 }
    175 
     197}
     198
     199close $dsFile;
    176200
    177201unless ($no_update) {
    178     my $command = "$dsreg --add $stage.$stage_id --copy --abspath --product $product --type $product --list $listFileName";
     202    my $command = "$dsreg --add $stage.$stage_id --copy --abspath --product $product --type $product --list $dsFileName";
    179203
    180204    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     
    185209unless ($no_update) {
    186210    my $command = "$pubtool -add -pub_id $pub_id -path_base $outroot";
     211    $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
     212    $command .= " -hostname $host" if defined $host;
     213
    187214    $command .= " -dbname $dbname" if defined $dbname;
    188215
     
    195222
    196223### Pau.
     224
     225# Check inputs for a diff
     226sub diff_check
     227{
     228    my $data = shift;           # Data hash
     229    my $comp = shift;           # Component data
     230    my $name = shift;           # Name of component
     231
     232    $data->{zp} = $comp->{zp} unless defined $data->{zp};
     233    $data->{zp_err} = $comp->{zp_err} unless defined $data->{zp_err};
     234    $data->{astrom} = $comp->{astrom} unless defined $data->{astrom};
     235    $data->{exp_name} = $comp->{exp_name} unless defined $data->{exp_name};
     236    $data->{exp_id} = $comp->{exp_id} unless defined $data->{exp_id};
     237    $data->{chip_id} = $comp->{chip_id} unless defined $data->{chip_id};
     238    $data->{cam_id} = $comp->{cam_id} unless defined $data->{cam_id};
     239    $data->{fake_id} = $comp->{fake_id} unless defined $data->{fake_id};
     240    $data->{warp_id} = $comp->{warp_id} unless defined $data->{warp_id};
     241    $data->{diff_id} = $comp->{diff_id} unless defined $data->{diff_id};
     242    $data->{direction} = $comp->{direction} unless defined $data->{direction};
     243
     244    &my_die("zp value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{zp} and $comp->{zp} != $data->{zp};
     245    &my_die("zp_err value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{zp_err} and $comp->{zp_err} != $data->{zp_err};
     246    &my_die("astrom value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{astrom} and $comp->{astrom} != $data->{astrom};
     247    &my_die("exp_name value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{exp_name} and $comp->{exp_name} ne $data->{exp_name};
     248    &my_die("exp_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{exp_id} and $comp->{exp_id} != $data->{exp_id};
     249    &my_die("chip_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{chip_id} and $comp->{chip_id} != $data->{chip_id};
     250    &my_die("cam_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{cam_id} and $comp->{cam_id} != $data->{cam_id};
     251    &my_die("fake_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{fake_id} and $comp->{fake_id} != $data->{fake_id};
     252    &my_die("warp_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{warp_id} and $comp->{warp_id} != $data->{warp_id};
     253    &my_die("diff_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{diff_id} and $comp->{diff_id} != $data->{diff_id};
     254    &my_die("direction value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{direction} and $comp->{direction} != $data->{direction};
     255
     256    return 1;
     257}
     258
     259# Combine multiple files for MOPS
     260sub mops_combine
     261{
     262    my $data = shift;           # Data
     263    my $output = shift;         # Output name
     264    my $input = shift;          # Input name
     265
     266    $output = $ipprc->file_resolve( $output, 'create' ) or
     267        &my_die( "Unable to resolve output file $output", $pub_id, $PS_EXIT_SYS_ERROR);
     268
     269    my $command = "$ppMops $input $output";
     270    $command .= " -exp_name " . $data->{exp_name} if defined $data->{exp_name};
     271    $command .= " -exp_id " . $data->{exp_id} if defined $data->{exp_id};
     272    $command .= " -chip_id " . $data->{chip_id} if defined $data->{chip_id};
     273    $command .= " -cam_id " . $data->{cam_id} if defined $data->{cam_id};
     274    $command .= " -fake_id " . $data->{fake_id} if defined $data->{fake_id};
     275    $command .= " -warp_id " . $data->{warp_id} if defined $data->{warp_id};
     276    $command .= " -diff_id " . $data->{diff_id} if defined $data->{diff_id};
     277    $command .= " -inverse" if defined $data->{direction} and $data->{direction} == 0;
     278    $command .= " -zp " . $data->{zp} if defined $data->{zp};
     279    $command .= " -zp_error " . $data->{zp_err} if defined $data->{zp_err};
     280    $command .= " -astrom_rms " . $data->{astrom} if defined $data->{astrom};
     281
     282    unless ($no_op) {
     283        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
     284            run(command => $command, verbose => $verbose);
     285        &my_die( "Unable to translate", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
     286        &my_die( "Unable to find translated file $output", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $output );
     287    } else {
     288        print "Not running: $command\n";
     289    }
     290
     291    return $output;
     292}
    197293
    198294
     
    210306        $command .= " -pub_id $pub_id";
    211307        $command .= " -path_base $outroot";
     308        $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
     309        $command .= " -hostname $host" if defined $host;
    212310        $command .= " -fault $fault";
    213311        $command .= " -dbname $dbname" if defined $dbname;
  • trunk/ippTools/share/difftool_skyfile.sql

    r25073 r25256  
    1212    -- The following are only valid for warps
    1313    -- XXX This needs to be more clever to handle diffs between stacks
     14    -- Zero points are appropriate for both forward and backward diffs
    1415    camProcessedInput.zpt_obs,
    1516    camProcessedInput.zpt_stdev,
     
    1920    rawInput.camera,
    2021    rawInput.exp_name AS exp_name_1,
     22    rawInput.exp_id AS exp_id_1,
     23    chipInput.chip_id AS chip_id_1,
     24    camInput.cam_id AS cam_id_1,
     25    fakeInput.fake_id AS fake_id_1,
     26    camProcessedInput.sigma_ra AS sigma_ra_1,
     27    camProcessedInput.sigma_dec AS sigma_dec_1,
    2128    rawTemplate.exp_name AS exp_name_2,
    22     rawInput.exp_id AS exp_id_1,
    23     rawTemplate.exp_id AS exp_id_2
     29    rawTemplate.exp_id AS exp_id_2,
     30    chipTemplate.chip_id AS chip_id_2,
     31    camTemplate.cam_id AS cam_id_2,
     32    fakeTemplate.fake_id AS fake_id_2,
     33    camProcessedTemplate.sigma_ra AS sigma_ra_2,
     34    camProcessedTemplate.sigma_dec AS sigma_dec_2
    2435FROM diffRun
    2536JOIN diffSkyfile USING(diff_id)
     
    4354LEFT JOIN camRun AS camTemplate
    4455    ON camTemplate.cam_id = fakeTemplate.cam_id
     56LEFT JOIN camProcessedExp AS camProcessedTemplate
     57    ON camProcessedTemplate.cam_id = camTemplate.cam_id
    4558LEFT JOIN chipRun AS chipTemplate
    4659    ON chipTemplate.chip_id = camTemplate.chip_id
  • trunk/ippTools/share/pxadmin_create_tables.sql

    r25012 r25256  
    14071407    pub_id BIGINT AUTO_INCREMENT, -- link to publishRun
    14081408    path_base VARCHAR(255),     -- base path of output
     1409    hostname VARCHAR(64),       -- name of host
     1410    dtime_script FLOAT,         -- run time for script
    14091411    fault SMALLINT NOT NULL DEFAULT 0, -- Fault code
    14101412    PRIMARY KEY(pub_id),
  • trunk/ippTools/src/pubtool.c

    r25098 r25256  
    259259    // required
    260260    PXOPT_LOOKUP_S64(pub_id, config->args, "-pub_id", true, false);
    261     PXOPT_LOOKUP_STR(path_base, config->args, "-path_base",  true, false);
     261    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
    262262
    263263    // optional
     264    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
     265    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
    264266    PXOPT_LOOKUP_S32(fault, config->args, "-fault", false, false);
    265267
     
    269271    }
    270272
    271     if (!publishDoneInsert(config->dbh, pub_id, path_base, fault)) {
     273    if (!publishDoneInsert(config->dbh, pub_id, path_base, hostname, dtime_script, fault)) {
    272274        psError(PS_ERR_UNKNOWN, false, "Unable to add file");
    273275        if (!psDBRollback(config->dbh)) {
  • trunk/ippTools/src/pubtoolConfig.c

    r24512 r25256  
    6868    psMetadataAddS64(addArgs, PS_LIST_TAIL, "-pub_id", 0, "define pub_id (required)", 0);
    6969    psMetadataAddStr(addArgs, PS_LIST_TAIL, "-path_base", 0, "define path_base (required)", NULL);
     70    psMetadataAddStr(addArgs, PS_LIST_TAIL, "-hostname", 0, "define hostname", NULL);
     71    psMetadataAddF32(addArgs, PS_LIST_TAIL, "-dtime_script", 0, "define time for script", NAN);
    7072    psMetadataAddS32(addArgs, PS_LIST_TAIL, "-fault", 0, "define fault code", 0);
    7173
  • trunk/ppMops/ICDlite.txt

    r25135 r25256  
    7979 * ASTRORMS added to make absolute (i.e., across exposures) astrometry errors more accurate
    8080 * DE_MAGnn and DE_EFFnn replace DE1 through DE10, which were never well defined
     81 * Removed LIMITMAG, which was never well defined, and is unnecessary given the DE_MAGnn and DE_EFFnn
    8182
    8283=== Table ===
     
    119120
    120121
     122=== Example ===
    121123
    122 
    123                             Table 3: IPP-MOPS Transient Detection Keywords
    124 FITS Keyword      Precision                     Description
    125 FPA ID            char(20)                      IPP-assigned identifier that can be used to trace back to this FPA
    126 MJD-OBS           F64                           midpoint time of the exposure as a MJD and day fraction
    127 RA                HH:MM:SS.SSS                 field center RA at exposure midpoint, string
    128 DEC               sDD:MM:SS (s is + or -) field center declination at exposure midpoint, string
    129 EXPTIME           F64                          exposure time in seconds
    130 ROTANGLE          F64                          image rotation of the y-axis in degrees, from local N toward E
    131 FILTER            char(3)                       effective filter used for the exposure, one of g, r, i, z, y, B, V, w
    132 AIRMASS           F64                          airmass at exposure midpoint
    133 LIMITMAG          F64                           limiting magnitude of detections for this FPA
    134 DE1 through DE10  F64                           detection efficiency coefficients
    135 OBSCODE           char(5)                       MPC three-character observatory code
    136 TEL ALT           F64                          telescope altitude at exposure midpoint, in degrees
    137 TEL AZ            F64                          telescope azimuth at exposure midpoint, in degrees
    138                          Table 4: IPP-MOPS Transient Detection Table Columns
    139              Column       Precision Description
    140              RA DEG       F64          detection center coordinates in degrees
    141              RA SIG       F64          error in the detection center, in degrees
    142              DEC DEG      F64          detection center coordinates in degrees
    143              DEC SIG      F64          error in the detection center, in degrees
    144              FLUX         F64          flux
    145              FLUX SIG     F64          error in the flux value
    146              STARPSF      F64          probability that the PSF matches a starlike PSF
    147              ANG          F64          detection’s elongation angle in degrees, local N toward E
    148              ANG SIG      F64          error in the angle, in degrees
    149              LEN          F64          elongation length of the detection in degrees
    150              LEN SIG      F64          error in the length, in degrees
     124{{{
     125XTENSION= 'BINTABLE'           / binary table extension
     126BITPIX  =                    8 / 8-bit bytes
     127NAXIS   =                    2 / 2-dimensional binary table
     128NAXIS1  =                   72 / width of table in bytes
     129NAXIS2  =                42032 / number of rows in table
     130PCOUNT  =                    0 / size of special data area
     131GCOUNT  =                    1 / one data group (required keyword)
     132TFIELDS =                   13 / number of fields in each row
     133TTYPE1  = 'RA      '           / label for field   1
     134TFORM1  = '1D      '           / data format of field: 8-byte DOUBLE
     135TTYPE2  = 'RA_ERR  '           / label for field   2
     136TFORM2  = '1D      '           / data format of field: 8-byte DOUBLE
     137TTYPE3  = 'DEC     '           / label for field   3
     138TFORM3  = '1D      '           / data format of field: 8-byte DOUBLE
     139TTYPE4  = 'DEC_ERR '           / label for field   4
     140TFORM4  = '1D      '           / data format of field: 8-byte DOUBLE
     141TTYPE5  = 'MAG     '           / label for field   5
     142TFORM5  = '1E      '           / data format of field: 4-byte REAL
     143TTYPE6  = 'MAG_ERR '           / label for field   6
     144TFORM6  = '1E      '           / data format of field: 4-byte REAL
     145TTYPE7  = 'STARPSF '           / label for field   7
     146TFORM7  = '1E      '           / data format of field: 4-byte REAL
     147TTYPE8  = 'ANGLE   '           / label for field   8
     148TFORM8  = '1E      '           / data format of field: 4-byte REAL
     149TTYPE9  = 'ANGLE_ERR'          / label for field   9
     150TFORM9  = '1E      '           / data format of field: 4-byte REAL
     151TTYPE10 = 'LENGTH  '           / label for field  10
     152TFORM10 = '1E      '           / data format of field: 4-byte REAL
     153TTYPE11 = 'LENGTH_ERR'         / label for field  11
     154TFORM11 = '1E      '           / data format of field: 4-byte REAL
     155TTYPE12 = 'FLAGS   '           / label for field  12
     156TFORM12 = '1J      '           / data format of field: 4-byte INTEGER
     157TZERO12 =           2147483648 / offset for unsigned integers
     158TSCAL12 =                    1 / data are not scaled
     159TTYPE13 = 'DIFF_SKYFILE_ID'    / label for field  13
     160TFORM13 = '1K      '           / data format of field: 8-byte INTEGER
     161SWSOURCE= '60eb6cdc-a59c-4636-a4e0-dba66a9721fd' / Software source
     162SWVERSN = 'branches/pap_mops/ppMops@25227' / Software version
     163HISTORY ppMops at 2009-09-02T03:48:46.695783
     164HISTORY psLib version: branches/pap_mops/psLib@25227
     165HISTORY psLib source: 60eb6cdc-a59c-4636-a4e0-dba66a9721fd
     166HISTORY ppMops version: branches/pap_mops/ppMops@25227
     167HISTORY ppMops source: 60eb6cdc-a59c-4636-a4e0-dba66a9721fd
     168EXP_NAME= 'o4995g0129o'        / Exposure name
     169EXP_ID  =                77164 / Exposure identifier
     170CHIP_ID =                24019 / Chip stage identifier
     171CAM_ID  =                17726 / Cam stage identifier
     172FAKE_ID =                10227 / Fake stage identifier
     173WARP_ID =                 8842 / Warp stage identifier
     174DIFF_ID =                    0 / Diff stage identifier
     175DIFF_POS=                    F / Positive subtraction?
     176MJD-OBS =     54995.4740598313 / MJD of exposure midpoint
     177RA      = '18:25:01.988'       / Right Ascension of boresight
     178DEC     = '-17:20:40.069'      / Declination of boresight
     179TEL_ALT =            51.951873 / Telescope altitude
     180TEL_AZ  =           179.483883 / Telescope azimuth
     181EXPTIME =                  38. / Exposure time (sec)
     182ROTANGLE=             333.1039 / Rotator position angle
     183FILTER  = 'r.00000 '           / Filter name
     184AIRMASS =                1.269 / Airmass of exposure
     185OBSCODE = 'F51     '           / IAU Observatory code
     186SEEING  =             1.678401 / Mean seeing
     187MAGZP   =             28.65226 / Magnitude zero point
     188MAGZPERR=             0.353063 / Error in magnitude zero point
     189ASTRORMS=            0.3111496 / RMS of astrometric fit
     190EXTNAME = 'MOPS_TRANSIENT_DETECTIONS'
     191END
     192}}}
  • trunk/ppMops/src/Makefile.am

    r24307 r25256  
    2828        ppMops.c                \
    2929        ppMopsVersion.c         \
    30         ppMopsData.c                   
     30        ppMopsArguments.c       \
     31        ppMopsDetections.c      \
     32        ppMopsRead.c            \
     33        ppMopsWrite.c           \
     34        ppMopsMerge.c
    3135
    3236noinst_HEADERS = \
  • trunk/ppMops/src/ppMops.c

    r25100 r25256  
    66int main(int argc, char *argv[])
    77{
    8     if (argc != 7) {
    9         fprintf(stderr, "Insufficient arguments.\n");
    10         fprintf(stderr, "Usage: %s DETECTIONS ZP EXP_ID EXP_NAME DIRECTION OUTPUT\n", argv[0]);
     8    psLibInit(NULL);
     9
     10    ppMopsArguments *args = ppMopsArgumentsParse(argc, argv); // Parsed arguments
     11    if (!args) {
     12        psErrorStackPrint(stderr, "Error parsing arguments");
    1113        exit(PS_EXIT_CONFIG_ERROR);
    1214    }
    1315
    14     ppMopsData *data = ppMopsDataAlloc(); // Configuration data
    15     data->detections = psStringCopy(argv[1]);
    16     data->zp = atof(argv[2]);
    17     data->exp_id = atoll(argv[3]);
    18     data->exp_name = psStringCopy(argv[4]);
    19     data->direction = atoi(argv[5]);
    20     data->output = psStringCopy(argv[6]);
    21 
    22     if (!isfinite(data->zp)) {
    23         psErrorStackPrint(stderr, "Zero point is unknown\n");
    24         exit(PS_EXIT_CONFIG_ERROR);
    25     }
     16    psArray *detections = ppMopsRead(args); // Detections from each input
     17    if (!detections) {
     18        psErrorStackPrint(stderr, "Unable to read detections");
     19        exit(PS_EXIT_SYS_ERROR);
     20    }
     21
     22    ppMopsDetections *merged = ppMopsMerge(detections); // Merged detections
     23    psFree(detections);
     24    if (!merged) {
     25        psErrorStackPrint(stderr, "Unable to merge detections");
     26        exit(PS_EXIT_SYS_ERROR);
     27    }
     28
     29    if (!ppMopsWrite(merged, args)) {
     30        psErrorStackPrint(stderr, "Unable to write detections");
     31        exit(PS_EXIT_SYS_ERROR);
     32    }
     33
     34    psFree(merged);
     35    psFree(args);
     36
     37    psLibFinalize();
     38
     39    return PS_EXIT_SUCCESS;
     40}
     41
     42
     43#if 0
     44    ps
     45
    2646
    2747    psArray *detections = NULL;         // Detections
     
    211231    psFree(data);
    212232
    213     return PS_EXIT_SUCCESS;
    214 }
     233#endif
     234
  • trunk/ppMops/src/ppMops.h

    r25100 r25256  
    1111                     PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_SKY_FAILURE) // Flags to exclude
    1212
    13 
    1413// Configuration data
    1514typedef struct {
    16     psString detections;                // Detections filename
    17     float zp;                           // Magnitude zero point
     15    psArray *input;                     // Input filenames
     16    psString exp_name;                  // Exposure name
    1817    psS64 exp_id;                       // Exposure identifier
    19     psString exp_name;                  // Exposure name
    20     bool direction;                     // Direction of subtraction, 1=positive, 0=negative
     18    psS64 chip_id;                      // Chip stage identifier
     19    psS64 cam_id;                       // Camera stage identifier
     20    psS64 fake_id;                      // Fake stage identifier
     21    psS64 warp_id;                      // Warp stage identifier
     22    psS64 diff_id;                      // Diff stage identifier
     23    bool positive;                      // Sense of subtraction, T=positive, F=negative
     24    float zp, zpErr;                    // Magnitude zero point and error
     25    float rmsAstrom;                    // Astrometric solution RMS
    2126    psString output;                    // Output filename
    22 } ppMopsData;
     27} ppMopsArguments;
    2328
    24 // Allocator
    25 ppMopsData *ppMopsDataAlloc(void);
     29/// Parse arguments
     30ppMopsArguments *ppMopsArgumentsParse(int argc, char *argv[]);
     31
     32typedef struct {
     33    psString raBoresight, decBoresight; // RA,Dec of telescope boresight
     34    psString filter;                    // Filter for exposure
     35    float airmass;                      // Airmass of exposure
     36    float exptime;                      // Exposure time
     37    double posangle;                    // Position angle
     38    double alt, az;                     // Telescope altitude and azimuth
     39    double mjd;                         // Modified Julian Date
     40    float seeing;                       // Seeing of exposure
     41    long num;                           // Number of detections
     42    psVector *x, *y;                    // Image coordinates
     43    psVector *ra, *dec;                 // Sky coordinates
     44    psVector *raErr, *decErr;           // Error in sky coordinates
     45    psVector *mag, *magErr;             // Magnitude and associated error
     46    psVector *extended;                 // Measure of extendedness
     47    psVector *angle, *angleErr;         // Angle of trail and associated error
     48    psVector *length, *lengthErr;       // Length of trail and associated error
     49    psVector *flags;                    // psphot flags
     50    psVector *diffSkyfileId;            // Identifier for source image
     51    psVector *naxis1, *naxis2;          // Size of image
     52    psVector *mask;                     // Mask for detections
     53} ppMopsDetections;
     54
     55ppMopsDetections *ppMopsDetectionsAlloc(long num);
     56
     57/// Copy a detection
     58bool ppMopsDetectionsCopySingle(ppMopsDetections *target, const ppMopsDetections *source, long index);
     59
     60/// Purge the detections list of masked detections
     61bool ppMopsDetectionsPurge(ppMopsDetections *detections);
     62
     63
     64/// Read detections
     65psArray *ppMopsRead(const ppMopsArguments *args);
     66
     67/// Merge detections
     68ppMopsDetections *ppMopsMerge(const psArray *detections);
     69
     70/// Write detections
     71bool ppMopsWrite(const ppMopsDetections *detections, const ppMopsArguments *args);
    2672
    2773
  • trunk/ppStack/src/ppStackMatch.c

    r25045 r25256  
    8787    x->n = y->n = numGood;
    8888
    89     psTree *tree = psTreePlant(2, 2, x, y); // kd tree
     89    psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y); // kd tree
    9090
    9191    psArray *filtered = psArrayAllocEmpty(numGood); // Filtered list of sources
  • trunk/psLib/src/sys/psType.h

    r21183 r25256  
    141141} psDataType;
    142142
    143 // macros to abstract the generic mask type : these values must be consistent 
     143// macros to abstract the generic mask type : these values must be consistent
    144144#define PS_TYPE_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
    145145#define PS_TYPE_MASK_DATA U8           /**< the data member to use for mask image */
     
    152152// alternate versions if needed
    153153// #define PS_NOT_MASK(A)(UINT16_MAX-(A))
    154 // #define PS_NOT_MASK(A)(UINT32_MAX-(A)) 
     154// #define PS_NOT_MASK(A)(UINT32_MAX-(A))
    155155// #define PS_NOT_MASK(A)(UINT64_MAX-(A))
    156156
    157 // macros to abstract the vector mask type : these values must be consistent 
     157// macros to abstract the vector mask type : these values must be consistent
    158158#define PS_TYPE_VECTOR_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
    159159#define PS_TYPE_VECTOR_MASK_DATA U8           /**< the data member to use for mask image */
     
    161161#define PS_MIN_VECTOR_MASK_TYPE 0             /**< minimum valid Vector Mask value */
    162162#define PS_MAX_VECTOR_MASK_TYPE UINT8_MAX     /**< maximum valid Vector Mask value */
    163 typedef psU8 psVectorMaskType;                    ///< the C datatype for a mask image
     163typedef psU8 psVectorMaskType;                    ///< the C datatype for a mask image
    164164#define PS_NOT_VECTOR_MASK(A)(UINT8_MAX-(A))
    165165
    166 // macros to abstract the image mask type : these values must be consistent 
    167 #define PS_TYPE_IMAGE_MASK PS_TYPE_U16       /**< the psElemType to use for mask image */
    168 #define PS_TYPE_IMAGE_MASK_DATA U16          /**< the data member to use for mask image */
    169 #define PS_TYPE_IMAGE_MASK_NAME "psU16"      /**< the data type for mask as a string */
     166// macros to abstract the image mask type : these values must be consistent
     167#define PS_TYPE_IMAGE_MASK PS_TYPE_U16       /**< the psElemType to use for mask image */
     168#define PS_TYPE_IMAGE_MASK_DATA U16          /**< the data member to use for mask image */
     169#define PS_TYPE_IMAGE_MASK_NAME "psU16"      /**< the data type for mask as a string */
    170170#define PS_MIN_IMAGE_MASK_TYPE 0             /**< minimum valid Image Mask value */
    171171#define PS_MAX_IMAGE_MASK_TYPE UINT16_MAX    /**< maximum valid Image Mask value */
     
    246246};
    247247
    248 /// Macro to get the bad pixel reason code (stored as part of mask value)
    249 #define PS_BADPIXEL_BITMASK 0x0f
    250 #define PS_GET_BADPIXEL(maskValue) (maskValue & PS_BADPIXEL_BITMASK)
    251 
    252 #define PS_IS_BADPIXEL(maskValue) (PS_GET_BADPIXEL(maskValue) != 0)
    253 
    254 /// Macro to apply a bad pixel reason code to mask image
    255 #define PS_SET_BADPIXEL(maskValue, reasonCode) \
    256 { \
    257     maskValue = (psMaskType)((reasonCode & PS_BADPIXEL_BITMASK) | (maskValue & ~PS_BADPIXEL_BITMASK)); \
    258 }
    259 
    260248/// Macro to determine if the psElemType is an integer.
    261249#define PS_IS_PSELEMTYPE_INT(x) ((x & 0x100) == 0x100)
  • trunk/psLib/src/types/psTree.c

    r18344 r25256  
    1414#include "psTree.h"
    1515
     16//#define INPUT_CHECK                   // Check inputs for functions that may be in a tight loop?
     17
    1618
    1719// XXX Upgrades:
     
    8486}
    8587
    86 psTree *psTreeAlloc(int dim, int maxLeafContents, long numNodes)
     88psTree *psTreeAlloc(int dim, int maxLeafContents, psTreeType type, long numNodes)
    8789{
    8890    psAssert(dim > 0, "Dimensionality (%d) must be positive", dim);
     
    9597    tree->dim = dim;
    9698    tree->maxLeafContents = maxLeafContents;
     99    tree->type = type;
    97100
    98101    tree->numNodes = numNodes;
     
    115118
    116119
    117 psTree *psTreePlant(int dim, int maxLeafContents, ...)
     120psTree *psTreePlant(int dim, int maxLeafContents, psTreeType type, ...)
    118121{
    119122    PS_ASSERT_INT_POSITIVE(dim, NULL);
     
    122125    // Parse coordinate list
    123126    va_list args;                       // Variable argument list
    124     va_start(args, maxLeafContents);
     127    va_start(args, type);
    125128    psArray *coords = psArrayAlloc(dim); // Array of coordinates
    126129    long numData = 0;                   // Number of data points
     
    145148        long pow2;                      // Smallest power of two >= numData
    146149        for (pow2 = 1; pow2 < numData; pow2 <<= 1);
    147         numNodes = PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1);
    148     }
    149 
    150     psTree *tree = psTreeAlloc(dim, maxLeafContents, numNodes);
     150        numNodes = PS_MAX(PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1), 1);
     151    }
     152
     153    psTree *tree = psTreeAlloc(dim, maxLeafContents, type, numNodes);
    151154    tree->data = psTreeCoordArrayAlloc(numData, dim);
    152155    tree->numData = numData;
     
    199202    }
    200203
     204    if (numData <= maxLeafContents) {
     205        // Don't need to do any more work
     206        return tree;
     207    }
     208
    201209    psArray *work = psArrayAlloc(numNodes); // Work queue
    202210    work->data[0] = root;
     
    365373psTreeNode *psTreeLeaf(const psTree *tree, const psVector *coords)
    366374{
    367 #if 1 // Might be in a tight loop
     375#ifdef INPUT_CHECK // Might be in a tight loop
    368376    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    369377    PS_ASSERT_VECTOR_NON_NULL(coords, NULL);
     
    403411{
    404412    int dim = tree->dim;                // Dimensionality
    405     switch (dim) {
    406       case 2:
    407         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    408             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
    409       case 3:
    410         return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
    411             PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
    412             PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
    413       default: {
    414           double distance2 = 0.0;             // Distance of interest
    415           for (int i = 0; i < dim; i++) {
    416               distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     413    switch (tree->type) {
     414      case PS_TREE_EUCLIDEAN:
     415        switch (dim) {
     416          case 2:
     417            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     418                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
     419          case 3:
     420            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
     421                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
     422                PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
     423          default: {
     424              double distance2 = 0.0;             // Distance of interest
     425              for (int i = 0; i < dim; i++) {
     426                  distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
     427              }
     428              return distance2;
    417429          }
    418           return distance2;
    419       }
    420     }
     430        }
     431        break;
     432      case PS_TREE_SPHERICAL:
     433        switch (dim) {
     434          case 2: {
     435              // Haversine formula
     436              double dphi = coords->data.F64[1] - tree->data->F64[index][1];
     437              double sindphi = sin(dphi / 2.0);
     438              double dlambda = coords->data.F64[0] - tree->data->F64[index][0];
     439              double sindlambda = sin(dlambda / 2.0);
     440              return PS_SQR(sindphi) +
     441                  cos(coords->data.F64[1]) * cos(tree->data->F64[index][1]) * PS_SQR(sindlambda);
     442          }
     443          default:
     444            psAbort("Spherical distances not supported for more than 2 dimensions");
     445        }
     446      default:
     447        psAbort("Unrecognised type: %x", tree->type);
     448    }
     449
    421450    return NAN;
    422451}
     
    430459        double minDiff = tree->min->F64[index][i] - coords->data.F64[i];
    431460        if (minDiff > 0) {
    432             distance += PS_SQR(minDiff);
     461            switch (tree->type) {
     462              case PS_TREE_EUCLIDEAN:
     463                distance += PS_SQR(minDiff);
     464                break;
     465              case PS_TREE_SPHERICAL: {
     466                  double sinDiff = sin(minDiff / 2.0);
     467                  distance += PS_SQR(sinDiff);
     468                  break;
     469              }
     470              default:
     471                psAbort("Unrecognised type: %x", tree->type);
     472            }
    433473            continue;
    434474        }
    435475        double maxDiff = coords->data.F64[i] - tree->max->F64[index][i];
    436476        if (maxDiff > 0) {
    437             distance += PS_SQR(maxDiff);
     477            switch (tree->type) {
     478              case PS_TREE_EUCLIDEAN:
     479                distance += PS_SQR(maxDiff);
     480                break;
     481              case PS_TREE_SPHERICAL: {
     482                  double sinDiff = sin(maxDiff / 2.0);
     483                  distance += PS_SQR(sinDiff);
     484                  break;
     485              }
     486              default:
     487                psAbort("Unrecognised type: %x", tree->type);
     488            }
    438489            continue;
    439490        }
     
    479530}
    480531
    481 // Return the index of the nearest neighbour to given coordinates, within some radius
     532// Return the index of the nearest neighbour to given coordinates, within some distance measure
    482533// This is the engine for psTreeNearest() and psTreeNearestWithin()
    483534static inline long treeNearestWithin(const psTree *tree, // Tree
    484535                                     const psVector *coordinates, // Coordinates of interest
    485                                      double bestDistance // Distance (radius-squared) to best point
     536                                     double bestDistance // Distance measure to best point
    486537    )
    487538{
    488 #if 1 // Might be in a tight loop
     539#ifdef INPUT_CHECK // Might be in a tight loop
    489540    PS_ASSERT_TREE_NON_NULL(tree, -1);
    490541    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    545596
    546597
     598// Convert a radius to our internal "distance measure"
     599// Often, we're given a search radius, but for efficiency reasons, we don't use that internally.
     600static double treeRadiusToDistance(const psTree *tree, double radius)
     601{
     602    switch (tree->type) {
     603      case PS_TREE_EUCLIDEAN:
     604        // Using the square of the distance as the distance measure
     605        return PS_SQR(radius);
     606      case PS_TREE_SPHERICAL: {
     607          // Using a rearrangement of the Haversine formula
     608          double sindist = sin(radius / 2.0);
     609          return PS_SQR(sindist);
     610      }
     611      default:
     612        psAbort("Unrecognised type: %x", tree->type);
     613    }
     614}
     615
     616
    547617long psTreeNearestWithin(const psTree *tree, const psVector *coords, double radius)
    548618{
    549     return treeNearestWithin(tree, coords, PS_SQR(radius));
    550 }
    551 
    552 
    553 // Search a leaf node for points within radius squared
    554 static inline long treeLeafSearchWithin(double radius2, // Radius squared to search
     619    return treeNearestWithin(tree, coords, treeRadiusToDistance(tree, radius));
     620}
     621
     622
     623// Search a leaf node for points within distance
     624static inline long treeLeafSearchWithin(double distance, // Distance to search
    555625                                        const psTree *tree, // Tree of interest
    556626                                        const psTreeNode *leaf, // Leaf to search
     
    561631    for (int i = 0; i < leaf->num; i++) {
    562632        long index = leaf->contents[i]; // Index of point
    563         double distance = treeContentDistance(tree, index, coords); // Distance to point
    564         if (distance < radius2) {
     633        if (treeContentDistance(tree, index, coords) < distance) {
    565634            num++;
    566635        }
     
    572641long psTreeWithin(const psTree *tree, const psVector *coordinates, double radius)
    573642{
    574 #if 1 // Might be in a tight loop
     643#ifdef INPUT_CHECK // Might be in a tight loop
    575644    PS_ASSERT_TREE_NON_NULL(tree, -1);
    576645    PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
     
    581650                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    582651
    583     radius *= radius;                   // We work with the radius-squared
     652    double distance = treeRadiusToDistance(tree, radius); // Distance measure
    584653    long num = 0;                       // Number of points in circle
    585654
     
    588657    // Find the closest point in the leaf that contains the point of interest
    589658    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    590     num += treeLeafSearchWithin(radius, tree, leaf, coords);
     659    num += treeLeafSearchWithin(distance, tree, leaf, coords);
    591660
    592661    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    605674            }
    606675            // Leaf node
    607             num += treeLeafSearchWithin(radius, tree, node, coords);
     676            num += treeLeafSearchWithin(distance, tree, node, coords);
    608677            work->data[workIndex] = NULL;
    609678            workIndex--;
     
    618687}
    619688
    620 // Search a leaf node for any points within radius squared
    621 static inline bool treeLeafSearchWithinAny(double radius2, // Radius squared to search
    622                                            const psTree *tree, // Tree of interest
    623                                            const psTreeNode *leaf, // Leaf to search
    624                                            const psVector *coords // Coordinates of interest
     689// Search a leaf node for points within distance
     690static inline void treeLeafSearchAllWithin(psVector *result,       // Result vector
     691                                          double distance, // Distance to search
     692                                          const psTree *tree, // Tree of interest
     693                                          const psTreeNode *leaf, // Leaf to search
     694                                          const psVector *coords // Coordinates of interest
    625695    )
    626696{
    627697    for (int i = 0; i < leaf->num; i++) {
    628698        long index = leaf->contents[i]; // Index of point
    629         double distance = treeContentDistance(tree, index, coords); // Distance to point
    630         if (distance < radius2) {
    631             return true;
    632         }
    633     }
    634     return false;
    635 }
    636 
    637 // Given an arbitrary point and a matching radius, return whether there are any points within that radius
    638 bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
    639 {
    640 #if 1 // Might be in a tight loop
    641     PS_ASSERT_TREE_NON_NULL(tree, false);
    642     PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
    643     PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     699        if (treeContentDistance(tree, index, coords) < distance) {
     700            psVectorAppend(result, index);
     701        }
     702    }
     703    return;
     704}
     705
     706// Given an arbitrary point and a matching radius, return the index of all points within that radius
     707psVector *psTreeAllWithin(const psTree *tree, const psVector *coordinates, double radius)
     708{
     709#ifdef INPUT_CHECK // Might be in a tight loop
     710    PS_ASSERT_TREE_NON_NULL(tree, NULL);
     711    PS_ASSERT_VECTOR_NON_NULL(coordinates, NULL);
     712    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, NULL);
    644713#endif
    645714
     
    647716                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
    648717
    649     radius *= radius;                   // We work with the radius-squared
    650 
    651     // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     718    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     719
     720    psVector *result = psVectorAllocEmpty(4, PS_TYPE_S64); // Indices of points within match radius
     721
     722    // This is essentially the same as psTreeNearest, except we're not allowed to prune
    652723
    653724    // Find the closest point in the leaf that contains the point of interest
    654725    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
    655     if (treeLeafSearchWithinAny(radius, tree, leaf, coords)) {
    656         psFree(coords);
    657         return true;
    658     }
     726    treeLeafSearchAllWithin(result, distance, tree, leaf, coords);
    659727
    660728    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     
    673741            }
    674742            // Leaf node
    675             if (treeLeafSearchWithinAny(radius, tree, node, coords)) {
     743            treeLeafSearchAllWithin(result, distance, tree, node, coords);
     744            work->data[workIndex] = NULL;
     745            workIndex--;
     746        }
     747
     748        leaf = up;
     749    }
     750    psFree(work);
     751    psFree(coords);
     752
     753    return result;
     754}
     755
     756// Search a leaf node for any points within distance measure
     757static inline bool treeLeafSearchWithinAny(double distance, // Distance to search
     758                                           const psTree *tree, // Tree of interest
     759                                           const psTreeNode *leaf, // Leaf to search
     760                                           const psVector *coords // Coordinates of interest
     761    )
     762{
     763    for (int i = 0; i < leaf->num; i++) {
     764        long index = leaf->contents[i]; // Index of point
     765        if (treeContentDistance(tree, index, coords) < distance) {
     766            return true;
     767        }
     768    }
     769    return false;
     770}
     771
     772// Given an arbitrary point and a matching radius, return whether there are any points within that radius
     773bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
     774{
     775#ifdef INPUT_CHECK // Might be in a tight loop
     776    PS_ASSERT_TREE_NON_NULL(tree, false);
     777    PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
     778    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
     779#endif
     780
     781    psVector *coords = (coordinates->type.type == PS_TYPE_F64 ? psMemIncrRefCounter((psVector*)coordinates) :
     782                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
     783
     784    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     785
     786    // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
     787
     788    // Find the closest point in the leaf that contains the point of interest
     789    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
     790    if (treeLeafSearchWithinAny(distance, tree, leaf, coords)) {
     791        psFree(coords);
     792        return true;
     793    }
     794
     795    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
     796    while (leaf->up) {
     797        psTreeNode *up = leaf->up;      // Parent node
     798
     799        long workIndex = 0;
     800        work->data[workIndex] = (leaf == up->left ? up->right : up->left); // The other node
     801        while (workIndex >= 0) {
     802            psTreeNode *node = work->data[workIndex];
     803            if (node->left) {
     804                // Branch node
     805                work->data[workIndex] = node->right;
     806                work->data[++workIndex] = node->left;
     807                continue;
     808            }
     809            // Leaf node
     810            if (treeLeafSearchWithinAny(distance, tree, node, coords)) {
    676811                // Clear out the work queue
    677812                memset(work->data, 0, (workIndex + 1) * sizeof(void));
     
    695830psVector *psTreeCoords(psVector *out, const psTree *tree, long index)
    696831{
    697 #if 1 // Might be in a tight loop
     832#ifdef INPUT_CHECK // Might be in a tight loop
    698833    PS_ASSERT_TREE_NON_NULL(tree, NULL);
    699834    PS_ASSERT_INT_NONNEGATIVE(index, NULL);
  • trunk/psLib/src/types/psTree.h

    r19539 r25256  
    1616} psTreeCoordArray;
    1717
     18/// Type of tree
     19///
     20/// Specifies how distances are measured
     21typedef enum {
     22    PS_TREE_EUCLIDEAN,                  // d^2 = dx^2 + dy^2 + ...
     23    PS_TREE_SPHERICAL,                  // sin(dist/2)^2 = sin(dphi/2)^2 + cos(phi1)cos(phi2)sin(dlambda/2)^2
     24} psTreeType;
     25
    1826/// A simple kd-tree implementation
    1927///
     
    2331    int dim;                            ///< Dimensionality
    2432    int maxLeafContents;                ///< Maximum number of points on a leaf
     33    psTreeType type;                    ///< Type of tree
    2534    long numNodes;                      ///< Number of nodes
    2635    long numData;                       ///< Number of data points
     
    6776psTree *psTreeAlloc(int dim,            ///< Dimensionality
    6877                    int maxLeafContents,///< Maximum number of points on a leaf
     78                    psTreeType type,    ///< Type of tree
    6979                    long numNodes       ///< Number of nodes in tree
    7080                    );
     
    7585psTree *psTreePlant(int dim,            ///< Dimensionality
    7686                    int maxLeafContents,///< Maximum number of points on a leaf
     87                    psTreeType type,    ///< Type of tree
    7788                    ...                 ///< psVector for each coordinate
    7889                    );
     
    108119                     );
    109120
     121/// Return the index of all points within some radius of given coordinates
     122psVector *psTreeAllWithin(const psTree *tree,          ///< Tree
     123                          const psVector *coordinates, ///< Coordinates of interest
     124                          double radius                ///< Radius of interest
     125                          );
     126
    110127/// Return the coordinates of a point in the tree, specified by its index
    111128psVector *psTreeCoords(psVector *out,   ///< Output vector, or NULL
  • trunk/psLib/test/optime

    • Property svn:ignore
      •  

        old new  
        22Makefile.in
        33.deps
         4tap_psStatsTiming
  • trunk/psLib/test/types/tap_psTree.c

    r23259 r25256  
    33#include "pstap.h"
    44
    5 #define NUM 10000                       // Number of points
     5#define NUM 1000000                      // Number of points
     6#define SPHERICAL_DISTANCE 3.0          // Distance of interest for spherical test
    67
    78int main(int argc, char *argv[])
    89{
    910    psLibInit(NULL);
    10     plan_tests(6);
     11    plan_tests(13);
    1112
     13    // Euclidean geometry: 6 tests
    1214    {
    1315        psMemId id = psMemGetId();
     
    2325        psFree(rng);
    2426
    25         psTree *tree = psTreePlant(2, 2, x, y);
     27        psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y);
    2628
    2729        ok(tree, "Tree planted");
     
    3537            long closeIndex = psTreeNearest(tree, coords);
    3638            psFree(coords);
    37             ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found point: %ld", closeIndex);
     39            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
    3840
    3941            long bestIndex = -1;
     
    6870    }
    6971
     72    // Spherical geometry: 7 tests
     73    {
     74        psMemId id = psMemGetId();
     75
     76        psVector *ra = psVectorAlloc(NUM, PS_TYPE_F64);
     77        psVector *dec = psVectorAlloc(NUM, PS_TYPE_F64);
     78
     79        psRandom *rng = psRandomAllocSpecific(PS_RANDOM_TAUS, 0);
     80        for (int i = 0; i < NUM; i++) {
     81            // Using http://mathworld.wolfram.com/SpherePointPicking.html
     82            ra->data.F64[i] = psRandomUniform(rng);
     83            dec->data.F64[i] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
     84        }
     85
     86        psTree *tree = psTreePlant(2, 2, PS_TREE_SPHERICAL, ra, dec);
     87
     88        ok(tree, "Tree planted");
     89        skip_start(!tree, 4, "tree died");
     90        {
     91            //            psTreePrint(stderr, tree);
     92
     93            psVector *coords = psVectorAlloc(2, PS_TYPE_F64);
     94            coords->data.F64[0] = psRandomUniform(rng);
     95            coords->data.F64[1] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
     96
     97            psVector *indices = psTreeAllWithin(tree, coords, DEG_TO_RAD(SPHERICAL_DISTANCE));
     98            ok(indices && indices->type.type == PS_TYPE_S64, "got list of indices (%ld points)", indices->n);
     99            long closeIndex = psTreeNearest(tree, coords);
     100            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
     101
     102            ok(psVectorSortInPlace(indices), "sorted indices");
     103
     104            bool allgood = true;        // All points in the appropriate place?
     105            double bestDistance = INFINITY; // Distance to best point
     106            long bestIndex = -1;        // Index of best point
     107            for (long i = 0, j = 0; i < NUM; i++) {
     108#if 1
     109                // Traditional formula
     110                double dist = acos(sin(coords->data.F64[1]) * sin(dec->data.F64[i]) +
     111                                   cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
     112                                   cos(coords->data.F64[0] - ra->data.F64[i]));
     113#else
     114                // Haversine formula: used in psTree
     115                double dphi = coords->data.F64[1] - dec->data.F64[i];
     116                double sindphi = sin(dphi/2.0);
     117                double dlambda = coords->data.F64[0] - ra->data.F64[i];
     118                double sindlambda = sin(dlambda/2.0);
     119                double dist = 2.0 * asin(sqrt(PS_SQR(sindphi) +
     120                                              cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
     121                                              PS_SQR(sindlambda)));
     122#endif
     123                                              if (dist < bestDistance) {
     124                    bestDistance = dist;
     125                    bestIndex = i;
     126                }
     127                if (i == indices->data.S64[j]) {
     128                    j++;
     129                    if (dist > DEG_TO_RAD(SPHERICAL_DISTANCE)) {
     130                        diag("%ld is in the list, but shouldn't be (%lf vs %lf)",
     131                             i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
     132                        allgood = false;
     133                    }
     134                } else if (dist <= DEG_TO_RAD(SPHERICAL_DISTANCE)) {
     135                    diag("%ld is not in the list, but should be (%lf vs %lf)",
     136                         i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
     137                    allgood = false;
     138                }
     139            }
     140            ok(allgood, "list is acurate");
     141            ok(bestIndex == closeIndex, "correct point: %ld vs %ld", closeIndex, bestIndex);
     142
     143            psFree(coords);
     144            psFree(indices);
     145
     146        }
     147        skip_end();
     148
     149        psFree(rng);
     150        psFree(tree);
     151        psFree(ra);
     152        psFree(dec);
     153
     154        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
     155    }
     156
    70157    psLibFinalize();
    71158}
  • trunk/psModules/src/camera/pmReadoutFake.c

    • Property svn:mergeinfo changed (with no actual effect on merging)
  • trunk/psModules/src/objects/pmSourceMatch.c

    r24262 r25256  
    221221        } else {
    222222            // Match with the master list
    223             psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, xMaster, yMaster); // kd Tree with sources
     223            psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, PS_TREE_EUCLIDEAN, xMaster, yMaster); // kd Tree
    224224            long numMatch = 0;          // Number of matches
    225225
  • trunk/psphot/doc/efficiency.txt

  • trunk/psphot/src/psphotFake.c

Note: See TracChangeset for help on using the changeset viewer.