ImpactX
Loading...
Searching...
No Matches
HandleWakefield.H
Go to the documentation of this file.
1/* Copyright 2022-2026 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: Alex Bojanich, Chad Mitchell, Axel Huebl
8 * License: BSD-3-Clause-LBNL
9 */
10#ifndef HANDLE_WAKEFIELD_H
11#define HANDLE_WAKEFIELD_H
12
14#include "ChargeBinning.H"
15#include "CSRBendElement.H"
16#include "WakeConvolution.H"
17#include "WakePush.H"
18
19#include <AMReX_GpuContainers.H>
20#include <AMReX_GpuDevice.H>
22
23#include <cmath>
24#include <stdexcept>
25#include <vector>
26
27
29{
40 template <typename T_Element>
42 impactx::ImpactXParticleContainer& particle_container,
43 T_Element const& element_variant,
44 amrex::Real slice_ds,
45 bool print_wakefield = false
46 )
47 {
48 if (slice_ds == 0.0) { return; }
49
50 BL_PROFILE("impactx::particles::wakefields::HandleWakefield")
51
52 amrex::ParmParse pp_algo("algo");
53 bool csr = false;
54 pp_algo.queryAdd("csr", csr);
55
56 // Call the CSR bend function
57 auto const [element_has_csr, R] = impactx::particles::wakefields::CSRBendElement(element_variant, particle_container.GetRefParticle());
58
59 // Enter loop if lattice has bend element
60 if (csr && element_has_csr)
61 {
62#ifndef ImpactX_USE_FFT
63 throw std::runtime_error("algo.csr was requested but ImpactX was not compiled with FFT support. Recompile with ImpactX_FFT=ON.");
64#endif
65
66 int csr_bins = 150;
67 pp_algo.queryAddWithParser("csr_bins", csr_bins);
68
69 // Measure beam size, extract the min, max of particle positions
70 [[maybe_unused]] auto const [x_min, y_min, t_min, x_max, y_max, t_max] =
71 particle_container.MinAndMaxPositions();
72
73 // Ensure we have a beam with a finite extent in t
74 if (t_min == t_max)
75 {
76 auto const npart = particle_container.TotalNumberOfParticles();
77 std::string error_msg = "Coherent Synchrotron Radiation (CSR) "
78 "modeling was enabled, but ";
79 if (npart == 1) {
80 error_msg.append("there is only one particle in the beam. ");
81 } else {
82 error_msg.append("the beam is flat in t. ");
83 }
84 error_msg.append(
85 "CSR modeling is a collective effect and requires "
86 "a particle beam with a finite extent in t. "
87 "Please set the CSR option to false."
88 );
89 throw std::runtime_error(error_msg);
90 }
91
92 // Set parameters for charge deposition
93 bool const is_unity_particle_weight = false; // Only true if w = 1
94 bool const GetNumberDensity = true;
95
96 int const num_bins = csr_bins; // Set resolution
97 amrex::Real const bin_min = t_min;
98 amrex::Real const bin_max = t_max;
99 amrex::Real const bin_size = (bin_max - bin_min) / (num_bins - 1); // number of evaluation points
100
101 // Allocate memory for the charge profile
102 amrex::Gpu::DeviceVector<amrex::Real> charge_distribution(num_bins + 1, 0.0);
103 amrex::Gpu::DeviceVector<amrex::Real> mean_x(num_bins, 0.0);
104 amrex::Gpu::DeviceVector<amrex::Real> mean_y(num_bins, 0.0);
105
106 // Call charge deposition function
107 impactx::particles::wakefields::DepositCharge1D(particle_container, charge_distribution, bin_min, bin_size, is_unity_particle_weight);
108
109 // Sum up all partial charge histograms to one MPI process to calculate the global wakefield.
110 // Once calculated, we will distribute convolved_wakefield back to every MPI process.
112 charge_distribution,
115 );
116
117 // Pre-size on every rank to the (global) wake length. On the IO
118 // processor this is overwritten by the convolution result of the
119 // same length.
120 amrex::Gpu::DeviceVector<amrex::Real> convolved_wakefield(num_bins, 0.0);
122 // Call the mean transverse position function
123 impactx::particles::wakefields::MeanTransversePosition(particle_container, mean_x, mean_y, bin_min,
124 bin_size, is_unity_particle_weight);
125
126 // Call charge density derivative function
127 amrex::Gpu::DeviceVector<amrex::Real> slopes(charge_distribution.size() - 1, 0.0);
128 impactx::particles::wakefields::DerivativeCharge1D(charge_distribution, slopes, bin_size,
129 GetNumberDensity); // Use number derivatives for convolution with CSR
130
131 // Construct CSR wake function on 2N support
132 amrex::Gpu::DeviceVector<amrex::Real> wake_function(num_bins*2, 0.0);
133 amrex::Real *const dptr_wake_function = wake_function.data();
134 auto const dR = R; // for NVCC capture
135 amrex::ParallelFor(num_bins*2, [=] AMREX_GPU_DEVICE(int i) {
136 if (i < num_bins) {
137 amrex::Real const s = static_cast<amrex::Real>(i) * bin_size;
138 dptr_wake_function[i] = impactx::particles::wakefields::w_l_csr(s, dR, bin_size);
139 }
140 else if (i > num_bins) {
141 amrex::Real const s = static_cast<amrex::Real>(i - 2*num_bins) * bin_size;
142 dptr_wake_function[i] = impactx::particles::wakefields::w_l_csr(s, dR, bin_size);
143 }
144 });
145
146 // Call convolution function
147 convolved_wakefield = impactx::particles::wakefields::convolve_fft(slopes, wake_function, bin_size);
148 }
149
150 // Broadcast the global wakefield from the IO processor (which alone
151 // computed it) to every MPI rank. Receivers are pre-sized above.
153 convolved_wakefield,
156 );
157
158 // Check convolution output
159 if (print_wakefield && amrex::ParallelDescriptor::IOProcessor())
160 {
161 // convolved_wakefield is in (non-managed) device memory. Copy it
162 // to the host before iterating it on the host for printing.
163 amrex::Gpu::HostVector<amrex::Real> h_wakefield(convolved_wakefield.size());
164 amrex::Gpu::dtoh_memcpy(h_wakefield.data(), convolved_wakefield.data(),
165 convolved_wakefield.size() * sizeof(amrex::Real));
166 std::cout << "Convolved wakefield: ";
167 std::ofstream outfile("convolved_wakefield.txt");
168 for (amrex::Real const val : h_wakefield) {
169 std::cout << val << " ";
170 outfile << val << "\n";
171 }
172 std::cout << "\n";
173 outfile.close();
174 }
175
176 // Call function to kick particles with wake
177 impactx::particles::wakefields::WakePush(particle_container, convolved_wakefield, slice_ds, bin_size, t_min);
178 }
179 }
180
181} // namespace impactx::particles::wakefields
182
183#endif // HANDLE_WAKEFIELD_H
#define BL_PROFILE(a)
#define AMREX_GPU_DEVICE
size_type size() const noexcept
T * data() noexcept
int queryAdd(std::string_view name, T &ref)
int queryAddWithParser(std::string_view name, T &ref)
Long TotalNumberOfParticles(bool only_valid=true, bool only_local=false) const
Definition ImpactXParticleContainer.H:136
std::tuple< amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal, amrex::ParticleReal > MinAndMaxPositions()
Definition ImpactXParticleContainer.cpp:440
RefPart & GetRefParticle()
Definition ImpactXParticleContainer.cpp:419
amrex_real Real
PinnedVector< T > HostVector
PODVector< T, ArenaAllocator< T > > DeviceVector
void Bcast(Gpu::DeviceVector< T > &v, int root, MPI_Comm comm)
int IOProcessorNumber() noexcept
bool IOProcessor() noexcept
void Sum(Gpu::DeviceVector< T > &v, int root, MPI_Comm comm)
void dtoh_memcpy(void *p_h, const void *p_d, const std::size_t sz) noexcept
MPI_Comm Communicator() noexcept
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition ChargeBinning.cpp:17
void DerivativeCharge1D(amrex::Gpu::DeviceVector< amrex::Real > const &charge_distribution, amrex::Gpu::DeviceVector< amrex::Real > &slopes, amrex::Real bin_size, bool GetNumberDensity)
Definition ChargeBinning.cpp:87
void HandleWakefield(impactx::ImpactXParticleContainer &particle_container, T_Element const &element_variant, amrex::Real slice_ds, bool print_wakefield=false)
Definition HandleWakefield.H:41
void DepositCharge1D(impactx::ImpactXParticleContainer &myspc, amrex::Gpu::DeviceVector< amrex::Real > &charge_distribution, amrex::Real bin_min, amrex::Real bin_size, bool is_unity_particle_weight)
Definition ChargeBinning.cpp:18
void MeanTransversePosition(impactx::ImpactXParticleContainer &myspc, amrex::Gpu::DeviceVector< amrex::Real > &mean_x, amrex::Gpu::DeviceVector< amrex::Real > &mean_y, amrex::Real bin_min, amrex::Real bin_size, bool is_unity_particle_weight)
Definition ChargeBinning.cpp:115
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real w_l_csr(amrex::Real s, amrex::Real R, amrex::Real const bin_size)
Definition WakeConvolution.H:106
std::tuple< bool, amrex::Real > CSRBendElement(VariantType const &element_variant, RefPart const &refpart)
Definition CSRBendElement.H:35
amrex::Gpu::DeviceVector< amrex::Real > convolve_fft(amrex::Gpu::DeviceVector< amrex::Real > const &beam_profile_slope, amrex::Gpu::DeviceVector< amrex::Real > const &wake_func, amrex::Real delta_t)
Definition WakeConvolution.cpp:66
void WakePush(ImpactXParticleContainer &pc, amrex::Gpu::DeviceVector< amrex::Real > const &convolved_wakefield, amrex::ParticleReal slice_ds, amrex::Real bin_size, amrex::Real bin_min)
Definition WakePush.cpp:21
@ s
fixed s as the independent variable
Definition ImpactXParticleContainer.H:37