Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9b26b53
preliminary implementation
MohamedElkamash Feb 15, 2026
df2f44c
added direction parameter instead of cellto and cellfrom
MohamedElkamash Feb 16, 2026
80f2274
added directions parameter to python api
MohamedElkamash Feb 16, 2026
b6a4a33
allowed the old syntax
MohamedElkamash Feb 19, 2026
1038551
added ssw_cell_id back to finalize
MohamedElkamash Feb 19, 2026
cc4c88f
changed the condition of adding a surface to bank from particle.cpp t…
MohamedElkamash Feb 19, 2026
e40c7a6
simplified the add site loop logic
MohamedElkamash Feb 20, 2026
2e4f8fe
handled duplicated cells
MohamedElkamash Feb 21, 2026
c3c9fc0
added descriptions for the parameters in the openmc api
MohamedElkamash Feb 21, 2026
643047f
refactored the site adding loop logic
MohamedElkamash Feb 21, 2026
7e466eb
added regression tests
MohamedElkamash Feb 22, 2026
e1b3734
added regression tests
MohamedElkamash Feb 22, 2026
3bcece0
added documentation
MohamedElkamash Feb 22, 2026
31cddb0
fixed order in creating surface_source_write xml
MohamedElkamash Feb 23, 2026
631d4ae
Update error messages + unit tests for surface_source_write
JoffreyDorville Mar 11, 2026
73bca18
Explicit dependencies
JoffreyDorville Mar 12, 2026
19284a7
Remove duplicate settings declaration and reorder settings
JoffreyDorville Mar 12, 2026
8d64ed8
Remove unused settings
JoffreyDorville Mar 12, 2026
61be8bd
Update documentation
JoffreyDorville Mar 12, 2026
f27bd33
Check that the bank is not full early in add_surf_source_to_bank()
JoffreyDorville Mar 12, 2026
6da8232
Formatting
JoffreyDorville Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions docs/source/io_formats/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1166,11 +1166,12 @@ attributes/sub-elements:

The ``<surf_source_write>`` 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:
Expand Down Expand Up @@ -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
Expand All @@ -1227,12 +1240,24 @@ attributes/sub-elements:

*Default*: None

.. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be
.. note:: If the ``cells`` attribute is used and the ``directions`` attribute is not,
all directions associated with the cells declared in the ``cells`` atttribute
are set to ``both`` by default.

.. note:: If only one cell is needed to filter particles, an alternative syntax can be
used to bank particles with the ``cell``, ``cellfrom`` and ``cellto`` attributes.
However, this syntax will be deprecated in the future.

.. note:: The ``cells``, ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be
used simultaneously.

.. note:: The ``directions`` attribute cannot be used with any of the ``cell``,
``cellfrom`` and ``cellto`` attributes.

.. 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.
are not eligible to store any particles when using ``cells``, ``cell``,
``cellfrom`` or ``cellto`` attributes. It is recommended to use surface
IDs instead.

------------------------------------
``<surface_grazing_cutoff>`` Element
Expand Down
53 changes: 44 additions & 9 deletions docs/source/usersguide/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -323,20 +323,55 @@ 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 = {'cell': 1, 'max_particles': 10000}
settings.surf_source_write = {
'surfaces_ids': [1, 2, 3],
'cells': [1, 2],
'max_particles': 10000
}

In this example, particles that are crossing any surface that bounds cell 1 will
be banked excluding any surface that does not use a 'transmission' or 'vacuum'
boundary condition.
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 will 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::
The constraint declared through the ``cells`` attribute is purely disjunctive.
This means that a particle crossing a target surface will be banked if at least one of
the clauses associated with all declared cells is true. In other terms, the logic inside
the ``cells`` attribute corresponds to an "OR" relationship, and not an "AND".

To account specifically for particles leaving or entering a given cell,
a list of directions can also be declared::

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 will be banked.

.. note::

If only one cell is needed to filter particles, an alternative syntax can be used to bank particles
with the ``cell``, ``cellfrom`` and ``cellto`` attributes. However, this syntax will be deprecated
in the future.

For a single cell, particles can be banked using the ``cell`` attribute::

settings.surf_source_write = {'cell': 1, 'max_particles': 10000}

In this example, particles that are crossing any surface that bounds cell 1 will
be banked.

Another example that combines surface IDs with a cell ID::

settings.surf_source_write = {
'cell': 1,
Expand All @@ -361,7 +396,7 @@ or particles going to a cell::
'max_particles': 10000
}

.. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be
.. note:: The ``cells``, ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be
used simultaneously.

To generate more than one surface source files when the maximum number of stored
Expand Down
12 changes: 8 additions & 4 deletions include/openmc/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <cstdint>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>

#include "pugixml.hpp"
Expand Down Expand Up @@ -177,12 +179,12 @@ 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 std::unordered_map<int64_t, SSWCellType>
ssw_cells; //!< Cell ids and directions for the surface source write setting

extern double surface_grazing_cutoff; //!< surface flux cosine cutoff
extern double surface_grazing_ratio; //!< surface flux substitution ratio

extern TemperatureMethod
temperature_method; //!< method for choosing temperatures
extern double
Expand Down Expand Up @@ -215,6 +217,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
56 changes: 42 additions & 14 deletions openmc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,24 @@ 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)
:cells: List of cell IDs used to determine if particles crossing identified
surfaces are to be banked. Particles coming from or going to these
declared cells will be banked depending on the requested direction
via the 'directions' keyword or both directions by default (int)
: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)
declared cell will be banked (int) ("cell" will be deprecated in the future,
please 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,
please 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,
please use "cells" and "directions" instead.)
surface_grazing_cutoff : float
Surface flux cosine cutoff. If not specified, the default value is
0.001. For more information, see the surface tally section in the theory
Expand All @@ -297,6 +306,7 @@ class Settings:
Surface flux cosine substitution ratio. If not specified, the default
value is 0.5. For more information, see the surface tally section in the
theory manual.

survival_biasing : bool
Indicate whether survival biasing is to be used
tabular_legendre : dict
Expand Down Expand Up @@ -879,16 +889,21 @@ 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", "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", "cells"):
name = {
"surface_ids": "surface id(s) for source banking",
"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"]):
raise ValueError("Allowed values for directions are: 'from', 'to', or 'both'.")
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"):
Expand Down Expand Up @@ -1569,19 +1584,29 @@ 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"):
if key in self._surf_source_write:
subelement = ET.SubElement(element, key)
subelement.text = str(self._surf_source_write[key])

for key in ("cells", "directions"):
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]
)

def _create_collision_track_subelement(self, root):
if self._collision_track:
element = ET.SubElement(root, "collision_track")
Expand Down Expand Up @@ -2088,9 +2113,12 @@ 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 == 'surface_ids':
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':
value = get_elem_list(elem, key, str)
else:
value = get_text(elem, key)
if value is not None:
Expand Down
2 changes: 0 additions & 2 deletions src/finalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,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;
settings::survival_biasing = false;
Expand Down
Loading
Loading