Exemple #1
0
def get_adc_values(pixels_signals, time_ticks, adc_list, adc_ticks_list, time_padding, rng_states):
    """
    Implementation of self-trigger logic

    Args:
        pixels_signals (:obj:`numpy.ndarray`): list of induced currents for
            each pixel
        time_ticks (:obj:`numpy.ndarray`): list of time ticks for each pixel
        adc_list (:obj:`numpy.ndarray`): list of integrated charges for each
            pixel
        adc_ticks_list (:obj:`numpy.ndarray`): list of the time ticks that
            correspond to each integrated charge.
    """
    ip = cuda.grid(1)

    if ip < pixels_signals.shape[0]:
        curre = pixels_signals[ip]
        ic = 0
        iadc = 0
        q_sum = xoroshiro128p_normal_float32(rng_states, ip) * RESET_NOISE_CHARGE * consts.e_charge

        while ic < curre.shape[0]:

            q = curre[ic]*consts.t_sampling

            q_sum += q
            q_noise = xoroshiro128p_normal_float32(rng_states, ip) * UNCORRELATED_NOISE_CHARGE * consts.e_charge

            if q_sum + q_noise >= DISCRIMINATION_THRESHOLD:

                interval = round((3 * CLOCK_CYCLE + ADC_HOLD_DELAY * CLOCK_CYCLE) / consts.t_sampling)
                integrate_end = ic+interval

                while ic <= integrate_end and ic < curre.shape[0]:
                    q = curre[ic] * consts.t_sampling
                    q_sum += q
                    ic += 1

                adc = q_sum + xoroshiro128p_normal_float32(rng_states, ip) * UNCORRELATED_NOISE_CHARGE * consts.e_charge
                
                if adc < DISCRIMINATION_THRESHOLD:
                    ic += round(CLOCK_CYCLE / consts.t_sampling)
                    continue

                if iadc >= MAX_ADC_VALUES:
                    print("More ADC values than possible, ", MAX_ADC_VALUES)
                    break

                adc_list[ip][iadc] = adc
                adc_ticks_list[ip][iadc] = time_ticks[ic]+time_padding
                ic += round(CLOCK_CYCLE / consts.t_sampling)
                q_sum = xoroshiro128p_normal_float32(rng_states, ip) * RESET_NOISE_CHARGE * consts.e_charge
                iadc += 1

            ic += 1
Exemple #2
0
def rng_kernel_float32(states, out, count, distribution):
    thread_id = cuda.grid(1)

    for i in range(count):
        if distribution == UNIFORM:
            out[thread_id * count + i] = xoroshiro128p_uniform_float32(states, thread_id)
        elif distribution == NORMAL:
            out[thread_id * count + i] = xoroshiro128p_normal_float32(states, thread_id)
Exemple #3
0
def mutation(inp_weights, n_ia, n_weights, rng_states, prob=0.1):
    # Thread id in a 1D block
    tx = cuda.threadIdx.x
    # Block id in a 1D grid
    ty = cuda.blockIdx.x
    if ty < n_ia and tx < n_weights:
        a = xoroshiro128p_uniform_float32(rng_states, cuda.grid(1))
        if a < prob:
            inp_weights[ty][tx] += (xoroshiro128p_normal_float32(
                rng_states, cuda.grid(1))) / 5.
Exemple #4
0
 def generate_rand(rng_states, xtr, cov, Xepi, d):
     i = cuda.grid(1)
     ntr, dx = xtr.shape
     if i < ntr:
         # Generate random points
         for nepi in range(Nepi):
             for dx in range(dx):
                 Xepi[i, dx, nepi] = xtr[i, dx] + \
                                     math.sqrt(float(cov)) * \
                                     xoroshiro128p_normal_float32(
                                         rng_states, i)
                 # Compute distances
         for nepi in range(Nepi):
             smallest = 1e9
             for nt in range(ntr):
                 dist = 0
                 for dx in range(dx):
                     dist += (Xepi[i, dx, nepi] - xtr[nt, dx])**2
                 if dist < smallest:
                     smallest = dist
             d[i, nepi] = smallest
