diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 4bbc96cf8..27a9d3643 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -1295,6 +1295,13 @@ Each ``material`` element can have the following attributes or sub-elements: *Default*: "" + :temperature: + + An element with no attributes which is used to set the temperature of the + material. This element accepts a maximum 6-character string that indicates + the default temperature rounded to the nearest integer in units of Kelvin, + e.g. "294K". + :density: An element with attributes/sub-elements called ``value`` and ``units``. The ``value`` attribute is the numeric value of the density while the ``units`` @@ -1315,17 +1322,16 @@ Each ``material`` element can have the following attributes or sub-elements: ``nuclide``, ``element``, or ``sab`` quantity. :nuclide: - An element with attributes/sub-elements called ``name``, ``xs``, and ``ao`` + An element with attributes/sub-elements called ``name``, and ``ao`` or ``wo``. The ``name`` attribute is the name of the cross-section for a - desired nuclide while the ``xs`` attribute is the cross-section - identifier. Finally, the ``ao`` and ``wo`` attributes specify the atom or + desired nuclide. Finally, the ``ao`` and ``wo`` attributes specify the atom or weight percent of that nuclide within the material, respectively. One example would be as follows: .. code-block:: xml - - + + .. note:: If one nuclide is specified in atom percent, all others must also be given in atom percent. The same applies for weight percentages. @@ -1349,11 +1355,10 @@ Each ``material`` element can have the following attributes or sub-elements: Specifies that a natural element is present in the material. The natural element is split up into individual isotopes based on `IUPAC Isotopic Compositions of the Elements 2009`_. This element has - attributes/sub-elements called ``name``, ``xs``, and ``ao``. The ``name`` - attribute is the atomic symbol of the element while the ``xs`` attribute is - the cross-section identifier. Finally, the ``ao`` attribute specifies the - atom percent of the element within the material, respectively. One example - would be as follows: + attributes/sub-elements called ``name``, and ``ao``. The ``name`` + attribute is the atomic symbol of the element. Finally, the ``ao`` + attribute specifies the atom percent of the element within the material, + respectively. One example would be as follows: .. code-block:: xml @@ -1383,10 +1388,9 @@ Each ``material`` element can have the following attributes or sub-elements: multi-group :ref:`energy_mode`. :sab: - Associates an S(a,b) table with the material. This element has - attributes/sub-elements called ``name`` and ``xs``. The ``name`` attribute - is the name of the S(a,b) table that should be associated with the material, - and ``xs`` is the cross-section identifier for the table. + Associates an S(a,b) table with the material. This element has one + attribute/sub-element called ``name``. The ``name`` attribute + is the name of the S(a,b) table that should be associated with the material. *Default*: None @@ -1397,14 +1401,13 @@ Each ``material`` element can have the following attributes or sub-elements: recognizes that some multi-group libraries may be providing material specific macroscopic cross sections instead of always providing nuclide specific data like in the continuous-energy case. To that end, the - macroscopic element has attributes/sub-elements called ``name``, and ``xs``. + macroscopic element has one attribute/sub-element called ``name``. The ``name`` attribute is the name of the cross-section for a - desired nuclide while the ``xs`` attribute is the cross-section - identifier. One example would be as follows: + desired nuclide. One example would be as follows: .. code-block:: xml - + .. note:: This element is only used in the multi-group :ref:`energy_mode`. @@ -1413,15 +1416,16 @@ Each ``material`` element can have the following attributes or sub-elements: .. _IUPAC Isotopic Compositions of the Elements 2009: http://pac.iupac.org/publications/pac/pdf/2011/pdf/8302x0397.pdf -```` Element +```` Element ------------------------ -In some circumstances, the cross-section identifier may be the same for many or -all nuclides in a given problem. In this case, rather than specifying the -``xs=...`` attribute on every nuclide, a ```` element can be used to -set the default cross-section identifier for any nuclide without an identifier -explicitly listed. This element has no attributes and accepts a 3-letter string -that indicates the default cross-section identifier, e.g. "70c". +In some circumstances, the temperature may be the same for many or +all materials in a given problem. In this case, rather than specifying the +```` element on every material, a ```` +element can be used to set the default material temperature for any material +without an explicitly provided temperature. This element has no attributes and +accepts a maximum 6-character string that indicates the default temperature +rounded to the nearest integer in units of Kelvin, e.g. "294K". *Default*: None diff --git a/examples/python/basic/build-xml.py b/examples/python/basic/build-xml.py index 1bfe50b2e..802debf8c 100644 --- a/examples/python/basic/build-xml.py +++ b/examples/python/basic/build-xml.py @@ -25,7 +25,7 @@ moderator = openmc.Material(material_id=41, name='moderator') moderator.set_density('g/cc', 1.0) moderator.add_nuclide(h1, 2.) moderator.add_nuclide(o16, 1.) -moderator.add_s_alpha_beta('c_H_in_H2O', '71t') +moderator.add_s_alpha_beta('c_H_in_H2O') fuel = openmc.Material(material_id=40, name='fuel') fuel.set_density('g/cc', 4.5) @@ -33,7 +33,7 @@ fuel.add_nuclide(u235, 1.) # Instantiate a Materials collection and export to XML materials_file = openmc.Materials([moderator, fuel]) -materials_file.default_xs = '71c' +materials_file.default_temperature = '294K' materials_file.export_to_xml() diff --git a/openmc/element.py b/openmc/element.py index ada5726b4..1b1680614 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -19,38 +19,28 @@ class Element(object): ---------- name : str Chemical symbol of the element, e.g. Pu - xs : str - Cross section identifier, e.g. 71c Attributes ---------- name : str Chemical symbol of the element, e.g. Pu - xs : str - Cross section identifier, e.g. 71c scattering : {'data', 'iso-in-lab', None} The type of angular scattering distribution to use """ - def __init__(self, name='', xs=None): + def __init__(self, name=''): # Initialize class attributes self._name = '' - self._xs = None self._scattering = None # Set class attributes self.name = name - if xs is not None: - self.xs = xs - def __eq__(self, other): if isinstance(other, Element): if self.name != other.name: return False - elif self.xs != other.xs: - return False else: return True elif isinstance(other, basestring) and other == self.name: @@ -72,17 +62,12 @@ class Element(object): def __repr__(self): string = 'Element - {0}\n'.format(self._name) - string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs) if self.scattering is not None: string += '{0: <16}{1}{2}\n'.format('\tscattering', '=\t', self.scattering) return string - @property - def xs(self): - return self._xs - @property def name(self): return self._name @@ -91,11 +76,6 @@ class Element(object): def scattering(self): return self._scattering - @xs.setter - def xs(self, xs): - check_type('cross section identifier', xs, basestring) - self._xs = xs - @name.setter def name(self, name): check_type('element name', name, basestring) @@ -127,6 +107,6 @@ class Element(object): isotopes = [] for isotope, abundance in sorted(NATURAL_ABUNDANCE.items()): if re.match(r'{}\d+'.format(self.name), isotope): - nuc = openmc.Nuclide(isotope, self.xs) + nuc = openmc.Nuclide(isotope) isotopes.append((nuc, abundance)) return isotopes diff --git a/openmc/macroscopic.py b/openmc/macroscopic.py index 9f55998e3..e47baf9fb 100644 --- a/openmc/macroscopic.py +++ b/openmc/macroscopic.py @@ -13,29 +13,21 @@ class Macroscopic(object): ---------- name : str Name of the macroscopic data, e.g. UO2 - xs : str - Cross section identifier, e.g. 71c Attributes ---------- name : str Name of the nuclide, e.g. UO2 - xs : str - Cross section identifier, e.g. 71c """ - def __init__(self, name='', xs=None): + def __init__(self, name=''): # Initialize class attributes self._name = '' - self._xs = None # Set the Macroscopic class attributes self.name = name - if xs is not None: - self.xs = xs - def __eq__(self, other): if isinstance(other, Macroscopic): if self.name != other.name: @@ -57,23 +49,13 @@ class Macroscopic(object): def __repr__(self): string = 'Nuclide - {0}\n'.format(self._name) - string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self._xs) return string @property def name(self): return self._name - @property - def xs(self): - return self._xs - @name.setter def name(self, name): check_type('name', name, basestring) self._name = name - - @xs.setter - def xs(self, xs): - check_type('cross-section identifier', xs, basestring) - self._xs = xs diff --git a/openmc/material.py b/openmc/material.py index 40dfc1a9b..d30487e2f 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -41,11 +41,19 @@ class Material(object): name : str, optional Name of the material. If not specified, the name will be the empty string. + temperature : str, optional + The temperature identifier applied to this material. The units are + in Kelvin and the temperature rounded to the nearest integer. + For example, a tempreature of 293.6K would be provided as '294K' Attributes ---------- id : int Unique identifier for the material + temperature : str + The temperature identifier applied to this material. The units are + in Kelvin and the temperature rounded to the nearest integer. + For example, a tempreature of 293.6K would be provided as '294K' density : float Density of the material (units defined separately) density_units : str @@ -63,10 +71,11 @@ class Material(object): """ - def __init__(self, material_id=None, name=''): + def __init__(self, material_id=None, name='', temperature=None): # Initialize class attributes self.id = material_id self.name = name + self.temperature = temperature self._density = None self._density_units = '' @@ -133,7 +142,7 @@ class Material(object): string += '{0: <16}\n'.format('\tNuclides') for nuclide, percent, percent_type in self._nuclides: - string += '{0: <16}'.format('\t{0.name}.{0.xs}'.format(nuclide)) + string += '{0: <16}'.format('\t{0.name}'.format(nuclide)) string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type) if self._macroscopic is not None: @@ -143,7 +152,7 @@ class Material(object): string += '{0: <16}\n'.format('\tElements') for element, percent, percent_type in self._elements: - string += '{0: <16}'.format('\t{0.name}.{0.xs}'.format(element)) + string += '{0: <16}'.format('\t{0.name}'.format(element)) string += '=\t{0: <12} [{1}]\n'.format(percent, percent_type) return string @@ -156,6 +165,10 @@ class Material(object): def name(self): return self._name + @property + def temperature(self): + return self._temperature + @property def density(self): return self._density @@ -201,6 +214,15 @@ class Material(object): else: self._name = '' + @temperature.setter + def temperature(self, temperature): + if temperature is not None: + cv.check_type('Temperature for Material ID="{0}"'.format(self._id), + temperature, basestring) + self._temperature = temperature + else: + self._temperature = '' + def set_density(self, units, density=None): """Set the density of the material @@ -458,15 +480,13 @@ class Material(object): if element == elm: self._nuclides.remove(elm) - def add_s_alpha_beta(self, name, xs): + def add_s_alpha_beta(self, name): r"""Add an :math:`S(\alpha,\beta)` table to the material Parameters ---------- name : str Name of the :math:`S(\alpha,\beta)` table - xs : str - Cross section identifier, e.g. '71t' """ @@ -480,18 +500,14 @@ class Material(object): 'non-string table name "{1}"'.format(self._id, name) raise ValueError(msg) - if not isinstance(xs, basestring): - msg = 'Unable to add an S(a,b) table to Material ID="{0}" with a ' \ - 'non-string cross-section identifier "{1}"'.format(self._id, xs) - raise ValueError(msg) - new_name = openmc.data.get_thermal_name(name) if new_name != name: msg = 'OpenMC S(a,b) tables follow the GND naming convention. ' \ 'Table "{}" is being renamed as "{}".'.format(name, new_name) warnings.warn(msg) - self._sab.append((new_name, xs)) + self._sab.append((new_name)) + def make_isotropic_in_lab(self): for nuclide, percent, percent_type in self._nuclides: @@ -554,9 +570,6 @@ class Material(object): else: xml_element.set("wo", str(nuclide[1])) - if nuclide[0].xs is not None: - xml_element.set("xs", nuclide[0].xs) - if not nuclide[0].scattering is None: xml_element.set("scattering", nuclide[0].scattering) @@ -581,9 +594,6 @@ class Material(object): else: xml_element.set("wo", str(element[1])) - if element[0].xs is not None: - xml_element.set("xs", element[0].xs) - if not element[0].scattering is None: xml_element.set("scattering", element[0].scattering) @@ -686,8 +696,7 @@ class Material(object): if len(self._sab) > 0: for sab in self._sab: subelement = ET.SubElement(element, "sab") - subelement.set("name", sab[0]) - subelement.set("xs", sab[1]) + subelement.set("name", sab) return element @@ -714,27 +723,29 @@ class Materials(cv.CheckedList): Attributes ---------- - default_xs : str - The default cross section identifier applied to a nuclide when none is - specified + default_temperature : str + The default temperature identifier applied to a material when none is + specified. The units are in Kelvin and the temperature rounded to the + nearest integer. For example, a tempreature of 293.6K would be + provided as '294K' """ def __init__(self, materials=None): super(Materials, self).__init__(Material, 'materials collection') - self._default_xs = None + self._default_temperature = None self._materials_file = ET.Element("materials") if materials is not None: self += materials @property - def default_xs(self): - return self._default_xs + def default_temperature(self): + return self._default_temperature - @default_xs.setter - def default_xs(self, xs): - cv.check_type('default xs', xs, basestring) - self._default_xs = xs + @default_temperature.setter + def default_temperature(self, temperature): + cv.check_type('default_temperature', temperature, basestring) + self._default_temperature = temperature def add_material(self, material): """Append material to collection @@ -817,9 +828,10 @@ class Materials(cv.CheckedList): material.make_isotropic_in_lab() def _create_material_subelements(self): - if self._default_xs is not None: - subelement = ET.SubElement(self._materials_file, "default_xs") - subelement.text = self._default_xs + if self._default_temperature is not None: + subelement = ET.SubElement(self._materials_file, + "default_temperature") + subelement.text = self._default_temperature for material in self: xml_element = material.get_material_xml() diff --git a/openmc/nuclide.py b/openmc/nuclide.py index 68f95beb9..186292a87 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -15,15 +15,11 @@ class Nuclide(object): ---------- name : str Name of the nuclide, e.g. U235 - xs : str - Cross section identifier, e.g. 71c Attributes ---------- name : str Name of the nuclide, e.g. U235 - xs : str - Cross section identifier, e.g. 71c zaid : int 1000*(atomic number) + mass number. As an example, the zaid of U235 would be 92235. @@ -32,25 +28,19 @@ class Nuclide(object): """ - def __init__(self, name='', xs=None): + def __init__(self, name=''): # Initialize class attributes self._name = '' - self._xs = None self._zaid = None self._scattering = None # Set the Material class attributes self.name = name - if xs is not None: - self.xs = xs - def __eq__(self, other): if isinstance(other, Nuclide): if self.name != other.name: return False - elif self.xs != other.xs: - return False else: return True elif isinstance(other, basestring) and other == self.name: @@ -72,7 +62,6 @@ class Nuclide(object): def __repr__(self): string = 'Nuclide - {0}\n'.format(self._name) - string += '{0: <16}{1}{2}\n'.format('\tXS', '=\t', self.xs) if self.zaid is not None: string += '{0: <16}{1}{2}\n'.format('\tZAID', '=\t', self.zaid) if self.scattering is not None: @@ -84,10 +73,6 @@ class Nuclide(object): def name(self): return self._name - @property - def xs(self): - return self._xs - @property def zaid(self): return self._zaid @@ -111,11 +96,6 @@ class Nuclide(object): '"{}" is being renamed as "{}".'.format(name, self._name) warnings.warn(msg) - @xs.setter - def xs(self, xs): - check_type('cross-section identifier', xs, basestring) - self._xs = xs - @zaid.setter def zaid(self, zaid): check_type('zaid', zaid, Integral) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index af6737de6..d827cfad1 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2129,6 +2129,7 @@ contains logical :: file_exists ! does materials.xml exist? logical :: sum_density ! density is taken to be sum of nuclide densities character(20) :: name ! name of isotope, e.g. 92235.03c + character(6) :: default_temperature ! Default temperature, e.g., '300K' character(MAX_WORD_LEN) :: units ! units on density character(MAX_LINE_LEN) :: filename ! absolute path to materials.xml character(MAX_LINE_LEN) :: temp_str ! temporary string when reading @@ -2162,6 +2163,13 @@ contains ! Parse materials.xml file call open_xmldoc(doc, filename) + ! Copy default temperature + if (check_for_node(doc, "default_temperature")) then + call get_node_value(doc, "default_temperature", default_temperature) + else + default_temperature = '' + end if + ! Get pointer to list of XML call get_node_list(doc, "material", node_mat_list) @@ -2200,6 +2208,11 @@ contains ! Copy material temperature if (check_for_node(node_mat, "temperature")) then call get_node_value(node_mat, "temperature", mat % temperature) + else if (default_temperature /= '') then + mat % temperature = default_temperature + else + call fatal_error("Must specify eithe a material temperature or a & + &default temperature") end if ! =======================================================================