mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 14:15:42 -04:00
Resolve relative input paths relative to XML files (#4031)
Some checks are pending
Tests and Coverage / filter-changes (push) Waiting to run
Tests and Coverage / Python 3.13 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14t (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=, event=y (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=y, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / coverage (push) Blocked by required conditions
Tests and Coverage / Check CI status (push) Blocked by required conditions
dockerhub-publish-develop / main (push) Waiting to run
dockerhub-publish-develop-dagmc-libmesh / main (push) Waiting to run
dockerhub-publish-develop-dagmc / main (push) Waiting to run
dockerhub-publish-develop-libmesh / main (push) Waiting to run
Some checks are pending
Tests and Coverage / filter-changes (push) Waiting to run
Tests and Coverage / Python 3.13 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14 (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.14t (omp=n, mpi=n, dagmc=, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=n, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=n, libmesh=n, event=n (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=n, dagmc=, libmesh=, event=y (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=y, libmesh=, event= (push) Blocked by required conditions
Tests and Coverage / Python 3.12 (omp=y, mpi=y, dagmc=, libmesh=y, event= (push) Blocked by required conditions
Tests and Coverage / coverage (push) Blocked by required conditions
Tests and Coverage / Check CI status (push) Blocked by required conditions
dockerhub-publish-develop / main (push) Waiting to run
dockerhub-publish-develop-dagmc-libmesh / main (push) Waiting to run
dockerhub-publish-develop-dagmc / main (push) Waiting to run
dockerhub-publish-develop-libmesh / main (push) Waiting to run
Co-authored-by: GuySten <guyste@post.bgu.ac.il>
This commit is contained in:
parent
04e4c6d094
commit
f3a8ba29fd
8 changed files with 93 additions and 46 deletions
|
|
@ -11,6 +11,7 @@ import openmc
|
|||
import openmc._xml as xml
|
||||
from .plots import add_plot_params
|
||||
from .checkvalue import check_type, check_less_than, check_greater_than, PathLike
|
||||
from .utility_funcs import set_xml_input_path
|
||||
|
||||
|
||||
class Geometry:
|
||||
|
|
@ -290,11 +291,12 @@ class Geometry:
|
|||
if isinstance(materials, (str, os.PathLike)):
|
||||
materials = openmc.Materials.from_xml(materials)
|
||||
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
|
||||
return cls.from_xml_element(root, materials)
|
||||
return cls.from_xml_element(root, materials)
|
||||
|
||||
def find(self, point) -> list:
|
||||
"""Find cells/universes/lattices which contain a given point
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import openmc.data
|
|||
import openmc.checkvalue as cv
|
||||
from ._xml import clean_indentation, get_elem_list, get_text
|
||||
from .mixin import IDManagerMixin
|
||||
from .utility_funcs import input_path
|
||||
from .utility_funcs import input_path, set_xml_input_path
|
||||
from . import waste
|
||||
from openmc.checkvalue import PathLike
|
||||
from openmc.stats import Univariate, Discrete, Mixture, Tabular
|
||||
|
|
@ -2286,11 +2286,12 @@ class Materials(cv.CheckedList):
|
|||
Materials collection
|
||||
|
||||
"""
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
|
||||
return cls.from_xml_element(root)
|
||||
return cls.from_xml_element(root)
|
||||
|
||||
|
||||
def deplete(
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from openmc.checkvalue import (check_type, check_value, check_greater_than,
|
|||
check_length, PathLike)
|
||||
from openmc.exceptions import InvalidIDError
|
||||
from openmc.plots import add_plot_params, _BASIS_INDICES, id_map_to_rgb
|
||||
from openmc.utility_funcs import change_directory
|
||||
from openmc.utility_funcs import change_directory, set_xml_input_path
|
||||
|
||||
|
||||
# Protocol for a function that is passed to search_keff
|
||||
|
|
@ -384,30 +384,31 @@ class Model:
|
|||
path : PathLike
|
||||
Path to model.xml file
|
||||
"""
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
|
||||
model = cls()
|
||||
model = cls()
|
||||
|
||||
desc_elem = root.find('description')
|
||||
if desc_elem is not None and desc_elem.text:
|
||||
model.description = desc_elem.text
|
||||
desc_elem = root.find('description')
|
||||
if desc_elem is not None and desc_elem.text:
|
||||
model.description = desc_elem.text
|
||||
|
||||
meshes = {}
|
||||
model.settings = openmc.Settings.from_xml_element(
|
||||
root.find('settings'), meshes)
|
||||
model.materials = openmc.Materials.from_xml_element(
|
||||
root.find('materials'))
|
||||
model.geometry = openmc.Geometry.from_xml_element(
|
||||
root.find('geometry'), model.materials)
|
||||
meshes = {}
|
||||
model.settings = openmc.Settings.from_xml_element(
|
||||
root.find('settings'), meshes)
|
||||
model.materials = openmc.Materials.from_xml_element(
|
||||
root.find('materials'))
|
||||
model.geometry = openmc.Geometry.from_xml_element(
|
||||
root.find('geometry'), model.materials)
|
||||
|
||||
if root.find('tallies') is not None:
|
||||
model.tallies = openmc.Tallies.from_xml_element(
|
||||
root.find('tallies'), meshes)
|
||||
if root.find('tallies') is not None:
|
||||
model.tallies = openmc.Tallies.from_xml_element(
|
||||
root.find('tallies'), meshes)
|
||||
|
||||
if root.find('plots') is not None:
|
||||
model.plots = openmc.Plots.from_xml_element(root.find('plots'))
|
||||
if root.find('plots') is not None:
|
||||
model.plots = openmc.Plots.from_xml_element(root.find('plots'))
|
||||
|
||||
return model
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from __future__ import annotations
|
||||
from collections.abc import Iterable, Mapping, Sequence
|
||||
from numbers import Integral, Real
|
||||
from pathlib import Path
|
||||
|
|
@ -14,6 +15,7 @@ from openmc.checkvalue import PathLike
|
|||
|
||||
from ._xml import clean_indentation, get_elem_list, get_text
|
||||
from .mixin import IDManagerMixin
|
||||
from .utility_funcs import set_xml_input_path
|
||||
|
||||
_BASES = {'xy', 'xz', 'yz'}
|
||||
|
||||
|
|
@ -2190,7 +2192,7 @@ class Plots(cv.CheckedList):
|
|||
tree.write(str(p), xml_declaration=True, encoding='utf-8')
|
||||
|
||||
@classmethod
|
||||
def from_xml_element(cls, elem):
|
||||
def from_xml_element(cls, elem) -> Plots:
|
||||
"""Generate plots collection from XML file
|
||||
|
||||
Parameters
|
||||
|
|
@ -2224,7 +2226,7 @@ class Plots(cv.CheckedList):
|
|||
return plots
|
||||
|
||||
@classmethod
|
||||
def from_xml(cls, path='plots.xml'):
|
||||
def from_xml(cls, path: PathLike = 'plots.xml') -> Plots:
|
||||
"""Generate plots collection from XML file
|
||||
|
||||
Parameters
|
||||
|
|
@ -2238,7 +2240,8 @@ class Plots(cv.CheckedList):
|
|||
Plots collection
|
||||
|
||||
"""
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
return cls.from_xml_element(root)
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
return cls.from_xml_element(root)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from openmc.stats.multivariate import MeshSpatial
|
|||
from ._xml import clean_indentation, get_elem_list, get_text
|
||||
from .mesh import _read_meshes, RegularMesh, MeshBase
|
||||
from .source import SourceBase, MeshSource, IndependentSource
|
||||
from .utility_funcs import input_path
|
||||
from .utility_funcs import input_path, set_xml_input_path
|
||||
from .volume import VolumeCalculation
|
||||
from .weight_windows import WeightWindows, WeightWindowGenerator, WeightWindowsList
|
||||
|
||||
|
|
@ -2775,8 +2775,9 @@ class Settings:
|
|||
Settings object
|
||||
|
||||
"""
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
meshes = _read_meshes(root)
|
||||
return cls.from_xml_element(root, meshes)
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
meshes = _read_meshes(root)
|
||||
return cls.from_xml_element(root, meshes)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ from openmc.arithmetic import (
|
|||
from ._sparse_compat import lil_array
|
||||
from ._xml import clean_indentation, get_elem_list, get_text
|
||||
from .mixin import IDManagerMixin
|
||||
from .utility_funcs import set_xml_input_path
|
||||
from .mesh import MeshBase
|
||||
|
||||
|
||||
|
|
@ -3938,7 +3939,8 @@ class Tallies(cv.CheckedList):
|
|||
Tallies object
|
||||
|
||||
"""
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
return cls.from_xml_element(root)
|
||||
with set_xml_input_path(path):
|
||||
parser = ET.XMLParser(huge_tree=True)
|
||||
tree = ET.parse(path, parser=parser)
|
||||
root = tree.getroot()
|
||||
return cls.from_xml_element(root)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from contextlib import contextmanager
|
||||
from contextvars import ContextVar
|
||||
import os
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
|
@ -9,6 +10,19 @@ import openmc
|
|||
from .checkvalue import PathLike
|
||||
|
||||
|
||||
_XML_INPUT_PATH = ContextVar('_XML_INPUT_PATH', default=None)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def set_xml_input_path(path: PathLike):
|
||||
"""Set the containing XML directory for resolving input paths."""
|
||||
token = _XML_INPUT_PATH.set(Path(path).resolve().parent)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_XML_INPUT_PATH.reset(token)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def change_directory(working_dir: PathLike | None = None, *, tmpdir: bool = False):
|
||||
"""Context manager for executing in a provided working directory
|
||||
|
|
@ -56,7 +70,11 @@ def input_path(filename: PathLike) -> Path:
|
|||
|
||||
"""
|
||||
if openmc.config['resolve_paths']:
|
||||
return Path(filename).resolve()
|
||||
path = Path(filename)
|
||||
xml_dir = _XML_INPUT_PATH.get()
|
||||
if xml_dir is not None and not path.is_absolute():
|
||||
path = xml_dir / path
|
||||
return path.resolve()
|
||||
else:
|
||||
return Path(filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,25 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
assert test_model.is_initialized is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize('resolve_paths', [True, False])
|
||||
def test_xml_input_paths(tmp_path, monkeypatch, resolve_paths):
|
||||
"""Input paths are interpreted relative to the containing XML file."""
|
||||
with openmc.config.patch('resolve_paths', False):
|
||||
univ = openmc.DAGMCUniverse('dagmc.h5m')
|
||||
model = openmc.Model(geometry=openmc.Geometry(univ))
|
||||
model_dir = tmp_path / 'model'
|
||||
model.export_to_model_xml(model_dir)
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
with openmc.config.patch('resolve_paths', resolve_paths):
|
||||
openmc.reset_auto_ids()
|
||||
loaded_model = openmc.Model.from_model_xml('model/model.xml')
|
||||
expected = (model_dir / 'dagmc.h5m').resolve()
|
||||
if not resolve_paths:
|
||||
expected = Path('dagmc.h5m')
|
||||
assert loaded_model.geometry.root_universe.filename == expected
|
||||
|
||||
|
||||
def test_init_finalize_lib(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
# We are going to init and then make sure data is loaded
|
||||
mats, geom, settings, tals, plots, _, _ = pin_model_attributes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue