3#include <Kokkos_Core.hpp>
14 std::shared_ptr<ParticleContainer_t> pc, std::shared_ptr<FieldContainer_t> fc,
18 for (
unsigned int i = 0; i < 6; i++) {
19 for (
unsigned int j = 0; j < 6; j++) {
44 for (
unsigned int i = 0; i < 6; i++) {
45 for (
unsigned int j = 0; j < 6; j++) {
47 if (i == j && i % 2 == 0) {
48 cov_m[i][j] = sigmaR[i / 2] * sigmaR[i / 2];
50 if (i == j && i % 2 == 1) {
51 cov_m[i][j] = sigmaP[i / 2] * sigmaP[i / 2];
78 ippl::Vector<double, 3>(
79 Kokkos::sqrt(
cov_m[0][0]), Kokkos::sqrt(
cov_m[2][2]),
80 Kokkos::sqrt(
cov_m[4][4])));
83 ippl::Vector<double, 3>(
84 Kokkos::sqrt(
cov_m[1][1]), Kokkos::sqrt(
cov_m[3][3]),
85 Kokkos::sqrt(
cov_m[5][5])));
104 *
gmsg <<
"* Seed = " << randInit <<
" on all ranks" << endl;
106 randInit =
static_cast<size_t>(
Options::seed + 100 * ippl::Comm->rank());
118 for (
unsigned int i = 0; i < 6; i++) {
119 for (
unsigned int j = 0; j < 6; j++) {
124 for (
unsigned int i = 0; i < 6; i++) {
125 for (
unsigned int j = 0; j <= i; j++) {
127 for (
unsigned int k = 0; k < j; k++) {
128 sum +=
L_m[i][k] *
L_m[j][k];
131 L_m[j][j] = Kokkos::sqrt(
cov_m[j][j] - sum);
148 for (
int i = 0; i < 3; i++) {
162 double sumMin, sumMax;
163 for (
int i = 0; i < 6; i++) {
166 for (
int j = 0; j < i; j++) {
174 for (
int i = 0; i < 3; i++) {
194 "MultiVariateGaussian::generateParticles",
196 +
"' is not supported for MULTIVARIATEGAUSS distributions");
213 const double par[6] = {0.0, 1.0, 0.0, 1.0, 0.0, 1.0};
214 using Dist_t = ippl::random::NormalDistribution<double, 3>;
215 using sampling_t = ippl::random::InverseTransformSampling<
216 double, 3, Kokkos::DefaultExecutionSpace,
Dist_t>;
219 const int nranks = std::max(1, ippl::Comm->size());
222 :
static_cast<size_t>(
223 floor(numberOfParticles / nranks)
224 + (ippl::Comm->rank() <
static_cast<int>(
225 numberOfParticles %
static_cast<size_t>(nranks))
231 const size_t nlocalCurrent =
pc_m->getLocalNum();
232 pc_m->createParticles(nlocal);
237 auto Rview = Kokkos::subview(RviewFull, std::make_pair(nlocalCurrent, nlocalCurrent + nlocal));
238 auto Pview = Kokkos::subview(PviewFull, std::make_pair(nlocalCurrent, nlocalCurrent + nlocal));
240 sampling.generate(Rview, rand_pool64);
243 sampling.generate(Pview, rand_pool64);
246 for (
unsigned int i = 0; i < 6; i++) {
247 for (
unsigned int j = 0; j < 6; j++) {
253 Kokkos::parallel_for(
254 nlocal, KOKKOS_LAMBDA(
const size_t k) {
255 double vec_old[6], vec[6] = {0.0};
256 for (
unsigned i = 0; i < 3; ++i) {
257 vec_old[2 * i] = Rview(k)[i];
258 vec_old[2 * i + 1] = Pview(k)[i];
260 for (
unsigned i = 0; i < 6; ++i) {
261 for (
unsigned j = 0; j < i + 1; ++j) {
262 vec[i] += L[i][j] * vec_old[j];
265 for (
unsigned i = 0; i < 3; ++i) {
266 Rview(k)[i] = vec[2 * i];
267 Pview(k)[i] = vec[2 * i + 1];
274 double meanR[3], loc_meanR[3];
277 for (
size_t i = 0; i < 3; i++) {
282 Kokkos::parallel_reduce(
283 "calc moments of particle distr.", nlocal,
284 KOKKOS_LAMBDA(
const size_t k,
double& cent0,
double& cent1,
double& cent2) {
285 cent0 += Rview(k)[0];
286 cent1 += Rview(k)[1];
287 cent2 += Rview(k)[2];
289 Kokkos::Sum<double>(loc_meanR[0]), Kokkos::Sum<double>(loc_meanR[1]),
290 Kokkos::Sum<double>(loc_meanR[2]));
293 MPI_Allreduce(loc_meanR, meanR, 3, MPI_DOUBLE, MPI_SUM, ippl::Comm->getCommunicator());
294 ippl::Comm->barrier();
296 for (
size_t i = 0; i < 3; i++) {
297 meanR[i] = meanR[i] / (1. * numberOfParticles);
300 Kokkos::parallel_for(
301 nlocal, KOKKOS_LAMBDA(
const size_t k) {
302 Rview(k)[0] -= meanR[0];
303 Rview(k)[1] -= meanR[1];
304 Rview(k)[2] -= meanR[2];
310 double meanP[3], loc_meanP[3];
312 for (
size_t i = 0; i < 3; i++) {
316 Kokkos::parallel_reduce(
317 "calc moments of particle distr.", nlocal,
318 KOKKOS_LAMBDA(
const size_t k,
double& cent0,
double& cent1,
double& cent2) {
319 cent0 += Pview(k)[0];
320 cent1 += Pview(k)[1];
321 cent2 += Pview(k)[2];
323 Kokkos::Sum<double>(loc_meanP[0]), Kokkos::Sum<double>(loc_meanP[1]),
324 Kokkos::Sum<double>(loc_meanP[2]));
327 MPI_Allreduce(loc_meanP, meanP, 3, MPI_DOUBLE, MPI_SUM, ippl::Comm->getCommunicator());
328 ippl::Comm->barrier();
330 for (
size_t i = 0; i < 3; i++) {
331 meanP[i] = meanP[i] / (1. * numberOfParticles);
334 Kokkos::parallel_for(
335 nlocal, KOKKOS_LAMBDA(
const size_t k) {
336 Pview(k)[0] -= meanP[0];
337 Pview(k)[1] -= meanP[1];
338 Pview(k)[2] -= meanP[2];
344 for (
size_t i = 0; i < 3; i++) {
349 Kokkos::parallel_for(
350 nlocal, KOKKOS_LAMBDA(
const size_t k) {
351 for (
size_t i = 0; i < 3; i++) {
352 Rview(k)[i] += meanR[i];
353 Pview(k)[i] += meanP[i];
363 Kokkos::parallel_for(
364 nlocal, KOKKOS_LAMBDA(
const size_t k) {
371 pc_m->markMomentsDirty();
378 const double tStart = t;
379 const double tEnd = t + dt;
389 if (!(tStart <=
t0_m &&
t0_m < tEnd)) {
401 const size_t nlocalBefore =
pc_m->getLocalNum();
407 const size_t nlocalAfter =
pc_m->getLocalNum();
408 const size_t nNew = nlocalAfter - nlocalBefore;
410 const double fracDt = tEnd -
t0_m;
411 auto dtview =
pc_m->dt.getView();
412 const size_t offset = nlocalBefore;
413 Kokkos::parallel_for(
414 "MultiVariateGaussian_setDt", nNew,
415 KOKKOS_LAMBDA(
const size_t j) { dtview(offset + j) = fracDt; });
ippl::Vector< T, Dim > Vector_t
typename ippl::detail::ViewType< ippl::Vector< double, Dim >, 1 >::view_type view_type
ippl::Vector< ippl::Vector< double, 6 >, 6 > Matrix_t
typename Kokkos::Random_XorShift64_Pool<> GeneratorPool
ippl::random::NormalDistribution< double, 3 > Dist_t
ippl::Vector< double, 3 > getCutoffP() const
size_t getNumParticles() const
ippl::Vector< double, 3 > getSigmaP() const
ippl::Vector< double, 3 > getSigmaR() const
Matrix_t correlationMatrix_m
ippl::Vector< double, 3 > getCutoffR() const
void emitParticles(double t, double dt) override
Time-stepped emission hook for one-shot delayed injection.
Vector_t< double, 6 > normMax_m
Vector_t< double, 3 > sigmaP_m
IpplTimings::TimerRef samplerTimer_m
Timer for performance profiling.
bool fixMeanR_m
Flag to exactly fix the mean R and P of particles after sampling.
Vector_t< double, 3 > meanP_m
void setCutoffR(const Vector_t< double, 3 > &cutoffR)
void setMeanP(const Vector_t< double, 3 > &meanP)
Vector_t< double, 6 > max_m
Vector_t< double, 3 > normPmin_m
void setCutoffP(const Vector_t< double, 3 > &cutoffP)
Vector_t< double, 3 > pmax_m
void ComputeCholeskyFactorization()
Computes the Cholesky factorization of the covariance matrix.
Vector_t< double, 3 > rmin_m
Vector_t< double, 3 > rmax_m
Vector_t< double, 3 > pmin_m
Vector_t< double, 3 > cutoffR_m
Cutoff multipliers for position and momentum distributions.
Vector_t< double, 6 > min_m
Min and Max bounds for all 6 dimensions (R0,P0,R1,P1,R2,P2).
Vector_t< double, 3 > normPmax_m
MultiVariateGaussian(std::shared_ptr< ParticleContainer_t > pc, std::shared_ptr< FieldContainer_t > fc, Distribution_t *opalDist)
Constructor for MultiVariateGaussian.
void setFixMeanR(bool fixMeanR)
void setMeanR(const Vector_t< double, 3 > &meanR)
Vector_t< double, 6 > normMin_m
void initRandomPool()
Initializes the random number generator pool.
Vector_t< double, 3 > normRmax_m
void generateParticles(size_t &numberOfParticles, Vector_t< double, 3 > nr) override
Generates particles based on the defined Gaussian distribution.
Vector_t< double, 3 > meanR_m
Vector_t< double, 3 > sigmaR_m
Standard deviations for position and momentum distributions.
void setSigmaP(const Vector_t< double, 3 > &sigmaP)
GeneratorPool randPool_m
Pool of random number generators for parallel sampling.
void setSigmaR(const Vector_t< double, 3 > &sigmaR)
void ComputeCenteredBounds()
Computes centered bounds for the particle distribution.
Vector_t< double, 3 > cutoffP_m
Vector_t< double, 3 > normRmin_m
void setFixMeanP(bool fixMeanP)
Vector_t< double, 3 > P0_m
Vector_t< double, 3 > R0_m
Emission source offset: position R0, momentum P0, start time t0 (applied in sample step).
bool hasEmittedOnce_m
For one-shot emitters (e.g. Gaussian at delayed t0): guard to avoid double sampling.
size_t computeLocalEmitCount(size_t totalToSample) const
Computes the number of particles this rank should emit so that the global total equals totalToSample ...
std::string emissionModel_m
Distribution_t * opalDist_m
void fillPolarization(size_t startIdx, size_t count)
std::shared_ptr< ParticleContainer_t > pc_m
int seed
The current random seed.