OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
makePosVelQuatCsv.py
Go to the documentation of this file.
1 from datetime import datetime as DT
2 from datetime import timedelta as TDel
3 import pickle
4 from astropy.time import Time
5 from scipy.interpolate import UnivariateSpline as UVS
6 import pandas as pd
7 import socket
8 import sys
9 import numpy as np
10 from hico.auxiliary import ConvLst2DT
11 from hico.exceptions import USGNCCoarseTimeException
12 from hico.exceptions import PVQInterpolation
13 from hico.exceptions import EmptyCSVException
14 from hico.exceptions import BadFormatCSVException
15 import os
16 import getpass
17 import platform
18 import re
19 
20 __version__ = "0.1"
21 __author__ = "R. Healy & E. Karakoylu (erdem.m.karakoylu@nasa.gov)"
22 __date__ = "2/3/2017"
23 
24 
26 
27  def __init__(self, hicoPtr, **kwargs):
28  gps_time = DT(1980, 1, 6, 0, 0, 0)
29  sec_per_count = 1.117460459e-6
30  secOffset = TDel(seconds=15)
31  self.__subSeconds2Seconds = 16.72e-6
32  self.__timeWrapAround = 65536
33  self.__time0Factor = 0.05
34  self.__time1Factor = 62.5e-9
35  do_nav_time_correction = kwargs.pop('doNavTimeCorrection', False)
36  self.beginTime = DT.now()
37  self.paramsDict = {}
38  self.paramsDict['d_tisspvq'] = kwargs.pop('delta_tisspvq', 0)
39  self.paramsDict['d_ticugps'] = kwargs.pop('delta_ticugps', 0)
40  self.paramsDict['orientation'] = hicoPtr.params['issOrientation']
41  self.paramsDict['gps_secs_090101'] = (DT(2009, 1, 1, 0, 0, 0) + secOffset
42  - gps_time).total_seconds()
43  self.paramsDict['trigger_pulse_width'] = 0.860e-3
44  self.paramsDict['start_date_time'] = ConvLst2DT(hicoPtr.L0.data['start_date'],
45  hicoPtr.L0.data['start_time'])
46  self.paramsDict['end_date_time'] = ConvLst2DT(hicoPtr.L0.data['end_date'],
47  hicoPtr.L0.data['end_time'])
48  self.paramsDict['start_date_time'] -= secOffset
49  self.paramsDict['end_date_time'] += secOffset
50  self.paramsDict['thetas'] = hicoPtr.L0.data['ScenePointingAngle']
51  self.paramsDict['nls'] = hicoPtr.L0.data['n_image']
52  ffpps_all = hicoPtr.L0.header['FFpps'] +\
53  hicoPtr.L0.header['FFppsSub'] * self.__subSeconds2Seconds
54  lfpps_all = hicoPtr.L0.header['LFpps'] +\
55  hicoPtr.L0.header['LFppsSub'] * self.__subSeconds2Seconds
56  if ffpps_all > lfpps_all:
57  ffpps_all += self.__timeWrapAround
58  self.paramsDict['ffpps_all'] = ffpps_all
59  self.paramsDict['lfpps_all'] = lfpps_all
60  self.paramsDict['exptimes'] = hicoPtr.L0.header['TriggerCount'] * sec_per_count
61  self.paramsDict['odrc_time_offset'] = self.__GetODRCTimeOffset(hicoPtr.inpDict['hdrFile'])
62  self.paramsDict['nav_time_offset'] = 0
63  self.paramsDict['jday_end'] = Time(self.paramsDict['end_date_time']).jd
64  self.paramsDict['jday_start'] = Time(self.paramsDict['start_date_time']).jd
65  self.paramsDict['exptimes'] = hicoPtr.L0.header['TriggerCount'] * sec_per_count
66  self.paramsDict['cexp'] = '_expDEF'
67  rootName = os.path.basename(hicoPtr.inpDict['l0File']).split('.bil')[0]
68  self.paramsDict['pvqFileName'] = kwargs.pop('outputFileName',
69  '%s_pos_vel_quat.csv' % rootName)
70  self.paramsDict['anglFileName'] = '%s_LonLatViewAngles.bil' % rootName
71  self.paramsDict['csvName'] = hicoPtr.inpDict['csvFile']
72  self.paramsDict['n_pixels'] = hicoPtr.L0.data['ns']
73  self.__ReadCSVFile()
74  if do_nav_time_correction:
75  self.__GetNavOffsetTimeCorrection(rootName)
76  self.__FillPoVeQuDF()
77  self.finishTime = DT.now()
78  self.__WriteHeader2CSV()
79  self.__WriteData2CSV()
80 
81  def __ReadCSVFile(self):
82  usecols = ['USGNC_PS_Pointing_Coarse_Time_Tag',
83  'USGNC_PS_Pointing_Inert_Posn_VectorX',
84  'USGNC_PS_Pointing_Inert_Posn_VectorY',
85  'USGNC_PS_Pointing_Inert_Posn_VectorZ',
86  'USGNC_PS_Pointing_Inert_Vel_VectorX',
87  'USGNC_PS_Pointing_Inert_Vel_VectorY',
88  'USGNC_PS_Pointing_Inert_Vel_VectorZ',
89  'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_0',
90  'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_1',
91  'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_2',
92  'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_3',
93  'USGNC_PS_PD_Fine_Pointing_Fine_Time_Tag',
94  'HSTCLOCKTIME0', 'HSTATTITUDEQUATS',
95  'HSTATTITUDESTATUSMODE',
96  'HSTATTITUDEQUATX', 'HSTATTITUDEQUATY', 'HSTATTITUDEQUATZ',
97  'HSTATTITUDETIME0', 'HSTATTITUDETIME1', '_ISSGPSTIME',
98  'ISSTIMESUBSECOND', 'ICUTIMEGPSSECONDS',
99  'ICUTIMEISSSUBSECOND', 'ICUTIMEHWREGSECOND',
100  'ICUTIMEHWREGSUBSECOND', 'ISSTIMECENTURY',
101  'ISSTIMEYEAR', 'ISSTIMEMONTH', 'ISSTIMEDAY', 'ISSTIMEHOUR',
102  'ISSTIMEMINUTE', 'ISSTIMESECOND']
103 
104  try:
105  self.dfCSV = pd.read_csv(self.paramsDict['csvName'],
106  usecols=usecols)
107  except ValueError:
108  print("badly formatted csv file - attempting to resolve")
109  ocdataroot = os.getenv('OCDATAROOT')
110  hicocaldir = os.path.join(ocdataroot, 'hico/cal')
111  col_name_file = os.path.join(hicocaldir, 'csv_columns.pkl')
112  try:
113  with open(col_name_file, 'rb') as f:
114  col_names = pickle.load(f)
115  try:
116  self.dfCSV = pd.read_csv(self.paramsDict['csvName'],
117  skiprows=1, names=col_names,
118  usecols=usecols)
119  print('csv format issue resolved')
120  except ValueError:
121  raise BadFormatCSVException
122  except FileNotFoundError:
123  raise BadFormatCSVException
124  else:
125  if self.dfCSV.empty:
126  raise EmptyCSVException
127 
128 
129  def __WriteHeader2CSV(self):
130  with open(self.paramsDict['pvqFileName'], 'w') as fpvq:
131  print('\nThis file name, %s' % os.path.basename(self.paramsDict['pvqFileName']),
132  file=fpvq)
133  print('Source CSV file, %s' % self.paramsDict['csvName'], file=fpvq)
134  print('Subset CSV file, None', file=fpvq)
135  print('Expected Lon/Lat/View angle filename, %s' % self.paramsDict['anglFileName'],
136  file=fpvq)
137  print('Epoch, 2009 Jan 01 00:00:00 UTC', file=fpvq)
138  print('Requested number of pixels, %d' % self.paramsDict['n_pixels'], file=fpvq)
139  print('Distance Unit, Feet', file=fpvq)
140  print('Central Body, Earth', file=fpvq)
141  print('CoordinateSystem, J2000', file=fpvq)
142  print('Theta (degrees from stowed position), %.16f' % self.paramsDict['thetas'],
143  file=fpvq)
144  print('Code name, %s' % __name__, file=fpvq)
145  print('Code version, %s' % __version__, file=fpvq)
146  print('Code date, %s' % __date__, file=fpvq)
147  print('Code author, %s' % __author__, file=fpvq)
148  print('Code executed on computer, %s' % socket.gethostname(), file=fpvq)
149  print('Code executed by username, %s' % getpass.getuser(), file=fpvq)
150  print('Code run under Python osfamily, %s' % os.name, file=fpvq)
151  print('Code run under Python os, %s' % platform.release(), file=fpvq)
152  print('Code start time, %s' % self.beginTime.strftime("%a %b %d %H:%M:%S"), file=fpvq)
153  print('Code end time, %s' % self.finishTime.strftime("%a %b %d %H:%M:%S"), file=fpvq)
154  print('Exposure interval (frame time), %f' % self.paramsDict['exptimes'], file=fpvq)
155  print('ISS orientation, %s' % self.paramsDict['orientation'], file=fpvq)
156  print('Trigger pulse width (s), %.3e' % self.paramsDict['trigger_pulse_width'],
157  file=fpvq)
158  print('ODRC broadcast time - gps time (s), %s' % self.paramsDict['odrc_time_offset'],
159  file=fpvq)
160  print('delta_ticugps (s), %.6f' % 0, file=fpvq)
161  print('delta_tisspvq (s), %.6f' % 0, file=fpvq)
162  print(file=fpvq)
163 
164  def __WriteData2CSV(self):
165  with open(self.paramsDict['pvqFileName'], 'a') as fpvq:
166  self.dfPVQ.to_csv(fpvq, index=False)
167 
168  def __GetPVQIdx(self, relTimes):
169  crstmtagfld = 'USGNC_PS_Pointing_Coarse_Time_Tag'
170  fntmtagfld = 'USGNC_PS_PD_Fine_Pointing_Fine_Time_Tag'
171  locs_goodt = ((self.dfCSV[crstmtagfld] >= relTimes[0] - 10) &
172  (self.dfCSV[crstmtagfld] <= relTimes[-1] + 10))
173  idx = locs_goodt[locs_goodt].index
174  if idx.size == 0:
175  raise(USGNCCoarseTimeException)
176  u_usgnc = self.dfCSV.loc[idx, crstmtagfld].duplicated()
177  udx_usgnc = u_usgnc.index[np.logical_not(u_usgnc)]
178  u_usgnc_coarse = self.dfCSV.loc[udx_usgnc, crstmtagfld].values
179  u_usgnc_fine = self.dfCSV.loc[udx_usgnc, fntmtagfld].values
180  t_issposvelquat = u_usgnc_coarse + u_usgnc_fine / 256 + self.paramsDict['d_tisspvq']
181  return udx_usgnc, t_issposvelquat
182 
183  def __GetStarTracking(self, hicoTimes, hstField):
184  hstattitudetime = self.dfCSV.HSTATTITUDETIME0 * self.__time0Factor +\
185  self.dfCSV.HSTATTITUDETIME1 * self.__time1Factor
186  hstclocktime = self.dfCSV.HSTCLOCKTIME0 * self.__time0Factor +\
187  self.dfCSV.HSTATTITUDETIME1 * self.__time1Factor
188  hstqt_pps = self.__GetIssPosVelQuatXYZ(hstclocktime, hstattitudetime, hstField)
189  t_issgps = self.dfCSV._ISSGPSTIME + 1e-6 * self.dfCSV.ISSTIMESUBSECOND -\
190  self.paramsDict['odrc_time_offset'] + self.paramsDict['nav_time_offset']
191  interpolator = self.__PVQInterpolator(t_issgps, hstqt_pps)
192  return interpolator(hicoTimes)
193 
194  def __SplineIfNeeded(self, hicoRelTimes, fieldName):
195  if self.dfCSV[fieldName].unique().size > 1:
196  return self.__GetStarTracking(hicoRelTimes, fieldName)
197  else:
198  return np.ones((self.dfPVQ.shape[0],),
199  dtype=self.dfCSV[fieldName].dtype) * self.dfCSV[fieldName].unique()
200 
201  def __GetNavOffsetTimeCorrection(self, rootname):
202  '''distance units are in km, time in s, speed in km/s'''
203  hico_ground_speed = 6.9 #km/s
204  rootnameparts = rootname.split('.')
205  scene_ref = 'H%s%s' % (rootnameparts[1], rootnameparts[3])
206  nav_offset_file = os.path.join(os.getenv('OCVARROOT'), 'hico', 'navigation_offsets.txt')
207  regex_pattern = re.compile(r'H\d+\s(-*\d*\.\d+|-*\d+)\s*(-*\d*\.\d+|-*\d+)*')
208  with open(nav_offset_file) as nof:
209  for line in nof:
210  if scene_ref in line:
211  linematch = regex_pattern.findall(line)
212  if linematch:
213  along_track = float(linematch[0][0])
214  across_track = float(linematch[0][1])
215  self.paramsDict['nav_offset_km'] = {'along_track': along_track,
216  'across_track': across_track,
217  'scene': scene_ref}
218  self.paramsDict['nav_time_offset'] = along_track / hico_ground_speed
219  # TODO add logging
220  break
221 
222 
223 
224  def __FillPoVeQuDF(self):
225  fields = ['SecondsSinceEpoch', 'ISSPOSX', 'ISSPOSY', 'ISSPOSZ', 'ISSVELX', 'ISSVELY',
226  'ISSVELZ', 'ISSQX', 'ISSQY', 'ISSQZ', 'ISSQS', 'STQX', 'STQY', 'STQZ', 'STQS',
227  'HST_ATTITUDE_STATUS']
228  vecPosXfld = 'USGNC_PS_Pointing_Inert_Posn_VectorX'
229  vecPosYfld = 'USGNC_PS_Pointing_Inert_Posn_VectorY'
230  vecPosZfld = 'USGNC_PS_Pointing_Inert_Posn_VectorZ'
231  vecVelXfld = 'USGNC_PS_Pointing_Inert_Vel_VectorX'
232  vecVelYfld = 'USGNC_PS_Pointing_Inert_Vel_VectorY'
233  vecVelZfld = 'USGNC_PS_Pointing_Inert_Vel_VectorZ'
234  vecQuat0fld = 'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_0'
235  vecQuat1fld = 'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_1'
236  vecQuat2fld = 'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_2'
237  vecQuat3fld = 'USGNC_PS_Pointing_Current_Inert_Att_Quatrn_3'
238  hstAttXfld = 'HSTATTITUDEQUATX'
239  hstAttYfld = 'HSTATTITUDEQUATY'
240  hstAttZfld = 'HSTATTITUDEQUATZ'
241  hstAttSfld = 'HSTATTITUDEQUATS'
242  hstAttStatfld = 'HSTATTITUDESTATUSMODE'
243  self.dfPVQ = pd.DataFrame(columns=fields)
244  hicoRelTimes = self.__GetSecsSinceEpoch()
245  self.dfPVQ['SecondsSinceEpoch'] = hicoRelTimes - self.paramsDict['gps_secs_090101']
246  pvIdx, pvTimes = self.__GetPVQIdx(hicoRelTimes)
247  self.dfPVQ['ISSPOSX'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecPosXfld, pvIdx)
248  self.dfPVQ['ISSPOSY'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecPosYfld, pvIdx)
249  self.dfPVQ['ISSPOSZ'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecPosZfld, pvIdx)
250  self.dfPVQ['ISSVELX'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecVelXfld, pvIdx)
251  self.dfPVQ['ISSVELY'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecVelYfld, pvIdx)
252  self.dfPVQ['ISSVELZ'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecVelZfld, pvIdx)
253  self.dfPVQ['ISSQX'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecQuat1fld, pvIdx)
254  self.dfPVQ['ISSQY'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecQuat2fld, pvIdx)
255  self.dfPVQ['ISSQZ'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecQuat3fld, pvIdx)
256  self.dfPVQ['ISSQS'] = self.__GetIssPosVelQuatXYZ(hicoRelTimes, pvTimes, vecQuat0fld, pvIdx)
257  self.dfPVQ['STQX'] = self.__SplineIfNeeded(hicoRelTimes, hstAttXfld)
258  self.dfPVQ['STQY'] = self.__SplineIfNeeded(hicoRelTimes, hstAttYfld)
259  self.dfPVQ['STQZ'] = self.__SplineIfNeeded(hicoRelTimes, hstAttZfld)
260  self.dfPVQ['STQS'] = self.__SplineIfNeeded(hicoRelTimes, hstAttSfld)
261  self.dfPVQ['HST_ATTITUDE_STATUS'] = self.__SplineIfNeeded(hicoRelTimes, hstAttStatfld)
262 
263  @staticmethod
264  def __PVQInterpolator(timeInGrid, pvqOutGrid):
265  ditp = pd.DataFrame(dict(time=timeInGrid, pvq=pvqOutGrid))
266  ditp.drop_duplicates(subset='time', inplace=True)
267  ditp.sort_values('time', inplace=True)
268  return UVS(ditp.time.values, ditp.pvq.values)
269 
270  @staticmethod
271  def __GetODRCTimeOffset(hdrFilePath):
272  try:
273  with open(hdrFilePath, 'rt') as fhdr:
274  for line in fhdr.readlines():
275  if 'odrc_time_offset' in line:
276  return float(line.split('=')[1])
277  return 0
278  except FileNotFoundError as e:
279  sys.exit(e)
280 
281 
282  def __ExtractTimeDataFromCSV(self):
283  """
284  Extracts columns for the rest of processing
285  replaces half-baked date and time columns with proper datetime
286  column.
287  """
288  def GetDateTime(row):
289  row = row.astype(int)
290  year = row['ISSTIMECENTURY'] * 100 + row['ISSTIMEYEAR']
291  return DT(year, row['ISSTIMEMONTH'], row['ISSTIMEDAY'],
292  row['ISSTIMEHOUR'], row['ISSTIMEMINUTE'], row['ISSTIMESECOND'])
293 
294  hsdat = pd.DataFrame(columns=['datetime', ])
295  cols2copy = ['ICUTIMEGPSSECONDS', 'ICUTIMEISSSUBSECOND',
296  'ICUTIMEHWREGSECOND', 'ICUTIMEHWREGSUBSECOND']
297  hsdat = self.dfCSV[cols2copy].copy()
298  #hsdat['datetime'] = self.dfCSV.apply(GetDateTime, axis=1)
299  hsdat['datetime'] = self.dfCSV.filter(regex='ISSTIME',
300  axis=1).apply(GetDateTime,
301  axis=1)
302  try:
303  np.testing.assert_array_equal(hsdat.datetime.values, np.sort(hsdat.datetime.values))
304  except AssertionError:
305  print("Caution: datetime column unordered")
306  finally:
307  return hsdat
308 
309  def __GetSecsSinceEpoch(self):
310  def CheckStuff(self, hsdat, hwreg):
311  badhwregs = (hsdat.ICUTIMEHWREGSECOND[0] > hsdat.ICUTIMEHWREGSECOND).values
312  if badhwregs.any():
313  hsdat.loc[badhwregs, 'ICUTIMEHWREGSECOND'] += self.__timeWrapAround
314  if self.paramsDict['lfpps_all'] < self.paramsDict['ffpps_all']:
315  self.paramsDict['ffpps_all'] += self.__timeWrapAround
316  if self.paramsDict['lfpps_all'] < hwreg[0]:
317  self.paramsDict['lfpps_all'] += self.__timeWrapAround
318  if self.paramsDict['ffpps_all'] < hwreg[0]:
319  self.paramsDict['ffpps_all'] += self.__timeWrapAround
320 
321  def GetHwReg(hsdat, ffpps_all):
322  hwreg = hsdat.ICUTIMEHWREGSECOND +\
323  hsdat.ICUTIMEHWREGSUBSECOND * 16.72e-6
324  locs_lt = hwreg <= ffpps_all
325  idx_lt = locs_lt.index[locs_lt]
326  # the first of these is the tick just after the camera stops
327  # hwreg_locs_gt = hwreg[hwreg >= lfpps_all]
328  return hwreg, idx_lt
329 
330  hsdat = self.__ExtractTimeDataFromCSV()
331  hwreg, idx_lt = GetHwReg(hsdat, self.paramsDict['ffpps_all'])
332 
333  d_ticugps = 0
334  t_icugps = hsdat.loc[:, 'ICUTIMEGPSSECONDS'].values +\
335  1.e-6 * hsdat.loc[:, 'ICUTIMEISSSUBSECOND'].values
336 
337  t_icugps -= self.paramsDict['odrc_time_offset']
338  t_icugps += d_ticugps # 2012/01/17 for testing
339  hwstart = (self.paramsDict['ffpps_all'] - hwreg[idx_lt[-2]]
340  ) / (hwreg[idx_lt[-1]] - hwreg[idx_lt[-2]])
341  time_start = hwstart*(t_icugps[idx_lt[-1]] -
342  t_icugps[idx_lt[-2]]) + t_icugps[idx_lt[-2]]
343  scanrange = np.arange(self.paramsDict['nls'], dtype=float)
344  testrange = np.multiply(scanrange, self.paramsDict['exptimes'])
345  hico_times = np.add(np.add(time_start, testrange),
346  (self.paramsDict['trigger_pulse_width'] + 0.5 *
347  self.paramsDict['exptimes']))
348  return hico_times
349 
350  def __GetIssPosVelQuatXYZ(self, hicoTimes, pvtimes, inputField, pvidx=np.zeros(1)):
351  if pvidx.any():
352  pvGrid = self.dfCSV.loc[pvidx, inputField].values
353  else:
354  pvGrid = self.dfCSV[inputField].values
355  try:
356  f = self.__PVQInterpolator(pvtimes, pvGrid)
357  except ValueError:
358  raise(PVQInterpolation(inputField))
359  issPvOut = f(hicoTimes)
360  return issPvOut
361 
362  def __GetSTQXYZS(self):
363  pass
364 
365  def __GetHSTAttitudeStat(self):
366  pass
def __init__(self, hicoPtr, **kwargs)
def __SplineIfNeeded(self, hicoRelTimes, fieldName)
def __PVQInterpolator(timeInGrid, pvqOutGrid)
double precision function f(R1)
Definition: tmd.lp.f:1454
def ConvLst2DT(date, time)
Definition: auxiliary.py:181
void filter(fctlstr *fctl, l1qstr *l1que, l1str *l1rec, int32_t dscan)
Definition: filter.c:1396
void copy(double **aout, double **ain, int n)
def __GetStarTracking(self, hicoTimes, hstField)
def __GetIssPosVelQuatXYZ(self, hicoTimes, pvtimes, inputField, pvidx=np.zeros(1))