Persisting Pointers
|
||
Working groups |
Blessed plots and figures |
Approving new results and publications |
Approval web pages - new results |
Approval web pages - new publications |
Mu2e Acronyn Dictionary |
Fermilab Meeting Rooms |
Fermilab Service Desk |
ReadyTalk : Home |
ReadyTalk : Help |
ReadyTalk : Toll Free Numbers |
For Mu2e I propose a solution in which:
At present, the solution is not quite complete and it does require two extra steps on the part of the physicist-programmer. One extra step occurs when first creating the object; that will remain. The other extra step occurs when reading data from an event; this extra step will go away in a later version of the framework.
Consider an object representing a digitized waveform produced in MC processing; in general this will be produced from one or more StepPointMC objects. It is useful to record which StepPointMC objects contributed to each digitized waveform object. Each of the contributing StepPointMC objects can be described uniquely by specifying the data product in which it is found and the offset, or index, within that data product. So a single precursor can be described by a class like,
struct DPIndex{ ProductID id; std::size_t index; };where ProductId is provided by the framework and is just a few ints. So a DPIndex is a POD and may be persisted. A general set of precursors, possibly coming from different data products, can be described by:
std::vector<DPIndex> precursors;In the general case, the precursor objects might come from different data products; this could happen if we merge StepPointMC objects from two files, perhaps some from a signal file and some from a cosmic ray file. In such a case, a given digi might result from the overlap of a signal track and a background track.
The following shows a fragment of what a digitized waveform class might look like if we did not have to worry about persisting pointers:
struct DigiWaveform{ StrawIndex strawIndex; // Straw identifier unsigned short timestamp; // Timestamp at the start of the first bin. std::vector<unsigned short> adc; // Pulseheights in 10 ns bins. std::vector<StepPointMC const*> stepPointMCs; // Pointers to precursors. DigiWaveform( StrawIndex s, unsigned short t, std::vector<unsigned short> const& a, std::vector<StepPointMC const*> const& p): strawIndex(s), timestamp(t), adc(a), stepPointMCs(p) { } };But we do have to persist pointers. The following shows a fragment of a digitized waveform class that uses DPIndex to persist pointers.
struct DigiWaveform{ // Persistent data. StrawIndex strawIndex; // Straw identifier unsigned short timestamp; // Timestamp at the start of the first bin. std::vector<unsigned short> adc; // Pulseheights in 10 ns bins. std::vector<DPIndex> stepPointIndices; // The StepPointMC objects that contributed to this. // Need some accessors for the private data. private: // This data is not persisted but can be recovered as needed. // On readback, the bool is intialized to false and the vector to empty. mutable bool pointersValid; mutable std::vector<StepPointMC const*> stepPointMCs; };So far it's pretty simple. Why are the private data members mutable? User code has only const access to the data products. So non-mutable data can never be changed. We want to be able to rebuild the pointers as needed so they must be mutable; similarly the validity flag needs to be able to change. We should never make public, persitable data mutable because that breaks the audit trail provided by the provenance.
Adding some constructors and accessors makes the class much, much busier. But the extra code is mostly boilerplate that will not change much from one persistent class to the next. A more complete fragment is below:
struct DigiWaveform{ // Persistent data. StrawIndex strawIndex; // Straw identifier unsigned short timestamp; // Timestamp at the start of the first bin. std::vector<unsigned short> adc; // Pulseheights in 10 ns bins. std::vector<DPIndex> stepPointIndices; // The StepPointMC objects that contributed to this. // One constructor. DigiWaveform( StrawIndex s, unsigned short t, std::vector<unsigned short> const& a, std::vector<StepPointMC const*> const& p, edm::Handle<StepPointMCCollection>& c): strawIndex(s), timestamp(t), adc(a), stepPointMCs(p), pointersValid(true), { // construct stepPointIndices from p and c. } // A second constructor. DigiWaveform( StrawIndex s, unsigned short t, std::vector<unsigned short> const& a, std::vector<DPIndex> const& idx, edm::Event const *event = 0 ): strawIndex(s), timestamp(t), adc(a), stepPointIndices(idx), pointersValid(false), stepPointMCs() { if ( event ){ // construct stepPointMCs from stepPointIndices and the event. } } // Accessor for the pointers. std::vectorSome comments on this:const& getStepPointMCs( edm::Event const& event) const{ if ( pointersValid ) return stepPointMCs; // Fill the pointers. resolveDPIndices<StepPointMCCollection>( event, stepPointIndices, stepPointMCs); return stepPointMCs; } // A second accessor that does not need an event but might throw. std::vector const& getStepPointMCs() const{ if ( pointersValid ) return stepPointMCs; throw ...; } // A safety checker, should be rarely needed. bool pointersOK() const { return pointersValid; } private: // This data is not persisted but can be recovered as needed. // On readback, the bool is intialized to false and the vector to empty. mutable bool pointersValid; mutable std::vector<StepPointMC const*> stepPointMCs; };
The class CrudeStrawHits contains several public data members that describe a crude hit in a straw. Since the main purpose of this class is to serve this data, they are public, not private. A crude straw hit can come from zero or more precusors. If a hit is just salt and pepper noise, it will not have any precursors. Right now we are making hits directly from StepPointMC objects and each CrudeStrawHit can come from one or more StepPointMC objects. In the future we will make CrudeStrawHit objects from unpacked digis and each CrudeStrawHit will come from exactly one unpacked digi object.
To allow a CrudeStrawHit to describe its precursors, the class contains two data members,
enum precursor_type { undefined, unpackedDigi, stepPointMC}; precursor_type precursorType; std::vectorA DPIndex is a class that contains two members, a ProductID and an int. The ProductID uniquely indentifies a data product in an event and the int is an index into the data product. The ProductIDprecursorIndices;
Security, Privacy, Legal |