7#include <FairParRootFileIo.h>
8#include <FairRootFileSink.h>
10#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>
17#include <fairlogger/Logger.h>
22#include <fmt/format.h>
25#include <magic_enum/magic_enum.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 constexpr auto trim_space(std::string_view str) -> std::string_view
57 return std::string_view{};
59 const auto* start_pos = std::ranges::find_if(str, [](
auto cha) ->
bool {
return cha !=
' ' and cha !=
'\n'; });
60 auto end_pos = std::ranges::find_if(str | std::views::reverse,
61 [](
auto cha) ->
bool {
return cha !=
' ' and cha !=
'\n'; });
62 if (start_pos > end_pos.base())
64 return std::string_view{};
66 return std::string_view{ start_pos, end_pos.base() };
74 std::unique_ptr<FairRun>
run,
75 std::reference_wrapper<Options> option)
91 LOGP(info,
"Writing all parameters to files");
92 run_->GetRuntimeDb()->writeContainers();
93 if (
auto* runtime_db =
run_->GetRuntimeDb(); runtime_db !=
nullptr)
95 runtime_db->writeContainers();
97 if (
auto* sink =
run_->GetSink(); sink !=
nullptr)
104 fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
105 "\nNeuland Application finished with a failure!\n\n");
109 fmt::print(fmt::emphasis::bold | fg(fmt::color::green),
110 "\nNeuland Application finished successfully!\n\n");
112 fmt::println(
"Real time: {}s, cpu time: {}s",
timer_.RealTime(),
timer_.CpuTime());
118 auto spec1 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
119 fair::VerbositySpec::Info::file_line_function);
120 fair::Logger::DefineVerbosity(
"user1", spec1);
122 auto spec2 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
123 fair::VerbositySpec::Info::timestamp_s,
124 fair::VerbositySpec::Info::file_line_function);
125 fair::Logger::DefineVerbosity(
"user2", spec2);
127 fair::Logger::SetConsoleColor(
true);
132 fair::Logger::SetConsoleSeverity(
option_.get().log_level);
133 fair::Logger::SetVerbosity(
option_.get().verbose_level);
138 LOGP(info,
"Initializing application ...");
145 LOGP(info,
"Application is initialized.");
156 auto dump_config_callback = [
this](
const std::string& filename) ->
void
162 auto use_config_callback = [
this](
const std::vector<std::string>& filename_or_option) ->
void
173 .add_option_function<std::vector<std::string>>(
174 "-c, --use-config", use_config_callback,
"Set the json config file")
176 ->run_callback_for_default()
178 ->trigger_on_parse();
181 .add_option_function<std::string>(
"--dump-config", dump_config_callback,
"Dump the config into a json file")
183 ->run_callback_for_default()
185 program_options.add_option(
"-s, --severity", options.log_level,
"Set the severity level");
186 program_options.add_option(
"-v, --verbose", options.verbose_level,
"Set the verbose level");
187 program_options.add_option(
"-n, --event-num", options.number_of_events,
"Set the event number")
188 ->capture_default_str();
189 program_options.add_option(
"--run-id", options.run_id,
"Set the run id")->capture_default_str();
191 program_options.add_option(
"-i, --input-file", options.input.data,
"Set the input filenames (regex)")
192 ->capture_default_str()
193 ->group(
"Input options");
195 .add_option(
"--input-tree-file",
196 options.input.tree_data,
197 "Set the input filenames (regex) containing only root tree")
198 ->group(
"Input options");
199 program_options.add_option(
"--par-in", options.input.par,
"Set the filename of the input parameter root file")
200 ->capture_default_str()
201 ->group(
"Input options");
203 program_options.add_option(
"-o, --output-file", options.output.data,
"Set the output filename")
204 ->capture_default_str()
205 ->group(
"Output options");
207 .add_option(
"--par-out", options.output.par,
"Set the filename of the output parameter root file")
208 ->capture_default_str()
209 ->group(
"Output options");
214 const auto& option =
option_.get();
217 const auto output_name =
218 option.enable_mpi ? fmt::format(
"{}.{}", option.output.data,
rank_num_) : option.output.data;
219 if (not
option_.get().output.data.empty())
222 auto file_path = option.output.working_dir.empty()
223 ? fs::path{ output_name }
224 : fs::path{ option.output.working_dir } / fs::path{ output_name };
226 std::make_unique<TFile>(file_path.c_str(), magic_enum::enum_name(option.output.mode).data());
227 auto file_sink = std::make_unique<FairRootFileSink>(root_file.release());
228 run_->SetSink(file_sink.release());
232 auto file_source = std::make_unique<R3BFileSource2>();
235 file_source->SetInitRunID(
option_.get().run_id);
237 LOGP(info,
"Filesource2: Set to run id {}",
option_.get().run_id);
240 if (not file_source->IsEmpty())
242 run_->SetSource(file_source.release());
248 const auto& input_option =
option_.get().input;
249 const auto& output_option =
option_.get().output;
250 const auto& input_wd = input_option.working_dir;
251 const auto& output_wd = output_option.working_dir;
253 if (not input_option.par.empty())
256 for (
const auto& par_filename : input_option.par)
258 if (not par_filename.empty())
260 auto file_path = [&]() -> fs::path
262 auto par_file = fs::path{ par_filename };
264 if (par_file.is_absolute())
268 return input_wd.empty() ? par_file : fs::path{ input_wd } / par_file;
270 LOGP(info,
"Input first parameter file is {:?}", file_path.c_str());
271 input_par_fileio->open(file_path.c_str(),
"READ");
274 run_->GetRuntimeDb()->setFirstInput(input_par_fileio.release());
277 if (not output_option.par.empty())
279 const auto& option =
option_.get();
280 const auto output_name =
281 option.enable_mpi ? fmt::format(
"{}.{}", output_option.par,
rank_num_) : output_option.par;
283 output_wd.empty() ? fs::path{ output_name } : fs::path{ output_wd } / fs::path{ output_name };
284 LOGP(info,
"Output parameter file is {:?}", file_path.string());
286 output_par_fileio->open(file_path.c_str(), magic_enum::enum_name(option.output.mode));
289 auto* rtdb =
run_->GetRuntimeDb();
290 rtdb->setOutput(output_par_fileio.release());
296 auto max_event =
option_.get().number_of_events;
297 max_event = max_event > 0 ? max_event : 0;
300 LOGP(info,
"{} is set to run with {} events",
app_name_, max_event);
312 for (
const auto& [filename, is_tree] : input_span)
314 filesource->
AddFile(filename, is_tree);
320 auto file_path = fs::path{};
321 const auto& working_dir =
option_.get().input.working_dir;
322 for (
const auto& filename :
option_.get().input.data)
325 file_path = working_dir.empty() ? fs::path{ filename } : fs::path{ working_dir } / fs::path{ filename };
327 for (
const auto& fairroot_input_file : fairroot_input_files)
332 for (
const auto& filename :
option_.get().input.tree_data)
335 for (
const auto& tree_input_file : tree_input_files)
344 auto is_json_native_string = [](std::string_view string) ->
bool
346 const auto trim_string = trim_space(
string);
347 return trim_string.starts_with(
'{') and trim_string.ends_with(
'}');
350 auto is_json_string = [](std::string_view string) ->
bool {
return string.contains(
'='); };
351 auto is_a_file = [](std::string_view string) ->
bool {
return std::filesystem::exists(
string); };
353 if (is_json_native_string(input))
357 if (is_json_string(input))
361 if (is_a_file(input))
370 auto raw_string = std::string{ input };
371 auto equal_pos = raw_string.find(
'=');
372 auto keys_string = raw_string.substr(0, equal_pos);
373 buffer = raw_string.substr(equal_pos + 1);
375 boost::algorithm::trim(keys_string);
376 boost::algorithm::trim(buffer);
378 auto keys = std::vector<std::string>{};
381 boost::split(keys, keys_string, boost::is_any_of(
"."));
383 for (
const auto& key : boost::adaptors::reverse(keys))
385 buffer = fmt::format(
"{{ {:?} : {}}}", key, buffer);
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.
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
virtual void post_init(FairRun *run)
static void transform_to_json_string(std::string_view input, std::string &buffer)
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
auto GetFilesFromRegex(std::string_view filename_regex) -> std::vector< std::string >