diff --git a/starcheck/src/lib/Ska/Starcheck/Obsid.pm b/starcheck/src/lib/Ska/Starcheck/Obsid.pm index ec8fb0b2..0f54ba71 100644 --- a/starcheck/src/lib/Ska/Starcheck/Obsid.pm +++ b/starcheck/src/lib/Ska/Starcheck/Obsid.pm @@ -310,10 +310,29 @@ sub set_maneuver { ################################################################################## my $self = shift; my $mm = shift; + my $ps = shift; my $n = 1; my $c; my $found; + my $dot_obsid = $self->{dot_obsid}; + # If date before "2020", get the ER obsids from the processing summary + # If the $dot_obsid does not begin with a number + if ($dot_obsid !~ /^\d/ && ($self->{date} lt '2020:001:00:00:00.000')) { + # The processing summary has lines that look like this + # 'P080200 CAL 2017:013:03:00:49.827 2017:013:03:00:59.827 000:00:00:10.000 OBSID = 50385 {Perigee Attitude} + # For each line like that, I want to extract the obsid as the up to 5 digit number after OBSID and I + # want to extract the "dot_obsid" as the first 5 characters of the line (P0802 in this case) + foreach my $ps_line (@$ps) { + if ($ps_line =~ /^\s*(\S{5}).*OBSID\s*=\s*(\d{1,5})/) { + if ($1 eq $dot_obsid) { + $dot_obsid = $2; + last; + } + } + } + } + while ($c = find_command($self, "MP_TARGQUAT", $n++)) { $found = 0; foreach my $m (@{$mm}) { @@ -321,7 +340,7 @@ sub set_maneuver { # where manvr_dest is either the final_obsid of a maneuver or the eventual destination obsid # of a segmented maneuver - if ( ($manvr_obsid eq $self->{dot_obsid}) + if ( ($manvr_obsid eq $dot_obsid) && abs($m->{q1} - $c->{Q1}) < 1e-7 && abs($m->{q2} - $c->{Q2}) < 1e-7 && abs($m->{q3} - $c->{Q3}) < 1e-7) @@ -383,6 +402,11 @@ sub set_maneuver { sprintf("Did not find match in maneuvers for MP_TARGQUAT at $c->{date}\n") unless ($found); + unless ($found) { + # throw error and quit + exit(1); + } + } } @@ -1023,6 +1047,45 @@ sub check_for_srdcs { } } +############################################################################################# +sub check_planets{ +############################################################################################# + my $self = shift; + my $c = find_command($self, 'MP_STARCAT'); + # Skip this check if the + # pass the proseco parameters do this check in Python + my $bright_data = call_python("utils.run_sparkles_planet_checks", + [ $self->{'proseco_args'} ]); + for my $warn_type (qw(warn fyi orange_warn yellow_warn)) { + if (exists $bright_data->{$warn_type}) { + for my $warn (@{ $bright_data->{$warn_type} }) { + # If the warning has an idx in it and an id, update the text to match the starcheck + # version of the catalog + if ($warn =~ /idx (\d+) id (\d+)/) { + my $idx = $1; + my $star_id = '---'; + if (defined $c) { + for my $i (1 .. 16) { + if ($c->{"TYPE$i"} ne 'NUL') { + $idx--; + if ($idx == 0) { + $star_id = $c->{"GS_ID$i"} if (defined $c->{"GS_ID$i"}); + last; + } + } + } + $star_id = $c->{"GS_ID$idx"} if (defined $c->{"GS_ID$idx"}); + } + $warn =~ s/IDX=$idx/STAR_ID=$star_id/; + } + + push @{ $self->{$warn_type} }, "$warn\n"; + } + } + } +} + + ############################################################################################# sub check_sim_position { ############################################################################################# @@ -1103,7 +1166,14 @@ sub check_star_catalog { my $is_er = ($self->{obsid} =~ /^\d+$/ && $self->{obsid} >= $ER_MIN_OBSID); my $min_guide = $is_science ? 5 : 6; # Minimum number of each object type my $min_acq = $is_science ? 4 : 5; - my $min_fid = 3; + my $target_name = ""; + if (defined $self->{TARGET_NAME}) { + $target_name = $self->{TARGET_NAME}; + } + if (defined $self->{SS_OBJECT}) { + $target_name = $self->{SS_OBJECT}; + } + my $min_fid = ($target_name =~ /Venus/) ? 2 : 3; ######################################################################## my @warn = (); @@ -1151,7 +1221,7 @@ sub check_star_catalog { # Global checks on star/fid numbers # ACA-005 ACA-006 ACA-007 ACA-008 ACA-044 - + print STDERR "$target_name\n"; push @warn, "Too Few Fid Lights\n" if (@{ $self->{fid} } < $min_fid && $is_science); push @warn, "Too Many Fid Lights\n" if ( (@{ $self->{fid} } > 0 && $is_er) @@ -3105,6 +3175,8 @@ sub proseco_args { %proseco_args = ( obsid => $self->{obsid}, date => $targ_cmd->{stop_date}, + duration => $self->{obs_tstop} - $self->{obs_tstart}, + target_name => ($self->{TARGET_NAME}) ? $self->{TARGET_NAME} : $self->{SS_OBJECT}, att => [ 0 + $targ_cmd->{q1}, 0 + $targ_cmd->{q2}, @@ -3128,7 +3200,6 @@ sub proseco_args { n_fid => scalar(@fid_ids), acq_indexes => \@acq_indexes ); - return \%proseco_args; } diff --git a/starcheck/src/starcheck.pl b/starcheck/src/starcheck.pl index b90e0cb6..8da3c4f2 100755 --- a/starcheck/src/starcheck.pl +++ b/starcheck/src/starcheck.pl @@ -437,7 +437,7 @@ $obs{$obsid}->set_obsid(\%guidesumm); # Commanded obsid $obs{$obsid}->set_target(); $obs{$obsid}->set_star_catalog(); - $obs{$obsid}->set_maneuver($mm); + $obs{$obsid}->set_maneuver($mm, \@ps); $obs{$obsid}->set_files( $STARCHECK, $backstop, @@ -648,6 +648,7 @@ sub json_obsids { $obs{$obsid}->check_bright_perigee($radmon); $obs{$obsid}->check_guide_count(); $obs{$obsid}->check_for_srdcs(\@bs); + $obs{$obsid}->check_planets(); } # Make sure there is only one star catalog per obsid diff --git a/starcheck/utils.py b/starcheck/utils.py index 40bedc25..f6e2fd01 100644 --- a/starcheck/utils.py +++ b/starcheck/utils.py @@ -1,3 +1,4 @@ +import collections import logging import os import warnings @@ -584,3 +585,76 @@ def vehicle_filter_backstop(backstop_file, outfile): ] # Write the filtered commands to the output file write_backstop(filtered_cmds, outfile) + + + +import astropy.units as u +from cxotime import CxoTimeLike +from Quaternion import QuatLike +from chandra_aca.planets import (get_planet_chandra_ccd_position, get_planet_mag_states) + + + +def get_proseco_catalog(**kw): + # Note that the fid ids in starcheck are 1-6 + # ACIS, 7-10 HRC-I 11-14 HRC-S. Proseco just uses indexes 1-6 so + # subtract off the offsets. + fid_ids = np.array(kw["fid_ids"]) + if kw["detector"] == "HRC-I": + fid_offset = 6 + elif kw["detector"] == "HRC-S": + fid_offset = 10 + else: + fid_offset = 0 + fid_ids -= fid_offset + + args = { + "obsid": int(kw["obsid"]), + "att": Quaternion.normalize(kw["att"]), + "duration": kw["duration"], + "target_name": kw["target_name"], + "date": kw["date"], + "n_acq": kw["n_acq"], + "n_guide": kw["n_guide"], + "man_angle": kw["man_angle"], + "t_ccd_acq": kw["t_ccd_acq"], + "t_ccd_guide": kw["t_ccd_guide"], + "dither_acq": ACABox(kw["dither_acq"]), + "dither_guide": ACABox(kw["dither_guide"]), + "include_ids_acq": kw["include_ids_acq"], + "include_halfws_acq": kw["include_halfws_acq"], + "detector": kw["detector"], + "sim_offset": kw["sim_offset"], + "include_ids_guide": kw["include_ids_guide"], + "include_ids_fid": list(fid_ids), + "n_fid": len(kw["fid_ids"]), + "focus_offset": 0, + } + if "monitors" in kw: + args["monitors"] = kw["monitors"] + aca = get_aca_catalog(**args) + # Let's write this out to a pickle file for debugging + + with open(f"aca_debug_{args['obsid']}.pkl", "wb") as f: + import pickle + pickle.dump(aca, f) + return aca + + + + +def run_sparkles_planet_checks(proseco_args): + from sparkles.checks import check_planets + from sparkles.messages import MessagesList + + aca = get_proseco_catalog(**proseco_args) + acar = aca.get_review_table() + + msgs = MessagesList(check_planets(acar)) + return { + "warn": [w["text"] for w in msgs == "critical"], + "orange_warn": [w["text"] for w in msgs == "caution"], + "yellow_warn": [w["text"] for w in msgs == "warning"], + "fyi": [w["text"] for w in msgs == "info"], + } +