summaryrefslogtreecommitdiff
path: root/chroma/cuda/pdf.cu
blob: c9c2ea4da9a4fb3151097c74c9e37a3eaa3e049e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// -*-c++-*-
#include <curand_kernel.h>

extern "C"
{

__global__ void
bin_hits(int nchannels, unsigned int *channel_q, float *channel_time,
	 unsigned int *hitcount, int tbins, float tmin, float tmax, int qbins,
	 float qmin, float qmax, unsigned int *pdf)
{
    int id = threadIdx.x + blockDim.x * blockIdx.x;

    if (id >= nchannels)
	return;

    unsigned int q = channel_q[id];
    float t = channel_time[id];
	
    if (t < 1e8 && t >= tmin && t < tmax && q >= qmin && q < qmax) {
	hitcount[id] += 1;
		
	int tbin = (t - tmin) / (tmax - tmin) * tbins;
	int qbin = (q - qmin) / (qmax - qmin) * qbins;
	    
	// row major order (channel, t, q)
	int bin = id * (tbins * qbins) + tbin * qbins + qbin;
	pdf[bin] += 1;
    }
}
	
__global__ void
accumulate_pdf_eval(int time_only, int nchannels, unsigned int *event_hit,
		    float *event_time, float *event_charge, float *mc_time,
		    unsigned int *mc_charge, // quirk of DAQ!
		    unsigned int *hitcount, unsigned int *bincount,
		    float min_twidth, float tmin, float tmax,
		    float min_qwidth, float qmin, float qmax,
		    float *nearest_mc, int min_bin_content)
{
    int id = threadIdx.x + blockDim.x * blockIdx.x;
	
    if (id >= nchannels)
	return;
	
    // Was this channel hit in the Monte Carlo?
    float channel_mc_time = mc_time[id];
    if (channel_mc_time >= 1e8)
	return; // Nothing else to do
	
    // Is this channel inside the range of the PDF?
    float distance;
    int channel_bincount = bincount[id];
    if (time_only) {
	if (channel_mc_time < tmin || channel_mc_time > tmax)
	    return;  // Nothing else to do
		
	// This MC information is contained in the PDF
	hitcount[id] += 1;
	  
	// Was this channel hit in the event-of-interest?
	int channel_event_hit = event_hit[id];
	if (!channel_event_hit)
	    return; // No need to update PDF value for unhit channel
		
	// Are we inside the minimum size bin?
	float channel_event_time = event_time[id];
	distance = fabsf(channel_mc_time - channel_event_time);
	if (distance < min_twidth/2.0)
	    bincount[id] = channel_bincount + 1;

    }
    else { // time and charge PDF
	float channel_mc_charge = mc_charge[id]; // int->float conversion because DAQ just returns an integer
	
	if (channel_mc_time < tmin || channel_mc_time > tmax ||
	    channel_mc_charge < qmin || channel_mc_charge > qmax)
	    return;  // Nothing else to do
		
	// This MC information is contained in the PDF
	hitcount[id] += 1;
	  
	// Was this channel hit in the event-of-interest?
	int channel_event_hit = event_hit[id];
	if (!channel_event_hit)
	    return; // No need to update PDF value for unhit channel
		
	// Are we inside the minimum size bin?
	float channel_event_time = event_time[id];
	float channel_event_charge = event_charge[id];
	float normalized_time_distance = fabsf(channel_event_time - channel_mc_time)/min_twidth/2.0;
	float normalized_charge_distance = fabsf(channel_event_charge - channel_mc_charge)/min_qwidth/2.0;
	distance = sqrt(normalized_time_distance*normalized_time_distance + normalized_charge_distance*normalized_charge_distance);

	if (distance < 1.0f)
	    bincount[id] = channel_bincount + 1;
    }

    // Do we need to keep updating the nearest_mc list?
    if (channel_bincount + 1 >= min_bin_content)
      return; // No need to perform insertion into nearest_mc because bincount is a better estimate of the PDF value

    // insertion sort the distance into the array of nearest MC points
    int offset = min_bin_content * id;
    int entry = min_bin_content - 1;
	
    // If last entry less than new entry, nothing to update
    if (distance > nearest_mc[offset + entry])
	return;

    // Find where to insert the new entry while sliding the rest
    // to the right
    entry--;
    while (entry >= 0) {
	if (nearest_mc[offset+entry] >= distance)
	    nearest_mc[offset+entry+1] = nearest_mc[offset+entry];
	else
	    break;
	entry--;
    }

    nearest_mc[offset+entry+1] = distance;
}

} // extern "C"