Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ jobs:
- name: test example iguana_ex_cpp_00_run_functions.cc
run: stdbuf -o0 iguana_ex_cpp_00_run_functions test_data.hipo ${{ env.num_events }} | tee equivalence.00.cpp.txt
if: ${{ matrix.id == 'cpp' || matrix.id == 'python' }}
- name: test example iguana_ex_cpp_00_run_functions_with_banks.cc
run: stdbuf -o0 iguana_ex_cpp_00_run_functions_with_banks test_data.hipo ${{ env.num_events }}
if: ${{ matrix.id == 'cpp' || matrix.id == 'python' }}
- name: test example iguana_ex_cpp_01_action_functions.cc
run: stdbuf -o0 iguana_ex_cpp_01_action_functions test_data.hipo ${{ env.num_events }} | tee equivalence.01.cpp.txt
if: ${{ matrix.id == 'cpp' || matrix.id == 'python' }}
Expand Down
5 changes: 4 additions & 1 deletion bind/python/iguana_ex_python_00_run_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,14 @@
# start the algorithms
seq.Start(banks)

# get the name of newly created banks (if you don't want to look them up in the documentation)
sector_finder_bank_name = seq.GetCreatedBankName("clas12::SectorFinder");

# get bank index, for each bank we want to use after Iguana algorithms run
# NOTE: new banks from creator algorithms are initialized by `Start`
b_config = hipo.getBanklistIndex(banks, 'RUN::config')
b_particle = hipo.getBanklistIndex(banks, 'REC::Particle')
b_sector = hipo.getBanklistIndex(banks, 'REC::Particle::Sector') # new created bank
b_sector = hipo.getBanklistIndex(banks, sector_finder_bank_name) # new created bank

# run the algorithm sequence on each event
iEvent = 0
Expand Down
19 changes: 11 additions & 8 deletions doc/gen/Doxyfile.in
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,18 @@ TAB_SIZE = 4

ALIASES =
# algorithm properties
ALIASES += brief_algo="@brief **%Algorithm:** "
ALIASES += begin_doc_algo{2|}="\par %Algorithm Name:^^&emsp;&emsp;&emsp;`%\1`\xrefitem algo \"Algorithm Type:\" \"List of all Algorithms\" \2 \par %Algorithm Inputs and Outputs:^^<table>"
ALIASES += input_banks{1}="<tr><td>**Input Banks**</td><td>`\1`</td></tr>"
ALIASES += output_banks{1}="<tr><td>**Output Banks**</td><td>`\1`</td></tr>"
ALIASES += end_doc="</table>"
ALIASES += algo_brief{1}="@brief **%Algorithm:** \1^^@xrefitem algo \"\" \"\" \1^^@link_to_run_ftn"
ALIASES += algo_type_filter="@par Type: Filter^^This algorithm will filter input bank(s).^^"
ALIASES += algo_type_transformer="@par Type: Transformer^^This algorithm will change values within input bank(s).^^"
ALIASES += algo_type_creator="@par Type: Creator^^This algorithm creates new bank(s) and its definition is found within the \link src/iguana/bankdefs/iguana.json **Iguana Bank Definitions JSON File** \endlink<ul><li>For guidance on how to read this JSON file, [see documentation on created banks](#mainpageCreatedBanks).</li><li>See also the return value type of this algorithm's action functions, which may be `struct`s with the same set of variables as the created bank.</li></ul>^^"
# configuration options
ALIASES += begin_doc_config{1}="\par Configuration Options:^^YAML configuration, which includes the default option values:^^@include \1/Config.yaml ^^Table of options and descriptions:^^<table><tr><th>Name</th><th>Type</th><th>Description</th></tr>"
ALIASES += config_param{3|}="<tr><td>`\1`</td><td>`\2`</td><td>\3</td></tr>"
ALIASES += end_doc="</table>^^"
# run functions
ALIASES += run_function="@brief **Run Function:** Process an event's `hipo::bank` objects^^^^The parameter list explains which banks are input (\"in\"), output (\"out\"), or both (\"in,out\").^^"
ALIASES += link_to_run_ftn="@par Input and Output Banks:^^See @link ::Run `Run` function(s) for the banks @endlink that are processed by this algorithm.^^"
ALIASES += run_function_returns_true="@returns `true`, _i.e._, this `%Run` function does not provide an event-level filter"
# action functions
ALIASES += action_function{1}="\xrefitem action \"Function Type\" \"List of all Action Functions\" \1 \brief **Action Function:** "
ALIASES += when_to_call{1}="@note This function should be called **\1**"
Expand All @@ -307,7 +311,6 @@ ALIASES += doxygen_on="@endcond"
ALIASES += latex{1}="@f$\1@f$"
# misc
ALIASES += spacer="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
ALIASES += creator_note="This algorithm creates a new bank and its definition is found within the \link src/iguana/bankdefs/iguana.json **Iguana Bank Definitions JSON File** \endlink<ul><li>For guidance on how to read this JSON file, [see documentation on created banks](#mainpageCreatedBanks).</li><li>See also the return value type of this algorithm's action functions, which may be `struct`s with the same set of variables as the created bank.</li></ul>"

# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
Expand Down Expand Up @@ -713,7 +716,7 @@ SORT_MEMBER_DOCS = YES
# this will also influence the order of the classes in the class list.
# The default value is: NO.

SORT_BRIEF_DOCS = NO
SORT_BRIEF_DOCS = YES

# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
Expand All @@ -732,7 +735,7 @@ SORT_MEMBERS_CTORS_1ST = NO
# appear in their defined order.
# The default value is: NO.

SORT_GROUP_NAMES = NO
SORT_GROUP_NAMES = YES

# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
# fully-qualified names, including namespaces. If set to NO, the class list will
Expand Down
14 changes: 11 additions & 3 deletions examples/iguana_ex_cpp_00_run_functions.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/// @begin_doc_example{cpp}
/// @file iguana_ex_cpp_00_run_functions.cc
/// @brief Example using **full HIPO banks** with Iguana algorithms' `Run` functions. This example requires the
/// user to have the C++ `hipo::bank` objects; see other examples if you do not have banks in this format.
/// @brief Example using **full HIPO banks** with Iguana algorithms' `Run` functions, using `hipo::banklist`
///
/// This example requires the user to have the C++ `hipo::banklist` objects, which are lists of `hipo::bank` objects.
///
/// - see `iguana_ex_cpp_00_run_functions_with_banks.cc` if you prefer just `hipo::bank` objects, rather than `hipo::banklist`
/// - see other examples if you do not have `hipo::bank` objects
///
/// @par Usage
/// ```bash
/// iguana_ex_cpp_00_run_functions [HIPO_FILE] [NUM_EVENTS]
Expand Down Expand Up @@ -55,11 +60,14 @@ int main(int argc, char** argv)
// start the algorithms
seq.Start(banks);

// get the name of newly created banks (or you can just get them from the documentation)
auto sector_finder_bank_name = seq.GetCreatedBankName("clas12::SectorFinder");

// get bank index, for each bank we want to use after Iguana algorithms run
// NOTE: new banks from creator algorithms are initialized by `Start`
auto b_config = hipo::getBanklistIndex(banks, "RUN::config");
auto b_particle = hipo::getBanklistIndex(banks, "REC::Particle");
auto b_sector = hipo::getBanklistIndex(banks, "REC::Particle::Sector"); // new created bank
auto b_sector = hipo::getBanklistIndex(banks, sector_finder_bank_name); // new created bank

// run the algorithm sequence on each event
int iEvent = 0;
Expand Down
126 changes: 126 additions & 0 deletions examples/iguana_ex_cpp_00_run_functions_with_banks.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/// @begin_doc_example{cpp}
/// @file iguana_ex_cpp_00_run_functions_with_banks.cc
/// @brief Example using **full HIPO banks** with Iguana algorithms' `Run` functions, using `hipo::bank`
///
/// This example requires the user to have the C++ `hipo::bank` objects.
///
/// - see `iguana_ex_cpp_00_run_functions.cc` if you prefer `hipo::banklist`
/// - see other examples if you do not have `hipo::bank` objects
///
/// @par Usage
/// ```bash
/// iguana_ex_cpp_00_run_functions_with_banks [HIPO_FILE] [NUM_EVENTS]
///
/// HIPO_FILE the HIPO file to analyze
///
/// NUM_EVENTS the number of events to analyze;
/// set to zero to analyze all events
/// ```
/// @end_doc_example

