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