diff --git a/doc/gen/Doxyfile.in b/doc/gen/Doxyfile.in index 0a58a8fc..c52120d3 100644 --- a/doc/gen/Doxyfile.in +++ b/doc/gen/Doxyfile.in @@ -306,6 +306,7 @@ ALIASES += doxygen_on="@endcond" ALIASES += latex{1}="@f$\1@f$" # misc ALIASES += spacer="     " +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" # 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 @@ -970,7 +971,8 @@ INPUT = @top_srcdir@/src/ \ @top_srcdir@/bind/ \ @top_srcdir@/doc/gen/ \ @top_srcdir@/doc/gen/mainpage.md \ - @top_srcdir@/examples/ + @top_srcdir@/examples/ \ + @top_srcdir@/src/iguana/bankdefs/iguana.json # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/doc/gen/mainpage.md b/doc/gen/mainpage.md index 96ee9214..1542c6ac 100644 --- a/doc/gen/mainpage.md +++ b/doc/gen/mainpage.md @@ -5,13 +5,13 @@ This documentation shows how to use the Iguana algorithms. For more documentatio | Quick Links || | --- | --- | -| @spacer [List of Algorithms](#algo) @spacer | @spacer [Examples of Code](#secExample) @spacer | -| @spacer [List of Action Functions](#action) @spacer | @spacer [Configuring Algorithms](#secConfiguring) @spacer | +| @spacer [List of Algorithms](#algo) @spacer | @spacer [Examples of Code](#mainpageExample) @spacer | +| @spacer [List of Action Functions](#action) @spacer | @spacer [Configuring Algorithms](#mainpageConfiguring) @spacer |


-@anchor secExample +@anchor mainpageExample ## Example Analysis Code Using Iguana To see Iguana algorithms used in the context of analysis code, with **various languages** and **use cases**, see: @@ -27,17 +27,17 @@ In summary, the general way to use an Iguana algorithm is as follows; see exampl 1. Decide [which algorithms](#algo) you want to use - Tip: you may use `iguana::AlgorithmSequence` to help run a _sequence_ of algorithms -2. Check each algorithm configuration, and [adjust it if you prefer](#secConfiguring) +2. Check each algorithm configuration, and [adjust it if you prefer](#mainpageConfiguring) 3. Start each algorithm, which "locks in" its configuration: - - call `Start(banklist)` if you use [**the HIPO API**](https://github.com/gavalian/hipo) and [Common Functions](#secCommon) - - call `Start()` otherwise, _i.e._, if you use [Action Functions](#secAction) + - call `Start(banklist)` if you use [**the HIPO API**](https://github.com/gavalian/hipo) and [Common Functions](#mainpageCommon) + - call `Start()` otherwise, _i.e._, if you use [Action Functions](#mainpageAction) 4. In the event loop, run the algorithm: - call `Run(...)` if you use Common Functions - call the Action Function(s) otherwise 5. Proceed with your analysis - if you called `Run(...)`, the banks will be filtered, transformed, and/or created - if you called action functions, you will need to handle their output yourself - - in either case, see [guidance on how to run algorithms](#secRunning) for more details + - in either case, see [guidance on how to run algorithms](#mainpageRunning) for more details 6. After your event loop, stop each algorithm by calling `Stop()` Please let the maintainers know if your use case is not covered in any examples or if you need any help. @@ -45,7 +45,7 @@ Please let the maintainers know if your use case is not covered in any examples


-@anchor secAlgorithms +@anchor mainpageAlgorithms ## Algorithms An Iguana algorithm is a function that maps input HIPO bank data to output data. There are a few different types of algorithms, based on how they act on HIPO data: @@ -61,23 +61,61 @@ The available algorithms are: - [Algorithms organized by Namespace](#algo_namespaces) - [Full List of Algorithms](#algo) +@anchor mainpageCreatedBanks +### New Banks from Iguana Creator Algorithms + +The definitions of the new banks that are created by **Creator** algorithms are found in: +- @link src/iguana/bankdefs/iguana.json **Iguana Bank Definitions:** `iguana.json` @endlink + +This JSON file follows a similar format as the bank definitions in `coatjava`, where we have: + +| Key | Description | +| --- | --- | +| name | the name of the new bank | +| algorithm | the algorithm that creates this bank | +| group | unique ID numbers for this bank | +| item | ^ | +| entries | the list of variables in this bank | + +Often the bank name matches the algorithm name, but not always; see the JSON keys \"name\" and \"algorithm\" to be sure. + +For each variable in "entries", we have: + +| Key | Description | +| --- | --- | +| name | the variable name | +| type | the variable type (see below) | +| info | the description of this variable | + +The variable types and their corresponding accessor methods from `hipo::bank` are: + +| Type Specification | `hipo::bank` accessor | +| --- | --- | +| B | `getByte` | +| S | `getShort` | +| I | `getInt` | +| L | `getLong` | +| F | `getFloat` | +| D | `getDouble` | + +


