ImpactX
Loading...
Searching...
No Matches
Thermal.H
Go to the documentation of this file.
1/* Copyright 2022-2023 The Regents of the University of California, through Lawrence
2 * Berkeley National Laboratory (subject to receipt of any required
3 * approvals from the U.S. Dept. of Energy). All rights reserved.
4 *
5 * This file is part of ImpactX.
6 *
7 * Authors: Ji Qiang, Axel Huebl, Chad Mitchell
8 * License: BSD-3-Clause-LBNL
9 */
10#ifndef IMPACTX_DISTRIBUTION_THERMAL
11#define IMPACTX_DISTRIBUTION_THERMAL
12
14
15#include <ablastr/constant.H>
16
17#include <AMReX_GpuContainers.H>
18#include <AMReX_Math.H>
19#include <AMReX_Print.H>
20#include <AMReX_Random.H>
21#include <AMReX_REAL.H>
22
23#include <cmath>
24#include <cstdint>
25#include <memory>
26#include <random>
27#include <utility>
28#include <vector>
29
30
31namespace impactx
32{
33namespace distribution
34{
36 {
37 static constexpr amrex::ParticleReal tolerance = 1.0e-3;
38 static constexpr amrex::ParticleReal rin = 1.0e-10;
39 static constexpr amrex::ParticleReal rout = 10.0;
40 static constexpr int nsteps = 2000;
41
50 int m_nbins;
59
60 // GPU data
61 static inline std::unique_ptr<amrex::Gpu::DeviceVector<amrex::ParticleReal>> m_d_cdf1;
62 static inline std::unique_ptr<amrex::Gpu::DeviceVector<amrex::ParticleReal>> m_d_cdf2;
63
71 )
72 {
73 m_k = kin;
74 m_T1 = T1in;
75 m_T2 = T2in;
76 m_p1 = p1in;
77 m_p2 = p2in;
78 m_w = win;
79 }
80
86 void
87 generate_radial_dist (amrex::ParticleReal bunch_charge, RefPart const & refpart)
88 {
89 using namespace amrex::literals; // for _rt and _prt
90 using namespace ablastr::constant::math; // for pi
93
94 // Get relativistic beta*gamma
95 amrex::ParticleReal bg = refpart.beta_gamma();
96 m_bg = bg;
97
98 // Get reference particle rest energy (eV) and charge (q_e)
99 amrex::ParticleReal Erest = refpart.mass_MeV() * 1.0e6_prt;
100 amrex::ParticleReal q_e = refpart.charge_qe();
101
102 // Set space charge intensity
103 m_Cintensity = q_e*bunch_charge/(powi<2>(bg)*Erest*ep0);
104
105 // Set minimum and maximum radius
107 amrex::ParticleReal rmin = rin*r_scale;
108 amrex::ParticleReal rmax = rout*r_scale;
109 // amrex::PrintToFile("equilibrium_params.out") << r_scale << " " << data.Cintensity << "\n";
110
111 // Scale the parameters p1 and p2
112 amrex::ParticleReal rt2pi = std::sqrt(2.0_prt*pi);
113 amrex::ParticleReal p_scale = powi<-3>(r_scale*rt2pi);
114 m_p1 = m_p1*p_scale;
115 m_p2 = m_p2*p_scale;
116
117 // store integration parameters
118 m_nbins = nsteps;
119 m_rmin = rmin;
120 m_rmax = rmax;
121
122 // allocate CDFs
123 std::vector<amrex::ParticleReal> cdf1(m_nbins+1);
124 std::vector<amrex::ParticleReal> cdf2(m_nbins+1);
125 m_cdf1 = cdf1.data();
126 m_cdf2 = cdf2.data();
127
128 // set initial conditions
129 m_f1 = 0.0_prt;
130 m_f2 = 0.0_prt;
131 m_phi1 = 0.0_prt;
132 m_phi2 = 0.0_prt;
133 m_cdf1[0] = 0.0_prt;
134 m_cdf2[0] = 0.0_prt;
135
136 // integrate ODEs for the radial density
137 integrate(rmin,rmax,nsteps);
138
139 // a search over normalization parameters p1, p2 can be added here
140
141 // rescale cdf to ensure the exact range [0,1]
142 for (int n = 0; n < m_nbins; ++n) {
143 m_cdf1[n] = m_cdf1[n] / m_cdf1[m_nbins];
144 m_cdf2[n] = m_cdf2[n] / m_cdf2[m_nbins];
145 }
146
147 // copy CFD data to device
148 m_d_cdf1 = std::make_unique<amrex::Gpu::DeviceVector<amrex::ParticleReal>>(m_nbins+1);
149 m_d_cdf2 = std::make_unique<amrex::Gpu::DeviceVector<amrex::ParticleReal>>(m_nbins+1);
151 cdf1.begin(), cdf1.end(),
152 m_d_cdf1->begin());
154 cdf2.begin(), cdf2.end(),
155 m_d_cdf2->begin());
157 }
158
161 {
162 using namespace amrex::literals; // for _rt and _prt
163 using namespace ablastr::constant::math; // for pi
164
166 amrex::ParticleReal kT = (1_prt - m_w) * m_T1 + m_w * m_T2;
167 amrex::ParticleReal a = m_Cintensity/(4_prt*pi*5_prt*std::sqrt(5_prt));
168 amrex::ParticleReal rscale = std::sqrt(kT + std::pow(a*k,2_prt/3_prt))/k;
169
170 return rscale;
171 }
172
173 void
177 int steps
178 )
179 {
180 using namespace amrex::literals; // for _rt and _prt
181
182 // initialize numerical integration parameters
183 amrex::ParticleReal const tau = (out-in)/steps;
184 amrex::ParticleReal const half = tau*0.5_prt;
185
186 // initialize the value of the independent variable
187 amrex::ParticleReal reval = in;
188
189 // loop over integration steps
190 for (int j=0; j < steps; ++j)
191 {
192 // for a second-order Strang splitting
193 map1(half, reval);
194 map2(tau, reval);
195 map1(half, reval);
196 // store tabulated CDF
197 m_cdf1[j+1] = m_f1;
198 m_cdf2[j+1] = m_f2;
199 // write cumulative density to file for debugging
200 /* comment in for debugging
201 amrex::PrintToFile("density1.out") << reval << " " << data.f1 << "\n";
202 amrex::PrintToFile("density2.out") << reval << " " << data.f2 << "\n";
203 amrex::PrintToFile("phi1.out") << reval << " " << data.phi1 << "\n";
204 amrex::PrintToFile("phi2.out") << reval << " " << data.phi2 << "\n";
205 */
206 }
207
208 }
209
210 void
213 amrex::ParticleReal & reval
214 )
215 {
216 using namespace amrex::literals; // for _rt and _prt
217 using namespace ablastr::constant::math; // for pi
218
219 amrex::ParticleReal const f1 = m_f1;
220 amrex::ParticleReal const f2 = m_f2;
221 amrex::ParticleReal const phi1 = m_phi1;
222 amrex::ParticleReal const phi2 = m_phi2;
223 amrex::ParticleReal const r = reval;
224
225 // Apply map to update phi1, phi2, and r:
226 reval = r + tau;
227 m_phi1 = phi1 + f1/(4.0_prt*pi*reval) - f1/(4.0_prt*pi*r);
228 m_phi2 = phi2 + f2/(4.0_prt*pi*reval) - f2/(4.0_prt*pi*r);;
229 m_f1 = f1;
230 m_f2 = f2;
231 }
232
233 void
236 amrex::ParticleReal & reval
237 )
238 {
239 using namespace amrex::literals; // for _rt and _prt
240 using namespace ablastr::constant::math; // for pi
241
242 amrex::ParticleReal const f1 = m_f1;
243 amrex::ParticleReal const f2 = m_f2;
244 amrex::ParticleReal const phi1 = m_phi1;
245 amrex::ParticleReal const phi2 = m_phi2;
246 amrex::ParticleReal const r = reval;
247 amrex::ParticleReal const k = m_k;
248 amrex::ParticleReal const w = m_w;
249 amrex::ParticleReal const T1 = m_T1;
250 amrex::ParticleReal const T2 = m_T2;
251
252 // Define space charge intensity parameters
253 amrex::ParticleReal const c1 = (1_prt-w) * m_Cintensity;
254 amrex::ParticleReal const c2 = w * m_Cintensity;
255
256 // Define intermediate quantities
257 amrex::ParticleReal potential = 0_prt;
258 potential = std::pow(k*r,2)*0.5_prt + c1*phi1 + c2*phi2;
259 amrex::ParticleReal Pdensity1 = m_p1 * std::exp(-potential/T1);
260 amrex::ParticleReal Pdensity2 = m_p2 * std::exp(-potential/T2);
261 // amrex::ParticleReal Pdensity_tot = (1.0_prt-w)*Pdensity1 + w*Pdensity2;
262 // amrex::PrintToFile("Pdensity.out") << reval << " " << Pdensity_tot << "\n";
263
264 // Apply map to update f1 and f2:
265 m_phi1 = phi1;
266 m_phi2 = phi2;
267 m_f1 = f1 + tau*4_prt*pi * std::pow(r,2)*Pdensity1;
268 m_f2 = f2 + tau*4_prt*pi * std::pow(r,2)*Pdensity2;
269 reval = r;
270 }
271 };
272
273 struct Thermal
274 {
291 amrex::ParticleReal kT_halo,
292 amrex::ParticleReal normalize,
293 amrex::ParticleReal normalize_halo,
295 )
296 : m_k(k),
297 m_T1(kT),
298 m_T2(kT_halo),
299 m_normalize(normalize),
300 m_normalize_halo(normalize_halo),
301 m_halo(halo)
302 {
303 }
304
312 void initialize (amrex::ParticleReal bunch_charge, RefPart const & ref)
313 {
314 // Generate the struct "data" containing the radial CDF:
316 data.generate_radial_dist(bunch_charge, ref);
317
318 // share data
319 m_w = data.m_w;
320 m_T1 = data.m_T1;
321 m_T2 = data.m_T2;
322 m_rmin = data.m_rmin;
323 m_rmax = data.m_rmax;
324 m_nbins = data.m_nbins;
325 m_bg = data.m_bg;
326 m_cdf1 = data.m_d_cdf1->data();
327 m_cdf2 = data.m_d_cdf2->data();
328 }
329
332 void
334 {
335 // deallocate
336 ThermalData::m_d_cdf1.reset();
337 ThermalData::m_d_cdf2.reset();
338 }
339
358 amrex::RandomEngine const & engine
359 ) const
360 {
361
362 using namespace amrex::literals; // for _rt and _prt
363 using namespace ablastr::constant::math; // for pi
364
365 amrex::ParticleReal ln1,norm,u1,u2,uhalo;
366 amrex::ParticleReal g1,g2,g3,g4,g5,g6;
368
369 // Use a Bernoulli random variable to select between core and halo:
370 // If u < w, the particle is in the halo population.
371 // If u >= w, the particle is in the core population.
372 uhalo = amrex::Random(engine);
373
374 // Generate six standard normal random variables using Box-Muller:
375 u1 = amrex::Random(engine);
376 u2 = amrex::Random(engine);
377 ln1 = std::sqrt(-2_prt*std::log(u1));
378 g1 = ln1 * std::cos(2_prt*pi*u2);
379 g2 = ln1 * std::sin(2_prt*pi*u2);
380 u1 = amrex::Random(engine);
381 u2 = amrex::Random(engine);
382 ln1 = std::sqrt(-2_prt*std::log(u1));
383 g3 = ln1 * std::cos(2_prt*pi*u2);
384 g4 = ln1 * std::sin(2_prt*pi*u2);
385 u1 = amrex::Random(engine);
386 u2 = amrex::Random(engine);
387 ln1 = std::sqrt(-2_prt*std::log(u1));
388 g5 = ln1 * std::cos(2_prt*pi*u2);
389 g6 = ln1 * std::sin(2_prt*pi*u2);
390
391 // Scale the last three variables to produce the momenta:
392 amrex::ParticleReal kT = (uhalo > m_w) ? m_T1 : m_T2; // select core or halo value
393 px = std::sqrt(kT)*g4;
394 py = std::sqrt(kT)*g5;
395 pz = std::sqrt(kT)*g6;
396
397 // Normalize the first three variables to produce uniform samples on the unit 3-sphere:
398 norm = std::sqrt(g1*g1+g2*g2+g3*g3);
399 g1 /= norm;
400 g2 /= norm;
401 g3 /= norm;
402
403 // Collect the radial CDF returned by generate_radial_dist:
404
405 // select core or halo CDF
406 amrex::ParticleReal const * cdf = (uhalo > m_w) ? m_cdf1 : m_cdf2;
407
408 // Generate a radial coordinate from the CDF
410 amrex::ParticleReal const * ptr = amrex::lower_bound(cdf, cdf + m_nbins + 1, u);
411 int const off = amrex::max(0, int(ptr - cdf - 1));
412 amrex::ParticleReal tv = (u - cdf[off]) / (cdf[off + 1] - cdf[off]);
415
416 // Scale to produce samples with the correct radial density:
417 x = g1*r;
418 y = g2*r;
419 z = g3*r;
420
421 // Transform longitudinal variables into the laboratory frame:
422 t = -z / m_bg;
423 pt = -pz * m_bg;
424 }
425
435
436 private:
437 // radial profile data
438 amrex::ParticleReal const * m_cdf1 = nullptr;
439 amrex::ParticleReal const * m_cdf2 = nullptr;
440 };
441
442} // namespace distribution
443} // namespace impactx
444
445#endif // IMPACTX_DISTRIBUTION_THERMAL
#define AMREX_FORCE_INLINE
#define AMREX_RESTRICT
#define AMREX_GPU_HOST_DEVICE
amrex_particle_real ParticleReal
Real Random()
constexpr auto epsilon_0_v
void copyAsync(HostToDevice, InIter begin, InIter end, OutIter result) noexcept
static constexpr HostToDevice hostToDevice
void streamSynchronize() noexcept
constexpr T powi(T x) noexcept
__host__ __device__ T norm(const GpuComplex< T > &a_z) noexcept
__host__ __device__ ItType lower_bound(ItType first, ItType last, const ValType &val)
__host__ __device__ constexpr const T & max(const T &a, const T &b) noexcept
Definition All.H:28
Definition CovarianceMatrixMath.H:25
@ t
fixed t as the independent variable
Definition ImpactXParticleContainer.H:38
Definition ReferenceParticle.H:33
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal beta_gamma() const
Definition ReferenceParticle.H:168
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal mass_MeV() const
Definition ReferenceParticle.H:184
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal charge_qe() const
Definition ReferenceParticle.H:278
Definition Thermal.H:36
void generate_radial_dist(amrex::ParticleReal bunch_charge, RefPart const &refpart)
Definition Thermal.H:87
amrex::ParticleReal m_bg
reference value of relativistic beta*gamma
Definition Thermal.H:54
amrex::ParticleReal m_phi2
potential generated by second population
Definition Thermal.H:45
void map1(amrex::ParticleReal const tau, amrex::ParticleReal &reval)
Definition Thermal.H:211
amrex::ParticleReal m_phi1
potential generated by first population
Definition Thermal.H:44
ThermalData(amrex::ParticleReal kin, amrex::ParticleReal T1in, amrex::ParticleReal T2in, amrex::ParticleReal p1in, amrex::ParticleReal p2in, amrex::ParticleReal win)
Definition Thermal.H:64
amrex::ParticleReal m_f1
cumulative distribution of first population
Definition Thermal.H:42
void map2(amrex::ParticleReal const tau, amrex::ParticleReal &reval)
Definition Thermal.H:234
amrex::ParticleReal * m_cdf2
tabulated cumulative distribution (second)
Definition Thermal.H:52
amrex::ParticleReal * m_cdf1
tabulated cumulative distribution (first)
Definition Thermal.H:51
amrex::ParticleReal m_Cintensity
space charge intensity parameter
Definition Thermal.H:53
static std::unique_ptr< amrex::Gpu::DeviceVector< amrex::ParticleReal > > m_d_cdf2
Definition Thermal.H:62
amrex::ParticleReal m_rmin
minimum r value for tabulated cdf
Definition Thermal.H:48
static constexpr amrex::ParticleReal rin
initial r value for numerical integration
Definition Thermal.H:38
void integrate(amrex::ParticleReal in, amrex::ParticleReal out, int steps)
Definition Thermal.H:174
static std::unique_ptr< amrex::Gpu::DeviceVector< amrex::ParticleReal > > m_d_cdf1
Definition Thermal.H:61
amrex::ParticleReal m_rmax
maximum r value for tabulated cdf
Definition Thermal.H:49
static constexpr amrex::ParticleReal tolerance
tolerance for matching condition
Definition Thermal.H:37
static constexpr int nsteps
number of radial steps for numerical integration
Definition Thermal.H:40
amrex::ParticleReal matched_scale_radius()
Definition Thermal.H:160
amrex::ParticleReal m_k
linear focusing strength (1/meters)
Definition Thermal.H:55
amrex::ParticleReal m_f2
cumulative distribution of second population
Definition Thermal.H:43
amrex::ParticleReal m_p2
normalization constant of second population
Definition Thermal.H:47
int m_nbins
number of radial bins for tabulated cdf
Definition Thermal.H:50
amrex::ParticleReal m_p1
normalization constant of first population
Definition Thermal.H:46
amrex::ParticleReal m_T1
temperature k*T of the primary (core) population
Definition Thermal.H:56
static constexpr amrex::ParticleReal rout
final r value for numerical integration
Definition Thermal.H:39
amrex::ParticleReal m_T2
temperature k*T of the secondary (halo) population
Definition Thermal.H:57
amrex::ParticleReal m_w
weight of the secondary (halo) population
Definition Thermal.H:58
void finalize()
Definition Thermal.H:333
Thermal(amrex::ParticleReal k, amrex::ParticleReal kT, amrex::ParticleReal kT_halo, amrex::ParticleReal normalize, amrex::ParticleReal normalize_halo, amrex::ParticleReal halo)
Definition Thermal.H:288
amrex::ParticleReal m_bg
reference value of relativistic beta*gamma
Definition Thermal.H:433
int m_nbins
number of radial bins for tabulated cdf
Definition Thermal.H:432
amrex::ParticleReal m_T1
linear focusing strength (1/meters)
Definition Thermal.H:427
void initialize(amrex::ParticleReal bunch_charge, RefPart const &ref)
Definition Thermal.H:312
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void operator()(amrex::ParticleReal &AMREX_RESTRICT x, amrex::ParticleReal &AMREX_RESTRICT y, amrex::ParticleReal &AMREX_RESTRICT t, amrex::ParticleReal &AMREX_RESTRICT px, amrex::ParticleReal &AMREX_RESTRICT py, amrex::ParticleReal &AMREX_RESTRICT pt, amrex::RandomEngine const &engine) const
Definition Thermal.H:351
amrex::ParticleReal m_rmin
relative weight of halo population
Definition Thermal.H:430
amrex::ParticleReal m_normalize
temperature of each particle population
Definition Thermal.H:428
amrex::ParticleReal m_T2
Definition Thermal.H:427
amrex::ParticleReal m_w
weight of the secondary (halo) population
Definition Thermal.H:434
amrex::ParticleReal const * m_cdf1
Definition Thermal.H:438
amrex::ParticleReal m_halo
normalization constant of first/second population
Definition Thermal.H:429
amrex::ParticleReal const * m_cdf2
non-owning pointer to device core CDF
Definition Thermal.H:439
amrex::ParticleReal m_rmax
maximum r value for tabulated cdf
Definition Thermal.H:431
amrex::ParticleReal m_normalize_halo
Definition Thermal.H:428
amrex::ParticleReal m_k
Definition Thermal.H:426