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{
35 using namespace amrex::literals; // for _rt and _prt at class scope
36
38 {
39 static constexpr amrex::ParticleReal tolerance = 1.0e-3_prt;
40 static constexpr amrex::ParticleReal rin = 1.0e-10_prt;
41 static constexpr amrex::ParticleReal rout = 10.0;
42 static constexpr int nsteps = 2000;
43
52 int m_nbins;
61
62 // GPU data
63 static inline std::unique_ptr<amrex::Gpu::DeviceVector<amrex::ParticleReal>> m_d_cdf1;
64 static inline std::unique_ptr<amrex::Gpu::DeviceVector<amrex::ParticleReal>> m_d_cdf2;
65
73 )
74 {
75 m_k = kin;
76 m_T1 = T1in;
77 m_T2 = T2in;
78 m_p1 = p1in;
79 m_p2 = p2in;
80 m_w = win;
81 }
82
88 void
89 generate_radial_dist (amrex::ParticleReal bunch_charge, RefPart const & refpart)
90 {
91 using namespace amrex::literals; // for _rt and _prt
92 using namespace ablastr::constant::math; // for pi
95
96 // Get relativistic beta*gamma
97 amrex::ParticleReal bg = refpart.beta_gamma();
98 m_bg = bg;
99
100 // Get reference particle rest energy (eV) and charge (q_e)
101 amrex::ParticleReal Erest = refpart.mass_MeV() * 1.0e6_prt;
102 amrex::ParticleReal q_e = refpart.charge_qe();
103
104 // Set space charge intensity
105 m_Cintensity = q_e*bunch_charge/(powi<2>(bg)*Erest*ep0);
106
107 // Set minimum and maximum radius
109 amrex::ParticleReal rmin = rin*r_scale;
110 amrex::ParticleReal rmax = rout*r_scale;
111 // amrex::PrintToFile("equilibrium_params.out") << r_scale << " " << data.Cintensity << "\n";
112
113 // Scale the parameters p1 and p2
114 amrex::ParticleReal rt2pi = std::sqrt(2.0_prt*pi);
115 amrex::ParticleReal p_scale = powi<-3>(r_scale*rt2pi);
116 m_p1 = m_p1*p_scale;
117 m_p2 = m_p2*p_scale;
118
119 // store integration parameters
120 m_nbins = nsteps;
121 m_rmin = rmin;
122 m_rmax = rmax;
123
124 // allocate CDFs
125 std::vector<amrex::ParticleReal> cdf1(m_nbins+1);
126 std::vector<amrex::ParticleReal> cdf2(m_nbins+1);
127 m_cdf1 = cdf1.data();
128 m_cdf2 = cdf2.data();
129
130 // set initial conditions
131 m_f1 = 0.0_prt;
132 m_f2 = 0.0_prt;
133 m_phi1 = 0.0_prt;
134 m_phi2 = 0.0_prt;
135 m_cdf1[0] = 0.0_prt;
136 m_cdf2[0] = 0.0_prt;
137
138 // integrate ODEs for the radial density
139 integrate(rmin,rmax,nsteps);
140
141 // a search over normalization parameters p1, p2 can be added here
142
143 // rescale cdf to ensure the exact range [0,1]
144 for (int n = 0; n < m_nbins; ++n) {
145 m_cdf1[n] = m_cdf1[n] / m_cdf1[m_nbins];
146 m_cdf2[n] = m_cdf2[n] / m_cdf2[m_nbins];
147 }
148
149 // copy CFD data to device
150 m_d_cdf1 = std::make_unique<amrex::Gpu::DeviceVector<amrex::ParticleReal>>(m_nbins+1);
151 m_d_cdf2 = std::make_unique<amrex::Gpu::DeviceVector<amrex::ParticleReal>>(m_nbins+1);
153 cdf1.begin(), cdf1.end(),
154 m_d_cdf1->begin());
156 cdf2.begin(), cdf2.end(),
157 m_d_cdf2->begin());
159 }
160
163 {
164 using namespace amrex::literals; // for _rt and _prt
165 using namespace ablastr::constant::math; // for pi
166
168 amrex::ParticleReal kT = (1_prt - m_w) * m_T1 + m_w * m_T2;
169 amrex::ParticleReal a = m_Cintensity/(4_prt*pi*5_prt*std::sqrt(5_prt));
170 amrex::ParticleReal rscale = std::sqrt(kT + std::pow(a*k,2_prt/3_prt))/k;
171
172 return rscale;
173 }
174
175 void
179 int steps
180 )
181 {
182 using namespace amrex::literals; // for _rt and _prt
183
184 // initialize numerical integration parameters
185 amrex::ParticleReal const tau = (out-in)/steps;
186 amrex::ParticleReal const half = tau*0.5_prt;
187
188 // initialize the value of the independent variable
189 amrex::ParticleReal reval = in;
190
191 // loop over integration steps
192 for (int j=0; j < steps; ++j)
193 {
194 // for a second-order Strang splitting
195 map1(half, reval);
196 map2(tau, reval);
197 map1(half, reval);
198 // store tabulated CDF
199 m_cdf1[j+1] = m_f1;
200 m_cdf2[j+1] = m_f2;
201 // write cumulative density to file for debugging
202 /* comment in for debugging
203 amrex::PrintToFile("density1.out") << reval << " " << data.f1 << "\n";
204 amrex::PrintToFile("density2.out") << reval << " " << data.f2 << "\n";
205 amrex::PrintToFile("phi1.out") << reval << " " << data.phi1 << "\n";
206 amrex::PrintToFile("phi2.out") << reval << " " << data.phi2 << "\n";
207 */
208 }
209
210 }
211
212 void
215 amrex::ParticleReal & reval
216 )
217 {
218 using namespace amrex::literals; // for _rt and _prt
219 using namespace ablastr::constant::math; // for pi
220
221 amrex::ParticleReal const f1 = m_f1;
222 amrex::ParticleReal const f2 = m_f2;
223 amrex::ParticleReal const phi1 = m_phi1;
224 amrex::ParticleReal const phi2 = m_phi2;
225 amrex::ParticleReal const r = reval;
226
227 // Apply map to update phi1, phi2, and r:
228 reval = r + tau;
229 m_phi1 = phi1 + f1/(4.0_prt*pi*reval) - f1/(4.0_prt*pi*r);
230 m_phi2 = phi2 + f2/(4.0_prt*pi*reval) - f2/(4.0_prt*pi*r);;
231 m_f1 = f1;
232 m_f2 = f2;
233 }
234
235 void
238 amrex::ParticleReal & reval
239 )
240 {
241 using namespace amrex::literals; // for _rt and _prt
242 using namespace ablastr::constant::math; // for pi
243
244 amrex::ParticleReal const f1 = m_f1;
245 amrex::ParticleReal const f2 = m_f2;
246 amrex::ParticleReal const phi1 = m_phi1;
247 amrex::ParticleReal const phi2 = m_phi2;
248 amrex::ParticleReal const r = reval;
249 amrex::ParticleReal const k = m_k;
250 amrex::ParticleReal const w = m_w;
251 amrex::ParticleReal const T1 = m_T1;
252 amrex::ParticleReal const T2 = m_T2;
253
254 // Define space charge intensity parameters
255 amrex::ParticleReal const c1 = (1_prt-w) * m_Cintensity;
256 amrex::ParticleReal const c2 = w * m_Cintensity;
257
258 // Define intermediate quantities
259 amrex::ParticleReal potential = 0_prt;
260 potential = amrex::Math::powi<2>(k*r)*0.5_prt + c1*phi1 + c2*phi2;
261 amrex::ParticleReal Pdensity1 = m_p1 * std::exp(-potential/T1);
262 amrex::ParticleReal Pdensity2 = m_p2 * std::exp(-potential/T2);
263 // amrex::ParticleReal Pdensity_tot = (1.0_prt-w)*Pdensity1 + w*Pdensity2;
264 // amrex::PrintToFile("Pdensity.out") << reval << " " << Pdensity_tot << "\n";
265
266 // Apply map to update f1 and f2:
267 m_phi1 = phi1;
268 m_phi2 = phi2;
269 m_f1 = f1 + tau*4_prt*pi * amrex::Math::powi<2>(r)*Pdensity1;
270 m_f2 = f2 + tau*4_prt*pi * amrex::Math::powi<2>(r)*Pdensity2;
271 reval = r;
272 }
273 };
274
275 struct Thermal
276 {
293 amrex::ParticleReal kT_halo,
294 amrex::ParticleReal normalize,
295 amrex::ParticleReal normalize_halo,
297 )
298 : m_k(k),
299 m_T1(kT),
300 m_T2(kT_halo),
301 m_normalize(normalize),
302 m_normalize_halo(normalize_halo),
303 m_halo(halo)
304 {
305 }
306
314 void initialize (amrex::ParticleReal bunch_charge, RefPart const & ref)
315 {
316 // Generate the struct "data" containing the radial CDF:
318 data.generate_radial_dist(bunch_charge, ref);
319
320 // share data
321 m_w = data.m_w;
322 m_T1 = data.m_T1;
323 m_T2 = data.m_T2;
324 m_rmin = data.m_rmin;
325 m_rmax = data.m_rmax;
326 m_nbins = data.m_nbins;
327 m_bg = data.m_bg;
328 m_cdf1 = data.m_d_cdf1->data();
329 m_cdf2 = data.m_d_cdf2->data();
330 }
331
334 void
336 {
337 // deallocate
338 ThermalData::m_d_cdf1.reset();
339 ThermalData::m_d_cdf2.reset();
340 }
341
360 amrex::RandomEngine const & engine
361 ) const
362 {
363
364 using namespace amrex::literals; // for _rt and _prt
365 using namespace ablastr::constant::math; // for pi
366
367 amrex::ParticleReal ln1,norm,u1,u2,uhalo;
368 amrex::ParticleReal g1,g2,g3,g4,g5,g6;
370
371 // Use a Bernoulli random variable to select between core and halo:
372 // If u < w, the particle is in the halo population.
373 // If u >= w, the particle is in the core population.
374 uhalo = amrex::Random(engine);
375
376 // Generate six standard normal random variables using Box-Muller:
377 u1 = amrex::Random(engine);
378 u2 = amrex::Random(engine);
379 ln1 = std::sqrt(-2_prt*std::log(u1));
380 g1 = ln1 * std::cos(2_prt*pi*u2);
381 g2 = ln1 * std::sin(2_prt*pi*u2);
382 u1 = amrex::Random(engine);
383 u2 = amrex::Random(engine);
384 ln1 = std::sqrt(-2_prt*std::log(u1));
385 g3 = ln1 * std::cos(2_prt*pi*u2);
386 g4 = ln1 * std::sin(2_prt*pi*u2);
387 u1 = amrex::Random(engine);
388 u2 = amrex::Random(engine);
389 ln1 = std::sqrt(-2_prt*std::log(u1));
390 g5 = ln1 * std::cos(2_prt*pi*u2);
391 g6 = ln1 * std::sin(2_prt*pi*u2);
392
393 // Scale the last three variables to produce the momenta:
394 amrex::ParticleReal kT = (uhalo > m_w) ? m_T1 : m_T2; // select core or halo value
395 px = std::sqrt(kT)*g4;
396 py = std::sqrt(kT)*g5;
397 pz = std::sqrt(kT)*g6;
398
399 // Normalize the first three variables to produce uniform samples on the unit 3-sphere:
400 norm = std::sqrt(g1*g1+g2*g2+g3*g3);
401 g1 /= norm;
402 g2 /= norm;
403 g3 /= norm;
404
405 // Collect the radial CDF returned by generate_radial_dist:
406
407 // select core or halo CDF
408 amrex::ParticleReal const * cdf = (uhalo > m_w) ? m_cdf1 : m_cdf2;
409
410 // Generate a radial coordinate from the CDF
412 amrex::ParticleReal const * ptr = amrex::lower_bound(cdf, cdf + m_nbins + 1, u);
413 int const off = amrex::max(0, int(ptr - cdf - 1));
414 amrex::ParticleReal tv = (u - cdf[off]) / (cdf[off + 1] - cdf[off]);
417
418 // Scale to produce samples with the correct radial density:
419 x = g1*r;
420 y = g2*r;
421 z = g3*r;
422
423 // Transform longitudinal variables into the laboratory frame:
424 t = -z / m_bg;
425 pt = -pz * m_bg;
426 }
427
437
438 private:
439 // radial profile data
440 amrex::ParticleReal const * m_cdf1 = nullptr;
441 amrex::ParticleReal const * m_cdf2 = nullptr;
442 };
443
444} // namespace distribution
445} // namespace impactx
446
447#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:167
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal mass_MeV() const
Definition ReferenceParticle.H:183
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::ParticleReal charge_qe() const
Definition ReferenceParticle.H:277
Definition Thermal.H:38
void generate_radial_dist(amrex::ParticleReal bunch_charge, RefPart const &refpart)
Definition Thermal.H:89
amrex::ParticleReal m_bg
reference value of relativistic beta*gamma
Definition Thermal.H:56
amrex::ParticleReal m_phi2
potential generated by second population
Definition Thermal.H:47
void map1(amrex::ParticleReal const tau, amrex::ParticleReal &reval)
Definition Thermal.H:213
amrex::ParticleReal m_phi1
potential generated by first population
Definition Thermal.H:46
ThermalData(amrex::ParticleReal kin, amrex::ParticleReal T1in, amrex::ParticleReal T2in, amrex::ParticleReal p1in, amrex::ParticleReal p2in, amrex::ParticleReal win)
Definition Thermal.H:66
amrex::ParticleReal m_f1
cumulative distribution of first population
Definition Thermal.H:44
void map2(amrex::ParticleReal const tau, amrex::ParticleReal &reval)
Definition Thermal.H:236
amrex::ParticleReal * m_cdf2
tabulated cumulative distribution (second)
Definition Thermal.H:54
amrex::ParticleReal * m_cdf1
tabulated cumulative distribution (first)
Definition Thermal.H:53
amrex::ParticleReal m_Cintensity
space charge intensity parameter
Definition Thermal.H:55
static std::unique_ptr< amrex::Gpu::DeviceVector< amrex::ParticleReal > > m_d_cdf2
Definition Thermal.H:64
amrex::ParticleReal m_rmin
minimum r value for tabulated cdf
Definition Thermal.H:50
static constexpr amrex::ParticleReal rin
initial r value for numerical integration
Definition Thermal.H:40
void integrate(amrex::ParticleReal in, amrex::ParticleReal out, int steps)
Definition Thermal.H:176
static std::unique_ptr< amrex::Gpu::DeviceVector< amrex::ParticleReal > > m_d_cdf1
Definition Thermal.H:63
amrex::ParticleReal m_rmax
maximum r value for tabulated cdf
Definition Thermal.H:51
static constexpr amrex::ParticleReal tolerance
tolerance for matching condition
Definition Thermal.H:39
static constexpr int nsteps
number of radial steps for numerical integration
Definition Thermal.H:42
amrex::ParticleReal matched_scale_radius()
Definition Thermal.H:162
amrex::ParticleReal m_k
linear focusing strength (1/meters)
Definition Thermal.H:57
amrex::ParticleReal m_f2
cumulative distribution of second population
Definition Thermal.H:45
amrex::ParticleReal m_p2
normalization constant of second population
Definition Thermal.H:49
int m_nbins
number of radial bins for tabulated cdf
Definition Thermal.H:52
amrex::ParticleReal m_p1
normalization constant of first population
Definition Thermal.H:48
amrex::ParticleReal m_T1
temperature k*T of the primary (core) population
Definition Thermal.H:58
static constexpr amrex::ParticleReal rout
final r value for numerical integration
Definition Thermal.H:41
amrex::ParticleReal m_T2
temperature k*T of the secondary (halo) population
Definition Thermal.H:59
amrex::ParticleReal m_w
weight of the secondary (halo) population
Definition Thermal.H:60
void finalize()
Definition Thermal.H:335
Thermal(amrex::ParticleReal k, amrex::ParticleReal kT, amrex::ParticleReal kT_halo, amrex::ParticleReal normalize, amrex::ParticleReal normalize_halo, amrex::ParticleReal halo)
Definition Thermal.H:290
amrex::ParticleReal m_bg
reference value of relativistic beta*gamma
Definition Thermal.H:435
int m_nbins
number of radial bins for tabulated cdf
Definition Thermal.H:434
amrex::ParticleReal m_T1
linear focusing strength (1/meters)
Definition Thermal.H:429
void initialize(amrex::ParticleReal bunch_charge, RefPart const &ref)
Definition Thermal.H:314
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:353
amrex::ParticleReal m_rmin
relative weight of halo population
Definition Thermal.H:432
amrex::ParticleReal m_normalize
temperature of each particle population
Definition Thermal.H:430
amrex::ParticleReal m_T2
Definition Thermal.H:429
amrex::ParticleReal m_w
weight of the secondary (halo) population
Definition Thermal.H:436
amrex::ParticleReal const * m_cdf1
Definition Thermal.H:440
amrex::ParticleReal m_halo
normalization constant of first/second population
Definition Thermal.H:431
amrex::ParticleReal const * m_cdf2
non-owning pointer to device core CDF
Definition Thermal.H:441
amrex::ParticleReal m_rmax
maximum r value for tabulated cdf
Definition Thermal.H:433
amrex::ParticleReal m_normalize_halo
Definition Thermal.H:430
amrex::ParticleReal m_k
Definition Thermal.H:428