Exemple #5
0
def tracks_current_mc(signals, pixels, tracks, response, rng_states):
    """
    This CUDA kernel calculates the charge induced on the pixels by the input tracks using a
    MC method

    Args:
        signals (:obj:`numpy.ndarray`): empty 3D array with dimensions S x P x T,
            where S is the number of track segments, P is the number of pixels, and T is
            the number of time ticks. The output is stored here.
        pixels (:obj:`numpy.ndarray`): 2D array with dimensions S x P , where S is
            the number of track segments, P is the number of pixels and contains the pixel ID number.
        tracks (:obj:`numpy.ndarray`): 2D array containing the detector segments.
        response (:obj:`numpy.ndarray`): 3D array containing the tabulated response.
        rng_states (:obj:`numpy.ndarray`): array of random states for noise
            generation
    """
    itrk, ipix, it = cuda.grid(3)
    ntrk, _, _ = cuda.gridsize(3)

    if itrk < signals.shape[0] and ipix < signals.shape[
            1] and it < signals.shape[2]:
        t = tracks[itrk]
        pID = pixels[itrk][ipix]
        pID_x, pID_y, pID_plane = id2pixel(pID)

        if pID_x >= 0 and pID_y >= 0:

            # Pixel coordinates
            x_p, y_p = get_pixel_coordinates(pID)
            x_p += detector.PIXEL_PITCH / 2
            y_p += detector.PIXEL_PITCH / 2

            if t["z_start"] < t["z_end"]:
                start = (t["x_start"], t["y_start"], t["z_start"])
                end = (t["x_end"], t["y_end"], t["z_end"])
            else:
                end = (t["x_start"], t["y_start"], t["z_start"])
                start = (t["x_end"], t["y_end"], t["z_end"])

            t_start = max(
                TIME_INTERVAL[0],
                round((t["t_start"] - detector.TIME_PADDING) /
                      detector.TIME_SAMPLING) * detector.TIME_SAMPLING)
            time_tick = t_start + it * detector.TIME_SAMPLING

            segment = (end[0] - start[0], end[1] - start[1], end[2] - start[2])
            length = sqrt(segment[0]**2 + segment[1]**2 + segment[2]**2)

            direction = (segment[0] / length, segment[1] / length,
                         segment[2] / length)
            sigmas = (t["tran_diff"], t["tran_diff"], t["long_diff"])

            impact_factor = sqrt(response.shape[0]**2 + response.shape[1]**2
                                 ) * detector.RESPONSE_BIN_SIZE

            subsegment_start, subsegment_end = overlapping_segment(
                x_p, y_p, start, end, impact_factor)
            subsegment = (subsegment_end[0] - subsegment_start[0],
                          subsegment_end[1] - subsegment_start[1],
                          subsegment_end[2] - subsegment_start[2])
            subsegment_length = sqrt(subsegment[0]**2 + subsegment[1]**2 +
                                     subsegment[2]**2)
            if subsegment_length == 0:
                return

            nstep = max(round(subsegment_length / MIN_STEP_SIZE), 1)
            step = subsegment_length / nstep  # refine step size

            charge = t["n_electrons"] * (subsegment_length / length) / (
                nstep * MC_SAMPLE_MULTIPLIER)
            total_current = 0
            rng_state = (rng_states[itrk + ntrk * ipix], )
            for istep in range(nstep):
                for _ in range(MC_SAMPLE_MULTIPLIER):
                    x = subsegment_start[0] + step * (istep +
                                                      0.5) * direction[0]
                    y = subsegment_start[1] + step * (istep +
                                                      0.5) * direction[1]
                    z = subsegment_start[2] + step * (istep +
                                                      0.5) * direction[2]

                    z += xoroshiro128p_normal_float32(rng_state, 0) * sigmas[2]
                    t0 = abs(z - TPC_BORDERS[t["pixel_plane"]][2][0]
                             ) / detector.V_DRIFT - detector.TIME_WINDOW
                    if not t0 < time_tick < t0 + detector.TIME_WINDOW:
                        continue

                    x += xoroshiro128p_normal_float32(rng_state, 0) * sigmas[0]
                    y += xoroshiro128p_normal_float32(rng_state, 0) * sigmas[1]
                    x_dist = abs(x_p - x)
                    y_dist = abs(y_p - y)

                    if x_dist > detector.RESPONSE_BIN_SIZE * response.shape[0]:
                        continue
                    if y_dist > detector.RESPONSE_BIN_SIZE * response.shape[1]:
                        continue

                    total_current += charge * get_closest_waveform(
                        x_dist, y_dist, time_tick - t0, response)

            signals[itrk, ipix, it] = total_current
