209 #include "TRestAxionField.h"
211 #include <TComplex.h>
212 #include <TVectorD.h>
213 #include <gsl/gsl_errno.h>
214 #include <gsl/gsl_integration.h>
252 Double_t lengthInMeters = Lcoh *
units(
"m");
256 Double_t sol = lengthInMeters * Bmag * tm;
270 Double_t lengthInMeters = Lcoh *
units(
"m");
274 Double_t sol = lengthInMeters * Bmag * tm / 2;
275 sol = sol * sol * 1.0e-20;
295 Double_t cohLength = fLcoh *
units(
"m");
297 Double_t photonMass = mg;
299 if (mg == 0 && fBufferGas) photonMass = fBufferGas->GetPhotonMass(fEa);
301 RESTDebug <<
"+--------------------------------------------------------------------------+" << RESTendl;
302 RESTDebug <<
" TRestAxionField::GammaTransmissionProbability. Parameter summary" << RESTendl;
303 RESTDebug <<
" Photon mass : " << photonMass <<
" eV" << RESTendl;
304 RESTDebug <<
" Axion mass : " << ma <<
" eV" << RESTendl;
305 RESTDebug <<
" Axion energy : " << fEa <<
" keV" << RESTendl;
306 RESTDebug <<
" Lcoh : " << fLcoh <<
" mm" << RESTendl;
307 RESTDebug <<
" Bmag : " << fBmag <<
" T" << RESTendl;
308 RESTDebug <<
"+--------------------------------------------------------------------------+" << RESTendl;
310 if (ma == 0.0 && photonMass == 0.0)
return BLHalfSquared(fBmag, fLcoh);
312 Double_t q = (ma * ma - photonMass * photonMass) / 2. / (fEa *
units(
"eV"));
314 Double_t phi = q * l;
316 Double_t Gamma = absLength;
317 if (absLength == 0 && fBufferGas) Gamma = fBufferGas->GetPhotonAbsorptionLength(fEa);
318 Double_t GammaL = Gamma * cohLength *
units(
"cm") /
units(
"m");
321 std::cout <<
"+------------------------+" << std::endl;
322 std::cout <<
" Intermediate calculations" << std::endl;
323 std::cout <<
" q : " << q <<
" eV" << std::endl;
324 std::cout <<
" l : " << l <<
" eV-1" << std::endl;
325 std::cout <<
" phi : " << phi << std::endl;
326 std::cout <<
"Gamma : " << Gamma << std::endl;
327 std::cout <<
"GammaL : " << GammaL << std::endl;
328 std::cout <<
"+------------------------+" << std::endl;
331 Double_t MFactor = phi * phi + GammaL * GammaL / 4.0;
332 MFactor = 1.0 / MFactor;
335 std::cout <<
"Mfactor : " << MFactor << std::endl;
336 std::cout <<
"(BL/2)^2 : " << BLHalfSquared(fBmag, fLcoh) << std::endl;
337 std::cout <<
"cos(phi) : " << cos(phi) << std::endl;
338 std::cout <<
"Exp(-GammaL) : " << exp(-GammaL) << std::endl;
341 double sol = (double)(MFactor * BLHalfSquared(fBmag, fLcoh) *
342 (1 + exp(-GammaL) - 2 * exp(-GammaL / 2) * cos(phi)));
344 if (fDebug) std::cout <<
"Axion-photon transmission probability : " << sol << std::endl;
354 Double_t mg, Double_t absLength) {
359 return GammaTransmissionProbability(ma, mg, absLength);
382 Double_t Ea, Double_t ma, Double_t mg,
383 Double_t absLength) {
385 Double_t Lcoh = (Bmag.size() - 1) * deltaL;
386 Double_t cohLength = Lcoh *
units(
"m");
388 Double_t photonMass = mg;
390 if (mg == 0 && fBufferGas) photonMass = fBufferGas->GetPhotonMass(Ea);
392 Double_t fieldAverage = 0;
393 if (Bmag.size() > 0) fieldAverage = std::accumulate(Bmag.begin(), Bmag.end(), 0.0) / Bmag.size();
396 std::cout <<
"+--------------------------------------------------------------------------+"
398 std::cout <<
" TRestAxionField::GammaTransmissionProbability. Parameter summary" << std::endl;
399 std::cout <<
" Photon mass : " << photonMass <<
" eV" << std::endl;
400 std::cout <<
" Axion mass : " << ma <<
" eV" << std::endl;
401 std::cout <<
" Axion energy : " << Ea <<
" keV" << std::endl;
402 std::cout <<
" Lcoh : " << cohLength <<
" m" << std::endl;
403 std::cout <<
" Bmag average : " << fieldAverage <<
" T" << std::endl;
404 std::cout <<
"+--------------------------------------------------------------------------+"
409 if (ma == 0.0 && photonMass == 0.0)
return BLHalfSquared(fieldAverage, Lcoh);
411 Double_t q = (ma * ma - photonMass * photonMass) / 2. / (Ea *
units(
"eV"));
413 Double_t phi = q * l;
415 Double_t Gamma = absLength;
416 if (absLength == 0 && fBufferGas) Gamma = fBufferGas->GetPhotonAbsorptionLength(Ea);
417 Double_t GammaL = Gamma * cohLength *
units(
"cm") /
units(
"m");
420 std::cout <<
"+------------------------+" << std::endl;
421 std::cout <<
" Intermediate calculations" << std::endl;
422 std::cout <<
" q : " << q <<
" eV" << std::endl;
423 std::cout <<
" l : " << l <<
" eV-1" << std::endl;
424 std::cout <<
" phi : " << phi << std::endl;
425 std::cout <<
"Gamma : " << Gamma << std::endl;
426 std::cout <<
"GammaL : " << GammaL << std::endl;
427 std::cout <<
"+------------------------+" << std::endl;
430 Double_t MFactor = phi * phi + GammaL * GammaL / 4.0;
431 MFactor = 1.0 / MFactor;
434 std::cout <<
"Mfactor : " << MFactor << std::endl;
435 std::cout <<
"(BL/2)^2 : " << BLHalfSquared(fieldAverage, Lcoh) << std::endl;
436 std::cout <<
"cos(phi) : " << cos(phi) << std::endl;
437 std::cout <<
"Exp(-GammaL) : " << exp(-GammaL) << std::endl;
443 for (
unsigned int n = 0; n < Bmag.size() - 1; n++) {
444 Double_t Bmiddle = 0.5 * (Bmag[n] + Bmag[n + 1]);
446 Double_t lStepIneV = ((double)n + 0.5) * deltaIneV;
447 Double_t lStepInCm = ((double)n + 0.5) * deltaL *
units(
"cm");
449 TComplex qCgC(0.5 * Gamma * lStepInCm, -q * lStepIneV);
450 qCgC = TComplex::Exp(qCgC);
452 TComplex integrand = Bmiddle * deltaL * qCgC;
457 Double_t sol = exp(-GammaL) * sum.Rho2() * BLHalfSquared(1, 1);
460 if (fDebug) std::cout <<
"Axion-photon transmission probability : " << sol << std::endl;
462 return (Double_t)sol;
486 gsl_set_error_handler_off();
488 if (!fMagneticField) {
489 RESTError <<
"TRestAxionField::GammaTransmissionFieldMapProbability requires a magnetic field map!"
491 RESTError <<
"Use TRestAxionField::AssignMagneticField method to assign one" << RESTendl;
495 if (fMagneticField->GetTrackLength() <= 0)
return {0.0, 0.0};
497 double photonMass = 0;
498 if (fBufferGas) photonMass = fBufferGas->GetPhotonMass(Ea);
501 std::cout <<
"+--------------------------------------------------------------------------+"
503 std::cout <<
" TRestAxionField::GammaTransmissionProbability. Parameter summary" << std::endl;
504 std::cout <<
" Photon mass : " << photonMass <<
" eV" << std::endl;
505 std::cout <<
" Axion mass : " << ma <<
" eV" << std::endl;
506 std::cout <<
" Axion energy : " << Ea <<
" keV" << std::endl;
507 std::cout <<
"+--------------------------------------------------------------------------+"
511 double q = (ma * ma - photonMass * photonMass) / 2. / (Ea *
units(
"eV"));
515 if (fBufferGas) Gamma = fBufferGas->GetPhotonAbsorptionLength(Ea) *
units(
"cm") /
units(
"mm");
518 std::cout <<
"+------------------------+" << std::endl;
519 std::cout <<
" Intermediate calculations" << std::endl;
520 std::cout <<
" q : " << q <<
" eV" << std::endl;
521 std::cout <<
"Gamma : " << Gamma << std::endl;
522 std::cout <<
"+------------------------+" << std::endl;
526 return ComputeResonanceIntegral(Gamma, accuracy, num_intervals);
528 return ComputeOffResonanceIntegral(q, Gamma, accuracy, num_intervals, qawo_levels);
550 Int_t num_intervals) {
553 std::pair<TRestAxionMagneticField*, double> params = {fMagneticField, Gamma};
555 gsl_integration_workspace* workspace = gsl_integration_workspace_alloc(num_intervals);
558 F.function = &Integrand;
561 auto start = std::chrono::system_clock::now();
563 int status = gsl_integration_qag(&F, 0, fMagneticField->GetTrackLength(), accuracy, accuracy,
564 num_intervals, GSL_INTEG_GAUSS61, workspace, &reprob, &rerr);
566 if (status > 0)
return {0, status};
568 auto end = std::chrono::system_clock::now();
569 auto seconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
571 double GammaL = Gamma * fMagneticField->GetTrackLength();
572 double C = exp(-GammaL) * BLHalfSquared(1, 1);
574 double prob = C * reprob * reprob;
575 double proberr = 2 * C * reprob * rerr;
578 std::cout <<
" ---- TRestAxionField::ComputeResonanceIntegral (QAG) ----" << std::endl;
579 std::cout <<
"Gamma: " << Gamma <<
" mm-1" << std::endl;
580 std::cout <<
"accuracy: " << accuracy << std::endl;
581 std::cout <<
"num_intervals: " << num_intervals << std::endl;
582 std::cout <<
" -------" << std::endl;
583 std::cout <<
"Probability: " << prob << std::endl;
584 std::cout <<
"Probability error: " << proberr << std::endl;
585 std::cout <<
"Computing time: " << seconds.count() << std::endl;
586 std::cout <<
" -------" << std::endl;
589 std::pair<Double_t, Double_t> sol = {prob, proberr};
614 double improb, imerr;
616 std::pair<TRestAxionMagneticField*, double> params = {fMagneticField, Gamma};
618 gsl_integration_workspace* workspace = gsl_integration_workspace_alloc(num_intervals);
621 F.function = &Integrand;
624 auto start = std::chrono::system_clock::now();
626 gsl_integration_qawo_table* wf =
627 gsl_integration_qawo_table_alloc(q, fMagneticField->GetTrackLength(), GSL_INTEG_COSINE, qawo_levels);
629 gsl_integration_qawo(&F, 0, accuracy, accuracy, num_intervals, workspace, wf, &reprob, &rerr);
631 gsl_integration_qawo_table_free(wf);
635 gsl_integration_qawo_table_set(wf, q, fMagneticField->GetTrackLength(), GSL_INTEG_SINE);
636 status = gsl_integration_qawo(&F, 0, accuracy, accuracy, num_intervals, workspace, wf, &improb, &imerr);
638 gsl_integration_qawo_table_free(wf);
642 auto end = std::chrono::system_clock::now();
643 auto seconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
645 double GammaL = Gamma * fMagneticField->GetTrackLength();
646 double C = exp(-GammaL) * BLHalfSquared(1, 1);
648 double prob = C * (reprob * reprob + improb * improb);
649 double proberr = 2 * C * TMath::Sqrt(reprob * reprob * rerr * rerr + improb * improb * imerr * imerr);
652 std::cout <<
" ---- TRestAxionField::ComputeOffResonanceIntegral (QAWO) ----" << std::endl;
653 std::cout <<
"Gamma: " << Gamma <<
" mm-1" << std::endl;
654 std::cout <<
"q: " << q <<
"mm-1" << std::endl;
655 std::cout <<
"accuracy: " << accuracy << std::endl;
656 std::cout <<
"num_intervals: " << num_intervals << std::endl;
657 std::cout <<
"qawo_levels: " << qawo_levels << std::endl;
658 std::cout <<
" -------" << std::endl;
659 std::cout <<
"Probability: " << prob << std::endl;
660 std::cout <<
"Probability error: " << proberr << std::endl;
661 std::cout <<
"Computing time: " << seconds.count() << std::endl;
662 std::cout <<
" -------" << std::endl;
665 std::pair<Double_t, Double_t> sol = {prob, proberr};
683 Double_t cohLength = fLcoh *
units(
"m");
685 Double_t photonMass = mg;
686 if (mg == 0 && fBufferGas) photonMass = fBufferGas->GetPhotonMass(fEa);
689 RESTDebug <<
"+--------------------------------------------------------------------------+"
691 RESTDebug <<
" TRestAxionField::AxionAbsorptionProbability. Parameter summary" << RESTendl;
692 RESTDebug <<
" Photon mass : " << photonMass <<
" eV" << RESTendl;
693 RESTDebug <<
" Axion mass : " << ma <<
" eV" << RESTendl;
694 RESTDebug <<
" Axion energy : " << fEa <<
" keV" << RESTendl;
695 RESTDebug <<
" Lcoh : " << fLcoh <<
" mm" << RESTendl;
696 RESTDebug <<
" Bmag : " << fBmag <<
" T" << RESTendl;
697 RESTDebug <<
"+--------------------------------------------------------------------------+"
701 if (ma == 0.0 && photonMass == 0.0)
return BLHalfSquared(fBmag, fLcoh);
703 Double_t q = (ma * ma - photonMass * photonMass) / 2. / (fEa *
units(
"eV"));
705 Double_t phi = q * l;
707 Double_t Gamma = absLength;
708 if (absLength == 0 && fBufferGas) Gamma = fBufferGas->GetPhotonAbsorptionLength(fEa);
709 Double_t GammaL = Gamma * cohLength *
units(
"cm") /
units(
"m");
712 RESTDebug <<
"+------------------------+" << RESTendl;
713 RESTDebug <<
" Intermediate calculations" << RESTendl;
714 RESTDebug <<
" q : " << q <<
" eV" << RESTendl;
715 RESTDebug <<
" l : " << l <<
" eV-1" << RESTendl;
716 RESTDebug <<
" phi : " << phi << RESTendl;
717 RESTDebug <<
"Gamma : " << Gamma << RESTendl;
718 RESTDebug <<
"GammaL : " << GammaL << RESTendl;
719 RESTDebug <<
"+------------------------+" << RESTendl;
722 Double_t MFactor = phi * phi + GammaL * GammaL / 4.0;
723 MFactor = 1.0 / MFactor;
726 RESTDebug <<
"Mfactor : " << MFactor << RESTendl;
727 RESTDebug <<
"(BL/2)^2 : " << BLHalfSquared(fBmag, fLcoh) << RESTendl;
728 RESTDebug <<
"cos(phi) : " << cos(phi) << RESTendl;
729 RESTDebug <<
"Exp(-GammaL) : " << exp(-GammaL) << RESTendl;
732 double sol = (double)(MFactor * BLHalfSquared(fBmag, fLcoh) * GammaL);
734 if (fDebug) RESTDebug <<
"Axion-photon absorption probability : " << sol << RESTendl;
744 Double_t mg, Double_t absLength) {
749 return AxionAbsorptionProbability(ma, mg, absLength);
765 Double_t maxMass = 10;
767 Double_t resonanceMass = 0;
768 if (fBufferGas) resonanceMass = fBufferGas->GetPhotonMass(fEa);
771 Double_t scanMass = resonanceMass;
772 Double_t Pmax = GammaTransmissionProbability(resonanceMass);
773 while (Pmax / 2 < GammaTransmissionProbability(scanMass)) {
775 if (scanMass > maxMass) {
776 RESTError <<
"TRestAxionField::GammaTransmissionProbability. Something went wrong when "
783 Double_t fwhm = scanMass - resonanceMass;
785 RESTError <<
"TRestAxionField::GammaTransmissionProbability. Problem calculating FWHM!" << RESTendl;
817 std::vector<std::pair<Double_t, Double_t>> massDensityPairs;
822 previousGas = fBufferGas;
823 fBufferGas =
nullptr;
827 double firstMass = GammaTransmissionFWHM() / 2;
831 AssignBufferGas(&gas);
833 Double_t ma = firstMass;
837 massDensityPairs.push_back(std::make_pair(ma, density));
840 Double_t factor = TMath::Exp(-ma * rampDown) + 1;
843 ma += GammaTransmissionFWHM() / factor;
846 massDensityPairs.push_back(std::make_pair(ma, density));
850 fBufferGas = previousGas;
852 return massDensityPairs;
A metadata class to define the gas properties used in axion search calculations.
Double_t GetDensityForMass(double m_gamma, double en=4.2)
It returns the equivalent gas density for a given photon mass expressed in eV and a given axion energ...
void SetGasDensity(TString gasName, Double_t density)
It adds a new gas component to the mixture. If it already exists it will update its density.
A basic class to define analytical axion-photon conversion calculations for axion helioscopes.
std::pair< Double_t, Double_t > GammaTransmissionFieldMapProbability(Double_t Ea, Double_t ma, Double_t accuracy=1.e-1, Int_t num_intervals=100, Int_t qawo_levels=20)
Performs the calculation of axion-photon conversion probability using directly equation (28) from J....
Double_t BL(Double_t Bmag, Double_t Lcoh)
Performs the calculation of (BL) factor in natural units.
Double_t AxionAbsorptionProbability(Double_t ma, Double_t mg=0, Double_t absLength=0)
Performs the calculation of axion-photon absorption probability using directly equation (18) from van...
void Initialize()
Initialization of TRestAxionField class.
Double_t GammaTransmissionProbability(Double_t ma, Double_t mg=0, Double_t absLength=0)
Performs the calculation of axion-photon conversion probability using directly equation (11) from van...
~TRestAxionField()
Default destructor.
Double_t BLHalfSquared(Double_t Bmag, Double_t Lcoh)
Performs the calculation of (BL/2)^2 factor in natural units.
std::vector< std::pair< Double_t, Double_t > > GetMassDensityScanning(std::string gasName="He", Double_t maMax=0.15, Double_t rampDown=5.0)
This method determines the proper densities to be used in an axion helioscope experiment in order to ...
std::pair< Double_t, Double_t > ComputeOffResonanceIntegral(Double_t q, Double_t Gamma, Double_t accuracy, Int_t num_intervals, Int_t qawo_levels)
Performs the calculation of axion-photon conversion probability using directly equation (28) from J....
TRestAxionField()
Default constructor.
Double_t GammaTransmissionFWHM(Double_t step=0.00001)
Performs the calculation of the FWHM for the axion-photon conversion probability computed in TRestAxi...
std::pair< Double_t, Double_t > ComputeResonanceIntegral(Double_t Gamma, Double_t accuracy, Int_t num_intervals)
Performs the calculation of axion-photon conversion probability using directly equation (28) from J....
constexpr double lightSpeed
Speed of light in m/s.
constexpr double PhMeterIneV
A meter in eV.
constexpr double naturalElectron
Electron charge in natural units.