diff --git a/HISTORY.md b/HISTORY.md index dea894e..f147a4a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -4,6 +4,29 @@ History Patch releases mean (the Z number in X.Y.Z version) that the underlying physics has not changed. Changes to the NEST version will always trigger a minor or major release. If this library changes such that end users have to change their code, this may also trigger a minor or major release. + +1.4.10 (2021-07-08) +----------------- +Sync with [NEST v2.2.2](https://github.com/NESTCollaboration/nest/releases/tag/v2.2.2) + +Code Quality and/or Misc Bug Fixes: + * Added default density argument for LXe case, forcing an argument re-ordering (Sophia) + * Moved position of "delete detector" in execNEST to solve python problem (Albert Baker, Greg R.) + * Approx eff func for single phe made simpler, for FlameDisx (Robert James, Sophia, Matthew) + * More robust rule used for when to approximate binomial as Gaussian (Sophia, Greg R.) + * Warn that you are in a region of too-low time between S1a and S1b for Kr83m only 1x (Sophia) + * Bad-order if-statements simplified with a min within a max for <0, >1 checks (Luke K., Matthew) +New Physics: + * Liquid Ar model for ER fits all the data better now, in both energy and dE/dx bases (Kate K.) + +Code Quality and/or Miscellaneous Bug Fixes: + * Deleted unused redundant line in GetS1 that re-calculated the drift time (Quentin Riffard, LBNL/LZ) + * Only print most error and warning messages if verbosity on (Quentin Riffard, LBNL/LZ) + * Updated TravisCI link in README and added note about OSX builds (Chris Tunnell, Rice/XENON) + * Use of abs value func standardized, lines broken up, multi-line string for cerr (Matthew at behest of Luke Kreczko, Bristol/LZ) +New Physics: + * Liquid Xe model for NR is now better behaved at few hundred keV and few hundred in S1: no odd increase in band width caused by Nex/Ni zeroing out and kinking the recombination probability. Mean yields model unchanged, nor recombination fluctuations / skewness. (Matthew and Greg R., UAlbany/LZ) + 1.4.9 (2021-06-01) ----------------- Sync with [NEST v2.2.1patch2](https://github.com/NESTCollaboration/nest/releases/tag/v2.2.1patch2) diff --git a/src/nestpy/LUX_Run03.hh b/src/nestpy/LUX_Run03.hh index 81618ad..d647f6c 100644 --- a/src/nestpy/LUX_Run03.hh +++ b/src/nestpy/LUX_Run03.hh @@ -80,7 +80,7 @@ public: double radius = sqrt(pow(xPos_mm,2.)+pow(yPos_mm,2.)); double amplitude = 307.9-0.3071*zPos_mm+0.0002257*pow(zPos_mm,2.); - double shape = 1.1525e-7*sqrt(fabs(zPos_mm-318.84)); + double shape = 1.1525e-7*sqrt(std::abs(zPos_mm-318.84)); double finalCorr = -shape * pow ( radius, 3. ) + amplitude; finalCorr /= 307.9; if ( (finalCorr < 0.5 || finalCorr > 1.5 || std::isnan(finalCorr)) && radius < radmax ) { diff --git a/src/nestpy/NEST.cpp b/src/nestpy/NEST.cpp index 009ccf3..444f4a7 100644 --- a/src/nestpy/NEST.cpp +++ b/src/nestpy/NEST.cpp @@ -302,7 +302,7 @@ QuantaResult NESTcalc::GetQuanta(const YieldResult& yields, double density, if (ValidityTests::nearlyEqual(yields.Lindhard, 1.) ) { skewness = 1. / (1. + exp((engy - E2) / E3)) * (alpha0 + cc0 * exp(-1. * fld / F0) * (1. - exp(-1. * engy / E0))) + 1. / (1. + exp(-1. * (engy - E2) / E3)) * cc1 * exp(-1. * engy / E1) * exp(-1. * sqrt(fld) / sqrt(F1)); - //if ( fabs(skewness) <= DBL_MIN ) skewness = DBL_MIN; + //if ( std::abs(skewness) <= DBL_MIN ) skewness = DBL_MIN; } else { skewness = FreeParam[5]; //2.25 but ~5-20 also good (for NR). All better than zero, but 0 is OK too @@ -311,7 +311,7 @@ QuantaResult NESTcalc::GetQuanta(const YieldResult& yields, double density, double widthCorrection = sqrt( 1. - (2./M_PI) * skewness*skewness/(1. + skewness*skewness)); double muCorrection = (sqrt(Variance)/widthCorrection)*(skewness/sqrt(1.+skewness*skewness))*sqrt(2./M_PI); - if ( fabs(skewness) > DBL_MIN && ValidityTests::nearlyEqual(ATOM_NUM, 54.) ) //skewness model only for Xenon! + if ( std::abs(skewness) > DBL_MIN && ValidityTests::nearlyEqual(ATOM_NUM, 54.) ) //skewness model only for Xenon! Ne = int(floor(RandomGen::rndm()->rand_skewGauss((1.-recombProb)*Ni-muCorrection,sqrt(Variance)/widthCorrection,skewness)+0.5)); else Ne = int(floor(RandomGen::rndm()->rand_gauss((1.-recombProb)*Ni,sqrt(Variance))+0.5)); @@ -413,7 +413,7 @@ YieldResult NESTcalc::GetYieldNR(double energy, double density, double dfield, d { throw std::runtime_error("ERROR: You need a minimum of 12 nuisance parameters for the mean yields."); } - if ( energy > 330. ) + if ( energy > HIGH_E_NR ) cerr << "\nWARNING: No data out here, you are beyond the AmBe endpoint of about 300 keV.\n"; int massNumber; double ScaleFactor[2] ={1., 1.}; @@ -436,16 +436,28 @@ YieldResult NESTcalc::GetYieldNR(double energy, double density, double dfield, d (1. - 1. / pow(1. + pow((energy / NuisParam[7]), NuisParam[8]), NuisParam[11])); Nq = Nph + Ne; double Ni = (4. / ThomasImel) * (exp(Ne * ThomasImel / 4.) - 1.); - double Nex = (-1. / ThomasImel) * (4. * exp(Ne * ThomasImel / 4.) - - (Ne + Nph) * ThomasImel - 4.); - if ( Nex <= 0. ) cerr << "\nCAUTION: You are approaching the border of NEST's validity for high-energy (OR, for LOW) NR, or are beyond it, at " << energy << " keV." << endl; - if ( fabs(Nex + Ni -Nq) > 2. * PHE_MIN ) + double Nex = (-1. / ThomasImel) * (4. * exp(Ne * ThomasImel / 4.) - (Ne + Nph) * ThomasImel - 4.); + + double NexONi = Nex / Ni; + Wvalue wvalue = WorkFunction(density,fdetector->get_molarMass(),fdetector->get_rmQuanta()); + if ( NexONi < wvalue.alpha && energy > 1e2 ) { + NexONi = wvalue.alpha; + Ni = Nq / ( 1. + NexONi ); + Nex = Nq - Ni; + } + if ( NexONi > 1.0 && energy < 1. ) { + NexONi = 1.00; + Ni = Nq / ( 1. + NexONi ); + Nex = Nq - Ni; + } + + if ( Nex <= 0. ) + cerr << "\nCAUTION: You are approaching the border of NEST's validity for high-energy (OR, for LOW) NR, or are beyond it, at " << energy << " keV." << endl; + if ( std::abs ( Nex + Ni - Nq ) > 2. * PHE_MIN ) { throw std::runtime_error("ERROR: Quanta not conserved. Tell Matthew Immediately!"); } - double NexONi = Nex / Ni; - Wvalue wvalue = WorkFunction(density,fdetector->get_molarMass(),fdetector->get_rmQuanta()); double Wq_eV = wvalue.Wq_eV; double L = (Nq / energy) * Wq_eV * 1e-3; @@ -784,7 +796,6 @@ vector NESTcalc::GetS1(const QuantaResult &quanta, double truthPosX, dou posDepSm = fdetector->FitS1(smearPos[0], smearPos[1], smearPos[2], VDetector::unfold); else posDepSm = fdetector->FitS1(0, 0, smearPos[2], VDetector::unfold); - double dt = (fdetector->get_TopDrift() - truthPos[2]) / driftVelocity; double dz_center = fdetector->get_TopDrift() - dV_mid * fdetector->get_dtCntr(); // go from t to z posDep /= @@ -894,7 +905,7 @@ vector NESTcalc::GetS1(const QuantaResult &quanta, double truthPosX, dou AreaTable[0].resize(numPts, 0.); AreaTable[1].resize(numPts, 0.); - int total_photons = (int)fabs(spike); + int total_photons = (int)std::abs(spike); int excitons = int(double(total_photons)*double(quanta.excitons)/double(quanta.photons)); photonstream photon_emission_times = GetPhotonTimes(type_num, total_photons, excitons, dfield, energy); @@ -909,7 +920,7 @@ vector NESTcalc::GetS1(const QuantaResult &quanta, double truthPosX, dou int ii, index; double min = 1e100, pTime; - for (ii = 0; ii < (int)fabs(spike); ++ii) { + for (ii = 0; ii < (int)std::abs(spike); ++ii) { PEperBin.clear(); PEperBin = fdetector->SinglePEWaveForm( photon_areas[0][ii] + photon_areas[1][ii], photon_times[ii]); @@ -1052,21 +1063,21 @@ vector NESTcalc::GetS1(const QuantaResult &quanta, double truthPosX, dou if ( RandomGen::rndm()->rand_uniform() > prob && prob < 1. ) { // coincidence has to happen in different PMTs // some of these are set to -1 to flag them as having been below threshold if (ValidityTests::nearlyEqual(scintillation[0], 0.)) scintillation[0] = PHE_MIN; - scintillation[0] = -1.*fabs(scintillation[0]); + scintillation[0] = -1.*std::abs(scintillation[0]); if (ValidityTests::nearlyEqual(scintillation[1], 0.)) scintillation[1] = PHE_MIN; - scintillation[1] = -1.*fabs(scintillation[1]); + scintillation[1] = -1.*std::abs(scintillation[1]); if (ValidityTests::nearlyEqual(scintillation[2], 0.)) scintillation[2] = PHE_MIN; - scintillation[2] = -1.*fabs(scintillation[2]); + scintillation[2] = -1.*std::abs(scintillation[2]); if (ValidityTests::nearlyEqual(scintillation[3], 0.)) scintillation[3] = PHE_MIN; - scintillation[3] = -1.*fabs(scintillation[3]); + scintillation[3] = -1.*std::abs(scintillation[3]); if (ValidityTests::nearlyEqual(scintillation[4], 0.)) scintillation[4] = PHE_MIN; - scintillation[4] = -1.*fabs(scintillation[4]); + scintillation[4] = -1.*std::abs(scintillation[4]); if (ValidityTests::nearlyEqual(scintillation[5], 0.)) scintillation[5] = PHE_MIN; - scintillation[5] = -1.*fabs(scintillation[5]); + scintillation[5] = -1.*std::abs(scintillation[5]); if (ValidityTests::nearlyEqual(scintillation[6], 0.)) scintillation[6] = PHE_MIN; - scintillation[6] = -1.*fabs(scintillation[6]); + scintillation[6] = -1.*std::abs(scintillation[6]); if (ValidityTests::nearlyEqual(scintillation[7], 0.)) scintillation[7] = PHE_MIN; - scintillation[7] = -1.*fabs(scintillation[7]); + scintillation[7] = -1.*std::abs(scintillation[7]); } // scintillation[8] = @@ -1164,7 +1175,7 @@ vector NESTcalc::GetS2(int Ne, double truthPosX, double truthPosY, doubl for (i = 0; i < stopPoint; ++i) { elecTravT = 0.; // resetting for the current electron DL = RandomGen::rndm()->rand_gauss(0., sigmaDL); - DT = fabs(RandomGen::rndm()->rand_gauss(0., sigmaDT)); + DT = std::abs(RandomGen::rndm()->rand_gauss(0., sigmaDT)); phi = 2. * M_PI * RandomGen::rndm()->rand_uniform(); sigX = DT * cos(phi); sigY = DT * sin(phi); @@ -1211,7 +1222,7 @@ vector NESTcalc::GetS2(int Ne, double truthPosX, double truthPosY, doubl DL_time = DL / driftVelocity_gas; electronstream[i] += DL_time; if ( i >= Nee && eTrain ) { // exponential based on arXiv:1711.07025, power on 2004.07791 - E_liq = fdetector->get_E_gas() / (EPS_LIQ / fabs(EPS_GAS)); + E_liq = fdetector->get_E_gas() / (EPS_LIQ / std::abs(EPS_GAS)); tau2 = ( fdetector->get_TopDrift() / driftVelocity );//0.58313 * exp(0.20929 * E_liq) * 1e3; tau1 = 1.40540 * exp(0.15578 * E_liq) * 1e3 * 1e-2; amp2 = 0.38157 * exp(0.21177 * E_liq) * 1e-2; @@ -1362,10 +1373,10 @@ vector NESTcalc::GetS2(int Ne, double truthPosX, double truthPosY, doubl // units) } - if (pulseArea < fabs(fdetector->get_s2_thr())) { + if (pulseArea < std::abs(fdetector->get_s2_thr())) { for (i = 0; i < 8; ++i) { if (ValidityTests::nearlyEqual(ionization[i], 0.)) ionization[i] = PHE_MIN; - ionization[i] = -1.*fabs(ionization[i]); + ionization[i] = -1.*std::abs(ionization[i]); } } @@ -1381,7 +1392,7 @@ vector NESTcalc::CalculateG2(bool verbosity) { // Set parameters for calculating EL yield and extraction double alpha = 0.137, beta = 4.70e-18, gamma = 0; // note the value of alpha is similar to ~1/7eV. Not coincidence. Noted in Mock et al. // actually listed as 'a' and 'b' in ref (below). Units 1/V, cm^2 - double epsilonRatio = EPS_LIQ / fabs(EPS_GAS); + double epsilonRatio = EPS_LIQ / std::abs(EPS_GAS); if (fdetector->get_inGas()) epsilonRatio = 1.; // in an all-gas detector, E_liq variable below simply // becomes the field value between anode and gate @@ -1501,7 +1512,7 @@ vector NESTcalc::GetSpike(int Nph, double dx, double dy, double dz, newSpike[1] = oldScint[5]; return newSpike; } - newSpike[0] = fabs(oldScint[6]); + newSpike[0] = std::abs(oldScint[6]); double TruncGauss = 0.; while ( TruncGauss <= 0. ) TruncGauss = RandomGen::rndm()->rand_gauss(newSpike[0],(fdetector->get_sPEres()/4.)*sqrt(newSpike[0])); @@ -1727,7 +1738,7 @@ double NESTcalc::GetDriftVelocity_MagBoltz( } if (gasdep >= 3.8e-17) edrift = 6e21 * gasdep - 32279.; - return fabs ( edrift ) * 1e-5; // from cm/s into mm per microsecond + return std::abs ( edrift ) * 1e-5; // from cm/s into mm per microsecond } vector NESTcalc::SetDriftVelocity_NonUniform(double rho, double zStep, @@ -1742,7 +1753,7 @@ vector NESTcalc::SetDriftVelocity_NonUniform(double rho, double zStep, if (!fdetector->get_inGas()) driftTime += zStep / SetDriftVelocity(fdetector->get_T_Kelvin(), rho, fdetector->get_E_gas() / - (EPS_LIQ / fabs(EPS_GAS)) * 1e3); + (EPS_LIQ / std::abs(EPS_GAS)) * 1e3); else // if gate == TopDrift properly set, shouldn't happen driftTime += zStep / GetDriftVelocity_MagBoltz( rho, fdetector->get_E_gas() * 1e3); @@ -1774,12 +1785,12 @@ vector NESTcalc::xyResolution(double xPos_mm, double yPos_mm, double sigmaR = kappa / sqrt(A_top); // ibid. double phi = 2. * M_PI * RandomGen::rndm()->rand_uniform(); - sigmaR = fabs(RandomGen::rndm()->rand_gauss(0.0, sigmaR)); + sigmaR = std::abs(RandomGen::rndm()->rand_gauss(0.0, sigmaR)); double sigmaX = sigmaR * cos(phi); double sigmaY = sigmaR * sin(phi); if ( sigmaR > 1e2 || std::isnan(sigmaR) || sigmaR <= 0. || - fabs(sigmaX) > 1e2 || fabs(sigmaY) > 1e2 ) { + std::abs(sigmaX) > 1e2 || std::abs(sigmaY) > 1e2 ) { if ( A_top > 20. ) { cerr << "WARNING: your position resolution is worse than 10 cm. Is that correct?!" << endl; cerr << "Setting resolution to perfect." << endl; sigmaX=0.; sigmaY=0.; diff --git a/src/nestpy/NEST.hh b/src/nestpy/NEST.hh index b2d4bb4..29a762c 100644 --- a/src/nestpy/NEST.hh +++ b/src/nestpy/NEST.hh @@ -76,6 +76,7 @@ #include #include +#define HIGH_E_NR 330. #define W_DEFAULT 13.4 // default work func, in eV. arXiv:1611.10322. +/- 0.35. 19.5-19.6 eV for LAr #define W_SCINT 8.5e-3 // the *max* possible energy of 1 scint phot, keV. Make this at least 10 eV for LAr #define NEST_AVO 6.0221409e+23 diff --git a/src/nestpy/TestSpectra.cpp b/src/nestpy/TestSpectra.cpp index 81fd84e..6d99186 100644 --- a/src/nestpy/TestSpectra.cpp +++ b/src/nestpy/TestSpectra.cpp @@ -289,7 +289,7 @@ double TestSpectra::WIMP_dRate(double ER, double mWimp, double dayNum) { if ((x_e + x_min) < x_esc) { thisCase = 1; } - if ((x_min > fabs(x_esc - x_e)) && ((x_e + x_esc) > x_min)) { + if ((x_min > std::abs(x_esc - x_e)) && ((x_e + x_esc) > x_min)) { thisCase = 2; } if (x_e > (x_min + x_esc)) { diff --git a/src/nestpy/__init__.py b/src/nestpy/__init__.py index f17948c..d0be9d8 100644 --- a/src/nestpy/__init__.py +++ b/src/nestpy/__init__.py @@ -1,5 +1,5 @@ -__version__ = '1.4.9' -__nest_version__ = '2.2.1patch2' +__version__ = '1.4.10' +__nest_version__ = '2.2.2' from .nestpy import * diff --git a/src/nestpy/execNEST.cpp b/src/nestpy/execNEST.cpp index 88d6a94..606c3ee 100644 --- a/src/nestpy/execNEST.cpp +++ b/src/nestpy/execNEST.cpp @@ -11,6 +11,7 @@ * Created on August 1, 2017, 1:03 PM */ +#include #include "NEST.hh" #include "TestSpectra.hh" #include "analysis.hh" @@ -41,7 +42,8 @@ int main(int argc, char** argv) { if ( ValidityTests::nearlyEqual(ATOM_NUM, 18.) ) { detector->set_molarMass(39.948); - cerr << "\nWARNING: Argon is currently only in alpha testing mode!! Many features copied over from Xenon wholesale still. Use models at your own risk.\n" << endl; + if ( verbosity ) + cerr << "\nWARNING: Argon is currently only in alpha testing mode!! Many features copied over from Xenon wholesale still. Use models at your own risk.\n" << endl; } /* vector eList = { 1., 2., 3. }; // fast example--for PLR, ML train @@ -159,7 +161,7 @@ int main(int argc, char** argv) { numEvts = (uint64_t)atof(argv[1]); if ( numEvts <= 0 ) { - cerr << "ERROR, you must simulate at least 1 event, or 1 kg*day" << endl; + if ( verbosity ) cerr << "ERROR, you must simulate at least 1 event, or 1 kg*day" << endl; return 1; } type = argv[2]; @@ -266,23 +268,23 @@ NESTObservableArray runNESTvec ( VDetector* detector, INTERACTION_TYPE particleT scint2= n.GetS2(quanta.electrons,truthPos[0],truthPos[1],truthPos[2],smearPos[0],smearPos[1],smearPos[2], driftTime,vD,i,useField,0,verbosity,wf_time,wf_amp,g2_params); if ( scint[7] > PHE_MIN && scint2[7] > PHE_MIN ) { //unlike usual, kill (don't skip, just -> 0) sub-thr evts - OutputResults.s1_nhits.push_back(abs(int(scint[0]))); - OutputResults.s1_nhits_thr.push_back(abs(int(scint[8]))); - OutputResults.s1_nhits_dpe.push_back(abs(int(scint[1]))); - OutputResults.s1r_phe.push_back(fabs(scint[2])); - OutputResults.s1c_phe.push_back(fabs(scint[3])); - OutputResults.s1r_phd.push_back(fabs(scint[4])); - OutputResults.s1c_phd.push_back(fabs(scint[5])); - OutputResults.s1r_spike.push_back(fabs(scint[6])); - OutputResults.s1c_spike.push_back(fabs(scint[7])); //default is S1c in units of spikes, 3-D XYZ corr - OutputResults.Nee.push_back(abs(int(scint2[0]))); - OutputResults.Nph.push_back(abs(int(scint2[1]))); - OutputResults.s2_nhits.push_back(abs(int(scint2[2]))); - OutputResults.s2_nhits_dpe.push_back(abs(int(scint2[3]))); - OutputResults.s2r_phe.push_back(fabs(scint2[4])); - OutputResults.s2c_phe.push_back(fabs(scint2[5])); - OutputResults.s2r_phd.push_back(fabs(scint2[6])); - OutputResults.s2c_phd.push_back(fabs(scint2[7])); //default is S2c in terms of phd, not phe a.k.a. PE + OutputResults.s1_nhits.push_back(std::abs(int(scint[0]))); + OutputResults.s1_nhits_thr.push_back(std::abs(int(scint[8]))); + OutputResults.s1_nhits_dpe.push_back(std::abs(int(scint[1]))); + OutputResults.s1r_phe.push_back(std::abs(scint[2])); + OutputResults.s1c_phe.push_back(std::abs(scint[3])); + OutputResults.s1r_phd.push_back(std::abs(scint[4])); + OutputResults.s1c_phd.push_back(std::abs(scint[5])); + OutputResults.s1r_spike.push_back(std::abs(scint[6])); + OutputResults.s1c_spike.push_back(std::abs(scint[7])); //default is S1c in units of spikes, 3-D XYZ corr + OutputResults.Nee.push_back(std::abs(int(scint2[0]))); + OutputResults.Nph.push_back(std::abs(int(scint2[1]))); + OutputResults.s2_nhits.push_back(std::abs(int(scint2[2]))); + OutputResults.s2_nhits_dpe.push_back(std::abs(int(scint2[3]))); + OutputResults.s2r_phe.push_back(std::abs(scint2[4])); + OutputResults.s2c_phe.push_back(std::abs(scint2[5])); + OutputResults.s2r_phd.push_back(std::abs(scint2[6])); + OutputResults.s2c_phd.push_back(std::abs(scint2[7])); //default is S2c in terms of phd, not phe a.k.a. PE } else { OutputResults.s1_nhits.push_back(0); @@ -313,12 +315,11 @@ int execNEST(VDetector* detector, uint64_t numEvts, const string& type, double fPos, int seed, bool no_seed, double dayNumber ) { // Construct NEST class using detector object NESTcalc n(detector); - NuisParam = {11.,1.1,0.0480,-0.0533,12.6,0.3,2.,0.3,2.,0.5,1., 1.}; - FreeParam = {1.,1.,0.10,0.5,0.19,2.25}; + NuisParam = {11.,1.1,0.0480,-0.0533,12.6,0.3,2.,0.3,2.,0.5,1.,1.}; + FreeParam = {1.,1.,0.1,0.5,0.19,2.25}; if (detector->get_TopDrift() <= 0. || detector->get_anode() <= 0. || detector->get_gate() <= 0.) { - cerr << "ERROR, unphysical value(s) of position within the detector " - "geometry."; // negative or 0 for cathode position is OK (e.g., LZ) + if ( verbosity ) cerr << "ERROR, unphysical value(s) of position within the detector geometry."; // negative or 0 for cathode position is OK (e.g., LZ) return 1; } @@ -347,7 +348,7 @@ vector signal1, signal2, signalE, vTable; eMax = hiEregime; // the default energy max if ( ValidityTests::nearlyEqual(eMax, 0.) && type != "muon" && type != "MIP" && type != "LIP" && type != "mu" && type != "mu-" ) { - cerr << "ERROR: The maximum energy (or Kr time sep) cannot be 0 keV (or 0 ns)!" << endl; + if ( verbosity ) cerr << "ERROR: The maximum energy (or Kr time sep) cannot be 0 keV (or 0 ns)!" << endl; return 1; } @@ -359,7 +360,7 @@ vector signal1, signal2, signalE, vTable; type_num = NR; //-1: default particle type is also NR else if (type == "WIMP") { if (eMin < 0.44) { //here eMin is WIMP mass - cerr << "WIMP mass too low, you're crazy!" << endl; + if ( verbosity ) cerr << "WIMP mass too low, you're crazy!" << endl; return 1; } type_num = WIMP; @@ -415,33 +416,36 @@ vector signal1, signal2, signalE, vTable; poisson_draw(1.5764e-7*double(numEvts)); } else if ( type == "fullGamma" ) { type_num = fullGamma; - cerr << "Please choose gamma source. The allowed sources are:\n\"Co57\"\n\"Co60\"\n\"Cs137\"\nSource: "; + if ( verbosity ) cerr << "Please choose gamma source. The allowed sources are:\n\"Co57\"\n\"Co60\"\n\"Cs137\"\nSource: "; cin >> gamma_source; - if ( gamma_source == "Co60" ) { + if ( gamma_source == "Co60" && verbosity ) { cerr << "WARNING: This source is in the pair production range. Electron/positron pairs are not accounted for after initial interaction, and some " << "photons and electrons may go unaccounted." << endl; } - } else { - cerr << "UNRECOGNIZED PARTICLE TYPE!! VALID OPTIONS ARE:" << endl; - cerr << "NR or neutron," << endl; - cerr << "WIMP," << endl; - cerr << "B8 or Boron8 or 8Boron or 8B or Boron-8," << endl; - cerr << "DD or D-D," << endl; - cerr << "AmBe," << endl; - cerr << "Cf or Cf252 or 252Cf or Cf-252," << endl; - cerr << "ion or nucleus," << endl; - cerr << "alpha," << endl; - cerr << "gamma or gammaRay," << endl; - cerr << "x-ray or xray or xRay or X-ray or Xray or XRay," << endl; - cerr << "Kr83m or 83mKr or Kr83," << endl; - cerr << "CH3T or tritium," << endl; - cerr << "Carbon14 or 14C or C14 or C-14 or Carbon-14," << endl; - cerr << "beta or ER or Compton or compton or electron or e-," << endl; - cerr << "pp or ppSolar with many various underscore, hyphen and capitalization permutations permitted," << endl; - cerr << "atmNu," << endl; - cerr << "muon or MIP or LIP or mu or mu-, and" << endl; - cerr << "fullGamma" << endl; - + } + else { + if ( verbosity ) { + string particleTypes = "UNRECOGNIZED PARTICLE TYPE!! VALID OPTIONS ARE:\n" + "NR or neutron,\n" + "WIMP,\n" + "B8 or Boron8 or 8Boron or 8B or Boron-8,\n" + "DD or D-D,\n" + "AmBe,\n" + "Cf or Cf252 or 252Cf or Cf-252,\n" + "ion or nucleus,\n" + "alpha,\n" + "gamma or gammaRay,\n" + "x-ray or xray or xRay or X-ray or Xray or XRay,\n" + "Kr83m or 83mKr or Kr83,\n" + "CH3T or tritium,\n" + "Carbon14 or 14C or C14 or C-14 or Carbon-14,\n" + "beta or ER or Compton or compton or electron or e-,\n" + "pp or ppSolar with many various underscore, hyphen and capitalization permutations permitted,\n" + "atmNu,\n" + "muon or MIP or LIP or mu or mu-, and\n" + "fullGamma\n"; + copy(particleTypes.begin(),particleTypes.end(),std::ostream_iterator(cerr,"")); + } return 1; } @@ -449,16 +453,14 @@ vector signal1, signal2, signalE, vTable; if (type_num == Kr83m) { if ( (ValidityTests::nearlyEqual(eMin, 9.4) || ValidityTests::nearlyEqual(eMin, 32.1) || ValidityTests::nearlyEqual(eMin, 41.5) || ValidityTests::nearlyEqual(eMin, 41.55) || ValidityTests::nearlyEqual(eMin, 41.6)) && eMin != eMax ) { maxTimeSep = eMax; - if ( eMax <= 0. ) { cerr << "Max t sep must be +." << endl; return 1; } + if ( eMax <= 0. ) { if ( verbosity ) cerr << "Max t sep must be +." << endl; return 1; } } else { - cerr << "ERROR: For Kr83m, put E_min as 9.4, 32.1, or 41.5 keV " - "and E_max as the max time-separation [ns] between the two decays " - "please." << endl; + if ( verbosity ) cerr << "ERROR: For Kr83m, put E_min as 9.4, 32.1, or 41.5 keV and E_max as the max time-separation [ns] between the two decays please." << endl; return 1; } } - if ((eMin < 10. || eMax < 10.) && type_num == gammaRay) { + if ((eMin < 10. || eMax < 10.) && type_num == gammaRay && verbosity) { cerr << "WARNING: Typically beta model works better for ER BG at low " "energies as in a WS." << endl; cerr << "ER data is often best matched by a weighted average of the beta & " @@ -468,7 +470,7 @@ vector signal1, signal2, signalE, vTable; double rho = n.SetDensity(detector->get_T_Kelvin(), detector->get_p_bar()); if (rho <= 0. || detector->get_T_Kelvin() <= 0. || detector->get_p_bar() <= 0.) { - cerr << "ERR: Unphysical thermodynamic property!"; + if ( verbosity ) cerr << "ERR: Unphysical thermodynamic property!"; return 1; } if ( rho < 1.75 && ValidityTests::nearlyEqual(ATOM_NUM, 54.) ) detector->set_inGas(true); @@ -480,7 +482,7 @@ vector signal1, signal2, signalE, vTable; // Calculate and print g1, g2 parameters (once per detector) vector g2_params = n.CalculateG2(verbosity); - g2 = fabs(g2_params[3]); + g2 = std::abs(g2_params[3]); double g1 = detector->get_g1(); double centralZ = @@ -499,7 +501,7 @@ vector signal1, signal2, signalE, vTable; } else { double energyMaximum; if (eMax < 0.) - energyMaximum = 1. / fabs(eMax); + energyMaximum = 1. / std::abs(eMax); else energyMaximum = eMax; if ( type_num == Kr83m ) @@ -508,7 +510,7 @@ vector signal1, signal2, signalE, vTable; yieldsMax = n.GetYields(type_num, energyMaximum, rho, centralField, double(massNum), double(atomNum), NuisParam); } - if ( ( g1 * yieldsMax.PhotonYield ) > ( 2. * maxS1 ) && eMin != eMax && type_num != Kr83m ) + if ( ( g1 * yieldsMax.PhotonYield ) > ( 2. * maxS1 ) && eMin != eMax && type_num != Kr83m && verbosity ) cerr << "\nWARNING: Your energy maximum may be too high given your maxS1.\n"; if ( type_num < 6 ) massNum = 0; @@ -627,10 +629,10 @@ vector signal1, signal2, signalE, vTable; if ( !dEOdxBasis ) { if ( keV < 0 ) { - cerr << "ERROR: Get ready for time travel or FTL--negative energy!" << endl; + if ( verbosity ) cerr << "ERROR: Get ready for time travel or FTL--negative energy!" << endl; return 1; } - if ( ValidityTests::nearlyEqual ( keV, 0. ) ) { + if ( ValidityTests::nearlyEqual ( keV, 0. ) && verbosity ) { cerr << "WARNING: Zero energy has occurred, and this is not normal" << endl; } } @@ -660,10 +662,10 @@ vector signal1, signal2, signalE, vTable; ++i; } if ( !dEOdxBasis ) { - if ( pos_x != -999. && pos_y != -999. && (pos_x * pos_x + pos_y * pos_y) > detector->get_radius()*detector->get_radius() && j == 0 ) + if ( pos_x != -999. && pos_y != -999. && (pos_x * pos_x + pos_y * pos_y) > detector->get_radius()*detector->get_radius() && j == 0 && verbosity ) cerr << "WARNING: outside fiducial radius." << endl; if ( pos_x != -999. && pos_y != -999. && (pos_x * pos_x + pos_y * pos_y) > detector->get_radmax()*detector->get_radmax() ) { - cerr << "\nERROR: outside physical radius!!!" << endl; + if ( verbosity ) cerr << "\nERROR: outside physical radius!!!" << endl; return EXIT_FAILURE; } pos_z = stof(position); @@ -690,14 +692,13 @@ vector signal1, signal2, signalE, vTable; field = inField; // no fringing if(field < 0. || detector->get_E_gas() < 0.) { - cerr << "\nERROR: Neg field is not permitted. We don't simulate field " - "dir (yet). Put in magnitude.\n"; + if ( verbosity ) cerr << "\nERROR: Neg field is not permitted. We don't simulate field dir (yet). Put in magnitude.\n"; return 1; } - if(ValidityTests::nearlyEqual(field, 0.) || std::isnan(field)) + if((ValidityTests::nearlyEqual(field, 0.) || std::isnan(field)) && verbosity) cerr << "\nWARNING: A LITERAL ZERO (or undefined) FIELD MAY YIELD WEIRD " "RESULTS. USE A SMALL VALUE INSTEAD.\n"; - if(field > 12e3 || detector->get_E_gas() > 17e3) + if((field > 12e3 || detector->get_E_gas() > 17e3) && verbosity) cerr << "\nWARNING: Your field is >12,000 V/cm. No data out here. Are " "you sure about this?\n"; @@ -727,7 +728,7 @@ vector signal1, signal2, signalE, vTable; if ( timeStamp > tZero ) fprintf ( stdout, "dayNum\t\t" ); if ( (ValidityTests::nearlyEqual(eMax, eMin) || type_num == Kr83m) && numBins == 1 && MCtruthE ) { MCtruthE = false; - fprintf(stderr, "Simulating a mono-E peak; setting MCtruthE false.\n"); + if ( verbosity ) fprintf(stderr, "Simulating a mono-E peak; setting MCtruthE false.\n"); } if(eMax > hiEregime) fprintf(stdout, "Energy [keV]"); @@ -750,7 +751,7 @@ vector signal1, signal2, signalE, vTable; if(inField != -1. && detector->get_dt_min() > (detector->get_TopDrift() - 0.) / vD && field >= FIELD_MIN) { - cerr << "ERROR: dt_min is too restrictive (too large)" << endl; + if ( verbosity ) cerr << "ERROR: dt_min is too restrictive (too large)" << endl; return 1; } if((driftTime > detector->get_dt_max() || @@ -758,7 +759,7 @@ vector signal1, signal2, signalE, vTable; (ValidityTests::nearlyEqual(fPos, -1.) || ValidityTests::nearlyEqual(stof(position), -1.)) && field >= FIELD_MIN) goto Z_NEW; if(detector->get_dt_max() > (detector->get_TopDrift() - 0.) / vD && !j && - field >= FIELD_MIN) { + field >= FIELD_MIN && verbosity) { cerr << "WARNING: dt_max is greater than max possible" << endl; } @@ -766,11 +767,11 @@ vector signal1, signal2, signalE, vTable; // code-block dealing with user error (rounding another possible culprit) if ( !dEOdxBasis ) { if(pos_z <= 0) { - cerr << "WARNING: unphysically low Z coordinate (vertical axis of detector) of " << pos_z << " mm" << endl; //warn user on screen + if ( verbosity ) cerr << "WARNING: unphysically low Z coordinate (vertical axis of detector) of " << pos_z << " mm" << endl; //warn user on screen pos_z = z_step; } if((pos_z > (detector->get_TopDrift() + z_step) || driftTime < 0.0) && field >= FIELD_MIN) { - cerr << "WARNING: unphysically big Z coordinate (vertical axis of detector) of " << pos_z << " mm" << endl; // give the specifics + if ( verbosity ) cerr << "WARNING: unphysically big Z coordinate (vertical axis of detector) of " << pos_z << " mm" << endl; // give the specifics driftTime = 0.0; pos_z = detector->get_TopDrift() - z_step; //just fix it and move on } @@ -826,7 +827,7 @@ vector signal1, signal2, signalE, vTable; norm[0] = (xf - xi) / distance; norm[1] = (yf - yi) / distance; norm[2] = (zf - zi) / distance; - while ( zz > zf && ( xx * xx + yy * yy ) < detector->get_radmax()*detector->get_radmax() && fabs(refEnergy) > PHE_MIN ) { + while ( zz > zf && ( xx * xx + yy * yy ) < detector->get_radmax()*detector->get_radmax() && std::abs(refEnergy) > PHE_MIN ) { // stop making S1 and S2 if particle exits Xe volume, OR runs out of energy (in case of beta) if ( eMin < 0. ) { if ( (keV+eStep) > -eMin ) eStep = -eMin - keV; @@ -964,11 +965,11 @@ vector signal1, signal2, signalE, vTable; } NEW_RANGES: - if(usePD == 0 && fabs(scint[3]) > minS1 && scint[3] < maxS1) + if(usePD == 0 && std::abs(scint[3]) > minS1 && scint[3] < maxS1) signal1.push_back(scint[3]); - else if(usePD == 1 && fabs(scint[5]) > minS1 && scint[5] < maxS1) + else if(usePD == 1 && std::abs(scint[5]) > minS1 && scint[5] < maxS1) signal1.push_back(scint[5]); - else if((usePD >= 2 && fabs(scint[7]) > minS1 && scint[7] < maxS1) || + else if((usePD >= 2 && std::abs(scint[7]) > minS1 && scint[7] < maxS1) || maxS1 >= 998.5) //xtra | handles bizarre bug of ~0eff, S1=999 signal1.push_back(scint[7]); else @@ -981,28 +982,28 @@ vector signal1, signal2, signalE, vTable; if ( (useS2 == 0 && logMax <= log10(maxS2/maxS1)) || (useS2 == 1 && logMax <= log10(maxS2)) || (useS2 == 2 && logMax <= log10(maxS2/maxS1)) ) { - if ( j == 0 ) + if ( j == 0 && verbosity ) cerr << "err: You may be chopping off the upper half of your (ER?) band; increase logMax and/or maxS2" << endl; } if ( (useS2 == 0 && logMin >= log10(lowest2/lowest1)) || (useS2 == 1 && logMin >= log10(lowest2)) || (useS2 == 2 && logMin >= log10(lowest2/lowest1)) ) { - if ( j == 0 ) + if ( j == 0 && verbosity ) cerr << "err: You may be chopping off the lower half of your (NR?) band; decrease logMin and/or minS2" << endl; } - if(usePD == 0 && fabs(scint2[5]) > minS2 && scint2[5] < maxS2) + if(usePD == 0 && std::abs(scint2[5]) > minS2 && scint2[5] < maxS2) signal2.push_back(scint2[5]); - else if(usePD >= 1 && fabs(scint2[7]) > minS2 && scint2[7] < maxS2) + else if(usePD >= 1 && std::abs(scint2[7]) > minS2 && scint2[7] < maxS2) signal2.push_back(scint2[7]); // no spike option for S2 else signal2.push_back(-999.); if ( ValidityTests::nearlyEqual(eMin, eMax) || type_num == Kr83m ) { - if((scint[3] > maxS1 || scint[5] > maxS1 || scint[7] > maxS1) && j < 10) + if((scint[3] > maxS1 || scint[5] > maxS1 || scint[7] > maxS1) && j < 10 && verbosity) cerr << "WARNING: Some S1 pulse areas are greater than maxS1" << endl; if((scint2[5] > maxS2 || scint2[7] > maxS2) && - j < 10) //don't repeat too much: only if within first 10 events then show (+above) + j < 10 && verbosity) //don't repeat too much: only if within first 10 events then show (+above) cerr << "WARNING: Some S2 pulse areas are greater than maxS2" << endl; } @@ -1024,15 +1025,15 @@ vector signal1, signal2, signalE, vTable; } else MultFact = 1.; } if(usePD == 0) - Nph = fabs(scint[3]) / (g1 * (1. + detector->get_P_dphe())); + Nph = std::abs(scint[3]) / (g1 * (1. + detector->get_P_dphe())); else if(usePD == 1) - Nph = fabs(scint[5]) / g1; + Nph = std::abs(scint[5]) / g1; else - Nph = fabs(scint[7]) / g1; + Nph = std::abs(scint[7]) / g1; if(usePD == 0) - Ne = fabs(scint2[5]) / (g2 * (1. + detector->get_P_dphe())); + Ne = std::abs(scint2[5]) / (g2 * (1. + detector->get_P_dphe())); else - Ne = fabs(scint2[7]) / g2; + Ne = std::abs(scint2[7]) / g2; Nph *= MultFact; if ( signal1.back() <= 0. && timeStamp == tZero ) Nph= 0.; if ( signal2.back() <= 0. && timeStamp == tZero ) Ne = 0.; @@ -1081,11 +1082,13 @@ vector signal1, signal2, signalE, vTable; signal1.pop_back(); signal2.pop_back(); signalE.pop_back(); - cerr << endl << "CAUTION: Efficiency seems to have been zero, so trying again with full S1 and S2 ranges." - << endl; - cerr - << "OR, you tried to simulate a mono-energetic peak with MC truth E turned on. Silly! Setting MCtruthE to false." - << endl; + if ( verbosity ) { + cerr << endl << "CAUTION: Efficiency seems to have been zero, so trying again with full S1 and S2 ranges." + << endl; + cerr + << "OR, you tried to simulate a mono-energetic peak with MC truth E turned on. Silly! Setting MCtruthE to false." + << endl; + } goto NEW_RANGES; } @@ -1139,7 +1142,7 @@ vector signal1, signal2, signalE, vTable; if ( truthPos[2] < detector->get_cathode() && verbosity && !BeenHere && !dEOdxBasis ) { BeenHere = true; - fprintf ( stderr, "gamma-X i.e. MSSI may be happening. This may be why even high-E eff is <100%%. Check your cathode position definition.\n\n" ); + if ( verbosity ) fprintf ( stderr, "gamma-X i.e. MSSI may be happening. This may be why even high-E eff is <100%%. Check your cathode position definition.\n\n" ); } if(PrintSubThr || ( @@ -1185,7 +1188,7 @@ vector signal1, signal2, signalE, vTable; // in case you want to drop all sub-threshold data } catch(exception &e) { - cerr << e.what() << endl; + if ( verbosity ) cerr << e.what() << endl; return 1; } } //end of the gigantic primary event number loop @@ -1212,7 +1215,7 @@ vector signal1, signal2, signalE, vTable; std::isnan(band[j][0]) || std::isnan(band[j][1]) || std::isnan(band[j][2]) || std::isnan(band[j][3]) || std::isnan(band[j][4]) || std::isnan(band[j][5])) { - if (eMax != -999.) { + if (eMax != -999. && verbosity) { if (((g1 * yieldsMax.PhotonYield) < maxS1 || (g2 * yieldsMax.ElectronYield) < maxS2) && j != 0) @@ -1263,8 +1266,7 @@ vector signal1, signal2, signalE, vTable; } else if ((ValidityTests::nearlyEqual(energies[0], eMin) || ValidityTests::nearlyEqual(energies[0], eMax) || energies[1] <= 1E-6) && field >= FIELD_MIN) - cerr << "If your energy resolution is 0% then you probably still " - "have MC truth energy on." << endl; + if ( verbosity ) cerr << "If your energy resolution is 0% then you probably still have MC truth energy on." << endl; else ; } @@ -1276,7 +1278,7 @@ vector signal1, signal2, signalE, vTable; vector> GetBand(vector S1s, vector S2s, bool resol, int nFold) { if ( numBins > NUMBINS_MAX ) { - cerr << "ERROR: Too many bins. Decrease numBins (analysis.hh) or increase NUMBINS_MAX (TestSpectra.hh)" << endl; + if ( verbosity ) cerr << "ERROR: Too many bins. Decrease numBins (analysis.hh) or increase NUMBINS_MAX (TestSpectra.hh)" << endl; exit ( EXIT_FAILURE ); } @@ -1306,8 +1308,8 @@ vector> GetBand(vector S1s, vector S2s, for (j = 0; j < numBins; ++j) { s1c = border + binWidth / 2. + double(j) * binWidth; if (i == 0 && !resol) band[j][0] = s1c; - if ( (fabs(S1s[i]) > (s1c - binWidth / 2.) && - fabs(S1s[i]) <=(s1c + binWidth / 2.)) || !nFold ) { + if ( (std::abs(S1s[i]) > (s1c - binWidth / 2.) && + std::abs(S1s[i]) <=(s1c + binWidth / 2.)) || !nFold ) { if (S1s[i] >= ReqS1 && S2s[i] >= 0.) { if (resol) { signals[j].push_back(S2s[i]); @@ -1350,7 +1352,7 @@ vector> GetBand(vector S1s, vector S2s, signals[j].erase(signals[j].begin()); numPts = (double)signals[j].size(); if (numPts <= 0 && resol) { - for (i = 0; i < S1s.size(); ++i) band[j][0] += fabs(S1s[i]); + for (i = 0; i < S1s.size(); ++i) band[j][0] += std::abs(S1s[i]); numPts = S1s.size(); } if (resol) band[j][0] /= numPts;