Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write surface source files per batch #3124

Merged
merged 24 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
abf9b6a
surface sourde per batch
zoeprieto Aug 19, 2024
4c3197a
surface source write only in active batchs for eigenvalue simulation
zoeprieto Aug 19, 2024
412eb3a
settings.surf_source_write with maximum particle files
zoeprieto Aug 19, 2024
8758a2f
default value of max_files added
zoeprieto Aug 19, 2024
3138746
format fix
zoeprieto Aug 19, 2024
c010270
info particle per surface file batch
zoeprieto Aug 23, 2024
29f2aa7
update messege
zoeprieto Aug 23, 2024
201ca7f
option to split source particle list per batch
zoeprieto Sep 10, 2024
b108ec7
format fix
zoeprieto Sep 10, 2024
4ba4c75
surface source batch and write message
zoeprieto Sep 12, 2024
9efee7f
suggested changes
zoeprieto Sep 13, 2024
242a320
message with number of particles
zoeprieto Sep 13, 2024
3c8f500
update test
zoeprieto Sep 13, 2024
2190220
suggested changes
zoeprieto Sep 13, 2024
a05b6fa
update settings.py
zoeprieto Sep 13, 2024
a52e61d
update documentation
zoeprieto Sep 16, 2024
8a93adc
unit test added and suggested changes
zoeprieto Sep 16, 2024
9ed9c08
Update docs/source/io_formats/settings.rst
zoeprieto Sep 17, 2024
177cb8c
option to write surface source file when maximum particle count is re…
zoeprieto Sep 26, 2024
6f8d653
change with clang format
zoeprieto Sep 26, 2024
4cdc3e9
Rename max_surf_files -> max_source_files
paulromano Oct 3, 2024
67a78b8
Variable name change, simplify mcpl/h5 source point calls
paulromano Oct 3, 2024
c44f1fc
Remove Python binding to current_surface_file
paulromano Oct 3, 2024
9e9335d
Rename current_source_file -> ssw_current_file
paulromano Oct 3, 2024
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
9 changes: 9 additions & 0 deletions docs/source/io_formats/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,15 @@ attributes/sub-elements:

*Default*: None

:batches:
An Iterable of integers indicating at what batches a surface source file
should be written. The surface source bank will be cleared in simulation
memory each time a surface source file is written. By default, in the
absence of this attribute, a ``surface_source.h5`` file will be created
after the last batch.

*Default*: None

:mcpl:
An optional boolean which indicates if the banked particles should be
written to a file in the MCPL_-format instead of the native HDF5-based
Expand Down
11 changes: 11 additions & 0 deletions docs/source/usersguide/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,17 @@ or particles going to a cell::
.. note:: The ``cell``, ``cellfrom`` and ``cellto`` attributes cannot be
used simultaneously.

To generate surface source files in different batches, ``batches`` is available. The
surface source bank will be cleared in simulation memory each time a surface source
file is written. As an example, to write a surface source file every five batches::

settings.batches = n
settings.surf_source_write = {
'surfaces_ids': [1, 2, 3],
'max_particles': 10000,
'batches': range(5, n + 5, 5)
}

.. _compiled_source:

Compiled Sources
Expand Down
5 changes: 4 additions & 1 deletion include/openmc/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,11 @@ extern std::unordered_set<int>
sourcepoint_batch; //!< Batches when source should be written
extern std::unordered_set<int>
statepoint_batch; //!< Batches when state should be written
extern std::unordered_set<int>
surface_source_batch; //!< Batches when surface source should be written
extern std::unordered_set<int>
source_write_surf_id; //!< Surface ids where sources will be written

extern int
max_history_splits; //!< maximum number of particle splits for weight windows
extern int64_t max_surface_particles; //!< maximum number of particles to be
Expand Down Expand Up @@ -171,4 +174,4 @@ void free_memory_settings();

} // namespace openmc

