OPALX (Object Oriented Parallel Accelerator Library for Exascale) MINIorX
OPALX
TrackRun.cpp
Go to the documentation of this file.
1// Class TrackRun
2// The RUN command.
3//
4// Copyright (c) 200x - 2022, Paul Scherrer Institut, Villigen PSI, Switzerland
5// All rights reserved
6//
7// This file is part of OPAL.
8//
9// OPAL is free software: you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 3 of the License, or
12// (at your option) any later version.
13//
14// You should have received a copy of the GNU General Public License
15// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
16//
17#include "Track/TrackRun.h"
18
20
22
24
26
27#include "Beamlines/TBeamline.h"
28
29#include "BasicActions/Option.h"
30
32
34
36
38
39#include "Physics/Physics.h"
40#include "Physics/Units.h"
41
42#include "Track/Track.h"
43
45
46#include "Structure/Beam.h"
48#include "Structure/DataSink.h"
51
52#include "OPALconfig.h"
53#include "changes.h"
54
55#include <boost/assign.hpp>
56
57#include <cmath>
58#include <fstream>
59#include <iomanip>
60
61#include <unistd.h>
62
63extern Inform* gmsg;
64
65namespace TRACKRUN {
66 // The attributes of class TrackRun.
67 enum {
68 METHOD, // Tracking method to use.
69 TURNS, // The number of turns to be tracked, we keep that for the moment
70 BEAM, // The beam to track
71 FIELDSOLVER, // The field solver attached
72 BOUNDARYGEOMETRY, // The boundary geometry
73 DISTRIBUTION, // The particle distribution
74 TRACKBACK, // In case we run the beam backwards
75 SIZE
76 };
77} // namespace TRACKRUN
78
79const boost::bimap<TrackRun::RunMethod, std::string> TrackRun::stringMethod_s =
80 boost::assign::list_of<const boost::bimap<TrackRun::RunMethod, std::string>::relation>(
81 RunMethod::PARALLEL, "PARALLEL");
82
84 : Action(
85 TRACKRUN::SIZE, "RUN",
86 "The \"RUN\" sub-command tracks the defined particles through "
87 "the given lattice."),
88 itsTracker_m(nullptr),
89 dist_m(nullptr),
90 fs_m(nullptr),
91 ds_m(nullptr),
92 phaseSpaceSink_m(nullptr),
93 isFollowupTrack_m(false),
94 method_m(RunMethod::NONE),
95 macromass_m(0.0),
96 macrocharge_m(0.0){
97
99 "METHOD", "Name of tracking algorithm to use.", {"PARALLEL"});
100
102 "TURNS",
103 "Number of turns to be tracked; Number of neighboring bunches to be tracked in cyclotron.",
104 1.0);
105
106 itsAttr[TRACKRUN::BEAM] = Attributes::makeString("BEAM", "Name of beam.");
107
109 Attributes::makeString("FIELDSOLVER", "Field solver to be used.");
110
112 "BOUNDARYGEOMETRY", "Boundary geometry to be used NONE (default).", "NONE");
113
115 Attributes::makeStringArray("DISTRIBUTION", "List of particle distributions to be used.");
116
118 Attributes::makeBool("TRACKBACK", "Track in reverse direction, default: false.", false);
119
122}
123
124TrackRun::TrackRun(const std::string& name, TrackRun* parent)
125 : Action(name, parent),
126 itsTracker_m(nullptr),
127 dist_m(nullptr),
128 fs_m(nullptr),
129 ds_m(nullptr),
130 phaseSpaceSink_m(nullptr),
131 isFollowupTrack_m(false),
132 method_m(RunMethod::NONE),
133 macromass_m(0.0),
134 macrocharge_m(0.0){
135 /*
136 the opal dictionary
137 */
138
140
141 const Vector_t<int, 3> nr(8);
142
143 ippl::NDIndex<3> domain;
144 for (unsigned i = 0; i < 3; i++) {
145 domain[i] = ippl::Index(nr[i]);
146 }
147
148 std::array<bool, 3> isParallel;
149
150 for (unsigned d = 0; d < 3; ++d) {
151 isParallel[d] = true;
152 }
153}
154
156 delete phaseSpaceSink_m;
157}
158
159TrackRun* TrackRun::clone(const std::string& name) {
160 return new TrackRun(name, this);
161}
162
164
165 const int currentVersion = ((OPAL_VERSION_MAJOR * 100) + OPAL_VERSION_MINOR) * 100;
166
167 if (Options::version < currentVersion) {
168 unsigned int fileVersion = Options::version / 100;
169 bool newerChanges = false;
170 for (auto it = Versions::changes.begin(); it != Versions::changes.end(); ++it) {
171 if (it->first > fileVersion) {
172 newerChanges = true;
173 break;
174 }
175 }
176 if (newerChanges) {
177 Inform errorMsg("Error");
178 errorMsg << "\n******************** V E R S I O N M I S M A T C H "
179 "***********************\n"
180 << endl;
181 for (auto it = Versions::changes.begin(); it != Versions::changes.end(); ++it) {
182 if (it->first > fileVersion) {
183 errorMsg << it->second << endl;
184 }
185 }
186 errorMsg << "\n"
187 << "* Make sure you do understand these changes and adjust your input file \n"
188 << "* accordingly. Then add\n"
189 << "* OPTION, VERSION = " << currentVersion << ";\n"
190 << "* to your input file. " << endl;
191 errorMsg << "\n************************************************************************"
192 "****\n"
193 << endl;
194 throw OpalException("TrackRun::execute", "Version mismatch");
195 }
196 }
197
200 throw OpalException(
201 "TrackRun::execute", "\"DISTRIBUTION\" must be set in \"RUN\" command.");
202 }
204 throw OpalException("TrackRun::execute", "\"FIELDSOLVER\" must be set in \"RUN\" command.");
205 }
206 if (!itsAttr[TRACKRUN::BEAM]) {
207 throw OpalException("TrackRun::execute", "\"BEAM\" must be set in \"RUN\" command.");
208 }
209
211
212 if (isFollowupTrack_m) {
214 }
215
216 /*
217
218 Gather all data in order to initialize the particle bunch_m
219
220 */
221
222 /*
223 * Distribution(s) can be set via a single distribution or a list
224 * (array) of distributions. If an array is defined the first in the
225 * list is treated as the primary distribution. All others are added to
226 * it to create the full distribution.
227 */
228 std::vector<std::string> distributionArray =
230 const size_t numberOfDistributions = distributionArray.size();
231
232 *gmsg << "* Number of distributions " << numberOfDistributions << endl;
233
234
235 // \todo here we can loop over several distributions
236
237 dist_m = std::shared_ptr<Distribution>(Distribution::find(distributionArray[0]));
238 dist_m->setDistType();
239 *gmsg << *dist_m << endl;
240
242 *gmsg << *fs_m << endl;
243
244
246 *gmsg << *beam << endl;
247
248 macrocharge_m = beam->getChargePerParticle(); // Returns macro charge in [C]
249 macromass_m = beam->getMassPerParticle(); // returns MACRO mass in GeV (mass per simulation particle)
250
252 double part_per_macro_ratio = macrocharge_m / (beam->getCharge() * Physics::q_e);
253 *gmsg << "* Macro charge per particle [eV]: " << (macrocharge_m) << endl;
254 *gmsg << "* Macro mass per particle: [GeV/c^2] " << (macromass_m) << endl;
255 *gmsg << "* Particles per macro particle: " << part_per_macro_ratio << endl;
256 /*
257 Here we can allocate the bunch.
258 */
259
260 // There's a change of units for particle mass that seems strange -> gives consistent Kinetic Energy
261 /*
262 Need the following units for mass and charge:
263 - Charge per macro particle in [C], this should be macrocharge_m or q_m in the bunch. This will be used for the field calculations.
264 - The pusher needs consistent units: eV for mass and elementary charges for charge. This will (hopefully) be handled inside the pusher routines!
265 */
266 bunch_m = std::make_shared<bunch_type>(macrocharge_m, // set the Charge per macro-particle
267 macromass_m, // set the Mass per macro-particle, [GeV], for correct particle kick!
268 // (see "3.1. Physical Units", where mass generally is in MeV/c^2)
269 // However, OPAL seems to use eV for the pusher!
271 beam->getNumberOfParticles()/*, 10*/, 1.0, "LF2", dist_m, fs_m);
272 bunch_m->setT(0.0);
273 bunch_m->setBeamFrequency(beam->getFrequency() * Units::MHz2Hz);
274
275 *gmsg << *(bunch_m->getBCHandler()) << endl;
276
277 double cc = 1.0 / (4 * Physics::pi * Physics::epsilon_0);
278 bunch_m->setCouplingConstant(cc);
279
281
282 // Get algorithm to use.
283 setRunMethod();
284
285 switch (method_m) {
286 case RunMethod::PARALLEL: {
287 break;
288 }
289 default: {
290 throw OpalException("TrackRun::execute", "Unknown \"METHOD\" for the \"RUN\" command");
291 }
292 }
293
294
295 /*
296 \todo Mohsen here we need to create the particles based on dist_m
297
298
299 We have 3 main modes: emit particles, inject particles or get particles from a restart run
300
301 Lets start with the inject particles.
302
303
304 Note: in the pre_run (bunch_m) I disables the particle generation.
305
306 */
307
308 //double deltaP = Attributes::getReal(itsAttr[Distribution::OFFSETP]);
309 //if (inputMoUnits_m == InputMomentumUnits::EVOVERC) {
310 // deltaP = Util::convertMomentumEVoverCToBetaGamma(deltaP, beam->getM());
311 //}
312
313 if (ippl::Comm->rank() == 0) {
314 long number_of_processors = sysconf(_SC_NPROCESSORS_ONLN);
315 *gmsg << "number_of_processors " << number_of_processors << endl;
316
317// *gmsg << "omp_get_max_threads() " << omp_get_max_threads() << endl;
318
319 int world_size;
320 MPI_Comm_size( MPI_COMM_WORLD, &world_size );
321 *gmsg << "MPI_Comm_size " << world_size << endl;
322 }
323
324 static IpplTimings::TimerRef samplingTime = IpplTimings::getTimer("samplingTime");
325 IpplTimings::startTimer(samplingTime);
326
327 // set distribution type
328 dist_m->setDist();
329 dist_m->setAvrgPz( beam->getMomentum()/beam->getMass() );
330
331 // sample particles
332 auto pc = bunch_m->getParticleContainer();
333 auto fc = bunch_m->getFieldContainer();
334 size_type Np = beam->getNumberOfParticles();
336
337 std::shared_ptr<Distribution> opalDist(dist_m);
338
339 switch (opalDist->getType()){
341 sampler_m = std::make_shared<Gaussian>(pc, fc, opalDist);
342 break;
344 sampler_m = std::make_shared<MultiVariateGaussian>(pc, fc, opalDist);
345 break;
347 sampler_m = std::make_shared<FlatTop>(pc, fc, opalDist);
348 break;
349 default:
350 throw OpalException("Distribution::create", "Unknown \"TYPE\" of \"DISTRIBUTION\"");
351 }
352
353 *gmsg << "* About to create particles ..." << endl;
354
355 static IpplTimings::TimerRef GenParticlesTimer = IpplTimings::getTimer("GenParticles");
356 IpplTimings::startTimer(GenParticlesTimer);
357
358 sampler_m->generateParticles(Np, nr);
359
360 IpplTimings::stopTimer(GenParticlesTimer);
361
362 *gmsg << "* Particle creation done" << endl;
363
364 IpplTimings::stopTimer(samplingTime);
365
366 /*
367 reset the fieldsolver with correct hr_m
368 based on the distribution
369 */
370
371 bunch_m->setCharge();
372 bunch_m->setMass();
373 bunch_m->bunchUpdate();
374 bunch_m->print(*gmsg);
375 initDataSink();
376
377 /*
378 if (!isFollowupTrack_m) {
379 *gmsg << std::scientific;
380 *gmsg << *dist_m << endl;
381 }
382 */
383
384 if (bunch_m->getTotalNum() > 0) {
385 double spos = Track::block->zstart;
386 auto& zstop = Track::block->zstop;
387 auto it = Track::block->dT.begin();
388
389 unsigned int i = 0;
390 while (i + 1 < zstop.size() && zstop[i + 1] < spos) {
391 ++i;
392 ++it;
393 }
394
395 bunch_m->setdT(*it);
396 } else {
397 Track::block->zstart = 0.0;
398 }
399
400 /* \todo this is also not unsed in the master.
401 This needs to come back as soon as we have RF
402
403 findPhasesForMaxEnergy();
404
405 */
406
408 *Track::block->use->fetchLine(), bunch_m.get(), *ds_m, Track::block->reference, false,
411
413
414 /*
415 opal_m->setRestartRun(false);
416
417 opal_m->bunchIsAllocated();
418 */
419
421}
422
425 throw OpalException(
426 "TrackRun::setRunMethod", "The attribute \"METHOD\" isn't set for the \"RUN\" command");
427 } else {
429 if (it != stringMethod_s.right.end()) {
430 method_m = it->second;
431 }
432 }
433}
434
435std::string TrackRun::getRunMethodName() const {
436 return stringMethod_s.left.at(method_m);
437}
438
439/*
440
441void TrackRun::setupFieldsolver() {
442 if (fs_m->getFieldSolverType() != FieldSolverType::NONE) {
443 size_t numGridPoints =
444 fs_m->getMX() * fs_m->getMY() * fs_m->getMZ(); // total number of gridpoints
445 Beam* beam = Beam::find(Attributes::getString(itsAttr[TRACKRUN::BEAM]));
446 size_t numParticles = beam->getNumberOfParticles();
447
448 if (!opal->inRestartRun() && numParticles < numGridPoints) {
449 throw OpalException(
450 "TrackRun::setupFieldsolver()",
451 "The number of simulation particles (" + std::to_string(numParticles) + ") \n"
452 + "is smaller than the number of gridpoints (" + std::to_string(numGridPoints)
453 + ").\n"
454 + "Please increase the number of particles or reduce the size of the mesh.\n");
455 }
456
457 OpalData::getInstance()->addProblemCharacteristicValue("MX", fs_m->getMX());
458 OpalData::getInstance()->addProblemCharacteristicValue("MY", fs_m->getMY());
459 OpalData::getInstance()->addProblemCharacteristicValue("MT", fs_m->getMZ());
460 }
461// fs_m->initCartesianFields();
462// Track::block->bunch->setSolver(fs_m);
463
464if (fs_m->hasPeriodicZ()) {
465 Track::block->bunch->setBCForDCBeam();
466} else {
467 Track::block->bunch->setBCAllOpen();
468}
469
470}
471*/
472
474 if (opal_m->inRestartRun()) {
476 opal_m->getInputBasename() + std::string(".h5"), opal_m->getRestartStep(),
477 OpalData::getInstance()->getRestartFileName(), H5_O_WRONLY);
478 } else if (isFollowupTrack_m) {
480 opal_m->getInputBasename() + std::string(".h5"), -1,
481 opal_m->getInputBasename() + std::string(".h5"), H5_O_WRONLY);
482 } else {
484 new H5PartWrapperForPT(opal_m->getInputBasename() + std::string(".h5"), H5_O_WRONLY);
485 }
486
487 if (!opal_m->inRestartRun()) {
490 } else {
493 }
494 } else {
496 }
498}
499
502 // Ask the dictionary if BoundaryGeometry is allocated.
503 // If it is allocated use the allocated BoundaryGeometry
504 if (!OpalData::getInstance()->hasGlobalGeometry()) {
505 const std::string geomDescriptor =
507 BoundaryGeometry* bg = BoundaryGeometry::find(geomDescriptor)->clone(geomDescriptor);
509 }
510 }
511}
512
514 os << endl;
515 os << "* ************* T R A C K R U N *************************************************** "
516 << endl;
517 if (!isFollowupTrack_m) {
518 os << "* Selected Tracking Method == " << getRunMethodName() << ", NEW TRACK" << '\n'
519 << "* "
520 "********************************************************************************** "
521 << '\n';
522 } else {
523 os << "* Selected Tracking Method == " << getRunMethodName() << ", FOLLOWUP TRACK" << '\n'
524 << "* "
525 "********************************************************************************** "
526 << '\n';
527 }
528 os << "* Phase space dump frequency = " << Options::psDumpFreq << '\n'
529 << "* Statistics dump frequency = " << Options::statDumpFreq << " w.r.t. the time step."
530 << '\n'
531 << "* DT = " << Track::block->dT.front() << " [s]\n"
532 << "* MAXSTEPS = " << Track::block->localTimeSteps.front() << '\n'
533 << "* Mass of simulation particle = " << Beam::find(Attributes::getString(itsAttr[TRACKRUN::BEAM]))->getChargePerParticle() << " [GeV/c^2]" << '\n'
534 << "* Charge of simulation particle = " << Beam::find(Attributes::getString(itsAttr[TRACKRUN::BEAM]))->getMassPerParticle() << " [C]" << '\n';
535 os << "* ********************************************************************************** ";
536 return os;
537}
Inform * gmsg
Definition: changes.cpp:7
#define OPAL_VERSION_MINOR
Definition: OPALconfig.h:7
#define OPAL_VERSION_MAJOR
Definition: OPALconfig.h:6
@ SIZE
Definition: IndexMap.cpp:173
PartBunch< T, Dim >::ConstIterator begin(PartBunch< T, Dim > const &bunch)
Defines the FlatTop class used for sampling emitting particles.
const int nr
Definition: ClassicRandom.h:24
ippl::detail::size_type size_type
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
Definition: Attributes.cpp:90
Attribute makeStringArray(const std::string &name, const std::string &help)
Create a string array attribute.
Definition: Attributes.cpp:473
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Definition: Attributes.cpp:409
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Definition: Attributes.cpp:240
bool getBool(const Attribute &attr)
Return logical value.
Definition: Attributes.cpp:100
std::vector< std::string > getStringArray(const Attribute &attr)
Get string array value.
Definition: Attributes.cpp:478
std::string getString(const Attribute &attr)
Get string value.
Definition: Attributes.cpp:343
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
Definition: Attributes.cpp:332
std::map< unsigned int, std::string > changes
Definition: changes.cpp:10
constexpr double epsilon_0
The permittivity of vacuum in As/Vm.
Definition: Physics.h:51
constexpr double q_e
The elementary charge in As.
Definition: Physics.h:69
constexpr double pi
The value of.
Definition: Physics.h:30
constexpr double MHz2Hz
Definition: Units.h:113
@ DISTRIBUTION
Definition: TrackRun.cpp:73
@ TRACKBACK
Definition: TrackRun.cpp:74
@ BOUNDARYGEOMETRY
Definition: TrackRun.cpp:72
@ FIELDSOLVER
Definition: TrackRun.cpp:71
int psDumpFreq
The frequency to dump the phase space, i.e.dump data when steppsDumpFreq==0.
Definition: Options.cpp:39
int version
opal version of input file
Definition: Options.cpp:97
int statDumpFreq
The frequency to dump statistical values, e.e. dump data when stepstatDumpFreq==0.
Definition: Options.cpp:41
std::unique_ptr< mpi::Communicator > Comm
Definition: Ippl.h:22
The base class for all OPAL actions.
Definition: Action.h:30
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition: Object.cpp:189
std::vector< Attribute > itsAttr
The object attributes.
Definition: Object.h:216
DataSink * getDataSink()
Definition: OpalData.cpp:389
std::string getInputBasename()
get input file name without extension
Definition: OpalData.cpp:685
std::string getRestartFileName()
get opals restart h5 format filename
Definition: OpalData.cpp:327
int getRestartStep()
get the step where to restart
Definition: OpalData.cpp:323
void setDataSink(DataSink *s)
Definition: OpalData.cpp:384
bool hasDataSinkAllocated()
true if we already allocated a DataSink object
Definition: OpalData.cpp:380
bool hasBunchAllocated()
true if we already allocated a ParticleBunch object
Definition: OpalData.cpp:364
static OpalData * getInstance()
Definition: OpalData.cpp:195
void setInOPALTMode()
Definition: OpalData.cpp:287
void setGlobalGeometry(BoundaryGeometry *bg)
Definition: OpalData.cpp:455
bool inRestartRun()
true if we do a restart run
Definition: OpalData.cpp:311
void setLocalTrackStep(long long n)
step in a TRACK command
virtual void execute()
Apply the algorithm to the top-level beamline.
static Distribution * find(const std::string &name)
Definition: Beam.h:31
double getChargePerParticle() const
Charge per macro particle in C.
Definition: Beam.cpp:182
double getMomentum() const
Definition: Beam.cpp:170
static Beam * find(const std::string &name)
Find named BEAM.
Definition: Beam.cpp:132
double getCharge() const
Return the charge number in elementary charge.
Definition: Beam.cpp:162
double getFrequency() const
Return the beam frequency in MHz.
Definition: Beam.cpp:178
size_t getNumberOfParticles() const
Return the number of (macro)particles.
Definition: Beam.cpp:142
double getMassPerParticle() const
Mass per macro particle in GeV/c^2.
Definition: Beam.cpp:187
double getMass() const
Return Particle's rest mass in GeV.
Definition: Beam.cpp:166
static BoundaryGeometry * find(const std::string &name)
virtual BoundaryGeometry * clone(const std::string &name)
Return a clone.
void changeH5Wrapper(H5PartWrapper *h5wrapper)
Definition: DataSink.cpp:114
static FieldSolverCmd * find(const std::string &name)
Find named FieldSolverCmd.
PartData reference
The reference data.
Definition: Track.h:46
double zstart
The location at which the simulation starts.
Definition: Track.h:74
std::vector< unsigned long long > localTimeSteps
Maximal number of timesteps.
Definition: Track.h:68
std::vector< double > zstop
The location at which the simulation stops.
Definition: Track.h:77
static Track * block
The block of track data.
Definition: Track.h:55
PartBunch_t * bunch
The particle bunch to be tracked.
Definition: Track.h:43
std::vector< double > dT
The initial timestep.
Definition: Track.h:58
DataSink * ds_m
Definition: TrackRun.h:86
RunMethod method_m
Definition: TrackRun.h:104
void setupBoundaryGeometry()
Definition: TrackRun.cpp:500
std::shared_ptr< SamplingBase > sampler_m
Definition: TrackRun.h:82
H5PartWrapper * phaseSpaceSink_m
Definition: TrackRun.h:88
virtual void execute()
Execute the command.
Definition: TrackRun.cpp:163
void initDataSink()
Definition: TrackRun.cpp:473
bool isFollowupTrack_m
Definition: TrackRun.h:100
void setRunMethod()
Definition: TrackRun.cpp:423
virtual ~TrackRun()
Definition: TrackRun.cpp:155
std::shared_ptr< FieldSolverCmd > fs_m
Definition: TrackRun.h:84
std::shared_ptr< Distribution > dist_m
Definition: TrackRun.h:78
TrackRun()
Exemplar constructor.
Definition: TrackRun.cpp:83
double macromass_m
Definition: TrackRun.h:108
OpalData * opal_m
Definition: TrackRun.h:90
Tracker * itsTracker_m
Definition: TrackRun.h:76
std::shared_ptr< bunch_type > bunch_m
Definition: TrackRun.h:98
virtual TrackRun * clone(const std::string &name)
Make clone.
Definition: TrackRun.cpp:159
std::string getRunMethodName() const
Definition: TrackRun.cpp:435
double macrocharge_m
Definition: TrackRun.h:109
Inform & print(Inform &os) const
Definition: TrackRun.cpp:513
static const boost::bimap< RunMethod, std::string > stringMethod_s
Definition: TrackRun.h:105
The base class for all OPAL exceptions.
Definition: OpalException.h:28
Definition: Inform.h:40
Timing::TimerRef TimerRef
Definition: IpplTimings.h:144
static TimerRef getTimer(const char *nm)
Definition: IpplTimings.h:150
static void stopTimer(TimerRef t)
Definition: IpplTimings.h:156
static void startTimer(TimerRef t)
Definition: IpplTimings.h:153