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

Open-Sn / opensn / #3

25 Mar 2026 03:18AM UTC coverage: 74.732% (+0.8%) from 73.898%
#3

push

web-flow
Merge pull request #1000 from wdhawkins/unit_tests

Adding unit tests to improve coverage

20739 of 27751 relevant lines covered (74.73%)

66496893.77 hits per line

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

96.43
/python/lib/xs.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/runtime.h"
6
#include "framework/materials/multi_group_xs/multi_group_xs.h"
7
#include "framework/materials/multi_group_xs/xsfile.h"
8
#include <pybind11/stl.h>
9
#include <memory>
10
#include <string>
11
#include <vector>
12

13
#define XS_GETTER(method_name) [](MultiGroupXS& self) { return convert_vector(self.method_name()); }
14

15
namespace opensn
16
{
17

18
// Wrap multi-group cross section
19
void
20
WrapMultiGroupXS(py::module& xs)
681✔
21
{
22
  // clang-format off
23
  // multi-group cross section
24
  auto multigroup_xs = py::class_<MultiGroupXS, std::shared_ptr<MultiGroupXS>>(
681✔
25
    xs,
26
    "MultiGroupXS",
27
    R"(
28
    Multi-group cross section.
29

30
    Wrapper of :cpp:class:`opensn::MultiGroupXS`.
31

32
    The Python API currently has two types of methods:
33

34
    - Creation/loading methods such as ``CreateSimpleOneGroup``,
35
      ``LoadFromOpenSn``, and ``LoadFromOpenMC`` populate an existing object.
36
    - ``Scale`` mutates the current object.
37
    - ``Combine`` returns a new cross-section object and does not mutate inputs.
38
    )"
39
  );
681✔
40
  multigroup_xs.def(
1,362✔
41
    py::init(
681✔
42
      []()
905✔
43
      {
44
        std::shared_ptr<MultiGroupXS> xs = std::make_shared<MultiGroupXS>();
905✔
45
        multigroup_xs_stack.push_back(xs);
905✔
46
        return xs;
905✔
47
      }),
×
48
    "Create an empty multi-group cross section."
49
  );
50
  multigroup_xs.def(
1,362✔
51
    "CreateSimpleOneGroup",
52
    [](MultiGroupXS& self, double sigma_t, double c, double velocity) {
869✔
53
      self = MultiGroupXS::CreateSimpleOneGroup(sigma_t, c, velocity);
188✔
54
    },
188✔
55
    R"(
56
    Populate this object with a one-group cross section.
57

58
    Parameters
59
    ----------
60
    sigma_t: float
61
        Total cross section.
62
    c: float
63
        Scattering ratio.
64
    velocity: float, optional
65
        Group velocity. If provided and positive, inverse velocity
66
        is populated with 1.0/velocity.
67

68
    Notes
69
    -----
70
    This method mutates ``self`` by replacing its current contents.
71
    )",
72
    py::arg("sigma_t"),
1,362✔
73
    py::arg("c"),
681✔
74
    py::arg("velocity") = 0.0
681✔
75
  );
76
  multigroup_xs.def(
681✔
77
    "LoadFromOpenSn",
78
    [](MultiGroupXS& self, const std::string& file_name)
1,325✔
79
    {
80
      self = MultiGroupXS::LoadFromOpenSn(file_name);
644✔
81
    },
644✔
82
    py::arg("file_name"),
681✔
83
    R"(
84
    Load multi-group cross sections from an OpenSn cross section input file
85
    into this object.
86

87
    Format is as follows (for transfers, gprime denotes the departing group and g is the arrival
88
    group).
89

90
    .. code-block:: none
91

92
       # Add comment lines, as needed
93
       NUM_GROUPS ng
94
       NUM_MOMENTS nmom
95

96
       SIGMA_T_BEGIN
97
       0 value
98
       .
99
       .
100
       ng-1 value
101
       SIGMA_T_END
102

103
       SIGMA_A_BEGIN
104
       0 value
105
       .
106
       .
107
       ng-1 value
108
       SIGMA_A_END
109

110
       TRANSFER_MOMENTS_BEGIN
111
       M_GFROM_GTO_VAL 0 0 0 value
112
       .
113
       M_GFROM_GTO_VAL moment gfrom gto value
114
       .
115
       M_GFROM_GTO_VAL nmom-1 ng-1 ng-1 value
116
       TRANSFER_MOMENTS_END
117

118
    Notes
119
    -----
120
    This method mutates ``self`` by replacing its current contents.
121
    )"
