Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4DNAIRTMoleculeEncounterStepper.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 * G4DNAIRTMoleculeEncounterStepper.cc
29 *
30 * Created on: Jul 23, 2019
31 * Author: W. G. Shin
32 * J. Ramos-Mendez and B. Faddegon
33*/
34
38#include "G4H2O.hh"
39#include "G4memory.hh"
40#include "G4UnitsTable.hh"
41#include "G4MoleculeFinder.hh"
43#include "G4Scheduler.hh"
44#include "G4ITReaction.hh"
45
46using namespace std;
47using namespace CLHEP;
48
49//#define DEBUG_MEM
50
51#ifdef DEBUG_MEM
52#include "G4MemStat.hh"
53using namespace G4MemStat;
54#endif
55
56G4DNAIRTMoleculeEncounterStepper::Utils::Utils(const G4Track& tA,
57 const G4MolecularConfiguration* pMoleculeB)
58 : fpTrackA(tA)
59 , fpMoleculeB(pMoleculeB)
60{
61 fpMoleculeA = GetMolecule(tA);
62 fDA = fpMoleculeA->GetDiffusionCoefficient();
63 fDB = fpMoleculeB->GetDiffusionCoefficient();
64 fConstant = 8 * (fDA + fDB + 2 * sqrt(fDA * fDB));
65}
66
69 , fHasAlreadyReachedNullTime(false)
70 , fMolecularReactionTable(reference_cast<const G4DNAMolecularReactionTable*>(fpReactionTable))
71 , fReactionModel(nullptr)
72 , fVerbose(0)
73{
74 fpTrackContainer = G4ITTrackHolder::Instance();
75 fReactionSet = G4ITReactionSet::Instance();
76}
77
79
81{
83 if(G4Scheduler::Instance()->GetGlobalTime() == G4Scheduler::Instance()->GetStartTime()){
86 }
87}
88
89void G4DNAIRTMoleculeEncounterStepper::InitializeForNewTrack()
90{
91 if (fReactants)
92 {
93 fReactants.reset();
94 }
96 fHasAlreadyReachedNullTime = false;
97}
98
99template<typename T>
100inline bool IsInf(T value)
101{
102 return std::numeric_limits<T>::has_infinity
103 && value == std::numeric_limits<T>::infinity();
104}
105
108 const G4double& userMinTimeStep)
109{
110
111 auto pMoleculeA = GetMolecule(trackA);
112 InitializeForNewTrack();
113 fUserMinTimeStep = userMinTimeStep;
114
115#ifdef G4VERBOSE
116 if (fVerbose)
117 {
118 G4cout
119 << "_______________________________________________________________________"
120 << G4endl;
121 G4cout << "G4DNAMoleculeEncounterStepper::CalculateStep" << G4endl;
122 G4cout << "Check done for molecule : " << pMoleculeA->GetName()
123 << " (" << trackA.GetTrackID() << ") "
124 << G4endl;
125 }
126#endif
127
128 //__________________________________________________________________
129 // Retrieve general informations for making reactions
130 auto pMolConfA = pMoleculeA->GetMolecularConfiguration();
131
132 const auto pReactantList = fMolecularReactionTable->CanReactWith(pMolConfA);
133
134 if (!pReactantList)
135 {
136#ifdef G4VERBOSE
137 // DEBUG
138 if (fVerbose > 1)
139 {
140 G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
141 G4cout << "!!! WARNING" << G4endl;
142 G4cout << "G4MoleculeEncounterStepper::CalculateStep will return infinity "
143 "for the reaction because the molecule "
144 << pMoleculeA->GetName()
145 << " does not have any reactants given in the reaction table."
146 << G4endl;
147 G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
148 }
149#endif
150 return DBL_MAX;
151 }
152
153 G4int nbReactives = (G4int)pReactantList->size();
154
155 if (nbReactives == 0)
156 {
157#ifdef G4VERBOSE
158 // DEBUG
159 if (fVerbose)
160 {
161 // TODO replace with the warning mode of G4Exception
162 G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
163 G4cout << "!!! WARNING" << G4endl;
164 G4cout << "G4MoleculeEncounterStepper::CalculateStep will return infinity "
165 "for the reaction because the molecule "
166 << pMoleculeA->GetName()
167 << " does not have any reactants given in the reaction table."
168 << "This message can also result from a wrong implementation of the reaction table."
169 << G4endl;
170 G4cout << "!!!!!!!!!!!!!!!!!!!!" << G4endl;
171 }
172#endif
173 return DBL_MAX;
174 }
175
176 fReactants.reset(new vector<G4Track*>());
177 fReactionModel->Initialise(pMolConfA, trackA);
178
179 //__________________________________________________________________
180 // Start looping on possible reactants
181 for (G4int i = 0; i < nbReactives; ++i)
182 {
183 auto pMoleculeB = (*pReactantList)[i];
184
185 //______________________________________________________________
186 // Retrieve reaction range
187 const G4double R = fReactionModel->GetReactionRadius(i);
188
189 //______________________________________________________________
190 // Use KdTree algorithm to find closest reactants
191 G4KDTreeResultHandle resultsNearest(
192 G4MoleculeFinder::Instance()->FindNearest(pMoleculeA,
193 pMoleculeB->GetMoleculeID()));
194
195 if (resultsNearest == 0) continue;
196
197 G4double r2 = resultsNearest->GetDistanceSqr();
198 Utils utils(trackA, pMoleculeB);
199
200 if (r2 <= R * R) // ==> Record in range
201 {
202 // Entering in this condition may due to the fact that molecules are very close
203 // to each other
204 // Therefore, if we only take the nearby reactant into account, it might have already
205 // reacted. Instead, we will take all possible reactants that satisfy the condition r<R
206
207 if (fHasAlreadyReachedNullTime == false)
208 {
209 fReactants->clear();
210 fHasAlreadyReachedNullTime = true;
211 }
212
214 G4KDTreeResultHandle resultsInRange(
215 G4MoleculeFinder::Instance()->FindNearestInRange(pMoleculeA,
216 pMoleculeB->GetMoleculeID(),
217 R));
218 CheckAndRecordResults(utils,
219#ifdef G4VERBOSE
220 R,
221#endif
222 resultsInRange);
223 }
224 else
225 {
226 G4double r = sqrt(r2);
227 G4double tempMinET = pow(r - R, 2) / utils.fConstant;
228 // constant = 16 * (fDA + fDB + 2*sqrt(fDA*fDB))
229
230 if (tempMinET <= fSampledMinTimeStep)
231 {
232 if (fUserMinTimeStep < DBL_MAX/*IsInf(fUserMinTimeStep) == false*/
233 && tempMinET <= fUserMinTimeStep) // ==> Record in range
234 {
236 {
237 fReactants->clear();
238 }
239
241
242 G4double range = R + sqrt(fUserMinTimeStep*utils.fConstant);
243
244 G4KDTreeResultHandle resultsInRange(
246 FindNearestInRange(pMoleculeA,
247 pMoleculeB->GetMoleculeID(),
248 range));
249
250 CheckAndRecordResults(utils,
251#ifdef G4VERBOSE
252 range,
253#endif
254 resultsInRange);
255 }
256 else // ==> Record nearest
257 {
258 if (tempMinET < fSampledMinTimeStep)
259 // to avoid cases where fSampledMinTimeStep == tempMinET
260 {
261 fSampledMinTimeStep = tempMinET;
262 fReactants->clear();
263 }
264
265 CheckAndRecordResults(utils,
266#ifdef G4VERBOSE
267 R,
268#endif
269 resultsNearest);
270 }
271 }
272 }
273 }
274
275#ifdef G4VERBOSE
276 if (fVerbose)
277 {
278 G4cout << "G4MoleculeEncounterStepper::CalculateStep will finally return :"
280
281 if (fVerbose > 1)
282 {
283 G4cout << "Selected reactants for trackA: " << pMoleculeA->GetName()
284 << " (" << trackA.GetTrackID() << ") are: ";
285
286 vector<G4Track*>::iterator it;
287 for (it = fReactants->begin(); it != fReactants->end(); it++)
288 {
289 G4Track* trackB = *it;
290 G4cout << GetMolecule(trackB)->GetName() << " ("
291 << trackB->GetTrackID() << ") \t ";
292 }
293 G4cout << G4endl;
294 }
295 }
296#endif
297 return fSampledMinTimeStep;
298}
299
300
301
302
303void G4DNAIRTMoleculeEncounterStepper::CheckAndRecordResults(const Utils& utils,
304#ifdef G4VERBOSE
305 const G4double R,
306#endif
307 G4KDTreeResultHandle& results)
308{
309 if (results == 0)
310 {
311#ifdef G4VERBOSE
312 if (fVerbose > 1)
313 {
314 G4cout << "No molecule " << utils.fpMoleculeB->GetName()
315 << " found to react with " << utils.fpMoleculeA->GetName()
316 << G4endl;
317 }
318#endif
319 return;
320 }
321
322 for (results->Rewind(); !results->End(); results->Next())
323 {
324 G4IT* reactiveB = results->GetItem<G4IT>();
325
326 if (reactiveB == 0)
327 {
328 continue;
329 }
330
331 G4Track *trackB = reactiveB->GetTrack();
332
333 if (trackB == 0)
334 {
335 G4ExceptionDescription exceptionDescription;
336 exceptionDescription
337 << "The reactant B found using the MoleculeFinder does not have a valid "
338 "track attached to it. If this is done on purpose, please do "
339 "not record this molecule in the MoleculeFinder."
340 << G4endl;
341 G4Exception("G4DNAMoleculeEncounterStepper::RetrieveResults",
342 "MoleculeEncounterStepper001", FatalErrorInArgument,
343 exceptionDescription);
344 continue;
345 }
346
347 if (trackB->GetTrackStatus() != fAlive)
348 {
349 continue;
350 }
351
352 if (trackB == &utils.fpTrackA)
353 {
354 G4ExceptionDescription exceptionDescription;
355 exceptionDescription
356 << "A track is reacting with itself (which is impossible) ie fpTrackA == trackB"
357 << G4endl;
358 exceptionDescription << "Molecule A (and B) is of type : "
359 << utils.fpMoleculeA->GetName() << " with trackID : "
360 << utils.fpTrackA.GetTrackID() << G4endl;
361
362 G4Exception("G4DNAMoleculeEncounterStepper::RetrieveResults",
363 "MoleculeEncounterStepper003", FatalErrorInArgument,
364 exceptionDescription);
365
366 }
367
368 if (fabs(trackB->GetGlobalTime() - utils.fpTrackA.GetGlobalTime())
369 > utils.fpTrackA.GetGlobalTime() * (1 - 1 / 100))
370 {
371 // DEBUG
372 G4ExceptionDescription exceptionDescription;
373 exceptionDescription
374 << "The interacting tracks are not synchronized in time" << G4endl;
375 exceptionDescription
376 << "trackB->GetGlobalTime() != fpTrackA.GetGlobalTime()" << G4endl;
377
378 exceptionDescription << "fpTrackA : trackID : " << utils.fpTrackA.GetTrackID()
379 << "\t Name :" << utils.fpMoleculeA->GetName()
380 << "\t fpTrackA->GetGlobalTime() = "
381 << G4BestUnit(utils.fpTrackA.GetGlobalTime(), "Time") << G4endl;
382
383 exceptionDescription << "trackB : trackID : " << trackB->GetTrackID()
384 << "\t Name :" << utils.fpMoleculeB->GetName()
385 << "\t trackB->GetGlobalTime() = "
386 << G4BestUnit(trackB->GetGlobalTime(), "Time") << G4endl;
387
388 G4Exception("G4DNAMoleculeEncounterStepper::RetrieveResults",
389 "MoleculeEncounterStepper004", FatalErrorInArgument,
390 exceptionDescription);
391 }
392
393#ifdef G4VERBOSE
394 if (fVerbose > 1)
395 {
396
397 G4double r2 = results->GetDistanceSqr();
398 G4cout << "\t ************************************************** " << G4endl;
399 G4cout << "\t Reaction between "
400 << utils.fpMoleculeA->GetName() << " (" << utils.fpTrackA.GetTrackID() << ") "
401 << " & " << utils.fpMoleculeB->GetName() << " (" << trackB->GetTrackID() << "), "
402 << "Interaction Range = "
403 << G4BestUnit(R, "Length") << G4endl;
404 G4cout << "\t Real distance between reactants = "
405 << G4BestUnit((utils.fpTrackA.GetPosition() - trackB->GetPosition()).mag(), "Length") << G4endl;
406 G4cout << "\t Distance between reactants calculated by nearest neighbor algorithm = "
407 << G4BestUnit(sqrt(r2), "Length") << G4endl;
408
409 }
410#endif
411
412 fReactants->push_back(trackB);
413 }
414}
415
417{
418 fReactionModel = pReactionModel;
419}
420
422{
423 return fReactionModel;
424}
425
427{
428 fVerbose = flag;
429}
430
432
433 G4bool start = true;
434 G4bool active = false;
435
436 fUserMinTimeStep = definedMinTimeStep;
437
438 if(fReactionSet->Empty()){
439 if(currentGlobalTime == G4Scheduler::Instance()->GetStartTime()){
440
441 for (auto pTrack : *fpTrackContainer->GetMainList())
442 {
443 if (pTrack == nullptr)
444 {
445 G4ExceptionDescription exceptionDescription;
446 exceptionDescription << "No track found.";
447 G4Exception("G4Scheduler::CalculateMinStep", "ITScheduler006",
448 FatalErrorInArgument, exceptionDescription);
449 continue;
450 }
451
452 G4TrackStatus trackStatus = pTrack->GetTrackStatus();
453 if (trackStatus == fStopAndKill || trackStatus == fStopButAlive)
454 {
455 start = false;
456 continue;
457 }
458 active = true;
459 }
460
461 if(start == true){
462 return -1;
463 }else if(active == false){
465 return fSampledMinTimeStep;
466 }else{
467 return fSampledMinTimeStep;
468 }
469
470 }else{
471 for (auto pTrack : *fpTrackContainer->GetMainList())
472 {
473 pTrack->SetGlobalTime(G4Scheduler::Instance()->GetEndTime());
474 }
475 return fSampledMinTimeStep;
476 }
477 }
478
479 auto fReactionSetInTime = fReactionSet->GetReactionsPerTime();
480 fSampledMinTimeStep = fReactionSetInTime.begin()->get()->GetTime() - currentGlobalTime;
481
482 return fSampledMinTimeStep;
483}
bool IsInf(T value)
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
G4Molecule * GetMolecule(const G4Track &track)
Definition: G4Molecule.cc:74
ReturnType & reference_cast(OriginalType &source)
G4TrackStatus
@ fAlive
@ fStopAndKill
@ fStopButAlive
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
virtual G4double CalculateMinTimeStep(G4double, G4double)
virtual G4double CalculateStep(const G4Track &, const G4double &)
const ReactantList * CanReactWith(Reactant *) const
void UpdatePositionMap() override
static G4ITFinder * Instance()
static G4ITReactionSet * Instance()
G4ITReactionPerTime & GetReactionsPerTime()
G4TrackList * GetMainList(Key)
static G4ITTrackHolder * Instance()
Definition: G4IT.hh:88
G4Track * GetTrack()
Definition: G4IT.hh:218
const G4String & GetName() const
Definition: G4Molecule.cc:336
static G4Scheduler * Instance()
Definition: G4Scheduler.cc:101
G4TrackStatus GetTrackStatus() const
G4int GetTrackID() const
const G4ThreeVector & GetPosition() const
G4double GetGlobalTime() const
virtual void Initialise(const G4MolecularConfiguration *, const G4Track &)
virtual G4double GetReactionRadius(const G4MolecularConfiguration *, const G4MolecularConfiguration *)=0
G4TrackVectorHandle fReactants
static G4ThreadLocal G4double fUserMinTimeStep
Definition: DoubConv.h:17
#define DBL_MAX
Definition: templates.hh:62