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