Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4VUserMoleculeReactionCounter.hh
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// Author: Christian Velten (2025)
27
28#ifndef G4VUSERMOLECULEREACTIONCOUNTER_HH
29#define G4VUSERMOLECULEREACTIONCOUNTER_HH 1
30
33#include "G4Scheduler.hh"
34#include "G4UnitsTable.hh"
36
37//------------------------------------------------------------------------------
38
39template<class TIndex>
40class G4VUserMoleculeReactionCounter : public G4VMoleculeReactionCounter
41{
42 static_assert(std::is_base_of<G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex, TIndex>::value,
43 "TIndex must be derived from G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex! "
44 "No forward declaration is allowed.");
45
46 protected:
47 struct Search;
48
49 public:
53 ~G4VUserMoleculeReactionCounter() override = default;
54
55 public:
56 void Initialize() final;
57 void InitializeUser() override = 0;
58 void ResetCounter() override;
59 void Dump() const override;
60 void DumpCounterMapIndices() const override;
61
63
65
67
69 std::set<G4double> GetRecordedTimes() const override;
70
71 protected:
73
74 public:
75 const std::map<TIndex, InnerCounterMapType>& GetCounterMap() const { return fCounterMap; }
76 std::vector<TIndex> GetMapIndices() const;
77
78 virtual G4int GetNbReactionsAtTime(const TIndex&, G4double) const;
79 virtual G4int GetNbReactionsAtTime(Search&, const TIndex&, G4double) const;
80 virtual std::vector<G4int> GetNbReactionsAtTimes(const TIndex&,
81 const std::vector<G4double>&) const;
82
83 //-SEARCH-----------------------------------------------------------------------
84 protected:
85 struct Search
86 {
87 Search() : fLowerBoundSet(false) {}
88 typename std::map<TIndex, InnerCounterMapType>::const_iterator fLastIndexSearched;
89 InnerCounterMapType::const_iterator fLowerBoundTime;
91 };
92 G4bool SearchIndexUpdated(Search&, const TIndex&) const;
94};
95
96//------------------------------------------------------------------------------
97
98// #include "G4VUserMoleculeReactionCounter.icc"
99
100//------------------------------------------------------------------------------
101
102template<typename T>
105
106//------------------------------------------------------------------------------
107
108template<typename T>
111 : G4VMoleculeReactionCounter(name, type)
112{}
113
114//------------------------------------------------------------------------------
115
116template<typename TIndex>
122
123//------------------------------------------------------------------------------
124
125template<typename TIndex>
127{
128 Search search = {};
129 return GetNbReactionsAtTime(search, index, time);
130}
131
132//------------------------------------------------------------------------------
133
134template<typename TIndex>
136 const TIndex& index,
137 G4double time) const
138{
139 G4bool sameIndex = !SearchIndexUpdated(search, index);
140 return SearchUpperBoundTime(search, time, sameIndex);
141}
142
143//------------------------------------------------------------------------------
144
145template<typename TIndex>
147 const TIndex& index, const std::vector<G4double>& times) const
148{
149 Search search = {};
150 std::vector<G4int> counts = {};
151 for (auto time : times)
152 counts.push_back(GetNbReactionsAtTime(search, index, time));
153 return counts;
154}
155
156//------------------------------------------------------------------------------
157
158template<typename TIndex>
160 std::unique_ptr<G4VMoleculeReactionCounter::G4VMoleculeReactionCounterIndex> pIndex,
161 G4double time, G4int number)
162{
163 const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
164
165 if (IsTimeAboveUpperBound(time)) {
166 if (fVerbose > 3) {
167 G4cout << "G4VUserMoleculeReactionCounter<"
169 << ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
170 << " at time : " << G4BestUnit(time, "Time") << G4endl;
171 G4cout << ":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true" << G4endl;
172 }
173 return;
174 }
175 else if (IsTimeBelowLowerBound(time)) {
176 if (fVerbose > 3) {
177 G4cout << "G4VUserMoleculeReactionCounter<"
179 << ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
180 << " at time : " << G4BestUnit(time, "Time") << G4endl;
181 G4cout << ":: [IsTimeBelowLowerBound] Skipping since IsTimeBelowLowerBound == true" << G4endl;
182 }
183 return;
184 }
185
186 if (fVerbose > 2) {
187 G4cout << "G4VUserMoleculeReactionCounter<"
189 << ")::RecordReaction : " << mapIndex->GetReactionData()->GetReactionID()
190 << " at time : " << G4BestUnit(time, "Time") << G4endl;
191 }
192
193 auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
194
195 if (indexIsNew || it->second.empty()) {
196 it->second.emplace(time, number);
197 // it->second[time] = number;
198 }
199 else {
200 if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent())
201 // can only do consistency check if the counters are cleared before each event
202 {
203 auto end = it->second.rbegin();
204
205 if ((end->first <= time || std::fabs(end->first - time) <= fTimeComparer.GetPrecisionAtTime(time)))
206 // Case 1 = new time comes after last recorded data
207 // Case 2 = new time is about the same as the last recorded one
208 {
209 // it->second[time] = end->second + number;
210 auto [it_time, _] = it->second.emplace(time, end->second);
211 it_time->second += number;
212 }
213 else {
215 errMsg << "Time of reaction " << mapIndex->GetReactionData()->GetReactionID() << " is "
216 << G4BestUnit(time, "Time") << "while the global time is "
217 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
218 << "(last counter time: " << G4BestUnit(end->first, "Time") << ")" << G4endl;
219 G4Exception(G4String("G4VUserMoleculeReactionCounter<"
221 + ">::RecordReaction"),
222 "TIME_DONT_MATCH", FatalException, errMsg);
223 }
224 }
225 else {
226 // since counters are not cleared after chemical run (i.e., after event)
227 // there will already be numbers in the map, so...
228 // (1) find the closest time
229 // (2) emplace entry using closest value as init + number
230 // (3) add number to all "future" entries as well
231 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(it->second, time);
232 auto [it_new, _] = it->second.emplace(time, it_closest->second);
233 do {
234 it_new->second += number;
235 } while (++it_new != it->second.end());
236 }
237 }
238}
239
240//------------------------------------------------------------------------------
241
242template<typename TIndex>
244{
245 if (fVerbose > 2) {
246 G4cout << "Entering in G4VUserMoleculeReactionCounter::GetMapIndices" << G4endl;
247 }
249}
250
251//------------------------------------------------------------------------------
252
253template<typename T>
254std::set<const G4DNAMolecularReactionData*> G4VUserMoleculeReactionCounter<T>::GetRecordedReactions() const
255{
256 if (fVerbose > 2) {
257 G4cout << "Entering in G4VUserMoleculeReactionCounter::GetRecordedReactions" << G4endl;
258 }
259 std::set<const G4DNAMolecularReactionData*> output{};
260 for (const auto& it : fCounterMap) {
261 output.insert(it.first.GetReactionData());
262 }
263 return output;
264}
265
266//------------------------------------------------------------------------------
267
268template<typename T>
273
274//------------------------------------------------------------------------------
275
276template<typename T>
282
283template<typename T>
288
289//------------------------------------------------------------------------------
290
291template<typename T>
293{
294 if (fVerbose > 1) {
295 G4cout << "G4VUserMoleculeReactionCounter<" << G4::MoleculeCounter::GetTemplateTypeName<T>()
296 << ">(" << GetName() << ")::ResetCounter" << G4endl;
297 }
298 fCounterMap.clear();
299}
300
301//------------------------------------------------------------------------------
302
303template<typename TIndex>
305{
306 if (search.fLowerBoundSet && !(search.fLastIndexSearched->first < index)
307 && !(index < search.fLastIndexSearched->first))
308 {
309 return true;
310 }
311
312 auto mol_it = fCounterMap.find(index);
313 search.fLastIndexSearched = mol_it;
314
315 if (mol_it != fCounterMap.end()) {
316 search.fLowerBoundTime = search.fLastIndexSearched->second.end();
317 search.fLowerBoundSet = true;
318 }
319 else {
320 search.fLowerBoundSet = false;
321 }
322
323 return false;
324}
325
326//------------------------------------------------------------------------------
327
328template<typename T>
330{
331 auto mol_it = search.fLastIndexSearched;
332 if (mol_it == fCounterMap.end()) {
333 return 0;
334 }
335
336 InnerCounterMapType const& timeMap = mol_it->second;
337 if (timeMap.empty()) {
338 return 0;
339 }
340
341 if (sameIndex) {
342 if (search.fLowerBoundSet && search.fLowerBoundTime != timeMap.end()) {
343 if (search.fLowerBoundTime->first < time) {
344 auto upperToLast = search.fLowerBoundTime;
345 upperToLast++;
346
347 if (upperToLast == timeMap.end()) {
348 return search.fLowerBoundTime->second;
349 }
350
351 if (upperToLast->first > time) {
352 return search.fLowerBoundTime->second;
353 }
354 }
355 }
356 }
357
358 auto up_time_it = timeMap.upper_bound(time);
359
360 if (up_time_it == timeMap.end()) {
361 auto last_time = timeMap.rbegin();
362 return last_time->second;
363 }
364 if (up_time_it == timeMap.begin()) {
365 return 0;
366 }
367
368 up_time_it--;
369
370 search.fLowerBoundTime = up_time_it;
371 search.fLowerBoundSet = true;
372
373 return search.fLowerBoundTime->second;
374}
375
376//------------------------------------------------------------------------------
377
378template<typename TIndex>
380 const G4VMoleculeCounterInternalBase* pCounterBase)
381{
382 if (pCounterBase == nullptr) {
384 errMsg << "Could not cast the pointer to type G4VUserMoleculeReactionCounter<"
386 << "Because the pointer is nullptr!" << G4endl;
387 G4Exception(G4String("G4VUserMoleculeReactionCounter<"
388 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
389 "BAD_REFERENCE", FatalException, errMsg);
390 }
391
392 auto pCounter = dynamic_cast<G4VUserMoleculeReactionCounter<TIndex> const*>(pCounterBase);
393
394 if (pCounter == nullptr) {
396 errMsg << "Could not cast the pointer to type G4VUserMoleculeReactionCounter<"
398 << "Because the objects aren't of the same type!" << G4endl;
399 G4Exception(G4String("G4VUserMoleculeReactionCounter<"
400 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
401 "BAD_REFERENCE", FatalException, errMsg);
402 }
403
404 if (pCounter->GetType() != GetType()) {
406 errMsg << "You are trying to absorb a counter with different type!" << G4endl;
407 G4Exception(G4String("G4VUserMoleculeReactionCounter<"
408 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
409 "TYPE_DIFF", JustWarning, errMsg);
410 }
411
412 for (auto const& worker_it : pCounter->GetCounterMap()) {
413 auto [master_it, indexIsNew] =
414 fCounterMap.emplace(worker_it.first, InnerCounterMapType{fTimeComparer});
415
416 G4int currentNumber = 0, previousNumber = 0;
417 for (auto const& [time, number] : worker_it.second) {
418 currentNumber = number - previousNumber;
419 previousNumber = number;
420
421 if (master_it->second.empty()) {
422 master_it->second.emplace(time, currentNumber);
423 }
424 else { // at least one element exists, so we can try to find the closest key
425 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(master_it->second, time);
426 auto [it, _] = master_it->second.emplace(time, it_closest->second);
427 do {
428 it->second += currentNumber;
429 } while (++it != master_it->second.end());
430 }
431 }
432 }
433}
434
435//------------------------------------------------------------------------------
436
437#endif
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define G4BestUnit(a, b)
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
std::map< G4double, G4int, G4MoleculeCounterTimeComparer > InnerCounterMapType
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
static G4MoleculeCounterManager * Instance()
static G4Scheduler * Instance()
MoleculeReactionCounterType GetType() const
void RecordReaction(std::unique_ptr< G4VMoleculeReactionCounterIndex >, G4double, G4int=1) override
G4bool SearchIndexUpdated(Search &, const TIndex &) const
void AbsorbCounter(const G4VMoleculeCounterInternalBase *) override
virtual std::vector< G4int > GetNbReactionsAtTimes(const TIndex &, const std::vector< G4double > &) const
virtual G4int GetNbReactionsAtTime(const TIndex &, G4double) const
std::unique_ptr< G4VMoleculeReactionCounterIndex > BuildSimpleIndex(const G4DNAMolecularReactionData *) const override=0
std::set< const G4DNAMolecularReactionData * > GetRecordedReactions() const override
const std::map< TIndex, InnerCounterMapType > & GetCounterMap() const
std::map< TIndex, InnerCounterMapType > fCounterMap
~G4VUserMoleculeReactionCounter() override=default
void InitializeUser() override=0
G4int SearchUpperBoundTime(Search &, G4double, G4bool) const
void DumpCounterMapIndices(const std::map< T, InnerCounterMapType > &map, G4bool includeEmpty=false)
const std::vector< T > GetMapIndices(const std::map< T, U > &_map)
void DumpCounterMapContents(const std::map< T, InnerCounterMapType > &map, G4bool includeEmpty=false)
std::map< TKey, TValue, TComp >::iterator FindClosestEntryForKey(std::map< TKey, TValue, TComp > &map, TKey key)
std::set< G4double > GetRecordedTimes(const std::map< T, InnerCounterMapType > &map)
std::map< TIndex, InnerCounterMapType >::const_iterator fLastIndexSearched
InnerCounterMapType::const_iterator fLowerBoundTime