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)