Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4VUserMoleculeCounter.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 G4VUSERMOLECULECOUNTER_HH
29#define G4VUSERMOLECULECOUNTER_HH 1
30
34#include "G4Scheduler.hh"
35#include "G4UnitsTable.hh"
36#include "G4VMoleculeCounter.hh"
37
38//------------------------------------------------------------------------------
39
40template<class TIndex>
41class G4VUserMoleculeCounter : public G4VMoleculeCounter
42{
43 static_assert(std::is_base_of<G4VMoleculeCounter::G4VMoleculeCounterIndex, TIndex>::value,
44 "TIndex must be derived from G4VMoleculeCounter::G4VMoleculeCounterIndex! "
45 "No forward declaration is allowed.");
46
47 protected:
48 struct Search;
49
50 public:
53 ~G4VUserMoleculeCounter() 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
64 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*) const override = 0;
65 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*, const G4StepPoint*) const override = 0;
66 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildSimpleIndex(const G4MolecularConfiguration*) const override = 0;
67
68 void AddMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
69 void RemoveMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
70
71 std::set<const G4MolecularConfiguration*> GetRecordedMolecules() const override;
72 std::set<G4double> GetRecordedTimes() const override;
73
75
76 protected:
78 std::map<TIndex, G4int> fShadowCounterMap{};
79
80 public:
81 const std::map<TIndex, InnerCounterMapType>& GetCounterMap() const { return fCounterMap; }
82 std::vector<TIndex> GetMapIndices() const;
83
84 virtual G4int GetNbMoleculesAtTime(const TIndex&, G4double) const;
85 virtual G4int GetNbMoleculesAtTime(Search&, const TIndex&, G4double) const;
86 virtual std::vector<G4int> GetNbMoleculesAtTimes(const TIndex&, const std::vector<G4double>&) const;
87
88 //-SEARCH-----------------------------------------------------------------------
89 protected:
90 struct Search
91 {
92 Search() : fLowerBoundSet(false) {}
93 typename std::map<TIndex, InnerCounterMapType>::const_iterator fLastIndexSearched;
94 InnerCounterMapType::const_iterator fLowerBoundTime;
96 };
97 G4bool SearchIndexUpdated(Search&, const TIndex&) const;
99};
100
101//------------------------------------------------------------------------------
102
103// #include "G4VUserMoleculeCounter.icc"
104
105//------------------------------------------------------------------------------
106
107template<typename T>
110
111//------------------------------------------------------------------------------
112
113template<typename T>
115 : G4VMoleculeCounter(name, type)
116{}
117
118//------------------------------------------------------------------------------
119
120template<typename TIndex>
126
127//------------------------------------------------------------------------------
128
129template<typename TIndex>
131{
132 Search search = {};
133 return GetNbMoleculesAtTime(search, index, time);
134}
135
136//------------------------------------------------------------------------------
137
138template<typename TIndex>
140 G4double time) const
141{
142 G4bool sameIndex = !SearchIndexUpdated(search, index);
143 return SearchUpperBoundTime(search, time, sameIndex);
144}
145
146//------------------------------------------------------------------------------
147
148template<typename TIndex>
149std::vector<G4int>
151 const std::vector<G4double>& times) const
152{
153 Search search = {};
154 std::vector<G4int> counts = {};
155 for (auto time : times)
156 counts.push_back(GetNbMoleculesAtTime(search, index, time));
157 return counts;
158}
159
160//------------------------------------------------------------------------------
161
162template<typename TIndex>
164 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
165{
166 const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
167
168 if(mapIndex == nullptr)
169 {
171 errMsg << "mapIndex is not found "<< G4endl;
172 G4Exception(G4String("G4VUserMoleculeCounter<"
174 "mapIndex == nullptr", FatalException, errMsg);
175 }else{
176 if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
177 || G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
178 {
179 return;
180 }
181
183 && std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
184 > G4Scheduler::Instance()->GetTimeTolerance())
185 {
187 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
188 << G4BestUnit(time, "Time") << "while the global time is "
189 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
190 G4Exception(G4String("G4VUserMoleculeCounter<"
192 "TIME_DONT_MATCH", FatalException, errMsg);
193 }
194
195 if (IsTimeAboveUpperBound(time)) {
196 if (fVerbose > 3) {
197 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
198 << ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
199 << " at time : " << G4BestUnit(time, "Time") << G4endl;
200 G4cout << ":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true"
201 << G4endl;
202 }
203 return;
204 }
205 else if (IsTimeBelowLowerBound(time)) {
206 // put into shadow counter
207 auto [it, indexIsNew] = fShadowCounterMap.emplace(*mapIndex, number);
208 if (!indexIsNew) it->second += number;
209 if (fVerbose > 3) {
210 G4cout << ":: [IsTimeBelowLowerBound] Adding " << mapIndex->GetInfo()
211 << " shadow count: " << it->second - number << " + " << number << G4endl;
212 }
213 return;
214 }
215
216 if (fVerbose > 1) {
217 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
218 << ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
219 << " at time : " << G4BestUnit(time, "Time") << G4endl;
220 }
221
222 // within time bounds && not-ignored molecule
223 // -> continue
224
225 auto it_shadow = fShadowCounterMap.find(*mapIndex);
226 auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
227
228 if (it_shadow != fShadowCounterMap.end()) {
229 // entry found in shadow counter
230 if (indexIsNew) {
231 // mapIndex is new, initialize with shadow counter
232 it->second[fActiveLowerBound] = it_shadow->second;
233 }
234 else {
235 // mapIndex existed, we need to add the shadow count to it
236 // this happens if we are in a subsequent event and have just crossed over the lower
237 // activity bound the counter has then already entries from the previous event
238 InnerCounterMapType::iterator it_time;
239 G4bool timeIsNew;
240 std::tie(it_time, timeIsNew) = it->second.emplace(fActiveLowerBound, 0);
241 do {
242 it_time->second += it_shadow->second;
243 } while (++it_time != it->second.end());
244 }
245 // either way, remove the shadow count
246 fShadowCounterMap.erase(it_shadow);
247 }
248
249 // map for index existed (and was not empty)
250 if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent())
251 // can only do consistency check if the counters are cleared for each event (= chem run)
252 {
253 auto end = it->second.rbegin();
254 auto init_n = end == it->second.rend() ? 0 : end->second;
255
256 auto [it_time, timeIsNew] = it->second.emplace(time, init_n);
257 it_time->second += number;
258
260 && !(end->first <= time
261 || std::fabs(end->first - time) <= fTimeComparer.GetPrecisionAtTime(time)))
262 // Case 1 = new time comes after last recorded data
263 // Case 2 = new time is about the same as the last recorded one
264 {
266 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
267 << G4BestUnit(time, "Time") << "while the global time is "
268 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
269 << "(last counter time: " << G4BestUnit(end->first, "Time") << ")" << G4endl;
270 G4Exception(G4String("G4VUserMoleculeCounter<"
272 + ">::AddMolecule"),
273 "TIME_DONT_MATCH", FatalException, errMsg);
274 }
275 }
276 else // counters are not (automatically) reset by manager
277 {
278 // since counters are not cleared after chemical run (i.e., after event)
279 // there will already be numbers in the map, so...
280 // (1) find the closest time
281 // (2) emplace entry using closest value as init + number
282 // (3) add number to all "future" entries as well
283 if (it->second.empty()) {
284 it->second.emplace(time, number);
285 }
286 else { // at least one element exists, so we can try to find the closest key
287 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(it->second, time);
288 auto [it_time, _] = it->second.emplace(time, it_closest->second);
289 do {
290 it_time->second += number;
291 } while (++it_time != it->second.end());
292 }
293 }
294 }
295}
296
297//------------------------------------------------------------------------------
298
299template<typename TIndex>
301 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
302{
303 const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
304
305 if(mapIndex == nullptr)
306 {
308 errMsg << "mapIndex is not found "<< G4endl;
309 G4Exception(G4String("G4VUserMoleculeCounter<"
311 "mapIndex == nullptr", FatalException, errMsg);
312 }else{
313 if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
314 || G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
315 {
316 return;
317 }
318
320 && std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
321 > G4Scheduler::Instance()->GetTimeTolerance())
322 {
324 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
325 << G4BestUnit(time, "Time") << "while the global time is "
326 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
327 G4Exception(G4String("G4VUserMoleculeCounter<"
329 + ">::RemoveMolecule"),
330 "TIME_DONT_MATCH", FatalException, errMsg);
331 }
332
333 if (IsTimeBelowLowerBound(time)) {
334 auto it = fShadowCounterMap.find(*mapIndex);
335 if (it == fShadowCounterMap.end()) {
337 errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
338 << " recorded at the time or even before the time asked" << G4endl;
339 G4Exception(G4String("G4VUserMoleculeCounter<"
341 + ">::RemoveMolecule"),
342 "", FatalErrorInArgument, errMsg);
343 }
344 else {
345 if (fVerbose > 3) {
346 G4cout << ":: [IsTimeBelowLowerBound] Removing " << mapIndex->GetInfo()
347 << " shadow count: " << it->second << " - " << number << G4endl;
348 }
349 it->second -= number;
350 return;
351 }
352 }
353 else if (IsTimeAboveUpperBound(time)) {
354 // if the "active" counter was not filled, add the shadow counter to it at the lower bound
355 // only needed for remove since remove will always be called at the end when the molecule is
356 // destroyed
357 auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
358 if (indexIsNew || it->second.empty()) {
359 auto it_shadow = fShadowCounterMap.find(*mapIndex);
360 if (it_shadow != fShadowCounterMap.end()) {
361 it->second[fActiveLowerBound] = it_shadow->second;
362 if (fVerbose > 3) {
363 G4cout << ":: [IsTimeAboveUpperBound] Set " << mapIndex->GetInfo()
364 << " Map[ActiveLowerBound] with shadow count:" << it_shadow->second << G4endl;
365 }
366 fShadowCounterMap.erase(it_shadow);
367 }
368 else if (fVerbose > 3) {
369 G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count since"
370 " no shadow count was found!"
371 << G4endl;
372 }
373 }
374 else if (fVerbose > 3) {
375 G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count"
376 " since it already exists "
377 << G4endl;
378 }
379 return;
380 }
381
382 if (fVerbose > 2) {
383 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
384 << ">(" << GetName() << ")::RemoveMolecule : " << mapIndex->GetMolecule()->GetName()
385 << " at time : " << G4BestUnit(time, "Time") << G4endl;
386 }
387
388 // within time bounds && not-ignored molecule
389 // -> continue
390
391 auto it_shadow = fShadowCounterMap.find(*mapIndex);
392 auto it = fCounterMap.find(*mapIndex);
393
394 if (it_shadow != fShadowCounterMap.end()) {
395 // entry found in shadow counter
396 if (it == fCounterMap.end()) {
397 // no mapIndex found, initialize with shadow counter
398 G4bool indexIsNew = false;
399 std::tie(it, indexIsNew) =
400 fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
401 if (!indexIsNew) {
403 errMsg << "We tried to emplace the index after it was found to not exist, but now it "
404 "says it existed!?"
405 << G4endl;
406 G4Exception(G4String("G4VUserMoleculeCounter<"
408 + ">::RemoveMolecule"),
409 "NONSENSICAL", FatalErrorInArgument, errMsg);
410 }
411 it->second[fActiveLowerBound] = it_shadow->second;
412 }
413 else { // it != fCounterMap.end()
414 // mapIndex exists, we need to add the shadow count to it
415 // this happens if we are in a subsequent event and have just crossed over the lower
416 // activity bound the counter has then already entries from the previous event
417 auto [it_time, _] = it->second.emplace(fActiveLowerBound, 0);
418 do {
419 it_time->second += it_shadow->second;
420 } while (++it_time != it->second.end());
421 }
422
423 // either way, remove the shadow count
424 fShadowCounterMap.erase(it_shadow);
425
426 // if (it_shadow != fShadowCounterMap.end()) {
427 // G4bool indexIsNew = false;
428 // // auto [it_, indexIsNew] = fCounterMap.emplace(*mapIndex,
429 // // InnerCounterMapType{fTimeComparer});
430 // std::tie(it, indexIsNew) = fCounterMap.emplace(*mapIndex,
431 // InnerCounterMapType{fTimeComparer}); if (!indexIsNew) {
432 // G4ExceptionDescription errMsg;
433 // errMsg << "We tried to emplace the index after it was found to not exist, but now it
434 // "
435 // "says it existed!?"
436 // << G4endl;
437 // G4Exception(G4String("G4VUserMoleculeCounter<"
438 // + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
439 // + ">::RemoveMolecule"),
440 // "NONSENSICAL", FatalErrorInArgument, errMsg);
441 // }
442 // it->second[fActiveLowerBound] = it_shadow->second;
443 // // it = it_;
444 // if (fVerbose > 3) {
445 // G4cout << ":: Initialize " << mapIndex->GetInfo()
446 // << " Map[ActiveLowerBound] with shadow count:" << it_shadow->second <<
447 // G4endl;
448 // }
449 // fShadowCounterMap.erase(it_shadow);
450 // }
451 }
452
453 InnerCounterMapType& nbMolPerTime = it->second;
454 InnerCounterMapType::iterator it_time;
455 G4bool isNewTime = false;
456 G4double oldTime = 0;
457
458 if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent()) {
459 auto end = nbMolPerTime.rbegin(); // get last entry
460 oldTime = end->first;
461
462 // CHECK: no molecules have been recorded for this index
463 if (end == nbMolPerTime.rend()) {
464 if (fVerbose > 2) {
465 mapIndex->GetMolecule()->PrintState();
466 Dump();
467 }
469 errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
470 << " recorded at the time or even before the time asked" << G4endl;
471 G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "", FatalErrorInArgument, errMsg);
472 }
473 // CHECK: current time is less (by more than counter precision) than the most recently
474 // recorded index
476 && time - end->first < -fTimeComparer.GetPrecisionAtTime(time))
477 {
478 if (fVerbose > 2) {
479 mapIndex->GetMolecule()->PrintState();
480 Dump();
481 }
483 errMsg << "Is time going back?? " << mapIndex->GetMolecule()->GetName()
484 << " is being removed at time " << G4BestUnit(time, "Time")
485 << "while last recorded time was " << G4BestUnit(end->first, "Time") << ".";
486 G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "RETURN_TO_THE_FUTUR",
487 FatalErrorInArgument, errMsg);
488 }
489 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, end->second);
490 // auto oldNumber = it_time->second;
491 it_time->second -= number;
492 // if (time > 0.001)
493 // G4cout << "(t=" << time << ")=" << number << " | old_it(t=" << it_time->first
494 // << ") = " << oldNumber << " | timeIsNew=" << isNewTime
495 // << " | new_it(t=" << it_time->first << ") = " << it_time->second << G4endl;
496 }
497 else {
498 // since counters are not cleared after chemical run (i.e., after event)
499 // there will already be numbers in the map, so...
500 // (1) find the closest time
501 // (2) emplace entry using closest value as init - number
502 // (3) remove number from all "future" entries as well
503 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(nbMolPerTime, time);
504 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, it_closest->second);
505 auto _it = it_time;
506 do {
507 _it->second -= number;
508 } while (++_it != it->second.end());
509 }
510
511 // Check that count at new time is >= 0
512 // This currently throws tons of errors for non-basic counters.
513 // auto it_time = nbMolPerTime.find(time);
514 if (it_time == nbMolPerTime.end() || it_time->second < 0) {
515 if (fVerbose > 2) Dump();
517 errMsg << "After removal of " << number << " species of "
518 << mapIndex->GetMolecule()->GetName() << " the final number at time "
519 << G4BestUnit(time, "Time") << " is less than zero and so not valid."
520 << "\nIndex was :" << mapIndex->GetInfo() << "\nGlobal time is "
521 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
522 << "\nPrevious selected time is " << G4BestUnit(oldTime, "Time") << G4endl;
524 G4Exception(G4String("G4VUserMoleculeCounter<"
526 + ">::RemoveMolecule"),
527 "N_INF_0", FatalException, errMsg);
528 }
529 else if (fVerbose > 0) {
530 G4Exception(G4String("G4VUserMoleculeCounter<"
532 + ">::RemoveMolecule"),
533 "N_INF_0", JustWarning, errMsg);
534 }
535 }
536 }
537}
538
539//------------------------------------------------------------------------------
540
541template<typename TIndex>
543{
544 // Add record to fCounterMap for each fShadowCounterMap index unless they exist already
545 for (auto& it_shadow : fShadowCounterMap) {
546 auto [it, indexIsNew] =
547 fCounterMap.emplace(it_shadow.first, InnerCounterMapType{fTimeComparer});
548 if (indexIsNew || it->second.empty()) {
549 it->second[fActiveLowerBound] = it_shadow.second;
550 if (fVerbose > 3) {
551 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
552 << ">(" << GetName() << ")::SchedulerEndedTracking : " << "setting map index '"
553 << it_shadow.first.GetInfo() << "' from shadow counter to n = " << it_shadow.second
554 << G4endl;
555 }
556 }
557 else if (fVerbose > 2) {
558 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
559 << ">(" << GetName() << ")::SchedulerEndedTracking : "
560 << "encountered dangling shadow counter iterator for index '"
561 << it_shadow.first.GetInfo() << "'" << G4endl;
562 }
563 }
564 fShadowCounterMap.clear();
565}
566
567//------------------------------------------------------------------------------
568
569template<typename TIndex>
571{
572 if (fVerbose > 2) {
573 G4cout << "Entering in G4VUserMoleculeCounter::GetMapIndices" << G4endl;
574 }
576}
577
578//------------------------------------------------------------------------------
579
580template<typename T>
581std::set<const G4MolecularConfiguration*> G4VUserMoleculeCounter<T>::GetRecordedMolecules() const
582{
583 if (fVerbose > 2) {
584 G4cout << "Entering in G4MoleculeCounter::RecordMolecules" << G4endl;
585 }
586 std::set<const G4MolecularConfiguration*> output{};
587 for (const auto& it : fCounterMap) {
588 output.insert(it.first.GetMolecule());
589 }
590 return output;
591}
592
593//------------------------------------------------------------------------------
594
595template<typename T>
600
601//------------------------------------------------------------------------------
602
603template<typename T>
609
610template<typename T>
615
616//------------------------------------------------------------------------------
617
618template<typename T>
620{
621 if (fVerbose > 1) {
622 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<T>() << ">("
623 << GetName() << ")::ResetCounter" << G4endl;
624 }
625 fCounterMap.clear();
626}
627
628//------------------------------------------------------------------------------
629
630template<typename TIndex>
632{
633 if (search.fLowerBoundSet && !(search.fLastIndexSearched->first < index)
634 && !(index < search.fLastIndexSearched->first))
635 {
636 return true;
637 }
638
639 auto mol_it = fCounterMap.find(index);
640 search.fLastIndexSearched = mol_it;
641
642 if (mol_it != fCounterMap.end()) {
643 search.fLowerBoundTime = search.fLastIndexSearched->second.end();
644 search.fLowerBoundSet = true;
645 }
646 else {
647 search.fLowerBoundSet = false;
648 }
649
650 return false;
651}
652
653//------------------------------------------------------------------------------
654
655template<typename T>
657 G4bool sameIndex) const
658{
659 auto mol_it = search.fLastIndexSearched;
660 if (mol_it == fCounterMap.end()) {
661 return 0;
662 }
663
664 InnerCounterMapType const& timeMap = mol_it->second;
665 if (timeMap.empty()) {
666 return 0;
667 }
668
669 if (sameIndex) {
670 if (search.fLowerBoundSet && search.fLowerBoundTime != timeMap.end()) {
671 if (search.fLowerBoundTime->first < time) {
672 auto upperToLast = search.fLowerBoundTime;
673 upperToLast++;
674
675 if (upperToLast == timeMap.end()) {
676 return search.fLowerBoundTime->second;
677 }
678
679 if (upperToLast->first > time) {
680 return search.fLowerBoundTime->second;
681 }
682 }
683 }
684 }
685
686 auto up_time_it = timeMap.upper_bound(time);
687
688 if (up_time_it == timeMap.end()) {
689 auto last_time = timeMap.rbegin();
690 return last_time->second;
691 }
692 if (up_time_it == timeMap.begin()) {
693 return 0;
694 }
695
696 up_time_it--;
697
698 search.fLowerBoundTime = up_time_it;
699 search.fLowerBoundSet = true;
700
701 return search.fLowerBoundTime->second;
702}
703
704//------------------------------------------------------------------------------
705
706template<typename TIndex>
707void G4VUserMoleculeCounter<TIndex>::AbsorbCounter(const G4VMoleculeCounterInternalBase* pCounterBase)
708{
709 if (pCounterBase == nullptr) {
711 errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
713 << "Because the pointer is nullptr!" << G4endl;
714 G4Exception(G4String("G4VUserMoleculeCounter<"
715 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
716 "BAD_REFERENCE", FatalException, errMsg);
717 }
718
719 auto pCounter = dynamic_cast<G4VUserMoleculeCounter<TIndex> const*>(pCounterBase);
720
721 if (pCounter == nullptr) {
723 errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
725 << "Because the objects aren't of the same type!" << G4endl;
726 G4Exception(G4String("G4VUserMoleculeCounter<"
727 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
728 "BAD_REFERENCE", FatalException, errMsg);
729 }
730
731 if (pCounter->GetType() != GetType()) {
733 errMsg << "You are trying to absorb a counter with different type!" << G4endl;
734 G4Exception(G4String("G4VUserMoleculeCounter<"
735 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
736 "TYPE_DIFF", JustWarning, errMsg);
737 }
738
739 for (auto const& worker_it : pCounter->GetCounterMap()) {
740 auto [master_it, indexIsNew] =
741 fCounterMap.emplace(worker_it.first, InnerCounterMapType{fTimeComparer});
742
743 G4int currentNumber = 0, previousNumber = 0;
744 for (auto const& [time, number] : worker_it.second) {
745 currentNumber = number - previousNumber;
746 previousNumber = number;
747
748 if (master_it->second.empty()) {
749 master_it->second.emplace(time, currentNumber);
750 }
751 else { // at least one element exists, so we can try to find the closest key
752 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(master_it->second, time);
753 auto [it, _] = master_it->second.emplace(time, it_closest->second);
754 do {
755 it->second += currentNumber;
756 } while (++it != master_it->second.end());
757 }
758 }
759 }
760}
761
762//------------------------------------------------------------------------------
763
764#endif
@ JustWarning
@ FatalException
@ FatalErrorInArgument
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()
MoleculeCounterType GetType() const
std::set< const G4MoleculeDefinition * > fIgnoredMolecules
std::set< const G4MolecularConfiguration * > fIgnoredReactants
virtual G4int GetNbMoleculesAtTime(const TIndex &, G4double) const
std::map< TIndex, InnerCounterMapType > fCounterMap
std::vector< TIndex > GetMapIndices() const
G4int SearchUpperBoundTime(Search &, G4double, G4bool) const
void AddMolecule(std::unique_ptr< G4VMoleculeCounter::G4VMoleculeCounterIndex >, G4double, G4int=1) override
std::unique_ptr< G4VMoleculeCounter::G4VMoleculeCounterIndex > BuildIndex(const G4Track *) const override=0
G4bool SearchIndexUpdated(Search &, const TIndex &) const
std::set< G4double > GetRecordedTimes() const override
~G4VUserMoleculeCounter() override=default
std::set< const G4MolecularConfiguration * > GetRecordedMolecules() const override
std::unique_ptr< G4VMoleculeCounter::G4VMoleculeCounterIndex > BuildSimpleIndex(const G4MolecularConfiguration *) const override=0
void RemoveMolecule(std::unique_ptr< G4VMoleculeCounter::G4VMoleculeCounterIndex >, G4double, G4int=1) override
void InitializeUser() override=0
void AbsorbCounter(const G4VMoleculeCounterInternalBase *) override
std::map< TIndex, G4int > fShadowCounterMap
const std::map< TIndex, InnerCounterMapType > & GetCounterMap() const
virtual std::vector< G4int > GetNbMoleculesAtTimes(const TIndex &, const std::vector< G4double > &) 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)
G4bool Contains(const std::set< T > &_set, const T &_value)
std::map< TIndex, InnerCounterMapType >::const_iterator fLastIndexSearched
InnerCounterMapType::const_iterator fLowerBoundTime