R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandTSyncer.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
14#include "R3BNeulandTSyncer.h"
15#include "LSQR.h"
16
17#include "FairLogger.h"
18
19#include "TF1.h"
20
21#include <numeric>
22
23constexpr auto NextBarLogSize = 128;
24constexpr auto NextPlaneLogSize = 64;
25constexpr auto NBins = 256;
26
27namespace R3B::Neuland // NOLINT
28{
29 namespace Calibration
30 {
32 : SamplingHistogram("", "", MaxCalTime / 2, -MaxCalTime, MaxCalTime)
33 {
34 SamplingHistogram.SetDirectory(nullptr);
35 for (auto& m : HitMask)
36 m = 0UL;
37
38 for (auto& bar : Data)
39 {
40 bar.NextBarLog.reserve(NextBarLogSize);
41 for (auto b = 0; b < BarsPerPlane; ++b)
42 bar.NextPlaneLog[b].reserve(NextPlaneLogSize);
43 }
44 }
45
46 void TSyncer::AddBarData(const Int_t barID, const Double_t time)
47 {
48 const auto bar = barID % BarsPerPlane;
49 const auto plane = ModuleID2PlaneID(barID);
50 HitMask[plane] |= 1UL << bar;
51 EventData[barID] = time;
52 }
53
54 void TSyncer::ClearBarData(const Int_t barID)
55 {
56 Data[barID].NextBar.Clear();
57 Data[barID].NextBarLog.clear();
58 for (auto b = 0; b < BarsPerPlane; ++b)
59 {
60 Data[barID].NextPlane[b].Clear();
61 Data[barID].NextPlaneLog[b].clear();
62 }
63
64 const auto bar = barID % BarsPerPlane;
65 const auto plane = ModuleID2PlaneID(barID);
66
67 if (bar != 0)
68 {
69 // This is not the first bar in the plane
70 // Clear the Data from the bar before
71 Data[barID - 1].NextBar.Clear();
72 Data[barID - 1].NextBarLog.clear();
73 }
74
75 if (plane != 0)
76 {
77 // This is not the first plane
78 // Clear the Data of this bar from the previous plane
79 for (auto b = (plane - 1) * BarsPerPlane; b < plane * BarsPerPlane; ++b)
80 {
81 Data[b].NextPlane[bar].Clear();
82 Data[b].NextPlaneLog[bar].clear();
83 }
84 }
85 }
86
88 {
89 for (auto plane = 0; plane < MaxNumberOfPlanes; ++plane)
90 {
91 if (HitMask[plane] == 0UL)
92 continue;
93
94 for (auto bar = 0; bar < BarsPerPlane; ++bar)
95 {
96 if ((HitMask[plane] & (1UL << bar)) == 0UL)
97 continue;
98
99 const auto barID = plane * BarsPerPlane + bar;
100 auto& barData = Data[barID];
101
102 if ((bar < BarsPerPlane - 1) && (HitMask[plane] & (1UL << (bar + 1))))
103 {
104 auto tdiff = EventData[barID + 1] - EventData[barID];
105 if (fabs(tdiff) > 0.5 * MaxCalTime)
106 {
107 if (tdiff < 0)
108 tdiff += MaxCalTime;
109 else
110 tdiff -= MaxCalTime;
111 }
112
113 if (barData.NextBarLog.size() < NextBarLogSize)
114 {
115 barData.NextBarLog.push_back(tdiff);
116 if (barData.NextBarLog.size() == NextBarLogSize)
117 {
118 SamplingHistogram.Reset();
119 for (auto t : barData.NextBarLog)
120 SamplingHistogram.Fill(t);
121 const auto max = SamplingHistogram.GetBinCenter(SamplingHistogram.GetMaximumBin());
122 barData.NextBar = TH1F("", "", NBins, max - 10, max + 10);
123 barData.NextBar.SetDirectory(nullptr);
124 for (auto t : barData.NextBarLog)
125 barData.NextBar.Fill(t);
126 }
127 }
128 else
129 {
130 barData.NextBar.Fill(tdiff);
131 }
132 }
133
134 const auto nextPlane = plane + 1;
135 if (nextPlane >= MaxNumberOfPlanes || !HitMask[nextPlane])
136 continue;
137
138 for (auto barInNextPlane = 0; barInNextPlane < BarsPerPlane; ++barInNextPlane)
139 {
140 if ((HitMask[nextPlane] & (1UL << barInNextPlane)) == 0UL)
141 continue;
142
143 const auto nextPlaneBarID = nextPlane * BarsPerPlane + barInNextPlane;
144 auto tdiff = EventData[nextPlaneBarID] - EventData[barID];
145 if (fabs(tdiff) > 0.5 * MaxCalTime)
146 {
147 if (tdiff < 0)
148 tdiff += MaxCalTime;
149 else
150 tdiff -= MaxCalTime;
151 }
152
153 if (barData.NextPlaneLog[barInNextPlane].size() < NextPlaneLogSize)
154 {
155 barData.NextPlaneLog[barInNextPlane].push_back(tdiff);
156 if (barData.NextPlaneLog[barInNextPlane].size() == NextPlaneLogSize)
157 {
158 SamplingHistogram.Reset();
159 for (auto t : barData.NextPlaneLog[barInNextPlane])
160 SamplingHistogram.Fill(t);
161 const auto max = SamplingHistogram.GetBinCenter(SamplingHistogram.GetMaximumBin());
162 barData.NextPlane[barInNextPlane] = TH1F("", "", NBins, max - 25, max + 25);
163 barData.NextPlane[barInNextPlane].SetDirectory(nullptr);
164 for (auto t : barData.NextPlaneLog[barInNextPlane])
165 barData.NextPlane[barInNextPlane].Fill(t);
166 }
167 }
168 else
169 {
170 barData.NextPlane[barInNextPlane].Fill(tdiff);
171 }
172 }
173 }
174 HitMask[plane] = 0UL;
175 }
176 }
177
178 std::vector<TSyncer::ValueErrorPair> TSyncer::GetTSync(UInt_t nPlanes)
179 {
180 calcTSyncs();
181 const auto nBars = nPlanes * BarsPerPlane;
182 std::vector<ValueErrorPair> solution(nBars, { NaN, NaN });
183 std::vector<Double_t> scaleFactors(nBars, 0.);
184
185 // First get the number of Equations and the scaling Factor.
186 // A bit slower but less Memory hungry
187 UInt_t numberOfEquations = 0;
188 for (auto b = 0; b < nBars; ++b)
189 {
190 if (!std::isnan(Data[b].TSyncNextBar.Value))
191 {
192 scaleFactors[b] += 1. / Sqr(Data[b].TSyncNextBar.Error);
193 scaleFactors[b + 1] += 1. / Sqr(Data[b].TSyncNextBar.Error);
194 ++numberOfEquations;
195 }
196
197 const auto plane = ModuleID2PlaneID(b);
198 if (plane == nPlanes - 1)
199 continue;
200
201 for (auto ob = 0; ob < BarsPerPlane; ++ob)
202 {
203 if (!std::isnan(Data[b].TSyncNextPlane[ob].Value))
204 {
205 scaleFactors[b] += 1. / Sqr(Data[b].TSyncNextPlane[ob].Error);
206 scaleFactors[plane * BarsPerPlane + ob] += 1. / Sqr(Data[b].TSyncNextPlane[ob].Error);
207 ++numberOfEquations;
208 }
209 }
210 }
211
212 // we have less Equations than bars,
213 // seems like we do not have enough statistics in most bars
214 if (numberOfEquations < nBars)
215 {
216 LOG(info) << "Can not synchronize NeuLAND. Not enough equations (" << numberOfEquations << ").";
217 return solution;
218 }
219
220 for (auto b = 0; b < nBars; ++b)
221 scaleFactors[b] = 1. / sqrt(scaleFactors[b]);
222
223 // Now setup for LSQR
224 // --- Legacy Code Warning ---
225
226 LSQR_INPUTS* input;
227 LSQR_OUTPUTS* output;
228 LSQR_WORK* work;
229
230 struct Element
231 {
232 std::array<UInt_t, 2> Index;
233 std::array<Double_t, 2> Value;
234 };
235
236 std::vector<Element> lhs(numberOfEquations);
237 const auto numberOfVariables = BarsPerPlane * nPlanes;
238 auto function = [&lhs, numberOfVariables](
239 int64_t mode, LSQR_DOUBLE_VECTOR* xVec, LSQR_DOUBLE_VECTOR* yVec, void* /*data*/)
240 {
241 double* x = xVec->elements;
242 double* y = yVec->elements;
243
244 if (mode == 0)
245 {
246 for (uint r = 0; r < lhs.size(); ++r)
247 {
248 *y += x[lhs[r].Index[0]] * lhs[r].Value[0] + x[lhs[r].Index[1]] * lhs[r].Value[1];
249
250 ++y;
251 }
252 }
253 else
254 {
255 for (uint r = 0; r < lhs.size(); ++r)
256 {
257 x[lhs[r].Index[0]] += (*y) * lhs[r].Value[0];
258 x[lhs[r].Index[1]] += (*y) * lhs[r].Value[1];
259
260 ++y;
261 }
262 }
263
264 x = xVec->elements;
265 y = yVec->elements + lhs.size();
266
267 if (mode == 0)
268 {
269 for (auto i = 0; i < numberOfVariables; i++)
270 *y += x[i];
271 }
272 else
273 {
274 for (auto i = 0; i < numberOfVariables; i++)
275 x[i] += *y;
276 }
277 };
278
279 alloc_lsqr_mem(&input, &output, &work, numberOfEquations + 1, nBars);
280
281 input->num_rows = numberOfEquations;
282 input->num_cols = nBars;
283 input->damp_val = 0.; // we want damping (i.e. in this case average of all solution vars = 0)
284 input->rel_mat_err = 1.0e-10; // TODO: this should be set to something reasonable
285 input->rel_rhs_err = 1.0e-10; // TODO: this should be set to something reasonable
286 input->cond_lim = 0.; // 10.0 * act_mat_cond_num;
287 input->max_iter = input->num_rows + input->num_cols + 50;
288 input->lsqr_fp_out = nullptr;
289
290 auto nEQ = 0;
291 for (UInt_t id = 0; id < Data.size(); ++id)
292 {
293 const auto plane = ModuleID2PlaneID(static_cast<int>(id));
294 if (!std::isnan(Data[id].TSyncNextBar.Value))
295 {
296 const auto weight = 1. / Data[id].TSyncNextBar.Error;
297 lhs[nEQ] = { { id, id + 1U }, { -weight * scaleFactors[id], weight * scaleFactors[id + 1U] } };
298 input->rhs_vec->elements[nEQ] = Data[id].TSyncNextBar.Value * weight;
299 ++nEQ;
300 }
301 for (UInt_t barInNextPlane = 0; barInNextPlane < BarsPerPlane; ++barInNextPlane)
302 {
303 if (!std::isnan(Data[id].TSyncNextPlane[barInNextPlane].Value))
304 {
305 const auto barInNextPlaneID = BarsPerPlane * (plane + 1) + barInNextPlane;
306 const auto weight = 1. / Data[id].TSyncNextPlane[barInNextPlane].Error;
307 lhs[nEQ] = { { id, barInNextPlaneID },
308 { -weight * scaleFactors[id], weight * scaleFactors[barInNextPlaneID] } };
309 input->rhs_vec->elements[nEQ] = Data[id].TSyncNextPlane[barInNextPlane].Value * weight;
310 ++nEQ;
311 }
312 }
313 }
314
315 for (auto bar = 0; bar < nBars; ++bar)
316 input->sol_vec->elements[bar] = 0.;
317
318 input->rhs_vec->elements[numberOfEquations] = 0.; // we will use this one the put the mean value to 0
319
320 LOG(debug) << "Syncing Neuland with " << numberOfEquations << " equations...";
321
322 lsqr(input, output, work, function, &lhs);
323
324 for (auto id = 0; id < nBars; ++id)
325 {
326 solution[id] = { output->sol_vec->elements[id] * scaleFactors[id],
327 output->std_err_vec->elements[id] * scaleFactors[id] };
328 }
329 free_lsqr_mem(input, output, work);
330
331 return solution;
332 }
333
334 void TSyncer::calcTSyncs()
335 {
336 for (auto& bar : Data)
337 {
338 bar.TSyncNextBar = { NaN, NaN };
339 if (bar.NextBar.Integral() > bar.NextBar.GetEntries() * 0.5 &&
340 bar.NextBar.Integral() > 0.5 * NextBarLogSize)
341 {
342 bar.TSyncNextBar = { bar.NextBar.GetMean(), bar.NextBar.GetStdDev() };
343 }
344
345 for (auto nb = 0; nb < BarsPerPlane; ++nb)
346 {
347 bar.TSyncNextPlane[nb] = { NaN, NaN };
348 if (bar.NextPlane[nb].Integral() > bar.NextPlane[nb].GetEntries() * 0.5 &&
349 bar.NextPlane[nb].Integral() > 0.5 * NextPlaneLogSize)
350 {
351 bar.TSyncNextPlane[nb] = { bar.NextPlane[nb].GetMean(), bar.NextPlane[nb].GetStdDev() };
352 }
353 }
354 }
355 }
356 } // namespace Calibration
357} // namespace R3B::Neuland
void lsqr(lsqr_input *input, lsqr_output *output, lsqr_work *work, std::function< void(long, dvec *, dvec *, void *)> mat_vec_prod, void *prod)
Definition LSQR.cxx:418
void alloc_lsqr_mem(lsqr_input **in_struct, lsqr_output **out_struct, lsqr_work **wrk_struct, long max_num_rows, long max_num_cols)
Definition LSQR.cxx:173
void free_lsqr_mem(lsqr_input *in_struct, lsqr_output *out_struct, lsqr_work *wrk_struct)
Definition LSQR.cxx:210
constexpr auto NBins
constexpr auto NextPlaneLogSize
constexpr auto NextBarLogSize
void AddBarData(const Int_t barID, const Double_t time)
std::vector< ValueErrorPair > GetTSync(UInt_t nPlanes=Neuland::MaxNumberOfPlanes)
Simulation of NeuLAND Bar/Paddle.
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto NaN
constexpr auto MaxNumberOfPlanes
constexpr T Sqr(const T val)
constexpr auto MaxCalTime
double * elements
Definition LSQR.h:113
dvec * rhs_vec
Definition LSQR.h:203
FILE * lsqr_fp_out
Definition LSQR.h:202
long num_rows
Definition LSQR.h:195
double damp_val
Definition LSQR.h:197
long num_cols
Definition LSQR.h:196
double cond_lim
Definition LSQR.h:200
dvec * sol_vec
Definition LSQR.h:204
long max_iter
Definition LSQR.h:201
double rel_rhs_err
Definition LSQR.h:199
double rel_mat_err
Definition LSQR.h:198
dvec * std_err_vec
Definition LSQR.h:312
dvec * sol_vec
Definition LSQR.h:311
constexpr Int_t nPlanes