BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSLinkTrackerInterface.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include <vector>
19#include <string>
20#include <filesystem>
21
22#include "CLHEP/Units/SystemOfUnits.h"
23#include "CLHEP/Units/PhysicalConstants.h"
24
25#include "G4ParticleTable.hh"
26#include "G4IonTable.hh"
27#include "G4Electron.hh"
28
29#include "BDSLinkTrackerInterface.hh"
30#include "BDSLinkBunch.hh"
31#include "BDSIMLink.hh"
32#include "BDSParticleDefinition.hh"
33#include "BDSException.hh"
34
35
36BDSLinkTrackerInterface* BDSLinkTrackerInterface::singleton = nullptr;
37
38BDSLinkTrackerInterface* BDSLinkTrackerInterface::GetInstance(std::string bdsimConfigFileIn,
39 int referenceParticlePDGIn,
40 double referenceKineticEnergyIn,
41 double relativeEnergyCutIn,
42 int seedIn,
43 int referenceIonChargeIn,
44 bool batchModeIn)
45{
46 if (singleton)
47 {return singleton;}
48 else
49 {
50 singleton = new BDSLinkTrackerInterface(bdsimConfigFileIn,
51 referenceParticlePDGIn,
52 referenceKineticEnergyIn,
53 relativeEnergyCutIn,
54 seedIn,
55 referenceIonChargeIn,
56 batchModeIn);
57 return singleton;
58 }
59}
60
61BDSLinkTrackerInterface* BDSLinkTrackerInterface::GetInstance(BDSParser* parserIn,
62 int referenceParticlePDGIn,
63 double referenceKineticEnergyIn,
64 double relativeEnergyCutIn,
65 int seedIn,
66 int referenceIonChargeIn,
67 bool batchModeIn)
68{
69 if (singleton)
70 {return singleton;}
71 else
72 {
73 singleton = new BDSLinkTrackerInterface(parserIn,
74 referenceParticlePDGIn,
75 referenceKineticEnergyIn,
76 relativeEnergyCutIn,
77 seedIn,
78 referenceIonChargeIn,
79 batchModeIn);
80 return singleton;
81 }
82}
83
84BDSLinkTrackerInterface* BDSLinkTrackerInterface::GetInstance()
85{
86 if (singleton)
87 {return singleton;}
88 else
89 {
90 std::cout << "BDSLinkTrackerInterface not initialised" << std::endl;
91 return nullptr;
92 }
93}
94
95BDSLinkTrackerInterface::BDSLinkTrackerInterface(std::string bdsimConfigFileIn,
96 int referenceParticlePDGIn,
97 double referenceKineticEnergyIn,
98 double relativeEnergyCutIn,
99 int seedIn,
100 int referenceIonChargeIn,
101 bool batchModeIn) :
102 bdsimConfigFile(bdsimConfigFileIn),
103 referenceParticlePDG(referenceParticlePDGIn),
104 referenceKineticEnergy(referenceKineticEnergyIn),
105 relativeEnergyCut(relativeEnergyCutIn),
106 seed(seedIn),
107 referenceIonCharge(referenceIonChargeIn),
108 batchMode(batchModeIn)
109{
110 // keep local tables for ease
111 g4particle_table = G4ParticleTable::GetParticleTable();
112 g4ion_table = g4particle_table->GetIonTable();
113
114 // create link objects
115 linkBunch = new BDSLinkBunch();
116 linkBDSIM = new BDSIMLink(linkBunch);
117
118 std::vector<std::string> bdsim_args;
119 bdsim_args.push_back("bdsim");
120 bdsim_args.push_back("--file="+bdsimConfigFile);
121 bdsim_args.push_back("--seed="+std::to_string(seed));
122 bdsim_args.push_back("--output=None");
123
124 // append batch configuration
125 if (batchMode)
126 {bdsim_args.push_back(std::string("--batch"));}
127 else
128 {bdsim_args.push_back(std::string("--vis_mac=vis.mac"));}
129
130 // set minimum kinetic energy
131 if (relativeEnergyCut < 1e-6)
132 {relativeEnergyCut = 1.0;}
133 minimumKineticEnergy = relativeEnergyCut * referenceKineticEnergy;
134
135 // Create a vector of char* pointing to c_str()
136 std::vector<char*> c_args;
137 for (auto& arg : bdsim_args)
138 {c_args.push_back(const_cast<char*>(arg.c_str()));}
139
140 // initialise link object
141 linkBDSIM->Initialise((int)c_args.size(),
142 c_args.data(),
143 true,
144 minimumKineticEnergy/CLHEP::GeV,
145 false);
146
147 referenceParticleDefinition = PrepareBDSParticleDefinition(referenceParticlePDG,
148 /* totalEnergy */ 0,
149 referenceKineticEnergy,
150 /* momentum= */ 0 ,
151 static_cast<int>(referenceIonCharge));
152}
153
154
155BDSLinkTrackerInterface::BDSLinkTrackerInterface(BDSParser *parserIn,
156 int referenceParticlePDGIn,
157 double referenceKineticEnergyIn,
158 double relativeEnergyCutIn,
159 int seedIn,
160 int referenceIonChargeIn,
161 bool batchModeIn) :
162 bdsimConfigFile(""),
163 referenceParticlePDG(referenceParticlePDGIn),
164 referenceKineticEnergy(referenceKineticEnergyIn),
165 relativeEnergyCut(relativeEnergyCutIn),
166 seed(seedIn),
167 referenceIonCharge(referenceIonChargeIn),
168 batchMode(batchModeIn)
169{
170 // keep local tables for ease
171 g4particle_table = G4ParticleTable::GetParticleTable();
172 g4ion_table = g4particle_table->GetIonTable();
173
174 // create link objects
175 linkBunch = new BDSLinkBunch();
176 linkBDSIM = new BDSIMLink(linkBunch, parserIn);
177
178 std::vector<std::string> bdsim_args;
179 bdsim_args.push_back("bdsim");
180 bdsim_args.push_back("--seed="+std::to_string(seed));
181 bdsim_args.push_back("--output=None");
182
183 // append batch configuration
184 if (batchMode)
185 {bdsim_args.push_back(std::string("--batch"));}
186 else
187 {bdsim_args.push_back(std::string("--vis_mac=vis.mac"));}
188
189 // set minimum kinetic energy
190 if (relativeEnergyCut < 1e-6)
191 {relativeEnergyCut = 1.0;}
192 minimumKineticEnergy = relativeEnergyCut * referenceKineticEnergy;
193
194 // Create a vector of char* pointing to c_str()
195 std::vector<char*> c_args;
196 for (auto& arg : bdsim_args)
197 {c_args.push_back(const_cast<char*>(arg.c_str()));}
198
199 // initialise link object
200 linkBDSIM->Initialise((int)c_args.size(),
201 c_args.data(),
202 true,
203 minimumKineticEnergy/CLHEP::GeV,
204 false);
205
206 referenceParticleDefinition = PrepareBDSParticleDefinition(referenceParticlePDG,
207 /* totalEnergy */ 0,
208 referenceKineticEnergy,
209 /* momentum= */ 0 ,
210 static_cast<int>(referenceIonCharge));
211}
212
213BDSLinkTrackerInterface::~BDSLinkTrackerInterface()
214{
215 std::cout << "BDSLinkTrackerInterface::~BDSLinkTrackerInterface" << std::endl;
216 delete linkBunch;
217 delete linkBDSIM;
218}
219
220void BDSLinkTrackerInterface::Reset()
221{
222 if (singleton)
223 {delete singleton;}
224 singleton = nullptr;
225}
226
227BDSParticleDefinition* BDSLinkTrackerInterface::PrepareBDSParticleDefinition(int pdg,
228 double totalEnergy,
229 double kineticEnergy,
230 double momentum,
231 int ionCharge)
232{
233 G4ParticleDefinition *particleDefGeant = nullptr;
234 BDSParticleDefinition *particleDefinition = nullptr;
235 BDSIonDefinition* ionDef = nullptr;
236
237 if (pdg < 1000000000)
238 {// Not an ion
239 particleDefGeant = g4particle_table->FindParticle(pdg);
240 particleDefinition = new BDSParticleDefinition(particleDefGeant,
241 totalEnergy,
242 kineticEnergy,
243 momentum,
244 1, nullptr);
245 }
246 else
247 {// Ions
248 particleDefGeant = g4ion_table->GetIon(pdg);
249
250 if (ionCharge == 0)
251 {ionCharge = particleDefGeant->GetAtomicNumber();}
252
253 ionDef = new BDSIonDefinition(particleDefGeant->GetAtomicMass(),
254 particleDefGeant->GetAtomicNumber(),
255 ionCharge);
256
257 auto mass = g4ion_table->GetIonMass(ionDef->Z(), ionDef->A());
258 auto charge = ionDef->Charge();
259
260 auto bdsimPartName = "ion " + std::to_string(ionDef->A()) +
261 " " + std::to_string(ionDef->Z()) +
262 " " + std::to_string(charge);
263
264 particleDefinition = new BDSParticleDefinition(bdsimPartName, mass, charge,
265 totalEnergy,
266 kineticEnergy,
267 momentum,
268 1, ionDef, pdg);
269 }
270 return particleDefinition;
271}
272
273BDSParticleDefinition* BDSLinkTrackerInterface::PrepareBDSParticleDefinition_Bjorn(int pdgIDIn,
274 double /* momentumIn */,
275 double kineticEnergyIn,
276 int ionChargeIn)
277{
278 G4int pdgID = (G4int) pdgIDIn;
279
280 G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
281 G4ParticleDefinition* particleDefGeant;
282
283 // Wrap in our class that calculates momentum and kinetic energy.
284 // Requires that one of E, Ek, P be non-zero (only one).
285 BDSParticleDefinition* particleDefinition = nullptr;
286 BDSIonDefinition* ionDef = nullptr;
287
288 // PDG for ions = 10LZZZAAAI
289 if (pdgID > 1000000000) // is an ion
290 {
291 G4IonTable* ionTable = particleTable->GetIonTable();
292 particleDefGeant = ionTable->GetIon(pdgID);
293 if (!particleDefGeant)
294 {throw BDSException("BDSXtrackInterface> Ion \"" + std::to_string(pdgID) + "\" not found");}
295
296 G4int ionCharge = ionChargeIn==0 ? particleDefGeant->GetAtomicNumber() : (G4int) ionChargeIn;
297 ionDef = new BDSIonDefinition(particleDefGeant->GetAtomicMass(),
298 particleDefGeant->GetAtomicNumber(),
299 ionCharge);
300
301 // correct the particle mass in the case of partially-stripped ions
302 G4double mass = ionTable->GetIonMass(ionDef->Z(), ionDef->A());
303 G4double charge = ionDef->Charge(); // correct even if overridden
304 mass += ionDef->NElectrons()*G4Electron::Definition()->GetPDGMass();
305 // The constructor with a custom name requires the bdsim name of the ion
306 std::string bdsimPartName = "ion " + std::to_string(static_cast<int>(ionDef->A()))
307 + " " + std::to_string(static_cast<int>(ionDef->Z()))
308 + " " + std::to_string(static_cast<int>(charge));
309
310 particleDefinition = new BDSParticleDefinition(bdsimPartName, mass, charge, 0,
311 kineticEnergyIn, 0, 1, ionDef, pdgID);
312 }
313 else
314 {
315 particleDefGeant = particleTable->FindParticle(pdgID);
316 if (!particleDefGeant)
317 {throw BDSException("BDSLinkTrackerInterface> Particle \"" + std::to_string(pdgID) + "\" not found");}
318 particleDefinition = new BDSParticleDefinition(particleDefGeant, 0, kineticEnergyIn, 0, 1, nullptr);
319 }
320
321 return particleDefinition;
322}
323
324void BDSLinkTrackerInterface::AddParticle(double x, double y, double px, double py,
325 double ct, double deltap, double chi,
326 double chargeRatio, double /*s*/,
327 int trackid, int pdgid)
328{
329 auto q = chargeRatio * referenceParticleDefinition->Charge();
330 auto mass_ratio = chargeRatio / chi;
331 auto p = referenceParticleDefinition->Momentum() * (deltap + 1) * mass_ratio;
332
333 auto pdg = 0;
334 if (pdgid == 0)
335 {pdg = referenceParticleDefinition->PDGID();}
336 else
337 {pdg = pdgid;}
338
339 auto partDef = PrepareBDSParticleDefinition(pdg, 0, 0, p, (int)q);
340 auto t = - ct * CLHEP::m / (referenceParticleDefinition->Beta() * CLHEP::c_light);
341 auto oneplusdelta = (1 + deltap);
342 auto xp = px / oneplusdelta;
343 auto yp = py / oneplusdelta;
344 auto sqrtarg = 1 - std::pow(xp,2) - std::pow(yp,2);
345
346 auto zp = 0.0;
347
348 if (sqrtarg >=0)
349 {zp = std::sqrt(sqrtarg);}
350
351 auto coords = BDSParticleCoordsFull(x,
352 y,
353 0,
354 xp,
355 yp,
356 zp,
357 t,
358 0,
359 partDef->TotalEnergy(),
360 1);
361
362 linkBunch->AddParticle(partDef, coords, trackid, trackid);
363}
364
366 double px, double py, double pz,
367 double t, double /*s*/,
368 int trackid, int pdgid)
369{
370 auto pdg = 0;
371 auto q = 0.0;
372
373 if (pdgid == 0)
374 {
375 pdg = referenceParticleDefinition->PDGID();
376 q = referenceParticleDefinition->Charge();
377 }
378 else
379 {
380 pdg = pdgid;
381 q = G4ParticleTable::GetParticleTable()->FindParticle(pdg)->GetPDGCharge();
382 }
383
384 auto p = std::sqrt(std::pow(px,2) +
385 std::pow(py,2) +
386 std::pow(pz,2));
387 auto partDef = PrepareBDSParticleDefinition(pdg, 0, 0, p, q);
388 auto xp = px / p;
389 auto yp = py / p;
390 auto zp = pz / p;
391
392 auto coords = BDSParticleCoordsFull(x,
393 y,
394 0,
395 xp,
396 yp,
397 zp,
398 t,
399 0,
400 partDef->TotalEnergy(),
401 1);
402
403 linkBunch->AddParticle(partDef, coords, trackid, trackid);
404}
405
406void BDSLinkTrackerInterface::AddParticles(std::vector<double>& x, std::vector<double>& y,
407 std::vector<double>& xp, std::vector<double>& yp,
408 std::vector<double>& ct, std::vector<double>& deltap,
409 std::vector<double>& chi, std::vector<double>& chargeRatio,
410 std::vector<double>& s, std::vector<int>& trackid,
411 std::vector<int>& pdgid)
412{
413 for (size_t i=0; i<x.size(); i++)
414 {
415 AddParticle(x[i], y[i], xp[i], yp[i], ct[i], deltap[i],
416 chi[i], chargeRatio[i], s[i], trackid[i], pdgid[i]);
417 }
418}
419
420void BDSLinkTrackerInterface::AddParticles(std::vector<double>& x, std::vector<double>& y,
421 std::vector<double>& px, std::vector<double>&py,
422 std::vector<double>& pz, std::vector<double> &t,
423 std::vector<double>& s, std::vector<int> &trackid,
424 std::vector<int> &pdgid)
425{
426 for(size_t i=0; i<x.size(); i++)
427 {
428 AddParticle(x[i], y[i],
429 px[i], py[i], pz[i],
430 t[i], s[i],
431 trackid[i], pdgid[i]);
432 }
433}
434
435void BDSLinkTrackerInterface::ClearData()
436{// TODO separate ClearSamplerHits to another function and add to top of track function
437 auto* link = GetBDSIMLink(); // Retrieve pointer to BDSIMLink
438 link->ClearSamplerHits();
439 auto* bunch = GetBunchLink(); // Retrieve pointer to BDSBunch
440 bunch->ClearParticles();
441 auto& active_state = GetParticleActiveState(); // Retrieve reference
442 std::vector<bool>().swap(active_state); // Efficient clear
443}
444
445G4ParticleDefinition* BDSLinkTrackerInterface::GetParticleDefinition(int pdgid)
446{
447 G4ParticleDefinition* particleDefGeant = nullptr;
448 if (pdgid < 1000000000) // Not an ion
449 {particleDefGeant = g4particle_table->FindParticle(pdgid);}
450 else
451 {particleDefGeant = g4ion_table->GetIon(pdgid);}
452 return particleDefGeant;
453}
454
455double BDSLinkTrackerInterface::GetParticlePDGMass(int pdgid)
456{
457 return GetParticleDefinition(pdgid)->GetPDGMass();
458}
459
460double BDSLinkTrackerInterface::GetParticlePDGCharge(int pdgid)
461{
462 return GetParticleDefinition(pdgid)->GetPDGCharge();
463}
464
466{
467 return GetParticlePDGCharge(pdgid)/referenceParticleDefinition->Charge();
468}
469
471{
472 return GetParticlePDGMass(pdgid)/referenceParticleDefinition->Mass();
473}
474
476{
477 return GetChargeRatio(pdgid)/ GetMassRatio(pdgid);
478}
General exception with possible name of object and message.
Class to parse an ion particle definition.
G4int NElectrons() const
Accessor.
G4int A() const
Accessor.
G4int Z() const
Accessor.
G4double Charge() const
Accessor.
A bunch distribution that holds a bunch from a Link.
void AddParticle(BDSParticleDefinition *particleDefinitionIn, const BDSParticleCoordsFull &coordsIn, int externalParticleID, int externalParentID)
Append particle to the bunch for tracking.
double GetChi(int pdgid)
Ratio of charge ratio to mass ratio between pdgid particle and reference particle.
double GetMassRatio(int pdgid)
Ratio of mass between pdgid particle and reference particle.
double GetChargeRatio(int pdgid)
Ratio of charge between pdgid particle and reference particle.
void AddParticle(double x, double y, double px, double py, double ct, double deltap, double chi, double chargeRatio, double s, int trackid, int pdgid)
Const entry to parser objects.
Definition BDSParser.hh:36
A set of particle coordinates including energy and weight.
Wrapper for particle definition.
G4double Mass() const
Accessor.
G4double Momentum() const
Accessor.
G4double Charge() const
Accessor.
G4double Beta() const
Accessor.