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

Open-Sn / opensn / 20943481625

13 Jan 2026 01:13AM UTC coverage: 74.47% (+0.03%) from 74.437%
20943481625

push

github

web-flow
Merge pull request #892 from andrsd/issue/90-quad-order

Quadrature order, number of polar, number of azimuthal is `unsigned int`

15 of 17 new or added lines in 5 files covered. (88.24%)

248 existing lines in 10 files now uncovered.

18733 of 25155 relevant lines covered (74.47%)

66799244.41 hits per line

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

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

4
#include "python/lib/py_wrappers.h"
5
#include "framework/math/functions/function.h"
6
#include "framework/math/quadratures/angular/legendre_poly/legendrepoly.h"
7
#include "framework/data_types/vector3.h"
8
#include <pybind11/functional.h>
9
#include <pybind11/stl.h>
10
#include <memory>
11
#include <sstream>
12
#include <stdexcept>
13

14
namespace opensn
15
{
16

17
// Wrap spherical harmonics
18
void
19
WrapYlm(py::module& math)
487✔
20
{
21
  // clang-format off
22
  math.def(
487✔
23
    "Ylm",
24
    &Ylm,
974✔
25
    R"(
26
    Compute the tesseral spherical harmonics.
27

28
    Parameters
29
    ----------
30
    l: int
31
        Degree of the associated Legendre polynomial.
32
    m: int
33
        Order of the associated Legendre polynomial.
34
    theta: float
35
        Polar angle of the evaluation point.
36
    varphi: float
37
        Azimuthal angle of the evaluation point.
38
    )",
39
    py::arg("l"),
974✔
40
    py::arg("m"),
974✔
41
    py::arg("theta"),
974✔
42
    py::arg("varphi")
487✔
43
  );
44
  // clang-format on
45
}
487✔
46

47
// Wrap Vector3
48
void
49
WrapVector3(py::module& math)
487✔
50
{
51
  // clang-format off
52
  auto vector3 = py::class_<Vector3, std::shared_ptr<Vector3>>(
487✔
53
    math,
54
    "Vector3",
55
    R"(
56
    General 3-element vector structure.
57

58
    Wrapper of :cpp:class:`opensn::Vector3`.
59

60
    Examples
61
    --------
62
    >>> a = Vector3(2.0, 3.0, 6.0)
63
    >>> b = Vector3(2.0, 1.0, -1.0)
64
    >>> a + b
65
    Vector3(4, 4, 5)
66
    >>> a - b
67
    Vector3(0, 2, 7)
68
    >>> 2 * a
69
    Vector3(4, 6, 12)
70
    >>> a / 2
71
    Vector3(1, 1.5, 3)
72
    >>> a *= 2
73
    >>> a
74
    Vector3(4, 6, 12)
75
    >>> a /= 2
76
    >>> a
77
    Vector3(2, 3, 6)
78
    >>> a.Norm()
79
    7.0
80
    >>> a @ b  # scalar product
81
    1.0
82
    )"
83
  );
487✔
84
  vector3.def(
974✔
85
    py::init(
487✔
86
      [](double x, double y, double z)
1,155✔
87
      {
88
        return std::make_shared<Vector3>(x, y, z);
1,155✔
89
      }
90
    ),
91
    R"(
92
    Construct a 3-element vector object.
93

94
    Parameters
95
    ----------
96
    x: float, default=0.0
97
        X-coordinate.
98
    y: float, default=0.0
99
        Y-coordinate.
100
    z: float, default=0.0
101
        Z-coordinate.
102
    )",
103
    py::arg("x") = 0.0,
974✔
104
    py::arg("y") = 0.0,
974✔
105
    py::arg("z") = 0.0
487✔
106
  );
107
  vector3.def_readwrite(
487✔
108
    "x",
109
    &Vector3::x,
110
    "X-coordinate."
111
  );
112
  vector3.def_readwrite(
487✔
113
    "y",
114
    &Vector3::y,
115
    "Y-coordinate."
116
  );
117
  vector3.def_readwrite(
487✔
118
    "z",
119
    &Vector3::z,
120
    "Z-coordinate."
121
  );
122
  vector3.def(
487✔
123
    "__add__",
124
    [](Vector3& self, Vector3& other)
487✔
125
    {
126
      return self + other;
×
127
    }
128
  );
129
  vector3.def(
487✔
130
    "__iadd__",
131
    [](Vector3& self, Vector3& other)
487✔
132
    {
133
      return self += other;
×
134
    }
135
  );
136
  vector3.def(
487✔
137
    "__sub__",
138
    [](Vector3& self, Vector3& other)
487✔
139
    {
140
      return self - other;
×
141
    }
142
  );
143
  vector3.def(
487✔
144
    "__isub__",
145
    [](Vector3& self, Vector3& other)
487✔
146
    {
147
      return self -= other;
×
148
    }
149
  );
150
  vector3.def(
487✔
151
    "__mul__",
152
    [](Vector3& self, double value)
487✔
153
    {
154
      return self * value;
×
155
    }
156
  );
157
  vector3.def(
487✔
158
    "__rmul__",
159
    [](Vector3& self, double value)
487✔
160
    {
161
      return self * value;
×
162
    }
163
  );
164
  vector3.def(
487✔
165
    "__imul__",
166
    [](Vector3& self, double value)
487✔
167
    {
168
      return self *= value;
×
169
    }
170
  );
171
  vector3.def(
487✔
172
    "__truediv__",
173
    [](Vector3& self, double value)
487✔
174
    {
175
      return self / value;
×
176
    }
177
  );
178
  vector3.def(
487✔
179
    "__itruediv__",
180
    [](Vector3& self, double value)
487✔
181
    {
182
      return self /= value;
×
183
    }
184
  );
185
  vector3.def(
487✔
186
    "__matmul__",
187
    [](Vector3& self, Vector3& other)
487✔
188
    {
189
      return self.Dot(other);
×
190
    }
191
  );
192
  vector3.def(
487✔
193
    "Norm",
194
    [](Vector3& self)
487✔
195
    {
196
      return self.Norm();
×
197
    }
198
  );
199
  vector3.def(
487✔
200
    "__repr__",
201
    [](Vector3& self)
487✔
202
    {
203
      std::ostringstream os;
487✔
204
      os << "Vector3(" << self.x << ", " << self.y << ", " << self.z << ")";
487✔
205
      return os.str();
974✔
206
    }
487✔
207
  );
208
  // clang-format on
209
}
487✔
210

211
// Wrap functors (temporary solution until the Lua interface is eradicated)
212
void
213
WrapFunctors(py::module& math)
487✔
214
{
215
  // clang-format off
216
  // vector spatial function
217
  auto vector_spatial_function = py::class_<VectorSpatialFunction, std::shared_ptr<VectorSpatialFunction>>(
487✔
218
    math,
219
    "VectorSpatialFunction",
220
    R"(
221
    Vector spatial function.
222

223
    Functions that accept a point and a number of groups as input and return a vector (per group).
224

225
    Wrapper of :cpp:class:`opensn::VectorSpatialFunction`.
226

227
    Examples
228
    --------
229
    >>> # Create from a Python function
230
    >>> def foo(point, n_groups):
231
    ...     return [point.x * point.y] * n_groups
232
    >>> f = VectorSpatialFunction(foo)
233
    >>> 
234
    >>> # Create from lambda
235
    >>> g = VectorSpatialFunction(lambda p, n : [p.x + p.y + p.z] * n)
236
    >>> 
237
    >>> # Evaluate
238
    >>> f(Vector3(1.0, 2.0, 3.0), 2)
239
    [2.0, 2.0]
240
    >>> g(Vector3(1.0, 2.0, 3.0), 3)
241
    [6.0, 6.0, 6.0]
242
    )"
243
  );
487✔
244
  vector_spatial_function.def(
487✔
245
    py::init(
487✔
246
      [](const std::function<std::vector<double>(const Vector3&, int)>& func)
16✔
247
      {
248
        return std::make_shared<VectorSpatialFunction>(func);
16✔
249
      }
250
    ),
251
    R"(
252
    Construct a vector spatial function from associated Python function or lambda.
253

254
    Parameters
255
    ----------
256
    func: Callable[[pyopensn.math.Vector3, int], List[float]]
257
        Referenced vector spatial function.
258
    )",
259
    py::arg("func")
487✔
260
  );
261
  vector_spatial_function.def(
487✔
262
    "__call__",
263
    [](VectorSpatialFunction& self, const Vector3& xyz, int num_groups)
487✔
264
    {
265
      return self(xyz, num_groups);
×
266
    },
267
    R"(
268
    Evaluate the associated function.
269

270
    Parameters
271
    ----------
272
    xyz: pyopensn.math.Vector3
273
        The xyz coordinates of the point where the function is called.
274
    num_groups: int
275
        The number of groups.
276
    )",
277
    py::arg("xyz"),
974✔
278
    py::arg("num_groups")
487✔
279
  );
280

281
  // angular flux function
282
  auto angular_flux_function = py::class_<AngularFluxFunction, std::shared_ptr<AngularFluxFunction>>(
487✔
283
    math,
284
    "AngularFluxFunction",
285
    R"(
286
    Angular flux function.
287

288
    Functions that accept a group index and a direction index and return the incoming angular
289
    flux value for that (group, direction) pair.
290

291
    Wrapper of :cpp:class:`opensn::AngularFluxFunction`.
292

293
    Examples
294
    --------
295
    >>> # Create from a Python function
296
    >>> def incident_flux(group, direction):
297
    ...     return 1.0 if group == 0 else 0.0
298
    >>> f = AngularFluxFunction(incident_flux)
299
    >>>
300
    >>> # Create from lambda
301
    >>> g = AngularFluxFunction(lambda g, n: 0.5 * (g + n))
302
    >>>
303
    >>> # Evaluate
304
    >>> f(0, 3)
305
    1.0
306
    >>> g(1, 2)
307
    1.5
308
    )"
309
  );
487✔
310
  angular_flux_function.def(
487✔
311
    py::init(
487✔
312
      [](const std::function<double(int, int)>& func)
4✔
313
      {
314
        return std::make_shared<AngularFluxFunction>(func);
4✔
315
      }
316
    ),
317
    R"(
318
    Construct an angular flux function from a Python function or lambda.
319

320
    Parameters
321
    ----------
322
    func: Callable[[int, int], float]
323
        Referenced angular flux function. The first argument is the energy group index.
324
        The second argument is the direction index in the angular quadrature for the groupset.
325
    )",
326
    py::arg("func")
487✔
327
  );
328
  angular_flux_function.def(
487✔
329
    "__call__",
330
    [](AngularFluxFunction& self, int group, int direction)
487✔
331
    {
UNCOV
332
      return self(group, direction);
×
333
    },
334
    R"(
335
    Evaluate the associated angular flux function.
336

337
    Parameters
338
    ----------
339
    group: int
340
        Energy group index.
341
    direction: int
342
        Direction index in the angular quadrature.
343
    )",
344
    py::arg("group"),
974✔
345
    py::arg("direction")
487✔
346
  );
347
  // clang-format on
348
}
487✔
349

350
// Wrap the angular quadrature components of OpenSn
351
void
352
py_math(py::module& pyopensn)
62✔
353
{
354
  py::module math = pyopensn.def_submodule("math", "Math module.");
62✔
355
  WrapYlm(math);
62✔
356
  WrapVector3(math);
62✔
357
  WrapFunctors(math);
62✔
358
}
62✔
359

360
} // 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