diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43e008352..5d000da15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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' }} diff --git a/.gitignore b/.gitignore index a75b1a501..aa188eab6 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ chameleon-tree # overrides !doc/gen/logo.png !doc/gen/logo_small.png +!doc/gen/mermaid/*.png # misc. artifacts .DS_Store diff --git a/bind/python/iguana_ex_python_00_run_functions.py b/bind/python/iguana_ex_python_00_run_functions.py index 9700385a3..ff013f341 100755 --- a/bind/python/iguana_ex_python_00_run_functions.py +++ b/bind/python/iguana_ex_python_00_run_functions.py @@ -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 diff --git a/doc/gen/Doxyfile.in b/doc/gen/Doxyfile.in index 55b605b3e..f8bbf4469 100644 --- a/doc/gen/Doxyfile.in +++ b/doc/gen/Doxyfile.in @@ -285,14 +285,18 @@ TAB_SIZE = 4 ALIASES = # algorithm properties -ALIASES += brief_algo="@brief **%Algorithm:** " -ALIASES += begin_doc_algo{2|}="\par %Algorithm Name:^^   `%\1`\xrefitem algo \"Algorithm Type:\" \"List of all Algorithms\" \2 \par %Algorithm Inputs and Outputs:^^" -ALIASES += input_banks{1}="" -ALIASES += output_banks{1}="" -ALIASES += end_doc="
**Input Banks**`\1`
**Output Banks**`\1`
" +ALIASES += algo_brief{1}="@brief **%Algorithm:** \1^^@xrefitem algo \"\" \"List of Algorithms\" \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); \ref created_banks \"click here for a description of all created banks\".^^- 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.^^^^" # 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:^^" ALIASES += config_param{3|}="" +ALIASES += end_doc="
NameTypeDescription
`\1``\2`\3
^^" +# 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**" @@ -307,7 +311,6 @@ 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 @@ -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 @@ -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 @@ -970,6 +973,7 @@ WARN_LOGFILE = INPUT = @top_srcdir@/src/ \ @top_builddir@/src/iguana/algorithms \ @top_builddir@/src/iguana/bankdefs \ + @top_builddir@/src/iguana/bankdefs/BankDefs.md \ @top_srcdir@/bind/ \ @top_srcdir@/doc/gen/ \ @top_srcdir@/doc/gen/mainpage.md \ @@ -1086,7 +1090,8 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = @top_srcdir@/doc/gen/logo.png +IMAGE_PATH = @top_srcdir@/doc/gen/logo.png \ + @top_srcdir@/doc/gen/mermaid/flowchart_usage.png # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -2545,7 +2550,7 @@ COLLABORATION_GRAPH = NO # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. -GROUP_GRAPHS = YES +GROUP_GRAPHS = NO # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling diff --git a/doc/gen/mainpage.md b/doc/gen/mainpage.md index 16bab584d..e05b7b363 100644 --- a/doc/gen/mainpage.md +++ b/doc/gen/mainpage.md @@ -7,6 +7,7 @@ This documentation shows how to use the Iguana algorithms. For more documentatio | --- | --- | | @spacer [List of Algorithms](#algo) @spacer | @spacer [Examples of Code](#mainpageExample) @spacer | | @spacer [List of Action Functions](#action) @spacer | @spacer [Configuring Algorithms](#mainpageConfiguring) @spacer | +| @spacer [Banks Created by Iguana](#created_banks) @spacer | |

