OPALX (Object Oriented Parallel Accelerator Library for Exascale) MINIorX
OPALX
FieldSolver.cpp
Go to the documentation of this file.
2
3#include <iomanip>
4#include <fstream>
5
6#include <boost/filesystem.hpp>
7#include <boost/format.hpp>
8
9#include "Utilities/Util.h"
11
12extern Inform* gmsg;
13
14template <>
15template <typename Solver>
17 Inform m ("initSolverWithParams ");
18 this->getSolver().template emplace<Solver>();
19 Solver& solver = std::get<Solver>(this->getSolver());
20 solver.mergeParameters(sp);
21
22 if constexpr (std::is_same_v<Solver, CGSolver_t<T, Dim>>) {
23 // The CG solver computes the potential directly and
24 // uses this to get the electric field
25 throw OpalException("FieldSolver<double,3>::initSolverWithParams", "Cannot use CGSolver yet, not implemented.");
26
28 m << "CG solver used " << endl;
29 solver.setLhs(*phi_m);
30 solver.setGradient(*E_m);
31 } else if constexpr (std::is_same_v<Solver, OpenSolver_t<T, Dim>>) {
32 // The periodic Poisson solver, Open boundaries solver,
33 // and the P3M solver compute the electric field directly
34 m << "OpenSolver used" << endl;
35 solver.setRhs(*rho_m);
36 m << "Set RHS for OpenSolver" << endl;
37 solver.setLhs(*E_m);
38 m << "Set LHS for OpenSolver" << endl;
39 solver.setGradFD();
40 m << "Set GradFD for OpenSolver" << endl;
41 } else if constexpr (std::is_same_v<Solver, FFTSolver_t<T, Dim>>) {
42 // The periodic Poisson solver
43 m << "FFTSolver used" << endl;
44 solver.setRhs(*rho_m);
45 solver.setLhs(*E_m);
46 } else if constexpr (std::is_same_v<Solver, NullSolver_t<T, Dim>>) {
47 m << "NullSolver used" << endl;
48 solver.setRhs(*rho_m);
49 solver.setLhs(*E_m);
50 }
51
52 call_counter_m = 0;
53}
54
55
56
57
58template <>
60 /*
61 what == ef
62 */
63
64 Inform m("FS::dumpVectorField() ");
65
66 // std::variant<Field_t<3>*, VField_t<double, 3>* > field;
67
68 if (ippl::Comm->size() > 1 || call_counter_m<2) {
69 return;
70 }
71
72/* Save the files in the output directory of the simulation. The file
73 * name of vector fields is
74 *
75 * 'basename'-'name'_field-'******'.dat
76 *
77 * and of scalar fields
78 *
79 * 'basename'-'name'_scalar-'******'.dat
80 *
81 * with
82 * 'basename': OPAL input file name (*.in)
83 * 'name': field name (input argument of function)
84 * '******': call_counter_m padded with zeros to 6 digits
85 */
86
87 std::string dirname = "data/";
88
89 std::string type;
90 std::string unit;
91
92 if (Util::toUpper(what) == "EF") {
93 type = "vector";
94 unit = "";
95 }
96
97 VField_t<double, 3>* field = this->getE();
98
99 auto localIdx = field->getOwned();
100 auto mesh_mp = &(field->get_mesh());
101 auto spacing = mesh_mp->getMeshSpacing();
102 auto origin = mesh_mp->getOrigin();
103
104 auto fieldV = field->getView();
105 auto field_hostV = field->getHostMirror();
106 Kokkos::deep_copy(field_hostV, fieldV);
107
108 boost::filesystem::path file(dirname);
109 boost::format filename("%1%-%2%-%|3$06|.dat");
110 std::string basename = OpalData::getInstance()->getInputBasename();
111 filename % basename % (what + std::string("_") + type) % call_counter_m;
112 file /= filename.str();
113 std::ofstream fout(file.string(), std::ios::out);
114
115 fout << std::setprecision(9);
116
117 fout << "# " << Util::toUpper(what) << " " << type << " data on grid" << std::endl
118 << "# origin= " << std::fixed << origin << " h= " << std::fixed << spacing << std::endl
119 << std::setw(5) << "i"
120 << std::setw(5) << "j"
121 << std::setw(5) << "k"
122 << std::setw(17) << "x [m]"
123 << std::setw(17) << "y [m]"
124 << std::setw(17) << "z [m]";
125
126 fout << std::setw(10) << what << "x [" << unit << "]"
127 << std::setw(10) << what << "y [" << unit << "]"
128 << std::setw(10) << what << "z [" << unit << "]";
129
130 fout << std::endl;
131
132 for (int i = localIdx[0].first() + 1; i <= localIdx[0].last() +1 ; i++) {
133 for (int j = localIdx[1].first() + 1 ; j <= localIdx[1].last() +1 ; j++) {
134 for (int k = localIdx[2].first() + 1 ; k <= localIdx[2].last() +1 ; k++) {
135
136 // define the physical points (cell-centered)
137 double x = i * spacing[0] + origin[0];
138 double y = j * spacing[1] + origin[1];
139 double z = k * spacing[2] + origin[2];
140
141 fout << std::setw(5) << i-1
142 << std::setw(5) << j-1
143 << std::setw(5) << k-1
144 << std::setw(17) << x
145 << std::setw(17) << y
146 << std::setw(17) << z
147 << std::scientific
148 << "\t" << field_hostV(i,j,k)[0]
149 << "\t" << field_hostV(i,j,k)[1]
150 << "\t" << field_hostV(i,j,k)[2]
151 << std::endl;
152 }
153 }
154 }
155 fout.close();
156 m << "*** FINISHED DUMPING " + Util::toUpper(what) + " FIELD *** to " << file.string() << endl;
157}
158
159template <>
161
162 /*
163 what == phi | rho
164 */
165
166 Inform m("FS::dumpScalField() ");
167
168 if (ippl::Comm->size() > 1 || call_counter_m<2) {
169 return;
170 }
171
172/* Save the files in the output directory of the simulation. The file
173 * name of vector fields is
174 *
175 * 'basename'-'name'_field-'******'.dat
176 *
177 * and of scalar fields
178 *
179 * 'basename'-'name'_scalar-'******'.dat
180 *
181 * with
182 * 'basename': OPAL input file name (*.in)
183 * 'name': field name (input argument of function)
184 * '******': call_counter_m padded with zeros to 6 digits
185 */
186
187
188 std::string dirname = "data/";
189
190 std::string type;
191 std::string unit;
192 bool isVectorField = false;
193
194 if (Util::toUpper(what) == "RHO") {
195 type = "scalar";
196 unit = "Cb/m^3";
197 } else if (Util::toUpper(what) == "PHI") {
198 type = "scalar";
199 unit = "V";
200 }
201
202
203 Field_t<3>* field = this->getRho(); // both rho and phi are in the same variable (in place computation)
204
205 auto localIdx = field->getOwned();
206 auto mesh_mp = &(field->get_mesh());
207 auto spacing = mesh_mp->getMeshSpacing();
208 auto origin = mesh_mp->getOrigin();
209
210 auto fieldV = field->getView();
211 auto field_hostV = field->getHostMirror();
212 Kokkos::deep_copy(field_hostV, fieldV);
213
214 boost::filesystem::path file(dirname);
215 boost::format filename("%1%-%2%-%|3$06|.dat");
216 std::string basename = OpalData::getInstance()->getInputBasename();
217 filename % basename % (what + std::string("_") + type) % call_counter_m;
218 file /= filename.str();
219 std::ofstream fout(file.string(), std::ios::out);
220
221 fout << std::setprecision(9);
222
223 fout << "# " << Util::toUpper(what) << " " << type << " data on grid" << std::endl
224 << "# origin= " << std::fixed << origin << " h= " << std::fixed << spacing << std::endl
225 << std::setw(5) << "i"
226 << std::setw(5) << "j"
227 << std::setw(5) << "k"
228 << std::setw(17) << "x [m]"
229 << std::setw(17) << "y [m]"
230 << std::setw(17) << "z [m]";
231
232 if (isVectorField) {
233 fout << std::setw(10) << what << "x [" << unit << "]"
234 << std::setw(10) << what << "y [" << unit << "]"
235 << std::setw(10) << what << "z [" << unit << "]";
236 } else {
237 fout << std::setw(13) << what << " [" << unit << "]";
238 }
239
240 fout << std::endl;
241
242 if (Util::toUpper(what) == "RHO") {
243 for (int i = localIdx[0].first(); i <= localIdx[0].last(); i++) {
244 for (int j = localIdx[1].first(); j <= localIdx[1].last(); j++) {
245 for (int k = localIdx[2].first(); k <= localIdx[2].last(); k++) {
246
247 // define the physical points (cell-centered)
248 double x = i * spacing[0] + origin[0];
249 double y = j * spacing[1] + origin[1];
250 double z = k * spacing[2] + origin[2];
251
252 fout << std::setw(5) << i
253 << std::setw(5) << j
254 << std::setw(5) << k
255 << std::setw(17) << x
256 << std::setw(17) << y
257 << std::setw(17) << z
258 << std::scientific << "\t" << field_hostV(i,j,k)
259 << std::endl;
260 }
261 }
262 }
263 }
264 else {
265 for (int i = localIdx[0].first() + 1; i <= localIdx[0].last() +1 ; i++) {
266 for (int j = localIdx[1].first() + 1 ; j <= localIdx[1].last() +1 ; j++) {
267 for (int k = localIdx[2].first() + 1 ; k <= localIdx[2].last() +1 ; k++) {
268
269 // define the physical points (cell-centered)
270 double x = i * spacing[0] + origin[0];
271 double y = j * spacing[1] + origin[1];
272 double z = k * spacing[2] + origin[2];
273
274 fout << std::setw(5) << i-1
275 << std::setw(5) << j-1
276 << std::setw(5) << k-1
277 << std::setw(17) << x
278 << std::setw(17) << y
279 << std::setw(17) << z
280 << std::scientific << "\t" << field_hostV(i,j,k)
281 << std::endl;
282 }
283 }
284 }
285 }
286 fout.close();
287 m << "*** FINISHED DUMPING " + Util::toUpper(what) + " FIELD *** to " << file.string() << endl;
288}
289
290template <>
294 sp.add("use_heffte_defaults", false);
295 sp.add("use_pencils", true);
296 sp.add("use_reorder", false);
297 sp.add("use_gpu_aware", true);
298 sp.add("comm", ippl::p2p_pl);
299 sp.add("r2c_direction", 0);
300 sp.add("algorithm", OpenSolver_t<double, 3>::HOCKNEY);
301 initSolverWithParams<OpenSolver_t<double, 3>>(sp);
302}
303
304template <>
306 if constexpr (Dim == 2 || Dim == 3) {
308 sp.add("output_type", FFTSolver_t<double, 3>::GRAD);
309 //sp.add("output_type", OpenSolver_t<double, 3>::SOL_AND_GRAD);
310 sp.add("use_heffte_defaults", false);
311 sp.add("use_pencils", true);
312 sp.add("use_reorder", false);
313 sp.add("use_gpu_aware", true);
314 sp.add("comm", ippl::p2p_pl);
315 sp.add("r2c_direction", 0);
316 initSolverWithParams<FFTSolver_t<double, 3>>(sp);
317 } else {
318 // TODO: add exception here
319 // throw std::runtime_error("Unsupported dimensionality for FFT solver");
320 }
321}
322
323
324template <>
326 Inform m;
327 if (this->getStype() == "FFT") {
328 initFFTSolver();
329 } else if (this->getStype() == "OPEN") {
330 initOpenSolver();
331 } else if (this->getStype() == "NONE") {
332 initNullSolver();
333 }
334 else {
335 m << "No solver matches the argument: " << this->getStype() << endl;
336 throw std::runtime_error("No solver match");
337 }
338}
339
340template <>
342 // CG requires explicit periodic boundary conditions while the periodic Poisson solver
343 // simply assumes them
344 if (this->getStype() == "CG") {
345 typedef ippl::BConds<Field<double, 3>, 3> bc_type;
346 bc_type allPeriodic;
347 for (unsigned int i = 0; i < 2 * 3; ++i) {
348 allPeriodic[i] = std::make_shared<ippl::PeriodicFace<Field<double, 3>>>(i);
349 }
350 phi_m->setFieldBC(allPeriodic);
351 }
352 }
353
354template<>
356 constexpr int Dim = 3;
357
358 if (this->getStype() == "CG") {
359 CGSolver_t<double, 3>& solver = std::get<CGSolver_t<double, 3>>(this->getSolver());
360 solver.solve();
361
362 if (ippl::Comm->rank() == 0) {
363 std::stringstream fname;
364 fname << "data/CG_";
365 fname << ippl::Comm->size();
366 fname << ".csv";
367
368 Inform log(NULL, fname.str().c_str(), Inform::APPEND);
369 int iterations = solver.getIterationCount();
370 // Assume the dummy solve is the first call
371 if (iterations == 0) {
372 log << "residue,iterations" << endl;
373 }
374 // Don't print the dummy solve
375 if (iterations > 0) {
376 log << solver.getResidue() << "," << iterations << endl;
377 }
378 }
379 ippl::Comm->barrier();
380 } else if (this->getStype() == "FFT") {
381 if constexpr (Dim == 2 || Dim == 3) {
382#ifdef OPALX_FIELD_DEBUG
383 this->dumpScalField("rho");
384 call_counter_m++;
385#endif
386
387 std::get<FFTSolver_t<double, 3>>(this->getSolver()).solve();
388#ifdef OPALX_FIELD_DEBUG
389 this->dumpScalField("phi");
390 this->dumpVectField("ef");
391 call_counter_m++;
392#endif
393 }
394 } else if (this->getStype() == "P3M") {
395 if constexpr (Dim == 3) {
396 std::get<FFTTruncatedGreenSolver_t<double, 3>>(this->getSolver()).solve();
397 }
398 } else if (this->getStype() == "OPEN") {
399 if constexpr (Dim == 3) {
400#ifdef OPALX_FIELD_DEBUG
401 this->dumpScalField("rho");
402 call_counter_m++;
403#endif
404 std::get<OpenSolver_t<double, 3>>(this->getSolver()).solve();
405#ifdef OPALX_FIELD_DEBUG
406 this->dumpScalField("phi");
407 this->dumpVectField("ef");
408 call_counter_m++;
409#endif
410 }
411 } else if (this->getStype() == "NONE") {
412 std::get<NullSolver_t<T, Dim>>(this->getSolver()).solve();
413 } else {
414 throw std::runtime_error("Unknown solver type");
415 }
416}
417
418template<>
421 if constexpr (Dim == 2 || Dim == 3) {
422 initSolverWithParams<NullSolver_t<T, Dim>>(sp);
423 } else {
424 throw std::runtime_error("Unsupported dimensionality for Null solver");
425 }
426}
427
428/*
429template <>
430void FieldSolver<double,3>::initCGSolver() {
431 ippl::ParameterList sp;
432 sp.add("output_type", CGSolver_t<double, 3>::GRAD);
433 // Increase tolerance in the 1D case
434 sp.add("tolerance", 1e-10);
435
436 initSolverWithParams<CGSolver_t<double, 3>>(sp);
437}
438
439template<>
440void FieldSolver<double,3>::initP3MSolver() {
441 // if constexpr (Dim == 3) {
442 ippl::ParameterList sp;
443 sp.add("output_type", P3MSolver_t<double, 3>::GRAD);
444 sp.add("use_heffte_defaults", false);
445 sp.add("use_pencils", true);
446 sp.add("use_reorder", false);
447 sp.add("use_gpu_aware", true);
448 sp.add("comm", ippl::p2p_pl);
449 sp.add("r2c_direction", 0);
450
451 initSolverWithParams<P3MSolver_t<double, 3>>(sp);
452 // } else {
453 // throw std::runtime_error("Unsupported dimensionality for P3M solver");
454 // }
455}
456
457*/
ConditionalType< Dim==2||Dim==3, ippl::FFTPeriodicPoissonSolver< VField_t< T, Dim >, Field_t< Dim > > > FFTSolver_t
Definition: #PartBunch.hpp#:48
ConditionalType< Dim==3, ippl::FFTOpenPoissonSolver< VField_t< T, Dim >, Field_t< Dim > > > OpenSolver_t
Definition: #PartBunch.hpp#:55
Inform * gmsg
Definition: changes.cpp:7
constexpr KOKKOS_INLINE_FUNCTION auto first()
Definition: AbsorbingBC.h:10
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
void solve(double *Matrix, double *Solution, double *rightHandSide, const int &M, const int &N)
std::string toUpper(const std::string &str)
Definition: Util.cpp:145
@ p2p_pl
Definition: FFT.h:59
std::unique_ptr< mpi::Communicator > Comm
Definition: Ippl.h:22
std::string getInputBasename()
get input file name without extension
Definition: OpalData.cpp:685
static OpalData * getInstance()
Definition: OpalData.cpp:195
void dumpVectField(std::string what)
void initSolver() override
void initFFTSolver()
void runSolver() override
void initSolverWithParams(const ippl::ParameterList &sp)
void initOpenSolver()
void initNullSolver()
void dumpScalField(std::string what)
void setPotentialBCs()
The base class for all OPAL exceptions.
Definition: OpalException.h:28
HostMirror getHostMirror() const
Definition: BareField.h:173
view_type & getView()
Definition: BareField.h:169
const Domain_t & getOwned() const
Definition: BareField.h:117
KOKKOS_INLINE_FUNCTION Mesh_t & get_mesh() const
Definition: Field.h:64
int getIterationCount()
Definition: PoissonCG.h:139
void solve() override
Definition: PoissonCG.h:123
Tlhs getResidue() const
Definition: PoissonCG.h:145
Definition: Inform.h:40
@ APPEND
Definition: Inform.h:45
void add(const std::string &key, const T &value)
Definition: ParameterList.h:44
constexpr unsigned Dim