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