#include <hipo4/reader.h>
#include <iguana/algorithms/clas12/EventBuilderFilter/Algorithm.h>
#include <iguana/algorithms/clas12/SectorFinder/Algorithm.h>
#include <iguana/algorithms/clas12/MomentumCorrection/Algorithm.h>

/// main function
int main(int argc, char** argv)
{

// parse arguments
char const* inFileName = argc > 1 ? argv[1] : "data.hipo";
int const numEvents = argc > 2 ? std::stoi(argv[2]) : 3;

// read input file
hipo::reader reader(inFileName, {0});

// set list of banks to be read
hipo::dictionary dict;
reader.readDictionary(dict);
hipo::bank bank_config(dict.getSchema("RUN::config"));
hipo::bank bank_particle(dict.getSchema("REC::Particle"));
hipo::bank bank_calorimeter(dict.getSchema("REC::Calorimeter"));
hipo::bank bank_track(dict.getSchema("REC::Track"));
hipo::bank bank_scintillator(dict.getSchema("REC::Scintillator"));

// iguana algorithm sequence
// NOTE: unlike `iguana_ex_cpp_00_run_functions`, we do not use `AlgorithmSequence`, since
// we'll be calling each algorithm's `Run(hipo::bank& bank1, ...)` functions, which are unique
// for each algorithm (unlike `Run(hipo::banklist&)`
iguana::clas12::EventBuilderFilter algo_eventbuilder_filter; // filter by Event Builder PID (a filter algorithm)
iguana::clas12::SectorFinder algo_sector_finder; // get the sector for each particle (a creator algorithm)
iguana::clas12::MomentumCorrection algo_momentum_correction; // momentum corrections (a transformer algorithm)

// set log levels
// NOTE: this can also be done in a config file
algo_eventbuilder_filter.SetOption("log", "info");
algo_sector_finder.SetOption("log", "info");
algo_momentum_correction.SetOption("log", "info");

// set algorithm options
// NOTE: this can also be done in a config file, but setting options here OVERRIDES config file settings
algo_eventbuilder_filter.SetOption<std::vector<int>>("pids", {11, 211, -211});

// start the algorithms
algo_eventbuilder_filter.Start();
algo_sector_finder.Start();
algo_momentum_correction.Start();

// define newly created bank object
hipo::bank bank_sector = algo_sector_finder.GetCreatedBank();

// run the algorithm sequence on each event
int iEvent = 0;
hipo::event event;
while(reader.next() && (numEvents == 0 || iEvent++ < numEvents)) {

// read the event's banks
reader.read(event);
event.getStructure(bank_config);
event.getStructure(bank_particle);
event.getStructure(bank_calorimeter);
event.getStructure(bank_track);
event.getStructure(bank_scintillator);

// print the event number
fmt::println("===== EVENT {} =====", bank_config.getInt("event", 0));

// print the particle bank before Iguana algorithms
fmt::println("----- BEFORE IGUANA -----");
bank_particle.show(); // the original particle bank

// run the sequence of Iguana algorithms, in your preferred order
algo_eventbuilder_filter.Run(bank_particle);
algo_sector_finder.Run(bank_particle, bank_track, bank_calorimeter, bank_scintillator, bank_sector);
algo_momentum_correction.Run(bank_particle, bank_sector, bank_config);

// print the banks after Iguana algorithms
fmt::println("----- AFTER IGUANA -----");
bank_particle.show(); // the filtered particle bank, with corrected momenta
bank_sector.show(); // the new sector bank

// print a table; first the header
fmt::print("----- Analysis Particles -----\n");
fmt::print(" {:<20} {:<20} {:<20} {:<20}\n", "row == pindex", "PDG", "|p|", "sector");
// then print a row for each particle
// - use the `hipo::bank::getRowList()` method to loop over the bank rows that PASS the filter
// - if you'd rather loop over ALL bank rows, iterate from `i=0` up to `i < hipo::bank::getRows()` instead
for(auto const& row : bank_particle.getRowList()) {
auto p = std::hypot(
bank_particle.getFloat("px", row),
bank_particle.getFloat("py", row),
bank_particle.getFloat("pz", row));
auto pdg = bank_particle.getInt("pid", row);
auto sector = bank_sector.getInt("sector", row);
fmt::print(" {:<20} {:<20} {:<20.3f} {:<20}\n", row, pdg, p, sector);
}
fmt::print("\n");

}

// stop algorithms
algo_eventbuilder_filter.Stop();
algo_sector_finder.Stop();
algo_momentum_correction.Stop();
return 0;
}
1 change: 1 addition & 0 deletions examples/iguana_ex_cpp_01_action_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ int main(int argc, char** argv)

