REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestAxionMagneticField.cxx
1/******************** REST disclaimer ***********************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
234
235#include "TRestAxionMagneticField.h"
236
237using namespace std;
238
239#include "TRestPhysics.h"
240using namespace REST_Physics;
241
242#include "TGraph.h"
244
249
264TRestAxionMagneticField::TRestAxionMagneticField(const char* cfgFileName, string name)
265 : TRestMetadata(cfgFileName) {
266 RESTDebug << "Entering TRestAxionMagneticField constructor( cfgFileName, name )" << RESTendl;
267
268 Initialize();
269
271
273}
274
279 RESTDebug << "Entering ... TRestAxionMagneticField() destructor." << RESTendl;
280}
281
286 SetSectionName(this->ClassName());
287 SetLibraryVersion(LIBRARY_VERSION);
288
289 fCanvas = NULL;
290 fHisto = NULL;
291}
292
337TCanvas* TRestAxionMagneticField::DrawHistogram(TString projection, TString Bcomp, Int_t volIndex,
338 Double_t step, TString style, Double_t depth) {
339 Double_t step_x, step_y, step_z;
341
342 if (fCanvas != NULL) {
343 delete fCanvas;
344 fCanvas = NULL;
345 }
346
347 if (fHisto != NULL) {
348 delete fHisto;
349 fHisto = NULL;
350 }
351
352 if (volIndex < 0) volIndex = 0;
353
354 if ((unsigned int)volIndex >= GetNumberOfVolumes()) {
355 RESTError << volIndex << " corresponds to none volume index " << RESTendl;
356 RESTError << "Total number of volumes : " << GetNumberOfVolumes() << RESTendl;
357 RESTError << "Setting volIndex to the first volume" << RESTendl;
358 volIndex = 0;
359 }
360
361 if (step <= 0) {
362 step_x = fMeshSize[volIndex].X();
363 step_y = fMeshSize[volIndex].Y();
364 step_z = fMeshSize[volIndex].Z();
365 } else
366 step_x = step_y = step_z = step;
367
368 MagneticFieldVolume* vol = GetMagneticVolume(volIndex);
369 if (!vol) return fCanvas;
370
371 if (!(projection == "XY" || projection == "XZ" || projection == "YZ")) {
372 RESTError << "You entered : " << projection << " as a projection but you have to choose XY, XZ or YZ"
373 << RESTendl;
374 return fCanvas;
375 }
376
377 Double_t centerX = fPositions[volIndex][0];
378 Double_t centerY = fPositions[volIndex][1];
379 Double_t centerZ = fPositions[volIndex][2];
380
381 Double_t halfSizeX = vol->mesh.GetNetSizeX() / 2.;
382 Double_t halfSizeY = vol->mesh.GetNetSizeY() / 2.;
383 Double_t halfSizeZ = vol->mesh.GetNetSizeZ() / 2.;
384
385 Double_t xMin = centerX - halfSizeX;
386 Double_t yMin = centerY - halfSizeY;
387 Double_t zMin = centerZ - halfSizeZ;
388
389 Double_t xMax = centerX + halfSizeX;
390 Double_t yMax = centerY + halfSizeY;
391 Double_t zMax = centerZ + halfSizeZ;
392
393 Int_t nBinsX = (xMax - xMin) / step_x;
394 Int_t nBinsY = (yMax - yMin) / step_y;
395 Int_t nBinsZ = (zMax - zMin) / step_z;
396
397 Double_t x = -1, y = -1, z = -1;
398 Double_t B = 0;
399 TVector3 Bvec;
400
401 if (projection == "XY") {
402 fCanvas = new TCanvas("fCanvas", "");
403 fHisto = new TH2D("", "", nBinsX, xMin, xMax, nBinsY, yMin, yMax);
404
405 if (depth < -100000.0)
406 z = (zMin + zMax) / 2.0;
407 else if ((depth >= zMin) && (depth <= zMax))
408 z = depth;
409 else
410 RESTError << "You entered depth = " << depth << ", but you have to choose depth between " << zMin
411 << " and " << zMax << RESTendl;
412 x = xMin;
413
414 for (Int_t i = 0; i < nBinsX; i++) {
415 y = yMin;
416 for (Int_t j = 0; j < nBinsY; j++) {
417 Bvec = GetMagneticField(TVector3(x, y, z), false);
418 if (Bcomp == "X")
419 B = Bvec[0];
420 else {
421 if (Bcomp == "Y")
422 B = Bvec[1];
423 else {
424 if (Bcomp == "Z")
425 B = Bvec[2];
426 else
427 RESTError << "You entered : " << Bcomp
428 << " as a B component but you have to choose X, Y or Z" << RESTendl;
429 }
430 }
431 fHisto->Fill(x, y, B);
432 y = y + step_y;
433 }
434 x = x + step_x;
435 }
436
437 fCanvas->cd();
438 fHisto->SetBit(TH1::kNoStats);
439 fHisto->GetXaxis()->SetTitle("x (mm)");
440 fHisto->GetYaxis()->SetTitle("y (mm)");
441
442 if (Bcomp == "X") {
443 TString title = Form("B_{x} against x and y @ z = %.1f", z);
444 fHisto->SetTitle(title);
445 fCanvas->SetTitle(title);
446 }
447 if (Bcomp == "Y") {
448 TString title = Form("B_{y} against x and y @ z = %.1f", z);
449 fHisto->SetTitle(title);
450 fCanvas->SetTitle(title);
451 }
452 if (Bcomp == "Z") {
453 TString title = Form("B_{z} against x and y @ z = %.1f", z);
454 fHisto->SetTitle(title);
455 fCanvas->SetTitle(title);
456 }
457
458 fHisto->Draw(style);
459 return fCanvas;
460 }
461
462 if (projection == "XZ") {
463 TCanvas* fCanvas = new TCanvas("fCanvas", "");
464 fHisto = new TH2D("", "", nBinsX, xMin, xMax, nBinsZ, zMin, zMax);
465
466 if (depth < -100000.0)
467 y = (yMin + yMax) / 2.0;
468 else if ((depth >= yMin) && (depth <= yMax))
469 y = depth;
470 else
471 RESTError << "You entered depth = " << depth << ", but you have to choose depth between " << yMin
472 << " and " << yMax << RESTendl;
473 x = xMin;
474
475 for (Int_t i = 0; i < nBinsX; i++) {
476 z = zMin;
477 for (Int_t j = 0; j < nBinsZ; j++) {
478 Bvec = GetMagneticField(TVector3(x, y, z), false);
479 if (Bcomp == "X")
480 B = Bvec[0];
481 else {
482 if (Bcomp == "Y")
483 B = Bvec[1];
484 else {
485 if (Bcomp == "Z")
486 B = Bvec[2];
487 else
488 RESTError << "You entered : " << Bcomp
489 << " as a B component but you have to choose X, Y or Z" << RESTendl;
490 }
491 }
492 fHisto->Fill(x, z, B);
493 z = z + step_z;
494 }
495 x = x + step_x;
496 }
497
498 fCanvas->cd();
499 fHisto->SetBit(TH1::kNoStats);
500 fHisto->GetXaxis()->SetTitle("x (mm)");
501 fHisto->GetYaxis()->SetTitle("z (mm)");
502
503 if (Bcomp == "X") {
504 TString title = Form("B_{x} against x and z @ y = %.1f", y);
505 fHisto->SetTitle(title);
506 fCanvas->SetTitle(title);
507 }
508 if (Bcomp == "Y") {
509 TString title = Form("B_{y} against x and z @ y = %.1f", y);
510 fHisto->SetTitle(title);
511 fCanvas->SetTitle(title);
512 }
513 if (Bcomp == "Z") {
514 TString title = Form("B_{z} against x and z @ y = %.1f", y);
515 fHisto->SetTitle(title);
516 fCanvas->SetTitle(title);
517 }
518
519 fHisto->Draw(style);
520 return fCanvas;
521 }
522
523 if (projection == "YZ") {
524 TCanvas* fCanvas = new TCanvas("fCanvas", "");
525 fHisto = new TH2D("", "", nBinsY, yMin, yMax, nBinsZ, zMin, zMax);
526
527 if (depth < -100000.0)
528 x = (xMin + xMax) / 2.0;
529 else if ((depth >= xMin) && (depth <= xMax))
530 x = depth;
531 else
532 RESTError << "You entered depth = " << depth << ", but you have to choose depth between " << xMin
533 << " and " << xMax << RESTendl;
534 y = yMin;
535
536 for (Int_t i = 0; i < nBinsY; i++) {
537 z = zMin;
538 for (Int_t j = 0; j < nBinsZ; j++) {
539 Bvec = GetMagneticField(TVector3(x, y, z), false);
540 if (Bcomp == "X")
541 B = Bvec[0];
542 else {
543 if (Bcomp == "Y")
544 B = Bvec[1];
545 else {
546 if (Bcomp == "Z")
547 B = Bvec[2];
548 else
549 RESTError << "You entered : " << Bcomp
550 << " as a B component but you have to choose X, Y or Z" << RESTendl;
551 }
552 }
553 fHisto->Fill(y, z, B);
554 z = z + step_z;
555 }
556 y = y + step_y;
557 }
558
559 fCanvas->cd();
560 fHisto->SetBit(TH1::kNoStats);
561 fHisto->GetXaxis()->SetTitle("y (mm)");
562 fHisto->GetYaxis()->SetTitle("z (mm)");
563
564 if (Bcomp == "X") {
565 TString title = Form("B_{x} against y and z @ x = %.1f", x);
566 fHisto->SetTitle(title);
567 fCanvas->SetTitle(title);
568 }
569 if (Bcomp == "Y") {
570 TString title = Form("B_{y} against y and z @ x = %.1f", x);
571 fHisto->SetTitle(title);
572 fCanvas->SetTitle(title);
573 }
574 if (Bcomp == "Z") {
575 TString title = Form("B_{z} against y and z @ x = %.1f", x);
576 fHisto->SetTitle(title);
577 fCanvas->SetTitle(title);
578 }
579
580 fHisto->Draw(style);
581 return fCanvas;
582 }
583
584 return fCanvas;
585}
586
591TCanvas* TRestAxionMagneticField::DrawTracks(TVector3 vanishingPoint, Int_t divisions, Int_t volId) {
592 if (fCanvas != NULL) {
593 delete fCanvas;
594 fCanvas = NULL;
595 }
596 fCanvas = new TCanvas("fCanvas", "", 1600, 600);
597
598 TPad* pad1 = new TPad("pad1", "This is pad1", 0.01, 0.02, 0.99, 0.97);
599 pad1->Divide(2, 1);
600 pad1->Draw();
601
602 pad1->cd(1);
603
604 Double_t genSizeY = fBoundMax[volId].Y() * 3.;
605 Double_t genPositionZ = fPositions[volId][2] - fBoundMax[volId].Z() - 2000;
606 Double_t finalPositionZ = fPositions[volId][2] + fBoundMax[volId].Z() + 2000;
607
608 // We generate the particle at different Y-highs
609 TGraph* bBox = new TGraph();
610 bBox->SetPoint(0, fPositions[volId][2] - fBoundMax[volId].Z(),
611 fPositions[volId][1] - fBoundMax[volId].Y());
612 bBox->SetPoint(1, fPositions[volId][2] - fBoundMax[volId].Z(),
613 fPositions[volId][1] + fBoundMax[volId].Y());
614 bBox->SetPoint(2, fPositions[volId][2] + fBoundMax[volId].Z(),
615 fPositions[volId][1] + fBoundMax[volId].Y());
616 bBox->SetPoint(3, fPositions[volId][2] + fBoundMax[volId].Z(),
617 fPositions[volId][1] - fBoundMax[volId].Y());
618 bBox->SetPoint(4, fPositions[volId][2] - fBoundMax[volId].Z(),
619 fPositions[volId][1] - fBoundMax[volId].Y());
620
621 RESTDebug << "Gen position : " << genPositionZ << RESTendl;
622
623 bBox->GetXaxis()->SetLimits(genPositionZ - 500, finalPositionZ + 500);
624 bBox->GetHistogram()->SetMaximum(genSizeY + 100);
625 bBox->GetHistogram()->SetMinimum(-genSizeY - 100);
626
627 bBox->GetXaxis()->SetTitle("Z [mm]");
628 bBox->GetXaxis()->SetTitleSize(0.05);
629 bBox->GetXaxis()->SetLabelSize(0.05);
630 bBox->GetYaxis()->SetTitle("Y [mm]");
631 bBox->GetYaxis()->SetTitleOffset(1.3);
632 bBox->GetYaxis()->SetTitleSize(0.05);
633 bBox->GetYaxis()->SetLabelSize(0.05);
634 bBox->SetLineWidth(2);
635 bBox->Draw("AL");
636
637 Int_t n = 0;
638 for (Double_t y = genSizeY; y >= -genSizeY; y -= fBoundMax[volId].Y()) {
639 TVector3 position(0, y, genPositionZ);
640 TVector3 direction = (vanishingPoint - position).Unit();
641
642 std::vector<TVector3> trackBounds = this->GetFieldBoundaries(position, direction);
643 TGraph* grB = new TGraph();
644 grB->SetPoint(0, trackBounds[0].Z(), trackBounds[0].Y());
645 grB->SetPoint(1, trackBounds[1].Z(), trackBounds[1].Y());
646
647 RESTDebug << "Initial" << RESTendl;
648 RESTDebug << "-------" << RESTendl;
650
651 RESTDebug << RESTendl;
652 RESTDebug << "Start moving along" << RESTendl;
653 RESTDebug << "++++++++++++++++++" << RESTendl;
654
655 TGraph* fieldGr = new TGraph();
656 Double_t posZ = fPositions[volId][2] - fBoundMax[volId].Z() - 10;
657 Double_t delta = fBoundMax[volId][2] * 2. / divisions;
658
659 Double_t field = this->GetTransversalComponent(position, direction);
660 fieldGr->SetPoint(fieldGr->GetN(), posZ, field);
661
662 while (posZ <= fPositions[volId][2] + fBoundMax[volId].Z()) {
663 TVector3 posAlongAxis = TVector3(fPositions[volId][0], fPositions[volId][1], posZ);
664
665 position = MoveToPlane(position, direction, TVector3(0, 0, 1), posAlongAxis);
666 Double_t field = this->GetTransversalComponent(position, direction);
667
668 fieldGr->SetPoint(fieldGr->GetN(), posZ, field);
669
670 posZ += delta;
671 }
672
673 TVector3 posAlongAxis = TVector3(fPositions[volId][0], fPositions[volId][1], posZ + 10);
674 position = MoveToPlane(position, direction, TVector3(0, 0, 1), posAlongAxis);
675
676 Double_t field2 = this->GetTransversalComponent(position, direction);
677 fieldGr->SetPoint(fieldGr->GetN(), posZ, field2);
678
679 pad1->cd(2);
680 fieldGr->SetLineWidth(3);
681 fieldGr->SetLineColor(38 + n);
682 fieldGr->GetXaxis()->SetLimits(genPositionZ - 500, finalPositionZ + 500);
683 fieldGr->GetHistogram()->SetMaximum(2.5);
684 fieldGr->GetHistogram()->SetMinimum(0);
685 fieldGr->GetXaxis()->SetTitle("Z [mm]");
686 fieldGr->GetXaxis()->SetTitleSize(0.05);
687 fieldGr->GetXaxis()->SetLabelSize(0.05);
688 fieldGr->GetYaxis()->SetTitle("B [T]");
689 fieldGr->GetYaxis()->SetTitleOffset(1.3);
690 fieldGr->GetYaxis()->SetTitleSize(0.05);
691 fieldGr->GetYaxis()->SetLabelSize(0.05);
692 if (y == genSizeY)
693 fieldGr->Draw("AL");
694 else
695 fieldGr->Draw("L");
696 pad1->cd(1);
697
698 TGraph* gr = new TGraph();
699 gr->SetPoint(0, genPositionZ, y);
700 position = MoveToPlane(position, direction, TVector3(0, 0, 1), TVector3(0, 0, finalPositionZ));
701 gr->SetPoint(1, finalPositionZ, position.Y());
702
703 gr->SetLineWidth(1.5);
704 gr->Draw("L");
705 grB->SetLineColor(38 + n);
706 n++;
707 grB->SetLineWidth(3);
708 grB->Draw("L");
709 }
710 bBox->Draw("L");
711
712 return fCanvas;
713}
714
722 std::vector<std::vector<Float_t>> data) {
723 mVol.field.resize(mVol.mesh.GetNodesX());
724 for (unsigned int n = 0; n < mVol.field.size(); n++) {
725 mVol.field[n].resize(mVol.mesh.GetNodesY());
726 for (unsigned int m = 0; m < mVol.field[n].size(); m++)
727 mVol.field[n][m].resize(mVol.mesh.GetNodesZ());
728 }
729
730 RESTDebug << "TRestAxionMagneticField::LoadMagneticFieldData. Printing first 5 data rows" << RESTendl;
731 for (unsigned int n = 0; n < data.size(); n++) {
732 // The magnetic field map is centered at zero.
733 // But the mesh definition contains the offset position
734 // We shift the data to match the mesh node network.
735 Int_t nX = mVol.mesh.GetNodeX((Int_t)(data[n][0] + mVol.mesh.GetNetSizeX() / 2.), true);
736 Int_t nY = mVol.mesh.GetNodeY((Int_t)(data[n][1] + mVol.mesh.GetNetSizeY() / 2.), true);
737 Int_t nZ = mVol.mesh.GetNodeZ((Int_t)(data[n][2] + mVol.mesh.GetNetSizeZ() / 2.), true);
738
739 if (n < 5) {
740 RESTDebug << "X: " << data[n][0] << " Y: " << data[n][1] << " Z: " << data[n][2] << RESTendl;
741 RESTDebug << "absX: " << data[n][0] + mVol.position.X()
742 << " absY: " << data[n][1] + mVol.position.Y()
743 << " absZ: " << data[n][2] + mVol.position.Z() << RESTendl;
744 RESTDebug << "nX: " << nX << " nY: " << nY << " nZ: " << nZ << RESTendl;
745 RESTDebug << "Bx: " << data[n][3] << " By: " << data[n][4] << " Bz: " << data[n][5] << RESTendl;
747 }
748
749 if (mVol.field[nX][nY][nZ] != TVector3(0.0, 0.0, 0.0)) {
750 RESTWarning << "X: " << data[n][0] << " Y: " << data[n][1] << " Z: " << data[n][2] << RESTendl;
751 RESTWarning << "nX: " << nX << " nY: " << nY << " nZ: " << nZ << RESTendl;
752 RESTWarning << "WARNING: field[nX][nY][nZ] element not equal to initial value (0, 0, 0) !!"
753 << RESTendl;
754 RESTWarning << "It has value: "
755 << "mVol.field[" << nX << "][" << nY << "][" << nZ << "] = ("
756 << mVol.field[nX][nY][nZ].X() << " , " << mVol.field[nX][nY][nZ].Y() << " , "
757 << mVol.field[nX][nY][nZ].Z() << ")" << RESTendl;
758 RESTWarning << "Values to write: "
759 << "Bx: " << data[n][3] << " By: " << data[n][4] << " Bz: " << data[n][5] << RESTendl
760 << RESTendl;
761
762 this->SetError("There was a problem assigning the field matrix!");
764 }
765
766 mVol.field[nX][nY][nZ] = TVector3(data[n][3], data[n][4], data[n][5]);
767 }
768}
769
776 for (unsigned int n = 0; n < fPositions.size(); n++) {
777 string fullPathName = SearchFile((string)fFileNames[n]);
778 RESTDebug << "Reading file : " << fFileNames[n] << RESTendl;
779 RESTDebug << "Full path : " << fullPathName << RESTendl;
780
781 if (fFileNames[n] != "none" && fullPathName == "") {
782 RESTError << "TRestAxionMagneticField::LoadMagneticVolumes. File " << fFileNames[n]
783 << " not found!" << RESTendl;
784 RESTError
785 << "REST will look for this file at any path given by <searchPath at globals definitions"
786 << RESTendl;
787 exit(5);
788 }
789
790 std::vector<std::vector<Float_t>> fieldData;
791 if (fFileNames[n] != "none")
792 if (fullPathName.find(".dat") != string::npos) {
793 RESTDebug << "Reading ASCII format" << RESTendl;
794 if (!TRestTools::ReadASCIITable(fullPathName, fieldData)) {
795 RESTError << "Problem reading file : " << fullPathName << RESTendl;
796 exit(1);
797 }
798 } else {
799 if (fullPathName.find(".bin") != string::npos) {
800 RESTDebug << "Reading binary format" << RESTendl;
801 if (!TRestTools::ReadBinaryTable(fullPathName, fieldData, 6)) {
802 RESTError << "Problem reading file : " << fullPathName << RESTendl;
803 exit(2);
804 }
805 }
806 }
807 else if (fFileNames[n] != "none") {
808 RESTError << "Filename : " << fullPathName << RESTendl;
809 RESTError << "File format not recognized!" << RESTendl;
810 exit(3);
811 }
812
813 if (fFileNames[n] != "none" && fieldData.size() < 2) {
814 RESTError << "Field data size is no more than 2 grid points!" << RESTendl;
815 RESTError << "Filename : " << fullPathName << RESTendl;
816 RESTError << "Probably something went wrong loading the file" << RESTendl;
817 exit(4);
818 }
819
820 Float_t xMin = -fBoundMax[n].X(), yMin = -fBoundMax[n].Y(), zMin = -fBoundMax[n].Z();
821 Float_t xMax = fBoundMax[n].X(), yMax = fBoundMax[n].Y(), zMax = fBoundMax[n].Z();
822 Float_t meshSizeX = fMeshSize[n].X(), meshSizeY = fMeshSize[n].Y(), meshSizeZ = fMeshSize[n].Z();
823
824 // If a field map is defined we get the boundaries, and mesh size from the volume
825 if (fieldData.size() > 0) {
826 RESTDebug << "Reading max boundary values" << RESTendl;
827 xMax = TRestTools::GetMaxValueFromTable(fieldData, 0);
828 yMax = TRestTools::GetMaxValueFromTable(fieldData, 1);
829 zMax = TRestTools::GetMaxValueFromTable(fieldData, 2);
830
831 if (fBoundMax[n] != TVector3(0, 0, 0)) {
832 if (fBoundMax[n] != TVector3(xMax, yMax, zMax)) {
833 RESTWarning << "Volume : " << n << RESTendl;
834 RESTWarning << "boundMax was defined in RML but does not match the field map boundaries!"
835 << RESTendl;
836 RESTWarning << "Max. Field map boundaries : (" << xMax << ", " << yMax << ", " << zMax
837 << ")" << RESTendl;
838 }
839 }
840
841 RESTDebug << "Reading min boundary values" << RESTendl;
842 xMin = TRestTools::GetMinValueFromTable(fieldData, 0);
843 yMin = TRestTools::GetMinValueFromTable(fieldData, 1);
844 zMin = TRestTools::GetMinValueFromTable(fieldData, 2);
845
846 if (fBoundMax[n] != TVector3(0, 0, 0)) {
847 if (-fBoundMax[n] != TVector3(xMin, yMin, zMin)) {
848 RESTWarning << "Volume : " << n << RESTendl;
849 RESTWarning << "boundMax was defined in RML but does not match the field map boundaries"
850 << RESTendl;
851 RESTWarning << "Min. Field map boundaries : (" << xMin << ", " << yMin << ", " << zMin
852 << ")" << RESTendl;
853 }
854 }
855 fBoundMax[n] = TVector3(xMax, yMax, zMax);
856
857 RESTDebug << "Reading mesh size" << RESTendl;
858 meshSizeX = TRestTools::GetLowestIncreaseFromTable(fieldData, 0);
859 meshSizeY = TRestTools::GetLowestIncreaseFromTable(fieldData, 1);
860 meshSizeZ = TRestTools::GetLowestIncreaseFromTable(fieldData, 2);
861
862 if (fMeshSize[n] != TVector3(0, 0, 0)) {
863 if (fMeshSize[n] != TVector3(meshSizeX, meshSizeY, meshSizeZ)) {
864 RESTWarning << "Volume : " << n << RESTendl;
865 RESTWarning
866 << "MeshSize was defined in RML but does not match the mesh size deduced from "
867 "field map"
868 << RESTendl;
869 RESTWarning << "Mesh size : (" << meshSizeX << ", " << meshSizeY << ", " << meshSizeZ
870 << ")" << RESTendl;
871 }
872 }
873 fMeshSize[n] = TVector3(meshSizeX, meshSizeY, meshSizeZ);
874 }
875
877 RESTDebug << "Reading magnetic field map" << RESTendl;
878 RESTDebug << "--------------------------" << RESTendl;
879
880 RESTDebug << "Full path : " << fullPathName << RESTendl;
881
882 RESTDebug << "Boundaries" << RESTendl;
883 RESTDebug << "xMin: " << xMin << " yMin: " << yMin << " zMin: " << zMin << RESTendl;
884 RESTDebug << "xMax: " << xMax << " yMax: " << yMax << " zMax: " << zMax << RESTendl;
885 RESTDebug << "Mesh size" << RESTendl;
886
887 RESTDebug << "sX: " << meshSizeX << " sY: " << meshSizeY << " sZ: " << meshSizeZ << RESTendl;
888
889 if (fieldData.size() > 4) {
890 RESTDebug << "Printing beginning of magnetic file table : " << fieldData.size() << RESTendl;
891 TRestTools::PrintTable(fieldData, 0, 5);
892 } else {
893 RESTDebug << "The data file contains no field map" << RESTendl;
894 }
895 }
897
898 // Number of nodes
899 Int_t nx = (Int_t)(2 * xMax / meshSizeX) + 1;
900 Int_t ny = (Int_t)(2 * yMax / meshSizeY) + 1;
901 Int_t nz = (Int_t)(2 * zMax / meshSizeZ) + 1;
902
903 // We create an auxiliar mesh helping to initialize the fieldMap
904 // The mesh is centered at zero. Absolute position is defined in the Magnetic volume
905 // TODO It would be interesting that TRestMesh could be used in cylindrical coordinates.
906 TRestMesh restMesh;
907 restMesh.SetSize(2 * xMax, 2 * yMax, 2 * zMax);
908 restMesh.SetOrigin(fPositions[n] - TVector3(xMax, yMax, zMax));
909 restMesh.SetNodes(nx, ny, nz);
910 if (fMeshType[n] == "cylinder")
911 restMesh.SetCylindrical(true);
912 else
913 restMesh.SetCylindrical(false);
914
915 MagneticFieldVolume mVolume;
916 mVolume.position = fPositions[n];
917 mVolume.mesh = restMesh;
918
919 if (fieldData.size() > 0) LoadMagneticFieldData(mVolume, fieldData);
920
921 if (fBoundMax[n] == TVector3(0, 0, 0)) {
922 RESTError << "The bounding box was not defined for volume " << n << "!" << RESTendl;
923 RESTError << "Please review RML configuration for TRestAxionMagneticField" << RESTendl;
924 exit(22);
925 } else if (fMeshSize[n] == TVector3(0, 0, 0)) {
926 RESTError << "The mesh grid size was not defined for volume " << n << "!" << RESTendl;
927 RESTError << "Please review RML configuration for TRestAxionMagneticField" << RESTendl;
928 exit(22);
929 }
930 fMagneticFieldVolumes.push_back(mVolume);
931 }
932
933 if (CheckOverlaps()) {
934 RESTError << "TRestAxionMagneticField::LoadMagneticVolumes. Volumes overlap!" << RESTendl;
935 exit(1);
936 }
937
938 for (size_t n = 0; n < fMagneticFieldVolumes.size(); n++)
939 if (fReMap != TVector3(0, 0, 0)) ReMap(n, fReMap);
940
941 RESTDebug << "Finished loading magnetic volumes" << RESTendl;
942}
943
947TVector3 TRestAxionMagneticField::GetMagneticField(Double_t x, Double_t y, Double_t z) {
948 return GetMagneticField(TVector3(x, y, z));
949}
950
959TVector3 TRestAxionMagneticField::GetMagneticField(TVector3 pos, Bool_t showWarning) {
960 Int_t id = GetVolumeIndex(pos);
961
962 if (id < 0) {
963 if (showWarning)
964 RESTWarning << "TRestAxionMagneticField::GetMagneticField position (" << pos.X() << ", "
965 << pos.Y() << ", " << pos.Z() << ") is outside any volume" << RESTendl;
966 return TVector3(0, 0, 0);
967 } else {
968 if (IsFieldConstant(id)) return fConstantField[id];
969 TVector3 node = GetMagneticVolumeNode(fMagneticFieldVolumes[id], pos);
970 Int_t nX = node.X();
971 Int_t nY = node.Y();
972 Int_t nZ = node.Z();
973
974 Int_t nX_1, nY_1, nZ_1;
975
976 if ((nX + 1) < fMagneticFieldVolumes[id].mesh.GetNodesX())
977 nX_1 = nX + 1;
978 else
979 nX_1 = nX;
980 if ((nY + 1) < fMagneticFieldVolumes[id].mesh.GetNodesY())
981 nY_1 = nY + 1;
982 else
983 nY_1 = nY;
984 if ((nZ + 1) < fMagneticFieldVolumes[id].mesh.GetNodesZ())
985 nZ_1 = nZ + 1;
986 else
987 nZ_1 = nZ;
988
989 TVector3 C000 = fMagneticFieldVolumes[id].field[nX][nY][nZ] + fConstantField[id];
990 TVector3 C100 = fMagneticFieldVolumes[id].field[nX_1][nY][nZ] + fConstantField[id];
991 TVector3 C010 = fMagneticFieldVolumes[id].field[nX][nY_1][nZ] + fConstantField[id];
992 TVector3 C110 = fMagneticFieldVolumes[id].field[nX_1][nY_1][nZ] + fConstantField[id];
993 TVector3 C001 = fMagneticFieldVolumes[id].field[nX][nY][nZ_1] + fConstantField[id];
994 TVector3 C101 = fMagneticFieldVolumes[id].field[nX_1][nY][nZ_1] + fConstantField[id];
995 TVector3 C011 = fMagneticFieldVolumes[id].field[nX][nY_1][nZ_1] + fConstantField[id];
996 TVector3 C111 = fMagneticFieldVolumes[id].field[nX_1][nY_1][nZ_1] + fConstantField[id];
997
998 Double_t x0 = fMagneticFieldVolumes[id].mesh.GetX(nX);
999 Double_t x1 = fMagneticFieldVolumes[id].mesh.GetX(nX_1);
1000 Double_t xd;
1001 if (x0 == x1)
1002 xd = 0;
1003 else
1004 xd = (pos.X() - x0) / (x1 - x0);
1005 if ((xd < -0.00001) || (xd > 1.00001))
1006 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: xd NOT between 0 and 1"
1007 << RESTendl;
1008
1009 Double_t y0 = fMagneticFieldVolumes[id].mesh.GetY(nY);
1010 Double_t y1 = fMagneticFieldVolumes[id].mesh.GetY(nY_1);
1011 Double_t yd;
1012 if (y0 == y1)
1013 yd = 0;
1014 else
1015 yd = (pos.Y() - y0) / (y1 - y0);
1016 if ((yd < -0.00001) || (yd > 1.00001))
1017 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: yd NOT between 0 and 1"
1018 << RESTendl;
1019
1020 Double_t z0 = fMagneticFieldVolumes[id].mesh.GetZ(nZ);
1021 Double_t z1 = fMagneticFieldVolumes[id].mesh.GetZ(nZ_1);
1022 Double_t zd;
1023 if (z0 == z1)
1024 zd = 0;
1025 else
1026 zd = (pos.Z() - z0) / (z1 - z0);
1027 if ((zd < -0.00001) || (zd > 1.00001))
1028 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: zd NOT between 0 and 1"
1029 << RESTendl;
1030
1031 // first we interpolate along x-axis
1032 TVector3 C00 = C000 * (1.0 - xd) + C100 * xd;
1033 TVector3 C01 = C001 * (1.0 - xd) + C101 * xd;
1034 TVector3 C10 = C010 * (1.0 - xd) + C110 * xd;
1035 TVector3 C11 = C011 * (1.0 - xd) + C111 * xd;
1036
1037 // then we interpolate along y-axis
1038 TVector3 C0 = C00 * (1.0 - yd) + C10 * yd;
1039 TVector3 C1 = C01 * (1.0 - yd) + C11 * yd;
1040
1041 // finally we interpolate along z-axis
1042 TVector3 C = C0 * (1.0 - zd) + C1 * zd;
1043
1044 RESTDebug << "position = (" << pos.X() << ", " << pos.Y() << ", " << pos.Z() << ") ";
1045 RESTDebug << "nX = " << nX << " nY = " << nY << " nZ = " << nZ << " nX_1 = " << nX_1
1046 << " nY_1 = " << nY_1 << " nZ_1 = " << nZ_1 << RESTendl << RESTendl;
1047 RESTDebug << "C000 = (" << C000.X() << ", " << C000.Y() << ", " << C000.Z() << ")" << RESTendl
1048 << RESTendl;
1049 RESTDebug << "C100 = (" << C100.X() << ", " << C100.Y() << ", " << C100.Z() << ")" << RESTendl
1050 << RESTendl;
1051 RESTDebug << "C010 = (" << C010.X() << ", " << C010.Y() << ", " << C010.Z() << ")" << RESTendl
1052 << RESTendl;
1053 RESTDebug << "C110 = (" << C110.X() << ", " << C110.Y() << ", " << C110.Z() << ")" << RESTendl
1054 << RESTendl;
1055 RESTDebug << "C001 = (" << C001.X() << ", " << C001.Y() << ", " << C001.Z() << ")" << RESTendl
1056 << RESTendl;
1057 RESTDebug << "C101 = (" << C101.X() << ", " << C101.Y() << ", " << C101.Z() << ")" << RESTendl
1058 << RESTendl;
1059 RESTDebug << "C011 = (" << C011.X() << ", " << C011.Y() << ", " << C011.Z() << ")" << RESTendl
1060 << RESTendl;
1061 RESTDebug << "C111 = (" << C111.X() << ", " << C111.Y() << ", " << C111.Z() << ")" << RESTendl
1062 << RESTendl;
1063 RESTDebug << " -------------------------------------------------------" << RESTendl;
1064 RESTDebug << "C00 = (" << C00.X() << ", " << C00.Y() << ", " << C00.Z() << ")" << RESTendl
1065 << RESTendl;
1066 RESTDebug << "C01 = (" << C01.X() << ", " << C01.Y() << ", " << C01.Z() << ")" << RESTendl
1067 << RESTendl;
1068 RESTDebug << "C10 = (" << C10.X() << ", " << C10.Y() << ", " << C10.Z() << ")" << RESTendl
1069 << RESTendl;
1070 RESTDebug << "C11 = (" << C11.X() << ", " << C11.Y() << ", " << C11.Z() << ")" << RESTendl
1071 << RESTendl;
1072 RESTDebug << " -------------------------------------------------------" << RESTendl;
1073 RESTDebug << "C0 = (" << C0.X() << ", " << C0.Y() << ", " << C0.Z() << ")" << RESTendl << RESTendl;
1074 RESTDebug << "C1 = (" << C1.X() << ", " << C1.Y() << ", " << C1.Z() << ")" << RESTendl << RESTendl;
1075 RESTDebug << " -------------------------------------------------------" << RESTendl;
1076 RESTDebug << "C = (" << C.X() << ", " << C.Y() << ", " << C.Z() << ")" << RESTendl << RESTendl;
1077
1078 return C;
1079 }
1080}
1081
1087void TRestAxionMagneticField::ReMap(const size_t& n, const TVector3& newMapSize) {
1088 if (newMapSize.X() == 0 || newMapSize.Y() == 0 || newMapSize.Z() == 0) {
1089 RESTError << "TRestAxionMagneticField::ReMap. The mesh granularity cannot be 0" << RESTendl;
1090 RESTError << "Remapping will not take effect" << RESTendl;
1091 return;
1092 }
1093
1094 Double_t remainder = std::fmod(newMapSize.X(), fMeshSize[n].X()) +
1095 std::fmod(newMapSize.Y(), fMeshSize[n].Y()) +
1096 std::fmod(newMapSize.Z(), fMeshSize[n].Z());
1097 if (remainder != 0) {
1098 RESTError << "TRestAxionMagneticField::ReMap. The field cannot be remapped." << RESTendl;
1099 RESTError << "The new mesh granularity must be a multiple of the existing granularity." << RESTendl;
1100 RESTError << "Present mesh size : (" << fMeshSize[n].X() << ", " << fMeshSize[n].Y() << ", "
1101 << fMeshSize[n].Z() << ")" << RESTendl;
1102 RESTError << "Requested mesh size : (" << newMapSize.X() << ", " << newMapSize.Y() << ", "
1103 << newMapSize.Z() << ")" << RESTendl;
1104 RESTError << "Remapping will not take effect" << RESTendl;
1105 return;
1106 }
1107
1108 Int_t scaleX = (Int_t)(newMapSize.X() / fMeshSize[n].X());
1109 Int_t scaleY = (Int_t)(newMapSize.Y() / fMeshSize[n].Y());
1110 Int_t scaleZ = (Int_t)(newMapSize.Z() / fMeshSize[n].Z());
1111
1112 Int_t newNodesX = (fMagneticFieldVolumes[n].mesh.GetNodesX() - 1) / scaleX + 1;
1113 Int_t newNodesY = (fMagneticFieldVolumes[n].mesh.GetNodesY() - 1) / scaleY + 1;
1114 Int_t newNodesZ = (fMagneticFieldVolumes[n].mesh.GetNodesZ() - 1) / scaleZ + 1;
1115
1116 for (Int_t nx = 0; nx < newNodesX; nx++)
1117 for (Int_t ny = 0; ny < newNodesY; ny++)
1118 for (Int_t nz = 0; nz < newNodesZ; nz++)
1119 fMagneticFieldVolumes[n].field[nx][ny][nz] =
1120 fMagneticFieldVolumes[n].field[nx * scaleX][ny * scaleY][nz * scaleZ];
1121
1122 fMagneticFieldVolumes[n].mesh.SetNodes(newNodesX, newNodesY, newNodesZ);
1123 fMagneticFieldVolumes[n].field.resize(fMagneticFieldVolumes[n].mesh.GetNodesX());
1124 for (unsigned int i = 0; i < fMagneticFieldVolumes[n].field.size(); i++) {
1125 fMagneticFieldVolumes[n].field[n].resize(fMagneticFieldVolumes[n].mesh.GetNodesY());
1126 for (unsigned int j = 0; j < fMagneticFieldVolumes[n].field[i].size(); j++)
1127 fMagneticFieldVolumes[n].field[i][j].resize(fMagneticFieldVolumes[n].mesh.GetNodesZ());
1128 }
1129
1130 fMeshSize[n] = TVector3(fMeshSize[n].X() * scaleX, fMeshSize[n].Y() * scaleY, fMeshSize[n].Z() * scaleZ);
1131}
1132
1139
1140 for (unsigned int n = 0; n < fMagneticFieldVolumes.size(); n++) {
1141 if (fMagneticFieldVolumes[n].mesh.IsInside(pos)) return n;
1142 }
1143 return -1;
1144}
1145
1150 if (GetVolumeIndex(pos) >= 0) return true;
1151 return false;
1152}
1153
1158
1163 if (id >= 0 && GetNumberOfVolumes() > (unsigned int)id)
1164 return fPositions[id];
1165 else {
1166 RESTWarning << "TRestAxionMagneticField::GetVolumePosition. Id : " << id << " out of range!"
1167 << RESTendl;
1168 RESTWarning << "Number of volumes defined : " << GetNumberOfVolumes() << RESTendl;
1169 return TVector3(0, 0, 0);
1170 }
1171}
1172
1177Double_t TRestAxionMagneticField::GetTransversalComponent(TVector3 position, TVector3 direction) {
1178 return abs(GetMagneticField(position, false).Perp(direction));
1179}
1180
1192std::vector<Double_t> TRestAxionMagneticField::GetTransversalComponentAlongPath(TVector3 from, TVector3 to,
1193 Double_t dl, Int_t Nmax) {
1194 Double_t length = (to - from).Mag();
1195
1196 Double_t diff = dl;
1197 if (Nmax > 0) {
1198 if (length / dl > Nmax) {
1199 diff = length / Nmax;
1200 RESTWarning << "TRestAxionMagneticField::GetTransversalComponentAlongPath. Nmax reached!"
1201 << RESTendl;
1202 RESTWarning << "Nmax = " << Nmax << RESTendl;
1203 RESTWarning << "Adjusting differential step to : " << diff << " mm" << RESTendl;
1204 }
1205 }
1206
1207 TVector3 direction = (to - from).Unit();
1208
1209 std::vector<Double_t> Bt;
1210 for (Double_t d = 0; d < length; d += diff) {
1211 Bt.push_back(GetTransversalComponent(from + d * direction, direction));
1212 }
1213
1214 return Bt;
1215}
1216
1221void TRestAxionMagneticField::SetTrack(const TVector3& position, const TVector3& direction) {
1222 std::vector<TVector3> trackBounds = GetFieldBoundaries(position, direction);
1223
1224 if (trackBounds.size() != 2) {
1225 fTrackStart = TVector3(0, 0, 0);
1226 fTrackDirection = TVector3(0, 0, 0);
1227 fTrackLength = 0;
1228 }
1229
1230 fTrackStart = trackBounds[0];
1231 fTrackLength = (trackBounds[1] - trackBounds[0]).Mag() - 1;
1232 fTrackDirection = (trackBounds[1] - trackBounds[0]).Unit();
1233}
1234
1244 if (x < 0 || x > fTrackLength) return 0;
1245
1247}
1248
1259Double_t TRestAxionMagneticField::GetTransversalFieldAverage(TVector3 from, TVector3 to, Double_t dl,
1260 Int_t Nmax) {
1261 Double_t Bavg = 0.;
1262 std::vector<Double_t> Bt = GetTransversalComponentAlongPath(from, to, dl, Nmax);
1263 for (auto& b : Bt) Bavg += b;
1264
1265 if (Bt.size() > 0) return Bavg / Bt.size();
1266
1267 RESTError << "TRestAxionMagneticField::GetTransversalFieldAverage. Lenght is zero!" << RESTendl;
1268 return 0.;
1269}
1270
1282TVector3 TRestAxionMagneticField::GetFieldAverageTransverseVector(TVector3 from, TVector3 to, Double_t dl,
1283 Int_t Nmax) {
1284 Double_t length = (to - from).Mag();
1285
1286 Double_t diff = dl;
1287 if (Nmax > 0) {
1288 if (length / dl > Nmax) {
1289 diff = length / Nmax;
1290 RESTWarning << "TRestAxionMagneticField::GetFieldAverageTransverseVector Nmax reached!"
1291 << RESTendl;
1292 RESTWarning << "Nmax = " << Nmax << RESTendl;
1293 RESTWarning << "Adjusting differential step to : " << diff << " mm" << RESTendl;
1294 }
1295 }
1296
1297 TVector3 direction = (to - from).Unit();
1298 TVector3 Bavg = TVector3(0.0, 0.0, 0.0);
1299 TVector3 BTavg = TVector3(0.0, 0.0, 0.0);
1300 Int_t numberofpoints = 0;
1301
1302 for (Double_t d = 0; d <= length; d += diff) {
1303 Bavg = Bavg + GetMagneticField(from + d * direction);
1304 numberofpoints = numberofpoints + 1;
1305 }
1306
1307 if ((length > 0) && (numberofpoints > 0)) {
1308 Bavg = Bavg * (1.0 / numberofpoints); // calculates the average magnetic field vector
1309 BTavg =
1310 Bavg - (Bavg * direction) *
1311 direction; // calculates the transverse component of the average magnetic field vector
1312 RESTDebug << "B average vector = (" << Bavg.x() << ", " << Bavg.y() << ", " << Bavg.z() << ")"
1313 << RESTendl;
1314 RESTDebug << "Transverse B average vector = (" << BTavg.x() << ", " << BTavg.y() << ", " << BTavg.z()
1315 << ")" << RESTendl;
1316 return BTavg;
1317 }
1318 RESTError << "TRestAxionMagneticField::GetTransversalFieldAverage. Lenght is zero!" << RESTendl;
1319 return TVector3(0.0, 0.0, 0.0);
1320}
1321
1330TVector3 TRestAxionMagneticField::GetMagneticVolumeNode(MagneticFieldVolume mVol, TVector3 pos) {
1331 Int_t nx = mVol.mesh.GetNodeX(pos.X());
1332 Int_t ny = mVol.mesh.GetNodeY(pos.Y());
1333 Int_t nz = mVol.mesh.GetNodeZ(pos.Z());
1334 return TVector3(nx, ny, nz);
1335}
1336
1341 RESTDebug << "Checking overlaps" << RESTendl;
1342 for (unsigned int n = 0; n < GetNumberOfVolumes(); n++) {
1343 for (unsigned int m = 0; m < GetNumberOfVolumes(); m++) {
1344 if (m == n) continue;
1345 RESTDebug << "Volume : " << m << RESTendl;
1346
1347 TVector3 b = GetMagneticVolume(m)->mesh.GetVertex(0);
1348 RESTDebug << "Relative bottom vertex : (" << b.X() << ", " << b.Y() << ", " << b.Z() << ")"
1349 << RESTendl;
1350 if (GetMagneticVolume(n)->mesh.IsInsideBoundingBox(b)) return true;
1351
1352 TVector3 t = GetMagneticVolume(m)->mesh.GetVertex(1);
1353 RESTDebug << "Relative top vertex : (" << t.X() << ", " << t.Y() << ", " << t.Z() << ")"
1354 << RESTendl;
1355 if (GetMagneticVolume(n)->mesh.IsInsideBoundingBox(t)) return true;
1356 }
1357 }
1358 return false;
1359}
1360
1374std::vector<TVector3> TRestAxionMagneticField::GetVolumeBoundaries(TVector3 pos, TVector3 dir, Int_t id) {
1375 MagneticFieldVolume* vol = GetMagneticVolume(id);
1376
1377 std::vector<TVector3> boundaries;
1378
1379 if (vol) boundaries = vol->mesh.GetTrackBoundaries(pos, dir);
1380
1381 return boundaries;
1382}
1383
1394std::vector<TVector3> TRestAxionMagneticField::GetFieldBoundaries(TVector3 pos, TVector3 dir,
1395 Double_t precision, Int_t id) {
1396 std::vector<TVector3> volumeBoundaries = GetVolumeBoundaries(pos, dir, id);
1397 if (volumeBoundaries.size() != 2) return volumeBoundaries;
1398
1399 if (IsFieldConstant(id)) return volumeBoundaries;
1400
1401 MagneticFieldVolume* vol = GetMagneticVolume(id);
1402 if (!vol) return volumeBoundaries;
1403
1404 if (precision == 0) precision = min(fMeshSize[id].X(), min(fMeshSize[id].Y(), fMeshSize[id].Z())) / 2.;
1405
1406 TVector3 unit = dir.Unit();
1407 std::vector<TVector3> fieldBoundaries;
1408
1409 TVector3 in = volumeBoundaries[0];
1410 while ((((volumeBoundaries[1] - in) * dir) > 0) && (GetTransversalComponent(in, dir) == 0))
1411 in = MoveByDistanceFast(in, unit, precision);
1412 if (((volumeBoundaries[1] - in) * dir) > 0)
1413 fieldBoundaries.push_back(in);
1414 else
1415 return fieldBoundaries;
1416
1417 TVector3 out = volumeBoundaries[1];
1418 while ((((volumeBoundaries[0] - out) * dir) < 0) && (GetTransversalComponent(out, -dir) == 0) &&
1419 (((out - in) * dir) > 0))
1420 out = MoveByDistanceFast(out, -unit, precision);
1421 if ((((volumeBoundaries[0] - out) * dir) < 0) && (((out - in) * dir) > 0))
1422 fieldBoundaries.push_back(out);
1423 else
1424 return fieldBoundaries;
1425
1426 return fieldBoundaries;
1427}
1428
1434
1435 auto magVolumeDef = GetElement("addMagneticVolume");
1436 while (magVolumeDef) {
1437 string filename = GetFieldValue("fileName", magVolumeDef);
1438 if (filename == "Not defined")
1439 fFileNames.push_back("none");
1440 else
1441 fFileNames.push_back(filename);
1442
1443 TVector3 position = Get3DVectorParameterWithUnits("position", magVolumeDef);
1444 if (position == TVector3(-1, -1, -1))
1445 fPositions.push_back(TVector3(0, 0, 0));
1446 else
1447 fPositions.push_back(position);
1448
1449 TVector3 field = Get3DVectorParameterWithUnits("field", magVolumeDef);
1450 if (field == TVector3(-1, -1, -1))
1451 fConstantField.push_back(TVector3(0, 0, 0));
1452 else
1453 fConstantField.push_back(field);
1454
1455 TVector3 boundMax = Get3DVectorParameterWithUnits("boundMax", magVolumeDef);
1456 if (boundMax == TVector3(-1, -1, -1))
1457 fBoundMax.push_back(TVector3(0, 0, 0));
1458 else
1459 fBoundMax.push_back(boundMax);
1460
1461 TVector3 meshSize = Get3DVectorParameterWithUnits("meshSize", magVolumeDef);
1462 if (meshSize == TVector3(-1, -1, -1))
1463 fMeshSize.push_back(TVector3(0, 0, 0));
1464 else
1465 fMeshSize.push_back(meshSize);
1466
1467 string type = GetParameter("meshType", magVolumeDef);
1468 if (type == "NO_SUCH_PARA")
1469 fMeshType.push_back("cylinder");
1470 else
1471 fMeshType.push_back(type);
1472
1473 // TRestMesh will only consider the first bounding component anyway
1474 if (fMeshType.back() == "cylinder" && fBoundMax.back().X() != fBoundMax.back().Y()) {
1475 RESTWarning << "Mesh type is cylinder. But X and Y inside boundMax are not the same!" << RESTendl;
1476 RESTWarning << "Making second bound component Y equal to the X bound component!" << RESTendl;
1477 fBoundMax.back().SetY(fBoundMax.back().X());
1478 }
1479
1480 RESTDebug << "Reading new magnetic volume" << RESTendl;
1481 RESTDebug << "-----" << RESTendl;
1482 RESTDebug << "Filename : " << filename << RESTendl;
1483 RESTDebug << "Position: ( " << position.X() << ", " << position.Y() << ", " << position.Z() << ") mm"
1484 << RESTendl;
1485 RESTDebug << "Field: ( " << field.X() << ", " << field.Y() << ", " << field.Z() << ") T" << RESTendl;
1486 RESTDebug << "Max bounding box ( " << boundMax.X() << ", " << boundMax.Y() << ", " << boundMax.Z()
1487 << ")" << RESTendl;
1488 RESTDebug << "Mesh size ( " << meshSize.X() << ", " << meshSize.Y() << ", " << meshSize.Z() << ")"
1489 << RESTendl;
1490 RESTDebug << "----" << RESTendl;
1491
1492 magVolumeDef = GetNextElement(magVolumeDef);
1493 }
1494
1496
1497 // TODO we should check that the volumes do not overlap
1498}
1499
1505
1506 if (fReMap != TVector3(0, 0, 0)) {
1507 RESTMetadata << "Fields original mesh size has been remapped" << RESTendl;
1508 RESTMetadata << " " << RESTendl;
1509 }
1510
1511 RESTMetadata << " - Number of magnetic volumes : " << GetNumberOfVolumes() << RESTendl;
1512 RESTMetadata << " ------------------------------------------------ " << RESTendl;
1513 for (unsigned int p = 0; p < GetNumberOfVolumes(); p++) {
1514 if (p > 0) RESTMetadata << " ------------------------------------------------ " << RESTendl;
1515
1516 Double_t centerX = fPositions[p][0];
1517 Double_t centerY = fPositions[p][1];
1518 Double_t centerZ = fPositions[p][2];
1519
1520 Double_t halfSizeX = fBoundMax[p].X();
1521 Double_t halfSizeY = fBoundMax[p].Y();
1522 Double_t halfSizeZ = fBoundMax[p].Z();
1523
1524 Double_t xMin = centerX - halfSizeX;
1525 Double_t yMin = centerY - halfSizeY;
1526 Double_t zMin = centerZ - halfSizeZ;
1527
1528 Double_t xMax = centerX + halfSizeX;
1529 Double_t yMax = centerY + halfSizeY;
1530 Double_t zMax = centerZ + halfSizeZ;
1531
1532 RESTMetadata << "* Volume " << p << " centered at (" << centerX << "," << centerY << "," << centerZ
1533 << ") mm" << RESTendl;
1534 RESTMetadata << " - Grid mesh element size. X: " << fMeshSize[p].X() << "mm "
1535 << " Y: " << fMeshSize[p].Y() << "mm "
1536 << " Z: " << fMeshSize[p].Z() << "mm " << RESTendl;
1537 RESTMetadata << " - Offset field [T] : (" << fConstantField[p].X() << ", " << fConstantField[p].Y()
1538 << ", " << fConstantField[p].Z() << ")" << RESTendl;
1539 RESTMetadata << " - File loaded : " << fFileNames[p] << RESTendl;
1540 RESTMetadata << " " << RESTendl;
1541 RESTMetadata << " - Bounds : " << RESTendl;
1542 RESTMetadata << " xmin : " << xMin << " mm , xmax : " << xMax << " mm" << RESTendl;
1543 RESTMetadata << " ymin : " << yMin << " mm, ymax : " << yMax << " mm" << RESTendl;
1544 RESTMetadata << " zmin : " << zMin << " mm, zmax : " << zMax << " mm" << RESTendl;
1545 RESTMetadata << " " << RESTendl;
1546 }
1547 RESTMetadata << "+++++++++++++++++++++++++++++++++++++++++++++++++" << RESTendl;
1548}
A class to load magnetic field maps and evaluate the field on those maps including interpolation.
TVector3 GetVolumeCenter(Int_t id)
it returns the volume position (or center) for the given volume id.
void PrintMetadata()
Prints on screen the information about the metadata members of TRestAxionMagneticField.
TVector3 GetVolumePosition(Int_t id)
it returns the volume position (or center) for the given volume id.
TVector3 fTrackDirection
The track direction used to parameterize the field along a track.
void InitFromConfigFile()
Initialization of TRestAxionMagnetic field members through a RML file.
Double_t fTrackLength
The total length of the track which defines the limit for field parameterization.
void LoadMagneticVolumes()
It will load the magnetic field data from the data filenames specified at the RML definition.
std::vector< TVector3 > fConstantField
A constant field component that will be added to the field map.
std::vector< TVector3 > fPositions
The absolute position of each of the magnetic volumes defined in this class.
void SetTrack(const TVector3 &position, const TVector3 &direction)
It initializes the field track boundaries data members of this class using a track position and direc...
TVector3 fReMap
A vector that defines the new mesh cell volume. It will re-scale the original fMeshSize.
std::vector< TVector3 > GetFieldBoundaries(TVector3 pos, TVector3 dir, Double_t precision=0, Int_t id=0)
Finds the in/out particle trajectory boundaries for a particular magnetic region, similar to the meth...
unsigned int GetNumberOfVolumes()
The number of magnetic volumes loaded into the object.
Bool_t CheckOverlaps()
It will return true if the magnetic the regions overlap.
TVector3 GetFieldAverageTransverseVector(TVector3 from, TVector3 to, Double_t dl=10., Int_t Nmax=0)
It returns the transverse component of the average magnetic field vector calculated along the line th...
TCanvas * DrawTracks(TVector3 vanishingPoint, Int_t divisions, Int_t volId=0)
A method that creates a canvas where tracks traversing the magnetic volume are drawm together with th...
TRestAxionMagneticField()
Default constructor.
std::vector< TVector3 > GetVolumeBoundaries(TVector3 pos, TVector3 dir, Int_t id=0)
Finds the in/out particle trajectory boundaries for a particular magnetic region bounding box.
void ReMap(const size_t &n, const TVector3 &newMapSize)
It allows to remap the magnetic field to a larger mesh size. The new mesh size granularity must be pr...
Int_t GetVolumeIndex(TVector3 pos)
It returns the corresponding volume index at the given position. If not found it will return -1.
std::vector< TVector3 > fBoundMax
A vector to store the maximum bounding box values.
TCanvas * DrawHistogram(TString projection, TString Bcomp, Int_t volIndex=-1, Double_t step=-1, TString style="COLZ0", Double_t depth=-100010.0)
A method that creates a canvas where magnetic field map is drawn.
Bool_t IsFieldConstant(Int_t id)
It returns true if no magnetic field map was loaded for that volume.
MagneticFieldVolume * GetMagneticVolume(Int_t id)
It returns a pointer to the corresponding magnetic volume id.
TVector3 fTrackStart
The start track position used to parameterize the field along a track.
TVector3 GetMagneticVolumeNode(MagneticFieldVolume mVol, TVector3 pos)
It returns the corresponding mesh node in the magnetic volume.
TVector3 GetMagneticField(Double_t x, Double_t y, Double_t z)
It returns the magnetic field vector at x,y,z.
std::vector< TVector3 > fMeshSize
std::vector< MagneticFieldVolume > fMagneticFieldVolumes
A magnetic field volume structure to store field data and mesh.
std::vector< Double_t > GetTransversalComponentAlongPath(TVector3 from, TVector3 to, Double_t dl=1., Int_t Nmax=0)
It returns a vector describing the transversal magnetic field component between from and to positions...
std::vector< TString > fMeshType
The type of the mesh used (default is cylindrical)
void LoadMagneticFieldData(MagneticFieldVolume &mVol, std::vector< std::vector< Float_t > > data)
A method to help loading magnetic field data, as x,y,z,Bx,By,Bz into a magnetic volume definition usi...
Double_t GetTransversalComponent(TVector3 position, TVector3 direction)
It returns the intensity of the transversal magnetic field component for the defined propagation dire...
std::vector< std::string > fFileNames
The name of the filenames containing the field data.
TH2D * fHisto
A helper histogram to plot the field.
TCanvas * fCanvas
A canvas to insert the histogram drawing.
~TRestAxionMagneticField()
Default destructor.
Bool_t IsInside(TVector3 pos)
It returns true if the given position is found inside a magnetic volume. False otherwise.
void Initialize()
Initialization of TRestAxionMagneticField members.
Double_t GetTransversalFieldAverage(TVector3 from, TVector3 to, Double_t dl=1., Int_t Nmax=0)
It returns the average of the transversal magnetic field intensity between the 3-d coordinates from a...
Double_t GetTransversalComponentInParametricTrack(Double_t x)
It will return the transversal magnetic field component evaluated at a parametric distance x (given b...
Bool_t FieldLoaded()
This private method returns true if the magnetic field volumes loaded are the same as the volumes def...
A basic class inheriting from TObject to help creating a node grid definition.
Definition: TRestMesh.h:38
void SetSize(Double_t sX, Double_t sY, Double_t sZ)
Sets the origin of the bounding-box and initializes the nodes vector to zero.
Definition: TRestMesh.cxx:527
void SetOrigin(Double_t oX, Double_t oY, Double_t oZ)
Sets the origin of the bounding-box and initializes the nodes vector to zero.
Definition: TRestMesh.cxx:507
void SetCylindrical(Bool_t v)
Sets the coordinate system to cylindrical.
Definition: TRestMesh.h:136
void SetNodes(Int_t nX, Int_t nY, Int_t nZ)
Sets the number of nodes and initializes the nodes vector to zero.
Definition: TRestMesh.cxx:539
A base class for any REST metadata class.
Definition: TRestMetadata.h:70
virtual void PrintMetadata()
Implemented it in the derived metadata class to print out specific metadata information.
endl_t RESTendl
Termination flag object for TRestStringOutput.
TiXmlElement * GetElement(std::string eleDeclare, TiXmlElement *e=nullptr)
Get an xml element from a given parent element, according to its declaration.
Int_t LoadConfigFromFile(const std::string &configFilename, const std::string &sectionName="")
Give the file name, find out the corresponding section. Then call the main starter.
virtual void InitFromConfigFile()
To make settings from rml file. This method must be implemented in the derived class.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
void SetError(std::string message="", bool print=true)
A metadata class may use this method to signal that something went wrong.
TRestStringOutput::REST_Verbose_Level GetVerboseLevel()
returns the verboselevel in type of REST_Verbose_Level enumerator
std::string GetFieldValue(std::string parName, TiXmlElement *e)
Returns the field value of an xml element which has the specified name.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string SearchFile(std::string filename)
Search files in current directory and directories specified in "searchPath" section.
std::string fConfigFileName
Full name of the rml file.
TiXmlElement * GetNextElement(TiXmlElement *e)
Get the next sibling xml element of this element, with same eleDeclare.
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
@ REST_Info
+show most of the information for each steps
@ REST_Debug
+show the defined debug messages
static int ReadASCIITable(std::string fName, std::vector< std::vector< Double_t > > &data, Int_t skipLines=0, std::string separator="\t")
Reads an ASCII file containing a table with values.
Definition: TRestTools.cxx:523
static int ReadBinaryTable(std::string fName, std::vector< std::vector< T > > &data, Int_t columns=-1)
Reads a binary file containing a fixed-columns table with values.
Definition: TRestTools.cxx:251
static int PrintTable(std::vector< std::vector< T > > data, Int_t start=0, Int_t end=0)
Prints the contents of the vector table given as argument in screen. Allowed types are Int_t,...
Definition: TRestTools.cxx:163
static T GetMaxValueFromTable(const std::vector< std::vector< T > > &data, Int_t column=-1)
It returns the maximum value for a particular column from the table given by argument....
Definition: TRestTools.cxx:368
static T GetLowestIncreaseFromTable(std::vector< std::vector< T > > data, Int_t column)
It returns the lowest increase, different from zero, between the elements of a particular column from...
Definition: TRestTools.cxx:440
static T GetMinValueFromTable(const std::vector< std::vector< T > > &data, Int_t column=-1)
It returns the minimum value for a particular column from the table given by argument....
Definition: TRestTools.cxx:403
This namespace serves to define physics constants and other basic physical operations.
Definition: TRestPhysics.h:34
TVector3 MoveToPlane(const TVector3 &pos, const TVector3 &dir, const TVector3 &n, const TVector3 &a)
This method will translate the vector with direction dir starting at position pos to the plane define...
TVector3 MoveByDistanceFast(const TVector3 &pos, const TVector3 &dir, Double_t d)
This method transports a position pos by a distance d in the direction defined by dir....
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.