diff --git a/openmc/geometry.py b/openmc/geometry.py index 889cb6b31c..b4f8046bd2 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -162,13 +162,13 @@ class Geometry: tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod - def from_xml(cls, path='geometry.xml', materials=None): - """Generate geometry from XML file + def from_xml_element(cls, elem, materials=None): + """Generate geometry from an XML element Parameters ---------- - path : str, optional - Path to geometry XML file + elem : xml.etree.ElementTree.Element + XML element materials : openmc.Materials or None Materials used to assign to cells. If None, an attempt is made to generate it from the materials.xml file. @@ -187,13 +187,10 @@ class Geometry: universes[univ_id] = univ return universes[univ_id] - tree = ET.parse(path) - root = tree.getroot() - # Get surfaces surfaces = {} periodic = {} - for surface in root.findall('surface'): + for surface in elem.findall('surface'): s = openmc.Surface.from_xml_element(surface) surfaces[s.id] = s @@ -207,15 +204,15 @@ class Geometry: surfaces[s1].periodic_surface = surfaces[s2] # Add any DAGMC universes - for elem in root.findall('dagmc_universe'): + for elem in elem.findall('dagmc_universe'): dag_univ = openmc.DAGMCUniverse.from_xml_element(elem) universes[dag_univ.id] = dag_univ # Dictionary that maps each universe to a list of cells/lattices that - # contain it (needed to determine which universe is the root) + # contain it (needed to determine which universe is the elem) child_of = defaultdict(list) - for elem in root.findall('lattice'): + for elem in elem.findall('lattice'): lat = openmc.RectLattice.from_xml_element(elem, get_universe) universes[lat.id] = lat if lat.outer is not None: @@ -223,7 +220,7 @@ class Geometry: for u in lat.universes.ravel(): child_of[u].append(lat) - for elem in root.findall('hex_lattice'): + for elem in elem.findall('hex_lattice'): lat = openmc.HexLattice.from_xml_element(elem, get_universe) universes[lat.id] = lat if lat.outer is not None: @@ -245,7 +242,7 @@ class Geometry: mats = {str(m.id): m for m in materials} mats['void'] = None - for elem in root.findall('cell'): + for elem in elem.findall('cell'): c = openmc.Cell.from_xml_element(elem, surfaces, mats, get_universe) if c.fill_type in ('universe', 'lattice'): child_of[c.fill].append(c) @@ -258,6 +255,29 @@ class Geometry: else: raise ValueError('Error determining root universe.') + @classmethod + def from_xml(cls, path='geometry.xml', materials=None): + """Generate geometry from XML file + + Parameters + ---------- + path : str, optional + Path to geometry XML file + materials : openmc.Materials or None + Materials used to assign to cells. If None, an attempt is made to + generate it from the materials.xml file. + + Returns + ------- + openmc.Geometry + Geometry object + + """ + 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 diff --git a/openmc/material.py b/openmc/material.py index 9e3951ccf4..c335968002 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1508,6 +1508,34 @@ class Materials(cv.CheckedList): errors='xmlcharrefreplace') as fh: self._write_xml(fh) + @classmethod + def from_xml_element(cls, elem): + """Generate materials collection from XML file + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.Materials + Materials collection + + """ + # Generate each material + materials = cls() + for material in elem.findall('material'): + materials.append(Material.from_xml_element(material)) + + # Check for cross sections settings + xs = elem.find('cross_sections') + if xs is not None: + materials.cross_sections = xs.text + + return materials + + @classmethod def from_xml(cls, path: PathLike = 'materials.xml'): """Generate materials collection from XML file @@ -1526,14 +1554,4 @@ class Materials(cv.CheckedList): tree = ET.parse(path) root = tree.getroot() - # Generate each material - materials = cls() - for material in root.findall('material'): - materials.append(Material.from_xml_element(material)) - - # Check for cross sections settings - xs = tree.find('cross_sections') - if xs is not None: - materials.cross_sections = xs.text - - return materials + return cls.from_xml_element(root) \ No newline at end of file diff --git a/openmc/model/model.py b/openmc/model/model.py index e3c4c4ae19..2193084c36 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -208,7 +208,42 @@ class Model: self._plots.append(plot) @classmethod - def from_xml(cls, geometry='geometry.xml', materials='materials.xml', + def from_xml(cls, separate_xmls=True, **kwargs): + if separate_xmls: + return cls.from_separate_xmls(**kwargs) + else: + return cls.from_model_xml(**kwargs) + + @classmethod + def from_model_xml(cls, path='model.xml'): + """Create model from single XML file + + Parameters + ---------- + path : str or Pathlike + Path to model.xml file + """ + tree = ET.parse(path) + root = tree.getroot() + + model = cls() + + model.settings = openmc.Settings.from_xml_element(root.find('settings')) + model.materials = openmc.Materials.from_xml_element(root.find('materials')) + model.geometry = \ + openmc.Geometry.from_xml_element(root.find('geometry'), model.materials) + + if tally_node := root.find('tallies'): + print(tally_node) + model.tallies = openmc.Tallies.from_xml_element(tally_node) + + if plots_node := root.find('plots'): + model.plots = openmc.Plots.from_xml_element(plots_node) + + return model + + @classmethod + def from_separate_xmls(cls, geometry='geometry.xml', materials='materials.xml', settings='settings.xml', tallies='tallies.xml', plots='plots.xml'): """Create model from existing XML files diff --git a/openmc/plots.py b/openmc/plots.py index 52dcf3fc13..badea2e586 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -941,6 +941,27 @@ class Plots(cv.CheckedList): tree = ET.ElementTree(self._plots_file) tree.write(str(p), xml_declaration=True, encoding='utf-8') + @classmethod + def from_xml_element(cls, elem): + """Generate plots collection from XML file + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.Plots + Plots collection + + """ + # Generate each plot + plots = cls() + for elem in elem.findall('plot'): + plots.append(Plot.from_xml_element(elem)) + return plots + @classmethod def from_xml(cls, path='plots.xml'): """Generate plots collection from XML file @@ -958,9 +979,6 @@ class Plots(cv.CheckedList): """ tree = ET.parse(path) root = tree.getroot() + return cls.from_xml_element(root) + - # Generate each plot - plots = cls() - for elem in root.findall('plot'): - plots.append(Plot.from_xml_element(elem)) - return plots diff --git a/openmc/settings.py b/openmc/settings.py index dd00413516..c2fca98f7d 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1595,7 +1595,7 @@ class Settings: clean_indentation(element) return element - + def export_to_xml(self, path: PathLike = 'settings.xml'): """Export simulation settings to an XML file. @@ -1617,6 +1617,71 @@ class Settings: tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') + @classmethod + def from_xml_element(cls, elem): + """Generate settings from XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.Settings + Settings object + + """ + settings = cls() + settings._eigenvalue_from_xml_element(elem) + settings._run_mode_from_xml_element(elem) + settings._particles_from_xml_element(elem) + settings._batches_from_xml_element(elem) + settings._inactive_from_xml_element(elem) + settings._max_lost_particles_from_xml_element(elem) + settings._rel_max_lost_particles_from_xml_element(elem) + settings._generations_per_batch_from_xml_element(elem) + settings._keff_trigger_from_xml_element(elem) + settings._source_from_xml_element(elem) + settings._volume_calcs_from_xml_element(elem) + settings._output_from_xml_element(elem) + settings._statepoint_from_xml_element(elem) + settings._sourcepoint_from_xml_element(elem) + settings._surf_source_read_from_xml_element(elem) + settings._surf_source_write_from_xml_element(elem) + settings._confidence_intervals_from_xml_element(elem) + settings._electron_treatment_from_xml_element(elem) + settings._energy_mode_from_xml_element(elem) + settings._max_order_from_xml_element(elem) + settings._photon_transport_from_xml_element(elem) + settings._ptables_from_xml_element(elem) + settings._seed_from_xml_element(elem) + settings._survival_biasing_from_xml_element(elem) + settings._cutoff_from_xml_element(elem) + settings._entropy_mesh_from_xml_element(elem) + settings._trigger_from_xml_element(elem) + settings._no_reduce_from_xml_element(elem) + settings._verbosity_from_xml_element(elem) + settings._tabular_legendre_from_xml_element(elem) + settings._temperature_from_xml_element(elem) + settings._trace_from_xml_element(elem) + settings._track_from_xml_element(elem) + settings._ufs_mesh_from_xml_element(elem) + settings._resonance_scattering_from_xml_element(elem) + settings._create_fission_neutrons_from_xml_element(elem) + settings._delayed_photon_scaling_from_xml_element(elem) + settings._event_based_from_xml_element(elem) + settings._max_particles_in_flight_from_xml_element(elem) + settings._material_cell_offsets_from_xml_element(elem) + settings._log_grid_bins_from_xml_element(elem) + settings._write_initial_source_from_xml_element(elem) + settings._weight_windows_from_xml_element(elem) + settings._max_splits_from_xml_element(elem) + settings._max_tracks_from_xml_element(elem) + + # TODO: Get volume calculations + return settings + @classmethod def from_xml(cls, path: PathLike = 'settings.xml'): """Generate settings from XML file @@ -1636,54 +1701,4 @@ class Settings: """ tree = ET.parse(path) root = tree.getroot() - - settings = cls() - settings._eigenvalue_from_xml_element(root) - settings._run_mode_from_xml_element(root) - settings._particles_from_xml_element(root) - settings._batches_from_xml_element(root) - settings._inactive_from_xml_element(root) - settings._max_lost_particles_from_xml_element(root) - settings._rel_max_lost_particles_from_xml_element(root) - settings._generations_per_batch_from_xml_element(root) - settings._keff_trigger_from_xml_element(root) - settings._source_from_xml_element(root) - settings._volume_calcs_from_xml_element(root) - settings._output_from_xml_element(root) - settings._statepoint_from_xml_element(root) - settings._sourcepoint_from_xml_element(root) - settings._surf_source_read_from_xml_element(root) - settings._surf_source_write_from_xml_element(root) - settings._confidence_intervals_from_xml_element(root) - settings._electron_treatment_from_xml_element(root) - settings._energy_mode_from_xml_element(root) - settings._max_order_from_xml_element(root) - settings._photon_transport_from_xml_element(root) - settings._ptables_from_xml_element(root) - settings._seed_from_xml_element(root) - settings._survival_biasing_from_xml_element(root) - settings._cutoff_from_xml_element(root) - settings._entropy_mesh_from_xml_element(root) - settings._trigger_from_xml_element(root) - settings._no_reduce_from_xml_element(root) - settings._verbosity_from_xml_element(root) - settings._tabular_legendre_from_xml_element(root) - settings._temperature_from_xml_element(root) - settings._trace_from_xml_element(root) - settings._track_from_xml_element(root) - settings._ufs_mesh_from_xml_element(root) - settings._resonance_scattering_from_xml_element(root) - settings._create_fission_neutrons_from_xml_element(root) - settings._delayed_photon_scaling_from_xml_element(root) - settings._event_based_from_xml_element(root) - settings._max_particles_in_flight_from_xml_element(root) - settings._material_cell_offsets_from_xml_element(root) - settings._log_grid_bins_from_xml_element(root) - settings._write_initial_source_from_xml_element(root) - settings._weight_windows_from_xml_element(root) - settings._max_splits_from_xml_element(root) - settings._max_tracks_from_xml_element(root) - - # TODO: Get volume calculations - - return settings + return cls.from_xml_element(root) diff --git a/openmc/tallies.py b/openmc/tallies.py index dfb0c98bfd..0355568ec0 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -3191,6 +3191,49 @@ class Tallies(cv.CheckedList): tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') + @classmethod + def from_xml_element(cls, elem): + """Generate tallies from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.Tallies + Tallies object + + """ + # Read mesh elements + meshes = {} + for elem in elem.findall('mesh'): + mesh = MeshBase.from_xml_element(elem) + meshes[mesh.id] = mesh + + # Read filter elements + filters = {} + for elem in elem.findall('filter'): + filter = openmc.Filter.from_xml_element(elem, meshes=meshes) + filters[filter.id] = filter + + # Read derivative elements + derivatives = {} + for elem in elem.findall('derivative'): + deriv = openmc.TallyDerivative.from_xml_element(elem) + derivatives[deriv.id] = deriv + + # Read tally elements + tallies = [] + for elem in elem.findall('tally'): + tally = openmc.Tally.from_xml_element( + elem, filters=filters, derivatives=derivatives + ) + tallies.append(tally) + + return cls(tallies) + @classmethod def from_xml(cls, path='tallies.xml'): """Generate tallies from XML file @@ -3208,31 +3251,4 @@ class Tallies(cv.CheckedList): """ tree = ET.parse(path) root = tree.getroot() - - # Read mesh elements - meshes = {} - for elem in root.findall('mesh'): - mesh = MeshBase.from_xml_element(elem) - meshes[mesh.id] = mesh - - # Read filter elements - filters = {} - for elem in root.findall('filter'): - filter = openmc.Filter.from_xml_element(elem, meshes=meshes) - filters[filter.id] = filter - - # Read derivative elements - derivatives = {} - for elem in root.findall('derivative'): - deriv = openmc.TallyDerivative.from_xml_element(elem) - derivatives[deriv.id] = deriv - - # Read tally elements - tallies = [] - for elem in root.findall('tally'): - tally = openmc.Tally.from_xml_element( - elem, filters=filters, derivatives=derivatives - ) - tallies.append(tally) - - return cls(tallies) + return cls.from_xml_element(root)