1b. Adding User Data for production
Typical forms of userData
In addition to the points made above, there are a few more section to add if you are adding "userData" (reduced area detector data). SmallDataProducer_userData.py has examples for the most standard requests. Parameters that are important for the production (ROI boundaries, centers for azimuthal projections,...) are stored in the "UserDataCfg" subdirectory.
A most current example of a producer file that show how to add both "pre packaged" feature extraction as well as more free form user data can be found in github:
https://github.com/slac-lcls/smalldata_tools/blob/master/examples/SmallDataProducer_userData.py
The tool that helps you extract the parameters necessary for feature extraction is described here: 3. Configuring User Data using parameters from SmallDataAna_psana
Run dependent parameters:
First up are functions that will return e.g. the region-of-interest boundaries for each run. During the experiment, this should be kept up-to-date so if the setup changes, the littleData file will get an entry with new boundaries for a just finished range of runs. This way, the littleDataRun script will always use the correct region of interest for each run.
UserData: Roi definition
def getROIs(run, expname):
if run<=314:
sigROI = [[1,2], [85,120], [0,388]]
sigROI2 = [[1,2], [0,184], [30,315]]
else:
sigROI = [[1,2], [83,112], [0,388]]
sigROI2 = [[1,2], [0,184], [30,315]]
return sigROI, sigROI2
ROI: whole area
Below is an entry that show how to add a ROI on a cs140k detector to the littleData. the integral of the ROI and the center-of-mass values for the ROI will always be stored. WriteArea=True will cause the full ROI be written to the event.
User Data: small subarea
have_cs140_0 = checkDet(env, 'cs140_0')
if have_cs140_0:
cs140_0 = DetObject('cs140_0' ,env, int(run), name='vonHamos')
cs140_0.addROI('ROI',ROIs[0], writeArea=True, rms=cs140_0.rms)
cs14)
dets.append(cs140_0)
ROI: projection
For a second cs140 detector, we chose a larger ROI, but only save the projections in "x" and "y". Here the projection is done without any further treatment (first lines) and with a threshold of 25 ADU. A threshold using the noise of the pixel as determined in the pedestal run is also possible (use cutRMS = xx where xx is the number of noise RMS a pixel needs to be higher as)
UserData: projections of ROI
have_cs140_1 = checkDet(env, 'cs140_1')
if have_cs140_1:
cs140_1 = DetObject('cs140_1' ,env, int(run), name='Rowland')
cs140_1.addROI('ROI',ROIs[1], rms=cs140_1.rms)
cs140_1.ROI.addProj('_x', axis=0)
cs140_1.ROI.addProj('_y', axis=1)
cs140_1.ROI.addProj('_ythres', axis=1, singlePhoton=False, cutADU=25.)
cs140_1.ROI.addProj('_xthres', axis=0, singlePhoton=False, cutADU=25.)
dets.append(cs140_1)
Azimuthal Integration
Another option is to reduce the data by azimuthally averaging the signal. Here, we need to know the center for the integration as well as the detector distance and beam energy. The latter two are mostly important for the q-values of the bins that will also be stored in the littleData. As conditions will change during an experiment, it is convenient to have a function that return the correct integration setup for each (range of) run(s).
run dependent integration parameters
def getAzIntParams(run):
ret_dict = {'eBeam': 8.015}
ret_dict['cspad_center'] = [87697.946016760892, 94865.383526655729]
ret_dict['cspad_dis_to_sam'] = 110.
return ret_dict
UserData: azimuthal integration
haveCspad = checkDet(ds.env(), 'cspad')
if haveCspad:
cspad = DetObject('cspad' ,ds.env(), int(run), name='cspad')
for iROI,ROI in enumerate(ROIs):
cspad.addROI('ROI_%d'%iROI, ROI)
cspad.azav_eBeam=azIntParams['eBeam']
if azIntParams.has_key('cspad_center'):
cspad.azav_center=azIntParams['cspad_center']
cspad.azav_dis_to_sam=azIntParams['cspad_dis_to_sam']
try:
cspad.addAzAv(phiBins=7)
except:
pass
dets.append(cspad)
Binned Image
You can store a "thumbnail" version of the whole image (or an ROI) if you do not need the full solution. You can pass the size of the desired ROI (one number will result in a square image).
Binned Data
have_cs140_1 = checkDet(env, 'cs140_1')
if have_cs140_1:
cs140_1 = DetObject('cs140_1' ,env, int(run), name='Rowland')
cs140_1.addROI('ROI',ROIs[1])
shape=200 #shape=[100,200] is also possible
cs140_1.ROI.addRebin(shape)
dets.append(cs140_1)
Droplet algorithm/Photon finding
Instead of storing all pixels, you can also run droplet reconstruction. You can either store the droplets or break them down in a list of single photons (the latter requires all photons to be of the same energy). This is useful if you have a low hit rate, care about sub-pixel position resolution for detectors where photons leave energy in >1 pixel (e.g. the EPIX) or would like to use deduce the energy of the incident photon and thus need to combine energy from all pixels that stem from the same photon.
The droplet algorithm and its parameters will be described in more detail later.
Droplet
epixnames = ['epix_vonHamos']
dets=[]
for iepix,epixname in enumerate(epixnames):
have_epix = checkDet(ds.env(), epixname)
if have_epix:
print 'creating epix detector object for epix ',epixname
epix = DetObject(epixname ,ds.env(), int(run), name=epixname,common_mode=46)
epix.addDroplet(threshold=10., thresholdLow=3., thresADU=0.,name='droplet')
epix['droplet'].addAduHist([0.,1500.])
epix['droplet'].addDropletSave(maxDroplets=nDrop[iepix])
dets.append(epix)