ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
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
49Variant EKSpecies::do_call_method(std::string const &method,
50 VariantMap const &parameters) {
51 if (method == "update_flux_boundary_from_shape") {
52 auto values = get_value<std::vector<double>>(parameters, "values");
53 std::transform(values.begin(), values.end(), values.begin(),
54 [this](double v) { return v * m_conv_flux; });
55
56 m_instance->update_flux_boundary_from_shape(
57 get_value<std::vector<int>>(parameters, "raster"), values);
58 return {};
59 }
60 if (method == "update_density_boundary_from_shape") {
61 auto values = get_value<std::vector<double>>(parameters, "values");
62 std::transform(values.begin(), values.end(), values.begin(),
63 [this](double v) { return v * m_conv_density; });
64 m_instance->update_density_boundary_from_shape(
65 get_value<std::vector<int>>(parameters, "raster"), values);
66 return {};
67 }
68 if (method == "clear_flux_boundaries") {
69 m_instance->clear_flux_boundaries();
70 return {};
71 }
72 if (method == "clear_density_boundaries") {
73 m_instance->clear_density_boundaries();
74 return {};
75 }
76 if (method == "save_checkpoint") {
77 auto const path = get_value<std::string>(parameters, "path");
78 auto const mode = get_value<int>(parameters, "mode");
79 save_checkpoint(path, mode);
80 return {};
81 }
82 if (method == "load_checkpoint") {
83 auto const path = get_value<std::string>(parameters, "path");
84 auto const mode = get_value<int>(parameters, "mode");
85 load_checkpoint(path, mode);
86 return {};
87 }
88 return Base::do_call_method(method, parameters);
89}
90
92 auto const diffusion = get_value<double>(params, "diffusion");
93 auto const ext_efield = get_value<Utils::Vector3d>(params, "ext_efield");
94 auto const density = get_value<double>(params, "density");
95 auto const kT = get_value<double>(params, "kT");
96 auto const precision = get_value<bool>(params, "single_precision");
97 auto const ek_diffusion = diffusion * m_conv_diffusion;
98 auto const ek_ext_efield = ext_efield * m_conv_ext_efield;
99 auto const ek_density = density * m_conv_density;
100 auto const ek_kT = kT * m_conv_energy;
102 m_lattice->lattice(), ek_diffusion, ek_kT,
103 get_value<double>(params, "valency"), ek_ext_efield, ek_density,
104 get_value<bool>(params, "advection"),
105 get_value<bool>(params, "friction_coupling"), precision);
106}
107
109 m_lattice = get_value<std::shared_ptr<LatticeWalberla>>(params, "lattice");
111 get_value_or<decltype(m_vtk_writers)>(params, "vtk_writers", {});
112 auto const agrid = get_value<double>(m_lattice->get_parameter("agrid"));
113 auto const density = get_value<double>(params, "density");
114 auto const kT = get_value<double>(params, "kT");
115 auto const tau = m_tau = get_value<double>(params, "tau");
116 context()->parallel_try_catch([&]() {
117 if (tau <= 0.) {
118 throw std::domain_error("Parameter 'tau' must be > 0");
119 }
120 if (kT < 0.) {
121 throw std::domain_error("Parameter 'kT' must be >= 0");
122 }
123 if (density < 0.) {
124 throw std::domain_error("Parameter 'density' must be >= 0");
125 }
126 m_conv_energy = Utils::int_pow<2>(tau) / Utils::int_pow<2>(agrid);
127 m_conv_diffusion = tau / Utils::int_pow<2>(agrid);
128 m_conv_ext_efield = Utils::int_pow<2>(tau) / agrid;
129 m_conv_density = Utils::int_pow<3>(agrid);
130 m_conv_flux = tau * Utils::int_pow<2>(agrid);
133 for (auto &vtk : m_vtk_writers) {
134 vtk->attach_to_lattice(m_instance, get_latice_to_md_units_conversion());
135 }
136 });
137}
138
139void EKSpecies::load_checkpoint(std::string const &filename, int mode) {
140 auto &ek_obj = *m_instance;
141
142 auto const read_metadata = [&ek_obj](CheckpointFile &cpfile) {
143 auto const expected_grid_size = ek_obj.get_lattice().get_grid_dimensions();
144 Utils::Vector3i read_grid_size;
145 cpfile.read(read_grid_size);
146 if (read_grid_size != expected_grid_size) {
147 std::stringstream message;
148 message << "grid dimensions mismatch, read [" << read_grid_size << "], "
149 << "expected [" << expected_grid_size << "].";
150 throw std::runtime_error(message.str());
151 }
152 };
153
154 auto const read_data = [&ek_obj](CheckpointFile &cpfile) {
155 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
156 auto const i_max = grid_size[0];
157 auto const j_max = grid_size[1];
158 auto const k_max = grid_size[2];
159 EKWalberlaNodeState cpnode;
160 for (int i = 0; i < i_max; i++) {
161 for (int j = 0; j < j_max; j++) {
162 for (int k = 0; k < k_max; k++) {
163 auto const ind = Utils::Vector3i{{i, j, k}};
164 cpfile.read(cpnode.density);
165 cpfile.read(cpnode.is_boundary_density);
166 if (cpnode.is_boundary_density) {
167 cpfile.read(cpnode.density_boundary);
168 }
169 cpfile.read(cpnode.is_boundary_flux);
170 if (cpnode.is_boundary_flux) {
171 cpfile.read(cpnode.flux_boundary);
172 }
173 ek_obj.set_node_density(ind, cpnode.density);
174 if (cpnode.is_boundary_density) {
175 ek_obj.set_node_density_boundary(ind, cpnode.density_boundary);
176 }
177 if (cpnode.is_boundary_flux) {
178 ek_obj.set_node_flux_boundary(ind, cpnode.flux_boundary);
179 }
180 }
181 }
182 }
183 };
184
185 auto const on_success = [&ek_obj]() { ek_obj.ghost_communication(); };
186
187 load_checkpoint_common(*context(), "EK", filename, mode, read_metadata,
188 read_data, on_success);
189}
190
191void EKSpecies::save_checkpoint(std::string const &filename, int mode) {
192 auto &ek_obj = *m_instance;
193
194 auto const write_metadata = [&ek_obj,
195 mode](std::shared_ptr<CheckpointFile> cpfile_ptr,
196 Context const &context) {
197 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
198 if (context.is_head_node()) {
199 cpfile_ptr->write(grid_size);
200 unit_test_handle(mode);
201 }
202 };
203
204 auto const on_failure = [](std::shared_ptr<CheckpointFile> const &,
205 Context const &context) {
206 if (context.is_head_node()) {
207 auto failure = true;
208 boost::mpi::broadcast(context.get_comm(), failure, 0);
209 }
210 };
211
212 auto const write_data = [&ek_obj,
213 mode](std::shared_ptr<CheckpointFile> cpfile_ptr,
214 Context const &context) {
215 auto const get_node_checkpoint =
216 [&](Utils::Vector3i const &ind) -> std::optional<EKWalberlaNodeState> {
217 auto const density = ek_obj.get_node_density(ind);
218 auto const is_b_d = ek_obj.get_node_is_density_boundary(ind);
219 auto const dens_b = ek_obj.get_node_density_at_boundary(ind);
220 auto const is_b_f = ek_obj.get_node_is_flux_boundary(ind);
221 auto const flux_b = ek_obj.get_node_flux_at_boundary(ind);
222 if (density and is_b_d and is_b_f and
223 ((*is_b_d) ? dens_b.has_value() : true) and
224 ((*is_b_f) ? flux_b.has_value() : true)) {
225 EKWalberlaNodeState cpnode;
226 cpnode.density = *density;
227 cpnode.is_boundary_density = *is_b_d;
228 if (*is_b_d) {
229 cpnode.density_boundary = *dens_b;
230 }
231 cpnode.is_boundary_flux = *is_b_f;
232 if (*is_b_f) {
233 cpnode.flux_boundary = *flux_b;
234 }
235 return cpnode;
236 }
237 return std::nullopt;
238 };
239
240 auto failure = false;
241 auto const &comm = context.get_comm();
242 auto const is_head_node = context.is_head_node();
243 auto const unit_test_mode = (mode != static_cast<int>(CptMode::ascii)) and
244 (mode != static_cast<int>(CptMode::binary));
245 auto const grid_size = ek_obj.get_lattice().get_grid_dimensions();
246 auto const i_max = grid_size[0];
247 auto const j_max = grid_size[1];
248 auto const k_max = grid_size[2];
249 EKWalberlaNodeState cpnode;
250 for (int i = 0; i < i_max; i++) {
251 for (int j = 0; j < j_max; j++) {
252 for (int k = 0; k < k_max; k++) {
253 auto const ind = Utils::Vector3i{{i, j, k}};
254 auto const result = get_node_checkpoint(ind);
255 if (!unit_test_mode) {
256 assert(1 == boost::mpi::all_reduce(comm, static_cast<int>(!!result),
257 std::plus<>()) &&
258 "Incorrect number of return values");
259 }
260 if (is_head_node) {
261 if (result) {
262 cpnode = *result;
263 } else {
264 comm.recv(boost::mpi::any_source, 42, cpnode);
265 }
266 auto &cpfile = *cpfile_ptr;
267 cpfile.write(cpnode.density);
268 cpfile.write(cpnode.is_boundary_density);
269 if (cpnode.is_boundary_density) {
270 cpfile.write(cpnode.density_boundary);
271 }
272 cpfile.write(cpnode.is_boundary_flux);
273 if (cpnode.is_boundary_flux) {
274 cpfile.write(cpnode.flux_boundary);
275 }
276 boost::mpi::broadcast(comm, failure, 0);
277 } else {
278 if (result) {
279 comm.send(0, 42, *result);
280 }
281 boost::mpi::broadcast(comm, failure, 0);
282 if (failure) {
283 return;
284 }
285 }
286 }
287 }
288 }
289 };
290
291 save_checkpoint_common(*context(), "EK", filename, mode, write_metadata,
292 write_data, on_failure);
293}
294
295} // namespace ScriptInterface::walberla
296
297#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:91
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:82
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:80
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)
static SteepestDescentParameters params
Currently active steepest descent instance.
Checkpoint data for a EK node.
Utils::Vector3d flux_boundary