From 3e45571a5b162febe3ccb0f981b0cbf7576cdaeb Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 00:24:10 +0200 Subject: [PATCH 01/51] multigroup inverse-speed data for void regions --- include/openmc/mgxs_interface.h | 2 ++ include/openmc/simulation.h | 1 + src/cell.cpp | 6 ++++++ src/mgxs_interface.cpp | 4 ++++ src/particle.cpp | 6 ++++++ src/simulation.cpp | 1 + 6 files changed, 20 insertions(+) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index da074f825ee..5afda1e3ad5 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -49,6 +49,8 @@ class MgxsInterface { // Get the group index corresponding to a continuous energy int get_group_index(double E); + int size() const { return macro_xs_.size(); } + int num_energy_groups_; int num_delayed_groups_; vector xs_names_; // available names in HDF5 file diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 9a6cf1b2131..842adbb07b8 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -34,6 +34,7 @@ extern "C" double extern "C" double k_abs_tra; //!< sum over batches of k_absorption * k_tracklength extern double log_spacing; //!< lethargy spacing for energy grid searches +extern int32_t mg_void_index; //!< index of void xs in mg data extern "C" int n_lost_particles; //!< cumulative number of lost particles extern "C" bool need_depletion_rx; //!< need to calculate depletion rx? extern "C" int restart_batch; //!< batch at which a restart job resumed diff --git a/src/cell.cpp b/src/cell.cpp index ebe28c3d2ce..1b86ef5beeb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -22,6 +22,7 @@ #include "openmc/material.h" #include "openmc/nuclide.h" #include "openmc/settings.h" +#include "openmc/simulation.h" #include "openmc/xml_interface.h" namespace openmc { @@ -397,6 +398,11 @@ CSGCell::CSGCell(pugi::xml_node cell_node) for (std::string mat : mats) { if (mat.compare("void") == 0) { material_.push_back(MATERIAL_VOID); + if (!settings::run_CE && simulation::mg_void_index < 0) + fatal_error("Could not find void data in the " + "multi-group nuclear data library. " + "Multi-group data for void regions" + " is needed for inverse-velocity data."); } else { material_.push_back(std::stoi(mat)); } diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 34f87d17984..fe6645b4ab1 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -17,6 +17,7 @@ #include "openmc/nuclide.h" #include "openmc/search.h" #include "openmc/settings.h" +#include "openmc/simulation.h" namespace openmc { @@ -108,6 +109,9 @@ void MgxsInterface::add_mgxs( fmt::format("Data for {} does not exist in provided MGXS Library", name)); } + if (name == "void") + simulation::mg_void_index = size(); + nuclides_.emplace_back( xs_grp, temperature, num_energy_groups_, num_delayed_groups_); close_group(xs_grp); diff --git a/src/particle.cpp b/src/particle.cpp index a1176abc79a..f426b54ae6c 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -66,6 +66,9 @@ double Particle::speed() const return C_LIGHT * std::sqrt(this->E() * (this->E() + 2 * mass)) / (this->E() + mass); } else { + auto mat = this->material(); + if (mat == MATERIAL_VOID) + mat = simulation::mg_void_index; auto& macro_xs = data::mg.macro_xs_[this->material()]; int macro_t = this->mg_xs_cache().t; int macro_a = macro_xs.get_angle_index(this->u()); @@ -232,6 +235,9 @@ void Particle::event_calculate_xs() macro_xs().absorption = 0.0; macro_xs().fission = 0.0; macro_xs().nu_fission = 0.0; + if (!settings::run_CE && simulation::mg_void_index > -1) { + data::mg.macro_xs_[simulation::mg_void_index].calculate_xs(*this); + } } } diff --git a/src/simulation.cpp b/src/simulation.cpp index 18e40a8bc73..f76589cdcdd 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -307,6 +307,7 @@ double keff_std; double k_col_abs {0.0}; double k_col_tra {0.0}; double k_abs_tra {0.0}; +int32_t mg_void_index {-1}; double log_spacing; int n_lost_particles {0}; bool need_depletion_rx {false}; From 1d19ba00064299ce4e26dab58b8b9a278036f941 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 01:06:40 +0200 Subject: [PATCH 02/51] wip --- openmc/mgxs_library.py | 78 +++++++++++++++++++++++++++++++++++++++--- src/cell.cpp | 7 ++-- src/particle.cpp | 11 ++++-- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index c1a15998e19..13098ddd3f0 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -177,7 +177,9 @@ class XSdata: def __init__(self, name, energy_groups, temperatures=[ROOM_TEMPERATURE_KELVIN], representation=REPRESENTATION_ISOTROPIC, num_delayed_groups=0): - # Initialize class attributes + self._is_void = False + + #Initialize class attributes self.name = name self.energy_groups = energy_groups self.num_delayed_groups = num_delayed_groups @@ -260,6 +262,9 @@ def name(self): def name(self, name): check_type('name for XSdata', name, str) + if name == 'void': + self._is_void = True + self._name = name @property @@ -481,6 +486,8 @@ def add_temperature(self, temperature): Temperature (in units of Kelvin) of the provided dataset. """ + if self._is_void: + raise TypeError('Cannot add temperatures to a void xs') check_type('temperature', temperature, Real) @@ -532,6 +539,8 @@ def set_total(self, total, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_total_mgxs() """ + if self._is_void: + raise TypeError('Cannot set total xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -561,6 +570,8 @@ def set_absorption(self, absorption, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_absorption_mgxs() """ + if self._is_void: + raise TypeError('Cannot set absorption xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -590,6 +601,8 @@ def set_fission(self, fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_fission_mgxs() """ + if self._is_void: + raise TypeError('Cannot set fission xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -621,6 +634,8 @@ def set_kappa_fission(self, kappa_fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_kappa_fission_mgxs() """ + if self._is_void: + raise TypeError('Cannot set kappa-fission xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -652,6 +667,8 @@ def set_chi(self, chi, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_mgxs() """ + if self._is_void: + raise TypeError('Cannot set chi in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"]] @@ -681,6 +698,8 @@ def set_chi_prompt(self, chi_prompt, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_prompt_mgxs() """ + if self._is_void: + raise TypeError('Cannot set chi-prompt in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"]] @@ -710,6 +729,8 @@ def set_chi_delayed(self, chi_delayed, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_delayed_mgxs() """ + if self._is_void: + raise TypeError('Cannot set chi-delayed in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"], self.xs_shapes["[DG][G']"]] @@ -741,6 +762,8 @@ def set_beta(self, beta, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_beta_mgxs() """ + if self._is_void: + raise TypeError('Cannot set beta in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG]"], self.xs_shapes["[DG][G]"]] @@ -770,6 +793,8 @@ def set_decay_rate(self, decay_rate, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_decay_rate_mgxs() """ + if self._is_void: + raise TypeError('Cannot set decay rate in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG]"]] @@ -799,6 +824,8 @@ def set_scatter_matrix(self, scatter, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_scatter_matrix_mgxs() """ + if self._is_void: + raise TypeError('Cannot set scatter matrix in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G][G'][Order]"]] @@ -830,6 +857,8 @@ def set_multiplicity_matrix(self, multiplicity, temperature=ROOM_TEMPERATURE_KEL openmc.mgxs_library.set_multiplicity_matrix_mgxs() """ + if self._is_void: + raise TypeError('Cannot set multiplicity matrix in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G][G']"]] @@ -861,6 +890,8 @@ def set_nu_fission(self, nu_fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_nu_fission_mgxs() """ + if self._is_void: + raise TypeError('Cannot set nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"], self.xs_shapes["[G][G']"]] @@ -893,6 +924,8 @@ def set_prompt_nu_fission(self, prompt_nu_fission, temperature=ROOM_TEMPERATURE_ openmc.mgxs_library.set_prompt_nu_fission_mgxs() """ + if self._is_void: + raise TypeError('Cannot set prompt nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"], self.xs_shapes["[G][G']"]] @@ -925,6 +958,8 @@ def set_delayed_nu_fission(self, delayed_nu_fission, temperature=ROOM_TEMPERATUR openmc.mgxs_library.set_delayed_nu_fission_mgxs() """ + if self._is_void: + raise TypeError('Cannot set delayed nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG][G]"], self.xs_shapes["[DG][G][G']"]] @@ -996,6 +1031,8 @@ def set_total_mgxs(self, total, temperature=ROOM_TEMPERATURE_KELVIN, nuclide='to openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set total xs in a void') check_type('total', total, (openmc.mgxs.TotalXS, openmc.mgxs.TransportXS)) @@ -1036,6 +1073,8 @@ def set_absorption_mgxs(self, absorption, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set absorption xs in a void') check_type('absorption', absorption, openmc.mgxs.AbsorptionXS) check_value('energy_groups', absorption.energy_groups, @@ -1078,6 +1117,8 @@ def set_fission_mgxs(self, fission, temperature=ROOM_TEMPERATURE_KELVIN, nuclide openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set fission in a void') check_type('fission', fission, openmc.mgxs.FissionXS) check_value('energy_groups', fission.energy_groups, @@ -1120,6 +1161,8 @@ def set_nu_fission_mgxs(self, nu_fission, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set nu-fission in a void') check_type('nu_fission', nu_fission, (openmc.mgxs.FissionXS, openmc.mgxs.NuFissionMatrixXS)) @@ -1171,6 +1214,8 @@ def set_prompt_nu_fission_mgxs(self, prompt_nu_fission, temperature=ROOM_TEMPERA openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set prompt nu-fission in a void') check_type('prompt_nu_fission', prompt_nu_fission, (openmc.mgxs.FissionXS, openmc.mgxs.NuFissionMatrixXS)) @@ -1218,6 +1263,8 @@ def set_delayed_nu_fission_mgxs(self, delayed_nu_fission, temperature=ROOM_TEMPE openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set delayed nu-fission in a void') check_type('delayed_nu_fission', delayed_nu_fission, (openmc.mgxs.DelayedNuFissionXS, @@ -1267,6 +1314,8 @@ def set_kappa_fission_mgxs(self, k_fission, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set kappa-fission in a void') check_type('kappa_fission', k_fission, openmc.mgxs.KappaFissionXS) check_value('energy_groups', k_fission.energy_groups, @@ -1308,6 +1357,8 @@ def set_chi_mgxs(self, chi, temperature=ROOM_TEMPERATURE_KELVIN, nuclide='total' openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set chi in a void') check_type('chi', chi, openmc.mgxs.Chi) check_value('energy_groups', chi.energy_groups, [self.energy_groups]) @@ -1346,6 +1397,8 @@ def set_chi_prompt_mgxs(self, chi_prompt, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set prompt chi in a void') check_type('chi_prompt', chi_prompt, openmc.mgxs.Chi) check_value('prompt', chi_prompt.prompt, [True]) @@ -1388,6 +1441,8 @@ def set_chi_delayed_mgxs(self, chi_delayed, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set delayed chi in a void') check_type('chi_delayed', chi_delayed, openmc.mgxs.ChiDelayed) check_value('energy_groups', chi_delayed.energy_groups, @@ -1431,6 +1486,8 @@ def set_beta_mgxs(self, beta, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set beta in a void') check_type('beta', beta, openmc.mgxs.Beta) check_value('num_delayed_groups', beta.num_delayed_groups, @@ -1471,6 +1528,8 @@ def set_decay_rate_mgxs(self, decay_rate, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set decay rate in a void') check_type('decay_rate', decay_rate, openmc.mgxs.DecayRate) check_value('num_delayed_groups', decay_rate.num_delayed_groups, @@ -1516,6 +1575,8 @@ def set_scatter_matrix_mgxs(self, scatter, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set scatter matrix in a void') check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS) check_value('energy_groups', scatter.energy_groups, @@ -1604,6 +1665,8 @@ def set_multiplicity_matrix_mgxs(self, nuscatter, scatter=None, openmc.mgxs.Library.get_xsdata() """ + if self._is_void: + raise TypeError('Cannot set multiplicity matrix in a void') check_type('nuscatter', nuscatter, (openmc.mgxs.ScatterMatrixXS, openmc.mgxs.MultiplicityMatrixXS)) @@ -1992,6 +2055,15 @@ def to_hdf5(self, file): xs_grp = grp.create_group(str(int(np.round(temperature))) + "K") + # Add the kinetics data + if self._inverse_velocity[i] is not None: + xs_grp.create_dataset("inverse-velocity", + data=self._inverse_velocity[i]) + elif self._is_void: + raise TypeError('Void mgxs must have inverse-velocity data.') + + if self._is_void: continue + if self._total[i] is None: raise ValueError('total data must be provided when writing ' 'the HDF5 library') @@ -2141,10 +2213,6 @@ def to_hdf5(self, file): scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0]) scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1]) - # Add the kinetics data - if self._inverse_velocity[i] is not None: - xs_grp.create_dataset("inverse-velocity", - data=self._inverse_velocity[i]) @classmethod def from_hdf5(cls, group, name, energy_groups, num_delayed_groups): diff --git a/src/cell.cpp b/src/cell.cpp index 1b86ef5beeb..235be310b97 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -399,10 +399,9 @@ CSGCell::CSGCell(pugi::xml_node cell_node) if (mat.compare("void") == 0) { material_.push_back(MATERIAL_VOID); if (!settings::run_CE && simulation::mg_void_index < 0) - fatal_error("Could not find void data in the " - "multi-group nuclear data library. " - "Multi-group data for void regions" - " is needed for inverse-velocity data."); + warning("Void data is not available in the " + "multi-group nuclear data library. " + "Time related calculation results might be wrong!"); } else { material_.push_back(std::stoi(mat)); } diff --git a/src/particle.cpp b/src/particle.cpp index f426b54ae6c..686faea0b9c 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -67,9 +67,14 @@ double Particle::speed() const (this->E() + mass); } else { auto mat = this->material(); - if (mat == MATERIAL_VOID) - mat = simulation::mg_void_index; - auto& macro_xs = data::mg.macro_xs_[this->material()]; + if (mat == MATERIAL_VOID) { + if (simulation::mg_void_index > -1) { + mat = simulation::mg_void_index; + } else { + return 0.0; + } + } + auto& macro_xs = data::mg.macro_xs_[mat]; int macro_t = this->mg_xs_cache().t; int macro_a = macro_xs.get_angle_index(this->u()); return 1.0 / macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, this->g(), nullptr, From 6c51c14f30d7e69f3749c10fb6db3092a126dc76 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 01:18:17 +0200 Subject: [PATCH 03/51] add another warning --- src/xsdata.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 1929f51e6fa..23b9960f5bc 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -96,6 +96,11 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, read_nd_vector(xsdata_grp, "absorption", absorption, true); read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); + if (!object_exists(xsdata_grp, "inverse-velocity")) { + warning("Inverse-velocity is not available in XsData " + "Time related calculation results might be wrong!"); + } + // Get scattering data scatter_from_hdf5( xsdata_grp, n_ang, scatter_format, final_scatter_format, order_data); From 51dfb7653801afff3bc77e01434d2e174c6a2ea8 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:10:27 +0200 Subject: [PATCH 04/51] wip --- include/openmc/mgxs_interface.h | 3 +-- include/openmc/simulation.h | 1 - openmc/mgxs_library.py | 4 +++- src/cell.cpp | 5 ++--- src/mgxs_interface.cpp | 28 ++++++++++++++++++++++++---- src/particle.cpp | 7 ++----- src/simulation.cpp | 1 - 7 files changed, 32 insertions(+), 17 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 5afda1e3ad5..71072056778 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -49,8 +49,6 @@ class MgxsInterface { // Get the group index corresponding to a continuous energy int get_group_index(double E); - int size() const { return macro_xs_.size(); } - int num_energy_groups_; int num_delayed_groups_; vector xs_names_; // available names in HDF5 file @@ -63,6 +61,7 @@ class MgxsInterface { vector energy_bin_avg_; vector rev_energy_bins_; vector> nuc_temps_; // all available temperatures + vecotr void_velocities_; // velocity of particles in void regions }; namespace data { diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 842adbb07b8..9a6cf1b2131 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -34,7 +34,6 @@ extern "C" double extern "C" double k_abs_tra; //!< sum over batches of k_absorption * k_tracklength extern double log_spacing; //!< lethargy spacing for energy grid searches -extern int32_t mg_void_index; //!< index of void xs in mg data extern "C" int n_lost_particles; //!< cumulative number of lost particles extern "C" bool need_depletion_rx; //!< need to calculate depletion rx? extern "C" int restart_batch; //!< batch at which a restart job resumed diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 13098ddd3f0..a02e05ec3f7 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -11,7 +11,7 @@ import openmc.mgxs from openmc.mgxs import SCATTER_TABULAR, SCATTER_LEGENDRE, SCATTER_HISTOGRAM from .checkvalue import check_type, check_value, check_greater_than, \ - check_iterable_type, check_less_than, check_filetype_version, PathLike + check_iterable_type, check_length, check_less_than, check_filetype_version, PathLike ROOM_TEMPERATURE_KELVIN = 294.0 @@ -327,6 +327,8 @@ def temperatures(self): @temperatures.setter def temperatures(self, temperatures): + if self._is_void: + check_length('temperatures', temperatures, 1, 1) check_iterable_type('temperatures', temperatures, Real) self._temperatures = np.array(temperatures) diff --git a/src/cell.cpp b/src/cell.cpp index 235be310b97..0664ccd9f2a 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -22,7 +22,6 @@ #include "openmc/material.h" #include "openmc/nuclide.h" #include "openmc/settings.h" -#include "openmc/simulation.h" #include "openmc/xml_interface.h" namespace openmc { @@ -398,8 +397,8 @@ CSGCell::CSGCell(pugi::xml_node cell_node) for (std::string mat : mats) { if (mat.compare("void") == 0) { material_.push_back(MATERIAL_VOID); - if (!settings::run_CE && simulation::mg_void_index < 0) - warning("Void data is not available in the " + if (!settings::run_CE && mg::void_velocities_.empty()) + warning("Void inverse-velocity data is not available in the " "multi-group nuclear data library. " "Time related calculation results might be wrong!"); } else { diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index fe6645b4ab1..d71beafe679 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -17,7 +17,6 @@ #include "openmc/nuclide.h" #include "openmc/search.h" #include "openmc/settings.h" -#include "openmc/simulation.h" namespace openmc { @@ -83,6 +82,30 @@ void MgxsInterface::init() "supported by OpenMC."); } + // Read void velocities + if (object_exists(file_id, "void")) { + auto void_grp = open_group(file_id, "void"); + // Determine the available temperatures + hid_t kT_group = open_group(void_grp, "kTs"); + size_t num_temps = get_num_datasets(kT_group); + char** dset_names = new char*[num_temps]; + for (int i = 0; i < num_temps; i++) { + dset_names[i] = new char[151]; + } + get_datasets(kT_group, dset_names); + if (num_temps > 1) + fatal_error("Multigroup void data must have only one dummy temperature"); + xsdata_grp = open_group(kT_group, dset_names[0]); + auto inverse_velocity = xt::zeros({ + num_energy_groups_, + }); + read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); + auto velocity = 1.0 / inverse_velocity; + for (double v : velocity) { + void_velocities_.push_back(v); + } + } + // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES for (unsigned i_nuc = 0; i_nuc < xs_to_read_.size(); ++i_nuc) @@ -109,9 +132,6 @@ void MgxsInterface::add_mgxs( fmt::format("Data for {} does not exist in provided MGXS Library", name)); } - if (name == "void") - simulation::mg_void_index = size(); - nuclides_.emplace_back( xs_grp, temperature, num_energy_groups_, num_delayed_groups_); close_group(xs_grp); diff --git a/src/particle.cpp b/src/particle.cpp index 686faea0b9c..f1146d5d0d7 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -68,8 +68,8 @@ double Particle::speed() const } else { auto mat = this->material(); if (mat == MATERIAL_VOID) { - if (simulation::mg_void_index > -1) { - mat = simulation::mg_void_index; + if (!mg::void_velocities_.empty()) { + return mg::void_velocities_[this->g()]; } else { return 0.0; } @@ -240,9 +240,6 @@ void Particle::event_calculate_xs() macro_xs().absorption = 0.0; macro_xs().fission = 0.0; macro_xs().nu_fission = 0.0; - if (!settings::run_CE && simulation::mg_void_index > -1) { - data::mg.macro_xs_[simulation::mg_void_index].calculate_xs(*this); - } } } diff --git a/src/simulation.cpp b/src/simulation.cpp index f76589cdcdd..18e40a8bc73 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -307,7 +307,6 @@ double keff_std; double k_col_abs {0.0}; double k_col_tra {0.0}; double k_abs_tra {0.0}; -int32_t mg_void_index {-1}; double log_spacing; int n_lost_particles {0}; bool need_depletion_rx {false}; From 3d22ce7e4adb3234bef771c983ba8ef6baa24814 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:12:04 +0200 Subject: [PATCH 05/51] fix typo and import --- include/openmc/mgxs_interface.h | 2 +- src/cell.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 71072056778..893ad1c1889 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -61,7 +61,7 @@ class MgxsInterface { vector energy_bin_avg_; vector rev_energy_bins_; vector> nuc_temps_; // all available temperatures - vecotr void_velocities_; // velocity of particles in void regions + vector void_velocities_; // velocity of particles in void regions }; namespace data { diff --git a/src/cell.cpp b/src/cell.cpp index 0664ccd9f2a..59aed8b82df 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -20,6 +20,7 @@ #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" #include "openmc/material.h" +#include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/settings.h" #include "openmc/xml_interface.h" From a1b09c271bcfd4629e1bfe05a048513f4b239387 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:14:18 +0200 Subject: [PATCH 06/51] fix typo --- src/cell.cpp | 2 +- src/mgxs_interface.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 59aed8b82df..63629e3ee49 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -398,7 +398,7 @@ CSGCell::CSGCell(pugi::xml_node cell_node) for (std::string mat : mats) { if (mat.compare("void") == 0) { material_.push_back(MATERIAL_VOID); - if (!settings::run_CE && mg::void_velocities_.empty()) + if (!settings::run_CE && data::mg.void_velocities_.empty()) warning("Void inverse-velocity data is not available in the " "multi-group nuclear data library. " "Time related calculation results might be wrong!"); diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index d71beafe679..0a647929a88 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -95,7 +95,7 @@ void MgxsInterface::init() get_datasets(kT_group, dset_names); if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); - xsdata_grp = open_group(kT_group, dset_names[0]); + auto xsdata_grp = open_group(kT_group, dset_names[0]); auto inverse_velocity = xt::zeros({ num_energy_groups_, }); From 7ac31b32f41068b661e27b43f6bdda23ff722372 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:25:29 +0200 Subject: [PATCH 07/51] fix typo --- src/mgxs_interface.cpp | 5 ++--- src/particle.cpp | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 0a647929a88..81a82312298 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -96,9 +96,8 @@ void MgxsInterface::init() if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); auto xsdata_grp = open_group(kT_group, dset_names[0]); - auto inverse_velocity = xt::zeros({ - num_energy_groups_, - }); + vector shape {1, num_energy_groups_}; + xt::xtensor inverse_velocity = xt::zeros(shape); read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); auto velocity = 1.0 / inverse_velocity; for (double v : velocity) { diff --git a/src/particle.cpp b/src/particle.cpp index f1146d5d0d7..531673af193 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -68,8 +68,8 @@ double Particle::speed() const } else { auto mat = this->material(); if (mat == MATERIAL_VOID) { - if (!mg::void_velocities_.empty()) { - return mg::void_velocities_[this->g()]; + if (!data::mg.void_velocities_.empty()) { + return data::mg.void_velocities_[this->g()]; } else { return 0.0; } From 6e358d18b352c8d59a434039d0234807b9c0e8ce Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:27:30 +0200 Subject: [PATCH 08/51] fix typo --- src/mgxs_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 81a82312298..1dfb2980e88 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -95,7 +95,7 @@ void MgxsInterface::init() get_datasets(kT_group, dset_names); if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); - auto xsdata_grp = open_group(kT_group, dset_names[0]); + auto xsdata_grp = open_group(void_grp, dset_names[0]); vector shape {1, num_energy_groups_}; xt::xtensor inverse_velocity = xt::zeros(shape); read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); From ba43542149ac04b7932b98c218785839af92a0b5 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 02:36:51 +0200 Subject: [PATCH 09/51] move around code --- src/mgxs_interface.cpp | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 1dfb2980e88..77858c43af7 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -82,29 +82,6 @@ void MgxsInterface::init() "supported by OpenMC."); } - // Read void velocities - if (object_exists(file_id, "void")) { - auto void_grp = open_group(file_id, "void"); - // Determine the available temperatures - hid_t kT_group = open_group(void_grp, "kTs"); - size_t num_temps = get_num_datasets(kT_group); - char** dset_names = new char*[num_temps]; - for (int i = 0; i < num_temps; i++) { - dset_names[i] = new char[151]; - } - get_datasets(kT_group, dset_names); - if (num_temps > 1) - fatal_error("Multigroup void data must have only one dummy temperature"); - auto xsdata_grp = open_group(void_grp, dset_names[0]); - vector shape {1, num_energy_groups_}; - xt::xtensor inverse_velocity = xt::zeros(shape); - read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); - auto velocity = 1.0 / inverse_velocity; - for (double v : velocity) { - void_velocities_.push_back(v); - } - } - // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES for (unsigned i_nuc = 0; i_nuc < xs_to_read_.size(); ++i_nuc) @@ -260,6 +237,29 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) "library file!"); } + // Read void velocities + if (object_exists(file_id, "void")) { + auto void_grp = open_group(file_id, "void"); + // Determine the available temperatures + hid_t kT_group = open_group(void_grp, "kTs"); + size_t num_temps = get_num_datasets(kT_group); + char** dset_names = new char*[num_temps]; + for (int i = 0; i < num_temps; i++) { + dset_names[i] = new char[151]; + } + get_datasets(kT_group, dset_names); + if (num_temps > 1) + fatal_error("Multigroup void data must have only one dummy temperature"); + auto xsdata_grp = open_group(void_grp, dset_names[0]); + vector shape {1, num_energy_groups_}; + xt::xtensor inverse_velocity = xt::zeros(shape); + read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); + auto velocity = 1.0 / inverse_velocity; + for (double v : velocity) { + void_velocities_.push_back(v); + } + } + // Close MGXS HDF5 file file_close(file_id); } From 59c0b50a15c57da83352dd6ddb3cbf6ff7416984 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 04:31:04 +0200 Subject: [PATCH 10/51] rename void to approx void in random ray example --- openmc/examples.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmc/examples.py b/openmc/examples.py index 350a4d24d5e..b53d22c6a05 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -1061,7 +1061,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): void_sigma_a = 4.0e-6 void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('void', groups) + void_mat_data = openmc.XSdata('approx void', groups) void_mat_data.order = 0 void_mat_data.set_total([void_sigma_a + void_sigma_s]) void_mat_data.set_absorption([void_sigma_a]) @@ -1097,7 +1097,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): # Instantiate some Macroscopic Data source_data = openmc.Macroscopic('source') - void_data = openmc.Macroscopic('void') + void_data = openmc.Macroscopic('approx void') absorber_data = openmc.Macroscopic('absorber') # Instantiate some Materials and register the appropriate Macroscopic objects @@ -1105,7 +1105,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): source_mat.set_density('macro', 1.0) source_mat.add_macroscopic(source_data) - void_mat = openmc.Material(name='void') + void_mat = openmc.Material(name='approx void') void_mat.set_density('macro', 1.0) void_mat.add_macroscopic(void_data) From 6568952a6c6382f2b3252069c1063a05fef0b4ca Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 07:32:21 +0200 Subject: [PATCH 11/51] update inputs --- .../random_ray_adjoint_fixed_source/inputs_true.dat | 4 ++-- .../random_ray_cell_density/fs/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_domain/cell/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_domain/material/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_domain/universe/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_linear/linear/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_linear/linear_xy/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_mesh/flat/inputs_true.dat | 4 ++-- .../random_ray_fixed_source_mesh/linear/inputs_true.dat | 4 ++-- .../False/inputs_true.dat | 4 ++-- .../True/inputs_true.dat | 4 ++-- tests/regression_tests/random_ray_low_density/inputs_true.dat | 4 ++-- tests/regression_tests/random_ray_low_density/test.py | 2 +- .../random_ray_point_source_locator/inputs_true.dat | 4 ++-- tests/regression_tests/random_ray_void/flat/inputs_true.dat | 4 ++-- tests/regression_tests/random_ray_void/linear/inputs_true.dat | 4 ++-- .../random_ray_volume_estimator/hybrid/inputs_true.dat | 4 ++-- .../random_ray_volume_estimator/naive/inputs_true.dat | 4 ++-- .../simulation_averaged/inputs_true.dat | 4 ++-- .../random_ray_volume_estimator_linear/hybrid/inputs_true.dat | 4 ++-- .../random_ray_volume_estimator_linear/naive/inputs_true.dat | 4 ++-- .../simulation_averaged/inputs_true.dat | 4 ++-- tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat | 4 ++-- .../weightwindows_fw_cadis_mesh/flat/inputs_true.dat | 4 ++-- .../weightwindows_fw_cadis_mesh/linear/inputs_true.dat | 4 ++-- 25 files changed, 49 insertions(+), 49 deletions(-) diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat b/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat index 0adfc548848..74937ce13e8 100644 --- a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat +++ b/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat b/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat index e90f25973e2..f8ebc855b3a 100644 --- a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat +++ b/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat index 9f1987f3acc..f58da8d57be 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat index b4f57dbfa8a..5c455d3608a 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat index ab91f74e50d..9a9b2aebb5b 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat index 220fa7db643..e22d48466a5 100644 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat index f8c4430852f..dbf29b9ae54 100644 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat index c84e544fcc4..219ccddb0d3 100644 --- a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat index 05c4846e6b4..f9593f4139e 100644 --- a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat index 0c870e10067..037c66b0488 100644 --- a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat index ab91f74e50d..9a9b2aebb5b 100644 --- a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_low_density/inputs_true.dat b/tests/regression_tests/random_ray_low_density/inputs_true.dat index ab91f74e50d..9a9b2aebb5b 100644 --- a/tests/regression_tests/random_ray_low_density/inputs_true.dat +++ b/tests/regression_tests/random_ray_low_density/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_low_density/test.py b/tests/regression_tests/random_ray_low_density/test.py index 1b4ffb78183..fa594e2cee0 100644 --- a/tests/regression_tests/random_ray_low_density/test.py +++ b/tests/regression_tests/random_ray_low_density/test.py @@ -25,7 +25,7 @@ def test_random_ray_low_density(): void_sigma_a = 4.0e-6 void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('void', groups) + void_mat_data = openmc.XSdata('approx void', groups) void_mat_data.order = 0 void_mat_data.set_total([void_sigma_a + void_sigma_s]) void_mat_data.set_absorption([void_sigma_a]) diff --git a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat b/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat index 088f803bfa8..3ef0b0ff985 100644 --- a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat +++ b/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_void/flat/inputs_true.dat b/tests/regression_tests/random_ray_void/flat/inputs_true.dat index aa28e7b68bf..22a5f22678b 100644 --- a/tests/regression_tests/random_ray_void/flat/inputs_true.dat +++ b/tests/regression_tests/random_ray_void/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_void/linear/inputs_true.dat b/tests/regression_tests/random_ray_void/linear/inputs_true.dat index e4b2f22fa27..7a33bee6049 100644 --- a/tests/regression_tests/random_ray_void/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_void/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat index 8e8a8ed9b81..255a2730ec5 100644 --- a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat index 1e25b97da66..0806732be55 100644 --- a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat index 78c16269763..f2c60ed8ab4 100644 --- a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat index 47a8a718249..9a9a3c6c695 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat index 80a9ada4d5b..dd250bfc483 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat index 4f032a62a82..0b383945c75 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat index 5fa6505ddf4..b0864454101 100644 --- a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat index ceb89e6e34c..e093825cf22 100644 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat index c7691e950c4..9a058a2362f 100644 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + From fb469c6f1c72128a77721911428faeada4e368c5 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 4 Feb 2026 12:13:26 +0200 Subject: [PATCH 12/51] more fixes --- openmc/mgxs_library.py | 1 + src/mgxs_interface.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index a02e05ec3f7..01a8a2b6b5c 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -214,6 +214,7 @@ def __deepcopy__(self, memo): # If this is the first time we have tried to copy this object, copy it if existing is None: clone = type(self).__new__(type(self)) + clone._is_void = self._is_void clone._name = self.name clone._energy_groups = copy.deepcopy(self.energy_groups, memo) clone._num_delayed_groups = self.num_delayed_groups diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 77858c43af7..70928d6b743 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -251,7 +251,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); auto xsdata_grp = open_group(void_grp, dset_names[0]); - vector shape {1, num_energy_groups_}; + vector shape {1, static_cast(num_energy_groups_)}; xt::xtensor inverse_velocity = xt::zeros(shape); read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); auto velocity = 1.0 / inverse_velocity; From 5672eacdb61bf7d5601f0a6194e4eeb42b71b8d7 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Feb 2026 18:00:37 +0200 Subject: [PATCH 13/51] use default velocity approx when imberse velocity data is missing --- src/mgxs_interface.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 70928d6b743..51a021ce555 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -258,6 +258,17 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) for (double v : velocity) { void_velocities_.push_back(v); } + } else { + for (int i = 0; i < energy_bins_.size() - 1; ++i) { + double e_min = energy_bins_[i]; + double e_max = energy_bins_[i + 1]; + double v = C_LIGHT * std::log(e_max / e_min) / + (std::acosh(1 + e_max / MASS_NEUTRON_EV) - + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - + std::acosh(1 + e_min / MASS_NEUTRON_EV) + + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)); + void_velocities_.push_back(v); + } } // Close MGXS HDF5 file From 9ef5648ad318f254587fbd6d1a269ccf8ac30efa Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Feb 2026 18:36:51 +0200 Subject: [PATCH 14/51] wip --- src/mgxs.cpp | 9 +++++---- src/mgxs_interface.cpp | 2 +- src/xsdata.cpp | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index a2c479f2156..a7e38508e6e 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -271,9 +271,9 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, //============================================================================== -Mgxs::Mgxs( - hid_t xs_id, const vector& temperature, int num_group, int num_delay) - : num_groups(num_group), num_delayed_groups(num_delay) +Mgxs::Mgxs(hid_t xs_id, const vector& temperature, + const vector& energy_bins, int num_delay) + : num_groups(energy_bins.size()), num_delayed_groups(num_delay) { // Call generic data gathering routine (will populate the metadata) int order_data; @@ -296,7 +296,8 @@ Mgxs::Mgxs( hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, - final_scatter_format, order_data, is_isotropic, n_pol, n_azi); + final_scatter_format, order_data, is_isotropic, n_pol, n_azi, + energy_bins); close_group(xsdata_grp); } // end temperature loop diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 51a021ce555..23a326f6bd8 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -109,7 +109,7 @@ void MgxsInterface::add_mgxs( } nuclides_.emplace_back( - xs_grp, temperature, num_energy_groups_, num_delayed_groups_); + xs_grp, temperature, energy_groups_, num_delayed_groups_); close_group(xs_grp); } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 23b9960f5bc..250f5064bb0 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -81,7 +81,7 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, AngleDistributionType final_scatter_format, int order_data, bool is_isotropic, - int n_pol, int n_azi) + int n_pol, int n_azi, const vector& energy_bins) { // Reconstruct the dimension information so it doesn't need to be passed size_t n_ang = n_pol * n_azi; From 05abd9c9f6a48f142c1a038e45569beb245b997f Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Feb 2026 18:57:18 +0200 Subject: [PATCH 15/51] wip --- include/openmc/mgxs.h | 6 +++--- src/mgxs_interface.cpp | 2 +- src/xsdata.cpp | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 9b1602f299a..0a031fd24c9 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -95,10 +95,10 @@ class Mgxs { //! //! @param xs_id HDF5 group id for the cross section data. //! @param temperature Temperatures to read. - //! @param num_group number of energy groups + //! @param energy_bins energy bins //! @param num_delay number of delayed groups - Mgxs(hid_t xs_id, const vector& temperature, int num_group, - int num_delay); + Mgxs(hid_t xs_id, const vector& temperature, + const vector& energy_bins, int num_delay); //! \brief Constructor that initializes and populates all data to build a //! macroscopic cross section from microscopic cross sections. diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 23a326f6bd8..1da998dc172 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -109,7 +109,7 @@ void MgxsInterface::add_mgxs( } nuclides_.emplace_back( - xs_grp, temperature, energy_groups_, num_delayed_groups_); + xs_grp, temperature, energy_bins_, num_delayed_groups_); close_group(xs_grp); } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 250f5064bb0..538bb94f068 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -97,8 +97,18 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); if (!object_exists(xsdata_grp, "inverse-velocity")) { - warning("Inverse-velocity is not available in XsData " - "Time related calculation results might be wrong!"); + vector inv_vel; + for (int i = 0; i < energy_bins_.size() - 1; ++i) { + double e_min = energy_bins_[i]; + double e_max = energy_bins_[i + 1]; + double inv_v = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - + std::acosh(1 + e_min / MASS_NEUTRON_EV) + + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / + std::log(e_max / e_min) / C_LIGHT; + inv_vel.push_back(inv_v); + } + inverse_velocity = xt::adapt(inv_vel); } // Get scattering data From 957d098965765234d1d68d03faf5f221eb9fce63 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Feb 2026 19:15:12 +0200 Subject: [PATCH 16/51] wip --- include/openmc/xsdata.h | 3 ++- src/xsdata.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index feafde68dd3..ba760bffa75 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -120,10 +120,11 @@ class XsData { //! the incoming particle. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. + //! @param energy_bins energy bins of XsData void from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, AngleDistributionType final_scatter_format, int order_data, - bool is_isotropic, int n_pol, int n_azi); + bool is_isotropic, int n_pol, int n_azi, const vector& energy_bins); //! \brief Combines the microscopic data to a macroscopic object. //! diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 538bb94f068..4bfe858c386 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -98,9 +98,9 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, if (!object_exists(xsdata_grp, "inverse-velocity")) { vector inv_vel; - for (int i = 0; i < energy_bins_.size() - 1; ++i) { - double e_min = energy_bins_[i]; - double e_max = energy_bins_[i + 1]; + for (int i = 0; i < energy_bins.size() - 1; ++i) { + double e_min = energy_bins[i]; + double e_max = energy_bins[i + 1]; double inv_v = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - std::acosh(1 + e_min / MASS_NEUTRON_EV) + From 59b4c008ec2cf66d940f22cc134e668dadb9058a Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Feb 2026 19:17:47 +0200 Subject: [PATCH 17/51] revert warning --- src/cell.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 63629e3ee49..ebe28c3d2ce 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -20,7 +20,6 @@ #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" #include "openmc/material.h" -#include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/settings.h" #include "openmc/xml_interface.h" @@ -398,10 +397,6 @@ CSGCell::CSGCell(pugi::xml_node cell_node) for (std::string mat : mats) { if (mat.compare("void") == 0) { material_.push_back(MATERIAL_VOID); - if (!settings::run_CE && data::mg.void_velocities_.empty()) - warning("Void inverse-velocity data is not available in the " - "multi-group nuclear data library. " - "Time related calculation results might be wrong!"); } else { material_.push_back(std::stoi(mat)); } From a78f7d618b5ea041125e9588cd7904b241304328 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 00:36:12 +0200 Subject: [PATCH 18/51] simplify code --- src/particle.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 05f8d173971..372e9e02a72 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -67,18 +67,13 @@ double Particle::speed() const (this->E() + mass); } else { auto mat = this->material(); - if (mat == MATERIAL_VOID) { - if (!data::mg.void_velocities_.empty()) { - return data::mg.void_velocities_[this->g()]; - } else { - return 0.0; - } - } + if (mat == MATERIAL_VOID) + return data::mg.void_velocities_[this->g()]; auto& macro_xs = data::mg.macro_xs_[mat]; int macro_t = this->mg_xs_cache().t; int macro_a = macro_xs.get_angle_index(this->u()); - return 1.0 / macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, this->g(), nullptr, - nullptr, nullptr, macro_t, macro_a); + return 1.0 / macro_xs.get_xs( + MgxsType::INVERSE_VELOCITY, this->g(), macro_t, macro_a); } } From a3949506e8de4cb1307e4e9ce8af42d91d553954 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 10:05:17 +0200 Subject: [PATCH 19/51] off by one --- src/mgxs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index a7e38508e6e..baa4dfb6e14 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -273,7 +273,7 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, Mgxs::Mgxs(hid_t xs_id, const vector& temperature, const vector& energy_bins, int num_delay) - : num_groups(energy_bins.size()), num_delayed_groups(num_delay) + : num_groups(energy_bins.size() - 1), num_delayed_groups(num_delay) { // Call generic data gathering routine (will populate the metadata) int order_data; @@ -374,7 +374,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, } } } // end switch - } // end microscopic temperature loop + } // end microscopic temperature loop // Now combine the microscopic data at each relevant temperature // We will do this by treating the multiple temperatures of a nuclide as From 68822cfb463f7ea808eba999bb62b720a2401ba9 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 10:22:10 +0200 Subject: [PATCH 20/51] fix xt code --- src/xsdata.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 4bfe858c386..a8948de6274 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -97,18 +97,19 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); if (!object_exists(xsdata_grp, "inverse-velocity")) { - vector inv_vel; - for (int i = 0; i < energy_bins.size() - 1; ++i) { + xt::xarray inv_vel = xt::zeros({energy_groups}); + for (int i = 0; i < energy_groups; ++i) { double e_min = energy_bins[i]; double e_max = energy_bins[i + 1]; - double inv_v = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - - std::acosh(1 + e_min / MASS_NEUTRON_EV) + - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / - std::log(e_max / e_min) / C_LIGHT; - inv_vel.push_back(inv_v); + inv_vel[i] = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - + std::acosh(1 + e_min / MASS_NEUTRON_EV) + + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / + std::log(e_max / e_min) / C_LIGHT; + } + for (int j = 0; j < n_ang; ++j) { + xt::view(inverse_velocity, j, xt::all()) = inv_vel; } - inverse_velocity = xt::adapt(inv_vel); } // Get scattering data From aa1703f36543c1ba923f2eeb317222d6cfbe2104 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 10:44:27 +0200 Subject: [PATCH 21/51] fix typo --- src/mgxs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index baa4dfb6e14..ccf9296bcdc 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -374,7 +374,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, } } } // end switch - } // end microscopic temperature loop + } // end microscopic temperature loop // Now combine the microscopic data at each relevant temperature // We will do this by treating the multiple temperatures of a nuclide as From 4998e8a0c9cd015f9f9b964f687356a360ca1846 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 19:50:39 +0200 Subject: [PATCH 22/51] simplify code --- openmc/examples.py | 6 +- openmc/mgxs_library.py | 83 ++----------------- src/mgxs_interface.cpp | 21 +++-- .../inputs_true.dat | 4 +- .../fs/inputs_true.dat | 4 +- .../cell/inputs_true.dat | 4 +- .../material/inputs_true.dat | 4 +- .../universe/inputs_true.dat | 4 +- .../linear/inputs_true.dat | 4 +- .../linear_xy/inputs_true.dat | 4 +- .../flat/inputs_true.dat | 4 +- .../linear/inputs_true.dat | 4 +- .../False/inputs_true.dat | 4 +- .../True/inputs_true.dat | 4 +- .../random_ray_low_density/inputs_true.dat | 4 +- .../random_ray_low_density/test.py | 2 +- .../inputs_true.dat | 4 +- .../random_ray_void/flat/inputs_true.dat | 4 +- .../random_ray_void/linear/inputs_true.dat | 4 +- .../hybrid/inputs_true.dat | 4 +- .../naive/inputs_true.dat | 4 +- .../simulation_averaged/inputs_true.dat | 4 +- .../hybrid/inputs_true.dat | 4 +- .../naive/inputs_true.dat | 4 +- .../simulation_averaged/inputs_true.dat | 4 +- .../weightwindows_fw_cadis/inputs_true.dat | 4 +- .../flat/inputs_true.dat | 4 +- .../linear/inputs_true.dat | 4 +- 28 files changed, 71 insertions(+), 137 deletions(-) diff --git a/openmc/examples.py b/openmc/examples.py index b53d22c6a05..350a4d24d5e 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -1061,7 +1061,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): void_sigma_a = 4.0e-6 void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('approx void', groups) + void_mat_data = openmc.XSdata('void', groups) void_mat_data.order = 0 void_mat_data.set_total([void_sigma_a + void_sigma_s]) void_mat_data.set_absorption([void_sigma_a]) @@ -1097,7 +1097,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): # Instantiate some Macroscopic Data source_data = openmc.Macroscopic('source') - void_data = openmc.Macroscopic('approx void') + void_data = openmc.Macroscopic('void') absorber_data = openmc.Macroscopic('absorber') # Instantiate some Materials and register the appropriate Macroscopic objects @@ -1105,7 +1105,7 @@ def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3): source_mat.set_density('macro', 1.0) source_mat.add_macroscopic(source_data) - void_mat = openmc.Material(name='approx void') + void_mat = openmc.Material(name='void') void_mat.set_density('macro', 1.0) void_mat.add_macroscopic(void_data) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 01a8a2b6b5c..c1a15998e19 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -11,7 +11,7 @@ import openmc.mgxs from openmc.mgxs import SCATTER_TABULAR, SCATTER_LEGENDRE, SCATTER_HISTOGRAM from .checkvalue import check_type, check_value, check_greater_than, \ - check_iterable_type, check_length, check_less_than, check_filetype_version, PathLike + check_iterable_type, check_less_than, check_filetype_version, PathLike ROOM_TEMPERATURE_KELVIN = 294.0 @@ -177,9 +177,7 @@ class XSdata: def __init__(self, name, energy_groups, temperatures=[ROOM_TEMPERATURE_KELVIN], representation=REPRESENTATION_ISOTROPIC, num_delayed_groups=0): - self._is_void = False - - #Initialize class attributes + # Initialize class attributes self.name = name self.energy_groups = energy_groups self.num_delayed_groups = num_delayed_groups @@ -214,7 +212,6 @@ def __deepcopy__(self, memo): # If this is the first time we have tried to copy this object, copy it if existing is None: clone = type(self).__new__(type(self)) - clone._is_void = self._is_void clone._name = self.name clone._energy_groups = copy.deepcopy(self.energy_groups, memo) clone._num_delayed_groups = self.num_delayed_groups @@ -263,9 +260,6 @@ def name(self): def name(self, name): check_type('name for XSdata', name, str) - if name == 'void': - self._is_void = True - self._name = name @property @@ -328,8 +322,6 @@ def temperatures(self): @temperatures.setter def temperatures(self, temperatures): - if self._is_void: - check_length('temperatures', temperatures, 1, 1) check_iterable_type('temperatures', temperatures, Real) self._temperatures = np.array(temperatures) @@ -489,8 +481,6 @@ def add_temperature(self, temperature): Temperature (in units of Kelvin) of the provided dataset. """ - if self._is_void: - raise TypeError('Cannot add temperatures to a void xs') check_type('temperature', temperature, Real) @@ -542,8 +532,6 @@ def set_total(self, total, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_total_mgxs() """ - if self._is_void: - raise TypeError('Cannot set total xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -573,8 +561,6 @@ def set_absorption(self, absorption, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_absorption_mgxs() """ - if self._is_void: - raise TypeError('Cannot set absorption xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -604,8 +590,6 @@ def set_fission(self, fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_fission_mgxs() """ - if self._is_void: - raise TypeError('Cannot set fission xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -637,8 +621,6 @@ def set_kappa_fission(self, kappa_fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_kappa_fission_mgxs() """ - if self._is_void: - raise TypeError('Cannot set kappa-fission xs in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"]] @@ -670,8 +652,6 @@ def set_chi(self, chi, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_mgxs() """ - if self._is_void: - raise TypeError('Cannot set chi in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"]] @@ -701,8 +681,6 @@ def set_chi_prompt(self, chi_prompt, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_prompt_mgxs() """ - if self._is_void: - raise TypeError('Cannot set chi-prompt in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"]] @@ -732,8 +710,6 @@ def set_chi_delayed(self, chi_delayed, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_chi_delayed_mgxs() """ - if self._is_void: - raise TypeError('Cannot set chi-delayed in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G']"], self.xs_shapes["[DG][G']"]] @@ -765,8 +741,6 @@ def set_beta(self, beta, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_beta_mgxs() """ - if self._is_void: - raise TypeError('Cannot set beta in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG]"], self.xs_shapes["[DG][G]"]] @@ -796,8 +770,6 @@ def set_decay_rate(self, decay_rate, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_decay_rate_mgxs() """ - if self._is_void: - raise TypeError('Cannot set decay rate in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG]"]] @@ -827,8 +799,6 @@ def set_scatter_matrix(self, scatter, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_scatter_matrix_mgxs() """ - if self._is_void: - raise TypeError('Cannot set scatter matrix in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G][G'][Order]"]] @@ -860,8 +830,6 @@ def set_multiplicity_matrix(self, multiplicity, temperature=ROOM_TEMPERATURE_KEL openmc.mgxs_library.set_multiplicity_matrix_mgxs() """ - if self._is_void: - raise TypeError('Cannot set multiplicity matrix in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G][G']"]] @@ -893,8 +861,6 @@ def set_nu_fission(self, nu_fission, temperature=ROOM_TEMPERATURE_KELVIN): openmc.mgxs_library.set_nu_fission_mgxs() """ - if self._is_void: - raise TypeError('Cannot set nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"], self.xs_shapes["[G][G']"]] @@ -927,8 +893,6 @@ def set_prompt_nu_fission(self, prompt_nu_fission, temperature=ROOM_TEMPERATURE_ openmc.mgxs_library.set_prompt_nu_fission_mgxs() """ - if self._is_void: - raise TypeError('Cannot set prompt nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[G]"], self.xs_shapes["[G][G']"]] @@ -961,8 +925,6 @@ def set_delayed_nu_fission(self, delayed_nu_fission, temperature=ROOM_TEMPERATUR openmc.mgxs_library.set_delayed_nu_fission_mgxs() """ - if self._is_void: - raise TypeError('Cannot set delayed nu-fission in a void') # Get the accepted shapes for this xs shapes = [self.xs_shapes["[DG][G]"], self.xs_shapes["[DG][G][G']"]] @@ -1034,8 +996,6 @@ def set_total_mgxs(self, total, temperature=ROOM_TEMPERATURE_KELVIN, nuclide='to openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set total xs in a void') check_type('total', total, (openmc.mgxs.TotalXS, openmc.mgxs.TransportXS)) @@ -1076,8 +1036,6 @@ def set_absorption_mgxs(self, absorption, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set absorption xs in a void') check_type('absorption', absorption, openmc.mgxs.AbsorptionXS) check_value('energy_groups', absorption.energy_groups, @@ -1120,8 +1078,6 @@ def set_fission_mgxs(self, fission, temperature=ROOM_TEMPERATURE_KELVIN, nuclide openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set fission in a void') check_type('fission', fission, openmc.mgxs.FissionXS) check_value('energy_groups', fission.energy_groups, @@ -1164,8 +1120,6 @@ def set_nu_fission_mgxs(self, nu_fission, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set nu-fission in a void') check_type('nu_fission', nu_fission, (openmc.mgxs.FissionXS, openmc.mgxs.NuFissionMatrixXS)) @@ -1217,8 +1171,6 @@ def set_prompt_nu_fission_mgxs(self, prompt_nu_fission, temperature=ROOM_TEMPERA openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set prompt nu-fission in a void') check_type('prompt_nu_fission', prompt_nu_fission, (openmc.mgxs.FissionXS, openmc.mgxs.NuFissionMatrixXS)) @@ -1266,8 +1218,6 @@ def set_delayed_nu_fission_mgxs(self, delayed_nu_fission, temperature=ROOM_TEMPE openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set delayed nu-fission in a void') check_type('delayed_nu_fission', delayed_nu_fission, (openmc.mgxs.DelayedNuFissionXS, @@ -1317,8 +1267,6 @@ def set_kappa_fission_mgxs(self, k_fission, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set kappa-fission in a void') check_type('kappa_fission', k_fission, openmc.mgxs.KappaFissionXS) check_value('energy_groups', k_fission.energy_groups, @@ -1360,8 +1308,6 @@ def set_chi_mgxs(self, chi, temperature=ROOM_TEMPERATURE_KELVIN, nuclide='total' openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set chi in a void') check_type('chi', chi, openmc.mgxs.Chi) check_value('energy_groups', chi.energy_groups, [self.energy_groups]) @@ -1400,8 +1346,6 @@ def set_chi_prompt_mgxs(self, chi_prompt, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set prompt chi in a void') check_type('chi_prompt', chi_prompt, openmc.mgxs.Chi) check_value('prompt', chi_prompt.prompt, [True]) @@ -1444,8 +1388,6 @@ def set_chi_delayed_mgxs(self, chi_delayed, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set delayed chi in a void') check_type('chi_delayed', chi_delayed, openmc.mgxs.ChiDelayed) check_value('energy_groups', chi_delayed.energy_groups, @@ -1489,8 +1431,6 @@ def set_beta_mgxs(self, beta, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set beta in a void') check_type('beta', beta, openmc.mgxs.Beta) check_value('num_delayed_groups', beta.num_delayed_groups, @@ -1531,8 +1471,6 @@ def set_decay_rate_mgxs(self, decay_rate, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set decay rate in a void') check_type('decay_rate', decay_rate, openmc.mgxs.DecayRate) check_value('num_delayed_groups', decay_rate.num_delayed_groups, @@ -1578,8 +1516,6 @@ def set_scatter_matrix_mgxs(self, scatter, temperature=ROOM_TEMPERATURE_KELVIN, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set scatter matrix in a void') check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS) check_value('energy_groups', scatter.energy_groups, @@ -1668,8 +1604,6 @@ def set_multiplicity_matrix_mgxs(self, nuscatter, scatter=None, openmc.mgxs.Library.get_xsdata() """ - if self._is_void: - raise TypeError('Cannot set multiplicity matrix in a void') check_type('nuscatter', nuscatter, (openmc.mgxs.ScatterMatrixXS, openmc.mgxs.MultiplicityMatrixXS)) @@ -2058,15 +1992,6 @@ def to_hdf5(self, file): xs_grp = grp.create_group(str(int(np.round(temperature))) + "K") - # Add the kinetics data - if self._inverse_velocity[i] is not None: - xs_grp.create_dataset("inverse-velocity", - data=self._inverse_velocity[i]) - elif self._is_void: - raise TypeError('Void mgxs must have inverse-velocity data.') - - if self._is_void: continue - if self._total[i] is None: raise ValueError('total data must be provided when writing ' 'the HDF5 library') @@ -2216,6 +2141,10 @@ def to_hdf5(self, file): scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0]) scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1]) + # Add the kinetics data + if self._inverse_velocity[i] is not None: + xs_grp.create_dataset("inverse-velocity", + data=self._inverse_velocity[i]) @classmethod def from_hdf5(cls, group, name, energy_groups, num_delayed_groups): diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 1da998dc172..baf024bc538 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -236,8 +236,9 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } - + // Read void velocities + bool void_velocities_exist = false; if (object_exists(file_id, "void")) { auto void_grp = open_group(file_id, "void"); // Determine the available temperatures @@ -251,14 +252,18 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); auto xsdata_grp = open_group(void_grp, dset_names[0]); - vector shape {1, static_cast(num_energy_groups_)}; - xt::xtensor inverse_velocity = xt::zeros(shape); - read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); - auto velocity = 1.0 / inverse_velocity; - for (double v : velocity) { - void_velocities_.push_back(v); + if (object_exists(xsdata_grp, "inverse-velocity")) { + vector shape {1, static_cast(num_energy_groups_)}; + xt::xtensor inverse_velocity = xt::zeros(shape); + read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); + auto velocity = 1.0 / inverse_velocity; + for (double v : velocity) { + void_velocities_.push_back(v); + } + void_velocities_exist = true; } - } else { + } + if (!void_velocities_exist) { for (int i = 0; i < energy_bins_.size() - 1; ++i) { double e_min = energy_bins_[i]; double e_max = energy_bins_[i + 1]; diff --git a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat b/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat index 74937ce13e8..0adfc548848 100644 --- a/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat +++ b/tests/regression_tests/random_ray_adjoint_fixed_source/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat b/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat index f8ebc855b3a..e90f25973e2 100644 --- a/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat +++ b/tests/regression_tests/random_ray_cell_density/fs/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat index f58da8d57be..9f1987f3acc 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/cell/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat index 5c455d3608a..b4f57dbfa8a 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/material/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat index 9a9b2aebb5b..ab91f74e50d 100644 --- a/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_domain/universe/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat index e22d48466a5..220fa7db643 100644 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_linear/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat index dbf29b9ae54..f8c4430852f 100644 --- a/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_linear/linear_xy/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat index 219ccddb0d3..c84e544fcc4 100644 --- a/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_mesh/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat index f9593f4139e..05c4846e6b4 100644 --- a/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_mesh/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat index 037c66b0488..0c870e10067 100644 --- a/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_normalization/False/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat b/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat index 9a9b2aebb5b..ab91f74e50d 100644 --- a/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat +++ b/tests/regression_tests/random_ray_fixed_source_normalization/True/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_low_density/inputs_true.dat b/tests/regression_tests/random_ray_low_density/inputs_true.dat index 9a9b2aebb5b..ab91f74e50d 100644 --- a/tests/regression_tests/random_ray_low_density/inputs_true.dat +++ b/tests/regression_tests/random_ray_low_density/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_low_density/test.py b/tests/regression_tests/random_ray_low_density/test.py index fa594e2cee0..1b4ffb78183 100644 --- a/tests/regression_tests/random_ray_low_density/test.py +++ b/tests/regression_tests/random_ray_low_density/test.py @@ -25,7 +25,7 @@ def test_random_ray_low_density(): void_sigma_a = 4.0e-6 void_sigma_s = 3.0e-4 - void_mat_data = openmc.XSdata('approx void', groups) + void_mat_data = openmc.XSdata('void', groups) void_mat_data.order = 0 void_mat_data.set_total([void_sigma_a + void_sigma_s]) void_mat_data.set_absorption([void_sigma_a]) diff --git a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat b/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat index 3ef0b0ff985..088f803bfa8 100644 --- a/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat +++ b/tests/regression_tests/random_ray_point_source_locator/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_void/flat/inputs_true.dat b/tests/regression_tests/random_ray_void/flat/inputs_true.dat index 22a5f22678b..aa28e7b68bf 100644 --- a/tests/regression_tests/random_ray_void/flat/inputs_true.dat +++ b/tests/regression_tests/random_ray_void/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_void/linear/inputs_true.dat b/tests/regression_tests/random_ray_void/linear/inputs_true.dat index 7a33bee6049..e4b2f22fa27 100644 --- a/tests/regression_tests/random_ray_void/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_void/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat index 255a2730ec5..8e8a8ed9b81 100644 --- a/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/hybrid/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat index 0806732be55..1e25b97da66 100644 --- a/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/naive/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat index f2c60ed8ab4..78c16269763 100644 --- a/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator/simulation_averaged/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat index 9a9a3c6c695..47a8a718249 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/hybrid/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat index dd250bfc483..80a9ada4d5b 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/naive/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat index 0b383945c75..4f032a62a82 100644 --- a/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat +++ b/tests/regression_tests/random_ray_volume_estimator_linear/simulation_averaged/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat index b0864454101..5fa6505ddf4 100644 --- a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat index e093825cf22..ceb89e6e34c 100644 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis_mesh/flat/inputs_true.dat @@ -6,9 +6,9 @@ - + - + diff --git a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat index 9a058a2362f..c7691e950c4 100644 --- a/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis_mesh/linear/inputs_true.dat @@ -6,9 +6,9 @@ - + - + From 28c044f9c5a30396e61fa2d88d4fbcc4dd3d899a Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 20:09:07 +0200 Subject: [PATCH 23/51] ran clang format --- src/mgxs_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index baf024bc538..4f79773bc76 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -236,7 +236,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } - + // Read void velocities bool void_velocities_exist = false; if (object_exists(file_id, "void")) { From 58c0090f8ab9a6820c85f51928259e4bc1a3e989 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 23:23:58 +0200 Subject: [PATCH 24/51] ensure minimum neutron energy --- openmc/mgxs/groups.py | 4 ++++ tests/regression_tests/mg_basic_delayed/test.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 8910c7d423d..2f2c8b0e659 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -79,6 +79,10 @@ def group_edges(self): def group_edges(self, edges): cv.check_type('group edges', edges, Iterable, Real) cv.check_greater_than('number of group edges', len(edges), 1) + for i, edge in enumerate(edges): + cv.check_greater_than( + "group edge {i}", edge, edges[i - 1] if i > 0 else 1e-5, equality=True + ) self._group_edges = np.array(edges) @property diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index f0474a5675d..8e26212027f 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) n_dg = 2 mg_cross_sections_file = openmc.MGXSLibrary(groups) From 26e6c6d0ddaef9487ecb58ad9108459afda42a00 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 23:45:14 +0200 Subject: [PATCH 25/51] ensure minimum neutron energy in tests --- tests/regression_tests/mg_basic/test.py | 194 ++++++------ tests/regression_tests/mg_legendre/test.py | 110 +++---- tests/regression_tests/mg_max_order/test.py | 110 +++---- .../mg_survival_biasing/test.py | 110 +++---- tests/regression_tests/mg_tallies/test.py | 296 +++++++++--------- .../mg_temperature/build_2g.py | 2 +- .../mgxs_library_ce_to_mg/test.py | 2 +- .../mgxs_library_ce_to_mg_nuclides/test.py | 2 +- .../mgxs_library_condense/test.py | 2 +- .../mgxs_library_correction/test.py | 2 +- .../mgxs_library_distribcell/test.py | 2 +- .../mgxs_library_hdf5/test.py | 2 +- .../mgxs_library_histogram/test.py | 2 +- .../mgxs_library_mesh/test.py | 2 +- .../mgxs_library_no_nuclides/test.py | 2 +- .../mgxs_library_nuclides/test.py | 2 +- .../mgxs_library_specific_nuclides/test.py | 2 +- tests/regression_tests/volume_calc/test.py | 2 +- 18 files changed, 423 insertions(+), 423 deletions(-) diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py index 7b456bb9d07..350043c1ec6 100644 --- a/tests/regression_tests/mg_basic/test.py +++ b/tests/regression_tests/mg_basic/test.py @@ -1,97 +1,97 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Make a version of mat-1 which has a tabular representation of the - # scattering vice Legendre with 33 points - mat_2 = mat_1.convert_scatter_format('tabular', 33) - mat_2.name = 'mat_2' - mg_cross_sections_file.add_xsdata(mat_2) - - # Make a version of mat-1 which has a histogram representation of the - # scattering vice Legendre with 33 bins - mat_3 = mat_1.convert_scatter_format('histogram', 33) - mat_3.name = 'mat_3' - mg_cross_sections_file.add_xsdata(mat_3) - - # Make a version which uses a fission matrix vice chi & nu-fission - mat_4 = openmc.XSdata('mat_4', groups) - mat_4.order = 1 - mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) - mat_4.set_absorption(absorption) - mat_4.set_scatter_matrix(scatter) - mat_4.set_total(total) - mg_cross_sections_file.add_xsdata(mat_4) - - # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles - mat_5 = mat_1.convert_representation('angle', 2, 2) - mat_5.name = 'mat_5' - mg_cross_sections_file.add_xsdata(mat_5) - - # Make a copy of mat_1 for testing microscopic cross sections - mat_6 = openmc.XSdata('mat_6', groups) - mat_6.order = 1 - mat_6.set_nu_fission(np.multiply(nu, fiss)) - mat_6.set_absorption(absorption) - mat_6.set_scatter_matrix(scatter) - mat_6.set_total(total) - mat_6.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_6) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_basic(): - create_library() - mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', - 'base ang', 'micro'] - model = slab_mg(num_regions=6, mat_names=mat_names) - # Modify the last material to be a microscopic combination of nuclides - model.materials[-1] = openmc.Material(name='micro', material_id=6) - model.materials[-1].set_density("sum") - model.materials[-1].add_nuclide("mat_1", 0.5) - model.materials[-1].add_nuclide("mat_6", 0.5) - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version of mat-1 which has a tabular representation of the + # scattering vice Legendre with 33 points + mat_2 = mat_1.convert_scatter_format('tabular', 33) + mat_2.name = 'mat_2' + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version of mat-1 which has a histogram representation of the + # scattering vice Legendre with 33 bins + mat_3 = mat_1.convert_scatter_format('histogram', 33) + mat_3.name = 'mat_3' + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version which uses a fission matrix vice chi & nu-fission + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles + mat_5 = mat_1.convert_representation('angle', 2, 2) + mat_5.name = 'mat_5' + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a copy of mat_1 for testing microscopic cross sections + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.set_nu_fission(np.multiply(nu, fiss)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mat_6.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_6) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_basic(): + create_library() + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', + 'base ang', 'micro'] + model = slab_mg(num_regions=6, mat_names=mat_names) + # Modify the last material to be a microscopic combination of nuclides + model.materials[-1] = openmc.Material(name='micro', material_id=6) + model.materials[-1].set_density("sum") + model.materials[-1].add_nuclide("mat_1", 0.5) + model.materials[-1].add_nuclide("mat_6", 0.5) + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_legendre/test.py b/tests/regression_tests/mg_legendre/test.py index b5a05c706d9..c3ee8817000 100644 --- a/tests/regression_tests/mg_legendre/test.py +++ b/tests/regression_tests/mg_legendre/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_legendre(): - create_library() - model = slab_mg() - model.settings.tabular_legendre = {'enable': False} - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_legendre(): + create_library() + model = slab_mg() + model.settings.tabular_legendre = {'enable': False} + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_max_order/test.py b/tests/regression_tests/mg_max_order/test.py index 97d3f57d7ab..73d823d58f3 100644 --- a/tests/regression_tests/mg_max_order/test.py +++ b/tests/regression_tests/mg_max_order/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], - [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 2 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_max_order(): - create_library() - model = slab_mg() - model.settings.max_order = 1 - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], + [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 2 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_max_order(): + create_library() + model = slab_mg() + model.settings.max_order = 1 + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_survival_biasing/test.py b/tests/regression_tests/mg_survival_biasing/test.py index 5d75611a9d4..55bfe4b47e6 100644 --- a/tests/regression_tests/mg_survival_biasing/test.py +++ b/tests/regression_tests/mg_survival_biasing/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_survival_biasing(): - create_library() - model = slab_mg() - model.settings.survival_biasing = True - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_survival_biasing(): + create_library() + model = slab_mg() + model.settings.survival_biasing = True + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index f4e9693f6f8..b70f50489ca 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -1,148 +1,148 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups, 6) - - # Make the base, isotropic data - nu = np.array([2.50, 2.50]) - fiss = np.array([0.002817, 0.097]) - capture = np.array([0.008708, 0.02518]) - absorption = capture + fiss - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = np.array([0.33588, 0.54628]) - chi = np.array([1., 0.]) - decay_rate = np.array([0.013336, 0.032739, 0.12078, 0.30278, 0.84949, - 2.853]) - delayed_yield = np.array([0.00055487, 0.00286407, 0.00273429, 0.0061305, - 0.00251342, 0.00105286]) - inv_vel = 1.0 / np.array([1.4e9, 4.4e5]) - - - mat_1 = openmc.XSdata('mat_1', groups, num_delayed_groups=6) - mat_1.order = 1 - mat_1.set_fission(fiss) - mat_1.set_kappa_fission(fiss * 200e6) - mat_1.set_nu_fission(nu * fiss) - mat_1.set_beta(delayed_yield / 2.5) - mat_1.set_decay_rate(decay_rate) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mat_1.set_inverse_velocity(inv_vel) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_tallies(): - create_library() - model = slab_mg() - - # Instantiate a tally mesh - mesh = openmc.RegularMesh(mesh_id=1) - mesh.dimension = [10, 1, 1] - mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [929.45, 1000, 1000] - - # Instantiate some tally filters - energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) - energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) - energies = [0.0, 0.625, 20.0e6] - matching_energy_filter = openmc.EnergyFilter(energies) - matching_eout_filter = openmc.EnergyoutFilter(energies) - mesh_filter = openmc.MeshFilter(mesh) - - mat_filter = openmc.MaterialFilter(model.materials) - - nuclides = model.xs_data - - scores_with_nuclides = [ - 'total', 'absorption', 'fission', 'nu-fission', 'inverse-velocity', - 'prompt-nu-fission', 'delayed-nu-fission', 'kappa-fission', 'events', - 'decay-rate'] - scores_without_nuclides = scores_with_nuclides + ['flux'] - - for do_nuclides, scores in ((False, scores_without_nuclides), - (True, scores_with_nuclides)): - t = openmc.Tally() - t.filters = [mesh_filter] - t.estimator = 'analog' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mesh_filter] - t.estimator = 'tracklength' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - # Impose energy bins that dont match the MG structure and those - # that do - for match_energy_bins in [False, True]: - if match_energy_bins: - e_filter = matching_energy_filter - eout_filter = matching_eout_filter - else: - e_filter = energy_filter - eout_filter = energyout_filter - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'analog' - t.scores = scores + ['scatter', 'nu-scatter'] - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'collision' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'tracklength' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter, eout_filter] - t.scores = ['scatter', 'nu-scatter', 'nu-fission'] - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups, 6) + + # Make the base, isotropic data + nu = np.array([2.50, 2.50]) + fiss = np.array([0.002817, 0.097]) + capture = np.array([0.008708, 0.02518]) + absorption = capture + fiss + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = np.array([0.33588, 0.54628]) + chi = np.array([1., 0.]) + decay_rate = np.array([0.013336, 0.032739, 0.12078, 0.30278, 0.84949, + 2.853]) + delayed_yield = np.array([0.00055487, 0.00286407, 0.00273429, 0.0061305, + 0.00251342, 0.00105286]) + inv_vel = 1.0 / np.array([1.4e9, 4.4e5]) + + + mat_1 = openmc.XSdata('mat_1', groups, num_delayed_groups=6) + mat_1.order = 1 + mat_1.set_fission(fiss) + mat_1.set_kappa_fission(fiss * 200e6) + mat_1.set_nu_fission(nu * fiss) + mat_1.set_beta(delayed_yield / 2.5) + mat_1.set_decay_rate(decay_rate) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mat_1.set_inverse_velocity(inv_vel) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_tallies(): + create_library() + model = slab_mg() + + # Instantiate a tally mesh + mesh = openmc.RegularMesh(mesh_id=1) + mesh.dimension = [10, 1, 1] + mesh.lower_left = [0.0, 0.0, 0.0] + mesh.upper_right = [929.45, 1000, 1000] + + # Instantiate some tally filters + energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) + energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) + energies = [0.0, 0.625, 20.0e6] + matching_energy_filter = openmc.EnergyFilter(energies) + matching_eout_filter = openmc.EnergyoutFilter(energies) + mesh_filter = openmc.MeshFilter(mesh) + + mat_filter = openmc.MaterialFilter(model.materials) + + nuclides = model.xs_data + + scores_with_nuclides = [ + 'total', 'absorption', 'fission', 'nu-fission', 'inverse-velocity', + 'prompt-nu-fission', 'delayed-nu-fission', 'kappa-fission', 'events', + 'decay-rate'] + scores_without_nuclides = scores_with_nuclides + ['flux'] + + for do_nuclides, scores in ((False, scores_without_nuclides), + (True, scores_with_nuclides)): + t = openmc.Tally() + t.filters = [mesh_filter] + t.estimator = 'analog' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mesh_filter] + t.estimator = 'tracklength' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + # Impose energy bins that dont match the MG structure and those + # that do + for match_energy_bins in [False, True]: + if match_energy_bins: + e_filter = matching_energy_filter + eout_filter = matching_eout_filter + else: + e_filter = energy_filter + eout_filter = energyout_filter + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'analog' + t.scores = scores + ['scatter', 'nu-scatter'] + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'collision' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'tracklength' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter, eout_filter] + t.scores = ['scatter', 'nu-scatter', 'nu-fission'] + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_temperature/build_2g.py b/tests/regression_tests/mg_temperature/build_2g.py index 1fb7234499b..cc32c829346 100644 --- a/tests/regression_tests/mg_temperature/build_2g.py +++ b/tests/regression_tests/mg_temperature/build_2g.py @@ -169,7 +169,7 @@ def create_macro_dict(xs_micro): def create_openmc_2mg_libs(names): """Built a micro/macro two group openmc MGXS libraries""" # Initialized library params - group_edges = [0.0, 0.625, 20.0e6] + group_edges = [1e-5, 0.625, 20.0e6] groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 075167f5884..d30d74a2a5f 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -14,7 +14,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py index 489105f8f54..dd6ace8197f 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -14,7 +14,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_condense/test.py b/tests/regression_tests/mgxs_library_condense/test.py index bbc4c11bfa9..ada5950f157 100644 --- a/tests/regression_tests/mgxs_library_condense/test.py +++ b/tests/regression_tests/mgxs_library_condense/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_correction/test.py b/tests/regression_tests/mgxs_library_correction/test.py index 64e638e442f..8a8bea068dc 100644 --- a/tests/regression_tests/mgxs_library_correction/test.py +++ b/tests/regression_tests/mgxs_library_correction/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_distribcell/test.py b/tests/regression_tests/mgxs_library_distribcell/test.py index 464b309c002..54c847afaf3 100644 --- a/tests/regression_tests/mgxs_library_distribcell/test.py +++ b/tests/regression_tests/mgxs_library_distribcell/test.py @@ -15,7 +15,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a one-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 20.e6]) # Initialize MGXS Library for a few cross section types # for one material-filled cell in the geometry diff --git a/tests/regression_tests/mgxs_library_hdf5/test.py b/tests/regression_tests/mgxs_library_hdf5/test.py index 4fb4bf09369..a3d0822a0db 100644 --- a/tests/regression_tests/mgxs_library_hdf5/test.py +++ b/tests/regression_tests/mgxs_library_hdf5/test.py @@ -16,7 +16,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_histogram/test.py b/tests/regression_tests/mgxs_library_histogram/test.py index 42fc1957a6b..f298eeb32c3 100644 --- a/tests/regression_tests/mgxs_library_histogram/test.py +++ b/tests/regression_tests/mgxs_library_histogram/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_mesh/test.py b/tests/regression_tests/mgxs_library_mesh/test.py index c1a5980b5d1..32d4c0b8a26 100644 --- a/tests/regression_tests/mgxs_library_mesh/test.py +++ b/tests/regression_tests/mgxs_library_mesh/test.py @@ -32,7 +32,7 @@ def model(): model.settings.particles = 1000 # Initialize a one-group structure - energy_groups = openmc.mgxs.EnergyGroups([0, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups([1e-5, 20.e6]) # Initialize MGXS Library for a few cross section types # for one material-filled cell in the geometry diff --git a/tests/regression_tests/mgxs_library_no_nuclides/test.py b/tests/regression_tests/mgxs_library_no_nuclides/test.py index a02086af3ec..4c77cbc469f 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_no_nuclides/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_nuclides/test.py b/tests/regression_tests/mgxs_library_nuclides/test.py index a10070358ad..4f563d5c31b 100644 --- a/tests/regression_tests/mgxs_library_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_nuclides/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/test.py b/tests/regression_tests/mgxs_library_specific_nuclides/test.py index 0ccbb83bdbe..ee8b9006fab 100644 --- a/tests/regression_tests/mgxs_library_specific_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_specific_nuclides/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index c94d16c7975..25e74cd4cc0 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -81,7 +81,7 @@ def __init__(self, is_ce, *args, **kwargs): # Create the MGXS file if necessary if not self.is_ce: - groups = openmc.mgxs.EnergyGroups(group_edges=[0., 20.e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 20.e6]) mg_xs_file = openmc.MGXSLibrary(groups) nu = [2.] From 4571f8d7234f73889f201a1ae7170f578e5e8f24 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 23:47:37 +0200 Subject: [PATCH 26/51] dos2unix --- tests/regression_tests/mg_basic/test.py | 194 ++++++------ tests/regression_tests/mg_legendre/test.py | 110 +++---- tests/regression_tests/mg_max_order/test.py | 110 +++---- .../mg_survival_biasing/test.py | 110 +++---- tests/regression_tests/mg_tallies/test.py | 296 +++++++++--------- 5 files changed, 410 insertions(+), 410 deletions(-) diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py index 350043c1ec6..46bfa336698 100644 --- a/tests/regression_tests/mg_basic/test.py +++ b/tests/regression_tests/mg_basic/test.py @@ -1,97 +1,97 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Make a version of mat-1 which has a tabular representation of the - # scattering vice Legendre with 33 points - mat_2 = mat_1.convert_scatter_format('tabular', 33) - mat_2.name = 'mat_2' - mg_cross_sections_file.add_xsdata(mat_2) - - # Make a version of mat-1 which has a histogram representation of the - # scattering vice Legendre with 33 bins - mat_3 = mat_1.convert_scatter_format('histogram', 33) - mat_3.name = 'mat_3' - mg_cross_sections_file.add_xsdata(mat_3) - - # Make a version which uses a fission matrix vice chi & nu-fission - mat_4 = openmc.XSdata('mat_4', groups) - mat_4.order = 1 - mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) - mat_4.set_absorption(absorption) - mat_4.set_scatter_matrix(scatter) - mat_4.set_total(total) - mg_cross_sections_file.add_xsdata(mat_4) - - # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles - mat_5 = mat_1.convert_representation('angle', 2, 2) - mat_5.name = 'mat_5' - mg_cross_sections_file.add_xsdata(mat_5) - - # Make a copy of mat_1 for testing microscopic cross sections - mat_6 = openmc.XSdata('mat_6', groups) - mat_6.order = 1 - mat_6.set_nu_fission(np.multiply(nu, fiss)) - mat_6.set_absorption(absorption) - mat_6.set_scatter_matrix(scatter) - mat_6.set_total(total) - mat_6.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_6) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_basic(): - create_library() - mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', - 'base ang', 'micro'] - model = slab_mg(num_regions=6, mat_names=mat_names) - # Modify the last material to be a microscopic combination of nuclides - model.materials[-1] = openmc.Material(name='micro', material_id=6) - model.materials[-1].set_density("sum") - model.materials[-1].add_nuclide("mat_1", 0.5) - model.materials[-1].add_nuclide("mat_6", 0.5) - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version of mat-1 which has a tabular representation of the + # scattering vice Legendre with 33 points + mat_2 = mat_1.convert_scatter_format('tabular', 33) + mat_2.name = 'mat_2' + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version of mat-1 which has a histogram representation of the + # scattering vice Legendre with 33 bins + mat_3 = mat_1.convert_scatter_format('histogram', 33) + mat_3.name = 'mat_3' + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version which uses a fission matrix vice chi & nu-fission + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles + mat_5 = mat_1.convert_representation('angle', 2, 2) + mat_5.name = 'mat_5' + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a copy of mat_1 for testing microscopic cross sections + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.set_nu_fission(np.multiply(nu, fiss)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mat_6.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_6) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_basic(): + create_library() + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', + 'base ang', 'micro'] + model = slab_mg(num_regions=6, mat_names=mat_names) + # Modify the last material to be a microscopic combination of nuclides + model.materials[-1] = openmc.Material(name='micro', material_id=6) + model.materials[-1].set_density("sum") + model.materials[-1].add_nuclide("mat_1", 0.5) + model.materials[-1].add_nuclide("mat_6", 0.5) + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_legendre/test.py b/tests/regression_tests/mg_legendre/test.py index c3ee8817000..6601715149e 100644 --- a/tests/regression_tests/mg_legendre/test.py +++ b/tests/regression_tests/mg_legendre/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_legendre(): - create_library() - model = slab_mg() - model.settings.tabular_legendre = {'enable': False} - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_legendre(): + create_library() + model = slab_mg() + model.settings.tabular_legendre = {'enable': False} + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_max_order/test.py b/tests/regression_tests/mg_max_order/test.py index 73d823d58f3..16542518081 100644 --- a/tests/regression_tests/mg_max_order/test.py +++ b/tests/regression_tests/mg_max_order/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], - [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 2 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_max_order(): - create_library() - model = slab_mg() - model.settings.max_order = 1 - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], + [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 2 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_max_order(): + create_library() + model = slab_mg() + model.settings.max_order = 1 + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_survival_biasing/test.py b/tests/regression_tests/mg_survival_biasing/test.py index 55bfe4b47e6..ac8b370c097 100644 --- a/tests/regression_tests/mg_survival_biasing/test.py +++ b/tests/regression_tests/mg_survival_biasing/test.py @@ -1,55 +1,55 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups) - - # Make the base, isotropic data - nu = [2.50, 2.50] - fiss = np.array([0.002817, 0.097]) - capture = [0.008708, 0.02518] - absorption = np.add(capture, fiss) - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = [0.33588, 0.54628] - chi = [1., 0.] - - mat_1 = openmc.XSdata('mat_1', groups) - mat_1.order = 1 - mat_1.set_nu_fission(np.multiply(nu, fiss)) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_survival_biasing(): - create_library() - model = slab_mg() - model.settings.survival_biasing = True - - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_survival_biasing(): + create_library() + model = slab_mg() + model.settings.survival_biasing = True + + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index b70f50489ca..fc63ff7301f 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -1,148 +1,148 @@ -import os - -import numpy as np - -import openmc -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def create_library(): - # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - - mg_cross_sections_file = openmc.MGXSLibrary(groups, 6) - - # Make the base, isotropic data - nu = np.array([2.50, 2.50]) - fiss = np.array([0.002817, 0.097]) - capture = np.array([0.008708, 0.02518]) - absorption = capture + fiss - scatter = np.array( - [[[0.31980, 0.06694], [0.004555, -0.0003972]], - [[0.00000, 0.00000], [0.424100, 0.05439000]]]) - total = np.array([0.33588, 0.54628]) - chi = np.array([1., 0.]) - decay_rate = np.array([0.013336, 0.032739, 0.12078, 0.30278, 0.84949, - 2.853]) - delayed_yield = np.array([0.00055487, 0.00286407, 0.00273429, 0.0061305, - 0.00251342, 0.00105286]) - inv_vel = 1.0 / np.array([1.4e9, 4.4e5]) - - - mat_1 = openmc.XSdata('mat_1', groups, num_delayed_groups=6) - mat_1.order = 1 - mat_1.set_fission(fiss) - mat_1.set_kappa_fission(fiss * 200e6) - mat_1.set_nu_fission(nu * fiss) - mat_1.set_beta(delayed_yield / 2.5) - mat_1.set_decay_rate(decay_rate) - mat_1.set_absorption(absorption) - mat_1.set_scatter_matrix(scatter) - mat_1.set_total(total) - mat_1.set_chi(chi) - mat_1.set_inverse_velocity(inv_vel) - mg_cross_sections_file.add_xsdata(mat_1) - - # Write the file - mg_cross_sections_file.export_to_hdf5('2g.h5') - - -class MGXSTestHarness(PyAPITestHarness): - def _cleanup(self): - super()._cleanup() - f = '2g.h5' - if os.path.exists(f): - os.remove(f) - - -def test_mg_tallies(): - create_library() - model = slab_mg() - - # Instantiate a tally mesh - mesh = openmc.RegularMesh(mesh_id=1) - mesh.dimension = [10, 1, 1] - mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [929.45, 1000, 1000] - - # Instantiate some tally filters - energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) - energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) - energies = [0.0, 0.625, 20.0e6] - matching_energy_filter = openmc.EnergyFilter(energies) - matching_eout_filter = openmc.EnergyoutFilter(energies) - mesh_filter = openmc.MeshFilter(mesh) - - mat_filter = openmc.MaterialFilter(model.materials) - - nuclides = model.xs_data - - scores_with_nuclides = [ - 'total', 'absorption', 'fission', 'nu-fission', 'inverse-velocity', - 'prompt-nu-fission', 'delayed-nu-fission', 'kappa-fission', 'events', - 'decay-rate'] - scores_without_nuclides = scores_with_nuclides + ['flux'] - - for do_nuclides, scores in ((False, scores_without_nuclides), - (True, scores_with_nuclides)): - t = openmc.Tally() - t.filters = [mesh_filter] - t.estimator = 'analog' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mesh_filter] - t.estimator = 'tracklength' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - # Impose energy bins that dont match the MG structure and those - # that do - for match_energy_bins in [False, True]: - if match_energy_bins: - e_filter = matching_energy_filter - eout_filter = matching_eout_filter - else: - e_filter = energy_filter - eout_filter = energyout_filter - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'analog' - t.scores = scores + ['scatter', 'nu-scatter'] - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'collision' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter] - t.estimator = 'tracklength' - t.scores = scores - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - t = openmc.Tally() - t.filters = [mat_filter, e_filter, eout_filter] - t.scores = ['scatter', 'nu-scatter', 'nu-fission'] - if do_nuclides: - t.nuclides = nuclides - model.tallies.append(t) - - harness = MGXSTestHarness('statepoint.10.h5', model) - harness.main() +import os + +import numpy as np + +import openmc +from openmc.examples import slab_mg + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups, 6) + + # Make the base, isotropic data + nu = np.array([2.50, 2.50]) + fiss = np.array([0.002817, 0.097]) + capture = np.array([0.008708, 0.02518]) + absorption = capture + fiss + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = np.array([0.33588, 0.54628]) + chi = np.array([1., 0.]) + decay_rate = np.array([0.013336, 0.032739, 0.12078, 0.30278, 0.84949, + 2.853]) + delayed_yield = np.array([0.00055487, 0.00286407, 0.00273429, 0.0061305, + 0.00251342, 0.00105286]) + inv_vel = 1.0 / np.array([1.4e9, 4.4e5]) + + + mat_1 = openmc.XSdata('mat_1', groups, num_delayed_groups=6) + mat_1.order = 1 + mat_1.set_fission(fiss) + mat_1.set_kappa_fission(fiss * 200e6) + mat_1.set_nu_fission(nu * fiss) + mat_1.set_beta(delayed_yield / 2.5) + mat_1.set_decay_rate(decay_rate) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mat_1.set_inverse_velocity(inv_vel) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_tallies(): + create_library() + model = slab_mg() + + # Instantiate a tally mesh + mesh = openmc.RegularMesh(mesh_id=1) + mesh.dimension = [10, 1, 1] + mesh.lower_left = [0.0, 0.0, 0.0] + mesh.upper_right = [929.45, 1000, 1000] + + # Instantiate some tally filters + energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) + energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) + energies = [0.0, 0.625, 20.0e6] + matching_energy_filter = openmc.EnergyFilter(energies) + matching_eout_filter = openmc.EnergyoutFilter(energies) + mesh_filter = openmc.MeshFilter(mesh) + + mat_filter = openmc.MaterialFilter(model.materials) + + nuclides = model.xs_data + + scores_with_nuclides = [ + 'total', 'absorption', 'fission', 'nu-fission', 'inverse-velocity', + 'prompt-nu-fission', 'delayed-nu-fission', 'kappa-fission', 'events', + 'decay-rate'] + scores_without_nuclides = scores_with_nuclides + ['flux'] + + for do_nuclides, scores in ((False, scores_without_nuclides), + (True, scores_with_nuclides)): + t = openmc.Tally() + t.filters = [mesh_filter] + t.estimator = 'analog' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mesh_filter] + t.estimator = 'tracklength' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + # Impose energy bins that dont match the MG structure and those + # that do + for match_energy_bins in [False, True]: + if match_energy_bins: + e_filter = matching_energy_filter + eout_filter = matching_eout_filter + else: + e_filter = energy_filter + eout_filter = energyout_filter + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'analog' + t.scores = scores + ['scatter', 'nu-scatter'] + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'collision' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter] + t.estimator = 'tracklength' + t.scores = scores + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + t = openmc.Tally() + t.filters = [mat_filter, e_filter, eout_filter] + t.scores = ['scatter', 'nu-scatter', 'nu-fission'] + if do_nuclides: + t.nuclides = nuclides + model.tallies.append(t) + + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() From 2c982863b0993704c7ff497b2c136f4f6ffaec88 Mon Sep 17 00:00:00 2001 From: GuySten Date: Mon, 9 Feb 2026 23:49:27 +0200 Subject: [PATCH 27/51] fix missing file --- tests/regression_tests/mgxs_library_condense/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/mgxs_library_condense/test.py b/tests/regression_tests/mgxs_library_condense/test.py index ada5950f157..eebe5f53ed1 100644 --- a/tests/regression_tests/mgxs_library_condense/test.py +++ b/tests/regression_tests/mgxs_library_condense/test.py @@ -48,7 +48,7 @@ def _get_results(self, hash_output=False): self.mgxs_lib.load_from_statepoint(sp) # Build a condensed 1-group MGXS Library - one_group = openmc.mgxs.EnergyGroups([0., 20.e6]) + one_group = openmc.mgxs.EnergyGroups([1e-5, 20.e6]) condense_lib = self.mgxs_lib.get_condensed_library(one_group) # Build a string from Pandas Dataframe for each 1-group MGXS From c4f149f4cff2830a93d4aa3eb029ab6d9d983651 Mon Sep 17 00:00:00 2001 From: GuySten Date: Tue, 10 Feb 2026 09:56:20 +0200 Subject: [PATCH 28/51] simplify code --- openmc/mgxs/groups.py | 2 ++ tests/regression_tests/mg_basic/test.py | 2 +- tests/regression_tests/mg_basic_delayed/test.py | 2 +- tests/regression_tests/mg_legendre/test.py | 2 +- tests/regression_tests/mg_max_order/test.py | 2 +- tests/regression_tests/mg_survival_biasing/test.py | 2 +- tests/regression_tests/mg_tallies/test.py | 2 +- tests/regression_tests/mg_temperature/build_2g.py | 2 +- tests/regression_tests/mgxs_library_ce_to_mg/test.py | 2 +- tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py | 2 +- tests/regression_tests/mgxs_library_condense/test.py | 4 ++-- tests/regression_tests/mgxs_library_correction/test.py | 2 +- tests/regression_tests/mgxs_library_distribcell/test.py | 2 +- tests/regression_tests/mgxs_library_hdf5/test.py | 2 +- tests/regression_tests/mgxs_library_histogram/test.py | 2 +- tests/regression_tests/mgxs_library_mesh/test.py | 2 +- tests/regression_tests/mgxs_library_no_nuclides/test.py | 2 +- tests/regression_tests/mgxs_library_nuclides/test.py | 2 +- tests/regression_tests/mgxs_library_specific_nuclides/test.py | 2 +- tests/regression_tests/volume_calc/test.py | 2 +- 20 files changed, 22 insertions(+), 20 deletions(-) diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 2f2c8b0e659..2403db4e3a7 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -78,6 +78,8 @@ def group_edges(self): @group_edges.setter def group_edges(self, edges): cv.check_type('group edges', edges, Iterable, Real) + edges[0] = max(edges[0], 1e-5) + cv.check_increasing('group edges', edges) cv.check_greater_than('number of group edges', len(edges), 1) for i, edge in enumerate(edges): cv.check_greater_than( diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py index 46bfa336698..7b456bb9d07 100644 --- a/tests/regression_tests/mg_basic/test.py +++ b/tests/regression_tests/mg_basic/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) mg_cross_sections_file = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index 8e26212027f..f0474a5675d 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) n_dg = 2 mg_cross_sections_file = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mg_legendre/test.py b/tests/regression_tests/mg_legendre/test.py index 6601715149e..b5a05c706d9 100644 --- a/tests/regression_tests/mg_legendre/test.py +++ b/tests/regression_tests/mg_legendre/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) mg_cross_sections_file = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mg_max_order/test.py b/tests/regression_tests/mg_max_order/test.py index 16542518081..97d3f57d7ab 100644 --- a/tests/regression_tests/mg_max_order/test.py +++ b/tests/regression_tests/mg_max_order/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) mg_cross_sections_file = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mg_survival_biasing/test.py b/tests/regression_tests/mg_survival_biasing/test.py index ac8b370c097..5d75611a9d4 100644 --- a/tests/regression_tests/mg_survival_biasing/test.py +++ b/tests/regression_tests/mg_survival_biasing/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) mg_cross_sections_file = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index fc63ff7301f..f4e9693f6f8 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -10,7 +10,7 @@ def create_library(): # Instantiate the energy group data and file object - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) mg_cross_sections_file = openmc.MGXSLibrary(groups, 6) diff --git a/tests/regression_tests/mg_temperature/build_2g.py b/tests/regression_tests/mg_temperature/build_2g.py index cc32c829346..1fb7234499b 100644 --- a/tests/regression_tests/mg_temperature/build_2g.py +++ b/tests/regression_tests/mg_temperature/build_2g.py @@ -169,7 +169,7 @@ def create_macro_dict(xs_micro): def create_openmc_2mg_libs(names): """Built a micro/macro two group openmc MGXS libraries""" # Initialized library params - group_edges = [1e-5, 0.625, 20.0e6] + group_edges = [0.0, 0.625, 20.0e6] groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index d30d74a2a5f..075167f5884 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -14,7 +14,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py index dd6ace8197f..489105f8f54 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -14,7 +14,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_condense/test.py b/tests/regression_tests/mgxs_library_condense/test.py index eebe5f53ed1..bbc4c11bfa9 100644 --- a/tests/regression_tests/mgxs_library_condense/test.py +++ b/tests/regression_tests/mgxs_library_condense/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) @@ -48,7 +48,7 @@ def _get_results(self, hash_output=False): self.mgxs_lib.load_from_statepoint(sp) # Build a condensed 1-group MGXS Library - one_group = openmc.mgxs.EnergyGroups([1e-5, 20.e6]) + one_group = openmc.mgxs.EnergyGroups([0., 20.e6]) condense_lib = self.mgxs_lib.get_condensed_library(one_group) # Build a string from Pandas Dataframe for each 1-group MGXS diff --git a/tests/regression_tests/mgxs_library_correction/test.py b/tests/regression_tests/mgxs_library_correction/test.py index 8a8bea068dc..64e638e442f 100644 --- a/tests/regression_tests/mgxs_library_correction/test.py +++ b/tests/regression_tests/mgxs_library_correction/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_distribcell/test.py b/tests/regression_tests/mgxs_library_distribcell/test.py index 54c847afaf3..464b309c002 100644 --- a/tests/regression_tests/mgxs_library_distribcell/test.py +++ b/tests/regression_tests/mgxs_library_distribcell/test.py @@ -15,7 +15,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a one-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 20.e6]) # Initialize MGXS Library for a few cross section types # for one material-filled cell in the geometry diff --git a/tests/regression_tests/mgxs_library_hdf5/test.py b/tests/regression_tests/mgxs_library_hdf5/test.py index a3d0822a0db..4fb4bf09369 100644 --- a/tests/regression_tests/mgxs_library_hdf5/test.py +++ b/tests/regression_tests/mgxs_library_hdf5/test.py @@ -16,7 +16,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_histogram/test.py b/tests/regression_tests/mgxs_library_histogram/test.py index f298eeb32c3..42fc1957a6b 100644 --- a/tests/regression_tests/mgxs_library_histogram/test.py +++ b/tests/regression_tests/mgxs_library_histogram/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_mesh/test.py b/tests/regression_tests/mgxs_library_mesh/test.py index 32d4c0b8a26..c1a5980b5d1 100644 --- a/tests/regression_tests/mgxs_library_mesh/test.py +++ b/tests/regression_tests/mgxs_library_mesh/test.py @@ -32,7 +32,7 @@ def model(): model.settings.particles = 1000 # Initialize a one-group structure - energy_groups = openmc.mgxs.EnergyGroups([1e-5, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups([0, 20.e6]) # Initialize MGXS Library for a few cross section types # for one material-filled cell in the geometry diff --git a/tests/regression_tests/mgxs_library_no_nuclides/test.py b/tests/regression_tests/mgxs_library_no_nuclides/test.py index 4c77cbc469f..a02086af3ec 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_no_nuclides/test.py @@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_nuclides/test.py b/tests/regression_tests/mgxs_library_nuclides/test.py index 4f563d5c31b..a10070358ad 100644 --- a/tests/regression_tests/mgxs_library_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_nuclides/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/test.py b/tests/regression_tests/mgxs_library_specific_nuclides/test.py index ee8b9006fab..0ccbb83bdbe 100644 --- a/tests/regression_tests/mgxs_library_specific_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_specific_nuclides/test.py @@ -12,7 +12,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Initialize a two-group structure - energy_groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.e6]) + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) # Initialize MGXS Library for a few cross section types self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 25e74cd4cc0..c94d16c7975 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -81,7 +81,7 @@ def __init__(self, is_ce, *args, **kwargs): # Create the MGXS file if necessary if not self.is_ce: - groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 20.e6]) + groups = openmc.mgxs.EnergyGroups(group_edges=[0., 20.e6]) mg_xs_file = openmc.MGXSLibrary(groups) nu = [2.] From 0c057df5009b8a6e86e4d8c2c4d59477552a838a Mon Sep 17 00:00:00 2001 From: GuySten <62616591+GuySten@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:58:06 +0200 Subject: [PATCH 29/51] Remove group edge validation checks Removed validation for group edges in the MGXS class. --- openmc/mgxs/groups.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 2403db4e3a7..09c6209de90 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -81,10 +81,6 @@ def group_edges(self, edges): edges[0] = max(edges[0], 1e-5) cv.check_increasing('group edges', edges) cv.check_greater_than('number of group edges', len(edges), 1) - for i, edge in enumerate(edges): - cv.check_greater_than( - "group edge {i}", edge, edges[i - 1] if i > 0 else 1e-5, equality=True - ) self._group_edges = np.array(edges) @property From db2c48c1abfcf74bd7e331172e7a139875b252ba Mon Sep 17 00:00:00 2001 From: GuySten Date: Tue, 10 Feb 2026 21:51:05 +0200 Subject: [PATCH 30/51] simplify code --- openmc/mgxs/groups.py | 1 - src/mgxs_interface.cpp | 2 +- src/xsdata.cpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 09c6209de90..aea7a6d2995 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -78,7 +78,6 @@ def group_edges(self): @group_edges.setter def group_edges(self, edges): cv.check_type('group edges', edges, Iterable, Real) - edges[0] = max(edges[0], 1e-5) cv.check_increasing('group edges', edges) cv.check_greater_than('number of group edges', len(edges), 1) self._group_edges = np.array(edges) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 4f79773bc76..24cba30afd5 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -265,7 +265,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) } if (!void_velocities_exist) { for (int i = 0; i < energy_bins_.size() - 1; ++i) { - double e_min = energy_bins_[i]; + double e_min = std::max(energy_bins_[i], 1e-5); double e_max = energy_bins_[i + 1]; double v = C_LIGHT * std::log(e_max / e_min) / (std::acosh(1 + e_max / MASS_NEUTRON_EV) - diff --git a/src/xsdata.cpp b/src/xsdata.cpp index a8948de6274..b2bf61eea71 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -99,7 +99,7 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, if (!object_exists(xsdata_grp, "inverse-velocity")) { xt::xarray inv_vel = xt::zeros({energy_groups}); for (int i = 0; i < energy_groups; ++i) { - double e_min = energy_bins[i]; + double e_min = std::max(energy_bins[i], 1e-5); double e_max = energy_bins[i + 1]; inv_vel[i] = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - From 1f653f76ea00b675cd6a86b868ebd207a7ff3ddf Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 11 Feb 2026 06:55:05 +0200 Subject: [PATCH 31/51] close hdf5 groups --- src/mgxs_interface.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 24cba30afd5..bf8ed856e23 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -249,6 +249,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) dset_names[i] = new char[151]; } get_datasets(kT_group, dset_names); + close_group(kT_group); if (num_temps > 1) fatal_error("Multigroup void data must have only one dummy temperature"); auto xsdata_grp = open_group(void_grp, dset_names[0]); @@ -262,6 +263,8 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) } void_velocities_exist = true; } + close_group(xsdata_grp); + close_group(void_grp); } if (!void_velocities_exist) { for (int i = 0; i < energy_bins_.size() - 1; ++i) { From e56b6edca9a476549e300ff3f259a7181fd47098 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 11 Feb 2026 17:40:39 +0200 Subject: [PATCH 32/51] update test results --- tests/regression_tests/mg_basic_delayed/results_true.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/mg_basic_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat index f150030b9b8..995556bdb02 100644 --- a/tests/regression_tests/mg_basic_delayed/results_true.dat +++ b/tests/regression_tests/mg_basic_delayed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.017078E+00 1.181139E-02 +1.012441E+00 7.095889E-03 From d5af24c7c911c4508b388e137b54ab5d407557f0 Mon Sep 17 00:00:00 2001 From: GuySten Date: Fri, 6 Mar 2026 20:54:10 +0200 Subject: [PATCH 33/51] update --- include/openmc/mgxs.h | 6 +-- include/openmc/mgxs_interface.h | 6 ++- include/openmc/xsdata.h | 3 +- src/mgxs.cpp | 9 ++--- src/mgxs_interface.cpp | 69 +++++++++++++-------------------- src/particle.cpp | 9 +---- src/xsdata.cpp | 18 +-------- 7 files changed, 43 insertions(+), 77 deletions(-) diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 83e26472a8e..5d8ff58c239 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -95,10 +95,10 @@ class Mgxs { //! //! @param xs_id HDF5 group id for the cross section data. //! @param temperature Temperatures to read. - //! @param energy_bins energy bins + //! @param num_group number of energy groups //! @param num_delay number of delayed groups - Mgxs(hid_t xs_id, const vector& temperature, - const vector& energy_bins, int num_delay); + Mgxs(hid_t xs_id, const vector& temperature, int num_group, + int num_delay); //! \brief Constructor that initializes and populates all data to build a //! macroscopic cross section from microscopic cross sections. diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 893ad1c1889..90b52791584 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -49,6 +49,9 @@ class MgxsInterface { // Get the group index corresponding to a continuous energy int get_group_index(double E); + // Get the inverse velocity corresponding to particle p + double get_inverse_velocity(const Particle& p); + int num_energy_groups_; int num_delayed_groups_; vector xs_names_; // available names in HDF5 file @@ -61,7 +64,8 @@ class MgxsInterface { vector energy_bin_avg_; vector rev_energy_bins_; vector> nuc_temps_; // all available temperatures - vector void_velocities_; // velocity of particles in void regions + vector + default_inverse_velocity; // approximate default inverse-velocity data }; namespace data { diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index bea217d8ec4..c9dbde986b2 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -120,11 +120,10 @@ class XsData { //! the incoming particle. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - //! @param energy_bins energy bins of XsData void from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, AngleDistributionType final_scatter_format, int order_data, - bool is_isotropic, int n_pol, int n_azi, const vector& energy_bins); + bool is_isotropic, int n_pol, int n_azi); //! \brief Combines the microscopic data to a macroscopic object. //! diff --git a/src/mgxs.cpp b/src/mgxs.cpp index fa5aabcc406..a0fe4060ddb 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -263,9 +263,9 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, //============================================================================== -Mgxs::Mgxs(hid_t xs_id, const vector& temperature, - const vector& energy_bins, int num_delay) - : num_groups(energy_bins.size() - 1), num_delayed_groups(num_delay) +Mgxs::Mgxs( + hid_t xs_id, const vector& temperature, int num_group, int num_delay) + : num_groups(num_group), num_delayed_groups(num_delay) { // Call generic data gathering routine (will populate the metadata) int order_data; @@ -288,8 +288,7 @@ Mgxs::Mgxs(hid_t xs_id, const vector& temperature, hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, - final_scatter_format, order_data, is_isotropic, n_pol, n_azi, - energy_bins); + final_scatter_format, order_data, is_isotropic, n_pol, n_azi); close_group(xsdata_grp); } // end temperature loop diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 9cce937804c..135ba5dd642 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -109,7 +109,7 @@ void MgxsInterface::add_mgxs( } nuclides_.emplace_back( - xs_grp, temperature, energy_bins_, num_delayed_groups_); + xs_grp, temperature, num_energy_groups_, num_delayed_groups_); close_group(xs_grp); } @@ -193,6 +193,23 @@ int MgxsInterface::get_group_index(double E) //============================================================================== +double get_inverse_velocity(const Particle& p) +{ + auto mat = p->material(); + if (mat != MATERIAL_VOID) { + auto& macro_xs = macro_xs_[mat]; + int macro_t = p->mg_xs_cache().t; + int macro_a = macro_xs.get_angle_index(p->u()); + double inv_v = + macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p->g(), macro_t, macro_a); + if (inv_v > 0.0) + return inv_v; + } + return default_inverse_velocity_[p->g()]; +} + +//============================================================================== + void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data @@ -237,46 +254,16 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) "library file!"); } - // Read void velocities - bool void_velocities_exist = false; - if (object_exists(file_id, "void")) { - auto void_grp = open_group(file_id, "void"); - // Determine the available temperatures - hid_t kT_group = open_group(void_grp, "kTs"); - size_t num_temps = get_num_datasets(kT_group); - char** dset_names = new char*[num_temps]; - for (int i = 0; i < num_temps; i++) { - dset_names[i] = new char[151]; - } - get_datasets(kT_group, dset_names); - close_group(kT_group); - if (num_temps > 1) - fatal_error("Multigroup void data must have only one dummy temperature"); - auto xsdata_grp = open_group(void_grp, dset_names[0]); - if (object_exists(xsdata_grp, "inverse-velocity")) { - vector shape {1, static_cast(num_energy_groups_)}; - xt::xtensor inverse_velocity = xt::zeros(shape); - read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); - auto velocity = 1.0 / inverse_velocity; - for (double v : velocity) { - void_velocities_.push_back(v); - } - void_velocities_exist = true; - } - close_group(xsdata_grp); - close_group(void_grp); - } - if (!void_velocities_exist) { - for (int i = 0; i < energy_bins_.size() - 1; ++i) { - double e_min = std::max(energy_bins_[i], 1e-5); - double e_max = energy_bins_[i + 1]; - double v = C_LIGHT * std::log(e_max / e_min) / - (std::acosh(1 + e_max / MASS_NEUTRON_EV) - - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - - std::acosh(1 + e_min / MASS_NEUTRON_EV) + - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)); - void_velocities_.push_back(v); - } + // Calculate approximate default inverse velocity data + for (int i = 0; i < energy_bins_.size() - 1; ++i) { + double e_min = std::max(energy_bins_[i], 1e-5); + double e_max = energy_bins_[i + 1]; + double inv_v = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - + std::acosh(1 + e_min / MASS_NEUTRON_EV) + + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / + (C_LIGHT * std::log(e_max / e_min)); + default_inverse_velocity.push_back(inv_v); } // Close MGXS HDF5 file diff --git a/src/particle.cpp b/src/particle.cpp index af8f04a0ea5..8e60d39aa34 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -62,14 +62,7 @@ double Particle::speed() const return C_LIGHT * std::sqrt(this->E() * (this->E() + 2 * mass)) / (this->E() + mass); } else { - auto mat = this->material(); - if (mat == MATERIAL_VOID) - return data::mg.void_velocities_[this->g()]; - auto& macro_xs = data::mg.macro_xs_[mat]; - int macro_t = this->mg_xs_cache().t; - int macro_a = macro_xs.get_angle_index(this->u()); - return 1.0 / macro_xs.get_xs( - MgxsType::INVERSE_VELOCITY, this->g(), macro_t, macro_a); + return 1.0 / data::mg.get_inverse_velocity(&p); } } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 7b94034c2a1..33d063a7b9a 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -78,7 +78,7 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, AngleDistributionType final_scatter_format, int order_data, bool is_isotropic, - int n_pol, int n_azi, const vector& energy_bins) + int n_pol, int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed size_t n_ang = n_pol * n_azi; @@ -93,22 +93,6 @@ void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, read_nd_tensor(xsdata_grp, "absorption", absorption, true); read_nd_tensor(xsdata_grp, "inverse-velocity", inverse_velocity); - if (!object_exists(xsdata_grp, "inverse-velocity")) { - xt::xarray inv_vel = xt::zeros({energy_groups}); - for (int i = 0; i < energy_groups; ++i) { - double e_min = std::max(energy_bins[i], 1e-5); - double e_max = energy_bins[i + 1]; - inv_vel[i] = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - - std::acosh(1 + e_min / MASS_NEUTRON_EV) + - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / - std::log(e_max / e_min) / C_LIGHT; - } - for (int j = 0; j < n_ang; ++j) { - xt::view(inverse_velocity, j, xt::all()) = inv_vel; - } - } - // Get scattering data scatter_from_hdf5( xsdata_grp, n_ang, scatter_format, final_scatter_format, order_data); From 1861ab1d1bd6bc4b37da9d14ca73813310b95ff1 Mon Sep 17 00:00:00 2001 From: GuySten Date: Fri, 6 Mar 2026 21:09:22 +0200 Subject: [PATCH 34/51] fix some errors --- include/openmc/mgxs_interface.h | 2 +- src/mgxs_interface.cpp | 14 +++++++------- src/particle.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 90b52791584..d92e51bcf2e 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -65,7 +65,7 @@ class MgxsInterface { vector rev_energy_bins_; vector> nuc_temps_; // all available temperatures vector - default_inverse_velocity; // approximate default inverse-velocity data + default_inverse_velocity_; // approximate default inverse-velocity data }; namespace data { diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 135ba5dd642..359c50e7863 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -193,19 +193,19 @@ int MgxsInterface::get_group_index(double E) //============================================================================== -double get_inverse_velocity(const Particle& p) +double MgxsInterface::get_inverse_velocity(const Particle& p) { - auto mat = p->material(); + auto mat = p.material(); if (mat != MATERIAL_VOID) { auto& macro_xs = macro_xs_[mat]; - int macro_t = p->mg_xs_cache().t; - int macro_a = macro_xs.get_angle_index(p->u()); + int macro_t = p.mg_xs_cache().t; + int macro_a = macro_xs.get_angle_index(p.u()); double inv_v = - macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p->g(), macro_t, macro_a); + macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p.g(), macro_t, macro_a); if (inv_v > 0.0) return inv_v; } - return default_inverse_velocity_[p->g()]; + return default_inverse_velocity_[p.g()]; } //============================================================================== @@ -263,7 +263,7 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) std::acosh(1 + e_min / MASS_NEUTRON_EV) + std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / (C_LIGHT * std::log(e_max / e_min)); - default_inverse_velocity.push_back(inv_v); + default_inverse_velocity_.push_back(inv_v); } // Close MGXS HDF5 file diff --git a/src/particle.cpp b/src/particle.cpp index 8e60d39aa34..135aa373dd8 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -62,7 +62,7 @@ double Particle::speed() const return C_LIGHT * std::sqrt(this->E() * (this->E() + 2 * mass)) / (this->E() + mass); } else { - return 1.0 / data::mg.get_inverse_velocity(&p); + return 1.0 / data::mg.get_inverse_velocity(*this); } } From fe7e5a3148d3b0438d66975d59ea80e6f63ac7c0 Mon Sep 17 00:00:00 2001 From: GuySten Date: Fri, 6 Mar 2026 21:51:33 +0200 Subject: [PATCH 35/51] another simplification --- src/particle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 135aa373dd8..80764bbbd87 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -247,8 +247,7 @@ void Particle::event_advance() double speed = this->speed(); double time_cutoff = settings::time_cutoff[type().transport_index()]; - double distance_cutoff = - (time_cutoff < INFTY) ? (time_cutoff - time()) * speed : INFTY; + double distance_cutoff = (time_cutoff - time()) * speed; // Select smaller of the three distances double distance = From d4f7c34e58e96b22298d6880f1b35a8778d7a8bb Mon Sep 17 00:00:00 2001 From: GuySten Date: Fri, 6 Mar 2026 23:11:42 +0200 Subject: [PATCH 36/51] Revert "another simplification" This reverts commit fe7e5a3148d3b0438d66975d59ea80e6f63ac7c0. --- src/particle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/particle.cpp b/src/particle.cpp index 80764bbbd87..135aa373dd8 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -247,7 +247,8 @@ void Particle::event_advance() double speed = this->speed(); double time_cutoff = settings::time_cutoff[type().transport_index()]; - double distance_cutoff = (time_cutoff - time()) * speed; + double distance_cutoff = + (time_cutoff < INFTY) ? (time_cutoff - time()) * speed : INFTY; // Select smaller of the three distances double distance = From f9a7e380db85ccf50349bc5f1cc0d00085efa972 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 12:05:49 +0200 Subject: [PATCH 37/51] rafactor mass method --- include/openmc/particle.h | 2 ++ src/particle.cpp | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 2f6e6196bf1..e75f3785a53 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -39,6 +39,8 @@ class Particle : public ParticleData { double speed() const; + double mass() const; + //! create a secondary particle // //! stores the current phase space attributes of the particle in the diff --git a/src/particle.cpp b/src/particle.cpp index 135aa373dd8..e48e082dabf 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -47,16 +47,7 @@ double Particle::speed() const { if (settings::run_CE) { // Determine mass in eV/c^2 - double mass; - switch (type().pdg_number()) { - case PDG_NEUTRON: - mass = MASS_NEUTRON_EV; - case PDG_ELECTRON: - case PDG_POSITRON: - mass = MASS_ELECTRON_EV; - default: - mass = this->type().mass() * AMU_EV; - } + double mass = this->mass(); // Equivalent to C * sqrt(1-(m/(m+E))^2) without problem at E<E() * (this->E() + 2 * mass)) / @@ -66,6 +57,19 @@ double Particle::speed() const } } +double Particle::mass() const +{ + switch (type().pdg_number()) { + case PDG_NEUTRON: + return MASS_NEUTRON_EV; + case PDG_ELECTRON: + case PDG_POSITRON: + return MASS_ELECTRON_EV; + default: + return this->type().mass() * AMU_EV; + } +} + bool Particle::create_secondary( double wgt, Direction u, double E, ParticleType type) { From ab6c7701e165c1bae17d2f9e2506e0fa34c64a89 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 21:12:54 +0200 Subject: [PATCH 38/51] further simplification --- include/openmc/mgxs_interface.h | 3 - src/mgxs.cpp | 2 + src/mgxs_interface.cpp | 27 ++------- src/particle.cpp | 9 ++- tests/unit_tests/test_mg_inverse_velocity.py | 60 ++++++++++++++++++++ 5 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 tests/unit_tests/test_mg_inverse_velocity.py diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index d92e51bcf2e..117ac503d49 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -49,9 +49,6 @@ class MgxsInterface { // Get the group index corresponding to a continuous energy int get_group_index(double E); - // Get the inverse velocity corresponding to particle p - double get_inverse_velocity(const Particle& p); - int num_energy_groups_; int num_delayed_groups_; vector xs_names_; // available names in HDF5 file diff --git a/src/mgxs.cpp b/src/mgxs.cpp index a0fe4060ddb..34a1b4f9d5f 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -510,6 +510,8 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, break; case MgxsType::INVERSE_VELOCITY: val = xs_t->inverse_velocity(a, gin); + if (val == 0) + val = data::mg.default_inverse_velocity_[gin]; break; case MgxsType::DECAY_RATE: if (dg != nullptr) { diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 359c50e7863..706ac457431 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -193,23 +193,6 @@ int MgxsInterface::get_group_index(double E) //============================================================================== -double MgxsInterface::get_inverse_velocity(const Particle& p) -{ - auto mat = p.material(); - if (mat != MATERIAL_VOID) { - auto& macro_xs = macro_xs_[mat]; - int macro_t = p.mg_xs_cache().t; - int macro_a = macro_xs.get_angle_index(p.u()); - double inv_v = - macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p.g(), macro_t, macro_a); - if (inv_v > 0.0) - return inv_v; - } - return default_inverse_velocity_[p.g()]; -} - -//============================================================================== - void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data @@ -256,12 +239,10 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) // Calculate approximate default inverse velocity data for (int i = 0; i < energy_bins_.size() - 1; ++i) { - double e_min = std::max(energy_bins_[i], 1e-5); - double e_max = energy_bins_[i + 1]; - double inv_v = (std::acosh(1 + e_max / MASS_NEUTRON_EV) - - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_max) - - std::acosh(1 + e_min / MASS_NEUTRON_EV) + - std::sqrt(1 + 2 * MASS_NEUTRON_EV / e_min)) / + double e_min = std::max(energy_bins_[i + 1], 1e-5); + double e_max = energy_bins_[i]; + double inv_v = (std::acosh(e_max / MASS_NEUTRON_EV) - + std::acosh(e_min / MASS_NEUTRON_EV)) / (C_LIGHT * std::log(e_max / e_min)); default_inverse_velocity_.push_back(inv_v); } diff --git a/src/particle.cpp b/src/particle.cpp index e48e082dabf..3f7691f36fb 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -53,7 +53,14 @@ double Particle::speed() const return C_LIGHT * std::sqrt(this->E() * (this->E() + 2 * mass)) / (this->E() + mass); } else { - return 1.0 / data::mg.get_inverse_velocity(*this); + auto mat = this->material(); + if (mat == MATERIAL_VOID) + return 1.0 / data::mg.default_inverse_velocity_[this->g()]; + auto& macro_xs = data::mg.macro_xs_[mat]; + int macro_t = this->mg_xs_cache().t; + int macro_a = macro_xs.get_angle_index(this->u()); + return 1.0 / macro_xs.get_xs( + MgxsType::INVERSE_VELOCITY, this->g(), macro_t, macro_a); } } diff --git a/tests/unit_tests/test_mg_inverse_velocity.py b/tests/unit_tests/test_mg_inverse_velocity.py new file mode 100644 index 00000000000..77569878eec --- /dev/null +++ b/tests/unit_tests/test_mg_inverse_velocity.py @@ -0,0 +1,60 @@ +import openmc +import numpy as np +import pytest + +@pytest.fixture +def one_group_lib(): + groups = openmc.mgxs.EnergyGroups([0.0, 20.0e6]) + xsdata = openmc.XSdata('slab_mat', groups) + xsdata.order = 0 + xsdata.set_total([0.0]) + xsdata.set_absorption([0.0]) + xsdata.set_scatter_matrix([[[0.0]]]) + + mg_library = openmc.MGXSLibrary(groups) + mg_library.add_xsdata(xsdata) + name = 'mgxs.h5' + mg_library.export_to_hdf5(name) + yield name + +@pytest.fixture +def slab_model(one_group_lib): + model = openmc.Model() + mat = openmc.Material(name='slab_material') + mat.set_density('macro', 1.0) + mat.add_macroscopic('slab_mat') + + model.materials = openmc.Materials([mat]) + model.materials.cross_sections = one_group_lib + + x_min = openmc.XPlane(x0=0.0, boundary_type='vacuum') + x_max = openmc.XPlane(x0=10.0, boundary_type='vacuum') + + y_min = openmc.YPlane(y0=-10.0, boundary_type='vacuum') + y_max = openmc.YPlane(y0=10.0, boundary_type='vacuum') + z_min = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') + z_max = openmc.ZPlane(z0=19.0, boundary_type='vacuum') + + cell = openmc.Cell(fill=mat, region=+z_min & -x_max & +y_min & -y_max & +z_min & -z_max) + model.geometry = openmc.Geometry([cell]) + + model.settings = openmc.Settings() + model.settings.energy_mode = 'multi-group' + model.settings.run_mode = 'fixed source' + model.settings.batches = 50 + model.settings.inactive = 10 + model.settings.particles = 5000 + + source = openmc.IndependentSource() + source.space = openmc.stats.Point((5.0, 0.0, 0.0)) + model.settings.source = source + return model + +def test_inverse_velocity(run_in_tmpdir, slab_model): + tally = openmc.Tally() + tally.scores = ['flux','inverse-velocity'] + slab_model.tallies = [tally] + slab_model.run(apply_tally_results=True) + inverse_velocity = tally.mean.squeeze()[1]/tally.mean.squeeze()[0] + + assert inverse_velocity == pytest.approx(5.25e-5) From 3d91c0dd0fa18b43e5336cd56acd4dc1b8ff0bc9 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 21:47:57 +0200 Subject: [PATCH 39/51] fix some errors --- src/mgxs.cpp | 2 +- src/mgxs_interface.cpp | 8 +++++--- tests/unit_tests/test_mg_inverse_velocity.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 34a1b4f9d5f..1dc090ab969 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -510,7 +510,7 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, break; case MgxsType::INVERSE_VELOCITY: val = xs_t->inverse_velocity(a, gin); - if (val == 0) + if (!(val > 0)) val = data::mg.default_inverse_velocity_[gin]; break; case MgxsType::DECAY_RATE: diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 706ac457431..c2253ce174b 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -241,9 +241,11 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) for (int i = 0; i < energy_bins_.size() - 1; ++i) { double e_min = std::max(energy_bins_[i + 1], 1e-5); double e_max = energy_bins_[i]; - double inv_v = (std::acosh(e_max / MASS_NEUTRON_EV) - - std::acosh(e_min / MASS_NEUTRON_EV)) / - (C_LIGHT * std::log(e_max / e_min)); + double f = 1.0 / (C_LIGHT * std::log(e_max / e_min)); + double k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); + double k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); + double inv_v = + f * (2.0 * (std::atan(k_max) - std::atan(k_min)) - (k_max - k_min)); default_inverse_velocity_.push_back(inv_v); } diff --git a/tests/unit_tests/test_mg_inverse_velocity.py b/tests/unit_tests/test_mg_inverse_velocity.py index 77569878eec..267d5f1f16e 100644 --- a/tests/unit_tests/test_mg_inverse_velocity.py +++ b/tests/unit_tests/test_mg_inverse_velocity.py @@ -57,4 +57,4 @@ def test_inverse_velocity(run_in_tmpdir, slab_model): slab_model.run(apply_tally_results=True) inverse_velocity = tally.mean.squeeze()[1]/tally.mean.squeeze()[0] - assert inverse_velocity == pytest.approx(5.25e-5) + assert inverse_velocity == pytest.approx(1.6144e-5, rel=1e-4) From c017a90978c571e68bc4ecfbf2b5e531405c7a91 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 21:51:38 +0200 Subject: [PATCH 40/51] revert test --- tests/regression_tests/mg_basic_delayed/results_true.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression_tests/mg_basic_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat index 995556bdb02..f150030b9b8 100644 --- a/tests/regression_tests/mg_basic_delayed/results_true.dat +++ b/tests/regression_tests/mg_basic_delayed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.012441E+00 7.095889E-03 +1.017078E+00 1.181139E-02 From f8da4ffc44dbda5ed4435943e1b85d2e493620da Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 21:53:44 +0200 Subject: [PATCH 41/51] decrease number of particles --- tests/unit_tests/test_mg_inverse_velocity.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/test_mg_inverse_velocity.py b/tests/unit_tests/test_mg_inverse_velocity.py index 267d5f1f16e..b520e48d193 100644 --- a/tests/unit_tests/test_mg_inverse_velocity.py +++ b/tests/unit_tests/test_mg_inverse_velocity.py @@ -41,9 +41,8 @@ def slab_model(one_group_lib): model.settings = openmc.Settings() model.settings.energy_mode = 'multi-group' model.settings.run_mode = 'fixed source' - model.settings.batches = 50 - model.settings.inactive = 10 - model.settings.particles = 5000 + model.settings.batches = 3 + model.settings.particles = 10 source = openmc.IndependentSource() source.space = openmc.stats.Point((5.0, 0.0, 0.0)) From f7b0fd4d3d8305aab366df2f4cfea1119116905f Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 21:58:54 +0200 Subject: [PATCH 42/51] try further simplification --- src/particle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 3f7691f36fb..1e1d216d2bb 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -258,8 +258,7 @@ void Particle::event_advance() double speed = this->speed(); double time_cutoff = settings::time_cutoff[type().transport_index()]; - double distance_cutoff = - (time_cutoff < INFTY) ? (time_cutoff - time()) * speed : INFTY; + double distance_cutoff = (time_cutoff - time()) * speed; // Select smaller of the three distances double distance = From efa92503c40362f6d9bb6de3f0b9336909ea0243 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 7 Mar 2026 22:34:55 +0200 Subject: [PATCH 43/51] Revert "try further simplification" This reverts commit f7b0fd4d3d8305aab366df2f4cfea1119116905f. --- src/particle.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/particle.cpp b/src/particle.cpp index 1e1d216d2bb..3f7691f36fb 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -258,7 +258,8 @@ void Particle::event_advance() double speed = this->speed(); double time_cutoff = settings::time_cutoff[type().transport_index()]; - double distance_cutoff = (time_cutoff - time()) * speed; + double distance_cutoff = + (time_cutoff < INFTY) ? (time_cutoff - time()) * speed : INFTY; // Select smaller of the three distances double distance = From d16f89aecb9b6b5f25ba53121b3a59ba727584ae Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 11 Mar 2026 00:44:50 +0200 Subject: [PATCH 44/51] added docs --- docs/source/methods/cross_sections.rst | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index a66abb3ed40..e2e3d61205e 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -289,6 +289,35 @@ sections. This allows flexibility for the model to use highly anisotropic scattering information in the water while the fuel can be simulated with linear or even isotropic scattering. +^^^^^^^^^^^^^^ +Particle Speed +^^^^^^^^^^^^^^ + +When using a multigroup representation of cross sections the particle speed +has meaning only in an average sense. The particle speed is important when modeling dynamic behavior. OpenMC calculate the particle speed using the inverse velocity multigroup data if it is available. If it is not OpenMC uses an approximate velocity using the group energy bounds in the following way: + +.. math:: + + \frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{k}{E} dE + +Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy boundaries for group :math:`g`. +:math:`v(E)` is the neutron velocity calculated using relativistic kinematics, +:math:`k` is a normalization constant for the :math:`\frac{1}{E}` spectrum. + +The solution to this equation is: + +.. math:: + + v_g = \frac{1.0}{c * log(\frac{E_{\text{max}}^g}{E_{\text{min}}^g})} * ( 2*(atan(k_max) - atan(k_min)) + (k_max-k_min)) + +Where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of variables: + +.. math:: + + k = \sqrt{1+\frac{2 M_n}{E}} + +Where :math:`E` is the particle kinetic energy in eV and :math:`M_n` is the neutron mass in units of eV. + .. _logarithmic mapping technique: https://mcnp.lanl.gov/pdf_files/TechReport_2014_LANL_LA-UR-14-24530_Brown.pdf .. _Hwang: https://doi.org/10.13182/NSE87-A16381 From 03af12df17737adf02ddf87d99bd535dd7e72701 Mon Sep 17 00:00:00 2001 From: Adam Nelson <1037107+nelsonag@users.noreply.github.com> Date: Tue, 10 Mar 2026 18:50:26 -0500 Subject: [PATCH 45/51] Update cross_sections.rst Minor editorial correction to cross_sections.rst --- docs/source/methods/cross_sections.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index e2e3d61205e..bb7ec0dcef7 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -294,7 +294,7 @@ Particle Speed ^^^^^^^^^^^^^^ When using a multigroup representation of cross sections the particle speed -has meaning only in an average sense. The particle speed is important when modeling dynamic behavior. OpenMC calculate the particle speed using the inverse velocity multigroup data if it is available. If it is not OpenMC uses an approximate velocity using the group energy bounds in the following way: +has meaning only in an average sense. The particle speed is important when modeling dynamic behavior. OpenMC calculates the particle speed using the inverse velocity multigroup data if it is available. If it is not OpenMC uses an approximate velocity using the group energy bounds in the following way: .. math:: From 222611310c24381c0231b4c267e0237000598fd3 Mon Sep 17 00:00:00 2001 From: GuySten Date: Wed, 11 Mar 2026 02:16:30 +0200 Subject: [PATCH 46/51] improved docs according to reviewer suggestions --- docs/source/io_formats/mgxs_library.rst | 4 ++++ docs/source/methods/cross_sections.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index f7f5387a483..8a26311d1e3 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -133,6 +133,10 @@ Temperature-dependent data, provided for temperature K. This dataset is optional. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of [polar][azimuthal][groups]. + When this data is not available, an approximation using the + group energy boundaries is used. For more information see + the particle speed subsection in the multigroup-data section + of the theory manual. **//K/scatter_data/** diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index bb7ec0dcef7..5102827f637 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -304,6 +304,8 @@ Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy :math:`v(E)` is the neutron velocity calculated using relativistic kinematics, :math:`k` is a normalization constant for the :math:`\frac{1}{E}` spectrum. +This equation is valid when inside the group boundaries the neutron spectrum follows a typical :math:`\frac{1}{E}` slowing down spectrum. This assumption is widely used when generating fine group neutron cross section data libraries from continuous energy data. + The solution to this equation is: .. math:: From 76edf35bec7626419fc2c4d69abab8574b1cfdc1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 13 Mar 2026 12:11:12 -0500 Subject: [PATCH 47/51] Fix documentation --- docs/source/methods/cross_sections.rst | 36 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 5102827f637..567d24720e9 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -289,36 +289,46 @@ sections. This allows flexibility for the model to use highly anisotropic scattering information in the water while the fuel can be simulated with linear or even isotropic scattering. -^^^^^^^^^^^^^^ Particle Speed -^^^^^^^^^^^^^^ +-------------- -When using a multigroup representation of cross sections the particle speed -has meaning only in an average sense. The particle speed is important when modeling dynamic behavior. OpenMC calculates the particle speed using the inverse velocity multigroup data if it is available. If it is not OpenMC uses an approximate velocity using the group energy bounds in the following way: +When using a multigroup representation of cross sections, the particle speed has +meaning only in an average sense. The particle speed is important when modeling +dynamic behavior. OpenMC calculates the particle speed using the inverse +velocity multigroup data if it is available. If such data is not available, +OpenMC uses an approximate velocity using the group energy bounds in the +following way: .. math:: - \frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{k}{E} dE + \frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{k}{E} dE -Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy boundaries for group :math:`g`. -:math:`v(E)` is the neutron velocity calculated using relativistic kinematics, -:math:`k` is a normalization constant for the :math:`\frac{1}{E}` spectrum. +Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy +boundaries for group :math:`g`. :math:`v(E)` is the neutron velocity calculated +using relativistic kinematics, :math:`k` is a normalization constant for the +:math:`\frac{1}{E}` spectrum. -This equation is valid when inside the group boundaries the neutron spectrum follows a typical :math:`\frac{1}{E}` slowing down spectrum. This assumption is widely used when generating fine group neutron cross section data libraries from continuous energy data. +This equation is valid when inside the group boundaries the neutron spectrum +follows a typical :math:`\frac{1}{E}` slowing down spectrum. This assumption is +widely used when generating fine group neutron cross section data libraries from +continuous energy data. The solution to this equation is: .. math:: - v_g = \frac{1.0}{c * log(\frac{E_{\text{max}}^g}{E_{\text{min}}^g})} * ( 2*(atan(k_max) - atan(k_min)) + (k_max-k_min)) + v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} + \left[ 2(\arctan(k_\text{max}) - \arctan(k_\text{min})) + (k_\text{max}-k_\text{min})) \right] -Where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of variables: +where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of +variables: .. math:: - k = \sqrt{1+\frac{2 M_n}{E}} + k = \sqrt{1+\frac{2 m_n}{E}} -Where :math:`E` is the particle kinetic energy in eV and :math:`M_n` is the neutron mass in units of eV. +where :math:`E` is the particle kinetic energy in [eV] and :math:`m_n` is the +neutron mass in units of [eV]. .. _logarithmic mapping technique: https://mcnp.lanl.gov/pdf_files/TechReport_2014_LANL_LA-UR-14-24530_Brown.pdf From 874fcac7a5f24865bdca1e145934f5b352d92961 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 14 Mar 2026 23:17:23 +0200 Subject: [PATCH 48/51] fix math --- docs/source/methods/cross_sections.rst | 6 +++--- src/mgxs_interface.cpp | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 567d24720e9..525590a3909 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -301,11 +301,11 @@ following way: .. math:: - \frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{k}{E} dE + \frac{1}{v_g} = \int_{E_{\text{min}}^g}^{E_{\text{max}}^g} \frac{1}{v(E)} \frac{\alpha}{E} dE Where :math:`E_{\text{min}}^g` and :math:`E_{\text{max}}^g` are the group energy boundaries for group :math:`g`. :math:`v(E)` is the neutron velocity calculated -using relativistic kinematics, :math:`k` is a normalization constant for the +using relativistic kinematics, :math:`\alpha` is a normalization constant for the :math:`\frac{1}{E}` spectrum. This equation is valid when inside the group boundaries the neutron spectrum @@ -318,7 +318,7 @@ The solution to this equation is: .. math:: v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} - \left[ 2(\arctan(k_\text{max}) - \arctan(k_\text{min})) + (k_\text{max}-k_\text{min})) \right] + \left[ 2(\arctanh(k_\text{max}) - \arctanh(k_\text{min})) + (k_\text{max}-k_\text{min})) \right] where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of variables: diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index c2253ce174b..9cd407ec2a3 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -1,5 +1,6 @@ #include "openmc/mgxs_interface.h" +#include #include #include @@ -241,12 +242,12 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) for (int i = 0; i < energy_bins_.size() - 1; ++i) { double e_min = std::max(energy_bins_[i + 1], 1e-5); double e_max = energy_bins_[i]; - double f = 1.0 / (C_LIGHT * std::log(e_max / e_min)); - double k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); - double k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); - double inv_v = - f * (2.0 * (std::atan(k_max) - std::atan(k_min)) - (k_max - k_min)); - default_inverse_velocity_.push_back(inv_v); + double alpha = 1.0 / (C_LIGHT * std::log(e_max / e_min)); + std::complex k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); + std::complex k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); + std::complex inv_v = + alpha * (2.0 * (std::atanh(k_max) - std::atanh(k_min)) - (k_max - k_min)); + default_inverse_velocity_.push_back(std::real(inv_v)); } // Close MGXS HDF5 file From 12b57f5cad597db164d53ff94286dbbb7b306a9a Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 14 Mar 2026 23:29:18 +0200 Subject: [PATCH 49/51] fix doc format --- docs/source/methods/cross_sections.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 525590a3909..6d6c1eb97d4 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -317,8 +317,7 @@ The solution to this equation is: .. math:: - v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} - \left[ 2(\arctanh(k_\text{max}) - \arctanh(k_\text{min})) + (k_\text{max}-k_\text{min})) \right] + v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} \left[ 2(\arctanh(k_{\text{max}}) - \arctanh(k_{\text{min}})) + (k_{\text{max}}-k_{\text{min}})) \right] where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of variables: From 33f7e99d0f9c43f28587df7729f067f3dd10a6b3 Mon Sep 17 00:00:00 2001 From: GuySten Date: Sat, 14 Mar 2026 23:41:43 +0200 Subject: [PATCH 50/51] try fix doc format --- docs/source/methods/cross_sections.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 6d6c1eb97d4..aa9d85429db 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -317,7 +317,9 @@ The solution to this equation is: .. math:: - v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} \left[ 2(\arctanh(k_{\text{max}}) - \arctanh(k_{\text{min}})) + (k_{\text{max}}-k_{\text{min}})) \right] + v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} + \left[ 2(\operatorname{arctanh}(k_{\text{max}}) - \operatorname{arctanh}(k_{\text{min}})) + + (k_{\text{max}}-k_{\text{min}})) \right] where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of variables: From 264dcb1efa495650ba0cbab28f93ceafa2fb0e35 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 2 Apr 2026 10:54:38 -0500 Subject: [PATCH 51/51] Avoid use of complex math, fix documentation --- docs/source/methods/cross_sections.rst | 16 ++++++++-------- src/mgxs_interface.cpp | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index aa9d85429db..764c4c62808 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -317,19 +317,19 @@ The solution to this equation is: .. math:: - v_g = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} - \left[ 2(\operatorname{arctanh}(k_{\text{max}}) - \operatorname{arctanh}(k_{\text{min}})) - + (k_{\text{max}}-k_{\text{min}})) \right] + \frac{1}{v_g} = \frac{1}{c \log\left(\frac{E_{\text{max}}^g}{E_{\text{min}}^g}\right)} + \left[ 2(\operatorname{arctanh}(k_{\text{max}}^{-1}) - \operatorname{arctanh}(k_{\text{min}}^{-1})) + - (k_{\text{max}}-k_{\text{min}}) \right] -where :math:`k_{\text{max}}`, :math:`k_{\text{min}}` are defined by a change of -variables: +where :math:`c` is the speed of light and :math:`k_{\text{max}}`, +:math:`k_{\text{min}}` are defined by a change of variables: .. math:: - k = \sqrt{1+\frac{2 m_n}{E}} + k = \sqrt{1+\frac{2 m_n c^2}{E}} -where :math:`E` is the particle kinetic energy in [eV] and :math:`m_n` is the -neutron mass in units of [eV]. +where :math:`E` is the particle kinetic energy and :math:`m_n` is the neutron +rest mass. .. _logarithmic mapping technique: https://mcnp.lanl.gov/pdf_files/TechReport_2014_LANL_LA-UR-14-24530_Brown.pdf diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 9cd407ec2a3..865c565808d 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -1,6 +1,5 @@ #include "openmc/mgxs_interface.h" -#include #include #include @@ -243,11 +242,12 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) double e_min = std::max(energy_bins_[i + 1], 1e-5); double e_max = energy_bins_[i]; double alpha = 1.0 / (C_LIGHT * std::log(e_max / e_min)); - std::complex k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); - std::complex k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); - std::complex inv_v = - alpha * (2.0 * (std::atanh(k_max) - std::atanh(k_min)) - (k_max - k_min)); - default_inverse_velocity_.push_back(std::real(inv_v)); + double k_max = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_max); + double k_min = std::sqrt(1 + 2.0 * MASS_NEUTRON_EV / e_min); + double inv_v = + alpha * (2.0 * (std::atanh(1.0 / k_max) - std::atanh(1.0 / k_min)) - + (k_max - k_min)); + default_inverse_velocity_.push_back(inv_v); } // Close MGXS HDF5 file