OPALX (Object Oriented Parallel Accelerator Library for Exascal) MINIorX
OPALX
MultiVariateGaussian.cpp
Go to the documentation of this file.
2#include <Kokkos_Core.hpp>
3#include <mpi.h>
4
5using Matrix_t = ippl::Vector<ippl::Vector<double, 6>, 6>;
6
13MultiVariateGaussian::MultiVariateGaussian(std::shared_ptr<ParticleContainer_t> &pc,
14 std::shared_ptr<FieldContainer_t> &fc,
15 std::shared_ptr<Distribution_t> &opalDist)
16 : SamplingBase(pc, fc, opalDist) {
17
18 // Initialize covariance matrix from the distribution.
19 for (unsigned int i = 0; i < 6; i++) {
20 for (unsigned int j = 0; j < 6; j++) {
21 cov_m[i][j] = opalDist_m->correlationMatrix_m[i][j];
22 }
23 }
24
25 setSigmaR(opalDist_m->getSigmaR());
26 setSigmaP(opalDist_m->getSigmaP());
27 setCutoffR(opalDist_m->getCutoffR());
28 setCutoffP(opalDist_m->getCutoffP());
29
30 meanR_m = 0.0;
31 meanP_m = 0.0;
32 meanP_m[2] = opalDist_m->getAvrgpz();
33
34 samplerTimer_m = IpplTimings::getTimer("SamplingTimer");
36 }
37
38MultiVariateGaussian::MultiVariateGaussian(std::shared_ptr<ParticleContainer_t> pc,
39 const Vector_t<double, 3>& meanR,
40 const Vector_t<double, 3>& meanP,
41 const Vector_t<double, 3>& sigmaR,
42 const Vector_t<double, 3>& sigmaP,
43 const Vector_t<double, 3>& cutoffR,
44 const Vector_t<double, 3>& cutoffP,
45 bool fixMeanR,
46 bool fixMeanP)
47 : SamplingBase(pc) {
48 // Initialize covariance matrix from the distribution.
49 for (unsigned int i = 0; i < 6; i++) {
50 for (unsigned int j = 0; j < 6; j++) {
51 cov_m[i][j] = 0.0;
52 if(i==j && i%2==0){
53 cov_m[i][j] = sigmaR[i/2]*sigmaR[i/2];
54 }
55 if(i==j && i%2==1){
56 cov_m[i][j] = sigmaP[i/2]*sigmaP[i/2];
57 }
58 }
59 }
60 setMeanR(meanR);
61 setMeanP(meanP);
62 setSigmaR(sigmaR);
63 setSigmaP(sigmaP);
64 setCutoffR(cutoffR);
65 setCutoffP(cutoffP);
66 setFixMeanR(fixMeanR);
67 setFixMeanP(fixMeanP);
68
69 samplerTimer_m = IpplTimings::getTimer("SamplingTimer");
71}
72
73
74MultiVariateGaussian::MultiVariateGaussian(std::shared_ptr<ParticleContainer_t> pc,
75 const Vector_t<double, 3>& meanR,
76 const Vector_t<double, 3>& meanP,
77 const Matrix_t &cov,
78 const Vector_t<double, 3>& cutoffR,
79 const Vector_t<double, 3>& cutoffP,
80 bool fixMeanR,
81 bool fixMeanP)
82 : SamplingBase(pc) {
83
84 cov_m = cov;
85
86 setMeanR(meanR);
87 setMeanP(meanP);
88 setSigmaR(ippl::Vector<double,3>(Kokkos::sqrt(cov_m[0][0]),
89 Kokkos::sqrt(cov_m[2][2]),
90 Kokkos::sqrt(cov_m[4][4])));
91
92 setSigmaP(ippl::Vector<double,3>(Kokkos::sqrt(cov_m[1][1]),
93 Kokkos::sqrt(cov_m[3][3]),
94 Kokkos::sqrt(cov_m[5][5])));
95 setCutoffR(cutoffR);
96 setCutoffP(cutoffP);
97 setFixMeanR(fixMeanR);
98
99 samplerTimer_m = IpplTimings::getTimer("SamplingTimer");
101}
102
107 extern Inform* gmsg;
108 size_t randInit;
109
110 if (Options::seed == -1) {
111 randInit = 1234567;
112 *gmsg << "* Seed = " << randInit << " on all ranks" << endl;
113 } else {
114 randInit = static_cast<size_t>(Options::seed + 100 * ippl::Comm->rank());
115 }
116
117 GeneratorPool rand_pool64(randInit);
118 randPool_m = rand_pool64;
119 return;
120}
121
126 for (unsigned int i = 0; i < 6; i++) {
127 for (unsigned int j = 0; j < 6; j++) {
128 L_m[i][j] = 0.0;
129 }
130 }
131 double sum = 0.0;
132 for (unsigned int i = 0; i < 6; i++) {
133 for (unsigned int j = 0; j <= i; j++) {
134 sum = 0.0;
135 for (unsigned int k = 0; k < j; k++) {
136 sum += L_m[i][k] * L_m[j][k];
137 }
138 if (j == i) {
139 L_m[j][j] = Kokkos::sqrt(cov_m[j][j] - sum);
140 } else {
141 L_m[i][j] = (cov_m[i][j] - sum) / L_m[j][j];
142 }
143 }
144 }
145}
146
151 rmin_m = -cutoffR_m;
153 pmin_m = -cutoffP_m;
155
156 for (int i = 0; i < 3; i++) {
157 rmin_m(i) *= sigmaR_m(i);
158 rmax_m(i) *= sigmaR_m(i);
159 pmin_m(i) *= sigmaP_m(i);
160 pmax_m(i) *= sigmaP_m(i);
161
162 min_m(i * 2) = rmin_m(i);
163 max_m(i * 2) = rmax_m(i);
164 min_m(i * 2 + 1) = pmin_m(i);
165 max_m(i * 2 + 1) = pmax_m(i);
166 }
167
168 normMin_m = 0.0;
169 normMax_m = 0.0;
170 double sumMin, sumMax;
171 for(int i=0; i<6; i++){
172 sumMin = 0.0;
173 sumMax = 0.0;
174 for(int j=0; j<i; j++){
175 sumMin += -L_m[i][j]*normMin_m(j);
176 sumMax += -L_m[i][j]*normMax_m(j);
177 }
178 normMin_m(i) = (min_m(i)-sumMin)/L_m[i][i];
179 normMax_m(i) = (max_m(i)-sumMax)/L_m[i][i];
180 }
181
182 for(int i=0; i<3; i++){
183 normRmin_m(i) = min_m(2*i)/sigmaR_m(i);
184 normRmax_m(i) = max_m(2*i)/sigmaR_m(i);
185 normPmin_m(i) = min_m(2*i+1)/sigmaP_m(i);
186 normPmax_m(i) = max_m(2*i+1)/sigmaP_m(i);
187
188 rmin_m(i) /= sigmaR_m(i);
189 rmax_m(i) /= sigmaR_m(i);
190 pmin_m(i) /= sigmaP_m(i);
191 pmax_m(i) /= sigmaP_m(i);
192 }
193}
194
199 IpplTimings::startTimer(samplerTimer_m);
200
201 auto rand_pool64 = randPool_m;
202 // compute L using Cholesky factorization cov=L*LT
204
205 // compute boundaries of normal random numbers
207
208 view_type &Rview = pc_m->R.getView();
209 view_type &Pview = pc_m->P.getView();
210
211 const double par[6] = {0.0, 1.0, 0.0, 1.0, 0.0, 1.0};
212 using Dist_t = ippl::random::NormalDistribution<double, 3>;
213 using sampling_t = ippl::random::InverseTransformSampling<double, 3, Kokkos::DefaultExecutionSpace, Dist_t>;
214 Dist_t dist(par);
215
216 MPI_Comm comm = MPI_COMM_WORLD;
217 int nranks, rank;
218 MPI_Comm_size(comm, &nranks);
219 MPI_Comm_rank(comm, &rank);
220
221 // if nlocal*nranks > numberOfParticles, put the remaining in rank 0
222 size_t nlocal = floor(numberOfParticles / nranks);
223 size_t remaining = numberOfParticles - nlocal * nranks;
224 if (remaining > 0 && rank == 0) {
225 nlocal += remaining;
226 }
227
228 sampling_t sampling(dist, normRmax_m, normRmin_m, normRmax_m, normRmin_m, nlocal);
229 pc_m->create(nlocal);
230 sampling.generate(Rview, rand_pool64);
231
232 sampling.updateBounds(normPmax_m, normPmin_m, normPmax_m, normPmin_m);
233 sampling.generate(Pview, rand_pool64);
234
235 Matrix_t L;
236 for (unsigned int i = 0; i < 6; i++) {
237 for (unsigned int j = 0; j < 6; j++) {
238 L[i][j] = L_m[i][j];
239 }
240 }
241
242 // Apply Cholesky transformation
243 Kokkos::parallel_for(nlocal, KOKKOS_LAMBDA(const int k) {
244 double vec_old[6], vec[6] = {0.0};
245 for (unsigned i = 0; i < 3; ++i) {
246 vec_old[2 * i] = Rview(k)[i];
247 vec_old[2 * i + 1] = Pview(k)[i];
248 }
249 for (unsigned i = 0; i < 6; ++i) {
250 for (unsigned j = 0; j < i + 1; ++j) {
251 vec[i] += L[i][j] * vec_old[j];
252 }
253 }
254 for (unsigned i = 0; i < 3; ++i) {
255 Rview(k)[i] = vec[2 * i];
256 Pview(k)[i] = vec[2 * i + 1];
257 }
258 });
259
260 Kokkos::fence();
261
262 // zero mean of R
263 double meanR[3], loc_meanR[3];
264
265 if (fixMeanR_m) {
266 for(int i=0; i<3; i++){
267 meanR[i] = 0.0;
268 loc_meanR[i] = 0.0;
269 }
270
271 Kokkos::parallel_reduce("calc moments of particle distr.", nlocal,
272 KOKKOS_LAMBDA(const int k, double& cent0, double& cent1, double& cent2) {
273 cent0 += Rview(k)[0];
274 cent1 += Rview(k)[1];
275 cent2 += Rview(k)[2];
276 },
277 Kokkos::Sum<double>(loc_meanR[0]), Kokkos::Sum<double>(loc_meanR[1]), Kokkos::Sum<double>(loc_meanR[2]));
278 Kokkos::fence();
279
280 MPI_Allreduce(loc_meanR, meanR, 3, MPI_DOUBLE, MPI_SUM, ippl::Comm->getCommunicator());
281 ippl::Comm->barrier();
282
283 for(int i=0; i<3; i++){
284 meanR[i] = meanR[i]/(1.*numberOfParticles);
285 }
286
287 Kokkos::parallel_for(nlocal, KOKKOS_LAMBDA(const int k) {
288 Rview(k)[0] -= meanR[0];
289 Rview(k)[1] -= meanR[1];
290 Rview(k)[2] -= meanR[2];
291 });
292 Kokkos::fence();
293 }
294
295 // zero mean of P
296 double meanP[3], loc_meanP[3];
297 if(fixMeanP_m){
298
299 for(int i=0; i<3; i++){
300 meanP[i] = 0.0;
301 loc_meanP[i] = 0.0;
302 }
303 Kokkos::parallel_reduce("calc moments of particle distr.", nlocal,
304 KOKKOS_LAMBDA(const int k, double& cent0, double& cent1, double& cent2) {
305 cent0 += Pview(k)[0];
306 cent1 += Pview(k)[1];
307 cent2 += Pview(k)[2];
308 },
309 Kokkos::Sum<double>(loc_meanP[0]), Kokkos::Sum<double>(loc_meanP[1]), Kokkos::Sum<double>(loc_meanP[2]));
310 Kokkos::fence();
311
312 MPI_Allreduce(loc_meanP, meanP, 3, MPI_DOUBLE, MPI_SUM, ippl::Comm->getCommunicator());
313 ippl::Comm->barrier();
314
315 for(int i=0; i<3; i++){
316 meanP[i] = meanP[i]/(1.*numberOfParticles);
317 }
318
319 Kokkos::parallel_for(nlocal, KOKKOS_LAMBDA(const int k) {
320 Pview(k)[0] -= meanP[0];
321 Pview(k)[1] -= meanP[1];
322 Pview(k)[2] -= meanP[2];
323 });
324 Kokkos::fence();
325 }
326
327 // correct the means of R and P from input
328 for(int i=0; i<3; i++){
329 meanR[i] = meanR_m[i];
330 meanP[i] = meanP_m[i];
331 }
332
333 Kokkos::parallel_for(nlocal, KOKKOS_LAMBDA(const int k) {
334 for(int i=0; i<3; i++){
335 Rview(k)[i] += meanR[i];
336 Pview(k)[i] += meanP[i];
337 }
338 });
339 Kokkos::fence();
340
341 IpplTimings::stopTimer(samplerTimer_m);
342}
Inform * gmsg
Definition changes.cpp:7
ippl::Vector< T, Dim > Vector_t
typename Kokkos::Random_XorShift64_Pool<> GeneratorPool
typename ippl::detail::ViewType< ippl::Vector< double, Dim >, 1 >::view_type view_type
ippl::Vector< ippl::Vector< double, 6 >, 6 > Matrix_t
ippl::Vector< ippl::Vector< double, 6 >, 6 > Matrix_t
ippl::random::NormalDistribution< double, 3 > Dist_t
const int nr
int seed
The current random seed.
Definition Options.cpp:37
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
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.
MultiVariateGaussian(std::shared_ptr< ParticleContainer_t > &pc, std::shared_ptr< FieldContainer_t > &fc, std::shared_ptr< Distribution_t > &opalDist)
Constructor for MultiVariateGaussian.
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)
SamplingBase(std::shared_ptr< ParticleContainer_t > &pc, std::shared_ptr< FieldContainer_t > &fc, std::shared_ptr< Distribution_t > &dist)
std::shared_ptr< Distribution_t > opalDist_m
std::shared_ptr< ParticleContainer_t > pc_m