Addressing comments from @paulromano

This commit is contained in:
Patrick Shriwise 2022-12-12 21:18:48 -06:00
parent 145594ebb8
commit f3bcad37b7
6 changed files with 85 additions and 88 deletions

View file

@ -43,7 +43,8 @@ def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None,
MPI execute command and any additional MPI arguments to pass,
e.g. ['mpiexec', '-n', '8'].
path_input : str or Pathlike
Name of a single XML input file for the OpenMC executable to read.
Path to a single XML file or a directory containing XML files for the
OpenMC executable to read.
.. versionadded:: 0.13.0
@ -135,7 +136,8 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None):
cwd : str, optional
Path to working directory to run in
path_input : str
Name of a single XML input file for the OpenMC executable to read.
Path to a single XML file or a directory containing XML files for the
OpenMC executable to read.
Raises
------
@ -146,7 +148,7 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None):
args = [openmc_exec, '-p']
if path_input is not None:
args += [path_input]
_run([openmc_exec, '-p'], output, cwd)
_run(args, output, cwd)
def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None):
@ -166,7 +168,8 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None):
cwd : str, optional
Path to working directory to run in
path_input : str
Name of a single XML input file for the OpenMC executable to read.
Path to a single XML file or a directory containing XML files for the
OpenMC executable to read.
Raises
------
@ -224,7 +227,9 @@ def calculate_volumes(threads=None, output=True, cwd='.',
Path to working directory to run in. Defaults to the current working
directory.
path_input : str or Pathlike
Name of a single XML input file for the OpenMC executable to read.
Path to a single XML file or a directory containing XML files for the
OpenMC executable to read.
Raises
------
@ -256,17 +261,17 @@ def run(particles=None, threads=None, geometry_debug=False,
Number of particles to simulate per generation.
threads : int, optional
Number of OpenMP threads. If OpenMC is compiled with OpenMP threading
enabled, the default is implementation-dependent but is usually equal
to the number of hardware threads available (or a value set by the
enabled, the default is implementation-dependent but is usually equal to
the number of hardware threads available (or a value set by the
:envvar:`OMP_NUM_THREADS` environment variable).
geometry_debug : bool, optional
Turn on geometry debugging during simulation. Defaults to False.
restart_file : str, optional
Path to restart file to use
tracks : bool, optional
Enables the writing of particles tracks. The number of particle
tracks written to tracks.h5 is limited to 1000 unless
Settings.max_tracks is set. Defaults to False.
Enables the writing of particles tracks. The number of particle tracks
written to tracks.h5 is limited to 1000 unless Settings.max_tracks is
set. Defaults to False.
output : bool
Capture OpenMC output from standard out
cwd : str, optional
@ -275,15 +280,16 @@ def run(particles=None, threads=None, geometry_debug=False,
openmc_exec : str, optional
Path to OpenMC executable. Defaults to 'openmc'.
mpi_args : list of str, optional
MPI execute command and any additional MPI arguments to pass,
e.g. ['mpiexec', '-n', '8'].
MPI execute command and any additional MPI arguments to pass, e.g.
['mpiexec', '-n', '8'].
event_based : bool, optional
Turns on event-based parallelism, instead of default history-based
.. versionadded:: 0.12
path_input : str or Pathlike
Name of a single XML input file for the OpenMC executable to read.
Path to a single XML file or a directory containing XML files for the
OpenMC executable to read.
Raises
------

View file

@ -179,6 +179,11 @@ class Geometry:
Geometry object
"""
mats = dict()
if materials is not None:
mats.update({str(m.id): m for m in materials})
mats['void'] = None
# Helper function for keeping a cache of Universe instances
universes = {}
def get_universe(univ_id):
@ -236,7 +241,7 @@ class Geometry:
child_of[u].append(lat)
for e in elem.findall('cell'):
c = openmc.Cell.from_xml_element(e, surfaces, materials, get_universe)
c = openmc.Cell.from_xml_element(e, surfaces, mats, get_universe)
if c.fill_type in ('universe', 'lattice'):
child_of[c.fill].append(c)
@ -266,17 +271,15 @@ class Geometry:
Geometry object
"""
tree = ET.parse(path)
root = tree.getroot()
# Create dictionary to easily look up materials
# Create dictionary to easily look up materials
if materials is None:
filename = Path(path).parent / 'materials.xml'
materials = openmc.Materials.from_xml(str(filename))
mats = {str(m.id): m for m in materials}
mats['void'] = None
return cls.from_xml_element(root, mats)
tree = ET.parse(path)
root = tree.getroot()
return cls.from_xml_element(root, materials)
def find(self, point):
"""Find cells/universes/lattices which contain a given point

View file

@ -256,8 +256,7 @@ class Model:
model.settings = openmc.Settings.from_xml_element(root.find('settings'))
model.materials = openmc.Materials.from_xml_element(root.find('materials'))
materials = {str(m.id): m for m in model.materials}
model.geometry = openmc.Geometry.from_xml_element(root.find('geometry'), materials)
model.geometry = openmc.Geometry.from_xml_element(root.find('geometry'), model.materials)
# gather meshes from other classes before reading the tally node
meshes = {}
@ -435,30 +434,7 @@ class Model:
depletion_operator.cleanup_when_done = True
depletion_operator.finalize()
def export_to_xml(self, directory='.', remove_surfs=False, separate_xmls=True, path='model.xml'):
"""Export model to an XML file(s).
Parameters
----------
directory : str
Directory to write XML files to. If it doesn't exist already, it
will be created. Only used if :math:`separate_xmls` is True.
remove_surfs : bool
Whether or not to remove redundant surfaces from the geometry when
exporting.
path : str
Path to an output filename or directory. Only used if :math:`separate_xmls` is False.
.. versionadded:: 0.13.1
separate_xmls : bool
Whether or not to write a single model.xml file or many XML files.
"""
if separate_xmls:
self._export_to_separate_xmls(directory, remove_surfs)
else:
self._export_to_single_xml(path, remove_surfs)
def _export_to_separate_xmls(self, directory='.', remove_surfs=False):
def export_to_xml(self, directory='.', remove_surfs=False):
"""Export model to separate XML files.
Parameters
@ -495,13 +471,14 @@ class Model:
if self.plots:
self.plots.export_to_xml(d)
def _export_to_single_xml(self, path='model.xml', remove_surfs=False):
def export_to_model_xml(self, path='model.xml', remove_surfs=False):
"""Export model to a single XML file.
Parameters
----------
path : str or Pathlike
Location of the XML file to write. Can be a directory or file path.
Location of the XML file to write (default is 'model.xml'). Can be a
directory or file path.
remove_surfs : bool
Whether or not to remove redundant surfaces from the geometry when
exporting.

View file

@ -1074,31 +1074,33 @@ class Settings:
subelement.text = str(value)
def _create_entropy_mesh_subelement(self, root, mesh_memo=None):
if self.entropy_mesh is not None:
# use default heuristic for entropy mesh if not set by user
if self.entropy_mesh.dimension is None:
if self.particles is None:
raise RuntimeError("Number of particles must be set in order to " \
"use entropy mesh dimension heuristic")
else:
n = ceil((self.particles / 20.0)**(1.0 / 3.0))
d = len(self.entropy_mesh.lower_left)
self.entropy_mesh.dimension = (n,)*d
if self.entropy_mesh is None:
return
# add mesh ID to this element
subelement = ET.SubElement(root, "entropy_mesh")
subelement.text = str(self.entropy_mesh.id)
# use default heuristic for entropy mesh if not set by user
if self.entropy_mesh.dimension is None:
if self.particles is None:
raise RuntimeError("Number of particles must be set in order to " \
"use entropy mesh dimension heuristic")
else:
n = ceil((self.particles / 20.0)**(1.0 / 3.0))
d = len(self.entropy_mesh.lower_left)
self.entropy_mesh.dimension = (n,)*d
# If this mesh has already been written outside the
# settings element, skip writing it again
if mesh_memo and self.entropy_mesh.id in mesh_memo:
return
# add mesh ID to this element
subelement = ET.SubElement(root, "entropy_mesh")
subelement.text = str(self.entropy_mesh.id)
# See if a <mesh> element already exists -- if not, add it
path = f"./mesh[@id='{self.entropy_mesh.id}']"
if root.find(path) is None:
root.append(self.entropy_mesh.to_xml_element())
if mesh_memo is not None: mesh_memo.add(self.entropy_mesh.id)
# If this mesh has already been written outside the
# settings element, skip writing it again
if mesh_memo and self.entropy_mesh.id in mesh_memo:
return
# See if a <mesh> element already exists -- if not, add it
path = f"./mesh[@id='{self.entropy_mesh.id}']"
if root.find(path) is None:
root.append(self.entropy_mesh.to_xml_element())
if mesh_memo is not None: mesh_memo.add(self.entropy_mesh.id)
def _create_trigger_subelement(self, root):
if self._trigger_active is not None:
@ -1149,15 +1151,21 @@ class Settings:
element = ET.SubElement(root, "track")
element.text = ' '.join(map(str, itertools.chain(*self._track)))
def _create_ufs_mesh_subelement(self, root):
if self.ufs_mesh is not None:
# See if a <mesh> element already exists -- if not, add it
path = f"./mesh[@id='{self.ufs_mesh.id}']"
if root.find(path) is None:
root.append(self.ufs_mesh.to_xml_element())
def _create_ufs_mesh_subelement(self, root, mesh_memo=None):
if self.ufs_mesh is None:
return
subelement = ET.SubElement(root, "ufs_mesh")
subelement.text = str(self.ufs_mesh.id)
subelement = ET.SubElement(root, "ufs_mesh")
subelement.text = str(self.ufs_mesh.id)
if mesh_memo and self.ufs_mesh.id in mesh_memo:
return
# See if a <mesh> element already exists -- if not, add it
path = f"./mesh[@id='{self.ufs_mesh.id}']"
if root.find(path) is None:
root.append(self.ufs_mesh.to_xml_element())
if mesh_memo is not None: mesh_memo.add(self.ufs_mesh.id)
def _create_resonance_scattering_subelement(self, root):
res = self.resonance_scattering

View file

@ -27,7 +27,7 @@ class ModelXMLTestHarness(PyAPITestHarness):
self.results_true = 'results_true.dat' if results_true is None else results_true
def _build_inputs(self):
self._model.export_to_xml(separate_xmls=False)
self._model.export_to_model_xml()
def _get_inputs(self):
return open('model.xml').read()
@ -77,21 +77,24 @@ def test_input_arg(run_in_tmpdir):
pincell.settings.particles = 100
# export to separate XML files and run
pincell.export_to_xml(separate_xmls=True)
pincell.export_to_xml()
openmc.run()
# make sure the executable isn't falling back on the separate XMLs
for f in glob.glob('*.xml'):
os.remove(f)
# now export to a single XML file with a custom name
pincell.export_to_xml(path='pincell.xml', separate_xmls=False)
pincell.export_to_model_xml('pincell.xml')
assert Path('pincell.xml').exists()
# run by specifying that single file
openmc.run(path_input='pincell.xml')
# check that this works for plotting too
openmc.plot_geometry(path_input='pincell.xml')
# now ensure we get an error for an incorrect filename,
# even in the presence of other, valid XML files
pincell.export_to_xml(separate_xmls=True)
pincell.export_to_model_xml()
with pytest.raises(RuntimeError, match='ex-em-ell.xml'):
openmc.run(path_input='ex-em-ell.xml')

View file

@ -542,18 +542,18 @@ def test_model_xml(run_in_tmpdir):
pwr_model.geometry.export_to_xml('geometry_ref.xml')
# now write and read a model.xml file
pwr_model.export_to_xml(separate_xmls=False)
pwr_model.export_to_model_xml()
new_model = openmc.Model.from_model_xml()
# make sure we can also export this again to separate
# XML files
new_model.export_to_xml(separate_xmls=True)
new_model.export_to_xml()
def test_model_exec(run_in_tmpdir):
def test_single_xml_exec(run_in_tmpdir):
pincell_model = openmc.examples.pwr_pin_cell()
pincell_model.export_to_xml(path='pwr_pincell.xml', separate_xmls=False)
pincell_model.export_to_model_xml('pwr_pincell.xml')
openmc.run(path_input='pwr_pincell.xml')
@ -562,7 +562,7 @@ def test_model_exec(run_in_tmpdir):
# test that a file in a different directory can be used
os.mkdir('inputs')
pincell_model.export_to_xml(path='./inputs/pincell.xml', separate_xmls=False)
pincell_model.export_to_model_xml('./inputs/pincell.xml')
openmc.run(path_input='./inputs/pincell.xml')
with pytest.raises(RuntimeError, match='input_dir'):