ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
scafacos.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022 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#if defined(SCAFACOS) or defined(SCAFACOS_DIPOLES)
23
26
27#include "scafacos.hpp"
28
30
31#include <utils/demangle.hpp>
32
33#include <boost/variant.hpp>
34
35#include <algorithm>
36#include <functional>
37#include <iomanip>
38#include <iterator>
39#include <optional>
40#include <sstream>
41#include <stdexcept>
42#include <string>
43#include <utility>
44#include <vector>
45
46namespace ScriptInterface {
47namespace Scafacos {
48
49std::vector<std::string> available_methods() {
51}
52
54 : public boost::static_visitor<std::vector<std::string>> {
55 auto operator()(std::string const &value) const { return result_type{value}; }
56
57 template <typename T, typename = std::enable_if_t<!std::is_arithmetic_v<T>>>
58 result_type operator()(T const &) const {
59 throw std::runtime_error("Cannot convert " + Utils::demangle<T>());
60 }
61
62 template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
63 auto operator()(T const &value) const {
64 return operator()(to_str(value));
65 }
66
67 auto operator()(double const &value) const {
68 return operator()(to_str(value));
69 }
70
71 auto operator()(result_type const &values) const { return values; }
72
73 auto operator()(std::vector<Variant> const &values) const {
74 result_type values_str;
75 for (auto const &v : values) {
76 values_str.emplace_back(boost::apply_visitor(*this, v).front());
77 }
78 return values_str;
79 }
80
81 template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
82 auto operator()(std::vector<T> const &values) const {
83 result_type values_str;
84 for (auto const &v : values) {
85 values_str.emplace_back(to_str(v));
86 }
87 return values_str;
88 }
89
90private:
91 std::string to_str(int const value) const { return std::to_string(value); }
92
93 std::string to_str(double const value) const {
94 std::ostringstream serializer;
95 serializer << std::scientific << std::setprecision(17);
96 serializer << value;
97 return serializer.str();
98 }
99};
100
102 : public boost::static_visitor<std::unordered_map<std::string, Variant>> {
103 auto operator()(result_type const &obj) const { return obj; }
104
105 template <typename T>
106 auto operator()(std::unordered_map<T, Variant> const &obj) const {
107 // handle the case of the empty dict, which can have any key type
108 return (obj.empty()) ? result_type{} : invalid(obj);
109 }
110
111 template <typename T> auto operator()(T const &obj) const {
112 return invalid(obj);
113 }
114
115private:
116 template <typename T> auto invalid(T const &obj) const {
117 return get_value<result_type>(obj);
118 }
119};
120
121std::string serialize_parameters(Variant const &pack) {
122 auto const parameters = boost::apply_visitor(GetParameterList(), pack);
123 if (parameters.empty()) {
124 throw std::invalid_argument(
125 "ScaFaCoS methods require at least 1 parameter");
126 }
127 auto const visitor = ConvertToStringVector();
128 std::string method_params = "";
129 for (auto const &kv : parameters) {
130 method_params += "," + kv.first;
131 for (auto const &value : boost::apply_visitor(visitor, kv.second)) {
132 method_params += "," + value;
133 }
134 }
135 return method_params.substr(1);
136}
137
138template <typename T>
139std::optional<Variant> string_to_number(std::string const &s) {
140 auto deserializer = std::istringstream(s);
141 T result;
142 deserializer >> result;
143 if (deserializer.fail() or not deserializer.eof()) {
144 return {};
145 }
146 return Variant{result};
147}
148
149std::unordered_map<std::string, Variant>
150deserialize_parameters(std::string const &parameters) {
151 /*
152 * ScaFaCoS parameters are serialized to a comma-separated string.
153 * Key-value pairs can be split with a look ahead: when the next
154 * item is a string, it is a parameter name and the current list
155 * of arithmetic values belong to the current parameter name.
156 * The only exception is string-valued parameters; in that case
157 * the current list of arithmetic values is empty.
158 */
159 auto const numbers = std::string("-0123456789");
160 std::unordered_map<std::string, Variant> method_params{};
161 std::vector<std::string> flat_array;
162 std::istringstream buffer;
163 buffer.str(parameters);
164 for (std::string line; std::getline(buffer, line, ',');) {
165 flat_array.emplace_back(line);
166 }
167 for (auto it = flat_array.begin(); it != flat_array.end();) {
168 auto const parameter_name = *it;
169 auto parameter_list = std::vector<Variant>{};
170 for (++it; it != flat_array.end(); ++it) {
171 if ((numbers.find(it->front()) == std::string::npos) and
172 not parameter_list.empty()) {
173 break;
174 }
175 auto result = Variant{*it};
176 if (auto converted = string_to_number<int>(*it)) {
177 result = Variant{*converted};
178 } else if (auto converted = string_to_number<double>(*it)) {
179 result = Variant{*converted};
180 }
181 parameter_list.emplace_back(result);
182 }
183 assert(not parameter_list.empty());
184 if (parameter_list.size() == 1ul) {
185 method_params[parameter_name] = parameter_list.front();
186 } else {
187 method_params[parameter_name] = Variant{std::move(parameter_list)};
188 }
189 }
190 return method_params;
191}
192
193} // namespace Scafacos
194} // namespace ScriptInterface
195
196#endif // SCAFACOS or SCAFACOS_DIPOLES
ScafacosContextBase provides the public interface of the ScaFaCoS bridge.
This file contains the defaults for ESPResSo.
std::unordered_map< std::string, Variant > deserialize_parameters(std::string const &parameters)
Convert flattened parameters to a map.
Definition scafacos.cpp:150
std::string serialize_parameters(Variant const &pack)
Flatten a parameter map.
Definition scafacos.cpp:121
std::vector< std::string > available_methods()
Fetch list of methods compiled in ScaFaCoS.
Definition scafacos.cpp:49
std::optional< Variant > string_to_number(std::string const &s)
Definition scafacos.cpp:139
PackedVariant pack(const Variant &v)
Transform a Variant to a PackedVariant.
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 std::vector< std::string > available_methods()
auto operator()(std::vector< T > const &values) const
Definition scafacos.cpp:82
auto operator()(std::vector< Variant > const &values) const
Definition scafacos.cpp:73
auto operator()(result_type const &values) const
Definition scafacos.cpp:71
auto operator()(double const &value) const
Definition scafacos.cpp:67
result_type operator()(T const &) const
Definition scafacos.cpp:58
auto operator()(std::string const &value) const
Definition scafacos.cpp:55
auto operator()(result_type const &obj) const
Definition scafacos.cpp:103
auto operator()(std::unordered_map< T, Variant > const &obj) const
Definition scafacos.cpp:106