6#include <FairParRootFileIo.h>
7#include <FairRootFileSink.h>
9#include <FairRuntimeDb.h>
10#include <boost/algorithm/string/classification.hpp>
11#include <boost/algorithm/string/split.hpp>
12#include <boost/algorithm/string/trim.hpp>
13#include <boost/range/adaptor/reversed.hpp>
16#include <fairlogger/Logger.h>
24#include <nlohmann/json.hpp>
25#include <nlohmann/json_fwd.hpp>
38 auto get_partition_from(
const std::vector<T>& elements,
int num_of_partitions,
int partition_num) -> span<const T>
40 const auto total_size = elements.size();
42 static_cast<int>(std::ceil(
static_cast<float>(total_size) /
static_cast<float>(num_of_partitions)));
43 if (step * partition_num >= total_size)
47 const auto span_size = step * (partition_num + 1) < total_size ? step : total_size - (step * partition_num);
48 return span<const T>{ &(elements.at(step * partition_num)), span_size };
51 enum class JSONConfigInputType : uint8_t
58 auto check_json_input_type(std::string_view input) -> JSONConfigInputType
60 auto is_json_string = [](std::string_view string) ->
bool {
return string.find(
'=') != std::string::npos; };
61 auto is_a_file = [](std::string_view string) ->
bool {
return std::filesystem::exists(
string); };
63 if (is_json_string(input))
65 return JSONConfigInputType::string;
69 return JSONConfigInputType::file;
71 return JSONConfigInputType::invalid;
74 auto transform_to_json_string(std::string_view input) -> std::string
76 auto raw_string = std::string{ input };
77 auto equal_pos = raw_string.find(
'=');
78 auto keys_string = raw_string.substr(0, equal_pos);
79 auto value_string = raw_string.substr(equal_pos + 1);
81 boost::algorithm::trim(keys_string);
82 boost::algorithm::trim(value_string);
84 auto keys = std::vector<std::string>{};
85 boost::split(keys, keys_string, boost::is_any_of(
"."));
87 for (
const auto& key : boost::adaptors::reverse(keys))
89 value_string = fmt::format(
"{{ {:?} : {}}}", key, value_string);
98 using json = nlohmann::ordered_json;
100 std::unique_ptr<FairRun>
run,
101 std::reference_wrapper<Options> option)
117 LOGP(info,
"Writting all parameters to files");
118 run_->GetRuntimeDb()->writeContainers();
119 run_->GetSink()->Close();
123 fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
124 "\nNeuland Application finished with a failure!\n\n");
128 fmt::print(fmt::emphasis::bold | fg(fmt::color::green),
129 "\nNeuland Application finished successfully!\n\n");
131 fmt::println(
"Real time: {}s, cpu time: {}s",
timer_.RealTime(),
timer_.CpuTime());
137 auto spec1 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
138 fair::VerbositySpec::Info::file_line_function);
139 fair::Logger::DefineVerbosity(
"user1", spec1);
141 auto spec2 = fair::VerbositySpec::Make(fair::VerbositySpec::Info::severity,
142 fair::VerbositySpec::Info::timestamp_s,
143 fair::VerbositySpec::Info::file_line_function);
144 fair::Logger::DefineVerbosity(
"user2", spec2);
146 fair::Logger::SetConsoleColor(
true);
151 fair::Logger::SetConsoleSeverity(
option_.get().log_level);
152 fair::Logger::SetVerbosity(
option_.get().verbose_level);
157 LOGP(info,
"Initializaing application ...");
164 LOGP(info,
"Application is initialized.");
175 auto dump_config_callback = [
this](
const std::string& filename)
181 auto use_config_callback = [
this](
const std::vector<std::string>& filename_or_option)
192 .add_option_function<std::vector<std::string>>(
193 "-c, --use-config", use_config_callback,
"Set the json config file")
195 ->run_callback_for_default()
197 ->trigger_on_parse();
200 .add_option_function<std::string>(
"--dump-config", dump_config_callback,
"Dump the config into a json file")
202 ->run_callback_for_default()
204 program_options.add_option(
"-s, --severity", options.log_level,
"Set the severity level");
205 program_options.add_option(
"-v, --verbose", options.verbose_level,
"Set the verbose level");
206 program_options.add_option(
"-n, --event-num", options.event_num,
"Set the event number")->capture_default_str();
207 program_options.add_option(
"--run-id", options.run_id,
"Set the run id")->capture_default_str();
209 program_options.add_option(
"-i, --input-file", options.input.data,
"Set the input filenames (regex)")
210 ->capture_default_str()
211 ->group(
"Input options");
213 .add_option(
"--input-tree-file",
214 options.input.tree_data,
215 "Set the input filenames (regex) containing only root tree")
216 ->group(
"Input options");
217 program_options.add_option(
"--par-in", options.input.par,
"Set the filename of the input parameter root file")
218 ->capture_default_str()
219 ->group(
"Input options");
222 "--par-in-second", options.input.par_2,
"Set the filename of the second input parameter root file")
223 ->group(
"Input options");
225 program_options.add_option(
"-o, --output-file", options.output.data,
"Set the output filename")
226 ->capture_default_str()
227 ->group(
"Output options");
229 .add_option(
"--par-out", options.output.par,
"Set the filename of the output parameter root file")
230 ->capture_default_str()
231 ->group(
"Output options");
236 const auto& option =
option_.get();
239 const auto output_name =
240 option.enable_mpi ? fmt::format(
"{}.{}", option.output.data,
rank_num_) : option.output.data;
241 if (not
option_.get().output.data.empty())
244 auto file_path = option.output.working_dir.empty()
245 ? fs::path{ output_name }
246 : fs::path{ option.output.working_dir } / fs::path{ output_name };
247 auto file_sink = std::make_unique<FairRootFileSink>(file_path.c_str());
248 run_->SetSink(file_sink.release());
252 auto file_source = std::make_unique<R3BFileSource2>();
255 file_source->SetInitRunID(
option_.get().run_id);
257 LOGP(info,
"Filesource2: Set to run id {}",
option_.get().run_id);
260 if (not file_source->IsEmpty())
262 run_->SetSource(file_source.release());
268 auto file_path = fs::path{};
269 const auto& input_option =
option_.get().input;
270 const auto& output_option =
option_.get().output;
271 const auto& input_wd = input_option.working_dir;
272 const auto& output_wd = output_option.working_dir;
274 if (not input_option.par.empty())
277 input_wd.empty() ? fs::path{ input_option.par } : fs::path{ input_wd } / fs::path{ input_option.par };
278 auto fileio = std::make_unique<FairParRootFileIo>();
279 LOGP(info,
"Input first parameter file is {:?}", file_path.string());
280 fileio->open(file_path.c_str(),
"READ");
281 run_->GetRuntimeDb()->setFirstInput(fileio.release());
284 if (not input_option.par_2.empty())
286 file_path = input_wd.empty() ? fs::path{ input_option.par_2 }
287 : fs::path{ input_wd } / fs::path{ input_option.par_2 };
288 auto fileio = std::make_unique<FairParRootFileIo>();
289 LOGP(info,
"Input second parameter file is {:?}", file_path.string());
290 fileio->open(file_path.c_str(),
"READ");
291 run_->GetRuntimeDb()->setSecondInput(fileio.release());
294 if (not output_option.par.empty())
296 const auto& option =
option_.get();
297 const auto output_name =
298 option.enable_mpi ? fmt::format(
"{}.{}", output_option.par,
rank_num_) : output_option.par;
299 file_path = output_wd.empty() ? fs::path{ output_name } : fs::path{ output_wd } / fs::path{ output_name };
300 LOGP(info,
"Ouptut parameter file is {:?}", file_path.string());
301 auto fileio = std::make_unique<FairParRootFileIo>(
true);
302 fileio->open(file_path.c_str(),
"RECREATE");
303 auto* rtdb =
run_->GetRuntimeDb();
304 rtdb->setOutput(fileio.release());
310 auto max_event =
option_.get().event_num;
311 max_event = max_event > 0 ? max_event : 0;
314 LOGP(info,
"{} is set to run with {} events",
app_name_, max_event);
326 for (
const auto& [filename, is_tree] : input_span)
328 filesource->
AddFile(filename, is_tree);
334 auto file_path = fs::path{};
335 const auto& working_dir =
option_.get().input.working_dir;
336 for (
const auto& filename :
option_.get().input.data)
339 file_path = working_dir.empty() ? fs::path{ filename } : fs::path{ working_dir } / fs::path{ filename };
341 for (
const auto& fairroot_input_file : fairroot_input_files)
346 for (
const auto& filename :
option_.get().input.tree_data)
349 for (
const auto& tree_input_file : tree_input_files)
357 const std::vector<std::string>& filenames_or_options)
359 for (
const auto& filename_or_option : filenames_or_options)
361 auto json_file_obj = [&filename_or_option]()
363 switch (check_json_input_type(filename_or_option))
365 case JSONConfigInputType::string:
367 auto json_string = transform_to_json_string(filename_or_option);
368 LOGP(info,
"Reading the configuration from the string {:?}.", json_string);
369 return nlohmann::ordered_json::parse(std::move(json_string),
nullptr,
true,
true);
371 case JSONConfigInputType::file:
373 auto file = std::ifstream{ filename_or_option };
374 LOGP(info,
"Reading the configuration from the json file {:?}.", filename_or_option);
375 return nlohmann::ordered_json::parse(file,
nullptr,
true,
true);
377 case JSONConfigInputType::invalid:
380 throw R3B::logic_error(fmt::format(
"Cannot parse the string {:?}", filename_or_option));
382 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)
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 >