#endif // OPENMC_SETTINGS_H
#endif // OPENMC_SETTINGS_H
34 changes: 20 additions & 14 deletions openmc/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ class Settings:
: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)
:batches: List of batches at which to write surface source files
survival_biasing : bool
Indicate whether survival biasing is to be used
tabular_legendre : dict
Expand Down Expand Up @@ -714,14 +715,18 @@ def surf_source_write(self, surf_source_write: dict):
cv.check_value(
"surface source writing key",
key,
("surface_ids", "max_particles", "mcpl", "cell", "cellfrom", "cellto"),
("surface_ids", "max_particles", "batches", "mcpl", "cell", "cellfrom", "cellto"),
)
if key == "surface_ids":
cv.check_type(
"surface ids for source banking", value, Iterable, Integral
if key in ("surface_ids", "batches"):
name = {
"surface_ids": "surface ids for source banking",
"batches": "surface source batches",
}[key]
cv.check_type(name, value, Iterable, Integral
)
for surf_id in value:
cv.check_greater_than("surface id for source banking", surf_id, 0)
for i in value:
cv.check_greater_than(name, i, 0)

elif key == "mcpl":
cv.check_type("write to an MCPL-format file", value, bool)
elif key in ("max_particles", "cell", "cellfrom", "cellto"):
Expand Down Expand Up @@ -1235,11 +1240,12 @@ 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"]
)
for key in ("surface_ids", "batches"):
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()
Expand Down Expand Up @@ -1642,10 +1648,10 @@ 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', 'mcpl', 'cell', 'cellto', 'cellfrom'):
for key in ('surface_ids', 'max_particles', 'batches', 'mcpl', 'cell', 'cellto', 'cellfrom'):
value = get_text(elem, key)
if value is not None:
if key == 'surface_ids':
if key in ('surface_ids', 'batches'):
value = [int(x) for x in value.split()]
elif key == 'mcpl':
value = value in ('true', '1')
Expand Down Expand Up @@ -2088,4 +2094,4 @@ def from_xml(cls, path: PathLike = 'settings.xml'):
tree = ET.parse(path, parser=parser)
root = tree.getroot()
meshes = _read_meshes(root)
return cls.from_xml_element(root, meshes)
return cls.from_xml_element(root, meshes)
11 changes: 10 additions & 1 deletion src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ SolverType solver_type {SolverType::MONTE_CARLO};
std::unordered_set<int> sourcepoint_batch;
std::unordered_set<int> statepoint_batch;
std::unordered_set<int> source_write_surf_id;
std::unordered_set<int> surface_source_batch;
int64_t max_surface_particles;
int64_t ssw_cell_id {C_NONE};
SSWCellType ssw_cell_type {SSWCellType::None};
Expand Down Expand Up @@ -783,6 +784,13 @@ void read_settings_xml(pugi::xml_node root)
}
}

// User gave specific batches to write surface source files
if (check_for_node(node_ssw, "batches")) {
auto temp = get_node_array<int>(node_ssw, "batches");
for (const auto& b : temp) {
surface_source_batch.insert(b);
}
}
// Get maximum number of particles to be banked per surface
if (check_for_node(node_ssw, "max_particles")) {
max_surface_particles =
Expand Down Expand Up @@ -1081,6 +1089,7 @@ void free_memory_settings()
settings::statepoint_batch.clear();
settings::sourcepoint_batch.clear();
settings::source_write_surf_id.clear();
settings::surface_source_batch.clear();
pshriwise marked this conversation as resolved.
Show resolved Hide resolved
settings::res_scat_nuclides.clear();
}

Expand Down Expand Up @@ -1134,4 +1143,4 @@ extern "C" int openmc_get_n_batches(int* n_batches, bool get_max_batches)
return 0;
}

} // namespace openmc
} // namespace openmc
42 changes: 29 additions & 13 deletions src/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,6 @@ void initialize_batch()
{
// Increment current batch
++simulation::current_batch;

if (settings::run_mode == RunMode::FIXED_SOURCE) {
if (settings::solver_type == SolverType::RANDOM_RAY &&
simulation::current_batch < settings::n_inactive + 1) {
Expand Down Expand Up @@ -464,17 +463,34 @@ void finalize_batch()
}

// Write out surface source if requested.
if (settings::surf_source_write &&
simulation::current_batch == settings::n_batches) {
auto filename = settings::path_output + "surface_source";
auto surf_work_index =
mpi::calculate_parallel_index_vector(simulation::surf_source_bank.size());
gsl::span<SourceSite> surfbankspan(simulation::surf_source_bank.begin(),
simulation::surf_source_bank.size());
if (settings::surf_mcpl_write) {
write_mcpl_source_point(filename.c_str(), surfbankspan, surf_work_index);
} else {
write_source_point(filename.c_str(), surfbankspan, surf_work_index);
if (settings::surf_source_write) {
if (contains(settings::surface_source_batch, simulation::current_batch) ||
(simulation::current_batch == settings::n_batches &&
settings::surface_source_batch.size() == 0)) {
auto filename = settings::path_output + "surface_source." +
std::to_string(simulation::current_batch);
// no batches specified for writing, write surface source bank
if (settings::surface_source_batch.size() == 0)
pshriwise marked this conversation as resolved.
Show resolved Hide resolved
filename = settings::path_output + "surface_source";
auto surf_work_index = mpi::calculate_parallel_index_vector(
simulation::surf_source_bank.size());
gsl::span<SourceSite> surfbankspan(simulation::surf_source_bank.begin(),
simulation::surf_source_bank.size());
if (settings::surf_mcpl_write) {
write_message(
"Creating surface source " + filename + ".mcpl with {} particles ...",
simulation::surf_source_bank.size(), 5);
write_mcpl_source_point(
filename.c_str(), surfbankspan, surf_work_index);
} else {
write_message(
pshriwise marked this conversation as resolved.
Show resolved Hide resolved
"Creating surface source " + filename + ".h5 with {} particles ...",
simulation::surf_source_bank.size(), 5);
write_source_point(filename.c_str(), surfbankspan, surf_work_index);
}
simulation::surf_source_bank.clear();
if (simulation::current_batch < settings::n_batches)
simulation::surf_source_bank.reserve(settings::max_surface_particles);
}
}
}
Expand Down Expand Up @@ -840,4 +856,4 @@ void transport_event_based()
}
}

} // namespace openmc
} // namespace openmc
3 changes: 1 addition & 2 deletions tests/regression_tests/dagmc/legacy/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,4 @@ def test_surf_source(model):

