R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BNeulandApp.h
Go to the documentation of this file.
1#pragma once
2
3#include "JsonParse/SpecialParsing.h" // IWYU pragma: keep
4#include <R3BException.h>
6#include <TStopwatch.h>
7#include <algorithm>
8#include <cstdint>
9#include <fairlogger/Logger.h>
10#include <fmt/base.h>
11#include <fmt/core.h>
12#include <fmt/format.h>
13#include <fstream>
14#include <functional>
15#include <glaze/core/context.hpp>
16#include <glaze/core/opts.hpp>
17#include <glaze/core/ostream_buffer.hpp>
18#include <glaze/core/reflect.hpp>
19#include <glaze/json/write.hpp> // IWYU pragma: keep
20#include <ios>
21#include <iterator>
22#include <memory>
23#include <string>
24#include <string_view>
25#include <utility>
26#include <vector>
27
28class FairRun;
29class R3BFileSource2;
30
31namespace CLI
32{
33 class App;
34}
35
36namespace R3B
37{
38 enum class WriteMode : uint8_t
39 {
44 };
45
46}
47
48namespace R3B::Neuland
49{
50 constexpr auto DEFAULT_EVENT_NUM = 100;
51 constexpr auto DEFAULT_RUN_ID = 999;
52 const auto DEFAULT_JSON_FILENAME = "config.json";
54 {
55 public:
56 struct Options
57 {
60 bool enable_mpi = false;
61 std::string log_level = "error";
62 std::string verbose_level = "user1";
63 struct Input
64 {
65 std::string working_dir;
66 std::vector<std::string> data;
67 std::vector<std::string> tree_data;
68 std::vector<std::string> par;
70 struct Output
71 {
72 std::string working_dir;
73 std::string data = "output.root";
74 std::string par = "output.par.root";
77 };
78
79 explicit CLIApplication(std::string_view name,
80 std::unique_ptr<FairRun> run,
81 std::reference_wrapper<Options> option);
84 auto operator=(const CLIApplication&) -> CLIApplication& = delete;
86 ~CLIApplication() override;
87
88 // common APIs:
89
90 template <typename CLIAPP, typename OptionType>
91 void setup_common_options(CLIAPP& program_options, OptionType& options);
92
93 template <typename OptionType>
94 void print_json_options(const OptionType& options);
95
96 template <typename OptionType>
97 void dump_json_options(const OptionType& options, const std::string& filename);
98
99 // setters:
100
101 void set_log_level(std::string_view log_level) { option_.get().log_level = log_level; }
102 void set_run_id(int run_id) { option_.get().run_id = run_id; }
103 void set_output_filename(std::string_view output_filename) { option_.get().output.data = output_filename; }
104 void add_inputpar_filename(std::string_view inputpar_filename)
105 {
106 option_.get().input.par.emplace_back(inputpar_filename);
107 }
108 void set_outputpar_filename(std::string_view outputpar_filename)
109 {
110 option_.get().output.par = outputpar_filename;
111 }
112 void set_event_num(int val) { option_.get().number_of_events = val; }
113 void set_input_filename(const std::vector<std::string>& input_filename)
114 {
115 std::ranges::copy(input_filename, std::back_inserter(option_.get().input.data));
116 }
117 void set_tree_input_filename(const std::vector<std::string>& input_filename)
118 {
119 std::ranges::copy(input_filename, std::back_inserter(option_.get().input.tree_data));
120 }
121
122 // Getters:
123
124 auto get_run() -> FairRun* { return run_.get(); }
125 auto has_mpi() -> bool { return option_.get().enable_mpi; }
126
127 protected:
128 template <typename OptionType>
129 void ParseApplicationOptionImp(const std::vector<std::string>& filename, OptionType& options);
130
131 private:
132 bool is_already_parsed_ = false; // guards for callbacks.
133 bool is_dump_ = false; // guards for callbacks.
136 int rank_num_ = 0;
137 std::string app_name_;
139 std::unique_ptr<FairRun> run_;
140 std::reference_wrapper<Options> option_;
141 TStopwatch timer_;
142 std::vector<std::pair<std::string, bool>> input_files_;
143
144 // private overriden virtual function:
145 void set_num_of_procs(int val) override { num_of_procs_ = val; }
146 void set_rank_num(int val) override { rank_num_ = val; }
148 void init() override;
149 void run() override;
150 void print_options() override { print_json_options(); }
151 [[nodiscard]] auto has_print_default_options() const -> bool override { return has_print_default_options_; }
152 [[nodiscard]] auto has_dump() const -> bool override { return is_dump_; }
153 void setup_options(CLI::App& program_options) override;
154 void post_parse() override;
155
156 // private virtual methods:
157 virtual void pre_init(FairRun* run) = 0;
158 virtual void ParseApplicationOption(const std::vector<std::string>& filename_or_option) = 0;
159 virtual void post_init(FairRun* run) {}
160 void add_input_filename(R3BFileSource2* filesource);
161 virtual void print_json_options() {}
162 virtual void dump_json_options(const std::string& filename) {}
163 virtual void run_action(FairRun* run, int num_of_events);
164 virtual void setup_application_options(CLI::App& program_options) {}
165
166 // private non-virtual methods:
167 void setup_common_options(CLI::App& program_options);
168 void add_inout_files();
169 void add_inout_pars();
170 void extract_input_files();
171 static void setup_logger();
172
173 enum class JSONConfigInputType : uint8_t
174 {
179 };
180 static auto check_json_input_type(std::string_view input) -> JSONConfigInputType;
181 static void transform_to_json_string(std::string_view input, std::string& buffer);
182 };
183
184 template <typename OptionType>
185 void CLIApplication::print_json_options(const OptionType& options)
186 {
187 fmt::println("{}", glz::write<glz::opts{ .prettify = true }>(options).value_or("error occurred"));
188 }
189
190 template <typename OptionType>
191 void CLIApplication::dump_json_options(const OptionType& options, const std::string& filename)
192 {
193
194 auto file = std::ofstream{ filename, std::ios::trunc };
195 auto buffer = glz::basic_ostream_buffer<std::ofstream>{ file };
196 auto error = glz::write<glz::opts{ .prettify = true }>(options, buffer);
197
198 if (error)
199 {
200 fmt::println("Error occurred:{}", glz::format_error(error));
201 }
202 else
203 {
204 fmt::println("Configuration of {} is saved into the file {:?}", app_name_, filename);
205 }
206 }
207
208 template <typename OptionType>
209 void CLIApplication::ParseApplicationOptionImp(const std::vector<std::string>& filenames_or_options,
210 OptionType& options)
211 {
212 auto buffer = std::string{};
213
214 for (const auto& filename_or_option : filenames_or_options)
215 {
216 buffer.clear();
217 auto error_code = glz::error_ctx{};
218 switch (check_json_input_type(filename_or_option))
219 {
221 {
222 buffer = filename_or_option;
223 LOGP(info, "Reading the configuration from the native JSON string {:?}.", buffer);
224 error_code = glz::read_json(options, buffer);
225 break;
226 }
228 {
229 transform_to_json_string(filename_or_option, buffer);
230 LOGP(info, "Reading the configuration from the string {:?}.", buffer);
231 error_code = glz::read_json(options, buffer);
232 break;
233 }
235 {
236 LOGP(info, "Reading the configuration from the JSON file {:?}.", filename_or_option);
237 error_code = glz::read_file_json(options, filename_or_option, buffer);
238 break;
239 }
241 throw R3B::logic_error(fmt::format("Cannot parse the string {:?}", filename_or_option));
242 }
243 if (error_code)
244 {
245 throw R3B::logic_error(fmt::format("Failed to parse to the JSON object from {:?}:\n{}",
246 filename_or_option,
247 glz::format_error(error_code, buffer)));
248 }
249 }
250 }
251} // namespace R3B::Neuland
CLIAbstract()=default
Default constructor.
void post_parse() override
Action done after the option parsing.
auto operator=(const CLIApplication &) -> CLIApplication &=delete
void set_rank_num(int val) override
void set_input_filename(const std::vector< std::string > &input_filename)
virtual void setup_application_options(CLI::App &program_options)
std::vector< std::pair< std::string, bool > > input_files_
static auto check_json_input_type(std::string_view input) -> JSONConfigInputType
CLIApplication(const CLIApplication &)=delete
virtual void post_init(FairRun *run)
static void transform_to_json_string(std::string_view input, std::string &buffer)
void set_outputpar_filename(std::string_view outputpar_filename)
void set_log_level(std::string_view log_level)
auto operator=(CLIApplication &&) -> CLIApplication &=delete
void run() override
Run the CLI program.
std::reference_wrapper< Options > option_
void ParseApplicationOptionImp(const std::vector< std::string > &filename, OptionType &options)
void add_input_filename(R3BFileSource2 *filesource)
CLIApplication(std::string_view name, std::unique_ptr< FairRun > run, std::reference_wrapper< Options > option)
auto has_dump() const -> bool override
Check whether the options should be dump to a JSON file.
auto has_print_default_options() const -> bool override
Check the flag whether the default options should be printed in JSON strings.
void set_output_filename(std::string_view output_filename)
void dump_json_options(const OptionType &options, const std::string &filename)
virtual void ParseApplicationOption(const std::vector< std::string > &filename_or_option)=0
void setup_options(CLI::App &program_options) override
Setup the CLI options given to the program.
virtual void pre_init(FairRun *run)=0
void add_inputpar_filename(std::string_view inputpar_filename)
virtual void run_action(FairRun *run, int num_of_events)
CLIApplication(CLIApplication &&)=delete
void init() override
Initialization of a CLI program.
auto get_run() -> FairRun *
void set_num_of_procs(int val) override
std::unique_ptr< FairRun > run_
void setup_common_options(CLIAPP &program_options, OptionType &options)
virtual void dump_json_options(const std::string &filename)
void set_tree_input_filename(const std::vector< std::string > &input_filename)
Simulation of NeuLAND Bar/Paddle.
constexpr auto DEFAULT_EVENT_NUM
const auto DEFAULT_JSON_FILENAME
constexpr auto DEFAULT_RUN_ID
struct R3B::Neuland::CLIApplication::Options::Input input
struct R3B::Neuland::CLIApplication::Options::Output output