Independent confirmation of ACA offsets

As part of the verification of the dynamic offsets process, SOT/ACA ops has independently confirmed the FOT aimpoint offsets for the JUL0415O test week. For this independent verification, we have used:

  • the ZERO OFFSET aimpoint table provided by SOT MP
  • the xija ACA thermal model for a test week

(note that in testing, this notebook required PYTHONPATH set to include the 'calc_aca_offsets' branch of starcheck and the 'read_zero_offset' branch of parse_cm)


In [1]:
import os
import sys
from glob import glob
import json
import numpy as np

from astropy.table import Table
from Chandra.Time import DateTime
from Ska.Matplotlib import plot_cxctime

from chandra_aca import drift
import parse_cm

Check dynamic offset file for consistency

The dynamic target offset file includes the aca offsets calculated by the FOT version of the chandra_aca.drift module. The file also includes inputs used to calculate the offsets values: detector, chip_id, chipx, chipy, a time, and a temperature. As a check of consistency, we recalculate the aca_offset_y and aca_offset_z values using those inputs and the SOT/Ska version of the chandra_aca.drift module. For each row in the table, this tests confirms that the re-calculated values of aca_offset_y and aca_offset_z are within 0.02 arcsecs of the values in the file.


In [2]:
TEST_DIR = '/proj/sot/ska/ops/SFE/JUL0415O/oflso'
dynam_table = Table.read(glob("{}/*dynamical_offsets.txt".format(TEST_DIR))[0], format='ascii')

In [3]:
# first, check table for self-consistent offsets
ys = []
zs = []
for row in dynam_table:
    y, z = drift.get_aca_offsets(row['detector'], row['chip_id'], row['chipx'], row['chipy'],
                                 time=row['mean_date'], t_ccd=row['mean_t_ccd'])
    ys.append(y)
    zs.append(z)
print "Y offsets consistent: {}".format(np.allclose(dynam_table['aca_offset_y'], ys, atol=0.02))
print "Z offsets consistent: {}".format(np.allclose(dynam_table['aca_offset_z'], zs, atol=0.02))


Y offsets consistent: True
Z offsets consistent: True

Run the ACA model and get new offsets

The dynamic offsets in the dynamic offsets / aimpoint file are calculated using the the xija ACA thermal model called from the FOT Matlab tools. To independently verify both the inputs and the outputs reported in the dynamic offsets/aimpoints file, we run the SOT version ACA model over the JUL0415O schedule interval and recalculate the aca_offsets using the calculated ACA ccd temperatures and the zero offset aimpoint information from the OR list. The ACA load review software, starcheck, already has code to determine inputs to the xija ACA model and to run the model over command products. For this test, the code to get the mean aca ccd temperature for each obsid has been extended to also run the offset calculation via chandra_aca.drift_get_aca_offsets.

+        if interval['obsid'] in obsreqs and len(ok_temps) > 0:
+            obsreq = obsreqs[interval['obsid']]
+            if 'chip_id' in obsreq:
+                ddy, ddz = get_aca_offsets(obsreq['detector'],
+                                           obsreq['chip_id'],
+                                           obsreq['chipx'],
+                                           obsreq['chipy'],
+                                           time=itimes,
+                                           t_ccd=ok_temps)
+                obs['aca_offset_y'] = np.mean(ddy)
+                obs['aca_offset_z'] = np.mean(ddz)

(see link to changed starcheck code)

Then, the returned values from that code include these independently calculated values of aca_offset_y and aca_offset_z that correspond to aca_offset_y and aca_offset_z in the dynamic aimpoint text product. (apologies for the starcheck log output)


In [4]:
from starcheck.calc_ccd_temps import get_ccd_temps
obsid_info = json.loads(get_ccd_temps(TEST_DIR,
                json_obsids=open("{}/starcheck/obsids.json".format(TEST_DIR)),
                model_spec="{}/starcheck/aca_spec.json".format(TEST_DIR),
                char_file="/proj/sot/ska/data/starcheck/characteristics.yaml",
                orlist="{}/mps/or/JUL0415_A.or".format(TEST_DIR)));


/proj/sot/ska/arch/x86_64-linux_CentOS-5/lib/python2.7/site-packages/matplotlib/__init__.py:1318: UserWarning:  This call to matplotlib.use() has no effect
because the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

  warnings.warn(_use_error_msg)
#####################################################################
INFO:calc_ccd_temps:#####################################################################
# calc_ccd_temps run at Thu Jul 28 10:33:43 2016 by jeanconn
INFO:calc_ccd_temps:# calc_ccd_temps run at Thu Jul 28 10:33:43 2016 by jeanconn
# calc_ccd_temps version = 11.11
INFO:calc_ccd_temps:# calc_ccd_temps version = 11.11
#####################################################################

INFO:calc_ccd_temps:#####################################################################

