GInX
Geodesics Integrator tool for particles in GRMHD using Adaptive Mesh Refinement using AMReX.
PhotonsInitializers.hxx
Go to the documentation of this file.
1
8#ifndef PHOTON_INITIALIZERS
9#define PHOTON_INITIALIZERS
10
11#include <AMReX_Box.H>
12#include <AMReX_Config.H>
13#include <AMReX_MFIter.H>
14#include <AMReX_Math.H>
15#include <AMReX_REAL.H>
16#include <AMReX_Random.H>
17#include <AMReX_RandomEngine.H>
18#include <AMReX_Scan.H>
19#include <cctk.h>
20#include <cmath>
21#include <iostream>
22
23#include "AMReX_Array.H"
24#include "AMReX_GpuDevice.H"
25#include "AMReX_ParallelDescriptor.H"
26#include "Interpolator.hxx"
27
28using namespace GInX;
29
41template <typename StructType, typename ParticleContainerClass>
42void random_spherical_initializer(ParticleContainerClass &pc,
43 const CCTK_REAL *real_params,
44 const CCTK_INT *int_params) {
45
46 CCTK_INFO("Initializing particles using the "
47 "random_spherical_photons_per_container_initializer");
48
49 const CCTK_INT level = 0;
50 const CCTK_REAL radius = real_params[0];
51
52 // Get the with of the discretization on each direction.
53 const auto dx = pc.Geom(level).CellSizeArray();
54
55 // Get the lower and higher value over the ParticleContainer Geometry
56 const auto p_lo = pc.Geom(level).ProbLoArray();
57 const auto p_hi = pc.Geom(level).ProbHiArray();
58
59 const int n_procs = amrex::ParallelDescriptor::NProcs();
60 const int proc_id = amrex::ParallelDescriptor::MyProc();
61
62 const int total_particles = int_params[0];
63 const int local_particles_size =
64 total_particles / n_procs + (proc_id < total_particles % n_procs);
65
66 int total_tiles{0};
67 for (amrex::MFIter mfi = pc.MakeMFIter(level); mfi.isValid(); ++mfi) {
68 total_tiles++;
69 }
70
71 int current_tile = 0;
72
73 // Iterating over all the tiles of the particle data structure
74 for (amrex::MFIter mfi = pc.MakeMFIter(level); mfi.isValid(); ++mfi) {
75
76 const unsigned int particles_per_tile =
77 local_particles_size / total_tiles +
78 (current_tile < local_particles_size % total_tiles);
79
80 // get each tile box
81 const amrex::Box &tile_box = mfi.tilebox();
82
83 // Get the tile bounds
84 const auto lo = amrex::lbound(tile_box);
85 const auto hi = amrex::ubound(tile_box);
86 // Get a reference to the particles
87 auto &particles = pc.GetParticles(level);
88 auto &particle_tile = pc.DefineAndReturnParticleTile(level, mfi);
89
90 // Determines the current size and the required new size
91 auto old_size = particle_tile.GetArrayOfStructs().size();
92
93 // Resize the container once, we do not need to do it one by one
94 auto new_size = old_size + particles_per_tile;
95 particle_tile.resize(new_size);
96
97 // Gets raw pointers to the two different ways particle data is stored for
98 // performance reasons: Array of Struct (AoS) and Struct of Arrays (SoA)
99 auto *p_struct = particle_tile.GetArrayOfStructs()().data();
100 auto arrdata = particle_tile.GetStructOfArrays().realarray();
101
102 std::vector<long> particle_ids(particles_per_tile);
103 for (int i = 0; i < particles_per_tile; ++i) {
104 particle_ids[i] = ParticleContainerClass::ParticleType::NextID();
105 }
106
107 // Copy IDs to GPU (AMReX handles this automatically if needed)
108 amrex::Gpu::DeviceVector<long> d_particle_ids(particle_ids.size());
109 amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, particle_ids.begin(),
110 particle_ids.end(), d_particle_ids.begin());
111 const long *id_ptr = d_particle_ids.data();
112
113 amrex::ParallelForRNG(
114 particles_per_tile,
115 [=] AMREX_GPU_DEVICE(int i,
116 amrex::RandomEngine const &engine) noexcept {
117 // Start a for loop with Random Number evolution
118 int pidx = old_size + i;
119
120 // Generate a random position
121 const amrex::Real ratio[AMREX_SPACEDIM] = {
122 (std::abs(p_hi[0] - p_lo[0]) - (radius) * 2.) * 0.5 *
123 Random(engine) +
124 radius,
125 Random(engine) * M_PI, Random(engine) * 2. * M_PI};
126
127 auto &p = p_struct[pidx];
128
129 p.id() = id_ptr[i];
130 p.cpu() = proc_id;
131
132 p.pos(0) = ratio[0] * std::sin(ratio[1]) * std::cos(ratio[2]);
133 p.pos(1) = ratio[0] * std::sin(ratio[1]) * std::sin(ratio[2]);
134 p.pos(2) = ratio[0] * std::cos(ratio[1]);
135
136 // Create the particle and add it to the container
137 arrdata[StructType::vx][pidx] = 2. * Random(engine) - 1.0;
138 arrdata[StructType::vy][pidx] = 2. * Random(engine) - 1.0;
139 arrdata[StructType::vz][pidx] = 2. * Random(engine) - 1.0;
140 arrdata[StructType::ln_E][pidx] = 0;
141 });
142 CCTK_VWarn(1, __LINE__, __FILE__, CCTK_THORNSTRING,
143 "Number of particles created at tile %d: %d ", current_tile,
144 particles_per_tile);
145 current_tile++;
146 }
147
148 pc.Redistribute();
149 pc.SortParticlesByCell();
150
151 CCTK_VINFO("%d particles created", pc.TotalNumberOfParticles());
152
153} // random_spherical_initializer
154
165template <typename StructType, typename ParticleContainerClass>
166void random_uniform_initializer(ParticleContainerClass &pc,
167 const CCTK_REAL *real_params,
168 const CCTK_INT *int_params) {
169
170 CCTK_INFO("Initializing particles using the "
171 "random_uniform_photons_per_container_initializer");
172
173 const CCTK_INT level = 0;
174 const CCTK_REAL radius = real_params[0];
175
176 // Get the lower and higher value over the ParticleContainer Geometry
177 const auto p_lo = pc.Geom(level).ProbLoArray();
178 const auto p_hi = pc.Geom(level).ProbHiArray();
179
180 const int n_procs = amrex::ParallelDescriptor::NProcs();
181 const int proc_id = amrex::ParallelDescriptor::MyProc();
182
183 const int total_particles = int_params[0];
184 const int local_particles_size =
185 total_particles / n_procs + (proc_id < total_particles % n_procs);
186
187 int total_tiles{0};
188 for (amrex::MFIter mfi = pc.MakeMFIter(level); mfi.isValid(); ++mfi) {
189 total_tiles++;
190 }
191
192 int current_tile = 0;
193
194 // Iterating over all the tiles of the particle data structure
195 for (amrex::MFIter mfi = pc.MakeMFIter(level); mfi.isValid(); ++mfi) {
196
197 const unsigned int particles_per_tile =
198 local_particles_size / total_tiles +
199 (current_tile < local_particles_size % total_tiles);
200
201 // get each tile box
202 const amrex::Box &tile_box = mfi.tilebox();
203
204 // Get the tile bounds
205 const auto lo = amrex::lbound(tile_box);
206 const auto hi = amrex::ubound(tile_box);
207 // Get a reference to the particles
208 auto &particles = pc.GetParticles(level);
209 auto &particle_tile = pc.DefineAndReturnParticleTile(level, mfi);
210
211 // Determines the current size and the required new size
212 auto old_size = particle_tile.GetArrayOfStructs().size();
213
214 // Resize the container once, we do not need to do it one by one
215 auto new_size = old_size + particles_per_tile;
216 particle_tile.resize(new_size);
217
218 // Gets raw pointers to the two different ways particle data is stored for
219 // performance reasons: Array of Struct (AoS) and Struct of Arrays (SoA)
220 auto *p_struct = particle_tile.GetArrayOfStructs()().data();
221 auto arrdata = particle_tile.GetStructOfArrays().realarray();
222
223 std::vector<long> particle_ids(particles_per_tile);
224 for (int i = 0; i < particles_per_tile; ++i) {
225 particle_ids[i] = ParticleContainerClass::ParticleType::NextID();
226 }
227
228 // Copy IDs to GPU (AMReX handles this automatically if needed)
229 amrex::Gpu::DeviceVector<long> d_particle_ids(particle_ids.size());
230 amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, particle_ids.begin(),
231 particle_ids.end(), d_particle_ids.begin());
232 const long *id_ptr = d_particle_ids.data();
233
234 amrex::ParallelForRNG(
235 particles_per_tile,
236 [=] AMREX_GPU_DEVICE(int i,
237 amrex::RandomEngine const &engine) noexcept {
238 // Start a for loop with Random Number evolution
239 int pidx = old_size + i;
240 auto &p = p_struct[pidx];
241
242 p.id() = id_ptr[i];
243 p.cpu() = proc_id;
244
245 do {
246 p.pos(0) = Random(engine) * (p_hi[0] - p_lo[0]) + p_lo[0];
247 p.pos(1) = Random(engine) * (p_hi[1] - p_lo[1]) + p_lo[1];
248 p.pos(2) = Random(engine) * (p_hi[2] - p_lo[2]) + p_lo[2];
249 } while ((p.pos(0) * p.pos(0) + p.pos(1) * p.pos(1) +
250 p.pos(2) * p.pos(2)) <
251 (radius) * (radius));
252
253 // Create the particle and add it to the container
254 arrdata[StructType::vx][pidx] = 2. * Random(engine) - 1.0;
255 arrdata[StructType::vy][pidx] = 2. * Random(engine) - 1.0;
256 arrdata[StructType::vz][pidx] = 2. * Random(engine) - 1.0;
257 arrdata[StructType::ln_E][pidx] = 0;
258 });
259 CCTK_VWarn(1, __LINE__, __FILE__, CCTK_THORNSTRING,
260 "Number of particles created at tile %d: %d ", current_tile,
261 particles_per_tile);
262 current_tile++;
263 }
264
265 pc.Redistribute();
266 pc.SortParticlesByCell();
267
268 CCTK_VINFO("%d particles created", pc.TotalNumberOfParticles());
269
270} // random_uniform_initializer
271
272#endif // !PHOTON_INITIALIZERS
Barycentric Lagrange interpolation related functions definitions.
void random_spherical_initializer(ParticleContainerClass &pc, const CCTK_REAL *real_params, const CCTK_INT *int_params)
This function random initializes particles spherically distributed around a sphere of radius real_par...
Definition: PhotonsInitializers.hxx:42
void random_uniform_initializer(ParticleContainerClass &pc, const CCTK_REAL *real_params, const CCTK_INT *int_params)
This function random initializes particles uniformly distributed in a box avoiding a sphere of radius...
Definition: PhotonsInitializers.hxx:166
Interpolators namespace.
Definition: ParticlesContainer.hxx:39