diff --git a/acispy/plots.py b/acispy/plots.py index 19d6544..1034caf 100644 --- a/acispy/plots.py +++ b/acispy/plots.py @@ -313,7 +313,7 @@ def set_xlim(self, xmin, xmax): xmax = datetime.strptime(CxoTime(xmax).iso, datefmt) self.ax.set_xlim(xmin, xmax) - def add_hline(self, y, lw=2, ls='-', color='green', + def add_hline(self, y, lw=2, ls='-', color='green', xmin=None, xmax=None, **kwargs): """ Add a horizontal line on the y-axis of the plot. diff --git a/acispy/states.py b/acispy/states.py index 5e98c17..86fdb3f 100644 --- a/acispy/states.py +++ b/acispy/states.py @@ -1,11 +1,11 @@ from astropy.io import ascii import requests from acispy.units import get_units -from acispy.utils import ensure_list, find_load, calc_off_nom_rolls +from acispy.utils import ensure_list, find_load, calc_off_nom_rolls, \ + dict_to_array from acispy.units import APQuantity, APStringArray, Quantity from acispy.time_series import TimeSeriesData import numpy as np -from collections import OrderedDict from cxotime import CxoTime cmd_state_codes = {("states", "hetg"): {"RETR": 0, "INSR": 1}, @@ -15,9 +15,9 @@ ("states", "instrument"): {"ACIS-S": 0, "ACIS-I": 1, "HRC-S": 2, "HRC-I": 3}, ("states", "dither"): {"DISA": 0, "ENAB": 1}, - ("states", "pcad_mode"): {"STBY": 0, "NPNT": 1, - "NMAN": 2, "NSUN": 3, - "PWRF": 4, "RMAN": 5, + ("states", "pcad_mode"): {"STBY": 0, "NPNT": 1, + "NMAN": 2, "NSUN": 3, + "PWRF": 4, "RMAN": 5, "NULL": 6}} state_dtypes = {"ccd_count": "int", @@ -30,7 +30,7 @@ class States(TimeSeriesData): def __init__(self, table): import numpy.lib.recfunctions as rf - new_table = OrderedDict() + new_table = {} if isinstance(table, np.ndarray): state_names = list(table.dtype.names) if "date" in state_names: @@ -127,11 +127,7 @@ def get_states(self, time): return state def as_array(self): - dtype = [(k, str(v.dtype)) for k, v in self.table.items()] - data = np.zeros(len(self), dtype=dtype) - for k, v in self.table.items(): - data[k] = v.value - return data + return dict_to_array(self.table) @property def current_states(self): diff --git a/acispy/tests/fptemp_ecs.dat b/acispy/tests/fptemp_ecs.dat new file mode 100644 index 0000000..bc75f8e --- /dev/null +++ b/acispy/tests/fptemp_ecs.dat @@ -0,0 +1,441 @@ +time date fptemp_11 dpa_power earth_solid_angle +706978252.0 2020:148:14:49:42.816 -115.0 64.43031803078048 0.0 +706978580.0 2020:148:14:55:10.816 -115.03704465588494 64.43031803078048 0.0 +706978908.0 2020:148:15:00:38.816 -115.07028958987088 64.43031803078048 0.0 +706979236.0 2020:148:15:06:06.816 -115.09987832014072 64.43031803078048 0.0 +706979564.0 2020:148:15:11:34.816 -115.12595006222591 64.43031803078048 0.0 +706979892.0 2020:148:15:17:02.816 -115.14863984501294 64.43031803078048 0.0 +706980220.0 2020:148:15:22:30.816 -115.16807862380459 64.43031803078048 0.0 +706980548.0 2020:148:15:27:58.816 -115.18439339050819 64.43031803078048 0.0 +706980876.0 2020:148:15:33:26.816 -115.19770728102093 64.43031803078048 0.0 +706981204.0 2020:148:15:38:54.816 -115.20813967988087 64.43031803078048 0.0 +706981532.0 2020:148:15:44:22.816 -115.21580632225077 64.43031803078048 0.0 +706981860.0 2020:148:15:49:50.816 -115.2208193932985 64.43031803078048 0.0 +706982188.0 2020:148:15:55:18.816 -115.22328762504209 64.43031803078048 0.0 +706982516.0 2020:148:16:00:46.816 -115.22331639071756 64.43031803078048 0.0 +706982844.0 2020:148:16:06:14.816 -115.22100779673167 64.43031803078048 0.0 +706983172.0 2020:148:16:11:42.816 -115.21646077225894 64.43031803078048 0.0 +706983500.0 2020:148:16:17:10.816 -115.20977115654081 64.43031803078048 0.0 +706983828.0 2020:148:16:22:38.816 -115.20103178394356 64.43031803078048 0.0 +706984156.0 2020:148:16:28:06.816 -115.19033256683018 64.43031803078048 0.0 +706984484.0 2020:148:16:33:34.816 -115.17776057629986 64.43031803078048 0.0 +706984812.0 2020:148:16:39:02.816 -115.16340012084798 64.43031803078048 0.0 +706985140.0 2020:148:16:44:30.816 -115.14733282299731 64.43031803078048 0.0 +706985468.0 2020:148:16:49:58.816 -115.12963769395061 64.43031803078048 0.0 +706985796.0 2020:148:16:55:26.816 -115.11039120631557 64.43031803078048 0.0 +706986124.0 2020:148:17:00:54.816 -115.08966736494692 64.43031803078048 0.0 +706986452.0 2020:148:17:06:22.816 -115.06753777595354 64.43031803078048 0.0 +706986780.0 2020:148:17:11:50.816 -115.04407171391571 64.43031803078048 0.0 +706987108.0 2020:148:17:17:18.816 -115.01933618735715 64.43031803078048 0.0 +706987436.0 2020:148:17:22:46.816 -114.99339600251487 64.43031803078048 0.0 +706987764.0 2020:148:17:28:14.816 -114.96631382544926 64.43031803078048 0.0 +706988092.0 2020:148:17:33:42.816 -114.93815024253556 64.43031803078048 0.0 +706988420.0 2020:148:17:39:10.816 -114.90896381937695 64.43031803078048 0.0 +706988748.0 2020:148:17:44:38.816 -114.87881115817781 64.43031803078048 0.0 +706989076.0 2020:148:17:50:06.816 -114.84774695361703 64.43031803078048 0.0 +706989404.0 2020:148:17:55:34.816 -114.81582404725833 64.43031803078048 0.0 +706989732.0 2020:148:18:01:02.816 -114.78309348053313 64.43031803078048 0.0 +706990060.0 2020:148:18:06:30.816 -114.74960454633197 64.43031803078048 0.0 +706990388.0 2020:148:18:11:58.816 -114.7154048392395 64.43031803078048 0.0 +706990716.0 2020:148:18:17:26.816 -114.68054030444668 64.43031803078048 0.0 +706991044.0 2020:148:18:22:54.816 -114.64505528537346 64.43031803078048 0.0 +706991372.0 2020:148:18:28:22.816 -114.60899257003412 64.43031803078048 0.0 +706991700.0 2020:148:18:33:50.816 -114.57239343617685 64.43031803078048 0.0 +706992028.0 2020:148:18:39:18.816 -114.53529769522827 64.43031803078048 0.0 +706992356.0 2020:148:18:44:46.816 -114.49774373507178 64.43031803078048 0.0 +706992684.0 2020:148:18:50:14.816 -114.45976856169214 64.43031803078048 0.0 +706993012.0 2020:148:18:55:42.816 -114.42140783971203 64.43031803078048 0.0 +706993340.0 2020:148:19:01:10.816 -114.3826959318491 64.43031803078048 0.0 +706993668.0 2020:148:19:06:38.816 -114.34366593732076 64.43031803078048 0.0 +706993996.0 2020:148:19:12:06.816 -114.30434972922342 64.43031803078048 0.0 +706994324.0 2020:148:19:17:34.816 -114.2647779909118 64.43031803078048 0.0 +706994652.0 2020:148:19:23:02.816 -114.22498025140382 64.43031803078048 0.0 +706994980.0 2020:148:19:28:30.816 -114.18498491983554 64.43031803078048 0.0 +706995308.0 2020:148:19:33:58.816 -114.14481931899022 64.43031803078048 0.0 +706995636.0 2020:148:19:39:26.816 -114.10450971792486 64.43031803078048 0.0 +706995964.0 2020:148:19:44:54.816 -114.06408136371638 64.43031803078048 0.0 +706996292.0 2020:148:19:50:22.816 -114.02355851235266 64.43031803078048 0.0 +706996620.0 2020:148:19:55:50.816 -113.98296445878695 64.43031803078048 0.0 +706996948.0 2020:148:20:01:18.816 -113.94232156617811 64.43031803078048 0.0 +706997276.0 2020:148:20:06:46.816 -113.90165129433738 64.43031803078048 0.0 +706997604.0 2020:148:20:12:14.816 -113.86097422740187 64.43031803078048 0.0 +706997932.0 2020:148:20:17:42.816 -113.82031010075436 64.43031803078048 0.0 +706998260.0 2020:148:20:23:10.816 -113.77967782720897 64.43031803078048 0.0 +706998588.0 2020:148:20:28:38.816 -113.73909552248122 64.43031803078048 0.0 +706998916.0 2020:148:20:34:06.816 -113.69858052996075 64.43031803078048 0.0 +706999244.0 2020:148:20:39:34.816 -113.65814944480428 64.43031803078048 0.0 +706999572.0 2020:148:20:45:02.816 -113.61781813736678 64.43031803078048 0.0 +706999900.0 2020:148:20:50:30.816 -113.5776017759886 64.43031803078048 0.0 +707000228.0 2020:148:20:55:58.816 -113.53751484915337 64.43031803078048 0.0 +707000556.0 2020:148:21:01:26.816 -113.49757118703377 64.43031803078048 0.0 +707000884.0 2020:148:21:06:54.816 -113.45778398244067 64.43031803078048 0.0 +707001212.0 2020:148:21:12:22.816 -113.41816581119122 64.43031803078048 0.0 +707001540.0 2020:148:21:17:50.816 -113.37872865191069 64.43031803078048 0.0 +707001868.0 2020:148:21:23:18.816 -113.33948390528298 64.43031803078048 0.0 +707002196.0 2020:148:21:28:46.816 -113.30044241276364 64.43031803078048 0.0 +707002524.0 2020:148:21:34:14.816 -113.26161447476981 64.43031803078048 0.0 +707002852.0 2020:148:21:39:42.816 -113.22300986835937 64.43031803078048 0.0 +707003180.0 2020:148:21:45:10.816 -113.18463786441491 64.43031803078048 0.0 +707003508.0 2020:148:21:50:38.816 -113.14650724434397 64.43031803078048 0.0 +707003836.0 2020:148:21:56:06.816 -113.10862631630773 64.43031803078048 0.0 +707004164.0 2020:148:22:01:34.816 -113.07100293099113 64.43031803078048 0.0 +707004492.0 2020:148:22:07:02.816 -113.03364449692589 64.43031803078048 0.0 +707004820.0 2020:148:22:12:30.816 -112.9965579953786 64.43031803078048 0.0 +707005148.0 2020:148:22:17:58.816 -112.95974999481491 64.43031803078048 0.0 +707005476.0 2020:148:22:23:26.816 -112.92322666495107 64.43031803078048 0.0 +707005804.0 2020:148:22:28:54.816 -112.88699379040357 64.43031803078048 0.0 +707006132.0 2020:148:22:34:22.816 -112.85105678394748 64.43031803078048 0.0 +707006460.0 2020:148:22:39:50.816 -112.81542069939275 64.43031803078048 0.0 +707006788.0 2020:148:22:45:18.816 -112.78009024409143 64.43031803078048 0.0 +707007116.0 2020:148:22:50:46.816 -112.74506979108288 64.43031803078048 0.0 +707007444.0 2020:148:22:56:14.816 -112.7103633908871 64.43031803078048 0.0 +707007772.0 2020:148:23:01:42.816 -112.67597478295562 64.43031803078048 0.0 +707008100.0 2020:148:23:07:10.816 -112.64190740678916 64.43031803078048 0.0 +707008428.0 2020:148:23:12:38.816 -112.60816441273066 64.43031803078048 0.0 +707008756.0 2020:148:23:18:06.816 -112.57474867244251 64.43031803078048 0.0 +707009084.0 2020:148:23:23:34.816 -112.54166278907618 64.43031803078048 0.0 +707009412.0 2020:148:23:29:02.816 -112.50890910714261 64.43031803078048 0.0 +707009740.0 2020:148:23:34:30.816 -112.47648972209093 64.43031803078048 0.0 +707010068.0 2020:148:23:39:58.816 -112.44440648960335 64.43031803078048 0.0 +707010396.0 2020:148:23:45:26.816 -112.41266103461548 64.43031803078048 0.0 +707010724.0 2020:148:23:50:54.816 -112.3812547600672 64.43031803078048 0.0 +707011052.0 2020:148:23:56:22.816 -112.35018885539206 64.43031803078048 0.0 +707011380.0 2020:149:00:01:50.816 -112.31946430475244 64.43031803078048 0.0 +707011708.0 2020:149:00:07:18.816 -112.28908189502708 64.43031803078048 0.0 +707012036.0 2020:149:00:12:46.816 -112.25904222355774 64.43031803078048 0.0 +707012364.0 2020:149:00:18:14.816 -112.2293457056616 64.43031803078048 0.0 +707012692.0 2020:149:00:23:42.816 -112.19999258191557 64.43031803078048 0.0 +707013020.0 2020:149:00:29:10.816 -112.1709829252187 64.43031803078048 0.0 +707013348.0 2020:149:00:34:38.816 -112.14231664763831 64.43031803078048 0.0 +707013676.0 2020:149:00:40:06.816 -112.11399350704673 64.43031803078048 0.0 +707014004.0 2020:149:00:45:34.816 -112.08601311355423 64.43031803078048 0.0 +707014332.0 2020:149:00:51:02.816 -112.05837493574276 64.43031803078048 0.0 +707014660.0 2020:149:00:56:30.816 -112.0310783067064 64.43031803078048 0.0 +707014988.0 2020:149:01:01:58.816 -112.00412242990392 64.43031803078048 0.0 +707015316.0 2020:149:01:07:26.816 -111.9775063848284 64.43031803078048 0.0 +707015644.0 2020:149:01:12:54.816 -111.95122913249921 64.43031803078048 0.0 +707015972.0 2020:149:01:18:22.816 -111.92528952078096 64.43031803078048 0.0 +707016300.0 2020:149:01:23:50.816 -111.89968628953439 64.43031803078048 0.0 +707016628.0 2020:149:01:29:18.816 -111.87441807560371 64.43031803078048 0.0 +707016956.0 2020:149:01:34:46.816 -111.84948341764422 64.43031803078048 0.0 +707017284.0 2020:149:01:40:14.816 -111.82488076079677 64.43031803078048 0.0 +707017612.0 2020:149:01:45:42.816 -111.80060846121161 64.43031803078048 0.0 +707017940.0 2020:149:01:51:10.816 -111.77666479042585 64.43031803078048 0.0 +707018268.0 2020:149:01:56:38.816 -111.75304793959901 64.43031803078048 0.0 +707018596.0 2020:149:02:02:06.816 -111.72975602361043 64.43031803078048 0.0 +707018924.0 2020:149:02:07:34.816 -111.7067870850226 64.43031803078048 0.0 +707019252.0 2020:149:02:13:02.816 -111.68413909791404 64.43031803078048 0.0 +707019580.0 2020:149:02:18:30.816 -111.66180997158551 64.43031803078048 0.0 +707019908.0 2020:149:02:23:58.816 -111.63979755414294 64.43031803078048 0.0 +707020236.0 2020:149:02:29:26.816 -111.61809963596073 64.43031803078048 0.0 +707020564.0 2020:149:02:34:54.816 -111.59671395302793 64.43031803078048 0.0 +707020892.0 2020:149:02:40:22.816 -111.57563819018327 64.43031803078048 0.0 +707021220.0 2020:149:02:45:50.816 -111.55486998423945 64.43031803078048 0.0 +707021548.0 2020:149:02:51:18.816 -111.53440692700076 64.43031803078048 0.0 +707021876.0 2020:149:02:56:46.816 -111.5142465681772 64.43031803078048 0.0 +707022204.0 2020:149:03:02:14.816 -111.49438641819783 64.43031803078048 0.0 +707022532.0 2020:149:03:07:42.816 -111.47482395092655 64.43031803078048 0.0 +707022860.0 2020:149:03:13:10.816 -111.4555566062828 64.43031803078048 0.0 +707023188.0 2020:149:03:18:38.816 -111.43658179277026 64.43031803078048 0.0 +707023516.0 2020:149:03:24:06.816 -111.41789688991592 64.43031803078048 0.0 +707023844.0 2020:149:03:29:34.816 -111.39949925062189 64.43031803078048 0.0 +707024172.0 2020:149:03:35:02.816 -111.38138620343298 64.43031803078048 0.0 +707024500.0 2020:149:03:40:30.816 -111.36355505472334 64.43031803078048 0.0 +707024828.0 2020:149:03:45:58.816 -111.34600309080272 64.43031803078048 0.0 +707025156.0 2020:149:03:51:26.816 -111.32872757994582 64.43031803078048 0.0 +707025484.0 2020:149:03:56:54.816 -111.31172577434646 64.43031803078048 0.0 +707025812.0 2020:149:04:02:22.816 -111.29499491199923 64.43031803078048 0.0 +707026140.0 2020:149:04:07:50.816 -111.2785322185105 64.43031803078048 0.0 +707026468.0 2020:149:04:13:18.816 -111.26233490884108 64.43031803078048 0.0 +707026796.0 2020:149:04:18:46.816 -111.24640018898229 64.43031803078048 0.0 +707027124.0 2020:149:04:24:14.816 -111.23072525756777 64.43031803078048 0.0 +707027452.0 2020:149:04:29:42.816 -111.21530730742197 64.43031803078048 0.0 +707027780.0 2020:149:04:35:10.816 -111.20014352704916 64.43031803078048 0.0 +707028108.0 2020:149:04:40:38.816 -111.18523110206365 64.43031803078048 0.0 +707028436.0 2020:149:04:46:06.816 -111.17056721656247 64.43031803078048 0.0 +707028764.0 2020:149:04:51:34.816 -111.15614905444296 64.43031803078048 0.0 +707029092.0 2020:149:04:57:02.816 -111.14197380066666 64.43031803078048 0.0 +707029420.0 2020:149:05:02:30.816 -111.12803864247125 64.43031803078048 0.0 +707029748.0 2020:149:05:07:58.816 -111.11434077053212 64.43031803078048 0.0 +707030076.0 2020:149:05:13:26.816 -111.10087738007515 64.43031803078048 0.0 +707030404.0 2020:149:05:18:54.816 -111.08764567194213 64.43031803078048 0.0 +707030732.0 2020:149:05:24:22.816 -111.07464285361037 64.43031803078048 0.0 +707031060.0 2020:149:05:29:50.816 -111.06186614016694 64.43031803078048 0.0 +707031388.0 2020:149:05:35:18.816 -111.04931275524174 64.43031803078048 0.0 +707031716.0 2020:149:05:40:46.816 -111.03697993189805 64.43031803078048 0.0 +707032044.0 2020:149:05:46:14.816 -111.02486491348262 64.43031803078048 0.0 +707032372.0 2020:149:05:51:42.816 -111.01296495443671 64.43031803078048 0.0 +707032700.0 2020:149:05:57:10.816 -111.00127732106924 64.43031803078048 0.0 +707033028.0 2020:149:06:02:38.816 -110.98979929229331 64.43031803078048 0.0 +707033356.0 2020:149:06:08:06.816 -110.97852816032729 64.43031803078048 0.0 +707033684.0 2020:149:06:13:34.816 -110.96746123136148 64.43031803078048 0.0 +707034012.0 2020:149:06:19:02.816 -110.95659582619174 64.43031803078048 0.0 +707034340.0 2020:149:06:24:30.816 -110.9459292808205 64.43031803078048 0.0 +707034668.0 2020:149:06:29:58.816 -110.93545894702656 64.43031803078048 0.0 +707034996.0 2020:149:06:35:26.816 -110.92518219290615 64.43031803078048 0.0 +707035324.0 2020:149:06:40:54.816 -110.91509640338397 64.43031803078048 0.0 +707035652.0 2020:149:06:46:22.816 -110.90519898069623 64.43031803078048 0.0 +707035980.0 2020:149:06:51:50.816 -110.89548734484644 64.43031803078048 0.0 +707036308.0 2020:149:06:57:18.816 -110.885958934035 64.43031803078048 0.0 +707036636.0 2020:149:07:02:46.816 -110.87661120506327 64.43031803078048 0.0 +707036964.0 2020:149:07:08:14.816 -110.86744163371323 64.43031803078048 0.0 +707037292.0 2020:149:07:13:42.816 -110.85844771510337 64.43031803078048 0.0 +707037620.0 2020:149:07:19:10.816 -110.84962696402171 64.43031803078048 0.0 +707037948.0 2020:149:07:24:38.816 -110.84097691523617 64.43031803078048 0.0 +707038276.0 2020:149:07:30:06.816 -110.83249512378423 64.43031803078048 0.0 +707038604.0 2020:149:07:35:34.816 -110.82417916524237 64.43031803078048 0.0 +707038932.0 2020:149:07:41:02.816 -110.81602663597518 64.43031803078048 0.0 +707039260.0 2020:149:07:46:30.816 -110.80803515336522 64.43031803078048 0.0 +707039588.0 2020:149:07:51:58.816 -110.80020235602454 64.43031803078048 0.0 +707039916.0 2020:149:07:57:26.816 -110.79252590398812 64.43031803078048 0.0 +707040244.0 2020:149:08:02:54.816 -110.78500347889036 64.43031803078048 0.0 +707040572.0 2020:149:08:08:22.816 -110.77763278412483 64.43031803078048 0.0 +707040900.0 2020:149:08:13:50.816 -110.77041154498812 64.43031803078048 0.0 +707041228.0 2020:149:08:19:18.816 -110.76333750880829 64.43031803078048 0.0 +707041556.0 2020:149:08:24:46.816 -110.75640844505767 64.43031803078048 0.0 +707041884.0 2020:149:08:30:14.816 -110.7496221454529 64.43031803078048 0.0 +707042212.0 2020:149:08:35:42.816 -110.74297642404079 64.43031803078048 0.0 +707042540.0 2020:149:08:41:10.816 -110.7364691172707 64.43031803078048 0.0 +707042868.0 2020:149:08:46:38.816 -110.73009808405435 64.43031803078048 0.0 +707043196.0 2020:149:08:52:06.816 -110.72386120581325 64.43031803078048 0.0 +707043524.0 2020:149:08:57:34.816 -110.71775638651458 64.43031803078048 0.0 +707043852.0 2020:149:09:03:02.816 -110.7117815526956 64.43031803078048 0.0 +707044180.0 2020:149:09:08:30.816 -110.70593465347739 64.43031803078048 0.0 +707044508.0 2020:149:09:13:58.816 -110.70021366056811 64.43031803078048 0.0 +707044836.0 2020:149:09:19:26.816 -110.69461656825618 64.43031803078048 0.0 +707045164.0 2020:149:09:24:54.816 -110.68914139339323 64.43031803078048 0.0 +707045492.0 2020:149:09:30:22.816 -110.68378617536958 64.43031803078048 0.0 +707045820.0 2020:149:09:35:50.816 -110.67854897608 64.43031803078048 0.0 +707046148.0 2020:149:09:41:18.816 -110.67342787988105 64.43031803078048 0.0 +707046476.0 2020:149:09:46:46.816 -110.66842099354035 64.43031803078048 0.0 +707046804.0 2020:149:09:52:14.816 -110.66352644617815 64.43031803078048 0.0 +707047132.0 2020:149:09:57:42.816 -110.65874238920152 64.43031803078048 0.0 +707047460.0 2020:149:10:03:10.816 -110.65406699623148 64.43031803078048 0.0 +707047788.0 2020:149:10:08:38.816 -110.64949846302338 64.43031803078048 0.0 +707048116.0 2020:149:10:14:06.816 -110.64503500738094 64.43031803078048 0.0 +707048444.0 2020:149:10:19:34.816 -110.64067486906366 64.43031803078048 0.0 +707048772.0 2020:149:10:25:02.816 -110.6364163096886 64.43031803078048 0.0 +707049100.0 2020:149:10:30:30.816 -110.63225761262753 64.43031803078048 0.0 +707049428.0 2020:149:10:35:58.816 -110.62819708289801 64.43031803078048 0.0 +707049756.0 2020:149:10:41:26.816 -110.62423304704957 64.43031803078048 0.0 +707050084.0 2020:149:10:46:54.816 -110.620363853045 64.43031803078048 0.0 +707050412.0 2020:149:10:52:22.816 -110.61658787013721 64.43031803078048 0.0 +707050740.0 2020:149:10:57:50.816 -110.61290348874167 64.43031803078048 0.0 +707051068.0 2020:149:11:03:18.816 -110.60930912030489 64.43031803078048 0.0 +707051396.0 2020:149:11:08:46.816 -110.60580319716902 64.43031803078048 0.0 +707051724.0 2020:149:11:14:14.816 -110.60238417243276 64.43031803078048 0.0 +707052052.0 2020:149:11:19:42.816 -110.59905051980823 64.43031803078048 0.0 +707052380.0 2020:149:11:25:10.816 -110.59580073347558 64.43031803078048 0.0 +707052708.0 2020:149:11:30:38.816 -110.59263332793469 64.43031803078048 0.0 +707053036.0 2020:149:11:36:06.816 -110.58954683785348 64.43031803078048 0.0 +707053364.0 2020:149:11:41:34.816 -110.58653981791366 64.43031803078048 0.0 +707053692.0 2020:149:11:47:02.816 -110.58361084265404 64.43031803078048 0.0 +707054020.0 2020:149:11:52:30.816 -110.58075850631137 64.43031803078048 0.0 +707054348.0 2020:149:11:57:58.816 -110.57798142265912 64.43031803078048 0.0 +707054676.0 2020:149:12:03:26.816 -110.5752782248442 64.43031803078048 0.0 +707055004.0 2020:149:12:08:54.816 -110.57264756522218 64.43031803078048 0.0 +707055332.0 2020:149:12:14:22.816 -110.57008811518985 64.43031803078048 0.0 +707055660.0 2020:149:12:19:50.816 -110.56759856501603 64.43031803078048 0.0 +707055988.0 2020:149:12:25:18.816 -110.56517762367281 64.43031803078048 0.0 +707056316.0 2020:149:12:30:46.816 -110.56282401866443 64.43031803078048 0.0 +707056644.0 2020:149:12:36:14.816 -110.56053649585496 64.43031803078048 0.0 +707056972.0 2020:149:12:41:42.816 -110.55831381929492 64.43031803078048 0.0 +707057300.0 2020:149:12:47:10.816 -110.55615477104696 64.43031803078048 0.0 +707057628.0 2020:149:12:52:38.816 -110.5540581510107 64.43031803078048 0.0 +707057956.0 2020:149:12:58:06.816 -110.55202277674684 64.43031803078048 0.0 +707058284.0 2020:149:13:03:34.816 -110.55004748330077 64.43031803078048 0.0 +707058612.0 2020:149:13:09:02.816 -110.54813112302548 64.43031803078048 0.0 +707058940.0 2020:149:13:14:30.816 -110.54627256540392 64.43031803078048 0.0 +707059268.0 2020:149:13:19:58.816 -110.54447069687073 64.43031803078048 0.0 +707059596.0 2020:149:13:25:26.816 -110.54272442063507 64.43031803078048 0.0 +707059924.0 2020:149:13:30:54.816 -110.54103265650251 64.43031803078048 0.0 +707060252.0 2020:149:13:36:22.816 -110.53939434069683 64.43031803078048 0.0 +707060580.0 2020:149:13:41:50.816 -110.53780842568182 64.43031803078048 0.0 +707060908.0 2020:149:13:47:18.816 -110.53627387998316 64.43031803078048 0.0 +707061236.0 2020:149:13:52:46.816 -110.53478968801055 64.43031803078048 0.0 +707061564.0 2020:149:13:58:14.816 -110.53335484987993 64.43031803078048 0.0 +707061892.0 2020:149:14:03:42.816 -110.5319683812361 64.43031803078048 0.0 +707062220.0 2020:149:14:09:10.816 -110.53062931307566 64.43031803078048 0.0 +707062548.0 2020:149:14:14:38.816 -110.52933669156982 64.43031803078048 0.0 +707062876.0 2020:149:14:20:06.816 -110.52808957788832 64.43031803078048 0.0 +707063204.0 2020:149:14:25:34.816 -110.52688704802432 64.43031803078048 0.0 +707063532.0 2020:149:14:31:02.816 -110.52572819261938 64.43031803078048 0.0 +707063860.0 2020:149:14:36:30.816 -110.5246121167891 64.43031803078048 0.0 +707064188.0 2020:149:14:41:58.816 -110.52353793994936 64.43031803078048 0.0 +707064516.0 2020:149:14:47:26.816 -110.52250479564343 64.43031803078048 0.0 +707064844.0 2020:149:14:52:54.816 -110.52151183136972 64.43031803078048 0.0 +707065172.0 2020:149:14:58:22.816 -110.52055820841049 64.43031803078048 0.0 +707065500.0 2020:149:15:03:50.816 -110.51964310166132 64.43031803078048 0.0 +707065828.0 2020:149:15:09:18.816 -110.51876569946148 64.43031803078048 0.0 +707066156.0 2020:149:15:14:46.816 -110.51792520342448 64.43031803078048 0.0 +707066484.0 2020:149:15:20:14.816 -110.51712082827102 64.43031803078048 0.0 +707066812.0 2020:149:15:25:42.816 -110.51635180166252 64.43031803078048 0.0 +707067140.0 2020:149:15:31:10.816 -110.51561736403555 64.43031803078048 0.0 +707067468.0 2020:149:15:36:38.816 -110.51491676843716 64.43031803078048 0.0 +707067796.0 2020:149:15:42:06.816 -110.51424928036143 64.43031803078048 0.0 +707068124.0 2020:149:15:47:34.816 -110.51361417758707 64.43031803078048 0.0 +707068452.0 2020:149:15:53:02.816 -110.51301075001628 64.43031803078048 0.0 +707068780.0 2020:149:15:58:30.816 -110.51243829951459 64.43031803078048 0.0 +707069108.0 2020:149:16:03:58.816 -110.51189613975201 64.43031803078048 0.0 +707069436.0 2020:149:16:09:26.816 -110.5113835960453 64.43031803078048 0.0 +707069764.0 2020:149:16:14:54.816 -110.51090000520063 64.43031803078048 0.0 +707070092.0 2020:149:16:20:22.816 -110.51044471535934 64.43031803078048 0.0 +707070420.0 2020:149:16:25:50.816 -110.51001708584413 64.43031803078048 0.0 +707070748.0 2020:149:16:31:18.816 -110.50961648700628 64.43031803078048 0.0 +707071076.0 2020:149:16:36:46.816 -110.50924230007438 64.43031803078048 0.0 +707071404.0 2020:149:16:42:14.816 -110.50889391700417 64.43031803078048 0.0 +707071732.0 2020:149:16:47:42.816 -110.50857074032986 64.43031803078048 0.0 +707072060.0 2020:149:16:53:10.816 -110.50827218301666 64.43031803078048 0.0 +707072388.0 2020:149:16:58:38.816 -110.5079976683147 64.43031803078048 0.0 +707072716.0 2020:149:17:04:06.816 -110.50774662961432 64.43031803078048 0.0 +707073044.0 2020:149:17:09:34.816 -110.50751851030216 64.43031803078048 0.0 +707073372.0 2020:149:17:15:02.816 -110.50731276361897 64.43031803078048 0.0 +707073700.0 2020:149:17:20:30.816 -110.50712885251959 64.43031803078048 0.0 +707074028.0 2020:149:17:25:58.816 -110.50696624953365 64.43031803078048 0.0 +707074356.0 2020:149:17:31:26.816 -110.5068244366277 64.43031803078048 0.0 +707074684.0 2020:149:17:36:54.816 -110.5067029050686 64.43031803078048 0.0 +707075012.0 2020:149:17:42:22.816 -110.50660115528838 64.43031803078048 0.0 +707075340.0 2020:149:17:47:50.816 -110.50651869675049 64.43031803078048 0.0 +707075668.0 2020:149:17:53:18.816 -110.50645504781737 64.43031803078048 0.0 +707075996.0 2020:149:17:58:46.816 -110.50640973561946 64.43031803078048 0.0 +707076324.0 2020:149:18:04:14.816 -110.50638229592556 64.43031803078048 0.0 +707076652.0 2020:149:18:09:42.816 -110.50637227301387 64.43031803078048 0.0 +707076980.0 2020:149:18:15:10.816 -110.50637921954554 64.43031803078048 0.0 +707077308.0 2020:149:18:20:38.816 -110.5064026964396 64.43031803078048 0.0 +707077636.0 2020:149:18:26:06.816 -110.50644227274887 64.43031803078048 0.0 +707077964.0 2020:149:18:31:34.816 -110.50649752553734 64.43031803078048 0.0 +707078292.0 2020:149:18:37:02.816 -110.50656803975876 64.43031803078048 0.0 +707078620.0 2020:149:18:42:30.816 -110.50665340813677 64.43031803078048 0.0 +707078948.0 2020:149:18:47:58.816 -110.50675323104629 64.43031803078048 0.0 +707079276.0 2020:149:18:53:26.816 -110.50686711639635 64.43031803078048 0.0 +707079604.0 2020:149:18:58:54.816 -110.50699467951425 64.43031803078048 0.0 +707079932.0 2020:149:19:04:22.816 -110.50713554303104 64.43031803078048 0.0 +707080260.0 2020:149:19:09:50.816 -110.50728933676731 64.43031803078048 0.0 +707080588.0 2020:149:19:15:18.816 -110.50745569762252 64.43031803078048 0.0 +707080916.0 2020:149:19:20:46.816 -110.50763426946455 64.43031803078048 0.0 +707081244.0 2020:149:19:26:14.816 -110.50782470302067 64.43031803078048 0.0 +707081572.0 2020:149:19:31:42.816 -110.50802665576974 64.43031803078048 0.0 +707081900.0 2020:149:19:37:10.816 -110.5082397918357 64.43031803078048 0.0 +707082228.0 2020:149:19:42:38.816 -110.50846378188251 64.43031803078048 0.0 +707082556.0 2020:149:19:48:06.816 -110.50869830301022 64.43031803078048 0.0 +707082884.0 2020:149:19:53:34.816 -110.5089430386525 64.43031803078048 0.0 +707083212.0 2020:149:19:59:02.816 -110.50919767847536 64.43031803078048 0.0 +707083540.0 2020:149:20:04:30.816 -110.50946191827686 64.43031803078048 0.0 +707083868.0 2020:149:20:09:58.816 -110.50973545988785 64.43031803078048 0.0 +707084196.0 2020:149:20:15:26.816 -110.51001801107543 64.43031803078048 0.0 +707084524.0 2020:149:20:20:54.816 -110.5103092854468 64.43031803078048 0.0 +707084852.0 2020:149:20:26:22.816 -110.5106090023543 64.43031803078048 0.0 +707085180.0 2020:149:20:31:50.816 -110.51091688680177 64.43031803078048 0.0 +707085508.0 2020:149:20:37:18.816 -110.51123266935203 64.43031803078048 0.0 +707085836.0 2020:149:20:42:46.816 -110.51155608603567 64.43031803078048 0.0 +707086164.0 2020:149:20:48:14.816 -110.511886878261 64.43031803078048 0.0 +707086492.0 2020:149:20:53:42.816 -110.51222479272522 64.43031803078048 0.0 +707086820.0 2020:149:20:59:10.816 -110.51256958132677 64.43031803078048 0.0 +707087148.0 2020:149:21:04:38.816 -110.51292100107818 64.43031803078048 0.0 +707087476.0 2020:149:21:10:06.816 -110.5132788140209 64.43031803078048 0.0 +707087804.0 2020:149:21:15:34.816 -110.51364278714168 64.43031803078048 0.0 +707088132.0 2020:149:21:21:02.816 -110.51401269228971 64.43031803078048 0.0 +707088460.0 2020:149:21:26:30.816 -110.51438830609469 64.43031803078048 0.0 +707088788.0 2020:149:21:31:58.816 -110.51476940988611 64.43031803078048 0.0 +707089116.0 2020:149:21:37:26.816 -110.51515578961369 64.43031803078048 0.0 +707089444.0 2020:149:21:42:54.816 -110.5155472357688 64.43031803078048 0.0 +707089772.0 2020:149:21:48:22.816 -110.51594354330717 64.43031803078048 0.0 +707090100.0 2020:149:21:53:50.816 -110.51634451157248 64.43031803078048 0.0 +707090428.0 2020:149:21:59:18.816 -110.51674994422119 64.43031803078048 0.0 +707090756.0 2020:149:22:04:46.816 -110.51715964914725 64.43031803078048 0.0 +707091084.0 2020:149:22:10:14.816 -110.51757343840985 64.43031803078048 0.0 +707091412.0 2020:149:22:15:42.816 -110.51799112816165 64.43031803078048 0.0 +707091740.0 2020:149:22:21:10.816 -110.51841253857766 64.43031803078048 0.0 +707092068.0 2020:149:22:26:38.816 -110.51883749378528 64.43031803078048 0.0 +707092396.0 2020:149:22:32:06.816 -110.51926582179527 64.43031803078048 0.0 +707092724.0 2020:149:22:37:34.816 -110.51969735443376 64.43031803078048 0.0 +707093052.0 2020:149:22:43:02.816 -110.5201319272752 64.43031803078048 0.0 +707093380.0 2020:149:22:48:30.816 -110.5205693795764 64.43031803078048 0.0 +707093708.0 2020:149:22:53:58.816 -110.52100955421139 64.43031803078048 0.0 +707094036.0 2020:149:22:59:26.816 -110.52145229760721 64.43031803078048 0.0 +707094364.0 2020:149:23:04:54.816 -110.52189745967966 64.43031803078048 0.0 +707094692.0 2020:149:23:10:22.816 -110.52234489377233 64.43031803078048 0.0 +707095020.0 2020:149:23:15:50.816 -110.52279445659532 64.43031803078048 0.0 +707095348.0 2020:149:23:21:18.816 -110.52324600816488 64.43031803078048 0.0 +707095676.0 2020:149:23:26:46.816 -110.52369941174388 64.43031803078048 0.0 +707096004.0 2020:149:23:32:14.816 -110.52415453378327 64.43031803078048 0.0 +707096332.0 2020:149:23:37:42.816 -110.52461124386443 64.43031803078048 0.0 +707096660.0 2020:149:23:43:10.816 -110.52506941464226 64.43031803078048 0.0 +707096988.0 2020:149:23:48:38.816 -110.52552892178929 64.43031803078048 0.0 +707097316.0 2020:149:23:54:06.816 -110.52598964394055 64.43031803078048 0.0 +707097644.0 2020:149:23:59:34.816 -110.52645146263876 64.43031803078048 0.0 +707097972.0 2020:150:00:05:02.816 -110.52691426228063 64.43031803078048 0.0 +707098300.0 2020:150:00:10:30.816 -110.52737793006507 64.43031803078048 0.0 +707098628.0 2020:150:00:15:58.816 -110.52784235594153 64.43031803078048 0.0 +707098956.0 2020:150:00:21:26.816 -110.5283074325589 64.43031803078048 0.0 +707099284.0 2020:150:00:26:54.816 -110.52877305521538 64.43031803078048 0.0 +707099612.0 2020:150:00:32:22.816 -110.52923912180906 64.43031803078048 0.0 +707099940.0 2020:150:00:37:50.816 -110.52970553278925 64.43031803078048 0.0 +707100268.0 2020:150:00:43:18.816 -110.53017219110866 64.43031803078048 0.0 +707100596.0 2020:150:00:48:46.816 -110.53063900217624 64.43031803078048 0.0 +707100924.0 2020:150:00:54:14.816 -110.53110587381084 64.43031803078048 0.0 +707101252.0 2020:150:00:59:42.816 -110.53157271619449 64.43031803078048 0.0 +707101580.0 2020:150:01:05:10.816 -110.53203944182808 64.43031803078048 0.0 +707101908.0 2020:150:01:10:38.816 -110.53250596548766 64.43031803078048 0.0 +707102236.0 2020:150:01:16:06.816 -110.53297220418094 64.43031803078048 0.0 +707102564.0 2020:150:01:21:34.816 -110.53343807710449 64.43031803078048 0.0 +707102892.0 2020:150:01:27:02.816 -110.53390350560166 64.43031803078048 0.0 +707103220.0 2020:150:01:32:30.816 -110.53436841312109 64.43031803078048 0.0 +707103548.0 2020:150:01:37:58.816 -110.534832725176 64.43031803078048 0.0 +707103876.0 2020:150:01:43:26.816 -110.53529636930406 64.43031803078048 0.0 +707104204.0 2020:150:01:48:54.816 -110.53575927502798 64.43031803078048 0.0 +707104532.0 2020:150:01:54:22.816 -110.53622137381666 64.43031803078048 0.0 +707104860.0 2020:150:01:59:50.816 -110.53668259904546 64.43031803078048 0.0 +707105188.0 2020:150:02:05:18.816 -110.53714288596024 64.43031803078048 0.0 +707105516.0 2020:150:02:10:46.816 -110.53760217164043 64.43031803078048 0.0 +707105844.0 2020:150:02:16:14.816 -110.53806039496274 64.43031803078048 0.0 +707106172.0 2020:150:02:21:42.816 -110.53851749656543 64.43031803078048 0.0 +707106500.0 2020:150:02:27:10.816 -110.5389734188132 64.43031803078048 0.0 +707106828.0 2020:150:02:32:38.816 -110.53942810576258 64.43031803078048 0.0 +707107156.0 2020:150:02:38:06.816 -110.53988150312804 64.43031803078048 0.0 +707107484.0 2020:150:02:43:34.816 -110.54033355824856 64.43031803078048 0.0 +707107812.0 2020:150:02:49:02.816 -110.54078422005473 64.43031803078048 0.0 +707108140.0 2020:150:02:54:30.816 -110.54123343903613 64.43031803078048 0.0 +707108468.0 2020:150:02:59:58.816 -110.54168116720862 64.43031803078048 0.0 +707108796.0 2020:150:03:05:26.816 -110.54212735808451 64.43031803078048 0.0 +707109124.0 2020:150:03:10:54.816 -110.54257196664187 64.43031803078048 0.0 +707109452.0 2020:150:03:16:22.816 -110.54301494929432 64.43031803078048 0.0 +707109780.0 2020:150:03:21:50.816 -110.5434562638614 64.43031803078048 0.0 +707110108.0 2020:150:03:27:18.816 -110.54389586953945 64.43031803078048 0.0 +707110436.0 2020:150:03:32:46.816 -110.54433372687292 64.43031803078048 0.0 +707110764.0 2020:150:03:38:14.816 -110.54476979772622 64.43031803078048 0.0 +707111092.0 2020:150:03:43:42.816 -110.54520404525604 64.43031803078048 0.0 +707111420.0 2020:150:03:49:10.816 -110.54563643388418 64.43031803078048 0.0 +707111748.0 2020:150:03:54:38.816 -110.54606692926978 64.43031803078048 0.0 +707112076.0 2020:150:04:00:06.816 -110.54649549828324 64.43031803078048 0.0 +707112404.0 2020:150:04:05:34.816 -110.54692210898126 64.43031803078048 0.0 +707112732.0 2020:150:04:11:02.816 -110.5473467305816 64.43031803078048 0.0 +707113060.0 2020:150:04:16:30.816 -110.54776933343787 64.43031803078048 0.0 +707113388.0 2020:150:04:21:58.816 -110.54818988901526 64.43031803078048 0.0 +707113716.0 2020:150:04:27:26.816 -110.54860836986641 64.43031803078048 0.0 +707114044.0 2020:150:04:32:54.816 -110.5490247496078 64.43031803078048 0.0 +707114372.0 2020:150:04:38:22.816 -110.54943900289648 64.43031803078048 0.0 +707114700.0 2020:150:04:43:50.816 -110.54985110540733 64.43031803078048 0.0 +707115028.0 2020:150:04:49:18.816 -110.55026103381061 64.43031803078048 0.0 +707115356.0 2020:150:04:54:46.816 -110.55066876574833 64.43031803078048 0.0 +707115684.0 2020:150:05:00:14.816 -110.55107427981388 64.43031803078048 0.0 +707116012.0 2020:150:05:05:42.816 -110.55147755553122 64.43031803078048 0.0 +707116340.0 2020:150:05:11:10.816 -110.55187857333401 64.43031803078048 0.0 +707116668.0 2020:150:05:16:38.816 -110.55227731454511 64.43031803078048 0.0 +707116996.0 2020:150:05:22:06.816 -110.55267376135644 64.43031803078048 0.0 +707117324.0 2020:150:05:27:34.816 -110.5530678968093 64.43031803078048 0.0 +707117652.0 2020:150:05:33:02.816 -110.55345970477484 64.43031803078048 0.0 +707117980.0 2020:150:05:38:30.816 -110.55384916993516 64.43031803078048 0.0 +707118308.0 2020:150:05:43:58.816 -110.55423627776449 64.43031803078048 0.0 +707118636.0 2020:150:05:49:26.816 -110.55462101451064 64.43031803078048 0.0 +707118964.0 2020:150:05:54:54.816 -110.55500336717526 64.43031803078048 0.0 +707119292.0 2020:150:06:00:22.816 -110.55538332349805 64.43031803078048 0.0 +707119620.0 2020:150:06:05:50.816 -110.55576087193947 64.43031803078048 0.0 +707119948.0 2020:150:06:11:18.816 -110.5561360016636 64.43031803078048 0.0 +707120276.0 2020:150:06:16:46.816 -110.55650870252141 64.43031803078048 0.0 +707120604.0 2020:150:06:22:14.816 -110.55687896503433 64.43031803078048 0.0 +707120932.0 2020:150:06:27:42.816 -110.5572467803781 64.43031803078048 0.0 +707121260.0 2020:150:06:33:10.816 -110.55761214036689 64.43031803078048 0.0 +707121588.0 2020:150:06:38:38.816 -110.5579750374378 64.43031803078048 0.0 +707121916.0 2020:150:06:44:06.816 -110.55833546463559 64.43031803078048 0.0 +707122244.0 2020:150:06:49:34.816 -110.55833546463559 64.43031803078048 0.0 diff --git a/acispy/tests/test_thermal_models.py b/acispy/tests/test_thermal_models.py index dd2b1f7..b4b8e0e 100644 --- a/acispy/tests/test_thermal_models.py +++ b/acispy/tests/test_thermal_models.py @@ -140,19 +140,35 @@ def test_single_state(answer_store): func(tm["states", k][0], v) -def test_ecs_run(): +def test_ecs_run(answer_store): tm = SimulateECSRun("1deamzt", "2016:201:05:12:03", 24, 14.0, - 150., 5, off_nom_roll=-6.0) + (150., -6.0), 5) for field in tm.field_list: if field[0] == "states": assert tm[field].size == 1 - t = ascii.read(test_dir / "single_ecs.dat") - assert_allclose_nounits(t["1deamzt"].data, tm["1deamzt"]) - assert_allclose_nounits(t["time"].data, tm["1deamzt"].times) - assert_equal_nounits(t["date"].data, tm["1deamzt"].dates) + if answer_store: + tm.write_model(test_dir / "single_ecs.dat", overwrite=True) + else: + t = ascii.read(test_dir / "single_ecs.dat") + assert_allclose_nounits(t["1deamzt"].data, tm["1deamzt"]) + assert_allclose_nounits(t["time"].data, tm["1deamzt"].times) + assert_equal_nounits(t["date"].data, tm["1deamzt"].dates) tm2 = SimulateECSRun("1deamzt", "2017:256:03:20:00", 24, 14.0, - 0.0, 5, vehicle_load="SEP0917C") - t2 = ascii.read(test_dir / "vehicle_ecs.dat") - assert_allclose_nounits(t2["1deamzt"].data, tm2["1deamzt"]) - assert_allclose_nounits(t2["time"].data, tm2["1deamzt"].times) - assert_equal_nounits(t2["date"].data, tm2["1deamzt"].dates) + "SEP0917C", 5) + if answer_store: + tm2.write_model(test_dir / "vehicle_ecs.dat", overwrite=True) + else: + t2 = ascii.read(test_dir / "vehicle_ecs.dat") + assert_allclose_nounits(t2["1deamzt"].data, tm2["1deamzt"]) + assert_allclose_nounits(t2["time"].data, tm2["1deamzt"].times) + assert_equal_nounits(t2["date"].data, tm2["1deamzt"].dates) + tm3 = SimulateECSRun("fptemp_11", "2020:148:14:45:00", 24, -115.0, + [-0.04470333, 0.63502552, -0.67575906, 0.37160988], + 4, instrument="ACIS-S") + if answer_store: + tm3.write_model(test_dir / "fptemp_ecs.dat", overwrite=True) + else: + t3 = ascii.read(test_dir / "fptemp_ecs.dat") + assert_allclose_nounits(t3["fptemp_11"].data, tm3["fptemp_11"]) + assert_allclose_nounits(t3["time"].data, tm3["fptemp_11"].times) + assert_equal_nounits(t3["date"].data, tm3["fptemp_11"].dates) diff --git a/acispy/thermal_models.py b/acispy/thermal_models.py index a89de2e..1fdd903 100755 --- a/acispy/thermal_models.py +++ b/acispy/thermal_models.py @@ -10,7 +10,8 @@ from acispy.msids import MSIDs from acispy.time_series import EmptyTimeSeries from acispy.utils import mylog, \ - ensure_list, plotdate2cxctime + ensure_list, plotdate2cxctime, \ + dict_to_array import Ska.Numpy import Ska.engarchive.fetch_sci as fetch import matplotlib.pyplot as plt @@ -18,6 +19,7 @@ import importlib from matplotlib import font_manager from pathlib import Path +from acis_thermal_check import get_acis_limits short_name = {"1deamzt": "dea", @@ -44,22 +46,6 @@ "tmp_fep1_fb": "FEP1 FB", "tmp_bep_pcb": "BEP PCB"} -limits = {'1deamzt': 37.5, - '1dpamzt': 37.5, - '1pdeaat': 52.5, - 'tmp_fep1_mong': 47.0, - 'tmp_fep1_actel': 46.0, - 'tmp_bep_pcb': 43.0, - 'tmp_fep1_fb': 41.0, - 'fptemp_11': {"ACIS-I": -112.0, "ACIS-S": -111.0}} - -low_limits = { - 'tmp_fep1_mong': 2.0, - 'tmp_fep1_actel': 2.0, - 'tmp_fep1_fb': 2.0, - 'tmp_bep_pcb': 4.5 -} - acis_models = ["1deamzt", "1dpamzt", "1pdeaat", @@ -68,14 +54,6 @@ "tmp_fep1_actel", "tmp_bep_pcb"] -margins = {'1deamzt': 2.0, - '1dpamzt': 2.0, - '1pdeaat': 4.5, - 'tmp_fep1_mong': 2.0, - 'tmp_fep1_actel': 2.0, - 'tmp_fep1_fb': 2.0, - 'tmp_bep_pcb': 2.0} - model_classes = { "dpa": "DPACheck", "dea": "DEACheck", @@ -86,6 +64,18 @@ "bep_pcb": "BEPPCBCheck" } +limits_map = { + "odb.caution.high": "yellow_hi", + "odb.caution.low": "yellow_lo", + "safety.caution.high": "yellow_hi", + "safety.caution.low": "yellow_lo", + "planning.warning.high": "planning_hi", + "planning.warning.low": "planning_lo", + "planning.data_quality.high.acisi": "acis_i", + "planning.data_quality.high.aciss": "acis_s", + "planning.data_quality.high.aciss_hot": "acis_hot", + "planning.data_quality.high.cold_ecs": "cold_ecs" +} def find_json(name, model_spec, repo_path, version): from xija.get_model_spec import get_xija_model_spec @@ -95,7 +85,7 @@ def find_json(name, model_spec, repo_path, version): name = short_name.get(name, name) try: model_spec, version = get_xija_model_spec(name, - repo_path=repo_path, + repo_path=repo_path, version=version) except ValueError: raise IOError(msg) @@ -141,7 +131,7 @@ def write_model(self, filename, overwrite=False): Ska.Numpy.pprint(temp_array, fmt, out) out.close() - def write_model_and_data(self, filename, overwrite=False, + def write_model_and_data(self, filename, overwrite=False, mask_radzones=False, mask_fmt1=False, mask_badtimes=True, tstart=None, tstop=None): @@ -219,7 +209,7 @@ def _get_msids(self, model, comps, tl_file): def make_dashboard_plots(self, msid, tstart=None, tstop=None, yplotlimits=None, errorplotlimits=None, fig=None, figfile=None, - bad_times=None, mask_radzones=False, plot_limits=True, + bad_times=None, mask_radzones=False, plot_limits=True, mask_fmt1=False): """ Make dashboard plots for the particular thermal model. @@ -296,15 +286,11 @@ def make_dashboard_plots(self, msid, tstart=None, tstop=None, yplotlimits=None, yplotlimits = [ymin, ymax] if errorplotlimits is None: errorplotlimits = [-5, 5] - mylimits = {"units": "C"} if plot_limits: - if msid == "fptemp_11": - mylimits["acisi_limit"] = -112.0 - mylimits["aciss_limit"] = -111.0 - mylimits["fp_sens_limit"] = -118.7 - else: - mylimits["caution_high"] = limits[msid]+margins[msid] - mylimits["planning_limit"] = limits[msid] + m = "fptemp" if msid == "fptemp_11" else msid + mylimits = self.limits[m] + else: + mylimits = {"units": "C"} dash.dashboard(pred.value[mask], telem.value[mask], times, mylimits, msid=msid, modelname=full_name.get(msid, msid), errorplotlimits=errorplotlimits, yplotlimits=yplotlimits, @@ -499,6 +485,9 @@ def __init__(self, name, tstart, tstop, states=None, T_init=None, rk4=None, tl_file=None, compute_model_supp=None, chandra_models_path=None, chandra_models_version=None): + if name in short_name_rev: + name = short_name_rev[name] + self.name = name.lower() self.sname = short_name.get(name, name) if self.name in acis_models: @@ -507,9 +496,9 @@ def __init__(self, name, tstart, tstop, states=None, T_init=None, else: self.model_check = None - self.model_spec = find_json(name, model_spec, - repo_path=chandra_models_path, - version=chandra_models_version) + model_spec = find_json(name, model_spec, + repo_path=chandra_models_path, + version=chandra_models_version) self.ephem_file = ephem_file @@ -543,6 +532,7 @@ def __init__(self, name, tstart, tstop, states=None, T_init=None, states["letg"] = np.array(["RETR"] * num_states) if "hetg" not in states: states["hetg"] = np.array(["RETR"] * num_states) + states = dict_to_array(states) if T_init is None: last_tlm_date = fetch.get_time_range(self.name, format='secs')[1] @@ -557,15 +547,19 @@ def __init__(self, name, tstart, tstop, states=None, T_init=None, if self.name in acis_models and states is not None: self.xija_model = self._compute_acis_model(self.name, tstart, tstop, - states, dt, T_init, + states, dt, T_init, model_spec, rk4=rk4, other_init=other_init, evolve_method=evolve_method) else: self.xija_model = self._compute_model(name, tstart, tstop, dt, T_init, - states, other_init=other_init, + states, model_spec, + other_init=other_init, evolve_method=evolve_method, rk4=rk4) + self.model_spec = self.xija_model.model_spec + self.limits = self.xija_model.limits + if states is None: states = self.xija_model.cmd_states states_obj = States(states) @@ -620,11 +614,12 @@ def _get_ephemeris(self, tstart, tstop, times): return ephem def _compute_model(self, name, tstart, tstop, dt, T_init, states, - other_init=None, evolve_method=None, rk4=None): + model_spec, other_init=None, evolve_method=None, + rk4=None): if name == "fptemp_11": name = "fptemp" model = xija.XijaModel(name, start=tstart, stop=tstop, dt=dt, - model_spec=self.model_spec, + model_spec=model_spec, evolve_method=evolve_method, rk4=rk4) model.comp[name].set_data(T_init) for t in ["dea0", "dpa0"]: @@ -652,14 +647,15 @@ def _compute_model(self, name, tstart, tstop, dt, T_init, states, return model def _compute_acis_model(self, name, tstart, tstop, states, dt, T_init, - other_init=None, evolve_method=None, rk4=None): + model_spec, other_init=None, evolve_method=None, + rk4=None): import re from acis_thermal_check.utils import calc_pitch_roll check_obj = getattr(self.model_check, model_classes[self.sname])() if name == "fptemp_11": name = "fptemp" model = xija.XijaModel(name, start=tstart, stop=tstop, dt=dt, - model_spec=self.model_spec, rk4=rk4, + model_spec=model_spec, rk4=rk4, evolve_method=evolve_method) ephem = self._get_ephemeris(model.tstart, model.tstop, model.times) if states is None: @@ -961,10 +957,6 @@ def make_default_states(): "letg": np.array(["RETR"]), "off_nom_roll": np.array([0.0]), "dh_heater": np.array([0], dtype='int'), - "targ_q1": np.array([1.0]), - "targ_q2": np.array([0.0]), - "targ_q3": np.array([0.0]), - "targ_q4": np.array([0.0]), "q1": np.array([1.0]), "q2": np.array([0.0]), "q3": np.array([0.0]), @@ -1040,6 +1032,8 @@ def __init__(self, name, tstart, tstop, states, T_init, model_spec=None, _states[k][0] = states[k] else: raise KeyError(f"You input a state ('{k}') which does not exist!") + for i in range(1, 5): + _states[f"targ_q{i}"] = _states[f"q{i}"] if name in short_name_rev: name = short_name_rev[name] tstart = CxoTime(tstart).secs @@ -1084,19 +1078,18 @@ class SimulateECSRun(ThermalModelRunner): per the ECS CAP. T_init : float The starting temperature for the model in degrees C. - pitch : float - The pitch at which to run the model in degrees. If `vehicle_load` - is not None, then this parameter will be ignored. + attitude : array_like + The input attitude for this simulated ECS run. Can be one of three + types: + * (pitch, roll) combination, e.g. (155.0, 5.0) + * Attitude quaternion, e.g [1.0, 0.0, 0.0, 0.0] + * Load name (for vehicle load): SEP0917C + If the (pitch, roll) combination is chosen, note that a default + quaternion of [1.0, 0.0, 0.0, 0.0] will be used, which means that the + focal plane prediction may be inaccurate since the earth solid angle + depends on the quaternion. ccd_count : integer The number of CCDs to clock. - vehicle_load : string, optional - If a vehicle load is running, specify it here, e.g. "SEP0917C". - Default: None, meaning no vehicle load. If this parameter is set, - the input values of pitch and off-nominal roll will be ignored - and the values from the vehicle load will be used. - off_nom_roll : float, optional - The off-nominal roll in degrees for the model. If `vehicle_load` - is not None, then this parameter will be ignored. Default: 0.0 dh_heater: integer, optional Flag to set whether (1) or not (0) the detector housing heater is on. Default: 0 @@ -1130,21 +1123,30 @@ class SimulateECSRun(ThermalModelRunner): Examples -------- >>> dea_run = SimulateECSRun("1deamzt", "2016:201:05:12:03", 24, 14.0, - ... 150., 5, off_nom_roll=-6.0, dh_heater=1) + ... (150.-6.0), 5, dh_heater=1) """ - def __init__(self, name, tstart, hours, T_init, pitch, ccd_count, - vehicle_load=None, off_nom_roll=0.0, dh_heater=0, - dt=328.0, evolve_method=None, rk4=None, - model_spec=None, no_earth_heat=False, - other_init=None, compute_model_supp=None): + def __init__(self, name, tstart, hours, T_init, attitude, ccd_count, + dh_heater=0, dt=328.0, evolve_method=None, + rk4=None, model_spec=None, no_earth_heat=False, + instrument=None, other_init=None, + compute_model_supp=None): + if name in short_name_rev: + name = short_name_rev[name] + if name.lower() == "fptemp_11" and instrument is None: + raise RuntimeError("Please specify instrument='ACIS-I' or " + "instrument='ACIS-S' when running the FP model!") tstart = CxoTime(tstart).secs tend = tstart+hours*3600.0+10012.0 tstop = tend+0.5*(tend-tstart) datestart = CxoTime(tstart).date datestop = CxoTime(tstop).date - self.vehicle_load = vehicle_load + if isinstance(attitude, str): + self.vehicle_load = attitude + else: + self.vehicle_load = None self.hours = hours self.no_earth_heat = no_earth_heat + self.instrument = instrument if self.vehicle_load is not None: mylog.info(f"Modeling a {ccd_count}-chip state concurrent with " f"the {self.vehicle_load} vehicle loads.") @@ -1164,7 +1166,6 @@ def __init__(self, name, tstart, hours, T_init, pitch, ccd_count, "fep_count": np.array([ccd_count], dtype='int'), "clocking": np.array([1], dtype='int'), "vid_board": np.array([1], dtype='int'), - "pitch": np.array([pitch]), "simpos": np.array([-99616.0]), "datestart": np.array([datestart]), "datestop": np.array([datestop]), @@ -1172,24 +1173,48 @@ def __init__(self, name, tstart, hours, T_init, pitch, ccd_count, "tstop": np.array([tstop]), "hetg": np.array(["RETR"]), "letg": np.array(["RETR"]), - "off_nom_roll": np.array([off_nom_roll]), "dh_heater": np.array([dh_heater], dtype='int') } + if len(attitude) == 2: + if name.lower() == "fptemp_11": + mylog.warning("For the ACIS FP model, an attitude quaternion " + "is required to accurately capture the effects of " + "earth solid angle. With only the pitch and " + "off-nominal roll specified, temperatures " + "near radiation zones may be inaccurate.") + states["pitch"] = np.array([attitude[0]]) + states["off_nom_roll"] = np.array([attitude[1]]) + q = [1.0, 0.0, 0.0, 0.0] + elif len(attitude) == 4: + q = attitude + else: + raise RuntimeError("Invalid format for 'attitude'! Either " + "supply [pitch, off_nom_roll], an " + "attitude quaternion, or a load name!") + for i in range(4): + states[f"q{i+1}"] = np.array([q[i]]) super().__init__(name, tstart, tstop, states=states, T_init=T_init, - dt=dt, evolve_method=evolve_method, rk4=rk4, + dt=dt, evolve_method=evolve_method, rk4=rk4, model_spec=model_spec, other_init=other_init, compute_model_supp=compute_model_supp) mylog.info("Run Parameters") mylog.info("--------------") + mylog.info(f"Modeled Temperature: {name}") mylog.info(f"Start Datestring: {datestart}") mylog.info(f"Length of state in hours: {self.hours}") mylog.info(f"Stop Datestring: {datestop}") mylog.info(f"Initial Temperature: {T_init} degrees C") mylog.info(f"CCD/FEP Count: {ccd_count}") if self.vehicle_load is None: + if len(attitude) == 2: + pitch, roll = attitude + else: + pitch = self.xija_model.comp["pitch"].dvals[0] + roll = self.xija_model.comp["roll"].dvals[0] + mylog.info(f"Quaternion: {attitude}") mylog.info(f"Pitch: {pitch}") - mylog.info(f"Off-nominal Roll: {off_nom_roll}") + mylog.info(f"Off-nominal Roll: {roll}") dhh = {0: "OFF", 1: "ON"}[dh_heater] mylog.info(f"Detector Housing Heater: {dhh}") @@ -1199,27 +1224,38 @@ def __init__(self, name, tstart, hours, T_init, pitch, ccd_count, mylog.info("Model Result") mylog.info("------------") - limit = limits[self.name] - margin = margins[self.name] - if self.name in low_limits: - self.low_limit = Quantity(low_limits[self.name], "deg_C") - else: - self.low_limit = None - self.limit = Quantity(limit, "deg_C") - self.margin = Quantity(margin, 'deg_C') + self.limits = get_acis_limits(self.name, self.model_spec, + limits_map=limits_map) + self.limit_time = None self.limit_date = None self.duration = None self.violate = False self.hours = hours + + if self.name.lower() == "fptemp_11": + cold = self.mvals.value < self.limits["cold_ecs"].value + cold &= self.xija_model.times < self.tend + cold_time = np.sum(cold) + if cold_time == 0: + msg = "The focal plane is never cold for this ECS measurement." + else: + msg = f"The focal plane is cold for " \ + f"{cold_time*self.xija_model.dt_ksec} ks." + mylog.info(msg) + limit_name = self.instrument.lower().replace("-", "_") + else: + limit_name = "planning_hi" + + self.limit = self.limits[limit_name] viols = self.mvals.value > self.limit.value if np.any(viols): idx = np.where(viols)[0][0] self.limit_time = self.times('model', self.name)[idx] self.limit_date = CxoTime(self.limit_time).date self.duration = Quantity((self.limit_time.value-tstart)*0.001, "ks") - msg = f"The limit of {self.limit.value} degrees C will be reached at {self.limit_date}, " - msg += f"after {self.duration.value} ksec." + msg = f"The limit of {self.limit.value} degrees C will be " \ + f"reached at {self.limit_date}, after {self.duration.value} ksec." mylog.info(msg) if self.limit_time.value < self.tend: self.violate = True @@ -1229,12 +1265,14 @@ def __init__(self, name, tstart, hours, T_init, pitch, ccd_count, viol_time = "after" mylog.info(f"The limit is reached {viol_time} the end of the observation.") else: - mylog.info(f"The limit of {self.limit.value} degrees C is never reached.") + mylog.info(f"The limit of {self.limit.value} degrees C " + f"is never reached.") - if self.violate: - mylog.warning("This observation is NOT safe from a thermal perspective.") - else: - mylog.info("This observation is safe from a thermal perspective.") + if name.lower() != "fptemp_11": + if self.violate: + mylog.warning("This observation is NOT safe from a thermal perspective.") + else: + mylog.info("This observation is safe from a thermal perspective.") def _time_ticks(self, dp, ymax, fontsize): from matplotlib.ticker import AutoMinorLocator @@ -1273,30 +1311,33 @@ def plot_model(self, plot=None, fontsize=18, **kwargs): viol_text = "NOT SAFE" if self.violate else "SAFE" dp = DatePlot(self, [("model", self.name)], field2=field2, plot=plot, fontsize=fontsize, **kwargs) - dp.add_text(find_text_time(self.dateend, hours=4.0), self.T_init.value + 2.0, - viol_text, fontsize=22, color='black') - dp.add_hline(self.limit.value, ls='-', lw=2, color='g') - dp.add_hline(self.limit.value+self.margin.value, ls='-', lw=2, color='gold') - if self.low_limit is not None: - dp.add_hline(self.low_limit.value, ls='-', lw=2, color='g') - dp.add_hline(self.low_limit.value - self.margin.value, ls='-', lw=2, color='gold') + dp.add_hline(self.limit.value, ls='-', lw=2, color=self.limit.color) + if self.name.lower() != "fptemp_11": + dp.add_text(find_text_time(self.dateend, hours=4.0), + self.T_init.value + 2.0, viol_text, fontsize=22, + color='black') + dp.add_hline(self.limits["yellow_hi"].value, ls='-', lw=2, + color=self.limits["yellow_hi"].color) + else: + dp.add_hline(self.limits["cold_ecs"].value, ls='-', lw=2, + color=self.limits["cold_ecs"].color) dp.add_vline(self.datestart, ls='--', lw=2, color='b') dp.add_text(find_text_time(self.datestart), self.limit.value - 2.0, "START", color='blue', rotation="vertical") dp.add_vline(self.dateend, ls='--', lw=2, color='b') - dp.add_text(find_text_time(self.dateend), self.limit.value - 12.0, + dp.add_text(find_text_time(self.dateend), self.limit.value - 2.0, "END", color='blue', rotation="vertical") if self.limit_date is not None: dp.add_vline(self.limit_date, ls='--', lw=2, color='r') dp.add_text(find_text_time(self.limit_date), self.limit.value-2.0, "VIOLATION", color='red', rotation="vertical") dp.set_xlim(find_text_time(self.datestart, hours=-1.0), self.datestop) - if self.low_limit is not None: - ymin = self.low_limit.value-self.margin.value + ymin = min(self.T_init.value, self.mvals.value.min())-2.0 + if self.name.lower() != "fptemp_11": + ymax = self.limits["yellow_hi"].value else: - ymin = self.T_init.value - ymin = min(ymin, self.mvals.value.min())-2.0 - ymax = max(self.limit.value+self.margin.value, self.mvals.value.max())+3.0 + ymax = self.limit.value + ymax = max(ymax, self.mvals.value.max())+3.0 self._time_ticks(dp, ymax, fontsize) dp.set_ylim(ymin, ymax) return dp diff --git a/acispy/utils.py b/acispy/utils.py index 3b61bb5..6b0c8e2 100644 --- a/acispy/utils.py +++ b/acispy/utils.py @@ -141,8 +141,8 @@ def calc_off_nom_rolls(states): "DEAP6VDCB": "deap6voltb"} cti_simodes = ["TE_007AC", "TE_00B26", "TE_007AE", - "TE_00CA8", "TE_00C60", "TE_007AE", - "TN_000B4", "TN_000B6"] + "TE_00CA8", "TE_00C60", "TN_000B4", + "TN_000B6", "TE_00C62"] def get_display_name(ftype, name): @@ -217,3 +217,11 @@ def plotdate2cxctime(dates): # Find the cxctime of first time and use a relative offset from there cxctime0 = CxoTime(dates[0], format='plot_date').secs return (np.asarray(dates) - dates[0]) * 86400. + cxctime0 + + +def dict_to_array(a): + dtype = [(k, str(v.dtype)) for k, v in a.items()] + data = np.zeros(a["datestart"].size, dtype=dtype) + for k, v in a.items(): + data[k] = getattr(v, "value", v) + return data diff --git a/doc/source/Thermal_Models.ipynb b/doc/source/Thermal_Models.ipynb index bcc287a..672e205 100755 --- a/doc/source/Thermal_Models.ipynb +++ b/doc/source/Thermal_Models.ipynb @@ -2,129 +2,132 @@ "cells": [ { "cell_type": "markdown", + "metadata": {}, "source": [ "# Thermal Models\n", "\n", "ACISpy provides the ability to run [Xija](http://cxc.cfa.harvard.edu/mta/ASPECT/tool_doc/xija/index.html) thermal models via a special class, `ThermalModelRunner`, which can input commanded states from a variety of sources. The really nice thing about `ThermalModelRunner` is that it is actually a `Dataset` object, so we can look at the different fields, make plots, and create derived fields." - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import acispy\n", "import numpy as np" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Basic Use of `ThermalModelRunner`" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "If a thermal model is being run entirely within the past or another situation where `kadi` commanded states are fully specified, you can simply run a thermal model by specifying the MSID to be modeled and the start and stop times of the model. The initial temperature will be specified from telemetry unless one sets an initial value using the `T_init` keyword argument. If we want to take model \"bad times\" into account, we also need to set `mask_bad_times=True`:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dea_model = acispy.ThermalModelRunner(\"1deamzt\", \"2020:142\", \"2020:150\", \n", " get_msids=True, mask_bad_times=True)" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "`get_msids=True` is set, so the resulting `Dataset` object will be populated with actual telemetry as well as model data, so that you can examine and plot both:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "print(dea_model[\"model\",\"1deamzt\"][:10])\n", "print(dea_model[\"msids\",\"1deamzt\"][:10])" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dp = acispy.DatePlot(dea_model, [(\"msids\", \"1deamzt\"), (\"model\", \"1deamzt\")], plot_bad=True)\n", "dp" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Note that for this period of time a segment of it was marked as a \"bad time\" in the model, and this shows up in the cyan region in the plot. " - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "By default, model specification files will be searched for in the `chandra_models` package. If your model spec file is not in that package, or you want to specify a different model specification file, you can pass `ThermalModelRunner` a `model_spec` optional argument:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, - "source": [ - "dea_model2 = acispy.ThermalModelRunner(\"1deamzt\", \"2020:142\", \"2020:150\",\n", - " model_spec=\"/Users/jzuhone/Source/dea_check/dea_check/dea_model_spec.json\")" - ], + "metadata": {}, "outputs": [], - "metadata": {} + "source": [ + "dea_model2 = acispy.ThermalModelRunner(\"1deamzt\", \"2020:142\", \"2020:150\", model_spec=\"dea_model_spec.json\")" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Running Thermal Models Using States from Various Sources" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "The `ThermalModelRunner` class also has various methods which one can use to run thermal models using states from various sources." - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Running a Thermal Model from Commands" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "You can use a set of commands (either a `kadi` `CommandTable` or list of command dicts) to run a thermal model using the `from_commands` method:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "scrolled": false + }, + "outputs": [], "source": [ "from kadi import commands\n", "# commands as a CommandTable\n", @@ -133,89 +136,87 @@ "# commands as a list of dicts\n", "dict_cmds = cmds.as_list_of_dict()\n", "psmc_model2 = acispy.ThermalModelRunner.from_commands(\"1pdeaat\", dict_cmds)" - ], - "outputs": [], - "metadata": { - "scrolled": false - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Running a Thermal Model from a Backstop File" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "You can use a backstop file as input to `ThermalModelRunner` to generate states for a thermal model run. In this case, `ThermalModelRunner` will go back to the latest telemetry to determine the initial temperature (unless one is specified, see below) and construct states from that point and handle continuity between those and the commands in the backstop file appropriately. To show this, we'll use the ACA thermal model, which requires that the initial value for the `aca0` pseudonode be specified, which we can do using the `other_init` keyword argument:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "tm_aca = acispy.ThermalModelRunner.from_backstop(\n", " \"aacccdpt\", \"/data/acis/LoadReviews/2020/AUG1720/ofls/CR229_2202.backstop\",\n", " other_init={\"aca0\": -10})" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dp = acispy.DatePlot(tm_aca, ('model','aacccdpt'), field2=\"pitch\")\n", "dp" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Running a Thermal Model Using a `states.dat` File" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "One can run a thermal model from a `states.dat` table file which would be outputted by the thermal model check scripts during a load review, using the `from_states_file()` method:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, - "source": [ - "dpa_model = acispy.ThermalModelRunner.from_states_file(\"1dpamzt\", \"my_states.dat\")" - ], - "outputs": [], "metadata": { "tags": [] - } + }, + "outputs": [], + "source": [ + "dpa_model = acispy.ThermalModelRunner.from_states_file(\"1dpamzt\", \"my_states.dat\")" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Running Thermal Models Using States Constructed By Hand" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "You can create a dictionary of states completely by hand and submit them as a keyword argument to `ThermalModelRunner`, for running completely hypothetical thermal models. For simplicity, we'll pick constant states except change the CCD count." - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "states = {\"ccd_count\": np.array([5,6,1]),\n", " \"pitch\": np.array([150.0]*3),\n", @@ -226,378 +227,452 @@ " \"simpos\": np.array([-99616.0]*3),\n", " \"datestart\": np.array([\"2015:002:00:00:00\",\"2015:002:12:00:00\",\"2015:003:12:00:00\"]),\n", " \"datestop\": np.array([\"2015:002:12:00:00\",\"2015:003:12:00:00\",\"2015:005:00:00:00\"])}" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "In the previous examples, we never specified an initial temperature, but we can always do so, and must do so if we are past the end value in telemetry. This is not the case here, but we'll set one anyway:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "T_init = 13.0 # in degrees C" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Now we can pass in the `states` dict we created, as well as the `T_init`:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "dea_model = acispy.ThermalModelRunner(\"1deamzt\", \"2015:002:00:00:00\", \n", " \"2015:005:00:00:00\", states=states, T_init=T_init)" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dp = acispy.DatePlot(dea_model, (\"model\",\"1deamzt\"), field2=\"ccd_count\")\n", "dp.set_ylim2(0,7)\n", "dp" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "We can also dump the results of the model run to disk, both the states and the model components:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dea_model.write_model(\"model.dat\", overwrite=True)\n", "dea_model.write_states(\"states.dat\", overwrite=True)" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "These files can be loaded in at a later date using `ModelDataFromFiles`." - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Making Dashboard Plots" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### NOTE: This functionality requires the `xijafit` package to be installed. " - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "It is possible to use the thermal model objects and the `xijafit` package to make dashboard plots. For this, use the `make_dashboard_plots()` method:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "dpa_model_long = acispy.ThermalModelRunner(\"1dpamzt\", \"2016:200\", \"2017:200\", \n", " mask_bad_times=True, get_msids=True)\n", "dpa_model_long.make_dashboard_plots(\"1dpamzt\", figfile=\"my_dpa_dash.png\")" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "`figfile` sets the filename to save the dashboard plot to.\n", "\n", "One can also use the `errorplotlimits` and `yplotlimits` arguments to set the bounds of the temperature and the errors on the plots:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "fp_model_long = acispy.ThermalModelRunner(\"fptemp_11\", \"2016:200\", \"2017:200\", \n", " mask_bad_times=True, get_msids=True)\n", "fp_model_long.make_dashboard_plots(\"fptemp_11\", yplotlimits=(-120.0, -104.0), \n", " errorplotlimits=(-5.0, 5.0))" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Plotting Pitch and State Power Heating Values" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "All thermal models have a solar heating component. To make a quick solar heating plot, use the `make_solarheat_plot` method, with the node that the solar heating component acts upon as the first argument. " - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dpa_model_long.make_solarheat_plot(\"dpa0\", figfile=\"dpa0_pitches.png\")" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Similarly, to plot the ACIS state power coefficients for a model (if present), use the `make_power_plot` method:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# For the 1DEAMZT model set use_ccd_count=True\n", "dpa_model_long.make_power_plot(figfile=\"acis_state_power.png\", use_ccd_count=False)" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Simulating Single States" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ - "The `SimulateSingleState` class is a simplified implemenation of `ThermalModelRunner` which assumes that the spacecraft state is constant over a period of time. " - ], - "metadata": {} + "The `SimulateSingleState` class is a simplified implemenation of `ThermalModelRunner` which assumes that the spacecraft state is constant over a period of time. This class takes the name of the temperature to simulate, a start and stop date, and a dictionary of states. It is not required to specify all states in this dictionary, but note that states not specified will be assumed to be the following:\n", + "\n", + "* `pitch`: 90 deg\n", + "* `off_nom_roll`: 0 deg\n", + "* `ccd_count`: 0\n", + "* `fep_count`: 0\n", + "* `clocking`: 0\n", + "* `vid_board`: 0\n", + "* `simpos`: -99616.0\n", + "* `hetg`: `\"RETR\"`\n", + "* `letg`: `\"RETR\"`\n", + "* `dh_heater`: 0\n", + "* `q1`: 1.0\n", + "* `q2`: 0.0\n", + "* `q3`: 0.0\n", + "* `q4`: 0.0 " + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "datestart = \"2019:181:01:00:00\" # start time of run\n", "datestop = \"2019:183:01:00:00\" # stop time of run\n", "states = {\"pitch\": 70.0}\n", "T_init = -11.0 # in degrees F \n", "aca_m = acispy.SimulateSingleState(\"aacccdpt\", datestart, datestop, states, T_init, other_init={\"aca0\": T_init})" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dp = acispy.DatePlot(aca_m, \"aacccdpt\")\n", "dp" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Simulating ECS Runs" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ - "A further special case of running a single state is an ECS run, which may be performed after a safing action. The `SimulateECSRun` class is a limited version of `SimulateSingleState` which assumes that the SIM-Z position is HRC-S (-99616) and that ACIS is clocking. The goal is to predict if the temperature will hit the planning limit within the time frame of the ECS run. The input parameters are mostly the same as `SimulateSingleState`, but instead of specifying a `tstop`, you input the number of `hours` in the ECS run (the same number of hours as specified on the ECS CAP):" - ], - "metadata": {} - }, - { - "cell_type": "code", - "execution_count": null, - "source": [ - "datestart = \"2015:002:00:00:00\" # start time of run\n", - "hours = 24 # length of ECS run in hours\n", - "pitch = 137. # in degrees\n", - "T_init = 7.5 # in degrees C\n", - "ccd_count = 6 # number of CCDs\n", - "off_nom_roll = 0.0 # in degrees, optional, default 0.0" - ], - "outputs": [], - "metadata": {} + "A further special case of running a single state is an ECS run, which may be performed after a safing action. The `SimulateECSRun` class is a limited version of `SimulateSingleState` which assumes that the SIM-Z position is HRC-S (-99616) and that ACIS is clocking. The goal is to predict if the temperature will hit the planning limit within the time frame of the ECS run. A start time is specified, as well as the number of `hours` in the ECS run (the same number of hours as specified on the ECS CAP). Then, an `attitude` must be specified, which can take one of three forms:\n", + "* A (pitch, off-nominal roll) combination\n", + "* An attitude quaternion\n", + "* The name of a load (for vehicle load ECS runs)" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ - "We pick a model to run (most relevant is `\"1dpamzt\"`) along with a start time a length of the ECS run in hours (24 in this case), and feed them and the above parameters into `SimulateECSRun`:" - ], - "metadata": {} + "We pick a model to run (most relevant is `\"1dpamzt\"`) along with a start time a length of the ECS run in hours (24 in this case), and feed the parameters into `SimulateECSRun`:" + ] }, { "cell_type": "code", "execution_count": null, - "source": [ - "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, pitch, ccd_count, \n", - " off_nom_roll=off_nom_roll)" - ], + "metadata": {}, "outputs": [], - "metadata": { - "tags": [] - } + "source": [ + "datestart = \"2015:002:00:00:00\" # start time of run\n", + "hours = 24 # length of ECS run in hours\n", + "attitude = [137.0, 0.0] # pitch, off-nominal roll in degrees\n", + "T_init = 7.5 # in degrees C\n", + "ccd_count = 6 # number of CCDs\n", + "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, attitude, \n", + " ccd_count)" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "*NOTE* that the actual length of the ECS run, as per the ECS CAP, is `hours`+ 10 ks + 12 s. \n", "\n", "The run reports back the input parameters and the time when the limit was reached, if it was at all. We can plot the model using the `plot_model()` method, \n", "which shows the limit value as a dashed green line and the time at which the limit was reached as a dashed red line, as well as whether or not this was a safe ECS run:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "dpa_ecs_run.plot_model()" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "On the other hand, if the ECS run had been shorter, the limit would be reached _after_ the ECS run, so this is safe." - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "hours = 14\n", - "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, pitch, ccd_count, \n", - " off_nom_roll=off_nom_roll)\n", + "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, attitude, \n", + " ccd_count)\n", "dpa_ecs_run.plot_model()" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "Note that for some combinations of parameters the limit may never be reached. For example, let's knock the CCD count down to 4:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "ccd_count = 4 # only 4 CCDs\n", - "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, pitch, ccd_count, \n", - " off_nom_roll=off_nom_roll)\n", + "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, attitude,\n", + " ccd_count)\n", "dpa_ecs_run.plot_model()" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Simulating ECS Runs with Vehicle Loads" - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ - "If the spacecraft executed SCS-107, we may be running an ECS run while the vehicle load is still running, which means that the pitch and off-nominal roll may change during the ECS run. If this is the case, pass the name of the load to the ``vehicle_load`` parameter. You still need to input the value of the ``pitch`` parameter, but the value of this parameter and that of the ``off_nom_roll`` optional parameter will be ignored in favor of the value in the vehicle load. An example of an ECS run with a vehicle load that is not safe:" - ], - "metadata": {} + "If the spacecraft executed SCS-107, we may be running an ECS run while the vehicle load is still running, which means that the pitch and off-nominal roll may change during the ECS run. If this is the case, pass the name of the load to the ``attitude`` parameter. An example of an ECS run with a vehicle load that is not safe:" + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "datestart = \"2017:256:03:20:00\"\n", "hours = 24\n", - "pitch = 0.0 # Doesn't matter what this is\n", "T_init = 12.0 # in degrees C\n", + "attitude = \"SEP0917C\" # attitude info will be take from this load\n", "ccd_count = 6 # number of CCDs \n", - "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, pitch, ccd_count, \n", - " vehicle_load=\"SEP0917C\")\n", + "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, attitude, ccd_count)\n", "dpa_ecs_run.plot_model()" - ], - "outputs": [], - "metadata": { - "tags": [] - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "But if we drop it down to 5 chips, it is safe:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], "source": [ "ccd_count = 5 # number of CCDs \n", - "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, pitch, ccd_count, \n", - " vehicle_load=\"SEP0917C\")\n", + "dpa_ecs_run = acispy.SimulateECSRun(\"1dpamzt\", datestart, hours, T_init, attitude, ccd_count)\n", "dpa_ecs_run.plot_model()" - ], + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Simulating the Focal Plane Temperature for ECS Runs \n", + "\n", + "The ACIS Focal Plane (FP) temperature can also be modeled for an ECS run. This will track the amount of \"cold time\" for the ECS measurement, as well as determine if the run will exceed the FP limit for that particular instrument, ACIS-I or ACIS-S. In this case, a quaternion generally should be supplied for the value of ``attitude``, since the FP temperature can depend on the value of the Earth solid angle. The ``instrument`` argument should also be supplied to determine what thermal limit will be applied. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], + "source": [ + "datestart = \"2020:148:14:45:00\" # start time of run\n", + "hours = 24 # length of ECS run in hours\n", + "T_init = -115.0 # in degrees C\n", + "ccd_count = 4 # number of CCDs\n", + "attitude = [-0.04470333, 0.63502552, -0.67575906, 0.37160988] # attitude quaternion required\n", + "instrument = \"ACIS-S\"\n", + "\n", + "fp_ecs_run = acispy.SimulateECSRun(\"fptemp_11\", datestart, hours, T_init, attitude, ccd_count,\n", + " instrument=instrument)\n", + "fp_ecs_run.plot_model()" + ] + }, + { + "cell_type": "markdown", "metadata": { - "tags": [] - } + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "This can also be done for a vehicle load as the ``attitude`` parameter:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "datestart = \"2017:256:03:20:00\"\n", + "hours = 24\n", + "T_init = -119.0 # in degrees C\n", + "attitude = \"SEP0917C\" # attitude info will be take from this load\n", + "ccd_count = 6 # number of CCDs \n", + "fp_ecs_run = acispy.SimulateECSRun(\"fptemp_11\", datestart, hours, T_init, attitude, ccd_count, \n", + " instrument=\"ACIS-I\")\n", + "fp_ecs_run.plot_model()" + ] } ], "metadata": { "anaconda-cloud": {}, + "kernelspec": { + "display_name": "ska", + "language": "python", + "name": "ska" + }, "language_info": { "codemirror_mode": { "name": "ipython", diff --git a/doc/source/dea_model_spec.json b/doc/source/dea_model_spec.json new file mode 100644 index 0000000..9d9d425 --- /dev/null +++ b/doc/source/dea_model_spec.json @@ -0,0 +1,740 @@ +{ + "bad_times": [ + [ + "2014:187:23:36:36", + "2014:189:00:00:00" + ], + [ + "2014:207:07:03:55", + "2014:208:23:57:00" + ], + [ + "2014:356:04:52:35", + "2014:356:22:57:00" + ], + [ + "2014:357:11:36:38", + "2014:358:18:30:01" + ], + [ + "2015:006:08:24:00", + "2015:009:03:06:08" + ], + [ + "2015:012:00:43:26", + "2015:013:13:30:00" + ], + [ + "2015:076:04:37:42", + "2015:078:03:11:26" + ], + [ + "2015:264:04:35:00", + "2015:266:05:00:00" + ], + [ + "2016:344:07:40:00", + "2016:345:23:30:00" + ], + [ + "2018:283:12:00:00", + "2018:296:12:00:00" + ], + [ + "2020:145:05:00:00", + "2020:147:12:00:00" + ] + ], + "comps": [ + { + "class_name": "Mask", + "init_args": [ + "1deamzt", + "gt", + 20.0 + ], + "init_kwargs": {}, + "name": "mask__1deamzt_gt" + }, + { + "class_name": "Node", + "init_args": [ + "1deamzt" + ], + "init_kwargs": { + "mask": "mask__1deamzt_gt" + }, + "name": "1deamzt" + }, + { + "class_name": "Node", + "init_args": [ + "dea0" + ], + "init_kwargs": { + "sigma": 100000.0 + }, + "name": "dea0" + }, + { + "class_name": "Coupling", + "init_args": [ + "1deamzt", + "dea0" + ], + "init_kwargs": { + "tau": 30.0 + }, + "name": "coupling__1deamzt__dea0" + }, + { + "class_name": "SimZ", + "init_args": [], + "init_kwargs": {}, + "name": "sim_z" + }, + { + "class_name": "Pitch", + "init_args": [], + "init_kwargs": {}, + "name": "pitch" + }, + { + "class_name": "Roll", + "init_args": [], + "init_kwargs": {}, + "name": "roll" + }, + { + "class_name": "Eclipse", + "init_args": [], + "init_kwargs": {}, + "name": "eclipse" + }, + { + "class_name": "CmdStatesData", + "init_args": [ + "fep_count" + ], + "init_kwargs": {}, + "name": "fep_count" + }, + { + "class_name": "CmdStatesData", + "init_args": [ + "ccd_count" + ], + "init_kwargs": {}, + "name": "ccd_count" + }, + { + "class_name": "CmdStatesData", + "init_args": [ + "vid_board" + ], + "init_kwargs": {}, + "name": "vid_board" + }, + { + "class_name": "CmdStatesData", + "init_args": [ + "clocking" + ], + "init_kwargs": {}, + "name": "clocking" + }, + { + "class_name": "SolarHeatHrcMult", + "init_args": [ + "dea0" + ], + "init_kwargs": { + "P_pitches": [ + 45, + 60, + 90, + 110, + 130, + 140, + 150, + 160, + 170, + 180 + ], + "Ps": [ + 0.58, + 0.5, + 0.41, + 0.7, + 1.0, + 1.01, + 0.9, + 0.8, + 0.8, + 0.79 + ], + "eclipse_comp": "eclipse", + "epoch": "2016:188:12:00:00", + "pitch_comp": "pitch", + "simz_comp": "sim_z", + "var_func": "linear" + }, + "name": "solarheat__dea0" + }, + { + "class_name": "SolarHeatOffNomRoll", + "init_args": [ + "dea0" + ], + "init_kwargs": { + "P_minus_y": 0.0, + "P_plus_y": 0.0, + "eclipse_comp": "eclipse", + "pitch_comp": "pitch", + "roll_comp": "roll" + }, + "name": "solarheat_off_nom_roll__dea0" + }, + { + "class_name": "HeatSinkRef", + "init_args": [ + "dea0" + ], + "init_kwargs": {}, + "name": "heatsink__dea0" + }, + { + "class_name": "AcisDpaStatePower", + "init_args": [ + "dea0" + ], + "init_kwargs": { + "ccd_count": "ccd_count", + "clocking": "clocking", + "fep_count": "fep_count", + "pow_states": [ + "00xx", + "30xx", + "x0xx", + "x1xx", + "x2xx", + "x3xx", + "x4xx", + "x5x0", + "x5x1", + "x6x0", + "x6x1" + ], + "vid_board": "vid_board" + }, + "name": "dpa_power" + }, + { + "class_name": "PropHeater", + "init_args": [ + "dea0" + ], + "init_kwargs": {}, + "name": "prop_heat__dea0" + } + ], + "datestart": "2017:354:12:03:34.816", + "datestop": "2020:159:11:51:42.816", + "dt": 328.0, + "evolve_method": 2, + "gui_config": { + "filename": "/Users/jzuhone/Source/dea_check/dea_check/dea_model_spec.json", + "plot_names": [], + "set_data_vals": { + "dea0": 20 + }, + "size": [ + 1440, + 799 + ] + }, + "limits": { + "1deamzt": { + "odb.caution.high": 39.5, + "odb.warning.high": 42.5, + "planning.warning.high": 37.5, + "unit": "degC" + } + }, + "mval_names": [], + "name": "1deamzt", + "pars": [ + { + "comp_name": "mask__1deamzt_gt", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "mask__1deamzt_gt__val", + "max": 50.0, + "min": -10.0, + "name": "val", + "val": -6.906267559163565 + }, + { + "comp_name": "coupling__1deamzt__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "coupling__1deamzt__dea0__tau", + "max": 200.0, + "min": 0.01, + "name": "tau", + "val": 0.16771969146369828 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_45", + "max": 2.0, + "min": -0.11139300563792043, + "name": "P_45", + "val": -0.10886743717705208 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_60", + "max": 2.0, + "min": -0.3441833953547427, + "name": "P_60", + "val": 0.006016166451239017 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_90", + "max": 2.0, + "min": -0.04055563694127384, + "name": "P_90", + "val": 0.04873448562729174 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_110", + "max": 2.0, + "min": 0.0, + "name": "P_110", + "val": 0.9634120490498219 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_130", + "max": 2.0, + "min": 0.0, + "name": "P_130", + "val": 1.6917540971913847 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_140", + "max": 2.0, + "min": 0.0, + "name": "P_140", + "val": 1.8838755049203153 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_150", + "max": 2.0, + "min": 0.0, + "name": "P_150", + "val": 1.9492232150490516 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_160", + "max": 2.039721551185886, + "min": 0.0, + "name": "P_160", + "val": 2.0286249683623825 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_170", + "max": 2.351249059942064, + "min": 0.0, + "name": "P_170", + "val": 2.0336978230347973 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__P_180", + "max": 2.351249059942064, + "min": 0.0, + "name": "P_180", + "val": 2.0336978230347973 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_45", + "max": 2.0, + "min": -2.0, + "name": "dP_45", + "val": -0.4292800197985668 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_60", + "max": 2.0, + "min": -2.0, + "name": "dP_60", + "val": -0.41144724462146853 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_90", + "max": 2.0, + "min": -2.0, + "name": "dP_90", + "val": -0.24048604123224543 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_110", + "max": 2.0, + "min": -2.0, + "name": "dP_110", + "val": 0.08281729842871052 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_130", + "max": 2.0, + "min": -2.0, + "name": "dP_130", + "val": 0.22501738948447342 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_140", + "max": 2.0, + "min": -2.0, + "name": "dP_140", + "val": 0.27326367391823403 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_150", + "max": 2.0, + "min": -2.0, + "name": "dP_150", + "val": 0.3984390846578584 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_160", + "max": 2.0, + "min": -2.0, + "name": "dP_160", + "val": 0.3144523531157936 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_170", + "max": 2.0, + "min": -2.0, + "name": "dP_170", + "val": 0.23240051948592683 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": false, + "full_name": "solarheat__dea0__dP_180", + "max": 2.0, + "min": -2.0, + "name": "dP_180", + "val": 0.23240051948592683 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__tau", + "max": 3000.0, + "min": 1000.0, + "name": "tau", + "val": 1285.5193832535247 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__ampl", + "max": 1.0, + "min": -1.0, + "name": "ampl", + "val": 0.04862162334745262 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__bias", + "max": 10.0, + "min": 0.0, + "name": "bias", + "val": 0.012022733145991952 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__hrci_bias", + "max": 10.0, + "min": -10.0, + "name": "hrci_bias", + "val": -0.038831792896207445 + }, + { + "comp_name": "solarheat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat__dea0__hrcs_bias", + "max": 10.0, + "min": -10.0, + "name": "hrcs_bias", + "val": -0.11055589512664464 + }, + { + "comp_name": "solarheat_off_nom_roll__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat_off_nom_roll__dea0__P_plus_y", + "max": 5.0, + "min": -5.0, + "name": "P_plus_y", + "val": -0.7389993977023577 + }, + { + "comp_name": "solarheat_off_nom_roll__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "solarheat_off_nom_roll__dea0__P_minus_y", + "max": 5.0, + "min": -5.0, + "name": "P_minus_y", + "val": -1.7031802468123538 + }, + { + "comp_name": "heatsink__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "heatsink__dea0__P", + "max": 10.0, + "min": -10.0, + "name": "P", + "val": -2.080111563866993 + }, + { + "comp_name": "heatsink__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "heatsink__dea0__tau", + "max": 200.0, + "min": 2.0, + "name": "tau", + "val": 18.50887349936709 + }, + { + "comp_name": "heatsink__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "heatsink__dea0__T_ref", + "max": 100, + "min": -100, + "name": "T_ref", + "val": 21.770299580078415 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_00xx", + "max": 60, + "min": -20.0, + "name": "pow_00xx", + "val": 6.081077887983957 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_30xx", + "max": 60, + "min": -20.0, + "name": "pow_30xx", + "val": 18.20737884560917 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x0xx", + "max": 60, + "min": -10.0, + "name": "pow_x0xx", + "val": 20.922770795050816 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x1xx", + "max": 60, + "min": 15, + "name": "pow_x1xx", + "val": 16.34878956732919 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x2xx", + "max": 80, + "min": 20, + "name": "pow_x2xx", + "val": 27.432535630640544 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x3xx", + "max": 100, + "min": 20, + "name": "pow_x3xx", + "val": 37.84282034846291 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x4xx", + "max": 120, + "min": 20, + "name": "pow_x4xx", + "val": 49.02702789096498 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x5x0", + "max": 120, + "min": 20, + "name": "pow_x5x0", + "val": 27.362096974476184 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x5x1", + "max": 120, + "min": 20, + "name": "pow_x5x1", + "val": 60.06767471054782 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x6x0", + "max": 140, + "min": 20, + "name": "pow_x6x0", + "val": 31.08868157302193 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__pow_x6x1", + "max": 140, + "min": 20, + "name": "pow_x6x1", + "val": 70.74199980495928 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__mult", + "max": 2.0, + "min": 0.0, + "name": "mult", + "val": 1.9179111900926304 + }, + { + "comp_name": "dpa_power", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "dpa_power__bias", + "max": 25.0, + "min": 10.0, + "name": "bias", + "val": 20.889862831906907 + }, + { + "comp_name": "prop_heat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "prop_heat__dea0__k", + "max": 2.0, + "min": 0.0, + "name": "k", + "val": 0.173931990673523 + }, + { + "comp_name": "prop_heat__dea0", + "fmt": "{:.4g}", + "frozen": true, + "full_name": "prop_heat__dea0__T_set", + "max": 15.0, + "min": 0.0, + "name": "T_set", + "val": 14.016419457765721 + } + ], + "rk4": 0, + "tlm_code": null +} \ No newline at end of file