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);
100 using json = nlohmann::ordered_json;
102 std::unique_ptr<FairRun>
run,
103 std::reference_wrapper<Options> option)
119 LOGP(info,
"Writting all parameters to files");
120 run_->GetRuntimeDb()->writeContainers();
121 if (
auto* runtime_db =
run_->GetRuntimeDb(); runtime_db !=
nullptr)
123 runtime_db->writeContainers();
125 if (
auto* sink =
run_->GetSink(); sink !=
nullptr)
132 fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
133 "\nNeuland Application finished with a failure!\n\n");
137 fmt::print(fmt::emphasis::bold | fg(fmt::color::green),
138 "\nNeuland Application finished successfully!\n\n");
140 fmt::println(
"Real time: {}s, cpu time: {}s",
timer_.RealTime(),
timer_.CpuTime());
146 auto spec1 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
147 fair::VerbositySpec::Info::file_line_function);
148 fair::Logger::DefineVerbosity(
"user1", spec1);
150 auto spec2 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
151 fair::VerbositySpec::Info::timestamp_s,
152 fair::VerbositySpec::Info::file_line_function);
153 fair::Logger::DefineVerbosity(
"user2", spec2);
155 fair::Logger::SetConsoleColor(
true);
160 fair::Logger::SetConsoleSeverity(
option_.get().log_level);
161 fair::Logger::SetVerbosity(
option_.get().verbose_level);
166 LOGP(info,
"Initializaing application ...");
173 LOGP(info,
"Application is initialized.");
184 auto dump_config_callback = [
this](
const std::string& filename)
190 auto use_config_callback = [
this](
const std::vector<std::string>& filename_or_option)
201 .add_option_function<std::vector<std::string>>(
202 "-c, --use-config", use_config_callback,
"Set the json config file")
204 ->run_callback_for_default()
206 ->trigger_on_parse();
209 .add_option_function<std::string>(
"--dump-config", dump_config_callback,
"Dump the config into a json file")
211 ->run_callback_for_default()
213 program_options.add_option(
"-s, --severity", options.log_level,
"Set the severity level");
214 program_options.add_option(
"-v, --verbose", options.verbose_level,
"Set the verbose level");
215 program_options.add_option(
"-n, --event-num", options.event_num,
"Set the event number")->capture_default_str();
216 program_options.add_option(
"--run-id", options.run_id,
"Set the run id")->capture_default_str();
218 program_options.add_option(
"-i, --input-file", options.input.data,
"Set the input filenames (regex)")
219 ->capture_default_str()
220 ->group(
"Input options");
222 .add_option(
"--input-tree-file",
223 options.input.tree_data,
224 "Set the input filenames (regex) containing only root tree")
225 ->group(
"Input options");
226 program_options.add_option(
"--par-in", options.input.par,
"Set the filename of the input parameter root file")
227 ->capture_default_str()
228 ->group(
"Input options");
230 program_options.add_option(
"-o, --output-file", options.output.data,
"Set the output filename")
231 ->capture_default_str()
232 ->group(
"Output options");
234 .add_option(
"--par-out", options.output.par,
"Set the filename of the output parameter root file")
235 ->capture_default_str()
236 ->group(
"Output options");
241 const auto& option =
option_.get();
244 const auto output_name =
245 option.enable_mpi ? fmt::format(
"{}.{}", option.output.data,
rank_num_) : option.output.data;
246 if (not
option_.get().output.data.empty())
249 auto file_path = option.output.working_dir.empty()
250 ? fs::path{ output_name }
251 : fs::path{ option.output.working_dir } / fs::path{ output_name };
252 auto file_sink = std::make_unique<FairRootFileSink>(file_path.c_str());
253 run_->SetSink(file_sink.release());
257 auto file_source = std::make_unique<R3BFileSource2>();
260 file_source->SetInitRunID(
option_.get().run_id);
262 LOGP(info,
"Filesource2: Set to run id {}",
option_.get().run_id);
265 if (not file_source->IsEmpty())
267 run_->SetSource(file_source.release());
273 auto file_path = fs::path{};
274 const auto& input_option =
option_.get().input;
275 const auto& output_option =
option_.get().output;
276 const auto& input_wd = input_option.working_dir;
277 const auto& output_wd = output_option.working_dir;
279 if (not input_option.par.empty())
282 input_wd.empty() ? fs::path{ input_option.par } : fs::path{ input_wd } / fs::path{ input_option.par };
284 LOGP(info,
"Input first parameter file is {:?}", file_path.string());
285 fileio->open(file_path.c_str(),
"READ");
286 run_->GetRuntimeDb()->setFirstInput(fileio.release());
289 if (not output_option.par.empty())
291 const auto& option =
option_.get();
292 const auto output_name =
293 option.enable_mpi ? fmt::format(
"{}.{}", output_option.par,
rank_num_) : output_option.par;
294 file_path = output_wd.empty() ? fs::path{ output_name } : fs::path{ output_wd } / fs::path{ output_name };
295 LOGP(info,
"Ouptut parameter file is {:?}", file_path.string());
297 fileio->open(file_path.c_str(), option.output.mode);
300 auto* rtdb =
run_->GetRuntimeDb();
301 rtdb->setOutput(fileio.release());
307 auto max_event =
option_.get().event_num;
308 max_event = max_event > 0 ? max_event : 0;
311 LOGP(info,
"{} is set to run with {} events",
app_name_, max_event);
323 for (
const auto& [filename, is_tree] : input_span)
325 filesource->
AddFile(filename, is_tree);
331 auto file_path = fs::path{};
332 const auto& working_dir =
option_.get().input.working_dir;
333 for (
const auto& filename :
option_.get().input.data)
336 file_path = working_dir.empty() ? fs::path{ filename } : fs::path{ working_dir } / fs::path{ filename };
338 for (
const auto& fairroot_input_file : fairroot_input_files)
343 for (
const auto& filename :
option_.get().input.tree_data)
346 for (
const auto& tree_input_file : tree_input_files)
354 const std::vector<std::string>& filenames_or_options)
356 for (
const auto& filename_or_option : filenames_or_options)
358 auto json_file_obj = [&filename_or_option]()
360 switch (check_json_input_type(filename_or_option))
362 case JSONConfigInputType::string:
364 auto json_string = transform_to_json_string(filename_or_option);
365 LOGP(info,
"Reading the configuration from the string {:?}.", json_string);
366 return nlohmann::ordered_json::parse(std::move(json_string),
nullptr,
true,
true);
368 case JSONConfigInputType::file:
370 auto file = std::ifstream{ filename_or_option };
371 LOGP(info,
"Reading the configuration from the json file {:?}.", filename_or_option);
372 return nlohmann::ordered_json::parse(file,
nullptr,
true,
true);
374 case JSONConfigInputType::invalid:
377 throw R3B::logic_error(fmt::format(
"Cannot parse the string {:?}", filename_or_option));
379 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 >