// stop the algorithms
algo_eventbuilder_filter.Stop();
algo_sector_finder.Stop();
algo_momentum_correction.Stop();
return 0;
}
1 change: 1 addition & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ install_subdir('config', install_dir: example_config_files_prefix, strip_directo
# example source information
example_sources = {
'iguana_ex_cpp_00_run_functions': {'sources': [ 'iguana_ex_cpp_00_run_functions.cc' ]},
'iguana_ex_cpp_00_run_functions_with_banks': {'sources': [ 'iguana_ex_cpp_00_run_functions_with_banks.cc' ]},
'iguana_ex_cpp_01_action_functions': {'sources': [ 'iguana_ex_cpp_01_action_functions.cc' ]},
'iguana_ex_cpp_dataframes': {
'sources': [ 'iguana_ex_cpp_dataframes.cc' ],
Expand Down
89 changes: 71 additions & 18 deletions src/iguana/algorithms/Algorithm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ namespace iguana {
return idx;
} catch(std::runtime_error const& ex) {
m_log->Error("required input bank '{}' not found; cannot `Start` algorithm '{}'", bank_name, m_class_name);
auto creators = AlgorithmFactory::QueryNewBank(bank_name);
auto creators = AlgorithmFactory::GetCreatorAlgorithms(bank_name);
if(creators)
m_log->Error(" -> this bank is created by algorithm(s) [{}]; please `Start` ONE of them BEFORE this algorithm", fmt::join(creators.value(), ", "));
throw std::runtime_error("cannot cache bank index");
Expand Down Expand Up @@ -208,7 +208,7 @@ namespace iguana {
}
catch(std::out_of_range const& o) {
m_log->Error("required input bank '{}' not found; cannot `Run` algorithm '{}'", expected_bank_name, m_class_name);
auto creators = AlgorithmFactory::QueryNewBank(expected_bank_name);
auto creators = AlgorithmFactory::GetCreatorAlgorithms(expected_bank_name);
if(creators)
m_log->Error(" -> this bank is created by algorithm(s) [{}]; please `Run` ONE of them BEFORE this algorithm", fmt::join(creators.value(), ", "));
}
Expand All @@ -218,18 +218,60 @@ namespace iguana {

///////////////////////////////////////////////////////////////////////////////

hipo::schema Algorithm::CreateBank(
hipo::banklist& banks,
hipo::banklist::size_type& bank_idx,
std::string const& bank_name) const noexcept(false)
std::vector<std::string> Algorithm::GetCreatedBankNames() const noexcept(false)
{
auto created_banks = AlgorithmFactory::GetCreatedBanks(m_class_name);
if(created_banks)
return created_banks.value();
throw std::runtime_error("failed to get created bank names");
}

///////////////////////////////////////////////////////////////////////////////

std::string Algorithm::GetCreatedBankName() const noexcept(false)
{
auto created_banks = GetCreatedBankNames();
switch(created_banks.size()) {
case 0:
m_log->Error("algorithm {:?} creates no new banks", m_class_name);
break;
case 1:
return created_banks.at(0);
break;
default:
m_log->Error("algorithm {:?} creates more than one bank; they are: [{}]", m_class_name, fmt::join(created_banks, ", "));
m_log->Error("- if you called `GetCreatedBank` or `GetCreatedBankSchema`, please specify which bank you want");
m_log->Error("- if you called `GetCreatedBankName`, call `GetCreatedBankNames` instead");
break;
}
throw std::runtime_error("failed to get created bank names");
}

///////////////////////////////////////////////////////////////////////////////

hipo::bank Algorithm::GetCreatedBank(std::string const& bank_name) const noexcept(false)
{
return hipo::bank(GetCreatedBankSchema(bank_name));
}

///////////////////////////////////////////////////////////////////////////////

hipo::schema Algorithm::GetCreatedBankSchema(std::string const& bank_name) const noexcept(false)
{
// loop over bank definitions
// NOTE: `BANK_DEFS` is generated at build-time using `src/iguana/bankdefs/iguana.json`
std::string bank_name_arg = bank_name; // copy, to permit modification

// if the user did not provide a bank name, get it from the list of banks created by the algorithm;
// this will fail if the algorithm creates more than one bank, in which case, the user must
// specify the bank name explicitly
if(bank_name.empty())
bank_name_arg = GetCreatedBankName();

// loop over bank definitions, `BANK_DEFS`, which is generated at build-time using `src/iguana/bankdefs/iguana.json`
for(auto const& bank_def : BANK_DEFS) {
if(bank_def.name == bank_name) {
if(bank_def.name == bank_name_arg) {
// make sure the new bank is in REGISTER_IGUANA_ALGORITHM
if(!AlgorithmFactory::QueryNewBank(bank_name)) {
m_log->Error("{:?} creates bank {:?}, which is not registered; new banks must be included in `REGISTER_IGUANA_ALGORITHM` arguments", m_class_name, bank_name);
if(!AlgorithmFactory::GetCreatorAlgorithms(bank_name_arg)) {
m_log->Error("algorithm {:?} creates bank {:?}, which is not registered; new banks must be included in `REGISTER_IGUANA_ALGORITHM` arguments", m_class_name, bank_name_arg);
throw std::runtime_error("CreateBank failed");
}
// create the schema format string
Expand All @@ -238,20 +280,31 @@ namespace iguana {
schema_def.push_back(entry.name + "/" + entry.type);
auto format_string = fmt::format("{}", fmt::join(schema_def, ","));
// create the new bank schema
hipo::schema bank_schema(bank_name.c_str(), bank_def.group, bank_def.item);
hipo::schema bank_schema(bank_name_arg.c_str(), bank_def.group, bank_def.item);
bank_schema.parse(format_string);
// create the new bank
banks.push_back({bank_schema});
bank_idx = GetBankIndex(banks, bank_name);
return bank_schema;
}
}
throw std::runtime_error(fmt::format("bank {:?} not found in 'BankDefs.h'; is this bank defined in src/iguana/bankdefs/iguana.json ?", bank_name));

throw std::runtime_error(fmt::format("bank {:?} not found in 'BankDefs.h'; is this bank defined in src/iguana/bankdefs/iguana.json ?", bank_name_arg));
}

///////////////////////////////////////////////////////////////////////////////

hipo::schema Algorithm::CreateBank(
hipo::banklist& banks,
hipo::banklist::size_type& bank_idx,
std::string const& bank_name) const noexcept(false)
{
auto bank_schema = GetCreatedBankSchema(bank_name);
banks.emplace_back(bank_schema);
bank_idx = GetBankIndex(banks, bank_name);
return bank_schema;
}

///////////////////////////////////////////////////////////////////////////////

void Algorithm::ShowBanks(hipo::banklist& banks, std::string_view message, Logger::Level const level) const
void Algorithm::ShowBanks(hipo::banklist const& banks, std::string_view message, Logger::Level const level) const
{
if(m_log->GetLevel() <= level) {
if(!message.empty())
Expand All @@ -263,7 +316,7 @@ namespace iguana {

///////////////////////////////////////////////////////////////////////////////

void Algorithm::ShowBank(hipo::bank& bank, std::string_view message, Logger::Level const level) const
void Algorithm::ShowBank(hipo::bank const& bank, std::string_view message, Logger::Level const level) const
{
if(m_log->GetLevel() <= level) {
if(!message.empty())
Expand Down
Loading