Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
THaSpectrometer.cxx
Go to the documentation of this file.
1//*-- Author : Ole Hansen 07-Sep-00
2
4//
5// THaSpectrometer
6//
7// Abstract base class for a spectrometer.
8//
9// It implements a generic Reconstruct() method that should be
10// useful for most situations. See specific description below.
11//
12// It also provides support for lists of different detector types
13// (e.g. tracking/non-tracking/PID) for efficient processing.
14//
16
17#include "THaSpectrometer.h"
18#include "THaParticleInfo.h"
19#include "THaTrackingDetector.h"
21#include "THaPIDinfo.h"
22#include "THaTrack.h"
23#include "TClass.h"
24#include "TList.h"
25#include "TMath.h"
26#include "TList.h"
27#include "VarDef.h"
28
29#ifdef WITH_DEBUG
30#include <iostream>
31#endif
32
33using namespace std;
34
35//_____________________________________________________________________________
36THaSpectrometer::THaSpectrometer( const char* name, const char* desc ) :
37 THaApparatus(name, desc),
38 fTracks{new TClonesArray("THaTrack", kInitTrackMultiplicity)},
39 fTrackPID{new TClonesArray("THaPIDinfo", kInitTrackMultiplicity)},
40 fTrackingDetectors{new TList},
41 fNonTrackingDetectors{new TList},
42 fPidDetectors{new TObjArray},
43 fPidParticles{new TObjArray},
44 fGoldenTrack{nullptr},
45 fThetaGeo{0.0}, fPhiGeo{0.0}, fThetaSph{0.0}, fPhiSph{0.0},
46 fSinThGeo{0.0}, fCosThGeo{1.0}, fSinPhGeo{0.0}, fCosPhGeo{1.0},
47 fSinThSph{0.0}, fCosThSph{1.0}, fSinPhSph{0.0}, fCosPhSph{1.0},
48 fPcentral{1.0},
49 fCollDist{0.0},
50 fStagesDone{0},
51 fPID{false}
52{
53 // Constructor.
54 // Protected. Can only be called by derived classes.
55
57
59
61}
62
63//_____________________________________________________________________________
65{
66 // Destructor. Delete the lists of specialized detectors.
67
68 fPidParticles->Delete(); //delete all THaParticleInfo objects
69
70 delete fPidParticles; fPidParticles = nullptr;
71 delete fPidDetectors; fPidDetectors = nullptr;
73 delete fTrackingDetectors; fTrackingDetectors = nullptr;
74 delete fTrackPID; fTrackPID = nullptr;
75 delete fTracks; fTracks = nullptr;
76
78}
79
80//_____________________________________________________________________________
83{
84 // Add a detector to the internal lists of spectrometer detectors.
85 // Duplicate detector names are not allowed.
86 //
87 // NOTE: The detector object must be allocated by the caller, but will be
88 // deleted by the spectrometer. Do not delete detectors you've added
89 // to an apparatus/spectrometer. Recommended: AddDetector( new MyDetector )
90 //
91 // NOTE: If an error occurs (wrong detector class, detector already exists),
92 // the passed detector is deleted and -1 is returned.
93
94 auto* sdet = dynamic_cast<THaSpectrometerDetector*>( pdet );
95 if( !sdet ) {
96 if( !quiet )
97 Error("AddDetector", "Detector is not a THaSpectrometerDetector. "
98 "Detector not added. Detector object deleted.");
99 delete pdet;
100 return -1;
101 }
102 Int_t status = THaApparatus::AddDetector( pdet, quiet, first );
103 if( status != 0 )
104 return status;
105
106 assert(sdet);
107 if( sdet->IsTracking() )
108 fTrackingDetectors->Add( sdet );
109 else
110 fNonTrackingDetectors->Add( sdet );
111
112 if( sdet->IsPid() )
113 fPidDetectors->Add( sdet );
114
115 return 0;
116}
117
118//_____________________________________________________________________________
120 const char* name,
121 Double_t mass, Int_t charge )
122{
123 // Add a particle type to the list of particles for which we want PID.
124 // The "charge" argument is optional.
125
126 fPidParticles->Add( new THaParticleInfo( shortname, name, mass, charge ));
127 return 0;
128}
129
130//_____________________________________________________________________________
132{
133 // Combine the PID information from all detectors into an overall PID
134 // for each track. The actual work is done in the THaPIDinfo class.
135 // This is just a loop over all tracks.
136 // Called by Reconstruct().
137
138 for( int i = 0; i < fTracks->GetLast()+1; i++ ) {
139 if( auto* theTrack = static_cast<THaTrack*>( fTracks->At(i) ) ) {
140 assert(dynamic_cast<THaTrack*>(theTrack));
141 if( THaPIDinfo* pid = theTrack->GetPIDinfo() ) {
142 pid->CombinePID();
143 }
144 }
145 }
146 return 0;
147}
148
149//_____________________________________________________________________________
151{
152 // Clear the spectrometer data for next event.
153
155 // Clear the track array and also the track objects themselves since they
156 // need to deallocate memory
157 fTracks->Clear("C");
158 TrkIfoClear();
159 VertexClear();
160 fGoldenTrack = nullptr;
161 fStagesDone = 0;
162}
163
164//_____________________________________________________________________________
166{
167 // Initialize spectrometer. First, ensure that the lists of detector types
168 // are in a consistent state. Then, do the Apparatus initialization,
169 // which reads our database and initializes the detectors. Finally, set up
170 // the PID structures if PID enabled.
171
172 ListInit();
173
174 EStatus ret = THaApparatus::Init(run_time);
175 if( ret )
176 return ret;
177
178 if( IsPID() )
179 PidInit();
180
181 // TODO: Set up vertex objects that can be associated with tracks?
182
183 return kOK;
184}
185
186//_____________________________________________________________________________
188{
189 // Define the default set of PID particles:
190 // electron, pion, kaon, proton
191 //
192 // This spectrometer does not necessarily have to have PID detectors
193 // that can identify all of these types. This is essentially a list of
194 // convenient candidates for medium energy experiments.
195
196 fPidParticles->Delete(); //make sure array is empty
197
198 AddPidParticle( "e", "electron", 0.511e-3, -1 );
199 AddPidParticle( "pi", "pion", 0.139, 0 );
200 AddPidParticle( "k", "kaon", 0.4936, 0 );
201 AddPidParticle( "p", "proton", 0.938, 1 );
202}
203
204//_____________________________________________________________________________
206{
207 // Define/delete standard variables for a spectrometer (tracks etc.)
208 // Can be overridden or extended by derived (actual) apparatuses
209
210 RVarDef vars[] = {
211 { "tr.n", "Number of tracks", "GetNTracks()" },
212 { "tr.x", "Track x coordinate (m)", "fTracks.THaTrack.fX" },
213 { "tr.y", "Track x coordinate (m)", "fTracks.THaTrack.fY" },
214 { "tr.th", "Tangent of track theta angle", "fTracks.THaTrack.fTheta" },
215 { "tr.ph", "Tangent of track phi angle", "fTracks.THaTrack.fPhi" },
216 { "tr.p", "Track momentum (GeV)", "fTracks.THaTrack.fP" },
217 { "tr.flag", "Track status flag", "fTracks.THaTrack.fFlag" },
218 { "tr.chi2", "Track's chi2 from hits", "fTracks.THaTrack.fChi2" },
219 { "tr.ndof", "Track's NDoF", "fTracks.THaTrack.fNDoF" },
220 { "tr.d_x", "Detector x coordinate (m)", "fTracks.THaTrack.fDX" },
221 { "tr.d_y", "Detector y coordinate (m)", "fTracks.THaTrack.fDY" },
222 { "tr.d_th", "Detector tangent of theta", "fTracks.THaTrack.fDTheta" },
223 { "tr.d_ph", "Detector tangent of phi", "fTracks.THaTrack.fDPhi" },
224 { "tr.r_x", "Rotated x coordinate (m)", "fTracks.THaTrack.fRX" },
225 { "tr.r_y", "Rotated y coordinate (m)", "fTracks.THaTrack.fRY" },
226 { "tr.r_th", "Rotated tangent of theta", "fTracks.THaTrack.fRTheta" },
227 { "tr.r_ph", "Rotated tangent of phi", "fTracks.THaTrack.fRPhi" },
228 { "tr.tg_y", "Target y coordinate", "fTracks.THaTrack.fTY"},
229 { "tr.tg_th", "Tangent of target theta angle", "fTracks.THaTrack.fTTheta"},
230 { "tr.tg_ph", "Tangent of target phi angle", "fTracks.THaTrack.fTPhi"},
231 { "tr.tg_dp", "Target delta", "fTracks.THaTrack.fDp"},
232 { "tr.px", "Lab momentum x (GeV)", "fTracks.THaTrack.GetLabPx()"},
233 { "tr.py", "Lab momentum y (GeV)", "fTracks.THaTrack.GetLabPy()"},
234 { "tr.pz", "Lab momentum z (GeV)", "fTracks.THaTrack.GetLabPz()"},
235 { "tr.vx", "Vertex x (m)", "fTracks.THaTrack.GetVertexX()"},
236 { "tr.vy", "Vertex y (m)", "fTracks.THaTrack.GetVertexY()"},
237 { "tr.vz", "Vertex z (m)", "fTracks.THaTrack.GetVertexZ()"},
238 { "tr.pathl", "Pathlength from tg to fp (m)","fTracks.THaTrack.GetPathLen()"},
239 { "tr.time", "Time of track@Ref Plane (s)", "fTracks.THaTrack.GetTime()"},
240 { "tr.dtime", "uncer of time (s)", "fTracks.THaTrack.GetdTime()"},
241 { "tr.beta", "Beta of track", "fTracks.THaTrack.GetBeta()"},
242 { "tr.dbeta", "uncertainty of beta", "fTracks.THaTrack.GetdBeta()"},
243 { "status", "Bits of completed analysis stages", "fStagesDone" },
244 { nullptr }
245 };
246
247 return DefineVarsFromList( vars, mode );
248}
249
250//_____________________________________________________________________________
252{
253 // Return vertex vector of the Golden Track.
254 // Overrides standard method of THaVertexModule.
255
257}
258
259//_____________________________________________________________________________
261{
262 return (fGoldenTrack) != nullptr && fGoldenTrack->HasVertex();
263}
264
265//_____________________________________________________________________________
267{
268 // Initialize lists of specialized detectors. Called by Init().
269
273
274 TIter next(fDetectors);
275 while( auto* theDetector = dynamic_cast<THaSpectrometerDetector*>( next() )) {
276
277 if( theDetector->IsTracking() )
278 fTrackingDetectors->Add( theDetector );
279 else
280 fNonTrackingDetectors->Add( theDetector );
281
282 if( theDetector->IsPid() )
283 fPidDetectors->Add( theDetector );
284 }
285}
286
287//_____________________________________________________________________________
289{
290 // Initialize PID structures that can be associated with tracks
291
292 // If not already done, set up this spectrometer's default PID particles
293 if( fPidParticles->IsEmpty() )
295
296 UInt_t ndet = GetNpidDetectors();
297 UInt_t npart = GetNpidParticles();
298
299 // Set up initial set of PIDinfo objects
300 for( Int_t i = 0; i < kInitTrackMultiplicity; i++ ) {
301 new( (*fTrackPID)[i]) THaPIDinfo(ndet, npart);
302 }
303}
304
305//_____________________________________________________________________________
307{
308 // Coarse Tracking: First step of spectrometer analysis
309
310 // 1st step: Coarse tracking. This should be quick and dirty.
311 // Any tracks found are put in the fTrack array.
313 while( auto* theTrackDetector =
314 static_cast<THaTrackingDetector*>( next() )) {
315 assert(dynamic_cast<THaTrackingDetector*>(theTrackDetector));
316#ifdef WITH_DEBUG
317 if( fDebug>1 ) cout << "Call CoarseTrack() for "
318 << theTrackDetector->GetName() << "... ";
319#endif
320 theTrackDetector->CoarseTrack( *fTracks );
321#ifdef WITH_DEBUG
322 if( fDebug>1 ) cout << "done.\n";
323#endif
324 }
325
327 return 0;
328}
329
330//_____________________________________________________________________________
332{
333 // 2nd step: Coarse processing. Pass the coarse tracks to the remaining
334 // detectors for any processing that can be done at this stage.
335 // This may include clustering and preliminary PID.
336 // PID information is tacked onto the tracks as a THaPIDinfo object.
337
338 if( !IsDone(kCoarseTrack) )
339 CoarseTrack();
340
342 while( auto* theNonTrackDetector =
343 static_cast<THaNonTrackingDetector*>( next() )) {
344 assert(dynamic_cast<THaNonTrackingDetector*>(theNonTrackDetector));
345#ifdef WITH_DEBUG
346 if( fDebug>1 ) cout << "Call CoarseProcess() for "
347 << theNonTrackDetector->GetName() << "... ";
348#endif
349 theNonTrackDetector->CoarseProcess( *fTracks );
350#ifdef WITH_DEBUG
351 if( fDebug>1 ) cout << "done.\n";
352#endif
353 }
354
356 return 0;
357}
358
359//_____________________________________________________________________________
361{
362 // Fine tracking. Compute the tracks with high precision.
363 // If coarse tracking was done, this step should simply "refine" the
364 // tracks found earlier, not add new tracks to fTrack.
365
366 if( !IsDone(kCoarseRecon) )
368
370 while( auto* theTrackDetector =
371 static_cast<THaTrackingDetector*>( next() )) {
372 assert(dynamic_cast<THaTrackingDetector*>(theTrackDetector));
373#ifdef WITH_DEBUG
374 if( fDebug>1 ) cout << "Call FineTrack() for "
375 << theTrackDetector->GetName() << "... ";
376#endif
377 theTrackDetector->FineTrack( *fTracks );
378#ifdef WITH_DEBUG
379 if( fDebug>1 ) cout << "done.\n";
380#endif
381 }
382
383 // Reconstruct tracks to target/vertex
384 // This usually also determines the track momentum
386
388 return 0;
389}
390
391//_____________________________________________________________________________
393{
394 // This method implements a fairly generic algorithm for spectrometer
395 // reconstruction which should be useful for most situations.
396 // Additional, equipment-specific processing can be done in
397 // a derived class that calls this method first.
398 //
399 // The algorithm is as follows:
400 //
401 // For all tracking detectors:
402 // CoarseTrack()
403 // For all non-tracking detectors:
404 // CoarseProcess()
405 // For all tracking detectors:
406 // FineTrack()
407 // Reconstruct tracks to target
408 // For all non-tracking detectors:
409 // FineProcess()
410 // Compute additional attributes of tracks (e.g. momentum, beta)
411 // Find "Golden Track"
412 // Combine all PID detectors to get overall PID for each track
413 //
414
415 // Do prior analysis stages if not done yet
416 if( !IsDone(kTracking) )
417 Track();
418
419 // Fine processing. Pass the precise tracks to the
420 // remaining detectors for any precision processing.
421 // PID likelihoods should be calculated here.
422
424 while( auto* theNonTrackDetector =
425 static_cast<THaNonTrackingDetector*>( next() )) {
426 assert(dynamic_cast<THaNonTrackingDetector*>(theNonTrackDetector));
427#ifdef WITH_DEBUG
428 if( fDebug>1 ) cout << "Call FineProcess() for "
429 << theNonTrackDetector->GetName() << "... ";
430#endif
431 theNonTrackDetector->FineProcess( *fTracks );
432#ifdef WITH_DEBUG
433 if( fDebug>1 ) cout << "done.\n";
434#endif
435 }
436
437 // Compute additional track properties (e.g. beta)
438 // Find "Golden Track" if appropriate.
439
440 TrackCalc();
441
442 // Compute combined PID
443
444 if( IsPID() )
445 CalcPID();
446
448 return 0;
449}
450
451//_____________________________________________________________________________
453{
454 // Convert TRANSPORT coordinates of 'track' to momentum vector 'pvect'
455 // in the lab coordinate system (z = beam, y = up).
456 // Uses the spectrometer angles from the database (loaded during Init())
457 // for the transformation.
458 //
459 // The track origin (vertex) is not calculated here because
460 // doing so requires knowledge of beam positions and and angles.
461 // Vertex calculations are done in a separate physics module.
462
463 TransportToLab( track.GetP(), track.GetTTheta(), track.GetTPhi(), pvect );
464}
465
466//_____________________________________________________________________________
468 TVector3& pvect ) const
469{
470 // Convert TRANSPORT vector to lab vector.
471 // Inputs:
472 // p: TRANSPORT momentum (absolute)
473 // th: Tangent of TRANSPORT theta
474 // ph: Tangent of TRANSPORT phi
475 // Output:
476 // pvect: Vector in lab frame (z = beam, y = up) in same units as p.
477 //
478 // Note: Simple vector transformation can be done trivially by multiplying
479 // with the appropriate rotation matrix, e.g.:
480 // TVector3 lab_vector = spect->GetToLabRot() * transport_vector;
481
482 TVector3 v( th, ph, 1.0 );
483 v *= p/TMath::Sqrt( 1.0+th*th+ph*ph );
484 pvect = fToLabRot * v;
485}
486
487//_____________________________________________________________________________
489 const TVector3& pvect,
490 TVector3& tvertex, Double_t* ray ) const
491{
492 // Convert lab coordinates to TRANSPORT coordinates in the spectrometer
493 // coordinate system.
494 // Inputs:
495 // vertex: Reaction point in lab system
496 // pvect: Momentum vector in lab
497 // Outputs:
498 // tvertex: The vertex point in the TRANSPORT system, without any
499 // coordinate projections applied
500 // ray: The TRANSPORT ray according to TRANSPORT conventions.
501 // This is an array of size 6 with elements x, tan(theta),
502 // y, tan(y), z, and delta.
503 // z is set to 0, and accordingly x and y are the TRANSPORT
504 // coordinates in the z=0 plane. delta is computed with respect
505 // to the present spectrometer's central momentum.
506 // Units are the same as of the input vectors.
507
508 tvertex = fToTraRot * ( vertex - fPointingOffset );
509 TVector3 pt = fToTraRot * pvect;
510 if( pt.Z() != 0.0 ) {
511 ray[1] = pt.X() / pt.Z();
512 ray[3] = pt.Y() / pt.Z();
513 // In the "ray", project the vertex to z=0
514 ray[0] = tvertex.X() - tvertex.Z() * ray[1];
515 ray[2] = tvertex.Y() - tvertex.Z() * ray[3];
516 } else
517 ray[0] = ray[1] = ray[2] = ray[3] = 0.0;
518
519 ray[4] = 0.0; // By definition for this ray, TRANSPORT z=0
520 ray[5] = pt.Mag() / fPcentral - 1.0;
521}
522
523//_____________________________________________________________________________
525 Bool_t bend_down )
526{
527 // Given geographical angles theta and phi (in degrees), compute the
528 // spectrometer's central angles in spherical coordinates and save trig.
529 // values of angles for later use.
530 // Note: negative theta corresponds to beam RIGHT.
531 // phi should be close to zero unless this is a true out-of-plane spectrometer.
532 // If 'bend_down' is true, the spectrometer bends downwards.
533
542
543 // Compute the rotation from TRANSPORT to lab and vice versa.
544 Double_t norm = TMath::Sqrt(ct*ct + st*st*cp*cp);
545 TVector3 nx( st*st*sp*cp/norm, -norm, st*ct*sp/norm );
546 TVector3 ny( ct/norm, 0.0, -st*cp/norm );
547 TVector3 nz( st*cp, st*sp, ct );
548 if( bend_down ) { nx *= -1.0; ny *= -1.0; }
549 fToLabRot.SetToIdentity().RotateAxes( nx, ny, nz );
551}
552
553//_____________________________________________________________________________
555{
556 // Query the run database for parameters specific to this spectrometer
557 // (central angles, momentum, offsets, drift, etc.)
558
560 if( err ) return err;
561
562 FILE* file = OpenRunDBFile( date );
563 if( !file ) return kFileError;
564
565 Double_t th = 0.0, ph = 0.0;
566 Double_t off_x = 0.0, off_y = 0.0, off_z = 0.0;
567
568 const DBRequest req[] = {
569 { "theta", &th },
570 { "phi", &ph, kDouble, 0, true },
571 { "pcentral", &fPcentral },
572 { "colldist", &fCollDist, kDouble, 0, true },
573 { "off_x", &off_x, kDouble, 0, true },
574 { "off_y", &off_y, kDouble, 0, true },
575 { "off_z", &off_z, kDouble, 0, true },
576 { nullptr }
577 };
578 err = LoadDB( file, date, req );
579 fclose(file);
580 if( err )
581 return kInitError;
582
583 SetCentralAngles( th, ph, false );
584
585 fPointingOffset.SetXYZ( off_x, off_y, off_z );
586
587 return kOK;
588}
589
590//_____________________________________________________________________________
592
int Int_t
unsigned int UInt_t
bool Bool_t
double Double_t
const char Option_t
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char mode
char name[80]
void Clear(Option_t *option="") override
static void GeoToSph(Double_t th_geo, Double_t ph_geo, Double_t &th_sph, Double_t &ph_sph)
virtual Int_t ReadRunDatabase(const TDatime &date)
static Int_t LoadDB(FILE *file, const TDatime &date, const DBRequest *request, const char *prefix, Int_t search=0, const char *here="THaAnalysisObject::LoadDB")
static Int_t DefineVarsFromList(const void *list, EType type, EMode mode, const char *def_prefix, const TObject *obj, const char *prefix, const char *here, const char *comment_subst="")
virtual FILE * OpenRunDBFile(const TDatime &date)
virtual Int_t AddDetector(THaDetector *det, Bool_t quiet=false, Bool_t first=false)
virtual void Clear(Option_t *opt="")
TList * fDetectors
Bool_t IsDone(UInt_t stage) const
virtual Int_t AddDetector(THaDetector *det, Bool_t quiet=false, Bool_t first=false)
THaTrack * fGoldenTrack
virtual Bool_t HasVertex() const
virtual Int_t CoarseReconstruct()
virtual void DefinePidParticles()
Int_t GetNpidDetectors() const
void SetCentralAngles(Double_t th, Double_t ph, Bool_t bend_down)
Int_t GetNpidParticles() const
virtual void LabToTransport(const TVector3 &vertex, const TVector3 &pvect, TVector3 &tvertex, Double_t *ray) const
TClonesArray * fTracks
virtual Int_t TrackCalc()=0
virtual Int_t AddPidParticle(const char *shortname, const char *name, Double_t mass, Int_t charge=0)
virtual Int_t ReadRunDatabase(const TDatime &date)
virtual void TransportToLab(Double_t p, Double_t th, Double_t ph, TVector3 &pvect) const
virtual void Clear(Option_t *opt="")
virtual Int_t CoarseTrack()
static const Int_t kInitTrackMultiplicity
TObjArray * fPidDetectors
virtual Int_t Reconstruct()
virtual Int_t FindVertices(TClonesArray &tracks)=0
virtual void ListInit()
TClonesArray * fTrackPID
virtual void PidInit()
virtual Int_t CalcPID()
virtual const TVector3 & GetVertex() const
virtual Int_t DefineVariables(EMode mode=kDefine)
THaSpectrometer(const char *name, const char *description)
TList * fNonTrackingDetectors
virtual void TrackToLab(THaTrack &track, TVector3 &pvect) const
virtual Int_t Track()
TObjArray * fPidParticles
virtual ~THaSpectrometer()
Bool_t IsPID() const
void SetSpectrometer(THaSpectrometer *s)
bool HasVertex() const
Definition THaTrack.h:139
TVector3 & GetVertex()
Definition THaTrack.h:120
Double_t GetTPhi() const
Definition THaTrack.h:109
Double_t GetP() const
Definition THaTrack.h:86
Double_t GetTTheta() const
Definition THaTrack.h:108
virtual void VertexClear()
void Clear(Option_t *option="") override
void Add(TObject *obj) override
void Clear(Option_t *option="") override
void Delete(Option_t *option="") override
TObject * At(Int_t idx) const override
Bool_t IsEmpty() const override
Int_t GetLast() const override
void Add(TObject *obj) override
virtual void Error(const char *method, const char *msgfmt,...) const
TRotation & SetToIdentity()
TRotation Inverse() const
TRotation & RotateAxes(const TVector3 &newX, const TVector3 &newY, const TVector3 &newZ)
Double_t Z() const
void SetXYZ(Double_t x, Double_t y, Double_t z)
Double_t Y() const
Double_t X() const
TPaveText * pt
constexpr Double_t DegToRad()
Double_t Sqrt(Double_t x)
Double_t Cos(Double_t)
Double_t Sin(Double_t)
STL namespace.
v
ClassImp(TPyArg)
double * vertex