Warning, file /include/Geant4/G4VUserMoleculeCounter.hh was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #ifndef G4VUSERMOLECULECOUNTER_HH
0029 #define G4VUSERMOLECULECOUNTER_HH 1
0030
0031 #include "G4MoleculeCounterManager.hh"
0032 #include "G4MolecularConfiguration.hh"
0033 #include "G4MoleculeCounterTemplates.hh"
0034 #include "G4Scheduler.hh"
0035 #include "G4UnitsTable.hh"
0036 #include "G4VMoleculeCounter.hh"
0037
0038
0039
0040 template<class TIndex>
0041 class G4VUserMoleculeCounter : public G4VMoleculeCounter
0042 {
0043 static_assert(std::is_base_of<G4VMoleculeCounter::G4VMoleculeCounterIndex, TIndex>::value,
0044 "TIndex must be derived from G4VMoleculeCounter::G4VMoleculeCounterIndex! "
0045 "No forward declaration is allowed.");
0046
0047 protected:
0048 struct Search;
0049
0050 public:
0051 G4VUserMoleculeCounter();
0052 G4VUserMoleculeCounter(G4String, MoleculeCounterType = MoleculeCounterType::Other);
0053 ~G4VUserMoleculeCounter() override = default;
0054
0055 public:
0056 void Initialize() final;
0057 void InitializeUser() override = 0;
0058 void ResetCounter() override;
0059 void Dump() const override;
0060 void DumpCounterMapIndices() const override;
0061
0062 void AbsorbCounter(const G4VMoleculeCounterInternalBase*) override;
0063
0064 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*) const override = 0;
0065 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildIndex(const G4Track*, const G4StepPoint*) const override = 0;
0066 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> BuildSimpleIndex(const G4MolecularConfiguration*) const override = 0;
0067
0068 void AddMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
0069 void RemoveMolecule(std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex>, G4double, G4int = 1) override;
0070
0071 std::set<const G4MolecularConfiguration*> GetRecordedMolecules() const override;
0072 std::set<G4double> GetRecordedTimes() const override;
0073
0074 void SchedulerFinalizedTracking() override;
0075
0076 protected:
0077 std::map<TIndex, InnerCounterMapType> fCounterMap{};
0078 std::map<TIndex, G4int> fShadowCounterMap{};
0079
0080 public:
0081 const std::map<TIndex, InnerCounterMapType>& GetCounterMap() const { return fCounterMap; }
0082 std::vector<TIndex> GetMapIndices() const;
0083
0084 virtual G4int GetNbMoleculesAtTime(const TIndex&, G4double) const;
0085 virtual G4int GetNbMoleculesAtTime(Search&, const TIndex&, G4double) const;
0086 virtual std::vector<G4int> GetNbMoleculesAtTimes(const TIndex&, const std::vector<G4double>&) const;
0087
0088
0089 protected:
0090 struct Search
0091 {
0092 Search() : fLowerBoundSet(false) {}
0093 typename std::map<TIndex, InnerCounterMapType>::const_iterator fLastIndexSearched;
0094 InnerCounterMapType::const_iterator fLowerBoundTime;
0095 G4bool fLowerBoundSet;
0096 };
0097 G4bool SearchIndexUpdated(Search&, const TIndex&) const;
0098 G4int SearchUpperBoundTime(Search&, G4double, G4bool) const;
0099 };
0100
0101
0102
0103
0104
0105
0106
0107 template<typename T>
0108 G4VUserMoleculeCounter<T>::G4VUserMoleculeCounter() : G4VMoleculeCounter()
0109 {}
0110
0111
0112
0113 template<typename T>
0114 G4VUserMoleculeCounter<T>::G4VUserMoleculeCounter(G4String name, MoleculeCounterType type)
0115 : G4VMoleculeCounter(name, type)
0116 {}
0117
0118
0119
0120 template<typename TIndex>
0121 void G4VUserMoleculeCounter<TIndex>::Initialize()
0122 {
0123 InitializeUser();
0124 fIsInitialized = true;
0125 }
0126
0127
0128
0129 template<typename TIndex>
0130 G4int G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTime(const TIndex& index, G4double time) const
0131 {
0132 Search search = {};
0133 return GetNbMoleculesAtTime(search, index, time);
0134 }
0135
0136
0137
0138 template<typename TIndex>
0139 G4int G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTime(Search& search, const TIndex& index,
0140 G4double time) const
0141 {
0142 G4bool sameIndex = !SearchIndexUpdated(search, index);
0143 return SearchUpperBoundTime(search, time, sameIndex);
0144 }
0145
0146
0147
0148 template<typename TIndex>
0149 std::vector<G4int>
0150 G4VUserMoleculeCounter<TIndex>::GetNbMoleculesAtTimes(const TIndex& index,
0151 const std::vector<G4double>& times) const
0152 {
0153 Search search = {};
0154 std::vector<G4int> counts = {};
0155 for (auto time : times)
0156 counts.push_back(GetNbMoleculesAtTime(search, index, time));
0157 return counts;
0158 }
0159
0160
0161
0162 template<typename TIndex>
0163 void G4VUserMoleculeCounter<TIndex>::AddMolecule(
0164 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
0165 {
0166 const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
0167
0168 if(mapIndex == nullptr)
0169 {
0170 G4ExceptionDescription errMsg;
0171 errMsg << "mapIndex is not found "<< G4endl;
0172 G4Exception(G4String("G4VUserMoleculeCounter<"
0173 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
0174 "mapIndex == nullptr", FatalException, errMsg);
0175 }else{
0176 if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
0177 || G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
0178 {
0179 return;
0180 }
0181
0182 if (fCheckTimeIsConsistentWithScheduler && G4Scheduler::Instance()->IsRunning()
0183 && std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
0184 > G4Scheduler::Instance()->GetTimeTolerance())
0185 {
0186 G4ExceptionDescription errMsg;
0187 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
0188 << G4BestUnit(time, "Time") << "while the global time is "
0189 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
0190 G4Exception(G4String("G4VUserMoleculeCounter<"
0191 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
0192 "TIME_DONT_MATCH", FatalException, errMsg);
0193 }
0194
0195 if (IsTimeAboveUpperBound(time)) {
0196 if (fVerbose > 3) {
0197 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0198 << ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
0199 << " at time : " << G4BestUnit(time, "Time") << G4endl;
0200 G4cout << ":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true"
0201 << G4endl;
0202 }
0203 return;
0204 }
0205 else if (IsTimeBelowLowerBound(time)) {
0206
0207 auto [it, indexIsNew] = fShadowCounterMap.emplace(*mapIndex, number);
0208 if (!indexIsNew) it->second += number;
0209 if (fVerbose > 3) {
0210 G4cout << ":: [IsTimeBelowLowerBound] Adding " << mapIndex->GetInfo()
0211 << " shadow count: " << it->second - number << " + " << number << G4endl;
0212 }
0213 return;
0214 }
0215
0216 if (fVerbose > 1) {
0217 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0218 << ">(" << GetName() << ")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
0219 << " at time : " << G4BestUnit(time, "Time") << G4endl;
0220 }
0221
0222
0223
0224
0225 auto it_shadow = fShadowCounterMap.find(*mapIndex);
0226 auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
0227
0228 if (it_shadow != fShadowCounterMap.end()) {
0229
0230 if (indexIsNew) {
0231
0232 it->second[fActiveLowerBound] = it_shadow->second;
0233 }
0234 else {
0235
0236
0237
0238 InnerCounterMapType::iterator it_time;
0239 G4bool timeIsNew;
0240 std::tie(it_time, timeIsNew) = it->second.emplace(fActiveLowerBound, 0);
0241 do {
0242 it_time->second += it_shadow->second;
0243 } while (++it_time != it->second.end());
0244 }
0245
0246 fShadowCounterMap.erase(it_shadow);
0247 }
0248
0249
0250 if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent())
0251
0252 {
0253 auto end = it->second.rbegin();
0254 auto init_n = end == it->second.rend() ? 0 : end->second;
0255
0256 auto [it_time, timeIsNew] = it->second.emplace(time, init_n);
0257 it_time->second += number;
0258
0259 if (fCheckRecordedTimesAreConsistent
0260 && !(end->first <= time
0261 || std::fabs(end->first - time) <= fTimeComparer.GetPrecisionAtTime(time)))
0262
0263
0264 {
0265 G4ExceptionDescription errMsg;
0266 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
0267 << G4BestUnit(time, "Time") << "while the global time is "
0268 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
0269 << "(last counter time: " << G4BestUnit(end->first, "Time") << ")" << G4endl;
0270 G4Exception(G4String("G4VUserMoleculeCounter<"
0271 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0272 + ">::AddMolecule"),
0273 "TIME_DONT_MATCH", FatalException, errMsg);
0274 }
0275 }
0276 else
0277 {
0278
0279
0280
0281
0282
0283 if (it->second.empty()) {
0284 it->second.emplace(time, number);
0285 }
0286 else {
0287 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(it->second, time);
0288 auto [it_time, _] = it->second.emplace(time, it_closest->second);
0289 do {
0290 it_time->second += number;
0291 } while (++it_time != it->second.end());
0292 }
0293 }
0294 }
0295 }
0296
0297
0298
0299 template<typename TIndex>
0300 void G4VUserMoleculeCounter<TIndex>::RemoveMolecule(
0301 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex, G4double time, G4int number)
0302 {
0303 const TIndex* mapIndex = dynamic_cast<TIndex*>(pIndex.get());
0304
0305 if(mapIndex == nullptr)
0306 {
0307 G4ExceptionDescription errMsg;
0308 errMsg << "mapIndex is not found "<< G4endl;
0309 G4Exception(G4String("G4VUserMoleculeCounter<"
0310 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AddMolecule"),
0311 "mapIndex == nullptr", FatalException, errMsg);
0312 }else{
0313 if (G4::MoleculeCounter::Contains(fIgnoredMolecules, mapIndex->GetMolecule()->GetDefinition())
0314 || G4::MoleculeCounter::Contains(fIgnoredReactants, mapIndex->GetMolecule()))
0315 {
0316 return;
0317 }
0318
0319 if (fCheckTimeIsConsistentWithScheduler && G4Scheduler::Instance()->IsRunning()
0320 && std::fabs(time - G4Scheduler::Instance()->GetGlobalTime())
0321 > G4Scheduler::Instance()->GetTimeTolerance())
0322 {
0323 G4ExceptionDescription errMsg;
0324 errMsg << "Time of species " << mapIndex->GetMolecule()->GetName() << " is "
0325 << G4BestUnit(time, "Time") << "while the global time is "
0326 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time") << G4endl;
0327 G4Exception(G4String("G4VUserMoleculeCounter<"
0328 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0329 + ">::RemoveMolecule"),
0330 "TIME_DONT_MATCH", FatalException, errMsg);
0331 }
0332
0333 if (IsTimeBelowLowerBound(time)) {
0334 auto it = fShadowCounterMap.find(*mapIndex);
0335 if (it == fShadowCounterMap.end()) {
0336 G4ExceptionDescription errMsg;
0337 errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
0338 << " recorded at the time or even before the time asked" << G4endl;
0339 G4Exception(G4String("G4VUserMoleculeCounter<"
0340 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0341 + ">::RemoveMolecule"),
0342 "", FatalErrorInArgument, errMsg);
0343 }
0344 else {
0345 if (fVerbose > 3) {
0346 G4cout << ":: [IsTimeBelowLowerBound] Removing " << mapIndex->GetInfo()
0347 << " shadow count: " << it->second << " - " << number << G4endl;
0348 }
0349 it->second -= number;
0350 return;
0351 }
0352 }
0353 else if (IsTimeAboveUpperBound(time)) {
0354
0355
0356
0357 auto [it, indexIsNew] = fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
0358 if (indexIsNew || it->second.empty()) {
0359 auto it_shadow = fShadowCounterMap.find(*mapIndex);
0360 if (it_shadow != fShadowCounterMap.end()) {
0361 it->second[fActiveLowerBound] = it_shadow->second;
0362 if (fVerbose > 3) {
0363 G4cout << ":: [IsTimeAboveUpperBound] Set " << mapIndex->GetInfo()
0364 << " Map[ActiveLowerBound] with shadow count:" << it_shadow->second << G4endl;
0365 }
0366 fShadowCounterMap.erase(it_shadow);
0367 }
0368 else if (fVerbose > 3) {
0369 G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count since"
0370 " no shadow count was found!"
0371 << G4endl;
0372 }
0373 }
0374 else if (fVerbose > 3) {
0375 G4cout << ":: [IsTimeAboveUpperBound] Not updating with shadow count"
0376 " since it already exists "
0377 << G4endl;
0378 }
0379 return;
0380 }
0381
0382 if (fVerbose > 2) {
0383 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0384 << ">(" << GetName() << ")::RemoveMolecule : " << mapIndex->GetMolecule()->GetName()
0385 << " at time : " << G4BestUnit(time, "Time") << G4endl;
0386 }
0387
0388
0389
0390
0391 auto it_shadow = fShadowCounterMap.find(*mapIndex);
0392 auto it = fCounterMap.find(*mapIndex);
0393
0394 if (it_shadow != fShadowCounterMap.end()) {
0395
0396 if (it == fCounterMap.end()) {
0397
0398 G4bool indexIsNew = false;
0399 std::tie(it, indexIsNew) =
0400 fCounterMap.emplace(*mapIndex, InnerCounterMapType{fTimeComparer});
0401 if (!indexIsNew) {
0402 G4ExceptionDescription errMsg;
0403 errMsg << "We tried to emplace the index after it was found to not exist, but now it "
0404 "says it existed!?"
0405 << G4endl;
0406 G4Exception(G4String("G4VUserMoleculeCounter<"
0407 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0408 + ">::RemoveMolecule"),
0409 "NONSENSICAL", FatalErrorInArgument, errMsg);
0410 }
0411 it->second[fActiveLowerBound] = it_shadow->second;
0412 }
0413 else {
0414
0415
0416
0417 auto [it_time, _] = it->second.emplace(fActiveLowerBound, 0);
0418 do {
0419 it_time->second += it_shadow->second;
0420 } while (++it_time != it->second.end());
0421 }
0422
0423
0424 fShadowCounterMap.erase(it_shadow);
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451 }
0452
0453 InnerCounterMapType& nbMolPerTime = it->second;
0454 InnerCounterMapType::iterator it_time;
0455 G4bool isNewTime = false;
0456 G4double oldTime = 0;
0457
0458 if (G4MoleculeCounterManager::Instance()->GetResetCountersBeforeEvent()) {
0459 auto end = nbMolPerTime.rbegin();
0460 oldTime = end->first;
0461
0462
0463 if (end == nbMolPerTime.rend()) {
0464 if (fVerbose > 2) {
0465 mapIndex->GetMolecule()->PrintState();
0466 Dump();
0467 }
0468 G4ExceptionDescription errMsg;
0469 errMsg << "There was no " << mapIndex->GetMolecule()->GetName()
0470 << " recorded at the time or even before the time asked" << G4endl;
0471 G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "", FatalErrorInArgument, errMsg);
0472 }
0473
0474
0475 if (fCheckRecordedTimesAreConsistent
0476 && time - end->first < -fTimeComparer.GetPrecisionAtTime(time))
0477 {
0478 if (fVerbose > 2) {
0479 mapIndex->GetMolecule()->PrintState();
0480 Dump();
0481 }
0482 G4ExceptionDescription errMsg;
0483 errMsg << "Is time going back?? " << mapIndex->GetMolecule()->GetName()
0484 << " is being removed at time " << G4BestUnit(time, "Time")
0485 << "while last recorded time was " << G4BestUnit(end->first, "Time") << ".";
0486 G4Exception("G4VUserMoleculeCounter::RemoveMolecule", "RETURN_TO_THE_FUTUR",
0487 FatalErrorInArgument, errMsg);
0488 }
0489 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, end->second);
0490
0491 it_time->second -= number;
0492
0493
0494
0495
0496 }
0497 else {
0498
0499
0500
0501
0502
0503 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(nbMolPerTime, time);
0504 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, it_closest->second);
0505 auto _it = it_time;
0506 do {
0507 _it->second -= number;
0508 } while (++_it != it->second.end());
0509 }
0510
0511
0512
0513
0514 if (it_time == nbMolPerTime.end() || it_time->second < 0) {
0515 if (fVerbose > 2) Dump();
0516 G4ExceptionDescription errMsg;
0517 errMsg << "After removal of " << number << " species of "
0518 << mapIndex->GetMolecule()->GetName() << " the final number at time "
0519 << G4BestUnit(time, "Time") << " is less than zero and so not valid."
0520 << "\nIndex was :" << mapIndex->GetInfo() << "\nGlobal time is "
0521 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
0522 << "\nPrevious selected time is " << G4BestUnit(oldTime, "Time") << G4endl;
0523 if (fNegativeCountsAreFatal) {
0524 G4Exception(G4String("G4VUserMoleculeCounter<"
0525 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0526 + ">::RemoveMolecule"),
0527 "N_INF_0", FatalException, errMsg);
0528 }
0529 else if (fVerbose > 0) {
0530 G4Exception(G4String("G4VUserMoleculeCounter<"
0531 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0532 + ">::RemoveMolecule"),
0533 "N_INF_0", JustWarning, errMsg);
0534 }
0535 }
0536 }
0537 }
0538
0539
0540
0541 template<typename TIndex>
0542 void G4VUserMoleculeCounter<TIndex>::SchedulerFinalizedTracking()
0543 {
0544
0545 for (auto& it_shadow : fShadowCounterMap) {
0546 auto [it, indexIsNew] =
0547 fCounterMap.emplace(it_shadow.first, InnerCounterMapType{fTimeComparer});
0548 if (indexIsNew || it->second.empty()) {
0549 it->second[fActiveLowerBound] = it_shadow.second;
0550 if (fVerbose > 3) {
0551 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0552 << ">(" << GetName() << ")::SchedulerEndedTracking : " << "setting map index '"
0553 << it_shadow.first.GetInfo() << "' from shadow counter to n = " << it_shadow.second
0554 << G4endl;
0555 }
0556 }
0557 else if (fVerbose > 2) {
0558 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<TIndex>()
0559 << ">(" << GetName() << ")::SchedulerEndedTracking : "
0560 << "encountered dangling shadow counter iterator for index '"
0561 << it_shadow.first.GetInfo() << "'" << G4endl;
0562 }
0563 }
0564 fShadowCounterMap.clear();
0565 }
0566
0567
0568
0569 template<typename TIndex>
0570 std::vector<TIndex> G4VUserMoleculeCounter<TIndex>::GetMapIndices() const
0571 {
0572 if (fVerbose > 2) {
0573 G4cout << "Entering in G4VUserMoleculeCounter::GetMapIndices" << G4endl;
0574 }
0575 return G4::MoleculeCounter::GetMapIndices(fCounterMap);
0576 }
0577
0578
0579
0580 template<typename T>
0581 std::set<const G4MolecularConfiguration*> G4VUserMoleculeCounter<T>::GetRecordedMolecules() const
0582 {
0583 if (fVerbose > 2) {
0584 G4cout << "Entering in G4MoleculeCounter::RecordMolecules" << G4endl;
0585 }
0586 std::set<const G4MolecularConfiguration*> output{};
0587 for (const auto& it : fCounterMap) {
0588 output.insert(it.first.GetMolecule());
0589 }
0590 return output;
0591 }
0592
0593
0594
0595 template<typename T>
0596 std::set<G4double> G4VUserMoleculeCounter<T>::GetRecordedTimes() const
0597 {
0598 return G4::MoleculeCounter::GetRecordedTimes<T>(fCounterMap);
0599 }
0600
0601
0602
0603 template<typename T>
0604 void G4VUserMoleculeCounter<T>::Dump() const
0605 {
0606 DumpCounterMapIndices();
0607 G4::MoleculeCounter::DumpCounterMapContents<T>(fCounterMap);
0608 }
0609
0610 template<typename T>
0611 void G4VUserMoleculeCounter<T>::DumpCounterMapIndices() const
0612 {
0613 G4::MoleculeCounter::DumpCounterMapIndices<T>(fCounterMap);
0614 }
0615
0616
0617
0618 template<typename T>
0619 void G4VUserMoleculeCounter<T>::ResetCounter()
0620 {
0621 if (fVerbose > 1) {
0622 G4cout << "G4VUserMoleculeCounter<" << G4::MoleculeCounter::GetTemplateTypeName<T>() << ">("
0623 << GetName() << ")::ResetCounter" << G4endl;
0624 }
0625 fCounterMap.clear();
0626 }
0627
0628
0629
0630 template<typename TIndex>
0631 G4bool G4VUserMoleculeCounter<TIndex>::SearchIndexUpdated(Search& search, const TIndex& index) const
0632 {
0633 if (search.fLowerBoundSet && !(search.fLastIndexSearched->first < index)
0634 && !(index < search.fLastIndexSearched->first))
0635 {
0636 return true;
0637 }
0638
0639 auto mol_it = fCounterMap.find(index);
0640 search.fLastIndexSearched = mol_it;
0641
0642 if (mol_it != fCounterMap.end()) {
0643 search.fLowerBoundTime = search.fLastIndexSearched->second.end();
0644 search.fLowerBoundSet = true;
0645 }
0646 else {
0647 search.fLowerBoundSet = false;
0648 }
0649
0650 return false;
0651 }
0652
0653
0654
0655 template<typename T>
0656 G4int G4VUserMoleculeCounter<T>::SearchUpperBoundTime(Search& search, G4double time,
0657 G4bool sameIndex) const
0658 {
0659 auto mol_it = search.fLastIndexSearched;
0660 if (mol_it == fCounterMap.end()) {
0661 return 0;
0662 }
0663
0664 InnerCounterMapType const& timeMap = mol_it->second;
0665 if (timeMap.empty()) {
0666 return 0;
0667 }
0668
0669 if (sameIndex) {
0670 if (search.fLowerBoundSet && search.fLowerBoundTime != timeMap.end()) {
0671 if (search.fLowerBoundTime->first < time) {
0672 auto upperToLast = search.fLowerBoundTime;
0673 upperToLast++;
0674
0675 if (upperToLast == timeMap.end()) {
0676 return search.fLowerBoundTime->second;
0677 }
0678
0679 if (upperToLast->first > time) {
0680 return search.fLowerBoundTime->second;
0681 }
0682 }
0683 }
0684 }
0685
0686 auto up_time_it = timeMap.upper_bound(time);
0687
0688 if (up_time_it == timeMap.end()) {
0689 auto last_time = timeMap.rbegin();
0690 return last_time->second;
0691 }
0692 if (up_time_it == timeMap.begin()) {
0693 return 0;
0694 }
0695
0696 up_time_it--;
0697
0698 search.fLowerBoundTime = up_time_it;
0699 search.fLowerBoundSet = true;
0700
0701 return search.fLowerBoundTime->second;
0702 }
0703
0704
0705
0706 template<typename TIndex>
0707 void G4VUserMoleculeCounter<TIndex>::AbsorbCounter(const G4VMoleculeCounterInternalBase* pCounterBase)
0708 {
0709 if (pCounterBase == nullptr) {
0710 G4ExceptionDescription errMsg;
0711 errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
0712 << G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
0713 << "Because the pointer is nullptr!" << G4endl;
0714 G4Exception(G4String("G4VUserMoleculeCounter<"
0715 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
0716 "BAD_REFERENCE", FatalException, errMsg);
0717 }
0718
0719 auto pCounter = dynamic_cast<G4VUserMoleculeCounter<TIndex> const*>(pCounterBase);
0720
0721 if (pCounter == nullptr) {
0722 G4ExceptionDescription errMsg;
0723 errMsg << "Could not cast the pointer to type G4VUserMoleculeCounter<"
0724 << G4::MoleculeCounter::GetTemplateTypeName<TIndex>() << ">!\n"
0725 << "Because the objects aren't of the same type!" << G4endl;
0726 G4Exception(G4String("G4VUserMoleculeCounter<"
0727 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
0728 "BAD_REFERENCE", FatalException, errMsg);
0729 }
0730
0731 if (pCounter->GetType() != GetType()) {
0732 G4ExceptionDescription errMsg;
0733 errMsg << "You are trying to absorb a counter with different type!" << G4endl;
0734 G4Exception(G4String("G4VUserMoleculeCounter<"
0735 + G4::MoleculeCounter::GetTemplateTypeName<TIndex>() + ">::AbsorbCounter"),
0736 "TYPE_DIFF", JustWarning, errMsg);
0737 }
0738
0739 for (auto const& worker_it : pCounter->GetCounterMap()) {
0740 auto [master_it, indexIsNew] =
0741 fCounterMap.emplace(worker_it.first, InnerCounterMapType{fTimeComparer});
0742
0743 G4int currentNumber = 0, previousNumber = 0;
0744 for (auto const& [time, number] : worker_it.second) {
0745 currentNumber = number - previousNumber;
0746 previousNumber = number;
0747
0748 if (master_it->second.empty()) {
0749 master_it->second.emplace(time, currentNumber);
0750 }
0751 else {
0752 auto it_closest = G4::MoleculeCounter::FindClosestEntryForKey(master_it->second, time);
0753 auto [it, _] = master_it->second.emplace(time, it_closest->second);
0754 do {
0755 it->second += currentNumber;
0756 } while (++it != master_it->second.end());
0757 }
0758 }
0759 }
0760 }
0761
0762
0763
0764 #endif