Project
Loading...
Searching...
No Matches
PadsPEM.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
17#include <cstring>
18#include <stdexcept>
19#include <vector>
20
22#include "mathieson.h"
23#include "mathUtil.h"
24
25#define VERBOSE 1
26#define CHECK 1
27
28namespace o2
29{
30namespace mch
31{
32
33extern ClusterConfig clusterConfig;
34
36{
38 double* xInf = pads.x;
39 double* yInf = pads.y;
40 double* xSup = pads.dx;
41 double* ySup = pads.dy;
42 for (int i = 0; i < nPads; i++) {
43 dx[i] = 0.5 * (xSup[i] - xInf[i]);
44 dy[i] = 0.5 * (ySup[i] - yInf[i]);
45 x[i] = xInf[i] + dx[i];
46 y[i] = yInf[i] + dy[i];
47 }
49 }
50}
51
53{
55 double* xInf = x;
56 double* yInf = y;
57 double* xSup = dx;
58 double* ySup = dy;
59 for (int i = 0; i < nPads; i++) {
60 xInf[i] = pads.x[i] - pads.dx[i];
61 xSup[i] = pads.x[i] + pads.dx[i];
62 yInf[i] = pads.y[i] - pads.dy[i];
63 ySup[i] = pads.y[i] + pads.dy[i];
64 }
66 }
67}
68
70{
72 double* xInf = x;
73 double* yInf = y;
74 double* xSup = dx;
75 double* ySup = dy;
76 double u;
77 for (int i = 0; i < nPads; i++) {
78 u = x[i];
79 xInf[i] = u - dx[i];
80 xSup[i] = u + dx[i];
81 u = y[i];
82 yInf[i] = u - dy[i];
83 ySup[i] = u + dy[i];
84 }
86 }
87}
88
90{
92 double* xInf = x;
93 double* yInf = y;
94 double* xSup = dx;
95 double* ySup = dy;
96 double du;
97 for (int i = 0; i < nPads; i++) {
98 dx[i] = 0.5 * (xSup[i] - xInf[i]);
99 dy[i] = 0.5 * (ySup[i] - yInf[i]);
100 x[i] = xInf[i] + dx[i];
101 y[i] = yInf[i] + dy[i];
102 }
104 }
105}
106PadIdx_t* Pads::buildFirstNeighbors(double* X, double* Y, double* DX,
107 double* DY, int N)
108{
109 const double eps = epsilonGeometry;
110 PadIdx_t* neighbors = new PadIdx_t[MaxNeighbors * N];
111 for (PadIdx_t i = 0; i < N; i++) {
112 PadIdx_t* i_neigh = getNeighborListOf(neighbors, i);
113 // Search neighbors of i
114 for (PadIdx_t j = 0; j < N; j++) {
115
116 int xMask0 = (std::fabs(X[i] - X[j]) < (DX[i] + DX[j]) + eps);
117 int yMask0 = (std::fabs(Y[i] - Y[j]) < (DY[i] + eps));
118 int xMask1 = (std::fabs(X[i] - X[j]) < (DX[i] + eps));
119 int yMask1 = (std::fabs(Y[i] - Y[j]) < (DY[i] + DY[j] + eps));
120 if ((xMask0 && yMask0) || (xMask1 && yMask1)) {
121 *i_neigh = j;
122 i_neigh++;
123 // Check
124 // printf( "pad %d neighbor %d xMask=%d yMask=%d\n", i, j, (xMask0 &&
125 // yMask0), (xMask1 && yMask1));
126 }
127 }
128 *i_neigh = -1;
129 if (CHECK &&
130 (std::fabs(i_neigh - getNeighborListOf(neighbors, i)) > MaxNeighbors)) {
131 printf("Pad %d : nbr of neighbours %ld greater than the limit %d \n", i,
132 i_neigh - getNeighborListOf(neighbors, i), MaxNeighbors);
133 throw std::out_of_range("Not enough allocation");
134 }
135 }
136 return neighbors;
137}
138// Build the K-neighbors list
140{
141 // kernelSize must be in the interval [0:2]
142 const double eps = epsilonGeometry;
143 const double* X = x;
144 const double* Y = y;
145 const double* DX = dx;
146 const double* DY = dy;
147 int N = nPads;
148 if ((kernelSize < 0) || (kernelSize > 2)) {
149 // set to default values
150 printf("Warning in getNeighbors : kerneSize overwritten by the default\n");
151 kernelSize = 1;
152 }
153 PadIdx_t* neighbors_ = new PadIdx_t[MaxNeighbors * N];
154 double factor = (2 * kernelSize - 1);
155 for (PadIdx_t i = 0; i < N; i++) {
156 PadIdx_t* i_neigh = getNeighborListOf(neighbors_, i);
157 double xTerm = factor * DX[i] + eps;
158 double yTerm = factor * DY[i] + eps;
159 // Search neighbors of i
160 for (PadIdx_t j = 0; j < N; j++) {
161 int xMask0 =
162 (fabs(X[i] - X[j]) < (xTerm + DX[j]));
163 int yMask0 = 0;
164 if (xMask0) {
165 yMask0 = (fabs(Y[i] - Y[j]) < (yTerm + DY[j]));
166 }
167 if (xMask0 && yMask0) {
168 *i_neigh = j;
169 i_neigh++;
170 // Check
171 // printf( "pad %d neighbor %d xMask=%d yMask=%d\n", i, j, (xMask0 &&
172 // yMask0), (xMask1 && yMask1));
173 }
174 }
175 // Set the End of list
176 *i_neigh = -1;
177 //
178 if (CHECK &&
179 (fabs(i_neigh - getNeighborListOf(neighbors_, i)) > MaxNeighbors)) {
180 printf("Pad %d : nbr of neighbours %ld greater than the limit %d \n", i,
181 i_neigh - getNeighborListOf(neighbors_, i), MaxNeighbors);
182 throw std::overflow_error("Not enough allocation");
183 }
184 }
185
187 Pads::printNeighbors(neighbors_, N);
188 }
189
190 return neighbors_;
191}
192
194{
195 double eps = epsilonGeometry;
196 //
197 std::vector<double> bX;
198 std::vector<double> bY;
199 std::vector<double> bdX;
200 std::vector<double> bdY;
201 int N = nPads;
202 // Build neigbors if required
203 PadIdx_t* neigh = getFirstNeighbors();
204 for (int i = 0; i < N; i++) {
205 bool east = true, west = true, north = true, south = true;
206 for (const PadIdx_t* neigh_ptr = getTheFirtsNeighborOf(neigh, i);
207 *neigh_ptr != -1; neigh_ptr++) {
208 PadIdx_t v = *neigh_ptr;
209 // If neighbours then no boundary pads to add
210 double xDelta = (x[v] - x[i]);
211 if (fabs(xDelta) > eps) {
212 if (xDelta > 0) {
213 east = false;
214 } else {
215 west = false;
216 }
217 }
218 double yDelta = (y[v] - y[i]);
219 if (fabs(yDelta) > eps) {
220 if (yDelta > 0) {
221 north = false;
222 } else {
223 south = false;
224 }
225 }
226 }
227 // Add new pads
228 if (east) {
229 bX.push_back(x[i] + 2 * dx[i]);
230 bY.push_back(y[i]);
231 bdX.push_back(dx[i]);
232 bdY.push_back(dy[i]);
233 }
234 if (west) {
235 bX.push_back(x[i] - 2 * dx[i]);
236 bY.push_back(y[i]);
237 bdX.push_back(dx[i]);
238 bdY.push_back(dy[i]);
239 }
240 if (north) {
241 bX.push_back(x[i]);
242 bY.push_back(y[i] + 2 * dy[i]);
243 bdX.push_back(dx[i]);
244 bdY.push_back(dy[i]);
245 }
246 if (south) {
247 bX.push_back(x[i]);
248 bY.push_back(y[i] - 2 * dy[i]);
249 bdX.push_back(dx[i]);
250 bdY.push_back(dy[i]);
251 }
252 }
253 // Suppress new pads which overlaps
254 int nPadToAdd = bX.size();
255 double error = epsilonGeometry;
256 int K = bX.size();
257 Mask_t toKeep[K];
258 vectorSetShort(toKeep, 1, K);
259 double xInf[K], xSup[K], yInf[K], ySup[K];
260 double maxInf[K], minSup[K];
261 double xOverlap[K], yOverlap[K];
262 double overlap;
263 // Compute x/y inf/sup
264 for (int k = 0; k < K; k++) {
265 xInf[k] = bX[k] - bdX[k];
266 xSup[k] = bX[k] + bdX[k];
267 yInf[k] = bY[k] - bdY[k];
268 ySup[k] = bY[k] + bdY[k];
269 }
270 // printf("[addBoundary] n=%d boundary pads added\n", K);
271
272 for (int k = 0; k < (K - 1); k++) {
273 if (toKeep[k]) {
274 // X overlap
275 vectorMaxScalar(&xInf[k + 1], xInf[k], K - k - 1, &maxInf[k + 1]);
276 vectorMinScalar(&xSup[k + 1], xSup[k], K - k - 1, &minSup[k + 1]);
277 vectorAddVector(&minSup[k + 1], -1.0, &maxInf[k + 1], K - k - 1, &xOverlap[k + 1]);
278 // Y overlap
279 vectorMaxScalar(&yInf[k + 1], yInf[k], K - k - 1, &maxInf[k + 1]);
280 vectorMinScalar(&ySup[k + 1], ySup[k], K - k - 1, &minSup[k + 1]);
281 vectorAddVector(&minSup[k + 1], -1.0, &maxInf[k + 1], K - k - 1, &yOverlap[k + 1]);
282
283 for (int l = k + 1; l < K; l++) {
284 // printf(" xOverlap[l]=%f, yOverlap[l]=%f\n", xOverlap[l], yOverlap[l]);
285 overlap = (xOverlap[l] < error) ? 0.0 : 1.0;
286 overlap = (yOverlap[l] < error) ? 0.0 * overlap : overlap * 1;
287 if (toKeep[l] && (overlap > 0.0)) {
288 toKeep[l] = 0;
289 nPadToAdd--;
290 // printf("[addBoundary] overlapping k=%d l=%d \n", k, l);
291 // printf(" pad k x=%f, dx=%f, y=%f, dy=%f\n", bX[k], bdX[k], bY[k], bdY[k]);
292 // printf(" pad l x=%f, dx=%f, y=%f, dy=%f\n", bX[l], bdX[l], bY[l], bdY[l]);
293 //
294 // Update boundary Pads
295 double infxy_ = bX[k] - bdX[k];
296 double supxy_ = bX[k] + bdX[k];
297 infxy_ = std::fmax(infxy_, xInf[l]);
298 supxy_ = std::fmin(supxy_, xSup[l]);
299 double dxy_ = 0.5 * (supxy_ - infxy_);
300 // pad center : xInf + 0.5 dx
301 bX[k] = infxy_ + dxy_;
302 bdX[k] = dxy_;
303 //
304 // The same for Y
305 infxy_ = bY[k] - bdY[k];
306 supxy_ = bY[k] + bdY[k];
307 infxy_ = std::fmax(infxy_, yInf[l]);
308 supxy_ = std::fmin(supxy_, ySup[l]);
309 dxy_ = 0.5 * (supxy_ - infxy_);
310 bY[k] = infxy_ + dxy_;
311 bdY[k] = dxy_;
312 // printf(" new pad k x=%f, dx=%f, y=%f, dy=%f\n", bX[k], bdX[k], bY[k], bdY[k]);
313 }
314 }
315 } // if (toKeep[k])
316 }
318 printf("[addBoundary] n=%d final boundary pads added, %d removed overlapping pads\n", nPadToAdd, K - nPadToAdd);
319 }
320
321 int nTotalPads = N + nPadToAdd;
323 printf("nTotalPads=%d, nPads=%d, nPadToAdd=%d\n", nTotalPads, N,
324 nPadToAdd);
325 }
326 Pads* padsWithBoundaries = new Pads(nTotalPads, chamberId);
327 Pads* newPads = padsWithBoundaries;
328 for (int i = 0; i < N; i++) {
329 newPads->x[i] = x[i];
330 newPads->y[i] = y[i];
331 newPads->dx[i] = dx[i];
332 newPads->dy[i] = dy[i];
333 newPads->q[i] = q[i];
334 newPads->saturate[i] = saturate[i];
335 }
336 newPads->nObsPads = N;
337 for (int i = N, k = 0; i < nTotalPads; k++) {
338 if (toKeep[k]) {
339 newPads->x[i] = bX[k];
340 newPads->y[i] = bY[k];
341 newPads->dx[i] = bdX[k];
342 newPads->dy[i] = bdY[k];
343 newPads->q[i] = 0.0;
344 newPads->saturate[i] = 0;
345 i++;
346 }
347 }
348 newPads->totalCharge = totalCharge;
349 //
350 // printPads( "[addBoundary] pads", *newPads );
351 return padsWithBoundaries;
352}
353
354Pads::Pads(int N, int chId, PadMode mode_)
355{
356 nPads = N;
357 nObsPads = N;
358 mode = mode_;
359 chamberId = chId;
360 allocate();
361}
362
363/* Old Version: not used
364// Merge the 2 pad sets
365// Remark : pads0, pads1 correspond respectively
366// to the cath-plane 0, 1
367Pads::Pads( const Pads *pads0, const Pads *pads1) {
368 int n0 = Pads::getNbrOfPads(pads0);
369 int n1 = Pads::getNbrOfPads(pads1);
370 nPads = n0 + n1;
371 if ( n0 != 0 ) {
372 chamberId = pads0->chamberId;
373 mode = pads0->mode;
374 }
375 else {
376 chamberId = pads1->chamberId;
377 mode = pads1->mode;
378 }
379 allocate();
380 totalCharge = 0.0;
381 // X, Y, dX, dY, q
382 if( n0 ) {
383 vectorCopy(pads0->x, n0, x);
384 vectorCopy(pads0->y, n0, y);
385 vectorCopy(pads0->dx, n0, dx);
386 vectorCopy(pads0->dy, n0, dy);
387 vectorCopy(pads0->q, n0, q);
388 // saturate pads
389 vectorCopyShort( pads0->saturate, n0, saturate);
390 totalCharge += pads0->totalCharge;
391 }
392 if (n1) {
393 vectorCopy(pads1->x, n1, &x[n0]);
394 vectorCopy(pads1->y, n1, &y[n0]);
395 vectorCopy(pads1->dx, n1, &dx[n0]);
396 vectorCopy(pads1->dy, n1, &dy[n0]);
397 vectorCopy(pads1->q, n1, &q[n0]);
398 // saturate pads
399 vectorCopyShort( pads1->saturate, n1, &saturate[n0]);
400 totalCharge += pads1->totalCharge;
401
402 }
403 // Cathode plane
404 vectorSetShort( cath, 0, n0 );
405 vectorSetShort( &cath[n0], 1, n1 );
406}
407*/
408
409// Over allocation
410Pads::Pads(const Pads* pads, int size)
411{
412 nPads = pads->nPads;
413 nObsPads = pads->nObsPads;
414 mode = pads->mode;
415 chamberId = pads->chamberId;
416 totalCharge = pads->totalCharge;
417 int size_ = (size < nPads) ? nPads : size;
418 allocate(size_);
419 memcpy(x, pads->x, sizeof(double) * nPads);
420 memcpy(y, pads->y, sizeof(double) * nPads);
421 memcpy(dx, pads->dx, sizeof(double) * nPads);
422 memcpy(dy, pads->dy, sizeof(double) * nPads);
423 memcpy(q, pads->q, sizeof(double) * nPads);
424 if (pads->saturate != nullptr) {
425 memcpy(saturate, pads->saturate, sizeof(Mask_t) * nPads);
426 }
427 if (pads->cath != nullptr) {
428 memcpy(cath, pads->cath, sizeof(Mask_t) * nPads);
429 }
430}
431
432Pads::Pads(const Pads& pads, PadMode mode_)
433{
434 nPads = pads.nPads;
435 nObsPads = pads.nObsPads;
436 mode = mode_;
437 chamberId = pads.chamberId;
438 totalCharge = pads.totalCharge;
439 allocate();
440 if (mode == pads.mode) {
441 memcpy(x, pads.x, sizeof(double) * nPads);
442 memcpy(y, pads.y, sizeof(double) * nPads);
443 memcpy(dx, pads.dx, sizeof(double) * nPads);
444 memcpy(dy, pads.dy, sizeof(double) * nPads);
445 memcpy(q, pads.q, sizeof(double) * nPads);
446 } else if (mode == PadMode::xydxdyMode) {
447 // xyInfSupMode -> xydxdyMode
448 padBoundsToCenter(pads);
449 memcpy(q, pads.q, sizeof(double) * nPads);
450 } else {
451 // xydxdyMode -> xyInfSupMode
452 padCenterToBounds(pads);
453 memcpy(q, pads.q, sizeof(double) * nPads);
454 }
455 if (pads.saturate) {
456 memcpy(saturate, pads.saturate, sizeof(Mask_t) * nPads);
457 }
458 if (pads.cath) {
459 memcpy(cath, pads.cath, sizeof(Mask_t) * nPads);
460 }
461}
462
463Pads::Pads(const Pads& pads, const Mask_t* mask)
464{
465 nPads = vectorSumShort(mask, pads.nPads);
467 chamberId = pads.chamberId;
468 allocate();
469
470 vectorGather(pads.x, mask, pads.nPads, x);
471 vectorGather(pads.y, mask, pads.nPads, y);
472 vectorGather(pads.dx, mask, pads.nPads, dx);
473 vectorGather(pads.dy, mask, pads.nPads, dy);
474 vectorGather(pads.q, mask, pads.nPads, q);
475 if (pads.saturate) {
476 vectorGatherShort(pads.saturate, mask, pads.nPads, saturate);
477 }
478 if (pads.cath) {
479 vectorGatherShort(pads.cath, mask, pads.nPads, cath);
480 }
481 totalCharge = vectorSum(q, nPads);
482 nObsPads = nPads;
483}
484
485/* Old version: Unused
486Pads::Pads( const double *x_, const double *y_, const double *dx_, const double
487*dy_, const double *q_, const Mask_t *saturate_, int chId, int nPads_) { mode =
488xydxdyMode; nPads = nPads_; chamberId = chId; allocate();
489 // Copy pads
490 memcpy ( x, x_, sizeof(double)*nPads );
491 memcpy ( y, y_, sizeof(double)*nPads);
492 memcpy ( dx, dx_, sizeof(double)*nPads );
493 memcpy ( dy, dy_, sizeof(double)*nPads );
494 memcpy ( q, q_, sizeof(double)*nPads );
495 if( saturate_ != nullptr ) {
496 memcpy ( saturate, saturate_, sizeof(Mask_t)*nPads );
497 }
498}
499*/
500
501// Take the ownership of coordinates (x, y, dx, dy)
502Pads::Pads(double* x_, double* y_, double* dx_, double* dy_, int chId,
503 int nPads_)
504{
506 nPads = nPads_;
507 nObsPads = nPads;
508 chamberId = chId;
509 x = x_;
510 y = y_;
511 dx = dx_;
512 dy = dy_;
513 q = new double[nPads];
514 // Set null Charge
515 vectorSetZero(q, nPads);
516 // others
517 saturate = nullptr;
518 cath = nullptr;
519 neighbors = nullptr;
520 totalCharge = 0;
521}
522
523Pads::Pads(const double* x_, const double* y_, const double* dx_,
524 const double* dy_, const double* q_, const short* cathode,
525 const Mask_t* saturate_, short selectedCath, int chId,
526 PadIdx_t* mapCathPadIdxToPadIdx, int nAllPads)
527{
529 int nCathode1 = vectorSumShort(cathode, nAllPads);
530 nPads = nCathode1;
531 if (selectedCath == 0) {
532 nPads = nAllPads - nCathode1;
533 }
534 nObsPads = nPads;
535 chamberId = chId;
536 allocate();
537 double qSum = 0;
538 // Copy pads
539 int k = 0;
540 for (int i = 0; i < nAllPads; i++) {
541 if (cathode[i] == selectedCath) {
542 x[k] = x_[i];
543 y[k] = y_[i];
544 dx[k] = dx_[i];
545 dy[k] = dy_[i];
546 q[k] = q_[i];
547 qSum += q_[i];
548 saturate[k] = saturate_[i];
549 mapCathPadIdxToPadIdx[k] = i;
550 k++;
551 }
552 }
553 totalCharge = qSum;
554}
555
556Pads::Pads(const double* x_, const double* y_, const double* dx_,
557 const double* dy_, const double* q_, const short* cathode,
558 const Mask_t* saturate_, int chId, int nAllPads)
559{
561 // int nCathode1 = vectorSumShort(cathode, nAllPads);
562 nPads = nAllPads;
563 nObsPads = nPads;
564 /*
565 if (selectedCath == 0) {
566 nPads = nAllPads - nCathode1;
567 }
568 */
569 chamberId = chId;
570 allocate();
571 double qSum = 0;
572 // Copy
573 vectorCopy(x_, nPads, x);
574 vectorCopy(y_, nPads, y);
575 vectorCopy(dx_, nPads, dx);
576 vectorCopy(dy_, nPads, dy);
577 vectorCopy(q_, nPads, q);
578 vectorCopyShort(cathode, nPads, cath);
579 vectorCopyShort(saturate_, nPads, saturate);
580 totalCharge = vectorSum(q, nPads);
581}
582
583// Concatenate pads
584Pads::Pads(const Pads* pads0, const Pads* pads1, PadMode mode_)
585{
586
587 // Take Care: pads0 and pads2 must be in xydxdyMode
588 bool padsMode = (pads0 == nullptr) ? true : (pads0->mode == PadMode::xydxdyMode);
589 padsMode = (pads1 == nullptr) ? padsMode : (pads1->mode == PadMode::xydxdyMode);
590 if (!padsMode) {
591 throw std::out_of_range("Pads:: bad mode (xydxdyMode required) for pad merging");
592 }
593
594 int N0 = (pads0 == nullptr) ? 0 : pads0->nPads;
595 int N1 = (pads1 == nullptr) ? 0 : pads1->nPads;
596 int nObs0 = (pads0 == nullptr) ? 0 : pads0->nObsPads;
597 int nObs1 = (pads1 == nullptr) ? 0 : pads1->nObsPads;
598 nPads = N0 + N1;
599 chamberId = (N0) ? pads0->chamberId : pads1->chamberId;
600 allocate();
601 // Copy observable pads0
602 int destIdx = 0;
603 copyPads(pads0, 0, destIdx, nObs0, 0);
604 destIdx += nObs0;
605 // Copy observable pads1
606 copyPads(pads1, 0, destIdx, nObs1, 1);
607 destIdx += nObs1;
608
609 // Boundary pads0
610 int n = N0 - nObs0;
611 copyPads(pads0, nObs0, destIdx, n, 0);
612 destIdx += n;
613 n = N1 - nObs1;
614 copyPads(pads1, nObs1, destIdx, n, 1);
615 destIdx += n;
616
617 /*
618 if (N1) {
619 memcpy(x, pads1->x, sizeof(double) * N1);
620 memcpy(y, pads1->y, sizeof(double) * N1);
621 memcpy(dx, pads1->dx, sizeof(double) * N1);
622 memcpy(dy, pads1->dy, sizeof(double) * N1);
623 memcpy(q, pads1->q, sizeof(double) * N1);
624 memcpy(saturate, pads1->saturate, sizeof(Mask_t) * N1);
625 vectorSetShort(cath, 0, N1);
626 }
627 if (N2) {
628 // Copy pads2
629 memcpy(&x[N1], pads2->x, sizeof(double) * N2);
630 memcpy(&y[N1], pads2->y, sizeof(double) * N2);
631 memcpy(&dx[N1], pads2->dx, sizeof(double) * N2);
632 memcpy(&dy[N1], pads2->dy, sizeof(double) * N2);
633 memcpy(&q[N1], pads2->q, sizeof(double) * N2);
634 memcpy(&saturate[N1], pads2->saturate, sizeof(Mask_t) * N2);
635 vectorSetShort(&cath[N1], 1, N2);
636 }
637 */
638 // ??? printPads(" Before InfSup", *this);
639 if (mode_ == PadMode::xyInfSupMode) {
641 }
642 totalCharge = vectorSum(q, nPads);
643 nObsPads = nObs0 + nObs1;
644 // ??? printPads(" after InfSup", *this);
645}
646/*
647void Pads::print(const char *title)
648{
649 printf("%s\n", title);
650 printf("print pads nPads=%4d nObsPads=%4d mode=%1d\n", nPads, nObsPads, mode);
651 printf("idx x y dx dy cath sat charge \n");
652 for (int i=0; i < nPads; i++) {
653 printf("%2d %7.3f %7.3f %7.3f %7.3f %1d %1d %7.3f \n", i, x[i], y[i], dx[i], dy[i], cath[i], saturate[i], q[i]);
654 }
655}
656*/
657
659{
660 Pads* sPads = new Pads(K, chamberId, mode);
661 int k0 = 0;
662 for (int k = 0; k < K; k++) {
663 int idx = index[k];
664 sPads->x[k0] = x[idx];
665 sPads->y[k0] = y[idx];
666 sPads->dx[k0] = dx[idx];
667 sPads->dy[k0] = dy[idx];
668 sPads->q[k0] = q[idx];
669 sPads->saturate[k0] = saturate[idx];
670 k0++;
671 }
672 sPads->nPads = K;
673 sPads->nObsPads = K;
674 return sPads;
675}
676
677// ??? removePad can be suppressed ????
678void Pads::removePad(int index)
679{
680 if (nObsPads != nPads) {
681 throw std::out_of_range("Pads::removePad: bad usage");
682 }
683 if ((index < 0) || (index >= nPads)) {
684 return;
685 }
686 int nItems = nPads - index;
687 if (index == nPads - 1) {
688 nPads = nPads - 1;
689 return;
690 }
691 vectorCopy(&x[index + 1], nItems, &x[index]);
692 vectorCopy(&y[index + 1], nItems, &y[index]);
693 vectorCopy(&dx[index + 1], nItems, &dx[index]);
694 vectorCopy(&dy[index + 1], nItems, &dy[index]);
695 //
696 vectorCopy(&q[index + 1], nItems, &q[index]);
697 vectorCopyShort(&saturate[index + 1], nItems, &saturate[index]);
698 //
699 nPads = nPads - 1;
700 nObsPads = nObsPads - 1;
701}
702
703void Pads::allocate()
704{
705 // Note: Must be deallocated/releases if required
706 x = nullptr;
707 y = nullptr;
708 dx = nullptr;
709 dy = nullptr;
710 saturate = nullptr;
711 q = nullptr;
712 neighbors = nullptr;
713 int N = nPads;
714 x = new double[N];
715 y = new double[N];
716 dx = new double[N];
717 dy = new double[N];
718 saturate = new Mask_t[N];
719 cath = new Mask_t[N];
720 q = new double[N];
721}
722
723// Over-allocation of pads
724void Pads::allocate(int size)
725{
726 // Note: Must be deallocated/releases if required
727 x = nullptr;
728 y = nullptr;
729 dx = nullptr;
730 dy = nullptr;
731 saturate = nullptr;
732 q = nullptr;
733 neighbors = nullptr;
734 // N nbr of pads used
735 int N = nPads;
736 // size allocation
737 x = new double[size];
738 y = new double[size];
739 dx = new double[size];
740 dy = new double[size];
741 saturate = new Mask_t[size];
742 cath = new Mask_t[size];
743 q = new double[size];
744}
745
746void Pads::copyPads(const Pads* srcPads, int srcIdx, int dstIdx, int N, Mask_t cathValue)
747{
748 if (N) {
749 memcpy(&x[dstIdx], &srcPads->x[srcIdx], sizeof(double) * N);
750 memcpy(&y[dstIdx], &srcPads->y[srcIdx], sizeof(double) * N);
751 memcpy(&dx[dstIdx], &srcPads->dx[srcIdx], sizeof(double) * N);
752 memcpy(&dy[dstIdx], &srcPads->dy[srcIdx], sizeof(double) * N);
753 memcpy(&q[dstIdx], &srcPads->q[srcIdx], sizeof(double) * N);
754 memcpy(&saturate[dstIdx], &srcPads->saturate[srcIdx], sizeof(Mask_t) * N);
755 vectorSetShort(&cath[dstIdx], cathValue, N);
756 }
757}
759{
760 totalCharge = vectorSum(q, nPads);
761 return totalCharge;
762}
763//
765{
766 double meanCharge;
767 if (cath != nullptr) {
768 int nCath1 = vectorSumShort(cath, nPads);
769 int nCath0 = nPads - nCath1;
770 int nCath = (nCath0 > 0) + (nCath1 > 0);
771 meanCharge = totalCharge / nCath;
772 } else {
773 meanCharge = totalCharge;
774 }
775 return meanCharge;
776}
777
778void Pads::setCharges(double c)
779{
780 vectorSet(q, c, nPads);
781 totalCharge = c * nPads;
782}
783
784void Pads::setCharges(double* q_, int n)
785{
786 vectorCopy(q_, n, q);
787 totalCharge = vectorSum(q_, n);
788}
789
790void Pads::setCathodes(Mask_t cath_) { vectorSetShort(cath, cath_, nPads); }
791
792void Pads::setSaturate(Mask_t val) { vectorSetShort(saturate, val, nPads); }
793
794void Pads::setToZero()
795{
796 for (int i = 0; i < nPads; i++) {
797 x[i] = 0.0;
798 y[i] = 0.0;
799 dx[i] = 0.0;
800 dy[i] = 0.0;
801 q[i] = 0.0;
802 }
803}
804
805int Pads::removePads(double qCut)
806{
807 if (nObsPads != nPads) {
808 throw std::out_of_range("Pads::removePad: bad usage");
809 }
810 double qSum = 0.0;
811 int k = 0;
812 for (int i = 0; i < nPads; i++) {
813 // printf("q %f\n", q[i]);
814 if (q[i] >= qCut) {
815 qSum += q[i];
816 q[k] = q[i];
817 x[k] = x[i];
818 y[k] = y[i];
819 dx[k] = dx[i];
820 dy[k] = dy[i];
821 k++;
822 }
823 }
824 totalCharge = qSum;
825 nPads = k;
826 nObsPads = k;
827 return k;
828}
829
831{
832 for (int i = 0; i < nPads; i++) {
833 q[i] = q[i] / totalCharge;
834 }
835}
836
837// Build the neighbor list
839{
840 int N = nPads;
841 if (neighbors == nullptr) {
842 neighbors = buildFirstNeighbors(x, y, dx, dy, N);
843 }
844 return neighbors;
845}
846
848 int nGroups)
849{
850 int nNewGroups = 0;
851 if (nPads == 0) {
852 return nGroups;
853 }
854
856 printf("[addIsolatedPadInGroups] nGroups=%d\n", nGroups);
857 vectorPrintShort(" cathToGrp input", cathToGrp, nPads);
858 }
859 PadIdx_t* neigh = getFirstNeighbors();
860
861 for (int p = 0; p < nPads; p++) {
862 if (cathToGrp[p] == 0) {
863 // Neighbors
864 //
865 int q = -1;
866 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, p); *neigh_ptr != -1;
867 neigh_ptr++) {
868 q = *neigh_ptr;
869 // printf(" Neigh of %d: %d\n", p, q);
870 if (cathToGrp[q] != 0) {
871 if (cathToGrp[p] == 0) {
872 // Propagation
873 cathToGrp[p] = cathToGrp[q];
874 // printf(" Neigh=%d: Propagate the grp=%d of the neighbor to
875 // p=%d\n", q, cathToGrp[q], p);
876 } else if (cathToGrp[p] != cathToGrp[q]) {
877 // newCathToGrp[p] changed
878 // Fuse Grp
879 Mask_t minGrp = cathToGrp[p];
880 Mask_t maxGrp = cathToGrp[q];
881 if (cathToGrp[p] > cathToGrp[q]) {
882 minGrp = cathToGrp[q];
883 maxGrp = cathToGrp[p];
884 }
885 grpToGrp[maxGrp] = minGrp;
886 // printf(" Neigh=%d: Fuse the grp=%d of the neighbor with
887 // p-Group=%d\n", q, cathToGrp[q], cathToGrp[p]); Update
888 cathToGrp[p] = minGrp;
889 }
890 }
891 }
892 if (cathToGrp[p] == 0) {
893 // New Group
894 nGroups++;
895 nNewGroups++;
896 cathToGrp[p] = nGroups;
897 // printf(" Grp-isolated pad p=%d, new grp=%d \n", p, nGroups);
898 }
899 }
900 }
901
902 // Finish the Fusion
903 for (int g = 0; g < (nGroups + 1); g++) {
904 Mask_t gBar = g;
905 while (gBar != grpToGrp[gBar]) {
906 gBar = grpToGrp[gBar];
907 }
908 // Terminal Grp : gBar = grpToGrp[gBar]
909 grpToGrp[g] = gBar;
910 }
911
913 printf(" grpToGrp\n");
914 for (int g = 0; g < (nGroups + 1); g++) {
915 printf(" %d -> %d\n", g, grpToGrp[g]);
916 }
917 }
918 // Apply group to Pads
919 for (int p = 0; p < nPads; p++) {
920 cathToGrp[p] = grpToGrp[cathToGrp[p]];
921 }
922 // Save in grpToGrp
923 vectorCopyShort(grpToGrp, (nGroups + 1), grpToGrp);
924 //
925 return nNewGroups;
926}
927
928void Pads::release()
929{
930 if (x != nullptr) {
931 delete[] x;
932 x = nullptr;
933 }
934 if (y != nullptr) {
935 delete[] y;
936 y = nullptr;
937 }
938 if (dx != nullptr) {
939 delete[] dx;
940 dx = nullptr;
941 }
942 if (dy != nullptr) {
943 delete[] dy;
944 dy = nullptr;
945 }
946
947 if (q != nullptr) {
948 delete[] q;
949 q = nullptr;
950 }
951 if (cath != nullptr) {
952 delete[] cath;
953 cath = nullptr;
954 }
955 if (saturate != nullptr) {
956 delete[] saturate;
957 saturate = nullptr;
958 }
959 deleteInt(neighbors);
960 nPads = 0;
961 nObsPads = 0;
962}
963
964// Refine on/around localMax
966 std::vector<PadIdx_t>& pixToRefineIdx, double Cij[])
967{
968
969 // Take care : here all pads data describe the pixels
970 // Number of Pixels
971 int K = nPads;
972 // Number of Pads
973 int N = pads.getNbrOfPads();
974
975 const double* xInf = pads.getXInf();
976 const double* yInf = pads.getYInf();
977 const double* xSup = pads.getXSup();
978 const double* ySup = pads.getYSup();
979 int chId = pads.getChamberId();
980
981 double cut = -1;
982 int count = N;
983 //
985 vectorPrint("Pads::refinePads", q, N);
986 printf("Pads::refinePads count(new nPads)=%d\n", count);
987 }
988
989 double* xWestIntegrals = new double[N];
990 double* xEastIntegrals = new double[N];
991 double* yNorthIntegrals = new double[N];
992 double* ySouthIntegrals = new double[N];
993 int axe;
994 double totalChargeInc = 0.0;
995 int k = K;
996 for (int i = 0; i < pixToRefineIdx.size(); i++) {
997 int pixelMaxIdx = pixToRefineIdx[i];
998 // printf("Refine pixel i=%d, q[pixelMaxIdx]=%f saturate[pixelMaxIdx]=%d\n", i, q[pixelMaxIdx], saturate[pixelMaxIdx]);
999 //
1000 // saturate is used to tag pixels already refined
1001 if (saturate[pixelMaxIdx] == 0) {
1002
1003 saturate[pixelMaxIdx] = 1;
1004 double xOld = x[pixelMaxIdx];
1005 double yOld = y[pixelMaxIdx];
1006 double dxOld = dx[pixelMaxIdx];
1007 double dyOld = dy[pixelMaxIdx];
1008 double qOld = q[pixelMaxIdx];
1009 totalChargeInc += (3 * qOld);
1010 // NW
1011 // Done in place (same pixel index)
1012 x[pixelMaxIdx] = xOld - 0.5 * dxOld;
1013 y[pixelMaxIdx] = yOld + 0.5 * dyOld;
1014 dx[pixelMaxIdx] = 0.5 * dxOld;
1015 dy[pixelMaxIdx] = 0.5 * dyOld;
1016 // rPads->q[k] = 0.25 * qOld;
1017 q[pixelMaxIdx] = qOld;
1018 // Update Cij
1019 axe = 0;
1020 compute1DPadIntegrals(xInf, xSup, N, x[pixelMaxIdx], axe, chId, xWestIntegrals);
1021 axe = 1;
1022 compute1DPadIntegrals(yInf, ySup, N, y[pixelMaxIdx], axe, chId, yNorthIntegrals);
1023 // 2D Integral
1024 vectorMultVector(xWestIntegrals, yNorthIntegrals, N, &Cij[N * pixelMaxIdx]);
1025 // k++;
1026
1027 // NE
1028 x[k] = xOld + 0.5 * dxOld;
1029 y[k] = yOld + 0.5 * dyOld;
1030 dx[k] = 0.5 * dxOld;
1031 dy[k] = 0.5 * dyOld;
1032 // rPads->q[k] = 0.25 * qOld;
1033 q[k] = qOld;
1034 saturate[k] = 1;
1035 // Update Cij
1036 axe = 0;
1037 compute1DPadIntegrals(xInf, xSup, N, x[k], axe, chId, xEastIntegrals);
1038 vectorMultVector(xEastIntegrals, yNorthIntegrals, N, &Cij[N * k]);
1039 k++;
1040
1041 // SW
1042 x[k] = xOld - 0.5 * dxOld;
1043 y[k] = yOld - 0.5 * dyOld;
1044 dx[k] = 0.5 * dxOld;
1045 dy[k] = 0.5 * dyOld;
1046 // rPads->q[k] = 0.25 * qOld;
1047 q[k] = qOld;
1048 saturate[k] = 1;
1049 // Update Cij
1050 axe = 1;
1051 compute1DPadIntegrals(yInf, ySup, N, y[k], axe, chId, ySouthIntegrals);
1052 vectorMultVector(xWestIntegrals, ySouthIntegrals, N, &Cij[N * k]);
1053 k++;
1054
1055 // SE
1056 x[k] = xOld + 0.5 * dxOld;
1057 y[k] = yOld - 0.5 * dyOld;
1058 dx[k] = 0.5 * dxOld;
1059 dy[k] = 0.5 * dyOld;
1060 // rPads->q[k] = 0.25 * qOld;
1061 q[k] = qOld;
1062 saturate[k] = 1;
1063 // Update Cij
1064 vectorMultVector(xEastIntegrals, ySouthIntegrals, N, &Cij[N * k]);
1065 k++;
1066 nPads += 3;
1067 }
1068 }
1069 totalCharge += totalChargeInc;
1070 nObsPads = nPads;
1071 delete[] xWestIntegrals;
1072 delete[] xEastIntegrals;
1073 delete[] yNorthIntegrals;
1074 delete[] ySouthIntegrals;
1075}
1076
1077// refinement on locam mwxima
1078// use for pixels
1079// Old version (without Cij update)
1080// To keep ???
1081void Pads::refineLocalMax(Pads& localMax, std::vector<PadIdx_t>& localMaxIdx)
1082{
1083 // ??? LocalMax not used except for the cutoff
1084
1085 // Take care : here all pads data describe the pixels
1086 int N = nPads;
1087 int nLocalMax = localMax.getNbrOfPads();
1088 /* qCut : not used
1089 // Count pad such as q > 4 * pixCutOf
1090 int count=0;
1091 double cut = 0.2;
1092 for (int i=0; i < N; i++) {
1093 if ( q[i] > cut ) {
1094 count++;
1095 }
1096 }
1097 */
1098 // printf("nPixels=%d nLocalMax=%d localMaxIdx.size=%lu\n", N, nLocalMax, localMaxIdx.size());
1099 double cut = -1;
1100 int count = N;
1101 //
1103 vectorPrint("Pads::refinePads", q, N);
1104 printf("Pads::refinePads count(new nPads)=%d\n", count);
1105 }
1106
1107 double totalChargeInc = 0.0;
1108 int k = N;
1109 for (int i = 0; i < localMaxIdx.size(); i++) {
1110 int pixelMaxIdx = localMaxIdx[i];
1111 // saturate is used to tag pixels already refined
1112 printf("Refinement i=%d, localMax.q[i]=%f saturate[pixelMaxIdx]=%d\n", i, localMax.q[i], saturate[pixelMaxIdx]);
1113 if ((localMax.q[i] > cut) && (saturate[pixelMaxIdx] == 0)) {
1114 saturate[pixelMaxIdx] = 1;
1115 double xOld = x[pixelMaxIdx];
1116 double yOld = y[pixelMaxIdx];
1117 double dxOld = dx[pixelMaxIdx];
1118 double dyOld = dy[pixelMaxIdx];
1119 double qOld = q[pixelMaxIdx];
1120 printf("refine on pixel %d\n", pixelMaxIdx);
1121 totalChargeInc += (3 * qOld);
1122 // NW
1123 // Done in place (same pixel index)
1124 x[pixelMaxIdx] = xOld - 0.5 * dxOld;
1125 y[pixelMaxIdx] = yOld + 0.5 * dyOld;
1126 dx[pixelMaxIdx] = 0.5 * dxOld;
1127 dy[pixelMaxIdx] = 0.5 * dyOld;
1128 // rPads->q[k] = 0.25 * qOld;
1129 q[pixelMaxIdx] = qOld;
1130 // k++;
1131
1132 // NE
1133 x[k] = xOld + 0.5 * dxOld;
1134 y[k] = yOld + 0.5 * dyOld;
1135 dx[k] = 0.5 * dxOld;
1136 dy[k] = 0.5 * dyOld;
1137 // rPads->q[k] = 0.25 * qOld;
1138 q[k] = qOld;
1139 saturate[k] = 1;
1140 k++;
1141
1142 // SW
1143 x[k] = xOld - 0.5 * dxOld;
1144 y[k] = yOld - 0.5 * dyOld;
1145 dx[k] = 0.5 * dxOld;
1146 dy[k] = 0.5 * dyOld;
1147 // rPads->q[k] = 0.25 * qOld;
1148 q[k] = qOld;
1149 saturate[k] = 1;
1150 k++;
1151
1152 // SE
1153 x[k] = xOld + 0.5 * dxOld;
1154 y[k] = yOld - 0.5 * dyOld;
1155 dx[k] = 0.5 * dxOld;
1156 dy[k] = 0.5 * dyOld;
1157 // rPads->q[k] = 0.25 * qOld;
1158 q[k] = qOld;
1159 saturate[k] = 1;
1160 k++;
1161 nPads += 3;
1162 }
1163 }
1164 totalCharge += totalChargeInc;
1165 // nPads = N+3*nLocalMax;
1166 nObsPads = nPads;
1167 // return rPads;
1168}
1169
1171{
1172 int N = nPads;
1173 /* qCut : not used
1174 // Count pad such as q > 4 * pixCutOf
1175 int count=0;
1176 double cut = 0.2;
1177 for (int i=0; i < N; i++) {
1178 if ( q[i] > cut ) {
1179 count++;
1180 }
1181 }
1182 */
1183 double cut = -1;
1184 int count = N;
1185 //
1187 vectorPrint("Pads::refinePads", q, N);
1188 printf("Pads::refinePads count(new nPads)=%d\n", count);
1189 }
1190 Pads* rPads = new Pads(count * 4, chamberId);
1191 int k = 0;
1192 for (int i = 0; i < N; i++) {
1193 if (q[i] > cut) {
1194 // NW
1195 rPads->x[k] = x[i] - 0.5 * dx[i];
1196 rPads->y[k] = y[i] + 0.5 * dy[i];
1197 rPads->dx[k] = 0.5 * dx[i];
1198 rPads->dy[k] = 0.5 * dy[i];
1199 // rPads->q[k] = 0.25 * q[i];
1200 rPads->q[k] = q[i];
1201 k++;
1202
1203 // NE
1204 rPads->x[k] = x[i] + 0.5 * dx[i];
1205 rPads->y[k] = y[i] + 0.5 * dy[i];
1206 rPads->dx[k] = 0.5 * dx[i];
1207 rPads->dy[k] = 0.5 * dy[i];
1208 // rPads->q[k] = 0.25 * q[i];
1209 rPads->q[k] = q[i];
1210 k++;
1211
1212 // SW
1213 rPads->x[k] = x[i] - 0.5 * dx[i];
1214 rPads->y[k] = y[i] - 0.5 * dy[i];
1215 rPads->dx[k] = 0.5 * dx[i];
1216 rPads->dy[k] = 0.5 * dy[i];
1217 // rPads->q[k] = 0.25 * q[i];
1218 rPads->q[k] = q[i];
1219 k++;
1220
1221 // SE
1222 rPads->x[k] = x[i] + 0.5 * dx[i];
1223 rPads->y[k] = y[i] - 0.5 * dy[i];
1224 rPads->dx[k] = 0.5 * dx[i];
1225 rPads->dy[k] = 0.5 * dy[i];
1226 // rPads->q[k] = 0.25 * q[i];
1227 rPads->q[k] = q[i];
1228 k++;
1229 }
1230 }
1231 rPads->totalCharge = 4 * totalCharge;
1232 return rPads;
1233}
1234
1235Pads* Pads::extractLocalMaxOnCoarsePads(std::vector<PadIdx_t>& localMaxIdx)
1236{
1238 printf(" - Pads::extractLocalMax on Coarse Pads(extractLocalMax nPads=%d)\n", nPads);
1239 }
1240 double qMax = vectorMax(q, nPads);
1241 //
1242 // TO DO ??? Compute the neighbors once
1243 // between to refinements
1244 if (neighbors != nullptr) {
1245 delete[] neighbors;
1246 }
1247 // 4(5) neighbors
1248 neighbors = getFirstNeighbors();
1249 PadIdx_t* neigh = neighbors;
1250 // printNeighbors( neigh, nPads);
1251 //
1252 // Part I - Morphologic Laplacian operator
1253 //
1254 double morphLaplacian[nPads];
1255 double laplacian[nPads];
1256 double weight[nPads];
1257 vectorSet(morphLaplacian, -1.0, nPads);
1258 // Invalid the neighbors of a local max
1259 Mask_t alreadyDone[nPads];
1260 vectorSetZeroShort(alreadyDone, nPads);
1261 std::vector<PadIdx_t> newPixelIdx;
1262 bool less;
1263 for (int i = 0; i < nPads; i++) {
1264 if (alreadyDone[i] == 0) {
1265 int nLess = 0;
1266 int count = 0;
1267 laplacian[i] = 0.0;
1268 weight[i] = 0.0;
1269 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1270 neigh_ptr++) {
1271 PadIdx_t v = *neigh_ptr;
1272 // Morphologic Laplacian
1273 // nLess += (q[v] < q[i]);
1274 less = (q[v] <= q[i]);
1275 count++;
1276 if (less) {
1277 nLess++;
1278 // Laplacian
1279 double cst;
1280 cst = (i == v) ? 1.0 : -0.25;
1281 laplacian[i] += cst * q[v];
1282 weight[i] += q[v];
1283 }
1284 }
1285 // Invalid ?? morphLaplacian[i] = double(nLess) / (count - 1);
1286 morphLaplacian[i] = double(nLess) / count;
1287 //
1289 printf(
1290 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1291 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1292 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1293 weight[i]);
1294 }
1295 if (morphLaplacian[i] >= 1.0) {
1296 // Local max charge must be higher than 1.5 % of the max and
1297 // the curvature must be greater than 50% of the peak
1298 // Inv ??? if ((q[i] > 0.015 * qMax) || (fabs(laplacian[i]) > (0.5 * q[i]))) {
1299 if (q[i] > 0.015 * qMax) {
1300 newPixelIdx.push_back(i);
1301 // if (clusterConfig.EMLocalMaxLog >= clusterConfig.info) {
1302 if (0) {
1303 printf(
1304 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1305 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1306 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1307 weight[i]);
1308 printf(" Selected %d\n", i);
1309 }
1310 }
1311 // Invalid the neihbors
1312 // they can't be a maximun
1313 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1314 neigh_ptr++) {
1315 PadIdx_t v = *neigh_ptr;
1316 alreadyDone[v] += 1;
1317 /*
1318 if (q[v] > 0.5 * q[i] ) {
1319 // Tag to be refined
1320 newPixelIdx.push_back(v);
1321
1322 }
1323 */
1324 }
1325 }
1326 }
1327 }
1328 //
1329 // Part II - Extract the local max
1330 //
1331 // Extract the new selected pixels
1332 int nNewPixels = newPixelIdx.size();
1333 // int indexInThePixel[nNewPixels];
1334 Pads* newPixels = new Pads(nNewPixels, chamberId);
1335 for (int i = 0; i < nNewPixels; i++) {
1336 newPixels->x[i] = x[newPixelIdx[i]];
1337 newPixels->y[i] = y[newPixelIdx[i]];
1338 newPixels->dx[i] = dx[newPixelIdx[i]];
1339 newPixels->dy[i] = dy[newPixelIdx[i]];
1340 newPixels->q[i] = q[newPixelIdx[i]];
1341 }
1342 Pads* localMax = nullptr;
1343 // Suppress local max. whose charge is less of 1%
1344 // of the max charge of local Max
1345 double cutRatio = 0.01;
1346 double qCut = cutRatio * vectorMax(newPixels->q, newPixels->nPads);
1347
1348 localMax = new Pads(nNewPixels, chamberId);
1349 localMax->setToZero();
1350
1351 int k0 = 0;
1352 printf(" q Cut-Off %f\n", qCut);
1353 for (int k = 0; k < nNewPixels; k++) {
1354 if (newPixels->q[k] > qCut) {
1355 localMax->q[k0] = newPixels->q[k];
1356 localMax->x[k0] = newPixels->x[k];
1357 localMax->y[k0] = newPixels->y[k];
1358 localMax->dx[k0] = newPixels->dx[k];
1359 localMax->dy[k0] = newPixels->dy[k];
1360 printf(" seed selected q=%8.2f, (x,y) = (%8.3f, %8.3f)\n",
1361 localMax->q[k0], localMax->x[k0], localMax->y[k0]);
1362 k0++;
1363 }
1364 }
1365 localMax->nPads = k0;
1366 localMax->nObsPads = k0;
1368 //
1369 // Part IV - Refine the charge and coordinates of the local max.
1370 //
1371 // Avoid taking the same charge for 2 different localMax
1372 // neigh = newPixels->buildFirstNeighbors();
1373 // printNeighbors( neigh, newPixels->getNbrOfPads());
1374 if (0) {
1375 Mask_t mask[nNewPixels];
1376 vectorSetShort(mask, 1, nNewPixels);
1377 int kSelected = 0;
1378 // ???
1379 qCut = 0.0;
1380
1381 for (int k = 0; k < nNewPixels; k++) {
1382 if (mask[k] == 1) {
1383 // Compute the charge barycenter
1384 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, k);
1385 *neigh_ptr != -1; neigh_ptr++) {
1386 PadIdx_t v = *neigh_ptr;
1387 localMax->q[k] += newPixels->q[v] * mask[v];
1388 localMax->x[k] += newPixels->x[v] * newPixels->q[v] * mask[v];
1389 localMax->y[k] += newPixels->y[v] * newPixels->q[v] * mask[v];
1390 mask[v] = 0;
1391 }
1392 // Select (or not) the local Max
1393 if (localMax->q[k] > qCut) {
1394 localMax->q[kSelected] = localMax->q[k];
1395 localMax->x[kSelected] = localMax->x[k] / localMax->q[k];
1396 localMax->y[kSelected] = localMax->y[k] / localMax->q[k];
1397 localMax->dx[kSelected] = newPixels->dx[k];
1398 localMax->dy[kSelected] = newPixels->dy[k];
1400 printf(" seed selected q=%8.2f, (x,y) = (%8.3f, %8.3f)\n",
1401 localMax->q[k], localMax->x[k], localMax->y[k]);
1402 }
1403 localMaxIdx.push_back(newPixelIdx[k]);
1404 kSelected++;
1405 }
1406 }
1407 }
1408
1409 for (int k = 0; k < nNewPixels; k++) {
1410 localMax->q[k] = newPixels->q[k];
1411 localMax->x[k] = newPixels->x[k];
1412 localMax->y[k] = newPixels->y[k];
1413 localMax->dx[k] = newPixels->dx[k];
1414 localMax->dy[k] = newPixels->dy[k];
1415 printf(" seed selected q=%8.2f, (x,y) = (%8.3f, %8.3f)\n",
1416 localMax->q[k], localMax->x[k], localMax->y[k]);
1417 }
1418 kSelected = nNewPixels;
1419 localMax->nPads = kSelected;
1420 localMax->nObsPads = kSelected;
1421 }
1422
1423 delete[] neighbors;
1424 neighbors = nullptr;
1425
1426 delete newPixels;
1427
1428 return localMax;
1429}
1430
1431// Assess or not if xyCheck is a remanent local Max (can be removed)
1432bool Pads::assessRemanent(double xyCheck, double* xy, double precision, int N)
1433{
1434 //
1435 double xyDiff[N];
1436 Mask_t mask[N];
1437 vectorAddScalar(xy, -xyCheck, N, xyDiff);
1438 // vectorPrint(" [assessRemanent] xy", xy, N);
1439 // vectorPrint(" [assessRemanent] xyDiff", xyDiff, N);
1440 vectorAbs(xyDiff, N, xyDiff);
1441 vectorBuildMaskLess(xyDiff, precision, N, mask);
1442 int nRemanents = vectorSumShort(mask, N);
1443 // One xyDiff is zero => nRemanents >= 1
1444 bool remanent = (nRemanents > 1) ? true : false;
1445 // printf(" [assessRemanent] xyCheck=%f precision=%f remanent=%d\n", xyCheck, precision, nRemanents);
1446 return remanent;
1447}
1448
1449Pads* Pads::extractLocalMaxOnCoarsePads_Remanent(std::vector<PadIdx_t>& localMaxIdx, double dxMinPadSize, double dyMinPadSize)
1450{
1452 printf(" - Pads::extractLocalMax on Coarse Pads(extractLocalMax nPads=%d)\n", nPads);
1453 }
1454 double qMax = vectorMax(q, nPads);
1455 //
1456 // TO DO ??? Compute the neighbors once
1457 // between to refinements
1458 if (neighbors != nullptr) {
1459 delete[] neighbors;
1460 }
1461 // 4(5) neighbors
1462 neighbors = getFirstNeighbors();
1463 PadIdx_t* neigh = neighbors;
1464 // printNeighbors( neigh, nPads);
1465 //
1466 // Part I - Morphologic Laplacian operator
1467 //
1468 double morphLaplacian[nPads];
1469 double laplacian[nPads];
1470 double weight[nPads];
1471 vectorSet(morphLaplacian, -1.0, nPads);
1472 // Invalid the neighbors of a local max
1473 Mask_t alreadyDone[nPads];
1474 vectorSetZeroShort(alreadyDone, nPads);
1475 std::vector<PadIdx_t> newPixelIdx;
1476 bool less;
1477 for (int i = 0; i < nPads; i++) {
1478 if (alreadyDone[i] == 0) {
1479 int nLess = 0;
1480 int count = 0;
1481 laplacian[i] = 0.0;
1482 weight[i] = 0.0;
1483 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1484 neigh_ptr++) {
1485 PadIdx_t v = *neigh_ptr;
1486 // Morphologic Laplacian
1487 // nLess += (q[v] < q[i]);
1488 less = (q[v] <= q[i]);
1489 count++;
1490 if (less) {
1491 nLess++;
1492 // Laplacian
1493 double cst;
1494 cst = (i == v) ? 1.0 : -0.25;
1495 laplacian[i] += cst * q[v];
1496 weight[i] += q[v];
1497 }
1498 }
1499 // Invalid ?? morphLaplacian[i] = double(nLess) / (count - 1);
1500 morphLaplacian[i] = double(nLess) / count;
1501 //
1503 printf(
1504 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1505 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1506 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1507 weight[i]);
1508 }
1509 if (morphLaplacian[i] >= 1.0) {
1510 // Local max charge must be higher than 1.5 % of the max and
1511 // the curvature must be greater than 50% of the peak
1512 // Inv ??? if ((q[i] > 0.015 * qMax) || (fabs(laplacian[i]) > (0.5 * q[i]))) {
1513 if (q[i] > 0.015 * qMax) {
1514 newPixelIdx.push_back(i);
1515 // if (clusterConfig.EMLocalMaxLog >= clusterConfig.info) {
1516 if (0) {
1517 printf(
1518 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1519 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1520 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1521 weight[i]);
1522 printf(" Selected %d\n", i);
1523 }
1524 }
1525 // Invalid the neihbors
1526 // they can't be a maximun
1527 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1528 neigh_ptr++) {
1529 PadIdx_t v = *neigh_ptr;
1530 alreadyDone[v] += 1;
1531 /*
1532 if (q[v] > 0.5 * q[i] ) {
1533 // Tag to be refined
1534 newPixelIdx.push_back(v);
1535
1536 }
1537 */
1538 }
1539 }
1540 }
1541 }
1542 //
1543 // Part II - Extract the local max
1544 //
1545 // Extract the new selected pixels
1546 int nNewPixels = newPixelIdx.size();
1547 // int indexInThePixel[nNewPixels];
1548 Pads* newPixels = new Pads(nNewPixels, chamberId);
1549 for (int i = 0; i < nNewPixels; i++) {
1550 newPixels->x[i] = x[newPixelIdx[i]];
1551 newPixels->y[i] = y[newPixelIdx[i]];
1552 newPixels->dx[i] = dx[newPixelIdx[i]];
1553 newPixels->dy[i] = dy[newPixelIdx[i]];
1554 newPixels->q[i] = q[newPixelIdx[i]];
1555 }
1556 Pads* localMax = nullptr;
1557 // Suppress local max. whose charge is less of 1%
1558 // of the max charge of local Max
1559 double cutRatio = 0.01;
1560 double qCut = cutRatio * vectorMax(newPixels->q, newPixels->nPads);
1561
1562 // Add pads / pixel to be refined.
1563 // They are neigbous of 2 or more local max
1564 /*
1565 for (int i = 0; i < nPads; i++) {
1566 if (alreadyDone[i] > 1) {
1567 newPixelIdx.push_back(i);
1568 printf("Other pad/pixel to be refined: i=%d x,y=(%7.2f,%7.2f) q=%8.1f \n", i, x[i], y[i], q[i]);
1569 }
1570 }
1571 */
1572
1573 //
1574 // Part III - suppress the remanent local max
1575 //
1577 printf(" [extractLocalMaxOnCoarsePads] Start suppressing remanent localMax: nbr Local Max [nNewPixels]=%d\n", nNewPixels);
1578 }
1579 int k0;
1580 if (nNewPixels > 3) {
1581 // ??? TODO: suppress the refinment to optimize
1582 localMax = new Pads(nNewPixels, chamberId);
1583 localMax->setToZero();
1584 // Sort local max by charge value
1585 // ??? visibly not used ???
1586 int index[nNewPixels];
1587 for (int k = 0; k < nNewPixels; k++) {
1588 index[k] = k;
1589 }
1590 std::sort(index, &index[nNewPixels], [=](int a, int b) {
1591 return (newPixels->q[a] > newPixels->q[b]);
1592 });
1593 // k0 describe the list of true local max (local max - remanent local max)
1594 // k0 number of true local max
1595 k0 = 0;
1596 for (int k = 0; k < nNewPixels; k++) {
1597 if (index[k] > -1) {
1598 // Store the true local max
1599 index[k0] = index[k];
1600 int idx0 = index[k0];
1601
1602 // Remove horizontal/vertical remanent local max
1603 double x0 = newPixels->x[idx0];
1604 double y0 = newPixels->y[idx0];
1606 printf(" Check remanent from loc.max k=%d, (x,y,q)= %f %f %f\n", k, x0, y0, newPixels->q[idx0]);
1607 }
1608 for (int l = k + 1; l < nNewPixels; l++) {
1609 if (index[l] > -1) {
1611 printf(" Case l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1612 }
1613
1614 bool sameX = (std::abs(newPixels->x[index[l]] - x0) < dxMinPadSize);
1615 bool sameY = (std::abs(newPixels->y[index[l]] - y0) < dyMinPadSize);
1616 if (sameX) {
1617 // Check in Y axe
1618 // Check other remanent loc max in y direction)
1619 // If founded : true remanent loc Max
1620 // if not a real remanent loc max (must be kept)
1621 bool realRemanent = assessRemanent(newPixels->y[index[l]], newPixels->y, dyMinPadSize, nNewPixels);
1622 if (realRemanent) {
1623 // Remanent local max: remove it
1624 // The local max absorb the charge of the remanent loc max newPixels->q[idx0] += newPixels->q[index[l]];
1625 // Remove the remanent
1627 printf(" XY-Remanent: remove l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1628 }
1629 index[l] = -1;
1630 }
1631 }
1632 if (sameY) {
1633 // Check in Y axe
1634 // Check other remanent loc max in y direction)
1635 // If founded : true remanent loc Max
1636 // if not a real remanent loc max (must be kept)
1637 bool realRemanent = assessRemanent(newPixels->x[index[l]], newPixels->x, dyMinPadSize, nNewPixels);
1638 if (realRemanent) {
1639 // Remanent local max: remove it
1640 // The local max absorb the charge of the remanent loc max
1641 newPixels->q[idx0] += newPixels->q[index[l]];
1642 // Remove the remanent
1644 printf(" YX-Remanent: remove l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1645 }
1646 index[l] = -1;
1647 }
1648 if ((sameX == 0) && (sameX == 0) && (clusterConfig.EMLocalMaxLog >= clusterConfig.info)) {
1649 printf(" Keep l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1650 }
1651 }
1652 }
1653 }
1654 k0++;
1655 }
1656 }
1658 for (int l = 0; l < k0; l++) {
1659 printf(" l=%d index[l]=%d (x, y, q)= %f %f %f\n", l, index[l], newPixels->getX()[index[l]], newPixels->getY()[index[l]], newPixels->getCharges()[index[l]]);
1660 }
1661 }
1662 // Clean the local Max - Remove definitely remanent local max
1663 delete localMax;
1664 localMax = newPixels->selectPads(index, k0);
1665 nNewPixels = k0;
1666 } else {
1667 if (localMax != nullptr) {
1668 delete localMax;
1669 }
1670 localMax = new Pads(*newPixels, PadMode::xydxdyMode);
1671 k0 = nNewPixels;
1672 }
1673
1674 if (0) {
1675 localMax = new Pads(nNewPixels, chamberId);
1676 localMax->setToZero();
1677 }
1679 //
1680 // Part IV - Refine the charge and coordinates of the local max.
1681 //
1682 // Avoid taking the same charge for 2 different localMax
1683 // neigh = newPixels->buildFirstNeighbors();
1684 // printNeighbors( neigh, newPixels->getNbrOfPads());
1685 if (0) {
1686 Mask_t mask[nNewPixels];
1687 vectorSetShort(mask, 1, nNewPixels);
1688 int kSelected = 0;
1689 // ???
1690 qCut = 0.0;
1691
1692 for (int k = 0; k < nNewPixels; k++) {
1693 if (mask[k] == 1) {
1694 // Compute the charge barycenter
1695 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, k);
1696 *neigh_ptr != -1; neigh_ptr++) {
1697 PadIdx_t v = *neigh_ptr;
1698 localMax->q[k] += newPixels->q[v] * mask[v];
1699 localMax->x[k] += newPixels->x[v] * newPixels->q[v] * mask[v];
1700 localMax->y[k] += newPixels->y[v] * newPixels->q[v] * mask[v];
1701 mask[v] = 0;
1702 }
1703 // Select (or not) the local Max
1704 if (localMax->q[k] > qCut) {
1705 localMax->q[kSelected] = localMax->q[k];
1706 localMax->x[kSelected] = localMax->x[k] / localMax->q[k];
1707 localMax->y[kSelected] = localMax->y[k] / localMax->q[k];
1708 localMax->dx[kSelected] = newPixels->dx[k];
1709 localMax->dy[kSelected] = newPixels->dy[k];
1711 printf(" seed selected q=%8.2f, (x,y) = (%8.3f, %8.3f)\n",
1712 localMax->q[k], localMax->x[k], localMax->y[k]);
1713 }
1714 localMaxIdx.push_back(newPixelIdx[k]);
1715 kSelected++;
1716 }
1717 }
1718 }
1719
1720 for (int k = 0; k < nNewPixels; k++) {
1721 localMax->q[k] = newPixels->q[k];
1722 localMax->x[k] = newPixels->x[k];
1723 localMax->y[k] = newPixels->y[k];
1724 localMax->dx[k] = newPixels->dx[k];
1725 localMax->dy[k] = newPixels->dy[k];
1726 printf(" seed selected q=%8.2f, (x,y) = (%8.3f, %8.3f)\n",
1727 localMax->q[k], localMax->x[k], localMax->y[k]);
1728 }
1729 kSelected = nNewPixels;
1730 localMax->nPads = kSelected;
1731 localMax->nObsPads = kSelected;
1732 }
1733
1734 delete[] neighbors;
1735 neighbors = nullptr;
1736
1737 delete newPixels;
1738
1739 return localMax;
1740}
1741
1742Pads* Pads::extractLocalMax(std::vector<PadIdx_t>& localMaxIdx, double dxMinPadSize, double dyMinPadSize)
1743{
1745 printf(" - Pads::extractLocalMax (extractLocalMax nPads=%d)\n", nPads);
1746 }
1747 double qMax = vectorMax(q, nPads);
1748 //
1749 // TO DO ??? Compute the neighbors once
1750 // between to refinements
1751 if (neighbors != nullptr) {
1752 delete[] neighbors;
1753 }
1754 // Kernel size of 1
1755 neighbors = buildKFirstsNeighbors(1);
1756 PadIdx_t* neigh = neighbors;
1757 // printNeighbors( neigh, nPads);
1758 //
1759 // Result of the Laplacian-like operator
1760 double morphLaplacian[nPads];
1761 double laplacian[nPads];
1762 double weight[nPads];
1763 vectorSet(morphLaplacian, -1.0, nPads);
1764 Mask_t alreadyDone[nPads];
1765 vectorSetZeroShort(alreadyDone, nPads);
1766 std::vector<PadIdx_t> newPixelIdx;
1767 bool less;
1768 for (int i = 0; i < nPads; i++) {
1769 if (alreadyDone[i] == 0) {
1770 int nLess = 0;
1771 int count = 0;
1772 laplacian[i] = 0.0;
1773 weight[i] = 0.0;
1774 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1775 neigh_ptr++) {
1776 PadIdx_t v = *neigh_ptr;
1777 // Morphologic Laplacian
1778 // nLess += (q[v] < q[i]);
1779 less = (q[v] <= q[i]);
1780 count++;
1781 if (less) {
1782 nLess++;
1783 // Laplacian
1784 double cst;
1785 cst = (i == v) ? 1.0 : -0.125;
1786 laplacian[i] += cst * q[v];
1787 weight[i] += q[v];
1788 }
1789 }
1790 // Invalid ?? morphLaplacian[i] = double(nLess) / (count - 1);
1791 morphLaplacian[i] = double(nLess) / count;
1792 //
1794 printf(
1795 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1796 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1797 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1798 weight[i]);
1799 }
1800 if (morphLaplacian[i] >= 1.0) {
1801 // Local max charge must be higher than 1.5 % of the max and
1802 // the curvature must be greater than 50% of the peak
1803 // Inv ??? if ((q[i] > 0.015 * qMax) || (fabs(laplacian[i]) > (0.5 * q[i]))) {
1804 if (q[i] > 0.015 * qMax) {
1805 newPixelIdx.push_back(i);
1806 // if (clusterConfig.EMLocalMaxLog >= clusterConfig.info) {
1807 if (0) {
1808 printf(
1809 " Laplacian i=%d, x=%6.3f, y=%6.3f, dx=%6.3f,dy=%6.3f, q=%6.3f, "
1810 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight=%6.3f",
1811 i, x[i], y[i], dx[i], dy[i], q[i], count, morphLaplacian[i], laplacian[i],
1812 weight[i]);
1813 printf(" Selected %d\n", i);
1814 }
1815 }
1816 // Invalid the neihbors
1817 // they can't be a maximun
1818 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
1819 neigh_ptr++) {
1820 PadIdx_t v = *neigh_ptr;
1821 alreadyDone[v] += 1;
1822 /*
1823 if (q[v] > 0.5 * q[i] ) {
1824 // Tag to be refined
1825 newPixelIdx.push_back(v);
1826
1827 }
1828 */
1829 }
1830 }
1831 }
1832 }
1833 //
1834 // Extract the new selected pixels
1835 int nNewPixels = newPixelIdx.size();
1836 // int indexInThePixel[nNewPixels];
1837 Pads* newPixels = new Pads(nNewPixels, chamberId);
1838 for (int i = 0; i < nNewPixels; i++) {
1839 newPixels->x[i] = x[newPixelIdx[i]];
1840 newPixels->y[i] = y[newPixelIdx[i]];
1841 newPixels->dx[i] = dx[newPixelIdx[i]];
1842 newPixels->dy[i] = dy[newPixelIdx[i]];
1843 newPixels->q[i] = q[newPixelIdx[i]];
1844 localMaxIdx.push_back(newPixelIdx[i]);
1845 }
1846 Pads* localMax = nullptr;
1847 // Suppress local max. whose charge is less of 1%
1848 // of the max charge of local Max
1849 double cutRatio = 0.01;
1850 double qCut = cutRatio * vectorMax(newPixels->q, newPixels->nPads);
1851
1852 // Add pads / pixel to be refined.
1853 // They are neigbous of 2 or more local max
1854 /*
1855 for (int i = 0; i < nPads; i++) {
1856 if (alreadyDone[i] > 1) {
1857 newPixelIdx.push_back(i);
1858 printf("Other pad/pixel to be refined: i=%d x,y=(%7.2f,%7.2f) q=%8.1f \n", i, x[i], y[i], q[i]);
1859 }
1860 }
1861 */
1862
1863 //
1864 // Part III - suppress the remanent local max
1865 //
1867 printf(" [extractLocalMax] (medium pads) Starting suppressing remanent Loc. Max nNewPixels=%d\n", nNewPixels);
1868 }
1869 int k0;
1870 std::vector<int> newPixelIdx2;
1871
1872 // if ( (nNewPixels > 3) && ( (dxMinPadSize > 3.5) || (dyMinPadSize > 3.5) )) {
1873 if ((nNewPixels > 3) && ((dxMinPadSize > 2.4) || (dyMinPadSize > 2.4))) {
1874 // ??? TODO: suppress the refinment to optimize
1875 localMax = new Pads(nNewPixels, chamberId);
1876 localMax->setToZero();
1877 // Sort local max by charge value
1878 // ??? visibly not used ???
1879 int index[nNewPixels];
1880 for (int k = 0; k < nNewPixels; k++) {
1881 index[k] = k;
1882 }
1883 std::sort(index, &index[nNewPixels], [=](int a, int b) {
1884 return (newPixels->q[a] > newPixels->q[b]);
1885 });
1886 // k0 describe the list of true local max (local max - remanent local max)
1887 // k0 number of true local max
1888 k0 = 0;
1889 // vectorPrintInt("Index", index, nNewPixels);
1890 // Pads::printPads("local max", *newPixels);
1891
1892 for (int k = 0; k < nNewPixels; k++) {
1893 if (index[k] > -1) {
1894 // Store the true local max
1895 index[k0] = index[k];
1896 int idx0 = index[k0];
1897
1898 // Remove horizontal/vertical remanent local max
1899 double x0 = newPixels->x[idx0];
1900 double y0 = newPixels->y[idx0];
1901 double dx0 = newPixels->dx[idx0];
1902 double dy0 = newPixels->dy[idx0];
1904 printf(" Remanent from loc max k=%d, (x,y,q)= %f %f %f (dx, dy)= (%f, %f)\n", k, x0, y0, newPixels->q[idx0], dx0, dy0);
1905 }
1906 for (int l = k + 1; l < nNewPixels; l++) {
1907 if (index[l] > -1) {
1908 double dx_ = 0.5 * (dx0 + newPixels->dx[index[l]]);
1909 double dy_ = 0.5 * (dy0 + newPixels->dy[index[l]]);
1910 bool sameX = (std::abs(newPixels->x[index[l]] - x0) < dx_);
1911 bool sameY = (std::abs(newPixels->y[index[l]] - y0) < dy_);
1912 // printf(" Remanent: precision l=%d, (dx,dy)= %f %f \n", l, dx_, dy_ );
1913 if (sameX) {
1914 // Check in Y axe
1915 // Check other remanent loc max in y direction)
1916 // If founded : true remanent loc Max
1917 // if not a real remanent loc max (must be kept)
1918 bool realRemanent = assessRemanent(newPixels->y[index[l]], newPixels->y, dy_, nNewPixels);
1919 if (realRemanent) {
1920 // Remanent local max: remove it
1921 // The local max absorb the charge of the remanent loc max newPixels->q[idx0] += newPixels->q[index[l]];
1922 // Remove the remanent
1924 printf(" XY-Remanent: remove l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1925 }
1926 index[l] = -1;
1927 }
1928 }
1929 if (sameY) {
1930 // Check in Y axe
1931 // Check other remanent loc max in y direction)
1932 // If founded : true remanent loc Max
1933 // if not a real remanent loc max (must be kept)
1934 bool realRemanent = assessRemanent(newPixels->x[index[l]], newPixels->x, dx_, nNewPixels);
1935 if (realRemanent) {
1936 // Remanent local max: remove it
1937 // The local max absorb the charge of the remanent loc max
1938 newPixels->q[idx0] += newPixels->q[index[l]];
1939 // Remove the remanent
1941 printf(" YX-Remanent: remove l=%d, (x,y,q)= %f %f %f\n", l, newPixels->x[index[l]], newPixels->y[index[l]], newPixels->q[index[l]]);
1942 }
1943 index[l] = -1;
1944 }
1945 }
1946 }
1947 }
1948 k0++;
1949 }
1950 }
1952 printf(" Local. max status before to suppress remanents\n");
1953 for (int l = 0; l < k0; l++) {
1954 printf(" l=%d index[l]=%d (x, y, q)= %f %f %f\n", l, index[l], newPixels->getX()[index[l]], newPixels->getY()[index[l]], newPixels->getCharges()[index[l]]);
1955 }
1956 }
1957
1958 // Clean the local Max - Remove definitely remanent local max
1959 if (localMax != nullptr) {
1960 delete localMax;
1961 }
1962 localMax = newPixels->selectPads(index, k0);
1963 // Update newPixelIdx
1964 if (1) {
1965 for (int l = 0; l < k0; l++) {
1966 int idx = index[l];
1967 newPixelIdx2.push_back(newPixelIdx[idx]);
1968 // Debug
1969 // printf(" newPixelIdx2 l=%d index[l]=%d (x, y, q)= %f %f %f\n", l, index[l], x[newPixelIdx[l]], y[newPixelIdx[l]], q[newPixelIdx[l]]);
1970 }
1971 }
1972 nNewPixels = k0;
1973 } else {
1974 // Copy newPixels -> localMax
1975 localMax = new Pads(*newPixels, PadMode::xydxdyMode);
1976 k0 = nNewPixels;
1977 newPixelIdx2 = newPixelIdx;
1978 }
1979
1980 /*
1981 //
1982 // Refine the charge and coordinates of the local max.
1983 //
1984 // ??? TODO: suppress te refinment to optimize
1985 localMax = new Pads(nNewPixels, chamberId);
1986 localMax->setToZero();
1987 // Sort local max by charge value
1988 int index[nNewPixels];
1989 for (int k = 0; k < nNewPixels; k++) {
1990 index[k] = k;
1991 }
1992 // ??? visibly not used ???
1993 std::sort(index, &index[nNewPixels], [=](int a, int b) {
1994 return (newPixels->q[a] > newPixels->q[b]);
1995 });
1996 */
1997
1999 // Avoid taking the same charge for 2 different localMax
2000 // Add the local max in list (to be refined)
2001
2002 // Unused
2003 // Mask_t mask[nNewPixels];
2004 // vectorSetShort(mask, 1, nNewPixels);
2005 int kSelected = 0;
2006 for (int l = 0; l < nNewPixels; l++) {
2007 PadIdx_t pixelIdx = newPixelIdx2[l];
2008 // Unused
2009 // if (mask[k] == 1) {
2010 // Compute the charge barycenter
2011 localMax->q[l] = 0.0;
2012 localMax->x[l] = 0.0;
2013 localMax->y[l] = 0.0;
2014 int nNeigh = 0;
2015 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, pixelIdx);
2016 *neigh_ptr != -1; neigh_ptr++) {
2017 PadIdx_t v = *neigh_ptr;
2018 localMax->q[l] += q[v]; // * mask[v];
2019 localMax->x[l] += x[v] * q[v]; // * mask[v];
2020 localMax->y[l] += y[v] * q[v]; // * mask[v];
2021 // Unused
2022 // mask[v] = 0;
2023 nNeigh++;
2024 }
2025 // Select (or not) the local Max
2026 if (localMax->q[l] > qCut) {
2027
2028 localMax->x[kSelected] = localMax->x[l] / localMax->q[l];
2029 localMax->y[kSelected] = localMax->y[l] / localMax->q[l];
2030 localMax->q[kSelected] = localMax->q[l] / nNeigh;
2031 localMax->dx[kSelected] = dx[pixelIdx];
2032 localMax->dy[kSelected] = dy[pixelIdx];
2034 printf(" [extractLocalMax] final seed selected (x,y) = (%8.3f, %8.3f), q=%8.2f\n",
2035 localMax->x[l], localMax->y[l], localMax->q[l]);
2036 }
2037 // localMaxIdx.push_back( pixelIdx );
2038 kSelected++;
2039 }
2040 // Unused }
2041 }
2042 localMax->nPads = kSelected;
2043 localMax->nObsPads = kSelected;
2044
2045 // Add high charge neighbors to be refined
2046 if (0) {
2047 for (int k = 0; k < nNewPixels; k++) {
2048 // Compute the charge barycenter
2049 PadIdx_t idxMax = newPixelIdx[k];
2050 for (PadIdx_t* neigh_ptr = getNeighborListOf(neighbors, idxMax);
2051 *neigh_ptr != -1; neigh_ptr++) {
2052 PadIdx_t v = *neigh_ptr;
2053 if ((q[v] > 0.5 * q[idxMax]) && (q[v] > clusterConfig.minChargeOfClusterPerCathode)) {
2054 // Tag to be refined
2055 localMaxIdx.push_back(v);
2056 printf("??? neigbors of idMax=%d: %d to be refined (charge %f/%f)\n", idxMax, v, q[v], q[idxMax]);
2057 // Inv printf("x,y : %f %f \n", x[v], y[v]);
2058 }
2059 }
2060 }
2061 }
2062
2063 delete[] neighbors;
2064 neighbors = nullptr;
2065 delete newPixels;
2066
2067 return localMax;
2068}
2069
2070Pads* Pads::clipOnLocalMax(bool extractLocalMax)
2071{
2072 // Option extractLocalMax
2073 // - true: extraxt local maxima
2074 // - false: filter pixels arround the maxima
2076 printf(" - ClipOnLocalMax (extractLocalMax Flag=%d, nPads=%d)\n",
2077 extractLocalMax, nPads);
2078 }
2079 double eps = epsilonGeometry;
2080 // relativeNoise unused (set to 0)
2081 double relativeNoise = 0.00;
2082 double qMax = vectorMax(q, nPads);
2083 double cutoff;
2084 // Compute the neighbors once
2085 if ((neighbors == nullptr) && extractLocalMax) {
2086 // Kernel size of 1
2087 neighbors = buildKFirstsNeighbors(1);
2088 } else if (neighbors == nullptr) {
2089 neighbors = buildKFirstsNeighbors(2);
2090 }
2091 PadIdx_t* neigh = neighbors;
2092 //
2093 // Result of the Laplacian-like operator
2094 double morphLaplacian[nPads];
2095 double laplacian[nPads];
2096 double weight[nPads];
2097 vectorSet(morphLaplacian, -1.0, nPads);
2098 Mask_t alreadySelect[nPads];
2099 vectorSetZeroShort(alreadySelect, nPads);
2100 std::vector<PadIdx_t> newPixelIdx;
2101 for (int i = 0; i < nPads; i++) {
2102 int nLess = 0;
2103 int count = 0;
2104 laplacian[i] = 0.0;
2105 weight[i] = 0.0;
2106 cutoff = relativeNoise * q[i];
2107 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i); *neigh_ptr != -1;
2108 neigh_ptr++) {
2109 PadIdx_t v = *neigh_ptr;
2110 // Morphologic Laplacian
2111 nLess += (q[v] < (q[i] - cutoff));
2112 count++;
2113 // Laplacian
2114 double cst;
2115 cst = (i == v) ? 1.0 : -0.125;
2116 laplacian[i] += cst * q[v];
2117 weight[i] += q[v];
2118 }
2119 morphLaplacian[i] = double(nLess) / (count - 1);
2120 //
2122 printf(
2123 " Laplacian i=%d, x[i]=%6.3f, y[i]=%6.3f, z[i]=%6.3f, count=%d, "
2124 "morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight[i]=%6.3f\n",
2125 i, x[i], y[i], q[i], count, morphLaplacian[i], laplacian[i],
2126 weight[i]);
2127 }
2128 if (morphLaplacian[i] >= 1.0) {
2129 if (extractLocalMax) {
2130 // Local max charge must be higher than 1.5 % of the max and
2131 // the curvature must be greater than 50% of the peak
2132 if ((q[i] > 0.015 * qMax) || (fabs(laplacian[i]) > (0.5 * q[i]))) {
2133 newPixelIdx.push_back(i);
2135 printf(
2136 " Laplacian i=%d, x[i]=%6.3f, y[i]=%6.3f, z[i]=%6.3f, "
2137 "count=%d, morphLapl[i]=%6.3f, lapl[i]=%6.3f, weight[i]=%6.3f",
2138 i, x[i], y[i], q[i], count, morphLaplacian[i], laplacian[i],
2139 weight[i]);
2140 printf(" Selected %d\n", i);
2141 }
2142 }
2143 } else {
2144 // Select as new pixels in the vinicity of the local max
2146 printf(" Selected neighbors of i=%d: ", i);
2147 }
2148 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i);
2149 *neigh_ptr != -1; neigh_ptr++) {
2150 PadIdx_t v = *neigh_ptr;
2151 if (alreadySelect[v] == 0) {
2152 alreadySelect[v] = 1;
2153 newPixelIdx.push_back(v);
2155 printf("%d, ", v);
2156 }
2157 }
2158 }
2160 printf("\n");
2161 }
2162 }
2163 }
2164 }
2165 // Extract the new selected pixels
2166 int nNewPixels = newPixelIdx.size();
2167 Pads* newPixels = new Pads(nNewPixels, chamberId);
2168 for (int i = 0; i < nNewPixels; i++) {
2169 newPixels->x[i] = x[newPixelIdx[i]];
2170 newPixels->y[i] = y[newPixelIdx[i]];
2171 newPixels->dx[i] = dx[newPixelIdx[i]];
2172 newPixels->dy[i] = dy[newPixelIdx[i]];
2173 newPixels->q[i] = q[newPixelIdx[i]];
2174 }
2175 Pads* localMax = nullptr;
2176 if (extractLocalMax) {
2177 // Suppress local max. whose charge is less of 1% of the max charge of local
2178 // Max
2179 double cutRatio = 0.01;
2180 double qCut = cutRatio * vectorMax(newPixels->q, newPixels->nPads);
2181 //
2182 // Refine the charge and coordinates of the local max.
2183 //
2184 // ??? TODO: suppress te refinment to optimize
2185 localMax = new Pads(nNewPixels, chamberId);
2186 localMax->setToZero();
2187 // Sort local max by charge value
2188 int index[nNewPixels];
2189 for (int k = 0; k < nNewPixels; k++) {
2190 index[k] = k;
2191 }
2192 std::sort(index, &index[nNewPixels], [=](int a, int b) {
2193 return (newPixels->q[a] > newPixels->q[b]);
2194 });
2196 neigh = newPixels->buildKFirstsNeighbors(1);
2197 // Avoid taking the same charge for 2 different localMax
2198 Mask_t mask[nNewPixels];
2199 vectorSetShort(mask, 1, nNewPixels);
2200 int kSelected = 0;
2201 for (int k = 0; k < nNewPixels; k++) {
2202 if (mask[k] == 1) {
2203 for (PadIdx_t* neigh_ptr = getNeighborListOf(neigh, k);
2204 *neigh_ptr != -1; neigh_ptr++) {
2205 PadIdx_t v = *neigh_ptr;
2206 localMax->q[k] += newPixels->q[v] * mask[v];
2207 localMax->x[k] += newPixels->x[v] * newPixels->q[v] * mask[v];
2208 localMax->y[k] += newPixels->y[v] * newPixels->q[v] * mask[v];
2209 mask[v] = 0;
2210 }
2211 if (localMax->q[k] > qCut) {
2212 localMax->q[kSelected] = localMax->q[k];
2213 localMax->x[kSelected] = localMax->x[k] / localMax->q[k];
2214 localMax->y[kSelected] = localMax->y[k] / localMax->q[k];
2215 localMax->dx[kSelected] = newPixels->dx[k];
2216 localMax->dy[kSelected] = newPixels->dy[k];
2218 printf(" add a seed q=%9.4f, (x,y) = (%9.4f, %9.4f)\n",
2219 localMax->q[k], localMax->x[k], localMax->q[k]);
2220 }
2221 kSelected++;
2222 }
2223 }
2224 }
2225 localMax->nPads = kSelected;
2226 localMax->nObsPads = kSelected;
2227 }
2228 delete[] neigh;
2229 if (extractLocalMax) {
2230 delete newPixels;
2231 return localMax;
2232 } else {
2233 return newPixels;
2234 }
2235}
2236
2237void Pads::printNeighbors(const PadIdx_t* neigh, int N)
2238{
2239 printf("Neighbors %d\n", N);
2240 for (int i = 0; i < N; i++) {
2241 printf(" neigh of i=%2d: ", i);
2242 for (const PadIdx_t* neigh_ptr = getNeighborListOf(neigh, i);
2243 *neigh_ptr != -1; neigh_ptr++) {
2244 PadIdx_t j = *neigh_ptr;
2245 printf("%d, ", j);
2246 }
2247 printf("\n");
2248 }
2249}
2250
2251void Pads::printPads(const char* title, const Pads& pads)
2252{
2253 printf("%s\n", title);
2254 printf("print pads nPads=%4d nObsPads=%4d mode=%1d\n", pads.nPads, pads.nObsPads, (int)pads.mode);
2255 if (pads.mode == PadMode::xydxdyMode) {
2256 printf(" i x y dx dy q\n");
2257 for (int i = 0; i < pads.nPads; i++) {
2258 printf(" %3d %7.3f %7.3f %7.3f %7.3f %9.2f\n", i,
2259 pads.x[i], pads.dx[i], pads.y[i], pads.dy[i], pads.q[i]);
2260 }
2261 } else {
2262 printf(" i xInf xSup yInf ySup q\n");
2263 for (int i = 0; i < pads.nPads; i++) {
2264 printf(" %3d %7.3f %7.3f %7.3f %7.3f %9.2f\n",
2265 i, pads.x[i], pads.dx[i], pads.y[i], pads.dy[i], pads.q[i]);
2266 }
2267 }
2268 // Invalid
2269 // } else {
2270 // printf("%s can't print nullptr\n", title);
2271 // }
2272}
2273
2274Pads::~Pads() { release(); }
2275
2276} // namespace mch
2277} // namespace o2
int32_t i
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
const double * getX() const
Definition PadsPEM.h:91
double getMeanTotalCharge()
Definition PadsPEM.cxx:764
static void printNeighbors(const PadIdx_t *neigh, int N)
Definition PadsPEM.cxx:2237
PadMode mode
Definition PadsPEM.h:58
const double * getXSup() const
Definition PadsPEM.h:97
int getChamberId() const
Definition PadsPEM.h:106
Pads(int N, int chId, PadMode mode=PadMode::xydxdyMode)
Definition PadsPEM.cxx:354
void refineLocalMaxAndUpdateCij(const Pads &pads, std::vector< PadIdx_t > &localMaxIdx, double Cij[])
Definition PadsPEM.cxx:965
@ xydxdyMode
x, y, dx, dy pad coordinates
@ xyInfSupMode
xInf=x, xSup=dx, yInf=y, ySup=dy pad coordinates
void setCathodes(Mask_t cath_)
Definition PadsPEM.cxx:790
Pads * extractLocalMax(std::vector< PadIdx_t > &localMaxIdx, double dxMinPadSize, double dyMinPadSize)
Definition PadsPEM.cxx:1742
static int getNbrOfPads(const Pads *pads)
Definition PadsPEM.h:63
void setSaturate(Mask_t val)
Definition PadsPEM.cxx:792
Pads * refineAll()
Definition PadsPEM.cxx:1170
void setCharges(double c)
Definition PadsPEM.cxx:778
int addIsolatedPadInGroups(Mask_t *cathToGrp, Mask_t *grpToGrp, int nGroups)
Definition PadsPEM.cxx:847
const double * getCharges() const
Definition PadsPEM.h:99
Pads * selectPads(int *index, int k)
Definition PadsPEM.cxx:658
Pads * extractLocalMaxOnCoarsePads(std::vector< PadIdx_t > &localMaxIdx)
Definition PadsPEM.cxx:1235
void refineLocalMax(Pads &localMax, std::vector< PadIdx_t > &localMaxIdx)
Definition PadsPEM.cxx:1081
const double * getYInf() const
Definition PadsPEM.h:96
const double * getY() const
Definition PadsPEM.h:92
Pads * addBoundaryPads()
Definition PadsPEM.cxx:193
Pads * extractLocalMaxOnCoarsePads_Remanent(std::vector< PadIdx_t > &localMaxIdx, double dxMinPadSize, double dyMinPadSize)
Definition PadsPEM.cxx:1449
const double * getXInf() const
Definition PadsPEM.h:95
void normalizeCharges()
Definition PadsPEM.cxx:830
void padCenterToBounds()
Definition PadsPEM.cxx:69
PadIdx_t * getFirstNeighbors()
Definition PadsPEM.cxx:838
PadIdx_t * buildKFirstsNeighbors(int kernelSize)
Definition PadsPEM.cxx:139
void padBoundsToCenter()
Definition PadsPEM.cxx:89
Pads * clipOnLocalMax(bool extractLocalMax)
Definition PadsPEM.cxx:2070
double updateTotalCharge()
Definition PadsPEM.cxx:758
static constexpr double epsilonGeometry
Definition PadsPEM.h:54
int removePads(double qCut)
Definition PadsPEM.cxx:805
const double * getYSup() const
Definition PadsPEM.h:98
static void printPads(const char *title, const Pads &pads)
Definition PadsPEM.cxx:2251
#define CHECK
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum mode
Definition glcorearb.h:266
GLint GLsizei count
Definition glcorearb.h:399
GLsizeiptr size
Definition glcorearb.h:659
const GLdouble * v
Definition glcorearb.h:832
GLuint index
Definition glcorearb.h:781
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLfloat x0
Definition glcorearb.h:5034
GLboolean GLboolean g
Definition glcorearb.h:1233
GLuint GLfloat * val
Definition glcorearb.h:1582
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint GLuint mask
Definition glcorearb.h:291
GLenum GLint GLint * precision
Definition glcorearb.h:1899
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
void vectorPrintShort(const char *str, const short *x, int K)
Definition mathUtil.cxx:43
void compute1DPadIntegrals(const double *xyInf, const double *xySup, int N, double xy0, int axe, int chamberId, double *integrals)
short Mask_t
void vectorPrint(const char *str, const double *x, int K)
Definition mathUtil.cxx:20
void deleteInt(int *ptr)
Definition mathUtil.h:532
ClusterConfig clusterConfig
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
@ info
Describes main steps and high level behaviors.
@ detail
Describes in detail.