Project
Loading...
Searching...
No Matches
ClusterPEM.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
17
18#include <cstdio>
19#include <stdexcept>
20#include <cmath>
21#include <iostream>
22
26#include "InspectModel.h"
27#include "mathUtil.h"
28#include "mathieson.h"
29#include "mathiesonFit.h"
30#include "poissonEM.h"
31
32namespace o2
33{
34namespace mch
35{
36
37extern ClusterConfig clusterConfig;
38
39// Fit parameters
40// doProcess = verbose + (doJacobian << 2) + ( doKhi << 3) + (doStdErr << 4)
41static const int processFitVerbose = 1 + (0 << 2) + (1 << 3) + (1 << 4);
42static const int processFit = 0 + (0 << 2) + (1 << 3) + (1 << 4);
43
44double epsilonGeometry = 1.0e-4;
45
62typedef double realtype;
63
64void print_matrix(const gsl_matrix* m)
65{
66 size_t i, j;
67
68 for (i = 0; i < m->size1; i++) {
69 for (j = 0; j < m->size2; j++) {
70 printf("%f\t", gsl_matrix_get(m, i, j));
71 }
72 printf("\n");
73 }
74}
75
76void printGSLVector(const char* str, const gsl_vector* v)
77{
78 int N = v->size;
79 int nPackets = N / 10 + 1;
80 printf("%s dim=%d nPackets=%d\n ", str, N, nPackets);
81 for (int i = 0; i < nPackets; i++) {
82 for (int k = 0; (k < 10) && ((i * 10 + k) < N); k++) {
83 printf("%f ", gsl_vector_get(v, i * 10 + k));
84 }
85 printf("\n");
86 }
87 printf("\n");
88}
89
100gsl_matrix* moore_penrose_pinv(gsl_matrix* A, const realtype rcond)
101{
102
103 gsl_matrix *V, *Sigma_pinv, *U, *A_pinv;
104 gsl_matrix* _tmp_mat = nullptr;
105 gsl_vector* _tmp_vec;
106 gsl_vector* u;
107 realtype x, cutoff;
108 size_t i, j;
109 unsigned int n = A->size1;
110 unsigned int m = A->size2;
111 bool was_swapped = false;
112
113 if (m > n) {
114 /* libgsl SVD can only handle the case m <= n - transpose matrix */
115 was_swapped = true;
116 _tmp_mat = gsl_matrix_alloc(m, n);
117 gsl_matrix_transpose_memcpy(_tmp_mat, A);
118 A = _tmp_mat;
119 i = m;
120 m = n;
121 n = i;
122 }
123
124 /* do SVD */
125 V = gsl_matrix_alloc(m, m);
126 u = gsl_vector_alloc(m);
127 _tmp_vec = gsl_vector_alloc(m);
128 gsl_linalg_SV_decomp(A, V, u, _tmp_vec);
129 gsl_vector_free(_tmp_vec);
130
131 /* compute ??? */
132 Sigma_pinv = gsl_matrix_alloc(m, n);
133 gsl_matrix_set_zero(Sigma_pinv);
134 cutoff = rcond * gsl_vector_max(u);
135
136 for (i = 0; i < m; ++i) {
137 if (gsl_vector_get(u, i) > cutoff) {
138 x = 1. / gsl_vector_get(u, i);
139 } else {
140 x = 0.;
141 }
142 gsl_matrix_set(Sigma_pinv, i, i, x);
143 }
144
145 /* libgsl SVD yields "thin" SVD - pad to full matrix by adding zeros */
146 U = gsl_matrix_alloc(n, n);
147 gsl_matrix_set_zero(U);
148
149 for (i = 0; i < n; ++i) {
150 for (j = 0; j < m; ++j) {
151 gsl_matrix_set(U, i, j, gsl_matrix_get(A, i, j));
152 }
153 }
154
155 if (_tmp_mat != nullptr) {
156 gsl_matrix_free(_tmp_mat);
157 }
158
159 /* two dot products to obtain pseudoinverse */
160 _tmp_mat = gsl_matrix_alloc(m, n);
161 gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1., V, Sigma_pinv, 0., _tmp_mat);
162
163 if (was_swapped) {
164 A_pinv = gsl_matrix_alloc(n, m);
165 gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1., U, _tmp_mat, 0., A_pinv);
166 } else {
167 A_pinv = gsl_matrix_alloc(m, n);
168 gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1., _tmp_mat, U, 0., A_pinv);
169 }
170
171 gsl_matrix_free(_tmp_mat);
172 gsl_matrix_free(U);
173 gsl_matrix_free(Sigma_pinv);
174 gsl_vector_free(u);
175 gsl_matrix_free(V);
176
177 return A_pinv;
178}
179
180int main()
181{
182
183 const unsigned int N = 2;
184 const unsigned int M = 3;
185 const realtype rcond = 1E-15;
186
187 gsl_matrix* A = gsl_matrix_alloc(N, M);
188 gsl_matrix* A_pinv;
189
190 gsl_matrix_set(A, 0, 0, 1.);
191 gsl_matrix_set(A, 0, 1, 3.);
192 gsl_matrix_set(A, 0, 2, 5.);
193 gsl_matrix_set(A, 1, 0, 2.);
194 gsl_matrix_set(A, 1, 1, 4.);
195 gsl_matrix_set(A, 1, 2, 6.);
196
197 printf("A matrix:\n");
199 A_pinv = moore_penrose_pinv(A, rcond);
200 printf("\nPseudoinverse of A:\n");
201 print_matrix(A_pinv);
202
203 gsl_matrix_free(A);
204 gsl_matrix_free(A_pinv);
205
206 return 0;
207}
208
209ClusterPEM::ClusterPEM() = default;
210
212{
213 int nPlanes = 0;
214 singleCathPlaneID = -1;
215 if (pads0 != nullptr) {
216 pads[nPlanes] = pads0;
217 nPlanes++;
218 } else {
219 singleCathPlaneID = 1;
220 }
221 if (pads1 != nullptr) {
222 pads[nPlanes] = pads1;
223 nPlanes++;
224 } else {
225 singleCathPlaneID = 0;
226 }
227 nbrOfCathodePlanes = nPlanes;
228}
229
230ClusterPEM::ClusterPEM(const double* x, const double* y, const double* dx,
231 const double* dy, const double* q, const short* cathodes,
232 const short* saturated, int chId, int nPads)
233{
234
235 chamberId = chId;
236 nbrSaturated = vectorSumShort(saturated, nPads);
237
238 int nbrCath1 = vectorSumShort(cathodes, nPads);
239 int nbrCath0 = nPads - nbrCath1;
240
241 // Build the pads for each cathode
242 int nCath = 0;
243 if (nbrCath0 != 0) {
244 mapCathPadIdxToPadIdx[0] = new PadIdx_t[nbrCath0];
245 pads[0] = new Pads(x, y, dx, dy, q, cathodes, saturated, 0, chId,
246 mapCathPadIdxToPadIdx[0], nPads);
247 singleCathPlaneID = 0;
248 nCath += 1;
249 }
250 if (nbrCath1 != 0) {
251 mapCathPadIdxToPadIdx[1] = new PadIdx_t[nbrCath1];
252 pads[1] = new Pads(x, y, dx, dy, q, cathodes, saturated, 1, chId,
253 mapCathPadIdxToPadIdx[1], nPads);
254 singleCathPlaneID = 1;
255 nCath += 1;
256 }
257 // Number of cathodes & alone cathode
258 nbrOfCathodePlanes = nCath;
259 if (nbrOfCathodePlanes == 2) {
260 singleCathPlaneID = -1;
261 }
262 // ??? To remove if default Constructor
263 // Projection
264 projectedPads = nullptr;
265 // Invalid projNeighbors = nullptr;
266 projPadToGrp = nullptr;
267 nbrOfProjGroups = 0;
268 // Groups
269 cathGroup[0] = nullptr;
270 cathGroup[1] = nullptr;
271 nbrOfCathGroups = 0;
272 // Geometry
273 IInterJ = nullptr;
274 JInterI = nullptr;
275 mapKToIJ = nullptr;
276 mapIJToK = nullptr;
277 aloneIPads = nullptr;
278 aloneJPads = nullptr;
279 aloneKPads = nullptr;
280
281 //
283 printf("-----------------------------\n");
284 printf("Starting CLUSTER PROCESSING\n");
285 printf("# cath0=%2d, cath1=%2d\n", nbrCath0, nbrCath1);
286 printf("# sum Q0=%7.3g, sum Q1=%7.3g\n",
287 (pads[0]) ? pads[0]->getTotalCharge() : 0,
288 (pads[1]) ? pads[1]->getTotalCharge() : 0);
289 printf("# singleCathPlaneID=%2d\n", singleCathPlaneID);
290 }
291}
292
293// Extract the subcluster g
295{
296 chamberId = cluster.chamberId;
297 int nbrCath[2] = {0, 0};
298 nbrCath[0] = (cluster.pads[0]) ? cluster.pads[0]->getNbrOfPads() : 0;
299 nbrCath[1] = (cluster.pads[1]) ? cluster.pads[1]->getNbrOfPads() : 0;
300 //
301 // Extract the pads of group g
302 //
303 Mask_t maskGrpCath0[nbrCath[0]];
304 Mask_t maskGrpCath1[nbrCath[1]];
305 Mask_t* maskGrpCath[2] = {maskGrpCath0, maskGrpCath1};
306 int nbrCathPlanes_ = 0;
307 int singleCathPlaneID_ = -1;
308 for (int c = 0; c < 2; c++) {
309 // Build the mask mapping the group g
310 int nbrPads = 0;
311 if (nbrCath[c]) {
312 nbrPads = vectorBuildMaskEqualShort(cluster.cathGroup[c], g,
313 cluster.pads[c]->getNbrOfPads(),
314 maskGrpCath[c]);
315 }
316 // inv ??? printf("??? pads in the same group cathode c=%d \n", c);
317 // inv ??? vectorPrintShort("??? maskGrpCath[c]", maskGrpCath[c], cluster.pads[c]->getNbrOfPads());
318 if (nbrPads != 0) {
319 // Create the pads of the group g
320 pads[c] = new Pads(*cluster.pads[c], maskGrpCath[c]);
321 nbrCathPlanes_++;
322 singleCathPlaneID_ = c;
323 }
324 }
325 nbrOfCathodePlanes = nbrCathPlanes_;
326 if (nbrCathPlanes_ != 2) {
327 singleCathPlaneID = singleCathPlaneID_;
328 }
329
330 //
331 // Extract the projected pads belonging to the group g
332 //
333
334 // Build the group-mask for proj pads
335 Mask_t maskProjGrp[cluster.projectedPads->getNbrOfPads()];
336 int nbrOfProjPadsInTheGroup = vectorBuildMaskEqualShort(
337 cluster.projPadToGrp, g, cluster.projectedPads->getNbrOfPads(),
338 maskProjGrp);
339 projectedPads = new Pads(*cluster.projectedPads, maskProjGrp);
340}
341
343{
344 for (int c = 0; c < 2; c++) {
345 if (pads[c] != nullptr) {
346 delete pads[c];
347 pads[c] = nullptr;
348 }
349 deleteInt(mapCathPadIdxToPadIdx[c]);
350 deleteShort(cathGroup[c]);
351 }
352 if (projectedPads != nullptr) {
353 delete projectedPads;
354 projectedPads = nullptr;
355 }
356 // Invalid deleteInt(projNeighbors);
357 deleteShort(projPadToGrp);
358 deleteInt(IInterJ);
359 deleteInt(JInterI);
360 if (mapKToIJ != nullptr) {
361 delete[] mapKToIJ;
362 mapKToIJ = nullptr;
363 }
364 deleteInt(mapIJToK);
365 deleteInt(aloneIPads);
366 deleteInt(aloneJPads);
367 deleteInt(aloneKPads);
368}
369
371{
372 double max = -1;
373 for (int c = 0; c < 2; c++) {
374 if (pads[c] != nullptr) {
375 max = std::fmax(max, vectorMax(pads[c]->getCharges(), getNbrOfPads(c)));
376 }
377 }
378 return max;
379}
380
381int ClusterPEM::getIndexByRow(const char* matrix, PadIdx_t N, PadIdx_t M,
382 PadIdx_t* IIdx)
383{
384 int k = 0;
385 // printf("N=%d, M=%d\n", N, M);
386 for (PadIdx_t i = 0; i < N; i++) {
387 for (PadIdx_t j = 0; j < M; j++) {
388 if (matrix[i * M + j] == 1) {
389 IIdx[k] = j;
390 k++;
391 // printf("k=%d,", k);
392 }
393 }
394 // end of row/columns
395 IIdx[k] = -1;
396 k++;
397 }
398 // printf("\n final k=%d \n", k);
399 return k;
400}
401
402int ClusterPEM::getIndexByColumns(const char* matrix, PadIdx_t N, PadIdx_t M,
403 PadIdx_t* JIdx)
404{
405 int k = 0;
406 for (PadIdx_t j = 0; j < M; j++) {
407 for (PadIdx_t i = 0; i < N; i++) {
408 if (matrix[i * M + j] == 1) {
409 JIdx[k] = i;
410 k++;
411 }
412 }
413 // end of row/columns
414 JIdx[k] = -1;
415 k++;
416 }
417 return k;
418}
419
420int ClusterPEM::checkConsistencyMapKToIJ(const char* intersectionMatrix,
421 const MapKToIJ_t* mapKToIJ,
422 const PadIdx_t* mapIJToK,
423 const PadIdx_t* aloneIPads,
424 const PadIdx_t* aloneJPads, int N0,
425 int N1, int nbrOfProjPads)
426{
427 MapKToIJ_t ij;
428 int n = 0;
429 int rc = 0;
430 // Consistency with intersectionMatrix
431 // and aloneI/JPads
432 for (PadIdx_t k = 0; k < nbrOfProjPads; k++) {
433 ij = mapKToIJ[k];
434 if ((ij.i >= 0) && (ij.j >= 0)) {
435 if (intersectionMatrix[ij.i * N1 + ij.j] != 1) {
436 printf("ERROR: no intersection %d %d %d\n", ij.i, ij.j,
437 intersectionMatrix[ij.i * N1 + ij.j]);
438 throw std::overflow_error("Divide by zero exception");
439 rc = -1;
440 } else {
441 n++;
442 }
443 } else if (ij.i < 0) {
444 if (aloneJPads[ij.j] != k) {
445 printf("ERROR: j-pad should be alone %d %d %d %d\n", ij.i, ij.j,
446 aloneIPads[ij.j], k);
447 throw std::overflow_error("Divide by zero exception");
448 rc = -1;
449 }
450 } else if (ij.j < 0) {
451 if (aloneIPads[ij.i] != k) {
452 printf("ERROR: i-pad should be alone %d %d %d %d\n", ij.i, ij.j,
453 aloneJPads[ij.j], k);
454 throw std::overflow_error("Divide by zero exception");
455 rc = -1;
456 }
457 }
458 }
459 // TODO : Make a test with alone pads ???
460 int sum = vectorSumChar(intersectionMatrix, N0 * N1);
461 if (sum != n) {
462 printf("ERROR: nbr of intersection differs %d %d \n", n, sum);
463 throw std::overflow_error("Divide by zero exception");
464 rc = -1;
465 }
466
467 for (int i = 0; i < N0; i++) {
468 for (int j = 0; j < N1; j++) {
469 int k = mapIJToK[i * N1 + j];
470 if (k >= 0) {
471 ij = mapKToIJ[k];
472 if ((ij.i != i) || (ij.j != j)) {
473 throw std::overflow_error(
474 "checkConsistencyMapKToIJ: MapIJToK/MapKToIJ");
475 printf("ij.i=%d, ij.j=%d, i=%d, j=%d \n", ij.i, ij.j, i, j);
476 }
477 }
478 }
479 }
480 // Check mapKToIJ / mapIJToK
481 for (PadIdx_t k = 0; k < nbrOfProjPads; k++) {
482 ij = mapKToIJ[k];
483 if (ij.i < 0) {
484 if (aloneJPads[ij.j] != k) {
485 printf("i, j, k = %d, %d %d\n", ij.i, ij.j, k);
486 throw std::overflow_error(
487 "checkConsistencyMapKToIJ: MapKToIJ/MapIJToK aloneJPads");
488 }
489 } else if (ij.j < 0) {
490 if (aloneIPads[ij.i] != k) {
491 printf("i, j, k = %d, %d %d\n", ij.i, ij.j, k);
492 throw std::overflow_error(
493 "checkConsistencyMapKToIJ: MapKToIJ/MapIJToK aloneIPads");
494 }
495 } else if (mapIJToK[ij.i * N1 + ij.j] != k) {
496 printf("i, j, k = %d, %d %d\n", ij.i, ij.j, k);
497 throw std::overflow_error("checkConsistencyMapKToIJ: MapKToIJ/MapIJToK");
498 }
499 }
500
501 return rc;
502}
503
504void ClusterPEM::computeProjectedPads(const Pads& pad0InfSup,
505 const Pads& pad1InfSup,
506 int maxNbrProjectedPads,
507 PadIdx_t* aloneIPads, PadIdx_t* aloneJPads,
508 PadIdx_t* aloneKPads, int includeAlonePads)
509{
510 // Use positive values of the intersectionMatrix
511 // negative ones are single pads
512 // Compute the new location of the projected pads (projected_xyDxy)
513 // and the mapping mapKToIJ which maps k (projected pads)
514 // to i, j (cathode pads)
515 const double* x0Inf = pad0InfSup.getXInf();
516 const double* y0Inf = pad0InfSup.getYInf();
517 const double* x0Sup = pad0InfSup.getXSup();
518 const double* y0Sup = pad0InfSup.getYSup();
519 const double* x1Inf = pad1InfSup.getXInf();
520 const double* y1Inf = pad1InfSup.getYInf();
521 const double* x1Sup = pad1InfSup.getXSup();
522 const double* y1Sup = pad1InfSup.getYSup();
523 int N0 = pad0InfSup.getNbrOfPads();
524 int N1 = pad1InfSup.getNbrOfPads();
525 //
526 // ??? Inv
527 /*
528 double *projX = projectedPads->getX();
529 double *projY = projectedPads->getY();
530 double *projDX = projectedPads->getDX();
531 double *projDY = projectedPads->getDY();
532 int nProjPads = projectedPads->getNbrOfPads
533 */
534 double* projX = new double[maxNbrProjectedPads];
535 double* projY = new double[maxNbrProjectedPads];
536 double* projDX = new double[maxNbrProjectedPads];
537 double* projDY = new double[maxNbrProjectedPads];
538 double l, r, b, t;
539 int k = 0;
540 PadIdx_t* ij_ptr = IInterJ;
541 double countIInterJ, countJInterI;
542 PadIdx_t i, j;
543 for (i = 0; i < N0; i++) {
544 // Nbr of j-pads intersepting i-pad
545 for (countIInterJ = 0; *ij_ptr != -1; countIInterJ++, ij_ptr++) {
546 j = *ij_ptr;
547 // Debug
548 // printf("X[0/1]inf/sup %d %d %9.3g %9.3g %9.3g %9.3g\n", i, j, x0Inf[i],
549 // x0Sup[i], x1Inf[j], x1Sup[j]);
550 l = std::fmax(x0Inf[i], x1Inf[j]);
551 r = std::fmin(x0Sup[i], x1Sup[j]);
552 b = std::fmax(y0Inf[i], y1Inf[j]);
553 t = std::fmin(y0Sup[i], y1Sup[j]);
554 projX[k] = (l + r) * 0.5;
555 projY[k] = (b + t) * 0.5;
556 projDX[k] = (r - l) * 0.5;
557 projDY[k] = (t - b) * 0.5;
558 mapKToIJ[k].i = i;
559 mapKToIJ[k].j = j;
560 mapIJToK[i * N1 + j] = k;
561 // Debug
563 printf("newpad %d %d %d %9.3g %9.3g %9.3g %9.3g\n", i, j, k, projX[k],
564 projY[k], projDX[k], projDY[k]);
565 }
566 k++;
567 }
568 // Test if there is no intercepting pads with i-pad
569 if ((countIInterJ == 0) && includeAlonePads) {
570 l = x0Inf[i];
571 r = x0Sup[i];
572 b = y0Inf[i];
573 t = y0Sup[i];
574 projX[k] = (l + r) * 0.5;
575 projY[k] = (b + t) * 0.5;
576 projDX[k] = (r - l) * 0.5;
577 projDY[k] = (t - b) * 0.5;
578 // printf("newpad alone cath0 %d %d %9.3g %9.3g %9.3g %9.3g\n", i, k,
579 // projX[k], projY[k], projDX[k], projDY[k]); Not used ???
580 mapKToIJ[k].i = i;
581 mapKToIJ[k].j = -1;
582 aloneIPads[i] = k;
583 aloneKPads[k] = i;
584 k++;
585 }
586 // Row change
587 ij_ptr++;
588 }
589 // Just add alone j-pads of cathode 1
590 if (includeAlonePads) {
591 ij_ptr = JInterI;
592 for (PadIdx_t j = 0; j < N1; j++) {
593 for (countJInterI = 0; *ij_ptr != -1; countJInterI++) {
594 ij_ptr++;
595 }
596 if (countJInterI == 0) {
597 l = x1Inf[j];
598 r = x1Sup[j];
599 b = y1Inf[j];
600 t = y1Sup[j];
601 projX[k] = (l + r) * 0.5;
602 projY[k] = (b + t) * 0.5;
603 projDX[k] = (r - l) * 0.5;
604 projDY[k] = (t - b) * 0.5;
605 // Debug
606 // printf("newpad alone cath1 %d %d %9.3g %9.3g %9.3g %9.3g\n", j, k,
607 // projX[k], projY[k], projDX[k], projDY[k]); newCh0[k] = ch0[i]; Not
608 // used ???
609 mapKToIJ[k].i = -1;
610 mapKToIJ[k].j = j;
611 aloneJPads[j] = k;
612 aloneKPads[k] = j;
613 k++;
614 }
615 // Skip -1, row/ col change
616 ij_ptr++;
617 }
618 }
620 printf("builProjectPads mapIJToK=%p, N0=%d N1=%d\\n", mapIJToK, N0, N1);
621 for (int i = 0; i < N0; i++) {
622 for (int j = 0; j < N1; j++) {
623 if ((mapIJToK[i * N1 + j] != -1)) {
624 printf(" %d inter %d\n", i, j);
625 }
626 }
627 }
628 vectorPrintInt("builProjectPads", aloneKPads, k);
629 }
630 projectedPads = new Pads(projX, projY, projDX, projDY, chamberId, k);
631}
632
633int ClusterPEM::buildProjectedGeometry(int includeSingleCathodePads)
634{
635 PadIdx_t* projNeighbors;
636 // Single cathode
637 if (nbrOfCathodePlanes == 1) {
638 // One Cathode case
639 // Pad Projection is the cluster itself
640 projectedPads = new Pads(*pads[singleCathPlaneID], Pads::PadMode::xydxdyMode);
641 projNeighbors = projectedPads->getFirstNeighbors();
642 return projectedPads->getNbrOfPads();
643 }
644
645 int N0 = pads[0]->getNbrOfPads();
646 int N1 = pads[1]->getNbrOfPads();
647 char intersectionMatrix[N0 * N1];
648 vectorSetZeroChar(intersectionMatrix, N0 * N1);
649
650 // Get the pad limits
651 Pads padInfSup0(*pads[0], Pads::PadMode::xyInfSupMode);
652 Pads padInfSup1(*pads[1], Pads::PadMode::xyInfSupMode);
653 mapIJToK = new PadIdx_t[N0 * N1];
654 vectorSetInt(mapIJToK, -1, N0 * N1);
655
656 //
657 // Build the intersection matrix
658 // Looking for j pads, intercepting pad i
659 //
660 double xmin, xmax, ymin, ymax;
661 PadIdx_t xInter, yInter;
662 const double* x0Inf = padInfSup0.getXInf();
663 const double* x0Sup = padInfSup0.getXSup();
664 const double* y0Inf = padInfSup0.getYInf();
665 const double* y0Sup = padInfSup0.getYSup();
666 const double* x1Inf = padInfSup1.getXInf();
667 const double* x1Sup = padInfSup1.getXSup();
668 const double* y1Inf = padInfSup1.getYInf();
669 const double* y1Sup = padInfSup1.getYSup();
670 for (PadIdx_t i = 0; i < N0; i++) {
671 for (PadIdx_t j = 0; j < N1; j++) {
672 xmin = std::fmax(x0Inf[i], x1Inf[j]);
673 xmax = std::fmin(x0Sup[i], x1Sup[j]);
674 xInter = (xmin <= (xmax - epsilonGeometry));
675 if (xInter) {
676 ymin = std::fmax(y0Inf[i], y1Inf[j]);
677 ymax = std::fmin(y0Sup[i], y1Sup[j]);
678 yInter = (ymin <= (ymax - epsilonGeometry));
679 intersectionMatrix[i * N1 + j] = yInter;
680 // printf("inter i=%3d, j=%3d, x0=%8.5f y0=%8.5f, x1=%8.5f y1=%8.5f\n",
681 // i, j, pads[0]->x[i], pads[0]->y[i], pads[1]->x[i], pads[1]->y[i]);
682 }
683 }
684 }
685 //
687 printMatrixChar(" Intersection Matrix", intersectionMatrix, N0, N1);
688 }
689 //
690 // Compute the max number of projected pads to make
691 // memory allocations
692 //
693 int maxNbrOfProjPads = vectorSumChar(intersectionMatrix, N0 * N1);
694 int nbrOfSinglePads = 0;
695 if (includeSingleCathodePads) {
696 // Add alone cath0-pads
697 for (PadIdx_t i = 0; i < N0; i++) {
698 if (vectorSumRowChar(&intersectionMatrix[i * N1], N0, N1) == 0) {
699 nbrOfSinglePads++;
700 }
701 }
702 // Add alone cath1-pads
703 for (PadIdx_t j = 0; j < N1; j++) {
704 if (vectorSumColumnChar(&intersectionMatrix[j], N0, N1) == 0) {
705 nbrOfSinglePads++;
706 }
707 }
708 }
709 // Add alone pas and row/column separators
710 maxNbrOfProjPads += nbrOfSinglePads + fmax(N0, N1);
712 printf(" maxNbrOfProjPads %d\n", maxNbrOfProjPads);
713 }
714 //
715 //
716 // Intersection Matrix Sparse representation
717 //
719 IInterJ = new PadIdx_t[maxNbrOfProjPads];
720 JInterI = new PadIdx_t[maxNbrOfProjPads];
721 int checkr = getIndexByRow(intersectionMatrix, N0, N1, IInterJ);
722 int checkc = getIndexByColumns(intersectionMatrix, N0, N1, JInterI);
724 if ((checkr > maxNbrOfProjPads) || (checkc > maxNbrOfProjPads)) {
725 printf(
726 "Allocation pb for IInterJ or JInterI: allocated=%d, needed for "
727 "row=%d, for col=%d \n",
728 maxNbrOfProjPads, checkr, checkc);
729 throw std::overflow_error("Allocation pb for IInterJ or JInterI");
730 }
731 }
733 printInterMap(" IInterJ", IInterJ, N0);
734 printInterMap(" JInterI", JInterI, N1);
735 }
736
737 //
738 // Remaining allocation
739 //
740 aloneIPads = new PadIdx_t[N0];
741 aloneJPads = new PadIdx_t[N1];
742 // PadIdx_t *aloneKPads = new PadIdx_t[N0*N1];
743 mapKToIJ = new MapKToIJ_t[maxNbrOfProjPads];
744 aloneKPads = new PadIdx_t[maxNbrOfProjPads];
745 vectorSetInt(aloneIPads, -1, N0);
746 vectorSetInt(aloneJPads, -1, N1);
747 vectorSetInt(aloneKPads, -1, maxNbrOfProjPads);
748
749 //
750 // Build the projected pads
751 //
752 computeProjectedPads(padInfSup0, padInfSup1, maxNbrOfProjPads, aloneIPads,
753 aloneJPads, aloneKPads, includeSingleCathodePads);
754
756 checkConsistencyMapKToIJ(intersectionMatrix, mapKToIJ, mapIJToK, aloneIPads,
757 aloneJPads, N0, N1, projectedPads->getNbrOfPads());
758 }
759 //
760 // Get the isolated new pads
761 // (they have no neighboring)
762 //
763 int thereAreIsolatedPads = 0;
764 projNeighbors = projectedPads->getFirstNeighbors();
765 // Pads::printPads("Projected Pads:", *projectedPads);
767 printf(" Neighbors of the projected geometry\n");
768 Pads::printNeighbors(projNeighbors, projectedPads->getNbrOfPads());
769 }
770 int nbrOfProjPads = projectedPads->getNbrOfPads();
771 MapKToIJ_t ij;
772 for (PadIdx_t k = 0; k < nbrOfProjPads; k++) {
773 if (getTheFirstNeighborOf(projNeighbors, k) == -1) {
774 // pad k is isolated
775 thereAreIsolatedPads = 1;
776 ij = mapKToIJ[k];
777 if ((ij.i >= 0) && (ij.j >= 0)) {
779 printf(" Isolated pad: nul intersection i,j = %d %d\n", ij.i, ij.j);
780 }
781 intersectionMatrix[ij.i * N1 + ij.j] = 0;
782 } else {
783 throw std::overflow_error("I/j negative (alone pad)");
784 }
785 }
786 }
787 if ((clusterConfig.padMappingLog >= clusterConfig.detail) && thereAreIsolatedPads) {
788 printf("There are isolated pads %d\n", thereAreIsolatedPads);
789 }
790 //
791 if (thereAreIsolatedPads == 1) {
792 // Recompute all
793 // Why ???
794 getIndexByRow(intersectionMatrix, N0, N1, IInterJ);
795 getIndexByColumns(intersectionMatrix, N0, N1, JInterI);
796 //
797 // Build the new pads
798 //
799 delete projectedPads;
800 computeProjectedPads(padInfSup0, padInfSup1, maxNbrOfProjPads, aloneIPads,
801 aloneJPads, aloneKPads, includeSingleCathodePads);
802 projNeighbors = projectedPads->getFirstNeighbors();
803 }
804 return projectedPads->getNbrOfPads();
805}
806
807double* ClusterPEM::projectChargeOnProjGeometry(int includeAlonePads)
808{
809
810 double* qProj;
811 if (nbrOfCathodePlanes == 1) {
812 Pads* sPads = pads[singleCathPlaneID];
813 qProj = new double[sPads->getNbrOfPads()];
814 vectorCopy(sPads->getCharges(), sPads->getNbrOfPads(), qProj);
815 return qProj;
816 }
817 int nbrOfProjPads = projectedPads->getNbrOfPads();
818 const double* ch0 = pads[0]->getCharges();
819 const double* ch1 = pads[1]->getCharges();
820 //
821 // Computing charges of the projected pads
822 // Ch0 part
823 //
824 double minProj[nbrOfProjPads];
825 double maxProj[nbrOfProjPads];
826 double projCh0[nbrOfProjPads];
827 double projCh1[nbrOfProjPads];
828 int N0 = pads[0]->getNbrOfPads();
829 int N1 = pads[1]->getNbrOfPads();
830 PadIdx_t k = 0;
831 double sumCh1ByRow;
832 PadIdx_t* ij_ptr = IInterJ;
833 PadIdx_t* rowStart;
834 for (PadIdx_t i = 0; i < N0; i++) {
835 // Save the starting index of the begining of the row
836 rowStart = ij_ptr;
837 // sum of charge with intercepting j-pad
838 for (sumCh1ByRow = 0.0; *ij_ptr != -1; ij_ptr++) {
839 sumCh1ByRow += ch1[*ij_ptr];
840 }
841 double ch0_i = ch0[i];
842 if (sumCh1ByRow != 0.0) {
843 double cst = ch0[i] / sumCh1ByRow;
844 for (ij_ptr = rowStart; *ij_ptr != -1; ij_ptr++) {
845 projCh0[k] = ch1[*ij_ptr] * cst;
846 minProj[k] = fmin(ch1[*ij_ptr], ch0_i);
847 maxProj[k] = fmax(ch1[*ij_ptr], ch0_i);
848 // Debug
849 // printf(" i=%d, j=%d, k=%d, sumCh0ByCol = %g, projCh1[k]= %g \n", i,
850 // *ij_ptr, k, sumCh1ByRow, projCh0[k]);
851 k++;
852 }
853 } else if (includeAlonePads) {
854 // Alone i-pad
855 projCh0[k] = ch0[i];
856 minProj[k] = ch0[i];
857 maxProj[k] = ch0[i];
858 k++;
859 }
860 // Move on a new row
861 ij_ptr++;
862 }
863 // Just add alone pads of cathode 1
864 if (includeAlonePads) {
865 for (PadIdx_t j = 0; j < N1; j++) {
866 k = aloneJPads[j];
867 if (k >= 0) {
868 projCh0[k] = ch1[j];
869 minProj[k] = ch1[j];
870 maxProj[k] = ch1[j];
871 }
872 }
873 }
874 //
875 // Computing charges of the projected pads
876 // Ch1 part
877 //
878 k = 0;
879 double sumCh0ByCol;
880 ij_ptr = JInterI;
881 PadIdx_t* colStart;
882 for (PadIdx_t j = 0; j < N1; j++) {
883 // Save the starting index of the beginnig of the column
884 colStart = ij_ptr;
885 // sum of charge intercepting i-pad
886 for (sumCh0ByCol = 0.0; *ij_ptr != -1; ij_ptr++) {
887 sumCh0ByCol += ch0[*ij_ptr];
888 }
889 if (sumCh0ByCol != 0.0) {
890 double cst = ch1[j] / sumCh0ByCol;
891 for (ij_ptr = colStart; *ij_ptr != -1; ij_ptr++) {
892 PadIdx_t i = *ij_ptr;
893 k = mapIJToK[i * N1 + j];
894 projCh1[k] = ch0[i] * cst;
895 // Debug
896 // printf(" j=%d, i=%d, k=%d, sumCh0ByCol = %g, projCh1[k]= %g \n", j,
897 // i, k, sumCh0ByCol, projCh1[k]);
898 }
899 } else if (includeAlonePads) {
900 // Alone j-pad
901 k = aloneJPads[j];
902 if (clusterConfig.padMappingCheck && (k < 0)) {
903 printf("ERROR: Alone j-pad with negative index j=%d\n", j);
904 // printf("Alone i-pad i=%d, k=%d\n", i, k);
905 }
906 projCh1[k] = ch1[j];
907 }
908 ij_ptr++;
909 }
910
911 // Just add alone pads of cathode 0
912 if (includeAlonePads) {
913 ij_ptr = IInterJ;
914 for (PadIdx_t i = 0; i < N0; i++) {
915 k = aloneIPads[i];
916 if (k >= 0) {
917 // printf("Alone i-pad i=%d, k=%d\n", i, k);
918 projCh1[k] = ch0[i];
919 }
920 }
921 }
922 // Charge Result
923 // Do the mean
924 qProj = new double[nbrOfProjPads];
925 vectorAddVector(projCh0, 1.0, projCh1, nbrOfProjPads, qProj);
926 vectorMultScalar(qProj, 0.5, nbrOfProjPads, qProj);
927 return qProj;
928}
929
931{
932
933 // Having one cathode plane (cathO, cath1 or projected cathodes)
934 // Extract the sub-clusters
935 int nProjPads = projectedPads->getNbrOfPads();
936 projPadToGrp = new Groups_t[nProjPads];
937 // Set to no Group (zero)
938 vectorSetShort(projPadToGrp, 0, nProjPads);
939
940 //
941 // Part I - Extract groups from projection plane
942 //
943 int nCathGroups = 0;
944 int nGroups = 0;
945 int nbrCath0 = (pads[0]) ? pads[0]->getNbrOfPads() : 0;
946 int nbrCath1 = (pads[1]) ? pads[1]->getNbrOfPads() : 0;
947
949 printf("\n");
950 printf("[buildGroupOfPads] Group processing\n");
951 printf("----------------\n");
952 }
953 //
954 // Build the "proj-groups"
955 // The pads which have no recovery with the other cathode plane
956 // are not considered. They are named 'single-pads'
957 nbrOfProjGroups = getConnectedComponentsOfProjPadsWOSinglePads();
958
960 saveProjPadToGroups(projPadToGrp, projectedPads->getNbrOfPads());
961 }
962
963 // Single cathode case
964 // The cath-group & proj-groups are the same
965 Groups_t grpToCathGrp[nbrOfProjGroups + 1];
966 if (nbrOfCathodePlanes == 1) {
967 // Copy the projPadGroup to cathGroup[0/1]
968 int nCathPads = pads[singleCathPlaneID]->getNbrOfPads();
969 cathGroup[singleCathPlaneID] = new Groups_t[nCathPads];
970 vectorCopyShort(projPadToGrp, nCathPads, cathGroup[singleCathPlaneID]);
971 nCathGroups = nbrOfProjGroups;
972 nGroups = nCathGroups;
973 // Identity mapping
974 for (int g = 0; g < (nbrOfProjGroups + 1); g++) {
975 grpToCathGrp[g] = g;
976 }
977 // Add the pads (not present in the projected plane)
978 int nNewGroups = pads[singleCathPlaneID]->addIsolatedPadInGroups(
979 cathGroup[singleCathPlaneID], grpToCathGrp, nGroups);
980 // ??? Check if some time
981 if (nNewGroups > 0) {
982 throw std::overflow_error("New group with one cathode plane ?????");
983 }
984 nGroups += nNewGroups;
985 //
986 } else {
987 //
988 // Part I - Extract groups from cathode planes
989 //
990 // 2 cathode planes & projected cathode plane
991 // Init. the new groups 'cath-groups'
992 int nCath0 = pads[0]->getNbrOfPads();
993 int nCath1 = pads[1]->getNbrOfPads();
994 cathGroup[0] = new Groups_t[nCath0];
995 cathGroup[1] = new Groups_t[nCath1];
996 vectorSetZeroShort(cathGroup[0], nCath0);
997 vectorSetZeroShort(cathGroup[1], nCath1);
999 printf("> Projected Groups nbrOfProjGroups=%d\n", nbrOfProjGroups);
1000 vectorPrintShort(" projPadToGrp", projPadToGrp, nProjPads);
1001 }
1002
1003 // Build cathode groups (merge the projected groups)
1004 //
1005 int nPads = pads[0]->getNbrOfPads() + pads[1]->getNbrOfPads();
1006 // Propagate proj-groups on the cathode pads
1007 nGroups = assignPadsToGroupFromProj(nbrOfProjGroups);
1008 // nGroups = assignGroupToCathPads( );
1010 printf("> Groups after cathodes propagation nCathGroups=%d\n", nGroups);
1011 }
1012
1013 // Compute the max allocation for the new cath-groups
1014 // Have to add single pads
1015 int nbrSinglePads = 0;
1016 for (int c = 0; c < 2; c++) {
1017 for (int p = 0; p < pads[c]->getNbrOfPads(); p++) {
1018 if (cathGroup[c][p] == 0) {
1019 nbrSinglePads += 1;
1020 }
1021 }
1022 }
1023 int nbrMaxGroups = nGroups + nbrSinglePads;
1024 // mapGrpToGrp is use to map oldGroups (proj-groups) to
1025 // newGroups (cath-groups) when
1026 // occurs
1027 Mask_t mapGrpToGrp[nbrMaxGroups + 1];
1028 for (int g = 0; g < (nbrMaxGroups + 1); g++) {
1029 mapGrpToGrp[g] = g;
1030 }
1031
1032 //
1033 // Add single pads of cath-0 and modyfy the groups
1034 //
1035 int nNewGrpCath0 =
1036 pads[0]->addIsolatedPadInGroups(cathGroup[0], mapGrpToGrp, nGroups);
1037 nGroups += nNewGrpCath0;
1038
1039 // Apply the new Groups on cath1
1040 for (int p = 0; p < nbrCath1; p++) {
1041 cathGroup[1][p] = mapGrpToGrp[cathGroup[1][p]];
1042 }
1043 // ... and on proj-pads
1044 for (int p = 0; p < nProjPads; p++) {
1045 projPadToGrp[p] = mapGrpToGrp[projPadToGrp[p]];
1046 }
1048 printf("> addIsolatedPadInGroups in cath-0 nNewGroups =%d\n", nGroups);
1049 vectorPrintShort(" mapGrpToGrp", mapGrpToGrp, nGroups + 1);
1050 }
1051
1052 //
1053 // Do the same on cath1
1054 // Add single pads of cath-1 and modify the groups
1055 //
1056 int nNewGrpCath1 =
1057 pads[1]->addIsolatedPadInGroups(cathGroup[1], mapGrpToGrp, nGroups);
1058 nGroups += nNewGrpCath1;
1059 // Apply the new Groups on cath1
1060 for (int p = 0; p < nbrCath0; p++) {
1061 cathGroup[0][p] = mapGrpToGrp[cathGroup[0][p]];
1062 }
1063 // ... and on proj-pads
1064 for (int p = 0; p < nProjPads; p++) {
1065 projPadToGrp[p] = mapGrpToGrp[projPadToGrp[p]];
1066 }
1068 printf("> addIsolatedPadInGroups in cath-1 nNewGroups =%d\n", nGroups);
1069 vectorPrintShort(" mapGrpToGrp", mapGrpToGrp, nGroups + 1);
1070 }
1071 // Remove low charged groups
1072 removeLowChargedGroups(nGroups);
1073
1074 // Some groups may be merged, others groups may diseappear
1075 // So the final groups must be renumbered
1076 int nNewGroups = renumberGroups(mapGrpToGrp, nGroups);
1078 printf("> Groups after renumbering nGroups=%d\n", nGroups);
1079 vectorPrintShort(" projPadToGrp", projPadToGrp, nProjPads);
1080 printf(" nNewGrpCath0=%d, nNewGrpCath1=%d, nGroups=%d\n", nNewGrpCath0,
1081 nNewGrpCath1, nGroups);
1082 vectorPrintShort(" cath0ToGrp ", cathGroup[0], nbrCath0);
1083 vectorPrintShort(" cath1ToGrp ", cathGroup[1], nbrCath1);
1084 vectorPrintShort(" mapGrpToGrp ", mapGrpToGrp, nNewGroups);
1085 }
1086 // Apply this renumbering on projection-pads
1087 for (int p = 0; p < nProjPads; p++) {
1088 projPadToGrp[p] = mapGrpToGrp[projPadToGrp[p]];
1089 }
1090
1091 nGroups = nNewGroups;
1092 // Propagate the cath-groups to the projected pads
1093 updateProjectionGroups();
1094 }
1095
1097 printf(" > Final Groups %d\n", nGroups);
1098 vectorPrintShort(" cathToGrp[0]", cathGroup[0], nbrCath0);
1099 vectorPrintShort(" cathToGrp[1]", cathGroup[1], nbrCath1);
1100 }
1101 return nGroups;
1102}
1103
1104int ClusterPEM::getConnectedComponentsOfProjPadsWOSinglePads()
1105{
1106 // Class from neighbors list of projected pads, the pads in groups (connected
1107 // components) projPadToGrp is set to the group Id of the pad. If the group Id
1108 // is zero, the the pad is unclassified Return the number of groups
1109 int N = projectedPads->getNbrOfPads();
1110 // Invalid Mem Leak : projPadToGrp = new Groups_t[N];
1111 PadIdx_t* neigh = projectedPads->getFirstNeighbors();
1112 PadIdx_t neighToDo[N];
1113 vectorSetZeroShort(projPadToGrp, N);
1114 // Nbr of pads alrready proccessed
1115 int nbrOfPadSetInGrp = 0;
1116 // Last projPadToGrp to process
1117 short* curPadGrp = projPadToGrp;
1118 short currentGrpId = 0;
1119 //
1120 int i, j, k;
1121 // printNeighbors();
1122
1124 printf(
1125 "> Extract connected components "
1126 "[getConnectedComponentsOfProjPadsWOIsolatedPads]\n");
1127 }
1128 while (nbrOfPadSetInGrp < N) {
1129 // Seeking the first unclassed pad (projPadToGrp[k]=0)
1130 for (; (curPadGrp < &projPadToGrp[N]) && *curPadGrp != 0;) {
1131 curPadGrp++;
1132 }
1133 k = curPadGrp - projPadToGrp;
1135 printf(" k=%d, nbrOfPadSetInGrp g=%d: n=%d\n", k, currentGrpId,
1136 nbrOfPadSetInGrp);
1137 }
1138 //
1139 // New group for pad k - then search all neighbours of k
1140 // aloneKPads = 0 if only one cathode
1141 if (aloneKPads && (aloneKPads[k] != -1)) {
1142 // Alone Pad no group at the moment
1144 printf(" isolated pad %d\n", k);
1145 }
1146 projPadToGrp[k] = -1;
1147 nbrOfPadSetInGrp++;
1148 continue;
1149 }
1150 currentGrpId++;
1152 printf(" New Grp, pad k=%d in new grp=%d\n", k, currentGrpId);
1153 }
1154 projPadToGrp[k] = currentGrpId;
1155 nbrOfPadSetInGrp++;
1156 PadIdx_t startIdx = 0, endIdx = 1;
1157 neighToDo[startIdx] = k;
1158 // Labels k neighbors
1159 // Propagation of the group in all neighbour list
1160 for (; startIdx < endIdx; startIdx++) {
1161 i = neighToDo[startIdx];
1163 printf(" propagate grp to neighbours of i=%d ", i);
1164 }
1165 //
1166 // Scan i neighbors
1167 for (PadIdx_t* neigh_ptr = getTheFirtsNeighborOf(neigh, i);
1168 *neigh_ptr != -1; neigh_ptr++) {
1169 j = *neigh_ptr;
1170 // printf(" neigh j %d\n, \n", j);
1171 if (projPadToGrp[j] == 0) {
1172 // Add the neighbors in the currentgroup
1173 //
1174 // aloneKPads = 0 if only one cathode
1175 if (aloneKPads && (aloneKPads[j] != -1)) {
1177 printf(" isolated pad %d, ", j);
1178 }
1179 projPadToGrp[j] = -1;
1180 nbrOfPadSetInGrp++;
1181 continue;
1182 }
1184 printf("%d, ", j);
1185 }
1186 projPadToGrp[j] = currentGrpId;
1187 nbrOfPadSetInGrp++;
1188 // Append in the neighbor list to search
1189 neighToDo[endIdx] = j;
1190 endIdx++;
1191 }
1192 }
1194 printf("\n");
1195 }
1196 }
1197 // printf("make groups grpId=%d, nbrOfPadSetInGrp=%d\n", currentGrpId,
1198 // nbrOfPadSetInGrp);
1199 }
1200 for (int k = 0; k < N; k++) {
1201 if (projPadToGrp[k] == -1) {
1202 projPadToGrp[k] = 0;
1203 }
1204 }
1205 // return tne number of Grp
1206 return currentGrpId;
1207}
1208
1210/*
1211void Cluster::assignSingleCathPadsToGroup( short *padGroup, int nPads, int nGrp,
1212int nCath0, int nCath1) { Groups_t cath0ToGrpFromProj[nCath0]; Groups_t
1213cath1ToGrpFromProj[nCath1]; cath1ToGrpFromProj = 0; if ( nCath0 != 0) {
1214 cath0ToGrpFromProj = new short[nCath0];
1215 vectorCopyShort( padGroup, nCath0, cath0ToGrpFromProj);
1216 } else {
1217 cath1ToGrpFromProj = new short[nCath1];
1218 vectorCopyShort( padGroup, nCath1, cath1ToGrpFromProj);
1219 }
1220 vectorSetShort( wellSplitGroup, 1, nGrp+1);
1221}
1222*/
1223
1224// Assign a group to the original pads
1225// Update the pad group and projected-pads group
1226int ClusterPEM::assignPadsToGroupFromProj(int nGrp)
1227{
1228 // Matrix for the mapping olg-group -> new group
1229 short matGrpGrp[(nGrp + 1) * (nGrp + 1)];
1230 vectorSetZeroShort(matGrpGrp, (nGrp + 1) * (nGrp + 1));
1231 //
1232 PadIdx_t i, j;
1233 short g, prevGroup;
1235 printf("[AssignPadsToGroupFromProj] Assign cath-grp from proj-grp \n");
1236 }
1237 // Expand the projected Groups
1238 // 'projPadToGrp' to the pad groups 'padToGrp'
1239 // If there are conflicts, fuse the groups
1240 // Build the Group-to-Group matrix matGrpGrp
1241 // which describe how to fuse Groups
1242 // with the projected Groups
1243 // projPadToGrp
1244 int nProjPads = projectedPads->getNbrOfPads();
1245 for (int k = 0; k < nProjPads; k++) {
1246 g = projPadToGrp[k];
1247 // Give the indexes of overlapping pad k
1248 i = mapKToIJ[k].i;
1249 j = mapKToIJ[k].j;
1250 //
1251 // Cathode 0
1252 //
1253 if (i >= 0) {
1254 // Remark: if i is an alone pad (j<0)
1255 // i is processed as well
1256 //
1257 prevGroup = cathGroup[0][i];
1258 if ((prevGroup == 0) || (prevGroup == g)) {
1259 // Case: no group before or same group
1260 //
1261 cathGroup[0][i] = g;
1262 matGrpGrp[g * (nGrp + 1) + g] = 1;
1263 } else {
1264 // Already a grp (Conflict)
1265 // Group to fuse
1266 // Store the grp into grp matrix
1267 // ??? to suppress cathGroup[0][i] = g;
1268 cathGroup[0][i] = std::min(g, prevGroup);
1269 matGrpGrp[g * (nGrp + 1) + prevGroup] = 1;
1270 matGrpGrp[prevGroup * (nGrp + 1) + g] = 1;
1271 }
1272 }
1273 //
1274 // Cathode 1
1275 //
1276 if ((j >= 0)) {
1277 // Remark: if j is an alone pad (j<0)
1278 // j is processed as well
1279 //
1280 prevGroup = cathGroup[1][j];
1281
1282 if ((prevGroup == 0) || (prevGroup == g)) {
1283 // No group before
1284 cathGroup[1][j] = g;
1285 matGrpGrp[g * (nGrp + 1) + g] = 1;
1286 } else {
1287 // Already a Group (Conflict)
1288 // cathGroup[1][j] = g;
1289 cathGroup[1][j] = std::min(g, prevGroup);
1290 matGrpGrp[g * (nGrp + 1) + prevGroup] = 1;
1291 matGrpGrp[prevGroup * (nGrp + 1) + g] = 1;
1292 }
1293 }
1294 }
1296 printMatrixShort(" Group/Group matrix", matGrpGrp, nGrp + 1, nGrp + 1);
1297 vectorPrintShort(" cathToGrp[0]", cathGroup[0], pads[0]->getNbrOfPads());
1298 vectorPrintShort(" cathToGrp[1]", cathGroup[1], pads[1]->getNbrOfPads());
1299 }
1300 //
1301 // Merge the groups (build the mapping grpToMergedGrp)
1302 //
1303 Groups_t grpToMergedGrp[nGrp + 1]; // Mapping old groups to new merged groups
1304 vectorSetZeroShort(grpToMergedGrp, nGrp + 1);
1305 //
1306 int iGroup = 1; // Describe the current group
1307 int curGroup; // Describe the mapping grpToMergedGrp[iGroup]
1308 while (iGroup < (nGrp + 1)) {
1309 // Define the new group to process
1310 if (grpToMergedGrp[iGroup] == 0) {
1311 // No group before
1312 grpToMergedGrp[iGroup] = iGroup;
1313 }
1314 curGroup = grpToMergedGrp[iGroup];
1315 // printf( " current iGroup=%d -> grp=%d \n", iGroup, curGroup);
1316 // Look for other groups in matGrpGrp
1317 int ishift = iGroup * (nGrp + 1);
1318 // Check if there is an overlaping group
1319 for (int j = iGroup + 1; j < (nGrp + 1); j++) {
1320 if (matGrpGrp[ishift + j]) {
1321 // Merge the groups with the current one
1322 if (grpToMergedGrp[j] == 0) {
1323 // No group assign before, merge the groups with the current one
1324 // printf( " newg merge grp=%d -> grp=%d\n", j, curGroup);
1325 grpToMergedGrp[j] = curGroup;
1326 } else {
1327 // A group is already assigned,
1328 // Merge the 2 groups curGroup and grpToMergedGrp[j]
1329 // printf( " oldg merge grp=%d -> grp=%d\n", curGroup,
1330 // grpToMergedGrp[j]); Remark : curGroup < j Fuse and propagate the
1331 // groups
1332 grpToMergedGrp[curGroup] = grpToMergedGrp[j];
1333 for (int g = 1; g < nGrp + 1; g++) {
1334 if (grpToMergedGrp[g] == curGroup) {
1335 grpToMergedGrp[g] = grpToMergedGrp[j];
1336 }
1337 }
1338 curGroup = grpToMergedGrp[j];
1339 }
1340 }
1341 }
1342 iGroup++;
1343 }
1344
1345 // Perform the mapping group -> mergedGroups
1347 vectorPrintShort(" Mapping grpToMergedGrp", grpToMergedGrp, nGrp + 1);
1348 }
1349 //
1350 // Renumber the fused groups
1351 //
1352 int newGroupID = 0;
1353 Mask_t map[nGrp + 1];
1354 vectorSetZeroShort(map, (nGrp + 1));
1355 for (int g = 1; g < (nGrp + 1); g++) {
1356 int gm = grpToMergedGrp[g];
1357 if (map[gm] == 0) {
1358 newGroupID++;
1359 map[gm] = newGroupID;
1360 }
1361 }
1362 // Apply the renumbering
1363 for (int g = 1; g < (nGrp + 1); g++) {
1364 grpToMergedGrp[g] = map[grpToMergedGrp[g]];
1365 }
1366
1367 // Perform the mapping grpToMergedGrp to the cath-groups
1369 vectorPrintShort(" Mapping renumbered grpToMergedGrp", grpToMergedGrp,
1370 nGrp + 1);
1371 }
1372 for (int c = 0; c < 2; c++) {
1373 for (int p = 0; p < pads[c]->getNbrOfPads(); p++) {
1374 // ??? Why abs() ... explain
1375 cathGroup[c][p] = grpToMergedGrp[std::abs(cathGroup[c][p])];
1376 }
1377 }
1378
1380 for (int c = 0; c < 2; c++) {
1381 for (int p = 0; p < pads[c]->getNbrOfPads(); p++) {
1382 if (clusterConfig.groupsLog >= clusterConfig.info && cathGroup[c][p] == 0) {
1383 printf(" [assignPadsToGroupFromProj] pad %d with no group\n", p);
1384 }
1385 }
1386 }
1387 }
1388
1389 // Perform the mapping grpToMergedGrp to the projected pads
1390 vectorMapShort(projPadToGrp, grpToMergedGrp, nProjPads);
1391
1392 //
1393 return newGroupID;
1394}
1395
1396// Add boundary pads with q charge equal 0
1398{
1399 int nbrOfPads = getNbrOfPads();
1400 // Simple case : no adding boundary pads
1401 if (nbrOfPads == 1) {
1402 return;
1403 }
1404 //
1405 for (int c = 0; c < 2; c++) {
1406 if (pads[c]) {
1407 Pads* bPads = pads[c]->addBoundaryPads();
1408 delete pads[c];
1409 pads[c] = bPads;
1410 }
1411 }
1412}
1413
1414// Propagate the proj-groups to the cath-pads
1415// Not used
1416int ClusterPEM::assignGroupToCathPads()
1417{
1418 //
1419 // From the cathode group found with the projection,
1420 int nCath0 = (pads[0]) ? pads[0]->getNbrOfPads() : 0;
1421 int nCath1 = (pads[1]) ? pads[1]->getNbrOfPads() : 0;
1422 int nGrp = nbrOfProjGroups;
1423 // Groups obtain with the projection
1424 /*
1425 Groups_t cath0ToGrpFromProj[nCath0];
1426 Groups_t cath1ToGrpFromProj[nCath1];
1427 vectorSetZeroShort( cath0ToGrpFromProj, nCath0);
1428 vectorSetZeroShort( cath1ToGrpFromProj, nCath1);
1429 */
1430 Groups_t* cath0ToGrpFromProj = cathGroup[0];
1431 Groups_t* cath1ToGrpFromProj = cathGroup[1];
1432 vectorSetZeroShort(cathGroup[0], nCath0);
1433 vectorSetZeroShort(cathGroup[1], nCath1);
1434 // Mapping proj-groups to cath-groups
1435 Groups_t projGrpToCathGrp[nGrp + 1];
1436 vectorSetZeroShort(projGrpToCathGrp, nGrp + 1);
1437 int nCathGrp = 0;
1438 //
1440 printf(" [assignGroupToCathPads]\n");
1441 }
1442 //
1443 PadIdx_t i, j;
1444 short g, prevGroup0, prevGroup1;
1445 if (nbrOfCathodePlanes == 1) {
1446 // Single cathode plane
1447 vectorCopyShort(projPadToGrp, pads[singleCathPlaneID]->getNbrOfPads(),
1448 cathGroup[singleCathPlaneID]);
1449 return nGrp;
1450 }
1451 int nProjPads = projectedPads->getNbrOfPads();
1452 for (int k = 0; k < nProjPads; k++) {
1453 // Group of the projection pad k
1454 g = projPadToGrp[k];
1455 // Intersection indexes of the 2 cath
1456 i = mapKToIJ[k].i;
1457 j = mapKToIJ[k].j;
1459 printf("map k=%d g=%d to i=%d/%d, j=%d/%d\n", k, g, i, nCath0, j, nCath1);
1460 }
1461 //
1462 // Cathode 0
1463 //
1464 if ((i >= 0) && (nCath0 != 0)) {
1465 // if the pad has already been set
1466 prevGroup0 = cath0ToGrpFromProj[i];
1467 if (prevGroup0 == 0) {
1468 if ((projGrpToCathGrp[g] == 0) && (g != 0)) {
1469 nCathGrp++;
1470 projGrpToCathGrp[g] = nCathGrp;
1471 }
1472 cath0ToGrpFromProj[i] = projGrpToCathGrp[g];
1473
1474 } else if (prevGroup0 != projGrpToCathGrp[g]) {
1475 // The previous cath-group of pad i differs from
1476 // those of g:
1477 // -> Fuse the 2 cath-groups g and prevGroup0
1478 printf(">>> Fuse group g=%d prevGrp0=%d, projGrpToCathGrp[g]=%d\n", g,
1479 prevGroup0, projGrpToCathGrp[g]);
1480 // projGrpToCathGrp[g] = prevGroup0;
1481 //
1482 Groups_t minGroup = (projGrpToCathGrp[g] != 0)
1483 ? std::min(projGrpToCathGrp[g], prevGroup0)
1484 : prevGroup0;
1485 projGrpToCathGrp[g] = minGroup;
1486 // projGrpToCathGrp[prevGroup0] = minGroup;
1487 }
1488 }
1489 //
1490 // Cathode 1
1491 //
1492 if ((j >= 0) && (nCath1 != 0)) {
1493 prevGroup1 = cath1ToGrpFromProj[j];
1494 if (prevGroup1 == 0) {
1495 if ((projGrpToCathGrp[g] == 0) && (g != 0)) {
1496 nCathGrp++;
1497 projGrpToCathGrp[g] = nCathGrp;
1498 }
1499 cath1ToGrpFromProj[j] = projGrpToCathGrp[g];
1500 } else if (prevGroup1 != projGrpToCathGrp[g]) {
1501 printf(">>> Fuse group g=%d prevGrp1=%d, projGrpToCathGrp[g]=%d\n", g,
1502 prevGroup1, projGrpToCathGrp[g]);
1503 // projGrpToCathGrp[g] = prevGroup1;
1504 // Groups_t minGroup = std::min( projGrpToCathGrp[g], prevGroup1);
1505 Groups_t minGroup = (projGrpToCathGrp[g] != 0)
1506 ? std::min(projGrpToCathGrp[g], prevGroup1)
1507 : prevGroup1;
1508 projGrpToCathGrp[g] = minGroup;
1509 // projGrpToCathGrp[prevGroup1] = minGroup;
1510 }
1511 }
1512 }
1513
1515 printf(" [assignGroupToCathPads] before renumbering nCathGrp=%d\n", nCathGrp);
1516 vectorPrintShort(" cath0ToGrpFromProj", cath0ToGrpFromProj, nCath0);
1517 vectorPrintShort(" cath1ToGrpFromProj", cath1ToGrpFromProj, nCath1);
1518 vectorPrintShort(" projGrpToCathGrp", projGrpToCathGrp, nGrp + 1);
1519 }
1520 //
1521 // Renumering cathodes groups
1522 // Desactivated ???
1523 int nNewGrp = renumberGroupsFromMap(projGrpToCathGrp, nGrp);
1524 // Test if renumbering is necessary
1525 if (nNewGrp != nGrp) {
1526 // Perform the renumbering
1527 vectorMapShort(cath0ToGrpFromProj, projGrpToCathGrp, nCath0);
1528 vectorMapShort(cath1ToGrpFromProj, projGrpToCathGrp, nCath1);
1529 }
1530 //
1531 //
1532 // int nNewGrp = nGrp;
1533 //
1534 // Set/update the cath/proj Groups
1535 // vectorCopyShort( cath0ToGrpFromProj, nCath0, cathGroup[0]);
1536 // vectorCopyShort( cath1ToGrpFromProj, nCath1, cathGroup[1]);
1537 //
1538 for (i = 0; i < nProjPads; i++) {
1539 projPadToGrp[i] = projGrpToCathGrp[projPadToGrp[i]];
1540 }
1541
1543 vectorPrintShort(" projPadToGrp", projPadToGrp, nProjPads);
1544 vectorPrintShort(" cath0ToGrp", cathGroup[0], nCath0);
1545 vectorPrintShort(" cath1ToGrp", cathGroup[1], nCath1);
1546 }
1547 //
1548 return nNewGrp;
1549}
1550
1552{
1553 int nbrOfPads = 0;
1554 for (int c = 0; c < 2; c++) {
1555 int nbrPads = getNbrOfPads(c);
1556 for (int p = 0; p < nbrPads; p++) {
1557 if (cathGroup[c][p] == g) {
1558 nbrOfPads++;
1559 }
1560 }
1561 }
1562 return nbrOfPads;
1563}
1564
1565std::pair<double, double> ClusterPEM::computeChargeBarycenter(int plane)
1566{
1567 int cStart(0), cEnd(0);
1568 if (plane == -1) {
1569 cStart = 0;
1570 cEnd = 2;
1571 } else if (plane == 0) {
1572 cStart = 0;
1573 cEnd = 1;
1574 } else {
1575 cStart = 1;
1576 cEnd = 2;
1577 }
1578 double xBary(0), yBary(0), wCharges(0);
1579 for (int c = cStart; c < cEnd; c++) {
1580 int P = getNbrOfPads(c);
1581 if (P > 0) {
1582 const double* charges = getCharges(c);
1583 const double* X = getPads(c)->getX();
1584 const double* Y = getPads(c)->getY();
1585 for (int p = 0; p < P; p++) {
1586 xBary += charges[p] * X[p];
1587 yBary += charges[p] * Y[p];
1588 wCharges += charges[p];
1589 }
1590 }
1591 }
1592 xBary = xBary / wCharges;
1593 yBary = yBary / wCharges;
1594 //
1595 return std::make_pair(xBary, yBary);
1596}
1597
1598std::pair<int, int> ClusterPEM::getNxNy(int c)
1599{
1600 int N = pads[c]->getNbrOfObsPads();
1601 const double* x = pads[c]->getX();
1602 const double* y = pads[c]->getY();
1603 const double* dx = pads[c]->getDX();
1604 const double* dy = pads[c]->getDY();
1605 double xMin = vectorMin(x, N);
1606 double xMax = vectorMax(x, N);
1607 double yMin = vectorMin(y, N);
1608 double yMax = vectorMax(y, N);
1609 double dxMin = 2 * vectorMin(dx, N);
1610 double dyMin = 2 * vectorMin(dy, N);
1611 // For allocation
1612 int nXMax = (int)((xMax - xMin) / dxMin + 0.5) + 1;
1613 int nYMax = (int)((yMax - yMin) / dyMin + 0.5) + 1;
1614 Mask_t xSampling[nXMax];
1615 Mask_t ySampling[nYMax];
1616 vectorSetShort(xSampling, 0, nXMax);
1617 vectorSetShort(ySampling, 0, nYMax);
1618 int nX(0), nY(0);
1619 for (int i = 0; i < N; i++) {
1620 // Calculate the indexes in the 1D charge integral
1621 // PadIntegralX:PadIntegralY
1622 int xIdx = (int)((x[i] - xMin) / dxMin + 0.5);
1623 int yIdx = (int)((y[i] - yMin) / dyMin + 0.5);
1624 if (xSampling[xIdx] == 0) {
1625 // printf("new x, iIdx=%d, x[i]=%6.2f, xMin=%6.2f, dxMin=%6.2f\n", xIdx, x[i], xMin, dxMin );
1626 xSampling[xIdx] = 1;
1627 nX++;
1628 }
1629 if (ySampling[yIdx] == 0) {
1630 // printf("new y, yIdx=%d, y[i]=%6.2f, yMin=%6.2f, dyMin=%6.2f\n", yIdx, y[i], yMin, dyMin );
1631 ySampling[yIdx] = 1;
1632 nY++;
1633 }
1634 }
1635 return std::make_pair(nX, nY);
1636}
1637
1638void ClusterPEM::removeLowChargedGroups(int nGroups)
1639{
1640 int nbrPadsInGroup[2][nGroups + 1];
1641 double chargeInGroup[2][nGroups + 1];
1642 vectorSetInt(nbrPadsInGroup[0], 0, nGroups);
1643 vectorSetInt(nbrPadsInGroup[1], 0, nGroups);
1644 vectorSet(chargeInGroup[0], 0, nGroups);
1645 vectorSet(chargeInGroup[1], 0, nGroups);
1646 int nbrCath = 0;
1647 //
1648 // Compute the total charge of a group
1649 for (int c = 0; c < 2; c++) {
1650 int nbrPads = pads[c]->getNbrOfPads();
1651 const double* q = pads[c]->getCharges();
1652 nbrCath += (nbrPads != 0) ? 1 : 0;
1653 for (int p = 0; p < nbrPads; p++) {
1654 nbrPadsInGroup[c][cathGroup[c][p]]++;
1655 chargeInGroup[c][cathGroup[c][p]] += q[p];
1656 }
1657 }
1658
1659 char str[256];
1660 for (Groups_t g = 1; g < nGroups + 1; g++) {
1661 // Better to use max charge of the two cath-planes
1662 double chargePerCath = chargeInGroup[0][g] + chargeInGroup[1][g];
1663 chargePerCath = chargePerCath / 2;
1664 double maxCharge = std::fmax(chargeInGroup[0][g], chargeInGroup[1][g]);
1665 int nbrPads = nbrPadsInGroup[0][g] + nbrPadsInGroup[1][g];
1666 if ((maxCharge < clusterConfig.minChargeOfClusterPerCathode) && (nbrPads > 0)) {
1667 // if ((chargePerCath < clusterConfig.minChargeOfClusterPerCathode) && (nbrPads > 0)) {
1668 // Remove groups
1669 // printf(" Remove group %d, charge=%f\n", g, charge);
1670 // scanf("%s", str);
1671 // Suppress the pads
1672 for (int c = 0; c < 2; c++) {
1673 int nbrPads = pads[c]->getNbrOfPads();
1674 for (int p = 0; p < nbrPads; p++) {
1675 if (cathGroup[c][p] == g) {
1676 cathGroup[c][p] = 0;
1677 }
1678 }
1679 }
1681 int nbrPads = chargeInGroup[0][g] + chargeInGroup[1][g];
1682 printf("> [removeLowChargedGroups] Remove low charge group g=%d, charge per cath= %f, #pads=%d \n", g, maxCharge, nbrPads);
1683 }
1684 }
1685 }
1687 vectorPrintShort(" cathToGrp[0]", cathGroup[0], pads[0]->getNbrOfPads());
1688 vectorPrintShort(" cathToGrp[1]", cathGroup[1], pads[1]->getNbrOfPads());
1689 }
1690}
1691
1692int ClusterPEM::filterFitModelOnSmallChargedSeeds(Pads& pads, double* theta, int K,
1693 Mask_t* maskFilteredTheta)
1694{
1695 //
1696 // W filter
1697 // w cut-off
1698 double* w_ = getW(theta, K);
1699 double w[K];
1700 double wSum = 0.0;
1701 int kSelectedInit = vectorSumShort(maskFilteredTheta, K);
1702 double meanCharge = pads.getMeanTotalCharge();
1703 // Old relative filter ???
1704 // double cutOff = 0.02 / kSelectedSeeds;
1705 // meanCharge = 1.0;
1706 //
1708 // Normalize new w
1709 for (int k = 0; k < K; k++) {
1710 wSum += (maskFilteredTheta[k] * w_[k]);
1711 }
1712 int kWFilter = 0;
1713 double norm = meanCharge / wSum;
1714 for (int k = 0; k < K; k++) {
1715 w[k] = maskFilteredTheta[k] * w_[k] * norm;
1716 if ((clusterConfig.processingLog >= clusterConfig.info) && (maskFilteredTheta[k] && (w[k] <= cutOff))) {
1717 printf("[filterFitModelOnSmallCharge] remove the %dth seeds, low charge=%f \n", k, w[k]);
1718 }
1719 maskFilteredTheta[k] = maskFilteredTheta[k] && (w[k] > cutOff);
1720 kWFilter += (maskFilteredTheta[k] && (w[k] > cutOff));
1721 }
1722 if ((clusterConfig.processingLog >= clusterConfig.info) && (kSelectedInit > kWFilter)) {
1723 printf("[filterFitModelOnSmallCharge] remove %d seeds (cutOff=%5.2f)\n",
1724 kSelectedInit - kWFilter, cutOff);
1725 }
1726 return kWFilter;
1727}
1728
1729// Remove the seeds outside of the frame delimiting the cluster.
1730int ClusterPEM::filterFitModelOnClusterRegion(Pads& pads, double* theta, int K,
1731 Mask_t* maskFilteredTheta)
1732{
1733 //
1734 // Spatial filter
1735 //
1736 const double* x = pads.getX();
1737 const double* y = pads.getY();
1738 const double* dx = pads.getDX();
1739 const double* dy = pads.getDY();
1740 int N = pads.getNbrOfPads();
1741 // Compute the frame enclosing the pads Min/Max x/y
1742 double xyTmp[N];
1743 int kSpacialFilter = 0;
1744 vectorAddVector(x, -1.0, dx, N, xyTmp);
1745 double xMin = vectorMin(xyTmp, N);
1746 vectorAddVector(x, +1.0, dx, N, xyTmp);
1747 double xMax = vectorMax(xyTmp, N);
1748 vectorAddVector(y, -1.0, dy, N, xyTmp);
1749 double yMin = vectorMin(xyTmp, N);
1750 vectorAddVector(y, +1.0, dy, N, xyTmp);
1751 double yMax = vectorMax(xyTmp, N);
1752 double* muX = getMuX(theta, K);
1753 double* muY = getMuY(theta, K);
1754 for (int k = 0; k < K; k++) {
1755 maskFilteredTheta[k] = 0;
1756 if ((muX[k] > xMin) && (muX[k] < xMax)) {
1757 if ((muY[k] > yMin) && (muY[k] < yMax)) {
1758 maskFilteredTheta[k] = 1;
1759 kSpacialFilter++;
1760 }
1761 }
1762 }
1763
1764 if ((clusterConfig.processingLog >= clusterConfig.info) && (kSpacialFilter != K)) {
1765 printf("[filterFitModelOnClusterRegion] ---> Out of the frame; removing %d hit\n", K - kSpacialFilter);
1766 }
1767 //
1768 // W filter
1769 // w cut-off
1770 double cutOff = 0.02 / kSpacialFilter;
1771 //
1772 double* w_ = getW(theta, K);
1773 double w[K];
1774 double wSum = 0.0;
1775 // Normalize new w
1776 for (int k = 0; k < K; k++) {
1777 wSum += (maskFilteredTheta[k] * w_[k]);
1778 }
1779 int kWFilter = 0;
1780 double norm = 1.0 / wSum;
1781 for (int k = 0; k < K; k++) {
1782 w[k] = maskFilteredTheta[k] * w_[k] * norm;
1783 maskFilteredTheta[k] = maskFilteredTheta[k] && (w[k] > cutOff);
1784 kWFilter += (maskFilteredTheta[k] && (w[k] > cutOff));
1785 }
1786 if ((clusterConfig.processingLog >= clusterConfig.detail) && (kSpacialFilter > kWFilter)) {
1787 printf(
1788 "[filterFitModelOnClusterRegion] At least one hit such as w[k] < "
1789 "(0.05 / K) = %8.4f) -> removing %d hit\n",
1790 cutOff, kSpacialFilter - kWFilter);
1791 }
1792 return kWFilter;
1793}
1794
1795// Remove seeds which drift from the EM solutions
1796// And remove close seeds
1797int ClusterPEM::filterFitModelOnSpaceVariations(const double* thetaEM, int kEM,
1798 double* thetaFit, int kFit,
1799 Mask_t* maskFilteredTheta)
1800{
1801 // Rq: kFit is the same for thetaEM & theta
1802
1803 int kSpacialFilter = 0;
1804 //
1805 // Spatial filter on the theta deplacements
1806 //
1807 const double* muEMX = getConstMuX(thetaEM, kEM);
1808 const double* muEMY = getConstMuY(thetaEM, kEM);
1809 const double* muEMDx = getConstVarX(thetaEM, kEM);
1810 const double* muEMDy = getConstVarY(thetaEM, kEM);
1811 double* muX = getMuX(thetaFit, kFit);
1812 double* muY = getMuY(thetaFit, kFit);
1813 double xTmp[kEM], yTmp[kEM];
1814
1815 // The order of thetaEM and thetaFit can be change
1816 // So take the the min distance
1817 for (int k = 0; k < kFit; k++) {
1818 // Find the the nearest seed mu[k](fit) of muEM[k]
1819 // Compute the distances to mu[k]
1820 vectorAddScalar(muEMX, -muX[k], kEM, xTmp);
1821 vectorMultVector(xTmp, xTmp, kEM, xTmp);
1822 vectorAddScalar(muEMY, -muY[k], kEM, yTmp);
1823 vectorMultVector(yTmp, yTmp, kEM, yTmp);
1824 vectorAddVector(xTmp, 1.0, yTmp, kEM, xTmp);
1825 // muEM[kMin] is the nearest seeds of mu[k]
1826 int kMin = vectorArgMin(xTmp, kEM);
1827 // printf("??? kMin=%d, dx=%f, dy=%f\n", kMin, muEMDx[k], muEMDy[k]);
1828 //
1829 // Build the frame around muEM[kMin] with a border
1830 // of 1.5 times the pixel size
1831 double xMin = muEMX[kMin] - 3 * muEMDx[kMin];
1832 double xMax = muEMX[kMin] + 3 * muEMDx[kMin];
1833 double yMin = muEMY[kMin] - 3 * muEMDy[kMin];
1834 double yMax = muEMY[kMin] + 3 * muEMDy[kMin];
1835 // Select Seeds which didn't move with the fitting
1836 if (((muX[k] > xMin) && (muX[k] < xMax)) &&
1837 ((muY[k] > yMin) && (muY[k] < yMax))) {
1838 // maskFilteredTheta[k] = 1;
1839 kSpacialFilter++;
1840 } else {
1842 printf("[filterFitModelOnSpaceVariations] ---> too much drift; deltaX/Y=(%6.2f,%6.2f) ---> k=%3d removed\n",
1843 muEMX[k] - muX[k], muEMY[k] - muY[k], k);
1844 printf("[filterFitModelOnSpaceVariations] ---> too much drift; EM=(%6.2f,%6.2f) dxyEM=(%6.2f,%6.2f) Fit=(%6.2f,%6.2f)\n",
1845 muEMX[k], muEMY[k], muEMDx[k], muEMDy[k], muX[k], muY[k]);
1846 // printf(" ??? muEMDx[kMin], muEMDy[kMin] = %f, %f\n", muEMDx[kMin], muEMDy[kMin]);
1847 }
1848 // Disable this seeds
1849 maskFilteredTheta[k] = 0;
1850 }
1851 }
1852 if ((clusterConfig.processingLog >= clusterConfig.info) && (kSpacialFilter != kFit)) {
1853 printf("[filterFitModelOnSpaceVariations] ---> Final filter: %d hit(s) removed\n", kFit - kSpacialFilter);
1854 }
1855 //
1856 // Suppress close seeds ~< 0.5 pad size
1857 // ??? inv double* muDX = getVarX(thetaFit, kFit);
1858 // ??? double* muDY = getVarY(thetaFit, kFit);
1859 double* w = getW(thetaFit, kFit);
1860 for (int k = 0; k < kFit; k++) {
1861 if (maskFilteredTheta[k]) {
1862 for (int l = k + 1; l < kFit; l++) {
1863 if (maskFilteredTheta[l]) {
1864 // Errror X/Y is the size of a projected pad
1865 double maxErrorX = 2.0 * std::fmin(muEMDx[k], muEMDx[l]);
1866 double maxErrorY = 2.0 * std::fmin(muEMDy[k], muEMDy[l]);
1867 bool xClose = std::fabs(muX[k] - muX[l]) < maxErrorX;
1868 bool yClose = std::fabs(muY[k] - muY[l]) < maxErrorY;
1869 // printf(" ??? Close seeds muX k/l= %f, %f, muDX K/l= %f, %f\n", muX[k], muX[l], muEMDx[k], muEMDx[l]);
1870 // printf(" ??? Close seeds muY k/l= %f, %f, muDY K/l= %f, %f\n", muY[k], muY[l], muEMDy[k], muEMDy[l]);
1871 if (xClose && yClose) {
1872 // Supress the weakest weight
1873 if (w[k] > w[l]) {
1874 maskFilteredTheta[l] = 0;
1875 w[k] += w[l];
1876 } else {
1877 maskFilteredTheta[k] = 0;
1878 w[l] += w[k];
1879 }
1880 }
1881 }
1882 }
1883 }
1884 }
1885 int kCloseFilter = vectorSumShort(maskFilteredTheta, kFit);
1886 if (clusterConfig.processingLog >= clusterConfig.info && (kSpacialFilter > kCloseFilter)) {
1887 printf(
1888 "[filterFitModelOnSpaceVariations] ---> Close seeds: removed %d close seeds\n",
1889 kSpacialFilter - kCloseFilter);
1890 }
1891 return kCloseFilter;
1892}
1893
1894DataBlock_t ClusterPEM::fit(double* thetaInit, int kInit)
1895{
1896 int nbrCath0 = getNbrOfPads(0);
1897 int nbrCath1 = getNbrOfPads(1);
1898 int nFit = nbrCath0 + nbrCath1;
1899 int nObsFit = getNbrOfObsPads();
1900 // double *xyDxyFit;
1901 // double *qFit;
1902 int filteredK = 0;
1903 int finalK = 0;
1904 // ThetaFit (output)
1905 double* thetaFit = new double[kInit * 5];
1906 vectorSet(thetaFit, 0, kInit * 5);
1907 int nX(0), nY(0);
1908 if (nbrOfCathodePlanes == 1) {
1909 std::pair<int, int> nXY = getNxNy(singleCathPlaneID);
1910 nX = nXY.first;
1911 nY = nXY.second;
1912 }
1913 /*
1914 else if( getNbrOfObsPads(0) + getNbrOfObsPads(1) < 5 ) {
1915 // ??? maybe to perform before LocalMax
1916 std::pair<int,int> nXY0 = getNxNy(0);
1917 std::pair<int,int> nXY1 = getNxNy(1);
1918 int n
1919 if( (nXY0.second == 1) && (nXY1.first == 1) ) {
1920
1921 }
1922 }
1923 */
1924 // Parameters dimensionality - Default (w,x, y)
1925 int dimOfParameters = 3;
1926 // Which axe to perform the fitting x(axe=0) or y(axe=1) or both (axe=-1)
1927 int axe = -1;
1928
1929 Pads* fitPads = nullptr;
1930
1931 if ((kInit == 1) && (nbrOfCathodePlanes == 1)) {
1932 // Get the Charge centroid to go closer to the seed
1933 std::pair<double, double> bary = computeChargeBarycenter(singleCathPlaneID);
1934 double* muX = getMuX(thetaInit, kInit);
1935 double* muY = getMuY(thetaInit, kInit);
1936 // double *w = getW(thetaInit, kInit);
1937 muX[0] = bary.first;
1938 muY[0] = bary.second;
1939 }
1941 printf("fit nbrCath=%d nbrPads=(%d, %d) nbrObsPads=(%d, %d) nX/Y=(%d, %d)\n",
1942 nbrOfCathodePlanes, getNbrOfPads(0), getNbrOfPads(1),
1943 getNbrOfObsPads(0), getNbrOfObsPads(1), nX, nY);
1944 }
1945 // Simple cases
1946 if ((nbrOfCathodePlanes == 1) && ((nX == 1) || (nY == 1))) {
1947 dimOfParameters = 2;
1948 // axe to fit
1949 axe = (nX == 1) ? 1 : 0;
1950 fitPads = pads[singleCathPlaneID];
1951 pads[singleCathPlaneID]->setCathodes(singleCathPlaneID);
1952
1953 } else {
1954 // Concatenate the 2 planes of the subCluster For the fitting
1955 fitPads = new Pads(pads[0], pads[1], Pads::PadMode::xydxdyMode);
1956 }
1957 // Compute the barycenter to speed
1958 /*
1959 double xBary(0), yBary(0), wCharges(0);
1960 for(int c=0; c <2; c++) {
1961 if ( getNbrOfPads(c) > 0) {
1962 const double *charges = getCharges(c);
1963 const double *X = getPads(c)->getX();
1964 const double *Y = getPads(c)->getY();
1965 for (int p=0; p < getNbrOfPads(c); p++) {
1966 xBary += charges[p] * X[p];
1967 yBary += charges[p] * Y[p];
1968 wCharges += charges[p];
1969 }
1970 }
1971 }
1972 xBary = xBary / wCharges;
1973 yBary = yBary / wCharges;
1974 double *muX = getMuX(thetaFit, kInit);
1975 double *muY = getMuY(thetaFit, kInit);
1976 double *w = getW(thetaFit, kInit);
1977 muX[0] = xBary;
1978 muY[0] = yBary;
1979 w[0] = 1.0;
1980 finalK = 1;
1981 */
1982 if ((nObsFit > 1) && (nObsFit < clusterConfig.nbrOfPadsLimitForTheFitting)) {
1983 //
1984 // Preparing the fitting
1985 //
1986 /*
1987 xyDxyFit = new double[nFit*4];
1988 qFit = new double[nFit];
1989 Mask_t cathFit[nFit];
1990 Mask_t notSaturatedFit[nFit];
1991 */
1992 //
1993
1994 // ??? Pads::printPads("Pads for fitting", *fitPads);
1995 // khi2 (output)
1996 double khi2[1];
1997 // pError (output)
1998 // double pError[3 * kInit * 3 * kInit];
1999 double pError[dimOfParameters * kInit * dimOfParameters * kInit];
2001 printf("Starting the fitting\n");
2002 printf("- # cath0, cath1 for fitting: %2d %2d\n", getNbrOfPads(0),
2003 getNbrOfPads(1));
2004 printTheta("- thetaInit", 1.0, thetaInit, kInit);
2005 }
2006 // Fit
2007 if ((kInit * dimOfParameters - 1) <= nFit) {
2008 // if ((kInit * 3 - 1) <= nFit) {
2009 /*
2010 fitMathieson( thetaInit, xyDxyFit, qFit, cathFit, notSaturatedFit,
2011 zCathTotalCharge, K, nFit, chamberId, processFitVerbose, thetaFit, khi2,
2012 pError
2013 );
2014 */
2015 fitMathieson(*fitPads, thetaInit, kInit, dimOfParameters, axe, processFitVerbose, thetaFit,
2016 khi2, pError);
2017 } else {
2018 printf("---> Fitting parameters to large : k=%d, (3 or 2)*k-1=%d, nFit=%d\n",
2019 kInit, kInit * dimOfParameters - 1, nFit);
2020 printf(" keep the EM solution\n");
2021 vectorCopy(thetaInit, kInit * 5, thetaFit);
2022 }
2024 printTheta("- thetaFit", 1.0, thetaFit, kInit);
2025 }
2026 // Filter Fitting solution
2027 Mask_t maskFilterFit[kInit];
2028 // select all
2029 vectorSetShort(maskFilterFit, 1, kInit);
2030 int filteredK(0);
2031 // filteredK =
2032 // filterFitModelOnClusterRegion(*fitPads, thetaFit, kInit, maskFilterFit);
2033
2034 // WARNING: can't used because of the fitting permutation
2035 // filteredK = filterFitModelOnSpaceVariations( thetaInit, kInit,
2036 // thetaFit, kInit, maskFilterFit);
2037 // Remove small Cluster Charge
2038 filteredK = filterFitModelOnSmallChargedSeeds(*fitPads, thetaFit, kInit,
2039 maskFilterFit);
2040 double filteredTheta[5 * filteredK];
2041 if ((filteredK != kInit) && (nFit >= filteredK)) {
2043 printf("Filtering the fitting K=%d >= K=%d\n", nFit, filteredK);
2044 // ??? Inv printTheta("- filteredTheta", filteredTheta, filteredK);
2045 }
2046 if (filteredK > 0) {
2047 maskedCopyTheta(thetaFit, kInit, maskFilterFit, kInit, filteredTheta,
2048 filteredK);
2049 /*
2050 fitMathieson(*fitPads, filteredTheta, filteredK, dimOfParameters, axe, processFitVerbose,
2051 filteredTheta, khi2, pError);
2052 delete[] thetaFit;
2053 thetaFit = new double[filteredK * 5];
2054 */
2055 copyTheta(filteredTheta, filteredK, thetaFit, filteredK, filteredK);
2056 finalK = filteredK;
2057 } else {
2058 // No hit with the fitting
2059 // ???? vectorCopy(thetaInit, kInit * 5, thetaFit);
2060 finalK = 0;
2061 }
2062 } else {
2063 // ??? InvvectorCopy( thetaFit, K*5, thetaFitFinal);
2064 // Don't Filter, theta resul in "thetaFit"
2065 finalK = kInit;
2066 }
2067 } else {
2068 // Keep "thetaInit (not enough pads)
2069 // or only one pad
2071 printf("[Cluster.fit] nbrOfPadsLimit reach. Keep the EM Result: nFit=%d >= nbrOfPadsLimitForTheFitting=%d\n",
2073 }
2074 vectorCopy(thetaInit, kInit * 5, thetaFit);
2075 finalK = kInit;
2076 }
2077 if (axe == -1) {
2078 delete fitPads;
2079 }
2080 return std::make_pair(finalK, thetaFit);
2081}
2082
2083// Old release
2084// Invalid, Should be removed
2085int ClusterPEM::renumberGroupsFromMap(short* grpToGrp, int nGrp)
2086{
2087 // short renumber[nGrp+1];
2088 // vectorSetShort( renumber, 0, nGrp+1 );
2089 int maxIdx = vectorMaxShort(grpToGrp, nGrp + 1);
2090 std::vector<short> counters(maxIdx + 1);
2091 vectorSetShort(counters.data(), 0, maxIdx + 1);
2092
2093 for (int g = 1; g <= nGrp; g++) {
2094 if (grpToGrp[g] != 0) {
2095 counters[grpToGrp[g]]++;
2096 }
2097 }
2098 int curGrp = 0;
2099 for (int g = 1; g <= maxIdx; g++) {
2100 if (counters[g] != 0) {
2101 curGrp++;
2102 counters[g] = curGrp;
2103 }
2104 }
2105 // Now counters contains the mapping oldGrp -> newGrp
2106 for (int g = 1; g <= nGrp; g++) {
2107 grpToGrp[g] = counters[grpToGrp[g]];
2108 }
2109 return curGrp;
2110}
2111
2112int ClusterPEM::renumberGroups(Mask_t* grpToGrp, int nGrp)
2113{
2114 int currentGrp = 0;
2115 for (int g = 0; g < (nGrp + 1); g++) {
2116 grpToGrp[g] = 0;
2117 }
2118 for (int c = 0; c < 2; c++) {
2119 Mask_t* cathToGrp = cathGroup[c];
2120 int nbrCath = pads[c]->getNbrOfPads();
2121 for (int p = 0; p < nbrCath; p++) {
2122 int g = cathToGrp[p];
2123 if (g != 0) {
2124 // Not the background group
2125 // ??? printf(" p=%d, g[p]=%d, grpToGrp[g]=%d\n", p, g, grpToGrp[g]);
2126 if (grpToGrp[g] == 0) {
2127 // It's a new Group
2128 currentGrp++;
2129 // Update the map and the cath-group
2130 grpToGrp[g] = currentGrp;
2131 cathToGrp[p] = currentGrp;
2132 } else {
2133 // The cath-pad takes the group of the map (new numbering)
2134 cathToGrp[p] = grpToGrp[g];
2135 }
2136 }
2137 }
2138 }
2139 int newNbrGroups = currentGrp;
2141 printf("> Groups renumbering [renumberGroups] newNbrGroups=%d\n",
2142 newNbrGroups);
2143 vectorPrintShort(" cath0ToGrp", cathGroup[0], pads[0]->getNbrOfPads());
2144 vectorPrintShort(" cath1ToGrp", cathGroup[1], pads[1]->getNbrOfPads());
2145 }
2146 return newNbrGroups;
2147}
2148
2149Pads* ClusterPEM::findLocalMaxWithRefinement(double* thetaL, int nbrOfPadsInTheGroupCath)
2150{
2151
2153 // Already done if 1 group
2154 Pads* cath0 = pads[0];
2155 Pads* cath1 = pads[1];
2156 Pads* projPads = projectedPads;
2157 // Compute the charge weight of each cathode
2158 double cWeight0 = getTotalCharge(0);
2159 double cWeight1 = getTotalCharge(1);
2160 double preClusterCharge = cWeight0 + cWeight1;
2161 cWeight0 /= preClusterCharge;
2162 cWeight1 /= preClusterCharge;
2163 int nMaxPads = std::fmax(getNbrOfPads(0), getNbrOfPads(1));
2164 double dxMinPadSize = 1000.0;
2165 double dyMinPadSize = 1000.0;
2166 double minDY[2] = {1000.0, 1000.0};
2167 int n0 = getNbrOfObsPads(0);
2168 int n1 = getNbrOfObsPads(1);
2169 if (n0) {
2170 dxMinPadSize = vectorMin(cath0->getDX(), n0);
2171 }
2172 if (n1) {
2173 dyMinPadSize = vectorMin(cath1->getDY(), n1);
2174 }
2175 //
2176 int chId = chamberId;
2178 printf(" - [findLocalMaxWithRefinement]\n");
2179 }
2180
2181 // Over allocate pixel for the refinement
2182 int maxNbrOfPixels = 4 * projPads->getNbrOfPads();
2183 // Call constructor with maxNbrOfPixels over allocation
2184 Pads* pixels = new Pads(projPads, maxNbrOfPixels);
2185 int nPixels = pixels->getNbrOfPads();
2186 // Merge pads of the 2 cathodes
2187 // TODO ??? : see if it can be once with Fitting (see fitPads)
2188 Pads* mergedPads = new Pads(pads[0], pads[1], Pads::PadMode::xyInfSupMode);
2189 int nPads = mergedPads->getNbrOfPads();
2190 // Local maximum locations
2191 Pads* localMax = nullptr;
2192 Pads* saveLocalMax = nullptr;
2193 std::pair<double, double> chi2;
2194 int dof, nParameters;
2195 // Pixel initilization
2196 // Rq: the charge projection is not used
2197 pixels->setCharges(1.0);
2198 // The field saturate is use to tag pixels as already refined
2199 pixels->setSaturate(0);
2200 // Init Cij
2201 double* Cij = new double[nPads * maxNbrOfPixels];
2202 // ??? to be removed : MaskCij Not used
2203 // MaskCij: Used to disable Cij contribution (disable pixels)
2204 Mask_t* maskCij = new Mask_t[nPads * maxNbrOfPixels];
2205 // Compute pad charge (xyInfSup mode) induced with a set of charge (the pixels)
2206 // computeCij(*mergedPads, *pixels, Cij);
2207 computeFastCij(*mergedPads, *pixels, Cij);
2208
2209 //
2210 // Check computeFastCij
2212 // Mode abort (-1)
2213 checkCij(*mergedPads, *pixels, Cij, -1);
2214 }
2215
2216 // Init loop
2217 int nbrLocalMax = 0;
2218 int nbrPrevLocalMax = 0;
2219 double previousCriterion = DBL_MAX;
2220 double criterion = DBL_MAX;
2221 bool goon = true;
2222 int macroIt = 0;
2224 printf(
2225 " Macro nParam ndof ndof chi2 chi2/ndof chi2/ndof chi2/ndof chi2/ndof ch2/ndof\n"
2226 " It. - cath0 cath1 - - cath-0 cath-1 sum 0/1 weight-sum\n");
2227 }
2228
2229 while (goon) {
2230 // Save previous local maxima and the criterion
2231 if (localMax != nullptr) {
2232 if (saveLocalMax != nullptr) {
2233 delete saveLocalMax;
2234 }
2235 saveLocalMax = new Pads(*localMax, o2::mch::Pads::PadMode::xydxdyMode);
2236 }
2237 previousCriterion = criterion;
2238
2239 chi2 =
2240 PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, 0, minPadResidues[macroIt],
2241 nIterations[macroIt]);
2242 // Obsolete
2243 // localMax = pixels->clipOnLocalMax(true);
2244
2245 // Find local maxima and set the pixel to be refined in newPixelIdx
2246 std::vector<PadIdx_t> newPixelIdx;
2247 if (localMax != nullptr) {
2248 delete localMax;
2249 }
2250 localMax = pixels->extractLocalMax(newPixelIdx, dxMinPadSize, dyMinPadSize);
2251 nbrLocalMax = newPixelIdx.size();
2252 // Debug
2253 if (0) {
2254 for (int t = 0; t < newPixelIdx.size(); t++) {
2255 int idx = newPixelIdx[t];
2256 printf(" localMax idx=%d, xy(%f, %f), q[idx]=%f, localMax.q[t]=%f max(pixels)=%f \n",
2257 idx, pixels->getX()[idx], pixels->getY()[idx], pixels->getCharges()[idx], localMax->getCharges()[t], vectorMax(pixels->getCharges(), pixels->getNbrOfPads()));
2258 }
2259 }
2260 nParameters = localMax->getNbrOfPads();
2261 dof = nMaxPads - 3 * nParameters + 1;
2262 if (dof == 0) {
2263 dof = 1;
2264 }
2265 double chi20 = chi2.first;
2266 double chi21 = chi2.second;
2267 int ndof0, ndof1;
2268 if (1) {
2269 ndof0 = getNbrOfPads(0) - 3 * nParameters + 1;
2270 ndof1 = getNbrOfPads(1) - 3 * nParameters + 1;
2271 } else {
2272 ndof0 = getNbrOfObsPads(0) - 3 * nParameters + 1;
2273 ndof1 = getNbrOfObsPads(1) - 3 * nParameters + 1;
2274 }
2275 // printf("??? ndof0/1=%d %d \n", ndof0, ndof1);
2276 if ((ndof0 <= 0) && (ndof1 <= 0)) {
2277 // No good discriminant
2278 // Force ndofx = 1
2279 ndof0 = 1;
2280 ndof1 = 1;
2281 }
2282 // ndofx <=0, deseable the cathode contribution
2283 if (ndof0 <= 0) {
2284 ndof0 = 1;
2285 cWeight0 = 0.0;
2286 cWeight1 = 1.0;
2287 }
2288 if (ndof1 <= 0.) {
2289 ndof1 = 1;
2290 cWeight0 = 1.0;
2291 cWeight1 = 0.0;
2292 }
2293
2294 // Model selection criteriom (nbre of parameters/seeds)
2295 // criteriom0 = fabs( (chi20+chi21 / dof));
2296 // criteriom1 = fabs(sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1));
2297 // printf( "??? cWeight0=%f, cWeight1=%f\n", cWeight0, cWeight1);
2298 criterion = cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1);
2299 // Inv ??? 2 2 5272.16 14.24 12.73 10.86 23.59 11.93
2300 // 3 3 4389.29 13.81 12.25 12.52 24.76 12.36
2301
2302 // printf( " ??? cWeight0=%f, sqrt(chi20 / ndof0)=%f, cWeight1=%f, sqrt(chi21 / ndof1)=%f\n", cWeight0, sqrt(chi20 / ndof0), cWeight1, sqrt(chi21 / ndof1));
2303
2305 printf(
2306 " %2d %3d %3d %3d %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
2307 macroIt, nParameters, ndof0, ndof1, chi20 + chi21, sqrt((chi20 + chi21) / dof),
2308 sqrt(chi20 / ndof0), sqrt(chi21 / ndof1),
2309 sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1),
2310 criterion);
2311 }
2313 inspectSavePixels(macroIt, *pixels);
2314 }
2315
2316 // printf("Before refinement pixel.nPads=%d\n", pixels->getNbrOfPads());
2317 pixels->refineLocalMaxAndUpdateCij(*mergedPads, newPixelIdx, Cij);
2318 // printf("After refinement pixel.nPads=%d\n", pixels->getNbrOfPads());
2320 checkCij(*mergedPads, *pixels, Cij, -1);
2321 }
2322
2323 macroIt++;
2324 goon =
2325 ((criterion < 1.0 * previousCriterion) || (macroIt < 3)) && (macroIt < nMacroIterations);
2326 // (criterion < 1.0 * previousCriterion) && (macroIt < nMacroIterations);
2327 // ((criteriom < 1.0 * previousCriteriom) || ( nbrLocalMax > nbrPrevLocalMax)) && (macroIt < nMacroIterations);
2328 nbrPrevLocalMax = nbrLocalMax;
2329 }
2331 if (criterion < 1.0 * previousCriterion) {
2332 delete saveLocalMax;
2333 } else {
2334 delete localMax;
2335 localMax = saveLocalMax;
2336 }
2337
2338 delete pixels;
2339 delete[] Cij;
2340 delete[] maskCij;
2341 delete mergedPads;
2342 return localMax;
2343}
2344
2345Pads* ClusterPEM::findLocalMaxWithoutRefinement(double* thetaL, int nbrOfPadsInTheGroupCath)
2346{
2347
2349 // Already done if 1 group
2350 Pads* cath0 = pads[0];
2351 Pads* cath1 = pads[1];
2352 Pads* projPads = projectedPads;
2353 // Compute the charge weight of each cathode
2354 double cWeight0 = getTotalCharge(0);
2355 double cWeight1 = getTotalCharge(1);
2356 double preClusterCharge = cWeight0 + cWeight1;
2357 cWeight0 /= preClusterCharge;
2358 cWeight1 /= preClusterCharge;
2359 double dxMinPadSize, dyMinPadSize;
2360 int n0 = getNbrOfObsPads(0);
2361 int n1 = getNbrOfObsPads(1);
2362 if (n0) {
2363 dxMinPadSize = 0.5 * vectorMin(cath0->getDX(), n0);
2364 }
2365 if (n1) {
2366 dyMinPadSize = 0.5 * vectorMin(cath1->getDY(), n1);
2367 }
2368 // Choose ???
2369 dxMinPadSize = 1.0e-4;
2370 dyMinPadSize = 1.0e-4;
2371 //
2372 int chId = chamberId;
2374 printf(" - [findLocalMaxWithoutRefinement]\n");
2375 }
2376
2377 int nMaxPads = std::fmax(getNbrOfPads(0), getNbrOfPads(1));
2378
2379 // ??? To Optimize/debug
2380 // Pads* pixels = projPads->refinePads();
2381 // Pads* pixels = projPads;
2382
2383 // Over allocate pixel for the refinement
2384 int maxNbrOfPixels = projPads->getNbrOfPads();
2385 if (maxNbrOfPixels == 0) {
2386 throw std::out_of_range("[findLocalMaxWithoutRefinement] No projected pads");
2387 }
2388 // Call constructor with maxNbrOfPixels over allocation
2389 Pads* pixels = new Pads(projPads, maxNbrOfPixels);
2390 int nPixels = pixels->getNbrOfPads();
2391 // Merge pads of the 2 cathodes
2392 // TODO ??? : see if it can be once with Fitting (see fitPads)
2393 Pads* mergedPads = new Pads(pads[0], pads[1], Pads::PadMode::xyInfSupMode);
2394 int nPads = mergedPads->getNbrOfPads();
2395 // ??? printf(" nbr merged pads = %d\n", nPads);
2396 // Local maximum locations
2397 Pads* localMax = nullptr;
2398 Pads* saveLocalMax = nullptr;
2399 std::pair<double, double> chi2;
2400 int dof, nParameters;
2401 // Pixel initilization
2402 // Rq: the charge projection is not used
2403 pixels->setCharges(1.0);
2404 // The field saturate is use to tag pixels as already refined
2405 pixels->setSaturate(0);
2406 // Init Cij
2407 double* Cij = new double[nPads * maxNbrOfPixels];
2408 // ??? to be removed : MaskCij Not used
2409 // MaskCij: Used to disable Cij contribution (disable pixels)
2410 Mask_t* maskCij = new Mask_t[nPads * maxNbrOfPixels];
2411 // Compute pad charge (xyInfSup mode) induced with a set of charge (the pixels)
2412 // computeCij(*mergedPads, *pixels, Cij);
2413 computeFastCij(*mergedPads, *pixels, Cij);
2414
2415 //
2416 // Check computeFastCij
2418 // Mode abort (-1)
2419 checkCij(*mergedPads, *pixels, Cij, -1);
2420 }
2421
2422 // Init loop
2423 int nbrLocalMax = 0;
2424 int nbrPrevLocalMax = 0;
2425 double previousCriterion = DBL_MAX;
2426 double criterion = DBL_MAX;
2427 bool goon = true;
2428 int macroIt = 0;
2430 printf(
2431 " Macro nParam ndof ndof chi2 chi2/ndof chi2/ndof chi2/ndof chi2/ndof ch2/ndof\n"
2432 " It. - cath0 cath1 - - cath-0 cath-1 sum 0/1 weight-sum\n");
2433 }
2434
2435 int nTotalIterations = nPads / 10;
2436 int chunk = ceil(float(nTotalIterations) / (nMacroIterations + 1));
2437 chunk = std::min(chunk, 5);
2438 for (int it = 0; it < nMacroIterations; it++) {
2439 nIterations[it] = (it + 1) * chunk;
2440 }
2441 nIterations[nMacroIterations - 1] += chunk;
2443 printf(" Macro Iterations: nIterations[0, 1, ..,nMacroIterations-1] = [%d, %d, ..., %d] \n",
2444 nIterations[0], nIterations[1], nIterations[nMacroIterations - 1]);
2445 }
2446 chi2 = PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, 0, 0,
2447 10);
2448 while (goon) {
2449 // Save previous local maxima and the criterion
2450 if (localMax != nullptr) {
2451 if (saveLocalMax != nullptr) {
2452 delete saveLocalMax;
2453 }
2454 saveLocalMax = new Pads(*localMax, o2::mch::Pads::PadMode::xydxdyMode);
2455 }
2456 previousCriterion = criterion;
2457
2458 chi2 =
2459 // PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, 0, minPadResidues[macroIt],
2460 // nIterations[macroIt]);
2461 PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, 0, 0,
2462 10);
2463 // Obsolete
2464 // localMax = pixels->clipOnLocalMax(true);
2465
2466 // Find local maxima and set the pixel to be refined in newPixelIdx
2467 std::vector<PadIdx_t> newPixelIdx;
2468 if (localMax != nullptr) {
2469 delete localMax;
2470 }
2471 localMax = pixels->extractLocalMaxOnCoarsePads_Remanent(newPixelIdx, dxMinPadSize, dyMinPadSize);
2472 // localMax = pixels->extractLocalMaxOnCoarsePads_Remanent( newPixelIdx, -1., -1.);
2473 // localMax = pixels->extractLocalMaxOnCoarsePads( newPixelIdx);
2474 nbrLocalMax = newPixelIdx.size();
2475 // Debug
2476 if (0) {
2477 for (int t = 0; t < newPixelIdx.size(); t++) {
2478 int idx = newPixelIdx[t];
2479 printf(" localMax idx=%d, xy(%f, %f), q[idx]=%f, localMax.q[t]=%f max(pixels)=%f \n",
2480 idx, pixels->getX()[idx], pixels->getY()[idx], pixels->getCharges()[idx], localMax->getCharges()[t], vectorMax(pixels->getCharges(), pixels->getNbrOfPads()));
2481 }
2482 }
2483 nParameters = localMax->getNbrOfPads();
2484 dof = nMaxPads - 3 * nParameters + 1;
2485 if (dof == 0) {
2486 dof = 1;
2487 }
2488 double chi20 = chi2.first;
2489 double chi21 = chi2.second;
2490 int ndof0, ndof1;
2491 if (1) {
2492 ndof0 = getNbrOfPads(0) - 3 * nParameters + 1;
2493 ndof1 = getNbrOfPads(1) - 3 * nParameters + 1;
2494 } else {
2495 ndof0 = getNbrOfObsPads(0) - 3 * nParameters + 1;
2496 ndof1 = getNbrOfObsPads(1) - 3 * nParameters + 1;
2497 }
2498 // printf("??? ndof0/1=%d %d \n", ndof0, ndof1);
2499 if ((ndof0 <= 0) && (ndof1 <= 0)) {
2500 // No good discriminant
2501 // Force ndofx = 1
2502 ndof0 = 1;
2503 ndof1 = 1;
2504 }
2505 // ndofx <=0, deseable the cathode contribution
2506 if (ndof0 <= 0) {
2507 ndof0 = 1;
2508 cWeight0 = 0.0;
2509 cWeight1 = 1.0;
2510 }
2511 if (ndof1 <= 0.) {
2512 ndof1 = 1;
2513 cWeight0 = 1.0;
2514 cWeight1 = 0.0;
2515 }
2516
2517 // Model selection criteriom (nbre of parameters/seeds)
2518 // criteriom0 = fabs( (chi20+chi21 / dof));
2519 // criteriom1 = fabs(sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1));
2520 // printf( "??? cWeight0=%f, cWeight1=%f\n", cWeight0, cWeight1);
2521 criterion = cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1);
2522 // Inv ??? 2 2 5272.16 14.24 12.73 10.86 23.59 11.93
2523 // 3 3 4389.29 13.81 12.25 12.52 24.76 12.36
2524
2525 // printf( " ??? cWeight0=%f, sqrt(chi20 / ndof0)=%f, cWeight1=%f, sqrt(chi21 / ndof1)=%f\n", cWeight0, sqrt(chi20 / ndof0), cWeight1, sqrt(chi21 / ndof1));
2526
2528 printf(
2529 " %2d %3d %3d %3d %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
2530 macroIt, nParameters, ndof0, ndof1, chi20 + chi21, sqrt((chi20 + chi21) / dof),
2531 sqrt(chi20 / ndof0), sqrt(chi21 / ndof1),
2532 sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1),
2533 criterion);
2534 }
2536 inspectSavePixels(macroIt, *pixels);
2537 }
2538
2539 macroIt++;
2540 goon =
2541 ((criterion < 1.0 * previousCriterion) && (macroIt < nMacroIterations));
2542 //((criterion < 1.0 * previousCriterion) || (macroIt < 3)) && (macroIt < nMacroIterations) ;
2543 // (criterion < 1.0 * previousCriterion) && (macroIt < nMacroIterations);
2544 // ((criteriom < 1.0 * previousCriteriom) || ( nbrLocalMax > nbrPrevLocalMax)) && (macroIt < nMacroIterations);
2545 nbrPrevLocalMax = nbrLocalMax;
2546 }
2548 // ??? std::cerr << "Without> del pixel " << pixels << std::endl;
2549 // ??? std::cerr << "Without> del mergedPads " << mergedPads << std::endl;
2550 // ??? std::cerr << "Without> Pass" << std::endl;
2551 if (criterion < 1.0 * previousCriterion) {
2552 delete saveLocalMax;
2553 } else {
2554 delete localMax;
2555 localMax = saveLocalMax;
2556 }
2557 delete pixels;
2558 delete mergedPads;
2559 delete[] Cij;
2560 delete[] maskCij;
2561 return localMax;
2562}
2563
2564int ClusterPEM::findLocalMaxWithPEM(double* thetaL, int nbrOfPadsInTheGroupCath)
2565{
2566
2568 // Already done if 1 group
2569 Pads* cath0 = pads[0];
2570 Pads* cath1 = pads[1];
2571 Pads* projPads = projectedPads;
2572
2573 // Compute the charge weight of each cathode
2574 double cWeight0 = getTotalCharge(0);
2575 double cWeight1 = getTotalCharge(1);
2576 double clusterCharge = cWeight0 + cWeight1;
2577 cWeight0 /= clusterCharge;
2578 cWeight1 /= clusterCharge;
2579 //
2580 int chId = chamberId;
2582 printf(" - [findLocalMaxWithPEM]\n");
2583 }
2584 //
2585 // Trivial cluster : only 1 pads
2586 //
2587 // ??? if (projPads->getNbrOfPads() == 1) {
2588 if (getNbrOfPads() == 1) {
2590 printf(" Trivial case: only one pad\n");
2591 }
2592 // Return the unique local maximum : the center of the pads
2593 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
2594 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
2595 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
2596 double* muDX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
2597 double* muDY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
2598 w[0] = 1.0;
2599 muX[0] = projPads->getX()[0];
2600 muY[0] = projPads->getY()[0];
2601 muDX[0] = projPads->getDX()[0] * 0.5;
2602 muDY[0] = projPads->getDY()[0] * 0.5;
2603 // Return 0 seed if cluster < minClusterCharge
2604 return (clusterCharge < clusterConfig.minChargeOfClusterPerCathode) ? 0 : 1;
2605 }
2606 Pads* localMax = nullptr;
2607
2608 // int nMaxPads = std::fmax(getNbrOfPads(0), getNbrOfPads(1));
2609
2610 //
2611 double minDX[2] = {1000.0, 1000.0};
2612 double minDY[2] = {1000.0, 1000.0};
2613 int n0 = getNbrOfObsPads(0);
2614 int n1 = getNbrOfObsPads(1);
2615 if (n0) {
2616 minDX[0] = vectorMin(cath0->getDX(), n0);
2617 minDY[0] = vectorMin(cath0->getDY(), n0);
2618 }
2619 if (n1) {
2620 minDX[1] = vectorMin(cath1->getDX(), n1);
2621 minDY[1] = vectorMin(cath1->getDY(), n1);
2622 }
2623
2624 // Large pads > 10.0
2625 bool largePads = (minDX[0] > 3.5) || (minDY[1] > 3.5);
2626 if (largePads) {
2627 // printf("??? minDXY %f %f without refinement \n", minDX, minDY);
2628 localMax = findLocalMaxWithoutRefinement(thetaL, nbrOfPadsInTheGroupCath);
2629 } else {
2630 // printf("??? minDXY %f %f with refinement\n", minDX, minDY);
2631 localMax = findLocalMaxWithRefinement(thetaL, nbrOfPadsInTheGroupCath);
2632 }
2633 // Debug ???
2634 /*
2635 for (int k = 0; k < localMax->getNbrOfPads(); k++) {
2636 printf("findLocalMax ??? k=%d q=%f, XY=%f,%f \n", k,
2637 localMax->getCharges()[k], localMax->getX()[k],localMax->getY()[k]);
2638 }
2639 */
2640 //
2641 // Select local Max
2642 // Remove local Max < 0.01 * max(LocalMax)
2643 //
2644 //
2645 // NOT USED ???
2646 //
2647 if (0) {
2648 double cutRatio = 0.01;
2649 double qCut =
2650 cutRatio * vectorMax(localMax->getCharges(), localMax->getNbrOfPads());
2651 int k = 0;
2652 double qSum = 0.0;
2653 // Remove the last hits if > (nMaxPads +1) / 3
2654 int nMaxSolutions =
2655 int((std::max(getNbrOfPads(0), getNbrOfPads(1)) + 1.0) / 3.0);
2656 // if (nMaxSolutions < 1) {
2657 // nMaxSolutions = 1;
2658 //}
2659 // To avoid 0 possibility and give more inputs to the fitting
2660 nMaxSolutions += 1;
2661 int removedLocMax = localMax->getNbrOfPads();
2662
2663 if (localMax->getNbrOfPads() > nMaxSolutions) {
2665 printf("seed selection: nbr Max parameters =%d, nLocMax=%d\n",
2666 nMaxSolutions, localMax->getNbrOfPads());
2667 printf(
2668 "seed selection: Reduce the nbr of solutions to fit: Take %d/%d "
2669 "solutions\n",
2670 nMaxSolutions, localMax->getNbrOfPads());
2671 }
2672 int index[localMax->getNbrOfPads()];
2673 for (int k = 0; k < localMax->getNbrOfPads(); k++) {
2674 index[k] = k;
2675 }
2676 const double* qLocalMax = localMax->getCharges();
2677 std::sort(index, &index[localMax->getNbrOfPads()],
2678 [=](int a, int b) { return (qLocalMax[a] > qLocalMax[b]); });
2679 // Reoder
2680 qCut = qLocalMax[index[nMaxSolutions - 1]] - 1.e-03;
2681 } else {
2683 }
2684 }
2685
2686 // Suppress local max with charge > 70 % of min Charge of a cluster/seeds
2687 double cutRatio = 0.7;
2688 cutRatio = largePads ? 0.0 : cutRatio;
2689 // Local max Charge normalization
2690 // double coef = ( (getNbrOfPads(0) == 0) || (getNbrOfPads(0) == 0) ) ? 1.0 : 0.5
2691 // double meanCharge = coef * (getTotalCharge(0) + getTotalCharge(1));
2692 double qPadMax = getMaxCharge();
2693 double qPixMax = vectorMax(localMax->getCharges(), localMax->getNbrOfPads());
2694 double qCut = cutRatio * clusterConfig.minChargeOfClusterPerCathode * qPixMax / qPadMax;
2695 int k0 = localMax->getNbrOfPads();
2696 int k = localMax->removePads(qCut);
2697 localMax->normalizeCharges();
2698 int removedLocMax = k0 - k;
2699 // printf("k0, k %d %d qCut=%f qPixMax=%f qPadMax=%f\n", k0, k, qCut, qPixMax, qPadMax);
2700 if (clusterConfig.processingLog >= clusterConfig.info && removedLocMax != 0) {
2701 printf(
2702 " > seed selection: Final cut -> %d percent (qcut=%8.2f), number of "
2703 "local max removed = %d\n",
2704 int(cutRatio * 100), qCut, removedLocMax);
2705 }
2706
2707 // Store the local max
2708 int K0 = localMax->getNbrOfPads();
2709 int K = std::min(K0, nbrOfPadsInTheGroupCath);
2710 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
2711 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
2712 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
2713 double* varX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
2714 double* varY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
2715 const double* ql = localMax->getCharges();
2716 const double* xl = localMax->getX();
2717 const double* yl = localMax->getY();
2718 const double* dxl = localMax->getDX();
2719 const double* dyl = localMax->getDY();
2720 for (int k = 0; k < K; k++) {
2721 w[k] = ql[k];
2722 muX[k] = xl[k];
2723 muY[k] = yl[k];
2724 varX[k] = dxl[k];
2725 varY[k] = dyl[k];
2726 if (clusterConfig.processingLog >= clusterConfig.info && removedLocMax != 0) {
2727 printf(" k=%d w=%f, XY=%f,%f varXY=%f,%f\n", k, w[k], muX[k], muY[k], varX[k], varY[k]);
2728 }
2729 }
2730 // printf("K0, K nbrOfPadsInTheGroupCath %d %d %d\n", K0, K, nbrOfPadsInTheGroupCath);
2731 delete localMax;
2732 return K;
2733}
2734
2735// Without ajusted rafinement
2736int ClusterPEM::findLocalMaxWithPEMFullRefinement(double* thetaL, int nbrOfPadsInTheGroupCath)
2737{
2738
2740 // Already done if 1 group
2741 Pads* cath0 = pads[0];
2742 Pads* cath1 = pads[1];
2743 Pads* projPads = projectedPads;
2744 // Compute the charge weight of each cathode
2745 double cWeight0 = getTotalCharge(0);
2746 double cWeight1 = getTotalCharge(1);
2747 double preClusterCharge = cWeight0 + cWeight1;
2748 cWeight0 /= preClusterCharge;
2749 cWeight1 /= preClusterCharge;
2750 //
2751 int chId = chamberId;
2753 printf(" - [findLocalMaxWithPEM]\n");
2754 }
2755 // Trivial cluster : only 1 pads
2756 if (projPads->getNbrOfPads() == 1) {
2757 // Return the unique local maximum : the center of the pads
2758 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
2759 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
2760 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
2761 double* muDX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
2762 double* muDY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
2763 w[0] = 1.0;
2764 muX[0] = projPads->getX()[0];
2765 muY[0] = projPads->getY()[0];
2766 muDX[0] = projPads->getDX()[0] * 0.5;
2767 muDY[0] = projPads->getDY()[0] * 0.5;
2768 return 1;
2769 }
2770 int nMaxPads = std::fmax(getNbrOfPads(0), getNbrOfPads(1));
2771
2772 // ??? To Optimize/debug
2773 Pads* pixels = projPads->refineAll();
2774 // Pads* pixels = projPads;
2775 // Reserve place for refinment
2776 /*
2777 int maxNbrOfPixels = 4*projPads->getNbrOfPads();
2778 Pads* pixels = new Pads(projPads, maxNbrOfPixels);
2779 printf("pixel allocation %d\n", maxNbrOfPixels);
2780 */
2781 int nPixels = pixels->getNbrOfPads();
2782 // Merge pads of the 2 cathodes
2783 // TODO ??? : see if it can be once with Fitting (see fitPads)
2784 Pads* mergedPads = new Pads(pads[0], pads[1], Pads::PadMode::xyInfSupMode);
2785 int nPads = mergedPads->getNbrOfPads();
2786 Pads* localMax = nullptr;
2787 Pads* saveLocalMax = nullptr;
2788 std::pair<double, double> chi2;
2789 int dof, nParameters;
2790 Pads::printPads("???????? mergedPads", *mergedPads);
2791 // Pixel initilization
2792 // Rq: the charge projection is not used
2793 pixels->setCharges(1.0);
2794 // The field saturate is use to tag pixels already refined
2795 // no refinment
2796 // pixels->setSaturate(0);
2797 // Init Cij
2798 double* Cij = new double[nPads * nPixels];
2800 // MaskCij: Used to disable Cij contribution (disable pixels)
2801 Mask_t* maskCij = new Mask_t[nPads * nPixels];
2802 // Mask_t* maskCij = new Mask_t[nPads * maxNbrOfPixels];
2803 // Compute pad charge xyInfSup induiced by a set of charge (the pixels)
2804 computeFastCij(*mergedPads, *pixels, Cij);
2805 // computeCij(*mergedPads, *pixels, Cij);
2806
2807 //
2808 // Check computeFastCij
2809 /*
2810 if (clusterConfig.mathiesonCheck) {
2811 double *CijTmp = new double[nPads*nPixels];
2812 double *diffCij = new double[nPads*nPixels];
2813 computeCij( *mergedPads, *pixels, CijTmp);
2814 vectorAddVector( Cij, -1, CijTmp, nPads*nPixels, diffCij);
2815 vectorAbs( diffCij, nPads*nPixels, diffCij);
2816 double minDiff = vectorMin(diffCij, nPads*nPixels);
2817 double maxDiff = vectorMax(diffCij, nPads*nPixels);
2818 int argMax = vectorArgMax(diffCij, nPads*nPixels);
2819 printf("\n\n nPads, nPixels %d %d\n", nPads, nPixels);
2820 int iIdx = argMax / nPads;
2821 int jIdx = argMax % nPads;
2822 printf("\n\n min/max(FastCij-Cij)=%f %f nPads*i+j %d %d\n", minDiff, maxDiff,
2823 iIdx, jIdx);
2824 printf("\n FastCij=%f differ from Cij=%f\n", Cij[iIdx*nPads+jIdx], CijTmp[iIdx*nPads+jIdx]);
2825 if ( maxDiff > 1.0e-5) {
2826 for( int k=0; k< nPixels; k++) {
2827 for( int l=0; l< nPads; l++) {
2828 if (diffCij[k*nPads+l] >1.0e-5) {
2829 printf("pad=%d pixel=%d FastCij=%f Cij=%f diff=%f\n", l, k, Cij[k*nPads+l], CijTmp[k*nPads+l], diffCij[k*nPads+l]);
2830 }
2831 }
2832 }
2833 printf("findLocalMaxWithPEM: WARNING maxDiff(Cij)=%f\n", maxDiff);
2834 // throw std::out_of_range(
2835 // "[findLocalMaxWithPEM] bad Cij value");
2836 }
2837 delete [] CijTmp;
2838 }
2839 */
2840
2841 // Init loop
2842
2843 double previousCriteriom = DBL_MAX;
2844 double criteriom = DBL_MAX;
2845 bool goon = true;
2846 int macroIt = 0;
2848 printf(
2849 " Macro nParam chi2 chi2/ndof chi2/ndof chi2/ndof chi2/ndof ch2/ndof\n"
2850 " It. - - - cath-0 cath-1 sum 0/1 weight-sum\n");
2851 }
2852 while (goon) {
2853 if (localMax != nullptr) {
2854 if (saveLocalMax != nullptr) {
2855 delete saveLocalMax;
2856 }
2857 saveLocalMax = new Pads(*localMax, o2::mch::Pads::PadMode::xydxdyMode);
2858 }
2859 previousCriteriom = criteriom;
2860 /*
2861 if (0) {
2862 vectorSet( Cij, 0.0, nPads*nPixels);
2863 for (int j = 0; j < nPads; j++) {
2864 Cij[nPads * j + j] = 1.0;
2865 // for (int i = 0; i < nPixels; i++) {
2866 // qPadPrediction[j] += Cij[nPads * i + j] * qPixels[i];
2867 // }
2868 }
2869 }
2870 */
2871 int qCutMode = 0;
2872 // int qCutMode = -1;
2873 chi2 =
2874 PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, qCutMode, minPadResidues[macroIt],
2875 nIterations[macroIt]);
2876 // Obsolete
2877 // localMax = pixels->clipOnLocalMax(true);
2878 std::vector<PadIdx_t> newPixelIdx;
2879 localMax = pixels->extractLocalMax(newPixelIdx, 0.0, 0.0);
2880 // Debug
2881 /*
2882 for (int t=0; t < newPixelIdx.size(); t++) {
2883 int idx = newPixelIdx[t];
2884 printf("localMax idx=%d, xy(%f, %f), q[idx]=%f, localMax.q[t]=%f max(pixels)=%f \n",
2885 idx, pixels->getX()[idx], pixels->getY()[idx], pixels->getCharges()[idx], localMax->getCharges()[t], vectorMax(pixels->getCharges(), pixels->getNbrOfPads()));
2886 }
2887 */
2888 nParameters = localMax->getNbrOfPads();
2889 dof = nMaxPads - 3 * nParameters + 1;
2890 double chi20 = chi2.first;
2891 double chi21 = chi2.second;
2892 int ndof0 = getNbrOfPads(0) - 3 * nParameters + 1;
2893 if (ndof0 <= 0) {
2894 ndof0 = 1;
2895 }
2896 int ndof1 = getNbrOfPads(1) - 3 * nParameters + 1;
2897 if (ndof1 <= 0.) {
2898 ndof1 = 1;
2899 }
2900 if (dof == 0) {
2901 dof = 1;
2902 }
2903 // Model selection criteriom (nbre of parameters/seeds)
2904 // criteriom0 = fabs( (chi20+chi21 / dof));
2905 // criteriom1 = fabs(sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1));
2906 // printf( "??? cWeight0=%f, cWeight1=%f\n", cWeight0, cWeight1);
2907 criteriom = cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1);
2908 // Inv ??? 2 2 5272.16 14.24 12.73 10.86 23.59 11.93
2909 // 3 3 4389.29 13.81 12.25 12.52 24.76 12.36
2910
2912 printf(
2913 " %2d %3d %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
2914 macroIt, nParameters, chi20 + chi21, sqrt((chi20 + chi21) / dof),
2915 sqrt(chi20 / ndof0), sqrt(chi21 / ndof1),
2916 sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1),
2917 cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1));
2918 }
2920 inspectSavePixels(macroIt, *pixels);
2921 }
2922 /*
2923 printf("pixels.size=%d\n", pixels->getNbrOfPads());
2924 printf("mergedPads.mode %d, mergedPads.size=%d\n", mergedPads->mode, mergedPads->getNbrOfPads());
2925 printf("nexPixelIdx[0;N-1]=(%d, %d) localMax->nPads=%d\n",
2926 newPixelIdx[0], newPixelIdx[newPixelIdx.size()-1],
2927 localMax->getNbrOfPads()
2928 );
2929 // pixels->refinePads( *localMax, newPixelIdx);
2930 printf("pixels.size=%d\n", pixels->getNbrOfPads());
2931 printf("mergedPads.mode %d, mergedPads.size=%d\n", mergedPads->mode, mergedPads->getNbrOfPads());
2932 printf("nexPixelIdx[0;N-1]=(%d, %d) localMax->nPads=%d\n",
2933 newPixelIdx[0], newPixelIdx[newPixelIdx.size()-1],
2934 localMax->getNbrOfPads()
2935 );
2936 */
2937 // pixel->padCenterToBounds();
2938 // computeFastCij(*mergedPads, *pixels, Cij);
2939 macroIt++;
2940 printf(" min/max, %g, %g \n", vectorMin(pixels->getCharges(), nPixels), vectorMax(pixels->getCharges(), nPixels));
2941 goon =
2942 (criteriom < 1.0 * previousCriteriom) && (macroIt < nMacroIterations);
2943 }
2945 delete pixels;
2946 if (criteriom < 1.01 * previousCriteriom) {
2947 delete saveLocalMax;
2948 } else {
2949 delete localMax;
2950 localMax = saveLocalMax;
2951 }
2952
2953 //
2954 // Select local Max
2955 // Remove local Max < 0.01 * max(LocalMax)
2956 //
2957 double cutRatio = 0.01;
2958 double qCut =
2959 cutRatio * vectorMax(localMax->getCharges(), localMax->getNbrOfPads());
2960 int k = 0;
2961 double qSum = 0.0;
2962 // Remove the last hits if > (nMaxPads +1) / 3
2963 int nMaxSolutions =
2964 int((std::max(getNbrOfPads(0), getNbrOfPads(1)) + 1.0) / 3.0);
2965 // if (nMaxSolutions < 1) {
2966 // nMaxSolutions = 1;
2967 //}
2968 // To avoid 0 possibility and give more inputs to the fitting
2969 nMaxSolutions += 1;
2970
2971 int removedLocMax = localMax->getNbrOfPads();
2972
2973 if (localMax->getNbrOfPads() > nMaxSolutions) {
2975 printf("seed selection: nbr Max parameters =%d, nLocMax=%d\n",
2976 nMaxSolutions, localMax->getNbrOfPads());
2977 printf(
2978 "seed selection: Reduce the nbr of solutions to fit: Take %d/%d "
2979 "solutions\n",
2980 nMaxSolutions, localMax->getNbrOfPads());
2981 }
2982 int index[localMax->getNbrOfPads()];
2983 for (int k = 0; k < localMax->getNbrOfPads(); k++) {
2984 index[k] = k;
2985 }
2986 const double* qLocalMax = localMax->getCharges();
2987 std::sort(index, &index[localMax->getNbrOfPads()],
2988 [=](int a, int b) { return (qLocalMax[a] > qLocalMax[b]); });
2989 // Reoder
2990 qCut = qLocalMax[index[nMaxSolutions - 1]] - 1.e-03;
2991 }
2992 k = localMax->removePads(qCut);
2993 localMax->normalizeCharges();
2994 removedLocMax -= k;
2995
2996 if (clusterConfig.processingLog >= clusterConfig.info && removedLocMax != 0) {
2997 printf(
2998 " > seed selection: Final cut -> %d percent (qcut=%8.2f), number of "
2999 "local max removed = %d\n",
3000 int(cutRatio * 100), qCut, removedLocMax);
3001 }
3002
3003 // Store the
3004 int K0 = localMax->getNbrOfPads();
3005 int K = std::min(K0, nbrOfPadsInTheGroupCath);
3006 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
3007 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
3008 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
3009 double* varX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
3010 double* varY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
3011 const double* ql = localMax->getCharges();
3012 const double* xl = localMax->getX();
3013 const double* yl = localMax->getY();
3014 const double* dxl = localMax->getDX();
3015 const double* dyl = localMax->getDY();
3016 for (int k = 0; k < K; k++) {
3017 w[k] = ql[k];
3018 muX[k] = xl[k];
3019 muY[k] = yl[k];
3020 varX[k] = dxl[k];
3021 varY[k] = dyl[k];
3022 printf("k=%d XY=%f,%f varXY=%f,%f\n", k, muX[k], muY[k], varX[k], varY[k]);
3023 }
3024 //
3025 // SVD
3026 //
3027 if (0) {
3028 double rcond = 1.e-2;
3029 gsl_matrix_view Cij_gsl = gsl_matrix_view_array(Cij, nPixels, nPads);
3030 double* qPixelsStar = new double[nPixels];
3031 gsl_vector_view qPixelsStar_gsl = gsl_vector_view_array(qPixelsStar, nPixels);
3032 /*
3033 double *Tji = new double[nPads*nPixels];
3034 gsl_matrix_view Tji_gsl = gsl_matrix_view_array(Tji, nPads, nPixels);
3035 gsl_matrix_transpose_memcpy(&Tji_gsl.matrix, &Cij_gsl.matrix);
3036 gsl_matrix* pInv = moore_penrose_pinv(&Tji_gsl.matrix, rcond);
3037
3038 // qPads
3039 gsl_vector_const_view qPads_gsl = gsl_vector_const_view_array(mergedPads->getCharges(), nPads);
3040 // qPixels solution
3041
3042 gsl_blas_dgemv(CblasNoTrans, 1.0, pInv, &qPads_gsl.vector, 0.0, &qPixelsStar_gsl.vector);
3043 */
3044
3045 // Cij . Cji
3046 gsl_matrix* CCii = gsl_matrix_alloc(nPixels, nPixels);
3047 gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1., &Cij_gsl.matrix, &Cij_gsl.matrix, 0., CCii);
3048 gsl_matrix* pInv = moore_penrose_pinv(CCii, rcond);
3049 double* pix = new double[nPixels];
3050 vectorSet(pix, 0.0, nPixels);
3051 pix[0] = 1.0;
3052 gsl_vector_view pix_gsl = gsl_vector_view_array(pix, nPixels);
3053 gsl_blas_dgemv(CblasNoTrans, 1.0, pInv, &pix_gsl.vector, 0.0, &qPixelsStar_gsl.vector);
3054 vectorAddScalar(pix, -1, nPixels, pix);
3055 //
3056 printGSLVector("qPixelStar", &qPixelsStar_gsl.vector);
3057 vectorPrint("qPixels", pixels->getCharges(), nPixels);
3058
3060 inspectOverWriteQ(macroIt - 1, qPixelsStar);
3061 // pixels->setCharges( qPixelsStar, nPixels );
3062 // inspectSavePixels(macroIt-1, *pixels);
3063 }
3064
3065 /*
3066 double *Tji = new double[nPads*nPixels];
3067 gsl_matrix_view Tji_gsl = gsl_matrix_view_array(Tji, nPads, nPixels);
3068 gsl_matrix_transpose_memcpy(&Tji_gsl.matrix, &Cij_gsl.matrix);
3069 double *V = new double[nPads*nPixels];
3070 double *S = new double[nPixels];
3071 double *work = new double[nPixels];
3072 // gsl_matrix_view V_gsl = gsl_matrix_view_array(V, nPads, nPixels);
3073 // gsl_vector_view S_gsl = gsl_vector_view_array(S, nPixels);
3074 gsl_matrix_view V_gsl = gsl_matrix_view_array(V, nPads, nPads);
3075 gsl_vector_view S_gsl = gsl_vector_view_array(S, nPads);
3076 gsl_vector_view work_gsl = gsl_vector_view_array(work, nPads);
3077 // A[M,N] = t(Cij), M=nPads, N=nPixels
3078 gsl_linalg_SV_decomp (&Cij_gsl.matrix , &V_gsl.matrix, &S_gsl.vector, &work_gsl.vector);
3079 printf("Matrix S:");
3080 for (int j = 0; j < nPads; j++) {
3081 double Sjj = gsl_vector_get(&S_gsl.vector,j);
3082 printf("%6.2f ", gsl_vector_get(&S_gsl.vector,j));
3083 if (Sjj > 1.0e-2) {
3084 Sjj = 1.0/Sjj;
3085 } else {
3086 Sjj = 0;
3087 }
3088 gsl_vector_set(&S_gsl.vector,j, Sjj);
3089 }
3090 printf("\n");
3091
3092 gsl_matrix *PInv = gsl_matrix_alloc (nPads, nPixels);
3093 gsl_matrix *Ut = gsl_matrix_alloc (nPads, nPixels);
3094 gsl_matrix_transpose_memcpy (Ut, &Cij_gsl.matrix);
3095 //gsl_matrix * SIpVT = gsl_matrix_alloc (n_row, n_row);
3096 for (int i = 0; i < nPads; i++) {
3097 for (int j = 0; j < nPads; j++) {
3098 // Vij = Vij*Sjj
3099 gsl_matrix_set(&V_gsl.matrix, i, j, gsl_matrix_get(&V_gsl.matrix, i, j) * gsl_vector_get(&S_gsl.vector,j));
3100 }
3101 }
3102 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans, // Calculating inv(S).trans(V)
3103 1.0, &V_gsl.matrix, Ut,
3104 0.0, PInv);
3105
3106 gsl_matrix *Id = gsl_matrix_alloc (nPixels, nPixels);
3107 // Test if 1 matrix
3108 gsl_blas_dgemm (CblasNoTrans, CblasNoTrans,
3109 1.0, &Cij_gsl.matrix, PInv,
3110 0.0, Id);
3111
3112
3113 printf("Matrix Id:");
3114 for (int j = 0; j < nPads; j++) {
3115 for (int i = 0; i < nPixels; i++) {
3116 printf("%6.2f ", gsl_matrix_get(Id, j, i));
3117 }
3118 printf("\n");
3119 }
3120 */
3121 }
3122 delete mergedPads;
3123 /*
3124 delete [] V;
3125 delete [] S;
3126 delete [] work;
3127 */
3128 delete localMax;
3129 delete[] Cij;
3130 delete[] maskCij;
3131 return K;
3132}
3133// Withot ajusted rafinement
3134int ClusterPEM::findLocalMaxWithPEM2Lev(double* thetaL, int nbrOfPadsInTheGroupCath)
3135{
3136
3138 // Already done if 1 group
3139 Pads* cath0 = pads[0];
3140 Pads* cath1 = pads[1];
3141 Pads* projPads = projectedPads;
3142 // Compute the charge weight of each cathode
3143 double cWeight0 = getTotalCharge(0);
3144 double cWeight1 = getTotalCharge(1);
3145 double preClusterCharge = cWeight0 + cWeight1;
3146 cWeight0 /= preClusterCharge;
3147 cWeight1 /= preClusterCharge;
3148 //
3149 int chId = chamberId;
3151 printf(" - [findLocalMaxWithPEM]\n");
3152 }
3153 // Trivial cluster : only 1 pads
3154 if (projPads->getNbrOfPads() == 1) {
3155 // Return the unique local maximum : the center of the pads
3156 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
3157 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
3158 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
3159 double* muDX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
3160 double* muDY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
3161 w[0] = 1.0;
3162 muX[0] = projPads->getX()[0];
3163 muY[0] = projPads->getY()[0];
3164 muDX[0] = projPads->getDX()[0] * 0.5;
3165 muDY[0] = projPads->getDY()[0] * 0.5;
3166 return 1;
3167 }
3168 int nMaxPads = std::fmax(getNbrOfPads(0), getNbrOfPads(1));
3169
3170 // ??? To Optimize/debug
3171 // Pads* pixels = projPads->refinePads();
3172 Pads* pixels = projPads;
3173 // Reserve place for refinment
3174 /*
3175 int maxNbrOfPixels = 4*projPads->getNbrOfPads();
3176 Pads* pixels = new Pads(projPads, maxNbrOfPixels);
3177 printf("pixel allocation %d\n", maxNbrOfPixels);
3178 */
3179 int nPixels = pixels->getNbrOfPads();
3180 // Merge pads of the 2 cathodes
3181 // TODO ??? : see if it can be once with Fitting (see fitPads)
3182 Pads* mergedPads = new Pads(pads[0], pads[1], Pads::PadMode::xyInfSupMode);
3183 int nPads = mergedPads->getNbrOfPads();
3184 Pads* localMax = nullptr;
3185 Pads* saveLocalMax = nullptr;
3186 std::pair<double, double> chi2;
3187 int dof, nParameters;
3188
3189 // Pixel initilization
3190 // Rq: the charge projection is not used
3191 pixels->setCharges(1.0);
3192 // The field saturate is use to tag pixels already refined
3193 // no refinment
3194 // pixels->setSaturate(0);
3195 // Init Cij
3196 double* Cij = new double[nPads * nPixels];
3198 // MaskCij: Used to disable Cij contribution (disable pixels)
3199 Mask_t* maskCij = new Mask_t[nPads * nPixels];
3200 // Mask_t* maskCij = new Mask_t[nPads * maxNbrOfPixels];
3201 // Compute pad charge xyInfSup induiced by a set of charge (the pixels)
3202 computeFastCij(*mergedPads, *pixels, Cij);
3203 // computeCij(*mergedPads, *pixels, Cij);
3204
3205 // Init loop
3206
3207 double previousCriteriom = DBL_MAX;
3208 double criteriom = DBL_MAX;
3209 bool goon = true;
3210 int macroIt = 0;
3212 printf(
3213 " Macro nParam chi2 chi2/ndof chi2/ndof chi2/ndof chi2/ndof ch2/ndof\n"
3214 " It. - - - cath-0 cath-1 sum 0/1 weight-sum\n");
3215 }
3216 while (goon) {
3217 if (localMax != nullptr) {
3218 if (saveLocalMax != nullptr) {
3219 delete saveLocalMax;
3220 }
3221 saveLocalMax = new Pads(*localMax, o2::mch::Pads::PadMode::xydxdyMode);
3222 }
3223 previousCriteriom = criteriom;
3224 /*
3225 if (0) {
3226 vectorSet( Cij, 0.0, nPads*nPixels);
3227 for (int j = 0; j < nPads; j++) {
3228 Cij[nPads * j + j] = 1.0;
3229 // for (int i = 0; i < nPixels; i++) {
3230 // qPadPrediction[j] += Cij[nPads * i + j] * qPixels[i];
3231 // }
3232 }
3233 }
3234 */
3235 int qCutMode = 0;
3236 // int qCutMode = -1;
3237 chi2 =
3238 PoissonEMLoop(*mergedPads, *pixels, Cij, maskCij, qCutMode, minPadResidues[macroIt],
3239 nIterations[macroIt]);
3240 // Obsolete
3241 // localMax = pixels->clipOnLocalMax(true);
3242 std::vector<PadIdx_t> newPixelIdx;
3243 localMax = pixels->extractLocalMax(newPixelIdx, 0.0, 0.0);
3244 for (int t = 0; t < newPixelIdx.size(); t++) {
3245 int idx = newPixelIdx[t];
3246 printf("localMax idx=%d, xy(%f, %f), q[idx]=%f, localMax.q[t]=%f max(pixels)=%f \n",
3247 idx, pixels->getX()[idx], pixels->getY()[idx], pixels->getCharges()[idx], localMax->getCharges()[t], vectorMax(pixels->getCharges(), pixels->getNbrOfPads()));
3248 }
3249 nParameters = localMax->getNbrOfPads();
3250 dof = nMaxPads - 3 * nParameters + 1;
3251 double chi20 = chi2.first;
3252 double chi21 = chi2.second;
3253 int ndof0 = getNbrOfPads(0) - 3 * nParameters + 1;
3254 if (ndof0 <= 0) {
3255 ndof0 = 1;
3256 }
3257 int ndof1 = getNbrOfPads(1) - 3 * nParameters + 1;
3258 if (ndof1 <= 0.) {
3259 ndof1 = 1;
3260 }
3261 if (dof == 0) {
3262 dof = 1;
3263 }
3264 // Model selection criteriom (nbre of parameters/seeds)
3265 // criteriom0 = fabs( (chi20+chi21 / dof));
3266 // criteriom1 = fabs(sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1));
3267 // printf( "??? cWeight0=%f, cWeight1=%f\n", cWeight0, cWeight1);
3268 criteriom = cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1);
3269 // Inv ??? 2 2 5272.16 14.24 12.73 10.86 23.59 11.93
3270 // 3 3 4389.29 13.81 12.25 12.52 24.76 12.36
3271
3273 printf(
3274 " %2d %3d %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
3275 macroIt, nParameters, chi20 + chi21, sqrt((chi20 + chi21) / dof),
3276 sqrt(chi20 / ndof0), sqrt(chi21 / ndof1),
3277 sqrt(chi20 / ndof0) + sqrt(chi21 / ndof1),
3278 cWeight0 * sqrt(chi20 / ndof0) + cWeight1 * sqrt(chi21 / ndof1));
3279 }
3281 inspectSavePixels(macroIt, *pixels);
3282 }
3283 /*
3284 printf("pixels.size=%d\n", pixels->getNbrOfPads());
3285 printf("mergedPads.mode %d, mergedPads.size=%d\n", mergedPads->mode, mergedPads->getNbrOfPads());
3286 printf("nexPixelIdx[0;N-1]=(%d, %d) localMax->nPads=%d\n",
3287 newPixelIdx[0], newPixelIdx[newPixelIdx.size()-1],
3288 localMax->getNbrOfPads()
3289 );
3290 // pixels->refinePads( *localMax, newPixelIdx);
3291 printf("pixels.size=%d\n", pixels->getNbrOfPads());
3292 printf("mergedPads.mode %d, mergedPads.size=%d\n", mergedPads->mode, mergedPads->getNbrOfPads());
3293 printf("nexPixelIdx[0;N-1]=(%d, %d) localMax->nPads=%d\n",
3294 newPixelIdx[0], newPixelIdx[newPixelIdx.size()-1],
3295 localMax->getNbrOfPads()
3296 );
3297 */
3298 // pixel->padCenterToBounds();
3299 // computeFastCij(*mergedPads, *pixels, Cij);
3300 macroIt++;
3301 if (macroIt == 4) {
3302 pixels = projPads->refineAll();
3303 nPixels = pixels->getNbrOfPads();
3304 delete[] Cij;
3305 Cij = new double[nPads * nPixels];
3306 delete[] maskCij;
3307 maskCij = new Mask_t[nPads * nPixels];
3308 computeFastCij(*mergedPads, *pixels, Cij);
3309 }
3310 printf(" min/max, %g, %g \n", vectorMin(pixels->getCharges(), nPixels), vectorMax(pixels->getCharges(), nPixels));
3311 goon =
3312 (criteriom < 1.0 * previousCriteriom) && (macroIt < nMacroIterations);
3313 }
3315 delete pixels;
3316 if (criteriom < 1.01 * previousCriteriom) {
3317 delete saveLocalMax;
3318 } else {
3319 delete localMax;
3320 localMax = saveLocalMax;
3321 }
3322
3323 //
3324 // Select local Max
3325 // Remove local Max < 0.01 * max(LocalMax)
3326 //
3327 double cutRatio = 0.01;
3328 double qCut =
3329 cutRatio * vectorMax(localMax->getCharges(), localMax->getNbrOfPads());
3330 int k = 0;
3331 double qSum = 0.0;
3332 // Remove the last hits if > (nMaxPads +1) / 3
3333 int nMaxSolutions =
3334 int((std::max(getNbrOfPads(0), getNbrOfPads(1)) + 1.0) / 3.0);
3335 // if (nMaxSolutions < 1) {
3336 // nMaxSolutions = 1;
3337 //}
3338 // To avoid 0 possibility and give more inputs to the fitting
3339 nMaxSolutions += 1;
3340
3341 int removedLocMax = localMax->getNbrOfPads();
3342
3343 if (localMax->getNbrOfPads() > nMaxSolutions) {
3345 printf("seed selection: nbr Max parameters =%d, nLocMax=%d\n",
3346 nMaxSolutions, localMax->getNbrOfPads());
3347 printf(
3348 "seed selection: Reduce the nbr of solutions to fit: Take %d/%d "
3349 "solutions\n",
3350 nMaxSolutions, localMax->getNbrOfPads());
3351 }
3352 int index[localMax->getNbrOfPads()];
3353 for (int k = 0; k < localMax->getNbrOfPads(); k++) {
3354 index[k] = k;
3355 }
3356 const double* qLocalMax = localMax->getCharges();
3357 std::sort(index, &index[localMax->getNbrOfPads()],
3358 [=](int a, int b) { return (qLocalMax[a] > qLocalMax[b]); });
3359 // Reoder
3360 qCut = qLocalMax[index[nMaxSolutions - 1]] - 1.e-03;
3361 }
3362 k = localMax->removePads(qCut);
3363 localMax->normalizeCharges();
3364 removedLocMax -= k;
3365
3366 if (clusterConfig.processingLog >= clusterConfig.info && removedLocMax != 0) {
3367 printf(
3368 " > seed selection: Final cut -> %d percent (qcut=%8.2f), number of "
3369 "local max removed = %d\n",
3370 int(cutRatio * 100), qCut, removedLocMax);
3371 }
3372
3373 // Store the
3374 int K0 = localMax->getNbrOfPads();
3375 int K = std::min(K0, nbrOfPadsInTheGroupCath);
3376 double* w = getW(thetaL, nbrOfPadsInTheGroupCath);
3377 double* muX = getMuX(thetaL, nbrOfPadsInTheGroupCath);
3378 double* muY = getMuY(thetaL, nbrOfPadsInTheGroupCath);
3379 double* varX = getVarX(thetaL, nbrOfPadsInTheGroupCath);
3380 double* varY = getVarY(thetaL, nbrOfPadsInTheGroupCath);
3381 const double* ql = localMax->getCharges();
3382 const double* xl = localMax->getX();
3383 const double* yl = localMax->getY();
3384 const double* dxl = localMax->getDX();
3385 const double* dyl = localMax->getDY();
3386 for (int k = 0; k < K; k++) {
3387 w[k] = ql[k];
3388 muX[k] = xl[k];
3389 muY[k] = yl[k];
3390 varX[k] = dxl[k];
3391 varY[k] = dyl[k];
3392 printf("k=%d XY=%f,%f varXY=%f,%f\n", k, muX[k], muY[k], varX[k], varY[k]);
3393 }
3394
3395 delete mergedPads;
3396 /*
3397 delete [] V;
3398 delete [] S;
3399 delete [] work;
3400 */
3401 delete localMax;
3402 delete[] Cij;
3403 delete[] maskCij;
3404 return K;
3405}
3406
3407// Propagate back cath-group to projection pads
3408void ClusterPEM::updateProjectionGroups()
3409{
3411 printf("> Update projected Groups [updateProjectionGroups]\n");
3412 }
3413 int nProjPads = projectedPads->getNbrOfPads();
3414 Groups_t* cath0ToGrp = cathGroup[0];
3415 Groups_t* cath1ToGrp = cathGroup[1];
3416
3417 // Save projPadToGrp to Check
3418 Groups_t savePadGrp[nProjPads];
3420 vectorCopyShort(projPadToGrp, nProjPads, savePadGrp);
3421 }
3422 for (int k = 0; k < nProjPads; k++) {
3423 MapKToIJ_t ij = mapKToIJ[k];
3424 PadIdx_t i = ij.i;
3425 PadIdx_t j = ij.j;
3426 if ((i > -1) && (j == -1)) {
3427 // int cath0Idx = mapPadToCathIdx[ i ];
3428 projPadToGrp[k] = cath0ToGrp[i];
3429 // printf(" projPadToGrp[k] = cath0ToGrp[cath0Idx], i=%d, j=%d,
3430 // cath0Idx=%d, cath0ToGrp[cath0Idx]=%d\n", i, j, cath0Idx,
3431 // cath0ToGrp[cath0Idx]);
3432 } else if ((i == -1) && (j > -1)) {
3433 // int cath1Idx = mapPadToCathIdx[ j ];
3434 projPadToGrp[k] = cath1ToGrp[j];
3435 // printf(" projPadToGrp[k] = cath1ToGrp[cath1Idx], i=%d, j=%d,
3436 // cath1Idx=%d, cath1ToGrp[cath1Idx]=%d\n", i, j, cath1Idx,
3437 // cath1ToGrp[cath1Idx]);
3438 } else if ((i > -1) && (j > -1)) {
3439 // projPadToGrp[k] = grpToGrp[ projPadToGrp[k] ];
3440 projPadToGrp[k] = cath0ToGrp[i];
3441 // ??? if (clusterConfig.groupsCheck && (cath0ToGrp[i] != cath1ToGrp[j])) {
3442 if (0) {
3443 printf(
3444 " [updateProjectionGroups] i, cath0ToGrp[i]=(%d, %d); j, "
3445 "cath1ToGrp[j]=(%d, %d)\n",
3446 i, cath0ToGrp[i], j, cath1ToGrp[j]);
3447 throw std::overflow_error(
3448 "updateProjectionGroups cath0ToGrp[i] != cath1ToGrp[j]");
3449 }
3450 // printf(" projPadToGrp[k] = grpToGrp[ projPadToGrp[k] ], i=%d, j=%d,
3451 // k=%d \n", i, j, k);
3452 } else {
3453 throw std::overflow_error("updateProjectionGroups i,j=-1");
3454 }
3455 }
3457 vectorPrintShort(" updated projGrp", projPadToGrp, nProjPads);
3458 }
3459 if (0) {
3460 bool same = true;
3461 for (int p = 0; p < nProjPads; p++) {
3462 same = same && (projPadToGrp[p] == savePadGrp[p]);
3463 }
3464 if (same == false) {
3465 vectorPrintShort(" WARNING: old projPadToGrp", savePadGrp, nProjPads);
3466 vectorPrintShort(" WARNING: new projPadToGrp", projPadToGrp, nProjPads);
3467 // throw std::overflow_error("updateProjectionGroups projection has
3468 // changed");
3469 }
3470 }
3471}
3472
3473// Not used in the Clustering/fitting
3474// Just to check hit results
3475int ClusterPEM::laplacian2D(const Pads& pads_, PadIdx_t* neigh, int chId,
3476 PadIdx_t* sortedLocalMax, int kMax, double* smoothQ)
3477{
3478 // ??? Place somewhere
3479 double eps = 1.0e-7;
3480 double noise = 4. * 0.22875;
3481 double laplacianCutOff = noise;
3482 // ??? Inv int atLeastOneMax = -1;
3483 //
3484 int N = pads_.getNbrOfPads();
3485 const double* x = pads_.getX();
3486 const double* y = pads_.getY();
3487 const double* dx = pads_.getDX();
3488 const double* dy = pads_.getDY();
3489 const double* q = pads_.getCharges();
3490 //
3491 // Laplacian allocation
3492 double lapl[N];
3493 // Locations not used as local max
3494 Mask_t unselected[N];
3495 vectorSetShort(unselected, 1, N);
3496 // printNeighbors(neigh, N);
3497 for (int i = 0; i < N; i++) {
3498 int nNeigh = 0;
3499 double sumNeigh = 0;
3500 int nNeighSmaller = 0;
3501 // printf(" Neighbors of i=%d [", i);
3502 //
3503 // For all neighbours of i
3504 for (PadIdx_t* neigh_ptr = getTheFirtsNeighborOf(neigh, i);
3505 *neigh_ptr != -1; neigh_ptr++) {
3506 PadIdx_t j = *neigh_ptr;
3507 // printf("%d ,", j);
3508 // nNeighSmaller += (q[j] <= ((q[i] + noise) * unselected[i]));
3509 nNeighSmaller += (q[j] <= ((q[i] + noise) * unselected[j]));
3510 nNeigh++;
3511 sumNeigh += q[j];
3512 }
3513 // printf("]");
3514 // printf(" nNeighSmaller %d / nNeigh %d \n", nNeighSmaller, nNeigh);
3515 lapl[i] = float(nNeighSmaller) / nNeigh;
3516 if (lapl[i] < laplacianCutOff) {
3517 lapl[i] = 0.0;
3518 }
3519 unselected[i] = (lapl[i] != 1.0);
3520 smoothQ[i] = sumNeigh / nNeigh;
3522 printf(
3523 "Laplacian i=%d, x[i]=%6.3f, y[i]=%6.3f, z[i]=%6.3f, "
3524 "smoothQ[i]=%6.3f, lapl[i]=%6.3f\n",
3525 i, x[i], y[i], q[i], smoothQ[i], lapl[i]);
3526 }
3527 }
3528 //
3529 // Get local maxima
3530 Mask_t localMaxMask[N];
3531 vectorBuildMaskEqual(lapl, 1.0, N, localMaxMask);
3532 // Get the location in lapl[]
3533 // Inv ??? int nSortedIdx = vectorSumShort( localMaxMask, N );
3534 // ??? Inv int sortPadIdx[nSortedIdx];
3535 int nSortedIdx = vectorGetIndexFromMask(localMaxMask, N, sortedLocalMax);
3536 // Sort the slected laplacian (index sorting)
3537 // Indexes for sorting
3538 // Rq: Sometimes chage the order of max
3539 // std::sort( sortedLocalMax, &sortedLocalMax[nSortedIdx], [=](int a, int b){
3540 // return smoothQ[a] > smoothQ[b]; });
3541 std::sort(sortedLocalMax, &sortedLocalMax[nSortedIdx],
3542 [=](int a, int b) { return q[a] > q[b]; });
3544 vectorPrint(" sort w", q, N);
3545 vectorPrintInt(" sorted q-indexes", sortedLocalMax, nSortedIdx);
3546 }
3547
3549 // Filtering local max
3551
3553 printf(" [laplacian2D] (InspectModel) filtering Local Max\n");
3554 }
3555 // At Least one locMax
3556 if ((nSortedIdx == 0) && (N != 0)) {
3557 // Take the first pad
3559 printf("-> No local Max, take the highest value < 1\n");
3560 }
3561 sortedLocalMax[0] = 0;
3562 nSortedIdx = 1;
3563 return nSortedIdx;
3564 }
3565
3566 // For a small number of pads
3567 // limit the number of max to 1 local max
3568 // if the aspect ratio of the cluster
3569 // is close to 1
3570 double aspectRatio = 0;
3571 if ((N > 0) && (N < 6) && (chId <= 6)) {
3572 double xInf = DBL_MAX, xSup = DBL_MIN, yInf = DBL_MAX, ySup = DBL_MIN;
3573 // Compute aspect ratio of the cluster
3574 for (int i = 0; i < N; i++) {
3575 xInf = fmin(xInf, x[i] - dx[i]);
3576 xSup = fmax(xSup, x[i] + dx[i]);
3577 yInf = fmin(yInf, y[i] - dy[i]);
3578 ySup = fmax(ySup, y[i] + dy[i]);
3579 }
3580 // Nbr of pads in x-direction
3581 int nX = int((xSup - xInf) / dx[0] + eps);
3582 // Nbr of pads in y-direction
3583 int nY = int((ySup - yInf) / dy[0] + eps);
3584 aspectRatio = fmin(nX, nY) / fmax(nX, nY);
3585 if (aspectRatio > 0.6) {
3586 // Take the max
3587 nSortedIdx = 1;
3589 printf(
3590 " -> Limit to one local Max, nPads=%d, chId=%d, aspect ratio=%6.3f\n",
3591 N, chId, aspectRatio);
3592 }
3593 }
3594 }
3595
3596 // Suppress noisy peaks when at least 1 peak
3597 // is bigger than
3598 if ((N > 0) && (q[sortedLocalMax[0]] > 2 * noise)) {
3599 int trunkIdx = nSortedIdx;
3600 for (int ik = 0; ik < nSortedIdx; ik++) {
3601 if (q[sortedLocalMax[ik]] <= 2 * noise) {
3602 trunkIdx = ik;
3603 }
3604 }
3605 nSortedIdx = std::max(trunkIdx, 1);
3606 if ((clusterConfig.EMLocalMaxLog >= clusterConfig.info) && (trunkIdx != nSortedIdx)) {
3607 printf("-> Suppress %d local Max. too noisy (q < %6.3f),\n",
3608 nSortedIdx - trunkIdx, 2 * noise);
3609 }
3610 }
3611 // At most
3612 // int nbrOfLocalMax = floor( (N + 1) / 3.0 );
3613 // if ( nSortedIdx > nbrOfLocalMax) {
3614 // printf("Suppress %d local Max. the limit of number of local max %d is
3615 // reached (< %d)\n", nSortedIdx-nbrOfLocalMax, nSortedIdx, nbrOfLocalMax);
3616 // nSortedIdx = nbrOfLocalMax;
3617 //}
3618
3619 return nSortedIdx;
3620}
3621
3622// Not used in the Clustering/fitting
3623// Just to check hit results
3624int ClusterPEM::findLocalMaxWithBothCathodes(double* thetaOut, int kMax)
3625{
3626
3627 int N0 = 0, N1 = 0;
3628 if (nbrOfCathodePlanes != 2) {
3629 if (singleCathPlaneID == 0) {
3630 N0 = pads[0]->getNbrOfPads();
3631 } else {
3632 N1 = pads[1]->getNbrOfPads();
3633 }
3634 } else {
3635 N0 = pads[0]->getNbrOfPads();
3636 N1 = pads[1]->getNbrOfPads();
3637 }
3638 int kMax0 = N0;
3639 int kMax1 = N1;
3640
3641 // Number of seeds founds
3642 int k = 0;
3643 //
3644 // Pad indexes of local max. allocation per cathode
3645 PadIdx_t localMax0[kMax0];
3646 PadIdx_t localMax1[kMax1];
3647 // Smoothed values of q[0/1] with neighbours
3648 double smoothQ0[N0];
3649 double smoothQ1[N1];
3650 // Local Maximum for each cathodes
3651 // There are sorted with the lissed q[O/1] values
3653 printf("> [findLocalMaxWithBothCathodes] N0=%d N1=%d\n", N0, N1);
3654 }
3655 PadIdx_t* grpNeighborsCath0 = nullptr;
3656 PadIdx_t* grpNeighborsCath1 = nullptr;
3657 // Number of local max
3658 int K0 = 0, K1 = 0;
3659 if (N0) {
3660 grpNeighborsCath0 = pads[0]->getFirstNeighbors();
3661 K0 = laplacian2D(*pads[0], grpNeighborsCath0, chamberId, localMax0, kMax0,
3662 smoothQ0);
3663 }
3664 if (N1) {
3665 grpNeighborsCath1 = pads[1]->getFirstNeighbors();
3666 K1 = laplacian2D(*pads[1], grpNeighborsCath1, chamberId, localMax1, kMax1,
3667 smoothQ1);
3668 }
3669
3670 // Seed allocation
3671 double localXMax[K0 + K1];
3672 double localYMax[K0 + K1];
3673 double localQMax[K0 + K1];
3674 //
3675 // Need an array to transform global index to the grp indexes
3676 PadIdx_t mapIToGrpIdx[N0];
3677 vectorSetInt(mapIToGrpIdx, -1, N0);
3678 PadIdx_t mapGrpIdxToI[N0];
3679 for (int i = 0; i < N0; i++) {
3680 // ??? printf("mapGrpIdxToI[%d]=%d\n", i, mapGrpIdxToI[i]);
3681 // VPads mapIToGrpIdx[ mapGrpIdxToI[i]] = i;
3682 mapIToGrpIdx[i] = i;
3683 mapGrpIdxToI[i] = i;
3684 }
3685 PadIdx_t mapJToGrpIdx[N1];
3686 vectorSetInt(mapJToGrpIdx, -1, N1);
3687 PadIdx_t mapGrpIdxToJ[N0];
3688 for (int j = 0; j < N1; j++) {
3689 // ??? printf("mapGrpIdxToJJ[%d]=%d\n", j, mapGrpIdxToJ[j]);
3690 // Vpads mapJToGrpIdx[ mapGrpIdxToJ[j]] = j;
3691 mapJToGrpIdx[j] = j;
3692 mapGrpIdxToJ[j] = j;
3693 }
3694 const double* x0;
3695 const double* y0;
3696 const double* dx0;
3697 const double* dy0;
3698 const double* q0;
3699
3700 const double* x1;
3701 const double* y1;
3702 const double* dx1;
3703 const double* dy1;
3704 const double* q1;
3705 if (N0) {
3706 x0 = pads[0]->getX();
3707 y0 = pads[0]->getY();
3708 dx0 = pads[0]->getDX();
3709 dy0 = pads[0]->getDY();
3710 q0 = pads[0]->getCharges();
3711 }
3712 if (N1) {
3713 x1 = pads[1]->getX();
3714 y1 = pads[1]->getY();
3715 dx1 = pads[1]->getDX();
3716 dy1 = pads[1]->getDY();
3717 q1 = pads[1]->getCharges();
3718 }
3719 const double* xProj = projectedPads->getX();
3720 const double* yProj = projectedPads->getY();
3721 const double* dxProj = projectedPads->getDX();
3722 const double* dyProj = projectedPads->getDX();
3723
3724 // Debug
3725 // vectorPrintInt( "mapIToGrpIdx", mapIToGrpIdx, N0);
3726 // vectorPrintInt( "mapJToGrpIdx", mapJToGrpIdx, N1);
3728 vectorPrint("findLocalMax q0", q0, N0);
3729 vectorPrint("findLocalMax q1", q1, N1);
3730 vectorPrintInt("findLocalMax localMax0", localMax0, K0);
3731 vectorPrintInt("findLocalMax localMax1", localMax1, K1);
3732 }
3733
3734 //
3735 // Make the combinatorics between the 2 cathodes
3736 // - Take the maxOf( N0,N1) for the external loop
3737 //
3739 printf(" Local max per cathode K0=%d, K1=%d\n", K0, K1);
3740 }
3741 bool K0GreaterThanK1 = (K0 >= K1);
3742 bool K0EqualToK1 = (K0 == K1);
3743 // Choose the highest last local max.
3744 bool highestLastLocalMax0;
3745 if (K0 == 0) {
3746 highestLastLocalMax0 = false;
3747 } else if (K1 == 0) {
3748 highestLastLocalMax0 = true;
3749 } else {
3750 // highestLastLocalMax0 = (smoothQ0[localMax0[std::max(K0-1, 0)]] >=
3751 // smoothQ1[localMax1[std::max(K1-1,0)]]);
3752 highestLastLocalMax0 = (q0[localMax0[std::max(K0 - 1, 0)]] >=
3753 q1[localMax1[std::max(K1 - 1, 0)]]);
3754 }
3755 // Permute cathodes if necessary
3756 int NU, NV;
3757 int KU, KV;
3758 PadIdx_t *localMaxU, *localMaxV;
3759 const double *qU, *qV;
3760 PadIdx_t* interUV;
3761 bool permuteIJ;
3762 const double *xu, *yu, *dxu, *dyu;
3763 const double *xv, *yv, *dxv, *dyv;
3764 const PadIdx_t *mapGrpIdxToU, *mapGrpIdxToV;
3765 PadIdx_t *mapUToGrpIdx, *mapVToGrpIdx;
3766
3767 // Do permutation between cath0/cath1 or not
3768 if (K0GreaterThanK1 || (K0EqualToK1 && highestLastLocalMax0)) {
3769 NU = N0;
3770 NV = N1;
3771 KU = K0;
3772 KV = K1;
3773 xu = x0;
3774 yu = y0;
3775 dxu = dx0;
3776 dyu = dy0;
3777 xv = x1;
3778 yv = y1;
3779 dxv = dx1;
3780 dyv = dy1;
3781 localMaxU = localMax0;
3782 localMaxV = localMax1;
3783 // qU = smoothQ0; qV = smoothQ1;
3784 qU = q0;
3785 qV = q1;
3786 interUV = IInterJ;
3787 mapGrpIdxToU = mapGrpIdxToI;
3788 mapGrpIdxToV = mapGrpIdxToJ;
3789 mapUToGrpIdx = mapIToGrpIdx;
3790 mapVToGrpIdx = mapJToGrpIdx;
3791 permuteIJ = false;
3792 } else {
3793 NU = N1;
3794 NV = N0;
3795 KU = K1;
3796 KV = K0;
3797 xu = x1;
3798 yu = y1;
3799 dxu = dx1;
3800 dyu = dy1;
3801 xv = x0;
3802 yv = y0;
3803 dxv = dx0;
3804 dyv = dy0;
3805 localMaxU = localMax1;
3806 localMaxV = localMax0;
3807 // qU = smoothQ1; qV = smoothQ0;
3808 qU = q1;
3809 qV = q0;
3810 interUV = JInterI;
3811 mapGrpIdxToU = mapGrpIdxToJ;
3812 mapGrpIdxToV = mapGrpIdxToI;
3813 mapUToGrpIdx = mapJToGrpIdx;
3814 mapVToGrpIdx = mapIToGrpIdx;
3815 permuteIJ = true;
3816 }
3817 // Keep the memory of the localMaxV already assigned
3818 Mask_t qvAvailable[KV];
3819 vectorSetShort(qvAvailable, 1, KV);
3820 // Compact intersection matrix
3821 PadIdx_t* UInterV;
3822 //
3823 // Cathodes combinatorics
3825 printf(" Local max combinatorics: KU=%d KV=%d\n", KU, KV);
3826 // printXYdXY("Projection", xyDxyProj, NProj, NProj, 0, 0);
3827 // printf(" mapIJToK=%p, N0=%d N1=%d\n", mapIJToK, N0, N1);
3828 for (int i = 0; i < N0; i++) {
3829 // VPads int ii = mapGrpIdxToI[i];
3830 int ii = i;
3831 for (int j = 0; j < N1; j++) {
3832 // VPads int jj = mapGrpIdxToJ[j];
3833 int jj = j;
3834 // if ( (mapIJToK[ii*nbrCath1+jj] != -1))
3835 printf(" %d inter %d, grp : %d inter %d yes=%d\n", ii, jj, i, j,
3836 mapIJToK[ii * N1 + jj]);
3837 }
3838 }
3839 }
3840 for (int u = 0; u < KU; u++) {
3841 //
3842 PadIdx_t uPadIdx = localMaxU[u];
3843 double maxValue = 0.0;
3844 // Cathode-V pad index of the max (localMaxV)
3845 PadIdx_t maxPadVIdx = -1;
3846 // Index in the maxCathv
3847 PadIdx_t maxCathVIdx = -1;
3848 // Choose the best localMaxV
3849 // i.e. the maximum value among
3850 // the unselected localMaxV
3851 //
3852 // uPadIdx in index in the Grp
3853 // need to get the cluster index
3854 // to checck the intersection
3855 // VPads int ug = mapGrpIdxToU[uPadIdx];
3856 int ug = uPadIdx;
3858 printf(" Cathode u=%d localMaxU[u]=%d, x,y= %6.3f, %6.3f, q=%6.3f\n", u,
3859 localMaxU[u], xu[localMaxU[u]], yu[localMaxU[u]],
3860 qU[localMaxU[u]]);
3861 }
3862 bool interuv;
3863 for (int v = 0; v < KV; v++) {
3864 PadIdx_t vPadIdx = localMaxV[v];
3865 // VPads int vg = mapGrpIdxToV[vPadIdx];
3866 int vg = vPadIdx;
3867 if (permuteIJ) {
3868 // printf("uPadIdx=%d,vPadIdx=%d, mapIJToK[vPadIdx*N0+uPadIdx]=%d
3869 // permute\n",uPadIdx,vPadIdx, mapIJToK[vPadIdx*N0+uPadIdx]);
3870 interuv = (mapIJToK[vg * N1 + ug] != -1);
3871 } else {
3872 // printf("uPadIdx=%d,vPadIdx=%d,
3873 // mapIJToK[uPadIdx*N1+vPadIdx]=%d\n",uPadIdx,vPadIdx,
3874 // mapIJToK[uPadIdx*N1+vPadIdx]);
3875 interuv = (mapIJToK[ug * N1 + vg] != -1);
3876 }
3877 if (interuv) {
3878 double val = qV[vPadIdx] * qvAvailable[v];
3879 if (val > maxValue) {
3880 maxValue = val;
3881 maxCathVIdx = v;
3882 maxPadVIdx = vPadIdx;
3883 }
3884 }
3885 }
3886 // A this step, we've got (or not) an
3887 // intercepting pad v with u. This v is
3888 // the maximum of all possible values
3889 // ??? printf("??? maxPadVIdx=%d, maxVal=%f\n", maxPadVIdx, maxValue);
3890 if (maxPadVIdx != -1) {
3891 // Found an intersevtion and a candidate
3892 // add in the list of seeds
3893 PadIdx_t kProj;
3894 int vg = mapGrpIdxToV[maxPadVIdx];
3895 if (permuteIJ) {
3896 kProj = mapIJToK[vg * N1 + ug];
3897 } else {
3898 kProj = mapIJToK[ug * N1 + vg];
3899 }
3900 // mapIJToK and projection UNUSED ????
3901 localXMax[k] = xProj[kProj];
3902 localYMax[k] = yProj[kProj];
3903 // localQMax[k] = 0.5 * (qU[uPadIdx] + qV[maxPadVIdx]);
3904 localQMax[k] = qU[uPadIdx];
3905 // Cannot be selected again as a seed
3906 qvAvailable[maxCathVIdx] = 0;
3908 printf(
3909 " found intersection of u with v: u,v=(%d,%d) , x=%f, y=%f, "
3910 "w=%f\n",
3911 u, maxCathVIdx, localXMax[k], localYMax[k], localQMax[k]);
3912 // printf("Projection u=%d, v=%d, uPadIdx=%d, ,maxPadVIdx=%d, kProj=%d,
3913 // xProj[kProj]=%f, yProj[kProj]=%f\n", u, maxCathVIdx,
3914 // uPadIdx, maxPadVIdx, kProj, xProj[kProj], yProj[kProj] );
3915 // kProj = mapIJToK[maxPadVIdx*N0 + uPadIdx];
3916 // printf(" permut kProj=%d xProj[kProj], yProj[kProj] = %f %f\n",
3917 // kProj, xProj[kProj], yProj[kProj] );
3918 }
3919 k++;
3920 } else {
3921 // No intersection u with localMaxV set
3922 // Approximate the seed position
3923 //
3924 // Search v pads intersepting u
3925 PadIdx_t* uInterV;
3926 PadIdx_t uPad = 0;
3928 printf(
3929 " No intersection between u=%d and v-set of , approximate the "
3930 "location\n",
3931 u);
3932 }
3933 // Go to the mapGrpIdxToU[uPadIdx] (???? mapUToGrpIdx[uPadIdx])
3934 uInterV = interUV;
3935 if (NV != 0) {
3936 for (uInterV = interUV; uPad < ug; uInterV++) {
3937 if (*uInterV == -1) {
3938 uPad++;
3939 }
3940 }
3941 }
3942 // if (uInterV) printf("??? uPad=%d, uPadIdx=%d *uInterV=%d\n", uPad,
3943 // uPadIdx, *uInterV); If intercepting pads or no V-Pad
3944 if ((NV != 0) && (uInterV[0] != -1)) {
3945 double vMin = 1.e+06;
3946 double vMax = -1.e+06;
3947 // Take the most precise direction
3948 if (dxu[u] < dyu[u]) {
3949 // x direction most precise
3950 // Find the y range intercepting pad u
3951 for (; *uInterV != -1; uInterV++) {
3952 PadIdx_t idx = mapVToGrpIdx[*uInterV];
3954 printf(" Global upad=%d intersect global vpad=%d grpIdx=%d\n",
3955 uPad, *uInterV, idx);
3956 }
3957 if (idx != -1) {
3958 vMin = fmin(vMin, yv[idx] - dyv[idx]);
3959 vMax = fmax(vMax, yv[idx] + dyv[idx]);
3960 }
3961 }
3962 localXMax[k] = xu[uPadIdx];
3963 localYMax[k] = 0.5 * (vMin + vMax);
3964 localQMax[k] = qU[uPadIdx];
3965 if (localYMax[k] == 0 &&
3967 printf("WARNING localYMax[k] == 0, meaning no intersection");
3968 }
3969 } else {
3970 // y direction most precise
3971 // Find the x range intercepting pad u
3972 for (; *uInterV != -1; uInterV++) {
3973 PadIdx_t idx = mapVToGrpIdx[*uInterV];
3975 printf(" Global upad=%d intersect global vpad=%d grpIdx=%d \n",
3976 uPad, *uInterV, idx);
3977 }
3978 if (idx != -1) {
3980 printf(
3981 "xv[idx], yv[idx], dxv[idx], dyv[idx]: %6.3f %6.3f "
3982 "%6.3f %6.3f\n",
3983 xv[idx], yv[idx], dxv[idx], dyv[idx]);
3984 }
3985 vMin = fmin(vMin, xv[idx] - dxv[idx]);
3986 vMax = fmax(vMax, xv[idx] + dxv[idx]);
3987 }
3988 }
3989 localXMax[k] = 0.5 * (vMin + vMax);
3990 localYMax[k] = yu[uPadIdx];
3991 localQMax[k] = qU[uPadIdx];
3992 // printf(" uPadIdx = %d/%d\n", uPadIdx, KU);
3993 if (localXMax[k] == 0 &&
3995 printf("WARNING localXMax[k] == 0, meaning no intersection");
3996 }
3997 }
3999 printf(
4000 " solution found with all intersection of u=%d with all v, x "
4001 "more precise %d, position=(%f,%f), qU=%f\n",
4002 u, (dxu[u] < dyu[u]), localXMax[k], localYMax[k],
4003 localQMax[k]);
4004 }
4005 k++;
4006 } else {
4007 // No interception in the v-list
4008 // or no V pads
4009 // Takes the u values
4010 // printf("No intersection of the v-set with u=%d, take the u location",
4011 // u);
4012
4013 localXMax[k] = xu[uPadIdx];
4014 localYMax[k] = yu[uPadIdx];
4015 localQMax[k] = qU[uPadIdx];
4017 printf(
4018 " No intersection with u, u added in local Max: k=%d u=%d, "
4019 "position=(%f,%f), qU=%f\n",
4020 k, u, localXMax[k], localYMax[k], localQMax[k]);
4021 }
4022 k++;
4023 }
4024 }
4025 }
4026 // Proccess unselected localMaxV
4027 for (int v = 0; v < KV; v++) {
4028 if (qvAvailable[v]) {
4029 int l = localMaxV[v];
4030 localXMax[k] = xv[l];
4031 localYMax[k] = yv[l];
4032 localQMax[k] = qV[l];
4034 printf(
4035 " Remaining VMax, v added in local Max: v=%d, "
4036 "position=(%f,%f), qU=%f\n",
4037 v, localXMax[k], localYMax[k], localQMax[k]);
4038 }
4039 k++;
4040 }
4041 }
4042 // k seeds
4043 double* varX = getVarX(thetaOut, kMax);
4044 double* varY = getVarY(thetaOut, kMax);
4045 double* muX = getMuX(thetaOut, kMax);
4046 double* muY = getMuY(thetaOut, kMax);
4047 double* w = getW(thetaOut, kMax);
4048 //
4049 double wRatio = 0;
4050 for (int k_ = 0; k_ < k; k_++) {
4051 wRatio += localQMax[k_];
4052 }
4053 wRatio = 1.0 / wRatio;
4055 printf("Local max found k=%d kmax=%d\n", k, kMax);
4056 }
4057 for (int k_ = 0; k_ < k; k_++) {
4058 muX[k_] = localXMax[k_];
4059 muY[k_] = localYMax[k_];
4060 w[k_] = localQMax[k_] * wRatio;
4062 printf(" w=%6.3f, mux=%7.3f, muy=%7.3f\n", w[k_], muX[k_], muY[k_]);
4063 }
4064 }
4065 return k;
4066}
4067
4068} // namespace mch
4069} // namespace o2
Clustering and fifting parameters.
Definition of a class to reconstruct clusters with the MLEM algorithm.
int32_t i
float & yMax
void inspectSavePixels(int which, o2::mch::Pads &pixels)
void saveProjPadToGroups(o2::mch::Groups_t *projPadToGrp, int N)
void inspectOverWriteQ(int which, const double *qPixels)
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
Definition A.h:16
std::pair< int, int > getNxNy(int c)
const double * getCharges(int c)
Definition ClusterPEM.h:70
int findLocalMaxWithBothCathodes(double *thetaOut, int kMax)
int findLocalMaxWithPEMFullRefinement(double *thetaL, int nbrOfPadsInTheGroupCath)
DataBlock_t fit(double *thetaInit, int K)
int buildProjectedGeometry(int includeAlonePads)
double * projectChargeOnProjGeometry(int includeAlonePads)
int getNbrOfPadsInGroup(int g)
int findLocalMaxWithPEM2Lev(double *thetaL, int nbrOfPadsInTheGroupCath)
std::pair< double, double > computeChargeBarycenter(int plane)
int findLocalMaxWithPEM(double *thetaL, int nbrOfPadsInTheGroupCath)
double getTotalCharge(int c)
Definition ClusterPEM.h:65
const Pads * getPads(int c)
Definition ClusterPEM.h:77
const double * getX() const
Definition PadsPEM.h:91
static void printNeighbors(const PadIdx_t *neigh, int N)
Definition PadsPEM.cxx:2237
const double * getXSup() const
Definition PadsPEM.h:97
@ 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
Pads * refineAll()
Definition PadsPEM.cxx:1170
const double * getDY() const
Definition PadsPEM.h:94
int addIsolatedPadInGroups(Mask_t *cathToGrp, Mask_t *grpToGrp, int nGroups)
Definition PadsPEM.cxx:847
const double * getCharges() const
Definition PadsPEM.h:99
const double * getYInf() const
Definition PadsPEM.h:96
const double * getY() const
Definition PadsPEM.h:92
int getNbrOfObsPads() const
Definition PadsPEM.h:90
Pads * addBoundaryPads()
Definition PadsPEM.cxx:193
const double * getXInf() const
Definition PadsPEM.h:95
void normalizeCharges()
Definition PadsPEM.cxx:830
PadIdx_t * getFirstNeighbors()
Definition PadsPEM.cxx:838
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
const double * getDX() const
Definition PadsPEM.h:93
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLint GLint GLsizei GLuint * counters
Definition glcorearb.h:3985
GLuint GLfloat GLfloat GLfloat GLfloat y1
Definition glcorearb.h:5034
const GLdouble * v
Definition glcorearb.h:832
GLuint GLfloat GLfloat GLfloat x1
Definition glcorearb.h:5034
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLfloat x0
Definition glcorearb.h:5034
GLboolean GLboolean g
Definition glcorearb.h:1233
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
Definition glcorearb.h:275
GLuint GLfloat * val
Definition glcorearb.h:1582
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLuint GLfloat GLfloat y0
Definition glcorearb.h:5034
void vectorPrintShort(const char *str, const short *x, int K)
Definition mathUtil.cxx:43
std::pair< int, double * > DataBlock_t
Definition ClusterPEM.h:30
void maskedCopyTheta(const double *theta, int K, const Mask_t *mask, int nMask, double *maskedTheta, int maskedK)
double * getMuY(double *theta, int K)
short Groups_t
void printTheta(const char *str, double meanCharge, const double *theta, int K)
void print_matrix(const gsl_matrix *m)
void computeFastCij(const Pads &pads, const Pads &pixel, double Cij[])
double epsilonGeometry
void printGSLVector(const char *str, const gsl_vector *v)
const double * getConstVarY(const double *theta, int K)
void copyTheta(const double *theta0, int K0, double *theta, int K1, int K)
short Mask_t
void vectorPrint(const char *str, const double *x, int K)
Definition mathUtil.cxx:20
double * getVarX(double *theta, int K)
void printMatrixShort(const char *str, const short *matrix, int N, int M)
Definition mathUtil.cxx:74
int main()
void checkCij(const Pads &pads, const Pads &pixels, const double *checkCij, int mode)
double * getMuX(double *theta, int K)
double * getW(double *theta, int K)
void printInterMap(const char *str, const PadIdx_t *inter, int N)
Definition mathUtil.cxx:98
const double * getConstMuX(const double *theta, int K)
void deleteInt(int *ptr)
Definition mathUtil.h:532
double * getVarY(double *theta, int K)
void deleteShort(short *ptr)
Definition mathUtil.h:540
const double * getConstMuY(const double *theta, int K)
ClusterConfig clusterConfig
gsl_matrix * moore_penrose_pinv(gsl_matrix *A, double rcond)
const double * getConstVarX(const double *theta, int K)
std::pair< double, double > PoissonEMLoop(const Pads &pads, Pads &pixels, const double *Cij, Mask_t *maskCij, int qCutMode, double minPadError, int nItMax)
void fitMathieson(const Pads &iPads, double *thetaInit, int kInit, int dimOfParameters, int axe, int mode, double *thetaFinal, double *khi2, double *pError)
void printMatrixChar(const char *str, const char *matrix, int N, int M)
Definition mathUtil.cxx:86
double realtype
void vectorPrintInt(const char *str, const int *x, int K)
Definition mathUtil.cxx:34
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
@ active
Describe default activation.
ActivateMode inspectModel
VerboseMode laplacianLocalMaxLog
@ info
Describes main steps and high level behaviors.
@ detail
Describes in detail.
constexpr size_t max
const std::string str