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

Open-Sn / opensn / 24437745168

15 Apr 2026 03:39AM UTC coverage: 74.813% (-0.2%) from 75.028%
24437745168

push

github

web-flow
Merge pull request #955 from wdhawkins/cepxs

Add support for CEPXS cross sections

15 of 212 new or added lines in 6 files covered. (7.08%)

319 existing lines in 10 files now uncovered.

21208 of 28348 relevant lines covered (74.81%)

65820875.2 hits per line

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

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

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

14
namespace opensn
15
{
16

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

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

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

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

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

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

84
    Format is as follows (for transfers, gprime denotes the departing group and g is the arrival
85
    group).
86

87
    .. code-block:: none
88

89
       # Add comment lines, as needed
90
       NUM_GROUPS ng
91
       NUM_MOMENTS nmom
92

93
       SIGMA_T_BEGIN
94
       0 value
95
       .
96
       .
97
       ng-1 value
98
       SIGMA_T_END
99

100
       SIGMA_A_BEGIN
101
       0 value
102
       .
103
       .
104
       ng-1 value
105
       SIGMA_A_END
106

107
       TRANSFER_MOMENTS_BEGIN
108
       M_GFROM_GTO_VAL 0 0 0 value
109
       .
110
       M_GFROM_GTO_VAL moment gfrom gto value
111
       .
112
       M_GFROM_GTO_VAL nmom-1 ng-1 ng-1 value
113
       TRANSFER_MOMENTS_END
114

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

126
    Parameters
127
    ----------
128

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

133
    Returns
134
    -------
135
    pyopensn.xs.MultiGroupXS
136
        A new combined cross-section object. The input cross sections are not
137
        modified.
138

139
    Notes
140
    -----
141
    Let :math:`d_i` be the supplied density for cross section :math:`i`.
142

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

152
    Examples
153
    --------
154

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

181
    Notes
182
    -----
183
    This method mutates ``self`` by replacing its current contents.
184
    )",
185
    py::arg("file_name"),
1,330✔
186
    py::arg("dataset_name"),
1,330✔
187
    py::arg("temperature"),
665✔
188
    py::arg("extra_xs_names") = std::vector<std::string>()
1,330✔
189
  );
190
  multigroup_xs.def(
1,330✔
191
    "LoadFromCEPXS",
192
    [](MultiGroupXS& self, const std::string& file_name, int material_id)
665✔
193
    {
NEW
194
      self = MultiGroupXS::LoadFromCEPXS(file_name, material_id);
×
NEW
195
    },
×
196
    "Load multi-group cross sections from a CEPXS cross-section file.",
197
    py::arg("file_name"),
665✔
198
    py::arg("material_id") = 0
665✔
199
  );
200
  multigroup_xs.def(
665✔
201
    "Scale",
202
    &MultiGroupXS::Scale,
1,330✔
203
    R"(
204
    Scale the cross sections in-place.
205

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

313
// Wrap the cross section components of OpenSn
314
void
315
py_xs(py::module& pyopensn)
72✔
316
{
317
  py::module xs = pyopensn.def_submodule("xs", "Cross section module.");
72✔
318
  WrapMultiGroupXS(xs);
72✔
319
}
72✔
320

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