OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
Distribution.cpp
Go to the documentation of this file.
1//
2// Class Distribution
3// This class defines the initial beam that is injected or emitted into the simulation.
4//
5// Copyright (c) 2008 - 2022, Paul Scherrer Institut, Villigen PSI, Switzerland
6// All rights reserved
7//
8// This file is part of OPAL.
9//
10// OPAL is free software: you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// You should have received a copy of the GNU General Public License
16// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
17//
22#include "BasicActions/Option.h"
25#include "OPALTypes.h"
26#include "Physics/Physics.h"
27#include "Physics/Units.h"
30#include "Utilities/Options.h"
31#include "Utilities/Util.h"
32#include "Utility/IpplTimings.h"
33
34#include "Utilities/GSLCompat.h"
35#include "Utilities/Random.h"
36
37#include <filesystem>
38#include <regex>
39
40#include <sys/time.h>
41
42#include <cfloat>
43#include <cmath>
44#include <iomanip>
45#include <iostream>
46#include <map>
47#include <numeric>
48
49extern Inform* gmsg;
50
51using GeneratorPool = typename Kokkos::Random_XorShift64_Pool<>;
52
53using view_type = typename ippl::detail::ViewType<ippl::Vector<double, Dim>, 1>::view_type;
54
91
92/*
93namespace {
94 matrix6x6_t getUnit6x6() {
95 matrix6x6_t unit6x6(0.0); // Initialize a 6x6 matrix with all elements as 0.0
96 for (unsigned int i = 0; i < 6u; ++i) {
97 unit6x6(i, i) = 1.0; // Set diagonal elements to 1.0
98 }
99 return unit6x6;
100 }
101}
102*/
103
105 : Definition(
106 DISTRIBUTION::SIZE, "DISTRIBUTION",
107 "The DISTRIBUTION statement defines data for the 6D particle distribution."),
108 totalNumberParticles_m(0),
109 distrTypeT_m(DistributionType::NODIST),
110 avrgpz_m(0.0) {
112 "TYPE", "Distribution type.",
113 {"GAUSS", "MULTIVARIATEGAUSS", "FLATTOP", "OPALFLATTOP", "FROMFILE",
114 "EMITTEDFROMFILE"});
115
117 Attributes::makeString("FNAME", "File for reading in 6D particle coordinates.", "");
118
119 // Parameters for defining an initial distribution.
120 itsAttr[DISTRIBUTION::SIGMAX] = Attributes::makeReal("SIGMAX", "SIGMAx (m)", 0.0);
121 itsAttr[DISTRIBUTION::SIGMAY] = Attributes::makeReal("SIGMAY", "SIGMAy (m)", 0.0);
122 itsAttr[DISTRIBUTION::SIGMAZ] = Attributes::makeReal("SIGMAZ", "SIGMAz (m)", 0.0);
123 itsAttr[DISTRIBUTION::SIGMAPX] = Attributes::makeReal("SIGMAPX", "SIGMApx", 0.0);
124 itsAttr[DISTRIBUTION::SIGMAPY] = Attributes::makeReal("SIGMAPY", "SIGMApy", 0.0);
125 itsAttr[DISTRIBUTION::SIGMAPZ] = Attributes::makeReal("SIGMAPZ", "SIGMApz", 0.0);
126
127 itsAttr[DISTRIBUTION::CORR] = Attributes::makeRealArray("CORR", "r correlation");
128
130 "CUTOFFPX", "Distribution cutoff px dimension in units of sigma.", 3.0);
132 "CUTOFFPY", "Distribution cutoff py dimension in units of sigma.", 3.0);
134 "CUTOFFPZ", "Distribution cutoff pz dimension in units of sigma.", 3.0);
135
137 "CUTOFFX", "Distribution cutoff x direction in units of sigma.", 3.0);
139 "CUTOFFY", "Distribution cutoff r direction in units of sigma.", 3.0);
141 "CUTOFFLONG", "Distribution cutoff z or t direction in units of sigma.", 3.0);
142
144 Attributes::makeReal("CORRX", "x/px correlation, (R12 in transport notation).", 0.0);
146 Attributes::makeReal("CORRY", "y/py correlation, (R34 in transport notation).", 0.0);
148 Attributes::makeReal("CORRZ", "z/pz correlation, (R56 in transport notation).", 0.0);
150 Attributes::makeReal("CORRT", "t/pt correlation, (R56 in transport notation).", 0.0);
151
152 itsAttr[DISTRIBUTION::SIGMAT] = Attributes::makeReal("SIGMAT", "SIGMAt (m)", 0.0);
154 Attributes::makeReal("TPULSEFWHM", "Pulse FWHM for emitted distribution.", 0.0);
156 Attributes::makeReal("TRISE", "Rise time for emitted distribution.", 0.0);
158 Attributes::makeReal("TFALL", "Fall time for emitted distribution.", 0.0);
159
161 "FTOSCAMPLITUDE",
162 "Amplitude of oscillations superimposed "
163 "on flat top portion of emitted GAUSS "
164 "distribtuion (in percent of flat top "
165 "amplitude)",
166 0.0);
167
169 "FTOSCPERIODS",
170 "Number of oscillations superimposed on "
171 "flat top portion of emitted GAUSS "
172 "distribution",
173 0.0);
174
176 "EMITTED",
177 "Emitted beam, from cathode, as opposed to "
178 "an injected beam.",
179 false);
180
182 "EMISSIONSTEPS",
183 "Number of OPAL-like time steps to use during OPALFLATTOP or EMITTEDFROMFILE "
184 "emission.",
185 100.0);
186
188 "NPARTDIST",
189 "Number of macroparticles for this DISTRIBUTION. "
190 "If 0 or negative, this distribution does not specify its own count.",
191 0.0);
192
194}
195
196Distribution::Distribution(const std::string& name, Distribution* parent)
197 : Definition(name, parent) {}
198
200
210 size_t locNumber = n / ippl::Comm->size();
211
212 // make sure the total number is exact
213 size_t remainder = n % ippl::Comm->size();
214 size_t myNode = ippl::Comm->rank();
215 if (myNode < remainder) ++locNumber;
216
217 return locNumber;
218}
219
221bool Distribution::canReplaceBy(Object* object) { return dynamic_cast<Distribution*>(object) != 0; }
222
223Distribution* Distribution::clone(const std::string& name) { return new Distribution(name, this); }
224
227 update();
228}
229
230Distribution* Distribution::find(const std::string& name) {
231 Distribution* dist = dynamic_cast<Distribution*>(OpalData::getInstance()->find(name));
232
233 if (dist == 0) {
234 throw OpalException("Distribution::find()", "Distribution \"" + name + "\" not found.");
235 }
236
237 return dist;
238}
239
240Inform& Distribution::printInfo(Inform& os) const {
241 os << "\n"
242 << "* ************* D I S T R I B U T I O N ********************************************"
243 << endl;
244 os << "* " << endl;
245 if (OpalData::getInstance()->inRestartRun()) {
246 os << "* In restart. Distribution read in from .h5 file." << endl;
247 } else {
248 switch (distrTypeT_m) {
250 printDistGauss(os);
251 break;
254 break;
258 break;
262 break;
263 default:
264 throw OpalException("Distribution Param", "Unknown \"TYPE\" of \"DISTRIBUTION\"");
265 }
266 os << "* " << endl;
267 os << "* Distribution is injected." << endl;
268 }
269 os << "* " << endl;
270 os << "* **********************************************************************************"
271 << endl;
272
273 return os;
274}
275
276void Distribution::setAvrgPz(double avrgpz) { avrgpz_m = avrgpz; }
277
278void Distribution::setTEmission(double tEmission) { tEmission_m = tEmission; }
279
280double Distribution::getTEmission() const { return tEmission_m; }
281
284 if (raw <= 0.0) {
285 return 100;
286 }
287 return static_cast<size_t>(std::ceil(raw));
288}
289
291 /*
292 * Set distribution parameters. Do all the necessary checks depending
293 * on the input attributes.
294 * In case of DistributionType::MATCHEDGAUSS we only need to set the cutoff parameters
295 */
296
297 cutoffR_m = 3.;
298 cutoffP_m = 3.;
299 /*
300 cutoffP_m = ippl::Vector<double, 3>(Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFPX]),
301 Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFPY]),
302 Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFPZ]));
303
304
305 cutoffR_m = ippl::Vector<double, 3>(Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFX]),
306 Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFY]),
307 Attributes::getReal(itsAttr[DISTRIBUTION::CUTOFFLONG]));
308 */
309
310 // if (std::abs(Attributes::getReal(itsAttr[Attrib::Distribution::SIGMAR])) > 0.0) {
311 // cutoffR_m[0] = Attributes::getReal(itsAttr[Attrib::Distribution::CUTOFFR]);
312 // cutoffR_m[1] = Attributes::getReal(itsAttr[Attrib::Distribution::CUTOFFR]);
313 // }
314
315 setSigmaR_m();
316 setSigmaP_m();
317
318 avrgpz_m = 0.0;
319}
320
322 cutoffR_m = 3.;
323 cutoffP_m = 3.;
324
325 // initialize the covariance matrix to identity
326 for (unsigned int i = 0; i < 6; ++i) {
327 for (unsigned int j = 0; j < 6; ++j) {
328 if (i == j)
329 correlationMatrix_m[i][j] = 1.0;
330 else
331 correlationMatrix_m[i][j] = 0.0;
332 }
333 }
334
335 // set diagonal elements first
336 setSigmaR_m();
337 setSigmaP_m();
338
339 for (unsigned int i = 0; i < 3; ++i) {
340 correlationMatrix_m[2 * i][2 * i] = sigmaR_m[i] * sigmaR_m[i];
341 correlationMatrix_m[2 * i + 1][2 * i + 1] = sigmaP_m[i] * sigmaP_m[i];
342 }
343
344 std::vector<double> cr = Attributes::getRealArray(itsAttr[DISTRIBUTION::CORR]);
345
346 if (!cr.empty()) {
347 // read off-diagonal correlation matrix from input file
348 if (cr.size() == 15) {
349 *gmsg << "* Use r to specify correlations" << endl;
350 unsigned int k = 0;
351 for (unsigned int i = 0; i < 5; ++i) {
352 for (unsigned int j = i + 1; j < 6; ++j, ++k) {
353 correlationMatrix_m[j][i] = cr.at(k) * cr.at(k);
354 correlationMatrix_m[i][j] = correlationMatrix_m[j][i]; // impose symmetry
355 }
356 }
357 } else {
358 throw OpalException(
359 "Distribution::SetDistParametersGauss",
360 "Inconsistent set of correlations specified, check manual");
361 }
362 }
363
364 avrgpz_m = 0.0;
365}
366
368 // avrgpz_m is not reset here; TrackRun sets it from BEAM (getMomentum()/getMass() = beta*gamma)
369 // so that initial and emitted particles get the correct reference momentum.
370
371 cutoffR_m = 3.;
372 cutoffP_m = 3.;
373
374 // set diagonal elements first
375 setSigmaR_m();
376 setSigmaP_m();
377
378 // initialize the covariance matrix to identity
379 for (unsigned int i = 0; i < 6; ++i) {
380 for (unsigned int j = 0; j < 6; ++j) {
381 if (i == j)
382 correlationMatrix_m[i][j] = 1.0;
383 else
384 correlationMatrix_m[i][j] = 0.0;
385 }
386 }
387
388 cutoffR_m = ippl::Vector<double, 3>(
392
396
399
401
402 if (emitting_m) {
403 sigmaR_m[2] = 0.0;
404
408
411
412 // If TRISE and TFALL are defined > 0.0 then these attributes
413 // override SIGMAT.
414 //
416 || std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::TFALL])) > 0.0) {
417 double timeRatio =
418 std::sqrt(2.0 * std::log(10.0)) - std::sqrt(2.0 * std::log(10.0 / 9.0));
419
420 if (std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::TRISE])) > 0.0)
422 std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::TRISE])) / timeRatio;
423
424 if (std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::TFALL])) > 0.0)
426 std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::TFALL])) / timeRatio;
427 }
428
429 // For an emitted beam, the longitudinal cutoff >= 0.
430 cutoffR_m[2] = std::abs(cutoffR_m[2]);
431 }
432}
433
434void Distribution::printDistGauss(Inform& os) const {
435 os << "* Distribution type: GAUSS" << endl;
436 os << "* " << endl;
437 os << "* SIGMAX = " << sigmaR_m[0] << " [m]" << endl;
438 os << "* SIGMAY = " << sigmaR_m[1] << " [m]" << endl;
439 os << "* SIGMAZ = " << sigmaR_m[2] << " [m]" << endl;
440 os << "* SIGMAPX = " << sigmaP_m[0] << " [Beta Gamma]" << endl;
441 os << "* SIGMAPY = " << sigmaP_m[1] << " [Beta Gamma]" << endl;
442 os << "* SIGMAPZ = " << sigmaP_m[2] << " [Beta Gamma]" << endl;
443}
444
446 os << "* Distribution type: MULTIVARIATEGAUSS" << endl;
447 os << "* " << endl;
448 os << "* SIGMAX = " << sigmaR_m[0] << " [m]" << endl;
449 os << "* SIGMAY = " << sigmaR_m[1] << " [m]" << endl;
450 os << "* SIGMAZ = " << sigmaR_m[2] << " [m]" << endl;
451 os << "* SIGMAPX = " << sigmaP_m[0] << " [Beta Gamma]" << endl;
452 os << "* SIGMAPY = " << sigmaP_m[1] << " [Beta Gamma]" << endl;
453 os << "* SIGMAPZ = " << sigmaP_m[2] << " [Beta Gamma]" << endl;
454
455 os << "* input cov matrix = ";
456 for (unsigned int i = 0; i < 6; ++i) {
457 for (unsigned int j = 0; j < 6; ++j) {
458 os << correlationMatrix_m[i][j] << " ";
459 }
460 os << endl << " ";
461 }
462}
463
464void Distribution::printDistFlatTop(Inform& os) const {
465 os << "* Distribution type: " << distT_m << endl;
466 os << "* " << endl;
467 os << "* SIGMAX = " << sigmaR_m[0] << " [m]" << endl;
468 os << "* SIGMAY = " << sigmaR_m[1] << " [m]" << endl;
469
470 if (emitting_m) {
471 os << "* Sigma Time Rise = " << sigmaTRise_m << " [sec]" << endl;
472 os << "* TPULSEFWHM = " << tPulseLengthFWHM_m << " [sec]" << endl;
473 os << "* Sigma Time Fall = " << sigmaTFall_m << " [sec]" << endl;
474 os << "* Longitudinal cutoff = " << cutoffR_m[2] << " [units of Sigma Time]"
475 << endl;
476 // os << "* Flat top modulation amplitude = "
477 // << Attributes::getReal(itsAttr[DISTRIBUTION::FTOSCAMPLITUDE])
478 // << " [Percent of distribution amplitude]" << endl;
479 // os << "* Flat top modulation periods = "
480 // << std::abs(Attributes::getReal(itsAttr[DISTRIBUTION::FTOSCPERIODS]))
481 // << endl;
482 } else {
483 os << "* SIGMAZ = " << sigmaR_m[2] << " [m]" << endl;
484 }
485}
486
487void Distribution::printDistFromFile(Inform& os) const {
488 os << "* Distribution type: " << distT_m << endl;
489 os << "* " << endl;
490 std::string fname = getFilename();
491 if (!fname.empty()) {
492 os << "* Filename: " << fname << endl;
493 } else {
494 os << "* Filename: (not set)" << endl;
495 }
496}
497
501
503 // Set distribution type and shape-related parameters.
504 setDist();
505
506 // Cache per-distribution particle count, if provided.
507 // A value <= 0 means \"unspecified\" and will be handled by TrackRun/BEAM.
508 const double npartDist = Attributes::getReal(itsAttr[DISTRIBUTION::NPARTDIST]);
510 npartDist > 0.0 ? static_cast<size_t>(npartDist) : static_cast<size_t>(0);
511}
512
514 // set distribution type
515 setDistType();
516 // set distribution parameters
517 switch (distrTypeT_m) {
520 break;
523 break;
527 break;
530 // File-based distributions read their records in the sampler class.
531 break;
532 default:
533 throw OpalException("Distribution Param", "Unknown \"TYPE\" of \"DISTRIBUTION\"");
534 }
535}
536
538 static const std::map<std::string, DistributionType> typeStringToDistType_s = {
539 {"NODIST", DistributionType::NODIST},
540 {"GAUSS", DistributionType::GAUSS},
541 {"MULTIVARIATEGAUSS", DistributionType::MULTIVARIATEGAUSS},
542 {"FLATTOP", DistributionType::FLATTOP},
543 {"OPALFLATTOP", DistributionType::OPALFLATTOP},
544 {"FROMFILE", DistributionType::FROMFILE},
545 {"EMITTEDFROMFILE", DistributionType::EMITTEDFROMFILE}};
546
548
549 if (distT_m.empty()) {
550 throw OpalException(
551 "Distribution::setDistType",
552 "The attribute \"TYPE\" isn't set for the \"DISTRIBUTION\"!");
553 } else {
554 distrTypeT_m = typeStringToDistType_s.at(distT_m);
555 }
556}
557
564
Inform * gmsg
Definition changes.cpp:7
typename Kokkos::Random_XorShift64_Pool<> GeneratorPool
typename ippl::detail::ViewType< ippl::Vector< double, Dim >, 1 >::view_type view_type
Inform * gmsg
Definition changes.cpp:7
DistributionType
@ SIZE
Definition IndexMap.cpp:179
The base class for all OPAL definitions.
Definition Definition.h:29
static Distribution * find(const std::string &name)
ippl::Vector< double, 3 > sigmaR_m
void printDistFlatTop(Inform &os) const
ippl::Vector< double, 3 > sigmaP_m
double FTOSCAmplitude_m
double sigmaTFall_m
double tPulseLengthFWHM_m
virtual void execute()
Execute the command.
double getTEmission() const
virtual bool canReplaceBy(Object *object)
Distribution can only be replaced by another distribution.
double FTOSCPeriods_m
ippl::Vector< double, 3 > cutoffR_m
virtual ~Distribution()
std::string getFilename() const
DistributionType distrTypeT_m
void setDistParametersMultiVariateGauss()
void printDistFromFile(Inform &os) const
virtual Distribution * clone(const std::string &name)
Return a clone.
void printDistMultiVariateGauss(Inform &os) const
ippl::Vector< double, 3 > cutoffP_m
double sigmaTRise_m
size_t totalNumberParticles_m
size_t getNumOfLocalParticlesToCreate(size_t n)
void setTEmission(double tEmission)
void setDistParametersFlatTop()
double tEmission_m
void setAvrgPz(double avrgpz)
std::string distT_m
void printDistGauss(Inform &os) const
Inform & printInfo(Inform &os) const
size_t getEmissionSteps() const
Matrix_t correlationMatrix_m
void setDistParametersGauss()
The base class for all OPAL objects.
Definition Object.h:45
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
Definition Object.cpp:169
virtual void update()
Update this object.
Definition Object.cpp:239
std::vector< Attribute > itsAttr
The object attributes.
Definition Object.h:210
Object * find(const std::string &name)
Find entry.
Definition OpalData.cpp:477
static OpalData * getInstance()
Definition OpalData.cpp:193
Attribute makeBool(const std::string &name, const std::string &help)
Make logical attribute.
double getReal(const Attribute &attr)
Return real value.
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.
bool getBool(const Attribute &attr)
Return logical 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::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.