FairShip
Loading...
Searching...
No Matches
ShipFieldMaker.cxx
Go to the documentation of this file.
1// SPDX-License-Identifier: LGPL-3.0-or-later
2// SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP
3// Collaboration
4
17#include "ShipFieldMaker.h"
18
19#include <cmath>
20#include <cstdlib>
21#include <fstream>
22#include <iostream>
23#include <string>
24
25#include "FairLogger.h"
26#include "ShipBFieldMap.h"
27#include "ShipBellField.h"
28#include "ShipConstField.h"
29#include "TCanvas.h"
30#include "TGeoChecker.h"
31#include "TGeoManager.h"
32#include "TGeoMatrix.h"
33#include "TGeoNode.h"
34#include "TGeoPhysicalNode.h"
35#include "TGeoUniformMagField.h"
36#include "TGeoVolume.h"
37#include "TH2.h"
38#include "TObjArray.h"
39#include "TROOT.h"
40#include "TStyle.h"
41#include "TVirtualMC.h"
42
44 : TG4VUserPostDetConstruction(),
45 globalField_(nullptr),
46 theFields_(),
47 regionInfo_(),
48 localInfo_(),
49 verbose_(verbose),
50 Tesla_(10.0), // To convert T to kGauss for VMC/FairRoot
51 theNode_(nullptr),
52 gotNode_(kFALSE) {}
53
55 // Delete the various magnetic fields
56 SFMap::iterator iter;
57 for (iter = theFields_.begin(); iter != theFields_.end(); ++iter) {
58 delete iter->second;
59 }
60
61 theFields_.clear();
62}
63
65 // Assign volumes with their regional (local + global) or local B fields
66 this->setAllRegionFields();
67 this->setAllLocalFields();
68}
69
70void ShipFieldMaker::readInputFile(const std::string& inputFile) {
71 // Check that we have a non-empty string
72 if (inputFile.size() < 1) {
73 std::cerr << "Skipping ShipFieldMaker::readInputFile(): file name is empty"
74 << std::endl;
75 return;
76 }
77
78 const char* vmcworkdir = getenv("VMCWORKDIR");
79 if (!vmcworkdir) {
80 LOG(fatal) << "VMCWORKDIR environment variable not set";
81 return;
82 }
83 std::string fullFileName = vmcworkdir;
84 fullFileName += "/";
85 fullFileName += inputFile.c_str();
86
87 std::cout << "ShipFieldMaker::makeFields inputFile = " << fullFileName
88 << std::endl;
89
90 std::ifstream getData(fullFileName);
91 std::string whiteSpace(" ");
92
93 // Loop while the input file is readable
94 while (getData.good()) {
95 if (getData.peek() == '\n') {
96 // Finish reading line
97 char c;
98 getData.get(c);
99
100 // Stop while loop if we have reached the end of the file
101 if (getData.eof()) {
102 break;
103 }
104
105 } else if (getData.peek() == '#') {
106 // Skip comment line
107 getData.ignore(1000, '\n');
108 getData.putback('\n');
109
110 // Stop while loop if we have reached the end of the file
111 if (getData.eof()) {
112 break;
113 }
114
115 } else {
116 // Read data line
117 std::string line("");
118 std::getline(getData, line);
119
120 // Stop while loop if we have reached the end of the file
121 if (getData.eof()) {
122 break;
123 }
124
125 // Split up the line according to white spaces
126 std::vector<std::string> lineVect = this->splitString(line, whiteSpace);
127
128 size_t nWords = lineVect.size();
129
130 // Check to see if we have at least one keyword at the start of the line
131 if (nWords > 1) {
132 TString keyWord(lineVect[0].c_str());
133 keyWord.ToLower();
134
135 if (!keyWord.CompareTo("uniform")) {
136 // Define the uniform magnetic field
137 this->defineUniform(lineVect);
138
139 } else if (!keyWord.CompareTo("constant")) {
140 // Define a uniform field with an x,y,z boundary
141 this->defineConstant(lineVect);
142
143 } else if (!keyWord.CompareTo("bell")) {
144 // Define the Bell-shaped field
145 this->defineBell(lineVect);
146
147 } else if (!keyWord.CompareTo("fieldmap")) {
148 // Define the field map
149 this->defineFieldMap(lineVect);
150
151 } else if (!keyWord.CompareTo("symfieldmap")) {
152 // Define the symmetric field map
153 this->defineFieldMap(lineVect, kTRUE);
154
155 } else if (!keyWord.CompareTo("copymap")) {
156 // Copy (& translate) the field map
157 this->defineFieldMapCopy(lineVect);
158
159 } else if (!keyWord.CompareTo("composite")) {
160 // Define the composite field
161 this->defineComposite(lineVect);
162
163 } else if (!keyWord.CompareTo("global")) {
164 // Define which fields are global
165 this->defineGlobalField(lineVect);
166
167 } else if (!keyWord.CompareTo("region")) {
168 // Define the local and global fields for the given volume
169 this->defineRegionField(lineVect);
170
171 } else if (!keyWord.CompareTo("local")) {
172 // Define the field for the given volume as the local one only
173 this->defineLocalField(lineVect);
174 }
175 }
176 }
177 }
178
179 getData.close();
180}
181
183 size_t nWords = inputLine.size();
184
185 // Expecting a line such as:
186 // Uniform Name Bx By Bz
187
188 if (nWords == 5) {
189 const TString name(inputLine[1].c_str());
190
191 Double_t Bx = std::atof(inputLine[2].c_str());
192 Double_t By = std::atof(inputLine[3].c_str());
193 Double_t Bz = std::atof(inputLine[4].c_str());
194 const TVector3 BVector(Bx, By, Bz);
195
196 this->defineUniform(name, BVector);
197
198 } else {
199 std::cout << "Expecting 5 words for the definition of the uniform field: "
200 << "Uniform Name Bx By Bz" << std::endl;
201 }
202}
203
204void ShipFieldMaker::defineUniform(const TString& name,
205 const TVector3& BVector) {
206 // Check if the field is already in the map
207 if (!this->gotField(name)) {
208 if (verbose_) {
209 std::cout << "Creating uniform field for " << name.Data() << std::endl;
210 }
211
212 Double_t Bx = BVector.X() * Tesla_;
213 Double_t By = BVector.Y() * Tesla_;
214 Double_t Bz = BVector.Z() * Tesla_;
215
216 TGeoUniformMagField* uField = new TGeoUniformMagField(Bx, By, Bz);
217 theFields_[name] = uField;
218
219 } else {
220 if (verbose_) {
221 std::cout << "We already have a uniform field with the name "
222 << name.Data() << std::endl;
223 }
224 }
225}
226
228 size_t nWords = inputLine.size();
229
230 // Expecting a line such as:
231 // Constant Name xMin xMax yMin yMax zMin zMax Bx By Bz
232
233 if (nWords == 11) {
234 TString name(inputLine[1].c_str());
235
236 Double_t xMin = std::atof(inputLine[2].c_str());
237 Double_t xMax = std::atof(inputLine[3].c_str());
238
239 Double_t yMin = std::atof(inputLine[4].c_str());
240 Double_t yMax = std::atof(inputLine[5].c_str());
241
242 Double_t zMin = std::atof(inputLine[6].c_str());
243 Double_t zMax = std::atof(inputLine[7].c_str());
244
245 // Input field in Tesla_, interface needs kGauss units
246 Double_t Bx = std::atof(inputLine[8].c_str());
247 Double_t By = std::atof(inputLine[9].c_str());
248 Double_t Bz = std::atof(inputLine[10].c_str());
249
250 const TVector2 xRange(xMin, xMax);
251 const TVector2 yRange(yMin, yMax);
252 const TVector2 zRange(zMin, zMax);
253 const TVector3 BVector(Bx, By, Bz);
254
255 this->defineConstant(name, xRange, yRange, zRange, BVector);
256
257 } else {
258 std::cout << "Expecting 11 words for the definition of the constant field: "
259 << "Constant Name xMin xMax yMin yMax zMin zMax Bx By Bz"
260 << std::endl;
261 }
262}
263
264void ShipFieldMaker::defineConstant(const TString& name, const TVector2& xRange,
265 const TVector2& yRange,
266 const TVector2& zRange,
267 const TVector3& BVector) {
268 // Check if the field is already in the map
269 if (!this->gotField(name)) {
270 Double_t xMin = xRange.X();
271 Double_t xMax = xRange.Y();
272 Double_t yMin = yRange.X();
273 Double_t yMax = yRange.Y();
274 Double_t zMin = zRange.X();
275 Double_t zMax = zRange.Y();
276
277 Double_t Bx = BVector.X() * Tesla_;
278 Double_t By = BVector.Y() * Tesla_;
279 Double_t Bz = BVector.Z() * Tesla_;
280
281 ShipConstField* theField = new ShipConstField(name.Data(), xMin, xMax, yMin,
282 yMax, zMin, zMax, Bx, By, Bz);
283 theFields_[name] = theField;
284
285 } else {
286 if (verbose_) {
287 std::cout << "We already have a constant field with the name "
288 << name.Data() << std::endl;
289 }
290 }
291}
292
294 size_t nWords = inputLine.size();
295
296 // Expecting a line such as:
297 // Bell Name BPeak zMiddle orientationInt tubeRadius
298
299 if (nWords == 6 || nWords == 9) {
300 TString name(inputLine[1].c_str());
301
302 Double_t BPeak = std::atof(inputLine[2].c_str());
303 Double_t zMiddle = std::atof(inputLine[3].c_str()); // cm
304
305 Int_t orient = std::atoi(inputLine[4].c_str());
306 Double_t tubeR = std::atof(inputLine[5].c_str()); // cm
307
308 Double_t xy(0.0), z(0.0), L(0.0);
309
310 if (nWords == 9) {
311 // Specify "target" dimensions (cm)
312 xy = std::atof(inputLine[6].c_str());
313 z = std::atof(inputLine[7].c_str());
314 L = std::atof(inputLine[8].c_str());
315 }
316
317 this->defineBell(name, BPeak, zMiddle, orient, tubeR, xy, z, L);
318
319 } else {
320 std::cout << "Expecting 6 or 9 words for the definition of the Bell field: "
321 << "Bell Name BPeak zMiddle orientationInt tubeRadius [targetXY "
322 "targetZ0 targetL]"
323 << std::endl;
324 }
325}
326
327void ShipFieldMaker::defineBell(const TString& name, Double_t BPeak,
328 Double_t zMiddle, Int_t orient, Double_t tubeR,
329 Double_t xy, Double_t z, Double_t L) {
330 if (!this->gotField(name)) {
331 ShipBellField* theField =
332 new ShipBellField(name.Data(), BPeak * Tesla_, zMiddle, orient, tubeR);
333
334 // Set additional parameters if we have a non-zero target length
335 if (fabs(L) > 0.0) {
336 theField->IncludeTarget(xy, z, L);
337 }
338
339 theFields_[name] = theField;
340
341 } else {
342 if (verbose_) {
343 std::cout << "We already have a Bell field with the name " << name.Data()
344 << std::endl;
345 }
346 }
347}
348
350 Bool_t useSymmetry) {
351 size_t nWords = inputLine.size();
352
353 // Expecting the line:
354 // FieldMap Name mapFileName [x0 y0 z0] [phi theta psi]
355
356 if (nWords == 3 || nWords == 6 || nWords == 9) {
357 const TString name(inputLine[1].c_str());
358 const TString mapFileName(inputLine[2].c_str());
359
360 Double_t x0(0.0), y0(0.0), z0(0.0);
361 Double_t phi(0.0), theta(0.0), psi(0.0);
362
363 if (nWords > 5) {
364 x0 = std::atof(inputLine[3].c_str());
365 y0 = std::atof(inputLine[4].c_str());
366 z0 = std::atof(inputLine[5].c_str());
367 }
368
369 if (nWords == 9) {
370 phi = std::atof(inputLine[6].c_str());
371 theta = std::atof(inputLine[7].c_str());
372 psi = std::atof(inputLine[8].c_str());
373 }
374
375 const TVector3 localCentre(x0, y0, z0);
376 const TVector3 localAngles(phi, theta, psi);
377
378 this->defineFieldMap(name, mapFileName, localCentre, localAngles,
379 useSymmetry);
380
381 } else {
382 std::cout
383 << "Expecting 3, 6 or 9 words for the definition of the field map: "
384 << "(Sym)FieldMap Name mapFileName [x0 y0 z0] [[phi theta psi]]"
385 << std::endl;
386 }
387}
388
389void ShipFieldMaker::defineFieldMap(const TString& name,
390 const TString& mapFileName,
391 const TVector3& localCentre,
392 const TVector3& localAngles,
393 Bool_t useSymmetry) {
394 // Check if the field is already in the map
395 if (!this->gotField(name)) {
396 // Add the VMCWORKDIR prefix to this map file location
397 const char* vmcworkdir = getenv("VMCWORKDIR");
398 if (!vmcworkdir) {
399 LOG(fatal) << "VMCWORKDIR environment variable not set";
400 return;
401 }
402 std::string fullFileName = vmcworkdir;
403 fullFileName += "/";
404 fullFileName += mapFileName.Data();
405
406 if (verbose_) {
407 if (useSymmetry) {
408 std::cout << "Creating symmetric field map called " << name.Data()
409 << " using " << fullFileName << std::endl;
410 } else {
411 std::cout << "Creating field map called " << name.Data() << " using "
412 << fullFileName << std::endl;
413 }
414 }
415
416 // Since field maps use floating point precision we convert any double
417 // parameter values to floats, i.e. we can't simply pass TVector3 objects
418 Float_t x0 = localCentre.X();
419 Float_t y0 = localCentre.Y();
420 Float_t z0 = localCentre.Z();
421
422 Float_t phi = localAngles.X();
423 Float_t theta = localAngles.Y();
424 Float_t psi = localAngles.Z();
425
426 Float_t scale(1.0);
427
428 ShipBFieldMap* mapField =
429 new ShipBFieldMap(name.Data(), fullFileName, x0, y0, z0, phi, theta,
430 psi, scale, useSymmetry);
431 theFields_[name] = mapField;
432
433 } else {
434 if (verbose_) {
435 std::cout << "We already have a field map with the name " << name.Data()
436 << std::endl;
437 }
438 }
439}
440
442 // Define a (translated) copy of a field map based in the input file line
443
444 size_t nWords = inputLine.size();
445
446 // Expecting the line:
447 // CopyMap Name MapNameToCopy x0 y0 z0 [phi theta psi]
448
449 if (nWords == 6 || nWords == 9) {
450 const TString name(inputLine[1].c_str());
451
452 // We want to try to copy and transpose an already existing field map
453 const TString mapNameToCopy(inputLine[2].c_str());
454
455 Double_t x0 = std::atof(inputLine[3].c_str());
456 Double_t y0 = std::atof(inputLine[4].c_str());
457 Double_t z0 = std::atof(inputLine[5].c_str());
458
459 Double_t phi(0.0), theta(0.0), psi(0.0);
460
461 if (nWords == 9) {
462 phi = std::atof(inputLine[6].c_str());
463 theta = std::atof(inputLine[7].c_str());
464 psi = std::atof(inputLine[8].c_str());
465 }
466
467 const TVector3 translation(x0, y0, z0);
468 const TVector3 eulerAngles(phi, theta, psi);
469
470 this->defineFieldMapCopy(name, mapNameToCopy, translation, eulerAngles);
471
472 } else {
473 std::cout << "Expecting 6 or 9 words for the copy of a field map: "
474 << "CopyMap Name MapNameToCopy x0 y0 z0 [phi theta psi]"
475 << std::endl;
476 }
477}
478
479void ShipFieldMaker::defineFieldMapCopy(const TString& name,
480 const TString& mapNameToCopy,
481 const TVector3& translation,
482 const TVector3& eulerAngles) {
483 // Check if the field is already in the map
484 if (!this->gotField(name)) {
485 ShipBFieldMap* fieldToCopy =
486 dynamic_cast<ShipBFieldMap*>(this->getField(mapNameToCopy));
487
488 if (fieldToCopy) {
489 if (verbose_) {
490 std::cout << "Creating map field copy " << name.Data() << " based on "
491 << mapNameToCopy.Data() << std::endl;
492 }
493
494 // Since field maps use floating point precision we convert any double
495 // parameter values to floats, i.e. we can't simply pass TVector3 objects
496 Float_t x0 = translation.X();
497 Float_t y0 = translation.Y();
498 Float_t z0 = translation.Z();
499
500 Float_t phi = eulerAngles.X();
501 Float_t theta = eulerAngles.Y();
502 Float_t psi = eulerAngles.Z();
503
504 Float_t scale(1.0);
505
506 ShipBFieldMap* copiedMap = new ShipBFieldMap(
507 name.Data(), *fieldToCopy, x0, y0, z0, phi, theta, psi, scale);
508 theFields_[name] = copiedMap;
509 }
510
511 } else {
512 std::cout << "We already have a copied field map with the name "
513 << name.Data() << std::endl;
514 }
515}
516
518 size_t nWords = inputLine.size();
519
520 // Expecting a line such as:
521 // Composite Name Field1 Field2 ... FieldN
522
523 if (nWords > 2) {
524 TString name(inputLine[1].c_str());
525
526 std::vector<TString> fieldNames;
527 for (size_t i = 2; i < nWords; i++) {
528 TString aName(inputLine[i].c_str());
529 fieldNames.push_back(aName);
530 }
531
532 this->defineComposite(name, fieldNames);
533
534 } else {
535 std::cout << "Expecting at least 3 words for the composite definition: "
536 << "Composite Name Field1 Field2 ... FieldN" << std::endl;
537 }
538}
539
540void ShipFieldMaker::defineComposite(const TString& name,
541 const TString& field1Name,
542 const TString& field2Name,
543 const TString& field3Name,
544 const TString& field4Name) {
545 std::vector<TString> fieldNames;
546 fieldNames.push_back(field1Name);
547 fieldNames.push_back(field2Name);
548
549 if (field3Name.Length() > 0) {
550 fieldNames.push_back(field3Name);
551 }
552 if (field4Name.Length() > 0) {
553 fieldNames.push_back(field4Name);
554 }
555
556 this->defineComposite(name, fieldNames);
557}
558
559void ShipFieldMaker::defineComposite(const TString& name,
560 std::vector<TString> fieldNames) {
561 // Check if the field is already in the map
562 if (!this->gotField(name)) {
563 // Loop over the list of fields and add them to the composite
564 std::vector<TVirtualMagField*> vectFields;
565
566 std::vector<TString>::iterator iter;
567 for (iter = fieldNames.begin(); iter != fieldNames.end(); ++iter) {
568 TString aName = *iter;
569 TVirtualMagField* aField = this->getField(aName);
570 if (aField) {
571 if (verbose_) {
572 std::cout << "Adding field " << aName << std::endl;
573 }
574 vectFields.push_back(aField);
575 }
576
577 ShipCompField* composite = new ShipCompField(name.Data(), vectFields);
578 theFields_[name] = composite;
579 }
580
581 } else {
582 std::cout << "We already have a composite field with the name "
583 << name.Data() << std::endl;
584 }
585}
586
588 // Define the global field using the input file line
589
590 size_t nWords = inputLine.size();
591
592 // Expecting the line:
593 // Global Field1 ... FieldN
594
595 if (nWords > 1) {
596 TString name("Global");
597
598 std::vector<TString> fieldNames;
599 for (size_t i = 1; i < nWords; i++) {
600 TString aName(inputLine[i].c_str());
601 fieldNames.push_back(aName);
602 }
603
604 this->defineGlobalField(fieldNames);
605
606 } else {
607 std::cout
608 << "Expecting at least two words for the global field definition: "
609 << "Global Field1 ... FieldN" << std::endl;
610 }
611}
612
613void ShipFieldMaker::defineGlobalField(const TString& field1Name,
614 const TString& field2Name,
615 const TString& field3Name,
616 const TString& field4Name) {
617 std::vector<TString> fieldNames;
618 fieldNames.push_back(field1Name);
619
620 if (field2Name.Length() > 0) {
621 fieldNames.push_back(field2Name);
622 }
623 if (field3Name.Length() > 0) {
624 fieldNames.push_back(field3Name);
625 }
626 if (field4Name.Length() > 0) {
627 fieldNames.push_back(field4Name);
628 }
629
630 this->defineGlobalField(fieldNames);
631}
632
633void ShipFieldMaker::defineGlobalField(std::vector<TString> fieldNames) {
634 if (globalField_) {
635 if (verbose_) {
636 std::cout << "Deleting already existing Global field" << std::endl;
637 }
638 delete globalField_;
639 }
640
641 if (verbose_) {
642 std::cout << "Setting the Global field" << std::endl;
643 }
644
645 std::vector<TVirtualMagField*> vectFields;
646
647 std::vector<TString>::iterator iter;
648 for (iter = fieldNames.begin(); iter != fieldNames.end(); ++iter) {
649 TString aName = *iter;
650 TVirtualMagField* aField = this->getField(aName);
651
652 if (aField) {
653 if (verbose_) {
654 std::cout << "Adding field " << aName << " to Global" << std::endl;
655 }
656 vectFields.push_back(aField);
657 } else {
658 std::cout << "Could not find the field " << aName << std::endl;
659 }
660 }
661
662 TString name("Global");
663 globalField_ = new ShipCompField(name.Data(), vectFields);
664
665 // Set this as the global field in the virtual MC
666 if (gMC) {
667 gMC->SetMagField(globalField_);
668 } else {
669 std::cout
670 << "The virtual MC pointer gMC is null! The global field can't be used "
671 "by Geant4 but will work for track fitting and track extrapolation"
672 << std::endl;
673 }
674}
675
677 // Set the local + global field for the region using info from inputLine
678 size_t nWords = inputLine.size();
679
680 // Expecting the line:
681 // Region VolName FieldName [FieldMapScaleFactor]
682
683 if (nWords == 3 || nWords == 4) {
684 TString volName(inputLine[1].c_str());
685 TString fieldName(inputLine[2].c_str());
686
687 Double_t scale(1.0);
688 if (nWords == 4) {
689 scale = std::atof(inputLine[3].c_str());
690 }
691
692 this->defineRegionField(volName, fieldName, scale);
693
694 } else {
695 std::cout << "Expecting 3 or 4 words for the region (local + global) field "
696 "definition: "
697 << "Region VolName LocalFieldName [LocalFieldMapScale]"
698 << std::endl;
699 }
700}
701
702void ShipFieldMaker::defineRegionField(const TString& volName,
703 const TString& fieldName,
704 Double_t scale) {
705 if (verbose_) {
706 std::cout << "ShipFieldMaker::defineRegionField for volume "
707 << volName.Data() << " and field " << fieldName.Data()
708 << " with scale = " << scale << std::endl;
709 }
710
711 fieldInfo theInfo(volName, fieldName, scale);
712 regionInfo_.push_back(theInfo);
713}
714
716 // Loop over all entries in the regionInfo_ vector and assign fields to their
717 // volumes
718 std::vector<fieldInfo>::iterator regionIter;
719
720 for (regionIter = regionInfo_.begin(); regionIter != regionInfo_.end();
721 ++regionIter) {
722 fieldInfo theInfo = *regionIter;
723 const TString volName = theInfo.volName_;
724 TString fieldName = theInfo.fieldName_;
725 Double_t scale = theInfo.scale_;
726
727 // Find the volume
728 TGeoVolume* theVol(0);
729 if (gGeoManager) {
730 theVol = gGeoManager->FindVolumeFast(volName.Data());
731 }
732
733 if (theVol) {
734 // Find the local field
735 TVirtualMagField* localField = this->getField(fieldName);
736
737 if (localField) {
738 // Check local field maps know about their associated volume position
739 // and orientation. This will update the localField pointer if required
740 this->checkLocalFieldMap(localField, volName, scale);
741
742 // Reset the fieldName to use the name from the localField pointer,
743 // since this could have changed for a local field map, for example
744 fieldName = localField->GetName();
745
746 // See if we have already combined this local field with the global
747 // field
748 if (globalField_ && fieldName.Length() > 0) {
749 TString lgName(fieldName);
750 lgName += "Global";
751 TVirtualMagField* lgField = this->getField(lgName);
752
753 if (!lgField) {
754 // Create the combined local + global field and store in the
755 // internal map. Other volumes that use the same combined field will
756 // use the stored pointer
757 if (verbose_) {
758 std::cout << "Creating the combined field " << lgName.Data()
759 << ", with local field " << fieldName.Data()
760 << " with the global field for volume "
761 << volName.Data() << std::endl;
762 }
763
764 ShipCompField* combField =
765 new ShipCompField(lgName.Data(), localField, globalField_);
766 theFields_[lgName] = combField;
767 theVol->SetField(combField);
768
769 } else {
770 if (verbose_) {
771 std::cout << "Setting the field " << lgName.Data()
772 << " for volume " << volName.Data() << std::endl;
773 }
774 theVol->SetField(lgField);
775 }
776
777 } else {
778 if (verbose_) {
779 std::cout << "There is no global field defined. Just setting the "
780 "local field"
781 << std::endl;
782 }
783 theVol->SetField(localField);
784 }
785
786 } else {
787 std::cout << "Could not find the local field " << fieldName.Data()
788 << std::endl;
789 }
790
791 } else {
792 std::cout << "Could not find the volume " << volName << std::endl;
793 }
794
795 } // regionIter loop
796}
797
799 // Set only the local field for the region using info from inputLine
800 size_t nWords = inputLine.size();
801
802 // Expecting the line:
803 // Local VolName FieldName [FieldMapScaleFactor]
804
805 if (nWords == 3 || nWords == 4) {
806 TString volName(inputLine[1].c_str());
807 TString fieldName(inputLine[2].c_str());
808
809 Double_t scale(1.0);
810 if (nWords == 4) {
811 scale = std::atof(inputLine[3].c_str());
812 }
813
814 this->defineLocalField(volName, fieldName, scale);
815
816 } else {
817 std::cout << "Expecting 3 or 4 words for the local field definition: "
818 << "Local VolName LocalFieldName [FieldMapScale]" << std::endl;
819 }
820}
821
822void ShipFieldMaker::defineLocalField(const TString& volName,
823 const TString& fieldName,
824 Double_t scale) {
825 if (verbose_) {
826 std::cout << "ShipFieldMaker::defineLocalField for volume "
827 << volName.Data() << " and field " << fieldName.Data()
828 << " with scale = " << scale << std::endl;
829 }
830
831 fieldInfo theInfo(volName, fieldName, scale);
832 localInfo_.push_back(theInfo);
833}
834
836 // Loop over all entries in the localInfo_ vector and assign fields to their
837 // volumes
838 std::vector<fieldInfo>::iterator localIter;
839
840 for (localIter = localInfo_.begin(); localIter != localInfo_.end();
841 ++localIter) {
842 fieldInfo theInfo = *localIter;
843 const TString volName = theInfo.volName_;
844 TString fieldName = theInfo.fieldName_;
845 Double_t scale = theInfo.scale_;
846
847 TGeoVolume* theVol(0);
848 if (gGeoManager) {
849 theVol = gGeoManager->FindVolumeFast(volName.Data());
850 }
851
852 if (theVol) {
853 TVirtualMagField* localField = this->getField(fieldName);
854
855 if (localField) {
856 this->checkLocalFieldMap(localField, volName, scale);
857 theVol->SetField(localField);
858
859 if (verbose_) {
860 std::cout << "Setting local field " << localField->GetName()
861 << " for volume " << volName << std::endl;
862 }
863
864 } else {
865 std::cout << "Could not find the field " << fieldName.Data()
866 << std::endl;
867 }
868
869 } else {
870 std::cout << "Could not find the volume " << volName.Data() << std::endl;
871 }
872
873 } // localIter loop
874}
875
876void ShipFieldMaker::checkLocalFieldMap(TVirtualMagField*& localField,
877 const TString& volName,
878 Double_t scale) {
879 // We assume that local field maps are stored using coordinates centred
880 // on the volume. However, GetField() uses global coordinates, so we need
881 // to find the global volume transformation (translation and rotation) so
882 // that we can find the equivalent local coordinates. This also means that
883 // each local volume needs to have its own lightweight field map copy, where
884 // we reuse the field map data but just change the coordinate transformation
885 // info
886
887 ShipBFieldMap* mapField = dynamic_cast<ShipBFieldMap*>(localField);
888 if (mapField) {
889 TString fieldName(mapField->GetName());
890 TString localName(fieldName);
891 localName += volName;
892
893 if (verbose_) {
894 std::cout << "Checking local field map " << fieldName
895 << " co-ord transformation for volume " << volName << std::endl;
896 }
897
898 // Check if we already have the local map to avoid duplication
899 ShipBFieldMap* localMap =
900 dynamic_cast<ShipBFieldMap*>(this->getField(localName));
901
902 if (!localMap && volName.Length() > 0) {
903 // Get the volume and its associate global transformation
904 TString volName1(volName);
905 volName1 += "_1";
906
907 transformInfo theInfo;
908 this->getTransformation(volName1, theInfo);
909
910 // The original field map may have defined its own translation and
911 // rotation. Apply this before the volume global transformation
912 Double_t origX0 = mapField->GetXOffset();
913 Double_t origY0 = mapField->GetYOffset();
914 Double_t origZ0 = mapField->GetZOffset();
915 TGeoTranslation origTrans("origTrans", origX0, origY0, origZ0);
916
917 Double_t origPhi = mapField->GetPhi();
918 Double_t origTheta = mapField->GetTheta();
919 Double_t origPsi = mapField->GetPsi();
920 TGeoRotation origRot("origRot", origPhi, origTheta, origPsi);
921
922 TGeoCombiTrans origComb(origTrans, origRot);
923 if (verbose_) {
924 std::cout << "The original field map transformation:" << std::endl;
925 origComb.Print();
926 }
927
928 TGeoTranslation newTrans("newTrans", theInfo.x0_, theInfo.y0_,
929 theInfo.z0_);
930 TGeoRotation newRot("newRot", theInfo.phi_, theInfo.theta_, theInfo.psi_);
931
932 TGeoCombiTrans newComb(newTrans, newRot);
933
934 if (verbose_) {
935 std::cout << "The volume transformation:" << std::endl;
936 newComb.Print();
937 }
938
939 // The full transformation
940 newComb = newComb * origComb;
941
942 if (verbose_) {
943 std::cout << "The combined transformation:" << std::endl;
944 newComb.Print();
945 }
946
947 // Update transformation info
948 const Double_t* newTransArray = newComb.GetTranslation();
949 theInfo.x0_ = newTransArray[0];
950 theInfo.y0_ = newTransArray[1];
951 theInfo.z0_ = newTransArray[2];
952
953 const TGeoRotation* fullRot = newComb.GetRotation();
954 if (fullRot) {
955 fullRot->GetAngles(theInfo.phi_, theInfo.theta_, theInfo.psi_);
956 }
957
958 // Create a lightweight copy, reusing the map data but just updating
959 // the global transformation
960 if (verbose_) {
961 std::cout << "Creating field map copy for " << localName << " based on "
962 << mapField->GetName() << ": x0 = " << theInfo.x0_
963 << ", y0 = " << theInfo.y0_ << ", z0 = " << theInfo.z0_
964 << ", phi = " << theInfo.phi_
965 << ", theta = " << theInfo.theta_
966 << ", psi = " << theInfo.psi_ << ", scale = " << scale
967 << " and symmetry = " << mapField->HasSymmetry() << std::endl;
968 }
969
970 localMap = new ShipBFieldMap(localName.Data(), *mapField, theInfo.x0_,
971 theInfo.y0_, theInfo.z0_, theInfo.phi_,
972 theInfo.theta_, theInfo.psi_, scale);
973 // Keep track that we have created this field pointer
974 theFields_[localName] = localMap;
975 }
976
977 // Set the localField pointer to use the (new or already existing) localMap
978 // pointer
979 localField = localMap;
980 }
981}
982
983void ShipFieldMaker::getTransformation(const TString& volName,
984 transformInfo& theInfo) {
985 // Find the geometry node that matches the volume name. We need to search
986 // the geometry hierarchy recursively until we get a match. Note that nodes
987 // have "_1" appended to the volume name.
988
989 theInfo.x0_ = 0.0;
990 theInfo.y0_ = 0.0;
991 theInfo.z0_ = 0.0;
992 theInfo.phi_ = 0.0;
993 theInfo.theta_ = 0.0;
994 theInfo.psi_ = 0.0;
995
996 TGeoMatrix* theMatrix(0);
997
998 TGeoVolume* topVolume = gGeoManager->GetTopVolume();
999 if (!topVolume) {
1000 std::cout
1001 << "Can't find the top volume in ShipFieldMaker::getTransformation"
1002 << std::endl;
1003 return;
1004 }
1005
1006 if (verbose_) {
1007 std::cout << "Finding transformation for " << volName << std::endl;
1008 }
1009
1010 // Find the geometry node that matches the required name
1011 theNode_ = 0;
1012 gotNode_ = kFALSE;
1013 this->findNode(topVolume, volName);
1014
1015 if (theNode_) {
1016 theMatrix = theNode_->GetMatrix();
1017 }
1018
1019 // Retrieve the translation and rotation information
1020 if (theMatrix) {
1021 // Translation displacement components
1022 const Double_t* theTrans = theMatrix->GetTranslation();
1023 theInfo.x0_ = theTrans[0];
1024 theInfo.y0_ = theTrans[1];
1025 theInfo.z0_ = theTrans[2];
1026
1027 // Euler rotation angles. First check if we have a combined translation
1028 // and rotation, then check if we just have a pure rotation
1029 if (theMatrix->IsCombi()) {
1030 TGeoCombiTrans* theCombi = dynamic_cast<TGeoCombiTrans*>(theMatrix);
1031 if (theCombi) {
1032 TGeoRotation* combRotn = theCombi->GetRotation();
1033 if (combRotn) {
1034 combRotn->GetAngles(theInfo.phi_, theInfo.theta_, theInfo.psi_);
1035 }
1036 }
1037
1038 } else if (theMatrix->IsRotation()) {
1039 TGeoRotation* theRotn = dynamic_cast<TGeoRotation*>(theMatrix);
1040 if (theRotn) {
1041 theRotn->GetAngles(theInfo.phi_, theInfo.theta_, theInfo.psi_);
1042 }
1043 }
1044 }
1045}
1046
1047void ShipFieldMaker::findNode(TGeoVolume* aVolume, const TString& volName) {
1048 // Find the geometry node that matches the required volume name
1049
1050 // Immediately exit the function if we have already found the volume
1051 if (gotNode_) {
1052 return;
1053 }
1054
1055 if (aVolume) {
1056 TObjArray* volNodes = aVolume->GetNodes();
1057
1058 if (volNodes) {
1059 // Loop over the geometry nodes
1060 int nNodes = volNodes->GetEntries();
1061 for (int i = 0; i < nNodes; i++) {
1062 TGeoNode* node = dynamic_cast<TGeoNode*>(volNodes->At(i));
1063
1064 if (node) {
1065 const TString nodeName(node->GetName());
1066 if (!nodeName.CompareTo(volName, TString::kExact)) {
1067 // We have a match. The node has the transformation we need
1068 theNode_ = node;
1069 gotNode_ = kTRUE;
1070 break;
1071
1072 } else if (node->GetNodes()) {
1073 // We have sub-volumes. Recursively call this function
1074 this->findNode(node->GetVolume(), volName);
1075 }
1076 }
1077 }
1078 }
1079 }
1080}
1081
1082TVirtualMagField* ShipFieldMaker::getVolumeField(const TString& volName) const {
1083 TVirtualMagField* theField(0);
1084 TGeoVolume* theVol(0);
1085 if (gGeoManager) {
1086 theVol = gGeoManager->FindVolumeFast(volName.Data());
1087 }
1088
1089 if (theVol) {
1090 // Need to cast the TObject* to a TVirtualMagField*
1091 theField = dynamic_cast<TVirtualMagField*>(theVol->GetField());
1092 }
1093
1094 return theField;
1095}
1096
1097Bool_t ShipFieldMaker::gotField(const TString& name) const {
1098 Bool_t result(kFALSE);
1099
1100 // Iterate over the internal map and see if we have a match
1101 SFMap::const_iterator iter;
1102 for (iter = theFields_.begin(); iter != theFields_.end(); ++iter) {
1103 TString key = iter->first;
1104 TVirtualMagField* theField = iter->second;
1105
1106 // Check that we have the key already stored and the pointer is not null
1107 if (!key.CompareTo(name, TString::kExact) && theField) {
1108 result = kTRUE;
1109 break;
1110 }
1111 }
1112
1113 return result;
1114}
1115
1116TVirtualMagField* ShipFieldMaker::getField(const TString& name) const {
1117 TVirtualMagField* theField(0);
1118
1119 // Iterate over the internal map and see if we have a match
1120 SFMap::const_iterator iter;
1121 for (iter = theFields_.begin(); iter != theFields_.end(); ++iter) {
1122 TString key = iter->first;
1123 TVirtualMagField* BField = iter->second;
1124
1125 // Check that we have the key already stored
1126 if (!key.CompareTo(name, TString::kExact)) {
1127 theField = BField;
1128 break;
1129 }
1130 }
1131
1132 return theField;
1133}
1134
1135void ShipFieldMaker::plotXYField(const TVector3& xAxis, const TVector3& yAxis,
1136 const std::string& plotFile) const {
1137 this->plotField(0, xAxis, yAxis, plotFile);
1138}
1139
1140void ShipFieldMaker::plotZXField(const TVector3& zAxis, const TVector3& xAxis,
1141 const std::string& plotFile) const {
1142 this->plotField(1, zAxis, xAxis, plotFile);
1143}
1144
1145void ShipFieldMaker::plotZYField(const TVector3& zAxis, const TVector3& yAxis,
1146 const std::string& plotFile) const {
1147 this->plotField(2, zAxis, yAxis, plotFile);
1148}
1149
1150void ShipFieldMaker::plotField(Int_t type, const TVector3& xAxis,
1151 const TVector3& yAxis,
1152 const std::string& plotFile) const {
1153 std::cout << "ShipFieldMaker plotField " << plotFile << ": type = " << type
1154 << std::endl;
1155
1156 Double_t xMin = xAxis(0);
1157 Double_t xMax = xAxis(1);
1158 Double_t dx = xAxis(2);
1159 Int_t Nx(0);
1160 if (dx > 0.0) {
1161 Nx = std::lround((xMax - xMin) / dx);
1162 }
1163
1164 Double_t yMin = yAxis(0);
1165 Double_t yMax = yAxis(1);
1166 Double_t dy = yAxis(2);
1167 Int_t Ny(0);
1168 if (dy > 0.0) {
1169 Ny = std::lround((yMax - yMin) / dy);
1170 }
1171
1172 // Create a 2d histogram
1173 const int nhistograms = 4; // x,y,z,and magnitude
1174 const int ncoordinates = 3; // x,y,z
1175
1176 TH2D theHist[nhistograms];
1177 std::string titles[nhistograms] = {"Bx (T)", "By (T)", "Bz (T)", "B (T)"};
1178 for (int icomponent = 0; icomponent < nhistograms; icomponent++) {
1179 theHist[icomponent] =
1180 TH2D(Form("theHist[%i]", icomponent), titles[icomponent].data(), Nx,
1181 xMin, xMax, Ny, yMin, yMax);
1182 theHist[icomponent].SetDirectory(0);
1183 if (type == 0) {
1184 // x-y
1185 theHist[icomponent].SetXTitle("x (cm)");
1186 theHist[icomponent].SetYTitle("y (cm)");
1187 } else if (type == 1) {
1188 // z-x
1189 theHist[icomponent].SetXTitle("z (cm)");
1190 theHist[icomponent].SetYTitle("x (cm)");
1191 } else if (type == 2) {
1192 // z-y
1193 theHist[icomponent].SetXTitle("z (cm)");
1194 theHist[icomponent].SetYTitle("y (cm)");
1195 }
1196 }
1197
1198 // Loop over "x" axis
1199 for (Int_t ix = 0; ix < Nx; ix++) {
1200 Double_t x = dx * ix + xMin;
1201
1202 // Loop over "y" axis
1203 for (Int_t iy = 0; iy < Ny; iy++) {
1204 Double_t y = dy * iy + yMin;
1205
1206 // Initialise the B field array to zero
1207 Double_t B[ncoordinates] = {0.0, 0.0, 0.0};
1208
1209 // Initialise the position array to zero
1210 Double_t position[ncoordinates] = {0.0, 0.0, 0.0};
1211 if (type == 0) {
1212 // x-y
1213 position[0] = x, position[1] = y;
1214 } else if (type == 1) {
1215 // z-x
1216 position[0] = y, position[2] = x;
1217 } else if (type == 2) {
1218 // z-y
1219 position[1] = y;
1220 position[2] = x;
1221 }
1222
1223 // Find out if the point is inside one of the geometry volumes
1224 Bool_t inside(kFALSE);
1225
1226 // Find the geometry node (volume path)
1227 TGeoNode* theNode =
1228 gGeoManager->FindNode(position[0], position[1], position[2]);
1229
1230 if (theNode) {
1231 // Get the volume
1232 TGeoVolume* theVol = theNode->GetVolume();
1233
1234 if (theVol) {
1235 // Get the magnetic field
1236 TVirtualMagField* theField =
1237 dynamic_cast<TVirtualMagField*>(theVol->GetField());
1238
1239 if (theField) {
1240 // Find the "local" field inside the volume (using global co-ords)
1241 theField->Field(position, B);
1242 inside = kTRUE;
1243
1244 } // theField
1245
1246 } // volume
1247
1248 } // node
1249
1250 // If no local volumes found, use global field if it exists
1251 if (inside == kFALSE && globalField_) {
1252 globalField_->Field(position, B);
1253 }
1254
1255 // Divide by the Tesla_ factor, since we want to plot Tesla_ not kGauss
1256 // (VMC/FairRoot units)
1257 for (int icomponent = 0; icomponent < ncoordinates; icomponent++) {
1258 theHist[icomponent].Fill(x, y, B[icomponent] / Tesla_);
1259 }
1260 Double_t BMag = sqrt(B[0] * B[0] + B[1] * B[1] + B[2] * B[2]) / Tesla_;
1261 theHist[3].Fill(x, y, BMag);
1262
1263 } // "y" axis
1264
1265 } // "x" axis
1266
1267 Bool_t wasBatch = gROOT->IsBatch();
1268 // Disable pop-up windows
1269 gROOT->SetBatch(kTRUE);
1270 TCanvas theCanvas("theCanvas", "", 900, 700);
1271 gROOT->SetStyle("Plain");
1272 gStyle->SetOptStat(0);
1273 // Set colour style
1274 gStyle->SetPalette(kBird);
1275 theCanvas.UseCurrentStyle();
1276
1277 theCanvas.Divide(2, 2);
1278 for (int icomponent = 0; icomponent < nhistograms; icomponent++) {
1279 theCanvas.cd(icomponent + 1);
1280 theHist[icomponent].Draw("colz");
1281 }
1282 theCanvas.Print(plotFile.c_str());
1283
1284 // Reset the batch boolean
1285 if (wasBatch == kFALSE) {
1286 gROOT->SetBatch(kFALSE);
1287 }
1288}
1289
1290void ShipFieldMaker::generateFieldMap(TString fileName, const float step,
1291 const float xRange, const float yRange,
1292 const float zRange, const float zShift) {
1293 std::ofstream myfile;
1294 myfile.open(fileName);
1295 int xSteps = ceil(xRange / step) + 1; // field map has X range from 0 to xMax
1296 int ySteps = ceil(yRange / step) + 1; // from 0 up to yMax
1297 int zSteps = ceil(zRange * 2. / step) + 1; // from -zMax up to zMax
1298 Double_t position[3] = {0.0, 0.0, 0.0};
1299 myfile << xSteps << " " << ySteps << " " << zSteps << " " << step
1300 << " " << xRange << " " << yRange << " " << zRange
1301 << std::endl;
1302 for (int i = 0; i < xSteps; i++) {
1303 for (int k = 0; k < ySteps; k++) {
1304 for (int m = 0; m < zSteps; m++) {
1305 Double_t B[3] = {0.0, 0.0, 0.0};
1306 Double_t x = step * i;
1307 Double_t y = step * k;
1308 Double_t z = m * step - zRange + zShift;
1309 position[0] = x;
1310 position[1] = y;
1311 position[2] = z;
1312 Bool_t inside(kFALSE);
1313 TGeoNode* theNode =
1314 gGeoManager->FindNode(position[0], position[1], position[2]);
1315 if (theNode) {
1316 TGeoVolume* theVol = theNode->GetVolume();
1317 if (theVol) {
1318 TVirtualMagField* theField =
1319 dynamic_cast<TVirtualMagField*>(theVol->GetField());
1320 if (theField) {
1321 theField->Field(position, B);
1322 inside = kTRUE;
1323 }
1324 }
1325 }
1326 if (inside == kFALSE && globalField_) {
1327 globalField_->Field(position, B);
1328 }
1329 myfile << x << " " << y << " " << z << " " << B[0] / Tesla_
1330 << " " << B[1] / Tesla_ << " " << B[2] / Tesla_
1331 << std::endl;
1332 }
1333 }
1334 }
1335 myfile.close();
1336}
1337
1339 std::string& theString, std::string& splitter) const {
1340 // Code from STLplus
1341 stringVect result;
1342
1343 if (!theString.empty() && !splitter.empty()) {
1344 for (std::string::size_type offset = 0;;) {
1345 std::string::size_type found = theString.find(splitter, offset);
1346
1347 if (found != std::string::npos) {
1348 std::string tmpString = theString.substr(offset, found - offset);
1349 if (tmpString.size() > 0) {
1350 result.push_back(tmpString);
1351 }
1352 offset = found + splitter.size();
1353 } else {
1354 std::string tmpString =
1355 theString.substr(offset, theString.size() - offset);
1356 if (tmpString.size() > 0) {
1357 result.push_back(tmpString);
1358 }
1359 break;
1360 }
1361 }
1362 }
1363
1364 return result;
1365}
Double_t m
Definition: diagrams_b.h:4
Class that defines a (3d) magnetic field map (distances in cm, fields in tesla)
Definition: ShipBFieldMap.h:20
Bool_t HasSymmetry() const
Get the boolean flag to specify if we have quadrant symmetry.
Float_t GetYOffset() const
Get the y offset coordinate of the map for global positioning.
Float_t GetTheta() const
Float_t GetPsi() const
Float_t GetPhi() const
Get the first Euler rotation angle about the z axis for global positioning.
Float_t GetXOffset() const
Get the x offset coordinate of the map for global positioning.
Float_t GetZOffset() const
Get the z offset coordinate of the map for global positioning.
void IncludeTarget(Double_t xy, Double_t z, Double_t l)
Class that defines a magnetic field composed from many fields.
Definition: ShipCompField.h:19
virtual void Field(const Double_t *position, Double_t *B)
void defineFieldMap(const TString &name, const TString &mapFileName, const TVector3 &localCentre=TVector3(0.0, 0.0, 0.0), const TVector3 &localAngles=TVector3(0.0, 0.0, 0.0), Bool_t useSymmetry=kFALSE)
std::vector< fieldInfo > localInfo_
Vector of fieldInfo for local fields.
Bool_t gotField(const TString &name) const
Check if we have a field stored with the given name name.
void findNode(TGeoVolume *aVolume, const TString &volName)
void defineComposite(const TString &name, const TString &field1Name, const TString &field2Name, const TString &field3Name="", const TString &field4Name="")
Define a composite field from up to four fields.
void plotField(Int_t type, const TVector3 &xAxis, const TVector3 &yAxis, const std::string &plotFile) const
Plot the magnetic field in "x-y" plane.
Bool_t gotNode_
Boolean to specify if we have found the volume node we need.
SFMap theFields_
The map storing all created magnetic fields.
TVirtualMagField * getField(const TString &name) const
Get the field stored with the given name name.
void plotZYField(const TVector3 &zAxis, const TVector3 &yAxis, const std::string &plotFile) const
Plot the magnetic field in z-y plane.
ShipFieldMaker(Bool_t verbose=kFALSE)
Constructor.
ShipCompField * globalField_
The global magnetic field.
std::vector< fieldInfo > regionInfo_
Vector of fieldInfo for regional fields.
std::vector< std::string > stringVect
Typedef of a vector of strings.
void getTransformation(const TString &volName, transformInfo &theInfo)
Get the transformation matrix for the volume position and orientation.
void readInputFile(const std::string &inputFile)
Read an input file to define fields and associated volumes.
TGeoNode * theNode_
The current volume node: used for finding volume transformations.
void plotXYField(const TVector3 &xAxis, const TVector3 &yAxis, const std::string &plotFile) const
Plot the magnetic field in x-y plane.
Double_t Tesla_
Double converting Tesla to kiloGauss (for VMC/FairRoot B field units)
TVirtualMagField * getVolumeField(const TString &volName) const
Get the magnetic field for the given volume.
void defineGlobalField(const TString &field1Name, const TString &field2Name="", const TString &field3Name="", const TString &field4Name="")
Define a composite field from up to four fields.
void defineLocalField(const TString &volName, const TString &fieldName, Double_t scale=1.0)
Define a localised field and volume pairing.
Bool_t verbose_
Verbose boolean.
void defineUniform(const TString &name, const TVector3 &BVector)
Define a uniform field.
virtual void Construct()
Set-up all local and regional fields and assign them to volumes.
virtual ~ShipFieldMaker()
Destructor.
void defineBell(const TString &name, Double_t BPeak, Double_t zMiddle, Int_t orient=1, Double_t tubeR=500.0, Double_t xy=0.0, Double_t z=0.0, Double_t L=0.0)
Define a Bell field.
void defineFieldMapCopy(const TString &name, const TString &mapNameToCopy, const TVector3 &translation, const TVector3 &eulerAngles=TVector3(0.0, 0.0, 0.0))
void defineConstant(const TString &name, const TVector2 &xRange, const TVector2 &yRange, const TVector2 &zRange, const TVector3 &BVector)
Define a constant field.
stringVect splitString(std::string &theString, std::string &splitter) const
Split a string.
void checkLocalFieldMap(TVirtualMagField *&localField, const TString &volName, Double_t scale)
void plotZXField(const TVector3 &zAxis, const TVector3 &xAxis, const std::string &plotFile) const
Plot the magnetic field in z-x plane.
void defineRegionField(const TString &volName, const TString &fieldName, Double_t scale=1.0)
Define a regional (local + global) field and volume pairing.
void generateFieldMap(TString fileName, const float step=2.5, const float xRange=179, const float yRange=317, const float zRange=1515.5, const float zShift=-4996)
Structure to hold volume name, field name and field scaling factor.
TString fieldName_
The name of the field.
Double_t scale_
The field scaling factor.
TString volName_
The name of the volume.
Structure to hold transformation information.
Double_t y0_
The y translation displacement.
Double_t theta_
The second Euler rotation angle (about new X' axis)
Double_t z0_
The z translation displacement.
Double_t x0_
The x translation displacement.
Double_t phi_
The first Euler rotation angle (about Z axis)
Double_t psi_
The third Euler rotation angle (about new Z' axis)