-@anchor secRunning +@anchor mainpageRunning ## How to Run Algorithms Algorithms may be run using either: -- [Common Functions](#secCommon): for users of the [**the HIPO API**](https://github.com/gavalian/hipo), which is likely the case if you are using C++, _e.g._, via `clas12root` -- [Action Functions](#secAction): for all other users +- [Common Functions](#mainpageCommon): for users of the [**the HIPO API**](https://github.com/gavalian/hipo), which is likely the case if you are using C++, _e.g._, via `clas12root` +- [Action Functions](#mainpageAction): for all other users The next sections describe each of these. @important It is highly recommended to read an algorithm's documentation carefully before using it.
-@anchor secCommon +@anchor mainpageCommon ### Common Functions All algorithms have the following **Common Functions**, which may be used in analysis code that uses [**the HIPO API**](https://github.com/gavalian/hipo). These functions act on `hipo::bank` objects, and are designed to be called at certain points in an analysis of HIPO data: @@ -120,14 +158,14 @@ typically change the particle momentum components. Creator-type algorithms will simply create a new `hipo::bank` object, appending it to the end of the input `hipo::banklist`. An initial version is created upon calling `iguana::Algorithm::Start`, so that you may begin to reference it; it is helpful to -use `hipo::getBanklistIndex` (see [the examples for details](#secExample)). +use `hipo::getBanklistIndex` (see [the examples for details](#mainpageExample)). Internally, `iguana::Algorithm::Run` calls Action Functions, which are described in the next section.
-@anchor secAction +@anchor mainpageAction ### Action Functions The action functions do the _real_ work of the algorithm, and are meant to be @@ -173,7 +211,7 @@ While algorithm developers are encouraged _not_ to make breaking changes to thei


