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 
237 using namespace std;
238 
239 #include "TRestPhysics.h"
240 using namespace REST_Physics;
241 
242 #include "TGraph.h"
243 ClassImp(TRestAxionMagneticField);
244 
249 
264 TRestAxionMagneticField::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 
337 TCanvas* 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 
650 TCanvas* 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(1.5);
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 
780 void TRestAxionMagneticField::LoadMagneticFieldData(MagneticFieldVolume& mVol,
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 
1006 TVector3 TRestAxionMagneticField::GetMagneticField(Double_t x, Double_t y, Double_t z) {
1007  return GetMagneticField(TVector3(x, y, z));
1008 }
1009 
1018 TVector3 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 
1146 void 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 
1197  if (!FieldLoaded()) LoadMagneticVolumes();
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 
1236 Double_t TRestAxionMagneticField::GetTransversalComponent(TVector3 position, TVector3 direction) {
1237  return abs(GetMagneticField(position, false).Perp(direction));
1238 }
1239 
1251 std::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 
1288 std::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 
1323 void 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 
1362 Double_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 
1385 TVector3 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 
1433 TVector3 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 
1477 std::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 
1497 std::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...
MagneticFieldVolume * GetMagneticVolume(Int_t id)
It returns a pointer to the corresponding magnetic volume id.
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.
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 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
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 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 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 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 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
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.