OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
Beam.cpp
Go to the documentation of this file.
1//
2// Class Beam
3// The class for the OPAL BEAM command.
4// A BEAM definition is used by most physics commands to define the
5// particle charge and the reference momentum, together with some other data.
6//
7// Copyright (c) 200x - 2021, Paul Scherrer Institut, Villigen PSI, Switzerland
8// All rights reserved
9//
10// This file is part of OPAL.
11//
12// OPAL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU General Public License as published by
14// the Free Software Foundation, either version 3 of the License, or
15// (at your option) any later version.
16//
17// You should have received a copy of the GNU General Public License
18// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
19//
20#include "Structure/Beam.h"
21
28#include "Physics/Physics.h"
29#include "Physics/Units.h"
31#include "Utilities/Options.h"
32
33#include <cmath>
34#include <iterator>
35
36using namespace Expressions;
37
38// The attributes of class Beam.
39namespace {
40 constexpr const char* photonParticleName = "PHOTON";
41
42 enum {
43 PARTICLE, // The particle name
44 MASS, // The particle rest mass in GeV
45 CHARGE, // The particle charge in proton charges
46 ENERGY, // The particle energy in GeV
47 PC, // The particle momentum in GeV/c
48 GAMMA, // ENERGY / MASS
49 BCURRENT, // Legacy, unused in OPALX (holdover from OPALCycl)
50 BFREQ, // Legacy, unused in OPALX (holdover from OPALCycl)
51 BCHARGE, // Bunch charge in C
52 NALLOC, // Allocation size (macroparticles) for this beam
53 SOURCES, // Name of EMISSIONSOURCELIST
54 GLOBALPROCESSES, // Global physics processes active for this beam
55 DAUGHTERBEAM, // Name of the beam that receives decay daughter particles
56 POLARIZATION, // Initial polarization vector P (rest-frame, lab-frame axes)
57 SIZE
58 };
59} // namespace
60
62 : Definition(
63 SIZE, "BEAM",
64 "The \"BEAM\" statement defines data for the particles "
65 "in a beam."),
66 reference(1.0, Physics::m_p * Units::GeV2eV, 1.0 * Units::GeV2eV) {
68 "PARTICLE", "Name of particle to be used",
69 {"PHOTON", "ELECTRON", "POSITRON", "MUON", "PION", "PROTON", "ANTIPROTON", "DEUTERON",
70 "HMINUS", "H2P", "ALPHA", "CARBON", "XENON", "URANIUM"});
71
72 itsAttr[MASS] = Attributes::makeReal("MASS", "Particle rest mass [GeV]");
73
74 itsAttr[CHARGE] = Attributes::makeReal("CHARGE", "Particle charge in proton charges");
75
76 itsAttr[ENERGY] = Attributes::makeReal("ENERGY", "Particle energy [GeV]");
77
78 itsAttr[PC] = Attributes::makeReal("PC", "Particle momentum [GeV/c]");
79
80 itsAttr[GAMMA] = Attributes::makeReal("GAMMA", "ENERGY / MASS");
81
82 itsAttr[BCURRENT] =
83 Attributes::makeReal("BCURRENT", "Legacy, unused in OPALX. Use BCHARGE instead.");
84
85 itsAttr[BFREQ] = Attributes::makeReal("BFREQ", "Legacy, unused in OPALX. Use BCHARGE instead.");
86
87 itsAttr[BCHARGE] = Attributes::makeReal("BCHARGE", "Bunch charge [C]");
88
89 itsAttr[NALLOC] =
90 Attributes::makeReal("NALLOC", "Allocation size (macroparticles) for this beam");
91
93 "SOURCES", "Name of the emission sources list (EMISSIONSOURCELIST).");
94
96 "GLOBALPROCESSES", "Global physics processes active for this beam.");
97
98 itsAttr[DAUGHTERBEAM] = Attributes::makeString(
99 "DAUGHTERBEAM", "Name of the BEAM that receives decay daughter particles.");
100
101 itsAttr[POLARIZATION] = Attributes::makeRealArray(
102 "POLARIZATION",
103 "Initial polarization vector P = {Px, Py, Pz} for this beam "
104 "(rest-frame Pauli expectation values along lab-frame axes). "
105 "Must be length-3 with |P| in [0, 1]. Only valid for PARTICLE=MUON; "
106 "setting POLARIZATION on any other species is rejected. Setting "
107 "POLARIZATION (even {0,0,0}) enables per-particle spin tracking for this "
108 "beam (Thomas-BMT integration); leaving it unset disables spin tracking. "
109 "For muons produced by an upstream decay (e.g. PionDecay) the per-particle "
110 "value is overwritten by the decay, but POLARIZATION must still be set to "
111 "enable the spin storage that receives it.");
112
113 // Set up default beam.
114 Beam* defBeam = clone("UNNAMED_BEAM");
115 defBeam->builtin = true;
116
117 try {
118 defBeam->update();
119 OpalData::getInstance()->define(defBeam);
120 } catch (...) {
121 delete defBeam;
122 }
123
125}
126
127Beam::Beam(const std::string& name, Beam* parent)
128 : Definition(name, parent), reference(parent->reference) {}
129
131
133 // Can replace only by another BEAM.
134 return dynamic_cast<Beam*>(object) != 0;
135}
136
137Beam* Beam::clone(const std::string& name) { return new Beam(name, this); }
138
140 const bool photon = itsAttr[PARTICLE] && getParticleName() == photonParticleName;
141
142 if (photon) {
143 if (!itsAttr[ENERGY]) {
144 throw OpalException("Beam::execute()", "\"ENERGY\" must be set for PARTICLE=PHOTON.");
145 }
146 if (itsAttr[MASS]) {
147 throw OpalException(
148 "Beam::execute()",
149 "\"MASS\" is not allowed for PARTICLE=PHOTON. Use \"ENERGY\".");
150 }
151 if (itsAttr[CHARGE]) {
152 throw OpalException(
153 "Beam::execute()", "\"CHARGE\" is not allowed for PARTICLE=PHOTON.");
154 }
155 if (itsAttr[PC]) {
156 throw OpalException(
157 "Beam::execute()",
158 "\"PC\" is not allowed for PARTICLE=PHOTON. Use \"ENERGY\".");
159 }
160 if (itsAttr[GAMMA]) {
161 throw OpalException(
162 "Beam::execute()",
163 "\"GAMMA\" is not allowed for PARTICLE=PHOTON. Use \"ENERGY\".");
164 }
165 if (itsAttr[SOURCES]) {
166 throw OpalException(
167 "Beam::execute()", "\"SOURCES\" is not allowed for PARTICLE=PHOTON.");
168 }
169 }
170
171 if (itsAttr[BCURRENT] || itsAttr[BFREQ]) {
172 throw OpalException(
173 "Beam::execute()",
174 "\"BCURRENT\" and \"BFREQ\" are no longer used in OPALX. "
175 "Use \"BCHARGE\" [C] to specify the bunch charge directly.");
176 }
177
178 update();
179
180 if (!(itsAttr[PARTICLE]) && (!itsAttr[MASS] || !(itsAttr[CHARGE]))) {
181 throw OpalException(
182 "Beam::execute()",
183 "The beam particle hasn't been set. "
184 "Set either \"PARTICLE\" or \"MASS\" and \"CHARGE\".");
185 }
186
187 if (!(itsAttr[NALLOC])) {
188 throw OpalException("Beam::execute()", "\"NALLOC\" must be set.");
189 }
190
191 if (photon) {
192 const double energy = Attributes::getReal(itsAttr[ENERGY]);
193 if (energy <= 0.0) {
194 throw OpalException(
195 "Beam::execute()", "\"ENERGY\" should be greater than 0 for PARTICLE=PHOTON.");
196 }
197 return;
198 }
199
200 // Beam-only validation: each non-photon beam must specify its EMISSIONSOURCELIST.
202
203 // Currently supported global process names (extend as new processes are implemented).
204 for (const std::string& name : getGlobalProcessNames()) {
205 if (name != "DECAY") {
206 throw OpalException(
207 "Beam::execute()", "Unsupported entry in \"GLOBALPROCESSES\": \"" + name
208 + "\". Supported values: DECAY.");
209 }
210 }
211
213}
214
216 if (!itsAttr[POLARIZATION]) {
217 return;
218 }
219 const std::vector<double> pol = Attributes::getRealArray(itsAttr[POLARIZATION]);
220 if (pol.empty()) {
221 // Attribute exists in the registry but the user did not specify a value;
222 // treat as "not set" and skip all polarization-specific validation.
223 return;
224 }
225 if (pol.size() != 3) {
226 throw OpalException(
227 "Beam::execute()", "\"POLARIZATION\" must be a length-3 vector {Px, Py, Pz}.");
228 }
229 // Only muons are currently spin-tracked. Reject POLARIZATION on any other
230 // species regardless of magnitude — setting it (even to zero) is meaningless
231 // for spin-0 particles and for species whose g-factor isn't wired into T-BMT.
232 if (!itsAttr[PARTICLE]) {
233 throw OpalException(
234 "Beam::execute()",
235 "\"POLARIZATION\" can only be set when \"PARTICLE\" is also set.");
236 }
238 if (pType != ParticleType::MUON) {
239 throw OpalException(
240 "Beam::execute()",
241 "\"POLARIZATION\" is only supported for PARTICLE=MUON; got \""
243 + "\". For muons produced by PionDecay, leave POLARIZATION unset — "
244 "the daughter polarization is determined by the pion decay.");
245 }
246 const double pMag2 = pol[0] * pol[0] + pol[1] * pol[1] + pol[2] * pol[2];
247 if (pMag2 > 1.0 + 1.0e-12) {
248 throw OpalException(
249 "Beam::execute()", "\"POLARIZATION\" magnitude must be in [0, 1]; got |P| = "
250 + std::to_string(std::sqrt(pMag2)) + ".");
251 }
252}
253
255 if (!itsAttr[SOURCES]) {
256 throw OpalException(
257 "Beam::getEmissionSourceListName()",
258 "\"SOURCES\" must be set for a beam (name of EMISSIONSOURCELIST).");
259 }
260
261 const std::string name = Attributes::getString(itsAttr[SOURCES]);
262 if (name.empty()) {
263 throw OpalException(
264 "Beam::getEmissionSourceListName()",
265 "\"SOURCES\" must not be empty for a beam (name of EMISSIONSOURCELIST).");
266 }
267 return name;
268}
269
270std::vector<std::string> Beam::getGlobalProcessNames() const {
271 return Attributes::getStringArray(itsAttr[GLOBALPROCESSES]);
272}
273
274std::string Beam::getDaughterBeamName() const {
275 return Attributes::getString(itsAttr[DAUGHTERBEAM]);
276}
277
278std::vector<double> Beam::getPolarization() const {
279 std::vector<double> pol = Attributes::getRealArray(itsAttr[POLARIZATION]);
280 if (pol.empty()) {
281 return {0.0, 0.0, 0.0};
282 }
283 return pol;
284}
285
287 return !Attributes::getRealArray(itsAttr[POLARIZATION]).empty();
288}
289
290Beam* Beam::find(const std::string& name) {
291 Beam* beam = dynamic_cast<Beam*>(OpalData::getInstance()->find(name));
292
293 if (beam == 0) {
294 throw OpalException("Beam::find()", "Beam \"" + name + "\" not found.");
295 }
296
297 return beam;
298}
299
300size_t Beam::getNumAlloc() const {
301 if (Attributes::getReal(itsAttr[NALLOC]) > 0) {
302 return (size_t)Attributes::getReal(itsAttr[NALLOC]);
303 } else {
304 throw OpalException(
305 "Beam::getNumAlloc()",
306 "Wrong allocation size for beam! \"NALLOC\" must be positive");
307 }
308}
309
311 // Cast away const, to allow logically constant Beam to update.
312 const_cast<Beam*>(this)->update();
313 return reference;
314}
315
316double Beam::getCurrent() const { return Attributes::getReal(itsAttr[BCURRENT]); }
317
318double Beam::getBunchCharge() const { return Attributes::getReal(itsAttr[BCHARGE]); }
319
320double Beam::getCharge() const { return Attributes::getReal(itsAttr[CHARGE]); }
321
322double Beam::getMass() const { return Attributes::getReal(itsAttr[MASS]); }
323
324double Beam::getMomentum() const { return reference.getP() / 1.e9; }
325
326std::string Beam::getParticleName() const { return Attributes::getString(itsAttr[PARTICLE]); }
327
328bool Beam::isPhoton() const { return itsAttr[PARTICLE] && getParticleName() == photonParticleName; }
329
330double Beam::getFrequency() const { return Attributes::getReal(itsAttr[BFREQ]); }
331
332bool Beam::hasExplicitEnergy() const { return itsAttr[GAMMA] || itsAttr[ENERGY] || itsAttr[PC]; }
333
335 return std::copysign(1.0, getCharge()) * getBunchCharge() / getNumAlloc();
336}
337
340}
341
343 if (itsAttr[PARTICLE]) {
344 std::string pName = getParticleName();
346 if (!itsAttr[MASS]) {
348 }
349 if (!itsAttr[CHARGE]) {
351 }
352 }
353
354 if (isPhoton()) {
356 reference.setQ(0.0);
357 reference.setM(0.0);
358 return;
359 }
360
361 // Set up particle reference; convert all to eV for OPALX.
362 double mass = (itsAttr[MASS] ? getMass() : Physics::m_p) * Units::GeV2eV;
363 double charge = itsAttr[CHARGE] ? getCharge() : 1.0;
364
365 reference = PartData(charge, mass, 1.0);
366
367 // Magnetic moment anomaly G = (g-2)/2 for the species (used by T-BMT).
368 if (itsAttr[PARTICLE]) {
371 }
372
373 if (itsAttr[GAMMA]) {
374 double gamma = Attributes::getReal(itsAttr[GAMMA]);
375 if (gamma > 1.0) {
376 reference.setGamma(gamma);
377 } else {
378 throw OpalException("Beam::update()", "\"GAMMA\" should be greater than 1.");
379 }
380 } else if (itsAttr[ENERGY]) {
381 double energy = Attributes::getReal(itsAttr[ENERGY]) * Units::GeV2eV;
382 if (energy > reference.getM()) {
383 reference.setE(energy);
384 } else {
385 throw OpalException("Beam::update()", "\"ENERGY\" should be greater than \"MASS\".");
386 }
387 } else if (itsAttr[PC]) {
388 double pc = Attributes::getReal(itsAttr[PC]) * Units::GeV2eV;
389 if (pc > 0.0) {
390 reference.setP(pc);
391 } else {
392 throw OpalException("Beam::update()", "\"PC\" should be greater than 0.");
393 }
394 }
395
396 // Set default name.
397 if (getOpalName().empty()) setOpalName("UNNAMED_BEAM");
398}
399
400void Beam::print(std::ostream& os) const {
401 double charge = Attributes::getReal(itsAttr[CHARGE]);
402 os << "* ************* B E A M ************************************************************ "
403 << std::endl;
404 os << "* BEAM " << getOpalName() << '\n'
405 << "* PARTICLE " << Attributes::getString(itsAttr[PARTICLE]) << '\n'
406 << "* REST MASS " << Attributes::getReal(itsAttr[MASS]) << " [GeV]\n"
407 << "* CHARGE " << (charge > 0 ? '+' : '-') << "e * " << std::abs(charge) << " \n"
408 << "* MOMENTUM " << reference.getP() << " [eV/c]\n"
409 << "* MOMENTUM " << Attributes::getReal(itsAttr[PC]) << " [GeV/c]\n"
410 << "* BCHARGE " << Attributes::getReal(itsAttr[BCHARGE]) << " [C]\n"
411 << "* NALLOC " << Attributes::getReal(itsAttr[NALLOC]) << '\n';
412 os << "* ********************************************************************************** "
413 << std::endl;
414}
@ SIZE
Definition IndexMap.cpp:179
Definition Beam.h:32
std::string getParticleName() const
Return Particle's name.
Definition Beam.cpp:326
std::string getEmissionSourceListName() const
Definition Beam.cpp:254
double getCurrent() const
Return the beam current in A (legacy; no longer used in OPALX)
Definition Beam.cpp:316
void validatePolarization() const
Definition Beam.cpp:215
double getChargePerParticle() const
Charge per macro particle in C.
Definition Beam.cpp:334
bool hasPolarization() const
Definition Beam.cpp:286
virtual void execute()
Check the BEAM data.
Definition Beam.cpp:139
double getBunchCharge() const
Return the bunch charge in C.
Definition Beam.cpp:318
double getMomentum() const
Definition Beam.cpp:324
static Beam * find(const std::string &name)
Find named BEAM.
Definition Beam.cpp:290
double getCharge() const
Return the charge number in elementary charge.
Definition Beam.cpp:320
virtual Beam * clone(const std::string &name)
Make clone.
Definition Beam.cpp:137
bool isPhoton() const
True if this beam is configured as a photon beam.
Definition Beam.cpp:328
size_t getNumAlloc() const
Return the allocation size (macroparticles) for this beam.
Definition Beam.cpp:300
PartData reference
Definition Beam.h:126
double getFrequency() const
Return the beam frequency in MHz.
Definition Beam.cpp:330
double getMassPerParticle() const
Mass per macro particle in GeV/c^2.
Definition Beam.cpp:338
double getMass() const
Return Particle's rest mass in GeV.
Definition Beam.cpp:322
virtual void update()
Update the BEAM data.
Definition Beam.cpp:342
void print(std::ostream &os) const
Print the object.
Definition Beam.cpp:400
Beam()
Exemplar constructor.
Definition Beam.cpp:61
bool hasExplicitEnergy() const
True if PC, ENERGY, or GAMMA was explicitly provided by the user.
Definition Beam.cpp:332
const PartData & getReference() const
Return the embedded OPALX PartData.
Definition Beam.cpp:310
virtual bool canReplaceBy(Object *object)
Test if replacement is allowed.
Definition Beam.cpp:132
std::string getDaughterBeamName() const
Return the name of the daughter beam (for decay products), or empty if not set.
Definition Beam.cpp:274
virtual ~Beam()
Definition Beam.cpp:130
std::vector< double > getPolarization() const
Definition Beam.cpp:278
std::vector< std::string > getGlobalProcessNames() const
Return the configured global process names for this beam.
Definition Beam.cpp:270
The base class for all OPAL definitions.
Definition Definition.h:29
The base class for all OPAL objects.
Definition Object.h:45
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition Object.cpp:169
const std::string & getOpalName() const
Return object name.
Definition Object.cpp:267
void setOpalName(const std::string &name)
Set object name.
Definition Object.cpp:281
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:210
bool builtin
Built-in flag.
Definition Object.h:226
Object * find(const std::string &name)
Find entry.
Definition OpalData.cpp:477
static OpalData * getInstance()
Definition OpalData.cpp:193
void define(Object *newObject)
Define a new object.
Definition OpalData.cpp:400
Particle reference data.
Definition PartData.h:37
void setM(double m)
Set reference mass expressed in eV/c^2.
Definition PartData.h:85
void setGamma(double gamma)
Set gamma.
Definition PartData.cpp:75
double getP() const
The constant reference momentum per particle.
Definition PartData.h:111
KOKKOS_INLINE_FUNCTION double getM() const
The constant mass per particle.
Definition PartData.h:109
void setP(double p)
Set reference momentum.
Definition PartData.cpp:41
void setE(double E)
Set reference energy.
Definition PartData.cpp:55
void setAnomaly(double a)
Definition PartData.h:93
void setQ(double q)
Set reference charge expressed in proton charges,.
Definition PartData.h:88
static double getParticleMass(const ParticleType &type)
static double getParticleCharge(const ParticleType &type)
static double getParticleAnomaly(const ParticleType &type)
static ParticleType getParticleType(const std::string &str)
double getReal(const Attribute &attr)
Return real value.
Attribute makeUpperCaseStringArray(const std::string &name, const std::string &help)
Make uppercase string array attribute.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
void setReal(Attribute &attr, double val)
Set real value.
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::vector< std::string > getStringArray(const Attribute &attr)
Get string array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Representation objects and parsers for attribute expressions.
Definition Air.h:27
constexpr double m_p
The proton rest mass in GeV.
Definition Physics.h:105
constexpr double q_e
The elementary charge in As.
Definition Physics.h:84
Definition Units.h:23
constexpr double GeV2eV
Definition Units.h:68