IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
LandauDampingMixedExec.cpp
Go to the documentation of this file.
1// Landau Damping Test
2// Usage:
3// srun ./LandauDamping
4// <nx> [<ny>...] <Np> <Nt> <stype>
5// <lbthres> --overallocate <ovfactor> <logT> --info 10
6// nx = No. cell-centered points in the x-direction
7// ny... = No. cell-centered points in the y-, z-, ...-direction
8// Np = Total no. of macro-particles in the simulation
9// Nt = Number of time steps
10// stype = Field solver type (FFT and CG supported)
11// lbthres = Load balancing threshold i.e., lbthres*100 is the maximum load imbalance
12// percentage which can be tolerated and beyond which
13// particle load balancing occurs. A value of 0.01 is good for many typical
14// simulations.
15// ovfactor = Over-allocation factor for the buffers used in the communication. Typical
16// values are 1.0, 2.0. Value 1.0 means no over-allocation.
17// logT = Logging period. Data logging is performed on the CPU in parallel to
18// GPU computation and only every logT timesteps.
19// Example:
20// srun ./LandauDamping 128 128 128 10000 10 FFT 0.01 --overallocate 2.0 --info 10
21//
22
23#include <Kokkos_MathematicalConstants.hpp>
24#include <Kokkos_MathematicalFunctions.hpp>
25#include <Kokkos_Random.hpp>
26#include <chrono>
27#include <iostream>
28#include <random>
29#include <set>
30#include <string>
31#include <vector>
32
33#include "Utility/IpplTimings.h"
34
35#include "ChargedParticles.hpp"
36
37constexpr unsigned Dim = 3;
38
39template <typename T>
40struct Newton1D {
41 double tol = 1e-12;
42 int max_iter = 20;
43 double pi = Kokkos::numbers::pi_v<double>;
44
46
47 KOKKOS_INLINE_FUNCTION Newton1D() {}
48
49 KOKKOS_INLINE_FUNCTION Newton1D(const T& k_, const T& alpha_, const T& u_)
50 : k(k_)
51 , alpha(alpha_)
52 , u(u_) {}
53
54 KOKKOS_INLINE_FUNCTION ~Newton1D() {}
55
56 KOKKOS_INLINE_FUNCTION T f(T& x) {
57 T F;
58 F = x + (alpha * (Kokkos::sin(k * x) / k)) - u;
59 return F;
60 }
61
62 KOKKOS_INLINE_FUNCTION T fprime(T& x) {
63 T Fprime;
64 Fprime = 1 + (alpha * Kokkos::cos(k * x));
65 return Fprime;
66 }
67
68 KOKKOS_FUNCTION
69 void solve(T& x) {
70 int iterations = 0;
71 while (iterations < max_iter && Kokkos::fabs(f(x)) > tol) {
72 x = x - (f(x) / fprime(x));
73 iterations += 1;
74 }
75 }
76};
77
78template <typename T, class GeneratorPool, unsigned Dim>
81 using value_type = typename T::value_type;
82 // Output View for the random numbers
84
85 // The GeneratorPool
86 GeneratorPool rand_pool;
87
89
91
92 // Initialize all members
93 generate_random(view_type x_, view_type v_, GeneratorPool rand_pool_, value_type& alpha_, T& k_,
94 T& minU_, T& maxU_)
95 : x(x_)
96 , v(v_)
97 , rand_pool(rand_pool_)
98 , alpha(alpha_)
99 , k(k_)
100 , minU(minU_)
101 , maxU(maxU_) {}
102
103 KOKKOS_INLINE_FUNCTION void operator()(const size_t i) const {
104 // Get a random number state from the pool for the active thread
105 typename GeneratorPool::generator_type rand_gen = rand_pool.get_state();
106
107 value_type u;
108 for (unsigned d = 0; d < Dim; ++d) {
109 u = rand_gen.drand(minU[d], maxU[d]);
110 x(i)[d] = u / (1 + alpha);
111 Newton1D<value_type> solver(k[d], alpha, u);
112 solver.solve(x(i)[d]);
113 v(i)[d] = rand_gen.normal(0.0, 1.0);
114 }
115
116 // Give the state back, which will allow another thread to acquire it
117 rand_pool.free_state(rand_gen);
118 }
119};
120
121double CDF(const double& x, const double& alpha, const double& k) {
122 double cdf = x + (alpha / k) * std::sin(k * x);
123 return cdf;
124}
125
126KOKKOS_FUNCTION
127double PDF(const Vector_t<double, Dim>& xvec, const double& alpha, const Vector_t<double, Dim>& kw,
128 const unsigned Dim) {
129 double pdf = 1.0;
130
131 for (unsigned d = 0; d < Dim; ++d) {
132 pdf *= (1.0 + alpha * Kokkos::cos(kw[d] * xvec[d]));
133 }
134 return pdf;
135}
136
137const char* TestName = "LandauDamping";
138
139int main(int argc, char* argv[]) {
140 ippl::initialize(argc, argv);
141 {
143
144 Inform msg("LandauDamping");
145 Inform msg2all("LandauDamping", INFORM_ALL_NODES);
146
147 auto start = std::chrono::high_resolution_clock::now();
148
149 int arg = 1;
150
152 for (unsigned d = 0; d < Dim; d++) {
153 nr[d] = std::atoi(argv[arg++]);
154 }
155
156 static IpplTimings::TimerRef mainTimer = IpplTimings::getTimer("total");
157 static IpplTimings::TimerRef particleCreation = IpplTimings::getTimer("particlesCreation");
158 static IpplTimings::TimerRef dumpDataTimer = IpplTimings::getTimer("dumpData");
159 static IpplTimings::TimerRef PTimer = IpplTimings::getTimer("pushVelocity");
160 static IpplTimings::TimerRef RTimer = IpplTimings::getTimer("pushPosition");
161 static IpplTimings::TimerRef updateTimer = IpplTimings::getTimer("update");
162 static IpplTimings::TimerRef DummySolveTimer = IpplTimings::getTimer("solveWarmup");
163 static IpplTimings::TimerRef SolveTimer = IpplTimings::getTimer("solve");
164 static IpplTimings::TimerRef domainDecomposition = IpplTimings::getTimer("loadBalance");
165
166 IpplTimings::startTimer(mainTimer);
167
168 const size_type totalP = std::atoll(argv[arg++]);
169 const unsigned int nt = std::atoi(argv[arg++]);
170
171 msg << "Landau damping" << endl
172 << "nt " << nt << " Np= " << totalP << " grid = " << nr << endl;
173
174 using bunch_type = ChargedParticles<PLayout_t<double, Dim>, double, Dim>;
175
176 std::unique_ptr<bunch_type> P;
177
178 ippl::NDIndex<Dim> domain;
179 for (unsigned i = 0; i < Dim; i++) {
180 domain[i] = ippl::Index(nr[i]);
181 }
182
183 std::array<bool, Dim> isParallel;
184 isParallel.fill(true);
185
186 // create mesh and layout objects for this problem domain
187 Vector_t<double, Dim> kw = 0.5;
188 double alpha = 0.05;
189 Vector_t<double, Dim> rmin(0.0);
190 Vector_t<double, Dim> rmax = 2 * pi / kw;
191
192 Vector_t<double, Dim> hr = rmax / nr;
193 // Q = -\int\int f dx dv
194 double Q = std::reduce(rmax.begin(), rmax.end(), -1., std::multiplies<double>());
195 Vector_t<double, Dim> origin = rmin;
196
197 const bool isAllPeriodic = true;
198 Mesh_t<Dim> mesh(domain, hr, origin);
199 FieldLayout_t<Dim> FL(MPI_COMM_WORLD, domain, isParallel, isAllPeriodic);
200 PLayout_t<double, Dim> PL(FL, mesh);
201
202 std::string solver = argv[arg++];
203
204 if (solver == "OPEN") {
205 throw IpplException("LandauDamping",
206 "Open boundaries solver incompatible with this simulation!");
207 }
208
209 P = std::make_unique<bunch_type>(PL, hr, rmin, rmax, isParallel, Q, solver);
210
211 P->nr_m = nr;
212
213 P->initializeFields(mesh, FL);
214
215 P->initSolver();
216 P->time_m = 0.0;
217 P->loadbalancethreshold_m = std::atof(argv[arg++]);
218
219 LoggingPeriod = std::atoll(argv[arg++]);
220 const double dt =
221 std::min(.05, 0.5 * *std::min_element(hr.begin(), hr.end())) / LoggingPeriod;
222
223 bool isFirstRepartition;
224
225 if ((P->loadbalancethreshold_m != 1.0) && (ippl::Comm->size() > 1)) {
226 msg << "Starting first repartition" << endl;
227 IpplTimings::startTimer(domainDecomposition);
228 isFirstRepartition = true;
229 const ippl::NDIndex<Dim>& lDom = FL.getLocalNDIndex();
230 const int nghost = P->rho_m.getNghost();
231 auto rhoview = P->rho_m.getView();
232
233 using index_array_type = typename ippl::RangePolicy<Dim>::index_array_type;
235 "Assign initial rho based on PDF", P->rho_m.getFieldRangePolicy(),
236 KOKKOS_LAMBDA(const index_array_type& args) {
237 // local to global index conversion
238 Vector_t<double, Dim> xvec = (args + lDom.first() - nghost + 0.5) * hr + origin;
239
240 // ippl::apply accesses the view at the given indices and obtains a
241 // reference; see src/Expression/IpplOperations.h
242 ippl::apply(rhoview, args) = PDF(xvec, alpha, kw, Dim);
243 });
244
245 Kokkos::fence();
246
247 P->initializeORB(FL, mesh);
248 P->repartition(FL, mesh, isFirstRepartition);
249 IpplTimings::stopTimer(domainDecomposition);
250 }
251
252 msg << "First domain decomposition done" << endl;
253 IpplTimings::startTimer(particleCreation);
254
255 typedef ippl::detail::RegionLayout<double, Dim, Mesh_t<Dim>>::uniform_type RegionLayout_t;
256 const RegionLayout_t& RLayout = PL.getRegionLayout();
257 const typename RegionLayout_t::host_mirror_type Regions = RLayout.gethLocalRegions();
258 Vector_t<double, Dim> Nr, Dr, minU, maxU;
259 int myRank = ippl::Comm->rank();
260 double factor = 1;
261 for (unsigned d = 0; d < Dim; ++d) {
262 Nr[d] = CDF(Regions(myRank)[d].max(), alpha, kw[d])
263 - CDF(Regions(myRank)[d].min(), alpha, kw[d]);
264 Dr[d] = CDF(rmax[d], alpha, kw[d]) - CDF(rmin[d], alpha, kw[d]);
265 minU[d] = CDF(Regions(myRank)[d].min(), alpha, kw[d]);
266 maxU[d] = CDF(Regions(myRank)[d].max(), alpha, kw[d]);
267 factor *= Nr[d] / Dr[d];
268 }
269
270 size_type nloc = (size_type)(factor * totalP);
271 size_type Total_particles = 0;
272
273 MPI_Allreduce(&nloc, &Total_particles, 1, MPI_UNSIGNED_LONG, MPI_SUM,
274 ippl::Comm->getCommunicator());
275
276 int rest = (int)(totalP - Total_particles);
277
278 if (ippl::Comm->rank() < rest) {
279 ++nloc;
280 }
281
282 P->create(nloc);
283 Kokkos::Random_XorShift64_Pool<> rand_pool64((size_type)(42 + 100 * ippl::Comm->rank()));
284 Kokkos::parallel_for(
285 nloc, generate_random<Vector_t<double, Dim>, Kokkos::Random_XorShift64_Pool<>, Dim>(
286 P->R.getView(), P->P.getView(), rand_pool64, alpha, kw, minU, maxU));
287
288 Kokkos::fence();
289 ippl::Comm->barrier();
290 IpplTimings::stopTimer(particleCreation);
291
292 P->q = P->Q_m / totalP;
293 msg << "particles created and initial conditions assigned " << endl;
294 isFirstRepartition = false;
295 // The update after the particle creation is not needed as the
296 // particles are generated locally
297
298 IpplTimings::startTimer(DummySolveTimer);
299 P->rho_m = 0.0;
300 P->runSolver();
301 IpplTimings::stopTimer(DummySolveTimer);
302
303 P->scatterCIC(totalP, 0, hr);
304
305 IpplTimings::startTimer(SolveTimer);
306 P->runSolver();
307 IpplTimings::stopTimer(SolveTimer);
308
309 auto Eview = P->getEMirror();
310
311 // gather E field
312 P->gatherCIC();
313
314 IpplTimings::startTimer(dumpDataTimer);
315 P->dumpLandau(Eview);
316 P->gatherStatistics(totalP);
317 // P->dumpLocalDomains(FL, 0);
318 IpplTimings::stopTimer(dumpDataTimer);
319
320 // begin main timestep loop
321 std::thread dumpThread;
322 msg << "Starting iterations ..." << endl;
323 for (unsigned int it = 0; it < nt * LoggingPeriod; it++) {
324 // LeapFrog time stepping https://en.wikipedia.org/wiki/Leapfrog_integration
325 // Here, we assume a constant charge-to-mass ratio of -1 for
326 // all the particles hence eliminating the need to store mass as
327 // an attribute
328 // kick
329
331 P->P = P->P - 0.5 * dt * P->E;
333
334 // drift
336 P->R = P->R + dt * P->P;
338 // P->R.print();
339
340 // Since the particles have moved spatially update them to correct processors
341 IpplTimings::startTimer(updateTimer);
342 P->update();
343 IpplTimings::stopTimer(updateTimer);
344
345 // Domain Decomposition
346 if (P->balance(totalP, it + 1)) {
347 msg << "Starting repartition" << endl;
348 IpplTimings::startTimer(domainDecomposition);
349 P->repartition(FL, mesh, isFirstRepartition);
350 IpplTimings::stopTimer(domainDecomposition);
351 // IpplTimings::startTimer(dumpDataTimer);
352 // P->dumpLocalDomains(FL, it+1);
353 // IpplTimings::stopTimer(dumpDataTimer);
354 }
355
356 // scatter the charge onto the underlying grid
357 P->scatterCIC(totalP, it + 1, hr);
358
359 // Field solve
360 IpplTimings::startTimer(SolveTimer);
361 P->runSolver();
362 IpplTimings::stopTimer(SolveTimer);
363
364 if ((it + 1) % LoggingPeriod == 0) {
365 P->updateEMirror(Eview);
366 if (dumpThread.joinable()) {
367 dumpThread.join();
368 }
369 auto dump = [&]() {
370 IpplTimings::startTimer(dumpDataTimer);
371 msg << "Processing time step " << it + 1 << " on host" << endl;
372 P->dumpLandau(Eview);
373 P->gatherStatistics(totalP);
374 IpplTimings::stopTimer(dumpDataTimer);
375 };
376 dumpThread = std::thread(dump);
377 }
378
379 // gather E field
380 P->gatherCIC();
381
382 // kick
384 P->P = P->P - 0.5 * dt * P->E;
386
387 P->time_m += dt;
388 msg << "Host reached end of time step: " << it + 1 << " time: " << P->time_m << endl;
389
390 if (checkSignalHandler()) {
391 msg << "Aborting timestepping loop due to signal " << interruptSignalReceived
392 << endl;
393 break;
394 }
395 }
396 if (dumpThread.joinable()) {
397 dumpThread.join();
398 }
399
400 msg << "LandauDamping: End." << endl;
401 IpplTimings::stopTimer(mainTimer);
403 IpplTimings::print(std::string("timing.dat"));
404 auto end = std::chrono::high_resolution_clock::now();
405
406 std::chrono::duration<double> time_chrono =
407 std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
408 std::cout << "Elapsed time: " << time_chrono.count() << std::endl;
409 }
411
412 return 0;
413}
constexpr unsigned Dim
int main(int argc, char *argv[])
KOKKOS_FUNCTION double PDF(const Vector_t< double, Dim > &xvec, const double &alpha, const Vector_t< double, Dim > &kw, const unsigned Dim)
double CDF(const double &x, const double &alpha, const double &k)
unsigned LoggingPeriod
const double pi
bool checkSignalHandler()
int interruptSignalReceived
void setSignalHandler()
constexpr unsigned Dim
ippl::detail::size_type size_type
Definition datatypes.h:23
const char * TestName
ippl::FieldLayout< Dim > FieldLayout_t
Definition datatypes.h:21
ippl::Vector< T, Dim > Vector_t
Definition datatypes.h:38
typename ippl::ParticleSpatialLayout< T, Dim, Mesh_t< Dim > > PLayout_t
Definition datatypes.h:15
ippl::UniformCartesian< double, Dim > Mesh_t
Definition datatypes.h:12
Inform & endl(Inform &inf)
Definition Inform.cpp:42
#define INFORM_ALL_NODES
Definition Inform.h:38
void initialize(int &argc, char *argv[], MPI_Comm comm)
Definition Ippl.cpp:16
void finalize()
Definition Ippl.cpp:94
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
std::unique_ptr< mpi::Communicator > Comm
Definition Ippl.h:22
const NDIndex_t & getLocalNDIndex() const
KOKKOS_INLINE_FUNCTION Vector< int, Dim > first() const
Definition NDIndex.hpp:170
const host_mirror_type gethLocalRegions() const
KOKKOS_INLINE_FUNCTION constexpr iterator begin()
Definition Vector.hpp:160
KOKKOS_INLINE_FUNCTION constexpr iterator end()
Definition Vector.hpp:165
Kokkos::View< typename NPtr< T, Dim >::type, Properties... > view_type
Definition ViewTypes.h:45
Timing::TimerRef TimerRef
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void print()
static void startTimer(TimerRef t)
::ippl::Vector< index_type, Dim > index_array_type
KOKKOS_FUNCTION void solve(T &x)
KOKKOS_INLINE_FUNCTION Newton1D(const T &k_, const T &alpha_, const T &u_)
KOKKOS_INLINE_FUNCTION T f(T &x)
KOKKOS_INLINE_FUNCTION ~Newton1D()
KOKKOS_INLINE_FUNCTION Newton1D()
KOKKOS_INLINE_FUNCTION T fprime(T &x)
KOKKOS_INLINE_FUNCTION void operator()(const size_t i) const
typename T::value_type value_type
generate_random(view_type x_, view_type v_, GeneratorPool rand_pool_, value_type &alpha_, T &k_, T &minU_, T &maxU_)
typename ippl::detail::ViewType< T, 1 >::view_type view_type