28#ifndef G4VUSERMOLECULECOUNTER_HH
29#define G4VUSERMOLECULECOUNTER_HH 1
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.");
59 void Dump() const override;
115 : G4VMoleculeCounter(name, type)
120template<
typename TIndex>
129template<
typename TIndex>
138template<
typename TIndex>
148template<
typename TIndex>
151 const std::vector<G4double>& times)
const
154 std::vector<G4int> counts = {};
155 for (
auto time : times)
162template<
typename TIndex>
164 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex,
G4double time,
G4int number)
166 const TIndex* mapIndex =
dynamic_cast<TIndex*
>(pIndex.get());
168 if(mapIndex ==
nullptr)
171 errMsg <<
"mapIndex is not found "<<
G4endl;
187 errMsg <<
"Time of species " << mapIndex->GetMolecule()->GetName() <<
" is "
188 <<
G4BestUnit(time,
"Time") <<
"while the global time is "
198 <<
">(" <<
GetName() <<
")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
200 G4cout <<
":: [IsTimeAboveUpperBound] Skipping since IsTimeAboveUpperBound == true"
208 if (!indexIsNew) it->second += number;
210 G4cout <<
":: [IsTimeBelowLowerBound] Adding " << mapIndex->GetInfo()
211 <<
" shadow count: " << it->second - number <<
" + " << number <<
G4endl;
218 <<
">(" <<
GetName() <<
")::AddMolecule : " << mapIndex->GetMolecule()->GetName()
238 InnerCounterMapType::iterator it_time;
242 it_time->second += it_shadow->second;
243 }
while (++it_time != it->second.end());
253 auto end = it->second.rbegin();
254 auto init_n = end == it->second.rend() ? 0 : end->second;
256 auto [it_time, timeIsNew] = it->second.emplace(time, init_n);
257 it_time->second += number;
260 && !(end->first <= time
261 || std::fabs(end->first - time) <=
fTimeComparer.GetPrecisionAtTime(time)))
266 errMsg <<
"Time of species " << mapIndex->GetMolecule()->GetName() <<
" is "
267 <<
G4BestUnit(time,
"Time") <<
"while the global time is "
269 <<
"(last counter time: " <<
G4BestUnit(end->first,
"Time") <<
")" <<
G4endl;
283 if (it->second.empty()) {
284 it->second.emplace(time, number);
288 auto [it_time, _] = it->second.emplace(time, it_closest->second);
290 it_time->second += number;
291 }
while (++it_time != it->second.end());
299template<
typename TIndex>
301 std::unique_ptr<G4VMoleculeCounter::G4VMoleculeCounterIndex> pIndex,
G4double time,
G4int number)
303 const TIndex* mapIndex =
dynamic_cast<TIndex*
>(pIndex.get());
305 if(mapIndex ==
nullptr)
308 errMsg <<
"mapIndex is not found "<<
G4endl;
324 errMsg <<
"Time of species " << mapIndex->GetMolecule()->GetName() <<
" is "
325 <<
G4BestUnit(time,
"Time") <<
"while the global time is "
329 +
">::RemoveMolecule"),
337 errMsg <<
"There was no " << mapIndex->GetMolecule()->GetName()
338 <<
" recorded at the time or even before the time asked" <<
G4endl;
341 +
">::RemoveMolecule"),
346 G4cout <<
":: [IsTimeBelowLowerBound] Removing " << mapIndex->GetInfo()
347 <<
" shadow count: " << it->second <<
" - " << number <<
G4endl;
349 it->second -= number;
358 if (indexIsNew || it->second.empty()) {
363 G4cout <<
":: [IsTimeAboveUpperBound] Set " << mapIndex->GetInfo()
364 <<
" Map[ActiveLowerBound] with shadow count:" << it_shadow->second <<
G4endl;
369 G4cout <<
":: [IsTimeAboveUpperBound] Not updating with shadow count since"
370 " no shadow count was found!"
375 G4cout <<
":: [IsTimeAboveUpperBound] Not updating with shadow count"
376 " since it already exists "
384 <<
">(" <<
GetName() <<
")::RemoveMolecule : " << mapIndex->GetMolecule()->GetName()
398 G4bool indexIsNew =
false;
399 std::tie(it, indexIsNew) =
403 errMsg <<
"We tried to emplace the index after it was found to not exist, but now it "
408 +
">::RemoveMolecule"),
419 it_time->second += it_shadow->second;
420 }
while (++it_time != it->second.end());
454 InnerCounterMapType::iterator it_time;
459 auto end = nbMolPerTime.rbegin();
460 oldTime = end->first;
463 if (end == nbMolPerTime.rend()) {
465 mapIndex->GetMolecule()->PrintState();
469 errMsg <<
"There was no " << mapIndex->GetMolecule()->GetName()
470 <<
" recorded at the time or even before the time asked" <<
G4endl;
476 && time - end->first < -
fTimeComparer.GetPrecisionAtTime(time))
479 mapIndex->GetMolecule()->PrintState();
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",
489 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, end->second);
491 it_time->second -= number;
504 std::tie(it_time, isNewTime) = nbMolPerTime.emplace(time, it_closest->second);
507 _it->second -= number;
508 }
while (++_it != it->second.end());
514 if (it_time == nbMolPerTime.end() || it_time->second < 0) {
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 "
526 +
">::RemoveMolecule"),
532 +
">::RemoveMolecule"),
541template<
typename TIndex>
546 auto [it, indexIsNew] =
548 if (indexIsNew || it->second.empty()) {
552 <<
">(" <<
GetName() <<
")::SchedulerEndedTracking : " <<
"setting map index '"
553 << it_shadow.first.GetInfo() <<
"' from shadow counter to n = " << it_shadow.second
559 <<
">(" <<
GetName() <<
")::SchedulerEndedTracking : "
560 <<
"encountered dangling shadow counter iterator for index '"
561 << it_shadow.first.GetInfo() <<
"'" <<
G4endl;
569template<
typename TIndex>
573 G4cout <<
"Entering in G4VUserMoleculeCounter::GetMapIndices" <<
G4endl;
584 G4cout <<
"Entering in G4MoleculeCounter::RecordMolecules" <<
G4endl;
586 std::set<const G4MolecularConfiguration*> output{};
588 output.insert(it.first.GetMolecule());
630template<
typename TIndex>
634 && !(index < search.fLastIndexSearched->first))
665 if (timeMap.empty()) {
675 if (upperToLast == timeMap.end()) {
679 if (upperToLast->first > time) {
686 auto up_time_it = timeMap.upper_bound(time);
688 if (up_time_it == timeMap.end()) {
689 auto last_time = timeMap.rbegin();
690 return last_time->second;
692 if (up_time_it == timeMap.begin()) {
706template<
typename TIndex>
709 if (pCounterBase ==
nullptr) {
711 errMsg <<
"Could not cast the pointer to type G4VUserMoleculeCounter<"
713 <<
"Because the pointer is nullptr!" <<
G4endl;
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;
731 if (pCounter->GetType() !=
GetType()) {
733 errMsg <<
"You are trying to absorb a counter with different type!" <<
G4endl;
739 for (
auto const& worker_it : pCounter->GetCounterMap()) {
740 auto [master_it, indexIsNew] =
743 G4int currentNumber = 0, previousNumber = 0;
744 for (
auto const& [time, number] : worker_it.second) {
745 currentNumber = number - previousNumber;
746 previousNumber = number;
748 if (master_it->second.empty()) {
749 master_it->second.emplace(time, currentNumber);
753 auto [it, _] = master_it->second.emplace(time, it_closest->second);
755 it->second += currentNumber;
756 }
while (++it != master_it->second.end());
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
std::map< G4double, G4int, G4MoleculeCounterTimeComparer > InnerCounterMapType
G4GLOB_DLL std::ostream G4cout
static G4MoleculeCounterManager * Instance()
static G4Scheduler * Instance()
G4bool IsTimeBelowLowerBound(G4double) const
G4MoleculeCounterTimeComparer fTimeComparer
const G4String & GetName() const
G4bool IsTimeAboveUpperBound(G4double) const
G4bool fCheckRecordedTimesAreConsistent
G4bool fCheckTimeIsConsistentWithScheduler
G4double fActiveLowerBound
MoleculeCounterType GetType() const
G4bool fNegativeCountsAreFatal
std::set< const G4MoleculeDefinition * > fIgnoredMolecules
std::set< const G4MolecularConfiguration * > fIgnoredReactants
virtual G4int GetNbMoleculesAtTime(const TIndex &, G4double) const
void DumpCounterMapIndices() const override
std::map< TIndex, InnerCounterMapType > fCounterMap
std::vector< TIndex > GetMapIndices() const
void SchedulerFinalizedTracking() override
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
void ResetCounter() override
void Dump() const override
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
G4String GetTemplateTypeName()
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