Using backstop file /proj/sot/ska/ops/SFE/JUL0415O/oflso/CR185_1018.backstop
INFO:calc_ccd_temps:Using backstop file /proj/sot/ska/ops/SFE/JUL0415O/oflso/CR185_1018.backstop
Found 1921 backstop commands between 2015:185:03:55:00.000 and 2015:194:02:29:56.800
INFO:calc_ccd_temps:Found 1921 backstop commands between 2015:185:03:55:00.000 and 2015:194:02:29:56.800
Fetching telemetry between 2015:155:03:55:01.000 and 2015:185:03:55:00.000
INFO:calc_ccd_temps:Fetching telemetry between 2015:155:03:55:01.000 and 2015:185:03:55:00.000
Constructed 657 commanded states from 2015:184:22:52:16.542 to 2015:194:02:29:56.800
INFO:calc_ccd_temps:Constructed 657 commanded states from 2015:184:22:52:16.542 to 2015:194:02:29:56.800
Calculating ACA thermal model
INFO:calc_ccd_temps:Calculating ACA thermal model
Propagation initial time and ACA: 2015:182:00:53:22.692 -16.47
INFO:calc_ccd_temps:Propagation initial time and ACA: 2015:182:00:53:22.692 -16.47
Making temperature check plots
INFO:calc_ccd_temps:Making temperature check plots
Writing plot file out/ccd_temperature.png
INFO:calc_ccd_temps:Writing plot file out/ccd_temperature.png

Compare values to dynamic offset table from Matlab

Then, for each entry in the dynamic offset table from the matlab tools, we compare the aca_offset_y and aca_offset_z with the values from the independent run of the model and the offset values calculated from within the starcheck code. For quick review, we print out the offsets and temperatures, with the dynamic aimpoint offset file versions in the first column of each value being checked.


In [5]:
y_diff = []
z_diff = []
for obsid in dynam_table['obsid']:
    dyn_rec = dynam_table[dynam_table['obsid'] == obsid][0]
    if str(obsid) in obsid_info:
        print "{} offset y {: .2f} vs {: .2f}  offset z {: .2f} vs {: .2f}  t_ccd {: .2f} vs {: .2f}".format(
            obsid,
            dyn_rec['aca_offset_y'], obsid_info[str(obsid)]['aca_offset_y'],
            dyn_rec['aca_offset_z'], obsid_info[str(obsid)]['aca_offset_z'],
            dyn_rec['mean_t_ccd'], obsid_info[str(obsid)]['ccd_temp'])
        y_diff.append(dyn_rec['aca_offset_y'] - obsid_info[str(obsid)]['aca_offset_y'])
        z_diff.append(dyn_rec['aca_offset_z'] - obsid_info[str(obsid)]['aca_offset_z'])
y_diff = np.array(y_diff)
z_diff = np.array(z_diff)


17242 offset y  6.07 vs  6.09  offset z  1.88 vs  1.89  t_ccd -15.70 vs -15.62
16653 offset y  6.05 vs  6.05  offset z  1.87 vs  1.87  t_ccd -15.70 vs -15.37
17304 offset y  7.90 vs  7.89  offset z  2.09 vs  2.08  t_ccd -16.09 vs -15.58
17065 offset y  5.04 vs  5.02  offset z  1.37 vs  1.37  t_ccd -15.44 vs -15.35
17121 offset y  4.19 vs  4.16  offset z  0.96 vs  0.94  t_ccd -15.22 vs -15.09
16737 offset y  3.82 vs  3.77  offset z  0.09 vs  0.07  t_ccd -15.05 vs -14.97
17325 offset y  7.13 vs  7.04  offset z  1.46 vs  1.42  t_ccd -15.32 vs -15.26
17326 offset y  5.73 vs  5.63  offset z  1.19 vs  1.14  t_ccd -15.39 vs -15.34
17327 offset y  5.89 vs  5.79  offset z  1.27 vs  1.22  t_ccd -15.43 vs -15.39
17328 offset y  5.96 vs  5.86  offset z  1.30 vs  1.25  t_ccd -15.45 vs -15.41
17329 offset y  6.04 vs  5.93  offset z  1.34 vs  1.29  t_ccd -15.47 vs -15.43
17305 offset y  4.24 vs  4.11  offset z  0.30 vs  0.24  t_ccd -15.16 vs -14.54
17668 offset y  1.22 vs  1.11  offset z -0.49 vs -0.55  t_ccd -14.47 vs -14.35
17306 offset y  6.43 vs  6.33  offset z  1.37 vs  1.32  t_ccd -15.72 vs -15.02
17692 offset y  2.97 vs  2.90  offset z  0.36 vs  0.32  t_ccd -14.91 vs -14.80
17307 offset y  4.08 vs  3.99  offset z  0.22 vs  0.17  t_ccd -15.12 vs -14.54
17693 offset y  1.23 vs  1.15  offset z -0.49 vs -0.53  t_ccd -14.47 vs -14.34
16767 offset y  3.49 vs  3.39  offset z -0.07 vs -0.12  t_ccd -14.97 vs -14.75
17308 offset y  7.13 vs  7.02  offset z  1.71 vs  1.66  t_ccd -15.89 vs -15.22
17440 offset y  3.74 vs  3.65  offset z  0.05 vs  0.01  t_ccd -15.03 vs -14.96
17309 offset y  3.87 vs  3.75  offset z  0.12 vs  0.06  t_ccd -15.06 vs -14.52
17695 offset y  1.14 vs  1.03  offset z -1.22 vs -1.27  t_ccd -14.37 vs -14.31
17694 offset y  1.62 vs  1.50  offset z -0.30 vs -0.36  t_ccd -14.56 vs -14.42

The maximum differences in the offsets between the values via an independent run of the model are within an arcsec.


In [6]:
print "Y offset max difference {:.2f} arcsec".format(np.max(np.abs(y_diff)))


Y offset max difference 0.13 arcsec

In [7]:
print "Z offset max difference {:.2f} arcsec".format(np.max(np.abs(z_diff)))


Z offset max difference 0.06 arcsec