Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4DNAEventScheduler.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#include <memory>
30#include "G4SystemOfUnits.hh"
31#include "G4UnitsTable.hh"
34#include "G4Timer.hh"
35#include "G4Scheduler.hh"
36#include "G4UserMeshAction.hh"
37#include "G4MoleculeCounter.hh"
39#include "G4Molecule.hh"
40
42 : fpGillespieReaction(new G4DNAGillespieDirectMethod())
43 , fpEventSet(new G4DNAEventSet())
44 , fpUpdateSystem(new G4DNAUpdateSystemModel())
45{}
46
47[[maybe_unused]] void G4DNAEventScheduler::AddTimeToRecord(const G4double& time)
48{
49 if(fTimeToRecord.find(time) == fTimeToRecord.end())
50 {
51 fTimeToRecord.insert(time);
52 }
53 fLastRecoredTime = fTimeToRecord.begin();
54}
55
57
59{
60 std::map<G4VDNAMesh::Index, MapList> TrackKeyMap;
61 if(fpMesh == nullptr){
62 fpMesh = std::make_unique<G4DNAMesh>(boundingBox, fPixel);
63 }else
64 {
65 auto newMesh = new G4DNAMesh(fpMesh->GetBoundingBox(), fPixel);
66
67 auto begin = fpMesh->begin();//old mesh, should be homogeneous
68 auto end = fpMesh->end();
69 for(; begin != end; begin++)
70 {
71 auto numberOfBoxes = fPixel*fPixel*fPixel;
72 const auto& mapData = std::get<2>(*begin);
73 for(auto it : mapData)
74 {
75 if(it.second == 0) continue;
76
77 G4int base_mol = std::floor((G4double)it.second / numberOfBoxes);
78 G4int remainder = (G4int)it.second % numberOfBoxes;
79 for(G4int i = 0; i < remainder; i++)
80 {
81 auto oldIndex = std::get<0>(*begin);
82 auto idx = newMesh->GetRandomIndex(oldIndex, fpMesh->GetResolution());
83 TrackKeyMap[idx][it.first] += base_mol + 1;
84 }
85 }
86 }
87 fpMesh.reset(newMesh);
88 }
89
90 if(!CheckingReactionRadius(fpMesh->GetResolution()))
91 {
92 G4String WarMessage = "resolution is not good : " +
93 std::to_string(fpMesh->GetResolution() / nm);
94 G4Exception("G4DNAEventScheduler::InitializeInMesh()", "WrongResolution",
95 JustWarning, WarMessage);
96 }
97
98 auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
99 for(auto track : *pMainList)
100 {
101 auto molType = GetMolecule(track)->GetMolecularConfiguration();
102
103 auto pScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
105 if(pScavengerMaterial != nullptr &&
106 pScavengerMaterial->find(molType)) // avoid voxelize the scavenger
107 {
108 continue;
109 }
110
111 auto key = fpMesh->GetIndex(track->GetPosition());
112 if(TrackKeyMap.find(key) != TrackKeyMap.end())
113 {
114 std::map<MolType, size_t>& TrackTypeMap = TrackKeyMap[key];
115 if(TrackTypeMap.find(molType) != TrackTypeMap.end())
116 {
117 TrackTypeMap[molType]++;
118 }
119 else
120 {
121 TrackTypeMap[molType] = 1;
122 }
123 }
124 else
125 {
126 TrackKeyMap[key][molType] = 1;
127 }
128 track->SetTrackStatus(fStopAndKill);//kill the track
129 }
131
132 for(auto& it : TrackKeyMap)
133 {
134 fpMesh->InitializeVoxel(it.first, std::move(it.second));
135 }
136}
137
139{
140 fPixel = pixel;
141 auto newMesh = new G4DNAMesh(fpMesh->GetBoundingBox(), fPixel);
142
143 auto begin = fpMesh->begin();
144 auto end = fpMesh->end();
145 std::map<G4VDNAMesh::Index, MapList> TrackKeyMap;
146 for(; begin != end; begin++)
147 {
148 auto index = std::get<0>(*begin);
149 auto newIndex = fpMesh->ConvertIndex(index, fPixel);
150 if(TrackKeyMap.find(newIndex) == TrackKeyMap.end())
151 {
152 TrackKeyMap[newIndex] = std::get<2>(*begin);
153 }
154 else
155 {
156 for(const auto& it : std::get<2>(*begin))
157 {
158 TrackKeyMap[newIndex][it.first] += it.second;
159 }
160 if(fVerbose > 1)
161 {
162 G4cout << " ReVoxelizing:: Old index : " << index
163 << " new index : " << fpMesh->ConvertIndex(index, fPixel)
164 << " number: " << std::get<2>(*begin).begin()->second << G4endl;
165 }
166 }
167 }
168 fpMesh.reset(newMesh);
169
170 for(auto& it : TrackKeyMap)
171 {
172 fpMesh->InitializeVoxel(it.first, std::move(it.second));
173 }
174}
176{
177 // find another solultion
178 fGlobalTime = fEndTime;
179
180 //
181 LastRegisterForCounter();//Last register for counter
182
183 if(fVerbose > 0)
184 {
185 G4cout << "End Processing and reset Gird, ScavengerTable, EventSet for new "
186 "simulation!!!!"
187 << G4endl;
188 }
189 fInitialized = false;
190 fTimeStep = 0;
191 fStepNumber = 0;
192 fGlobalTime = fStartTime;
193 fRunning = true;
194 fReactionNumber = 0;
195 fJumpingNumber = 0;
196 fpEventSet->RemoveEventSet();
197 if(fpMesh != nullptr) {
198 fpMesh->Reset();
199 fpMesh.reset();
200 //reset for each event
201 }
202 fpGillespieReaction->ResetEquilibrium();
203}
204
206 G4int pixel)
207{
208 if(!fInitialized)
209 {
210 fPixel = pixel;
211 // Scavenger();
212
213 auto pScavengerMaterial = dynamic_cast<G4DNAScavengerMaterial*>(
215 if(pScavengerMaterial == nullptr)
216 {
217 G4cout << "There is no scavenger" << G4endl;
218 }
219 else
220 {
221 if(fVerbose > 1)
222 {
223 pScavengerMaterial->PrintInfo();
224 }
225 }
226
227 Voxelizing(boundingBox);
228 fEndTime = std::min(G4ITTrackHolder::Instance()->GetNextTime(), G4Scheduler::Instance()->GetEndTime()-1*ps);
229
230 //G4cout<<"fEndTime" <<fEndTime<<" G4ITTrackHolder::Instance()->GetNextTime() : "<<G4ITTrackHolder::Instance()->GetNextTime()<<G4endl;
231
232 fpGillespieReaction->SetVoxelMesh(*fpMesh);
233 fpGillespieReaction->SetEventSet(fpEventSet.get());
234 fpGillespieReaction->SetTimeStep(0);// reset fTimeStep = 0 in fpGillespieReaction
235 fpGillespieReaction->Initialize();
236 fpGillespieReaction->CreateEvents();
237 fpUpdateSystem->SetMesh(fpMesh.get());
238 fInitialized = true;
239 }
240
241 if(fVerbose > 0)
242 {
243 fpUpdateSystem->SetVerbose(1);
244 }
245
246 if(fVerbose > 2)
247 {
248 fpMesh->PrintMesh();
249 }
250}
252{
253 if(fPixel <= 1)
254 {
255 fRunning = false;
256 return;
257 }
258 // TEST /3
259 ReVoxelizing(fPixel / 2); //
260 // ReVoxelizing(fPixel/3);//
261
262 fpGillespieReaction->SetVoxelMesh(*fpMesh);
263 fpUpdateSystem->SetMesh(fpMesh.get());
264 fpGillespieReaction->CreateEvents();
265}
266
268{
269 if(fVerbose > 0)
270 {
271 G4cout
272 << "*** End Processing In Mesh and reset Mesh, EventSet for new Mesh!!!!"
273 << G4endl;
274 }
275 fpEventSet->RemoveEventSet();
276 fInitialized = false;
277 fIsChangeMesh = false;
278 fReactionNumber = 0;
279 fJumpingNumber = 0;
280 fStepNumberInMesh = 0;
281}
282
283G4double G4DNAEventScheduler::GetStartTime() const { return fStartTime; }
284
285G4double G4DNAEventScheduler::GetGlobalTime() const { return fGlobalTime; }
286
287G4double G4DNAEventScheduler::GetEndTime() const { return fEndTime; }
288
290{
291 return fTimeStep;
292}
293
294G4int G4DNAEventScheduler::GetVerbose() const { return fVerbose; }
295
297{
298 fMaxStep = max;
299}
300
302{
303 fStartTime = time;
304 fGlobalTime = fStartTime;
305}
306
307void G4DNAEventScheduler::Stop() { fRunning = false; }
309{
310 G4Timer localtimer;
311 if(fVerbose > 2)
312 {
313 localtimer.Start();
314 G4cout << "***G4DNAEventScheduler::Run*** for Pixel : " << fPixel << G4endl;
315 }
316 while(fEndTime > fGlobalTime && fRunning)
317 {
318 RunInMesh();
319 }
320 fInitialized = false;
321 if(fVerbose > 2)
322 {
323 if(!fRunning)
324 {
325 G4cout << " StepNumber(" << fStepNumber << ") = MaxStep(" << fMaxStep
326 << ")" << G4endl;
327 }
328 else if(fEndTime <= fGlobalTime)
329 {
330 G4cout << " GlobalTime(" << fGlobalTime << ") > EndTime(" << fEndTime
331 << ")"
332 << " StepNumber : " << fStepNumber << G4endl;
333 }
334 localtimer.Stop();
335 G4cout << "***G4DNAEventScheduler::Ending::"
336 << G4BestUnit(fGlobalTime, "Time")
337 << " Events left : " << fpEventSet->size() << G4endl;
338 if(fVerbose > 1)
339 {
340 fpMesh->PrintMesh();
341 }
342 G4cout << " Computing Time : " << localtimer << G4endl;
343 }
344}
345
347{
348 if(!fInitialized)
349 {
351 }
352 if(fVerbose > 0)
353 {
354 G4double resolution = fpMesh->GetResolution();
355 G4cout << "At Time : " << std::setw(7) << G4BestUnit(fGlobalTime, "Time")
356 << " the Mesh has " << fPixel << " x " << fPixel << " x " << fPixel
357 << " voxels with Resolution " << G4BestUnit(resolution, "Length")
358 << " during next "
359 << G4BestUnit(fGlobalTime + resolution * resolution * C / (6 * D), "Time")
360 << G4endl;
361 }
362
363 if(fVerbose > 2)
364 {
365 fpMesh->PrintMesh();
366 }
367
368 if(fpUserMeshAction != nullptr)
369 {
370 fpUserMeshAction->BeginOfMesh(fpMesh.get(), fGlobalTime);
371 }
372
373 // if diffusive jumping is avaiable, EventSet is never empty
374
375 while(!fpEventSet->Empty() && !fIsChangeMesh && fEndTime > fGlobalTime)
376 {
377 Stepping();
378 fGlobalTime = fTimeStep + fStartTime;
379
380 if(fpUserMeshAction != nullptr)
381 {
382 fpUserMeshAction->InMesh(fpMesh.get(), fGlobalTime);
383 }
384
385 if(fVerbose > 2)
386 {
387 G4cout << "fGlobalTime : " << G4BestUnit(fGlobalTime, "Time")
388 << " fTimeStep : " << G4BestUnit(fTimeStep, "Time") << G4endl;
389 }
390 G4double resolution = fpMesh->GetResolution();
391 fTransferTime = resolution * resolution * C / (6 * D);
392 if(fTransferTime == 0)
393 {
394 G4ExceptionDescription exceptionDescription;
395 exceptionDescription << "fTransferTime == 0";
396 G4Exception("G4DNAEventScheduler::RunInMesh", "G4DNAEventScheduler001",
397 FatalErrorInArgument, exceptionDescription);
398 }
399 if(fTransferTime < fTimeStep &&
400 fPixel != 1) // dont change Mesh if fPixel == 1
401 {
402 if(fSetChangeMesh)
403 {
404 if(fVerbose > 1)
405 {
406 G4cout << " Pixels : " << fPixel << " resolution : "
407 << G4BestUnit(fpMesh->GetResolution(), "Length")
408 << " fStepNumberInMesh : " << fStepNumberInMesh
409 << " at fGlobalTime : " << G4BestUnit(fGlobalTime, "Time")
410 << " at fTimeStep : " << G4BestUnit(fTimeStep, "Time")
411 << " fReactionNumber : " << fReactionNumber
412 << " transferTime : " << G4BestUnit(fTransferTime, "Time")
413 << G4endl;
414 }
415 fIsChangeMesh = true;
416 }
417 }
418 }
419
420 if(fVerbose > 1)
421 {
422 G4cout << "***G4DNAEventScheduler::Ending::"
423 << G4BestUnit(fGlobalTime, "Time")
424 << " Event left : " << fpEventSet->size() << G4endl;
425 G4cout << " Due to : ";
426 if(fpEventSet->Empty())
427 {
428 G4cout << "EventSet is Empty" << G4endl;
429 }
430 else if(fIsChangeMesh)
431 {
432 G4cout << "Changing Mesh from : " << fPixel
433 << " pixels to : " << fPixel / 2 << " pixels" << G4endl;
434 G4cout << "Info : ReactionNumber : " << fReactionNumber
435 << " JumpingNumber : " << fJumpingNumber << G4endl;
436 }
437 else if(fEndTime > fGlobalTime)
438 {
439 G4cout << " GlobalTime(" << fGlobalTime << ") > EndTime(" << fEndTime
440 << ")"
441 << " StepNumber : " << fStepNumber << G4endl;
442 }
443 if(fVerbose > 2)
444 {
445 fpMesh->PrintMesh();
446 }
447 G4cout << G4endl;
448 }
449
450 if(fpUserMeshAction != nullptr)
451 {
452 fpUserMeshAction->EndOfMesh(fpMesh.get(), fGlobalTime);
453 }
454 ResetInMesh();
455}
456
457void G4DNAEventScheduler::Stepping() // this event loop
458{
459 fStepNumber < fMaxStep ? fStepNumber++ : static_cast<int>(fRunning = false);
460 if(fpEventSet->size() > fpMesh->size())
461 {
462 G4ExceptionDescription exceptionDescription;
463 exceptionDescription
464 << "impossible that fpEventSet->size() > fpMesh->size()";
465 G4Exception("G4DNAEventScheduler::Stepping", "G4DNAEventScheduler002",
466 FatalErrorInArgument, exceptionDescription);
467 }
468
469 auto selected = fpEventSet->begin();
470 auto index = (*selected)->GetIndex();
471
472 if(fVerbose > 1)
473 {
474 G4cout << "G4DNAEventScheduler::Stepping()*********************************"
475 "*******"
476 << G4endl;
477 (*selected)->PrintEvent();
478 }
479
480 // get selected time step
481 fTimeStep = (*selected)->GetTime();
482
483 if(fTimeStep + fStartTime >fEndTime){ return;}
484
485 // selected data
486 auto pJumping = (*selected)->GetJumpingData();
487 auto pReaction = (*selected)->GetReactionData();
488
489 fpUpdateSystem->SetGlobalTime(fTimeStep +
490 fStartTime); // this is just for printing
491 fpGillespieReaction->SetTimeStep(fTimeStep);
492 if(pJumping == nullptr && pReaction != nullptr)
493 {
494 fpUpdateSystem->UpdateSystem(index, *pReaction);
495 fpEventSet->RemoveEvent(selected);
496
497 //hoang's exp
498 if(fpGillespieReaction->SetEquilibrium(pReaction))
499 {
500 ResetEventSet();
501 }
502 //end Hoang's exp
503
504 // create new event
505 fpGillespieReaction->CreateEvent(index);
506 fReactionNumber++;
507 // recordTime in reaction
508 RecordTime();
509 }
510 else if(pJumping != nullptr && pReaction == nullptr)
511 {
512 // dont change this
513 fpUpdateSystem->UpdateSystem(index, *pJumping);
514 // save jumping Index before delete selected event
515 auto jumpingIndex = pJumping->second;
516 fpEventSet->RemoveEvent(selected);
517 // create new event
518 // should create Jumping before key
519 fpGillespieReaction->CreateEvent(jumpingIndex);
520 fpGillespieReaction->CreateEvent(index);
521 fJumpingNumber++;
522 }
523 else
524 {
525 G4ExceptionDescription exceptionDescription;
526 exceptionDescription << "pJumping == nullptr && pReaction == nullptr";
527 G4Exception("G4DNAEventScheduler::Stepping", "G4DNAEventScheduler003",
528 FatalErrorInArgument, exceptionDescription);
529 }
530
531 if(fVerbose > 1)
532 {
533 G4cout << "G4DNAEventScheduler::Stepping::end "
534 "Print***********************************"
535 << G4endl;
536 G4cout << G4endl;
537 }
538 fStepNumberInMesh++;
539}
540
542{
543 fEndTime = endTime;
544}
545
547{
548 if(fLastRecoredTime == fTimeToRecord.end())
549 {
550 return;
551 }
552 auto recordTime = *fLastRecoredTime;
553 if(fGlobalTime >= recordTime && fCounterMap[recordTime].empty())
554 {
555 if(fpMesh == nullptr) return;
556 //G4cout<<"recordTime for meso: "<<recordTime<<" fGlobalTime : "<<fGlobalTime<<G4endl;
557 auto begin = fpMesh->begin();
558 auto end = fpMesh->end();
559 for(; begin != end; begin++)
560 {
561 const auto& mapData = std::get<2>(*begin);
562 if(mapData.empty())
563 {
564 continue;
565 }
566 for(const auto& it : mapData)
567 {
568 fCounterMap[recordTime][it.first] += it.second;
569 }
570 }
571 fLastRecoredTime++;
572 }
573}
574
576{
577 G4cout << "CounterMap.size : " << fCounterMap.size() << G4endl;
578 for(const auto& i : fCounterMap)
579 {
580 auto map = i.second;
581 auto begin = map.begin(); //
582 auto end = map.end(); //
583 for(; begin != end; begin++)
584 {
585 auto molecule = begin->first;
586 auto number = begin->second;
587 if(number == 0)
588 {
589 continue;
590 }
591 G4cout << "molecule : " << molecule->GetName() << " number : " << number
592 << G4endl;
593 }
594 }
595}
596
599{
600 return fCounterMap;
601}
602
604 std::unique_ptr<G4UserMeshAction> pUserMeshAction)
605{
606 fpUserMeshAction = std::move(pUserMeshAction);
607}
608
609G4DNAMesh* G4DNAEventScheduler::GetMesh() const { return fpMesh.get(); }
610
611G4int G4DNAEventScheduler::GetPixels() const { return fPixel; }
612
614{
615 auto pMolecularReactionTable = G4DNAMolecularReactionTable::Instance();
616 auto reactionDataList = pMolecularReactionTable->GetVectorOfReactionData();
617 if(reactionDataList.empty())
618 {
619 G4cout << "reactionDataList.empty()" << G4endl;
620 return true;
621 }
622
623 for(auto it : reactionDataList)
624 {
625 if(it->GetEffectiveReactionRadius() >= resolution / CLHEP::pi)
626 {
627 G4cout << it->GetReactant1()->GetName() << " + "
628 << it->GetReactant2()->GetName() << G4endl;
629 G4cout << "G4DNAEventScheduler::ReactionRadius : "
630 << G4BestUnit(it->GetEffectiveReactionRadius(), "Length")
631 << G4endl;
632 G4cout << "resolution : " << G4BestUnit(resolution, "Length") << G4endl;
633 return false;
634 }
635 }
636 return true;
637}
638
639void G4DNAEventScheduler::ResetEventSet()
640{
641 fpEventSet->RemoveEventSet();
642 fpGillespieReaction->CreateEvents();
643}
644
645void G4DNAEventScheduler::LastRegisterForCounter()
646{
647 if(fLastRecoredTime == fTimeToRecord.end())
648 {
649 //fully recorded -> happy ending
650 return;
651 }else
652 {
653 auto lastRecorded = --fLastRecoredTime;//fixed
654 while (fLastRecoredTime != fTimeToRecord.end())
655 {
656 fCounterMap[*fLastRecoredTime] = fCounterMap[*lastRecorded];
657 fLastRecoredTime++;
658 }
659 }
660
661}
662
664 if(fLastRecoredTime == fTimeToRecord.end())
665 {
666 return;
667 }
668 auto recordTime = *fLastRecoredTime;
669 if (recordTime < G4Scheduler::Instance()->GetGlobalTime()) {
670
671 //check meso if exist
672
673 if(fpMesh != nullptr){
674 //G4cout<<"there is a mesh"<<G4endl;
675 auto begin = fpMesh->begin();
676 auto end = fpMesh->end();
677 for(; begin != end; begin++)
678 {
679 const auto& mapData = std::get<2>(*begin);
680 if(mapData.empty())
681 {
682 continue;
683 }
684 for(const auto& it : mapData)
685 {
686 fCounterMap[recordTime][it.first] += it.second;
687 }
688 }
689 }
690
691 //then particle based
692 auto pMainList = G4ITTrackHolder::Instance()->GetMainList();
693 for (auto track: *pMainList) {
694 auto molType = GetMolecule(track)->GetMolecularConfiguration();
695
696 auto pScavengerMaterial =
698 if (pScavengerMaterial != nullptr
699 && pScavengerMaterial->find(molType)) // avoid voxelize the scavenger
700 {
701 continue;
702 }
703 fCounterMap[recordTime][molType]++;
704 }
705 fLastRecoredTime++;
706 //PrintRecordTime();
707 }
708}
709
711{
712 fCounterMap.clear();
713 if(fTimeToRecord.empty())
714 {
715 G4String WarMessage = "fTimeToRecord is empty ";
716 G4Exception("G4DNAEventScheduler::ClearAndReChargeCounter()",
717 "TimeToRecord is empty", JustWarning, WarMessage);
718 }
719 fLastRecoredTime = fTimeToRecord.begin();
720}
@ JustWarning
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
G4Molecule * GetMolecule(const G4Track &track)
Definition G4Molecule.cc:75
#define G4BestUnit(a, b)
@ fStopAndKill
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 Initialize(const G4DNABoundingBox &boundingBox, G4int pixel)
static G4bool CheckingReactionRadius(G4double resolution)
void SetUserMeshAction(std::unique_ptr< G4UserMeshAction >)
std::map< G4double, MapCounter > GetCounterMap() const
void SetEndTime(const G4double &)
G4double GetTimeStep() const
G4double GetEndTime() const
~G4DNAEventScheduler() override
void Voxelizing(const G4DNABoundingBox &boundingBox)
G4double GetGlobalTime() const
G4DNAMesh * GetMesh() const
G4double GetStartTime() const
void SetStartTime(G4double time)
std::map< MolType, G4int > MapCounter
void AddTimeToRecord(const G4double &time)
static G4DNAMolecularReactionTable * Instance()
static G4ITReactionSet * Instance()
G4TrackList * GetMainList(Key)
static G4ITTrackHolder * Instance()
const G4MolecularConfiguration * GetMolecularConfiguration() const
static G4Scheduler * Instance()
G4VScavengerMaterial * GetScavengerMaterial() const
void Stop()
void Start()
std::string to_string(G4FermiAtomicMass mass)