77 """Calculate time of midpoint of travel for this profile.
79 Derived from Shuang Liang's CTN-002 (https://ctn-002.lsst.io).
80 Equation numbers listed are from this document. As the fits
81 have already been done, we can ignore the raw position/Hall
87 Fit model to use to calculate the midpoint.
92 The time of the midpoint from the start of motion in
93 seconds, as derived from the point where the acceleration
94 on the shutter is zero.
96 The time of the midpoint from the start of motion in
97 seconds, as derived from the point where the shutter
98 position is midway between its starting and ending
104 Raised if the requested ``modelName`` is not found in the
108 for idx, name
in enumerate(self.
fit_name):
109 if name == modelName:
112 raise RuntimeError(f
"Unknown model {modelName} requested.")
135 tm_accel = newton(acc, 0.5*(t2 + t1))
136 except Exception
as e:
137 self.
log.warn(f
"Midpoint calculation (from acceleration) failed to converge: {e}")
142 V1 = t1**2 * (j0 - j1)/2. - t1*A1
143 S1 = t1**3 * (j0 - j1)/6. - t1**2 * A1/2. - t1*V1
147 return j1*(t**3)/6. + A1*(t**2)/2. + V1*t + S1 - Smid
150 tm_position = newton(pos, tm_accel)
151 except Exception
as e:
152 self.
log.warn(f
"Midpoint calculation (from position) failed to converge: {e}")
156 return tm_accel + t0, tm_position + t0
160 """Construct a ShutterMotionProfile from a dictionary of properties.
165 Dictionary of properties.
169 calib : `lsst.ip.isr.ShutterMotionProfile
170 Constructed calibration.
175 Raised if the supplied dictionary is for a different
180 if calib._OBSTYPE != dictionary[
"fileType"]:
181 raise RuntimeError(f
"Incorrect calibration supplied. Expected {calib._OBSTYPE}, "
182 f
"found {dictionary['OBSTYPE']}")
183 motionProfile = dictionary.pop(
"motionProfile")
185 encodeSamples = motionProfile.pop(
"encodeSamples")
186 hallTransitions = motionProfile.pop(
"hallTransitions")
187 fitResults = motionProfile.pop(
"fitResults")
189 if "metadata" in dictionary:
190 metadata = dictionary.pop(
"metadata")
191 for key, value
in metadata.items():
192 dictionary[key] = value
193 calib.setMetadata(dictionary)
195 formatVersion = calib.metadata[
"version"]
197 startTime = motionProfile.pop(
"startTime")
198 if formatVersion == 1.0:
200 motionProfile[
"startTime_tai"] = startTime[
"tai"]
201 motionProfile[
"startTime_mjd"] = startTime[
"mjd"]
204 motionProfile[
"startTime_tai"] = startTime[
"tai"][
"isot"]
205 motionProfile[
"startTime_mjd"] = startTime[
"tai"][
"mjd"]
207 calib.readEncodeSamples(encodeSamples, formatVersion)
208 calib.readHallTransitions(hallTransitions, formatVersion)
209 calib.readFitResults(fitResults)
211 calib.updateMetadata(**motionProfile)
290 """Construct calibration from a list of tables.
292 This method uses the `fromDict` method to create the
293 calibration, after constructing an appropriate dictionary from
298 tableList : `list` [`lsst.afw.table.Table`]
299 List of tables to use to construct the crosstalk
300 calibration. For shutter motion profiles, the first table
301 contains the samples, the second the Hall transition data,
302 and the third the model fits.
306 calib : `lsst.ip.isr.ShutterMotionProfile`
307 The calibration defined in the tables.
309 samples = tableList[0]
310 transitions = tableList[1]
311 modelFits = tableList[2]
313 metadata = samples.meta
316 calib.time_tai = np.squeeze(samples[
"TIME_TAI"].data).tolist()
317 if hasattr(calib.time_tai[0],
"decode"):
318 calib.time_tai = [time.decode(
"utf-8")
for time
in calib.time_tai]
319 calib.time_mjd = np.squeeze(samples[
"TIME_MJD"].data).tolist()
320 calib.position = np.squeeze(samples[
"POSITION"].data).tolist()
322 calib.hall_time_tai = np.squeeze(transitions[
"HALL_TIME_TAI"].data).tolist()
323 if hasattr(calib.hall_time_tai[0],
"decode"):
324 calib.hall_time_tai = [time.decode(
"utf-8")
for time
in calib.hall_time_tai]
325 calib.hall_time_mjd = np.squeeze(transitions[
"HALL_TIME_MJD"].data).tolist()
326 calib.hall_position = np.squeeze(transitions[
"HALL_POSITION"].data).tolist()
327 calib.hall_sensorId = np.squeeze(transitions[
"HALL_SENSORID"].data).tolist()
328 calib.hall_isOn = np.squeeze(transitions[
"HALL_ISON"].data).tolist()
330 calib.fit_model = modelFits.meta[
"FIT_MODEL"]
332 calib.fit_name = np.squeeze(modelFits[
"FIT_NAME"].data).tolist()
333 if hasattr(calib.fit_name[0],
"decode"):
334 calib.fit_name = [fit.decode(
"utf-8")
for fit
in calib.fit_name]
335 calib.fit_start_time = np.squeeze(modelFits[
"FIT_START_TIME"].data).tolist()
336 calib.fit_pivot1 = np.squeeze(modelFits[
"FIT_PIVOT1"].data).tolist()
337 calib.fit_pivot2 = np.squeeze(modelFits[
"FIT_PIVOT2"].data).tolist()
338 calib.fit_jerk0 = np.squeeze(modelFits[
"FIT_JERK0"].data).tolist()
339 calib.fit_jerk1 = np.squeeze(modelFits[
"FIT_JERK1"].data).tolist()
340 calib.fit_jerk2 = np.squeeze(modelFits[
"FIT_JERK2"].data).tolist()
342 if "OBSTYPE" not in metadata:
347 for key
in (
"fileName",
"fileType",
"obsId",
"version",
"side",
"isOpen"):
348 if key.upper()
in metadata:
349 value = metadata.pop(key.upper())
350 metadata[key] = value
351 for key
in (
"CALIB_ID",
"DETECTOR",
"DET_NAME",
"DET_SER",
"FILTER",
"INSTRUME",
352 "RAFTNAME",
"SEQCKSUM",
"SEQFILE",
"SEQNAME",
"SLOTNAME"):
354 if metadata[key] ==
"":
357 calib.updateMetadata(**metadata)