ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
EKSpeciesNode.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
20#include <config/config.hpp>
21
22#ifdef ESPRESSO_WALBERLA
23
24#include "EKSpeciesNode.hpp"
25#include "errorhandling.hpp"
26
27#include "LatticeIndices.hpp"
28
31
32#include <utils/Vector.hpp>
34
35#include <boost/mpi/collectives/all_reduce.hpp>
36#include <boost/serialization/vector.hpp>
37
38#include <cassert>
39#include <memory>
40#include <optional>
41#include <stdexcept>
42#include <string>
43
45
46static bool is_boundary_all_reduce(boost::mpi::communicator const &comm,
47 std::optional<bool> const &is_boundary) {
48 return boost::mpi::all_reduce(comm, is_boundary ? *is_boundary : false,
49 std::logical_or<>());
50}
51
52Variant EKSpeciesNode::do_call_method(std::string const &name,
53 VariantMap const &params) {
54 if (name == "override_index") {
55 // this hidden feature is used to iterate an EK slice without
56 // rebuilding a EKSpeciesNode for each node in the slice
57 auto const index = get_value<Utils::Vector3i>(params, "index");
58 if (not is_index_valid(index, m_grid_size)) {
59 return 1;
60 }
61 m_index = index;
62 return 0;
63 }
64 if (not name.starts_with("get_")) {
66 [&]() { ek_throw_if_expired(m_mpi_cart_comm_observer); });
67 }
68 if (name == "set_density") {
69 auto const dens = get_value<double>(params, "value");
70 m_ek_species->set_node_density(m_index, dens * m_conv_dens);
71 m_ek_species->ghost_communication();
72 return {};
73 }
74 if (name == "get_density") {
75 auto const result = m_ek_species->get_node_density(m_index);
76 return Utils::Mpi::reduce_optional(context()->get_comm(), result) /
77 m_conv_dens;
78 }
79 if (name == "get_flux_vector") {
80 auto const result = m_ek_species->get_node_flux_vector(m_index);
81 return Utils::Mpi::reduce_optional(context()->get_comm(), result) /
82 m_conv_flux;
83 }
84 if (name == "get_is_boundary") {
85 auto const result = m_ek_species->get_node_is_boundary(m_index);
86 return Utils::Mpi::reduce_optional(context()->get_comm(), result);
87 }
88 if (name == "get_node_density_at_boundary") {
89 auto const boundary_opt =
90 m_ek_species->get_node_is_density_boundary(m_index);
91 if (is_boundary_all_reduce(context()->get_comm(), boundary_opt)) {
92 auto const result = m_ek_species->get_node_density_at_boundary(m_index);
93 return Utils::Mpi::reduce_optional(context()->get_comm(), result) /
94 m_conv_dens;
95 }
96 return Variant{None{}};
97 }
98 if (name == "set_node_density_at_boundary") {
99 if (is_none(params.at("value"))) {
100 m_ek_species->remove_node_from_density_boundary(m_index);
101 } else {
102 auto const dens = get_value<double>(params, "value") * m_conv_dens;
103 m_ek_species->set_node_density_boundary(m_index, dens);
104 }
105 return {};
106 }
107 if (name == "get_node_flux_at_boundary") {
108 auto const boundary_opt = m_ek_species->get_node_is_flux_boundary(m_index);
109 if (is_boundary_all_reduce(context()->get_comm(), boundary_opt)) {
110 auto const result = m_ek_species->get_node_flux_at_boundary(m_index);
111 return Utils::Mpi::reduce_optional(context()->get_comm(), result) /
112 m_conv_flux;
113 }
114 return Variant{None{}};
115 }
116 if (name == "set_node_flux_at_boundary") {
117 if (is_none(params.at("value"))) {
118 m_ek_species->remove_node_from_flux_boundary(m_index);
119 } else {
120 context()->parallel_try_catch([&]() {
121 if (get_lattice().get_ghost_layers() < 2) {
122 if (context()->get_comm().size() > 1) {
123 throw std::runtime_error("The number of ghostlayers should be > 1 "
124 "when using flux boundaries and mpi.");
125 }
126 runtimeWarningMsg() << "The number of ghostlayers should be > 1 when "
127 "using flux boundaries and mpi.";
128 }
129 });
130 auto const flux =
131 get_value<Utils::Vector3d>(params, "value") * m_conv_flux;
132 m_ek_species->set_node_flux_boundary(m_index, flux);
133 }
134 return {};
135 }
136
137 return {};
138}
139
140} // namespace ScriptInterface::walberla
141
142#endif // ESPRESSO_WALBERLA
Vector implementation and trait types for boost qvm interoperability.
virtual void parallel_try_catch(std::function< void()> const &cb) const =0
bool is_index_valid(Utils::Vector3i const &index, Utils::Vector3i const &shape) const
Type to indicate no value in Variant.
Definition None.hpp:32
Context * context() const
Responsible context.
std::string_view name() const
Variant do_call_method(std::string const &name, VariantMap const &params) override
::LatticeWalberla const & get_lattice() const
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeWarningMsg()
void ek_throw_if_expired(std::optional< ResourceObserver > const &mpi_obs)
Definition EKSpecies.hpp:57
static bool is_boundary_all_reduce(boost::mpi::communicator const &comm, std::optional< bool > const &is_boundary)
constexpr bool is_none(Variant const &v)
Definition Variant.hpp:163
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:133
T reduce_optional(boost::mpi::communicator const &comm, std::optional< T > const &result)
Reduce an optional on the head node.
Recursive variant implementation.
Definition Variant.hpp:84