GCC Code Coverage Report


Directory: ./
File: include/na64calib/indices/range-override.hh
Date: 2025-09-01 06:19:01
Exec Total Coverage
Lines: 6 79 7.6%
Functions: 1 18 5.6%
Branches: 4 13 30.8%

Line Branch Exec Source
1 /* This file is a part of NA64SW software.
2 * Copyright (C) 2015-2022 NA64 Collaboration, CERN
3 *
4 * NA64SW is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 #pragma once
18
19 #include "na64sw-config.h"
20 #include "na64util/na64/event-id.hh"
21 #include "na64calib/manager.hh"
22 #include "na64util/demangle.hh"
23
24 #include <map>
25 #include <cassert>
26
27 #include <yaml-cpp/yaml.h>
28
29 namespace na64dp {
30 namespace errors {
31
32 /// Indexing container has no valid range wrt given value
33 class NoValidForRange : public std::runtime_error {
34 public:
35 NoValidForRange()
36 : std::runtime_error( "No valid entry has been found for event." ) {}
37 };
38
39 } // namespace na64dp::error
40
41 namespace calib {
42
43 namespace aux {
44 /// This auxiliary function is used by RangeOverrideRunIndex::to_yaml() to
45 /// represent a key
46 template<typename KeyT> std::string key_to_str_for_yaml(KeyT k) {
47 std::ostringstream oss;
48 oss << k;
49 return oss.str();
50 }
51
52 /// Specialization for time structure
53 template<> std::string key_to_str_for_yaml(std::pair<time_t, uint32_t>);
54
55 /// Specialization for run number
56 template<> std::string key_to_str_for_yaml(EventID);
57
58 template<typename KeyT> std::pair<KeyT, KeyT>
59 deduce_key( EventID oldEventID, EventID newEventID
60 , const std::pair<time_t, uint32_t> & oldDatetime
61 , const std::pair<time_t, uint32_t> & newDateTime
62 );
63
64 template<> std::pair<EventID, EventID>
65 deduce_key( EventID oldEventID, EventID newEventID
66 , const std::pair<time_t, uint32_t> & oldDatetime
67 , const std::pair<time_t, uint32_t> & newDateTime
68 );
69
70 template<> std::pair<std::pair<time_t, uint32_t>, std::pair<time_t, uint32_t>>
71 deduce_key( EventID oldEventID, EventID newEventID
72 , const std::pair<time_t, uint32_t> & oldDatetime
73 , const std::pair<time_t, uint32_t> & newDateTime
74 );
75
76 } // namespace ::na64dp::calib::aux
77
78 /**\brief A runs validity range index helper class.
79 *
80 * Maps objects that are valid _from_ certain run number. This helper class
81 * incapsulates `std::upper_bound()` over sorted associative array to provide
82 * a bit more intuitive way of retreiving the data associated with range.
83 *
84 * Ususal application is to index calibration data wrt runs ranges. */
85 template<typename KeyT, typename T, typename Compare = std::less<KeyT>>
86 class RangeIndex : public std::map<KeyT, T, Compare> {
87 public:
88 typedef std::map<KeyT, T, Compare> Parent;
89 public:
90 typename Parent::iterator
91 11 get_valid_entry_for(KeyT rn) {
92
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 assert( !Parent::empty() );
93 // it->first > rn, i.e. get iterator to the next element
94
1/1
✓ Branch 1 taken 11 times.
11 auto it = Parent::upper_bound( rn );
95
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
11 if( it == Parent::begin() ) {
96 1 return Parent::end();
97 }
98 // Return element previous to upper bound
99 10 return --it;
100 }
101 };
102
103 /**\brief A basic externally-configured calibration index class.
104 *
105 * Indexes calibration entries by key. Each entry of certain
106 * calibration type considered valid *from* certain key value *until* the
107 * next key value. The `validTo` attribute to the update recipe is considered
108 * only on the update loading and may result in a runtime expression.
109 */
110 template<typename KeyT, typename T, typename Compare = std::less<KeyT>>
111 class RangeOverrideRunIndex : public virtual iIndex {
112 public:
113 struct UpdateRecipe : public iSpecificUpdate<T> {
114 Dispatcher::CIDataID subjectDataType;
115 KeyT validTo;
116 std::shared_ptr<iLoader> recommendedLoader;
117
118 UpdateRecipe( Dispatcher::CIDataID dt
119 , KeyT validTo_
120 , std::shared_ptr<iLoader> lPtr
121 , const T pl
122 ) : iSpecificUpdate<T>(pl)
123 , subjectDataType(dt)
124 , validTo(validTo_)
125 , recommendedLoader(lPtr)
126 {}
127
128 Dispatcher::CIDataID subject_data_type() const override
129 { return subjectDataType; }
130 iLoader * recommended_loader() const override
131 { return recommendedLoader.get(); }
132 };
133 private:
134 /// Collection of run range sub-indexes, grouped by calibration data type
135 std::unordered_map< std::string
136 , RangeIndex< KeyT, UpdateRecipe, Compare >
137 > _types;
138 public:
139 virtual ~RangeOverrideRunIndex() {}
140 /// Collects calibration information differences between two time
141 /// moments/runs
142 void append_updates( EventID oldEventID, EventID newEventID
143 , const std::pair<time_t, uint32_t> & oldDatetime
144 , const std::pair<time_t, uint32_t> & newDateTime
145 , Updates & ul ) override {
146 auto keys = aux::deduce_key<KeyT>( oldEventID, newEventID
147 , oldDatetime, newDateTime
148 );
149 for( auto it = _types.begin()
150 ; _types.end() != it
151 ; ++it ) {
152 auto cidID = it->first;
153 auto & runIdx = it->second;
154 auto oldEntryIt = runIdx.get_valid_entry_for( keys.first )
155 , newEntryIt = runIdx.get_valid_entry_for( keys.second )
156 ;
157 if( oldEntryIt == newEntryIt ) continue;
158 if( runIdx.end() == newEntryIt ) {
159 throw errors::NoValidForRange();
160 }
161 ul.push_back(&(newEntryIt->second));
162 log4cpp::Category::getInstance("calibrations.indeces.rangeOverride")
163 << log4cpp::Priority::DEBUG
164 << "Update of (aliased) type \""
165 << it->first
166 << "\" with validity ("
167 << aux::key_to_str_for_yaml(newEntryIt->first)
168 << ") has been pushed into updates list for "
169 << "/("
170 << aux::key_to_str_for_yaml(oldEventID) << "), ("
171 << aux::key_to_str_for_yaml(newEventID) << ")/ -> /("
172 << aux::key_to_str_for_yaml(oldDatetime) << ", "
173 << aux::key_to_str_for_yaml(newDateTime) << ")/"
174 << "."
175 ;
176 }
177 }
178
179 /// Adds new calibration data entry into index
180 void add_entry( KeyT k
181 , const std::string & typeKey
182 , const UpdateRecipe & updRecipe
183 ) {
184 // find or insert typed entry (ranges index)
185 auto tIt = _types.find( typeKey );
186 if( _types.end() == tIt ) {
187 auto ir = _types.emplace( typeKey
188 , RangeIndex<KeyT, UpdateRecipe, Compare>() );
189 tIt = ir.first;
190 }
191 // emplace new entry
192 RangeIndex< KeyT, UpdateRecipe, Compare> & rangeIndex = tIt->second;
193 auto ir = rangeIndex.emplace(k, updRecipe);
194 if( ! ir.second ) {
195 log4cpp::Category::getInstance("calibrations.indeces.rangeOverride").warn(
196 "Doubling specification for calibration"
197 " data %s."
198 , typeKey.c_str()
199 //, std::to_string(k.to_str())
200 );
201 } else {
202 log4cpp::Category::getInstance("calibrations.indeces.rangeOverride")
203 << log4cpp::Priority::DEBUG
204 << "RangeOverrideRunIndex::add_entry("
205 << aux::key_to_str_for_yaml(k) << ", "
206 << typeKey << ", ("
207 << aux::key_to_str_for_yaml(updRecipe.validTo)
208 << ", ...)"
209 ;
210 }
211 }
212 /// Dumps content of the index index to YAML node for debugging
213 void to_yaml(YAML::Node & outNode) const override {
214 outNode["keyType"]
215 = std::string(util::demangle_cpp(typeid(KeyT).name()).get());
216 outNode["valueType"]
217 = std::string(util::demangle_cpp(typeid(T).name()).get());
218 YAML::Node typesNode;
219 for( auto subIdxPair : _types ) {
220 char bf[64];
221 // NOTE: subIdxPair.second is always of UpdateRecipe
222 YAML::Node typedNode;
223 size_t nEntry = 0;
224 for( auto updPair : subIdxPair.second ) {
225 YAML::Node entryNode;
226 entryNode["validFrom"] = aux::key_to_str_for_yaml(updPair.first);
227 entryNode["validTo"] = aux::key_to_str_for_yaml(updPair.second.validTo);
228 entryNode["subjectType"] = util::calib_id_to_str(updPair.second.subjectDataType);
229 snprintf(bf, sizeof(bf), "%p", updPair.second.recommendedLoader.get());
230 typedNode["recommendedLoader"] = bf;
231 updPair.second.to_yaml(entryNode);
232 typedNode[nEntry++] = entryNode;
233 }
234 typesNode[subIdxPair.first] = typedNode;
235 }
236 outNode["byTypeAlias"] = typesNode;
237 }
238 };
239
240 } // namespace calib
241 } // namespace na64dp
242
243