28#include <TGraphErrors.h>
36#include <fairlogger/Logger.h>
39#include <fmt/format.h>
42#include <magic_enum/magic_enum.hpp>
46#include <range/v3/algorithm/all_of.hpp>
47#include <range/v3/algorithm/copy.hpp>
48#include <range/v3/algorithm/max.hpp>
49#include <range/v3/algorithm/min_element.hpp>
50#include <range/v3/iterator/operations.hpp>
51#include <range/v3/numeric/accumulate.hpp>
52#include <range/v3/view/all.hpp>
53#include <range/v3/view/drop.hpp>
54#include <range/v3/view/filter.hpp>
55#include <range/v3/view/iota.hpp>
56#include <range/v3/view/join.hpp>
57#include <range/v3/view/map.hpp>
58#include <range/v3/view/repeat.hpp>
59#include <range/v3/view/sliding.hpp>
60#include <range/v3/view/take.hpp>
61#include <range/v3/view/transform.hpp>
70namespace rng = ranges;
81 enum class FilterEvent : uint8_t
89 for (
auto& [module_num, module_par] : module_pars)
91 if (module_par.effective_speed.value != 0)
93 module_par.t_diff = module_par.t_diff / module_par.effective_speed;
101 for (
auto& [module_num, module_par] : module_pars)
103 module_par.t_diff = module_par.t_diff * module_par.effective_speed;
107 template <
typename T,
typename U>
108 void vector_zip_action(
const T& data, U&& unitary_action)
110 namespace sr = ranges;
111 namespace sv = ranges::views;
112 const auto max_size = sr::max(data | sv::transform([](
const auto& vec) ->
auto {
return vec.size(); }));
113 static constexpr auto nth_element = [](
auto& vec,
const int n) ->
auto
114 {
return sv::repeat(vec) | sv::join | sv::drop(n) | sv::take(1); };
116 for (
const auto index : sv::iota(std::size_t{ 0 }, max_size))
118 auto zip_view = data | sv::filter([](
const auto& vec) ->
auto {
return not vec.empty(); }) |
119 sv::transform([index](
auto&& vec) ->
auto {
return nth_element(vec, index); }) | sv::join;
120 std::forward<U>(unitary_action)(zip_view);
124 namespace sv = ranges::views;
146 if (
const auto* r3b_dir = std::getenv(
"R3BROOTPATH"); r3b_dir !=
nullptr)
155 "Environment variable R3BROOTPATH is not defined! Did you forget to source the \"config.sh\" file?");
158 std::make_unique<Mille>((fs::path{
working_dir_ } /
config_.mille_data_filename).string());
169 const auto filename = FairRun::Instance()->GetSink()->GetFileName();
170 const auto output_dir = fs::path{ filename.View() }.parent_path();
171 const auto time_now = std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now());
172 const auto output_folder_name =
173 config_.outdir_has_timestamp ? fmt::format(
"{:%Y-%m-%d_%H-%M-%S}", time_now) :
"output";
176 LOGP(debug,
"Working dir has set to be: {}",
working_dir_);
183 auto res = std::pair<int, GlobalLabel>{};
184 res.first = ((par_num - 1) % num_of_module) + 1;
192 const auto factor = (par_num - 1) / num_of_module;
203 fmt::format(
"An error occurred with unrecognized global par id: {}", par_num));
209 fmt::format(
"cal mode {} is not implemented!", magic_enum::enum_name(
config_.cal_mode)));
230 return module_num + num_of_module;
234 throw R3B::logic_error(fmt::format(
"cal mode {} is not implemented!", magic_enum::enum_name(
config_.cal_mode)));
243 change_time_offset(cal_to_hit_par);
246 const auto& pars = result.
get_pars();
247 for (
const auto& [par_id, par] : pars)
252 auto& par_ref = module_pars.emplace(module_num,
HitModulePar{}).first->second;
258 par_ref.t_sync.error = 0.;
268 switch (global_label)
277 par_ref.effective_speed.value += par.value;
278 par_ref.effective_speed.error = par.error;
281 throw std::runtime_error(
"An error occurred with unrecognized global tag");
287 fmt::format(
"cal mode {} is not implemented!", magic_enum::enum_name(
config_.cal_mode)));
293 calculate_time_offset(cal_to_hit_par);
300 auto filtered_signals =
301 rng::filter_view(signals | rng::views::all,
302 [](
const auto& bar_signal) ->
auto
303 {
return bar_signal.left.size() == 1 and bar_signal.right.size() == 1; });
304 if (filtered_signals.empty())
311 auto t_sum_view = filtered_signals | rng::views::transform(
312 [](
const auto& bar_signal) ->
auto
314 const auto& left_signal = bar_signal.left.front();
315 const auto& right_signal = bar_signal.right.front();
316 return (left_signal.leading_time - left_signal.trigger_time +
317 right_signal.leading_time - right_signal.trigger_time)
320 auto sum = rng::accumulate(t_sum_view, 0.F);
321 average_t_sum_ = sum /
static_cast<float>(rng::distance(t_sum_view.begin(), t_sum_view.end()));
322 LOGP(info,
"Average t_sum is calculated to be {}",
average_t_sum_.value());
329 const auto n_plane =
GetTask()->GetBasePar()->get_num_of_planes();
334 for (
const auto& bar_data : signals)
336 if (bar_data.left.size() != bar_data.right.size())
340 if (bar_data.left.size() != 1)
344 const auto module_num = bar_data.module_num;
348 const auto n_hit_plane = std::ranges::count_if(
plane_counter_, [](
auto val) ->
bool {
return val != 0; });
350 if (n_hit_plane <
config_.min_plane_num)
367 const auto x_z_slope = fit_coeff.x_z.slope;
368 const auto y_z_slope = fit_coeff.y_z.slope;
369 const auto a_z = std::sqrt(1 + (x_z_slope * x_z_slope) + (y_z_slope * y_z_slope)) /
CLight;
370 const auto sign_factor = (y_z_slope > 0.) ? 1. : -1.;
372 const auto module_num =
static_cast<int>(signal.module_num);
375 const auto init_effective_c =
cal_to_hit_par_->GetModuleParAt(module_num).effective_speed.value;
380 const auto& left_signal = signal.left;
381 const auto& right_signal = signal.right;
382 const auto t_sum = (left_signal.leading_time - left_signal.trigger_time) +
383 (right_signal.leading_time - right_signal.trigger_time) -
average_t_sum_.value_or(0.F);
385 auto meas =
static_cast<float>((t_sum.value / 2.F) + (sign_factor * pos_z * a_z) -
386 (
BarLength / init_effective_c / 2.F) - init_t_sync) /
394 const auto local_derivs_t = std::array{ 1.F };
395#ifdef HAS_CPP_STANDARD_17
396 std::copy(local_derivs_t.begin(), local_derivs_t.end(), std::back_inserter(
input_data_buffer_.locals));
412 auto n_not_outlier = 0;
413 auto pos_bar_vert_disp = std::accumulate(plane_signals.begin(),
416 [
this, &n_not_outlier](
double sum,
const auto& signal) ->
double
418 if (data_preprocessor_->check_is_outlier(signal.module_num))
425 if (n_not_outlier == 0)
427 LOGP(debug,
"no valid constraint found in event id: {}", GetTask()->GetEventHeader()->GetEventno());
430 pos_bar_vert_disp /= n_not_outlier;
431 const auto local_derivs = std::array{ pos_z /
SCALE_FACTOR, 1.F };
433 input_data_buffer_.measurement =
static_cast<float>(pos_bar_vert_disp /
SCALE_FACTOR);
436#ifdef HAS_CPP_STANDARD_17
437 std::copy(local_derivs.begin(), local_derivs.end(), std::back_inserter(input_data_buffer_.locals));
439 ranges::copy(local_derivs, std::back_inserter(input_data_buffer_.locals));
447 const auto module_num =
static_cast<int>(signal.
module_num);
451 const auto init_effective_c = module_par.effective_speed.value;
452 const auto init_t_offset = module_par.t_diff.value;
453 const auto pos_z =
static_cast<float>(
PlaneID2ZPos(plane_id));
455 const auto& left_signal = signal.
left;
456 const auto& right_signal = signal.
right;
457 const auto t_diff = (right_signal.leading_time - right_signal.trigger_time) -
458 (left_signal.leading_time - left_signal.trigger_time);
460 const auto t_error = t_diff.error == 0 ?
DEFAULT_T_ERROR : t_diff.error;
464 static_cast<float>(t_error /
SCALE_FACTOR / 2. * std::abs(init_effective_c) *
config_.scale_factor);
465 const auto local_derivs = std::array{ pos_z /
SCALE_FACTOR, 1.F };
474 "Writing Mille data to binary file with meas = {} and z = {}",
482 if (iter != plane_data.end())
484 auto residual = iter->residual;
486 if (residual >
config_.t_diff_residual_cut)
488 return plane_data.end();
500 const auto is_xz_flat = std::abs(fit_coeff.
x_z.
slope) < std::abs(config_.max_abs_a_xz);
501 const auto is_yz_flat = std::abs(fit_coeff.
y_z.
slope) < std::abs(config_.max_abs_a_yz);
502 auto add_to_constraints = [
this, &processed_data](
bool is_x_z) ->
void
504 for (
const auto& [plane_id, plane_signals] :
505 processed_data | rng::views::filter(
506 [is_x_z](
const auto& planeid_signals) ->
auto
508 return (not planeid_signals.second.empty()) and
512 add_spacial_local_constraint(plane_id, plane_signals);
515 for (
const auto& [plane_id, plane_signals] :
516 processed_data | rng::views::filter([](
const auto& planeid_signals) ->
auto
517 {
return not planeid_signals.second.empty(); }))
520 if (not(is_horizontal ? is_xz_flat : is_yz_flat))
524 for (
const auto& signal : plane_signals)
526 add_signal_t_diff(signal);
527 add_to_constraints(is_horizontal);
528 binary_data_writer_->end();
531 if (config_.enable_data_write)
533 for (
const auto& bar_signal : processed_data | sv::values | sv::join)
535 output_mille_data_.get().push_back(bar_signal);
544 for (
const auto& [plane_id, plane_signals] :
545 processed_data | rng::views::filter([](
const auto& planeid_signals) ->
auto
546 {
return not planeid_signals.second.empty(); }))
548 auto iter = select_t_sync_signal(plane_signals);
549 if (iter == plane_signals.end())
553 auto mille_data = *iter;
554 mille_data.tsync_meas = add_signal_t_sum(mille_data, fit_coeff);
555 if (config_.enable_data_write)
557 output_tsync_mille_data_.get().push_back(mille_data);
561 binary_data_writer_->end();
569 task->ConditionFillToHist(
"preprocess_fail");
572 task->ConditionFillToHist(
"preprocess_success");
580 const auto is_xz_flat = std::abs(fit_coeff.x_z.slope) < std::abs(
config_.max_abs_a_xz);
581 const auto is_yz_flat = std::abs(fit_coeff.y_z.slope) < std::abs(
config_.max_abs_a_yz);
583 if (not(is_xz_flat or is_yz_flat))
598 fmt::format(
"Unrecognized calibration mode: {}", magic_enum::enum_name(
config_.cal_mode)));
607 LOGP(info,
"Launching pede algorithm..");
619 for (
const auto& [module_num, par] : pars)
621 graph_time_offset_->SetPoint(
static_cast<int>(module_num), module_num, par.t_diff.value);
622 graph_time_offset_->SetPointError(
static_cast<int>(module_num), 0., par.t_diff.error);
623 graph_time_sync_->SetPoint(
static_cast<int>(module_num), module_num, par.t_sync.value);
624 graph_time_sync_->SetPointError(
static_cast<int>(module_num), 0., par.t_sync.error);
625 graph_effective_c_->SetPoint(
static_cast<int>(module_num), module_num, par.effective_speed.value);
626 graph_effective_c_->SetPointError(
static_cast<int>(module_num), 0., par.effective_speed.error);
653 static constexpr auto RESIDUAL_BIN_NUM = 500;
654 static constexpr auto PAR_BIN_NUM = 400;
655 static const auto SLOPE_MAX = 10.;
656 static const auto OFFSET_MAX = 200.;
658 auto set_x_title = [](
auto* hist, std::string_view title) ->
void { hist->GetXaxis()->SetTitle(title.data()); };
659 auto set_y_title = [](
auto* hist, std::string_view title) ->
void { hist->GetYaxis()->SetTitle(title.data()); };
662 "t_diff_residual",
"Residual values of the positions calculated from t_dff", RESIDUAL_BIN_NUM, 0., 1000.);
665 "p_value_xz",
"p values from the fitting of the muon track in xz plane", RESIDUAL_BIN_NUM, 0., 1.);
667 "p_value_yz",
"p values from the fitting of the muon track in yz plane", RESIDUAL_BIN_NUM, 0., 1.);
668 hist_a_xz_ = histograms.
add_hist<TH1D>(
"a_xz",
"slope of the xz plane", PAR_BIN_NUM, 0., SLOPE_MAX);
670 set_y_title(
hist_a_xz_, fmt::format(
"counts per {}", SLOPE_MAX / PAR_BIN_NUM));
672 hist_b_xz_ = histograms.
add_hist<TH1D>(
"b_xz",
"offset of the xz plane", PAR_BIN_NUM, 0., OFFSET_MAX);
674 set_y_title(
hist_b_xz_, fmt::format(
"counts per {}", OFFSET_MAX / PAR_BIN_NUM));
676 hist_a_yz_ = histograms.
add_hist<TH1D>(
"a_yz",
"slope of the yz plane", PAR_BIN_NUM, 0., SLOPE_MAX);
678 set_y_title(
hist_a_yz_, fmt::format(
"counts per {}", SLOPE_MAX / PAR_BIN_NUM));
680 hist_b_yz_ = histograms.
add_hist<TH1D>(
"b_yz",
"offset of the yz plane", PAR_BIN_NUM, 0., OFFSET_MAX);
682 set_y_title(
hist_b_yz_, fmt::format(
"counts per {}", OFFSET_MAX / PAR_BIN_NUM));
688 histograms.
add_hist<TH1D>(
"plane_hit_num",
"Number of hit planes", n_plane + 1, -0.5, 0.5 + n_plane);
692 static constexpr auto residual_bin_num = 1000;
693 static constexpr auto max_residual = 300.;
694 static constexpr auto max_diff = 50;
731 "The reference bar (bar_num {}) from the input tsync parameter has the wrong value ({}, should be "
732 "{}). Offsetting the input parameters ...",
736 for (
auto& [module_num, module_par] : module_pars)
738 module_par.t_sync.value -= reference_bar_value;
760 steer_writer.set_data_filepath(
config_.mille_data_filename);
761 static constexpr auto NUMBER_OF_ITERATION = 3.F;
762 static constexpr auto CONVERGENCE_RECOGNITION = 0.001F;
764 std::make_pair(NUMBER_OF_ITERATION, CONVERGENCE_RECOGNITION));
765 steer_writer.add_other_options(std::vector<std::string>{
"hugecut",
"50000" });
775 steer_writer.add_other_options(std::vector<std::string>{
"outlierdownweighting",
"2" });
778 if (
config_.num_of_threads > 0)
780 steer_writer.add_other_options(std::vector<std::string>{
781 "threads", fmt::format(
"{}",
config_.num_of_threads), fmt::format(
"{}",
config_.num_of_threads) });
783 steer_writer.write();
constexpr auto SCALE_FACTOR
constexpr auto DEFAULT_T_ERROR
constexpr auto DEFAULT_RES_FILENAME
constexpr auto DEFAULT_RES_JSON_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 *
auto get_pars() const -> const auto &
auto GetListOfModulePar() const -> const std::unordered_map< int, ::R3B::Neuland::HitModulePar > &
auto GetListOfModuleParRef() -> auto &
auto GetTask() -> Cal2HitParTask *
auto GetModuleSize() const -> auto
TGraphErrors * graph_time_offset_
auto to_module_num_label(int par_num) -> std::pair< int, GlobalLabel >
R3B::OutputVectorConnector< MilleCalData > output_tsync_mille_data_
R3B::OutputConnector< NeulandTrackInfo > output_mille_track_info_
MilleDataPoint input_data_buffer_
void add_fit_result_hist(const MilleDataProcessor::FitResult &fit_result)
TH1L * barplot_filter_counts_
auto select_t_sync_signal(const std::vector< MilleCalData > &plane_data)
void Calibrate(Cal2HitPar &hit_par) override
void add_spacial_local_constraint(int plane_id, const std::vector< MilleCalData > &plane_signals)
auto set_minimum_values(const std::vector< R3B::Neuland::BarCalData > &signals) -> bool
void EndOfEvent(unsigned int event_num=0) override
static constexpr std::string_view DEFAULT_SUB_DIR
void fill_module_parameters(const Millepede::ResultReader &result, Neuland::Cal2HitPar &cal_to_hit_par)
std::unique_ptr< Mille > binary_data_writer_
void EndOfTask() override
void set_options(const MillepedeOptions &options)
std::unique_ptr< MilleDataProcessor > data_preprocessor_
TH1D * hist_plane_hit_num_
void fill_data_to_figure(Cal2HitPar &hit_par)
auto add_signal_t_sum(const MilleCalData &signal, const TrackFitResult &fit_coeff) -> float
TH1D * hist_t_offset_residual_
Cal2HitPar * cal_to_hit_par_
void add_signal_t_diff(const MilleCalData &signal)
std::vector< int > plane_counter_
auto SignalFilter(const std::vector< BarCalData > &signals) -> bool override
void add_signals(const DataBufferType &processed_data, const TrackFitResult &fit_coeff)
void AddSignals(const std::vector< BarCalData > &signals) override
std::string input_parameter_filename_
TGraphErrors * graph_time_sync_
auto get_global_label_id(int module_num, GlobalLabel label) -> int
void EventReset() override
TGraphErrors * graph_effective_c_
void HistInit(DataMonitor &histograms) override
std::string pede_steer_filename_
R3B::OutputVectorConnector< MilleCalData > output_mille_data_
std::optional< float > average_t_sum_
Millepede::Launcher pede_launcher_
Millepede::ResultReader par_result_
static constexpr auto ModuleID2PlaneID(int moduleID) -> int
void set_working_dir(std::string_view dir)
constexpr auto DEFAULT_TSYNC_REFERENCE_BAR_VALUE
constexpr auto DEFAULT_TSYNC_REFERENCE_BAR_NUM
std::unordered_map< int, std::vector< MilleCalData > > DataBufferType
constexpr auto BarsPerPlane
constexpr auto ModuleID2PlaneID(int moduleID) -> int
constexpr auto GetBarVerticalDisplacement(int module_num) -> double
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
Data structure to store the cal level data for the data preprocessing.
int module_num
1 based bar num
float residual
residual value against the fitted line