Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4MoleculeCounter.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//
27
28#include "G4MoleculeCounter.hh"
29
32#include "G4MoleculeTable.hh"
33#include "G4Scheduler.hh" // TODO: remove this dependency
34#include "G4SystemOfUnits.hh"
35#include "G4UIcommand.hh"
36#include "G4UnitsTable.hh"
37
38#include <iomanip>
39#include <memory>
40
41using namespace std;
42
43namespace G4{
44namespace MoleculeCounter {
45
46bool TimePrecision::operator()(const double& a, const double& b) const
47{
48 if (std::fabs(a - b) < fPrecision)
49 {
50 return false;
51 }
52
53 return a < b;
54}
55
56G4ThreadLocal double TimePrecision::fPrecision = 0.5 * picosecond;
57}
58}
59
60//------------------------------------------------------------------------------
62{
63 if (fpInstance == nullptr)
64 {
66 }
67 return dynamic_cast<G4MoleculeCounter*>(fpInstance);
68}
69
70//------------------------------------------------------------------------------
71
77
78//------------------------------------------------------------------------------
79
81
82//------------------------------------------------------------------------------
83
85{
87 while ((mol_iterator)())
88 {
89 if (!IsRegistered(mol_iterator.value()->GetDefinition()))
90 {
91 continue;
92 }
93
94 fCounterMap[mol_iterator.value()]; // initialize the second map
95 }
96}
97
98//------------------------------------------------------------------------------
99
104
105//------------------------------------------------------------------------------
106
108{
109 if (fpLastSearch == nullptr)
110 {
111 fpLastSearch = std::make_unique<Search>();
112 }
113 else
114 {
115 if (fpLastSearch->fLowerBoundSet &&
116 fpLastSearch->fLastMoleculeSearched->first == molecule)
117 {
118 return true;
119 }
120 }
121
122 auto mol_it = fCounterMap.find(molecule);
123 fpLastSearch->fLastMoleculeSearched = mol_it;
124
125 if (mol_it != fCounterMap.end())
126 {
127 fpLastSearch->fLowerBoundTime = fpLastSearch->fLastMoleculeSearched->second
128 .end();
129 fpLastSearch->fLowerBoundSet = true;
130 }
131 else
132 {
133 fpLastSearch->fLowerBoundSet = false;
134 }
135
136 return false;
137}
138
139//------------------------------------------------------------------------------
140
142 bool sameTypeOfMolecule)
143{
144 auto mol_it = fpLastSearch->fLastMoleculeSearched;
145 if (mol_it == fCounterMap.end())
146 {
147 return 0;
148 }
149
150 NbMoleculeAgainstTime& timeMap = mol_it->second;
151 if (timeMap.empty())
152 {
153 return 0;
154 }
155
156 if (sameTypeOfMolecule)
157 {
158 if (fpLastSearch->fLowerBoundSet && fpLastSearch->fLowerBoundTime != timeMap.end())
159 {
160 if (fpLastSearch->fLowerBoundTime->first < time)
161 {
162 auto upperToLast = fpLastSearch->fLowerBoundTime;
163 upperToLast++;
164
165 if (upperToLast == timeMap.end())
166 {
167 return fpLastSearch->fLowerBoundTime->second;
168 }
169
170 if (upperToLast->first > time)
171 {
172 return fpLastSearch->fLowerBoundTime->second;
173 }
174 }
175 }
176 }
177
178 auto up_time_it = timeMap.upper_bound(time);
179
180 if (up_time_it == timeMap.end())
181 {
182 auto last_time = timeMap.rbegin();
183 return last_time->second;
184 }
185 if (up_time_it == timeMap.begin())
186 {
187 return 0;
188 }
189
190 up_time_it--;
191
192 fpLastSearch->fLowerBoundTime = up_time_it;
193 fpLastSearch->fLowerBoundSet = true;
194
195 return fpLastSearch->fLowerBoundTime->second;
196}
197
198//------------------------------------------------------------------------------
199
201 double time)
202{
203 G4bool sameTypeOfMolecule = SearchTimeMap(molecule);
204 return SearchUpperBoundTime(time, sameTypeOfMolecule);
205}
206
207//------------------------------------------------------------------------------
208
210 G4double time,
211 const G4ThreeVector* /*position*/,
212 int number)
213{
214 if (fDontRegister[molecule->GetDefinition()])
215 {
216 return;
217 }
218
219 if (fVerbose != 0)
220 {
221 G4cout << "G4MoleculeCounter::AddAMoleculeAtTime : " << molecule->GetName()
222 << " at time : " << G4BestUnit(time, "Time") << G4endl;
223 }
224
225 auto counterMap_i = fCounterMap.find(molecule);
226
227 if (counterMap_i == fCounterMap.end())
228 {
229 fCounterMap[molecule][time] = number;
230 }
231 else if (counterMap_i->second.empty())
232 {
233 counterMap_i->second[time] = number;
234 }
235 else
236 {
237 auto end = counterMap_i->second.rbegin();
238
239 if (end->first <= time ||
240 fabs(end->first - time) <= G4::MoleculeCounter::TimePrecision::fPrecision)
241 // Case 1 = new time comes after last recorded data
242 // Case 2 = new time is about the same as the last recorded one
243 {
244 double newValue = end->second + number;
245 counterMap_i->second[time] = newValue;
246 }
247 else
248 {
249 // if(fabs(time - G4Scheduler::Instance()->GetGlobalTime()) >
250 // G4Scheduler::Instance()->GetTimeTolerance())
251 {
253 errMsg << "Time of species "
254 << molecule->GetName() << " is "
255 << G4BestUnit(time, "Time") << " while "
256 << " global time is "
257 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
258 << G4endl;
259 G4Exception("G4MoleculeCounter::AddAMoleculeAtTime",
260 "TIME_DONT_MATCH",
261 FatalException, errMsg);
262 }
263 }
264 }
265}
266
267//------------------------------------------------------------------------------
268
270 G4double time,
271 const G4ThreeVector* /*position*/,
272 int number)
273{
274 if (fDontRegister[pMolecule->GetDefinition()])
275 {
276 return;
277 }
278
279 if (fVerbose != 0)
280 {
281 G4cout << "G4MoleculeCounter::RemoveAMoleculeAtTime : "
282 << pMolecule->GetName() << " at time : " << G4BestUnit(time, "Time")
283 << G4endl;
284 }
285
287 {
288 if (fabs(time - G4Scheduler::Instance()->GetGlobalTime()) >
289 G4Scheduler::Instance()->GetTimeTolerance())
290 {
292 errMsg << "Time of species "
293 << pMolecule->GetName() << " is "
294 << G4BestUnit(time, "Time") << " while "
295 << " global time is "
296 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
297 << G4endl;
298 G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
299 "TIME_DONT_MATCH",
300 FatalException, errMsg);
301 }
302 }
303
304 NbMoleculeAgainstTime& nbMolPerTime = fCounterMap[pMolecule];
305
306 if (nbMolPerTime.empty())
307 {
308 pMolecule->PrintState();
309 Dump();
310 G4String errMsg =
311 "You are trying to remove molecule " + pMolecule->GetName() +
312 " from the counter while this kind of molecules has not been registered yet";
313 G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime", "",
314 FatalErrorInArgument, errMsg);
315
316 return;
317 }
318
319 auto it = nbMolPerTime.rbegin();
320
321 if (it == nbMolPerTime.rend())
322 {
323 it--;
324
325 G4String errMsg =
326 "There was no " + pMolecule->GetName() + " recorded at the time or even before the time asked";
327 G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime", "",
328 FatalErrorInArgument, errMsg);
329 }
330
332 {
333 Dump();
335 errMsg << "Is time going back?? " << pMolecule->GetName()
336 << " is being removed at time " << G4BestUnit(time, "Time")
337 << " while last recorded time was "
338 << G4BestUnit(it->first, "Time") << ".";
339 G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
340 "RETURN_TO_THE_FUTUR",
342 errMsg);
343 }
344
345 double finalN = it->second - number;
346
347 if (finalN < 0)
348 {
349 Dump();
351 errMsg << "After removal of " << number << " species of "
352 << pMolecule->GetName() << " the final number at time "
353 << G4BestUnit(time, "Time") << " is less than zero and so not valid."
354 << " Global time is "
355 << G4BestUnit(G4Scheduler::Instance()->GetGlobalTime(), "Time")
356 << ". Previous selected time is "
357 << G4BestUnit(it->first, "Time")
358 << G4endl;
359 G4Exception("G4MoleculeCounter::RemoveAMoleculeAtTime",
360 "N_INF_0",
361 FatalException, errMsg);
362 }
363
364 nbMolPerTime[time] = finalN;
365}
366
367//------------------------------------------------------------------------------
368
370{
371 if (fVerbose > 1)
372 {
373 G4cout << "Entering in G4MoleculeCounter::RecordMolecules" << G4endl;
374 }
375
376 RecordedMolecules output(new ReactantList());
377
378 for (const auto & it : fCounterMap)
379 {
380 output->push_back(it.first);
381 }
382 return output;
383}
384
385//------------------------------------------------------------------------------
386
388{
389 RecordedTimes output(new std::set<G4double>);
390
391 for(const auto& it : fCounterMap)
392 {
393 for(const auto& it2 : it.second)
394 {
395 //time = it2->first;
396 output->insert(it2.first);
397 }
398 }
399
400 return output;
401}
402
403//------------------------------------------------------------------------------
404
405// >>DEV<<
406//void G4MoleculeCounter::SignalReceiver(G4SpeciesInCM* /*speciesInCM*/,
407// size_t moleculeID,
408// int /*number*/,
409// G4SpeciesInCM::SpeciesChange speciesChange,
410// int diff)
411//{
412// switch(speciesChange)
413// {
414// case G4SpeciesInCM::eAdd:
415// AddAMoleculeAtTime(G4MoleculeTable::Instance()->GetConfiguration((int)moleculeID),
416// G4Scheduler::Instance()->GetGlobalTime(),
417// diff);
418// break;
419// case G4SpeciesInCM::eRemove:
420// RemoveAMoleculeAtTime(G4MoleculeTable::Instance()->GetConfiguration((int)moleculeID),
421// G4Scheduler::Instance()->GetGlobalTime(),
422// diff);
423// break;
424// }
425//}
426
427//------------------------------------------------------------------------------
428
430{
431 for (const auto& it : fCounterMap)
432 {
433 auto pReactant = it.first;
434
435 G4cout << " --- > For " << pReactant->GetName() << G4endl;
436
437 for (const auto& it2 : it.second)
438 {
439 G4cout << " " << G4BestUnit(it2.first, "Time")
440 << " " << it2.second << G4endl;
441 }
442 }
443}
444
445//------------------------------------------------------------------------------
446
448{
449 if (fVerbose != 0)
450 {
451 G4cout << " ---> G4MoleculeCounter::ResetCounter" << G4endl;
452 }
453 fCounterMap.clear();
454 fpLastSearch.reset(nullptr);
455}
456
457//------------------------------------------------------------------------------
458
463
464//------------------------------------------------------------------------------
465
467{
468 fVerbose = level;
469}
470
471//------------------------------------------------------------------------------
472
477
478//------------------------------------------------------------------------------
479
481{
482 fDontRegister[molDef] = true;
483}
484
485//------------------------------------------------------------------------------
486
488{
489 return fDontRegister.find(molDef) == fDontRegister.end();
490}
491
492//------------------------------------------------------------------------------
493
495{
496 fDontRegister.clear();
497}
498
503
508
@ FatalException
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
std::map< G4double, G4int, G4::MoleculeCounter::TimePrecision > NbMoleculeAgainstTime
std::unique_ptr< std::set< G4double > > RecordedTimes
#define G4BestUnit(a, b)
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
const G4String & GetName() const
const G4MoleculeDefinition * GetDefinition() const
std::unique_ptr< ReactantList > RecordedMolecules
void Initialize() override
std::map< const G4MoleculeDefinition *, G4bool > fDontRegister
const NbMoleculeAgainstTime & GetNbMoleculeAgainstTime(Reactant *molecule)
RecordedTimes GetRecordedTimes()
static void SetTimeSlice(double)
void RegisterAll() override
G4bool fCheckTimeIsConsistentWithScheduler
void DontRegister(const G4MoleculeDefinition *) override
G4bool SearchTimeMap(Reactant *molecule)
static G4MoleculeCounter * Instance()
void ResetCounter() override
int GetNMoleculesAtTime(Reactant *molecule, double time)
G4bool IsTimeCheckedForConsistency() const
std::unique_ptr< Search > fpLastSearch
CounterMapType fCounterMap
void AddAMoleculeAtTime(Reactant *, G4double time, const G4ThreeVector *position=nullptr, int number=1) override
void RemoveAMoleculeAtTime(Reactant *, G4double time, const G4ThreeVector *position=nullptr, int number=1) override
~G4MoleculeCounter() override
RecordedMolecules GetRecordedMolecules()
void CheckTimeForConsistency(G4bool flag)
int SearchUpperBoundTime(double time, bool sameTypeOfMolecule)
bool IsRegistered(const G4MoleculeDefinition *) override
std::vector< Reactant * > ReactantList
static G4MoleculeTable * Instance()
G4ConfigurationIterator GetConfigurationIterator()
static G4Scheduler * Instance()
static G4ThreadLocal G4VMoleculeCounter * fpInstance
static G4ThreadLocal double fPrecision
bool operator()(const double &a, const double &b) const
#define G4ThreadLocal
Definition tls.hh:77