8#include <FairParRootFileIo.h>
9#include <FairRootFileSink.h>
11#include <FairRuntimeDb.h>
12#include <boost/algorithm/string/classification.hpp>
13#include <boost/algorithm/string/split.hpp>
14#include <boost/algorithm/string/trim.hpp>
15#include <boost/range/adaptor/reversed.hpp>
18#include <fairlogger/Logger.h>
26#include <nlohmann/json.hpp>
27#include <nlohmann/json_fwd.hpp>
40 auto get_partition_from(
const std::vector<T>& elements,
int num_of_partitions,
int partition_num) -> span<const T>
42 const auto total_size = elements.size();
44 static_cast<int>(std::ceil(
static_cast<float>(total_size) /
static_cast<float>(num_of_partitions)));
45 if (step * partition_num >= total_size)
49 const auto span_size = step * (partition_num + 1) < total_size ? step : total_size - (step * partition_num);
50 return span<const T>{ &(elements.at(step * partition_num)), span_size };
53 enum class JSONConfigInputType : uint8_t
60 auto check_json_input_type(std::string_view input) -> JSONConfigInputType
62 auto is_json_string = [](std::string_view string) ->
bool {
return string.find(
'=') != std::string::npos; };
63 auto is_a_file = [](std::string_view string) ->
bool {
return std::filesystem::exists(
string); };
65 if (is_json_string(input))
67 return JSONConfigInputType::string;
71 return JSONConfigInputType::file;
73 return JSONConfigInputType::invalid;
76 auto transform_to_json_string(std::string_view input) -> std::string
78 auto raw_string = std::string{ input };
79 auto equal_pos = raw_string.find(
'=');
80 auto keys_string = raw_string.substr(0, equal_pos);
81 auto value_string = raw_string.substr(equal_pos + 1);
83 boost::algorithm::trim(keys_string);
84 boost::algorithm::trim(value_string);
86 auto keys = std::vector<std::string>{};
87 boost::split(keys, keys_string, boost::is_any_of(
"."));
89 for (
const auto& key : boost::adaptors::reverse(keys))
91 value_string = fmt::format(
"{{ {:?} : {}}}", key, value_string);
99 using json = nlohmann::ordered_json;
101 std::unique_ptr<FairRun>
run,
102 std::reference_wrapper<Options> option)
118 LOGP(info,
"Writting all parameters to files");
119 run_->GetRuntimeDb()->writeContainers();
120 if (
auto* runtime_db =
run_->GetRuntimeDb(); runtime_db !=
nullptr)
122 runtime_db->writeContainers();
124 if (
auto* sink =
run_->GetSink(); sink !=
nullptr)
131 fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
132 "\nNeuland Application finished with a failure!\n\n");
136 fmt::print(fmt::emphasis::bold | fg(fmt::color::green),
137 "\nNeuland Application finished successfully!\n\n");
139 fmt::println(
"Real time: {}s, cpu time: {}s",
timer_.RealTime(),
timer_.CpuTime());
145 auto spec1 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
146 fair::VerbositySpec::Info::file_line_function);
147 fair::Logger::DefineVerbosity(
"user1", spec1);
149 auto spec2 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
150 fair::VerbositySpec::Info::timestamp_s,
151 fair::VerbositySpec::Info::file_line_function);
152 fair::Logger::DefineVerbosity(
"user2", spec2);
154 fair::Logger::SetConsoleColor(
true);
159 fair::Logger::SetConsoleSeverity(
option_.get().log_level);
160 fair::Logger::SetVerbosity(
option_.get().verbose_level);
165 LOGP(info,
"Initializaing application ...");
172 LOGP(info,
"Application is initialized.");
183 auto dump_config_callback = [
this](
const std::string& filename)
189 auto use_config_callback = [
this](
const std::vector<std::string>& filename_or_option)
200 .add_option_function<std::vector<std::string>>(
201 "-c, --use-config", use_config_callback,
"Set the json config file")
203 ->run_callback_for_default()
205 ->trigger_on_parse();
208 .add_option_function<std::string>(
"--dump-config", dump_config_callback,
"Dump the config into a json file")
210 ->run_callback_for_default()
212 program_options.add_option(
"-s, --severity", options.log_level,
"Set the severity level");
213 program_options.add_option(
"-v, --verbose", options.verbose_level,
"Set the verbose level");
214 program_options.add_option(
"-n, --event-num", options.event_num,
"Set the event number")->capture_default_str();
215 program_options.add_option(
"--run-id", options.run_id,
"Set the run id")->capture_default_str();
217 program_options.add_option(
"-i, --input-file", options.input.data,
"Set the input filenames (regex)")
218 ->capture_default_str()
219 ->group(
"Input options");
221 .add_option(
"--input-tree-file",
222 options.input.tree_data,
223 "Set the input filenames (regex) containing only root tree")
224 ->group(
"Input options");
225 program_options.add_option(
"--par-in", options.input.par,
"Set the filename of the input parameter root file")
226 ->capture_default_str()
227 ->group(
"Input options");
229 program_options.add_option(
"-o, --output-file", options.output.data,
"Set the output filename")
230 ->capture_default_str()
231 ->group(
"Output options");
233 .add_option(
"--par-out", options.output.par,
"Set the filename of the output parameter root file")
234 ->capture_default_str()
235 ->group(
"Output options");
240 const auto& option =
option_.get();
243 const auto output_name =
244 option.enable_mpi ? fmt::format(
"{}.{}", option.output.data,
rank_num_) : option.output.data;
245 if (not
option_.get().output.data.empty())
248 auto file_path = option.output.working_dir.empty()
249 ? fs::path{ output_name }
250 : fs::path{ option.output.working_dir } / fs::path{ output_name };
251 auto file_sink = std::make_unique<FairRootFileSink>(file_path.c_str());
252 run_->SetSink(file_sink.release());
256 auto file_source = std::make_unique<R3BFileSource2>();
259 file_source->SetInitRunID(
option_.get().run_id);
261 LOGP(info,
"Filesource2: Set to run id {}",
option_.get().run_id);
264 if (not file_source->IsEmpty())
266 run_->SetSource(file_source.release());
272 const auto& input_option =
option_.get().input;
273 const auto& output_option =
option_.get().output;
274 const auto& input_wd = input_option.working_dir;
275 const auto& output_wd = output_option.working_dir;
277 if (not input_option.par.empty())
280 for (
const auto& par_filename : input_option.par)
282 if (not par_filename.empty())
284 auto file_path = [&]()
286 auto par_file = fs::path{ par_filename };
288 if (par_file.is_absolute())
292 return input_wd.empty() ? par_file : fs::path{ input_wd } / par_file;
294 LOGP(info,
"Input first parameter file is {:?}", file_path.c_str());
295 input_par_fileio->open(file_path.c_str(),
"READ");
298 run_->GetRuntimeDb()->setFirstInput(input_par_fileio.release());
301 if (not output_option.par.empty())
303 const auto& option =
option_.get();
304 const auto output_name =
305 option.enable_mpi ? fmt::format(
"{}.{}", output_option.par,
rank_num_) : output_option.par;
307 output_wd.empty() ? fs::path{ output_name } : fs::path{ output_wd } / fs::path{ output_name };
308 LOGP(info,
"Ouptut parameter file is {:?}", file_path.string());
310 output_par_fileio->open(file_path.c_str(), option.output.mode);
313 auto* rtdb =
run_->GetRuntimeDb();
314 rtdb->setOutput(output_par_fileio.release());
320 auto max_event =
option_.get().event_num;
321 max_event = max_event > 0 ? max_event : 0;
324 LOGP(info,
"{} is set to run with {} events",
app_name_, max_event);
336 for (
const auto& [filename, is_tree] : input_span)
338 filesource->
AddFile(filename, is_tree);
344 auto file_path = fs::path{};
345 const auto& working_dir =
option_.get().input.working_dir;
346 for (
const auto& filename :
option_.get().input.data)
349 file_path = working_dir.empty() ? fs::path{ filename } : fs::path{ working_dir } / fs::path{ filename };
351 for (
const auto& fairroot_input_file : fairroot_input_files)
356 for (
const auto& filename :
option_.get().input.tree_data)
359 for (
const auto& tree_input_file : tree_input_files)
367 const std::vector<std::string>& filenames_or_options)
369 for (
const auto& filename_or_option : filenames_or_options)
371 auto json_file_obj = [&filename_or_option]()
373 switch (check_json_input_type(filename_or_option))
375 case JSONConfigInputType::string:
377 auto json_string = transform_to_json_string(filename_or_option);
378 LOGP(info,
"Reading the configuration from the string {:?}.", json_string);
379 return nlohmann::ordered_json::parse(std::move(json_string),
nullptr,
true,
true);
381 case JSONConfigInputType::file:
383 auto file = std::ifstream{ filename_or_option };
384 LOGP(info,
"Reading the configuration from the json file {:?}.", filename_or_option);
385 return nlohmann::ordered_json::parse(file,
nullptr,
true,
true);
387 case JSONConfigInputType::invalid:
390 throw R3B::logic_error(fmt::format(
"Cannot parse the string {:?}", filename_or_option));
392 json_obj.merge_patch(json_file_obj);
auto has_failed() const -> bool
auto has_inited() const -> bool
void set_inited(bool is_inited)
bool has_print_default_options_
void post_parse() override
Action done after the option parsing.
static void patch_files_or_strings(nlohmann::ordered_json &json_obj, const std::vector< std::string > &filenames_or_options)
virtual void setup_application_options(CLI::App &program_options)
std::vector< std::pair< std::string, bool > > input_files_
virtual void post_init(FairRun *run)
void run() override
Run the CLI program.
void extract_input_files()
std::reference_wrapper< Options > option_
std::string dump_json_filename_
void add_input_filename(R3BFileSource2 *filesource)
CLIApplication(std::string_view name, std::unique_ptr< FairRun > run, std::reference_wrapper< Options > option)
~CLIApplication() override
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
virtual void run_action(FairRun *run, int num_of_events)
void init() override
Initialization of a CLI program.
static void setup_logger()
std::unique_ptr< FairRun > run_
void setup_common_options(CLIAPP &program_options, OptionType &options)
static auto Output()
Factory method to create an instance for parameter output.
static auto Input()
Factory method to create an instance for parameter input.
void AddFile(std::string file_name, bool is_tree_file=false)
Simulation of NeuLAND Bar/Paddle.
const auto DEFAULT_JSON_FILENAME
nlohmann::ordered_json json
auto GetFilesFromRegex(std::string_view filename_regex) -> std::vector< std::string >