From e6fdb9a50c2ee920d809a9763a820fda0d5a1854 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 15 Feb 2026 12:21:25 -0600 Subject: [PATCH 01/20] preliminary implementation --- include/openmc/settings.h | 8 +- openmc/settings.py | 52 ++++--- src/finalize.cpp | 1 - src/particle.cpp | 135 ++++++++++-------- src/settings.cpp | 26 +++- .../surface_source_write/_visualize.py | 6 +- .../case-22/inputs_true.dat | 42 ++++++ .../case-22/results_true.dat | 0 .../case-23/inputs_true.dat | 42 ++++++ .../case-23/results_true.dat | 0 .../case-24/inputs_true.dat | 42 ++++++ .../case-24/results_true.dat | 0 .../surface_source_write/test.py | 119 +++++++++++---- tests/unit_tests/test_surface_source_write.py | 30 ++-- 14 files changed, 369 insertions(+), 134 deletions(-) create mode 100644 tests/regression_tests/surface_source_write/case-22/inputs_true.dat create mode 100644 tests/regression_tests/surface_source_write/case-22/results_true.dat create mode 100644 tests/regression_tests/surface_source_write/case-23/inputs_true.dat create mode 100644 tests/regression_tests/surface_source_write/case-23/results_true.dat create mode 100644 tests/regression_tests/surface_source_write/case-24/inputs_true.dat create mode 100644 tests/regression_tests/surface_source_write/case-24/results_true.dat diff --git a/include/openmc/settings.h b/include/openmc/settings.h index b369c99fef8..44df973abad 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -177,10 +177,10 @@ extern int64_t ssw_max_particles; //!< maximum number of particles to be //!< banked on surfaces per process extern int64_t ssw_max_files; //!< maximum number of surface source files //!< to be created -extern int64_t ssw_cell_id; //!< Cell id for the surface source - //!< write setting -extern SSWCellType ssw_cell_type; //!< Type of option for the cell - //!< argument of surface source write +extern vector ssw_cell_ids; //!< Cell ids for the surface source + //!< write setting +extern SSWCellType ssw_cell_type; //!< Type of option for the cell + //!< argument of surface source write extern TemperatureMethod temperature_method; //!< method for choosing temperatures extern double diff --git a/openmc/settings.py b/openmc/settings.py index 2ad1d06e757..1c67138eb20 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -280,13 +280,13 @@ class Settings: process (int) :max_source_files: Maximum number of surface source files to be created (int) :mcpl: Output in the form of an MCPL-file (bool) - :cell: Cell ID used to determine if particles crossing identified + :cell: List of cell IDs used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this declared cell will be banked (int) - :cellfrom: Cell ID used to determine if particles crossing identified + :cellfrom: List of cell IDs used to determine if particles crossing identified surfaces are to be banked. Particles coming from this declared cell will be banked (int) - :cellto: Cell ID used to determine if particles crossing identified + :cellto: List of cell IDs used to determine if particles crossing identified surfaces are to be banked. Particles going to this declared cell will be banked (int) survival_biasing : bool @@ -850,23 +850,24 @@ def surf_source_write(self, surf_source_write: dict): ("surface_ids", "max_particles", "max_source_files", "mcpl", "cell", "cellfrom", "cellto"), ) - if key == "surface_ids": - cv.check_type( - "surface ids for source banking", value, Iterable, Integral - ) - for surf_id in value: - cv.check_greater_than( - "surface id for source banking", surf_id, 0) + if key in ("surface_ids", "cell", "cellfrom", "cellto"): + name = { + "surface_ids": "surface id(s) for source banking", + "cell": "Cell ID(s) for source banking (from or to)", + "cellfrom": "Cell ID(s) for source banking (from only)", + "cellto": "Cell ID(s) for source banking (to only)", + }[key] + + cv.check_type(name, value, Iterable, Integral) + for x in value: + cv.check_greater_than(name, x, 0) elif key == "mcpl": cv.check_type("write to an MCPL-format file", value, bool) - elif key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): + elif key in ("max_particles", "max_source_files"): name = { "max_particles": "maximum particle banks on surfaces per process", "max_source_files": "maximun surface source files to be written", - "cell": "Cell ID for source banking (from or to)", - "cellfrom": "Cell ID for source banking (from only)", - "cellto": "Cell ID for source banking (to only)", }[key] cv.check_type(name, value, Integral) cv.check_greater_than(name, value, 0) @@ -1538,19 +1539,30 @@ def _create_surf_source_read_subelement(self, root): def _create_surf_source_write_subelement(self, root): if self._surf_source_write: element = ET.SubElement(root, "surf_source_write") + if "surface_ids" in self._surf_source_write: subelement = ET.SubElement(element, "surface_ids") subelement.text = " ".join( str(x) for x in self._surf_source_write["surface_ids"] ) - if "mcpl" in self._surf_source_write: - subelement = ET.SubElement(element, "mcpl") - subelement.text = str(self._surf_source_write["mcpl"]).lower() - for key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): + + for key in ("max_particles", "max_source_files"): if key in self._surf_source_write: subelement = ET.SubElement(element, key) subelement.text = str(self._surf_source_write[key]) + for key in ("cell", "cellfrom", "cellto"): + if key in self._surf_source_write: + subelement = ET.SubElement(element, key) + subelement.text = " ".join( + str(x) for x in self._surf_source_write[key] + ) + + if "mcpl" in self._surf_source_write: + subelement = ET.SubElement(element, "mcpl") + subelement.text = str(self._surf_source_write["mcpl"]).lower() + + def _create_collision_track_subelement(self, root): if self._collision_track: element = ET.SubElement(root, "collision_track") @@ -2048,14 +2060,14 @@ def _surf_source_write_from_xml_element(self, root): if elem is None: return for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cell', 'cellto', 'cellfrom'): - if key == 'surface_ids': + if key in ('surface_ids', 'cell', 'cellto', 'cellfrom'): value = get_elem_list(elem, key, int) else: value = get_text(elem, key) if value is not None: if key == 'mcpl': value = value in ('true', '1') - elif key in ('max_particles', 'max_source_files', 'cell', 'cellfrom', 'cellto'): + elif key in ('max_particles', 'max_source_files'): value = int(value) self.surf_source_write[key] = value diff --git a/src/finalize.cpp b/src/finalize.cpp index 4ac6d09f321..9826073de72 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -128,7 +128,6 @@ int openmc_finalize() settings::source_rejection_fraction = 0.05; settings::source_separate = false; settings::source_write = true; - settings::ssw_cell_id = C_NONE; settings::ssw_cell_type = SSWCellType::None; settings::ssw_max_particles = 0; settings::ssw_max_files = 1; diff --git a/src/particle.cpp b/src/particle.cpp index 8d0e5b3f06e..b28834feabc 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -894,83 +894,98 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) return; } + bool add_site = true; // If a cell/cellfrom/cellto parameter is defined - if (settings::ssw_cell_id != C_NONE) { - - // Retrieve cell index and storage type - int cell_idx = model::cell_map[settings::ssw_cell_id]; + if (!settings::ssw_cell_ids.empty()) { + for (auto& b : settings::ssw_cell_ids) { + add_site = true; + // Retrieve cell index and storage type + int cell_idx = model::cell_map[b]; + + if (surf.bc_) { + // Leave if cellto with vacuum boundary condition + if (surf.bc_->type() == "vacuum" && + settings::ssw_cell_type == SSWCellType::To) { + add_site = false; + continue; + } - if (surf.bc_) { - // Leave if cellto with vacuum boundary condition - if (surf.bc_->type() == "vacuum" && - settings::ssw_cell_type == SSWCellType::To) { - return; + // Leave if other boundary condition than vacuum + if (surf.bc_->type() != "vacuum") { + add_site = false; + continue; + } } - // Leave if other boundary condition than vacuum - if (surf.bc_->type() != "vacuum") { - return; + // Check if the cell of interest has been exited + bool exited = false; + for (int i = 0; i < p.n_coord_last(); ++i) { + if (p.cell_last(i) == cell_idx) { + exited = true; + } } - } - // Check if the cell of interest has been exited - bool exited = false; - for (int i = 0; i < p.n_coord_last(); ++i) { - if (p.cell_last(i) == cell_idx) { - exited = true; + // Check if the cell of interest has been entered + bool entered = false; + for (int i = 0; i < p.n_coord(); ++i) { + if (p.coord(i).cell() == cell_idx) { + entered = true; + } } - } - // Check if the cell of interest has been entered - bool entered = false; - for (int i = 0; i < p.n_coord(); ++i) { - if (p.coord(i).cell() == cell_idx) { - entered = true; - } - } + // Vacuum boundary conditions: return if cell is not exited + if (surf.bc_) { + if (surf.bc_->type() == "vacuum" && !exited) { + add_site = false; + continue; + } + } else { - // Vacuum boundary conditions: return if cell is not exited - if (surf.bc_) { - if (surf.bc_->type() == "vacuum" && !exited) { - return; - } - } else { + // If we both enter and exit the cell of interest + if (entered && exited) { + add_site = false; + continue; + } - // If we both enter and exit the cell of interest - if (entered && exited) { - return; - } + // If we did not enter nor exit the cell of interest + if (!entered && !exited) { + add_site = false; + continue; + } - // If we did not enter nor exit the cell of interest - if (!entered && !exited) { - return; - } + // If cellfrom and the cell before crossing is not the cell of + // interest + if (settings::ssw_cell_type == SSWCellType::From && !exited) { + add_site = false; + continue; + } - // If cellfrom and the cell before crossing is not the cell of - // interest - if (settings::ssw_cell_type == SSWCellType::From && !exited) { - return; + // If cellto and the cell after crossing is not the cell of interest + if (settings::ssw_cell_type == SSWCellType::To && !entered) { + add_site = false; + continue; + } } - - // If cellto and the cell after crossing is not the cell of interest - if (settings::ssw_cell_type == SSWCellType::To && !entered) { - return; + if (add_site) { + break; } } } - SourceSite site; - site.r = p.r(); - site.u = p.u(); - site.E = p.E(); - site.time = p.time(); - site.wgt = p.wgt(); - site.delayed_group = p.delayed_group(); - site.surf_id = surf.id_; - site.particle = p.type(); - site.parent_id = p.id(); - site.progeny_id = p.n_progeny(); - int64_t idx = simulation::surf_source_bank.thread_safe_append(site); + if (add_site) { + SourceSite site; + site.r = p.r(); + site.u = p.u(); + site.E = p.E(); + site.time = p.time(); + site.wgt = p.wgt(); + site.delayed_group = p.delayed_group(); + site.surf_id = surf.id_; + site.particle = p.type(); + site.parent_id = p.id(); + site.progeny_id = p.n_progeny(); + int64_t idx = simulation::surf_source_bank.thread_safe_append(site); + } } } // namespace openmc diff --git a/src/settings.cpp b/src/settings.cpp index b6a9ab95377..eb419432739 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,7 +134,7 @@ std::unordered_set source_write_surf_id; CollisionTrackConfig collision_track_config {}; int64_t ssw_max_particles; int64_t ssw_max_files; -int64_t ssw_cell_id {C_NONE}; +vector ssw_cell_ids; SSWCellType ssw_cell_type {SSWCellType::None}; TemperatureMethod temperature_method {TemperatureMethod::NEAREST}; double temperature_tolerance {10.0}; @@ -926,23 +926,36 @@ void read_settings_xml(pugi::xml_node root) } // Get cell information if (check_for_node(node_ssw, "cell")) { - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cell")); + if (!ssw_cell_ids.empty()) { + fatal_error( + "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); + } + auto temp = get_node_array(node_ssw, "cell"); + for (const auto& cell_id : temp) { + ssw_cell_ids.push_back(cell_id); + } ssw_cell_type = SSWCellType::Both; } if (check_for_node(node_ssw, "cellfrom")) { - if (ssw_cell_id != C_NONE) { + if (!ssw_cell_ids.empty()) { fatal_error( "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); } - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellfrom")); + auto temp = get_node_array(node_ssw, "cellfrom"); + for (const auto& cell_id : temp) { + ssw_cell_ids.push_back(cell_id); + } ssw_cell_type = SSWCellType::From; } if (check_for_node(node_ssw, "cellto")) { - if (ssw_cell_id != C_NONE) { + if (!ssw_cell_ids.empty()) { fatal_error( "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); } - ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellto")); + auto temp = get_node_array(node_ssw, "cellto"); + for (const auto& cell_id : temp) { + ssw_cell_ids.push_back(cell_id); + } ssw_cell_type = SSWCellType::To; } } @@ -1277,6 +1290,7 @@ void free_memory_settings() settings::statepoint_batch.clear(); settings::sourcepoint_batch.clear(); settings::source_write_surf_id.clear(); + settings::ssw_cell_ids.clear(); settings::res_scat_nuclides.clear(); } diff --git a/tests/regression_tests/surface_source_write/_visualize.py b/tests/regression_tests/surface_source_write/_visualize.py index 73340cae06f..21cb88e5f4a 100644 --- a/tests/regression_tests/surface_source_write/_visualize.py +++ b/tests/regression_tests/surface_source_write/_visualize.py @@ -10,11 +10,11 @@ # Select an option # "show": 3D visualization using matplotlib # "savefig": 2D representation using matplotlib and storing the fig under plot_2d.png - option = "show" - # option = "savefig" + #option = "show" + option = "savefig" # Select the case from its folder name - folder = "case-20" + folder = "case-24" # Reading the surface source file with h5py.File(f"{folder}/surface_source_true.h5", "r") as fp: diff --git a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat new file mode 100644 index 00000000000..801f17191b9 --- /dev/null +++ b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + fixed source + 20 + 5 + + + 0.5 0.5 1.5 + + + + + + 1.5 0.5 1.5 + + + + + 7 + 300 + 1 + + 1 + + diff --git a/tests/regression_tests/surface_source_write/case-22/results_true.dat b/tests/regression_tests/surface_source_write/case-22/results_true.dat new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/surface_source_write/case-23/inputs_true.dat b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat new file mode 100644 index 00000000000..e898fb31977 --- /dev/null +++ b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + fixed source + 20 + 5 + + + 0.5 0.5 1.5 + + + + + + 1.5 0.5 1.5 + + + + + 7 + 300 + 2 + + 1 + + diff --git a/tests/regression_tests/surface_source_write/case-23/results_true.dat b/tests/regression_tests/surface_source_write/case-23/results_true.dat new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat new file mode 100644 index 00000000000..99fb72c651b --- /dev/null +++ b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + fixed source + 20 + 5 + + + 0.5 0.5 1.5 + + + + + + 1.5 0.5 1.5 + + + + + 7 + 300 + 1 2 + + 1 + + diff --git a/tests/regression_tests/surface_source_write/case-24/results_true.dat b/tests/regression_tests/surface_source_write/case-24/results_true.dat new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py index 094df1f8b84..2f74d3fa51d 100644 --- a/tests/regression_tests/surface_source_write/test.py +++ b/tests/regression_tests/surface_source_write/test.py @@ -25,6 +25,7 @@ - model_2: cylindrical core in 1 box (vacuum BC), - model_3: cylindrical core in 1 box (reflective BC), - model_4: cylindrical core in 1 box (periodic BC). +- model_5: 2*2 array of boxes Two models including DAGMC geometries are also used, based on the mesh file 'dagmc.h5m' available from tests/regression_tests/dagmc/legacy: @@ -79,6 +80,9 @@ case-20 model_4 1 No P+R Particles crossing the declared periodic surface case-21 model_4 1 cell (root universe) P+R None +case-22 model_5 1 cellfrom (multiple) T particles crossing the declared + surface that come from multiple + cells ======== ======= ========= ========================= ===== =================================== *: BC stands for Boundary Conditions, T for Transmission, R for Reflective, and V for Vacuum. @@ -603,6 +607,56 @@ def model_4(): return model +@pytest.fixture +def model_5(): + """2*1*2 array of boxes""" + openmc.reset_auto_ids() + model = openmc.Model() + + # ============================================================================= + # Materials + # ============================================================================= + + # ============================================================================= + # Geometry + # ============================================================================= + + x1 = openmc.XPlane(x0=0, boundary_type='vacuum') + x2 = openmc.XPlane(x0=1, boundary_type='vacuum') + x3 = openmc.XPlane(x0=2, boundary_type='vacuum') + y1 = openmc.YPlane(y0=0, boundary_type='vacuum') + y2 = openmc.YPlane(y0=1, boundary_type='vacuum') + z1 = openmc.ZPlane(z0=0, boundary_type='vacuum') + z2 = openmc.ZPlane(z0=1, boundary_type='transmission') + z3 = openmc.ZPlane(z0=2, boundary_type='vacuum') + + box_11 = openmc.Cell(region = +x1 & -x2 & +y1 & -y2 & +z1 & -z2) + box_12 = openmc.Cell(region = +x2 & -x3 & +y1 & -y2 & +z1 & -z2) + box_21 = openmc.Cell(region = +x1 & -x2 & +y1 & -y2 & +z2 & -z3) + box_22 = openmc.Cell(region = +x2 & -x3 & +y1 & -y2 & +z2 & -z3) + + root = openmc.Universe(cells=(box_11, box_12, box_21, box_22)) + model.geometry = openmc.Geometry(root) + + # ============================================================================= + # Settings + # ============================================================================= + + model.settings = openmc.Settings() + model.settings.run_mode = 'fixed source' + model.settings.particles = 20 + model.settings.batches = 5 + model.settings.seed = 1 + + point_1 = openmc.stats.Point((0.5,0.5,1.5)) + point_2 = openmc.stats.Point((1.5,0.5,1.5)) + direction = openmc.stats.Monodirectional((0,0,-1)) + source_1 = openmc.IndependentSource(space=point_1, angle=direction, strength=0.8) + source_2 = openmc.IndependentSource(space=point_2, angle=direction, strength=0.2) + model.settings.source = [source_1, source_2] + + return model + def return_surface_source_data(filepath): """Read a surface source file and return a sorted array composed @@ -754,19 +808,19 @@ def _cleanup(self): ( "case-04", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, ), ( "case-05", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), - ("case-06", "model_1", {"max_particles": 300, "cell": 2}), - ("case-07", "model_1", {"max_particles": 300, "cell": 3}), - ("case-08", "model_1", {"max_particles": 300, "cellfrom": 2}), - ("case-09", "model_1", {"max_particles": 300, "cellto": 2}), - ("case-10", "model_1", {"max_particles": 300, "cellfrom": 3}), - ("case-11", "model_1", {"max_particles": 300, "cellto": 3}), + ("case-06", "model_1", {"max_particles": 300, "cell": [2]}), + ("case-07", "model_1", {"max_particles": 300, "cell": [3]}), + ("case-08", "model_1", {"max_particles": 300, "cellfrom": [2]}), + ("case-09", "model_1", {"max_particles": 300, "cellto": [2]}), + ("case-10", "model_1", {"max_particles": 300, "cellfrom": [3]}), + ("case-11", "model_1", {"max_particles": 300, "cellto": [3]}), ( "case-12", "model_2", @@ -775,17 +829,17 @@ def _cleanup(self): ( "case-13", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ( "case-14", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, ), ( "case-15", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, ), ( "case-16", @@ -795,17 +849,17 @@ def _cleanup(self): ( "case-17", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ( "case-18", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, ), ( "case-19", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, ), ( "case-20", @@ -815,7 +869,22 @@ def _cleanup(self): ( "case-21", "model_4", - {"max_particles": 300, "surface_ids": [4], "cell": 3}, + {"max_particles": 300, "surface_ids": [4], "cell": [3]}, + ), + ( + "case-22", + "model_5", + {"max_particles": 300, "surface_ids": [7], "cellto": [1]}, + ), + ( + "case-23", + "model_5", + {"max_particles": 300, "surface_ids": [7], "cellto": [2]}, + ), + ( + "case-24", + "model_5", + {"max_particles": 300, "surface_ids": [7], "cellto": [1, 2]}, ), ], ) @@ -848,7 +917,7 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process model_1.settings.surf_source_write = { "max_particles": 200, "surface_ids": [1, 2, 3], - "cellfrom": 2, + "cellfrom": [2], } harness = SurfaceSourceWriteTestHarness( "statepoint.5.h5", model=model_1, workdir="case-a01" @@ -863,13 +932,13 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process ( "case-e01", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, ), - ("case-e02", "model_1", {"max_particles": 300, "cell": 3}), + ("case-e02", "model_1", {"max_particles": 300, "cell": [3]}), ( "case-e03", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ], ) @@ -1083,21 +1152,21 @@ def model_dagmc_2(): [ ("case-d01", "model_dagmc_1", {"max_particles": 300}), ("case-d02", "model_dagmc_1", {"max_particles": 300, "surface_ids": [1]}), - ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": 2}), + ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": [2]}), ( "case-d04", "model_dagmc_1", - {"max_particles": 300, "surface_ids": [1], "cell": 2}, + {"max_particles": 300, "surface_ids": [1], "cell": [2]}, ), - ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": 2}), - ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": 2}), + ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": [2]}), + ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": [2]}), ( "case-d07", "model_dagmc_2", { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": 7, + "cell": [7], }, ), ( @@ -1106,7 +1175,7 @@ def model_dagmc_2(): { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": 8, + "cell": [8], }, ), ], diff --git a/tests/unit_tests/test_surface_source_write.py b/tests/unit_tests/test_surface_source_write.py index 6f18d32b718..05923386b55 100644 --- a/tests/unit_tests/test_surface_source_write.py +++ b/tests/unit_tests/test_surface_source_write.py @@ -25,13 +25,13 @@ def geometry(): "parameter", [ {"max_particles": 200}, - {"max_particles": 200, "cell": 1}, - {"max_particles": 200, "cellto": 1}, - {"max_particles": 200, "cellfrom": 1}, + {"max_particles": 200, "cell": [1]}, + {"max_particles": 200, "cellto": [1]}, + {"max_particles": 200, "cellfrom": [1]}, {"max_particles": 200, "surface_ids": [2]}, - {"max_particles": 200, "surface_ids": [2], "cell": 1}, - {"max_particles": 200, "surface_ids": [2], "cellto": 1}, - {"max_particles": 200, "surface_ids": [2], "cellfrom": 1}, + {"max_particles": 200, "surface_ids": [2], "cell": [1]}, + {"max_particles": 200, "surface_ids": [2], "cellto": [1]}, + {"max_particles": 200, "surface_ids": [2], "cellfrom": [1]}, {"max_particles": 200, "surface_ids": [2], "max_source_files": 1}, ], ) @@ -108,11 +108,11 @@ def test_number_surface_source_file_created(max_particles, max_source_files, @pytest.mark.parametrize( "parameter, error", [ - ({"cell": 1}, ERROR_MSG_1), - ({"max_particles": 200, "cell": 1, "cellto": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cell": 1, "cellfrom": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), - ({"max_particles": 200, "cell": 1, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), + ({"cell": [1]}, ERROR_MSG_1), + ({"max_particles": 200, "cell": [1], "cellto": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cell": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cell": [1], "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), ], ) def test_exceptions(parameter, error, run_in_tmpdir, geometry): @@ -161,8 +161,8 @@ def model(): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": 2, "surface_ids": [2]}, - {"max_particles": 200, "cellfrom": 2, "surface_ids": [2]}, + {"max_particles": 200, "cellto": [2], "surface_ids": [2]}, + {"max_particles": 200, "cellfrom": [2], "surface_ids": [2]}, ], ) def test_particle_direction(parameter, run_in_tmpdir, model): @@ -249,8 +249,8 @@ def model_dagmc(request): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": 1}, - {"max_particles": 200, "cellfrom": 1}, + {"max_particles": 200, "cellto": [1]}, + {"max_particles": 200, "cellfrom": [1]}, ], ) def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): From 47b89d70ee91c8613f0e22933498245b43ff2c53 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 15 Feb 2026 23:01:33 -0600 Subject: [PATCH 02/20] added direction parameter instead of cellto and cellfrom --- include/openmc/settings.h | 11 ++++--- src/finalize.cpp | 1 - src/particle.cpp | 15 +++++----- src/settings.cpp | 62 ++++++++++++++++++--------------------- 4 files changed, 42 insertions(+), 47 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 44df973abad..a42b6475e45 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "pugixml.hpp" @@ -177,10 +178,10 @@ extern int64_t ssw_max_particles; //!< maximum number of particles to be //!< banked on surfaces per process extern int64_t ssw_max_files; //!< maximum number of surface source files //!< to be created -extern vector ssw_cell_ids; //!< Cell ids for the surface source - //!< write setting -extern SSWCellType ssw_cell_type; //!< Type of option for the cell - //!< argument of surface source write +extern std::unordered_map + ssw_cells; //!< Cell ids and directions + //!< for the surface source write setting + extern TemperatureMethod temperature_method; //!< method for choosing temperatures extern double @@ -213,6 +214,8 @@ void read_settings_xml(pugi::xml_node root); void free_memory_settings(); +SSWCellType ssw_cell_type_from_string(std::string_view s); + } // namespace openmc #endif // OPENMC_SETTINGS_H diff --git a/src/finalize.cpp b/src/finalize.cpp index 9826073de72..6eb17868a9c 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -128,7 +128,6 @@ int openmc_finalize() settings::source_rejection_fraction = 0.05; settings::source_separate = false; settings::source_write = true; - settings::ssw_cell_type = SSWCellType::None; settings::ssw_max_particles = 0; settings::ssw_max_files = 1; settings::survival_biasing = false; diff --git a/src/particle.cpp b/src/particle.cpp index b28834feabc..f9bb95ba552 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -896,16 +896,15 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) bool add_site = true; // If a cell/cellfrom/cellto parameter is defined - if (!settings::ssw_cell_ids.empty()) { - for (auto& b : settings::ssw_cell_ids) { + if (!settings::ssw_cells.empty()) { + for (auto& cell : settings::ssw_cells) { add_site = true; // Retrieve cell index and storage type - int cell_idx = model::cell_map[b]; - + int cell_idx = model::cell_map[cell.first]; + SSWCellType direction = cell.second; if (surf.bc_) { // Leave if cellto with vacuum boundary condition - if (surf.bc_->type() == "vacuum" && - settings::ssw_cell_type == SSWCellType::To) { + if (surf.bc_->type() == "vacuum" && direction == SSWCellType::To) { add_site = false; continue; } @@ -955,13 +954,13 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) // If cellfrom and the cell before crossing is not the cell of // interest - if (settings::ssw_cell_type == SSWCellType::From && !exited) { + if (direction == SSWCellType::From && !exited) { add_site = false; continue; } // If cellto and the cell after crossing is not the cell of interest - if (settings::ssw_cell_type == SSWCellType::To && !entered) { + if (direction == SSWCellType::To && !entered) { add_site = false; continue; } diff --git a/src/settings.cpp b/src/settings.cpp index eb419432739..5deb76c0c95 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,8 +134,7 @@ std::unordered_set source_write_surf_id; CollisionTrackConfig collision_track_config {}; int64_t ssw_max_particles; int64_t ssw_max_files; -vector ssw_cell_ids; -SSWCellType ssw_cell_type {SSWCellType::None}; +std::unordered_map ssw_cells; TemperatureMethod temperature_method {TemperatureMethod::NEAREST}; double temperature_tolerance {10.0}; double temperature_default {293.6}; @@ -925,38 +924,22 @@ void read_settings_xml(pugi::xml_node root) surf_mcpl_write = get_node_value_bool(node_ssw, "mcpl"); } // Get cell information - if (check_for_node(node_ssw, "cell")) { - if (!ssw_cell_ids.empty()) { - fatal_error( - "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); - } - auto temp = get_node_array(node_ssw, "cell"); - for (const auto& cell_id : temp) { - ssw_cell_ids.push_back(cell_id); - } - ssw_cell_type = SSWCellType::Both; - } - if (check_for_node(node_ssw, "cellfrom")) { - if (!ssw_cell_ids.empty()) { - fatal_error( - "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); - } - auto temp = get_node_array(node_ssw, "cellfrom"); - for (const auto& cell_id : temp) { - ssw_cell_ids.push_back(cell_id); - } - ssw_cell_type = SSWCellType::From; - } - if (check_for_node(node_ssw, "cellto")) { - if (!ssw_cell_ids.empty()) { - fatal_error( - "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); - } - auto temp = get_node_array(node_ssw, "cellto"); - for (const auto& cell_id : temp) { - ssw_cell_ids.push_back(cell_id); + if (check_for_node(node_ssw, "cells")) { + auto ids = get_node_array(node_ssw, "cells"); + if (check_for_node(node_ssw, "directions")) { + auto directions = get_node_array(node_ssw, "directions"); + if (directions.size() != ids.size()) { + fatal_error("'directions' must have the same length as 'cells'"); + } + for (std::size_t i {0}; i < ids.size(); ++i) { + SSWCellType direction = ssw_cell_type_from_string(directions[i]); + ssw_cells.emplace(ids[i], direction); + } + } else { + for (std::size_t i {0}; i < ids.size(); ++i) { + ssw_cells.emplace(ids[i], SSWCellType::Both); + } } - ssw_cell_type = SSWCellType::To; } } @@ -1290,10 +1273,21 @@ void free_memory_settings() settings::statepoint_batch.clear(); settings::sourcepoint_batch.clear(); settings::source_write_surf_id.clear(); - settings::ssw_cell_ids.clear(); + settings::ssw_cells.clear(); settings::res_scat_nuclides.clear(); } +SSWCellType ssw_cell_type_from_string(std::string_view s) +{ + if (s == "from") + return SSWCellType::From; + if (s == "to") + return SSWCellType::To; + if (s == "both") + return SSWCellType::Both; + throw std::invalid_argument("direction must be 'from', 'to', or 'both'"); +} + //============================================================================== // C API functions //============================================================================== From 52d384d89ac8a1e2617dfa957f9e86592f5a46ab Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 15 Feb 2026 23:50:31 -0600 Subject: [PATCH 03/20] added directions parameter to python api --- openmc/settings.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index 1c67138eb20..d1646c5d306 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -280,15 +280,11 @@ class Settings: process (int) :max_source_files: Maximum number of surface source files to be created (int) :mcpl: Output in the form of an MCPL-file (bool) - :cell: List of cell IDs used to determine if particles crossing identified + :cells: List of cell IDs used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this declared cell will be banked (int) - :cellfrom: List of cell IDs used to determine if particles crossing identified - surfaces are to be banked. Particles coming from this - declared cell will be banked (int) - :cellto: List of cell IDs used to determine if particles crossing identified - surfaces are to be banked. Particles going to this declared - cell will be banked (int) + :directions: List of directions corresponding to cells. + Acceptable entries are: "from", "to", or "both" (str) survival_biasing : bool Indicate whether survival biasing is to be used tabular_legendre : dict @@ -848,20 +844,22 @@ def surf_source_write(self, surf_source_write: dict): "surface source writing key", key, ("surface_ids", "max_particles", "max_source_files", - "mcpl", "cell", "cellfrom", "cellto"), + "mcpl", "cells", "directions"), ) - if key in ("surface_ids", "cell", "cellfrom", "cellto"): + if key in ("surface_ids", "cells"): name = { "surface_ids": "surface id(s) for source banking", - "cell": "Cell ID(s) for source banking (from or to)", - "cellfrom": "Cell ID(s) for source banking (from only)", - "cellto": "Cell ID(s) for source banking (to only)", + "cells": "Cell ID(s) for source banking", }[key] - cv.check_type(name, value, Iterable, Integral) for x in value: cv.check_greater_than(name, x, 0) - + elif key == "directions": + cv.check_type("directions corresponding to cells (from, to or both)", value, Iterable, str) + for direction in value: + if (direction not in ["from", "to", "both"]): + msg = "allowed values for direction: 'from', 'to', 'both' " + raise ValueError(msg) elif key == "mcpl": cv.check_type("write to an MCPL-format file", value, bool) elif key in ("max_particles", "max_source_files"): @@ -1551,7 +1549,7 @@ def _create_surf_source_write_subelement(self, root): subelement = ET.SubElement(element, key) subelement.text = str(self._surf_source_write[key]) - for key in ("cell", "cellfrom", "cellto"): + for key in ("cells", "directions"): if key in self._surf_source_write: subelement = ET.SubElement(element, key) subelement.text = " ".join( @@ -2059,9 +2057,11 @@ def _surf_source_write_from_xml_element(self, root): elem = root.find('surf_source_write') if elem is None: return - for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cell', 'cellto', 'cellfrom'): - if key in ('surface_ids', 'cell', 'cellto', 'cellfrom'): + for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cells', 'directions'): + if key in ['surface_ids', 'cells']: value = get_elem_list(elem, key, int) + elif key == 'directions': + value = get_elem_list(elem, key, str) else: value = get_text(elem, key) if value is not None: @@ -2071,6 +2071,7 @@ def _surf_source_write_from_xml_element(self, root): value = int(value) self.surf_source_write[key] = value + def _collision_track_from_xml_element(self, root): elem = root.find('collision_track') if elem is not None: From 6a12e7988b93a81e35c007b29115576c49dc977e Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Mon, 16 Feb 2026 00:16:12 -0600 Subject: [PATCH 04/20] changed input files in surface_source_write tests cases to the new syntax --- .../case-04/inputs_true.dat | 2 +- .../case-05/inputs_true.dat | 2 +- .../case-06/inputs_true.dat | 2 +- .../case-07/inputs_true.dat | 2 +- .../case-08/inputs_true.dat | 3 +- .../case-09/inputs_true.dat | 3 +- .../case-10/inputs_true.dat | 3 +- .../case-11/inputs_true.dat | 3 +- .../case-13/inputs_true.dat | 2 +- .../case-14/inputs_true.dat | 3 +- .../case-15/inputs_true.dat | 3 +- .../case-17/inputs_true.dat | 2 +- .../case-18/inputs_true.dat | 3 +- .../case-19/inputs_true.dat | 3 +- .../case-21/inputs_true.dat | 2 +- .../case-22/inputs_true.dat | 3 +- .../case-23/inputs_true.dat | 3 +- .../case-24/inputs_true.dat | 3 +- .../case-a01/inputs_true.dat | 3 +- .../surface_source_write/test.py | 57 ++++++++++--------- 20 files changed, 60 insertions(+), 47 deletions(-) diff --git a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat b/tests/regression_tests/surface_source_write/case-04/inputs_true.dat index 46701aea7ee..42a5215fd42 100644 --- a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-04/inputs_true.dat @@ -52,7 +52,7 @@ 4 5 6 7 8 9 300 - 2 + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat b/tests/regression_tests/surface_source_write/case-05/inputs_true.dat index c420d797ce3..4bd4602b100 100644 --- a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-05/inputs_true.dat @@ -52,7 +52,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat b/tests/regression_tests/surface_source_write/case-06/inputs_true.dat index e02d5e90c12..1a9f83c526e 100644 --- a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-06/inputs_true.dat @@ -51,7 +51,7 @@ 300 - 2 + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat b/tests/regression_tests/surface_source_write/case-07/inputs_true.dat index a4588c8d083..94f9f4a3440 100644 --- a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-07/inputs_true.dat @@ -51,7 +51,7 @@ 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat b/tests/regression_tests/surface_source_write/case-08/inputs_true.dat index ecf3a6a2e50..65f252dd7eb 100644 --- a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-08/inputs_true.dat @@ -51,7 +51,8 @@ 300 - 2 + 2 + from 1 diff --git a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat b/tests/regression_tests/surface_source_write/case-09/inputs_true.dat index 5d60f9dbeb3..072e947b310 100644 --- a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-09/inputs_true.dat @@ -51,7 +51,8 @@ 300 - 2 + 2 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat b/tests/regression_tests/surface_source_write/case-10/inputs_true.dat index 1940826c23b..c5890026dab 100644 --- a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-10/inputs_true.dat @@ -51,7 +51,8 @@ 300 - 3 + 3 + from 1 diff --git a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat b/tests/regression_tests/surface_source_write/case-11/inputs_true.dat index a4feff1b1fe..e8d6aa7156c 100644 --- a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-11/inputs_true.dat @@ -51,7 +51,8 @@ 300 - 3 + 3 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat b/tests/regression_tests/surface_source_write/case-13/inputs_true.dat index 2a93fdb4d62..3552fdb816a 100644 --- a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-13/inputs_true.dat @@ -45,7 +45,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat b/tests/regression_tests/surface_source_write/case-14/inputs_true.dat index 893f8ddc153..c623497fbae 100644 --- a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-14/inputs_true.dat @@ -45,7 +45,8 @@ 4 5 6 7 8 9 300 - 3 + 3 + from 1 diff --git a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat b/tests/regression_tests/surface_source_write/case-15/inputs_true.dat index 875a2fb0bb9..f8224a0079c 100644 --- a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-15/inputs_true.dat @@ -45,7 +45,8 @@ 4 5 6 7 8 9 300 - 3 + 3 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat b/tests/regression_tests/surface_source_write/case-17/inputs_true.dat index 95d0a67124a..c732a19bd42 100644 --- a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-17/inputs_true.dat @@ -45,7 +45,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat b/tests/regression_tests/surface_source_write/case-18/inputs_true.dat index 807c72ae65a..e72ba0702f2 100644 --- a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-18/inputs_true.dat @@ -45,7 +45,8 @@ 4 5 6 7 8 9 300 - 3 + 3 + from 1 diff --git a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat b/tests/regression_tests/surface_source_write/case-19/inputs_true.dat index 42aa78a096d..5f92aa25678 100644 --- a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-19/inputs_true.dat @@ -45,7 +45,8 @@ 4 5 6 7 8 9 300 - 3 + 3 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat b/tests/regression_tests/surface_source_write/case-21/inputs_true.dat index 71f9aae6a9c..432fdb8ab80 100644 --- a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-21/inputs_true.dat @@ -45,7 +45,7 @@ 4 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat index 801f17191b9..b73455f432d 100644 --- a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat @@ -35,7 +35,8 @@ 7 300 - 1 + 1 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-23/inputs_true.dat b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat index e898fb31977..2ae36feba48 100644 --- a/tests/regression_tests/surface_source_write/case-23/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat @@ -35,7 +35,8 @@ 7 300 - 2 + 2 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat index 99fb72c651b..fc5c109864a 100644 --- a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat @@ -35,7 +35,8 @@ 7 300 - 1 2 + 1 2 + to to 1 diff --git a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat index e9840be8753..ff2d075a13a 100644 --- a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat @@ -52,7 +52,8 @@ 1 2 3 200 - 2 + 2 + from 1 diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py index 2f74d3fa51d..4a0583a00a6 100644 --- a/tests/regression_tests/surface_source_write/test.py +++ b/tests/regression_tests/surface_source_write/test.py @@ -808,19 +808,19 @@ def _cleanup(self): ( "case-04", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [2]}, ), ( "case-05", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, ), - ("case-06", "model_1", {"max_particles": 300, "cell": [2]}), - ("case-07", "model_1", {"max_particles": 300, "cell": [3]}), - ("case-08", "model_1", {"max_particles": 300, "cellfrom": [2]}), - ("case-09", "model_1", {"max_particles": 300, "cellto": [2]}), - ("case-10", "model_1", {"max_particles": 300, "cellfrom": [3]}), - ("case-11", "model_1", {"max_particles": 300, "cellto": [3]}), + ("case-06", "model_1", {"max_particles": 300, "cells": [2]}), + ("case-07", "model_1", {"max_particles": 300, "cells": [3]}), + ("case-08", "model_1", {"max_particles": 300, "cells": [2], "directions": ['from']}), + ("case-09", "model_1", {"max_particles": 300, "cells": [2], "directions": ['to']}), + ("case-10", "model_1", {"max_particles": 300, "cells": [3], "directions": ['from']}), + ("case-11", "model_1", {"max_particles": 300, "cells": [3], "directions": ['to']}), ( "case-12", "model_2", @@ -829,17 +829,17 @@ def _cleanup(self): ( "case-13", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, ), ( "case-14", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['from']}, ), ( "case-15", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['to']}, ), ( "case-16", @@ -849,17 +849,17 @@ def _cleanup(self): ( "case-17", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, ), ( "case-18", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['from']}, ), ( "case-19", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['to']}, ), ( "case-20", @@ -869,22 +869,22 @@ def _cleanup(self): ( "case-21", "model_4", - {"max_particles": 300, "surface_ids": [4], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4], "cells": [3]}, ), ( "case-22", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [1]}, + {"max_particles": 300, "surface_ids": [7], "cells": [1], "directions": ['to']}, ), ( "case-23", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [2]}, + {"max_particles": 300, "surface_ids": [7], "cells": [2], "directions": ['to']}, ), ( "case-24", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [1, 2]}, + {"max_particles": 300, "surface_ids": [7], "cells": [1, 2], "directions": ['to', 'to']}, ), ], ) @@ -917,7 +917,8 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process model_1.settings.surf_source_write = { "max_particles": 200, "surface_ids": [1, 2, 3], - "cellfrom": [2], + "cells": [2], + "directions": ['from'], } harness = SurfaceSourceWriteTestHarness( "statepoint.5.h5", model=model_1, workdir="case-a01" @@ -932,13 +933,13 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process ( "case-e01", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [2]}, ), - ("case-e02", "model_1", {"max_particles": 300, "cell": [3]}), + ("case-e02", "model_1", {"max_particles": 300, "cells": [3]}), ( "case-e03", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, ), ], ) @@ -1152,21 +1153,21 @@ def model_dagmc_2(): [ ("case-d01", "model_dagmc_1", {"max_particles": 300}), ("case-d02", "model_dagmc_1", {"max_particles": 300, "surface_ids": [1]}), - ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": [2]}), + ("case-d03", "model_dagmc_1", {"max_particles": 300, "cells": [2]}), ( "case-d04", "model_dagmc_1", - {"max_particles": 300, "surface_ids": [1], "cell": [2]}, + {"max_particles": 300, "surface_ids": [1], "cells": [2]}, ), - ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": [2]}), - ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": [2]}), + ("case-d05", "model_dagmc_1", {"max_particles": 300, "cells": [2], "directions": ['from']}), + ("case-d06", "model_dagmc_1", {"max_particles": 300, "cells": [2], "directions": ['to']}), ( "case-d07", "model_dagmc_2", { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": [7], + "cells": [7], }, ), ( @@ -1175,7 +1176,7 @@ def model_dagmc_2(): { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": [8], + "cells": [8], }, ), ], From 12260c4d5329391c8530e122fca0e71adb188999 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Mon, 16 Feb 2026 00:53:12 -0600 Subject: [PATCH 05/20] updated test_surface_source_write.py --- tests/unit_tests/test_surface_source_write.py | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/tests/unit_tests/test_surface_source_write.py b/tests/unit_tests/test_surface_source_write.py index 05923386b55..0f66a55a6a1 100644 --- a/tests/unit_tests/test_surface_source_write.py +++ b/tests/unit_tests/test_surface_source_write.py @@ -25,13 +25,13 @@ def geometry(): "parameter", [ {"max_particles": 200}, - {"max_particles": 200, "cell": [1]}, - {"max_particles": 200, "cellto": [1]}, - {"max_particles": 200, "cellfrom": [1]}, + {"max_particles": 200, "cells": [1]}, + {"max_particles": 200, "cells": [1], "directions": ['to']}, + {"max_particles": 200, "cells": [1], "directions": ['from']}, {"max_particles": 200, "surface_ids": [2]}, - {"max_particles": 200, "surface_ids": [2], "cell": [1]}, - {"max_particles": 200, "surface_ids": [2], "cellto": [1]}, - {"max_particles": 200, "surface_ids": [2], "cellfrom": [1]}, + {"max_particles": 200, "surface_ids": [2], "cells": [1]}, + {"max_particles": 200, "surface_ids": [2], "cells": [1], "directions": ['to']}, + {"max_particles": 200, "surface_ids": [2], "cells": [1], "directions": ['from']}, {"max_particles": 200, "surface_ids": [2], "max_source_files": 1}, ], ) @@ -102,17 +102,11 @@ def test_number_surface_source_file_created(max_particles, max_source_files, "using the 'max_particles' parameter to store surface " "source points." ) -ERROR_MSG_2 = "'cell', 'cellfrom' and 'cellto' cannot be used at the same time." - @pytest.mark.parametrize( "parameter, error", [ - ({"cell": [1]}, ERROR_MSG_1), - ({"max_particles": 200, "cell": [1], "cellto": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cell": [1], "cellfrom": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cell": [1], "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"cells": [1]}, ERROR_MSG_1), ], ) def test_exceptions(parameter, error, run_in_tmpdir, geometry): @@ -161,8 +155,8 @@ def model(): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": [2], "surface_ids": [2]}, - {"max_particles": 200, "cellfrom": [2], "surface_ids": [2]}, + {"max_particles": 200, "cells": [2], "surface_ids": [2], "directions": ['to']}, + {"max_particles": 200, "cells": [2], "surface_ids": [2], "directions": ['from']}, ], ) def test_particle_direction(parameter, run_in_tmpdir, model): @@ -185,10 +179,11 @@ def test_particle_direction(parameter, run_in_tmpdir, model): # depending on cellfrom or cellto. In this case, it is equivalent # to just compare the z component of the direction of the particle. for point in source: - if "cellto" in parameter.keys(): - assert point["u"]["z"] > 0.0 - elif "cellfrom" in parameter.keys(): - assert point["u"]["z"] < 0.0 + if "directions" in parameter.keys(): + if parameter["directions"] == "to": + assert point["u"]["z"] > 0.0 + elif parameter["directions"] == "from": + assert point["u"]["z"] < 0.0 else: assert False @@ -249,8 +244,8 @@ def model_dagmc(request): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": [1]}, - {"max_particles": 200, "cellfrom": [1]}, + {"max_particles": 200, "cells": [1], "directions": ["to"]}, + {"max_particles": 200, "cells": [1], "directions": ["from"]}, ], ) def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): @@ -276,26 +271,29 @@ def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): if np.allclose(abs(z), h): # If the point is also on the cylindrical surface if np.allclose(np.sqrt(x**2 + y**2), r): - if "cellfrom" in parameter.keys(): - assert (uz * z > 0) or (ux * x + uy * y > 0) - elif "cellto" in parameter.keys(): - assert (uz * z < 0) or (ux * x + uy * y < 0) + if "directions" in parameter.keys(): + if parameter["directions"] == "from": + assert (uz * z > 0) or (ux * x + uy * y > 0) + elif parameter["directions"] == "to": + assert (uz * z < 0) or (ux * x + uy * y < 0) else: assert False # If the point is not on the cylindrical surface else: - if "cellfrom" in parameter.keys(): - assert uz * z > 0 - elif "cellto" in parameter.keys(): - assert uz * z < 0 + if "directions" in parameter.keys(): + if parameter["directions"] == "from": + assert uz * z > 0 + elif parameter["directions"] == "to": + assert uz * z < 0 else: assert False # If the point is not on the upper or lower circle, # meaning it is on the cylindrical surface else: - if "cellfrom" in parameter.keys(): - assert ux * x + uy * y > 0 - elif "cellto" in parameter.keys(): - assert ux * x + uy * y < 0 + if "directions" in parameter.keys(): + if parameter["directions"] == "from": + assert ux * x + uy * y > 0 + if parameter["directions"] == "to": + assert ux * x + uy * y < 0 else: assert False From 634a23d10c1be2657750dc224b1aeef0949bedfd Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Thu, 19 Feb 2026 12:59:42 -0600 Subject: [PATCH 06/20] reverted tests back to original state to allow testing with older syntax --- .../case-04/inputs_true.dat | 2 +- .../case-05/inputs_true.dat | 2 +- .../case-06/inputs_true.dat | 2 +- .../case-07/inputs_true.dat | 2 +- .../case-08/inputs_true.dat | 3 +- .../case-09/inputs_true.dat | 3 +- .../case-10/inputs_true.dat | 3 +- .../case-11/inputs_true.dat | 3 +- .../case-13/inputs_true.dat | 2 +- .../case-14/inputs_true.dat | 3 +- .../case-15/inputs_true.dat | 3 +- .../case-17/inputs_true.dat | 2 +- .../case-18/inputs_true.dat | 3 +- .../case-19/inputs_true.dat | 3 +- .../case-21/inputs_true.dat | 2 +- .../case-22/inputs_true.dat | 3 +- .../case-23/inputs_true.dat | 3 +- .../case-24/inputs_true.dat | 3 +- .../case-a01/inputs_true.dat | 3 +- .../surface_source_write/test.py | 57 ++++++++--------- tests/unit_tests/test_surface_source_write.py | 64 ++++++++++--------- 21 files changed, 80 insertions(+), 91 deletions(-) diff --git a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat b/tests/regression_tests/surface_source_write/case-04/inputs_true.dat index 42a5215fd42..46701aea7ee 100644 --- a/tests/regression_tests/surface_source_write/case-04/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-04/inputs_true.dat @@ -52,7 +52,7 @@ 4 5 6 7 8 9 300 - 2 + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat b/tests/regression_tests/surface_source_write/case-05/inputs_true.dat index 4bd4602b100..c420d797ce3 100644 --- a/tests/regression_tests/surface_source_write/case-05/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-05/inputs_true.dat @@ -52,7 +52,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat b/tests/regression_tests/surface_source_write/case-06/inputs_true.dat index 1a9f83c526e..e02d5e90c12 100644 --- a/tests/regression_tests/surface_source_write/case-06/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-06/inputs_true.dat @@ -51,7 +51,7 @@ 300 - 2 + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat b/tests/regression_tests/surface_source_write/case-07/inputs_true.dat index 94f9f4a3440..a4588c8d083 100644 --- a/tests/regression_tests/surface_source_write/case-07/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-07/inputs_true.dat @@ -51,7 +51,7 @@ 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat b/tests/regression_tests/surface_source_write/case-08/inputs_true.dat index 65f252dd7eb..ecf3a6a2e50 100644 --- a/tests/regression_tests/surface_source_write/case-08/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-08/inputs_true.dat @@ -51,8 +51,7 @@ 300 - 2 - from + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat b/tests/regression_tests/surface_source_write/case-09/inputs_true.dat index 072e947b310..5d60f9dbeb3 100644 --- a/tests/regression_tests/surface_source_write/case-09/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-09/inputs_true.dat @@ -51,8 +51,7 @@ 300 - 2 - to + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat b/tests/regression_tests/surface_source_write/case-10/inputs_true.dat index c5890026dab..1940826c23b 100644 --- a/tests/regression_tests/surface_source_write/case-10/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-10/inputs_true.dat @@ -51,8 +51,7 @@ 300 - 3 - from + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat b/tests/regression_tests/surface_source_write/case-11/inputs_true.dat index e8d6aa7156c..a4feff1b1fe 100644 --- a/tests/regression_tests/surface_source_write/case-11/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-11/inputs_true.dat @@ -51,8 +51,7 @@ 300 - 3 - to + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat b/tests/regression_tests/surface_source_write/case-13/inputs_true.dat index 3552fdb816a..2a93fdb4d62 100644 --- a/tests/regression_tests/surface_source_write/case-13/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-13/inputs_true.dat @@ -45,7 +45,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat b/tests/regression_tests/surface_source_write/case-14/inputs_true.dat index c623497fbae..893f8ddc153 100644 --- a/tests/regression_tests/surface_source_write/case-14/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-14/inputs_true.dat @@ -45,8 +45,7 @@ 4 5 6 7 8 9 300 - 3 - from + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat b/tests/regression_tests/surface_source_write/case-15/inputs_true.dat index f8224a0079c..875a2fb0bb9 100644 --- a/tests/regression_tests/surface_source_write/case-15/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-15/inputs_true.dat @@ -45,8 +45,7 @@ 4 5 6 7 8 9 300 - 3 - to + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat b/tests/regression_tests/surface_source_write/case-17/inputs_true.dat index c732a19bd42..95d0a67124a 100644 --- a/tests/regression_tests/surface_source_write/case-17/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-17/inputs_true.dat @@ -45,7 +45,7 @@ 4 5 6 7 8 9 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat b/tests/regression_tests/surface_source_write/case-18/inputs_true.dat index e72ba0702f2..807c72ae65a 100644 --- a/tests/regression_tests/surface_source_write/case-18/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-18/inputs_true.dat @@ -45,8 +45,7 @@ 4 5 6 7 8 9 300 - 3 - from + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat b/tests/regression_tests/surface_source_write/case-19/inputs_true.dat index 5f92aa25678..42aa78a096d 100644 --- a/tests/regression_tests/surface_source_write/case-19/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-19/inputs_true.dat @@ -45,8 +45,7 @@ 4 5 6 7 8 9 300 - 3 - to + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat b/tests/regression_tests/surface_source_write/case-21/inputs_true.dat index 432fdb8ab80..71f9aae6a9c 100644 --- a/tests/regression_tests/surface_source_write/case-21/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-21/inputs_true.dat @@ -45,7 +45,7 @@ 4 300 - 3 + 3 1 diff --git a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat index b73455f432d..801f17191b9 100644 --- a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat @@ -35,8 +35,7 @@ 7 300 - 1 - to + 1 1 diff --git a/tests/regression_tests/surface_source_write/case-23/inputs_true.dat b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat index 2ae36feba48..e898fb31977 100644 --- a/tests/regression_tests/surface_source_write/case-23/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-23/inputs_true.dat @@ -35,8 +35,7 @@ 7 300 - 2 - to + 2 1 diff --git a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat index fc5c109864a..99fb72c651b 100644 --- a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat @@ -35,8 +35,7 @@ 7 300 - 1 2 - to to + 1 2 1 diff --git a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat b/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat index ff2d075a13a..e9840be8753 100644 --- a/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-a01/inputs_true.dat @@ -52,8 +52,7 @@ 1 2 3 200 - 2 - from + 2 1 diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py index 4a0583a00a6..2f74d3fa51d 100644 --- a/tests/regression_tests/surface_source_write/test.py +++ b/tests/regression_tests/surface_source_write/test.py @@ -808,19 +808,19 @@ def _cleanup(self): ( "case-04", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, ), ( "case-05", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), - ("case-06", "model_1", {"max_particles": 300, "cells": [2]}), - ("case-07", "model_1", {"max_particles": 300, "cells": [3]}), - ("case-08", "model_1", {"max_particles": 300, "cells": [2], "directions": ['from']}), - ("case-09", "model_1", {"max_particles": 300, "cells": [2], "directions": ['to']}), - ("case-10", "model_1", {"max_particles": 300, "cells": [3], "directions": ['from']}), - ("case-11", "model_1", {"max_particles": 300, "cells": [3], "directions": ['to']}), + ("case-06", "model_1", {"max_particles": 300, "cell": [2]}), + ("case-07", "model_1", {"max_particles": 300, "cell": [3]}), + ("case-08", "model_1", {"max_particles": 300, "cellfrom": [2]}), + ("case-09", "model_1", {"max_particles": 300, "cellto": [2]}), + ("case-10", "model_1", {"max_particles": 300, "cellfrom": [3]}), + ("case-11", "model_1", {"max_particles": 300, "cellto": [3]}), ( "case-12", "model_2", @@ -829,17 +829,17 @@ def _cleanup(self): ( "case-13", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ( "case-14", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['from']}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, ), ( "case-15", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['to']}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, ), ( "case-16", @@ -849,17 +849,17 @@ def _cleanup(self): ( "case-17", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ( "case-18", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['from']}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, ), ( "case-19", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3], "directions": ['to']}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, ), ( "case-20", @@ -869,22 +869,22 @@ def _cleanup(self): ( "case-21", "model_4", - {"max_particles": 300, "surface_ids": [4], "cells": [3]}, + {"max_particles": 300, "surface_ids": [4], "cell": [3]}, ), ( "case-22", "model_5", - {"max_particles": 300, "surface_ids": [7], "cells": [1], "directions": ['to']}, + {"max_particles": 300, "surface_ids": [7], "cellto": [1]}, ), ( "case-23", "model_5", - {"max_particles": 300, "surface_ids": [7], "cells": [2], "directions": ['to']}, + {"max_particles": 300, "surface_ids": [7], "cellto": [2]}, ), ( "case-24", "model_5", - {"max_particles": 300, "surface_ids": [7], "cells": [1, 2], "directions": ['to', 'to']}, + {"max_particles": 300, "surface_ids": [7], "cellto": [1, 2]}, ), ], ) @@ -917,8 +917,7 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process model_1.settings.surf_source_write = { "max_particles": 200, "surface_ids": [1, 2, 3], - "cells": [2], - "directions": ['from'], + "cellfrom": [2], } harness = SurfaceSourceWriteTestHarness( "statepoint.5.h5", model=model_1, workdir="case-a01" @@ -933,13 +932,13 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process ( "case-e01", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, ), - ("case-e02", "model_1", {"max_particles": 300, "cells": [3]}), + ("case-e02", "model_1", {"max_particles": 300, "cell": [3]}), ( "case-e03", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cells": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, ), ], ) @@ -1153,21 +1152,21 @@ def model_dagmc_2(): [ ("case-d01", "model_dagmc_1", {"max_particles": 300}), ("case-d02", "model_dagmc_1", {"max_particles": 300, "surface_ids": [1]}), - ("case-d03", "model_dagmc_1", {"max_particles": 300, "cells": [2]}), + ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": [2]}), ( "case-d04", "model_dagmc_1", - {"max_particles": 300, "surface_ids": [1], "cells": [2]}, + {"max_particles": 300, "surface_ids": [1], "cell": [2]}, ), - ("case-d05", "model_dagmc_1", {"max_particles": 300, "cells": [2], "directions": ['from']}), - ("case-d06", "model_dagmc_1", {"max_particles": 300, "cells": [2], "directions": ['to']}), + ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": [2]}), + ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": [2]}), ( "case-d07", "model_dagmc_2", { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cells": [7], + "cell": [7], }, ), ( @@ -1176,7 +1175,7 @@ def model_dagmc_2(): { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cells": [8], + "cell": [8], }, ), ], diff --git a/tests/unit_tests/test_surface_source_write.py b/tests/unit_tests/test_surface_source_write.py index 0f66a55a6a1..05923386b55 100644 --- a/tests/unit_tests/test_surface_source_write.py +++ b/tests/unit_tests/test_surface_source_write.py @@ -25,13 +25,13 @@ def geometry(): "parameter", [ {"max_particles": 200}, - {"max_particles": 200, "cells": [1]}, - {"max_particles": 200, "cells": [1], "directions": ['to']}, - {"max_particles": 200, "cells": [1], "directions": ['from']}, + {"max_particles": 200, "cell": [1]}, + {"max_particles": 200, "cellto": [1]}, + {"max_particles": 200, "cellfrom": [1]}, {"max_particles": 200, "surface_ids": [2]}, - {"max_particles": 200, "surface_ids": [2], "cells": [1]}, - {"max_particles": 200, "surface_ids": [2], "cells": [1], "directions": ['to']}, - {"max_particles": 200, "surface_ids": [2], "cells": [1], "directions": ['from']}, + {"max_particles": 200, "surface_ids": [2], "cell": [1]}, + {"max_particles": 200, "surface_ids": [2], "cellto": [1]}, + {"max_particles": 200, "surface_ids": [2], "cellfrom": [1]}, {"max_particles": 200, "surface_ids": [2], "max_source_files": 1}, ], ) @@ -102,11 +102,17 @@ def test_number_surface_source_file_created(max_particles, max_source_files, "using the 'max_particles' parameter to store surface " "source points." ) +ERROR_MSG_2 = "'cell', 'cellfrom' and 'cellto' cannot be used at the same time." + @pytest.mark.parametrize( "parameter, error", [ - ({"cells": [1]}, ERROR_MSG_1), + ({"cell": [1]}, ERROR_MSG_1), + ({"max_particles": 200, "cell": [1], "cellto": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cell": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"max_particles": 200, "cell": [1], "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), ], ) def test_exceptions(parameter, error, run_in_tmpdir, geometry): @@ -155,8 +161,8 @@ def model(): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cells": [2], "surface_ids": [2], "directions": ['to']}, - {"max_particles": 200, "cells": [2], "surface_ids": [2], "directions": ['from']}, + {"max_particles": 200, "cellto": [2], "surface_ids": [2]}, + {"max_particles": 200, "cellfrom": [2], "surface_ids": [2]}, ], ) def test_particle_direction(parameter, run_in_tmpdir, model): @@ -179,11 +185,10 @@ def test_particle_direction(parameter, run_in_tmpdir, model): # depending on cellfrom or cellto. In this case, it is equivalent # to just compare the z component of the direction of the particle. for point in source: - if "directions" in parameter.keys(): - if parameter["directions"] == "to": - assert point["u"]["z"] > 0.0 - elif parameter["directions"] == "from": - assert point["u"]["z"] < 0.0 + if "cellto" in parameter.keys(): + assert point["u"]["z"] > 0.0 + elif "cellfrom" in parameter.keys(): + assert point["u"]["z"] < 0.0 else: assert False @@ -244,8 +249,8 @@ def model_dagmc(request): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cells": [1], "directions": ["to"]}, - {"max_particles": 200, "cells": [1], "directions": ["from"]}, + {"max_particles": 200, "cellto": [1]}, + {"max_particles": 200, "cellfrom": [1]}, ], ) def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): @@ -271,29 +276,26 @@ def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): if np.allclose(abs(z), h): # If the point is also on the cylindrical surface if np.allclose(np.sqrt(x**2 + y**2), r): - if "directions" in parameter.keys(): - if parameter["directions"] == "from": - assert (uz * z > 0) or (ux * x + uy * y > 0) - elif parameter["directions"] == "to": - assert (uz * z < 0) or (ux * x + uy * y < 0) + if "cellfrom" in parameter.keys(): + assert (uz * z > 0) or (ux * x + uy * y > 0) + elif "cellto" in parameter.keys(): + assert (uz * z < 0) or (ux * x + uy * y < 0) else: assert False # If the point is not on the cylindrical surface else: - if "directions" in parameter.keys(): - if parameter["directions"] == "from": - assert uz * z > 0 - elif parameter["directions"] == "to": - assert uz * z < 0 + if "cellfrom" in parameter.keys(): + assert uz * z > 0 + elif "cellto" in parameter.keys(): + assert uz * z < 0 else: assert False # If the point is not on the upper or lower circle, # meaning it is on the cylindrical surface else: - if "directions" in parameter.keys(): - if parameter["directions"] == "from": - assert ux * x + uy * y > 0 - if parameter["directions"] == "to": - assert ux * x + uy * y < 0 + if "cellfrom" in parameter.keys(): + assert ux * x + uy * y > 0 + elif "cellto" in parameter.keys(): + assert ux * x + uy * y < 0 else: assert False From 9e8776c646f4b9f21e56f57c3479e685f93975c3 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Thu, 19 Feb 2026 15:09:15 -0600 Subject: [PATCH 07/20] allowed the old syntax --- include/openmc/settings.h | 2 + openmc/settings.py | 13 +++--- src/particle.cpp | 11 +++-- src/settings.cpp | 41 +++++++++++++++++- .../case-24/inputs_true.dat | 3 +- .../surface_source_write/test.py | 42 +++++++++---------- tests/unit_tests/test_surface_source_write.py | 30 ++++++------- 7 files changed, 96 insertions(+), 46 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index a42b6475e45..c89a218d636 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -178,6 +178,8 @@ extern int64_t ssw_max_particles; //!< maximum number of particles to be //!< banked on surfaces per process extern int64_t ssw_max_files; //!< maximum number of surface source files //!< to be created +extern int64_t ssw_cell_id; //!< Cell id for the surface source + extern std::unordered_map ssw_cells; //!< Cell ids and directions //!< for the surface source write setting diff --git a/openmc/settings.py b/openmc/settings.py index d1646c5d306..d9a4cd081c6 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -844,7 +844,7 @@ def surf_source_write(self, surf_source_write: dict): "surface source writing key", key, ("surface_ids", "max_particles", "max_source_files", - "mcpl", "cells", "directions"), + "mcpl", "cells", "directions", "cell", "cellfrom", "cellto"), ) if key in ("surface_ids", "cells"): name = { @@ -862,10 +862,13 @@ def surf_source_write(self, surf_source_write: dict): raise ValueError(msg) elif key == "mcpl": cv.check_type("write to an MCPL-format file", value, bool) - elif key in ("max_particles", "max_source_files"): + elif key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): name = { "max_particles": "maximum particle banks on surfaces per process", "max_source_files": "maximun surface source files to be written", + "cell": "Cell ID for source banking (from or to)", + "cellfrom": "Cell ID for source banking (from only)", + "cellto": "Cell ID for source banking (to only)", }[key] cv.check_type(name, value, Integral) cv.check_greater_than(name, value, 0) @@ -1544,7 +1547,7 @@ def _create_surf_source_write_subelement(self, root): str(x) for x in self._surf_source_write["surface_ids"] ) - for key in ("max_particles", "max_source_files"): + for key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): if key in self._surf_source_write: subelement = ET.SubElement(element, key) subelement.text = str(self._surf_source_write[key]) @@ -2057,7 +2060,7 @@ def _surf_source_write_from_xml_element(self, root): elem = root.find('surf_source_write') if elem is None: return - for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cells', 'directions'): + for key in ('surface_ids', 'max_particles', 'max_source_files', 'mcpl', 'cells', 'directions', 'cell', 'cellto', 'cellfrom'): if key in ['surface_ids', 'cells']: value = get_elem_list(elem, key, int) elif key == 'directions': @@ -2067,7 +2070,7 @@ def _surf_source_write_from_xml_element(self, root): if value is not None: if key == 'mcpl': value = value in ('true', '1') - elif key in ('max_particles', 'max_source_files'): + elif key in ('max_particles', 'max_source_files', 'cell', 'cellfrom', 'cellto'): value = int(value) self.surf_source_write[key] = value diff --git a/src/particle.cpp b/src/particle.cpp index f9bb95ba552..07e9f77f52a 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -894,11 +894,14 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) return; } - bool add_site = true; - // If a cell/cellfrom/cellto parameter is defined + bool add_site = + true; // this insures that a site is added if 'cells' is not defined + + // If 'cells' is defined if (!settings::ssw_cells.empty()) { for (auto& cell : settings::ssw_cells) { - add_site = true; + add_site = true; // we assume the cell-direction pair is valid until it + // gets rejected // Retrieve cell index and storage type int cell_idx = model::cell_map[cell.first]; SSWCellType direction = cell.second; @@ -965,6 +968,8 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) continue; } } + // if any cell-direction pair survived all the checks we terminate the + // loop if (add_site) { break; } diff --git a/src/settings.cpp b/src/settings.cpp index 5deb76c0c95..d7fcd108b95 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,6 +134,7 @@ std::unordered_set source_write_surf_id; CollisionTrackConfig collision_track_config {}; int64_t ssw_max_particles; int64_t ssw_max_files; +int64_t ssw_cell_id {C_NONE}; std::unordered_map ssw_cells; TemperatureMethod temperature_method {TemperatureMethod::NEAREST}; double temperature_tolerance {10.0}; @@ -925,6 +926,13 @@ void read_settings_xml(pugi::xml_node root) } // Get cell information if (check_for_node(node_ssw, "cells")) { + // raise an error if the new syntax is mixed with the old syntax + if (check_for_node(node_ssw, "cell") || + check_for_node(node_ssw, "cellfrom") || + check_for_node(node_ssw, "cellto")) { + fatal_error("'cells' cannot be used at the same time with 'cell', " + "'cellfrom' or 'cellto'."); + } auto ids = get_node_array(node_ssw, "cells"); if (check_for_node(node_ssw, "directions")) { auto directions = get_node_array(node_ssw, "directions"); @@ -935,11 +943,42 @@ void read_settings_xml(pugi::xml_node root) SSWCellType direction = ssw_cell_type_from_string(directions[i]); ssw_cells.emplace(ids[i], direction); } - } else { + } else { // default behavior if 'directions' is not defined for (std::size_t i {0}; i < ids.size(); ++i) { ssw_cells.emplace(ids[i], SSWCellType::Both); } } + } else { + if (check_for_node(node_ssw, "directions")) { + fatal_error("'directions' cannot be used if 'cells' is not defined."); + } + // old syntax will be deprecated in the future + if (check_for_node(node_ssw, "cell")) { + warning("'cell' is deprecated and will be removed in the future. Use " + "'cells' and 'directions' instead."); + ssw_cell_id = std::stoll(get_node_value(node_ssw, "cell")); + ssw_cells.emplace(ssw_cell_id, SSWCellType::Both); + } + if (check_for_node(node_ssw, "cellfrom")) { + warning("'cellfrom' is deprecated and will be removed in the future. " + "Use 'cells' and 'directions' instead."); + if (ssw_cell_id != C_NONE) { + fatal_error( + "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); + } + ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellfrom")); + ssw_cells.emplace(ssw_cell_id, SSWCellType::From); + } + if (check_for_node(node_ssw, "cellto")) { + warning("'cellto' is deprecated and will be removed in the future. Use " + "'cells' and 'directions' instead."); + if (ssw_cell_id != C_NONE) { + fatal_error( + "'cell', 'cellfrom' and 'cellto' cannot be used at the same time."); + } + ssw_cell_id = std::stoll(get_node_value(node_ssw, "cellto")); + ssw_cells.emplace(ssw_cell_id, SSWCellType::To); + } } } diff --git a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat index 99fb72c651b..fc5c109864a 100644 --- a/tests/regression_tests/surface_source_write/case-24/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-24/inputs_true.dat @@ -35,7 +35,8 @@ 7 300 - 1 2 + 1 2 + to to 1 diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py index 2f74d3fa51d..933a708bd31 100644 --- a/tests/regression_tests/surface_source_write/test.py +++ b/tests/regression_tests/surface_source_write/test.py @@ -808,19 +808,19 @@ def _cleanup(self): ( "case-04", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, ), ( "case-05", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, ), - ("case-06", "model_1", {"max_particles": 300, "cell": [2]}), - ("case-07", "model_1", {"max_particles": 300, "cell": [3]}), - ("case-08", "model_1", {"max_particles": 300, "cellfrom": [2]}), - ("case-09", "model_1", {"max_particles": 300, "cellto": [2]}), - ("case-10", "model_1", {"max_particles": 300, "cellfrom": [3]}), - ("case-11", "model_1", {"max_particles": 300, "cellto": [3]}), + ("case-06", "model_1", {"max_particles": 300, "cell": 2}), + ("case-07", "model_1", {"max_particles": 300, "cell": 3}), + ("case-08", "model_1", {"max_particles": 300, "cellfrom": 2}), + ("case-09", "model_1", {"max_particles": 300, "cellto": 2}), + ("case-10", "model_1", {"max_particles": 300, "cellfrom": 3}), + ("case-11", "model_1", {"max_particles": 300, "cellto": 3}), ( "case-12", "model_2", @@ -829,17 +829,17 @@ def _cleanup(self): ( "case-13", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, ), ( "case-14", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, ), ( "case-15", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, ), ( "case-16", @@ -849,17 +849,17 @@ def _cleanup(self): ( "case-17", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, ), ( "case-18", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellfrom": 3}, ), ( "case-19", "model_3", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cellto": 3}, ), ( "case-20", @@ -869,22 +869,22 @@ def _cleanup(self): ( "case-21", "model_4", - {"max_particles": 300, "surface_ids": [4], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4], "cell": 3}, ), ( "case-22", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [1]}, + {"max_particles": 300, "surface_ids": [7], "cellto": 1}, ), ( "case-23", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [2]}, + {"max_particles": 300, "surface_ids": [7], "cellto": 2}, ), ( "case-24", "model_5", - {"max_particles": 300, "surface_ids": [7], "cellto": [1, 2]}, + {"max_particles": 300, "surface_ids": [7], "cells": [1, 2], "directions": ["to", "to"]}, ), ], ) @@ -917,7 +917,7 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process model_1.settings.surf_source_write = { "max_particles": 200, "surface_ids": [1, 2, 3], - "cellfrom": [2], + "cellfrom": 2, } harness = SurfaceSourceWriteTestHarness( "statepoint.5.h5", model=model_1, workdir="case-a01" @@ -932,13 +932,13 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process ( "case-e01", "model_1", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [2]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, ), ("case-e02", "model_1", {"max_particles": 300, "cell": [3]}), ( "case-e03", "model_2", - {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": [3]}, + {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 3}, ), ], ) diff --git a/tests/unit_tests/test_surface_source_write.py b/tests/unit_tests/test_surface_source_write.py index 05923386b55..6f18d32b718 100644 --- a/tests/unit_tests/test_surface_source_write.py +++ b/tests/unit_tests/test_surface_source_write.py @@ -25,13 +25,13 @@ def geometry(): "parameter", [ {"max_particles": 200}, - {"max_particles": 200, "cell": [1]}, - {"max_particles": 200, "cellto": [1]}, - {"max_particles": 200, "cellfrom": [1]}, + {"max_particles": 200, "cell": 1}, + {"max_particles": 200, "cellto": 1}, + {"max_particles": 200, "cellfrom": 1}, {"max_particles": 200, "surface_ids": [2]}, - {"max_particles": 200, "surface_ids": [2], "cell": [1]}, - {"max_particles": 200, "surface_ids": [2], "cellto": [1]}, - {"max_particles": 200, "surface_ids": [2], "cellfrom": [1]}, + {"max_particles": 200, "surface_ids": [2], "cell": 1}, + {"max_particles": 200, "surface_ids": [2], "cellto": 1}, + {"max_particles": 200, "surface_ids": [2], "cellfrom": 1}, {"max_particles": 200, "surface_ids": [2], "max_source_files": 1}, ], ) @@ -108,11 +108,11 @@ def test_number_surface_source_file_created(max_particles, max_source_files, @pytest.mark.parametrize( "parameter, error", [ - ({"cell": [1]}, ERROR_MSG_1), - ({"max_particles": 200, "cell": [1], "cellto": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cell": [1], "cellfrom": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), - ({"max_particles": 200, "cell": [1], "cellto": [1], "cellfrom": [1]}, ERROR_MSG_2), + ({"cell": 1}, ERROR_MSG_1), + ({"max_particles": 200, "cell": 1, "cellto": 1}, ERROR_MSG_2), + ({"max_particles": 200, "cell": 1, "cellfrom": 1}, ERROR_MSG_2), + ({"max_particles": 200, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), + ({"max_particles": 200, "cell": 1, "cellto": 1, "cellfrom": 1}, ERROR_MSG_2), ], ) def test_exceptions(parameter, error, run_in_tmpdir, geometry): @@ -161,8 +161,8 @@ def model(): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": [2], "surface_ids": [2]}, - {"max_particles": 200, "cellfrom": [2], "surface_ids": [2]}, + {"max_particles": 200, "cellto": 2, "surface_ids": [2]}, + {"max_particles": 200, "cellfrom": 2, "surface_ids": [2]}, ], ) def test_particle_direction(parameter, run_in_tmpdir, model): @@ -249,8 +249,8 @@ def model_dagmc(request): @pytest.mark.parametrize( "parameter", [ - {"max_particles": 200, "cellto": [1]}, - {"max_particles": 200, "cellfrom": [1]}, + {"max_particles": 200, "cellto": 1}, + {"max_particles": 200, "cellfrom": 1}, ], ) def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc): From 571a63f716bc81d3dec55eca0dc7850d3297615f Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Thu, 19 Feb 2026 15:15:25 -0600 Subject: [PATCH 08/20] added ssw_cell_id back to finalize --- src/finalize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/finalize.cpp b/src/finalize.cpp index 6eb17868a9c..934e815cdd7 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -128,6 +128,7 @@ int openmc_finalize() settings::source_rejection_fraction = 0.05; settings::source_separate = false; settings::source_write = true; + settings::ssw_cell_id = C_NONE; settings::ssw_max_particles = 0; settings::ssw_max_files = 1; settings::survival_biasing = false; From 086b36e5d3754d73114a86c02d7a6b91d87bb901 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Thu, 19 Feb 2026 16:08:29 -0600 Subject: [PATCH 09/20] changed the condition of adding a surface to bank from particle.cpp to surface.cpp --- src/particle.cpp | 3 +-- src/surface.cpp | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 07e9f77f52a..c648b48f080 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -889,8 +889,7 @@ void Particle::update_neutron_xs( //============================================================================== void add_surf_source_to_bank(Particle& p, const Surface& surf) { - if (simulation::current_batch <= settings::n_inactive || - simulation::surf_source_bank.full()) { + if (simulation::current_batch <= settings::n_inactive) { return; } diff --git a/src/surface.cpp b/src/surface.cpp index 81b756deae7..25ae5091efe 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -63,8 +63,9 @@ Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { id_ = std::stoi(get_node_value(surf_node, "id")); - if (contains(settings::source_write_surf_id, id_) || - settings::source_write_surf_id.empty()) { + if (settings::surf_source_write && + (contains(settings::source_write_surf_id, id_) || + settings::source_write_surf_id.empty())) { surf_source_ = true; } } else { From eec7d757a5253e626cadad460a12b72ace60c46f Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Fri, 20 Feb 2026 06:51:11 -0600 Subject: [PATCH 10/20] simplified the add site loop logic --- src/particle.cpp | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index c648b48f080..35b70a995bc 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -893,27 +893,24 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) return; } - bool add_site = - true; // this insures that a site is added if 'cells' is not defined + bool add_site = true; // add the site if 'cells' is not defined // If 'cells' is defined if (!settings::ssw_cells.empty()) { for (auto& cell : settings::ssw_cells) { - add_site = true; // we assume the cell-direction pair is valid until it - // gets rejected + add_site = false; // we assume the cell-direction pair is invalid till it + // passes all the tests // Retrieve cell index and storage type int cell_idx = model::cell_map[cell.first]; SSWCellType direction = cell.second; if (surf.bc_) { // Leave if cellto with vacuum boundary condition if (surf.bc_->type() == "vacuum" && direction == SSWCellType::To) { - add_site = false; continue; } // Leave if other boundary condition than vacuum if (surf.bc_->type() != "vacuum") { - add_site = false; continue; } } @@ -937,41 +934,35 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) // Vacuum boundary conditions: return if cell is not exited if (surf.bc_) { if (surf.bc_->type() == "vacuum" && !exited) { - add_site = false; continue; } } else { // If we both enter and exit the cell of interest if (entered && exited) { - add_site = false; continue; } // If we did not enter nor exit the cell of interest if (!entered && !exited) { - add_site = false; continue; } // If cellfrom and the cell before crossing is not the cell of // interest if (direction == SSWCellType::From && !exited) { - add_site = false; continue; } // If cellto and the cell after crossing is not the cell of interest if (direction == SSWCellType::To && !entered) { - add_site = false; continue; } } - // if any cell-direction pair survived all the checks we terminate the - // loop - if (add_site) { - break; - } + // if the cell-direction pair survived all the checks we add the site and + // terminate the loop + add_site = true; + break; } } From ef928fac4d8e117cbe5bc661c7e19f6690586100 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sat, 21 Feb 2026 10:58:22 -0600 Subject: [PATCH 11/20] handled duplicated cells --- src/settings.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/settings.cpp b/src/settings.cpp index d7fcd108b95..ea8aae7eb65 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -941,7 +941,12 @@ void read_settings_xml(pugi::xml_node root) } for (std::size_t i {0}; i < ids.size(); ++i) { SSWCellType direction = ssw_cell_type_from_string(directions[i]); - ssw_cells.emplace(ids[i], direction); + auto [it, inserted] = ssw_cells.emplace(ids[i], direction); + //check for duplicate keys with different values + if (!inserted && it->second != direction) { + // the union of different values will always be 'Both' + it->second = SSWCellType::Both; + } } } else { // default behavior if 'directions' is not defined for (std::size_t i {0}; i < ids.size(); ++i) { From 63bbc1a5dc25961aab0b0c3ecb1d06510e79cc18 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sat, 21 Feb 2026 11:02:44 -0600 Subject: [PATCH 12/20] added descriptions for the parameters in the openmc api --- openmc/settings.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openmc/settings.py b/openmc/settings.py index d9a4cd081c6..66b83504fb2 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -284,6 +284,15 @@ class Settings: surfaces are to be banked. Particles coming from or going to this declared cell will be banked (int) :directions: List of directions corresponding to cells. + :cell: Cell ID used to determine if particles crossing identified + surfaces are to be banked. Particles coming from or going to this + declared cell will be banked (int) + :cellfrom: Cell ID used to determine if particles crossing identified + surfaces are to be banked. Particles coming from this + declared cell will be banked (int) + :cellto: Cell ID used to determine if particles crossing identified + surfaces are to be banked. Particles going to this declared + cell will be banked (int) Acceptable entries are: "from", "to", or "both" (str) survival_biasing : bool Indicate whether survival biasing is to be used From 2b9424f7a28a0c1911a8fee9fe03a75c0e955f67 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sat, 21 Feb 2026 11:46:08 -0600 Subject: [PATCH 13/20] refactored the site adding loop logic --- src/particle.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 35b70a995bc..f6af5ffd991 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -897,24 +897,21 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) // If 'cells' is defined if (!settings::ssw_cells.empty()) { + if (surf.bc_ && surf.bc_->type() != "vacuum") { + // Leave if other boundary condition than vacuum + return; + } + add_site = false; // we assume all cell-direction pairs are invalid till one of + // them passes all the tests for (auto& cell : settings::ssw_cells) { - add_site = false; // we assume the cell-direction pair is invalid till it - // passes all the tests // Retrieve cell index and storage type int cell_idx = model::cell_map[cell.first]; SSWCellType direction = cell.second; - if (surf.bc_) { - // Leave if cellto with vacuum boundary condition - if (surf.bc_->type() == "vacuum" && direction == SSWCellType::To) { + if (surf.bc_ && surf.bc_->type() == "vacuum" && direction == SSWCellType::To) { + // skip if cellto with vacuum boundary condition continue; } - // Leave if other boundary condition than vacuum - if (surf.bc_->type() != "vacuum") { - continue; - } - } - // Check if the cell of interest has been exited bool exited = false; for (int i = 0; i < p.n_coord_last(); ++i) { From 1c5c8c246c51d543a5470fc367c202267927f8e5 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 22 Feb 2026 12:28:53 -0600 Subject: [PATCH 14/20] added regression tests --- openmc/settings.py | 6 +- src/particle.cpp | 2 +- .../case-22/inputs_true.dat | 70 +++++-- .../case-22/surface_source_true.h5 | Bin 0 -> 15068 bytes .../case-23/inputs_true.dat | 70 +++++-- .../case-23/surface_source_true.h5 | Bin 0 -> 14564 bytes .../case-24/inputs_true.dat | 69 +++++-- .../case-24/surface_source_true.h5 | Bin 0 -> 27416 bytes .../surface_source_write/test.py | 171 ++++++++++++++---- 9 files changed, 302 insertions(+), 86 deletions(-) create mode 100644 tests/regression_tests/surface_source_write/case-22/surface_source_true.h5 create mode 100644 tests/regression_tests/surface_source_write/case-23/surface_source_true.h5 create mode 100644 tests/regression_tests/surface_source_write/case-24/surface_source_true.h5 diff --git a/openmc/settings.py b/openmc/settings.py index 66b83504fb2..938211348aa 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -286,13 +286,13 @@ class Settings: :directions: List of directions corresponding to cells. :cell: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this - declared cell will be banked (int) + declared cell will be banked (int) ("cell" will be deprecated in the future, use "cells" instead.) :cellfrom: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles coming from this - declared cell will be banked (int) + declared cell will be banked (int) ("cellfrom" will be deprecated in the future, use "cells" and "directions" instead.) :cellto: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles going to this declared - cell will be banked (int) + cell will be banked (int) ("cellto" will be deprecated in the future, use "cells" and "directions" instead.) Acceptable entries are: "from", "to", or "both" (str) survival_biasing : bool Indicate whether survival biasing is to be used diff --git a/src/particle.cpp b/src/particle.cpp index f6af5ffd991..5c6894f275d 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -956,7 +956,7 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) continue; } } - // if the cell-direction pair survived all the checks we add the site and + // if a cell-direction pair survived all the checks we add the site and // terminate the loop add_site = true; break; diff --git a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat index 801f17191b9..a39d905ce90 100644 --- a/tests/regression_tests/surface_source_write/case-22/inputs_true.dat +++ b/tests/regression_tests/surface_source_write/case-22/inputs_true.dat @@ -3,39 +3,75 @@ - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + fixed source - 20 + 60 5 - + + + 1.5 0.5 0.5 + + + + + + 2.5 0.5 0.5 + + + + 0.5 0.5 1.5 + + + + + 3.5 0.5 1.5 + + + + + + 1.5 0.5 2.5 + - + - 1.5 0.5 1.5 + 2.5 0.5 2.5 - 7 + 2 4 9 10 300 - 1 + 6 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-22/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-22/surface_source_true.h5 new file mode 100644 index 0000000000000000000000000000000000000000..27bca94959af53ff6a72ddde88fa80370ebd6056 GIT binary patch literal 15068 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 n;J4T>D(cDfH#{`wkx$z^doPm>yFbkY - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + fixed source - 20 + 60 5 - + + + 1.5 0.5 0.5 + + + + + + 2.5 0.5 0.5 + + + + 0.5 0.5 1.5 + + + + + 3.5 0.5 1.5 + + + + + + 1.5 0.5 2.5 + - + - 1.5 0.5 1.5 + 2.5 0.5 2.5 - 7 + 2 4 9 10 300 - 2 + 7 + to 1 diff --git a/tests/regression_tests/surface_source_write/case-23/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-23/surface_source_true.h5 new file mode 100644 index 0000000000000000000000000000000000000000..432adb6a30c7e60505b5e11aaf9b3b58f3500f91 GIT binary patch literal 14564 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 - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + fixed source - 20 + 60 5 - + + + 1.5 0.5 0.5 + + + + + + 2.5 0.5 0.5 + + + + 0.5 0.5 1.5 + + + + + 3.5 0.5 1.5 + + + + + + 1.5 0.5 2.5 + - + - 1.5 0.5 1.5 + 2.5 0.5 2.5 - 7 + 2 4 9 10 300 - 1 2 + 6 7 to to 1 diff --git a/tests/regression_tests/surface_source_write/case-24/surface_source_true.h5 b/tests/regression_tests/surface_source_write/case-24/surface_source_true.h5 new file mode 100644 index 0000000000000000000000000000000000000000..5fd380aba2df6506bd02ba99539d9a7aa1686593 GIT binary patch literal 27416 zcmeHPd00*B+is#H4Tc7h2AXAS7S(>5=ae)WA|XN(QpQdkP39pL;TK0`CNkzAQ*lH} zN{UQTBB4azrrvLRcGj}&>-_Uw-!B(?_qNu(?&rDh=Y5~`uAKx28@oQ@1H}cteTj() zhzLl3e@p)9==zeM-8n+OCqEDDdL!8Ny1MIipHSx;K@Q@#pUHQPOLyTb3wI8rc8z;^ z+S&?mjwJZxwd=;cr8-oa=aTUL!bvnS9A|@W16cn#sYOV`P*qIgx$)Vhb4d7BKAK zoWJP%_nhga>y_%|XXnOr9gJtC?g&3ScYfDl#4Fv;>KysM93yAa{QlMH#;$LE^76C% zM1{=x?pM>F9RK6c&(2*qBkKDh>>m&O$@`z3J1sbL%A(+DlV?QCn;*tG$KfaE{W$bv zZA8wGm_9jVnt;oX2mIvykLQFO9Q%{we;oSp+#Vd)eybZHA))UTCDv7E z!h-v{>>M`r$8-C3x%}I~UMEsR#<{uM2yzgJ_w&2z^~ZDm`<`hAK3R4iS=05})b+}H zev@VPf%TuXPr5@&&xrl^BVL$y9?^MxFU~h?B8UJlCTHUM=~q)hP>63Y-zQEGon7-- zA+a7|eruq(m||TRgeSR1QvomZA!X%i%S{HbTqeMf^S!o!m~_R5KeB`z|LQ)^V)^I+h!5;JHFi3?hG3D-Nn8eJH~O8AsJ9z0jP z`qQte4)MgX6JEqiBo}0y>-nbJn!d= zO~SQ_c{11CCDnOO&#g{yX_npI>OZW*SW9Jn!}0QB>;AhJ<%V75*dgmIjmPOJXP2Amd!!cO26i zadDmoyr>8ev6|S9FtP5;=cW8P{Wd%lWx=Ox(|bGM6T-xG#9a6IbtSvjjn#+yepLaZ zkA6Uy^tyMCnbgtM=+=W%(ygG*e}jWg4P70P{E>W8>t0mE%0D#31fCe1Wa%1W&(nK} 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 Date: Sun, 22 Feb 2026 13:51:13 -0600 Subject: [PATCH 15/20] added documentation --- docs/source/io_formats/settings.rst | 29 +++++++++++++++++++++----- docs/source/usersguide/settings.rst | 32 +++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index db72984a63b..b25e7d517f5 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -1166,11 +1166,12 @@ attributes/sub-elements: The ```` element triggers OpenMC to bank particles crossing certain surfaces and write out the source bank in a separate file called -``surface_source.h5``. One or multiple surface IDs and one cell ID can be used -to select the surfaces of interest. If no surface IDs are declared, every surface -of the model is eligible to bank particles. In that case, a cell ID (using -either the ``cell``, ``cellfrom`` or ``cellto`` attributes) can be used to select -every surface of a specific cell. This element has the following +``surface_source.h5``. One or multiple surface IDs and one or multiple cell IDs can be used +to select the surfaces of interest. The cell IDs can have direction flags assosciated with them +to further filter the banked particles. Allowed directions are ``to``, ``from`` or ``both``. +If only one cell ID is used in banking, the ``cell``, ``cellfrom`` or ``cellto`` attributes +can be used instead of the ``cells`` and ``directions`` attributes. If no surface IDs are declared, +every surface of the model is eligible to bank particles. This element has the following attributes/sub-elements: :surface_ids: @@ -1206,6 +1207,18 @@ attributes/sub-elements: .. _MCPL: https://mctools.github.io/mcpl/mcpl.pdf + :cells: + A list of integers representing the cell IDs used to determine if particles crossing + identified surfaces are to be banked. + + *Default*: None + + :directions: + A list of strings representing the directions corresponding to the cell IDs. Allowed values are + ``to``, ``from`` or ``both``. Must have the same length as ``cells``. + + *Default*: None + :cell: An integer representing the cell ID used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this @@ -1227,9 +1240,15 @@ attributes/sub-elements: *Default*: None +.. note:: The ``cell``, ``cellfrom`` or ``cellto`` attributes cannot be + used simultaneously with ``cells`` attribute. + .. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be used simultaneously. +.. note:: If ``cells`` attribute is defined and ``directions`` attribute is not, + all the directions of in ``cells`` will default to ``both``. + .. note:: Surfaces with boundary conditions that are not "transmission" or "vacuum" are not eligible to store any particles when using ``cell``, ``cellfrom`` or ``cellto`` attributes. It is recommended to use surface IDs instead. diff --git a/docs/source/usersguide/settings.rst b/docs/source/usersguide/settings.rst index 5a04fedd70a..309a6e1b582 100644 --- a/docs/source/usersguide/settings.rst +++ b/docs/source/usersguide/settings.rst @@ -323,8 +323,32 @@ crossing any surface of the model will be banked:: settings.surf_source_write = {'max_particles': 10000} -A cell ID can also be used to bank particles that are crossing any surface of -a cell that particles are either coming from or going to:: +A list of cell IDs can also be used to bank particles that are crossing surfaces of +cells that particles are either coming from or going to:: + + settings.surf_source_write = { + 'surfaces_ids': [1, 2, 3], + 'cells': [1, 2] + 'max_particles': 10000 + } + +In this example, particles that are crossing surfaces with IDs of 1, 2, or 3 and +entering or exiting cells with IDs 1 or 2 are banked. + +To account specifically for particles leaving or entering a given cell, +a list of directions can be used to further filter particles banked:: + + settings.surf_source_write = { + 'surfaces_ids': [1, 2, 3], + 'cells': [1, 2] + 'directions': '"to", "from"' + 'max_particles': 10000 + } + +In this example, particles that are crossing surfaces with IDs of 1, 2, or 3 and +entering cell with ID 1 or exiting cell with ID 2 are banked. + +If only one cell is used to filter particles, an alternative syntax can be used to bank particles:: settings.surf_source_write = {'cell': 1, 'max_particles': 10000} @@ -333,10 +357,10 @@ be banked excluding any surface that does not use a 'transmission' or 'vacuum' boundary condition. .. note:: Surfaces with boundary conditions that are not "transmission" or "vacuum" - are not eligible to store any particles when using ``cell``, ``cellfrom`` + are not eligible to store any particles when using ``cells``, ``cell``, ``cellfrom`` or ``cellto`` attributes. It is recommended to use surface IDs instead. -Surface IDs can be used in combination with a cell ID:: +Another example that combines surface IDs with a cell ID:: settings.surf_source_write = { 'cell': 1, From 6f66e21708129d8c73b08fe3817ac484b33a42c7 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 22 Feb 2026 14:07:30 -0600 Subject: [PATCH 16/20] fixed formatting --- src/particle.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/particle.cpp b/src/particle.cpp index 5c6894f275d..6b38053cf11 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -901,16 +901,17 @@ void add_surf_source_to_bank(Particle& p, const Surface& surf) // Leave if other boundary condition than vacuum return; } - add_site = false; // we assume all cell-direction pairs are invalid till one of - // them passes all the tests + add_site = false; // we assume all cell-direction pairs are invalid till one + // of them passes all the tests for (auto& cell : settings::ssw_cells) { // Retrieve cell index and storage type int cell_idx = model::cell_map[cell.first]; SSWCellType direction = cell.second; - if (surf.bc_ && surf.bc_->type() == "vacuum" && direction == SSWCellType::To) { + if (surf.bc_ && surf.bc_->type() == "vacuum" && + direction == SSWCellType::To) { // skip if cellto with vacuum boundary condition - continue; - } + continue; + } // Check if the cell of interest has been exited bool exited = false; From 59b4ba5179cd9347ef803f566bbd42aa318ee5ae Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 22 Feb 2026 15:07:36 -0600 Subject: [PATCH 17/20] fixed typos --- openmc/settings.py | 13 ++++++++----- .../surface_source_write/test.py | 16 +++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index 938211348aa..9d72902ae57 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -283,17 +283,20 @@ class Settings: :cells: List of cell IDs used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this declared cell will be banked (int) - :directions: List of directions corresponding to cells. + :directions: List of directions corresponding to cells. Acceptable entries are: + "from", "to", or "both" (str) :cell: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles coming from or going to this - declared cell will be banked (int) ("cell" will be deprecated in the future, use "cells" instead.) + declared cell will be banked (int) ("cell" will be deprecated in the future, + use "cells" instead.) :cellfrom: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles coming from this - declared cell will be banked (int) ("cellfrom" will be deprecated in the future, use "cells" and "directions" instead.) + declared cell will be banked (int) ("cellfrom" will be deprecated in the future, + use "cells" and "directions" instead.) :cellto: Cell ID used to determine if particles crossing identified surfaces are to be banked. Particles going to this declared - cell will be banked (int) ("cellto" will be deprecated in the future, use "cells" and "directions" instead.) - Acceptable entries are: "from", "to", or "both" (str) + cell will be banked (int) ("cellto" will be deprecated in the future, + use "cells" and "directions" instead.) survival_biasing : bool Indicate whether survival biasing is to be used tabular_legendre : dict diff --git a/tests/regression_tests/surface_source_write/test.py b/tests/regression_tests/surface_source_write/test.py index 96503e123f3..55d118eec71 100644 --- a/tests/regression_tests/surface_source_write/test.py +++ b/tests/regression_tests/surface_source_write/test.py @@ -961,7 +961,7 @@ def test_consistency_low_realization_number(model_1, two_threads, single_process "model_1", {"max_particles": 300, "surface_ids": [4, 5, 6, 7, 8, 9], "cell": 2}, ), - ("case-e02", "model_1", {"max_particles": 300, "cell": [3]}), + ("case-e02", "model_1", {"max_particles": 300, "cell": 3}), ( "case-e03", "model_2", @@ -1179,21 +1179,21 @@ def model_dagmc_2(): [ ("case-d01", "model_dagmc_1", {"max_particles": 300}), ("case-d02", "model_dagmc_1", {"max_particles": 300, "surface_ids": [1]}), - ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": [2]}), + ("case-d03", "model_dagmc_1", {"max_particles": 300, "cell": 2}), ( "case-d04", "model_dagmc_1", - {"max_particles": 300, "surface_ids": [1], "cell": [2]}, + {"max_particles": 300, "surface_ids": [1], "cell": 2}, ), - ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": [2]}), - ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": [2]}), + ("case-d05", "model_dagmc_1", {"max_particles": 300, "cellfrom": 2}), + ("case-d06", "model_dagmc_1", {"max_particles": 300, "cellto": 2}), ( "case-d07", "model_dagmc_2", { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": [7], + "cell": 7, }, ), ( @@ -1202,7 +1202,7 @@ def model_dagmc_2(): { "max_particles": 300, "surface_ids": [101, 102, 103, 104, 105, 106], - "cell": [8], + "cell": 8, }, ), ], @@ -1238,8 +1238,6 @@ def run_and_count(model, folder, parameter): harness._compare_inputs() harness._run_openmc() harness._test_output_created() - - # count banked particles in surface_source.h5 return len(return_surface_source_data("surface_source.h5")) finally: harness._cleanup() From 993d99c1968f664b51955a2d868daf5919cabcec Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 22 Feb 2026 19:40:51 -0600 Subject: [PATCH 18/20] fixed formatting error --- src/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.cpp b/src/settings.cpp index ea8aae7eb65..023ba1b162f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -942,7 +942,7 @@ void read_settings_xml(pugi::xml_node root) for (std::size_t i {0}; i < ids.size(); ++i) { SSWCellType direction = ssw_cell_type_from_string(directions[i]); auto [it, inserted] = ssw_cells.emplace(ids[i], direction); - //check for duplicate keys with different values + // check for duplicate keys with different values if (!inserted && it->second != direction) { // the union of different values will always be 'Both' it->second = SSWCellType::Both; From 7113ea55754306107c56a91a638b571939291265 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Sun, 22 Feb 2026 22:24:20 -0600 Subject: [PATCH 19/20] fixed order in creating surface_source_write xml --- openmc/settings.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index 9d72902ae57..e19d057f6be 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1559,6 +1559,10 @@ def _create_surf_source_write_subelement(self, root): str(x) for x in self._surf_source_write["surface_ids"] ) + if "mcpl" in self._surf_source_write: + subelement = ET.SubElement(element, "mcpl") + subelement.text = str(self._surf_source_write["mcpl"]).lower() + for key in ("max_particles", "max_source_files", "cell", "cellfrom", "cellto"): if key in self._surf_source_write: subelement = ET.SubElement(element, key) @@ -1571,11 +1575,6 @@ def _create_surf_source_write_subelement(self, root): str(x) for x in self._surf_source_write[key] ) - if "mcpl" in self._surf_source_write: - subelement = ET.SubElement(element, "mcpl") - subelement.text = str(self._surf_source_write["mcpl"]).lower() - - def _create_collision_track_subelement(self, root): if self._collision_track: element = ET.SubElement(root, "collision_track") From b76e2466e9dfaf7d50d1a06041e68df36aab0e74 Mon Sep 17 00:00:00 2001 From: MohamedElkamash Date: Thu, 26 Feb 2026 16:56:29 -0600 Subject: [PATCH 20/20] triggering CI