Exemple #1
0
    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)
Exemple #2
0
    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
Exemple #3
0
 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)
Exemple #4
0
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 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.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):
        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)
Exemple #7
0
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,
        ch3t=9,
        c14=10,
        kr83m=11,
        nonetype=12,
    )

    interaction_object = nestpy.INTERACTION_TYPE(nest_interaction_number[name])
    return interaction_object
Exemple #8
0
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
Exemple #9
0
 def test_nestcalc_get_yields_defaults(self):
     yields = self.nestcalc.GetYields(nestpy.INTERACTION_TYPE(0),
                                      10)
Exemple #10
0
    def photon_timings(t,
                       n_photon_hits,
                       recoil_type,
                       config,
                       phase,
                       channels=None,
                       positions=None,
                       e_dep=None,
                       n_photons_emitted=None,
                       n_excitons=None,
                       local_field=None,
                       resource=None,
                       nestpy_calc=None):
        """Calculate distribution of photon arrival timnigs
        :param t: 1d array of ints
        :param n_photon_hits: number of photon hits, 1d array of ints
        :param recoil_type: 1d array of ints
        :param config: dict wfsim config
        :param phase: str "liquid"
        :param channels: list of photon hit channels 
        :param positions: nx3 array of true XYZ positions from instruction
        :param e_dep: energy of the deposit, 1d float array
        :param n_photons_emitted: number of orignally emitted photons/quanta, 1d int array
        :param n_excitons: number of exctions in deposit, 1d int array
        :param local_field: local field in the point of the deposit, 1d array of floats
        :param resource: pointer to resources class of wfsim that contains s1 timing splines
        returns photon timing array"""
        _photon_timings = np.repeat(t, n_photon_hits)
        _n_hits_total = len(_photon_timings)

        if len(_photon_timings) == 0:
            return _photon_timings.astype(np.int64)

        if 'optical_propagation' in config['s1_model_type']:
            z_positions = np.repeat(positions[:, 2], n_photon_hits)
            _photon_timings += S1.optical_propagation(
                channels,
                z_positions,
                config,
                spline=resource.s1_optical_propagation_spline).astype(np.int64)

        if 'simple' in config['s1_model_type']:
            # Simple S1 model enabled: use it for ER and NR.
            _photon_timings += np.random.exponential(
                config['s1_decay_time'], _n_hits_total).astype(np.int64)
            _photon_timings += np.random.normal(0, config['s1_decay_spread'],
                                                _n_hits_total).astype(np.int64)

        if 'nest' in config['s1_model_type'] or 'custom' in config[
                's1_model_type']:
            # Pulse model depends on recoil type
            counts_start = 0
            for i, counts in enumerate(n_photon_hits):

                if 'custom' in config['s1_model_type']:
                    for k in vars(NestId):
                        if k.startswith('_'):
                            continue
                        if recoil_type[i] in getattr(NestId, k):
                            str_recoil_type = k
                    try:
                        _photon_timings[counts_start: counts_start + counts] += \
                            getattr(S1, str_recoil_type.lower())(
                            size=counts,
                            config=config,
                            phase=phase).astype(np.int64)
                    except AttributeError:
                        raise AttributeError(
                            f"Recoil type must be ER, NR, alpha or LED, "
                            f"not {recoil_type}. Check nest ids")

                if 'nest' in config['s1_model_type']:
                    # Allow overwriting with "override_s1_photon_time_field"
                    # xenon:j_angevaare:wfsim_photon_timing_bug
                    _local_field = config.get('override_s1_photon_time_field',
                                              local_field[i])
                    _local_field = (_local_field
                                    if _local_field > 0 else local_field[i])
                    scint_time = nestpy_calc.GetPhotonTimes(
                        nestpy.INTERACTION_TYPE(recoil_type[i]),
                        n_photons_emitted[i], n_excitons[i], _local_field,
                        e_dep[i])

                    scint_time = np.clip(
                        scint_time, 0,
                        config.get('maximum_recombination_time', 10000))

                    # The first part of the scint_time is from exciton only, see
                    # https://github.com/NESTCollaboration/nestpy/blob/fe3d5d7da5d9b33ac56fbea519e02ef55152bc1d/src/nestpy/NEST.cpp#L164-L179
                    _photon_timings[counts_start: counts_start + counts] += \
                        np.random.choice(scint_time, counts, replace=False).astype(np.int64)

                counts_start += counts

        return _photon_timings
Exemple #11
0
 def test_intteraction_type_constructor(self):
     it = nestpy.INTERACTION_TYPE(0)
     assert it is not None
     assert str(it) != ""
     assert isinstance(it, nestpy.INTERACTION_TYPE)
Exemple #12
0
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
Exemple #13
0
 def test_nestcalc_get_yields_named(self):
     yields = self.nestcalc.GetYields(nestpy.INTERACTION_TYPE(0),
                                      energy=10)
Exemple #14
0
 def setUpClass(cls):
     cls.detector = nestpy.VDetector()
     cls.detector.Initialization()
     cls.it = nestpy.INTERACTION_TYPE(0)
     cls.nestcalc = nestpy.NESTcalc(cls.detector)
Exemple #15
0
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
Exemple #16
0
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
Exemple #17
0
import nestpy
import numpy as np
import scipy as sp

with open('mock.txt') as f:
    events = f.read().splitlines()
events = np.asarray([float(num) for num in events])
print(events.shape)
detector = nestpy.DetectorExample_XENON10()
detector.Initialization()

# nc = nestpy.testNEST(detector, 10, 'NR', 100., 120., 10., "0., 0., 0.", "120.", -1., 1, True, 1.0)

# print(nc[0])
nc = nestpy.NESTcalc(detector)
interaction = nestpy.INTERACTION_TYPE(0)
yields = np.empty((events.shape[0], 2))
g1 = detector.get_g1()
g2 = nc.CalculateG2(False)
electron = np.random.choice(events, events.shape, replace=True)
for i in range(events.shape[0]):
    y = nc.GetYields(interaction, events[i])
    x = nc.GetQuanta(y)
    s1 = x.photons * g1
    s2 = x.electrons * g2[3]
    yields[i, 0] = s1
    yields[i, 1] = s2
np.save('s1_s2_data', yields)