In Run 18 planned on Aug 2019 the new single-piece 4M Jungfrau detector is going to be used with a couple of controllers. In daq and psana it will be seen as two independent detectors, i.e. MfxEndstation.0:Jungfrau.0 and 1. It seems natural to process data of these two detectors as a single piece. To make it feasible class AreaDetectorCompound was developed with functionality as explained in this note.
Class AreaDetectorCompound constructor receives as input parameter a list of detector names which need to be processed together. From this list it generates a list of AreaDetector objects, which is used to wrap most of AreaDetector interface methods. Wrapping methods concatenates numpy arrays for the 3-rd to last index, assuming that two last index describes 2-d AreaDetector. This type of concatenation can be done for identical two last indexes, e.g. for Jungfrau
raw or calib arrays: (2, 512, 1024) (+) (1, 512, 1024) (=) (3, 512, 1024) pedestals, gain and offset: (3, 2, 512, 1024) (+) (3, 1, 512, 1024) (=) (3, 3, 512, 1024) |
raw, calib, pedestals, rms, gain, offset, bkgd, status, mask, photons,
coords_x, coords_y, coords_z,
indexes_x, indexes_y, indexes_z,
common_mode_correction, common_mode_apply,
mask_geo, mask_comb, mask_edges, mask_neighbors, mask_calib,
datast, status_as_mask, gain_mask, gain_mask_non_zero, areas
coords_xy, indexes_xy, indexes_xy_at_z
list_raw, list_calib, list_shape, list_size, list_ndim, list_common_mode, list_geometry
common_mode
- returns array of the common mode parameters
Detector interface provides for user uniform access to any detector data and hides specific detector complexity. The same is valid for compound detector. There is a couple of differences too keep in mind.
There are a few options of the detector object initialization usyng class AreaDetectorCompound
directly or through the standard Detector
factory.
Detector
is a standard wrapper for all LCLS detectors including AreaDetectorCompound. Compound detector object can be created usind generic Detector
, e.g.
import psana # DataSource object MUST be defined before Detector. ds = psana.DataSource(dsname) # i.e. dsname='exp=xpptut15:run=460' det = psana.Detector(<str-or-list-of-derector-names>) |
Example of direct AreaDetectorCompound
object initialization:
from Detector.AreaDetectorCompound import AreaDetectorCompound det = AreaDetectorCompound(<str-or-list-of-derector-names>, env) |
Parammeter <str-or-list-of-derector-names>
can be the space separated string of detector names prepended by keyword 'compound'
, e.g.
'compound MecTargetChamber.0:Cspad2x2.1 MecTargetChamber.0:Cspad2x2.2 MecTargetChamber.0:Cspad2x2.3' |
or just a list of detector names, e.g.
['MecTargetChamber.0:Cspad2x2.1', 'MecTargetChamber.0:Cspad2x2.2', 'MecTargetChamber.0:Cspad2x2.3'] |
Second parameter, env = ds.env()
, is mandatory for AreaDetectorCompound
and is optional for Detector
(passed from DataSource
initialization).
### Direct usage: # from Detector.AreaDetectorCompound import AreaDetectorCompound # det = AreaDetectorCompound(..., env) import psana from Detector.GlobalUtils import print_ndarr ds = psana.DataSource('exp=xpptut15:run=460') # Make Detector object using: # space separated string of detector names prepended by 'compound': det = psana.Detector('compound MecTargetChamber.0:Cspad2x2.1'\ ' MecTargetChamber.0:Cspad2x2.2'\ ' MecTargetChamber.0:Cspad2x2.3') # or list of string detector names: det = psana.Detector(['MecTargetChamber.0:Cspad2x2.1',\ 'MecTargetChamber.0:Cspad2x2.2',\ 'MecTargetChamber.0:Cspad2x2.3']) env = ds.env() evt = ds.events().next() rnum = evt.run() if True : print 'rnum :', rnum print 'calibdir :', str(env.calibDir()) print 'size :', str(det.list_size(evt)) print 'shapes :', str(det.list_shape(evt)) print 'ndims :', str(det.list_ndim(evt)) raws = det.list_raw(evt) for nda in raws : print_ndarr(nda, name='-- per det list_raw', first=0, last=5) raw = det.raw(evt) print_ndarr(raw, name='raw as nda', first=0, last=5) calib = det.calib(evt) print_ndarr(calib, name='calib', first=0, last=5) xy0_offset = (550,550) img_raw = det.image(evt, nda_in=raw, xy0_off_pix=xy0_offset) #img_calib = det.image(evt, nda_in=calib, xy0_off_pix=xy0_offset) #img_at_z = det.image_at_z(evt, zplane=500000, nda_in=raw, xy0_off_pix=xy0_offset) if True : # True or False for to plot image or not from pyimgalgos.GlobalGraphics import plotImageLarge, show img = img_raw plotImageLarge(img, title='img as %s' % str(img.shape), amp_range=(0,5000)) show() |
img = det.image(evt, nda_in=raw, xy0_off_pix=xy0_offset) img = det.image_at_z(evt, zplane=500000, nda_in=raw, xy0_off_pix=xy0_offset) |
det.image - generates image in the "detector plane" assuming all detector sensors are in the same plane
det.image_at_z - projects intensities from each detector to the plane orthogonal to the beam with specified z coordinate relative to IP.
Compound detector image examples for three cspad2x1 from exp=xpptut15:run=460 and 1M and 512k Jungfrau from exp=mfxls4916:run=298
/reg/d/psdm/xpp/xpptut15/calib/CsPad2x2::CalibV1/MecTargetChamber.0:Cspad2x2.1/geometry/460-460.data /reg/d/psdm/xpp/xpptut15/calib/CsPad2x2::CalibV1/MecTargetChamber.0:Cspad2x2.2/geometry/460-460.data /reg/d/psdm/xpp/xpptut15/calib/CsPad2x2::CalibV1/MecTargetChamber.0:Cspad2x2.3/geometry/460-460.data |
The last line of each file is responsible for clpad2x1 position and rotation, i.e
IP 0 CSPAD2X2:V1 0 0 0 1000000 120 0 0 0.00000 0.00000 0.00000 |
See Detector Geometry for detail.
Until release grater than ana-1.4.6 is available
ssh -Y pslogin.slac.stanford.edu ssh -Y psana . /reg/g/psdm/etc/psconda.sh source conda_setup --reldir /reg/neh/home/dubrovin/LCLS/con-ana-1.4.6 python /reg/neh/home/dubrovin/LCLS/con-ana-1.4.6/Detector/examples/ex_AreaDetectorCompound.py 3 # or other test # from 1 to 5. |