diff --git a/openmc/model/model.py b/openmc/model/model.py index c1ffafafd3f..1813f8ca72a 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -51,6 +51,8 @@ class Model: Tallies information plots : openmc.Plots, optional Plot information + description : str, optional + Description of the model Attributes ---------- @@ -64,6 +66,8 @@ class Model: Tallies information plots : openmc.Plots Plot information + description : str + Description of the model """ @@ -74,12 +78,15 @@ def __init__( settings: openmc.Settings | None = None, tallies: openmc.Tallies | None = None, plots: openmc.Plots | None = None, + description: str | None = None ): self.geometry = openmc.Geometry() if geometry is None else geometry self.materials = openmc.Materials() if materials is None else materials self.settings = openmc.Settings() if settings is None else settings self.tallies = openmc.Tallies() if tallies is None else tallies self.plots = openmc.Plots() if plots is None else plots + if description is not None: + self.description = description @property def geometry(self) -> openmc.Geometry: @@ -115,6 +122,24 @@ def settings(self, settings): check_type('settings', settings, openmc.Settings) self._settings = settings + @property + def description(self) -> str: + return self.settings.description + + @description.setter + def description(self, description: str): + cv.check_type('description', description, str) + self.settings.description = description + + @property + def description(self) -> str: + return self.settings.description + + @description.setter + def description(self, description: str): + check_type('description', description, str) + self.settings.description = description + @property def tallies(self) -> openmc.Tallies: return self._tallies diff --git a/openmc/settings.py b/openmc/settings.py index 8f8aedc93e8..7bb5fd509a9 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -342,6 +342,8 @@ class Settings: weight_windows_file: Pathlike Path to a weight window file to load during simulation initialization + description : str + Description of the model .. versionadded::0.14.0 write_initial_source : bool @@ -370,6 +372,7 @@ def __init__(self, **kwargs): self._confidence_intervals = None self._electron_treatment = None self._photon_transport = None + self._description = None self._plot_seed = None self._ptables = None self._uniform_source_sampling = None @@ -1255,6 +1258,15 @@ def source_rejection_fraction(self, source_rejection_fraction: float): cv.check_less_than('source_rejection_fraction', source_rejection_fraction, 1) self._source_rejection_fraction = source_rejection_fraction + @property + def description(self): + return self._description + + @description.setter + def description(self, description): + cv.check_type('description', description, str) + self._description = description + def _create_run_mode_subelement(self, root): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode.value @@ -1733,6 +1745,11 @@ def _create_source_rejection_fraction_subelement(self, root): element = ET.SubElement(root, "source_rejection_fraction") element.text = str(self._source_rejection_fraction) + def _create_description_subelement(self, root): + if self._description is not None: + subelement = ET.SubElement(root, "description") + subelement.text = self._description + def _eigenvalue_from_xml_element(self, root): elem = root.find('eigenvalue') if elem is not None: @@ -2171,6 +2188,11 @@ def _source_rejection_fraction_from_xml_element(self, root): if text is not None: self.source_rejection_fraction = float(text) + def _description_from_xml_element(self, root): + text = get_text(root, 'description') + if text is not None: + self.description = text + def to_xml_element(self, mesh_memo=None): """Create a 'settings' element to be written to an XML file. @@ -2241,6 +2263,7 @@ def to_xml_element(self, mesh_memo=None): self._create_random_ray_subelement(element, mesh_memo) self._create_use_decay_photons_subelement(element) self._create_source_rejection_fraction_subelement(element) + self._create_description_subelement(element) # Clean the indentation in the file to be user-readable clean_indentation(element) @@ -2352,6 +2375,7 @@ def from_xml_element(cls, elem, meshes=None): settings._random_ray_from_xml_element(elem, meshes) settings._use_decay_photons_from_xml_element(elem) settings._source_rejection_fraction_from_xml_element(elem) + settings._description_from_xml_element(elem) return settings diff --git a/tests/unit_tests/test_model_description.py b/tests/unit_tests/test_model_description.py new file mode 100644 index 00000000000..ec06f013422 --- /dev/null +++ b/tests/unit_tests/test_model_description.py @@ -0,0 +1,30 @@ +import openmc + +DESCRIPTION_TEXT = "This is a test model." + + +def test_model_description(): + """Test the description attribute on the Model class.""" + model = openmc.Model() + model.description = DESCRIPTION_TEXT + + # Check that the description is set on the underlying settings object + assert model.settings.description == DESCRIPTION_TEXT + + +def test_settings_description_xml(): + """Test the XML representation of the description in Settings.""" + settings = openmc.Settings() + settings.description = DESCRIPTION_TEXT + + # Generate XML element + elem = settings.to_xml_element() + + # Check for the presence and content of the description tag + desc_elem = elem.find('description') + assert desc_elem is not None + assert desc_elem.text == DESCRIPTION_TEXT + + # Test from_xml_element + new_settings = openmc.Settings.from_xml_element(elem) + assert new_settings.description == DESCRIPTION_TEXT