Last significant change: 2004/03/11
plexus (plek'sus) n. pl. -us or -us
es. Anat. A structure in the form of a network, esp. of nerves, blood vessels, or lymphatics: the solar plexus. [
Lat., p.p. of plectere, to plait.]
The Plex package provides services for managing the logical connection between elements of the detector above the physical level. Thus it is not concerned with the placement of physical scintillator strips and steel sheets in 3-space, but instead is responsible for providing the navigation from strips to fibers to pixel spots to pixels (anodes) to photomultiplier tube and so forth. It allows reverse navigation as well (e.g. one-to-many as well as many-to-one).
A connection map representing one of the detectors is valid for a particular time and may evolve as components are added or re-configured (e.g. to correct a mis-cabling). Thus instantiating a plexus must involve constructing it for a particular detector at a particular time in its existence - a plexus will be constructed that has a time range that covers the requested time. The underlying mapping information will come from the database.
Diagram 5.1 is a schematic sketch of some of the detector components and how they relate. Figure 5.2 is an illustrative (i.e., non-authoritative) representation of the same concepts as seen from a UML5.1perspective.
The user does not work directly with a Plexus object, but instead works through a PlexHandle. These PlexHandles are lightweight proxy objects that do little work of any substance. During the creation of a PlexHandle a loan pool of real Plexus objects searched for an appropriate object; if no match exists one will be created. The PlexHandle then forwards member function calls to the correct Plexus. This allows the PlexHandle to share the larger underlying collection of information and it lowers the overhead of the creation and deletion of PlexHandles.
This approach also allows the PlexHandles to be created on the stack and thus avoids a common source of memory leaks. The lookup procedure is so fast that users should not be concerned with (or even attempt) to retain a handle, but rather should construct one from a VldContext whenever one is needed.
#include "RawData/RawRecord.h"
#include "Plex/PlexHandle.h"
// somehow acquire a raw record, perhaps:
RawRecord *rawrec = (RawRecord*) (mom->GetFragment("RawRecord"));
// retrieve a copy of the VldContext object identifying the configuration
VldContext vldc = rawrec->GetRawHeader()->GetVldContext();
// create a PlexHandle (on the stack)
PlexHandle ph(vldc)
[....]
// work with PlexHandle and it gets automagically destroyed
// when the code block ends, but the next invocation is
// likely to acquire the same underlying Plexus without
// significant overhead.
// PlexLoanPool is a CfgConfigurable
PlexLoanPool* plpool = PlexLoanPool::Instance();
plpool->Set("...");
plpool->Set("...");
plpool->Update();
On startup the interface checks the environmental variable ENV_PLEX
which can contain a semi-colon separated list of configuration requests,
e.g.:
setenv ENV_PLEX "MaxUnref=2; Cache='/tmp/myplex.cache'; CacheWrite=0"One can also show the current status of the PlexLoanPool using:
PlexLoanPool::Instance()->Print();which gives something like:
"PlexLoanPool Configuration", 3 entries. keys unlocked, values unlocked
Cache = ''
CacheWrite = 1
MaxUnref = 1
--- Shared PlexLoanPool ---
Plexus has 1 references
|CalDet|Data|
2001-07-24 00:00:04.000000000Z
2001-08-06 00:00:00.000000000Z
from source: , From Database
--- Private PlexLoanPool ---
End of PlexLoanPool
Nevertheless, it is sometime useful. This behavour can be enabled by setting the Cache config variable to the name of the root file to use. One then runs the job once to build the necessary plex from the database and the job will write the file upon teardown of the PlexLoanPool at job end. Subsequent jobs will then read the cached file and can avoid the re-writing overhead by setting the CacheWrite config value to zero.
The most frequently encountered identifier is a PlexStripEndId. This identifies a logical scintillator strip-end; it encapsulates identifiers for the physical detector, plane, strip-in-plane it refers to. It also, when meaningful, identifies which end of the strip in the case of two-sided readout. The components can be extracted via Get methods. It derives from PlexPlaneId, so some of the Get methods are implemented there. The most common comparisons to other PlexStripEndIds are available via methods in the class:
#include "MessageService/MsgService.h"
#include "Plex/PlexStripEndId.h"
PlexStripEndId seid = [...]
PlexStripEndId another = [...]
// decompose PlexStripEndId into components
DetectorType::Detector_t detector = seid.GetDetector();
PlaneView::PlaneView_t view = seid.GetPlaneView();
UShort_t plane = seid.GetPlane();
UShort_t strip = seid.GetStrip();
StripEnd::StripEnd_t end = seid.GetEnd();
// seid.Print() might yield "[ Far| 2 Ut|123|*E]"
// for the far detector, plane 2 (U view, Total coverage),
// strip 123, whole strip, east end.
// these tests should output exactly one message
if ( ! seid.IsSameStrip(another) )
MSG("XXX",Msg::kInfo) << " not the same (detector,plane,strip)" << endl;
if ( seid.IsSameStripEnd(another) )
MSG("XXX",Msg::kInfo) << " same (detector,plane,strip,end)" << endl;
if ( seid.IsOppositeStripEnd(another) )
MSG("XXX",Msg::kInfo) << " same (detector,plane,strip) && different (end)" << endl;
}
An unexceptional list will normally have a consistent plane number and strip end enumeration and so GetPlane() and GetEnd() are generally well defined operations. It is conceivable that a miscabling could mix signals from different planes so that the mapping from RawChannelId to a list of PlexStripEndIds can't give a unique answer, but currently that isn't handled other than to note, as a printed warning, the exception.
The PlexSEIdAltL is a STL5.2 vector of PlexSEIdAltLItems each of which represent an alternative PlexStripEndId and associated fields. The associated data includes the PlexPixelSpotId (distinguishes pixel spots for the far and different pixels for the near spectrometer); the assigned weight; and when generated in conjunction with real digitization information, some calibration corrected quantities, such as photo-electrons, strip-to-strip corrected signal and times.
#include "Plex/PlexHandle.h"
#if !defined(__CINT__) || defined(__MAKECINT__)
#include "MessageService/MsgService.h"
CVSID("$Id: plexus.tex,v 1.7 2004/06/14 19:38:45 west Exp $");
#else
#include <iostream>
using namespace std;
#define MSG(a,b) cout
#endif
void plex_tutor()
{
Detector::Detector_t det = Detector::kFar;
VldContext vldc(det,SimFlag::kData,VldTimeStamp());
PlexHandle ph(vldc);
PlexStripEndId seid(det,1,0,StripEnd::kEast);
RawChannelId rcid = ph.GetRawChannelId(seid);
PlexSEIdAltL alt = ph.GetSEIdAltL(rcid);
// loop over alternatives assigning increasing weights
for (unsigned int i=0; i < alt.size(); ++i) {
alt[i].SetWeight(i);
}
alt.Print();
// retrieve values for the entry with the largest weight
// the iterator cursor is left unchanged
PlexStripEndId best_seid = alt.GetBestSEId();
Float_t best_wgt = alt.GetBestWeight();
MSG("test",Msg::kInfo)
<< "Best " << best_seid << " weight " << best_wgt << endl;
// Iteration using SetFirst()/Next(), SetLast()/Previous()
// is now deprecated along with all the methods involving the
// word "Current". PlexSEIdAltL is a STL vector and CINT has
// full access to its STL methods.
// iterate forward, retrieve each value in turn
alt.SetFirst();
while ( alt.IsValid() ) { // while the cursor is still in range
PlexStripEndId seid = alt.GetCurrentSEId();
Float_t wgt = alt.GetCurrentWeight();
MSG("test",Msg::kInfo) << seid << " had weight " << wgt << std::endl;
alt.Next();
}
// iterate backwards
alt.SetLast();
while ( alt.IsValid() ) {
alt.SetCurrentWeight(alt.size()-alt.GetCurrentWeight());
alt.Previous();
}
}
The ordering of entries initially follows the order in which they were entered into the list. The list can be sorted by weight value but this must be via an explicit method call so as not to confuse iteration.
One can set all the weights to zero using ClearWeights(). The individual weight for the ``current'' position of the iterator cursor can be adjusted via SetCurrentWeight() or AddToCurrentWeight().
There is one method, AddStripEndId(), for adding to the list of strip-end, weight pairs but this is the purview of the plexus itself and isn't a normal operation for the user. The user of the list though may wish to delete selected entries and a variety of such facilities are provided:
// iterate *backwards*, remove various values
// testing each and skipping none
alt.SetLast();
while ( alt.IsValid() ) {
[...]
if (bad_choice) alt.DropCurrent();
alt.Previous();
}
The Plex can be queried by RawChannelId as to which ReadoutType
(see Section
) is generating data on that channel.
For readout types other than kScintStrip, kPinDiode and
kVACommonMode this information is given to the Plex via the
PLEXRAWCHANNELREADOUTTYPE table in the database, which should be
kept up-to-date whenever special channels are rewired. The READOUTNAME
column should start with the appropriate readout type name, but can
have appended to it any useful descriptive text.
Since, for some of these special readouts, there might be multiple channels of this special type one can use the extra information in the READOUTNAME to select specific instances. Thus given:
RawChannelId READOUTNAME ReadoutTypeone can look up a specific special channel via:
C:V--:0x00:1524 'FlashTrigPMT' kFlashTrigPMT
C:V--:0x00:05b0 'CerenkovAdc1' kCerenkov
C:V--:0x00:0590 'CerenkovAdc2' kCerenkov
C:V--:0x00:05d0 'CerenkovAdc3' kCerenkov
C:V--:0x00:1602 'TOFAdc1' kTOF
C:V--:0x00:1590 'TOFAdc2' kTOF
C:V--:0x00:15b0 'TOFAdc3' kTOF
RawChannelId rcid = ... // special channel...or not
// get the readout type
ReadoutType::Readout_t rtype = ph.GetReadoutType(rcid);
if ( ReadoutType::ScintStrip != rtype &&
ReadoutType::PinDiode != rtype &&
ReadoutType::VACommonMode != rtype ) {
// not mundane, let's ask for more info
std::string descript = ph.GetSpecialDescript(rcid);
}
// look up the specific CerenkovAdc1 channel, if one is so labelled
RawChannelId ckv1 = ph.GetSpecialChannelContains("CerenkovAdc1");
The construction of the far detector veto shield is an ad hoc afterthought. As a consequence it suffers from a lack of regularity and consistency. The veto shield only uses C and E modules; but which is used where and in what orientation forms no regular pattern. And while all normal planes, once installed, never change their orientation this is not true for the veto shield. Additional confusion arises because a numbering scheme was used in entering the strip-to-pixel mapping that lumps together modules in different orientations, in effect having non-planar ``planes''. Since a PlexPlaneId (and a PlexStripEndId which derives from it) are supposed to support the concept of asking for a PlaneView::PlaneView_t, this leads to ambiguity.
|
|