Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4MoleculeCounterManager.cc
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
29
30#include "G4AutoLock.hh"
33#include "G4StateManager.hh"
34#include "G4Step.hh"
35#include "G4Threading.hh"
36
37//------------------------------------------------------------------------------
38
39static G4Mutex managerInstance;
40static G4Mutex masterInstanceMutex;
41static G4Mutex workerInstancesMutex;
42
43const G4MoleculeCounterManager* G4MoleculeCounterManager::fpMasterInstance = nullptr;
44std::vector<const G4MoleculeCounterManager*> G4MoleculeCounterManager::fWorkerInstances = {};
45G4ThreadLocal std::unique_ptr<G4MoleculeCounterManager> G4MoleculeCounterManager::fpInstance = nullptr;
46
47//------------------------------------------------------------------------------
48
49G4ThreadLocal std::atomic<G4bool> G4MoleculeCounterManager::fBeginOfEventTriggered(false);
50std::atomic<G4bool> G4MoleculeCounterManager::fBeginOfRunTriggered(false);
51
52//------------------------------------------------------------------------------
53
54//
55// CTOR & INSTANCE
56//
57
59 : fVerbosity(0), fIsInitialized(false), fIsActive(true)
60{
61 fpMessenger = std::make_unique<G4MoleculeCounterManagerMessenger>(this);
62}
63
65{
66 // The manager owns all the counters as raw pointers, clean up:
68
69 if (fVerbosity > 0) {
70 if (GetResetCountersBeforeRun() && !fBeginOfRunTriggered.load()) {
71 G4Exception("G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN000", JustWarning,
72 "The molecule counter manager was configured to reset counters before each run"
73 " but the BeginOfRunAction was never triggered!\n"
74 "Ensure that the user code calls either the G4DNAChemistryManager's or "
75 "G4MoleculeCounterManager's Run methods!");
76 }
77 if (GetResetCountersBeforeEvent() && !fBeginOfEventTriggered.load()
79 {
80 // ignore, if this is the master of a MT application
81 G4Exception("G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN000", JustWarning,
82 "The molecule counter manager was configured to reset counters before each event"
83 " but the BeginOfEventAction was never triggered!\n"
84 "This can occurr if this thread is never processing an event but:\n"
85 "Ensure that the user code calls either the G4DNAChemistryManager's or "
86 "G4MoleculeCounterManager's Event methods!");
87 }
88 }
89
90 // Handle the recorded master and worker instances
92 // This is the master's dtor: set the master const* to nullptr (as it will point to nothing of use)
93 G4AutoLock lockMaster(&masterInstanceMutex);
94 fpMasterInstance = nullptr;
95 }
96 else {
97 // This is a worker's dtor: make sure that this worker is still in the list of instances.
98 // If not, throw a warning (something fishy going on?)
99 // Either way, set this worker's const* to nullptr in the list of instances.
100 G4AutoLock lock(&workerInstancesMutex);
101 auto it = std::find(fWorkerInstances.begin(), fWorkerInstances.end(), this);
102 if (it == fWorkerInstances.end()) {
104 "G4MoleculeCounterManager::~G4MoleculeCounterManager", "MOLMAN_DTOR", JustWarning,
105 "The destroyed instance of G4MoleculeCounterManager has not been registered as a worker!");
106 }
107 else {
108 (*it) = nullptr;
109 }
110 }
111}
112
113void G4MoleculeCounterManager::RegisterInstance()
114{
115 if (fInstancesRegistered) {
116 G4Exception("G4MoleculeCounterManager::RegisterInstance", "MOLMAN000", FatalException,
117 "Instances were already registered once!");
118 }
119 else {
121 G4AutoLock lock(&masterInstanceMutex);
122 if (fpMasterInstance != nullptr) {
123 G4Exception("G4MoleculeCounterManager::RegisterInstance", "MOLMAN000", FatalException,
124 "Master instance was set already!");
125 }
126 fpMasterInstance = Instance();
127 }
128 else {
129 G4AutoLock lock(&workerInstancesMutex);
130 fWorkerInstances.push_back(Instance());
131 }
132 fInstancesRegistered = true;
133 }
134}
135
137{
138 if (fpInstance == nullptr) {
139 G4AutoLock lock(&managerInstance);
140 fpInstance = std::make_unique<G4MoleculeCounterManager>(G4MoleculeCounterManager::Private());
141 fpInstance->RegisterInstance();
142 }
143 return fpInstance.get();
144}
145
150
152{
153 G4AutoLock lock(&managerInstance);
154
155 if (fpInstance != nullptr) {
156 fpInstance.reset();
157 // this should (test!) trigger the dtor, which will delete/deregister the counters
158 }
159}
160
161// ---------------------------------------------------------------------
162
163//
164// Initialization
165//
166
168{
169 if (fVerbosity > 0) {
170 G4cout << "G4MoleculeCounterManager::Initialize ("
171 << (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
172 }
173
176 InitializeWorker();
177 else
178 InitializeMaster();
179 }
180 else {
181 InitializeMaster();
182 }
183}
184
185void G4MoleculeCounterManager::InitializeMaster()
186{
187 if (fIsInitialized) return;
188 for (auto& counter : fCounters)
189 counter.second->Initialize();
190}
191
192void G4MoleculeCounterManager::InitializeWorker()
193{
194 if (fIsInitialized) return;
195 for (auto& counter : fCounters)
196 counter.second->Initialize();
197}
198
199// ---------------------------------------------------------------------
200
201//
202// Add & Remove Molecules
203//
204
206 G4double time, G4int n)
207{
208 for (auto& [id, counter] : fCounters) {
209 counter->AddMolecule(counter->BuildSimpleIndex(molecule), time, n);
210 }
211}
212
214 G4double time, G4int n)
215{
216 for (auto& [id, counter] : fCounters) {
217 counter->RemoveMolecule(counter->BuildSimpleIndex(molecule), time, n);
218 }
219}
220
222{
223 for (auto& [id, counter] : fCounters) {
224 counter->AddMolecule(counter->BuildIndex(aTrack), time, n);
225 }
226}
227
229{
230 for (auto& [id, counter] : fCounters) {
231 counter->RemoveMolecule(counter->BuildIndex(aTrack), time, n);
232 }
233}
234
235void G4MoleculeCounterManager::AddMolecule(const G4Track* aTrack, const G4StepPoint* aStepPoint,
236 G4double time, G4int n)
237{
238 for (auto& [id, counter] : fCounters) {
239 if (counter->GetSensitiveToStepping()) {
240 counter->AddMolecule(counter->BuildIndex(aTrack, aStepPoint), time, n);
241 }
242 }
243}
244
246 G4double time, G4int n)
247{
248 for (auto& [id, counter] : fCounters) {
249 if (counter->GetSensitiveToStepping()) {
250 counter->RemoveMolecule(counter->BuildIndex(aTrack, aStepPoint), time, n);
251 }
252 }
253}
254
255// ---------------------------------------------------------------------
256
258 G4double time, G4int n)
259{
260 for (auto& [id, counter] : fReactionCounters) {
261 counter->RecordReaction(counter->BuildSimpleIndex(reactionData), time, n);
262 }
263}
264
265// ---------------------------------------------------------------------
266
267//
268// Notification of Step or Finalization (must be implemented in a custom G4ITTrackingInteractivity!
269//
270
271/* Example:
272 void ChemistrySteppingAction::UserSteppingAction(const G4Step* aStep)
273 {
274 if (G4MoleculeCounterManager::Instance()->GetIsActive())
275 G4MoleculeCounterManager::Instance()->NotifyOfStep(aStep);
276 }
277 */
278
280{
281 const G4Track* aTrack = aStep->GetTrack();
282
283 for (auto& [id, counter] : fCounters) {
284 auto preStepIndex = counter->BuildIndex(aTrack, aStep->GetPreStepPoint());
285 auto postStepIndex = counter->BuildIndex(aTrack, aStep->GetPostStepPoint());
286
287 if (!(*preStepIndex == *postStepIndex)) {
288#ifdef G4VERBOSE
289 if (GetVerbosity() > 1) {
290 G4cout << "G4MoleculeCounterManager::NotifyOfStep for counter " << counter->GetName()
291 << ":\n-- Pre = " << preStepIndex->GetInfo() << "\n"
292 << "-- Post = " << postStepIndex->GetInfo() << G4endl;
293 }
294#endif
295 counter->RemoveMolecule(std::move(preStepIndex), aTrack->GetGlobalTime(), 1);
296 counter->AddMolecule(std::move(postStepIndex), aTrack->GetGlobalTime(), 1);
297 }
298 }
299}
300
302{
303 for (auto& [id, counter] : fCounters) {
304 counter->SchedulerFinalizedTracking();
305 }
306}
307
308//
309// Broadcast Functions
310//
311
313{
314 for (auto& [id, counter] : fCounters) {
315 counter->IgnoreMolecule(molecule);
316 }
317}
318
320{
321 for (auto& [id, counter] : fCounters) {
322 counter->IgnoreReactant(molecule);
323 }
324}
325
327{
328 for (auto& [id, counter] : fCounters) {
329 counter->RegisterAll();
330 }
331}
332
333//------------------------------------------------------------------------------
334
335//
336// Manager Functions
337//
338
339G4int G4MoleculeCounterManager::RegisterCounter(std::unique_ptr<G4VMoleculeCounter> counter)
340{
341 auto idProvider = [&]() {
342 if (fCounters.size() == 0) return 0;
343 auto indices = G4::MoleculeCounter::GetMapIndices(fCounters);
344 auto lastIndex = *indices.rbegin();
345 return ++lastIndex;
346 };
347
348 return RegisterCounter(fCounters, std::move(counter), idProvider);
349}
350
351//------------------------------------------------------------------------------
352
353G4int G4MoleculeCounterManager::RegisterCounter(std::unique_ptr<G4VMoleculeReactionCounter> counter)
354{
355 auto idProvider = [&] {
356 if (fReactionCounters.size() == 0) return 0;
357 auto indices = G4::MoleculeCounter::GetMapIndices(fReactionCounters);
358 auto lastIndex = *indices.rbegin();
359 return ++lastIndex;
360 };
361
362 return RegisterCounter(fReactionCounters, std::move(counter), idProvider);
363}
364
365//------------------------------------------------------------------------------
366
368{
369 for (auto& [id, ctr] : fCounters) {
370 delete ctr;
371 }
372 fCounters.clear();
373
374 for (auto& [id, ctr] : fReactionCounters) {
375 delete ctr;
376 }
377 fReactionCounters.clear();
378}
379
380//------------------------------------------------------------------------------
381
382//
383// Manipulate Counters
384//
385
387{
388 if (fVerbosity > 0) {
389 G4cout << "G4MoleculeCounterManager::ResetCounters ("
390 << (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
391 }
392
393 for (auto& [id, counter] : fCounters)
394 counter->ResetCounter();
395 for (auto& [id, counter] : fReactionCounters)
396 counter->ResetCounter();
397}
398
399//------------------------------------------------------------------------------
400
402 G4double belowTime, G4bool aboveTimeInclusive,
403 G4bool belowTimeInclusive)
404{
405 if (fVerbosity > 0) {
406 G4cout << "G4MoleculeCounterManager::ActivateCounterAtTimes ("
407 << (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
408 }
409
411 counter->SetActiveLowerBound(aboveTime, aboveTimeInclusive);
412 counter->SetActiveUpperBound(belowTime, belowTimeInclusive);
413}
414
416 G4double belowTime,
417 G4bool aboveTimeInclusive,
418 G4bool belowTimeInclusive)
419{
420 if (fVerbosity > 0) {
421 G4cout << "G4MoleculeCounterManager::ActivateReactionCounterAtTimes ("
422 << (G4Threading::IsMasterThread() ? "master" : "worker") << ")" << G4endl;
423 }
424
426 counter->SetActiveLowerBound(aboveTime, aboveTimeInclusive);
427 counter->SetActiveUpperBound(belowTime, belowTimeInclusive);
428}
429
430//------------------------------------------------------------------------------
431
433{
434 auto it = fCounters.find(id);
435 if (it == fCounters.end()) {
436 G4ExceptionDescription description;
437 description << "No molecule counter with Id = " << id << " was found!\n";
438 G4Exception("G4MoleculeCounterManager::GetMoleculeCounter", "MOLMAN001", FatalErrorInArgument,
439 description);
440 return nullptr;
441 }else{
442 return it->second;
443 }
444}
445
446std::vector<const G4VMoleculeCounter*> G4MoleculeCounterManager::GetMoleculeCounters() const
447{
448 std::vector<const G4VMoleculeCounter*> output;
449 output.reserve(fCounters.size());
450 for (auto& [id, counter] : fCounters)
451 output.push_back(counter);
452 return output;
453}
454
455std::vector<const G4VMoleculeCounter*> G4MoleculeCounterManager::GetMoleculeCounters(G4String name) const
456{
457 std::vector<const G4VMoleculeCounter*> output;
458 for (auto& [id, counter] : fCounters) {
459 if (name == counter->GetName()) output.push_back(counter);
460 }
461 return output;
462}
463
464//------------------------------------------------------------------------------
465
468{
469 auto it = fReactionCounters.find(id);
470 if (it == fReactionCounters.end()) {
471 G4ExceptionDescription description;
472 description << "No molecule reaction counter with Id = " << id << " was found!\n";
473 G4Exception("G4MoleculeCounterManager::GetMoleculeReactionCounter", "MOLMAN001",
474 FatalErrorInArgument, description);
475 return nullptr;
476 }else
477 {
478 return it->second;
479 }
480}
481
482std::vector<const G4VMoleculeReactionCounter*>
484{
485 std::vector<const G4VMoleculeReactionCounter*> output;
486 output.reserve(fReactionCounters.size());
487 for (auto& [id, counter] : fReactionCounters)
488 output.push_back(counter);
489 return output;
490}
491
492std::vector<const G4VMoleculeReactionCounter*>
494{
495 std::vector<const G4VMoleculeReactionCounter*> output;
496 for (auto& [id, counter] : fReactionCounters) {
497 if (name == counter->GetName()) output.push_back(counter);
498 }
499 return output;
500}
501
502//------------------------------------------------------------------------------
503
505{
506 fBeginOfEventTriggered = true;
507
509 // trigger reset if:
510 // * is not an MT app (master = worker)
511 // * is an MT app, master, and we want to reset the master
512 // * is an MT app and worker
518 }
519}
520
521//------------------------------------------------------------------------------
522
524{
525 fBeginOfRunTriggered = true;
526
528 // trigger reset if:
529 // * is not an MT app (master = worker)
530 // * is an MT app, master, and we want to reset the master
531 // * is an MT app and worker
537 }
538}
539
540//------------------------------------------------------------------------------
541
543{
544 // EndOfEvent is never triggered on the master of a G4MT
547 {
549 }
550}
551
552//------------------------------------------------------------------------------
553
555{
558 // if ResetBeforeEvent, AbsorbWorkerManagerCounters will have been triggered already
561}
562
563//------------------------------------------------------------------------------
564
566 const G4MoleculeCounterManager* selectedWorker)
567{
568 if (selectedWorker == nullptr && !G4Threading::IsMasterThread()) {
569 // Can only call without worker from master thread!
570 G4ExceptionDescription description;
571 description << "This method may only be called from the master thread!";
572 G4Exception("G4MoleculeCounterManager::AbsorbWorkerManagerCounters", "MOLMAN999",
573 FatalException, description);
574 }
575
576 // prevent changes to any of the instances
577 G4AutoLock lockMaster(&masterInstanceMutex);
578 G4AutoLock lockWorker(&workerInstancesMutex);
579
580 for (auto const& worker : fWorkerInstances) {
581 if (selectedWorker == nullptr || worker != selectedWorker) continue;
582
583 for (auto& [id, masterCounter] : fpMasterInstance->fCounters) {
584 // acquire worker counter
585 auto workerCounter = worker->GetMoleculeCounter(id);
586 masterCounter->AbsorbCounter(workerCounter);
587 }
588
589 for (auto& [id, masterCounter] : fpMasterInstance->fReactionCounters) {
590 // acquire worker counter
591 auto workerCounter = worker->GetMoleculeReactionCounter(id);
592 masterCounter->AbsorbCounter(workerCounter);
593 }
594 }
595}
596
597//------------------------------------------------------------------------------
598
600{
601 G4AutoLock lock(&masterInstanceMutex);
602
603 for (auto const& pCounter : fpMasterInstance->GetMoleculeCounters()) {
604 G4cout << "=========================================================================== \n"
605 << " >> [MASTER] Dumping Molecule Counter `" << pCounter->GetName() << "`\n"
606 << G4endl;
607 pCounter->Dump();
608 G4cout << "\n=========================================================================== "
609 << G4endl;
610 }
611
612 for (auto const& pCounter : fpMasterInstance->GetMoleculeReactionCounters()) {
613 G4cout << "=========================================================================== \n"
614 << " >> [MASTER] Dumping Molecule Reaction Counter `" << pCounter->GetName() << "`\n"
615 << G4endl;
616 pCounter->Dump();
617 G4cout << "\n=========================================================================== "
618 << G4endl;
619 }
620}
621
622//------------------------------------------------------------------------------
623
625{
626 G4AutoLock lock(&workerInstancesMutex);
627
628 for (auto const& worker : G4MoleculeCounterManager::fWorkerInstances) {
629 for (auto const& pCounter : worker->GetMoleculeCounters()) {
630 G4cout << "=========================================================================== \n"
631 << " >> [WORKER<" << worker << ">] Dumping Molecule Counter `" << pCounter->GetName()
632 << "`\n"
633 << G4endl;
634 pCounter->Dump();
635 G4cout << "\n=========================================================================== "
636 << G4endl;
637 }
638
639 for (auto const& pCounter : worker->GetMoleculeReactionCounters()) {
640 G4cout << "=========================================================================== \n"
641 << " >> [WORKER<" << worker << ">] Dumping Molecule Reaction Counter `"
642 << pCounter->GetName() << "`\n"
643 << G4endl;
644 pCounter->Dump();
645 G4cout << "\n=========================================================================== "
646 << G4endl;
647 }
648 }
649}
650
651//------------------------------------------------------------------------------
652
653std::atomic<G4bool> G4MoleculeCounterManager::fResetCountersBeforeEvent(false);
654std::atomic<G4bool> G4MoleculeCounterManager::fResetCountersBeforeRun(false);
655std::atomic<G4bool> G4MoleculeCounterManager::fAccumulateCounterIntoMaster(true);
656std::atomic<G4bool> G4MoleculeCounterManager::fResetMasterCounterWithWorkers(false);
657
659{
660 return fResetCountersBeforeEvent.load();
661}
663{
664 if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit) {
665 fResetCountersBeforeEvent = flag;
666 }
667 else
668 G4Exception("G4DNAChemistryManager::SetResetCountersBeforeEvent", "WRONG_STATE", FatalException,
669 "This flag may only be set during the PreInit state!");
670}
671
673{
674 return fResetCountersBeforeRun.load();
675}
677{
678 if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
679 fResetCountersBeforeRun = flag;
680 else
681 G4Exception("G4DNAChemistryManager::SetResetCountersBeforeRun", "WRONG_STATE", FatalException,
682 "This flag may only be set during the PreInit state!");
683}
684
686{
687 return fAccumulateCounterIntoMaster.load();
688}
690{
691 if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
692 fAccumulateCounterIntoMaster = flag;
693 else
694 G4Exception("G4DNAChemistryManager::SetAccumulateCounterIntoMaster", "WRONG_STATE",
695 FatalException, "This flag may only be set during the PreInit state!");
696}
697
699{
700 return fResetMasterCounterWithWorkers.load();
701}
703{
704 if (G4StateManager::GetStateManager()->GetCurrentState() == G4State_PreInit)
705 fResetMasterCounterWithWorkers = flag;
706 else
707 G4Exception("G4DNAChemistryManager::SetResetMasterCounterWithWorkers", "WRONG_STATE",
708 FatalException, "This flag may only be set during the PreInit state!");
709}
710
711//------------------------------------------------------------------------------
@ G4State_PreInit
G4TemplateAutoLock< G4Mutex > G4AutoLock
@ JustWarning
@ FatalException
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
std::mutex G4Mutex
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
void ActivateReactionCounterAtTimes(G4int, G4double, G4double, G4bool=true, G4bool=true)
void BroadcastIgnoreMolecule(const G4MoleculeDefinition *)
void RecordReaction(const G4DNAMolecularReactionData *, G4double, G4int=1)
void EndOfEventAction(const G4Event *)
void SetResetMasterCounterWithWorkers(G4bool=true)
void AddMoleculeWithoutTrack(const G4MolecularConfiguration *, G4double, G4int=1)
G4int RegisterCounter(std::unique_ptr< G4VMoleculeCounter >)
G4VMoleculeReactionCounter * GetEditableMoleculeReactionCounter(G4int) const
void SetAccumulateCounterIntoMaster(G4bool=true)
void AddMolecule(const G4Track *, G4double, G4int=1)
void BeginOfEventAction(const G4Event *)
void RemoveMoleculeWithoutTrack(const G4MolecularConfiguration *, G4double, G4int=1)
static G4MoleculeCounterManager * GetInstanceIfExists()
G4VMoleculeCounter * GetEditableMoleculeCounter(G4int) const
void AbsorbWorkerManagerCounters(const G4MoleculeCounterManager *=nullptr)
static G4MoleculeCounterManager * Instance()
void ActivateCounterAtTimes(G4int, G4double, G4double, G4bool=true, G4bool=true)
std::vector< const G4VMoleculeReactionCounter * > GetMoleculeReactionCounters() const
void RemoveMolecule(const G4Track *, G4double, G4int=1)
void SetResetCountersBeforeEvent(G4bool=true)
void BroadcastIgnoreReactant(const G4MolecularConfiguration *)
std::vector< const G4VMoleculeCounter * > GetMoleculeCounters() const
Definition G4Run.hh:48
static G4StateManager * GetStateManager()
G4Track * GetTrack() const
G4StepPoint * GetPreStepPoint() const
G4StepPoint * GetPostStepPoint() const
G4double GetGlobalTime() const
G4bool IsWorkerThread()
G4bool IsMultithreadedApplication()
G4bool IsMasterThread()
const std::vector< T > GetMapIndices(const std::map< T, U > &_map)
#define G4ThreadLocal
Definition tls.hh:77