Skip to content

Commit

Permalink
Merge pull request #69 from NESTCollaboration/gr_sync2
Browse files Browse the repository at this point in the history
Synced files from tagged NESTv2.2.3 for nestpy release of v1.4.11
  • Loading branch information
grischbieter authored Aug 24, 2021
2 parents 3cfe989 + f336204 commit dc2b15d
Show file tree
Hide file tree
Showing 11 changed files with 2,452 additions and 2,120 deletions.
12 changes: 12 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ 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.11 (2021-08-09)
-----------------
Sync with [NEST v2.2.3](https://github.com/NESTCollaboration/nest/releases/tag/v2.2.3)

* Replaced useTiming variable by an enum and made the GetS1 result a class member. Separated the S1 and S2 calculation modes.
* Made GetS1 return a ref to avoid vector copy
* Made the GetS2 results a private member returned by reference, while also making GetS1 and GetS2 results "const"
* Removed useless, unused variables that caused a lot of memory allocation/deallocation; result of all this and the above: +~1-5% faster
* Updated the parametric S1 calc to account for the truncated-Gaussian SPE and DPE distributions, making it more consistent with "full"
* Changed hybrid-mode transition to be 100 keV, ~500 photon hits in modern TPCs, instead of hits directly, creating a smooth transition
* Efficiency adjustment in the S1 parametric mode that further makes the parametric and full modes (previously useTiming -1,0) closer.
* Changes driven by Quentin Riffard (LZ/LBNL) & Greg Rischbieter (LZ/UA), with ideas from Matthew (UA) & Luke Kreczko (Bristol)

1.4.10 (2021-07-08)
-----------------
Expand Down
3,934 changes: 2,063 additions & 1,871 deletions src/nestpy/NEST.cpp

Large diffs are not rendered by default.

517 changes: 299 additions & 218 deletions src/nestpy/NEST.hh

Large diffs are not rendered by default.

30 changes: 18 additions & 12 deletions src/nestpy/RandomGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using namespace std;

// Global static pointer used to ensure a single instance of the class.
RandomGen* RandomGen::m_pInstance = NULL;
RandomGen* RandomGen::m_pInstance = nullptr;

// Only allow one instance of class to be generated.
RandomGen* RandomGen::rndm() {
Expand All @@ -25,37 +25,43 @@ void RandomGen::SetSeed(uint64_t s) {
}

double RandomGen::rand_uniform() {
return (double)(rng() - rng.min()) / (double)(rng.max() - rng.min());
return (static_cast<double>(rng()) - xoroshiro128plus64_min) / xoroshiro128plus64_minmax;
}

double RandomGen::rand_gauss ( double mean, double sigma ) {

//std::normal_distribution<double> norm(mean, sigma);
//return norm(rng);
double u = rand_uniform(), v = rand_uniform();
return mean + sigma * sqrt(-2. * log(u)) * cos(2. * M_PI * v);

return mean + sigma * sqrt2 * sqrt(-log(u)) * cos(two_PI * v);
}

double RandomGen::rand_zero_trunc_gauss ( double mean, double sigma ) {
double r = rand_gauss(mean, sigma);
while( r <= 0 ){
r = rand_gauss(mean, sigma);
}
return r;
}

double RandomGen::rand_exponential(double half_life) {
double r = rand_uniform();
return log(1 - r) * -1 * half_life / log(2.);
return - log(1 - r) * half_life / log2;
}

double RandomGen::rand_skewGauss(double xi, double omega, double alpha) {
double delta = alpha/sqrt(1 + alpha*alpha);
double gamma1 = 0.5*(4. - M_PI)*( pow(delta*sqrt(2./M_PI), 3.) / pow( 1 - 2.*delta*delta/M_PI, 1.5 ) ); //skewness
double muz = delta*sqrt(2./M_PI); double sigz = sqrt(1. - muz*muz);
double gamma1 = four_minus_PI_div_2 * ( pow(delta * sqrt2_div_PI, 3.) / pow( 1 - 2. * delta * delta / M_PI, 1.5 ) ); //skewness
double muz = delta * sqrt2_div_PI; double sigz = sqrt(1. - muz*muz);
double m_o;
if (alpha > 0.){
m_o = muz - 0.5*gamma1*sigz - 0.5*exp( -2.*M_PI/alpha );
m_o = muz - 0.5 * gamma1 * sigz - 0.5 * exp( -two_PI/alpha );
}
if (alpha < 0.){
m_o = muz - 0.5*gamma1*sigz + 0.5*exp( +2.*M_PI/alpha );
m_o = muz - 0.5 * gamma1 * sigz + 0.5 * exp( two_PI/alpha );
}
double mode = xi + omega*m_o;
//the height should be the value of the PDF at the mode
double height = exp( -0.5*( pow((mode - xi)/omega, 2.) ) ) / ( sqrt( 2.*M_PI ) * omega ) * erfc( -1.*alpha*(mode - xi)/omega/sqrt(2.) );
double height = exp( -0.5*( pow((mode - xi)/omega, 2.) ) ) / ( sqrt2_PI * omega ) * erfc( -1.*alpha*(mode - xi)/omega/sqrt2 );
bool gotValue = false;
double minX = xi - 6.*omega; double maxX = xi + 6.*omega; // +/- 6sigma should be essentially +/- infinity
// can increase these for even better accuracy, at the cost of speed
Expand All @@ -64,7 +70,7 @@ double RandomGen::rand_skewGauss(double xi, double omega, double alpha) {
testX = minX + ( maxX - minX ) * RandomGen::rndm()->rand_uniform();
testY = height*RandomGen::rndm()->rand_uniform(); // between 0 and peak height
//calculate the value of the skewGauss PDF at the test x-value
testProb = exp( -0.5*( pow((testX - xi)/omega, 2.) ) ) / ( sqrt( 2.*M_PI ) * omega ) * erfc( -1.*alpha*(testX - xi)/omega/sqrt(2.) );
testProb = exp( -0.5*( pow((testX - xi)/omega, 2.) ) ) / ( sqrt2_PI * omega ) * erfc( -1.*alpha*(testX - xi)/omega/sqrt2 );
if ( testProb >= testY ){ gotValue = true; }
}
return testX;
Expand Down
17 changes: 15 additions & 2 deletions src/nestpy/RandomGen.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
#ifndef RANDOMGEN_HH
#define RANDOMGEN_HH 1
#include "xoroshiro.hh"
#include <math.h>
#include <stdlib.h>
//#include "gcem.hpp"
#include <cmath>
#include <cstdlib>
#include <random>
#include <vector>

Expand All @@ -19,6 +20,7 @@ class RandomGen {
void SetSeed(uint64_t s);
double rand_uniform();
double rand_gauss(double mean, double sigma);
double rand_zero_trunc_gauss ( double mean, double sigma );
double rand_exponential(double half_life);
double rand_skewGauss( double xi, double omega, double alpha);
int poisson_draw(double mean);
Expand All @@ -32,6 +34,17 @@ class RandomGen {
// std::ranlux24 rng;
xoroshiro128plus64 rng;

double xoroshiro128plus64_min = static_cast<double>(xoroshiro128plus64::min());
double xoroshiro128plus64_minmax = static_cast<double>(xoroshiro128plus64::max() - xoroshiro128plus64::min());

double two_PI = 2. * M_PI;
double four_minus_PI_div_2 = 0.5*(4. - M_PI);
double sqrt2 = sqrt(2.);
double sqrt2_PI = sqrt( 2. * M_PI );
double sqrt2_div_PI = sqrt(2./M_PI);
double log2 = log(2.);


RandomGen()= default; // private so that it cannot be manually called
RandomGen(RandomGen const&); // copy constructor is private
void operator=(RandomGen const&); // assignment operator is private
Expand Down
2 changes: 1 addition & 1 deletion src/nestpy/TestSpectra.hh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

#define NUMBINS_MAX 1000

static const double ElectronRestMassEnergy = 510.9989461;
static constexpr double ElectronRestMassEnergy = 510.9989461;

class TestSpectra {
public:
Expand Down
4 changes: 2 additions & 2 deletions src/nestpy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__version__ = '1.4.10'
__nest_version__ = '2.2.2'
__version__ = '1.4.11'
__nest_version__ = '2.2.3'

from .nestpy import *

Expand Down
17 changes: 14 additions & 3 deletions src/nestpy/analysis.hh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "NEST.hh"

// Verbosity flag (for limiting output to yields; no timing)
bool verbosity = true;
Expand All @@ -12,9 +13,19 @@ bool PrintSubThr = true;
bool MCtruthE = false; // false means reconstructed energy
bool MCtruthPos = false; // false means reconstructed position

int useTiming = 0; // photon arrival times + pulse shapes (2=eTrains)
// if 1 or 2 but verb off, then timing only saved as vectors
// if -1 it means a special extra-fast mode for higher energies
// Setting the S1 and S2 calculation modes
NEST::S1CalculationMode s1CalculationMode = NEST::S1CalculationMode::Full;
// S1 calculation mode options are:
// Full [Default]: calculating the pulse area by looping over all the pmt hits
// Parametric: calculating the pulse area by using a parametric equation
// Hybrid: Using Full and Parametric with a transition point: n_pmt_hits > n_pmts
// Waveform: calculating the pulse area with the Full calculation mode and the waveform

NEST::S2CalculationMode s2CalculationMode = NEST::S2CalculationMode::Full;
// S2 calculation mode options are:
// Full [Default]: calculate only the pulse area
// Waveform: calculate the pulse area and the waveform
// WaveformWithEtrain: calculate the pulse area and the waveform with etrain

// 0 means PE, 1 means phd (PE/~1.2), 2 means spike count
int usePD = 2;
Expand Down
15 changes: 15 additions & 0 deletions src/nestpy/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ PYBIND11_MODULE(nestpy, m) {
.value("NoneType", NEST::INTERACTION_TYPE::NoneType)
.export_values();


py::enum_<NEST::S1CalculationMode>(m, "S1CalculationMode", py::arithmetic())
.value("Full", NEST::S1CalculationMode::Full)
.value("Parametric", NEST::S1CalculationMode::Parametric)
.value("Hybrid", NEST::S1CalculationMode::Hybrid)
.value("Waveform", NEST::S1CalculationMode::Waveform)
.export_values();

py::enum_<NEST::S2CalculationMode>(m, "S2CalculationMode", py::arithmetic())
.value("Full", NEST::S2CalculationMode::Full)
.value("Waveform", NEST::S2CalculationMode::Waveform)
.value("WaveformWithEtrain", NEST::S2CalculationMode::WaveformWithEtrain)
.export_values();


// Binding for the VDetector class
py::class_<VDetector, std::unique_ptr<VDetector, py::nodelete>>(m, "VDetector") // py::nodelete added so that NESTcalc() deconstructor does
// not delete instance of VDetector()
Expand Down
20 changes: 11 additions & 9 deletions src/nestpy/execNEST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ int main(int argc, char** argv) {
no_seed = false;
FreeParam.clear(); NuisParam.clear();
verbosity = false;
useTiming = 0; //-1 for faster (less accurate)

if ( type == "ER" ) {

Expand Down Expand Up @@ -263,10 +262,10 @@ NESTObservableArray runNESTvec ( VDetector* detector, INTERACTION_TYPE particleT
quanta = result.quanta;
vD = n.SetDriftVelocity(detector->get_T_Kelvin(),rho,useField);
scint = n.GetS1(quanta,truthPos[0],truthPos[1],truthPos[2],smearPos[0],smearPos[1],smearPos[2],
vD,vD,particleType,i,useField,eList[i],0,verbosity,wf_time,wf_amp); //0 means useTiming = 0
vD,vD,particleType,i,useField,eList[i],NEST::S1CalculationMode::Full,verbosity,wf_time,wf_amp);
driftTime = (detector->get_TopDrift()-z)/vD; //vD,vDmiddle assumed same (uniform field)
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);
driftTime,vD,i,useField,S2CalculationMode::Full,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(std::abs(int(scint[0])));
OutputResults.s1_nhits_thr.push_back(std::abs(int(scint[8])));
Expand Down Expand Up @@ -315,8 +314,8 @@ 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.1,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.10,0.5,0.19,2.25};
if (detector->get_TopDrift() <= 0. || detector->get_anode() <= 0. ||
detector->get_gate() <= 0.) {
if ( verbosity ) cerr << "ERROR, unphysical value(s) of position within the detector geometry."; // negative or 0 for cathode position is OK (e.g., LZ)
Expand Down Expand Up @@ -949,7 +948,7 @@ vector<double> signal1, signal2, signalE, vTable;
vector<double> scint =
n.GetS1(quanta, truthPos[0], truthPos[1], truthPos[2], smearPos[0], smearPos[1], smearPos[2],
vD, vD_middle, type_num, j, field,
keV, useTiming, verbosity, wf_time, wf_amp);
keV, s1CalculationMode, verbosity, wf_time, wf_amp);
if ( truthPos[2] < detector->get_cathode() &&
!dEOdxBasis )
quanta.electrons=0;
Expand All @@ -958,7 +957,7 @@ vector<double> signal1, signal2, signalE, vTable;
scint2 =
n.GetS2(quanta.electrons, truthPos[0], truthPos[1], truthPos[2], smearPos[0], smearPos[1], smearPos[2],
driftTime, vD, j, field,
useTiming, verbosity, wf_time, wf_amp, g2_params);
s2CalculationMode, verbosity, wf_time, wf_amp, g2_params);
if ( dEOdxBasis ) {
driftTime = (detector->get_TopDrift()-pos_z)/vD_middle;
scint2[7] *= exp(driftTime/detector->get_eLife_us());
Expand Down Expand Up @@ -1010,7 +1009,11 @@ vector<double> signal1, signal2, signalE, vTable;
double Nph = 0.0, Ne = 0.0;
if(!MCtruthE) {
double MultFact = 1., eff = detector->get_sPEeff();
if(useTiming >= 0) {

if( s1CalculationMode == S1CalculationMode::Full
|| s1CalculationMode == S1CalculationMode::Hybrid
|| s1CalculationMode == S1CalculationMode::Waveform ) {

if(detector->get_sPEthr() >= 0. && detector->get_sPEres() > 0. && eff > 0.) {
MultFact = 0.5 * (1. + erf((detector->get_sPEthr() - 1.) / (detector->get_sPEres() * sqrt(2.)))) /
(detector->get_sPEres() * sqrt(2. * M_PI));
Expand Down Expand Up @@ -1408,5 +1411,4 @@ void GetEnergyRes ( vector<double> Es ) {
energies[1] = sqrt(energies[1]);

energies[2] = numerator / double(numPts);

}
4 changes: 2 additions & 2 deletions tests/core_nest_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def test_nestcalc_get_s1(self):
10., 10.,
self.it,
100, 10., 10.,
0, False,
nestpy.S1CalculationMode.Full, False,
[0, 1, 2],
[0., 1., 2.])

Expand All @@ -186,7 +186,7 @@ def test_nestcalc_get_s2(self):
10., 10., -30., #smear pos x y z
10., 10.,
100, 10.,
0, False,
nestpy.S2CalculationMode.Full, False,
[0, 1, 2],
[0., 1., 2.],
[0., 82., 2., 3., 4.])
Expand Down

0 comments on commit dc2b15d

Please sign in to comment.