Issues
- how will AMI elegantly handle dict/list attributes?
- how will AMI elegantly handle complex types like the list of times/peaks from the hsd fex (or even values/times from hsd raw)? Maybe stick to raw hsd data in AMI for now?
Proposal
Proposal | Arguments In Favor | Argument Against |
---|---|---|
Data shall be accessible with a syntax like: det = run.Detector('xppcspad') det.datatype.attr1.attr2.method(evt) | passing in event at lowest level means Detector object can be reused for many different events | |
Unlike LCLS1, the Detector interface should be used only to access per-event data, not per-run data like calibration constants | Cleaner separation of classes | Need to implement separate interface for calibration access that also takes detector name as its principal argument |
The object returned by the Detector constructor shall only need information from the run's configure transition (using the software/version information) and shall be tab-completable in ipython so users can explore the object. | ||
The object returned by Detector will have static attributes/methods (i.e. not event dependent). | Simpler for users to explore and check for missing data | Doesn't reflect the dynamic nature of the data (e.g. raw data only rarely present) |
"datatype" above corresponds to a detector interface class (e.g. "raw", "fex", "roi1") currently in psana/psana/detector/detectors.py. attr1/attr2 are used for the various fields supported by that data type (e.g. for an roi data-type, this might be the roi data, and the "corners" of the roi for that particular event). | ||
The lowest-level "method(evt)" must return None if the data is not accessible for any reason (e.g. missing detector, missing raw data, missing calibration constants). We should create a mechanism for the user to discover the reason why the data is missing. | makes user code simpler to check for missing information | |
"evt" is the only allowed argument for "method(evt)" and is mandatory. If a method doesn't use "evt", then it is an indication that it shouldn't be part of the Detector interface. | AMI ease-of-use | |
"method(evt)" shall return a fundamental type (int, float, numpy array) or a dict/list of fundamental types (e.g. for HSD chan(evt) will return a dict with key corresponding to the channel numbers). There are also more complex data not covered by these cases: e.g. xpphsd.fex.chan[0] returns a list of (times, peaks) which is a "complex type" that would need special handling in AMI. | ||
A psana-python detector interface class name must follow the naming convention "dettype_drpalg_major_minor_micro", e.g. (cspad_raw_2_3_42) | ||
If a detector interface needs a "channel number" concept, that channel number shall be a pair consisting of (segment, channel) and shall be used with the lowest-level attributes, e.g. hsd.waveforms(evt)[segment][channel] | Allows multiple segments to have for example, channel 0. |
Implementation (Schematic)
In psana, the detector interface is constructed roughly like the following:
class Container: def __init__(self): pass class mybase(DetectorImpl): def calib(self): return mikhails_calib_works_with_both_rois_and_daq(self.raw()) class epix10k_daq_0_0_1(mybase): def __init__(self): super().__init__() class epix10k_rois_0_0_1(mybase): def __init__(self): super().__init__() det = Container() setattr(det,'daq',epix10k_daq_0_0_1()) setattr(det,'rois',epix10k_rois_0_0_1()) det.daq.calib() det.rois.calib()
Scans and Epics
See this page for some Detector Interface behavior: Raw Data Python Interface
Area Detector Brainstorming (AreaDetector)
Jan. 29, 2019
Aug. 4, 2020 (cpo, Mikhail, Valerio)
- det = run.Detector(det_name)
- det.raw.raw(evt) returns 2D array for single-segment detectors, dict for multi-segment detectors. key is panel number (integer). similarly for det.raw.calib(evt)
- have a flag if we want to return single-segment detectors as a dict as well (e.g. for uniformity in psocake)
- maybe image(evt, array=array) should be an algorithm? det.raw.image(evt,array=None)? or could split det.raw.image(evt), det.raw.image(array=array)? ideally shouldn't have to pass evt.
- get_calib_const(det_name, timestamp or run or evt). Mikhail suggests we should consider det.get_calib_const(timestamp or run or evt). cpo believes it should be separate from the detector interface (unlike LCLS1)
- flexible number of segments (no hardwired "32" segments for a cspad). e.g. a "full detector" may have segments 2,3,4,7,8,9. one run may have segments 3,4,7 another run may have segments 2,3,8,9
- calibration data must be taken and stored with all segments in the "full detector" (i.e. 2,3,4,7,8,9)
- try to use same common-mode algorithm for all detectors (stripes/banks). multiple passes needed for different directions. (e.g. Jungfrau and epix are currently same)
- default geometries for single panel detectors
- what do do about ROIs (future problem)?
- dict approach similar to det.raw.raw() multi-segment detectors could also be used for ROIs
- ROIs also need the information about the "corner" of the ROI
- software ROIs are really "feature extracted" data i.e. instead det.raw.image() it's det.fex.image()
- hardware ROIs should be handled in a manner similar to hsd
- how do we reuse the python code in the DRP which is multi-threaded C++? cpo suggests maybe we have a python multi-process DRP. another labor-intensive option is supporting multi-threaded C++. or write C++ and wrap with python (was complicated for the hsd, but perhaps just because we needed to avoid 1MHz malloc)
- DRP will have to work on one or more segments of a full detector (in units of panels). this is why it's important that the detector interface be very flexible with the panels it processes (e.g. for det.calib())
- epix/jungfrau offsets should be handled uniformly: like the Jungfrau so they can be changed without redeploying pedestals
- all python methods of an area detector should start with "_" except raw(),calib(),image() because we want to keep the ami interface simple.
2020-09-04 Proposal for Detector interface from Mikhail
- have an option to create detector object directly, outside run
det = Detector(detname)
advantage- OO design: object detector physically exists without run
- reduce redundant dependences
- have an option to work with info from calibration db - pixel geometry, imaging of constans like pedestals, gains, masks, pixel_status.
- eliminate forks for duplication of code in
data = det.raw.raw(evt)
data = det.fex.raw(evt)
replace it with det.raw(evt)
The same is valid for det.calib() and det.image()
2020-09-08 Proposal for Geometry from Valerio
Geometry package for psana: psgeom or PSCalib
- psgeom:
- Pros:
Clean and modern interface
Clean and nice coding style
- Cons:
No single true internal geometry representation
Main mantainer not working at LCLS (!!!)
- Pros:
- PSCalib.GeometryAccess:
- Based on the content of this page Detector Geometry
Pros:
True internal representation of the geometry
Better integration with the rest of psana
Maintained and developed at LCLS (!!!)
Cons:
Interface is often not very Pythonic (example: vebosity bits)
Documentation could be more accessible
- psgeom:
Proposal: I propose that we make PSCalib the default geometry package for psana
Geometry Interface improvement proposals (Work in progress):
Expose the bit flags in various functions as Python bool flags - NOTE: maybe already fixed in LCLS2
Do not require parameters that are not strictly needed (for clarity)
Example: det.daq.image(evt,array=None) could be det.daq.image(evt) or det.daq.image(array), either with two separate functions or with different behavior depending on the input data
Use more descriptive names for some parameters. Examples: oname, oindex, vbase, etc.
Make documentation more accessible (use one of the standard for docstrings?) - NOTE: maybe already fixed in LCLS2
All this can be accomplished with wrappers, without breakage
I volunteer to do that, of course