Exemple #6
0
def get_adc_values(pixels_signals, pixels_signals_tracks, time_ticks, adc_list,
                   adc_ticks_list, time_padding, rng_states, current_fractions,
                   pixel_thresholds):
    """
    Implementation of self-trigger logic

    Args:
        pixels_signals (:obj:`numpy.ndarray`): list of induced currents for
            each pixel
        pixels_signals_tracks (:obj:`numpy.ndarray`): list of induced currents
            for each track that induces current on each pixel
        time_ticks (:obj:`numpy.ndarray`): list of time ticks for each pixel
        adc_list (:obj:`numpy.ndarray`): list of integrated charges for each
            pixel
        adc_ticks_list (:obj:`numpy.ndarray`): list of the time ticks that
            correspond to each integrated charge
        time_padding (float): time interval to add to each time tick.
        rng_states (:obj:`numpy.ndarray`): array of random states for noise
            generation
        current_fractions (:obj:`numpy.ndarray`): 2D array that will contain
            the fraction of current induced on the pixel by each track
        pixel_thresholds(: obj: `numpy.ndarray`): list of discriminator
            thresholds for each pixel
    """
    ip = cuda.grid(1)

    if ip < pixels_signals.shape[0]:
        curre = pixels_signals[ip]
        ic = 0
        iadc = 0
        adc_busy = 0
        last_reset = 0
        q_sum = xoroshiro128p_normal_float32(rng_states,
                                             ip) * RESET_NOISE_CHARGE

        while ic < curre.shape[0] or adc_busy > 0:

            if iadc >= MAX_ADC_VALUES:
                print("More ADC values than possible,", MAX_ADC_VALUES)
                break

            q = 0
            if BUFFER_RISETIME > 0:
                conv_start = max(
                    last_reset,
                    floor(ic - 10 * BUFFER_RISETIME / detector.TIME_SAMPLING))
                for jc in range(conv_start, min(ic + 1, curre.shape[0])):
                    w = exp(
                        (jc - ic) * detector.TIME_SAMPLING / BUFFER_RISETIME
                    ) * (1 - exp(-detector.TIME_SAMPLING / BUFFER_RISETIME))
                    q += curre[jc] * detector.TIME_SAMPLING * w

                    for itrk in range(current_fractions.shape[2]):
                        current_fractions[ip][iadc][
                            itrk] += pixels_signals_tracks[ip][jc][
                                itrk] * detector.TIME_SAMPLING * w

            elif ic < curre.shape[0]:
                q += curre[ic] * detector.TIME_SAMPLING
                for itrk in range(current_fractions.shape[2]):
                    current_fractions[ip][iadc][itrk] += pixels_signals_tracks[
                        ip][ic][itrk] * detector.TIME_SAMPLING

            q_sum += q

            q_noise = xoroshiro128p_normal_float32(
                rng_states, ip) * UNCORRELATED_NOISE_CHARGE
            disc_noise = xoroshiro128p_normal_float32(rng_states,
                                                      ip) * DISCRIMINATOR_NOISE

            if adc_busy > 0:
                adc_busy -= 1

            if q_sum + q_noise >= pixel_thresholds[
                    ip] + disc_noise and adc_busy == 0:
                interval = round(
                    (3 * CLOCK_CYCLE + ADC_HOLD_DELAY * CLOCK_CYCLE) /
                    detector.TIME_SAMPLING)
                integrate_end = ic + interval

                ic += 1

                while ic <= integrate_end:
                    q = 0

                    if BUFFER_RISETIME > 0:
                        conv_start = max(
                            last_reset,
                            floor(ic - 10 * BUFFER_RISETIME /
                                  detector.TIME_SAMPLING))
                        for jc in range(conv_start,
                                        min(ic + 1, curre.shape[0])):
                            w = exp(
                                (jc - ic) * detector.TIME_SAMPLING /
                                BUFFER_RISETIME) * (1 - exp(
                                    -detector.TIME_SAMPLING / BUFFER_RISETIME))
                            q += curre[jc] * detector.TIME_SAMPLING * w

                            for itrk in range(current_fractions.shape[2]):
                                current_fractions[ip][iadc][
                                    itrk] += pixels_signals_tracks[ip][jc][
                                        itrk] * detector.TIME_SAMPLING * w

                    elif ic < curre.shape[0]:
                        q += curre[ic] * detector.TIME_SAMPLING
                        for itrk in range(current_fractions.shape[2]):
                            current_fractions[ip][iadc][
                                itrk] += pixels_signals_tracks[ip][ic][
                                    itrk] * detector.TIME_SAMPLING

                    q_sum += q
                    ic += 1

                adc = q_sum + xoroshiro128p_normal_float32(
                    rng_states, ip) * UNCORRELATED_NOISE_CHARGE
                disc_noise = xoroshiro128p_normal_float32(
                    rng_states, ip) * DISCRIMINATOR_NOISE

                if adc < pixel_thresholds[ip] + disc_noise:
                    ic += round(RESET_CYCLES * CLOCK_CYCLE /
                                detector.TIME_SAMPLING)
                    q_sum = xoroshiro128p_normal_float32(
                        rng_states, ip) * RESET_NOISE_CHARGE

                    for itrk in range(current_fractions.shape[2]):
                        current_fractions[ip][iadc][itrk] = 0
                    last_reset = ic
                    continue

                tot_backtracked = 0
                for itrk in range(current_fractions.shape[2]):
                    tot_backtracked += current_fractions[ip][iadc][itrk]

                for itrk in range(current_fractions.shape[2]):
                    current_fractions[ip][iadc][itrk] /= tot_backtracked

                adc_list[ip][iadc] = adc

                crossing_time_tick = min((ic, len(time_ticks) - 1))
                # handle case when tick extends past end of current array
                post_adc_ticks = max((ic - crossing_time_tick, 0))
                #+2-tick delay from when the PACMAN receives the trigger and when it registers it.
                adc_ticks_list[ip][iadc] = time_ticks[
                    crossing_time_tick] + time_padding - 2 + post_adc_ticks

                ic += round(RESET_CYCLES * CLOCK_CYCLE /
                            detector.TIME_SAMPLING)
                last_reset = ic
                adc_busy = round(ADC_BUSY_DELAY * CLOCK_CYCLE /
                                 detector.TIME_SAMPLING)

                q_sum = xoroshiro128p_normal_float32(rng_states,
                                                     ip) * RESET_NOISE_CHARGE

                iadc += 1
                continue

            ic += 1