| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "Algorithm.h" | ||
| 4 | |||
| 5 | namespace iguana { | ||
| 6 | |||
| 7 | /// @algo_brief{An algorithm that can run a sequence of algorithms} | ||
| 8 | /// | ||
| 9 | /// This algorithm requires the use of `hipo::banklist`; there are neither `Run` functions which take | ||
| 10 | /// individual `hipo::bank` parameters nor action functions. If you do not use `hipo::banklist`, you | ||
| 11 | /// should use individual algorithms instead of this sequencing algorithm. | ||
| 12 | /// | ||
| 13 | /// Use the `Add` function to add algorithms to the sequence; the order is important, since | ||
| 14 | /// the `Start`, `Run`, and `Stop` methods will sequentially call the corresponding algorithms' methods, | ||
| 15 | /// in the same order that the algorithms were added to the sequence by `Add`. | ||
| 16 | /// | ||
| 17 | /// If an algorithm's `Run` function returns `false`, _i.e._, its "event-level" filter returns `false`, then `AlgorithmSequence`'s | ||
| 18 | /// `Run` function will stop immediately and return `false`. | ||
| 19 | /// | ||
| 20 | /// @par Custom Event Filters | ||
| 21 | /// If an algorithm's event-level filter is not adequate for your needs, and you want to tighten or override | ||
| 22 | /// an algorithm's event-level filter, _i.e._, you want more control over how that algorithm's `Run` function return | ||
| 23 | /// value is used, we recommond defining _two_ `AlgorithmSequence` instances. For example, suppose you want a tighter | ||
| 24 | /// event-level filter from or after `algo2` in the sequence `algo1`, `algo2`, `algo3`, `algo4`; you may implement this by | ||
| 25 | /// using _two_ sequences, where the first ends at `algo2`: | ||
| 26 | /// @code | ||
| 27 | /// // define sequences | ||
| 28 | /// iguana::AlgorithmSequence seq1 | ||
| 29 | /// seq1.Add("algo1"); | ||
| 30 | /// seq1.Add("algo2"); | ||
| 31 | /// iguana::AlgorithmSequence seq2 | ||
| 32 | /// seq2.Add("algo3"); | ||
| 33 | /// seq2.Add("algo4"); | ||
| 34 | /// // start them | ||
| 35 | /// seq1.Start(banks); | ||
| 36 | /// seq2.Start(banks); | ||
| 37 | /// @endcode | ||
| 38 | /// Then, in your event loop, call your tighter filter between the sequences' `Run` calls: | ||
| 39 | /// @code | ||
| 40 | /// if(!seq1.Run(banks)) continue; | ||
| 41 | /// if( /*your event filter */) continue; | ||
| 42 | /// if(!seq2.Run(banks)) continue; | ||
| 43 | /// @endcode | ||
| 44 | /// | ||
| 45 | class AlgorithmSequence : public Algorithm | ||
| 46 | { | ||
| 47 | |||
| 48 |
6/14✓ Branch 2 → 3 taken 27 times.
✗ Branch 2 → 6 not taken.
✗ Branch 5 → 7 not taken.
✓ Branch 5 → 8 taken 27 times.
✓ Branch 9 → 10 taken 27 times.
✗ Branch 9 → 32 not taken.
✓ Branch 10 → 11 taken 27 times.
✗ Branch 10 → 17 not taken.
✓ Branch 17 → 18 taken 27 times.
✗ Branch 17 → 40 not taken.
✓ Branch 24 → 25 taken 27 times.
✗ Branch 24 → 40 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 39 not taken.
|
198 | DEFINE_IGUANA_ALGORITHM(AlgorithmSequence, seq) |
| 49 | |||
| 50 | public: | ||
| 51 | |||
| 52 | void Start(hipo::banklist& banks) override; | ||
| 53 | bool Run(hipo::banklist& banks) const override; | ||
| 54 | void Stop() override; | ||
| 55 | |||
| 56 | /// Create and add an algorithm to the sequence, by name. | ||
| 57 | /// | ||
| 58 | /// **Example** | ||
| 59 | /// @code | ||
| 60 | /// Add("iguana::MyAlgorithm", "my_algorithm_name"); | ||
| 61 | /// @endcode | ||
| 62 | /// @param algo_class_name the name of the algorithm class | ||
| 63 | /// @param algo_instance_name a user-specified unique name for this algorithm instance; | ||
| 64 | /// if not specified, `algo_class_name` will be used | ||
| 65 |
7/18✗ Branch 17 → 18 not taken.
✗ Branch 17 → 137 not taken.
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 298 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 137 not taken.
✓ Branch 28 → 29 taken 6 times.
✗ Branch 28 → 108 not taken.
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 298 not taken.
✓ Branch 37 → 38 taken 16 times.
✗ Branch 37 → 108 not taken.
✓ Branch 44 → 45 taken 16 times.
✗ Branch 44 → 108 not taken.
✓ Branch 47 → 48 taken 1 time.
✗ Branch 47 → 298 not taken.
✓ Branch 60 → 61 taken 1 time.
✗ Branch 60 → 298 not taken.
|
73 | void Add(std::string const& algo_class_name, std::string const& algo_instance_name = ""); |
| 66 | |||
| 67 | /// Create and add an algorithm to the sequence. | ||
| 68 | /// | ||
| 69 | /// **Example** | ||
| 70 | /// @code | ||
| 71 | /// Add<iguana::MyAlgorithm>("my_algorithm_name"); | ||
| 72 | /// @endcode | ||
| 73 | /// @param algo_instance_name a user-specified unique name for this algorithm instance; | ||
| 74 | /// if not specified, the class name will be used | ||
| 75 | template <class ALGORITHM> | ||
| 76 | void Add(std::string_view algo_instance_name = "") | ||
| 77 | { | ||
| 78 | if(algo_instance_name == "") | ||
| 79 | Add(std::make_unique<ALGORITHM>()); | ||
| 80 | else | ||
| 81 | Add(std::make_unique<ALGORITHM>(algo_instance_name)); | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Add an existing algorithm to the sequence. The `AlgorithmSequence` instance will take ownership of the algorithm | ||
| 85 | /// (if it is an `lvalue`, you will have to `std::move` it). | ||
| 86 | /// | ||
| 87 | /// **Example** | ||
| 88 | /// @code | ||
| 89 | /// Add(std::make_unique<iguana::MyAlgorithm>("my_algorithm_name")); | ||
| 90 | /// @endcode | ||
| 91 | /// @param algo the algorithm | ||
| 92 | void Add(algo_t&& algo); | ||
| 93 | |||
| 94 | /// Get an algorithm by its instance name | ||
| 95 | /// | ||
| 96 | /// **Example** | ||
| 97 | /// @code | ||
| 98 | /// Get<iguana::MyAlgorithm>("my_algorithm_name"); | ||
| 99 | /// @endcode | ||
| 100 | /// @param algo_instance_name the instance name of the algorithm | ||
| 101 | /// @return a reference to the algorithm | ||
| 102 | template <class ALGORITHM = Algorithm> | ||
| 103 | 1906 | ALGORITHM* Get(std::string const& algo_instance_name) | |
| 104 | { | ||
| 105 |
2/4iguana::Algorithm* iguana::AlgorithmSequence::Get<iguana::Algorithm>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 5 → 6 taken 67 times.
✗ Branch 5 → 8 not taken.
iguana::clas12::PhotonGBTFilter* iguana::AlgorithmSequence::Get<iguana::clas12::PhotonGBTFilter>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 5 → 6 taken 1839 times.
✗ Branch 5 → 9 not taken.
|
1906 | if(auto it{m_algo_names.find(algo_instance_name)}; it != m_algo_names.end()) |
| 106 |
1/2✓ Branch 7 → 8 taken 1839 times.
✗ Branch 7 → 13 not taken.
|
1906 | return dynamic_cast<ALGORITHM*>(m_sequence[it->second].get()); |
| 107 | ✗ | m_log->Error("cannot find algorithm '{}' in sequence", algo_instance_name); | |
| 108 | ✗ | throw std::runtime_error("cannot Get algorithm"); | |
| 109 | } | ||
| 110 | |||
| 111 | /// Set an algorithm option | ||
| 112 | /// @see `Algorithm::SetOption` | ||
| 113 | /// @param algo_instance_name the algorithm instance name | ||
| 114 | /// @param key the option name | ||
| 115 | /// @param val the option value | ||
| 116 | template <typename OPTION_TYPE> | ||
| 117 | 11 | void SetOption(std::string const& algo_instance_name, std::string const& key, const OPTION_TYPE val) | |
| 118 | { | ||
| 119 |
17/40void iguana::AlgorithmSequence::SetOption<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 6 → 7 taken 2 times.
✗ Branch 6 → 18 not taken.
void iguana::AlgorithmSequence::SetOption<std::vector<int, std::allocator<int> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<int, std::allocator<int> >):
✓ Branch 4 → 5 taken 8 times.
✗ Branch 4 → 12 not taken.
✓ Branch 35 → 36 taken 2 times.
✗ Branch 35 → 151 not taken.
✗ Branch 35 → 177 not taken.
✓ Branch 36 → 37 taken 2 times.
✗ Branch 36 → 151 not taken.
✗ Branch 36 → 177 not taken.
✓ Branch 62 → 63 taken 1 time.
✗ Branch 62 → 228 not taken.
✓ Branch 63 → 64 taken 1 time.
✗ Branch 63 → 228 not taken.
✓ Branch 77 → 78 taken 1 time.
✗ Branch 77 → 240 not taken.
✓ Branch 78 → 79 taken 1 time.
✗ Branch 78 → 240 not taken.
✓ Branch 92 → 93 taken 1 time.
✗ Branch 92 → 252 not taken.
✓ Branch 93 → 94 taken 1 time.
✗ Branch 93 → 252 not taken.
void iguana::AlgorithmSequence::SetOption<std::vector<double, std::allocator<double> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<double, std::allocator<double> >):
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 12 not taken.
None:
✓ Branch 22 → 23 taken 1 time.
✗ Branch 22 → 106 not taken.
✓ Branch 23 → 24 taken 1 time.
✗ Branch 23 → 106 not taken.
✓ Branch 35 → 36 taken 1 time.
✗ Branch 35 → 226 not taken.
✓ Branch 36 → 37 taken 1 time.
✗ Branch 36 → 226 not taken.
✓ Branch 49 → 50 taken 16 times.
✗ Branch 49 → 102 not taken.
✓ Branch 50 → 51 taken 16 times.
✗ Branch 50 → 102 not taken.
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 131 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 131 not taken.
|
36 | Get<Algorithm>(algo_instance_name)->SetOption(key, val); |
| 120 | 34 | } | |
| 121 | |||
| 122 | /// Set the name of this sequence | ||
| 123 | /// @param name the new name | ||
| 124 | void SetName(std::string_view name); | ||
| 125 | |||
| 126 | /// Get the list of created bank names, for creator-type algorithms | ||
| 127 | /// @see `AlgorithmSequence::GetCreatedBankName` for algorithms which create only one bank | ||
| 128 | /// @param algo_instance_name the algorithm instance name | ||
| 129 | /// @returns the list of new bank names | ||
| 130 | std::vector<std::string> GetCreatedBankNames(std::string const& algo_instance_name) const noexcept(false); | ||
| 131 | |||
| 132 | /// Get the created bank name, for creator-type algorithms which create only one new bank | ||
| 133 | /// @see `AlgorithmSequence::GetCreatedBankNames` for algorithms which create more than one new bank | ||
| 134 | /// @param algo_instance_name the algorithm instance name | ||
| 135 | /// @returns the new bank name | ||
| 136 | std::string GetCreatedBankName(std::string const& algo_instance_name) const noexcept(false); | ||
| 137 | |||
| 138 | /// Print the names of the algorithms in this sequence | ||
| 139 | /// @param level the log level of the printout | ||
| 140 | void PrintSequence(Logger::Level level = Logger::info) const; | ||
| 141 | |||
| 142 | /// @brief Set a custom configuration file for each algorithm in the sequence | ||
| 143 | /// | ||
| 144 | /// Use this function if you have a single configuration file for all the | ||
| 145 | /// algorithms in your sequence | ||
| 146 | /// @param name the configuration file name | ||
| 147 | void SetConfigFileForEachAlgorithm(std::string const& name); | ||
| 148 | |||
| 149 | /// @brief Set a custom configuration file directory for each algorithm in the sequence | ||
| 150 | /// | ||
| 151 | /// Use this function if you have a single configuration file directory for all the | ||
| 152 | /// algorithms in your sequence | ||
| 153 | /// @param name the directory name | ||
| 154 | void SetConfigDirectoryForEachAlgorithm(std::string const& name); | ||
| 155 | |||
| 156 | /// @brief Call a function for each algorithm in the sequence | ||
| 157 | /// | ||
| 158 | /// Use as: | ||
| 159 | /// ```cpp | ||
| 160 | /// ForEachAlgorithm([](auto& algo){ algo->...; }); | ||
| 161 | /// ``` | ||
| 162 | /// @param func the function to call for each algorithm `algo` | ||
| 163 | void ForEachAlgorithm(std::function<void(algo_t&)> func); | ||
| 164 | |||
| 165 | /// Get the index of a bank in a `hipo::banklist`; throws an exception if the bank is not found | ||
| 166 | /// @param banks the list of banks this algorithm will use | ||
| 167 | /// @param bank_name the name of the bank | ||
| 168 | /// @param algo_instance_name the algorithm instance name, | ||
| 169 | /// to disambiguate the case where two algorithms create a bank with the same name (_cf._ `variant` parameter of tools::GetBankIndex) | ||
| 170 | /// @returns the `hipo::banklist` index of the bank | ||
| 171 | /// @see tools::GetBankIndex for a function that is independent of algorithm | ||
| 172 | /// @see GetCreatedBankIndex, a convenience method for _Iguana-created_ banks | ||
| 173 | hipo::banklist::size_type GetBankIndex( | ||
| 174 | hipo::banklist& banks, | ||
| 175 | std::string const& bank_name, | ||
| 176 | std::string const& algo_instance_name) const noexcept(false); | ||
| 177 | |||
| 178 | /// Get the index of an _Iguana-created_ bank in a `hipo::banklist`; throws an exception if the bank is not found, or if the algorithm | ||
| 179 | /// creates more than one bank | ||
| 180 | /// @param banks the list of banks this algorithm will use | ||
| 181 | /// @param algo_instance_name the algorithm instance name, | ||
| 182 | /// to disambiguate the case where two algorithms create a bank with the same name (_cf._ `variant` parameter of tools::GetBankIndex) | ||
| 183 | /// @returns the `hipo::banklist` index of the bank | ||
| 184 | /// @see GetBankIndex for a more general method | ||
| 185 | hipo::banklist::size_type GetCreatedBankIndex( | ||
| 186 | hipo::banklist& banks, | ||
| 187 | std::string const& algo_instance_name) const noexcept(false); | ||
| 188 | |||
| 189 | private: | ||
| 190 | |||
| 191 | /// The sequence of algorithms | ||
| 192 | std::vector<algo_t> m_sequence; | ||
| 193 | |||
| 194 | /// Association of algorithm name to its index in the sequence | ||
| 195 | std::unordered_map<std::string, std::vector<algo_t>::size_type> m_algo_names; | ||
| 196 | }; | ||
| 197 | } | ||
| 198 |