-@anchor secConfiguring +@anchor mainpageConfiguring ## How to Configure Algorithms Many algorithms are configurable. An algorithm's configuration parameters and their default values are found in the algorithm's documentation. diff --git a/meson.build b/meson.build index 5572baae..b695d2ea 100644 --- a/meson.build +++ b/meson.build @@ -205,6 +205,7 @@ endif # build and install shared libraries subdir('src/iguana/services') +subdir('src/iguana/bankdefs') subdir('src/iguana/algorithms') subdir('src/iguana/tests') diff --git a/src/iguana/algorithms/Algorithm.cc b/src/iguana/algorithms/Algorithm.cc index b6f37a27..d5cc8da6 100644 --- a/src/iguana/algorithms/Algorithm.cc +++ b/src/iguana/algorithms/Algorithm.cc @@ -1,7 +1,5 @@ #include "Algorithm.h" -#include - namespace iguana { void Algorithm::Start() @@ -223,29 +221,32 @@ namespace iguana { hipo::schema Algorithm::CreateBank( hipo::banklist& banks, hipo::banklist::size_type& bank_idx, - std::string const& bank_name, - std::vector schema_def, - int group_id, - int item_id) const + std::string const& bank_name) const noexcept(false) { - 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); - throw std::runtime_error("CreateBank failed"); - } - if(schema_def.empty()) { - m_log->Error("empty schema_def in CreateBank"); - throw std::runtime_error("CreateBank failed"); + // loop over bank definitions + // NOTE: `BANK_DEFS` is generated at build-time using `src/iguana/bankdefs/iguana.json` + for(auto const& bank_def : BANK_DEFS) { + if(bank_def.name == bank_name) { + // 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); + throw std::runtime_error("CreateBank failed"); + } + // create the schema format string + std::vector schema_def; + for(auto const& entry : bank_def.entries) + 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); + bank_schema.parse(format_string); + // create the new bank + banks.push_back({bank_schema}); + bank_idx = GetBankIndex(banks, bank_name); + return bank_schema; + } } - hipo::schema bank_schema(bank_name.c_str(), group_id, item_id); - bank_schema.parse(std::accumulate( - std::next(schema_def.begin()), - schema_def.end(), - schema_def[0], - [](std::string a, std::string b) - { return a + "," + b; })); - 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)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/Algorithm.h b/src/iguana/algorithms/Algorithm.h index 1700ca5c..8913cec2 100644 --- a/src/iguana/algorithms/Algorithm.h +++ b/src/iguana/algorithms/Algorithm.h @@ -6,8 +6,8 @@ #include - -#include "iguana/algorithms/AlgorithmBoilerplate.h" +#include "AlgorithmBoilerplate.h" +#include "iguana/bankdefs/BankDefs.h" #include "iguana/services/YAMLReader.h" #include @@ -153,21 +153,15 @@ namespace iguana { /// returns the `hipo::banklist` index of the bank hipo::banklist::size_type GetBankIndex(hipo::banklist& banks, std::string const& bank_name) const noexcept(false); - /// Create a new bank and push it to the bank list + /// Create a new bank and push it to the bank list. The bank must be defined in `src/iguana/bankdefs/iguana.json`. /// @param [out] banks the `hipo::banklist` onto which the new bank will be pushed /// @param [out] bank_idx will be set to the `hipo::banklist` index of the new bank /// @param [in] bank_name the new bank name - /// @param [in] schema_def a list of variables for the schema - /// @param [in] group_id the group ID for the schema - /// @param [in] item_id the item ID for the schema /// @returns the bank's schema hipo::schema CreateBank( hipo::banklist& banks, hipo::banklist::size_type& bank_idx, - std::string const& bank_name, - std::vector schema_def, - int group_id, // FIXME: generalize group_id and item_id setting - int item_id) const noexcept(false); + std::string const& bank_name) const noexcept(false); /// Dump all banks in a `hipo::banklist` /// @param banks the banks to show diff --git a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc index 0adfa93b..7cce65a2 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc +++ b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc @@ -43,8 +43,7 @@ namespace iguana::clas12 { } // create the output bank - // FIXME: generalize the groupid and itemid - auto result_schema = CreateBank(banks, b_result, "REC::Particle::Sector", {"sector/I","pindex/S"}, 0xF000, 4); + auto result_schema = CreateBank(banks, b_result, "REC::Particle::Sector"); i_sector = result_schema.getEntryOrder("sector"); i_pindex = result_schema.getEntryOrder("pindex"); } diff --git a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h index 63edee1d..de582b95 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h +++ b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h @@ -15,6 +15,8 @@ namespace iguana::clas12 { /// @config_param{bank_charged | string | if not `default`, use this bank for sector finding of charged particles} /// @config_param{bank_uncharged | string | if not `default`, use this bank for sector finding of neutral particles} /// @end_doc + /// + /// @creator_note class SectorFinder : public Algorithm { diff --git a/src/iguana/algorithms/meson.build b/src/iguana/algorithms/meson.build index 170b558a..49ff5e98 100644 --- a/src/iguana/algorithms/meson.build +++ b/src/iguana/algorithms/meson.build @@ -114,6 +114,7 @@ algo_sources = [ 'Algorithm.cc', 'AlgorithmFactory.cc', 'AlgorithmSequence.cc', + bankdef_tgt[1], # BankDefs.cc ] algo_headers = [ 'Algorithm.h', diff --git a/src/iguana/algorithms/physics/Depolarization/Algorithm.cc b/src/iguana/algorithms/physics/Depolarization/Algorithm.cc index 73954888..49c6f88c 100644 --- a/src/iguana/algorithms/physics/Depolarization/Algorithm.cc +++ b/src/iguana/algorithms/physics/Depolarization/Algorithm.cc @@ -10,13 +10,7 @@ namespace iguana::physics { // create the output bank // FIXME: generalize the groupid and itemid - auto result_schema = CreateBank( - banks, - b_result, - GetClassName(), - {"epsilon/D", "A/D", "B/D", "C/D", "V/D", "W/D"}, - 0xF000, - 1); + auto result_schema = CreateBank(banks, b_result, GetClassName()); i_epsilon = result_schema.getEntryOrder("epsilon"); i_A = result_schema.getEntryOrder("A"); i_B = result_schema.getEntryOrder("B"); diff --git a/src/iguana/algorithms/physics/Depolarization/Algorithm.h b/src/iguana/algorithms/physics/Depolarization/Algorithm.h index d68f875d..e041d5ad 100644 --- a/src/iguana/algorithms/physics/Depolarization/Algorithm.h +++ b/src/iguana/algorithms/physics/Depolarization/Algorithm.h @@ -4,33 +4,18 @@ namespace iguana::physics { - /// Set of depolarization variables - struct DepolarizationVars { - /// @brief @latex{\varepsilon(Q^2,x,y)}, the ratio of transverse and longitudinal photon flux - double epsilon; - /// @brief depolarization factor @latex{A(\varepsilon,y)} - double A; - /// @brief depolarization factor @latex{B(\varepsilon,y)} - double B; - /// @brief depolarization factor @latex{C(\varepsilon,y)} - double C; - /// @brief depolarization factor @latex{V(\varepsilon,y)} - double V; - /// @brief depolarization factor @latex{W(\varepsilon,y)} - double W; - }; - - /// @brief_algo Calculate depolarization factors defined in `iguana::physics::DepolarizationVars` + /// @brief_algo Calculate depolarization factors + /// + /// @par References + /// - https://arxiv.org/pdf/hep-ph/0611265 + /// - https://arxiv.org/pdf/1408.5721 /// /// @begin_doc_algo{physics::Depolarization | Creator} /// @input_banks{%physics::InclusiveKinematics} /// @output_banks{%physics::Depolarization} /// @end_doc /// - /// References: - /// - /// - https://arxiv.org/pdf/hep-ph/0611265 - /// - https://arxiv.org/pdf/1408.5721 + /// @creator_note class Depolarization : public Algorithm { diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc index 980145e2..ead9ae2a 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc @@ -13,28 +13,7 @@ namespace iguana::physics { b_inc_kin = GetBankIndex(banks, "physics::InclusiveKinematics"); // create the output bank - // FIXME: generalize the groupid and itemid - auto result_schema = CreateBank( - banks, - b_result, - GetClassName(), - { - "pindex_a/S", - "pindex_b/S", - "pdg_a/I", - "pdg_b/I", - "Mh/D", - "z/D", - "PhPerp/D", - "MX2/D", - "xF/D", - "yB/D", - "phiH/D", - "phiR/D", - "theta/D" - }, - 0xF000, - 5); + auto result_schema = CreateBank(banks, b_result, GetClassName()); i_pindex_a = result_schema.getEntryOrder("pindex_a"); i_pindex_b = result_schema.getEntryOrder("pindex_b"); i_pdg_a = result_schema.getEntryOrder("pdg_a"); diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h index 5234e876..8052c52e 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h @@ -7,39 +7,6 @@ namespace iguana::physics { - /// Set of dihadron kinematics variables - struct DihadronKinematicsVars { - /// @brief `REC::Particle` row (`pindex`) of hadron A - int pindex_a; - /// @brief `REC::Particle` row (`pindex`) of hadron B - int pindex_b; - /// @brief PDG code of hadron A - int pdg_a; - /// @brief PDG code of hadron B - int pdg_b; - /// @brief @latex{M_h}: Invariant mass of the dihadron - double Mh; - /// @brief @latex{z}: Momentum fraction of the fragmenting parton carried by the dihadron - double z; - /// @brief @latex{P_h^\perp}: transverse momentum of the dihadron in the @latex{\perp}-frame (transverse to @latex{\vec{q}}) - double PhPerp; - /// @brief @latex{M_X(ehhX)^2}: Missing mass squared of the dihadron - double MX2; - /// @brief @latex{x_F}: Feynman-x of the dihadron - double xF; - /// @brief @latex{y_{h,B}}: Breit frame rapidity of the dihadron - double yB; - /// @brief @latex{\phi_h}: @latex{q}-azimuthal angle between the lepton-scattering plane and the @latex{\vec{q}\times\vec{P}_h} plane; - /// if the value is `tools::UNDEF`, the calculation failed - double phiH; - /// @brief @latex{\phi_R}: @latex{q}-azimuthal angle between the lepton-scattering plane and dihadron plane; - /// if the value is `tools::UNDEF`, the calculation failed - double phiR; - /// @brief @latex{\theta}: The "decay" angle of hadron A in the dihadron rest frame, with respect; - /// to the dihadron momentum direction - double theta; - }; - /// @brief_algo Calculate semi-inclusive dihadron kinematic quantities defined in `iguana::physics::DihadronKinematicsVars` /// /// @begin_doc_algo{physics::DihadronKinematics | Creator} @@ -69,6 +36,8 @@ namespace iguana::physics { /// /// @par theta calculation methods /// - `"hadron_a"`: use hadron A's "decay angle" in the dihadron rest frame + /// + /// @creator_note class DihadronKinematics : public Algorithm { diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc index 6763a602..399c4ee7 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc @@ -13,14 +13,7 @@ namespace iguana::physics { b_config = GetBankIndex(banks, "RUN::config"); // create the output bank - // FIXME: generalize the groupid and itemid - auto result_schema = CreateBank( - banks, - b_result, - GetClassName(), - {"pindex/S", "Q2/D", "x/D", "y/D", "W/D", "nu/D", "qx/D", "qy/D", "qz/D", "qE/D", "beamPz/D", "targetM/D"}, - 0xF000, - 1); + auto result_schema = CreateBank(banks, b_result, GetClassName()); i_pindex = result_schema.getEntryOrder("pindex"); i_Q2 = result_schema.getEntryOrder("Q2"); i_x = result_schema.getEntryOrder("x"); diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h index 7b4a9594..12d2e16b 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h @@ -7,35 +7,7 @@ namespace iguana::physics { - /// Set of inclusive kinematics variables - struct InclusiveKinematicsVars { - /// @brief `REC::Particle` row (`pindex`) of the scattered electron - int pindex; - /// @brief @latex{x}-component of virtual photon momentum @latex{q} - vector_element_t qx; - /// @brief @latex{y}-component of virtual photon momentum @latex{q} - vector_element_t qy; - /// @brief @latex{z}-component of virtual photon momentum @latex{q} - vector_element_t qz; - /// @brief @latex{E}-component of virtual photon momentum @latex{q} - vector_element_t qE; - /// @brief @latex{Q^2} (GeV@latex{^2}) - double Q2; - /// @brief @latex{x_B} - double x; - /// @brief @latex{y} - double y; - /// @brief @latex{W} (GeV) - double W; - /// @brief @latex{\nu} - double nu; - /// @brief beam momentum @latex{z}-component (GeV) - double beamPz; - /// @brief target mass (GeV) - double targetM; - }; - - /// @brief_algo Calculate inclusive kinematics quantities defined in `iguana::physics::InclusiveKinematicsVars` + /// @brief_algo Calculate inclusive kinematics quantities /// /// @begin_doc_algo{physics::InclusiveKinematics | Creator} /// @input_banks{REC::Particle, RUN::config} @@ -49,6 +21,8 @@ namespace iguana::physics { /// @config_param{reconstruction | string | kinematics reconstruction method; only `scattered_lepton` is available at this time} /// @config_param{lepton_finder | string | algorithm to find the scattered lepton; only `highest_energy_FD_trigger` is available at this time} /// @end_doc + /// + /// @creator_note class InclusiveKinematics : public Algorithm { diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc index 4b55bfd9..10136d0e 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc @@ -14,24 +14,7 @@ namespace iguana::physics { b_inc_kin = GetBankIndex(banks, "physics::InclusiveKinematics"); // create the output bank - // FIXME: generalize the groupid and itemid - auto result_schema = CreateBank( - banks, - b_result, - GetClassName(), - { - "pindex/S", - "pdg/I", - "z/D", - "PhPerp/D", - "MX2/D", - "xF/D", - "yB/D", - "phiH/D", - "xi/D" - }, - 0xF000, - 7); + auto result_schema = CreateBank(banks, b_result, GetClassName()); i_pindex = result_schema.getEntryOrder("pindex"); i_pdg = result_schema.getEntryOrder("pdg"); i_z = result_schema.getEntryOrder("z"); diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h index 3920d463..3cacca33 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h @@ -6,30 +6,7 @@ namespace iguana::physics { - /// Set of hadron kinematics variables - struct SingleHadronKinematicsVars { - /// @brief `REC::Particle` row (`pindex`) of the hadron - int pindex; - /// @brief PDG code of the hadron - int pdg; - /// @brief @latex{z}: Momentum fraction of the fragmenting parton carried by the hadron - double z; - /// @brief @latex{P_h^\perp}: transverse momentum of the hadron in the @latex{\perp}-frame (transverse to @latex{\vec{q}}) - double PhPerp; - /// @brief @latex{M_X(ehX)^2}: Missing mass squared of the hadron - double MX2; - /// @brief @latex{x_F}: Feynman-x of the hadron - double xF; - /// @brief @latex{y_{h,B}}: Breit frame rapidity of the hadron - double yB; - /// @brief @latex{\phi_h}: @latex{q}-azimuthal angle between the lepton-scattering plane and the @latex{\vec{q}\times\vec{P}_h} plane; - /// if the value is `tools::UNDEF`, the calculation failed - double phiH; - /// @brief @latex{\xi_h}: Longitudinal momentum fraction of the nucleon carried by the hadron - double xi; - }; - - /// @brief_algo Calculate semi-inclusive hadron kinematic quantities defined in `iguana::physics::SingleHadronKinematicsVars` + /// @brief_algo Calculate semi-inclusive hadron kinematic quantities /// /// @begin_doc_algo{physics::SingleHadronKinematics | Creator} /// @input_banks{REC::Particle, %physics::InclusiveKinematics} @@ -48,6 +25,8 @@ namespace iguana::physics { /// corresponding row in the output bank will be zeroed, since no calculations are performed for /// those particles /// - particles which are not listed in the configuration parameter `hadron_list` will also be filtered out and zeroed + /// + /// @creator_note class SingleHadronKinematics : public Algorithm { diff --git a/src/iguana/bankdefs/README.md b/src/iguana/bankdefs/README.md new file mode 100644 index 00000000..96082972 --- /dev/null +++ b/src/iguana/bankdefs/README.md @@ -0,0 +1,20 @@ +# Iguana Bank Definitions + +Creator algorithms create new banks; the files in this directory describe the new banks, in particular, [`iguana.json`](iguana.json). + +This JSON file follows a similar format as the `coatjava` bank definitions and may be used as a reference; the only change is the addition of the `algorithm` key, which is used to inform which algorithm creates the bank. See [the user guide](https://jeffersonlab.github.io/iguana/doxygen) for more general information about the format of this JSON file. + +## Additional notes for developers +- [`bankgen.py`](bankgen.py) will read the JSON file and generate C++ code to handle the bank creation + - while you are developing your creator algorithm, you may first update the JSON file, then compile the code; this will run `bankgen.py`, which will generate `BankDefs.h` and `BankDefs.cc` within the _build_ directory, so you may inspect those files for further information if this documentation is not clear + - compilation will fail if the JSON syntax is incorrect +- for action functions' convenience, `bankgen.py` will generate a C++ `struct` with the name `[ALGORITHM_NAME]Vars` (the algorithm name with `Vars` appended) + - this `struct` may be used as the _return value_ type of action functions, if needed + - the variables in the `struct` have the same name and types as those defined in the bank "entries"; the "info" docstrings are used by `doxygen` +- add a new bank to the end of the JSON file, and increment the "item" number + - the "group" and "item" numbers must be unique for all banks (including those upstream in `coatjava`) + - all Iguana banks must use "group" `30000` +- values of "info" entries must be `doxygen` docstrings + - they are used in the documentation generation + - all backslashes must be escaped, _i.e._ instead of `\` write `\\`, otherwise the JSON syntax will be invalid +- our convention is that the bank name matches the algorithm name, but that does not have to be followed (early creator algorithms did not have this convention) diff --git a/src/iguana/bankdefs/bankgen.py b/src/iguana/bankdefs/bankgen.py new file mode 100755 index 00000000..6c31ab9c --- /dev/null +++ b/src/iguana/bankdefs/bankgen.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 + +""" +Reads an input JSON data model file, which defines the bank schema, and +generates C++ source code for handling these banks in Iguana. +""" + +import sys, json, textwrap + +# parse arguments +if(len(sys.argv) < 3): + print(f'USAGE {__file__} [INPUT_JSON] [OUTPUT_BASENAME]') + exit(2) +input_file_name = sys.argv[1] +output_base_name = sys.argv[2] + +# return a comma if `idx` does not point to the last element of list `arr` +def trailing_comma(arr, idx): + if(idx < len(arr)): + return ',' + else: + return '' + +# map `type` character to C++ type +type_dict = { + 'B': 'int', + 'S': 'int', + 'I': 'int', + 'F': 'float', + 'D': 'double', + 'L': 'long', +} + +# all iguana banks should have this group ID +iguana_group_id = 30000 + +# open the JSON file +with open(input_file_name) as input_file: + + try: + bank_defs = json.load(input_file) + + # start the output C++ files + out_h = open(f'{output_base_name}.h', 'w') + out_cc = open(f'{output_base_name}.cc', 'w') + + # start the header file with some common structs + out_h.write(textwrap.dedent('''\ + #include + #include + + namespace iguana { + + /// A bank column + struct BankColDef { + /// @brief the name of the column + std::string name; + /// @brief the type of the column + std::string type; + }; + + /// The definition of a bank + struct BankDef { + /// @brief the name of the bank + std::string name; + /// @brief the group ID of the bank + int group; + /// @brief the item ID of the bank + int item; + /// @brief the set of columns + std::vector entries; + }; + + /// Definitions of banks that Iguana algorithms may create; this variable is + /// defined in code generated by `src/iguana/bankdefs/bankgen.py` + extern std::vector const BANK_DEFS; + + } + + ''')) + + # the `.cc` source file will define `BANK_DEFS`; start its definition + out_cc.write(textwrap.dedent(f'''\ + #include "BankDefs.h" + + namespace iguana {{ + std::vector const BANK_DEFS = {{ + ''')) + + # loop over bank definitions in the JSON file + i_bank_def = 0 + unique_item_ids = [] + for bank_def in bank_defs: + + i_bank_def += 1 + trail_bank_def = trailing_comma(bank_defs, i_bank_def) + + # make sure the item ID is unique and the group ID is a expected + if(bank_def["item"] in unique_item_ids): + print(f'ERROR: item ID {bank_def["item"]} is not unique in {input_file_name}', file=sys.stderr) + exit(1) + unique_item_ids.append(bank_def["item"]) + if(bank_def["group"] != iguana_group_id): + print(f'ERROR: all group IDs must be {iguana_group_id}', file=sys.stderr) + exit(1) + + # append this bank to `BANK_DEFS` + out_cc.write(textwrap.indent(textwrap.dedent(f'''\ + {{ + .name = "{bank_def["name"]}", + .group = {bank_def["group"]}, + .item = {bank_def["item"]}, + .entries = {{ + '''), ' ')) + i_entry = 0 + for entry in bank_def['entries']: + i_entry += 1 + trail_entry = trailing_comma(bank_def['entries'], i_entry) + out_cc.write(f' {{ .name = "{entry["name"]}", .type = "{entry["type"]}" }}{trail_entry}\n') + out_cc.write(f' }}\n') + out_cc.write(f' }}{trail_bank_def}\n') + + # make a struct for this algorithm's action function output + algo_name = bank_def["algorithm"] + namespace_name = '::'.join(['iguana', *algo_name.split('::')[0:-1]]) + struct_name = algo_name.split('::')[-1] + 'Vars' + out_h.write(textwrap.dedent(f'''\ + namespace {namespace_name} {{ + /// Set of variables created by creator algorithm `iguana::{algo_name}` + struct {struct_name} {{ + ''')) + for entry in bank_def['entries']: + if entry["type"] in type_dict: + out_h.write(textwrap.indent(textwrap.dedent(f'''\ + /// @brief {entry["info"]} + {type_dict[entry["type"]]} {entry["name"]}; + '''), ' ')) + else: + print(f'ERROR: bank entry type "{entry["type"]}" is unknown', file=sys.stderr) + exit(1) + out_h.write(' };\n') + out_h.write('}\n\n') + + out_cc.write(' };\n') + out_cc.write('}\n') + out_cc.close() + out_h.close() + + except json.decoder.JSONDecodeError: + print(f'ERROR: failed to parse {input_file_name}; check its JSON syntax', file=sys.stderr) + exit(1) + +# for ext in ['h', 'cc']: +# print(f'Generated {output_base_name}.{ext}') diff --git a/src/iguana/bankdefs/iguana.json b/src/iguana/bankdefs/iguana.json new file mode 100644 index 00000000..41911661 --- /dev/null +++ b/src/iguana/bankdefs/iguana.json @@ -0,0 +1,89 @@ +[ + { + "name": "REC::Particle::Sector", + "algorithm": "clas12::SectorFinder", + "group": 30000, + "item": 1, + "info": "", + "entries": [ + { "name": "pindex", "type": "S", "info": "row number in the particle bank" }, + { "name": "sector", "type": "I", "info": "sector for this particle" } + ] + }, + { + "name": "physics::InclusiveKinematics", + "algorithm": "physics::InclusiveKinematics", + "group": 30000, + "item": 2, + "info": "", + "entries": [ + { "name": "pindex", "type": "S", "info": "`REC::Particle` row (`pindex`) of the scattered electron" }, + { "name": "Q2", "type": "D", "info": "@latex{Q^2} (GeV@latex{^2})" }, + { "name": "x", "type": "D", "info": "@latex{x_B}" }, + { "name": "y", "type": "D", "info": "@latex{y}" }, + { "name": "W", "type": "D", "info": "@latex{W} (GeV)" }, + { "name": "nu", "type": "D", "info": "@latex{\\nu}" }, + { "name": "qx", "type": "D", "info": "@latex{x}-component of virtual photon momentum @latex{q}" }, + { "name": "qy", "type": "D", "info": "@latex{y}-component of virtual photon momentum @latex{q}" }, + { "name": "qz", "type": "D", "info": "@latex{z}-component of virtual photon momentum @latex{q}" }, + { "name": "qE", "type": "D", "info": "@latex{E}-component of virtual photon momentum @latex{q}" }, + { "name": "beamPz", "type": "D", "info": "beam momentum @latex{z}-component (GeV)" }, + { "name": "targetM", "type": "D", "info": "target mass (GeV)" } + ] + }, + { + "name": "physics::SingleHadronKinematics", + "algorithm": "physics::SingleHadronKinematics", + "group": 30000, + "item": 3, + "info": "", + "entries": [ + { "name": "pindex", "type": "S", "info": "`REC::Particle` row (`pindex`) of the hadron" }, + { "name": "pdg", "type": "I", "info": "PDG code of the hadron" }, + { "name": "z", "type": "D", "info": "@latex{z}: Momentum fraction of the fragmenting parton carried by the hadron" }, + { "name": "PhPerp", "type": "D", "info": "@latex{P_h^\\perp}: transverse momentum of the hadron in the @latex{\\perp}-frame (transverse to @latex{\\vec{q}})" }, + { "name": "MX2", "type": "D", "info": "@latex{M_X^2(ehX)}: Missing mass squared of the hadron" }, + { "name": "xF", "type": "D", "info": "@latex{x_F}: Feynman-x of the hadron" }, + { "name": "yB", "type": "D", "info": "@latex{y_{h,B}}: Breit frame rapidity of the hadron" }, + { "name": "phiH", "type": "D", "info": "@latex{\\phi_h}: @latex{q}-azimuthal angle between the lepton-scattering plane and the @latex{\\vec{q}\\times\\vec{P}_h} plane; if the value is `tools::UNDEF`, the calculation failed" }, + { "name": "xi", "type": "D", "info": "@latex{\\xi_h}: Longitudinal momentum fraction of the nucleon carried by the hadron" } + ] + }, + { + "name": "physics::DihadronKinematics", + "algorithm": "physics::DihadronKinematics", + "group": 30000, + "item": 4, + "info": "", + "entries": [ + { "name": "pindex_a", "type": "S", "info": "`REC::Particle` row (`pindex`) of hadron A" }, + { "name": "pindex_b", "type": "S", "info": "`REC::Particle` row (`pindex`) of hadron B" }, + { "name": "pdg_a", "type": "I", "info": "PDG code of hadron A" }, + { "name": "pdg_b", "type": "I", "info": "PDG code of hadron B" }, + { "name": "Mh", "type": "D", "info": "@latex{M_h}: Invariant mass of the dihadron" }, + { "name": "z", "type": "D", "info": "@latex{z}: Momentum fraction of the fragmenting parton carried by the dihadron" }, + { "name": "PhPerp", "type": "D", "info": "@latex{P_h^\\perp}: transverse momentum of the dihadron in the @latex{\\perp}-frame (transverse to @latex{\\vec{q}})" }, + { "name": "MX2", "type": "D", "info": "@latex{M_X^2(ehhX)}: Missing mass squared of the dihadron" }, + { "name": "xF", "type": "D", "info": "@latex{x_F}: Feynman-x of the dihadron" }, + { "name": "yB", "type": "D", "info": "@latex{y_{h,B}}: Breit frame rapidity of the dihadron" }, + { "name": "phiH", "type": "D", "info": "@latex{\\phi_h}: @latex{q}-azimuthal angle between the lepton-scattering plane and the @latex{\\vec{q}\\times\\vec{P}_h} plane; if the value is `tools::UNDEF`, the calculation failed" }, + { "name": "phiR", "type": "D", "info": "@latex{\\phi_R}: @latex{q}-azimuthal angle between the lepton-scattering plane and dihadron plane; if the value is `tools::UNDEF`, the calculation failed" }, + { "name": "theta", "type": "D", "info": "@latex{\\theta}: The 'decay' angle of hadron A in the dihadron rest frame, with respect; to the dihadron momentum direction" } + ] + }, + { + "name": "physics::Depolarization", + "algorithm": "physics::Depolarization", + "group": 30000, + "item": 5, + "info": "", + "entries": [ + { "name": "epsilon", "type": "D", "info": "@latex{\\varepsilon(Q^2, x, y)}, the ratio of transverse and longitudinal photon flux" }, + { "name": "A", "type": "D", "info": "depolarization factor @latex{A(\\varepsilon, y)}" }, + { "name": "B", "type": "D", "info": "depolarization factor @latex{B(\\varepsilon, y)}" }, + { "name": "C", "type": "D", "info": "depolarization factor @latex{C(\\varepsilon, y)}" }, + { "name": "V", "type": "D", "info": "depolarization factor @latex{V(\\varepsilon, y)}" }, + { "name": "W", "type": "D", "info": "depolarization factor @latex{W(\\varepsilon, y)}" } + ] + } +] diff --git a/src/iguana/bankdefs/meson.build b/src/iguana/bankdefs/meson.build new file mode 100644 index 00000000..664ec46d --- /dev/null +++ b/src/iguana/bankdefs/meson.build @@ -0,0 +1,20 @@ +bankdef_json = files('iguana.json') + +prog_bankgen_sources = files('bankgen.py') +prog_bankgen = find_program(prog_bankgen_sources) + +# generate BankDefs.{h,cc} from the JSON data model file +bankdef_tgt = custom_target( + 'bankdefs', + input: [ + bankdef_json, + prog_bankgen_sources, + ], + output: [ 'BankDefs.h', 'BankDefs.cc' ], + command: [ prog_bankgen, '@INPUT0@', '@OUTDIR@/BankDefs' ], + install: true, + install_dir: [ get_option('includedir') / meson.project_name() / 'bankdefs', false ], +) + +# install the JSON data model file; iguana won't need it, but it can be useful for user reference +install_data(bankdef_json, install_dir: project_etc / 'bankdefs' / 'hipo4')