def test_dagmc(model):
harness = PyAPITestHarness('statepoint.5.h5', model)
harness.main()

harness.main()
2 changes: 1 addition & 1 deletion tests/regression_tests/surface_source/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,4 @@ def test_surface_source_read(model):
harness = SurfaceSourceTestHarness('statepoint.10.h5',
model,
'inputs_true_read.dat')
harness.main()
harness.main()
2 changes: 1 addition & 1 deletion tests/regression_tests/surface_source_write/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,4 +1129,4 @@ def test_surface_source_cell_dagmc(
harness = SurfaceSourceWriteTestHarness(
"statepoint.5.h5", model=model, workdir=folder
)
harness.main()
harness.main()
57 changes: 56 additions & 1 deletion tests/unit_tests/test_surface_source_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pytest
import h5py
import numpy as np
import os


@pytest.fixture(scope="module")
Expand All @@ -32,6 +33,7 @@ def geometry():
{"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, "batches": [1,2,3]},
],
)
def test_xml_serialization(parameter, run_in_tmpdir):
Expand All @@ -44,6 +46,59 @@ def test_xml_serialization(parameter, run_in_tmpdir):
assert read_settings.surf_source_write == parameter


@pytest.fixture(scope="module")
def model():
"""Simple hydrogen sphere geometry"""
openmc.reset_auto_ids()
model = openmc.Model()

# Material
material = openmc.Material(name="H1")
material.add_element("H", 1.0)

# Geometry
radius = 1.0
sphere = openmc.Sphere(r=radius, boundary_type="reflective")
cell = openmc.Cell(region=-sphere, fill=material)
root = openmc.Universe(cells=[cell])
model.geometry = openmc.Geometry(root)

# Settings
model.settings = openmc.Settings()
model.settings.run_mode = "fixed source"
model.settings.particles = 100
model.settings.batches = 3
model.settings.seed = 1

bounds = [-radius, -radius, -radius, radius, radius, radius]
distribution = openmc.stats.Box(bounds[:3], bounds[3:])
model.settings.source = openmc.IndependentSource(space=distribution)

return model

@pytest.mark.parametrize(
"parameter",
[
{"max_particles": 200, "batches": [1]},
{"max_particles": 200, "batches": [2]},
{"max_particles": 200, "batches": [1,2]},
{"max_particles": 200, "batches": [2,3]},
{"max_particles": 200, "batches": [1,3]},
{"max_particles": 200, "batches": [1,2,3]},
],
)

def test_number_surface_source_file_created(parameter, run_in_tmpdir, model):
"""Check the number of surface source files written."""
model.settings.surf_source_write = parameter
model.run()
for batch in parameter["batches"]:
filename = "surface_source."+str(batch)+".h5"
if not os.path.exists(filename):
assert False
if os.path.exists("surface_source.h5"):
assert False

ERROR_MSG_1 = (
"A maximum number of particles needs to be specified "
"using the 'max_particles' parameter to store surface "
Expand Down Expand Up @@ -245,4 +300,4 @@ def test_particle_direction_dagmc(parameter, run_in_tmpdir, model_dagmc):
elif "cellto" in parameter.keys():
assert ux * x + uy * y < 0
else:
assert False
assert False