122
  );
123
  multigroup_xs.def_static(
681✔
124
    "Combine",
125
    &MultiGroupXS::Combine,
1,362✔
126
    R"(
127
    Return a new combined cross-section.
128

129
    Parameters
130
    ----------
131

132
    combinations: List[Tuple[pyopensn.xs.MultiGroupXS, float]]
133
        List of ``(cross_section, density)`` pairs.
134
        The density values are linear weights used to combine raw cross sections.
135

136
    Returns
137
    -------
138
    pyopensn.xs.MultiGroupXS
139
        A new combined cross-section object. The input cross sections are not
140
        modified.
141

142
    Notes
143
    -----
144
    Let :math:`d_i` be the supplied density for cross section :math:`i`.
145

146
    - Raw XS terms are density-weighted sums:
147
      :math:`\sigma = \sum_i d_i \sigma_i`
148
      (e.g. total, absorption, fission, transfer, production).
149
    - Fission spectra and precursor yields are weighted by fissile density
150
      fraction so their sums remain normalized.
151
    - All inputs must have the same number of groups.
152
    - If inverse velocity is present, all inputs must have identical values.
153

154
    Examples
155
    --------
156

157
    >>> xs_1 = MultiGroupXS()
158
    >>> xs_1.CreateSimpleOneGroup(sigma_t=1, c=0.5)
159
    >>> xs_2 = MultiGroupXS()
160
    >>> xs_2.CreateSimpleOneGroup(sigma_t=2, c=1./3.)
161
    >>> combo = [
162
    ...     ( xs_1, 0.5 ),
163
    ...     ( xs_2, 3.0 )
164
    ... ]
165
    >>> xs_combined = MultiGroupXS.Combine(combo)
166
    )",
167
    py::arg("combinations")
681✔
168
  );
169
  multigroup_xs.def(
1,362✔
170
    "LoadFromOpenMC",
171
    [](MultiGroupXS& self,
754✔
172
       const std::string& file_name,
173
       const std::string& dataset_name,
174
       double temperature,
175
       const std::vector<std::string>& extra_xs_names)
176
    {
177
      self = MultiGroupXS::LoadFromOpenMC(file_name, dataset_name, temperature, extra_xs_names);
73✔
178
    },
73✔
179
    R"(
180
    Load multi-group cross sections from an OpenMC cross-section file into this
181
    object.
182

183
    Notes
184
    -----
185
    This method mutates ``self`` by replacing its current contents.
186
    )",
187
    py::arg("file_name"),
1,362✔
188
    py::arg("dataset_name"),
1,362✔
189
    py::arg("temperature"),
681✔
190
    py::arg("extra_xs_names") = std::vector<std::string>()
1,362✔
191
  );
192
  multigroup_xs.def(
681✔
193
    "Scale",
194
    &MultiGroupXS::Scale,
1,362✔
195
    R"(
196
    Scale the cross sections in-place.
197

198
    Notes
199
    -----
200
    Scaling does not compound. Each call scales from the original baseline data.
201
    )",
202
    py::arg("factor")
681✔
203
  );
204
  multigroup_xs.def_property_readonly(
681✔
205
    "num_groups",
206
    &MultiGroupXS::GetNumGroups,
681✔
207
    "Get number of energy groups."
208
  );
209
  multigroup_xs.def_property_readonly(
681✔
210
    "scattering_order",
211
    &MultiGroupXS::GetScatteringOrder,
681✔
212
    "Get Legendre scattering order."
213
  );
