Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
THaDetectorBase.cxx
Go to the documentation of this file.
1//*-- Author : Ole Hansen 15-Jun-01
2
4//
5// THaDetectorBase
6//
7// Abstract base class for a detector or subdetector.
8//
9// Derived classes must define all internal variables, a constructor
10// that registers any internal variables of interest in the global
11// physics variable list, and a Decode() method that fills the variables
12// based on the information in the THaEvData structure.
13//
15
16#include "THaDetectorBase.h"
17#include "THaDetMap.h"
18#include "THaEvData.h"
19#include "TMath.h"
20#include "VarType.h"
21#include "TRotation.h"
22
23#include <sstream>
24#include <stdexcept>
25
26using namespace std;
27
28//_____________________________________________________________________________
30 const char* description ) :
31 THaAnalysisObject(name,description),
32 fDetMap(new THaDetMap),
33 fNelem(0),
34 fNviews(1),
36 fXax(1.0,0.0,0.0),
37 fYax(0.0,1.0,0.0),
38 fZax(0.0,0.0,1.0)
39{
40 // Normal constructor. Creates a detector with an empty detector map.
41}
42
43//_____________________________________________________________________________
45 fDetMap(nullptr), fNelem(0), fNviews(1), fSize{kBig,kBig,kBig}
46{
47 // for ROOT I/O only
48}
49
50//_____________________________________________________________________________
52{
53 // Destructor
55 delete fDetMap;
56}
57
58//_____________________________________________________________________________
60{
61 // Clear event-by-event data in fDetectorData objects
63
64 for( auto& detData : fDetectorData ) {
65 detData->Clear(opt);
66 }
67}
68
69//_____________________________________________________________________________
71{
72 // Clear event-by-event data and calibration data in fDetectorData objects
73 Clear(opt);
74
75 for( auto& detData : fDetectorData ) {
76 detData->Reset(opt);
77 }
78}
79
80//_____________________________________________________________________________
82{
83 // Define detector orientation, assuming a tilt by rotation_angle (in rad)
84 // around the y-axis
85
86 fXax.SetXYZ( 1.0, 0.0, 0.0 );
87 fXax.RotateY( rotation_angle );
88 fYax.SetXYZ( 0.0, 1.0, 0.0 );
90
91}
92
93//_____________________________________________________________________________
95{
96 // Default method for getting the readout number of a detector element
97 // from the hardware channel given in 'hitinfo'. The the detector map is
98 // assumed to be organized in groups of fNelem consecutive channels
99 // corresponding to each view.
100 //
101 // For example, a detector may have 6 elements (e.g. paddles), each with two
102 // readouts, one on the right side, the other on the left, for a total of
103 // 12 channels. The detector map should then specify the 6 right-side
104 // channels first, followed by the 6 left-side channels (or vice versa).
105 //
106 // Derived classes may implement other schemes, for example alternating
107 // left/right channels.
108 //
109 // Throws an exception if the view number exceeds the number of defined
110 // views (fNviews).
111
112 if( fNelem == 0 ) return 0; // don't crash if unset
113 Int_t view = hitinfo.lchan / fNelem;
114 if( view < 0 || view >= fNviews ) {
115 ostringstream msg;
116 msg << "View out of range (= " << view << ", max " << fNviews << "). "
117 << "Should never happen. Call expert.";
118 throw logic_error(msg.str());
119 }
120 return view;
121}
122
123//_____________________________________________________________________________
124Int_t THaDetectorBase::FillDetMap( const vector<Int_t>& values, UInt_t flags,
125 const char* here )
126{
127 // Utility function to fill this detector's detector map.
128 // See THaDetMap::Fill for documentation.
129
130 Int_t ret = fDetMap->Fill( values, flags );
131 if( ret > 0 )
132 return ret;
133 if( ret == 0 ) {
134 Error( Here(here), "No detector map entries found. Check database." );
135 } else if( ret == -1 ) {
136 Error( Here(here), "Unknown hardware module number. "
137 "Check database or add module in THaDetMap.cxx." );
138 } else if( ret == -128 ) {
139 Error( Here(here), "Bad flag combination for filling "
140 "detector map. Call expert." );
141 } else if( ret < 0 ) {
142 Error( Here(here), "Invalid detector map data format "
143 "(wrong number of values). Check database." );
144 }
145 return ret;
146}
147
148//_____________________________________________________________________________
150{
151 // Convert coordinates of point 'p' from the detector to the track
152 // reference frame.
153
154 return TVector3( p.X()*fXax + p.Y()*fYax + p.Z()*fZax + fOrigin );
155}
156
157//_____________________________________________________________________________
159{
160 // Convert x/y coordinates in detector plane to the track reference frame.
161
162 return TVector3( x*fXax + y*fYax + fOrigin );
163}
164
165//_____________________________________________________________________________
167{
168 // Convert/project coordinates of the given 'point' to coordinates in this
169 // detector's reference frame (defined by fOrigin, fXax, and fYax).
170
171 TVector3 v = point - fOrigin;
172 // This works out to exactly the same as a multiplication with TRotation
173 return TVector3( v.Dot(fXax), v.Dot(fYax), v.Dot(fZax) );
174}
175
176//_____________________________________________________________________________
178{
179 // Check if given (x,y) coordinates are inside this detector's active area
180 // (defined by fSize). x and y MUST be given in coordinates of this detector
181 // plane, i.e. relative to fOrigin and measured along fXax and fYax.
182
183 return ( TMath::Abs(x) <= fSize[0] &&
184 TMath::Abs(y) <= fSize[1] );
185}
186
187//_____________________________________________________________________________
189{
190 // Check if given point 'point' is inside this detector's active area
191 // (defined by fSize). 'point' is first projected onto the detector
192 // plane (defined by fOrigin, fXax and fYax), and then the projected
193 // (x,y) coordinates are checked against fSize.
194 // Usually 'point' lies within the detector plane. If it does not,
195 // be sure you know what you are doing.
196
197 TVector3 v = TrackToDetCoord( point );
198 return IsInActiveArea( v.X(), v.Y() );
199}
200
201//_____________________________________________________________________________
203{
204 // Print out detector map.
205
206 fDetMap->Print( opt );
207}
208
209//_____________________________________________________________________________
211 Bool_t required )
212{
213 // Read this detector's basic geometry information from the database.
214 // Derived classes may override to read more advanced data.
215
216 const char* const here = "ReadGeometry";
217
218 vector<double> position, size, angles;
219 Bool_t optional = !required;
220 DBRequest request[] = {
221 { "position", &position, kDoubleV, 0, optional, 0,
222 "\"position\" (detector position [m])" },
223 { "size", &size, kDoubleV, 0, optional, 0,
224 "\"size\" (detector size [m])" },
225 { "angle", &angles, kDoubleV, 0, true, 0,
226 "\"angle\" (detector angles(s) [deg]" },
227 { nullptr }
228 };
229 Int_t err = LoadDB( file, date, request );
230 if( err )
231 return kInitError;
232
233 if( !position.empty() ) {
234 if( position.size() != 3 ) {
235 Error( Here(here), "Incorrect number of values = %lu for "
236 "detector position. Must be exactly 3. Fix database.",
237 position.size() );
238 return 1;
239 }
240 fOrigin.SetXYZ( position[0], position[1], position[2] );
241 }
242 else
243 fOrigin.SetXYZ(0,0,0);
244
245 if( !size.empty() ) {
246 if( size.size() != 3 ) {
247 Error( Here(here), "Incorrect number of values = %lu for "
248 "detector size. Must be exactly 3. Fix database.", size.size() );
249 return 2;
250 }
251 if( size[0] == 0 || size[1] == 0 || size[2] == 0 ) {
252 Error( Here(here), "Illegal zero detector dimension. Fix database." );
253 return 3;
254 }
255 if( size[0] < 0 || size[1] < 0 || size[2] < 0 ) {
256 Warning( Here(here), "Illegal negative value for detector dimension. "
257 "Taking absolute. Check database." );
258 }
259 fSize[0] = 0.5 * TMath::Abs(size[0]);
260 fSize[1] = 0.5 * TMath::Abs(size[1]);
261 fSize[2] = TMath::Abs(size[2]);
262 }
263 else
264 fSize[0] = fSize[1] = fSize[2] = kBig;
265
266 if( !angles.empty() ) {
267 if( angles.size() != 1 && angles.size() != 3 ) {
268 Error( Here(here), "Incorrect number of values = %lu for "
269 "detector angle(s). Must be either 1 or 3. Fix database.",
270 angles.size() );
271 return 4;
272 }
273 // If one angle is given, it indicates a rotation about y, as before.
274 // If three angles are given, they are interpreted as Euler angles
275 // following the y-convention, i.e. rotation about z, rotation about y',
276 // rotation about z''. The sign of a rotation is defined by the right-hand
277 // rule (mathematics definition): if the thumb points along the positive
278 // direction of the axis, the fingers indicate a positive rotation.
279 if( angles.size() == 1 ) {
280 DefineAxes( angles[0] * TMath::DegToRad() );
281 }
282 else {
283 TRotation m;
284 // For TRotation (and only TRotation, it seems), ROOT's definition of the
285 // sense of rotation seems to be the left-hand rule: "A rotation around a
286 // specified axis means counterclockwise rotation around the positive
287 // direction of the axis." But we define rotations by the right-hand rule,
288 // so we need to invert all angles.
289 m.SetYEulerAngles( -angles[0] * TMath::DegToRad(),
290 -angles[1] * TMath::DegToRad(),
291 -angles[2] * TMath::DegToRad() );
292 fXax.SetXYZ( m.XX(), m.XY(), m.XZ() );
293 fYax.SetXYZ( m.YX(), m.YY(), m.YZ() );
294 fZax.SetXYZ( m.ZX(), m.ZY(), m.ZZ() );
295 }
296 } else
297 DefineAxes(0);
298
299 return 0;
300}
301
302//_____________________________________________________________________________
303void THaDetectorBase::DebugWarning( const char* here, const char* msg,
304 UInt_t evnum )
305{
306 if( fDebug > 0 ) {
307 Warning( Here(here), "Event %d: %s", evnum, msg );
308 }
309}
310
311//_____________________________________________________________________________
313 const char* here )
314{
315 ostringstream msg;
316 msg << hitinfo.nhit << " hits on "
317 << (hitinfo.type == Decoder::ChannelType::kADC ? "ADC" : "TDC")
318 << " channel "
319 << hitinfo.crate << "/" << hitinfo.slot << "/" << hitinfo.chan;
320 ++fMessages[msg.str()];
321
322 DebugWarning(here, msg.str().c_str(), hitinfo.ev);
323}
324
325//_____________________________________________________________________________
327 const char* here )
328{
329 ostringstream msg;
330 msg << "Failed to load data for "
331 << (hitinfo.type == Decoder::ChannelType::kADC ? "ADC" : "TDC")
332 << " channel "
333 << hitinfo.crate << "/" << hitinfo.slot << "/" << hitinfo.chan
334 << ". Skipping channel.";
335 ++fMessages[msg.str()];
336
337 DebugWarning(here, msg.str().c_str(), hitinfo.ev);
338}
339
340//_____________________________________________________________________________
342{
343 // Define variables. Calls DefineVariables for all objects in fDetectorData
344
346 if( ret )
347 return ret;
348
349 for( auto& detData : fDetectorData )
350 if( (mode == kDefine) xor detData->IsSetup() )
351 detData->DefineVariables(mode);
352
353 return kOK;
354}
355
356//_____________________________________________________________________________
358{
359 // Read database. Resets all objects in fDetectorData
360
362 if( status != kOK )
363 return status;
364
365 for( auto& detData : fDetectorData )
366 detData->Reset();
367
368 return kOK;
369}
370
371//_____________________________________________________________________________
373{
374 // Put decoded frontend data into fDetectorData. Used by Decode().
375 // hitinfo: channel info (crate/slot/channel/hit/type)
376 // data: data registered in this channel
377
378 for( auto& detData : fDetectorData ) {
379 if( !detData->HitDone() )
380 detData->StoreHit(hitinfo, data);
381 }
382
383 return 0;
384}
385
386//_____________________________________________________________________________
388 const DigitizerHitInfo_t& hitinfo )
389{
390 // Default method for loading the data for the hit referenced in 'hitinfo'.
391 // Callback from Decode().
392
393 return evdata.GetData(hitinfo.crate, hitinfo.slot, hitinfo.chan, hitinfo.hit);
394}
395
396//_____________________________________________________________________________
398{
399 // Generic Decode method. It loops over all active channels (= hit) in
400 // 'evdata' that are associated with this detector's detector map.
401 // For each hit, the following callbacks are made:
402 //
403 // LoadData(evdata,hitinfo): Returns data for the 'hitinfo' channel
404 //
405 // StoreData(hitinfo,data): Save data in member variables
406 //
407 // The default LoadData and StoreData may be enough for simple detectors.
408 // The default StoreData sends the data to the StoreData function of all
409 // 'detector data' objects that his detector has placed in fDetectorData.
410 //
411 // For debugging, each detector may define a PrintDecodedData function.
412 // The default version calls Print on all objects in fDetectorData.
413
414 const char* const here = "Decode";
415
416 // Loop over all modules defined for this detector
417 bool has_warning = false;
418 Int_t nhits = 0;
419
420 auto hitIter = fDetMap->MakeIterator(evdata);
421 while( hitIter ) {
422 const auto& hitinfo = *hitIter;
423 if( hitinfo.nhit > 1 ) {
424 // Multiple hits in a channel (usually noise)
425 // For multifunction modules, assume "hit" is a data word index, so
426 // don't log anything but assume the user simply wants the first word.
427 if( hitinfo.modtype != Decoder::ChannelType::kMultiFunctionADC and
428 hitinfo.modtype != Decoder::ChannelType::kMultiFunctionTDC ) {
429 MultipleHitWarning(hitinfo, here);
430 has_warning = true;
431 }
432 }
433
434 // Get the data for this hit
435 auto data = LoadData(evdata, hitinfo);
436 if( !data ) {
437 // Data could not be retrieved (probably decoder bug)
438 DataLoadWarning(hitinfo, here);
439 has_warning = true;
440 continue;
441 }
442
443 // Store hit data (and derived quantities) in fDetectorData.
444 // Multi-function modules can load additional data here.
445 StoreHit(hitinfo, data.value());
446
447 // Clear the hit-done flag which can be used in custom StoreHit methods
448 // to reorder module processing
449 for( auto& detData : fDetectorData )
450 detData->ClearHitDone();
451
452 // Next active channel
453 ++hitIter;
454 ++nhits;
455 }
456 if( has_warning )
458
459#ifdef WITH_DEBUG
460 if ( fDebug > 3 )
461 PrintDecodedData(evdata);
462#endif
463
464 return nhits;
465}
466
467//_____________________________________________________________________________
468void THaDetectorBase::PrintDecodedData( const THaEvData& /*evdata*/ ) const
469{
470 // Default Print function for decoded data
471
472 //TODO implement
473}
474
475//_____________________________________________________________________________
int Int_t
unsigned int UInt_t
const Data_t kBig
Definition DataType.h:15
size_t fSize
size_t size(const MatrixT &matrix)
bool Bool_t
double Double_t
const char Option_t
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char mode
char name[80]
static const char *const here
Definition THaVar.cxx:64
static Int_t LoadDB(FILE *file, const TDatime &date, const DBRequest *request, const char *prefix, Int_t search=0, const char *here="THaAnalysisObject::LoadDB")
virtual const char * Here(const char *) const
virtual Int_t ReadDatabase(const TDatime &date)
std::map< std::string, UInt_t > fMessages
virtual Int_t DefineVariables(EMode mode=kDefine)
virtual void Clear(Option_t *="")
Decoder::Module *Decoder::ChannelType type
Definition THaDetMap.h:197
virtual void Print(Option_t *opt="") const
THaDetMap::Iterator MakeIterator(const THaEvData &evdata)
virtual Int_t Fill(const std::vector< Int_t > &values, UInt_t flags=0)
Int_t FillDetMap(const std::vector< Int_t > &values, UInt_t flags=0, const char *here="FillDetMap")
virtual void Clear(Option_t *="")
THaDetMap * fDetMap
virtual Int_t StoreHit(const DigitizerHitInfo_t &hitinfo, UInt_t data)
void PrintDetMap(Option_t *opt="") const
virtual Bool_t IsInActiveArea(Double_t x, Double_t y) const
virtual Int_t ReadGeometry(FILE *file, const TDatime &date, Bool_t required=false)
void DataLoadWarning(const DigitizerHitInfo_t &hitinfo, const char *here)
virtual Int_t DefineVariables(EMode mode=kDefine)
Double_t fSize[3]
virtual void DefineAxes(Double_t rotation_angle)
virtual ~THaDetectorBase()
void DebugWarning(const char *here, const char *msg, UInt_t evnum)
TVector3 DetToTrackCoord(const TVector3 &point) const
TVector3 TrackToDetCoord(const TVector3 &point) const
void MultipleHitWarning(const DigitizerHitInfo_t &hitinfo, const char *here)
virtual OptUInt_t LoadData(const THaEvData &evdata, const DigitizerHitInfo_t &hitinfo)
VecDetData_t fDetectorData
virtual void Reset(Option_t *opt="")
virtual Int_t GetView(const DigitizerHitInfo_t &hitinfo) const
virtual Int_t ReadDatabase(const TDatime &date)
virtual Int_t Decode(const THaEvData &)
virtual void PrintDecodedData(const THaEvData &evdata) const
UInt_t GetData(UInt_t crate, UInt_t slot, UInt_t chan, UInt_t hit) const
Definition THaEvData.h:273
virtual void Warning(const char *method, const char *msgfmt,...) const
virtual void Error(const char *method, const char *msgfmt,...) const
void SetXYZ(Double_t x, Double_t y, Double_t z)
TVector3 Cross(const TVector3 &) const
void RotateY(Double_t)
Double_t y[n]
Double_t x[n]
constexpr Double_t DegToRad()
Double_t Abs(Double_t d)
STL namespace.
v
TMarker m
ClassImp(TPyArg)