R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandMillepede.cxx
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2023 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 "R3BNeulandMillepede.h"
15#include "ParResultReader.h"
16#include "R3BDataMonitor.h"
17#include "R3BLogger.h"
18#include "R3BNeulandCalData2.h"
21#include <R3BException.h>
23#include <R3BNeulandCommon.h>
24#include <SteerWriter.h>
25
26#include <TGraphErrors.h>
27#include <TH1.h>
28#include <algorithm>
29#include <array>
30#include <fmt/core.h>
31#include <iterator>
32#include <memory>
33#include <numeric>
34#include <range/v3/algorithm/all_of.hpp>
35#include <range/v3/iterator/operations.hpp>
36#include <range/v3/numeric/accumulate.hpp>
37#include <range/v3/view.hpp>
38
39#include <cstdlib>
40#include <optional>
41#include <range/v3/view/all.hpp>
42#include <range/v3/view/filter.hpp>
43#include <range/v3/view/sliding.hpp>
44#include <range/v3/view/transform.hpp>
45#include <stdexcept>
46#include <string>
47#include <utility>
48#include <vector>
49
50namespace rng = ranges;
51
52constexpr auto DEFAULT_RES_FILENAME = "millepede.res";
53constexpr auto SCALE_FACTOR = 10.F;
54// constexpr auto REFERENCE_BAR_NUM = 25;
55constexpr auto MILLE_BUFFER_SIZE = std::size_t{ 100000 };
56constexpr auto DEFAULT_T_ERROR = 2; // ns
57
58namespace
59{
60 void calculate_time_offset(R3B::Neuland::Cal2HitPar& cal_to_hit_par)
61 {
62 auto& module_pars = cal_to_hit_par.GetListOfModuleParRef();
63 for (auto& [module_num, module_par] : module_pars)
64 {
65 if (module_par.effective_speed.value != 0)
66 {
67 module_par.t_diff = module_par.t_diff / module_par.effective_speed;
68 }
69 }
70 }
71
72 void change_time_offset(R3B::Neuland::Cal2HitPar& cal_to_hit_par)
73 {
74 auto& module_pars = cal_to_hit_par.GetListOfModuleParRef();
75 for (auto& [module_num, module_par] : module_pars)
76 {
77 module_par.t_diff = module_par.t_diff * module_par.effective_speed;
78 }
79 }
80} // namespace
81
83{
85 {
86 cal_to_hit_par_ = GetTask()->GetCal2HitPar();
87
88 par_result_.set_filename(DEFAULT_RES_FILENAME);
89 pede_launcher_.set_steer_filename(pede_steer_filename_);
90 pede_launcher_.set_parameter_filename(parameter_filename_);
91 if (const auto* r3b_dir = std::getenv("R3BROOTPATH"); r3b_dir != nullptr)
92 {
93 pede_launcher_.set_binary_dir(fmt::format("{}/bin", r3b_dir));
94 }
95 else
96 {
98 "Environment variable R3BROOTPATH is not defined! Did you forget to source the \"config.sh\" file?");
99 }
100 binary_data_writer_.set_buffer_size(MILLE_BUFFER_SIZE);
101 data_preprocessor_ = std::make_unique<MilleDataProcessor>(GetModuleSize());
102 data_preprocessor_->set_p_value_cut(p_value_cut_);
103
104 init_steer_writer();
105 init_parameter();
106 }
107
108 // output: module_num & global label
109 inline auto MillepedeEngine::to_module_num_label(int par_num) -> std::pair<int, GlobalLabel>
110 {
111 const auto num_of_module = GetModuleSize();
112 auto res = std::pair<int, GlobalLabel>{};
113 const auto factor = (par_num - 1) / num_of_module;
114 res.first = (par_num - 1) % num_of_module + 1;
115
116 switch (factor)
117 {
118 // case 0:
119 // res.second = GlobalLabel::tsync;
120 // break;
121 // case 1:
122 // res.second = GlobalLabel::offset_effective_c;
123 // break;
124 // case 2:
125 // res.second = GlobalLabel::effective_c;
126 // break;
127 case 0:
129 break;
130 case 1:
131 res.second = GlobalLabel::effective_c;
132 break;
133 default:
134 throw R3B::logic_error(fmt::format("An error occured with unrecognized global par id: {}", par_num));
135 }
136
137 return res;
138 }
139
140 inline auto MillepedeEngine::get_global_label_id(int module_num, GlobalLabel label) -> int
141 {
142 const auto num_of_module = GetModuleSize();
143 switch (label)
144 {
145 // case GlobalLabel::tsync:
146 // return module_num;
147 // case GlobalLabel::offset_effective_c:
148 // return module_num + num_of_module;
149 // case GlobalLabel::effective_c:
150 // return module_num + (2 * num_of_module);
152 return module_num;
154 return module_num + num_of_module;
155 default:
156 throw R3B::logic_error("An error occured with unrecognized global tag");
157 }
158 }
159
160 void MillepedeEngine::fill_module_parameters(const Millepede::ResultReader& result,
161 Neuland::Cal2HitPar& cal_to_hit_par)
162 {
163 change_time_offset(cal_to_hit_par);
164 const auto& pars = result.get_pars();
165 for (const auto& [par_id, par] : pars)
166 {
167 const auto [module_num, global_label] = to_module_num_label(par_id);
168 auto& module_pars = cal_to_hit_par.GetListOfModuleParRef();
169
170 auto& par_ref = module_pars.emplace(module_num, HitModulePar{}).first->second;
171 switch (global_label)
172 {
174 par_ref.t_sync.value = par.value * SCALE_FACTOR;
175 par_ref.t_sync.error = par.error * SCALE_FACTOR;
176 break;
178 // The value here is the product of tDiff and effectiveSped. Real tDiff will be calculated later
179 par_ref.t_diff.value += par.value * SCALE_FACTOR;
180 par_ref.t_diff.error += par.error * SCALE_FACTOR;
181 break;
183 par_ref.effective_speed.value += par.value;
184 par_ref.effective_speed.error += par.error;
185 break;
186 default:
187 throw std::runtime_error("An error occured with unrecognized global tag");
188 }
189 }
190
191 calculate_time_offset(cal_to_hit_par);
192 }
193
194 auto MillepedeEngine::set_minimum_values(const std::vector<R3B::Neuland::BarCalData>& signals) -> bool
195 {
196 // make sure only one hit exists in one bar
197 auto filtered_signals = rng::filter_view(
198 signals | rng::views::all,
199 [](const auto& bar_signal) { return bar_signal.left.size() == 1 and bar_signal.right.size() == 1; });
200 if (filtered_signals.empty())
201 {
202 return false;
203 }
204
205 if (not average_t_sum_.has_value())
206 {
207 auto t_sum_view = filtered_signals | rng::views::transform(
208 [](const auto& bar_signal)
209 {
210 const auto& left_signal = bar_signal.left.front();
211 const auto& right_signal = bar_signal.right.front();
212 return (left_signal.leading_time - left_signal.trigger_time +
213 right_signal.leading_time - right_signal.trigger_time)
214 .value;
215 });
216 auto sum = rng::accumulate(t_sum_view, 0.F);
217 average_t_sum_ = sum / static_cast<float>(rng::distance(t_sum_view.begin(), t_sum_view.end()));
218 R3BLOG(info, fmt::format("Average t_sum is calculated to be {}", average_t_sum_.value()));
219 }
220 return true;
221 }
222
223 auto MillepedeEngine::SignalFilter(const std::vector<BarCalData>& signals) -> bool
224 {
225 // select out rays with few hits
226 if (signals.size() < minimum_hit_)
227 {
228 return false;
229 }
230
231 // select out vertical cosmic rays
232 if (rng::all_of(signals |
233 rng::views::transform([](const auto& bar_signal)
234 { return ModuleID2PlaneID(bar_signal.module_num - 1); }) |
235 rng::views::sliding(2),
236 [](const auto& pair) { return pair.front() == pair.back(); }))
237 {
238 return false;
239 }
240
241 if (not set_minimum_values(signals))
242 {
243 return false;
244 }
245
246 return true;
247 }
248
249 void MillepedeEngine::add_signal_t_sum(const MilleCalData& signal)
250 {
251 buffer_clear();
252 const auto module_num = static_cast<int>(signal.module_num);
253 const auto pos_z = ModuleNum2ZPos<float>(static_cast<int>(module_num));
254
255 auto init_effective_c = cal_to_hit_par_->GetModuleParAt(module_num).effective_speed.value;
256
257 const auto& left_signal = signal.left;
258 const auto& right_signal = signal.right;
259 const auto t_sum = (left_signal.leading_time - left_signal.trigger_time) +
260 (right_signal.leading_time - right_signal.trigger_time) - average_t_sum_.value_or(0.F);
261
262 input_data_buffer_.measurement =
263 static_cast<float>((t_sum.value / SCALE_FACTOR / 2.F) - (BarLength / SCALE_FACTOR / init_effective_c));
264 input_data_buffer_.sigma = static_cast<float>(t_sum.error / SCALE_FACTOR / 2. * error_scale_factor_);
265 // input_data_buffer_.sigma = static_cast<float>(DEFAULT_MEAS_ERROR);
266 const auto local_derivs_t = std::array{ 0.F, 0.F, pos_z / SCALE_FACTOR, 0.F, 0.F, 1.F };
267 std::copy(local_derivs_t.begin(), local_derivs_t.end(), std::back_inserter(input_data_buffer_.locals));
268 input_data_buffer_.globals.emplace_back(get_global_label_id(module_num, GlobalLabel::tsync), 1.F);
269 input_data_buffer_.globals.emplace_back(get_global_label_id(module_num, GlobalLabel::effective_c),
270 -BarLength / SCALE_FACTOR / 2.F / init_effective_c / init_effective_c);
271
272 write_to_buffer();
273 }
274
275 void MillepedeEngine::add_spacial_local_constraint(int plane_id, const std::vector<MilleCalData>& plane_signals)
276 {
277 buffer_clear();
278 const auto pos_z = PlaneID2ZPos<float>(plane_id);
279 const auto is_horizontal = IsPlaneIDHorizontal(plane_id);
280 // const auto pos_bar_vert_disp = GetBarVerticalDisplacement(module_num);
281 const auto pos_bar_vert_disp = std::accumulate(plane_signals.begin(),
282 plane_signals.end(),
283 0.,
284 [](double sum, const auto& signal) {
285 return sum + GetBarVerticalDisplacement(signal.module_num);
286 }) /
287 static_cast<double>(plane_signals.size());
288 const auto local_derivs = is_horizontal ? std::array{ 0.F, pos_z / SCALE_FACTOR, 0.F, 1.F }
289 : std::array{ pos_z / SCALE_FACTOR, 0.F, 1.F, 0.F };
290 // const auto local_derivs = is_horizontal ? std::array{ 0.F, pos_z / SCALE_FACTOR, 0.F, 0.F, 1.F, 0.F }
291 // : std::array{ pos_z / SCALE_FACTOR, 0.F, 0.F, 1.F, 0.F, 0.F };
292
293 input_data_buffer_.measurement = static_cast<float>(pos_bar_vert_disp / SCALE_FACTOR);
294 input_data_buffer_.sigma = static_cast<float>(BarSize_XY / SQRT_12 / SCALE_FACTOR * error_scale_factor_);
295
296 // if (not is_horizontal)
297 // {
298 // fmt::println("c_value_1.append({})\na_value_1.append({})\nb_value_1.append({})",
299 // pos_bar_vert_disp / SCALE_FACTOR,
300 // pos_z / SCALE_FACTOR,
301 // 1.);
302 // }
303 std::copy(local_derivs.begin(), local_derivs.end(), std::back_inserter(input_data_buffer_.locals));
304 write_to_buffer();
305 }
306
307 void MillepedeEngine::add_signal_t_diff(const MilleCalData& signal)
308 {
309 buffer_clear();
310 const auto module_num = static_cast<int>(signal.module_num);
311 const auto plane_id = ModuleID2PlaneID(static_cast<int>(module_num) - 1);
312 const auto is_horizontal = IsPlaneIDHorizontal(plane_id);
313 const auto& module_par = cal_to_hit_par_->GetModuleParAt(module_num);
314 auto init_effective_c = module_par.effective_speed.value;
315 auto init_t_offset = module_par.t_diff.value;
316 const auto pos_z = static_cast<float>(PlaneID2ZPos(plane_id));
317
318 const auto& left_signal = signal.left;
319 const auto& right_signal = signal.right;
320 const auto t_diff = (right_signal.leading_time - right_signal.trigger_time) -
321 (left_signal.leading_time - left_signal.trigger_time);
322
323 const auto t_error = t_diff.error == 0 ? DEFAULT_T_ERROR : t_diff.error;
324 input_data_buffer_.measurement = static_cast<float>((init_effective_c * init_t_offset / 2. / SCALE_FACTOR) -
325 (init_effective_c * t_diff.value / SCALE_FACTOR / 2.));
326 input_data_buffer_.sigma =
327 static_cast<float>(t_error / SCALE_FACTOR / 2. * std::abs(init_effective_c) * error_scale_factor_);
328 const auto local_derivs = is_horizontal ? std::array{ pos_z / SCALE_FACTOR, 0.F, 1.F, 0.F }
329 : std::array{ 0.F, pos_z / SCALE_FACTOR, 0.F, 1.F };
330 // const auto local_derivs = is_horizontal ? std::array{ pos_z / SCALE_FACTOR, 0.F, 0.F, 1.F, 0.F, 0.F }
331 // : std::array{ 0.F, pos_z / SCALE_FACTOR, 0.F, 0.F, 1.F, 0.F };
332 std::copy(local_derivs.begin(), local_derivs.end(), std::back_inserter(input_data_buffer_.locals));
333 // fmt::println("Adding global: {}", get_global_label_id(module_num, GlobalLabel::offset_effective_c));
334 input_data_buffer_.globals.emplace_back(get_global_label_id(module_num, GlobalLabel::offset_effective_c),
335 -0.5F);
336 input_data_buffer_.globals.emplace_back(get_global_label_id(module_num, GlobalLabel::effective_c),
337 static_cast<float>(t_diff.value / SCALE_FACTOR / 2.));
338
339 // if (is_horizontal)
340 // {
341 // const auto c_val = (0.5 * (module_par.t_diff * module_par.effective_speed).value / SCALE_FACTOR) -
342 // (module_par.effective_speed.value * t_diff.value / SCALE_FACTOR / 2.);
343 // fmt::println(
344 // "c_value_2.append({})\na_value_2.append({})\nb_value_2.append({})", c_val, pos_z / SCALE_FACTOR, 1.);
345 // }
346 write_to_buffer();
347 R3BLOG(
348 debug,
349 fmt::format(
350 "Writting Mille data to binary file with meas = {} and z = {}", input_data_buffer_.measurement, pos_z));
351 }
352
353 auto MillepedeEngine::select_t_diff_signal(const std::vector<MilleCalData>& plane_data)
354 {
355 if (plane_data.empty())
356 {
357 return plane_data.end();
358 }
359 auto calculate_residual = [this](const MilleCalData& signal) -> double
360 {
361 const auto t_diff = (signal.right.leading_time - signal.right.trigger_time) -
362 (signal.left.leading_time - signal.left.trigger_time);
363 const auto& module_par = cal_to_hit_par_->GetModuleParAt(signal.module_num);
364 const auto position = (-t_diff + module_par.t_diff) / 2 * module_par.effective_speed;
365 const auto res =
366 data_preprocessor_->calculate_residual(position.value, static_cast<int>(signal.module_num));
367 return res;
368 };
369 auto iter = std::min_element(plane_data.begin(),
370 plane_data.end(),
371 [calculate_residual](const auto& first, const auto& second)
372 { return calculate_residual(first) < calculate_residual(second); });
373 if (iter != plane_data.end())
374 {
375 auto residual = calculate_residual(*iter);
376 hist_t_offset_residual_->Fill(residual);
377 if (residual > t_diff_residual_cut_)
378 {
379 return plane_data.end();
380 }
381 // fmt::println("selected signal residual: {}", residual);
382 }
383 return iter;
384 }
385
386 void MillepedeEngine::AddSignals(const std::vector<BarCalData>& signals)
387 {
388
389 // fmt::println("==================new event===============\n");
390 if (not data_preprocessor_->filter(signals))
391 {
392 return;
393 }
394 const auto& processed_data = data_preprocessor_->get_data();
395 for (const auto& [plane_id, plane_signals] :
396 processed_data |
397 rng::views::filter([](const auto& planeid_signals) { return not planeid_signals.second.empty(); }))
398 {
399 // fmt::println("\n--------------------\n");
400 auto iter = select_t_diff_signal(plane_signals);
401 if (iter == plane_signals.end())
402 {
403 continue;
404 }
405 // fmt::println("selected signal: {}", *iter);
406 // for (const auto& signal : plane_signals)
407 // {
408 // // add_signal_t_sum(signal);
409 add_signal_t_diff(*iter);
410 add_spacial_local_constraint(plane_id, plane_signals);
411 // }
412 }
413 }
414
416 {
417 binary_data_writer_.close();
418 R3BLOG(info, "Launching pede algorithm..");
419 pede_launcher_.launch();
420 pede_launcher_.end();
421
422 par_result_.read();
423 fill_module_parameters(par_result_, hit_par);
424 fill_data_to_figure(hit_par);
425 }
426
427 void MillepedeEngine::fill_data_to_figure(Cal2HitPar& hit_par)
428 {
429 const auto& pars = hit_par.GetListOfModulePar();
430 for (const auto& [module_num, par] : pars)
431 {
432 graph_time_offset_->SetPoint(static_cast<int>(module_num), module_num, par.t_diff.value);
433 graph_time_offset_->SetPointError(static_cast<int>(module_num), 0., par.t_diff.error);
434 graph_time_sync_->SetPoint(static_cast<int>(module_num), module_num, par.t_sync.value);
435 graph_time_sync_->SetPointError(static_cast<int>(module_num), 0., par.t_sync.error);
436 graph_effective_c_->SetPoint(static_cast<int>(module_num), module_num, par.effective_speed.value);
437 graph_effective_c_->SetPointError(static_cast<int>(module_num), 0., par.effective_speed.error);
438 }
439 }
440
441 void MillepedeEngine::EndOfEvent(unsigned int /*event_num*/)
442 {
443 // TODO: could be an empty event
444 binary_data_writer_.end();
445 data_preprocessor_->reset();
446 }
447
449
451 {
452 const auto module_size = GetModuleSize();
453
454 graph_time_offset_ = histograms.add_graph("time_offset", std::make_unique<TGraphErrors>(module_size));
455 graph_time_offset_->SetTitle("Time offset vs BarNum");
456
457 graph_time_sync_ = histograms.add_graph("time_sync", std::make_unique<TGraphErrors>(module_size));
458 graph_time_sync_->SetTitle("Time sync vs BarNum");
459
460 graph_effective_c_ = histograms.add_graph("effective_c", std::make_unique<TGraphErrors>(module_size));
461 graph_effective_c_->SetTitle("Effective c vs BarNum");
462
463 static constexpr auto RESIDUAL_BIN_NUM = 500;
464 hist_t_offset_residual_ = histograms.add_hist<TH1D>(
465 "t_diff_residual", "Residual values of the positios calculated from t_dff", RESIDUAL_BIN_NUM, 0., 1000.);
466 }
467
468 void MillepedeEngine::buffer_clear()
469 {
470 input_data_buffer_.locals.clear();
471 input_data_buffer_.globals.clear();
472 input_data_buffer_.measurement = 0.F;
473 input_data_buffer_.sigma = 0.F;
474 }
475
476 void MillepedeEngine::write_to_buffer() { binary_data_writer_.mille(input_data_buffer_); }
477
479 {
480 average_t_sum_.reset();
481 buffer_clear();
482 }
483
484 void MillepedeEngine::init_parameter()
485 {
486 if (cal_to_hit_par_ == nullptr)
487 {
488 throw R3B::runtime_error("Pointer to cal_to_hit_par is nullptr!");
489 }
490 }
491
492 void MillepedeEngine::init_steer_writer()
493 {
494 auto steer_writer = SteerWriter{};
495 steer_writer.set_filepath(pede_steer_filename_);
496 steer_writer.set_parameter_file(parameter_filename_);
497 steer_writer.set_data_filepath(input_data_filename_);
498 static constexpr auto NUMBER_OF_ITERARTION = 3.F;
499 static constexpr auto CONVERGENCE_RECOGNITION = 0.001F;
500 steer_writer.add_method(SteerWriter::Method::inversion,
501 std::make_pair(NUMBER_OF_ITERARTION, CONVERGENCE_RECOGNITION));
502 steer_writer.add_other_options(std::vector<std::string>{ "hugecut", "50000" });
503 steer_writer.add_other_options(std::vector<std::string>{ "outlierdownweighting", "4" });
504
505 // const auto module_size = GetModuleSize();
506 // for (int module_num{ 1 }; module_num <= module_size; ++module_num)
507 // {
508 // const auto& module_par = cal_to_hit_par_->GetModuleParAt(module_num);
509 // steer_writer.add_parameter_default(
510 // get_global_label_id(module_num, GlobalLabel::effective_c),
511 // // std::make_pair(module_par.effective_speed.value, module_par.effective_speed.error));
512 // std::make_pair(DEFAULT_EFFECTIVE_C, module_par.effective_speed.error));
513
514 // const auto offset_effective_c = module_par.t_diff * module_par.effective_speed;
515 // steer_writer.add_parameter_default(
516 // get_global_label_id(module_num, GlobalLabel::offset_effective_c),
517 // std::make_pair(offset_effective_c.value / SCALE_FACTOR, offset_effective_c.error / SCALE_FACTOR));
518 // }
519 // steer_writer.add_parameter_default(get_global_label_id(REFERENCE_BAR_NUM, GlobalLabel::tsync),
520 // std::make_pair(0.F, -1.F));
521 steer_writer.write();
522 }
523} // namespace R3B::Neuland::Calibration
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
constexpr auto SCALE_FACTOR
constexpr auto DEFAULT_T_ERROR
constexpr auto DEFAULT_RES_FILENAME
constexpr auto MILLE_BUFFER_SIZE
auto add_hist(std::unique_ptr< TH1 > hist) -> TH1 *
auto add_graph(std::string_view graph_name, std::unique_ptr< GraphType > graph) -> GraphType *
void mille(const MilleDataPoint &data_point)
Definition Mille.cxx:42
auto GetListOfModuleParRef() -> auto &
auto GetModuleParAt(unsigned int module_num) const -> const ::R3B::Neuland::HitModulePar &
auto GetListOfModulePar() const -> const std::unordered_map< unsigned int, ::R3B::Neuland::HitModulePar > &
void Calibrate(Cal2HitPar &hit_par) override
void EndOfEvent(unsigned int event_num=0) override
auto SignalFilter(const std::vector< BarCalData > &signals) -> bool override
void AddSignals(const std::vector< BarCalData > &signals) override
void HistInit(DataMonitor &histograms) override
void set_filepath(std::string_view filepath)
Definition SteerWriter.h:43
STL class.
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto SQRT_12
constexpr auto BarLength
constexpr auto BarSize_XY
constexpr auto ModuleNum2ZPos(int module_num) -> T
constexpr auto IsPlaneIDHorizontal(int plane_id) -> bool
constexpr auto PlaneID2ZPos(int plane_id) -> T
std::vector< std::pair< int, float > > globals
Definition MilleEntry.h:24
std::vector< float > locals
Definition MilleEntry.h:23