• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-Sn / opensn / 23371558143

20 Mar 2026 05:40PM UTC coverage: 73.918% (-0.5%) from 74.407%
23371558143

push

github

web-flow
Merge pull request #980 from wdhawkins/transient_fix

Transient solver should always compute t^(n+1)

7 of 7 new or added lines in 1 file covered. (100.0%)

304 existing lines in 15 files now uncovered.

20502 of 27736 relevant lines covered (73.92%)

66612898.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.65
/python/lib/py_wrappers.h
1
// SPDX-FileCopyrightText: 2025 The OpenSn Authors <https://open-sn.github.io/opensn/>
2
// SPDX-License-Identifier: MIT
3

4
#pragma once
5

6
#include "framework/parameters/parameter_block.h"
7
#include "framework/data_types/vector.h"
8
#include <pybind11/pybind11.h>
9
#include <unordered_set>
10
#include <unordered_map>
11
#include <vector>
12

13
namespace py = pybind11;
14

15
namespace opensn
16
{
17

18
// Converter
19

20
/// Convert a C++ vector to a Python memoryview.
21
template <typename T>
22
py::memoryview
23
convert_vector(const std::vector<T>& vec)
24
{
25
  return py::memoryview::from_buffer(const_cast<T*>(vec.data()), {vec.size()}, {sizeof(T)}, true);
26
}
27

28
/// Convert an OpenSn vector to a Python memoryview.
29
template <typename T>
30
py::memoryview
31
convert_vector(const Vector<T>& vec)
32
{
33
  return py::memoryview::from_buffer(const_cast<T*>(vec.data()), {vec.size()}, {sizeof(T)}, true);
34
}
35

36
// Cast kwargs to ParameterBlock
37

38
/// Translate a Python object into a ParameterBlock.
39
ParameterBlock pyobj_to_param_block(const std::string& key, const py::object& obj);
40

41
/// Translate a Python dictionary into a ParameterBlock.
42
ParameterBlock kwargs_to_param_block(const py::kwargs& params);
43

44
// Retrieve arguments from the Python interface
45

46
/// Pop an object from kwargs with default value
47
inline py::object
48
pop_cast(py::kwargs& kwargs, const std::string& key, const py::object& default_value)
1,199✔
49
{
50
  if (kwargs.contains(key.c_str()))
1,199✔
51
  {
52
    return kwargs.attr("pop")(key);
18✔
53
  }
54
  return default_value;
1,190✔
55
}
56

57
/// Pop an object from kwargs and raise error if the key is not found
58
inline py::object
59
pop_cast(py::kwargs& kwargs, const std::string& key)
1,663✔
60
{
61
  if (!kwargs.contains(key.c_str()))
1,663✔
62
  {
63
    throw std::runtime_error("Key \"" + key + "\" must be provided.\n");
×
64
  }
65
  return kwargs.attr("pop")(key);
3,326✔
66
}
67

68
/// Extract tuple of arguments
69
template <typename... Args>
70
std::tuple<Args...>
71
extract_args_tuple(py::kwargs& kwargs,
598✔
72
                   const std::vector<std::string>& required_keys,
73
                   const std::vector<std::pair<std::string, py::object>>& optional_keys =
74
                     std::vector<std::pair<std::string, py::object>>())
75
{
76
  // check size
77
  if (required_keys.size() + optional_keys.size() != sizeof...(Args))
598✔
78
  {
79
    throw std::runtime_error(
×
80
      "Mismatch number of arguments. "
81
      "This is a dev bug, please contact OpenSn developpers for this issue!");
82
  }
83
  // initialize retriever
84
  std::size_t index = 0;
598✔
85
  auto retriever = [&](auto& arg)
5,126✔
86
  {
87
    using ArgType = std::decay_t<decltype(arg)>;
88
    if (index < required_keys.size())
89
    {
90
      const std::string& key = required_keys[index];
91
      arg = pop_cast(kwargs, key).cast<ArgType>();
92
    }
93
    else
94
    {
95
      const auto& [key, default_val] = optional_keys[index - required_keys.size()];
96
      arg = pop_cast(kwargs, key, default_val).cast<ArgType>();
97
    }
98
    ++index;
99
  };
100
  // retrieve keys
101
  std::tuple<Args...> args;
598✔
102
  std::apply([&](auto&... args) { (retriever(args), ...); }, args);
1,196✔
103
  // check for orphan keys
104
  if (!kwargs.empty())
598✔
105
  {
106
    std::ostringstream err_log;
×
107
    err_log << "Unknown arguments(s):";
×
108
    for (const auto& item : kwargs)
×
109
    {
110
      std::string key = py::str(item.first);
×
111
      err_log << " \"" << key << "\"";
×
112
    }
113
    err_log << ".";
×
114
    throw std::runtime_error(err_log.str());
×
115
  }
×
116
  return args;
598✔
UNCOV
117
}
×
118

2,264✔
119
/**
1,068✔
120
 *  \brief Construct an object from kwargs
1,068✔
121
 *  \details This function template allows construction of a C++ object from Python keyword
1,196✔
122
 *  arguments (`py::kwargs`), with enforcement of required and optional arguments.
1,196✔
123
 *  \tparam T The target class type to construct.
2,264✔
124
 *  \tparam Args The constructor argument types of T.
2,695✔
125
 *  \param kwargs Python keyword arguments provided from a Pybind11 binding.
5,390✔
126
 *  \param required_keys List of required argument names (must appear in ``kwargs``).
127
 *  \param optional_keys List of optional arguments with default values (used if not found in
128
 *  ``kwargs``).
129
 *  \note This function is meant to replace the functionality of ``InputParameters``.
130
 *  \example
131
 *  // C++ class
132
 *  class Foo {
133
 *    public:
134
 *      Foo(int a, double b, const std::string& name, bool verbose = false);
135
 *  };
136
 *
137
 *  // Pybind11 constructor wrapper
138
 *  foo.def(
139
 *    py::init(
140
 *      [](py::kwargs& params) {
141
 *        const std::vector<std::string> required_keys = {"a", "b", "name"};
142
 *        const std::vector<std::pair<std::string, py::object>> optional_keys = {
143
 *          {"verbose", py::bool_(false)}
144
 *        };
145
 *        return construct_from_kwargs<Foo, int, double, std::string, bool>(params, required_keys,
146
 *                                                                          optional_keys);
147
 *      }
148
 *    ),
149
 *    R"(
150
 *    Construct ...
151
 *
152
 *    Parameters
153
 *    ----------
154
 *    a: int
155
 *        ...
156
 *    b: float
157
 *        ...
158
 *    name: str
159
 *        ...
160
 *    verbose: bool, default=False
161
 *        ...
162
 *    )"
163
 *  );
164
 */
165
template <class T, typename... Args>
166
std::shared_ptr<T>
167
construct_from_kwargs(py::kwargs& kwargs,
168
                      const std::vector<std::string>& required_keys,
169
                      const std::vector<std::pair<std::string, py::object>>& optional_keys =
170
                        std::vector<std::pair<std::string, py::object>>())
171
{
172
  std::tuple<Args...> args = extract_args_tuple<Args...>(kwargs, required_keys, optional_keys);
173
  return std::apply(
174
    [](auto&&... unpacked_args)
175
    { return std::make_shared<T>(std::forward<decltype(unpacked_args)>(unpacked_args)...); },
176
    args);
177
}
178

179
// Module wrappers
180

181
/// Wrap the context components of OpenSn.
182
void py_context(py::module& pyopensn);
183

184
/// Wrap the angular quadrature components of OpenSn.
185
void py_aquad(py::module& pyopensn);
186
void WrapQuadraturePointPhiTheta(py::module& aquad);
187
void WrapQuadrature(py::module& aquad);
188
void WrapProductQuadrature(py::module& aquad);
189
void WrapTriangularQuadrature(py::module& aquad);
190
void WrapCurvilinearProductQuadrature(py::module& aquad);
191
void WrapSLDFEsqQuadrature(py::module& aquad);
192
void WrapLebedevQuadrature(py::module& aquad);
193

194
/// Wrap the field function components of OpenSn.
195
void py_ffunc(py::module& pyopensn);
196
void WrapFieldFunction(py::module& ffunc);
197
void WrapFieldFunctionGridBased(py::module& ffunc);
198
void WrapFieldFunctionInterpolation(py::module& ffunc);
199

200
/// Wrap the logical volume components of OpenSn.
201
void py_logvol(py::module& pyopensn);
202
void WrapLogicalVolume(py::module& logvol);
203

204
// Wrap the math components of OpenSn
205
void py_math(py::module& pyopensn);
206
void WrapYlm(py::module& math);
207
void WrapVector3(py::module& math);
208
void WrapFunctors(py::module& math);
209

210
/// Wrap the mesh components of OpenSn.
211
void py_mesh(py::module& pyopensn);
212
void WrapMesh(py::module& mesh);
213
void WrapMeshGenerator(py::module& mesh);
214
void WrapGraphPartitioner(py::module& mesh);
215

216
/// Wrap the response components of OpenSn.
217
void py_response(py::module& pyopensn);
218
void WrapResEval(py::module& response);
219

220
/// Wrap the settings components of OpenSn
221
void py_settings(py::module& pyopensn);
222

223
/// Wrap the solver components of OpenSn (unfinshed).
224
void py_solver(py::module& pyopensn);
225
void WrapProblem(py::module& slv);
226
void WrapSolver(py::module& slv);
227
void WrapLBS(py::module& slv);
228
void WrapSteadyState(py::module& slv);
229
void WrapTransient(py::module& slv);
230
void WrapNLKEigen(py::module& slv);
231
void WrapPIteration(py::module& slv);
232
void WrapDiscreteOrdinatesKEigenAcceleration(py::module& slv);
233

234
/// Wrap the source components of OpenSn.
235
void py_source(py::module& pyopensn);
236
void WrapPointSource(py::module& src);
237
void WrapVolumetricSource(py::module& src);
238

239
/// Wrap the cross section components of OpenSn.
240
void py_xs(py::module& pyopensn);
241
void WrapMultiGroupXS(py::module& xs);
242

243
} // namespace opensn
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc