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

Open-Sn / opensn / 25845198749

14 May 2026 04:45AM UTC coverage: 75.683% (-0.01%) from 75.694%
25845198749

push

github

web-flow
Merge pull request #1054 from andrsd/mpicpp-lite-2.6

Bump mpicpp-lite to 2.6.0

22303 of 29469 relevant lines covered (75.68%)

64823441.74 hits per line

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

85.85
/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)
723✔
20
{
21
  // clang-format off
22
  math.def(
723✔
23
    "Ylm",
24
    &Ylm,
1,446✔
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"),
1,446✔
40
    py::arg("m"),
1,446✔
41
    py::arg("theta"),
1,446✔
42
    py::arg("varphi")
723✔
43
  );
44
  // clang-format on
45
}
723✔
46

47
// Wrap Vector3
48
void
49
WrapVector3(py::module& math)
723✔
50
{
51
  // clang-format off
52
  auto vector3 = py::class_<Vector3, std::shared_ptr<Vector3>>(
723✔
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
  );
723✔
84
  vector3.def(
1,446✔
85
    py::init(
723✔
86
      [](double x, double y, double z)
1,185✔
87
      {
88
        return std::make_shared<Vector3>(x, y, z);
1,185✔
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,
1,446✔
104
    py::arg("y") = 0.0,
1,446✔
105
    py::arg("z") = 0.0
723✔
106
  );
107
  vector3.def_readwrite(
723✔
108
    "x",
109
    &Vector3::x,
110
    "X-coordinate."
111
  );
112
  vector3.def_readwrite(
723✔
113
    "y",
114
    &Vector3::y,
115
    "Y-coordinate."
116
  );
117
  vector3.def_readwrite(
723✔
118
    "z",
119
    &Vector3::z,
120
    "Z-coordinate."
121
  );
122
  vector3.def(
723✔
123
    "__add__",
124
    [](Vector3& self, Vector3& other)
723✔
125
    {
126
      return self + other;
×
127
    }
128
  );
129
  vector3.def(
723✔
130
    "__iadd__",
131
    [](Vector3& self, Vector3& other)
723✔
132
    {
133
      return self += other;
×
134
    }
135
  );
136
  vector3.def(
723✔
137
    "__sub__",
138
    [](Vector3& self, Vector3& other)
723✔
139
    {
140
      return self - other;
×
141
    }
142
  );
143
  vector3.def(
723✔
144
    "__isub__",
145
    [](Vector3& self, Vector3& other)
723✔
146
    {
147
      return self -= other;
×
148
    }
149
  );
150
  vector3.def(
723✔
151
    "__mul__",
152
    [](Vector3& self, double value)
723✔
153
    {
154
      return self * value;
×
155
    }
156
  );
157
  vector3.def(
723✔
158
    "__rmul__",
159
    [](Vector3& self, double value)
723✔
160
    {
161
      return self * value;
×
162
    }
163
  );
164
  vector3.def(
723✔
165
    "__imul__",
166
    [](Vector3& self, double value)
723✔
167
    {
168
      return self *= value;
×
169
    }
170
  );
171
  vector3.def(
723✔
172
    "__truediv__",
173
    [](Vector3& self, double value)
723✔
174
    {
175
      return self / value;
×
176
    }
177
  );
178
  vector3.def(
723✔
179
    "__itruediv__",
180
    [](Vector3& self, double value)
723✔
181
    {
182
      return self /= value;
×
183
    }
184
  );
185
  vector3.def(
723✔
186
    "__matmul__",
187
    [](Vector3& self, Vector3& other)
723✔
188
    {
189
      return self.Dot(other);
×
190
    }
191
  );
192
  vector3.def(
723✔
193
    "Norm",
194
    [](Vector3& self)
723✔
195
    {
196
      return self.Norm();
×
197
    }
198
  );
199
  vector3.def(
723✔
200
    "__repr__",
201
    [](Vector3& self)
723✔
202
    {
203
      std::ostringstream os;
723✔
204
      os << "Vector3(" << self.x << ", " << self.y << ", " << self.z << ")";
723✔
205
      return os.str();
1,446✔
206
    }
723✔
207
  );
208
  // clang-format on
209
}
723✔
210

211
// Wrap functors (temporary solution until the Lua interface is eradicated)
212
void
213
WrapFunctors(py::module& math)
723✔
214
{
215
  // clang-format off
216
  // vector spatial function
217
  auto vector_spatial_function = py::class_<VectorSpatialFunction, std::shared_ptr<VectorSpatialFunction>>(
723✔
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
  );
723✔
244
  vector_spatial_function.def(
723✔
245
    py::init(
723✔
246
      [](const std::function<std::vector<double>(const Vector3&, int)>& func)
×
247
      {
248
        return std::make_shared<VectorSpatialFunction>(func);
×
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")
723✔
260
  );
261
  vector_spatial_function.def(
723✔
262
    "__call__",
263
    [](VectorSpatialFunction& self, const Vector3& xyz, int num_groups)
723✔
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"),
1,446✔
278
    py::arg("num_groups")
723✔
279
  );
280

281
  // angular flux function
282
  auto angular_flux_function = py::class_<AngularFluxFunction, std::shared_ptr<AngularFluxFunction>>(
723✔
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
  );
723✔
310
  angular_flux_function.def(
723✔
311
    py::init(
723✔
312
      [](const std::function<double(int, int)>& func)
16✔
313
      {
314
        return std::make_shared<AngularFluxFunction>(func);
16✔
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")
723✔
327
  );
328
  angular_flux_function.def(
723✔
329
    "__call__",
330
    [](AngularFluxFunction& self, int group, int direction)
723✔
331
    {
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"),
1,446✔
345
    py::arg("direction")
723✔
346
  );
347

348
  // angular flux time function
349
  auto angular_flux_time_function = py::class_<AngularFluxTimeFunction,
723✔
350
                                               std::shared_ptr<AngularFluxTimeFunction>>(
351
    math,
352
    "AngularFluxTimeFunction",
353
    R"(
354
    Time-dependent angular flux function.
355

356
    Functions that accept a group index, a direction index, and time, and return the incoming
357
    angular flux value for that (group, direction, time) tuple.
358

359
    Wrapper of :cpp:class:`opensn::AngularFluxTimeFunction`.
360

361
    Examples
362
    --------
363
    >>> # Create from a Python function
364
    >>> def incident_flux(group, direction, time):
365
    ...     return 1.0 if group == 0 and time <= 0.5 else 0.0
366
    >>> f = AngularFluxTimeFunction(incident_flux)
367
    >>>
368
    >>> # Create from lambda
369
    >>> g = AngularFluxTimeFunction(lambda group, direction, time: time)
370
    >>>
371
    >>> # Evaluate
372
    >>> f(0, 3, 0.25)
373
    1.0
374
    >>> g(1, 2, 0.5)
375
    0.5
376
    )"
377
  );
723✔
378
  angular_flux_time_function.def(
723✔
379
    py::init(
723✔
380
      [](const std::function<double(int, int, double)>& func)
100✔
381
      {
382
        return std::make_shared<AngularFluxTimeFunction>(func);
100✔
383
      }
384
    ),
385
    R"(
386
    Construct a time-dependent angular flux function from a Python function or lambda.
387

388
    Parameters
389
    ----------
390
    func: Callable[[int, int, float], float]
391
        Referenced angular flux function. The arguments are energy group index, direction index,
392
        and time.
393
    )",
394
    py::arg("func")
723✔
395
  );
396
  angular_flux_time_function.def(
723✔
397
    "__call__",
398
    [](AngularFluxTimeFunction& self, int group, int direction, double time)
731✔
399
    {
400
      return self(group, direction, time);
8✔
401
    },
402
    R"(
403
    Evaluate the associated time-dependent angular flux function.
404

405
    Parameters
406
    ----------
407
    group: int
408
        Energy group index.
409
    direction: int
410
        Direction index in the angular quadrature.
411
    time: float
412
        Evaluation time.
413
    )",
414
    py::arg("group"),
1,446✔
415
    py::arg("direction"),
1,446✔
416
    py::arg("time")
723✔
417
  );
418
  // clang-format on
419
}
723✔
420

421
// Wrap the angular quadrature components of OpenSn
422
void
423
py_math(py::module& pyopensn)
72✔
424
{
425
  py::module math = pyopensn.def_submodule("math", "Math module.");
72✔
426
  WrapYlm(math);
72✔
427
  WrapVector3(math);
72✔
428
  WrapFunctors(math);
72✔
429
}
72✔
430

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