OPALX (Object Oriented Parallel Accelerator Library for Exascale) MINIorX
OPALX
FlatTop.cpp
Go to the documentation of this file.
1#include "Distribution.h"
2#include "SamplingBase.hpp"
3#include "FlatTop.h"
4#include <memory>
5#include <cmath>
6
10using GeneratorPool = typename Kokkos::Random_XorShift64_Pool<>;
12
13FlatTop::FlatTop(std::shared_ptr<ParticleContainer_t> &pc,
14 std::shared_ptr<FieldContainer_t> &fc,
15 std::shared_ptr<Distribution_t> &opalDist)
16 : SamplingBase(pc, fc, opalDist), rand_pool_m(determineRandInit()) {
17 setParameters(opalDist);
18}
19
21 std::shared_ptr<ParticleContainer_t> &pc,
22 std::shared_ptr<FieldContainer_t> &fc,
23 bool emitting,
24 double sigmaTFall,
25 double sigmaTRise,
27 double tPulseLengthFWHM,
29)
30 : SamplingBase(pc, fc), rand_pool_m(determineRandInit()) {
32 emitting,
33 sigmaTFall,
34 sigmaTRise,
35 cutoff,
36 tPulseLengthFWHM,
37 sigmaR
38 );
39}
40
42 std::shared_ptr<ParticleContainer_t> &pc,
43 bool emitting,
44 double sigmaTFall,
45 double sigmaTRise,
47 double tPulseLengthFWHM,
49)
50 : SamplingBase(pc), rand_pool_m(determineRandInit()) {
52 emitting,
53 sigmaTFall,
54 sigmaTRise,
55 cutoff,
56 tPulseLengthFWHM,
57 sigmaR
58 );
59}
60
61void FlatTop::setWithDomainDecomp(bool withDomainDecomp) {
62 withDomainDecomp_m = withDomainDecomp;
63}
64
66 extern Inform* gmsg;
67 size_t randInit;
68 if (Options::seed == -1) {
69 randInit = 1234567;
70 *gmsg << "* Seed = " << randInit << " on all ranks" << endl;
71 } else {
72 randInit = static_cast<size_t>(Options::seed + 100 * ippl::Comm->rank());
73 }
74 return randInit;
75}
76
77void FlatTop::setParameters(const std::shared_ptr<Distribution_t> &opalDist) {
79 opalDist->emitting_m,
80 opalDist_m->getSigmaTFall(),
81 opalDist_m->getSigmaTRise(),
82 opalDist_m->getCutoffR(),
83 opalDist->getTPulseLengthFWHM(),
84 opalDist_m->getSigmaR()
85 );
86
87 opalDist_m->setTEmission(emissionTime_m);
88
89 // make sure only z direction is decomposed
90 fc_m->setDecomp({false, false, true});
91}
92
94 double sigmaTFall,
95 double sigmaTRise,
97 double tPulseLengthFWHM,
99 ) {
100 emitting_m = emitting;
101 // time span of fall is [0, riseTime, riseTime+flattopTime, fallTime+flattopTime+riseTime ]
102 sigmaTFall_m = sigmaTFall;
103 sigmaTRise_m = sigmaTRise;
104 cutoffR_m = cutoff;
105
106 fallTime_m = sigmaTFall_m * cutoffR_m[2]; // fall is [0, fallTime]
107 flattopTime_m = tPulseLengthFWHM
108 - std::sqrt(2.0 * std::log(2.0)) * (sigmaTRise_m + sigmaTFall_m);
109 if (flattopTime_m < 0.0) {
110 flattopTime_m = 0.0;
111 }
113
115
116 // These expression are taken from the old OPAL
117 // I think normalizedFlankArea is int_0^{cutoff} exp(-(x/sigma)^2/2 ) / sigma
118 // Instead of int_0^{cutoff} exp(-(x/sigma)^2/2 ) / sqrt(2*pi) / sigma, which is strange!
119 // So the distribution of tails are exp(-(x/sigma)^2/2 ) and not Gaussian!
120 normalizedFlankArea_m = 0.5 * std::sqrt(Physics::two_pi) * std::erf(cutoffR_m[2] / std::sqrt(2.0));
122
123 sigmaR_m = sigmaR;
124}
125
126void FlatTop::generateUniformDisk(size_type nlocal, size_t nNew) {
127
128 GeneratorPool rand_pool = rand_pool_m;
132
133 view_type Rview = pc_m->R.getView();
134 view_type Pview = pc_m->P.getView();
135
136 double pi = Physics::pi;
138 // Sample (Rx,Ry) on a unit ring, then scale with sigmaRx and sigmaRy, set Px=Py=0
140 "unitDisk", Kokkos::RangePolicy<>(nlocal, nlocal+nNew), KOKKOS_LAMBDA(const size_t j) {
141 auto generator = rand_pool.get_state();
142 double r = Kokkos::sqrt( generator.drand(0., 1.) );
143 double theta = 2.0 * pi * generator.drand(0., 1.);
144 rand_pool.free_state(generator);
145
146 Rview(j)[0] = r * Kokkos::cos(theta) * sigmaR[0];
147 Rview(j)[1] = r * Kokkos::sin(theta) * sigmaR[1];
148 Rview(j)[2] = 0.0;
149 Pview(j)[0] = 0.0;
150 Pview(j)[1] = 0.0;
151 Pview(j)[2] = 0.0;
152 });
154}
155
157 nr_m = nr;
158}
159
160void FlatTop::generateParticles(size_t& numberOfParticles, Vector_t<double, 3> nr) {
161
162 setNr(nr);
163
164 // initial allocation is similar for both emitting and non-emitting cases
165 allocateParticles(numberOfParticles);
166
167 if(emitting_m){
168 // set nlocal to 0 for the very first time step, before sampling particles
169 //pc_m->setLocalNum(0);
170
171 Kokkos::View<bool*> tmp_invalid("tmp_invalid", 0);
172 // \todo might be abuse of semantics: maybe think about new pc_m->setTotalNum or pc_m->updateTotal function instead?
173 pc_m->destroy(tmp_invalid, pc_m->getLocalNum());
174 }
175}
176
177double FlatTop::FlatTopProfile(double t){
178 double t0;
179 if(t<riseTime_m){
180 t0 = riseTime_m;
181 return exp( -pow((t-t0)/sigmaTRise_m,2) /2. );
182 // In the old opal, tails seem to be exp(-x^2/sigma^2/2) rather than Gaussian with normalizing factor.
183 }
184 else if( t>riseTime_m && t<riseTime_m + flattopTime_m){
185 return 1.;
186 }
189 return exp( -pow((t-t0)/sigmaTFall_m,2)/2. );
190 // In the old opal, tails seem to be exp(-x^2/sigma^2/2) rather than Gaussian with normalizing factor.
191 }
192 else
193 return 0.;
194}
195
196size_t FlatTop::computeNlocalUniformly(size_t nglobal){
197 MPI_Comm comm = MPI_COMM_WORLD;
198 int nranks;
199 int rank;
200 MPI_Comm_size(comm, &nranks);
201 MPI_Comm_rank(comm, &rank);
202
203 size_type nlocal = floor(nglobal/nranks);
204
205 size_t remaining = nglobal - nlocal*nranks;
206
207 if(remaining>0 && rank==0){
208 nlocal += remaining;
209 }
210
211 return nlocal;
212}
213
214double FlatTop::integrateTrapezoidal(double x1, double x2, double y1, double y2){
215 return 0.5 * (y1+y2) * fabs(x2-x1);
216}
217
218void FlatTop::initDomainDecomp(double BoxIncr) {
219 auto *mesh = &fc_m->getMesh();
220 auto *FL = &fc_m->getFL();
224 double tol = 1e-15; // enlarge grid by tol to avoid missing particles on boundaries
225 o[0] = -sigmaR[0] - tol;
226 e[0] = sigmaR[0] + tol;
227 o[1] = -sigmaR[1] - tol;
228 e[1] = sigmaR[1] + tol;
229 o[2] = 0.0 - tol;
230 e[2] = Physics::c * emissionTime_m + tol;
231
233 hr_m = (1.0+BoxIncr/100.)*(l / nr_m);
234 mesh->setMeshSpacing(hr_m);
235 mesh->setOrigin(o-0.5*hr_m*BoxIncr/100.);
236 pc_m->getLayout().updateLayout(*FL, *mesh);
237}
238
239double FlatTop::countEnteringParticlesPerRank(double t0, double tf){
240 size_type nlocalNew=0;
241 double tArea = 0.0;
242 tArea = integrateTrapezoidal(t0, tf, FlatTopProfile(t0), FlatTopProfile(tf));
243 size_type totalNew = floor(totalN_m * tArea / distArea_m);
244 nlocalNew = 0;
245
246 if(totalNew>0){
248 // the same number of particles per rank
249 nlocalNew = computeNlocalUniformly(totalNew);
250 }
251 else{
252 // select number of particles per rank using estimated domain decomposition at final emission time
253 // find min/max of particle positions for [t,t+dt]
254 Vector_t<double, 3> prmin, prmax;
256 prmin[0] = -sigmaR[0];
257 prmax[0] = sigmaR[0];
258 prmin[1] = -sigmaR[1];
259 prmax[1] = sigmaR[1];
260 prmin[2] = std::max(0.0, Physics::c * t0);
261 prmax[2] = Physics::c*tf;
262
263 double dx = prmax[0] - prmin[0];
264 double dy = prmax[1] - prmin[1];
265 double dz = prmax[2] - prmin[2];
266
267 if (dx <= 0 || dy <= 0 || dz <= 0) {
268 throw std::runtime_error("Invalid global particle volume: prmax must be greater than prmin.");
269 }
270
271 double globalpvolume = dx * dy * dz;
272
273 // find min/max of subdomains for the current rank
274 auto regions = pc_m->getLayout().getRegionLayout().gethLocalRegions();
275 int rank = ippl::Comm->rank();
276
277 if (rank < 0 || static_cast<size_t>(rank) >= regions.size()) {
278 throw std::runtime_error("Invalid rank index in gethLocalRegions()");
279 }
280
281 Vector_t<double, 3> locrmin, locrmax;
282 for (unsigned d = 0; d < Dim; ++d) {
283 locrmax[d] = regions(rank)[d].max();
284 locrmin[d] = regions(rank)[d].min();
285 }
286
287 if (prmax[0] >= locrmin[0] && prmin[0] <= locrmax[0] &&
288 prmax[1] >= locrmin[1] && prmin[1] <= locrmax[1] &&
289 prmax[2] >= locrmin[2] && prmin[2] <= locrmax[2]) {
290
291 double x1 = std::max(prmin[0], locrmin[0]);
292 double x2 = std::min(prmax[0], locrmax[0]);
293 double y1 = std::max(prmin[1], locrmin[1]);
294 double y2 = std::min(prmax[1], locrmax[1]);
295 double z1 = std::max(prmin[2], locrmin[2]);
296 double z2 = std::min(prmax[2], locrmax[2]);
297
298 if (x2 >= x1 && y2 >= y1 && z2 >= z1) {
299 double locpvolume = (x2 - x1) * (y2 - y1) * (z2 - z1);
300 if (globalpvolume > 0) {
301 nlocalNew = static_cast<int>(totalNew * locpvolume / globalpvolume);
302 }
303 else{
304 nlocalNew = 0;
305 }
306 } else {
307 nlocalNew = 0;
308 }
309 }
310 }
311 }
312 return nlocalNew;
313}
314
315void FlatTop::allocateParticles(size_t numberOfParticles){
316 totalN_m = numberOfParticles;
317
318 size_type nlocal;
319
321
322 pc_m->create(nlocal);
323}
324
325void FlatTop::emitParticles(double t, double dt) {
326 extern Inform* gmsg;
327
328 // count number of new particles to be emitted
330
331 // current number of particles per rank
332 size_type nlocal = pc_m->getLocalNum();
333
334 // extend particle container to accomodate new particles
335 pc_m->create(nNew);
336
337 // generate new particles on uniform disc
338 *gmsg << "* generate particles on a disc" << endl;
339 generateUniformDisk(nlocal, nNew);
340
341 *gmsg << "* new particles emmitted" << endl;
342}
343
345 size_type nNew;
346 int rank, numRanks;
347 double t = 0.0;
348 double c = Physics::c;
349
350 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
351 MPI_Comm_size(MPI_COMM_WORLD, &numRanks);
352
353 std::string filename = "timeNpart_" + std::to_string(rank) + ".txt";
354 std::ofstream file(filename);
355
356 // Check if the file opened successfully
357 if (!file.is_open()) {
358 throw std::runtime_error("Failed to open file: " + filename);
359 }
360
361 for(size_type i=0; i<nsteps; i++){
362 nNew = countEnteringParticlesPerRank(t, t + dt);
363
364 // current number of particles per rank
365 size_type nlocal = pc_m->getLocalNum();
366
367 // extend particle container to accomodate new particles
368 pc_m->create(nNew);
369
370 // generate new particles on uniform disc
371 generateUniformDisk(nlocal, nNew);
372
373 // write to a file
374 auto rViewDevice = pc_m->R.getView();
375 auto rView = Kokkos::create_mirror_view(rViewDevice);
376 Kokkos::deep_copy(rView,rViewDevice);
377
378 for(size_type j=nlocal; j<nlocal+nNew; j++){
379 file << t << " " << (emissionTime_m-t)*c << " " << rView(j)[0] << " " << rView(j)[1] << "\n";
380 }
381 file.flush(); // Ensure data is written to disk
382
383 t = t + dt;
384 }
385 file.close();
386 ippl::Comm->barrier();
387}
388
389void FlatTop::testEmitParticles(size_type nsteps, double dt) {
390 double t = 0.0;
391
392 for(size_type i=0; i<nsteps; i++){
393 emitParticles(t, dt);
394
395 t = t + dt;
396 }
397}
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
Defines the FlatTop class used for sampling emitting particles.
const int nr
Definition: ClassicRandom.h:24
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
constexpr double two_pi
The value of.
Definition: Physics.h:33
constexpr double e
The value of.
Definition: Physics.h:39
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:45
constexpr double pi
The value of.
Definition: Physics.h:30
int seed
The current random seed.
Definition: Options.cpp:37
void fence()
Definition: Ippl.cpp:103
KOKKOS_INLINE_FUNCTION Vector< T, Dim > max(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
Definition: Vector.hpp:226
KOKKOS_INLINE_FUNCTION Vector< T, Dim > min(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
Definition: Vector.hpp:217
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
std::unique_ptr< mpi::Communicator > Comm
Definition: Ippl.h:22
void setNr(Vector_t< double, 3 > nr)
Sets the number of grid points per direction.
Definition: FlatTop.cpp:156
void testEmitParticles(size_type nsteps, double dt) override
Tests particle emission over a given number of steps.
Definition: FlatTop.cpp:389
double distArea_m
Total area of the flattop distribution.
Definition: FlatTop.h:135
Vector_t< double, 3 > sigmaR_m
Definition: FlatTop.h:147
double FlatTopProfile(double t)
Computes the flat-top profile value at a given time.
Definition: FlatTop.cpp:177
bool emitting_m
Flag for particle emission status.
Definition: FlatTop.h:141
Vector_t< double, 3 > nr_m
Number of grid points per direction.
Definition: FlatTop.h:145
static size_t determineRandInit()
Determines the random seed initialization.
Definition: FlatTop.cpp:65
void allocateParticles(size_t numberOfParticles)
Allocates memory for a given number of particles.
Definition: FlatTop.cpp:315
double emissionTime_m
Total emission time.
Definition: FlatTop.h:144
double sigmaTRise_m
Standard deviation for rise time profile.
Definition: FlatTop.h:137
size_type totalN_m
Total number of particles.
Definition: FlatTop.h:142
GeneratorPool rand_pool_m
Random number generator pool.
Definition: FlatTop.h:132
double sigmaTFall_m
Standard deviation for fall time profile.
Definition: FlatTop.h:136
bool withDomainDecomp_m
Flag for domain decomposition.
Definition: FlatTop.h:143
void initDomainDecomp(double BoxIncr) override
Initializes the domain decomposition.
Definition: FlatTop.cpp:218
Vector_t< double, 3 > hr_m
Grid spacing.
Definition: FlatTop.h:146
double integrateTrapezoidal(double x1, double x2, double y1, double y2)
Integrates using the trapezoidal rule.
Definition: FlatTop.cpp:214
double fallTime_m
Time duration for the fall phase.
Definition: FlatTop.h:139
size_t computeNlocalUniformly(size_t nglobal)
Computes the local number of particles uniformly distributed among ranks.
Definition: FlatTop.cpp:196
double normalizedFlankArea_m
Normalized area of the distribution flanks.
Definition: FlatTop.h:134
void setWithDomainDecomp(bool withDomainDecomp) override
Sets whether to use domain decomposition.
Definition: FlatTop.cpp:61
void emitParticles(double t, double dt) override
Emits new particles within a given time interval.
Definition: FlatTop.cpp:325
void setInternalVariables(bool emitting, double sigmaTFall, double sigmaTRise, Vector_t< double, 3 > cutoff, double tPulseLengthFWHM, Vector_t< double, 3 > sigmaR)
Definition: FlatTop.cpp:93
double riseTime_m
Time duration for the rise phase.
Definition: FlatTop.h:140
void generateParticles(size_t &numberOfParticles, Vector_t< double, 3 > nr) override
Generates particles with a given number and grid configuration.
Definition: FlatTop.cpp:160
double countEnteringParticlesPerRank(double t0, double tf)
Counts the number of particles entering per rank in a given time interval.
Definition: FlatTop.cpp:239
void generateUniformDisk(size_type nlocal, size_t nNew)
Generates particles (x,y) uniformly on a disk distribution.
Definition: FlatTop.cpp:126
void testNumEmitParticles(size_type nsteps, double dt) override
Tests the number of emitted particles over a given number of steps.
Definition: FlatTop.cpp:344
Vector_t< double, 3 > cutoffR_m
Cutoff radius.
Definition: FlatTop.h:138
double flattopTime_m
Time duration of when the time profile is flat.
Definition: FlatTop.h:133
FlatTop(std::shared_ptr< ParticleContainer_t > &pc, std::shared_ptr< FieldContainer_t > &fc, std::shared_ptr< Distribution_t > &opalDist)
Constructor for FlatTop.
Definition: FlatTop.cpp:13
ippl::detail::size_type size_type
Definition: FlatTop.h:131
void setParameters(const std::shared_ptr< Distribution_t > &opalDist)
Sets distribution parameters.
Definition: FlatTop.cpp:77
std::shared_ptr< FieldContainer_t > fc_m
std::shared_ptr< Distribution_t > opalDist_m
std::shared_ptr< ParticleContainer_t > pc_m
Definition: Inform.h:40
const double pi
constexpr unsigned Dim