00001
00002
00003
00004
00005
00006 """
00007 :py:class:`PSCalib.DCRange` - class for the Detector Calibration (DC) project.
00008
00009 Usage::
00010
00011 # Import
00012 from PSCalib.DCRange import DCRange
00013
00014 # Initialization
00015 o = DCRange(begin, end=None, cmt=None)
00016
00017 # Methods
00018 str_range = o.range() # (str) of the time stamp validity range
00019 t_sec = o.begin() # (double) time stamp beginning validity range
00020 t_sec = o.end() # (double) time stamp ending validity range or (str) 'end'
00021 dico = o.versions() # (list of uint) versions of calibrations
00022 v = o.vnum_def() # returns default version number
00023 v = o.vnum_last() # returns last version number
00024 vo = o.version(vnum=None) # returns version object for specified version
00025 ts_in_range = o.tsec_in_range(tsec) # (bool) True/False if tsec is/not in the validity range
00026 evt_in_range= o.evt_in_range(evt) # (bool) True/False if evt is/not in the validity range
00027 o.set_begin(tsbegin) # set (int) time stamp beginning validity range
00028 o.set_end(tsend) # set (int) time stamp ending validity range
00029 o.add_version(vnum=None, tsec_prod=None, nda=None, cmt=None) # add object for new version of calibration data
00030 o.set_vnum_def(vnum=None) # set default version number, if available. vnum=None - use last available.
00031 vd = o.mark_version(vnum=None) # mark version for deletion, returns version number or None if nothing was deleted
00032 o.mark_versions() # mark all registered versions for deletion
00033
00034 o.save(group) # saves object content under h5py.group in the hdf5 file.
00035 o.load(group) # loads object content from the hdf5 file.
00036 o.print_obj() # print info about this object and its children
00037
00038 @see project modules
00039 * :py:class:`PSCalib.DCStore`
00040 * :py:class:`PSCalib.DCType`
00041 * :py:class:`PSCalib.DCRange`
00042 * :py:class:`PSCalib.DCVersion`
00043 * :py:class:`PSCalib.DCBase`
00044 * :py:class:`PSCalib.DCInterface`
00045 * :py:class:`PSCalib.DCUtils`
00046 * :py:class:`PSCalib.DCDetectorId`
00047 * :py:class:`PSCalib.DCConfigParameters`
00048 * :py:class:`PSCalib.DCFileName`
00049 * :py:class:`PSCalib.DCLogger`
00050 * :py:class:`PSCalib.DCMethods`
00051 * :py:class:`PSCalib.DCEmail`
00052
00053 This software was developed for the SIT project.
00054 If you use all or part of it, please give an appropriate acknowledgment.
00055
00056 @version $Id: DCRange.py 12730 2016-10-11 21:11:56Z dubrovin@SLAC.STANFORD.EDU $
00057
00058 @author Mikhail S. Dubrovin
00059 """
00060
00061
00062 __version__ = "$Revision: 12730 $"
00063
00064
00065 import os
00066 import sys
00067 from math import floor, ceil
00068
00069
00070
00071
00072 from PSCalib.DCInterface import DCRangeI
00073 from PSCalib.DCLogger import log
00074 from PSCalib.DCVersion import DCVersion, version_int_to_str
00075 from PSCalib.DCUtils import sp, evt_time, get_subgroup, save_object_as_dset, delete_object
00076
00077
00078
00079 def key(begin, end=None) :
00080 """ Return range as a string,
00081 ex.: 1471285222-1471285555 or 1471285222-end from double time like 1471285222.123456
00082 """
00083 str_begin = ('%d' % floor(begin)) if begin is not None else 0
00084 str_end = 'end' if (end is None or end=='end') else ('%d' % ceil(end))
00085 return '%s-%s' % (str_begin, str_end)
00086
00087
00088
00089 class DCRange(DCRangeI) :
00090
00091 """Class for the Detector Calibration (DC) project
00092
00093 Parameters
00094
00095 begin : double - time in sec
00096 end : double - time in sec or None meaning infinity
00097 cmt : str - comment
00098 """
00099
00100 def __init__(self, begin, end=None, cmt=None) :
00101 DCRangeI.__init__(self, begin, end, cmt)
00102 self._name = self.__class__.__name__
00103 self.set_begin(begin)
00104 self.set_end(end)
00105 self._dicvers = {}
00106 self._vnum_def = 0
00107 self._str_range = key(begin, end)
00108 log.debug('In c-tor for range: %s' % self._str_range, self._name)
00109
00110 def range(self) : return self._str_range
00111
00112 def begin(self) : return self._begin
00113
00114 def end(self) : return self._end
00115
00116 def versions(self) : return self._dicvers
00117
00118 def vnum_def(self) :
00119
00120 if self._vnum_def == 0 or self._vnum_def is None :
00121 return self.vnum_last()
00122 return self._vnum_def
00123
00124 def vnum_last(self) :
00125 keys = self._dicvers.keys()
00126 return keys[-1] if len(keys) else 0
00127
00128 def version(self, vnum=None) :
00129 v = vnum if vnum is not None else self.vnum_def()
00130 return self._dicvers.get(v, None) if v is not None else None
00131
00132 def set_begin(self, begin) : self._begin = begin
00133
00134 def set_end(self, end=None) : self._end = 'end' if end is None else end
00135
00136 def set_str_range(self, str_range) : self._str_range = str_range
00137
00138
00139 def add_version(self, vnum=None, tsec_prod=None, nda=None, cmt=False) :
00140 vn = self.vnum_last() + 1 if vnum is None else vnum
00141 if vn in self._dicvers.keys() :
00142 return self._dicvers[vn]
00143 o = self._dicvers[vn] = DCVersion(vn, tsec_prod, nda)
00144
00145 rec = self.make_record('add version', str(vn), cmt)
00146 if cmt is not False : self.add_history_record(rec)
00147 log.info(rec, self.__class__.__name__)
00148 return o
00149
00150
00151 def set_vnum_def(self, vnum=None) :
00152 if vnum is None or vnum == 0 :
00153 self._vnum_def = 0
00154 elif vnum in self._dicvers.keys() :
00155 self._vnum_def = vnum
00156 self.add_history_record('WARNING: set_vnum_defdef sets default version %d' % vnum)
00157 else :
00158 msg = 'Attemt to set non-existent version %d as default' % vnum
00159 log.warning(msg, self._name)
00160
00161
00162 def mark_version(self, vnum=None, cmt=False) :
00163 """Marks child object for deletion in save()"""
00164 vers = self.vnum_last() if vnum is None else vnum
00165
00166 if vers in self._dicvers.keys() :
00167 self._lst_del_keys.append(vers)
00168
00169 rec = self.make_record('del version', str(vers), cmt)
00170 if cmt is not False : self.add_history_record(rec)
00171 log.info(rec, self.__class__.__name__)
00172 return vers
00173 else :
00174 msg = 'Marking of non-existent version %s' % str(vers)
00175 log.warning(msg, self._name)
00176 return None
00177
00178
00179 def mark_versions(self) :
00180 """Marks all child objects for deletion in save()"""
00181 for vers in self._dicvers.keys() :
00182 self.mark_version(vers)
00183
00184
00185
00186 def __del__(self) :
00187 for vers in self._dicvers.keys() :
00188 del self._dicvers[vers]
00189
00190
00191 def clear_versions(self) :
00192 self._dicvers.clear()
00193
00194
00195 def tsec_in_range(self, tsec) :
00196 if tsec < self.begin() : return False
00197 if self.end() == 'end' : return True
00198 if tsec > self.end() : return False
00199 return True
00200
00201
00202 def evt_in_range(self, evt) :
00203 return self.tsec_in_range(evt_time(evt))
00204
00205
00206 def __cmp__(self, other) :
00207 """for comparison in sorted()
00208 """
00209 if self.begin() < other.begin() : return -1
00210 if self.begin() > other.begin() : return 1
00211 if self.begin() == other.begin() :
00212 if self.end() == other.end() : return 0
00213 if self.end() == 'end' : return -1
00214 if other.end() == 'end' : return 1
00215 if self.end() > other.end() : return -1
00216 if self.end() < other.end() : return 1
00217
00218
00219 def save(self, group) :
00220
00221 grp = get_subgroup(group, self.range())
00222
00223 ds1 = save_object_as_dset(grp, 'begin', data=self.begin())
00224 ds2 = save_object_as_dset(grp, 'end', data=self.end())
00225 ds3 = save_object_as_dset(grp, 'range', data=self.range())
00226 ds4 = save_object_as_dset(grp, 'versdef', data=self._vnum_def)
00227
00228 msg = '=== save(), group %s object for %s' % (grp.name, self.range())
00229 log.debug(msg, self._name)
00230
00231
00232
00233
00234 for k,v in self._dicvers.iteritems() :
00235 if k in self._lst_del_keys : delete_object(grp, version_int_to_str(k))
00236 else : v.save(grp)
00237
00238
00239 for k in self._lst_del_keys :
00240 del self._dicvers[k]
00241
00242 self._lst_del_keys = []
00243
00244 self.save_base(grp)
00245
00246
00247 def load(self, grp) :
00248 msg = '=== load data from group %s and fill object %s' % (grp.name, self._name)
00249 log.debug(msg, self._name)
00250
00251 for k,v in dict(grp).iteritems() :
00252
00253
00254
00255 if isinstance(v, sp.dataset_t) :
00256 log.debug('load dataset "%s"' % k, self._name)
00257 if k == 'begin' : self.set_begin(v[0])
00258 elif k == 'end' : self.set_end(v[0])
00259 elif k == 'range' : self.set_str_range(v[0])
00260 elif k == 'versdef' : self.set_vnum_def(v[0])
00261 else : log.warning('group "%s" has unrecognized dataset "%s"' % (grp.name, k), self._name)
00262
00263 elif isinstance(v, sp.group_t) :
00264 if self.is_base_group(k,v) : continue
00265 log.debug('load group "%s"' % k, self._name)
00266 o = self.add_version(v['version'][0], cmt=False)
00267 o.load(v)
00268
00269
00270 def print_obj(self) :
00271 offset = 3 * self._offspace
00272 self.print_base(offset)
00273 print '%s begin %s' % (offset, self.begin()),
00274 print ': %s' % self.tsec_to_tstr(self.begin())
00275 print '%s end %s' % (offset, self.end()),
00276 print ' %s' % ('' if (self.end() in (None,'end')) else self.tsec_to_tstr(self.end()))
00277 print '%s range %s' % (offset, self.range())
00278 print '%s versdef %s' % (offset, self.vnum_def())
00279 print '%s N vers %s' % (offset, len(self.versions()))
00280 print '%s versions %s' % (offset, str(self.versions().keys()))
00281
00282 for k,v in self.versions().iteritems() :
00283 v.print_obj()
00284
00285
00286
00287 def test_DCRange() :
00288
00289 o = DCRange(None, None)
00290
00291 r = o.begin()
00292 r = o.end()
00293 r = o.versions()
00294 r = o.vnum_def()
00295 r = o.version(None)
00296 o.set_begin(None)
00297 o.set_end(None)
00298 o.add_version()
00299 o.set_vnum_def(None)
00300 v = o.del_version(None)
00301 o.del_versions()
00302 o.clear_versions()
00303
00304 r = o.get(None, None, None)
00305
00306 o.load(None)
00307
00308
00309
00310 def test() :
00311 log.setPrintBits(0377)
00312
00313 if len(sys.argv)==1 : print 'For test(s) use command: python %s <test-number=1-4>' % sys.argv[0]
00314 elif(sys.argv[1]=='1') : test_DCRange()
00315 else : print 'Non-expected arguments: sys.argv = %s use 1,2,...' % sys.argv
00316
00317
00318
00319 if __name__ == "__main__" :
00320 test()
00321 sys.exit( 'End of %s test.' % sys.argv[0])
00322
00323