214
  multigroup_xs.def_property_readonly(
681✔
215
    "num_precursors",
216
    &MultiGroupXS::GetNumPrecursors,
681✔
217
    "Get number of precursors."
218
  );
219
  multigroup_xs.def_property_readonly(
681✔
220
    "is_fissionable",
221
    &MultiGroupXS::IsFissionable,
681✔
222
    "Check if the material is fissile."
223
  );
224
  multigroup_xs.def(
681✔
225
    "GetScaleFactor",
226
    &MultiGroupXS::GetScaleFactor,
681✔
227
    "Get the scaling factor."
228
  );
229
  multigroup_xs.def_property_readonly(
681✔
230
    "sigma_t",
231
    XS_GETTER(GetSigmaTotal),
19✔
232
    "Get total cross section.",
233
    py::keep_alive<0, 1>()
681✔
234
  );
235
  multigroup_xs.def_property_readonly(
681✔
236
    "sigma_a",
237
    XS_GETTER(GetSigmaAbsorption),
2,512✔
238
    "Get absorption cross section.",
239
    py::keep_alive<0, 1>()
681✔
240
  );
241
  multigroup_xs.def_property_readonly(
681✔
242
    "sigma_f",
243
    XS_GETTER(GetSigmaFission),
4✔
244
    "Get fission cross section.",
245
    py::keep_alive<0, 1>()
681✔
246
  );
247
  multigroup_xs.def_property_readonly(
681✔
248
    "chi",
249
    XS_GETTER(GetChi),
2✔
250
    "Get neutron fission spectrum.",
251
    py::keep_alive<0, 1>()
681✔
252
  );
253
  multigroup_xs.def_property_readonly(
681✔
254
    "nu_sigma_f",
255
    XS_GETTER(GetNuSigmaF),
28✔
256
    "Get neutron production due to fission.",
257
    py::keep_alive<0, 1>()
681✔
258
  );
259
  multigroup_xs.def_property_readonly(
681✔
260
    "nu_prompt_sigma_f",
261
    XS_GETTER(GetNuPromptSigmaF),
×
262
    "Get prompt neutron production due to fission.",
263
    py::keep_alive<0, 1>()
681✔
264
  );
265
  multigroup_xs.def_property_readonly(
681✔
266
    "nu_delayed_sigma_f",
267
    XS_GETTER(GetNuDelayedSigmaF),
×
268
    "Get delayed neutron production due to fission.",
269
    py::keep_alive<0, 1>()
681✔
270
  );
271
  multigroup_xs.def(
681✔
272
    "has_custom_xs",
273
    &MultiGroupXS::HasCustomXS,
1,362✔
274
    "Check if a custom XS is available.",
275
    py::arg("name")
681✔
276
  );
277
  multigroup_xs.def(
681✔
278
    "get_custom_xs",
279
    [](MultiGroupXS& self, const std::string& name)
682✔
280
    { return convert_vector(self.GetCustomXS(name)); },
1✔
281
    "Get a custom XS vector.",
282
    py::arg("name")
681✔
283
  );
284
  multigroup_xs.def(
681✔
285
    "custom_xs_names",
286
    &MultiGroupXS::GetCustomXSNames,
681✔
287
    "Get a list of custom XS entries."
288
  );
289
  multigroup_xs.def_property_readonly(
681✔
290
    "inv_velocity",
291
    XS_GETTER(GetInverseVelocity),
25✔
292
    "Get inverse velocity.",
293
    py::keep_alive<0, 1>()
681✔
294
  );
295
  // clang-format on
296
}
681✔
297

298
// Wrap the cross section components of OpenSn
299
void
300
py_xs(py::module& pyopensn)
72✔
301
{
302
  py::module xs = pyopensn.def_submodule("xs", "Cross section module.");
72✔
303
  WrapMultiGroupXS(xs);
72✔
304
}
72✔
305

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