R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandAnalysisApp.cxx
Go to the documentation of this file.
2#include <CLI/CLI.hpp>
3#include <FairRunAna.h>
8#include <R3BEventHeader.h>
9#include <R3BException.h>
10#include <R3BFileSource2.h>
11#include <R3BLogger.h>
15#include <R3BNeulandDigitizer.h>
16#include <R3BNeulandHitMon.h>
23#include <boost/algorithm/string.hpp>
24#include <fstream>
25
26namespace Digitizing = R3B::Digitizing;
35using json = nlohmann::ordered_json;
36
37namespace
38{
39 void resolve_branch_names(const std::string& input, std::vector<std::string>& output)
40 {
41 output.clear();
42 boost::split(output, input, boost::is_any_of(";"));
43 // trim the empty spaces
44 std::for_each(output.begin(), output.end(), [](auto& name) { boost::trim(name); });
45 // remove empty names
46 output.erase(std::remove(output.begin(), output.end(), ""), output.end());
47 }
48
49 template <typename Option>
50 void parse_branch_names(const Option& option,
51 std::vector<std::string>& read,
52 int read_num,
53 std::vector<std::string>& write,
54 int write_num)
55 {
56 resolve_branch_names(option.read, read);
57 if (read.size() != read_num)
58 {
59 throw R3B::logic_error(fmt::format(
60 "Task {:?} requires {} read branch(es) but only received {} branch(es)! Parsed string: {:?}",
61 option.name,
62 read_num,
63 read.size(),
64 option.read));
65 }
66 resolve_branch_names(option.write, write);
67 if (write.size() != write_num)
68 {
69 throw R3B::logic_error(fmt::format(
70 "Task {:?} requires {} write branch(es) but only received {} branch(es)! Parsed string: {:?}",
71 option.name,
72 read_num,
73 write.size(),
74 option.write));
75 }
76 }
77} // namespace
78
79namespace R3B::Neuland
80{
82
83 namespace
84 {
85 template <typename Depender, typename Dependee>
86 void requires_dependecy(const Depender& depender, const Dependee& dependee)
87 {
88 if (not dependee.enable)
89 {
90 throw R3B::logic_error(fmt::format(
91 "Cannot run the task {} because its dependee tasks {} is disabled!", depender.name, dependee.name));
92 }
93 }
94 } // namespace
95
96 auto AnalysisApplication::create_neuland_digi_engine_map(const Options::Tasks::Digi& option,
97 std::string_view hit_par_name)
98 {
99 auto pileup_strategy = option.pileup_strategy;
100 const auto& tamex_par = option.tamex_par;
101 R3B::Neuland::Cal2HitPar* cal_to_hit_par{ nullptr };
102 if (option.enable_hit_par)
103 {
104 R3BLOG(info, "cal_to_hit_par is used in digitization task!");
105 cal_to_hit_par = std::make_unique<R3B::Neuland::Cal2HitPar>(hit_par_name).release();
106 get_run()->GetRuntimeDb()->addContainer(cal_to_hit_par);
107 }
108 else
109 {
110 R3BLOG(info, "cal_to_hit_par is not used in digitization task!");
111 }
112 return std::map<std::pair<const std::string, const std::string>,
113 std::function<std::unique_ptr<Digitizing::DigitizingEngineInterface>()>>{
114 { { "neuland", "tamex" },
115 [&tamex_par, pileup_strategy, cal_to_hit_par]()
116 {
117 return Digitizing::CreateEngine(UsePaddle<NeulandPaddle>(cal_to_hit_par),
118 UseChannel<TamexChannel>(pileup_strategy, tamex_par, cal_to_hit_par));
119 } },
120 { { "neuland", "tacquila" },
121 [cal_to_hit_par]() {
122 return Digitizing::CreateEngine(UsePaddle<NeulandPaddle>(cal_to_hit_par),
123 UseChannel<TacquilaChannel>());
124 } },
125 { { "mock", "tamex" },
126 [&tamex_par, pileup_strategy, cal_to_hit_par]()
127 {
128 return Digitizing::CreateEngine(UsePaddle<MockPaddle>(),
129 UseChannel<TamexChannel>(pileup_strategy, tamex_par, cal_to_hit_par));
130 } },
131 { { "neuland", "mock" },
132 [cal_to_hit_par]() {
133 return Digitizing::CreateEngine(UsePaddle<NeulandPaddle>(cal_to_hit_par), UseChannel<MockChannel>());
134 } },
135 { { "mock", "mock" },
136 []() { return Digitizing::CreateEngine(UsePaddle<MockPaddle>(), UseChannel<MockChannel>()); } }
137 };
138 }
139
141 : Application{ "neuland_ana", std::make_unique<FairRunAna>(), std::ref(options_.general) }
142 {
143 options_.general.input.data.emplace_back("sim.output.root");
144 options_.general.input.par = "sim.par.root";
145
146 options_.general.output.data = "digi.output.root";
147 options_.general.output.par = "digi.par.root";
148 }
149
151 {
152 const auto analysis_option_group = std::string{ "Analysis options" };
153 program_options.add_option("--paddle", options_.tasks.digi.paddle, R"(Set the paddle name. e.g. "neuland")")
154 ->capture_default_str()
155 ->group(analysis_option_group);
156 program_options.add_option("--channel", options_.tasks.digi.channel, R"(Set the channel name. e.g. "tamex")")
157 ->capture_default_str()
158 ->group(analysis_option_group);
159 }
160
162 {
163
164 auto EvntHeader = std::make_unique<R3BEventHeader>();
165 auto read_branch_names = std::vector<std::string>{};
166 auto write_branch_names = std::vector<std::string>{};
167 run->SetEventHeader(EvntHeader.release());
168
169 auto task_option = options_.tasks;
170 run->SetEventHeader(std::make_unique<R3BEventHeader>().release());
171
172 if (const auto& option = task_option.digi; option.enable)
173 {
174 parse_branch_names(option, read_branch_names, 2, write_branch_names, 2);
175 auto engine_map = create_neuland_digi_engine_map(option, read_branch_names.at(1));
176 auto engine_gen = engine_map.at({ option.paddle, option.channel });
177 auto task = std::make_unique<R3BNeulandDigitizer>(
178 engine_gen(), read_branch_names.at(0), write_branch_names.at(0), write_branch_names.at(1));
179 task->EnableCalDataOutput(option.enable_sim_cal);
180 task->SetName(task_option.digi.name.c_str());
181 run->AddTask(task.release());
182 }
183
184 if (const auto& option = task_option.sim_cal_to_cal; option.enable)
185 {
186 parse_branch_names(option, read_branch_names, 1, write_branch_names, 1);
187 auto task = std::make_unique<R3B::Neuland::SimCal2Cal>(read_branch_names.at(0), write_branch_names.at(0));
188 task->SetName(option.name.c_str());
189 run->AddTask(task.release());
190 }
191
192 if (const auto& option = task_option.hit_monitor; option.enable)
193 {
194 parse_branch_names(option, read_branch_names, 1, write_branch_names, 0);
195 auto task = std::make_unique<R3BNeulandHitMon>(read_branch_names.at(0));
196 task->SetName(option.name.c_str());
197 run->AddTask(task.release());
198 }
199
200 if (const auto& option = task_option.prim_inter_finder; option.enable)
201 {
202 parse_branch_names(option, read_branch_names, 2, write_branch_names, 3);
203 auto task = std::make_unique<R3BNeulandPrimaryInteractionFinder>(read_branch_names.at(0),
204 read_branch_names.at(1),
205 write_branch_names.at(0),
206 write_branch_names.at(1),
207 write_branch_names.at(2));
208 task->SetName(option.name.c_str());
209 run->AddTask(task.release());
210 }
211
212 if (const auto& option = task_option.cluster_finder; option.enable)
213 {
214 parse_branch_names(option, read_branch_names, 1, write_branch_names, 1);
215 auto task = std::make_unique<R3BNeulandClusterFinder>(read_branch_names.at(0), write_branch_names.at(0));
216 task->SetName(option.name.c_str());
217 run->AddTask(task.release());
218 }
219
220 if (const auto& option = task_option.cluster_finder; option.enable)
221 {
222 parse_branch_names(option, read_branch_names, 2, write_branch_names, 2);
223 auto task = std::make_unique<R3BNeulandPrimaryClusterFinder>(
224 read_branch_names.at(0), read_branch_names.at(1), write_branch_names.at(0), write_branch_names.at(1));
225 task->SetName(option.name.c_str());
226 run->AddTask(task.release());
227 }
228
229 if (const auto& option = task_option.multi_calorimeter_train; option.enable)
230 {
231 parse_branch_names(option, read_branch_names, 3, write_branch_names, 0);
232 auto task = std::make_unique<R3BNeulandMultiplicityCalorimetricTrain>(
233 read_branch_names.at(0), read_branch_names.at(1), read_branch_names.at(2));
234 task->SetName(option.name.c_str());
235 task->SetUseHits(option.use_hit);
236 task->SetWeight(option.weight);
237 task->SetEdepOpt(option.edep_opt.init, option.edep_opt.step, option.edep_opt.lower, option.edep_opt.upper);
238 task->SetEdepOffOpt(option.edep_off_opt.init,
239 option.edep_off_opt.step,
240 option.edep_off_opt.lower,
241 option.edep_off_opt.upper);
242 task->SetNclusterOffOpt(option.n_cluster_opt.init,
243 option.n_cluster_opt.step,
244 option.n_cluster_opt.lower,
245 option.n_cluster_opt.upper);
246 task->SetNclusterOffOpt(option.n_cluster_off_opt.init,
247 option.n_cluster_off_opt.step,
248 option.n_cluster_off_opt.lower,
249 option.n_cluster_off_opt.upper);
250 run->AddTask(task.release());
251 }
252
253 if (const auto& option = task_option.multi_bayes_train; option.enable)
254 {
255 parse_branch_names(option, read_branch_names, 2, write_branch_names, 0);
256 auto task =
257 std::make_unique<R3BNeulandMultiplicityBayesTrain>(read_branch_names.at(0), read_branch_names.at(1));
258 task->SetName(option.name.c_str());
259 run->AddTask(task.release());
260 }
261
262 if (const auto& option = task_option.multi_bayes; option.enable)
263 {
264 parse_branch_names(option, read_branch_names, 1, write_branch_names, 1);
265 auto task =
266 std::make_unique<R3BNeulandMultiplicityBayes>(read_branch_names.at(0), write_branch_names.at(0));
267 task->SetName(option.name.c_str());
268 run->AddTask(task.release());
269 }
270
271 if (const auto& option = task_option.neutron_r_value; option.enable)
272 {
273 parse_branch_names(option, read_branch_names, 2, write_branch_names, 1);
274 auto task = std::make_unique<R3BNeulandNeutronsRValue>(
275 option.neutron_energy_mev, read_branch_names.at(0), read_branch_names.at(1), write_branch_names.at(0));
276 task->SetName(option.name.c_str());
277 run->AddTask(task.release());
278 }
279
280 if (const auto& option = task_option.cal_to_hit_par_task; option.enable)
281 {
282 parse_branch_names(option, read_branch_names, 2, write_branch_names, 1);
283 auto task = std::make_unique<R3B::Neuland::Cal2HitParTask>(
284 option.method, read_branch_names.at(0), read_branch_names.at(1), write_branch_names.at(0));
285 task->SetMinStat(option.min_stat);
286 run->AddTask(task.release());
287 }
288 }
289
290 void AnalysisApplication::set_parameters() {}
291
293 {
294 auto json_obj = json{ options_ };
295 if (json_obj.is_array())
296 {
297 fmt::print("{}\n", json_obj.front().dump(4));
298 }
299 else
300 {
301 fmt::print("{}\n", json_obj.dump(4));
302 }
303 }
304
305 void AnalysisApplication::dump_json_options(const std::string& filename)
306 {
307 auto file = std::ofstream{ filename, std::ios::trunc };
308 auto json_obj = json{ options_ };
309 if (json_obj.is_array())
310 {
311 file << json_obj.front().dump(4);
312 }
313 else
314 {
315 file << json_obj.dump(4);
316 }
317 R3BLOG(info, fmt::format("Configuration of neuland_ana is saved into the file {:?}", filename));
318 }
319
320} // namespace R3B::Neuland
#define R3BLOG(severity, x)
Definition R3BLogger.h:35
nlohmann::ordered_json json
Tamex::Channel TamexChannel
Digitizing::Neuland::MockPaddle MockPaddle
Digitizing::Neuland::NeulandPaddle NeulandPaddle
Digitizing::Neuland::MockChannel MockChannel
Digitizing::Neuland::TacQuila::Channel TacquilaChannel
void setup_application_options(CLI::App &program_options) override
void dump_json_options(const std::string &filename) override
Application(std::string_view name, std::unique_ptr< FairRun > run, std::reference_wrapper< Options > option)
auto get_run() -> FairRun *
auto CreateEngine(Args &&... args) -> std::unique_ptr< decltype(DigitizingEngine{ std::forward< Args >(args)... })>
Simulation of NeuLAND Bar/Paddle.
nlohmann::ordered_json json
AnalysisApplication::Options Options