@@ -22,26 +23,49 @@ To see Iguana algorithms used in the context of analysis code, with **various la | ^ | Includes guidance on how to build Iguana with your C++ code | | @spacer [Python examples](#examples_python) @spacer | For users of Python tools, such as `PyROOT` | | @spacer [Fortran examples](#examples_fortran) @spacer | See also the [Fortran usage guide](#fortran_usage_guide) | - -In summary, the general way to use an Iguana algorithm is as follows; see examples and documentation below for more details. - -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](#mainpageConfiguring) -3. Start each algorithm, which "locks in" its configuration: - - call iguana::Algorithm::Start(hipo::banklist&) if you use [**the HIPO API**](https://github.com/gavalian/hipo) and [Common Functions](#mainpageCommon) - - call iguana::Algorithm::Start() otherwise, _i.e._, if you use [Action Functions](#mainpageAction) -4. In the event loop, run the algorithm: - - call iguana::Algorithm::Run(hipo::banklist&) const if you use Common Functions - - call the Action Function(s) otherwise -5. Proceed with your analysis - - if you called iguana::Algorithm::Run(hipo::banklist&) const, the banks will be filtered, transformed, and/or created - - if you called action functions, you will need to handle their output yourself +| @spacer **Java** @spacer | We do not yet support Java, but we plan to soon | + +

+ +## Usage Summary + +In summary, the general way to use an Iguana algorithm is the following: + +1. Decide how you will use Iguana with your analysis code (see also [the flowchart](#mainpageFlowchart), just below) + - Use [Iguana Common Functions](#mainpageCommon) if your analysis uses: + - The [**HIPO C++ API**](https://github.com/gavalian/hipo) + - [**`clas12root`**](https://github.com/JeffersonLab/clas12root) + - Our [Our Python bindings](#examples_python) + - Use [Iguana Action Functions](#mainpageAction) otherwise +2. Decide [which algorithms](#algo) you want to use +3. Check each algorithm configuration, and [adjust it if you prefer](#mainpageConfiguring) +4. Start each algorithm, which "locks in" its configuration: + - if using Common Functions: + - call @link iguana::Algorithm::Start() `Start()` @endlink if you will be using individual `hipo::bank` objects (_e.g._, if you are using `clas12root`) + - call @link iguana::Algorithm::Start(hipo::banklist&) `Start(hipo::banklist&)` @endlink if you use `hipo::banklist` + - **Tip:** `hipo::banklist` users may use @link iguana::AlgorithmSequence `AlgorithmSequence` @endlink to help run a _sequence_ of algorithms + - if using Action Functions: + - call @link iguana::Algorithm::Start() `Start()` @endlink +5. In the event loop, Run the algorithm for each event: + - if using Common Functions, either: + - call specialized `Run` functions, which act on individual `hipo::bank` objects and are unique for each algorithm; users of `clas12root` versions _newer_ than `1.8.6` should use this + - call @link iguana::Algorithm::Run(hipo::banklist&) const `Run(hipo::banklist&)` @endlink if you use `hipo::banklist` + - call the [Action Function(s)](#action) otherwise +6. Proceed with your analysis + - if you called a `Run` function, 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](#mainpageRunning) for more details -6. After your event loop, stop each algorithm by calling iguana::Algorithm::Stop() +7. After your event loop, stop each algorithm by calling @link iguana::Algorithm::Stop() `Stop()` @endlink Please let the maintainers know if your use case is not covered in any examples or if you need any help. +@anchor mainpageFlowchart +### Flowchart for Usage + +Here is a flowchart, illustrating the above: + + +


@@ -52,60 +76,22 @@ An Iguana algorithm is a function that maps input HIPO bank data to output data. | Type | Description | Example | | --- | --- | --- | -| **Filter** | Filters rows of a bank based on a Boolean condition | `iguana::clas12::FiducialFilter`: filter particles with fiducial cuts | -| **Transformer** | Transform (mutate) elements of a bank | `iguana::clas12::MomentumCorrection`: correct particle momenta | -| **Creator** | Create a new bank | `iguana::physics::InclusiveKinematics`: calculate inclusive kinematics @latex{x}, @latex{Q^2}, _etc_. | +| **Filter** | Filters rows of a bank based on a Boolean condition | @link iguana::clas12::FiducialFilter @endlink: filter particles with fiducial cuts | +| **Transformer** | Transform (mutate) elements of a bank | @link iguana::clas12::MomentumCorrection @endlink: correct particle momenta | +| **Creator** | Create a new bank | @link iguana::physics::InclusiveKinematics @endlink: calculate inclusive kinematics @latex{x}, @latex{Q^2}, _etc_. | 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 mainpageRunning ## How to Run Algorithms -Algorithms may be run using either: +Algorithms may be run using one of the following; see [the usage flowchart](#mainpageFlowchart) for help deciding what to do. - [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 @@ -122,22 +108,30 @@ All algorithms have the following **Common Functions**, which may be used in ana | Common Functions || | --- | --- | -| iguana::Algorithm::Start(hipo::banklist&) | To be called before event processing | -| iguana::Algorithm::Run(hipo::banklist&) const | To be called for every event | -| iguana::Algorithm::Stop() | To be called after event processing | - -The algorithms are implemented in C++ classes which inherit from the base class `iguana::Algorithm`; these three class methods are overridden in each algorithm. - -The iguana::Algorithm::Run(hipo::banklist&) const function should be called on every event; the general consequence, that is, how the user should handle the algorithm's results, depends on the +| `Start` | To be called before event processing | +| `Run` | To be called for every event | +| `Stop` | To be called after event processing | + +- for `Start`: + - call @link iguana::Algorithm::Start() `Start()` @endlink if you will be using individual `hipo::bank` objects (_e.g._, if you are using `clas12root`) + - call @link iguana::Algorithm::Start(hipo::banklist&) `Start(hipo::banklist&)` @endlink if you use `hipo::banklist` + - **Tip:** `hipo::banklist` users may use @link iguana::AlgorithmSequence `AlgorithmSequence` @endlink to help run a _sequence_ of algorithms +- for `Run`: + - call specialized `Run` functions, which act on individual `hipo::bank` objects and are unique for each algorithm; users of `clas12root` versions _newer_ than `1.8.6` should use this + - call @link iguana::Algorithm::Run(hipo::banklist&) const `Run(hipo::banklist&)` @endlink if you use `hipo::banklist` +- the `Stop` function is the same for either case + +The `Run` function should be called on every event; the general consequence, that is, how the user should handle the algorithm's results, depends on the algorithm type:
Type How to handle the results
**Filter** -The involved banks will be filtered. -To iterate over _filtered_ bank rows, use the function `hipo::bank::getRowList`, -rather than iterating from `0` up to `hipo::bank::getRows()`; for example, given a -bank object named `particle_bank`: +The involved banks will be filtered. To iterate over _filtered_ bank rows, use +the function `hipo::bank::getRowList`, rather than iterating from `0` up to +`hipo::bank::getRows()`. +
+For example, given a bank object named `particle_bank`: ```cpp for(auto const& row : particle_bank.getRowList()) { // loops over only the rows which pass the filter @@ -150,24 +144,32 @@ for(int row = 0; row < particle_bank.getRows(); row++) { ```
**Transformer** -The transformed `hipo::bank` will simply have -the relevant bank elements changed. For example, momentum correction algorithms -typically change the particle momentum components. +The transformed `hipo::bank` will simply have the relevant bank elements changed. +
+For example, momentum correction algorithms typically change the particle momentum components.
**Creator** -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(hipo::banklist&), so that you may begin to reference it; it is helpful to -use `hipo::getBanklistIndex` (see [the examples for details](#mainpageExample)). +Creator-type algorithms will create a new `hipo::bank` object, appending +it to the end of the input `hipo::banklist`. +
    +
  • [Click here for descriptions of all created banks](#created_banks)
  • +
  • An initial version is created upon calling `Start(hipo::banklist&)`, so that you may begin to reference it
  • +
      +
    • It is helpful to use `hipo::getBanklistIndex`, to get the created bank index within the `hipo::banklist`
    • +
    • See [the examples for details](#mainpageExample)
    • +
    +
-Internally, iguana::Algorithm::Run(hipo::banklist&) const calls Action Functions, which are described in the next section. +Internally, `Run(hipo::banklist&)` calls Action Functions, which are described in the next section.
@anchor mainpageAction ### Action Functions +@todo **Unfortunately, some algorithms are not yet fully supported by action functions, but we can try to add support upon request.** + The action functions do the _real_ work of the algorithm, and are meant to be easily callable from _any_ analysis, even if HIPO banks are not directly used. These functions are unique to each algorithm, so view the algorithm @@ -176,8 +178,8 @@ documentation for details, or browse the full list: - [List of all Action Functions](#action) @note To start an algorithm in order to use action functions, you may `Start` it without a bank list, that is, call -iguana::Algorithm::Start() instead of iguana::Algorithm::Start(hipo::banklist&). Stopping the algorithm is the same -regardless of whether you use action functions or not: call iguana::Algorithm::Stop(). +`Start()` instead of `Start(hipo::banklist&)`. Stopping the algorithm is the same +regardless of whether you use action functions or not: call `Stop()`. Action function parameters are supposed to be _simple_: numbers or lists of numbers, preferably obtainable _directly_ from HIPO bank rows. The return type of an action function depends on the algorithm type: @@ -205,8 +207,8 @@ To maximize compatibility with user analysis code, these functions are overloade Finally, it is important to note _when_ to call action functions in the analysis code. For example, some action functions should be called _once_ every event, while others should be called for every particle of the `REC::Particle` bank. Some algorithms have _both_ of these types of functions, for example: -- `iguana::clas12::ZVertexFilter::PrepareEvent`, which must be called first, at the beginning of an event's analysis -- `iguana::clas12::ZVertexFilter::Filter`, which must be called on every particle, using the _output_ of `PrepareEvent` in one of its input parameters +- @link iguana::clas12::ZVertexFilter::PrepareEvent @endlink, which must be called first, at the beginning of an event's analysis +- @link iguana::clas12::ZVertexFilter::Filter @endlink, which must be called on every particle, using the _output_ of `PrepareEvent` in one of its input parameters It is highly recommended to read an algorithm's documentation carefully before using it, _especially_ if you use action functions. @@ -223,7 +225,7 @@ Many algorithms are configurable. An algorithm's configuration parameters and th Iguana provides a few ways to configure algorithms; in general, you may either: - use YAML for configuration that gets applied at runtime, _i.e._, no need to recompile -- use `iguana::Algorithm::SetOption` to configure an algorithm more directly, which may require recompilation, depending on how you use Iguana algorithms +- use @link iguana::Algorithm::SetOption @endlink to configure an algorithm more directly, which may require recompilation, depending on how you use Iguana algorithms The default configuration YAML files are installed in the `etc/` subdirectory of the Iguana installation. If you have set the Iguana environment variables using, _e.g._ `source this_iguana.sh`, or if you are using the version of Iguana installed on `ifarm`, you will have the environment variable `$IGUANA_CONFIG_PATH` set to include this `etc/` directory. @@ -271,8 +273,8 @@ physics::AlgorithmB ``` Once you have a YAML file, you just need to tell each algorithm to use it: -- use `iguana::Algorithm::SetConfigFile` on each algorithm -- if you use `iguana::AlgorithmSequence`, use `iguana::AlgorithmSequence::SetConfigFileForEachAlgorithm` to use this file for each algorithm in the algorithm sequence +- use @link iguana::Algorithm::SetConfigFile @endlink on each algorithm +- if you use @link iguana::AlgorithmSequence @endlink, use @link iguana::AlgorithmSequence::SetConfigFileForEachAlgorithm @endlink to use this file for each algorithm in the algorithm sequence ### Option 2: Copy the default directory, and modify @@ -293,4 +295,4 @@ setenv IGUANA_CONFIG_PATH `pwd`/my_iguana_config:$IGUANA_CONFIG_PATH # tcsh or The algorithms will then search `my_iguana_config` for the configuration before searching the default paths. You may add multiple paths, if needed. Paths which appear first in `$IGUANA_CONFIG_PATH` will be prioritized when the algorithm searches for configuration parameters; this behavior is similar to that of `$PATH` or `$LD_LIBRARY_PATH`. Note that `source this_iguana.sh` will _overwrite_ `$IGUANA_CONFIG_PATH`. -2. Use `iguana::Algorithm::SetConfigDirectory` instead of prepending `$IGUANA_CONFIG_PATH` (and if you use an algorithm sequence, use `iguana::AlgorithmSequence::SetConfigDirectoryForEachAlgorithm`) +2. Use @link iguana::Algorithm::SetConfigDirectory @endlink instead of prepending `$IGUANA_CONFIG_PATH` (and if you use an algorithm sequence, use @link iguana::AlgorithmSequence::SetConfigDirectoryForEachAlgorithm @endlink) diff --git a/doc/gen/mermaid/build.sh b/doc/gen/mermaid/build.sh new file mode 100755 index 000000000..902dac79b --- /dev/null +++ b/doc/gen/mermaid/build.sh @@ -0,0 +1,9 @@ +#!/usr/bin/bash +# requires `mermaid-cli` +# NOTE: this is not automated by `meson`, to avoid introducing `mermaid-cli` dependency; +# this is okay, since we do not expect this figure to change often +exec mmdc \ + --backgroundColor transparent \ + --width 1600 \ + --input flowchart_usage.mmd \ + --output flowchart_usage.png diff --git a/doc/gen/mermaid/flowchart_usage.mmd b/doc/gen/mermaid/flowchart_usage.mmd new file mode 100644 index 000000000..929ee3a6f --- /dev/null +++ b/doc/gen/mermaid/flowchart_usage.mmd @@ -0,0 +1,76 @@ +--- +config: + theme: "base" + themeVariables: + fontSize: "20px" + fontFamily: "arial" + edgeLabelBackground: "#ff8" + lineColor: "#880" + tertiaryColor: "#cfc" + primaryBorderColor: "#888" +--- +flowchart TB + + classDef dec fill:#8f8,color:black + classDef cftn fill:#8ff,color:black + classDef sftn fill:#f8f,color:black + classDef aftn fill:#f88,color:black + classDef lang fill:#ff8,color:black + + %% language nodes + subgraph "Start Here" + language{{"What language do you want to use?"}}:::dec + cpp([C++]):::lang + python([Python]):::lang + fortran([Fortran]):::lang + java([Java]):::lang + end + + %% decision nodes + clas12root{{"Do you use clas12root, a version newer than 1.8.6?"}}:::dec + hipo_cpp{{"Do you use the HIPO C++ API directly, e.g., hipo::bank objects?"}}:::dec + hipo_cppyy{{"Do you use cppyy bindings to the HIPO C++ API? (see our Python examples)"}}:::dec + hipo_banklist{{"Do you use hipo::banklist?"}}:::dec + + %% function nodes + %% common function nodes are prefixed with c_ + %% action function nodes are prefixed with a_ + subgraph "before events" + c_start_no_arg["Start()"]:::cftn + c_start_banklist["Start(banklist)"]:::cftn + a_start["Start()"]:::aftn + end + subgraph "for each event" + c_run_banks["Run(bank1, bank2, ...)"]:::cftn + c_run_banklist["Run(banklist)"]:::cftn + a_action["call action function(s)"]:::aftn + end + subgraph "     after events" + stop["Stop()"]:::sftn + end + todo["Not yet supported"]:::lang + fortran_note["You will be using C wrapper functions (see documentation)"]:::lang + + %% edges + language ==> cpp ===> clas12root + language ==> python ===> hipo_cppyy + language ==> fortran ===> fortran_note ==> a_start + language ==> java ===> todo + + clas12root == | YES | ===> c_start_no_arg + clas12root == | NO | ===> hipo_cpp + + hipo_cpp == | YES | ===> hipo_banklist + hipo_cpp == | NO | ===> a_start + + hipo_cppyy == | YES | ===> hipo_banklist + hipo_cppyy == | NO | ===> a_start + + hipo_banklist == | NO | ===> c_start_no_arg + hipo_banklist == | YES | ===> c_start_banklist + + c_start_no_arg ==> c_run_banks ==> stop + c_start_banklist ==> c_run_banklist ==> stop + a_start ==> a_action ==> stop + + diff --git a/doc/gen/mermaid/flowchart_usage.png b/doc/gen/mermaid/flowchart_usage.png new file mode 100644 index 000000000..aff2faf1b Binary files /dev/null and b/doc/gen/mermaid/flowchart_usage.png differ diff --git a/examples/iguana_ex_cpp_00_run_functions.cc b/examples/iguana_ex_cpp_00_run_functions.cc index f5758560d..8bb100335 100644 --- a/examples/iguana_ex_cpp_00_run_functions.cc +++ b/examples/iguana_ex_cpp_00_run_functions.cc @@ -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] @@ -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; diff --git a/examples/iguana_ex_cpp_00_run_functions_with_banks.cc b/examples/iguana_ex_cpp_00_run_functions_with_banks.cc new file mode 100644 index 000000000..c781564d3 --- /dev/null +++ b/examples/iguana_ex_cpp_00_run_functions_with_banks.cc @@ -0,0 +1,128 @@ +/// @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 +#include +#include +#include + +/// 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>("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; continue + // to the next event if any of the Run functions return `false`, which happens + // if, for example, no particles pass a filter + if(!algo_eventbuilder_filter.Run(bank_particle)) continue; + if(!algo_sector_finder.Run(bank_particle, bank_track, bank_calorimeter, bank_scintillator, bank_sector)) continue; + if(!algo_momentum_correction.Run(bank_particle, bank_sector, bank_config)) continue; + + // 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; +} diff --git a/examples/iguana_ex_cpp_01_action_functions.cc b/examples/iguana_ex_cpp_01_action_functions.cc index 568ff7dcd..66ee1c3a7 100644 --- a/examples/iguana_ex_cpp_01_action_functions.cc +++ b/examples/iguana_ex_cpp_01_action_functions.cc @@ -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; } diff --git a/examples/meson.build b/examples/meson.build index d3614dd60..b564c3b62 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -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' ], diff --git a/src/iguana/algorithms/Algorithm.cc b/src/iguana/algorithms/Algorithm.cc index d5cc8da60..cf6c5f99b 100644 --- a/src/iguana/algorithms/Algorithm.cc +++ b/src/iguana/algorithms/Algorithm.cc @@ -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"); @@ -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(), ", ")); } @@ -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 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 @@ -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()) @@ -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()) diff --git a/src/iguana/algorithms/Algorithm.h b/src/iguana/algorithms/Algorithm.h index c84f4f0f6..6b81524e1 100644 --- a/src/iguana/algorithms/Algorithm.h +++ b/src/iguana/algorithms/Algorithm.h @@ -64,9 +64,13 @@ namespace iguana { /// use this method if you intend to use "action functions" instead of `Algorithm::Run`. void Start(); - /// @brief Run this algorithm for an event. + /// @brief **Run Function:** Process an event's `hipo::banklist` /// @param banks the list of banks to process - virtual void Run(hipo::banklist& banks) const = 0; + /// @returns a boolean value, which is typically used to decide whether or not to continue analyzing an event, _i.e._, it can be used + /// as an _event-level_ filter; not all algorithms use or need this feature; see the algorithm's more specialized `Run` functions, + /// which have `hipo::bank` parameters + /// @see Specialized `%Run` function(s) above/below; they take individual `hipo::bank` objects as parameters, and their documentation explains which banks are used by this algorithm and how. + virtual bool Run(hipo::banklist& banks) const = 0; /// @brief Finalize this algorithm after all events are processed. virtual void Stop() = 0; @@ -136,6 +140,29 @@ namespace iguana { /// @param name the directory name void SetConfigDirectory(std::string const& name); + /// Get the list of created bank names, for creator-type algorithms + /// @see `Algorithm::GetCreatedBankName` for algorithms which create only one bank + /// @returns the list of new bank names + std::vector GetCreatedBankNames() const noexcept(false); + + /// Get the created bank name, for creator-type algorithms which create only one new bank + /// @see `Algorithm::GetCreatedBankNames` for algorithms which create more than one new bank + /// @returns the new bank name + std::string GetCreatedBankName() const noexcept(false); + + /// Get a bank created by a creator-type algorithm. The bank must be defined in `src/iguana/bankdefs/iguana.json`. + /// Use this function if you intend to use specialized `Run(hipo::bank&, ...)` functions, where one of its parameters + /// is a (reference to) a created bank. + /// @param [in] bank_name the created bank name, which is only needed if the algorithm creates more than one bank + /// @returns the new bank + hipo::bank GetCreatedBank(std::string const& bank_name = "") const noexcept(false); + + /// Get a bank schema created by a creator-type algorithm. The bank must be defined in `src/iguana/bankdefs/iguana.json`. + /// @see `Algorithm::GetCreatedBank` + /// @param [in] bank_name the created bank name, which is only needed if the algorithm creates more than one bank + /// @returns the new bank schema + hipo::schema GetCreatedBankSchema(std::string const& bank_name = "") const noexcept(false); + protected: // methods /// Parse YAML configuration files. Sets `m_yaml_config`. @@ -168,13 +195,13 @@ namespace iguana { /// @param banks the banks to show /// @param message if specified, print a header message /// @param level the log level - void ShowBanks(hipo::banklist& banks, std::string_view message = "", Logger::Level const level = Logger::trace) const; + void ShowBanks(hipo::banklist const& banks, std::string_view message = "", Logger::Level const level = Logger::trace) const; /// Dump a single bank /// @param bank the bank to show /// @param message if specified, print a header message /// @param level the log level - void ShowBank(hipo::bank& bank, std::string_view message = "", Logger::Level const level = Logger::trace) const; + void ShowBank(hipo::bank const& bank, std::string_view message = "", Logger::Level const level = Logger::trace) const; /// Get an option from the option cache /// @param key the key name associated with this option @@ -246,28 +273,36 @@ namespace iguana { AlgorithmFactory() = delete; /// Register an algorithm with a unique name. Algorithms register themselves by calling this function. - /// @param name the name of the algorithm (not equivalent to `Object::m_name`) + /// @param algo_name the name of the algorithm (not equivalent to `Object::m_name`) /// @param creator the creator function /// @param new_banks if this algorithm creates *new* banks, list them here /// @returns true if the algorithm has not yet been registered - static bool Register(std::string const& name, algo_creator_t creator, std::vector const new_banks = {}) noexcept; + static bool Register(std::string const& algo_name, algo_creator_t creator, std::vector const new_banks = {}) noexcept; /// Create an algorithm. Throws an exception if the algorithm cannot be created - /// @param name the name of the algorithm, which was used as an argument in the `AlgorithmFactory::Register` call + /// @param algo_name the name of the algorithm, which was used as an argument in the `AlgorithmFactory::Register` call /// @returns the algorithm instance - static algo_t Create(std::string const& name) noexcept(false); + static algo_t Create(std::string const& algo_name) noexcept(false); - /// Check if a bank is created by an algorithm - /// @param bank_name the name of the bank - /// @returns the list of algorithms which create it, if any - static std::optional> QueryNewBank(std::string const& bank_name) noexcept; + /// Get list of creator-type algorithms which create a particular bank + /// @param bank_name the bank name + /// @returns the list of algorithms which create the bank, if any + static std::optional> GetCreatorAlgorithms(std::string const& bank_name) noexcept; + + /// Get list of banks which are created by a particular creator-type algorithm + /// @param algo_name the algorithm name + /// @returns the list of banks which are created by the algorithm, if any + static std::optional> GetCreatedBanks(std::string const& algo_name) noexcept(false); private: /// Association between the algorithm names and their creators static std::unordered_map s_creators; - /// Association between a created bank and its creator algorithms - static std::unordered_map> s_created_banks; + /// Association from a created bank to the creator-type algorithms that create it + static std::unordered_map> s_bank_to_algos; + + /// Association from a creator-type algorithm to the banks it creates + static std::unordered_map> s_algo_to_banks; }; } diff --git a/src/iguana/algorithms/AlgorithmFactory.cc b/src/iguana/algorithms/AlgorithmFactory.cc index b0ab258b6..6c8bbb855 100644 --- a/src/iguana/algorithms/AlgorithmFactory.cc +++ b/src/iguana/algorithms/AlgorithmFactory.cc @@ -3,33 +3,43 @@ namespace iguana { std::unordered_map AlgorithmFactory::s_creators; - std::unordered_map> AlgorithmFactory::s_created_banks; + std::unordered_map> AlgorithmFactory::s_bank_to_algos; + std::unordered_map> AlgorithmFactory::s_algo_to_banks; - bool AlgorithmFactory::Register(std::string const& name, algo_creator_t creator, std::vector const new_banks) noexcept + bool AlgorithmFactory::Register(std::string const& algo_name, algo_creator_t creator, std::vector const new_banks) noexcept { - if(auto it = s_creators.find(name); it == s_creators.end()) { - s_creators.insert({name, creator}); + if(auto it = s_creators.find(algo_name); it == s_creators.end()) { + s_creators.insert({algo_name, creator}); + s_algo_to_banks.insert({algo_name, new_banks}); for(auto const& new_bank : new_banks) { - if(auto it = s_created_banks.find(new_bank); it == s_created_banks.end()) - s_created_banks.insert({new_bank, {}}); - s_created_banks.at(new_bank).push_back(name); + if(auto it = s_bank_to_algos.find(new_bank); it == s_bank_to_algos.end()) + s_bank_to_algos.insert({new_bank, {}}); + s_bank_to_algos.at(new_bank).push_back(algo_name); } return true; } return false; } - algo_t AlgorithmFactory::Create(std::string const& name) + algo_t AlgorithmFactory::Create(std::string const& algo_name) { - if(auto it = s_creators.find(name); it != s_creators.end()) + if(auto it = s_creators.find(algo_name); it != s_creators.end()) return it->second(); - throw std::runtime_error(fmt::format("AlgorithmFactory: algorithm with name {:?} does not exist", name)); + throw std::runtime_error(fmt::format("AlgorithmFactory: algorithm with name {:?} does not exist", algo_name)); } - std::optional> AlgorithmFactory::QueryNewBank(std::string const& bank_name) noexcept + std::optional> AlgorithmFactory::GetCreatorAlgorithms(std::string const& bank_name) noexcept { - if(auto it = s_created_banks.find(bank_name); it != s_created_banks.end()) + if(auto it = s_bank_to_algos.find(bank_name); it != s_bank_to_algos.end()) return it->second; return {}; } + + std::optional> AlgorithmFactory::GetCreatedBanks(std::string const& algo_name) noexcept(false) + { + if(auto it = s_algo_to_banks.find(algo_name); it != s_algo_to_banks.end()) + return it->second; + return {}; + } + } diff --git a/src/iguana/algorithms/AlgorithmSequence.cc b/src/iguana/algorithms/AlgorithmSequence.cc index a2da03954..6333da838 100644 --- a/src/iguana/algorithms/AlgorithmSequence.cc +++ b/src/iguana/algorithms/AlgorithmSequence.cc @@ -9,25 +9,30 @@ namespace iguana { for(auto const& algo : m_sequence) algo->Start(banks); } - void AlgorithmSequence::Run(hipo::banklist& banks) const + + bool AlgorithmSequence::Run(hipo::banklist& banks) const { - for(auto const& algo : m_sequence) - algo->Run(banks); + for(auto const& algo : m_sequence) { + if(!algo->Run(banks)) + return false; + } + return true; } + void AlgorithmSequence::Stop() { for(auto const& algo : m_sequence) algo->Stop(); } - void AlgorithmSequence::Add(std::string const& class_name, std::string const& instance_name) + void AlgorithmSequence::Add(std::string const& algo_class_name, std::string const& algo_instance_name) { - auto algo = AlgorithmFactory::Create(class_name); + auto algo = AlgorithmFactory::Create(algo_class_name); if(algo == nullptr) { - m_log->Error("algorithm '{}' does not exist", class_name); + m_log->Error("algorithm '{}' does not exist", algo_class_name); throw std::runtime_error("AlgorithmFactory cannot create non-existent algorithm"); } - algo->SetName(instance_name == "" ? class_name : instance_name); + algo->SetName(algo_instance_name == "" ? algo_class_name : algo_instance_name); Add(std::move(algo)); } @@ -60,6 +65,22 @@ namespace iguana { Algorithm::SetName(name); } + std::vector AlgorithmSequence::GetCreatedBankNames(std::string const& algo_instance_name) const noexcept(false) + { + if(auto it{m_algo_names.find(algo_instance_name)}; it != m_algo_names.end()) + return m_sequence[it->second]->GetCreatedBankNames(); + m_log->Error("cannot find algorithm '{}' in sequence", algo_instance_name); + throw std::runtime_error("GetCreatedBankNames failed"); + } + + std::string AlgorithmSequence::GetCreatedBankName(std::string const& algo_instance_name) const noexcept(false) + { + if(auto it{m_algo_names.find(algo_instance_name)}; it != m_algo_names.end()) + return m_sequence[it->second]->GetCreatedBankName(); + m_log->Error("cannot find algorithm '{}' in sequence", algo_instance_name); + throw std::runtime_error("GetCreatedBankName failed"); + } + void AlgorithmSequence::PrintSequence(Logger::Level level) const { m_log->Print(level, "algorithms in this sequence:"); diff --git a/src/iguana/algorithms/AlgorithmSequence.h b/src/iguana/algorithms/AlgorithmSequence.h index f2cca6bb3..de3e00912 100644 --- a/src/iguana/algorithms/AlgorithmSequence.h +++ b/src/iguana/algorithms/AlgorithmSequence.h @@ -7,7 +7,12 @@ namespace iguana { /// @brief An algorithm that can run a sequence of algorithms /// /// The `Start`, `Run`, and `Stop` methods will sequentially call the corresponding algorithms' methods, - /// in the order the algorithms were added to the sequence by `AlgorithmSequence::Add`. + /// in the order the algorithms were added to the sequence by `AlgorithmSequence::Add`. If an algorithm's + /// `Run` function returns false, then `AlgorithmSequence`'s `Run` function will stop and return `false`. + /// + /// This algorithm requires the use of `hipo::banklist`; there are neither `Run` functions which take + /// individual `hipo::bank` parameters nor action functions. If you do not use `hipo::banklist`, you + /// should use individual algorithms instead of this sequencing algorithm. class AlgorithmSequence : public Algorithm { @@ -16,7 +21,7 @@ namespace iguana { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; /// Create and add an algorithm to the sequence, by name. @@ -25,10 +30,10 @@ namespace iguana { /// @code /// Add("iguana::MyAlgorithm", "my_algorithm_name"); /// @endcode - /// @param class_name the name of the algorithm class - /// @param instance_name a user-specified unique name for this algorithm instance; - /// if not specified, `class_name` will be used - void Add(std::string const& class_name, std::string const& instance_name = ""); + /// @param algo_class_name the name of the algorithm class + /// @param algo_instance_name a user-specified unique name for this algorithm instance; + /// if not specified, `algo_class_name` will be used + void Add(std::string const& algo_class_name, std::string const& algo_instance_name = ""); /// Create and add an algorithm to the sequence. /// @@ -36,15 +41,15 @@ namespace iguana { /// @code /// Add("my_algorithm_name"); /// @endcode - /// @param instance_name a user-specified unique name for this algorithm instance; + /// @param algo_instance_name a user-specified unique name for this algorithm instance; /// if not specified, the class name will be used template - void Add(std::string_view instance_name = "") + void Add(std::string_view algo_instance_name = "") { - if(instance_name == "") + if(algo_instance_name == "") Add(std::make_unique()); else - Add(std::make_unique(instance_name)); + Add(std::make_unique(algo_instance_name)); } /// Add an existing algorithm to the sequence. The `AlgorithmSequence` instance will take ownership of the algorithm @@ -63,32 +68,44 @@ namespace iguana { /// @code /// Get("my_algorithm_name"); /// @endcode - /// @param instance_name the instance name of the algorithm + /// @param algo_instance_name the instance name of the algorithm /// @return a reference to the algorithm template - ALGORITHM* Get(std::string const& instance_name) + ALGORITHM* Get(std::string const& algo_instance_name) { - if(auto it{m_algo_names.find(instance_name)}; it != m_algo_names.end()) + if(auto it{m_algo_names.find(algo_instance_name)}; it != m_algo_names.end()) return dynamic_cast(m_sequence[it->second].get()); - m_log->Error("cannot find algorithm '{}' in sequence", instance_name); + m_log->Error("cannot find algorithm '{}' in sequence", algo_instance_name); throw std::runtime_error("cannot Get algorithm"); } /// Set an algorithm option /// @see `Algorithm::SetOption` - /// @param algo_name the algorithm instance name + /// @param algo_instance_name the algorithm instance name /// @param key the option name /// @param val the option value template - void SetOption(std::string const& algo_name, std::string const& key, const OPTION_TYPE val) + void SetOption(std::string const& algo_instance_name, std::string const& key, const OPTION_TYPE val) { - Get(algo_name)->SetOption(key, val); + Get(algo_instance_name)->SetOption(key, val); } /// Set the name of this sequence /// @param name the new name void SetName(std::string_view name); + /// Get the list of created bank names, for creator-type algorithms + /// @see `AlgorithmSequence::GetCreatedBankName` for algorithms which create only one bank + /// @param algo_instance_name the algorithm instance name + /// @returns the list of new bank names + std::vector GetCreatedBankNames(std::string const& algo_instance_name) const noexcept(false); + + /// Get the created bank name, for creator-type algorithms which create only one new bank + /// @see `AlgorithmSequence::GetCreatedBankNames` for algorithms which create more than one new bank + /// @param algo_instance_name the algorithm instance name + /// @returns the new bank name + std::string GetCreatedBankName(std::string const& algo_instance_name) const noexcept(false); + /// Print the names of the algorithms in this sequence /// @param level the log level of the printout void PrintSequence(Logger::Level level = Logger::info) const; diff --git a/src/iguana/algorithms/TypeDefs.h b/src/iguana/algorithms/TypeDefs.h index f280835d8..18a9c0183 100644 --- a/src/iguana/algorithms/TypeDefs.h +++ b/src/iguana/algorithms/TypeDefs.h @@ -132,6 +132,12 @@ namespace iguana { ////////////////////////////////////////////////////////////////////////////////// + /// @param sec the sector number to check + /// @returns `true` if the sector number is a valid sector number + inline bool IsValidSector(int const& sec) { + return sec >= 1 && sec <= 6; + } + /// detector IDs; this is a _copy_ of `coatjava`'s `DetectorType` `enum` enum DetectorType { UNDEFINED = 0, diff --git a/src/iguana/algorithms/Validator.h b/src/iguana/algorithms/Validator.h index 38bfe1e38..a487bec0a 100644 --- a/src/iguana/algorithms/Validator.h +++ b/src/iguana/algorithms/Validator.h @@ -36,9 +36,9 @@ namespace iguana { } virtual ~Validator() {} - void Start(hipo::banklist& banks) override{}; - void Run(hipo::banklist& banks) const override{}; - void Stop() override{}; + void Start(hipo::banklist& banks) override {} + bool Run(hipo::banklist& banks) const override { return true; } + void Stop() override {} /// Set this validator's output directory /// @param output_dir the output directory diff --git a/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.cc b/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.cc index cc4079e12..401822d68 100644 --- a/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.cc +++ b/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.cc @@ -31,11 +31,19 @@ namespace iguana::clas12 { i_ecout_energy = result_schema.getEntryOrder("ecout_energy"); } - void CalorimeterLinker::Run(hipo::banklist& banks) const + bool CalorimeterLinker::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_calorimeter, "REC::Calorimeter"), + GetBank(banks, b_result, "REC::Particle::Calorimeter")); + } + + bool CalorimeterLinker::Run( + hipo::bank const& bank_particle, + hipo::bank const& bank_calorimeter, + hipo::bank& bank_result) const { - auto& bank_particle = GetBank(banks, b_particle, "REC::Particle"); - auto& bank_calorimeter = GetBank(banks, b_calorimeter, "REC::Calorimeter"); - auto& bank_result = GetBank(banks, b_result, "REC::Particle::Calorimeter"); ShowBank(bank_particle, Logger::Header("INPUT PARTICLE BANK")); ShowBank(bank_calorimeter, Logger::Header("INPUT CALORIMETER BANK")); @@ -124,6 +132,7 @@ namespace iguana::clas12 { bank_result.putFloat(i_ecout_energy, row_particle, link_particle.ecout_energy); } ShowBank(bank_result, Logger::Header("CREATED BANK")); + return true; } void CalorimeterLinker::Stop() diff --git a/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.h b/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.h index faa2978ab..0c1bbcd60 100644 --- a/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.h +++ b/src/iguana/algorithms/clas12/CalorimeterLinker/Algorithm.h @@ -4,19 +4,13 @@ namespace iguana::clas12 { - /// @brief_algo Link particle bank to bank `REC::Calorimeter` - /// - /// @begin_doc_algo{clas12::CalorimeterLinker | Creator} - /// @input_banks{REC::Particle, REC::Calorimeter} - /// @output_banks{%REC::Particle::Calorimeter} - /// @end_doc + /// @algo_brief{Link particle bank to bank `REC::Calorimeter`} + /// @algo_type_creator /// /// This algorithm reads `REC::Calorimeter` and produces a new bank, `REC::Particle::Calorimeter`, /// to make it easier to access commonly used `REC::Calorimeter` information for each particle. /// /// If this algorithm does not provide information you need, ask the maintainers or open a pull request. - /// - /// @creator_note class CalorimeterLinker : public Algorithm { @@ -25,9 +19,19 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] bank_particle `REC::Particle` + /// @param [in] bank_calorimeter `REC::Calorimeter` + /// @param [out] bank_result `REC::Particle::Calorimeter`, which will be created + /// @run_function_returns_true + bool Run( + hipo::bank const& bank_particle, + hipo::bank const& bank_calorimeter, + hipo::bank& bank_result) const; + private: /// `hipo::banklist` indices diff --git a/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.cc b/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.cc index 7d4fa5b84..2863c103c 100644 --- a/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.cc +++ b/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.cc @@ -16,12 +16,13 @@ namespace iguana::clas12 { } - void EventBuilderFilter::Run(hipo::banklist& banks) const + bool EventBuilderFilter::Run(hipo::banklist& banks) const { + return Run(GetBank(banks, b_particle, "REC::Particle")); + } - // get the banks - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - + bool EventBuilderFilter::Run(hipo::bank& particleBank) const + { // dump the bank ShowBank(particleBank, Logger::Header("INPUT PARTICLES")); @@ -35,6 +36,9 @@ namespace iguana::clas12 { // dump the modified bank ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); + + // return false if everything is filtered out + return ! particleBank.getRowList().empty(); } diff --git a/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.h b/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.h index 954b52538..aeb2706e7 100644 --- a/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/EventBuilderFilter/Algorithm.h @@ -4,12 +4,8 @@ namespace iguana::clas12 { - /// @brief_algo Filter the `REC::Particle` (or similar) bank by PID from the Event Builder - /// - /// @begin_doc_algo{clas12::EventBuilderFilter | Filter} - /// @input_banks{REC::Particle} - /// @output_banks{REC::Particle} - /// @end_doc + /// @algo_brief{Filter the `REC::Particle` (or similar) bank by PID from the Event Builder} + /// @algo_type_filter /// /// @begin_doc_config{clas12/EventBuilderFilter} /// @config_param{pids | list[int] | list of PDG codes to filter} @@ -22,9 +18,14 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] particleBank `REC::Particle`, which will be filtered + /// @returns `false` if all particles are filtered out + bool Run(hipo::bank& particleBank) const; + /// @action_function{scalar filter} checks if the PDG `pid` is a part of the list of user-specified PDGs /// @param pid the particle PDG to check /// @returns `true` if `pid` is one the user wants diff --git a/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.cc b/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.cc index 124c54b9e..4b5c95309 100644 --- a/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.cc +++ b/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.cc @@ -8,8 +8,13 @@ namespace iguana::clas12 { electron_mass = particle::mass.at(particle::electron); } - void FTEnergyCorrection::Run(hipo::banklist& banks) const { - auto& ftParticleBank = GetBank(banks, b_ft_particle, "RECFT::Particle"); + bool FTEnergyCorrection::Run(hipo::banklist& banks) const + { + return Run(GetBank(banks, b_ft_particle, "RECFT::Particle")); + } + + bool FTEnergyCorrection::Run(hipo::bank& ftParticleBank) const + { ShowBank(ftParticleBank, Logger::Header("INPUT FT PARTICLES")); for(auto const& row : ftParticleBank.getRowList()) { if(ftParticleBank.getInt("pid", row) == particle::PDG::electron) { @@ -24,6 +29,7 @@ namespace iguana::clas12 { } } ShowBank(ftParticleBank, Logger::Header("OUTPUT FT PARTICLES")); + return true; } Momentum4 FTEnergyCorrection::Transform( diff --git a/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.h b/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.h index acf82f984..e70d40def 100644 --- a/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.h +++ b/src/iguana/algorithms/clas12/FTEnergyCorrection/Algorithm.h @@ -5,12 +5,8 @@ namespace iguana::clas12 { - /// @brief_algo Forward Tagger energy correction - /// - /// @begin_doc_algo{clas12::FTEnergyCorrection | Transformer} - /// @input_banks{RECFT::Particle} - /// @output_banks{RECFT::Particle} - /// @end_doc + /// @algo_brief{Forward Tagger energy correction} + /// @algo_type_transformer class FTEnergyCorrection : public Algorithm { DEFINE_IGUANA_ALGORITHM(FTEnergyCorrection, clas12::FTEnergyCorrection) @@ -18,9 +14,14 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] ftParticleBank `RECFT::Particle`, which will have the correction applied + /// @run_function_returns_true + bool Run(hipo::bank& ftParticleBank) const; + /// @action_function{scalar transformer} /// Transformation function that returns 4-vector of electron with corrected energy for the Forward Tagger. /// Currently only validated for Fall 2018 outbending data. diff --git a/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.cc b/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.cc index b8214759f..0403a383b 100644 --- a/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.cc +++ b/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.cc @@ -8,11 +8,6 @@ namespace iguana::clas12 { void FiducialFilter::Start(hipo::banklist& banks) { ParseYAMLConfig(); - o_pass = GetOptionScalar("pass"); - if(o_pass!=1){ - m_log->Warn("FiducialFilter only contains fiducial cuts for pass1...we will default to using those..."); - o_pass = 1; - } o_pcal_electron_cut_level = ParseCutLevel(GetOptionScalar("pcal_electron_cut_level")); o_pcal_photon_cut_level = ParseCutLevel(GetOptionScalar("pcal_photon_cut_level")); o_enable_pcal_cuts = GetOptionScalar("enable_pcal_cuts") == 1; @@ -20,60 +15,66 @@ namespace iguana::clas12 { b_particle = GetBankIndex(banks, "REC::Particle"); b_config = GetBankIndex(banks, "RUN::config"); - if(o_pass == 1) { - b_traj = GetBankIndex(banks, "REC::Particle::Traj"); - b_cal = GetBankIndex(banks, "REC::Particle::Calorimeter"); - } + b_traj = GetBankIndex(banks, "REC::Particle::Traj"); + b_cal = GetBankIndex(banks, "REC::Particle::Calorimeter"); } ////////////////////////////////////////////////////////////////////////////////// - void FiducialFilter::Run(hipo::banklist& banks) const { - - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - auto& configBank = GetBank(banks, b_config, "RUN::config"); - auto torus = configBank.getFloat("torus", 0); + bool FiducialFilter::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_config, "RUN::config"), + GetBank(banks, b_traj, "REC::Particle::Traj"), + GetBank(banks, b_cal, "REC::Particle::Calorimeter")); + } + bool FiducialFilter::Run( + hipo::bank& particleBank, + hipo::bank const& configBank, + hipo::bank const& trajBank, + hipo::bank const& calBank) const + { ShowBank(particleBank, Logger::Header("INPUT PARTICLES")); - if(o_pass == 1) { - auto& trajBank = GetBank(banks, b_traj, "REC::Particle::Traj"); - auto& calBank = GetBank(banks, b_cal, "REC::Particle::Calorimeter"); - if(auto num_rows{particleBank.getRows()}; num_rows != trajBank.getRows() || num_rows != calBank.getRows()) { - m_log->Error("number of particle bank rows differs from 'REC::Particle::Traj' and/or 'REC::Particle::Calorimeter' rows; are you sure these input banks are being filled?"); - throw std::runtime_error("cannot proceed"); - } - particleBank.getMutableRowList().filter([this, torus, &trajBank, &calBank](hipo::bank& bank, int row) { - auto pid = bank.getInt("pid", row); - if(row >= 0 && row < calBank.getRows() && row < trajBank.getRows()) { - // call the action function - return FilterRgaPass1( - calBank.getInt("pcal_sector", row), - calBank.getFloat("pcal_lv", row), - calBank.getFloat("pcal_lw", row), - calBank.getByte("pcal_found", row) == 1, - trajBank.getInt("sector", row), - trajBank.getFloat("r1_x", row), - trajBank.getFloat("r1_y", row), - trajBank.getFloat("r1_z", row), - trajBank.getByte("r1_found", row) == 1, - trajBank.getFloat("r2_x", row), - trajBank.getFloat("r2_y", row), - trajBank.getFloat("r2_z", row), - trajBank.getByte("r2_found", row) == 1, - trajBank.getFloat("r3_x", row), - trajBank.getFloat("r3_y", row), - trajBank.getFloat("r3_z", row), - trajBank.getByte("r3_found", row) == 1, - torus, - pid); - } - else - throw std::runtime_error(fmt::format("FiducialFilter filter encountered bad row number {}", row)); - }); + if(auto num_rows{particleBank.getRows()}; num_rows != trajBank.getRows() || num_rows != calBank.getRows()) { + m_log->Error("number of particle bank rows differs from 'REC::Particle::Traj' and/or 'REC::Particle::Calorimeter' rows; are you sure these input banks are being filled?"); + throw std::runtime_error("cannot proceed"); } + auto torus = configBank.getFloat("torus", 0); + particleBank.getMutableRowList().filter([this, torus, &trajBank, &calBank](hipo::bank& bank, int row) { + auto pid = bank.getInt("pid", row); + if(row >= 0 && row < calBank.getRows() && row < trajBank.getRows()) { + // call the action function + return FilterRgaPass1( + calBank.getInt("pcal_sector", row), + calBank.getFloat("pcal_lv", row), + calBank.getFloat("pcal_lw", row), + calBank.getByte("pcal_found", row) == 1, + trajBank.getInt("sector", row), + trajBank.getFloat("r1_x", row), + trajBank.getFloat("r1_y", row), + trajBank.getFloat("r1_z", row), + trajBank.getByte("r1_found", row) == 1, + trajBank.getFloat("r2_x", row), + trajBank.getFloat("r2_y", row), + trajBank.getFloat("r2_z", row), + trajBank.getByte("r2_found", row) == 1, + trajBank.getFloat("r3_x", row), + trajBank.getFloat("r3_y", row), + trajBank.getFloat("r3_z", row), + trajBank.getByte("r3_found", row) == 1, + torus, + pid); + } + else + throw std::runtime_error(fmt::format("FiducialFilter filter encountered bad row number {}", row)); + } + ); ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); + return ! particleBank.getRowList().empty(); } ////////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.h b/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.h index ea74f236a..43afdfaed 100644 --- a/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/FiducialFilter/Algorithm.h @@ -4,15 +4,11 @@ namespace iguana::clas12 { - /// @brief_algo Filter the `REC::Particle` bank by applying DC (drift chamber) and ECAL (electromagnetic calorimeter) fiducial cuts + /// @algo_brief{Filter the `REC::Particle` bank by applying DC (drift chamber) and ECAL (electromagnetic calorimeter) fiducial cuts} + /// @algo_type_filter /// /// Currently these are the "legacy" Pass 1 fiducial cuts tuned for Run Group A. /// - /// @begin_doc_algo{clas12::FiducialFilter | Filter} - /// @input_banks{REC::Particle, RUN::config, and others (see below)} - /// @output_banks{REC::Particle} - /// @end_doc - /// /// The following **additional banks** are needed: /// - if configuration option `pass` is `1`: /// - `REC::Particle::Traj`, created by algorithm `iguana::clas12::TrajLinker` @@ -40,9 +36,21 @@ namespace iguana::clas12 { }; void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] particleBank `REC::Particle`, which will be filtered + /// @param [in] configBank `RUN::config` + /// @param [in] trajBank `REC::Particle::Traj`, created by algorithm `clas12::TrajLinker` + /// @param [in] calBank `REC::Particle::Calorimeter`, created by algorithm `clas12::CalorimeterLinker` + /// @returns `false` if all particles are filtered out + bool Run( + hipo::bank& particleBank, + hipo::bank const& configBank, + hipo::bank const& trajBank, + hipo::bank const& calBank) const; + /// @action_function{scalar filter} top-level fiducial cut for RG-A Pass 1 /// @param pcal_sector PCAL sector /// @param pcal_lv PCAL lv @@ -169,7 +177,6 @@ namespace iguana::clas12 { hipo::banklist::size_type b_config; // options - int o_pass = 1; CutLevel o_pcal_electron_cut_level; CutLevel o_pcal_photon_cut_level; bool o_enable_pcal_cuts; diff --git a/src/iguana/algorithms/clas12/FiducialFilter/Config.yaml b/src/iguana/algorithms/clas12/FiducialFilter/Config.yaml index 46d3670fe..506166931 100644 --- a/src/iguana/algorithms/clas12/FiducialFilter/Config.yaml +++ b/src/iguana/algorithms/clas12/FiducialFilter/Config.yaml @@ -1,5 +1,4 @@ clas12::FiducialFilter: - pass: 1 # cut levels for PCAL homogeneous cuts; one of 'loose', 'medium', or 'tight' pcal_electron_cut_level: loose # for electrons and positrons diff --git a/src/iguana/algorithms/clas12/FiducialFilter/Validator.cc b/src/iguana/algorithms/clas12/FiducialFilter/Validator.cc index 9c07d6626..40f3417d6 100644 --- a/src/iguana/algorithms/clas12/FiducialFilter/Validator.cc +++ b/src/iguana/algorithms/clas12/FiducialFilter/Validator.cc @@ -83,7 +83,7 @@ namespace iguana::clas12 { } - void FiducialFilterValidator::Run(hipo::banklist& banks) const + bool FiducialFilterValidator::Run(hipo::banklist& banks) const { auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); auto& traj_bank = GetBank(banks, b_traj, "REC::Particle::Traj"); @@ -119,6 +119,7 @@ namespace iguana::clas12 { if(traj_bank.getByte("r3_found", row) == 1) u_DC3_after.at(pid)->Fill(traj_bank.getFloat("r3_x", row), traj_bank.getFloat("r3_y", row)); } + return true; } diff --git a/src/iguana/algorithms/clas12/FiducialFilter/Validator.h b/src/iguana/algorithms/clas12/FiducialFilter/Validator.h index 4f04c2252..d24c447a6 100644 --- a/src/iguana/algorithms/clas12/FiducialFilter/Validator.h +++ b/src/iguana/algorithms/clas12/FiducialFilter/Validator.h @@ -22,7 +22,7 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.cc b/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.cc index 233eb6cfa..de51da0ac 100644 --- a/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.cc +++ b/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.cc @@ -13,14 +13,23 @@ namespace iguana::clas12 { } - void MomentumCorrection::Run(hipo::banklist& banks) const + bool MomentumCorrection::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_sector, "REC::Particle::Sector"), + GetBank(banks, b_config, "RUN::config")); + } + + + bool MomentumCorrection::Run( + hipo::bank& particleBank, + hipo::bank const& sectorBank, + hipo::bank const& configBank) const { - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - auto& sectorBank = GetBank(banks, b_sector, "REC::Particle::Sector"); - auto& configBank = GetBank(banks, b_config, "RUN::config"); ShowBank(particleBank, Logger::Header("INPUT PARTICLES")); - auto torus = configBank.getFloat("torus", 0); + auto torus = configBank.getFloat("torus", 0); for(auto const& row : particleBank.getRowList()) { @@ -37,6 +46,7 @@ namespace iguana::clas12 { } ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); + return true; } @@ -65,6 +75,10 @@ namespace iguana::clas12 { if(!(pid == particle::electron || pid == particle::pi_plus || pid == particle::pi_minus || pid == particle::proton)) return 1.0; + // skip if the sector is unknown + if(!IsValidSector(sec)) + return 1.0; + // Momentum Magnitude double pp = sqrt(px * px + py * py + pz * pz); @@ -243,6 +257,10 @@ namespace iguana::clas12 { if(!(pid == particle::electron || pid == particle::pi_plus || pid == particle::pi_minus)) return 1.0; + // skip if the sector is unknown + if(!IsValidSector(sec)) + return 1.0; + // Momentum Magnitude double pp = sqrt(px * px + py * py + pz * pz); diff --git a/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.h b/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.h index 38fa4f343..f43c416de 100644 --- a/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.h +++ b/src/iguana/algorithms/clas12/MomentumCorrection/Algorithm.h @@ -5,14 +5,9 @@ namespace iguana::clas12 { - /// @brief_algo Momentum Corrections - /// + /// @algo_brief{Momentum Corrections} + /// @algo_type_transformer /// Adapted from - /// - /// @begin_doc_algo{clas12::MomentumCorrection | Transformer} - /// @input_banks{RUN::config, REC::Particle, REC::Particle::Sector} - /// @output_banks{REC::Particle} - /// @end_doc class MomentumCorrection : public Algorithm { @@ -21,9 +16,19 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] particleBank `REC::Particle`; the momenta will be corrected + /// @param [in] sectorBank `REC::Particle::Sector`, from `SectorFinder` + /// @param [in] configBank `RUN::config` + /// @run_function_returns_true + bool Run( + hipo::bank& particleBank, + hipo::bank const& sectorBank, + hipo::bank const& configBank) const; + /// @action_function{scalar transformer} Apply the momentum correction /// @param px @f$p_x@f$ /// @param py @f$p_y@f$ diff --git a/src/iguana/algorithms/clas12/MomentumCorrection/Validator.cc b/src/iguana/algorithms/clas12/MomentumCorrection/Validator.cc index f42fee52b..eccbf309e 100644 --- a/src/iguana/algorithms/clas12/MomentumCorrection/Validator.cc +++ b/src/iguana/algorithms/clas12/MomentumCorrection/Validator.cc @@ -46,7 +46,7 @@ namespace iguana::clas12 { } - void MomentumCorrectionValidator::Run(hipo::banklist& banks) const + bool MomentumCorrectionValidator::Run(hipo::banklist& banks) const { // get the momenta before auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); @@ -71,7 +71,7 @@ namespace iguana::clas12 { auto sector = sector_bank.getInt("sector", row); // skip central particle, or unknown sector - if(sector == 0) + if(!IsValidSector(sector)) continue; double p_corrected = std::hypot( @@ -81,6 +81,7 @@ namespace iguana::clas12 { auto delta_p = p_corrected - p_measured.at(row); u_deltaPvsP.at(pdg).at(sector - 1)->Fill(p_corrected, delta_p); } + return true; } diff --git a/src/iguana/algorithms/clas12/MomentumCorrection/Validator.h b/src/iguana/algorithms/clas12/MomentumCorrection/Validator.h index a552f6c90..16947c1d4 100644 --- a/src/iguana/algorithms/clas12/MomentumCorrection/Validator.h +++ b/src/iguana/algorithms/clas12/MomentumCorrection/Validator.h @@ -18,7 +18,7 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.cc b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.cc index e5df2242f..4680df790 100644 --- a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.cc +++ b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.cc @@ -43,14 +43,19 @@ namespace iguana::clas12 { o_threshold = GetOptionScalar("threshold"); } + bool PhotonGBTFilter::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_calorimeter, "REC::Calorimeter"), + GetBank(banks,b_config,"RUN::config")); + } - - void PhotonGBTFilter::Run(hipo::banklist& banks) const + bool PhotonGBTFilter::Run( + hipo::bank& particleBank, + hipo::bank const& caloBank, + hipo::bank const& configBank) const { - - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - auto& caloBank = GetBank(banks, b_calorimeter, "REC::Calorimeter"); - auto& configBank = GetBank(banks,b_config,"RUN::config"); int runnum = configBank.getInt("run",0); // Get CaloMap for the event @@ -70,7 +75,7 @@ namespace iguana::clas12 { // dump the modified bank ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); - + return ! particleBank.getRowList().empty(); } bool PhotonGBTFilter::PidPurityPhotonFilter(float const E, float const Epcal, float const theta) const diff --git a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h index a4bc6d6ab..801ee02e3 100644 --- a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h @@ -8,15 +8,11 @@ namespace iguana::clas12 { /// - /// @brief_algo Filter the `REC::Particle` photons using pretrained GBT models + /// @algo_brief{Filter the `REC::Particle` photons using pretrained GBT models} + /// @algo_type_filter /// /// For each photon (labeled the photon of interest or POI), we obtain its intrinsic features (energy, angle, pcal edep, etc.) and features corresponding to its nearest neighbors (angle of proximity, energy difference, etc.). This requires the reading of both the REC::Particle and REC::Calorimeter banks. An input std::vector is produced and passed to the pretrained GBT models, which yield a classification score between 0 and 1. An option variable `threshold` then determines the minimum photon `p-value` to survive the cut. /// - /// @begin_doc_algo{clas12::PhotonGBTFilter | Filter} - /// @input_banks{REC::Particle, REC::Calorimeter, RUN::config} - /// @output_banks{REC::Particle} - /// @end_doc - /// /// @begin_doc_config{clas12/PhotonGBTFilter} /// @config_param{pass | int | cook type} /// @config_param{threshold | double | minimum value to qualify a photon as "true"} @@ -29,9 +25,19 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] particleBank `REC::Particle`, which will be filtered + /// @param [in] caloBank `REC::Calorimeter` + /// @param [in] configBank `RUN::config` + /// @returns `false` if all particles are filtered out + bool Run( + hipo::bank& particleBank, + hipo::bank const& caloBank, + hipo::bank const& configBank) const; + /// Applies forward detector cut using REC::Particle Theta /// @param theta lab angle of the particle with respect to the beam direction (radians) /// @returns `true` if the particle's theta is within the forward detector coverage, `false` otherwise diff --git a/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.cc b/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.cc index b668b6286..ce659cd45 100644 --- a/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.cc +++ b/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.cc @@ -26,7 +26,7 @@ namespace iguana::clas12 { InitializeHistograms(); } - void PhotonGBTFilterValidator::Run(hipo::banklist& banks) const + bool PhotonGBTFilterValidator::Run(hipo::banklist& banks) const { // get the particle bank auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); @@ -63,6 +63,7 @@ namespace iguana::clas12 { FillHistograms(photons, 0); FillHistograms(filtered_photons, 1); + return true; } void PhotonGBTFilterValidator::InitializeHistograms() { diff --git a/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.h b/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.h index f4b5afc33..39b8791ed 100644 --- a/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.h +++ b/src/iguana/algorithms/clas12/PhotonGBTFilter/Validator.h @@ -19,7 +19,7 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.cc b/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.cc index 53e0d4eb3..24beebcfc 100644 --- a/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.cc +++ b/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.cc @@ -136,17 +136,29 @@ void RGAFiducialFilter::Start(hipo::banklist& banks) LoadConfig(); } -void RGAFiducialFilter::Run(hipo::banklist& banks) const { - auto& particle = GetBank(banks, b_particle, "REC::Particle"); - auto& conf = GetBank(banks, b_config, "RUN::config"); - auto* cal = m_have_calor ? &GetBank(banks, b_calor, "REC::Calorimeter") : nullptr; - auto* ft = m_have_ft ? &GetBank(banks, b_ft, "REC::ForwardTagger") : nullptr; - auto* traj = m_have_traj ? &GetBank(banks, b_traj, "REC::Traj") : nullptr; - - particle.getMutableRowList().filter([this, &conf, cal, ft, traj](auto bank, auto row) { - const bool keep = Filter(static_cast(row), bank, conf, cal, ft, traj); +bool RGAFiducialFilter::Run(hipo::banklist& banks) const +{ + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_config, "RUN::config"), + m_have_calor ? &GetBank(banks, b_calor, "REC::Calorimeter") : nullptr, + m_have_traj ? &GetBank(banks, b_traj, "REC::Traj") : nullptr, + m_have_ft ? &GetBank(banks, b_ft, "REC::ForwardTagger") : nullptr + ); +} + +bool RGAFiducialFilter::Run( + hipo::bank& particle, + hipo::bank const& conf, + hipo::bank const* cal, + hipo::bank const* traj, + hipo::bank const* ft) const +{ + particle.getMutableRowList().filter([this, &conf, cal, traj, ft](auto bank, auto row) { + const bool keep = Filter(row, bank, conf, cal, traj, ft); return keep ? 1 : 0; }); + return ! particle.getRowList().empty(); } RGAFiducialFilter::CalLayers @@ -315,7 +327,7 @@ bool RGAFiducialFilter::PassDCFiducial(int pindex, const hipo::bank& particleBan bool RGAFiducialFilter::Filter(int track_index, const hipo::bank& particleBank, const hipo::bank& configBank, const hipo::bank* calBank, - const hipo::bank* ftBank, const hipo::bank* trajBank) const { + const hipo::bank* trajBank, const hipo::bank* ftBank) const { const int pid = particleBank.getInt("pid", track_index); const int strictness = m_cal_strictness; @@ -369,4 +381,4 @@ bool RGAFiducialFilter::Filter(int track_index, const hipo::bank& particleBank, return true; } -} \ No newline at end of file +} diff --git a/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.h b/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.h index 192f1bd95..e124bc85b 100644 --- a/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/RGAFiducialFilter/Algorithm.h @@ -4,7 +4,8 @@ namespace iguana::clas12 { - /// @brief_algo Filter the `REC::Particle` bank using subsystem-specific fiducial cuts + /// @algo_brief{Filter the `REC::Particle` bank using subsystem-specific fiducial cuts} + /// @algo_type_filter /// /// RGA fiducial filter: /// @@ -15,10 +16,14 @@ namespace iguana::clas12 { /// - Drift Chamber (DC) fiducial: /// - three region edge thresholds with separate inbending/outbending track logic /// - /// @begin_doc_algo{clas12::RGAFiducialFilter | Filter} - /// @input_banks{REC::Particle, RUN::config, REC::Calorimeter, REC::ForwardTagger, REC::Traj} - /// @output_banks{REC::Particle} - /// @end_doc + /// **References:** + /// + /// - https://clas12-docdb.jlab.org/DocDB/0012/001240/001/rga_fiducial_cuts.pdf + /// + /// **NOTE:** this algorithm has multiple `Run(hipo::bank bank1, ...)` functions, which + /// take `hipo::bank` parameters, and some parameters may be optional, since you may + /// be reading data which lack certain banks. If you use these functions, take a look at all them + /// to decide which one best suits your use case. /// /// @begin_doc_config{clas12/RGAFiducialFilter} /// @config_param{calorimeter.strictness | int | calorimeter cut strictness} @@ -58,11 +63,57 @@ namespace iguana::clas12 { }; public: - // algorithm API + void Start(hipo::banklist& banks) override; - void Run (hipo::banklist& banks) const override; + bool Run (hipo::banklist& banks) const override; void Stop () override {} + /// @run_function + /// @param [in,out] particle `REC::Particle` bank, which will be filtered + /// @param [in] conf `RUN::config` bank + /// @param [in] cal pointer to `REC::Calorimeter` bank; it is a _pointer_ since it is _optional_ (use `nullptr` for "unused") + /// @param [in] traj pointer to `REC::Traj` bank; it is a _pointer_ since it is _optional_ (use `nullptr` for "unused") + /// @param [in] ft pointer to `REC::ForwardTagger` bank; it is a _pointer_ since it is _optional_ (use `nullptr` for "unused") + /// @returns `false` if all particles are filtered out + bool Run( + hipo::bank& particle, + hipo::bank const& conf, + hipo::bank const* cal, + hipo::bank const* traj, + hipo::bank const* ft) const; + + /// @run_function + /// @param [in,out] particle `REC::Particle` bank, which will be filtered + /// @param [in] conf `RUN::config` bank + /// @param [in] cal `REC::Calorimeter` bank + /// @param [in] traj `REC::Traj` bank + /// @returns `false` if all particles are filtered out + bool Run( + hipo::bank& particle, + hipo::bank const& conf, + hipo::bank const& cal, + hipo::bank const& traj) const + { + return Run(particle, conf, &cal, &traj, nullptr); + } + + /// @run_function + /// @param [in,out] particle `REC::Particle` bank, which will be filtered + /// @param [in] conf `RUN::config` bank + /// @param [in] cal `REC::Calorimeter` bank + /// @param [in] traj `REC::Traj` bank + /// @param [in] ft `REC::ForwardTagger` bank + /// @returns `false` if all particles are filtered out + bool Run( + hipo::bank& particle, + hipo::bank const& conf, + hipo::bank const& cal, + hipo::bank const& traj, + hipo::bank const& ft) const + { + return Run(particle, conf, &cal, &traj, &ft); + } + /// @returns calorimeter strictness int CalStrictness() const { return m_cal_strictness; } /// @returns FT configuration parameters @@ -97,7 +148,7 @@ namespace iguana::clas12 { bool PassDCFiducial(int track_index, const hipo::bank& particleBank, const hipo::bank& configBank, const hipo::bank* trajBank) const; bool Filter(int track_index, const hipo::bank& particleBank, const hipo::bank& configBank, - const hipo::bank* calBank, const hipo::bank* ftBank, const hipo::bank* trajBank) const; + const hipo::bank* calBank, const hipo::bank* trajBank, const hipo::bank* ftBank) const; // ---- Config loading void LoadConfig(); diff --git a/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.cc b/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.cc index e896d2a86..3c41956c7 100644 --- a/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.cc +++ b/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.cc @@ -175,7 +175,7 @@ static inline void SetDCPadMargins() { gPad->SetTopMargin(0.08); } -void RGAFiducialFilterValidator::Run(hipo::banklist& banks) const { +bool RGAFiducialFilterValidator::Run(hipo::banklist& banks) const { auto& particle = GetBank(banks, b_particle, "REC::Particle"); auto& config = GetBank(banks, b_config, "RUN::config"); @@ -419,6 +419,7 @@ void RGAFiducialFilterValidator::Run(hipo::banklist& banks) const { const_cast(this)->m_dc_neg_before_n += (long long) inter3(neg_b1, neg_b2, neg_b3); const_cast(this)->m_dc_neg_after_n += (long long) inter3(neg_a1, neg_a2, neg_a3); } + return true; } // plotting @@ -678,4 +679,4 @@ void RGAFiducialFilterValidator::Stop() { gROOT->GetListOfCanvases()->Delete(); } -} \ No newline at end of file +} diff --git a/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.h b/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.h index 5e1e61981..36ea9fb6c 100644 --- a/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.h +++ b/src/iguana/algorithms/clas12/RGAFiducialFilter/Validator.h @@ -21,7 +21,7 @@ class RGAFiducialFilterValidator : public Validator { public: void Start(hipo::banklist& banks) override; - void Run (hipo::banklist& banks) const override; + bool Run (hipo::banklist& banks) const override; void Stop () override; private: diff --git a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc index 070827eff..668bdfd74 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc +++ b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.cc @@ -10,7 +10,13 @@ namespace iguana::clas12 { // define options, their default values, and cache them ParseYAMLConfig(); o_bankname_charged = GetOptionScalar("bank_charged"); - o_bankname_uncharged = GetOptionScalar("bank_uncharged"); + try { + o_bankname_neutral = GetOptionScalar("bank_neutral"); + } catch(std::runtime_error const& ex) { + m_log->Warn("searching instead for configuration parameter named 'bank_uncharged'..."); + o_bankname_neutral = GetOptionScalar("bank_uncharged"); + m_log->Warn("...found 'bank_uncharged' and using it; note that 'bank_uncharged' has been renamed to 'bank_neutral', please update your configuration"); + } bool setDefaultBanks=false; // get expected bank indices @@ -20,26 +26,26 @@ namespace iguana::clas12 { userSpecifiedBank_charged = true; } else { - b_calorimeter = GetBankIndex(banks, "REC::Calorimeter"); b_track = GetBankIndex(banks, "REC::Track"); + b_calorimeter = GetBankIndex(banks, "REC::Calorimeter"); b_scint = GetBankIndex(banks, "REC::Scintillator"); setDefaultBanks = true; userSpecifiedBank_charged = false; } - if(o_bankname_uncharged != "default") { - b_user_uncharged = GetBankIndex(banks, o_bankname_uncharged); - userSpecifiedBank_uncharged = true; + if(o_bankname_neutral != "default") { + b_user_neutral = GetBankIndex(banks, o_bankname_neutral); + userSpecifiedBank_neutral = true; } else { //avoid setting default banks twice if(!setDefaultBanks){ - b_calorimeter = GetBankIndex(banks, "REC::Calorimeter"); b_track = GetBankIndex(banks, "REC::Track"); + b_calorimeter = GetBankIndex(banks, "REC::Calorimeter"); b_scint = GetBankIndex(banks, "REC::Scintillator"); setDefaultBanks = true; } - userSpecifiedBank_uncharged = false; + userSpecifiedBank_neutral = false; } // create the output bank @@ -48,68 +54,94 @@ namespace iguana::clas12 { i_pindex = result_schema.getEntryOrder("pindex"); } - void SectorFinder::Run(hipo::banklist& banks) const + bool SectorFinder::Run(hipo::banklist& banks) const { - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - auto& resultBank = GetBank(banks, b_result, "REC::Particle::Sector"); - - std::vector sectors_user_uncharged; - std::vector pindices_user_uncharged; - if(userSpecifiedBank_uncharged){ - auto const& userBank = GetBank(banks, b_user_uncharged); - GetListsSectorPindex(userBank,sectors_user_uncharged,pindices_user_uncharged); - } + auto includeDefaultBanks = !(userSpecifiedBank_charged && userSpecifiedBank_neutral); + return RunImpl( + &GetBank(banks, b_particle, "REC::Particle"), + includeDefaultBanks ? &GetBank(banks, b_track, "REC::Track") : nullptr, + includeDefaultBanks ? &GetBank(banks, b_calorimeter, "REC::Calorimeter") : nullptr, + includeDefaultBanks ? &GetBank(banks, b_scint, "REC::Scintillator") : nullptr, + userSpecifiedBank_charged ? &GetBank(banks, b_user_charged) : nullptr, + userSpecifiedBank_neutral ? &GetBank(banks, b_user_neutral) : nullptr, + &GetBank(banks, b_result, "REC::Particle::Sector")); + } - std::vector sectors_user_charged; - std::vector pindices_user_charged; - if(userSpecifiedBank_charged){ - auto const& userBank = GetBank(banks, b_user_charged); - GetListsSectorPindex(userBank,sectors_user_charged,pindices_user_charged); - } + bool SectorFinder::RunImpl( + hipo::bank const* particleBank, + hipo::bank const* trackBank, + hipo::bank const* calBank, + hipo::bank const* scintBank, + hipo::bank const* userChargedBank, + hipo::bank const* userNeutralBank, + hipo::bank* resultBank) const + { std::vector sectors_track; std::vector pindices_track; - if(!userSpecifiedBank_charged || !userSpecifiedBank_uncharged){ - auto const& trackBank = GetBank(banks, b_track); - GetListsSectorPindex(trackBank,sectors_track,pindices_track); - } - std::vector sectors_cal; std::vector pindices_cal; - if(!userSpecifiedBank_charged || !userSpecifiedBank_uncharged){ - auto const& calBank = GetBank(banks, b_calorimeter); - GetListsSectorPindex(calBank,sectors_cal,pindices_cal); - } - std::vector sectors_scint; std::vector pindices_scint; - if(!userSpecifiedBank_charged || !userSpecifiedBank_uncharged){ - auto const& scintBank = GetBank(banks, b_scint); - GetListsSectorPindex(scintBank,sectors_scint,pindices_scint); + std::vector sectors_user_neutral; + std::vector pindices_user_neutral; + std::vector sectors_user_charged; + std::vector pindices_user_charged; + + if(!userSpecifiedBank_charged || !userSpecifiedBank_neutral){ + if(trackBank!=nullptr && calBank!=nullptr && scintBank!=nullptr) { + GetListsSectorPindex(*trackBank,sectors_track,pindices_track); + GetListsSectorPindex(*scintBank,sectors_scint,pindices_scint); + GetListsSectorPindex(*calBank,sectors_cal,pindices_cal); + } + else + throw std::runtime_error("SectorFinder::RunImpl called with unexpected null pointer to either the track, calorimeter, or scintillator bank(s); please contact the maintainers"); } + if(userSpecifiedBank_neutral){ + if(userNeutralBank!=nullptr) + GetListsSectorPindex(*userNeutralBank,sectors_user_neutral,pindices_user_neutral); + else + throw std::runtime_error("SectorFinder::RunImpl called with unexpected null pointer to a user-specified bank; please contact the maintainers"); + } - // sync new bank with particle bank, and fill it with zeroes - resultBank.setRows(particleBank.getRows()); - resultBank.getMutableRowList().setList(particleBank.getRowList()); - for(int row = 0; row < resultBank.getRows(); row++){ - resultBank.putInt(i_sector, row, 0); - resultBank.putShort(i_pindex, row, static_cast(row)); + if(userSpecifiedBank_charged){ + if(userChargedBank!=nullptr) + GetListsSectorPindex(*userChargedBank,sectors_user_charged,pindices_user_charged); + else + throw std::runtime_error("SectorFinder::RunImpl called with unexpected null pointer to a user-specified bank; please contact the maintainers"); + } + + // trace logging + if(m_log->GetLevel() <= Logger::Level::trace) { + m_log->Trace("pindices_track = {}", fmt::join(pindices_track, ",")); + m_log->Trace("sectors_track = {}", fmt::join(sectors_track, ",")); + m_log->Trace("pindices_scint = {}", fmt::join(pindices_scint, ",")); + m_log->Trace("sectors_scint = {}", fmt::join(sectors_scint, ",")); + m_log->Trace("pindices_cal = {}", fmt::join(pindices_cal, ",")); + m_log->Trace("sectors_cal = {}", fmt::join(sectors_cal, ",")); + m_log->Trace("pindices_user_neutral = {}", fmt::join(pindices_user_neutral, ",")); + m_log->Trace("sectors_user_neutral = {}", fmt::join(sectors_user_neutral, ",")); + m_log->Trace("pindices_user_charged = {}", fmt::join(pindices_user_charged, ",")); + m_log->Trace("sectors_user_charged = {}", fmt::join(sectors_user_charged, ",")); } + // sync new bank with particle bank + resultBank->setRows(particleBank->getRows()); + resultBank->getMutableRowList().setList(particleBank->getRowList()); // some downstream algorithms may still need sector info, so obtain sector for _all_ particles, // not just the ones that were filtered out (use `.getRows()` rather than `.getRowList()`) - for(int row = 0; row < particleBank.getRows(); row++) { + for(int row = 0; row < particleBank->getRows(); row++) { - auto charge=particleBank.getInt("charge",row); - int sect = -1; + auto charge=particleBank->getInt("charge",row); + int sect = UNKNOWN_SECTOR; // if user-specified bank - if(charge==0 ? userSpecifiedBank_uncharged : userSpecifiedBank_charged) + if(charge==0 ? userSpecifiedBank_neutral : userSpecifiedBank_charged) sect = GetSector( - charge==0 ? sectors_user_uncharged : sectors_user_charged, - charge==0 ? pindices_user_uncharged : pindices_user_charged, + charge==0 ? sectors_user_neutral : sectors_user_charged, + charge==0 ? pindices_user_neutral : pindices_user_charged, row); else // if not user-specified bank, use the standard method sect = GetStandardSector( @@ -121,17 +153,20 @@ namespace iguana::clas12 { pindices_scint, row); - if (sect!=-1){ - resultBank.putInt(i_sector, row, sect); - resultBank.putShort(i_pindex, row, static_cast(row)); - } + resultBank->putInt(i_sector, row, sect); + resultBank->putShort(i_pindex, row, static_cast(row)); } - ShowBank(resultBank, Logger::Header("CREATED BANK")); + ShowBank(*resultBank, Logger::Header("CREATED BANK")); + return true; } void SectorFinder::GetListsSectorPindex(hipo::bank const& bank, std::vector& sectors, std::vector& pindices) const { + if(m_log->GetLevel() <= Logger::Level::trace) { + m_log->Trace("called `GetListsSectorPindex` for the following bank:"); + bank.show(); + } for(auto const& row : bank.getRowList()) { //check that we're only using FD detectors //eg have "sectors" in CND which we don't want to add here @@ -147,10 +182,11 @@ namespace iguana::clas12 { { for(std::size_t i=0;iTrace("{} pindex {} sect {}", det_name, pindex_particle, sect); + m_log->Trace("{} pindex {} sect {}", det_name, pindex_particle, sect); + if(IsValidSector(sect)) // return this sector number; if not valid, continue to next detector in `det_enum` return sect; - } } - return -1; + return UNKNOWN_SECTOR; // not found in any detector in `det_enum` } std::vector SectorFinder::GetStandardSector( diff --git a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h index 2a13c2386..95b633743 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h +++ b/src/iguana/algorithms/clas12/SectorFinder/Algorithm.h @@ -5,31 +5,27 @@ namespace iguana::clas12 { - /// @brief_algo Find the sector for all rows in `REC::Particle` - /// - /// @begin_doc_algo{clas12::SectorFinder | Creator} - /// @input_banks{REC::Particle, REC::Track, REC::Calorimeter, REC::Scintillator} - /// @output_banks{%REC::Particle::Sector} - /// @end_doc + /// @algo_brief{Find the sector for all rows in `REC::Particle`} + /// @algo_type_creator /// /// @begin_doc_config{clas12/SectorFinder} /// @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} + /// @config_param{bank_neutral | string | if not `default`, use this bank for sector finding of neutral particles} /// @end_doc /// - /// If `bank_charged` and/or `bank_uncharged` is default, then all of the following banks are needed, in addition to `REC::Particle`: + /// If `bank_charged` and/or `bank_neutral` is default, then all of the following banks are needed, in addition to `REC::Particle`: /// /// - `REC::Track` /// - `REC::Calorimeter` /// - `REC::Scintillator` /// - /// Otherwise only the bank(s) specified by `bank_charged` and `bank_uncharged` is/are needed, if both of them are non-default. + /// Otherwise only the bank(s) specified by `bank_charged` and `bank_neutral` is/are needed, if both of them are non-default. + /// + /// If the sector cannot be determined, the value `UNKNOWN_SECTOR` will be used instead. /// /// The action function ::GetStandardSector identifies the sector(s) using these banks in a priority order, whereas /// the action function ::GetSector uses a single bank's data. /// Note: rows that have been filtered out of `REC::Particle` will still have their sectors determined. - /// - /// @creator_note class SectorFinder : public Algorithm { @@ -37,10 +33,91 @@ namespace iguana::clas12 { public: + /// if this algorithm cannot determine the sector, this value will be used + static int const UNKNOWN_SECTOR = -1; + void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// uses track, calorimeter, and scintillator banks for both charged and neutral particles + /// @see this algorithm contains multiple run functions, for if you prefer to use other banks + /// @param [in] particleBank `REC::Particle` + /// @param [in] trackBank `REC::Track` + /// @param [in] calBank `REC::Calorimeter` + /// @param [in] scintBank `REC::Scintillator` + /// @param [out] resultBank the output `REC::Particle::Sector` bank + /// @run_function_returns_true + bool Run( + hipo::bank const& particleBank, + hipo::bank const& trackBank, + hipo::bank const& calBank, + hipo::bank const& scintBank, + hipo::bank& resultBank) const + { + return RunImpl(&particleBank, &trackBank, &calBank, &scintBank, nullptr, nullptr, &resultBank); + } + + /// @run_function + /// uses track, calorimeter, and scintillator banks for neutral particles, and a custom bank for charged particles + /// @see this algorithm contains multiple run functions, for if you prefer to use other banks + /// @param [in] particleBank `REC::Particle` + /// @param [in] trackBank `REC::Track` + /// @param [in] calBank `REC::Calorimeter` + /// @param [in] scintBank `REC::Scintillator` + /// @param [in] userChargedBank custom bank used to obtain charged-particles' sectors + /// @param [out] resultBank the output `REC::Particle::Sector` bank + /// @run_function_returns_true + bool RunWithCustomChargedBank( + hipo::bank const& particleBank, + hipo::bank const& trackBank, + hipo::bank const& calBank, + hipo::bank const& scintBank, + hipo::bank const& userChargedBank, + hipo::bank& resultBank) const + { + return RunImpl(&particleBank, &trackBank, &calBank, &scintBank, &userChargedBank, nullptr, &resultBank); + } + + /// @run_function + /// uses track, calorimeter, and scintillator banks for charged particles, and a custom bank for neutral particles + /// @see this algorithm contains multiple run functions, for if you prefer to use other banks + /// @param [in] particleBank `REC::Particle` + /// @param [in] trackBank `REC::Track` + /// @param [in] calBank `REC::Calorimeter` + /// @param [in] scintBank `REC::Scintillator` + /// @param [in] userNeutralBank custom bank used to obtain neutral-particles' sectors + /// @param [out] resultBank the output `REC::Particle::Sector` bank + /// @run_function_returns_true + bool RunWithCustomNeutralBank( + hipo::bank const& particleBank, + hipo::bank const& trackBank, + hipo::bank const& calBank, + hipo::bank const& scintBank, + hipo::bank const& userNeutralBank, + hipo::bank& resultBank) const + { + return RunImpl(&particleBank, &trackBank, &calBank, &scintBank, nullptr, &userNeutralBank, &resultBank); + } + + /// @run_function + /// uses custom banks for both charged and neutral particles + /// @see this algorithm contains multiple run functions, for if you prefer to use other banks + /// @param [in] particleBank `REC::Particle` + /// @param [in] userChargedBank custom bank used to obtain charged-particles' sectors + /// @param [in] userNeutralBank custom bank used to obtain neutral-particles' sectors + /// @param [out] resultBank the output `REC::Particle::Sector` bank + /// @run_function_returns_true + bool RunWithCustomBanks( + hipo::bank const& particleBank, + hipo::bank const& userChargedBank, + hipo::bank const& userNeutralBank, + hipo::bank& resultBank) const + { + return RunImpl(&particleBank, nullptr, nullptr, nullptr, &userChargedBank, &userNeutralBank, &resultBank); + } + /// @action_function{scalar creator} for a given particle with index `pindex_particle`, get its sector from /// a detector bank's list of `sectors` and `pindices` (both must be ordered in the same way) /// @@ -82,7 +159,7 @@ namespace iguana::clas12 { /// @param sectors list of sectors in a detector bank /// @param pindices list of pindices in a detector bank /// @param pindex_particle index in `REC::Particle` bank for which to get sector - /// @returns sector for `pindex_particle` in list, -1 if `pindex_particle` not in inputted list + /// @returns sector for `pindex_particle` in list, `UNKNOWN_SECTOR` if `pindex_particle` not in inputted list int GetSector( std::vector const& sectors, std::vector const& pindices, @@ -106,7 +183,7 @@ namespace iguana::clas12 { /// @param sectors_scint list of sectors in `REC::Scintillator` /// @param pindices_scint list of pindices in `REC::Scintillator` /// @param pindex_particle index in `REC::Particle` bank for which to get sector - /// @returns sector for `pindex_particle` in lists, -1 if `pindex_particle` not any of the inputted lists + /// @returns sector for `pindex_particle` in lists, `UNKNOWN_SECTOR` if `pindex_particle` not any of the inputted lists int GetStandardSector( std::vector const& sectors_track, std::vector const& pindices_track, @@ -150,16 +227,34 @@ namespace iguana::clas12 { private: + /// @brief private implementation of the run function, called by public run functions + /// @param [in] particleBank `REC::Particle` + /// @param [in] trackBank `REC::Track` + /// @param [in] calBank `REC::Calorimeter` + /// @param [in] scintBank `REC::Scintillator` + /// @param [in] userChargedBank custom bank used to obtain charged-particles' sectors + /// @param [in] userNeutralBank custom bank used to obtain neutral-particles' sectors + /// @param [out] resultBank the output `REC::Particle::Sector` bank + /// @run_function_returns_true + bool RunImpl( + hipo::bank const* particleBank, + hipo::bank const* trackBank, + hipo::bank const* calBank, + hipo::bank const* scintBank, + hipo::bank const* userChargedBank, + hipo::bank const* userNeutralBank, + hipo::bank* resultBank) const; + /// `hipo::banklist` index for the particle bank hipo::banklist::size_type b_particle; - hipo::banklist::size_type b_calorimeter; hipo::banklist::size_type b_track; + hipo::banklist::size_type b_calorimeter; hipo::banklist::size_type b_scint; hipo::banklist::size_type b_user_charged; - hipo::banklist::size_type b_user_uncharged; + hipo::banklist::size_type b_user_neutral; hipo::banklist::size_type b_result; bool userSpecifiedBank_charged{false}; - bool userSpecifiedBank_uncharged{true}; + bool userSpecifiedBank_neutral{false}; // `b_result` bank item indices int i_sector; @@ -167,7 +262,7 @@ namespace iguana::clas12 { /// Configuration options std::string o_bankname_charged; - std::string o_bankname_uncharged; + std::string o_bankname_neutral; //only want sectors from FD detectors std::set const listFDDets{ diff --git a/src/iguana/algorithms/clas12/SectorFinder/Config.yaml b/src/iguana/algorithms/clas12/SectorFinder/Config.yaml index be33a1eec..9cb2cc6b7 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Config.yaml +++ b/src/iguana/algorithms/clas12/SectorFinder/Config.yaml @@ -1,9 +1,9 @@ clas12::SectorFinder: - ### use the default banks for both charged/uncharged particles + ### use the default banks for both charged/neutral particles bank_charged: default - bank_uncharged: default + bank_neutral: default ### alternatively, use custom banks; for example: - # bank_charged: default # default bank for charged particles - # bank_uncharged: REC::Calorimeter # custom bank for neutral particles + # bank_charged: default # default bank for charged particles + # bank_neutral: REC::Calorimeter # custom bank for neutral particles diff --git a/src/iguana/algorithms/clas12/SectorFinder/Validator.cc b/src/iguana/algorithms/clas12/SectorFinder/Validator.cc index 70442affc..3adc998b1 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Validator.cc +++ b/src/iguana/algorithms/clas12/SectorFinder/Validator.cc @@ -52,7 +52,7 @@ namespace iguana::clas12 { } - void SectorFinderValidator::Run(hipo::banklist& banks) const + bool SectorFinderValidator::Run(hipo::banklist& banks) const { auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); @@ -95,12 +95,13 @@ namespace iguana::clas12 { } // skip central particle, or unknown sector - if(sector == 0) + if(!IsValidSector(sector)) continue; m_log->Trace("Filling SectorFinder Validator, pdg {} sector {} pindex {}", pdg, sector, row); u_YvsX.at(pdg).at(sector - 1)->Fill(x, y); } + return true; } diff --git a/src/iguana/algorithms/clas12/SectorFinder/Validator.h b/src/iguana/algorithms/clas12/SectorFinder/Validator.h index 089c1afaa..20d92d68f 100644 --- a/src/iguana/algorithms/clas12/SectorFinder/Validator.h +++ b/src/iguana/algorithms/clas12/SectorFinder/Validator.h @@ -19,7 +19,7 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/clas12/TrajLinker/Algorithm.cc b/src/iguana/algorithms/clas12/TrajLinker/Algorithm.cc index 9c94332e5..9815e525a 100644 --- a/src/iguana/algorithms/clas12/TrajLinker/Algorithm.cc +++ b/src/iguana/algorithms/clas12/TrajLinker/Algorithm.cc @@ -26,12 +26,19 @@ namespace iguana::clas12 { i_r3_z = result_schema.getEntryOrder("r3_z"); } - void TrajLinker::Run(hipo::banklist& banks) const + bool TrajLinker::Run(hipo::banklist& banks) const { - auto& bank_particle = GetBank(banks, b_particle, "REC::Particle"); - auto& bank_traj = GetBank(banks, b_traj, "REC::Traj"); - auto& bank_result = GetBank(banks, b_result, "REC::Particle::Traj"); + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_traj, "REC::Traj"), + GetBank(banks, b_result, "REC::Particle::Traj")); + } + bool TrajLinker::Run( + hipo::bank const& bank_particle, + hipo::bank const& bank_traj, + hipo::bank& bank_result) const + { ShowBank(bank_particle, Logger::Header("INPUT PARTICLE BANK")); ShowBank(bank_traj, Logger::Header("INPUT TRAJECTORY BANK")); @@ -107,6 +114,7 @@ namespace iguana::clas12 { bank_result.putFloat(i_r3_z, row_particle, link_particle.r3_z); } ShowBank(bank_result, Logger::Header("CREATED BANK")); + return true; } void TrajLinker::Stop() diff --git a/src/iguana/algorithms/clas12/TrajLinker/Algorithm.h b/src/iguana/algorithms/clas12/TrajLinker/Algorithm.h index 69b7aa04e..48430cc11 100644 --- a/src/iguana/algorithms/clas12/TrajLinker/Algorithm.h +++ b/src/iguana/algorithms/clas12/TrajLinker/Algorithm.h @@ -4,19 +4,13 @@ namespace iguana::clas12 { - /// @brief_algo Link particle bank to bank `REC::Traj` - /// - /// @begin_doc_algo{clas12::TrajLinker | Creator} - /// @input_banks{REC::Particle, REC::Traj} - /// @output_banks{%REC::Particle::Traj} - /// @end_doc + /// @algo_brief{Link particle bank to bank `REC::Traj`} + /// @algo_type_creator /// /// This algorithm reads `REC::Traj` and produces a new bank, `REC::Particle::Traj`, /// to make it easier to access commonly used `REC::Traj` information for each particle. /// /// If this algorithm does not provide information you need, ask the maintainers or open a pull request. - /// - /// @creator_note class TrajLinker : public Algorithm { @@ -25,9 +19,19 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] bank_particle `REC::Particle` + /// @param [in] bank_traj `REC::Traj` + /// @param [out] bank_result `REC::Particle::Traj`, which will be created + /// @run_function_returns_true + bool Run( + hipo::bank const& bank_particle, + hipo::bank const& bank_traj, + hipo::bank& bank_result) const; + /// @returns the DC sector given (x,y,z), or `-1` if failed /// @param x x-position /// @param y y-position diff --git a/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.cc b/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.cc index f869c229c..ededd9e19 100644 --- a/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.cc +++ b/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.cc @@ -18,13 +18,15 @@ namespace iguana::clas12 { b_config = GetBankIndex(banks, "RUN::config"); } - void ZVertexFilter::Run(hipo::banklist& banks) const + bool ZVertexFilter::Run(hipo::banklist& banks) const { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_config, "RUN::config")); + } - // get the banks - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); - auto& configBank = GetBank(banks, b_config, "RUN::config"); - + bool ZVertexFilter::Run(hipo::bank& particleBank, hipo::bank const& configBank) const + { // dump the bank ShowBank(particleBank, Logger::Header("INPUT PARTICLES")); @@ -43,6 +45,7 @@ namespace iguana::clas12 { // dump the modified bank ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); + return ! particleBank.getRowList().empty(); } concurrent_key_t ZVertexFilter::PrepareEvent(int const runnum) const { diff --git a/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.h b/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.h index 917158921..6d8366166 100644 --- a/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/ZVertexFilter/Algorithm.h @@ -5,12 +5,8 @@ namespace iguana::clas12 { - /// @brief_algo Filter the `REC::Particle` (or similar) bank by cutting on Z Vertex - /// - /// @begin_doc_algo{clas12::ZVertexFilter | Filter} - /// @input_banks{REC::Particle, RUN::config} - /// @output_banks{REC::Particle} - /// @end_doc + /// @algo_brief{Filter the `REC::Particle` (or similar) bank by cutting on Z Vertex} + /// @algo_type_filter /// /// @begin_doc_config{clas12/ZVertexFilter} /// @config_param{electron_vz | list[double] | lower and upper electron @f$z@f$-vertex cuts; run-range dependent; cuts are not applied to FT electrons (FD and CD only)} @@ -23,9 +19,15 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in,out] particleBank `REC::Particle`, which will be filtered + /// @param [in] configBank `RUN::config` + /// @returns `false` if all particles are filtered out + bool Run(hipo::bank& particleBank, hipo::bank const& configBank) const; + /// @action_function{reload} prepare the event /// @when_to_call{for each event} /// @param runnum the run number diff --git a/src/iguana/algorithms/clas12/ZVertexFilter/Validator.cc b/src/iguana/algorithms/clas12/ZVertexFilter/Validator.cc index daaf3206a..433e5babf 100644 --- a/src/iguana/algorithms/clas12/ZVertexFilter/Validator.cc +++ b/src/iguana/algorithms/clas12/ZVertexFilter/Validator.cc @@ -47,7 +47,7 @@ namespace iguana::clas12 { } - void ZVertexFilterValidator::Run(hipo::banklist& banks) const + bool ZVertexFilterValidator::Run(hipo::banklist& banks) const { auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); @@ -80,6 +80,7 @@ namespace iguana::clas12 { u_zvertexplots.at(pdg).at(1)->Fill(vz); } } + return true; } void ZVertexFilterValidator::Stop() diff --git a/src/iguana/algorithms/clas12/ZVertexFilter/Validator.h b/src/iguana/algorithms/clas12/ZVertexFilter/Validator.h index f62c36b7b..4ea393b2b 100644 --- a/src/iguana/algorithms/clas12/ZVertexFilter/Validator.h +++ b/src/iguana/algorithms/clas12/ZVertexFilter/Validator.h @@ -17,7 +17,7 @@ namespace iguana::clas12 { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.cc b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.cc index bab21861d..b31dae7b7 100644 --- a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.cc +++ b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.cc @@ -52,19 +52,28 @@ namespace iguana::example { // ############################################################################ - // # define `ExampleAlgorithm::Run()` - // # - this overrides the virtual function `Algorithm::Run` + // # define `ExampleAlgorithm::Run` functions + // # - this `Run` function that acts on `hipo::banklist` should just call the `Run` + // # function that acts on `hipo::bank` objects; let's define it first + // ############################################################################ + bool ExampleAlgorithm::Run(hipo::banklist& banks) const + { + // ############################################################################ + // # use `GetBank` to get the banks; here we just need `REC::Particle` + // ############################################################################ + return Run(GetBank(banks, b_particle, "REC::Particle")); + } + + // ############################################################################ + // # here is the `Run` function which acts on `hipo::bank` objects // # - note that this method must be _thread safe_, for example, you cannot modify - // # class instance objects + // # class instance objects; therefore it _must_ be `const` // # - try to avoid expensive operations here; instead, put them in the `Start` method // # if it is reasonable to do so + // # - the function's `bool` return value can be used as an event-level filter // ############################################################################ - void ExampleAlgorithm::Run(hipo::banklist& banks) const + bool ExampleAlgorithm::Run(hipo::bank& particleBank) const { - // ############################################################################ - // # get the banks; here we just need `REC::Particle` - // ############################################################################ - auto& particleBank = GetBank(banks, b_particle, "REC::Particle"); // ############################################################################ // # dump the bank // # - this will only happen if the log level for this algorithm is set low enough @@ -98,6 +107,12 @@ namespace iguana::example { // # dump the modified bank (only if the log level is low enough); this is also optional // ############################################################################ ShowBank(particleBank, Logger::Header("OUTPUT PARTICLES")); + + // ############################################################################ + // # return true or false, used as an event-level filter; in this case, we + // # return false if all particles have been filtered out + // ############################################################################ + return ! particleBank.getRowList().empty(); } diff --git a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h index 64137e93c..cd7d0a839 100644 --- a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h +++ b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h @@ -26,15 +26,11 @@ namespace iguana::example { // # - see Doxygen documentation for more details, or see other algorithms // ############################################################################ /// - /// @brief_algo This is a template algorithm, used as an example showing how to write an algorithm. + /// @algo_brief{This is a template algorithm, used as an example showing how to write an algorithm.} + /// @algo_type_filter /// /// Provide a more detailed description of your algorithm here. /// - /// @begin_doc_algo{example::ExampleAlgorithm | Filter} - /// @input_banks{REC::Particle} - /// @output_banks{REC::Particle} - /// @end_doc - /// /// @begin_doc_config{example/ExampleAlgorithm} /// @config_param{exampleInt | int | an example `integer` configuration parameter} /// @config_param{exampleDouble | double | an example `double` configuration parameter} @@ -63,9 +59,28 @@ namespace iguana::example { // # - each algorithm must have these methods (even if they do nothing) // ############################################################################ void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + // ############################################################################ + // # define an additional `Run` function which takes `hipo::bank` parameters + // # - the parameters should be lvalue references, i.e., `hipo::bank&`, to avoid copying the banks + // # - if a bank is ONLY read, and not modified, you should use `const`, i.e., `hipo::bank const&` + // # - in this example, `particleBank` will be modified, so we use `hipo::bank&` + // # - be sure the function itself is also marked `const` + // # - you'll also need to write Doxygen docstrings for this function + // # - use `@run_function`, so the documentation understands this is a `Run` function + // # - use `@param [in]` for a bank that is only read (type should be `hipo::bank const&`) + // # - use `@param [out]` for a bank that is newly created (type should be `hipo::bank&`) + // # - use `@param [in,out]` for a bank that is read and mutated (type should be `hipo::bank&`) + // # - use `@run_function_returns_true` if the function does not use the `bool` return value, otherwise + // # use `@returns` and explain why the return value could be `false` + // ############################################################################ + /// @run_function + /// @param [in,out] particleBank `REC::Particle` bank + /// @returns `false` if all particles are filtered out + bool Run(hipo::bank& particleBank) const; + // ############################################################################ // # additional public functions go here // # - typically these are "action functions", which expose the primary operation of an algorithm diff --git a/src/iguana/algorithms/physics/Depolarization/Algorithm.cc b/src/iguana/algorithms/physics/Depolarization/Algorithm.cc index 842573679..4597e272a 100644 --- a/src/iguana/algorithms/physics/Depolarization/Algorithm.cc +++ b/src/iguana/algorithms/physics/Depolarization/Algorithm.cc @@ -20,11 +20,17 @@ namespace iguana::physics { /////////////////////////////////////////////////////////////////////////////// - void Depolarization::Run(hipo::banklist& banks) const + bool Depolarization::Run(hipo::banklist& banks) const { - auto& inc_kin_bank = GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"); - auto& result_bank = GetBank(banks, b_result, GetClassName()); + return Run( + GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"), + GetBank(banks, b_result, GetClassName())); + } + bool Depolarization::Run( + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const + { ShowBank(inc_kin_bank, Logger::Header("INPUT INCLUSIVE KINEMATICS")); // set `result_bank` rows and rowlist to match those of `inc_kin_bank` @@ -59,6 +65,7 @@ namespace iguana::physics { } ShowBank(result_bank, Logger::Header("CREATED BANK")); + return true; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/physics/Depolarization/Algorithm.h b/src/iguana/algorithms/physics/Depolarization/Algorithm.h index e041d5ad1..2f1205b0e 100644 --- a/src/iguana/algorithms/physics/Depolarization/Algorithm.h +++ b/src/iguana/algorithms/physics/Depolarization/Algorithm.h @@ -4,18 +4,12 @@ namespace iguana::physics { - /// @brief_algo Calculate depolarization factors + /// @algo_brief{Calculate depolarization factors} + /// @algo_type_creator /// /// @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 - /// - /// @creator_note class Depolarization : public Algorithm { @@ -24,9 +18,17 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] inc_kin_bank `%physics::InclusiveKinematics`, produced by the `physics::InclusiveKinematics` algorithm + /// @param [out] result_bank `%physics::Depolarization`, which will be created + /// @run_function_returns_true + bool Run( + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const; + /// @action_function{scalar creator} compute depolarization factors /// @param Q2 @latex{Q^2}, from `iguana::physics::InclusiveKinematics` /// @param x Bjorken-@latex{x}, from `iguana::physics::InclusiveKinematics` diff --git a/src/iguana/algorithms/physics/Depolarization/Validator.cc b/src/iguana/algorithms/physics/Depolarization/Validator.cc index ba5ca07a7..4915f3745 100644 --- a/src/iguana/algorithms/physics/Depolarization/Validator.cc +++ b/src/iguana/algorithms/physics/Depolarization/Validator.cc @@ -93,7 +93,7 @@ namespace iguana::physics { } - void DepolarizationValidator::Run(hipo::banklist& banks) const + bool DepolarizationValidator::Run(hipo::banklist& banks) const { // calculate kinematics m_algo_seq->Run(banks); @@ -103,7 +103,7 @@ namespace iguana::physics { // skip events with empty bank(s) if(inc_kin_bank.getRowList().size() == 0 || depol_bank.getRowList().size() == 0) { m_log->Debug("skip this event, since it has no kinematics results"); - return; + return false; } // lock mutex and fill the plots @@ -116,6 +116,7 @@ namespace iguana::physics { for(auto& plot : plots_vs_y) plot.hist->Fill(inc_kin_bank.getDouble("y", row), plot.get_val(depol_bank, row)); } + return true; } diff --git a/src/iguana/algorithms/physics/Depolarization/Validator.h b/src/iguana/algorithms/physics/Depolarization/Validator.h index b06b74936..5f7f9b304 100644 --- a/src/iguana/algorithms/physics/Depolarization/Validator.h +++ b/src/iguana/algorithms/physics/Depolarization/Validator.h @@ -17,7 +17,7 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc index 823afef82..fda4f8735 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.cc @@ -50,16 +50,24 @@ namespace iguana::physics { /////////////////////////////////////////////////////////////////////////////// - void DihadronKinematics::Run(hipo::banklist& banks) const + bool DihadronKinematics::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"), + GetBank(banks, b_result, GetClassName())); + } + + bool DihadronKinematics::Run( + hipo::bank const& particle_bank, + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const { - auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); - auto& inc_kin_bank = GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"); - auto& result_bank = GetBank(banks, b_result, GetClassName()); ShowBank(particle_bank, Logger::Header("INPUT PARTICLES")); if(particle_bank.getRowList().empty() || inc_kin_bank.getRowList().empty()) { m_log->Debug("skip this event, since not all required banks have entries"); - return; + return false; } // get beam and target momenta @@ -195,6 +203,7 @@ namespace iguana::physics { } ShowBank(result_bank, Logger::Header("CREATED BANK")); + return true; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h index 8052c52ef..9d0362aee 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/DihadronKinematics/Algorithm.h @@ -7,12 +7,8 @@ namespace iguana::physics { - /// @brief_algo Calculate semi-inclusive dihadron kinematic quantities defined in `iguana::physics::DihadronKinematicsVars` - /// - /// @begin_doc_algo{physics::DihadronKinematics | Creator} - /// @input_banks{REC::Particle, %physics::InclusiveKinematics} - /// @output_banks{%physics::DihadronKinematics} - /// @end_doc + /// @algo_brief{Calculate semi-inclusive dihadron kinematic quantities defined in `iguana::physics::DihadronKinematicsVars`} + /// @algo_type_creator /// /// @begin_doc_config{physics/DihadronKinematics} /// @config_param{hadron_a_list | list[int] | list of "hadron A" PDGs} @@ -36,8 +32,6 @@ 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 { @@ -46,9 +40,19 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] particle_bank `REC::Particle` + /// @param [in] inc_kin_bank `%physics::InclusiveKinematics`, produced by the `physics::InclusiveKinematics` algorithm + /// @param [out] result_bank `%physics::DihadronKinematics`, which will be created + /// @returns `false` if the input banks do not have enough information, _e.g._, if the inclusive kinematics bank is empty + bool Run( + hipo::bank const& particle_bank, + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const; + /// @brief form dihadrons by pairing hadrons /// @param particle_bank the particle bank (`REC::Particle`) /// @returns a list of pairs of hadron rows diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Validator.cc b/src/iguana/algorithms/physics/DihadronKinematics/Validator.cc index a57c08d2a..a3b78c44f 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Validator.cc +++ b/src/iguana/algorithms/physics/DihadronKinematics/Validator.cc @@ -81,7 +81,7 @@ namespace iguana::physics { } - void DihadronKinematicsValidator::Run(hipo::banklist& banks) const + bool DihadronKinematicsValidator::Run(hipo::banklist& banks) const { // calculate kinematics m_algo_seq->Run(banks); @@ -90,7 +90,7 @@ namespace iguana::physics { // skip events with no dihadrons if(result_bank.getRowList().size() == 0) { m_log->Debug("skip this event, since it has no kinematics results"); - return; + return false; } // lock mutex and fill the plots @@ -99,6 +99,7 @@ namespace iguana::physics { for(auto& plot : plot_list) plot.hist->Fill(plot.get_val(result_bank, row)); } + return true; } diff --git a/src/iguana/algorithms/physics/DihadronKinematics/Validator.h b/src/iguana/algorithms/physics/DihadronKinematics/Validator.h index d7ca5ee6f..9abaec24d 100644 --- a/src/iguana/algorithms/physics/DihadronKinematics/Validator.h +++ b/src/iguana/algorithms/physics/DihadronKinematics/Validator.h @@ -18,7 +18,7 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc index 59a180ddb..5583bc2fb 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.cc @@ -74,11 +74,19 @@ namespace iguana::physics { /////////////////////////////////////////////////////////////////////////////// - void InclusiveKinematics::Run(hipo::banklist& banks) const + bool InclusiveKinematics::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_config, "RUN::config"), + GetBank(banks, b_result, GetClassName())); + } + + bool InclusiveKinematics::Run( + hipo::bank const& particle_bank, + hipo::bank const& config_bank, + hipo::bank& result_bank) const { - auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); - auto& config_bank = GetBank(banks, b_config, "RUN::config"); - auto& result_bank = GetBank(banks, b_result, GetClassName()); ShowBank(particle_bank, Logger::Header("INPUT PARTICLES")); auto key = PrepareEvent(config_bank.getInt("run",0)); @@ -86,7 +94,7 @@ namespace iguana::physics { auto lepton_pindex = FindScatteredLepton(particle_bank, key); if(lepton_pindex < 0) { ShowBank(result_bank, Logger::Header("CREATED BANK IS EMPTY")); - return; + return false; } auto result_vars = ComputeFromLepton( @@ -111,6 +119,7 @@ namespace iguana::physics { result_bank.putDouble(i_targetM, 0, result_vars.targetM); ShowBank(result_bank, Logger::Header("CREATED BANK")); + return true; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h index 12d2e16b9..39720c220 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Algorithm.h @@ -7,13 +7,8 @@ namespace iguana::physics { - /// @brief_algo Calculate inclusive kinematics quantities - /// - /// @begin_doc_algo{physics::InclusiveKinematics | Creator} - /// @input_banks{REC::Particle, RUN::config} - /// @output_banks{%physics::InclusiveKinematics} - /// @end_doc - /// + /// @algo_brief{Calculate inclusive kinematics quantities} + /// @algo_type_creator /// @begin_doc_config{physics/InclusiveKinematics} /// @config_param{beam_direction | list[double] | beam direction vector} /// @config_param{target_particle | string | target particle} @@ -21,8 +16,6 @@ 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 { @@ -31,9 +24,20 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] particle_bank `REC::Particle` + /// @param [in] config_bank `RUN::config` + /// @param [out] result_bank `%physics::InclusiveKinematics`, which will be created + /// @returns `true` if the kinematics were calculated; _e.g._, if the calculations are performed using + /// the scattered lepton, and no scattered lepton was found, `false` will be returned + bool Run( + hipo::bank const& particle_bank, + hipo::bank const& config_bank, + hipo::bank& result_bank) const; + /// @action_function{reload} prepare the event /// @when_to_call{for each event} /// @param runnum the run number diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Validator.cc b/src/iguana/algorithms/physics/InclusiveKinematics/Validator.cc index 97b6b52c5..ed8ba80e6 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Validator.cc +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Validator.cc @@ -50,7 +50,7 @@ namespace iguana::physics { } - void InclusiveKinematicsValidator::Run(hipo::banklist& banks) const + bool InclusiveKinematicsValidator::Run(hipo::banklist& banks) const { // calculate kinematics m_algo_seq->Run(banks); @@ -59,7 +59,7 @@ namespace iguana::physics { if(result_bank.getRowList().size() == 0) { m_log->Debug("skip this event, since it has no inclusive kinematics results"); - return; + return false; } if(result_bank.getRowList().size() > 1) { m_log->Warn("found event with more than 1 inclusive kinematics bank rows; only the first row will be used"); @@ -95,6 +95,7 @@ namespace iguana::physics { Q2_vs_W->Fill(W, Q2); y_dist->Fill(y); nu_dist->Fill(nu); + return true; } diff --git a/src/iguana/algorithms/physics/InclusiveKinematics/Validator.h b/src/iguana/algorithms/physics/InclusiveKinematics/Validator.h index f5550cf33..4df6b859b 100644 --- a/src/iguana/algorithms/physics/InclusiveKinematics/Validator.h +++ b/src/iguana/algorithms/physics/InclusiveKinematics/Validator.h @@ -18,7 +18,7 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc index 10136d0e6..96ec027f0 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.cc @@ -34,16 +34,24 @@ namespace iguana::physics { /////////////////////////////////////////////////////////////////////////////// - void SingleHadronKinematics::Run(hipo::banklist& banks) const + bool SingleHadronKinematics::Run(hipo::banklist& banks) const + { + return Run( + GetBank(banks, b_particle, "REC::Particle"), + GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"), + GetBank(banks, b_result, GetClassName())); + } + + bool SingleHadronKinematics::Run( + hipo::bank const& particle_bank, + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const { - auto& particle_bank = GetBank(banks, b_particle, "REC::Particle"); - auto& inc_kin_bank = GetBank(banks, b_inc_kin, "physics::InclusiveKinematics"); - auto& result_bank = GetBank(banks, b_result, GetClassName()); ShowBank(particle_bank, Logger::Header("INPUT PARTICLES")); if(particle_bank.getRowList().empty() || inc_kin_bank.getRowList().empty()) { m_log->Debug("skip this event, since not all required banks have entries"); - return; + return false; } // get beam and target momenta @@ -159,6 +167,7 @@ namespace iguana::physics { result_bank.getMutableRowList().setList(result_bank_rowlist); ShowBank(result_bank, Logger::Header("CREATED BANK")); + return true; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h index 3cacca337..650859b18 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Algorithm.h @@ -6,12 +6,8 @@ namespace iguana::physics { - /// @brief_algo Calculate semi-inclusive hadron kinematic quantities - /// - /// @begin_doc_algo{physics::SingleHadronKinematics | Creator} - /// @input_banks{REC::Particle, %physics::InclusiveKinematics} - /// @output_banks{%physics::SingleHadronKinematics} - /// @end_doc + /// @algo_brief{Calculate semi-inclusive hadron kinematic quantities} + /// @algo_type_creator /// /// @begin_doc_config{physics/SingleHadronKinematics} /// @config_param{hadron_list | list[int] | calculate kinematics for these hadron PDGs} @@ -25,8 +21,6 @@ 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 { @@ -35,9 +29,19 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; + /// @run_function + /// @param [in] particle_bank `REC::Particle` + /// @param [in] inc_kin_bank `%physics::InclusiveKinematics`, produced by the `physics::InclusiveKinematics` algorithm + /// @param [out] result_bank `%physics::SingleHadronKinematics`, which will be created + /// @returns `false` if the input banks do not have enough information, _e.g._, if the inclusive kinematics bank is empty + bool Run( + hipo::bank const& particle_bank, + hipo::bank const& inc_kin_bank, + hipo::bank& result_bank) const; + private: // banklist indices diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.cc b/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.cc index c1e839e2b..a62de941c 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.cc +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.cc @@ -72,7 +72,7 @@ namespace iguana::physics { } - void SingleHadronKinematicsValidator::Run(hipo::banklist& banks) const + bool SingleHadronKinematicsValidator::Run(hipo::banklist& banks) const { // calculate kinematics m_algo_seq->Run(banks); @@ -81,7 +81,7 @@ namespace iguana::physics { // skip events with no hadrons if(result_bank.getRowList().size() == 0) { m_log->Debug("skip this event, since it has no kinematics results"); - return; + return false; } // lock mutex and fill the plots @@ -90,6 +90,7 @@ namespace iguana::physics { for(auto& plot : plot_list) plot.hist->Fill(plot.get_val(result_bank, row)); } + return true; } diff --git a/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.h b/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.h index 3017da570..be4515cdb 100644 --- a/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.h +++ b/src/iguana/algorithms/physics/SingleHadronKinematics/Validator.h @@ -18,7 +18,7 @@ namespace iguana::physics { public: void Start(hipo::banklist& banks) override; - void Run(hipo::banklist& banks) const override; + bool Run(hipo::banklist& banks) const override; void Stop() override; private: diff --git a/src/iguana/bankdefs/bankgen.py b/src/iguana/bankdefs/bankgen.py index bda528f2d..1cdba6b27 100755 --- a/src/iguana/bankdefs/bankgen.py +++ b/src/iguana/bankdefs/bankgen.py @@ -30,6 +30,15 @@ def trailing_comma(arr, idx): 'D': 'double', 'L': 'long', } +# and to a more standard name, for documentation +type_name_dict = { + 'B': 'byte', + 'S': 'short', + 'I': 'int', + 'F': 'float', + 'D': 'double', + 'L': 'long', +} # all iguana banks should have this group ID iguana_group_id = 30000 @@ -40,9 +49,10 @@ def trailing_comma(arr, idx): try: bank_defs = json.load(input_file) - # start the output C++ files + # start the output files out_h = open(f'{output_base_name}.h', 'w') out_cc = open(f'{output_base_name}.cc', 'w') + out_md = open(f'{output_base_name}.md', 'w') # start the header file with some common structs out_h.write(textwrap.dedent('''\ @@ -87,6 +97,24 @@ def trailing_comma(arr, idx): std::vector const BANK_DEFS = {{ ''')) + # start the documentation `.md` file + out_md.write(textwrap.dedent('''\ + @defgroup created_banks Banks Created by Iguana Algorithms + + The following tables describe banks created by creator-type algorithms. Often the bank name matches the algorithm name, but not always. + + The variable types and their corresponding accessor methods from `hipo::bank` are: + + | Type Specification | `hipo::bank` accessor | + | --- | --- | + | `byte` | `getByte` | + | `short` | `getShort` | + | `int` | `getInt` | + | `long` | `getLong` | + | `float` | `getFloat` | + | `double` | `getDouble` | + ''')) + # loop over bank definitions in the JSON file i_bank_def = 0 unique_item_ids = [] @@ -121,12 +149,11 @@ def trailing_comma(arr, idx): 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' + namespace_name = '::'.join(['iguana', *bank_def['algorithm'].split('::')[0:-1]]) + struct_name = bank_def['algorithm'].split('::')[-1] + 'Vars' out_h.write(textwrap.dedent(f'''\ namespace {namespace_name} {{ - /// Set of variables created by creator algorithm `iguana::{algo_name}` + /// Set of variables created by creator algorithm `iguana::{bank_def['algorithm']}` struct {struct_name} {{ ''')) for entry in bank_def['entries']: @@ -141,10 +168,27 @@ def trailing_comma(arr, idx): out_h.write(' };\n') out_h.write('}\n\n') + # add a table to the documentation + out_md.write(textwrap.dedent(f'''\ + +

+ ## `{bank_def['name']}` + + **Description:** {bank_def['info']} + + **Creator Algorithm:** `iguana::{bank_def['algorithm']}` + + | Variable | Type | Description | + | --- | --- | --- | + ''')) + for entry in bank_def['entries']: + out_md.write(f'| `{entry["name"]}` | `{type_name_dict[entry["type"]]}` | {entry["info"]} |\n') + out_cc.write(' };\n') out_cc.write('}\n') out_cc.close() out_h.close() + out_md.close() except json.decoder.JSONDecodeError: print(f'ERROR: failed to parse {input_file_name}; check its JSON syntax', file=sys.stderr) diff --git a/src/iguana/bankdefs/iguana.json b/src/iguana/bankdefs/iguana.json index e0ae6e116..08842f75d 100644 --- a/src/iguana/bankdefs/iguana.json +++ b/src/iguana/bankdefs/iguana.json @@ -4,7 +4,7 @@ "algorithm": "clas12::SectorFinder", "group": 30000, "item": 1, - "info": "", + "info": "sector information for each particle", "entries": [ { "name": "pindex", "type": "S", "info": "row number in the particle bank" }, { "name": "sector", "type": "I", "info": "sector for this particle" } @@ -15,7 +15,7 @@ "algorithm": "physics::InclusiveKinematics", "group": 30000, "item": 2, - "info": "", + "info": "inclusive kinematics", "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})" }, @@ -36,7 +36,7 @@ "algorithm": "physics::SingleHadronKinematics", "group": 30000, "item": 3, - "info": "", + "info": "SIDIS single-hadron kinematics", "entries": [ { "name": "pindex", "type": "S", "info": "`REC::Particle` row (`pindex`) of the hadron" }, { "name": "pdg", "type": "I", "info": "PDG code of the hadron" }, @@ -54,7 +54,7 @@ "algorithm": "physics::DihadronKinematics", "group": 30000, "item": 4, - "info": "", + "info": "SIDIS dihadron kinematics", "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" }, @@ -76,7 +76,7 @@ "algorithm": "physics::Depolarization", "group": 30000, "item": 5, - "info": "", + "info": "SIDIS depolarization factors", "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)}" }, @@ -91,7 +91,7 @@ "algorithm": "clas12::CalorimeterLinker", "group": 30000, "item": 6, - "info": "", + "info": "calorimeter information linked to particles", "entries": [ { "name": "pindex", "type": "S", "info": "row number in the particle bank" }, { "name": "pcal_found", "type": "B", "info": "1 if PCAL info found for this particle, 0 otherwise" }, @@ -119,7 +119,7 @@ "algorithm": "clas12::TrajLinker", "group": 30000, "item": 7, - "info": "", + "info": "trajectory information linked to particles", "entries": [ { "name": "pindex", "type": "S", "info": "row number in the particle bank" }, { "name": "sector", "type": "I", "info": "sector" }, diff --git a/src/iguana/bankdefs/meson.build b/src/iguana/bankdefs/meson.build index 897f6f3f7..720a82bdd 100644 --- a/src/iguana/bankdefs/meson.build +++ b/src/iguana/bankdefs/meson.build @@ -10,10 +10,10 @@ bankdef_tgt = custom_target( bankdef_json, prog_bankgen_sources, ], - output: [ 'BankDefs.h', 'BankDefs.cc' ], + output: [ 'BankDefs.h', 'BankDefs.cc', 'BankDefs.md' ], command: [ prog_bankgen, '@INPUT0@', '@OUTDIR@/BankDefs' ], install: true, - install_dir: [ get_option('includedir') / meson.project_name() / 'bankdefs', false ], + install_dir: [ get_option('includedir') / meson.project_name() / 'bankdefs', false, false ], ) # install the JSON data model file; iguana won't need it, but it can be useful for user reference