def setUpClass(cls): cls.detector = nestpy.VDetector() cls.detector.Initialization() cls.it = nestpy.INTERACTION_TYPE(0) cls.nestcalc = nestpy.NESTcalc(cls.detector) cls.nuisance = cls.nestcalc.default_NuisParam cls.free = cls.nestcalc.default_FreeParam cls.nestcalc = nestpy.NESTcalc(cls.detector)
def setUpClass(cls): cls.detector = nestpy.VDetector() cls.detector.Initialization() cls.it = nestpy.INTERACTION_TYPE(0) cls.nestcalc = nestpy.NESTcalc(cls.detector) cls.nuisance = cls.nestcalc.default_NuisParam cls.free = cls.nestcalc.default_FreeParam cls.nestcalc = nestpy.NESTcalc(cls.detector) cls.result = cls.nestcalc.FullCalculation(cls.it, 10., 3., 100., 131, 56, cls.nuisance, cls.free, True) cls.position = [2, 3, 4]
def test_readme_example(self): # This is same as C++ NEST with naming nc = nestpy.NESTcalc() A = 131.293 Z = 54. density = 2.9 # g/cm^3 interaction = nestpy.INTERACTION_TYPE(0) # NR E = 10 # keV print('For an %s keV %s' % (E, interaction)) # Get particle yields y = nc.GetYields( interaction, E, density, 124, # Drift field, V/cm A, Z, (1, 1)) print('The photon yield is:', y.PhotonYield) print('With statistical fluctuations', nc.GetQuanta(y, density).photons)
def setUpClass(cls): cls.detector = nestpy.VDetector() cls.detector.Initialization() cls.it = nestpy.INTERACTION_TYPE(0) cls.nestcalc = nestpy.NESTcalc(cls.detector) cls.result = cls.nestcalc.FullCalculation( cls.it, 10., 3., 100., 131, 56, [11., 1.1, 0.0480, -0.0533, 12.6, 0.3, 2., 0.3, 2., 0.5, 1.], [1., 1., 0.1, 0.5, 0.07], True)
def kr83m_instructions(c): """ Instruction that is meant to simulate Kr83m events in the TPC. """ import nestpy half_life = 156.94e-9 # Kr intermediate state half-life in ns decay_energies = [32.2, 9.4] # Decay energies in KeV n = c['nevents'] = c['event_rate'] * c['chunk_size'] * c['nchunk'] c['total_time'] = c['chunk_size'] * c['nchunk'] # Uses 4*n to get the two energies for S1 and S2 instructions = np.zeros(4 * n, dtype=wfsim.instruction_dtype) instructions['event_number'] = np.digitize( instructions['time'], 1e9 * np.arange(c['nchunk']) * c['chunk_size']) - 1 instructions['type'] = np.tile([1, 2], 2 * n) instructions['recoil'] = ['er' for i in range(4 * n)] # Random positioning r = np.sqrt(np.random.uniform(0, c['tpc_radius']**2, n)) t = np.random.uniform(-np.pi, np.pi, n) instructions['x'] = np.repeat(r * np.cos(t), 4) instructions['y'] = np.repeat(r * np.sin(t), 4) instructions['z'] = -10 * np.ones(4 * n) # Choosing shallow z positioning # For correct times need to include the 156.94 ns half life of the intermediate state uniform_times = c['total_time'] * (np.arange(n) + 0.5) / n delayed_times = uniform_times + np.random.exponential( half_life / np.log(2), len(uniform_times)) instructions['time'] = np.repeat(list(zip(uniform_times, delayed_times)), 2) * 1e9 # Defining XENON-like detector nc = nestpy.NESTcalc(nestpy.VDetector()) A = 131.293 Z = 54 density = 2.862 # g/cm^3 # SR1 Value drift_field = 82 # V/cm # SR1 Value interaction = nestpy.INTERACTION_TYPE(7) # gamma energy = np.tile(decay_energies, n) quanta = [] for en in energy: y = nc.GetYields(interaction, en, density, drift_field, A, Z, (1, 1)) quanta.append(nc.GetQuanta(y, density).photons) quanta.append(nc.GetQuanta(y, density).electrons) instructions['amp'] = quanta return instructions
def test_readme_example(self): import nestpy # This is same as C++ NEST with naming nc = nestpy.NESTcalc(nestpy.VDetector()) interaction = nestpy.INTERACTION_TYPE(0) # NR E = 10 # keV print('For an %s keV %s' % (E, interaction)) # Get particle yields y = nc.GetYields(interaction, E) print('The photon yield is:', y.PhotonYield) print('With statistical fluctuations', nc.GetQuanta(y).photons)
def __init__(self, config): super().__init__(config) self.phase = 'liquid' # To distinguish singlet/triplet time delay. if 'nest' in self.config['s1_model_type'] and (self.nestpy_calc is None): log.info( 'Using NEST for scintillation time without set calculator\n' 'Creating new nestpy calculator') self.nestpy_calc = nestpy.NESTcalc( nestpy.DetectorExample_XENON10()) # Check if user specified s1 model type exist S1VALIDTYPE = ['', 'simple', 'custom', 'optical_propagation', 'nest'] def s1_valid_type(s, c='+ ,'): if len(c) > 0: for k in s.split(c[0]): s1_valid_type(k, c[1:]) else: assert s in S1VALIDTYPE, f'Model type "{s}" not in {S1VALIDTYPE}' s1_valid_type(self.config['s1_model_type'])
def read_g4(file): nc = nestpy.NESTcalc(nestpy.VDetector()) A = 131.293 Z = 54. density = 2.9 # g/cm^3 drift_field = 124 # V/cm interaction = nestpy.INTERACTION_TYPE(7) data = uproot.open(file) all_ttrees = dict( data.allitems( filterclass=lambda cls: issubclass(cls, uproot.tree.TTreeMethods))) e = all_ttrees[b'events/events;1'] ins = np.zeros(2 * len(e), dtype=instruction_dtype) sort_key = np.argsort(e.array('time')[:, 0]) e_dep, ins['x'], ins['y'], ins['z'], ins['t'] = e.array('etot')[sort_key], \ np.repeat(e.array('xp_pri')[sort_key], 2) / 10, \ np.repeat(e.array('yp_pri')[sort_key], 2) / 10, \ np.repeat(e.array('zp_pri')[sort_key], 2) / 10, \ 1e9*np.repeat(e.array('time')[:, 0][sort_key], 2) ins['event_number'] = 0 ins['type'] = np.tile(('s1', 's2'), len(e)) ins['recoil'] = np.repeat('er', 2 * len(e)) quanta = [] for en in e_dep: y = nc.GetYields(interaction, en, density, drift_field, A, Z, (1, 1)) quanta.append(nc.GetQuanta(y, density).photons) quanta.append(nc.GetQuanta(y, density).electrons) ins['amp'] = quanta return ins
def test_nestcalc_constructor_vdetect(self): detector = nestpy.VDetector() detector.Initialization() nestcalc = nestpy.NESTcalc(detector) assert nestcalc is not None assert isinstance(nestcalc, nestpy.nestpy.NESTcalc)
def test_nestcalc_constructor(self): nestcalc = nestpy.NESTcalc() assert nestcalc is not None assert isinstance(nestcalc, nestpy.nestpy.NESTcalc)
def setUpClass(cls): cls.detector = nestpy.VDetector() cls.detector.Initialization() cls.it = nestpy.INTERACTION_TYPE(0) cls.nestcalc = nestpy.NESTcalc(cls.detector)
def test_nestcalc_get_xyresolution(self): self.detector = nestpy.DetectorExample_XENON10() self.detector.Initialization() self.nestcalc = nestpy.NESTcalc(self.detector) self.nestcalc.xyResolution( 0., 1.,2.)
import nestpy import numpy as np import matplotlib.pyplot as plt import matplotlib.axes as axes import os #Detector identification detector = nestpy.DetectorExample_XENON10() # detector = nestpy.VDetector() # Performing NEST calculations according to the given detector example nc = nestpy.NESTcalc(detector) #can also be left empty #GetInteractionObject grabs the number for the interaction you want so you don't have to always reference the dictionary. Just type e.g., 'ion' #It just changes the name to a number for nestpy to do its work. def GetInteractionObject(name): name = name.lower() if name == 'er': raise ValueError("For 'er', specify either 'gammaray' or 'beta'") nest_interaction_number = dict( nr=0, wimp=1, b8=2, dd=3, ambe=4, cf=5, ion=6, gammaray=7, beta=8,
# Figure parameters common throughout all plots version_textbox = " NEST v{0} \n nestpy v{1}".format(nestpy.__nest_version__, nestpy.__version__) bbox = dict(boxstyle="round", fc="1.00", edgecolor='none') params = { 'xtick.labelsize': 'x-large', 'ytick.labelsize': 'x-large', } # Updates plots to apply the above formatting to all plots in doc pylab.rcParams.update(params) # Detector identification detector = nestpy.DetectorExample_XENON10() # Performing NEST calculations according to the given detector example nc = nestpy.NESTcalc(detector) #Once you have interaction, you can get yields ''' Below are field and energy arrays. - Energies are broadcase to be repeated by the dimensions of the fields, owing to the nature of vectorized functions below. - Functions will loop over each energy and field simultaneously that way, rather than nesting for loops inside each other. ''' fields = [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000] energies = np.logspace(-1, 4, 2000) energies = np.broadcast_to(energies, (len(fields), len(energies))) @np.vectorize def GetYieldsVectorized(interaction, yield_type, **kwargs):
def _rand_instructions( event_rate: int, chunk_size: int, n_chunk: int, drift_field: float, energy_range: ty.Union[tuple, list, np.ndarray], tpc_length: float = straxen.tpc_z, tpc_radius: float = straxen.tpc_r, nest_inst_types: ty.Union[ty.List[int], ty.Tuple[ty.List], np.ndarray, None] = None, ) -> np.ndarray: import nestpy if nest_inst_types is None: nest_inst_types = [7] n_events = event_rate * chunk_size * n_chunk total_time = chunk_size * n_chunk inst = np.zeros(2 * n_events, dtype=instruction_dtype) inst[:] = -1 uniform_times = total_time * (np.arange(n_events) + 0.5) / n_events inst['time'] = np.repeat(uniform_times, 2) * int(1e9) inst['event_number'] = np.digitize( inst['time'], 1e9 * np.arange(n_chunk) * chunk_size) - 1 inst['type'] = np.tile([1, 2], n_events) r = np.sqrt(np.random.uniform(0, tpc_radius**2, n_events)) t = np.random.uniform(-np.pi, np.pi, n_events) inst['x'] = np.repeat(r * np.cos(t), 2) inst['y'] = np.repeat(r * np.sin(t), 2) inst['z'] = np.repeat(np.random.uniform(-tpc_length, 0, n_events), 2) # Here we'll define our XENON-like detector nest_calc = nestpy.NESTcalc(nestpy.VDetector()) nucleus_A = 131.293 nucleus_Z = 54. lxe_density = 2.862 # g/cm^3 #SR1 Value energy = np.random.uniform(*energy_range, n_events) quanta = [] exciton = [] recoil = [] e_dep = [] for energy_deposit in tqdm(energy, desc='generating instructions from nest'): interaction_type = np.random.choice(nest_inst_types) interaction = nestpy.INTERACTION_TYPE(interaction_type) y = nest_calc.GetYields( interaction, energy_deposit, lxe_density, drift_field, nucleus_A, nucleus_Z, ) q = nest_calc.GetQuanta(y, lxe_density) quanta.append(q.photons) quanta.append(q.electrons) exciton.append(q.excitons) exciton.append(0) # both S1 and S2 recoil += [interaction_type, interaction_type] e_dep += [energy_deposit, energy_deposit] inst['amp'] = quanta inst['local_field'] = drift_field inst['n_excitons'] = exciton inst['recoil'] = recoil inst['e_dep'] = e_dep for field in inst.dtype.names: if np.any(inst[field] == -1): log.warn(f'{field} is not (fully) filled') return inst
def GetFlowImage(pid, eDep, field, savefig=True, output_dir='./', output_filename='test.png'): if not os.path.exists(output_dir): os.makedirs(output_dir) fig, ax = plt.subplots(1, 1, figsize=(XC.fig_width, XC.fig_height)) ax.set_xlim([0, XC.axes_xmax]) ax.set_ylim([XC.axes_ymin, 0]) SetColors(pid) if pid == 'NR': interaction = nestpy.INTERACTION_TYPE(0) elif pid == 'gamma': interaction = nestpy.INTERACTION_TYPE(7) elif pid == 'beta' or pid == 'ER': interaction = nestpy.INTERACTION_TYPE(8) yields = nestpy.NESTcalc(nestpy.VDetector()).GetYields(interaction, energy=eDep, density=DC.Density, drift_field=field) Ni = (yields.PhotonYield + yields.ElectronYield) / yields.ExcitonRatio / ( 1. + 1. / yields.ExcitonRatio) Nex = yields.PhotonYield + yields.ElectronYield - Ni Nph = yields.PhotonYield Ne = yields.ElectronYield L = yields.Lindhard if (pid == 'ER' or pid == 'beta' or pid == 'gamma'): # An estimate of how much energy goes into heat for ERs L = 1. - XC.ER_heat_fraction SingTripRatio = NESThelper.GetSingTripRatio(pid, eDep, field) SetText(pid, eDep, field, Ni, Nex, Nph, Ne, SingTripRatio) SetArrowWidths(pid, Ni, Nex, Nph, Ne, L, SingTripRatio) for a in range(len(XC.arrow_properties['name'])): DrawArrow(fig, ax, a) for t in range(len(XC.text_properties['name'])): DrawText(fig, ax, t) DrawAtom(fig, ax, pid) ax.set_xlim([0, XC.axes_xmax]) ax.set_ylim([XC.axes_ymin, 0]) ax.axis('off') fig.tight_layout() if savefig: fig.savefig(output_dir + output_filename, transparent=False) im_out = Image.open(output_dir + output_filename) else: buf = io.BytesIO() fig.savefig(buf, format='png') buf.seek(0) im_out = Image.open(buf) plt.close('all') return im_out
def quanta_from_NEST(en, model, e_field, A, Z, create_s2, **kwargs): """ Function which uses NEST to yield photons and electrons for a given set of parameters. Note: In case the energy deposit is outside of the range of NEST a -1 is returned. Args: en (numpy.array): Energy deposit of the interaction [keV] model (numpy.array): Nest Id for qunata generation (integers) e_field (numpy.array): Field value in the interaction site [V/cm] A (numpy.array): Atomic mass number Z (numpy.array): Atomic number create_s2 (bool): Specifies if S2 can be produced by interaction, in this case electrons are generated. kwargs: Additional keyword arguments which can be taken by GetYields e.g. density. Returns: photons (numpy.array): Number of generated photons electrons (numpy.array): Number of generated electrons excitons (numpy.array): Number of generated excitons """ nc = nestpy.NESTcalc(nestpy.VDetector()) density = 2.862 # g/cm^3 # Fix for Kr83m events. # Energies have to be very close to 32.1 keV or 9.4 keV # See: https://github.com/NESTCollaboration/nest/blob/master/src/NEST.cpp#L567 # and: https://github.com/NESTCollaboration/nest/blob/master/src/NEST.cpp#L585 max_allowed_energy_difference = 1 # keV if model == 11: if abs(en - 32.1) < max_allowed_energy_difference: en = 32.1 if abs(en - 9.4) < max_allowed_energy_difference: en = 9.4 # Some addition taken from # https://github.com/NESTCollaboration/nestpy/blob/e82c71f864d7362fee87989ed642cd875845ae3e/src/nestpy/helpers.py#L94-L100 if model == 0 and en > 2e2: warnings.warn( f"Energy deposition of {en} keV beyond NEST validity for NR model of 200 keV - Remove Interaction" ) return -1, -1, -1 if model == 7 and en > 3e3: warnings.warn( f"Energy deposition of {en} keV beyond NEST validity for gamma model of 3 MeV - Remove Interaction" ) return -1, -1, -1 if model == 8 and en > 3e3: warnings.warn( f"Energy deposition of {en} keV beyond NEST validity for beta model of 3 MeV - Remove Interaction" ) return -1, -1, -1 y = nc.GetYields(interaction=nestpy.INTERACTION_TYPE(model), energy=en, drift_field=e_field, A=A, Z=Z, **kwargs) event_quanta = nc.GetQuanta( y) # Density argument is not use in function... photons = event_quanta.photons excitons = event_quanta.excitons electrons = 0 if create_s2: electrons = event_quanta.electrons return photons, electrons, excitons