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
592 Int_t divisions = 100;
593 if (fCanvas != NULL) {
594 delete fCanvas;
595 fCanvas = NULL;
596 }
597 fCanvas = new TCanvas("fCanvas", "", 1600, 600);
598
599 TPad* pad1 = new TPad("pad1", "This is pad1", 0.01, 0.02, 0.99, 0.97);
600 // pad1->Divide(2, 1);
601 pad1->Draw();
602 pad1->cd();
603
604 Int_t n = 0;
605 Double_t genPositionZ = fPositions[volId][2] - fBoundMax[volId].Z() - 2000;
606 Double_t finalPositionZ = fPositions[volId][2] + fBoundMax[volId].Z() + 2000;
607 TVector3 position(0, 0, genPositionZ);
608 TVector3 direction(0, 0, 1);
609
610 RESTDebug << RESTendl;
611 RESTDebug << "Start moving along" << RESTendl;
612 RESTDebug << "++++++++++++++++++" << RESTendl;
613
614 TGraph* fieldGr = new TGraph();
615 Double_t posZ = fPositions[volId][2] - fBoundMax[volId].Z() - 10;
616 Double_t delta = fBoundMax[volId][2] * 2. / divisions;
617
618 while (posZ <= fPositions[volId][2] + fBoundMax[volId].Z()) {
619 TVector3 posAlongAxis = TVector3(fPositions[volId][0], fPositions[volId][1], posZ);
620
621 position = MoveToPlane(position, direction, TVector3(0, 0, 1), posAlongAxis);
622 Double_t fieldY = this->GetMagneticField(position).Y();
623
624 fieldGr->SetPoint(fieldGr->GetN(), posZ, fieldY);
625
626 posZ += delta;
627 }
628
629 fieldGr->SetLineWidth(3);
630 fieldGr->SetLineColor(38 + n);
631 fieldGr->GetXaxis()->SetLimits(genPositionZ - 500, finalPositionZ + 500);
632 fieldGr->GetHistogram()->SetMaximum(2.5);
633 fieldGr->GetHistogram()->SetMinimum(0);
634 fieldGr->GetXaxis()->SetTitle("Z [mm]");
635 fieldGr->GetXaxis()->SetTitleSize(0.05);
636 fieldGr->GetXaxis()->SetLabelSize(0.05);
637 fieldGr->GetYaxis()->SetTitle("B [T]");
638 fieldGr->GetYaxis()->SetTitleOffset(1.3);
639 fieldGr->GetYaxis()->SetTitleSize(0.05);
640 fieldGr->GetYaxis()->SetLabelSize(0.05);
641 fieldGr->Draw("AL");
642
643 return fCanvas;
644}
645
650TCanvas* TRestAxionMagneticField::DrawTracks(TVector3 vanishingPoint, Int_t divisions, Int_t volId) {
651 if (fCanvas != NULL) {
652 delete fCanvas;
653 fCanvas = NULL;
654 }
655 fCanvas = new TCanvas("fCanvas", "", 1600, 600);
656
657 TPad* pad1 = new TPad("pad1", "This is pad1", 0.01, 0.02, 0.99, 0.97);
658 pad1->Divide(2, 1);
659 pad1->Draw();
660
661 pad1->cd(1);
662
663 Double_t genSizeY = fBoundMax[volId].Y() * 3.;
664 Double_t genPositionZ = fPositions[volId][2] - fBoundMax[volId].Z() - 2000;
665 Double_t finalPositionZ = fPositions[volId][2] + fBoundMax[volId].Z() + 2000;
666
667 // We generate the particle at different Y-highs
668 TGraph* bBox = new TGraph();
669 bBox->SetPoint(0, fPositions[volId][2] - fBoundMax[volId].Z(),
670 fPositions[volId][1] - fBoundMax[volId].Y());
671 bBox->SetPoint(1, fPositions[volId][2] - fBoundMax[volId].Z(),
672 fPositions[volId][1] + fBoundMax[volId].Y());
673 bBox->SetPoint(2, fPositions[volId][2] + fBoundMax[volId].Z(),
674 fPositions[volId][1] + fBoundMax[volId].Y());
675 bBox->SetPoint(3, fPositions[volId][2] + fBoundMax[volId].Z(),
676 fPositions[volId][1] - fBoundMax[volId].Y());
677 bBox->SetPoint(4, fPositions[volId][2] - fBoundMax[volId].Z(),
678 fPositions[volId][1] - fBoundMax[volId].Y());
679
680 RESTDebug << "Gen position : " << genPositionZ << RESTendl;
681
682 bBox->GetXaxis()->SetLimits(genPositionZ - 500, finalPositionZ + 500);
683 bBox->GetHistogram()->SetMaximum(genSizeY + 100);
684 bBox->GetHistogram()->SetMinimum(-genSizeY - 100);
685
686 bBox->GetXaxis()->SetTitle("Z [mm]");
687 bBox->GetXaxis()->SetTitleSize(0.05);
688 bBox->GetXaxis()->SetLabelSize(0.05);
689 bBox->GetYaxis()->SetTitle("Y [mm]");
690 bBox->GetYaxis()->SetTitleOffset(1.3);
691 bBox->GetYaxis()->SetTitleSize(0.05);
692 bBox->GetYaxis()->SetLabelSize(0.05);
693 bBox->SetLineWidth(2);
694 bBox->Draw("AL");
695
696 Int_t n = 0;
697 for (Double_t y = genSizeY; y >= -genSizeY; y -= fBoundMax[volId].Y()) {
698 TVector3 position(0, y, genPositionZ);
699 TVector3 direction = (vanishingPoint - position).Unit();
700
701 std::vector<TVector3> trackBounds = this->GetFieldBoundaries(position, direction);
702 TGraph* grB = new TGraph();
703 grB->SetPoint(0, trackBounds[0].Z(), trackBounds[0].Y());
704 grB->SetPoint(1, trackBounds[1].Z(), trackBounds[1].Y());
705
706 RESTDebug << "Initial" << RESTendl;
707 RESTDebug << "-------" << RESTendl;
709
710 RESTDebug << RESTendl;
711 RESTDebug << "Start moving along" << RESTendl;
712 RESTDebug << "++++++++++++++++++" << RESTendl;
713
714 TGraph* fieldGr = new TGraph();
715 Double_t posZ = fPositions[volId][2] - fBoundMax[volId].Z() - 10;
716 Double_t delta = fBoundMax[volId][2] * 2. / divisions;
717
718 Double_t field = this->GetTransversalComponent(position, direction);
719 fieldGr->SetPoint(fieldGr->GetN(), posZ, field);
720
721 while (posZ <= fPositions[volId][2] + fBoundMax[volId].Z()) {
722 TVector3 posAlongAxis = TVector3(fPositions[volId][0], fPositions[volId][1], posZ);
723
724 position = MoveToPlane(position, direction, TVector3(0, 0, 1), posAlongAxis);
725 Double_t field = this->GetTransversalComponent(position, direction);
726
727 fieldGr->SetPoint(fieldGr->GetN(), posZ, field);
728
729 posZ += delta;
730 }
731
732 TVector3 posAlongAxis = TVector3(fPositions[volId][0], fPositions[volId][1], posZ + 10);
733 position = MoveToPlane(position, direction, TVector3(0, 0, 1), posAlongAxis);
734
735 Double_t field2 = this->GetTransversalComponent(position, direction);
736 fieldGr->SetPoint(fieldGr->GetN(), posZ, field2);
737
738 pad1->cd(2);
739 fieldGr->SetLineWidth(3);
740 fieldGr->SetLineColor(38 + n);
741 fieldGr->GetXaxis()->SetLimits(genPositionZ - 500, finalPositionZ + 500);
742 fieldGr->GetHistogram()->SetMaximum(2.5);
743 fieldGr->GetHistogram()->SetMinimum(0);
744 fieldGr->GetXaxis()->SetTitle("Z [mm]");
745 fieldGr->GetXaxis()->SetTitleSize(0.05);
746 fieldGr->GetXaxis()->SetLabelSize(0.05);
747 fieldGr->GetYaxis()->SetTitle("B [T]");
748 fieldGr->GetYaxis()->SetTitleOffset(1.3);
749 fieldGr->GetYaxis()->SetTitleSize(0.05);
750 fieldGr->GetYaxis()->SetLabelSize(0.05);
751 if (y == genSizeY)
752 fieldGr->Draw("AL");
753 else
754 fieldGr->Draw("L");
755 pad1->cd(1);
756
757 TGraph* gr = new TGraph();
758 gr->SetPoint(0, genPositionZ, y);
759 position = MoveToPlane(position, direction, TVector3(0, 0, 1), TVector3(0, 0, finalPositionZ));
760 gr->SetPoint(1, finalPositionZ, position.Y());
761
762 gr->SetLineWidth(2);
763 gr->Draw("L");
764 grB->SetLineColor(38 + n);
765 n++;
766 grB->SetLineWidth(3);
767 grB->Draw("L");
768 }
769 bBox->Draw("L");
770
771 return fCanvas;
772}
773
781 std::vector<std::vector<Float_t>> data) {
782 mVol.field.resize(mVol.mesh.GetNodesX());
783 for (unsigned int n = 0; n < mVol.field.size(); n++) {
784 mVol.field[n].resize(mVol.mesh.GetNodesY());
785 for (unsigned int m = 0; m < mVol.field[n].size(); m++)
786 mVol.field[n][m].resize(mVol.mesh.GetNodesZ());
787 }
788
789 RESTDebug << "TRestAxionMagneticField::LoadMagneticFieldData. Printing first 5 data rows" << RESTendl;
790 for (unsigned int n = 0; n < data.size(); n++) {
791 // The magnetic field map is centered at zero.
792 // But the mesh definition contains the offset position
793 // We shift the data to match the mesh node network.
794 Int_t nX = mVol.mesh.GetNodeX((Int_t)(data[n][0] + mVol.mesh.GetNetSizeX() / 2.), true);
795 Int_t nY = mVol.mesh.GetNodeY((Int_t)(data[n][1] + mVol.mesh.GetNetSizeY() / 2.), true);
796 Int_t nZ = mVol.mesh.GetNodeZ((Int_t)(data[n][2] + mVol.mesh.GetNetSizeZ() / 2.), true);
797
798 if (n < 5) {
799 RESTDebug << "X: " << data[n][0] << " Y: " << data[n][1] << " Z: " << data[n][2] << RESTendl;
800 RESTDebug << "absX: " << data[n][0] + mVol.position.X()
801 << " absY: " << data[n][1] + mVol.position.Y()
802 << " absZ: " << data[n][2] + mVol.position.Z() << RESTendl;
803 RESTDebug << "nX: " << nX << " nY: " << nY << " nZ: " << nZ << RESTendl;
804 RESTDebug << "Bx: " << data[n][3] << " By: " << data[n][4] << " Bz: " << data[n][5] << RESTendl;
806 }
807
808 if (mVol.field[nX][nY][nZ] != TVector3(0.0, 0.0, 0.0)) {
809 RESTWarning << "X: " << data[n][0] << " Y: " << data[n][1] << " Z: " << data[n][2] << RESTendl;
810 RESTWarning << "nX: " << nX << " nY: " << nY << " nZ: " << nZ << RESTendl;
811 RESTWarning << "WARNING: field[nX][nY][nZ] element not equal to initial value (0, 0, 0) !!"
812 << RESTendl;
813 RESTWarning << "It has value: "
814 << "mVol.field[" << nX << "][" << nY << "][" << nZ << "] = ("
815 << mVol.field[nX][nY][nZ].X() << " , " << mVol.field[nX][nY][nZ].Y() << " , "
816 << mVol.field[nX][nY][nZ].Z() << ")" << RESTendl;
817 RESTWarning << "Values to write: "
818 << "Bx: " << data[n][3] << " By: " << data[n][4] << " Bz: " << data[n][5] << RESTendl
819 << RESTendl;
820
821 this->SetError("There was a problem assigning the field matrix!");
823 }
824
825 mVol.field[nX][nY][nZ] = TVector3(data[n][3], data[n][4], data[n][5]);
826 }
827}
828
835 for (unsigned int n = 0; n < fPositions.size(); n++) {
836 string fullPathName = SearchFile((string)fFileNames[n]);
837 RESTDebug << "Reading file : " << fFileNames[n] << RESTendl;
838 RESTDebug << "Full path : " << fullPathName << RESTendl;
839
840 if (fFileNames[n] != "none" && fullPathName == "") {
841 RESTError << "TRestAxionMagneticField::LoadMagneticVolumes. File " << fFileNames[n]
842 << " not found!" << RESTendl;
843 RESTError
844 << "REST will look for this file at any path given by <searchPath at globals definitions"
845 << RESTendl;
846 exit(5);
847 }
848
849 std::vector<std::vector<Float_t>> fieldData;
850 if (fFileNames[n] != "none")
851 if (fullPathName.find(".dat") != string::npos) {
852 RESTDebug << "Reading ASCII format" << RESTendl;
853 if (!TRestTools::ReadASCIITable(fullPathName, fieldData)) {
854 RESTError << "Problem reading file : " << fullPathName << RESTendl;
855 exit(1);
856 }
857 } else {
858 if (fullPathName.find(".bin") != string::npos) {
859 RESTDebug << "Reading binary format" << RESTendl;
860 if (!TRestTools::ReadBinaryTable(fullPathName, fieldData, 6)) {
861 RESTError << "Problem reading file : " << fullPathName << RESTendl;
862 exit(2);
863 }
864 }
865 }
866 else if (fFileNames[n] != "none") {
867 RESTError << "Filename : " << fullPathName << RESTendl;
868 RESTError << "File format not recognized!" << RESTendl;
869 exit(3);
870 }
871
872 if (fFileNames[n] != "none" && fieldData.size() < 2) {
873 RESTError << "Field data size is no more than 2 grid points!" << RESTendl;
874 RESTError << "Filename : " << fullPathName << RESTendl;
875 RESTError << "Probably something went wrong loading the file" << RESTendl;
876 exit(4);
877 }
878
879 Float_t xMin = -fBoundMax[n].X(), yMin = -fBoundMax[n].Y(), zMin = -fBoundMax[n].Z();
880 Float_t xMax = fBoundMax[n].X(), yMax = fBoundMax[n].Y(), zMax = fBoundMax[n].Z();
881 Float_t meshSizeX = fMeshSize[n].X(), meshSizeY = fMeshSize[n].Y(), meshSizeZ = fMeshSize[n].Z();
882
883 // If a field map is defined we get the boundaries, and mesh size from the volume
884 if (fieldData.size() > 0) {
885 RESTDebug << "Reading max boundary values" << RESTendl;
886 xMax = TRestTools::GetMaxValueFromTable(fieldData, 0);
887 yMax = TRestTools::GetMaxValueFromTable(fieldData, 1);
888 zMax = TRestTools::GetMaxValueFromTable(fieldData, 2);
889
890 if (fBoundMax[n] != TVector3(0, 0, 0)) {
891 if (fBoundMax[n] != TVector3(xMax, yMax, zMax)) {
892 RESTWarning << "Volume : " << n << RESTendl;
893 RESTWarning << "boundMax was defined in RML but does not match the field map boundaries!"
894 << RESTendl;
895 RESTWarning << "Max. Field map boundaries : (" << xMax << ", " << yMax << ", " << zMax
896 << ")" << RESTendl;
897 }
898 }
899
900 RESTDebug << "Reading min boundary values" << RESTendl;
901 xMin = TRestTools::GetMinValueFromTable(fieldData, 0);
902 yMin = TRestTools::GetMinValueFromTable(fieldData, 1);
903 zMin = TRestTools::GetMinValueFromTable(fieldData, 2);
904
905 if (fBoundMax[n] != TVector3(0, 0, 0)) {
906 if (-fBoundMax[n] != TVector3(xMin, yMin, zMin)) {
907 RESTWarning << "Volume : " << n << RESTendl;
908 RESTWarning << "boundMax was defined in RML but does not match the field map boundaries"
909 << RESTendl;
910 RESTWarning << "Min. Field map boundaries : (" << xMin << ", " << yMin << ", " << zMin
911 << ")" << RESTendl;
912 }
913 }
914 fBoundMax[n] = TVector3(xMax, yMax, zMax);
915
916 RESTDebug << "Reading mesh size" << RESTendl;
917 meshSizeX = TRestTools::GetLowestIncreaseFromTable(fieldData, 0);
918 meshSizeY = TRestTools::GetLowestIncreaseFromTable(fieldData, 1);
919 meshSizeZ = TRestTools::GetLowestIncreaseFromTable(fieldData, 2);
920
921 if (fMeshSize[n] != TVector3(0, 0, 0)) {
922 if (fMeshSize[n] != TVector3(meshSizeX, meshSizeY, meshSizeZ)) {
923 RESTWarning << "Volume : " << n << RESTendl;
924 RESTWarning
925 << "MeshSize was defined in RML but does not match the mesh size deduced from "
926 "field map"
927 << RESTendl;
928 RESTWarning << "Mesh size : (" << meshSizeX << ", " << meshSizeY << ", " << meshSizeZ
929 << ")" << RESTendl;
930 }
931 }
932 fMeshSize[n] = TVector3(meshSizeX, meshSizeY, meshSizeZ);
933 }
934
936 RESTDebug << "Reading magnetic field map" << RESTendl;
937 RESTDebug << "--------------------------" << RESTendl;
938
939 RESTDebug << "Full path : " << fullPathName << RESTendl;
940
941 RESTDebug << "Boundaries" << RESTendl;
942 RESTDebug << "xMin: " << xMin << " yMin: " << yMin << " zMin: " << zMin << RESTendl;
943 RESTDebug << "xMax: " << xMax << " yMax: " << yMax << " zMax: " << zMax << RESTendl;
944 RESTDebug << "Mesh size" << RESTendl;
945
946 RESTDebug << "sX: " << meshSizeX << " sY: " << meshSizeY << " sZ: " << meshSizeZ << RESTendl;
947
948 if (fieldData.size() > 4) {
949 RESTDebug << "Printing beginning of magnetic file table : " << fieldData.size() << RESTendl;
950 TRestTools::PrintTable(fieldData, 0, 5);
951 } else {
952 RESTDebug << "The data file contains no field map" << RESTendl;
953 }
954 }
956
957 // Number of nodes
958 Int_t nx = (Int_t)(2 * xMax / meshSizeX) + 1;
959 Int_t ny = (Int_t)(2 * yMax / meshSizeY) + 1;
960 Int_t nz = (Int_t)(2 * zMax / meshSizeZ) + 1;
961
962 // We create an auxiliar mesh helping to initialize the fieldMap
963 // The mesh is centered at zero. Absolute position is defined in the Magnetic volume
964 // TODO It would be interesting that TRestMesh could be used in cylindrical coordinates.
965 TRestMesh restMesh;
966 restMesh.SetSize(2 * xMax, 2 * yMax, 2 * zMax);
967 restMesh.SetOrigin(fPositions[n] - TVector3(xMax, yMax, zMax));
968 restMesh.SetNodes(nx, ny, nz);
969 if (fMeshType[n] == "cylinder")
970 restMesh.SetCylindrical(true);
971 else
972 restMesh.SetCylindrical(false);
973
974 MagneticFieldVolume mVolume;
975 mVolume.position = fPositions[n];
976 mVolume.mesh = restMesh;
977
978 if (fieldData.size() > 0) LoadMagneticFieldData(mVolume, fieldData);
979
980 if (fBoundMax[n] == TVector3(0, 0, 0)) {
981 RESTError << "The bounding box was not defined for volume " << n << "!" << RESTendl;
982 RESTError << "Please review RML configuration for TRestAxionMagneticField" << RESTendl;
983 exit(22);
984 } else if (fMeshSize[n] == TVector3(0, 0, 0)) {
985 RESTError << "The mesh grid size was not defined for volume " << n << "!" << RESTendl;
986 RESTError << "Please review RML configuration for TRestAxionMagneticField" << RESTendl;
987 exit(22);
988 }
989 fMagneticFieldVolumes.push_back(mVolume);
990 }
991
992 if (CheckOverlaps()) {
993 RESTError << "TRestAxionMagneticField::LoadMagneticVolumes. Volumes overlap!" << RESTendl;
994 exit(1);
995 }
996
997 for (size_t n = 0; n < fMagneticFieldVolumes.size(); n++)
998 if (fReMap != TVector3(0, 0, 0)) ReMap(n, fReMap);
999
1000 RESTDebug << "Finished loading magnetic volumes" << RESTendl;
1001}
1002
1006TVector3 TRestAxionMagneticField::GetMagneticField(Double_t x, Double_t y, Double_t z) {
1007 return GetMagneticField(TVector3(x, y, z));
1008}
1009
1018TVector3 TRestAxionMagneticField::GetMagneticField(TVector3 pos, Bool_t showWarning) {
1019 Int_t id = GetVolumeIndex(pos);
1020
1021 if (id < 0) {
1022 if (showWarning)
1023 RESTWarning << "TRestAxionMagneticField::GetMagneticField position (" << pos.X() << ", "
1024 << pos.Y() << ", " << pos.Z() << ") is outside any volume" << RESTendl;
1025 return TVector3(0, 0, 0);
1026 } else {
1027 if (IsFieldConstant(id)) return fConstantField[id];
1028 TVector3 node = GetMagneticVolumeNode((size_t)id, pos);
1029 Int_t nX = node.X();
1030 Int_t nY = node.Y();
1031 Int_t nZ = node.Z();
1032
1033 Int_t nX_1, nY_1, nZ_1;
1034
1035 if ((nX + 1) < fMagneticFieldVolumes[id].mesh.GetNodesX())
1036 nX_1 = nX + 1;
1037 else
1038 nX_1 = nX;
1039 if ((nY + 1) < fMagneticFieldVolumes[id].mesh.GetNodesY())
1040 nY_1 = nY + 1;
1041 else
1042 nY_1 = nY;
1043 if ((nZ + 1) < fMagneticFieldVolumes[id].mesh.GetNodesZ())
1044 nZ_1 = nZ + 1;
1045 else
1046 nZ_1 = nZ;
1047
1048 TVector3 C000 = fMagneticFieldVolumes[id].field[nX][nY][nZ] + fConstantField[id];
1049 TVector3 C100 = fMagneticFieldVolumes[id].field[nX_1][nY][nZ] + fConstantField[id];
1050 TVector3 C010 = fMagneticFieldVolumes[id].field[nX][nY_1][nZ] + fConstantField[id];
1051 TVector3 C110 = fMagneticFieldVolumes[id].field[nX_1][nY_1][nZ] + fConstantField[id];
1052 TVector3 C001 = fMagneticFieldVolumes[id].field[nX][nY][nZ_1] + fConstantField[id];
1053 TVector3 C101 = fMagneticFieldVolumes[id].field[nX_1][nY][nZ_1] + fConstantField[id];
1054 TVector3 C011 = fMagneticFieldVolumes[id].field[nX][nY_1][nZ_1] + fConstantField[id];
1055 TVector3 C111 = fMagneticFieldVolumes[id].field[nX_1][nY_1][nZ_1] + fConstantField[id];
1056
1057 Double_t x0 = fMagneticFieldVolumes[id].mesh.GetX(nX);
1058 Double_t x1 = fMagneticFieldVolumes[id].mesh.GetX(nX_1);
1059 Double_t xd;
1060 if (x0 == x1)
1061 xd = 0;
1062 else
1063 xd = (pos.X() - x0) / (x1 - x0);
1064 if ((xd < -0.00001) || (xd > 1.00001))
1065 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: xd NOT between 0 and 1"
1066 << RESTendl;
1067
1068 Double_t y0 = fMagneticFieldVolumes[id].mesh.GetY(nY);
1069 Double_t y1 = fMagneticFieldVolumes[id].mesh.GetY(nY_1);
1070 Double_t yd;
1071 if (y0 == y1)
1072 yd = 0;
1073 else
1074 yd = (pos.Y() - y0) / (y1 - y0);
1075 if ((yd < -0.00001) || (yd > 1.00001))
1076 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: yd NOT between 0 and 1"
1077 << RESTendl;
1078
1079 Double_t z0 = fMagneticFieldVolumes[id].mesh.GetZ(nZ);
1080 Double_t z1 = fMagneticFieldVolumes[id].mesh.GetZ(nZ_1);
1081 Double_t zd;
1082 if (z0 == z1)
1083 zd = 0;
1084 else
1085 zd = (pos.Z() - z0) / (z1 - z0);
1086 if ((zd < -0.00001) || (zd > 1.00001))
1087 RESTWarning << "TRestAxionMagneticField::GetMagneticField Error: zd NOT between 0 and 1"
1088 << RESTendl;
1089
1090 // first we interpolate along x-axis
1091 TVector3 C00 = C000 * (1.0 - xd) + C100 * xd;
1092 TVector3 C01 = C001 * (1.0 - xd) + C101 * xd;
1093 TVector3 C10 = C010 * (1.0 - xd) + C110 * xd;
1094 TVector3 C11 = C011 * (1.0 - xd) + C111 * xd;
1095
1096 // then we interpolate along y-axis
1097 TVector3 C0 = C00 * (1.0 - yd) + C10 * yd;
1098 TVector3 C1 = C01 * (1.0 - yd) + C11 * yd;
1099
1100 // finally we interpolate along z-axis
1101 TVector3 C = C0 * (1.0 - zd) + C1 * zd;
1102
1103 RESTDebug << "position = (" << pos.X() << ", " << pos.Y() << ", " << pos.Z() << ") ";
1104 RESTDebug << "nX = " << nX << " nY = " << nY << " nZ = " << nZ << " nX_1 = " << nX_1
1105 << " nY_1 = " << nY_1 << " nZ_1 = " << nZ_1 << RESTendl << RESTendl;
1106 RESTDebug << "C000 = (" << C000.X() << ", " << C000.Y() << ", " << C000.Z() << ")" << RESTendl
1107 << RESTendl;
1108 RESTDebug << "C100 = (" << C100.X() << ", " << C100.Y() << ", " << C100.Z() << ")" << RESTendl
1109 << RESTendl;
1110 RESTDebug << "C010 = (" << C010.X() << ", " << C010.Y() << ", " << C010.Z() << ")" << RESTendl
1111 << RESTendl;
1112 RESTDebug << "C110 = (" << C110.X() << ", " << C110.Y() << ", " << C110.Z() << ")" << RESTendl
1113 << RESTendl;
1114 RESTDebug << "C001 = (" << C001.X() << ", " << C001.Y() << ", " << C001.Z() << ")" << RESTendl
1115 << RESTendl;
1116 RESTDebug << "C101 = (" << C101.X() << ", " << C101.Y() << ", " << C101.Z() << ")" << RESTendl
1117 << RESTendl;
1118 RESTDebug << "C011 = (" << C011.X() << ", " << C011.Y() << ", " << C011.Z() << ")" << RESTendl
1119 << RESTendl;
1120 RESTDebug << "C111 = (" << C111.X() << ", " << C111.Y() << ", " << C111.Z() << ")" << RESTendl
1121 << RESTendl;
1122 RESTDebug << " -------------------------------------------------------" << RESTendl;
1123 RESTDebug << "C00 = (" << C00.X() << ", " << C00.Y() << ", " << C00.Z() << ")" << RESTendl
1124 << RESTendl;
1125 RESTDebug << "C01 = (" << C01.X() << ", " << C01.Y() << ", " << C01.Z() << ")" << RESTendl
1126 << RESTendl;
1127 RESTDebug << "C10 = (" << C10.X() << ", " << C10.Y() << ", " << C10.Z() << ")" << RESTendl
1128 << RESTendl;
1129 RESTDebug << "C11 = (" << C11.X() << ", " << C11.Y() << ", " << C11.Z() << ")" << RESTendl
1130 << RESTendl;
1131 RESTDebug << " -------------------------------------------------------" << RESTendl;
1132 RESTDebug << "C0 = (" << C0.X() << ", " << C0.Y() << ", " << C0.Z() << ")" << RESTendl << RESTendl;
1133 RESTDebug << "C1 = (" << C1.X() << ", " << C1.Y() << ", " << C1.Z() << ")" << RESTendl << RESTendl;
1134 RESTDebug << " -------------------------------------------------------" << RESTendl;
1135 RESTDebug << "C = (" << C.X() << ", " << C.Y() << ", " << C.Z() << ")" << RESTendl << RESTendl;
1136
1137 return C;
1138 }
1139}
1140
1146void TRestAxionMagneticField::ReMap(const size_t& n, const TVector3& newMapSize) {
1147 if (newMapSize.X() == 0 || newMapSize.Y() == 0 || newMapSize.Z() == 0) {
1148 RESTError << "TRestAxionMagneticField::ReMap. The mesh granularity cannot be 0" << RESTendl;
1149 RESTError << "Remapping will not take effect" << RESTendl;
1150 return;
1151 }
1152
1153 Double_t remainder = std::fmod(newMapSize.X(), fMeshSize[n].X()) +
1154 std::fmod(newMapSize.Y(), fMeshSize[n].Y()) +
1155 std::fmod(newMapSize.Z(), fMeshSize[n].Z());
1156 if (remainder != 0) {
1157 RESTError << "TRestAxionMagneticField::ReMap. The field cannot be remapped." << RESTendl;
1158 RESTError << "The new mesh granularity must be a multiple of the existing granularity." << RESTendl;
1159 RESTError << "Present mesh size : (" << fMeshSize[n].X() << ", " << fMeshSize[n].Y() << ", "
1160 << fMeshSize[n].Z() << ")" << RESTendl;
1161 RESTError << "Requested mesh size : (" << newMapSize.X() << ", " << newMapSize.Y() << ", "
1162 << newMapSize.Z() << ")" << RESTendl;
1163 RESTError << "Remapping will not take effect" << RESTendl;
1164 return;
1165 }
1166
1167 Int_t scaleX = (Int_t)(newMapSize.X() / fMeshSize[n].X());
1168 Int_t scaleY = (Int_t)(newMapSize.Y() / fMeshSize[n].Y());
1169 Int_t scaleZ = (Int_t)(newMapSize.Z() / fMeshSize[n].Z());
1170
1171 Int_t newNodesX = (fMagneticFieldVolumes[n].mesh.GetNodesX() - 1) / scaleX + 1;
1172 Int_t newNodesY = (fMagneticFieldVolumes[n].mesh.GetNodesY() - 1) / scaleY + 1;
1173 Int_t newNodesZ = (fMagneticFieldVolumes[n].mesh.GetNodesZ() - 1) / scaleZ + 1;
1174
1175 for (Int_t nx = 0; nx < newNodesX; nx++)
1176 for (Int_t ny = 0; ny < newNodesY; ny++)
1177 for (Int_t nz = 0; nz < newNodesZ; nz++)
1178 fMagneticFieldVolumes[n].field[nx][ny][nz] =
1179 fMagneticFieldVolumes[n].field[nx * scaleX][ny * scaleY][nz * scaleZ];
1180
1181 fMagneticFieldVolumes[n].mesh.SetNodes(newNodesX, newNodesY, newNodesZ);
1182 fMagneticFieldVolumes[n].field.resize(fMagneticFieldVolumes[n].mesh.GetNodesX());
1183 for (unsigned int i = 0; i < fMagneticFieldVolumes[n].field.size(); i++) {
1184 fMagneticFieldVolumes[n].field[n].resize(fMagneticFieldVolumes[n].mesh.GetNodesY());
1185 for (unsigned int j = 0; j < fMagneticFieldVolumes[n].field[i].size(); j++)
1186 fMagneticFieldVolumes[n].field[i][j].resize(fMagneticFieldVolumes[n].mesh.GetNodesZ());
1187 }
1188
1189 fMeshSize[n] = TVector3(fMeshSize[n].X() * scaleX, fMeshSize[n].Y() * scaleY, fMeshSize[n].Z() * scaleZ);
1190}
1191
1198
1199 for (unsigned int n = 0; n < fMagneticFieldVolumes.size(); n++) {
1200 if (fMagneticFieldVolumes[n].mesh.IsInside(pos)) return n;
1201 }
1202 return -1;
1203}
1204
1209 if (GetVolumeIndex(pos) >= 0) return true;
1210 return false;
1211}
1212
1217
1222 if (id >= 0 && GetNumberOfVolumes() > (unsigned int)id)
1223 return fPositions[id];
1224 else {
1225 RESTWarning << "TRestAxionMagneticField::GetVolumePosition. Id : " << id << " out of range!"
1226 << RESTendl;
1227 RESTWarning << "Number of volumes defined : " << GetNumberOfVolumes() << RESTendl;
1228 return TVector3(0, 0, 0);
1229 }
1230}
1231
1236Double_t TRestAxionMagneticField::GetTransversalComponent(TVector3 position, TVector3 direction) {
1237 return abs(GetMagneticField(position, false).Perp(direction));
1238}
1239
1251std::vector<Double_t> TRestAxionMagneticField::GetTransversalComponentAlongPath(TVector3 from, TVector3 to,
1252 Double_t dl, Int_t Nmax) {
1253 Double_t length = (to - from).Mag();
1254
1255 Double_t diff = dl;
1256 if (Nmax > 0) {
1257 if (length / dl > Nmax) {
1258 diff = length / Nmax;
1259 RESTWarning << "TRestAxionMagneticField::GetTransversalComponentAlongPath. Nmax reached!"
1260 << RESTendl;
1261 RESTWarning << "Nmax = " << Nmax << RESTendl;
1262 RESTWarning << "Adjusting differential step to : " << diff << " mm" << RESTendl;
1263 }
1264 }
1265
1266 TVector3 direction = (to - from).Unit();
1267
1268 std::vector<Double_t> Bt;
1269 for (Double_t d = 0; d < length; d += diff) {
1270 Bt.push_back(GetTransversalComponent(from + d * direction, direction));
1271 }
1272
1273 return Bt;
1274}
1275
1288std::vector<Double_t> TRestAxionMagneticField::GetComponentAlongPath(Int_t axis, TVector3 from, TVector3 to,
1289 Double_t dl, Int_t Nmax) {
1290 std::vector<Double_t> Bt;
1291 if (axis != 0 && axis != 1 && axis != 2) {
1292 RESTError << "TRestAxionMagneticField::GetComponentAlongPath. Axis must take values 0,1 or 2"
1293 << RESTendl;
1294 return Bt;
1295 }
1296 Double_t length = (to - from).Mag();
1297
1298 Double_t diff = dl;
1299 if (Nmax > 0) {
1300 if (length / dl > Nmax) {
1301 diff = length / Nmax;
1302 RESTWarning << "TRestAxionMagneticField::GetComponentAlongPath. Nmax reached!" << RESTendl;
1303 RESTWarning << "Nmax = " << Nmax << RESTendl;
1304 RESTWarning << "Adjusting differential step to : " << diff << " mm" << RESTendl;
1305 }
1306 }
1307
1308 TVector3 direction = (to - from).Unit();
1309
1310 for (Double_t d = 0; d < length; d += diff) {
1311 if (axis == 0) Bt.push_back(GetMagneticField(from + d * direction).X());
1312 if (axis == 1) Bt.push_back(GetMagneticField(from + d * direction).Y());
1313 if (axis == 2) Bt.push_back(GetMagneticField(from + d * direction).Z());
1314 }
1315
1316 return Bt;
1317}
1318
1323void TRestAxionMagneticField::SetTrack(const TVector3& position, const TVector3& direction) {
1324 std::vector<TVector3> trackBounds = GetFieldBoundaries(position, direction);
1325
1326 if (trackBounds.size() != 2) {
1327 fTrackStart = TVector3(0, 0, 0);
1328 fTrackDirection = TVector3(0, 0, 0);
1329 fTrackLength = 0;
1330 return;
1331 }
1332
1333 fTrackStart = trackBounds[0];
1334 fTrackLength = (trackBounds[1] - trackBounds[0]).Mag() - 1;
1335 fTrackDirection = (trackBounds[1] - trackBounds[0]).Unit();
1336}
1337
1347 if (x < 0 || x > fTrackLength) return 0;
1348
1350}
1351
1362Double_t TRestAxionMagneticField::GetTransversalFieldAverage(TVector3 from, TVector3 to, Double_t dl,
1363 Int_t Nmax) {
1364 Double_t Bavg = 0.;
1365 std::vector<Double_t> Bt = GetTransversalComponentAlongPath(from, to, dl, Nmax);
1366 for (auto& b : Bt) Bavg += b;
1367
1368 if (Bt.size() > 0) return Bavg / Bt.size();
1369
1370 RESTError << "TRestAxionMagneticField::GetTransversalFieldAverage. Lenght is zero!" << RESTendl;
1371 return 0.;
1372}
1373
1385TVector3 TRestAxionMagneticField::GetFieldAverageTransverseVector(TVector3 from, TVector3 to, Double_t dl,
1386 Int_t Nmax) {
1387 Double_t length = (to - from).Mag();
1388
1389 Double_t diff = dl;
1390 if (Nmax > 0) {
1391 if (length / dl > Nmax) {
1392 diff = length / Nmax;
1393 RESTWarning << "TRestAxionMagneticField::GetFieldAverageTransverseVector Nmax reached!"
1394 << RESTendl;
1395 RESTWarning << "Nmax = " << Nmax << RESTendl;
1396 RESTWarning << "Adjusting differential step to : " << diff << " mm" << RESTendl;
1397 }
1398 }
1399
1400 TVector3 direction = (to - from).Unit();
1401 TVector3 Bavg = TVector3(0.0, 0.0, 0.0);
1402 TVector3 BTavg = TVector3(0.0, 0.0, 0.0);
1403 Int_t numberofpoints = 0;
1404
1405 for (Double_t d = 0; d <= length; d += diff) {
1406 Bavg = Bavg + GetMagneticField(from + d * direction);
1407 numberofpoints = numberofpoints + 1;
1408 }
1409
1410 if ((length > 0) && (numberofpoints > 0)) {
1411 Bavg = Bavg * (1.0 / numberofpoints); // calculates the average magnetic field vector
1412 BTavg =
1413 Bavg - (Bavg * direction) *
1414 direction; // calculates the transverse component of the average magnetic field vector
1415 RESTDebug << "B average vector = (" << Bavg.x() << ", " << Bavg.y() << ", " << Bavg.z() << ")"
1416 << RESTendl;
1417 RESTDebug << "Transverse B average vector = (" << BTavg.x() << ", " << BTavg.y() << ", " << BTavg.z()
1418 << ")" << RESTendl;
1419 return BTavg;
1420 }
1421 RESTError << "TRestAxionMagneticField::GetTransversalFieldAverage. Lenght is zero!" << RESTendl;
1422 return TVector3(0.0, 0.0, 0.0);
1423}
1424
1433TVector3 TRestAxionMagneticField::GetMagneticVolumeNode(size_t id, TVector3 pos) {
1434 Int_t nx = fMagneticFieldVolumes[id].mesh.GetNodeX(pos.X());
1435 Int_t ny = fMagneticFieldVolumes[id].mesh.GetNodeY(pos.Y());
1436 Int_t nz = fMagneticFieldVolumes[id].mesh.GetNodeZ(pos.Z());
1437 return TVector3(nx, ny, nz);
1438}
1439
1444 RESTDebug << "Checking overlaps" << RESTendl;
1445 for (unsigned int n = 0; n < GetNumberOfVolumes(); n++) {
1446 for (unsigned int m = 0; m < GetNumberOfVolumes(); m++) {
1447 if (m == n) continue;
1448 RESTDebug << "Volume : " << m << RESTendl;
1449
1450 TVector3 b = GetMagneticVolume(m)->mesh.GetVertex(0);
1451 RESTDebug << "Relative bottom vertex : (" << b.X() << ", " << b.Y() << ", " << b.Z() << ")"
1452 << RESTendl;
1453 if (GetMagneticVolume(n)->mesh.IsInsideBoundingBox(b)) return true;
1454
1455 TVector3 t = GetMagneticVolume(m)->mesh.GetVertex(1);
1456 RESTDebug << "Relative top vertex : (" << t.X() << ", " << t.Y() << ", " << t.Z() << ")"
1457 << RESTendl;
1458 if (GetMagneticVolume(n)->mesh.IsInsideBoundingBox(t)) return true;
1459 }
1460 }
1461 return false;
1462}
1463
1477std::vector<TVector3> TRestAxionMagneticField::GetVolumeBoundaries(TVector3 pos, TVector3 dir, Int_t id) {
1478 MagneticFieldVolume* vol = GetMagneticVolume(id);
1479
1480 std::vector<TVector3> boundaries;
1481
1482 if (vol) boundaries = vol->mesh.GetTrackBoundaries(pos, dir);
1483
1484 return boundaries;
1485}
1486
1497std::vector<TVector3> TRestAxionMagneticField::GetFieldBoundaries(TVector3 pos, TVector3 dir,
1498 Double_t precision, Int_t id) {
1499 std::vector<TVector3> volumeBoundaries = GetVolumeBoundaries(pos, dir, id);
1500 if (volumeBoundaries.size() != 2) return volumeBoundaries;
1501
1502 if (IsFieldConstant(id)) return volumeBoundaries;
1503
1504 MagneticFieldVolume* vol = GetMagneticVolume(id);
1505 if (!vol) return volumeBoundaries;
1506
1507 if (precision == 0) precision = min(fMeshSize[id].X(), min(fMeshSize[id].Y(), fMeshSize[id].Z())) / 2.;
1508
1509 TVector3 unit = dir.Unit();
1510 std::vector<TVector3> fieldBoundaries;
1511
1512 TVector3 in = volumeBoundaries[0];
1513 while ((((volumeBoundaries[1] - in) * dir) > 0) && (GetTransversalComponent(in, dir) == 0))
1514 in = MoveByDistanceFast(in, unit, precision);
1515 if (((volumeBoundaries[1] - in) * dir) > 0)
1516 fieldBoundaries.push_back(in);
1517 else
1518 return fieldBoundaries;
1519
1520 TVector3 out = volumeBoundaries[1];
1521 while ((((volumeBoundaries[0] - out) * dir) < 0) && (GetTransversalComponent(out, -dir) == 0) &&
1522 (((out - in) * dir) > 0))
1523 out = MoveByDistanceFast(out, -unit, precision);
1524 if ((((volumeBoundaries[0] - out) * dir) < 0) && (((out - in) * dir) > 0))
1525 fieldBoundaries.push_back(out);
1526 else
1527 return fieldBoundaries;
1528
1529 return fieldBoundaries;
1530}
1531
1537
1538 auto magVolumeDef = GetElement("addMagneticVolume");
1539 while (magVolumeDef) {
1540 string filename = GetFieldValue("fileName", magVolumeDef);
1541 if (filename == "Not defined")
1542 fFileNames.push_back("none");
1543 else
1544 fFileNames.push_back(filename);
1545
1546 TVector3 position = Get3DVectorParameterWithUnits("position", magVolumeDef);
1547 if (position == TVector3(-1, -1, -1))
1548 fPositions.push_back(TVector3(0, 0, 0));
1549 else
1550 fPositions.push_back(position);
1551
1552 TVector3 field = Get3DVectorParameterWithUnits("field", magVolumeDef);
1553 if (field == TVector3(-1, -1, -1))
1554 fConstantField.push_back(TVector3(0, 0, 0));
1555 else
1556 fConstantField.push_back(field);
1557
1558 TVector3 boundMax = Get3DVectorParameterWithUnits("boundMax", magVolumeDef);
1559 if (boundMax == TVector3(-1, -1, -1))
1560 fBoundMax.push_back(TVector3(0, 0, 0));
1561 else
1562 fBoundMax.push_back(boundMax);
1563
1564 TVector3 meshSize = Get3DVectorParameterWithUnits("meshSize", magVolumeDef);
1565 if (meshSize == TVector3(-1, -1, -1))
1566 fMeshSize.push_back(TVector3(0, 0, 0));
1567 else
1568 fMeshSize.push_back(meshSize);
1569
1570 string type = GetParameter("meshType", magVolumeDef);
1571 if (type == "NO_SUCH_PARA")
1572 fMeshType.push_back("cylinder");
1573 else
1574 fMeshType.push_back(type);
1575
1576 // TRestMesh will only consider the first bounding component anyway
1577 if (fMeshType.back() == "cylinder" && fBoundMax.back().X() != fBoundMax.back().Y()) {
1578 RESTWarning << "Mesh type is cylinder. But X and Y inside boundMax are not the same!" << RESTendl;
1579 RESTWarning << "Making second bound component Y equal to the X bound component!" << RESTendl;
1580 fBoundMax.back().SetY(fBoundMax.back().X());
1581 }
1582
1583 RESTDebug << "Reading new magnetic volume" << RESTendl;
1584 RESTDebug << "-----" << RESTendl;
1585 RESTDebug << "Filename : " << filename << RESTendl;
1586 RESTDebug << "Position: ( " << position.X() << ", " << position.Y() << ", " << position.Z() << ") mm"
1587 << RESTendl;
1588 RESTDebug << "Field: ( " << field.X() << ", " << field.Y() << ", " << field.Z() << ") T" << RESTendl;
1589 RESTDebug << "Max bounding box ( " << boundMax.X() << ", " << boundMax.Y() << ", " << boundMax.Z()
1590 << ")" << RESTendl;
1591 RESTDebug << "Mesh size ( " << meshSize.X() << ", " << meshSize.Y() << ", " << meshSize.Z() << ")"
1592 << RESTendl;
1593 RESTDebug << "----" << RESTendl;
1594
1595 magVolumeDef = GetNextElement(magVolumeDef);
1596 }
1597
1599
1600 // TODO we should check that the volumes do not overlap
1601}
1602
1608
1609 if (fReMap != TVector3(0, 0, 0)) {
1610 RESTMetadata << "Fields original mesh size has been remapped" << RESTendl;
1611 RESTMetadata << " " << RESTendl;
1612 }
1613
1614 RESTMetadata << " - Number of magnetic volumes : " << GetNumberOfVolumes() << RESTendl;
1615 RESTMetadata << " ------------------------------------------------ " << RESTendl;
1616 for (unsigned int p = 0; p < GetNumberOfVolumes(); p++) {
1617 if (p > 0) RESTMetadata << " ------------------------------------------------ " << RESTendl;
1618
1619 Double_t centerX = fPositions[p][0];
1620 Double_t centerY = fPositions[p][1];
1621 Double_t centerZ = fPositions[p][2];
1622
1623 Double_t halfSizeX = fBoundMax[p].X();
1624 Double_t halfSizeY = fBoundMax[p].Y();
1625 Double_t halfSizeZ = fBoundMax[p].Z();
1626
1627 Double_t xMin = centerX - halfSizeX;
1628 Double_t yMin = centerY - halfSizeY;
1629 Double_t zMin = centerZ - halfSizeZ;
1630
1631 Double_t xMax = centerX + halfSizeX;
1632 Double_t yMax = centerY + halfSizeY;
1633 Double_t zMax = centerZ + halfSizeZ;
1634
1635 RESTMetadata << "* Volume " << p << " centered at (" << centerX << "," << centerY << "," << centerZ
1636 << ") mm" << RESTendl;
1637 RESTMetadata << " - Grid mesh element size. X: " << fMeshSize[p].X() << "mm "
1638 << " Y: " << fMeshSize[p].Y() << "mm "
1639 << " Z: " << fMeshSize[p].Z() << "mm " << RESTendl;
1640 RESTMetadata << " - Offset field [T] : (" << fConstantField[p].X() << ", " << fConstantField[p].Y()
1641 << ", " << fConstantField[p].Z() << ")" << RESTendl;
1642 RESTMetadata << " - File loaded : " << fFileNames[p] << RESTendl;
1643 RESTMetadata << " " << RESTendl;
1644 RESTMetadata << " - Bounds : " << RESTendl;
1645 RESTMetadata << " xmin : " << xMin << " mm , xmax : " << xMax << " mm" << RESTendl;
1646 RESTMetadata << " ymin : " << yMin << " mm, ymax : " << yMax << " mm" << RESTendl;
1647 RESTMetadata << " zmin : " << zMin << " mm, zmax : " << zMax << " mm" << RESTendl;
1648 RESTMetadata << " " << RESTendl;
1649 }
1650 RESTMetadata << "+++++++++++++++++++++++++++++++++++++++++++++++++" << RESTendl;
1651}
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...
std::vector< Double_t > GetComponentAlongPath(Int_t axis, TVector3 from, TVector3 to, Double_t dl=1., Int_t Nmax=0)
It returns a vector describing the magnetic field profile component requested using the axis argument...
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.
TCanvas * DrawComponents(Int_t volId=0)
A method that creates a canvas where tracks traversing the magnetic volume are drawm together with th...
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(size_t id, 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:74
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.
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.
void SetError(std::string message="", bool print=true, int maxPrint=5)
A metadata class may use this method to signal that something went wrong.
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:577
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:253
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:370
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:442
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:405
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.