Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
EKSpecies.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021-2023 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#include "config/config.hpp"
20
21#ifdef WALBERLA
22
23#include "EKSpecies.hpp"
26
28
29#include <boost/mpi.hpp>
30#include <boost/mpi/collectives/all_reduce.hpp>
31#include <boost/mpi/collectives/broadcast.hpp>
32
33#include <algorithm>
34#include <cassert>
35#include <functional>
36#include <memory>
37#include <optional>
38#include <sstream>
39#include <stdexcept>
40#include <string>
41#include <vector>
42
44
45std::unordered_map<std::string, int> const EKVTKHandle::obs_map = {
46 {"density", static_cast<int>(EKOutputVTK::density)},
47};
48
50 VariantMap const &parameters) {
51 if (method == "update_flux_boundary_from_shape") {
53 std::ranges::for_each(values, [this](double &v) { v *= m_conv_flux; });
54
55 m_instance->update_flux_boundary_from_shape(
56 get_value<std::vector<int>>(parameters, "raster"), values);
57 return {};
58 }
59 if (method == "update_density_boundary_from_shape") {
61 std::ranges::for_each(values, [this](double &v) { v *= m_conv_density; });
62 m_instance->update_density_boundary_from_shape(
63 get_value<std::vector<int>>(parameters, "raster"), values);
64 return {};
65 }
66 if (method == "clear_flux_boundaries") {
67 m_instance->clear_flux_boundaries();
68 return {};
69 }
70 if (method == "clear_density_boundaries") {
71 m_instance->clear_density_boundaries();
72 return {};
73 }
74 if (method == "save_checkpoint") {
75 auto const path = get_value<std::string>(parameters, "path");
76 auto const mode = get_value<int>(parameters, "mode");
77 save_checkpoint(path, mode);
78 return {};
79 }
80 if (method == "load_checkpoint") {
81 auto const path = get_value<std::string>(parameters, "path");
82 auto const mode = get_value<int>(parameters, "mode");
83 load_checkpoint(path, mode);
84 return {};
85 }
87}
88
90 auto const diffusion = get_value<double>(params, "diffusion");
91 auto const ext_efield = get_value<Utils::Vector3d>(params, "ext_efield");
92 auto const density = get_value<double>(params, "density");
93 auto const kT = get_value<double>(params, "kT");
96 auto const ek_density = density * m_conv_density;
97 auto const ek_kT = kT * m_conv_energy;
99 m_lattice->lattice(), ek_diffusion, ek_kT,
101 get_value<bool>(params, "advection"),
102 get_value<bool>(params, "friction_coupling"),
103 get_value<bool>(params, "single_precision"),
104 get_value_or<bool>(params, "thermalized", false),
105 static_cast<uint>(get_value_or<int>(params, "seed", 0)));
106 m_instance->ghost_communication();
107}
108
113 auto const agrid = get_value<double>(m_lattice->get_parameter("agrid"));
114 auto const density = get_value<double>(params, "density");
115 auto const kT = get_value<double>(params, "kT");
116 auto const tau = m_tau = get_value<double>(params, "tau");
117 auto const seed = get_value_or<int>(params, "seed", 0);
118 context()->parallel_try_catch([&]() {
119 if (get_value<bool>(params, "thermalized") and
120 not params.contains("seed")) {
121 throw std::invalid_argument(
122 "Parameter 'seed' is required for thermalized EKSpecies");
123 }
124 if (seed < 0) {
125 throw std::domain_error("Parameter 'seed' must be >= 0");
126 }
127 if (tau <= 0.) {
128 throw std::domain_error("Parameter 'tau' must be > 0");
129 }
130 if (kT < 0.) {
131 throw std::domain_error("Parameter 'kT' must be >= 0");
132 }
133 if (density < 0.) {
134 throw std::domain_error("Parameter 'density' must be >= 0");
135 }
136 m_conv_energy = Utils::int_pow<2>(tau) / Utils::int_pow<2>(agrid);
137 m_conv_diffusion = tau / Utils::int_pow<2>(agrid);
138 m_conv_ext_efield = Utils::int_pow<2>(tau) / agrid;
139 m_conv_density = Utils::int_pow<3>(agrid);
140 m_conv_flux = tau * Utils::int_pow<2>(agrid);
143 for (auto &vtk : m_vtk_writers) {
144 vtk->attach_to_lattice(m_instance, get_latice_to_md_units_conversion());
145 }
146 });
147}
148
149void EKSpecies::load_checkpoint(std::string const &filename, int mode) {
150 auto &ek_obj = *m_instance;
151
152 auto const read_metadata = [&ek_obj](CheckpointFile &cpfile) {
153 auto const expected_grid_size = ek_obj.get_lattice().get_grid_dimensions();
157 std::stringstream message;
158 message << "grid dimensions mismatch, read [" << read_grid_size << "], "
159 << "expected [" << expected_grid_size << "].";
160 throw std::runtime_error(message.str());
161 }
162 };
163
164 auto const read_data = [&ek_obj](CheckpointFile &cpfile) {
165 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
166 auto const i_max = grid_size[0];
167 auto const j_max = grid_size[1];
168 auto const k_max = grid_size[2];
170 for (int i = 0; i < i_max; i++) {
171 for (int j = 0; j < j_max; j++) {
172 for (int k = 0; k < k_max; k++) {
173 auto const ind = Utils::Vector3i{{i, j, k}};
174 cpfile.read(cpnode.density);
175 cpfile.read(cpnode.is_boundary_density);
176 if (cpnode.is_boundary_density) {
177 cpfile.read(cpnode.density_boundary);
178 }
179 cpfile.read(cpnode.is_boundary_flux);
180 if (cpnode.is_boundary_flux) {
181 cpfile.read(cpnode.flux_boundary);
182 }
183 ek_obj.set_node_density(ind, cpnode.density);
184 if (cpnode.is_boundary_density) {
185 ek_obj.set_node_density_boundary(ind, cpnode.density_boundary);
186 }
187 if (cpnode.is_boundary_flux) {
188 ek_obj.set_node_flux_boundary(ind, cpnode.flux_boundary);
189 }
190 }
191 }
192 }
193 };
194
195 auto const on_success = [&ek_obj]() { ek_obj.ghost_communication(); };
196
199}
200
201void EKSpecies::save_checkpoint(std::string const &filename, int mode) {
202 auto &ek_obj = *m_instance;
203
204 auto const write_metadata = [&ek_obj,
205 mode](std::shared_ptr<CheckpointFile> cpfile_ptr,
206 Context const &context) {
207 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
208 if (context.is_head_node()) {
209 cpfile_ptr->write(grid_size);
211 }
212 };
213
214 auto const on_failure = [](std::shared_ptr<CheckpointFile> const &,
215 Context const &context) {
216 if (context.is_head_node()) {
217 auto failure = true;
218 boost::mpi::broadcast(context.get_comm(), failure, 0);
219 }
220 };
221
222 auto const write_data = [&ek_obj,
223 mode](std::shared_ptr<CheckpointFile> cpfile_ptr,
224 Context const &context) {
225 auto const get_node_checkpoint =
226 [&](Utils::Vector3i const &ind) -> std::optional<EKWalberlaNodeState> {
227 auto const density = ek_obj.get_node_density(ind);
228 auto const is_b_d = ek_obj.get_node_is_density_boundary(ind);
229 auto const dens_b = ek_obj.get_node_density_at_boundary(ind);
230 auto const is_b_f = ek_obj.get_node_is_flux_boundary(ind);
231 auto const flux_b = ek_obj.get_node_flux_at_boundary(ind);
233 ((*is_b_d) ? dens_b.has_value() : true) and
234 ((*is_b_f) ? flux_b.has_value() : true)) {
237 cpnode.is_boundary_density = *is_b_d;
238 if (*is_b_d) {
239 cpnode.density_boundary = *dens_b;
240 }
241 cpnode.is_boundary_flux = *is_b_f;
242 if (*is_b_f) {
243 cpnode.flux_boundary = *flux_b;
244 }
245 return cpnode;
246 }
247 return std::nullopt;
248 };
249
250 auto failure = false;
251 auto const &comm = context.get_comm();
252 auto const is_head_node = context.is_head_node();
253 auto const unit_test_mode = (mode != static_cast<int>(CptMode::ascii)) and
254 (mode != static_cast<int>(CptMode::binary));
255 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
256 auto const i_max = grid_size[0];
257 auto const j_max = grid_size[1];
258 auto const k_max = grid_size[2];
260 for (int i = 0; i < i_max; i++) {
261 for (int j = 0; j < j_max; j++) {
262 for (int k = 0; k < k_max; k++) {
263 auto const ind = Utils::Vector3i{{i, j, k}};
264 auto const result = get_node_checkpoint(ind);
265 if (!unit_test_mode) {
266 assert(1 == boost::mpi::all_reduce(comm, static_cast<int>(!!result),
267 std::plus<>()) &&
268 "Incorrect number of return values");
269 }
270 if (is_head_node) {
271 if (result) {
272 cpnode = *result;
273 } else {
274 comm.recv(boost::mpi::any_source, 42, cpnode);
275 }
276 auto &cpfile = *cpfile_ptr;
277 cpfile.write(cpnode.density);
278 cpfile.write(cpnode.is_boundary_density);
279 if (cpnode.is_boundary_density) {
280 cpfile.write(cpnode.density_boundary);
281 }
282 cpfile.write(cpnode.is_boundary_flux);
283 if (cpnode.is_boundary_flux) {
284 cpfile.write(cpnode.flux_boundary);
285 }
286 boost::mpi::broadcast(comm, failure, 0);
287 } else {
288 if (result) {
289 comm.send(0, 42, *result);
290 }
291 boost::mpi::broadcast(comm, failure, 0);
292 if (failure) {
293 return;
294 }
295 }
296 }
297 }
298 }
299 };
300
303}
304
305} // namespace ScriptInterface::walberla
306
307#endif // WALBERLA
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
virtual bool is_head_node() const =0
virtual boost::mpi::communicator const & get_comm() const =0
Context * context() const
Responsible context.
void make_instance(VariantMap const &params) override
Definition EKSpecies.cpp:89
Variant do_call_method(std::string const &method, VariantMap const &parameters) override
Definition EKSpecies.cpp:49
::LatticeModel::units_map get_latice_to_md_units_conversion() const override
void do_construct(VariantMap const &params) override
Variant do_call_method(std::string const &method_name, VariantMap const &params) override
This file contains the defaults for ESPResSo.
void save_checkpoint_common(Context const &context, std::string const classname, std::string const &filename, int mode, F1 const write_metadata, F2 const write_data, F3 const on_failure)
void unit_test_handle(int mode)
Inject code for unit tests.
void load_checkpoint_common(Context const &context, std::string const classname, std::string const &filename, int mode, F1 const read_metadata, F2 const read_data, F3 const on_success)
T get_value(Variant const &v)
Extract value of specific type T from a Variant.
std::unordered_map< std::string, Variant > VariantMap
Definition Variant.hpp:69
boost::make_recursive_variant< None, bool, int, std::size_t, double, std::string, ObjectRef, Utils::Vector3b, Utils::Vector3i, Utils::Vector2d, Utils::Vector3d, Utils::Vector4d, std::vector< int >, std::vector< double >, std::vector< boost::recursive_variant_ >, std::unordered_map< int, boost::recursive_variant_ >, std::unordered_map< std::string, boost::recursive_variant_ > >::type Variant
Possible types for parameters.
Definition Variant.hpp:67
static FUNC_PREFIX double *RESTRICT int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const int64_t const double grid_size
std::shared_ptr< EKinWalberlaBase > new_ek_walberla(std::shared_ptr< LatticeWalberla > const &lattice, double diffusion, double kT, double valency, Utils::Vector3d ext_efield, double density, bool advection, bool friction_coupling, bool single_precision, bool thermalized, unsigned int seed)
static SteepestDescentParameters params
Currently active steepest descent instance.
Checkpoint data for a EK node.