00001
00002
00003
00004
00005
00006
00007
00008 """Class contains a collection of direct python access methods to detector associated information.
00009
00010 Access method to calibration and geometry parameters, raw data, etc.
00011 Low level implementation is done on python.
00012
00013 @see classes
00014 \n :py:class:`Detector.PyDetector` - factory for different detectors
00015 \n :py:class:`Detector.DetectorAccess` - c++ access interface to data
00016
00017 This software was developed for the LCLS project.
00018 If you use all or part of it, please give an appropriate acknowledgment.
00019
00020 @version $Id: PyDetectorAccess.py 13030 2016-12-19 22:50:20Z cpo@SLAC.STANFORD.EDU $
00021
00022 @author Mikhail S. Dubrovin
00023 """
00024
00025 __version__ = "$Revision: 13030 $"
00026
00027
00028
00029 import sys
00030 import numpy as np
00031 import _psana
00032 import Detector.PyDataAccess as pda
00033
00034
00035 import PSCalib.GlobalUtils as gu
00036
00037 from PSCalib.CalibParsStore import cps
00038 from PSCalib.CalibFileFinder import CalibFileFinder
00039 from PSCalib.GeometryAccess import GeometryAccess, img_from_pixel_arrays
00040 from PSCalib.NDArrIO import save_txt, load_txt
00041 from pyimgalgos.cm_epix import cm_epix
00042
00043
00044
00045
00046
00047
00048
00049 class PyDetectorAccess :
00050 """Direct python access to detector data.
00051 """
00052 GEO_NOT_LOADED = 0
00053 GEO_LOADED_CALIB = 1
00054 GEO_LOADED_DEFAULT = 2
00055 GEO_LOADED_DCS = 3
00056
00057
00058
00059 def __init__(self, source, env, pbits=0) :
00060 """Constructor.
00061 - source - data source, ex: _psana.Source('DetInfo(CxiDs2.0:Cspad.0)')
00062 - env - environment
00063 - pbits - print control bit-word
00064 """
00065
00066
00067 self.source = source
00068 self.str_src= gu.string_from_source(source)
00069 self.env = env
00070 self.pbits = pbits
00071 self.dettype = gu.det_type_from_source(self.str_src)
00072 self.do_offset = False
00073 self.correct_time = True
00074 self.do_calib_imp = False
00075 if self.pbits & 1 : self.print_attributes()
00076
00077 self.cpst = None
00078 self.runnum_cps = -1
00079
00080 self.geo = None
00081 self.runnum_geo = -1
00082 self.mbits = None
00083
00084 self.cfg_gain_mask_is_loaded = False
00085 self.runnum_cfg = -1
00086 self._gain_mask = None
00087
00088 self.counter_cspad2x2_msg = 0
00089 self.reshape_to_3d = False
00090
00091
00092
00093 def cpstore(self, par) :
00094
00095 runnum = par if isinstance(par, int) else par.run()
00096
00097
00098
00099
00100
00101
00102 if runnum != self.runnum_cps or self.cpst is None :
00103 self.runnum_cps = runnum
00104 group = gu.dic_det_type_to_calib_group[self.dettype]
00105
00106 self.cpst = cps.CreateForEvtEnv(self.env.calibDir(), group, self.str_src, par, self.env, self.pbits & 16)
00107 if self.pbits & 1 : print 'PSCalib.CalibParsStore object is created for run %d' % runnum
00108
00109 return self.cpst
00110
00111
00112
00113 def default_geometry(self) :
00114 """Returns default geometry object for some of detectors"""
00115 import CalibManager.AppDataPath as apputils
00116
00117 if self.dettype == gu.EPIX100A :
00118 fname = apputils.AppDataPath('Detector/geometry-def-epix100a.data').path()
00119 if self.pbits : print '%s: Load default geometry from file %s' % (self.__class__.__name__, fname)
00120 return GeometryAccess(fname, 0377 if self.pbits else 0)
00121
00122 return None
00123
00124
00125
00126 def geoaccess_dcs(self, evt) :
00127 import PSCalib.DCMethods as dcm
00128
00129 cdir = self.env.calibDir()
00130
00131
00132
00133
00134 data = dcm.get_constants(evt, self.env, self.str_src, ctype=gu.GEOMETRY, calibdir=cdir, vers=None, verb=self.pbits & 16)
00135
00136 if data is None : return
00137
00138
00139
00140
00141
00142
00143
00144
00145 self.geo = GeometryAccess(pbits=0377 if self.pbits else 0)
00146 self.geo.load_pars_from_str(data)
00147
00148 self.geo_load_status = self.GEO_LOADED_DCS
00149
00150
00151
00152 def geoaccess_calib(self, runnum) :
00153
00154 group = gu.dic_det_type_to_calib_group[self.dettype]
00155 cff = CalibFileFinder(self.env.calibDir(), group, 0377 if self.pbits else 0)
00156 fname = cff.findCalibFile(self.str_src, 'geometry', runnum)
00157 if fname :
00158 self.geo = GeometryAccess(fname, 0377 if self.pbits else 0)
00159 if self.pbits & 1 : print 'PSCalib.GeometryAccess object is created for run %d' % runnum
00160 if self.geo.valid : self.geo_load_status = self.GEO_LOADED_CALIB
00161 else :
00162 self.geo = None
00163 if self.pbits & 1 : print 'WARNING: PSCalib.GeometryAccess object is NOT created for run %d - geometry file is missing.' % runnum
00164
00165 if self.geo is None :
00166
00167 self.geo = self.default_geometry()
00168 if self.geo is not None : self.geo_load_status = self.GEO_LOADED_DEFAULT
00169
00170
00171
00172 def geoaccess(self, par) :
00173
00174 runnum = par if isinstance(par, int) else par.run()
00175
00176
00177
00178 if runnum != self.runnum_geo or self.geo is None :
00179
00180 self.geo_load_status = self.GEO_NOT_LOADED
00181
00182 self.runnum_geo = runnum
00183 self.geoaccess_calib(runnum)
00184
00185
00186 if self.geo is None or self.geo_load_status == self.GEO_LOADED_DEFAULT:
00187 self.geoaccess_dcs(par)
00188
00189
00190 self.iX = None
00191 self.iY = None
00192 self.coords_x_arr = None
00193 self.coords_y_arr = None
00194 self.coords_z_arr = None
00195 self.areas_arr = None
00196 self.mask_geo_arr = None
00197 self.mbits = None
00198 self.pixel_size_val = None
00199
00200 return self.geo
00201
00202
00203
00204 def print_attributes(self) :
00205 print 'PyDetectorAccess attributes:\n source: %s\n dtype : %d\n pbits : %d' % \
00206 (self.source, self.dettype, self.pbits), \
00207 '\n do_offset (Camera): %s\n correct_time (Acqiris): %s\n do_calib_imp (Imp): %s' % \
00208 (self.do_offset, self.correct_time, self.do_calib_imp)
00209
00210
00211
00212 def set_env(self, env) :
00213 self.env = env
00214
00215
00216
00217 def set_source(self, source) :
00218 self.source = source
00219 self.str_src = gu.string_from_source(source)
00220
00221
00222
00223 def pedestals(self, par) :
00224 return self.cpstore(par).pedestals()
00225
00226
00227
00228 def pixel_rms(self, par) :
00229 return self.cpstore(par).pixel_rms()
00230
00231
00232
00233 def pixel_gain(self, par) :
00234 return self.cpstore(par).pixel_gain()
00235
00236
00237
00238 def pixel_mask(self, par) :
00239 return self.cpstore(par).pixel_mask()
00240
00241
00242
00243 def pixel_bkgd(self, par) :
00244 return self.cpstore(par).pixel_bkgd()
00245
00246
00247
00248 def pixel_status(self, par) :
00249 return self.cpstore(par).pixel_status()
00250
00251
00252
00253 def common_mode(self, par) :
00254 return self.cpstore(par).common_mode()
00255
00256
00257
00258 def common_mode_apply(self, alg_num, kwargs, nda):
00259 if alg_num == 6:
00260 cm_epix(img=nda, **kwargs)
00261 else:
00262 print 'alg_num does not exist'
00263
00264
00265
00266 def ndim(self, par=0, ctype=gu.PEDESTALS) :
00267 sh = np.array(self.shape())
00268 if sh is not None : return sh.size
00269 return self.cpstore(par).ndim(ctype)
00270
00271
00272
00273 def size(self, par=0, ctype=gu.PEDESTALS) :
00274 sh = np.array(self.shape())
00275 if sh is not None : return sh.prod()
00276 return self.cpstore(par).size(ctype)
00277
00278
00279
00280 def shape_calib(self, par, ctype=gu.PEDESTALS) :
00281 return self.cpstore(par).shape(ctype)
00282
00283
00284
00285 def status(self, par, ctype=gu.PEDESTALS) :
00286 return self.cpstore(par).status(ctype)
00287
00288
00289
00290
00291
00292 def _shaped_geo_array(self, arr) :
00293 if arr is None : return None
00294 if self.dettype == gu.EPIX100A : arr.shape = (704, 768)
00295
00296 return arr
00297
00298
00299
00300 def _update_coord_arrays(self, par, do_update=False) :
00301 """ Returns True if pixel index arrays are available, othervise False.
00302 """
00303 if self.geoaccess(par) is None : return False
00304 else :
00305 if self.coords_x_arr is None or do_update :
00306 self.coords_x_arr, self.coords_y_arr, self.coords_z_arr = self.geo.get_pixel_coords()
00307 if self.coords_x_arr is None : return False
00308 return True
00309
00310
00311
00312 def coords_x(self, par) :
00313 if not self._update_coord_arrays(par) : return None
00314 return self._shaped_geo_array(self.coords_x_arr)
00315
00316
00317
00318 def coords_y(self, par) :
00319 if not self._update_coord_arrays(par) : return None
00320 return self._shaped_geo_array(self.coords_y_arr)
00321
00322
00323
00324 def coords_z(self, par) :
00325 if not self._update_coord_arrays(par) : return None
00326 return self._shaped_geo_array(self.coords_z_arr)
00327
00328
00329
00330 def coords_xy(self, par) :
00331 if not self._update_coord_arrays(par) : return None
00332 return self._shaped_geo_array(self.coords_x_arr), self._shaped_geo_array(self.coords_y_arr)
00333
00334
00335
00336 def coords_xyz(self, par) :
00337 if not self._update_coord_arrays(par) : return None
00338 return self._shaped_geo_array(self.coords_x_arr),\
00339 self._shaped_geo_array(self.coords_y_arr),\
00340 self._shaped_geo_array(self.coords_z_arr)
00341
00342
00343
00344 def areas(self, par) :
00345 if self.geoaccess(par) is None : return None
00346 else :
00347 if self.areas_arr is None :
00348 self.areas_arr = self.geo.get_pixel_areas()
00349 return self._shaped_geo_array(self.areas_arr)
00350
00351
00352
00353
00354 def mask_geo(self, par, mbits=15) :
00355
00356 if mbits != self.mbits :
00357 self.mbits = mbits
00358 self.mask_geo_arr = None
00359
00360 if self.geoaccess(par) is None : return None
00361 else :
00362 if self.mask_geo_arr is None :
00363 self.mask_geo_arr = self.geo.get_pixel_mask(mbits=mbits)
00364 return self._shaped_geo_array(self.mask_geo_arr)
00365
00366
00367
00368 def _update_index_arrays(self, par, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00369 """ Returns True if pixel index arrays are available, othervise False.
00370 """
00371 if self.geoaccess(par) is None : return False
00372 else :
00373 if self.iX is None or do_update :
00374 self.iX, self.iY = self.geo.get_pixel_coord_indexes(oname=None, oindex=0,\
00375 pix_scale_size_um=pix_scale_size_um,\
00376 xy0_off_pix=xy0_off_pix, do_tilt=True)
00377 if self.iX is None : return False
00378 return True
00379
00380
00381
00382 def indexes_x(self, par, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00383 """Returns pixel index array iX."""
00384 if not self._update_index_arrays(par, pix_scale_size_um, xy0_off_pix, do_update) : return None
00385 return self._shaped_geo_array(self.iX)
00386
00387
00388
00389 def indexes_y(self, par, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00390 """Returns pixel index array iY."""
00391 if not self._update_index_arrays(par, pix_scale_size_um, xy0_off_pix, do_update) : return None
00392 return self._shaped_geo_array(self.iY)
00393
00394
00395
00396 def indexes_xy(self, par, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00397 """Returns two pixel index arrays iX and iY."""
00398 if not self._update_index_arrays(par, pix_scale_size_um, xy0_off_pix, do_update) : return None
00399 if self.iX is None : return None, None
00400 return self._shaped_geo_array(self.iX), self._shaped_geo_array(self.iY)
00401
00402
00403
00404 def point_indexes(self, par, pxy_um=(0,0), pix_scale_size_um=None, xy0_off_pix=None) :
00405 """Returns ix, iy indexes of the point p_um x,y coordinates in [um]"""
00406 if self.geoaccess(par) is None : return None, None
00407 ix, iy = self.geo.point_coord_indexes(p_um=pxy_um, oname=None, oindex=0,\
00408 pix_scale_size_um=pix_scale_size_um,\
00409 xy0_off_pix=xy0_off_pix, do_tilt=True)
00410 return ix, iy
00411
00412
00413
00414 def pixel_size(self, par) :
00415 if self.geoaccess(par) is None : return None
00416 else :
00417 if self.pixel_size_val is None :
00418 self.pixel_size_val = self.geo.get_pixel_scale_size()
00419 return self.pixel_size_val
00420
00421
00422
00423 def move_geo(self, par, dx, dy, dz) :
00424 if self.geoaccess(par) is None : pass
00425 else : return self.geo.move_geo(None, 0, dx, dy, dz)
00426
00427
00428
00429 def tilt_geo(self, par, dtx, dty, dtz) :
00430 if self.geoaccess(par) is None : pass
00431 else : return self.geo.tilt_geo(None, 0, dtx, dty, dtz)
00432
00433
00434
00435 def image_xaxis(self, par, pix_scale_size_um=None, x0_off_pix=None) :
00436 pix_size = pix_scale_size_um if pix_scale_size_um is not None else self.pixel_size(par)
00437 carr = self.coords_x(par)
00438 if carr is None : return None
00439 cmin, cmax = carr.min(), carr.max() + 0.5*pix_size
00440 if x0_off_pix is None :
00441 return np.arange(cmin, cmax, pix_size)
00442 else :
00443 return np.arange(cmin-pix_size*x0_off_pix, cmax, pix_size)
00444
00445
00446
00447 def image_yaxis(self, par, pix_scale_size_um=None, y0_off_pix=None) :
00448 pix_size = pix_scale_size_um if pix_scale_size_um is not None else self.pixel_size(par)
00449 carr = self.coords_y(par)
00450 if carr is None : return None
00451 cmin, cmax = carr.min(), carr.max() + 0.5*pix_size
00452 if y0_off_pix is None :
00453 return np.arange(cmin, cmax, pix_size)
00454 else :
00455 return np.arange(cmin-pix_size*y0_off_pix, cmax, pix_size)
00456
00457
00458
00459 def image(self, par, img_nda, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00460 if not self._update_index_arrays(par, pix_scale_size_um, xy0_off_pix, do_update) : return None
00461 return img_from_pixel_arrays(self.iX, self.iY, img_nda)
00462
00463
00464
00465 def do_reshape_2d_to_3d(self, flag=False) :
00466 self.reshape_to_3d = flag
00467
00468
00469
00470 def ndarray_from_image(self, par, image, pix_scale_size_um=None, xy0_off_pix=None, do_update=False) :
00471
00472 if image is None : return None
00473 if len(image.shape) != 2 : return None
00474
00475
00476
00477 if self.reshape_to_3d and self.geoaccess(par) is None :
00478 return np.array(image, copy=True)
00479
00480 if not self._update_index_arrays(par, pix_scale_size_um, xy0_off_pix, do_update) : return None
00481 return self._shaped_geo_array(np.array([image[r,c] for r,c in zip(self.iX, self.iY)]))
00482
00483
00484
00485
00486
00487
00488 def inst(self) :
00489 return self.env.instrument()
00490
00491
00492
00493 def print_config(self, evt) :
00494 print '%s:print_config(evt) - is not implemented in pythonic version' % self.__class__.__name__
00495
00496
00497
00498 def set_print_bits(self, pbits) :
00499 self.pbits = pbits
00500
00501
00502
00503 def set_do_offset(self, do_offset=False) :
00504 """On/off application of offset in raw_data_camera(...)
00505 """
00506 self.do_offset = do_offset
00507
00508
00509
00510 def set_correct_acqiris_time(self, correct_time=True) :
00511 """On/off correction of time for acqiris
00512 """
00513 self.correct_time = correct_time
00514
00515
00516
00517 def set_calib_imp(self, do_calib_imp=False) :
00518 """On/off imp calibration
00519 """
00520 self.do_calib_imp = do_calib_imp
00521
00522
00523
00524 def gain_mask(self, par, gain=None) :
00525 """Returns a gain map extracted from detector configuration data.
00526 Currently implemented for CSPAD only.
00527 Returns None for other detectors or missing configuration for CSPAD.
00528 """
00529 runnum = par if isinstance(par, int) else par.run()
00530
00531 if runnum == self.runnum_cfg :
00532 if self.cfg_gain_mask_is_loaded :
00533 return self._gain_mask
00534 else :
00535 self.runnum_cfg = runnum
00536 self.cfg_gain_mask_is_loaded = False
00537
00538 if self.dettype == gu.CSPAD : self._gain_mask = self.cspad_gain_mask(gain)
00539 elif self.dettype == gu.CSPAD2X2 : self._gain_mask = self.cspad2x2_gain_mask(gain)
00540 else :
00541 self.cfg_gain_mask_is_loaded = True
00542 self._gain_mask = None
00543 return self._gain_mask
00544
00545
00546
00547 def gain_mask_non_zero(self, par, gain=None) :
00548 """The same as gain_mask, but returns None if ALL pixels have high gain"""
00549
00550 gm = self.gain_mask(par, gain)
00551
00552 if gm is not None :
00553 if not gm.any() : return None
00554
00555 return gm
00556
00557
00558
00559 def raw_data(self, evt, env) :
00560
00561
00562
00563
00564 if self.dettype == gu.CSPAD : return self.raw_data_cspad(evt, env)
00565 elif self.dettype == gu.CSPAD2X2 : return self.raw_data_cspad2x2(evt, env)
00566 elif self.dettype == gu.PRINCETON : return self.raw_data_princeton(evt, env)
00567 elif self.dettype == gu.PNCCD : return self.raw_data_pnccd(evt, env)
00568 elif self.dettype == gu.ANDOR : return self.raw_data_andor(evt, env)
00569 elif self.dettype == gu.ANDOR3D : return self.raw_data_andor(evt, env)
00570 elif self.dettype == gu.JUNGFRAU : return self.raw_data_jungfrau(evt, env)
00571 elif self.dettype == gu.FCCD960 : return self.raw_data_fccd960(evt, env)
00572 elif self.dettype == gu.EPIX100A : return self.raw_data_epix(evt, env)
00573 elif self.dettype == gu.EPIX10K : return self.raw_data_epix(evt, env)
00574 elif self.dettype == gu.EPIX : return self.raw_data_epix(evt, env)
00575 elif self.dettype == gu.ACQIRIS : return self.raw_data_acqiris(evt, env)
00576 elif self.dettype == gu.OPAL1000 : return self.raw_data_camera(evt, env)
00577 elif self.dettype == gu.OPAL2000 : return self.raw_data_camera(evt, env)
00578 elif self.dettype == gu.OPAL4000 : return self.raw_data_camera(evt, env)
00579 elif self.dettype == gu.OPAL8000 : return self.raw_data_camera(evt, env)
00580 elif self.dettype == gu.ORCAFL40 : return self.raw_data_camera(evt, env)
00581 elif self.dettype == gu.TM6740 : return self.raw_data_camera(evt, env)
00582 elif self.dettype == gu.QUARTZ4A150: return self.raw_data_camera(evt, env)
00583 elif self.dettype == gu.RAYONIX : return self.raw_data_camera(evt, env)
00584 elif self.dettype == gu.IMP : return self.raw_data_imp(evt, env)
00585 elif self.dettype == gu.FCCD : return self.raw_data_camera(evt, env)
00586 elif self.dettype == gu.TIMEPIX : return self.raw_data_timepix(evt, env)
00587 elif self.dettype == gu.FLI : return self.raw_data_fli(evt, env)
00588 elif self.dettype == gu.PIMAX : return self.raw_data_pimax(evt, env)
00589 else : return None
00590
00591
00592
00593 def raw_data_cspad(self, evt, env) :
00594
00595
00596 d = pda.get_cspad_data_object(evt, self.source)
00597 if d is None :
00598 if self.pbits & 1 : print 'cspad data object is not found'
00599 return None
00600
00601
00602 c = pda.get_cspad_config_object(env, self.source)
00603 if c is None :
00604 if self.pbits & 1 : print 'cspad config object is not found'
00605 return None
00606
00607 nquads = d.quads_shape()[0]
00608 nquads_c = c.numQuads()
00609
00610
00611 if self.pbits & 8 : print 'nquads in data: %d and config: %d' % (nquads, nquads_c)
00612
00613 arr = np.zeros((4,8,185,388), dtype=np.int16) if nquads<4 else np.empty((4,8,185,388), dtype=np.int16)
00614
00615 for iq in range(nquads) :
00616 q = d.quads(iq)
00617 qnum = q.quad()
00618 qdata = q.data()
00619 roim = c.roiMask(qnum)
00620 if self.pbits & 8 : print 'qnum: %d qdata.shape: %s, mask: %d' % (qnum, str(qdata.shape), roim)
00621
00622
00623 if roim == 0377 :
00624 arr[qnum,:] = qdata
00625
00626 else :
00627 if self.pbits : print 'PyDetectorAccessr: quad configuration has non-complete mask = %d of included 2x1' % roim
00628 qdata_full = np.zeros((8,185,388), dtype=qdata.dtype)
00629 i = 0
00630 for s in range(8) :
00631 if roim & (1<<s) :
00632 qdata_full[s,:] = qdata[i,:]
00633 i += 1
00634 arr[qnum,:,:] = qdata_full
00635
00636 if self.pbits & 8 : print 'arr.shape: ', arr.shape
00637 arr.shape = (32,185,388)
00638 return arr
00639
00640
00641
00642 def raw_data_cspad2x2(self, evt, env) :
00643
00644 d = pda.get_cspad2x2_data_object(evt, self.source)
00645 if d is None : return None
00646
00647
00648 c = pda.get_cspad2x2_config_object(env, self.source)
00649 if c is None :
00650 if self.pbits and self.counter_cspad2x2_msg <3 :
00651 print 'WARNING PyDetectorAccess: missing configuration object for source %s' % (self.str_src)
00652 if self.counter_cspad2x2_msg == 2 : print 'Stop WARNING messages for %s configuration' % self.str_src
00653 self.counter_cspad2x2_msg += 1
00654
00655
00656 if c.roiMask() != 3 :
00657 if self.pbits and self.counter_cspad2x2_msg <3 :
00658 print 'WARNING PyDetectorAccess: configuration of %s has non-complete mask=%d of included 2x1' % (self.str_src, c.roiMask())
00659 if self.counter_cspad2x2_msg == 2 : print 'Stop WARNING messages for %s configuration' % self.str_src
00660 self.counter_cspad2x2_msg += 1
00661
00662 return d.data()
00663
00664
00665
00666 def raw_data_camera(self, evt, env) :
00667
00668 d = pda.get_camera_data_object(evt, self.source)
00669 if d is None : return None
00670
00671
00672
00673
00674
00675
00676 offset = d.offset()
00677
00678 d16 = d.data16()
00679 if d16 is not None and d16 != [] :
00680 if self.do_offset : return np.array(d16, dtype=np.int32) - d.offset()
00681 else : return d16
00682
00683 d8 = d.data8()
00684 if d8 is not None and d8 != [] :
00685 if self.do_offset : return np.array(d8, dtype=np.int32) - d.offset()
00686 else : return d8
00687
00688 return None
00689
00690
00691
00692 def raw_data_fccd960(self, evt, env) :
00693
00694 d = pda.get_camera_data_object(evt, self.source)
00695 if d is None : return None
00696
00697
00698
00699
00700
00701 arr = d.data16()
00702 if arr is None : return None
00703
00704 arr_c = (arr>>13)&03
00705 arr_v = arr&017777
00706
00707
00708
00709 return np.select([arr_c==0, arr_c==1, arr_c==3], \
00710 [arr_v, arr_v<<2, arr_v<<3])
00711
00712
00713
00714 def raw_data_princeton(self, evt, env) :
00715
00716 d = pda.get_princeton_data_object(evt, self.source)
00717 if d is None : return None
00718
00719
00720
00721
00722
00723
00724 nda = d.data()
00725 return nda if nda is not None else None
00726
00727
00728
00729 def raw_data_pnccd(self, evt, env) :
00730
00731
00732
00733
00734 d = pda.get_pnccd_data_object(evt, self.source)
00735 if d is None : return None
00736
00737
00738
00739
00740
00741 arr = []
00742 nlinks = d.numLinks()
00743 for i in range(nlinks) :
00744 frame = d.frame(i)
00745 fdata = frame.data()
00746 arr.append(fdata)
00747
00748
00749 nda = np.array(arr)
00750
00751 return nda
00752
00753
00754
00755 def raw_data_andor(self, evt, env) :
00756
00757 d = pda.get_andor_data_object(evt, self.source)
00758 if d is None : return None
00759
00760 if self.pbits & 4 :
00761 print 'Data object:', d
00762 print 'shotIdStart = ', d.shotIdStart()
00763 print 'readoutTime = ', d.readoutTime()
00764 print 'temperature = ', d.temperature()
00765
00766 c = pda.get_andor_config_object(env, self.source)
00767
00768 if c is not None and self.pbits & 4 :
00769 print 'Configuration object:', c
00770 print 'width = ', c.width()
00771 print 'height = ', c.height()
00772 print 'numSensors = ', c.numSensors()
00773 print 'orgX = ', c.orgX()
00774 print 'orgY = ', c.orgY()
00775 print 'binX = ', c.binX()
00776 print 'binY = ', c.binY()
00777 print 'exposureTime = ', c.exposureTime()
00778 print 'coolingTemp = ', c.coolingTemp ()
00779 print 'fanMode = ', c.fanMode ()
00780 print 'baselineClamp = ', c.baselineClamp()
00781 print 'highCapacity = ', c.highCapacity()
00782 print 'gainIndex = ', c.gainIndex()
00783 print 'readoutSpeedIndex = ', c.readoutSpeedIndex()
00784 print 'exposureEventCode = ', c.exposureEventCode()
00785 print 'exposureStartDelay = ', c.exposureStartDelay()
00786 print 'numDelayShots = ', c.numDelayShots()
00787 print 'frameSize = ', c.frameSize()
00788 print 'numPixelsX = ', c.numPixelsX()
00789 print 'numPixelsY = ', c.numPixelsY()
00790 print 'numPixelsPerSensor = ', c.numPixelsPerSensor()
00791 print 'numPixels = ', c.numPixels()
00792
00793 nda = d.data()
00794 return nda if nda is not None else None
00795
00796
00797
00798 def raw_data_jungfrau(self, evt, env) :
00799 d = pda.get_jungfrau_data_object(evt, self.source)
00800 if d is None : return None
00801 return d.frame()
00802
00803
00804
00805 def raw_data_epix(self, evt, env) :
00806
00807 d = pda.get_epix_data_object(evt, self.source)
00808 if d is None : return None
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 nda = d.frame()
00820 return nda if nda is not None else None
00821
00822
00823
00824 def raw_data_timepix(self, evt, env) :
00825
00826 d = pda.get_timepix_data_object(evt, self.source)
00827 if d is None : return None
00828
00829
00830
00831
00832
00833
00834 nda = d.data()
00835 return nda if nda is not None else None
00836
00837
00838
00839 def raw_data_fli(self, evt, env) :
00840
00841 d = pda.get_fli_data_object(evt, self.source)
00842 if d is None : return None
00843
00844
00845
00846
00847
00848
00849 nda = d.data()
00850 return nda if nda is not None else None
00851
00852
00853
00854 def raw_data_pimax(self, evt, env) :
00855
00856 d = pda.get_pimax_data_object(evt, self.source)
00857 if d is None : return None
00858
00859
00860
00861
00862
00863
00864 nda = d.data()
00865 return nda if nda is not None else None
00866
00867
00868
00869
00870
00871
00872 def raw_data_acqiris(self, evt, env) :
00873 """returns two 2-d ndarrays wf,wt with shape=(nbrChannels, nbrSamples) or None
00874 """
00875
00876 d = pda.get_acqiris_data_object(evt, self.source)
00877 if d is None : return None
00878
00879
00880 c = pda.get_acqiris_config_object(env, self.source)
00881 if c is None : return None
00882
00883
00884 nbrChannels = c.nbrChannels()
00885
00886 h = c.horiz()
00887 sampInterval = h.sampInterval()
00888 nbrSamples = h.nbrSamples()
00889
00890 if self.pbits & 4 : print ' nbrChannels: %d, H-nbrSamples: %d, H-sampInterval: %g' \
00891 % (nbrChannels, nbrSamples, sampInterval)
00892
00893 shape = (nbrChannels, nbrSamples)
00894 wf = np.zeros(shape, dtype=np.float)
00895 wt = np.zeros(shape, dtype=np.float)
00896
00897 for chan in range(nbrChannels) :
00898 elem = d.data(chan)
00899 vert = c.vert()[chan]
00900
00901 slope = vert.slope()
00902 offset= vert.offset()
00903
00904 nbrSegments = elem.nbrSegments()
00905 nbrSamplesInSeg = elem.nbrSamplesInSeg()
00906 indexFirstPoint = elem.indexFirstPoint()
00907 tstamps = elem.timestamp()
00908 wforms = elem.waveforms()
00909
00910 if self.pbits & 4 :
00911 print ' chan: %d, nbrSegments: %d, nbrSamplesInSeg: %d, indexFirstPoint: %d,' \
00912 % (chan, nbrSegments, nbrSamplesInSeg, indexFirstPoint), \
00913 ' V-slope: %f, V-offset: %f, H-pos[seg=0]: %g' % (slope, offset, tstamps[0].pos())
00914
00915 for seg in range(nbrSegments) :
00916 raw = wforms[seg]
00917 pos = tstamps[seg].pos()
00918 i0_seg = seg * nbrSamplesInSeg + int(pos/sampInterval) if self.correct_time else seg * nbrSamplesInSeg
00919 size = nbrSamplesInSeg if (i0_seg + nbrSamplesInSeg) <= nbrSamples else nbrSamples - i0_seg
00920
00921 if self.correct_time :
00922 if (indexFirstPoint + size) > nbrSamplesInSeg : size = nbrSamplesInSeg - indexFirstPoint
00923
00924 wf[chan, i0_seg:i0_seg+size] = raw[indexFirstPoint:indexFirstPoint+size]*slope - offset
00925 else :
00926 wf[chan, i0_seg:i0_seg+size] = raw[0:size]*slope - offset
00927
00928 wt[chan, i0_seg:i0_seg+size] = np.arange(size)*sampInterval + pos
00929
00930 return wf, wt
00931
00932
00933
00934 def raw_data_imp(self, evt, env) :
00935 """returns ndarray with shape=(4, 1023) or None
00936 """
00937
00938 d = pda.get_imp_data_object(evt, self.source)
00939 if d is None : return None
00940
00941 if self.pbits & 4 :
00942
00943 c = pda.get_imp_config_object(env, self.source)
00944 if c is None : return None
00945
00946 print "Configuration object for %s" % self.source
00947 print " range =", c.range()
00948 print " calRange =", c.calRange()
00949 print " reset =", c.reset()
00950 print " biasData =", c.biasData()
00951 print " calData =", c.calData()
00952 print " biasDacData =", c.biasDacData()
00953 print " calStrobe =", c.calStrobe()
00954 print " numberOfSamples =", c.numberOfSamples()
00955 print " trigDelay =", c.trigDelay()
00956 print " adcDelay =", c.adcDelay()
00957
00958 print "Data object for %s" % self.source
00959 print " vc =", d.vc()
00960 print " lane =", d.lane()
00961 print " frameNumber =", d.frameNumber()
00962 print " range =", d.range()
00963
00964 laneStatus = d.laneStatus()
00965 print " laneStatus.linkErrCount =", laneStatus.linkErrCount()
00966 print " laneStatus.linkDownCount =", laneStatus.linkDownCount()
00967 print " laneStatus.cellErrCount =", laneStatus.cellErrCount()
00968 print " laneStatus.rxCount =", laneStatus.rxCount()
00969 print " laneStatus.locLinked =", laneStatus.locLinked()
00970 print " laneStatus.remLinked =", laneStatus.remLinked()
00971 print " laneStatus.zeros =", laneStatus.zeros()
00972 print " laneStatus.powersOkay =", laneStatus.powersOkay()
00973
00974 lst_of_samps = d.samples()
00975 a = np.array([sample.channels() for sample in lst_of_samps])
00976
00977 a = np.transpose(a)
00978
00979 if self.do_calib_imp :
00980 c = pda.get_imp_config_object(env, self.source)
00981 if c is None : return None
00982 bias = c.biasData()
00983 return np.array(a, dtype=np.int32) - bias
00984
00985 return a
00986
00987
00988
00989 def cspad_gain_mask(self, gain=None) :
00990 """ Returns the gain mask of 1/0 for low/high gain pixels as a numpy array of shape=(32,185,388), dtype=uint8.
00991 If gain is set, method returns a map of (float) gain/1 values for low/high gain pixels, respectively.
00992 None is returned if configuration data is missing.
00993 """
00994
00995 c = pda.get_cspad_config_object(self.env, self.source)
00996 if c is None :
00997 msg = '%s.cspad_gain_mask - config object is not available' % self.__class__.__name__
00998
00999 print msg
01000 return None
01001
01002
01003 self.gm = np.zeros((32,185,388), dtype=np.uint8)
01004 asic1 = np.ones((185,194), dtype=np.uint8)
01005
01006 for iquad in range(c.quads_shape()[0]):
01007
01008 gm = np.array(c.quads(iquad).gm().gainMap())
01009
01010 for i2x1 in range(8):
01011 gmasic0 = gm & 1
01012 gm = np.right_shift(gm, asic1)
01013 gm2x1 = np.hstack((gmasic0, gm & 1))
01014 self.gm[i2x1+iquad*8][:][:] = np.logical_not(gm2x1)
01015 if i2x1 < 7 : gm = np.right_shift(gm, asic1)
01016
01017 self.cfg_gain_mask_is_loaded = True
01018
01019 if gain is None :
01020 return self.gm
01021 else :
01022 f=float(gain-1.)
01023 return np.array(self.gm,dtype=np.float) * f + 1
01024
01025
01026
01027 def cspad2x2_gain_mask(self, gain=None) :
01028 """ Returns the gain mask of 1/0 for low/high gain pixels as a numpy array of shape=(2,185,388), dtype=uint8.
01029 If gain is set, method returns a map of (float) gain/1 values for low/high gain pixels, respectively.
01030 None is returned if configuration data is missing.
01031 """
01032
01033 c = pda.get_cspad2x2_config_object(self.env, self.source)
01034 if c is None :
01035 msg = '%s.cspad_gain_mask - config object is not available' % self.__class__.__name__
01036
01037 if self.pbits : print msg
01038 return None
01039
01040
01041 self.gm = np.zeros((2,185,388), dtype=np.uint8)
01042 asic1 = np.ones((185,194), dtype=np.uint8)
01043
01044 gm = np.array(c.quad().gm().gainMap())
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 for i2x1 in range(2):
01056 gmasic0 = gm & 1
01057 gm = np.right_shift(gm, asic1)
01058 gm2x1 = np.hstack((gmasic0, gm & 1))
01059 self.gm[i2x1][:][:] = np.logical_not(gm2x1)
01060 if i2x1 < 1 : gm = np.right_shift(gm, asic1)
01061
01062 self.cfg_gain_mask_is_loaded = True
01063
01064 if gain is None :
01065 return self.gm
01066 else :
01067 f=float(gain-1.)
01068 return np.array(self.gm,dtype=np.float) * f + 1
01069
01070
01071
01072 def raw_data_cspad_v0(self, evt, env) :
01073
01074
01075 d = pda.get_cspad_data_object(evt, self.source)
01076 if d is None :
01077 if self.pbits & 1 : print 'cspad data object is not found'
01078 return None
01079
01080
01081 c = pda.get_cspad_config_object(env, self.source)
01082 if c is None :
01083 if self.pbits & 1 : print 'cspad config object is not found'
01084 return None
01085
01086 nquads = d.quads_shape()[0]
01087 nquads_c = c.numQuads()
01088
01089
01090 if self.pbits & 8 : print 'nquads in data: %d and config: %d' % (nquads, nquads_c)
01091
01092 arr = []
01093 for iq in range(nquads) :
01094 q = d.quads(iq)
01095 qnum = q.quad()
01096 qdata = q.data()
01097
01098 roim = c.roiMask(qnum)
01099 if self.pbits & 8 : print 'qnum: %d qdata.shape: %s, mask: %d' % (qnum, str(qdata.shape), roim)
01100
01101
01102
01103
01104 if roim == 0377 : arr.append(qdata)
01105 else :
01106 if self.pbits : print 'PyDetectorAccessr: quad configuration has non-complete mask = %d of included 2x1' % roim
01107 qdata_full = np.zeros((8,185,388), dtype=qdata.dtype)
01108 i = 0
01109 for s in range(8) :
01110 if roim & (1<<s) :
01111 qdata_full[s,:] = qdata[i,:]
01112 i += 1
01113 arr.append(qdata_full)
01114
01115 nda = np.array(arr)
01116 if self.pbits & 8 : print 'nda.shape: ', nda.shape
01117 nda.shape = (32,185,388)
01118 return nda
01119
01120
01121
01122
01123 def shape_config_cspad(self, env) :
01124
01125
01126 c = pda.get_cspad_config_object(env, self.source)
01127 if c is None : return None
01128
01129
01130 return (32, 185, 388)
01131
01132
01133
01134 def shape_config_cspad2x2(self, env) :
01135 c = pda.get_cspad2x2_config_object(env, self.source)
01136
01137 return (185, 388, 2)
01138
01139
01140
01141 def shape_config_epix100(self, env) :
01142 c = pda.get_epix_config_object(env, self.source)
01143 if c is None : return None
01144 return (c.numberOfRows(), c.numberOfColumns())
01145
01146
01147
01148
01149 def shape_config_pnccd(self, env) :
01150 c = pda.get_pnccd_config_object(env, self.source)
01151 if c is None : return None
01152 return (c.numSubmodules(), c.numSubmoduleRows(), c.numSubmoduleChannels())
01153
01154
01155
01156
01157
01158 def shape_config_princeton(self, env) :
01159 c = pda.get_princeton_config_object(env, self.source)
01160 if c is None : return None
01161 return (c.numPixelsY(), c.numPixelsX())
01162
01163
01164
01165
01166
01167 def shape_config_rayonix(self, env) :
01168
01169
01170
01171 c = pda.get_rayonix_config_object(env, self.source)
01172 if c is None : return None
01173 npix_in_colbin = c.binning_f()
01174 npix_in_rowbin = c.binning_s()
01175 if npix_in_rowbin>0 and npix_in_colbin>0 : return (3840/npix_in_rowbin, 3840/npix_in_colbin)
01176 return None
01177
01178
01179
01180 def shape_config_andor(self, env) :
01181
01182 c = pda.get_andor_config_object(env, self.source)
01183 if c is None : return None
01184 nsegs = None
01185 try : nsegs = c.numSensors()
01186 except : pass
01187
01188
01189 npixx = c.width() / c.binX()
01190 npixy = c.height() / c.binY()
01191
01192 if npixx and npixy :
01193 return (npixy, npixx) if nsegs is None else (nsegs, npixy, npixx)
01194 return None
01195
01196
01197
01198 def shape_config_jungfrau(self, env) :
01199
01200 c = pda.get_jungfrau_config_object(env, self.source)
01201 if c is None : return None
01202 nsegs = c.numberOfModules()
01203 npixx = c.numberOfRowsPerModule()
01204 npixy = c.numberOfColumnsPerModule()
01205
01206 return (nsegs, npixy, npixx)
01207
01208
01209
01210 def shape_config_timepix(self, env) :
01211
01212
01213
01214
01215 return (512, 512)
01216
01217
01218 def shape_config_fli(self, env) :
01219
01220 c = pda.get_fli_config_object(env, self.source)
01221 if c is None : return None
01222 return (c.numPixelsY(), c.numPixelsX())
01223
01224
01225
01226 def shape_config_pimax(self, env) :
01227
01228 c = pda.get_pimax_config_object(env, self.source)
01229 if c is None : return None
01230 return (c.numPixelsY(), c.numPixelsX())
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243 def shape_config_camera(self, env) :
01244
01245 c = None
01246 if self.dettype in (gu.OPAL1000, gu.OPAL2000, gu.OPAL4000, gu.OPAL8000) :
01247 c = pda.get_opal1k_config_object(env, self.source)
01248
01249 elif self.dettype == gu.FCCD :
01250 c = pda.get_fccd_config_object(env, self.source)
01251
01252
01253 elif self.dettype == gu.FCCD960 :
01254 c = pda.get_fccd_config_object(env, self.source)
01255
01256
01257 elif self.dettype == gu.ORCAFL40 :
01258 c = pda.get_orca_config_object(env, self.source)
01259
01260
01261 elif self.dettype == gu.TM6740 :
01262 c = pda.get_tm6740_config_object(env, self.source)
01263
01264 elif self.dettype == gu.QUARTZ4A150 :
01265 c = pda.get_quartz_config_object(env, self.source)
01266
01267
01268 if c is None : return None
01269 return (c.Row_Pixels, c.Column_Pixels)
01270
01271
01272
01273
01274 def shape_data_camera(self, evt) :
01275
01276 o = pda.get_camera_data_object(evt, self.source)
01277 if o is None : return None
01278 return (o.width(),o.height())
01279
01280
01281
01282 def shape_config(self, env) :
01283
01284
01285
01286
01287 if self.dettype == gu.CSPAD : return self.shape_config_cspad(env)
01288 elif self.dettype == gu.CSPAD2X2 : return self.shape_config_cspad2x2(env)
01289 elif self.dettype == gu.EPIX100A : return self.shape_config_epix100(env)
01290 elif self.dettype == gu.PRINCETON : return self.shape_config_princeton(env)
01291 elif self.dettype == gu.PNCCD : return self.shape_config_pnccd(env)
01292 elif self.dettype == gu.ANDOR : return self.shape_config_andor(env)
01293 elif self.dettype == gu.ANDOR3D : return self.shape_config_andor(env)
01294 elif self.dettype == gu.JUNGFRAU : return self.shape_config_jungfrau(env)
01295 elif self.dettype == gu.RAYONIX : return self.shape_config_rayonix(env)
01296 elif self.dettype in (gu.OPAL1000, gu.OPAL2000, gu.OPAL4000, gu.OPAL8000,
01297 gu.FCCD, gu.FCCD960, gu.ORCAFL40, gu.TM6740, gu.QUARTZ4A150) \
01298 : return self.shape_config_camera(env)
01299 elif self.dettype == gu.TIMEPIX : return self.shape_config_timepix(env)
01300 elif self.dettype == gu.FLI : return self.shape_config_fli(env)
01301 elif self.dettype == gu.PIMAX : return self.shape_config_pimax(env)
01302
01303
01304
01305
01306 else : return None
01307
01308
01309
01310 def shape(self, par=0) :
01311 """Returns the detector shape.
01312
01313 Shape is retrieved from configuration object and
01314 if it is None, then from calibration file.
01315 """
01316 shc = self.shape_config(self.env)
01317 return shc if shc is not None else self.shape_calib(par, ctype=gu.PEDESTALS)
01318
01319
01320
01321
01322
01323 def save_txtnda(self, fname='nda.txt', ndarr=None, cmts=(), fmt='%.1f', verbos=False, addmetad=True) :
01324 save_txt(fname, ndarr, cmts, fmt, verbos, addmetad)
01325
01326
01327
01328 def load_txtnda(self, fname) :
01329 nda = load_txt(fname)
01330 if len(nda.shape)>2 : return nda
01331 shape = self.shape()
01332 if shape is not None : nda.shape = shape
01333 return nda
01334
01335
01336
01337 from time import time
01338
01339 if __name__ == "__main__" :
01340
01341 ds, src = _psana.DataSource('exp=cxif5315:run=169'), _psana.Source('DetInfo(CxiDs2.0:Cspad.0)')
01342
01343
01344 env = ds.env()
01345 cls = env.calibStore()
01346 evts = ds.events()
01347 evt = evts.next()
01348
01349 for key in evt.keys() : print key
01350
01351 det = PyDetectorAccess(src, env, pbits=255)
01352
01353 nda = det.pedestals(evt)
01354 print '\npedestals nda:', nda
01355 if nda is not None : print 'nda.dtype: %s nda.shape: %s' % (nda.dtype, nda.shape)
01356
01357 t0_sec = time()
01358 nda = det.raw_data(evt, env)
01359 print '\nPython consumed time to get raw data (sec) =', time()-t0_sec
01360
01361 print '\nraw_data nda:\n', nda
01362
01363 sys.exit ('Self test is done')
01364
01365