Skip to content
Merged
67 changes: 54 additions & 13 deletions starcheck/pcad_att_check.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import re
from astropy.table import Table
import numpy as np
import Quaternion
from Quaternion import Quat
import math

from parse_cm import read_backstop, read_or_list
from Chandra.Time import DateTime
Expand Down Expand Up @@ -71,23 +74,20 @@ def recent_attitude_history(time, file):
return greta_time, float(q1), float(q2), float(q3), float(q4)


def make_pcad_attitude_check_report(backstop_file, or_list_file=None, attitude_file=None,
simtrans_file=None, simfocus_file=None,
ofls_characteristics_file=None, out=None,
dynamic_offsets_file=None,
):
"""
Make a report for checking PCAD attitudes
def run(backstop_file, or_list_file=None, attitude_file=None,
simtrans_file=None, simfocus_file=None,
ofls_characteristics_file=None, out=None,
dynamic_offsets_file=None):

"""
all_ok = True
lines = [] # output report lines
lines = []

bs = read_backstop(backstop_file)

# Get initial state attitude and sim position from history
att_time, q1, q2, q3, q4 = recent_attitude_history(DateTime(bs[0]['date']).secs,
attitude_file)
att_time, q1, q2, q3, q4 = recent_attitude_history(
DateTime(bs[0]['date']).secs,
attitude_file)
q = Quaternion.normalize([q1, q2, q3, q4])
simfa_time, simfa = recent_sim_history(DateTime(bs[0]['date']).secs,
simfocus_file)
Expand Down Expand Up @@ -139,7 +139,46 @@ def make_pcad_attitude_check_report(backstop_file, or_list_file=None, attitude_f
# gives the history of updates as a dict with a `value` and `date` key.
sc = hopper.run_cmds(backstop_file, or_list, ofls_characteristics_file,
initial_state=initial_state, starcheck=True)
# Iterate through checks by obsid to print status

# Make maneuver structure
mm = []
for m in sc.maneuvers:
q1 = Quat(q=Quaternion.normalize(
[m['initial']['q1'], m['initial']['q2'],
m['initial']['q3'], m['initial']['q4']]))
q2 = Quat(q=Quaternion.normalize(
[m['final']['q1'], m['final']['q2'],
m['final']['q3'], m['final']['q4']]))

# Calculate maneuver angle using code borrowed from kadi
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the angle calculation to just use that 4th component -- which seems to work and was already numerically stable here with the logic from kadi commands even if q2 == q1?

q_manvr_3 = np.abs(-q2.q[0] * q1.q[0] - q2.q[1] * q1.q[1]
- q2.q[2] * q1.q[2] + q2.q[3] * -q1.q[3])
# 4th component is cos(theta/2)
if q_manvr_3 > 1:
q_manvr_3 = 1
angle = np.degrees(2 * math.acos(q_manvr_3))

# Re-arrange the hopper maneuever structure to match the structure previously used
# from Parse_CM_File.pm
man = {'initial_obsid': m['initial']['obsid'],
'final_obsid': m['final']['obsid'],
'start_date': m['initial']['date'],
'stop_date': m['final']['date'],
'ra': q2.ra,
'dec': q2.dec,
'roll': q2.roll,
'dur': m['dur'],
'angle': angle,
'q1': m['final']['q1'],
'q2': m['final']['q2'],
'q3': m['final']['q3'],
'q4': m['final']['q4'],
'tstart': DateTime(m['initial']['date']).secs,
'tstop': DateTime(m['final']['date']).secs,
}
mm.append(man)

# Do the attitude checks
checks = sc.get_checks_by_obsid()
for obsid in sc.obsids:
for check in checks[obsid]:
Expand All @@ -153,8 +192,10 @@ def make_pcad_attitude_check_report(backstop_file, or_list_file=None, attitude_f
line = '{:5d}: {}'.format(obsid, message)
lines.append(line)

# Write the attitude report
if out is not None:
with open(out, 'w') as fh:
fh.writelines("\n".join(lines))

return all_ok
# Return the attitude status check and the maneuver structure
return {'mm': mm, 'att_check_ok': all_ok}
27 changes: 13 additions & 14 deletions starcheck/src/lib/Ska/Starcheck/Obsid.pm
Original file line number Diff line number Diff line change
Expand Up @@ -328,20 +328,19 @@ sub find_command {
##################################################################################
sub set_maneuver {
#
# Find the right obsid for each maneuver. Note that obsids in mm_file don't
# always match those in DOT, etc
# Find the maneuver for each dot obsid.
#
##################################################################################
my $self = shift;
my %mm = @_;
my $mm = shift;
my $n = 1;
my $c;
my $found;

while ($c = find_command($self, "MP_TARGQUAT", $n++)) {
$found = 0;
foreach my $m (values %mm) {
my $manvr_obsid = $m->{manvr_dest};
foreach my $m (@{$mm}) {
my $manvr_obsid = $m->{final_obsid};

# where manvr_dest is either the final_obsid of a maneuver or the eventual destination obsid
# of a segmented maneuver
Expand All @@ -359,9 +358,6 @@ sub set_maneuver {
$c->{man_err} = (exists $c->{angle}) ? 35 + $c->{angle} / 2. : 85;
$c->{man_err} = 85 if ($c->{man_err} > 85);

# Now check for consistency between quaternion from MANUEVER summary
# file and the quat from backstop (MP_TARGQUAT cmd)

# Get quat from MP_TARGQUAT (backstop) command.
# Compute 4th component (as only first 3 are uplinked) and renormalize.
# Intent is to match OBC Target Reference subfunction
Expand All @@ -372,14 +368,16 @@ sub set_maneuver {
sprintf(
"Uplink quaternion norm value $norm is too far from 1.0\n");
}

my @c_quat_norm = (
$c->{Q1} / $norm,
$c->{Q2} / $norm,
$c->{Q3} / $norm,
$q4_obc / $norm
);

# Get quat from MANEUVER summary file. This is correct to high precision
# Compare to quaternion used in $m (which provides {ra} {dec} {roll}) which was built
# directly from the 4 components in Backstop
my $q_man = Quat->new($m->{ra}, $m->{dec}, $m->{roll});
my $q_obc = Quat->new(@c_quat_norm);
my @q_man = @{ $q_man->{q} };
Expand All @@ -400,11 +398,12 @@ sub set_maneuver {
$q_man[0], $q_man[1], $q_man[2], $q_man[3]
);
}

}

}
push @{ $self->{yellow_warn} },
sprintf("Did not find match in MAN summary for MP_TARGQUAT at $c->{date}\n")
sprintf("Did not find match in maneuvers for MP_TARGQUAT at $c->{date}\n")
unless ($found);

}
Expand Down Expand Up @@ -1869,14 +1868,14 @@ sub check_monitor_commanding {
}

# Now check in backstop commands for :
# Dither is disabled (AODSDITH) 1 min prior to the end of the maneuver (EOM)
# Dither is disabled (AODSDITH) 1 min - 10s prior to the end of the maneuver (EOM)
# to the target attitude.
# The OFP Aspect Camera Process is restarted (AOACRSET) 3 minutes after EOM.
# Dither is enabled (AOENDITH) 5 min after EOM
# The OFP Aspect Camera Process is restarted (AOACRSET) 3 minutes - 10s after EOM.
# Dither is enabled (AOENDITH) 5 min - 10s after EOM
# ACA-040

my $t_manv = $manv->{tstop};
my %dt = (AODSDITH => -60, AOACRSET => 180, AOENDITH => 300);
my %dt = (AODSDITH => -70, AOACRSET => 170, AOENDITH => 290);
my %cnt = map { $_ => 0 } keys %dt;
foreach $bs (grep { $_->{cmd} eq 'COMMAND_SW' } @{$backstop}) {
my %param = Ska::Parse_CM_File::parse_params($bs->{params});
Expand Down
39 changes: 18 additions & 21 deletions starcheck/src/starcheck.pl
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,23 @@
print "Reading TLR file $tlr_file\n";
my @load_segments = Ska::Parse_CM_File::TLR_load_segments($tlr_file);

print "Reading MM file $mm_file\n";
my $att_report = "${STARCHECK}/pcad_att_check.txt";
my $att_check = call_python(
"pcad_att_check.run",
[],
{
backstop_file => $backstop,
or_list_file => $or_file,
simtrans_file => $simtrans_file,
simfocus_file => $simfocus_file,
attitude_file => $attitude_file,
ofls_characteristics_file => $char_file,
dynamic_offsets_file => $aimpoint_file,
out => $att_report,
}
);

# Read momentum management (maneuvers + SIM move) summary file
my %mm = Ska::Parse_CM_File::MM({ file => $mm_file, ret_type => 'hash' })
if ($mm_file);
my $mm = $att_check->{mm};

# Read maneuver management summary for handy obsid time checks
print "Reading process summary $ps_file\n";
Expand Down Expand Up @@ -416,7 +428,7 @@
$obs{$obsid}->set_obsid(\%guidesumm); # Commanded obsid
$obs{$obsid}->set_target();
$obs{$obsid}->set_star_catalog();
$obs{$obsid}->set_maneuver(%mm) if ($mm_file);
$obs{$obsid}->set_maneuver($mm);
$obs{$obsid}->set_manerr(@manerr) if (@manerr);
$obs{$obsid}->set_files(
$STARCHECK,
Expand Down Expand Up @@ -744,21 +756,7 @@ sub json_obsids {
}
else {
my $att_report = "${STARCHECK}/pcad_att_check.txt";
my $att_ok = call_python(
"utils._make_pcad_attitude_check_report",
[],
{
backstop_file => $backstop,
or_list_file => $or_file,
simtrans_file => $simtrans_file,
simfocus_file => $simfocus_file,
attitude_file => $attitude_file,
ofls_characteristics_file => $char_file,
out => $att_report,
dynamic_offsets_file => $aimpoint_file
}
);
if ($att_ok) {
if ($att_check->{att_check_ok} == 1) {
$out .= "<A HREF=\"${att_report}\">[OK] Coordinates as expected.</A>\n";
}
else {
Expand Down Expand Up @@ -1051,7 +1049,6 @@ sub make_annotated_file {
# $backstop = get_file("$par{dir}/*.backstop",'backstop', 'required');
# $guide_summ = get_file("$par{dir}/mg*.sum", 'guide summary');
# $or_file = get_file("$par{dir}/*.or", 'OR');
# $mm_file = get_file("$par{dir}/*/mm*.sum", 'maneuver');
# $dot_file = get_file("$par{dir}/*.dot", 'DOT', 'required');

my ($start_rexp, $id_pre, $id_post, $file_in, $lines) = @_;
Expand Down
5 changes: 0 additions & 5 deletions starcheck/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
from starcheck import __version__ as version
from starcheck.calc_ccd_temps import get_ccd_temps
from starcheck.check_ir_zone import ir_zone_ok
from starcheck.pcad_att_check import make_pcad_attitude_check_report
from starcheck.plot import make_plots_for_obsid

ACQS = mica.stats.acq_stats.get_stats()
Expand Down Expand Up @@ -104,10 +103,6 @@ def get_data_dir():
return sc_data if os.path.exists(sc_data) else ""


def _make_pcad_attitude_check_report(**kwargs):
return make_pcad_attitude_check_report(**kwargs)


def make_ir_check_report(**kwargs):
return ir_zone_ok(**kwargs)

Expand Down