From 0c92b18a1e174f84aaa9c37b821a4752d253c8fd Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 3 Sep 2016 11:19:19 -0400 Subject: [PATCH 01/82] Updating the mgxs library format manual as a starting point --- docs/source/io_formats/mgxs_library.rst | 385 +++++++----------------- 1 file changed, 109 insertions(+), 276 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index b6708a88db..0313369d92 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -8,19 +8,17 @@ OpenMC can be run in continuous-energy mode or multi-group mode, provided the nuclear data is available. In continuous-energy mode, the ``cross_sections.xml`` file contains necessary meta-data for each data set, including the name and a file system location where the complete library -can be found. In multi-group mode, this ``mgxs.xml`` file contains -this same meta-data describing the nuclide or material, but also contains the -group-wise nuclear data. This portion of the manual describes the format of -the multi-group data library required to be used in the ``mgxs.xml`` -file. +can be found. In multi-group mode, the multi-group meta-data and the +nuclear data itself is contained within an ``mgxs.h5``. This portion of +the manual describes the format of the multi-group data library required +to be used in the ``mgxs.h5`` file. -Similar to the other input file types, the multi-group library is provided in -the XML_ format. This library must provide some meta-data about the library -itself (such as the number of groups and the group structure, etc.) as well as -the actual cross section data itself for each of the necessary nuclides or -materials. +The multi-group library is provided in the HDF5_ format. This library must +provide some meta-data about the library itself (such as the number of +groups and the group structure, etc.) as well as the actual cross section +data itself for each of the necessary nuclides or materials. -.. _XML: http://www.w3.org/XML/ +.. _HDF5: http://www.hdfgroup.org/HDF5/ .. _mgxs_lib_spec: @@ -28,277 +26,112 @@ materials. MGXS Library Specification -------------------------- -The multi-group library meta-data is contained within the groups_, -group_structure_, and inverse_velocities_ elements. -The actual multi-group data itself is contained within the xsdata_ element. +**/** -.. _groups: +:Attributes: - **groups** (*int*) -- Number of energy groups + - **group structure** (*double[]*) -- Monotonically increasing + list of group boundaries, in units of MeV. The length of this + array should be the number of groups plus 1. + - **inverse velocities** (*double[]*) -- Average inverse velocitiy + for each of the groups in the library. This is an optional + attribute. -```` Element --------------------- +**//** -The ```` element has no attributes and simply provides the number of -energy groups contained within the library. +The data within contains the temperature-dependent multi-group +data for the nuclide or material that it represents. - *Default*: None, this must be provided. +:Attributes: - **awr** (*double*) -- The atomic weight ratio (optional, i.e. it + is not meaningful for material-wise data) + - **fissionable** (*int*) -- Whether the dataset is fissionable + (1) or not (0). + - **representation** (*char[]*) -- The method used to generate and + represent the multi-group cross sections. That is, whether they + were generated with scalar flux weighting (or reduced to a + similar representation) and thus are angle-independent, or if the + data was generated with angular dependent fluxes and thus the + data is angle-dependent. Valid values are either "isotropic" or + "angle". + - **num-azimuthal** (*int*) -- Number of equal width angular bins + that the azimuthal angular domain is subdivided if the + `representation` attribute is "angle". This parameter is + ignored otherwise. + - **num-polar** (*int*) -- Number of equal width angular bins + that the polar angular domain is subdivided if the + `representation` attribute is "angle". This parameter is + ignored otherwise. + - **scatter-type** (*char[]*) -- The representation of the + scattering angular distribution. The options are either + "legendre", "histogram", or "tabular". + - **order** (*int*) -- Either the Legendre order, number of bins, + or number of points (depending on the value of `scatter-type`) + used to describe the angular distribution associated with each group-to-group transfer probability. -.. _group_structure: +**//kTs/** -```` Element ------------------------------ +:Datasets: - **K** (*double*) -- kT values (in MeV) for each Temperature + TTT (in Kelvin), rounded to the nearest integer -The ```` element has no attributes and should be provided as a -monotonically increasing list of bounding energies, in MeV, for a number of -groups. To provide proper energy boundaries, the length of the data within the -```` element should be one more than the number of groups in -the problem. For example, a two-group problem could be specified as: +**//K/** -.. code-block:: xml - - 0.0 0.625E-6 20.0 - -*Default*: None, this must be provided. - -.. _inverse_velocities: - -```` Element --------------------------------- - -The ```` element optionally indicates the average -inverse velocity corresponding to each of the groups in the problem. -This element should therefore be an array with a length which matches the -number of groups set in the groups_ element. - -*Default*: Should this be needed by the presence of an ``inverse-velocity`` -score in the ``tallies.xml`` file and not provided in this element, OpenMC -will simply convert the group mid-point energy to an inverse of the velocity -and use this information for tallying. - -.. _xsdata: - -```` Element --------------------- - -The ```` element contains the nuclide or material-specific meta-data as -well as the actual cross section data. The following are the -attributes/sub-elements required to describe the meta-data: - - :name: - The name of the microscopic or macroscopic data set. An extension to the - name must be provided (e.g., the ``.300K`` in ``UO2.300K``). The name and - extension together must be twelve or less characters in length. This - extension must follow a period and be five characters or less in length. - similar to the equivalent in the continuous-energy ``cross_sections.xml`` - file, is used to denote variants of the particular nuclide or material of - interest (i.e. the ``UO2`` data in this example could have been generated - at a temperature of 300K). - - *Default*: None, this must be provided. - - :alias: - An alternative name to use for the microscopic or macroscopic data set. - - *Default*: If no alias is provided, it will adopt the value of ``name``. - - :kT: - The temperature times Boltzmann's constant (in units of MeV) at which the - data was generated. - - *Default*: Room temperature, 2.53E-8 MeV - - :fissionable: - This element states whether or not the data in question is fissionable. - Accepted values are "true" or "false". - - *Default*: None, this element must be provided. - - :representation: - This element provides the method used to generate and represent the - multi-group cross sections. That is, whether they were generated with - scalar flux weighting (or reduced to an equivalent representation) - and thus are angle-independent, or if the data was generated with angular - dependent fluxes and thus the data is angle-dependent. The options are - either "isotropic" or "angle". - - *Default*: "isotropic" - - :num_azimuthal: - This element provides the number of equal width angular bins that the - azimuthal angular domain is subdivided in the case of angle-dependent - cross sections (i.e., "angle" is passed to the ``representation`` element). - Note that these bins are equal in azimuthal angle widths, not equal in the - cosine of the azimuthal angle widths. - - *Default*: If ``representation`` is "angle", this must be provided. This - parameter is not used for other ``representation`` types. - - :num_polar: - This element provides the number of equal width angular bins that the - polar angular domain is subdivided in the case of angle-dependent - cross sections (i.e., "angle" is passed to the ``representation`` element). - Note that these bins are equal in polar angle widths, not equal in the - cosine of the polar angle widths. - - - *Default*: If ``representation`` is "angle", this must be provided. This - parameter is not used for other ``representation`` types. - - :scatt_type: - This element provides the representation of the angular distribution - associated with each group-to-group transfer probability. The options are - either "legendre", "histogram", or "tabular". - The "legendre" option means the angular distribution has been - expanded via Legendre polynomials of the order provided in the "order" - element. - The "histogram" option means the angular distribution is provided in - an equi-width histogram format with a number of bins as provided in the - "order" element. This is useful when the angular distribution was - obtained from a Monte Carlo tally and thus is natively in the histogram - format. - The "tabular" option means the angular distribution is provided in an - equi-spaced point-wise representation. - - *Default*: "legendre" - - :order: - This element provides either the Legendre order, number of bins, or number - of points used to describe the angular distribution associated with each - group-to-group transfer probability. The specific meaning of this bin - depends upon the value of ``scatt_type`` as discussed above. - - *Default*: None, this element must be provided. - - :tabular_legendre: - This optional element is used to set how the Legendre scattering kernel, if - provided via the ``scatt_type`` element above, is represented and thus used - during the scattering process. Specifically, the options are to either - convert the Legendre expansion to a tabular representation or leave it as - a set of Legendre coefficients. Converting to a tabular representation - will cost memory but can allow for a decrease in runtime compared to - leaving as a set of Legendre coefficients. This element has the following - attributes/sub-elements: - - :enable: - This attribute/sub-element denotes whether or not the conversion to the - tabular format should be performed or not. A value of "true" means - the conversion should be performed, "false" means it should not. - - *Default*: "true" - - :num_points: - If the conversion is to take place the number of tabular points is - required. This attribute/sub-element allows the user to set the desired - number of points. - - *Default*: 33 - - The following attributes/sub-elements are the cross section values to - be used during the transport process. - - :total: - This element requires the group-wise total cross section ordered by - increasing group index (i.e., fast to thermal). If ``representation`` is - "isotropic", then the length of this list should equal the number of - groups described in the ``groups`` element. If ``representation`` is - "angle", then the length of this list should equal the number of groups - times the number of azimuthal angles times the number of polar angles, - with the inner-dimension being groups, intermediate-dimension being - azimuthal angles and outer-dimension being the polar angles. - - *Default*: If not provided, it will be determined by summing the - absorption and scattering cross sections. - - :absorption: - This element requires the group-wise absorption cross section ordered by - increasing group index (i.e., fast to thermal). If ``representation`` is - "isotropic", then the length of this list should equal the number of - groups described in the ``groups`` element. If ``representation`` is - "angle", then the length of this list should equal the number of groups - times the number of azimuthal angles times the number of polar angles, - with the inner-dimension being groups, intermediate-dimension being - azimuthal angles and outer-dimension being the polar angles. - - *Default*: None, this must be provided. - - :scatter: - This element requires the scattering moment matrices presented with the - columns representing incoming group and rows representing the outgoing - group. That is, down-scatter will be above the diagonal of the resultant - matrix. This matrix is repeated for every Legendre order (in order of - increasing orders) if ``scatt_type`` is "legendre"; otherwise, this - matrix is repeated for every bin of the histogram or tabular - representation. Finally, if ``representation`` is "angle", the above - is repeated for every azimuthal angle and every polar angle, in that - order. - - *Default*: None, this must be provided. - - :multiplicity: - This element provides the ratio of neutrons produced in scattering - collisions to the neutrons which undergo scattering collisions; that is, - the multiplicity provides the code with a scaling factor to account for - neutrons being produced in (n,xn) reactions. This information is assumed - isotropic and therefore does not need to be repeated for every Legendre - moment or histogram/tabular bin. This matrix follows the same arrangement - as described for the ``scatter`` element, with the exception of the - data needed to provide the scattering type information. - - *Default*: Multiplicities of 1.0 are assumed (i.e., (n,xn) reactions are - neglected). - - The following fission-specific data are only needed should ``fissionable`` - be "true". - - :fission: - This element requires the group-wise fission cross section ordered by - increasing group index (i.e., fast to thermal). If ``representation`` is - "isotropic", then the length of this list should equal the number of - groups described in the ``groups`` element. If ``representation`` is - "angle", then the length of this list should equal the number of groups - times the number of azimuthal angles times the number of polar angles, - with the inner-dimension being groups, intermediate-dimension being - azimuthal angles and outer-dimension being the polar angles. - - *Default*: None, this is required only if fission tallies are - requested and the material is fissionable. - - :kappa_fission: - This element requires the group-wise kappa-fission cross section ordered by - increasing group index (i.e., fast to thermal). If ``representation`` is - "isotropic", then the length of this list should equal the number of - groups described in the ``groups`` element. If ``representation`` is - "angle", then the length of this list should equal the number of groups - times the number of azimuthal angles times the number of polar angles, - with the inner-dimension being groups, intermediate-dimension being - azimuthal angles and outer-dimension being the polar angles. - - *Default*: None, this is required only if kappa_fission tallies are - requested and the material is fissionable. - - :chi: - This element requires the group-wise fission spectra ordered by - increasing group index (i.e., fast to thermal). This element should be - used if making the common approximation that the fission spectra does - not depend on incoming energy. If the user does not wish to make this - approximation, then this should not be provided and this information - included in the ``nu_fission`` element instead. If ``representation`` is - "isotropic", then the length of this list should equal the number of - groups described in the ``groups`` element. If ``representation`` is - "angle", then the length of this list should equal the number of groups - times the number of azimuthal angles times the number of polar angles, - with the inner-dimension being groups, intermediate-dimension being - azimuthal angles and outer-dimension being the polar angles. - - *Default*: None, either this element is provided or ``nu_fission`` is - provided in fission matrix form, or the material is not fissionable. - - :nu_fission: - This element provides either the group-wise fission production cross - section vector (i.e., if ``chi`` is provided), or is the group-wise fission - production matrix. If providing the vector, it should be ordered the same - as the ``fission`` data. If providing the matrix, it should be ordered - the same as the ``multiplicity`` matrix. - - *Default*: None, either this element must be provided if the material - is fissionable. +Temperature-dependent data, provided for temperature K. +:Datasets: - **total** (*double[]* or *double[][][]*) -- Total cross section. + This is a 1-D vector if `representation` is "isotropic", or a 3-D + vector if `representation` is "angle" with dimensions of + [groups, azimuthal, polar]. + - **absorption** (*double[]* or *double[][][]*) -- Absorption + cross section. + This is a 1-D vector if `representation` is "isotropic", or a 3-D + vector if `representation` is "angle" with dimensions of + [groups, azimuthal, polar]. + - **scatter matrix** (*double[][][]* or *double[][][][][]*) -- + Scattering moment matrices. This dataset requires the scattering + moment matrices presented with the columns representing incoming + group and rows representing the outgoing group. That is, + down-scatter will be above the diagonal of the resultant matrix. + This matrix is repeated for every Legendre order (in order of + increasing orders) if `scatter-type` is "legendre"; otherwise, this + matrix is repeated for every bin of the histogram or tabular + representation. Finally, if ``representation`` is "angle", the + above is repeated for every azimuthal angle and every polar angle, + in that order. + - **multiplicity matrix** (*double[][]* or *double[][][][]*) -- + Scattering multiplicity matrices. + This dataset provides the ratio of neutrons produced in scattering + collisions to the neutrons which undergo scattering collisions; + that is, the multiplicity provides the code with a scaling factor + to account for neutrons being produced in (n,xn) reactions. This + information is assumed isotropic and therefore is not repeated for + every Legendre moment or histogram/tabular bin. This matrix + follows the same arrangement as described for the `scatter` + dataset, with the exception of the data needed to provide the + scattering type information. + This dataset is optional, if it is not provided no multiplication + (i.e., values of 1.0) will be assumed. + - **fission** (*double[]* or *double[][][]*) -- Fission + cross section. + This is a 1-D vector if `representation` is "isotropic", or a 3-D + vector if `representation` is "angle" with dimensions of + [groups, azimuthal, polar]. This is only required if the data set + is fissionable and fission-tallies are expected to be used. + - **kappa-fission** (*double[]* or *double[][][]*) -- Kappa-Fission + (energy-release from fission) cross section. + This is a 1-D vector if `representation` is "isotropic", or a 3-D + vector if `representation` is "angle" with dimensions of + [groups, azimuthal, polar]. This is only required if the data set + is fissionable and fission-tallies are expected to be used. + - **chi** (*double[]* or *double[][][]*) -- Fission neutron energy + spectra. + This is a 1-D vector if `representation` is "isotropic", or a 3-D + vector if `representation` is "angle" with dimensions of + [groups, azimuthal, polar]. This is only required if the data set + is fissionable and fission-tallies are expected to be used. + - **nu-fission** (*double[]* to *double[][][][]*) -- Nu-Fission + cross section. + If **chi** is provided, then `nu-fission` has the same + dimensionality as `fission`. If **chi** is not provided, then + the `nu-fission` data must represent the fission neutron energy + spectra as well and thus will have one additional dimension + for the outgoing energy group. In this case, `nu-fission` has the + same dimensionality as `multiplicity matrix`. \ No newline at end of file From 35c8caaae8dc9ce1ddd1a70b259c99b5f0cf2e85 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 3 Sep 2016 13:09:55 -0400 Subject: [PATCH 02/82] Updated python api to support new MGXS Library format --- openmc/mgxs/library.py | 105 ++---- openmc/mgxs_library.py | 791 +++++++++++++++++++++++------------------ 2 files changed, 471 insertions(+), 425 deletions(-) diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 4b68952a67..9f0e173f3c 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -822,11 +822,12 @@ class Library(object): return pickle.load(open(full_filename, 'rb')) def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro', - order=None, tabular_legendre=None, tabular_points=33, - subdomain=None): + order=None, subdomain=None): """Generates an openmc.XSdata object describing a multi-group cross section data set for eventual combination in to an openmc.MGXSLibrary object - (i.e., the library). + (i.e., the library). Note that this method does not build an XSdata + object with nested temperature tables. The temperature of each + XsData object will be left at the default value of 300K. Parameters ---------- @@ -845,18 +846,6 @@ class Library(object): Scattering order for this data entry. Default is None, which will set the XSdata object to use the order of the Library. - tabular_legendre : None or bool - Flag to denote whether or not the Legendre expansion of the - scattering angular distribution is to be converted to a tabular - representation by OpenMC. A value of `True` means that it is to be - converted while a value of `False` means that it will not be. - Defaults to `None` which leaves the default behavior of OpenMC in - place (the distribution is converted to a tabular representation). - tabular_points : int - This parameter is not used unless the ``tabular_legendre`` - parameter is set to `True`. In this case, this parameter sets the - number of equally-spaced points in the domain of [-1,1] to be used - in building the tabular distribution. Default is `33`. subdomain : iterable of int This parameter is not used unless using a mesh domain. In that case, the subdomain is an [i,j,k] index (1-based indexing) of the @@ -890,10 +879,6 @@ class Library(object): if order is not None: cv.check_greater_than('order', order, 0, equality=True) cv.check_less_than('order', order, 10, equality=True) - cv.check_type('tabular_legendre', tabular_legendre, - (type(None), bool)) - if tabular_points is not None: - cv.check_greater_than('tabular_points', tabular_points, 1) if subdomain is not None: cv.check_iterable_type('subdomain', subdomain, Integral, max_depth=3) @@ -922,11 +907,6 @@ class Library(object): # the provided order or the Library's order. xsdata.order = min(order, self.legendre_order) - # Set the tabular_legendre option if needed - if tabular_legendre is not None: - xsdata.tabular_legendre = {'enable': tabular_legendre, - 'num_points': tabular_points} - if nuclide is not 'total': xsdata.zaid = self._nuclides[nuclide][0] xsdata.awr = self._nuclides[nuclide][1] @@ -979,48 +959,52 @@ class Library(object): # If multiplicity matrix is available, prefer that if 'multiplicity matrix' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'multiplicity matrix') - xsdata.set_multiplicity_mgxs(mymgxs, xs_type=xs_type, - nuclide=[nuclide], - subdomain=subdomain) + xsdata.set_multiplicity_matrix_mgxs(mymgxs, xs_type=xs_type, + nuclide=[nuclide], + subdomain=subdomain) using_multiplicity = True # multiplicity will fall back to using scatter and nu-scatter elif ((('scatter matrix' in self.mgxs_types) and ('nu-scatter matrix' in self.mgxs_types))): scatt_mgxs = self.get_mgxs(domain, 'scatter matrix') nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix') - xsdata.set_multiplicity_mgxs(nuscatt_mgxs, scatt_mgxs, - xs_type=xs_type, nuclide=[nuclide], - subdomain=subdomain) + xsdata.set_multiplicity_matrix_mgxs(nuscatt_mgxs, scatt_mgxs, + xs_type=xs_type, + nuclide=[nuclide], + subdomain=subdomain) using_multiplicity = True else: using_multiplicity = False if using_multiplicity: nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix') - xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type, - nuclide=[nuclide], subdomain=subdomain) + xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type, + nuclide=[nuclide], + subdomain=subdomain) else: if 'nu-scatter matrix' in self.mgxs_types: nuscatt_mgxs = self.get_mgxs(domain, 'nu-scatter matrix') - xsdata.set_scatter_mgxs(nuscatt_mgxs, xs_type=xs_type, - nuclide=[nuclide], - subdomain=subdomain) + xsdata.set_scatter_matrix_mgxs(nuscatt_mgxs, xs_type=xs_type, + nuclide=[nuclide], + subdomain=subdomain) # Since we are not using multiplicity, then # scattering multiplication (nu-scatter) must be # accounted for approximately by using an adjusted # absorption cross section. if 'total' in self.mgxs_types: - xsdata.absorption = \ - np.subtract(xsdata.total, - np.sum(xsdata.scatter[0, :, :], axis=1)) + for i in range(len(xsdata.temperatures)): + xsdata._absorption[i] = \ + np.subtract(xsdata._total[i], np.sum( + xsdata._scatter_matrix[i][0, :, :], axis=1)) return xsdata - def create_mg_library(self, xs_type='macro', xsdata_names=None, - tabular_legendre=None, tabular_points=33): + def create_mg_library(self, xs_type='macro', xsdata_names=None): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the - Multi-Group mode of OpenMC. + Multi-Group mode of OpenMC. Note that this library will not make use + of nested temperature tables. Every dataset in te library will be + treated as if it was at the same default temperature. Parameters ---------- @@ -1031,18 +1015,6 @@ class Library(object): xsdata_names : Iterable of str List of names to apply to the "xsdata" entries in the resultant mgxs data file. Defaults to 'set1', 'set2', ... - tabular_legendre : None or bool - Flag to denote whether or not the Legendre expansion of the - scattering angular distribution is to be converted to a tabular - representation by OpenMC. A value of `True` means that it is to be - converted while a value of `False` means that it will not be. - Defaults to `None` which leaves the default behavior of OpenMC in - place (the distribution is converted to a tabular representation). - tabular_points : int - This parameter is not used unless the ``tabular_legendre`` - parameter is set to `True`. In this case, this parameter sets the - number of equally-spaced points in the domain of [-1,1] to be used - in building the tabular distribution. Default is `33`. Returns ------- @@ -1094,8 +1066,6 @@ class Library(object): # Create XSdata and Macroscopic for this domain xsdata = self.get_xsdata(domain, xsdata_name, - tabular_legendre=tabular_legendre, - tabular_points=tabular_points, subdomain=subdomain) mgxs_file.add_xsdata(xsdata) i += 1 @@ -1117,16 +1087,13 @@ class Library(object): xsdata_name += '_' + nuclide xsdata = self.get_xsdata(domain, xsdata_name, - nuclide=nuclide, xs_type=xs_type, - tabular_legendre=tabular_legendre, - tabular_points=tabular_points) + nuclide=nuclide, xs_type=xs_type) mgxs_file.add_xsdata(xsdata) return mgxs_file - def create_mg_mode(self, xsdata_names=None, tabular_legendre=None, - tabular_points=33, bc=['reflective'] * 6): + def create_mg_mode(self, xsdata_names=None, bc=['reflective'] * 6): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the Multi-Group mode of OpenMC as well as the associated openmc.Materials and openmc.Geometry objects. The created Geometry is the same as that @@ -1134,24 +1101,15 @@ class Library(object): modifications to point to newly-created Materials which point to the multi-group data. This method only creates a macroscopic MGXS Library even if nuclidic tallies are specified in the Library. + Note that this library will not make use of nested temperature tables. + Every dataset in te library will be treated as if it was at the same + default temperature. Parameters ---------- xsdata_names : Iterable of str List of names to apply to the "xsdata" entries in the resultant mgxs data file. Defaults to 'set1', 'set2', ... - tabular_legendre : None or bool - Flag to denote whether or not the Legendre expansion of the - scattering angular distribution is to be converted to a tabular - representation by OpenMC. A value of `True` means that it is to be - converted while a value of `False` means that it will not be. - Defaults to `None` which leaves the default behavior of OpenMC in - place (the distribution is converted to a tabular representation). - tabular_points : int - This parameter is not used unless the ``tabular_legendre`` - parameter is set to `True`. In this case, this parameter sets the - number of equally-spaced points in the domain of [-1,1] to be used - in building the tabular distribution. Default is `33`. bc : iterable of {'reflective', 'periodic', 'transmission', or 'vacuum'} Boundary conditions for each of the four faces of a rectangle (if applying to a 2D mesh) or six faces of a parallelepiped @@ -1198,8 +1156,7 @@ class Library(object): cv.check_length("domains", self.domains, 1, 1) # Get the MGXS File Data - mgxs_file = self.create_mg_library('macro', xsdata_names, - tabular_legendre, tabular_points) + mgxs_file = self.create_mg_library('macro', xsdata_names) # Now move on the creating the geometry and assigning materials if self.domain_type == 'mesh': diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 37ad6c1be4..68c0063f2b 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1,82 +1,31 @@ from collections import Iterable from numbers import Real, Integral -from xml.etree import ElementTree as ET import sys import numpy as np +import h5py import openmc import openmc.mgxs from openmc.checkvalue import check_type, check_value, check_greater_than, \ - check_iterable_type -from openmc.clean_xml import sort_xml_elements, clean_xml_indentation + check_less_than, check_iterable_type if sys.version_info[0] >= 3: basestring = str # Supported incoming particle MGXS angular treatment representations +_REPRESENTATION_ISOTROPIC = 1 +_REPRESENTATION_ANGLE = 2 +_SCATTER_TYPE_TABULAR = 3 +_SCATTER_TYPE_LEGENDRE = 4 +_SCATTER_TYPE_HISTOGRAM = 5 _REPRESENTATIONS = ['isotropic', 'angle'] - - -def ndarray_to_string(arr): - """Converts a numpy ndarray in to a join with spaces between entries - similar to ' '.join(map(str,arr)) but applied to all sub-dimensions. - - Parameters - ---------- - arr : numpy.ndarray - Array to combine in to a string - - Returns - ------- - text : str - String representation of array in arr - - """ - - shape = arr.shape - ndim = arr.ndim - tab = ' ' - indent = '\n' + tab + tab - text = indent - - if ndim == 1: - text += tab - for i in range(shape[0]): - text += '{:.7E} '.format(arr[i]) - text += indent - elif ndim == 2: - for i in range(shape[0]): - text += tab - for j in range(shape[1]): - text += '{:.7E} '.format(arr[i, j]) - text += indent - elif ndim == 3: - for i in range(shape[0]): - for j in range(shape[1]): - text += tab - for k in range(shape[2]): - text += '{:.7E} '.format(arr[i, j, k]) - text += indent - elif ndim == 4: - for i in range(shape[0]): - for j in range(shape[1]): - for k in range(shape[2]): - text += tab - for l in range(shape[3]): - text += '{:.7E} '.format(arr[i, j, k, l]) - text += indent - elif ndim == 5: - for i in range(shape[0]): - for j in range(shape[1]): - for k in range(shape[2]): - for l in range(shape[3]): - text += tab - for m in range(shape[4]): - text += '{:.7E} '.format(arr[i, j, k, l, m]) - text += indent - - return text +_REPRESENTATIONS_TEXT = {'isotropic': _REPRESENTATION_ISOTROPIC, + 'angle': _REPRESENTATION_ANGLE} +_SCATTER_TYPES = ['tabular', 'legendre', 'histogram'] +_SCATTER_TYPES_TEXT = {'tabular': _SCATTER_TYPE_TABULAR, + 'legendre': _SCATTER_TYPE_LEGENDRE, + 'histogram': _SCATTER_TYPE_HISTOGRAM} class XSdata(object): @@ -85,40 +34,37 @@ class XSdata(object): Parameters ---------- - name : str, optional + name : str Name of the mgxs data set. energy_groups : openmc.mgxs.EnergyGroups Energygroup structure representation : {'isotropic', 'angle'}, optional Method used in generating the MGXS (isotropic or angle-dependent flux weighting). Defaults to 'isotropic' + temperatures : numpy.ndarray + Temperatures (in units of Kelvin) of the provided datasets. Defaults + to a single temperature at 300K. Attributes ---------- name : str Unique identifier for the xsdata object - alias : str - Separate unique identifier for the xsdata object awr : float Atomic weight ratio of an isotope. That is, the ratio of the mass of the isotope to the mass of a single neutron. - kT : float - Temperature (in units of MeV). + temperatures : numpy.ndarray + Temperatures (in units of Kelvin) of the provided datasets. Defaults + to a single temperature at 300K. energy_groups : openmc.mgxs.EnergyGroups Energy group structure fissionable : bool Whether or not this is a fissionable data set. - scatt_type : {'legendre', 'histogram', or 'tabular'} + scatter_type : {'legendre', 'histogram', or 'tabular'} Angular distribution representation (legendre, histogram, or tabular) order : int Either the Legendre order, number of bins, or number of points used to describe the angular distribution associated with each group-to-group transfer probability. - tabular_legendre : dict - Set how to treat the Legendre scattering kernel (tabular or leave in - Legendre polynomial form). Dict contains two keys: 'enable' and - 'num_points'. 'enable' is a boolean and 'num_points' is the - number of points to use, if 'enable' is True. representation : {'isotropic', 'angle'} Method used in generating the MGXS (isotropic or angle-dependent flux weighting). @@ -160,16 +106,16 @@ class XSdata(object): azimuthal angles times the number of polar angles, with the inner-dimension being groups, intermediate-dimension being azimuthal angles and outer-dimension being the polar angles. - scatter : numpy.ndarray + scatter_matrix : numpy.ndarray Scattering moment matrices presented with the columns representing incoming group and rows representing the outgoing group. That is, down-scatter will be above the diagonal of the resultant matrix. This matrix is repeated for every Legendre order (in order of increasing - orders) if ``scatt_type`` is "legendre"; otherwise, this matrix is + orders) if ``scatter_type`` is "legendre"; otherwise, this matrix is repeated for every bin of the histogram or tabular representation. Finally, if ``representation`` is "angle", the above is repeated for every azimuthal angle and every polar angle, in that order. - multiplicity : numpy.ndarray + multiplicity_matrix : numpy.ndarray Ratio of neutrons produced in scattering collisions to the neutrons which undergo scattering collisions; that is, the multiplicity provides the code with a scaling factor to account for neutrons produced in @@ -218,29 +164,28 @@ class XSdata(object): """ - def __init__(self, name, energy_groups, representation='isotropic'): + def __init__(self, name, energy_groups, temperatures=[300.], + representation='isotropic'): # Initialize class attributes - self._name = name - self._energy_groups = energy_groups - self._representation = representation - self._alias = None + self.name = name + self.energy_groups = energy_groups + self.temperatures = temperatures + self.representation = representation self._awr = None - self._kT = None self._fissionable = False - self._scatt_type = 'legendre' + self._scatter_type = 'legendre' self._order = None - self._tabular_legendre = None self._num_polar = None self._num_azimuthal = None - self._total = None - self._absorption = None - self._scatter = None - self._multiplicity = None - self._fission = None - self._nu_fission = None - self._kappa_fission = None - self._chi = None self._use_chi = None + self._total = len(temperatures) * [None] + self._absorption = len(temperatures) * [None] + self._scatter_matrix = len(temperatures) * [None] + self._multiplicity_matrix = len(temperatures) * [None] + self._fission = len(temperatures) * [None] + self._nu_fission = len(temperatures) * [None] + self._kappa_fission = len(temperatures) * [None] + self._chi = len(temperatures) * [None] @property def name(self): @@ -254,30 +199,26 @@ class XSdata(object): def representation(self): return self._representation - @property - def alias(self): - return self._alias - @property def awr(self): return self._awr @property - def kT(self): - return self._kT + def fissionable(self): + return self._fissionable @property - def scatt_type(self): - return self._scatt_type + def temperatures(self): + return self._temperatures + + @property + def scatter_type(self): + return self._scatter_type @property def order(self): return self._order - @property - def tabular_legendre(self): - return self._tabular_legendre - @property def num_polar(self): return self._num_polar @@ -299,12 +240,12 @@ class XSdata(object): return self._absorption @property - def scatter(self): - return self._scatter + def scatter_matrix(self): + return self._scatter_matrix @property - def multiplicity(self): - return self._multiplicity + def multiplicity_matrix(self): + return self._multiplicity_matrix @property def fission(self): @@ -324,36 +265,36 @@ class XSdata(object): @property def num_orders(self): - if (self._order is not None) and (self._scatt_type is not None): - if self._scatt_type is 'legendre': + if self._order is not None: + if self._scatter_type in (None, 'legendre'): return self._order + 1 else: return self._order @property def vector_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups,) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups) @property def matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups, self.energy_groups.num_groups) @property def pn_matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) @@ -380,13 +321,6 @@ class XSdata(object): check_value('representation', representation, _REPRESENTATIONS) self._representation = representation - @alias.setter - def alias(self, alias): - if alias is not None: - check_type('alias', alias, basestring) - self._alias = alias - else: - self._alias = self._name @awr.setter def awr(self, awr): @@ -395,19 +329,28 @@ class XSdata(object): check_greater_than('awr', awr, 0.0) self._awr = awr - @kT.setter - def kT(self, kT): - # Check validity of type and that the kT value is >= 0 - check_type('kT', kT, Real) - check_greater_than('kT', kT, 0.0, equality=True) - self._kT = kT + @fissionable.setter + def fissionable(self, fissionable): + check_type('fissionable', fissionable, bool) + self._fissionable = fissionable - @scatt_type.setter - def scatt_type(self, scatt_type): + @temperatures.setter + def temperatures(self, temperatures): + check_type('temperatures', temperatures, Iterable, + expected_iter_type=Real) + # Convert to a numpy array so we can easily get the shape for + # checking + nptemperatures = np.asarray(temperatures) + + check_value('temperatures dimensionality', nptemperatures.ndim, [1]) + + self._temperatures = nptemperatures + + @scatter_type.setter + def scatter_type(self, scatter_type): # check to see it is of a valid type and value - check_value('scatt_type', scatt_type, ['legendre', 'histogram', - 'tabular']) - self._scatt_type = scatt_type + check_value('scatter_type', scatter_type, _SCATTER_TYPES) + self._scatter_type = scatter_type @order.setter def order(self, order): @@ -416,29 +359,6 @@ class XSdata(object): check_greater_than('order', order, 0, equality=True) self._order = order - @tabular_legendre.setter - def tabular_legendre(self, tabular_legendre): - # Check to make sure this is a dict and it has our keys with the - # right values. - check_type('tabular_legendre', tabular_legendre, dict) - if 'enable' in tabular_legendre: - enable = tabular_legendre['enable'] - check_type('enable', enable, bool) - else: - msg = 'The tabular_legendre dict must include a value keyed by ' \ - '"enable"' - raise ValueError(msg) - if 'num_points' in tabular_legendre: - num_points = tabular_legendre['num_points'] - check_type('num_points', num_points, Integral) - check_greater_than('num_points', num_points, 0) - else: - if not enable: - num_points = 1 - else: - num_points = 33 - self._tabular_legendre = {'enable': enable, 'num_points': num_points} - @num_polar.setter def num_polar(self, num_polar): # Make sure we have positive ints @@ -457,42 +377,111 @@ class XSdata(object): check_type('use_chi', use_chi, bool) self._use_chi = use_chi - @total.setter - def total(self, total): + def set_total(self, total, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + total: nd.nparray + Total Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_total_mgxs() + + """ check_type('total', total, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for # checking nptotal = np.asarray(total) check_value('total shape', nptotal.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._total = nptotal + i = self.temperatures.tolist().index(temperature) + self._total[i] = nptotal - @absorption.setter - def absorption(self, absorption): + def set_absorption(self, absorption, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + absorption: nd.nparray + Absorption Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_absorption_mgxs() + + """ check_type('absorption', absorption, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for # checking npabsorption = np.asarray(absorption) check_value('absorption shape', npabsorption.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._absorption = npabsorption + i = self.temperatures.tolist().index(temperature) + self._absorption[i] = npabsorption - @fission.setter - def fission(self, fission): + def set_fission(self, fission, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + fission: nd.nparray + Fission Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_fission_mgxs() + + """ check_type('fission', fission, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for # checking npfission = np.asarray(fission) check_value('fission shape', npfission.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._fission = npfission + i = self.temperatures.tolist().index(temperature) + self._fission[i] = npfission - if np.sum(self._fission) > 0.0: + if np.sum(npfission) > 0.0: self._fissionable = True - @kappa_fission.setter - def kappa_fission(self, kappa_fission): + def set_kappa_fission(self, kappa_fission, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + kappa_fission: nd.nparray + Kappa-Fission Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_kappa_fission_mgxs() + + """ check_type('kappa_fission', kappa_fission, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for @@ -500,18 +489,36 @@ class XSdata(object): npkappa_fission = np.asarray(kappa_fission) check_value('kappa fission shape', npkappa_fission.shape, [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._kappa_fission = npkappa_fission + i = self.temperatures.tolist().index(temperature) + self._kappa_fission[i] = npkappa_fission - if np.sum(self._kappa_fission) > 0.0: + if np.sum(npkappa_fission) > 0.0: self._fissionable = True - @chi.setter - def chi(self, chi): + def set_chi(self, chi, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + chi: nd.nparray + Fission Spectrum + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_chi_mgxs() + + """ if self.use_chi is not None: if not self.use_chi: - msg = 'Providing "chi" when "nu-fission" already provided as a' \ - 'matrix' + msg = 'Providing "chi" when "nu-fission" already provided ' \ + 'as a matrix' raise ValueError(msg) check_type('chi', chi, Iterable, expected_iter_type=Real) @@ -522,25 +529,61 @@ class XSdata(object): if npchi.shape != self.vector_shape: msg = 'Provided chi iterable does not have the expected shape.' raise ValueError(msg) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._chi = npchi + i = self.temperatures.tolist().index(temperature) + self._chi[i] = npchi if self.use_chi is not None: self.use_chi = True - @scatter.setter - def scatter(self, scatter): + def set_scatter_matrix(self, scatter, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + scatter: nd.nparray + Scattering Matrix Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_scatter_matrix_mgxs() + + """ # Convert to a numpy array so we can easily get the shape for # checking npscatter = np.asarray(scatter) check_iterable_type('scatter', npscatter, Real, max_depth=len(npscatter.shape)) check_value('scatter shape', npscatter.shape, [self.pn_matrix_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._scatter = npscatter + i = self.temperatures.tolist().index(temperature) + self._scatter_matrix[i] = npscatter - @multiplicity.setter - def multiplicity(self, multiplicity): + def set_multiplicity_matrix(self, multiplicity, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + multiplicity: nd.nparray + Multiplicity Matrix Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_multiplicity_matrix_mgxs() + + """ # Convert to a numpy array so we can easily get the shape for # checking npmultiplicity = np.asarray(multiplicity) @@ -548,11 +591,29 @@ class XSdata(object): max_depth=len(npmultiplicity.shape)) check_value('multiplicity shape', npmultiplicity.shape, [self.matrix_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - self._multiplicity = npmultiplicity + i = self.temperatures.tolist().index(temperature) + self._multiplicity_matrix[i] = npmultiplicity - @nu_fission.setter - def nu_fission(self, nu_fission): + def set_nu_fission(self, nu_fission, temperature=300.): + """This method sets the cross section for this XSdata object at the + provided temperature. + + Parameters + ---------- + nu_fission: nd.nparray + Nu-fission Cross Section + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K + + See also + -------- + openmc.mgxs_library.set_nu_fission_mgxs() + + """ # The NuFissionXS class does not have the capability to produce # a fission matrix and therefore if this path is pursued, we know # chi must be used. @@ -569,6 +630,8 @@ class XSdata(object): check_iterable_type('nu_fission', npnu_fission, Real, max_depth=len(npnu_fission.shape)) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) if self.use_chi is not None: if self.use_chi: @@ -582,14 +645,18 @@ class XSdata(object): [self.vector_shape, self.matrix_shape]) # Find out if we have a nu-fission matrix or vector # and set a flag to allow other methods to check this later. - self.use_chi = (npnu_fission.shape == self.vector_shape) + if npnu_fission.shape == self.vector_shape: + self.use_chi = True + else: + self.use_chi = False - self._nu_fission = npnu_fission - if np.sum(self._nu_fission) > 0.0: + i = self.temperatures.tolist().index(temperature) + self._nu_fission[i] = npnu_fission + if np.sum(npnu_fission) > 0.0: self._fissionable = True - def set_total_mgxs(self, total, nuclide='total', xs_type='macro', - subdomain='all'): + def set_total_mgxs(self, total, temperature=300., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.TotalXS or openmc.mgxs.TransportXS to be used to set the total cross section for this XSdata object. @@ -599,6 +666,9 @@ class XSdata(object): total: openmc.mgxs.TotalXS or openmc.mgxs.TransportXS MGXS Object containing the total or transport cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -621,16 +691,19 @@ class XSdata(object): check_value('energy_groups', total.energy_groups, [self.energy_groups]) check_value('domain_type', total.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._total = total.get_xs(nuclides=nuclide, xs_type=xs_type, - subdomains=subdomain) + self._total[i] = total.get_xs(nuclides=nuclide, xs_type=xs_type, + subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_absorption_mgxs(self, absorption, nuclide='total', - xs_type='macro', subdomain=None): + def set_absorption_mgxs(self, absorption, temperature=300., + nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.AbsorptionXS to be used to set the absorption cross section for this XSdata object. @@ -639,6 +712,9 @@ class XSdata(object): absorption: openmc.mgxs.AbsorptionXS MGXS Object containing the absorption cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -661,17 +737,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', absorption.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._absorption = absorption.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) + self._absorption[i] = absorption.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_fission_mgxs(self, fission, nuclide='total', xs_type='macro', - subdomain=None): + def set_fission_mgxs(self, fission, temperature=300., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.FissionXS to be used to set the fission cross section for this XSdata object. @@ -680,6 +759,9 @@ class XSdata(object): fission: openmc.mgxs.FissionXS MGXS Object containing the fission cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -702,17 +784,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._fission = fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) + self._fission[i] = fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_nu_fission_mgxs(self, nu_fission, nuclide='total', - xs_type='macro', subdomain=None): + def set_nu_fission_mgxs(self, nu_fission, temperature=300., + nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.NuFissionXS to be used to set the nu-fission cross section for this XSdata object. @@ -721,6 +806,9 @@ class XSdata(object): nu_fission: openmc.mgxs.NuFissionXS MGXS Object containing the nu-fission cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -744,11 +832,14 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', nu_fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._nu_fission = nu_fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) + self._nu_fission[i] = nu_fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -761,8 +852,9 @@ class XSdata(object): if np.sum(self._nu_fission) > 0.0: self._fissionable = True - def set_kappa_fission_mgxs(self, k_fission, nuclide='total', - xs_type='macro', subdomain=None): + def set_kappa_fission_mgxs(self, k_fission, temperature=300., + nuclide='total', xs_type='macro', + subdomain=None): """This method allows for an openmc.mgxs.KappaFissionXS to be used to set the kappa-fission cross section for this XSdata object. @@ -772,6 +864,9 @@ class XSdata(object): kappa_fission: openmc.mgxs.KappaFissionXS MGXS Object containing the kappa-fission cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -794,17 +889,20 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', k_fission.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._kappa_fission = k_fission.get_xs(nuclides=nuclide, - xs_type=xs_type, - subdomains=subdomain) + self._kappa_fission[i] = k_fission.get_xs(nuclides=nuclide, + xs_type=xs_type, + subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_chi_mgxs(self, chi, nuclide='total', xs_type='macro', - subdomain=None): + def set_chi_mgxs(self, chi, temperature=300., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.Chi to be used to set chi for this XSdata object. @@ -812,6 +910,9 @@ class XSdata(object): ---------- chi: openmc.mgxs.Chi MGXS Object containing chi for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -839,10 +940,13 @@ class XSdata(object): check_value('energy_groups', chi.energy_groups, [self.energy_groups]) check_value('domain_type', chi.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': - self._chi = chi.get_xs(nuclides=nuclide, - xs_type=xs_type, subdomains=subdomain) + self._chi[i] = chi.get_xs(nuclides=nuclide, + xs_type=xs_type, subdomains=subdomain) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -850,8 +954,9 @@ class XSdata(object): if self.use_chi is not None: self.use_chi = True - def set_scatter_mgxs(self, scatter, nuclide='total', xs_type='macro', - subdomain=None): + def set_scatter_matrix_mgxs(self, scatter, temperature=300., + nuclide='total', xs_type='macro', + subdomain=None): """This method allows for an openmc.mgxs.ScatterMatrixXS to be used to set the scatter matrix cross section for this XSdata object. If the XSdata.order attribute has not yet been set, then @@ -862,6 +967,9 @@ class XSdata(object): scatter: openmc.mgxs.ScatterMatrixXS MGXS Object containing the scatter matrix cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -884,8 +992,10 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) - if self.scatt_type != 'legendre': + if (self.scatter_type != 'legendre'): msg = 'Anisotropic scattering representations other than ' \ 'Legendre expansions have not yet been implemented in ' \ 'openmc.mgxs.' @@ -901,13 +1011,14 @@ class XSdata(object): check_value('legendre_order', scatter.legendre_order, [self.order]) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': # Get the scattering orders in the outermost dimension - self._scatter = np.zeros((self.num_orders, - self.energy_groups.num_groups, - self.energy_groups.num_groups)) + self._scatter_matrix[i] = np.zeros((self.num_orders, + self.energy_groups.num_groups, + self.energy_groups.num_groups)) for moment in range(self.num_orders): - self._scatter[moment, :, :] = \ + self._scatter_matrix[i][moment, :, :] = \ scatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=moment, subdomains=subdomain) @@ -915,10 +1026,12 @@ class XSdata(object): msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_multiplicity_mgxs(self, nuscatter, scatter=None, nuclide='total', - xs_type='macro', subdomain=None): + def set_multiplicity_matrix_mgxs(self, nuscatter, scatter=None, + temperature=300., nuclide='total', + xs_type='macro', subdomain=None): """This method allows for either the direct use of only an - openmc.mgxs.MultiplicityMatrixXS OR an openmc.mgxs.NuScatterMatrixXS and + openmc.mgxs.MultiplicityMatrixXS OR + an openmc.mgxs.NuScatterMatrixXS and openmc.mgxs.ScatterMatrixXS to be used to set the scattering multiplicity for this XSdata object. Multiplicity, in OpenMC parlance, is a factor used to account for the production @@ -935,6 +1048,9 @@ class XSdata(object): scatter: openmc.mgxs.ScatterMatrixXS MGXS Object containing the scattering matrix cross section for the domain of interest. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 300K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -958,6 +1074,9 @@ class XSdata(object): [self.energy_groups]) check_value('domain_type', nuscatter.domain_type, ['universe', 'cell', 'material', 'mesh']) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + if scatter is not None: check_type('scatter', scatter, openmc.mgxs.ScatterMatrixXS) if isinstance(nuscatter, openmc.mgxs.MultiplicityMatrixXS): @@ -970,102 +1089,81 @@ class XSdata(object): check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) + i = self.temperatures.tolist().index(temperature) if self.representation is 'isotropic': nuscatt = nuscatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, subdomains=subdomain) if isinstance(nuscatter, openmc.mgxs.MultiplicityMatrixXS): - self._multiplicity = nuscatt + self._multiplicity_matrix[i] = nuscatt else: scatt = scatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, subdomains=subdomain) - self._multiplicity = np.divide(nuscatt, scatt) + self._multiplicity_matrix[i] = np.divide(nuscatt, scatt) elif self.representation is 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - self._multiplicity = np.nan_to_num(self._multiplicity) + self._multiplicity_matrix[i] = \ + np.nan_to_num(self._multiplicity_matrix[i]) - def _get_xsdata_xml(self): - element = ET.Element('xsdata') - element.set('name', self._name) + def _get_xsdata_group(self, file, compression): + if compression is not None: + check_type("compression", compression, Integral) + check_greater_than("compression", compression, 0, equality=True) + check_less_than("compression", compression, 9, equality=True) - if self._alias is not None: - subelement = ET.SubElement(element, 'alias') - subelement.text = self.alias + grp = file.create_group(self.name) + if self.awr is not None: + grp.attrs['awr'] = self.awr + if self.fissionable is not None: + grp.attrs['fissionable'] = self.fissionable + if self.representation is not None: + grp.attrs['representation'] = \ + np.string_(_REPRESENTATIONS_TEXT[self.representation]) + if self.representation == 'angle': + if self.num_azimuthal is not None: + grp.attrs['num-azimuthal'] = self.num_azimuthal + if self.num_polar is not None: + grp.attrs['num-polar'] = self.num_polar + if self.scatter_type is not None: + grp.attrs['scatter-type'] = \ + np.string_(_SCATTER_TYPES_TEXT[self.scatter_type]) + if self.order is not None: + grp.attrs['order'] = self.order - if self._kT is not None: - subelement = ET.SubElement(element, 'kT') - subelement.text = str(self._kT) - - if self._awr is not None: - subelement = ET.SubElement(element, 'awr') - subelement.text = str(self._awr) - - if self._fissionable is not None: - subelement = ET.SubElement(element, 'fissionable') - subelement.text = str(self._fissionable) - - if self._representation is not None: - subelement = ET.SubElement(element, 'representation') - subelement.text = self._representation - - if self._representation == 'angle': - if self._num_azimuthal is not None: - subelement = ET.SubElement(element, 'num_azimuthal') - subelement.text = str(self._num_azimuthal) - if self._num_polar is not None: - subelement = ET.SubElement(element, 'num_polar') - subelement.text = str(self._num_polar) - - if self._scatt_type is not None: - subelement = ET.SubElement(element, 'scatt_type') - subelement.text = self._scatt_type - - if self._order is not None: - subelement = ET.SubElement(element, 'order') - subelement.text = str(self._order) - - if self._tabular_legendre is not None: - subelement = ET.SubElement(element, 'tabular_legendre') - subelement.set('enable', str(self._tabular_legendre['enable'])) - subelement.set('num_points', - str(self._tabular_legendre['num_points'])) - - if self._total is not None: - subelement = ET.SubElement(element, 'total') - subelement.text = ndarray_to_string(self._total) - - if self._absorption is not None: - subelement = ET.SubElement(element, 'absorption') - subelement.text = ndarray_to_string(self._absorption) - - if self._scatter is not None: - subelement = ET.SubElement(element, 'scatter') - subelement.text = ndarray_to_string(self._scatter) - - if self._multiplicity is not None: - subelement = ET.SubElement(element, 'multiplicity') - subelement.text = ndarray_to_string(self._multiplicity) - - if self._fissionable: - if self._fission is not None: - subelement = ET.SubElement(element, 'fission') - subelement.text = ndarray_to_string(self._fission) - - if self._kappa_fission is not None: - subelement = ET.SubElement(element, 'k_fission') - subelement.text = ndarray_to_string(self._kappa_fission) - - if self._nu_fission is not None: - subelement = ET.SubElement(element, 'nu_fission') - subelement.text = ndarray_to_string(self._nu_fission) - - if self._chi is not None: - subelement = ET.SubElement(element, 'chi') - subelement.text = ndarray_to_string(self._chi) - - return element + # Create the temperature datasets + for i, temperature in enumerate(self.temperatures): + xsgrp = grp.create_group(str(np.round(temperature)) + "K") + if self._total[i] is not None: + xsgrp.create_dataset("total", data=self._total[i], + compression=compression) + if self._absorption[i] is not None: + xsgrp.create_dataset("absorption", data=self._absorption[i], + compression=compression) + if self._scatter_matrix[i] is not None: + xsgrp.create_dataset("scatter matrix", + data=self._scatter_matrix[i], + compression=compression) + if self._multiplicity_matrix[i] is not None: + xsgrp.create_dataset("multiplicity matrix", + data=self._multiplicity_matrix[i], + compression=compression) + if self.fissionable: + if self._fission[i] is not None: + xsgrp.create_dataset("fission", data=self._fission[i], + compression=compression) + if self._kappa_fission[i] is not None: + xsgrp.create_dataset("kappa-fission", + data=self._kappa_fission[i], + compression=compression) + if self._chi[i] is not None: + xsgrp.create_dataset("chi", data=self._chi[i], + compression=compression) + if self._nu_fission[i] is not None: + xsgrp.create_dataset("nu-fission", + data=self._nu_fission[i], + compression=compression) class MGXSLibrary(object): @@ -1073,6 +1171,11 @@ class MGXSLibrary(object): Corresponds directly to the MG version of the cross_sections.xml input file. + Parameters + ---------- + energy_groups : openmc.mgxs.EnergyGroups + Energygroup structure + Attributes ---------- energy_groups : openmc.mgxs.EnergyGroups @@ -1084,10 +1187,9 @@ class MGXSLibrary(object): """ def __init__(self, energy_groups): - self._xsdatas = [] - self._energy_groups = energy_groups + self.energy_groups = energy_groups self._inverse_velocities = None - self._cross_sections_file = ET.Element('cross_sections') + self._xsdatas = [] @property def inverse_velocities(self): @@ -1097,6 +1199,10 @@ class MGXSLibrary(object): def energy_groups(self): return self._energy_groups + @property + def temperatures(self): + return self._temperatures + @property def xsdatas(self): return self._xsdatas @@ -1163,52 +1269,35 @@ class MGXSLibrary(object): self._xsdatas.remove(xsdata) - def _create_groups_subelement(self): - if self._energy_groups is not None: - element = ET.SubElement(self._cross_sections_file, 'groups') - element.text = str(self._energy_groups.num_groups) - - def _create_group_structure_subelement(self): - if self._energy_groups is not None: - element = ET.SubElement(self._cross_sections_file, - 'group_structure') - element.text = ' '.join(map(str, self._energy_groups.group_edges)) - - def _create_inverse_velocities_subelement(self): - if self._inverse_velocities is not None: - element = ET.SubElement(self._cross_sections_file, - 'inverse_velocities') - element.text = ' '.join(map(str, self._inverse_velocities)) - - def _create_xsdata_subelements(self): - for xsdata in self._xsdatas: - xml_element = xsdata._get_xsdata_xml() - self._cross_sections_file.append(xml_element) - - def export_to_xml(self, filename='mgxs.xml'): - """Create an mgxs.xml file that can be used for a - simulation. + def export_to_hdf5(self, filename='mgxs.h5', compression=None): + """Create an mgxs.h5 file that can be used for a simulation. Parameters ---------- - filename : str, optional - filename of file, default is mgxs.xml + filename : str + Filename of file, default is mgxs.xml. + compression : None or int + The compression level to use in the datasets within the hdf5 file. + A value of None implies no compression, numbers between 0 and 9 + refer to the compression level using the gzip algorithm. + Defaults to None. """ - # Reset xml element tree - self._cross_sections_file.clear() + check_type('filename', filename, basestring) + if compression is not None: + check_type("compression", compression, Integral) + check_greater_than("compression", compression, 0, equality=True) + check_less_than("compression", compression, 9, equality=True) - self._create_groups_subelement() - self._create_group_structure_subelement() - self._create_inverse_velocities_subelement() - self._create_xsdata_subelements() + # Create and write to the HDF5 file + file = h5py.File(filename, "w") + file.attrs['groups'] = self.energy_groups.num_groups + file.attrs['group structure'] = self.energy_groups.group_edges + if self.inverse_velocities is not None: + file.attrs['inverse velocities'] = self.inverse_velocities - # Clean the indentation in the file to be user-readable - sort_xml_elements(self._cross_sections_file) - clean_xml_indentation(self._cross_sections_file) + for xsdata in self._xsdatas: + xsdata._get_xsdata_group(file, compression) - # Write the XML Tree to the xsdatas.xml file - tree = ET.ElementTree(self._cross_sections_file) - tree.write(filename, xml_declaration=True, - encoding='utf-8', method='xml') + file.close() From ab05e1b71b41ad6da911f7d36e6627d84a496d79 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 4 Sep 2016 05:26:16 -0400 Subject: [PATCH 03/82] finished updating mgxs_header, now just need to update the code that uses it --- docs/source/io_formats/mgxs_library.rst | 3 +- src/hdf5_interface.F90 | 78 +- src/mgxs_data.F90 | 6 +- src/mgxs_header.F90 | 2659 +++++++++++------------ 4 files changed, 1400 insertions(+), 1346 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 0313369d92..ccd68c1844 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -62,7 +62,8 @@ data for the nuclide or material that it represents. ignored otherwise. - **scatter-type** (*char[]*) -- The representation of the scattering angular distribution. The options are either - "legendre", "histogram", or "tabular". + "legendre", "histogram", or "tabular". If not provided, the + default of "legendre" will be assumed. - **order** (*int*) -- Either the Legendre order, number of bins, or number of points (depending on the value of `scatter-type`) used to describe the angular distribution associated with each group-to-group transfer probability. diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 415ec55c9e..13abd9754b 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -74,6 +74,7 @@ module hdf5_interface module procedure read_attribute_integer_2D module procedure read_attribute_string module procedure read_attribute_string_1D + module procedure read_attribute_logical end interface read_attribute interface write_attribute @@ -84,14 +85,17 @@ module hdf5_interface public :: write_dataset public :: read_dataset + public :: check_attribute public :: write_attribute public :: read_attribute public :: file_create public :: file_open public :: file_close public :: create_group + public :: check_group public :: open_group public :: close_group + public :: check_dataset public :: open_dataset public :: close_dataset public :: get_shape @@ -245,6 +249,52 @@ contains end subroutine get_groups +!=============================================================================== +! CHECK_ATTRIBUTE Checks to see if an attribute exists in the object +!=============================================================================== + + function check_attribute(object_id, name) result(exists) + integer(HID_T), intent(in) :: object_id + character(*), intent(in) :: name ! name of group + logical :: exists + + integer :: hdf5_err ! HDF5 error code + + ! Check if attribute exists + call h5aexists_by_name_f(object_id, '.', trim(name), exists, hdf5_err) + + end function check_attribute + +!=============================================================================== +! CHECK_GROUP Checks to see if a group exists in the object +!=============================================================================== + + function check_group(object_id, name) result(exists) + integer(HID_T), intent(in) :: object_id + character(*), intent(in) :: name ! name of group + logical :: exists + + integer :: hdf5_err ! HDF5 error code + + ! Check if group exists + call h5ltpath_valid_f(object_id, trim(name), .true., exists, hdf5_err) + + end function check_group + +!=============================================================================== +! CHECK_DATASET Checks to see if a dataset exists in the object +!=============================================================================== + + function check_dataset(object_id, name) result(exists) + integer(HID_T), intent(in) :: object_id + character(*), intent(in) :: name ! name of group + logical :: exists + + ! Wrap check_group since the method used there will work here too + exists = check_group(object_id, name) + + end function check_dataset + !=============================================================================== ! GET_DATASETS Gets a list of all the datasets in a given location. !=============================================================================== @@ -296,7 +346,7 @@ contains integer :: hdf5_err ! HDF5 error code ! Check if group exists - call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err) + exists = check_group(group_id, name) ! open group if it exists if (exists) then @@ -319,7 +369,7 @@ contains logical :: exists ! does the group exist ! Check if group exists - call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err) + exists = check_group(group_id, name) ! create group if (exists) then @@ -357,7 +407,7 @@ contains integer :: hdf5_err ! HDF5 error code ! Check if group exists - call h5ltpath_valid_f(group_id, trim(name), .true., exists, hdf5_err) + exists = check_group(group_id, name) ! open group if it exists if (exists) then @@ -2487,6 +2537,28 @@ contains call h5tclose_f(memtype, hdf5_err) end subroutine read_attribute_string_1D_explicit + subroutine read_attribute_logical(buffer, obj_id, name) + logical, intent(inout), target :: buffer + integer(HID_T), intent(in) :: obj_id + character(*), intent(in) :: name + + integer, target :: int_buffer + integer :: hdf5_err + integer(HID_T) :: attr_id + type(c_ptr) :: f_ptr + + call h5aopen_f(obj_id, trim(name), attr_id, hdf5_err) + f_ptr = c_loc(int_buffer) + call h5aread_f(attr_id, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) + call h5aclose_f(attr_id, hdf5_err) + ! Convert to Fortran logical + if (int_buffer == 0) then + buffer = .false. + else + buffer = .true. + end if + end subroutine read_attribute_logical + subroutine get_shape(obj_id, dims) integer(HID_T), intent(in) :: obj_id integer(HSIZE_T), intent(out) :: dims(:) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 05d6eb5ec6..aa96910f30 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -172,7 +172,6 @@ contains subroutine create_macro_xs() integer :: i_mat ! index in materials array type(Material), pointer :: mat ! current material - integer :: scatt_type allocate(macro_xs(n_materials)) @@ -182,9 +181,6 @@ contains ! Check to see how our nuclides are represented ! Force all to be the same type ! Therefore type(nuclides(mat % nuclide(1)) % obj) dictates type(macroxs) - ! At the same time, we will find the scattering type, as that will dictate - ! how we allocate the scatter object within macroxs - scatt_type = nuclides_MG(mat % nuclide(1)) % obj % scatt_type select type(nuc => nuclides_MG(mat % nuclide(1)) % obj) type is (MgxsIso) allocate(MgxsIso :: macro_xs(i_mat) % obj) @@ -192,7 +188,7 @@ contains allocate(MgxsAngle :: macro_xs(i_mat) % obj) end select call macro_xs(i_mat) % obj % combine(mat, nuclides_MG, energy_groups, & - max_order, scatt_type) + max_order) end do end subroutine create_macro_xs diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 9409398b3e..2f569c6fe0 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -1,35 +1,66 @@ module mgxs_header + use, intrinsic :: ISO_FORTRAN_ENV + use, intrinsic :: ISO_C_BINDING + + use hdf5, only: HID_T, HSIZE_T, SIZE_T, h5iget_name_f + use h5lt, only: h5ltpath_valid_f + use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI use error, only: fatal_error - use, intrinsic :: ISO_FORTRAN_ENV, only: OUTPUT_UNIT - use list_header, only: ListInt + use hdf5_interface use material_header, only: material - use math, only: calc_pn, calc_rn, expand_harmonic, & - evaluate_legendre + use math, only: evaluate_legendre use nuclide_header, only: MaterialMacroXS use random_lcg, only: prn use scattdata_header use string - use xml_interface + use stl_vector, only: VectorInt, VectorReal + +!=============================================================================== +! XS* contains the temperature-dependent cross section data for an MGXS +!=============================================================================== + + type :: XsDataIso + ! Microscopic cross sections + real(8), allocatable :: total(:) ! total cross section + real(8), allocatable :: absorption(:) ! absorption cross section + class(ScattData), allocatable :: scatter ! scattering info + real(8), allocatable :: nu_fission(:) ! fission production + real(8), allocatable :: k_fission(:) ! kappa-fission + real(8), allocatable :: fission(:) ! fission + real(8), allocatable :: chi(:, :) ! Fission Spectra + end type XsDataIso + + type :: XsDataAngle + ! Microscopic cross sections + ! In all cases, right-most indices are theta, phi + real(8), allocatable :: total(:, :, :) ! total cross section + real(8), allocatable :: absorption(:, :, :) ! absorption cross section + type(ScattDataContainer), allocatable :: scatter(:, :) ! scattering info + real(8), allocatable :: nu_fission(:, :, :) ! fission production + real(8), allocatable :: k_fission(:, :, :) ! kappa-fission + real(8), allocatable :: fission(:, :, :) ! fission + real(8), allocatable :: chi(:, :, :, :) ! Fission Spectra + end type XsDataAngle !=============================================================================== ! MGXS contains the base mgxs data for a nuclide/material !=============================================================================== type, abstract :: Mgxs - character(len=104) :: name ! name of dataset, e.g. 92235.03c - real(8) :: awr ! Atomic Weight Ratio - real(8) :: kT ! temperature in MeV (k*T) + character(len=104) :: name ! name of dataset, e.g. 92235.03c + real(8) :: awr ! Atomic Weight Ratio + real(8), allocatable :: kTs(:) ! temperature in MeV (k*T) ! Fission information - logical :: fissionable ! mgxs object is fissionable? - integer :: scatt_type ! either legendre, histogram, or tabular. + logical :: fissionable ! mgxs object is fissionable? + integer :: scatter_type ! either legendre, histogram, or tabular. contains - procedure(mgxs_init_file_), deferred :: init_file ! Initialize the data - procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs + procedure(mgxs_from_hdf5_), deferred :: from_hdf5 ! Load the data procedure(mgxs_combine_), deferred :: combine ! initializes object + procedure(mgxs_get_xs_), deferred :: get_xs ! Get the requested xs ! Sample the outgoing energy from a fission event procedure(mgxs_sample_fission_), deferred :: sample_fission_energy ! Sample the outgoing energy and angle from a scatter event @@ -51,63 +82,56 @@ module mgxs_header !=============================================================================== abstract interface - subroutine mgxs_init_file_(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - import Mgxs, Node - class(Mgxs), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Should we get fiss data? - integer, intent(in) :: max_order ! Maximum requested order - end subroutine mgxs_init_file_ + subroutine mgxs_from_hdf5_(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order) + import Mgxs, HID_T, VectorReal + class(Mgxs), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Library data + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(in) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order + end subroutine mgxs_from_hdf5_ - pure function mgxs_get_xs_(this,xstype,gin,gout,uvw,mu) result(xs) + subroutine mgxs_combine_(this, temps, mat, nuclides, groups, max_order) + import Mgxs, Material, MgxsContainer, VectorReal + class(Mgxs), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain + type(Material), pointer, intent(in) :: mat ! base material + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: groups ! Number of E groups + integer, intent(in) :: max_order ! Maximum requested order + end subroutine mgxs_combine_ + + pure function mgxs_get_xs_(this, t, xstype, gin, gout, uvw, mu) result(xs_val) import Mgxs class(Mgxs), intent(in) :: this + integer, intent(in) :: t ! Temperature index of data character(*), intent(in) :: xstype ! Cross Section Type integer, intent(in) :: gin ! Incoming Energy group integer, optional, intent(in) :: gout ! Outgoing Group real(8), optional, intent(in) :: uvw(3) ! Requested Angle real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Resultant xs + real(8) :: xs_val ! Resultant xs end function mgxs_get_xs_ - pure function mgxs_calc_f_(this,gin,gout,mu,uvw,iazi,ipol) result(f) + function mgxs_sample_fission_(this, t, gin, uvw) result(gout) import Mgxs - class(Mgxs), intent(in) :: this - integer, intent(in) :: gin ! Incoming Energy Group - integer, intent(in) :: gout ! Outgoing Energy Group - real(8), intent(in) :: mu ! Angle of interest - real(8), intent(in), optional :: uvw(3) ! Direction vector - integer, intent(in), optional :: iazi ! Incoming Energy Group - integer, intent(in), optional :: ipol ! Outgoing Energy Group - real(8) :: f ! Return value of f(mu) - - end function mgxs_calc_f_ - - subroutine mgxs_combine_(this, mat, nuclides, groups, max_order, scatt_type) - import Mgxs, Material, MgxsContainer - class(Mgxs), intent(inout) :: this ! The Mgxs to initialize - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: groups ! Number of E groups - integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt? - end subroutine mgxs_combine_ - - function mgxs_sample_fission_(this, gin, uvw) result(gout) - import Mgxs - class(Mgxs), intent(in) :: this ! Data to work with + class(Mgxs), intent(in) :: this + integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming energy group real(8), intent(in) :: uvw(3) ! Particle Direction integer :: gout ! Sampled outgoing group end function mgxs_sample_fission_ - subroutine mgxs_sample_scatter_(this, uvw, gin, gout, mu, wgt) + subroutine mgxs_sample_scatter_(this, t, uvw, gin, gout, mu, wgt) import Mgxs - class(Mgxs), intent(in) :: this + class(Mgxs), intent(in) :: this + integer, intent(in) :: t ! Temperature index of data real(8), intent(in) :: uvw(3) ! Incoming neutron direction integer, intent(in) :: gin ! Incoming neutron group integer, intent(out) :: gout ! Sampled outgoin group @@ -115,9 +139,10 @@ module mgxs_header real(8), intent(inout) :: wgt ! Particle weight end subroutine mgxs_sample_scatter_ - subroutine mgxs_calculate_xs_(this, gin, uvw, xs) + subroutine mgxs_calculate_xs_(this, t, gin, uvw, xs) import Mgxs, MaterialMacroXS class(Mgxs), intent(in) :: this + integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data @@ -130,18 +155,9 @@ module mgxs_header !=============================================================================== type, extends(Mgxs) :: MgxsIso - - ! Microscopic cross sections - real(8), allocatable :: total(:) ! total cross section - real(8), allocatable :: absorption(:) ! absorption cross section - class(ScattData), allocatable :: scatter ! scattering information - real(8), allocatable :: nu_fission(:) ! fission matrix (Gout x Gin) - real(8), allocatable :: k_fission(:) ! kappa-fission - real(8), allocatable :: fission(:) ! neutron production - real(8), allocatable :: chi(:, :) ! Fission Spectra - + type(XsDataIso), allocatable :: xs(:) ! One for every temperature contains - procedure :: init_file => mgxsiso_init_file ! Initialize Nuclidic MGXS Data + procedure :: from_hdf5 => mgxsiso_from_hdf5 ! Initialize Nuclidic MGXS Data procedure :: get_xs => mgxsiso_get_xs ! Gets Size of Data w/in Object procedure :: combine => mgxsiso_combine ! inits object procedure :: sample_fission_energy => mgxsiso_sample_fission_energy @@ -155,23 +171,14 @@ module mgxs_header !=============================================================================== type, extends(Mgxs) :: MgxsAngle - - ! Microscopic cross sections - real(8), allocatable :: total(:, :, :) ! total cross section - real(8), allocatable :: absorption(:, :, :) ! absorption cross section - type(ScattDataContainer), allocatable :: scatter(:, :) ! scattering information - real(8), allocatable :: nu_fission(:, :, :) ! fission matrix (Gout x Gin) - real(8), allocatable :: k_fission(:, :, :) ! kappa-fission - real(8), allocatable :: fission(:, :, :) ! neutron production - real(8), allocatable :: chi(:, :, :, :) ! Fission Spectra - ! In all cases, right-most indices are theta, phi - integer :: n_pol ! Number of polar angles - integer :: n_azi ! Number of azimuthal angles - real(8), allocatable :: polar(:) ! polar angles - real(8), allocatable :: azimuthal(:) ! azimuthal angles + type(XsDataAngle), allocatable :: xs(:) ! One for every temperature + integer :: n_pol ! Number of polar angles + integer :: n_azi ! Number of azimuthal angles + real(8), allocatable :: polar(:) ! polar angles + real(8), allocatable :: azimuthal(:) ! azimuthal angles contains - procedure :: init_file => mgxsang_init_file ! Initialize Nuclidic MGXS Data + procedure :: from_hdf5 => mgxsang_from_hdf5 ! Initialize Nuclidic MGXS Data procedure :: get_xs => mgxsang_get_xs ! Gets Size of Data w/in Object procedure :: combine => mgxsang_combine ! inits object procedure :: sample_fission_energy => mgxsang_sample_fission_energy @@ -184,69 +191,185 @@ module mgxs_header !=============================================================================== ! MGXS*_INIT reads in the data from the XML file. At the point of entry ! the file would have been opened and metadata read. This routine begins with -! the xsdata object node itself. +! the xs_id object node itself. !=============================================================================== - subroutine mgxs_init_file(this, node_xsdata) - class(Mgxs), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml + subroutine mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + class(Mgxs), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(in) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + type(VectorInt), intent(out) :: temps_to_read ! Temperatures to read + integer, intent(out) :: order_dim ! Scattering data order size - character(MAX_LINE_LEN) :: temp_str + integer :: hdf5_err + integer(SIZE_T) :: name_len, name_file_len + integer(HID_T) :: kT_group, kT_dset + character(MAX_FILE_LEN), allocatable :: dset_names(:) + real(8), allocatable :: temps_available(:) ! temperatures available + real(8) :: temp_desired + real(8) :: temp_actual + logical :: exists + character(MAX_WORD_LEN) :: temp_str + real(8) :: dangle + integer :: ipol, iazi - ! Load the nuclide metadata - call get_node_value(node_xsdata, "name", this % name) - this % name = to_lower(this % name) - if (check_for_node(node_xsdata, "kT")) then - call get_node_value(node_xsdata, "kT", this % kT) - else - this % kT = ZERO - end if - if (check_for_node(node_xsdata, "awr")) then - call get_node_value(node_xsdata, "awr", this % awr) + ! Get name of dataset from group + name_len = len(this % name) + call h5iget_name_f(xs_id, this % name, name_len, name_file_len, hdf5_err) + + ! Get rid of leading '/' + this % name = trim(this % name(2:)) + + if (check_attribute(xs_id, "awr")) then + call read_attribute(this % awr, xs_id, "awr") else this % awr = -ONE end if - if (check_for_node(node_xsdata, "scatt_type")) then - call get_node_value(node_xsdata, "scatt_type", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'legendre') then - this % scatt_type = ANGLE_LEGENDRE - else if (temp_str == 'histogram') then - this % scatt_type = ANGLE_HISTOGRAM - else if (temp_str == 'tabular') then - this % scatt_type = ANGLE_TABULAR + + ! Determine temperatures available + kT_group = open_group(xs_id, 'kTs') + call get_datasets(kT_group, dset_names) + allocate(temps_available(size(dset_names))) + do i = 1, size(dset_names) + ! Read temperature value + call read_dataset(temps_available(i), kT_group, trim(dset_names(i))) + temps_available(i) = temps_available(i) / K_BOLTZMANN + end do + + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + TEMP_LOOP: do i = 1, temperature % size() + temp_desired = temperature % data(i) + i_closest = minloc(abs(temps_available - temp_desired), dim=1) + temp_actual = temps_available(i_closest) + if (abs(temp_actual - temp_desired) < tolerance) then + if (find(temps_to_read, nint(temp_actual)) == -1) then + call temps_to_read % push_back(nint(temp_actual)) + end if + else + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired))) // " K.") + end if + end do TEMP_LOOP + + case (TEMPERATURE_INTERPOLATION) + ! TODO: Get bounding temperatures + call fatal_error("Temperature interpolation not yet implemented") + end select + + ! Sort temperatures to read + call sort(temps_to_read) + + ! Get temperatures + n_temperature = temps_to_read % size() + allocate(this % kTs(n_temperature)) + do i = 1, n_temperature + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(i))) // "K" + + ! Read exact temperature value + call read_dataset(this % kTs(i), kT_group, trim(temp_str)) + end do + call close_group(kT_group) + + ! Allocate the XS object for the number of temperatures + select type(this) + type is (MgxsIso) + allocate(this % xs(n_temperature)) + type is (MgxsAngle) + allocate(this % xs(n_temperature)) + end select + + ! Load the remaining metadata + if (check_attribute(xs_id, "scatter-type")) then + call read_attribute(temp_str, xs_id, "scatter-type") + temp_str = trim(temp_str) + if (to_lower(temp_str) == 'legendre') then + this % scatter_type = ANGLE_LEGENDRE + else if (to_lower(temp_str) == 'histogram') then + this % scatter_type = ANGLE_HISTOGRAM + else if (to_lower(temp_str) == 'tabular') then + this % scatter_type = ANGLE_TABULAR else - call fatal_error("Invalid scatt_type option!") + call fatal_error("Invalid scatter-type option!") end if else - this % scatt_type = ANGLE_LEGENDRE + this % scatter_type = ANGLE_LEGENDRE end if - - if (check_for_node(node_xsdata, "fissionable")) then - call get_node_value(node_xsdata, "fissionable", temp_str) - temp_str = to_lower(temp_str) - if (trim(temp_str) == 'true' .or. trim(temp_str) == '1') then - this % fissionable = .true. - else - this % fissionable = .false. - end if + if (check_attribute(xs_id, "fissionable")) then + call read_attribute(this % fissionable, xs_id, "fissionable") else call fatal_error("Fissionable element must be set!") end if - end subroutine mgxs_init_file + ! Get the library's value for the order + if (check_attribute(xs_id, "order")) then + call read_attribute(order_dim, xs_id, "order") + else + call fatal_error("Order must be provided!") + end if - subroutine mgxsiso_init_file(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - class(MgxsIso), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Need fiss data? - integer, intent(in) :: max_order ! Maximum requested order + ! Store the dimensionality of the data in order_dim. + ! For Legendre data, we usually refer to it as Pn where n is the order. + ! However Pn has n+1 sets of points (since you need to + ! the count the P0 moment). Adjust for that. Histogram and Tabular + ! formats dont need this adjustment. + if (this % scatter_type == ANGLE_LEGENDRE) then + order_dim = order_dim + 1 + else + order_dim = order_dim + end if + + ! Get angular meta-data and allocate as needed based off of the + ! information therein + select type(this) + type is (MgxsAngle) + if (check_attribute(xs_id, "num-polar")) then + call read_attribute(this % n_pol, xs_id, "num-polar") + else + call fatal_error("num-polar must be provided!") + end if + + if (check_attribute(xs_id, "num-azimuthal")) then + call read_attribute(this % n_azi, xs_id, "num-azimuthal") + else + call fatal_error("num-azimuthal must be provided!") + end if + + ! Set angle data to use equally-spaced bins + allocate(this % polar(this % n_pol)) + dangle = PI / real(this % n_pol, 8) + do ipol = 1, this % n_pol + this % polar(ipol) = (real(ipol, 8) - HALF) * dangle + end do + allocate(this % azimuthal(this % n_azi)) + dangle = TWO * PI / real(this % n_azi, 8) + do iazi = 1, this % n_azi + this % azimuthal(iazi) = -PI + (real(iazi, 8) - HALF) * dangle + end do + end select + + end subroutine mgxs_from_hdf5 + + subroutine mgxsiso_from_hdf5(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order) + class(MgxsIso), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(in) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order - type(Node), pointer :: node_legendre_mu character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp logical :: enable_leg_mu real(8), allocatable :: temp_arr(:), temp_2d(:, :) real(8), allocatable :: temp_mult(:, :) @@ -256,596 +379,138 @@ module mgxs_header real(8) :: dmu, mu, norm integer :: order, order_dim, gin, gout, l, arr_len integer :: legendre_mu_points, imu + type(VectorInt) :: temps_to_read + integer :: t ! Call generic data gathering routine (will populate the metadata) - call mgxs_init_file(this, node_xsdata) + call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + !!!TODO: Fix + enable_leg_mu = .True. ! Load the more specific data - allocate(this % nu_fission(groups)) - allocate(this % chi(groups,groups)) - if (this % fissionable) then - if (check_for_node(node_xsdata, "chi")) then - ! Chi was provided, that means they are giving chi and nu-fission - ! vectors - ! Get chi - allocate(temp_arr(groups)) - call get_node_array(node_xsdata, "chi", temp_arr) - do gin = 1, groups - do gout = 1, groups - this % chi(gout, gin) = temp_arr(gout) - end do - ! Normalize chi so its CDF goes to 1 - this % chi(:, gin) = this % chi(:, gin) / sum(this % chi(:, gin)) - end do - deallocate(temp_arr) - - ! Get nu_fission (as a vector) - if (check_for_node(node_xsdata, "nu_fission")) then - call get_node_array(node_xsdata, "nu_fission", this % nu_fission) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - else - ! chi isnt provided but is within nu_fission, existing as a matrix - ! So, get nu_fission (as a matrix) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups*groups)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - allocate(temp_2d(groups, groups)) - temp_2d = reshape(temp_arr, (/groups, groups/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - ! Set the vector nu-fission from the matrix nu-fission - do gin = 1, groups - this % nu_fission(gin) = sum(temp_2d(:, gin)) - end do - - ! Now pull out information needed for chi - this % chi(:, :) = temp_2d - ! Normalize chi so its CDF goes to 1 - do gin = 1, groups - this % chi(:, gin) = this % chi(:, gin) / sum(this % chi(:, gin)) - end do - deallocate(temp_2d) - end if - ! If we have a need* for the fission and kappa-fission x/s, get them - ! (*Need is defined as will be using it to tally) - if (get_fiss) then - allocate(this % fission(groups)) - if (check_for_node(node_xsdata, "fission")) then - call get_node_array(node_xsdata, "fission", this % fission) - else - call fatal_error("Fission data missing, required due to fission& - & tallies in tallies.xml file!") - end if - end if - if (get_kfiss) then - allocate(this % k_fission(groups)) - if (check_for_node(node_xsdata, "kappa_fission")) then - call get_node_array(node_xsdata, "kappa_fission", this % k_fission) - else - call fatal_error("kappa_fission data missing, required due to & - &kappa-fission tallies in tallies.xml file!") - end if - end if - else - this % nu_fission = ZERO - this % chi = ZERO - end if - - allocate(this % absorption(groups)) - if (check_for_node(node_xsdata, "absorption")) then - call get_node_array(node_xsdata, "absorption", this % absorption) - else - call fatal_error("Must provide absorption!") - end if - - ! Get multiplication data if present - allocate(temp_mult(groups, groups)) - if (check_for_node(node_xsdata, "multiplicity")) then - arr_len = get_arraysize_double(node_xsdata, "multiplicity") - if (arr_len == groups * groups) then - allocate(temp_arr(arr_len)) - call get_node_array(node_xsdata, "multiplicity", temp_arr) - temp_mult(:, :) = reshape(temp_arr, (/groups, groups/)) - deallocate(temp_arr) - else - call fatal_error("Multiplicity length not same as number of groups& - & squared!") - end if - else - temp_mult(:, :) = ONE - end if - - ! Get scattering treatment information - ! Tabular_legendre tells us if we are to treat the provided - ! Legendre polynomials as tabular data (if enable is true, default) - ! or leaving them as Legendres (if enable is false) - - ! Set the default (Convert to tabular format w/ 33 points) - enable_leg_mu = .true. - legendre_mu_points = 33 - ! Get the user-provided values - if (check_for_node(node_xsdata, "tabular_legendre")) then - call get_node_ptr(node_xsdata, "tabular_legendre", node_legendre_mu) - if (check_for_node(node_legendre_mu, "enable")) then - call get_node_value(node_legendre_mu, "enable", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'true' .or. temp_str == '1') then - enable_leg_mu = .true. - elseif (temp_str == 'false' .or. temp_str == '0') then - enable_leg_mu = .false. - else - call fatal_error("Unrecognized tabular_legendre/enable: " & - // temp_str) - end if - end if - ! Ok, so if we need to convert to a tabular form, get the user provided - ! number of points - if (enable_leg_mu) then - if (check_for_node(node_legendre_mu, "num_points")) then - call get_node_value(node_legendre_mu, "num_points", & - legendre_mu_points) - if (legendre_mu_points <= 0) & - call fatal_error("num_points element must be positive& - & and non-zero!") - else - ! Set the default number of points (0.0625 spacing) - legendre_mu_points = 33 - end if - end if - end if - - ! Get the library's value for the order - if (check_for_node(node_xsdata, "order")) then - call get_node_value(node_xsdata, "order", order) - else - call fatal_error("Order must be provided!") - end if - - ! Before retrieving the data, store the dimensionality of the data in - ! order_dim. For Legendre data, we usually refer to it as Pn where - ! n is the order. However Pn has n+1 sets of points (since you need to - ! the count the P0 moment). Adjust for that. Histogram and Tabular - ! formats dont need this adjustment. - if (this % scatt_type == ANGLE_LEGENDRE) then - order_dim = order + 1 - else - order_dim = order - end if - - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order. We will get it in that format in input_scatt, - ! but then need to convert it to a more useful ordering for processing - ! (Order x Gout x Gin). - allocate(input_scatt(groups, groups, order_dim)) - if (check_for_node(node_xsdata, "scatter")) then - allocate(temp_arr(groups * groups * order_dim)) - call get_node_array(node_xsdata, "scatter", temp_arr) - input_scatt = reshape(temp_arr, (/groups, groups, order_dim/)) - deallocate(temp_arr) - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatt_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - allocate(temp_scatt(groups, groups, order_dim)) - temp_scatt(:, :, :) = input_scatt(:, :, 1:order_dim) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note this is also - ! the default behavior), convert that now. - if (this % scatt_type == ANGLE_LEGENDRE .and. enable_leg_mu) then - ! Convert input parameters to what we need for the rest. - this % scatt_type = ANGLE_TABULAR - order_dim = legendre_mu_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - scatt_coeffs(imu, gout, gin) = & - evaluate_legendre(temp_scatt(gout, gin, :),mu) - ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin) < ZERO) & - scatt_coeffs(imu, gout, gin) = ZERO - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin) + & - scatt_coeffs(imu, gout, gin)) - end if + do t = 1, temps_to_read % size() + associate(xs => this % xs(t)) + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(i))) // "K" + xsdata_grp = open_group(xs_id, trim(temp_str)) + if (this % fissionable) then + allocate(xs % nu_fission(groups)) + allocate(xs % chi(groups,groups)) + if (check_dataset(xsdata_grp, "chi")) then + ! Chi was provided, that means we need chi and nu-fission vectors + ! Get chi + allocate(temp_arr(groups)) + call read_dataset(temp_arr, xsdata_grp, "chi") + do gin = 1, groups + do gout = 1, groups + xs % chi(gout, gin) = temp_arr(gout) + end do + ! Normalize chi so its CDF goes to 1 + xs % chi(:, gin) = xs % chi(:, gin) / sum(xs % chi(:, gin)) end do - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(:, gout, gin) = scatt_coeffs(:, gout, gin) * & - temp_scatt(gout, gin, 1) / norm + deallocate(temp_arr) + + ! Get nu_fission (as a vector) + if (check_dataset(xsdata_grp, "nu-fission")) then + call read_dataset(xs % nu_fission, xsdata_grp, "nu-fission") + else + call fatal_error("If fissionable, must provide nu-fission!") end if - end do - end do - else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - do l = 1, order_dim - scatt_coeffs(l, gout, gin) = temp_scatt(gout, gin, l) + + else + ! chi isnt provided but is within nu_fission, existing as a matrix + ! So, get nu_fission (as a matrix) + if (check_dataset(xsdata_grp, "nu-fission")) then + allocate(temp_2d(groups, groups)) + call read_dataset(temp_2d, xsdata_grp, "nu-fission") + else + call fatal_error("If fissionable, must provide nu-fission!") + end if + + ! Set the vector nu-fission from the matrix nu-fission + do gin = 1, groups + xs % nu_fission(gin) = sum(temp_2d(:, gin)) end do - end do - end do - end if - deallocate(temp_scatt) - else - call fatal_error("Must provide scatter!") - end if - ! Allocate and initialize our ScattData Object. - if (this % scatt_type == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: this % scatter) - else if (this % scatt_type == ANGLE_TABULAR) then - allocate(ScattDataTabular :: this % scatter) - else if (this % scatt_type == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: this % scatter) - end if - - ! Initialize the ScattData Object - call this % scatter % init(temp_mult, scatt_coeffs) - - ! Check sigA to ensure it is not 0 since it is - ! often divided by in the tally routines - ! (This may happen with Helium data) - do gin = 1, groups - if (this % absorption(gin) == ZERO) this % absorption(gin) = 1E-10_8 - end do - - ! Get, or infer, total xs data. - allocate(this % total(groups)) - if (check_for_node(node_xsdata, "total")) then - call get_node_array(node_xsdata, "total", this % total) - else - this % total(:) = this % absorption(:) + this % scatter % scattxs(:) - end if - - ! Deallocate temporaries for the next material - deallocate(input_scatt, scatt_coeffs, temp_mult) - - ! Finally, check sigT to ensure it is not 0 since it is - ! often divided by in the tally routines - do gin = 1, groups - if (this % total(gin) == ZERO) this % total(gin) = 1E-10_8 - end do - - - end subroutine mgxsiso_init_file - - subroutine mgxsang_init_file(this, node_xsdata, groups, get_kfiss, get_fiss, & - max_order) - class(MgxsAngle), intent(inout) :: this ! Working Object - type(Node), pointer, intent(in) :: node_xsdata ! Data from MGXS xml - integer, intent(in) :: groups ! Number of Energy groups - logical, intent(in) :: get_kfiss ! Need Kappa-Fission? - logical, intent(in) :: get_fiss ! Should we get fiss data? - integer, intent(in) :: max_order ! Maximum requested order - - type(Node), pointer :: node_legendre_mu - character(MAX_LINE_LEN) :: temp_str - logical :: enable_leg_mu - real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) - real(8), allocatable :: temp_mult(:, :, :, :) - real(8), allocatable :: scatt_coeffs(:, :, :, :, :) - real(8), allocatable :: input_scatt(:, :, :, :, :) - real(8), allocatable :: temp_scatt(:, :, :, :, :) - real(8) :: dmu, mu, norm, dangle - integer :: order, order_dim, gin, gout, l, arr_len - integer :: legendre_mu_points, imu, ipol, iazi - - ! Call generic data gathering routine (will populate the metadata) - call mgxs_init_file(this, node_xsdata) - - if (check_for_node(node_xsdata, "num_polar")) then - call get_node_value(node_xsdata, "num_polar", this % n_pol) - else - call fatal_error("num_polar must be provided!") - end if - - if (check_for_node(node_xsdata, "num_azimuthal")) then - call get_node_value(node_xsdata, "num_azimuthal", this % n_azi) - else - call fatal_error("num_azimuthal must be provided!") - end if - - ! Load angle data, if present (else equally spaced) - allocate(this % polar(this % n_pol)) - allocate(this % azimuthal(this % n_azi)) - if (check_for_node(node_xsdata, "polar")) then - call fatal_error("User-Specified polar angle bins not yet supported!") - ! When this feature is supported, this line will be activated - call get_node_array(node_xsdata, "polar", this % polar) - else - dangle = PI / real(this % n_pol, 8) - do ipol = 1, this % n_pol - this % polar(ipol) = (real(ipol, 8) - HALF) * dangle - end do - end if - if (check_for_node(node_xsdata, "azimuthal")) then - call fatal_error("User-Specified azimuthal angle bins not yet supported!") - ! When this feature is supported, this line will be activated - call get_node_array(node_xsdata, "azimuthal", this % azimuthal) - else - dangle = TWO * PI / real(this % n_azi, 8) - do iazi = 1, this % n_azi - this % azimuthal(iazi) = -PI + (real(iazi, 8) - HALF) * dangle - end do - end if - - ! Load the more specific data - allocate(this % nu_fission(groups, this % n_azi, this % n_pol)) - allocate(this % chi(groups, groups, this % n_azi, this % n_pol)) - if (this % fissionable) then - if (check_for_node(node_xsdata, "chi")) then - ! Chi was provided, that means they are giving chi and nu-fission - ! vectors - ! Get chi - allocate(temp_arr(1 * groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "chi", temp_arr) - ! Initialize counter for temp_arr - l = 0 - gin = 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gout = 1, groups - l = l + 1 - this % chi(gout, gin, iazi, ipol) = temp_arr(l) - end do + ! Now pull out information needed for chi + xs % chi(:, :) = temp_2d ! Normalize chi so its CDF goes to 1 - this % chi(:, gin, iazi, ipol) = & - this % chi(:, gin, iazi, ipol) / & - sum(this % chi(:, gin, iazi, ipol)) - end do - end do - - ! Now set all the other gin values - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 2, groups - this % chi(:, gin, iazi, ipol) = & - this % chi(:, 1, iazi, ipol) - end do - end do - end do - deallocate(temp_arr) - - ! Get nu_fission (as a vector) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - this % nu_fission(:, :, :) = reshape(temp_arr, (/groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - else - ! chi isnt provided but is within nu_fission, existing as a matrix - ! So, get nu_fission (as a matrix) - if (check_for_node(node_xsdata, "nu_fission")) then - allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "nu_fission", temp_arr) - allocate(temp_4d(groups, groups, this % n_azi,this % n_pol)) - temp_4d(:, :, :, :) = reshape(temp_arr, (/groups, groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("If fissionable, must provide nu_fission!") - end if - - ! Set the vector nu-fission from the matrix nu-fission - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi do gin = 1, groups - this % nu_fission(gin, iazi, ipol) = & - sum(temp_4d(:, gin, iazi, ipol)) + xs % chi(:, gin) = xs % chi(:, gin) / sum(xs % chi(:, gin)) end do - end do - end do + deallocate(temp_2d) + end if - ! Now pull out information needed for chi - this % chi = temp_4d - ! Normalize chi so its CDF goes to 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - this % chi(:, gin, iazi, ipol) = & - this % chi(:, gin, iazi, ipol) / & - sum(this % chi(:, gin, iazi, ipol)) - end do - end do - end do - deallocate(temp_4d) - end if - - ! If we have a need* for the fission and kappa-fission x/s, get them - ! (*Need is defined as will be using it to tally) - if (get_fiss) then - if (check_for_node(node_xsdata, "fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "fission", temp_arr) - allocate(this % fission(groups, this % n_azi, this % n_pol)) - this % fission(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Fission data missing, required due to fission& - & tallies in tallies.xml file!") + ! If we have a need* for the fission and kappa-fission x/s, get them + ! (*Need is defined as will be using it to tally) + if (get_fiss) then + allocate(xs % fission(groups)) + if (check_dataset(xsdata_grp, "fission")) then + call read_dataset(xs % fission, xsdata_grp, "fission") + else + call fatal_error("Fission data missing, required due to fission& + & tallies in tallies.xml file!") + end if + end if + if (get_kfiss) then + allocate(xs % k_fission(groups)) + if (check_dataset(xsdata_grp, "kappa-fission")) then + call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") + else + call fatal_error("kappa-fission data missing, required due to & + &kappa-fission tallies in tallies.xml file!") + end if + end if end if - end if - if (get_kfiss) then - if (check_for_node(node_xsdata, "kappa_fission")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "kappa_fission", temp_arr) - allocate(this % k_fission(groups, this % n_azi, this % n_pol)) - this % k_fission(:, :, :) = reshape(temp_arr, (/groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) + + allocate(xs % absorption(groups)) + if (check_dataset(xsdata_grp, "absorption")) then + call read_dataset(xs % absorption, xsdata_grp, "absorption") else - call fatal_error("kappa_fission data missing, required due to & - &kappa-fission tallies in tallies.xml file!") + call fatal_error("Must provide absorption!") end if - end if - else - this % nu_fission(:, :, :) = ZERO - this % chi(:, :, :, :) = ZERO - end if - if (check_for_node(node_xsdata, "absorption")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "absorption", temp_arr) - allocate(this % absorption(groups, this % n_azi, this % n_pol)) - this % absorption(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Must provide absorption!") - end if - - ! Get multiplication data if present - allocate(temp_mult(groups,groups, this % n_azi, this % n_pol)) - if (check_for_node(node_xsdata, "multiplicity")) then - arr_len = get_arraysize_double(node_xsdata, "multiplicity") - if (arr_len == groups * groups * this % n_azi * this % n_pol) then - allocate(temp_arr(arr_len)) - call get_node_array(node_xsdata, "multiplicity", temp_arr) - temp_mult(:, :, :, :) = reshape(temp_arr, (/groups, groups, & - this % n_azi, this % n_pol/)) - deallocate(temp_arr) - else - call fatal_error("Multiplicity length not same as number of groups& - & squared!") - end if - else - temp_mult(:, :, :, :) = ONE - end if - - ! Get scattering treatment information - ! Tabular_legendre tells us if we are to treat the provided - ! Legendre polynomials as tabular data (if enable is true) or leaving - ! them as Legendres (if enable is false, or the default) - - ! Set the default (leave as Legendre polynomials) - enable_leg_mu = .false. - if (check_for_node(node_xsdata, "tabular_legendre")) then - call get_node_ptr(node_xsdata, "tabular_legendre", node_legendre_mu) - if (check_for_node(node_legendre_mu, "enable")) then - call get_node_value(node_legendre_mu, "enable", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'true' .or. temp_str == '1') then - enable_leg_mu = .true. - elseif (temp_str == 'false' .or. temp_str == '0') then - enable_leg_mu = .false. + ! Get multiplication data if present + allocate(temp_mult(groups, groups)) + if (check_dataset(xsdata_grp, "multiplicity matrix")) then + call read_dataset(temp_mult, xsdata_grp, "multiplicity matrix") else - call fatal_error("Unrecognized tabular_legendre/enable: " & - // temp_str) + temp_mult(:, :) = ONE end if - end if - ! Ok, so if we need to convert to a tabular form, get the user provided - ! number of points - if (enable_leg_mu) then - if (check_for_node(node_legendre_mu, "num_points")) then - call get_node_value(node_legendre_mu, "num_points", & - legendre_mu_points) - if (legendre_mu_points <= 0) & - call fatal_error("num_points element must be positive& - & and non-zero!") - else - ! Set the default number of points (0.0625 spacing) - legendre_mu_points = 33 - end if - end if - end if - ! Get the library's value for the order - if (check_for_node(node_xsdata, "order")) then - call get_node_value(node_xsdata, "order", order) - else - call fatal_error("Order must be provided!") - end if + ! Get scattering data + ! The input is gathered in the more user-friendly facing format of + ! Gout x Gin x Order. We will get it in that format in input_scatt, + ! but then need to convert it to a more useful ordering for processing + ! (Order x Gout x Gin). + allocate(input_scatt(groups, groups, order_dim)) + if (check_dataset(xsdata_grp, "scatter matrix")) then + call read_dataset(input_scatt, xsdata_grp, "scatter matrix") - ! Before retrieving the data, store the dimensionality of the data in - ! order_dim. For Legendre data, we usually refer to it as Pn where - ! n is the order. However Pn has n+1 sets of points (since you need to - ! the count the P0 moment). Adjust for that. Histogram and Tabular - ! formats dont need this adjustment. - if (this % scatt_type == ANGLE_LEGENDRE) then - order_dim = order + 1 - else - order_dim = order - end if + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + allocate(temp_scatt(groups, groups, order_dim)) + temp_scatt(:, :, :) = input_scatt(:, :, 1:order_dim) - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order x Azi x Pol. We will get it in that format in - ! input_scatt, but then need to convert it to a more useful ordering - ! for processing (Order x Gout x Gin x Azi x Pol). - allocate(input_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - if (check_for_node(node_xsdata, "scatter")) then - allocate(temp_arr(groups * groups * order_dim * this % n_azi * & - this % n_pol)) - call get_node_array(node_xsdata, "scatter", temp_arr) - input_scatt(:, :, :, :, :) = reshape(temp_arr, (/groups, groups, & - order_dim, this % n_azi, this % n_pol/)) - deallocate(temp_arr) + ! Take input format (groups, groups, order) and convert to + ! the more useful format needed for scattdata: (order, groups, groups) + ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was + ! provided as Legendre coefficients), and the user requested that + ! these legendres be converted to tabular form (note xs is also + ! the default behavior), convert that now. + if (this % scatter_type == ANGLE_LEGENDRE .and. enable_leg_mu) then + ! Convert input parameters to what we need for the rest. + this % scatter_type = ANGLE_TABULAR + order_dim = legendre_mu_points + order = order_dim + dmu = TWO / real(order - 1, 8) - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatt_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - - allocate(temp_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - temp_scatt(:, :, :, :, :) = input_scatt(:, :, 1:order_dim, :, :) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note this is also - ! the default behavior), convert that now. - if (this % scatt_type == ANGLE_LEGENDRE .and. enable_leg_mu) then - - ! Convert input parameters to what we need for the rest. - this % scatt_type = ANGLE_TABULAR - order_dim = legendre_mu_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi + allocate(scatt_coeffs(order_dim, groups, groups)) do gin = 1, groups do gout = 1, groups norm = ZERO @@ -857,371 +522,476 @@ module mgxs_header else mu = -ONE + real(imu - 1, 8) * dmu end if - scatt_coeffs(imu, gout, gin, iazi, ipol) = & - evaluate_legendre(temp_scatt(gout, gin, :, iazi, ipol), mu) + scatt_coeffs(imu, gout, gin) = & + evaluate_legendre(temp_scatt(gout, gin, :),mu) ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin, iazi, ipol) < ZERO) & - scatt_coeffs(imu, gout, gin, iazi, ipol) = ZERO + if (scatt_coeffs(imu, gout, gin) < ZERO) & + scatt_coeffs(imu, gout, gin) = ZERO ! And accrue the integral if (imu > 1) then norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin, iazi, ipol) + & - scatt_coeffs(imu, gout, gin, iazi, ipol)) + (scatt_coeffs(imu - 1, gout, gin) + & + scatt_coeffs(imu, gout, gin)) end if - end do + end do ! mu ! Now that we have the integral, lets ensure that the distribution ! is normalized such that it preserves the original scattering xs if (norm > ZERO) then - scatt_coeffs(:, gout, gin, iazi, ipol) = & - scatt_coeffs(:, gout, gin, iazi, ipol) * & - temp_scatt(gout, gin, 1, iazi, ipol) / norm + scatt_coeffs(:, gout, gin) = scatt_coeffs(:, gout, gin) * & + temp_scatt(gout, gin, 1) / norm end if - end do - end do - end do - end do - else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi + end do ! gout + end do ! gin + else + ! Sticking with current representation, carry forward but change + ! the array ordering + allocate(scatt_coeffs(order_dim, groups, groups)) do gin = 1, groups do gout = 1, groups do l = 1, order_dim - scatt_coeffs(l, gout, gin, iazi, ipol) = & - temp_scatt(gout, gin, l, iazi, ipol) + scatt_coeffs(l, gout, gin) = temp_scatt(gout, gin, l) end do end do end do - end do - end do - end if - deallocate(temp_scatt) - else - call fatal_error("Must provide scatter!") - end if + end if + deallocate(temp_scatt) + else + call fatal_error("Must provide scatter matrix!") + end if - allocate(this % scatter(this % n_azi, this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi ! Allocate and initialize our ScattData Object. - if (this % scatt_type == ANGLE_HISTOGRAM) then - allocate(ScattDataHistogram :: this % scatter(iazi, ipol) % obj) - else if (this % scatt_type == ANGLE_TABULAR) then - allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj) - else if (this % scatt_type == ANGLE_LEGENDRE) then - allocate(ScattDataLegendre :: this % scatter(iazi, ipol) % obj) + if (this % scatter_type == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: xs % scatter) + else if (this % scatter_type == ANGLE_TABULAR) then + allocate(ScattDataTabular :: xs % scatter) + else if (this % scatter_type == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: xs % scatter) end if ! Initialize the ScattData Object - call this % scatter(iazi, ipol) % obj % init(& - temp_mult(:, :, iazi, ipol), & - scatt_coeffs(:, :, :, iazi, ipol)) - end do - end do - ! Deallocate temporaries for the next material - deallocate(input_scatt, scatt_coeffs, temp_mult) + call xs % scatter % init(temp_mult, scatt_coeffs) - allocate(this % total(groups, this % n_azi, this % n_pol)) - if (check_for_node(node_xsdata, "total")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call get_node_array(node_xsdata, "total", temp_arr) - this % total(:, :, :) = reshape(temp_arr, (/groups, this % n_azi, & - this % n_pol/)) - deallocate(temp_arr) - else - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - this % total(:, iazi, ipol) = this % absorption(:, iazi, ipol) + & - this % scatter(iazi, ipol) % obj % scattxs(:) + ! Check sigA to ensure it is not 0 since it is + ! often divided by in the tally routines + ! (This may happen with Helium data) + do gin = 1, groups + if (xs % absorption(gin) == ZERO) xs % absorption(gin) = 1E-10_8 end do - end do - end if - end subroutine mgxsang_init_file - -!=============================================================================== -! MGXS*_GET_XS returns the requested data cross section data -!=============================================================================== - - pure function mgxsiso_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) - class(MgxsIso), intent(in) :: this ! The Mgxs to initialize - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Requested x/s - - select case(xstype) - case('total') - xs = this % total(gin) - case('absorption') - xs = this % absorption(gin) - case('fission') - if (allocated(this % fission)) then - xs = this % fission(gin) - else - xs = ZERO - end if - case('kappa_fission') - if (allocated(this % k_fission)) then - xs = this % k_fission(gin) - else - xs = ZERO - end if - case('nu_fission') - xs = this % nu_fission(gin) - case('chi') - if (present(gout)) then - xs = this % chi(gout,gin) - else - ! Not sure youd want a 1 or a 0, but here you go! - xs = sum(this % chi(:, gin)) - end if - case('scatter') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO + ! Get, or infer, total xs data. + allocate(xs % total(groups)) + if (check_dataset(xsdata_grp, "total")) then + call read_dataset(xs % total, xsdata_grp, "total") else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) + xs % total(:) = xs % absorption(:) + xs % scatter % scattxs(:) end if - else - xs = this % scatter % scattxs(gin) - end if - case('scatter/mult') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) / & - this % scatter % mult(gin) % data(gout) - end if - else - xs = this % scatter % scattxs(gin) / & - (dot_product(this % scatter % mult(gin) % data, & - this % scatter % energy(gin) % data)) - end if - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % scatter % gmin(gin) .or. & - gout > this % scatter % gmax(gin)) then - xs = ZERO - else - xs = this % scatter % scattxs(gin) * & - this % scatter % energy(gin) % data(gout) * & - this % scatter % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / this % scatter % mult(gin) % data(gout) - end if - end if - else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. - end if - case default - xs = ZERO - end select - end function mgxsiso_get_xs + ! Finally, check sigT to ensure it is not 0 since it is + ! often divided by in the tally routines + do gin = 1, groups + if (xs % total(gin) == ZERO) xs % total(gin) = 1E-10_8 + end do - pure function mgxsang_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) - class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize - character(*) , intent(in) :: xstype ! Type of xs requested - integer, intent(in) :: gin ! Incoming Energy group - integer, optional, intent(in) :: gout ! Outgoing Energy group - real(8), optional, intent(in) :: uvw(3) ! Requested Angle - real(8), optional, intent(in) :: mu ! Change in angle - real(8) :: xs ! Requested x/s + ! Close the groups we have opened and deallocate + call close_group(xsdata_grp) + deallocate(input_scatt, scatt_coeffs, temp_mult) + end associate ! xs + end do ! Temperatures + end subroutine mgxsiso_from_hdf5 - integer :: iazi, ipol + subroutine mgxsang_from_hdf5(this, xs_id, groups, temperature, method, & + tolerance, get_kfiss, get_fiss, max_order) + class(MgxsAngle), intent(inout) :: this ! Working Object + integer(HID_T), intent(in) :: xs_id ! Group in H5 file + integer, intent(in) :: groups ! Number of Energy groups + type(VectorReal), intent(in) :: temperature ! list of desired temperatures + integer, intent(in) :: method ! Type of temperature access + real(8), intent(in) :: tolerance ! Tolerance on method + logical, intent(in) :: get_kfiss ! Need Kappa-Fission? + logical, intent(in) :: get_fiss ! Should we get fiss data? + integer, intent(in) :: max_order ! Maximum requested order + + character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp + logical :: enable_leg_mu + real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) + real(8), allocatable :: temp_mult(:, :, :, :) + real(8), allocatable :: scatt_coeffs(:, :, :, :, :) + real(8), allocatable :: input_scatt(:, :, :, :, :) + real(8), allocatable :: temp_scatt(:, :, :, :, :) + real(8) :: dmu, mu, norm, dangle + integer :: order, order_dim, gin, gout, l, arr_len + integer :: legendre_mu_points, imu, ipol, iazi + type(VectorInt) :: temps_to_read + integer :: t + + ! Call generic data gathering routine (will populate the metadata) + call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & + temps_to_read, order_dim) + !!!TODO: Fix + enable_leg_mu = .True. + + ! Load the more specific data + do t = 1, temps_to_read % size() + associate(xs => this % xs(t)) + ! Get temperature as a string + temp_str = trim(to_str(temps_to_read % data(i))) // "K" + xsdata_grp = open_group(xs_id, trim(temp_str)) + if (this % fissionable) then + if (check_dataset(xsdata_grp, "chi")) then + ! Chi was provided, that means we need chi and nu-fission vectors + ! Get chi + allocate(temp_arr(1 * groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "chi") + ! Initialize counter for temp_arr + l = 0 + gin = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gout = 1, groups + l = l + 1 + xs % chi(gout, gin, iazi, ipol) = temp_arr(l) + end do + ! Normalize chi so its CDF goes to 1 + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, gin, iazi, ipol) / & + sum(xs % chi(:, gin, iazi, ipol)) + end do + end do + + ! Now set all the other gin values + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 2, groups + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, 1, iazi, ipol) + end do + end do + end do + deallocate(temp_arr) + + ! Get nu_fission (as a vector) + if (check_dataset(xsdata_grp, "nu-fission")) then + call read_dataset(xs % nu_fission, xsdata_grp, "nu-fission") + else + call fatal_error("If fissionable, must provide nu-fission!") + end if - if (present(uvw)) then - call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - select case(xstype) - case('total') - xs = this % total(gin, iazi, ipol) - case('absorption') - xs = this % absorption(gin, iazi, ipol) - case('fission') - if (allocated(this % fission)) then - xs = this % fission(gin, iazi, ipol) - else - xs = ZERO - end if - case('kappa_fission') - if (allocated(this % k_fission)) then - xs = this % k_fission(gin, iazi, ipol) - else - xs = ZERO - end if - case('nu_fission') - xs = this % nu_fission(gin, iazi, ipol) - case('chi') - if (present(gout)) then - xs = this % chi(gout, gin, iazi, ipol) - else - ! Not sure you would want a 1 or a 0, but here you go! - xs = sum(this % chi(:, gin, iazi, ipol)) - end if - case('scatter') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + ! chi isnt provided but is within nu_fission, existing as a matrix + ! So, get nu_fission (as a matrix) + if (check_dataset(xsdata_grp, "nu-fission")) then + allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "nu-fission") + allocate(temp_4d(groups, groups, this % n_azi,this % n_pol)) + temp_4d(:, :, :, :) = reshape(temp_arr, (/groups, groups, & + this % n_azi, this % n_pol/)) + deallocate(temp_arr) + else + call fatal_error("If fissionable, must provide nu-fission!") + end if + + ! Set the vector nu-fission from the matrix nu-fission + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + xs % nu_fission(gin, iazi, ipol) = & + sum(temp_4d(:, gin, iazi, ipol)) + end do + end do + end do + + ! Now pull out information needed for chi + xs % chi = temp_4d + ! Normalize chi so its CDF goes to 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + xs % chi(:, gin, iazi, ipol) = & + xs % chi(:, gin, iazi, ipol) / & + sum(xs % chi(:, gin, iazi, ipol)) + end do + end do + end do + deallocate(temp_4d) end if - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) - end if - case('scatter/mult') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) / & - this % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + + ! If we have a need* for the fission and kappa-fission x/s, get them + ! (*Need is defined as will be using it to tally) + if (get_fiss) then + if (check_dataset(xsdata_grp, "fission")) then + allocate(xs % fission(groups, this % n_azi, this % n_pol)) + call read_dataset(xs % fission, xsdata_grp, "fission") + else + call fatal_error("Fission data missing, required due to fission& + & tallies in tallies.xml file!") + end if end if - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) / & - (dot_product(this % scatter(iazi, ipol) % obj % mult(gin) % data, & - this % scatter(iazi, ipol) % obj % energy(gin) % data)) - end if - case('scatter*f_mu/mult','scatter*f_mu') - if (present(gout)) then - if (gout < this % scatter(iazi, ipol) % obj % gmin(gin) .or. & - gout > this % scatter(iazi, ipol) % obj % gmax(gin)) then - xs = ZERO - else - xs = this % scatter(iazi, ipol) % obj % scattxs(gin) * & - this % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - xs = xs * this % scatter(iazi, ipol) % obj % calc_f(gin, gout, mu) - if (xstype == 'scatter*f_mu/mult') then - xs = xs / & - this % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + if (get_kfiss) then + if (check_dataset(xsdata_grp, "kappa-fission")) then + allocate(xs % k_fission(groups, this % n_azi, this % n_pol)) + call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") + else + call fatal_error("kappa_fission data missing, required due to & + &kappa-fission tallies in tallies.xml file!") end if end if else - xs = ZERO - ! TODO (Not likely needed) - ! (asking for f_mu without asking for a group or mu would mean the - ! user of this code wants the complete 1-outgoing group distribution - ! which Im not sure what they would do with that. + xs % nu_fission(:, :, :) = ZERO + xs % chi(:, :, :, :) = ZERO end if - case default - xs = ZERO - end select - else - xs = ZERO - end if - end function mgxsang_get_xs + if (check_dataset(xsdata_grp, "absorption")) then + allocate(xs % absorption(groups, this % n_azi, this % n_pol)) + call read_dataset(xs % absorption, xsdata_grp, "absorption") + else + call fatal_error("Must provide absorption!") + end if + + ! Get multiplication data if present + allocate(temp_mult(groups,groups, this % n_azi, this % n_pol)) + if (check_dataset(xsdata_grp, "multiplicity matrix")) then + call read_dataset(temp_mult, xsdata_grp, "multiplicity matrix") + else + temp_mult(:, :, :, :) = ONE + end if + + ! Get scattering data + ! The input is gathered in the more user-friendly facing format of + ! Gout x Gin x Order x Azi x Pol. We will get it in that format in + ! input_scatt, but then need to convert it to a more useful ordering + ! for processing (Order x Gout x Gin x Azi x Pol). + allocate(input_scatt(groups, groups, order_dim, this % n_azi, & + this % n_pol)) + if (check_dataset(xsdata_grp, "scatter matrix")) then + allocate(temp_arr(groups * groups * order_dim * this % n_azi * & + this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "scatter matrix") + input_scatt(:, :, :, :, :) = reshape(temp_arr, (/groups, groups, & + order_dim, this % n_azi, this % n_pol/)) + deallocate(temp_arr) + + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + + allocate(temp_scatt(groups, groups, order_dim, this % n_azi, & + this % n_pol)) + temp_scatt(:, :, :, :, :) = input_scatt(:, :, 1:order_dim, :, :) + + ! Take input format (groups, groups, order) and convert to + ! the more useful format needed for scattdata: (order, groups, groups) + ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was + ! provided as Legendre coefficients), and the user requested that + ! these legendres be converted to tabular form (note xs is also + ! the default behavior), convert that now. + if (this % scatter_type == ANGLE_LEGENDRE .and. enable_leg_mu) then + + ! Convert input parameters to what we need for the rest. + this % scatter_type = ANGLE_TABULAR + order_dim = legendre_mu_points + order = order_dim + dmu = TWO / real(order - 1, 8) + + allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & + this % n_pol)) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + do gout = 1, groups + norm = ZERO + do imu = 1, order_dim + if (imu == 1) then + mu = -ONE + else if (imu == order_dim) then + mu = ONE + else + mu = -ONE + real(imu - 1, 8) * dmu + end if + scatt_coeffs(imu, gout, gin, iazi, ipol) = & + evaluate_legendre(temp_scatt(gout, gin, :, iazi, ipol), mu) + ! Ensure positivity of distribution + if (scatt_coeffs(imu, gout, gin, iazi, ipol) < ZERO) & + scatt_coeffs(imu, gout, gin, iazi, ipol) = ZERO + ! And accrue the integral + if (imu > 1) then + norm = norm + HALF * dmu * & + (scatt_coeffs(imu - 1, gout, gin, iazi, ipol) + & + scatt_coeffs(imu, gout, gin, iazi, ipol)) + end if + end do + ! Now that we have the integral, lets ensure that the distribution + ! is normalized such that it preserves the original scattering xs + if (norm > ZERO) then + scatt_coeffs(:, gout, gin, iazi, ipol) = & + scatt_coeffs(:, gout, gin, iazi, ipol) * & + temp_scatt(gout, gin, 1, iazi, ipol) / norm + end if + end do + end do + end do + end do + else + ! Sticking with current representation, carry forward but change + ! the array ordering + allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & + this % n_pol)) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + do gout = 1, groups + do l = 1, order_dim + scatt_coeffs(l, gout, gin, iazi, ipol) = & + temp_scatt(gout, gin, l, iazi, ipol) + end do + end do + end do + end do + end do + end if + deallocate(temp_scatt) + else + call fatal_error("Must provide scatter matrix!") + end if + + allocate(xs % scatter(this % n_azi, this % n_pol)) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + ! Allocate and initialize our ScattData Object. + if (this % scatter_type == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: xs % scatter(iazi, ipol) % obj) + else if (this % scatter_type == ANGLE_TABULAR) then + allocate(ScattDataTabular :: xs % scatter(iazi, ipol) % obj) + else if (this % scatter_type == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: xs % scatter(iazi, ipol) % obj) + end if + + ! Initialize the ScattData Object + call xs % scatter(iazi, ipol) % obj % init(& + temp_mult(:, :, iazi, ipol), & + scatt_coeffs(:, :, :, iazi, ipol)) + end do + end do + + allocate(xs % total(groups, this % n_azi, this % n_pol)) + if (check_dataset(xsdata_grp, "total")) then + call read_dataset(xs % total, xsdata_grp, "total") + else + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + xs % total(:, iazi, ipol) = xs % absorption(:, iazi, ipol) + & + xs % scatter(iazi, ipol) % obj % scattxs(:) + end do + end do + end if + + ! Close the groups we have opened and deallocate + call close_group(xsdata_grp) + deallocate(input_scatt, scatt_coeffs, temp_mult) + end associate ! xs + end do ! Temperatures + end subroutine mgxsang_from_hdf5 !=============================================================================== -! MACROXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs -! objects +! MGXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs objects !=============================================================================== - subroutine mgxs_combine(this, mat, scatt_type) + subroutine mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) class(Mgxs), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material - integer, intent(in) :: scatt_type ! How is data presented + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(out) :: scatter_type ! Type of scatter + integer, intent(out) :: order_dim ! Scattering data order size + + integer :: t, mat_max_order, max_order, order, n_pol, n_azi + real(8) :: dangle ! Fill in meta-data from material information if (mat % name == "") then - this % name = trim(to_str(mat % id)) + this % name = trim(to_str(mat % id)) else - this % name = mat % name + this % name = mat % name end if this % fissionable = mat % fissionable - this % scatt_type = scatt_type ! The following info we should initialize, but we dont need it nor ! does it have guaranteed meaning. this % awr = -ONE - this % kT = -ONE - end subroutine mgxs_combine + allocate(this % kTs(temps % size())) + do t = 1, temps % size() + this % kTs(t) = temps % data(i) + end do - subroutine mgxsiso_combine(this, mat, nuclides, groups, max_order, scatt_type) - class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize - type(Material), pointer, intent(in) :: mat ! base material - type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from - integer, intent(in) :: groups ! Number of E groups - integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! How is data presented - - integer :: i ! loop index over nuclides - integer :: gin, gout ! group indices - real(8) :: atom_density ! atom density of a nuclide - real(8) :: norm, nuscatt - integer :: mat_max_order, order, order_dim, nuc_order_dim - real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) - real(8), allocatable :: scatt_coeffs(:, :, :) - - ! Set the meta-data - call mgxs_combine(this, mat, scatt_type) + ! Allocate the XS object for the number of temperatures + select type(this) + type is (MgxsIso) + allocate(this % xs(temps % size())) + type is (MgxsAngle) + allocate(this % xs(temps % size())) + end select ! Determine the scattering type of our data and ensure all scattering orders ! are the same. + scatter_type = nuclides(mat % nuclide(1)) % obj % scatter_type select type(nuc => nuclides(mat % nuclide(1)) % obj) type is (MgxsIso) - order = size(nuc % scatter % dist(1) % data, dim=1) + order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) + type is (MgxsAngle) + order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) end select ! If we have tabular only data, then make sure all datasets have same size - if (scatt_type == ANGLE_HISTOGRAM) then + if (scatter_type == ANGLE_HISTOGRAM) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (order /= size(nuc % scatter % dist(1) % data, dim=1)) & + if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & + call fatal_error("All histogram scattering entries must be& + & same length!") + type is (MgxsAngle) + if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & call fatal_error("All histogram scattering entries must be& & same length!") end select end do ! Ok, got our order, store the dimensionality order_dim = order - - ! Set our Scatter Object Type - allocate(ScattDataHistogram :: this % scatter) - - else if (scatt_type == ANGLE_TABULAR) then + else if (scatter_type == ANGLE_TABULAR) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (order /= size(nuc % scatter % dist(1) % data, dim=1)) & + if (order /= size(nuc % xs(1) % scatter % dist(1) % data, dim=1)) & + call fatal_error("All tabular scattering entries must be& + & same length!") + type is (MgxsAngle) + if (order /= size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1)) & call fatal_error("All tabular scattering entries must be& & same length!") end select end do ! Ok, got our order, store the dimensionality order_dim = order - - ! Set our Scatter Object Type - allocate(ScattDataTabular :: this % scatter) - - else if (scatt_type == ANGLE_LEGENDRE) then + else if (scatter_type == ANGLE_LEGENDRE) then ! Need to determine the maximum scattering order of all data in this material mat_max_order = 0 do i = 1, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (size(nuc % scatter % dist(1) % data, dim=1) > mat_max_order) & - mat_max_order = size(nuc % scatter % dist(1) % data, dim=1) + if (size(nuc % xs(1) % scatter % dist(1) % data, dim=1) > & + mat_max_order) & + mat_max_order = size(nuc % xs(1) % scatter % dist(1) % data, & + dim=1) + type is (MgxsAngle) + if (size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) > & + mat_max_order) & + mat_max_order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & + dim=1) end select end do @@ -1230,135 +1000,190 @@ module mgxs_header order = min(mat_max_order, max_order) ! Ok, got our order, store the dimensionality order_dim = order + 1 - - ! Set our Scatter Object Type - allocate(ScattDataLegendre :: this % scatter) end if - ! Allocate and initialize data needed for macro_xs(i_mat) object - allocate(this % total(groups)) - this % total(:) = ZERO - allocate(this % absorption(groups)) - this % absorption(:) = ZERO - allocate(this % fission(groups)) - this % fission(:) = ZERO - allocate(this % k_fission(groups)) - this % k_fission(:) = ZERO - allocate(this % nu_fission(groups)) - this % nu_fission(:) = ZERO - allocate(this % chi(groups,groups)) - this % chi(:, :) = ZERO - allocate(temp_mult(groups,groups)) - temp_mult(:, :) = ZERO - allocate(mult_num(groups,groups)) - mult_num(:, :) = ZERO - allocate(mult_denom(groups,groups)) - mult_denom(:, :) = ZERO - allocate(scatt_coeffs(order_dim,groups,groups)) - scatt_coeffs(:, :, :) = ZERO + end subroutine mgxs_combine - ! Add contribution from each nuclide in material - do i = 1, mat % n_nuclides - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - ! Perform our operations which depend upon the type - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - ! Add contributions to total, absorption, and fission data (if necessary) - this % total(:) = this % total(:) + atom_density * nuc % total(:) - this % absorption(:) = this % absorption(:) + & - atom_density * nuc % absorption(:) - if (nuc % fissionable) then - this % chi(:, :) = this % chi(:, :) + atom_density * nuc % chi(:, :) - this % nu_fission(:) = this % nu_fission(:)+ atom_density * & - nuc % nu_fission(:) - if (allocated(nuc % fission)) then - this % fission(:) = this % fission(:) + atom_density * nuc % fission(:) - end if - if (allocated(nuc % k_fission)) then - this % k_fission(:) = this % k_fission(:) + atom_density * & - nuc % k_fission(:) - end if - end if - - ! Get the multiplication matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do gin = 1, groups - do gout = nuc % scatter % gmin(gin), nuc % scatter % gmax(gin) - nuscatt = nuc % scatter % scattxs(gin) * & - nuc % scatter % energy(gin) % data(gout) - mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & - nuscatt - if (nuc % scatter % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & - nuscatt / nuc % scatter % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density - end if - end do - end do - - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % scatter % dist(1) % data, dim=1) - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) + & - atom_density * & - nuc % scatter % get_matrix(min(nuc_order_dim, order_dim)) - - type is (MgxsAngle) - call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") - end select - end do - - ! Obtain temp_mult - do gin = 1, groups - do gout = 1, groups - if (mult_denom(gout, gin) > ZERO) then - temp_mult(gout, gin) = mult_num(gout, gin) / mult_denom(gout, gin) - else - temp_mult(gout, gin) = ONE - end if - end do - end do - - ! Initialize the ScattData Object - call this % scatter % init(temp_mult, scatt_coeffs) - - ! Now normalize chi - if (mat % fissionable) then - do gin = 1, groups - norm = sum(this % chi(:, gin)) - if (norm > ZERO) then - this % chi(:, gin) = this % chi(:, gin) / norm - end if - end do - end if - - ! Deallocate temporaries - deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) - - end subroutine mgxsiso_combine - - subroutine mgxsang_combine(this, mat, nuclides, groups, max_order, scatt_type) - class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize + subroutine mgxsiso_combine(this, temps, mat, nuclides, groups, max_order) + class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain + type(Material), pointer, intent(in) :: mat ! base material + type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: groups ! Number of E groups + integer, intent(in) :: max_order ! Maximum requested order + + integer :: i ! loop index over nuclides + integer :: t ! Index in to temps + integer :: gin, gout ! group indices + real(8) :: atom_density ! atom density of a nuclide + real(8) :: norm, nuscatt + integer :: mat_max_order, order, order_dim, nuc_order_dim + real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) + real(8), allocatable :: scatt_coeffs(:, :, :) + integer :: nuc_t + real(8) :: temp_actual, temp_desired + integer :: scatter_type + + ! Set the meta-data + call mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) + + ! Create the Xs Data for each temperature + TEMP_LOOP: do t = 1, temps % size() + ! Allocate and initialize the data needed for macro_xs(i_mat) object + allocate(this % xs(t) % total(groups)) + this % xs(t) % total(:) = ZERO + allocate(this % xs(t) % absorption(groups)) + this % xs(t) % absorption(:) = ZERO + allocate(this % xs(t) % fission(groups)) + this % xs(t) % fission(:) = ZERO + allocate(this % xs(t) % k_fission(groups)) + this % xs(t) % k_fission(:) = ZERO + allocate(this % xs(t) % nu_fission(groups)) + this % xs(t) % nu_fission(:) = ZERO + allocate(this % xs(t) % chi(groups,groups)) + this % xs(t) % chi(:, :) = ZERO + allocate(temp_mult(groups,groups)) + temp_mult(:, :) = ZERO + allocate(mult_num(groups,groups)) + mult_num(:, :) = ZERO + allocate(mult_denom(groups,groups)) + mult_denom(:, :) = ZERO + allocate(scatt_coeffs(order_dim,groups,groups)) + scatt_coeffs(:, :, :) = ZERO + + if (scatter_type == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: this % xs(t) % scatter) + else if (scatter_type == ANGLE_TABULAR) then + allocate(ScattDataTabular :: this % xs(t) % scatter) + else if (scatter_type == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: this % xs(t) % scatter) + end if + + ! Add contribution from each nuclide in material + NUC_LOOP: do i = 1, mat % n_nuclides + associate(nuc => nuclides(mat % nuclide(i)) % obj) + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + temp_desired = temps % data(i) + nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(i_closest) + if (abs(temp_actual - temp_desired) >= tolerance) then + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired))) // " K.") + end if + + case (TEMPERATURE_INTERPOLATION) + ! TODO: Get bounding temperatures + call fatal_error("Temperature interpolation not yet implemented") + end select + + ! Copy atom density of nuclide in material + atom_density = mat % atom_density(i) + + select type(nuc) + type is (MgxsIso) + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data (if necessary) + this % xs(t) % total(:) = this % xs(t) % total(:) + & + atom_density * nuc % xs(nuc_t) % total(:) + this % xs(t) % absorption(:) = this % xs(t) % absorption(:) + & + atom_density * nuc % xs(nuc_t) % absorption(:) + if (nuc % fissionable) then + this % xs(t) % chi(:, :) = this % xs(t) % chi(:, :) + & + atom_density * nuc % xs(nuc_t) % chi(:, :) + this % xs(t) % nu_fission(:) = this % xs(t) % nu_fission(:) + & + atom_density * nuc % xs(nuc_t) % nu_fission(:) + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission(:) = this % xs(t) % fission(:) + & + atom_density * nuc % xs(nuc_t) % fission(:) + end if + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission(:) = this % xs(t) % k_fission(:) + & + atom_density * nuc % xs(nuc_t) % k_fission(:) + end if + end if + + ! Get the multiplication matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), nuc % xs(nuc_t) % scatter % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter % scattxs(gin) * & + nuc % xs(nuc_t) % scatter % energy(gin) % data(gout) + mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & + nuscatt + if (nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) > ZERO) then + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & + nuscatt / nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) + else + ! Avoid division by zero + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density + end if + end do + end do + + ! Get the complete scattering matrix + nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) + scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) = & + scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) + & + atom_density * & + nuc % xs(nuc_t) % scatter % get_matrix(min(nuc_order_dim, order_dim)) + type is (MgxsAngle) + call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") + end select + + ! Obtain temp_mult + do gin = 1, groups + do gout = 1, groups + if (mult_denom(gout, gin) > ZERO) then + temp_mult(gout, gin) = mult_num(gout, gin) / mult_denom(gout, gin) + else + temp_mult(gout, gin) = ONE + end if + end do + end do + + ! Initialize the ScattData Object + call this % xs(t) % scatter % init(temp_mult, scatt_coeffs) + + ! Now normalize chi + if (mat % fissionable) then + do gin = 1, groups + norm = sum(this % xs(t) % chi(:, gin)) + if (norm > ZERO) then + this % xs(t) % chi(:, gin) = this % xs(t) % chi(:, gin) / norm + end if + end do + end if + + ! Deallocate temporaries + deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) + end associate ! nuc + end do NUC_LOOP + end do TEMP_LOOP + + end subroutine mgxsiso_combine + + subroutine mgxsang_combine(this, temps, mat, nuclides, groups, max_order) + class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize + type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups integer, intent(in) :: max_order ! Maximum requested order - integer, intent(in) :: scatt_type ! Legendre or Tabular Scatt? integer :: i ! loop index over nuclides + integer :: t ! temperature loop index integer :: gin, gout ! group indices real(8) :: atom_density ! atom density of a nuclide integer :: ipol, iazi, n_pol, n_azi @@ -1366,9 +1191,12 @@ module mgxs_header integer :: mat_max_order, order, order_dim, nuc_order_dim real(8), allocatable :: temp_mult(:, :, :, :), mult_num(:, :, :, :) real(8), allocatable :: mult_denom(:, :, :, :), scatt_coeffs(:, :, :, :, :) + integer :: nuc_t + real(8) :: temp_actual, temp_desired + integer :: scatter_type ! Set the meta-data - call mgxs_combine(this, mat, scatt_type) + call mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) ! Get the number of each polar and azi angles and make sure all the ! NuclideAngle types have the same number of these angles @@ -1392,266 +1220,419 @@ module mgxs_header end select end do - ! Determine the scattering type of our data and ensure all scattering orders - ! are the same. - select type(nuc => nuclides(mat % nuclide(1)) % obj) - type is (MgxsAngle) - order = size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1) - end select - ! If we have tabular only data, then make sure all datasets have same size - if (scatt_type == ANGLE_HISTOGRAM) then - ! Check all scattering data to ensure it is the same size - ! order = size(nuclides(mat % nuclide(1)) % obj % scatter % data,dim=1) - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (order /= size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All histogram scattering entries must be& - & same length!") - end select - end do - ! Ok, got our order, store the dimensionality - order_dim = order + ! Create the Xs Data for each temperature + TEMP_LOOP: do t = 1, temps % size() + ! Allocate and initialize the data needed for macro_xs(i_mat) object + allocate(this % xs(t) % total(n_azi, n_pol, groups)) + this % xs(t) % total = ZERO + allocate(this % xs(t) % absorption(n_azi, n_pol, groups)) + this % xs(t) % absorption = ZERO + allocate(this % xs(t) % fission(n_azi, n_pol, groups)) + this % xs(t) % fission = ZERO + allocate(this % xs(t) % k_fission(n_azi, n_pol, groups)) + this % xs(t) % k_fission = ZERO + allocate(this % xs(t) % nu_fission(n_azi, n_pol, groups)) + this % xs(t) % nu_fission = ZERO + allocate(this % xs(t) % chi(n_azi, n_pol, groups, groups)) + this % xs(t) % chi = ZERO + allocate(temp_mult(n_azi, n_pol, groups, groups)) + temp_mult = ZERO + allocate(mult_num(n_azi, n_pol, groups, groups)) + mult_num = ZERO + allocate(mult_denom(n_azi, n_pol, groups, groups)) + mult_denom = ZERO + allocate(scatt_coeffs(n_azi, n_pol, order_dim, groups, groups)) + scatt_coeffs = ZERO - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) + allocate(this % xs(t) % scatter(n_azi, n_pol)) do ipol = 1, n_pol do iazi = 1, n_azi - allocate(ScattDataHistogram :: this % scatter(iazi, ipol) % obj) - end do - end do - - else if (scatt_type == ANGLE_TABULAR) then - ! Check all scattering data to ensure it is the same size - do i = 2, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (order /= size(nuc % scatter(1, 1) % obj % dist(1) % data, dim=1)) & - call fatal_error("All tabular scattering entries must be& - & same length!") - end select - end do - ! Ok, got our order, store the dimensionality - order_dim = order - - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) - do ipol = 1, n_pol - do iazi = 1, n_azi - allocate(ScattDataTabular :: this % scatter(iazi, ipol) % obj) - end do - end do - - else if (scatt_type == ANGLE_LEGENDRE) then - ! Need to determine the maximum scattering order of all data in this material - mat_max_order = 0 - do i = 1, mat % n_nuclides - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsAngle) - if (size(nuc % scatter(1,1) % obj % dist(1) % data, dim=1) > mat_max_order) & - mat_max_order = size(nuc % scatter(1,1) % obj% dist(1) % data, dim=1) - end select - end do - - ! Now need to compare this material maximum scattering order with - ! the problem wide max scatt order and use whichever is lower - order = min(mat_max_order, max_order) - ! Ok, got our order, store the dimensionality - order_dim = order + 1 - - ! Set our Scatter Object Type - allocate(this % scatter(n_azi, n_pol)) - do ipol = 1, n_pol - do iazi = 1, n_azi - allocate(ScattDataLegendre :: this % scatter(iazi, ipol) % obj) - end do - end do - end if - - ! Allocate and initialize data within macro_xs(i_mat) object - allocate(this % total(groups, n_azi, n_pol)) - this % total(:, :, :) = ZERO - allocate(this % absorption(groups, n_azi, n_pol)) - this % absorption(:, :, :) = ZERO - allocate(this % fission(groups, n_azi, n_pol)) - this % fission(:, :, :) = ZERO - allocate(this % k_fission(groups, n_azi, n_pol)) - this % k_fission(:, :, :) = ZERO - allocate(this % nu_fission(groups, n_azi, n_pol)) - this % nu_fission(:, :, :) = ZERO - allocate(this % chi(groups, groups, n_azi, n_pol)) - this % chi(:, :, :, :) = ZERO - allocate(temp_mult(groups, groups, n_azi, n_pol)) - temp_mult(:, :, :, :) = ZERO - allocate(mult_num(groups, groups, n_azi, n_pol)) - mult_num(:, :, :, :) = ZERO - allocate(mult_denom(groups, groups, n_azi, n_pol)) - mult_denom(:, :, :, :) = ZERO - allocate(scatt_coeffs(order_dim, groups, groups, n_azi, n_pol)) - scatt_coeffs(:, :, :, :, :) = ZERO - - ! Add contribution from each nuclide in material - do i = 1, mat % n_nuclides - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) - - ! Perform our operations which depend upon the type - select type(nuc => nuclides(mat % nuclide(i)) % obj) - type is (MgxsIso) - call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") - type is (MgxsAngle) - ! Add contributions to total, absorption, and fission data (if necessary) - this % total(:, :, :) = this % total(:, :, :) + & - atom_density * nuc % total(:, :, :) - this % absorption(:, :, :) = this % absorption(:, :, :) + & - atom_density * nuc % absorption(:, :, :) - if (nuc % fissionable) then - this % chi = this % chi + atom_density * nuc % chi - this % nu_fission(:, :, :) = this % nu_fission(:, :, :) + & - atom_density * nuc % nu_fission(:, :, :) - if (allocated(nuc % fission)) then - this % fission(:, :, :) = this % fission(:, :, :) + & - atom_density * nuc % fission(:, :, :) + if (scatter_type == ANGLE_LEGENDRE) then + allocate(ScattDataLegendre :: & + this % xs(t) % scatter(iazi, ipol) % obj) + else if (scatter_type == ANGLE_TABULAR) then + allocate(ScattDataTabular :: & + this % xs(t) % scatter(iazi, ipol) % obj) + else if (scatter_type == ANGLE_HISTOGRAM) then + allocate(ScattDataHistogram :: & + this % xs(t) % scatter(iazi, ipol) % obj) end if - if (allocated(nuc % k_fission)) then - this % k_fission(:, :, :) = this % k_fission(:, :, :) + & - atom_density * nuc % k_fission(:, :, :) - end if - end if + end do + end do - ! Get the multiplication matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - do gout = nuc % scatter(iazi, ipol) % obj % gmin(gin), & - nuc % scatter(iazi, ipol) % obj % gmax(gin) - nuscatt = nuc % scatter(iazi, ipol) % obj % scattxs(gin) * & - nuc % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - mult_num(gout, gin, iazi, ipol) = mult_num(gout, gin, iazi, ipol) + & - atom_density * nuscatt - if (nuc % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + & - atom_density * nuscatt / & - nuc % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout,gin, iazi, ipol) + atom_density - end if + ! Add contribution from each nuclide in material + NUC_LOOP: do i = 1, mat % n_nuclides + associate(nuc => nuclides(mat % nuclide(i)) % obj) + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + temp_desired = temps % data(i) + nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(i_closest) + if (abs(temp_actual - temp_desired) >= tolerance) then + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired))) // " K.") + end if + + case (TEMPERATURE_INTERPOLATION) + ! TODO: Get bounding temperatures + call fatal_error("Temperature interpolation not yet implemented") + end select + + ! Copy atom density of nuclide in material + atom_density = mat % atom_density(i) + + select type(nuc) + type is (MgxsAngle) + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data (if necessary) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption + if (nuc % fissionable) then + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission + end if + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission + end if + end if + + ! Get the multiplication matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter(iazi, ipol) %obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + mult_num(iazi, ipol, gout, gin) = & + mult_num(iazi, ipo, gout, gin) + atom_density * & + nuscatt + if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then + mult_denom(iazi, ipol, gout, gin) = & + mult_denom(iazi, ipol, gout, gin) + atom_density * & + nuscatt / & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + else + ! Avoid division by zero + mult_denom(iazi, ipol, gout, gin) = & + mult_denom(iazi, ipol, gout, gin) + atom_density + end if + end do + end do + + ! Get the complete scattering matrix + nuc_order_dim = & + size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % dist(1) % data, dim=1) + scatt_coeffs(iazi, ipol, 1:min(nuc_order_dim, order_dim), :, :) = & + scatt_coeffs(iazi, ipol, 1:min(nuc_order_dim, order_dim), :, :) + & + atom_density * & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % get_matrix(min(nuc_order_dim, order_dim)) + end do + end do + type is (MgxsIso) + call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") + end select + + ! Obtain temp_mult + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + do gout = 1, groups + if (mult_denom(iazi, ipol, gout, gin) > ZERO) then + temp_mult(iazi, ipol, gout, gin) = & + mult_num(iazi, ipol, gout, gin) / & + mult_denom(iazi, ipol, gout, gin) + else + temp_mult(iazi, ipol, gout, gin) = ONE + end if + end do end do end do end do - end do - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % scatter(1, 1) % obj % dist(1) % data, dim=1) - do ipol = 1, n_pol - do iazi = 1, n_azi - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) + & - atom_density * nuc % scatter(iazi, ipol) % obj % get_matrix(& - min(nuc_order_dim, order_dim)) + ! Initialize the ScattData Object + do ipol = 1, n_pol + do iazi = 1, n_azi + call this % xs(t) % scatter(iazi, ipol) % obj % init(& + temp_mult(iazi, ipol, :, :), & + scatt_coeffs(iazi, ipol, :, :, :)) + end do end do - end do - end select - end do - ! Obtain temp_mult - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - do gout = 1, groups - if (mult_denom(gout, gin, iazi, ipol) > ZERO) then - temp_mult(gout, gin, iazi, ipol) = & - mult_num(gout, gin, iazi, ipol) / & - mult_denom(gout, gin, iazi, ipol) - else - temp_mult(gout, gin, iazi, ipol) = ONE - end if - end do - end do - end do - end do + ! Now normalize chi + if (mat % fissionable) then + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + norm = sum(this % xs(t) % chi(iazi, ipol, :, gin)) + if (norm > ZERO) then + this % xs(t) % chi(iazi, ipol, :, gin) = & + this % xs(t) % chi(iazi, ipol, :, gin) / norm + end if + end do + end do + end do + end if - ! Initialize the ScattData Object - do ipol = 1, n_pol - do iazi = 1, n_azi - call this % scatter(iazi, ipol) % obj % init( & - temp_mult(:, :, iazi, ipol), scatt_coeffs(:, :, :, iazi, ipol)) - end do - end do - - ! Now normalize chi - if (mat % fissionable) then - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - norm = sum(this % chi(:, gin, iazi, ipol)) - if (norm > ZERO) then - this % chi(:, gin, iazi, ipol) = this % chi(:, gin, iazi, ipol) / norm - end if - end do - end do - end do - end if - - ! Deallocate temporaries for the next material - deallocate(scatt_coeffs, temp_mult) + ! Deallocate temporaries + deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) + end associate ! nuc + end do NUC_LOOP + end do TEMP_LOOP end subroutine mgxsang_combine +!=============================================================================== +! MGXS*_GET_XS returns the requested data cross section data +!=============================================================================== + + pure function mgxsiso_get_xs(this, t, xstype, gin, gout, uvw, mu) result(xs) + class(MgxsIso), intent(in) :: this ! The Xs to get data from + integer, intent(in) :: t ! Temperature index of data + character(*) , intent(in) :: xstype ! Type of xs requested + integer, intent(in) :: gin ! Incoming Energy group + integer, optional, intent(in) :: gout ! Outgoing Energy group + real(8), optional, intent(in) :: uvw(3) ! Requested Angle + real(8), optional, intent(in) :: mu ! Change in angle + real(8) :: xs ! Requested x/s + + select case(xstype) + case('total') + xs = this % xs(t) % total(gin) + case('absorption') + xs = this % xs(t) % absorption(gin) + case('fission') + if (allocated(this % xs(t) % fission)) then + xs = this % xs(t) % fission(gin) + else + xs = ZERO + end if + case('kappa_fission') + if (allocated(this % xs(t) % k_fission)) then + xs = this % xs(t) % k_fission(gin) + else + xs = ZERO + end if + case('nu_fission') + xs = this % xs(t) % nu_fission(gin) + case('chi') + if (present(gout)) then + xs = this % xs(t) % chi(gout,gin) + else + ! Not sure youd want a 1 or a 0, but here you go! + xs = sum(this % xs(t) % chi(:, gin)) + end if + case('scatter') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter % scattxs(gin) + end if + case('scatter/mult') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) / & + this % xs(t) % scatter % mult(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter % scattxs(gin) / & + (dot_product(this % xs(t) % scatter % mult(gin) % data, & + this % xs(t) % scatter % energy(gin) % data)) + end if + case('scatter*f_mu/mult','scatter*f_mu') + if (present(gout)) then + if (gout < this % xs(t) % scatter % gmin(gin) .or. & + gout > this % xs(t) % scatter % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter % scattxs(gin) * & + this % xs(t) % scatter % energy(gin) % data(gout) * & + this % xs(t) % scatter % calc_f(gin, gout, mu) + if (xstype == 'scatter*f_mu/mult') then + xs = xs / this % xs(t) % scatter % mult(gin) % data(gout) + end if + end if + else + xs = ZERO + ! TODO (Not likely needed) + ! (asking for f_mu without asking for a group or mu would mean the + ! user of this code wants the complete 1-outgoing group distribution + ! which Im not sure what they would do with that. + end if + case default + xs = ZERO + end select + end function mgxsiso_get_xs + + pure function mgxsang_get_xs(this, t, xstype, gin, gout, uvw, mu) result(xs) + class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize + integer, intent(in) :: t ! Temperature index of data + character(*) , intent(in) :: xstype ! Type of xs requested + integer, intent(in) :: gin ! Incoming Energy group + integer, optional, intent(in) :: gout ! Outgoing Energy group + real(8), optional, intent(in) :: uvw(3) ! Requested Angle + real(8), optional, intent(in) :: mu ! Change in angle + real(8) :: xs ! Requested x/s + + integer :: iazi, ipol + + if (present(uvw)) then + call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) + select case(xstype) + case('total') + xs = this % xs(t) % total(gin, iazi, ipol) + case('absorption') + xs = this % xs(t) % absorption(gin, iazi, ipol) + case('fission') + if (allocated(this % xs(t) % fission)) then + xs = this % xs(t) % fission(gin, iazi, ipol) + else + xs = ZERO + end if + case('kappa_fission') + if (allocated(this % xs(t) % k_fission)) then + xs = this % xs(t) % k_fission(gin, iazi, ipol) + else + xs = ZERO + end if + case('nu_fission') + xs = this % xs(t) % nu_fission(gin, iazi, ipol) + case('chi') + if (present(gout)) then + xs = this % xs(t) % chi(gout, gin, iazi, ipol) + else + ! Not sure you would want a 1 or a 0, but here you go! + xs = sum(this % xs(t) % chi(:, gin, iazi, ipol)) + end if + case('scatter') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) + end if + case('scatter/mult') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) / & + this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + end if + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) / & + (dot_product(this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data, & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data)) + end if + case('scatter*f_mu/mult','scatter*f_mu') + if (present(gout)) then + if (gout < this % xs(t) % scatter(iazi, ipol) % obj % gmin(gin) .or. & + gout > this % xs(t) % scatter(iazi, ipol) % obj % gmax(gin)) then + xs = ZERO + else + xs = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + this % xs(t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + xs = xs * this % xs(t) % scatter(iazi, ipol) % obj % calc_f(gin, gout, mu) + if (xstype == 'scatter*f_mu/mult') then + xs = xs / & + this % xs(t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + end if + end if + else + xs = ZERO + ! TODO (Not likely needed) + ! (asking for f_mu without asking for a group or mu would mean the + ! user of this code wants the complete 1-outgoing group distribution + ! which Im not sure what they would do with that. + end if + case default + xs = ZERO + end select + else + xs = ZERO + end if + end function mgxsang_get_xs + !=============================================================================== ! MGXS*_SAMPLE_FISSION_ENERGY samples the outgoing energy from a fission event !=============================================================================== - function mgxsiso_sample_fission_energy(this, gin, uvw) result(gout) + function mgxsiso_sample_fission_energy(this, t, gin, uvw) result(gout) class(MgxsIso), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer :: gout ! Sampled outgoing group - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability + integer, intent(in) :: t ! Temperature index of data + integer, intent(in) :: gin ! Incoming energy group + real(8), intent(in) :: uvw(3) ! Particle Direction + integer :: gout ! Sampled outgoing group + real(8) :: xi ! Our random number + real(8) :: prob ! Running probability xi = prn() gout = 1 - prob = this % chi(gout,gin) + prob = this % xs(t) % chi(gout,gin) do while (prob < xi) gout = gout + 1 - prob = prob + this % chi(gout,gin) + prob = prob + this % xs(t) % chi(gout,gin) end do end function mgxsiso_sample_fission_energy - function mgxsang_sample_fission_energy(this, gin, uvw) result(gout) + function mgxsang_sample_fission_energy(this, t, gin, uvw) result(gout) class(MgxsAngle), intent(in) :: this ! Data to work with - integer, intent(in) :: gin ! Incoming energy group - real(8), intent(in) :: uvw(3) ! Particle Direction - integer :: gout ! Sampled outgoing group - real(8) :: xi ! Our random number - real(8) :: prob ! Running probability - integer :: iazi, ipol + integer, intent(in) :: t ! Temperature index of data + integer, intent(in) :: gin ! Incoming energy group + real(8), intent(in) :: uvw(3) ! Particle Direction + integer :: gout ! Sampled outgoing group + real(8) :: xi ! Our random number + real(8) :: prob ! Running probability + integer :: iazi, ipol ! Angle indices call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) xi = prn() gout = 1 - prob = this % chi(gout, gin, iazi, ipol) + prob = this % xs(t) % chi(gout, gin, iazi, ipol) do while (prob < xi) gout = gout + 1 - prob = prob + this % chi(gout, gin, iazi, ipol) + prob = prob + this % xs(t) % chi(gout, gin, iazi, ipol) end do end function mgxsang_sample_fission_energy @@ -1660,30 +1641,32 @@ module mgxs_header ! MGXS*_SAMPLE_SCATTER Selects outgoing energy and angle after a scatter event !=============================================================================== - subroutine mgxsiso_sample_scatter(this, uvw, gin, gout, mu, wgt) + subroutine mgxsiso_sample_scatter(this, t, uvw, gin, gout, mu, wgt) class(MgxsIso), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight + integer, intent(in) :: t ! Temperature index + real(8), intent(in) :: uvw(3) ! Incoming neutron direction + integer, intent(in) :: gin ! Incoming neutron group + integer, intent(out) :: gout ! Sampled outgoin group + real(8), intent(out) :: mu ! Sampled change in angle + real(8), intent(inout) :: wgt ! Particle weight - call this % scatter % sample(gin, gout, mu, wgt) + call this % xs(t) % scatter % sample(gin, gout, mu, wgt) end subroutine mgxsiso_sample_scatter - subroutine mgxsang_sample_scatter(this, uvw, gin, gout, mu, wgt) + subroutine mgxsang_sample_scatter(this, t, uvw, gin, gout, mu, wgt) class(MgxsAngle), intent(in) :: this - real(8), intent(in) :: uvw(3) ! Incoming neutron direction - integer, intent(in) :: gin ! Incoming neutron group - integer, intent(out) :: gout ! Sampled outgoin group - real(8), intent(out) :: mu ! Sampled change in angle - real(8), intent(inout) :: wgt ! Particle weight + integer, intent(in) :: t ! Temperature index + real(8), intent(in) :: uvw(3) ! Incoming neutron direction + integer, intent(in) :: gin ! Incoming neutron group + integer, intent(out) :: gout ! Sampled outgoin group + real(8), intent(out) :: mu ! Sampled change in angle + real(8), intent(inout) :: wgt ! Particle weight integer :: iazi, ipol ! Angular indices call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - call this % scatter(iazi, ipol) % obj % sample(gin, gout, mu, wgt) + call this % xs(t) % scatter(iazi, ipol) % obj % sample(gin, gout, mu, wgt) end subroutine mgxsang_sample_scatter @@ -1692,22 +1675,24 @@ module mgxs_header ! for the material the particle is currently traveling through. !=============================================================================== - subroutine mgxsiso_calculate_xs(this, gin, uvw, xs) + subroutine mgxsiso_calculate_xs(this, t, gin, uvw, xs) class(MgxsIso), intent(in) :: this + integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - xs % total = this % total(gin) - xs % elastic = this % scatter % scattxs(gin) - xs % absorption = this % absorption(gin) - xs % fission = this % fission(gin) - xs % nu_fission = this % nu_fission(gin) + xs % total = this % xs(t) % total(gin) + xs % elastic = this % xs(t) % scatter % scattxs(gin) + xs % absorption = this % xs(t) % absorption(gin) + xs % fission = this % xs(t) % fission(gin) + xs % nu_fission = this % xs(t) % nu_fission(gin) end subroutine mgxsiso_calculate_xs - subroutine mgxsang_calculate_xs(this, gin, uvw, xs) + subroutine mgxsang_calculate_xs(this, t, gin, uvw, xs) class(MgxsAngle), intent(in) :: this + integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data @@ -1715,11 +1700,11 @@ module mgxs_header integer :: iazi, ipol call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - xs % total = this % total(gin, iazi, ipol) - xs % elastic = this % scatter(iazi, ipol) % obj % scattxs(gin) - xs % absorption = this % absorption(gin, iazi, ipol) - xs % fission = this % fission(gin, iazi, ipol) - xs % nu_fission = this % nu_fission(gin, iazi, ipol) + xs % total = this % xs(t) % total(gin, iazi, ipol) + xs % elastic = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) + xs % absorption = this % xs(t) % absorption(gin, iazi, ipol) + xs % fission = this % xs(t) % fission(gin, iazi, ipol) + xs % nu_fission = this % xs(t) % nu_fission(gin, iazi, ipol) end subroutine mgxsang_calculate_xs From aeb7f0c787f9069ca8f5ab1928a1165ef5c21efa Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 4 Sep 2016 06:34:33 -0400 Subject: [PATCH 04/82] Got the temperature dependent MGXS data hooked in to the rest of the code. On to debugging! --- src/cross_section.F90 | 1 + src/initialize.F90 | 6 --- src/input_xml.F90 | 84 +++++++++++++++--------------- src/mgxs_data.F90 | 117 ++++++++++++++++++++++++++---------------- src/mgxs_header.F90 | 109 +++++++++++++++++++++++---------------- src/tracking.F90 | 4 ++ 6 files changed, 186 insertions(+), 135 deletions(-) diff --git a/src/cross_section.F90 b/src/cross_section.F90 index 800552f891..e2cc31d5ea 100644 --- a/src/cross_section.F90 +++ b/src/cross_section.F90 @@ -161,6 +161,7 @@ contains ! If using multipole data but outside the RRR, pick the nearest ! temperature. Note that there is no tolerance here, so this ! temperature could be very far off! + kT = sqrtkT**2 i_temp = minloc(abs(nuclides(i_nuclide) % kTs - kT), dim=1) end if else diff --git a/src/initialize.F90 b/src/initialize.F90 index 2bcf2e01f2..4fe6f8769c 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -113,12 +113,6 @@ contains if (run_CE) then ! Construct log energy grid for cross-sections call logarithmic_grid() - else - ! Create material macroscopic data for MGXS - call time_read_xs%start() - call read_mgxs() - call create_macro_xs() - call time_read_xs%stop() end if ! Allocate and setup tally stride, matching_bins, and tally maps diff --git a/src/input_xml.F90 b/src/input_xml.F90 index eeeae865b6..eafbc717c2 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -48,8 +48,8 @@ contains call read_settings_xml() call read_geometry_xml() - call read_materials() call read_tallies_xml() + call read_materials() if (cmfd_run) call configure_cmfd() end subroutine read_input_xml @@ -1356,11 +1356,7 @@ contains ! Read cell temperatures. If the temperature is not specified, set it to ! ERROR_REAL for now. During initialization we'll replace ERROR_REAL with ! the temperature from the material data. - if (.not. run_CE) then - ! Cell temperatures are not used for MG mode. - allocate(c % sqrtkT(1)) - c % sqrtkT(1) = ZERO - else if (check_for_node(node_cell, "temperature")) then + if (check_for_node(node_cell, "temperature")) then n = get_arraysize_double(node_cell, "temperature") if (n > 0) then ! Make sure this is a "normal" cell. @@ -2038,7 +2034,7 @@ contains if (run_CE) then call read_ce_cross_sections_xml(libraries) else - call read_mg_cross_sections_xml(libraries) + call read_mg_cross_sections_header(libraries) end if ! Creating dictionary that maps the name of the material to the entry @@ -2069,10 +2065,16 @@ contains call get_temperatures(nuc_temps, sab_temps) ! Read continuous-energy cross sections - if (run_CE .and. run_mode /= MODE_PLOTTING) then - call time_read_xs%start() - call read_ce_cross_sections(libraries, library_dict, nuc_temps, sab_temps) - call time_read_xs%stop() + if (run_mode /= MODE_PLOTTING) then + call time_read_xs % start() + if (run_CE) then + call read_ce_cross_sections(libraries, library_dict, nuc_temps, sab_temps) + else + ! Create material macroscopic data for MGXS + call read_mgxs(nuc_temps) + call create_macro_xs() + end if + call time_read_xs % stop() end if ! Normalize atom/weight percents @@ -4601,44 +4603,43 @@ contains end subroutine read_ce_cross_sections_xml - subroutine read_mg_cross_sections_xml(libraries) + subroutine read_mg_cross_sections_header(libraries) type(Library), allocatable, intent(out) :: libraries(:) integer :: i ! loop index integer :: n_libraries - logical :: file_exists ! does cross_sections.xml exist? - type(Node), pointer :: doc => null() - type(Node), pointer :: node_xsdata => null() - type(NodeList), pointer :: node_xsdata_list => null() + logical :: file_exists ! does mgxs.h5 exist? + integer(HID_T) :: file_id real(8), allocatable :: rev_energy_bins(:) + character(len=255), allocatable :: names(:) - ! Check if mgxs.xml exists + ! Check if mgxs.h5 exists inquire(FILE=path_cross_sections, EXIST=file_exists) if (.not. file_exists) then - ! Could not find mgxs.xml file - call fatal_error("Cross sections XML file '" & + ! Could not find mgxs.h5 file + call fatal_error("Cross sections HDF5 file '" & // trim(path_cross_sections) // "' does not exist!") end if - call write_message("Reading cross sections XML file...", 5) + call write_message("Reading cross sections HDF5 file...", 5) - ! Parse mgxs.xml file - call open_xmldoc(doc, path_cross_sections) + ! Open file for reading + file_id = file_open(path_cross_sections, 'r', parallel=.true.) - if (check_for_node(doc, "groups")) then + if (check_attribute(file_id, "groups")) then ! Get neutron group count - call get_node_value(doc, "groups", energy_groups) + call read_attribute(energy_groups, file_id, "groups") else - call fatal_error("groups element must exist!") + call fatal_error("'groups' attribute must exist!") end if allocate(rev_energy_bins(energy_groups + 1)) allocate(energy_bins(energy_groups + 1)) - if (check_for_node(doc, "group_structure")) then + if (check_attribute(file_id, "group structure")) then ! Get neutron group structure - call get_node_array(doc, "group_structure", energy_bins) + call read_attribute(energy_bins, file_id, "group structure") else - call fatal_error("group_structures element must exist!") + call fatal_error("'group structure' attribute must exist!") end if ! First reverse the order of energy_groups @@ -4650,9 +4651,9 @@ contains end do allocate(inverse_velocities(energy_groups)) - if (check_for_node(doc, "inverse_velocities")) then + if (check_attribute(file_id, "inverse velocities")) then ! Get inverse velocities - call get_node_array(doc, "inverse_velocities", inverse_velocities) + call read_attribute(inverse_velocities, file_id, "inverse velocities") else ! If not given, estimate them by using average energy in group which is ! assumed to be the midpoint @@ -4663,31 +4664,28 @@ contains end do end if - ! Get node list of all - call get_node_list(doc, "xsdata", node_xsdata_list) - n_libraries = get_list_size(node_xsdata_list) + ! Get the datasets present in the library + call get_groups(file_id, names) + n_libraries = size(names) - ! Allocate xs_listings array + ! Allocate libraries array if (n_libraries == 0) then - call fatal_error("At least one element must be present in & - &mgxs.xml file!") + call fatal_error("At least one MGXS data set must be present in & + &mgxs library file!") else allocate(libraries(n_libraries)) end if do i = 1, n_libraries - ! Get pointer to xsdata table XML node - call get_list_item(node_xsdata_list, i, node_xsdata) - ! Get name of material allocate(libraries(i) % materials(1)) - call get_node_value(node_xsdata, "name", libraries(i) % materials(1)) + libraries(i) % materials(1) = names(i) end do - ! Close cross sections XML file - call close_xmldoc(doc) + ! Close MGXS HDF file + call file_close(file_id) - end subroutine read_mg_cross_sections_xml + end subroutine read_mg_cross_sections_header !=============================================================================== ! EXPAND_NATURAL_ELEMENT converts natural elements specified using an diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index aa96910f30..7cbb4864c7 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -3,13 +3,13 @@ module mgxs_data use constants use error, only: fatal_error use global + use hdf5 use material_header, only: Material use mgxs_header use output, only: write_message use set_header, only: SetChar + use stl_vector, only: VectorReal use string, only: to_lower - use xml_interface - implicit none contains @@ -19,21 +19,20 @@ contains ! nuclides and sab_tables arrays !=============================================================================== - subroutine read_mgxs() + subroutine read_mgxs(temps) + type(VectorReal), allocatable :: temps(:) integer :: i ! index in materials array integer :: j ! index over nuclides in material integer :: i_xsdata ! index in list - integer :: i_nuclide ! index in nuclides - character(20) :: name ! name of isotope, e.g. 92235.03c + integer :: i_nuclide ! index in nuclides array + character(20) :: name ! name of library to load integer :: representation ! Data representation - type(Material), pointer :: mat + type(Material), pointer :: mat type(SetChar) :: already_read - type(Node), pointer :: doc => null() - type(Node), pointer :: node_xsdata - type(NodeList), pointer :: node_xsdata_list => null() + integer(HID_T) :: file_id + integer(HID_T) :: xsdata_group logical :: file_exists - character(MAX_LINE_LEN) :: temp_str logical :: get_kfiss, get_fiss integer :: l type(DictCharInt) :: xsdata_dict @@ -42,30 +41,16 @@ contains inquire(FILE=path_cross_sections, EXIST=file_exists) if (.not. file_exists) then ! Could not find cross_sections.xml file - call fatal_error("Cross sections XML file '" & + call fatal_error("Cross sections HDF5 file '" & &// trim(path_cross_sections) // "' does not exist!") end if call write_message("Loading Cross Section Data...", 5) - ! Parse cross_sections.xml file - call open_xmldoc(doc, path_cross_sections) + ! Open file for reading + file_id = file_open(path_cross_sections, 'r', parallel=.true.) - ! Get node list of all - call get_node_list(doc, "xsdata", node_xsdata_list) - - ! Build dictionary mapping nuclide names to an index in the node - ! list - do i = 1, get_list_size(node_xsdata_list) - ! Get pointer to xsdata table XML node - call get_list_item(node_xsdata_list, i, node_xsdata) - - ! Get name and create pair (name, i) - call get_node_value(node_xsdata, "name", name) - call xsdata_dict % add_key(to_lower(name), i) - end do - - ! allocate arrays for ACE table storage and cross section cache + ! allocate arrays for MGXS storage and cross section cache allocate(nuclides_MG(n_nuclides_total)) !$omp parallel allocate(micro_xs(n_nuclides_total)) @@ -102,20 +87,21 @@ contains i_xsdata = xsdata_dict % get_key(to_lower(name)) i_nuclide = mat % nuclide(j) - ! Get pointer to xsdata table XML node - call get_list_item(node_xsdata_list, i_xsdata, node_xsdata) - call write_message("Loading " // trim(name) // " Data...", 5) + ! Check to make sure cross section set exists in the library + if (check_group(file_id, trim(name))) then + xsdata_group = open_group(file_id, trim(name)) + else + call fatal_error("Data for '" // trim(name) // "' does not exist in "& + &// trim(path_cross_sections)) + end if + ! First find out the data representation - if (check_for_node(node_xsdata, "representation")) then - call get_node_value(node_xsdata, "representation", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == 'isotropic' .or. temp_str == 'iso') then - representation = MGXS_ISOTROPIC - else if (temp_str == 'angle') then - representation = MGXS_ANGLE - else + if (check_attribute(xsdata_group, "representation")) then + call read_attribute(representation, xsdata_group, "representation") + if (representation /= MGXS_ISOTROPIC .and. & + representation /= MGXS_ANGLE) then call fatal_error("Invalid Data Representation!") end if else @@ -132,8 +118,9 @@ contains end select ! Now read in the data specific to the type we just declared - call nuclides_MG(i_nuclide) % obj % init_file(node_xsdata, & - energy_groups, get_kfiss, get_fiss, max_order) + call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, & + energy_groups, temps(i_nuclide), temperature_method, & + temperature_tolerance, get_kfiss, get_fiss, max_order) ! Add name to dictionary call already_read % add(name) @@ -172,9 +159,13 @@ contains subroutine create_macro_xs() integer :: i_mat ! index in materials array type(Material), pointer :: mat ! current material + type(VectorReal), allocatable :: kTs(:) allocate(macro_xs(n_materials)) + ! Get temperatures to read for each material + call get_mat_kTs(kTs) + do i_mat = 1, n_materials mat => materials(i_mat) @@ -187,9 +178,49 @@ contains type is (MgxsAngle) allocate(MgxsAngle :: macro_xs(i_mat) % obj) end select - call macro_xs(i_mat) % obj % combine(mat, nuclides_MG, energy_groups, & - max_order) + call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & + energy_groups, max_order) end do end subroutine create_macro_xs +!=============================================================================== +! GET_MAT_kTs returns a list of temperatures (in MeV) that each +! material appears at in the model. +!=============================================================================== + + subroutine get_mat_kTs(kTs) + type(VectorReal), allocatable, intent(out) :: kTs(:) + + integer :: i, j + integer :: i_material ! Index in materials array + real(8) :: kT ! temperature in MeV + + allocate(kTs(size(materials))) + + do i = 1, size(cells) + do j = 1, size(cells(i) % material) + ! Skip any non-material cells and void materials + if (cells(i) % material(j) == NONE .or. & + cells(i) % material(j) == MATERIAL_VOID) cycle + + ! Get temperature of cell (rounding to nearest integer) + if (size(cells(i) % sqrtkT) > 1) then + kT = cells(i) % sqrtkT(j)**2 + else + kT = cells(i) % sqrtkT(1)**2 + end if + + i_material = material_dict % get_key(cells(i) % material(j)) + + ! Add temperature if it hasn't already been added + if (find(kTs(i_material), kT) == -1) then + call kTs(i_material) % push_back(kT) + end if + + end do + end do + + end subroutine get_mat_kTs + + end module mgxs_data diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 2f569c6fe0..c86685bc0d 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -57,6 +57,9 @@ module mgxs_header logical :: fissionable ! mgxs object is fissionable? integer :: scatter_type ! either legendre, histogram, or tabular. + ! Caching information + integer :: index_temp ! temperature index for nuclide + contains procedure(mgxs_from_hdf5_), deferred :: from_hdf5 ! Load the data procedure(mgxs_combine_), deferred :: combine ! initializes object @@ -67,6 +70,7 @@ module mgxs_header procedure(mgxs_sample_scatter_), deferred :: sample_scatter ! Calculate the material specific MGXS data from the nuclides procedure(mgxs_calculate_xs_), deferred :: calculate_xs + procedure :: find_temperature => mgxs_find_temperature end type Mgxs !=============================================================================== @@ -106,10 +110,9 @@ module mgxs_header integer, intent(in) :: max_order ! Maximum requested order end subroutine mgxs_combine_ - pure function mgxs_get_xs_(this, t, xstype, gin, gout, uvw, mu) result(xs_val) + pure function mgxs_get_xs_(this, xstype, gin, gout, uvw, mu) result(xs_val) import Mgxs class(Mgxs), intent(in) :: this - integer, intent(in) :: t ! Temperature index of data character(*), intent(in) :: xstype ! Cross Section Type integer, intent(in) :: gin ! Incoming Energy group integer, optional, intent(in) :: gout ! Outgoing Group @@ -118,20 +121,18 @@ module mgxs_header real(8) :: xs_val ! Resultant xs end function mgxs_get_xs_ - function mgxs_sample_fission_(this, t, gin, uvw) result(gout) + function mgxs_sample_fission_(this, gin, uvw) result(gout) import Mgxs class(Mgxs), intent(in) :: this - integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming energy group real(8), intent(in) :: uvw(3) ! Particle Direction integer :: gout ! Sampled outgoing group end function mgxs_sample_fission_ - subroutine mgxs_sample_scatter_(this, t, uvw, gin, gout, mu, wgt) + subroutine mgxs_sample_scatter_(this, uvw, gin, gout, mu, wgt) import Mgxs class(Mgxs), intent(in) :: this - integer, intent(in) :: t ! Temperature index of data real(8), intent(in) :: uvw(3) ! Incoming neutron direction integer, intent(in) :: gin ! Incoming neutron group integer, intent(out) :: gout ! Sampled outgoin group @@ -139,10 +140,9 @@ module mgxs_header real(8), intent(inout) :: wgt ! Particle weight end subroutine mgxs_sample_scatter_ - subroutine mgxs_calculate_xs_(this, t, gin, uvw, xs) + subroutine mgxs_calculate_xs_(this, gin, uvw, xs) import Mgxs, MaterialMacroXS class(Mgxs), intent(in) :: this - integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data @@ -1006,7 +1006,7 @@ module mgxs_header subroutine mgxsiso_combine(this, temps, mat, nuclides, groups, max_order) class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize - type(VectorReal), intent(in) :: temps ! Temperatures to obtain + type(VectorReal), intent(in) :: temps ! Temperatures to obtain [MeV] type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups @@ -1406,15 +1406,17 @@ module mgxs_header ! MGXS*_GET_XS returns the requested data cross section data !=============================================================================== - pure function mgxsiso_get_xs(this, t, xstype, gin, gout, uvw, mu) result(xs) + pure function mgxsiso_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) class(MgxsIso), intent(in) :: this ! The Xs to get data from - integer, intent(in) :: t ! Temperature index of data character(*) , intent(in) :: xstype ! Type of xs requested integer, intent(in) :: gin ! Incoming Energy group integer, optional, intent(in) :: gout ! Outgoing Energy group real(8), optional, intent(in) :: uvw(3) ! Requested Angle real(8), optional, intent(in) :: mu ! Change in angle real(8) :: xs ! Requested x/s + integer :: t ! temperature index + + t = this % index_temp select case(xstype) case('total') @@ -1494,9 +1496,8 @@ module mgxs_header end select end function mgxsiso_get_xs - pure function mgxsang_get_xs(this, t, xstype, gin, gout, uvw, mu) result(xs) + pure function mgxsang_get_xs(this, xstype, gin, gout, uvw, mu) result(xs) class(MgxsAngle), intent(in) :: this ! The Mgxs to initialize - integer, intent(in) :: t ! Temperature index of data character(*) , intent(in) :: xstype ! Type of xs requested integer, intent(in) :: gin ! Incoming Energy group integer, optional, intent(in) :: gout ! Outgoing Energy group @@ -1504,7 +1505,9 @@ module mgxs_header real(8), optional, intent(in) :: mu ! Change in angle real(8) :: xs ! Requested x/s - integer :: iazi, ipol + integer :: iazi, ipol, t + + t = this % index_temp if (present(uvw)) then call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) @@ -1594,9 +1597,8 @@ module mgxs_header ! MGXS*_SAMPLE_FISSION_ENERGY samples the outgoing energy from a fission event !=============================================================================== - function mgxsiso_sample_fission_energy(this, t, gin, uvw) result(gout) + function mgxsiso_sample_fission_energy(this, gin, uvw) result(gout) class(MgxsIso), intent(in) :: this ! Data to work with - integer, intent(in) :: t ! Temperature index of data integer, intent(in) :: gin ! Incoming energy group real(8), intent(in) :: uvw(3) ! Particle Direction integer :: gout ! Sampled outgoing group @@ -1605,18 +1607,17 @@ module mgxs_header xi = prn() gout = 1 - prob = this % xs(t) % chi(gout,gin) + prob = this % xs(this % index_temp) % chi(gout,gin) do while (prob < xi) gout = gout + 1 - prob = prob + this % xs(t) % chi(gout,gin) + prob = prob + this % xs(this % index_temp) % chi(gout,gin) end do end function mgxsiso_sample_fission_energy - function mgxsang_sample_fission_energy(this, t, gin, uvw) result(gout) + function mgxsang_sample_fission_energy(this, gin, uvw) result(gout) class(MgxsAngle), intent(in) :: this ! Data to work with - integer, intent(in) :: t ! Temperature index of data integer, intent(in) :: gin ! Incoming energy group real(8), intent(in) :: uvw(3) ! Particle Direction integer :: gout ! Sampled outgoing group @@ -1628,11 +1629,11 @@ module mgxs_header xi = prn() gout = 1 - prob = this % xs(t) % chi(gout, gin, iazi, ipol) + prob = this % xs(this % index_temp) % chi(gout, gin, iazi, ipol) do while (prob < xi) gout = gout + 1 - prob = prob + this % xs(t) % chi(gout, gin, iazi, ipol) + prob = prob + this % xs(this % index_temp) % chi(gout, gin, iazi, ipol) end do end function mgxsang_sample_fission_energy @@ -1641,22 +1642,20 @@ module mgxs_header ! MGXS*_SAMPLE_SCATTER Selects outgoing energy and angle after a scatter event !=============================================================================== - subroutine mgxsiso_sample_scatter(this, t, uvw, gin, gout, mu, wgt) + subroutine mgxsiso_sample_scatter(this, uvw, gin, gout, mu, wgt) class(MgxsIso), intent(in) :: this - integer, intent(in) :: t ! Temperature index real(8), intent(in) :: uvw(3) ! Incoming neutron direction integer, intent(in) :: gin ! Incoming neutron group integer, intent(out) :: gout ! Sampled outgoin group real(8), intent(out) :: mu ! Sampled change in angle real(8), intent(inout) :: wgt ! Particle weight - call this % xs(t) % scatter % sample(gin, gout, mu, wgt) + call this % xs(this % index_temp) % scatter % sample(gin, gout, mu, wgt) end subroutine mgxsiso_sample_scatter - subroutine mgxsang_sample_scatter(this, t, uvw, gin, gout, mu, wgt) + subroutine mgxsang_sample_scatter(this, uvw, gin, gout, mu, wgt) class(MgxsAngle), intent(in) :: this - integer, intent(in) :: t ! Temperature index real(8), intent(in) :: uvw(3) ! Incoming neutron direction integer, intent(in) :: gin ! Incoming neutron group integer, intent(out) :: gout ! Sampled outgoin group @@ -1666,7 +1665,8 @@ module mgxs_header integer :: iazi, ipol ! Angular indices call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - call this % xs(t) % scatter(iazi, ipol) % obj % sample(gin, gout, mu, wgt) + call this % xs(this % index_temp) % scatter(iazi, ipol) % obj % sample( & + gin, gout, mu, wgt) end subroutine mgxsang_sample_scatter @@ -1675,24 +1675,22 @@ module mgxs_header ! for the material the particle is currently traveling through. !=============================================================================== - subroutine mgxsiso_calculate_xs(this, t, gin, uvw, xs) + subroutine mgxsiso_calculate_xs(this, gin, uvw, xs) class(MgxsIso), intent(in) :: this - integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data - xs % total = this % xs(t) % total(gin) - xs % elastic = this % xs(t) % scatter % scattxs(gin) - xs % absorption = this % xs(t) % absorption(gin) - xs % fission = this % xs(t) % fission(gin) - xs % nu_fission = this % xs(t) % nu_fission(gin) + xs % total = this % xs(this % index_temp) % total(gin) + xs % elastic = this % xs(this % index_temp) % scatter % scattxs(gin) + xs % absorption = this % xs(this % index_temp) % absorption(gin) + xs % fission = this % xs(this % index_temp) % fission(gin) + xs % nu_fission = this % xs(this % index_temp) % nu_fission(gin) end subroutine mgxsiso_calculate_xs - subroutine mgxsang_calculate_xs(this, t, gin, uvw, xs) + subroutine mgxsang_calculate_xs(this, gin, uvw, xs) class(MgxsAngle), intent(in) :: this - integer, intent(in) :: t ! Temperature index integer, intent(in) :: gin ! Incoming neutron group real(8), intent(in) :: uvw(3) ! Incoming neutron direction type(MaterialMacroXS), intent(inout) :: xs ! Resultant Mgxs Data @@ -1700,16 +1698,41 @@ module mgxs_header integer :: iazi, ipol call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) - xs % total = this % xs(t) % total(gin, iazi, ipol) - xs % elastic = this % xs(t) % scatter(iazi, ipol) % obj % scattxs(gin) - xs % absorption = this % xs(t) % absorption(gin, iazi, ipol) - xs % fission = this % xs(t) % fission(gin, iazi, ipol) - xs % nu_fission = this % xs(t) % nu_fission(gin, iazi, ipol) + xs % total = this % xs(this % index_temp) % & + total(gin, iazi, ipol) + xs % elastic = this % xs(this % index_temp) % & + scatter(iazi, ipol) % obj % scattxs(gin) + xs % absorption = this % xs(this % index_temp) % & + absorption(gin, iazi, ipol) + xs % fission = this % xs(this % index_temp) % & + fission(gin, iazi, ipol) + xs % nu_fission = this % xs(this % index_temp) % & + nu_fission(gin, iazi, ipol) end subroutine mgxsang_calculate_xs !=============================================================================== -! find_angle finds the closest angle on the data grid and returns that index +! MGXS_FIND_TEMPERATURE sets the temperature index for the given +! sqrt(temperature), (with temperature in units of MeV) +!=============================================================================== + + pure subroutine mgxs_find_temperature(this, sqrtkT, tolerance) + class(Mgxs), intent(in) :: this + real(8), intent(in) :: sqrtkT ! Temperature (in units of of MeV) + real(8), intent(in) :: tolerance ! Temperature tolerance + + real(8) :: kT + integer :: i_temp + + kT = sqrtkT**2 + do i_temp = 1, size(this % kTs) + if (abs(this % kTs(i_temp) - kT) < K_BOLTZMANN * tolerance) exit + end do + + end subroutine mgxs_find_temperature + +!=============================================================================== +! FIND_ANGLE finds the closest angle on the data grid and returns that index !=============================================================================== pure subroutine find_angle(polar, azimuthal, uvw, i_azi, i_pol) diff --git a/src/tracking.F90 b/src/tracking.F90 index f2613146e4..a03cde98dd 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -92,6 +92,10 @@ contains ! Since the MGXS can be angle dependent, this needs to be done ! After every collision for the MGXS mode if (p % material /= MATERIAL_VOID) then + ! Update the temperature index + call macro_xs(p % material) % obj % find_temperature(p % sqrtkT, & + temperature_tolerance) + ! Get the data call macro_xs(p % material) % obj % calculate_xs(p % g, & p % coord(p % n_coord) % uvw, material_xs) else From 7e5326d705b90f5081eca9206388cc91fa6bafb9 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 4 Sep 2016 15:40:02 -0400 Subject: [PATCH 05/82] Removed unused variables, cleaned up other code base, fixed all the bugs (seems to work now!), set default MGXS library temperature (via the API) to 294K to be consistent with the default w/in OpenMC. Looking good folks. Next up is re-implementing the user-facing option for converting Legendre to tabular (it shouldnt be in the library like it was before), implementing a script to convert from xml to h5, and switching the library format to use sparse scattering matrices instead of dense --- openmc/mesh.py | 7 +++- openmc/mgxs/library.py | 5 ++- openmc/mgxs_library.py | 90 +++++++++++++++++++++--------------------- src/input_xml.F90 | 1 + src/mgxs_data.F90 | 15 +++++-- src/mgxs_header.F90 | 76 +++++++++++++++++++---------------- src/tracking.F90 | 3 +- 7 files changed, 108 insertions(+), 89 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index 7d7b483f73..43ac7aef05 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -288,9 +288,12 @@ class Mesh(object): openmc.YPlane(y0=self.upper_right[1], boundary_type=bc[3])] if twod: - zplanes = [openmc.ZPlane(z0=np.finfo(np.float).min, + # Would prefer to have the z ranges be the max supported float, but + # these values are apparently different between python and Fortran. + # Choosing a safe and sane default. + zplanes = [openmc.ZPlane(z0=-1000., boundary_type='reflective'), - openmc.ZPlane(z0=np.finfo(np.float).max, + openmc.ZPlane(z0=1000., boundary_type='reflective')] else: zplanes = [openmc.ZPlane(z0=self.lower_left[2], diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 9f0e173f3c..a04ec8c557 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -907,8 +907,11 @@ class Library(object): # the provided order or the Library's order. xsdata.order = min(order, self.legendre_order) + # Right now only 'legendre' data and isotropic weighting is supported + self.scatter_type = 'legendre' + self.representation = 'isotropic' + if nuclide is not 'total': - xsdata.zaid = self._nuclides[nuclide][0] xsdata.awr = self._nuclides[nuclide][1] if subdomain is None: diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 68c0063f2b..15d80dc913 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -20,13 +20,7 @@ _SCATTER_TYPE_TABULAR = 3 _SCATTER_TYPE_LEGENDRE = 4 _SCATTER_TYPE_HISTOGRAM = 5 _REPRESENTATIONS = ['isotropic', 'angle'] -_REPRESENTATIONS_TEXT = {'isotropic': _REPRESENTATION_ISOTROPIC, - 'angle': _REPRESENTATION_ANGLE} _SCATTER_TYPES = ['tabular', 'legendre', 'histogram'] -_SCATTER_TYPES_TEXT = {'tabular': _SCATTER_TYPE_TABULAR, - 'legendre': _SCATTER_TYPE_LEGENDRE, - 'histogram': _SCATTER_TYPE_HISTOGRAM} - class XSdata(object): """A multi-group cross section data set providing all the @@ -43,7 +37,7 @@ class XSdata(object): weighting). Defaults to 'isotropic' temperatures : numpy.ndarray Temperatures (in units of Kelvin) of the provided datasets. Defaults - to a single temperature at 300K. + to a single temperature at 294K. Attributes ---------- @@ -54,7 +48,7 @@ class XSdata(object): of the isotope to the mass of a single neutron. temperatures : numpy.ndarray Temperatures (in units of Kelvin) of the provided datasets. Defaults - to a single temperature at 300K. + to a single temperature at 294K. energy_groups : openmc.mgxs.EnergyGroups Energy group structure fissionable : bool @@ -164,7 +158,7 @@ class XSdata(object): """ - def __init__(self, name, energy_groups, temperatures=[300.], + def __init__(self, name, energy_groups, temperatures=[294.], representation='isotropic'): # Initialize class attributes self.name = name @@ -377,7 +371,7 @@ class XSdata(object): check_type('use_chi', use_chi, bool) self._use_chi = use_chi - def set_total(self, total, temperature=300.): + def set_total(self, total, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -387,7 +381,7 @@ class XSdata(object): Total Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -405,7 +399,7 @@ class XSdata(object): i = self.temperatures.tolist().index(temperature) self._total[i] = nptotal - def set_absorption(self, absorption, temperature=300.): + def set_absorption(self, absorption, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -415,7 +409,7 @@ class XSdata(object): Absorption Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -434,7 +428,7 @@ class XSdata(object): i = self.temperatures.tolist().index(temperature) self._absorption[i] = npabsorption - def set_fission(self, fission, temperature=300.): + def set_fission(self, fission, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -444,7 +438,7 @@ class XSdata(object): Fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -465,7 +459,7 @@ class XSdata(object): if np.sum(npfission) > 0.0: self._fissionable = True - def set_kappa_fission(self, kappa_fission, temperature=300.): + def set_kappa_fission(self, kappa_fission, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -475,7 +469,7 @@ class XSdata(object): Kappa-Fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -498,7 +492,7 @@ class XSdata(object): if np.sum(npkappa_fission) > 0.0: self._fissionable = True - def set_chi(self, chi, temperature=300.): + def set_chi(self, chi, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -508,7 +502,7 @@ class XSdata(object): Fission Spectrum temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -538,7 +532,7 @@ class XSdata(object): if self.use_chi is not None: self.use_chi = True - def set_scatter_matrix(self, scatter, temperature=300.): + def set_scatter_matrix(self, scatter, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -548,7 +542,7 @@ class XSdata(object): Scattering Matrix Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -567,7 +561,7 @@ class XSdata(object): i = self.temperatures.tolist().index(temperature) self._scatter_matrix[i] = npscatter - def set_multiplicity_matrix(self, multiplicity, temperature=300.): + def set_multiplicity_matrix(self, multiplicity, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -577,7 +571,7 @@ class XSdata(object): Multiplicity Matrix Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -597,7 +591,7 @@ class XSdata(object): i = self.temperatures.tolist().index(temperature) self._multiplicity_matrix[i] = npmultiplicity - def set_nu_fission(self, nu_fission, temperature=300.): + def set_nu_fission(self, nu_fission, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. @@ -607,7 +601,7 @@ class XSdata(object): Nu-fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K See also -------- @@ -655,7 +649,7 @@ class XSdata(object): if np.sum(npnu_fission) > 0.0: self._fissionable = True - def set_total_mgxs(self, total, temperature=300., nuclide='total', + def set_total_mgxs(self, total, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.TotalXS or openmc.mgxs.TransportXS to be used to set the total cross section @@ -668,7 +662,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -702,7 +696,7 @@ class XSdata(object): msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_absorption_mgxs(self, absorption, temperature=300., + def set_absorption_mgxs(self, absorption, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.AbsorptionXS to be used to set the absorption cross section for this XSdata object. @@ -714,7 +708,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -749,7 +743,7 @@ class XSdata(object): msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_fission_mgxs(self, fission, temperature=300., nuclide='total', + def set_fission_mgxs(self, fission, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.FissionXS to be used to set the fission cross section for this XSdata object. @@ -761,7 +755,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -796,7 +790,7 @@ class XSdata(object): msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_nu_fission_mgxs(self, nu_fission, temperature=300., + def set_nu_fission_mgxs(self, nu_fission, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.NuFissionXS to be used to set the nu-fission cross section for this XSdata object. @@ -808,7 +802,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -852,7 +846,7 @@ class XSdata(object): if np.sum(self._nu_fission) > 0.0: self._fissionable = True - def set_kappa_fission_mgxs(self, k_fission, temperature=300., + def set_kappa_fission_mgxs(self, k_fission, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.KappaFissionXS @@ -866,7 +860,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -901,7 +895,7 @@ class XSdata(object): msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) - def set_chi_mgxs(self, chi, temperature=300., nuclide='total', + def set_chi_mgxs(self, chi, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.Chi to be used to set chi for this XSdata object. @@ -912,7 +906,7 @@ class XSdata(object): MGXS Object containing chi for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -954,7 +948,7 @@ class XSdata(object): if self.use_chi is not None: self.use_chi = True - def set_scatter_matrix_mgxs(self, scatter, temperature=300., + def set_scatter_matrix_mgxs(self, scatter, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.ScatterMatrixXS @@ -969,7 +963,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -1027,7 +1021,7 @@ class XSdata(object): raise ValueError(msg) def set_multiplicity_matrix_mgxs(self, nuscatter, scatter=None, - temperature=300., nuclide='total', + temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for either the direct use of only an openmc.mgxs.MultiplicityMatrixXS OR @@ -1050,7 +1044,7 @@ class XSdata(object): for the domain of interest. temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults - to 300K + to 294K nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -1119,22 +1113,26 @@ class XSdata(object): if self.fissionable is not None: grp.attrs['fissionable'] = self.fissionable if self.representation is not None: - grp.attrs['representation'] = \ - np.string_(_REPRESENTATIONS_TEXT[self.representation]) + grp.attrs['representation'] = np.string_(self.representation) if self.representation == 'angle': if self.num_azimuthal is not None: grp.attrs['num-azimuthal'] = self.num_azimuthal if self.num_polar is not None: grp.attrs['num-polar'] = self.num_polar if self.scatter_type is not None: - grp.attrs['scatter-type'] = \ - np.string_(_SCATTER_TYPES_TEXT[self.scatter_type]) + grp.attrs['scatter-type'] = np.string_(self.scatter_type) if self.order is not None: grp.attrs['order'] = self.order + ktg = grp.create_group('kTs') + for temperature in self.temperatures: + temp_label = str(int(np.round(temperature))) + "K" + kT = temperature * openmc.data.K_BOLTZMANN + ktg.create_dataset(temp_label, data=kT) + # Create the temperature datasets for i, temperature in enumerate(self.temperatures): - xsgrp = grp.create_group(str(np.round(temperature)) + "K") + xsgrp = grp.create_group(str(int(np.round(temperature))) + "K") if self._total[i] is not None: xsgrp.create_dataset("total", data=self._total[i], compression=compression) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index eafbc717c2..c44c6b7bda 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -16,6 +16,7 @@ module input_xml use hdf5_interface use list_header, only: ListChar, ListInt, ListReal use mesh_header, only: RegularMesh + use mgxs_data, only: create_macro_xs, read_mgxs use multipole, only: multipole_read use output, only: write_message use plot_header diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 7cbb4864c7..d4ad96da57 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -1,6 +1,7 @@ module mgxs_data use constants + use algorithm, only: find use error, only: fatal_error use global use hdf5 @@ -28,6 +29,7 @@ contains integer :: i_nuclide ! index in nuclides array character(20) :: name ! name of library to load integer :: representation ! Data representation + character(MAX_LINE_LEN) :: temp_str type(Material), pointer :: mat type(SetChar) :: already_read integer(HID_T) :: file_id @@ -99,9 +101,12 @@ contains ! First find out the data representation if (check_attribute(xsdata_group, "representation")) then - call read_attribute(representation, xsdata_group, "representation") - if (representation /= MGXS_ISOTROPIC .and. & - representation /= MGXS_ANGLE) then + call read_attribute(temp_str, xsdata_group, "representation") + if (trim(temp_str) == 'isotropic') then + representation = MGXS_ISOTROPIC + else if (trim(temp_str) == 'angle') then + representation = MGXS_ANGLE + else call fatal_error("Invalid Data Representation!") end if else @@ -179,7 +184,9 @@ contains allocate(MgxsAngle :: macro_xs(i_mat) % obj) end select call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & - energy_groups, max_order) + energy_groups, max_order, & + temperature_tolerance, & + temperature_method) end do end subroutine create_macro_xs diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index c86685bc0d..0c0bcc94f2 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -6,6 +6,7 @@ module mgxs_header use hdf5, only: HID_T, HSIZE_T, SIZE_T, h5iget_name_f use h5lt, only: h5ltpath_valid_f + use algorithm, only: find, sort use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI use error, only: fatal_error use hdf5_interface @@ -100,7 +101,8 @@ module mgxs_header integer, intent(in) :: max_order ! Maximum requested order end subroutine mgxs_from_hdf5_ - subroutine mgxs_combine_(this, temps, mat, nuclides, groups, max_order) + subroutine mgxs_combine_(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) import Mgxs, Material, MgxsContainer, VectorReal class(Mgxs), intent(inout) :: this ! The Mgxs to initialize type(VectorReal), intent(in) :: temps ! Temperatures to obtain @@ -108,6 +110,8 @@ module mgxs_header type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups integer, intent(in) :: max_order ! Maximum requested order + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access end subroutine mgxs_combine_ pure function mgxs_get_xs_(this, xstype, gin, gout, uvw, mu) result(xs_val) @@ -206,12 +210,11 @@ module mgxs_header integer :: hdf5_err integer(SIZE_T) :: name_len, name_file_len - integer(HID_T) :: kT_group, kT_dset + integer(HID_T) :: kT_group character(MAX_FILE_LEN), allocatable :: dset_names(:) real(8), allocatable :: temps_available(:) ! temperatures available real(8) :: temp_desired real(8) :: temp_actual - logical :: exists character(MAX_WORD_LEN) :: temp_str real(8) :: dangle integer :: ipol, iazi @@ -236,6 +239,7 @@ module mgxs_header do i = 1, size(dset_names) ! Read temperature value call read_dataset(temps_available(i), kT_group, trim(dset_names(i))) + ! Convert MeV to Kelvin temps_available(i) = temps_available(i) / K_BOLTZMANN end do @@ -377,7 +381,7 @@ module mgxs_header real(8), allocatable :: input_scatt(:, :, :) real(8), allocatable :: temp_scatt(:, :, :) real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l, arr_len + integer :: order, order_dim, gin, gout, l integer :: legendre_mu_points, imu type(VectorInt) :: temps_to_read integer :: t @@ -387,12 +391,13 @@ module mgxs_header temps_to_read, order_dim) !!!TODO: Fix enable_leg_mu = .True. + legendre_mu_points = 33 ! Load the more specific data do t = 1, temps_to_read % size() associate(xs => this % xs(t)) ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(i))) // "K" + temp_str = trim(to_str(temps_to_read % data(t))) // "K" xsdata_grp = open_group(xs_id, trim(temp_str)) if (this % fissionable) then allocate(xs % nu_fission(groups)) @@ -619,8 +624,8 @@ module mgxs_header real(8), allocatable :: scatt_coeffs(:, :, :, :, :) real(8), allocatable :: input_scatt(:, :, :, :, :) real(8), allocatable :: temp_scatt(:, :, :, :, :) - real(8) :: dmu, mu, norm, dangle - integer :: order, order_dim, gin, gout, l, arr_len + real(8) :: dmu, mu, norm + integer :: order, order_dim, gin, gout, l integer :: legendre_mu_points, imu, ipol, iazi type(VectorInt) :: temps_to_read integer :: t @@ -630,12 +635,13 @@ module mgxs_header temps_to_read, order_dim) !!!TODO: Fix enable_leg_mu = .True. + legendre_mu_points = 33 ! Load the more specific data do t = 1, temps_to_read % size() associate(xs => this % xs(t)) ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(i))) // "K" + temp_str = trim(to_str(temps_to_read % data(t))) // "K" xsdata_grp = open_group(xs_id, trim(temp_str)) if (this % fissionable) then if (check_dataset(xsdata_grp, "chi")) then @@ -899,16 +905,17 @@ module mgxs_header ! MGXS*_COMBINE Builds a macroscopic Mgxs object from microscopic Mgxs objects !=============================================================================== - subroutine mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) + subroutine mgxs_combine(this, temps, mat, nuclides, max_order, & + scatter_type, order_dim) class(Mgxs), intent(inout) :: this ! The Mgxs to initialize type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from + integer, intent(in) :: max_order ! Maximum requested order integer, intent(out) :: scatter_type ! Type of scatter integer, intent(out) :: order_dim ! Scattering data order size - integer :: t, mat_max_order, max_order, order, n_pol, n_azi - real(8) :: dangle + integer :: t, mat_max_order, order ! Fill in meta-data from material information if (mat % name == "") then @@ -924,7 +931,7 @@ module mgxs_header allocate(this % kTs(temps % size())) do t = 1, temps % size() - this % kTs(t) = temps % data(i) + this % kTs(t) = temps % data(t) end do ! Allocate the XS object for the number of temperatures @@ -1004,20 +1011,23 @@ module mgxs_header end subroutine mgxs_combine - subroutine mgxsiso_combine(this, temps, mat, nuclides, groups, max_order) + subroutine mgxsiso_combine(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) class(MgxsIso), intent(inout) :: this ! The Mgxs to initialize type(VectorReal), intent(in) :: temps ! Temperatures to obtain [MeV] type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups integer, intent(in) :: max_order ! Maximum requested order + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access integer :: i ! loop index over nuclides integer :: t ! Index in to temps integer :: gin, gout ! group indices real(8) :: atom_density ! atom density of a nuclide real(8) :: norm, nuscatt - integer :: mat_max_order, order, order_dim, nuc_order_dim + integer :: order_dim, nuc_order_dim real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) real(8), allocatable :: scatt_coeffs(:, :, :) integer :: nuc_t @@ -1025,7 +1035,8 @@ module mgxs_header integer :: scatter_type ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & + order_dim) ! Create the Xs Data for each temperature TEMP_LOOP: do t = 1, temps % size() @@ -1067,11 +1078,11 @@ module mgxs_header ! Determine actual temperatures to read temp_desired = temps % data(i) nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(i_closest) + temp_actual = nuc % kTs(nuc_t) if (abs(temp_actual - temp_desired) >= tolerance) then call fatal_error("MGXS library does not contain cross sections & &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired))) // " K.") + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") end if case (TEMPERATURE_INTERPOLATION) @@ -1174,13 +1185,16 @@ module mgxs_header end subroutine mgxsiso_combine - subroutine mgxsang_combine(this, temps, mat, nuclides, groups, max_order) + subroutine mgxsang_combine(this, temps, mat, nuclides, groups, max_order, & + tolerance, method) class(MgxsAngle), intent(inout) :: this ! The Mgxs to initialize type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: groups ! Number of E groups integer, intent(in) :: max_order ! Maximum requested order + real(8), intent(in) :: tolerance ! Tolerance on method + integer, intent(in) :: method ! Type of temperature access integer :: i ! loop index over nuclides integer :: t ! temperature loop index @@ -1188,7 +1202,7 @@ module mgxs_header real(8) :: atom_density ! atom density of a nuclide integer :: ipol, iazi, n_pol, n_azi real(8) :: norm, nuscatt - integer :: mat_max_order, order, order_dim, nuc_order_dim + integer :: order_dim, nuc_order_dim real(8), allocatable :: temp_mult(:, :, :, :), mult_num(:, :, :, :) real(8), allocatable :: mult_denom(:, :, :, :), scatt_coeffs(:, :, :, :, :) integer :: nuc_t @@ -1196,7 +1210,8 @@ module mgxs_header integer :: scatter_type ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, scatter_type, order_dim) + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & + order_dim) ! Get the number of each polar and azi angles and make sure all the ! NuclideAngle types have the same number of these angles @@ -1268,11 +1283,11 @@ module mgxs_header ! Determine actual temperatures to read temp_desired = temps % data(i) nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(i_closest) + temp_actual = nuc % kTs(nuc_t) if (abs(temp_actual - temp_desired) >= tolerance) then call fatal_error("MGXS library does not contain cross sections & &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired))) // " K.") + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") end if case (TEMPERATURE_INTERPOLATION) @@ -1325,7 +1340,7 @@ module mgxs_header nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) mult_num(iazi, ipol, gout, gin) = & - mult_num(iazi, ipo, gout, gin) + atom_density * & + mult_num(iazi, ipol, gout, gin) + atom_density * & nuscatt if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then mult_denom(iazi, ipol, gout, gin) = & @@ -1716,18 +1731,11 @@ module mgxs_header ! sqrt(temperature), (with temperature in units of MeV) !=============================================================================== - pure subroutine mgxs_find_temperature(this, sqrtkT, tolerance) - class(Mgxs), intent(in) :: this - real(8), intent(in) :: sqrtkT ! Temperature (in units of of MeV) - real(8), intent(in) :: tolerance ! Temperature tolerance + pure subroutine mgxs_find_temperature(this, sqrtkT) + class(Mgxs), intent(inout) :: this + real(8), intent(in) :: sqrtkT ! Temperature (in units of of MeV) - real(8) :: kT - integer :: i_temp - - kT = sqrtkT**2 - do i_temp = 1, size(this % kTs) - if (abs(this % kTs(i_temp) - kT) < K_BOLTZMANN * tolerance) exit - end do + this % index_temp = minloc(abs(this % kTs - (sqrtkT * sqrtkT)), dim=1) end subroutine mgxs_find_temperature diff --git a/src/tracking.F90 b/src/tracking.F90 index a03cde98dd..b62cfc85a0 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -93,8 +93,7 @@ contains ! After every collision for the MGXS mode if (p % material /= MATERIAL_VOID) then ! Update the temperature index - call macro_xs(p % material) % obj % find_temperature(p % sqrtkT, & - temperature_tolerance) + call macro_xs(p % material) % obj % find_temperature(p % sqrtkT) ! Get the data call macro_xs(p % material) % obj % calculate_xs(p % g, & p % coord(p % n_coord) % uvw, material_xs) From 252c9152e67c6c25fab80e15fce82db63711f977 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 5 Sep 2016 06:09:05 -0400 Subject: [PATCH 06/82] Re-enabled the option to convert Legendre scattering kernels to tabular, but this time in settings.xml instead of within the library --- docs/source/usersguide/input.rst | 30 ++++++++++++++++++++++++ openmc/settings.py | 35 ++++++++++++++++++++++++++++ src/global.F90 | 6 +++++ src/input_xml.F90 | 26 +++++++++++++++++++++ src/mgxs_data.F90 | 3 ++- src/mgxs_header.F90 | 40 +++++++++++++++++--------------- 6 files changed, 120 insertions(+), 20 deletions(-) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index e9126f16b3..70ba30171b 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -709,6 +709,36 @@ survival biasing, otherwise known as implicit capture or absorption. *Default*: false +.. _tabular_legendre: + +```` Element +--------------------------------- + +The optional ```` element specifies how the multi-group +Legendre scattering kernel is represented if encountered in a multi-group +problem. Specifically, the options are to either convert the Legendre +expansion to a tabular representation or leave it as a set of Legendre +coefficients. Converting to a tabular representation will cost memory but can +allow for a decrease in runtime compared to leaving as a set of Legendre +coefficients. This element has the following attributes/sub-elements: + + :enable: + This attribute/sub-element denotes whether or not the conversion of a + Legendre scattering expansion to the tabular format should be performed or + not. A value of “true” means the conversion should be performed, “false” + means it will not. + + *Default*: true + + :num_points: + If the conversion is to take place the number of tabular points is + required. This attribute/sub-element allows the user to set the desired + number of points. + + *Default*: 33 + + .. note:: This element is not used in the multi-group :ref:`energy_mode`. + .. _temperature_default: ```` Element diff --git a/openmc/settings.py b/openmc/settings.py index 86aac94712..ffd7a42233 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -101,6 +101,13 @@ class Settings(object): Coordinates of the lower-left point of the Shannon entropy mesh entropy_upper_right : tuple or list Coordinates of the upper-right point of the Shannon entropy mesh + tabular_legendre : dict + Determines if a multi-group scattering moment kernel expanded via + Legendre polynomials is to be converted to a tabular distribution or + not. Accepted keys are 'enable', and 'num_points'. The value for + 'enable' is a bool stating whether the conversion to tabular is + performed; the value for 'num_points' sets the number of points to use + in the tabular distribution, should 'enable' be True. temperature : dict Defines a default temperature and method for treating intermediate temperatures at which nuclear data doesn't exist. Accepted keys are @@ -199,6 +206,8 @@ class Settings(object): self._trace = None self._track = None + self._tabular_legendre = {} + self._temperature = {} # Cutoff subelement @@ -362,6 +371,10 @@ class Settings(object): def verbosity(self): return self._verbosity + @property + def tabular_legendre(self): + return self._tabular_legendre + @property def temperature(self): return self._temperature @@ -667,6 +680,19 @@ class Settings(object): cv.check_type('no reduction option', no_reduce, bool) self._no_reduce = no_reduce + @tabular_legendre.setter + def tabular_legendre(self, tabular_legendre): + cv.check_type('tabular_legendre settings', tabular_legendre, Mapping) + for key, value in tabular_legendre.items(): + cv.check_value('tabular_legendre key', key, + ['enable', 'num_points']) + if key == 'enable': + cv.check_type('enable tabular_legendre', value, bool) + elif key == 'num_points': + cv.check_type('num_points tabular_legendre', value, Integral) + cv.check_greater_than('num_points tabular_legendre', value, 0) + self._tabular_legendre = tabular_legendre + @temperature.setter def temperature(self, temperature): cv.check_type('temperature settings', temperature, Mapping) @@ -1048,6 +1074,14 @@ class Settings(object): element = ET.SubElement(self._settings_file, "no_reduce") element.text = str(self._no_reduce).lower() + def _create_tabular_legendre_subelements(self): + if self.tabular_legendre: + element = ET.SubElement(self._settings_file, "tabular_legendre") + subelement = ET.SubElement(element, "enable") + subelement.text = str(self._tabular_legendre['enable']).lower() + subelement = ET.SubElement(element, "num_points") + subelement.text = str(self._tabular_legendre['num_points']) + def _create_temperature_subelements(self): if self.temperature: for key, value in self.temperature.items(): @@ -1149,6 +1183,7 @@ class Settings(object): self._create_no_reduce_subelement() self._create_threads_subelement() self._create_verbosity_subelement() + self._create_tabular_legendre_subelements() self._create_temperature_subelements() self._create_trace_subelement() self._create_track_subelement() diff --git a/src/global.F90 b/src/global.F90 index bea5f61a83..6e804c90af 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -128,6 +128,12 @@ module global ! Maximum Data Order integer :: max_order + ! Whether or no to convert Legendres to tabulars + logical :: legendre_to_tabular = .True. + + ! Number of points to use in the Legendre to tabular conversion + integer :: legendre_to_tabular_points = 33 + ! ============================================================================ ! TALLY-RELATED VARIABLES diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c44c6b7bda..24875d1fe9 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -92,6 +92,7 @@ contains type(Node), pointer :: node_trigger => null() type(Node), pointer :: node_keff_trigger => null() type(Node), pointer :: node_vol => null() + type(Node), pointer :: node_tab_leg => null() type(NodeList), pointer :: node_scat_list => null() type(NodeList), pointer :: node_source_list => null() type(NodeList), pointer :: node_vol_list => null() @@ -1093,6 +1094,31 @@ contains call get_node_value(doc, "temperature_tolerance", temperature_tolerance) end if + ! Check for tabular_legendre options + if (check_for_node(doc, "tabular_legendre")) then + + ! Get pointer to tabular_legendre node + call get_node_ptr(doc, "tabular_legendre", node_tab_leg) + + ! Check for enable option + if (check_for_node(node_tab_leg, "enable")) then + call get_node_value(node_tab_leg, "enable", temp_str) + temp_str = to_lower(temp_str) + if (trim(temp_str) == 'false' .or. & + trim(temp_str) == '0') legendre_to_tabular = .false. + end if + + ! Check for the number of points + if (check_for_node(node_tab_leg, "num_points")) then + call get_node_value(node_tab_leg, "num_points", & + legendre_to_tabular_points) + if (legendre_to_tabular_points <= 1 .and. (.not. run_CE)) then + call fatal_error("The 'num_points' subelement/attribute of the & + &'tabular_legendre' element must contain a value greater than 1") + end if + end if + end if + ! Close settings XML file call close_xmldoc(doc) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index d4ad96da57..f17f2781ed 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -125,7 +125,8 @@ contains ! Now read in the data specific to the type we just declared call nuclides_MG(i_nuclide) % obj % from_hdf5(xsdata_group, & energy_groups, temps(i_nuclide), temperature_method, & - temperature_tolerance, get_kfiss, get_fiss, max_order) + temperature_tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) ! Add name to dictionary call already_read % add(name) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 0c0bcc94f2..cefd8725d6 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -88,7 +88,8 @@ module mgxs_header abstract interface subroutine mgxs_from_hdf5_(this, xs_id, groups, temperature, method, & - tolerance, get_kfiss, get_fiss, max_order) + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) import Mgxs, HID_T, VectorReal class(Mgxs), intent(inout) :: this ! Working Object integer(HID_T), intent(in) :: xs_id ! Library data @@ -99,6 +100,9 @@ module mgxs_header logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion end subroutine mgxs_from_hdf5_ subroutine mgxs_combine_(this, temps, mat, nuclides, groups, max_order, & @@ -361,7 +365,8 @@ module mgxs_header end subroutine mgxs_from_hdf5 subroutine mgxsiso_from_hdf5(this, xs_id, groups, temperature, method, & - tolerance, get_kfiss, get_fiss, max_order) + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) class(MgxsIso), intent(inout) :: this ! Working Object integer(HID_T), intent(in) :: xs_id ! Group in H5 file integer, intent(in) :: groups ! Number of Energy groups @@ -371,27 +376,25 @@ module mgxs_header logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion character(MAX_LINE_LEN) :: temp_str integer(HID_T) :: xsdata_grp - logical :: enable_leg_mu real(8), allocatable :: temp_arr(:), temp_2d(:, :) real(8), allocatable :: temp_mult(:, :) real(8), allocatable :: scatt_coeffs(:, :, :) real(8), allocatable :: input_scatt(:, :, :) real(8), allocatable :: temp_scatt(:, :, :) real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l - integer :: legendre_mu_points, imu + integer :: order, order_dim, gin, gout, l, imu type(VectorInt) :: temps_to_read integer :: t ! Call generic data gathering routine (will populate the metadata) call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & temps_to_read, order_dim) - !!!TODO: Fix - enable_leg_mu = .True. - legendre_mu_points = 33 ! Load the more specific data do t = 1, temps_to_read % size() @@ -508,10 +511,10 @@ module mgxs_header ! provided as Legendre coefficients), and the user requested that ! these legendres be converted to tabular form (note xs is also ! the default behavior), convert that now. - if (this % scatter_type == ANGLE_LEGENDRE .and. enable_leg_mu) then + if (this % scatter_type == ANGLE_LEGENDRE .and. legendre_to_tabular) then ! Convert input parameters to what we need for the rest. this % scatter_type = ANGLE_TABULAR - order_dim = legendre_mu_points + order_dim = legendre_to_tabular_points order = order_dim dmu = TWO / real(order - 1, 8) @@ -605,7 +608,8 @@ module mgxs_header end subroutine mgxsiso_from_hdf5 subroutine mgxsang_from_hdf5(this, xs_id, groups, temperature, method, & - tolerance, get_kfiss, get_fiss, max_order) + tolerance, get_kfiss, get_fiss, max_order, & + legendre_to_tabular, legendre_to_tabular_points) class(MgxsAngle), intent(inout) :: this ! Working Object integer(HID_T), intent(in) :: xs_id ! Group in H5 file integer, intent(in) :: groups ! Number of Energy groups @@ -615,27 +619,25 @@ module mgxs_header logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? integer, intent(in) :: max_order ! Maximum requested order + logical, intent(in) :: legendre_to_tabular ! Convert Legendres to Tabular? + integer, intent(in) :: legendre_to_tabular_points ! Number of points to use + ! in that conversion character(MAX_LINE_LEN) :: temp_str integer(HID_T) :: xsdata_grp - logical :: enable_leg_mu real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) real(8), allocatable :: temp_mult(:, :, :, :) real(8), allocatable :: scatt_coeffs(:, :, :, :, :) real(8), allocatable :: input_scatt(:, :, :, :, :) real(8), allocatable :: temp_scatt(:, :, :, :, :) real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l - integer :: legendre_mu_points, imu, ipol, iazi + integer :: order, order_dim, gin, gout, l, imu, ipol, iazi type(VectorInt) :: temps_to_read integer :: t ! Call generic data gathering routine (will populate the metadata) call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & temps_to_read, order_dim) - !!!TODO: Fix - enable_leg_mu = .True. - legendre_mu_points = 33 ! Load the more specific data do t = 1, temps_to_read % size() @@ -794,11 +796,11 @@ module mgxs_header ! provided as Legendre coefficients), and the user requested that ! these legendres be converted to tabular form (note xs is also ! the default behavior), convert that now. - if (this % scatter_type == ANGLE_LEGENDRE .and. enable_leg_mu) then + if (this % scatter_type == ANGLE_LEGENDRE .and. legendre_to_tabular) then ! Convert input parameters to what we need for the rest. this % scatter_type = ANGLE_TABULAR - order_dim = legendre_mu_points + order_dim = legendre_to_tabular_points order = order_dim dmu = TWO / real(order - 1, 8) From 6e68b23d58de20bf51532fb1372434a2d5279db0 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 5 Sep 2016 19:42:12 -0400 Subject: [PATCH 07/82] Added script to convert old xml mgxs libraries to new hdf5 libraries --- .../python/pincell_multigroup/build-xml.py | 69 ++-- .../pincell_multigroup/mg_cross_sections.xml | 383 ------------------ examples/xml/pincell_multigroup/settings.xml | 3 +- openmc/mgxs_library.py | 26 +- scripts/openmc-update-mgxs.py | 229 +++++++++++ src/mgxs_data.F90 | 14 +- src/mgxs_header.F90 | 15 +- 7 files changed, 308 insertions(+), 431 deletions(-) delete mode 100644 examples/xml/pincell_multigroup/mg_cross_sections.xml create mode 100755 scripts/openmc-update-mgxs.py diff --git a/examples/python/pincell_multigroup/build-xml.py b/examples/python/pincell_multigroup/build-xml.py index 2b08e82748..70421281da 100644 --- a/examples/python/pincell_multigroup/build-xml.py +++ b/examples/python/pincell_multigroup/build-xml.py @@ -21,44 +21,47 @@ groups = openmc.mgxs.EnergyGroups(group_edges=[1E-11, 0.0635E-6, 10.0E-6, # Instantiate the 7-group (C5G7) cross section data uo2_xsdata = openmc.XSdata('UO2', groups) uo2_xsdata.order = 0 -uo2_xsdata.total = [0.1779492, 0.3298048, 0.4803882, 0.5543674, - 0.3118013, 0.3951678, 0.5644058] -uo2_xsdata.absorption = [8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, - 3.0020E-02, 1.1126E-01, 2.8278E-01] -uo2_xsdata.scatter = [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]] -uo2_xsdata.fission = [7.21206E-03, 8.19301E-04, 6.45320E-03, - 1.85648E-02, 1.78084E-02, 8.30348E-02, - 2.16004E-01] -uo2_xsdata.nu_fission = [2.005998E-02, 2.027303E-03, 1.570599E-02, - 4.518301E-02, 4.334208E-02, 2.020901E-01, - 5.257105E-01] -uo2_xsdata.chi = [5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07, - 0.0000E+00, 0.0000E+00, 0.0000E+00] +uo2_xsdata.set_total( + [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, + 0.5644058]) +uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, + 3.0020E-02, 1.1126E-01, 2.8278E-01]) +uo2_xsdata.set_scatter_matrix( + [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) +uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03, + 1.85648E-02, 1.78084E-02, 8.30348E-02, + 2.16004E-01]) +uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02, + 4.518301E-02, 4.334208E-02, 2.020901E-01, + 5.257105E-01]) +uo2_xsdata.set_chi([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00, + 0.0000E+00, 0.0000E+00]) h2o_xsdata = openmc.XSdata('LWTR', groups) h2o_xsdata.order = 0 -h2o_xsdata.total = [0.15920605, 0.412969593, 0.59030986, 0.58435, - 0.718, 1.2544497, 2.650379] -h2o_xsdata.absorption = [6.0105E-04, 1.5793E-05, 3.3716E-04, - 1.9406E-03, 5.7416E-03, 1.5001E-02, - 3.7239E-02] -h2o_xsdata.scatter = [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], - [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], - [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], - [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], - [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], - [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]] +h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, + 0.718, 1.2544497, 2.650379]) +h2o_xsdata.set_absorption([6.0105E-04, 1.5793E-05, 3.3716E-04, + 1.9406E-03, 5.7416E-03, 1.5001E-02, + 3.7239E-02]) +h2o_xsdata.set_scatter_matrix( + [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], + [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], + [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], + [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], + [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) mg_cross_sections_file = openmc.MGXSLibrary(groups) mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata]) -mg_cross_sections_file.export_to_xml() +mg_cross_sections_file.export_to_hdf5() ############################################################################### @@ -129,7 +132,7 @@ geometry.export_to_xml() # Instantiate a Settings object, set all runtime parameters, and export to XML settings_file = openmc.Settings() settings_file.energy_mode = "multi-group" -settings_file.cross_sections = "./mgxs.xml" +settings_file.cross_sections = "./mgxs.h5" settings_file.batches = batches settings_file.inactive = inactive settings_file.particles = particles diff --git a/examples/xml/pincell_multigroup/mg_cross_sections.xml b/examples/xml/pincell_multigroup/mg_cross_sections.xml deleted file mode 100644 index af1f0072b4..0000000000 --- a/examples/xml/pincell_multigroup/mg_cross_sections.xml +++ /dev/null @@ -1,383 +0,0 @@ - - - - 7 - - 1E-11 0.0635E-6 10.0E-6 1.0E-4 1.0E-3 0.5 1.0 20.0 - - - - - - UO2 - UO2 - 2.53E-8 - 0 - true - - isotropic - - - - 8.0248E-03 3.7174E-03 2.6769E-02 9.6236E-02 3.0020E-02 1.1126E-01 2.8278E-01 - - - - 2.005998E-02 2.027303E-03 1.570599E-02 4.518301E-02 4.334208E-02 2.020901E-01 5.257105E-01 - - - - 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00 - - - 7.21206E-03 8.19301E-04 6.45320E-03 1.85648E-02 1.78084E-02 8.30348E-02 2.16004E-01 - - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 0.1275370 0.0423780 0.0000094 0.0000000 0.0000000 0.0000000 0.0000000 - 0.0000000 0.3244560 0.0016314 0.0000000 0.0000000 0.0000000 0.0000000 - 0.0000000 0.0000000 0.4509400 0.0026792 0.0000000 0.0000000 0.0000000 - 0.0000000 0.0000000 0.0000000 0.4525650 0.0055664 0.0000000 0.0000000 - 0.0000000 0.0000000 0.0000000 0.0001253 0.2714010 0.0102550 0.0000000 - 0.0000000 0.0000000 0.0000000 0.0000000 0.0012968 0.2658020 0.0168090 - 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0085458 0.2730800 - - - - - 0.1779492 0.3298048 0.4803882 0.5543674000000001 0.3118013 0.39516779999999996 0.5644058 - - - - - - - MOX1 - MOX1 - 2.53E-8 - 0 - true - - - - 8.4339E-03 3.7577E-03 2.7970E-02 1.0421E-01 1.3994E-01 4.0918E-01 4.0935E-01 - - - - 1.27888062E-02 8.95701528E-03 7.37557218E-06 2.55837033E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1.49041240E-03 1.04385401E-03 8.59552023E-07 2.98153464E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 9.56411400E-03 6.69850756E-03 5.51582469E-06 1.91327830E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3.84928781E-02 2.69596154E-02 2.21996483E-05 7.70040890E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1.80629998E-02 1.26509513E-02 1.04173100E-05 3.61346022E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3.91930789E-01 2.74500216E-01 2.26034688E-04 7.84048241E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 4.19762096E-01 2.93992687E-01 2.42085585E-04 8.39724109E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00 - - - - 7.62704E-03 8.76898E-04 5.69835E-03 2.28872E-02 1.07635E-02 2.32757E-01 2.48968E-01 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 1.27537000E-01 4.23780000E-02 9.43740000E-06 5.51630000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 3.24456000E-01 1.63140000E-03 3.14270000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 4.50940000E-01 2.67920000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 4.52565000E-01 5.56640000E-03 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.25250000E-04 2.71401000E-01 1.02550000E-02 1.00210000E-08 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.29680000E-03 2.65802000E-01 1.68090000E-02 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.54580000E-03 2.73080000E-01 - - - - 0.1783583429163 0.3298451031427 0.4815892 0.5623414 0.421721260021 0.6930878 0.6909757999999999 - - - - - - - MOX2 - MOX2 - 2.53E-8 - 0 - true - - - - 0.0090657 0.0042967 0.032881 0.12203 0.18298 0.56846 0.58521 - - - - 1.40004593E-02 9.80563205E-03 8.07435789E-06 2.80075866E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2.26856185E-03 1.58885378E-03 1.30832709E-06 4.53820413E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1.41886199E-02 9.93741584E-03 8.18287404E-06 2.83839974E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 5.54788444E-02 3.88562347E-02 3.19958106E-05 1.10984111E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2.69085702E-02 1.88462058E-02 1.55187355E-05 5.38299559E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 5.45687127E-01 3.82187973E-01 3.14709185E-04 1.09163414E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 6.13307712E-01 4.29548032E-01 3.53707392E-04 1.22690752E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00 - - - - 0.00825446 0.00132565 0.00842156 0.032873 0.0159636 0.323794 0.362803 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 1.30457000E-01 4.17920000E-02 8.51050000E-06 5.13290000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 3.28428000E-01 1.64360000E-03 2.20170000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 4.58371000E-01 2.53310000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 4.63709000E-01 5.47660000E-03 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.76190000E-04 2.82313000E-01 8.72890000E-03 9.00160000E-09 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2.27600000E-03 2.49751000E-01 1.31140000E-02 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.86450000E-03 2.59529000E-01 - - - - 0.1813232156329 0.3343683022017 0.4937851 0.5912156 0.47419809900160004 0.833601 0.8536035 - - - - - - - MOX3 - MOX3 - 2.53E-8 - 0 - true - - - - 9.48620000E-03 4.65560000E-03 3.62400000E-02 1.32720000E-01 2.08400000E-01 6.58700000E-01 6.90170000E-01 - - - - 1.48071013E-02 1.03705874E-02 8.53956516E-06 2.96212546E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 2.78640474E-03 1.95154023E-03 1.60697792E-06 5.57413653E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 1.73304404E-02 1.21378819E-02 9.99482763E-06 3.46691346E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 6.59928975E-02 4.62200600E-02 3.80594850E-05 1.32017225E-08 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 3.25131926E-02 2.27715674E-02 1.87510386E-05 6.50418701E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 6.32002662E-01 4.42641588E-01 3.64489161E-04 1.26430632E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 7.28595687E-01 5.10293344E-01 4.20196380E-04 1.45753838E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00 - - - - 8.67209000E-03 1.62426000E-03 1.02716000E-02 3.90447000E-02 1.92576000E-02 3.74888000E-01 4.30599000E-01 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 1.31504000E-01 4.20460000E-02 8.69720000E-06 5.19380000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 3.30403000E-01 1.64630000E-03 2.60060000E-09 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 4.61792000E-01 2.47490000E-03 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 4.68021000E-01 5.43300000E-03 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.85970000E-04 2.85771000E-01 8.39730000E-03 8.92800000E-09 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2.39160000E-03 2.47614000E-01 1.23220000E-02 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 8.96810000E-03 2.56093000E-01 - - - - 1.83044902E-01 3.36704903E-01 5.00506900E-01 6.06174000E-01 5.02754279E-01 9.21027600E-01 9.55231100E-01 - - - - - - - FC - FC - 2.53E-8 - 0 - true - - - - 5.1132E-04 7.5813E-05 3.1643E-04 1.1675E-03 3.3977E-03 9.1886E-03 2.3244E-02 - - - - 1.323401E-08 1.434500E-08 1.128599E-06 1.276299E-05 3.538502E-07 1.740099E-06 5.063302E-06 - - - - 5.8791E-01 4.1176E-01 3.3906E-04 1.1761E-07 0.0000E+00 0.0000E+00 0.0000E+00 - - - - 4.79002E-09 5.82564E-09 4.63719E-07 5.24406E-06 1.45390E-07 7.14972E-07 2.08041E-06 - - - - - 1.0 1.0 1.0 1.0 1.0 1.0 1.0 - - - - - - 6.61659000E-02 5.90700000E-02 2.83340000E-04 1.46220000E-06 2.06420000E-08 0.00000000E00 0.00000000E00 - 0.00000000E00 2.40377000E-01 5.24350000E-02 2.49900000E-04 1.92390000E-05 2.98750000E-06 4.21400000E-07 - 0.00000000E00 0.00000000E00 1.83425000E-01 9.22880000E-02 6.93650000E-03 1.07900000E-03 2.05430000E-04 - 0.00000000E00 0.00000000E00 0.00000000E00 7.90769000E-02 1.69990000E-01 2.58600000E-02 4.92560000E-03 - 0.00000000E00 0.00000000E00 0.00000000E00 3.73400000E-05 9.97570000E-02 2.06790000E-01 2.44780000E-02 - 0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 9.17420000E-04 3.16774000E-01 2.38760000E-01 - 0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 0.00000000E00 4.97930000E-02 1.09910000E00 - - - - 1.26032048E-01 2.93160367E-01 2.84250824E-01 2.81025244E-01 3.34460185E-01 5.65640735E-01 1.17213908E00 - - - - - - - GT - GT - 2.53E-8 - 0 - false - - - - 5.11320000E-04 7.58010000E-05 3.15720000E-04 1.15820000E-03 3.39750000E-03 9.18780000E-03 2.32420000E-02 - - - - - - 6.61659000E-02 5.90700000E-02 2.83340000E-04 1.46220000E-06 2.06420000E-08 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 2.40377000E-01 5.24350000E-02 2.49900000E-04 1.92390000E-05 2.98750000E-06 4.21400000E-07 - 0.00000000E+00 0.00000000E+00 1.83297000E-01 9.23970000E-02 6.94460000E-03 1.08030000E-03 2.05670000E-04 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 7.88511000E-02 1.70140000E-01 2.58810000E-02 4.92970000E-03 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 3.73330000E-05 9.97372000E-02 2.06790000E-01 2.44780000E-02 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 9.17260000E-04 3.16765000E-01 2.38770000E-01 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 4.97920000E-02 1.09912000E+00 - - - - 1.26032043E-01 2.93160349E-01 2.84240290E-01 2.80960000E-01 3.34440033E-01 5.65640060E-01 1.17215400E+00 - - - - - - LWTR - LWTR - 2.53E-8 - 0 - false - - - - 6.0105E-04 1.5793E-05 3.3716E-04 1.9406E-03 5.7416E-03 1.5001E-02 3.7239E-02 - - - - - - 0.0444777 0.1134000 0.0007235 0.0000037 0.0000001 0.0000000 0.0000000 - 0.0000000 0.2823340 0.1299400 0.0006234 0.0000480 0.0000074 0.0000010 - 0.0000000 0.0000000 0.3452560 0.2245700 0.0169990 0.0026443 0.0005034 - 0.0000000 0.0000000 0.0000000 0.0910284 0.4155100 0.0637320 0.0121390 - 0.0000000 0.0000000 0.0000000 0.0000714 0.1391380 0.5118200 0.0612290 - 0.0000000 0.0000000 0.0000000 0.0000000 0.0022157 0.6999130 0.5373200 - 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.1324400 2.4807000 - - - - 0.15920605 0.41296959299999997 0.59030986 0.5843499999999999 0.7180000000000001 1.2544497000000001 2.650379 - - - - - - - CR - CR - 2.53E-8 - 0 - false - - - - 1.70490000E-03 8.36224000E-03 8.37901000E-02 3.97797000E-01 6.98763000E-01 9.29508000E-01 1.17836000E+00 - - - - - - 1.70563000E-01 4.44012000E-02 9.83670000E-05 1.27786000E-07 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 4.71050000E-01 6.85480000E-04 3.91395000E-10 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 8.01859000E-01 7.20132000E-04 0.00000000E+00 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 5.70752000E-01 1.46015000E-03 0.00000000E+00 0.00000000E+00 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 6.55562000E-05 2.07838000E-01 3.81486000E-03 3.69760000E-09 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 1.02427000E-03 2.02465000E-01 4.75290000E-03 - 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 3.53043000E-03 6.58597000E-01 - - - - 2.16767595E-01 4.80097720E-01 8.86369232E-01 9.70009150E-01 9.10481420E-01 1.13775017E+00 1.84048743E+00 - - - diff --git a/examples/xml/pincell_multigroup/settings.xml b/examples/xml/pincell_multigroup/settings.xml index dfd2fac813..1030762faf 100644 --- a/examples/xml/pincell_multigroup/settings.xml +++ b/examples/xml/pincell_multigroup/settings.xml @@ -28,13 +28,12 @@ - true true true false - ./mg_cross_sections.xml + ./mg_cross_sections.h5 diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 15d80dc913..3188631bcf 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -315,7 +315,6 @@ class XSdata(object): check_value('representation', representation, _REPRESENTATIONS) self._representation = representation - @awr.setter def awr(self, awr): # Check validity of type and that the awr value is > 0 @@ -371,6 +370,31 @@ class XSdata(object): check_type('use_chi', use_chi, bool) self._use_chi = use_chi + def add_temperature(self, temperature): + """This method re-sizes the attributes of this XSdata object so that it + can accomodate an additional temperature. Note that the set_* methods + will still need to be executed. + + Parameters + ---------- + temperature : float + Temperature (in units of Kelvin) of the provided dataset. + + """ + check_type('temperature', temperature, Real) + + temp_store = self.temperatures.tolist().append(temperature) + self.temperatures = temp_store + + self._total.append(None) + self._absorption.append(None) + self._scatter_matrix.append(None) + self._multiplicity_matrix.append(None) + self._fission.append(None) + self._nu_fission.append(None) + self._kappa_fission.append(None) + self._chi.append(None) + def set_total(self, total, temperature=294.): """This method sets the cross section for this XSdata object at the provided temperature. diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py new file mode 100755 index 0000000000..a130040428 --- /dev/null +++ b/scripts/openmc-update-mgxs.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python +"""Update OpenMC's deprecated multi-group cross section XML files to the latest +HDF5-based format. + +Usage information can be obtained by running 'openmc-update-mgxs --help': + +usage: openmc-update-mgxs [-h] in out + +Update mgxs.xml files to the latest format. This will remove 'outside' +attributes/elements from lattices and replace them with 'outer' attributes. For +'cell' elements, any 'surfaces' attributes/elements will be renamed +'region'. Note that this script will not delete the given files; it will append +'.original' to the given files and write new ones. + +positional arguments: + in Input mgxs xml file + out Output mgxs hdf5 file + +optional arguments: + -h, --help show this help message and exit + +""" + +from __future__ import print_function +from shutil import move +import warnings +import xml.etree.ElementTree as ET + +import argparse +import h5py +import numpy as np + +import openmc.mgxs_library + +description = """\ +Update OpenMC's deprecated multi-group cross section XML files to the latest +HDF5-based format.""" + + +def parse_args(): + """Read the input files from the commandline.""" + # Create argument parser + parser = argparse.ArgumentParser(description=description, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-c', '--compression', type=int, + help='input XML file') + parser.add_argument('-i', '--input', type=argparse.FileType('r'), + help='input XML file') + parser.add_argument('-o', '--output', nargs='?', default='', + help='output file, in HDF5 format') + args = vars(parser.parse_args()) + + if args['output'] == '': + fname = args['input'].name.split('.') + fname[-1] = '.h5' + args['output'] = ''.join(fname) + + # Parse and return commandline arguments. + return args + + +if __name__ == '__main__': + args = parse_args() + + # Parse the XML data. + tree = ET.parse(args['input']) + root = tree.getroot() + + if root.tag != 'library': + raise ValueError("Invalid XML file type") + + # Get old metadata + temp = tree.find('group_structure').text + temp = np.array(temp.split()) + group_structure = temp.astype(np.float) + energy_groups = openmc.mgxs.EnergyGroups(group_structure) + temp = tree.find('inverse_velocities') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + inverse_velocities = temp.astype(np.float) + else: + inverse_velocities = None + + xsd = [] + names = [] + + # Now move on to the cross section data itself + for xsdata_elem in root.iter('xsdata'): + name = xsdata_elem.find('name').text + + temperature = xsdata_elem.find('kT') + if temperature is not None: + temperature = \ + float(temperature.text) / openmc.data.K_BOLTZMANN + else: + temperature = 294. + temperatures = [temperature] + + awr = xsdata_elem.find('awr') + if awr is not None: + awr = float(awr.text) + + representation = xsdata_elem.find('representation') + if representation is not None: + representation = representation.text + else: + representation = 'isotropic' + if representation == 'angle': + n_azi = int(xsdata_elem.find('num_azimuthal').text) + n_pol = int(xsdata_elem.find('num_polar').text) + + scatter_type = xsdata_elem.find('scatt_type') + if scatter_type is not None: + scatter_type = scatter_type.text + else: + scatter_type = 'legendre' + + order = int(xsdata_elem.find('order').text) + + tab_leg = xsdata_elem.find('tabular_legendre') + if tab_leg is not None: + warnings.Warning('The tabular_legendre option has moved to the ' + 'settings.xml file and must be added manually') + + # Either add the data to a previously existing xsdata (if it is + # for the same 'name' but a different temperature), or create a + # new one. + + try: + # It is in our list, so store that entry + i = names.index(name) + except: + # It is not in our list, so add it + i = -1 + xsd.append(openmc.XSdata(name, energy_groups, + temperatures=temperatures, + representation=representation)) + if awr is not None: + xsd[-1].awr = awr + if representation == 'angle': + xsd[-1].num_azimuthal = n_azi + xsd[-1].num_polar = n_pol + xsd[-1].scatter_type = scatter_type + xsd[-1].order = order + names.append(name) + + if scatter_type == 'legendre': + order_dim = order + 1 + else: + order_dim = order + + if i != -1: + xsd[i].add_temperature(temperature) + + temp = xsdata_elem.find('total') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + total = temp.astype(np.float) + total = np.reshape(total, xsd[i].vector_shape) + xsd[i].set_total(total, temperature) + + temp = xsdata_elem.find('absorption').text + temp = np.array(temp.split()) + absorption = temp.astype(np.float) + absorption = np.reshape(absorption, xsd[i].vector_shape) + xsd[i].set_absorption(absorption, temperature) + + temp = xsdata_elem.find('scatter').text + temp = np.array(temp.split()) + temp = temp.astype(np.float) + scatter = np.reshape(temp, xsd[i].pn_matrix_shape) + xsd[i].set_scatter_matrix(scatter, temperature) + + temp = xsdata_elem.find('multiplicity') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + temp = temp.astype(np.float) + multiplicity = np.reshape(temp, xsd[i].matrix_shape) + xsd[i].set_multiplicity_matrix(multiplicity, temperature) + + temp = xsdata_elem.find('fission') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + fission = temp.astype(np.float) + fission = np.reshape(fission, xsd[i].vector_shape) + xsd[i].set_fission(fission, temperature) + + temp = xsdata_elem.find('kappa_fission') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + kappa_fission = temp.astype(np.float) + kappa_fission = np.reshape(kappa_fission, xsd[i].vector_shape) + xsd[i].set_kappa_fission(kappa_fission, temperature) + + temp = xsdata_elem.find('chi') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + chi = temp.astype(np.float) + chi = np.reshape(chi, xsd[i].vector_shape) + xsd[i].set_chi(chi, temperature) + else: + chi = None + + temp = xsdata_elem.find('nu_fission') + if temp is not None: + temp = temp.text + temp = np.array(temp.split()) + temp = temp.astype(np.float) + if chi is not None: + nu_fission = np.reshape(temp, xsd[i].vector_shape) + else: + nu_fission = np.reshape(temp, xsd[i].matrix_shape) + xsd[i].set_nu_fission(nu_fission, temperature) + + # Build library as we go, but first we have enough to initialize it + lib = openmc.MGXSLibrary(energy_groups) + if inverse_velocities is not None: + lib.inverse_velocities = inverse_velocities + + lib.add_xsdatas(xsd) + + print(args['output']) + lib.export_to_hdf5(args['output'], compression=args['compression']) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index f17f2781ed..d9039a3ad7 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -1,6 +1,6 @@ module mgxs_data -use constants + use constants use algorithm, only: find use error, only: fatal_error use global @@ -184,10 +184,14 @@ contains type is (MgxsAngle) allocate(MgxsAngle :: macro_xs(i_mat) % obj) end select - call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & - energy_groups, max_order, & - temperature_tolerance, & - temperature_method) + ! Do not read materials which we do not actually use in the problem to + ! save space + if (allocated(kTs(i_mat) % data)) then + call macro_xs(i_mat) % obj % combine(kTs(i_mat), mat, nuclides_MG, & + energy_groups, max_order, & + temperature_tolerance, & + temperature_method) + end if end do end subroutine create_macro_xs diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index cefd8725d6..cef4685172 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -923,7 +923,7 @@ module mgxs_header if (mat % name == "") then this % name = trim(to_str(mat % id)) else - this % name = mat % name + this % name = trim(mat % name) end if this % fissionable = mat % fissionable @@ -992,15 +992,16 @@ module mgxs_header do i = 1, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) type is (MgxsIso) - if (size(nuc % xs(1) % scatter % dist(1) % data, dim=1) > & - mat_max_order) & + if (size(nuc % xs(1) % scatter % dist(1) % data, & + dim=1) > mat_max_order) & mat_max_order = size(nuc % xs(1) % scatter % dist(1) % data, & dim=1) type is (MgxsAngle) - if (size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) > & - mat_max_order) & - mat_max_order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & - dim=1) + if (size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & + dim=1) > mat_max_order) & + mat_max_order = & + size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, & + dim=1) end select end do From 1305e99ce39f49471e1c37e52242bd7a00c5dcc4 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 5 Sep 2016 19:48:30 -0400 Subject: [PATCH 08/82] Updated test MGXS library an fixed bug in setting num_azimuthal and num_polar in mgxs_library. --- openmc/mgxs_library.py | 4 +- scripts/openmc-update-mgxs.py | 37 +- tests/1d_mgxs.xml | 9859 --------------------------------- 3 files changed, 20 insertions(+), 9880 deletions(-) delete mode 100644 tests/1d_mgxs.xml diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 3188631bcf..ad60a57798 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -355,13 +355,13 @@ class XSdata(object): @num_polar.setter def num_polar(self, num_polar): # Make sure we have positive ints - check_value('num_polar', num_polar, Integral) + check_type('num_polar', num_polar, Integral) check_greater_than('num_polar', num_polar, 0) self._num_polar = num_polar @num_azimuthal.setter def num_azimuthal(self, num_azimuthal): - check_value('num_azimuthal', num_azimuthal, Integral) + check_type('num_azimuthal', num_azimuthal, Integral) check_greater_than('num_azimuthal', num_azimuthal, 0) self._num_azimuthal = num_azimuthal diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py index a130040428..bc0c201c3e 100755 --- a/scripts/openmc-update-mgxs.py +++ b/scripts/openmc-update-mgxs.py @@ -70,13 +70,13 @@ if __name__ == '__main__': raise ValueError("Invalid XML file type") # Get old metadata - temp = tree.find('group_structure').text + temp = tree.find('group_structure').text.strip() temp = np.array(temp.split()) group_structure = temp.astype(np.float) energy_groups = openmc.mgxs.EnergyGroups(group_structure) temp = tree.find('inverse_velocities') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) inverse_velocities = temp.astype(np.float) else: @@ -87,36 +87,36 @@ if __name__ == '__main__': # Now move on to the cross section data itself for xsdata_elem in root.iter('xsdata'): - name = xsdata_elem.find('name').text + name = xsdata_elem.find('name').text.strip() temperature = xsdata_elem.find('kT') if temperature is not None: temperature = \ - float(temperature.text) / openmc.data.K_BOLTZMANN + float(temperature.text.strip()) / openmc.data.K_BOLTZMANN else: temperature = 294. temperatures = [temperature] awr = xsdata_elem.find('awr') if awr is not None: - awr = float(awr.text) + awr = float(awr.text.strip()) representation = xsdata_elem.find('representation') if representation is not None: - representation = representation.text + representation = representation.text.strip() else: representation = 'isotropic' if representation == 'angle': - n_azi = int(xsdata_elem.find('num_azimuthal').text) - n_pol = int(xsdata_elem.find('num_polar').text) + n_azi = int(xsdata_elem.find('num_azimuthal').text.strip()) + n_pol = int(xsdata_elem.find('num_polar').text.strip()) scatter_type = xsdata_elem.find('scatt_type') if scatter_type is not None: - scatter_type = scatter_type.text + scatter_type = scatter_type.text.strip() else: scatter_type = 'legendre' - order = int(xsdata_elem.find('order').text) + order = int(xsdata_elem.find('order').text.strip()) tab_leg = xsdata_elem.find('tabular_legendre') if tab_leg is not None: @@ -155,19 +155,19 @@ if __name__ == '__main__': temp = xsdata_elem.find('total') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) total = temp.astype(np.float) total = np.reshape(total, xsd[i].vector_shape) xsd[i].set_total(total, temperature) - temp = xsdata_elem.find('absorption').text + temp = xsdata_elem.find('absorption').text.strip() temp = np.array(temp.split()) absorption = temp.astype(np.float) absorption = np.reshape(absorption, xsd[i].vector_shape) xsd[i].set_absorption(absorption, temperature) - temp = xsdata_elem.find('scatter').text + temp = xsdata_elem.find('scatter').text.strip() temp = np.array(temp.split()) temp = temp.astype(np.float) scatter = np.reshape(temp, xsd[i].pn_matrix_shape) @@ -175,7 +175,7 @@ if __name__ == '__main__': temp = xsdata_elem.find('multiplicity') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) temp = temp.astype(np.float) multiplicity = np.reshape(temp, xsd[i].matrix_shape) @@ -183,7 +183,7 @@ if __name__ == '__main__': temp = xsdata_elem.find('fission') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) fission = temp.astype(np.float) fission = np.reshape(fission, xsd[i].vector_shape) @@ -191,7 +191,7 @@ if __name__ == '__main__': temp = xsdata_elem.find('kappa_fission') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) kappa_fission = temp.astype(np.float) kappa_fission = np.reshape(kappa_fission, xsd[i].vector_shape) @@ -199,7 +199,7 @@ if __name__ == '__main__': temp = xsdata_elem.find('chi') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) chi = temp.astype(np.float) chi = np.reshape(chi, xsd[i].vector_shape) @@ -209,7 +209,7 @@ if __name__ == '__main__': temp = xsdata_elem.find('nu_fission') if temp is not None: - temp = temp.text + temp = temp.text.strip() temp = np.array(temp.split()) temp = temp.astype(np.float) if chi is not None: @@ -225,5 +225,4 @@ if __name__ == '__main__': lib.add_xsdatas(xsd) - print(args['output']) lib.export_to_hdf5(args['output'], compression=args['compression']) diff --git a/tests/1d_mgxs.xml b/tests/1d_mgxs.xml deleted file mode 100644 index 8704b49ad4..0000000000 --- a/tests/1d_mgxs.xml +++ /dev/null @@ -1,9859 +0,0 @@ - - - 1 - 0.0000000E+00 2.0000000E+01 - - - uo2_iso - uo2_iso - 2.5300000E-08 - 5 - true - isotropic - - 4.1022364E-01 - - - 3.4687432E-02 - - - 4.9631431E-02 - - - 1.0000000E+00 - - - 2.0019027E-02 - - - 3.7564339E-01 - - 4.4983802E-02 - - 2.2781624E-02 - - 1.1639469E-02 - - 7.1975833E-03 - - 3.5887673E-03 - - - 1.0002764E+00 - - - - - clad_iso - clad_iso - 2.5300000E-08 - 5 - false - isotropic - - 3.0736836E-01 - - - 1.7027907E-03 - - - 3.0566993E-01 - - 4.1625057E-02 - - 2.2287832E-02 - - 3.9580806E-03 - - 3.3420849E-03 - - 1.3963828E-03 - - - 1.0000372E+00 - - - - - lwtr_iso - lwtr_iso - 2.5300000E-08 - 5 - false - isotropic - - 9.6904862E-01 - - - 1.0230968E-02 - - - 9.5881780E-01 - - 3.9202760E-01 - - 1.2865356E-01 - - 9.5231115E-03 - - -1.9647208E-02 - - 5.9291968E-04 - - - 1.0000000E+00 - - - - - uo2_iso_mu - uo2_iso_mu - 2.5300000E-08 - 32 - true - isotropic - histogram - - 4.1022364E-01 - - - 3.4687432E-02 - - - 4.9631431E-02 - - - 1.0000000E+00 - - - 2.0019027E-02 - - - 9.7621928E-03 - - 9.6669975E-03 - - 9.6217012E-03 - - 9.6029285E-03 - - 9.6155223E-03 - - 9.6417022E-03 - - 9.6845888E-03 - - 9.7355785E-03 - - 9.7971852E-03 - - 9.8708684E-03 - - 9.9451996E-03 - - 1.0026273E-02 - - 1.0121536E-02 - - 1.0227606E-02 - - 1.0340467E-02 - - 1.0461281E-02 - - 1.0600371E-02 - - 1.0742182E-02 - - 1.0892295E-02 - - 1.1062409E-02 - - 1.1236639E-02 - - 1.1440302E-02 - - 1.1662283E-02 - - 1.1931512E-02 - - 1.2259589E-02 - - 1.2696194E-02 - - 1.3272953E-02 - - 1.4078939E-02 - - 1.5238289E-02 - - 1.6956791E-02 - - 1.9602217E-02 - - 2.3848802E-02 - - - 1.0002764E+00 - - - - - clad_iso_mu - clad_iso_mu - 2.5300000E-08 - 32 - false - isotropic - histogram - - 3.0736836E-01 - - - 1.7027907E-03 - - - 8.7275040E-03 - - 8.3252599E-03 - - 8.0120655E-03 - - 7.7711039E-03 - - 7.5947251E-03 - - 7.4705350E-03 - - 7.3804037E-03 - - 7.3241515E-03 - - 7.3010244E-03 - - 7.3107188E-03 - - 7.3487081E-03 - - 7.4144814E-03 - - 7.5104992E-03 - - 7.6438156E-03 - - 7.7974114E-03 - - 7.9812213E-03 - - 8.1816102E-03 - - 8.4284406E-03 - - 8.6892059E-03 - - 8.9675370E-03 - - 9.2626673E-03 - - 9.6121293E-03 - - 9.9669464E-03 - - 1.0354054E-02 - - 1.0794903E-02 - - 1.1296566E-02 - - 1.1883978E-02 - - 1.2592532E-02 - - 1.3494682E-02 - - 1.4666635E-02 - - 1.6229823E-02 - - 1.8334594E-02 - - - 1.0000372E+00 - - - - - lwtr_iso_mu - lwtr_iso_mu - 2.5300000E-08 - 32 - false - isotropic - histogram - - 9.6904862E-01 - - - 1.0230968E-02 - - - 5.8755233E-03 - - 1.0934725E-02 - - 1.1142414E-02 - - 1.0437139E-02 - - 1.0756915E-02 - - 1.0623054E-02 - - 1.1295335E-02 - - 1.1326212E-02 - - 1.1795885E-02 - - 1.2179916E-02 - - 1.2528003E-02 - - 1.3121696E-02 - - 1.3563685E-02 - - 1.4242846E-02 - - 1.4567732E-02 - - 1.5913317E-02 - - 1.6851680E-02 - - 2.0792196E-02 - - 2.4129531E-02 - - 2.8258248E-02 - - 3.2040957E-02 - - 3.6266761E-02 - - 4.0455247E-02 - - 4.4731350E-02 - - 4.8820583E-02 - - 5.3746086E-02 - - 5.7743648E-02 - - 6.3513540E-02 - - 6.7353451E-02 - - 7.2430683E-02 - - 8.0723820E-02 - - 8.0655621E-02 - - - 1.0000000E+00 - - - - - uo2_ang - uo2_ang - 2.5300000E-08 - 5 - true - 32 - 1 - angle - - 4.0734790E-01 - - 4.0709470E-01 - - 4.0665280E-01 - - 4.0605122E-01 - - 4.0509226E-01 - - 4.0399893E-01 - - 4.0264927E-01 - - 4.0112684E-01 - - 3.9937450E-01 - - 3.9743081E-01 - - 3.9533879E-01 - - 3.9307550E-01 - - 3.9084961E-01 - - 3.8878017E-01 - - 3.8751931E-01 - - 3.8693825E-01 - - 3.9039929E-01 - - 4.0037023E-01 - - 4.1057791E-01 - - 4.1924835E-01 - - 4.2629128E-01 - - 4.3202621E-01 - - 4.3673213E-01 - - 4.4062993E-01 - - 4.4385222E-01 - - 4.4647166E-01 - - 4.4861335E-01 - - 4.5026817E-01 - - 4.5165329E-01 - - 4.5255720E-01 - - 4.5310208E-01 - - 4.5337269E-01 - - - 3.1599020E-02 - - 3.1371085E-02 - - 3.1023091E-02 - - 3.0539250E-02 - - 2.9839460E-02 - - 2.9013479E-02 - - 2.8058288E-02 - - 2.7047229E-02 - - 2.5977776E-02 - - 2.4952391E-02 - - 2.4009896E-02 - - 2.3244570E-02 - - 2.2725200E-02 - - 2.2489873E-02 - - 2.2624168E-02 - - 2.3059735E-02 - - 2.4782557E-02 - - 2.8553081E-02 - - 3.3194318E-02 - - 3.8038660E-02 - - 4.2666012E-02 - - 4.6923885E-02 - - 5.0708283E-02 - - 5.3996846E-02 - - 5.6845491E-02 - - 5.9213445E-02 - - 6.1182604E-02 - - 6.2742563E-02 - - 6.3985293E-02 - - 6.4852148E-02 - - 6.5364227E-02 - - 6.5703785E-02 - - - 4.5146530E-02 - - 4.4766687E-02 - - 4.4155441E-02 - - 4.3323960E-02 - - 4.2141314E-02 - - 4.0739637E-02 - - 3.9143652E-02 - - 3.7465300E-02 - - 3.5735871E-02 - - 3.4113931E-02 - - 3.2678644E-02 - - 3.1591060E-02 - - 3.0966537E-02 - - 3.0821062E-02 - - 3.1238242E-02 - - 3.2075654E-02 - - 3.4603728E-02 - - 3.9898114E-02 - - 4.6725370E-02 - - 5.4142159E-02 - - 6.1436273E-02 - - 6.8238302E-02 - - 7.4365771E-02 - - 7.9727018E-02 - - 8.4398863E-02 - - 8.8315890E-02 - - 9.1574736E-02 - - 9.4183896E-02 - - 9.6266615E-02 - - 9.7706019E-02 - - 9.8564505E-02 - - 9.9171965E-02 - - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - - 1.8183034E-02 - - 1.8028751E-02 - - 1.7777081E-02 - - 1.7434939E-02 - - 1.6947918E-02 - - 1.6371445E-02 - - 1.5714505E-02 - - 1.5023310E-02 - - 1.4310527E-02 - - 1.3640363E-02 - - 1.3045308E-02 - - 1.2590537E-02 - - 1.2323486E-02 - - 1.2250235E-02 - - 1.2408325E-02 - - 1.2741816E-02 - - 1.3791905E-02 - - 1.6011218E-02 - - 1.8846275E-02 - - 2.1907807E-02 - - 2.4909120E-02 - - 2.7704245E-02 - - 3.0220623E-02 - - 3.2422114E-02 - - 3.4339614E-02 - - 3.5947934E-02 - - 3.7286018E-02 - - 3.8357139E-02 - - 3.9212858E-02 - - 3.9804080E-02 - - 4.0156625E-02 - - 4.0404918E-02 - - - 3.7585902E-01 - - 4.4872720E-02 - - 2.2814276E-02 - - 1.1556342E-02 - - 7.2018303E-03 - - 3.6175403E-03 - - - - 3.7582315E-01 - - 4.4995749E-02 - - 2.2725116E-02 - - 1.1466478E-02 - - 7.0875483E-03 - - 3.5308164E-03 - - - - 3.7572011E-01 - - 4.4992452E-02 - - 2.2759820E-02 - - 1.1516099E-02 - - 7.0323440E-03 - - 3.5020003E-03 - - - - 3.7562995E-01 - - 4.5132914E-02 - - 2.2777514E-02 - - 1.1548988E-02 - - 7.0831467E-03 - - 3.5299129E-03 - - - - 3.7536612E-01 - - 4.5293164E-02 - - 2.2890080E-02 - - 1.1675089E-02 - - 7.1438522E-03 - - 3.5771809E-03 - - - - 3.7510372E-01 - - 4.5594244E-02 - - 2.2986083E-02 - - 1.1616892E-02 - - 7.1593645E-03 - - 3.5827527E-03 - - - - 3.7471139E-01 - - 4.5893399E-02 - - 2.3129097E-02 - - 1.1710573E-02 - - 7.2294990E-03 - - 3.6035030E-03 - - - - 3.7417853E-01 - - 4.6212271E-02 - - 2.3407493E-02 - - 1.1803607E-02 - - 7.2768873E-03 - - 3.6185275E-03 - - - - 3.7350485E-01 - - 4.6653124E-02 - - 2.3603271E-02 - - 1.1928427E-02 - - 7.3368483E-03 - - 3.6311780E-03 - - - - 3.7257204E-01 - - 4.7127424E-02 - - 2.3927026E-02 - - 1.2138279E-02 - - 7.4376541E-03 - - 3.6855451E-03 - - - - 3.7144563E-01 - - 4.7675499E-02 - - 2.4252831E-02 - - 1.2320100E-02 - - 7.5749097E-03 - - 3.7669728E-03 - - - - 3.6996977E-01 - - 4.8300830E-02 - - 2.4647138E-02 - - 1.2560662E-02 - - 7.7886594E-03 - - 3.8654464E-03 - - - - 3.6821602E-01 - - 4.8824396E-02 - - 2.5017750E-02 - - 1.2840163E-02 - - 7.9274823E-03 - - 3.9779025E-03 - - - - 3.6638016E-01 - - 4.9306135E-02 - - 2.5474307E-02 - - 1.3192593E-02 - - 8.2112330E-03 - - 4.1160831E-03 - - - - 3.6503713E-01 - - 4.9560796E-02 - - 2.5756337E-02 - - 1.3455138E-02 - - 8.3858370E-03 - - 4.2114689E-03 - - - - 3.6400368E-01 - - 4.9633132E-02 - - 2.5987536E-02 - - 1.3659891E-02 - - 8.5714354E-03 - - 4.3181256E-03 - - - - 3.6576117E-01 - - 4.8863049E-02 - - 2.5525363E-02 - - 1.3370670E-02 - - 8.3567729E-03 - - 4.1905625E-03 - - - - 3.7192172E-01 - - 4.6844936E-02 - - 2.3959446E-02 - - 1.2270393E-02 - - 7.5751281E-03 - - 3.7309644E-03 - - - - 3.7748124E-01 - - 4.4748629E-02 - - 2.2514789E-02 - - 1.1348962E-02 - - 6.9297472E-03 - - 3.4104693E-03 - - - - 3.8128097E-01 - - 4.3075850E-02 - - 2.1398961E-02 - - 1.0675116E-02 - - 6.5306660E-03 - - 3.2210938E-03 - - - - 3.8373406E-01 - - 4.1672472E-02 - - 2.0547117E-02 - - 1.0330913E-02 - - 6.3048028E-03 - - 3.1386749E-03 - - - - 3.8520439E-01 - - 4.0681902E-02 - - 2.0057126E-02 - - 1.0056063E-02 - - 6.1829817E-03 - - 3.0802737E-03 - - - - 3.8614505E-01 - - 3.9879282E-02 - - 1.9626439E-02 - - 9.9375963E-03 - - 6.1229946E-03 - - 3.0426688E-03 - - - - 3.8675390E-01 - - 3.9278504E-02 - - 1.9339777E-02 - - 9.8184985E-03 - - 6.0956157E-03 - - 3.0580002E-03 - - - - 3.8705360E-01 - - 3.8883125E-02 - - 1.9159064E-02 - - 9.7301477E-03 - - 6.0595588E-03 - - 3.0225068E-03 - - - - 3.8731880E-01 - - 3.8576519E-02 - - 1.9045072E-02 - - 9.7127863E-03 - - 6.0463869E-03 - - 3.0519472E-03 - - - - 3.8756725E-01 - - 3.8382695E-02 - - 1.8916082E-02 - - 9.6925622E-03 - - 6.0590015E-03 - - 2.9913798E-03 - - - - 3.8761982E-01 - - 3.8249486E-02 - - 1.8841512E-02 - - 9.6699646E-03 - - 6.0488356E-03 - - 3.0212480E-03 - - - - 3.8779017E-01 - - 3.8052198E-02 - - 1.8815974E-02 - - 9.5833623E-03 - - 5.9965640E-03 - - 2.9751261E-03 - - - - 3.8780028E-01 - - 3.7931450E-02 - - 1.8735581E-02 - - 9.6072395E-03 - - 5.9416328E-03 - - 3.0080955E-03 - - - - 3.8782277E-01 - - 3.7963999E-02 - - 1.8776116E-02 - - 9.6491264E-03 - - 5.9087373E-03 - - 3.0066367E-03 - - - - 3.8767898E-01 - - 3.7876954E-02 - - 1.8837344E-02 - - 9.7088929E-03 - - 5.9136976E-03 - - 3.0171235E-03 - - - 1.0002763E+00 - - - 1.0002760E+00 - - - 1.0002658E+00 - - - 1.0002710E+00 - - - 1.0002776E+00 - - - 1.0002767E+00 - - - 1.0002833E+00 - - - 1.0002791E+00 - - - 1.0002788E+00 - - - 1.0002858E+00 - - - 1.0002884E+00 - - - 1.0002916E+00 - - - 1.0003039E+00 - - - 1.0003181E+00 - - - 1.0003365E+00 - - - 1.0003544E+00 - - - 1.0003372E+00 - - - 1.0002764E+00 - - - 1.0002508E+00 - - - 1.0002343E+00 - - - 1.0002360E+00 - - - 1.0002375E+00 - - - 1.0002331E+00 - - - 1.0002344E+00 - - - 1.0002385E+00 - - - 1.0002316E+00 - - - 1.0002360E+00 - - - 1.0002360E+00 - - - 1.0002354E+00 - - - 1.0002349E+00 - - - 1.0002325E+00 - - - 1.0002268E+00 - - - - - clad_ang - clad_ang - 2.5300000E-08 - 5 - false - 32 - 1 - angle - - 3.1005638E-01 - - 3.0999067E-01 - - 3.0994879E-01 - - 3.0987779E-01 - - 3.0961631E-01 - - 3.0948272E-01 - - 3.0913340E-01 - - 3.0868239E-01 - - 3.0799925E-01 - - 3.0712597E-01 - - 3.0590948E-01 - - 3.0432728E-01 - - 3.0235012E-01 - - 2.9996873E-01 - - 2.9743091E-01 - - 2.9739624E-01 - - 3.0835788E-01 - - 3.1305337E-01 - - 3.1379599E-01 - - 3.1314506E-01 - - 3.1216249E-01 - - 3.1129786E-01 - - 3.1059203E-01 - - 3.1009561E-01 - - 3.0977837E-01 - - 3.0951041E-01 - - 3.0930940E-01 - - 3.0929712E-01 - - 3.0925741E-01 - - 3.0917641E-01 - - 3.0919741E-01 - - 3.0912502E-01 - - - 1.3490691E-03 - - 1.3463259E-03 - - 1.3498512E-03 - - 1.3366347E-03 - - 1.3288899E-03 - - 1.3176269E-03 - - 1.3059971E-03 - - 1.2891508E-03 - - 1.2713136E-03 - - 1.2555332E-03 - - 1.2394055E-03 - - 1.2170158E-03 - - 1.1969201E-03 - - 1.1849620E-03 - - 1.1899173E-03 - - 1.2761137E-03 - - 1.6244505E-03 - - 1.9090551E-03 - - 2.0837409E-03 - - 2.1976011E-03 - - 2.2746911E-03 - - 2.3308251E-03 - - 2.3700744E-03 - - 2.3981231E-03 - - 2.4248079E-03 - - 2.4441792E-03 - - 2.4510541E-03 - - 2.4640212E-03 - - 2.4741885E-03 - - 2.4697219E-03 - - 2.4721421E-03 - - 2.4729172E-03 - - - 3.0860746E-01 - - 5.0621457E-02 - - 2.7347709E-02 - - 4.7204795E-03 - - 4.0838896E-03 - - 1.6974585E-03 - - - - 3.0865194E-01 - - 5.0806752E-02 - - 2.6916586E-02 - - 4.8439138E-03 - - 4.1728626E-03 - - 1.7130886E-03 - - - - 3.0861586E-01 - - 5.0757624E-02 - - 2.7196188E-02 - - 4.8679553E-03 - - 4.0626181E-03 - - 1.7815988E-03 - - - - 3.0850283E-01 - - 5.0925397E-02 - - 2.7204505E-02 - - 4.8109149E-03 - - 4.1177685E-03 - - 1.7500469E-03 - - - - 3.0831737E-01 - - 5.1138142E-02 - - 2.7308021E-02 - - 4.8683307E-03 - - 4.0620680E-03 - - 1.6728150E-03 - - - - 3.0815133E-01 - - 5.1220538E-02 - - 2.7286345E-02 - - 4.8715905E-03 - - 4.0963982E-03 - - 1.6783881E-03 - - - - 3.0777979E-01 - - 5.1536936E-02 - - 2.7522750E-02 - - 4.9751865E-03 - - 4.1461347E-03 - - 1.7481718E-03 - - - - 3.0740186E-01 - - 5.1745014E-02 - - 2.7548398E-02 - - 4.9705992E-03 - - 4.2128374E-03 - - 1.7852471E-03 - - - - 3.0674467E-01 - - 5.2102012E-02 - - 2.7721735E-02 - - 4.9326171E-03 - - 4.2065723E-03 - - 1.7520577E-03 - - - - 3.0588587E-01 - - 5.2410298E-02 - - 2.7935183E-02 - - 5.1068594E-03 - - 4.2771962E-03 - - 1.7875734E-03 - - - - 3.0465659E-01 - - 5.2543078E-02 - - 2.7962434E-02 - - 5.0839680E-03 - - 4.3050048E-03 - - 1.8499733E-03 - - - - 3.0312229E-01 - - 5.2483292E-02 - - 2.8137041E-02 - - 5.2734764E-03 - - 4.4574974E-03 - - 1.8578935E-03 - - - - 3.0117092E-01 - - 5.2332000E-02 - - 2.8003257E-02 - - 5.2432554E-03 - - 4.5485878E-03 - - 1.8980534E-03 - - - - 2.9880209E-01 - - 5.1679340E-02 - - 2.7750518E-02 - - 5.3056401E-03 - - 4.5878997E-03 - - 1.9401945E-03 - - - - 2.9627667E-01 - - 5.0169523E-02 - - 2.7059202E-02 - - 5.2026216E-03 - - 4.5921641E-03 - - 1.8856744E-03 - - - - 2.9609986E-01 - - 4.6032461E-02 - - 2.4630572E-02 - - 4.5841577E-03 - - 3.9297754E-03 - - 1.6420383E-03 - - - - 3.0675667E-01 - - 3.7400062E-02 - - 1.9426565E-02 - - 2.7294131E-03 - - 2.0654845E-03 - - 6.7157182E-04 - - - - 3.1112942E-01 - - 3.2514340E-02 - - 1.7042298E-02 - - 2.2975512E-03 - - 1.7171252E-03 - - 6.1586296E-04 - - - - 3.1168284E-01 - - 2.9994361E-02 - - 1.5982971E-02 - - 2.2082409E-03 - - 1.7621544E-03 - - 6.7848731E-04 - - - - 3.1094402E-01 - - 2.9043011E-02 - - 1.5559822E-02 - - 2.3867453E-03 - - 1.8805422E-03 - - 8.0257257E-04 - - - - 3.0988917E-01 - - 2.8642621E-02 - - 1.5527633E-02 - - 2.5363175E-03 - - 2.0667848E-03 - - 8.9512793E-04 - - - - 3.0900783E-01 - - 2.8683967E-02 - - 1.5531635E-02 - - 2.6907133E-03 - - 2.2374989E-03 - - 9.9838820E-04 - - - - 3.0823110E-01 - - 2.8772506E-02 - - 1.5617343E-02 - - 2.7855260E-03 - - 2.3324886E-03 - - 1.0334317E-03 - - - - 3.0768619E-01 - - 2.9118421E-02 - - 1.5860568E-02 - - 2.8469804E-03 - - 2.4600144E-03 - - 1.0754851E-03 - - - - 3.0729355E-01 - - 2.9429106E-02 - - 1.6138063E-02 - - 2.9901807E-03 - - 2.5154903E-03 - - 1.1139796E-03 - - - - 3.0707342E-01 - - 2.9773340E-02 - - 1.6110013E-02 - - 2.9606704E-03 - - 2.6433692E-03 - - 1.1310602E-03 - - - - 3.0685025E-01 - - 3.0055483E-02 - - 1.6246774E-02 - - 3.1035410E-03 - - 2.6316501E-03 - - 1.1158252E-03 - - - - 3.0681469E-01 - - 3.0238686E-02 - - 1.6524723E-02 - - 3.0402635E-03 - - 2.6108287E-03 - - 1.1691486E-03 - - - - 3.0690606E-01 - - 3.0618190E-02 - - 1.6493402E-02 - - 3.0268029E-03 - - 2.5956288E-03 - - 1.0751657E-03 - - - - 3.0676357E-01 - - 3.0613175E-02 - - 1.6679358E-02 - - 2.8764512E-03 - - 2.5398735E-03 - - 1.0482210E-03 - - - - 3.0676223E-01 - - 3.0798581E-02 - - 1.6764686E-02 - - 3.1471928E-03 - - 2.7160881E-03 - - 1.2265875E-03 - - - - 3.0687178E-01 - - 3.0702117E-02 - - 1.6628813E-02 - - 2.8692462E-03 - - 2.4997850E-03 - - 9.3974161E-04 - - - 1.0000416E+00 - - - 1.0000513E+00 - - - 1.0000397E+00 - - - 1.0000409E+00 - - - 1.0000455E+00 - - - 1.0000417E+00 - - - 1.0000452E+00 - - - 1.0000431E+00 - - - 1.0000455E+00 - - - 1.0000451E+00 - - - 1.0000445E+00 - - - 1.0000482E+00 - - - 1.0000507E+00 - - - 1.0000542E+00 - - - 1.0000545E+00 - - - 1.0000461E+00 - - - 1.0000114E+00 - - - 1.0000112E+00 - - - 1.0000195E+00 - - - 1.0000216E+00 - - - 1.0000279E+00 - - - 1.0000307E+00 - - - 1.0000302E+00 - - - 1.0000313E+00 - - - 1.0000334E+00 - - - 1.0000309E+00 - - - 1.0000325E+00 - - - 1.0000318E+00 - - - 1.0000346E+00 - - - 1.0000335E+00 - - - 1.0000285E+00 - - - 1.0000358E+00 - - - - - lwtr_ang - lwtr_ang - 2.5300000E-08 - 5 - false - 32 - 1 - angle - - 8.3129229E-01 - - 8.3203829E-01 - - 8.3332424E-01 - - 8.3539719E-01 - - 8.3799288E-01 - - 8.4156597E-01 - - 8.4594074E-01 - - 8.5122773E-01 - - 8.5788274E-01 - - 8.6633387E-01 - - 8.7719846E-01 - - 8.9195077E-01 - - 9.1326621E-01 - - 9.4469159E-01 - - 9.9368716E-01 - - 1.0616854E+00 - - 1.0982938E+00 - - 1.0997200E+00 - - 1.0855410E+00 - - 1.0676695E+00 - - 1.0508172E+00 - - 1.0369337E+00 - - 1.0255762E+00 - - 1.0162841E+00 - - 1.0086633E+00 - - 1.0025783E+00 - - 9.9737297E-01 - - 9.9326768E-01 - - 9.9030852E-01 - - 9.8792719E-01 - - 9.8610453E-01 - - 9.8540665E-01 - - - 7.7368065E-03 - - 7.7519393E-03 - - 7.7819449E-03 - - 7.8285240E-03 - - 7.8881877E-03 - - 7.9652685E-03 - - 8.0588251E-03 - - 8.1724303E-03 - - 8.3079937E-03 - - 8.4749946E-03 - - 8.6811506E-03 - - 8.9456784E-03 - - 9.3049336E-03 - - 9.8025199E-03 - - 1.0529992E-02 - - 1.1498571E-02 - - 1.2065971E-02 - - 1.2168395E-02 - - 1.2053690E-02 - - 1.1870414E-02 - - 1.1678759E-02 - - 1.1516371E-02 - - 1.1377145E-02 - - 1.1262809E-02 - - 1.1166687E-02 - - 1.1090107E-02 - - 1.1022668E-02 - - 1.0968772E-02 - - 1.0931381E-02 - - 1.0898236E-02 - - 1.0872094E-02 - - 1.0866295E-02 - - - 8.2371185E-01 - - 3.5234207E-01 - - 1.1927931E-01 - - 7.4555729E-03 - - -1.8093822E-02 - - 4.7584668E-04 - - - - 8.2420033E-01 - - 3.5255993E-01 - - 1.1937026E-01 - - 7.2853742E-03 - - -1.8313481E-02 - - 4.3042936E-04 - - - - 8.2554395E-01 - - 3.5269171E-01 - - 1.1923224E-01 - - 7.3701368E-03 - - -1.8272340E-02 - - 4.4800957E-04 - - - - 8.2759297E-01 - - 3.5316566E-01 - - 1.1927088E-01 - - 7.3660347E-03 - - -1.8328170E-02 - - 4.1130682E-04 - - - - 8.3010220E-01 - - 3.5369971E-01 - - 1.1938537E-01 - - 7.4104975E-03 - - -1.8303317E-02 - - 4.1953876E-04 - - - - 8.3343687E-01 - - 3.5441436E-01 - - 1.1949872E-01 - - 7.5322327E-03 - - -1.8306753E-02 - - 4.5747101E-04 - - - - 8.3787092E-01 - - 3.5551997E-01 - - 1.1969232E-01 - - 7.5811660E-03 - - -1.8329166E-02 - - 4.7852748E-04 - - - - 8.4310387E-01 - - 3.5672367E-01 - - 1.1987885E-01 - - 7.6564988E-03 - - -1.8365527E-02 - - 4.5067238E-04 - - - - 8.4958953E-01 - - 3.5843887E-01 - - 1.2018528E-01 - - 7.7892315E-03 - - -1.8386164E-02 - - 4.8596316E-04 - - - - 8.5783406E-01 - - 3.6063097E-01 - - 1.2066889E-01 - - 7.9351893E-03 - - -1.8471175E-02 - - 4.7399741E-04 - - - - 8.6863002E-01 - - 3.6377631E-01 - - 1.2139807E-01 - - 8.1733217E-03 - - -1.8540490E-02 - - 5.0406643E-04 - - - - 8.8306988E-01 - - 3.6819641E-01 - - 1.2250274E-01 - - 8.4479144E-03 - - -1.8664160E-02 - - 5.3786229E-04 - - - - 9.0387733E-01 - - 3.7488040E-01 - - 1.2420959E-01 - - 8.7500816E-03 - - -1.8976448E-02 - - 4.9664889E-04 - - - - 9.3478951E-01 - - 3.8530100E-01 - - 1.2704555E-01 - - 9.1818403E-03 - - -1.9402464E-02 - - 5.3777400E-04 - - - - 9.8306151E-01 - - 4.0212328E-01 - - 1.3182489E-01 - - 9.8420986E-03 - - -2.0147587E-02 - - 5.9236718E-04 - - - - 1.0501953E+00 - - 4.2587762E-01 - - 1.3867637E-01 - - 1.0689470E-02 - - -2.1155894E-02 - - 6.5005469E-04 - - - - 1.0862685E+00 - - 4.3797788E-01 - - 1.4197736E-01 - - 1.1172759E-02 - - -2.1737067E-02 - - 6.5599084E-04 - - - - 1.0874414E+00 - - 4.3717092E-01 - - 1.4142760E-01 - - 1.1235986E-02 - - -2.1646253E-02 - - 6.5585383E-04 - - - - 1.0736455E+00 - - 4.3084349E-01 - - 1.3933736E-01 - - 1.1186759E-02 - - -2.1309779E-02 - - 6.3989000E-04 - - - - 1.0558960E+00 - - 4.2321090E-01 - - 1.3684390E-01 - - 1.1034633E-02 - - -2.0842589E-02 - - 6.8339604E-04 - - - - 1.0391120E+00 - - 4.1635648E-01 - - 1.3463939E-01 - - 1.0869743E-02 - - -2.0503958E-02 - - 6.5877305E-04 - - - - 1.0254663E+00 - - 4.1079355E-01 - - 1.3288830E-01 - - 1.0692002E-02 - - -2.0222325E-02 - - 7.2411022E-04 - - - - 1.0142449E+00 - - 4.0621344E-01 - - 1.3145072E-01 - - 1.0526222E-02 - - -1.9995334E-02 - - 6.8891812E-04 - - - - 1.0049846E+00 - - 4.0236090E-01 - - 1.3022093E-01 - - 1.0429641E-02 - - -1.9811424E-02 - - 7.3287561E-04 - - - - 9.9758865E-01 - - 3.9933064E-01 - - 1.2934518E-01 - - 1.0285856E-02 - - -1.9735216E-02 - - 6.4095239E-04 - - - - 9.9137092E-01 - - 3.9669204E-01 - - 1.2850897E-01 - - 1.0180247E-02 - - -1.9595919E-02 - - 7.4239863E-04 - - - - 9.8633885E-01 - - 3.9464706E-01 - - 1.2782783E-01 - - 1.0115679E-02 - - -1.9489063E-02 - - 6.7732699E-04 - - - - 9.8241480E-01 - - 3.9293162E-01 - - 1.2725328E-01 - - 1.0076113E-02 - - -1.9411729E-02 - - 6.7080378E-04 - - - - 9.7912906E-01 - - 3.9164180E-01 - - 1.2687293E-01 - - 9.9947816E-03 - - -1.9390105E-02 - - 6.8484948E-04 - - - - 9.7702901E-01 - - 3.9079267E-01 - - 1.2678305E-01 - - 1.0006132E-02 - - -1.9296574E-02 - - 7.3827259E-04 - - - - 9.7553202E-01 - - 3.9010913E-01 - - 1.2644932E-01 - - 9.9292219E-03 - - -1.9314591E-02 - - 7.3482134E-04 - - - - 9.7483429E-01 - - 3.8985598E-01 - - 1.2640804E-01 - - 9.9206549E-03 - - -1.9266376E-02 - - 7.6472379E-04 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - - - uo2_ang_mu - uo2_ang_mu - 2.5300000E-08 - 32 - true - 32 - 1 - angle - histogram - - 4.0734790E-01 - - 4.0709470E-01 - - 4.0665280E-01 - - 4.0605122E-01 - - 4.0509226E-01 - - 4.0399893E-01 - - 4.0264927E-01 - - 4.0112684E-01 - - 3.9937450E-01 - - 3.9743081E-01 - - 3.9533879E-01 - - 3.9307550E-01 - - 3.9084961E-01 - - 3.8878017E-01 - - 3.8751931E-01 - - 3.8693825E-01 - - 3.9039929E-01 - - 4.0037023E-01 - - 4.1057791E-01 - - 4.1924835E-01 - - 4.2629128E-01 - - 4.3202621E-01 - - 4.3673213E-01 - - 4.4062993E-01 - - 4.4385222E-01 - - 4.4647166E-01 - - 4.4861335E-01 - - 4.5026817E-01 - - 4.5165329E-01 - - 4.5255720E-01 - - 4.5310208E-01 - - 4.5337269E-01 - - - 3.1599020E-02 - - 3.1371085E-02 - - 3.1023091E-02 - - 3.0539250E-02 - - 2.9839460E-02 - - 2.9013479E-02 - - 2.8058288E-02 - - 2.7047229E-02 - - 2.5977776E-02 - - 2.4952391E-02 - - 2.4009896E-02 - - 2.3244570E-02 - - 2.2725200E-02 - - 2.2489873E-02 - - 2.2624168E-02 - - 2.3059735E-02 - - 2.4782557E-02 - - 2.8553081E-02 - - 3.3194318E-02 - - 3.8038660E-02 - - 4.2666012E-02 - - 4.6923885E-02 - - 5.0708283E-02 - - 5.3996846E-02 - - 5.6845491E-02 - - 5.9213445E-02 - - 6.1182604E-02 - - 6.2742563E-02 - - 6.3985293E-02 - - 6.4852148E-02 - - 6.5364227E-02 - - 6.5703785E-02 - - - 4.5146530E-02 - - 4.4766687E-02 - - 4.4155441E-02 - - 4.3323960E-02 - - 4.2141314E-02 - - 4.0739637E-02 - - 3.9143652E-02 - - 3.7465300E-02 - - 3.5735871E-02 - - 3.4113931E-02 - - 3.2678644E-02 - - 3.1591060E-02 - - 3.0966537E-02 - - 3.0821062E-02 - - 3.1238242E-02 - - 3.2075654E-02 - - 3.4603728E-02 - - 3.9898114E-02 - - 4.6725370E-02 - - 5.4142159E-02 - - 6.1436273E-02 - - 6.8238302E-02 - - 7.4365771E-02 - - 7.9727018E-02 - - 8.4398863E-02 - - 8.8315890E-02 - - 9.1574736E-02 - - 9.4183896E-02 - - 9.6266615E-02 - - 9.7706019E-02 - - 9.8564505E-02 - - 9.9171965E-02 - - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - 1.0000000E+00 - - - 1.8183034E-02 - - 1.8028751E-02 - - 1.7777081E-02 - - 1.7434939E-02 - - 1.6947918E-02 - - 1.6371445E-02 - - 1.5714505E-02 - - 1.5023310E-02 - - 1.4310527E-02 - - 1.3640363E-02 - - 1.3045308E-02 - - 1.2590537E-02 - - 1.2323486E-02 - - 1.2250235E-02 - - 1.2408325E-02 - - 1.2741816E-02 - - 1.3791905E-02 - - 1.6011218E-02 - - 1.8846275E-02 - - 2.1907807E-02 - - 2.4909120E-02 - - 2.7704245E-02 - - 3.0220623E-02 - - 3.2422114E-02 - - 3.4339614E-02 - - 3.5947934E-02 - - 3.7286018E-02 - - 3.8357139E-02 - - 3.9212858E-02 - - 3.9804080E-02 - - 4.0156625E-02 - - 4.0404918E-02 - - - 9.8066123E-03 - - 9.6646401E-03 - - 9.6663597E-03 - - 9.6289590E-03 - - 9.6096138E-03 - - 9.6458323E-03 - - 9.7060173E-03 - - 9.7686742E-03 - - 9.7497590E-03 - - 9.8863575E-03 - - 9.9653503E-03 - - 1.0024461E-02 - - 1.0143433E-02 - - 1.0224038E-02 - - 1.0343441E-02 - - 1.0433289E-02 - - 1.0526146E-02 - - 1.0783759E-02 - - 1.0949268E-02 - - 1.1096291E-02 - - 1.1232675E-02 - - 1.1455467E-02 - - 1.1650746E-02 - - 1.1903201E-02 - - 1.2297735E-02 - - 1.2748370E-02 - - 1.3264457E-02 - - 1.4048689E-02 - - 1.5280440E-02 - - 1.6908123E-02 - - 1.9601832E-02 - - 2.3844984E-02 - - - - 9.7708240E-03 - - 9.6914019E-03 - - 9.6149267E-03 - - 9.5973173E-03 - - 9.6433893E-03 - - 9.6506128E-03 - - 9.7039801E-03 - - 9.6956785E-03 - - 9.7873194E-03 - - 9.8654118E-03 - - 9.9413480E-03 - - 1.0063248E-02 - - 1.0102923E-02 - - 1.0232802E-02 - - 1.0308882E-02 - - 1.0501651E-02 - - 1.0589986E-02 - - 1.0719182E-02 - - 1.0893048E-02 - - 1.1057750E-02 - - 1.1303383E-02 - - 1.1462120E-02 - - 1.1668725E-02 - - 1.1965138E-02 - - 1.2270967E-02 - - 1.2704483E-02 - - 1.3318045E-02 - - 1.4113776E-02 - - 1.5284443E-02 - - 1.6903540E-02 - - 1.9623766E-02 - - 2.3773086E-02 - - - - 9.7573912E-03 - - 9.6754767E-03 - - 9.6414920E-03 - - 9.5888776E-03 - - 9.6229707E-03 - - 9.6517720E-03 - - 9.7047117E-03 - - 9.7260741E-03 - - 9.8017859E-03 - - 9.8536413E-03 - - 9.9389825E-03 - - 1.0024606E-02 - - 1.0138509E-02 - - 1.0234629E-02 - - 1.0324330E-02 - - 1.0453936E-02 - - 1.0578467E-02 - - 1.0739823E-02 - - 1.0879319E-02 - - 1.1046986E-02 - - 1.1241981E-02 - - 1.1441204E-02 - - 1.1664457E-02 - - 1.1957610E-02 - - 1.2276940E-02 - - 1.2759947E-02 - - 1.3279607E-02 - - 1.4124886E-02 - - 1.5267698E-02 - - 1.6982394E-02 - - 1.9550155E-02 - - 2.3789453E-02 - - - - 9.7595941E-03 - - 9.6406785E-03 - - 9.6091241E-03 - - 9.6094212E-03 - - 9.6096714E-03 - - 9.6231813E-03 - - 9.6784094E-03 - - 9.7493834E-03 - - 9.7951671E-03 - - 9.8514115E-03 - - 9.9241369E-03 - - 1.0012170E-02 - - 1.0117529E-02 - - 1.0213412E-02 - - 1.0335767E-02 - - 1.0447944E-02 - - 1.0584231E-02 - - 1.0753231E-02 - - 1.0883138E-02 - - 1.1065663E-02 - - 1.1250080E-02 - - 1.1439297E-02 - - 1.1646700E-02 - - 1.1958053E-02 - - 1.2287514E-02 - - 1.2721568E-02 - - 1.3290189E-02 - - 1.4110041E-02 - - 1.5281715E-02 - - 1.6979118E-02 - - 1.9608566E-02 - - 2.3793845E-02 - - - - 9.7316881E-03 - - 9.6194631E-03 - - 9.6065192E-03 - - 9.5773341E-03 - - 9.6080573E-03 - - 9.6136679E-03 - - 9.6707217E-03 - - 9.7207622E-03 - - 9.7745677E-03 - - 9.8542855E-03 - - 9.9290325E-03 - - 1.0013807E-02 - - 1.0087705E-02 - - 1.0212493E-02 - - 1.0318553E-02 - - 1.0440413E-02 - - 1.0586043E-02 - - 1.0693482E-02 - - 1.0881032E-02 - - 1.1028668E-02 - - 1.1236016E-02 - - 1.1448039E-02 - - 1.1645248E-02 - - 1.1940864E-02 - - 1.2280554E-02 - - 1.2704859E-02 - - 1.3284908E-02 - - 1.4087561E-02 - - 1.5269781E-02 - - 1.6974160E-02 - - 1.9647654E-02 - - 2.3878185E-02 - - - - 9.7161201E-03 - - 9.6202380E-03 - - 9.5797790E-03 - - 9.5545189E-03 - - 9.5785124E-03 - - 9.5970413E-03 - - 9.6077970E-03 - - 9.7078158E-03 - - 9.7457417E-03 - - 9.8241572E-03 - - 9.9053715E-03 - - 9.9664533E-03 - - 1.0069700E-02 - - 1.0182303E-02 - - 1.0310258E-02 - - 1.0426742E-02 - - 1.0561490E-02 - - 1.0707708E-02 - - 1.0863937E-02 - - 1.1051125E-02 - - 1.1221704E-02 - - 1.1442069E-02 - - 1.1658848E-02 - - 1.1941489E-02 - - 1.2275743E-02 - - 1.2702110E-02 - - 1.3323051E-02 - - 1.4108176E-02 - - 1.5289516E-02 - - 1.6993392E-02 - - 1.9675117E-02 - - 2.3895695E-02 - - - - 9.6862964E-03 - - 9.6118860E-03 - - 9.5204994E-03 - - 9.5427943E-03 - - 9.5461966E-03 - - 9.5657839E-03 - - 9.5949449E-03 - - 9.6654696E-03 - - 9.7413833E-03 - - 9.7999604E-03 - - 9.8652718E-03 - - 9.9395415E-03 - - 1.0066252E-02 - - 1.0162957E-02 - - 1.0288525E-02 - - 1.0410136E-02 - - 1.0544012E-02 - - 1.0683294E-02 - - 1.0857487E-02 - - 1.1034643E-02 - - 1.1202400E-02 - - 1.1413244E-02 - - 1.1649707E-02 - - 1.1927823E-02 - - 1.2268032E-02 - - 1.2711207E-02 - - 1.3301163E-02 - - 1.4107114E-02 - - 1.5299888E-02 - - 1.7035047E-02 - - 1.9688248E-02 - - 2.3980184E-02 - - - - 9.6789320E-03 - - 9.5794368E-03 - - 9.5136834E-03 - - 9.4987637E-03 - - 9.5122403E-03 - - 9.5462846E-03 - - 9.5893599E-03 - - 9.6291844E-03 - - 9.6755880E-03 - - 9.7758823E-03 - - 9.8512097E-03 - - 9.9153183E-03 - - 1.0010492E-02 - - 1.0132751E-02 - - 1.0249082E-02 - - 1.0374304E-02 - - 1.0525789E-02 - - 1.0647590E-02 - - 1.0816183E-02 - - 1.1002705E-02 - - 1.1172733E-02 - - 1.1391942E-02 - - 1.1634015E-02 - - 1.1896152E-02 - - 1.2250313E-02 - - 1.2701494E-02 - - 1.3297953E-02 - - 1.4128277E-02 - - 1.5304878E-02 - - 1.7057822E-02 - - 1.9759949E-02 - - 2.4058227E-02 - - - - 9.6295658E-03 - - 9.5389047E-03 - - 9.4742925E-03 - - 9.4575039E-03 - - 9.4670086E-03 - - 9.5016333E-03 - - 9.5287576E-03 - - 9.5962610E-03 - - 9.6450345E-03 - - 9.7355000E-03 - - 9.8168240E-03 - - 9.8832939E-03 - - 9.9783337E-03 - - 1.0096077E-02 - - 1.0226691E-02 - - 1.0343925E-02 - - 1.0478576E-02 - - 1.0624400E-02 - - 1.0795052E-02 - - 1.0971506E-02 - - 1.1155210E-02 - - 1.1359948E-02 - - 1.1600072E-02 - - 1.1891155E-02 - - 1.2217464E-02 - - 1.2687949E-02 - - 1.3279851E-02 - - 1.4139232E-02 - - 1.5331088E-02 - - 1.7109049E-02 - - 1.9804341E-02 - - 2.4140346E-02 - - - - 9.5761863E-03 - - 9.4820918E-03 - - 9.4335419E-03 - - 9.4124923E-03 - - 9.4238881E-03 - - 9.4447526E-03 - - 9.4999957E-03 - - 9.5315541E-03 - - 9.6078277E-03 - - 9.7003335E-03 - - 9.7574525E-03 - - 9.8379436E-03 - - 9.9462733E-03 - - 1.0053971E-02 - - 1.0174903E-02 - - 1.0296178E-02 - - 1.0416178E-02 - - 1.0598338E-02 - - 1.0736969E-02 - - 1.0921999E-02 - - 1.1103049E-02 - - 1.1337535E-02 - - 1.1560952E-02 - - 1.1844754E-02 - - 1.2186109E-02 - - 1.2650980E-02 - - 1.3288356E-02 - - 1.4113781E-02 - - 1.5336174E-02 - - 1.7136757E-02 - - 1.9885917E-02 - - 2.4274812E-02 - - - - 9.5122168E-03 - - 9.4370370E-03 - - 9.3789842E-03 - - 9.3641793E-03 - - 9.3461446E-03 - - 9.3736151E-03 - - 9.4378621E-03 - - 9.4888307E-03 - - 9.5578870E-03 - - 9.6287585E-03 - - 9.7018579E-03 - - 9.7842398E-03 - - 9.8853931E-03 - - 9.9928939E-03 - - 1.0118830E-02 - - 1.0234335E-02 - - 1.0390558E-02 - - 1.0549529E-02 - - 1.0695492E-02 - - 1.0871300E-02 - - 1.1074656E-02 - - 1.1276285E-02 - - 1.1528116E-02 - - 1.1795259E-02 - - 1.2170410E-02 - - 1.2620687E-02 - - 1.3248447E-02 - - 1.4113310E-02 - - 1.5330992E-02 - - 1.7146317E-02 - - 1.9971083E-02 - - 2.4420125E-02 - - - - 9.4655965E-03 - - 9.3472543E-03 - - 9.3135845E-03 - - 9.2723897E-03 - - 9.2802062E-03 - - 9.3207904E-03 - - 9.3438769E-03 - - 9.4089282E-03 - - 9.4772470E-03 - - 9.5593066E-03 - - 9.6350349E-03 - - 9.7156422E-03 - - 9.8254749E-03 - - 9.9256153E-03 - - 1.0046422E-02 - - 1.0170127E-02 - - 1.0324109E-02 - - 1.0494779E-02 - - 1.0643991E-02 - - 1.0830850E-02 - - 1.1006031E-02 - - 1.1226896E-02 - - 1.1461160E-02 - - 1.1751421E-02 - - 1.2117075E-02 - - 1.2580807E-02 - - 1.3191655E-02 - - 1.4078045E-02 - - 1.5308284E-02 - - 1.7194422E-02 - - 2.0045307E-02 - - 2.4607445E-02 - - - - 9.3803794E-03 - - 9.2679518E-03 - - 9.2244314E-03 - - 9.2113545E-03 - - 9.2138570E-03 - - 9.2462589E-03 - - 9.2883856E-03 - - 9.3378797E-03 - - 9.4087558E-03 - - 9.4791189E-03 - - 9.5459849E-03 - - 9.6532937E-03 - - 9.7407231E-03 - - 9.8542750E-03 - - 9.9718785E-03 - - 1.0102253E-02 - - 1.0257191E-02 - - 1.0422947E-02 - - 1.0576154E-02 - - 1.0751370E-02 - - 1.0937694E-02 - - 1.1150504E-02 - - 1.1403363E-02 - - 1.1690271E-02 - - 1.2041631E-02 - - 1.2515941E-02 - - 1.3148002E-02 - - 1.4030663E-02 - - 1.5293666E-02 - - 1.7182409E-02 - - 2.0111404E-02 - - 2.4776028E-02 - - - - 9.3172617E-03 - - 9.2089569E-03 - - 9.1486659E-03 - - 9.1277777E-03 - - 9.1461098E-03 - - 9.1678665E-03 - - 9.2093270E-03 - - 9.2630599E-03 - - 9.3084731E-03 - - 9.4133582E-03 - - 9.4836368E-03 - - 9.5792942E-03 - - 9.6772510E-03 - - 9.7775420E-03 - - 9.9042034E-03 - - 1.0042269E-02 - - 1.0180349E-02 - - 1.0339342E-02 - - 1.0499500E-02 - - 1.0689206E-02 - - 1.0856780E-02 - - 1.1064872E-02 - - 1.1313606E-02 - - 1.1607748E-02 - - 1.1964604E-02 - - 1.2435691E-02 - - 1.3060461E-02 - - 1.3974178E-02 - - 1.5269813E-02 - - 1.7174181E-02 - - 2.0168154E-02 - - 2.5006625E-02 - - - - 9.2675186E-03 - - 9.1560947E-03 - - 9.1099682E-03 - - 9.0686023E-03 - - 9.0949282E-03 - - 9.1189359E-03 - - 9.1587135E-03 - - 9.2079644E-03 - - 9.2872523E-03 - - 9.3678425E-03 - - 9.4331971E-03 - - 9.5255074E-03 - - 9.6234797E-03 - - 9.7408756E-03 - - 9.8464228E-03 - - 9.9839770E-03 - - 1.0134229E-02 - - 1.0296950E-02 - - 1.0437157E-02 - - 1.0621205E-02 - - 1.0805038E-02 - - 1.1016214E-02 - - 1.1261528E-02 - - 1.1539985E-02 - - 1.1895722E-02 - - 1.2371092E-02 - - 1.3001136E-02 - - 1.3913205E-02 - - 1.5214879E-02 - - 1.7172526E-02 - - 2.0220324E-02 - - 2.5144658E-02 - - - - 9.2487420E-03 - - 9.1281258E-03 - - 9.0754703E-03 - - 9.0528962E-03 - - 9.0607826E-03 - - 9.0836186E-03 - - 9.1336267E-03 - - 9.1791302E-03 - - 9.2456080E-03 - - 9.3262261E-03 - - 9.3970635E-03 - - 9.4814471E-03 - - 9.5988170E-03 - - 9.7082444E-03 - - 9.8223867E-03 - - 9.9431245E-03 - - 1.0105918E-02 - - 1.0235908E-02 - - 1.0399441E-02 - - 1.0585520E-02 - - 1.0757015E-02 - - 1.0981562E-02 - - 1.1194196E-02 - - 1.1486474E-02 - - 1.1845432E-02 - - 1.2322129E-02 - - 1.2940763E-02 - - 1.3835543E-02 - - 1.5166292E-02 - - 1.7159569E-02 - - 2.0241404E-02 - - 2.5261208E-02 - - - - 9.3326963E-03 - - 9.2136145E-03 - - 9.1672115E-03 - - 9.1448034E-03 - - 9.1509378E-03 - - 9.1710414E-03 - - 9.2163629E-03 - - 9.2665486E-03 - - 9.3325121E-03 - - 9.4016396E-03 - - 9.5034088E-03 - - 9.5773816E-03 - - 9.6674816E-03 - - 9.7850853E-03 - - 9.9014422E-03 - - 1.0023693E-02 - - 1.0166562E-02 - - 1.0315995E-02 - - 1.0472398E-02 - - 1.0641203E-02 - - 1.0830711E-02 - - 1.1048828E-02 - - 1.1263336E-02 - - 1.1551095E-02 - - 1.1894787E-02 - - 1.2358496E-02 - - 1.2983340E-02 - - 1.3874895E-02 - - 1.5186930E-02 - - 1.7144384E-02 - - 2.0133533E-02 - - 2.5038814E-02 - - - - 9.5906528E-03 - - 9.4714149E-03 - - 9.4373276E-03 - - 9.4092245E-03 - - 9.4080878E-03 - - 9.4464166E-03 - - 9.4856267E-03 - - 9.5436808E-03 - - 9.6059463E-03 - - 9.6771305E-03 - - 9.7582049E-03 - - 9.8361595E-03 - - 9.9382461E-03 - - 1.0051079E-02 - - 1.0152805E-02 - - 1.0287101E-02 - - 1.0441087E-02 - - 1.0565078E-02 - - 1.0711502E-02 - - 1.0891178E-02 - - 1.1071184E-02 - - 1.1292859E-02 - - 1.1522246E-02 - - 1.1788324E-02 - - 1.2135266E-02 - - 1.2615017E-02 - - 1.3201487E-02 - - 1.4060330E-02 - - 1.5281894E-02 - - 1.7084038E-02 - - 1.9845860E-02 - - 2.4315267E-02 - - - - 9.8248104E-03 - - 9.7323237E-03 - - 9.6774360E-03 - - 9.6780777E-03 - - 9.6806071E-03 - - 9.7078157E-03 - - 9.7458638E-03 - - 9.8100671E-03 - - 9.8562275E-03 - - 9.9244575E-03 - - 1.0022233E-02 - - 1.0083426E-02 - - 1.0184960E-02 - - 1.0286955E-02 - - 1.0393298E-02 - - 1.0523934E-02 - - 1.0674383E-02 - - 1.0799950E-02 - - 1.0950769E-02 - - 1.1117330E-02 - - 1.1304368E-02 - - 1.1511486E-02 - - 1.1731876E-02 - - 1.2009368E-02 - - 1.2343059E-02 - - 1.2776813E-02 - - 1.3375541E-02 - - 1.4170942E-02 - - 1.5323633E-02 - - 1.7010159E-02 - - 1.9570530E-02 - - 2.3678539E-02 - - - - 1.0003922E-02 - - 9.9126090E-03 - - 9.8710015E-03 - - 9.8670066E-03 - - 9.8659781E-03 - - 9.8893674E-03 - - 9.9377144E-03 - - 9.9843851E-03 - - 1.0043716E-02 - - 1.0114248E-02 - - 1.0187530E-02 - - 1.0267347E-02 - - 1.0358552E-02 - - 1.0462167E-02 - - 1.0591882E-02 - - 1.0702606E-02 - - 1.0831901E-02 - - 1.0977238E-02 - - 1.1108339E-02 - - 1.1308120E-02 - - 1.1462407E-02 - - 1.1644185E-02 - - 1.1896695E-02 - - 1.2152261E-02 - - 1.2470909E-02 - - 1.2904242E-02 - - 1.3463705E-02 - - 1.4217800E-02 - - 1.5306830E-02 - - 1.6913123E-02 - - 1.9352840E-02 - - 2.3210338E-02 - - - - 1.0110150E-02 - - 1.0038689E-02 - - 1.0006487E-02 - - 9.9882512E-03 - - 1.0012465E-02 - - 1.0038003E-02 - - 1.0080385E-02 - - 1.0133099E-02 - - 1.0195776E-02 - - 1.0230495E-02 - - 1.0337794E-02 - - 1.0414378E-02 - - 1.0494026E-02 - - 1.0600307E-02 - - 1.0712290E-02 - - 1.0823942E-02 - - 1.0947285E-02 - - 1.1079870E-02 - - 1.1237336E-02 - - 1.1392659E-02 - - 1.1573008E-02 - - 1.1782567E-02 - - 1.1965944E-02 - - 1.2231191E-02 - - 1.2530296E-02 - - 1.2940908E-02 - - 1.3487030E-02 - - 1.4206747E-02 - - 1.5258559E-02 - - 1.6813287E-02 - - 1.9165344E-02 - - 2.2905494E-02 - - - - 1.0214736E-02 - - 1.0132229E-02 - - 1.0105238E-02 - - 1.0076016E-02 - - 1.0102342E-02 - - 1.0126079E-02 - - 1.0166649E-02 - - 1.0211271E-02 - - 1.0274414E-02 - - 1.0328594E-02 - - 1.0415141E-02 - - 1.0493084E-02 - - 1.0583179E-02 - - 1.0679080E-02 - - 1.0785554E-02 - - 1.0896861E-02 - - 1.1025180E-02 - - 1.1151734E-02 - - 1.1308616E-02 - - 1.1460250E-02 - - 1.1631030E-02 - - 1.1818829E-02 - - 1.2020589E-02 - - 1.2270878E-02 - - 1.2564608E-02 - - 1.2974969E-02 - - 1.3498179E-02 - - 1.4207601E-02 - - 1.5228538E-02 - - 1.6730509E-02 - - 1.9011440E-02 - - 2.2710972E-02 - - - - 1.0268267E-02 - - 1.0196885E-02 - - 1.0157361E-02 - - 1.0140649E-02 - - 1.0169437E-02 - - 1.0183304E-02 - - 1.0243979E-02 - - 1.0276945E-02 - - 1.0343732E-02 - - 1.0412311E-02 - - 1.0476453E-02 - - 1.0547309E-02 - - 1.0646659E-02 - - 1.0745962E-02 - - 1.0848409E-02 - - 1.0960759E-02 - - 1.1082990E-02 - - 1.1214082E-02 - - 1.1358598E-02 - - 1.1499661E-02 - - 1.1661477E-02 - - 1.1836025E-02 - - 1.2058652E-02 - - 1.2293116E-02 - - 1.2566338E-02 - - 1.2977505E-02 - - 1.3480636E-02 - - 1.4176526E-02 - - 1.5190195E-02 - - 1.6660100E-02 - - 1.8910243E-02 - - 2.2560488E-02 - - - - 1.0317792E-02 - - 1.0247350E-02 - - 1.0209518E-02 - - 1.0176974E-02 - - 1.0202003E-02 - - 1.0234569E-02 - - 1.0290041E-02 - - 1.0329819E-02 - - 1.0401460E-02 - - 1.0453530E-02 - - 1.0512745E-02 - - 1.0606160E-02 - - 1.0688319E-02 - - 1.0769020E-02 - - 1.0865579E-02 - - 1.0991642E-02 - - 1.1131957E-02 - - 1.1257621E-02 - - 1.1387433E-02 - - 1.1532542E-02 - - 1.1687029E-02 - - 1.1880598E-02 - - 1.2082924E-02 - - 1.2307513E-02 - - 1.2595319E-02 - - 1.2957554E-02 - - 1.3464867E-02 - - 1.4143088E-02 - - 1.5132042E-02 - - 1.6579665E-02 - - 1.8862731E-02 - - 2.2454495E-02 - - - - 1.0353436E-02 - - 1.0273106E-02 - - 1.0227967E-02 - - 1.0220784E-02 - - 1.0226684E-02 - - 1.0260876E-02 - - 1.0312588E-02 - - 1.0358157E-02 - - 1.0401938E-02 - - 1.0498406E-02 - - 1.0534029E-02 - - 1.0633113E-02 - - 1.0711786E-02 - - 1.0806930E-02 - - 1.0902341E-02 - - 1.1005862E-02 - - 1.1140903E-02 - - 1.1256190E-02 - - 1.1418216E-02 - - 1.1551704E-02 - - 1.1699315E-02 - - 1.1876316E-02 - - 1.2095791E-02 - - 1.2321059E-02 - - 1.2598778E-02 - - 1.2945785E-02 - - 1.3441410E-02 - - 1.4150310E-02 - - 1.5110707E-02 - - 1.6555004E-02 - - 1.8801362E-02 - - 2.2362745E-02 - - - - 1.0368488E-02 - - 1.0298130E-02 - - 1.0243651E-02 - - 1.0237480E-02 - - 1.0271825E-02 - - 1.0283702E-02 - - 1.0344999E-02 - - 1.0388950E-02 - - 1.0443402E-02 - - 1.0499057E-02 - - 1.0554275E-02 - - 1.0647638E-02 - - 1.0712690E-02 - - 1.0827382E-02 - - 1.0931601E-02 - - 1.1018556E-02 - - 1.1152881E-02 - - 1.1290059E-02 - - 1.1420028E-02 - - 1.1563732E-02 - - 1.1705467E-02 - - 1.1895794E-02 - - 1.2092710E-02 - - 1.2310135E-02 - - 1.2594991E-02 - - 1.2963713E-02 - - 1.3446042E-02 - - 1.4105472E-02 - - 1.5078624E-02 - - 1.6548015E-02 - - 1.8734322E-02 - - 2.2344993E-02 - - - - 1.0381081E-02 - - 1.0306858E-02 - - 1.0277150E-02 - - 1.0252664E-02 - - 1.0290401E-02 - - 1.0294657E-02 - - 1.0329546E-02 - - 1.0392619E-02 - - 1.0438626E-02 - - 1.0515024E-02 - - 1.0591864E-02 - - 1.0665572E-02 - - 1.0764627E-02 - - 1.0867664E-02 - - 1.0949159E-02 - - 1.1055591E-02 - - 1.1176115E-02 - - 1.1296618E-02 - - 1.1417920E-02 - - 1.1572450E-02 - - 1.1714864E-02 - - 1.1894815E-02 - - 1.2080388E-02 - - 1.2311306E-02 - - 1.2600200E-02 - - 1.2956245E-02 - - 1.3438289E-02 - - 1.4113577E-02 - - 1.5087407E-02 - - 1.6503410E-02 - - 1.8740374E-02 - - 2.2290166E-02 - - - - 1.0379499E-02 - - 1.0316828E-02 - - 1.0280998E-02 - - 1.0282758E-02 - - 1.0275605E-02 - - 1.0306117E-02 - - 1.0348208E-02 - - 1.0378745E-02 - - 1.0464787E-02 - - 1.0530463E-02 - - 1.0608232E-02 - - 1.0674147E-02 - - 1.0763998E-02 - - 1.0837280E-02 - - 1.0949195E-02 - - 1.1058508E-02 - - 1.1190589E-02 - - 1.1322242E-02 - - 1.1432422E-02 - - 1.1582770E-02 - - 1.1718207E-02 - - 1.1912632E-02 - - 1.2075287E-02 - - 1.2309263E-02 - - 1.2598203E-02 - - 1.2947275E-02 - - 1.3422204E-02 - - 1.4101792E-02 - - 1.5074531E-02 - - 1.6493963E-02 - - 1.8703917E-02 - - 2.2279156E-02 - - - - 1.0425160E-02 - - 1.0318223E-02 - - 1.0301788E-02 - - 1.0294047E-02 - - 1.0284686E-02 - - 1.0349566E-02 - - 1.0366017E-02 - - 1.0397170E-02 - - 1.0476721E-02 - - 1.0527169E-02 - - 1.0602826E-02 - - 1.0679945E-02 - - 1.0766188E-02 - - 1.0868516E-02 - - 1.0967919E-02 - - 1.1069388E-02 - - 1.1166089E-02 - - 1.1293657E-02 - - 1.1442396E-02 - - 1.1579055E-02 - - 1.1756181E-02 - - 1.1901153E-02 - - 1.2075228E-02 - - 1.2329489E-02 - - 1.2582177E-02 - - 1.2965246E-02 - - 1.3451596E-02 - - 1.4114325E-02 - - 1.5048259E-02 - - 1.6478843E-02 - - 1.8702139E-02 - - 2.2209013E-02 - - - - 1.0403120E-02 - - 1.0338330E-02 - - 1.0290627E-02 - - 1.0277361E-02 - - 1.0322671E-02 - - 1.0363565E-02 - - 1.0362094E-02 - - 1.0440786E-02 - - 1.0485173E-02 - - 1.0557958E-02 - - 1.0608779E-02 - - 1.0701287E-02 - - 1.0735526E-02 - - 1.0841760E-02 - - 1.0953485E-02 - - 1.1083460E-02 - - 1.1193252E-02 - - 1.1297597E-02 - - 1.1457508E-02 - - 1.1572681E-02 - - 1.1742409E-02 - - 1.1907920E-02 - - 1.2078022E-02 - - 1.2328222E-02 - - 1.2585186E-02 - - 1.2967887E-02 - - 1.3432333E-02 - - 1.4108413E-02 - - 1.5033330E-02 - - 1.6472418E-02 - - 1.8651936E-02 - - 2.2205180E-02 - - - - 1.0383972E-02 - - 1.0327340E-02 - - 1.0320447E-02 - - 1.0278943E-02 - - 1.0322805E-02 - - 1.0366993E-02 - - 1.0395218E-02 - - 1.0418111E-02 - - 1.0463460E-02 - - 1.0564171E-02 - - 1.0601357E-02 - - 1.0671268E-02 - - 1.0756633E-02 - - 1.0863620E-02 - - 1.0982943E-02 - - 1.1088262E-02 - - 1.1182298E-02 - - 1.1297412E-02 - - 1.1404871E-02 - - 1.1585288E-02 - - 1.1730768E-02 - - 1.1878353E-02 - - 1.2074551E-02 - - 1.2333404E-02 - - 1.2612428E-02 - - 1.2970577E-02 - - 1.3454326E-02 - - 1.4077858E-02 - - 1.5040384E-02 - - 1.6507810E-02 - - 1.8671362E-02 - - 2.2195534E-02 - - - - 1.0393621E-02 - - 1.0343827E-02 - - 1.0278122E-02 - - 1.0307024E-02 - - 1.0321853E-02 - - 1.0374136E-02 - - 1.0395136E-02 - - 1.0457919E-02 - - 1.0485306E-02 - - 1.0588898E-02 - - 1.0597124E-02 - - 1.0623537E-02 - - 1.0731134E-02 - - 1.0828231E-02 - - 1.0959209E-02 - - 1.1072327E-02 - - 1.1248877E-02 - - 1.1263490E-02 - - 1.1402046E-02 - - 1.1566689E-02 - - 1.1767919E-02 - - 1.1861445E-02 - - 1.2076314E-02 - - 1.2322575E-02 - - 1.2537228E-02 - - 1.2963070E-02 - - 1.3353083E-02 - - 1.4108968E-02 - - 1.5044977E-02 - - 1.6501651E-02 - - 1.8769742E-02 - - 2.2133504E-02 - - - 1.0002763E+00 - - - 1.0002760E+00 - - - 1.0002658E+00 - - - 1.0002710E+00 - - - 1.0002776E+00 - - - 1.0002767E+00 - - - 1.0002833E+00 - - - 1.0002791E+00 - - - 1.0002788E+00 - - - 1.0002858E+00 - - - 1.0002884E+00 - - - 1.0002916E+00 - - - 1.0003039E+00 - - - 1.0003181E+00 - - - 1.0003365E+00 - - - 1.0003544E+00 - - - 1.0003372E+00 - - - 1.0002764E+00 - - - 1.0002508E+00 - - - 1.0002343E+00 - - - 1.0002360E+00 - - - 1.0002375E+00 - - - 1.0002331E+00 - - - 1.0002344E+00 - - - 1.0002385E+00 - - - 1.0002316E+00 - - - 1.0002360E+00 - - - 1.0002360E+00 - - - 1.0002354E+00 - - - 1.0002349E+00 - - - 1.0002325E+00 - - - 1.0002268E+00 - - - - - clad_ang_mu - clad_ang_mu - 2.5300000E-08 - 32 - false - 32 - 1 - angle - histogram - - 3.1005638E-01 - - 3.0999067E-01 - - 3.0994879E-01 - - 3.0987779E-01 - - 3.0961631E-01 - - 3.0948272E-01 - - 3.0913340E-01 - - 3.0868239E-01 - - 3.0799925E-01 - - 3.0712597E-01 - - 3.0590948E-01 - - 3.0432728E-01 - - 3.0235012E-01 - - 2.9996873E-01 - - 2.9743091E-01 - - 2.9739624E-01 - - 3.0835788E-01 - - 3.1305337E-01 - - 3.1379599E-01 - - 3.1314506E-01 - - 3.1216249E-01 - - 3.1129786E-01 - - 3.1059203E-01 - - 3.1009561E-01 - - 3.0977837E-01 - - 3.0951041E-01 - - 3.0930940E-01 - - 3.0929712E-01 - - 3.0925741E-01 - - 3.0917641E-01 - - 3.0919741E-01 - - 3.0912502E-01 - - - 1.3490691E-03 - - 1.3463259E-03 - - 1.3498512E-03 - - 1.3366347E-03 - - 1.3288899E-03 - - 1.3176269E-03 - - 1.3059971E-03 - - 1.2891508E-03 - - 1.2713136E-03 - - 1.2555332E-03 - - 1.2394055E-03 - - 1.2170158E-03 - - 1.1969201E-03 - - 1.1849620E-03 - - 1.1899173E-03 - - 1.2761137E-03 - - 1.6244505E-03 - - 1.9090551E-03 - - 2.0837409E-03 - - 2.1976011E-03 - - 2.2746911E-03 - - 2.3308251E-03 - - 2.3700744E-03 - - 2.3981231E-03 - - 2.4248079E-03 - - 2.4441792E-03 - - 2.4510541E-03 - - 2.4640212E-03 - - 2.4741885E-03 - - 2.4697219E-03 - - 2.4721421E-03 - - 2.4729172E-03 - - - 8.6638893E-03 - - 8.2719674E-03 - - 7.8055649E-03 - - 7.4105610E-03 - - 7.2544086E-03 - - 7.0854147E-03 - - 6.9965517E-03 - - 7.0314805E-03 - - 6.8552954E-03 - - 6.9138525E-03 - - 6.9528906E-03 - - 7.0689776E-03 - - 7.0720596E-03 - - 7.2523539E-03 - - 7.5405167E-03 - - 7.7624175E-03 - - 7.9838046E-03 - - 8.1702629E-03 - - 8.4784584E-03 - - 8.8970906E-03 - - 9.3105862E-03 - - 9.7826390E-03 - - 1.0253151E-02 - - 1.0659455E-02 - - 1.1134076E-02 - - 1.1649276E-02 - - 1.2603655E-02 - - 1.3342297E-02 - - 1.4372697E-02 - - 1.5779610E-02 - - 1.7933383E-02 - - 2.0318816E-02 - - - - 8.6137649E-03 - - 8.0815773E-03 - - 7.7778880E-03 - - 7.4879636E-03 - - 7.2446680E-03 - - 7.0652074E-03 - - 6.9244607E-03 - - 6.9131046E-03 - - 6.9017486E-03 - - 6.9408066E-03 - - 6.9814132E-03 - - 7.0440438E-03 - - 7.1589812E-03 - - 7.3353447E-03 - - 7.5896522E-03 - - 7.7529390E-03 - - 8.0199791E-03 - - 8.3484454E-03 - - 8.5960425E-03 - - 8.9554799E-03 - - 9.2763754E-03 - - 9.7440398E-03 - - 1.0084034E-02 - - 1.0634976E-02 - - 1.1176800E-02 - - 1.1768004E-02 - - 1.2488944E-02 - - 1.3414293E-02 - - 1.4307639E-02 - - 1.5845012E-02 - - 1.7838866E-02 - - 2.0339442E-02 - - - - 8.6069286E-03 - - 8.1600584E-03 - - 7.7753343E-03 - - 7.5082514E-03 - - 7.2541589E-03 - - 7.1052368E-03 - - 7.0049508E-03 - - 6.9087178E-03 - - 6.8877253E-03 - - 6.9276318E-03 - - 6.9580813E-03 - - 7.0116019E-03 - - 7.1577180E-03 - - 7.3369857E-03 - - 7.5182280E-03 - - 7.7277374E-03 - - 7.9440018E-03 - - 8.2744779E-03 - - 8.6378977E-03 - - 8.8881451E-03 - - 9.2653867E-03 - - 9.6492794E-03 - - 1.0205685E-02 - - 1.0657959E-02 - - 1.1210208E-02 - - 1.1713716E-02 - - 1.2497402E-02 - - 1.3347079E-02 - - 1.4469243E-02 - - 1.5835834E-02 - - 1.7754882E-02 - - 2.0415319E-02 - - - - 8.6357058E-03 - - 8.1456937E-03 - - 7.7155413E-03 - - 7.4818571E-03 - - 7.2524325E-03 - - 7.0736756E-03 - - 7.0115740E-03 - - 6.8735456E-03 - - 6.8726489E-03 - - 6.9218219E-03 - - 6.9136015E-03 - - 7.0770385E-03 - - 7.1125358E-03 - - 7.2947303E-03 - - 7.5540473E-03 - - 7.7247333E-03 - - 7.9593143E-03 - - 8.2175104E-03 - - 8.5783123E-03 - - 8.9662416E-03 - - 9.2850446E-03 - - 9.7500218E-03 - - 1.0192206E-02 - - 1.0589252E-02 - - 1.1196518E-02 - - 1.1754610E-02 - - 1.2477858E-02 - - 1.3364244E-02 - - 1.4489097E-02 - - 1.5799582E-02 - - 1.7806262E-02 - - 2.0415575E-02 - - - - 8.6187094E-03 - - 8.1028888E-03 - - 7.7502930E-03 - - 7.4368288E-03 - - 7.2053294E-03 - - 7.0754195E-03 - - 6.9609624E-03 - - 6.9199506E-03 - - 6.8721819E-03 - - 6.9170716E-03 - - 6.9278240E-03 - - 7.0082024E-03 - - 7.1469258E-03 - - 7.2928174E-03 - - 7.4578635E-03 - - 7.7005853E-03 - - 7.9397817E-03 - - 8.2897923E-03 - - 8.5642424E-03 - - 8.9336425E-03 - - 9.2822429E-03 - - 9.6866617E-03 - - 1.0169638E-02 - - 1.0601319E-02 - - 1.1134062E-02 - - 1.1797713E-02 - - 1.2521413E-02 - - 1.3398584E-02 - - 1.4465948E-02 - - 1.5920693E-02 - - 1.7831503E-02 - - 2.0386280E-02 - - - - 8.5957828E-03 - - 8.0917421E-03 - - 7.7483058E-03 - - 7.4335661E-03 - - 7.2051598E-03 - - 7.0542832E-03 - - 6.9482999E-03 - - 6.8660522E-03 - - 6.8566650E-03 - - 6.8895446E-03 - - 6.9769966E-03 - - 7.0151292E-03 - - 7.1289919E-03 - - 7.2728159E-03 - - 7.4843447E-03 - - 7.6904746E-03 - - 7.9728210E-03 - - 8.2376090E-03 - - 8.5714149E-03 - - 8.9027889E-03 - - 9.2973443E-03 - - 9.6952072E-03 - - 1.0177798E-02 - - 1.0619290E-02 - - 1.1136220E-02 - - 1.1749356E-02 - - 1.2532485E-02 - - 1.3371645E-02 - - 1.4476030E-02 - - 1.5936887E-02 - - 1.7814576E-02 - - 2.0401706E-02 - - - - 8.5762717E-03 - - 8.0787798E-03 - - 7.6957274E-03 - - 7.4218081E-03 - - 7.1969403E-03 - - 7.0456914E-03 - - 6.9243998E-03 - - 6.8670339E-03 - - 6.8410876E-03 - - 6.8440959E-03 - - 6.9114894E-03 - - 6.9709444E-03 - - 7.1246584E-03 - - 7.2467020E-03 - - 7.4540634E-03 - - 7.6790984E-03 - - 7.9072251E-03 - - 8.2202101E-03 - - 8.5598098E-03 - - 8.9093117E-03 - - 9.2775317E-03 - - 9.6625479E-03 - - 1.0156279E-02 - - 1.0632045E-02 - - 1.1116292E-02 - - 1.1767916E-02 - - 1.2489983E-02 - - 1.3349302E-02 - - 1.4524155E-02 - - 1.5953415E-02 - - 1.7870641E-02 - - 2.0504336E-02 - - - - 8.5580155E-03 - - 8.0552826E-03 - - 7.6847006E-03 - - 7.3901486E-03 - - 7.1714794E-03 - - 6.9956094E-03 - - 6.8966894E-03 - - 6.8584904E-03 - - 6.8074847E-03 - - 6.8182305E-03 - - 6.8700458E-03 - - 6.9598760E-03 - - 7.0775275E-03 - - 7.2721659E-03 - - 7.4256244E-03 - - 7.6626570E-03 - - 7.8956048E-03 - - 8.2476025E-03 - - 8.5876768E-03 - - 8.8916497E-03 - - 9.2599869E-03 - - 9.6607086E-03 - - 1.0104818E-02 - - 1.0621057E-02 - - 1.1139577E-02 - - 1.1789513E-02 - - 1.2505652E-02 - - 1.3335138E-02 - - 1.4480446E-02 - - 1.5926378E-02 - - 1.7926012E-02 - - 2.0526011E-02 - - - - 8.5161659E-03 - - 8.0446298E-03 - - 7.6545410E-03 - - 7.3722009E-03 - - 7.1148071E-03 - - 6.9727284E-03 - - 6.8574133E-03 - - 6.7687628E-03 - - 6.7671107E-03 - - 6.8028617E-03 - - 6.8012426E-03 - - 6.9205557E-03 - - 7.0398688E-03 - - 7.2416867E-03 - - 7.3960899E-03 - - 7.6495518E-03 - - 7.9006016E-03 - - 8.1906074E-03 - - 8.4993478E-03 - - 8.8863636E-03 - - 9.2483009E-03 - - 9.6547452E-03 - - 1.0109959E-02 - - 1.0588004E-02 - - 1.1123575E-02 - - 1.1768480E-02 - - 1.2510924E-02 - - 1.3377043E-02 - - 1.4514862E-02 - - 1.5985046E-02 - - 1.7920853E-02 - - 2.0545741E-02 - - - - 8.4881904E-03 - - 8.0008968E-03 - - 7.5800933E-03 - - 7.3219921E-03 - - 7.0930406E-03 - - 6.9243759E-03 - - 6.8395166E-03 - - 6.7595356E-03 - - 6.7209304E-03 - - 6.7524289E-03 - - 6.7924495E-03 - - 6.8886916E-03 - - 7.0061035E-03 - - 7.1949742E-03 - - 7.3557793E-03 - - 7.6015942E-03 - - 7.8273839E-03 - - 8.1635087E-03 - - 8.4872268E-03 - - 8.8563257E-03 - - 9.1982925E-03 - - 9.6315629E-03 - - 1.0058991E-02 - - 1.0542942E-02 - - 1.1120245E-02 - - 1.1716127E-02 - - 1.2496242E-02 - - 1.3357995E-02 - - 1.4520670E-02 - - 1.5968277E-02 - - 1.7999571E-02 - - 2.0619911E-02 - - - - 8.4547550E-03 - - 7.9415583E-03 - - 7.5504996E-03 - - 7.2492760E-03 - - 7.0388623E-03 - - 6.9114334E-03 - - 6.7880701E-03 - - 6.7298137E-03 - - 6.6707776E-03 - - 6.6865113E-03 - - 6.7469676E-03 - - 6.8440431E-03 - - 6.9530093E-03 - - 7.1334872E-03 - - 7.3320937E-03 - - 7.5447909E-03 - - 7.7926035E-03 - - 8.1024597E-03 - - 8.4776176E-03 - - 8.7989469E-03 - - 9.1860513E-03 - - 9.6106103E-03 - - 1.0035921E-02 - - 1.0516926E-02 - - 1.1111883E-02 - - 1.1693054E-02 - - 1.2421315E-02 - - 1.3359879E-02 - - 1.4448956E-02 - - 1.5939312E-02 - - 1.7946680E-02 - - 2.0638422E-02 - - - - 8.4199682E-03 - - 7.9132357E-03 - - 7.5289024E-03 - - 7.2000914E-03 - - 6.9952420E-03 - - 6.8508371E-03 - - 6.7532303E-03 - - 6.6833325E-03 - - 6.6177839E-03 - - 6.6622382E-03 - - 6.7105208E-03 - - 6.7909136E-03 - - 6.9136513E-03 - - 7.0763901E-03 - - 7.2891302E-03 - - 7.5133811E-03 - - 7.7798727E-03 - - 8.0728234E-03 - - 8.3719982E-03 - - 8.7418259E-03 - - 9.0827206E-03 - - 9.5593221E-03 - - 9.9725625E-03 - - 1.0449294E-02 - - 1.0985324E-02 - - 1.1627712E-02 - - 1.2345830E-02 - - 1.3279892E-02 - - 1.4416720E-02 - - 1.5897541E-02 - - 1.7949472E-02 - - 2.0670535E-02 - - - - 8.3808798E-03 - - 7.8549469E-03 - - 7.4548947E-03 - - 7.1338816E-03 - - 6.9441484E-03 - - 6.7971643E-03 - - 6.6772004E-03 - - 6.6034372E-03 - - 6.5689962E-03 - - 6.6291014E-03 - - 6.6629260E-03 - - 6.7229080E-03 - - 6.8650107E-03 - - 7.0400011E-03 - - 7.2281319E-03 - - 7.4627838E-03 - - 7.7395439E-03 - - 8.0343750E-03 - - 8.3395359E-03 - - 8.6563579E-03 - - 9.0736921E-03 - - 9.4975103E-03 - - 9.9294641E-03 - - 1.0370071E-02 - - 1.0916688E-02 - - 1.1554450E-02 - - 1.2270239E-02 - - 1.3181629E-02 - - 1.4291357E-02 - - 1.5819158E-02 - - 1.7859062E-02 - - 2.0611377E-02 - - - - 8.3161285E-03 - - 7.8077760E-03 - - 7.3959293E-03 - - 7.1090603E-03 - - 6.8980291E-03 - - 6.7587447E-03 - - 6.6504860E-03 - - 6.5749792E-03 - - 6.5613818E-03 - - 6.5416597E-03 - - 6.6015118E-03 - - 6.7070747E-03 - - 6.8290963E-03 - - 7.0031900E-03 - - 7.1846853E-03 - - 7.4125063E-03 - - 7.6750420E-03 - - 7.9813021E-03 - - 8.2806571E-03 - - 8.6141119E-03 - - 8.9704813E-03 - - 9.3882871E-03 - - 9.8368112E-03 - - 1.0298412E-02 - - 1.0822136E-02 - - 1.1413491E-02 - - 1.2145337E-02 - - 1.3048321E-02 - - 1.4114237E-02 - - 1.5706737E-02 - - 1.7654188E-02 - - 2.0500295E-02 - - - - 8.3192873E-03 - - 7.7697531E-03 - - 7.3819594E-03 - - 7.0971817E-03 - - 6.8836908E-03 - - 6.7313952E-03 - - 6.6234836E-03 - - 6.5684539E-03 - - 6.5572540E-03 - - 6.5781759E-03 - - 6.6163018E-03 - - 6.6999200E-03 - - 6.8297696E-03 - - 6.9564324E-03 - - 7.1572917E-03 - - 7.4359960E-03 - - 7.6444528E-03 - - 7.9171531E-03 - - 8.2232683E-03 - - 8.5632604E-03 - - 8.9017284E-03 - - 9.3233527E-03 - - 9.7185361E-03 - - 1.0167756E-02 - - 1.0690318E-02 - - 1.1287654E-02 - - 1.1955699E-02 - - 1.2797701E-02 - - 1.3915636E-02 - - 1.5417831E-02 - - 1.7413631E-02 - - 2.0132344E-02 - - - - 8.3402366E-03 - - 7.8783074E-03 - - 7.5306252E-03 - - 7.2763123E-03 - - 7.0815582E-03 - - 6.9389151E-03 - - 6.8574149E-03 - - 6.7982581E-03 - - 6.7740232E-03 - - 6.7825822E-03 - - 6.8155653E-03 - - 6.8794036E-03 - - 7.0109342E-03 - - 7.1732489E-03 - - 7.3504593E-03 - - 7.5193707E-03 - - 7.7780813E-03 - - 8.0399365E-03 - - 8.3133536E-03 - - 8.6051891E-03 - - 8.9148994E-03 - - 9.3197524E-03 - - 9.7034206E-03 - - 1.0115863E-02 - - 1.0600845E-02 - - 1.1142903E-02 - - 1.1780624E-02 - - 1.2556047E-02 - - 1.3579729E-02 - - 1.4891180E-02 - - 1.6672103E-02 - - 1.9078712E-02 - - - - 8.8088395E-03 - - 8.4507679E-03 - - 8.1708811E-03 - - 7.9801672E-03 - - 7.8027326E-03 - - 7.7405325E-03 - - 7.6178992E-03 - - 7.5796349E-03 - - 7.5729815E-03 - - 7.5709385E-03 - - 7.6313441E-03 - - 7.6551420E-03 - - 7.7197992E-03 - - 7.8770525E-03 - - 7.9879526E-03 - - 8.1371998E-03 - - 8.3342910E-03 - - 8.5247565E-03 - - 8.7962504E-03 - - 9.0806648E-03 - - 9.3313150E-03 - - 9.6858805E-03 - - 1.0017311E-02 - - 1.0396502E-02 - - 1.0810783E-02 - - 1.1308495E-02 - - 1.1873348E-02 - - 1.2517849E-02 - - 1.3292300E-02 - - 1.4204872E-02 - - 1.5413040E-02 - - 1.6865149E-02 - - - - 9.0402122E-03 - - 8.7656934E-03 - - 8.5418137E-03 - - 8.3375574E-03 - - 8.2205328E-03 - - 8.0954859E-03 - - 8.0140696E-03 - - 7.9720195E-03 - - 7.9707073E-03 - - 7.9496524E-03 - - 7.9729738E-03 - - 8.0286530E-03 - - 8.0949490E-03 - - 8.2040408E-03 - - 8.3348436E-03 - - 8.4638271E-03 - - 8.5967473E-03 - - 8.8120082E-03 - - 9.0406595E-03 - - 9.2571730E-03 - - 9.4741636E-03 - - 9.7864082E-03 - - 1.0105154E-02 - - 1.0426882E-02 - - 1.0815324E-02 - - 1.1263114E-02 - - 1.1718090E-02 - - 1.2294266E-02 - - 1.2954841E-02 - - 1.3732023E-02 - - 1.4787929E-02 - - 1.6057604E-02 - - - - 9.1615425E-03 - - 8.8847745E-03 - - 8.6630839E-03 - - 8.4765570E-03 - - 8.3309009E-03 - - 8.2383585E-03 - - 8.1836800E-03 - - 8.1120640E-03 - - 8.1261785E-03 - - 8.0708249E-03 - - 8.1480561E-03 - - 8.1784637E-03 - - 8.2346151E-03 - - 8.3274337E-03 - - 8.4147598E-03 - - 8.5448285E-03 - - 8.7091710E-03 - - 8.8843142E-03 - - 9.0949279E-03 - - 9.2936363E-03 - - 9.5389840E-03 - - 9.7958383E-03 - - 1.0086138E-02 - - 1.0400309E-02 - - 1.0727798E-02 - - 1.1115580E-02 - - 1.1556966E-02 - - 1.2062390E-02 - - 1.2723933E-02 - - 1.3461879E-02 - - 1.4407800E-02 - - 1.5727050E-02 - - - - 9.1377654E-03 - - 8.8751018E-03 - - 8.6821226E-03 - - 8.4858221E-03 - - 8.3554460E-03 - - 8.2804350E-03 - - 8.2266991E-03 - - 8.1758459E-03 - - 8.1472390E-03 - - 8.1455783E-03 - - 8.1349878E-03 - - 8.1925776E-03 - - 8.2538648E-03 - - 8.3264317E-03 - - 8.4644531E-03 - - 8.6009391E-03 - - 8.7147401E-03 - - 8.9206598E-03 - - 9.1064325E-03 - - 9.2780740E-03 - - 9.4991589E-03 - - 9.7677443E-03 - - 1.0040842E-02 - - 1.0310399E-02 - - 1.0637483E-02 - - 1.1002699E-02 - - 1.1454957E-02 - - 1.1928711E-02 - - 1.2543618E-02 - - 1.3315003E-02 - - 1.4311921E-02 - - 1.5626273E-02 - - - - 9.1477964E-03 - - 8.8569131E-03 - - 8.6480911E-03 - - 8.4806682E-03 - - 8.3743826E-03 - - 8.2509863E-03 - - 8.2112855E-03 - - 8.1583830E-03 - - 8.1332616E-03 - - 8.1132990E-03 - - 8.1560439E-03 - - 8.1779291E-03 - - 8.2488074E-03 - - 8.3305803E-03 - - 8.4259072E-03 - - 8.5822114E-03 - - 8.7017305E-03 - - 8.8788944E-03 - - 9.0655429E-03 - - 9.2582475E-03 - - 9.4805275E-03 - - 9.7278007E-03 - - 9.9553998E-03 - - 1.0269546E-02 - - 1.0586672E-02 - - 1.0921006E-02 - - 1.1328973E-02 - - 1.1802691E-02 - - 1.2450626E-02 - - 1.3255698E-02 - - 1.4251456E-02 - - 1.5657809E-02 - - - - 9.0883340E-03 - - 8.8433984E-03 - - 8.6289182E-03 - - 8.4439323E-03 - - 8.3093188E-03 - - 8.2332632E-03 - - 8.1799745E-03 - - 8.1280446E-03 - - 8.0845653E-03 - - 8.1128997E-03 - - 8.1014997E-03 - - 8.1603558E-03 - - 8.2532133E-03 - - 8.3021938E-03 - - 8.4337253E-03 - - 8.5567067E-03 - - 8.6772027E-03 - - 8.8890649E-03 - - 9.0381936E-03 - - 9.2474046E-03 - - 9.4507499E-03 - - 9.7047326E-03 - - 9.9402566E-03 - - 1.0205441E-02 - - 1.0504990E-02 - - 1.0882385E-02 - - 1.1274627E-02 - - 1.1783289E-02 - - 1.2386232E-02 - - 1.3164784E-02 - - 1.4270026E-02 - - 1.5728107E-02 - - - - 9.0807708E-03 - - 8.8015024E-03 - - 8.5814276E-03 - - 8.4248165E-03 - - 8.2946254E-03 - - 8.2126919E-03 - - 8.1370075E-03 - - 8.0715301E-03 - - 8.0815288E-03 - - 8.0835771E-03 - - 8.1054492E-03 - - 8.1477700E-03 - - 8.2076231E-03 - - 8.2545960E-03 - - 8.4024583E-03 - - 8.5599026E-03 - - 8.6575633E-03 - - 8.8233051E-03 - - 9.0064404E-03 - - 9.2354725E-03 - - 9.4557209E-03 - - 9.6788857E-03 - - 9.8947250E-03 - - 1.0174410E-02 - - 1.0498117E-02 - - 1.0823664E-02 - - 1.1218924E-02 - - 1.1737640E-02 - - 1.2318916E-02 - - 1.3224386E-02 - - 1.4293237E-02 - - 1.5742419E-02 - - - - 9.0662532E-03 - - 8.7875937E-03 - - 8.5608939E-03 - - 8.3990606E-03 - - 8.2689578E-03 - - 8.1502455E-03 - - 8.0945876E-03 - - 8.0499873E-03 - - 8.0046473E-03 - - 8.0312744E-03 - - 8.0845285E-03 - - 8.0864516E-03 - - 8.1794243E-03 - - 8.2886692E-03 - - 8.3753921E-03 - - 8.5095259E-03 - - 8.6235784E-03 - - 8.8149234E-03 - - 9.0064533E-03 - - 9.1933604E-03 - - 9.4366281E-03 - - 9.6340012E-03 - - 9.8577424E-03 - - 1.0162178E-02 - - 1.0489950E-02 - - 1.0830480E-02 - - 1.1216758E-02 - - 1.1718234E-02 - - 1.2372964E-02 - - 1.3217004E-02 - - 1.4300060E-02 - - 1.5874384E-02 - - - - 9.0385593E-03 - - 8.7911739E-03 - - 8.5398942E-03 - - 8.3506015E-03 - - 8.2438909E-03 - - 8.1613890E-03 - - 8.0460870E-03 - - 8.0305903E-03 - - 8.0028889E-03 - - 8.0232434E-03 - - 8.0276194E-03 - - 8.1064278E-03 - - 8.1288298E-03 - - 8.2312446E-03 - - 8.3452218E-03 - - 8.4759402E-03 - - 8.6203085E-03 - - 8.7737100E-03 - - 8.9852040E-03 - - 9.1640184E-03 - - 9.3706145E-03 - - 9.6371098E-03 - - 9.8385671E-03 - - 1.0187163E-02 - - 1.0453859E-02 - - 1.0791575E-02 - - 1.1239213E-02 - - 1.1704998E-02 - - 1.2413952E-02 - - 1.3197580E-02 - - 1.4388298E-02 - - 1.5983777E-02 - - - - 9.0381972E-03 - - 8.7249421E-03 - - 8.5299403E-03 - - 8.3296610E-03 - - 8.1906552E-03 - - 8.0856852E-03 - - 8.0084895E-03 - - 7.9976213E-03 - - 7.9681027E-03 - - 7.9954298E-03 - - 8.0300023E-03 - - 8.0899341E-03 - - 8.1518784E-03 - - 8.2341280E-03 - - 8.3101161E-03 - - 8.4644180E-03 - - 8.6281121E-03 - - 8.7991411E-03 - - 8.9588100E-03 - - 9.1981791E-03 - - 9.3869641E-03 - - 9.6145258E-03 - - 9.9132005E-03 - - 1.0156461E-02 - - 1.0475933E-02 - - 1.0810611E-02 - - 1.1229999E-02 - - 1.1691965E-02 - - 1.2394061E-02 - - 1.3229214E-02 - - 1.4413895E-02 - - 1.6023151E-02 - - - - 8.9900779E-03 - - 8.7242101E-03 - - 8.4738461E-03 - - 8.3135886E-03 - - 8.1704723E-03 - - 8.0916227E-03 - - 8.0054050E-03 - - 7.9890825E-03 - - 7.9822260E-03 - - 7.9494275E-03 - - 8.0343148E-03 - - 8.0498187E-03 - - 8.1090198E-03 - - 8.2328458E-03 - - 8.3082672E-03 - - 8.4585469E-03 - - 8.6087756E-03 - - 8.8041342E-03 - - 8.9504229E-03 - - 9.1682953E-03 - - 9.3389911E-03 - - 9.6352014E-03 - - 9.8666333E-03 - - 1.0149489E-02 - - 1.0464017E-02 - - 1.0804437E-02 - - 1.1200629E-02 - - 1.1730829E-02 - - 1.2396625E-02 - - 1.3311556E-02 - - 1.4467897E-02 - - 1.6069551E-02 - - - - 9.0103050E-03 - - 8.7325667E-03 - - 8.5095225E-03 - - 8.3198922E-03 - - 8.1828827E-03 - - 8.0755069E-03 - - 7.9981914E-03 - - 7.9413633E-03 - - 7.9823990E-03 - - 7.9246563E-03 - - 7.9815454E-03 - - 8.0345931E-03 - - 8.0725191E-03 - - 8.2341012E-03 - - 8.3041608E-03 - - 8.3831836E-03 - - 8.6106789E-03 - - 8.7518346E-03 - - 8.9641474E-03 - - 9.0978032E-03 - - 9.3592003E-03 - - 9.5996223E-03 - - 9.9237621E-03 - - 1.0175830E-02 - - 1.0455459E-02 - - 1.0836548E-02 - - 1.1244650E-02 - - 1.1760188E-02 - - 1.2384627E-02 - - 1.3346254E-02 - - 1.4480133E-02 - - 1.6136563E-02 - - - - 9.0228604E-03 - - 8.6804828E-03 - - 8.4614534E-03 - - 8.2426545E-03 - - 8.1392111E-03 - - 8.0814949E-03 - - 7.9912702E-03 - - 7.9974952E-03 - - 7.9421615E-03 - - 7.9138029E-03 - - 7.9451587E-03 - - 8.0340001E-03 - - 8.0954821E-03 - - 8.1764077E-03 - - 8.3095930E-03 - - 8.4157262E-03 - - 8.6168490E-03 - - 8.7576427E-03 - - 8.9333274E-03 - - 9.1895534E-03 - - 9.3857577E-03 - - 9.6418300E-03 - - 9.8564788E-03 - - 1.0150132E-02 - - 1.0487898E-02 - - 1.0870470E-02 - - 1.1271947E-02 - - 1.1778020E-02 - - 1.2502739E-02 - - 1.3339816E-02 - - 1.4543555E-02 - - 1.6130789E-02 - - - - 9.0622003E-03 - - 8.7178702E-03 - - 8.4596226E-03 - - 8.2747360E-03 - - 8.1644825E-03 - - 8.0165944E-03 - - 7.9932716E-03 - - 7.9360246E-03 - - 7.9425974E-03 - - 7.9418553E-03 - - 7.9541528E-03 - - 8.0182907E-03 - - 8.0812624E-03 - - 8.0915456E-03 - - 8.2908500E-03 - - 8.4101146E-03 - - 8.5246086E-03 - - 8.7454336E-03 - - 8.9623361E-03 - - 9.1273983E-03 - - 9.3738784E-03 - - 9.6552369E-03 - - 9.8941901E-03 - - 1.0161555E-02 - - 1.0501008E-02 - - 1.0866011E-02 - - 1.1314128E-02 - - 1.1790338E-02 - - 1.2447300E-02 - - 1.3396964E-02 - - 1.4531939E-02 - - 1.6115773E-02 - - - - 8.9679455E-03 - - 8.7523346E-03 - - 8.4194831E-03 - - 8.2562897E-03 - - 8.2501744E-03 - - 8.0453964E-03 - - 7.9636250E-03 - - 7.9278064E-03 - - 7.9395130E-03 - - 7.8808053E-03 - - 7.8942591E-03 - - 7.9779525E-03 - - 8.1203535E-03 - - 8.1780129E-03 - - 8.2976996E-03 - - 8.3927501E-03 - - 8.5693973E-03 - - 8.7760972E-03 - - 8.9639268E-03 - - 9.1777904E-03 - - 9.3233365E-03 - - 9.6757573E-03 - - 9.8043550E-03 - - 1.0142972E-02 - - 1.0460099E-02 - - 1.0900581E-02 - - 1.1166513E-02 - - 1.1798843E-02 - - 1.2569032E-02 - - 1.3335377E-02 - - 1.4567713E-02 - - 1.6266042E-02 - - - - 9.0235493E-03 - - 8.7359753E-03 - - 8.4400355E-03 - - 8.2314136E-03 - - 8.1409585E-03 - - 8.0562549E-03 - - 8.0165174E-03 - - 7.9631855E-03 - - 7.9527283E-03 - - 7.9590026E-03 - - 7.9558654E-03 - - 7.9982172E-03 - - 7.9903743E-03 - - 8.1472328E-03 - - 8.3527175E-03 - - 8.3019999E-03 - - 8.5775481E-03 - - 8.8353190E-03 - - 8.9853803E-03 - - 9.0836784E-03 - - 9.4481131E-03 - - 9.5401367E-03 - - 9.8920227E-03 - - 1.0186917E-02 - - 1.0500634E-02 - - 1.0833697E-02 - - 1.1379042E-02 - - 1.1793671E-02 - - 1.2553389E-02 - - 1.3369577E-02 - - 1.4595165E-02 - - 1.6031466E-02 - - - 1.0000416E+00 - - - 1.0000513E+00 - - - 1.0000397E+00 - - - 1.0000409E+00 - - - 1.0000455E+00 - - - 1.0000417E+00 - - - 1.0000452E+00 - - - 1.0000431E+00 - - - 1.0000455E+00 - - - 1.0000451E+00 - - - 1.0000445E+00 - - - 1.0000482E+00 - - - 1.0000507E+00 - - - 1.0000542E+00 - - - 1.0000545E+00 - - - 1.0000461E+00 - - - 1.0000114E+00 - - - 1.0000112E+00 - - - 1.0000195E+00 - - - 1.0000216E+00 - - - 1.0000279E+00 - - - 1.0000307E+00 - - - 1.0000302E+00 - - - 1.0000313E+00 - - - 1.0000334E+00 - - - 1.0000309E+00 - - - 1.0000325E+00 - - - 1.0000318E+00 - - - 1.0000346E+00 - - - 1.0000335E+00 - - - 1.0000285E+00 - - - 1.0000358E+00 - - - - - lwtr_ang_mu - lwtr_ang_mu - 2.5300000E-08 - 32 - false - 32 - 1 - angle - histogram - - 8.3129229E-01 - - 8.3203829E-01 - - 8.3332424E-01 - - 8.3539719E-01 - - 8.3799288E-01 - - 8.4156597E-01 - - 8.4594074E-01 - - 8.5122773E-01 - - 8.5788274E-01 - - 8.6633387E-01 - - 8.7719846E-01 - - 8.9195077E-01 - - 9.1326621E-01 - - 9.4469159E-01 - - 9.9368716E-01 - - 1.0616854E+00 - - 1.0982938E+00 - - 1.0997200E+00 - - 1.0855410E+00 - - 1.0676695E+00 - - 1.0508172E+00 - - 1.0369337E+00 - - 1.0255762E+00 - - 1.0162841E+00 - - 1.0086633E+00 - - 1.0025783E+00 - - 9.9737297E-01 - - 9.9326768E-01 - - 9.9030852E-01 - - 9.8792719E-01 - - 9.8610453E-01 - - 9.8540665E-01 - - - 7.7368065E-03 - - 7.7519393E-03 - - 7.7819449E-03 - - 7.8285240E-03 - - 7.8881877E-03 - - 7.9652685E-03 - - 8.0588251E-03 - - 8.1724303E-03 - - 8.3079937E-03 - - 8.4749946E-03 - - 8.6811506E-03 - - 8.9456784E-03 - - 9.3049336E-03 - - 9.8025199E-03 - - 1.0529992E-02 - - 1.1498571E-02 - - 1.2065971E-02 - - 1.2168395E-02 - - 1.2053690E-02 - - 1.1870414E-02 - - 1.1678759E-02 - - 1.1516371E-02 - - 1.1377145E-02 - - 1.1262809E-02 - - 1.1166687E-02 - - 1.1090107E-02 - - 1.1022668E-02 - - 1.0968772E-02 - - 1.0931381E-02 - - 1.0898236E-02 - - 1.0872094E-02 - - 1.0866295E-02 - - - 5.0690953E-03 - - 8.8284325E-03 - - 9.0078067E-03 - - 8.3473577E-03 - - 8.6118779E-03 - - 8.5008333E-03 - - 9.0278160E-03 - - 9.0320024E-03 - - 9.3778370E-03 - - 9.6052477E-03 - - 9.9703821E-03 - - 1.0342612E-02 - - 1.0646441E-02 - - 1.1197549E-02 - - 1.1382812E-02 - - 1.2469275E-02 - - 1.3368771E-02 - - 1.7162734E-02 - - 2.0335842E-02 - - 2.4108518E-02 - - 2.7585384E-02 - - 3.1409361E-02 - - 3.5211839E-02 - - 3.9132244E-02 - - 4.2882641E-02 - - 4.7206070E-02 - - 5.1012876E-02 - - 5.6053305E-02 - - 5.9624825E-02 - - 6.4222850E-02 - - 7.1113785E-02 - - 7.1863425E-02 - - - - 5.0668773E-03 - - 8.8623444E-03 - - 8.9736897E-03 - - 8.4193826E-03 - - 8.6200366E-03 - - 8.5331711E-03 - - 9.0253536E-03 - - 9.0024868E-03 - - 9.3587966E-03 - - 9.6337679E-03 - - 9.9001048E-03 - - 1.0351369E-02 - - 1.0700823E-02 - - 1.1172796E-02 - - 1.1445656E-02 - - 1.2427412E-02 - - 1.3375674E-02 - - 1.7104580E-02 - - 2.0306601E-02 - - 2.4056263E-02 - - 2.7577305E-02 - - 3.1469932E-02 - - 3.5286392E-02 - - 3.9182103E-02 - - 4.2943152E-02 - - 4.7360483E-02 - - 5.1005109E-02 - - 5.6171187E-02 - - 5.9667108E-02 - - 6.4232789E-02 - - 7.1121280E-02 - - 7.1846306E-02 - - - - 5.0585819E-03 - - 8.8480548E-03 - - 9.0578095E-03 - - 8.4267843E-03 - - 8.6269032E-03 - - 8.5421136E-03 - - 9.0526837E-03 - - 9.0736449E-03 - - 9.4245294E-03 - - 9.6888060E-03 - - 9.9567766E-03 - - 1.0375670E-02 - - 1.0725481E-02 - - 1.1243110E-02 - - 1.1484936E-02 - - 1.2521826E-02 - - 1.3438046E-02 - - 1.7151864E-02 - - 2.0343472E-02 - - 2.4110251E-02 - - 2.7659343E-02 - - 3.1511614E-02 - - 3.5309076E-02 - - 3.9196826E-02 - - 4.3043312E-02 - - 4.7345488E-02 - - 5.1124137E-02 - - 5.6080519E-02 - - 5.9764341E-02 - - 6.4292466E-02 - - 7.1165161E-02 - - 7.1900319E-02 - - - - 5.0739533E-03 - - 8.8878014E-03 - - 9.0739746E-03 - - 8.4571184E-03 - - 8.6763187E-03 - - 8.5845734E-03 - - 9.0893274E-03 - - 9.1072493E-03 - - 9.4607350E-03 - - 9.7370233E-03 - - 1.0006337E-02 - - 1.0437546E-02 - - 1.0767301E-02 - - 1.1309766E-02 - - 1.1552543E-02 - - 1.2572863E-02 - - 1.3499221E-02 - - 1.7217227E-02 - - 2.0383163E-02 - - 2.4178222E-02 - - 2.7731888E-02 - - 3.1561770E-02 - - 3.5431417E-02 - - 3.9298803E-02 - - 4.3075219E-02 - - 4.7440921E-02 - - 5.1196928E-02 - - 5.6281715E-02 - - 5.9863517E-02 - - 6.4363763E-02 - - 7.1290039E-02 - - 7.1984722E-02 - - - - 5.0933569E-03 - - 8.9571748E-03 - - 9.1350789E-03 - - 8.5026806E-03 - - 8.7154122E-03 - - 8.6182850E-03 - - 9.1387403E-03 - - 9.1503576E-03 - - 9.5054271E-03 - - 9.8046510E-03 - - 1.0063015E-02 - - 1.0512898E-02 - - 1.0850976E-02 - - 1.1369711E-02 - - 1.1602210E-02 - - 1.2644534E-02 - - 1.3573331E-02 - - 1.7276147E-02 - - 2.0485160E-02 - - 2.4267827E-02 - - 2.7795345E-02 - - 3.1650606E-02 - - 3.5516413E-02 - - 3.9384282E-02 - - 4.3193261E-02 - - 4.7565933E-02 - - 5.1283045E-02 - - 5.6364736E-02 - - 5.9999740E-02 - - 6.4499325E-02 - - 7.1460960E-02 - - 7.2121578E-02 - - - - 5.1073627E-03 - - 9.0205393E-03 - - 9.1796662E-03 - - 8.5645656E-03 - - 8.7990379E-03 - - 8.7021912E-03 - - 9.2162069E-03 - - 9.2138958E-03 - - 9.5751521E-03 - - 9.8799162E-03 - - 1.0149817E-02 - - 1.0595940E-02 - - 1.0925157E-02 - - 1.1451227E-02 - - 1.1697295E-02 - - 1.2747125E-02 - - 1.3679064E-02 - - 1.7388258E-02 - - 2.0589616E-02 - - 2.4369432E-02 - - 2.7920510E-02 - - 3.1792267E-02 - - 3.5621878E-02 - - 3.9491661E-02 - - 4.3278532E-02 - - 4.7679951E-02 - - 5.1436615E-02 - - 5.6547886E-02 - - 6.0145268E-02 - - 6.4662138E-02 - - 7.1681806E-02 - - 7.2326892E-02 - - - - 5.1442091E-03 - - 9.0852521E-03 - - 9.2735609E-03 - - 8.6388628E-03 - - 8.8708740E-03 - - 8.7690933E-03 - - 9.2934119E-03 - - 9.3186161E-03 - - 9.6592707E-03 - - 9.9678700E-03 - - 1.0236163E-02 - - 1.0694734E-02 - - 1.1025890E-02 - - 1.1566030E-02 - - 1.1820104E-02 - - 1.2881706E-02 - - 1.3817409E-02 - - 1.7525018E-02 - - 2.0707299E-02 - - 2.4504049E-02 - - 2.8056398E-02 - - 3.1942086E-02 - - 3.5781215E-02 - - 3.9676732E-02 - - 4.3508487E-02 - - 4.7899374E-02 - - 5.1653601E-02 - - 5.6724194E-02 - - 6.0363176E-02 - - 6.4884496E-02 - - 7.1995314E-02 - - 7.2586420E-02 - - - - 5.1859947E-03 - - 9.1884111E-03 - - 9.3553722E-03 - - 8.7326674E-03 - - 8.9615831E-03 - - 8.8682756E-03 - - 9.3981872E-03 - - 9.4022342E-03 - - 9.7833217E-03 - - 1.0082626E-02 - - 1.0346345E-02 - - 1.0823172E-02 - - 1.1169852E-02 - - 1.1713674E-02 - - 1.1957780E-02 - - 1.3030310E-02 - - 1.3974055E-02 - - 1.7679518E-02 - - 2.0873339E-02 - - 2.4674002E-02 - - 2.8233633E-02 - - 3.2098518E-02 - - 3.5967409E-02 - - 3.9901149E-02 - - 4.3708564E-02 - - 4.8163155E-02 - - 5.1864987E-02 - - 5.6965609E-02 - - 6.0598955E-02 - - 6.5237827E-02 - - 7.2317026E-02 - - 7.2846315E-02 - - - - 5.2179276E-03 - - 9.2840460E-03 - - 9.4689692E-03 - - 8.8426310E-03 - - 9.0784020E-03 - - 8.9710561E-03 - - 9.5058449E-03 - - 9.5242525E-03 - - 9.8985438E-03 - - 1.0230104E-02 - - 1.0489612E-02 - - 1.0966586E-02 - - 1.1313882E-02 - - 1.1867051E-02 - - 1.2127596E-02 - - 1.3217267E-02 - - 1.4158489E-02 - - 1.7874095E-02 - - 2.1071639E-02 - - 2.4904630E-02 - - 2.8444961E-02 - - 3.2350782E-02 - - 3.6218293E-02 - - 4.0127228E-02 - - 4.3958446E-02 - - 4.8412743E-02 - - 5.2176893E-02 - - 5.7339635E-02 - - 6.0969984E-02 - - 6.5571180E-02 - - 7.2752295E-02 - - 7.3254466E-02 - - - - 5.2716442E-03 - - 9.4281164E-03 - - 9.6132026E-03 - - 8.9742401E-03 - - 9.2100433E-03 - - 9.1094424E-03 - - 9.6671272E-03 - - 9.6893875E-03 - - 1.0054424E-02 - - 1.0384782E-02 - - 1.0663088E-02 - - 1.1145331E-02 - - 1.1502660E-02 - - 1.2069220E-02 - - 1.2330654E-02 - - 1.3451168E-02 - - 1.4376732E-02 - - 1.8119744E-02 - - 2.1312268E-02 - - 2.5156150E-02 - - 2.8702855E-02 - - 3.2612605E-02 - - 3.6519082E-02 - - 4.0492357E-02 - - 4.4282144E-02 - - 4.8807320E-02 - - 5.2599863E-02 - - 5.7759050E-02 - - 6.1395630E-02 - - 6.6046712E-02 - - 7.3333461E-02 - - 7.3753560E-02 - - - - 5.3238344E-03 - - 9.5970913E-03 - - 9.7854600E-03 - - 9.1224140E-03 - - 9.3984166E-03 - - 9.2843910E-03 - - 9.8479041E-03 - - 9.8775712E-03 - - 1.0248815E-02 - - 1.0588076E-02 - - 1.0866467E-02 - - 1.1377201E-02 - - 1.1745016E-02 - - 1.2324752E-02 - - 1.2591933E-02 - - 1.3738942E-02 - - 1.4661945E-02 - - 1.8420789E-02 - - 2.1616210E-02 - - 2.5483933E-02 - - 2.9053296E-02 - - 3.3018657E-02 - - 3.6902567E-02 - - 4.0918920E-02 - - 4.4768920E-02 - - 4.9324206E-02 - - 5.3104469E-02 - - 5.8346792E-02 - - 6.2007342E-02 - - 6.6700912E-02 - - 7.4111114E-02 - - 7.4471661E-02 - - - - 5.4122500E-03 - - 9.8114809E-03 - - 9.9988824E-03 - - 9.3373137E-03 - - 9.6193550E-03 - - 9.5022652E-03 - - 1.0091629E-02 - - 1.0102292E-02 - - 1.0507181E-02 - - 1.0845994E-02 - - 1.1145961E-02 - - 1.1663724E-02 - - 1.2054675E-02 - - 1.2641320E-02 - - 1.2925378E-02 - - 1.4109631E-02 - - 1.5019788E-02 - - 1.8801255E-02 - - 2.2007215E-02 - - 2.5928762E-02 - - 2.9530128E-02 - - 3.3525210E-02 - - 3.7488914E-02 - - 4.1518826E-02 - - 4.5409731E-02 - - 5.0007891E-02 - - 5.3821041E-02 - - 5.9155539E-02 - - 6.2863258E-02 - - 6.7589912E-02 - - 7.5149452E-02 - - 7.5483624E-02 - - - - 5.5291381E-03 - - 1.0106920E-02 - - 1.0289680E-02 - - 9.6380580E-03 - - 9.9265277E-03 - - 9.8058620E-03 - - 1.0411771E-02 - - 1.0436031E-02 - - 1.0855919E-02 - - 1.1210324E-02 - - 1.1523264E-02 - - 1.2064653E-02 - - 1.2477020E-02 - - 1.3073068E-02 - - 1.3372106E-02 - - 1.4596687E-02 - - 1.5522669E-02 - - 1.9346144E-02 - - 2.2590235E-02 - - 2.6577078E-02 - - 3.0198519E-02 - - 3.4263702E-02 - - 3.8312940E-02 - - 4.2417033E-02 - - 4.6331184E-02 - - 5.1039786E-02 - - 5.4923952E-02 - - 6.0373272E-02 - - 6.4126997E-02 - - 6.8933518E-02 - - 7.6721947E-02 - - 7.6881324E-02 - - - - 5.7051926E-03 - - 1.0534340E-02 - - 1.0734999E-02 - - 1.0047973E-02 - - 1.0355258E-02 - - 1.0218464E-02 - - 1.0877782E-02 - - 1.0922582E-02 - - 1.1349348E-02 - - 1.1717445E-02 - - 1.2048634E-02 - - 1.2622834E-02 - - 1.3044209E-02 - - 1.3697572E-02 - - 1.4007429E-02 - - 1.5297796E-02 - - 1.6229092E-02 - - 2.0130646E-02 - - 2.3419720E-02 - - 2.7507372E-02 - - 3.1241243E-02 - - 3.5411821E-02 - - 3.9541855E-02 - - 4.3748213E-02 - - 4.7789294E-02 - - 5.2605069E-02 - - 5.6580575E-02 - - 6.2218120E-02 - - 6.6002923E-02 - - 7.0996802E-02 - - 7.9059610E-02 - - 7.9125302E-02 - - - - 5.9798621E-03 - - 1.1178770E-02 - - 1.1398960E-02 - - 1.0686315E-02 - - 1.1015007E-02 - - 1.0888426E-02 - - 1.1578312E-02 - - 1.1599595E-02 - - 1.2096215E-02 - - 1.2485774E-02 - - 1.2847301E-02 - - 1.3454293E-02 - - 1.3910042E-02 - - 1.4624946E-02 - - 1.4951480E-02 - - 1.6345303E-02 - - 1.7294576E-02 - - 2.1305917E-02 - - 2.4724135E-02 - - 2.8975117E-02 - - 3.2851405E-02 - - 3.7179235E-02 - - 4.1473071E-02 - - 4.5870569E-02 - - 5.0061541E-02 - - 5.5118747E-02 - - 5.9217709E-02 - - 6.5121185E-02 - - 6.9056004E-02 - - 7.4268036E-02 - - 8.2796332E-02 - - 8.2707329E-02 - - - - 6.3814382E-03 - - 1.2092503E-02 - - 1.2307256E-02 - - 1.1538828E-02 - - 1.1908080E-02 - - 1.1757836E-02 - - 1.2534374E-02 - - 1.2563508E-02 - - 1.3099926E-02 - - 1.3526120E-02 - - 1.3927022E-02 - - 1.4604411E-02 - - 1.5096848E-02 - - 1.5885767E-02 - - 1.6230507E-02 - - 1.7756050E-02 - - 1.8747181E-02 - - 2.2956423E-02 - - 2.6549953E-02 - - 3.1007445E-02 - - 3.5079178E-02 - - 3.9663485E-02 - - 4.4205438E-02 - - 4.8827182E-02 - - 5.3252335E-02 - - 5.8585422E-02 - - 6.2916830E-02 - - 6.9202743E-02 - - 7.3345048E-02 - - 7.8865458E-02 - - 8.8060504E-02 - - 8.7720181E-02 - - - - 6.5814203E-03 - - 1.2589556E-02 - - 1.2831098E-02 - - 1.2021990E-02 - - 1.2420962E-02 - - 1.2274328E-02 - - 1.3072229E-02 - - 1.3125790E-02 - - 1.3684984E-02 - - 1.4120320E-02 - - 1.4541810E-02 - - 1.5241834E-02 - - 1.5792664E-02 - - 1.6581300E-02 - - 1.6973815E-02 - - 1.8580511E-02 - - 1.9572617E-02 - - 2.3865583E-02 - - 2.7520381E-02 - - 3.2101383E-02 - - 3.6273771E-02 - - 4.0991031E-02 - - 4.5628107E-02 - - 5.0375712E-02 - - 5.4927552E-02 - - 6.0463390E-02 - - 6.4846891E-02 - - 7.1361573E-02 - - 7.5574981E-02 - - 8.1252683E-02 - - 9.0772914E-02 - - 9.0305344E-02 - - - - 6.5954047E-03 - - 1.2649872E-02 - - 1.2894758E-02 - - 1.2088299E-02 - - 1.2500706E-02 - - 1.2323868E-02 - - 1.3135140E-02 - - 1.3183877E-02 - - 1.3757540E-02 - - 1.4215358E-02 - - 1.4630076E-02 - - 1.5341576E-02 - - 1.5875377E-02 - - 1.6697400E-02 - - 1.7075964E-02 - - 1.8685615E-02 - - 1.9688554E-02 - - 2.3959638E-02 - - 2.7582865E-02 - - 3.2154359E-02 - - 3.6319478E-02 - - 4.0991674E-02 - - 4.5627244E-02 - - 5.0390376E-02 - - 5.4901681E-02 - - 6.0435636E-02 - - 6.4805706E-02 - - 7.1338882E-02 - - 7.5494665E-02 - - 8.1186566E-02 - - 9.0719563E-02 - - 9.0193680E-02 - - - - 6.5336047E-03 - - 1.2512090E-02 - - 1.2764479E-02 - - 1.1984145E-02 - - 1.2375802E-02 - - 1.2210337E-02 - - 1.3005945E-02 - - 1.3053548E-02 - - 1.3626485E-02 - - 1.4068961E-02 - - 1.4494598E-02 - - 1.5200428E-02 - - 1.5722617E-02 - - 1.6508783E-02 - - 1.6910525E-02 - - 1.8489314E-02 - - 1.9473998E-02 - - 2.3688731E-02 - - 2.7256893E-02 - - 3.1731269E-02 - - 3.5822276E-02 - - 4.0457390E-02 - - 4.5020879E-02 - - 4.9721896E-02 - - 5.4161674E-02 - - 5.9588663E-02 - - 6.3895979E-02 - - 7.0351683E-02 - - 7.4478980E-02 - - 8.0093110E-02 - - 8.9495166E-02 - - 8.8945256E-02 - - - - 6.4468824E-03 - - 1.2344191E-02 - - 1.2577769E-02 - - 1.1799198E-02 - - 1.2185250E-02 - - 1.2024671E-02 - - 1.2823561E-02 - - 1.2867050E-02 - - 1.3414223E-02 - - 1.3868383E-02 - - 1.4274902E-02 - - 1.4957665E-02 - - 1.5477639E-02 - - 1.6280478E-02 - - 1.6660201E-02 - - 1.8210099E-02 - - 1.9176459E-02 - - 2.3317865E-02 - - 2.6814611E-02 - - 3.1226187E-02 - - 3.5261695E-02 - - 3.9778054E-02 - - 4.4282066E-02 - - 4.8849080E-02 - - 5.3188035E-02 - - 5.8562223E-02 - - 6.2824222E-02 - - 6.9127893E-02 - - 7.3188187E-02 - - 7.8690046E-02 - - 8.7933862E-02 - - 8.7463314E-02 - - - - 6.3504172E-03 - - 1.2150642E-02 - - 1.2387727E-02 - - 1.1620660E-02 - - 1.2007755E-02 - - 1.1841239E-02 - - 1.2616226E-02 - - 1.2659354E-02 - - 1.3210608E-02 - - 1.3647237E-02 - - 1.4056090E-02 - - 1.4738601E-02 - - 1.5248667E-02 - - 1.6022604E-02 - - 1.6399027E-02 - - 1.7924821E-02 - - 1.8865800E-02 - - 2.2962104E-02 - - 2.6396869E-02 - - 3.0722714E-02 - - 3.4680261E-02 - - 3.9148700E-02 - - 4.3549586E-02 - - 4.8057389E-02 - - 5.2369847E-02 - - 5.7634643E-02 - - 6.1797568E-02 - - 6.8018235E-02 - - 7.1991375E-02 - - 7.7432633E-02 - - 8.6562066E-02 - - 8.6040544E-02 - - - - 6.2807225E-03 - - 1.2005102E-02 - - 1.2236833E-02 - - 1.1484849E-02 - - 1.1844265E-02 - - 1.1694745E-02 - - 1.2469442E-02 - - 1.2503258E-02 - - 1.3035750E-02 - - 1.3456731E-02 - - 1.3869786E-02 - - 1.4538788E-02 - - 1.5043345E-02 - - 1.5804904E-02 - - 1.6173155E-02 - - 1.7678967E-02 - - 1.8617817E-02 - - 2.2640680E-02 - - 2.6043512E-02 - - 3.0350793E-02 - - 3.4235767E-02 - - 3.8635112E-02 - - 4.3006209E-02 - - 4.7438737E-02 - - 5.1680206E-02 - - 5.6869882E-02 - - 6.0948428E-02 - - 6.7112720E-02 - - 7.1046470E-02 - - 7.6389984E-02 - - 8.5416908E-02 - - 8.4912400E-02 - - - - 6.2384011E-03 - - 1.1883626E-02 - - 1.2102819E-02 - - 1.1362792E-02 - - 1.1727085E-02 - - 1.1577991E-02 - - 1.2321572E-02 - - 1.2368887E-02 - - 1.2886627E-02 - - 1.3323476E-02 - - 1.3712662E-02 - - 1.4368905E-02 - - 1.4867001E-02 - - 1.5621404E-02 - - 1.6001770E-02 - - 1.7495457E-02 - - 1.8410484E-02 - - 2.2403739E-02 - - 2.5792442E-02 - - 3.0003874E-02 - - 3.3860219E-02 - - 3.8194472E-02 - - 4.2513447E-02 - - 4.6944801E-02 - - 5.1102508E-02 - - 5.6230364E-02 - - 6.0282905E-02 - - 6.6396185E-02 - - 7.0267237E-02 - - 7.5567209E-02 - - 8.4430462E-02 - - 8.3984117E-02 - - - - 6.1845926E-03 - - 1.1774745E-02 - - 1.2008907E-02 - - 1.1282463E-02 - - 1.1630642E-02 - - 1.1486008E-02 - - 1.2212483E-02 - - 1.2255192E-02 - - 1.2777462E-02 - - 1.3204562E-02 - - 1.3600398E-02 - - 1.4255316E-02 - - 1.4736561E-02 - - 1.5470029E-02 - - 1.5845176E-02 - - 1.7313807E-02 - - 1.8247178E-02 - - 2.2230316E-02 - - 2.5531152E-02 - - 2.9731972E-02 - - 3.3558284E-02 - - 3.7872884E-02 - - 4.2109048E-02 - - 4.6517240E-02 - - 5.0645413E-02 - - 5.5683251E-02 - - 5.9750465E-02 - - 6.5766931E-02 - - 6.9579667E-02 - - 7.4872290E-02 - - 8.3643239E-02 - - 8.3206968E-02 - - - - 6.1719734E-03 - - 1.1719545E-02 - - 1.1917909E-02 - - 1.1189341E-02 - - 1.1548606E-02 - - 1.1416064E-02 - - 1.2129643E-02 - - 1.2168083E-02 - - 1.2694983E-02 - - 1.3100793E-02 - - 1.3481593E-02 - - 1.4146417E-02 - - 1.4630389E-02 - - 1.5367839E-02 - - 1.5730917E-02 - - 1.7184516E-02 - - 1.8089440E-02 - - 2.2023196E-02 - - 2.5336832E-02 - - 2.9501303E-02 - - 3.3286048E-02 - - 3.7579302E-02 - - 4.1818920E-02 - - 4.6160226E-02 - - 5.0276169E-02 - - 5.5322377E-02 - - 5.9292479E-02 - - 6.5292838E-02 - - 6.9134443E-02 - - 7.4296625E-02 - - 8.3006295E-02 - - 8.2573545E-02 - - - - 6.1382782E-03 - - 1.1652027E-02 - - 1.1858603E-02 - - 1.1149474E-02 - - 1.1500153E-02 - - 1.1352538E-02 - - 1.2052433E-02 - - 1.2104328E-02 - - 1.2615826E-02 - - 1.3028027E-02 - - 1.3393814E-02 - - 1.4056119E-02 - - 1.4520800E-02 - - 1.5244525E-02 - - 1.5619872E-02 - - 1.7065448E-02 - - 1.7976677E-02 - - 2.1928655E-02 - - 2.5188600E-02 - - 2.9345474E-02 - - 3.3098490E-02 - - 3.7352890E-02 - - 4.1577882E-02 - - 4.5851588E-02 - - 4.9907550E-02 - - 5.5007580E-02 - - 5.8924848E-02 - - 6.4866195E-02 - - 6.8653679E-02 - - 7.3799695E-02 - - 8.2491620E-02 - - 8.2047228E-02 - - - - 6.1241006E-03 - - 1.1590726E-02 - - 1.1801215E-02 - - 1.1080585E-02 - - 1.1434054E-02 - - 1.1286311E-02 - - 1.2000496E-02 - - 1.2020032E-02 - - 1.2555074E-02 - - 1.2968561E-02 - - 1.3345040E-02 - - 1.3984260E-02 - - 1.4471501E-02 - - 1.5187071E-02 - - 1.5527587E-02 - - 1.6969733E-02 - - 1.7880430E-02 - - 2.1827072E-02 - - 2.5070882E-02 - - 2.9204178E-02 - - 3.2920367E-02 - - 3.7138445E-02 - - 4.1355200E-02 - - 4.5651496E-02 - - 4.9686415E-02 - - 5.4664866E-02 - - 5.8632525E-02 - - 6.4518086E-02 - - 6.8341097E-02 - - 7.3449748E-02 - - 8.2031901E-02 - - 8.1619798E-02 - - - - 6.1062727E-03 - - 1.1540200E-02 - - 1.1761046E-02 - - 1.1040109E-02 - - 1.1412932E-02 - - 1.1240736E-02 - - 1.1950046E-02 - - 1.1997678E-02 - - 1.2505989E-02 - - 1.2930265E-02 - - 1.3303213E-02 - - 1.3935054E-02 - - 1.4397122E-02 - - 1.5128867E-02 - - 1.5487202E-02 - - 1.6938379E-02 - - 1.7810772E-02 - - 2.1723430E-02 - - 2.4973244E-02 - - 2.9068452E-02 - - 3.2834028E-02 - - 3.7010997E-02 - - 4.1148015E-02 - - 4.5454526E-02 - - 4.9470264E-02 - - 5.4447102E-02 - - 5.8392796E-02 - - 6.4249338E-02 - - 6.8034422E-02 - - 7.3189468E-02 - - 8.1672467E-02 - - 8.1260364E-02 - - - - 6.0833777E-03 - - 1.1517436E-02 - - 1.1712978E-02 - - 1.1032819E-02 - - 1.1358893E-02 - - 1.1208870E-02 - - 1.1912352E-02 - - 1.1958737E-02 - - 1.2469851E-02 - - 1.2881147E-02 - - 1.3237414E-02 - - 1.3873203E-02 - - 1.4346868E-02 - - 1.5065060E-02 - - 1.5417558E-02 - - 1.6865782E-02 - - 1.7748238E-02 - - 2.1647065E-02 - - 2.4885779E-02 - - 2.8999390E-02 - - 3.2709869E-02 - - 3.6878634E-02 - - 4.1028900E-02 - - 4.5288735E-02 - - 4.9351482E-02 - - 5.4263443E-02 - - 5.8208019E-02 - - 6.4026596E-02 - - 6.7817431E-02 - - 7.2944166E-02 - - 8.1408951E-02 - - 8.0980011E-02 - - - - 6.0960595E-03 - - 1.1509277E-02 - - 1.1717750E-02 - - 1.1016084E-02 - - 1.1324287E-02 - - 1.1181299E-02 - - 1.1926512E-02 - - 1.1924795E-02 - - 1.2430825E-02 - - 1.2836520E-02 - - 1.3191644E-02 - - 1.3847845E-02 - - 1.4306693E-02 - - 1.5047376E-02 - - 1.5361189E-02 - - 1.6797970E-02 - - 1.7681035E-02 - - 2.1572902E-02 - - 2.4843981E-02 - - 2.8950004E-02 - - 3.2646669E-02 - - 3.6798605E-02 - - 4.0927881E-02 - - 4.5165770E-02 - - 4.9225435E-02 - - 5.4165928E-02 - - 5.8066998E-02 - - 6.3897046E-02 - - 6.7667188E-02 - - 7.2785603E-02 - - 8.1253392E-02 - - 8.0864443E-02 - - - - 6.0706294E-03 - - 1.1507691E-02 - - 1.1695334E-02 - - 1.0977998E-02 - - 1.1320263E-02 - - 1.1167309E-02 - - 1.1887145E-02 - - 1.1908635E-02 - - 1.2405259E-02 - - 1.2838152E-02 - - 1.3210507E-02 - - 1.3849960E-02 - - 1.4283591E-02 - - 1.5028182E-02 - - 1.5329706E-02 - - 1.6759635E-02 - - 1.7685388E-02 - - 2.1572849E-02 - - 2.4772494E-02 - - 2.8864133E-02 - - 3.2582677E-02 - - 3.6784719E-02 - - 4.0900801E-02 - - 4.5137865E-02 - - 4.9135372E-02 - - 5.4093178E-02 - - 5.8034149E-02 - - 6.3786244E-02 - - 6.7502120E-02 - - 7.2584553E-02 - - 8.1167082E-02 - - 8.0688398E-02 - - - - 6.0461907E-03 - - 1.1481547E-02 - - 1.1737058E-02 - - 1.0999643E-02 - - 1.1361089E-02 - - 1.1125441E-02 - - 1.1866202E-02 - - 1.1842566E-02 - - 1.2424994E-02 - - 1.2799184E-02 - - 1.3219862E-02 - - 1.3773742E-02 - - 1.4257782E-02 - - 1.4972557E-02 - - 1.5426839E-02 - - 1.6740630E-02 - - 1.7654390E-02 - - 2.1573482E-02 - - 2.4801577E-02 - - 2.8800263E-02 - - 3.2583876E-02 - - 3.6801622E-02 - - 4.0806074E-02 - - 4.5107401E-02 - - 4.9075545E-02 - - 5.3960225E-02 - - 5.7982974E-02 - - 6.3859228E-02 - - 6.7502946E-02 - - 7.2470281E-02 - - 8.1149466E-02 - - 8.0629616E-02 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - 1.0000000E+00 - - - - - \ No newline at end of file From 1625927b4427e80c508e29d709403f907dea5cb2 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 5 Sep 2016 21:04:50 -0400 Subject: [PATCH 09/82] Slowly getting the tests to work --- scripts/openmc-update-mgxs.py | 12 ++-- src/input_xml.F90 | 20 ++++--- src/mgxs_data.F90 | 54 ++++++++++++++++- src/mgxs_header.F90 | 58 +++++++++---------- tests/input_set.py | 2 +- tests/test_mg_basic/inputs_true.dat | 2 +- tests/test_mg_max_order/inputs_true.dat | 2 +- tests/test_mg_nuclide/inputs_true.dat | 2 +- tests/test_mg_tallies/inputs_true.dat | 2 +- .../test_mgxs_library_ce_to_mg.py | 6 +- 10 files changed, 106 insertions(+), 54 deletions(-) diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py index bc0c201c3e..fc9bad30f8 100755 --- a/scripts/openmc-update-mgxs.py +++ b/scripts/openmc-update-mgxs.py @@ -42,18 +42,20 @@ def parse_args(): # Create argument parser parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('-c', '--compression', type=int, - help='input XML file') parser.add_argument('-i', '--input', type=argparse.FileType('r'), help='input XML file') parser.add_argument('-o', '--output', nargs='?', default='', help='output file, in HDF5 format') + parser.add_argument('-c', '--compression', type=int, + help='HDF5 Compression Level') args = vars(parser.parse_args()) if args['output'] == '': - fname = args['input'].name.split('.') - fname[-1] = '.h5' - args['output'] = ''.join(fname) + filename = args['input'].name + extension = filename[filename.rfind('.'):] + if extension == '.xml': + filename = filename[:filename.rfind('.')] + '.h5' + args['output'] = filename # Parse and return commandline arguments. return args diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 24875d1fe9..d755f21682 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -49,10 +49,18 @@ contains call read_settings_xml() call read_geometry_xml() - call read_tallies_xml() call read_materials() + call read_tallies_xml() if (cmfd_run) call configure_cmfd() + if (.not. run_CE) then + ! Create material macroscopic data for MGXS + call time_read_xs % start() + call read_mgxs() + call create_macro_xs() + call time_read_xs % stop() + end if + end subroutine read_input_xml !=============================================================================== @@ -2092,15 +2100,9 @@ contains call get_temperatures(nuc_temps, sab_temps) ! Read continuous-energy cross sections - if (run_mode /= MODE_PLOTTING) then + if (run_CE .and. run_mode /= MODE_PLOTTING) then call time_read_xs % start() - if (run_CE) then - call read_ce_cross_sections(libraries, library_dict, nuc_temps, sab_temps) - else - ! Create material macroscopic data for MGXS - call read_mgxs(nuc_temps) - call create_macro_xs() - end if + call read_ce_cross_sections(libraries, library_dict, nuc_temps, sab_temps) call time_read_xs % stop() end if diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index d9039a3ad7..45737ff1dc 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -20,9 +20,7 @@ contains ! nuclides and sab_tables arrays !=============================================================================== - subroutine read_mgxs(temps) - type(VectorReal), allocatable :: temps(:) - + subroutine read_mgxs() integer :: i ! index in materials array integer :: j ! index over nuclides in material integer :: i_xsdata ! index in list @@ -38,6 +36,7 @@ contains logical :: get_kfiss, get_fiss integer :: l type(DictCharInt) :: xsdata_dict + type(VectorReal), allocatable :: temps(:) ! Check if cross_sections.xml exists inquire(FILE=path_cross_sections, EXIST=file_exists) @@ -49,6 +48,9 @@ contains call write_message("Loading Cross Section Data...", 5) + ! Get temperatures + call get_temperatures(temps) + ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) @@ -234,5 +236,51 @@ contains end subroutine get_mat_kTs +!=============================================================================== +! GET_TEMPERATURES returns a list of temperatures that each MGXS table +! appears at in the model. Later, this list is used to determine the actual +! temperatures to read (which may be different if interpolation is used) +!=============================================================================== + + subroutine get_temperatures(temps) + type(VectorReal), allocatable, intent(out) :: temps(:) + + integer :: i, j, k + integer :: i_nuclide ! index in nuclides array + integer :: i_material + real(8) :: temperature ! temperature in Kelvin + + allocate(temps(n_nuclides_total)) + + do i = 1, size(cells) + do j = 1, size(cells(i) % material) + ! Skip any non-material cells and void materials + if (cells(i) % material(j) == NONE .or. & + cells(i) % material(j) == MATERIAL_VOID) cycle + + ! Get temperature of cell (rounding to nearest integer) + if (size(cells(i) % sqrtkT) > 1) then + temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN + else + temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN + end if + + i_material = material_dict % get_key(cells(i) % material(j)) + associate (mat => materials(i_material)) + NUC_NAMES_LOOP: do k = 1, size(mat % names) + ! Get index in temps array + i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k))) + + ! Add temperature if it hasn't already been added + if (find(temps(i_nuclide), temperature) == -1) then + call temps(i_nuclide) % push_back(temperature) + end if + end do NUC_NAMES_LOOP + end associate + end do + end do + + end subroutine get_temperatures + end module mgxs_data diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index cef4685172..73a11476c5 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -691,7 +691,7 @@ module mgxs_header if (check_dataset(xsdata_grp, "nu-fission")) then allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "nu-fission") - allocate(temp_4d(groups, groups, this % n_azi,this % n_pol)) + allocate(temp_4d(groups, groups, this % n_azi, this % n_pol)) temp_4d(:, :, :, :) = reshape(temp_arr, (/groups, groups, & this % n_azi, this % n_pol/)) deallocate(temp_arr) @@ -1241,25 +1241,25 @@ module mgxs_header ! Create the Xs Data for each temperature TEMP_LOOP: do t = 1, temps % size() ! Allocate and initialize the data needed for macro_xs(i_mat) object - allocate(this % xs(t) % total(n_azi, n_pol, groups)) + allocate(this % xs(t) % total(groups, n_azi, n_pol)) this % xs(t) % total = ZERO - allocate(this % xs(t) % absorption(n_azi, n_pol, groups)) + allocate(this % xs(t) % absorption(groups, n_azi, n_pol)) this % xs(t) % absorption = ZERO - allocate(this % xs(t) % fission(n_azi, n_pol, groups)) + allocate(this % xs(t) % fission(groups, n_azi, n_pol)) this % xs(t) % fission = ZERO - allocate(this % xs(t) % k_fission(n_azi, n_pol, groups)) + allocate(this % xs(t) % k_fission(groups, n_azi, n_pol)) this % xs(t) % k_fission = ZERO - allocate(this % xs(t) % nu_fission(n_azi, n_pol, groups)) + allocate(this % xs(t) % nu_fission(groups, n_azi, n_pol)) this % xs(t) % nu_fission = ZERO - allocate(this % xs(t) % chi(n_azi, n_pol, groups, groups)) + allocate(this % xs(t) % chi(groups, groups, n_azi, n_pol)) this % xs(t) % chi = ZERO - allocate(temp_mult(n_azi, n_pol, groups, groups)) + allocate(temp_mult(groups, groups, n_azi, n_pol)) temp_mult = ZERO - allocate(mult_num(n_azi, n_pol, groups, groups)) + allocate(mult_num(groups, groups, n_azi, n_pol)) mult_num = ZERO - allocate(mult_denom(n_azi, n_pol, groups, groups)) + allocate(mult_denom(groups, groups, n_azi, n_pol)) mult_denom = ZERO - allocate(scatt_coeffs(n_azi, n_pol, order_dim, groups, groups)) + allocate(scatt_coeffs(order_dim, groups, groups, n_azi, n_pol)) scatt_coeffs = ZERO allocate(this % xs(t) % scatter(n_azi, n_pol)) @@ -1342,18 +1342,18 @@ module mgxs_header nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - mult_num(iazi, ipol, gout, gin) = & - mult_num(iazi, ipol, gout, gin) + atom_density * & + mult_num(gout, gin, iazi, ipol) = & + mult_num(gout, gin, iazi, ipol) + atom_density * & nuscatt if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then - mult_denom(iazi, ipol, gout, gin) = & - mult_denom(iazi, ipol, gout, gin) + atom_density * & + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density * & nuscatt / & nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) else ! Avoid division by zero - mult_denom(iazi, ipol, gout, gin) = & - mult_denom(iazi, ipol, gout, gin) + atom_density + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density end if end do end do @@ -1361,8 +1361,8 @@ module mgxs_header ! Get the complete scattering matrix nuc_order_dim = & size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % dist(1) % data, dim=1) - scatt_coeffs(iazi, ipol, 1:min(nuc_order_dim, order_dim), :, :) = & - scatt_coeffs(iazi, ipol, 1:min(nuc_order_dim, order_dim), :, :) + & + scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) = & + scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) + & atom_density * & nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % get_matrix(min(nuc_order_dim, order_dim)) end do @@ -1376,12 +1376,12 @@ module mgxs_header do iazi = 1, n_azi do gin = 1, groups do gout = 1, groups - if (mult_denom(iazi, ipol, gout, gin) > ZERO) then - temp_mult(iazi, ipol, gout, gin) = & - mult_num(iazi, ipol, gout, gin) / & - mult_denom(iazi, ipol, gout, gin) + if (mult_denom(gout, gin, iazi, ipol) > ZERO) then + temp_mult(gout, gin, iazi, ipol) = & + mult_num(gout, gin, iazi, ipol) / & + mult_denom(gout, gin, iazi, ipol) else - temp_mult(iazi, ipol, gout, gin) = ONE + temp_mult(gout, gin, iazi, ipol) = ONE end if end do end do @@ -1392,8 +1392,8 @@ module mgxs_header do ipol = 1, n_pol do iazi = 1, n_azi call this % xs(t) % scatter(iazi, ipol) % obj % init(& - temp_mult(iazi, ipol, :, :), & - scatt_coeffs(iazi, ipol, :, :, :)) + temp_mult(:, :, iazi, ipol), & + scatt_coeffs(:, :, :, iazi, ipol)) end do end do @@ -1402,10 +1402,10 @@ module mgxs_header do ipol = 1, n_pol do iazi = 1, n_azi do gin = 1, groups - norm = sum(this % xs(t) % chi(iazi, ipol, :, gin)) + norm = sum(this % xs(t) % chi(:, gin, iazi, ipol)) if (norm > ZERO) then - this % xs(t) % chi(iazi, ipol, :, gin) = & - this % xs(t) % chi(iazi, ipol, :, gin) / norm + this % xs(t) % chi(:, gin, iazi, ipol) = & + this % xs(t) % chi(:, gin, iazi, ipol) / norm end if end do end do diff --git a/tests/input_set.py b/tests/input_set.py index e409fba58f..2dcef059a5 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -893,7 +893,7 @@ class MGInputSet(InputSet): self.settings.source = Source(space=Box([0.0, 0.0, 0.0], [10.0, 10.0, 2.0])) self.settings.energy_mode = "multi-group" - self.settings.cross_sections = "../1d_mgxs.xml" + self.settings.cross_sections = "../1d_mgxs.h5" def build_defualt_plots(self): plot = openmc.Plot() diff --git a/tests/test_mg_basic/inputs_true.dat b/tests/test_mg_basic/inputs_true.dat index bfb0cc09e9..1f95579c71 100644 --- a/tests/test_mg_basic/inputs_true.dat +++ b/tests/test_mg_basic/inputs_true.dat @@ -1 +1 @@ -d90692c6bf8db3672d70103ded682326d7f14d416e79e18ec055bdeafe1dbc1dbe642e8410cad95bf247f27c907b10b1567127bd2868d466ce2586aacff0411f \ No newline at end of file +ed4d8a6c1a00d4dad10bc5522bf42d0c7a13ef5f86fc93a3f249e77681cda4424ce8879919015b05272c276ffea41e3aecef882592e8dbd97085273a356fb630 \ No newline at end of file diff --git a/tests/test_mg_max_order/inputs_true.dat b/tests/test_mg_max_order/inputs_true.dat index d827cfaa49..9b5d32ce6c 100644 --- a/tests/test_mg_max_order/inputs_true.dat +++ b/tests/test_mg_max_order/inputs_true.dat @@ -1 +1 @@ -7d508b1f3a2661566b8e8cb76fee61aecb96e8b60d633b06f13c4600bd854ea3366cdebd033c0a71ffb8adb90a9aeb64fe5ac0ef3235260921f5689c93e54305 \ No newline at end of file +8752d3167989d876c6f29b4b1ca7eed4b91793d8579c92de85633fd90235c67d63ee76d49081006047e0078f6f86eb6e3420c1f8fe44564e7a1fb62e828587d0 \ No newline at end of file diff --git a/tests/test_mg_nuclide/inputs_true.dat b/tests/test_mg_nuclide/inputs_true.dat index 18811f2854..93de08656d 100644 --- a/tests/test_mg_nuclide/inputs_true.dat +++ b/tests/test_mg_nuclide/inputs_true.dat @@ -1 +1 @@ -be296da93031694b2915e1a10e3e6fd663d612cdd29a84745e3ccb0065c088b4bcda45f6919962f6ee784efe52ebe178bf7d3ce019859637ae57c2da1e240a04 \ No newline at end of file +10b64fa97cc4feb1b1b8ba401b25b68ab682aba55ad4303a76a9a293ae79cdfff2f65d74310eb917da0aac243c24713d91eafae7ec5f0c4ae535d49fc928a869 \ No newline at end of file diff --git a/tests/test_mg_tallies/inputs_true.dat b/tests/test_mg_tallies/inputs_true.dat index c74d7759f7..5707fe6de0 100644 --- a/tests/test_mg_tallies/inputs_true.dat +++ b/tests/test_mg_tallies/inputs_true.dat @@ -1 +1 @@ -707285b77a091904a69720e78bf87a6779f2223c0fa2a3725353d00ca30f2624c7d53af016d78c7ad30b70a24bb53eda7dea2f592499b098f541591825b67143 \ No newline at end of file +34af3b6ee8f65c6257d85a7c9594bc9bbabdabcb055e42bf6dd3ebfc0e41503367674223093363798950524e04f4377eae80f6d535301e55d268ff0c74e4261f \ No newline at end of file diff --git a/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py b/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py index baa54b018b..a86f73796d 100644 --- a/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py +++ b/tests/test_mgxs_library_ce_to_mg/test_mgxs_library_ce_to_mg.py @@ -61,14 +61,14 @@ class MGXSTestHarness(PyAPITestHarness): self._input_set.geometry = self.mgxs_lib.create_mg_mode() # Modify settings so we can run in MG mode - self._input_set.settings.cross_sections = './mgxs.xml' + self._input_set.settings.cross_sections = './mgxs.h5' self._input_set.settings.energy_mode = 'multi-group' # Write modified input files self._input_set.settings.export_to_xml() self._input_set.geometry.export_to_xml() self._input_set.materials.export_to_xml() - self._input_set.mgxs_file.export_to_xml() + self._input_set.mgxs_file.export_to_hdf5() # Dont need tallies.xml, so remove the file if os.path.exists('./tallies.xml'): os.remove('./tallies.xml') @@ -85,7 +85,7 @@ class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): return super(MGXSTestHarness, self)._cleanup() - f = os.path.join(os.getcwd(), 'mgxs.xml') + f = os.path.join(os.getcwd(), 'mgxs.h5') if os.path.exists(f): os.remove(f) From 88abdfb5ce54c9599d42ec3cbd6c76ae7074f36a Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 5 Sep 2016 21:18:17 -0400 Subject: [PATCH 10/82] Fixed most failing tests, ce_to_mg is next --- .gitignore | 1 + tests/1d_mgxs.h5 | Bin 0 -> 100568 bytes tests/run_tests.py | 2 +- .../test_mgxs_library_ce_to_mg.py | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 tests/1d_mgxs.h5 diff --git a/.gitignore b/.gitignore index 2ca1c7d145..b1cb1a623e 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ tests/ctestscript.run # HDF5 files *.h5 +!tests/1d_mgxs.h5 # Build files src/CMakeCache.txt diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 new file mode 100644 index 0000000000000000000000000000000000000000..4b7b94cb45772879a531852ad5db9fdbe58a49d6 GIT binary patch literal 100568 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

vHL_hxQ3HPiI5iPC~;Lvu1 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 Date: Wed, 7 Sep 2016 04:23:05 -0400 Subject: [PATCH 11/82] Implemented new scatter MGXS library specification on python side and fixed python2 bug in writing strings to hdf5 file --- docs/source/io_formats/mgxs_library.rst | 85 ++++++++++------ openmc/mgxs_library.py | 129 ++++++++++++++++++++---- 2 files changed, 162 insertions(+), 52 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index ccd68c1844..4f6233aafc 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -56,17 +56,18 @@ data for the nuclide or material that it represents. that the azimuthal angular domain is subdivided if the `representation` attribute is "angle". This parameter is ignored otherwise. - - **num-polar** (*int*) -- Number of equal width angular bins + - **num-polar** (*int*) -- Number of equal width angular bins that the polar angular domain is subdivided if the `representation` attribute is "angle". This parameter is ignored otherwise. - - **scatter-type** (*char[]*) -- The representation of the - scattering angular distribution. The options are either - "legendre", "histogram", or "tabular". If not provided, the - default of "legendre" will be assumed. - - **order** (*int*) -- Either the Legendre order, number of bins, - or number of points (depending on the value of `scatter-type`) - used to describe the angular distribution associated with each group-to-group transfer probability. + - **scatter-type** (*char[]*) -- The representation of the + scattering angular distribution. The options are either + "legendre", "histogram", or "tabular". If not provided, the + default of "legendre" will be assumed. + - **order** (*int*) -- Either the Legendre order, number of bins, + or number of points (depending on the value of `scatter-type`) + used to describe the angular distribution associated with each + group-to-group transfer probability. **//kTs/** @@ -86,30 +87,6 @@ Temperature-dependent data, provided for temperature K. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of [groups, azimuthal, polar]. - - **scatter matrix** (*double[][][]* or *double[][][][][]*) -- - Scattering moment matrices. This dataset requires the scattering - moment matrices presented with the columns representing incoming - group and rows representing the outgoing group. That is, - down-scatter will be above the diagonal of the resultant matrix. - This matrix is repeated for every Legendre order (in order of - increasing orders) if `scatter-type` is "legendre"; otherwise, this - matrix is repeated for every bin of the histogram or tabular - representation. Finally, if ``representation`` is "angle", the - above is repeated for every azimuthal angle and every polar angle, - in that order. - - **multiplicity matrix** (*double[][]* or *double[][][][]*) -- - Scattering multiplicity matrices. - This dataset provides the ratio of neutrons produced in scattering - collisions to the neutrons which undergo scattering collisions; - that is, the multiplicity provides the code with a scaling factor - to account for neutrons being produced in (n,xn) reactions. This - information is assumed isotropic and therefore is not repeated for - every Legendre moment or histogram/tabular bin. This matrix - follows the same arrangement as described for the `scatter` - dataset, with the exception of the data needed to provide the - scattering type information. - This dataset is optional, if it is not provided no multiplication - (i.e., values of 1.0) will be assumed. - **fission** (*double[]* or *double[][][]*) -- Fission cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D @@ -135,4 +112,46 @@ Temperature-dependent data, provided for temperature K. the `nu-fission` data must represent the fission neutron energy spectra as well and thus will have one additional dimension for the outgoing energy group. In this case, `nu-fission` has the - same dimensionality as `multiplicity matrix`. \ No newline at end of file + same dimensionality as `multiplicity matrix`. + +**//K/scatter data/** + +Data specific to neutron scattering for the temperature K + +:Datasets: - **g_out bounds** (*int[2]* or *int[][][2]) -- + Minimum (most energetic) and maximum (most thermal) outgoing groups + with non-zero values of the scattering matrix. These group numbers + use the standard ordering where the fastest neutron energy group + is group 1 while the most thermal neutron energy group is group G. + The dimensionality of `g_out bounds` is: + `g_out bounds][g_in][g_out]`, or + `g_out bounds[num-polar][num-azimuthal][g_in][g_out]`. + The former is used when `representation` is "isotropic", and the + latter when `representation` is "angle". + - **scatter matrix** (*double[][]* or *double[][][][]*) -- + Flattened representation of the scattering moment matrices where + the [g_in] and [g_out] indices are flattened. The pre-flattened + array is shaped as follows (in row-major format): + `scatter matrix[order(+1)][g_in][g_out]`, or + `scatter matrix[num-polar][num-azimuthal][order(+1)][g_in][g_out]` + The former is used when `representation` is "isotropic", and the + latter when `representation` is "angle". Note that if the value of + `scatter-type` is "legendre", the order dimension will be one + larger than the value of `order`, otherwise it will match `order`. + Finally, the g_out dimension has a dimensionality of + `g_out bounds`[0] to `g_out bounds`[1]. + - **multiplicity matrix** (*double[]*) -- Flattened representation of + the scattering moment matrices where the [g_in] and [g_out] indices + are flattened. This dataset provides the code with a scaling factor + to account for neutrons being produced in (n,xn) reactions. This + is assumed isotropic and therefore is not repeated for every + Legendre moment or histogram/tabular bin. This dataset is optional, + if it is not provided no multiplication (i.e., values of 1.0) will + be assumed. + The pre-flattened array is shaped as follows (in row-major format): + `multiplicity matrix[g_in][g_out]`, or + `multiplicity matrix[num-polar][num-azimuthal][g_in][g_out]` + The former is used when `representation` is "isotropic", and the + latter when `representation` is "angle". Finally, the g_out + dimension has a dimensionality of `g_out bounds`[0] to + `g_out bounds`[1]. \ No newline at end of file diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index ad60a57798..687e2d693a 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1137,14 +1137,15 @@ class XSdata(object): if self.fissionable is not None: grp.attrs['fissionable'] = self.fissionable if self.representation is not None: - grp.attrs['representation'] = np.string_(self.representation) + grp.attrs['representation'] = np.array(self.representation, + dtype='S') if self.representation == 'angle': if self.num_azimuthal is not None: grp.attrs['num-azimuthal'] = self.num_azimuthal if self.num_polar is not None: grp.attrs['num-polar'] = self.num_polar if self.scatter_type is not None: - grp.attrs['scatter-type'] = np.string_(self.scatter_type) + grp.attrs['scatter-type'] = np.array(self.scatter_type, dtype='S') if self.order is not None: grp.attrs['order'] = self.order @@ -1157,20 +1158,16 @@ class XSdata(object): # Create the temperature datasets for i, temperature in enumerate(self.temperatures): xsgrp = grp.create_group(str(int(np.round(temperature))) + "K") - if self._total[i] is not None: - xsgrp.create_dataset("total", data=self._total[i], - compression=compression) - if self._absorption[i] is not None: - xsgrp.create_dataset("absorption", data=self._absorption[i], - compression=compression) - if self._scatter_matrix[i] is not None: - xsgrp.create_dataset("scatter matrix", - data=self._scatter_matrix[i], - compression=compression) - if self._multiplicity_matrix[i] is not None: - xsgrp.create_dataset("multiplicity matrix", - data=self._multiplicity_matrix[i], - compression=compression) + if self._total[i] is None: + raise ValueError('total data must be provided when writing ' + 'the HDF5 library') + xsgrp.create_dataset("total", data=self._total[i], + compression=compression) + if self._absorption[i] is None: + raise ValueError('absorption data must be provided when ' + 'writing the HDF5 library') + xsgrp.create_dataset("absorption", data=self._absorption[i], + compression=compression) if self.fissionable: if self._fission[i] is not None: xsgrp.create_dataset("fission", data=self._fission[i], @@ -1182,9 +1179,103 @@ class XSdata(object): if self._chi[i] is not None: xsgrp.create_dataset("chi", data=self._chi[i], compression=compression) - if self._nu_fission[i] is not None: - xsgrp.create_dataset("nu-fission", - data=self._nu_fission[i], + if self._nu_fission[i] is None: + raise ValueError('nu-fission data must be provided when ' + 'writing the HDF5 library') + xsgrp.create_dataset("nu-fission", + data=self._nu_fission[i], + compression=compression) + + if self._scatter_matrix[i] is None: + raise ValueError('Scatter matrix must be provided when ' + 'writing the HDF5 library') + # Get the sparse scattering data to print to the library + G = self.energy_groups.num_groups + if self.representation is 'isotropic': + g_out_bounds = np.zeros((G, 2), dtype=np.int) + for g_in in range(G): + nz = np.nonzero(self._scatter_matrix[i][0, g_in, :]) + g_out_bounds[g_in, 0] = nz[0] + g_out_bounds[g_in, 1] = nz[-1] + # Now create the flattened scatter matrix array + flat_scatt = [] + for l in range(self._scatter_matrix[i].shape[0]): + for g_in in range(G): + matrix = self._scatter_matrix[i][l, g_in, :] + for g_out in range(g_out_bounds[g_in, 0], + g_out_bounds[g_in, 1] + 1): + flat_scatt.append(matrix[g_out]) + # And write it. + scatt_grp = xsgrp.create_group('scatter data') + scatt_grp.create_dataset("scatter matrix", + data=np.array(flat_scatt), + compression=compression) + # Repeat for multiplicity + if self._multiplicity_matrix[i] is not None: + # Now create the flattened scatter matrix array + flat_mult = [] + for g_in in range(G): + matrix = self._multiplicity_matrix[i][g_in, :] + for g_out in range(g_out_bounds[g_in, 0], + g_out_bounds[g_in, 1] + 1): + flat_mult.append(matrix[g_out]) + scatt_grp.create_dataset("multiplicity matrix", + data=np.array(flat_mult), + compression=compression) + # And finally, adjust g_out_bounds for 1-based group counting + # and write it. + g_out_bounds[:, :] += 1 + scatt_grp.create_dataset("g_out bounds", data=g_out_bounds, + compression=compression) + + else: + Np = self.num_polar + Na = self.num_azimuthal + g_out_bounds = np.zeros((Np, Na, G, 2), dtype=np.int) + for p in range(Np): + for a in range(Na): + for g_in in range(G): + matrix = self._scatter_matrix[i][p, a, 0, g_in, :] + nz = np.nonzero(matrix) + g_out_bounds[p, a, g_in, 0] = nz[0] + g_out_bounds[p, a, g_in, 1] = nz[-1] + # Now create the flattened scatter matrix array + flat_scatt = [[[] for a in range(Na)] for p in range(Np)] + for p in range(Np): + for a in range(Na): + for l in range(self._scatter_matrix[i].shape[2]): + for g_in in range(G): + matrix = \ + self._scatter_matrix[i][p, a, 0, g_in, :] + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + + 1): + flat_scatt[p][a].append(matrix[g_out]) + # And write it. + scatt_grp = xsgrp.create_group('scatter data') + scatt_grp.create_dataset("scatter matrix", + data=np.array(flat_scatt).flatten(), + compression=compression) + # Repeat for multiplicity + if self._multiplicity_matrix[i] is not None: + # Now create the flattened scatter matrix array + flat_mult = [[[] for a in range(Na)] for p in range(Np)] + for p in range(Np): + for a in range(Na): + for l in range(self._scatter_matrix[i].shape[2]): + for g_in in range(G): + matrix = \ + self._multiplicity_matrix[i][p, a, g_in, :] + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + 1): + flat_mult[p][a].append(matrix[g_out]) + scatt_grp.create_dataset("multiplicity matrix", + data=np.array(flat_mult).flatten(), + compression=compression) + # And finally, adjust g_out_bounds for 1-based group counting + # and write it. + g_out_bounds[:, :, :, :] += 1 + scatt_grp.create_dataset("g_out bounds", data=g_out_bounds, compression=compression) From 0cc5f06114aca33af769bc6318a74ca9b64f2c69 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Wed, 7 Sep 2016 18:39:10 -0400 Subject: [PATCH 12/82] Updated fortran side of the sparse scattering matrices, almost --- docs/source/io_formats/mgxs_library.rst | 42 +++-- openmc/mgxs_library.py | 16 +- src/mgxs_header.F90 | 217 +++++++++++++++--------- src/scattdata_header.F90 | 50 +++--- 4 files changed, 193 insertions(+), 132 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 4f6233aafc..0a02431f6c 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -118,20 +118,27 @@ Temperature-dependent data, provided for temperature K. Data specific to neutron scattering for the temperature K -:Datasets: - **g_out bounds** (*int[2]* or *int[][][2]) -- - Minimum (most energetic) and maximum (most thermal) outgoing groups - with non-zero values of the scattering matrix. These group numbers - use the standard ordering where the fastest neutron energy group - is group 1 while the most thermal neutron energy group is group G. +:Datasets: - **g_min** (*int[]* or *int[][][]) -- + Minimum (most energetic) outgoing groups with non-zero values of + the scattering matrix. These group numbers use the standard + ordering where the fastest neutron energy group is group 1 while + the slowest neutron energy group is group G. The dimensionality of `g_out bounds` is: - `g_out bounds][g_in][g_out]`, or - `g_out bounds[num-polar][num-azimuthal][g_in][g_out]`. + `g_min[g_in]`, or `g_min[num-polar][num-azimuthal][g_in]`. The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". - - **scatter matrix** (*double[][]* or *double[][][][]*) -- - Flattened representation of the scattering moment matrices where - the [g_in] and [g_out] indices are flattened. The pre-flattened - array is shaped as follows (in row-major format): + - **g_max** (*int[]* or *int[][][]) -- + Maximum (least energetic) outgoing groups with non-zero values of + the scattering matrix. These group numbers use the standard + ordering where the fastest neutron energy group is group 1 while + the slowest neutron energy group is group G. + The dimensionality of `g_out bounds` is: + `g_max[g_in]`, or `g_max[num-polar][num-azimuthal][g_in]`. + The former is used when `representation` is "isotropic", and the + latter when `representation` is "angle". + - **scatter matrix** (*double[]*) -- Flattened representation of the + scattering moment matrices. The pre-flattened array is shaped as + follows (in row-major format): `scatter matrix[order(+1)][g_in][g_out]`, or `scatter matrix[num-polar][num-azimuthal][order(+1)][g_in][g_out]` The former is used when `representation` is "isotropic", and the @@ -141,13 +148,12 @@ Data specific to neutron scattering for the temperature K Finally, the g_out dimension has a dimensionality of `g_out bounds`[0] to `g_out bounds`[1]. - **multiplicity matrix** (*double[]*) -- Flattened representation of - the scattering moment matrices where the [g_in] and [g_out] indices - are flattened. This dataset provides the code with a scaling factor - to account for neutrons being produced in (n,xn) reactions. This - is assumed isotropic and therefore is not repeated for every - Legendre moment or histogram/tabular bin. This dataset is optional, - if it is not provided no multiplication (i.e., values of 1.0) will - be assumed. + the scattering moment matrices. This dataset provides the code with + a scaling factor to account for neutrons being produced in (n,xn) + reactions. This is assumed isotropic and therefore is not repeated + for every Legendre moment or histogram/tabular bin. This dataset is + optional, if it is not provided no multiplication (i.e., values of + 1.0) will be assumed. The pre-flattened array is shaped as follows (in row-major format): `multiplicity matrix[g_in][g_out]`, or `multiplicity matrix[num-polar][num-azimuthal][g_in][g_out]` diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 687e2d693a..eaf66d1200 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1225,7 +1225,9 @@ class XSdata(object): # And finally, adjust g_out_bounds for 1-based group counting # and write it. g_out_bounds[:, :] += 1 - scatt_grp.create_dataset("g_out bounds", data=g_out_bounds, + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0], + compression=compression) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1], compression=compression) else: @@ -1240,7 +1242,7 @@ class XSdata(object): g_out_bounds[p, a, g_in, 0] = nz[0] g_out_bounds[p, a, g_in, 1] = nz[-1] # Now create the flattened scatter matrix array - flat_scatt = [[[] for a in range(Na)] for p in range(Np)] + flat_scatt = [] for p in range(Np): for a in range(Na): for l in range(self._scatter_matrix[i].shape[2]): @@ -1250,16 +1252,16 @@ class XSdata(object): for g_out in range(g_out_bounds[p, a, g_in, 0], g_out_bounds[p, a, g_in, 1] + 1): - flat_scatt[p][a].append(matrix[g_out]) + flat_scatt.append(matrix[g_out]) # And write it. scatt_grp = xsgrp.create_group('scatter data') scatt_grp.create_dataset("scatter matrix", - data=np.array(flat_scatt).flatten(), + data=np.array(flat_scatt), compression=compression) # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: # Now create the flattened scatter matrix array - flat_mult = [[[] for a in range(Na)] for p in range(Np)] + flat_mult = [] for p in range(Np): for a in range(Na): for l in range(self._scatter_matrix[i].shape[2]): @@ -1268,9 +1270,9 @@ class XSdata(object): self._multiplicity_matrix[i][p, a, g_in, :] for g_out in range(g_out_bounds[p, a, g_in, 0], g_out_bounds[p, a, g_in, 1] + 1): - flat_mult[p][a].append(matrix[g_out]) + flat_mult.append(matrix[g_out]) scatt_grp.create_dataset("multiplicity matrix", - data=np.array(flat_mult).flatten(), + data=np.array(flat_mult), compression=compression) # And finally, adjust g_out_bounds for 1-based group counting # and write it. diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 73a11476c5..7ed7f090c0 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -381,16 +381,17 @@ module mgxs_header ! in that conversion character(MAX_LINE_LEN) :: temp_str - integer(HID_T) :: xsdata_grp + integer(HID_T) :: xsdata_grp, scatt_grp real(8), allocatable :: temp_arr(:), temp_2d(:, :) - real(8), allocatable :: temp_mult(:, :) real(8), allocatable :: scatt_coeffs(:, :, :) - real(8), allocatable :: input_scatt(:, :, :) real(8), allocatable :: temp_scatt(:, :, :) real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l, imu + integer :: order, order_dim, gin, gout, l, imu, length type(VectorInt) :: temps_to_read integer :: t + type(Jagged2D) :: input_scatt(:) + type(Jagged1D) :: temp_mult(:) + integer, allocatable :: gmin(:), gmax(:) ! Call generic data gathering routine (will populate the metadata) call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & @@ -488,84 +489,134 @@ module mgxs_header end if ! Get scattering data - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order. We will get it in that format in input_scatt, - ! but then need to convert it to a more useful ordering for processing - ! (Order x Gout x Gin). - allocate(input_scatt(groups, groups, order_dim)) - if (check_dataset(xsdata_grp, "scatter matrix")) then - call read_dataset(input_scatt, xsdata_grp, "scatter matrix") - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - allocate(temp_scatt(groups, groups, order_dim)) - temp_scatt(:, :, :) = input_scatt(:, :, 1:order_dim) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note xs is also - ! the default behavior), convert that now. - if (this % scatter_type == ANGLE_LEGENDRE .and. legendre_to_tabular) then - ! Convert input parameters to what we need for the rest. - this % scatter_type = ANGLE_TABULAR - order_dim = legendre_to_tabular_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - scatt_coeffs(imu, gout, gin) = & - evaluate_legendre(temp_scatt(gout, gin, :),mu) - ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin) < ZERO) & - scatt_coeffs(imu, gout, gin) = ZERO - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin) + & - scatt_coeffs(imu, gout, gin)) - end if - end do ! mu - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(:, gout, gin) = scatt_coeffs(:, gout, gin) * & - temp_scatt(gout, gin, 1) / norm - end if - end do ! gout - end do ! gin - else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups)) - do gin = 1, groups - do gout = 1, groups - do l = 1, order_dim - scatt_coeffs(l, gout, gin) = temp_scatt(gout, gin, l) - end do - end do - end do - end if - deallocate(temp_scatt) + if (.not. check_group(xsdata_grp, "scatter data")) & + call fatal_error("Must provide 'scatter data'") + scatt_grp = open_group(xsdata_grp, 'scatter data') + ! First get the outgoing group boundary indices + if (check_dataset(xsdata_grp, "g_min")) then + allocate(g_min(groups)) + call read_dataset(g_min, scatt_grp, "g_min") else - call fatal_error("Must provide scatter matrix!") + call fatal_error("'g_min' for the scatter matrix must be provided") end if + if (check_dataset(xsdata_grp, "g_max")) then + allocate(g_max(groups)) + call read_dataset(g_max, scatt_grp, "g_max") + else + call fatal_error("'g_max' for the scatter matrix must be provided") + end if + + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do gin = 1, groups + length = length + order_dim * (g_max(gin) - gmin(gin) + 1) + end do + ! Allocate flattened array + allocate(temp_arr(length)) + jf (.not. check_dataset(scatt_grp, 'scatter matrix') & + call fatal_error("'scatter matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing + ! to ScattData + allocate(input_scatt(groups)) + index = 1 + do gin = 1, groups + allocate(input_scatt(gin) % data(order_dim, gmin(gin):gmax(gin))) + do l = 1, order_dim + do gout = gmin(gin), gmax(gin) + input_scatt(gin) % data(l, gout) = temp_arr(index) + index = index + 1 + end do + end do + end do + deallocate(temp_arr) + + ! Finally convert the legendre to tabular if needed + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + + allocate(scatt_coeffs(gin)) + + if (this % scatter_type == ANGLE_LEGENDRE .and. & + legendre_to_tabular) then + this % scatter_type = ANGLE_TABULAR + order_dim = legendre_to_tabular_points + order = order_dim + dmu = TWO / real(order - 1, 8) + do gin = 1, groups + allocate(scatt_coeffs(gin) % data(order_dim, groups)) + do gout = gmin(gin), gmax(gin) + norm = ZERO + do imu = 1, order_dim + if (imu == 1) then + mu = -ONE + else if (imu == order_dim) then + mu = ONE + else + mu = -ONE + real(imu - 1, 8) * dmu + end if + scatt_coeffs(gin) % data(imu, gout) = & + evaluate_legendre(input_scatt(gin) % data(:, gout), mu) + ! Ensure positivity of distribution + if (scatt_coeffs(gin) % data(imu, gout) < ZERO) & + scatt_coeffs(gin) % data(imu, gout) = ZERO + ! And accrue the integral + if (imu > 1) then + norm = norm + HALF * dmu * & + (scatt_coeffs(gin) % data(imu - 1, gout) + & + scatt_coeffs(gin) % data(imu, gout)) + end if + end do ! mu + ! Now that we have the integral, lets ensure that the distribution + ! is normalized such that it preserves the original scattering xs + if (norm > ZERO) then + scatt_coeffs(gin) % data(i:, gout) = & + scatt_coeffs(gin) % data(:, gout) * & + input_scatt(gin) % data(1, gout) + end if + end do ! gout + end do ! gin + else + ! Sticking with current representation, carry forward but change + ! the array ordering + do gin = 1, groups + allocate(scatt_coeffs(gin) % data(order_dim, groups)) + scatt_coeffs(gin) % data(:, :) = input_scatt(gin) % data(:, :) + end do + end if + deallocate(input_scatt) + + ! Now get the multiplication matrix + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do gin = 1, groups + length = length + (g_max(gin) - gmin(gin) + 1) + end do + ! Allocate flattened array + allocate(temp_arr(length)) + jf (.not. check_dataset(scatt_grp, 'multiplicity matrix') & + call fatal_error("'multiplicity matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups)) + index = 1 + do gin = 1, groups + allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) + temp_mult(gin) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + deallocate(temp_arr) ! Allocate and initialize our ScattData Object. if (this % scatter_type == ANGLE_HISTOGRAM) then @@ -577,7 +628,7 @@ module mgxs_header end if ! Initialize the ScattData Object - call xs % scatter % init(temp_mult, scatt_coeffs) + call xs % scatter % init(gmin, gmax, temp_mult, scatt_coeffs) ! Check sigA to ensure it is not 0 since it is ! often divided by in the tally routines @@ -1168,7 +1219,7 @@ module mgxs_header end do ! Initialize the ScattData Object - call this % xs(t) % scatter % init(temp_mult, scatt_coeffs) + call this % xs(t) % scatter % init_from_dense(temp_mult, scatt_coeffs) ! Now normalize chi if (mat % fissionable) then @@ -1391,7 +1442,7 @@ module mgxs_header ! Initialize the ScattData Object do ipol = 1, n_pol do iazi = 1, n_azi - call this % xs(t) % scatter(iazi, ipol) % obj % init(& + call this % xs(t) % scatter(iazi, ipol) % obj % init_from_dense(& temp_mult(:, :, iazi, ipol), & scatt_coeffs(:, :, :, iazi, ipol)) end do diff --git a/src/scattdata_header.F90 b/src/scattdata_header.F90 index d4643a0721..3bd29bb265 100644 --- a/src/scattdata_header.F90 +++ b/src/scattdata_header.F90 @@ -42,18 +42,20 @@ module scattdata_header contains procedure(scattdata_init_), deferred :: init ! Initializes ScattData + ! Initializes ScattData from a dense matrix + procedure(scattdata_init_dense_), deferred :: init_from_dense procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu procedure(scattdata_sample_), deferred :: sample ! sample the scatter event procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix end type ScattData abstract interface - subroutine scattdata_init_(this, mult, coeffs) + subroutine scattdata_init_dense_(this, mult, coeffs) import ScattData class(ScattData), intent(inout) :: this ! Object to work with real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use - end subroutine scattdata_init_ + end subroutine scattdata_init_dense_ pure function scattdata_calc_f_(this, gin, gout, mu) result(f) import ScattData @@ -79,9 +81,9 @@ module scattdata_header ! Maximal value for rejection sampling from rectangle type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout)) contains - procedure :: init => scattdatalegendre_init - procedure :: calc_f => scattdatalegendre_calc_f - procedure :: sample => scattdatalegendre_sample + procedure :: init_from_dense => scattdatalegendre_init_from_dense + procedure :: calc_f => scattdatalegendre_calc_f + procedure :: sample => scattdatalegendre_sample end type ScattDataLegendre type, extends(ScattData) :: ScattDataHistogram @@ -90,10 +92,10 @@ module scattdata_header ! Histogram of f(mu) (dist has CDF) type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) contains - procedure :: init => scattdatahistogram_init - procedure :: calc_f => scattdatahistogram_calc_f - procedure :: sample => scattdatahistogram_sample - procedure :: get_matrix => scattdatahistogram_get_matrix + procedure :: init_from_dense => scattdatahistogram_init_from_dense + procedure :: calc_f => scattdatahistogram_calc_f + procedure :: sample => scattdatahistogram_sample + procedure :: get_matrix => scattdatahistogram_get_matrix end type ScattDataHistogram type, extends(ScattData) :: ScattDataTabular @@ -102,10 +104,10 @@ module scattdata_header ! PDF of f(mu) (dist has CDF) type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) contains - procedure :: init => scattdatatabular_init - procedure :: calc_f => scattdatatabular_calc_f - procedure :: sample => scattdatatabular_sample - procedure :: get_matrix => scattdatatabular_get_matrix + procedure :: init_from_dense => scattdatatabular_init_from_dense + procedure :: calc_f => scattdatatabular_calc_f + procedure :: sample => scattdatatabular_sample + procedure :: get_matrix => scattdatatabular_get_matrix end type ScattDataTabular !=============================================================================== @@ -122,7 +124,7 @@ contains ! SCATTDATA*_INIT builds the scattdata object !=============================================================================== - subroutine scattdata_init(this, order, energy, mult) + subroutine scattdata_init_from_dense(this, order, energy, mult) class(ScattData), intent(inout) :: this ! Object to work on integer, intent(in) :: order ! Data Order real(8), intent(inout) :: energy(:, :) ! Energy Transfer Matrix @@ -167,9 +169,9 @@ contains this % gmin(gin) = gmin this % gmax(gin) = gmax end do - end subroutine scattdata_init + end subroutine scattdata_init_from_dense - subroutine scattdatalegendre_init(this, mult, coeffs) + subroutine scattdatalegendre_init_from_dense(this, mult, coeffs) class(ScattDataLegendre), intent(inout) :: this ! Object to work on real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use @@ -206,7 +208,7 @@ contains end do end do - call scattdata_init(this, order, energy, mult) + call scattdata_init_from_dense(this, order, energy, mult) allocate(this % max_val(groups)) ! Set dist values from matrix and initialize max_val @@ -244,9 +246,9 @@ contains this % max_val(gin) % data(gout) * 1.1_8 end do end do - end subroutine scattdatalegendre_init + end subroutine scattdatalegendre_init_from_dense - subroutine scattdatahistogram_init(this, mult, coeffs) + subroutine scattdatahistogram_init_from_dense(this, mult, coeffs) class(ScattDataHistogram), intent(inout) :: this ! Object to work on real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use @@ -283,7 +285,7 @@ contains end do end do - call scattdata_init(this, order, energy, mult) + call scattdata_init_from_dense(this, order, energy, mult) allocate(this % mu(order)) this % dmu = TWO / real(order, 8) @@ -321,9 +323,9 @@ contains end do end do - end subroutine scattdatahistogram_init + end subroutine scattdatahistogram_init_from_dense - subroutine scattdatatabular_init(this, mult, coeffs) + subroutine scattdatatabular_init_from_dense(this, mult, coeffs) class(ScattDataTabular), intent(inout) :: this ! Object to work on real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use @@ -378,7 +380,7 @@ contains energy(gout, gin) = norm end do end do - call scattdata_init(this, order, energy, mult) + call scattdata_init_from_dense(this, order, energy, mult) ! Calculate f(mu) and integrate it so we can avoid rejection sampling allocate(this % fmu(groups)) @@ -415,7 +417,7 @@ contains end if end do end do - end subroutine scattdatatabular_init + end subroutine scattdatatabular_init_from_dense !=============================================================================== ! SCATTDATA_*_CALC_F Calculates the value of f given mu (and gin,gout pair) From 3b6f836ec4509296d4793e8dcfbc774a75ac9d93 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Thu, 8 Sep 2016 05:15:58 -0400 Subject: [PATCH 13/82] Revised the mgxs_combine procedure to work with the sparse format of scattering data --- src/mgxs_header.F90 | 461 ++++++++++++++++++++++++--------------- src/scattdata_header.F90 | 395 +++++++++++++++++++++------------ 2 files changed, 543 insertions(+), 313 deletions(-) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 7ed7f090c0..2986024021 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -380,18 +380,16 @@ module mgxs_header integer, intent(in) :: legendre_to_tabular_points ! Number of points to use ! in that conversion - character(MAX_LINE_LEN) :: temp_str - integer(HID_T) :: xsdata_grp, scatt_grp - real(8), allocatable :: temp_arr(:), temp_2d(:, :) - real(8), allocatable :: scatt_coeffs(:, :, :) - real(8), allocatable :: temp_scatt(:, :, :) - real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l, imu, length - type(VectorInt) :: temps_to_read - integer :: t - type(Jagged2D) :: input_scatt(:) - type(Jagged1D) :: temp_mult(:) - integer, allocatable :: gmin(:), gmax(:) + character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp, scatt_grp + real(8), allocatable :: temp_arr(:), temp_2d(:, :) + real(8) :: dmu, mu, norm + integer :: order, order_dim, gin, gout, l, imu, length + type(VectorInt) :: temps_to_read + integer :: t + type(Jagged2D), allocatable :: input_scatt(:), scatt_coeffs(:) + type(Jagged1D), allocatable :: temp_mult(:) + integer, allocatable :: gmin(:), gmax(:) ! Call generic data gathering routine (will populate the metadata) call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & @@ -480,28 +478,20 @@ module mgxs_header call fatal_error("Must provide absorption!") end if - ! Get multiplication data if present - allocate(temp_mult(groups, groups)) - if (check_dataset(xsdata_grp, "multiplicity matrix")) then - call read_dataset(temp_mult, xsdata_grp, "multiplicity matrix") - else - temp_mult(:, :) = ONE - end if - ! Get scattering data if (.not. check_group(xsdata_grp, "scatter data")) & call fatal_error("Must provide 'scatter data'") scatt_grp = open_group(xsdata_grp, 'scatter data') ! First get the outgoing group boundary indices if (check_dataset(xsdata_grp, "g_min")) then - allocate(g_min(groups)) - call read_dataset(g_min, scatt_grp, "g_min") + allocate(gmin(groups)) + call read_dataset(gmin, scatt_grp, "g_min") else call fatal_error("'g_min' for the scatter matrix must be provided") end if if (check_dataset(xsdata_grp, "g_max")) then - allocate(g_max(groups)) - call read_dataset(g_max, scatt_grp, "g_max") + allocate(gmax(groups)) + call read_dataset(gmax, scatt_grp, "g_max") else call fatal_error("'g_max' for the scatter matrix must be provided") end if @@ -510,11 +500,11 @@ module mgxs_header ! to hold the flattened data length = 0 do gin = 1, groups - length = length + order_dim * (g_max(gin) - gmin(gin) + 1) + length = length + order_dim * (gmax(gin) - gmin(gin) + 1) end do ! Allocate flattened array allocate(temp_arr(length)) - jf (.not. check_dataset(scatt_grp, 'scatter matrix') & + if (.not. check_dataset(scatt_grp, 'scatter matrix')) & call fatal_error("'scatter matrix' must be provided") call read_dataset(temp_arr, scatt_grp, "scatter matrix") @@ -542,7 +532,6 @@ module mgxs_header end if allocate(scatt_coeffs(gin)) - if (this % scatter_type == ANGLE_LEGENDRE .and. & legendre_to_tabular) then this % scatter_type = ANGLE_TABULAR @@ -576,7 +565,7 @@ module mgxs_header ! Now that we have the integral, lets ensure that the distribution ! is normalized such that it preserves the original scattering xs if (norm > ZERO) then - scatt_coeffs(gin) % data(i:, gout) = & + scatt_coeffs(gin) % data(:, gout) = & scatt_coeffs(gin) % data(:, gout) * & input_scatt(gin) % data(1, gout) end if @@ -597,11 +586,11 @@ module mgxs_header ! to hold the flattened data length = 0 do gin = 1, groups - length = length + (g_max(gin) - gmin(gin) + 1) + length = length + (gmax(gin) - gmin(gin) + 1) end do ! Allocate flattened array allocate(temp_arr(length)) - jf (.not. check_dataset(scatt_grp, 'multiplicity matrix') & + if (.not. check_dataset(scatt_grp, 'multiplicity matrix')) & call fatal_error("'multiplicity matrix' must be provided") call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") @@ -674,17 +663,16 @@ module mgxs_header integer, intent(in) :: legendre_to_tabular_points ! Number of points to use ! in that conversion - character(MAX_LINE_LEN) :: temp_str - integer(HID_T) :: xsdata_grp - real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) - real(8), allocatable :: temp_mult(:, :, :, :) - real(8), allocatable :: scatt_coeffs(:, :, :, :, :) - real(8), allocatable :: input_scatt(:, :, :, :, :) - real(8), allocatable :: temp_scatt(:, :, :, :, :) - real(8) :: dmu, mu, norm - integer :: order, order_dim, gin, gout, l, imu, ipol, iazi - type(VectorInt) :: temps_to_read - integer :: t + character(MAX_LINE_LEN) :: temp_str + integer(HID_T) :: xsdata_grp, scatt_grp + real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) + real(8) :: dmu, mu, norm + integer :: order, order_dim, gin, gout, l, imu + type(VectorInt) :: temps_to_read + integer :: t, length, ipol, iazi + type(Jagged2D), allocatable :: input_scatt(:, :, :), scatt_coeffs(:, :, :) + type(Jagged1D), allocatable :: temp_mult(:, :, :) + integer, allocatable :: gmin(:, :, :), gmax(:, :, :) ! Call generic data gathering routine (will populate the metadata) call mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & @@ -807,115 +795,167 @@ module mgxs_header call fatal_error("Must provide absorption!") end if - ! Get multiplication data if present - allocate(temp_mult(groups,groups, this % n_azi, this % n_pol)) - if (check_dataset(xsdata_grp, "multiplicity matrix")) then - call read_dataset(temp_mult, xsdata_grp, "multiplicity matrix") - else - temp_mult(:, :, :, :) = ONE - end if - ! Get scattering data - ! The input is gathered in the more user-friendly facing format of - ! Gout x Gin x Order x Azi x Pol. We will get it in that format in - ! input_scatt, but then need to convert it to a more useful ordering - ! for processing (Order x Gout x Gin x Azi x Pol). - allocate(input_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - if (check_dataset(xsdata_grp, "scatter matrix")) then - allocate(temp_arr(groups * groups * order_dim * this % n_azi * & - this % n_pol)) - call read_dataset(temp_arr, xsdata_grp, "scatter matrix") - input_scatt(:, :, :, :, :) = reshape(temp_arr, (/groups, groups, & - order_dim, this % n_azi, this % n_pol/)) - deallocate(temp_arr) - - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - - allocate(temp_scatt(groups, groups, order_dim, this % n_azi, & - this % n_pol)) - temp_scatt(:, :, :, :, :) = input_scatt(:, :, 1:order_dim, :, :) - - ! Take input format (groups, groups, order) and convert to - ! the more useful format needed for scattdata: (order, groups, groups) - ! However, if scatt_type was ANGLE_LEGENDRE (i.e., the data was - ! provided as Legendre coefficients), and the user requested that - ! these legendres be converted to tabular form (note xs is also - ! the default behavior), convert that now. - if (this % scatter_type == ANGLE_LEGENDRE .and. legendre_to_tabular) then - - ! Convert input parameters to what we need for the rest. - this % scatter_type = ANGLE_TABULAR - order_dim = legendre_to_tabular_points - order = order_dim - dmu = TWO / real(order - 1, 8) - - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - do gout = 1, groups - norm = ZERO - do imu = 1, order_dim - if (imu == 1) then - mu = -ONE - else if (imu == order_dim) then - mu = ONE - else - mu = -ONE + real(imu - 1, 8) * dmu - end if - scatt_coeffs(imu, gout, gin, iazi, ipol) = & - evaluate_legendre(temp_scatt(gout, gin, :, iazi, ipol), mu) - ! Ensure positivity of distribution - if (scatt_coeffs(imu, gout, gin, iazi, ipol) < ZERO) & - scatt_coeffs(imu, gout, gin, iazi, ipol) = ZERO - ! And accrue the integral - if (imu > 1) then - norm = norm + HALF * dmu * & - (scatt_coeffs(imu - 1, gout, gin, iazi, ipol) + & - scatt_coeffs(imu, gout, gin, iazi, ipol)) - end if - end do - ! Now that we have the integral, lets ensure that the distribution - ! is normalized such that it preserves the original scattering xs - if (norm > ZERO) then - scatt_coeffs(:, gout, gin, iazi, ipol) = & - scatt_coeffs(:, gout, gin, iazi, ipol) * & - temp_scatt(gout, gin, 1, iazi, ipol) / norm - end if - end do - end do - end do - end do - else - ! Sticking with current representation, carry forward but change - ! the array ordering - allocate(scatt_coeffs(order_dim, groups, groups, this % n_azi, & - this % n_pol)) - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - do gout = 1, groups - do l = 1, order_dim - scatt_coeffs(l, gout, gin, iazi, ipol) = & - temp_scatt(gout, gin, l, iazi, ipol) - end do - end do - end do - end do - end do - end if - deallocate(temp_scatt) + if (.not. check_group(xsdata_grp, "scatter data")) & + call fatal_error("Must provide 'scatter data'") + scatt_grp = open_group(xsdata_grp, 'scatter data') + ! First get the outgoing group boundary indices + if (check_dataset(xsdata_grp, "g_min")) then + allocate(gmin(groups, this % n_azi, this % n_pol)) + call read_dataset(gmin, scatt_grp, "g_min") else - call fatal_error("Must provide scatter matrix!") + call fatal_error("'g_min' for the scatter matrix must be provided") + end if + if (check_dataset(xsdata_grp, "g_max")) then + allocate(gmax(groups, this % n_azi, this % n_pol)) + call read_dataset(gmax, scatt_grp, "g_max") + else + call fatal_error("'g_max' for the scatter matrix must be provided") end if + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + length = length + order_dim * (gmax(gin, iazi, ipol) - & + gmin(gin, iazi, ipol) + 1) + end do + end do + end do + ! Allocate flattened array + allocate(temp_arr(length)) + if (.not. check_dataset(scatt_grp, 'scatter matrix')) & + call fatal_error("'scatter matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing + ! to ScattData + allocate(input_scatt(groups, this % n_azi, this % n_pol)) + index = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(input_scatt(gin, iazi, ipol) % data(order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do l = 1, order_dim + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + input_scatt(gin, iazi, ipol) % data(l, gout) = & + temp_arr(index) + index = index + 1 + end do ! gout + end do ! order + end do ! gin + end do ! iazi + end do ! ipol + deallocate(temp_arr) + + ! Finally convert the legendre to tabular if needed + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + + allocate(scatt_coeffs(gin, this % n_azi, this % n_pol)) + if (this % scatter_type == ANGLE_LEGENDRE .and. & + legendre_to_tabular) then + this % scatter_type = ANGLE_TABULAR + order_dim = legendre_to_tabular_points + order = order_dim + dmu = TWO / real(order - 1, 8) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(scatt_coeffs(gin, iazi, ipol) % data(& + order_dim, groups)) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + norm = ZERO + do imu = 1, order_dim + if (imu == 1) then + mu = -ONE + else if (imu == order_dim) then + mu = ONE + else + mu = -ONE + real(imu - 1, 8) * dmu + end if + scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = & + evaluate_legendre(& + input_scatt(gin, iazi, ipol) % data(:, gout), mu) + ! Ensure positivity of distribution + if (scatt_coeffs(gin, iazi, ipol) % data(imu, gout) < ZERO) & + scatt_coeffs(gin, iazi, ipol) % data(imu, gout) = ZERO + ! And accrue the integral + if (imu > 1) then + norm = norm + HALF * dmu * & + (scatt_coeffs(gin, iazi, ipol) % data(imu - 1, gout) + & + scatt_coeffs(gin, iazi, ipol) % data(imu, gout)) + end if + end do ! mu + ! Now that we have the integral, lets ensure that the distribution + ! is normalized such that it preserves the original scattering xs + if (norm > ZERO) then + scatt_coeffs(gin, iazi, ipol) % data(:, gout) = & + scatt_coeffs(gin, iazi, ipol) % data(:, gout) * & + input_scatt(gin, iazi, ipol) % data(1, gout) + end if + end do ! gout + end do ! gin + end do ! iazi + end do ! ipol + else + ! Sticking with current representation, carry forward but change + ! the array ordering + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, groups)) + scatt_coeffs(gin, iazi, ipol) % data(:, :) = & + input_scatt(gin, iazi, ipol) % data(:, :) + end do + end do + end do + end if + deallocate(input_scatt) + + ! Now get the multiplication matrix + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + length = length + (gmax(gin, iazi, ipol) - gmin(gin, iazi, ipol) + 1) + end do + end do + end do + ! Allocate flattened array + allocate(temp_arr(length)) + if (.not. check_dataset(scatt_grp, 'multiplicity matrix')) & + call fatal_error("'multiplicity matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups, this % n_azi, this % n_pol)) + index = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(temp_mult(gin, iazi, ipol) % data( & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + temp_mult(gin, iazi, ipol) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + end do + end do + deallocate(temp_arr) + + ! Allocate and initialize our ScattData Object. allocate(xs % scatter(this % n_azi, this % n_pol)) do ipol = 1, this % n_pol do iazi = 1, this % n_azi @@ -929,9 +969,22 @@ module mgxs_header end if ! Initialize the ScattData Object - call xs % scatter(iazi, ipol) % obj % init(& - temp_mult(:, :, iazi, ipol), & - scatt_coeffs(:, :, :, iazi, ipol)) + call xs % scatter(iazi, ipol) % obj % init(gmin(:, iazi, ipol), & + gmax(:, iazi, ipol), temp_mult(:, iazi, ipol), & + scatt_coeffs(:, iazi, ipol)) + end do + end do + + ! Check sigA to ensure it is not 0 since it is + ! often divided by in the tally routines + ! (This may happen with Helium data) + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + if (xs % absorption(gin, iazi, ipol) == ZERO) then + xs % absorption(gin, iazi, ipol) = 1E-10_8 + end if + end do end do end do @@ -947,6 +1000,18 @@ module mgxs_header end do end if + ! Finally, check sigT to ensure it is not 0 since it is + ! often divided by in the tally routines + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + if (xs % total(gin, iazi, ipol) == ZERO) then + xs % total(gin, iazi, ipol) = 1E-10_8 + end if + end do + end do + end do + ! Close the groups we have opened and deallocate call close_group(xsdata_grp) deallocate(input_scatt, scatt_coeffs, temp_mult) @@ -1087,6 +1152,10 @@ module mgxs_header integer :: nuc_t real(8) :: temp_actual, temp_desired integer :: scatter_type + type(Jagged2D), allocatable :: nuc_matrix(:) + integer, allocatable :: gmin(:), gmax(:) + type(Jagged2D), allocatable :: jagged_scatt(:) + type(Jagged1D), allocatable :: jagged_mult(:) ! Set the meta-data call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & @@ -1170,7 +1239,13 @@ module mgxs_header end if end if - ! Get the multiplication matrix + ! We will next gather the multiplicaity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. + + ! Get the multiplicity matrix ! To combine from nuclidic data we need to use the final relationship ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) @@ -1199,10 +1274,18 @@ module mgxs_header ! Get the complete scattering matrix nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :) + & - atom_density * & - nuc % xs(nuc_t) % scatter % get_matrix(min(nuc_order_dim, order_dim)) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter % get_matrix(nuc_order_dim, & + nuc_matrix) + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), & + nuc % xs(nuc_t) % scatter % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin) = & + scatt_coeffs(1: nuc_order_dim, gout, gin) + & + atom_density * nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do + end do + type is (MgxsAngle) call fatal_error("Invalid passing of MgxsAngle to MgxsIso object") end select @@ -1218,8 +1301,13 @@ module mgxs_header end do end do + ! Now create our jagged data from the dense data + call jagged_from_dense_2D(scatt_coeffs, jagged_scatt) + call jagged_from_dense_1D(temp_mult, jagged_mult, gmin, gmax) + ! Initialize the ScattData Object - call this % xs(t) % scatter % init_from_dense(temp_mult, scatt_coeffs) + call this % xs(t) % scatter % init(gmin, gmax, jagged_mult, & + jagged_scatt) ! Now normalize chi if (mat % fissionable) then @@ -1232,7 +1320,8 @@ module mgxs_header end if ! Deallocate temporaries - deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) + deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & + temp_mult, mult_num, mult_denom) end associate ! nuc end do NUC_LOOP end do TEMP_LOOP @@ -1262,6 +1351,10 @@ module mgxs_header integer :: nuc_t real(8) :: temp_actual, temp_desired integer :: scatter_type + type(Jagged2D), allocatable :: nuc_matrix(:) + integer, allocatable :: gmin(:), gmax(:) + type(Jagged2D), allocatable :: jagged_scatt(:) + type(Jagged1D), allocatable :: jagged_mult(:) ! Set the meta-data call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & @@ -1375,7 +1468,13 @@ module mgxs_header end if end if - ! Get the multiplication matrix + ! We will next gather the multiplicaity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. + + ! Get the multiplicity matrix ! To combine from nuclidic data we need to use the final relationship ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) @@ -1411,20 +1510,31 @@ module mgxs_header ! Get the complete scattering matrix nuc_order_dim = & - size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % dist(1) % data, dim=1) - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) = & - scatt_coeffs(1:min(nuc_order_dim, order_dim), :, :, iazi, ipol) + & - atom_density * & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % get_matrix(min(nuc_order_dim, order_dim)) - end do - end do + size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + dist(1) % data, dim=1) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + get_matrix(nuc_order_dim, nuc_matrix) + do gin = 1, groups + do gout = & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin, iazi, ipol) = & + scatt_coeffs(1: nuc_order_dim, gout, gin, iazi, ipol) + & + atom_density * nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do ! gout + end do ! gin + end do ! iazi + end do ! ipol type is (MgxsIso) call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") end select - ! Obtain temp_mult + ! Obtain temp_mult, create jaged arrays and initialize the + ! ScattData object. do ipol = 1, n_pol do iazi = 1, n_azi + ! Obtain temp_mult do gin = 1, groups do gout = 1, groups if (mult_denom(gout, gin, iazi, ipol) > ZERO) then @@ -1436,15 +1546,17 @@ module mgxs_header end if end do end do - end do - end do - ! Initialize the ScattData Object - do ipol = 1, n_pol - do iazi = 1, n_azi - call this % xs(t) % scatter(iazi, ipol) % obj % init_from_dense(& - temp_mult(:, :, iazi, ipol), & - scatt_coeffs(:, :, :, iazi, ipol)) + ! Create the Jagged arrays + call jagged_from_dense_2D(scatt_coeffs(:, :, :, iazi, ipol), & + jagged_scatt) + call jagged_from_dense_1D(temp_mult(:, :, iazi, ipol), & + jagged_mult, gmin, gmax) + + ! Initialize the ScattData Object + ! Initialize the ScattData Object + call this % xs(t) % scatter(iazi, ipol) % obj % init(gmin, & + gmax, jagged_mult, jagged_scatt) end do end do @@ -1464,7 +1576,8 @@ module mgxs_header end if ! Deallocate temporaries - deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) + deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & + temp_mult, mult_num, mult_denom) end associate ! nuc end do NUC_LOOP end do TEMP_LOOP diff --git a/src/scattdata_header.F90 b/src/scattdata_header.F90 index 3bd29bb265..6dd104d5cd 100644 --- a/src/scattdata_header.F90 +++ b/src/scattdata_header.F90 @@ -41,21 +41,21 @@ module scattdata_header real(8), allocatable :: scattxs(:) ! Isotropic Sigma_{s,g_{in}} contains - procedure(scattdata_init_), deferred :: init ! Initializes ScattData - ! Initializes ScattData from a dense matrix - procedure(scattdata_init_dense_), deferred :: init_from_dense + procedure(scattdata_init_), deferred :: init ! Initializes ScattData procedure(scattdata_calc_f_), deferred :: calc_f ! Calculates f, given mu procedure(scattdata_sample_), deferred :: sample ! sample the scatter event procedure :: get_matrix => scattdata_get_matrix ! Rebuild scattering matrix end type ScattData abstract interface - subroutine scattdata_init_dense_(this, mult, coeffs) - import ScattData - class(ScattData), intent(inout) :: this ! Object to work with - real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix - real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use - end subroutine scattdata_init_dense_ + subroutine scattdata_init_(this, gmin, gmax, mult, coeffs) + import ScattData, Jagged1D, Jagged2D + class(ScattData), intent(inout) :: this ! Object to work with + integer, intent(in) :: gmin(:) ! Min Gout + integer, intent(in) :: gmax(:) ! Max Gout + type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix + type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use + end subroutine scattdata_init_ pure function scattdata_calc_f_(this, gin, gout, mu) result(f) import ScattData @@ -81,7 +81,7 @@ module scattdata_header ! Maximal value for rejection sampling from rectangle type(Jagged1D), allocatable :: max_val(:) ! (Gin % data(Gout)) contains - procedure :: init_from_dense => scattdatalegendre_init_from_dense + procedure :: init => scattdatalegendre_init procedure :: calc_f => scattdatalegendre_calc_f procedure :: sample => scattdatalegendre_sample end type ScattDataLegendre @@ -92,7 +92,7 @@ module scattdata_header ! Histogram of f(mu) (dist has CDF) type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) contains - procedure :: init_from_dense => scattdatahistogram_init_from_dense + procedure :: init => scattdatahistogram_init procedure :: calc_f => scattdatahistogram_calc_f procedure :: sample => scattdatahistogram_sample procedure :: get_matrix => scattdatahistogram_get_matrix @@ -104,7 +104,7 @@ module scattdata_header ! PDF of f(mu) (dist has CDF) type(Jagged2D), allocatable :: fmu(:) ! (Gin % data(Order/Nmu x Gout) contains - procedure :: init_from_dense => scattdatatabular_init_from_dense + procedure :: init => scattdatatabular_init procedure :: calc_f => scattdatatabular_calc_f procedure :: sample => scattdatatabular_sample procedure :: get_matrix => scattdatatabular_get_matrix @@ -124,13 +124,15 @@ contains ! SCATTDATA*_INIT builds the scattdata object !=============================================================================== - subroutine scattdata_init_from_dense(this, order, energy, mult) - class(ScattData), intent(inout) :: this ! Object to work on - integer, intent(in) :: order ! Data Order - real(8), intent(inout) :: energy(:, :) ! Energy Transfer Matrix - real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix + subroutine scattdata_init(this, order, gmin, gmax, energy, mult) + class(ScattData), intent(inout) :: this ! Object to work on + integer, intent(in) :: order ! Data Order + integer, intent(in) :: gmin(:) ! Min Gout + integer, intent(in) :: gmax(:) ! Max Gout + type(Jagged1D), intent(inout) :: energy(:) ! Energy Transfer Matrix + type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix - integer :: groups, gmin, gmax, gin + integer :: groups, gin real(8) :: norm groups = size(energy, dim=1) @@ -140,83 +142,79 @@ contains allocate(this % energy(groups)) allocate(this % mult(groups)) allocate(this % dist(groups)) - ! Use energy to find the gmin and gmax values - ! Also set energy values when doing it + + this % gmin = gmin + this % gmax = gmax + + ! Set the outgoing energy PDF values do gin = 1, groups ! Make sure energy is normalized (i.e., CDF is 1) - norm = sum(energy(:, gin)) - if (norm /= ZERO) energy(:, gin) = energy(:, gin) / norm - ! Find gmin by checking the P0 moment - do gmin = 1, groups - if (energy(gmin, gin) > ZERO) exit - end do - ! Find gmax by checking the P0 moment - do gmax = groups, 1, -1 - if (energy(gmax, gin) > ZERO) exit - end do - ! Treat the case of all zeros - if (gmin > gmax) then - gmin = gin - gmax = gin - ! By not changing energy(gin) here we are leaving it as zero - end if - allocate(this % energy(gin) % data(gmin:gmax)) - this % energy(gin) % data(gmin:gmax) = energy(gmin:gmax, gin) - allocate(this % mult(gin) % data(gmin:gmax)) - this % mult(gin) % data(gmin:gmax) = mult(gmin:gmax, gin) - allocate(this % dist(gin) % data(order, gmin:gmax)) + norm = sum(energy(gin) % data(:)) + if (norm /= ZERO) energy(gin) % data(:) = energy(gin) % data(:) / norm + ! Set the values + allocate(this % energy(gin) % data(gmin(gin):gmax(gin))) + this % energy(gin) % data(:) = energy(gin) % data(:) + allocate(this % mult(gin) % data(gmin(gin):gmax(gin))) + this % mult(gin) % data(:) = mult(gin) % data(:) + allocate(this % dist(gin) % data(order, gmin(gin):gmax(gin))) this % dist(gin) % data = ZERO - this % gmin(gin) = gmin - this % gmax(gin) = gmax end do - end subroutine scattdata_init_from_dense + end subroutine scattdata_init - subroutine scattdatalegendre_init_from_dense(this, mult, coeffs) - class(ScattDataLegendre), intent(inout) :: this ! Object to work on - real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix - real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use + subroutine scattdatalegendre_init(this, gmin, gmax, mult, coeffs) + class(ScattDataLegendre), intent(inout) :: this ! Object to work on + integer, intent(in) :: gmin(:) ! Min Gout + integer, intent(in) :: gmax(:) ! Max Gout + type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix + type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use real(8) :: dmu, mu, f, norm integer :: imu, Nmu, gout, gin, groups, order - real(8), allocatable :: energy(:, :) - real(8), allocatable :: matrix(:, :, :) + type(Jagged1D), allocatable :: energy(:) + type(Jagged2D), allocatable :: matrix(:) - groups = size(coeffs, dim=3) - order = size(coeffs, dim=1) + groups = size(coeffs) + order = size(coeffs(1) % data, dim=1) ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(order, groups, groups)) - matrix (:, :, :)= coeffs + allocate(matrix(groups)) + do gin = 1, groups + allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) + matrix(gin) % data = coeffs(gin) % data + end do ! Get scattxs value allocate(this % scattxs(groups)) ! Get this by summing the un-normalized P0 coefficient in matrix ! over all outgoing groups - this % scattxs(:) = sum(matrix(1, :, :), dim=1) + do gin = 1, groups + this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1) + end do - allocate(energy(groups, groups)) - energy(:, :) = ZERO + allocate(energy(groups)) ! Build energy transfer probability matrix from data in matrix ! while also normalizing matrix itself (making CDF of f(mu=1)=1) do gin = 1, groups - do gout = 1, groups - norm = matrix(1, gout, gin) - energy(gout, gin) = norm + allocate(energy(gin) % data(gmin(gin):gmax(gin))) + energy(gin) % data = ZERO + do gout = gmin(gin), gmax(gin) + norm = matrix(gin) % data(1, gout) + energy(gin) % data(gout) = norm if (norm /= ZERO) then - matrix(:, gout, gin) = matrix(:, gout, gin) / norm + matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm end if end do end do - call scattdata_init_from_dense(this, order, energy, mult) + call scattdata_init(this, order, gmin, gmax, energy, mult) allocate(this % max_val(groups)) ! Set dist values from matrix and initialize max_val do gin = 1, groups - do gout = this % gmin(gin), this % gmax(gin) - this % dist(gin) % data(:, gout) = matrix(:, gout, gin) + do gout = gmin(gin), gmax(gin) + this % dist(gin) % data(:, gout) = matrix(gin) % data(:, gout) end do - allocate(this % max_val(gin) % data(this % gmin(gin):this % gmax(gin))) + allocate(this % max_val(gin) % data(gmin(gin):gmax(gin))) this % max_val(gin) % data(:) = ZERO end do @@ -225,7 +223,7 @@ contains Nmu = 1001 dmu = TWO / real(Nmu - 1, 8) do gin = 1, groups - do gout = this % gmin(gin), this % gmax(gin) + do gout = gmin(gin), gmax(gin) do imu = 1, Nmu ! Update mu. Do first and last seperate to avoid float errors if (imu == 1) then @@ -246,46 +244,52 @@ contains this % max_val(gin) % data(gout) * 1.1_8 end do end do - end subroutine scattdatalegendre_init_from_dense + end subroutine scattdatalegendre_init - subroutine scattdatahistogram_init_from_dense(this, mult, coeffs) - class(ScattDataHistogram), intent(inout) :: this ! Object to work on - real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix - real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use + subroutine scattdatahistogram_init(this, gmin, gmax, mult, coeffs) + class(ScattDataHistogram), intent(inout) :: this ! Object to work on + integer, intent(in) :: gmin(:) ! Min Gout + integer, intent(in) :: gmax(:) ! Max Gout + type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix + type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use integer :: imu, gin, gout, groups, order real(8) :: norm - real(8), allocatable :: energy(:, :) - real(8), allocatable :: matrix(:, :, :) + type(Jagged1D), allocatable :: energy(:) + type(Jagged2D), allocatable :: matrix(:) - groups = size(coeffs, dim=3) - order = size(coeffs, dim=1) + groups = size(coeffs) + order = size(coeffs(1) % data, dim=1) ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(order, groups, groups)) - matrix(:, :, :) = coeffs + allocate(matrix(groups)) + do gin = 1, groups + allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) + matrix(gin) % data = coeffs(gin) % data + end do ! Get scattxs value allocate(this % scattxs(groups)) ! Get this by summing the un-normalized P0 coefficient in matrix ! over all outgoing groups - this % scattxs(:) = sum(sum(matrix(:, :, :), dim=1), dim=1) + do gin = 1, groups + this % scattxs(gin) = sum(matrix(gin) % data(1, :), dim=1) + end do - allocate(energy(groups, groups)) - energy(:, :) = ZERO + allocate(energy(groups)) ! Build energy transfer probability matrix from data in matrix ! while also normalizing matrix itself (making CDF of f(mu=1)=1) do gin = 1, groups do gout = 1, groups - norm = sum(matrix(:, gout, gin)) - energy(gout, gin) = norm + norm = sum(matrix(gin) % data(:, gout)) + energy(gin) % data(gout) = norm if (norm /= ZERO) then - matrix(:, gout, gin) = matrix(:, gout, gin) / norm + matrix(gin) % data(:, gout) = matrix(gin) % data(:, gout) / norm end if end do end do - call scattdata_init_from_dense(this, order, energy, mult) + call scattdata_init(this, order, gmin, gmax, energy, mult) allocate(this % mu(order)) this % dmu = TWO / real(order, 8) @@ -298,17 +302,16 @@ contains ! also saving the original histogram in fmu allocate(this % fmu(groups)) do gin = 1, groups - allocate(this % fmu(gin) % data(order, & - this % gmin(gin):this % gmax(gin))) - do gout = this % gmin(gin), this % gmax(gin) + allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) ! Store the histogram - this % fmu(gin) % data(:, gout) = matrix(:, gout, gin) + this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout) ! Integrate the histogram this % dist(gin) % data(1, gout) = & - this % dmu * matrix(1, gout, gin) + this % dmu * matrix(gin) % data(1, gout) do imu = 2, order this % dist(gin) % data(imu, gout) = & - this % dmu * matrix(imu, gout, gin) + & + this % dmu * matrix(gin) % data(imu, gout) + & this % dist(gin) % data(imu - 1, gout) end do @@ -323,24 +326,29 @@ contains end do end do - end subroutine scattdatahistogram_init_from_dense + end subroutine scattdatahistogram_init - subroutine scattdatatabular_init_from_dense(this, mult, coeffs) - class(ScattDataTabular), intent(inout) :: this ! Object to work on - real(8), intent(in) :: mult(:, :) ! Scatter Prod'n Matrix - real(8), intent(in) :: coeffs(:, :, :) ! Coefficients to use + subroutine scattdatatabular_init(this, gmin, gmax, mult, coeffs) + class(ScattDataTabular), intent(inout) :: this ! Object to work on + integer, intent(in) :: gmin(:) ! Min Gout + integer, intent(in) :: gmax(:) ! Max Gout + type(Jagged1D), intent(in) :: mult(:) ! Scatter Prod'n Matrix + type(Jagged2D), intent(in) :: coeffs(:) ! Coefficients to use integer :: imu, gin, gout, groups, order real(8) :: norm - real(8), allocatable :: energy(:, :) - real(8), allocatable :: matrix(:, :, :) + type(Jagged1D), allocatable :: energy(:) + type(Jagged2D), allocatable :: matrix(:) - groups = size(coeffs, dim=3) - order = size(coeffs, dim=1) + groups = size(coeffs) + order = size(coeffs(1) % data, dim=1) ! make a copy of coeffs that we can use to extract data and normalize - allocate(matrix(order, groups, groups)) - matrix(:, :, :) = coeffs + allocate(matrix(groups)) + do gin = 1, groups + allocate(matrix(gin) % data(order, gmin(gin):gmax(gin))) + matrix(gin) % data = coeffs(gin) % data + end do ! Build the angular distribution mu values allocate(this % mu(order)) @@ -358,39 +366,39 @@ contains ! over all outgoing groups do gin = 1, groups norm = ZERO - do gout = 1, groups + do gout = gmin(gin), gmax(gin) do imu = 2, order - norm = norm + HALF * this % dmu * (matrix(imu - 1, gout, gin) + & - matrix(imu, gout, gin)) + norm = norm + HALF * this % dmu * & + (matrix(gin) % data(imu - 1, gout) + & + matrix(gin) % data(imu, gout)) end do end do this % scattxs(gin) = norm end do - allocate(energy(groups, groups)) - energy(:, :) = ZERO + allocate(energy(groups)) ! Build energy transfer probability matrix from data in matrix do gin = 1, groups - do gout = 1, groups + do gout = gmin(gin), gmax(gin) norm = ZERO do imu = 2, order norm = norm + HALF * this % dmu * & - (matrix(imu - 1, gout, gin) + matrix(imu, gout, gin)) + (matrix(gin) % data(imu - 1, gout) + & + matrix(gin) % data(imu, gout)) end do - energy(gout, gin) = norm + energy(gin) % data(gout) = norm end do end do - call scattdata_init_from_dense(this, order, energy, mult) + call scattdata_init(this, order, gmin, gmax, energy, mult) ! Calculate f(mu) and integrate it so we can avoid rejection sampling allocate(this % fmu(groups)) do gin = 1, groups - allocate(this % fmu(gin) % data(order, & - this % gmin(gin):this % gmax(gin))) - do gout = this % gmin(gin), this % gmax(gin) + allocate(this % fmu(gin) % data(order, gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) ! Coeffs contain f(mu), put in f(mu) as that is where the ! PDF lives - this % fmu(gin) % data(:, gout) = matrix(:, gout, gin) + this % fmu(gin) % data(:, gout) = matrix(gin) % data(:, gout) ! Force positivity do imu = 1, order @@ -417,7 +425,7 @@ contains end if end do end do - end subroutine scattdatatabular_init_from_dense + end subroutine scattdatatabular_init !=============================================================================== ! SCATTDATA_*_CALC_F Calculates the value of f given mu (and gin,gout pair) @@ -642,10 +650,10 @@ contains ! using ScattData's information of fmu/dist, energy, and scattxs !=============================================================================== - pure function scattdata_get_matrix(this, req_order) result(matrix) - class(ScattData), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built + subroutine scattdata_get_matrix(this, req_order, matrix) + class(ScattData), intent(in) :: this ! Scattering Object to work with + integer, intent(in) :: req_order ! Requested order of matrix + type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built integer :: order, groups, gin, gout @@ -653,66 +661,175 @@ contains ! Set gin and gout for getting the order order = min(req_order, size(this % dist(1) % data, dim=1)) - allocate(matrix(order, groups, groups)) + if (allocated(matrix)) deallocate(matrix) + allocate(matrix(groups)) ! Initialize to 0; this way the zero entries in the dense matrix dont ! need to be explicitly set, requiring a significant increase in the ! lines of code. - matrix(:, :, :) = ZERO do gin = 1, groups + allocate(matrix(gin) % data(order, groups)) do gout = this % gmin(gin), this % gmax(gin) - matrix(:, gout, gin) = this % scattxs(gin) * & + matrix(gin) % data(:, gout) = this % scattxs(gin) * & this % energy(gin) % data(gout) * & this % dist(gin) % data(1:order, gout) end do end do - end function scattdata_get_matrix + end subroutine scattdata_get_matrix - pure function scattdatahistogram_get_matrix(this, req_order) result(matrix) - class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built + subroutine scattdatahistogram_get_matrix(this, req_order, matrix) + class(ScattDataHistogram), intent(in) :: this ! Scattering Object to work with + integer, intent(in) :: req_order ! Requested order of matrix + type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built integer :: order, groups, gin, gout groups = size(this % energy) order = min(req_order, size(this % dist(1) % data, dim=1)) - allocate(matrix(order, groups, groups)) + if (allocated(matrix)) deallocate(matrix) + allocate(matrix(groups)) ! Initialize to 0; this way the zero entries in the dense matrix dont ! need to be explicitly set, requiring a significant increase in the ! lines of code. - matrix(:, :, :) = ZERO do gin = 1, groups + allocate(matrix(gin) % data(order, groups)) do gout = this % gmin(gin), this % gmax(gin) - matrix(:, gout, gin) = this % scattxs(gin) * & + matrix(gin) % data(:, gout) = this % scattxs(gin) * & this % energy(gin) % data(gout) * & this % fmu(gin) % data(1:order, gout) end do end do - end function scattdatahistogram_get_matrix + end subroutine scattdatahistogram_get_matrix - pure function scattdatatabular_get_matrix(this, req_order) result(matrix) - class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with - integer, intent(in) :: req_order ! Requested order of matrix - real(8), allocatable :: matrix(:, :, :) ! Resultant matrix just built + subroutine scattdatatabular_get_matrix(this, req_order, matrix) + class(ScattDataTabular), intent(in) :: this ! Scattering Object to work with + integer, intent(in) :: req_order ! Requested order of matrix + type(Jagged2D), allocatable, intent(inout) :: matrix(:) ! Resultant matrix just built integer :: order, groups, gin, gout groups = size(this % energy) order = min(req_order, size(this % dist(1) % data, dim=1)) - allocate(matrix(order, groups, groups)) + if (allocated(matrix)) deallocate(matrix) + allocate(matrix(groups)) ! Initialize to 0; this way the zero entries in the dense matrix dont ! need to be explicitly set, requiring a significant increase in the ! lines of code. - matrix(:, :, :) = ZERO do gin = 1, groups + allocate(matrix(gin) % data(order, groups)) do gout = this % gmin(gin), this % gmax(gin) - matrix(:, gout, gin) = this % scattxs(gin) * & + matrix(gin) % data(:, gout) = this % scattxs(gin) * & this % energy(gin) % data(gout) * & this % fmu(gin) % data(1:order, gout) end do end do - end function scattdatatabular_get_matrix + end subroutine scattdatatabular_get_matrix + +!=============================================================================== +! JAGGED_FROM_DENSE_*D Creates a jagged array from a sparse dense matrix. +! The user can supply a key which indicates the values to remove, but the +! default is ZERO +!=============================================================================== + + subroutine jagged_from_dense_1D(dense, jagged, lo_bounds, hi_bounds, key_) + real(8), intent(in) :: dense(:, :) + type(Jagged1D), allocatable, intent(inout) :: jagged(:) + real(8), intent(in), optional :: key_ + integer, intent(inout), allocatable, optional :: lo_bounds(:) + integer, intent(inout), allocatable, optional :: hi_bounds(:) + + real(8) :: key + integer :: i, jmin, jmax + + if (present(key_)) then + key = key_ + else + key = ZERO + end if + + if (present(lo_bounds)) then + if (allocated(lo_bounds)) deallocate(lo_bounds) + allocate(lo_bounds(size(dense, dim=2))) + end if + if (present(hi_bounds)) then + if (allocated(hi_bounds)) deallocate(hi_bounds) + allocate(hi_bounds(size(dense, dim=2))) + end if + + allocate(jagged(size(dense, dim=2))) + do i = 1, size(dense, dim=2) + ! Find the min and max j values + do jmin = 1, size(dense, dim=1) + if (dense(jmin, i) > key) exit + end do + do jmax = size(dense, dim=1), 1, -1 + if (dense(jmax, i) > key) exit + end do + ! Treat the case of all values matching the key + if (jmin > jmax) then + jmin = i + jmax = i + end if + + ! Now store the jagged row + allocate(jagged(i) % data(jmin:jmax)) + jagged(i) % data(jmin:jmax) = dense(jmin:jmax, i) + + if (present(lo_bounds)) lo_bounds(i) = jmin + if (present(hi_bounds)) hi_bounds(i) = jmax + end do + + end subroutine jagged_from_dense_1D + + subroutine jagged_from_dense_2D(dense, jagged, lo_bounds, hi_bounds, key_) + real(8), intent(in) :: dense(:, :, :) + type(Jagged2D), allocatable, intent(inout) :: jagged(:) + real(8), intent(in), optional :: key_ + integer, intent(inout), allocatable, optional :: lo_bounds(:) + integer, intent(inout), allocatable, optional :: hi_bounds(:) + + real(8) :: key + integer :: i, jmin, jmax + + if (present(key_)) then + key = key_ + else + key = ZERO + end if + + if (present(lo_bounds)) then + if (allocated(lo_bounds)) deallocate(lo_bounds) + allocate(lo_bounds(size(dense, dim=3))) + end if + if (present(hi_bounds)) then + if (allocated(hi_bounds)) deallocate(hi_bounds) + allocate(hi_bounds(size(dense, dim=3))) + end if + + allocate(jagged(size(dense, dim=3))) + do i = 1, size(dense, dim=3) + ! Find the min and max j values + do jmin = 1, size(dense, dim=1) + if (sum(dense(:, jmin, i)) > key) exit + end do + do jmax = size(dense, dim=1), 1, -1 + if (sum(dense(:, jmax, i)) > key) exit + end do + ! Treat the case of all values matching the key + if (jmin > jmax) then + jmin = i + jmax = i + end if + + ! Now store the jagged row + allocate(jagged(i) % data(size(dense, dim=1), jmin:jmax)) + jagged(i) % data(:, jmin:jmax) = dense(:, jmin:jmax, i) + + if (present(lo_bounds)) lo_bounds(i) = jmin + if (present(hi_bounds)) hi_bounds(i) = jmax + end do + + end subroutine jagged_from_dense_2D end module scattdata_header From a235aa8cbad878a7e0b4c995287a0e399ed06efc Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Fri, 9 Sep 2016 20:39:05 -0400 Subject: [PATCH 14/82] Progressively fixing bugs, last one seems to be tabular representation doesnt produce correct results anymore --- .../pythonapi/examples/mgxs-part-iv.ipynb | 213 ++++++++++-------- openmc/mgxs_library.py | 61 +++-- openmc/settings.py | 5 +- src/mgxs_header.F90 | 61 ++--- src/scattdata_header.F90 | 83 ++++--- tests/1d_mgxs.h5 | Bin 100568 -> 123864 bytes 6 files changed, 226 insertions(+), 197 deletions(-) diff --git a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb index 301bbf0155..a4f4069516 100644 --- a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb +++ b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb @@ -431,7 +431,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "" ] @@ -577,7 +577,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/romano/openmc/openmc/mgxs/library.py:373: RuntimeWarning: The P0 correction will be ignored since the scattering order 0 is greater than zero\n", + "/home/nelsonag/git/openmc/openmc/mgxs/library.py:373: RuntimeWarning: The P0 correction will be ignored since the scattering order 0 is greater than zero\n", " warn(msg, RuntimeWarning)\n" ] } @@ -734,8 +734,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | fbebf7bf709fe2fe1813af95bff9b29c0d59312c\n", - " Date/Time | 2016-08-31 10:48:01\n", + " Git SHA1 | 6cf7f7fa48d70d26165403f8067aedb598534990\n", + " Date/Time | 2016-09-08 20:16:34\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -746,12 +746,12 @@ " Reading geometry XML file...\n", " Reading cross sections XML file...\n", " Reading materials XML file...\n", - " Reading U235 from /home/romano/openmc/data/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/romano/openmc/data/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/romano/openmc/data/nndc_hdf5/O16.h5\n", - " Reading Zr90 from /home/romano/openmc/data/nndc_hdf5/Zr90.h5\n", - " Reading H1 from /home/romano/openmc/data/nndc_hdf5/H1.h5\n", - " Reading B10 from /home/romano/openmc/data/nndc_hdf5/B10.h5\n", + " Reading U235 from /opt/xsdata/nndc/U235.h5\n", + " Reading U238 from /opt/xsdata/nndc/U238.h5\n", + " Reading O16 from /opt/xsdata/nndc/O16.h5\n", + " Reading Zr90 from /opt/xsdata/nndc/Zr90.h5\n", + " Reading H1 from /opt/xsdata/nndc/H1.h5\n", + " Reading B10 from /opt/xsdata/nndc/B10.h5\n", " Maximum neutron transport energy: 20.0000 MeV for U235\n", " Reading tallies XML file...\n", " Building neighboring cells lists for each surface...\n", @@ -822,20 +822,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 4.2200E-01 seconds\n", - " Reading cross sections = 2.8800E-01 seconds\n", - " Total time in simulation = 4.1409E+01 seconds\n", - " Time in transport only = 4.1265E+01 seconds\n", - " Time in inactive batches = 4.6120E+00 seconds\n", - " Time in active batches = 3.6797E+01 seconds\n", - " Time synchronizing fission bank = 9.0000E-03 seconds\n", - " Sampling source sites = 6.0000E-03 seconds\n", - " SEND/RECV source sites = 3.0000E-03 seconds\n", + " Total time for initialization = 3.2700E-01 seconds\n", + " Reading cross sections = 2.1500E-01 seconds\n", + " Total time in simulation = 2.2139E+01 seconds\n", + " Time in transport only = 2.1970E+01 seconds\n", + " Time in inactive batches = 2.6960E+00 seconds\n", + " Time in active batches = 1.9443E+01 seconds\n", + " Time synchronizing fission bank = 2.0000E-03 seconds\n", + " Sampling source sites = 1.0000E-03 seconds\n", + " SEND/RECV source sites = 1.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 4.1869E+01 seconds\n", - " Calculation Rate (inactive) = 10841.3 neutrons/second\n", - " Calculation Rate (active) = 5435.23 neutrons/second\n", + " Total time elapsed = 2.2488E+01 seconds\n", + " Calculation Rate (inactive) = 18546.0 neutrons/second\n", + " Calculation Rate (active) = 10286.5 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -973,13 +973,26 @@ "metadata": { "collapsed": false }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(array([0, 1]),)\n", + "(array([0, 1]),)\n", + "(array([0, 1]),)\n", + "(array([0, 1]),)\n", + "(array([0, 1]),)\n", + "(array([0, 1]),)\n" + ] + } + ], "source": [ "# Create a MGXS File which can then be written to disk\n", "mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=['fuel', 'zircaloy', 'water'])\n", "\n", "# Write the file to disk using the default filename of `mgxs.xml`\n", - "mgxs_file.export_to_xml()" + "mgxs_file.export_to_hdf5()" ] }, { @@ -1051,7 +1064,7 @@ "outputs": [], "source": [ "# Set the location of the cross sections file\n", - "settings_file.cross_sections = './mgxs.xml'\n", + "settings_file.cross_sections = './mgxs.h5'\n", "settings_file.energy_mode = 'multi-group'\n", "\n", "# Export to \"settings.xml\"\n", @@ -1108,8 +1121,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | fbebf7bf709fe2fe1813af95bff9b29c0d59312c\n", - " Date/Time | 2016-08-31 10:48:43\n", + " Git SHA1 | 6cf7f7fa48d70d26165403f8067aedb598534990\n", + " Date/Time | 2016-09-08 20:16:57\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -1118,14 +1131,14 @@ "\n", " Reading settings XML file...\n", " Reading geometry XML file...\n", - " Reading cross sections XML file...\n", + " Reading cross sections HDF5 file...\n", " Reading materials XML file...\n", " Reading tallies XML file...\n", - " Building neighboring cells lists for each surface...\n", " Loading Cross Section Data...\n", " Loading fuel Data...\n", " Loading zircaloy Data...\n", " Loading water Data...\n", + " Building neighboring cells lists for each surface...\n", " Initializing source particles...\n", "\n", " ===========================================================================\n", @@ -1134,56 +1147,56 @@ "\n", " Bat./Gen. k Average k \n", " ========= ======== ==================== \n", - " 1/1 0.99122 \n", - " 2/1 1.03963 \n", - " 3/1 1.01551 \n", - " 4/1 1.03582 \n", - " 5/1 0.99023 \n", - " 6/1 1.00419 \n", - " 7/1 1.02047 \n", - " 8/1 1.05456 \n", - " 9/1 1.01063 \n", - " 10/1 1.03370 \n", - " 11/1 1.04616 \n", - " 12/1 1.04458 1.04537 +/- 0.00079\n", - " 13/1 1.02171 1.03748 +/- 0.00790\n", - " 14/1 1.02060 1.03326 +/- 0.00700\n", - " 15/1 1.01653 1.02992 +/- 0.00637\n", - " 16/1 1.02956 1.02986 +/- 0.00520\n", - " 17/1 1.01145 1.02723 +/- 0.00512\n", - " 18/1 1.03774 1.02854 +/- 0.00463\n", - " 19/1 1.00829 1.02629 +/- 0.00466\n", - " 20/1 1.03624 1.02729 +/- 0.00429\n", - " 21/1 1.03296 1.02780 +/- 0.00391\n", - " 22/1 0.99315 1.02491 +/- 0.00459\n", - " 23/1 0.99628 1.02271 +/- 0.00476\n", - " 24/1 1.04034 1.02397 +/- 0.00459\n", - " 25/1 1.02523 1.02406 +/- 0.00427\n", - " 26/1 1.07905 1.02749 +/- 0.00527\n", - " 27/1 1.01678 1.02686 +/- 0.00499\n", - " 28/1 1.01817 1.02638 +/- 0.00473\n", - " 29/1 1.03293 1.02672 +/- 0.00449\n", - " 30/1 1.01224 1.02600 +/- 0.00432\n", - " 31/1 1.01524 1.02549 +/- 0.00414\n", - " 32/1 1.00996 1.02478 +/- 0.00401\n", - " 33/1 1.05545 1.02612 +/- 0.00406\n", - " 34/1 1.02082 1.02589 +/- 0.00389\n", - " 35/1 0.99120 1.02451 +/- 0.00398\n", - " 36/1 1.03012 1.02472 +/- 0.00383\n", - " 37/1 1.01179 1.02424 +/- 0.00372\n", - " 38/1 1.04023 1.02481 +/- 0.00363\n", - " 39/1 1.05876 1.02598 +/- 0.00369\n", - " 40/1 0.99332 1.02490 +/- 0.00373\n", - " 41/1 1.05319 1.02581 +/- 0.00372\n", - " 42/1 1.03381 1.02606 +/- 0.00361\n", - " 43/1 1.00607 1.02545 +/- 0.00355\n", - " 44/1 1.03957 1.02587 +/- 0.00347\n", - " 45/1 1.02472 1.02584 +/- 0.00337\n", - " 46/1 1.00948 1.02538 +/- 0.00331\n", - " 47/1 1.02380 1.02534 +/- 0.00322\n", - " 48/1 1.05392 1.02609 +/- 0.00322\n", - " 49/1 1.01171 1.02572 +/- 0.00316\n", - " 50/1 1.03942 1.02606 +/- 0.00310\n", + " 1/1 0.68770 \n", + " 2/1 0.71454 \n", + " 3/1 0.69764 \n", + " 4/1 0.68400 \n", + " 5/1 0.69412 \n", + " 6/1 0.70489 \n", + " 7/1 0.70203 \n", + " 8/1 0.70721 \n", + " 9/1 0.69408 \n", + " 10/1 0.70103 \n", + " 11/1 0.69351 \n", + " 12/1 0.71450 0.70401 +/- 0.01049\n", + " 13/1 0.70298 0.70366 +/- 0.00607\n", + " 14/1 0.69351 0.70113 +/- 0.00499\n", + " 15/1 0.70901 0.70270 +/- 0.00417\n", + " 16/1 0.70364 0.70286 +/- 0.00341\n", + " 17/1 0.68831 0.70078 +/- 0.00355\n", + " 18/1 0.69861 0.70051 +/- 0.00309\n", + " 19/1 0.71634 0.70227 +/- 0.00324\n", + " 20/1 0.70641 0.70268 +/- 0.00293\n", + " 21/1 0.69300 0.70180 +/- 0.00279\n", + " 22/1 0.70086 0.70172 +/- 0.00255\n", + " 23/1 0.68664 0.70056 +/- 0.00262\n", + " 24/1 0.70558 0.70092 +/- 0.00245\n", + " 25/1 0.70057 0.70090 +/- 0.00228\n", + " 26/1 0.68193 0.69971 +/- 0.00244\n", + " 27/1 0.69492 0.69943 +/- 0.00231\n", + " 28/1 0.68723 0.69875 +/- 0.00228\n", + " 29/1 0.71304 0.69950 +/- 0.00228\n", + " 30/1 0.69086 0.69907 +/- 0.00221\n", + " 31/1 0.71083 0.69963 +/- 0.00218\n", + " 32/1 0.69658 0.69949 +/- 0.00208\n", + " 33/1 0.70807 0.69987 +/- 0.00202\n", + " 34/1 0.71266 0.70040 +/- 0.00201\n", + " 35/1 0.69799 0.70030 +/- 0.00193\n", + " 36/1 0.67602 0.69937 +/- 0.00207\n", + " 37/1 0.72219 0.70021 +/- 0.00217\n", + " 38/1 0.71427 0.70072 +/- 0.00215\n", + " 39/1 0.71017 0.70104 +/- 0.00210\n", + " 40/1 0.69683 0.70090 +/- 0.00203\n", + " 41/1 0.71530 0.70137 +/- 0.00202\n", + " 42/1 0.69487 0.70116 +/- 0.00197\n", + " 43/1 0.69785 0.70106 +/- 0.00191\n", + " 44/1 0.72084 0.70165 +/- 0.00194\n", + " 45/1 0.69741 0.70152 +/- 0.00189\n", + " 46/1 0.70040 0.70149 +/- 0.00183\n", + " 47/1 0.71724 0.70192 +/- 0.00183\n", + " 48/1 0.70980 0.70213 +/- 0.00180\n", + " 49/1 0.70660 0.70224 +/- 0.00175\n", + " 50/1 0.69329 0.70202 +/- 0.00172\n", " Creating state point statepoint.50.h5...\n", "\n", " ===========================================================================\n", @@ -1193,27 +1206,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 4.1000E-02 seconds\n", - " Reading cross sections = 4.0000E-03 seconds\n", - " Total time in simulation = 3.1713E+01 seconds\n", - " Time in transport only = 3.1522E+01 seconds\n", - " Time in inactive batches = 3.8940E+00 seconds\n", - " Time in active batches = 2.7819E+01 seconds\n", - " Time synchronizing fission bank = 2.1000E-02 seconds\n", - " Sampling source sites = 1.2000E-02 seconds\n", - " SEND/RECV source sites = 9.0000E-03 seconds\n", + " Total time for initialization = 3.5000E-02 seconds\n", + " Reading cross sections = 6.0000E-03 seconds\n", + " Total time in simulation = 3.7004E+01 seconds\n", + " Time in transport only = 3.6761E+01 seconds\n", + " Time in inactive batches = 3.6530E+00 seconds\n", + " Time in active batches = 3.3351E+01 seconds\n", + " Time synchronizing fission bank = 7.0000E-03 seconds\n", + " Sampling source sites = 6.0000E-03 seconds\n", + " SEND/RECV source sites = 1.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 3.1791E+01 seconds\n", - " Calculation Rate (inactive) = 12840.3 neutrons/second\n", - " Calculation Rate (active) = 7189.33 neutrons/second\n", + " Total time elapsed = 3.7062E+01 seconds\n", + " Calculation Rate (inactive) = 13687.4 neutrons/second\n", + " Calculation Rate (active) = 5996.82 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.02474 +/- 0.00282\n", - " k-effective (Track-length) = 1.02606 +/- 0.00310\n", - " k-effective (Absorption) = 1.02589 +/- 0.00165\n", - " Combined k-effective = 1.02601 +/- 0.00170\n", + " k-effective (Collision) = 0.70328 +/- 0.00159\n", + " k-effective (Track-length) = 0.70202 +/- 0.00172\n", + " k-effective (Absorption) = 0.70409 +/- 0.00106\n", + " Combined k-effective = 0.70345 +/- 0.00102\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -1295,8 +1308,8 @@ "output_type": "stream", "text": [ "Continuous-Energy keff = 1.024295\n", - "Multi-Group keff = 1.026013\n", - "bias [pcm]: -171.8\n" + "Multi-Group keff = 0.703447\n", + "bias [pcm]: 32084.7\n" ] } ], @@ -1393,7 +1406,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 40, @@ -1402,9 +1415,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index eaf66d1200..2079b88015 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1191,20 +1191,20 @@ class XSdata(object): 'writing the HDF5 library') # Get the sparse scattering data to print to the library G = self.energy_groups.num_groups - if self.representation is 'isotropic': + if self.representation == 'isotropic': g_out_bounds = np.zeros((G, 2), dtype=np.int) for g_in in range(G): nz = np.nonzero(self._scatter_matrix[i][0, g_in, :]) - g_out_bounds[g_in, 0] = nz[0] - g_out_bounds[g_in, 1] = nz[-1] + g_out_bounds[g_in, 0] = nz[0][0] + g_out_bounds[g_in, 1] = nz[0][-1] # Now create the flattened scatter matrix array + matrix = self._scatter_matrix[i] flat_scatt = [] - for l in range(self._scatter_matrix[i].shape[0]): - for g_in in range(G): - matrix = self._scatter_matrix[i][l, g_in, :] - for g_out in range(g_out_bounds[g_in, 0], - g_out_bounds[g_in, 1] + 1): - flat_scatt.append(matrix[g_out]) + for g_in in range(G): + for g_out in range(g_out_bounds[g_in, 0], + g_out_bounds[g_in, 1] + 1): + for l in range(len(matrix[:, g_in, g_out])): + flat_scatt.append(matrix[l, g_in, g_out]) # And write it. scatt_grp = xsgrp.create_group('scatter data') scatt_grp.create_dataset("scatter matrix", @@ -1213,12 +1213,12 @@ class XSdata(object): # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: # Now create the flattened scatter matrix array + matrix = self._multiplicity_matrix[i][:, :] flat_mult = [] for g_in in range(G): - matrix = self._multiplicity_matrix[i][g_in, :] for g_out in range(g_out_bounds[g_in, 0], g_out_bounds[g_in, 1] + 1): - flat_mult.append(matrix[g_out]) + flat_mult.append(matrix[g_in, g_out]) scatt_grp.create_dataset("multiplicity matrix", data=np.array(flat_mult), compression=compression) @@ -1230,7 +1230,7 @@ class XSdata(object): scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1], compression=compression) - else: + elif self.representation == 'angle': Np = self.num_polar Na = self.num_azimuthal g_out_bounds = np.zeros((Np, Na, G, 2), dtype=np.int) @@ -1239,20 +1239,18 @@ class XSdata(object): for g_in in range(G): matrix = self._scatter_matrix[i][p, a, 0, g_in, :] nz = np.nonzero(matrix) - g_out_bounds[p, a, g_in, 0] = nz[0] - g_out_bounds[p, a, g_in, 1] = nz[-1] + g_out_bounds[p, a, g_in, 0] = nz[0][0] + g_out_bounds[p, a, g_in, 1] = nz[0][-1] # Now create the flattened scatter matrix array flat_scatt = [] for p in range(Np): for a in range(Na): - for l in range(self._scatter_matrix[i].shape[2]): - for g_in in range(G): - matrix = \ - self._scatter_matrix[i][p, a, 0, g_in, :] - for g_out in range(g_out_bounds[p, a, g_in, 0], - g_out_bounds[p, a, g_in, 1] - + 1): - flat_scatt.append(matrix[g_out]) + matrix = self._scatter_matrix[i][p, a, :, :, :] + for g_in in range(G): + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + 1): + for l in range(len(matrix[:, g_in, g_out])): + flat_scatt.append(matrix[l, g_in, g_out]) # And write it. scatt_grp = xsgrp.create_group('scatter data') scatt_grp.create_dataset("scatter matrix", @@ -1264,20 +1262,17 @@ class XSdata(object): flat_mult = [] for p in range(Np): for a in range(Na): - for l in range(self._scatter_matrix[i].shape[2]): - for g_in in range(G): - matrix = \ - self._multiplicity_matrix[i][p, a, g_in, :] - for g_out in range(g_out_bounds[p, a, g_in, 0], - g_out_bounds[p, a, g_in, 1] + 1): - flat_mult.append(matrix[g_out]) - scatt_grp.create_dataset("multiplicity matrix", - data=np.array(flat_mult), - compression=compression) + matrix = self._multiplicity_matrix[i][p, a, :, :] + for g_in in range(G): + for g_out in range(g_out_bounds[p, a, g_in, 0], + g_out_bounds[p, a, g_in, 1] + 1): + flat_mult.append(matrix[g_in, g_out]) # And finally, adjust g_out_bounds for 1-based group counting # and write it. g_out_bounds[:, :, :, :] += 1 - scatt_grp.create_dataset("g_out bounds", data=g_out_bounds, + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0], + compression=compression) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1], compression=compression) diff --git a/openmc/settings.py b/openmc/settings.py index 4a9e050426..14d89543f5 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1079,8 +1079,9 @@ class Settings(object): element = ET.SubElement(self._settings_file, "tabular_legendre") subelement = ET.SubElement(element, "enable") subelement.text = str(self._tabular_legendre['enable']).lower() - subelement = ET.SubElement(element, "num_points") - subelement.text = str(self._tabular_legendre['num_points']) + if 'num_points' in self._tabular_legendre: + subelement = ET.SubElement(element, "num_points") + subelement.text = str(self._tabular_legendre['num_points']) def _create_temperature_subelements(self): if self.temperature: diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 2986024021..51fb1384c2 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -403,7 +403,7 @@ module mgxs_header xsdata_grp = open_group(xs_id, trim(temp_str)) if (this % fissionable) then allocate(xs % nu_fission(groups)) - allocate(xs % chi(groups,groups)) + allocate(xs % chi(groups, groups)) if (check_dataset(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi @@ -483,13 +483,13 @@ module mgxs_header call fatal_error("Must provide 'scatter data'") scatt_grp = open_group(xsdata_grp, 'scatter data') ! First get the outgoing group boundary indices - if (check_dataset(xsdata_grp, "g_min")) then + if (check_dataset(scatt_grp, "g_min")) then allocate(gmin(groups)) call read_dataset(gmin, scatt_grp, "g_min") else call fatal_error("'g_min' for the scatter matrix must be provided") end if - if (check_dataset(xsdata_grp, "g_max")) then + if (check_dataset(scatt_grp, "g_max")) then allocate(gmax(groups)) call read_dataset(gmax, scatt_grp, "g_max") else @@ -514,8 +514,8 @@ module mgxs_header index = 1 do gin = 1, groups allocate(input_scatt(gin) % data(order_dim, gmin(gin):gmax(gin))) - do l = 1, order_dim - do gout = gmin(gin), gmax(gin) + do gout = gmin(gin), gmax(gin) + do l = 1, order_dim input_scatt(gin) % data(l, gout) = temp_arr(index) index = index + 1 end do @@ -531,7 +531,7 @@ module mgxs_header order_dim = order + 1 end if - allocate(scatt_coeffs(gin)) + allocate(scatt_coeffs(groups)) if (this % scatter_type == ANGLE_LEGENDRE .and. & legendre_to_tabular) then this % scatter_type = ANGLE_TABULAR @@ -539,7 +539,7 @@ module mgxs_header order = order_dim dmu = TWO / real(order - 1, 8) do gin = 1, groups - allocate(scatt_coeffs(gin) % data(order_dim, groups)) + allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) do gout = gmin(gin), gmax(gin) norm = ZERO do imu = 1, order_dim @@ -572,10 +572,9 @@ module mgxs_header end do ! gout end do ! gin else - ! Sticking with current representation, carry forward but change - ! the array ordering + ! Sticking with current representation do gin = 1, groups - allocate(scatt_coeffs(gin) % data(order_dim, groups)) + allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) scatt_coeffs(gin) % data(:, :) = input_scatt(gin) % data(:, :) end do end if @@ -642,7 +641,7 @@ module mgxs_header ! Close the groups we have opened and deallocate call close_group(xsdata_grp) - deallocate(input_scatt, scatt_coeffs, temp_mult) + deallocate(scatt_coeffs, temp_mult) end associate ! xs end do ! Temperatures end subroutine mgxsiso_from_hdf5 @@ -685,6 +684,8 @@ module mgxs_header temp_str = trim(to_str(temps_to_read % data(t))) // "K" xsdata_grp = open_group(xs_id, trim(temp_str)) if (this % fissionable) then + allocate(xs % nu_fission(groups, this % n_azi, this % n_pol)) + allocate(xs % chi(groups, groups, this % n_azi, this % n_pol)) if (check_dataset(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi @@ -783,9 +784,6 @@ module mgxs_header &kappa-fission tallies in tallies.xml file!") end if end if - else - xs % nu_fission(:, :, :) = ZERO - xs % chi(:, :, :, :) = ZERO end if if (check_dataset(xsdata_grp, "absorption")) then @@ -800,13 +798,13 @@ module mgxs_header call fatal_error("Must provide 'scatter data'") scatt_grp = open_group(xsdata_grp, 'scatter data') ! First get the outgoing group boundary indices - if (check_dataset(xsdata_grp, "g_min")) then + if (check_dataset(scatt_grp, "g_min")) then allocate(gmin(groups, this % n_azi, this % n_pol)) call read_dataset(gmin, scatt_grp, "g_min") else call fatal_error("'g_min' for the scatter matrix must be provided") end if - if (check_dataset(xsdata_grp, "g_max")) then + if (check_dataset(scatt_grp, "g_max")) then allocate(gmax(groups, this % n_azi, this % n_pol)) call read_dataset(gmax, scatt_grp, "g_max") else @@ -839,8 +837,8 @@ module mgxs_header do gin = 1, groups allocate(input_scatt(gin, iazi, ipol) % data(order_dim, & gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - do l = 1, order_dim - do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + do l = 1, order_dim input_scatt(gin, iazi, ipol) % data(l, gout) = & temp_arr(index) index = index + 1 @@ -859,7 +857,7 @@ module mgxs_header order_dim = order + 1 end if - allocate(scatt_coeffs(gin, this % n_azi, this % n_pol)) + allocate(scatt_coeffs(groups, this % n_azi, this % n_pol)) if (this % scatter_type == ANGLE_LEGENDRE .and. & legendre_to_tabular) then this % scatter_type = ANGLE_TABULAR @@ -870,7 +868,8 @@ module mgxs_header do iazi = 1, this % n_azi do gin = 1, groups allocate(scatt_coeffs(gin, iazi, ipol) % data(& - order_dim, groups)) + order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) norm = ZERO do imu = 1, order_dim @@ -906,12 +905,12 @@ module mgxs_header end do ! iazi end do ! ipol else - ! Sticking with current representation, carry forward but change - ! the array ordering + ! Sticking with current representation, carry forward do ipol = 1, this % n_pol do iazi = 1, this % n_azi do gin = 1, groups - allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, groups)) + allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) scatt_coeffs(gin, iazi, ipol) % data(:, :) = & input_scatt(gin, iazi, ipol) % data(:, :) end do @@ -1014,7 +1013,7 @@ module mgxs_header ! Close the groups we have opened and deallocate call close_group(xsdata_grp) - deallocate(input_scatt, scatt_coeffs, temp_mult) + deallocate(scatt_coeffs, temp_mult) end associate ! xs end do ! Temperatures end subroutine mgxsang_from_hdf5 @@ -1063,6 +1062,7 @@ module mgxs_header ! Determine the scattering type of our data and ensure all scattering orders ! are the same. scatter_type = nuclides(mat % nuclide(1)) % obj % scatter_type +write(*,*) 'scatter_type', scatter_type select type(nuc => nuclides(mat % nuclide(1)) % obj) type is (MgxsIso) order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) @@ -1125,7 +1125,7 @@ module mgxs_header ! the problem wide max scatt order and use whichever is lower order = min(mat_max_order, max_order) ! Ok, got our order, store the dimensionality - order_dim = order + 1 + order_dim = order end if end subroutine mgxs_combine @@ -1185,6 +1185,7 @@ module mgxs_header allocate(scatt_coeffs(order_dim,groups,groups)) scatt_coeffs(:, :, :) = ZERO + this % scatter_type = scatter_type if (scatter_type == ANGLE_LEGENDRE) then allocate(ScattDataLegendre :: this % xs(t) % scatter) else if (scatter_type == ANGLE_TABULAR) then @@ -1302,8 +1303,8 @@ module mgxs_header end do ! Now create our jagged data from the dense data - call jagged_from_dense_2D(scatt_coeffs, jagged_scatt) - call jagged_from_dense_1D(temp_mult, jagged_mult, gmin, gmax) + call jagged_from_dense_2D(scatt_coeffs, jagged_scatt, gmin, gmax) + call jagged_from_dense_1D(temp_mult, jagged_mult) ! Initialize the ScattData Object call this % xs(t) % scatter % init(gmin, gmax, jagged_mult, & @@ -1319,6 +1320,8 @@ module mgxs_header end do end if + write(*,*) this % scatter_type + ! Deallocate temporaries deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & temp_mult, mult_num, mult_denom) @@ -1557,6 +1560,7 @@ module mgxs_header ! Initialize the ScattData Object call this % xs(t) % scatter(iazi, ipol) % obj % init(gmin, & gmax, jagged_mult, jagged_scatt) + deallocate(jagged_scatt, jagged_mult, gmin, gmax) end do end do @@ -1576,8 +1580,7 @@ module mgxs_header end if ! Deallocate temporaries - deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & - temp_mult, mult_num, mult_denom) + deallocate(scatt_coeffs, temp_mult, mult_num, mult_denom) end associate ! nuc end do NUC_LOOP end do TEMP_LOOP diff --git a/src/scattdata_header.F90 b/src/scattdata_header.F90 index 6dd104d5cd..6004cbd190 100644 --- a/src/scattdata_header.F90 +++ b/src/scattdata_header.F90 @@ -155,7 +155,8 @@ contains allocate(this % energy(gin) % data(gmin(gin):gmax(gin))) this % energy(gin) % data(:) = energy(gin) % data(:) allocate(this % mult(gin) % data(gmin(gin):gmax(gin))) - this % mult(gin) % data(:) = mult(gin) % data(:) + this % mult(gin) % data(gmin(gin):gmax(gin)) = & + mult(gin) % data(gmin(gin):gmax(gin)) allocate(this % dist(gin) % data(order, gmin(gin):gmax(gin))) this % dist(gin) % data = ZERO end do @@ -280,6 +281,7 @@ contains ! Build energy transfer probability matrix from data in matrix ! while also normalizing matrix itself (making CDF of f(mu=1)=1) do gin = 1, groups + allocate(energy(gin) % data(gmin(gin):gmax(gin))) do gout = 1, groups norm = sum(matrix(gin) % data(:, gout)) energy(gin) % data(gout) = norm @@ -379,6 +381,7 @@ contains allocate(energy(groups)) ! Build energy transfer probability matrix from data in matrix do gin = 1, groups + allocate(energy(gin) % data(gmin(gin):gmax(gin))) do gout = gmin(gin), gmax(gin) norm = ZERO do imu = 2, order @@ -732,15 +735,16 @@ contains ! default is ZERO !=============================================================================== - subroutine jagged_from_dense_1D(dense, jagged, lo_bounds, hi_bounds, key_) + subroutine jagged_from_dense_1D(dense, jagged, lo_bounds_, hi_bounds_, key_) real(8), intent(in) :: dense(:, :) type(Jagged1D), allocatable, intent(inout) :: jagged(:) real(8), intent(in), optional :: key_ - integer, intent(inout), allocatable, optional :: lo_bounds(:) - integer, intent(inout), allocatable, optional :: hi_bounds(:) + integer, intent(inout), allocatable, optional :: lo_bounds_(:) + integer, intent(inout), allocatable, optional :: hi_bounds_(:) real(8) :: key integer :: i, jmin, jmax + integer, allocatable :: lo_bounds(:), hi_bounds(:) if (present(key_)) then key = key_ @@ -748,23 +752,18 @@ contains key = ZERO end if - if (present(lo_bounds)) then - if (allocated(lo_bounds)) deallocate(lo_bounds) - allocate(lo_bounds(size(dense, dim=2))) - end if - if (present(hi_bounds)) then - if (allocated(hi_bounds)) deallocate(hi_bounds) - allocate(hi_bounds(size(dense, dim=2))) - end if + allocate(lo_bounds(size(dense, dim=2))) + allocate(hi_bounds(size(dense, dim=2))) + if (allocated(jagged)) deallocate(jagged) allocate(jagged(size(dense, dim=2))) do i = 1, size(dense, dim=2) ! Find the min and max j values do jmin = 1, size(dense, dim=1) - if (dense(jmin, i) > key) exit + if (dense(jmin, i) /= key) exit end do do jmax = size(dense, dim=1), 1, -1 - if (dense(jmax, i) > key) exit + if (dense(jmax, i) /= key) exit end do ! Treat the case of all values matching the key if (jmin > jmax) then @@ -776,21 +775,33 @@ contains allocate(jagged(i) % data(jmin:jmax)) jagged(i) % data(jmin:jmax) = dense(jmin:jmax, i) - if (present(lo_bounds)) lo_bounds(i) = jmin - if (present(hi_bounds)) hi_bounds(i) = jmax + lo_bounds(i) = jmin + hi_bounds(i) = jmax end do + if (present(lo_bounds_)) then + if (allocated(lo_bounds_)) deallocate(lo_bounds_) + allocate(lo_bounds_(size(dense, dim=2))) + lo_bounds_ = lo_bounds + end if + if (present(hi_bounds_)) then + if (allocated(hi_bounds_)) deallocate(hi_bounds_) + allocate(hi_bounds_(size(dense, dim=2))) + hi_bounds_ = hi_bounds + end if + end subroutine jagged_from_dense_1D - subroutine jagged_from_dense_2D(dense, jagged, lo_bounds, hi_bounds, key_) + subroutine jagged_from_dense_2D(dense, jagged, lo_bounds_, hi_bounds_, key_) real(8), intent(in) :: dense(:, :, :) type(Jagged2D), allocatable, intent(inout) :: jagged(:) real(8), intent(in), optional :: key_ - integer, intent(inout), allocatable, optional :: lo_bounds(:) - integer, intent(inout), allocatable, optional :: hi_bounds(:) + integer, intent(inout), allocatable, optional :: lo_bounds_(:) + integer, intent(inout), allocatable, optional :: hi_bounds_(:) real(8) :: key integer :: i, jmin, jmax + integer, allocatable :: lo_bounds(:), hi_bounds(:) if (present(key_)) then key = key_ @@ -798,23 +809,18 @@ contains key = ZERO end if - if (present(lo_bounds)) then - if (allocated(lo_bounds)) deallocate(lo_bounds) - allocate(lo_bounds(size(dense, dim=3))) - end if - if (present(hi_bounds)) then - if (allocated(hi_bounds)) deallocate(hi_bounds) - allocate(hi_bounds(size(dense, dim=3))) - end if + allocate(lo_bounds(size(dense, dim=3))) + allocate(hi_bounds(size(dense, dim=3))) + if (allocated(jagged)) deallocate(jagged) allocate(jagged(size(dense, dim=3))) do i = 1, size(dense, dim=3) ! Find the min and max j values - do jmin = 1, size(dense, dim=1) - if (sum(dense(:, jmin, i)) > key) exit + do jmin = 1, size(dense, dim=2) + if (any(dense(:, jmin, i) /= key)) exit end do - do jmax = size(dense, dim=1), 1, -1 - if (sum(dense(:, jmax, i)) > key) exit + do jmax = size(dense, dim=2), 1, -1 + if (any(dense(:, jmax, i) /= key)) exit end do ! Treat the case of all values matching the key if (jmin > jmax) then @@ -826,10 +832,21 @@ contains allocate(jagged(i) % data(size(dense, dim=1), jmin:jmax)) jagged(i) % data(:, jmin:jmax) = dense(:, jmin:jmax, i) - if (present(lo_bounds)) lo_bounds(i) = jmin - if (present(hi_bounds)) hi_bounds(i) = jmax + lo_bounds(i) = jmin + hi_bounds(i) = jmax end do + if (present(lo_bounds_)) then + if (allocated(lo_bounds_)) deallocate(lo_bounds_) + allocate(lo_bounds_(size(dense, dim=3))) + lo_bounds_ = lo_bounds + end if + if (present(hi_bounds_)) then + if (allocated(hi_bounds_)) deallocate(hi_bounds_) + allocate(hi_bounds_(size(dense, dim=3))) + hi_bounds_ = hi_bounds + end if + end subroutine jagged_from_dense_2D end module scattdata_header diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 index 4b7b94cb45772879a531852ad5db9fdbe58a49d6..38bb500677ae2d95948a7992f0c580130546e90c 100644 GIT binary patch literal 123864 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�iaN{9 zP3YqYM4yCs-3DQ_yw{_Ubrke zeoq6}zce*wZb*ac_wViYuuFr1|GG3BI6e(bK1}PNqnifjVsx4wQb~h^R}b~C{4In> z-OpcdMeW~R7&Ij^_@WT@?>aSp{AcQW1)A#42X>{wyFni}=8Q;(Gbh#6KBS~WUS@#) ztWo#j+_^IblOpfKxZnqq7QVd?g(J^pj_jQQgX@mz(3qbApF)EkehJC|VY_3On#5TWW2C%vyW; zUGK6DLQb6sD+t{Ns+toZ#4H4|Cz+?z7_<}g^&D0RzlH->-6Y~q*FDf-zxmBc!hOI= zdpm(&GaBMr4&H6|em`7rHgt2{cMw8{2Xszv5d$_eyuJEQIs}^s`1u+c9fpS=bo`$* zhz0jf8BL~}$3hL>=~X)0V?nLi*z<9xV&Sdj&28^*$HK7BE6xXn1;K-srwX}Cf*@&s zz4%Ujg5a(J@9mQGjj+h9yYG#e8==D|$Hp-i1L5tzdYhLt3xtzPRaXaGS`YEJ!xyGb zSO=XBzwld@w+3Qn-U@L$5di(y4IJL^+G@C%d1g%gL94+dXH8tB=4w#7zC~}f^=gQ} z-z?Z%D**O7S#^3fcrCoKIT1P7DiB=jYirw&+XQ-JOlouNw!+zin&+-~gup=6*L-)A zP-qZvGp5sTzlQZs`3gxl^ZRd*Hf#N0qgE_JD8n z+-`A=_d>VyBV&7;?**;pJXV)XBi^g@YK=ey&q?#mFNKc<(ak1md=oM7jY?Of6>{_OaES=YrCw8os3U{G>C z#2DAKVgSvf6@Ty8zgG!%ByOsUbE5l{PRGS`!M#hTBlB_zeM_g~;qsFDAv!{xkJB1h zZ%DkVr$;F8g%u2Pq*rZl%}WTNvh_-i%X@t?DOcM2F;(q*hvLCKQKj&E z@@4NYj~a;W3zx`9gp&T)<=fMhe!Rr*ss75Q-oRFzv1{bblgi$}R%|ljTIQioUcgq| zw=I25>Sr%tE53>Us?qnA7qAsqt=Sq_C)*3yip`odILc4;0=8n0@ZLk$-thvqV(Rb} ziw`7t0b8;Ejg${Dp&m|D#qL zZ(u8)e-?BoZ-qCo6`#3g%#Jwj4Q$22vCh#;o_hmZ(fncPQomY0z*g*VBPwK7TOVL8 zF6$cIy$@A?mg1>>Z?hZy<^ya+m&Wb2V+?$Nt*D<{>xyuQ53m)p=hYc=ZH5o96-V~8 zZaZ*-53m*Qayqo_Im`#xicL2S>BSrE18hb5ek!phc-4ZGl?Y_rX84@a>9p|mfwN1e zBkPs)2b4}Hg&n!cmR$FUBv1kSskFzEDj_g=TUR0}4}I~oQc^)|bMccSl^`fBU-YG7 z5se0=Fi2;3;u55PXStvQE|U~3rk9kHnK-|q|NeV>#D*a!-mrV9eiMBzU1v7k{q#kTVuYO|&Sa+E`h@-gkzLC_5D;sU;CGd$pQ$=8x|V)mjIS6zv6T+NdP$qU6UNo3&4ExiWLU&0(f?| z|KYdP_ecBxp*Bl(vj8T~PT)3QCIFR(QzsptA%IJD$JUAMC4j%+c9gcd0J{9DHz+_& z0Lhx(vF%O^Ab5@!r=fZZB!?ZiGO%e1435g)w6S&ygoIm}yL=SD&^Mfn@h=2moOR3c zOr`)1PJS|Ehfo0L+SHEb3j~net$SjPTU5Hmw5XFesPCHcuXXgL@NI(Iwnx_mu))AO zea$rijG6G|RThQAcHN$EoT^8kfBbUix0nWBGn{O*>rVrh_<-2Mt)@Zt=);?N*;C8uMxcM#pwoZi`2Pem!vziK?5qsJ;YcmzPeYV>&B4rA6oYTrvGiVB2$vWb* zc)}E@X?EwLf4&jaQhL}GLXF@$&%~hF0wYKnkx}qyl@SCy%Z%jbOo5?SO&8nmoC%-a zb0_GIGzFtc+cTdxG>6aqr)nSP%!Pt=LsppXo(mxsF1@t0EZ}%@4<-Hr3()P~dG&yO z7SJf5V~XAb3$WW_d?H!Z64Hn8BL_CI1f`$`6K#7~!s(p0spp1Sg6Hb-Y32hh;qHU_ zJ)C)#(Eax>6Pp@Xg5$v4u&$hZXrg=OdS41Z^v??KOyRE~%2{0~RPC7@*Mq`(-7lOJ z(e<4%%1V^>cG%dn+c)R8&$AyR%KsQ|w!b@t)30s~=tZHEOH5}`xjXjszN=56&GJ(n z`%@U1`DmIRg*j?n-qoS-So>vXMfmW>N{1#CZaCT}Qj@~H^JWZbMPXpx2R$x@YkDOf zXhUJoUA69r(vN-4s8PtqcKDn>%(iVnUl_nS1PBbOD?lMHdW6g^3kb{kC!lv6B@3+svFN&Nmz zHz!wnQP?PsC;yB6Vr2Ed^c;|c75y(cRjdkTi{Agz!1r^<{c>{qirxo?gWu;S?VbL9 zKhaOM<%lCf$FoI8W;A{Y-_;!@$D5F(hBquGo}&W@Pyd?$VOlp%}N5`$t-?4AT7unJ-G9?Z+bRePQx`vZc9`xri~+N_Ay$ zDQWM1cD|vk`@0xo`&h)fm~%<{Xe^^fKX)40JJGBO`teC8cPVp_sgp;xpJgeR#@UC1Yg;DC2ij&x}M1L6Qg#P)F*|Xs4gvrSv}}}f`>25 z#CC?1Li~ZPxs!vn3x{LtY~y5YZ)0s??c~ZOnG`WKFknqh&xp{RA}cb!TBIP1lIEt?*qY~h?7_1hRXex1j7-Vfi2SJd4_uc zTQN-k*{$Hi9>7){ceP&d;Ybf)D`u=}Y=2<82e1_zzDhb~7w7?O#iee3Ru6nVfUS7o zoxc4GdkuoV}6yr}etp$D)PPYhhhSvlAP*ow|)_4j@4>;Y`WExT7e zs-xxsY{hyb)bAZr_W-tH)*bg9hnsi+TXD#-H8v)-J%O#LeeBbj-@QD6t+@P|@xsv; zJ%O$0;bq7A}J4ju>>k_{|CeQ%;aQ-pG?Jq z9LR$&U-D2FuhAlQg1o=(z87(sh?$kOj*zn-5fVG1SVvf~dMt0H)7KFaebU8xMEEW5 zeIm$r+HxYW{^9%8W4k}SQLg-L$o8a$Xna>sP5%l;T2Bu^1NDuw+iQdw3U(CrU- z-y$084-rB|zb6^~JJLh+&*3EDbk3oY`pLukP3Y+QPWWXDO2%a0=%lI^nk zzE5e4?I;eHv2-QvsByWwCIMNAWWuk47xw%GRsh`$l(p58D2_s9)aZFM+4 zPt6^MrEZKk)X5z_X2cHCGIR&dgfBfidbmT(#Qd6Zr`_S#)=$)vR6JnCM6S=YSst+2 zYQ{vHs~(`EJ0qgyWKY=9uvXor^{MZBEpGXCdSh?sq}_h|xj-KXS<g zI`RJCQLui>+2{Un=KiI}+YkH0h1RnRy(aoY?wez7YR~~Vgu zdbZ#0cN%`M{O|L#Hazr&rGvh{=g0ekac;0vy-mLG!J>WijU~RYq*v!QJuQ6U!M_o% z$&-A+LvQAJ?P0#~I&pw)!y&$a^g5rlNR&^3NE6s5hw5V274=X^Kp}x2mw>c>B0Wx& z)lUpQi!3LJCl&p~AAc5A`3ibJk%udzhx-|%ZdG?bg`^8OHsF%Fh)^G`BThZiv z`}CYa&cIe2uxip3OH*fHE2hqQ-!EaCGq4p0Ea{cI_%G`DvlI)m-rwldbqTN)Rb15K z680?tw&F7zosUK)OM$KUPG_m|^i?jvR!p1za=1Y1Bja(}iWgRm3uQdThMZ05(;s9lAEK8B&GW4XL5*yya!=jF{zzyye3js344< za&R$X$~UcLq`h$O5r(S3!%NlRVO;!6Xf&i69^)uC=ZRk&<7&-k40V`~k=b?m%ianv zGKI-da;dCA6>$|}j+a_0l}S_23ItGV_(gwx)(}4#!$5V}AkA#J+&WDpp-~W{M}4tD zikf|biJHDah}nGkU7;v?N1fWvNNw04Or1KxNL3Zkqn1g!Q@J)S^#`AFF!WUW8|%^k z9o0rmc5F*c6{s1ke7{EgaKj$8;9}bJ>jj1uLw(pPK^=Bir{3fjp+}@TLPJB{<9?jl z;Nh|O=vO28M-kLAFr-;LHpwgv&A9yW z%R)&zFG1zs?9BXIpvogRAH;BlZvL}66Fn_$J0h6mz%$aU0?x6EDl}b~LFIH5f@w#s3)g2ZmX1`KuKasN)2= z#Yr=*49!8!5%8rdNiX&P!7qZDW4ZFM(jtF`H!#xDs4R1ec53UdyAzB^ksIoNG3%q^ zpUj%RY0UV)<5g;?0_G29*=h39wyRPDHRZV4cm6peWDIBnRDaR^x1J!n%VAPEq%eF; zJC>T5@1!!XmgL$5fA+A*ih!Mqtk~nDvGjU{9%;+vD$Rd3<5=!>rJm}_C{*9w^$F-} z5u0df*r~Pr!pka}L(9AS7pHt)@G>#uLp(EexVi_*mOH$L@g{$KcX7XIWDW$y}~ z3UwFnd|oqQbe7pftDu$8Soe!hxf*}+X;GH@ddp?kWuwhVmEI>soi`k&`WzBXwJgT$!~ByS_Y7AQhxvC~#1ARX!~Y)m z4>K5GO??nAgmIwqyGkq25=1n&58o4njf7 zLyO8~Zn^k;#VD%UEIvm@5gEYk05Bh=x|jMS+>My7ayB@P-=UkD3{hDt4!vZa@cE$ z|JGL8_}^Xr-LTSlukc>jcbVI?96rD95Vs4dIc`Gbc1M^ov}wQFFS6T`Rh2fIgZjvC z$-?|6#}mEOF`WNq_~Inmm$3`u(p+d(9GH*)FGH%}xAff5{};KDPF`U;we-k5V9AaK z{Rb5m?P$Ov@il$0ORrb7Gi|wC74pw!9Lv3~)KmRylodu4{`&skMl|p*Bl=gDOGY&G zpFRJZEqx*X!IrE3eoOTE)&JkQLJ3>pN+EvnZqbZ}FEfQ!0k>>MX{&yJ-6BtF6xC3F z|07GNikp>PA z%dY<^KMd>JZ0gfFL8g19OEs&0;mgpnrIKMjHL^O5ww>#56n6QWg)K}% z4EoE$rsXV_RxE5^)*|x|=){~~e7s^{3v(AABLhoYmHg}O1S73sVnU-1RbeEOwtem2 zM*0OUg_as(=$0rVy!2r-EA&}}r&0)>BE-X#viy#odXANsVF`R9{Jsl^%PRlQ#nuPZ zp{AVJFZnPots;?aoeH!k&dv1~lOcMnF})ZU3}I1UHc@iDppP#(63f~LYZf{ml`<7T zr#e@a#@5r{gxaqu~cSo5gR0S4oHD>OEbzRE(MH>nr-gtoLyKySW9OZrg zBcBX$`=3{CUlk0Qcb>#HjeCOWeyj68>H46Ltahwep#Zjx&}!p+QlTvN)Wn7{GK{Kl zs10cbLuHYU?Z^Qy*bpAdSdQs~4~K4k5;n)78SwrXFN#Qo{OLRWX%El<_qXbZnFNC_ z=Y{K33om%7V;i)0p%=?V#3mYfTQ_o`CU>xo`q zcke)0zmHv^1R^A@v)bo zZ+hXX;MJww!P;3cq#;p5(%Fq6pzEM*Lz2rntS0f3+w(#*FtzR zJ@MgYcN%2BDel7Qsz<;k*0+bB)8ioZx}(tez;RHJD!!6j(hHTRe8yka6oNr|`f0pOnLvX2%fJ#T-!!&Pjpuse8)2rAU&h<}C_Q#_M=!y=9|11Qy&ARtA&Zon6L%pzR z{Yc=yURR{IGZbW^4|0j>`#?s9PII$gFHAb*;w%ex7lEsId+UdFXW@{@@W74LQ6Nnp z$HdwZ3O~_K`x{3shh*V zn~RUiqTvgB4G*sG(eH)s7iVJdZbfkT`^f6Rb7$d^>TAl4FHs;4_mW3r!hpsKSGnrt z6<=8U{YgZQYcK5EGW?Xfx(KA(w{0{QI}0CnV`jJ=qTu~AUoNYSVQ{x$N34*HFWft~ z`gVM4FC6JpR%QQI059}tlshSD(7Z-!uc}A{+zr|_$IF0&&G)IA&hf{=u~T|&!KOY) z3@ zTRwa=DEOQ)mJDu#ZSCEIM39}{b8xgi5W04}jTdrs2b)R!0lv6Ccz^hgFz?}ufa8@d zJ;0m{;fL>CvfV_4Q?rLNIXcgPW?TaNO->@dVvJY%-%oebDINfXCr)9T`+zkfXmjw}3ox`@h0gmt6+Y7KF>-!~hjS(0yxw*MK(dA{$eK8Sig`idHK z0d`iux)7pG1$AS?jlS7b(;0NlKF>dWywSD^3oOXGRc2el2Fo~wN>z=4-V?JPT};Od+F zWa2g+q~yF(Z*L8N@mj)t+ZIgimx{E?xz9++pDNOFY)jw z^P&LDXVn0R_+-|1^oDD>{5lM#U|s}+5y8;VFS(IrUxJ}oa$T6!%dUpn(JDl3ujZu= zS8LL?b1!m@$aO@Vy(=7)LML!|Bok&_%Qq0lJ{Bx0xS4% z{vvfhy$vgrRL;_mANF zZTTW9N!7?l8G*k#{e?<6YW~^xzky?6)qerUn~9i$zfsL)&Fa4bJ@cE3NMbRV3usYm3P1SRs_K{;(A8?8K55e z{gKDi2^{2}qpkaV!3Rc;Z<0t*I0`o9#|pyhI^oIo1I;5`#ZVr%(F-?_0kQ?rqUS13 zz+CqQj)%{DAYs+J=pC1>VGH-pmVld`;8XSCV2fNacqsd8=YGxr3vs=~_Nfzap3`fs zBkF%c+#4@_S1Xus6}M`r>V&A5^6W`!I5Ysmxy+fV49HhuJg+``0yev~5gb~4;6Uvh z?h?)lB%kqPim!Eo*y}@?YaENA3!99clsgC2#nb+ScK+}(gFP-{!3TWWthXG^vj(1! zf&PHYsQ$C67~_y)ptwB0dQs&Z@MQCFuv+^=@a6J%fqQ&`sY5OBIS!7(T<2-0ikwc! zTchZ)v7{Kra8Jc~9M8dFPF7+-hc9@ydE^vTSc8K3cavOdC#-Y3(?aYn zhJvk$PRtqSfNJpj;dG?ukDrRcw7Hl}-OM4OIU8a?C-e6ZoPzBQzft1H1FLrk9t`!4ZX^f|)ZX z;oGOsU6DC{uuWpnXceC=@~ltwEHHP2(&`FRjV=7jE><5SE zAz=M$8xY>s)M+sD1g!V-txHHKfGFNq6^*Ltkb1=9RL@;Ms7u(wdWqKu%(8LxTUFjz z0$-&~%_w4l9FI{CpX3FQ`*!Sl>@6mWj!r2`}*bh0|avjvVJ0WHAS!1wiCX7{BX3ac` zg9!H_9+sA4unOsz^?N&Td{dS>YnkcY(fX&Eq&INnoky zW_E@LGb(HCOdY`G(M_2sD?^xPA%9@2>4e_ZTNEQtWkP06kp8!YI4InB=;fsjXBf1S z)l1&s2;PpxJ*4-BAawV+yU0~Efwx&wsvViYPxdTt*cA`kw%z<3ZR`R9*rLt!Qpa$x z?!iv8vGYcteC$R1wc<{=uA(LXuQjnx`AEugZ6vk97i{2f^|Jdd9GC=sEY(+)l8* zbobe-&*wo_z}InLA|CO&is|(mS8$?H`*y(531+y~HZ)0@z@r^Sh8B69(A3fY(bh5x zX3TB}TznM|!&1}7iyykep0c5IFD)mK8dbMX%rt^YZG}s#aA<&!@oi4*7FlrD5`X6y zcLH?FOvR z@F|N|;4yGMmVZm=;lXlwZVaaU-XmI!(Ek!&B-UzSiWc3{-_gY|N>9W;Sn@YZ=?TWi zf4a@Z^u*LXgb$HrS*Q{Vviwy`2*PONY3 zz4p#t9zZy-$EM$Q97L)Ql8(gpz-(T7?wYtd$WH06)9wuh8P%6>?ldIUizV-&cU9R5 zLgHo;1McH6Xn@fOP3!@S7B3bIsSc8yY#1dKLU7Pn@$&1!^~Cz3(S#G0*1I4nIYA>Y zXdIsDPm5`v?E$~FbA}O=I*_1Oe%U7*0xcd3#pmxN*7JF9K9W4U1DM-nf|cUO;UlhT z!|Dq?zY%HS`RfwvOSeyITn$l&u$JIQ_)Ft}zh;$CU5e`g zWedZe)2VgvO#P9O;L{Lzx4+s6Q=eEr6#a~T{lYHz?(ykz&*O2pcZ{vOr=bTNu?ugc z^6FqXJ)yyi6$d}+M8aR74=QyH7`Czo*!?4IuHx%BcrWk};<|c3&0XEvzN`-N{bcGr ztZ{JdgJpqRTVnmgTwzfLT*NLIoqK5CBR>Ii^BgHfQ$27Q&+c;SP90F_2i~TmjDyO3 z!=xvjiS=1K*T2}%58%xt=5BXl0-oF>Oi;N|#^Q-0tS+DXTW&Y9{8aZ zA{jq936`dT*33V8L1h1^;MPa=a3lN-SNud6j7DvL9(SBt-^6~)Mo~utrfHhW9*(^O z!Q*5cskyKZcJpm9V$f=UiUHrccdg-ILuX^O>p8XF^by<8W;6gZ#>;Kj$qyhkAg1S7 z+Ye3`FPmH#YJlD&uLO8E5ug~)Sdx&FRL^TF-7V^-1v(kKQ_@?fz-0udoU~^EHaSdH zNHjFU8vYPF>k%Rx|K_-Aq$s&QdMj>o2kU{oQ1M8V+sb|#vSjOQyBG#xTfjGW!_Bur zu9C;J?ga^k7ea@2X{OX)DwjChAF>yeIM&T>a-N3O4$QYQz7D`QHM?sD{I`K^hcrGJ{?Pq7Z79hF<(ZKwn0{F<`)b_)T-uP-%|~d2_3xh9n52_{zw=DM?IX$c z_o!Q*+&ZQMTlr$&Y|Wm6l6md?Ym#7XwW8_wA4&DCTlQKi zr0j(;=cg8jT&Do%#aqnayZR;AgGvO?U1o z$mhTOUbmqizB#v=abIcx`kjnbqSi#H*?MV{-@YVVy|b>rW7{e{NQ*LIgvk%k+t$pN z8`}?Ujz4J~VjEyT6RTPS2N5`~D7`zal2qS4-Ff#K4Pu$?OxU674^SADM(g6(4@#QX zY#00*ppDfx%f6og8J(X7XE>7TKjd;ul$q#3!QH7~p7;;2-G#aC^`3s{m%kEQWQ}Wp zmWNMIkZ%xxv1ed-YL;5xGgOeMoEE%yOD zKbA`|k%Vz++)E{Qh1=(#?Skf&)0mTv%TRO#7fGXglwRB0-=Q0oP7-H(O2 z^}t%yxU^UC1BB3U;GAdrphtcBjUr?oN84EQ0T1inD|I=wMLKXAZzZScG0|>N~!i)K}0?nNEW~oip*e}0Jnf$Yh z#kI!1v0q4_{oT^*6%RkZT;`qnXEUGWURUb<9%Tgy4F3}e1Wf#e1b+AV>x;6d|Jn8L z%{q#%OK)g4tzQ}kL&Ne51Mx0D=U7fv4BIa~pipy)gqVHImufd)sKqzaF(rR<_K!aiBkAX2ws;QxX36;>s!V8`a=-1o(P;4-?x%Jfs?H z^~|E{2>s8W=2du5(EmnOF2#eShwL@QMm#+HM3-7WjNbQF?n%cGfJ@+5Xz3gt8e0W? z4S)dZWvnHYt^{Dh?Xs^R6W|erk-~kK0IyT(B#%rHz^W=)a$1fE7D-m-Yix)(s5+AD zd=r_Z^IXqz9iQNd`$l%R=)(GO#oA zr&ZWdAoi3XYpi?(WRN=cbZm%(Z)-Q|Imtx94^DrC3L$04~8ZKL6JVS8L2(gl0{BI{=`o)p zfU7d2ZExA4#R~TRFiQZHIftqz0z?RHdQkfc7e)k!7rKL6%a9TO%Cu){h6tza4oUGI zA_1%M6t~|+63|?Xao8bAhS}>!Do&gsqmYQ_cJpg8=*4couqBKFUA}pTh$y4)!oJYk zwmK3TW}0sW>qLP`M%~BKH_`AgH)-36196ae@Z(YGLkZwd*OI4!^5SJ@k{;sbkE8*& z&i&!i1w4Fm`H8D-$HU{HG|7oNJmkwH9W}dvhqH22EtTtd2ob;j_TU{ntQq@g$$?~G z0_&NeHGzk#G92EYxCo%Vm)Sx>jsVlV=J~Hs!kzA$b8ichfo&nBdAKG5T)2NTf8-MZ zR)5LbI4MqqaFtfyqOAPeq>IsYjdR}ZA4IU%ITiR?mjqD^H>_K;NWk~{wFDDA z8OGVzT(QT=kP=lrPI*O!LA?#29!!CG4(lKJ;t`PN8_xSmBod5{N|qj0iUON;J{!W{ zMMLh_+qIXp1KD0u1i=x;nc$2^OkwI2kSLG`N`hG^*zt9_+Txd=5r4_ll%z z`&fbpt`>t*ekA=TH8yDNMAxIXwPYhiiCDK*L7gXfU`-t2!6NA&y41-P%uayHHP<-5 zZbs5ha@(-M1o2$@+I7t^0`R`FX~b0#phQ$=_Rcr~M4!({PskAAEw01(;7unYWJi4S zmMRCd2k(Mt`gq8NSx{pHq8E2IG)` zic^RJ!=>umlw=}cyScz@6Kf>YR*%lV+#UtnWQ8tPzm5j>p>3RW25~S+BIuv{|A@Y^1pqSMPnb|8#3%Mnqe ze^qOdDbkKt>wNWhw;|d1{4O)_Egt$fyS2+!6JWPf^5Y;R19wRu+5Ogt2-1I+y`uPg_C%oP?Y??g43(nBi|yh=Kt*3Jx)Jl4@$#pPW6-F73E#-34aRYfInNbWCU0+?LLH| zi-e*xLb8G?QINo(e0-`u8Y1g>4V(7H!NZAzX_xI2K!7{s7G4mS1k-i-&xt3}AS5a! zo@EpdbuBlrcM%1iDspU&KaU5wzT6I@1U&RKuiiY0D3Q~=nL88Ng)70^u4o{NT-RK+ zQ1${3G3QntqJF|d%8#||Wr75dA#XXUy^jDj`}=O}cO$@&8s9yhSp=v%$U!~%lmI=S z9bBSt8;KwpFPW8TNrZEPTNJf&h`^lZyle6u5p-PVrn-Oxj%zNzn$IBt=1Nee%K`}+ zh&#fjkQQX$o8d_tCWFuACSnVs!1o&sX7or4$VSHI@v9<%Ju54BW)eW5JpQL)JF)|YintS!TtwjQF>8HmL-^y=ZT#p*fDUb(iGw7tcCR@debD(+0#c+!DP zv zPg2rJ@U2Vut!8W*$Y*cWibi^UPFi}m1LD2U&dB+uQjmolJyxo58hJ~#xSc)^kp&%}6|c0TBfz1+(S_&89=uP_3JE%hLLW}H z5c^O9tQtDl5!gV0F5FJW(17m*5H4203jq;!if+P2A#XTlnt#}(jR?_dbm0#rNl-r~ z#+gDP0lj{0PYnujq|&nz3r)#j-;}^k?L>PTOb&+79;Lt+>5MH`c_P4Ib#?JBBm?p@ zZ<#)+M*)?1XxF|E(QqQFdq&zk4mdQ&{YLC;>SZ!wz5 z;Vq9hibmieDucL6(*+OV`sc6s+u$KDFU!Hl5f9PV_vEIYL^$Bm2Bmg9@`8?gEtHW~ zJaC!MyxV|>n-wq0l&6qo%-h}G%TIu4)$?6SjKPk7D zT4XqNX#QYJBN<#nuC_T^Qea15oMr%B1iWY9EED?{0R!ysyiOxufJ@q)#_%Z`#L*Jc z8>cuJX)Nt!B;pbvuBo6iMK=j5#Sbe%RT`*0?3yb%hX;>wuMTq$JS^xZ#Elr?p*yp~ zbU+6W*@2|~E(1Jh9oe_D`3N2g@7DL+M6&U$ZDWKk5f5`wY;D@eE;RdySKoQI_?~IQ z4dh+Fc5n6>mq5$V{3gnkHUxN;Bq*^3mr8&$(?6|~dI%u7ZSQ$$9_0Oohw9dv5n*3z zdtXuoy2e)|Ykfz!;1uu3UK z9%T4Lfk*2{A2hy=0N5TnGr27aoVcRSUqN^v>W=d9MAtaDg2n0M45AZ2YPQJWi#1v( zKbXyi8%TpPm1tpcB;^lR?=P-4!NbedduR5k;6c;7 z`%mNWQm0X{_14i=u9^VuKJyB<5I|_UXvcF=mk2^Z=I!6l5`kT>CztSs2tKA&@>jJ; zuzmKj%%M^e+rHc^1v?Rd+hNeXn!ntvGTi-4C8%Kd3X zqd-z~gNqNM07DJ)_){bU{Gzxu1Ff+MU?}Kv)!;-D?EEs@mx4)$+ABK;t~uZ#mr-SB z0h(#MVwoh(S|sI1#kgI*hr^WsM#WGJ9yH#N4z=*$;q}SvcP~WoFnmU5?wd9q*81AS zwYlO!+O^TG3sK_PdD9TeO*~M_I6WV}#>2YiH{*6f2qWT7^iy6SpkQa^|6w~78H`J> z4zKMZfTFvQe;a~GPw|(I?F%8o$*7rqghxbpo^*g4D@Ov3gE?nRBS}zLu=|Yg52O{Y zKc0RJAj6pODh3fw3T)xJuhY{`0S>>frgKdZz%}giSq*JliR^m6ZKf+4p4sv9%~-?% z?oM=puzN-VJhEDKuaT4lKaR7OUR6qmDVnb;bldPSD8}Z!b|D-r?Qm+EBjM0Y$>nl+ z77j$?7c-U5!y%#L%3%42aHy+YyXpZQk`YIjpS41G_{mh*`5IBeaNfH0z8fACe`LG# zA>Z+JWI|#?Gm0~0)vKpJ;&Gtl(dHb80KJ_2*;Ix9wr<@4byXD^O;dhY`rt$dthT3RwOY-C2XN-%3XOCZg)JjVLyR)5V)}+odwCsSHt0naQj-No8hoS-fY|1 zyWv23ul4aTs;7S?|7rMqI7k>93m9|YAvAtG`j9Rj;&avHH+kY=i@_=WL&&$-?+MB) z#&zJKEQ;m~(4!23c0x&k9s$IePLY`tP&rc6&>Q7O*gaSOc(9oWT9<$$U6#l{`k5DVZ?*yHie|flHrhraeQkt8ScK=IQKe~0!H5QiZ4$`z=?@T zXW#lr2pRe25pq5nlBzN?a4iTD9Tl9syCEe3u5EC6^C>?Gyld5!4rio8VxIf{{;%N> zY<_gd@rH1Sh#gUf!f?n`Ii?hs7!KD%z0$3-!=Y;C#=ytRNER9{-e_$M2dAVf?AZh1 zFoKtVqljdp{+MlqpFHx8o~C-0$daBA;rYBF91nNMrMRRs*Ac|BTCYeygRT#>an>?u z=E^Jj!f@Fco#+od=X zC~vJO*W*C@<6hb%=;V?i%;bE_J!_-|`hJ6}4o5(uo!^JU*$5l1DQY5xL_^vI+^yiR zo8ll+d{^b=5-SQ>3A_?+ZH+mE6)8W0dr5I*99KyEi9=wBiPQ$YnBb|a~milIs zNhG4k*{Fh(vElG^fSiB)Y&c{XH)Z8lghTEoL7MPK;n4g1J)})1vBM^DgK-%l}Mgr_`vQJ_^N&u%eKTEf32s}3R z7{-4lz|GI^j~p;SzQDK4cM!!39{cDv-eo{BqJ-js&|nfsc0Gz&m?VMUW;b6|5*c)M z+0DBnpOAWyy2*TJ1k9L!Zo3j13A=6=N<21;1{~+S$eu9vIJ5|RSxz@G0VY_UWJ}j1 zf#l`q^IXr<0n;I>Pqz^dXB57As)~F4yLDIe}hr8xhI9!|HIHG+I z&AjvDK8E3NFmMatJA!1#B#0|VuXosC;8~<7(XJsQKDJT z_7Iix4LseDMYOcDOuds$0t*KL8+A@HoVDht;VUFVrG?f$eIx@fljZif9g2V*vyo1; zsgYoBv+kvjJ1!dD+;-b#!XF2lcUX%WAYbshPm=sHGYKBNU_N^HLOQ&`eaqI$LwMh0 z>VCZwLc{qxE)ARD;c^d0t@vI%_>Wr1Mk7nNQ)DDD&m8#*u}fN8y^!5tx01SmP%}>S z;y%602tTlh2AoCeen#ftdI1z`I_S)O{fZMu`mWUdI247;*W(($6($p)@NlTdj|T)W z?VmJu;Y7TiOZy_~K!lAi$D7125J5TtPK|va!jNaW%*KN#I$kJ}4!%r+mXhM(>%wG6 zYnm_ll17HZ@4Ptz#VPP^=lw3*rxe&(n>{hw9RX?qj;Z!cQNTYf6OAi+7!8%gjP)B) zaM*wPi+x~70^Amik`IerB#IHoPBEToLNl?nDoN)< zXnFmbt?Ruy@lcabom-5A+7b?5yYLAQ_sZXm8>}aQ2aD3FP@gqrHyuI5R34ylLOvdO=Ttq<6kNHfa=~KRaq> zq#FTytOg#}$V7sZ)&A<-V^MI@5Ep%+fG!3Ex6~;Aw2uQd9S=VNj|6C$)nqbYP6D6r z*r)Q4290Bhr5~^;zQ22Kfc*dg+AQaf!FB>{Jffi@r9yyP#hNmiDAJiz2=*M-Ksla> z+kR?@rFSG+gRUY&7IlH9?h!KS$4WUJTPg`KOmP?4`V2)zxP1lRSQv;fYnN*HY#R|~ zhF<6?co9KV!~C$)Rg@KDUVRECh`?&$D9$8Lg6#3qY4soyP*v;b=Icq|wLf=rz(&myHrYWj11idIuFcd}G~D+)0J8GlSMS6$qrRPG^vb zBftRuz>F?Rd;8mev#;_e0O#3`1MVo(@p)^pmWDgQF&s%(DzDfd0+gL^VDl)|D$F?z=k>O<{ZEs3B%91&G+MX1lfB;3N zBOPVOt{f{XE?yG>w5{rcK}8Ypp<8Hg6S9Dohonh7SvVvFU%npj;*Ei${Q^QSAPx>h zZc7c_o&bFZ@1Nq%rh;BOzBIxgZ6DV^S$Jv!Ww{JVjml_7>tj0Cu_4o(v?u1vO|-&L zxQYH)1OhJnJ4B5ZYLU|tt0HS4!$tk_IrZWg0XCFOhBh!0A@O{)$0jKvq_}m)QE+JH zg}q}VPH5&iC6T*wFB4%f{qfVW=R}ZOlNM9ULxMG2KPJ~3k-#KH^PEi*vh5Qo&Q%EU ztUk_BKaY5S^mfjT0EGQ0>l-|1pOBII?Xe3`roeO!r-a6N3b@H+A3cNegIkiQVrOnf zz;mt5gXa??LB###IPQI36qvg!y&FOlsM_J$ET(`0178~dR*?h{0W64ueiJGJ~TkrqeOwv}y1>uof#vT1%O2eh@ew&WTKcrV3fxXzIv=ULeHEhq-W59r#8#-N!W zuJ}0rf(%nzj2y7LD6rf6!I1Jb3Wz_%@`-MVfTv-TX7;raU?&@}bA}oT`6S#Av)YU( zSleJCkjxkZDS@9(G6}>%YhJ2@IeP*)=zg74K1u~K<%B9;{#4XaL3)S?5y(PwjPc)4 zCgbgqLp5&+keRyLw73_!>Atr`_eTiOp)8p`hys~-v)IXLl;Aj=xTEJ0;(6TN-KN$D z(E6M26P6;B_$1*PYU(SY1Jlj)(-@#X{YI)6^*7)NvAHor?yGPwNe$zsJHj zu{}uhYdi${GM;EKq=KyF)%-(0Qb0UVwop!)2yHZuA32aTKjYdI;`|ZW_SaIbx$g<^ zw)))u8WhfZAGv?3U=eE#> z&CwLNd2wcxYbSEc4+780uO~tUqkeoAl5+na<_8_;P&nTkx5|l$2${v31+&v)tC&Q!55?nRl=?arLLg~(u}x^tU@BN@bBuI;HVCBqYk zGF}zPXYu#Vc#vfmIx8m8_pbEM})0g=#&bP^fw=UbiG=S2;Z3Wiu(|Z zAFEHq<&08@fTcd4kVoDwo$YjQS1%D1Z7o`wSV-`KuTu8@9ujQ&n6ex1i6R`V)$LTj#s>U zN8{l`P>V{50u{1%%->M&Oaaw#hP!=xh|nPTeA{;fN?k>L6_wdgkoq*qT^R9P`LwN- z9SbsOx36c|A_^&PIyvW~NQCmc_Y+T`c5SInAL5P^!5KG^*zqHt2(P3$AKj@&{=Z7~ zwh2Ny4uf1)-iQLvDn0lH6iIMGKXNSvQJ}Nyd`B-@6H+ixJHCE`1p8+O(l#nAN_%(3 z3pX-w_ul2YUPT7k;3B~rKglp@`p`Mwi2|boOeybbC{Xo8&M;jCdBMVOay&>2a7$Yi zBHI@ z_brIf`?B1x3R%QS4woc;KBUGA#px`F=ek=rDTr|pVN1}0x|9+EuMe0sT6Um>#`QUh zfIbmSs_H;4uMjGVIc_@V{M22G;STZ?e{+bpf)~ zjT~DFjM%gnzeW@=+OI*QtPuh2FFRDO+`&bF>tpXhVoW6LkX9@RkB$Q7l3ls;NCvEQ zMMbkZVqu3Ii+9&hJhX`f9Vn1QGEm8q`{`B+=qkF2s2@aWd%e%nTALBe`mCuMNa~r| zxmXO4Hf+rA@MA?OoKM$2Nrb2of#KP`$|_Z43Fi!{U+syIHciK;fjdKl%kfE~ZdpY5 z!qT^mtp*8=IngV29Jx!gvv0$`ArktpaZ*+$fwXnU^Ooai<`a)QCXp9pT&?mHJBe_B z$A(r#F*Nh5JFYUGCd1>yb~Els3l<))Iq9;70==}?=e9Ufz*J}Ql65Tw?2e!M7y%KW z_+T#=PU|iLg+XDaZ(}1tMJHyvTX+;uYEFv{p>%nFbh^{S`?1hu?w~30JRVX+!*_=8 zQK8&B!)3NM1-fa(MHID(ux;L3AXJhFfp>0yd?|_&mS48m39}+gw~^jk2vJ~fk~r*F zNA^JEb|lY!l)xwhh4qJtuttg=*Y(T`@gASca4DAvt+~(E$RHW87^9eXJS9SELwau_ zif+v&-W@AOD-wV`2Q2sAd$ISOS32kx8&8ZtD0ahh;o)=MIzh3E(w-xgLoau}V zHE3hclo`VT6bEEv8OM~Epg6#3Z)+ryfsughQ+qVgn(-)3>v&XG1jtlwwKIy3gj4}t z&gqyau=g(7_!OndQfd@sLt10u)@egK&o}WfR(NqFS&$0)4^p_iYEobwb&rw;3RHZu zeLsmK8?SM;Tkaa-y}ihfBmGG4iLo(-Sz<)+Vru-%h|>G*p_&mahyw06DuqA0qcYC$ z`9~up1H6}CcI8|lLcq}ax6|cBIP!e(=YvLshFfwxmA?|9YgQs&U<(PZc6<`K=Su?d zgMEoSB_!BuS5TSHM23Rv;Y@}o>dgu9xISw^29=p7H+0I74|x2=qJ@tF9j(ul+V@i+ z=2)=T>6;W3l+w{9p?rY-nVhLTf+Z2qb?joRJ@N$wTKi57nn!`Kl~9f}S~%?e8jv&k zI2J-Mp{$Qz#{-Y&77jaAD)dzxI3!b?0{?Hva02f9d-uuWvC-k7e{N>@&vQ7a+VDTB zp_Z!{H)5!*enLy9k8%TcvusnjRGbp7+74t2Pe{%Q*?=7ymM#sNd+F9}#WSMRg=j{zgmUKdP5s;@N0 zd(ZIlf&HaQG&KJnXyrRy9hN?LrQTmh`)`QIV2m)dZ~w8=WtE*Q=4zwL(g`6u#sBz% zADF+knasZS>k^70h_*o=}nmKI@K7Y2S@1(!yqLP0G) z*0yFI2WBC=j3dzQP-8c`phuO#;Jqu4ltvc}Zg*Rv+zYWVR(jzwGdiGKvg5Y70XG&B z^BE+|jj+&psoN?y5DN~pH`T0Xu`uPdDJpdi3v+b>@A4{w0pm5z)b=t2RFAiDV;|yh z;B|B7#&(NP2+_|IO1v2g!p4rCQb)s}`JBeS3##GZi+x$`#fb;z(v+kLMgrWZYs)!{ z5YIm5k6l?^L^x(<>Ts$RnP$5PD=J!;l<3f%ntmJsyWdGXP&SDI5^a3#aqk$I;-;39 zH^l>=@7yQhqlw@V|FqD*4J}5KyG&-+=Y_%h&)L&lF`?j}6EIdWfPBTfd9OFWES*KG-y1%NOraDG&&*rH2Q5U<%Y0Bi zh@jb?8!@+^Aj5-`Fe_`NMu4f*(7Ty{D0m=S@yPf<3~18WH(pkY2Ug3yjF#GoFgx1a zha2on0(Jg==kV+>s9SRtr&<{bOd?UP4E;F3tZ{oa-w*;ev3E{HAQ=!-UkJ444~D{| z2x+yeSQwuZX*V>$!r|kD(gWMDK+|qWBWZ_)^UZWMYeNx*#e z#P5iXEFV8C{`vUB5LlxagsT)Rz=4jV@6fb%C{&!io2BwG6x0cHnEJ9XI1#ih@8i~R zxclyv5Wmeru*V9b8jaRh7I0dwEIMYvFf!J)(C`NeD`y7 zXIcd8yX}6y(ku#+-VaW!$wd?pitN(f9uN1V#Xg(KC4xUauK8KRn64vB&r45QR9&RW- zc{v80X(oR*ZHWh~H|?w1)Dr=B_I*3c6GQ=n7S^;Y`C*{vs%Qdf=u~!XxOa0MI;+f8 zN#;h!#!LCQUz*{AVR~Q9$&CwGVER_Ekq?iBT{e4pdCjq){d}t)22p^y{?aDF5XqSVGt-qZ{Q zm*g0pU0*}tfSCLyk;pK}l>DO9svi#9Mes2Rw0K|`yi}czc1(E4eXZy~nU5EIN;BdJ zz|b)2hxsErz+gzX(^;AVEZCB>op});@%&ck4Ie}SPts-M>=;;0%btZl5D)XOM&5d8 z;u0a>F?zlDFxs6Kveu^8`@M_hd%j=t1*!O`> zasSp}P)%Ve;Cm1Z7E>WXZ*T=6pv`uaZA~Z+y4^A-SWQD=lDb;v#q&`3blA1~6*`a3 z8)U(ktsV|%^^3i*%xJ~4rM;AU0Of#p`%d!q5#W3)>(}^tB7A7hkVt7GK>?H0a~2K? z$as|(`H{Q&s7ZNN0NZ^{k?MU z_%M*D)eOjp3WbTc47{-@UNDv7^fh%3f$LI)nTWt(2tT6XFg<|uo-pTr8(G45fx~tg z!dRFz-xAknKk=xq0rUMFYx0G z4$`o@fnbMZe<$wj@JnYYl>#<-t9-t}nG6 zqHHL9Q{)H`96{djBvXKUN*ILjSkm2B35TA}%`T&#!{H3eN2?$A@NgukwzB&w0h~8i ziiI=~;mjJ18|LjKcubbb=aWF-)4EqF{v2A2UTB#-aVQG(*;mC+7Q}#uXQn9TP(0w8 zG9(WuStUZr@qXRr)yYsitLii969y0Il|Gc82?hCco0V-Wao~M!mw=&C2z)mEj&&Cg zhLQzNvUeO7<%4cLBk*8BN9fMGxauHy9c$#*bt4Gqx=r+9xBL%!m9g+Z|uAq3PPh5 zk{evZz_#fyWfk%T8=LojXr2m(sB!MOXJ}O$cU`iEjI!iK;kv!j$P&H`yYYFpg#-yd z?qB5Mr+~p-`-di35fHQXypg9<6!75hJesSH0d_GtT?ZR<4$rz!nWxVp5lVS49iC=N zhOu+jIeQ$?p^TS}3U?ilFy_d&9$15e8`F396@L$g)`z&1RMueFy*H7j7D>M`*Neu6 zRaiL7>PGkKN)RyHYOi)B2SIaig{gO85R4f(={i3N0_`>lE~D*O5b+L7IerZbW}Btt z0&xMsa84^|e!WNtRL9(N=@-Sp*!#Dotqh^?rj<99p(+&o?2HT=?89JKc6LllEF9be zZ%)MYghTyBqu|PFvv`5%_qy-o^Hk-J>y%QT3<5t!Ah`4LY*Lysnxxe-_P$F);;g_hq2O)tXuK^a9xmF<)x87WY^wqI%Dq-eItyClV+?F+wbPyr0!HgkJ46-w7c zxBjifW-Agnyt`O-fPoA`NqV1!U*PR@;mJ{;UkLDakI>HKsg()gxIY6l)5 znYBS;Z}>_$bcv=`nO%tlFHiO?SF30+?|IGYl172hzl6<#7meb*$2JiV~aJu6|rP&3H0Y?qNQpptXx~E*UAwhzWS=&A8 zyNICuX?80k%H7mhiaT8Jk-5EcE%f%pe82tA^toaD0`+$r}5tf&5rv;;tJ_=X$1%b5MYAq#q2LU5T4ntd^nmF2uW}5 zJkm)Bg7n*K8-xY|xah6M8eb>E6;EoMAqNQtmda{f?~uU2H`P=ng$%c)x2n5e3kIu` z*?co+L*VI*i}fsG#eXh`Z40yvgOF=~7{|)O!TWZ5h6s*iwyQSk{M?9w^C_O*Pfidh z&`#WZd-_m36xGgI6=^4e{7f9T7;g%sP=m%-S*Z_kNI8n&9a6)DJ$>#t+JD z_6N>GFG}9~U@W{klRQB9=?_mFP7!Tu0^rmElasY>fpDExjhti^1apm&m)?31pn7@z z2+@oPZdpESSHBVA1Fv}aNo-hXx`;RVZOCx*sb9RLN-%uqR=8$_Y_}zbk6vdHC3pD~ zMOu)+zCbu{@GDX`DchSPOU5I>Aiv@7&f8Jo5t!0XSVGt>z3RtFH%`a6+ z7H7#!8_B?Sl4ZDog#;b8mz1Oj2q3gay&zgO2pU~)%YSA^^Q2c#s&*U-fSAb=gnr9=1)+l2T&l+aJESsUy?2Tz+_N#Xw;CpbM$e)} zP9zDc2S+;Cu`(KE3s4f|MxB6m%PWIfWXJKZ^1i}3;MPAevd@vW6HQP#xyBz3b0I|! zR01L(*l~wNwL%oM$`E9>^dcdlu-XdjlHy=cE@R{UU;>myYu`;oLc(M}F{=iHj&GGU zlqgJucamy-?ju29Io_}Eus0C=JAUg?Xt5&7dNTC;GS+%AwK}1g4ZXz8g9AtWfjg~% zmgBxZbSyVSvvuRjc<;PWu;35J28xE0qyvDR5LaSIXbFJ+hFR143xV*L^mZzkHwf}f zCL8jf1%a#V%Ck9aMpcTabVt3hKj1BOPh%vZzZK`F^js3OGJcQxrA~$-Gl7jG$coEQ z;9|E&r9{v?t5{wOlG^C1O{Q_Q+jFH&kgGoozL#7}y|O0)l$Azz|7k`rTEaHQrnWB{ zf;@Z7P7q>&x)3)NxFZ47zggB=M<#)KL$s^)W;|#D+1^q0NpObd756l@=|aB*=V#9m zA(zRHv*Q~9lwNPOiEPB#65X4lD{=&Iiji*bXC*+{BHg`_O$1mT6fkL|BLK6w*;&@( z1WTe*JK z&5Hy*%;)btq$h*y>AQy}(#c>I#x$dYY?tKq;qimm7s%N2-ToSkw7$f$_Z^7)70tT0 zeisRYIH^d|9FA`Jx4i0MGmHTCuL;M#Q4x%GzOYu|7qfTogD-KdLYu9|ync zQ`fmQ6M(m2t*tVc40N$W*Y2-kkC?bPU>!t)?U$zLPVFRt&-^jfk65fyYyxhdPbNb4 zmRpL|&e%bXo-(5v6H(~kad^du2mv>fPt9o&;k;Y7o3IHH$V}n!#sp7%rcC$BIPry2 zJy%<_dWlf8&*RZ3e&T%r_Y3{cl0ZU$xP2NC*s%Aak`Ap$$QtddtD zZd;4rT^`{?Sbf-=^s$Br@vCcu7w_&9p|$FwiNRYUsQV}!`Nc*8epB(~2S-S7=|!pc zDuDz)&V1j?KSTog+kxI+WN`&51>*i;!FgFfxF5xgJU@%b4k=_#ztrcH7)DJh}VHOY)T&<%y(*P|=1|3s+wY1UL{CsMnEcHNS$2#054grH=}Mr5s=o3f?dh75(K z3om98qQTJG>%b6+0;j!-z1n%=ffVe_*WXNr?DIo^d8NtV|APL}r!IUnWZ6!7EY0?@ zkbjr*k>I(Rl+;-~qBG7kjfuY|f^NaK8-#mAI4E&rj)0#y!|y14KH>`xjXjcgmJ#6# zL48_Gvx^8S;cRP{W{I$Ty#3x)T!GM*<+46}_L3{IBunpm8%>`#q>~o+ny*w1~#E&5w2zuI8{e(I%ADsmAFt=suN!b3EuzUx}K{CWGsU{%`;v8Q^gH zQh8Wi70fcs9$(V5aUAbR@^?VA>{8IFP>OfJ&$v$lk*ovzDGfk z@mufA!xR{}`N)BZHy%92-no9kBUdA}sU(z<3|E)MTSV~DI5M~0VZulC@nPoUM}LT5 zCcHNC0-wFNJi^DtyxpJUzW;IUfX5a@SWSD5SP0@u99?@$_?4Q0`##oRx(l~Q zTfb?TcpniR1EvI?;7YJF4vpz6kYK!^r|J#j07tJ+`EG5+BY5fY_f>Y>1vZa<{O}~h z5!UCzTNaQV>mhF&dLH?JA!b{`kR|s}@-VqZBLs{&i)D?F?*Ey=&zS|s|91orr?nu# z=^F>ZIdJ6{7KsPFY-U+7Ek3-vP^yBAg%lQ6d(LP?F590z(xgDF_O{V3fq2m7`ZQ~t zK!&memob&UB#D;%$9gOq876dkF7s)Z>9Y`q9*L47!}>V)neWWN4*#Jaj&g1P|;V zbO`W}Ao#48zSIPEOs*Zf7BQ%GyW~T>{fH2^xj5w9OFRjMnw7&!FgLvC zcU}EKf|cOh@>iG0s3Xd~lk$)Z+Q$-7XAYuqAG5{U&AS*2uY3fLiXqAMqQf{X^8enj zO3S}O9?%8h=zqyPC3lu78U|swJlmTB zTKpgR*{tIs;y9nqO6t8ADRyH{vtr|@9e_GV$V2Xlf)!THRb3KA#?Z@Y5}yWvRfTEV|&h=_!nHUuFq zz<(!t!{;z6CzKibx@u8J^eh2vkU<&f)+jKKXxZM&n?E`t1*~p1wumr}rBSF}@M`7eSQojX;g0EcHRezX=z4PBuyKlqcRG|oduK9yn;@3{ zeMi!Zv2|n|B ztu!0q5-*(6^UFtcT&`krhKUT)#64~qCb$d6pL7l&Q~IFPOG%?W!7$9LGJF#?AmuMQ zc)lT5)c1Xsh5C~a(EM>RRUEk>G^vD$KU8G1r>gz^W$`5pNI6p@mdio<;5~#eE8I{{lLflTO!_xB?o=i;Dl0)A{vQZ+ozW zI$G;mck`cJKy@nCP$j{F;i2iKA`<-anwky!Oadb{!$h zFaosgmy}tuA|X(u;OVSkG>B)k&Cxxf0ORvFOQ|98aH-ntvs@eo-`zv4m2dFmvr#eD zGRA?0BI60O6(aZ?%sw4;iwN?~GP`ImW0`OBq5ZKnM!(RPgPq4PHq7#D6$mGYAlIVt z_$3C#Mv185iPJ<7*U#>l!WU#}-mjXAAwn%n-&7`7^+!zpIo(#K=9b!#NPO4U?lwB|AYOVM>Gj56j0Wxb|B}WX1&~p8*#C25+a;9s9i)qL4FPc=l`$X`7pw|w4D@lZo2ic|fOo?Ej z*mBV^p9rx^IR;d$5yih4*xPLo;q|@T*GdOT@NTOd%c~d?Syz^x^z(KAtKqsY66FC&wsjJTNY9bDmJgZFA1fedj+7MDXG7ohrN} zSnUXkFTfg6eS7RCUYrxQeo*y1#!ZIZEk{j0Vm546K3a7nlMMToWllzzqpNEdt#220 zNJlqj`c53j*>UjnoA+ag7p{qaQMJSvaCh-L^c&gkIoW?DruDE*HvD#5YhMI-ey=c3 zYl?*A#6BQjh=%LFLlf*%6sSMYsO6DDsy8#g)UT}Ryo#=+2V2t z^krI2kPaYPd(}X&w-?PAT4_?-aE`5@uP8Zg5DtPt1s#Erk*HZnA7kHz@prfJTQYA_ z0vO%US6}Q;hTBiP)MsnbfxevFeGalgiYej5Bu5^!wU4W7Gf~0i^F`&oEQK%U19<2$T+zLA0qat;O;?A8e6a{x zw7EXvPlma_yvEZWWDpL^acRViywnkO72WU6*2+n6_?;t1co43@fLDPcD)x9Lp3}%9Qor}J z>yo5iFa+;89)5c`7z&oZe^PS5`E_gBn;~TCRV*>psr^8P@51KlJhUG9%OkwWB^1Th zvp`^BEsBJvO?PRWkTPs3)XjT5J^>=mHR&u4Cc`NQsaVTev=T_ZzN^(J8_xe0H8?Gt z2MKIu>r5O}&>Wx~$zm@Anze?BM=Zsl?IrrHT&)xyGtSyBOO+!hiTis>b0s*n35K|5 zR6~)&>r@}FTG++Lr}aUp9@_K>RR^{?)q}29#}C(Tw9++rM1F{~$jWv_bzA&ooGOV* zKMYCmDm1)%@*xRKZ5Y2iNhX1EqvN=14tD5jat8gysA=@FwiL5P7Z>>*qO{AX+KM~( zQVtb83Q3(!TFB1+!*{w$k_}lLj-A{|68P-5{@5{w1bZ=ppAv8H{YY3p*ZRn>C>qYF zCPq8tCjf)X^t{nHuE4Wx^wJ%8Il!Im#QPVsLDFtc^jK(E-V(oo?~A`@C@`fyl1!{dR~`SsI~c9;#n!wq6OWFk(Jf}7FU6mSr=FlFWB2`w zW-N!pfInBOi$)vwzbw~@nT~J*Jn>=7vz?9vIpyV|v(KWzui{3=P;CN$6aC9=zms9X zRZXw_bvmRUU}Unpkqx?MOnJ%jdBD+=y!a-eXi9i%lKuyuzDTCV=qTt<> z#8Exn7%=!;vxQ?N0jx}a8R*ET0Jn|qR4P{nq_DdDeQ_rnqKADb%@%pEI_qP$U`T}z zdX4hrGlkIcAuQqE$zq_jE7d*`RthY%%ty~%Ek}j#QNFL6tHA4bCg;*@HI&$y%4=rV zg0&ri`|~OHdYH~<-oltt57rMv-pr|af%l|ynGNZDQk7_L5I2ei|$s@5| zh)X@yF%egO9|m_{{%A5qKAQ|-x5jp(Kx9)ZT+gJ|M1k|Qws|+ylM`lqt&@2YA$aq3 z_I{fbxV0ne=-v|~x5DS709)@u82Ll-Ix9^LA&kC-S1d_+7^TR z16hON(o&=XE=zBTEr-f#y^?gvDv%L-8a%*QgX%6fez%5NAk0bUoVO0H2R`9AtF6WL zpb}*G*ulmNPI|@01=HiR%{7kjc0fkXwxVH91V_97h6L89VfJJ7f9QfU%C{V?v(Iqf zAOE{0;uv{xabF;Rq7kh=l#Hp*1t=Ni~YRBca>qQXY z+k>I?NE*}(9^%B8RHuynrQVK8(`MPBgGhk=b(x$3C zIl!QEf&Wx|9=Kne1^H+ySP#8F7aLs&$3M>2+#(gj>b4%P*e9jXeU+2$Q*${mzm=Z2 zX;}p#RO$gQr5aG(D1EK@gis5QCtH6^<<>)V=!3t#?e#Ep{=4F>G%v)JpIdD)K-ZQ} zii*1sZK+n7fjAOX_OpZx=`B{TEm3qWrF=DsX(Si|ZgH$Qr=cs0 zdH6^UGWs3Y$34S`P+qPpLwkMzbHJeRRAX#7Xasv{{mGMKg|v+XrpN2 zo&~Rdj3)&S=_YurQ4)cLU!8lRKLvIgNEJtPWPq73?}nB`4ipOwcx2S)!A|Ekw)}c3 zi171nc4;kyR}GYdVwJ_PW54r^=6WeOylx4z{!|V}($e|U6RUvt#Al@a)_|kUmahbl zxmxIrtv|E&2v5Lq38&x>7y~yBEqFfn0z+4co&xltxytRVa0%y64P3_6kE+RFw*8u* zA4dH~O!?b7j1gHo^D`p*(Wk0R#gIWL7ljICVp{0TwE5Y@ar20D2$hrdvffpoxBN=rhh7 z2ij|W9-#U%$3qi|o1P_gnr&iQq9bkicmDrT-ydz<7 zf~!pF3Nm;EcuK@Qv~p@_MN0qu>Maj77bu~9EEr0q}IGbGUEiBmE=3@ zLmw|^pEvJ`gY{tH`@Vfi@aLg0-Ly~|>{B}%%%GG7ie5kUtd?#nY8SESz%s06u(DX)*tSA)UmtY4lB?*CMh zQ)pgM9mwz>tJ+f7fV0VC$wAc(Fz+h%+t}J0wkBvDU`j%jl>vkF5tI-)Qk{62lhJ?f zd$yd20W%PK%$x39kPoQ6^W~eK3WIdF6Tzlt;V_;Pve-C*YE8{TMHaLQ$#%*Jx^i>~j#=?zVXIlF2#zS?#rg=qE0#x6coltt20ykd#$v$P60m9YA zG9?u`P#P<*I`c9Q=&6Hz;w%O5P+a-kwY0q)7|UlBRf1o2O0Z|h4n!RvD$HC;vg zK+i-+>uYBOl0oVj9YnZc_JP?2ewS! z!Ds#};ILUC64_sHiZR?clmz2RJA5WdX|N^lg3P>37W5DXom|>;VWB8)YWiC~%&87H zJ<>0P`Z1>S+|*)NVz0A&|F;x)u7wGbTi`@CjL9S~NY z_&2vbt_S50Q~hBF8zKM2eQx3CW(em`cOAUm3^%zC#R+`#L&d&HCZ#(PB-qva4{Alh z0^4?(KPZTgG04!BKn7ke*KLQ54ku&}^>z5CxfTeO}{?F~Dgyeu957 z2DDE8t>^BhfFE0+37=9N0p6;nwyo}uhs=Z-`C1f7e;z;PnS!2z7919T9x^6@6=N~i z2--)?XMd4UzLJhJ4PTNT-j-5-;Z$WBRzT+xbh>>LsSwL1*7^8PAr!u-QB1HZ0rzzt z$B~{gsEhjj{Dxp95D}y#J?TUMdE7)@#_7`6$5ft1QmuI|X*04EA*- zT*fOk40uDRIDum(H%ANZP5_!OP0>~XXc>@VbkRsS34UGJ8>EWHdK-$7yWZoiV^ze< zcdL(L4QO3@Eb>MkSd%@jd#6(&i`LI{3|C<2UZVPST!Bk;bDj^Ml|k!t*R36Vm0-Q| z#Ffj-)sTDStub#}EvQ8az9ML7)I%5Lklsz>22|#cPzt*nVM<-L@#5hYu$r5F{b^SV z2=0&(U+eILt!hK3zvM=O2E&N8#@;CSo7dUAH#!1B-Ci&Tm_-5?xv{pDHWE^9x!I3V zqrh{NE%s$=6b#<-9hIAl28NgHYcellAc4$8Z&pJACR+)@{3W3{IDYcf6gPoQ<*d^4B^mptNs)C|s=yf0au{D6N}P;(y5 zPq;?7l5ILr?Ro7;jI?9~>>pc6Nd6iDPFF)29P%Q-<=d>Xnnn~nx|E=_*&+(83u_}5 zP_a{%@cntw z){3G;xTM8=VS}0k6NTpP1@F^9PC}0Jv{x2bx;8!jLA1D#+XQP5g=2p6%^M%;J zL?()04Y*>+A$*^%4EXu)=-oI{0RjC&Lhsh9fOBmk3OF(U-`ZD|cD}w2M9gk7+_+m0 z*HpM>m_!?4^D*MZSL9}R+OIOdVc!e~w`~@grt<@_7{Pdti3n(EsY|?T9SJ$tG*S|u zg#+(|OnPWq1X_!2$SNO0oysA~!N{RV$k=AyD*7=JUN6PQv%Dou;W>1!s{}uQPYd^~6K7;zyeai$qA0VRMQ#OoF24 zbIrEFX|NiiJ=MjO1u13(kH=oQu$-OimHi+e7W1qebXg0*wG48Fbcwt$-`86ZGJv;(3>RM?~`~l zNJ(Y)v@y9T!}CFElv!=9s{j;)tQO`r;R?`y8=urJg}xTGZv%Ka5}80v-6Bv02Tf@w z2>J3g&{Y|op?jbXjIN0O+I_Gd>~a}2bYdF-D(x0NylsNH^Ndw5?>1qfdYttN#TWJq z9X{o08Ud$PEZ$i?L7PaLV|#2h(K_JVcfb}c6OKd2Nos>R2KWc)i zErR4TJ%=c~z$UoL6wOq-xr+&=cAV%TsOiz|=|+Kz$E�uEruq>4F9SMjUXj8)QAS ziw9wbq@yMa36T4_wfxYVM7Tjc=1aSr3f-$g{%4&tVNmbv%-P#F!IjhBWshk-WQD80 zI2>C5m#gR!j2;$2=W#}1F_uy|%&d^lD~VTn?HgG-+*1j*M+iTtm)=%`llMN6bAM|= zRCYR>dA$x!a_HOJU{3f**tuIZrwQn2W-8VQO<*FR`lRbDS6LBL40-d;Su8yMag3zc40_3pd^xrHh2+O^+Cl?T!S~JI0Ib`=dZVIK^ON zb2KOu*w#YA-b91xPrf}dQojY=h9iKwVt74yF#;USy&n(!jRcyysfyG=l!uwcXmqP)N5jDK z_m!tVW1w-DMq(tU$H_BB9#Xz>z-B1_vlBT=DShwEUZS<2>OkK^mas&4Ev{1zlvGe+ z(xsnS&HzR!-A}0sHzD@2sK>j_`Ec1;RybX)0Fv0ryr-S9ABg0VJVPx3`t6|etgQ?* zTxLHj8WSo((8TF_ie)tv{KE=wsRe1nX8)&nBAU@Bhw(5pz%Y+})C@F%zRYR4D3K<( z(*2!uZLcr*Ye}bVdK(VL9)ayf+7S>^o6H{h3QgB@HJu#LK&L@0X!I|H!{?7lQY+OF zAY>@#xUVMy$m=CUV>}rz4DFY>La0X6ORVRVl6y2%9X7DM{v-z4-%oXOv{8W9Hkur& z90#sz$6F27v5Z%7v+P38;be706 zYp>*i!_FnzMZp4ip8iI$Ub_emu8*#d`j$X%u4s@yr3|SD` zbFbu%tXg=pduyh4QXPc!`?*F=)q^$%_nrL$O)&A~&-N{}P2j%RbT@_57dn^T%)P&h zM7x~>8mjxz9@0O4*`+QF*jJbC-*pLxhY7nGwD{3hiaMg-l7xmC3w3tiaw34(I7sqs z#%oihe-e6*$Dyv<$a|M!@qOui2meGyl`M`|OlEV!uItP5DZE(UAAc@d?El4KqwXFiu^d z0H^5gJ??K}fuy}JOAVR)w0p1mXdrw0*4|xQ=~9WHGPUrfNHP_Kwsu;U`e(pWVUED2 z`W#T+c6g`x{XEE7pUHXffeIBZ7d+Z%i(qerV;ASa61esC;!64nLK!d^@zP!Hu7Hv3 zFZ7oru;!zmIqOVxQ0I#qlr$yJD>aVLJ}WqIrs-dW`Z6-lXIA{oF^_2 zFFmQ>b(Y{23E$lx#4w+Z0>L-_0m_@AK~_LQ=eSi2uu3@$4(L)~TqNM8IGU$Sv}~KK z@j}mWA@Q03xdf2*GL`y`b-}hktrdB$R9IR|J=bt01JaAqKd=|&z=po1$M%*yI6lsJ z`ou65XuP|g5xy2e-8^^455W@XFPkS5cFLE*-dO4i70ctxT#tpn-Km0>$PZCCcY~B! zAEpAMI@o%U)V-5h54~z8O$_+#_X}~WL^NQhL>$;3^415O27Zf}B_P7lb6)&5Rz8e5 zoU8e0tVcKY`S(s4G*N5|9-ct*MY!+YbZxT;$O~QkM8U2ZQt}8@A04r2Jo-9q5?7!+ zTt$@+i$swzT1o5kF`zBgBGht>0)H#YJ-NHEOWu9i-~f6JU)VFg{R&z)mM!Y*3h*Vu zUxxekvbX{_SWkWWc0L36>b6M7#pXbXh=y`ibsn&-$XZ-|MFopSbJ5i=h2Zn!=Vb%F z5*Ru}pb|92%b=}!YHW9X1^Dl$pDS*zg2UnqX*wpgFc;oe^ir!1Y+X%m&m`BwTv0>$ z`L0ITdo!teqofhOxrlw6?DT=lZ+?pv1c$@w7OvwNENGU-k;}Cfh6KEn9E$%5#QS!w zJAdv*I;z3mN`1WuP%k*Iw}4f$F~N4b_sOeRL|VpQ^issOxjlK9ekbOFDQ`()yl?}N|@DWbtu( Date: Fri, 9 Sep 2016 21:25:05 -0400 Subject: [PATCH 15/82] Possibly have a fix --- src/mgxs_header.F90 | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 51fb1384c2..47081eb5a5 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -567,7 +567,7 @@ module mgxs_header if (norm > ZERO) then scatt_coeffs(gin) % data(:, gout) = & scatt_coeffs(gin) % data(:, gout) * & - input_scatt(gin) % data(1, gout) + input_scatt(gin) % data(1, gout) / norm end if end do ! gout end do ! gin @@ -1062,7 +1062,6 @@ module mgxs_header ! Determine the scattering type of our data and ensure all scattering orders ! are the same. scatter_type = nuclides(mat % nuclide(1)) % obj % scatter_type -write(*,*) 'scatter_type', scatter_type select type(nuc => nuclides(mat % nuclide(1)) % obj) type is (MgxsIso) order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) @@ -1320,8 +1319,6 @@ write(*,*) 'scatter_type', scatter_type end do end if - write(*,*) this % scatter_type - ! Deallocate temporaries deallocate(jagged_mult, jagged_scatt, gmin, gmax, scatt_coeffs, & temp_mult, mult_num, mult_denom) @@ -1901,7 +1898,7 @@ write(*,*) 'scatter_type', scatter_type ! sqrt(temperature), (with temperature in units of MeV) !=============================================================================== - pure subroutine mgxs_find_temperature(this, sqrtkT) + subroutine mgxs_find_temperature(this, sqrtkT) class(Mgxs), intent(inout) :: this real(8), intent(in) :: sqrtkT ! Temperature (in units of of MeV) From 61feb8cc6de0bcac0bab46876f2c7fe978d9fe46 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 10 Sep 2016 08:40:04 -0400 Subject: [PATCH 16/82] Updated mgxs-part-iv --- .../pythonapi/examples/mgxs-part-iv.ipynb | 193 ++++++++---------- 1 file changed, 90 insertions(+), 103 deletions(-) diff --git a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb index a4f4069516..b360206917 100644 --- a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb +++ b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb @@ -431,7 +431,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "" ] @@ -734,8 +734,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 6cf7f7fa48d70d26165403f8067aedb598534990\n", - " Date/Time | 2016-09-08 20:16:34\n", + " Git SHA1 | 84df6a1f10c7811eed59e4ea04cddf2afd42ef75\n", + " Date/Time | 2016-09-10 08:37:58\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -822,20 +822,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 3.2700E-01 seconds\n", - " Reading cross sections = 2.1500E-01 seconds\n", - " Total time in simulation = 2.2139E+01 seconds\n", - " Time in transport only = 2.1970E+01 seconds\n", - " Time in inactive batches = 2.6960E+00 seconds\n", - " Time in active batches = 1.9443E+01 seconds\n", - " Time synchronizing fission bank = 2.0000E-03 seconds\n", - " Sampling source sites = 1.0000E-03 seconds\n", - " SEND/RECV source sites = 1.0000E-03 seconds\n", + " Total time for initialization = 3.3600E-01 seconds\n", + " Reading cross sections = 2.1200E-01 seconds\n", + " Total time in simulation = 2.1540E+01 seconds\n", + " Time in transport only = 2.1352E+01 seconds\n", + " Time in inactive batches = 2.4040E+00 seconds\n", + " Time in active batches = 1.9136E+01 seconds\n", + " Time synchronizing fission bank = 6.0000E-03 seconds\n", + " Sampling source sites = 3.0000E-03 seconds\n", + " SEND/RECV source sites = 3.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 2.2488E+01 seconds\n", - " Calculation Rate (inactive) = 18546.0 neutrons/second\n", - " Calculation Rate (active) = 10286.5 neutrons/second\n", + " Total time elapsed = 2.1898E+01 seconds\n", + " Calculation Rate (inactive) = 20798.7 neutrons/second\n", + " Calculation Rate (active) = 10451.5 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -973,25 +973,12 @@ "metadata": { "collapsed": false }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(array([0, 1]),)\n", - "(array([0, 1]),)\n", - "(array([0, 1]),)\n", - "(array([0, 1]),)\n", - "(array([0, 1]),)\n", - "(array([0, 1]),)\n" - ] - } - ], + "outputs": [], "source": [ "# Create a MGXS File which can then be written to disk\n", "mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=['fuel', 'zircaloy', 'water'])\n", "\n", - "# Write the file to disk using the default filename of `mgxs.xml`\n", + "# Write the file to disk using the default filename of `mgxs.h5`\n", "mgxs_file.export_to_hdf5()" ] }, @@ -1121,8 +1108,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 6cf7f7fa48d70d26165403f8067aedb598534990\n", - " Date/Time | 2016-09-08 20:16:57\n", + " Git SHA1 | 84df6a1f10c7811eed59e4ea04cddf2afd42ef75\n", + " Date/Time | 2016-09-10 08:38:20\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -1147,56 +1134,56 @@ "\n", " Bat./Gen. k Average k \n", " ========= ======== ==================== \n", - " 1/1 0.68770 \n", - " 2/1 0.71454 \n", - " 3/1 0.69764 \n", - " 4/1 0.68400 \n", - " 5/1 0.69412 \n", - " 6/1 0.70489 \n", - " 7/1 0.70203 \n", - " 8/1 0.70721 \n", - " 9/1 0.69408 \n", - " 10/1 0.70103 \n", - " 11/1 0.69351 \n", - " 12/1 0.71450 0.70401 +/- 0.01049\n", - " 13/1 0.70298 0.70366 +/- 0.00607\n", - " 14/1 0.69351 0.70113 +/- 0.00499\n", - " 15/1 0.70901 0.70270 +/- 0.00417\n", - " 16/1 0.70364 0.70286 +/- 0.00341\n", - " 17/1 0.68831 0.70078 +/- 0.00355\n", - " 18/1 0.69861 0.70051 +/- 0.00309\n", - " 19/1 0.71634 0.70227 +/- 0.00324\n", - " 20/1 0.70641 0.70268 +/- 0.00293\n", - " 21/1 0.69300 0.70180 +/- 0.00279\n", - " 22/1 0.70086 0.70172 +/- 0.00255\n", - " 23/1 0.68664 0.70056 +/- 0.00262\n", - " 24/1 0.70558 0.70092 +/- 0.00245\n", - " 25/1 0.70057 0.70090 +/- 0.00228\n", - " 26/1 0.68193 0.69971 +/- 0.00244\n", - " 27/1 0.69492 0.69943 +/- 0.00231\n", - " 28/1 0.68723 0.69875 +/- 0.00228\n", - " 29/1 0.71304 0.69950 +/- 0.00228\n", - " 30/1 0.69086 0.69907 +/- 0.00221\n", - " 31/1 0.71083 0.69963 +/- 0.00218\n", - " 32/1 0.69658 0.69949 +/- 0.00208\n", - " 33/1 0.70807 0.69987 +/- 0.00202\n", - " 34/1 0.71266 0.70040 +/- 0.00201\n", - " 35/1 0.69799 0.70030 +/- 0.00193\n", - " 36/1 0.67602 0.69937 +/- 0.00207\n", - " 37/1 0.72219 0.70021 +/- 0.00217\n", - " 38/1 0.71427 0.70072 +/- 0.00215\n", - " 39/1 0.71017 0.70104 +/- 0.00210\n", - " 40/1 0.69683 0.70090 +/- 0.00203\n", - " 41/1 0.71530 0.70137 +/- 0.00202\n", - " 42/1 0.69487 0.70116 +/- 0.00197\n", - " 43/1 0.69785 0.70106 +/- 0.00191\n", - " 44/1 0.72084 0.70165 +/- 0.00194\n", - " 45/1 0.69741 0.70152 +/- 0.00189\n", - " 46/1 0.70040 0.70149 +/- 0.00183\n", - " 47/1 0.71724 0.70192 +/- 0.00183\n", - " 48/1 0.70980 0.70213 +/- 0.00180\n", - " 49/1 0.70660 0.70224 +/- 0.00175\n", - " 50/1 0.69329 0.70202 +/- 0.00172\n", + " 1/1 0.99100 \n", + " 2/1 1.02112 \n", + " 3/1 1.04240 \n", + " 4/1 1.01591 \n", + " 5/1 1.02044 \n", + " 6/1 1.04127 \n", + " 7/1 1.01783 \n", + " 8/1 1.03856 \n", + " 9/1 1.03637 \n", + " 10/1 1.03884 \n", + " 11/1 1.04466 \n", + " 12/1 1.01060 1.02763 +/- 0.01703\n", + " 13/1 1.02517 1.02681 +/- 0.00987\n", + " 14/1 1.05287 1.03333 +/- 0.00954\n", + " 15/1 1.04369 1.03540 +/- 0.00768\n", + " 16/1 1.01304 1.03167 +/- 0.00729\n", + " 17/1 1.04258 1.03323 +/- 0.00636\n", + " 18/1 1.02301 1.03195 +/- 0.00565\n", + " 19/1 1.03906 1.03274 +/- 0.00505\n", + " 20/1 1.04148 1.03362 +/- 0.00460\n", + " 21/1 1.01271 1.03172 +/- 0.00457\n", + " 22/1 1.02021 1.03076 +/- 0.00428\n", + " 23/1 0.99553 1.02805 +/- 0.00478\n", + " 24/1 1.02434 1.02778 +/- 0.00443\n", + " 25/1 1.02987 1.02792 +/- 0.00413\n", + " 26/1 1.01676 1.02722 +/- 0.00393\n", + " 27/1 1.02738 1.02723 +/- 0.00369\n", + " 28/1 1.04014 1.02795 +/- 0.00355\n", + " 29/1 1.02831 1.02797 +/- 0.00336\n", + " 30/1 1.02643 1.02789 +/- 0.00319\n", + " 31/1 1.03939 1.02844 +/- 0.00308\n", + " 32/1 1.03277 1.02864 +/- 0.00294\n", + " 33/1 1.00167 1.02746 +/- 0.00305\n", + " 34/1 1.01791 1.02707 +/- 0.00294\n", + " 35/1 1.03889 1.02754 +/- 0.00286\n", + " 36/1 1.02693 1.02752 +/- 0.00275\n", + " 37/1 1.02346 1.02737 +/- 0.00265\n", + " 38/1 1.00974 1.02674 +/- 0.00263\n", + " 39/1 1.01456 1.02632 +/- 0.00257\n", + " 40/1 1.02217 1.02618 +/- 0.00249\n", + " 41/1 0.99130 1.02505 +/- 0.00266\n", + " 42/1 1.05167 1.02588 +/- 0.00271\n", + " 43/1 1.01675 1.02561 +/- 0.00264\n", + " 44/1 1.00496 1.02500 +/- 0.00263\n", + " 45/1 1.00466 1.02442 +/- 0.00262\n", + " 46/1 1.01644 1.02420 +/- 0.00255\n", + " 47/1 1.01033 1.02382 +/- 0.00251\n", + " 48/1 1.02299 1.02380 +/- 0.00245\n", + " 49/1 1.01468 1.02357 +/- 0.00239\n", + " 50/1 1.02616 1.02363 +/- 0.00233\n", " Creating state point statepoint.50.h5...\n", "\n", " ===========================================================================\n", @@ -1206,27 +1193,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 3.5000E-02 seconds\n", - " Reading cross sections = 6.0000E-03 seconds\n", - " Total time in simulation = 3.7004E+01 seconds\n", - " Time in transport only = 3.6761E+01 seconds\n", - " Time in inactive batches = 3.6530E+00 seconds\n", - " Time in active batches = 3.3351E+01 seconds\n", + " Total time for initialization = 4.0000E-02 seconds\n", + " Reading cross sections = 8.0000E-03 seconds\n", + " Total time in simulation = 1.5523E+01 seconds\n", + " Time in transport only = 1.5428E+01 seconds\n", + " Time in inactive batches = 1.6880E+00 seconds\n", + " Time in active batches = 1.3835E+01 seconds\n", " Time synchronizing fission bank = 7.0000E-03 seconds\n", - " Sampling source sites = 6.0000E-03 seconds\n", - " SEND/RECV source sites = 1.0000E-03 seconds\n", + " Sampling source sites = 5.0000E-03 seconds\n", + " SEND/RECV source sites = 2.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 3.7062E+01 seconds\n", - " Calculation Rate (inactive) = 13687.4 neutrons/second\n", - " Calculation Rate (active) = 5996.82 neutrons/second\n", + " Total time elapsed = 1.5587E+01 seconds\n", + " Calculation Rate (inactive) = 29620.9 neutrons/second\n", + " Calculation Rate (active) = 14456.1 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.70328 +/- 0.00159\n", - " k-effective (Track-length) = 0.70202 +/- 0.00172\n", - " k-effective (Absorption) = 0.70409 +/- 0.00106\n", - " Combined k-effective = 0.70345 +/- 0.00102\n", + " k-effective (Collision) = 1.02217 +/- 0.00260\n", + " k-effective (Track-length) = 1.02363 +/- 0.00233\n", + " k-effective (Absorption) = 1.02649 +/- 0.00171\n", + " Combined k-effective = 1.02638 +/- 0.00171\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -1308,8 +1295,8 @@ "output_type": "stream", "text": [ "Continuous-Energy keff = 1.024295\n", - "Multi-Group keff = 0.703447\n", - "bias [pcm]: 32084.7\n" + "Multi-Group keff = 1.026377\n", + "bias [pcm]: -208.3\n" ] } ], @@ -1406,7 +1393,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 40, @@ -1415,9 +1402,9 @@ }, { "data": { - "image/png": "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\n", + "image/png": "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\nj6+jc35fUPaoKtihatHMSnmsV8q32daN9/Gl728Wag6s807/rKprWalq0fFFZ/mFYT6/uueOUHPw\nQTdnpr9F1qc1EtZebMAfjK8axiZV+y34/Ru/Osxn14eiLx+w6Eufxdi2BM2Qeo7V21WwYdWCn799\n5OLFNXW4ws5q8oDeIN++sWBw9Igq2Ltqwc+Lf9k/LOtuPyjUjKnYITb68Nj317vt9cXWza66hi5V\nJy34PXFcfH7QJi7r9c3WCzVHcUuouZ5jF1t3XdVMTqxaMM6OZcj6YknCf/hRqBniJ4SacXeUMIj4\nH3XqZ3wVbFK16LoRszKz6Nu3LSNHrljUt5ujy6UP8La7T07faR1K8iBPiNaOfFu0aJojoHdj0W9B\nTKVh34EQoqUi3xYtmuboQ6/vVqD+e7FRVQv/X65zM5jSvLSr3KbcJjSYVSo3jUUtjZUqQ8mU6glM\nrW72sSyl+/aIqoX/t2t9vr18K/TtrSvblduEhrFKZYnCUdT2ab7zTvYcJM0R0KeSfJCnlrUo9nGe\nun3mrYzWGdC/V24TGs7KlaFk7cr1Wbty4Scynh/UkE+Xl0zpvl3QZ94aaVfZJxa1MLapbB+LWhIl\nB/Qd0gV69GjLhAnFnyE1R5fLi0APM1vHkg/AH0zywXwhWjvybdGiafIWurvPN7OTSUYs1r7a9UZT\nlyPE0ka+LVo6zfIeurs/SsNmJRKiVSDfFi2ZZgnoJXNrkL5HCXl8XYKmhPmRtnk/a2KfhNHdsmal\nSpjMuqFm/mbx5Op3sG9m+hZedw6CxTnnP38ONcM/jL8Ie/r+9X12fVGe6bd9qHn6D7uGmiMe/muo\n6ctjoeaKUNG8rHfM4u9213KPH1g0rZYxv/5hXMh18Xvf3Y5/J9QUnUungPW3fC3UvD1ti1Dz5Qpx\nYS8smzVjW5rPrA6h5hIGhJoevFuCJq7DcW1KeA/9k1iy6MRJ9ZG93xr6L4QQOUEBXQghcoICuhBC\n5AQFdCGEyAkK6EIIkRMU0IUQIicooAshRE5QQBdCiJxQtjlFzcy5K/sD9BWV8TzHx3cdEmqunvW7\n2KCZ8YAH23B+qDnBrgw1r9T0DDXPWmVm+sHhqCy4a+IxocbWi/fJr4oHQv2sfzwbyUOv7B9qVtjw\no1DTr8PDoeYeO7pZZiwqBTPzR2uKT5yw2zIPxJlc1CmUzD0+bo/NaxNXQbsOsQ+Mt3hiihk1XUPN\n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\nAwmwhqwYOz+DAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1447,7 +1434,7 @@ "collapsed": true }, "source": [ - "We also see very good agreement between the fission rate distributions, though these should converge closer together with an increasing number of particle histories in both the continuous-energy run to generate the multi-group cross sections, and in the multi-group calculation itself." + "We also see good agreement between the fission rate distributions, though these should converge closer together with an increasing number of particle histories in both the continuous-energy run to generate the multi-group cross sections, and in the multi-group calculation itself." ] }, { From 255aba1fc0ca9f576b9784acda8c7778927e4210 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 10 Sep 2016 11:28:08 -0400 Subject: [PATCH 17/82] Updated ipython notebook, fixed minor corrections throughout, and added h5 wrapper functions in hdf5_interface so the various from_hdf5 routines dont have to call low-level functions directly --- .../pythonapi/examples/mgxs-part-iv.ipynb | 112 ++++++------ docs/source/usersguide/input.rst | 2 +- openmc/mesh.py | 4 + openmc/mgxs_library.py | 6 +- src/hdf5_interface.F90 | 22 +++ src/mgxs_header.F90 | 169 ++++++++++-------- src/nuclide_header.F90 | 37 ++-- src/reaction_header.F90 | 17 +- src/sab_header.F90 | 16 +- src/secondary_uncorrelated.F90 | 17 +- 10 files changed, 206 insertions(+), 196 deletions(-) diff --git a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb index b360206917..f384afb55e 100644 --- a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb +++ b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb @@ -431,7 +431,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "" ] @@ -734,8 +734,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 84df6a1f10c7811eed59e4ea04cddf2afd42ef75\n", - " Date/Time | 2016-09-10 08:37:58\n", + " Git SHA1 | 61feb8cc6de0bcac0bab46876f2c7fe978d9fe46\n", + " Date/Time | 2016-09-10 09:22:09\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -822,20 +822,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 3.3600E-01 seconds\n", - " Reading cross sections = 2.1200E-01 seconds\n", - " Total time in simulation = 2.1540E+01 seconds\n", - " Time in transport only = 2.1352E+01 seconds\n", - " Time in inactive batches = 2.4040E+00 seconds\n", - " Time in active batches = 1.9136E+01 seconds\n", - " Time synchronizing fission bank = 6.0000E-03 seconds\n", - " Sampling source sites = 3.0000E-03 seconds\n", - " SEND/RECV source sites = 3.0000E-03 seconds\n", + " Total time for initialization = 2.9000E-01 seconds\n", + " Reading cross sections = 1.7200E-01 seconds\n", + " Total time in simulation = 1.9592E+01 seconds\n", + " Time in transport only = 1.9464E+01 seconds\n", + " Time in inactive batches = 2.3150E+00 seconds\n", + " Time in active batches = 1.7277E+01 seconds\n", + " Time synchronizing fission bank = 1.0000E-02 seconds\n", + " Sampling source sites = 5.0000E-03 seconds\n", + " SEND/RECV source sites = 5.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 2.1898E+01 seconds\n", - " Calculation Rate (inactive) = 20798.7 neutrons/second\n", - " Calculation Rate (active) = 10451.5 neutrons/second\n", + " Total time elapsed = 1.9904E+01 seconds\n", + " Calculation Rate (inactive) = 21598.3 neutrons/second\n", + " Calculation Rate (active) = 11576.1 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -1108,8 +1108,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 84df6a1f10c7811eed59e4ea04cddf2afd42ef75\n", - " Date/Time | 2016-09-10 08:38:20\n", + " Git SHA1 | 61feb8cc6de0bcac0bab46876f2c7fe978d9fe46\n", + " Date/Time | 2016-09-10 09:22:29\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -1165,25 +1165,25 @@ " 29/1 1.02831 1.02797 +/- 0.00336\n", " 30/1 1.02643 1.02789 +/- 0.00319\n", " 31/1 1.03939 1.02844 +/- 0.00308\n", - " 32/1 1.03277 1.02864 +/- 0.00294\n", - " 33/1 1.00167 1.02746 +/- 0.00305\n", - " 34/1 1.01791 1.02707 +/- 0.00294\n", - " 35/1 1.03889 1.02754 +/- 0.00286\n", - " 36/1 1.02693 1.02752 +/- 0.00275\n", - " 37/1 1.02346 1.02737 +/- 0.00265\n", - " 38/1 1.00974 1.02674 +/- 0.00263\n", - " 39/1 1.01456 1.02632 +/- 0.00257\n", - " 40/1 1.02217 1.02618 +/- 0.00249\n", - " 41/1 0.99130 1.02505 +/- 0.00266\n", - " 42/1 1.05167 1.02588 +/- 0.00271\n", - " 43/1 1.01675 1.02561 +/- 0.00264\n", - " 44/1 1.00496 1.02500 +/- 0.00263\n", - " 45/1 1.00466 1.02442 +/- 0.00262\n", - " 46/1 1.01644 1.02420 +/- 0.00255\n", - " 47/1 1.01033 1.02382 +/- 0.00251\n", - " 48/1 1.02299 1.02380 +/- 0.00245\n", - " 49/1 1.01468 1.02357 +/- 0.00239\n", - " 50/1 1.02616 1.02363 +/- 0.00233\n", + " 32/1 1.03282 1.02864 +/- 0.00294\n", + " 33/1 1.00098 1.02744 +/- 0.00306\n", + " 34/1 1.01763 1.02703 +/- 0.00296\n", + " 35/1 1.01412 1.02651 +/- 0.00288\n", + " 36/1 1.01564 1.02609 +/- 0.00280\n", + " 37/1 1.02255 1.02596 +/- 0.00270\n", + " 38/1 1.04764 1.02674 +/- 0.00271\n", + " 39/1 1.03299 1.02695 +/- 0.00263\n", + " 40/1 1.01040 1.02640 +/- 0.00260\n", + " 41/1 1.03493 1.02667 +/- 0.00253\n", + " 42/1 1.00289 1.02593 +/- 0.00256\n", + " 43/1 1.01429 1.02558 +/- 0.00250\n", + " 44/1 1.04207 1.02606 +/- 0.00248\n", + " 45/1 1.03141 1.02622 +/- 0.00241\n", + " 46/1 1.02055 1.02606 +/- 0.00235\n", + " 47/1 1.03659 1.02634 +/- 0.00230\n", + " 48/1 1.04200 1.02676 +/- 0.00228\n", + " 49/1 1.02003 1.02658 +/- 0.00222\n", + " 50/1 1.04396 1.02702 +/- 0.00221\n", " Creating state point statepoint.50.h5...\n", "\n", " ===========================================================================\n", @@ -1193,27 +1193,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 4.0000E-02 seconds\n", - " Reading cross sections = 8.0000E-03 seconds\n", - " Total time in simulation = 1.5523E+01 seconds\n", - " Time in transport only = 1.5428E+01 seconds\n", - " Time in inactive batches = 1.6880E+00 seconds\n", - " Time in active batches = 1.3835E+01 seconds\n", - " Time synchronizing fission bank = 7.0000E-03 seconds\n", + " Total time for initialization = 3.1000E-02 seconds\n", + " Reading cross sections = 6.0000E-03 seconds\n", + " Total time in simulation = 1.4773E+01 seconds\n", + " Time in transport only = 1.4743E+01 seconds\n", + " Time in inactive batches = 1.4380E+00 seconds\n", + " Time in active batches = 1.3335E+01 seconds\n", + " Time synchronizing fission bank = 5.0000E-03 seconds\n", " Sampling source sites = 5.0000E-03 seconds\n", - " SEND/RECV source sites = 2.0000E-03 seconds\n", + " SEND/RECV source sites = 0.0000E+00 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 1.5587E+01 seconds\n", - " Calculation Rate (inactive) = 29620.9 neutrons/second\n", - " Calculation Rate (active) = 14456.1 neutrons/second\n", + " Total time elapsed = 1.4827E+01 seconds\n", + " Calculation Rate (inactive) = 34770.5 neutrons/second\n", + " Calculation Rate (active) = 14998.1 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.02217 +/- 0.00260\n", - " k-effective (Track-length) = 1.02363 +/- 0.00233\n", - " k-effective (Absorption) = 1.02649 +/- 0.00171\n", - " Combined k-effective = 1.02638 +/- 0.00171\n", + " k-effective (Collision) = 1.02681 +/- 0.00251\n", + " k-effective (Track-length) = 1.02702 +/- 0.00221\n", + " k-effective (Absorption) = 1.02734 +/- 0.00171\n", + " Combined k-effective = 1.02733 +/- 0.00150\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -1295,8 +1295,8 @@ "output_type": "stream", "text": [ "Continuous-Energy keff = 1.024295\n", - "Multi-Group keff = 1.026377\n", - "bias [pcm]: -208.3\n" + "Multi-Group keff = 1.027328\n", + "bias [pcm]: -303.3\n" ] } ], @@ -1393,7 +1393,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 40, @@ -1402,9 +1402,9 @@ }, { "data": { - "image/png": "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\nj6+jc35fUPaoKtihatHMSnmsV8q32daN9/Gl728Wag6s807/rKprWalq0fFFZ/mFYT6/uueOUHPw\nQTdnpr9F1qc1EtZebMAfjK8axiZV+y34/Ru/Osxn14eiLx+w6Eufxdi2BM2Qeo7V21WwYdWCn799\n5OLFNXW4ws5q8oDeIN++sWBw9Igq2Ltqwc+Lf9k/LOtuPyjUjKnYITb68Nj317vt9cXWza66hi5V\nJy34PXFcfH7QJi7r9c3WCzVHcUuouZ5jF1t3XdVMTqxaMM6OZcj6YknCf/hRqBniJ4SacXeUMIj4\nH3XqZ3wVbFK16LoRszKz6Nu3LSNHrljUt5ujy6UP8La7T07faR1K8iBPiNaOfFu0aJojoHdj0W9B\nTKVh34EQoqUi3xYtmuboQ6/vVqD+e7FRVQv/X65zM5jSvLSr3KbcJjSYVSo3jUUtjZUqQ8mU6glM\nrW72sSyl+/aIqoX/t2t9vr18K/TtrSvblduEhrFKZYnCUdT2ab7zTvYcJM0R0KeSfJCnlrUo9nGe\nun3mrYzWGdC/V24TGs7KlaFk7cr1Wbty4Scynh/UkE+Xl0zpvl3QZ94aaVfZJxa1MLapbB+LWhIl\nB/Qd0gV69GjLhAnFnyE1R5fLi0APM1vHkg/AH0zywXwhWjvybdGiafIWurvPN7OTSUYs1r7a9UZT\nlyPE0ka+LVo6zfIeurs/SsNmJRKiVSDfFi2ZZgnoJXNrkL5HCXl8XYKmhPmRtnk/a2KfhNHdsmal\nSpjMuqFm/mbx5Op3sG9m+hZedw6CxTnnP38ONcM/jL8Ie/r+9X12fVGe6bd9qHn6D7uGmiMe/muo\n6ctjoeaKUNG8rHfM4u9213KPH1g0rZYxv/5hXMh18Xvf3Y5/J9QUnUungPW3fC3UvD1ti1Dz5Qpx\nYS8smzVjW5rPrA6h5hIGhJoevFuCJq7DcW1KeA/9k1iy6MRJ9ZG93xr6L4QQOUEBXQghcoICuhBC\n5AQFdCGEyAkK6EIIkRMU0IUQIicooAshRE5QQBdCiJxQtjlFzcy5K/sD9BWV8TzHx3cdEmqunvW7\n2KCZ8YAH23B+qDnBrgw1r9T0DDXPWmVm+sHhqCy4a+IxocbWi/fJr4oHQv2sfzwbyUOv7B9qVtjw\no1DTr8PDoeYeO7pZZiwqBTPzR2uKT5yw2zIPxJlc1CmUzD0+bo/NaxNXQbsOsQ+Mt3hiihk1XUPN\n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\nAwmwhqwYOz+DAAAAAElFTkSuQmCC\n", + "image/png": "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\ngg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 08444f23a9..b6e66c85ac 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -737,7 +737,7 @@ coefficients. This element has the following attributes/sub-elements: *Default*: 33 - .. note:: This element is not used in the multi-group :ref:`energy_mode`. + .. note:: This element is only used in the multi-group :ref:`energy_mode`. .. _temperature_default: diff --git a/openmc/mesh.py b/openmc/mesh.py index 43ac7aef05..d2a911262b 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -291,6 +291,10 @@ class Mesh(object): # Would prefer to have the z ranges be the max supported float, but # these values are apparently different between python and Fortran. # Choosing a safe and sane default. + # Values of +/-1000 are used here as there seems to be an + # inconsistency between what numpy uses as the max float and what + # Fortran expects for a real(8), so this avoids code complication + # and achieves the same goal. zplanes = [openmc.ZPlane(z0=-1000., boundary_type='reflective'), openmc.ZPlane(z0=1000., diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 2079b88015..a15aa51aec 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -14,14 +14,10 @@ if sys.version_info[0] >= 3: basestring = str # Supported incoming particle MGXS angular treatment representations -_REPRESENTATION_ISOTROPIC = 1 -_REPRESENTATION_ANGLE = 2 -_SCATTER_TYPE_TABULAR = 3 -_SCATTER_TYPE_LEGENDRE = 4 -_SCATTER_TYPE_HISTOGRAM = 5 _REPRESENTATIONS = ['isotropic', 'angle'] _SCATTER_TYPES = ['tabular', 'legendre', 'histogram'] + class XSdata(object): """A multi-group cross section data set providing all the multi-group data necessary for a multi-group OpenMC calculation. diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 2ac06595b7..0eafd49b3c 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -102,6 +102,7 @@ module hdf5_interface public :: write_attribute_string public :: get_groups public :: get_datasets + public :: get_name contains @@ -333,6 +334,27 @@ contains end subroutine get_datasets +!=============================================================================== +! GET_NAME Obtains the name of the current group in group_id +!=============================================================================== + + function get_name(group_id, name_len_) result(name) + integer(HID_T), intent(in) :: group_id + integer(SIZE_T), optional, intent(in) :: name_len_ + + character(len=255) :: name ! name of group + integer(SIZE_T) :: name_len, name_file_len + integer :: hdf5_err ! HDF5 error code + + if (present(name_len_)) then + name_len = name_len_ + else + name_len = 255 + end if + + call h5iget_name_f(group_id, name, name_len, name_file_len, hdf5_err) + end function get_name + !=============================================================================== ! OPEN_GROUP opens an existing HDF5 group !=============================================================================== diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 47081eb5a5..e3cc09bd7d 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -3,8 +3,7 @@ module mgxs_header use, intrinsic :: ISO_FORTRAN_ENV use, intrinsic :: ISO_C_BINDING - use hdf5, only: HID_T, HSIZE_T, SIZE_T, h5iget_name_f - use h5lt, only: h5ltpath_valid_f + use hdf5, only: HID_T, HSIZE_T, SIZE_T use algorithm, only: find, sort use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI @@ -212,8 +211,7 @@ module mgxs_header type(VectorInt), intent(out) :: temps_to_read ! Temperatures to read integer, intent(out) :: order_dim ! Scattering data order size - integer :: hdf5_err - integer(SIZE_T) :: name_len, name_file_len + integer(SIZE_T) :: name_len integer(HID_T) :: kT_group character(MAX_FILE_LEN), allocatable :: dset_names(:) real(8), allocatable :: temps_available(:) ! temperatures available @@ -225,7 +223,7 @@ module mgxs_header ! Get name of dataset from group name_len = len(this % name) - call h5iget_name_f(xs_id, this % name, name_len, name_file_len, hdf5_err) + this % name = get_name(xs_id, name_len) ! Get rid of leading '/' this % name = trim(this % name(2:)) @@ -452,8 +450,8 @@ module mgxs_header ! If we have a need* for the fission and kappa-fission x/s, get them ! (*Need is defined as will be using it to tally) if (get_fiss) then - allocate(xs % fission(groups)) if (check_dataset(xsdata_grp, "fission")) then + allocate(xs % fission(groups)) call read_dataset(xs % fission, xsdata_grp, "fission") else call fatal_error("Fission data missing, required due to fission& @@ -461,8 +459,8 @@ module mgxs_header end if end if if (get_kfiss) then - allocate(xs % k_fission(groups)) if (check_dataset(xsdata_grp, "kappa-fission")) then + allocate(xs % k_fission(groups)) call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") else call fatal_error("kappa-fission data missing, required due to & @@ -471,8 +469,8 @@ module mgxs_header end if end if - allocate(xs % absorption(groups)) if (check_dataset(xsdata_grp, "absorption")) then + allocate(xs % absorption(groups)) call read_dataset(xs % absorption, xsdata_grp, "absorption") else call fatal_error("Must provide absorption!") @@ -581,30 +579,37 @@ module mgxs_header deallocate(input_scatt) ! Now get the multiplication matrix - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - do gin = 1, groups - length = length + (gmax(gin) - gmin(gin) + 1) - end do - ! Allocate flattened array - allocate(temp_arr(length)) - if (.not. check_dataset(scatt_grp, 'multiplicity matrix')) & - call fatal_error("'multiplicity matrix' must be provided") - call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") - - ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing - ! to ScattData - allocate(temp_mult(groups)) - index = 1 - do gin = 1, groups - allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) - do gout = gmin(gin), gmax(gin) - temp_mult(gin) % data(gout) = temp_arr(index) - index = index + 1 + if (check_dataset(scatt_grp, 'multiplicity matrix')) then + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do gin = 1, groups + length = length + (gmax(gin) - gmin(gin) + 1) end do - end do - deallocate(temp_arr) + ! Allocate flattened array + allocate(temp_arr(length)) + call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups)) + index = 1 + do gin = 1, groups + allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) + do gout = gmin(gin), gmax(gin) + temp_mult(gin) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + deallocate(temp_arr) + else + ! Default to multiplicities of 1.0 + allocate(temp_mult(groups)) + do gin = 1, groups + allocate(temp_mult(gin) % data(gmin(gin):gmax(gin))) + temp_mult(gin) % data = ONE + end do + end if ! Allocate and initialize our ScattData Object. if (this % scatter_type == ANGLE_HISTOGRAM) then @@ -641,6 +646,7 @@ module mgxs_header ! Close the groups we have opened and deallocate call close_group(xsdata_grp) + call close_group(scatt_grp) deallocate(scatt_coeffs, temp_mult) end associate ! xs end do ! Temperatures @@ -689,7 +695,7 @@ module mgxs_header if (check_dataset(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi - allocate(temp_arr(1 * groups * this % n_azi * this % n_pol)) + allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "chi") ! Initialize counter for temp_arr l = 0 @@ -920,39 +926,50 @@ module mgxs_header deallocate(input_scatt) ! Now get the multiplication matrix - ! Now use this information to find the length of a container array - ! to hold the flattened data - length = 0 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - length = length + (gmax(gin, iazi, ipol) - gmin(gin, iazi, ipol) + 1) - end do - end do - end do - ! Allocate flattened array - allocate(temp_arr(length)) - if (.not. check_dataset(scatt_grp, 'multiplicity matrix')) & - call fatal_error("'multiplicity matrix' must be provided") - call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") - - ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing - ! to ScattData - allocate(temp_mult(groups, this % n_azi, this % n_pol)) - index = 1 - do ipol = 1, this % n_pol - do iazi = 1, this % n_azi - do gin = 1, groups - allocate(temp_mult(gin, iazi, ipol) % data( & - gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) - do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) - temp_mult(gin, iazi, ipol) % data(gout) = temp_arr(index) - index = index + 1 + if (check_dataset(scatt_grp, 'multiplicity matrix')) then + ! Now use this information to find the length of a container array + ! to hold the flattened data + length = 0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + length = length + (gmax(gin, iazi, ipol) - gmin(gin, iazi, ipol) + 1) end do end do end do - end do - deallocate(temp_arr) + ! Allocate flattened array + allocate(temp_arr(length)) + call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing + ! to ScattData + allocate(temp_mult(groups, this % n_azi, this % n_pol)) + index = 1 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(temp_mult(gin, iazi, ipol) % data( & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + do gout = gmin(gin, iazi, ipol), gmax(gin, iazi, ipol) + temp_mult(gin, iazi, ipol) % data(gout) = temp_arr(index) + index = index + 1 + end do + end do + end do + end do + deallocate(temp_arr) + else + allocate(temp_mult(groups, this % n_azi, this % n_pol)) + ! Default to multiplicities of 1.0 + do ipol = 1, this % n_pol + do iazi = 1, this % n_azi + do gin = 1, groups + allocate(temp_mult(gin, iazi, ipol) % data( & + gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) + temp_mult(gin, iazi, ipol) % data = ONE + end do + end do + end do + end if ! Allocate and initialize our ScattData Object. allocate(xs % scatter(this % n_azi, this % n_pol)) @@ -1013,6 +1030,7 @@ module mgxs_header ! Close the groups we have opened and deallocate call close_group(xsdata_grp) + call close_group(scatt_grp) deallocate(scatt_coeffs, temp_mult) end associate ! xs end do ! Temperatures @@ -1220,22 +1238,22 @@ module mgxs_header type is (MgxsIso) ! Perform our operations which depend upon the type ! Add contributions to total, absorption, and fission data (if necessary) - this % xs(t) % total(:) = this % xs(t) % total(:) + & - atom_density * nuc % xs(nuc_t) % total(:) - this % xs(t) % absorption(:) = this % xs(t) % absorption(:) + & - atom_density * nuc % xs(nuc_t) % absorption(:) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption if (nuc % fissionable) then - this % xs(t) % chi(:, :) = this % xs(t) % chi(:, :) + & - atom_density * nuc % xs(nuc_t) % chi(:, :) - this % xs(t) % nu_fission(:) = this % xs(t) % nu_fission(:) + & - atom_density * nuc % xs(nuc_t) % nu_fission(:) + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission if (allocated(nuc % xs(nuc_t) % fission)) then - this % xs(t) % fission(:) = this % xs(t) % fission(:) + & - atom_density * nuc % xs(nuc_t) % fission(:) + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission end if if (allocated(nuc % xs(nuc_t) % k_fission)) then - this % xs(t) % k_fission(:) = this % xs(t) % k_fission(:) + & - atom_density * nuc % xs(nuc_t) % k_fission(:) + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission end if end if @@ -1547,13 +1565,12 @@ module mgxs_header end do end do - ! Create the Jagged arrays + ! Now create our jagged data from the dense data call jagged_from_dense_2D(scatt_coeffs(:, :, :, iazi, ipol), & jagged_scatt) call jagged_from_dense_1D(temp_mult(:, :, iazi, ipol), & jagged_mult, gmin, gmax) - ! Initialize the ScattData Object ! Initialize the ScattData Object call this % xs(t) % scatter(iazi, ipol) % obj % init(gmin, & gmax, jagged_mult, jagged_scatt) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 1fbd691ee8..07b8a99b7b 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -3,9 +3,7 @@ module nuclide_header use, intrinsic :: ISO_FORTRAN_ENV use, intrinsic :: ISO_C_BINDING - use hdf5, only: HID_T, HSIZE_T, SIZE_T, h5iget_name_f, h5gget_info_f, & - h5lget_name_by_idx_f, H5_INDEX_NAME_F, H5_ITER_INC_F - use h5lt, only: h5ltpath_valid_f + use hdf5, only: HID_T, HSIZE_T, SIZE_T use algorithm, only: sort, find use constants @@ -14,7 +12,8 @@ module nuclide_header use endf_header, only: Function1D, Polynomial, Tabulated1D use error, only: fatal_error, warning use hdf5_interface, only: read_attribute, open_group, close_group, & - open_dataset, read_dataset, close_dataset, get_shape, get_datasets + open_dataset, read_dataset, close_dataset, get_shape, get_datasets, & + check_group, get_name, get_groups use list_header, only: ListInt use math, only: evaluate_legendre use multipole_header, only: MultipoleArray @@ -194,10 +193,6 @@ module nuclide_header real(8), intent(in) :: tolerance integer :: i - integer :: storage_type - integer :: max_corder - integer :: n_links - integer :: hdf5_err integer :: i_closest integer :: n_temperature integer(HID_T) :: urr_group, nu_group @@ -208,21 +203,21 @@ module nuclide_header integer(HID_T) :: total_nu integer(HID_T) :: fer_group ! fission_energy_release group integer(HID_T) :: fer_dset - integer(SIZE_T) :: name_len, name_file_len + integer(SIZE_T) :: name_len integer(HSIZE_T) :: j integer(HSIZE_T) :: dims(1) character(MAX_WORD_LEN) :: temp_str character(MAX_FILE_LEN), allocatable :: dset_names(:) + character(MAX_FILE_LEN), allocatable :: grp_names(:) real(8), allocatable :: temps_available(:) ! temperatures available real(8) :: temp_desired real(8) :: temp_actual - logical :: exists type(VectorInt) :: MTs type(VectorInt) :: temps_to_read ! Get name of nuclide from group name_len = len(this % name) - call h5iget_name_f(group_id, this % name, name_len, name_file_len, hdf5_err) + this % name = get_name(group_id, name_len) ! Get rid of leading '/' this % name = trim(this % name(2:)) @@ -305,12 +300,10 @@ module nuclide_header ! Get MT values based on group names rxs_group = open_group(group_id, 'reactions') - call h5gget_info_f(rxs_group, storage_type, n_links, max_corder, hdf5_err) - do j = 0, n_links - 1 - call h5lget_name_by_idx_f(rxs_group, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, & - j, temp_str, hdf5_err, name_len) - if (starts_with(temp_str, "reaction_")) then - call MTs % push_back(int(str_to_int(temp_str(10:12)))) + call get_groups(rxs_group, grp_names) + do j = 1, size(grp_names) + if (starts_with(grp_names(j), "reaction_")) then + call MTs % push_back(int(str_to_int(grp_names(j)(10:12)))) end if end do @@ -326,8 +319,7 @@ module nuclide_header call close_group(rxs_group) ! Read unresolved resonance probability tables if present - call h5ltpath_valid_f(group_id, 'urr', .true., exists, hdf5_err) - if (exists) then + if (check_group(group_id, 'urr')) then this % urr_present = .true. allocate(this % urr_data(n_temperature)) @@ -368,8 +360,7 @@ module nuclide_header end if ! Check for nu-total - call h5ltpath_valid_f(group_id, 'total_nu', .true., exists, hdf5_err) - if (exists) then + if (check_group(group_id, 'total_nu')) then nu_group = open_group(group_id, 'total_nu') ! Read total nu data @@ -388,9 +379,7 @@ module nuclide_header end if ! Read fission energy release data if present - call h5ltpath_valid_f(group_id, 'fission_energy_release', .true., exists, & - hdf5_err) - if (exists) then + if (check_group(group_id, 'fission_energy_release')) then fer_group = open_group(group_id, 'fission_energy_release') ! Check to see if this is polynomial or tabulated data diff --git a/src/reaction_header.F90 b/src/reaction_header.F90 index a7896e9ff3..12b3888c4b 100644 --- a/src/reaction_header.F90 +++ b/src/reaction_header.F90 @@ -5,7 +5,7 @@ module reaction_header use constants, only: MAX_WORD_LEN use hdf5_interface, only: read_attribute, open_group, close_group, & - open_dataset, read_dataset, close_dataset, get_shape + open_dataset, read_dataset, close_dataset, get_shape, get_groups use product_header, only: ReactionProduct use stl_vector, only: VectorInt use string, only: to_str, starts_with @@ -42,17 +42,12 @@ contains integer :: i integer :: cm integer :: n_product - integer :: storage_type - integer :: max_corder - integer :: n_links - integer :: hdf5_err integer(HID_T) :: pgroup integer(HID_T) :: xs, temp_group - integer(SIZE_T) :: name_len integer(HSIZE_T) :: dims(1) integer(HSIZE_T) :: j - character(MAX_WORD_LEN) :: name character(MAX_WORD_LEN) :: temp_str ! temperature dataset name, e.g. '294K' + character(MAX_WORD_LEN), allocatable :: grp_names(:) call read_attribute(this % Q_value, group_id, 'Q_value') call read_attribute(this % MT, group_id, 'mt') @@ -74,12 +69,10 @@ contains end do ! Determine number of products - call h5gget_info_f(group_id, storage_type, n_links, max_corder, hdf5_err) n_product = 0 - do j = 0, n_links - 1 - call h5lget_name_by_idx_f(group_id, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, & - j, name, hdf5_err, name_len) - if (starts_with(name, "product_")) n_product = n_product + 1 + call get_groups(group_id, grp_names) + do j = 1, size(grp_names) + if (starts_with(grp_names(j), "product_")) n_product = n_product + 1 end do ! Read products diff --git a/src/sab_header.F90 b/src/sab_header.F90 index 147643065a..5f49fdc42b 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -8,9 +8,9 @@ module sab_header use distribution_univariate, only: Tabular use error, only: warning, fatal_error use hdf5, only: HID_T, HSIZE_T, SIZE_T - use h5lt, only: h5ltpath_valid_f, h5iget_name_f use hdf5_interface, only: read_attribute, get_shape, open_group, close_group, & - open_dataset, read_dataset, close_dataset, get_datasets + open_dataset, read_dataset, close_dataset, get_datasets, check_group, & + get_name use secondary_correlated, only: CorrelatedAngleEnergy use stl_vector, only: VectorInt, VectorReal use string, only: to_str, str_to_int @@ -91,8 +91,7 @@ contains integer :: n_energy, n_energy_out, n_mu integer :: i_closest integer :: n_temperature - integer :: hdf5_err - integer(SIZE_T) :: name_len, name_file_len + integer(SIZE_T) :: name_len integer(HID_T) :: T_group integer(HID_T) :: elastic_group integer(HID_T) :: inelastic_group @@ -102,7 +101,6 @@ contains integer(HSIZE_T) :: dims3(3) real(8), allocatable :: temp(:,:) character(20) :: type - logical :: exists type(CorrelatedAngleEnergy) :: correlated_dist character(MAX_WORD_LEN) :: temp_str @@ -114,7 +112,7 @@ contains ! Get name of table from group name_len = len(this % name) - call h5iget_name_f(group_id, this % name, name_len, name_file_len, hdf5_err) + this % name = get_name(group_id, name_len) ! Get rid of leading '/' this % name = trim(this % name(2:)) @@ -180,8 +178,7 @@ contains T_group = open_group(group_id, temp_str) ! Coherent elastic data - call h5ltpath_valid_f(T_group, 'elastic', .true., exists, hdf5_err) - if (exists) then + if (check_group(T_group, 'elastic')) then ! Read cross section data elastic_group = open_group(T_group, 'elastic') dset_id = open_dataset(elastic_group, 'xs') @@ -223,8 +220,7 @@ contains end if ! Inelastic data - call h5ltpath_valid_f(T_group, 'inelastic', .true., exists, hdf5_err) - if (exists) then + if (check_group(T_group, 'inelastic')) then ! Read type of inelastic data inelastic_group = open_group(T_group, 'inelastic') diff --git a/src/secondary_uncorrelated.F90 b/src/secondary_uncorrelated.F90 index fc215484a9..756ff83df7 100644 --- a/src/secondary_uncorrelated.F90 +++ b/src/secondary_uncorrelated.F90 @@ -1,6 +1,5 @@ module secondary_uncorrelated - use h5lt, only: h5ltpath_valid_f use hdf5, only: HID_T use angle_distribution, only: AngleDistribution @@ -9,7 +8,7 @@ module secondary_uncorrelated use energy_distribution, only: EnergyDistribution, LevelInelastic, & ContinuousTabular, MaxwellEnergy, Evaporation, WattEnergy, DiscretePhoton use error, only: warning - use hdf5_interface, only: read_attribute, open_group, close_group + use hdf5_interface, only: read_attribute, open_group, close_group, check_group use random_lcg, only: prn !=============================================================================== @@ -56,25 +55,19 @@ contains class(UncorrelatedAngleEnergy), intent(inout) :: this integer(HID_T), intent(in) :: group_id - logical :: exists - integer :: hdf5_err integer(HID_T) :: energy_group integer(HID_T) :: angle_group character(MAX_WORD_LEN) :: type - ! Check if energy group is present - call h5ltpath_valid_f(group_id, 'angle', .true., exists, hdf5_err) - - if (exists) then + ! Check if angle group is present & read + if (check_group(group_id, 'angle')) then angle_group = open_group(group_id, 'angle') call this%angle%from_hdf5(angle_group) call close_group(angle_group) end if - ! Check if energy group is present - call h5ltpath_valid_f(group_id, 'energy', .true., exists, hdf5_err) - - if (exists) then + ! Check if energy group is present & read + if (check_group(group_id, 'energy')) then energy_group = open_group(group_id, 'energy') call read_attribute(type, energy_group, 'type') select case (type) From e8c8fb7aa8f84400ed304268479cea296b3fe638 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 10 Sep 2016 11:35:26 -0400 Subject: [PATCH 18/82] Updated example pincell_multigroup problem to use h5 library --- .gitignore | 1 + examples/xml/pincell_multigroup/mgxs.h5 | Bin 0 -> 59616 bytes examples/xml/pincell_multigroup/settings.xml | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 examples/xml/pincell_multigroup/mgxs.h5 diff --git a/.gitignore b/.gitignore index b1cb1a623e..724e137038 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ tests/ctestscript.run # HDF5 files *.h5 !tests/1d_mgxs.h5 +!examples/xml/pincell_multigroup/mgxs.h5 # Build files src/CMakeCache.txt diff --git a/examples/xml/pincell_multigroup/mgxs.h5 b/examples/xml/pincell_multigroup/mgxs.h5 new file mode 100644 index 0000000000000000000000000000000000000000..ada3b1c71d8db394f330abf18d5a934544e44456 GIT binary patch literal 59616 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 literal 0 HcmV?d00001 diff --git a/examples/xml/pincell_multigroup/settings.xml b/examples/xml/pincell_multigroup/settings.xml index 1030762faf..ab716d9e47 100644 --- a/examples/xml/pincell_multigroup/settings.xml +++ b/examples/xml/pincell_multigroup/settings.xml @@ -34,6 +34,6 @@ false - ./mg_cross_sections.h5 + ./mgxs.h5 From 8c8e0a7174664fcfc75b6eacce35928076595ecd Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 10 Sep 2016 15:04:07 -0400 Subject: [PATCH 19/82] Updating failing tests --- openmc/mgxs_library.py | 4 +++ src/mgxs_header.F90 | 45 ++++++++++++++++++++------ tests/1d_mgxs.h5 | Bin 123864 -> 123864 bytes tests/test_mg_basic/inputs_true.dat | 2 +- tests/test_mg_tallies/inputs_true.dat | 2 +- 5 files changed, 42 insertions(+), 11 deletions(-) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index a15aa51aec..a5968e299e 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1263,6 +1263,10 @@ class XSdata(object): for g_out in range(g_out_bounds[p, a, g_in, 0], g_out_bounds[p, a, g_in, 1] + 1): flat_mult.append(matrix[g_in, g_out]) + # And write it. + scatt_grp.create_dataset("multiplicity matrix", + data=np.array(flat_mult), + compression=compression) # And finally, adjust g_out_bounds for 1-based group counting # and write it. g_out_bounds[:, :, :, :] += 1 diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index e3cc09bd7d..04fab444a7 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -726,7 +726,11 @@ module mgxs_header ! Get nu_fission (as a vector) if (check_dataset(xsdata_grp, "nu-fission")) then - call read_dataset(xs % nu_fission, xsdata_grp, "nu-fission") + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "nu-fission") + xs % nu_fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) else call fatal_error("If fissionable, must provide nu-fission!") end if @@ -774,8 +778,12 @@ module mgxs_header ! (*Need is defined as will be using it to tally) if (get_fiss) then if (check_dataset(xsdata_grp, "fission")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "fission") allocate(xs % fission(groups, this % n_azi, this % n_pol)) - call read_dataset(xs % fission, xsdata_grp, "fission") + xs % fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) else call fatal_error("Fission data missing, required due to fission& & tallies in tallies.xml file!") @@ -783,8 +791,12 @@ module mgxs_header end if if (get_kfiss) then if (check_dataset(xsdata_grp, "kappa-fission")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "kappa-fission") allocate(xs % k_fission(groups, this % n_azi, this % n_pol)) - call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") + xs % k_fission = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) else call fatal_error("kappa_fission data missing, required due to & &kappa-fission tallies in tallies.xml file!") @@ -793,8 +805,12 @@ module mgxs_header end if if (check_dataset(xsdata_grp, "absorption")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "absorption") allocate(xs % absorption(groups, this % n_azi, this % n_pol)) - call read_dataset(xs % absorption, xsdata_grp, "absorption") + xs % absorption = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) else call fatal_error("Must provide absorption!") end if @@ -805,14 +821,20 @@ module mgxs_header scatt_grp = open_group(xsdata_grp, 'scatter data') ! First get the outgoing group boundary indices if (check_dataset(scatt_grp, "g_min")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, scatt_grp, "g_min") allocate(gmin(groups, this % n_azi, this % n_pol)) - call read_dataset(gmin, scatt_grp, "g_min") + gmin = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(temp_arr) else call fatal_error("'g_min' for the scatter matrix must be provided") end if if (check_dataset(scatt_grp, "g_max")) then + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, scatt_grp, "g_max") allocate(gmax(groups, this % n_azi, this % n_pol)) - call read_dataset(gmax, scatt_grp, "g_max") + gmax = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(temp_arr) else call fatal_error("'g_max' for the scatter matrix must be provided") end if @@ -857,7 +879,7 @@ module mgxs_header ! Finally convert the legendre to tabular if needed ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. + ! problem. Strip off the superfluous orders if needed. if (this % scatter_type == ANGLE_LEGENDRE) then order = min(order_dim - 1, max_order) order_dim = order + 1 @@ -904,7 +926,8 @@ module mgxs_header if (norm > ZERO) then scatt_coeffs(gin, iazi, ipol) % data(:, gout) = & scatt_coeffs(gin, iazi, ipol) % data(:, gout) * & - input_scatt(gin, iazi, ipol) % data(1, gout) + input_scatt(gin, iazi, ipol) % data(1, gout) / & + norm end if end do ! gout end do ! gin @@ -1006,7 +1029,11 @@ module mgxs_header allocate(xs % total(groups, this % n_azi, this % n_pol)) if (check_dataset(xsdata_grp, "total")) then - call read_dataset(xs % total, xsdata_grp, "total") + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "total") + xs % total = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) else do ipol = 1, this % n_pol do iazi = 1, this % n_azi diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 index 38bb500677ae2d95948a7992f0c580130546e90c..d764cb69fbf7d76401c15d7224f62b9d2a28942d 100644 GIT binary patch delta 30608 zcmZ6zc_3D6_dZTVgA`Ix8jMAQh)SwU$Pmh$sfbJ=Ly~ydcqa2aCW&M!QbZ&~(nQG| zr9sM2nJT5>cfaSH_w%0b@2_XDpL_3n?X}i*U2CnayJ>EB)7+9W-r4DO?k$gzmMMj&pF9@rCW9?{BObO-Ty3D zi+?S6eed539`uPw7@obX)K}H@f2)S-{Ilv}{r|0c-RNJ7-Z%Yc(HOITEgE9+??soF zYFnQCYthnLJ4vp;uDO2&*`f1)cj&_V_f`+O{`1D#?VmU9Cj$Q7*JrQ)+H&371R0;d z)-OHi^WWo7pPK)Fw(t$M`s+6d*dABv#QNtXvZ0s$XA7su|9%_&ugeyT{r6=rEBz4b z{r6>Cr~Px;|5;He^Pk`LUugbo#nP)e|GKu}yuYt)asEHowx)pjziZPf&G~0P761I^ zbH&kwEd${R^0)pz`QM)-64a_i|Jo7x9QTyFw5591EGnVDAuIZOE{3HQB`;W|VAjcV z-+Bt!h#b0;R!9XPIO6;I&}=t!3nzusc)PK1rtNX@{5-TN3*1!Mmx4dSOD|OWvvJIp zq1rJw02-6S=krHh(G;g-^_Zs{=MOyHphAuxuuv&9Kahg{sr;O}BsL^XKAfItrct=% zuwQ6ri7RgU6>K$J(2b?-3OWTV^AKy;yX==?3S{!za41uzy#uSV10a4i&12 zO{ZWW$v{6~VFYeHX4tU0E{nCJ%~oLS^0?QnB=W z-;qylq3GSqzhe(?Al^1@=@zYZgTta``yJg~a8=D6Un-gp9{Ze7qo7p8(2I6X^@bv6 z+dKXVpFkMIGrma5oxtvQ`vw{syYPgEcmJqUKHiUye7@C@iVN=x+clNLu%7pWDfN<@ zLdp%hHN(9puw`B0)uf^>l>2xLzp2WHZd%$2;oWJlp)X`OR)(S6&eN3RJq4BdBe&cN z-EppGY_unqY(P`&Rmh)wEZV4fU*&unw(DyJkL!eE#f_Q*tzAKoi98@6rsIM1bdAPF zuP%(*W?SU#DS(s2Q>yv%(z7@y`l`2LP6VX6W9IX=2I0?{jvVej4;1ZrbnUKH7bGu# zvz%vB0OiXDjF;ADp?Ara_egXE`UDJqrECm_yMS;4kBTSu=^t3$sndmy*Jq;W&IK_2 zH898T+*v%{@h-IDdjuqKKWQ*37#x=6v)^3x#FAgsv#>0uE@*Fh^*mut0i>U9TV*JI z7N7TUP72ya;L{6F0n1gvxL3C`dX0=H?w^}eAKTo8L){8H7XQq{Yb_3iw$M~GE?l>7 zhiDk?`S1QFG?&802MMYUu_s{HCcPwYeK+Fy<=XcT<-+t@<-;&pjqsvrRskY~Ux+m~_j z%DZu-Vk&QuOAb8E;<%@T60vQvKULa-ftYpE-L8UXa9K0kdTi7Q-EQ0`66(6qx?g$V zphynZ9R1+a(wu;|P8VWsu4JILK>KLLH(#_c6)czYI#U=BKj}kj>;`X`|Hgn17tz06 zk<0yj0w%cj8aRBU<6O~Cw-2qpNK*2i$*Xt5lg0NRwm;~G<(@yA_3AEy-zY{hDkuS2 z7nY0Y4$#qKFqA2D*B8C&JBsW%oKd@A?8RVnH{9y!?02~r;nAynulh&=imDG3UF)If z(6rBNHzX%e-7eK^6YPWy=OU~cTDq}zX!xFc(nZL!>`rgdAs4jhYEgGH9mlkF#tZKG zqWq%nhB9$05N;bxKub?ZqtHl1-S zNZ zN3c>|8zx5+cP$zzfSmY>tMfU}f&ckt{`)2;v1gIhUG*vtuu9L$=0CASspEY9DRR6N zAHD3*>_Yg7T7_`MrlY02L~&c!NofAG(uiH|i9~^>SKIil(8xSdZAFgvjaAt5{$~LK zswA`wdeWgB^y{(9*hvc6=VsM>z372~6YC}8wj9Qh(qnlcHEnpdU9WLKpb(`otK6vG zbZp3r6gyXT65l#5@;!Rtfw6%zHN-CrgYtNm$n1Y(vBw*~N)U6gk1%a~YFk>Bv=_cV2nwBsMy? zFl?JVpjZ8kx=dL@>ctAq!s~4ie|IorpoVg|XY1kVK z_~%WYIfb8Jf_8^zd10GmpTTTlYm$0Jo8#BCK{C;j8Z19mh?t#oZ)Y7php$5}BZqID z!Zv2k)g5H3GbHArs3=4A$*!crHp`RB14(E|z43tbfS+tL9770V;DM{J-tCm<+_Qv*MA zKOKn}YD3xRpyJI-7qDAsmulF_IB1NYangTgi>cPn5|Uz8F!F27R^F_R`!S+P=O)@P zzk63;SNVBZU6|zVIvk5c%I4sKIm>OaMpE|mtbQxJu`+awRn~xqg?w%BU>gnumz+6y zI|G@2rl;Co#30Uh*V-ddcK9yb`y}?s5vUZq`kvO^kF0Ikwn`msNFIH0C%`xZLuD43 zlaFH%cD#QXPt!5XCNXC9$p&`sOHy7L>tWfA*-iKFwSjs+UF~6PodL}m?uLa=Vo(&v zQ`WJ-0S_k?m)IEF!twDfnFvdLO!KfmFRE%o*PKmq;XWD2sPfnOITM5YRR`Z(ZgoJP zvt6==zO8gi_Ei!y{Ti)tWZPj*(0j# zez6S#*S8wJxOW~h_A?Q`v&j!uO$fbBb#=z#*|~Pp(f06o7$7U6WeDy5mx9l;+hBG1 z-ix1BIA9moRo!ACW7s7=41GX$Y-V{&&c-7X$4_$CNz9FdtNP5dJ;9DB7d-Hs z$Ib5;9FFDQUi0WcspELZ-;xJkB>%#g1ow{71fy?%qmg@uOG076veM~q8yEanjaA&A z#rZePRJhOO{C{z#LS+Hxzkp^VO>C;$au`X&Lv@Xjomed#Ub`%;264gOBGqAm;JWyy zQvxC?6}OeA}c52H_)Qzacuc=M4ElA; zxXNOx6AI?~ou^Z3@Iv{q!RqIM__)8)p0hT-wmvC%FDlM+gjhDjj8qtu~>X}I$BbL zTrZhg7b^z%3dormkQgB!EcX_cFK<6+caNt!B{7*&=))U+^s<9IR_;H()BY1Y7F_Iui#K<$bdFuyiurUjQMk+yQxxF!d z<#2qhc0s$fB_EI^Jy*8%(Fjt{T{t14)rI6(ublBEwMflUyi9Gp9fY&_Eju)S#@9Y^ z_d9-^p#r7uj)s-0qtF(5afMCPOQg&6M^md>j4lj+C9W5Y_NzM+u8Snpie38SJDj-} zztsYzVn;_|VeDtM;CB~9_Ybb#`nVPqA!h_)M}jdJvHfMtiGDv#bqVd3K>gxh&ii4BYjVDTJsnj2PlQay}ej( zJ60xHcLxhs1lm{)Fmd9i-Ryyaq}s@>)W%j`y?rQqEGB4qbR3x*YOLGm_F#@0fnQ_f)7GBK+_3u_quDx6;dA28TALRL#POWzs#~j-Qx6^<0;-`|$b=?*9ShQ1} zJ}`@o{xvVW++~t$SGcaQDGk_%1z)Y-=WZIu*rg}&WAVL^Y*`oB(s2ik6qlRL(jgW; zn8hqsewI}GyrlNvgKz36%7((^z!=8glx}#tv=^6GCUyuj?qK=H7e|cJSXj|^#<%`Z zQtkbOP0wy0)4*2Y==WPMjG<^+JvZsnbDZvQ;CrEb2kgLf#aF5mYy_a?(RqLSXZPzke3#k!C^Dz1uT`i5m z+0i{{vHLU2Ho6Y`=kqGn@iD=7RsQ2?#l+f<@wR){Imj)uo(w)%`5E~Usk0pIdLXZQ z-Fn8W4lTT%nMZpVNN@YnH_4Y+`#GC$q{K)IdH2Qwmc@R?cE<%Z@AmefNA_xTffZGU zrbo|DvMU&v*V+4OY$~C)vp+ApT}}gM94|_byMM;gio=BuC3~P_F!j1ayAHvcUcc{W zGoUu{T=4QM;?<|-Nr}wtgTAZNX>OCx=xMroH=nNuX2Fpf*1PLatMcrXgf9c7TMm!> zd7e z=45?AIW4?bQu`Ra{WAn4TeKp-bwg5?qbWeP4z!5kvyCPU*iPP5RcK166`?wwtQFLP z)eghrF1gPLaHrHz!Ffe`GIGrc9DxtPrCcfj_BJG4H)!!3d zRnM!K7UXQ7^&c#$c(R=H{~%{1<&7}s-{mrbITcjFPwazK> zI>7zskJ(K+w&?t1D-_cq<+9RlYZklK}ydV?o8==(y7?;;9P; zluLMv%AFXPPwhTh#%ADg=)6$Ddknlwu8}%4#(?F`B&qSuOqeHHnk_uSq;T_4lEW?H zbt@Pt?x0_WI zB#?+c_R|Ng$Ej49XKFsKoW(#NN7?w&9wLB;Ix~Ki(4pw%v!*_e4t*Kp=Al|Td_@Kg zOB?90+c*k6lV{k3BrU6Ne8+}X^!AIJfh(9oKSo&Zbyt$fkR7eq}Cn|gd|+E(aSqkMz{Ll*atFRJFz0*bs!<6h zLKI(7Vf{`_L|A&aNEedVg$_COznM6y;p6vClZA-66;{oeEC|1QCpn*+jp0R$oMi;pVmq!2ZUmp&+2!sL>O{BLxkRnhQr{nRI#ai1dc5ASQ+v$64^iMt1qj^ z;P!y|h7P+p^zC=MHZ>;^GdC$pM$IY}mr|ZbbpE8nX6xkF0J3wpaITh#B02<`bc8rzBqlR;cbEaOmy^;XGE97+S`81}vS;E#*iU!aA|~ATH!45m zVxgO*w`fqCg&N05$_a^N;@r z=fkO(DF4l;_=%3yx|aS&O6jO?Gu@m-%0bqL$GEgINFE60&9oyH>6zVJU`(Rp?NU#j zJuSpHzJAQ``#?uGe}{U>90vB-Cq3~eK5&mUvH1!~obx=AT~~*Y%3DfkcV9jOgO_5{ zwTT5RlaAjW5GC=?vrmkE|0omOLLC>yikXN$(9r8M$b?enwPTO8SU9zCZi9R>3#aES z4*x*l-}}Xj`}|%c9~6gF`Sh^yHuPimN$*f(!Fy4pR2aWfH6^?>4Yc{M_j6mF6 zg%e{vkqEC5(r?%ogGVC=Qm-71gNR_@ZTe~|5#u$vFPSG(5g3si%QHwvO;ZK!9M@MJloQ;FT5?PHK1v5xqxEiqSstU2l4b|B*C9mm-Iyd`Z!WTM{ ze=k{FvYG)I_NG(n+6+|f@2=SI%)p^4&%Lgh4AdOpOE~qMfzGeCjuF% zcwA{&{6v)sdXxn z4zt_K?klCxvBS!xjGjx!iP8Kc0R%IW@3T$zPm=s$VdcU>@_~uWkHdRNMtmsbQMB2T zfjd9>&SYdTu%$HikN#7V2lVBrlTrdq2z8n?e=uNzOY^dca4I1%skL5fUNgaYJa5;@ zT`cVE^(i+d%q(+ed6CvQ3mWSii`uN&xOF;7p}Cih^CuGZGDy#&!1c+|nKfa^4DT~E znHP>#QI}s`+#P}F0hxzehy|n%-&Tk;i9ux-M_#sP9Q>rH6<^j#C*o)O+7GJHsgS*} zRV|Xl^*L$jJ+|cDd+Z9I{@_oC{KhE%W!`igwCB)TM?PB!?8)MYqT^w^rf@RJkb}pH zRZbJMREpW<@rY#5;VFr78!iS8`VG#!B>CV|T4tdC0Yawv7X=;-VqkXvfmXjd2HL4z z^MZVTF|f993w;fk*d?}}7D3Q($T-*3v4x39C9aT1QY_RCiSs9ivcRoV-C0FQ^SZRm z_qU?wH4`5b#Hpf+C+z4x`K{?1RXoS+Z&#dr-RQr#A&@TvB2hiy01^rkym&5 z)zSnyVDoa>9^y-NIctsLUJ~E1%XhDz&w$6ZM2<&$81VKUr|9cW6Z-za&U$kt1IIn4 zx7;QKq2ZFvvP+swtnoK{`s*wci?uql8Sk0!Fuo~!O^t=^Q&(gT7PCefU z*G5bNIyRVn?(Yu6n}?;|9AXiWQeEljK`b!0YQgYx;sYzh zsD-`F(Q(jU?RZW1WFmHbpXyHLOhfh6UA@Byd^xGRtB^r>8l6vqU1peJQCC5M2ED~9p`ppi5KUM14D1o z5n96U`sf`UOB>%0+pHlRkviEE`kD|08%yuc+Y?B_xct_1Njn2_$Jcnb5Q_Aie)*Vo zAQPt|Cbb!lnRuC~CrI1O0^fnGGsfX8RTquOG(W8p0s(%HyjN>2Zd)f7&+L9*Gw=D}*P_V?f=F%v*arJr0j8XWzfWO2qFI zyv5h#(=f*ILy>D69ev`9+?ULRz`}-7QXL3EV`#R3(#!}&mpL( zUNZY37x580$3N9;==d`~zwI5dg#NTu^8;r(?YXpV_-ybWh2oU8$Sxr$bp57AQAl~oh+zu%AdJpL3F{hSsDD}gdeQ9YN1s?^ug&ZGGDU7uy51-DbtVP z2v&J=V`X(DoD;oPXd6;7c=6=Tgj#AGY|gfwS(=)NJ;%qEzde$M>)r;}KMK;}|Gsjc zWM2r9f^JKNRfpj4uDqnAYaw{H_URJ&TOrsfYqIU^y%4ZIsZE%Y<8-d(J`b4=fuy0K zh#?;xL9xS;2Q}%4%~q0K?@GreU7r;P3AP;F>z`9dwbD@%!EpxMM3bt=73FC$ATi&E zy&#T!4j0pRCu)1K>zv;YH!`7i<@daXAc7GQ%<&zh(o%KFz)X;!#eG4Ua| z5#*L;bs+>dCo6gu0(b?)R^7M?|RZ@V1Bg2L9aQY}6*O!4MOoJKYq!A9qs?pu*4 z(DCYUO}7^)U#S*j;`lDGo&`o4#k4B_gMJl{>RG z4WAq=#5u=95WHRUz+H0BIhHNqlujl)OL@QED4ba2Y((Cv=ny>bW#^ta8-jGhhRocu z5M-}k%@OiA1YIvbQC1{6sG2*kE(p`%m8wm@yN8ajnlkNK1X~_aQVmWK`Gjm%r3McZ z5_w8j+O2*S13T@HCN4hAfPIUXh4Xbn9veFKW4|(R>+7dOdb$J)JWD+Lh+c5f=2~@c zF42gRa(Y1lEJ(FKj+z-|!E2+l=MEMd8oO<#j}uHtxs6a^?kvHo+ab63}cx3Uo zK390gz+{$!bJSWU?j{{R9p%NudwGuKiyo2Bxw@{-BqLhbSft#&z=FB0$Ps0JHqKh{ zRSD;_QEslLtwVg^P15GQ&IiM=b1K|^R!TUI9$EUv<2V(G_w~-ZjaI~9<4!9vU4jMg zx~14}G7|Cd^@79qE~eo<_49&S4&nPoV-ITW2^-GcdHIzQ9alQ}swMW(;XP=+A(CXe zU7`c=Ic5Ya#4oFDbt8FWvE{mpgf&xQm$bF65dOd;=6jZe`x%)7%SDLRwAJ|b;|C={ z;$6PuNf43CH)8Jm%uiw<-!#bO_d^DZdqxc%`N_Thmik@HmWfqwh8rX0C1NUGpbB+8lT%U2O`*mL^(QNO@A)c5ABK4X}O&>`gs;lWhAo$9Tc zOVEnt!DACnG~$rYyfY1CCl;1PX~KjpFJHKIxmz0@Rk;b@{-cCi;!Lk!{6fe5(vQQs z%NcOtk@pFbC5mWLLR^D@o#dXHLt!iienxJi*ynQ@C_DXj%ky3aLe(9sjL44F*o(Ub zwVCKi=n9FCVq)gXYWI_5{^YluU7gly7UatBnpnEA;F2VDulOzt{`>w@USgBM7+K0B zferUrA8)_r4n^We&t*qaL&1G^(8NG940|nmpH#_&!`^a#W%jWMoYJQvFXnMYVfCge zg+E7QprqmACE^l?rYY6=x(gEF@r(9c7OA*16kq(AM)du?`@M_x7-+GWK8EcKtU9Ek zxK5FQ+l8t!8AR!P+Y;dVN`=&T!s@-0$Su7q+3bIfB(jK$95s(gNxv!pf@^LXW=58Z4ib>>*>5Iqnq72c=yHk63f zlLF@9VX#>GWkI-GI3(iK-u1>4R=iqj!_ytBqi}Z(&x9-?1YKO&zE=$5pg0w_Qn@t& zt)9`xPu@+z(3w7~tTIAU=cLV*iD96Zt~aSk3aQ>le;&Q*%>e(|R=wk-((!d`>r`_z z1M!z(&3%c1je96o0Z}@v)YiAm*QCm(obae}k^w(g38k40ME}>io2?TwCMwwXfzdz! z=^uO*Uz2fz3A2|sm5j!i_%yTgeV+^q2QxixvRzncoHqZl;2H~|Ekk8#v)PE%iEf!^ z!p56Bv$~Q?NtMjr)%uiZC`3YKTGL2%?CPKZ%YZ<9*6D&4}1hKBtYvay*SL9%o^&P%J&%|RW5zj z9R;$ZVZ`CUT;_GIT-Md7=%uQ1V<_T>4{OC~liOpU5u#==5@ z-=oV7STIUfJ$EFLdd4Q^mPH4$5fiEpS5P;L zyqUN?UD?x?#>A1TTSteRnYbg;arOr%3rD_8w3KWo9UPA64XIwF2DG)hy68F!LYJe{ zoxZV<^&)utCZYl9y_(iyQDo<)WfRk{*%;eoU`yK_iaqWR`xUN-LgEokSZq@mo(GSb z9IXz6%?96HlL_I-Wl_IPs?#H|q|QhrXzR3(gH=9V6XW$FZL&?WPCVuu<8Q?87Xs&3%dwRcYi2&Fu*{of>c@`5i+qR z(WB#}z+oD{v-2^z=P~#87+dL)j*jOuo&r+%WKnfhwPkGLHibp!uR>zPHU1n#J^?5dy z@44-FfJG)r6vPUe1YPg)pew1_>uT3PZS-@u`5Ya8Q@>HG5Ad zM1WtzUYz$^B+S1o*NyxYjbY|ff7Ktc@bjE^vQ9q%8!WEn9{imQ3BL{bn-!R7;jo+F zBi{T%V11y&1j+61);VQ=V&FsNx&2i{&buFa;FC9-iORAB(YvcjAtO6bH=iW9pxs+( z=ZFQCfAHA4C5Xg7$3+K^7x7GN$*oX-dXEYGbWU7M;+_#;l`<~M!h#Mu%myW|2IFB>BTcC*}V*$|s8dD?~G{oGYFzb9YV5ET!TI%gP)QrT6> zMUA1D6v>acPv%aWB|9zcn!}(O9M@w&r@}Gs;=7Oy><9!2x}EC$5eaMKB@I>+(bz{{ zOn)>Pi<2vIcnVb#VEN^mv+7_nZe5xj6xc;z`JvxA+2u@>&C`j^Bwp_Q+w6edHzMb| zVrJXVXCk9;G_N>pX#Lg#e8=|p)%HQzGxfq{{G-4j>HG% zDt;mH7a0yNhJs>RSOjQNevZa(BQf+YIWPQmG|arFXkW);QTa!ae>oWuT&9yRl>Ryy zzDvYc7O66EutbBeVI}G1$Zn{VCGmaIGeh0{4+8HD?_xsE+PtZOhlSU|PJo%s5T zjld}ro`b{!!H4;j&)yEjl9y|lmx%>lxY}+PYYBrJgF11yIW!zh{dMO!k*ct}F4zmaZDEF`!7)He?~CQ9!;h(Aew*OFrYIpzct4%A3| z>+e`5-b(X7zFSG~|K^T*Bf@lS`vffAi3MJiy9oEnv2ao+d`T#=KwJCy)-KW$+M=s; zV)+OQ`zL!-S8e%^w|A7ic4kAc>z=@kn`~?dC|F(bhmBF=M-I96p&0C)pZu{Z6gQu3 z)=yI;D473q^D+_z)ZfkTa2(@ps1y!}z?$}p{tmB+Fj&7?&%QqzC2obQACZxsjqTc* ztJfu9zr?v7v!}@zbl}F-TNk$yyb4*+zOu~4kFpY=YbIq;mw}|sGvB`f% zd7V5VuMg*|H0>k>jT_%WMRb@jx=Al-^(OJZIykjVJ%$M)#h{C1Jlq)iY~F*=Qf@J0{}J#%?up z@A`5!c!v+a&s;+K0&L5QEbCAV9C=#!j#$88zY2$fN*JELX;r*>mkNW^6Zbx5R5*4@ z%jJbcMqokF?(Ave1D2X%VwtVc*twanGlbk%Hy-O*U(J zNv2!H?Y@RsU|*sH_A8ToAX*>3Y(FVrlwiwpQzjO!ynzcS>BBd^^E1sxZlaY_d3P~rVH2qheQXr}SWoVdq-e8fTne42ZK^AC=(bGc2 z0{gX!``s-G{`05Jn_ERjMaE3#>Jc4~o@p3WWJGj;{l4aK;sXP|7ku`rlAiG(rFJ5s zJq$ACTWt(t!;vDQ$v++yfursPtDciGS#p)!hQQ`%+&-;u*?)_2G--mig+%u!2@-xMmaGQVU>pW84e;TA3 z#zQP{yrO*V*W=_frT=omfcSvWl{f8KSDEnbU;bgdl!-$x`~EzwcZ9%`_NLN}pN<8^$%!NL7^tXe z$vR8WPkX^cduBTm$4rcEeVR#_+JspqkS3L6tLE7FlQ8W0DEUyqC<3fmvDGKsqcA3z zP|98(3t`W1U)COuhfD19eD4<0m}IvbO)bv}#;30r#s#8+;GN|=RMtzObGGy7^~-_y z!o93M=}G|h$;NDO8l&OTrJ06jRy3&HxMe%6Peb=li+Qv5(NG*xl=Rh&2A@MS9pR}o zcxNmS+5VgcyI0({)rJA2Q0bFa$PNKAX#?K)`8I?mJa51c%8~7&#Iqx>UDV`#o(3PJ>$B3L?Hu*vSVG|Qt84pYQ z2u$y-h^l`^oRE?I=`K+3&fG=yC=hl4~Q$z_#Islfc(TT zX{Bp441W`Ss;^6f=?O-$-ZmOIp6YW*+0bylk*jJ+5V6qa+$i~*Gzgte(s4E*zdOHX zg&ld;>4d4o*AtHdu~5#RDqo#PLBr0oe_TBXWoPeYDozAJnZdIKwii zq&NsyzQ61?K1)IG^XN^TOMzr|*@wG|cyA+5hl%!g8uGW;@NFPFTlHho%zYgVDs}QX zfl|cVMdrFJvY=tblt-gGiH5wum_<*2(xAV=^Wi+P0H}LN?iG9;fE6RxM1PM3!iN&l zJ1~8bgxkZL z@r5~+4>+^SXh_~gW-&DaAaEzYL7+bX+`n5(Tz#%x4$`6Ep%tBN%L#+z%iBQ}9>fB!tSg2WqA+LH;!L_;ET-QMd~i{v;*o0? zxm@BEnN$i~;!#M#PSAkb?HC_~ybCfMCDjzB3a*spdj;aP*0{!1pd4W)0ba>IiAPODM86&*LK^RS#BlG%Y5Wbi?b-X1HvI+T{3tvzU z!C9R`H`)Ty{c3tzEZ9rxfqOhhg}NCy-^}|Xww8&{jp>rfEiB~CU-y!SFBCFvr3G1q zM1qaiK1m_Zx$$W@^`>8nf}3LB(Rzbebf@AAHM2V&XJ0Dn%MK)h|I__a_t;=aR;&7^ zM+9Ny!(5?g!X1s*@p~FO1meaz#$=dZ074F_*pBy-xMzGjUQaS%tca;i`dS)B%{KWu zaM3WH`GX^R9t~no<~`YQkOnV7*2UN;8kUrA_*k9fcJ_c^+75$5Z0TX zYp(XDU?86Npg=ANsn-sV-suQ}w4$O?3p*IiJiG}!2*FJ8kdiP59S_EyD1CWAC%j(y z+SA9R`lZJhRUxAGDR+&xI4M--vfoYIBbjjck+6h$Vi-gsSN(it8iB%ZPnUMpkP6Ir zb@X!6Sp3*cWgIWojmHZ;+3U;xB;qv1wtvA22G_leDs3tV?HwybexIR`D){Jw=)OQ~ zp&lOUvJOD_i{oi-c{Gwro4%HUhP64gKbMx%U@`2gD)Yu4>&lg$p7`jGJ*wzDOenn6_4K#gr9PJzN-fa z8lIZ(dptQ9fy*qo9w>&Ovu&f};MWkG;hC`feV>j){?+9j*BEfvSS}t|$HbY1Divl= zS$M*h$rY9)M8v8~KK2}GOwKfoo;(-yHKrH&zwN6PsTv9qa6%;Z@@e z-%|wv6iT?CHCX8c;^3bzqhcl$tT{hE+OjzavmcmN?7A0(HG^eRE1iO2-C!Czn_$7J z#(kd~$3hS>EcopO>2Ojvq^j7YVpICdxSitVU@42tlK;u#X^@&$LA+u=$uv7URyHq{pQY= zd$zylf0~>y8HF)rP4dHSrJ}_q#O`)fs}?O9lbum1G_$ zigTnTjWoAwYHx<6Fri=bV9vICER=CLO=SLNqmipjF)JkuXSNvLcDIbc^!>G_vu{UX zyWG@A>Zf@u<8p-BN9Et)95f%EbQg1nS1RyrRb9nDO;sbMT*=oNJ1ox3o0^%bSln2~y zaS<@Of8b_(xm7TZy|gdb%oPIB1ijB!q66^^!nk18p%sj$y%9B6c)hYt!4|{lyr$mAIhgz`4-Y^!ngI5n^*uH9H5I2BYk&BL*LPy2KWG`hC;GJg@s-I@9zgTQt~*k{9z69&Wb0+|0KyN{ zDZb|%VuT>fwO070&>H~u;~THd?*-!BzBxq?UJzf{J3N~fN*K|Xy9uU}#0Sjo&)W4q z7&1n*HDA+0pwVL-*hwZI0`FTE2a>k_QHN>D!-0vVLhPMqC>AO`#h2}S%0}(sYL!MU zGPwBa$|o8b)3IA?dV7W?a8UoksMe85p{O}X{!s9V z2w48X54(gtdRMLU$CgbhiAnp(ae?pq{lbWa4lLKCttS5(;LY-<@4u6T@YrVJ^`7(q zBs{Nb)QJm3YURvts+7WUy~$`J?;v=1X2%!^2BU4Xpv1K*7zfWJo9;{sLFJ}JdrzFC z!%E|v$e;-Wj|Pt)c~9zwKV4Xh11wo!oczh%SHQ;U%DOahQl97ARi-ojI~<3TJWoGR zr=n07w4m~xd@L@Ne6YHt9S?=U7$K>ZNl3~L?B|&m4865-Lp(DS!X|w4S(g_tIb>vZ-PbiTl#~Uv`J@CYdgFWBB1ueu(DzN?-ZP4=MR^j&6_q@R>8V zU3P&#mdZcPd*w@fp+i5hjhgnygJW7jHdkrT+H9;*;uZjJ&fOsiR)P3XCgbqJokH>W zFXbS!Ah@Ob&Uk$Z!t0gm*&0N!a5M#-Uu7MF^N;*uWp>i>RY>uqA(?y{<@$Kagj7tA z{|pZvmL|GD>_Yn#8RLuMD-X--55>W((mzWo!{Hu~^o$xMC79HrZyIh(N%85PUC`K) zc<5W0gv|Y&2wsi(U8VDbQE%h0eN!6+(Y1RoM(heinQNuOXMXZu7djpk3CPnB`L0dPA8O8K{<Jxw3=wgckjblxra)91+w`jhR(! zd|+Ih* zm4Ucm{I)dfaUfjfCLVtvVsz)F>{)wG6Me8U|3nIRF!{$AOFyM%2ICg@*YNLqLvYD# z^>1Y|A(f`MoZpU2%?A$gNL{EP15UGwjo*WRJC>*s;A=_-8pO zOiJ5CT9-VDK%nPCGj%E&*~2jd0RnN@`~Ow--Qiq^-}@n}k`$4d86qSzItfWuA&HEn zjEqvssNTaKZ+mCH?Y*f`G9ragQi-x>g|vj<`TV}$?{ECob=6f@&U2pUoO7T1zF(`B z71klKpiv#>V!aI?ntLoGR6`P++47ca632AGKLWGU=ZTQPXvfjAN&uzzJ8eR0aL+*d z;n=b~0UX1noBOvDpm3h{$J!C$_t-l+U#koM{GVh}wen|0(Dg4}m7*OuCTfx&@%nw-KC&8|(6SSxHkicv9xY{B%s}!5NkF4T|khr{nvh9BxE`@2vSX-ByHR&g;OT!(=E))V#jZL;|}Voyy`^mbDJ+ zC3dlrKu15PMSGM8m22hSQd)@6%U$$pXBrXM*yNNvbMV?){OxcLBEm{rckE(05u#Ss z2(L$;5}~2=imA~jB4~Ii9R0&W0zNbGrDsP;aP@V;ofQHJex3O#!Z%2QBaiOg`7VbM zDB+L%41{Jj-ca_cw3 zelH(Pw6-G6_x|38(#1jWN{nznPO=6W4Cg0oX;^VvU3=;ERCE}ewe~zTNTR@L&pgj& z?kFJnIq~+_ks;M;aFa)x48E`F+P`+-(U9d@>993Bz)b#Iz)ON2b1A8F_(Uh4sT~%7 zPXzsJ*4u<9M39xZJww2sIN9eIT^8aCZ6@wZ z10xVnzf{M!Np%4X-w})NWpkjv7trA|CnT%eI6N>7Z20f;Y1WI6cDI) z%MV1C5I~5@i@Ymz!q*fTL-{TI5Hll!&!XMXjTcRL7ec6K@X?gC7pPFNY$-p8Q zC(Kz#0>`qDt!JzetP&S|kRXOVV`~_7Vv-1#W^Qn>_Yq<8m0i~PS|Zp{@+S@!5TW+p z_lO$IiJH`aGQJv|dJkr3?MlQPAe8dTHsi#z*&Z30fypFSInAGZ%8A=KT4{yO}^1b0eXJpG(FB=|Q@B{JPJ|cw6{=hL* zFDTCx0B=)xcHJpM^qli^YO_@!C~%zEnk!ETf(YAJ*0gBdQ}gh1Lmj>cb9$1+-J)SY zo(|YPB13_cHIwJbOi^Gsc|CMGl?*OJhVSn3k^xkjUow}F;5|d8Ba0qB$!lxl-djnK z8gS=J@-TMIr%MwHn~88)W2)3W7m?Muz<=2hMBv%J@7H~d09PXWm_H$r2FoYvYrbwiO#dkZ2^5AZU-f;$n>vMW}r{~6Z|hQ5^M~E!-fhZ z7|re~{eU>Yv0D?~I~(u`UU>dkjpjw!Gt4E&KRlR-{^gum~j>SSU@GQ9?34N>;$KK%YU#*l=ZZkX2!DE);L$7 ziredW=Ixg`!VtM^e%Y=~fe2mJj~)C`pv(Dn+9a9`h0)H#s+%N`&QE@96O6^FwfRk; zJP8i@#XmmtjR;I{>D>2JB7#CIBt98Sgf#p6G=6t+oNxOP(_~KsZXHpFY7fj2Lgn5a z85oL=Lk1FAkwi$GS$<-JNs~_&ypZ>Y2vfUs_wgUVaa=d@=nYpA2-c+UQ!gYzBXi4o z1Pd9)f74d~!3dafur2=@Aj99d#7;7@<~%ivo7W%v!9lCm7kaW70X5SbGrjm87~R)+ z=8KzA3HfWM4+R3jKS}9%?{D1yZLxjw7>mLwx6gc=X2@ch^Z)iQ5SS6ux&r# zvyDa+u!Xfx^kCAZ^@v^Op&>&9ox@?Pdn9;v`B@7;HwpaCc^XQM;l$+9vUeVnTEF9n z{~aG9L~hHAKaW3g)61@?zRN_oqO_NI&kgTC$0>us&g(>&OEom+P9Xv(L6Yq~UY8ot zspZg*MA+R@T&vGX0>jZt_qUe#5(?HS2j*jK_{`_B@{0t^ei=n?uaZ$ylJPjcjSRZS zqZ6iN(ea1LVlBN9bK$L*z%el-JYKOMr9m#(hwaiw-XbUDl2Baf#6BF6`W!{5@mqsH zzU8x8*Y6-mQ+exl*9D!km?q@UF^0h#cvqBqhXOi$i+n8BQ4oBBS1%nS5cl`Z^raCJ zoG#mkFp~7MQWbID75I9-&Vf#F1 z7(6!HrOp&U0sR|Xw{0AwU__7d=CTtRR>z11o1aK<$NQIcqXoirzvTYZVRPy$6{A{) zJ)%kPlH&OoBK+_$)fT=&ggsnDV%$X{gz5fJ`-cO~W&J&beO)?4$RghN(Yr+i2HqRC zE_hAWA3asP{eTFzdUYQ!4HMx+1}o zlTGm!jJ{|cK-R3RRG*~rem{7}qxvo#^#Db$Tew$|H|YKOfrZ8kf6)GQB|#i{0b3FX z!T+epY)(+${A2Mw5J+h{O6PEsIqsVK?&{?bcxvj_y;m~~E}% zxZ_;3aTAHkgPfX|#z^2A)A;;4Ue60l>WuW;uvl#^UXZ~K=-U@<*@+O0K>z$6OFa9L zW$mU&L{y9}$$IX&K!i-ffPhuEDiJQ&){kdmNIGPD-(1H?JP-pZ6P){fycaFDVGf*^ zx|P&ULju+JG9Tp+k`T9(YVoGx!xP74>AOGzZW&9$OG`5BTq^M%$s)u2$(-alNz{Z4 z7u^4a#OKGum%3++{h>w5r*juFsG7e#TPb!zA{1nBe(*x(!@$99w(g8Ua4&zb?h!{Y z=v^QYc(E32(ox5CaD|e(LLIAcsZ9UREucE)X{wQ6?(E^o+FTO+ z@tl|r{6+#}b>$fh5>Ss3$xl>(BKRCnM!ovQ%WpmQ>8=Ct?na zyBfVK^&uc}NI>|7hGrnFU+Lp}$`J(nT`M{E2n2)f>!I4+{zYQE;`){F{6vCST*>hLR8X^4X}G=$PQbLXknse3=MdvZ<#-9}?k6oy=aE zYuM)7d})4ejoB~wUAFZ&=7xEutpY)d2=eus&-*YbHu6Q!YMmy6xM6C`1pb8-?Wd(P z;Y6rl?){{X*XX>|`yDTFGm^k);BBlzLdyu5ug~v>W034Xk8U}j%r(4`FaPehF4E14#Z(C&|mR!Cs0TM@bTO(qj_Y%?KrqZ z8AfHpzLP7q!3Z8-Hoa`}`(6nAJ@|`l#61kjEA)f&Efn}{|6M7c7zLi3?AkA^$gr~a z*X<{mgj{6u#8E`e+zD$pN@j@AJvdr;XAp7}?Oh){p4QR0>wCOP9x z!j;4m_#3rqoxQ^NK+x$1e3B$W%d^yiCuT&jP^`b=kVS+Dr8FZd_K4!&jV{}55aIok zjQ2{iBpBH#&-^x=1ewC+1M+`xKG>B!UW&Ki#N+Q$Juk5*H2=7b4{?Dqp7Ro8ul<0j zx#+kdyFXOq$rTK?`@?Y(Vd){a3-W?_m6f(5`)#UHg2oHkF85snr`BM&c?#v|1oQmk5qYG|-Ftzu73Nw4@#p ztzsNPt?|LQ!s;}pf!F4|o!g%O3=n=QKU-CKNU+j!KPnr0M2%e$TX}F#*ziT|#&Iq( z?5jU!x`@@VPWf2r?G!Q`Sduvzd;#s?I%vE*a6&q^G1aSe0(ZxLlOH}0qndtA{JWYZ z=75{C&*8twd`?TPh3@})4iU8f#YLcw(c$ z__m?Oe19A~df}-tU7iGVMdZ%&kP1?a(OTo|nb6ccs-eqB1?O*9ltq|xVCb%KVcm~h zIINWW$^KvgNG8g%U*s=>r0}%ft<@#)MX6UvG^h-I%sOPwT(5xS!Vy!yBUSLn@W7Fr zD}*Xwc+=!h^9)Vdj?F&4CWcLLmhQ1vwkVhqw{$p!w~+q2{^Lv7D4B2d7##G*syuIV zYs{AnGn+gnlkQ{?3QTjZ!4k315_)|ETSYg=Co!axcq!x)RrkpUK;NMhu`_c>Gdgfp zuk{Od2Xd)Pebche;Efw7q0joL5*wH zlzFO(dMbR(zF#@On+f89TJLtUQGvyMS)r6Q2aIbz?9Tm{3-6?qc&JbSOFt!VpXV!r zp4C$)y;@4(N-*7gd3YK4u5s8#-l%}>XY%&YC{#gF^Meh7zkL-5*UL2-KD-5=>^FKB z`N`mQ{XyzfIMM~aym`lZf&|5#pUu~bNT4#}z#eoTBQW5Zt%!0W?y;UNM-Vy|`R1}9 zY2XKb`%eTtdglk(OFzFV+2caBA@Rc?(uj%|7%SC(A^mV}TUjRhB5ZOCZFLSnCFnE| zn78MKz{}dkEsn@%v=r>*IS~~N!RKrB=HJA@DSN31%L>#v$KBf7V4Mn8e?^T>3uQty zi}^YuI~BACC`TW#<-nG;>alj_Jka$NT`f{CfaeU;wo6h)NRr|D8DCcdj!gpoZpmek zYyUpM%d-OZvheDBQL2I_148K`R>vyP*J=6X(uvN0M(yM_T#l7AD{9!{PsX7dqx9=6 z3El<-b&j`@z|4l>`-?adDAzcQx}@RAs4j2RpNE1gPisptTeO%svRjm92_+?w=lkSQ zZlDm`TC0Q9(SN+BOC?#5R^ZUe6)S;fzw_7bVPyY`5qy+*x}S!?`uT=-pWHAwqZSip zpA`-C&XcpoqZol#taQ>XXmk5`7xC$pRFJfr(flNy2^rOc)jt2 z^n)c2M0#w*rB4@tR{xtpUq$royAb>L$LkW97xXc5%PRw!dBJBQJ{8cy&1|>pcoh(K zsC26)x>mum<7Qm@@GX%4o0BJuP4KqVKfzA5So|Kn^ZMXK0^z+s`|S`ov7YM4x}Aq5 zBl+Q~X+4VP*mxCOP*7FteDqD+9X~XA6{rk$XIheib0VEb>!R5AS~~W$1L|?JD?PdrZx9{uX$i z(mj3A8>ORLzkh#$qPV>d$3ygyKym$?&}UT~6CBltO>ZH9Qg!Cdh2>Eko*S4Y8c}LC zdwE@4I2FaSeUGQ-kNShv?O*B{qzaBgdgC*1Twg>YrruYbt)XQoj-nDIR{$B_#;!q^Wb{i^%9a(0j!StUY$Bu1ce4W4-c)BfT^Rf z;l-C_pz?7uzlu@;t!sBh2u&BNKxnFEoX)=r=3-;`xORI2xmRLR_W>EY$(kp(ZXj`L zA|>Q_B?2hAjg$#VGDIl*bp)*myP~J0%tPBZ+G5&{WulE-g!~#EHYtb+RJ?IEET>O)Ept7 z$$^$HfzeM+<^hdefv#3y0Wi}r9Xsz)g!02QXCRl^Wl~*3eDb zzB@<)-v<+ubC!VSIxl4Wd{8bpWVfcE!|V^+gj^2D=V5F3QFH#bYyc{_jz)MQQ1VjG zR9yLUAT;*l|n5K1*e-$v#uz1B}{o+$8pDi-?m$9{WkIN zaQA~_B3j8Xcs+<&XEqf?pYew(xo3jTO7q{d&Qy4FY^VK#YYw<~jxhhW%>%b*az^h8 z3Xq$&B)ub|2ujKf@{=S>K}PJQ-vC27N>5z*T&pX9Fe9C2W$jl5yh4!|cji@r>ix6N z?QJ~aq-R8=A03`;hDq=pd!&f4=Dy=Vw61g0|6WxhR=@4OZO*tf`^4Tb{R;2>iOn6s zH%We=B`?QXp^ehB;kh#bD4hB)qhF+&Zg1Ae^9+QsQyw7=*c+SaMrJe{1QTHOS>h#& zL6m@BWDUjblm{!UU7Qgw3ZT=2gZ67(5ios{9!s|@1z{@n zkf%~PsBILy*M32$fal{4za}!OAS~e7W_NQH3|jqEe3Jct1G`D(<6z|{WDhj&D=ze0sV;Fve z0*CdZ-Pb5Fz|5z?HP#;wdyJ&=f?JZo+?!`Z$36}61P9!ct1@AaQxi*86%~Z}c(yq= z>0QT?e1FgRn!O_GdzNDB^;L-YqJk)YAv1$;2;H^PfP zRbr0F*LnL{ml1w&p`-!72BHi*K+gJS{IAJ_~ zv7H6cft-T`#fR!4u;0lw`_+pOaC;aNCm|dT76i#*JDbT&Q*RSJTn+LDFnv7vl{9%=R3%KStHKC>fXXSn%|N+*DEj`67S#Lt-u? zSD-tHwCK+l{sC~-=unA^BC3L>`ywmx?8PrKhlq^_f%08mPJxPGNG71`Z{;|eVaZ<} zN%sncWX7yCGV+)g-qH70wnV_S{Z~FwQO%S5srxW%NCL!|YqqjcQlRw%gSn`BI@D-# zTvC$Ef|$!PN>Amo5vwlE_@R*tMi&JemLMN?@IJStrW8Wp)=!>p5ykMJu9ZyHErXw5 zR6Tn*@&2E-jHARDR6^87Uc!c2HOv*?-Zg1l4Rl^iwGVS|LoMCR;5S@?4K!DHJws_& zn!5(@H=&I9QOSm-DZ+u@y8O8~{K0FH1Z~DhoXTynzH5VI`iS_>%%g#z#aXCy9Vw-Y zo-$|1$*A-wj5}jd8w`9ay(cLY?EmBPMDMaZ4@LL)gz~q@t{Y>yC^>?I(etHLs|#I` zu5! zeJ-e-5R7{GFdrJOm@5iOgT$UY=yI)ofvo2zPO|0+0&S;%OjIk&IF`}0~iuwizsv{3m9GYYOOqCZ_Kzaa2 z6#cbDw2aaZli}1sFRaRb;W+C+*zUAgZE_5CP7gwd&LATEG~}z!kCI?`Jzl+U%ZCtf z7x3g-Ak>9|w*BD^FP3mP|0h>(u{<2UwMe?$G>rt?f5D5E=~3`5dZcqdF4503Eq0r& zC4z%`#N7$WROqN4GpSk6fOj{fLJ5LYI9bGX_sy{!$bKhtUGi!kTy`o*8@z*`GMJlF zVEI-AEF{;Rg1<{3<&jz`%g1t1sd=PFh@Px~owK!NLsC@`?rwMBxOxp_=-Qr&(5QhQ zVs~iI-}eIb5pUkfi9kql)$%hl4}#G&|M{9Rl#*%ZC^DmuL8@!=t782?C=uP&V2xT9 zv+p*#LFjQ)lbLgW3bkx}T0fOUVnV>ckc(1o6ben-9J3ctw(zH~hj4V{ZaBPdJHk-D zLV>z6y3#M{5pa9&nfm_5C@AaKzEE5n4P_6f$CUcw;r8o)si)2+gHTzXOnz}16hs_R zo9fF1I_eu+KIB`IyI1AN#lbSa)QL9q(se$P}doU=8f_z3X{<+2{!sKJz0Bzf1DD);2 zjKa@x#aD-cg_-2>_JDAB5%G6;ZiWJ6g3#@3u6a~$MJ_+L)QUnu^p5ezc; zv-&lM82#ngv5LW*mz=O{xsaF~y3@y&;W&dJRxu1*U0 zu-r4{Rf;6QC$)s8m4i``5$N)oXHIv=gq=^aCb2o|x{=l^mb=XJSa^u>H|TjzEd>MDfF(7!#m z1xg@;Y*f2*wG3`%aO(FYS3t*@N?@}V_W#;9yE?v@SHoGt;n#m&)xag*jm`4o8NZ)VO1#!sb_{z!>w@DU zw==<-?0)M`5)~fM_?Qi21O}hPXxzdGT&114(e|nk8YVj)?&d84>pfc6uPv29#?enE zJc$*c9xCvbps85}9hAcc=_b`E8y=$Mbk@LxhFr}Rm3p{1GyVSS-g*$&EhE0x;sZO? z2Ty;`2mwv{A!|*MP}t0DtrH0gh5*;s40p{#fRkKP(LfUd@ef@u4^uXg@~(cSk-L3%mUl^(+M4Ocn+9hGIBzJgLcnTn5ouVmWs$E8rF{q2^LFZ523A zntfwos|MO99FA+m8qj;f-*8~I4$S=W+xgn-z)72@Z@Z%p@J$P7&!RH}=MZO{O$$oV zZXOMnmJEi2!^_ceKZ3#0BY@sMGZ>s#r)>U->g>klI*?`ECOk>&17hIcZ z9&N}eA4lQDVTx?XUz4>C{<;$# zj1M5*oZ$Z4GXs`VGdxqDWx;&rMSK12Ip9(V8G`zGFv=rk|2L%o)T)iWlwTLYvU^Ic zF1ZvgM(oo2noTH&Mg5QIIZlfqjm zM-N^<@`kHi-F|`zC=XIOw~)aa0t$44X4Z&i)s#h=^=Jgc-7UV{&MQGc%UCZJ7ZL&q zMVVg=asS~BZcp!4g#z)7$FO{47-;ezl58blG8jvYaQZ!`z>MUjgzczZOAnSgAR!Y4 z#(HwBRgqCJplxmMj$4O$vDbO}Tz$Hr3C0)x$k?>lle4Y23Wx<0Wjn^s>*>J6tHrlu? z7g|p+2#GNlfC`gB7LO!;f#kr@f=X8j*d8VPqF((}299?Q2%q1q08zQgRHpSxILU5! z*#>LEB4N)ywX|BG-7;0YMyLf-e*JHB=e)tNBRs&8FBrVGKTzC{jx9Cm1K}rlP|Ln~ z(7dM)XS;#+$v>DACxmJqexwb7rLFA@$M=PR*<+J=wu7Ny=ofFau`LXg2`p>=fgi%a z>^JZJ2{{Vr-Ee4>KNJCW8vjI^%OYVd^K(l*YR#l{%;sw!qtlE1*2|a6V}L94)$y>_ z1o*tm=fR*z3XtA~e%k4g4ieYm#3_fe;90*l?;iVXczJ+D_H1M>Y;bOg=IP4^Ugn)_ zhrbqrYSZdRKXM5W8n?^Mr6yual+#VaJy-$qr;c*}>8%7`rNy{6lGX6moVg;$sTK_W zS)ODusD-qD-uF9oyy45rdbRVGV0fY+RP5{+47EqJ7v1Lq!R$>*!OOfL81XqOWq2tF zVx|5HxV{Sp>hjrJar41of8oyafz1%uQaMqa@CNlt=HZ&1YN=r`u=I2Je&#>M&>!~g!4cMr{o!GKG5v~y;n_zpy@pQP0@r<0s^Lv zx8g0!Ap1Ww<@yScK3nJe5?@4fy0}1Y`f7N`eK~XrYQa$Ew0x*=EnM&XNxCWG4Zb?k ziCaGffr7l}_UP_WEq4FoCIrE^#aOB3vS1KAEAMciD;UV@ z`9u?Z87~bUl(|kQL)1&G>y(mP7?i3QS>AdP4$Yq@I@y~jz+)Rm4p5E+m$efOM(dG~ zJ8mR-Ip*utLzAvQ^xUx052|pxCVB(WR&y|B^Fv=k!x%)u{eAu@$ zMK`t*{QG@eLMEy}m!0eJLH=48d+~4A4w_nUo3Cw*=kSKsg%2~I8M7vE~iQyAD49CjFbxbs`dN zKljcq=a{0a$CHtij_h#w@<;67(QFD(KMP4-MXxJg*B*~W{8q}5t&Ai;+h|}7wJ=9w zDq2Nm(F|TlfNNLxIvpxW2B*j(h3e@vAQ+xh`u-skR++E5_R?j;cA9NKmdXXirlPG> zn|%07^V5xR9dm$6xE92;UJSDhb-Ov}%YgfX^(PJg3MjvmVBUSd5-3WMx+&dN@Q#gP zVcV8k@OaF(#xz+2RI_HT30iL;j@7wbM&~x_o%^Fwd(qqa%uDmbsex#)5Zqm8gYJGD z3_I-TQA}I3ok7d{Kl45}hk8sfwASu+YeG5E7~z#`*CF3fI0!-v^~b_s^j^H~S_lpZ zd!%U8?^0kYb>YC+S_E`IYTxy&J`z}K9c}c?@rxqG45k0nVnDMlv$p6M=71PIb3#lq zoPOEV#ov|&J3VH_GkP=OtfccA_X-tmc3;=FV9SL*&g0#$wex{ipEgy}v=9g`PSbJs zJ{N;j%_;7}$x>jOCD7-3RN#wsU#`Zv5)7KW{KBv==+Aqaes`t@-2Sue@2-J=?@hJF z=DeWYB#ZM_LJ&CZN!0uEF9>$Y7);qDAt}xVC(bl-lr4-r7p zJ@7ysspT{x9$uPACw?fhmorH!22>~JzUN9NfZ)zn%L3nISjb7^-&&Oh%B(7TEEi6$3Bf*m?IWb@(Sk1NYbT7*KNH|C+e)>#Zgso&{tbeH1iPbL_5 z*jGTnm17mY7b`*4#evbQqzb-;iAE^BtAXOhQ6Zj&8nAh@PCoS83uY|?X{BS(*W~Ys zPH&v^w|la;CF4}Ab0~1PtQWPvM6ne14u^bP0xzmeUgq`0K)ps=en3o+0ql z?O8a}=}-{(;CokjYZ%D!OX!`r7!KQ|?B5LNQ(#p1Zn`)+JB-z{j+c9)A+n%&`Ca*F zkoGi_`ip%5>ph+2Bb*7au$FMX`g$@XNgwjO^92$?kPaMYx6a}fO@nVxGJWL~L zZ50l>QuTuM$0@K`Ty%r01E=JD*NhIK5$dJ=qr0x7uUz50p*}xv3~bUry)1_jxV`<< z*Hx=z;H}&t9T|}Z`NEpYrDd7GvMgue@sr{N@)USxq#XaX zFapkIj_L3uMZ(}A&%#?GI3*u^v~vTcCX9DdMl3M`2Om2Z#9v8<-Hbh7U*AiE9{Qx4 zZ!rQ5Ov3?%m;((xD4*rZhvUTYG-kK`h2Y-q@lq!&V9l@{oyavJMUSE-%8i;LP^-I(nr}>{R5IOxX*Z?}5 literal 123864 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�iaN{9 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 Date: Sun, 11 Sep 2016 05:43:45 -0400 Subject: [PATCH 20/82] bug fixes --- src/hdf5_interface.F90 | 13 +++++---- src/input_xml.F90 | 2 +- src/mgxs_header.F90 | 60 ++++++++++++++++++++++-------------------- src/nuclide_header.F90 | 4 +-- src/sab_header.F90 | 4 +-- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 0eafd49b3c..7e4f16f261 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -218,12 +218,11 @@ contains subroutine get_groups(object_id, names) integer(HID_T), intent(in) :: object_id - character(len=255), allocatable, intent(out) :: names(:) + character(len=150), allocatable, intent(out) :: names(:) integer :: n_members, i, group_count, type integer :: hdf5_err - character(len=255) :: name - + character(len=150) :: name ! Get number of members in this location call h5gn_members_f(object_id, './', n_members, hdf5_err) @@ -302,11 +301,11 @@ contains subroutine get_datasets(object_id, names) integer(HID_T), intent(in) :: object_id - character(len=255), allocatable, intent(out) :: names(:) + character(len=150), allocatable, intent(out) :: names(:) integer :: n_members, i, dset_count, type integer :: hdf5_err - character(len=255) :: name + character(len=150) :: name ! Get number of members in this location @@ -342,14 +341,14 @@ contains integer(HID_T), intent(in) :: group_id integer(SIZE_T), optional, intent(in) :: name_len_ - character(len=255) :: name ! name of group + character(len=150) :: name ! name of group integer(SIZE_T) :: name_len, name_file_len integer :: hdf5_err ! HDF5 error code if (present(name_len_)) then name_len = name_len_ else - name_len = 255 + name_len = 150 end if call h5iget_name_f(group_id, name, name_len, name_file_len, hdf5_err) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index d755f21682..1820350aaa 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4640,7 +4640,7 @@ contains logical :: file_exists ! does mgxs.h5 exist? integer(HID_T) :: file_id real(8), allocatable :: rev_energy_bins(:) - character(len=255), allocatable :: names(:) + character(len=MAX_WORD_LEN), allocatable :: names(:) ! Check if mgxs.h5 exists inquire(FILE=path_cross_sections, EXIST=file_exists) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 04fab444a7..46c4bcb503 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -6,7 +6,7 @@ module mgxs_header use hdf5, only: HID_T, HSIZE_T, SIZE_T use algorithm, only: find, sort - use constants, only: MAX_FILE_LEN, ZERO, ONE, TWO, PI + use constants, only: MAX_WORD_LEN, ZERO, ONE, TWO, PI use error, only: fatal_error use hdf5_interface use material_header, only: material @@ -49,9 +49,9 @@ module mgxs_header !=============================================================================== type, abstract :: Mgxs - character(len=104) :: name ! name of dataset, e.g. 92235.03c - real(8) :: awr ! Atomic Weight Ratio - real(8), allocatable :: kTs(:) ! temperature in MeV (k*T) + character(len=MAX_WORD_LEN) :: name ! name of dataset, e.g. UO2 + real(8) :: awr ! Atomic Weight Ratio + real(8), allocatable :: kTs(:) ! temperature in MeV (k*T) ! Fission information logical :: fissionable ! mgxs object is fissionable? @@ -213,7 +213,7 @@ module mgxs_header integer(SIZE_T) :: name_len integer(HID_T) :: kT_group - character(MAX_FILE_LEN), allocatable :: dset_names(:) + character(MAX_WORD_LEN), allocatable :: dset_names(:) real(8), allocatable :: temps_available(:) ! temperatures available real(8) :: temp_desired real(8) :: temp_actual @@ -506,6 +506,13 @@ module mgxs_header call fatal_error("'scatter matrix' must be provided") call read_dataset(temp_arr, scatt_grp, "scatter matrix") + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the supefluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing ! to ScattData allocate(input_scatt(groups)) @@ -522,13 +529,6 @@ module mgxs_header deallocate(temp_arr) ! Finally convert the legendre to tabular if needed - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the supefluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - allocate(scatt_coeffs(groups)) if (this % scatter_type == ANGLE_LEGENDRE .and. & legendre_to_tabular) then @@ -573,7 +573,8 @@ module mgxs_header ! Sticking with current representation do gin = 1, groups allocate(scatt_coeffs(gin) % data(order_dim, gmin(gin):gmax(gin))) - scatt_coeffs(gin) % data(:, :) = input_scatt(gin) % data(:, :) + scatt_coeffs(gin) % data(:, :) = & + input_scatt(gin) % data(1:order_dim, :) end do end if deallocate(input_scatt) @@ -670,6 +671,7 @@ module mgxs_header character(MAX_LINE_LEN) :: temp_str integer(HID_T) :: xsdata_grp, scatt_grp + integer, allocatable :: int_arr(:) real(8), allocatable :: temp_arr(:), temp_4d(:, :, :, :) real(8) :: dmu, mu, norm integer :: order, order_dim, gin, gout, l, imu @@ -821,20 +823,20 @@ module mgxs_header scatt_grp = open_group(xsdata_grp, 'scatter data') ! First get the outgoing group boundary indices if (check_dataset(scatt_grp, "g_min")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call read_dataset(temp_arr, scatt_grp, "g_min") + allocate(int_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(int_arr, scatt_grp, "g_min") allocate(gmin(groups, this % n_azi, this % n_pol)) - gmin = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/)) - deallocate(temp_arr) + gmin = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(int_arr) else call fatal_error("'g_min' for the scatter matrix must be provided") end if if (check_dataset(scatt_grp, "g_max")) then - allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call read_dataset(temp_arr, scatt_grp, "g_max") + allocate(int_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(int_arr, scatt_grp, "g_max") allocate(gmax(groups, this % n_azi, this % n_pol)) - gmax = reshape(temp_arr, (/groups, this % n_azi, this % n_pol/)) - deallocate(temp_arr) + gmax = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) + deallocate(int_arr) else call fatal_error("'g_max' for the scatter matrix must be provided") end if @@ -856,6 +858,13 @@ module mgxs_header call fatal_error("'scatter matrix' must be provided") call read_dataset(temp_arr, scatt_grp, "scatter matrix") + ! Compare the number of orders given with the maximum order of the + ! problem. Strip off the superfluous orders if needed. + if (this % scatter_type == ANGLE_LEGENDRE) then + order = min(order_dim - 1, max_order) + order_dim = order + 1 + end if + ! Convert temp_arr to a jagged array ((gin) % data(l, gout)) for passing ! to ScattData allocate(input_scatt(groups, this % n_azi, this % n_pol)) @@ -878,13 +887,6 @@ module mgxs_header deallocate(temp_arr) ! Finally convert the legendre to tabular if needed - ! Compare the number of orders given with the maximum order of the - ! problem. Strip off the superfluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then - order = min(order_dim - 1, max_order) - order_dim = order + 1 - end if - allocate(scatt_coeffs(groups, this % n_azi, this % n_pol)) if (this % scatter_type == ANGLE_LEGENDRE .and. & legendre_to_tabular) then @@ -941,7 +943,7 @@ module mgxs_header allocate(scatt_coeffs(gin, iazi, ipol) % data(order_dim, & gmin(gin, iazi, ipol):gmax(gin, iazi, ipol))) scatt_coeffs(gin, iazi, ipol) % data(:, :) = & - input_scatt(gin, iazi, ipol) % data(:, :) + input_scatt(gin, iazi, ipol) % data(1:order_dim, :) end do end do end do diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 07b8a99b7b..f5365fc043 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -207,8 +207,8 @@ module nuclide_header integer(HSIZE_T) :: j integer(HSIZE_T) :: dims(1) character(MAX_WORD_LEN) :: temp_str - character(MAX_FILE_LEN), allocatable :: dset_names(:) - character(MAX_FILE_LEN), allocatable :: grp_names(:) + character(MAX_WORD_LEN), allocatable :: dset_names(:) + character(MAX_WORD_LEN), allocatable :: grp_names(:) real(8), allocatable :: temps_available(:) ! temperatures available real(8) :: temp_desired real(8) :: temp_actual diff --git a/src/sab_header.F90 b/src/sab_header.F90 index 5f49fdc42b..8eaff01678 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -66,7 +66,7 @@ module sab_header end type SabData type SAlphaBeta - character(100) :: name ! name of table, e.g. lwtr.10t + character(150) :: name ! name of table, e.g. lwtr.10t real(8) :: awr ! weight of nucleus in neutron masses real(8), allocatable :: kTs(:) ! temperatures in MeV (k*T) character(10), allocatable :: nuclides(:) ! List of valid nuclides @@ -104,7 +104,7 @@ contains type(CorrelatedAngleEnergy) :: correlated_dist character(MAX_WORD_LEN) :: temp_str - character(MAX_FILE_LEN), allocatable :: dset_names(:) + character(MAX_WORD_LEN), allocatable :: dset_names(:) real(8), allocatable :: temps_available(:) ! temperatures available real(8) :: temp_desired real(8) :: temp_actual From 26244eabcf4d164ed209693dc2608d4e863720f6 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 11 Sep 2016 06:22:40 -0400 Subject: [PATCH 21/82] argh. The failing ce_to_mg test was only because of precision of the xs in the xml and h5 datasets... when you convert the xml lib to h5 (per the script), the answer is then passing. groan. --- scripts/openmc-update-mgxs.py | 70 +++++++++---------- .../results_true.dat | 2 +- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py index fc9bad30f8..5aea89883e 100755 --- a/scripts/openmc-update-mgxs.py +++ b/scripts/openmc-update-mgxs.py @@ -60,6 +60,20 @@ def parse_args(): # Parse and return commandline arguments. return args +def get_data(element, entry): + try: + value = element.find(entry).text + except: + if entry in element.attrib: + value = element.attrib[entry] + else: + value = None + + if value is not None: + value = value.strip() + + return value + if __name__ == '__main__': args = parse_args() @@ -68,9 +82,6 @@ if __name__ == '__main__': tree = ET.parse(args['input']) root = tree.getroot() - if root.tag != 'library': - raise ValueError("Invalid XML file type") - # Get old metadata temp = tree.find('group_structure').text.strip() temp = np.array(temp.split()) @@ -89,38 +100,34 @@ if __name__ == '__main__': # Now move on to the cross section data itself for xsdata_elem in root.iter('xsdata'): - name = xsdata_elem.find('name').text.strip() + name = get_data(xsdata_elem, 'name') - temperature = xsdata_elem.find('kT') + temperature = get_data(xsdata_elem, 'kT') if temperature is not None: temperature = \ - float(temperature.text.strip()) / openmc.data.K_BOLTZMANN + float(temperature) / openmc.data.K_BOLTZMANN else: temperature = 294. temperatures = [temperature] - awr = xsdata_elem.find('awr') + awr = get_data(xsdata_elem, 'awr') if awr is not None: - awr = float(awr.text.strip()) + awr = float(awr) - representation = xsdata_elem.find('representation') - if representation is not None: - representation = representation.text.strip() - else: + representation = get_data(xsdata_elem, 'representation') + if representation is None: representation = 'isotropic' if representation == 'angle': - n_azi = int(xsdata_elem.find('num_azimuthal').text.strip()) - n_pol = int(xsdata_elem.find('num_polar').text.strip()) + n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) + n_pol = int(get_data(xsdata_elem, 'num_polar')) - scatter_type = xsdata_elem.find('scatt_type') - if scatter_type is not None: - scatter_type = scatter_type.text.strip() - else: + scatter_type = get_data(xsdata_elem, 'scatt_type') + if scatter_type is None: scatter_type = 'legendre' - order = int(xsdata_elem.find('order').text.strip()) + order = int(get_data(xsdata_elem, 'order')) - tab_leg = xsdata_elem.find('tabular_legendre') + tab_leg = get_data(xsdata_elem, 'tabular_legendre') if tab_leg is not None: warnings.Warning('The tabular_legendre option has moved to the ' 'settings.xml file and must be added manually') @@ -128,7 +135,6 @@ if __name__ == '__main__': # Either add the data to a previously existing xsdata (if it is # for the same 'name' but a different temperature), or create a # new one. - try: # It is in our list, so store that entry i = names.index(name) @@ -155,53 +161,48 @@ if __name__ == '__main__': if i != -1: xsd[i].add_temperature(temperature) - temp = xsdata_elem.find('total') + temp = get_data(xsdata_elem, 'total') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) total = temp.astype(np.float) total = np.reshape(total, xsd[i].vector_shape) xsd[i].set_total(total, temperature) - temp = xsdata_elem.find('absorption').text.strip() + temp = get_data(xsdata_elem, 'absorption') temp = np.array(temp.split()) absorption = temp.astype(np.float) absorption = np.reshape(absorption, xsd[i].vector_shape) xsd[i].set_absorption(absorption, temperature) - temp = xsdata_elem.find('scatter').text.strip() + temp = get_data(xsdata_elem, 'scatter') temp = np.array(temp.split()) temp = temp.astype(np.float) scatter = np.reshape(temp, xsd[i].pn_matrix_shape) xsd[i].set_scatter_matrix(scatter, temperature) - temp = xsdata_elem.find('multiplicity') + temp = get_data(xsdata_elem, 'multiplicity') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) temp = temp.astype(np.float) multiplicity = np.reshape(temp, xsd[i].matrix_shape) xsd[i].set_multiplicity_matrix(multiplicity, temperature) - temp = xsdata_elem.find('fission') + temp = get_data(xsdata_elem, 'fission') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) fission = temp.astype(np.float) fission = np.reshape(fission, xsd[i].vector_shape) xsd[i].set_fission(fission, temperature) - temp = xsdata_elem.find('kappa_fission') + temp = get_data(xsdata_elem, 'kappa_fission') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) kappa_fission = temp.astype(np.float) kappa_fission = np.reshape(kappa_fission, xsd[i].vector_shape) xsd[i].set_kappa_fission(kappa_fission, temperature) - temp = xsdata_elem.find('chi') + temp = get_data(xsdata_elem, 'chi') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) chi = temp.astype(np.float) chi = np.reshape(chi, xsd[i].vector_shape) @@ -209,9 +210,8 @@ if __name__ == '__main__': else: chi = None - temp = xsdata_elem.find('nu_fission') + temp = get_data(xsdata_elem, 'nu_fission') if temp is not None: - temp = temp.text.strip() temp = np.array(temp.split()) temp = temp.astype(np.float) if chi is not None: diff --git a/tests/test_mgxs_library_ce_to_mg/results_true.dat b/tests/test_mgxs_library_ce_to_mg/results_true.dat index 6710c82be1..0b73724c9c 100644 --- a/tests/test_mgxs_library_ce_to_mg/results_true.dat +++ b/tests/test_mgxs_library_ce_to_mg/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.140804E+00 2.937150E-02 +1.140724E+00 2.952379E-02 From f4731567e137ccf5850ac5b5ee77255174e8aea1 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 11 Sep 2016 06:29:45 -0400 Subject: [PATCH 22/82] Updated ipython notebook and some poor indentation --- .../pythonapi/examples/mgxs-part-iv.ipynb | 122 +++++++++--------- src/mgxs_header.F90 | 4 +- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb index f384afb55e..478a35d8b9 100644 --- a/docs/source/pythonapi/examples/mgxs-part-iv.ipynb +++ b/docs/source/pythonapi/examples/mgxs-part-iv.ipynb @@ -8,9 +8,7 @@ "\n", " - Calculation of multi-group cross sections for a fuel assembly\n", " - Automated creation and storage of MGXS with openmc.mgxs.Library\n", - " - Steady-state pin-by-pin fission rates comparison between continuous-energy and multi-group OpenMC.\n", - "\n", - "Note: This Notebook illustrates the use of Pandas DataFrames to containerize multi-group cross section data. We recommend using Pandas >v0.15.0 or later since OpenMC's Python API leverages the multi-indexing feature included in the most recent releases of Pandas.\n" + " - Steady-state pin-by-pin fission rates comparison between continuous-energy and multi-group OpenMC.\n" ] }, { @@ -431,7 +429,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "" ] @@ -734,8 +732,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 61feb8cc6de0bcac0bab46876f2c7fe978d9fe46\n", - " Date/Time | 2016-09-10 09:22:09\n", + " Git SHA1 | e97aed325c45f5c79d64befd32e25cf1cbb0d15a\n", + " Date/Time | 2016-09-11 06:25:46\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -822,20 +820,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 2.9000E-01 seconds\n", - " Reading cross sections = 1.7200E-01 seconds\n", - " Total time in simulation = 1.9592E+01 seconds\n", - " Time in transport only = 1.9464E+01 seconds\n", - " Time in inactive batches = 2.3150E+00 seconds\n", - " Time in active batches = 1.7277E+01 seconds\n", - " Time synchronizing fission bank = 1.0000E-02 seconds\n", - " Sampling source sites = 5.0000E-03 seconds\n", - " SEND/RECV source sites = 5.0000E-03 seconds\n", + " Total time for initialization = 3.1300E-01 seconds\n", + " Reading cross sections = 2.0000E-01 seconds\n", + " Total time in simulation = 1.9923E+01 seconds\n", + " Time in transport only = 1.9810E+01 seconds\n", + " Time in inactive batches = 2.3950E+00 seconds\n", + " Time in active batches = 1.7528E+01 seconds\n", + " Time synchronizing fission bank = 6.0000E-03 seconds\n", + " Sampling source sites = 6.0000E-03 seconds\n", + " SEND/RECV source sites = 0.0000E+00 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 1.9904E+01 seconds\n", - " Calculation Rate (inactive) = 21598.3 neutrons/second\n", - " Calculation Rate (active) = 11576.1 neutrons/second\n", + " Total time elapsed = 2.0258E+01 seconds\n", + " Calculation Rate (inactive) = 20876.8 neutrons/second\n", + " Calculation Rate (active) = 11410.3 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -1108,8 +1106,8 @@ " Copyright | 2011-2016 Massachusetts Institute of Technology\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", " Version | 0.8.0\n", - " Git SHA1 | 61feb8cc6de0bcac0bab46876f2c7fe978d9fe46\n", - " Date/Time | 2016-09-10 09:22:29\n", + " Git SHA1 | e97aed325c45f5c79d64befd32e25cf1cbb0d15a\n", + " Date/Time | 2016-09-11 06:26:07\n", " OpenMP Threads | 4\n", "\n", " ===========================================================================\n", @@ -1163,27 +1161,27 @@ " 27/1 1.02738 1.02723 +/- 0.00369\n", " 28/1 1.04014 1.02795 +/- 0.00355\n", " 29/1 1.02831 1.02797 +/- 0.00336\n", - " 30/1 1.02643 1.02789 +/- 0.00319\n", - " 31/1 1.03939 1.02844 +/- 0.00308\n", - " 32/1 1.03282 1.02864 +/- 0.00294\n", - " 33/1 1.00098 1.02744 +/- 0.00306\n", - " 34/1 1.01763 1.02703 +/- 0.00296\n", - " 35/1 1.01412 1.02651 +/- 0.00288\n", - " 36/1 1.01564 1.02609 +/- 0.00280\n", - " 37/1 1.02255 1.02596 +/- 0.00270\n", - " 38/1 1.04764 1.02674 +/- 0.00271\n", - " 39/1 1.03299 1.02695 +/- 0.00263\n", - " 40/1 1.01040 1.02640 +/- 0.00260\n", - " 41/1 1.03493 1.02667 +/- 0.00253\n", - " 42/1 1.00289 1.02593 +/- 0.00256\n", - " 43/1 1.01429 1.02558 +/- 0.00250\n", - " 44/1 1.04207 1.02606 +/- 0.00248\n", - " 45/1 1.03141 1.02622 +/- 0.00241\n", - " 46/1 1.02055 1.02606 +/- 0.00235\n", - " 47/1 1.03659 1.02634 +/- 0.00230\n", - " 48/1 1.04200 1.02676 +/- 0.00228\n", - " 49/1 1.02003 1.02658 +/- 0.00222\n", - " 50/1 1.04396 1.02702 +/- 0.00221\n", + " 30/1 1.02692 1.02792 +/- 0.00319\n", + " 31/1 1.00070 1.02662 +/- 0.00330\n", + " 32/1 1.02954 1.02675 +/- 0.00315\n", + " 33/1 1.01082 1.02606 +/- 0.00308\n", + " 34/1 1.00925 1.02536 +/- 0.00304\n", + " 35/1 1.03836 1.02588 +/- 0.00296\n", + " 36/1 1.03738 1.02632 +/- 0.00288\n", + " 37/1 1.03579 1.02667 +/- 0.00279\n", + " 38/1 1.01886 1.02639 +/- 0.00270\n", + " 39/1 1.02478 1.02634 +/- 0.00261\n", + " 40/1 0.99992 1.02546 +/- 0.00267\n", + " 41/1 1.02050 1.02530 +/- 0.00259\n", + " 42/1 1.04066 1.02578 +/- 0.00255\n", + " 43/1 1.03999 1.02621 +/- 0.00251\n", + " 44/1 1.04462 1.02675 +/- 0.00249\n", + " 45/1 1.01079 1.02629 +/- 0.00246\n", + " 46/1 1.04428 1.02679 +/- 0.00245\n", + " 47/1 1.04993 1.02742 +/- 0.00246\n", + " 48/1 1.02245 1.02729 +/- 0.00240\n", + " 49/1 1.04914 1.02785 +/- 0.00240\n", + " 50/1 1.01745 1.02759 +/- 0.00236\n", " Creating state point statepoint.50.h5...\n", "\n", " ===========================================================================\n", @@ -1193,27 +1191,27 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 3.1000E-02 seconds\n", - " Reading cross sections = 6.0000E-03 seconds\n", - " Total time in simulation = 1.4773E+01 seconds\n", - " Time in transport only = 1.4743E+01 seconds\n", - " Time in inactive batches = 1.4380E+00 seconds\n", - " Time in active batches = 1.3335E+01 seconds\n", - " Time synchronizing fission bank = 5.0000E-03 seconds\n", - " Sampling source sites = 5.0000E-03 seconds\n", - " SEND/RECV source sites = 0.0000E+00 seconds\n", + " Total time for initialization = 2.4000E-02 seconds\n", + " Reading cross sections = 4.0000E-03 seconds\n", + " Total time in simulation = 1.5027E+01 seconds\n", + " Time in transport only = 1.4990E+01 seconds\n", + " Time in inactive batches = 1.4270E+00 seconds\n", + " Time in active batches = 1.3600E+01 seconds\n", + " Time synchronizing fission bank = 6.0000E-03 seconds\n", + " Sampling source sites = 3.0000E-03 seconds\n", + " SEND/RECV source sites = 3.0000E-03 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 1.4827E+01 seconds\n", - " Calculation Rate (inactive) = 34770.5 neutrons/second\n", - " Calculation Rate (active) = 14998.1 neutrons/second\n", + " Total time elapsed = 1.5074E+01 seconds\n", + " Calculation Rate (inactive) = 35038.5 neutrons/second\n", + " Calculation Rate (active) = 14705.9 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 1.02681 +/- 0.00251\n", - " k-effective (Track-length) = 1.02702 +/- 0.00221\n", - " k-effective (Absorption) = 1.02734 +/- 0.00171\n", - " Combined k-effective = 1.02733 +/- 0.00150\n", + " k-effective (Collision) = 1.02564 +/- 0.00242\n", + " k-effective (Track-length) = 1.02759 +/- 0.00236\n", + " k-effective (Absorption) = 1.02487 +/- 0.00175\n", + " Combined k-effective = 1.02586 +/- 0.00175\n", " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] @@ -1295,8 +1293,8 @@ "output_type": "stream", "text": [ "Continuous-Energy keff = 1.024295\n", - "Multi-Group keff = 1.027328\n", - "bias [pcm]: -303.3\n" + "Multi-Group keff = 1.025860\n", + "bias [pcm]: -156.6\n" ] } ], @@ -1393,7 +1391,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 40, @@ -1402,9 +1400,9 @@ }, { "data": { - "image/png": "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\ngg==\n", + "image/png": "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\nAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 46c4bcb503..62a212f919 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -531,7 +531,7 @@ module mgxs_header ! Finally convert the legendre to tabular if needed allocate(scatt_coeffs(groups)) if (this % scatter_type == ANGLE_LEGENDRE .and. & - legendre_to_tabular) then + legendre_to_tabular) then this % scatter_type = ANGLE_TABULAR order_dim = legendre_to_tabular_points order = order_dim @@ -889,7 +889,7 @@ module mgxs_header ! Finally convert the legendre to tabular if needed allocate(scatt_coeffs(groups, this % n_azi, this % n_pol)) if (this % scatter_type == ANGLE_LEGENDRE .and. & - legendre_to_tabular) then + legendre_to_tabular) then this % scatter_type = ANGLE_TABULAR order_dim = legendre_to_tabular_points order = order_dim From fd69421a5bc2bbd51870f4f5f2ae4bd90f43ae3a Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 12 Sep 2016 19:45:52 -0400 Subject: [PATCH 23/82] Resolved @samuelshaner comments --- .gitignore | 4 ++++ openmc/mgxs/library.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 724e137038..21db60397c 100644 --- a/.gitignore +++ b/.gitignore @@ -91,3 +91,7 @@ docs/source/pythonapi/examples/mgxs docs/source/pythonapi/examples/tracks docs/source/pythonapi/examples/fission-rates docs/source/pythonapi/examples/plots + +# VSCode workspace directory +.vscode +.vscode/* diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index a04ec8c557..f63d773277 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -1006,7 +1006,7 @@ class Library(object): def create_mg_library(self, xs_type='macro', xsdata_names=None): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the Multi-Group mode of OpenMC. Note that this library will not make use - of nested temperature tables. Every dataset in te library will be + of nested temperature tables. Every dataset in the library will be treated as if it was at the same default temperature. Parameters @@ -1105,7 +1105,7 @@ class Library(object): multi-group data. This method only creates a macroscopic MGXS Library even if nuclidic tallies are specified in the Library. Note that this library will not make use of nested temperature tables. - Every dataset in te library will be treated as if it was at the same + Every dataset in the library will be treated as if it was at the same default temperature. Parameters From cbcd3a7f573c1c5ead8a7d1ec5457d34fa034f87 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 24 Feb 2016 11:01:12 -0600 Subject: [PATCH 24/82] Extend openmc.data to be able to import ENDF data and perform resonance reconstruction. --- .gitignore | 5 + docs/source/pythonapi/index.rst | 73 +- openmc/data/__init__.py | 2 + openmc/data/angle_distribution.py | 99 ++- openmc/data/angle_energy.py | 3 +- openmc/data/correlated.py | 53 +- openmc/data/data.py | 60 +- openmc/data/endf.py | 409 +++++++++++ openmc/data/endf_utils.py | 44 -- openmc/data/energy_distribution.py | 189 +++++ openmc/data/fission_energy.py | 68 +- openmc/data/function.py | 78 ++ openmc/data/kalbach_mann.py | 52 ++ openmc/data/laboratory.py | 139 ++++ openmc/data/nbody.py | 23 + openmc/data/neutron.py | 100 ++- openmc/data/product.py | 3 +- openmc/data/reaction.py | 493 ++++++++++++- openmc/data/reconstruct.pyx | 515 ++++++++++++++ openmc/data/resonance.py | 1059 ++++++++++++++++++++++++++++ setup.py | 12 + 21 files changed, 3308 insertions(+), 171 deletions(-) create mode 100644 openmc/data/endf.py delete mode 100644 openmc/data/endf_utils.py create mode 100644 openmc/data/laboratory.py create mode 100644 openmc/data/reconstruct.pyx create mode 100644 openmc/data/resonance.py diff --git a/.gitignore b/.gitignore index 2ca1c7d145..b72a18c84a 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,8 @@ docs/source/pythonapi/examples/mgxs docs/source/pythonapi/examples/tracks docs/source/pythonapi/examples/fission-rates docs/source/pythonapi/examples/plots + +# Cython files +*.c +*.html +*.so diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index d8eb5200a7..93507442e3 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -333,6 +333,7 @@ Functions .. autosummary:: :toctree: generated :nosignatures: + :template: myfunction.rst openmc.model.create_triso_lattice openmc.model.pack_trisos @@ -341,16 +342,6 @@ Functions :mod:`openmc.data` -- Nuclear Data Interface -------------------------------------------- -Physical Data -------------- - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: myfunction.rst - - openmc.data.atomic_mass - Core Classes ------------ @@ -363,9 +354,20 @@ Core Classes openmc.data.Reaction openmc.data.Product openmc.data.Tabulated1D + openmc.data.FissionEnergyRelease openmc.data.ThermalScattering openmc.data.CoherentElastic - openmc.data.FissionEnergyRelease + +Core Functions +-------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.data.atomic_mass + openmc.data.write_compact_458_library Angle-Energy Distributions -------------------------- @@ -380,6 +382,7 @@ Angle-Energy Distributions openmc.data.CorrelatedAngleEnergy openmc.data.UncorrelatedAngleEnergy openmc.data.NBodyPhaseSpace + openmc.data.LaboratoryAngleEnergy openmc.data.AngleDistribution openmc.data.EnergyDistribution openmc.data.ArbitraryTabulated @@ -392,6 +395,24 @@ Angle-Energy Distributions openmc.data.LevelInelastic openmc.data.ContinuousTabular +Resonance Data +-------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass.rst + + openmc.data.Resonances + openmc.data.ResonanceRange + openmc.data.SingleLevelBreitWigner + openmc.data.MultiLevelBreitWigner + openmc.data.ReichMoore + openmc.data.RMatrixLimited + openmc.data.ParticlePair + openmc.data.SpinGroup + openmc.data.Unresolved + ACE Format ---------- @@ -412,9 +433,37 @@ Functions .. autosummary:: :toctree: generated :nosignatures: + :template: myfunction.rst openmc.data.ace.ascii_to_binary - openmc.data.write_compact_458_library + +ENDF Format +----------- + +Classes ++++++++ + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass.rst + + openmc.data.endf.Evaluation + +Functions ++++++++++ + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.data.endf.float_endf + openmc.data.endf.get_cont_record + openmc.data.endf.get_head_record + openmc.data.endf.get_tab1_record + openmc.data.endf.get_tab2_record + openmc.data.endf.get_text_record .. _Jupyter: https://jupyter.org/ .. _NumPy: http://www.numpy.org/ diff --git a/openmc/data/__init__.py b/openmc/data/__init__.py index e60878d601..3f42ef90e1 100644 --- a/openmc/data/__init__.py +++ b/openmc/data/__init__.py @@ -4,6 +4,7 @@ from .reaction import * from .ace import * from .angle_distribution import * from .function import * +from .endf import * from .energy_distribution import * from .product import * from .angle_energy import * @@ -15,3 +16,4 @@ from .thermal import * from .urr import * from .library import * from .fission_energy import * +from .resonance import * diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 80b6cdbdb1..0f0105c2a5 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -1,12 +1,15 @@ from collections import Iterable +from io import StringIO from numbers import Real import numpy as np import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from openmc.stats import Univariate, Tabular, Uniform +from openmc.stats import Univariate, Tabular, Uniform, Legendre from .function import INTERPOLATION_SCHEME +from .endf import get_head_record, get_cont_record, get_tab1_record, \ + get_list_record, get_tab2_record class AngleDistribution(EqualityMixin): @@ -199,3 +202,97 @@ class AngleDistribution(EqualityMixin): mu.append(mu_i) return cls(energy, mu) + + @classmethod + def from_endf(cls, ev, mt): + """Generate an angular distribution from an ENDF evaluation + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + mt : int + The MT value of the reaction to get angular distributions for + + Returns + ------- + openmc.data.AngleDistribution + Angular distribution + + """ + file_obj = StringIO(ev.section[4, mt]) + + # Read HEAD record + items = get_head_record(file_obj) + ltt = items[3] + + # Read CONT record + items = get_cont_record(file_obj) + li = items[2] + center_of_mass = (items[3] == 2) + + if ltt == 0 and li == 1: + # Purely isotropic + energy = np.array([0., ev.info['energy_max']]) + mu = [Uniform(-1., 1.), Uniform(-1., 1.)] + + elif ltt == 1 and li == 0: + # Legendre polynomial coefficients + params, tab2 = get_tab2_record(file_obj) + n_energy = params[5] + + energy = np.zeros(n_energy) + mu = [] + for i in range(n_energy): + items, al = get_list_record(file_obj) + temperature = items[0] + energy[i] = items[1] + coefficients = np.asarray([1.0] + al) + mu.append(Legendre(coefficients)) + + elif ltt == 2 and li == 0: + # Tabulated probability distribution + params, tab2 = get_tab2_record(file_obj) + n_energy = params[5] + + energy = np.zeros(n_energy) + mu = [] + for i in range(n_energy): + params, f = get_tab1_record(file_obj) + temperature = params[0] + energy[i] = params[1] + if f.n_regions > 1: + raise NotImplementedError('Angular distribution with multiple ' + 'interpolation regions not supported.') + mu.append(Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]])) + + elif ltt == 3 and li == 0: + # Legendre for low energies / tabulated for high energies + params, tab2 = get_tab2_record(file_obj) + n_energy_legendre = params[5] + + energy_legendre = np.zeros(n_energy_legendre) + mu = [] + for i in range(n_energy_legendre): + items, al = get_list_record(file_obj) + temperature = items[0] + energy_legendre[i] = items[1] + coefficients = np.asarray([1.0] + al) + mu.append(Legendre(coefficients)) + + params, tab2 = get_tab2_record(file_obj) + n_energy_tabulated = params[5] + + energy_tabulated = np.zeros(n_energy_tabulated) + for i in range(n_energy_tabulated): + params, f = get_tab1_record(file_obj) + temperature = params[0] + energy_tabulated[i] = params[1] + if f.n_regions > 1: + raise NotImplementedError('Angular distribution with multiple ' + 'interpolation regions not supported.') + mu.append(Tabular(f.x, f.y, INTERPOLATION_SCHEME[f.interpolation[0]])) + + energy = np.concatenate((energy_legendre, energy_tabulated)) + + return AngleDistribution(energy, mu) diff --git a/openmc/data/angle_energy.py b/openmc/data/angle_energy.py index 4a5e391e3f..9cee89aa5c 100644 --- a/openmc/data/angle_energy.py +++ b/openmc/data/angle_energy.py @@ -1,4 +1,5 @@ from abc import ABCMeta, abstractmethod +from io import StringIO import openmc.data from openmc.mixin import EqualityMixin @@ -40,7 +41,7 @@ class AngleEnergy(EqualityMixin): @staticmethod def from_ace(ace, location_dist, location_start, rx=None): - """Generate an AngleEnergy object from ACE data + """Generate an angle-energy distribution from ACE data Parameters ---------- diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index d6ce8ab470..dac1968ad4 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -5,9 +5,11 @@ from warnings import warn import numpy as np import openmc.checkvalue as cv -from openmc.stats import Tabular, Univariate, Discrete, Mixture, Uniform +from openmc.stats import Tabular, Univariate, Discrete, Mixture, \ + Uniform, Legendre from .function import INTERPOLATION_SCHEME from .angle_energy import AngleEnergy +from .endf import get_list_record, get_tab2_record class CorrelatedAngleEnergy(AngleEnergy): @@ -405,3 +407,52 @@ class CorrelatedAngleEnergy(AngleEnergy): mu.append(mu_i) return cls(breakpoints, interpolation, energy, energy_out, mu) + + @classmethod + def from_endf(cls, file_obj): + """Generate correlated angle-energy distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for a correlated + angle-energy distribution + + Returns + ------- + openmc.data.CorrelatedAngleEnergy + Correlated angle-energy distribution + + """ + params, tab2 = get_tab2_record(file_obj) + lep = params[3] + ne = params[5] + energy = np.zeros(ne) + n_discrete_energies = np.zeros(ne, dtype=int) + energy_out = [] + mu = [] + for i in range(ne): + items, values = get_list_record(file_obj) + energy[i] = items[1] + n_discrete_energies[i] = items[2] + # TODO: separate out discrete lines + n_angle = items[3] + n_energy_out = items[5] + values = np.asarray(values) + values.shape = (n_energy_out, n_angle + 2) + + # Outgoing energy distribution at the i-th incoming energy + eout_i = values[:,0] + eout_p_i = values[:,1] + energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep], + ignore_negative=True) + energy_out.append(energy_out_i) + + # Legendre coefficients used for angular distributions + mu_i = [] + for j in range(n_energy_out): + mu_i.append(Legendre(values[j,1:])) + mu.append(mu_i) + + return cls(tab2.breakpoints, tab2.interpolation, energy, + energy_out, mu) diff --git a/openmc/data/data.py b/openmc/data/data.py index 574ae541aa..46fcdf36f6 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -104,8 +104,8 @@ NATURAL_ABUNDANCE = { 'U234': 5.4e-05, 'U235': 0.007204, 'U238': 0.992742 } -ATOMIC_SYMBOL = {1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C', 7: 'N', - 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al', +ATOMIC_SYMBOL = {0: 'n', 1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C', + 7: 'N', 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mg', 13: 'Al', 14: 'Si', 15: 'P', 16: 'S', 17: 'Cl', 18: 'Ar', 19: 'K', 20: 'Ca', 21: 'Sc', 22: 'Ti', 23: 'V', 24: 'Cr', 25: 'Mn', 26: 'Fe', 27: 'Co', 28: 'Ni', 29: 'Cu', 30: 'Zn', 31: 'Ga', @@ -129,60 +129,6 @@ ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()} _ATOMIC_MASS = {} -REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)', - 5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', 17: '(n,3n)', - 18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', 21: '(n,2nf)', - 22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', 25: '(n,3na)', - 27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)', - 30: '(n,2n2a)', 32: '(n,nd)', 33: '(n,nt)', 34: '(n,nHe-3)', - 35: '(n,nd2a)', 36: '(n,nt2a)', 37: '(n,4n)', 38: '(n,3nf)', - 41: '(n,2np)', 42: '(n,3np)', 44: '(n,n2p)', 45: '(n,npa)', - 91: '(n,nc)', 101: '(n,disappear)', 102: '(n,gamma)', - 103: '(n,p)', 104: '(n,d)', 105: '(n,t)', 106: '(n,3He)', - 107: '(n,a)', 108: '(n,2a)', 109: '(n,3a)', 111: '(n,2p)', - 112: '(n,pa)', 113: '(n,t2a)', 114: '(n,d2a)', 115: '(n,pd)', - 116: '(n,pt)', 117: '(n,da)', 152: '(n,5n)', 153: '(n,6n)', - 154: '(n,2nt)', 155: '(n,ta)', 156: '(n,4np)', 157: '(n,3nd)', - 158: '(n,nda)', 159: '(n,2npa)', 160: '(n,7n)', 161: '(n,8n)', - 162: '(n,5np)', 163: '(n,6np)', 164: '(n,7np)', 165: '(n,4na)', - 166: '(n,5na)', 167: '(n,6na)', 168: '(n,7na)', 169: '(n,4nd)', - 170: '(n,5nd)', 171: '(n,6nd)', 172: '(n,3nt)', 173: '(n,4nt)', - 174: '(n,5nt)', 175: '(n,6nt)', 176: '(n,2n3He)', - 177: '(n,3n3He)', 178: '(n,4n3He)', 179: '(n,3n2p)', - 180: '(n,3n3a)', 181: '(n,3npa)', 182: '(n,dt)', - 183: '(n,npd)', 184: '(n,npt)', 185: '(n,ndt)', - 186: '(n,np3He)', 187: '(n,nd3He)', 188: '(n,nt3He)', - 189: '(n,nta)', 190: '(n,2n2p)', 191: '(n,p3He)', - 192: '(n,d3He)', 193: '(n,3Hea)', 194: '(n,4n2p)', - 195: '(n,4n2a)', 196: '(n,4npa)', 197: '(n,3p)', - 198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 444: '(n,damage)', - 649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)', - 849: '(n,ac)'} -REACTION_NAME.update({i: '(n,n{})'.format(i-50) for i in range(50, 91)}) -REACTION_NAME.update({i: '(n,p{})'.format(i-600) for i in range(600, 649)}) -REACTION_NAME.update({i: '(n,d{})'.format(i-650) for i in range(650, 699)}) -REACTION_NAME.update({i: '(n,t{})'.format(i-700) for i in range(700, 749)}) -REACTION_NAME.update({i: '(n,3He{})'.format(i-750) for i in range(750, 799)}) -REACTION_NAME.update({i: '(n,a{})'.format(i-800) for i in range(800, 849)}) - -SUM_RULES = {1: [2, 3], - 3: [4, 5, 11, 16, 17, 22, 23, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, - 36, 37, 41, 42, 44, 45, 152, 153, 154, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, - 186, 187, 188, 189, 190, 194, 195, 196, 198, 199, 200], - 4: list(range(50, 92)), - 16: list(range(875, 892)), - 18: [19, 20, 21, 38], - 27: [18, 101], - 101: [102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, - 115, 116, 117, 155, 182, 191, 192, 193, 197], - 103: list(range(600, 650)), - 104: list(range(650, 700)), - 105: list(range(700, 750)), - 106: list(range(750, 800)), - 107: list(range(800, 850))} - def atomic_mass(isotope): """Return atomic mass of isotope in atomic mass units. @@ -207,7 +153,7 @@ def atomic_mass(isotope): mass_file = os.path.join(os.path.dirname(__file__), 'mass.mas12') with open(mass_file, 'r') as ame: # Read lines in file starting at line 40 - for line in itertools.islice(ame, 40, None): + for line in itertools.islice(ame, 39, None): name = '{}{}'.format(line[20:22].strip(), int(line[16:19])) mass = float(line[96:99]) + 1e-6*float( line[100:106] + '.' + line[107:112]) diff --git a/openmc/data/endf.py b/openmc/data/endf.py new file mode 100644 index 0000000000..ba398598d8 --- /dev/null +++ b/openmc/data/endf.py @@ -0,0 +1,409 @@ +"""Module for parsing and manipulating data from ENDF evaluations. + +All the classes and functions in this module are based on document +ENDF-102 titled "Data Formats and Procedures for the Evaluated Nuclear +Data File ENDF-6". The latest version from June 2009 can be found at +http://www-nds.iaea.org/ndspub/documents/endf/endf102/endf102.pdf + +""" +from __future__ import print_function, division, unicode_literals + +import io +import re +import os +from math import pi +from collections import OrderedDict, Iterable + +import numpy as np +from numpy.polynomial.polynomial import Polynomial + +from .function import Tabulated1D, INTERPOLATION_SCHEME +from openmc.stats.univariate import Uniform, Tabular, Legendre + + +LIBRARIES = {0: 'ENDF/B', 1: 'ENDF/A', 2: 'JEFF', 3: 'EFF', + 4: 'ENDF/B High Energy', 5: 'CENDL', 6: 'JENDL', + 31: 'INDL/V', 32: 'INDL/A', 33: 'FENDL', 34: 'IRDF', + 35: 'BROND', 36: 'INGDB-90', 37: 'FENDL/A', 41: 'BROND'} + +SUM_RULES = {1: [2, 3], + 3: [4, 5, 11, 16, 17, 22, 23, 24, 25, 28, 29, 30, 32, 33, 34, 35, + 36, 37, 41, 42, 44, 45, 152, 153, 154, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 183, 184, 185, + 186, 187, 188, 189, 190, 194, 195, 196, 198, 199, 200], + 4: list(range(50, 92)), + 16: list(range(875, 892)), + 18: [19, 20, 21, 38], + 27: [8, 101], + 101: [102, 103, 104, 105, 106, 107, 108, 109, 111, 112, 113, 114, + 115, 116, 117, 155, 182, 191, 192, 193, 197], + 103: list(range(600, 650)), + 104: list(range(650, 700)), + 105: list(range(700, 750)), + 106: list(range(750, 800)), + 107: list(range(800, 850))} + +_ENDF_FLOAT_RE = re.compile(r'([\s\-\+]?\d*\.\d+)([\+\-]\d+)') + + +def radiation_type(value): + p = {0: 'gamma', 1: 'beta-', 2: 'ec/beta+', 3: 'IT', + 4: 'alpha', 5: 'neutron', 6: 'sf', 7: 'proton', + 8: 'e-', 9: 'xray', 10: 'unknown'} + if value % 1.0 == 0: + return p[int(value)] + else: + return (p[int(value)], p[int(10*value % 10)]) + + +def float_endf(s): + """Convert string of floating point number in ENDF to float. + + The ENDF-6 format uses an 'e-less' floating point number format, + e.g. -1.23481+10. Trying to convert using the float built-in won't work + because of the lack of an 'e'. This function allows such strings to be + converted while still allowing numbers that are not in exponential notation + to be converted as well. + + Parameters + ---------- + s : str + Floating-point number from an ENDF file + + Returns + ------- + float + The number + + """ + return float(_ENDF_FLOAT_RE.sub(r'\1e\2', s)) + + +def get_text_record(file_obj): + """Return data from a TEXT record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + str + Text within the TEXT record + + """ + return file_obj.readline()[:66] + + +def get_cont_record(file_obj, skipC=False): + """Return data from a CONT record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the CONT record + + """ + line = file_obj.readline() + if skipC: + C1 = None + C2 = None + else: + C1 = float_endf(line[:11]) + C2 = float_endf(line[11:22]) + L1 = int(line[22:33]) + L2 = int(line[33:44]) + N1 = int(line[44:55]) + N2 = int(line[55:66]) + return [C1, C2, L1, L2, N1, N2] + + +def get_head_record(file_obj): + """Return data from a HEAD record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the HEAD record + + """ + line = file_obj.readline() + ZA = int(float_endf(line[:11])) + AWR = float_endf(line[11:22]) + L1 = int(line[22:33]) + L2 = int(line[33:44]) + N1 = int(line[44:55]) + N2 = int(line[55:66]) + return [ZA, AWR, L1, L2, N1, N2] + + +def get_list_record(file_obj): + """Return data from a LIST record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the header + list + The values within the list + + """ + # determine how many items are in list + items = get_cont_record(file_obj) + NPL = items[4] + + # read items + b = [] + for i in range((NPL - 1)//6 + 1): + line = file_obj.readline() + n = min(6, NPL - 6*i) + for j in range(n): + b.append(float_endf(line[11*j:11*(j + 1)])) + + return (items, b) + + +def get_tab1_record(file_obj): + """Return data from a TAB1 record in an ENDF-6 file. + + Parameters + ---------- + file_obj : file-like object + ENDF-6 file to read from + + Returns + ------- + list + The six items within the header + openmc.data.Tabulated1D + The tabulated function + + """ + # Determine how many interpolation regions and total points there are + line = file_obj.readline() + C1 = float_endf(line[:11]) + C2 = float_endf(line[11:22]) + L1 = int(line[22:33]) + L2 = int(line[33:44]) + n_regions = int(line[44:55]) + n_pairs = int(line[55:66]) + params = [C1, C2, L1, L2] + + # Read the interpolation region data, namely NBT and INT + breakpoints = np.zeros(n_regions, dtype=int) + interpolation = np.zeros(n_regions, dtype=int) + m = 0 + for i in range((n_regions - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_regions - m) + for j in range(to_read): + breakpoints[m] = int(line[0:11]) + interpolation[m] = int(line[11:22]) + line = line[22:] + m += 1 + + # Read tabulated pairs x(n) and y(n) + x = np.zeros(n_pairs) + y = np.zeros(n_pairs) + m = 0 + for i in range((n_pairs - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_pairs - m) + for j in range(to_read): + x[m] = float_endf(line[:11]) + y[m] = float_endf(line[11:22]) + line = line[22:] + m += 1 + + return params, Tabulated1D(x, y, breakpoints, interpolation) + + +def get_tab2_record(file_obj): + # Determine how many interpolation regions and total points there are + params = get_cont_record(file_obj) + n_regions = params[4] + + # Read the interpolation region data, namely NBT and INT + breakpoints = np.zeros(n_regions, dtype=int) + interpolation = np.zeros(n_regions, dtype=int) + m = 0 + for i in range((n_regions - 1)//3 + 1): + line = file_obj.readline() + to_read = min(3, n_regions - m) + for j in range(to_read): + breakpoints[m] = int(line[0:11]) + interpolation[m] = int(line[11:22]) + line = line[22:] + m += 1 + + return params, Tabulated2D(breakpoints, interpolation) + + +class Evaluation(object): + """ENDF material evaluation with multiple files/sections + + Parameters + ---------- + filename : str + Path to ENDF file to read + + Attributes + ---------- + info : dict + Miscallaneous information about the evaluation. + target : dict + Information about the target material, such as its mass, isomeric state, + whether it's stable, and whether it's fissionable. + projectile : dict + Information about the projectile such as its mass. + reaction_list : list of 4-tuples + List of sections in the evaluation. The entries of the tuples are the + file (MF), section (MT), number of records (NC), and modification + indicator (MOD). + + """ + def __init__(self, filename): + fh = open(filename, 'r') + self.section = {} + self.info = {} + self.target = {} + self.projectile = {} + self.reaction_list = [] + + # Determine MAT number for this evaluation + MF = 0 + while MF == 0: + position = fh.tell() + line = fh.readline() + MF = int(line[70:72]) + self.material = int(line[66:70]) + fh.seek(position) + + while True: + # Find next section + while True: + position = fh.tell() + line = fh.readline() + MAT = int(line[66:70]) + MF = int(line[70:72]) + MT = int(line[72:75]) + if MT > 0 or MAT == 0: + fh.seek(position) + break + + # If end of material reached, exit loop + if MAT == 0: + break + + section_data = '' + while True: + line = fh.readline() + if line[72:75] == ' 0': + break + else: + section_data += line + self.section[MF, MT] = section_data + + self._read_header() + + def _read_header(self): + file_obj = io.StringIO(self.section[1, 451]) + + # Information about target/projectile + items = get_head_record(file_obj) + self.target['atomic_number'] = items[0] // 1000 + self.target['mass_number'] = items[0] % 1000 + self.target['mass'] = items[1] + self._LRP = items[2] + self.target['fissionable'] = (items[3] == 1) + try: + global LIBRARIES + library = LIBRARIES[items[4]] + except KeyError: + library = 'Unknown' + self.info['modification'] = items[5] + + # Control record 1 + items = get_cont_record(file_obj) + self.target['excitation_energy'] = items[0] + self.target['stable'] = (int(items[1]) == 0) + self.target['state'] = items[2] + self.target['isomeric_state'] = items[3] + self.info['format'] = items[5] + assert self.info['format'] == 6 + + # Control record 2 + items = get_cont_record(file_obj) + self.projectile['mass'] = items[0] + self.info['energy_max'] = items[1] + library_release = items[2] + self.info['sublibrary'] = items[4] + library_version = items[5] + self.info['library'] = (library, library_version, library_release) + + # Control record 3 + items = get_cont_record(file_obj) + self.target['temperature'] = items[0] + self.info['derived'] = (items[2] > 0) + NWD = items[4] + NXC = items[5] + + # Text records + text = [get_text_record(file_obj) for i in range(NWD)] + if len(text) >= 5: + self.target['zsymam'] = text[0][0:11] + self.info['laboratory'] = text[0][11:22] + self.info['date'] = text[0][22:32] + self.info['author'] = text[0][32:66] + self.info['reference'] = text[1][1:22] + self.info['date_distribution'] = text[1][22:32] + self.info['date_release'] = text[1][33:43] + self.info['date_entry'] = text[1][55:63] + self.info['identifier'] = text[2:5] + self.info['description'] = text[5:] + + # File numbers, reaction designations, and number of records + for i in range(NXC): + items = get_cont_record(file_obj, skipC=True) + MF, MT, NC, MOD = items[2:6] + self.reaction_list.append((MF, MT, NC, MOD)) + + + +class Tabulated2D(object): + """Metadata for a two-dimensional function. + + This is a dummy class that is not really used other than to store the + interpolation information for a two-dimensional function. Once we refactor + to adopt GND-like data containers, this will probably be removed or + extended. + + Parameters + ---------- + breakpoints : Iterable of int + Breakpoints for interpolation regions + interpolation : Iterable of int + Interpolation scheme identification number, e.g., 3 means y is linear in + ln(x). + + """ + def __init__(self, breakpoints, interpolation): + self.breakpoints = breakpoints + self.interpolation = interpolation diff --git a/openmc/data/endf_utils.py b/openmc/data/endf_utils.py deleted file mode 100644 index 1a77c60a5e..0000000000 --- a/openmc/data/endf_utils.py +++ /dev/null @@ -1,44 +0,0 @@ -"""This module contains a few utility functions for reading ENDF_ data. It is by -no means enough to read an entire ENDF file. For a more complete ENDF reader, -see Pyne_. - -.. _ENDF: http://www.nndc.bnl.gov/endf -.. _Pyne: http://www.pyne.io - -""" - -import re - -def read_float(float_string): - """Parse ENDF 6E11.0 formatted string into a float.""" - assert len(float_string) == 11 - pattern = r'([\s\-]\d+\.\d+)([\+\-]\d+)' - return float(re.sub(pattern, r'\1e\2', float_string)) - - -def read_CONT_line(line): - """Parse 80-column line from ENDF CONT record into floats and ints.""" - return (read_float(line[0:11]), read_float(line[11:22]), int(line[22:33]), - int(line[33:44]), int(line[44:55]), int(line[55:66]), - int(line[66:70]), int(line[70:72]), int(line[72:75]), - int(line[75:80])) - - -def identify_nuclide(fname): - """Read the header of an ENDF file and extract identifying information.""" - with open(fname, 'r') as fh: - # Skip the tape id (TPID). - line = fh.readline() - - # Read the first HEAD and CONT info. - line = fh.readline() - ZA, AW, LRP, LFI, NLIB, NMOD, MAT, MF, MT, NS = read_CONT_line(line) - line = fh.readline() - ELIS, STA, LIS, LISO, junk, NFOR, MAT, MF, MT, NS = read_CONT_line(line) - - # Return dictionary of the most important identifying information. - return {'Z': int(ZA) // 1000, - 'A': int(ZA) % 1000, - 'LFI': bool(LFI), - 'LIS': LIS, - 'LISO': LISO} diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index a160906353..b42887b2fd 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -9,6 +9,7 @@ from .function import Tabulated1D, INTERPOLATION_SCHEME from openmc.stats.univariate import Univariate, Tabular, Discrete, Mixture import openmc.checkvalue as cv from openmc.mixin import EqualityMixin +from .endf import get_tab1_record, get_tab2_record class EnergyDistribution(EqualityMixin): @@ -57,6 +58,40 @@ class EnergyDistribution(EqualityMixin): raise ValueError("Unknown energy distribution type: {}" .format(energy_type)) + @staticmethod + def from_endf(file_obj, params): + """Generate energy distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.EnergyDistribution + A sub-class of :class:`openmc.data.EnergyDistribution` + + """ + lf = params[3] + if lf == 1: + return ArbitraryTabulated.from_endf(file_obj, params) + elif lf == 5: + return GeneralEvaporation.from_endf(file_obj, params) + elif lf == 7: + return MaxwellEnergy.from_endf(file_obj, params) + elif lf == 9: + return Evaporation.from_endf(file_obj, params) + elif lf == 11: + return WattEnergy.from_endf(file_obj, params) + elif lf == 12: + return MadlandNix.from_endf(file_obj, params) + class ArbitraryTabulated(EnergyDistribution): r"""Arbitrary tabulated function given in ENDF MF=5, LF=1 represented as @@ -88,6 +123,37 @@ class ArbitraryTabulated(EnergyDistribution): def to_hdf5(self, group): raise NotImplementedError + @classmethod + def from_endf(cls, file_obj, params): + """Generate arbitrary tabulated distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.ArbitraryTabulated + Arbitrary tabulated distribution + + """ + params, tab2 = get_tab2_record(file_obj) + n_energies = params[5] + + energy = np.zeros(n_energies) + pdf = [] + for j in range(n_energies): + params, func = get_tab1_record(file_obj) + energy[j] = params[1] + pdf.append(func) + return cls(energy, pdf) + class GeneralEvaporation(EnergyDistribution): r"""General evaporation spectrum given in ENDF MF=5, LF=5 represented as @@ -130,6 +196,31 @@ class GeneralEvaporation(EnergyDistribution): def from_ace(cls, ace, idx=0): raise NotImplementedError + @classmethod + def from_endf(cls, file_obj, params): + """Generate general evaporation spectrum from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.GeneralEvaporation + General evaporation spectrum + + """ + u = params[0] + params, theta = get_tab1_record(file_obj) + params, g = get_tab1_record(file_obj) + return cls(theta, g, u) + class MaxwellEnergy(EnergyDistribution): r"""Simple Maxwellian fission spectrum represented as @@ -238,6 +329,30 @@ class MaxwellEnergy(EnergyDistribution): return cls(theta, u) + @classmethod + def from_endf(cls, file_obj, params): + """Generate Maxwell distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.MaxwellEnergy + Maxwell distribution + + """ + u = params[0] + params, theta = get_tab1_record(file_obj) + return cls(theta, u) + class Evaporation(EnergyDistribution): r"""Evaporation spectrum represented as @@ -346,6 +461,30 @@ class Evaporation(EnergyDistribution): return cls(theta, u) + @classmethod + def from_endf(cls, file_obj, params): + """Generate evaporation spectrum from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.Evaporation + Evaporation spectrum + + """ + u = params[0] + params, theta = get_tab1_record(file_obj) + return cls(theta, u) + class WattEnergy(EnergyDistribution): r"""Energy-dependent Watt spectrum represented as @@ -480,6 +619,31 @@ class WattEnergy(EnergyDistribution): return cls(a, b, u) + @classmethod + def from_endf(cls, file_obj, params): + """Generate Watt fission spectrum from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.WattEnergy + Watt fission spectrum + + """ + u = params[0] + params, a = get_tab1_record(file_obj) + params, b = get_tab1_record(file_obj) + return cls(a, b, u) + class MadlandNix(EnergyDistribution): r"""Energy-dependent fission neutron spectrum (Madland and Nix) given in @@ -587,6 +751,31 @@ class MadlandNix(EnergyDistribution): tm = Tabulated1D.from_hdf5(group['tm']) return cls(efl, efh, tm) + @classmethod + def from_endf(cls, file_obj, params): + """Generate Madland-Nix fission spectrum from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for an energy + distribution. + params : list + List of parameters at the start of the energy distribution that + includes the LF value indicating what type of energy distribution is + present. + + Returns + ------- + openmc.data.MadlandNix + Madland-Nix fission spectrum + + """ + params, tm = get_tab1_record(file_obj) + efl, efh = params[0:2] + return cls(efl, efh, tm) + + class DiscretePhoton(EnergyDistribution): """Discrete photon energy distribution diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 6352915cc6..c7f71b6573 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -1,12 +1,13 @@ from collections import Callable from copy import deepcopy +from io import StringIO import sys import h5py import numpy as np from .data import ATOMIC_SYMBOL -from .endf_utils import read_float, read_CONT_line, identify_nuclide +from .endf import get_cont_record, get_list_record, Evaluation from .function import Function1D, Tabulated1D, Polynomial, Sum import openmc.checkvalue as cv from openmc.mixin import EqualityMixin @@ -15,13 +16,13 @@ if sys.version_info[0] >= 3: basestring = str -def _extract_458_data(filename): +def _extract_458_data(ev): """Read an ENDF file and extract the MF=1, MT=458 values. Parameters ---------- - filename : str - Path to and ENDF file + ev : openmc.data.Evaluation + ENDF evaluation Returns ------- @@ -37,33 +38,22 @@ def _extract_458_data(filename): caution. """ - ident = identify_nuclide(filename) - - if not ident['LFI']: + if not ev.target['fissionable']: # This nuclide isn't fissionable. return None - # Extract the MF=1, MT=458 section. - lines = [] - with open(filename, 'r') as fh: - line = fh.readline() - while line != '': - if line[70:75] == ' 1458': - lines.append(line) - line = fh.readline() - - if len(lines) == 0: + if (1, 458) not in ev.section: # No 458 data here. return None + file_obj = StringIO(ev.section[1, 458]) + # Read the number of coefficients in this LIST record. - NPL = read_CONT_line(lines[1])[4] + items = get_cont_record(file_obj) + NPL = items[3] # Parse the ENDF LIST into an array. - data = [] - for i in range(NPL): - row, column = divmod(i, 6) - data.append(read_float(lines[2 + row][11*column:11*(column+1)])) + items, data = get_list_record(file_obj) # Declare the coefficient names and the order they are given in. The LIST # contains a value followed immediately by an uncertainty for each of these @@ -161,20 +151,22 @@ def write_compact_458_library(endf_files, output_name='fission_Q_data.h5', for fname in endf_files: if verbose: print(fname) - ident = identify_nuclide(fname) + ev = Evaluation(fname) # Skip non-fissionable nuclides. - if not ident['LFI']: continue + if not ev.target['fissionable']: + continue # Get the important bits. - data = _extract_458_data(fname) + data = _extract_458_data(ev) if data is None: continue value, uncertainty = data # Make a group for this isomer. - name = ATOMIC_SYMBOL[ident['Z']] + str(ident['A']) - if ident['LISO'] != 0: - name += '_m' + str(ident['LISO']) + name = ATOMIC_SYMBOL[ev.target['atomic_number']] + \ + str(ev.target['mass_number']) + if ev.target['isomeric_state'] != 0: + name += '_m' + str(ev.target['isomeric_state']) nuclide_group = out.create_group(name) # Write all the coefficients into one array. The first dimension gives @@ -371,7 +363,6 @@ class FissionEnergyRelease(EqualityMixin): component. The keys are the 2-3 letter strings used in ENDF-102, e.g. 'EFR' and 'ET'. The list will have a length of 1 for Sher-Beck data, more for polynomial data. - incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset @@ -440,14 +431,13 @@ class FissionEnergyRelease(EqualityMixin): return out @classmethod - def from_endf(cls, filename, incident_neutron): + def from_endf(cls, ev, incident_neutron): """Generate fission energy release data from an ENDF file. Parameters ---------- - filename : str - Name of the ENDF file containing fission energy release data - + ev : openmc.data.endf.Evaluation + ENDF evaluation incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset @@ -459,21 +449,20 @@ class FissionEnergyRelease(EqualityMixin): """ # Check to make sure this ENDF file matches the expected isomer. - ident = identify_nuclide(filename) - if ident['Z'] != incident_neutron.atomic_number: + if ev.target['atomic_number'] != incident_neutron.atomic_number: raise ValueError('The atomic number of the ENDF evaluation does ' 'not match the given IncidentNeutron.') - if ident['A'] != incident_neutron.mass_number: + if ev.target['mass_number'] != incident_neutron.mass_number: raise ValueError('The atomic mass of the ENDF evaluation does ' 'not match the given IncidentNeutron.') - if ident['LISO'] != incident_neutron.metastable: + if ev.target['isomeric_state'] != incident_neutron.metastable: raise ValueError('The metastable state of the ENDF evaluation does ' 'not match the given IncidentNeutron.') - if not ident['LFI']: + if not ev.target['fissionable']: raise ValueError('The ENDF evaluation is not fissionable.') # Read the 458 data from the ENDF file. - value, uncertainty = _extract_458_data(filename) + value, uncertainty = _extract_458_data(ev) # Build the object. return cls._from_dictionary(value, incident_neutron) @@ -516,7 +505,6 @@ class FissionEnergyRelease(EqualityMixin): Path to an HDF5 file containing fission energy release data. This file should have been generated form the :func:`openmc.data.write_compact_458_library` function. - incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset diff --git a/openmc/data/function.py b/openmc/data/function.py index 94a2f0911e..13df12b47e 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -4,6 +4,7 @@ from numbers import Real, Integral import numpy as np +import openmc.data import openmc.checkvalue as cv from openmc.mixin import EqualityMixin @@ -423,3 +424,80 @@ class Sum(EqualityMixin): def functions(self, functions): cv.check_type('functions', functions, Iterable, Callable) self._functions = functions + + +class ResonancesWithBackground(EqualityMixin): + """Cross section in resolved resonance region. + + Parameters + ---------- + resonances : openmc.data.Resonances + Resolved resonance parameter data + background : Callable + Background cross section as a function of energy + mt : int + MT value of the reaction + + Attributes + ---------- + resonances : openmc.data.Resonances + Resolved resonance parameter data + background : Callable + Background cross section as a function of energy + mt : int + MT value of the reaction + + """ + + + def __init__(self, resonances, background, mt): + self.resonances = resonances + self.background = background + self.mt = mt + + def __call__(self, x): + # Get background cross section + xs = self.background(x) + + rrr = self.resonances.resolved + if isinstance(x, Iterable): + # Determine which energies are within resolved resonance range + within_rrr = (rrr.energy_min <= x) & (x <= rrr.energy_max) + + # Get resonance cross sections and add to background + resonant_xs = rrr.reconstruct(x[within_rrr]) + xs[within_rrr] += resonant_xs[self.mt] + else: + if rrr.energy_min <= x <= rrr.energy_max: + resonant_xs = rrr.reconstruct(x) + xs += resonant_xs[self.mt] + + return xs + + @property + def background(self): + return self._background + + @property + def mt(self): + return self._mt + + @property + def resonances(self): + return self._resonances + + @background.setter + def background(self, background): + cv.check_type('background cross section', background, Callable) + self._background = background + + @mt.setter + def mt(self, mt): + cv.check_type('MT value', mt, Integral) + self._mt = mt + + @resonances.setter + def resonances(self, resonances): + cv.check_type('resolved resonance parameters', resonances, + openmc.data.Resonances) + self._resonances = resonances diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index 5aca17ba9f..e84e6a77a0 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -8,6 +8,7 @@ import openmc.checkvalue as cv from openmc.stats import Tabular, Univariate, Discrete, Mixture from .function import Tabulated1D, INTERPOLATION_SCHEME from .angle_energy import AngleEnergy +from .endf import get_list_record, get_tab2_record class KalbachMann(AngleEnergy): @@ -346,3 +347,54 @@ class KalbachMann(AngleEnergy): km_a.append(Tabulated1D(data[0], data[4])) return cls(breakpoints, interpolation, energy, energy_out, km_r, km_a) + + @classmethod + def from_endf(cls, file_obj): + """Generate Kalbach-Mann distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of the Kalbach-Mann distribution + + Returns + ------- + openmc.data.KalbachMann + Kalbach-Mann energy-angle distribution + + """ + params, tab2 = get_tab2_record(file_obj) + lep = params[3] + ne = params[5] + energy = np.zeros(ne) + n_discrete_energies = np.zeros(ne, dtype=int) + energy_out = [] + precompound = [] + slope = [] + for i in range(ne): + items, values = get_list_record(file_obj) + energy[i] = items[1] + n_discrete_energies[i] = items[2] + # TODO: split out discrete energies + n_angle = items[3] + n_energy_out = items[5] + values = np.asarray(values) + values.shape = (n_energy_out, n_angle + 2) + + # Outgoing energy distribution at the i-th incoming energy + eout_i = values[:,0] + eout_p_i = values[:,1] + energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep]) + energy_out.append(energy_out_i) + + # Precompound and slope factors for Kalbach-Mann + r_i = values[:,2] + if n_angle == 2: + a_i = values[:,3] + else: + a_i = np.zeros_like(r_i) + precompound.append(Tabulated1D(eout_i, r_i)) + slope.append(Tabulated1D(eout_i, a_i)) + + return cls(tab2.breakpoints, tab2.interpolation, energy, + energy_out, precompound, slope) diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py new file mode 100644 index 0000000000..be449b79a0 --- /dev/null +++ b/openmc/data/laboratory.py @@ -0,0 +1,139 @@ +from collections import Iterable +from numbers import Real, Integral + +import numpy as np + +import openmc.checkvalue as cv +from openmc.stats import Tabular, Univariate, Discrete, Mixture +from .angle_energy import AngleEnergy +from .function import INTERPOLATION_SCHEME +from .endf import get_tab2_record, get_tab1_record + + +class LaboratoryAngleEnergy(AngleEnergy): + """Laboratory angle-energy distribution + + Parameters + ---------- + breakpoints : Iterable of int + Breakpoints defining interpolation regions + interpolation : Iterable of int + Interpolation codes + energy : Iterable of float + Incoming energies at which distributions exist + mu : Iterable of openmc.stats.Univariate + Distribution of scattering cosines for each incoming energy + energy_out : Iterable of Iterable of openmc.stats.Univariate + Distribution of outgoing energies for each incoming energy/scattering + cosine + + Attributes + ---------- + breakpoints : Iterable of int + Breakpoints defining interpolation regions + interpolation : Iterable of int + Interpolation codes + energy : Iterable of float + Incoming energies at which distributions exist + mu : Iterable of openmc.stats.Univariate + Distribution of scattering cosines for each incoming energy + energy_out : Iterable of Iterable of openmc.stats.Univariate + Distribution of outgoing energies for each incoming energy/scattering + cosine + + """ + + def __init__(self, breakpoints, interpolation, energy, mu, energy_out): + super(LaboratoryAngleEnergy).__init__() + self.breakpoints = breakpoints + self.interpolation = interpolation + self.energy = energy + self.mu = mu + self.energy_out = energy_out + + @property + def breakpoints(self): + return self._breakpoints + + @property + def interpolation(self): + return self._interpolation + @property + def energy(self): + return self._energy + + @property + def mu(self): + return self._mu + + @property + def energy_out(self): + return self._energy_out + + @breakpoints.setter + def breakpoints(self, breakpoints): + cv.check_type('laboratory angle-energy breakpoints', breakpoints, + Iterable, Integral) + self._breakpoints = breakpoints + + @interpolation.setter + def interpolation(self, interpolation): + cv.check_type('laboratory angle-energy interpolation', interpolation, + Iterable, Integral) + self._interpolation = interpolation + + @energy.setter + def energy(self, energy): + cv.check_type('laboratory angle-energy incoming energy', energy, + Iterable, Real) + self._energy = energy + + @mu.setter + def mu(self, mu): + cv.check_type('laboratory angle-energy outgoing cosine', mu, + Iterable, Univariate) + self._mu = mu + + @energy_out.setter + def energy_out(self, energy_out): + cv.check_iterable_type('laboratory angle-energy outgoing energy', + energy_out, Univariate, 2, 2) + self._energy_out = energy_out + + @classmethod + def from_endf(cls, file_obj): + """Generate laboratory angle-energy distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the start of a section for a correlated + angle-energy distribution + + Returns + ------- + openmc.data.LaboratoryAngleEnergy + Laboratory angle-energy distribution + + """ + params, tab2 = get_tab2_record(file_obj) + ne = params[5] + energy = np.zeros(ne) + mu = [] + energy_out = [] + for i in range(ne): + params, tab2mu = get_tab2_record(file_obj) + energy[i] = params[1] + n_mu = params[5] + mu_i = np.zeros(n_mu) + p_mu_i = np.zeros(n_mu) + energy_out_i = [] + for j in range(n_mu): + params, f = get_tab1_record(file_obj) + mu_i[j] = params[1] + p_mu_i[j] = sum(f.y) + energy_out_i.append(Tabular(f.x, f.y)) + mu.append(Tabular(mu_i, p_mu_i)) + energy_out.append(energy_out_i) + + return cls(tab2.breakpoints, tab2.interpolation, energy, mu, energy_out) diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index a34380dc93..6616b1858d 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -4,6 +4,7 @@ import numpy as np import openmc.checkvalue as cv from .angle_energy import AngleEnergy +from .endf import get_cont_record class NBodyPhaseSpace(AngleEnergy): """N-body phase space distribution @@ -140,3 +141,25 @@ class NBodyPhaseSpace(AngleEnergy): n_particles = int(ace.xss[idx]) total_mass = ace.xss[idx + 1] return cls(total_mass, n_particles, ace.atomic_weight_ratio, q_value) + + @classmethod + def from_endf(cls, file_obj): + """Generate N-body phase space distribution from an ENDF evaluation + + Parameters + ---------- + file_obj : file-like object + ENDF file positions at the start of the N-body phase space + distribution + + Returns + ------- + openmc.data.NBodyPhaseSpace + N-body phase space distribution + + """ + items = get_cont_record(file_obj) + total_mass = items[0] + n_particles = items[5] + # TODO: get awr and Q value + return cls(total_mass, n_particles, 1.0, 0.0) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 2431ba74af..0c74aeaa1f 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -8,12 +8,14 @@ from warnings import warn import numpy as np import h5py -from .data import ATOMIC_SYMBOL, SUM_RULES, K_BOLTZMANN from .ace import Table, get_table +from .data import ATOMIC_SYMBOL, K_BOLTZMANN from .fission_energy import FissionEnergyRelease -from .function import Tabulated1D, Sum +from .function import Tabulated1D, Sum, ResonancesWithBackground +from .endf import Evaluation, SUM_RULES from .product import Product -from .reaction import Reaction, _get_photon_products +from .reaction import Reaction, _get_photon_products_ace +from .resonance import Resonances, _RESOLVED from .urr import ProbabilityTables import openmc.checkvalue as cv from openmc.mixin import EqualityMixin @@ -137,6 +139,8 @@ class IncidentNeutron(EqualityMixin): Contains the cross sections, secondary angle and energy distributions, and other associated data for each reaction. The keys are the MT values and the values are Reaction objects. + resonances : openmc.data.Resonances or None + Resonance parameters summed_reactions : collections.OrderedDict Contains summed cross sections, e.g., the total cross section. The keys are the MT values and the values are Reaction objects. @@ -166,6 +170,7 @@ class IncidentNeutron(EqualityMixin): self.reactions = OrderedDict() self.summed_reactions = OrderedDict() self._urr = {} + self._resonances = None def __contains__(self, mt): return mt in self.reactions or mt in self.summed_reactions @@ -212,6 +217,10 @@ class IncidentNeutron(EqualityMixin): def reactions(self): return self._reactions + @property + def resonances(self): + return self._resonances + @property def summed_reactions(self): return self._summed_reactions @@ -236,7 +245,7 @@ class IncidentNeutron(EqualityMixin): @atomic_number.setter def atomic_number(self, atomic_number): cv.check_type('atomic number', atomic_number, Integral) - cv.check_greater_than('atomic number', atomic_number, 0) + cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number @mass_number.setter @@ -268,6 +277,11 @@ class IncidentNeutron(EqualityMixin): cv.check_type('reactions', reactions, Mapping) self._reactions = reactions + @resonances.setter + def resonances(self, resonances): + cv.check_type('resonances', resonances, Resonances) + self._resonances = resonances + @summed_reactions.setter def summed_reactions(self, summed_reactions): cv.check_type('summed reactions', summed_reactions, Mapping) @@ -587,7 +601,7 @@ class IncidentNeutron(EqualityMixin): for mt_i in mts]) # Determine summed cross section - rx.products += _get_photon_products(ace, rx) + rx.products += _get_photon_products_ace(ace, rx) data.summed_reactions[mt] = rx # Read unresolved resonance probability tables @@ -596,3 +610,79 @@ class IncidentNeutron(EqualityMixin): data.urr[strT] = urr return data + + @classmethod + def from_endf(cls, ev_or_filename): + """Generate incident neutron continuous-energy data from an ENDF evaluation + + Parameters + ---------- + ev_or_filename : openmc.data.endf.Evaluation or str + ENDF evaluation to read from. If given as a string, it is assumed to + be the filename for the ENDF file. + + Returns + ------- + openmc.data.IncidentNeutron + Incident neutron continuous-energy data + + """ + if isinstance(ev_or_filename, Evaluation): + ev = ev_or_filename + else: + ev = Evaluation(ev_or_filename) + + atomic_number = ev.target['atomic_number'] + mass_number = ev.target['mass_number'] + metastable = ev.target['isomeric_state'] + atomic_weight_ratio = ev.target['mass'] + temperature = ev.target['temperature'] + + # Determine name + element = ATOMIC_SYMBOL[atomic_number] + if metastable > 0: + name = '{}{}_m{}'.format(element, mass_number, metastable) + else: + name = '{}{}'.format(element, mass_number) + + # Instantiate incident neutron data + data = cls(name, atomic_number, mass_number, metastable, + atomic_weight_ratio, temperature) + + if (2, 151) in ev.section: + data.resonances = Resonances.from_endf(ev) + + # Read each reaction + for mf, mt, nc, mod in ev.reaction_list: + if mf == 3: + data.reactions[mt] = Reaction.from_endf(ev, mt) + + # Replace cross sections for elastic, capture, fission + try: + if isinstance(data.resonances.resolved, _RESOLVED): + for mt in (2, 102, 18): + if mt in data.reactions: + rx = data.reactions[mt] + rx.xs['0K'] = ResonancesWithBackground( + data.resonances, rx.xs['0K'], mt) + except ValueError: + # Thrown if multiple resolved ranges (e.g. Pu239 in ENDF/B-VII.1) + pass + + # If first-chance, second-chance, etc. fission are present, check + # whether energy distributions were specified in MF=5. If not, copy the + # energy distribution from MT=18. + for mt, rx in data.reactions.items(): + if mt in (19, 20, 21, 38): + if (5, mt) not in ev.section: + neutron = data.reactions[18].products[0] + rx.products[0].applicability = neutron.applicability + rx.products[0].distribution = neutron.distribution + + # Read fission energy release (requires that we already know nu for + # fission) + if (1, 458) in ev.section: + data.fission_energy = FissionEnergyRelease.from_endf(ev, data) + + data._evaluation = ev + return data diff --git a/openmc/data/product.py b/openmc/data/product.py index 753888f6df..d9c3506e59 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -1,4 +1,5 @@ from collections import Iterable +from io import StringIO from numbers import Real import sys @@ -6,8 +7,8 @@ import numpy as np import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from .function import Tabulated1D, Polynomial, Function1D from .angle_energy import AngleEnergy +from .function import Tabulated1D, Polynomial, Function1D if sys.version_info[0] >= 3: basestring = str diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index eb33e1395f..cef6351352 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -3,21 +3,190 @@ from collections import Iterable, Callable, MutableMapping from copy import deepcopy from numbers import Real, Integral from warnings import warn +from io import StringIO import numpy as np import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from openmc.stats import Uniform +from openmc.stats import Uniform, Tabular, Legendre from .angle_distribution import AngleDistribution from .angle_energy import AngleEnergy -from .function import Tabulated1D, Polynomial, Function1D -from .data import REACTION_NAME, K_BOLTZMANN +from .correlated import CorrelatedAngleEnergy +from .data import ATOMIC_SYMBOL, K_BOLTZMANN +from .endf import get_head_record, get_tab1_record, get_list_record, \ + get_tab2_record, get_cont_record +from .energy_distribution import EnergyDistribution, LevelInelastic, \ + DiscretePhoton +from .function import Tabulated1D, Polynomial +from .kalbach_mann import KalbachMann +from .laboratory import LaboratoryAngleEnergy +from .nbody import NBodyPhaseSpace from .product import Product from .uncorrelated import UncorrelatedAngleEnergy -def _get_fission_products(ace): +REACTION_NAME = {1: '(n,total)', 2: '(n,elastic)', 4: '(n,level)', + 5: '(n,misc)', 11: '(n,2nd)', 16: '(n,2n)', 17: '(n,3n)', + 18: '(n,fission)', 19: '(n,f)', 20: '(n,nf)', 21: '(n,2nf)', + 22: '(n,na)', 23: '(n,n3a)', 24: '(n,2na)', 25: '(n,3na)', + 27: '(n,absorption)', 28: '(n,np)', 29: '(n,n2a)', + 30: '(n,2n2a)', 32: '(n,nd)', 33: '(n,nt)', 34: '(n,nHe-3)', + 35: '(n,nd2a)', 36: '(n,nt2a)', 37: '(n,4n)', 38: '(n,3nf)', + 41: '(n,2np)', 42: '(n,3np)', 44: '(n,n2p)', 45: '(n,npa)', + 91: '(n,nc)', 101: '(n,disappear)', 102: '(n,gamma)', + 103: '(n,p)', 104: '(n,d)', 105: '(n,t)', 106: '(n,3He)', + 107: '(n,a)', 108: '(n,2a)', 109: '(n,3a)', 111: '(n,2p)', + 112: '(n,pa)', 113: '(n,t2a)', 114: '(n,d2a)', 115: '(n,pd)', + 116: '(n,pt)', 117: '(n,da)', 152: '(n,5n)', 153: '(n,6n)', + 154: '(n,2nt)', 155: '(n,ta)', 156: '(n,4np)', 157: '(n,3nd)', + 158: '(n,nda)', 159: '(n,2npa)', 160: '(n,7n)', 161: '(n,8n)', + 162: '(n,5np)', 163: '(n,6np)', 164: '(n,7np)', 165: '(n,4na)', + 166: '(n,5na)', 167: '(n,6na)', 168: '(n,7na)', 169: '(n,4nd)', + 170: '(n,5nd)', 171: '(n,6nd)', 172: '(n,3nt)', 173: '(n,4nt)', + 174: '(n,5nt)', 175: '(n,6nt)', 176: '(n,2n3He)', + 177: '(n,3n3He)', 178: '(n,4n3He)', 179: '(n,3n2p)', + 180: '(n,3n3a)', 181: '(n,3npa)', 182: '(n,dt)', + 183: '(n,npd)', 184: '(n,npt)', 185: '(n,ndt)', + 186: '(n,np3He)', 187: '(n,nd3He)', 188: '(n,nt3He)', + 189: '(n,nta)', 190: '(n,2n2p)', 191: '(n,p3He)', + 192: '(n,d3He)', 193: '(n,3Hea)', 194: '(n,4n2p)', + 195: '(n,4n2a)', 196: '(n,4npa)', 197: '(n,3p)', + 198: '(n,n3p)', 199: '(n,3n2pa)', 200: '(n,5n2p)', 444: '(n,damage)', + 649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)', + 849: '(n,ac)'} +REACTION_NAME.update({i: '(n,n{})'.format(i-50) for i in range(50, 91)}) +REACTION_NAME.update({i: '(n,p{})'.format(i-600) for i in range(600, 649)}) +REACTION_NAME.update({i: '(n,d{})'.format(i-650) for i in range(650, 699)}) +REACTION_NAME.update({i: '(n,t{})'.format(i-700) for i in range(700, 749)}) +REACTION_NAME.update({i: '(n,3He{})'.format(i-750) for i in range(750, 799)}) +REACTION_NAME.update({i: '(n,a{})'.format(i-800) for i in range(800, 849)}) + + +def _get_products(ev, mt): + """Generate products from MF=6 in an ENDF evaluation + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation to read from + mt : int + The MT value of the reaction to get products for + + Returns + ------- + products : list of openmc.data.Product + Products of the reaction + + """ + file_obj = StringIO(ev.section[6, mt]) + + # Read HEAD record + items = get_head_record(file_obj) + reference_frame = {1: 'laboratory', 2: 'center-of-mass', + 3: 'light-heavy'}[items[3]] + n_products = items[4] + + products = [] + for i in range(n_products): + # Get yield for this product + params, yield_ = get_tab1_record(file_obj) + + za = params[0] + awr = params[1] + lip = params[2] + law = params[3] + + if za == 0: + p = Product('photon') + elif za == 1: + p = Product('neutron') + elif za == 1000: + p = Product('electron') + else: + z = za // 1000 + a = za % 1000 + p = Product('{}{}'.format(ATOMIC_SYMBOL[z], a)) + + p.yield_ = yield_ + + """ + # Set reference frame + if reference_frame == 'laboratory': + p.center_of_mass = False + elif reference_frame == 'center-of-mass': + p.center_of_mass = True + elif reference_frame == 'light-heavy': + p.center_of_mass = (awr <= 4.0) + """ + + if law == 0: + # No distribution given + pass + if law == 1: + # Continuum energy-angle distribution + + # Peak ahead to determine type of distribution + position = file_obj.tell() + params = get_cont_record(file_obj) + file_obj.seek(position) + + lang = params[2] + if lang == 1: + p.distribution = [CorrelatedAngleEnergy.from_endf(file_obj)] + elif lang == 2: + p.distribution = [KalbachMann.from_endf(file_obj)] + + elif law == 2: + # Discrete two-body scattering + params, tab2 = get_tab2_record(file_obj) + ne = params[5] + energy = np.zeros(ne) + mu = [] + for i in range(ne): + items, values = get_list_record(file_obj) + energy[i] = items[1] + lang = items[2] + if lang == 0: + mu.append(Legendre(values)) + elif lang == 12: + mu.append(Tabular(values[::2], values[1::2])) + elif lang == 14: + mu.append(Tabular(values[::2], values[1::2], + 'log-linear')) + + angle_dist = AngleDistribution(energy, mu) + dist = UncorrelatedAngleEnergy(angle_dist) + p.distribution = [dist] + # TODO: Add level-inelastic info? + + elif law == 3: + # Isotropic discrete emission + p.distribution = [UncorrelatedAngleEnergy()] + # TODO: Add level-inelastic info? + + elif law == 4: + # Discrete two-body recoil + pass + + elif law == 5: + # Charged particle elastic scattering + pass + + elif law == 6: + # N-body phase-space distribution + p.distribution = [NBodyPhaseSpace.from_endf(file_obj)] + + elif law == 7: + # Laboratory energy-angle distribution + p.distribution = [LaboratoryAngleEnergy.from_endf(file_obj)] + + products.append(p) + + return products + + +def _get_fission_products_ace(ace): """Generate fission products from an ACE table Parameters @@ -148,7 +317,116 @@ def _get_fission_products(ace): return products, derived_products -def _get_photon_products(ace, rx): +def _get_fission_products_endf(ev): + """Generate fission products from an ENDF evaluation + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + + Returns + ------- + products : list of openmc.data.Product + Prompt and delayed fission neutrons + derived_products : list of openmc.data.Product + "Total" fission neutron + + """ + products = [] + derived_products = [] + + if (1, 456) in ev.section: + prompt_neutron = Product('neutron') + prompt_neutron.emission_mode = 'prompt' + + # Prompt nu values + file_obj = StringIO(ev.section[1, 456]) + lnu = get_head_record(file_obj)[3] + if lnu == 1: + # Polynomial representation + items, coefficients = get_list_record(file_obj) + prompt_neutron.yield_ = Polynomial(coefficients) + elif lnu == 2: + # Tabulated representation + params, prompt_neutron.yield_ = get_tab1_record(file_obj) + + products.append(prompt_neutron) + + if (1, 452) in ev.section: + total_neutron = Product('neutron') + total_neutron.emission_mode = 'total' + + # Total nu values + file_obj = StringIO(ev.section[1, 452]) + lnu = get_head_record(file_obj)[3] + if lnu == 1: + # Polynomial representation + items, coefficients = get_list_record(file_obj) + total_neutron.yield_ = Polynomial(coefficients) + elif lnu == 2: + # Tabulated representation + params, total_neutron.yield_ = get_tab1_record(file_obj) + + if (1, 456) in ev.section: + derived_products.append(total_neutron) + else: + products.append(total_neutron) + + if (1, 455) in ev.section: + file_obj = StringIO(ev.section[1, 455]) + + # Determine representation of delayed nu data + items = get_head_record(file_obj) + ldg = items[2] + lnu = items[3] + + if ldg == 0: + # Delayed-group constants energy independent + items, decay_constants = get_list_record(file_obj) + for constant in decay_constants: + delayed_neutron = Product('neutron') + delayed_neutron.emission_mode = 'delayed' + delayed_neutron.decay_rate = constant + products.append(delayed_neutron) + elif ldg == 1: + # Delayed-group constants energy dependent + raise NotImplementedError('Delayed neutron with energy-dependent ' + 'group constants.') + + # In MF=1, MT=455, the delayed-group abundances are actually not + # specified if the group constants are energy-independent. In this case, + # the abundances must be inferred from MF=5, MT=455 where multiple + # energy distributions are given. + if lnu == 1: + # Nu represented as polynomial + items, coefficients = get_list_record(file_obj) + yield_ = Polynomial(coefficients) + for neutron in products[-6:]: + neutron.yield_ = deepcopy(yield_) + elif lnu == 2: + # Nu represented by tabulation + params, yield_ = get_tab1_record(file_obj) + for neutron in products[-6:]: + neutron.yield_ = deepcopy(yield_) + + if (5, 455) in ev.section: + file_obj = StringIO(ev.section[5, 455]) + items = get_head_record(file_obj) + nk = items[4] + assert nk == len(decay_constants) + for i in range(nk): + params, applicability = get_tab1_record(file_obj) + dist = UncorrelatedAngleEnergy() + dist.energy = EnergyDistribution.from_endf(file_obj, params) + + delayed_neutron = products[-6 + i] + delayed_neutron.yield_.y *= applicability.y[0] + delayed_neutron.distribution.append(dist) + + return products, derived_products + + +def _get_photon_products_ace(ace, rx): """Generate photon products from an ACE table Parameters @@ -253,6 +531,117 @@ def _get_photon_products(ace, rx): return photons +def _get_photon_products_endf(ev, rx): + """Generate photon products from an ENDF evaluation + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation to read from + rx : openmc.data.Reaction + Reaction that generates photons + + Returns + ------- + photons : list of openmc.Products + Photons produced from reaction with given MT + + """ + products = [] + + if (12, rx.mt) in ev.section: + file_obj = StringIO(ev.section[12, rx.mt]) + + items = get_head_record(file_obj) + option = items[2] + + if option == 1: + # Multiplicities given + n_discrete_photon = items[4] + if n_discrete_photon > 1: + items, total_yield = get_tab1_record(file_obj) + for k in range(n_discrete_photon): + photon = Product('photon') + + # Get photon yield + items, photon.yield_ = get_tab1_record(file_obj) + + # Get photon energy distribution + law = items[3] + dist = UncorrelatedAngleEnergy() + if law == 1: + # TODO: Get file 15 distribution + pass + elif law == 2: + energy = items[1] + primary_flag = items[2] + dist.energy = DiscretePhoton(primary_flag, energy, + ev.target['mass']) + + photon.distribution.append(dist) + products.append(photon) + + elif option == 2: + # Transition probability arrays given + ppyield = {} + ppyield['type'] = 'transition' + ppyield['transition'] = transition = {} + + # Determine whether simple (LG=1) or complex (LG=2) transitions + lg = items[3] + + # Get transition data + items, values = get_list_record(file_obj) + transition['energy_start'] = items[0] + transition['energies'] = np.array(values[::lg + 1]) + transition['direct_probability'] = np.array(values[1::lg + 1]) + if lg == 2: + # Complex case + transition['conditional_probability'] = np.array( + values[2::lg + 1]) + + elif (13, rx.mt) in ev.section: + file_obj = StringIO(ev.section[13, rx.mt]) + + # Determine option + items = get_head_record(file_obj) + n_discrete_photon = items[4] + if n_discrete_photon > 1: + items, total_xs = get_tab1_record(file_obj) + for k in range(n_discrete_photon): + photon = Product('photon') + items, xs = get_tab1_record(file_obj) + + # Re-interpolation photon production cross section and neutron cross + # section to union energy grid + energy = np.union1d(xs.x, rx.xs['0K'].x) + photon_prod_xs = xs(energy) + neutron_xs = rx.xs['0K'](energy) + idx = np.where(neutron_xs > 0) + + # Calculate yield as ratio + yield_ = np.zeros_like(energy) + yield_[idx] = photon_prod_xs[idx] / neutron_xs[idx] + photon.yield_ = Tabulated1D(energy, yield_) + + # Get photon energy distribution + law = items[3] + dist = UncorrelatedAngleEnergy() + if law == 1: + # TODO: Get file 15 distribution + pass + elif law == 2: + energy = items[1] + primary_flag = items[2] + dist.energy = DiscretePhoton(primary_flag, energy, + ev.target['mass']) + + photon.distribution.append(dist) + products.append(photon) + + return products + + class Reaction(EqualityMixin): """A nuclear reaction @@ -350,7 +739,7 @@ class Reaction(EqualityMixin): cv.check_type('reaction cross section dictionary', xs, MutableMapping) for key, value in xs.items(): cv.check_type('reaction cross section temperature', key, basestring) - cv.check_type('reaction cross section', value, Function1D) + cv.check_type('reaction cross section', value, Callable) self._xs = xs def to_hdf5(self, group): @@ -397,7 +786,7 @@ class Reaction(EqualityMixin): Returns ------- - openmc.data.ace.Reaction + openmc.data.Reaction Reaction data """ @@ -500,7 +889,7 @@ class Reaction(EqualityMixin): rx.products.append(neutron) else: assert mt in (18, 19, 20, 21, 38) - rx.products, rx.derived_products = _get_fission_products(ace) + rx.products, rx.derived_products = _get_fission_products_ace(ace) for p in rx.products: if p.emission_mode in ('prompt', 'total'): @@ -568,6 +957,92 @@ class Reaction(EqualityMixin): # ====================================================================== # PHOTON PRODUCTION - rx.products += _get_photon_products(ace, rx) + rx.products += _get_photon_products_ace(ace, rx) + + return rx + + @classmethod + def from_endf(cls, ev, mt): + """Generate a reaction from an ENDF evaluation + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + mt : int + The MT value of the reaction to get angular distributions for + + Returns + ------- + rx : openmc.data.Reaction + Reaction data + + """ + rx = Reaction(mt) + + # Integrated cross section + if (3, mt) in ev.section: + file_obj = StringIO(ev.section[3, mt]) + get_head_record(file_obj) + params, rx.xs['0K'] = get_tab1_record(file_obj) + rx.q_value = params[1] + + # Get fission product yields (nu) as well as delayed neutron energy + # distributions + if mt in (18, 19, 20, 21, 38): + rx.products, rx.derived_products = _get_fission_products_endf(ev) + + if (6, mt) in ev.section: + # Product angle-energy distribution + rx.products = _get_products(ev, mt) + + elif (4, mt) in ev.section or (5, mt) in ev.section: + # Uncorrelated angle-energy distribution + neutron = Product('neutron') + + # Note that the energy distribution for MT=455 is read in + # _get_fission_products_endf rather than here + if (5, mt) in ev.section: + file_obj = StringIO(ev.section[5, mt]) + items = get_head_record(file_obj) + nk = items[4] + for i in range(nk): + params, applicability = get_tab1_record(file_obj) + dist = UncorrelatedAngleEnergy() + dist.energy = EnergyDistribution.from_endf(file_obj, params) + + neutron.applicability.append(applicability) + neutron.distribution.append(dist) + elif mt == 2: + # Elastic scattering -- no energy distribution is given since it + # can be calulcated analytically + dist = UncorrelatedAngleEnergy() + neutron.distribution.append(dist) + elif mt >= 51 and mt < 91: + # Level inelastic scattering -- no energy distribution is given + # since it can be calculated analytically. Here we determine the + # necessary parameters to create a LevelInelastic object + dist = UncorrelatedAngleEnergy() + + A = ev.target['mass'] + threshold = (A + 1.)/A*abs(rx.q_value) + mass_ratio = (A/(A + 1.))**2 + dist.energy = LevelInelastic(threshold, mass_ratio) + + neutron.distribution.append(dist) + + if (4, mt) in ev.section: + for dist in neutron.distribution: + dist.angle = AngleDistribution.from_endf(ev, mt) + + if mt in (18, 19, 20, 21, 38) and (5, mt) in ev.section: + # For fission reactions, + rx.products[0].applicability = neutron.applicability + rx.products[0].distribution = neutron.distribution + else: + rx.products.append(neutron) + + if (12, mt) in ev.section or (13, mt) in ev.section: + rx.products += _get_photon_products_endf(ev, rx) return rx diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx new file mode 100644 index 0000000000..4790cc345c --- /dev/null +++ b/openmc/data/reconstruct.pyx @@ -0,0 +1,515 @@ +from libc.stdlib cimport malloc, calloc, free +from libc.math cimport cos, sin, sqrt, atan, M_PI + +cimport numpy as np +import numpy as np +from numpy.linalg import inv +cimport cython + + +cdef extern from "complex.h": + double cabs(double complex) + double complex conj(double complex) + double creal(complex double) + double cimag(complex double) + double complex cexp(double complex) + +# Physical constants are from CODATA 2014 +cdef double NEUTRON_MASS_ENERGY = 939.5654133e6 # MeV/c^2 +cdef double HBAR_C = 197.3269788e5 # MeV-b^0.5 + + +@cython.cdivision(True) +def wave_number(double A, double E): + r"""Neutron wave number in center-of-mass system. + + ENDF-102 defines the neutron wave number in the center-of-mass system in + Equation D.10 as + + .. math:: + k = \frac{2m_n}{\hbar} \frac{A}{A + 1} \sqrt{|E|} + + Parameters + ---------- + A : double + Ratio of target mass to neutron mass + E : double + Energy in eV + + Returns + ------- + double + Neutron wave number in b^-0.5 + + """ + return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C + +@cython.cdivision(True) +cdef double _wave_number(double A, double E): + return A/(A + 1)*sqrt(2*NEUTRON_MASS_ENERGY*abs(E))/HBAR_C + + +@cython.cdivision(True) +cdef double phaseshift(int l, double rho): + """Calculate hardsphere phase shift as given in ENDF-102, Equation D.13 + + Parameters + ---------- + l : int + Angular momentum quantum number + rho : float + Product of the wave number and the channel radius + + Returns + ------- + double + Hardsphere phase shift + + """ + + if l == 0: + return rho + elif l == 1: + return rho - atan(rho) + elif l == 2: + return rho - atan(3*rho/(3 - rho**2)) + elif l == 3: + return rho - atan((15*rho - rho**3)/(15 - 6*rho**2)) + elif l == 4: + return rho - atan((105*rho - 10*rho**3)/(105 - 45*rho**2 + rho**4)) + + +@cython.cdivision(True) +def penetration_shift(int l, double rho): + r"""Calculate shift and penetration factors as given in ENDF-102, Equations D.11 + and D.12. + + Parameters + ---------- + l : int + Angular momentum quantum number + rho : float + Product of the wave number and the channel radius + + Returns + ------- + double + Penetration factor for given :math:`l` + double + Shift factor for given :math:`l` + + """ + cdef double den + + if l == 0: + return rho, 0. + elif l == 1: + den = 1 + rho**2 + return rho**3/den, -1/den + elif l == 2: + den = 9 + 3*rho**2 + rho**4 + return rho**5/den, -(18 + 3*rho**2)/den + elif l == 3: + den = 225 + 45*rho**2 + 6*rho**4 + rho**6 + return rho**7/den, -(675 + 90*rho**2 + 6*rho**4)/den + elif l == 4: + den = 11025 + 1575*rho**2 + 135*rho**4 + 10*rho**6 + rho**8 + return rho**9/den, -(44100 + 4725*rho**2 + 270*rho**4 + 10*rho**6)/den + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_mlbw(mlbw, double E): + """Evaluate cross section using MLBW data. + + Parameters + ---------- + mlbw : openmc.data.MultiLevelBreitWigner + Multi-level Breit-Wigner resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, nJ, ij, l, n_res, i_res + cdef double elastic, capture, fission + cdef double A, k, rho, rhohat, I + cdef double P, S, phi, cos2phi, sin2phi + cdef double Ex, Q, rhoc, rhochat, P_c, S_c + cdef double jmin, jmax, j, Dl + cdef double E_r, gt, gn, gg, gf, gx, P_r, S_r, P_rx + cdef double gnE, gtE, Eprime, x, f + cdef double *g + cdef double (*s)[2] + cdef double [:,:] params + + I = mlbw.target_spin + A = mlbw.atomic_weight_ratio + k = _wave_number(A, E) + + elastic = 0. + capture = 0. + fission = 0. + + for i, l in enumerate(mlbw._l_values): + params = mlbw._parameter_matrix[l] + + rho = k*mlbw.channel_radius[l](E) + rhohat = k*mlbw.scattering_radius[l](E) + P, S = penetration_shift(l, rho) + phi = phaseshift(l, rhohat) + cos2phi = cos(2*phi) + sin2phi = sin(2*phi) + + # Determine shift and penetration at modified energy + if mlbw._competitive[i]: + Ex = E + mlbw.q_value[l]*(A + 1)/A + rhoc = mlbw.channel_radius[l](Ex) + rhochat = mlbw.scattering_radius[l](Ex) + P_c, S_c = penetration_shift(l, rhoc) + if Ex < 0: + P_c = 0 + + # Determine range of total angular momentum values based on equation + # 41 in LA-UR-12-27079 + jmin = abs(abs(I - l) - 0.5) + jmax = I + l + 0.5 + nJ = int(jmax - jmin + 1) + + # Determine Dl factor using Equation 43 in LA-UR-12-27079 + Dl = 2*l + 1 + g = malloc(nJ*sizeof(double)) + for ij in range(nJ): + j = jmin + ij + g[ij] = (2*j + 1)/(4*I + 2) + Dl -= g[ij] + + s = calloc(2*nJ, sizeof(double)) + for i_res in range(params.shape[0]): + # Copy resonance parameters + E_r = params[i_res, 0] + j = params[i_res, 2] + ij = int(j - jmin) + gt = params[i_res, 3] + gn = params[i_res, 4] + gg = params[i_res, 5] + gf = params[i_res, 6] + gx = params[i_res, 7] + P_r = params[i_res, 8] + S_r = params[i_res, 9] + P_rx = params[i_res, 10] + + # Calculate neutron and total width at energy E + gnE = P*gn/P_r # ENDF-102, Equation D.7 + gtE = gnE + gg + gf + if gx > 0: + gtE += gx*P_c/P_rx + + Eprime = E_r + (S_r - S)/(2*P_r)*gn # ENDF-102, Equation D.9 + x = 2*(E - Eprime)/gtE # LA-UR-12-27079, Equation 26 + f = 2*gnE/(gtE*(1 + x*x)) # Common factor in Equation 40 + s[ij][0] += f # First sum in Equation 40 + s[ij][1] += f*x # Second sum in Equation 40 + capture += f*g[ij]*gg/gtE + if gf > 0: + fission += f*g[ij]*gf/gtE + + for ij in range(nJ): + # Add all but last term of LA-UR-12-27079, Equation 40 + elastic += g[ij]*((1 - cos2phi - s[ij][0])**2 + + (sin2phi + s[ij][1])**2) + + # Add final term with Dl from Equation 40 + elastic += 2*Dl*(1 - cos2phi) + + # Free memory + free(g) + free(s) + + capture *= 2*M_PI/(k*k) + fission *= 2*M_PI/(k*k) + elastic *= M_PI/(k*k) + + return (elastic, capture, fission) + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_slbw(slbw, double E): + """Evaluate cross section using SLBW data. + + Parameters + ---------- + slbw : openmc.data.SingleLevelBreitWigner + Single-level Breit-Wigner resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, l, i_res + cdef double elastic, capture, fission + cdef double A, k, rho, rhohat, I + cdef double P, S, phi, cos2phi, sin2phi, sinphi2 + cdef double Ex, rhoc, rhochat, P_c, S_c + cdef double E_r, J, gt, gn, gg, gf, gx, P_r, S_r, P_rx + cdef double gnE, gtE, Eprime, f + cdef double x, theta, psi, chi + cdef double [:,:] params + + I = slbw.target_spin + A = slbw.atomic_weight_ratio + k = _wave_number(A, E) + + elastic = 0. + capture = 0. + fission = 0. + + for i, l in enumerate(slbw._l_values): + params = slbw._parameter_matrix[l] + + rho = k*slbw.channel_radius[l](E) + rhohat = k*slbw.scattering_radius[l](E) + P, S = penetration_shift(l, rho) + phi = phaseshift(l, rhohat) + cos2phi = cos(2*phi) + sin2phi = sin(2*phi) + sinphi2 = sin(phi)**2 + + # Add potential scattering -- first term in ENDF-102, Equation D.2 + elastic += 4*M_PI/(k*k)*(2*l + 1)*sinphi2 + + # Determine shift and penetration at modified energy + if slbw._competitive[i]: + Ex = E + slbw.q_value[l]*(A + 1)/A + rhoc = slbw.channel_radius[l](Ex) + rhochat = slbw.scattering_radius[l](Ex) + P_c, S_c = penetration_shift(l, rhoc) + if Ex < 0: + P_c = 0 + + for i_res in range(params.shape[0]): + # Copy resonance parameters + E_r = params[i_res, 0] + J = params[i_res, 2] + gt = params[i_res, 3] + gn = params[i_res, 4] + gg = params[i_res, 5] + gf = params[i_res, 6] + gx = params[i_res, 7] + P_r = params[i_res, 8] + S_r = params[i_res, 9] + P_rx = params[i_res, 10] + + # Calculate neutron and total width at energy E + gnE = P*gn/P_r # Equation D.7 + gtE = gnE + gg + gf + if gx > 0: + gtE += gx*P_c/P_rx + + Eprime = E_r + (S_r - S)/(2*P_r)*gn # Equation D.9 + gJ = (2*J + 1)/(4*I + 2) # Mentioned in section D.1.1.4 + + # Calculate common factor for elastic, capture, and fission + # cross sections + f = M_PI/(k*k)*gJ*gnE/((E - Eprime)**2 + gtE**2/4) + + # Add contribution to elastic per Equation D.2 + elastic += f*(gnE*cos2phi - 2*(gg + gf)*sinphi2 + + 2*(E - Eprime)*sin2phi) + + # Add contribution to capture per Equation D.3 + capture += f*gg + + # Add contribution to fission per Equation D.6 + if gf > 0: + fission += f*gf + + return (elastic, capture, fission) + + +@cython.boundscheck(False) +@cython.wraparound(False) +@cython.cdivision(True) +def reconstruct_rm(rm, double E): + """Evaluate cross section using Reich-Moore data. + + Parameters + ---------- + rm : openmc.data.ReichMoore + Reich-Moore resonance parameters + E : double + Energy in eV at which to evaluate the cross section + + Returns + ------- + elastic : double + Elastic scattering cross section in barns + capture : double + Radiative capture cross section in barns + fission : double + Fission cross section in barns + + """ + cdef int i, l, m, n, i_res + cdef int i_s, num_s, i_J, num_J + cdef double elastic, capture, fission, total + cdef double A, k, rho, rhohat, I + cdef double P, S, phi + cdef double smin, smax, s, Jmin, Jmax, J, j + cdef double E_r, gn, gg, gfa, gfb, P_r + cdef double E_diff, abs_value, gJ + cdef double complex Ubar, U_, denominator_inverse + cdef bint hasfission + cdef np.ndarray[double, ndim=2] one + cdef np.ndarray[double complex, ndim=2] K, Imat, U + cdef double [:,:] params + + # Get nuclear spin + I = rm.target_spin + + elastic = 0. + fission = 0. + total = 0. + A = rm.atomic_weight_ratio + k = _wave_number(A, E) + one = np.eye(3) + K = np.zeros((3,3), dtype=complex) + + for i, l in enumerate(rm._l_values): + # Check for l-dependent scattering radius + rho = k*rm.channel_radius[l](E) + rhohat = k*rm.scattering_radius[l](E) + + # Calculate shift and penetrability + P, S = penetration_shift(l, rho) + + # Calculate phase shift + phi = phaseshift(l, rhohat) + + # Calculate common factor on collision matrix terms (term outside curly + # braces in ENDF-102, Eq. D.27) + Ubar = cexp(-2j*phi) + + # The channel spin is the vector sum of the target spin, I, and the + # neutron spin, 1/2, so can take on values of |I - 1/2| < s < I + 1/2 + smin = abs(I - 0.5) + smax = I + 0.5 + num_s = int(smax - smin + 1) + + for i_s in range(num_s): + s = i_s + smin + + # Total angular momentum is the vector sum of l and s and can assume + # values between |l - s| < J < l + s + Jmin = abs(l - s) + Jmax = l + s + num_J = int(Jmax - Jmin + 1) + + for i_J in range(num_J): + J = i_J + Jmin + + # Initialize K matrix + for m in range(3): + for n in range(3): + K[m,n] = 0.0 + + hasfission = False + if (l, J) in rm._parameter_matrix: + params = rm._parameter_matrix[l, J] + + for i_res in range(params.shape[0]): + # Sometimes, the same (l, J) quantum numbers can occur + # for different values of the channel spin, s. In this + # case, the sign of the channel spin indicates which + # spin is to be used. If the spin is negative assume + # this resonance comes from the I - 1/2 channel and vice + # versa. + j = params[i_res, 2] + if l > 0: + if (j < 0 and s != smin) or (j > 0 and s != smax): + continue + + # Copy resonance parameters + E_r = params[i_res, 0] + gn = params[i_res, 3] + gg = params[i_res, 4] + gfa = params[i_res, 5] + gfb = params[i_res, 6] + P_r = params[i_res, 7] + + # Calculate neutron width at energy E + gn = sqrt(P*gn/P_r) + + # Calculate inverse of denominator of K matrix terms + E_diff = E_r - E + abs_value = E_diff*E_diff + 0.25*gg*gg + denominator_inverse = (E_diff + 0.5j*gg)/abs_value + + # Upper triangular portion of K matrix -- see ENDF-102, + # Equation D.28 + K[0,0] = K[0,0] + gn*gn*denominator_inverse + if gfa != 0.0 or gfb != 0.0: + # Negate fission widths if necessary + gfa = (-1 if gfa < 0 else 1)*sqrt(abs(gfa)) + gfb = (-1 if gfb < 0 else 1)*sqrt(abs(gfb)) + + K[0,1] = K[0,1] + gn*gfa*denominator_inverse + K[0,2] = K[0,2] + gn*gfb*denominator_inverse + K[1,1] = K[1,1] + gfa*gfa*denominator_inverse + K[1,2] = K[1,2] + gfa*gfb*denominator_inverse + K[2,2] = K[2,2] + gfb*gfb*denominator_inverse + hasfission = True + + # multiply by factor of i/2 + for m in range(3): + for n in range(3): + K[m,n] = K[m,n] * 0.5j + + # Get collision matrix + gJ = (2*J + 1)/(4*I + 2) + if hasfission: + # Copy upper triangular portion of K to lower triangular + K[1,0] = K[0,1] + K[2,0] = K[0,2] + K[2,1] = K[1,2] + + Imat = inv(one - K) + U = Ubar*(2*Imat - one) # ENDF-102, Eq. D.27 + elastic += gJ*cabs(1 - U[0,0])**2 # ENDF-102, Eq. D.24 + total += 2*gJ*(1 - creal(U[0,0])) # ENDF-102, Eq. D.23 + + # Calculate fission from ENDF-102, Eq. D.26 + fission += 4*gJ*(cabs(Imat[1,0])**2 + cabs(Imat[2,0])**2) + else: + U_ = Ubar*(2*conj(1 - K[0,0])/cabs(1 - K[0,0])**2 - 1) + elastic += gJ*cabs(1 - U_)**2 # ENDF-102, Eq. D.24 + total += 2*gJ*(1 - creal(U_)) # ENDF-102, Eq. D.23 + + # Calculate capture as difference of other cross sections as per ENDF-102, + # Equation D.25 + capture = total - elastic - fission + + elastic *= M_PI/(k*k) + capture *= M_PI/(k*k) + fission *= M_PI/(k*k) + + return (elastic, capture, fission) diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py new file mode 100644 index 0000000000..206a56df45 --- /dev/null +++ b/openmc/data/resonance.py @@ -0,0 +1,1059 @@ +from collections import defaultdict, MutableSequence, Iterable +import io + +import numpy as np +from numpy.polynomial import Polynomial +import pandas as pd + +from .endf import get_head_record, get_cont_record, get_tab1_record, get_list_record +try: + from .reconstruct import wave_number, penetration_shift, reconstruct_mlbw, \ + reconstruct_slbw, reconstruct_rm + _reconstruct = True +except ImportError: + _reconstruct = False +import openmc.checkvalue as cv + +class Resonances(object): + """Resolved and unresolved resonance data + + Parameters + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + + Attributes + ---------- + ranges : list of openmc.data.ResonanceRange + Distinct energy ranges for resonance data + resolved : openmc.data.ResonanceRange or None + Resolved resonance range + unresolved : openmc.data.Unresolved or None + Unresolved resonance range + + """ + + def __init__(self, ranges): + self.ranges = ranges + + @property + def ranges(self): + return self._ranges + + @property + def resolved(self): + resolved_ranges = [r for r in self.ranges + if not isinstance(r, Unresolved)] + if len(resolved_ranges) > 1: + raise ValueError('More than one resolved range present') + elif len(resolved_ranges) == 0: + return None + else: + return resolved_ranges[0] + + @property + def unresolved(self): + for r in self.ranges: + if isinstance(r, Unresolved): + return r + else: + return None + + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + + @classmethod + def from_endf(cls, ev): + """Generate resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + + Returns + ------- + openmc.data.Resonances + Resonance data + + """ + file_obj = io.StringIO(ev.section[2, 151]) + + # Determine whether discrete or continuous representation + items = get_head_record(file_obj) + n_isotope = items[4] # Number of isotopes + + ranges = [] + for iso in range(n_isotope): + items = get_cont_record(file_obj) + abundance = items[1] + fission_widths = (items[3] == 1) # fission widths are given? + n_ranges = items[4] # number of resonance energy ranges + + for j in range(n_ranges): + items = get_cont_record(file_obj) + resonance_flag = items[2] # flag for resolved (1)/unresolved (2) + formalism = items[3] # resonance formalism + + if resonance_flag in (0, 1): + # resolved resonance region + erange = _FORMALISMS[formalism].from_endf(ev, file_obj, items) + + elif resonance_flag == 2: + # unresolved resonance region + erange = Unresolved.from_endf(file_obj, items, fission_widths) + + #erange.material = self + ranges.append(erange) + + return cls(ranges) + + +class ResonanceRange(object): + """Resolved resonance range + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energ + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + self.target_spin = target_spin + self.energy_min = energy_min + self.energy_max = energy_max + self.channel_radius = channel + self.scattering_radius = scattering + + self._prepared = False + self._parameter_matrix = {} + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create resonance range from an ENDF evaluation. + + This factory method is only used when LRU=0, indicating that only a + scattering radius appears in MF=2, MT=151. All subclasses of + ResonanceRange override this method with their own. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.ResonanceRange + Resonance range data + + """ + energy_min, energy_max = items[0:2] + + # For scattering radius-only, NRO must be zero + assert items[4] == 0 + + # Get energy-independent scattering radius + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*ev.target['mass'])**(1./3.) + 0.08,)) + + return cls(target_spin, energy_min, energy_max, {0: a}, {0: ap}) + + def reconstruct(self, energies): + """Evaluate cross section at specified energies. + + Parameters + ---------- + energies : float or Iterable of float + Energies at which the cross section should be evaluated + + Returns + ------- + 3-tuple of float or numpy.ndarray + Elastic, capture, and fission cross sections at the specified + energies + + """ + if not _reconstruct: + raise RuntimeError("Resonance reconstruction not available.") + + # Pre-calculate penetrations and shifts for resonances + if not self._prepared: + self._prepare_resonances() + + if isinstance(energies, Iterable): + elastic = np.zeros_like(energies) + capture = np.zeros_like(energies) + fission = np.zeros_like(energies) + + for i, E in enumerate(energies): + xse, xsg, xsf = self._reconstruct(self, E) + elastic[i] = xse + capture[i] = xsg + fission[i] = xsf + else: + elastic, capture, fission = self._reconstruct(self, energies) + + return {2: elastic, 102: capture, 18: fission} + + +class MultiLevelBreitWigner(ResonanceRange): + """Multi-level Breit-Wigner resolved resonance formalism data. + + Multi-level Breit-Wigner resolved resonance data is identified by LRF=2 in + the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + q_value : dict + Q-value to be added to incident particle's center-of-mass energy to + determine the channel energy for use in the penetrability factor. The + keys of the dictionary are l-values. + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(MultiLevelBreitWigner, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + self.parameters = None + self.q_value = {} + self.atomic_weight_ratio = None + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_mlbw + else: + self._reconstruct = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create MLBW data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.MultiLevelBreitWigner + Multi-level Breit-Wigner resonance parameters + + """ + + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) # energy-independent scattering-radius + NLS = items[4] # number of l-values + + # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} + q_value = {} + records = [] + for l in range(NLS): + items, values = get_list_record(file_obj) + l_value = items[2] + awri = items[0] + q_value[l_value] = items[1] + competitive = items[3] + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*awri)**(1./3.) + 0.08,)) + + # Construct scattering and channel radius + if nro == 0: + scattering_radius[l_value] = ap + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = ap + elif nro == 1: + scattering_radius[l_value] = ape + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = ape + elif naps == 2: + channel_radius[l_value] = ap + + energy = values[0::6] + spin = values[1::6] + gt = np.asarray(values[2::6]) + gn = np.asarray(values[3::6]) + gg = np.asarray(values[4::6]) + gf = np.asarray(values[5::6]) + if competitive > 0: + gx = gt - (gn + gg + gf) + else: + gx = np.zeros_like(gt) + + for i, E in enumerate(energy): + records.append([energy[i], l_value, spin[i], gt[i], gn[i], + gg[i], gf[i], gx[i]]) + + columns = ['energy', 'L', 'J', 'totalWidth', 'neutronWidth', + 'captureWidth', 'fissionWidth', 'competitiveWidth'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of class + mlbw = cls(target_spin, energy_min, energy_max, + channel_radius, scattering_radius) + mlbw.q_value = q_value + mlbw.atomic_weight_ratio = awri + mlbw.parameters = parameters + + return mlbw + + def _prepare_resonances(self): + df = self.parameters.copy() + + # Penetration and shift factors + p = np.zeros(len(df)) + s = np.zeros(len(df)) + + # Penetration and shift factors for competitive reaction + px = np.zeros(len(df)) + sx = np.zeros(len(df)) + + l_values = [] + competitive = [] + + A = self.atomic_weight_ratio + for i, E, l, J, gt, gn, gg, gf, gx in df.itertuples(): + if l not in l_values: + l_values.append(l) + competitive.append(gx > 0) + + # Determine penetration and shift corresponding to resonance energy + k = wave_number(A, E) + rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) + p[i], s[i] = penetration_shift(l, rho) + + # Determine penetration at modified energy for competitive reaction + if gx > 0: + Ex = E + self.q[l]*(A + 1)/A + rho = k*self.channel_radius[l](Ex) + rhohat = k*self.scattering_radius[l](Ex) + px[i], sx[i] = penetration_shift(l, rho) + else: + px[i] = sx[i] = 0.0 + + df['p'] = p + df['s'] = s + df['px'] = px + df['sx'] = sx + + self._l_values = np.array(l_values) + self._competitive = np.array(competitive) + for l in l_values: + self._parameter_matrix[l] = df[df.L == l].as_matrix() + + self._prepared = True + + +class SingleLevelBreitWigner(MultiLevelBreitWigner): + """Single-level Breit-Wigner resolved resonance formalism data. + + Single-level Breit-Wigner resolved resonance data is is identified by LRF=1 + in the ENDF-6 format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + q_value : dict + Q-value to be added to incident particle's center-of-mass energy to + determine the channel energy for use in the penetrability factor. The + keys of the dictionary are l-values. + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(SingleLevelBreitWigner, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_slbw + else: + self._reconstruct = None + + +class ReichMoore(ResonanceRange): + """Reich-Moore resolved resonance formalism data. + + Reich-Moore resolved resonance data is identified by LRF=3 in the ENDF-6 + format. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + channel : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + scattering : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + + Attributes + ---------- + angle_distribution : bool + Indicate whether parameters can be used to compute angular distributions + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide given as a function of + l-value. Note that this may be different than the value for the + evaluation as a whole. + channel_radius : dict + Dictionary whose keys are l-values and values are channel radii as a + function of energy + energy_max : float + Maximum energy of the resolved resonance range in eV + energy_min : float + Minimum energy of the resolved resonance range in eV + num_l_convergence : int + Number of l-values which must be used to converge the calculation + scattering_radius : dict + Dictionary whose keys are l-values and values are scattering radii as a + function of energy + parameters : pandas.DataFrame + Energies, spins, and resonances widths for each resonance + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super(ReichMoore, self).__init__( + target_spin, energy_min, energy_max, channel, scattering) + self.parameters = None + self.angle_distribution = False + self.num_l_convergence = 0 + + # Set resonance reconstruction function + if _reconstruct: + self._reconstruct = reconstruct_rm + else: + self._reconstruct = None + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Create Reich-Moore resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.ReichMoore + Reich-Moore resonance parameters + + """ + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro, naps = items[4:6] + if nro != 0: + params, ape = get_tab1_record(file_obj) + + # Other scatter radius parameters + items = get_cont_record(file_obj) + target_spin = items[0] + ap = Polynomial((items[1],)) + angle_distribution = (items[3] == 1) # Flag for angular distribution + NLS = items[4] # Number of l-values + num_l_convergence = items[5] # Number of l-values for convergence + + # Read resonance widths, J values, etc + channel_radius = {} + scattering_radius = {} + records = [] + for i in range(NLS): + items, values = get_list_record(file_obj) + apl = Polynomial((items[1],)) if items[1] != 0.0 else ap + l_value = items[2] + awri = items[0] + + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (1.008665*awri)**(1./3.) + 0.08,)) + + # Construct scattering and channel radius + if nro == 0: + scattering_radius[l_value] = apl + if naps == 0: + channel_radius[l_value] = a + elif naps == 1: + channel_radius[l_value] = apl + elif nro == 1: + if naps == 0: + channel_radius[l_value] = a + scattering_radius[l_value] = ape + elif naps == 1: + channel_radius[l_value] = scattering_radius[l_value] = ape + elif naps == 2: + channel_radius[l_value] = apl + scattering_radius[l_value] = ape + + energy = values[0::6] + spin = values[1::6] + gn = values[2::6] + gg = values[3::6] + gfa = values[4::6] + gfb = values[5::6] + + for i, E in enumerate(energy): + records.append([energy[i], l_value, spin[i], gn[i], gg[i], + gfa[i], gfb[i]]) + + # Create pandas DataFrame with resonance data + columns = ['energy', 'L', 'J', 'neutronWidth', 'captureWidth', + 'fissionWidthA', 'fissionWidthB'] + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Create instance of ReichMoore + rm = cls(target_spin, energy_min, energy_max, + channel_radius, scattering_radius) + rm.parameters = parameters + rm.angle_distribution = angle_distribution + rm.num_l_convergence = num_l_convergence + rm.atomic_weight_ratio = awri + + return rm + + def _prepare_resonances(self): + df = self.parameters.copy() + + # Penetration and shift factors + p = np.zeros(len(df)) + s = np.zeros(len(df)) + + l_values = [] + lj_values = [] + + A = self.atomic_weight_ratio + for i, E, l, J, gn, gg, gfa, gfb in df.itertuples(): + if l not in l_values: + l_values.append(l) + if (l, abs(J)) not in lj_values: + lj_values.append((l, abs(J))) + + # Determine penetration and shift corresponding to resonance energy + k = wave_number(A, E) + rho = k*self.channel_radius[l](E) + rhohat = k*self.scattering_radius[l](E) + p[i], s[i] = penetration_shift(l, rho) + + df['p'] = p + df['s'] = s + + self._l_values = np.array(l_values) + for (l, J) in lj_values: + self._parameter_matrix[l, J] = df[(df.L == l) & + (abs(df.J) == J)].as_matrix() + + self._prepared = True + + +class RMatrixLimited(ResonanceRange): + """R-matrix limited resolved resonance formalism data. + + R-matrix limited resolved resonance data is identified by LRF=7 in the + ENDF-6 format. + + Parameters + ---------- + energy_min : float + Minimum energy of the resolved resonance range in eV + energy_max : float + Maximum energy of the resolved resonance range in eV + particle_pairs : list of dict + List of particle pairs. Each particle pair is represented by a + dictionary that contains the mass, atomic number, spin, and parity of + each particle as well as other characteristics. + spin_groups : list of dict + List of spin groups. Each spin group is characterized by channels, + resonance energies, and resonance widths. + + Attributes + ---------- + reduced_width : bool + Flag indicating whether channel widths in eV or reduced-width amplitudes + in eV^1/2 are given + formalism : int + Flag to specify which formulae for the R-matrix are to be used + particle_pairs : list of dict + List of particle pairs. Each particle pair is represented by a + dictionary that contains the mass, atomic number, spin, and parity of + each particle as well as other characteristics. + spin_groups : list of dict + List of spin groups. Each spin group is characterized by channels, + resonance energies, and resonance widths. + + """ + + def __init__(self, energy_min, energy_max, particle_pairs, spin_groups): + super(RMatrixLimited, self).__init__(0.0, energy_min, energy_max, + None, None) + self.reduced_width = False + self.formalism = 3 + self.particle_pairs = particle_pairs + self.spin_groups = spin_groups + + @classmethod + def from_endf(cls, ev, file_obj, items): + """Read R-Matrix limited resonance data from an ENDF evaluation. + + Parameters + ---------- + ev : openmc.data.endf.Evaluation + ENDF evaluation + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + + Returns + ------- + openmc.data.RMatrixLimited + R-matrix limited resonance parameters + + """ + energy_min, energy_max = items[0:2] + + items = get_cont_record(file_obj) + reduced_width = (items[2] == 1) # reduced width amplitude? + formalism = items[3] # Specify which formulae are used + n_spin_groups = items[4] # Number of Jpi values (NJS) + + particle_pairs = [] + spin_groups = [] + + items, values = get_list_record(file_obj) + n_pairs = items[5]//2 # Number of particle pairs (NPP) + for i in range(n_pairs): + first = {'mass': values[12*i], + 'z': int(values[12*i + 2]), + 'spin': values[12*i + 4], + 'parity': values[12*i + 10]} + second = {'mass': values[12*i + 1], + 'z': int(values[12*i + 3]), + 'spin': values[12*i + 5], + 'parity': values[12*i + 11]} + + q_value = values[12*i + 6] + penetrability = values[12*i + 7] + shift = values[12*i + 8] + mt = int(values[12*i + 9]) + + particle_pairs.append(ParticlePair( + first, second, q_value, penetrability, shift, mt)) + + # loop over spin groups + for i in range(n_spin_groups): + items, values = get_list_record(file_obj) + J = items[0] + if J == 0.0: + parity = '+' if items[1] == 1.0 else '-' + else: + parity = '+' if J > 0. else '-' + J = abs(J) + kbk = items[2] + kps = items[3] + n_channels = items[5] + channels = [] + for j in range(n_channels): + channel = {} + channel['particle_pair'] = particle_pairs[ + int(values[6*j]) - 1] + channel['l'] = values[6*j + 1] + channel['spin'] = values[6*j + 2] + channel['boundary'] = values[6*j + 3] + channel['effective_radius'] = values[6*j + 4] + channel['true_radius'] = values[6*j + 5] + channels.append(channel) + + # Read resonance energies and widths + items, values = get_list_record(file_obj) + n_resonances = items[3] + records = [] + m = n_channels//6 + 1 + for j in range(n_resonances): + energy = values[6*m*j] + records.append([energy] + [values[6*m*j + k + 1] + for k in range(n_channels)]) + + # Determine column names + columns = ['energy'] + for channel in channels: + mt = channel['particle_pair'].mt + if mt == 2: + columns.append('neutronWidth') + elif mt == 18: + columns.append('fissionWidth') + elif mt == 102: + columns.append('captureWidth') + else: + columns.append('width (MT={})'.format(mt)) + + # Create Pandas dataframe with resonance parameters + parameters = pd.DataFrame.from_records(records, columns=columns) + + # Construct SpinGroup instance and add to list + sg = SpinGroup(J, parity, channels, parameters) + spin_groups.append(sg) + + # Optional extension (Background R-Matrix) + if kbk > 0: + items, values = get_list_record(file_obj) + lbk = items[4] + if lbk == 1: + params, rbr = get_tab1_record(file_obj) + params, rbi = get_tab1_record(file_obj) + + # Optional extension (Tabulated phase shifts) + if kps > 0: + items, values = get_list_record(file_obj) + lps = items[4] + if lps == 1: + params, psr = get_tab1_record(file_obj) + params, psi = get_tab1_record(file_obj) + + rml = cls(energy_min, energy_max, particle_pairs, spin_groups) + rml.reduced_width = reduced_width + rml.formalism = formalism + + return rml + + +class ParticlePair(object): + def __init__(self, first, second, q_value, penetrability, + shift, mt): + self.first = first + self.second = second + self.q_value = q_value + self.penetrability = penetrability + self.shift = shift + self.mt = mt + + +class SpinGroup(object): + """Resonance spin group + + Attributes + ---------- + spin : float + Total angular momentum (nuclear spin) + parity : {'+', '-'} + Even (+) or odd(-) parity + channels : list of openmc.data.Channel + Available channels + parameters : pandas.DataFrame + Energies/widths for each resonance/channel + + """ + + def __init__(self, spin, parity, channels, parameters): + self.spin = spin + self.parity = parity + self.channels = channels + self.parameters = parameters + + def __repr__(self): + return ''.format(self.spin, self.parity) + + +class Unresolved(ResonanceRange): + """Unresolved resonance parameters as identified by LRU=2 in MF=2. + + Parameters + ---------- + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + energy_min : float + Minimum energy of the unresolved resonance range in eV + energy_max : float + Maximum energy of the unresolved resonance range in eV + scatter : openmc.data.Function1D + Scattering radii as a function of energy + + Attributes + ---------- + add_to_background : bool + If True, file 3 contains partial cross sections to be added to the + average unresolved cross sections calculated from parameters. + energies : Iterable of float + Energies at which parameters are tabulated + energy_max : float + Maximum energy of the unresolved resonance range in eV + energy_min : float + Minimum energy of the unresolved resonance range in eV + parameters : list of pandas.DataFrame + Average resonance parameters at each energy + scattering_radius : openmc.data.Function1D + Scattering radii as a function of energy + target_spin : float + Intrinsic spin, :math:`I`, of the target nuclide + + """ + + def __init__(self, target_spin, energy_min, energy_max, scatter): + super(Unresolved, self).__init__( + target_spin, energy_min, energy_max, None, scatter) + self.energies = None + self.parameters = None + self.add_to_background = False + + @classmethod + def from_endf(cls, file_obj, items, fission_widths): + """Read unresolved resonance data from an ENDF evaluation. + + Parameters + ---------- + file_obj : file-like object + ENDF file positioned at the second record of a resonance range + subsection in MF=2, MT=151 + items : list + Items from the CONT record at the start of the resonance range + subsection + fission_widths : bool + Whether fission widths are given + + Returns + ------- + openmc.data.Unresolved + Unresolved resonance region parameters + + """ + # Read energy-dependent scattering radius if present + energy_min, energy_max = items[0:2] + nro = items[4] + if nro != 0: + params, scattering_radius = get_tab1_record(file_obj) + + # Get SPI, AP, and LSSF + formalism = items[3] + if not (fission_widths and formalism == 1): + items = get_cont_record(file_obj) + target_spin = items[0] + if nro == 0: + scattering_radius = items[1] + add_to_background = (items[2] == 0) + + if not fission_widths and formalism == 1: + # Case A -- fission widths not given, all parameters are + # energy-independent + NLS = items[4] + columns = ['L', 'J', 'd', 'amun', 'gn', 'gg', 'gf'] + records = [] + for ls in range(NLS): + items, values = get_list_record(file_obj) + l = items[2] + NJS = items[5] + for j in range(NJS): + d, j, amun, gn, gg = values[6*j:6*j + 5] + records.append([l, j, d, amun, gn, gg, 0.0]) + parameters = pd.DataFrame.from_records(records, columns=columns) + energies = None + + elif fission_widths and formalism == 1: + # Case B -- fission widths given, only fission widths are + # energy-dependent + items, energies = get_list_record(file_obj) + target_spin = items[0] + if nro == 0: + scattering_radius = items[1] + add_to_background = (items[2] == 0) + NE, NLS = items[4:6] + l_values = np.zeros(NLS, int) + records = [[] for e in energies] + columns = ['L', 'J', 'd', 'amun', 'gn0', 'gg', 'gf'] + for ls in range(NLS): + items = get_cont_record(file_obj) + l = items[2] + NJS = items[4] + for j in range(NJS): + items, values = get_list_record(file_obj) + muf = items[3] + d = values[0] + j = values[1] + amun = values[2] + gn0 = values[3] + gg = values[4] + gf = values[6:] + for k, gf_i in enumerate(gf): + records[k].append([l, j, d, amun, gn0, gg, gf]) + parameters = [pd.DataFrame(r, columns=columns) for r in records] + + elif formalism == 2: + # Case C -- all parameters are energy-dependent + NLS = items[4] + columns = ['L', 'J', 'E', 'd', 'gx', 'gn0', 'gg', 'gf'] + records = [] + for ls in range(NLS): + items = get_cont_record(file_obj) + l = items[2] + NJS = items[4] + for j in range(NJS): + items, values = get_list_record(file_obj) + ne = items[5] + j = items[0] + amux = values[2] + amun = values[3] + amug = values[4] + amuf = values[5] + for k in range(1, ne + 1): + E = values[6*k] + d = values[6*k + 1] + gx = values[6*k + 2] + gn0 = values[6*k + 3] + gg = values[6*k + 4] + gf = values[6*k + 5] + records.append([l, j, E, d, gx, gn0, gg, gf]) + parameters = pd.DataFrame.from_records(records, columns=columns) + energies = None + + urr = cls(target_spin, energy_min, energy_max, scattering_radius) + urr.parameters = parameters + urr.add_to_background = add_to_background + urr.energies = energies + + return urr + + +_FORMALISMS = {0: ResonanceRange, + 1: SingleLevelBreitWigner, + 2: MultiLevelBreitWigner, + 3: ReichMoore, + 7: RMatrixLimited} + +_RESOLVED = (SingleLevelBreitWigner, MultiLevelBreitWigner, + ReichMoore, RMatrixLimited) diff --git a/setup.py b/setup.py index 4479bb82c5..52ffaecf49 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,12 @@ except ImportError: from distutils.core import setup have_setuptools = False +try: + from Cython.Build import cythonize + have_cython = True +except ImportError: + have_cython = False + kwargs = {'name': 'openmc', 'version': '0.8.0', 'packages': ['openmc', 'openmc.data', 'openmc.mgxs', 'openmc.model', @@ -48,4 +54,10 @@ if have_setuptools: }, }) +# If Cython is present, add resonance reconstruction capability +if have_cython: + kwargs.update({ + 'ext_modules': cythonize('openmc/data/reconstruct.pyx') + }) + setup(**kwargs) From 697dfb09c431f190ccebc7d7c307ce347c8c4474 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Thu, 15 Sep 2016 20:49:03 -0400 Subject: [PATCH 25/82] Merged with latest changes and added interpolation to the MG library --- src/mgxs_header.F90 | 420 +++++++++++------- .../results_true.dat | 14 +- .../results_true.dat | 14 +- tests/test_mgxs_library_hdf5/results_true.dat | 24 +- tests/test_mgxs_library_mesh/results_true.dat | 52 +-- .../results_true.dat | 26 +- 6 files changed, 321 insertions(+), 229 deletions(-) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 62a212f919..56fbb5965f 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -94,7 +94,7 @@ module mgxs_header integer(HID_T), intent(in) :: xs_id ! Library data integer, intent(in) :: groups ! Number of Energy groups type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(in) :: method ! Type of temperature access + integer, intent(inout) :: method ! Type of temperature access real(8), intent(in) :: tolerance ! Tolerance on method logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? @@ -206,7 +206,7 @@ module mgxs_header class(Mgxs), intent(inout) :: this ! Working Object integer(HID_T), intent(in) :: xs_id ! Group in H5 file type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(in) :: method ! Type of temperature access + integer, intent(inout) :: method ! Type of temperature access real(8), intent(in) :: tolerance ! Tolerance on method type(VectorInt), intent(out) :: temps_to_read ! Temperatures to read integer, intent(out) :: order_dim ! Scattering data order size @@ -244,6 +244,16 @@ module mgxs_header ! Convert MeV to Kelvin temps_available(i) = temps_available(i) / K_BOLTZMANN end do + call sort(temps_available) + + ! If only one temperature is available, revert to nearest temperature + if (size(temps_available) == 1 .and. & + method == TEMPERATURE_INTERPOLATION) then + call warning("Cross sections for " // trim(this % name) // " are only & + &available at one temperature. Reverting to nearest temperature & + &method.") + method = TEMPERATURE_NEAREST + end if select case (method) case (TEMPERATURE_NEAREST) @@ -264,8 +274,28 @@ module mgxs_header end do TEMP_LOOP case (TEMPERATURE_INTERPOLATION) - ! TODO: Get bounding temperatures - call fatal_error("Temperature interpolation not yet implemented") + ! If temperature interpolation or multipole is selected, get a list of + ! bounding temperatures for each actual temperature present in the model + TEMPS_LOOP: do i = 1, temperature % size() + temp_desired = temperature % data(i) + + do j = 1, size(temps_available) - 1 + if (temps_available(j) <= temp_desired .and. & + temp_desired < temps_available(j + 1)) then + if (find(temps_to_read, nint(temps_available(j))) == -1) then + call temps_to_read % push_back(nint(temps_available(j))) + end if + if (find(temps_to_read, nint(temps_available(j + 1))) == -1) then + call temps_to_read % push_back(nint(temps_available(j + 1))) + end if + cycle TEMPS_LOOP + end if + end do + + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired))) // " K.") + end do TEMPS_LOOP end select ! Sort temperatures to read @@ -369,7 +399,7 @@ module mgxs_header integer(HID_T), intent(in) :: xs_id ! Group in H5 file integer, intent(in) :: groups ! Number of Energy groups type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(in) :: method ! Type of temperature access + integer, intent(inout) :: method ! Type of temperature access real(8), intent(in) :: tolerance ! Tolerance on method logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? @@ -660,7 +690,7 @@ module mgxs_header integer(HID_T), intent(in) :: xs_id ! Group in H5 file integer, intent(in) :: groups ! Number of Energy groups type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(in) :: method ! Type of temperature access + integer, intent(inout) :: method ! Type of temperature access real(8), intent(in) :: tolerance ! Tolerance on method logical, intent(in) :: get_kfiss ! Need Kappa-Fission? logical, intent(in) :: get_fiss ! Should we get fiss data? @@ -1196,7 +1226,8 @@ module mgxs_header real(8), allocatable :: temp_mult(:, :), mult_num(:, :), mult_denom(:, :) real(8), allocatable :: scatt_coeffs(:, :, :) integer :: nuc_t - real(8) :: temp_actual, temp_desired + integer, allocatable :: nuc_ts(:) + real(8) :: temp_actual, temp_desired, interp integer :: scatter_type type(Jagged2D), allocatable :: nuc_matrix(:) integer, allocatable :: gmin(:), gmax(:) @@ -1243,12 +1274,16 @@ module mgxs_header ! Add contribution from each nuclide in material NUC_LOOP: do i = 1, mat % n_nuclides associate(nuc => nuclides(mat % nuclide(i)) % obj) + ! Copy atom density of nuclide in material + atom_density = mat % atom_density(i) + select case (method) case (TEMPERATURE_NEAREST) ! Determine actual temperatures to read temp_desired = temps % data(i) - nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(nuc_t) + allocate(nuc_ts(1)) + nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(nuc_ts(1)) if (abs(temp_actual - temp_desired) >= tolerance) then call fatal_error("MGXS library does not contain cross sections & &for " // trim(this % name) // " at or near " // & @@ -1256,80 +1291,106 @@ module mgxs_header end if case (TEMPERATURE_INTERPOLATION) - ! TODO: Get bounding temperatures - call fatal_error("Temperature interpolation not yet implemented") - end select + ! If temperature interpolation or multipole is selected, get a + ! list of bounding temperatures for each actual temperature + ! present in the model + temp_desired = temps % data(i) + allocate(nuc_ts(2)) + do j = 1, size(nuc % kTs) - 1 + if (nuc % kTs(j) <= temp_desired .and. & + temp_desired < nuc % kTs(j + 1)) then + nuc_ts(1) = j + nuc_ts(2) = j + 1 + end if + end do - ! Copy atom density of nuclide in material - atom_density = mat % atom_density(i) + call fatal_error("Nuclear data library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired))) // " K.") + end select select type(nuc) type is (MgxsIso) - ! Perform our operations which depend upon the type - ! Add contributions to total, absorption, and fission data (if necessary) - this % xs(t) % total = this % xs(t) % total + & - atom_density * nuc % xs(nuc_t) % total - this % xs(t) % absorption = this % xs(t) % absorption + & - atom_density * nuc % xs(nuc_t) % absorption - if (nuc % fissionable) then - this % xs(t) % chi = this % xs(t) % chi + & - atom_density * nuc % xs(nuc_t) % chi - this % xs(t) % nu_fission = this % xs(t) % nu_fission + & - atom_density * nuc % xs(nuc_t) % nu_fission - if (allocated(nuc % xs(nuc_t) % fission)) then - this % xs(t) % fission = this % xs(t) % fission + & - atom_density * nuc % xs(nuc_t) % fission + do j = 1, size(nuc_ts) + nuc_t = nuc_ts(j) + if (size(nuc_ts) == 1) then + interp = ONE + else if (j == 1) then + interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & + (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) + else + interp = ONE - interp end if - if (allocated(nuc % xs(nuc_t) % k_fission)) then - this % xs(t) % k_fission = this % xs(t) % k_fission + & - atom_density * nuc % xs(nuc_t) % k_fission - end if - end if - ! We will next gather the multiplicaity and scattering matrices. - ! To avoid multiple re-allocations as we resize the storage - ! matrix (and/or to avoidlots of duplicate code), we will use a - ! dense matrix for this storage, with a reduction to the sparse - ! format at the end. - - ! Get the multiplicity matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do gin = 1, groups - do gout = nuc % xs(nuc_t) % scatter % gmin(gin), nuc % xs(nuc_t) % scatter % gmax(gin) - nuscatt = nuc % xs(nuc_t) % scatter % scattxs(gin) * & - nuc % xs(nuc_t) % scatter % energy(gin) % data(gout) - mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & - nuscatt - if (nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & - nuscatt / nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data (if necessary) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total * interp + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption * interp + if (nuc % fissionable) then + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi * interp + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission * interp + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission * interp end if - end do - end do + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission * interp + end if + end if - ! Get the complete scattering matrix - nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) - nuc_order_dim = min(nuc_order_dim, order_dim) - call nuc % xs(nuc_t) % scatter % get_matrix(nuc_order_dim, & - nuc_matrix) - do gin = 1, groups - do gout = nuc % xs(nuc_t) % scatter % gmin(gin), & - nuc % xs(nuc_t) % scatter % gmax(gin) - scatt_coeffs(1:nuc_order_dim, gout, gin) = & - scatt_coeffs(1: nuc_order_dim, gout, gin) + & - atom_density * nuc_matrix(gin) % data(1:nuc_order_dim, gout) + ! We will next gather the multiplicaity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. + + ! Get the multiplicity matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), nuc % xs(nuc_t) % scatter % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter % scattxs(gin) * & + nuc % xs(nuc_t) % scatter % energy(gin) % data(gout) + mult_num(gout, gin) = mult_num(gout, gin) + atom_density * & + nuscatt * interp + if (nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) > ZERO) then + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & + nuscatt / nuc % xs(nuc_t) % scatter % mult(gin) % data(gout) * & + interp + else + ! Avoid division by zero + mult_denom(gout, gin) = mult_denom(gout,gin) + atom_density * & + interp + end if + end do + end do + + ! Get the complete scattering matrix + nuc_order_dim = size(nuc % xs(nuc_t) % scatter % dist(1) % data, dim=1) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter % get_matrix(nuc_order_dim, & + nuc_matrix) + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter % gmin(gin), & + nuc % xs(nuc_t) % scatter % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin) = & + scatt_coeffs(1: nuc_order_dim, gout, gin) + & + atom_density * interp * & + nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do end do end do @@ -1396,7 +1457,8 @@ module mgxs_header real(8), allocatable :: temp_mult(:, :, :, :), mult_num(:, :, :, :) real(8), allocatable :: mult_denom(:, :, :, :), scatt_coeffs(:, :, :, :, :) integer :: nuc_t - real(8) :: temp_actual, temp_desired + integer, allocatable :: nuc_ts(:) + real(8) :: temp_actual, temp_desired, interp integer :: scatter_type type(Jagged2D), allocatable :: nuc_matrix(:) integer, allocatable :: gmin(:), gmax(:) @@ -1472,107 +1534,137 @@ module mgxs_header ! Add contribution from each nuclide in material NUC_LOOP: do i = 1, mat % n_nuclides associate(nuc => nuclides(mat % nuclide(i)) % obj) - select case (method) - case (TEMPERATURE_NEAREST) - ! Determine actual temperatures to read - temp_desired = temps % data(i) - nuc_t = minloc(abs(nuc % kTs - temp_desired), dim=1) - temp_actual = nuc % kTs(nuc_t) - if (abs(temp_actual - temp_desired) >= tolerance) then - call fatal_error("MGXS library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") - end if - case (TEMPERATURE_INTERPOLATION) - ! TODO: Get bounding temperatures - call fatal_error("Temperature interpolation not yet implemented") - end select + select case (method) + case (TEMPERATURE_NEAREST) + ! Determine actual temperatures to read + temp_desired = temps % data(i) + allocate(nuc_ts(1)) + nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) + temp_actual = nuc % kTs(nuc_ts(1)) + if (abs(temp_actual - temp_desired) >= tolerance) then + call fatal_error("MGXS library does not contain cross sections & + &for " // trim(this % name) // " at or near " // & + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") + end if + + case (TEMPERATURE_INTERPOLATION) + ! If temperature interpolation or multipole is selected, get a + ! list of bounding temperatures for each actual temperature + ! present in the model + temp_desired = temps % data(i) + allocate(nuc_ts(2)) + do j = 1, size(nuc % kTs) - 1 + if (nuc % kTs(j) <= temp_desired .and. & + temp_desired < nuc % kTs(j + 1)) then + nuc_ts(1) = j + nuc_ts(2) = j + 1 + end if + end do + + call fatal_error("Nuclear data library does not contain cross sections & + &for " // trim(this % name) // " at temperatures that bound " // & + trim(to_str(nint(temp_desired))) // " K.") + end select ! Copy atom density of nuclide in material atom_density = mat % atom_density(i) select type(nuc) type is (MgxsAngle) - ! Perform our operations which depend upon the type - ! Add contributions to total, absorption, and fission data (if necessary) - this % xs(t) % total = this % xs(t) % total + & - atom_density * nuc % xs(nuc_t) % total - this % xs(t) % absorption = this % xs(t) % absorption + & - atom_density * nuc % xs(nuc_t) % absorption - if (nuc % fissionable) then - this % xs(t) % chi = this % xs(t) % chi + & - atom_density * nuc % xs(nuc_t) % chi - this % xs(t) % nu_fission = this % xs(t) % nu_fission + & - atom_density * nuc % xs(nuc_t) % nu_fission - if (allocated(nuc % xs(nuc_t) % fission)) then - this % xs(t) % fission = this % xs(t) % fission + & - atom_density * nuc % xs(nuc_t) % fission + do j = 1, size(nuc_ts) + nuc_t = nuc_ts(j) + if (size(nuc_ts) == 1) then + interp = ONE + else if (j == 1) then + interp = (ONE - (temp_desired - nuc % kTs(nuc_ts(1))) / & + (nuc % kTs(nuc_ts(2)) - nuc % kTs(nuc_ts(1)))) + else + interp = ONE - interp end if - if (allocated(nuc % xs(nuc_t) % k_fission)) then - this % xs(t) % k_fission = this % xs(t) % k_fission + & - atom_density * nuc % xs(nuc_t) % k_fission + ! Perform our operations which depend upon the type + ! Add contributions to total, absorption, and fission data + ! (if necessary) + this % xs(t) % total = this % xs(t) % total + & + atom_density * nuc % xs(nuc_t) % total * interp + this % xs(t) % absorption = this % xs(t) % absorption + & + atom_density * nuc % xs(nuc_t) % absorption * interp + if (nuc % fissionable) then + this % xs(t) % chi = this % xs(t) % chi + & + atom_density * nuc % xs(nuc_t) % chi * interp + this % xs(t) % nu_fission = this % xs(t) % nu_fission + & + atom_density * nuc % xs(nuc_t) % nu_fission * interp + if (allocated(nuc % xs(nuc_t) % fission)) then + this % xs(t) % fission = this % xs(t) % fission + & + atom_density * nuc % xs(nuc_t) % fission * interp + end if + if (allocated(nuc % xs(nuc_t) % k_fission)) then + this % xs(t) % k_fission = this % xs(t) % k_fission + & + atom_density * nuc % xs(nuc_t) % k_fission * interp + end if end if - end if - ! We will next gather the multiplicaity and scattering matrices. - ! To avoid multiple re-allocations as we resize the storage - ! matrix (and/or to avoidlots of duplicate code), we will use a - ! dense matrix for this storage, with a reduction to the sparse - ! format at the end. + ! We will next gather the multiplicaity and scattering matrices. + ! To avoid multiple re-allocations as we resize the storage + ! matrix (and/or to avoidlots of duplicate code), we will use a + ! dense matrix for this storage, with a reduction to the sparse + ! format at the end. - ! Get the multiplicity matrix - ! To combine from nuclidic data we need to use the final relationship - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! Developed as follows: - ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) - ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / - ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) - ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and - ! scatter % scattxs - do ipol = 1, n_pol - do iazi = 1, n_azi - do gin = 1, groups - do gout = nuc % xs(nuc_t) % scatter(iazi, ipol) %obj % gmin(gin), & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) - nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) - mult_num(gout, gin, iazi, ipol) = & - mult_num(gout, gin, iazi, ipol) + atom_density * & - nuscatt - if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + atom_density * & - nuscatt / & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) - else - ! Avoid division by zero - mult_denom(gout, gin, iazi, ipol) = & - mult_denom(gout, gin, iazi, ipol) + atom_density - end if + ! Get the multiplicity matrix + ! To combine from nuclidic data we need to use the final relationship + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! Developed as follows: + ! mult_{gg'} = nuScatt{g,g'} / Scatt{g,g'} + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / sum(N_i*scatt_{i,g,g'}) + ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / + ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) + ! nuscatt_{i,g,g'} can be reconstructed from scatter % energy and + ! scatter % scattxs + do ipol = 1, n_pol + do iazi = 1, n_azi + do gin = 1, groups + do gout = nuc % xs(nuc_t) % scatter(iazi, ipol) %obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + nuscatt = nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % scattxs(gin) * & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % energy(gin) % data(gout) + mult_num(gout, gin, iazi, ipol) = & + mult_num(gout, gin, iazi, ipol) + atom_density * & + nuscatt * interp + if (nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) > ZERO) then + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density * & + interp * nuscatt / & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % mult(gin) % data(gout) + else + ! Avoid division by zero + mult_denom(gout, gin, iazi, ipol) = & + mult_denom(gout, gin, iazi, ipol) + atom_density * & + interp + end if + end do end do - end do - ! Get the complete scattering matrix - nuc_order_dim = & - size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & - dist(1) % data, dim=1) - nuc_order_dim = min(nuc_order_dim, order_dim) - call nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & - get_matrix(nuc_order_dim, nuc_matrix) - do gin = 1, groups - do gout = & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmin(gin), & - nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) - scatt_coeffs(1:nuc_order_dim, gout, gin, iazi, ipol) = & - scatt_coeffs(1: nuc_order_dim, gout, gin, iazi, ipol) + & - atom_density * nuc_matrix(gin) % data(1:nuc_order_dim, gout) - end do ! gout - end do ! gin - end do ! iazi - end do ! ipol + ! Get the complete scattering matrix + nuc_order_dim = & + size(nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + dist(1) % data, dim=1) + nuc_order_dim = min(nuc_order_dim, order_dim) + call nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % & + get_matrix(nuc_order_dim, nuc_matrix) + do gin = 1, groups + do gout = & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmin(gin), & + nuc % xs(nuc_t) % scatter(iazi, ipol) % obj % gmax(gin) + scatt_coeffs(1:nuc_order_dim, gout, gin, iazi, ipol) = & + scatt_coeffs(1: nuc_order_dim, gout, gin, iazi, ipol) + & + atom_density * interp * & + nuc_matrix(gin) % data(1:nuc_order_dim, gout) + end do ! gout + end do ! gin + end do ! iazi + end do ! ipol + end do type is (MgxsIso) call fatal_error("Invalid passing of MgxsIso to MgxsAngle object") end select diff --git a/tests/test_mgxs_library_condense/results_true.dat b/tests/test_mgxs_library_condense/results_true.dat index cd84d0a3ac..5b02ce3dbc 100644 --- a/tests/test_mgxs_library_condense/results_true.dat +++ b/tests/test_mgxs_library_condense/results_true.dat @@ -61,13 +61,13 @@ 3 10000 4 1 total 0.002752 0.000240 4 10000 5 1 total 0.001231 0.000105 5 10000 6 1 total 0.000512 0.000044 - material delayedgroup group in nuclide mean std. dev. -0 10000 1 1 total 0.000000 0.000000 -1 10000 2 1 total 0.032739 0.028454 -2 10000 3 1 total 0.120780 0.170809 -3 10000 4 1 total 0.302780 0.109110 -4 10000 5 1 total 0.000000 0.000000 -5 10000 6 1 total 0.000000 0.000000 + material delayedgroup group in nuclide mean std. dev. +0 10000 1 1 total 0.000000e+00 0.000000e+00 +1 10000 2 1 total 3.273900e-10 2.845437e-10 +2 10000 3 1 total 1.207800e-09 1.708087e-09 +3 10000 4 1 total 3.027800e-09 1.091095e-09 +4 10000 5 1 total 0.000000e+00 0.000000e+00 +5 10000 6 1 total 0.000000e+00 0.000000e+00 material group in nuclide mean std. dev. 0 10001 1 total 0.311594 0.013793 material group in nuclide mean std. dev. diff --git a/tests/test_mgxs_library_distribcell/results_true.dat b/tests/test_mgxs_library_distribcell/results_true.dat index 87f18db1c7..dba6ae60de 100644 --- a/tests/test_mgxs_library_distribcell/results_true.dat +++ b/tests/test_mgxs_library_distribcell/results_true.dat @@ -61,10 +61,10 @@ 3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.002727 0.000135 4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.001210 0.000058 5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 0.000504 0.000024 - avg(distribcell) delayedgroup group in nuclide mean std. dev. -0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 1 1 total 0.000000 0.000000 -1 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 2 1 total 0.032739 0.046300 -2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 3 1 total 0.120780 0.170809 -3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.000000 0.000000 -4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.000000 0.000000 -5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 2.853000 4.034751 + avg(distribcell) delayedgroup group in nuclide mean std. dev. +0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 1 1 total 0.000000e+00 0.000000e+00 +1 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 2 1 total 3.273900e-10 4.629994e-10 +2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 3 1 total 1.207800e-09 1.708087e-09 +3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.000000e+00 0.000000e+00 +4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.000000e+00 0.000000e+00 +5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 2.853000e-08 4.034751e-08 diff --git a/tests/test_mgxs_library_hdf5/results_true.dat b/tests/test_mgxs_library_hdf5/results_true.dat index 8cec5c6299..0e57dbaf3a 100644 --- a/tests/test_mgxs_library_hdf5/results_true.dat +++ b/tests/test_mgxs_library_hdf5/results_true.dat @@ -112,18 +112,18 @@ domain=10000 type=beta [ 1.82980497e-04 4.50738567e-04] [ 7.48899920e-05 1.88812772e-04]] domain=10000 type=decay-rate -[[ 0. 0. ] - [ 0. 0.032739] - [ 0. 0.12078 ] - [ 0. 0.30278 ] - [ 0. 0. ] - [ 0. 0. ]] -[[ 0. 0. ] - [ 0. 0.02845437] - [ 0. 0.17080871] - [ 0. 0.10910951] - [ 0. 0. ] - [ 0. 0. ]] +[[ 0.00000000e+00 0.00000000e+00] + [ 0.00000000e+00 3.27390000e-10] + [ 0.00000000e+00 1.20780000e-09] + [ 0.00000000e+00 3.02780000e-09] + [ 0.00000000e+00 0.00000000e+00] + [ 0.00000000e+00 0.00000000e+00]] +[[ 0.00000000e+00 0.00000000e+00] + [ 0.00000000e+00 2.84543737e-10] + [ 0.00000000e+00 1.70808714e-09] + [ 0.00000000e+00 1.09109511e-09] + [ 0.00000000e+00 0.00000000e+00] + [ 0.00000000e+00 0.00000000e+00]] domain=10001 type=total [ 0.31373767 0.3008214 ] [ 0.0155819 0.02805245] diff --git a/tests/test_mgxs_library_mesh/results_true.dat b/tests/test_mgxs_library_mesh/results_true.dat index 8ad0f2eee1..bf34b196d2 100644 --- a/tests/test_mgxs_library_mesh/results_true.dat +++ b/tests/test_mgxs_library_mesh/results_true.dat @@ -208,29 +208,29 @@ 21 2 2 1 4 1 total 0.002143 0.001028 22 2 2 1 5 1 total 0.001026 0.000492 23 2 2 1 6 1 total 0.000408 0.000196 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y z -0 1 1 1 1 1 total 0.00000 0.000000 -1 1 1 1 2 1 total 0.00000 0.000000 -2 1 1 1 3 1 total 0.00000 0.000000 -3 1 1 1 4 1 total 0.30278 0.428196 -4 1 1 1 5 1 total 0.00000 0.000000 -5 1 1 1 6 1 total 0.00000 0.000000 -6 1 2 1 1 1 total 0.00000 0.000000 -7 1 2 1 2 1 total 0.00000 0.000000 -8 1 2 1 3 1 total 0.00000 0.000000 -9 1 2 1 4 1 total 0.00000 0.000000 -10 1 2 1 5 1 total 0.00000 0.000000 -11 1 2 1 6 1 total 0.00000 0.000000 -12 2 1 1 1 1 total 0.00000 0.000000 -13 2 1 1 2 1 total 0.00000 0.000000 -14 2 1 1 3 1 total 0.00000 0.000000 -15 2 1 1 4 1 total 0.00000 0.000000 -16 2 1 1 5 1 total 0.00000 0.000000 -17 2 1 1 6 1 total 0.00000 0.000000 -18 2 2 1 1 1 total 0.00000 0.000000 -19 2 2 1 2 1 total 0.00000 0.000000 -20 2 2 1 3 1 total 0.00000 0.000000 -21 2 2 1 4 1 total 0.00000 0.000000 -22 2 2 1 5 1 total 0.00000 0.000000 -23 2 2 1 6 1 total 0.00000 0.000000 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.000000e+00 0.000000e+00 +1 1 1 1 2 1 total 0.000000e+00 0.000000e+00 +2 1 1 1 3 1 total 0.000000e+00 0.000000e+00 +3 1 1 1 4 1 total 3.027800e-09 4.281956e-09 +4 1 1 1 5 1 total 0.000000e+00 0.000000e+00 +5 1 1 1 6 1 total 0.000000e+00 0.000000e+00 +6 1 2 1 1 1 total 0.000000e+00 0.000000e+00 +7 1 2 1 2 1 total 0.000000e+00 0.000000e+00 +8 1 2 1 3 1 total 0.000000e+00 0.000000e+00 +9 1 2 1 4 1 total 0.000000e+00 0.000000e+00 +10 1 2 1 5 1 total 0.000000e+00 0.000000e+00 +11 1 2 1 6 1 total 0.000000e+00 0.000000e+00 +12 2 1 1 1 1 total 0.000000e+00 0.000000e+00 +13 2 1 1 2 1 total 0.000000e+00 0.000000e+00 +14 2 1 1 3 1 total 0.000000e+00 0.000000e+00 +15 2 1 1 4 1 total 0.000000e+00 0.000000e+00 +16 2 1 1 5 1 total 0.000000e+00 0.000000e+00 +17 2 1 1 6 1 total 0.000000e+00 0.000000e+00 +18 2 2 1 1 1 total 0.000000e+00 0.000000e+00 +19 2 2 1 2 1 total 0.000000e+00 0.000000e+00 +20 2 2 1 3 1 total 0.000000e+00 0.000000e+00 +21 2 2 1 4 1 total 0.000000e+00 0.000000e+00 +22 2 2 1 5 1 total 0.000000e+00 0.000000e+00 +23 2 2 1 6 1 total 0.000000e+00 0.000000e+00 diff --git a/tests/test_mgxs_library_no_nuclides/results_true.dat b/tests/test_mgxs_library_no_nuclides/results_true.dat index 961ae9ba9f..e4e5620328 100644 --- a/tests/test_mgxs_library_no_nuclides/results_true.dat +++ b/tests/test_mgxs_library_no_nuclides/results_true.dat @@ -123,19 +123,19 @@ 6 10000 4 2 total 0.011426 0.001099 8 10000 5 2 total 0.004684 0.000451 10 10000 6 2 total 0.001962 0.000189 - material delayedgroup group in nuclide mean std. dev. -1 10000 1 1 total 0.000000 0.000000 -3 10000 2 1 total 0.000000 0.000000 -5 10000 3 1 total 0.000000 0.000000 -7 10000 4 1 total 0.000000 0.000000 -9 10000 5 1 total 0.000000 0.000000 -11 10000 6 1 total 0.000000 0.000000 -0 10000 1 2 total 0.000000 0.000000 -2 10000 2 2 total 0.032739 0.028454 -4 10000 3 2 total 0.120780 0.170809 -6 10000 4 2 total 0.302780 0.109110 -8 10000 5 2 total 0.000000 0.000000 -10 10000 6 2 total 0.000000 0.000000 + material delayedgroup group in nuclide mean std. dev. +1 10000 1 1 total 0.000000e+00 0.000000e+00 +3 10000 2 1 total 0.000000e+00 0.000000e+00 +5 10000 3 1 total 0.000000e+00 0.000000e+00 +7 10000 4 1 total 0.000000e+00 0.000000e+00 +9 10000 5 1 total 0.000000e+00 0.000000e+00 +11 10000 6 1 total 0.000000e+00 0.000000e+00 +0 10000 1 2 total 0.000000e+00 0.000000e+00 +2 10000 2 2 total 3.273900e-10 2.845437e-10 +4 10000 3 2 total 1.207800e-09 1.708087e-09 +6 10000 4 2 total 3.027800e-09 1.091095e-09 +8 10000 5 2 total 0.000000e+00 0.000000e+00 +10 10000 6 2 total 0.000000e+00 0.000000e+00 material group in nuclide mean std. dev. 1 10001 1 total 0.313738 0.015582 0 10001 2 total 0.300821 0.028052 From 1c3d1a38da18e6234463b34577d4834ef26dd7da Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sun, 18 Sep 2016 12:39:50 -0400 Subject: [PATCH 26/82] Updated results after I realized I needed new NNDC data for the shakes to seconds thing --- .../results_true.dat | 14 ++--- .../results_true.dat | 14 ++--- tests/test_mgxs_library_hdf5/results_true.dat | 24 ++++----- tests/test_mgxs_library_mesh/results_true.dat | 52 +++++++++---------- .../results_true.dat | 26 +++++----- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/tests/test_mgxs_library_condense/results_true.dat b/tests/test_mgxs_library_condense/results_true.dat index 5b02ce3dbc..cd84d0a3ac 100644 --- a/tests/test_mgxs_library_condense/results_true.dat +++ b/tests/test_mgxs_library_condense/results_true.dat @@ -61,13 +61,13 @@ 3 10000 4 1 total 0.002752 0.000240 4 10000 5 1 total 0.001231 0.000105 5 10000 6 1 total 0.000512 0.000044 - material delayedgroup group in nuclide mean std. dev. -0 10000 1 1 total 0.000000e+00 0.000000e+00 -1 10000 2 1 total 3.273900e-10 2.845437e-10 -2 10000 3 1 total 1.207800e-09 1.708087e-09 -3 10000 4 1 total 3.027800e-09 1.091095e-09 -4 10000 5 1 total 0.000000e+00 0.000000e+00 -5 10000 6 1 total 0.000000e+00 0.000000e+00 + material delayedgroup group in nuclide mean std. dev. +0 10000 1 1 total 0.000000 0.000000 +1 10000 2 1 total 0.032739 0.028454 +2 10000 3 1 total 0.120780 0.170809 +3 10000 4 1 total 0.302780 0.109110 +4 10000 5 1 total 0.000000 0.000000 +5 10000 6 1 total 0.000000 0.000000 material group in nuclide mean std. dev. 0 10001 1 total 0.311594 0.013793 material group in nuclide mean std. dev. diff --git a/tests/test_mgxs_library_distribcell/results_true.dat b/tests/test_mgxs_library_distribcell/results_true.dat index dba6ae60de..87f18db1c7 100644 --- a/tests/test_mgxs_library_distribcell/results_true.dat +++ b/tests/test_mgxs_library_distribcell/results_true.dat @@ -61,10 +61,10 @@ 3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.002727 0.000135 4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.001210 0.000058 5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 0.000504 0.000024 - avg(distribcell) delayedgroup group in nuclide mean std. dev. -0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 1 1 total 0.000000e+00 0.000000e+00 -1 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 2 1 total 3.273900e-10 4.629994e-10 -2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 3 1 total 1.207800e-09 1.708087e-09 -3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.000000e+00 0.000000e+00 -4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.000000e+00 0.000000e+00 -5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 2.853000e-08 4.034751e-08 + avg(distribcell) delayedgroup group in nuclide mean std. dev. +0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 1 1 total 0.000000 0.000000 +1 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 2 1 total 0.032739 0.046300 +2 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 3 1 total 0.120780 0.170809 +3 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 4 1 total 0.000000 0.000000 +4 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 5 1 total 0.000000 0.000000 +5 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,... 6 1 total 2.853000 4.034751 diff --git a/tests/test_mgxs_library_hdf5/results_true.dat b/tests/test_mgxs_library_hdf5/results_true.dat index 0e57dbaf3a..8cec5c6299 100644 --- a/tests/test_mgxs_library_hdf5/results_true.dat +++ b/tests/test_mgxs_library_hdf5/results_true.dat @@ -112,18 +112,18 @@ domain=10000 type=beta [ 1.82980497e-04 4.50738567e-04] [ 7.48899920e-05 1.88812772e-04]] domain=10000 type=decay-rate -[[ 0.00000000e+00 0.00000000e+00] - [ 0.00000000e+00 3.27390000e-10] - [ 0.00000000e+00 1.20780000e-09] - [ 0.00000000e+00 3.02780000e-09] - [ 0.00000000e+00 0.00000000e+00] - [ 0.00000000e+00 0.00000000e+00]] -[[ 0.00000000e+00 0.00000000e+00] - [ 0.00000000e+00 2.84543737e-10] - [ 0.00000000e+00 1.70808714e-09] - [ 0.00000000e+00 1.09109511e-09] - [ 0.00000000e+00 0.00000000e+00] - [ 0.00000000e+00 0.00000000e+00]] +[[ 0. 0. ] + [ 0. 0.032739] + [ 0. 0.12078 ] + [ 0. 0.30278 ] + [ 0. 0. ] + [ 0. 0. ]] +[[ 0. 0. ] + [ 0. 0.02845437] + [ 0. 0.17080871] + [ 0. 0.10910951] + [ 0. 0. ] + [ 0. 0. ]] domain=10001 type=total [ 0.31373767 0.3008214 ] [ 0.0155819 0.02805245] diff --git a/tests/test_mgxs_library_mesh/results_true.dat b/tests/test_mgxs_library_mesh/results_true.dat index bf34b196d2..8ad0f2eee1 100644 --- a/tests/test_mgxs_library_mesh/results_true.dat +++ b/tests/test_mgxs_library_mesh/results_true.dat @@ -208,29 +208,29 @@ 21 2 2 1 4 1 total 0.002143 0.001028 22 2 2 1 5 1 total 0.001026 0.000492 23 2 2 1 6 1 total 0.000408 0.000196 - mesh 1 delayedgroup group in nuclide mean std. dev. - x y z -0 1 1 1 1 1 total 0.000000e+00 0.000000e+00 -1 1 1 1 2 1 total 0.000000e+00 0.000000e+00 -2 1 1 1 3 1 total 0.000000e+00 0.000000e+00 -3 1 1 1 4 1 total 3.027800e-09 4.281956e-09 -4 1 1 1 5 1 total 0.000000e+00 0.000000e+00 -5 1 1 1 6 1 total 0.000000e+00 0.000000e+00 -6 1 2 1 1 1 total 0.000000e+00 0.000000e+00 -7 1 2 1 2 1 total 0.000000e+00 0.000000e+00 -8 1 2 1 3 1 total 0.000000e+00 0.000000e+00 -9 1 2 1 4 1 total 0.000000e+00 0.000000e+00 -10 1 2 1 5 1 total 0.000000e+00 0.000000e+00 -11 1 2 1 6 1 total 0.000000e+00 0.000000e+00 -12 2 1 1 1 1 total 0.000000e+00 0.000000e+00 -13 2 1 1 2 1 total 0.000000e+00 0.000000e+00 -14 2 1 1 3 1 total 0.000000e+00 0.000000e+00 -15 2 1 1 4 1 total 0.000000e+00 0.000000e+00 -16 2 1 1 5 1 total 0.000000e+00 0.000000e+00 -17 2 1 1 6 1 total 0.000000e+00 0.000000e+00 -18 2 2 1 1 1 total 0.000000e+00 0.000000e+00 -19 2 2 1 2 1 total 0.000000e+00 0.000000e+00 -20 2 2 1 3 1 total 0.000000e+00 0.000000e+00 -21 2 2 1 4 1 total 0.000000e+00 0.000000e+00 -22 2 2 1 5 1 total 0.000000e+00 0.000000e+00 -23 2 2 1 6 1 total 0.000000e+00 0.000000e+00 + mesh 1 delayedgroup group in nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 0.00000 0.000000 +1 1 1 1 2 1 total 0.00000 0.000000 +2 1 1 1 3 1 total 0.00000 0.000000 +3 1 1 1 4 1 total 0.30278 0.428196 +4 1 1 1 5 1 total 0.00000 0.000000 +5 1 1 1 6 1 total 0.00000 0.000000 +6 1 2 1 1 1 total 0.00000 0.000000 +7 1 2 1 2 1 total 0.00000 0.000000 +8 1 2 1 3 1 total 0.00000 0.000000 +9 1 2 1 4 1 total 0.00000 0.000000 +10 1 2 1 5 1 total 0.00000 0.000000 +11 1 2 1 6 1 total 0.00000 0.000000 +12 2 1 1 1 1 total 0.00000 0.000000 +13 2 1 1 2 1 total 0.00000 0.000000 +14 2 1 1 3 1 total 0.00000 0.000000 +15 2 1 1 4 1 total 0.00000 0.000000 +16 2 1 1 5 1 total 0.00000 0.000000 +17 2 1 1 6 1 total 0.00000 0.000000 +18 2 2 1 1 1 total 0.00000 0.000000 +19 2 2 1 2 1 total 0.00000 0.000000 +20 2 2 1 3 1 total 0.00000 0.000000 +21 2 2 1 4 1 total 0.00000 0.000000 +22 2 2 1 5 1 total 0.00000 0.000000 +23 2 2 1 6 1 total 0.00000 0.000000 diff --git a/tests/test_mgxs_library_no_nuclides/results_true.dat b/tests/test_mgxs_library_no_nuclides/results_true.dat index e4e5620328..961ae9ba9f 100644 --- a/tests/test_mgxs_library_no_nuclides/results_true.dat +++ b/tests/test_mgxs_library_no_nuclides/results_true.dat @@ -123,19 +123,19 @@ 6 10000 4 2 total 0.011426 0.001099 8 10000 5 2 total 0.004684 0.000451 10 10000 6 2 total 0.001962 0.000189 - material delayedgroup group in nuclide mean std. dev. -1 10000 1 1 total 0.000000e+00 0.000000e+00 -3 10000 2 1 total 0.000000e+00 0.000000e+00 -5 10000 3 1 total 0.000000e+00 0.000000e+00 -7 10000 4 1 total 0.000000e+00 0.000000e+00 -9 10000 5 1 total 0.000000e+00 0.000000e+00 -11 10000 6 1 total 0.000000e+00 0.000000e+00 -0 10000 1 2 total 0.000000e+00 0.000000e+00 -2 10000 2 2 total 3.273900e-10 2.845437e-10 -4 10000 3 2 total 1.207800e-09 1.708087e-09 -6 10000 4 2 total 3.027800e-09 1.091095e-09 -8 10000 5 2 total 0.000000e+00 0.000000e+00 -10 10000 6 2 total 0.000000e+00 0.000000e+00 + material delayedgroup group in nuclide mean std. dev. +1 10000 1 1 total 0.000000 0.000000 +3 10000 2 1 total 0.000000 0.000000 +5 10000 3 1 total 0.000000 0.000000 +7 10000 4 1 total 0.000000 0.000000 +9 10000 5 1 total 0.000000 0.000000 +11 10000 6 1 total 0.000000 0.000000 +0 10000 1 2 total 0.000000 0.000000 +2 10000 2 2 total 0.032739 0.028454 +4 10000 3 2 total 0.120780 0.170809 +6 10000 4 2 total 0.302780 0.109110 +8 10000 5 2 total 0.000000 0.000000 +10 10000 6 2 total 0.000000 0.000000 material group in nuclide mean std. dev. 1 10001 1 total 0.313738 0.015582 0 10001 2 total 0.300821 0.028052 From c5dc4fad3d183491a71164895dea0b23a5e944b5 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 19 Sep 2016 20:44:06 -0400 Subject: [PATCH 27/82] Updating to resolve @samuelshaner comments --- docs/source/io_formats/mgxs_library.rst | 11 +- examples/xml/pincell_multigroup/mgxs.h5 | Bin 59616 -> 16496 bytes openmc/mesh.py | 12 +- openmc/mgxs/library.py | 4 +- openmc/mgxs_library.py | 300 ++++++++++-------------- openmc/settings.py | 2 +- scripts/openmc-update-mgxs.py | 18 +- src/global.F90 | 5 +- src/hdf5_interface.F90 | 1 + src/input_xml.F90 | 18 +- src/mgxs_data.F90 | 4 +- src/mgxs_header.F90 | 116 +++++---- src/tally.F90 | 14 +- tests/1d_mgxs.h5 | Bin 123864 -> 123864 bytes 14 files changed, 243 insertions(+), 262 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 0a02431f6c..04474c01b5 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -32,9 +32,6 @@ MGXS Library Specification - **group structure** (*double[]*) -- Monotonically increasing list of group boundaries, in units of MeV. The length of this array should be the number of groups plus 1. - - **inverse velocities** (*double[]*) -- Average inverse velocitiy - for each of the groups in the library. This is an optional - attribute. **//** @@ -60,12 +57,12 @@ data for the nuclide or material that it represents. that the polar angular domain is subdivided if the `representation` attribute is "angle". This parameter is ignored otherwise. - - **scatter-type** (*char[]*) -- The representation of the + - **scatter-format** (*char[]*) -- The representation of the scattering angular distribution. The options are either "legendre", "histogram", or "tabular". If not provided, the default of "legendre" will be assumed. - **order** (*int*) -- Either the Legendre order, number of bins, - or number of points (depending on the value of `scatter-type`) + or number of points (depending on the value of `scatter-format`) used to describe the angular distribution associated with each group-to-group transfer probability. @@ -113,6 +110,8 @@ Temperature-dependent data, provided for temperature K. spectra as well and thus will have one additional dimension for the outgoing energy group. In this case, `nu-fission` has the same dimensionality as `multiplicity matrix`. + - **inverse velocities** (*double[]*) -- Average inverse velocity + for each of the groups in the library. This dataset is optional. **//K/scatter data/** @@ -143,7 +142,7 @@ Data specific to neutron scattering for the temperature K `scatter matrix[num-polar][num-azimuthal][order(+1)][g_in][g_out]` The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". Note that if the value of - `scatter-type` is "legendre", the order dimension will be one + `scatter-format` is "legendre", the order dimension will be one larger than the value of `order`, otherwise it will match `order`. Finally, the g_out dimension has a dimensionality of `g_out bounds`[0] to `g_out bounds`[1]. diff --git a/examples/xml/pincell_multigroup/mgxs.h5 b/examples/xml/pincell_multigroup/mgxs.h5 index ada3b1c71d8db394f330abf18d5a934544e44456..cbe338c1c7de692a9bed69901f1da186bc1d3348 100644 GIT binary patch delta 578 zcmaEGk@-Ud;{*++0*8%SeN2-J*f=I1V3J_*2@eUHd}p`sW=-a;%#2Kv>)ACY|6tdc zxc$TA09TI58XTKM_!&5WusAufq$IUSH!Z&?H?d^%JC1KG?EhOIgflR7Ox)PZmh{<5 zfz@Pk9iNn7?7w-N6ZSr|7tEek(EH`Gz4zvoe9svTAu6Knjx6C+y_;~vo-LZ2MI!H( zeekSj4Hq9jvi}{Ed-UI?NA?L%FDTvq`ON;>=9e4hGj81RfpO!37mO1RI80XHVcT3M z*2lsOw0ASVbSM*uF_~Ywaq@v>S(Ah0lu-Cd@~HeG1q45VQ)07$;uB`D2LI)qn-{1a zVT5|8VdBQt$sg2PkhqI9nJ0gk6NEJ+Ccon-nxv_)`G<}Ta)5vxd(LncGo!)eOjG^I z9m^I?wlagbz<>F~$sf!NgcunhAi)wsH&{<@GG8|FKmgc3lPpl&%Y~#WDpZ}(cH=5O zrpXh+IT@`dcda?W$sq_ay(q~_NZQ!O zuv@G(rIaLH%yv^oD&>-vvSIoC=Y8Lqro`^&^UtTA=bZPv=Q+75A63Nw@7(INvy|9@R{+C1|6KoQl zuO(M17eggENEpl-Vj>lAlhA>61m8d+$BG^<7b&6BVhO&fM2>NAxLof^f~IE>qct|@ zihtRK1Vg$oM?&Y^#QErx(T45}LWGp;I9#?sLN_=Qe5OP$blq^dGznd>0i`GyqfF`z z4P_El{BL`}njJgVht1j%6}p~8;`dPB%PYLmf8;|Vak#w0qZ2IMZ8sUA(JB+vR(<)2 z&%X5()V7=mJ=|9Z?)*zC&&e@_gg>%6x5GN@(Oqat{UytIq7YhyqvQQ+TjAG_^Vjje zJcTFzeMUciZi0^%ZV`89b;62WFI=N0c7hx!sH0+j9N5kYuZt)T2D4*hUmKmzfbhf@ zm*Xzqfb`w`2Zy_h;E3ORHn{D!%bR8R)3r z`KA?Fob0mm#Rolfp1l?`qUH+|+2RZL_Xb_JpWq3nGZ#OLuFpdjay=i-*wbgvRw*F0(8=YrS?%3h3F~?Y-5N2wfZJm1%Q;o*{J)K5w$)St0sCp!Mv|Bj^qd*mUBC zAGEe7*R*~yLQsJ!lle}*coA_DPE}a5=+UUuVLDs~=jd{S`o!s`m{Twvi^S`q3E(xq0i()qmUGb1wbiGGk9zF%H z>>R_lc%Z;j9ly40elIfdT+fl*$yT^b;i#lW=kTY{A83EDWM=~y#<}GDb!HBPc4lZ^ zT(}39u{v=%+A8xIP{*e~tW5%?x=t z@iD2sqMHHf!K8fcvIJjHT#g3LtkD{D!eie~Cj zDY5g!o1saINT`FDLVNY7WQI8OIw;%fBdV@%N(mf`Sv*=;ck(H_rRD@B)UYB>V_;U!xa z^|R3@uffrkJXewI^A)(J*f~;{6Sm2)CC>Pm(E-j`)mH@&r4U(Ly#4}Ai@IbM$=85hT-MYx=N2fgBEp357Yufb%f_1Q-5s?sh zxdj{>-G4e891dd^u1EXE>qE1~(Sw`SYQgZZJ#(ih4*2g7^oq9=5@S5UeDa00y0G6T z#jgJEhu~}1@0QS<1Z^wsj5(|y5AU7p_vvI*gFI?R*TIXCfojKVx!^LG8FaNE<&Y2_ zCA28%%ZniUjfH&K`e(4y+jUy9rU+iuop_=W^%~r}>K;09dw?`w+cI`*0*qVRt}Rg8 z4$J49K0W407U){tQ6Bh50RE0hS7TlUoFo4}N?oG^j7yiUe=@EUuJy-S* zeA&IrGwt_5?R$FX`L3tPrOTxO<=YJL1HBa4d@-SJ159zhwbJjyYM9`1s_RAn4P?wE zLBFcL94?bR>4TB_Z7v-A5Y+QWGY3}B_Q>w(Z%3TZd6(9f&BA3Yo*rOyx90;;>>umr zUWAsukhk;t4Nfs3*fV~hwftEhODH%xOsk&B~lnE)YwTUt!R|jT{8ai{plh+Vu-hRVUKR^= zC$kN}dcnOgb@y7(4fx;wbn`gSqTO3yJ<|y}lC2YUC^bOb+tB69t9cJ0^TLb<7rR8r z3(q09u8fCx%A5AOfNE5SZZoXKnPxdBtY(S;#&?+Tr{1Xrb6dMrMrO5eN^jgE&wpxQ z)^i5${zf5e;W(YVq16T%n?t%Zirzv_L(wv)A_pkksTWlEWGo~eX2(|lJ_oFV{Esy< zmq4VArAM@I3(SA~w_H?BJoIU?LR=oCg5$f?k}D~5kb>kXZT_Qd3=xg1oj1--K7)8? zrP`Hz5h5zCqRq7a^#Ds&!2B4n^;%EglHxirsvuT7(?P zurFNj<|^`oGxPJ5Kr)$|L{g@7u*cn$^X6^tXdHdOXR1Uhw9Qr*k zu@GE4xxk350KtQ{(qj5ac=gxaFp;Y6B3R~nWXEWiM=+`LzEb|tDhS|D6-Go~g3QGH zr`^Z@0<>2xG=?7>u@MXE)$xzdU_n*z4>kE>S_`}WY0ZXDH4yKmJR?FJR7ZP}aiKV< z>nPEOrws|}bM%DM%hs`wp{Xm9u^zf$OXx;*|+Y&tA6h;TMC+X25WuAC@Hkpo(-*&#M(q<`D18X7q& zi{RFzr`JUDAHmOxSv_*eRWPt^j_We9d-tkuX!;^{FPFzeMV3^QZm&oV5SPTkmV~ty zE0t_9+lR~R#QP4q=C`_$oaJA0v2Mh4Bi@aeZo#{eh7EW(GUU$tpWR4WAW_~5Hsi&g zvz6#Z8aCtINOdsrR9dhHBs60i!Iu{7P>B|)oJ{M`Zp2OVd)-K6&|o(rTLL#IGi+El zV!iF_ZUlGBH@cCo?U-Y+Ze(BwHp99RYPfhd*o`nEhHuV6LbIcWZ!US;U^n77vKtxB z`c60EM`-+ZHzHdX-*MM2Nwcd+j{2${!FpZ#3PP8x9}!<5@Ltzpk9c>3z%t#9?ONRH zQW~P9$jV>wHHNT0w`&9!Ll!*_M;3h_j;w-M99gnYKL6e4M#d9{rtQVI6?lL^R>58z zS@|5|sT45{5_%ws;7gIkl4z02$+Qkd7VEpn^4&j(EZGvcL9vJUG=?U{sQj4J5(WGl zne?(imo&B<$!9AEGU}%|nO1(95brvJR!oefFjo$N1ea2NScYiPIc!yS{9doK%HVcz3+lYm{T}CS zR@i6wGv-i8YmYy8E2K18GvgpB!Shdt72V8^f#3iGGmm>(u&&{A5^s7Oa(2M1^NL<81U+0h-X`1y z?DH0|qdPv@-y-~Q^yT+%Fj0d`O~LUY z=@nq}fVRrVAq3Jpw%*phV}eX-{v%PVoCUju6?<2|xCe9NK8o%}h%ZeD8aK1?Wf1JC zRFJnF+wpZ9&1b7K z7|at^C7vgyJVM*ZJfT+)%@fi?X`bX%O7nzq_3J#rN-Apv7b~fvI=rNc>ha@_Q-?=W z_P;Iv7R@A@n~*RvupZxqbrW&)aq97-FSeO@Dh*VQgf4Fx?kJ{2i&Rdgb!b2XzY|az z#h`KU=#wph8^n4-gtV=D%tz+gzzMADGvJRNRnwS?|{Hr!H&R%u8DGF8%$%3i|P qj_eo=DZTw0J=4HdLifm?srvcQ01G;$0S;`J1~`rXtpHbl&HX?4Dzw!A diff --git a/openmc/mesh.py b/openmc/mesh.py index 9fc36f75ae..af65a2a164 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -286,10 +286,8 @@ class Mesh(object): openmc.XPlane(x0=self.upper_right[0], boundary_type=bc[1])] if len(self.dimension) == 1: - yplanes = [openmc.YPlane(y0=np.finfo(np.float).min, - boundary_type='reflective'), - openmc.YPlane(y0=np.finfo(np.float).max, - boundary_type='reflective')] + yplanes = [openmc.YPlane(y0=1000., boundary_type='reflective'), + openmc.YPlane(y0=1000., boundary_type='reflective')] else: yplanes = [openmc.YPlane(y0=self.lower_left[1], boundary_type=bc[2]), @@ -304,10 +302,8 @@ class Mesh(object): # inconsistency between what numpy uses as the max float and what # Fortran expects for a real(8), so this avoids code complication # and achieves the same goal. - zplanes = [openmc.ZPlane(z0=-1000., - boundary_type='reflective'), - openmc.ZPlane(z0=1000., - boundary_type='reflective')] + zplanes = [openmc.ZPlane(z0=-1000., boundary_type='reflective'), + openmc.ZPlane(z0=1000., boundary_type='reflective')] else: zplanes = [openmc.ZPlane(z0=self.lower_left[2], boundary_type=bc[4]), diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index f63d773277..02c63f50bb 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -827,7 +827,7 @@ class Library(object): data set for eventual combination in to an openmc.MGXSLibrary object (i.e., the library). Note that this method does not build an XSdata object with nested temperature tables. The temperature of each - XsData object will be left at the default value of 300K. + XSdata object will be left at the default value of 300K. Parameters ---------- @@ -908,7 +908,7 @@ class Library(object): xsdata.order = min(order, self.legendre_order) # Right now only 'legendre' data and isotropic weighting is supported - self.scatter_type = 'legendre' + self.scatter_format = 'legendre' self.representation = 'isotropic' if nuclide is not 'total': diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index a5968e299e..cba5c20a15 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -27,7 +27,7 @@ class XSdata(object): name : str Name of the mgxs data set. energy_groups : openmc.mgxs.EnergyGroups - Energygroup structure + Energy group structure representation : {'isotropic', 'angle'}, optional Method used in generating the MGXS (isotropic or angle-dependent flux weighting). Defaults to 'isotropic' @@ -49,7 +49,7 @@ class XSdata(object): Energy group structure fissionable : bool Whether or not this is a fissionable data set. - scatter_type : {'legendre', 'histogram', or 'tabular'} + scatter_format : {'legendre', 'histogram', or 'tabular'} Angular distribution representation (legendre, histogram, or tabular) order : int Either the Legendre order, number of bins, or number of points used to @@ -78,79 +78,53 @@ class XSdata(object): Dimensionality of scattering matrix data (e.g., the scattering matrix cross section). The return result depends on the value of ``representation``. - total : numpy.ndarray - Group-wise total cross section ordered by increasing group index (i.e., - fast to thermal). If ``representation`` is "isotropic", then the length - of this list should equal the number of groups described in the - ``groups`` element. If ``representation`` is "angle", then the length - of this list should equal the number of groups times the number of - azimuthal angles times the number of polar angles, with the - inner-dimension being groups, intermediate-dimension being azimuthal - angles and outer-dimension being the polar angles. - absorption : numpy.ndarray - Group-wise absorption cross section ordered by increasing group index - (i.e., fast to thermal). If ``representation`` is "isotropic", then the - length of this list should equal the number of groups described in the - ``groups`` attribute. If ``representation`` is "angle", then the length - of this list should equal the number of groups times the number of - azimuthal angles times the number of polar angles, with the - inner-dimension being groups, intermediate-dimension being azimuthal - angles and outer-dimension being the polar angles. - scatter_matrix : numpy.ndarray + total : dict of numpy.ndarray + Group-wise total cross section. + absorption : dict of numpy.ndarray + Group-wise absorption cross section. + scatter_matrix : dict of numpy.ndarray Scattering moment matrices presented with the columns representing incoming group and rows representing the outgoing group. That is, - down-scatter will be above the diagonal of the resultant matrix. This - matrix is repeated for every Legendre order (in order of increasing - orders) if ``scatter_type`` is "legendre"; otherwise, this matrix is - repeated for every bin of the histogram or tabular representation. - Finally, if ``representation`` is "angle", the above is repeated for - every azimuthal angle and every polar angle, in that order. - multiplicity_matrix : numpy.ndarray + down-scatter will be above the diagonal of the resultant matrix. + multiplicity_matrix : dict of numpy.ndarray Ratio of neutrons produced in scattering collisions to the neutrons which undergo scattering collisions; that is, the multiplicity provides the code with a scaling factor to account for neutrons produced in - (n,xn) reactions. This information is assumed isotropic and therefore - does not need to be repeated for every Legendre moment or - histogram/tabular bin. This matrix follows the same arrangement as - described for the ``scatter`` attribute, with the exception of the data - needed to provide the scattering type information. - fission : numpy.ndarray - Group-wise fission cross section ordered by increasing group index - (i.e., fast to thermal). If ``representation`` is "isotropic", then the - length of this list should equal the number of groups described in the - ``groups`` attribute. If ``representation`` is "angle", then the length - of this list should equal the number of groups times the number of - azimuthal angles times the number of polar angles, with the - inner-dimension being groups, intermediate-dimension being azimuthal - angles and outer-dimension being the polar angles. - kappa_fission : numpy.ndarray - Group-wise kappa-fission cross section ordered by increasing group - index (i.e., fast to thermal). If ``representation`` is "isotropic", - then the length of this list should equal the number of groups in the - ``groups`` attribute. If ``representation`` is "angle", then the length - of this list should equal the number of groups times the number of - azimuthal angles times the number of polar angles, with the - inner-dimension being groups, intermediate-dimension being azimuthal - angles and outer-dimension being the polar angles. - chi : numpy.ndarray + (n,xn) reactions. + fission : dict of numpy.ndarray + Group-wise fission cross section. + kappa_fission : dict of numpy.ndarray + Group-wise kappa-fission cross section. + chi : dict of numpy.ndarray Group-wise fission spectra ordered by increasing group index (i.e., - fast to thermal). This attribute should be used if making the common + fast to thermal). This attribute should be used if making the common approximation that the fission spectra does not depend on incoming - energy. If the user does not wish to make this approximation, then + energy. If the user does not wish to make this approximation, then this should not be provided and this information included in the - ``nu_fission`` element instead. If ``representation`` is "isotropic", - then the length of this list should equal the number of groups - in the ``groups`` element. If ``representation`` is "angle", then the - length of this list should equal the number of groups times the number - of azimuthal angles times the number of polar angles, with the - inner-dimension being groups, intermediate-dimension being azimuthal - angles and outer-dimension being the polar angles. - nu_fission : numpy.ndarray + ``nu_fission`` attribute instead. + nu_fission : dict of numpy.ndarray Group-wise fission production cross section vector (i.e., if ``chi`` is - provided), or is the group-wise fission production matrix. If providing - the vector, it should be ordered the same as the ``fission`` data. If - providing the matrix, it should be ordered the same as the - ``multiplicity`` matrix. + provided), or is the group-wise fission production matrix. + inverse_velocities : dict of numpy.ndarray + Inverse of velocities, in units of sec/cm. + + Notes + ----- + The parameters containing cross section data have dimensionalities which + depend upon the value of ``representation`` as well as the number of + Legendre or other angular dimensions as described by ``order``. The + ``vector_shape``, ``matrix_shape``, and ``pn_matrix_shape`` properties are + provided to obtain the dimensionality of the data for each temperature. + + The following are cross sections which should use each of these properties: + + vector_shape : + total, absorption, fission, kappa_fission, chi, nu_fission (if chi is + provided), inverse_velocities + matrix_shape : + multiplicity_matrix, nu_fission (if chi is not provided) + pn_matrix_shape : + scatter_matrix """ @@ -163,7 +137,7 @@ class XSdata(object): self.representation = representation self._awr = None self._fissionable = False - self._scatter_type = 'legendre' + self._scatter_format = 'legendre' self._order = None self._num_polar = None self._num_azimuthal = None @@ -176,6 +150,7 @@ class XSdata(object): self._nu_fission = len(temperatures) * [None] self._kappa_fission = len(temperatures) * [None] self._chi = len(temperatures) * [None] + self._inverse_velocities = len(temperatures) * [None] @property def name(self): @@ -202,8 +177,8 @@ class XSdata(object): return self._temperatures @property - def scatter_type(self): - return self._scatter_type + def scatter_format(self): + return self._scatter_format @property def order(self): @@ -256,7 +231,7 @@ class XSdata(object): @property def num_orders(self): if self._order is not None: - if self._scatter_type in (None, 'legendre'): + if self._scatter_format in (None, 'legendre'): return self._order + 1 else: return self._order @@ -327,19 +302,18 @@ class XSdata(object): def temperatures(self, temperatures): check_type('temperatures', temperatures, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking nptemperatures = np.asarray(temperatures) check_value('temperatures dimensionality', nptemperatures.ndim, [1]) self._temperatures = nptemperatures - @scatter_type.setter - def scatter_type(self, scatter_type): + @scatter_format.setter + def scatter_format(self, scatter_format): # check to see it is of a valid type and value - check_value('scatter_type', scatter_type, _SCATTER_TYPES) - self._scatter_type = scatter_type + check_value('scatter_format', scatter_format, _SCATTER_TYPES) + self._scatter_format = scatter_format @order.setter def order(self, order): @@ -390,6 +364,7 @@ class XSdata(object): self._nu_fission.append(None) self._kappa_fission.append(None) self._chi.append(None) + self._inverse_velocities.append(None) def set_total(self, total, temperature=294.): """This method sets the cross section for this XSdata object at the @@ -397,7 +372,7 @@ class XSdata(object): Parameters ---------- - total: nd.nparray + total: np.ndarray Total Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -409,8 +384,7 @@ class XSdata(object): """ check_type('total', total, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking nptotal = np.asarray(total) check_value('total shape', nptotal.shape, [self.vector_shape]) check_type('temperature', temperature, Real) @@ -425,7 +399,7 @@ class XSdata(object): Parameters ---------- - absorption: nd.nparray + absorption: np.ndarray Absorption Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -437,8 +411,7 @@ class XSdata(object): """ check_type('absorption', absorption, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npabsorption = np.asarray(absorption) check_value('absorption shape', npabsorption.shape, [self.vector_shape]) @@ -454,7 +427,7 @@ class XSdata(object): Parameters ---------- - fission: nd.nparray + fission: np.ndarray Fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -466,8 +439,7 @@ class XSdata(object): """ check_type('fission', fission, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npfission = np.asarray(fission) check_value('fission shape', npfission.shape, [self.vector_shape]) check_type('temperature', temperature, Real) @@ -485,7 +457,7 @@ class XSdata(object): Parameters ---------- - kappa_fission: nd.nparray + kappa_fission: np.ndarray Kappa-Fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -498,8 +470,7 @@ class XSdata(object): """ check_type('kappa_fission', kappa_fission, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npkappa_fission = np.asarray(kappa_fission) check_value('kappa fission shape', npkappa_fission.shape, [self.vector_shape]) @@ -518,7 +489,7 @@ class XSdata(object): Parameters ---------- - chi: nd.nparray + chi: np.ndarray Fission Spectrum temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -536,8 +507,7 @@ class XSdata(object): raise ValueError(msg) check_type('chi', chi, Iterable, expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npchi = np.asarray(chi) # Check the shape if npchi.shape != self.vector_shape: @@ -558,7 +528,7 @@ class XSdata(object): Parameters ---------- - scatter: nd.nparray + scatter: np.ndarray Scattering Matrix Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -569,8 +539,7 @@ class XSdata(object): openmc.mgxs_library.set_scatter_matrix_mgxs() """ - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npscatter = np.asarray(scatter) check_iterable_type('scatter', npscatter, Real, max_depth=len(npscatter.shape)) @@ -587,7 +556,7 @@ class XSdata(object): Parameters ---------- - multiplicity: nd.nparray + multiplicity: np.ndarray Multiplicity Matrix Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -598,8 +567,7 @@ class XSdata(object): openmc.mgxs_library.set_multiplicity_matrix_mgxs() """ - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npmultiplicity = np.asarray(multiplicity) check_iterable_type('multiplicity', npmultiplicity, Real, max_depth=len(npmultiplicity.shape)) @@ -617,7 +585,7 @@ class XSdata(object): Parameters ---------- - nu_fission: nd.nparray + nu_fission: np.ndarray Nu-fission Cross Section temperature : float Temperature (in units of Kelvin) of the provided dataset. Defaults @@ -638,8 +606,7 @@ class XSdata(object): # chi already has been set. If not, we just check that this is OK # and set the use_chi flag accordingly - # Convert to a numpy array so we can easily get the shape for - # checking + # Convert to a numpy array so we can easily get the shape for checking npnu_fission = np.asarray(nu_fission) check_iterable_type('nu_fission', npnu_fission, Real, @@ -669,6 +636,31 @@ class XSdata(object): if np.sum(npnu_fission) > 0.0: self._fissionable = True + def set_inverse_velocities(self, inv_vel, temperature=294.): + """This method sets the inverse velocities for this XSdata object at the + provided temperature. + + Parameters + ---------- + inv_vel: np.ndarray + Inverse velocities in units of sec/cm. + temperature : float + Temperature (in units of Kelvin) of the provided dataset. Defaults + to 294K + + """ + check_type('inverse velocities', inv_vel, Iterable, + expected_iter_type=Real) + # Convert to a numpy array so we can easily get the shape for checking + npinv_vel = np.asarray(inv_vel) + check_value('inverse velocities shape', npinv_vel.shape, + [self.vector_shape]) + check_type('temperature', temperature, Real) + check_value('temperature', temperature, self.temperatures) + + i = self.temperatures.tolist().index(temperature) + self._inverse_velocities[i] = npinv_vel + def set_total_mgxs(self, total, temperature=294., nuclide='total', xs_type='macro', subdomain=None): """This method allows for an openmc.mgxs.TotalXS or @@ -1009,7 +1001,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - if (self.scatter_type != 'legendre'): + if (self.scatter_format != 'legendre'): msg = 'Anisotropic scattering representations other than ' \ 'Legendre expansions have not yet been implemented in ' \ 'openmc.mgxs.' @@ -1121,12 +1113,7 @@ class XSdata(object): self._multiplicity_matrix[i] = \ np.nan_to_num(self._multiplicity_matrix[i]) - def _get_xsdata_group(self, file, compression): - if compression is not None: - check_type("compression", compression, Integral) - check_greater_than("compression", compression, 0, equality=True) - check_less_than("compression", compression, 9, equality=True) - + def _get_xsdata_group(self, file): grp = file.create_group(self.name) if self.awr is not None: grp.attrs['awr'] = self.awr @@ -1140,8 +1127,9 @@ class XSdata(object): grp.attrs['num-azimuthal'] = self.num_azimuthal if self.num_polar is not None: grp.attrs['num-polar'] = self.num_polar - if self.scatter_type is not None: - grp.attrs['scatter-type'] = np.array(self.scatter_type, dtype='S') + if self.scatter_format is not None: + grp.attrs['scatter-format'] = np.array(self.scatter_format, + dtype='S') if self.order is not None: grp.attrs['order'] = self.order @@ -1153,38 +1141,32 @@ class XSdata(object): # Create the temperature datasets for i, temperature in enumerate(self.temperatures): - xsgrp = grp.create_group(str(int(np.round(temperature))) + "K") + xs_grp = grp.create_group(str(int(np.round(temperature))) + "K") if self._total[i] is None: raise ValueError('total data must be provided when writing ' 'the HDF5 library') - xsgrp.create_dataset("total", data=self._total[i], - compression=compression) + xs_grp.create_dataset("total", data=self._total[i]) if self._absorption[i] is None: raise ValueError('absorption data must be provided when ' 'writing the HDF5 library') - xsgrp.create_dataset("absorption", data=self._absorption[i], - compression=compression) + xs_grp.create_dataset("absorption", data=self._absorption[i]) if self.fissionable: if self._fission[i] is not None: - xsgrp.create_dataset("fission", data=self._fission[i], - compression=compression) + xs_grp.create_dataset("fission", data=self._fission[i]) if self._kappa_fission[i] is not None: - xsgrp.create_dataset("kappa-fission", - data=self._kappa_fission[i], - compression=compression) + xs_grp.create_dataset("kappa-fission", + data=self._kappa_fission[i]) if self._chi[i] is not None: - xsgrp.create_dataset("chi", data=self._chi[i], - compression=compression) + xs_grp.create_dataset("chi", data=self._chi[i]) if self._nu_fission[i] is None: raise ValueError('nu-fission data must be provided when ' 'writing the HDF5 library') - xsgrp.create_dataset("nu-fission", - data=self._nu_fission[i], - compression=compression) + xs_grp.create_dataset("nu-fission", data=self._nu_fission[i]) if self._scatter_matrix[i] is None: raise ValueError('Scatter matrix must be provided when ' 'writing the HDF5 library') + # Get the sparse scattering data to print to the library G = self.energy_groups.num_groups if self.representation == 'isotropic': @@ -1202,10 +1184,9 @@ class XSdata(object): for l in range(len(matrix[:, g_in, g_out])): flat_scatt.append(matrix[l, g_in, g_out]) # And write it. - scatt_grp = xsgrp.create_group('scatter data') + scatt_grp = xs_grp.create_group('scatter data') scatt_grp.create_dataset("scatter matrix", - data=np.array(flat_scatt), - compression=compression) + data=np.array(flat_scatt)) # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: # Now create the flattened scatter matrix array @@ -1216,15 +1197,13 @@ class XSdata(object): g_out_bounds[g_in, 1] + 1): flat_mult.append(matrix[g_in, g_out]) scatt_grp.create_dataset("multiplicity matrix", - data=np.array(flat_mult), - compression=compression) + data=np.array(flat_mult)) + # And finally, adjust g_out_bounds for 1-based group counting # and write it. g_out_bounds[:, :] += 1 - scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0], - compression=compression) - scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1], - compression=compression) + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0]) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1]) elif self.representation == 'angle': Np = self.num_polar @@ -1248,10 +1227,9 @@ class XSdata(object): for l in range(len(matrix[:, g_in, g_out])): flat_scatt.append(matrix[l, g_in, g_out]) # And write it. - scatt_grp = xsgrp.create_group('scatter data') + scatt_grp = xs_grp.create_group('scatter data') scatt_grp.create_dataset("scatter matrix", - data=np.array(flat_scatt), - compression=compression) + data=np.array(flat_scatt)) # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: # Now create the flattened scatter matrix array @@ -1265,15 +1243,18 @@ class XSdata(object): flat_mult.append(matrix[g_in, g_out]) # And write it. scatt_grp.create_dataset("multiplicity matrix", - data=np.array(flat_mult), - compression=compression) + data=np.array(flat_mult)) + # And finally, adjust g_out_bounds for 1-based group counting # and write it. g_out_bounds[:, :, :, :] += 1 - scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0], - compression=compression) - scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1], - compression=compression) + scatt_grp.create_dataset("g_min", data=g_out_bounds[:, :, :, 0]) + scatt_grp.create_dataset("g_max", data=g_out_bounds[:, :, :, 1]) + + # Add the kinetics data + if self._inverse_velocities[i] is not None: + xs_grp.create_dataset("inverse-velocities", + data=self._inverse_velocities[i]) class MGXSLibrary(object): @@ -1284,27 +1265,20 @@ class MGXSLibrary(object): Parameters ---------- energy_groups : openmc.mgxs.EnergyGroups - Energygroup structure + Energy group structure Attributes ---------- energy_groups : openmc.mgxs.EnergyGroups Energy group structure. - inverse_velocities : Iterable of Real - Inverse of velocities, units of sec/cm xsdatas : Iterable of openmc.XSdata Iterable of multi-Group cross section data objects """ def __init__(self, energy_groups): self.energy_groups = energy_groups - self._inverse_velocities = None self._xsdatas = [] - @property - def inverse_velocities(self): - return self._inverse_velocities - @property def energy_groups(self): return self._energy_groups @@ -1317,13 +1291,6 @@ class MGXSLibrary(object): def xsdatas(self): return self._xsdatas - @inverse_velocities.setter - def inverse_velocities(self, inverse_velocities): - check_type('inverse_velocities', inverse_velocities, Iterable, Real) - check_greater_than('number of inverse_velocities', - len(inverse_velocities), 0.0) - self._inverse_velocities = np.array(inverse_velocities) - @energy_groups.setter def energy_groups(self, energy_groups): check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) @@ -1379,35 +1346,24 @@ class MGXSLibrary(object): self._xsdatas.remove(xsdata) - def export_to_hdf5(self, filename='mgxs.h5', compression=None): - """Create an mgxs.h5 file that can be used for a simulation. + def export_to_hdf5(self, filename='mgxs.h5'): + """Create an hdf5 file that can be used for a simulation. Parameters ---------- filename : str - Filename of file, default is mgxs.xml. - compression : None or int - The compression level to use in the datasets within the hdf5 file. - A value of None implies no compression, numbers between 0 and 9 - refer to the compression level using the gzip algorithm. - Defaults to None. + Filename of file, default is mgxs.h5. """ check_type('filename', filename, basestring) - if compression is not None: - check_type("compression", compression, Integral) - check_greater_than("compression", compression, 0, equality=True) - check_less_than("compression", compression, 9, equality=True) # Create and write to the HDF5 file file = h5py.File(filename, "w") file.attrs['groups'] = self.energy_groups.num_groups file.attrs['group structure'] = self.energy_groups.group_edges - if self.inverse_velocities is not None: - file.attrs['inverse velocities'] = self.inverse_velocities for xsdata in self._xsdatas: - xsdata._get_xsdata_group(file, compression) + xsdata._get_xsdata_group(file) file.close() diff --git a/openmc/settings.py b/openmc/settings.py index b320a429ef..a1b029d4bd 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -104,7 +104,7 @@ class Settings(object): tabular_legendre : dict Determines if a multi-group scattering moment kernel expanded via Legendre polynomials is to be converted to a tabular distribution or - not. Accepted keys are 'enable', and 'num_points'. The value for + not. Accepted keys are 'enable' and 'num_points'. The value for 'enable' is a bool stating whether the conversion to tabular is performed; the value for 'num_points' sets the number of points to use in the tabular distribution, should 'enable' be True. diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py index 5aea89883e..e3fd1bd2f6 100755 --- a/scripts/openmc-update-mgxs.py +++ b/scripts/openmc-update-mgxs.py @@ -60,6 +60,7 @@ def parse_args(): # Parse and return commandline arguments. return args + def get_data(element, entry): try: value = element.find(entry).text @@ -121,9 +122,9 @@ if __name__ == '__main__': n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) n_pol = int(get_data(xsdata_elem, 'num_polar')) - scatter_type = get_data(xsdata_elem, 'scatt_type') - if scatter_type is None: - scatter_type = 'legendre' + scatter_format = get_data(xsdata_elem, 'scatt_type') + if scatter_format is None: + scatter_format = 'legendre' order = int(get_data(xsdata_elem, 'order')) @@ -149,11 +150,11 @@ if __name__ == '__main__': if representation == 'angle': xsd[-1].num_azimuthal = n_azi xsd[-1].num_polar = n_pol - xsd[-1].scatter_type = scatter_type + xsd[-1].scatter_format = scatter_format xsd[-1].order = order names.append(name) - if scatter_type == 'legendre': + if scatter_format == 'legendre': order_dim = order + 1 else: order_dim = order @@ -168,6 +169,9 @@ if __name__ == '__main__': total = np.reshape(total, xsd[i].vector_shape) xsd[i].set_total(total, temperature) + if inverse_velocities is not None: + xsd[i].set_inverse_velocities(inverse_velocities, temperature) + temp = get_data(xsdata_elem, 'absorption') temp = np.array(temp.split()) absorption = temp.astype(np.float) @@ -222,9 +226,7 @@ if __name__ == '__main__': # Build library as we go, but first we have enough to initialize it lib = openmc.MGXSLibrary(energy_groups) - if inverse_velocities is not None: - lib.inverse_velocities = inverse_velocities lib.add_xsdatas(xsd) - lib.export_to_hdf5(args['output'], compression=args['compression']) + lib.export_to_hdf5(args['output']) diff --git a/src/global.F90 b/src/global.F90 index 6e804c90af..ca376e6421 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -122,13 +122,10 @@ module global ! Midpoint of the energy group structure real(8), allocatable :: energy_bin_avg(:) - ! Inverse velocities of the energy groups (provided or estimated) - real(8), allocatable :: inverse_velocities(:) - ! Maximum Data Order integer :: max_order - ! Whether or no to convert Legendres to tabulars + ! Whether or not to convert Legendres to tabulars logical :: legendre_to_tabular = .True. ! Number of points to use in the Legendre to tabular conversion diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 7e4f16f261..262bbc232c 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -2571,6 +2571,7 @@ contains f_ptr = c_loc(int_buffer) call h5aread_f(attr_id, H5T_NATIVE_INTEGER, f_ptr, hdf5_err) call h5aclose_f(attr_id, hdf5_err) + ! Convert to Fortran logical if (int_buffer == 0) then buffer = .false. diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 1aa3a8a87a..2959e876dd 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4618,10 +4618,10 @@ contains real(8), allocatable :: rev_energy_bins(:) character(len=MAX_WORD_LEN), allocatable :: names(:) - ! Check if mgxs.h5 exists + ! Check if MGXS Library exists inquire(FILE=path_cross_sections, EXIST=file_exists) if (.not. file_exists) then - ! Could not find mgxs.h5 file + ! Could not find MGXS Library file call fatal_error("Cross sections HDF5 file '" & // trim(path_cross_sections) // "' does not exist!") end if @@ -4655,20 +4655,6 @@ contains energy_bin_avg(i) = HALF * (energy_bins(i) + energy_bins(i + 1)) end do - allocate(inverse_velocities(energy_groups)) - if (check_attribute(file_id, "inverse velocities")) then - ! Get inverse velocities - call read_attribute(inverse_velocities, file_id, "inverse velocities") - else - ! If not given, estimate them by using average energy in group which is - ! assumed to be the midpoint - do i = 1, energy_groups - inverse_velocities(i) = ONE / & - (sqrt(TWO * energy_bin_avg(i) / (MASS_NEUTRON_MEV)) * & - C_LIGHT * 100.0_8) - end do - end if - ! Get the datasets present in the library call get_groups(file_id, names) n_libraries = size(names) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 45737ff1dc..724bfa837c 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -38,10 +38,10 @@ contains type(DictCharInt) :: xsdata_dict type(VectorReal), allocatable :: temps(:) - ! Check if cross_sections.xml exists + ! Check if MGXS Library exists inquire(FILE=path_cross_sections, EXIST=file_exists) if (.not. file_exists) then - ! Could not find cross_sections.xml file + ! Could not find MGXS Library file call fatal_error("Cross sections HDF5 file '" & &// trim(path_cross_sections) // "' does not exist!") end if diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 56fbb5965f..dd34dbee05 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -30,6 +30,7 @@ module mgxs_header real(8), allocatable :: k_fission(:) ! kappa-fission real(8), allocatable :: fission(:) ! fission real(8), allocatable :: chi(:, :) ! Fission Spectra + real(8), allocatable :: inv_vel(:) ! Inverse velocities end type XsDataIso type :: XsDataAngle @@ -42,6 +43,7 @@ module mgxs_header real(8), allocatable :: k_fission(:, :, :) ! kappa-fission real(8), allocatable :: fission(:, :, :) ! fission real(8), allocatable :: chi(:, :, :, :) ! Fission Spectra + real(8), allocatable :: inv_vel(:, :, :) ! Inverse velocities end type XsDataAngle !=============================================================================== @@ -55,7 +57,7 @@ module mgxs_header ! Fission information logical :: fissionable ! mgxs object is fissionable? - integer :: scatter_type ! either legendre, histogram, or tabular. + integer :: scatter_format ! either legendre, histogram, or tabular. ! Caching information integer :: index_temp ! temperature index for nuclide @@ -322,20 +324,20 @@ module mgxs_header end select ! Load the remaining metadata - if (check_attribute(xs_id, "scatter-type")) then - call read_attribute(temp_str, xs_id, "scatter-type") + if (check_attribute(xs_id, "scatter-format")) then + call read_attribute(temp_str, xs_id, "scatter-format") temp_str = trim(temp_str) if (to_lower(temp_str) == 'legendre') then - this % scatter_type = ANGLE_LEGENDRE + this % scatter_format = ANGLE_LEGENDRE else if (to_lower(temp_str) == 'histogram') then - this % scatter_type = ANGLE_HISTOGRAM + this % scatter_format = ANGLE_HISTOGRAM else if (to_lower(temp_str) == 'tabular') then - this % scatter_type = ANGLE_TABULAR + this % scatter_format = ANGLE_TABULAR else - call fatal_error("Invalid scatter-type option!") + call fatal_error("Invalid scatter-format option!") end if else - this % scatter_type = ANGLE_LEGENDRE + this % scatter_format = ANGLE_LEGENDRE end if if (check_attribute(xs_id, "fissionable")) then call read_attribute(this % fissionable, xs_id, "fissionable") @@ -355,7 +357,7 @@ module mgxs_header ! However Pn has n+1 sets of points (since you need to ! the count the P0 moment). Adjust for that. Histogram and Tabular ! formats dont need this adjustment. - if (this % scatter_type == ANGLE_LEGENDRE) then + if (this % scatter_format == ANGLE_LEGENDRE) then order_dim = order_dim + 1 else order_dim = order_dim @@ -538,7 +540,7 @@ module mgxs_header ! Compare the number of orders given with the maximum order of the ! problem. Strip off the supefluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then + if (this % scatter_format == ANGLE_LEGENDRE) then order = min(order_dim - 1, max_order) order_dim = order + 1 end if @@ -560,9 +562,9 @@ module mgxs_header ! Finally convert the legendre to tabular if needed allocate(scatt_coeffs(groups)) - if (this % scatter_type == ANGLE_LEGENDRE .and. & + if (this % scatter_format == ANGLE_LEGENDRE .and. & legendre_to_tabular) then - this % scatter_type = ANGLE_TABULAR + this % scatter_format = ANGLE_TABULAR order_dim = legendre_to_tabular_points order = order_dim dmu = TWO / real(order - 1, 8) @@ -643,11 +645,11 @@ module mgxs_header end if ! Allocate and initialize our ScattData Object. - if (this % scatter_type == ANGLE_HISTOGRAM) then + if (this % scatter_format == ANGLE_HISTOGRAM) then allocate(ScattDataHistogram :: xs % scatter) - else if (this % scatter_type == ANGLE_TABULAR) then + else if (this % scatter_format == ANGLE_TABULAR) then allocate(ScattDataTabular :: xs % scatter) - else if (this % scatter_type == ANGLE_LEGENDRE) then + else if (this % scatter_format == ANGLE_LEGENDRE) then allocate(ScattDataLegendre :: xs % scatter) end if @@ -669,12 +671,18 @@ module mgxs_header xs % total(:) = xs % absorption(:) + xs % scatter % scattxs(:) end if - ! Finally, check sigT to ensure it is not 0 since it is + ! Check sigT to ensure it is not 0 since it is ! often divided by in the tally routines do gin = 1, groups if (xs % total(gin) == ZERO) xs % total(gin) = 1E-10_8 end do + ! Get kinetics data + if (check_dataset(xsdata_grp, "inverse-velocities")) then + allocate(xs % inv_vel(groups)) + call read_dataset(xs % inv_vel, xsdata_grp, "inverse-velocities") + end if + ! Close the groups we have opened and deallocate call close_group(xsdata_grp) call close_group(scatt_grp) @@ -890,7 +898,7 @@ module mgxs_header ! Compare the number of orders given with the maximum order of the ! problem. Strip off the superfluous orders if needed. - if (this % scatter_type == ANGLE_LEGENDRE) then + if (this % scatter_format == ANGLE_LEGENDRE) then order = min(order_dim - 1, max_order) order_dim = order + 1 end if @@ -918,9 +926,9 @@ module mgxs_header ! Finally convert the legendre to tabular if needed allocate(scatt_coeffs(groups, this % n_azi, this % n_pol)) - if (this % scatter_type == ANGLE_LEGENDRE .and. & + if (this % scatter_format == ANGLE_LEGENDRE .and. & legendre_to_tabular) then - this % scatter_type = ANGLE_TABULAR + this % scatter_format = ANGLE_TABULAR order_dim = legendre_to_tabular_points order = order_dim dmu = TWO / real(order - 1, 8) @@ -1031,11 +1039,11 @@ module mgxs_header do ipol = 1, this % n_pol do iazi = 1, this % n_azi ! Allocate and initialize our ScattData Object. - if (this % scatter_type == ANGLE_HISTOGRAM) then + if (this % scatter_format == ANGLE_HISTOGRAM) then allocate(ScattDataHistogram :: xs % scatter(iazi, ipol) % obj) - else if (this % scatter_type == ANGLE_TABULAR) then + else if (this % scatter_format == ANGLE_TABULAR) then allocate(ScattDataTabular :: xs % scatter(iazi, ipol) % obj) - else if (this % scatter_type == ANGLE_LEGENDRE) then + else if (this % scatter_format == ANGLE_LEGENDRE) then allocate(ScattDataLegendre :: xs % scatter(iazi, ipol) % obj) end if @@ -1075,8 +1083,8 @@ module mgxs_header end do end if - ! Finally, check sigT to ensure it is not 0 since it is - ! often divided by in the tally routines + ! Check sigT to ensure it is not 0 since it is often divided by in + ! the tally routines do ipol = 1, this % n_pol do iazi = 1, this % n_azi do gin = 1, groups @@ -1087,6 +1095,16 @@ module mgxs_header end do end do + ! Get kinetics data + if (check_dataset(xsdata_grp, "inverse-velocities")) then + allocate(xs % inv_vel(groups, this % n_azi, this % n_pol)) + allocate(temp_arr(groups * this % n_azi * this % n_pol)) + call read_dataset(temp_arr, xsdata_grp, "inverse-velocities") + xs % inv_vel = reshape(temp_arr, (/groups, this % n_azi, & + this % n_pol/)) + deallocate(temp_arr) + end if + ! Close the groups we have opened and deallocate call close_group(xsdata_grp) call close_group(scatt_grp) @@ -1100,13 +1118,13 @@ module mgxs_header !=============================================================================== subroutine mgxs_combine(this, temps, mat, nuclides, max_order, & - scatter_type, order_dim) + scatter_format, order_dim) class(Mgxs), intent(inout) :: this ! The Mgxs to initialize type(VectorReal), intent(in) :: temps ! Temperatures to obtain type(Material), pointer, intent(in) :: mat ! base material type(MgxsContainer), intent(in) :: nuclides(:) ! List of nuclides to harvest from integer, intent(in) :: max_order ! Maximum requested order - integer, intent(out) :: scatter_type ! Type of scatter + integer, intent(out) :: scatter_format ! Type of scatter integer, intent(out) :: order_dim ! Scattering data order size integer :: t, mat_max_order, order @@ -1138,7 +1156,7 @@ module mgxs_header ! Determine the scattering type of our data and ensure all scattering orders ! are the same. - scatter_type = nuclides(mat % nuclide(1)) % obj % scatter_type + scatter_format = nuclides(mat % nuclide(1)) % obj % scatter_format select type(nuc => nuclides(mat % nuclide(1)) % obj) type is (MgxsIso) order = size(nuc % xs(1) % scatter % dist(1) % data, dim=1) @@ -1146,7 +1164,7 @@ module mgxs_header order = size(nuc % xs(1) % scatter(1, 1) % obj % dist(1) % data, dim=1) end select ! If we have tabular only data, then make sure all datasets have same size - if (scatter_type == ANGLE_HISTOGRAM) then + if (scatter_format == ANGLE_HISTOGRAM) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) @@ -1162,7 +1180,7 @@ module mgxs_header end do ! Ok, got our order, store the dimensionality order_dim = order - else if (scatter_type == ANGLE_TABULAR) then + else if (scatter_format == ANGLE_TABULAR) then ! Check all scattering data to ensure it is the same size do i = 2, mat % n_nuclides select type(nuc => nuclides(mat % nuclide(i)) % obj) @@ -1178,7 +1196,7 @@ module mgxs_header end do ! Ok, got our order, store the dimensionality order_dim = order - else if (scatter_type == ANGLE_LEGENDRE) then + else if (scatter_format == ANGLE_LEGENDRE) then ! Need to determine the maximum scattering order of all data in this material mat_max_order = 0 do i = 1, mat % n_nuclides @@ -1228,14 +1246,14 @@ module mgxs_header integer :: nuc_t integer, allocatable :: nuc_ts(:) real(8) :: temp_actual, temp_desired, interp - integer :: scatter_type + integer :: scatter_format type(Jagged2D), allocatable :: nuc_matrix(:) integer, allocatable :: gmin(:), gmax(:) type(Jagged2D), allocatable :: jagged_scatt(:) type(Jagged1D), allocatable :: jagged_mult(:) ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & order_dim) ! Create the Xs Data for each temperature @@ -1253,6 +1271,8 @@ module mgxs_header this % xs(t) % nu_fission(:) = ZERO allocate(this % xs(t) % chi(groups,groups)) this % xs(t) % chi(:, :) = ZERO + allocate(this % xs(t) % inv_vel(groups)) + this % xs(t) % inv_vel(:) = ZERO allocate(temp_mult(groups,groups)) temp_mult(:, :) = ZERO allocate(mult_num(groups,groups)) @@ -1262,12 +1282,12 @@ module mgxs_header allocate(scatt_coeffs(order_dim,groups,groups)) scatt_coeffs(:, :, :) = ZERO - this % scatter_type = scatter_type - if (scatter_type == ANGLE_LEGENDRE) then + this % scatter_format = scatter_format + if (scatter_format == ANGLE_LEGENDRE) then allocate(ScattDataLegendre :: this % xs(t) % scatter) - else if (scatter_type == ANGLE_TABULAR) then + else if (scatter_format == ANGLE_TABULAR) then allocate(ScattDataTabular :: this % xs(t) % scatter) - else if (scatter_type == ANGLE_HISTOGRAM) then + else if (scatter_format == ANGLE_HISTOGRAM) then allocate(ScattDataHistogram :: this % xs(t) % scatter) end if @@ -1342,6 +1362,10 @@ module mgxs_header atom_density * nuc % xs(nuc_t) % k_fission * interp end if end if + if (allocated(nuc % xs(nuc_t) % inv_vel)) then + this % xs(t) % inv_vel = this % xs(t) % inv_vel + & + atom_density * nuc % xs(nuc_t) % inv_vel * interp + end if ! We will next gather the multiplicaity and scattering matrices. ! To avoid multiple re-allocations as we resize the storage @@ -1459,14 +1483,14 @@ module mgxs_header integer :: nuc_t integer, allocatable :: nuc_ts(:) real(8) :: temp_actual, temp_desired, interp - integer :: scatter_type + integer :: scatter_format type(Jagged2D), allocatable :: nuc_matrix(:) integer, allocatable :: gmin(:), gmax(:) type(Jagged2D), allocatable :: jagged_scatt(:) type(Jagged1D), allocatable :: jagged_mult(:) ! Set the meta-data - call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_type, & + call mgxs_combine(this, temps, mat, nuclides, max_order, scatter_format, & order_dim) ! Get the number of each polar and azi angles and make sure all the @@ -1506,6 +1530,8 @@ module mgxs_header this % xs(t) % nu_fission = ZERO allocate(this % xs(t) % chi(groups, groups, n_azi, n_pol)) this % xs(t) % chi = ZERO + allocate(this % xs(t) % inv_vel(groups, n_azi, n_pol)) + this % xs(t) % inv_vel = ZERO allocate(temp_mult(groups, groups, n_azi, n_pol)) temp_mult = ZERO allocate(mult_num(groups, groups, n_azi, n_pol)) @@ -1518,13 +1544,13 @@ module mgxs_header allocate(this % xs(t) % scatter(n_azi, n_pol)) do ipol = 1, n_pol do iazi = 1, n_azi - if (scatter_type == ANGLE_LEGENDRE) then + if (scatter_format == ANGLE_LEGENDRE) then allocate(ScattDataLegendre :: & this % xs(t) % scatter(iazi, ipol) % obj) - else if (scatter_type == ANGLE_TABULAR) then + else if (scatter_format == ANGLE_TABULAR) then allocate(ScattDataTabular :: & this % xs(t) % scatter(iazi, ipol) % obj) - else if (scatter_type == ANGLE_HISTOGRAM) then + else if (scatter_format == ANGLE_HISTOGRAM) then allocate(ScattDataHistogram :: & this % xs(t) % scatter(iazi, ipol) % obj) end if @@ -1589,6 +1615,10 @@ module mgxs_header atom_density * nuc % xs(nuc_t) % total * interp this % xs(t) % absorption = this % xs(t) % absorption + & atom_density * nuc % xs(nuc_t) % absorption * interp + if (allocated(nuc % xs(nuc_t) % inv_vel)) then + this % xs(t) % inv_vel = this % xs(t) % inv_vel + & + atom_density * nuc % xs(nuc_t) % inv_vel * interp + end if if (nuc % fissionable) then this % xs(t) % chi = this % xs(t) % chi + & atom_density * nuc % xs(nuc_t) % chi * interp @@ -1811,6 +1841,8 @@ module mgxs_header ! user of this code wants the complete 1-outgoing group distribution ! which Im not sure what they would do with that. end if + case('inv_vel') + xs = this % xs(t) % inv_vel(gin) case default xs = ZERO end select @@ -1905,6 +1937,8 @@ module mgxs_header ! user of this code wants the complete 1-outgoing group distribution ! which Im not sure what they would do with that. end if + case('inv_vel') + xs = this % xs(t) % inv_vel(gin, iazi, ipol) case default xs = ZERO end select diff --git a/src/tally.F90 b/src/tally.F90 index 3c008e30e5..81f02d631e 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -1222,11 +1222,21 @@ contains else score = p % last_wgt end if - score = score * inverse_velocities(p_g) / material_xs % total * flux + if (i_nuclide > 0) then + score = score * nucxs % get_xs('inv_vel', p_g, UVW=p_uvw) / & + matxs % get_xs('total', p_g, UVW=p_uvw) * flux + else + score = matxs % get_xs('inv_vel', p_g, UVW=p_uvw) * flux + end if else ! For inverse velocity, we need no cross section - score = flux * inverse_velocities(p_g) + if (i_nuclide > 0) then + score = score * nucxs % get_xs('inv_vel', p_g, UVW=p_uvw) * & + atom_density * flux + else + score = flux * matxs % get_xs('inv_vel', p_g, UVW=p_uvw) + end if end if diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 index d764cb69fbf7d76401c15d7224f62b9d2a28942d..65dcf36cf7ee6c22d854c4fbcf2160e63209280f 100644 GIT binary patch delta 1526 zcmZ{kZAep57{@zKbC$L~gxa9gftZpxZl+Sn$_N$(3#5=6fJIJ?Gwg7I)k)&vQ8E{Ql4XdCrZ@ zW=3W+ebf3ahIM-JyWHexZ@(avU*v^WM>`7W|D@}duf<@n$%Cw$hO^fa6g8emlU6Ow z3254GQev(^jq3_Y%(spDi{d(I&ywIloyD(!bc>}VLkghHoq${^*=_Hb@|STsO*Jr} z7htTk5Jk%O%c{KSDR*5;kfoZc5{byXw^Bu})KX;7!XW(z3DV{sfQ!0Z)LD04n~Q!P zR$TC+zN3_9IIi;i^$ad_lH%?(Fu1FySX>@Da@vss7ie516$P7$GbG=lM$tEy>|1jV zG0@gR1A8kC__l6xa!HUoRPq&;xg|2Px#j&G1L>L$qt&hj)!EM8GbFK8dyw-6#aHy* zSDkgmtrJ4rWQghMw!BoyR4%1TYqqNjDR{j{hHG1!z#6nNTnR*rg zt`zk=e#CUnipHrsnBKO89nc)_hukwFnB)WS&`c4TSM2c2tw--?CiHR+%~|>A*K1{< zhmh;dOVW>ux3yW)WbZ#RoP36^mDL0O8^fc|ZXt zM!swX#66LW1tZv;t%-$!#v#0;1hgmvhHG}p?5H`39q%78Rnl8&k4CsX|1H#2u?t!G zI93H{TSS+zbsw0Q9Ki)=S-G5@9_v}SiDP!~F@@aKuDkeLDh!=d){sTx>HB7KpIUmYa8GH;Mhy38!Mlzd%2Tuk7c{!MW UuCiU8xeyM$0ON(yMn3HN2Si7@>Hq)$ delta 1526 zcmZ{kZAep57{@(MbCzZwV%nh8ftZpxZl+Sn$_N$(3nY6fJIJ?Gwg7I)k)&vQ8E{Ql4XdCm>b zXN2c7W@oh9vs1LfccsbJ(b4QI>*&7JoRWh4+COQUyY-7O(Bwwut)p2R35w`Xr;4kl zmN+!*GRQHPuf(+lB<9=4eT6ZNxM#)bMqNd(fOw0kI9&{&#TAEK3E6G!oc5J+8dWvW zuXVy`NdXF%9g^RXRV5IS@j!)wT&tnTfQdo+ju529H3XM6I@DErQJsr^ z9+O@0pn(&Vmvc(t`RW*4u%6;>H!!%XXINY=I)2uc1m|yDClv*niqb{jB6`6$hvZvJ zHZjoBN&{;f4fyt6a&pBfb*T6&EOm)wWN}IRJBQL#9Y*UtONz5y{pUzxs&XUyb&4+^ zxUV>CzbUQWVoEg(v!&|L_u*vDHjdI#t>d)R4OZR+y)|<0oybB@yi7gI4@f;ZQ?#D^ z>7FF@JbuJ<&Wya&9ZYXq!8T}&4MOf25lr$Scyz9i%qzCJ7dD~ybCX&rhsMl2^y{@e z&?Ct4<|XMz`P-UIakBXk71p=3PhFTi$_<~HQLc_sfsq(1Pyo(;qw^Kf_al3Jk#J1E zi^vP&LqA~MD$&e`THwsI4y~;k($$;1_pf3K4yFPE#e4=xq~gPyfr7Bl!yBM^}1BR>jNbHC)fgKwhGgQ!9X^+OZ{r@f0R Date: Mon, 19 Sep 2016 20:53:29 -0400 Subject: [PATCH 28/82] minor typo --- src/mgxs_header.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index dd34dbee05..f9d54093e3 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -1367,7 +1367,7 @@ module mgxs_header atom_density * nuc % xs(nuc_t) % inv_vel * interp end if - ! We will next gather the multiplicaity and scattering matrices. + ! We will next gather the multiplicity and scattering matrices. ! To avoid multiple re-allocations as we resize the storage ! matrix (and/or to avoidlots of duplicate code), we will use a ! dense matrix for this storage, with a reduction to the sparse @@ -1634,7 +1634,7 @@ module mgxs_header end if end if - ! We will next gather the multiplicaity and scattering matrices. + ! We will next gather the multiplicity and scattering matrices. ! To avoid multiple re-allocations as we resize the storage ! matrix (and/or to avoidlots of duplicate code), we will use a ! dense matrix for this storage, with a reduction to the sparse From eed74c9d2632944f041196a19f0177088de5637a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 21 Sep 2016 14:17:25 -0500 Subject: [PATCH 29/82] Fix issue with losing precision in RM reconstruction when K and phi are small --- openmc/data/reconstruct.pyx | 47 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx index 4790cc345c..452968d145 100644 --- a/openmc/data/reconstruct.pyx +++ b/openmc/data/reconstruct.pyx @@ -66,7 +66,6 @@ cdef double phaseshift(int l, double rho): Hardsphere phase shift """ - if l == 0: return rho elif l == 1: @@ -377,7 +376,8 @@ def reconstruct_rm(rm, double E): cdef double smin, smax, s, Jmin, Jmax, J, j cdef double E_r, gn, gg, gfa, gfb, P_r cdef double E_diff, abs_value, gJ - cdef double complex Ubar, U_, denominator_inverse + cdef double Kr, Ki, x + cdef double complex Ubar, U_, factor cdef bint hasfission cdef np.ndarray[double, ndim=2] one cdef np.ndarray[double complex, ndim=2] K, Imat, U @@ -459,31 +459,24 @@ def reconstruct_rm(rm, double E): # Calculate neutron width at energy E gn = sqrt(P*gn/P_r) - # Calculate inverse of denominator of K matrix terms - E_diff = E_r - E - abs_value = E_diff*E_diff + 0.25*gg*gg - denominator_inverse = (E_diff + 0.5j*gg)/abs_value + # Calculate j/2 * inverse of denominator of K matrix terms + factor = 0.5j/(E_r - E - 0.5j*gg) # Upper triangular portion of K matrix -- see ENDF-102, # Equation D.28 - K[0,0] = K[0,0] + gn*gn*denominator_inverse + K[0,0] = K[0,0] + gn*gn*factor if gfa != 0.0 or gfb != 0.0: # Negate fission widths if necessary gfa = (-1 if gfa < 0 else 1)*sqrt(abs(gfa)) gfb = (-1 if gfb < 0 else 1)*sqrt(abs(gfb)) - K[0,1] = K[0,1] + gn*gfa*denominator_inverse - K[0,2] = K[0,2] + gn*gfb*denominator_inverse - K[1,1] = K[1,1] + gfa*gfa*denominator_inverse - K[1,2] = K[1,2] + gfa*gfb*denominator_inverse - K[2,2] = K[2,2] + gfb*gfb*denominator_inverse + K[0,1] = K[0,1] + gn*gfa*factor + K[0,2] = K[0,2] + gn*gfb*factor + K[1,1] = K[1,1] + gfa*gfa*factor + K[1,2] = K[1,2] + gfa*gfb*factor + K[2,2] = K[2,2] + gfb*gfb*factor hasfission = True - # multiply by factor of i/2 - for m in range(3): - for n in range(3): - K[m,n] = K[m,n] * 0.5j - # Get collision matrix gJ = (2*J + 1)/(4*I + 2) if hasfission: @@ -500,9 +493,23 @@ def reconstruct_rm(rm, double E): # Calculate fission from ENDF-102, Eq. D.26 fission += 4*gJ*(cabs(Imat[1,0])**2 + cabs(Imat[2,0])**2) else: - U_ = Ubar*(2*conj(1 - K[0,0])/cabs(1 - K[0,0])**2 - 1) - elastic += gJ*cabs(1 - U_)**2 # ENDF-102, Eq. D.24 - total += 2*gJ*(1 - creal(U_)) # ENDF-102, Eq. D.23 + U_ = Ubar*(2/(1 - K[0,0]) - 1) + if abs(creal(K[0,0])) < 3e-4 and abs(phi) < 3e-4: + # If K and phi are both very small, the calculated cross + # sections can lose precision because the real part of U + # ends up very close to unity. To get around this, we + # use Euler's formula to express Ubar by real and + # imaginary parts, expand cos(2phi) = 1 - 2phi^2 + + # O(phi^4), and then simplify + Kr = creal(K[0,0]) + Ki = cimag(K[0,0]) + x = 2*(-Kr + (Kr*Kr + Ki*Ki)*(1 - phi*phi) + phi*phi - + sin(2*phi)*Ki)/((1 - Kr)*(1 - Kr) + Ki*Ki) + total += 2*gJ*x + elastic += gJ*(x*x + cimag(U_)**2) + else: + total += 2*gJ*(1 - creal(U_)) # ENDF-102, Eq. D.23 + elastic += gJ*cabs(1 - U_)**2 # ENDF-102, Eq. D.24 # Calculate capture as difference of other cross sections as per ENDF-102, # Equation D.25 From f08550f5ed830fbe39786b490c94a2b3b8618705 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 21 Sep 2016 14:32:08 -0500 Subject: [PATCH 30/82] Handle reconstruction for multiple resolved ranges (Pu239 in ENDF/B-VII.1) --- openmc/data/function.py | 25 ++++++++++++++----------- openmc/data/neutron.py | 2 +- openmc/data/resonance.py | 4 ++++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/openmc/data/function.py b/openmc/data/function.py index 13df12b47e..4121918e21 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -459,18 +459,21 @@ class ResonancesWithBackground(EqualityMixin): # Get background cross section xs = self.background(x) - rrr = self.resonances.resolved - if isinstance(x, Iterable): - # Determine which energies are within resolved resonance range - within_rrr = (rrr.energy_min <= x) & (x <= rrr.energy_max) + for r in self.resonances: + if not isinstance(r, openmc.data.resonance._RESOLVED): + continue - # Get resonance cross sections and add to background - resonant_xs = rrr.reconstruct(x[within_rrr]) - xs[within_rrr] += resonant_xs[self.mt] - else: - if rrr.energy_min <= x <= rrr.energy_max: - resonant_xs = rrr.reconstruct(x) - xs += resonant_xs[self.mt] + if isinstance(x, Iterable): + # Determine which energies are within resolved resonance range + within = (r.energy_min <= x) & (x <= r.energy_max) + + # Get resonance cross sections and add to background + resonant_xs = r.reconstruct(x[within]) + xs[within] += resonant_xs[self.mt] + else: + if r.energy_min <= x <= r.energy_max: + resonant_xs = r.reconstruct(x) + xs += resonant_xs[self.mt] return xs diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 0c74aeaa1f..f903ea6f54 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -659,7 +659,7 @@ class IncidentNeutron(EqualityMixin): # Replace cross sections for elastic, capture, fission try: - if isinstance(data.resonances.resolved, _RESOLVED): + if any(isinstance(r, _RESOLVED) for r in data.resonances): for mt in (2, 102, 18): if mt in data.reactions: rx = data.reactions[mt] diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 206a56df45..77d522a044 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -36,6 +36,10 @@ class Resonances(object): def __init__(self, ranges): self.ranges = ranges + def __iter__(self): + for r in self.ranges: + yield r + @property def ranges(self): return self._ranges From 9d769378838a8404a7e878a65a6bf7f9fb8e083d Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Fri, 23 Sep 2016 15:59:47 -0400 Subject: [PATCH 31/82] Fixes to kT vs K --- src/mgxs_data.F90 | 2 +- src/mgxs_header.F90 | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 724bfa837c..2fbfdfd420 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -23,7 +23,7 @@ contains subroutine read_mgxs() integer :: i ! index in materials array integer :: j ! index over nuclides in material - integer :: i_xsdata ! index in list + integer :: i_xsdata ! index in xsdata_dict integer :: i_nuclide ! index in nuclides array character(20) :: name ! name of library to load integer :: representation ! Data representation diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index f9d54093e3..193f337f13 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -198,9 +198,8 @@ module mgxs_header contains !=============================================================================== -! MGXS*_INIT reads in the data from the XML file. At the point of entry -! the file would have been opened and metadata read. This routine begins with -! the xs_id object node itself. +! MGXS*_FROM_HDF5 reads in the data from the HDF5 Library. At the point of entry +! the file would have been opened and metadata read. !=============================================================================== subroutine mgxs_from_hdf5(this, xs_id, temperature, method, tolerance, & @@ -1304,7 +1303,7 @@ module mgxs_header allocate(nuc_ts(1)) nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) temp_actual = nuc % kTs(nuc_ts(1)) - if (abs(temp_actual - temp_desired) >= tolerance) then + if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then call fatal_error("MGXS library does not contain cross sections & &for " // trim(this % name) // " at or near " // & trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") @@ -1326,7 +1325,7 @@ module mgxs_header call fatal_error("Nuclear data library does not contain cross sections & &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired))) // " K.") + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") end select select type(nuc) @@ -1568,7 +1567,7 @@ module mgxs_header allocate(nuc_ts(1)) nuc_ts(1) = minloc(abs(nuc % kTs - temp_desired), dim=1) temp_actual = nuc % kTs(nuc_ts(1)) - if (abs(temp_actual - temp_desired) >= tolerance) then + if (abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) then call fatal_error("MGXS library does not contain cross sections & &for " // trim(this % name) // " at or near " // & trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") @@ -1590,7 +1589,7 @@ module mgxs_header call fatal_error("Nuclear data library does not contain cross sections & &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired))) // " K.") + trim(to_str(nint(temp_desired / K_BOLTZMANN))) // " K.") end select ! Copy atom density of nuclide in material From 5555cfd1aaefcccdc9dcaeba847dc8d38ee21dc0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 30 Sep 2016 14:44:44 -0500 Subject: [PATCH 32/82] Respond to @smharper comments on #721 --- openmc/data/nbody.py | 4 ++-- openmc/data/reaction.py | 4 +--- openmc/data/reconstruct.pyx | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index 6616b1858d..b186c253a5 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -18,7 +18,7 @@ class NBodyPhaseSpace(AngleEnergy): atomic_weight_ratio : float Atomic weight ratio of target nuclide q_value : float - Q value for reaction in MeV + Q value for reaction in MeV or eV, depending on the data source. Attributes ---------- @@ -29,7 +29,7 @@ class NBodyPhaseSpace(AngleEnergy): atomic_weight_ratio : float Atomic weight ratio of target nuclide q_value : float - Q value for reaction in MeV + Q value for reaction in MeV or eV, depending on the data source. """ diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index cef6351352..fa55fbab92 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -663,9 +663,7 @@ class Reaction(EqualityMixin): mt : int The ENDF MT number for this reaction. q_value : float - The Q-value of this reaction in MeV. - threshold : float - Threshold of the reaction in MeV + The Q-value of this reaction in MeV or eV, depending on the data source. xs : dict of str to openmc.data.Function1D Microscopic cross section for this reaction as a function of incident energy; these cross sections are provided in a dictionary where the key diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx index 452968d145..f63a155b15 100644 --- a/openmc/data/reconstruct.pyx +++ b/openmc/data/reconstruct.pyx @@ -15,8 +15,8 @@ cdef extern from "complex.h": double complex cexp(double complex) # Physical constants are from CODATA 2014 -cdef double NEUTRON_MASS_ENERGY = 939.5654133e6 # MeV/c^2 -cdef double HBAR_C = 197.3269788e5 # MeV-b^0.5 +cdef double NEUTRON_MASS_ENERGY = 939.5654133e6 # eV/c^2 +cdef double HBAR_C = 197.3269788e5 # eV-b^0.5 @cython.cdivision(True) From a7d8a49e07c2ed3aa9eba94044d4b92762be9611 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 4 Oct 2016 23:08:34 -0500 Subject: [PATCH 33/82] Describe skipC argument in get_cont_record --- openmc/data/endf.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index ba398598d8..0940fcc8ec 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -104,6 +104,9 @@ def get_cont_record(file_obj, skipC=False): ---------- file_obj : file-like object ENDF-6 file to read from + skipC : bool + Determine whether to skip the first two quantities (C1, C2) of the CONT + record. Returns ------- From cbd2637efc4dfdd52ce3f4dc6469dba761cdcbaf Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Oct 2016 15:08:59 -0500 Subject: [PATCH 34/82] Handle energy-dependent delayed neutron group probabilities in ENDF files. --- openmc/data/reaction.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index fa55fbab92..081cbc2451 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -419,8 +419,37 @@ def _get_fission_products_endf(ev): dist = UncorrelatedAngleEnergy() dist.energy = EnergyDistribution.from_endf(file_obj, params) - delayed_neutron = products[-6 + i] - delayed_neutron.yield_.y *= applicability.y[0] + delayed_neutron = products[1 + i] + yield_ = delayed_neutron.yield_ + + # Here we handle the fact that the delayed neutron yield is the + # product of the total delayed neutron yield and the + # "applicability" of the energy distribution law in file 5. + if isinstance(yield_, Tabulated1D): + if np.all(applicability.y == applicability.y[0]): + yield_.y *= applicability.y[0] + else: + # Get union energy grid and ensure energies are within + # interpolable range of both functions + max_energy = min(yield_.x[-1], applicability.x[-1]) + energy = np.union1d(yield_.x, applicability.x) + energy = energy[energy <= max_energy] + + # Calculate group yield + group_yield = yield_(energy) * applicability(energy) + delayed_neutron.yield_ = Tabulated1D(energy, group_yield) + elif isinstance(yield_, Polynomial): + if len(yield_) == 1: + delayed_neutron.yield_ = deepcopy(applicability) + delayed_neutron.yield_.y *= yield_.coef[0] + else: + if np.all(applicability.y == applicability.y[0]): + yield_.coef[0] *= applicability.y[0] + else: + raise NotImplementedError( + 'Total delayed neutron yield and delayed group ' + 'probability are both energy-dependent.') + delayed_neutron.distribution.append(dist) return products, derived_products From b3e351474c50f7cb5283890a5f2c5fa912c06391 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Oct 2016 15:10:12 -0500 Subject: [PATCH 35/82] Handle Sher-Beck energy release data with polynomial nu. --- openmc/data/fission_energy.py | 38 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index c7f71b6573..9479e67313 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -405,27 +405,35 @@ class FissionEnergyRelease(EqualityMixin): # MT=18 (n, fission) might not be available so try MT=19 (n, f) as # well. if 18 in incident_neutron.reactions: - nu_prompt = [p for p in incident_neutron[18].products - if p.particle == 'neutron' - and p.emission_mode == 'prompt'] + nu = [p.yield_ for p in incident_neutron[18].products + if p.particle == 'neutron' + and p.emission_mode in ('prompt', 'total')] elif 19 in incident_neutron.reactions: - nu_prompt = [p for p in incident_neutron[19].products - if p.particle == 'neutron' - and p.emission_mode == 'prompt'] + nu = [p.yield_ for p in incident_neutron[19].products + if p.particle == 'neutron' + and p.emission_mode in ('prompt', 'total')] else: raise ValueError('IncidentNeutron data has no fission ' 'reaction.') - if len(nu_prompt) == 0: + if len(nu) == 0: raise ValueError('Nu data is needed to compute fission energy ' 'release with the Sher-Beck format.') - if len(nu_prompt) > 1: - raise ValueError('Ambiguous prompt value.') - if not isinstance(nu_prompt[0].yield_, Tabulated1D): - raise TypeError('Sher-Beck fission energy release currently ' - 'only supports Tabulated1D nu data.') - ENP = deepcopy(nu_prompt[0].yield_) - ENP.y = (energy_release['ENP'] + 1.307 * ENP.x - - 8.07 * (ENP.y - ENP.y[0])) + if len(nu) > 1: + raise ValueError('Ambiguous prompt/total nu value.') + + nu = nu[0] + if isinstance(nu, Tabulated1D): + ENP = deepcopy(nu) + ENP.y = (energy_release['ENP'] + 1.307 * nu.x + - 8.07 * (nu.y - nu.y[0])) + elif isinstance(nu, Polynomial): + if len(nu) == 1: + ENP = Polynomial([energy_release['ENP'][0], 1.307]) + else: + ENP = Polynomial( + [energy_release['ENP'][0], 1.307 - 8.07*nu.coef[1]] + + [-8.07*c for c in nu.coef[2:]]) + out.prompt_neutrons = ENP return out From 9079ae7b7478919d2cba685d3cdf491f6bc13738 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Oct 2016 15:10:41 -0500 Subject: [PATCH 36/82] Ignore obsolete energy transformation matrix in MF=4. --- openmc/data/angle_distribution.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 0f0105c2a5..669951059c 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -1,6 +1,7 @@ from collections import Iterable from io import StringIO from numbers import Real +from warnings import warn import numpy as np @@ -224,13 +225,23 @@ class AngleDistribution(EqualityMixin): # Read HEAD record items = get_head_record(file_obj) + lvt = items[2] ltt = items[3] # Read CONT record items = get_cont_record(file_obj) li = items[2] + nk = items[4] center_of_mass = (items[3] == 2) + # Check for obsolete energy transformation matrix. If present, just skip + # it and keep reading + if lvt > 0: + warn('Obsolete energy transformation matrix in MF=4 angular ' + 'distribution.') + for _ in range((nk + 5)//6): + file_obj.readline() + if ltt == 0 and li == 1: # Purely isotropic energy = np.array([0., ev.info['energy_max']]) From 348685057a3638bed5b64faa392f43da5ad9b717 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 16:36:55 -0500 Subject: [PATCH 37/82] Handle missing MOD values in JEFF 3.2 gracefully --- openmc/data/endf.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openmc/data/endf.py b/openmc/data/endf.py index 0940fcc8ec..0c590be0a8 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -384,10 +384,17 @@ class Evaluation(object): # File numbers, reaction designations, and number of records for i in range(NXC): - items = get_cont_record(file_obj, skipC=True) - MF, MT, NC, MOD = items[2:6] - self.reaction_list.append((MF, MT, NC, MOD)) - + line = file_obj.readline() + mf = int(line[22:33]) + mt = int(line[33:44]) + nc = int(line[44:55]) + try: + mod = int(line[55:66]) + except ValueError: + # In JEFF 3.2, a few isotopes of U have MOD values that are + # missing. This prevents failure on these isotopes. + mod = 0 + self.reaction_list.append((mf, mt, nc, mod)) class Tabulated2D(object): From e2ff3a83572a00383f8e56aa629a0ecee13b1c22 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 16:47:33 -0500 Subject: [PATCH 38/82] Add error message when number of delayed fission spectra doesn't match number of precursor groups. --- openmc/data/reaction.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index 081cbc2451..af903fe8a1 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -413,7 +413,11 @@ def _get_fission_products_endf(ev): file_obj = StringIO(ev.section[5, 455]) items = get_head_record(file_obj) nk = items[4] - assert nk == len(decay_constants) + if nk != len(decay_constants): + raise ValueError( + 'Number of delayed neutron fission spectra ({}) does not ' + 'match number of delayed neutron precursors ({}).'.format( + nk, len(decay_constants))) for i in range(nk): params, applicability = get_tab1_record(file_obj) dist = UncorrelatedAngleEnergy() From aafc89d475e095a19778739ad77a1b36807ec275 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 17:07:32 -0500 Subject: [PATCH 39/82] Add instructions for installing from conda-forge --- docs/source/quickinstall.rst | 20 +++++++++++++++++++ docs/source/usersguide/install.rst | 32 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 7faa4978dd..8e970d9587 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -8,6 +8,26 @@ This quick install guide outlines the basic steps needed to install OpenMC on your computer. For more detailed instructions on configuring and installing OpenMC, see :ref:`usersguide_install` in the User's Manual. +---------------------------------------- +Installing on Linux/Mac with conda-forge +---------------------------------------- + +`Conda `_ is an open source package management +system and environment management system for installing multiple versions of +software packages and their dependencies and switching easily between them. If +you have `conda` installed on your system, OpenMC can be installed via the +`conda-forge` channel. First, add the `conda-forge` channel with: + +.. code-block:: sh + + conda config --add channels conda-forge + +OpenMC can then be installed with: + +.. code-block:: sh + + conda install openmc + -------------------------------- Installing on Ubuntu through PPA -------------------------------- diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 3dab08e9d3..5abd48ee0d 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -4,6 +4,38 @@ Installation and Configuration ============================== +---------------------------------------- +Installing on Linux/Mac with conda-forge +---------------------------------------- + +`Conda `_ is an open source package management +system and environment management system for installing multiple versions of +software packages and their dependencies and switching easily between +them. `conda-forge `_ is a community-led conda +channel of installable packages. For instructions on installing conda, please +consult their `documentation +`_. + +Once you have `conda` installed on your system, add the `conda-forge` channel to +your configuration with: + +.. code-block:: sh + + conda config --add channels conda-forge + +Once the `conda-forge` channel has been enabled, OpenMC can then be installed +with: + +.. code-block:: sh + + conda install openmc + +It is possible to list all of the versions of OpenMC available on your platform with: + +.. code-block:: sh + + conda search openmc --channel conda-forge + ----------------------------- Installing on Ubuntu with PPA ----------------------------- From f1ea8cfaaa6f694b5e829e1aeb98393166a694e9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 17:18:14 -0500 Subject: [PATCH 40/82] Move scripts in data/ folder to scripts/ --- data/readme.rst | 37 ------------------- docs/source/usersguide/install.rst | 34 +++++++---------- .../openmc-convert-mcnp70-data | 0 .../openmc-convert-mcnp71-data | 0 .../openmc-get-jeff-data | 0 .../openmc-get-multipole-data | 0 .../openmc-get-nndc-data | 0 7 files changed, 14 insertions(+), 57 deletions(-) delete mode 100644 data/readme.rst rename data/convert_mcnp_70.py => scripts/openmc-convert-mcnp70-data (100%) rename data/convert_mcnp_71.py => scripts/openmc-convert-mcnp71-data (100%) rename data/get_jeff_data.py => scripts/openmc-get-jeff-data (100%) rename data/get_multipole_data.py => scripts/openmc-get-multipole-data (100%) rename data/get_nndc_data.py => scripts/openmc-get-nndc-data (100%) diff --git a/data/readme.rst b/data/readme.rst deleted file mode 100644 index 03685491d0..0000000000 --- a/data/readme.rst +++ /dev/null @@ -1,37 +0,0 @@ -======================== -cross_sections.xml Files -======================== - -As a reminder, in order to run a simulation with OpenMC, you will need cross -section data for each nuclide in your problem. OpenMC is not currently -distributed with cross section data, so you will have to obtain cross section -data by other means. The `user's guide`_ offers some helpful advice on how you -can obtain cross sections. - -When OpenMC starts up, it needs a cross_sections.xml file that tells it where to -find ACE format cross sections. The files in this directory are configured to -work with a few common cross section sources. - -- **cross_sections_ascii.xml** -- This file matches ENDF/B-VII.0 cross sections - distributed with MCNP5 / MCNP6 beta. - -- **cross_sections_nndc.xml** -- This file matches ENDF/B-VII.1 cross sections - distributed from the `NNDC website`_. - -- **cross_sections_serpent.xml** -- This file matches ENDF/B-VII.0 cross - sections distributed with Serpent 1.1.7. - -- **cross_sections.xml** - This file matches ENDF/B-VII.0 cross sections - distributed with MCNP5 / MCNP6 beta *that have been converted to binary*. - -To use any of these files, you need to follow two steps: - -1. Change the path on the ```` element in the cross_sections.xml file -to the directory containing the ACE files. - -2. Enter the absolute path of the cross_sections.xml on the ```` -element in your settings.xml, or set the CROSS_SECTIONS environment variable to -the full path of the cross_sections.xml file. - -.. _user's guide: http://mit-crpg.github.io/openmc/usersguide/install.html#cross-section-configuration -.. _NNDC website: http://www.nndc.bnl.gov/endf/b7.1/acefiles.html diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 5abd48ee0d..0b75bf1904 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -439,13 +439,11 @@ extract the ACE data, fix any deficiencies, and create an HDF5 library: .. code-block:: sh - cd openmc/data - python get_nndc_data.py + openmc-get-nndc-data At this point, you should set the :envvar:`OPENMC_CROSS_SECTIONS` environment -variable to the absolute path of the file -``openmc/data/nndc_hdf5/cross_sections.xml``. This cross section set is used by -the test suite. +variable to the absolute path of the file ``nndc_hdf5/cross_sections.xml``. This +cross section set is used by the test suite. Using JEFF Cross Sections from OECD/NEA --------------------------------------- @@ -456,12 +454,10 @@ and extract the ACE data, fix any deficiencies, and create an HDF5 library. .. code-block:: sh - cd openmc/data - python get_jeff_data.py + openmc-get-jeff-data At this point, you should set the :envvar:`OPENMC_CROSS_SECTIONS` environment -variable to the absolute path of the file -``openmc/data/jeff-3.2-hdf5/cross_sections.xml``. +variable to the absolute path of the file ``jeff-3.2-hdf5/cross_sections.xml``. Using Cross Sections from MCNP ------------------------------ @@ -473,8 +469,7 @@ format, run the following: .. code-block:: sh - cd openmc/data - python convert_mcnp_endf70.py /path/to/mcnpdata/ + openmc-convert-mcnp70-data /path/to/mcnpdata/ where ``/path/to/mcnpdata`` is the directory containing the ``endf70[a-k]`` files. @@ -484,8 +479,7 @@ the following script: .. code-block:: sh - cd openmc/data - python convert_mcnp_endf71.py /path/to/mcnpdata + openmc-convert-mcnp71-data /path/to/mcnpdata where ``/path/to/mcnpdata`` is the directory containing the ``endf71x`` and ``ENDF71SaB`` directories. @@ -502,16 +496,16 @@ that are to be converted: 1. List each ACE library as a positional argument. This is very useful in conjunction with the usual shell utilities (ls, find, etc.). -2. Use the --xml option to specify a pre-v0.9 cross_sections.xml file. -3. Use the --xsdir option to specify a MCNP xsdir file. -4. Use the --xsdata option to specify a Serpent xsdata file. +2. Use the ``--xml`` option to specify a pre-v0.9 cross_sections.xml file. +3. Use the ``--xsdir` option to specify a MCNP xsdir file. +4. Use the ``--xsdata`` option to specify a Serpent xsdata file. The script does not use any extra information from cross_sections.xml/ xsdir/ xsdata files to determine whether the nuclide is metastable. Instead, the ---metastable argument can be used to specify whether the ZAID naming convention -follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the MCNP data -convention (essentially the same as NNDC, except that the first metastable state -of Am242 is 95242 and the ground state is 95642). +``--metastable`` argument can be used to specify whether the ZAID naming +convention follows the NNDC data convention (1000*Z + A + 300 + 100*m), or the +MCNP data convention (essentially the same as NNDC, except that the first +metastable state of Am242 is 95242 and the ground state is 95642). The ``openmc-ace-to-hdf5`` script has the following command-line flags: diff --git a/data/convert_mcnp_70.py b/scripts/openmc-convert-mcnp70-data similarity index 100% rename from data/convert_mcnp_70.py rename to scripts/openmc-convert-mcnp70-data diff --git a/data/convert_mcnp_71.py b/scripts/openmc-convert-mcnp71-data similarity index 100% rename from data/convert_mcnp_71.py rename to scripts/openmc-convert-mcnp71-data diff --git a/data/get_jeff_data.py b/scripts/openmc-get-jeff-data similarity index 100% rename from data/get_jeff_data.py rename to scripts/openmc-get-jeff-data diff --git a/data/get_multipole_data.py b/scripts/openmc-get-multipole-data similarity index 100% rename from data/get_multipole_data.py rename to scripts/openmc-get-multipole-data diff --git a/data/get_nndc_data.py b/scripts/openmc-get-nndc-data similarity index 100% rename from data/get_nndc_data.py rename to scripts/openmc-get-nndc-data From 24af2829b9dc637eeddcd6df06d0bf0be317e504 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 18:21:58 -0500 Subject: [PATCH 41/82] Add description in scripts and use six for imports --- .travis.yml | 2 +- scripts/openmc-convert-mcnp70-data | 19 ++++++++++++--- scripts/openmc-convert-mcnp71-data | 19 ++++++++++++--- scripts/openmc-get-jeff-data | 28 +++++++++++++--------- scripts/openmc-get-multipole-data | 35 ++++++++++++++------------- scripts/openmc-get-nndc-data | 38 +++++++++++++++++------------- setup.py | 2 +- 7 files changed, 91 insertions(+), 52 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46bb847e6a..19535d23b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ before_install: - conda config --set always_yes yes --set changeps1 no - conda update -q conda - conda info -a - - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy h5py=2.5 pandas + - conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION six numpy scipy h5py=2.5 pandas - source activate test-environment # Install GCC, MPICH, HDF5, PHDF5 diff --git a/scripts/openmc-convert-mcnp70-data b/scripts/openmc-convert-mcnp70-data index e68bd848e1..a3081e3ee1 100755 --- a/scripts/openmc-convert-mcnp70-data +++ b/scripts/openmc-convert-mcnp70-data @@ -1,7 +1,7 @@ #!/usr/bin/env python from __future__ import print_function -from argparse import ArgumentParser +import argparse from collections import defaultdict import glob import os @@ -9,8 +9,21 @@ import os import openmc.data -# Get path to MCNP data -parser = ArgumentParser() +description = """ +Convert ENDF/B-VII.0 ACE data from the MCNP5/6 distribution into an HDF5 library +that can be used by OpenMC. This assumes that you have a directory containing +files named endf70a, endf70b, ..., endf70k, and endf70sab. + +""" + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + +parser = argparse.ArgumentParser( + description=description, + formatter_class=CustomFormatter +) parser.add_argument('-d', '--destination', default='mcnp_endfb70', help='Directory to create new library in') parser.add_argument('mcnpdata', help='Directory containing endf70[a-k] and endf70sab') diff --git a/scripts/openmc-convert-mcnp71-data b/scripts/openmc-convert-mcnp71-data index 7e7fd923f1..9440959197 100755 --- a/scripts/openmc-convert-mcnp71-data +++ b/scripts/openmc-convert-mcnp71-data @@ -1,7 +1,7 @@ #!/usr/bin/env python from __future__ import print_function -from argparse import ArgumentParser +import argparse from collections import defaultdict import glob import os @@ -9,8 +9,21 @@ import os import openmc.data -# Get path to MCNP data -parser = ArgumentParser() +description = """ +Convert ENDF/B-VII.1 ACE data from the MCNP6 distribution into an HDF5 library +that can be used by OpenMC. This assumes that you have a directory containing +subdirectories 'endf71x' and 'ENDF71SaB'. + +""" + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + +parser = argparse.ArgumentParser( + description=description, + formatter_class=CustomFormatter +) parser.add_argument('-d', '--destination', default='mcnp_endfb71', help='Directory to create new library in') parser.add_argument('-f', '--fission_energy_release', diff --git a/scripts/openmc-get-jeff-data b/scripts/openmc-get-jeff-data index d0e5839b93..3166b3854e 100755 --- a/scripts/openmc-get-jeff-data +++ b/scripts/openmc-get-jeff-data @@ -10,18 +10,17 @@ import glob import argparse from string import digits +from six.moves import input +from six.moves.urllib.request import urlopen + import openmc.data -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen -if sys.version_info[0] < 3: - askuser = raw_input -else: - askuser = input +description = """ +Download JEFF 3.2 ACE data from OECD/NEA and convert it to a multi-temperature +HDF5 library for use with OpenMC. +""" download_warning = """ WARNING: This script will download approximately 9 GB of data. Extracting and @@ -32,14 +31,21 @@ space. Note that if you don't need all 11 temperatures, you can modify the Are you sure you want to continue? ([y]/n) """ -parser = argparse.ArgumentParser() +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + +parser = argparse.ArgumentParser( + description=description, + formatter_class=CustomFormatter +) parser.add_argument('-b', '--batch', action='store_true', help='supresses standard in') parser.add_argument('-d', '--destination', default='jeff-3.2-hdf5', help='Directory to create new library in') args = parser.parse_args() -response = askuser(download_warning) if not args.batch else 'y' +response = input(download_warning) if not args.batch else 'y' if response.lower().startswith('n'): sys.exit() @@ -82,7 +88,7 @@ for f in files: files_complete.append(f) continue else: - overwrite = askuser('Overwrite {}? ([y]/n) '.format(f)) + overwrite = input('Overwrite {}? ([y]/n) '.format(f)) if overwrite.lower().startswith('n'): continue diff --git a/scripts/openmc-get-multipole-data b/scripts/openmc-get-multipole-data index d51c196dcc..bf0add2840 100755 --- a/scripts/openmc-get-multipole-data +++ b/scripts/openmc-get-multipole-data @@ -10,18 +10,27 @@ import glob import hashlib import argparse -parser = argparse.ArgumentParser() +from six.moves import input +from six.moves.urllib.request import urlopen + + +description = """ +Download and extract windowed multipole data based on ENDF/B-VII.1. + +""" + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + +parser = argparse.ArgumentParser( + description=description, + formatter_class=CustomFormatter +) parser.add_argument('-b', '--batch', action='store_true', help='supresses standard in') args = parser.parse_args() -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen - -cwd = os.getcwd() -sys.path.insert(0, os.path.join(cwd, '..')) baseUrl = 'https://github.com/smharper/windowed_multipole_library/blob/master/' files = ['multipole_lib.tar.gz?raw=true'] @@ -54,10 +63,7 @@ for f in files: filesComplete.append(fname) continue else: - if sys.version_info[0] < 3: - overwrite = raw_input('Overwrite {0}? ([y]/n) '.format(fname)) - else: - overwrite = input('Overwrite {0}? ([y]/n) '.format(fname)) + overwrite = input('Overwrite {0}? ([y]/n) '.format(fname)) if overwrite.lower().startswith('n'): continue @@ -110,10 +116,7 @@ os.rmdir('wmp/multipole_lib') # Ask user to delete if not args.batch: - if sys.version_info[0] < 3: - response = raw_input('Delete *.tar.gz files? ([y]/n) ') - else: - response = input('Delete *.tar.gz files? ([y]/n) ') + response = input('Delete *.tar.gz files? ([y]/n) ') else: response = 'y' diff --git a/scripts/openmc-get-nndc-data b/scripts/openmc-get-nndc-data index 5bec3865ec..5231b67ef0 100755 --- a/scripts/openmc-get-nndc-data +++ b/scripts/openmc-get-nndc-data @@ -10,15 +10,28 @@ import glob import hashlib import argparse -parser = argparse.ArgumentParser() +from six.moves import input +from six.moves.urllib.request import urlopen + + +description = """ +Download ENDF/B-VII.1 ACE data from NNDC and convert it to an HDF5 library for +use with OpenMC. + +""" + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + +parser = argparse.ArgumentParser( + description=description, + formatter_class=CustomFormatter +) parser.add_argument('-b', '--batch', action='store_true', help='supresses standard in') args = parser.parse_args() -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen baseUrl = 'http://www.nndc.bnl.gov/endf/b7.1/aceFiles/' files = ['ENDF-B-VII.1-neutron-293.6K.tar.gz', @@ -50,10 +63,7 @@ for f in files: filesComplete.append(f) continue else: - if sys.version_info[0] < 3: - overwrite = raw_input('Overwrite {0}? ([y]/n) '.format(f)) - else: - overwrite = input('Overwrite {0}? ([y]/n) '.format(f)) + overwrite = input('Overwrite {0}? ([y]/n) '.format(f)) if overwrite.lower().startswith('n'): continue @@ -115,10 +125,7 @@ with open(graphite, 'w') as fh: # Ask user to delete if not args.batch: - if sys.version_info[0] < 3: - response = raw_input('Delete *.tar.gz files? ([y]/n) ') - else: - response = input('Delete *.tar.gz files? ([y]/n) ') + response = input('Delete *.tar.gz files? ([y]/n) ') else: response = 'y' @@ -134,10 +141,7 @@ if not response or response.lower().startswith('y'): # Ask user to convert if not args.batch: - if sys.version_info[0] < 3: - response = raw_input('Generate HDF5 library? ([y]/n) ') - else: - response = input('Generate HDF5 library? ([y]/n) ') + response = input('Generate HDF5 library? ([y]/n) ') else: response = 'y' diff --git a/setup.py b/setup.py index 4479bb82c5..fd6a2e1a37 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ kwargs = {'name': 'openmc', if have_setuptools: kwargs.update({ # Required dependencies - 'install_requires': ['numpy>=1.9', 'h5py', 'matplotlib'], + 'install_requires': ['six', 'numpy>=1.9', 'h5py', 'matplotlib'], # Optional dependencies 'extras_require': { From de009f4c34a322a6a4efc6e8f11668c09e318fa5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 18:30:42 -0500 Subject: [PATCH 42/82] Use six.add_metaclass to be compatible with Python 2 and 3 --- openmc/data/angle_energy.py | 6 +++--- openmc/data/energy_distribution.py | 5 ++--- openmc/data/function.py | 5 ++--- openmc/filter.py | 9 +++------ openmc/lattice.py | 6 ++---- openmc/mgxs/mdgxs.py | 6 ++---- openmc/mgxs/mgxs.py | 13 ++++--------- openmc/model/triso.py | 5 ++--- openmc/region.py | 5 ++--- openmc/stats/multivariate.py | 9 +++------ openmc/stats/univariate.py | 5 ++--- openmc/surface.py | 10 +++------- 12 files changed, 30 insertions(+), 54 deletions(-) diff --git a/openmc/data/angle_energy.py b/openmc/data/angle_energy.py index 4a5e391e3f..66fb89a53a 100644 --- a/openmc/data/angle_energy.py +++ b/openmc/data/angle_energy.py @@ -1,14 +1,14 @@ from abc import ABCMeta, abstractmethod +from six import add_metaclass + import openmc.data from openmc.mixin import EqualityMixin +@add_metaclass(ABCMeta) class AngleEnergy(EqualityMixin): """Distribution in angle and energy of a secondary particle.""" - - __metaclass = ABCMeta - @abstractmethod def to_hdf5(self, group): pass diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index a160906353..255b253bae 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -3,6 +3,7 @@ from collections import Iterable from numbers import Integral, Real from warnings import warn +from six import add_metaclass import numpy as np from .function import Tabulated1D, INTERPOLATION_SCHEME @@ -11,11 +12,9 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin +@add_metaclass(ABCMeta) class EnergyDistribution(EqualityMixin): """Abstract superclass for all energy distributions.""" - - __metaclass__ = ABCMeta - def __init__(self): pass diff --git a/openmc/data/function.py b/openmc/data/function.py index 94a2f0911e..8e539b9088 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -2,6 +2,7 @@ from abc import ABCMeta, abstractmethod from collections import Iterable, Callable from numbers import Real, Integral +from six import add_metaclass import numpy as np import openmc.checkvalue as cv @@ -11,11 +12,9 @@ INTERPOLATION_SCHEME = {1: 'histogram', 2: 'linear-linear', 3: 'linear-log', 4: 'log-linear', 5: 'log-log'} +@add_metaclass(ABCMeta) class Function1D(EqualityMixin): """A function of one independent variable with HDF5 support.""" - - __metaclass__ = ABCMeta - @abstractmethod def __call__(self): pass diff --git a/openmc/filter.py b/openmc/filter.py index d11af96f52..72a7db47ae 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -1,21 +1,17 @@ from abc import ABCMeta, abstractproperty from collections import Iterable, OrderedDict import copy -from six import with_metaclass from numbers import Real, Integral import sys from xml.etree import ElementTree as ET +from six import add_metaclass import numpy as np import openmc import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str - - _FILTER_TYPES = ['universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup'] @@ -37,7 +33,8 @@ class FilterMeta(ABCMeta): **kwargs) -class Filter(with_metaclass(FilterMeta, object)): +@add_metaclass(FilterMeta) +class Filter(object): """Tally modifier that describes phase-space and other characteristics. Parameters diff --git a/openmc/lattice.py b/openmc/lattice.py index c6a5af4109..20fd57442d 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -7,6 +7,7 @@ from numbers import Real, Integral from xml.etree import ElementTree as ET import sys +from six import ABCMeta import numpy as np import openmc.checkvalue as cv @@ -16,6 +17,7 @@ if sys.version_info[0] >= 3: basestring = str +@add_metaclass(ABCMeta) class Lattice(object): """A repeating structure wherein each element is a universe. @@ -42,10 +44,6 @@ class Lattice(object): of the lattice """ - - # This is an abstract class which cannot be instantiated - __metaclass__ = abc.ABCMeta - def __init__(self, lattice_id=None, name=''): # Initialize Lattice class attributes self.id = lattice_id diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 2c616b3682..bb6822d92c 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -8,6 +8,7 @@ import sys import copy import abc +from six import ABCMeta import numpy as np import openmc @@ -28,6 +29,7 @@ MDGXS_TYPES = ['delayed-nu-fission', MAX_DELAYED_GROUPS = 8 +@add_metaclass(ABCMeta) class MDGXS(MGXS): """An abstract multi-delayed-group cross section for some energy and delayed group structures within some spatial domain. @@ -117,10 +119,6 @@ class MDGXS(MGXS): The key used to index multi-group cross sections in an HDF5 data store """ - - # This is an abstract class which cannot be instantiated - __metaclass__ = abc.ABCMeta - def __init__(self, domain=None, domain_type=None, energy_groups=None, delayed_groups=None, by_nuclide=False, name=''): super(MDGXS, self).__init__(domain, domain_type, energy_groups, diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 65802f2ef0..1520f81d11 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -9,6 +9,7 @@ import copy import abc import itertools +from six import add_metaclass import numpy as np import openmc @@ -61,6 +62,7 @@ _DOMAINS = (openmc.Cell, openmc.Mesh) +@add_metaclass(ABCMeta) class MGXS(object): """An abstract multi-group cross section for some energy group structure within some spatial domain. @@ -145,10 +147,6 @@ class MGXS(object): The key used to index multi-group cross sections in an HDF5 data store """ - - # This is an abstract class which cannot be instantiated - __metaclass__ = abc.ABCMeta - def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name=''): self._name = '' @@ -1530,7 +1528,7 @@ class MGXS(object): # Override energy groups bounds with indices all_groups = np.arange(self.num_groups, 0, -1, dtype=np.int) - all_groups = np.repeat(all_groups, len(query_nuclides)) + all_groups = np.repeat(all_groups, len(query_nuclides)) if 'energy low [MeV]' in df and 'energyout low [MeV]' in df: df.rename(columns={'energy low [MeV]': 'group in'}, inplace=True) @@ -1616,6 +1614,7 @@ class MGXS(object): return 'cm^-1' if xs_type == 'macro' else 'barns' +@add_metaclass(ABCMeta) class MatrixMGXS(MGXS): """An abstract multi-group cross section for some energy group structure within some spatial domain. This class is specifically intended for @@ -1703,10 +1702,6 @@ class MatrixMGXS(MGXS): The key used to index multi-group cross sections in an HDF5 data store """ - - # This is an abstract class which cannot be instantiated - __metaclass__ = abc.ABCMeta - @property def filters(self): # Create the non-domain specific Filters for the Tallies diff --git a/openmc/model/triso.py b/openmc/model/triso.py index 5525ea559c..046bd45159 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -10,6 +10,7 @@ from heapq import heappush, heappop from math import pi, sin, cos, floor, log10, sqrt from abc import ABCMeta, abstractproperty, abstractmethod +from six import add_metaclass import numpy as np try: import scipy.spatial @@ -95,6 +96,7 @@ class TRISO(openmc.Cell): k_min:k_max+1, j_min:j_max+1, i_min:i_max+1])) +@add_metaclass(ABCMeta) class _Domain(object): """Container in which to pack particles. @@ -123,9 +125,6 @@ class _Domain(object): Volume of the container. """ - - __metaclass__ = ABCMeta - def __init__(self, particle_radius, center=[0., 0., 0.]): self._cell_length = None self._limits = None diff --git a/openmc/region.py b/openmc/region.py index a1b9e9fd0d..ce970f8120 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,11 +1,13 @@ from abc import ABCMeta, abstractmethod from collections import Iterable +from six import add_metaclass import numpy as np from openmc.checkvalue import check_type +@add_metaclass(ABCMeta) class Region(object): """Region of space that can be assigned to a cell. @@ -16,9 +18,6 @@ class Region(object): created through operators of the Surface and Region classes. """ - - __metaclass__ = ABCMeta - def __and__(self, other): return Intersection(self, other) diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index e49a94ee19..fdae6c789e 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -5,6 +5,7 @@ from numbers import Real import sys from xml.etree import ElementTree as ET +from six import add_metaclass import numpy as np import openmc.checkvalue as cv @@ -14,6 +15,7 @@ if sys.version_info[0] >= 3: basestring = str +@add_metaclass(ABCMeta) class UnitSphere(object): """Distribution of points on the unit sphere. @@ -31,9 +33,6 @@ class UnitSphere(object): Direction from which polar angle is measured """ - - __metaclass__ = ABCMeta - def __init__(self, reference_uvw=None): self._reference_uvw = None if reference_uvw is not None: @@ -184,6 +183,7 @@ class Monodirectional(UnitSphere): return element +@add_metaclass(ABCMeta) class Spatial(object): """Distribution of locations in three-dimensional Euclidean space. @@ -191,9 +191,6 @@ class Spatial(object): distributions of source sites. """ - - __metaclass__ = ABCMeta - def __init__(self): pass diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index ce0f0fae1d..2fabde8c5f 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -4,6 +4,7 @@ from numbers import Real import sys from xml.etree import ElementTree as ET +from six import add_metaclass import numpy as np import openmc.checkvalue as cv @@ -16,6 +17,7 @@ _INTERPOLATION_SCHEMES = ['histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'] +@add_metaclass(ABCMeta) class Univariate(EqualityMixin): """Probability distribution of a single random variable. @@ -23,9 +25,6 @@ class Univariate(EqualityMixin): specific probability distribution. """ - - __metaclass__ = ABCMeta - def __init__(self): pass diff --git a/openmc/surface.py b/openmc/surface.py index c33c4ee74c..8745a1867b 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,6 +4,7 @@ from xml.etree import ElementTree as ET import sys from math import sqrt +from six import add_metaclass import numpy as np from openmc.checkvalue import check_type, check_value, check_greater_than @@ -642,6 +643,7 @@ class ZPlane(Plane): return point[2] - self.z0 +@add_metaclass(ABCMeta) class Cylinder(Surface): """A cylinder whose length is parallel to the x-, y-, or z-axis. @@ -677,9 +679,6 @@ class Cylinder(Surface): Type of the surface """ - - __metaclass__ = ABCMeta - def __init__(self, surface_id=None, boundary_type='transmission', R=1., name=''): super(Cylinder, self).__init__(surface_id, boundary_type, name=name) @@ -1210,7 +1209,7 @@ class Sphere(Surface): z = point[2] - self.z0 return x**2 + y**2 + z**2 - self.r**2 - +@add_metaclass(ABCMeta) class Cone(Surface): """A conical surface parallel to the x-, y-, or z-axis. @@ -1257,9 +1256,6 @@ class Cone(Surface): Type of the surface """ - - __metaclass__ = ABCMeta - def __init__(self, surface_id=None, boundary_type='transmission', x0=0., y0=0., z0=0., R2=1., name=''): super(Cone, self).__init__(surface_id, boundary_type, name=name) From 5a126d086e7a611cde23dba5aa27bda072d9a5d5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 21:39:57 -0500 Subject: [PATCH 43/82] Use six.string_types instead of basestring --- openmc/arithmetic.py | 23 ++++++------- openmc/cell.py | 10 +++--- openmc/cmfd.py | 7 ++-- openmc/data/ace.py | 7 ++-- openmc/data/fission_energy.py | 3 -- openmc/data/neutron.py | 8 ++--- openmc/data/product.py | 6 ++-- openmc/data/reaction.py | 3 +- openmc/element.py | 10 +++--- openmc/executor.py | 5 ++- openmc/lattice.py | 9 ++--- openmc/macroscopic.py | 9 +++-- openmc/material.py | 17 +++++---- openmc/mesh.py | 8 ++--- openmc/mgxs/groups.py | 4 --- openmc/mgxs/library.py | 27 +++++++-------- openmc/mgxs/mdgxs.py | 38 ++++++++++---------- openmc/mgxs/mgxs.py | 65 +++++++++++++++++------------------ openmc/mgxs_library.py | 7 ++-- openmc/nuclide.py | 9 +++-- openmc/plots.py | 15 ++++---- openmc/settings.py | 10 +++--- openmc/source.py | 7 ++-- openmc/statepoint.py | 3 -- openmc/stats/multivariate.py | 3 -- openmc/stats/univariate.py | 2 -- openmc/surface.py | 8 ++--- openmc/tallies.py | 28 +++++++-------- openmc/trigger.py | 7 ++-- openmc/universe.py | 5 ++- 30 files changed, 154 insertions(+), 209 deletions(-) diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 1632520c5f..f549537206 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -2,14 +2,13 @@ import sys import copy from collections import Iterable +from six import string_types import numpy as np import openmc from openmc.filter import _FILTER_TYPES import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str # Acceptable tally arithmetic binary operations _TALLY_ARITHMETIC_OPS = ['+', '-', '*', '/', '^'] @@ -86,18 +85,18 @@ class CrossScore(object): @left_score.setter def left_score(self, left_score): cv.check_type('left_score', left_score, - (basestring, CrossScore, AggregateScore)) + string_types + (CrossScore, AggregateScore)) self._left_score = left_score @right_score.setter def right_score(self, right_score): cv.check_type('right_score', right_score, - (basestring, CrossScore, AggregateScore)) + string_types + (CrossScore, AggregateScore)) self._right_score = right_score @binary_op.setter def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, basestring) + cv.check_type('binary_op', binary_op, string_types) cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) self._binary_op = binary_op @@ -202,7 +201,7 @@ class CrossNuclide(object): @binary_op.setter def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, basestring) + cv.check_type('binary_op', binary_op, string_types) cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) self._binary_op = binary_op @@ -343,7 +342,7 @@ class CrossFilter(object): @binary_op.setter def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, basestring) + cv.check_type('binary_op', binary_op, string_types) cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) self._binary_op = binary_op @@ -495,12 +494,12 @@ class AggregateScore(object): @scores.setter def scores(self, scores): - cv.check_iterable_type('scores', scores, basestring) + cv.check_iterable_type('scores', scores, string_types) self._scores = scores @aggregate_op.setter def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, (basestring, CrossScore)) + cv.check_type('aggregate_op', aggregate_op, string_types +(CrossScore,)) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op @@ -575,12 +574,12 @@ class AggregateNuclide(object): @nuclides.setter def nuclides(self, nuclides): cv.check_iterable_type('nuclides', nuclides, - (basestring, openmc.Nuclide, CrossNuclide)) + string_types + (openmc.Nuclide, CrossNuclide)) self._nuclides = nuclides @aggregate_op.setter def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, basestring) + cv.check_type('aggregate_op', aggregate_op, string_types) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op @@ -711,7 +710,7 @@ class AggregateFilter(object): @aggregate_op.setter def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, basestring) + cv.check_type('aggregate_op', aggregate_op, string_types) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op diff --git a/openmc/cell.py b/openmc/cell.py index 1cfc09f372..f950963d27 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -5,6 +5,7 @@ from xml.etree import ElementTree as ET import sys import warnings +from six import string_types import numpy as np import openmc @@ -12,9 +13,6 @@ import openmc.checkvalue as cv from openmc.surface import Halfspace from openmc.region import Region, Intersection, Complement -if sys.version_info[0] >= 3: - basestring = str - # A static variable for auto-generated Cell IDs AUTO_CELL_ID = 10000 @@ -243,7 +241,7 @@ class Cell(object): @name.setter def name(self, name): if name is not None: - cv.check_type('cell name', name, basestring) + cv.check_type('cell name', name, string_types) self._name = name else: self._name = '' @@ -251,7 +249,7 @@ class Cell(object): @fill.setter def fill(self, fill): if fill is not None: - if isinstance(fill, basestring): + if isinstance(fill, string_types): if fill.strip().lower() != 'void': msg = 'Unable to set Cell ID="{0}" to use a non-Material ' \ 'or Universe fill "{1}"'.format(self._id, fill) @@ -336,7 +334,7 @@ class Cell(object): @distribcell_paths.setter def distribcell_paths(self, distribcell_paths): cv.check_iterable_type('distribcell_paths', distribcell_paths, - basestring) + string_types) self._distribcell_paths = distribcell_paths def add_surface(self, surface, halfspace): diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 76d8685ff1..51acf4d426 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -15,13 +15,12 @@ from numbers import Real, Integral from xml.etree import ElementTree as ET import sys +from six import string_types + from openmc.clean_xml import clean_xml_indentation from openmc.checkvalue import (check_type, check_length, check_value, check_greater_than, check_less_than) -if sys.version_info[0] >= 3: - basestring = str - class CMFDMesh(object): """A structured Cartesian mesh used for Coarse Mesh Finite Difference (CMFD) @@ -339,7 +338,7 @@ class CMFD(object): @display.setter def display(self, display): - check_type('CMFD display', display, basestring) + check_type('CMFD display', display, string_types) check_value('CMFD display', display, ['balance', 'dominance', 'entropy', 'source']) self._display = display diff --git a/openmc/data/ace.py b/openmc/data/ace.py index 831e40fc81..d7ec97edce 100644 --- a/openmc/data/ace.py +++ b/openmc/data/ace.py @@ -20,15 +20,12 @@ from os import SEEK_CUR import struct import sys +from six import string_types import numpy as np from openmc.mixin import EqualityMixin -if sys.version_info[0] >= 3: - basestring = str - - def ascii_to_binary(ascii_file, binary_file): """Convert an ACE file in ASCII format (type 1) to binary format (type 2). @@ -156,7 +153,7 @@ class Library(EqualityMixin): """ def __init__(self, filename, table_names=None, verbose=False): - if isinstance(table_names, basestring): + if isinstance(table_names, string_types): table_names = [table_names] if table_names is not None: table_names = set(table_names) diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 6352915cc6..b527629e23 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -11,9 +11,6 @@ from .function import Function1D, Tabulated1D, Polynomial, Sum import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -if sys.version_info[0] >= 3: - basestring = str - def _extract_458_data(filename): """Read an ENDF file and extract the MF=1, MT=458 values. diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index c638dfd9bd..9004eb3c7c 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -5,6 +5,7 @@ from itertools import chain from numbers import Integral, Real from warnings import warn +from six import string_types import numpy as np import h5py @@ -18,9 +19,6 @@ from .urr import ProbabilityTables import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -if sys.version_info[0] >= 3: - basestring = str - def _get_metadata(zaid, metastable_scheme='nndc'): """Return basic identifying data for a nuclide with a given ZAID. @@ -226,7 +224,7 @@ class IncidentNeutron(EqualityMixin): @name.setter def name(self, name): - cv.check_type('name', name, basestring) + cv.check_type('name', name, string_types) self._name = name @property @@ -277,7 +275,7 @@ class IncidentNeutron(EqualityMixin): def urr(self, urr): cv.check_type('probability table dictionary', urr, MutableMapping) for key, value in urr: - cv.check_type('probability table temperature', key, basestring) + cv.check_type('probability table temperature', key, string_types) cv.check_type('probability tables', value, ProbabilityTables) self._urr = urr diff --git a/openmc/data/product.py b/openmc/data/product.py index 753888f6df..483358c28b 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -2,6 +2,7 @@ from collections import Iterable from numbers import Real import sys +from six import string_types import numpy as np import openmc.checkvalue as cv @@ -9,9 +10,6 @@ from openmc.mixin import EqualityMixin from .function import Tabulated1D, Polynomial, Function1D from .angle_energy import AngleEnergy -if sys.version_info[0] >= 3: - basestring = str - class Product(EqualityMixin): """Secondary particle emitted in a nuclear reaction @@ -114,7 +112,7 @@ class Product(EqualityMixin): @particle.setter def particle(self, particle): - cv.check_type('product particle type', particle, basestring) + cv.check_type('product particle type', particle, string_types) self._particle = particle @yield_.setter diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index eb33e1395f..cfebda374d 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -4,6 +4,7 @@ from copy import deepcopy from numbers import Real, Integral from warnings import warn +from six import string_types import numpy as np import openmc.checkvalue as cv @@ -349,7 +350,7 @@ class Reaction(EqualityMixin): def xs(self, xs): cv.check_type('reaction cross section dictionary', xs, MutableMapping) for key, value in xs.items(): - cv.check_type('reaction cross section temperature', key, basestring) + cv.check_type('reaction cross section temperature', key, string_types) cv.check_type('reaction cross section', value, Function1D) self._xs = xs diff --git a/openmc/element.py b/openmc/element.py index 1b16806148..e1484198cf 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -1,14 +1,12 @@ import re import sys +from six import string_types + import openmc from openmc.checkvalue import check_type, check_length from openmc.data import NATURAL_ABUNDANCE -if sys.version_info[0] >= 3: - basestring = str - - class Element(object): """A natural element used in a material via . Internally, OpenMC will @@ -43,7 +41,7 @@ class Element(object): return False else: return True - elif isinstance(other, basestring) and other == self.name: + elif isinstance(other, string_types) and other == self.name: return True else: return False @@ -78,7 +76,7 @@ class Element(object): @name.setter def name(self, name): - check_type('element name', name, basestring) + check_type('element name', name, string_types) check_length('element name', name, 1, 2) self._name = name diff --git a/openmc/executor.py b/openmc/executor.py index fbd9e5d82a..a20437e1cd 100644 --- a/openmc/executor.py +++ b/openmc/executor.py @@ -3,8 +3,7 @@ import subprocess from numbers import Integral import sys -if sys.version_info[0] >= 3: - basestring = str +from six import string_types def _run(command, output, cwd): @@ -89,7 +88,7 @@ def run(particles=None, threads=None, geometry_debug=False, if geometry_debug: post_args += '-g ' - if isinstance(restart_file, basestring): + if isinstance(restart_file, string_types): post_args += '-r {0} '.format(restart_file) if tracks: diff --git a/openmc/lattice.py b/openmc/lattice.py index 20fd57442d..95c16841ff 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1,21 +1,18 @@ from __future__ import division -import abc +from abc import ABCMeta from collections import OrderedDict, Iterable from math import sqrt, floor from numbers import Real, Integral from xml.etree import ElementTree as ET import sys -from six import ABCMeta +from six import add_metaclass, string_types import numpy as np import openmc.checkvalue as cv import openmc -if sys.version_info[0] >= 3: - basestring = str - @add_metaclass(ABCMeta) class Lattice(object): @@ -104,7 +101,7 @@ class Lattice(object): @name.setter def name(self, name): if name is not None: - cv.check_type('lattice name', name, basestring) + cv.check_type('lattice name', name, string_types) self._name = name else: self._name = '' diff --git a/openmc/macroscopic.py b/openmc/macroscopic.py index a1ca62c9ab..4d35891417 100644 --- a/openmc/macroscopic.py +++ b/openmc/macroscopic.py @@ -1,9 +1,8 @@ import sys -from openmc.checkvalue import check_type +from six import string_types -if sys.version_info[0] >= 3: - basestring = str +from openmc.checkvalue import check_type class Macroscopic(object): @@ -34,7 +33,7 @@ class Macroscopic(object): return False else: return True - elif isinstance(other, basestring) and other == self.name: + elif isinstance(other, string_types) and other == self.name: return True else: return False @@ -55,5 +54,5 @@ class Macroscopic(object): @name.setter def name(self, name): - check_type('name', name, basestring) + check_type('name', name, string_types) self._name = name diff --git a/openmc/material.py b/openmc/material.py index 0639db5629..6f9c4ba15f 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -5,14 +5,13 @@ import warnings from xml.etree import ElementTree as ET import sys +from six import string_types + import openmc import openmc.data import openmc.checkvalue as cv from openmc.clean_xml import sort_xml_elements, clean_xml_indentation -if sys.version_info[0] >= 3: - basestring = str - # A static variable for auto-generated Material IDs AUTO_MATERIAL_ID = 10000 @@ -207,7 +206,7 @@ class Material(object): def name(self, name): if name is not None: cv.check_type('name for Material ID="{0}"'.format(self._id), - name, basestring) + name, string_types) self._name = name else: self._name = '' @@ -256,7 +255,7 @@ class Material(object): warnings.warn('This feature is not yet implemented in a release ' 'version of openmc') - if not isinstance(filename, basestring) and filename is not None: + if not isinstance(filename, string_types) and filename is not None: msg = 'Unable to add OTF material file to Material ID="{0}" with a ' \ 'non-string name "{1}"'.format(self._id, filename) raise ValueError(msg) @@ -290,7 +289,7 @@ class Material(object): 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) - if not isinstance(nuclide, (openmc.Nuclide, basestring)): + if not isinstance(nuclide, string_types + (openmc.Nuclide,)): msg = 'Unable to add a Nuclide to Material ID="{0}" with a ' \ 'non-Nuclide value "{1}"'.format(self._id, nuclide) raise ValueError(msg) @@ -355,7 +354,7 @@ class Material(object): 'has already been added'.format(self._id, macroscopic) raise ValueError(msg) - if not isinstance(macroscopic, (openmc.Macroscopic, basestring)): + if not isinstance(macroscopic, string_types + (openmc.Macroscopic,)): msg = 'Unable to add a Macroscopic to Material ID="{0}" with a ' \ 'non-Macroscopic value "{1}"'.format(self._id, macroscopic) raise ValueError(msg) @@ -425,7 +424,7 @@ class Material(object): 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) - if not isinstance(element, (openmc.Element, basestring)): + if not isinstance(element, string_types + (openmc.Element,)): msg = 'Unable to add an Element to Material ID="{0}" with a ' \ 'non-Element value "{1}"'.format(self._id, element) raise ValueError(msg) @@ -490,7 +489,7 @@ class Material(object): 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) - if not isinstance(name, basestring): + if not isinstance(name, string_types): msg = 'Unable to add an S(a,b) table to Material ID="{0}" with a ' \ 'non-string table name "{1}"'.format(self._id, name) raise ValueError(msg) diff --git a/openmc/mesh.py b/openmc/mesh.py index 420dba0661..730e54547e 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -3,15 +3,13 @@ from numbers import Real, Integral from xml.etree import ElementTree as ET import sys +from six import string_types import numpy as np import openmc.checkvalue as cv import openmc -if sys.version_info[0] >= 3: - basestring = str - # "Static" variable for auto-generated and Mesh IDs AUTO_MESH_ID = 10000 @@ -131,7 +129,7 @@ class Mesh(object): def name(self, name): if name is not None: cv.check_type('name for mesh ID="{0}"'.format(self._id), - name, basestring) + name, string_types) self._name = name else: self._name = '' @@ -139,7 +137,7 @@ class Mesh(object): @type.setter def type(self, meshtype): cv.check_type('type for mesh ID="{0}"'.format(self._id), - meshtype, basestring) + meshtype, string_types) cv.check_value('type for mesh ID="{0}"'.format(self._id), meshtype, ['regular']) self._type = meshtype diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index 068977d888..9441a80511 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -8,10 +8,6 @@ import numpy as np import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str - - class EnergyGroups(object): """An energy groups structure used for multi-group cross-sections. diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 4b68952a67..ca1bd1b3ee 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -6,6 +6,7 @@ from numbers import Integral from collections import OrderedDict from warnings import warn +from six import string_types import numpy as np import openmc @@ -14,10 +15,6 @@ import openmc.checkvalue as cv from openmc.tallies import ESTIMATOR_TYPES -if sys.version_info[0] >= 3: - basestring = str - - class Library(object): """A multi-energy-group and multi-delayed-group cross section library for some energy group structure. @@ -259,7 +256,7 @@ class Library(object): @name.setter def name(self, name): - cv.check_type('name', name, basestring) + cv.check_type('name', name, string_types) self._name = name @mgxs_types.setter @@ -268,7 +265,7 @@ class Library(object): if mgxs_types == 'all': self._mgxs_types = all_mgxs_types else: - cv.check_iterable_type('mgxs_types', mgxs_types, basestring) + cv.check_iterable_type('mgxs_types', mgxs_types, string_types) for mgxs_type in mgxs_types: cv.check_value('mgxs_type', mgxs_type, all_mgxs_types) self._mgxs_types = mgxs_types @@ -730,8 +727,8 @@ class Library(object): 'since a statepoint has not yet been loaded' raise ValueError(msg) - cv.check_type('filename', filename, basestring) - cv.check_type('directory', directory, basestring) + cv.check_type('filename', filename, string_types) + cv.check_type('directory', directory, string_types) import h5py @@ -773,8 +770,8 @@ class Library(object): """ - cv.check_type('filename', filename, basestring) - cv.check_type('directory', directory, basestring) + cv.check_type('filename', filename, string_types) + cv.check_type('directory', directory, string_types) # Make directory if it does not exist if not os.path.exists(directory): @@ -808,8 +805,8 @@ class Library(object): """ - cv.check_type('filename', filename, basestring) - cv.check_type('directory', directory, basestring) + cv.check_type('filename', filename, string_types) + cv.check_type('directory', directory, string_types) # Make directory if it does not exist if not os.path.exists(directory): @@ -883,8 +880,8 @@ class Library(object): cv.check_type('domain', domain, (openmc.Material, openmc.Cell, openmc.Universe, openmc.Mesh)) - cv.check_type('xsdata_name', xsdata_name, basestring) - cv.check_type('nuclide', nuclide, basestring) + cv.check_type('xsdata_name', xsdata_name, string_types) + cv.check_type('nuclide', nuclide, string_types) cv.check_value('xs_type', xs_type, ['macro', 'micro']) cv.check_type('order', order, (type(None), Integral)) if order is not None: @@ -1069,7 +1066,7 @@ class Library(object): cv.check_value('xs_type', xs_type, ['macro', 'micro']) if xsdata_names is not None: - cv.check_iterable_type('xsdata_names', xsdata_names, basestring) + cv.check_iterable_type('xsdata_names', xsdata_names, string_types) # If gathering material-specific data, set the xs_type to macro if not self.by_nuclide: diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index bb6822d92c..101edec1d2 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -6,9 +6,9 @@ import warnings import os import sys import copy -import abc +from abc import ABCMeta -from six import ABCMeta +from six import add_metaclass, string_types import numpy as np import openmc @@ -16,8 +16,6 @@ from openmc.mgxs import MGXS from openmc.mgxs.mgxs import _DOMAIN_TO_FILTER import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str # Supported cross section types MDGXS_TYPES = ['delayed-nu-fission', @@ -320,7 +318,7 @@ class MDGXS(MGXS): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: @@ -328,7 +326,7 @@ class MDGXS(MGXS): filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) for group in groups: filters.append(openmc.EnergyFilter) @@ -336,7 +334,7 @@ class MDGXS(MGXS): (self.energy_groups.get_group_bounds(group),)) # Construct list of delayed group tuples for all requested groups - if not isinstance(delayed_groups, basestring): + if not isinstance(delayed_groups, string_types): cv.check_type('delayed groups', delayed_groups, list, int) for delayed_group in delayed_groups: filters.append(openmc.DelayedGroupFilter) @@ -432,7 +430,7 @@ class MDGXS(MGXS): """ - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) cv.check_iterable_type('energy_groups', groups, Integral) cv.check_type('delayed groups', delayed_groups, list, int) @@ -542,7 +540,7 @@ class MDGXS(MGXS): return # Construct a collection of the subdomains to report - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains, dtype=np.int) @@ -559,7 +557,7 @@ class MDGXS(MGXS): elif nuclides == 'sum': nuclides = ['sum'] else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) else: nuclides = ['sum'] @@ -649,8 +647,8 @@ class MDGXS(MGXS): """ - cv.check_type('filename', filename, basestring) - cv.check_type('directory', directory, basestring) + cv.check_type('filename', filename, string_types) + cv.check_type('directory', directory, string_types) cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex']) cv.check_value('xs_type', xs_type, ['macro', 'micro']) @@ -740,11 +738,11 @@ class MDGXS(MGXS): """ - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) if nuclides != 'all' and nuclides != 'sum': - cv.check_iterable_type('nuclides', nuclides, basestring) - if not isinstance(delayed_groups, basestring): + cv.check_iterable_type('nuclides', nuclides, string_types) + if not isinstance(delayed_groups, string_types): cv.check_type('delayed groups', delayed_groups, list, int) cv.check_value('xs_type', xs_type, ['macro', 'micro']) @@ -819,7 +817,7 @@ class MDGXS(MGXS): columns = ['group in'] # Select out those groups the user requested - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): if 'group in' in df: df = df[df['group in'].isin(groups)] if 'group out' in df: @@ -1210,7 +1208,7 @@ class ChiDelayed(MDGXS): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: @@ -1218,7 +1216,7 @@ class ChiDelayed(MDGXS): filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) for group in groups: filters.append(openmc.EnergyoutFilter) @@ -1226,7 +1224,7 @@ class ChiDelayed(MDGXS): (self.energy_groups.get_group_bounds(group),)) # Construct list of delayed group tuples for all requested groups - if not isinstance(delayed_groups, basestring): + if not isinstance(delayed_groups, string_types): cv.check_type('delayed groups', delayed_groups, list, int) for delayed_group in delayed_groups: filters.append(openmc.DelayedGroupFilter) @@ -1274,7 +1272,7 @@ class ChiDelayed(MDGXS): # Get chi delayed for user-specified nuclides in the domain else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) xs = self.xs_tally.get_values(filters=filters, filter_bins=filter_bins, nuclides=nuclides, value=value) diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 1520f81d11..b839e92151 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -6,10 +6,10 @@ import warnings import os import sys import copy -import abc +from abc import ABCMeta import itertools -from six import add_metaclass +from six import add_metaclass, string_types import numpy as np import openmc @@ -17,9 +17,6 @@ import openmc.checkvalue as cv from openmc.tallies import ESTIMATOR_TYPES from openmc.mgxs import EnergyGroups -if sys.version_info[0] >= 3: - basestring = str - # Supported cross section types MGXS_TYPES = ['total', @@ -366,7 +363,7 @@ class MGXS(object): @name.setter def name(self, name): - cv.check_type('name', name, basestring) + cv.check_type('name', name, string_types) self._name = name @by_nuclide.setter @@ -376,7 +373,7 @@ class MGXS(object): @nuclides.setter def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) self._nuclides = nuclides @estimator.setter @@ -560,7 +557,7 @@ class MGXS(object): """ - cv.check_type('nuclide', nuclide, basestring) + cv.check_type('nuclide', nuclide, string_types) # Get list of all nuclides in the spatial domain nuclides = self.domain.get_nuclide_densities() @@ -786,7 +783,7 @@ class MGXS(object): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: @@ -794,7 +791,7 @@ class MGXS(object): filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) for group in groups: filters.append(openmc.EnergyFilter) @@ -956,7 +953,7 @@ class MGXS(object): """ # Construct a collection of the subdomain filter bins to average across - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains) @@ -1011,7 +1008,7 @@ class MGXS(object): """ - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) cv.check_iterable_type('energy_groups', groups, Integral) # Build lists of filters and filter bins to slice @@ -1165,7 +1162,7 @@ class MGXS(object): """ # Construct a collection of the subdomains to report - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains, dtype=np.int) @@ -1182,7 +1179,7 @@ class MGXS(object): elif nuclides == 'sum': nuclides = ['sum'] else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) else: nuclides = ['sum'] @@ -1300,7 +1297,7 @@ class MGXS(object): xs_results = h5py.File(filename, 'w') # Construct a collection of the subdomains to report - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains, dtype=np.int) @@ -1321,7 +1318,7 @@ class MGXS(object): elif nuclides == 'sum': nuclides = ['sum'] else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) else: nuclides = ['sum'] @@ -1399,8 +1396,8 @@ class MGXS(object): """ - cv.check_type('filename', filename, basestring) - cv.check_type('directory', directory, basestring) + cv.check_type('filename', filename, string_types) + cv.check_type('directory', directory, string_types) cv.check_value('format', format, ['csv', 'excel', 'pickle', 'latex']) cv.check_value('xs_type', xs_type, ['macro', 'micro']) @@ -1486,10 +1483,10 @@ class MGXS(object): """ - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) if nuclides != 'all' and nuclides != 'sum': - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) cv.check_value('xs_type', xs_type, ['macro', 'micro']) # Get a Pandas DataFrame from the derived xs tally @@ -1561,7 +1558,7 @@ class MGXS(object): columns = ['group in'] # Select out those groups the user requested - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): if 'group in' in df: df = df[df['group in'].isin(groups)] if 'group out' in df: @@ -1781,7 +1778,7 @@ class MatrixMGXS(MGXS): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: @@ -1789,7 +1786,7 @@ class MatrixMGXS(MGXS): filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(in_groups, basestring): + if not isinstance(in_groups, string_types): cv.check_iterable_type('groups', in_groups, Integral) for group in in_groups: filters.append(openmc.EnergyFilter) @@ -1797,7 +1794,7 @@ class MatrixMGXS(MGXS): self.energy_groups.get_group_bounds(group),)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(out_groups, basestring): + if not isinstance(out_groups, string_types): cv.check_iterable_type('groups', out_groups, Integral) for group in out_groups: filters.append(openmc.EnergyoutFilter) @@ -1943,7 +1940,7 @@ class MatrixMGXS(MGXS): """ # Construct a collection of the subdomains to report - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains, dtype=np.int) @@ -1960,7 +1957,7 @@ class MatrixMGXS(MGXS): if nuclides == 'sum': nuclides = ['sum'] else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) else: nuclides = ['sum'] @@ -3616,21 +3613,21 @@ class ScatterMatrixXS(MatrixMGXS): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: filters.append(_DOMAIN_TO_FILTER[self.domain_type]) filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(in_groups, basestring): + if not isinstance(in_groups, string_types): cv.check_iterable_type('groups', in_groups, Integral) for group in in_groups: filters.append(openmc.EnergyFilter) filter_bins.append((self.energy_groups.get_group_bounds(group),)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(out_groups, basestring): + if not isinstance(out_groups, string_types): cv.check_iterable_type('groups', out_groups, Integral) for group in out_groups: filters.append(openmc.EnergyoutFilter) @@ -3804,7 +3801,7 @@ class ScatterMatrixXS(MatrixMGXS): """ # Construct a collection of the subdomains to report - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': subdomains = np.arange(self.num_subdomains, dtype=np.int) @@ -3821,7 +3818,7 @@ class ScatterMatrixXS(MatrixMGXS): if nuclides == 'sum': nuclides = ['sum'] else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) else: nuclides = ['sum'] @@ -4604,14 +4601,14 @@ class Chi(MGXS): filter_bins = [] # Construct a collection of the domain filter bins - if not isinstance(subdomains, basestring): + if not isinstance(subdomains, string_types): cv.check_iterable_type('subdomains', subdomains, Integral, max_depth=3) for subdomain in subdomains: filters.append(_DOMAIN_TO_FILTER[self.domain_type]) filter_bins.append((subdomain,)) # Construct list of energy group bounds tuples for all requested groups - if not isinstance(groups, basestring): + if not isinstance(groups, string_types): cv.check_iterable_type('groups', groups, Integral) for group in groups: filters.append(openmc.EnergyoutFilter) @@ -4656,7 +4653,7 @@ class Chi(MGXS): # Get chi for user-specified nuclides in the domain else: - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) xs = self.xs_tally.get_values(filters=filters, filter_bins=filter_bins, nuclides=nuclides, value=value) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 37ad6c1be4..8394d9cc0b 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -3,6 +3,7 @@ from numbers import Real, Integral from xml.etree import ElementTree as ET import sys +from six import string_types import numpy as np import openmc @@ -11,8 +12,6 @@ from openmc.checkvalue import check_type, check_value, check_greater_than, \ check_iterable_type from openmc.clean_xml import sort_xml_elements, clean_xml_indentation -if sys.version_info[0] >= 3: - basestring = str # Supported incoming particle MGXS angular treatment representations _REPRESENTATIONS = ['isotropic', 'angle'] @@ -360,7 +359,7 @@ class XSdata(object): @name.setter def name(self, name): - check_type('name for XSdata', name, basestring) + check_type('name for XSdata', name, string_types) self._name = name @energy_groups.setter @@ -383,7 +382,7 @@ class XSdata(object): @alias.setter def alias(self, alias): if alias is not None: - check_type('alias', alias, basestring) + check_type('alias', alias, string_types) self._alias = alias else: self._alias = self._name diff --git a/openmc/nuclide.py b/openmc/nuclide.py index 11c59e6879..5b844582c6 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -2,10 +2,9 @@ from numbers import Integral import sys import warnings -from openmc.checkvalue import check_type +from six import string_types -if sys.version_info[0] >= 3: - basestring = str +from openmc.checkvalue import check_type class Nuclide(object): @@ -39,7 +38,7 @@ class Nuclide(object): return False else: return True - elif isinstance(other, basestring) and other == self.name: + elif isinstance(other, string_types) and other == self.name: return True else: return False @@ -73,7 +72,7 @@ class Nuclide(object): @name.setter def name(self, name): - check_type('name', name, basestring) + check_type('name', name, string_types) self._name = name if '-' in name: diff --git a/openmc/plots.py b/openmc/plots.py index 6915604a3c..48af6f23c3 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -4,14 +4,13 @@ from xml.etree import ElementTree as ET import sys import warnings +from six import string_types import numpy as np import openmc import openmc.checkvalue as cv from openmc.clean_xml import clean_xml_indentation -if sys.version_info[0] >= 3: - basestring = str # A static variable for auto-generated Plot IDs AUTO_PLOT_ID = 10000 @@ -166,7 +165,7 @@ class Plot(object): @name.setter def name(self, name): - cv.check_type('plot name', name, basestring) + cv.check_type('plot name', name, string_types) self._name = name @width.setter @@ -191,24 +190,24 @@ class Plot(object): @filename.setter def filename(self, filename): - cv.check_type('filename', filename, basestring) + cv.check_type('filename', filename, string_types) self._filename = filename @color.setter def color(self, color): - cv.check_type('plot color', color, basestring) + cv.check_type('plot color', color, string_types) cv.check_value('plot color', color, ['cell', 'mat']) self._color = color @type.setter def type(self, plottype): - cv.check_type('plot type', plottype, basestring) + cv.check_type('plot type', plottype, string_types) cv.check_value('plot type', plottype, ['slice', 'voxel']) self._type = plottype @basis.setter def basis(self, basis): - cv.check_type('plot basis', basis, basestring) + cv.check_type('plot basis', basis, string_types) cv.check_value('plot basis', basis, ['xy', 'xz', 'yz']) self._basis = basis @@ -387,7 +386,7 @@ class Plot(object): cv.check_less_than('alpha', alpha, 1., equality=True) # Get a background (R,G,B) tuple to apply in alpha compositing - if isinstance(background, basestring): + if isinstance(background, string_types): if background == 'white': background = (255, 255, 255) elif background == 'black': diff --git a/openmc/settings.py b/openmc/settings.py index f255a8bb10..1e07ca223d 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -4,15 +4,13 @@ import warnings from xml.etree import ElementTree as ET import sys +from six import string_types import numpy as np from openmc.clean_xml import clean_xml_indentation import openmc.checkvalue as cv from openmc import Nuclide, VolumeCalculation, Source -if sys.version_info[0] >= 3: - basestring = str - class Settings(object): """Settings used for an OpenMC simulation. @@ -527,7 +525,7 @@ class Settings(object): @output_path.setter def output_path(self, output_path): - cv.check_type('output path', output_path, basestring) + cv.check_type('output path', output_path, string_types) self._output_path = output_path @verbosity.setter @@ -583,12 +581,12 @@ class Settings(object): @cross_sections.setter def cross_sections(self, cross_sections): - cv.check_type('cross sections', cross_sections, basestring) + cv.check_type('cross sections', cross_sections, string_types) self._cross_sections = cross_sections @multipole_library.setter def multipole_library(self, multipole_library): - cv.check_type('cross sections', multipole_library, basestring) + cv.check_type('cross sections', multipole_library, string_types) self._multipole_library = multipole_library @ptables.setter diff --git a/openmc/source.py b/openmc/source.py index ee32cd0f4b..1aee435147 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -2,13 +2,12 @@ from numbers import Real import sys from xml.etree import ElementTree as ET +from six import string_types + from openmc.stats.univariate import Univariate from openmc.stats.multivariate import UnitSphere, Spatial import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str - class Source(object): """Distribution of phase space coordinates for source sites. @@ -79,7 +78,7 @@ class Source(object): @file.setter def file(self, filename): - cv.check_type('source file', filename, basestring) + cv.check_type('source file', filename, string_types) self._file = filename @space.setter diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 1a97b695b4..aaa5c0b840 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -9,9 +9,6 @@ import numpy as np import openmc import openmc.checkvalue as cv -if sys.version > '3': - long = int - class StatePoint(object): """State information on a simulation at a certain point in time (at the end diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index fdae6c789e..ca25cf5fb3 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -11,9 +11,6 @@ import numpy as np import openmc.checkvalue as cv from openmc.stats.univariate import Univariate, Uniform -if sys.version_info[0] >= 3: - basestring = str - @add_metaclass(ABCMeta) class UnitSphere(object): diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 2fabde8c5f..dcbb9982c7 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -10,8 +10,6 @@ import numpy as np import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -if sys.version_info[0] >= 3: - basestring = str _INTERPOLATION_SCHEMES = ['histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'] diff --git a/openmc/surface.py b/openmc/surface.py index 8745a1867b..c88c4ccc7c 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,14 +4,12 @@ from xml.etree import ElementTree as ET import sys from math import sqrt -from six import add_metaclass +from six import add_metaclass, string_types import numpy as np from openmc.checkvalue import check_type, check_value, check_greater_than from openmc.region import Region, Intersection -if sys.version_info[0] >= 3: - basestring = str # A static variable for auto-generated Surface IDs AUTO_SURFACE_ID = 10000 @@ -135,14 +133,14 @@ class Surface(object): @name.setter def name(self, name): if name is not None: - check_type('surface name', name, basestring) + check_type('surface name', name, string_types) self._name = name else: self._name = '' @boundary_type.setter def boundary_type(self, boundary_type): - check_type('boundary type', boundary_type, basestring) + check_type('boundary type', boundary_type, string_types) check_value('boundary type', boundary_type, _BC_TYPES) self._boundary_type = boundary_type diff --git a/openmc/tallies.py b/openmc/tallies.py index f9daa7a228..6047131450 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -11,15 +11,13 @@ import sys import warnings from xml.etree import ElementTree as ET +from six import string_types import numpy as np import openmc import openmc.checkvalue as cv from openmc.clean_xml import clean_xml_indentation -if sys.version_info[0] >= 3: - basestring = str - # "Static" variable for auto-generated Tally IDs AUTO_TALLY_ID = 10000 @@ -33,9 +31,9 @@ _PRODUCT_TYPES = ['tensor', 'entrywise'] # The following indicate acceptable types when setting Tally.scores, # Tally.nuclides, and Tally.filters -_SCORE_CLASSES = (basestring, openmc.CrossScore, openmc.AggregateScore) -_NUCLIDE_CLASSES = (basestring, openmc.Nuclide, openmc.CrossNuclide, - openmc.AggregateNuclide) +_SCORE_CLASSES = string_types + (openmc.CrossScore, openmc.AggregateScore) +_NUCLIDE_CLASSES = string_types + (openmc.Nuclide, openmc.CrossNuclide, + openmc.AggregateNuclide) _FILTER_CLASSES = (openmc.Filter, openmc.CrossFilter, openmc.AggregateFilter) # Valid types of estimators @@ -431,7 +429,7 @@ class Tally(object): @name.setter def name(self, name): if name is not None: - cv.check_type('tally name', name, basestring) + cv.check_type('tally name', name, string_types) self._name = name else: self._name = '' @@ -478,7 +476,7 @@ class Tally(object): raise ValueError(msg) # If score is a string, strip whitespace - if isinstance(score, basestring): + if isinstance(score, string_types): scores[i] = score.strip() self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) @@ -1355,7 +1353,7 @@ class Tally(object): """ - cv.check_iterable_type('nuclides', nuclides, basestring) + cv.check_iterable_type('nuclides', nuclides, string_types) # Determine the score indices from any of the requested scores if nuclides: @@ -1390,7 +1388,7 @@ class Tally(object): """ for score in scores: - if not isinstance(score, (basestring, openmc.CrossScore)): + if not isinstance(score, string_types + (openmc.CrossScore,)): msg = 'Unable to get score indices for score "{0}" in Tally ' \ 'ID="{1}" since it is not a string or CrossScore'\ .format(score, self.id) @@ -1585,7 +1583,7 @@ class Tally(object): column_name = 'score' for score in self.scores: - if isinstance(score, (basestring, openmc.CrossScore)): + if isinstance(score, string_types + (openmc.CrossScore,)): scores.append(str(score)) elif isinstance(score, openmc.AggregateScore): scores.append(score.name) @@ -1700,13 +1698,13 @@ class Tally(object): msg = 'The Tally ID="{0}" has no data to export'.format(self.id) raise KeyError(msg) - if not isinstance(filename, basestring): + if not isinstance(filename, string_types): msg = 'Unable to export the results for Tally ID="{0}" to ' \ 'filename="{1}" since it is not a ' \ 'string'.format(self.id, filename) raise ValueError(msg) - elif not isinstance(directory, basestring): + elif not isinstance(directory, string_types): msg = 'Unable to export the results for Tally ID="{0}" to ' \ 'directory="{1}" since it is not a ' \ 'string'.format(self.id, directory) @@ -2354,11 +2352,11 @@ class Tally(object): raise ValueError(msg) # Check that the scores are valid - if not isinstance(score1, (basestring, openmc.CrossScore)): + if not isinstance(score1, string_types + (openmc.CrossScore,)): msg = 'Unable to swap score1 "{0}" in Tally ID="{1}" since it is ' \ 'not a string or CrossScore'.format(score1, self.id) raise ValueError(msg) - elif not isinstance(score2, (basestring, openmc.CrossScore)): + elif not isinstance(score2, string_types + (openmc.CrossScore,)): msg = 'Unable to swap score2 "{0}" in Tally ID="{1}" since it is ' \ 'not a string or CrossScore'.format(score2, self.id) raise ValueError(msg) diff --git a/openmc/trigger.py b/openmc/trigger.py index f23838dcff..69ec8c6200 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -4,10 +4,9 @@ import sys import warnings from collections import Iterable -import openmc.checkvalue as cv +from six import string_types -if sys.version_info[0] >= 3: - basestring = str +import openmc.checkvalue as cv class Trigger(object): @@ -77,7 +76,7 @@ class Trigger(object): @scores.setter def scores(self, scores): - cv.check_type('trigger scores', scores, Iterable, basestring) + cv.check_type('trigger scores', scores, Iterable, string_types) # Set scores making sure not to have duplicates self._scores = [] diff --git a/openmc/universe.py b/openmc/universe.py index c8fb89a384..545b05d5a1 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -3,13 +3,12 @@ from numbers import Integral import random import sys +from six import string_types import numpy as np import openmc import openmc.checkvalue as cv -if sys.version_info[0] >= 3: - basestring = str # A dictionary for storing IDs of cell elements that have already been written, # used to optimize the writing process @@ -118,7 +117,7 @@ class Universe(object): @name.setter def name(self, name): if name is not None: - cv.check_type('universe name', name, basestring) + cv.check_type('universe name', name, string_types) self._name = name else: self._name = '' From fdc22a3d70056a04c412d436153279b09be85f3e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 21:45:59 -0500 Subject: [PATCH 44/82] Use six to import Tkinter modules in openmc-plot-mesh-tally --- scripts/openmc-plot-mesh-tally | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index 04f1f06c6c..cf17fabe9a 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -5,6 +5,11 @@ import os import sys +import six.moves.tkinter as tk +import six.moves.tkinter_filedialog as filedialog +import six.moves.tkinter_font as font +import six.moves.tkinter_messagebox as messagebox +import six.moves.tkinter_ttk as ttk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import NavigationToolbar2TkAgg from matplotlib.figure import Figure @@ -13,19 +18,6 @@ import numpy as np from openmc.statepoint import StatePoint -if sys.version_info[0] < 3: - import Tkinter as tk - import tkFileDialog as filedialog - import tkFont as font - import tkMessageBox as messagebox - import ttk as ttk -else: - import tkinter as tk - import tkinter.filedialog as filedialog - import tkinter.font as font - import tkinter.messagebox as messagebox - import tkinter.ttk as ttk - class MeshPlotter(tk.Frame): def __init__(self, parent, filename): From 36cf8934fd5ed9875963439eddd0bea76557dc74 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Oct 2016 22:17:52 -0500 Subject: [PATCH 45/82] Fix units for fission energy release in ENDF files --- openmc/data/fission_energy.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 9479e67313..687cb5703e 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -16,13 +16,15 @@ if sys.version_info[0] >= 3: basestring = str -def _extract_458_data(ev): +def _extract_458_data(ev, units='eV'): """Read an ENDF file and extract the MF=1, MT=458 values. Parameters ---------- ev : openmc.data.Evaluation ENDF evaluation + units : {'eV', 'MeV'} + The units are used in values returned. Returns ------- @@ -86,12 +88,13 @@ def _extract_458_data(ev): for coeffs in uncertainty.values(): coeffs[2] *= 1e-6 # Convert eV to MeV. - for coeffs in value.values(): - for i in range(len(coeffs)): - coeffs[i] *= 10**(-6 + 6*i) - for coeffs in uncertainty.values(): - for i in range(len(coeffs)): - coeffs[i] *= 10**(-6 + 6*i) + if units == 'MeV': + for coeffs in value.values(): + for i in range(len(coeffs)): + coeffs[i] *= 10**(-6 + 6*i) + for coeffs in uncertainty.values(): + for i in range(len(coeffs)): + coeffs[i] *= 10**(-6 + 6*i) return value, uncertainty @@ -158,7 +161,7 @@ def write_compact_458_library(endf_files, output_name='fission_Q_data.h5', continue # Get the important bits. - data = _extract_458_data(ev) + data = _extract_458_data(ev, 'MeV') if data is None: continue value, uncertainty = data From e96849c3842142641053ba3619ff202fbd28ead5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 7 Oct 2016 17:02:49 -0400 Subject: [PATCH 46/82] Improve 0K substitution warning messages --- src/input_xml.F90 | 4 ++-- src/nuclide_header.F90 | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 16892397aa..5aa22fba53 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -5765,7 +5765,7 @@ contains file_id = file_open(libraries(i_library) % path, 'r') group_id = open_group(file_id, name) call nuclides(i_nuclide) % from_hdf5(group_id, nuc_temps(i_nuclide), & - temperature_method, temperature_tolerance) + temperature_method, temperature_tolerance, master) call close_group(group_id) call file_close(file_id) @@ -5999,7 +5999,7 @@ contains group_id = open_group(file_id, name) method = TEMPERATURE_NEAREST call resonant_nuc % from_hdf5(group_id, temperature, & - method, 1000.0_8) + method, 1000.0_8, master) call close_group(group_id) call file_close(file_id) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 4235f4234d..93832869ce 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -186,12 +186,16 @@ module nuclide_header end subroutine nuclide_clear - subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance) - class(Nuclide), intent(inout) :: this - integer(HID_T), intent(in) :: group_id + subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance, & + master) + class(Nuclide), intent(inout) :: this + integer(HID_T), intent(in) :: group_id type(VectorReal), intent(in) :: temperature ! list of desired temperatures - integer, intent(inout) :: method - real(8), intent(in) :: tolerance + integer, intent(inout) :: method + real(8), intent(in) :: tolerance + logical, intent(in) :: master ! if this is the master proc + ! (can't use global cuz + ! circular dependance) integer :: i integer :: storage_type @@ -265,15 +269,17 @@ module nuclide_header call temps_to_read % push_back(nint(temp_actual)) ! Write warning for resonance scattering data if 0K is not available - if (abs(temp_actual - temp_desired) > 0 .and. temp_desired == 0) then + if (abs(temp_actual - temp_desired) > 0 .and. temp_desired == 0 & + .and. master) then call warning(trim(this % name) // " does not contain 0K data & &needed for resonance scattering options selected. Using & - &data at " // trim(to_str(nint(temp_actual))) // " K instead.") + &data at " // trim(to_str(temp_actual)) & + // " K instead.") end if end if else - call fatal_error("Nuclear data library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & + call fatal_error("Nuclear data library does not contain cross & + §ions for " // trim(this % name) // " at or near " // & trim(to_str(nint(temp_desired))) // " K.") end if end do From 9a8d42baf32dfa19df0f704cc1fe23f4a719ec8e Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 8 Oct 2016 10:40:28 -0400 Subject: [PATCH 47/82] modified travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 46bb847e6a..ed81e6716e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ -sudo: false +sudo: required +dist: trusty language: python python: - "2.7" From 73d9f7ce019f700211c92cf1ca4ae1abd7b2ec35 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 8 Oct 2016 11:20:13 -0400 Subject: [PATCH 48/82] removed low-hanging gnu fortran 4.6 specific code --- src/global.F90 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index bea5f61a83..d971581bae 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -468,12 +468,7 @@ contains do i = 1, size(nuclides) call nuclides(i) % clear() end do - - ! WARNING: The following statement should work but doesn't under gfortran - ! 4.6 because of a bug. Technically, commenting this out leaves a memory - ! leak. - - ! deallocate(nuclides) + deallocate(nuclides) end if if (allocated(nuclides_0K)) then From 490a0d8338dc2b1e24ed2f39961a121618ce1e79 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 8 Oct 2016 11:34:28 -0400 Subject: [PATCH 49/82] Updated reference to gfrotran 4.6.0 in the docs as being the minimum version --- docs/source/usersguide/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 3dab08e9d3..925008495a 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -51,7 +51,7 @@ Prerequisites installed on your machine. Since a number of Fortran 2003/2008 features are used in the code, it is recommended that you use the latest version of whatever compiler you choose. For gfortran_, it is necessary to use - version 4.6.0 or above. + version 4.8.0 or above. If you are using Debian or a Debian derivative such as Ubuntu, you can install the gfortran compiler using the following command:: From 65513b2664b4686f15c39592b77d6f4d94098ed3 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 09:04:57 -0400 Subject: [PATCH 50/82] Changes to testing scripts to less over-subscribe Travis (3 OMP threads to 2 and 3 MPI processes to 2) --- .travis.yml | 2 +- tests/testing_harness.py | 2 +- tests/travis_install.sh | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed81e6716e..4236c36d1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,6 +55,6 @@ before_script: script: - cd tests - - export OMP_NUM_THREADS=3 + - export OMP_NUM_THREADS=2 - ./travis.sh - cd .. diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 5300131642..150d124c8c 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -24,7 +24,7 @@ class TestHarness(object): self.parser = OptionParser() self.parser.add_option('--exe', dest='exe', default='openmc') self.parser.add_option('--mpi_exec', dest='mpi_exec', default=None) - self.parser.add_option('--mpi_np', dest='mpi_np', type=int, default=3) + self.parser.add_option('--mpi_np', dest='mpi_np', type=int, default=2) self.parser.add_option('--update', dest='update', action='store_true', default=False) self._opts = None diff --git a/tests/travis_install.sh b/tests/travis_install.sh index df1c81314b..2e35c4f65b 100755 --- a/tests/travis_install.sh +++ b/tests/travis_install.sh @@ -8,7 +8,7 @@ if [[ ! -e $HOME/mpich_install/bin/mpiexec ]]; then tar -xzvf mpich-3.1.3.tar.gz >/dev/null 2>&1 cd mpich-3.1.3 ./configure --prefix=$HOME/mpich_install -q - make >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi @@ -22,7 +22,7 @@ if [[ ! -e $HOME/phdf5_install/bin/h5pfc ]]; then ./configure \ --prefix=$HOME/phdf5_install -q --enable-fortran \ --enable-fortran2003 --enable-parallel - make >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi @@ -33,7 +33,7 @@ if [[ ! -e $HOME/hdf5_install/bin/h5fc ]]; then cd hdf5-1.8.15 CC=gcc FC=gfortran ./configure --prefix=$HOME/hdf5_install -q \ --enable-fortran --enable-fortran2003 - make -j >/dev/null 2>&1 + make -j 2 >/dev/null 2>&1 make install >/dev/null 2>&1 cd .. fi From 4f3454edead1eacb3aed4b53e3aa9ff79724b316 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 09:49:01 -0400 Subject: [PATCH 51/82] Significantly reduced the number of nuclides in the standard (HM problem I believe) input set, reducing the total test time by a good amount --- tests/input_set.py | 96 ----- tests/test_asymmetric_lattice/inputs_true.dat | 2 +- .../test_asymmetric_lattice/results_true.dat | 2 +- tests/test_filter_mesh/inputs_true.dat | 2 +- tests/test_filter_mesh/results_true.dat | 2 +- tests/test_iso_in_lab/inputs_true.dat | 2 +- tests/test_iso_in_lab/results_true.dat | 2 +- tests/test_mgxs_library_mesh/inputs_true.dat | 2 +- tests/test_mgxs_library_mesh/results_true.dat | 348 +++++++++--------- tests/test_tallies/inputs_true.dat | 2 +- tests/test_tallies/results_true.dat | 2 +- tests/test_tally_aggregation/inputs_true.dat | 2 +- tests/test_tally_aggregation/results_true.dat | 2 +- .../test_tally_aggregation.py | 6 +- tests/test_tally_arithmetic/inputs_true.dat | 2 +- .../test_tally_arithmetic.py | 4 +- tests/test_tally_slice_merge/inputs_true.dat | 2 +- tests/test_tally_slice_merge/results_true.dat | 96 ++--- 18 files changed, 240 insertions(+), 336 deletions(-) diff --git a/tests/input_set.py b/tests/input_set.py index 94576acf0d..f3f9e88bd4 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -27,37 +27,8 @@ class InputSet(object): fuel.set_density('g/cm3', 10.062) fuel.add_nuclide("U234", 4.9476e-6) fuel.add_nuclide("U235", 4.8218e-4) - fuel.add_nuclide("U236", 9.0402e-5) fuel.add_nuclide("U238", 2.1504e-2) - fuel.add_nuclide("Np237", 7.3733e-6) - fuel.add_nuclide("Pu238", 1.5148e-6) - fuel.add_nuclide("Pu239", 1.3955e-4) - fuel.add_nuclide("Pu240", 3.4405e-5) - fuel.add_nuclide("Pu241", 2.1439e-5) - fuel.add_nuclide("Pu242", 3.7422e-6) - fuel.add_nuclide("Am241", 4.5041e-7) - fuel.add_nuclide("Am242_m1", 9.2301e-9) - fuel.add_nuclide("Am243", 4.7878e-7) - fuel.add_nuclide("Cm242", 1.0485e-7) - fuel.add_nuclide("Cm243", 1.4268e-9) - fuel.add_nuclide("Cm244", 8.8756e-8) - fuel.add_nuclide("Cm245", 3.5285e-9) - fuel.add_nuclide("Mo95", 2.6497e-5) - fuel.add_nuclide("Tc99", 3.2772e-5) - fuel.add_nuclide("Ru101", 3.0742e-5) - fuel.add_nuclide("Ru103", 2.3505e-6) - fuel.add_nuclide("Ag109", 2.0009e-6) fuel.add_nuclide("Xe135", 1.0801e-8) - fuel.add_nuclide("Cs133", 3.4612e-5) - fuel.add_nuclide("Nd143", 2.6078e-5) - fuel.add_nuclide("Nd145", 1.9898e-5) - fuel.add_nuclide("Sm147", 1.6128e-6) - fuel.add_nuclide("Sm149", 1.1627e-7) - fuel.add_nuclide("Sm150", 7.1727e-6) - fuel.add_nuclide("Sm151", 5.4947e-7) - fuel.add_nuclide("Sm152", 3.0221e-6) - fuel.add_nuclide("Eu153", 2.6209e-6) - fuel.add_nuclide("Gd155", 1.5369e-9) fuel.add_nuclide("O16", 4.5737e-2) clad = openmc.Material(name='Cladding', material_id=2) @@ -93,27 +64,10 @@ class InputSet(object): rpv_steel.add_nuclide("Fe58", 0.00282159, 'wo') rpv_steel.add_nuclide("Ni58", 0.0067198, 'wo') rpv_steel.add_nuclide("Ni60", 0.0026776, 'wo') - rpv_steel.add_nuclide("Ni61", 0.0001183, 'wo') - rpv_steel.add_nuclide("Ni62", 0.0003835, 'wo') - rpv_steel.add_nuclide("Ni64", 0.0001008, 'wo') rpv_steel.add_nuclide("Mn55", 0.01, 'wo') - rpv_steel.add_nuclide("Mo92", 0.000849, 'wo') - rpv_steel.add_nuclide("Mo94", 0.0005418, 'wo') - rpv_steel.add_nuclide("Mo95", 0.0009438, 'wo') - rpv_steel.add_nuclide("Mo96", 0.0010002, 'wo') - rpv_steel.add_nuclide("Mo97", 0.0005796, 'wo') - rpv_steel.add_nuclide("Mo98", 0.0014814, 'wo') - rpv_steel.add_nuclide("Mo100", 0.0006042, 'wo') - rpv_steel.add_nuclide("Si28", 0.00367464, 'wo') - rpv_steel.add_nuclide("Si29", 0.00019336, 'wo') - rpv_steel.add_nuclide("Si30", 0.000132, 'wo') - rpv_steel.add_nuclide("Cr50", 0.00010435, 'wo') rpv_steel.add_nuclide("Cr52", 0.002092475, 'wo') - rpv_steel.add_nuclide("Cr53", 0.00024185, 'wo') - rpv_steel.add_nuclide("Cr54", 6.1325e-05, 'wo') rpv_steel.add_nuclide("C0", 0.0025, 'wo') rpv_steel.add_nuclide("Cu63", 0.0013696, 'wo') - rpv_steel.add_nuclide("Cu65", 0.0006304, 'wo') lower_rad_ref = openmc.Material(name='Lower radial reflector', material_id=6) @@ -127,18 +81,8 @@ class InputSet(object): lower_rad_ref.add_nuclide("Fe57", 0.01362750048, 'wo') lower_rad_ref.add_nuclide("Fe58", 0.001848545204, 'wo') lower_rad_ref.add_nuclide("Ni58", 0.055298376566, 'wo') - lower_rad_ref.add_nuclide("Ni60", 0.022034425592, 'wo') - lower_rad_ref.add_nuclide("Ni61", 0.000973510811, 'wo') - lower_rad_ref.add_nuclide("Ni62", 0.003155886695, 'wo') - lower_rad_ref.add_nuclide("Ni64", 0.000829500336, 'wo') lower_rad_ref.add_nuclide("Mn55", 0.0182870, 'wo') - lower_rad_ref.add_nuclide("Si28", 0.00839976771, 'wo') - lower_rad_ref.add_nuclide("Si29", 0.00044199679, 'wo') - lower_rad_ref.add_nuclide("Si30", 0.0003017355, 'wo') - lower_rad_ref.add_nuclide("Cr50", 0.007251360806, 'wo') lower_rad_ref.add_nuclide("Cr52", 0.145407678031, 'wo') - lower_rad_ref.add_nuclide("Cr53", 0.016806340306, 'wo') - lower_rad_ref.add_nuclide("Cr54", 0.004261520857, 'wo') lower_rad_ref.add_s_alpha_beta('c_H_in_H2O') upper_rad_ref = openmc.Material(name='Upper radial reflector /' @@ -153,18 +97,8 @@ class InputSet(object): upper_rad_ref.add_nuclide("Fe57", 0.01375486056, 'wo') upper_rad_ref.add_nuclide("Fe58", 0.001865821363, 'wo') upper_rad_ref.add_nuclide("Ni58", 0.055815129186, 'wo') - upper_rad_ref.add_nuclide("Ni60", 0.022240333032, 'wo') - upper_rad_ref.add_nuclide("Ni61", 0.000982608081, 'wo') - upper_rad_ref.add_nuclide("Ni62", 0.003185377845, 'wo') - upper_rad_ref.add_nuclide("Ni64", 0.000837251856, 'wo') upper_rad_ref.add_nuclide("Mn55", 0.0184579, 'wo') - upper_rad_ref.add_nuclide("Si28", 0.00847831314, 'wo') - upper_rad_ref.add_nuclide("Si29", 0.00044612986, 'wo') - upper_rad_ref.add_nuclide("Si30", 0.000304557, 'wo') - upper_rad_ref.add_nuclide("Cr50", 0.00731912987, 'wo') upper_rad_ref.add_nuclide("Cr52", 0.146766614995, 'wo') - upper_rad_ref.add_nuclide("Cr53", 0.01696340737, 'wo') - upper_rad_ref.add_nuclide("Cr54", 0.004301347765, 'wo') upper_rad_ref.add_s_alpha_beta('c_H_in_H2O') bot_plate = openmc.Material(name='Bottom plate region', material_id=8) @@ -178,18 +112,8 @@ class InputSet(object): bot_plate.add_nuclide("Fe57", 0.014750478, 'wo') bot_plate.add_nuclide("Fe58", 0.002000875025, 'wo') bot_plate.add_nuclide("Ni58", 0.059855207342, 'wo') - bot_plate.add_nuclide("Ni60", 0.023850159704, 'wo') - bot_plate.add_nuclide("Ni61", 0.001053732407, 'wo') - bot_plate.add_nuclide("Ni62", 0.003415945715, 'wo') - bot_plate.add_nuclide("Ni64", 0.000897854832, 'wo') bot_plate.add_nuclide("Mn55", 0.0197940, 'wo') - bot_plate.add_nuclide("Si28", 0.00909197802, 'wo') - bot_plate.add_nuclide("Si29", 0.00047842098, 'wo') - bot_plate.add_nuclide("Si30", 0.000326601, 'wo') - bot_plate.add_nuclide("Cr50", 0.007848910646, 'wo') bot_plate.add_nuclide("Cr52", 0.157390026871, 'wo') - bot_plate.add_nuclide("Cr53", 0.018191270146, 'wo') - bot_plate.add_nuclide("Cr54", 0.004612692337, 'wo') bot_plate.add_s_alpha_beta('c_H_in_H2O') bot_nozzle = openmc.Material(name='Bottom nozzle region', @@ -204,18 +128,8 @@ class InputSet(object): bot_nozzle.add_nuclide("Fe57", 0.01163454624, 'wo') bot_nozzle.add_nuclide("Fe58", 0.001578204652, 'wo') bot_nozzle.add_nuclide("Ni58", 0.047211231662, 'wo') - bot_nozzle.add_nuclide("Ni60", 0.018811987544, 'wo') - bot_nozzle.add_nuclide("Ni61", 0.000831139127, 'wo') - bot_nozzle.add_nuclide("Ni62", 0.002694352115, 'wo') - bot_nozzle.add_nuclide("Ni64", 0.000708189552, 'wo') bot_nozzle.add_nuclide("Mn55", 0.0156126, 'wo') - bot_nozzle.add_nuclide("Si28", 0.007171335558, 'wo') - bot_nozzle.add_nuclide("Si29", 0.000377356542, 'wo') - bot_nozzle.add_nuclide("Si30", 0.0002576079, 'wo') - bot_nozzle.add_nuclide("Cr50", 0.006190885148, 'wo') bot_nozzle.add_nuclide("Cr52", 0.124142524198, 'wo') - bot_nozzle.add_nuclide("Cr53", 0.014348496148, 'wo') - bot_nozzle.add_nuclide("Cr54", 0.003638294506, 'wo') bot_nozzle.add_s_alpha_beta('c_H_in_H2O') top_nozzle = openmc.Material(name='Top nozzle region', material_id=10) @@ -229,18 +143,8 @@ class InputSet(object): top_nozzle.add_nuclide("Fe57", 0.0101152584, 'wo') top_nozzle.add_nuclide("Fe58", 0.00137211607, 'wo') top_nozzle.add_nuclide("Ni58", 0.04104621835, 'wo') - top_nozzle.add_nuclide("Ni60", 0.0163554502, 'wo') - top_nozzle.add_nuclide("Ni61", 0.000722605975, 'wo') - top_nozzle.add_nuclide("Ni62", 0.002342513875, 'wo') - top_nozzle.add_nuclide("Ni64", 0.0006157116, 'wo') top_nozzle.add_nuclide("Mn55", 0.0135739, 'wo') - top_nozzle.add_nuclide("Si28", 0.006234853554, 'wo') - top_nozzle.add_nuclide("Si29", 0.000328078746, 'wo') - top_nozzle.add_nuclide("Si30", 0.0002239677, 'wo') - top_nozzle.add_nuclide("Cr50", 0.005382452306, 'wo') top_nozzle.add_nuclide("Cr52", 0.107931450781, 'wo') - top_nozzle.add_nuclide("Cr53", 0.012474806806, 'wo') - top_nozzle.add_nuclide("Cr54", 0.003163190107, 'wo') top_nozzle.add_s_alpha_beta('c_H_in_H2O') top_fa = openmc.Material(name='Top of fuel assemblies', material_id=11) diff --git a/tests/test_asymmetric_lattice/inputs_true.dat b/tests/test_asymmetric_lattice/inputs_true.dat index 9d278724f8..7e48dcf430 100644 --- a/tests/test_asymmetric_lattice/inputs_true.dat +++ b/tests/test_asymmetric_lattice/inputs_true.dat @@ -1 +1 @@ -dfb59bace10a91bb7ffc871d8ee87e91d94754bb8bb002ac6088f80fe0f480741c0489f74b753fc37158d0ff0f1368739ea60638b42083791311eefeac79168e \ No newline at end of file +6bcc9cca24d42995bdff9bf9aca5e852c2dbca5cfb42a12ac637def9cf5cac227654182fc9cf9e17d07cf2e9af11fea832e3ae0eb7001cc09856f73d219664f9 \ No newline at end of file diff --git a/tests/test_asymmetric_lattice/results_true.dat b/tests/test_asymmetric_lattice/results_true.dat index a33b9c9e59..c753afbc78 100644 --- a/tests/test_asymmetric_lattice/results_true.dat +++ b/tests/test_asymmetric_lattice/results_true.dat @@ -1 +1 @@ -bc8bef8121f9b6470e4fea817a4e48eabb1ecba1f42761a4cbd77d71181bf9e1612df4a3d6ddfbcd08a3086ac873e5f3c3e560bf96b2b7c959a2f7aad7e4e08d \ No newline at end of file +a2848fdb0a12c99ce31f4ddee766e0cf33bd5c6feca927bcb4bceca6fbb094bb1309fb8548589a99fcb09a830911457b9175b460aa45773822f8112a34b3b5c1 \ No newline at end of file diff --git a/tests/test_filter_mesh/inputs_true.dat b/tests/test_filter_mesh/inputs_true.dat index b683ebaeb0..d98e2f6f78 100644 --- a/tests/test_filter_mesh/inputs_true.dat +++ b/tests/test_filter_mesh/inputs_true.dat @@ -1 +1 @@ -5a9e65b8a8c9d7c575fc48c5d289bbc805739729a33d83aa79985473d83c8cc3a0c7dad8e95221090917c35ac4842667c8c9daecd06dc6b909a92475f5083753 \ No newline at end of file +c0882d16048d434219d32ed7b875615e00142b55ab78be5b51e0195e23cb534a3aa5a8e9c212f0bfff96c452177315deb1264421d688438814560b4131c88930 \ No newline at end of file diff --git a/tests/test_filter_mesh/results_true.dat b/tests/test_filter_mesh/results_true.dat index 2cc3c9532b..06cd450eff 100644 --- a/tests/test_filter_mesh/results_true.dat +++ b/tests/test_filter_mesh/results_true.dat @@ -1 +1 @@ -89387dd9e5b962c773e1782ff829846968dc456d899963f5dd98761fbde73a3f81676717ff3599bc26a1b77247826c38756735a9b2b329b80ad66286a62bd3f9 \ No newline at end of file +041b7e79d384771bad5bc6800138bd20be6af7d6e1543bdcfef521de3df33ef7b7aca00ea3ccb0234c3a4d7d738dfe17987b5c1a59474efef630217f8ee1af1e \ No newline at end of file diff --git a/tests/test_iso_in_lab/inputs_true.dat b/tests/test_iso_in_lab/inputs_true.dat index 310bccb139..454f891cd6 100644 --- a/tests/test_iso_in_lab/inputs_true.dat +++ b/tests/test_iso_in_lab/inputs_true.dat @@ -1 +1 @@ -4b3d0270a479e65579b305d1c2339b76971790bc7371c685efa6e2d341980fec301cf0859c34796ae04ae98aa01ab8b4905a8d8a3a916895c36d82ca6b58fb39 \ No newline at end of file +57d1ece4aa9633e5fc6d2fce9f7bba444d02046e0cdadc6e53efdf591b6e50fd0e5a14b956b7ad10710b4535b10354899e2ffc783fd78de5ccd09a061cb5678d \ No newline at end of file diff --git a/tests/test_iso_in_lab/results_true.dat b/tests/test_iso_in_lab/results_true.dat index 354ccb0f8c..5b2c5dd001 100644 --- a/tests/test_iso_in_lab/results_true.dat +++ b/tests/test_iso_in_lab/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.638450E-01 1.237705E-02 +9.753410E-01 6.608245E-02 diff --git a/tests/test_mgxs_library_mesh/inputs_true.dat b/tests/test_mgxs_library_mesh/inputs_true.dat index 6e3fc6e63e..a87549a607 100644 --- a/tests/test_mgxs_library_mesh/inputs_true.dat +++ b/tests/test_mgxs_library_mesh/inputs_true.dat @@ -1 +1 @@ -88b1a1b52bcae466bab63038d03e9b2fb9f2a28aac3d73573ca00d5f0c116aa9e1c97341215b80266e8317a0549f11d9adcb8726c82fcc1741a5a730e10c8186 \ No newline at end of file +5011f0aec7bb04e22f96cec2c23ae485fe21371dc03e16cb38695b3765cb92545459a897184b501bb99f8e7d162cfbf85eb3fb52ce2d82b2d2ca722b567cbff3 \ No newline at end of file diff --git a/tests/test_mgxs_library_mesh/results_true.dat b/tests/test_mgxs_library_mesh/results_true.dat index 8ad0f2eee1..16d20391cf 100644 --- a/tests/test_mgxs_library_mesh/results_true.dat +++ b/tests/test_mgxs_library_mesh/results_true.dat @@ -1,168 +1,168 @@ mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.640786 0.044177 -1 1 2 1 1 total 0.615276 0.104046 -2 2 1 1 1 total 0.660597 0.128423 -3 2 2 1 1 total 0.646999 0.186709 - mesh 1 group in nuclide mean std. dev. - x y z -0 1 1 1 1 total 0.36665 0.048814 -1 1 2 1 1 total 0.36356 0.074111 -2 2 1 1 1 total 0.40784 0.096486 -3 2 2 1 1 total 0.41456 0.160443 +0 1 1 1 1 total 0.654966 0.098415 +1 1 2 1 1 total 0.639357 0.282107 +2 2 1 1 1 total 0.713534 0.079789 +3 2 2 1 1 total 0.641095 0.091519 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.366650 0.048814 -1 1 2 1 1 total 0.363560 0.074111 -2 2 1 1 1 total 0.407840 0.096486 -3 2 2 1 1 total 0.414593 0.160436 +0 1 1 1 1 total 0.413423 0.087250 +1 1 2 1 1 total 0.392074 0.244272 +2 2 1 1 1 total 0.458841 0.087921 +3 2 2 1 1 total 0.403898 0.074343 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.025749 0.002863 -1 1 2 1 1 total 0.022988 0.004099 -2 2 1 1 1 total 0.028400 0.005275 -3 2 2 1 1 total 0.027589 0.010350 +0 1 1 1 1 total 0.413423 0.087250 +1 1 2 1 1 total 0.392074 0.244272 +2 2 1 1 1 total 0.458841 0.087921 +3 2 2 1 1 total 0.403898 0.074343 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.015861 0.002876 -1 1 2 1 1 total 0.014403 0.003542 -2 2 1 1 1 total 0.017280 0.004371 -3 2 2 1 1 total 0.018061 0.010110 +0 1 1 1 1 total 0.021476 0.004248 +1 1 2 1 1 total 0.020653 0.008355 +2 2 1 1 1 total 0.027384 0.003568 +3 2 2 1 1 total 0.021826 0.004584 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.009888 0.001077 -1 1 2 1 1 total 0.008585 0.001552 -2 2 1 1 1 total 0.011121 0.002456 -3 2 2 1 1 total 0.009527 0.003659 +0 1 1 1 1 total 0.013234 0.004146 +1 1 2 1 1 total 0.012342 0.006800 +2 2 1 1 1 total 0.016807 0.003428 +3 2 2 1 1 total 0.013253 0.004795 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.026065 0.002907 -1 1 2 1 1 total 0.022596 0.004062 -2 2 1 1 1 total 0.029084 0.006430 -3 2 2 1 1 total 0.025066 0.009687 +0 1 1 1 1 total 0.008241 0.001798 +1 1 2 1 1 total 0.008311 0.003296 +2 2 1 1 1 total 0.010577 0.001333 +3 2 2 1 1 total 0.008573 0.002017 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 1.938476 0.211550 -1 1 2 1 1 total 1.682799 0.303764 -2 2 1 1 1 total 2.177360 0.480780 -3 2 2 1 1 total 1.864890 0.715661 +0 1 1 1 1 total 0.020322 0.004415 +1 1 2 1 1 total 0.020546 0.008145 +2 2 1 1 1 total 0.026008 0.003213 +3 2 2 1 1 total 0.021015 0.004911 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.615037 0.041754 -1 1 2 1 1 total 0.592288 0.100439 -2 2 1 1 1 total 0.632196 0.123878 -3 2 2 1 1 total 0.619410 0.177190 +0 1 1 1 1 total 1.596880 0.348354 +1 1 2 1 1 total 1.610266 0.638515 +2 2 1 1 1 total 2.048209 0.257682 +3 2 2 1 1 total 1.660283 0.390011 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.584014 0.054315 -1 1 2 1 1 total 0.587256 0.084833 -2 2 1 1 1 total 0.622514 0.111323 -3 2 2 1 1 total 0.613792 0.168612 +0 1 1 1 1 total 0.633490 0.094536 +1 1 2 1 1 total 0.618705 0.273934 +2 2 1 1 1 total 0.686150 0.076703 +3 2 2 1 1 total 0.619269 0.087616 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.638348 0.097266 +1 1 2 1 1 total 0.588378 0.266032 +2 2 1 1 1 total 0.698373 0.092394 +3 2 2 1 1 total 0.625643 0.075089 mesh 1 group in group out nuclide moment mean std. dev. x y z -0 1 1 1 1 1 total P0 0.584014 0.054315 -1 1 1 1 1 1 total P1 0.243427 0.025488 -2 1 1 1 1 1 total P2 0.089236 0.007357 -3 1 1 1 1 1 total P3 0.008994 0.005768 -4 1 2 1 1 1 total P0 0.587256 0.084833 -5 1 2 1 1 1 total P1 0.245120 0.041033 -6 1 2 1 1 1 total P2 0.086784 0.016255 -7 1 2 1 1 1 total P3 0.008660 0.004755 -8 2 1 1 1 1 total P0 0.622514 0.111323 -9 2 1 1 1 1 total P1 0.239376 0.042594 -10 2 1 1 1 1 total P2 0.088386 0.017200 -11 2 1 1 1 1 total P3 -0.001243 0.005639 -12 2 2 1 1 1 total P0 0.612950 0.167940 -13 2 2 1 1 1 total P1 0.226176 0.061882 -14 2 2 1 1 1 total P2 0.086593 0.026126 -15 2 2 1 1 1 total P3 0.009672 0.011995 +0 1 1 1 1 1 total P0 0.638348 0.097266 +1 1 1 1 1 1 total P1 0.247099 0.035574 +2 1 1 1 1 1 total P2 0.092195 0.010891 +3 1 1 1 1 1 total P3 0.013224 0.004528 +4 1 2 1 1 1 total P0 0.588378 0.266032 +5 1 2 1 1 1 total P1 0.221552 0.102564 +6 1 2 1 1 1 total P2 0.069798 0.034699 +7 1 2 1 1 1 total P3 -0.003039 0.009633 +8 2 1 1 1 1 total P0 0.698373 0.092394 +9 2 1 1 1 1 total P1 0.261835 0.035253 +10 2 1 1 1 1 total P2 0.096206 0.013947 +11 2 1 1 1 1 total P3 0.016973 0.004808 +12 2 2 1 1 1 total P0 0.625643 0.075089 +13 2 2 1 1 1 total P1 0.244646 0.028604 +14 2 2 1 1 1 total P2 0.088580 0.012369 +15 2 2 1 1 1 total P3 0.019989 0.013950 mesh 1 group in group out nuclide moment mean std. dev. x y z -0 1 1 1 1 1 total P0 0.584014 0.054315 -1 1 1 1 1 1 total P1 0.243427 0.025488 -2 1 1 1 1 1 total P2 0.089236 0.007357 -3 1 1 1 1 1 total P3 0.008994 0.005768 -4 1 2 1 1 1 total P0 0.587256 0.084833 -5 1 2 1 1 1 total P1 0.245120 0.041033 -6 1 2 1 1 1 total P2 0.086784 0.016255 -7 1 2 1 1 1 total P3 0.008660 0.004755 -8 2 1 1 1 1 total P0 0.622514 0.111323 -9 2 1 1 1 1 total P1 0.239376 0.042594 -10 2 1 1 1 1 total P2 0.088386 0.017200 -11 2 1 1 1 1 total P3 -0.001243 0.005639 -12 2 2 1 1 1 total P0 0.613792 0.168612 -13 2 2 1 1 1 total P1 0.226142 0.061856 -14 2 2 1 1 1 total P2 0.086174 0.025979 -15 2 2 1 1 1 total P3 0.009721 0.012027 +0 1 1 1 1 1 total P0 0.638348 0.097266 +1 1 1 1 1 1 total P1 0.247099 0.035574 +2 1 1 1 1 1 total P2 0.092195 0.010891 +3 1 1 1 1 1 total P3 0.013224 0.004528 +4 1 2 1 1 1 total P0 0.588378 0.266032 +5 1 2 1 1 1 total P1 0.221552 0.102564 +6 1 2 1 1 1 total P2 0.069798 0.034699 +7 1 2 1 1 1 total P3 -0.003039 0.009633 +8 2 1 1 1 1 total P0 0.698373 0.092394 +9 2 1 1 1 1 total P1 0.261835 0.035253 +10 2 1 1 1 1 total P2 0.096206 0.013947 +11 2 1 1 1 1 total P3 0.016973 0.004808 +12 2 2 1 1 1 total P0 0.625643 0.075089 +13 2 2 1 1 1 total P1 0.244646 0.028604 +14 2 2 1 1 1 total P2 0.088580 0.012369 +15 2 2 1 1 1 total P3 0.019989 0.013950 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.0 0.153265 +1 1 2 1 1 1 total 1.0 0.454973 +2 2 1 1 1 1 total 1.0 0.146747 +3 2 2 1 1 1 total 1.0 0.141824 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 1.000000 0.088094 -1 1 2 1 1 1 total 1.000000 0.126864 -2 2 1 1 1 1 total 1.000000 0.160891 -3 2 2 1 1 1 total 1.001374 0.305883 - mesh 1 group in group out nuclide mean std. dev. - x y z -0 1 1 1 1 1 total 0.027395 0.004680 -1 1 2 1 1 1 total 0.019384 0.002846 -2 2 1 1 1 1 total 0.022914 0.006025 -3 2 2 1 1 1 total 0.029629 0.006292 +0 1 1 1 1 1 total 0.021059 0.003031 +1 1 2 1 1 1 total 0.017348 0.008786 +2 2 1 1 1 1 total 0.020409 0.003354 +3 2 2 1 1 1 total 0.011105 0.003806 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.220956 -1 1 2 1 1 total 1.0 0.132140 -2 2 1 1 1 total 1.0 0.316565 -3 2 2 1 1 total 1.0 0.181577 +0 1 1 1 1 total 1.0 0.135958 +1 1 2 1 1 total 1.0 0.557756 +2 2 1 1 1 total 1.0 0.201340 +3 2 2 1 1 total 1.0 0.475608 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.222246 -1 1 2 1 1 total 1.0 0.132140 -2 2 1 1 1 total 1.0 0.316565 -3 2 2 1 1 total 1.0 0.181577 +0 1 1 1 1 total 1.0 0.133151 +1 1 2 1 1 total 1.0 0.557756 +2 2 1 1 1 total 1.0 0.201340 +3 2 2 1 1 total 1.0 0.475608 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 3.610522e-07 3.169931e-08 -1 1 2 1 1 total 3.097784e-07 5.252025e-08 -2 2 1 1 1 total 3.942353e-07 8.459167e-08 -3 2 2 1 1 total 3.799163e-07 1.806470e-07 +0 1 1 1 1 total 4.697405e-07 8.304381e-08 +1 1 2 1 1 total 4.173069e-07 1.694647e-07 +2 2 1 1 1 total 6.581421e-07 1.337227e-07 +3 2 2 1 1 total 4.714011e-07 1.140489e-07 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.025920 0.002893 -1 1 2 1 1 total 0.022467 0.004039 -2 2 1 1 1 total 0.028922 0.006394 -3 2 2 1 1 total 0.024923 0.009632 +0 1 1 1 1 total 0.020173 0.004383 +1 1 2 1 1 total 0.020397 0.008086 +2 2 1 1 1 total 0.025824 0.003192 +3 2 2 1 1 total 0.020865 0.004879 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000004 4.432732e-07 -1 1 1 1 2 1 total 0.000026 2.653319e-06 -2 1 1 1 3 1 total 0.000024 2.402270e-06 -3 1 1 1 4 1 total 0.000054 5.464055e-06 -4 1 1 1 5 1 total 0.000026 2.663025e-06 -5 1 1 1 6 1 total 0.000010 1.038005e-06 -6 1 2 1 1 1 total 0.000004 6.987770e-07 -7 1 2 1 2 1 total 0.000023 4.115234e-06 -8 1 2 1 3 1 total 0.000021 3.816392e-06 -9 1 2 1 4 1 total 0.000049 8.885822e-06 -10 1 2 1 5 1 total 0.000024 4.378290e-06 -11 1 2 1 6 1 total 0.000009 1.745695e-06 -12 2 1 1 1 1 total 0.000005 1.098837e-06 -13 2 1 1 2 1 total 0.000029 6.436855e-06 -14 2 1 1 3 1 total 0.000027 5.926286e-06 -15 2 1 1 4 1 total 0.000061 1.359391e-05 -16 2 1 1 5 1 total 0.000029 6.489015e-06 -17 2 1 1 6 1 total 0.000011 2.574270e-06 -18 2 2 1 1 1 total 0.000004 1.660497e-06 -19 2 2 1 2 1 total 0.000025 9.701974e-06 -20 2 2 1 3 1 total 0.000023 9.005217e-06 -21 2 2 1 4 1 total 0.000054 2.084107e-05 -22 2 2 1 5 1 total 0.000026 9.981045e-06 -23 2 2 1 6 1 total 0.000010 3.987979e-06 +0 1 1 1 1 1 total 0.000005 1.004627e-06 +1 1 1 1 2 1 total 0.000025 5.397916e-06 +2 1 1 1 3 1 total 0.000025 5.274991e-06 +3 1 1 1 4 1 total 0.000058 1.230430e-05 +4 1 1 1 5 1 total 0.000026 5.548686e-06 +5 1 1 1 6 1 total 0.000011 2.306996e-06 +6 1 2 1 1 1 total 0.000004 1.779307e-06 +7 1 2 1 2 1 total 0.000024 9.648451e-06 +8 1 2 1 3 1 total 0.000024 9.479454e-06 +9 1 2 1 4 1 total 0.000056 2.231366e-05 +10 1 2 1 5 1 total 0.000026 1.028267e-05 +11 1 2 1 6 1 total 0.000011 4.268087e-06 +12 2 1 1 1 1 total 0.000006 7.462931e-07 +13 2 1 1 2 1 total 0.000031 3.842628e-06 +14 2 1 1 3 1 total 0.000031 3.666739e-06 +15 2 1 1 4 1 total 0.000071 8.228956e-06 +16 2 1 1 5 1 total 0.000031 3.416811e-06 +17 2 1 1 6 1 total 0.000013 1.429034e-06 +18 2 2 1 1 1 total 0.000005 1.049553e-06 +19 2 2 1 2 1 total 0.000025 5.392757e-06 +20 2 2 1 3 1 total 0.000024 5.145263e-06 +21 2 2 1 4 1 total 0.000056 1.156820e-05 +22 2 2 1 5 1 total 0.000025 4.880083e-06 +23 2 2 1 6 1 total 0.000010 2.037276e-06 mesh 1 delayedgroup group out nuclide mean std. dev. x y z 0 1 1 1 1 1 total 0.0 0.000000 1 1 1 1 2 1 total 0.0 0.000000 2 1 1 1 3 1 total 0.0 0.000000 -3 1 1 1 4 1 total 1.0 1.414214 -4 1 1 1 5 1 total 0.0 0.000000 +3 1 1 1 4 1 total 0.0 0.000000 +4 1 1 1 5 1 total 1.0 1.414214 5 1 1 1 6 1 total 0.0 0.000000 6 1 2 1 1 1 total 0.0 0.000000 7 1 2 1 2 1 total 0.0 0.000000 @@ -184,53 +184,53 @@ 23 2 2 1 6 1 total 0.0 0.000000 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000166 0.000023 -1 1 1 1 2 1 total 0.000989 0.000136 -2 1 1 1 3 1 total 0.000907 0.000123 -3 1 1 1 4 1 total 0.002087 0.000282 -4 1 1 1 5 1 total 0.001014 0.000137 -5 1 1 1 6 1 total 0.000400 0.000054 -6 1 2 1 1 1 total 0.000167 0.000030 -7 1 2 1 2 1 total 0.001002 0.000178 -8 1 2 1 3 1 total 0.000926 0.000165 -9 1 2 1 4 1 total 0.002149 0.000384 -10 1 2 1 5 1 total 0.001056 0.000189 -11 1 2 1 6 1 total 0.000417 0.000076 -12 2 1 1 1 1 total 0.000171 0.000039 -13 2 1 1 2 1 total 0.001003 0.000226 -14 2 1 1 3 1 total 0.000918 0.000208 -15 2 1 1 4 1 total 0.002100 0.000477 -16 2 1 1 5 1 total 0.000996 0.000228 -17 2 1 1 6 1 total 0.000394 0.000090 -18 2 2 1 1 1 total 0.000171 0.000082 -19 2 2 1 2 1 total 0.001007 0.000480 -20 2 2 1 3 1 total 0.000929 0.000445 -21 2 2 1 4 1 total 0.002143 0.001028 -22 2 2 1 5 1 total 0.001026 0.000492 -23 2 2 1 6 1 total 0.000408 0.000196 +0 1 1 1 1 1 total 0.000227 0.000061 +1 1 1 1 2 1 total 0.001228 0.000327 +2 1 1 1 3 1 total 0.001206 0.000320 +3 1 1 1 4 1 total 0.002835 0.000748 +4 1 1 1 5 1 total 0.001300 0.000340 +5 1 1 1 6 1 total 0.000540 0.000141 +6 1 2 1 1 1 total 0.000218 0.000074 +7 1 2 1 2 1 total 0.001182 0.000400 +8 1 2 1 3 1 total 0.001160 0.000393 +9 1 2 1 4 1 total 0.002726 0.000926 +10 1 2 1 5 1 total 0.001249 0.000428 +11 1 2 1 6 1 total 0.000519 0.000177 +12 2 1 1 1 1 total 0.000226 0.000033 +13 2 1 1 2 1 total 0.001207 0.000174 +14 2 1 1 3 1 total 0.001175 0.000167 +15 2 1 1 4 1 total 0.002721 0.000378 +16 2 1 1 5 1 total 0.001207 0.000160 +17 2 1 1 6 1 total 0.000502 0.000067 +18 2 2 1 1 1 total 0.000220 0.000068 +19 2 2 1 2 1 total 0.001178 0.000355 +20 2 2 1 3 1 total 0.001150 0.000343 +21 2 2 1 4 1 total 0.002675 0.000783 +22 2 2 1 5 1 total 0.001199 0.000341 +23 2 2 1 6 1 total 0.000499 0.000142 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.00000 0.000000 -1 1 1 1 2 1 total 0.00000 0.000000 -2 1 1 1 3 1 total 0.00000 0.000000 -3 1 1 1 4 1 total 0.30278 0.428196 -4 1 1 1 5 1 total 0.00000 0.000000 -5 1 1 1 6 1 total 0.00000 0.000000 -6 1 2 1 1 1 total 0.00000 0.000000 -7 1 2 1 2 1 total 0.00000 0.000000 -8 1 2 1 3 1 total 0.00000 0.000000 -9 1 2 1 4 1 total 0.00000 0.000000 -10 1 2 1 5 1 total 0.00000 0.000000 -11 1 2 1 6 1 total 0.00000 0.000000 -12 2 1 1 1 1 total 0.00000 0.000000 -13 2 1 1 2 1 total 0.00000 0.000000 -14 2 1 1 3 1 total 0.00000 0.000000 -15 2 1 1 4 1 total 0.00000 0.000000 -16 2 1 1 5 1 total 0.00000 0.000000 -17 2 1 1 6 1 total 0.00000 0.000000 -18 2 2 1 1 1 total 0.00000 0.000000 -19 2 2 1 2 1 total 0.00000 0.000000 -20 2 2 1 3 1 total 0.00000 0.000000 -21 2 2 1 4 1 total 0.00000 0.000000 -22 2 2 1 5 1 total 0.00000 0.000000 -23 2 2 1 6 1 total 0.00000 0.000000 +0 1 1 1 1 1 total 0.00000 0.00000 +1 1 1 1 2 1 total 0.00000 0.00000 +2 1 1 1 3 1 total 0.00000 0.00000 +3 1 1 1 4 1 total 0.00000 0.00000 +4 1 1 1 5 1 total 0.84949 1.20136 +5 1 1 1 6 1 total 0.00000 0.00000 +6 1 2 1 1 1 total 0.00000 0.00000 +7 1 2 1 2 1 total 0.00000 0.00000 +8 1 2 1 3 1 total 0.00000 0.00000 +9 1 2 1 4 1 total 0.00000 0.00000 +10 1 2 1 5 1 total 0.00000 0.00000 +11 1 2 1 6 1 total 0.00000 0.00000 +12 2 1 1 1 1 total 0.00000 0.00000 +13 2 1 1 2 1 total 0.00000 0.00000 +14 2 1 1 3 1 total 0.00000 0.00000 +15 2 1 1 4 1 total 0.00000 0.00000 +16 2 1 1 5 1 total 0.00000 0.00000 +17 2 1 1 6 1 total 0.00000 0.00000 +18 2 2 1 1 1 total 0.00000 0.00000 +19 2 2 1 2 1 total 0.00000 0.00000 +20 2 2 1 3 1 total 0.00000 0.00000 +21 2 2 1 4 1 total 0.00000 0.00000 +22 2 2 1 5 1 total 0.00000 0.00000 +23 2 2 1 6 1 total 0.00000 0.00000 diff --git a/tests/test_tallies/inputs_true.dat b/tests/test_tallies/inputs_true.dat index 5f4bebb0d2..d716a171ce 100644 --- a/tests/test_tallies/inputs_true.dat +++ b/tests/test_tallies/inputs_true.dat @@ -1 +1 @@ -96d2f92c6017e62d688e3ca245c2ff7904a92816d188d096829440cd8fcfd4f8639dc67c12d54b324081c19e1c7dd2e79c1caeac53d7826399f11766826d5410 \ No newline at end of file +b112ccd96ff89c706c62b4c334021e352de78fc494c4c0513ca7a924bb2e9b18139c5b4fd50c9a92fff07525cc1d9b1464fcc5ca24293e6fd3a8d03d9e12b171 \ No newline at end of file diff --git a/tests/test_tallies/results_true.dat b/tests/test_tallies/results_true.dat index 108c7ee800..6b3bbf4d53 100644 --- a/tests/test_tallies/results_true.dat +++ b/tests/test_tallies/results_true.dat @@ -1 +1 @@ -a6afd2f11affce2467d77b8477881ab20091f67df4f632226ec2dd5d4cd7fabb9ac3e182563bb467ed249e4b3fe95b319cb688d653757f8ea154759b8a7f50e1 \ No newline at end of file +1e0ce3915c37809cf147e5c0634b696bafd99fa3f41573235d884e54a9a62e8440234a4ee1bf4ce94b363e7afde2ded7c0fd22d0dd897b8aacf1ee017b974449 \ No newline at end of file diff --git a/tests/test_tally_aggregation/inputs_true.dat b/tests/test_tally_aggregation/inputs_true.dat index 6d2990754d..d0f617dbfe 100644 --- a/tests/test_tally_aggregation/inputs_true.dat +++ b/tests/test_tally_aggregation/inputs_true.dat @@ -1 +1 @@ -4a4e481b9af3612c71bdc93245011555807061bbd9d9be4c5b399f2c38820d38d9ce3ac6255d045415a216737eac65fb0f0b6e331e49b90bf8edc814d0f2f0e8 \ No newline at end of file +e6604f58a6a3115b902364ac9c73fcb8babb9df0c527b0b04780fefda61fb41856cffac548a1f81fba5fdac8ab55dd00f683b724c732ed54506933e9d943574d \ No newline at end of file diff --git a/tests/test_tally_aggregation/results_true.dat b/tests/test_tally_aggregation/results_true.dat index 6c2d7a5193..929fc9fcf8 100644 --- a/tests/test_tally_aggregation/results_true.dat +++ b/tests/test_tally_aggregation/results_true.dat @@ -1 +1 @@ -840d2648f9ba782926c71baa84e5a2ad31331e156740a3d1e9d86af8f1f0d301ef8c0f69474975d365dbcf8d229a68c62d3e60286d18045e5254373f4e1010bf \ No newline at end of file +2fba1e497435b63ee277a1c8a0ecc566440c56a25cdfef1b790b839fc93da1414bd1af38a63a64fcf3e868d1347ad138f528ae12c1067aea29733670d2c9128f \ No newline at end of file diff --git a/tests/test_tally_aggregation/test_tally_aggregation.py b/tests/test_tally_aggregation/test_tally_aggregation.py index 955d7fecbb..f1915b261e 100644 --- a/tests/test_tally_aggregation/test_tally_aggregation.py +++ b/tests/test_tally_aggregation/test_tally_aggregation.py @@ -16,9 +16,9 @@ class TallyAggregationTestHarness(PyAPITestHarness): self._input_set.settings.output = {'summary': True} # Initialize the nuclides + u234 = openmc.Nuclide('U234') u235 = openmc.Nuclide('U235') u238 = openmc.Nuclide('U238') - pu239 = openmc.Nuclide('Pu239') # Initialize the filters energy_filter = openmc.EnergyFilter([0.0, 0.253e-6, 1.0e-3, 1.0, 20.0]) @@ -28,7 +28,7 @@ class TallyAggregationTestHarness(PyAPITestHarness): tally = openmc.Tally(name='distribcell tally') tally.filters = [energy_filter, distrib_filter] tally.scores = ['nu-fission', 'total'] - tally.nuclides = [u235, u238, pu239] + tally.nuclides = [u234, u235, u238] tallies_file = openmc.Tallies([tally]) # Export tallies to file @@ -59,7 +59,7 @@ class TallyAggregationTestHarness(PyAPITestHarness): outstr += ', '.join(map(str, tally_sum.std_dev)) # Sum across all nuclides - tally_sum = tally.summation(nuclides=['U235', 'U238', 'Pu239']) + tally_sum = tally.summation(nuclides=['U234', 'U235', 'U238']) outstr += ', '.join(map(str, tally_sum.mean)) outstr += ', '.join(map(str, tally_sum.std_dev)) diff --git a/tests/test_tally_arithmetic/inputs_true.dat b/tests/test_tally_arithmetic/inputs_true.dat index b0da0ed247..8cf6c4ff5d 100644 --- a/tests/test_tally_arithmetic/inputs_true.dat +++ b/tests/test_tally_arithmetic/inputs_true.dat @@ -1 +1 @@ -6747131dad4c1efd8c87d857ce9127cb16ec883fdf5fabe309d82732d47851424273e9ad4878a335555d8b25bb0c0a15e68ac30e355ae346e9885c499e9ec979 \ No newline at end of file +530c54691a4f2df131627849dd58c5e6f331ede786c1ffff0b1126c4c0fe64929a15113699103a05f2c6178ec90be4a3d6fc12b80c32ec608ed4a59c965ef2e4 \ No newline at end of file diff --git a/tests/test_tally_arithmetic/test_tally_arithmetic.py b/tests/test_tally_arithmetic/test_tally_arithmetic.py index 6e52313ef7..d28db3e959 100644 --- a/tests/test_tally_arithmetic/test_tally_arithmetic.py +++ b/tests/test_tally_arithmetic/test_tally_arithmetic.py @@ -19,9 +19,9 @@ class TallyArithmeticTestHarness(PyAPITestHarness): tallies_file = openmc.Tallies() # Initialize the nuclides + u234 = openmc.Nuclide('U234') u235 = openmc.Nuclide('U235') u238 = openmc.Nuclide('U238') - pu239 = openmc.Nuclide('Pu239') # Initialize Mesh mesh = openmc.Mesh(mesh_id=1) @@ -40,7 +40,7 @@ class TallyArithmeticTestHarness(PyAPITestHarness): tally = openmc.Tally(name='tally 1') tally.filters = [material_filter, energy_filter, distrib_filter] tally.scores = ['nu-fission', 'total'] - tally.nuclides = [u235, pu239] + tally.nuclides = [u234, u235] tallies_file.append(tally) tally = openmc.Tally(name='tally 2') diff --git a/tests/test_tally_slice_merge/inputs_true.dat b/tests/test_tally_slice_merge/inputs_true.dat index 7a747e6b52..ef2595fbfd 100644 --- a/tests/test_tally_slice_merge/inputs_true.dat +++ b/tests/test_tally_slice_merge/inputs_true.dat @@ -1 +1 @@ -144dd4059444fad5e2e4fa20681fbdc74c0e5cbf3265104a0b49d87c768798eaeb25e3c6c795bcac2eebdde784c51588006d62c9f25be96dda5c51011a76b7c1 \ No newline at end of file +41b06951808ee7ed1e44defbaadff7305737ae494e8e98c682aefa272c0682cbd8803dd2658d8e7d78e3f5f7fb1e9f0f5e443a9374a68474bd25d0d649ac6924 \ No newline at end of file diff --git a/tests/test_tally_slice_merge/results_true.dat b/tests/test_tally_slice_merge/results_true.dat index 278d8ee108..0f43b35e1f 100644 --- a/tests/test_tally_slice_merge/results_true.dat +++ b/tests/test_tally_slice_merge/results_true.dat @@ -1,36 +1,36 @@ cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 fission 1.08e-01 7.94e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 nu-fission 2.64e-01 1.94e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U238 fission 1.51e-07 1.00e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U238 nu-fission 3.76e-07 2.50e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U235 fission 3.12e-02 2.56e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U235 nu-fission 7.65e-02 6.24e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U238 fission 2.00e-02 1.30e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 6.25e-07 2.00e+01 U238 nu-fission 5.56e-02 3.78e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U235 fission 4.43e-02 7.21e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U235 nu-fission 1.08e-01 1.76e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U238 fission 6.14e-08 9.64e-09 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-07 U238 nu-fission 1.53e-07 2.40e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U235 fission 1.39e-02 1.06e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U235 nu-fission 3.40e-02 2.61e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U238 fission 9.72e-03 1.21e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 27 6.25e-07 2.00e+01 U238 nu-fission 2.71e-02 3.80e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-07 U235 fission 1.08e-01 7.94e-03 -1 21 0.00e+00 6.25e-07 U235 nu-fission 2.64e-01 1.94e-02 -2 21 0.00e+00 6.25e-07 U238 fission 1.51e-07 1.00e-08 -3 21 0.00e+00 6.25e-07 U238 nu-fission 3.76e-07 2.50e-08 -4 21 6.25e-07 2.00e+01 U235 fission 3.12e-02 2.56e-03 -5 21 6.25e-07 2.00e+01 U235 nu-fission 7.65e-02 6.24e-03 -6 21 6.25e-07 2.00e+01 U238 fission 2.00e-02 1.30e-03 -7 21 6.25e-07 2.00e+01 U238 nu-fission 5.56e-02 3.78e-03 -8 27 0.00e+00 6.25e-07 U235 fission 4.43e-02 7.21e-03 -9 27 0.00e+00 6.25e-07 U235 nu-fission 1.08e-01 1.76e-02 -10 27 0.00e+00 6.25e-07 U238 fission 6.14e-08 9.64e-09 -11 27 0.00e+00 6.25e-07 U238 nu-fission 1.53e-07 2.40e-08 -12 27 6.25e-07 2.00e+01 U235 fission 1.39e-02 1.06e-03 -13 27 6.25e-07 2.00e+01 U235 nu-fission 3.40e-02 2.61e-03 -14 27 6.25e-07 2.00e+01 U238 fission 9.72e-03 1.21e-03 -15 27 6.25e-07 2.00e+01 U238 nu-fission 2.71e-02 3.80e-03 +0 21 0.00e+00 6.25e-07 U235 fission 2.36e-01 2.26e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U235 nu-fission 5.74e-01 5.51e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U238 fission 3.19e-07 3.06e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U238 nu-fission 7.96e-07 7.63e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U235 fission 2.82e-02 1.82e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U235 nu-fission 6.92e-02 4.42e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U238 fission 1.98e-02 1.74e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 6.25e-07 2.00e+01 U238 nu-fission 5.54e-02 4.65e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U235 fission 1.11e-01 1.16e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U235 nu-fission 2.71e-01 2.83e-02 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U238 fission 1.53e-07 1.67e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-07 U238 nu-fission 3.81e-07 4.15e-08 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U235 fission 2.00e-02 2.72e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U235 nu-fission 4.89e-02 6.62e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U238 fission 1.06e-02 6.18e-04 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 27 6.25e-07 2.00e+01 U238 nu-fission 2.91e-02 1.85e-03 cell energy low [MeV] energy high [MeV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-07 U235 fission 2.36e-01 2.26e-02 +1 21 0.00e+00 6.25e-07 U235 nu-fission 5.74e-01 5.51e-02 +2 21 0.00e+00 6.25e-07 U238 fission 3.19e-07 3.06e-08 +3 21 0.00e+00 6.25e-07 U238 nu-fission 7.96e-07 7.63e-08 +4 21 6.25e-07 2.00e+01 U235 fission 2.82e-02 1.82e-03 +5 21 6.25e-07 2.00e+01 U235 nu-fission 6.92e-02 4.42e-03 +6 21 6.25e-07 2.00e+01 U238 fission 1.98e-02 1.74e-03 +7 21 6.25e-07 2.00e+01 U238 nu-fission 5.54e-02 4.65e-03 +8 27 0.00e+00 6.25e-07 U235 fission 1.11e-01 1.16e-02 +9 27 0.00e+00 6.25e-07 U235 nu-fission 2.71e-01 2.83e-02 +10 27 0.00e+00 6.25e-07 U238 fission 1.53e-07 1.67e-08 +11 27 0.00e+00 6.25e-07 U238 nu-fission 3.81e-07 4.15e-08 +12 27 6.25e-07 2.00e+01 U235 fission 2.00e-02 2.72e-03 +13 27 6.25e-07 2.00e+01 U235 nu-fission 4.89e-02 6.62e-03 +14 27 6.25e-07 2.00e+01 U238 fission 1.06e-02 6.18e-04 +15 27 6.25e-07 2.00e+01 U238 nu-fission 2.91e-02 1.85e-03 sum(distribcell) energy low [MeV] energy high [MeV] nuclide score mean std. dev. 0 (0, 100, 2000, 30000) 0.00e+00 6.25e-07 U235 fission 0.00e+00 0.00e+00 1 (0, 100, 2000, 30000) 0.00e+00 6.25e-07 U235 nu-fission 0.00e+00 0.00e+00 @@ -49,19 +49,19 @@ 14 (500, 5000, 50000) 6.25e-07 2.00e+01 U238 fission 0.00e+00 0.00e+00 15 (500, 5000, 50000) 6.25e-07 2.00e+01 U238 nu-fission 0.00e+00 0.00e+00 sum(mesh) energy low [MeV] energy high [MeV] nuclide score mean std. dev. -0 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 fission 8.54e-03 1.30e-03 -1 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.08e-02 3.17e-03 -2 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.21e-08 1.74e-09 -3 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.01e-08 4.34e-09 -4 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 fission 2.20e-03 6.05e-04 -5 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 5.38e-03 1.48e-03 -6 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 fission 1.40e-03 7.17e-04 -7 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 3.84e-03 1.97e-03 -8 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 fission 9.40e-03 1.62e-03 -9 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.29e-02 3.95e-03 -10 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.34e-08 2.08e-09 -11 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.33e-08 5.18e-09 -12 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 fission 9.41e-04 2.52e-04 -13 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 2.31e-03 6.13e-04 -14 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 fission 7.54e-04 3.45e-04 -15 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 2.12e-03 1.02e-03 +0 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 fission 1.12e-02 2.45e-03 +1 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 2.74e-02 5.96e-03 +2 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.56e-08 3.04e-09 +3 ((1, 1, 1), (1, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 3.89e-08 7.57e-09 +4 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 fission 1.15e-03 4.71e-04 +5 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 2.81e-03 1.15e-03 +6 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 fission 3.25e-04 9.99e-05 +7 ((1, 1, 1), (1, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 8.81e-04 2.68e-04 +8 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 fission 1.44e-02 5.57e-03 +9 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U235 nu-fission 3.51e-02 1.36e-02 +10 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 fission 1.95e-08 7.37e-09 +11 ((2, 1, 1), (2, 2, 1)) 0.00e+00 6.25e-07 U238 nu-fission 4.86e-08 1.84e-08 +12 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 fission 2.55e-03 1.30e-03 +13 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U235 nu-fission 6.23e-03 3.16e-03 +14 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 fission 8.62e-04 4.53e-04 +15 ((2, 1, 1), (2, 2, 1)) 6.25e-07 2.00e+01 U238 nu-fission 2.30e-03 1.21e-03 From 935d72af0dc9c81532239f875862381d91f92167 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 15:19:47 -0400 Subject: [PATCH 52/82] Resolution of @paulromano comments --- .gitignore | 6 - docs/source/io_formats/mgxs_library.rst | 52 +++--- openmc/mesh.py | 6 +- openmc/mgxs/library.py | 2 +- openmc/mgxs_library.py | 95 +++++----- scripts/openmc-update-mgxs.py | 232 ------------------------ src/geometry_header.F90 | 78 +++++++- src/hdf5_interface.F90 | 33 +--- src/input_xml.F90 | 87 ++------- src/mgxs_data.F90 | 56 +----- src/mgxs_header.F90 | 114 ++++++------ src/nuclide_header.F90 | 8 +- src/sab_header.F90 | 6 +- src/secondary_uncorrelated.F90 | 7 +- 14 files changed, 254 insertions(+), 528 deletions(-) delete mode 100755 scripts/openmc-update-mgxs.py diff --git a/.gitignore b/.gitignore index 21db60397c..2ca1c7d145 100644 --- a/.gitignore +++ b/.gitignore @@ -50,8 +50,6 @@ tests/ctestscript.run # HDF5 files *.h5 -!tests/1d_mgxs.h5 -!examples/xml/pincell_multigroup/mgxs.h5 # Build files src/CMakeCache.txt @@ -91,7 +89,3 @@ docs/source/pythonapi/examples/mgxs docs/source/pythonapi/examples/tracks docs/source/pythonapi/examples/fission-rates docs/source/pythonapi/examples/plots - -# VSCode workspace directory -.vscode -.vscode/* diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 04474c01b5..e9b59a20f2 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -38,8 +38,8 @@ MGXS Library Specification The data within contains the temperature-dependent multi-group data for the nuclide or material that it represents. -:Attributes: - **awr** (*double*) -- The atomic weight ratio (optional, i.e. it - is not meaningful for material-wise data) +:Attributes: - **atomic_weight_ratio** (*double*) -- The atomic weight ratio (optional, + i.e. it is not meaningful for material-wise data) - **fissionable** (*int*) -- Whether the dataset is fissionable (1) or not (0). - **representation** (*char[]*) -- The method used to generate and @@ -49,26 +49,27 @@ data for the nuclide or material that it represents. data was generated with angular dependent fluxes and thus the data is angle-dependent. Valid values are either "isotropic" or "angle". - - **num-azimuthal** (*int*) -- Number of equal width angular bins + - **num_azimuthal** (*int*) -- Number of equal width angular bins that the azimuthal angular domain is subdivided if the `representation` attribute is "angle". This parameter is ignored otherwise. - - **num-polar** (*int*) -- Number of equal width angular bins + - **num_polar** (*int*) -- Number of equal width angular bins that the polar angular domain is subdivided if the `representation` attribute is "angle". This parameter is ignored otherwise. - - **scatter-format** (*char[]*) -- The representation of the + - **scatter_format** (*char[]*) -- The representation of the scattering angular distribution. The options are either "legendre", "histogram", or "tabular". If not provided, the default of "legendre" will be assumed. - **order** (*int*) -- Either the Legendre order, number of bins, - or number of points (depending on the value of `scatter-format`) + or number of points (depending on the value of `scatter_format`) used to describe the angular distribution associated with each group-to-group transfer probability. **//kTs/** -:Datasets: - **K** (*double*) -- kT values (in MeV) for each Temperature +:Datasets: + - **K** (*double*) -- kT values (in MeV) for each Temperature TTT (in Kelvin), rounded to the nearest integer **//K/** @@ -109,44 +110,44 @@ Temperature-dependent data, provided for temperature K. the `nu-fission` data must represent the fission neutron energy spectra as well and thus will have one additional dimension for the outgoing energy group. In this case, `nu-fission` has the - same dimensionality as `multiplicity matrix`. - - **inverse velocities** (*double[]*) -- Average inverse velocity + same dimensionality as `multiplicity_matrix`. + - **inverse_velocities** (*double[]*) -- Average inverse velocity for each of the groups in the library. This dataset is optional. -**//K/scatter data/** +**//K/scatter_data/** Data specific to neutron scattering for the temperature K -:Datasets: - **g_min** (*int[]* or *int[][][]) -- +:Datasets: - **g_min** (*int[]* or *int[][][]*) -- Minimum (most energetic) outgoing groups with non-zero values of the scattering matrix. These group numbers use the standard ordering where the fastest neutron energy group is group 1 while the slowest neutron energy group is group G. - The dimensionality of `g_out bounds` is: - `g_min[g_in]`, or `g_min[num-polar][num-azimuthal][g_in]`. + The dimensionality of `g_min` is: + `g_min[g_in]`, or `g_min[num_polar][num_azimuthal][g_in]`. The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". - - **g_max** (*int[]* or *int[][][]) -- + - **g_max** (*int[]* or *int[][][]*) -- Maximum (least energetic) outgoing groups with non-zero values of the scattering matrix. These group numbers use the standard ordering where the fastest neutron energy group is group 1 while the slowest neutron energy group is group G. - The dimensionality of `g_out bounds` is: - `g_max[g_in]`, or `g_max[num-polar][num-azimuthal][g_in]`. + The dimensionality of `g_max` is: + `g_max[g_in]`, or `g_max[num_polar][num_azimuthal][g_in]`. The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". - - **scatter matrix** (*double[]*) -- Flattened representation of the + - **scatter_matrix** (*double[]*) -- Flattened representation of the scattering moment matrices. The pre-flattened array is shaped as follows (in row-major format): - `scatter matrix[order(+1)][g_in][g_out]`, or - `scatter matrix[num-polar][num-azimuthal][order(+1)][g_in][g_out]` + `scatter_matrix[order(+1)][g_in][g_out]`, or + `scatter_matrix[num_polar][num_azimuthal][order(+1)][g_in][g_out]` The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". Note that if the value of - `scatter-format` is "legendre", the order dimension will be one + `scatter_format` is "legendre", the order dimension will be one larger than the value of `order`, otherwise it will match `order`. Finally, the g_out dimension has a dimensionality of - `g_out bounds`[0] to `g_out bounds`[1]. - - **multiplicity matrix** (*double[]*) -- Flattened representation of + `g_min` to `g_max`. + - **multiplicity_matrix** (*double[]*) -- Flattened representation of the scattering moment matrices. This dataset provides the code with a scaling factor to account for neutrons being produced in (n,xn) reactions. This is assumed isotropic and therefore is not repeated @@ -154,9 +155,8 @@ Data specific to neutron scattering for the temperature K optional, if it is not provided no multiplication (i.e., values of 1.0) will be assumed. The pre-flattened array is shaped as follows (in row-major format): - `multiplicity matrix[g_in][g_out]`, or - `multiplicity matrix[num-polar][num-azimuthal][g_in][g_out]` + `multiplicity_matrix[g_in][g_out]`, or + `multiplicity_matrix[num_polar][num_azimuthal][g_in][g_out]` The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". Finally, the g_out - dimension has a dimensionality of `g_out bounds`[0] to - `g_out bounds`[1]. \ No newline at end of file + dimension has a dimensionality of `g_min` to `g_max`. \ No newline at end of file diff --git a/openmc/mesh.py b/openmc/mesh.py index af65a2a164..2d5fda09bc 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -298,12 +298,12 @@ class Mesh(object): # Would prefer to have the z ranges be the max supported float, but # these values are apparently different between python and Fortran. # Choosing a safe and sane default. - # Values of +/-1000 are used here as there seems to be an + # Values of +/-1e10 are used here as there seems to be an # inconsistency between what numpy uses as the max float and what # Fortran expects for a real(8), so this avoids code complication # and achieves the same goal. - zplanes = [openmc.ZPlane(z0=-1000., boundary_type='reflective'), - openmc.ZPlane(z0=1000., boundary_type='reflective')] + zplanes = [openmc.ZPlane(z0=-1e10., boundary_type='reflective'), + openmc.ZPlane(z0=1e10., boundary_type='reflective')] else: zplanes = [openmc.ZPlane(z0=self.lower_left[2], boundary_type=bc[4]), diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 02c63f50bb..c4515c9693 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -912,7 +912,7 @@ class Library(object): self.representation = 'isotropic' if nuclide is not 'total': - xsdata.awr = self._nuclides[nuclide][1] + xsdata.atomic_weight_ratio = self._nuclides[nuclide][1] if subdomain is None: subdomain = 'all' diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index cba5c20a15..2bc320b7b7 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -31,7 +31,7 @@ class XSdata(object): representation : {'isotropic', 'angle'}, optional Method used in generating the MGXS (isotropic or angle-dependent flux weighting). Defaults to 'isotropic' - temperatures : numpy.ndarray + temperatures : Iterable of float Temperatures (in units of Kelvin) of the provided datasets. Defaults to a single temperature at 294K. @@ -39,7 +39,7 @@ class XSdata(object): ---------- name : str Unique identifier for the xsdata object - awr : float + aromic_weight_ratio : float Atomic weight ratio of an isotope. That is, the ratio of the mass of the isotope to the mass of a single neutron. temperatures : numpy.ndarray @@ -60,24 +60,26 @@ class XSdata(object): weighting). num_azimuthal : int Number of equal width angular bins that the azimuthal angular domain is - subdivided into. This only applies when ``representation`` is "angle". + subdivided into. This only applies when :attr:`XSdata.representation` + is "angle". num_polar : int Number of equal width angular bins that the polar angular domain is - subdivided into. This only applies when ``representation`` is "angle". + subdivided into. This only applies when :attr:`XSdata.representation` + is "angle". use_chi : bool Whether or not a chi vector or nu-fission matrix was used. vector_shape : iterable of int Dimensionality of vector multi-group cross sections (e.g., the total cross section). The return result depends on the value of - ``representation``. + :attr:`XSdata.representation`. matrix_shape : iterable of int Dimensionality of matrix multi-group cross sections (e.g., the fission matrix cross section). The return result depends on the - value of ``representation``. + value of :attr:`XSdata.representation`. pn_matrix_shape : iterable of int Dimensionality of scattering matrix data (e.g., the scattering matrix cross section). The return result depends on the - value of ``representation``. + value of :attr:`XSdata.representation`. total : dict of numpy.ndarray Group-wise total cross section. absorption : dict of numpy.ndarray @@ -101,20 +103,22 @@ class XSdata(object): approximation that the fission spectra does not depend on incoming energy. If the user does not wish to make this approximation, then this should not be provided and this information included in the - ``nu_fission`` attribute instead. + :attr:`XSdata.nu_fission` attribute instead. nu_fission : dict of numpy.ndarray - Group-wise fission production cross section vector (i.e., if ``chi`` is - provided), or is the group-wise fission production matrix. + Group-wise fission production cross section vector (i.e., if + :attr:`XSdata.chi` is provided), or is the group-wise fission production + matrix. inverse_velocities : dict of numpy.ndarray Inverse of velocities, in units of sec/cm. Notes ----- The parameters containing cross section data have dimensionalities which - depend upon the value of ``representation`` as well as the number of - Legendre or other angular dimensions as described by ``order``. The - ``vector_shape``, ``matrix_shape``, and ``pn_matrix_shape`` properties are - provided to obtain the dimensionality of the data for each temperature. + depend upon the value of :attr:`XSdata.representation` as well as the + number of Legendre or other angular dimensions as described by + :attr:`XSdata.order`. The :attr:`XSdata.vector_shape`, + :attr:`XSdata.matrix_shape`, and :attr:`XSdata.pn_matrix_shape` properties + are provided to obtain the dimensionality of the data for each temperature. The following are cross sections which should use each of these properties: @@ -135,7 +139,7 @@ class XSdata(object): self.energy_groups = energy_groups self.temperatures = temperatures self.representation = representation - self._awr = None + self._atomic_weight_ratio = None self._fissionable = False self._scatter_format = 'legendre' self._order = None @@ -165,8 +169,8 @@ class XSdata(object): return self._representation @property - def awr(self): - return self._awr + def atomic_weight_ratio(self): + return self._atomic_weight_ratio @property def fissionable(self): @@ -286,12 +290,12 @@ class XSdata(object): check_value('representation', representation, _REPRESENTATIONS) self._representation = representation - @awr.setter - def awr(self, awr): - # Check validity of type and that the awr value is > 0 - check_type('awr', awr, Real) - check_greater_than('awr', awr, 0.0) - self._awr = awr + @atomic_weight_ratio.setter + def atomic_weight_ratio(self, atomic_weight_ratio): + # Check validity of type and that the atomic_weight_ratio value is > 0 + check_type('atomic_weight_ratio', atomic_weight_ratio, Real) + check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) + self._atomic_weight_ratio = atomic_weight_ratio @fissionable.setter def fissionable(self, fissionable): @@ -300,14 +304,9 @@ class XSdata(object): @temperatures.setter def temperatures(self, temperatures): - check_type('temperatures', temperatures, Iterable, - expected_iter_type=Real) - # Convert to a numpy array so we can easily get the shape for checking - nptemperatures = np.asarray(temperatures) + check_iterable_type('temperatures', temperatures, Real) - check_value('temperatures dimensionality', nptemperatures.ndim, [1]) - - self._temperatures = nptemperatures + self._temperatures = temperatures @scatter_format.setter def scatter_format(self, scatter_format): @@ -1113,10 +1112,18 @@ class XSdata(object): self._multiplicity_matrix[i] = \ np.nan_to_num(self._multiplicity_matrix[i]) - def _get_xsdata_group(self, file): + def to_hdf5(self, file): + """Write XSdata to an HDF5 file + + Parameters + ---------- + file : h5py.File + HDF5 File (a root Group) to write to + + """ grp = file.create_group(self.name) - if self.awr is not None: - grp.attrs['awr'] = self.awr + if self.atomic_weight_ratio is not None: + grp.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio if self.fissionable is not None: grp.attrs['fissionable'] = self.fissionable if self.representation is not None: @@ -1124,11 +1131,11 @@ class XSdata(object): dtype='S') if self.representation == 'angle': if self.num_azimuthal is not None: - grp.attrs['num-azimuthal'] = self.num_azimuthal + grp.attrs['num_azimuthal'] = self.num_azimuthal if self.num_polar is not None: - grp.attrs['num-polar'] = self.num_polar + grp.attrs['num_polar'] = self.num_polar if self.scatter_format is not None: - grp.attrs['scatter-format'] = np.array(self.scatter_format, + grp.attrs['scatter_format'] = np.array(self.scatter_format, dtype='S') if self.order is not None: grp.attrs['order'] = self.order @@ -1184,8 +1191,8 @@ class XSdata(object): for l in range(len(matrix[:, g_in, g_out])): flat_scatt.append(matrix[l, g_in, g_out]) # And write it. - scatt_grp = xs_grp.create_group('scatter data') - scatt_grp.create_dataset("scatter matrix", + scatt_grp = xs_grp.create_group('scatter_data') + scatt_grp.create_dataset("scatter_matrix", data=np.array(flat_scatt)) # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: @@ -1196,7 +1203,7 @@ class XSdata(object): for g_out in range(g_out_bounds[g_in, 0], g_out_bounds[g_in, 1] + 1): flat_mult.append(matrix[g_in, g_out]) - scatt_grp.create_dataset("multiplicity matrix", + scatt_grp.create_dataset("multiplicity_matrix", data=np.array(flat_mult)) # And finally, adjust g_out_bounds for 1-based group counting @@ -1227,8 +1234,8 @@ class XSdata(object): for l in range(len(matrix[:, g_in, g_out])): flat_scatt.append(matrix[l, g_in, g_out]) # And write it. - scatt_grp = xs_grp.create_group('scatter data') - scatt_grp.create_dataset("scatter matrix", + scatt_grp = xs_grp.create_group('scatter_data') + scatt_grp.create_dataset("scatter_matrix", data=np.array(flat_scatt)) # Repeat for multiplicity if self._multiplicity_matrix[i] is not None: @@ -1242,7 +1249,7 @@ class XSdata(object): g_out_bounds[p, a, g_in, 1] + 1): flat_mult.append(matrix[g_in, g_out]) # And write it. - scatt_grp.create_dataset("multiplicity matrix", + scatt_grp.create_dataset("multiplicity_matrix", data=np.array(flat_mult)) # And finally, adjust g_out_bounds for 1-based group counting @@ -1253,7 +1260,7 @@ class XSdata(object): # Add the kinetics data if self._inverse_velocities[i] is not None: - xs_grp.create_dataset("inverse-velocities", + xs_grp.create_dataset("inverse_velocities", data=self._inverse_velocities[i]) @@ -1364,6 +1371,6 @@ class MGXSLibrary(object): file.attrs['group structure'] = self.energy_groups.group_edges for xsdata in self._xsdatas: - xsdata._get_xsdata_group(file) + xsdata.to_hdf5(file) file.close() diff --git a/scripts/openmc-update-mgxs.py b/scripts/openmc-update-mgxs.py deleted file mode 100755 index e3fd1bd2f6..0000000000 --- a/scripts/openmc-update-mgxs.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python -"""Update OpenMC's deprecated multi-group cross section XML files to the latest -HDF5-based format. - -Usage information can be obtained by running 'openmc-update-mgxs --help': - -usage: openmc-update-mgxs [-h] in out - -Update mgxs.xml files to the latest format. This will remove 'outside' -attributes/elements from lattices and replace them with 'outer' attributes. For -'cell' elements, any 'surfaces' attributes/elements will be renamed -'region'. Note that this script will not delete the given files; it will append -'.original' to the given files and write new ones. - -positional arguments: - in Input mgxs xml file - out Output mgxs hdf5 file - -optional arguments: - -h, --help show this help message and exit - -""" - -from __future__ import print_function -from shutil import move -import warnings -import xml.etree.ElementTree as ET - -import argparse -import h5py -import numpy as np - -import openmc.mgxs_library - -description = """\ -Update OpenMC's deprecated multi-group cross section XML files to the latest -HDF5-based format.""" - - -def parse_args(): - """Read the input files from the commandline.""" - # Create argument parser - parser = argparse.ArgumentParser(description=description, - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('-i', '--input', type=argparse.FileType('r'), - help='input XML file') - parser.add_argument('-o', '--output', nargs='?', default='', - help='output file, in HDF5 format') - parser.add_argument('-c', '--compression', type=int, - help='HDF5 Compression Level') - args = vars(parser.parse_args()) - - if args['output'] == '': - filename = args['input'].name - extension = filename[filename.rfind('.'):] - if extension == '.xml': - filename = filename[:filename.rfind('.')] + '.h5' - args['output'] = filename - - # Parse and return commandline arguments. - return args - - -def get_data(element, entry): - try: - value = element.find(entry).text - except: - if entry in element.attrib: - value = element.attrib[entry] - else: - value = None - - if value is not None: - value = value.strip() - - return value - - -if __name__ == '__main__': - args = parse_args() - - # Parse the XML data. - tree = ET.parse(args['input']) - root = tree.getroot() - - # Get old metadata - temp = tree.find('group_structure').text.strip() - temp = np.array(temp.split()) - group_structure = temp.astype(np.float) - energy_groups = openmc.mgxs.EnergyGroups(group_structure) - temp = tree.find('inverse_velocities') - if temp is not None: - temp = temp.text.strip() - temp = np.array(temp.split()) - inverse_velocities = temp.astype(np.float) - else: - inverse_velocities = None - - xsd = [] - names = [] - - # Now move on to the cross section data itself - for xsdata_elem in root.iter('xsdata'): - name = get_data(xsdata_elem, 'name') - - temperature = get_data(xsdata_elem, 'kT') - if temperature is not None: - temperature = \ - float(temperature) / openmc.data.K_BOLTZMANN - else: - temperature = 294. - temperatures = [temperature] - - awr = get_data(xsdata_elem, 'awr') - if awr is not None: - awr = float(awr) - - representation = get_data(xsdata_elem, 'representation') - if representation is None: - representation = 'isotropic' - if representation == 'angle': - n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) - n_pol = int(get_data(xsdata_elem, 'num_polar')) - - scatter_format = get_data(xsdata_elem, 'scatt_type') - if scatter_format is None: - scatter_format = 'legendre' - - order = int(get_data(xsdata_elem, 'order')) - - tab_leg = get_data(xsdata_elem, 'tabular_legendre') - if tab_leg is not None: - warnings.Warning('The tabular_legendre option has moved to the ' - 'settings.xml file and must be added manually') - - # Either add the data to a previously existing xsdata (if it is - # for the same 'name' but a different temperature), or create a - # new one. - try: - # It is in our list, so store that entry - i = names.index(name) - except: - # It is not in our list, so add it - i = -1 - xsd.append(openmc.XSdata(name, energy_groups, - temperatures=temperatures, - representation=representation)) - if awr is not None: - xsd[-1].awr = awr - if representation == 'angle': - xsd[-1].num_azimuthal = n_azi - xsd[-1].num_polar = n_pol - xsd[-1].scatter_format = scatter_format - xsd[-1].order = order - names.append(name) - - if scatter_format == 'legendre': - order_dim = order + 1 - else: - order_dim = order - - if i != -1: - xsd[i].add_temperature(temperature) - - temp = get_data(xsdata_elem, 'total') - if temp is not None: - temp = np.array(temp.split()) - total = temp.astype(np.float) - total = np.reshape(total, xsd[i].vector_shape) - xsd[i].set_total(total, temperature) - - if inverse_velocities is not None: - xsd[i].set_inverse_velocities(inverse_velocities, temperature) - - temp = get_data(xsdata_elem, 'absorption') - temp = np.array(temp.split()) - absorption = temp.astype(np.float) - absorption = np.reshape(absorption, xsd[i].vector_shape) - xsd[i].set_absorption(absorption, temperature) - - temp = get_data(xsdata_elem, 'scatter') - temp = np.array(temp.split()) - temp = temp.astype(np.float) - scatter = np.reshape(temp, xsd[i].pn_matrix_shape) - xsd[i].set_scatter_matrix(scatter, temperature) - - temp = get_data(xsdata_elem, 'multiplicity') - if temp is not None: - temp = np.array(temp.split()) - temp = temp.astype(np.float) - multiplicity = np.reshape(temp, xsd[i].matrix_shape) - xsd[i].set_multiplicity_matrix(multiplicity, temperature) - - temp = get_data(xsdata_elem, 'fission') - if temp is not None: - temp = np.array(temp.split()) - fission = temp.astype(np.float) - fission = np.reshape(fission, xsd[i].vector_shape) - xsd[i].set_fission(fission, temperature) - - temp = get_data(xsdata_elem, 'kappa_fission') - if temp is not None: - temp = np.array(temp.split()) - kappa_fission = temp.astype(np.float) - kappa_fission = np.reshape(kappa_fission, xsd[i].vector_shape) - xsd[i].set_kappa_fission(kappa_fission, temperature) - - temp = get_data(xsdata_elem, 'chi') - if temp is not None: - temp = np.array(temp.split()) - chi = temp.astype(np.float) - chi = np.reshape(chi, xsd[i].vector_shape) - xsd[i].set_chi(chi, temperature) - else: - chi = None - - temp = get_data(xsdata_elem, 'nu_fission') - if temp is not None: - temp = np.array(temp.split()) - temp = temp.astype(np.float) - if chi is not None: - nu_fission = np.reshape(temp, xsd[i].vector_shape) - else: - nu_fission = np.reshape(temp, xsd[i].matrix_shape) - xsd[i].set_nu_fission(nu_fission, temperature) - - # Build library as we go, but first we have enough to initialize it - lib = openmc.MGXSLibrary(energy_groups) - - lib.add_xsdatas(xsd) - - lib.export_to_hdf5(args['output']) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 1d1826fbfb..3b489ece7d 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -1,6 +1,12 @@ module geometry_header - use constants, only: HALF, TWO, THREE, INFINITY + use algorithm, only: find + use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & + MATERIAL_VOID, NONE + use dict_header, only: DictCharInt, DictIntInt + use material_header, only: Material + use stl_vector, only: VectorReal + use string, only: to_lower implicit none @@ -319,4 +325,74 @@ contains end if end function get_local_hex +!=============================================================================== +! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table +! appears at in the model. Later, this list is used to determine the actual +! temperatures to read (which may be different if interpolation is used) +!=============================================================================== + + subroutine get_temperatures(cells, materials, material_dict, nuclide_dict, & + n_nucs, nuc_temps, sab_dict, n_sabs, sab_temps) + type(Cell), allocatable, intent(in) :: cells(:) + type(Material), allocatable, intent(in) :: materials(:) + type(DictIntInt), intent(in) :: material_dict + type(DictCharInt), intent(in) :: nuclide_dict + integer, intent(in) :: n_nucs + type(VectorReal), allocatable, intent(out) :: nuc_temps(:) + type(DictCharInt), optional, intent(in) :: sab_dict + integer, optional, intent(in) :: n_sabs + type(VectorReal), optional, allocatable, intent(out) :: sab_temps(:) + + integer :: i, j, k + integer :: i_nuclide ! index in nuclides array + integer :: i_sab ! index in S(a,b) array + integer :: i_material + real(8) :: temperature ! temperature in Kelvin + + allocate(nuc_temps(n_nucs)) + if (present(n_sabs) .and. present(sab_temps)) allocate(sab_temps(n_sabs)) + + do i = 1, size(cells) + do j = 1, size(cells(i) % material) + ! Skip any non-material cells and void materials + if (cells(i) % material(j) == NONE .or. & + cells(i) % material(j) == MATERIAL_VOID) cycle + + ! Get temperature of cell (rounding to nearest integer) + if (size(cells(i) % sqrtkT) > 1) then + temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN + else + temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN + end if + + i_material = material_dict % get_key(cells(i) % material(j)) + associate (mat => materials(i_material)) + NUC_NAMES_LOOP: do k = 1, size(mat % names) + ! Get index in nuc_temps array + i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k))) + + ! Add temperature if it hasn't already been added + if (find(nuc_temps(i_nuclide), temperature) == -1) then + call nuc_temps(i_nuclide) % push_back(temperature) + end if + end do NUC_NAMES_LOOP + + if (present(sab_temps) .and. present(sab_dict) .and. & + mat % n_sab > 0) then + SAB_NAMES_LOOP: do k = 1, size(mat % sab_names) + ! Get index in nuc_temps array + i_sab = sab_dict % get_key(to_lower(mat % sab_names(k))) + + ! Add temperature if it hasn't already been added + if (find(sab_temps(i_sab), temperature) == -1) then + call sab_temps(i_sab) % push_back(temperature) + end if + end do SAB_NAMES_LOOP + end if + end associate + end do + end do + + end subroutine get_temperatures + end module geometry_header diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index 262bbc232c..ce689afa3b 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -85,17 +85,16 @@ module hdf5_interface public :: write_dataset public :: read_dataset - public :: check_attribute + public :: attribute_exists public :: write_attribute public :: read_attribute public :: file_create public :: file_open public :: file_close public :: create_group - public :: check_group + public :: object_exists public :: open_group public :: close_group - public :: check_dataset public :: open_dataset public :: close_dataset public :: get_shape @@ -253,7 +252,7 @@ contains ! CHECK_ATTRIBUTE Checks to see if an attribute exists in the object !=============================================================================== - function check_attribute(object_id, name) result(exists) + function attribute_exists(object_id, name) result(exists) integer(HID_T), intent(in) :: object_id character(*), intent(in) :: name ! name of group logical :: exists @@ -263,13 +262,13 @@ contains ! Check if attribute exists call h5aexists_by_name_f(object_id, '.', trim(name), exists, hdf5_err) - end function check_attribute + end function attribute_exists !=============================================================================== ! CHECK_GROUP Checks to see if a group exists in the object !=============================================================================== - function check_group(object_id, name) result(exists) + function object_exists(object_id, name) result(exists) integer(HID_T), intent(in) :: object_id character(*), intent(in) :: name ! name of group logical :: exists @@ -279,21 +278,7 @@ contains ! Check if group exists call h5ltpath_valid_f(object_id, trim(name), .true., exists, hdf5_err) - end function check_group - -!=============================================================================== -! CHECK_DATASET Checks to see if a dataset exists in the object -!=============================================================================== - - function check_dataset(object_id, name) result(exists) - integer(HID_T), intent(in) :: object_id - character(*), intent(in) :: name ! name of group - logical :: exists - - ! Wrap check_group since the method used there will work here too - exists = check_group(object_id, name) - - end function check_dataset + end function object_exists !=============================================================================== ! GET_DATASETS Gets a list of all the datasets in a given location. @@ -367,7 +352,7 @@ contains integer :: hdf5_err ! HDF5 error code ! Check if group exists - exists = check_group(group_id, name) + exists = object_exists(group_id, name) ! open group if it exists if (exists) then @@ -390,7 +375,7 @@ contains logical :: exists ! does the group exist ! Check if group exists - exists = check_group(group_id, name) + exists = object_exists(group_id, name) ! create group if (exists) then @@ -428,7 +413,7 @@ contains integer :: hdf5_err ! HDF5 error code ! Check if group exists - exists = check_group(group_id, name) + exists = object_exists(group_id, name) ! open group if it exists if (exists) then diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 2959e876dd..8d56285671 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1,17 +1,15 @@ module input_xml - use hdf5 - - use algorithm, only: find use cmfd_input, only: configure_cmfd use constants - use dict_header, only: DictIntInt, ElemKeyValueCI + use dict_header, only: DictIntInt, DictCharInt, ElemKeyValueCI use distribution_multivariate use distribution_univariate use endf, only: reaction_name use energy_grid, only: grid_method, n_log_bins use error, only: fatal_error, warning - use geometry_header, only: Cell, Lattice, RectLattice, HexLattice + use geometry_header, only: Cell, Lattice, RectLattice, HexLattice, & + get_temperatures use global use hdf5_interface use list_header, only: ListChar, ListInt, ListReal @@ -61,6 +59,9 @@ contains call time_read_xs % stop() end if + ! Normalize atom/weight percents + if (run_mode /= MODE_PLOTTING) call normalize_ao() + end subroutine read_input_xml !=============================================================================== @@ -2097,7 +2098,9 @@ contains call assign_temperatures(material_temps) ! Determine desired temperatures for each nuclide and S(a,b) table - call get_temperatures(nuc_temps, sab_temps) + call get_temperatures(cells, materials, material_dict, nuclide_dict, & + n_nuclides_total, nuc_temps, sab_dict, & + n_sab_tables, sab_temps) ! Read continuous-energy cross sections if (run_CE .and. run_mode /= MODE_PLOTTING) then @@ -2106,9 +2109,6 @@ contains call time_read_xs % stop() end if - ! Normalize atom/weight percents - if (run_mode /= MODE_PLOTTING) call normalize_ao() - ! Clear dictionary call library_dict % clear() end subroutine read_materials @@ -4631,7 +4631,7 @@ contains ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) - if (check_attribute(file_id, "groups")) then + if (attribute_exists(file_id, "groups")) then ! Get neutron group count call read_attribute(energy_groups, file_id, "groups") else @@ -4640,7 +4640,7 @@ contains allocate(rev_energy_bins(energy_groups + 1)) allocate(energy_bins(energy_groups + 1)) - if (check_attribute(file_id, "group structure")) then + if (attribute_exists(file_id, "group structure")) then ! Get neutron group structure call read_attribute(energy_bins, file_id, "group structure") else @@ -5621,7 +5621,7 @@ contains if (run_CE) then awr = nuclides(mat % nuclide(j)) % awr else - awr = ONE + awr = nuclides_MG(mat % nuclide(j)) % obj % awr end if ! if given weight percent, convert all values so that they are divided @@ -5646,7 +5646,7 @@ contains if (run_CE) then awr = nuclides(mat % nuclide(j)) % awr else - awr = ONE + awr = nuclides_MG(mat % nuclide(j)) % obj % awr end if x = mat % atom_density(j) sum_percent = sum_percent + x*awr @@ -5910,67 +5910,6 @@ contains end do end subroutine assign_temperatures -!=============================================================================== -! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table -! appears at in the model. Later, this list is used to determine the actual -! temperatures to read (which may be different if interpolation is used) -!=============================================================================== - - subroutine get_temperatures(nuc_temps, sab_temps) - type(VectorReal), allocatable, intent(out) :: nuc_temps(:) - type(VectorReal), allocatable, intent(out) :: sab_temps(:) - - integer :: i, j, k - integer :: i_nuclide ! index in nuclides array - integer :: i_sab ! index in S(a,b) array - integer :: i_material - real(8) :: temperature ! temperature in Kelvin - - allocate(nuc_temps(n_nuclides_total)) - allocate(sab_temps(n_sab_tables)) - - do i = 1, size(cells) - do j = 1, size(cells(i) % material) - ! Skip any non-material cells and void materials - if (cells(i) % material(j) == NONE .or. & - cells(i) % material(j) == MATERIAL_VOID) cycle - - ! Get temperature of cell (rounding to nearest integer) - if (size(cells(i) % sqrtkT) > 1) then - temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN - else - temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN - end if - - i_material = material_dict % get_key(cells(i) % material(j)) - associate (mat => materials(i_material)) - NUC_NAMES_LOOP: do k = 1, size(mat % names) - ! Get index in nuc_temps array - i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k))) - - ! Add temperature if it hasn't already been added - if (find(nuc_temps(i_nuclide), temperature) == -1) then - call nuc_temps(i_nuclide) % push_back(temperature) - end if - end do NUC_NAMES_LOOP - - if (mat % n_sab > 0) then - SAB_NAMES_LOOP: do k = 1, size(mat % sab_names) - ! Get index in nuc_temps array - i_sab = sab_dict % get_key(to_lower(mat % sab_names(k))) - - ! Add temperature if it hasn't already been added - if (find(sab_temps(i_sab), temperature) == -1) then - call sab_temps(i_sab) % push_back(temperature) - end if - end do SAB_NAMES_LOOP - end if - end associate - end do - end do - - end subroutine get_temperatures - !=============================================================================== ! READ_0K_ELASTIC_SCATTERING !=============================================================================== diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index 2fbfdfd420..857b2ded05 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -3,8 +3,9 @@ module mgxs_data use constants use algorithm, only: find use error, only: fatal_error + use geometry_header, only: get_temperatures use global - use hdf5 + use hdf5_interface use material_header, only: Material use mgxs_header use output, only: write_message @@ -49,7 +50,8 @@ contains call write_message("Loading Cross Section Data...", 5) ! Get temperatures - call get_temperatures(temps) + call get_temperatures(cells, materials, material_dict, nuclide_dict, & + n_nuclides_total, temps) ! Open file for reading file_id = file_open(path_cross_sections, 'r', parallel=.true.) @@ -94,7 +96,7 @@ contains call write_message("Loading " // trim(name) // " Data...", 5) ! Check to make sure cross section set exists in the library - if (check_group(file_id, trim(name))) then + if (object_exists(file_id, trim(name))) then xsdata_group = open_group(file_id, trim(name)) else call fatal_error("Data for '" // trim(name) // "' does not exist in "& @@ -102,7 +104,7 @@ contains end if ! First find out the data representation - if (check_attribute(xsdata_group, "representation")) then + if (attribute_exists(xsdata_group, "representation")) then call read_attribute(temp_str, xsdata_group, "representation") if (trim(temp_str) == 'isotropic') then representation = MGXS_ISOTROPIC @@ -236,51 +238,5 @@ contains end subroutine get_mat_kTs -!=============================================================================== -! GET_TEMPERATURES returns a list of temperatures that each MGXS table -! appears at in the model. Later, this list is used to determine the actual -! temperatures to read (which may be different if interpolation is used) -!=============================================================================== - - subroutine get_temperatures(temps) - type(VectorReal), allocatable, intent(out) :: temps(:) - - integer :: i, j, k - integer :: i_nuclide ! index in nuclides array - integer :: i_material - real(8) :: temperature ! temperature in Kelvin - - allocate(temps(n_nuclides_total)) - - do i = 1, size(cells) - do j = 1, size(cells(i) % material) - ! Skip any non-material cells and void materials - if (cells(i) % material(j) == NONE .or. & - cells(i) % material(j) == MATERIAL_VOID) cycle - - ! Get temperature of cell (rounding to nearest integer) - if (size(cells(i) % sqrtkT) > 1) then - temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN - else - temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN - end if - - i_material = material_dict % get_key(cells(i) % material(j)) - associate (mat => materials(i_material)) - NUC_NAMES_LOOP: do k = 1, size(mat % names) - ! Get index in temps array - i_nuclide = nuclide_dict % get_key(to_lower(mat % names(k))) - - ! Add temperature if it hasn't already been added - if (find(temps(i_nuclide), temperature) == -1) then - call temps(i_nuclide) % push_back(temperature) - end if - end do NUC_NAMES_LOOP - end associate - end do - end do - - end subroutine get_temperatures - end module mgxs_data diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index 193f337f13..ddce50be38 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -229,8 +229,8 @@ module mgxs_header ! Get rid of leading '/' this % name = trim(this % name(2:)) - if (check_attribute(xs_id, "awr")) then - call read_attribute(this % awr, xs_id, "awr") + if (attribute_exists(xs_id, "atomic_weight_ratio")) then + call read_attribute(this % awr, xs_id, "atomic_weight_ratio") else this % awr = -ONE end if @@ -323,8 +323,8 @@ module mgxs_header end select ! Load the remaining metadata - if (check_attribute(xs_id, "scatter-format")) then - call read_attribute(temp_str, xs_id, "scatter-format") + if (attribute_exists(xs_id, "scatter_format")) then + call read_attribute(temp_str, xs_id, "scatter_format") temp_str = trim(temp_str) if (to_lower(temp_str) == 'legendre') then this % scatter_format = ANGLE_LEGENDRE @@ -333,19 +333,19 @@ module mgxs_header else if (to_lower(temp_str) == 'tabular') then this % scatter_format = ANGLE_TABULAR else - call fatal_error("Invalid scatter-format option!") + call fatal_error("Invalid scatter_format option!") end if else this % scatter_format = ANGLE_LEGENDRE end if - if (check_attribute(xs_id, "fissionable")) then + if (attribute_exists(xs_id, "fissionable")) then call read_attribute(this % fissionable, xs_id, "fissionable") else call fatal_error("Fissionable element must be set!") end if ! Get the library's value for the order - if (check_attribute(xs_id, "order")) then + if (attribute_exists(xs_id, "order")) then call read_attribute(order_dim, xs_id, "order") else call fatal_error("Order must be provided!") @@ -366,16 +366,16 @@ module mgxs_header ! information therein select type(this) type is (MgxsAngle) - if (check_attribute(xs_id, "num-polar")) then - call read_attribute(this % n_pol, xs_id, "num-polar") + if (attribute_exists(xs_id, "num_polar")) then + call read_attribute(this % n_pol, xs_id, "num_polar") else - call fatal_error("num-polar must be provided!") + call fatal_error("num_polar must be provided!") end if - if (check_attribute(xs_id, "num-azimuthal")) then - call read_attribute(this % n_azi, xs_id, "num-azimuthal") + if (attribute_exists(xs_id, "num_azimuthal")) then + call read_attribute(this % n_azi, xs_id, "num_azimuthal") else - call fatal_error("num-azimuthal must be provided!") + call fatal_error("num_azimuthal must be provided!") end if ! Set angle data to use equally-spaced bins @@ -433,7 +433,7 @@ module mgxs_header if (this % fissionable) then allocate(xs % nu_fission(groups)) allocate(xs % chi(groups, groups)) - if (check_dataset(xsdata_grp, "chi")) then + if (object_exists(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi allocate(temp_arr(groups)) @@ -448,7 +448,7 @@ module mgxs_header deallocate(temp_arr) ! Get nu_fission (as a vector) - if (check_dataset(xsdata_grp, "nu-fission")) then + if (object_exists(xsdata_grp, "nu-fission")) then call read_dataset(xs % nu_fission, xsdata_grp, "nu-fission") else call fatal_error("If fissionable, must provide nu-fission!") @@ -457,7 +457,7 @@ module mgxs_header else ! chi isnt provided but is within nu_fission, existing as a matrix ! So, get nu_fission (as a matrix) - if (check_dataset(xsdata_grp, "nu-fission")) then + if (object_exists(xsdata_grp, "nu-fission")) then allocate(temp_2d(groups, groups)) call read_dataset(temp_2d, xsdata_grp, "nu-fission") else @@ -481,7 +481,7 @@ module mgxs_header ! If we have a need* for the fission and kappa-fission x/s, get them ! (*Need is defined as will be using it to tally) if (get_fiss) then - if (check_dataset(xsdata_grp, "fission")) then + if (object_exists(xsdata_grp, "fission")) then allocate(xs % fission(groups)) call read_dataset(xs % fission, xsdata_grp, "fission") else @@ -490,7 +490,7 @@ module mgxs_header end if end if if (get_kfiss) then - if (check_dataset(xsdata_grp, "kappa-fission")) then + if (object_exists(xsdata_grp, "kappa-fission")) then allocate(xs % k_fission(groups)) call read_dataset(xs % k_fission, xsdata_grp, "kappa-fission") else @@ -500,7 +500,7 @@ module mgxs_header end if end if - if (check_dataset(xsdata_grp, "absorption")) then + if (object_exists(xsdata_grp, "absorption")) then allocate(xs % absorption(groups)) call read_dataset(xs % absorption, xsdata_grp, "absorption") else @@ -508,21 +508,21 @@ module mgxs_header end if ! Get scattering data - if (.not. check_group(xsdata_grp, "scatter data")) & - call fatal_error("Must provide 'scatter data'") - scatt_grp = open_group(xsdata_grp, 'scatter data') + if (.not. object_exists(xsdata_grp, "scatter_data")) & + call fatal_error("Must provide 'scatter_data'") + scatt_grp = open_group(xsdata_grp, 'scatter_data') ! First get the outgoing group boundary indices - if (check_dataset(scatt_grp, "g_min")) then + if (object_exists(scatt_grp, "g_min")) then allocate(gmin(groups)) call read_dataset(gmin, scatt_grp, "g_min") else - call fatal_error("'g_min' for the scatter matrix must be provided") + call fatal_error("'g_min' for the scatter_data must be provided") end if - if (check_dataset(scatt_grp, "g_max")) then + if (object_exists(scatt_grp, "g_max")) then allocate(gmax(groups)) call read_dataset(gmax, scatt_grp, "g_max") else - call fatal_error("'g_max' for the scatter matrix must be provided") + call fatal_error("'g_max' for the scatter_data must be provided") end if ! Now use this information to find the length of a container array @@ -533,9 +533,9 @@ module mgxs_header end do ! Allocate flattened array allocate(temp_arr(length)) - if (.not. check_dataset(scatt_grp, 'scatter matrix')) & - call fatal_error("'scatter matrix' must be provided") - call read_dataset(temp_arr, scatt_grp, "scatter matrix") + if (.not. object_exists(scatt_grp, 'scatter_matrix')) & + call fatal_error("'scatter_matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter_matrix") ! Compare the number of orders given with the maximum order of the ! problem. Strip off the supefluous orders if needed. @@ -611,7 +611,7 @@ module mgxs_header deallocate(input_scatt) ! Now get the multiplication matrix - if (check_dataset(scatt_grp, 'multiplicity matrix')) then + if (object_exists(scatt_grp, 'multiplicity_matrix')) then ! Now use this information to find the length of a container array ! to hold the flattened data length = 0 @@ -620,7 +620,7 @@ module mgxs_header end do ! Allocate flattened array allocate(temp_arr(length)) - call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + call read_dataset(temp_arr, scatt_grp, "multiplicity_matrix") ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing ! to ScattData @@ -664,7 +664,7 @@ module mgxs_header ! Get, or infer, total xs data. allocate(xs % total(groups)) - if (check_dataset(xsdata_grp, "total")) then + if (object_exists(xsdata_grp, "total")) then call read_dataset(xs % total, xsdata_grp, "total") else xs % total(:) = xs % absorption(:) + xs % scatter % scattxs(:) @@ -677,9 +677,9 @@ module mgxs_header end do ! Get kinetics data - if (check_dataset(xsdata_grp, "inverse-velocities")) then + if (object_exists(xsdata_grp, "inverse_velocities")) then allocate(xs % inv_vel(groups)) - call read_dataset(xs % inv_vel, xsdata_grp, "inverse-velocities") + call read_dataset(xs % inv_vel, xsdata_grp, "inverse_velocities") end if ! Close the groups we have opened and deallocate @@ -731,7 +731,7 @@ module mgxs_header if (this % fissionable) then allocate(xs % nu_fission(groups, this % n_azi, this % n_pol)) allocate(xs % chi(groups, groups, this % n_azi, this % n_pol)) - if (check_dataset(xsdata_grp, "chi")) then + if (object_exists(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi allocate(temp_arr(groups * this % n_azi * this % n_pol)) @@ -764,7 +764,7 @@ module mgxs_header deallocate(temp_arr) ! Get nu_fission (as a vector) - if (check_dataset(xsdata_grp, "nu-fission")) then + if (object_exists(xsdata_grp, "nu-fission")) then allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "nu-fission") xs % nu_fission = reshape(temp_arr, (/groups, this % n_azi, & @@ -777,7 +777,7 @@ module mgxs_header else ! chi isnt provided but is within nu_fission, existing as a matrix ! So, get nu_fission (as a matrix) - if (check_dataset(xsdata_grp, "nu-fission")) then + if (object_exists(xsdata_grp, "nu-fission")) then allocate(temp_arr(groups * groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "nu-fission") allocate(temp_4d(groups, groups, this % n_azi, this % n_pol)) @@ -816,7 +816,7 @@ module mgxs_header ! If we have a need* for the fission and kappa-fission x/s, get them ! (*Need is defined as will be using it to tally) if (get_fiss) then - if (check_dataset(xsdata_grp, "fission")) then + if (object_exists(xsdata_grp, "fission")) then allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "fission") allocate(xs % fission(groups, this % n_azi, this % n_pol)) @@ -829,7 +829,7 @@ module mgxs_header end if end if if (get_kfiss) then - if (check_dataset(xsdata_grp, "kappa-fission")) then + if (object_exists(xsdata_grp, "kappa-fission")) then allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "kappa-fission") allocate(xs % k_fission(groups, this % n_azi, this % n_pol)) @@ -843,7 +843,7 @@ module mgxs_header end if end if - if (check_dataset(xsdata_grp, "absorption")) then + if (object_exists(xsdata_grp, "absorption")) then allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "absorption") allocate(xs % absorption(groups, this % n_azi, this % n_pol)) @@ -855,27 +855,27 @@ module mgxs_header end if ! Get scattering data - if (.not. check_group(xsdata_grp, "scatter data")) & - call fatal_error("Must provide 'scatter data'") - scatt_grp = open_group(xsdata_grp, 'scatter data') + if (.not. object_exists(xsdata_grp, "scatter_data")) & + call fatal_error("Must provide 'scatter_data'") + scatt_grp = open_group(xsdata_grp, 'scatter_data') ! First get the outgoing group boundary indices - if (check_dataset(scatt_grp, "g_min")) then + if (object_exists(scatt_grp, "g_min")) then allocate(int_arr(groups * this % n_azi * this % n_pol)) call read_dataset(int_arr, scatt_grp, "g_min") allocate(gmin(groups, this % n_azi, this % n_pol)) gmin = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) deallocate(int_arr) else - call fatal_error("'g_min' for the scatter matrix must be provided") + call fatal_error("'g_min' for the scatter_data must be provided") end if - if (check_dataset(scatt_grp, "g_max")) then + if (object_exists(scatt_grp, "g_max")) then allocate(int_arr(groups * this % n_azi * this % n_pol)) call read_dataset(int_arr, scatt_grp, "g_max") allocate(gmax(groups, this % n_azi, this % n_pol)) gmax = reshape(int_arr, (/groups, this % n_azi, this % n_pol/)) deallocate(int_arr) else - call fatal_error("'g_max' for the scatter matrix must be provided") + call fatal_error("'g_max' for the scatter_data must be provided") end if ! Now use this information to find the length of a container array @@ -891,9 +891,9 @@ module mgxs_header end do ! Allocate flattened array allocate(temp_arr(length)) - if (.not. check_dataset(scatt_grp, 'scatter matrix')) & - call fatal_error("'scatter matrix' must be provided") - call read_dataset(temp_arr, scatt_grp, "scatter matrix") + if (.not. object_exists(scatt_grp, 'scatter_matrix')) & + call fatal_error("'scatter_matrix' must be provided") + call read_dataset(temp_arr, scatt_grp, "scatter_matrix") ! Compare the number of orders given with the maximum order of the ! problem. Strip off the superfluous orders if needed. @@ -988,7 +988,7 @@ module mgxs_header deallocate(input_scatt) ! Now get the multiplication matrix - if (check_dataset(scatt_grp, 'multiplicity matrix')) then + if (object_exists(scatt_grp, 'multiplicity_matrix')) then ! Now use this information to find the length of a container array ! to hold the flattened data length = 0 @@ -1001,7 +1001,7 @@ module mgxs_header end do ! Allocate flattened array allocate(temp_arr(length)) - call read_dataset(temp_arr, scatt_grp, "multiplicity matrix") + call read_dataset(temp_arr, scatt_grp, "multiplicity_matrix") ! Convert temp_arr to a jagged array ((gin) % data(gout)) for passing ! to ScattData allocate(temp_mult(groups, this % n_azi, this % n_pol)) @@ -1067,7 +1067,7 @@ module mgxs_header end do allocate(xs % total(groups, this % n_azi, this % n_pol)) - if (check_dataset(xsdata_grp, "total")) then + if (object_exists(xsdata_grp, "total")) then allocate(temp_arr(groups * this % n_azi * this % n_pol)) call read_dataset(temp_arr, xsdata_grp, "total") xs % total = reshape(temp_arr, (/groups, this % n_azi, & @@ -1095,10 +1095,10 @@ module mgxs_header end do ! Get kinetics data - if (check_dataset(xsdata_grp, "inverse-velocities")) then + if (object_exists(xsdata_grp, "inverse_velocities")) then allocate(xs % inv_vel(groups, this % n_azi, this % n_pol)) allocate(temp_arr(groups * this % n_azi * this % n_pol)) - call read_dataset(temp_arr, xsdata_grp, "inverse-velocities") + call read_dataset(temp_arr, xsdata_grp, "inverse_velocities") xs % inv_vel = reshape(temp_arr, (/groups, this % n_azi, & this % n_pol/)) deallocate(temp_arr) @@ -1372,7 +1372,7 @@ module mgxs_header ! dense matrix for this storage, with a reduction to the sparse ! format at the end. - ! Get the multiplicity matrix + ! Get the multiplicity_matrix ! To combine from nuclidic data we need to use the final relationship ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) @@ -1639,7 +1639,7 @@ module mgxs_header ! dense matrix for this storage, with a reduction to the sparse ! format at the end. - ! Get the multiplicity matrix + ! Get the multiplicity_matrix ! To combine from nuclidic data we need to use the final relationship ! mult_{gg'} = sum_i(N_i*nuscatt_{i,g,g'}) / ! sum_i(N_i*(nuscatt_{i,g,g'} / mult_{i,g,g'})) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 16d0a6b98a..ed66004056 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -13,7 +13,7 @@ module nuclide_header use error, only: fatal_error, warning use hdf5_interface, only: read_attribute, open_group, close_group, & open_dataset, read_dataset, close_dataset, get_shape, get_datasets, & - check_group, get_name, get_groups + object_exists, get_name, get_groups use list_header, only: ListInt use math, only: evaluate_legendre use multipole_header, only: MultipoleArray @@ -350,7 +350,7 @@ module nuclide_header call close_group(rxs_group) ! Read unresolved resonance probability tables if present - if (check_group(group_id, 'urr')) then + if (object_exists(group_id, 'urr')) then this % urr_present = .true. allocate(this % urr_data(n_temperature)) @@ -391,7 +391,7 @@ module nuclide_header end if ! Check for nu-total - if (check_group(group_id, 'total_nu')) then + if (object_exists(group_id, 'total_nu')) then nu_group = open_group(group_id, 'total_nu') ! Read total nu data @@ -410,7 +410,7 @@ module nuclide_header end if ! Read fission energy release data if present - if (check_group(group_id, 'fission_energy_release')) then + if (object_exists(group_id, 'fission_energy_release')) then fer_group = open_group(group_id, 'fission_energy_release') ! Check to see if this is polynomial or tabulated data diff --git a/src/sab_header.F90 b/src/sab_header.F90 index df2089ddee..fbb981b885 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -9,7 +9,7 @@ module sab_header use error, only: warning, fatal_error use hdf5, only: HID_T, HSIZE_T, SIZE_T use hdf5_interface, only: read_attribute, get_shape, open_group, close_group, & - open_dataset, read_dataset, close_dataset, get_datasets, check_group, & + open_dataset, read_dataset, close_dataset, get_datasets, object_exists, & get_name use secondary_correlated, only: CorrelatedAngleEnergy use stl_vector, only: VectorInt, VectorReal @@ -209,7 +209,7 @@ contains T_group = open_group(group_id, temp_str) ! Coherent elastic data - if (check_group(T_group, 'elastic')) then + if (object_exists(T_group, 'elastic')) then ! Read cross section data elastic_group = open_group(T_group, 'elastic') dset_id = open_dataset(elastic_group, 'xs') @@ -251,7 +251,7 @@ contains end if ! Inelastic data - if (check_group(T_group, 'inelastic')) then + if (object_exists(T_group, 'inelastic')) then ! Read type of inelastic data inelastic_group = open_group(T_group, 'inelastic') diff --git a/src/secondary_uncorrelated.F90 b/src/secondary_uncorrelated.F90 index 756ff83df7..40aa827da6 100644 --- a/src/secondary_uncorrelated.F90 +++ b/src/secondary_uncorrelated.F90 @@ -8,7 +8,8 @@ module secondary_uncorrelated use energy_distribution, only: EnergyDistribution, LevelInelastic, & ContinuousTabular, MaxwellEnergy, Evaporation, WattEnergy, DiscretePhoton use error, only: warning - use hdf5_interface, only: read_attribute, open_group, close_group, check_group + use hdf5_interface, only: read_attribute, open_group, close_group, & + object_exists use random_lcg, only: prn !=============================================================================== @@ -60,14 +61,14 @@ contains character(MAX_WORD_LEN) :: type ! Check if angle group is present & read - if (check_group(group_id, 'angle')) then + if (object_exists(group_id, 'angle')) then angle_group = open_group(group_id, 'angle') call this%angle%from_hdf5(angle_group) call close_group(angle_group) end if ! Check if energy group is present & read - if (check_group(group_id, 'energy')) then + if (object_exists(group_id, 'energy')) then energy_group = open_group(group_id, 'energy') call read_attribute(type, energy_group, 'type') select case (type) From a00a880b88c03bbd79db3b17965590c649151988 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 15:20:03 -0400 Subject: [PATCH 53/82] Forgot to include file --- scripts/openmc-update-mgxs | 233 +++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100755 scripts/openmc-update-mgxs diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs new file mode 100755 index 0000000000..5d9591627a --- /dev/null +++ b/scripts/openmc-update-mgxs @@ -0,0 +1,233 @@ +#!/usr/bin/env python +"""Update OpenMC's deprecated multi-group cross section XML files to the latest +HDF5-based format. + +Usage information can be obtained by running 'openmc-update-mgxs --help': + +usage: openmc-update-mgxs [-h] in out + +Update mgxs.xml files to the latest format. This will remove 'outside' +attributes/elements from lattices and replace them with 'outer' attributes. For +'cell' elements, any 'surfaces' attributes/elements will be renamed +'region'. Note that this script will not delete the given files; it will append +'.original' to the given files and write new ones. + +positional arguments: + in Input mgxs xml file + out Output mgxs hdf5 file + +optional arguments: + -h, --help show this help message and exit + +""" + +from __future__ import print_function +import os +from shutil import move +import warnings +import xml.etree.ElementTree as ET + +import argparse +import h5py +import numpy as np + +import openmc.mgxs_library + +description = """\ +Update OpenMC's deprecated multi-group cross section XML files to the latest +HDF5-based format.""" + + +def parse_args(): + """Read the input files from the commandline.""" + # Create argument parser + parser = argparse.ArgumentParser(description=description, + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-i', '--input', type=argparse.FileType('r'), + help='input XML file') + parser.add_argument('-o', '--output', nargs='?', default='', + help='output file, in HDF5 format') + parser.add_argument('-c', '--compression', type=int, + help='HDF5 Compression Level') + args = vars(parser.parse_args()) + + if args['output'] == '': + filename = args['input'].name + extension = filenameos.path.splitext() + if extension == '.xml': + filename = filename[:filename.rfind('.')] + '.h5' + args['output'] = filename + + # Parse and return commandline arguments. + return args + + +def get_data(element, entry): + try: + value = element.find(entry).text + except: + if entry in element.attrib: + value = element.attrib[entry] + else: + value = None + + if value is not None: + value = value.strip() + + return value + + +if __name__ == '__main__': + args = parse_args() + + # Parse the XML data. + tree = ET.parse(args['input']) + root = tree.getroot() + + # Get old metadata + temp = tree.find('group_structure').text.strip() + temp = np.array(temp.split()) + group_structure = temp.astype(np.float) + energy_groups = openmc.mgxs.EnergyGroups(group_structure) + temp = tree.find('inverse_velocities') + if temp is not None: + temp = temp.text.strip() + temp = np.array(temp.split()) + inverse_velocities = temp.astype(np.float) + else: + inverse_velocities = None + + xsd = [] + names = [] + + # Now move on to the cross section data itself + for xsdata_elem in root.iter('xsdata'): + name = get_data(xsdata_elem, 'name') + + temperature = get_data(xsdata_elem, 'kT') + if temperature is not None: + temperature = \ + float(temperature) / openmc.data.K_BOLTZMANN + else: + temperature = 294. + temperatures = [temperature] + + awr = get_data(xsdata_elem, 'awr') + if awr is not None: + awr = float(awr) + + representation = get_data(xsdata_elem, 'representation') + if representation is None: + representation = 'isotropic' + if representation == 'angle': + n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) + n_pol = int(get_data(xsdata_elem, 'num_polar')) + + scatter_format = get_data(xsdata_elem, 'scatt_type') + if scatter_format is None: + scatter_format = 'legendre' + + order = int(get_data(xsdata_elem, 'order')) + + tab_leg = get_data(xsdata_elem, 'tabular_legendre') + if tab_leg is not None: + warnings.Warning('The tabular_legendre option has moved to the ' + 'settings.xml file and must be added manually') + + # Either add the data to a previously existing xsdata (if it is + # for the same 'name' but a different temperature), or create a + # new one. + try: + # It is in our list, so store that entry + i = names.index(name) + except: + # It is not in our list, so add it + i = -1 + xsd.append(openmc.XSdata(name, energy_groups, + temperatures=temperatures, + representation=representation)) + if awr is not None: + xsd[-1].atomic_weight_ratio = awr + if representation == 'angle': + xsd[-1].num_azimuthal = n_azi + xsd[-1].num_polar = n_pol + xsd[-1].scatter_format = scatter_format + xsd[-1].order = order + names.append(name) + + if scatter_format == 'legendre': + order_dim = order + 1 + else: + order_dim = order + + if i != -1: + xsd[i].add_temperature(temperature) + + temp = get_data(xsdata_elem, 'total') + if temp is not None: + temp = np.array(temp.split(), dtype=float) + total = temp.astype(np.float) + total.shape = xsd[i].vector_shape + xsd[i].set_total(total, temperature) + + if inverse_velocities is not None: + xsd[i].set_inverse_velocities(inverse_velocities, temperature) + + temp = get_data(xsdata_elem, 'absorption') + temp = np.array(temp.split()) + absorption = temp.astype(np.float) + absorption.shape = xsd[i].vector_shape + xsd[i].set_absorption(absorption, temperature) + + temp = get_data(xsdata_elem, 'scatter') + temp = np.array(temp.split()) + scatter = temp.astype(np.float) + scatter.shape = xsd[i].pn_matrix_shape + xsd[i].set_scatter_matrix(scatter, temperature) + + temp = get_data(xsdata_elem, 'multiplicity') + if temp is not None: + temp = np.array(temp.split()) + multiplicity = temp.astype(np.float) + multiplicity.shape = xsd[i].matrix_shape + xsd[i].set_multiplicity_matrix(multiplicity, temperature) + + temp = get_data(xsdata_elem, 'fission') + if temp is not None: + temp = np.array(temp.split()) + fission = temp.astype(np.float) + fission.shape = xsd[i].vector_shape + xsd[i].set_fission(fission, temperature) + + temp = get_data(xsdata_elem, 'kappa_fission') + if temp is not None: + temp = np.array(temp.split()) + kappa_fission = temp.astype(np.float) + kappa_fission.shape = xsd[i].vector_shape + xsd[i].set_kappa_fission(kappa_fission, temperature) + + temp = get_data(xsdata_elem, 'chi') + if temp is not None: + temp = np.array(temp.split()) + chi = temp.astype(np.float) + chi.shape = xsd[i].vector_shape + xsd[i].set_chi(chi, temperature) + else: + chi = None + + temp = get_data(xsdata_elem, 'nu_fission') + if temp is not None: + temp = np.array(temp.split()) + nu_fission = temp.astype(np.float) + if chi is not None: + nu_fission.shape = xsd[i].vector_shape + else: + nu_fission.shape = xsd[i].matrix_shape + xsd[i].set_nu_fission(nu_fission, temperature) + + # Build library as we go, but first we have enough to initialize it + lib = openmc.MGXSLibrary(energy_groups) + + lib.add_xsdatas(xsd) + + lib.export_to_hdf5(args['output']) From c446f10e5add8af9020ae42c0010fedaab3946e6 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 15:33:14 -0400 Subject: [PATCH 54/82] Last @paulromano comment I held off on. Didnt update all mgxs h5 libraries yet as future comments from others will require I do that anyways. --- openmc/mesh.py | 4 ++-- openmc/mgxs_library.py | 2 +- scripts/openmc-update-mgxs | 14 ++++++-------- tests/1d_mgxs.h5 | Bin 123864 -> 123864 bytes 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index 2d5fda09bc..014cbc4679 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -302,8 +302,8 @@ class Mesh(object): # inconsistency between what numpy uses as the max float and what # Fortran expects for a real(8), so this avoids code complication # and achieves the same goal. - zplanes = [openmc.ZPlane(z0=-1e10., boundary_type='reflective'), - openmc.ZPlane(z0=1e10., boundary_type='reflective')] + zplanes = [openmc.ZPlane(z0=-1e10, boundary_type='reflective'), + openmc.ZPlane(z0=1e10, boundary_type='reflective')] else: zplanes = [openmc.ZPlane(z0=self.lower_left[2], boundary_type=bc[4]), diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 2bc320b7b7..8e6089a1a5 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -306,7 +306,7 @@ class XSdata(object): def temperatures(self, temperatures): check_iterable_type('temperatures', temperatures, Real) - self._temperatures = temperatures + self._temperatures = np.array(temperatures) @scatter_format.setter def scatter_format(self, scatter_format): diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs index 5d9591627a..f16ad9d1bb 100755 --- a/scripts/openmc-update-mgxs +++ b/scripts/openmc-update-mgxs @@ -63,17 +63,15 @@ def parse_args(): def get_data(element, entry): - try: - value = element.find(entry).text - except: + value = element.find(entry) + if value is not None: + value = value.text.strip() + else: if entry in element.attrib: - value = element.attrib[entry] + value = element.attrib[entry].strip() else: value = None - if value is not None: - value = value.strip() - return value @@ -140,7 +138,7 @@ if __name__ == '__main__': try: # It is in our list, so store that entry i = names.index(name) - except: + except ValueError: # It is not in our list, so add it i = -1 xsd.append(openmc.XSdata(name, energy_groups, diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 index 65dcf36cf7ee6c22d854c4fbcf2160e63209280f..401fe02fc54bedac6d1b5443db23a923de30c5f0 100644 GIT binary patch delta 1643 zcmZvcUr19?9LG8SUuE_XYChyYR1(E8O0ATcLKp=T#E>GcwwHvwCZy~-2hq z7$^tQ&TVW6Zbs1_*YYHp*T<~qaFOx8ZQ8JUP|<+55{ z^`P!-&;uvxIZtJ)OiVVRDkSTw-lOWN38{K6a@B{mg6geHqG}R4ce$CUD)wwJh^nL} z+AVUMv!W@zH-&iBpn268&rCBl@q=`YALQo1zjpV)u2zbJwp+FIa=yY`D{qVIOqbk_dP0B>I!vJfB=^f0{oIHa3A!Yg`5g>JXT+;kkK$Aum@pV4b5VS@LV zIvJ&wELk&>XZuB$byfhItni@bI#6{S=DlZ6V0s&J5cOXhp~TS zonG^9h@eDx=9?g_u7Pcn4Wu`v8(I8IOwIT!i!GhJ`~z0+vR>rnM)-U(5e0Uq{^!)_ zpO91769H5V#U2AF2$o|(I0-J>2f|U5xOfm`!GUq^Z=l3l>&(1W`u9P@EivCyG~{z#JSZ&BnPWqK%d*7N~xj(4g&$-)s)UZ{u&8zmH)=tbdfg3f!+dABp`=Hy;fdlEaw>8nbw*t^>aiOXM1N)U1@2km zc{0pVARX3c9U{+;)*Ixxll6<<+P1lnBl|s|b&a_(^Z-rvO=vjE?wi{tJ$c4xP=Lw{ z7F8HGdS#f8CUv@sX4utYjzr{;{-mI{HC6+IrOhF=U>R5Q8U;1aX{Khf_rZ#5nJ>Z=W_`Yv$QhjoJL&5NRH3OakKg{aET959Hg z&CRr1{$q_ZjC*Ho<8;~C1UG+^;Zvs z_A{Mg`^o5sQ!$;jzcawwHxF4gH0WV?<#AXyb%a;+j|$yxjd|%fOpOaYZakycP|^hN zF>O*qdW5B`M)GW5t>i(czZ8P5LgUQ-ZOlt;;|8c-?}difyf6CR2Ph|SA`uY2`IzZ zzrIGV`PW5IB0T+F5LVW}vB3t?uj@wE%|)hW{GH8~PFng2Yj#;L(oz$AKADVyyD$Fd z)aakEQ`i>;6b#uJ3n&Pd;y@$`E>8fFC~|xv2(jQ`B49B1O9}|lY|38`17|*WxkChU0raR1}FHw5d2yBvRAl z(Ua52W9uAnnT$IX9rY#>Iw16osfhRk*MrRCmm$EQ?6?lEUfAXp^QYJxH$?>6tB2}B{Wp3jk8Zg8?7%`p!z9J ylQb>RV4nxHC6J9|f9DFx#2ZdRRvk~g1#C01G#e&qbS?O>?;RLVr@J97HU0%r Date: Mon, 10 Oct 2016 16:10:39 -0400 Subject: [PATCH 55/82] Resolved @wbinventor comments --- docs/source/io_formats/mgxs_library.rst | 8 +- openmc/mgxs/library.py | 88 ++++++++-------- openmc/mgxs_library.py | 127 ++++++++++++------------ scripts/openmc-update-mgxs | 12 +-- src/input_xml.F90 | 2 +- 5 files changed, 118 insertions(+), 119 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index e9b59a20f2..9262a234e7 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -6,7 +6,7 @@ Multi-Group Cross Section Library Format OpenMC can be run in continuous-energy mode or multi-group mode, provided the nuclear data is available. In continuous-energy mode, the -``cross_sections.xml`` file contains necessary meta-data for each data set, +``cross_sections.xml`` file contains necessary meta-data for each dataset, including the name and a file system location where the complete library can be found. In multi-group mode, the multi-group meta-data and the nuclear data itself is contained within an ``mgxs.h5``. This portion of @@ -89,19 +89,19 @@ Temperature-dependent data, provided for temperature K. cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the data set + [groups, azimuthal, polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **kappa-fission** (*double[]* or *double[][][]*) -- Kappa-Fission (energy-release from fission) cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the data set + [groups, azimuthal, polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **chi** (*double[]* or *double[][][]*) -- Fission neutron energy spectra. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the data set + [groups, azimuthal, polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **nu-fission** (*double[]* to *double[][][][]*) -- Nu-Fission cross section. diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index c4515c9693..5535f84856 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -186,14 +186,14 @@ class Library(object): @property def domains(self): - if self._domains == 'all': - if self.domain_type == 'material': + if self._domains is 'all': + if self.domain_type is 'material': return self.openmc_geometry.get_all_materials() elif self.domain_type in ['cell', 'distribcell']: return self.openmc_geometry.get_all_material_cells() - elif self.domain_type == 'universe': + elif self.domain_type is 'universe': return self.openmc_geometry.get_all_universes() - elif self.domain_type == 'mesh': + elif self.domain_type is 'mesh': raise ValueError('Unable to get domains for Mesh domain type') else: raise ValueError('Unable to get domains without a domain type') @@ -265,7 +265,7 @@ class Library(object): @mgxs_types.setter def mgxs_types(self, mgxs_types): all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES - if mgxs_types == 'all': + if mgxs_types is 'all': self._mgxs_types = all_mgxs_types else: cv.check_iterable_type('mgxs_types', mgxs_types, basestring) @@ -277,7 +277,7 @@ class Library(object): def by_nuclide(self, by_nuclide): cv.check_type('by_nuclide', by_nuclide, bool) - if by_nuclide == True and self.domain_type == 'mesh': + if by_nuclide == True and self.domain_type is 'mesh': raise ValueError('Unable to create MGXS library by nuclide with ' 'mesh domain') @@ -287,7 +287,7 @@ class Library(object): def domain_type(self, domain_type): cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) - if self.by_nuclide == True and domain_type == 'mesh': + if self.by_nuclide == True and domain_type is 'mesh': raise ValueError('Unable to create MGXS library by nuclide with ' 'mesh domain') @@ -297,21 +297,21 @@ class Library(object): def domains(self, domains): # Use all materials, cells or universes in the geometry as domains - if domains == 'all': + if domains is 'all': self._domains = domains # User specified a list of material, cell or universe domains else: - if self.domain_type == 'material': + if self.domain_type is 'material': cv.check_iterable_type('domain', domains, openmc.Material) all_domains = self.openmc_geometry.get_all_materials() elif self.domain_type in ['cell', 'distribcell']: cv.check_iterable_type('domain', domains, openmc.Cell) all_domains = self.openmc_geometry.get_all_material_cells() - elif self.domain_type == 'universe': + elif self.domain_type is 'universe': cv.check_iterable_type('domain', domains, openmc.Universe) all_domains = self.openmc_geometry.get_all_universes() - elif self.domain_type == 'mesh': + elif self.domain_type is 'mesh': cv.check_iterable_type('domain', domains, openmc.Mesh) # The mesh and geometry are independent, so set all_domains @@ -355,7 +355,7 @@ class Library(object): def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) - if correction == 'P0' and self.legendre_order > 0: + if correction is 'P0' and self.legendre_order > 0: warn('The P0 correction will be ignored since the scattering ' 'order "{}" is greater than zero'.format(self.legendre_order)) @@ -367,7 +367,7 @@ class Library(object): cv.check_greater_than('legendre_order', legendre_order, 0, equality=True) cv.check_less_than('legendre_order', legendre_order, 10, equality=True) - if self.correction == 'P0' and legendre_order > 0: + if self.correction is 'P0' and legendre_order > 0: msg = 'The P0 correction will be ignored since the scattering ' \ 'order {} is greater than zero'.format(self.legendre_order) warn(msg, RuntimeWarning) @@ -505,7 +505,7 @@ class Library(object): self._openmc_geometry = statepoint.summary.openmc_geometry self._nuclides = statepoint.summary.nuclides - if statepoint.run_mode == 'k-eigenvalue': + if statepoint.run_mode is 'k-eigenvalue': self._keff = statepoint.k_combined[0] # Load tallies for each MGXS for each domain and mgxs type @@ -543,13 +543,13 @@ class Library(object): """ - if self.domain_type == 'material': + if self.domain_type is 'material': cv.check_type('domain', domain, (openmc.Material, Integral)) - elif self.domain_type == 'cell' or self.domain_type == 'distribcell': + elif self.domain_type is 'cell' or self.domain_type is 'distribcell': cv.check_type('domain', domain, (openmc.Cell, Integral)) - elif self.domain_type == 'universe': + elif self.domain_type is 'universe': cv.check_type('domain', domain, (openmc.Universe, Integral)) - elif self.domain_type == 'mesh': + elif self.domain_type is 'mesh': cv.check_type('domain', domain, (openmc.Mesh, Integral)) # Check that requested domain is included in library @@ -662,7 +662,7 @@ class Library(object): # Clone this Library to initialize the subdomain-averaged version subdomain_avg_library = copy.deepcopy(self) - if subdomain_avg_library.domain_type == 'distribcell': + if subdomain_avg_library.domain_type is 'distribcell': subdomain_avg_library.domain_type = 'cell' else: return subdomain_avg_library @@ -671,7 +671,7 @@ class Library(object): for domain in self.domains: for mgxs_type in self.mgxs_types: mgxs = subdomain_avg_library.get_mgxs(domain, mgxs_type) - if mgxs.domain_type == 'distribcell': + if mgxs.domain_type is 'distribcell': avg_mgxs = mgxs.get_subdomain_avg_xs() subdomain_avg_library.all_mgxs[domain.id][mgxs_type] = avg_mgxs @@ -751,7 +751,7 @@ class Library(object): for mgxs_type in self.mgxs_types: mgxs = self.all_mgxs[domain.id][mgxs_type] - if subdomains == 'avg': + if subdomains is 'avg': mgxs = mgxs.get_subdomain_avg_xs() mgxs.build_hdf5_store(filename, directory, xs_type=xs_type, @@ -824,8 +824,9 @@ class Library(object): def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro', order=None, subdomain=None): """Generates an openmc.XSdata object describing a multi-group cross section - data set for eventual combination in to an openmc.MGXSLibrary object - (i.e., the library). Note that this method does not build an XSdata + dataset for writing to an openmc.MGXSLibrary object. + + Note that this method does not build an XSdata object with nested temperature tables. The temperature of each XSdata object will be left at the default value of 300K. @@ -856,7 +857,7 @@ class Library(object): Returns ------- xsdata : openmc.XSdata - Multi-Group Cross Section data set object. + Multi-Group Cross Section dataset object. Raises ------ @@ -920,7 +921,7 @@ class Library(object): subdomain = [subdomain] # Now get xs data itself - if 'nu-transport' in self.mgxs_types and self.correction == 'P0': + if 'nu-transport' in self.mgxs_types and self.correction is 'P0': mymgxs = self.get_mgxs(domain, 'nu-transport') xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomains=subdomain) @@ -995,7 +996,7 @@ class Library(object): # scattering multiplication (nu-scatter) must be # accounted for approximately by using an adjusted # absorption cross section. - if 'total' in self.mgxs_types: + if 'total' in self.mgxs_types or 'transport' in self.mgxs_types: for i in range(len(xsdata.temperatures)): xsdata._absorption[i] = \ np.subtract(xsdata._total[i], np.sum( @@ -1005,9 +1006,11 @@ class Library(object): def create_mg_library(self, xs_type='macro', xsdata_names=None): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the - Multi-Group mode of OpenMC. Note that this library will not make use - of nested temperature tables. Every dataset in the library will be - treated as if it was at the same default temperature. + Multi-Group mode of OpenMC. + + Note that this library will not make use of nested temperature tables. + Every dataset in the library will be treated as if it was at the same + default temperature. Parameters ---------- @@ -1053,7 +1056,7 @@ class Library(object): # Initialize file mgxs_file = openmc.MGXSLibrary(self.energy_groups) - if self.domain_type == 'mesh': + if self.domain_type is 'mesh': # Create the xsdata objects and add to the mgxs_file i = 0 for domain in self.domains: @@ -1099,14 +1102,15 @@ class Library(object): def create_mg_mode(self, xsdata_names=None, bc=['reflective'] * 6): """Creates an openmc.MGXSLibrary object to contain the MGXS data for the Multi-Group mode of OpenMC as well as the associated openmc.Materials - and openmc.Geometry objects. The created Geometry is the same as that - used to generate the MGXS data, with the only differences being - modifications to point to newly-created Materials which point to the - multi-group data. This method only creates a macroscopic - MGXS Library even if nuclidic tallies are specified in the Library. - Note that this library will not make use of nested temperature tables. - Every dataset in the library will be treated as if it was at the same - default temperature. + and openmc.Geometry objects. + + The created Geometry is the same as that used to generate the MGXS + data, with the only differences being modifications to point to + newly-created Materials which point to the multi-group data. This + method only creates a macroscopic MGXS Library even if nuclidic tallies + are specified in the Library. Note that this library will not make + use of nested temperature tables. Every dataset in the library will + be treated as if it was at the same default temperature. Parameters ---------- @@ -1155,14 +1159,14 @@ class Library(object): # the multiple meshes could be overlapping or in disparate regions # of the continuous energy model. The next step makes sure there is # only one before continuing. - if self.domain_type == 'mesh': + if self.domain_type is 'mesh': cv.check_length("domains", self.domains, 1, 1) # Get the MGXS File Data mgxs_file = self.create_mg_library('macro', xsdata_names) # Now move on the creating the geometry and assigning materials - if self.domain_type == 'mesh': + if self.domain_type is 'mesh': root = openmc.Universe(name='root', universe_id=0) # Add cells representative of the mesh with reflective BC @@ -1208,13 +1212,13 @@ class Library(object): materials.append(material) # Differentiate Geometry with new Material - if self.domain_type == 'material': + if self.domain_type is 'material': # Fill all appropriate Cells with new Material for cell in all_cells: if cell.fill.id == domain.id: cell.fill = material - elif self.domain_type == 'cell': + elif self.domain_type is 'cell': for cell in all_cells: if cell.id == domain.id: cell.fill = material diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 8e6089a1a5..67a9b01f44 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -242,28 +242,28 @@ class XSdata(object): @property def vector_shape(self): - if self.representation == 'isotropic': + if self.representation is 'isotropic': return (self.energy_groups.num_groups,) - elif self.representation == 'angle': + elif self.representation is 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups) @property def matrix_shape(self): - if self.representation == 'isotropic': + if self.representation is 'isotropic': return (self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation == 'angle': + elif self.representation is 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups, self.energy_groups.num_groups) @property def pn_matrix_shape(self): - if self.representation == 'isotropic': + if self.representation is 'isotropic': return (self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation == 'angle': + elif self.representation is 'angle': return (self.num_polar, self.num_azimuthal, self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) @@ -297,11 +297,6 @@ class XSdata(object): check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio - @fissionable.setter - def fissionable(self, fissionable): - check_type('fissionable', fissionable, bool) - self._fissionable = fissionable - @temperatures.setter def temperatures(self, temperatures): check_iterable_type('temperatures', temperatures, Real) @@ -374,8 +369,8 @@ class XSdata(object): total: np.ndarray Total Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -389,7 +384,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._total[i] = nptotal def set_absorption(self, absorption, temperature=294.): @@ -401,8 +396,8 @@ class XSdata(object): absorption: np.ndarray Absorption Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -417,7 +412,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._absorption[i] = npabsorption def set_fission(self, fission, temperature=294.): @@ -429,8 +424,8 @@ class XSdata(object): fission: np.ndarray Fission Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -444,7 +439,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._fission[i] = npfission if np.sum(npfission) > 0.0: @@ -459,8 +454,8 @@ class XSdata(object): kappa_fission: np.ndarray Kappa-Fission Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -476,7 +471,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._kappa_fission[i] = npkappa_fission if np.sum(npkappa_fission) > 0.0: @@ -491,8 +486,8 @@ class XSdata(object): chi: np.ndarray Fission Spectrum temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -515,7 +510,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._chi[i] = npchi if self.use_chi is not None: @@ -530,8 +525,8 @@ class XSdata(object): scatter: np.ndarray Scattering Matrix Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -546,7 +541,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._scatter_matrix[i] = npscatter def set_multiplicity_matrix(self, multiplicity, temperature=294.): @@ -558,8 +553,8 @@ class XSdata(object): multiplicity: np.ndarray Multiplicity Matrix Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -575,7 +570,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._multiplicity_matrix[i] = npmultiplicity def set_nu_fission(self, nu_fission, temperature=294.): @@ -587,8 +582,8 @@ class XSdata(object): nu_fission: np.ndarray Nu-fission Cross Section temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). See also -------- @@ -630,7 +625,7 @@ class XSdata(object): else: self.use_chi = False - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._nu_fission[i] = npnu_fission if np.sum(npnu_fission) > 0.0: self._fissionable = True @@ -644,8 +639,8 @@ class XSdata(object): inv_vel: np.ndarray Inverse velocities in units of sec/cm. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). """ check_type('inverse velocities', inv_vel, Iterable, @@ -657,7 +652,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) self._inverse_velocities[i] = npinv_vel def set_total_mgxs(self, total, temperature=294., nuclide='total', @@ -672,8 +667,8 @@ class XSdata(object): MGXS Object containing the total or transport cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -699,7 +694,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._total[i] = total.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) @@ -718,8 +713,8 @@ class XSdata(object): MGXS Object containing the absorption cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -745,7 +740,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._absorption[i] = absorption.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -765,8 +760,8 @@ class XSdata(object): MGXS Object containing the fission cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -792,7 +787,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._fission[i] = fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -812,8 +807,8 @@ class XSdata(object): MGXS Object containing the nu-fission cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -840,7 +835,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._nu_fission[i] = nu_fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -870,8 +865,8 @@ class XSdata(object): MGXS Object containing the kappa-fission cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -897,7 +892,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._kappa_fission[i] = k_fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -916,8 +911,8 @@ class XSdata(object): chi: openmc.mgxs.Chi MGXS Object containing chi for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -948,7 +943,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': self._chi[i] = chi.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) @@ -973,8 +968,8 @@ class XSdata(object): MGXS Object containing the scatter matrix cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -1000,7 +995,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - if (self.scatter_format != 'legendre'): + if self.scatter_format is not 'legendre': msg = 'Anisotropic scattering representations other than ' \ 'Legendre expansions have not yet been implemented in ' \ 'openmc.mgxs.' @@ -1016,7 +1011,7 @@ class XSdata(object): check_value('legendre_order', scatter.legendre_order, [self.order]) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': # Get the scattering orders in the outermost dimension self._scatter_matrix[i] = np.zeros((self.num_orders, @@ -1054,8 +1049,8 @@ class XSdata(object): MGXS Object containing the scattering matrix cross section for the domain of interest. temperature : float - Temperature (in units of Kelvin) of the provided dataset. Defaults - to 294K + Temperature (in Kelvin) of the data. Defaults to room temperature + (294K). nuclide : str Individual nuclide (or 'total' if obtaining material-wise data) to gather data for. Defaults to 'total'. @@ -1094,7 +1089,7 @@ class XSdata(object): check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) - i = self.temperatures.tolist().index(temperature) + i = np.where(self.temperatures == temperature) if self.representation is 'isotropic': nuscatt = nuscatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, @@ -1129,7 +1124,7 @@ class XSdata(object): if self.representation is not None: grp.attrs['representation'] = np.array(self.representation, dtype='S') - if self.representation == 'angle': + if self.representation is 'angle': if self.num_azimuthal is not None: grp.attrs['num_azimuthal'] = self.num_azimuthal if self.num_polar is not None: @@ -1176,7 +1171,7 @@ class XSdata(object): # Get the sparse scattering data to print to the library G = self.energy_groups.num_groups - if self.representation == 'isotropic': + if self.representation is 'isotropic': g_out_bounds = np.zeros((G, 2), dtype=np.int) for g_in in range(G): nz = np.nonzero(self._scatter_matrix[i][0, g_in, :]) @@ -1212,7 +1207,7 @@ class XSdata(object): scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0]) scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1]) - elif self.representation == 'angle': + elif self.representation is 'angle': Np = self.num_polar Na = self.num_azimuthal g_out_bounds = np.zeros((Np, Na, G, 2), dtype=np.int) diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs index f16ad9d1bb..6122ff6262 100755 --- a/scripts/openmc-update-mgxs +++ b/scripts/openmc-update-mgxs @@ -51,10 +51,10 @@ def parse_args(): help='HDF5 Compression Level') args = vars(parser.parse_args()) - if args['output'] == '': + if args['output'] is '': filename = args['input'].name extension = filenameos.path.splitext() - if extension == '.xml': + if extension is '.xml': filename = filename[:filename.rfind('.')] + '.h5' args['output'] = filename @@ -75,7 +75,7 @@ def get_data(element, entry): return value -if __name__ == '__main__': +if __name__ is '__main__': args = parse_args() # Parse the XML data. @@ -117,7 +117,7 @@ if __name__ == '__main__': representation = get_data(xsdata_elem, 'representation') if representation is None: representation = 'isotropic' - if representation == 'angle': + if representation is 'angle': n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) n_pol = int(get_data(xsdata_elem, 'num_polar')) @@ -146,14 +146,14 @@ if __name__ == '__main__': representation=representation)) if awr is not None: xsd[-1].atomic_weight_ratio = awr - if representation == 'angle': + if representation is 'angle': xsd[-1].num_azimuthal = n_azi xsd[-1].num_polar = n_pol xsd[-1].scatter_format = scatter_format xsd[-1].order = order names.append(name) - if scatter_format == 'legendre': + if scatter_format is 'legendre': order_dim = order + 1 else: order_dim = order diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 8d56285671..fd8a33c683 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4673,7 +4673,7 @@ contains libraries(i) % materials(1) = names(i) end do - ! Close MGXS HDF file + ! Close MGXS HDF5 file call file_close(file_id) end subroutine read_mg_cross_sections_header From 23049dc03cd86a03e1b82a5cbcd6eff83c619099 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Mon, 10 Oct 2016 16:23:38 -0400 Subject: [PATCH 56/82] Replaced nptotal with total (et al) per the request by @wbinventor --- openmc/mgxs_library.py | 79 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 67a9b01f44..c2246fa926 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -379,13 +379,13 @@ class XSdata(object): """ check_type('total', total, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - nptotal = np.asarray(total) - check_value('total shape', nptotal.shape, [self.vector_shape]) + total = np.asarray(total) + check_value('total shape', total.shape, [self.vector_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._total[i] = nptotal + self._total[i] = total def set_absorption(self, absorption, temperature=294.): """This method sets the cross section for this XSdata object at the @@ -406,14 +406,13 @@ class XSdata(object): """ check_type('absorption', absorption, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - npabsorption = np.asarray(absorption) - check_value('absorption shape', npabsorption.shape, - [self.vector_shape]) + absorption = np.asarray(absorption) + check_value('absorption shape', absorption.shape, [self.vector_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._absorption[i] = npabsorption + self._absorption[i] = absorption def set_fission(self, fission, temperature=294.): """This method sets the cross section for this XSdata object at the @@ -434,15 +433,15 @@ class XSdata(object): """ check_type('fission', fission, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - npfission = np.asarray(fission) - check_value('fission shape', npfission.shape, [self.vector_shape]) + fission = np.asarray(fission) + check_value('fission shape', fission.shape, [self.vector_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._fission[i] = npfission + self._fission[i] = fission - if np.sum(npfission) > 0.0: + if np.sum(fission) > 0.0: self._fissionable = True def set_kappa_fission(self, kappa_fission, temperature=294.): @@ -465,16 +464,16 @@ class XSdata(object): check_type('kappa_fission', kappa_fission, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - npkappa_fission = np.asarray(kappa_fission) - check_value('kappa fission shape', npkappa_fission.shape, + kappa_fission = np.asarray(kappa_fission) + check_value('kappa fission shape', kappa_fission.shape, [self.vector_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._kappa_fission[i] = npkappa_fission + self._kappa_fission[i] = kappa_fission - if np.sum(npkappa_fission) > 0.0: + if np.sum(kappa_fission) > 0.0: self._fissionable = True def set_chi(self, chi, temperature=294.): @@ -502,16 +501,16 @@ class XSdata(object): check_type('chi', chi, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - npchi = np.asarray(chi) + chi = np.asarray(chi) # Check the shape - if npchi.shape != self.vector_shape: + if chi.shape != self.vector_shape: msg = 'Provided chi iterable does not have the expected shape.' raise ValueError(msg) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._chi[i] = npchi + self._chi[i] = chi if self.use_chi is not None: self.use_chi = True @@ -534,15 +533,15 @@ class XSdata(object): """ # Convert to a numpy array so we can easily get the shape for checking - npscatter = np.asarray(scatter) - check_iterable_type('scatter', npscatter, Real, - max_depth=len(npscatter.shape)) - check_value('scatter shape', npscatter.shape, [self.pn_matrix_shape]) + scatter = np.asarray(scatter) + check_iterable_type('scatter', scatter, Real, + max_depth=len(scatter.shape)) + check_value('scatter shape', scatter.shape, [self.pn_matrix_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._scatter_matrix[i] = npscatter + self._scatter_matrix[i] = scatter def set_multiplicity_matrix(self, multiplicity, temperature=294.): """This method sets the cross section for this XSdata object at the @@ -562,16 +561,16 @@ class XSdata(object): """ # Convert to a numpy array so we can easily get the shape for checking - npmultiplicity = np.asarray(multiplicity) - check_iterable_type('multiplicity', npmultiplicity, Real, - max_depth=len(npmultiplicity.shape)) - check_value('multiplicity shape', npmultiplicity.shape, + multiplicity = np.asarray(multiplicity) + check_iterable_type('multiplicity', multiplicity, Real, + max_depth=len(multiplicity.shape)) + check_value('multiplicity shape', multiplicity.shape, [self.matrix_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._multiplicity_matrix[i] = npmultiplicity + self._multiplicity_matrix[i] = multiplicity def set_nu_fission(self, nu_fission, temperature=294.): """This method sets the cross section for this XSdata object at the @@ -601,33 +600,33 @@ class XSdata(object): # and set the use_chi flag accordingly # Convert to a numpy array so we can easily get the shape for checking - npnu_fission = np.asarray(nu_fission) + nu_fission = np.asarray(nu_fission) - check_iterable_type('nu_fission', npnu_fission, Real, - max_depth=len(npnu_fission.shape)) + check_iterable_type('nu_fission', nu_fission, Real, + max_depth=len(nu_fission.shape)) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) if self.use_chi is not None: if self.use_chi: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.vector_shape]) else: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.matrix_shape]) else: - check_value('nu_fission shape', npnu_fission.shape, + check_value('nu_fission shape', nu_fission.shape, [self.vector_shape, self.matrix_shape]) # Find out if we have a nu-fission matrix or vector # and set a flag to allow other methods to check this later. - if npnu_fission.shape == self.vector_shape: + if nu_fission.shape == self.vector_shape: self.use_chi = True else: self.use_chi = False i = np.where(self.temperatures == temperature) - self._nu_fission[i] = npnu_fission - if np.sum(npnu_fission) > 0.0: + self._nu_fission[i] = nu_fission + if np.sum(nu_fission) > 0.0: self._fissionable = True def set_inverse_velocities(self, inv_vel, temperature=294.): @@ -646,14 +645,14 @@ class XSdata(object): check_type('inverse velocities', inv_vel, Iterable, expected_iter_type=Real) # Convert to a numpy array so we can easily get the shape for checking - npinv_vel = np.asarray(inv_vel) - check_value('inverse velocities shape', npinv_vel.shape, + inv_vel = np.asarray(inv_vel) + check_value('inverse velocities shape', inv_vel.shape, [self.vector_shape]) check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature) - self._inverse_velocities[i] = npinv_vel + self._inverse_velocities[i] = inv_vel def set_total_mgxs(self, total, temperature=294., nuclide='total', xs_type='macro', subdomain=None): From b3ec0d345ff4dba107b9a27ca8dd4468c8475316 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 10 Oct 2016 18:11:48 -0400 Subject: [PATCH 57/82] Remove bad English --- src/nuclide_header.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 93832869ce..3533fc9697 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -194,8 +194,6 @@ module nuclide_header integer, intent(inout) :: method real(8), intent(in) :: tolerance logical, intent(in) :: master ! if this is the master proc - ! (can't use global cuz - ! circular dependance) integer :: i integer :: storage_type From 6976960d17467d37e3c804999de5d273b4a43976 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 11 Oct 2016 14:28:58 -0500 Subject: [PATCH 58/82] Disallow export_to_hdf5() when data came from ENDF --- openmc/data/neutron.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 166ffe42a4..c125e3e040 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -377,7 +377,7 @@ class IncidentNeutron(EqualityMixin): return mts def export_to_hdf5(self, path, mode='a'): - """Export table to an HDF5 file. + """Export incident neutron data to an HDF5 file. Parameters ---------- @@ -388,6 +388,10 @@ class IncidentNeutron(EqualityMixin): to the :class:`h5py.File` constructor. """ + # If data come from ENDF, don't allow exporting to HDF5 + if hasattr(self, '_evaluation'): + raise NotImplementedError('Cannot export incident neutron data that ' + 'originated from an ENDF file.') f = h5py.File(path, mode, libver='latest') From 37d230e65bc1621953baa76c90222df7b1376af1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 11 Oct 2016 21:09:50 -0500 Subject: [PATCH 59/82] Fix typo in units description --- openmc/data/fission_energy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 687cb5703e..83f61a1aec 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -24,7 +24,7 @@ def _extract_458_data(ev, units='eV'): ev : openmc.data.Evaluation ENDF evaluation units : {'eV', 'MeV'} - The units are used in values returned. + The units that are used in values returned. Returns ------- From 965a1acf60e0d0d4addac6029917fdcbde50db51 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 12 Oct 2016 07:45:16 -0500 Subject: [PATCH 60/82] Make sure MF=6 distributions get applied to fission products correctly --- openmc/data/reaction.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index af903fe8a1..922e13ed4f 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -1025,7 +1025,12 @@ class Reaction(EqualityMixin): if (6, mt) in ev.section: # Product angle-energy distribution - rx.products = _get_products(ev, mt) + for product in _get_products(ev, mt): + if mt in (18, 19, 20, 21, 38) and product.particle == 'neutron': + rx.products[0].applicability = product.applicability + rx.products[0].distribution = product.distribution + else: + rx.products.append(product) elif (4, mt) in ev.section or (5, mt) in ev.section: # Uncorrelated angle-energy distribution From 04e670c71563f868975ea07fdb5d14787466b5c4 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Sat, 8 Oct 2016 16:53:14 -0400 Subject: [PATCH 61/82] add a create_fission_neutrons option Whether create fission neutrons --- src/global.F90 | 3 +++ src/input_xml.F90 | 13 +++++++++++++ src/physics.F90 | 5 +++-- src/physics_mg.F90 | 2 +- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index f00a1d368f..a5720464de 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -352,6 +352,9 @@ module global ! Write out initial source logical :: write_initial_source = .false. + ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE + logical :: create_fission_neutrons = .true. + ! ============================================================================ ! CMFD VARIABLES diff --git a/src/input_xml.F90 b/src/input_xml.F90 index db08eedaab..c92ceee8c5 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1102,6 +1102,19 @@ contains end select end if + ! Check whether create fission sites + if (run_mode == MODE_FIXEDSOURCE) then + if (check_for_node(doc, "create_fission_neutrons")) then + call get_node_value(doc, "create_fission_neutrons", temp_str) + temp_str = to_lower(temp_str) + if (trim(temp_str) == 'true' .or. trim(temp_str) == '1') then + create_fission_neutrons = .true. + else if (trim(temp_str) == 'false' .or. trim(temp_str) == '0') then + create_fission_neutrons = .false. + end if + end if + end if + ! Close settings XML file call close_xmldoc(doc) diff --git a/src/physics.F90 b/src/physics.F90 index 6a6a9787d5..232effebf3 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -96,10 +96,11 @@ contains ! absorption (including fission) if (nuc % fissionable) then - call sample_fission(i_nuclide, i_reaction) if (run_mode == MODE_EIGENVALUE) then + call sample_fission(i_nuclide, i_reaction) call create_fission_sites(p, i_nuclide, i_reaction, fission_bank, n_bank) - elseif (run_mode == MODE_FIXEDSOURCE) then + elseif (run_mode == MODE_FIXEDSOURCE .and. create_fission_neutrons) then + call sample_fission(i_nuclide, i_reaction) call create_fission_sites(p, i_nuclide, i_reaction, & p % secondary_bank, p % n_secondary) end if diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 2e5e467c14..c60fc6e2e1 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -73,7 +73,7 @@ contains if (mat % fissionable) then if (run_mode == MODE_EIGENVALUE) then call create_fission_sites(p, fission_bank, n_bank) - elseif (run_mode == MODE_FIXEDSOURCE) then + elseif (run_mode == MODE_FIXEDSOURCE .and. create_fission_neutrons) then call create_fission_sites(p, p % secondary_bank, p % n_secondary) end if end if From f42a324143fa6b58372552be6fd62e7555b07282 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Sat, 8 Oct 2016 16:54:32 -0400 Subject: [PATCH 62/82] support create_fission_neutrons option in Python API --- openmc/settings.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/openmc/settings.py b/openmc/settings.py index 335de839a5..b453215ea0 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -141,6 +141,8 @@ class Settings(object): The elastic scattering model to use for resonant isotopes volume_calculations : VolumeCalculation or iterable of VolumeCalculation Stochastic volume calculation specifications + create_fission_neutrons : bool + Indicate whether fission neutrons should be created or not. """ @@ -227,6 +229,8 @@ class Settings(object): self._volume_calculations = cv.CheckedList( VolumeCalculation, 'volume calculations') + self._create_fission_neutrons = None + @property def run_mode(self): return self._run_mode @@ -427,6 +431,10 @@ class Settings(object): def volume_calculations(self): return self._volume_calculations + @property + def create_fission_neutrons(self): + return self._create_fission_neutrons + @run_mode.setter def run_mode(self, run_mode): if run_mode not in ['eigenvalue', 'fixed source']: @@ -826,6 +834,12 @@ class Settings(object): self._volume_calculations = cv.CheckedList( VolumeCalculation, 'stochastic volume calculations', vol_calcs) + @create_fission_neutrons.setter + def create_fission_neutrons(self, create_fission_neutrons): + cv.check_type('Whether create fission neutrons', + create_fission_neutrons, bool) + self._create_fission_neutrons = create_fission_neutrons + def _create_run_mode_subelement(self): if self.run_mode == 'eigenvalue': @@ -1121,6 +1135,11 @@ class Settings(object): for r in self.resonance_scattering: elem.append(r.to_xml_element()) + def _create_create_fission_neutrons_subelement(self): + if self._create_fission_neutrons is not None: + elem = ET.SubElement(self._settings_file, "create_fission_neutrons") + elem.text = str(self._create_fission_neutrons).lower() + def export_to_xml(self, path='settings.xml'): """Export simulation settings to an XML file. @@ -1164,6 +1183,7 @@ class Settings(object): self._create_dd_subelement() self._create_resonance_scattering_subelement() self._create_volume_calcs_subelement() + self._create_create_fission_neutrons_subelement() # Clean the indentation in the file to be user-readable clean_xml_indentation(self._settings_file) From f4ac440407fd64d5ec02cdc5bb9364dde55e3fb2 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Sat, 8 Oct 2016 16:55:29 -0400 Subject: [PATCH 63/82] add a create_fission_neutrons unit test --- .../inputs_true.dat | 1 + .../results_true.dat | 3 + .../test_create_fission_neutrons.py | 80 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/test_create_fission_neutrons/inputs_true.dat create mode 100644 tests/test_create_fission_neutrons/results_true.dat create mode 100755 tests/test_create_fission_neutrons/test_create_fission_neutrons.py diff --git a/tests/test_create_fission_neutrons/inputs_true.dat b/tests/test_create_fission_neutrons/inputs_true.dat new file mode 100644 index 0000000000..8a1a17b9e9 --- /dev/null +++ b/tests/test_create_fission_neutrons/inputs_true.dat @@ -0,0 +1 @@ +c3581501d1486293c255390251d20584431a198fbb7c07dc2879dc95dc96e26786d3913ce0db8007f542468fd137ff3267824844c03b4687fdad81ea568c92d7 \ No newline at end of file diff --git a/tests/test_create_fission_neutrons/results_true.dat b/tests/test_create_fission_neutrons/results_true.dat new file mode 100644 index 0000000000..be7c5c438d --- /dev/null +++ b/tests/test_create_fission_neutrons/results_true.dat @@ -0,0 +1,3 @@ +tally 1: +sum = 2.056839E+02 +sum_sq = 4.244628E+03 diff --git a/tests/test_create_fission_neutrons/test_create_fission_neutrons.py b/tests/test_create_fission_neutrons/test_create_fission_neutrons.py new file mode 100755 index 0000000000..80da831cc0 --- /dev/null +++ b/tests/test_create_fission_neutrons/test_create_fission_neutrons.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python + +import os +import sys +sys.path.insert(0, os.pardir) +from testing_harness import PyAPITestHarness +import openmc + + +class CreateFissionNeutronsTestHarness(PyAPITestHarness): + def _build_inputs(self): + # Material is composed of H-1 and U-235 + mat = openmc.Material(material_id=1, name='mat') + mat.set_density('atom/b-cm', 0.069335) + mat.add_nuclide('H1', 40.0) + mat.add_nuclide('U235', 1.0) + materials_file = openmc.Materials([mat]) + materials_file.export_to_xml() + + # Cell is box with reflective boundary + x1 = openmc.XPlane(surface_id=1, x0=-1) + x2 = openmc.XPlane(surface_id=2, x0=1) + y1 = openmc.YPlane(surface_id=3, y0=-1) + y2 = openmc.YPlane(surface_id=4, y0=1) + z1 = openmc.ZPlane(surface_id=5, z0=-1) + z2 = openmc.ZPlane(surface_id=6, z0=1) + for surface in [x1, x2, y1, y2, z1, z2]: + surface.boundary_type = 'reflective' + box = openmc.Cell(cell_id=1, name='box') + box.region = +x1 & -x2 & +y1 & -y2 & +z1 & -z2 + box.fill = mat + root = openmc.Universe(universe_id=0, name='root universe') + root.add_cell(box) + geometry = openmc.Geometry(root) + geometry.export_to_xml() + + # Set the running parameters + settings_file = openmc.Settings() + settings_file.run_mode = 'fixed source' + settings_file.batches = 10 + settings_file.particles = 100 + settings_file.create_fission_neutrons = False + bounds = [-1, -1, -1, 1, 1, 1] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + watt_dist = openmc.stats.Watt() + settings_file.source = openmc.source.Source(space=uniform_dist, + energy=watt_dist) + settings_file.export_to_xml() + + # Create tallies + tallies = openmc.Tallies() + tally = openmc.Tally(1) + tally.scores = ['flux'] + tallies.append(tally) + tallies.export_to_xml() + + def _get_results(self): + """Digest info in the statepoint and return as a string.""" + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # Write out tally data. + outstr = '' + t = sp.get_tally() + outstr += 'tally {0}:\n'.format(t.id) + outstr += 'sum = {0:12.6E}\n'.format(t.sum[0, 0, 0]) + outstr += 'sum_sq = {0:12.6E}\n'.format(t.sum_sq[0, 0, 0]) + + return outstr + + def _cleanup(self): + super(CreateFissionNeutronsTestHarness, self)._cleanup() + f = os.path.join(os.getcwd(), 'tallies.xml') + if os.path.exists(f): + os.remove(f) + + +if __name__ == '__main__': + harness = CreateFissionNeutronsTestHarness('statepoint.10.h5', True) + harness.main() From 4e1046585f7277faf8b5de7c1c2bb3bfa0a10cba Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Mon, 10 Oct 2016 22:46:18 -0400 Subject: [PATCH 64/82] add docs for --- docs/source/usersguide/input.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 847dc66fff..4eb83d7033 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -872,6 +872,19 @@ displayed. This element takes the following attributes: *Default*: 5 +```` Element +------------------------------------- + +The ```` element indicates whether fission neutrons +should be created or not. If this element is set to "true", fission neutrons +will be created; otherwise the fission is treated as capture and no fission +neutron will be created. Note that this option is only applied to fixed source +calculation. For eigenvalue calculation, fission will always be treated as real +fission. + + *Default*: true + + ```` Element ------------------------- From 83dcfb40f877695012edbe1703983699833ea387 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 12 Oct 2016 18:15:03 -0400 Subject: [PATCH 65/82] Fix mixed-unit error in fission Q values --- openmc/data/fission_energy.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index 83f61a1aec..924fe00865 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -40,6 +40,9 @@ def _extract_458_data(ev, units='eV'): caution. """ + cv.check_type('evaluation', ev, Evaluation) + cv.check_value('energy units', units, ('eV', 'MeV')) + if not ev.target['fissionable']: # This nuclide isn't fissionable. return None @@ -356,7 +359,7 @@ class FissionEnergyRelease(EqualityMixin): self._neutrinos = energy_release @classmethod - def _from_dictionary(cls, energy_release, incident_neutron): + def _from_dictionary(cls, energy_release, incident_neutron, units='eV'): """Generate fission energy release data from a dictionary. Parameters @@ -368,6 +371,8 @@ class FissionEnergyRelease(EqualityMixin): data, more for polynomial data. incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset + units : {'eV', 'MeV'} + The energy units used in the returned object. Returns ------- @@ -375,6 +380,8 @@ class FissionEnergyRelease(EqualityMixin): Fission energy release data """ + cv.check_value('energy units', units, ('eV', 'MeV')) + out = cls() # How many coefficients are given for each component? If we only find @@ -425,24 +432,28 @@ class FissionEnergyRelease(EqualityMixin): raise ValueError('Ambiguous prompt/total nu value.') nu = nu[0] + if units == 'eV': + nu_const = 8.07e6 + else: + nu_const = 8.07 if isinstance(nu, Tabulated1D): ENP = deepcopy(nu) ENP.y = (energy_release['ENP'] + 1.307 * nu.x - - 8.07 * (nu.y - nu.y[0])) + - nu_const * (nu.y - nu.y[0])) elif isinstance(nu, Polynomial): if len(nu) == 1: ENP = Polynomial([energy_release['ENP'][0], 1.307]) else: ENP = Polynomial( - [energy_release['ENP'][0], 1.307 - 8.07*nu.coef[1]] + - [-8.07*c for c in nu.coef[2:]]) + [energy_release['ENP'][0], 1.307 - nu_const*nu.coef[1]] + + [-nu_const*c for c in nu.coef[2:]]) out.prompt_neutrons = ENP return out @classmethod - def from_endf(cls, ev, incident_neutron): + def from_endf(cls, ev, incident_neutron, units='eV'): """Generate fission energy release data from an ENDF file. Parameters @@ -451,6 +462,8 @@ class FissionEnergyRelease(EqualityMixin): ENDF evaluation incident_neutron : openmc.data.IncidentNeutron Corresponding incident neutron dataset + units : {'eV', 'MeV'} + The energy units used in the returned object. Returns ------- @@ -458,6 +471,7 @@ class FissionEnergyRelease(EqualityMixin): Fission energy release data """ + cv.check_type('evaluation', ev, Evaluation) # Check to make sure this ENDF file matches the expected isomer. if ev.target['atomic_number'] != incident_neutron.atomic_number: @@ -473,10 +487,10 @@ class FissionEnergyRelease(EqualityMixin): raise ValueError('The ENDF evaluation is not fissionable.') # Read the 458 data from the ENDF file. - value, uncertainty = _extract_458_data(ev) + value, uncertainty = _extract_458_data(ev, units) # Build the object. - return cls._from_dictionary(value, incident_neutron) + return cls._from_dictionary(value, incident_neutron, units) @classmethod def from_hdf5(cls, group): From 5ab6160c2a590685085069cec59cb798c192c64f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 13 Oct 2016 07:09:50 -0500 Subject: [PATCH 66/82] Move fission Q file to openmc/data and make sure it's accessible from openmc-get-nndc-data --- .../data}/fission_Q_data_endfb71.h5 | Bin scripts/openmc-get-nndc-data | 36 ++++++++---------- setup.py | 2 +- 3 files changed, 17 insertions(+), 21 deletions(-) rename {data => openmc/data}/fission_Q_data_endfb71.h5 (100%) diff --git a/data/fission_Q_data_endfb71.h5 b/openmc/data/fission_Q_data_endfb71.h5 similarity index 100% rename from data/fission_Q_data_endfb71.h5 rename to openmc/data/fission_Q_data_endfb71.h5 diff --git a/scripts/openmc-get-nndc-data b/scripts/openmc-get-nndc-data index 5231b67ef0..fe9d3ff5bd 100755 --- a/scripts/openmc-get-nndc-data +++ b/scripts/openmc-get-nndc-data @@ -13,6 +13,8 @@ import argparse from six.moves import input from six.moves.urllib.request import urlopen +import openmc.data + description = """ Download ENDF/B-VII.1 ACE data from NNDC and convert it to an HDF5 library for @@ -20,6 +22,7 @@ use with OpenMC. """ + class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter): pass @@ -75,7 +78,8 @@ for f in files: if not chunk: break fh.write(chunk) downloaded += len(chunk) - status = '{0:10} [{1:3.2f}%]'.format(downloaded, downloaded * 100. / file_size) + status = '{0:10} [{1:3.2f}%]'.format( + downloaded, downloaded * 100. / file_size) print(status + chr(8)*len(status), end='') print('') filesComplete.append(f) @@ -109,7 +113,7 @@ for f in files: for filename in glob.glob('nndc/293.6K/ENDF-B-VII.1-neutron-293.6K/*'): shutil.move(filename, 'nndc/293.6K/') -#=============================================================================== +# ============================================================================== # EDIT GRAPHITE ZAID (6012 to 6000) print('Changing graphite ZAID from 6012 to 6000') @@ -137,24 +141,16 @@ if not response or response.lower().startswith('y'): os.remove(f) # ============================================================================== -# PROMPT USER TO GENERATE HDF5 LIBRARY +# GENERATE HDF5 LIBRARY -# Ask user to convert -if not args.batch: - response = input('Generate HDF5 library? ([y]/n) ') -else: - response = 'y' +# get a list of all ACE files +ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*'))) -# Convert files if requested -if not response or response.lower().startswith('y'): - # get a list of all ACE files - ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*'))) +# Get path to fission energy release data +data_dir = os.path.dirname(sys.modules['openmc.data'].__file__) +fer_file = os.path.join(data_dir, 'fission_Q_data_endfb71.h5') - # Ensure 'import openmc.data' works in the openmc-ace-to-xml script - cwd = os.getcwd() - env = os.environ.copy() - env['PYTHONPATH'] = os.path.join(cwd, '..') - - subprocess.call(['../scripts/openmc-ace-to-hdf5', '-d', 'nndc_hdf5', - '--fission_energy_release', 'fission_Q_data_endfb71.h5'] - + ace_files, env=env) +pwd = os.path.dirname(os.path.realpath(__file__)) +ace2hdf5 = os.path.join(pwd, 'openmc-ace-to-hdf5') +subprocess.call([ace2hdf5, '-d', 'nndc_hdf5', '--fission_energy_release', + fer_file] + ace_files) diff --git a/setup.py b/setup.py index fe1de3df8e..83098a9d5c 100644 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ if have_setuptools: # Data files 'package_data': { - 'openmc.data': ['mass.mas12'] + 'openmc.data': ['mass.mas12', 'fission_Q_data_endfb71.h5'] }, }) From b605c4441de6d1261024bbcd4b5455b115e2ea20 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 13 Oct 2016 07:31:13 -0500 Subject: [PATCH 67/82] Fix .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8df8f320eb..676bfb42f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,11 +47,9 @@ before_script: fi - export OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml - - cd data - git clone --branch=master git://github.com/smharper/windowed_multipole_library.git wmp_lib - tar xzvf wmp_lib/multipole_lib.tar.gz - export OPENMC_MULTIPOLE_LIBRARY=$PWD/multipole_lib - - cd .. script: - cd tests From 477da9b47dd7aec81c5ada5056559cc004b7db7f Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Tue, 11 Oct 2016 14:35:09 -0400 Subject: [PATCH 68/82] add energy_cutoff Kill particles under certain energy --- src/global.F90 | 1 + src/input_xml.F90 | 11 +++++++++-- src/physics.F90 | 7 +++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/global.F90 b/src/global.F90 index a5720464de..042d530f37 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -304,6 +304,7 @@ module global logical :: survival_biasing = .false. real(8) :: weight_cutoff = 0.25_8 + real(8) :: energy_cutoff = ZERO real(8) :: weight_survive = ONE ! ============================================================================ diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c92ceee8c5..18af461a79 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -659,8 +659,15 @@ contains ! Cutoffs if (check_for_node(doc, "cutoff")) then call get_node_ptr(doc, "cutoff", node_cutoff) - call get_node_value(node_cutoff, "weight", weight_cutoff) - call get_node_value(node_cutoff, "weight_avg", weight_survive) + if (check_for_node(node_cutoff, "weight")) then + call get_node_value(node_cutoff, "weight", weight_cutoff) + end if + if (check_for_node(node_cutoff, "weight_avg")) then + call get_node_value(node_cutoff, "weight_avg", weight_survive) + end if + if (check_for_node(node_cutoff, "energy")) then + call get_node_value(node_cutoff, "energy", energy_cutoff) + end if end if ! Particle trace diff --git a/src/physics.F90 b/src/physics.F90 index 232effebf3..842540d166 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -127,6 +127,13 @@ contains if (.not. p % alive) return end if + ! Kill neutron under certain energy + if (p % E < energy_cutoff) then + p % alive = .false. + p % wgt = ZERO + p % last_wgt = ZERO + end if + end subroutine sample_reaction !=============================================================================== From bc9b53ed27c9a8f914941d74f41f38fb9819fe71 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Tue, 11 Oct 2016 14:35:33 -0400 Subject: [PATCH 69/82] support energy cutoff in Python API --- openmc/settings.py | 70 ++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/openmc/settings.py b/openmc/settings.py index b453215ea0..497eeea75b 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -89,10 +89,14 @@ class Settings(object): Seed for the linear congruential pseudorandom number generator survival_biasing : bool Indicate whether survival biasing is to be used - weight : float - Weight cutoff below which particle undergo Russian roulette - weight_avg : float - Weight assigned to particles that are not killed after Russian roulette + cutoff : dict + Dictionary defining weight cutoff and energy cutoff. The dictionary may + have three keys, 'weight', 'weight_avg' and 'energy'. Value for 'weight' + should be a float indicating weight cutoff below which particle undergo + Russian roulette. Value for 'weight_avg' should be a float indicating + weight assigned to particles that are not killed after Russian + roulette. Value of energy should be a float indicating energy in MeV + below which particle will be killed. entropy_dimension : tuple or list Number of Shannon entropy mesh cells in the x, y, and z directions, respectively @@ -205,8 +209,7 @@ class Settings(object): self._temperature = {} # Cutoff subelement - self._weight = None - self._weight_avg = None + self._cutoff = None # Uniform fission source subelement self._ufs_dimension = 1 @@ -380,12 +383,8 @@ class Settings(object): return self._track @property - def weight(self): - return self._weight - - @property - def weight_avg(self): - return self._weight_avg + def cutoff(self): + return self._cutoff @property def ufs_dimension(self): @@ -622,17 +621,29 @@ class Settings(object): cv.check_type('survival biasing', survival_biasing, bool) self._survival_biasing = survival_biasing - @weight.setter - def weight(self, weight): - cv.check_type('weight cutoff', weight, Real) - cv.check_greater_than('weight cutoff', weight, 0.0) - self._weight = weight + @cutoff.setter + def cutoff(self, cutoff): + if not isinstance(cutoff, Mapping): + msg = 'Unable to set cutoff from "{0}" which is not a '\ + ' Python dictionary'.format(cutoff) + raise ValueError(msg) + for key in cutoff: + if key == 'weight': + cv.check_type('weight cutoff', cutoff['weight'], Real) + cv.check_greater_than('weight cutoff', cutoff['weight'], 0.0) + elif key == 'weight_avg': + cv.check_type('average survival weight', cutoff['weight_avg'], + Real) + cv.check_greater_than('average survival weight', + cutoff['weight_avg'], 0.0) + elif key == 'energy': + cv.check_type('energy cutoff', cutoff['energy'], Real) + cv.check_greater_than('energy cutoff', cutoff['energy'], 0.0) + else: + msg = 'Unable to set cutoff to "{0}" which is unsupported by '\ + 'OpenMC'.format(key) - @weight_avg.setter - def weight_avg(self, weight_avg): - cv.check_type('average survival weight', weight_avg, Real) - cv.check_greater_than('average survival weight', weight_avg, 0.0) - self._weight_avg = weight_avg + self._cutoff = cutoff @entropy_dimension.setter def entropy_dimension(self, dimension): @@ -1004,14 +1015,19 @@ class Settings(object): element.text = str(self._survival_biasing).lower() def _create_cutoff_subelement(self): - if self._weight is not None: + if self._cutoff is not None: element = ET.SubElement(self._settings_file, "cutoff") + if 'weight' in self._cutoff: + subelement = ET.SubElement(element, "weight") + subelement.text = str(self._cutoff['weight']) - subelement = ET.SubElement(element, "weight") - subelement.text = str(self._weight) + if 'weight_avg' in self._cutoff: + subelement = ET.SubElement(element, "weight_avg") + subelement.text = str(self._cutoff['weight_avg']) - subelement = ET.SubElement(element, "weight_avg") - subelement.text = str(self._weight_avg) + if 'energy' in self._cutoff: + subelement = ET.SubElement(element, "energy") + subelement.text = str(self._cutoff['energy']) def _create_entropy_subelement(self): if self._entropy_lower_left is not None and \ From bc8f794d330319530416a0b7c673fa41cb5c9b82 Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Tue, 11 Oct 2016 14:35:53 -0400 Subject: [PATCH 70/82] add docs for energy cutoff --- docs/source/usersguide/input.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 4eb83d7033..b1eedf59cd 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -121,10 +121,13 @@ multi-group mode. ```` Element -------------------- -The ```` element indicates the weight cutoff used below which particles -undergo Russian roulette. Surviving particles are assigned a user-determined -weight. Note that weight cutoffs and Russian rouletting are not turned on by -default. This element has the following attributes/sub-elements: +The ```` element indicates two kinds of cutoffs. The first is the weight +cutoff used below which particles undergo Russian roulette. Surviving particles +are assigned a user-determined weight. Note that weight cutoffs and Russian +rouletting are not turned on by default. The second is the energy cutoff which +is used to kill particles under certain energy. The energy cutoff should not be +used unless you know particles under the energy are of no importance to results +you care. This element has the following attributes/sub-elements: :weight: The weight below which particles undergo Russian roulette. @@ -137,6 +140,11 @@ default. This element has the following attributes/sub-elements: *Default*: 1.0 + :energy: + The energy under which particles will be killed. + + *Default*: 0.0 + .. _eigenvalue: ```` Element From 48a95a5b8d195174e16dc465c5f81a7d8441a47e Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Tue, 11 Oct 2016 14:36:10 -0400 Subject: [PATCH 71/82] add an unit test for energy cutoff --- tests/test_energy_cutoff/inputs_true.dat | 1 + tests/test_energy_cutoff/results_true.dat | 3 + .../test_energy_cutoff/test_energy_cutoff.py | 84 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/test_energy_cutoff/inputs_true.dat create mode 100644 tests/test_energy_cutoff/results_true.dat create mode 100755 tests/test_energy_cutoff/test_energy_cutoff.py diff --git a/tests/test_energy_cutoff/inputs_true.dat b/tests/test_energy_cutoff/inputs_true.dat new file mode 100644 index 0000000000..0630d2acc2 --- /dev/null +++ b/tests/test_energy_cutoff/inputs_true.dat @@ -0,0 +1 @@ +4dc6a7b131f6757ecc9b06e93d425712f0813c546ed9eaa0aafa4990383b2f3a5b742a5a39ef5f27300d2c861b344e78de2d2c569b9439e7893dc06b03bf3b02 \ No newline at end of file diff --git a/tests/test_energy_cutoff/results_true.dat b/tests/test_energy_cutoff/results_true.dat new file mode 100644 index 0000000000..5ad463b774 --- /dev/null +++ b/tests/test_energy_cutoff/results_true.dat @@ -0,0 +1,3 @@ +tally 1: +sum = 0.000000E+00 +sum_sq = 0.000000E+00 diff --git a/tests/test_energy_cutoff/test_energy_cutoff.py b/tests/test_energy_cutoff/test_energy_cutoff.py new file mode 100755 index 0000000000..6467a59255 --- /dev/null +++ b/tests/test_energy_cutoff/test_energy_cutoff.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +import os +import sys +sys.path.insert(0, os.pardir) +from testing_harness import PyAPITestHarness +import openmc + + +class EnergyCutoffTestHarness(PyAPITestHarness): + def _build_inputs(self): + # Set energy cutoff + energy_cutoff = 4e-6 + + # Material is composed of H-1 + mat = openmc.Material(material_id=1, name='mat') + mat.set_density('atom/b-cm', 0.069335) + mat.add_nuclide('H1', 40.0) + materials_file = openmc.Materials([mat]) + materials_file.export_to_xml() + + # Cell is box with reflective boundary + x1 = openmc.XPlane(surface_id=1, x0=-1) + x2 = openmc.XPlane(surface_id=2, x0=1) + y1 = openmc.YPlane(surface_id=3, y0=-1) + y2 = openmc.YPlane(surface_id=4, y0=1) + z1 = openmc.ZPlane(surface_id=5, z0=-1) + z2 = openmc.ZPlane(surface_id=6, z0=1) + for surface in [x1, x2, y1, y2, z1, z2]: + surface.boundary_type = 'reflective' + box = openmc.Cell(cell_id=1, name='box') + box.region = +x1 & -x2 & +y1 & -y2 & +z1 & -z2 + box.fill = mat + root = openmc.Universe(universe_id=0, name='root universe') + root.add_cell(box) + geometry = openmc.Geometry(root) + geometry.export_to_xml() + + # Set the running parameters + settings_file = openmc.Settings() + settings_file.run_mode = 'fixed source' + settings_file.batches = 10 + settings_file.particles = 100 + settings_file.cutoff = {'energy': energy_cutoff} + bounds = [-1, -1, -1, 1, 1, 1] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + watt_dist = openmc.stats.Watt() + settings_file.source = openmc.source.Source(space=uniform_dist, + energy=watt_dist) + settings_file.export_to_xml() + + # Tally flux under energy cutoff + tallies = openmc.Tallies() + tally = openmc.Tally(1) + tally.scores = ['flux'] + energy_filter = openmc.filter.EnergyFilter((0.0, energy_cutoff)) + tally.filters = [energy_filter] + tallies.append(tally) + tallies.export_to_xml() + + def _get_results(self): + """Digest info in the statepoint and return as a string.""" + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # Write out tally data. + outstr = '' + t = sp.get_tally() + outstr += 'tally {0}:\n'.format(t.id) + outstr += 'sum = {0:12.6E}\n'.format(t.sum[0, 0, 0]) + outstr += 'sum_sq = {0:12.6E}\n'.format(t.sum_sq[0, 0, 0]) + + return outstr + + def _cleanup(self): + super(EnergyCutoffTestHarness, self)._cleanup() + f = os.path.join(os.getcwd(), 'tallies.xml') + if os.path.exists(f): + os.remove(f) + + +if __name__ == '__main__': + harness = EnergyCutoffTestHarness('statepoint.10.h5', True) + harness.main() From e85393936fef8d89f37bb9f04e119af7ab32a73d Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Thu, 13 Oct 2016 19:36:23 -0400 Subject: [PATCH 72/82] Fixed failing test_mgxs_library_ce_to_mg --- openmc/mgxs/library.py | 2 +- openmc/mgxs_library.py | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 5535f84856..64210606df 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -924,7 +924,7 @@ class Library(object): if 'nu-transport' in self.mgxs_types and self.correction is 'P0': mymgxs = self.get_mgxs(domain, 'nu-transport') xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], - subdomains=subdomain) + subdomain=subdomain) elif 'total' in self.mgxs_types: mymgxs = self.get_mgxs(domain, 'total') xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index c2246fa926..edddd0bfac 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -384,7 +384,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._total[i] = total def set_absorption(self, absorption, temperature=294.): @@ -411,7 +411,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._absorption[i] = absorption def set_fission(self, fission, temperature=294.): @@ -438,7 +438,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._fission[i] = fission if np.sum(fission) > 0.0: @@ -470,7 +470,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._kappa_fission[i] = kappa_fission if np.sum(kappa_fission) > 0.0: @@ -509,7 +509,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._chi[i] = chi if self.use_chi is not None: @@ -540,7 +540,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._scatter_matrix[i] = scatter def set_multiplicity_matrix(self, multiplicity, temperature=294.): @@ -569,7 +569,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._multiplicity_matrix[i] = multiplicity def set_nu_fission(self, nu_fission, temperature=294.): @@ -624,7 +624,7 @@ class XSdata(object): else: self.use_chi = False - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._nu_fission[i] = nu_fission if np.sum(nu_fission) > 0.0: self._fissionable = True @@ -651,7 +651,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] self._inverse_velocities[i] = inv_vel def set_total_mgxs(self, total, temperature=294., nuclide='total', @@ -693,7 +693,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._total[i] = total.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) @@ -739,7 +739,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._absorption[i] = absorption.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -786,7 +786,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._fission[i] = fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -834,7 +834,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._nu_fission[i] = nu_fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -891,7 +891,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._kappa_fission[i] = k_fission.get_xs(nuclides=nuclide, xs_type=xs_type, @@ -942,7 +942,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': self._chi[i] = chi.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) @@ -1010,7 +1010,7 @@ class XSdata(object): check_value('legendre_order', scatter.legendre_order, [self.order]) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': # Get the scattering orders in the outermost dimension self._scatter_matrix[i] = np.zeros((self.num_orders, @@ -1088,7 +1088,7 @@ class XSdata(object): check_value('domain_type', scatter.domain_type, ['universe', 'cell', 'material', 'mesh']) - i = np.where(self.temperatures == temperature) + i = np.where(self.temperatures == temperature)[0][0] if self.representation is 'isotropic': nuscatt = nuscatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, From 7b3007d30ce967214b7640d5c441225433e3f9c4 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Thu, 13 Oct 2016 19:40:34 -0400 Subject: [PATCH 73/82] fixed source indentation issue --- src/geometry_header.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 3b489ece7d..9f4be90b9b 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -378,7 +378,7 @@ contains end do NUC_NAMES_LOOP if (present(sab_temps) .and. present(sab_dict) .and. & - mat % n_sab > 0) then + mat % n_sab > 0) then SAB_NAMES_LOOP: do k = 1, size(mat % sab_names) ! Get index in nuc_temps array i_sab = sab_dict % get_key(to_lower(mat % sab_names(k))) From b005aace7e2014e0d6b211d760ab50b8e94ac3db Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 11:33:00 -0400 Subject: [PATCH 74/82] Added a scatter_shape parameter to the library format and the ability to read/write it (but do nothing with it aside from check for the default value). Also converted back from is checks in the python for a string to ==, since is does not work for many cases --- docs/source/io_formats/mgxs_library.rst | 74 +++++++++++------------ openmc/mgxs/library.py | 62 ++++++++++---------- openmc/mgxs_library.py | 75 +++++++++++++++--------- scripts/openmc-update-mgxs | 14 ++--- src/mgxs_header.F90 | 7 +++ tests/1d_mgxs.h5 | Bin 123864 -> 124632 bytes 6 files changed, 128 insertions(+), 104 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 9262a234e7..2a1e63d435 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -38,10 +38,10 @@ MGXS Library Specification The data within contains the temperature-dependent multi-group data for the nuclide or material that it represents. -:Attributes: - **atomic_weight_ratio** (*double*) -- The atomic weight ratio (optional, - i.e. it is not meaningful for material-wise data) - - **fissionable** (*int*) -- Whether the dataset is fissionable - (1) or not (0). +:Attributes: - **atomic_weight_ratio** (*double*) -- The atomic weight ratio + (optional, i.e. it is not meaningful for material-wise data). + - **fissionable** (*bool*) -- Whether the dataset is fissionable + (True) or not (False). - **representation** (*char[]*) -- The method used to generate and represent the multi-group cross sections. That is, whether they were generated with scalar flux weighting (or reduced to a @@ -65,6 +65,15 @@ data for the nuclide or material that it represents. or number of points (depending on the value of `scatter_format`) used to describe the angular distribution associated with each group-to-group transfer probability. + - **scatter_shape** (*char[]*) -- The shape of the provided + scatter and multiplicity matrix. The values provided are strings + describing the ordering the scattering array is provided in + row-major (i.e., C/C++ and Python) indexing. Valid values are + "[Order][G][G']" or "[Order][G'][G]" where "G'" denotes the + secondary/outgoing energy groups, "G" denotes the incoming + energy groups, and "Order" is the angular distribution index. + This value is not required; if not the default value of + "[Order][G][G']" will be assumed. **//kTs/** @@ -79,29 +88,29 @@ Temperature-dependent data, provided for temperature K. :Datasets: - **total** (*double[]* or *double[][][]*) -- Total cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. + [groups][azimuthal][polar]. - **absorption** (*double[]* or *double[][][]*) -- Absorption cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. + [groups][azimuthal][polar]. - **fission** (*double[]* or *double[][][]*) -- Fission cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the dataset + [groups][azimuthal][polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **kappa-fission** (*double[]* or *double[][][]*) -- Kappa-Fission (energy-release from fission) cross section. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the dataset + [groups][azimuthal][polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **chi** (*double[]* or *double[][][]*) -- Fission neutron energy spectra. This is a 1-D vector if `representation` is "isotropic", or a 3-D vector if `representation` is "angle" with dimensions of - [groups, azimuthal, polar]. This is only required if the dataset + [groups][azimuthal][polar]. This is only required if the dataset is fissionable and fission-tallies are expected to be used. - **nu-fission** (*double[]* to *double[][][][]*) -- Nu-Fission cross section. @@ -119,34 +128,30 @@ Temperature-dependent data, provided for temperature K. Data specific to neutron scattering for the temperature K :Datasets: - **g_min** (*int[]* or *int[][][]*) -- - Minimum (most energetic) outgoing groups with non-zero values of - the scattering matrix. These group numbers use the standard + Minimum (most energetic) groups with non-zero values of + the scattering matrix provided. If `scatter_shape` is + "[Order][G][G']" then `g_min` will describe the minimum values + of "G'" for each "G"; if `scatter_shape` is "[Order][G'][G]" + then `g_min` will describe the minimum values of "G" for each "G'". + These group numbers use the standard ordering where the fastest neutron energy group is group 1 while the slowest neutron energy group is group G. The dimensionality of `g_min` is: - `g_min[g_in]`, or `g_min[num_polar][num_azimuthal][g_in]`. + `g_min[g]`, or `g_min[num_polar][num_azimuthal][g]`. The former is used when `representation` is "isotropic", and the latter when `representation` is "angle". - **g_max** (*int[]* or *int[][][]*) -- - Maximum (least energetic) outgoing groups with non-zero values of - the scattering matrix. These group numbers use the standard - ordering where the fastest neutron energy group is group 1 while - the slowest neutron energy group is group G. - The dimensionality of `g_max` is: - `g_max[g_in]`, or `g_max[num_polar][num_azimuthal][g_in]`. - The former is used when `representation` is "isotropic", and the - latter when `representation` is "angle". + Similar to `g_min`, except this dataset describes the maximum + (least energetic) groups with non-zero values of + the scattering matrix. - **scatter_matrix** (*double[]*) -- Flattened representation of the - scattering moment matrices. The pre-flattened array is shaped as - follows (in row-major format): - `scatter_matrix[order(+1)][g_in][g_out]`, or - `scatter_matrix[num_polar][num_azimuthal][order(+1)][g_in][g_out]` - The former is used when `representation` is "isotropic", and the - latter when `representation` is "angle". Note that if the value of - `scatter_format` is "legendre", the order dimension will be one - larger than the value of `order`, otherwise it will match `order`. - Finally, the g_out dimension has a dimensionality of - `g_min` to `g_max`. + scattering moment matrices. The pre-flattened array corresponds to + the shape provied in `scatter_shape`, but if `representation` is + "angle" the dimensionality in `scatter_shape` is prepended by + "[num_polar][num_azimuthal]" dimensions. The right-most energy + group dimension will only include the entries between `g_min` and + `g_max`. + dimension has a dimensionality of `g_min` to `g_max`. - **multiplicity_matrix** (*double[]*) -- Flattened representation of the scattering moment matrices. This dataset provides the code with a scaling factor to account for neutrons being produced in (n,xn) @@ -154,9 +159,6 @@ Data specific to neutron scattering for the temperature K for every Legendre moment or histogram/tabular bin. This dataset is optional, if it is not provided no multiplication (i.e., values of 1.0) will be assumed. - The pre-flattened array is shaped as follows (in row-major format): - `multiplicity_matrix[g_in][g_out]`, or - `multiplicity_matrix[num_polar][num_azimuthal][g_in][g_out]` - The former is used when `representation` is "isotropic", and the - latter when `representation` is "angle". Finally, the g_out - dimension has a dimensionality of `g_min` to `g_max`. \ No newline at end of file + The pre-flattened array is shapes consistent with `scatter_matrix` + except the "[Order]" dimension in `scatter_shape` is ignored since + this data is assumed isotropic. \ No newline at end of file diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 64210606df..c03aa78771 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -186,14 +186,14 @@ class Library(object): @property def domains(self): - if self._domains is 'all': - if self.domain_type is 'material': + if self._domains == 'all': + if self.domain_type == 'material': return self.openmc_geometry.get_all_materials() elif self.domain_type in ['cell', 'distribcell']: return self.openmc_geometry.get_all_material_cells() - elif self.domain_type is 'universe': + elif self.domain_type == 'universe': return self.openmc_geometry.get_all_universes() - elif self.domain_type is 'mesh': + elif self.domain_type == 'mesh': raise ValueError('Unable to get domains for Mesh domain type') else: raise ValueError('Unable to get domains without a domain type') @@ -265,7 +265,7 @@ class Library(object): @mgxs_types.setter def mgxs_types(self, mgxs_types): all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES - if mgxs_types is 'all': + if mgxs_types == 'all': self._mgxs_types = all_mgxs_types else: cv.check_iterable_type('mgxs_types', mgxs_types, basestring) @@ -277,7 +277,7 @@ class Library(object): def by_nuclide(self, by_nuclide): cv.check_type('by_nuclide', by_nuclide, bool) - if by_nuclide == True and self.domain_type is 'mesh': + if by_nuclide == True and self.domain_type == 'mesh': raise ValueError('Unable to create MGXS library by nuclide with ' 'mesh domain') @@ -287,7 +287,7 @@ class Library(object): def domain_type(self, domain_type): cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) - if self.by_nuclide == True and domain_type is 'mesh': + if self.by_nuclide == True and domain_type == 'mesh': raise ValueError('Unable to create MGXS library by nuclide with ' 'mesh domain') @@ -297,21 +297,21 @@ class Library(object): def domains(self, domains): # Use all materials, cells or universes in the geometry as domains - if domains is 'all': + if domains == 'all': self._domains = domains # User specified a list of material, cell or universe domains else: - if self.domain_type is 'material': + if self.domain_type == 'material': cv.check_iterable_type('domain', domains, openmc.Material) all_domains = self.openmc_geometry.get_all_materials() elif self.domain_type in ['cell', 'distribcell']: cv.check_iterable_type('domain', domains, openmc.Cell) all_domains = self.openmc_geometry.get_all_material_cells() - elif self.domain_type is 'universe': + elif self.domain_type == 'universe': cv.check_iterable_type('domain', domains, openmc.Universe) all_domains = self.openmc_geometry.get_all_universes() - elif self.domain_type is 'mesh': + elif self.domain_type == 'mesh': cv.check_iterable_type('domain', domains, openmc.Mesh) # The mesh and geometry are independent, so set all_domains @@ -355,7 +355,7 @@ class Library(object): def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) - if correction is 'P0' and self.legendre_order > 0: + if correction == 'P0' and self.legendre_order > 0: warn('The P0 correction will be ignored since the scattering ' 'order "{}" is greater than zero'.format(self.legendre_order)) @@ -367,7 +367,7 @@ class Library(object): cv.check_greater_than('legendre_order', legendre_order, 0, equality=True) cv.check_less_than('legendre_order', legendre_order, 10, equality=True) - if self.correction is 'P0' and legendre_order > 0: + if self.correction == 'P0' and legendre_order > 0: msg = 'The P0 correction will be ignored since the scattering ' \ 'order {} is greater than zero'.format(self.legendre_order) warn(msg, RuntimeWarning) @@ -505,7 +505,7 @@ class Library(object): self._openmc_geometry = statepoint.summary.openmc_geometry self._nuclides = statepoint.summary.nuclides - if statepoint.run_mode is 'k-eigenvalue': + if statepoint.run_mode == 'k-eigenvalue': self._keff = statepoint.k_combined[0] # Load tallies for each MGXS for each domain and mgxs type @@ -543,13 +543,13 @@ class Library(object): """ - if self.domain_type is 'material': + if self.domain_type == 'material': cv.check_type('domain', domain, (openmc.Material, Integral)) - elif self.domain_type is 'cell' or self.domain_type is 'distribcell': + elif self.domain_type == 'cell' or self.domain_type == 'distribcell': cv.check_type('domain', domain, (openmc.Cell, Integral)) - elif self.domain_type is 'universe': + elif self.domain_type == 'universe': cv.check_type('domain', domain, (openmc.Universe, Integral)) - elif self.domain_type is 'mesh': + elif self.domain_type == 'mesh': cv.check_type('domain', domain, (openmc.Mesh, Integral)) # Check that requested domain is included in library @@ -662,7 +662,7 @@ class Library(object): # Clone this Library to initialize the subdomain-averaged version subdomain_avg_library = copy.deepcopy(self) - if subdomain_avg_library.domain_type is 'distribcell': + if subdomain_avg_library.domain_type == 'distribcell': subdomain_avg_library.domain_type = 'cell' else: return subdomain_avg_library @@ -671,7 +671,7 @@ class Library(object): for domain in self.domains: for mgxs_type in self.mgxs_types: mgxs = subdomain_avg_library.get_mgxs(domain, mgxs_type) - if mgxs.domain_type is 'distribcell': + if mgxs.domain_type == 'distribcell': avg_mgxs = mgxs.get_subdomain_avg_xs() subdomain_avg_library.all_mgxs[domain.id][mgxs_type] = avg_mgxs @@ -751,7 +751,7 @@ class Library(object): for mgxs_type in self.mgxs_types: mgxs = self.all_mgxs[domain.id][mgxs_type] - if subdomains is 'avg': + if subdomains == 'avg': mgxs = mgxs.get_subdomain_avg_xs() mgxs.build_hdf5_store(filename, directory, xs_type=xs_type, @@ -896,7 +896,7 @@ class Library(object): # Build & add metadata to XSdata object name = xsdata_name - if nuclide is not 'total': + if nuclide != 'total': name += '_' + nuclide xsdata = openmc.XSdata(name, self.energy_groups) @@ -912,7 +912,7 @@ class Library(object): self.scatter_format = 'legendre' self.representation = 'isotropic' - if nuclide is not 'total': + if nuclide != 'total': xsdata.atomic_weight_ratio = self._nuclides[nuclide][1] if subdomain is None: @@ -921,7 +921,7 @@ class Library(object): subdomain = [subdomain] # Now get xs data itself - if 'nu-transport' in self.mgxs_types and self.correction is 'P0': + if 'nu-transport' in self.mgxs_types and self.correction == 'P0': mymgxs = self.get_mgxs(domain, 'nu-transport') xsdata.set_total_mgxs(mymgxs, xs_type=xs_type, nuclide=[nuclide], subdomain=subdomain) @@ -1056,7 +1056,7 @@ class Library(object): # Initialize file mgxs_file = openmc.MGXSLibrary(self.energy_groups) - if self.domain_type is 'mesh': + if self.domain_type == 'mesh': # Create the xsdata objects and add to the mgxs_file i = 0 for domain in self.domains: @@ -1089,7 +1089,7 @@ class Library(object): xsdata_name = 'set' + str(i + 1) else: xsdata_name = xsdata_names[i] - if nuclide is not 'total': + if nuclide != 'total': xsdata_name += '_' + nuclide xsdata = self.get_xsdata(domain, xsdata_name, @@ -1159,14 +1159,14 @@ class Library(object): # the multiple meshes could be overlapping or in disparate regions # of the continuous energy model. The next step makes sure there is # only one before continuing. - if self.domain_type is 'mesh': + if self.domain_type == 'mesh': cv.check_length("domains", self.domains, 1, 1) # Get the MGXS File Data mgxs_file = self.create_mg_library('macro', xsdata_names) # Now move on the creating the geometry and assigning materials - if self.domain_type is 'mesh': + if self.domain_type == 'mesh': root = openmc.Universe(name='root', universe_id=0) # Add cells representative of the mesh with reflective BC @@ -1212,13 +1212,13 @@ class Library(object): materials.append(material) # Differentiate Geometry with new Material - if self.domain_type is 'material': + if self.domain_type == 'material': # Fill all appropriate Cells with new Material for cell in all_cells: if cell.fill.id == domain.id: cell.fill = material - elif self.domain_type is 'cell': + elif self.domain_type == 'cell': for cell in all_cells: if cell.id == domain.id: cell.fill = material @@ -1283,7 +1283,7 @@ class Library(object): ('nu-transport' not in self.mgxs_types))): error_flag = True warn('A "nu-transport" MGXS type is required since a "P0" ' - 'correction is applied, but a "nu-transport" MGXS is ' + 'correction is applied, but a "nu-transport" MGXS == ' 'not provided.') elif (((self.correction is None) and ('total' not in self.mgxs_types))): diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index edddd0bfac..35dff1223a 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -8,7 +8,7 @@ import h5py import openmc import openmc.mgxs from openmc.checkvalue import check_type, check_value, check_greater_than, \ - check_less_than, check_iterable_type + check_iterable_type if sys.version_info[0] >= 3: basestring = str @@ -16,6 +16,7 @@ if sys.version_info[0] >= 3: # Supported incoming particle MGXS angular treatment representations _REPRESENTATIONS = ['isotropic', 'angle'] _SCATTER_TYPES = ['tabular', 'legendre', 'histogram'] +_SCATTER_SHAPES = ["[Order][G][G']"] class XSdata(object): @@ -51,6 +52,8 @@ class XSdata(object): Whether or not this is a fissionable data set. scatter_format : {'legendre', 'histogram', or 'tabular'} Angular distribution representation (legendre, histogram, or tabular) + scatter_shapes : {"[Order][G][G']"} + Dimensionality of the scattering and multiplicity matrices order : int Either the Legendre order, number of bins, or number of points used to describe the angular distribution associated with each group-to-group @@ -106,8 +109,8 @@ class XSdata(object): :attr:`XSdata.nu_fission` attribute instead. nu_fission : dict of numpy.ndarray Group-wise fission production cross section vector (i.e., if - :attr:`XSdata.chi` is provided), or is the group-wise fission production - matrix. + :attr:`XSdata.chi` is provided), or is the group-wise fission + production matrix. inverse_velocities : dict of numpy.ndarray Inverse of velocities, in units of sec/cm. @@ -142,6 +145,7 @@ class XSdata(object): self._atomic_weight_ratio = None self._fissionable = False self._scatter_format = 'legendre' + self._scatter_shape = "[Order][G][G']" self._order = None self._num_polar = None self._num_azimuthal = None @@ -184,6 +188,10 @@ class XSdata(object): def scatter_format(self): return self._scatter_format + @property + def scatter_shape(self): + return self._scatter_shape + @property def order(self): return self._order @@ -242,28 +250,28 @@ class XSdata(object): @property def vector_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups,) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups) @property def matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.energy_groups.num_groups, self.energy_groups.num_groups) @property def pn_matrix_shape(self): - if self.representation is 'isotropic': + if self.representation == 'isotropic': return (self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) - elif self.representation is 'angle': + elif self.representation == 'angle': return (self.num_polar, self.num_azimuthal, self.num_orders, self.energy_groups.num_groups, self.energy_groups.num_groups) @@ -309,6 +317,12 @@ class XSdata(object): check_value('scatter_format', scatter_format, _SCATTER_TYPES) self._scatter_format = scatter_format + @scatter_shape.setter + def scatter_shape(self, scatter_shape): + # check to see it is of a valid type and value + check_value('scatter_shape', scatter_shape, _SCATTER_SHAPES) + self._scatter_shape = scatter_shape + @order.setter def order(self, order): # Check type and value @@ -694,10 +708,10 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._total[i] = total.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -740,11 +754,11 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._absorption[i] = absorption.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -787,11 +801,11 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._fission[i] = fission.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -835,11 +849,11 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._nu_fission[i] = nu_fission.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -892,11 +906,11 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._kappa_fission[i] = k_fission.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -943,10 +957,10 @@ class XSdata(object): check_value('temperature', temperature, self.temperatures) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': self._chi[i] = chi.get_xs(nuclides=nuclide, xs_type=xs_type, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -994,7 +1008,7 @@ class XSdata(object): check_type('temperature', temperature, Real) check_value('temperature', temperature, self.temperatures) - if self.scatter_format is not 'legendre': + if self.scatter_format != 'legendre': msg = 'Anisotropic scattering representations other than ' \ 'Legendre expansions have not yet been implemented in ' \ 'openmc.mgxs.' @@ -1011,7 +1025,7 @@ class XSdata(object): [self.order]) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': # Get the scattering orders in the outermost dimension self._scatter_matrix[i] = np.zeros((self.num_orders, self.energy_groups.num_groups, @@ -1021,7 +1035,7 @@ class XSdata(object): scatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=moment, subdomains=subdomain) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) @@ -1089,7 +1103,7 @@ class XSdata(object): ['universe', 'cell', 'material', 'mesh']) i = np.where(self.temperatures == temperature)[0][0] - if self.representation is 'isotropic': + if self.representation == 'isotropic': nuscatt = nuscatter.get_xs(nuclides=nuclide, xs_type=xs_type, moment=0, subdomains=subdomain) @@ -1100,7 +1114,7 @@ class XSdata(object): xs_type=xs_type, moment=0, subdomains=subdomain) self._multiplicity_matrix[i] = np.divide(nuscatt, scatt) - elif self.representation is 'angle': + elif self.representation == 'angle': msg = 'Angular-Dependent MGXS have not yet been implemented' raise ValueError(msg) self._multiplicity_matrix[i] = \ @@ -1123,7 +1137,7 @@ class XSdata(object): if self.representation is not None: grp.attrs['representation'] = np.array(self.representation, dtype='S') - if self.representation is 'angle': + if self.representation == 'angle': if self.num_azimuthal is not None: grp.attrs['num_azimuthal'] = self.num_azimuthal if self.num_polar is not None: @@ -1131,6 +1145,9 @@ class XSdata(object): if self.scatter_format is not None: grp.attrs['scatter_format'] = np.array(self.scatter_format, dtype='S') + if self.scatter_shape is not None: + grp.attrs['scatter_shape'] = np.array(self.scatter_shape, + dtype='S') if self.order is not None: grp.attrs['order'] = self.order @@ -1170,7 +1187,7 @@ class XSdata(object): # Get the sparse scattering data to print to the library G = self.energy_groups.num_groups - if self.representation is 'isotropic': + if self.representation == 'isotropic': g_out_bounds = np.zeros((G, 2), dtype=np.int) for g_in in range(G): nz = np.nonzero(self._scatter_matrix[i][0, g_in, :]) @@ -1206,7 +1223,7 @@ class XSdata(object): scatt_grp.create_dataset("g_min", data=g_out_bounds[:, 0]) scatt_grp.create_dataset("g_max", data=g_out_bounds[:, 1]) - elif self.representation is 'angle': + elif self.representation == 'angle': Np = self.num_polar Na = self.num_azimuthal g_out_bounds = np.zeros((Np, Na, G, 2), dtype=np.int) diff --git a/scripts/openmc-update-mgxs b/scripts/openmc-update-mgxs index 6122ff6262..658be9fef7 100755 --- a/scripts/openmc-update-mgxs +++ b/scripts/openmc-update-mgxs @@ -47,14 +47,12 @@ def parse_args(): help='input XML file') parser.add_argument('-o', '--output', nargs='?', default='', help='output file, in HDF5 format') - parser.add_argument('-c', '--compression', type=int, - help='HDF5 Compression Level') args = vars(parser.parse_args()) - if args['output'] is '': + if args['output'] == '': filename = args['input'].name extension = filenameos.path.splitext() - if extension is '.xml': + if extension == '.xml': filename = filename[:filename.rfind('.')] + '.h5' args['output'] = filename @@ -75,7 +73,7 @@ def get_data(element, entry): return value -if __name__ is '__main__': +if __name__ == '__main__': args = parse_args() # Parse the XML data. @@ -117,7 +115,7 @@ if __name__ is '__main__': representation = get_data(xsdata_elem, 'representation') if representation is None: representation = 'isotropic' - if representation is 'angle': + if representation == 'angle': n_azi = int(get_data(xsdata_elem, 'num_azimuthal')) n_pol = int(get_data(xsdata_elem, 'num_polar')) @@ -146,14 +144,14 @@ if __name__ is '__main__': representation=representation)) if awr is not None: xsd[-1].atomic_weight_ratio = awr - if representation is 'angle': + if representation == 'angle': xsd[-1].num_azimuthal = n_azi xsd[-1].num_polar = n_pol xsd[-1].scatter_format = scatter_format xsd[-1].order = order names.append(name) - if scatter_format is 'legendre': + if scatter_format == 'legendre': order_dim = order + 1 else: order_dim = order diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index ddce50be38..cbdf470b02 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -338,6 +338,13 @@ module mgxs_header else this % scatter_format = ANGLE_LEGENDRE end if + if (attribute_exists(xs_id, "scatter_shape")) then + call read_attribute(temp_str, xs_id, "scatter_shape") + temp_str = trim(temp_str) + if (to_lower(temp_str) /= "[order][g][g']") then + call fatal_error("Invalid scatter_shape option!") + end if + end if if (attribute_exists(xs_id, "fissionable")) then call read_attribute(this % fissionable, xs_id, "fissionable") else diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 index 401fe02fc54bedac6d1b5443db23a923de30c5f0..3befba194015f15f271447424bd93c7163e81324 100644 GIT binary patch delta 7975 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 delta 7769 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 From c1dd7df7dd83ff973ccbb2d080b3f686a48fe823 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 15:15:50 -0400 Subject: [PATCH 75/82] Increased MG mode test coverage from 63% to 74%. --- src/mgxs_header.F90 | 2 +- src/tally.F90 | 2 + tests/input_set.py | 85 +- tests/test_mg_basic/inputs_true.dat | 2 +- tests/test_mg_basic/results_true.dat | 2 +- tests/test_mg_max_order/inputs_true.dat | 2 +- tests/test_mg_max_order/results_true.dat | 2 +- tests/test_mg_max_order/test_mg_max_order.py | 75 +- tests/test_mg_nuclide/inputs_true.dat | 2 +- tests/test_mg_nuclide/results_true.dat | 2 +- tests/test_mg_nuclide/test_mg_nuclide.py | 73 +- tests/test_mg_tallies/inputs_true.dat | 2 +- tests/test_mg_tallies/results_true.dat | 3604 ++++-------------- tests/test_mg_tallies/test_mg_tallies.py | 58 +- 14 files changed, 819 insertions(+), 3094 deletions(-) diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index cbdf470b02..e223238589 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -1865,7 +1865,7 @@ module mgxs_header integer :: iazi, ipol, t - t = this % index_temp + t = this % index_temp if (present(uvw)) then call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) diff --git a/src/tally.F90 b/src/tally.F90 index 24c1b94950..b12bc0a970 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -1149,6 +1149,8 @@ contains ! Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide > 0) then nucxs => nuclides_MG(i_nuclide) % obj + ! And since we haven't calculated this temperature index yet, do so now + call nucxs % find_temperature(p % sqrtkT) end if i = 0 diff --git a/tests/input_set.py b/tests/input_set.py index 62c4abd5eb..c62fc5914b 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -728,60 +728,59 @@ class AssemblyInputSet(object): class MGInputSet(InputSet): - def build_default_materials_and_geometry(self): + def build_default_materials_and_geometry(self, reps=None, as_macro=True): # Define materials needed for 1D/1G slab problem - uo2_data = openmc.Macroscopic('uo2_iso') - uo2 = openmc.Material(name='UO2', material_id=1) - uo2.set_density('macro', 1.0) - uo2.add_macroscopic(uo2_data) + mat_names = ['uo2', 'clad', 'lwtr'] + mgxs_reps = ['ang', 'ang_mu', 'iso', 'iso_mu'] - clad_data = openmc.Macroscopic('clad_ang_mu') - clad = openmc.Material(name='Clad', material_id=2) - clad.set_density('macro', 1.0) - clad.add_macroscopic(clad_data) + if reps is None: + reps = mgxs_reps - water_data = openmc.Macroscopic('lwtr_iso_mu') - water = openmc.Material(name='LWTR', material_id=3) - water.set_density('macro', 1.0) - water.add_macroscopic(water_data) + xs = [] + mats = [] + i = 0 + for mat in mat_names: + for rep in reps: + i += 1 + if as_macro: + xs.append(openmc.Macroscopic(mat + '_' + rep)) + mats.append(openmc.Material(name=str(i))) + mats[-1].set_density('macro', 1.) + mats[-1].add_macroscopic(xs[-1]) + else: + xs.append(openmc.Nuclide(mat + '_' + rep)) + mats.append(openmc.Material(name=str(i))) + mats[-1].set_density('atom/b-cm', 1.) + mats[-1].add_nuclide(xs[-1].name, 1.0, 'ao') # Define the materials file. - self.materials += (uo2, clad, water) + self.xs_data = xs + self.materials += mats # Define surfaces. - # Assembly/Problem Boundary - left = openmc.XPlane(x0=0.0, surface_id=200, - boundary_type='reflective') - right = openmc.XPlane(x0=10.0, surface_id=201, - boundary_type='reflective') - bottom = openmc.YPlane(y0=0.0, surface_id=300, - boundary_type='reflective') - top = openmc.YPlane(y0=10.0, surface_id=301, - boundary_type='reflective') + left = openmc.XPlane(x0=0.0, boundary_type='reflective') + right = openmc.XPlane(x0=10.0, boundary_type='reflective') + bottom = openmc.YPlane(y0=0.0, boundary_type='reflective') + top = openmc.YPlane(y0=10.0, boundary_type='reflective') + # for each material add a plane + planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')] + dz = 5. / float(len(mats)) + for i in range(len(mats) - 1): + planes.append(openmc.ZPlane(z0=dz * (i + 1))) + planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective')) - down = openmc.ZPlane(z0=0.0, surface_id=0, - boundary_type='reflective') - fuel_clad_intfc = openmc.ZPlane(z0=2.0, surface_id=1) - clad_lwtr_intfc = openmc.ZPlane(z0=2.4, surface_id=2) - up = openmc.ZPlane(z0=5.0, surface_id=3, - boundary_type='reflective') - - # Define cells - c1 = openmc.Cell(cell_id=1) - c1.region = +left & -right & +bottom & -top & +down & -fuel_clad_intfc - c1.fill = uo2 - c2 = openmc.Cell(cell_id=2) - c2.region = +left & -right & +bottom & -top & +fuel_clad_intfc & -clad_lwtr_intfc - c2.fill = clad - c3 = openmc.Cell(cell_id=3) - c3.region = +left & -right & +bottom & -top & +clad_lwtr_intfc & -up - c3.fill = water + # Define cells for each material + cells = [] + xy = +left & -right & +bottom & -top + for i, mat in enumerate(mats): + cells.append(openmc.Cell()) + cells[-1].region = xy & +planes[i] & -planes[i + 1] + cells[-1].fill = mat # Define root universe. root = openmc.Universe(universe_id=0, name='root universe') - - root.add_cells((c1, c2, c3)) + root.add_cells(cells) # Assign root universe to geometry self.geometry.root_universe = root @@ -791,7 +790,7 @@ class MGInputSet(InputSet): self.settings.inactive = 5 self.settings.particles = 100 self.settings.source = Source(space=Box([0.0, 0.0, 0.0], - [10.0, 10.0, 2.0])) + [10.0, 10.0, 5.])) self.settings.energy_mode = "multi-group" self.settings.cross_sections = "../1d_mgxs.h5" diff --git a/tests/test_mg_basic/inputs_true.dat b/tests/test_mg_basic/inputs_true.dat index e44aa66a5b..31673c1335 100644 --- a/tests/test_mg_basic/inputs_true.dat +++ b/tests/test_mg_basic/inputs_true.dat @@ -1 +1 @@ -002fff0d8ba33340c9039f7650ece41bd26324d2e5c2816acc232adb298ae9dbd0873c5e28520df33ebe5af4c58e2ad338547ca337b2b42f53d255bff1ae314b \ No newline at end of file +c657f05432d9668f56e671a463ba08aed47103a33072d3f893146ff24fce6711ec41ba49c7d14a70b076cccb9a526375a4d8c1241e64e8167b8e0e876ae6655c \ No newline at end of file diff --git a/tests/test_mg_basic/results_true.dat b/tests/test_mg_basic/results_true.dat index 7cdda73b5d..a367c60266 100644 --- a/tests/test_mg_basic/results_true.dat +++ b/tests/test_mg_basic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.047136E+00 2.765964E-02 +1.034509E+00 4.099331E-02 diff --git a/tests/test_mg_max_order/inputs_true.dat b/tests/test_mg_max_order/inputs_true.dat index 9b5d32ce6c..375a7fe215 100644 --- a/tests/test_mg_max_order/inputs_true.dat +++ b/tests/test_mg_max_order/inputs_true.dat @@ -1 +1 @@ -8752d3167989d876c6f29b4b1ca7eed4b91793d8579c92de85633fd90235c67d63ee76d49081006047e0078f6f86eb6e3420c1f8fe44564e7a1fb62e828587d0 \ No newline at end of file +b4adeb6b98d1d6310484c6623dde61ccfb02e0b8b9422c60d94cb65e556f3e2744c94cb3661a94aa365964acb463a6bd93cddf2dd954bfc36e316335b4a058f3 \ No newline at end of file diff --git a/tests/test_mg_max_order/results_true.dat b/tests/test_mg_max_order/results_true.dat index 4db04e0897..1fa95fb90a 100644 --- a/tests/test_mg_max_order/results_true.dat +++ b/tests/test_mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.102093E+00 4.962190E-02 +1.099449E+00 1.956787E-02 diff --git a/tests/test_mg_max_order/test_mg_max_order.py b/tests/test_mg_max_order/test_mg_max_order.py index da699316ca..8c7948a323 100644 --- a/tests/test_mg_max_order/test_mg_max_order.py +++ b/tests/test_mg_max_order/test_mg_max_order.py @@ -2,83 +2,26 @@ import os import sys + sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import PyAPITestHarness from input_set import MGInputSet -import openmc -class MGNuclideInputSet(MGInputSet): - def build_default_materials_and_geometry(self): - # Define materials needed for 1D/1G slab problem - uo2_data = openmc.Macroscopic('uo2_iso') - uo2 = openmc.Material(name='UO2', material_id=1) - uo2.set_density('macro', 1.0) - uo2.add_macroscopic(uo2_data) - - clad_data = openmc.Macroscopic('clad_iso') - clad = openmc.Material(name='Clad', material_id=2) - clad.set_density('macro', 1.0) - clad.add_macroscopic(clad_data) - - water_data = openmc.Macroscopic('lwtr_iso') - water = openmc.Material(name='LWTR', material_id=3) - water.set_density('macro', 1.0) - water.add_macroscopic(water_data) - - # Define the materials file. - self.materials += (uo2, clad, water) - - # Define surfaces. - - # Assembly/Problem Boundary - left = openmc.XPlane(x0=0.0, surface_id=200, - boundary_type='reflective') - right = openmc.XPlane(x0=10.0, surface_id=201, - boundary_type='reflective') - bottom = openmc.YPlane(y0=0.0, surface_id=300, - boundary_type='reflective') - top = openmc.YPlane(y0=10.0, surface_id=301, - boundary_type='reflective') - - down = openmc.ZPlane(z0=0.0, surface_id=0, - boundary_type='reflective') - fuel_clad_intfc = openmc.ZPlane(z0=2.0, surface_id=1) - clad_lwtr_intfc = openmc.ZPlane(z0=2.4, surface_id=2) - up = openmc.ZPlane(z0=5.0, surface_id=3, - boundary_type='reflective') - - # Define cells - c1 = openmc.Cell(cell_id=1) - c1.region = +left & -right & +bottom & -top & +down & -fuel_clad_intfc - c1.fill = uo2 - c2 = openmc.Cell(cell_id=2) - c2.region = +left & -right & +bottom & -top & +fuel_clad_intfc & -clad_lwtr_intfc - c2.fill = clad - c3 = openmc.Cell(cell_id=3) - c3.region = +left & -right & +bottom & -top & +clad_lwtr_intfc & -up - c3.fill = water - - # Define root universe. - root = openmc.Universe(universe_id=0, name='root universe') - - root.add_cells((c1,c2,c3)) - - # Define the geometry file. - geometry = openmc.Geometry() - geometry.root_universe = root - - self.geometry = geometry class MGMaxOrderTestHarness(PyAPITestHarness): def __init__(self, statepoint_name, tallies_present, mg=False): PyAPITestHarness.__init__(self, statepoint_name, tallies_present) - self._input_set = MGNuclideInputSet() + self._input_set = MGInputSet() def _build_inputs(self): + """Write input XML files.""" + reps = ['iso'] + self._input_set.build_default_materials_and_geometry(reps=reps) + self._input_set.build_default_settings() # Set P1 scattering self._input_set.settings.max_order = 1 - # Call standard input build - super(MGMaxOrderTestHarness, self)._build_inputs() + self._input_set.export() + if __name__ == '__main__': harness = MGMaxOrderTestHarness('statepoint.10.*', False, mg=True) diff --git a/tests/test_mg_nuclide/inputs_true.dat b/tests/test_mg_nuclide/inputs_true.dat index 93de08656d..5950ad3e49 100644 --- a/tests/test_mg_nuclide/inputs_true.dat +++ b/tests/test_mg_nuclide/inputs_true.dat @@ -1 +1 @@ -10b64fa97cc4feb1b1b8ba401b25b68ab682aba55ad4303a76a9a293ae79cdfff2f65d74310eb917da0aac243c24713d91eafae7ec5f0c4ae535d49fc928a869 \ No newline at end of file +130e51d00cd4c00be14b4e722c285ef5725f7f7a25361f48524dc51bb70c0869149adb839199915fe6193273cb957414c073be2a9fda3ed03754967571b73f68 \ No newline at end of file diff --git a/tests/test_mg_nuclide/results_true.dat b/tests/test_mg_nuclide/results_true.dat index 7cdda73b5d..a367c60266 100644 --- a/tests/test_mg_nuclide/results_true.dat +++ b/tests/test_mg_nuclide/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.047136E+00 2.765964E-02 +1.034509E+00 4.099331E-02 diff --git a/tests/test_mg_nuclide/test_mg_nuclide.py b/tests/test_mg_nuclide/test_mg_nuclide.py index 89694eea25..b94af258f2 100644 --- a/tests/test_mg_nuclide/test_mg_nuclide.py +++ b/tests/test_mg_nuclide/test_mg_nuclide.py @@ -2,81 +2,22 @@ import os import sys + sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import PyAPITestHarness from input_set import MGInputSet -import openmc -class MGNuclideInputSet(MGInputSet): - def build_default_materials_and_geometry(self): - # Define materials needed for 1D/1G slab problem - # This time do using nuclide, not macroscopic - uo2 = openmc.Material(name='UO2', material_id=1) - uo2.set_density('sum', 1.0) - uo2.add_nuclide("uo2_iso", 1.0) - - clad = openmc.Material(name='Clad', material_id=2) - clad.set_density('sum', 1.0) - clad.add_nuclide("clad_ang_mu", 1.0) - - # water_data = openmc.Nuclide('lwtr_iso_mu', '71c') - water = openmc.Material(name='LWTR', material_id=3) - water.set_density('sum', 1.0) - water.add_nuclide("lwtr_iso_mu", 1.0) - - # Define the materials file. - self.materials.default_xs = '71c' - self.materials += (uo2, clad, water) - - # Define surfaces. - - # Assembly/Problem Boundary - left = openmc.XPlane(x0=0.0, surface_id=200, - boundary_type='reflective') - right = openmc.XPlane(x0=10.0, surface_id=201, - boundary_type='reflective') - bottom = openmc.YPlane(y0=0.0, surface_id=300, - boundary_type='reflective') - top = openmc.YPlane(y0=10.0, surface_id=301, - boundary_type='reflective') - - down = openmc.ZPlane(z0=0.0, surface_id=0, - boundary_type='reflective') - fuel_clad_intfc = openmc.ZPlane(z0=2.0, surface_id=1) - clad_lwtr_intfc = openmc.ZPlane(z0=2.4, surface_id=2) - up = openmc.ZPlane(z0=5.0, surface_id=3, - boundary_type='reflective') - - # Define cells - c1 = openmc.Cell(cell_id=1) - c1.region = +left & -right & +bottom & -top & +down & -fuel_clad_intfc - c1.fill = uo2 - c2 = openmc.Cell(cell_id=2) - c2.region = +left & -right & +bottom & -top & +fuel_clad_intfc & -clad_lwtr_intfc - c2.fill = clad - c3 = openmc.Cell(cell_id=3) - c3.region = +left & -right & +bottom & -top & +clad_lwtr_intfc & -up - c3.fill = water - - # Define root universe. - root = openmc.Universe(universe_id=0, name='root universe') - - root.add_cells((c1,c2,c3)) - - # Define the geometry file. - geometry = openmc.Geometry() - geometry.root_universe = root - - self.geometry = geometry class MGNuclideTestHarness(PyAPITestHarness): def __init__(self, statepoint_name, tallies_present, mg=False): PyAPITestHarness.__init__(self, statepoint_name, tallies_present) - self._input_set = MGNuclideInputSet() + self._input_set = MGInputSet() def _build_inputs(self): - super(MGNuclideTestHarness, self)._build_inputs() - + """Write input XML files.""" + self._input_set.build_default_materials_and_geometry(as_macro=False) + self._input_set.build_default_settings() + self._input_set.export() if __name__ == '__main__': diff --git a/tests/test_mg_tallies/inputs_true.dat b/tests/test_mg_tallies/inputs_true.dat index ca92dcb099..6e1b5dd621 100644 --- a/tests/test_mg_tallies/inputs_true.dat +++ b/tests/test_mg_tallies/inputs_true.dat @@ -1 +1 @@ -615fe0688980afc02bc11f41ac065b9479d2f6618acf6d20fcb91cd78209aed1d8fbaf73b06f153368a16aa90249d6d3ce06f840d9071a40b2118d36178fd84f \ No newline at end of file +051fcc001b79dc016d74e339348e75d1dab0338f3246643fb0032a928dd3660574543e23a6f428ee3b1b174e7e5a9aa64b27a795fa42c80068d13e98cf42a294 \ No newline at end of file diff --git a/tests/test_mg_tallies/results_true.dat b/tests/test_mg_tallies/results_true.dat index cb0498e511..09a041c7d1 100644 --- a/tests/test_mg_tallies/results_true.dat +++ b/tests/test_mg_tallies/results_true.dat @@ -1,2906 +1,712 @@ k-combined: -1.047136E+00 2.765964E-02 +1.034509E+00 4.099331E-02 tally 1: -2.490837E+00 -1.335515E+00 -8.299408E-02 -1.628477E-03 -3.917892E+00 -3.395475E+00 -3.777816E-02 -3.574150E-04 -9.366009E-02 -2.196850E-03 -2.099094E+00 -8.919271E-01 -7.540489E-02 -1.194829E-03 -3.366752E+00 -2.321133E+00 -3.536709E-02 -2.711517E-04 -8.768256E-02 -1.666633E-03 -2.667561E+00 -1.528159E+00 -6.981409E-02 -1.036744E-03 -3.696781E+00 -2.912439E+00 -2.768232E-02 -1.628195E-04 -6.863038E-02 -1.000769E-03 -2.643152E+00 -1.461242E+00 -7.777503E-02 -1.277892E-03 -3.881716E+00 -3.158579E+00 -3.318888E-02 -2.353505E-04 -8.228231E-02 -1.446581E-03 -2.379478E+00 -1.220072E+00 -7.149541E-02 -1.036720E-03 -3.597267E+00 -2.694760E+00 -3.098378E-02 -1.953397E-04 -7.681538E-02 -1.200655E-03 -3.128432E+00 -2.123023E+00 -8.683081E-02 -1.593217E-03 -4.568791E+00 -4.439900E+00 -3.595477E-02 -2.733665E-04 -8.913952E-02 -1.680246E-03 -3.320603E+00 -2.324411E+00 -9.169756E-02 -1.769612E-03 -4.811447E+00 -4.885591E+00 -3.780490E-02 -3.050758E-04 -9.372640E-02 -1.875147E-03 -3.709821E+00 -2.847102E+00 -1.037249E-01 -2.264974E-03 -5.329369E+00 -5.878403E+00 -4.295875E-02 -3.964777E-04 -1.065039E-01 -2.436949E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.410307E+00 -1.211320E+00 -7.104710E-02 -1.056830E-03 -3.619111E+00 -2.712466E+00 -3.046789E-02 -2.019483E-04 -7.553639E-02 -1.241275E-03 -2.413065E+00 -1.186499E+00 -7.505466E-02 -1.154624E-03 -3.609948E+00 -2.664048E+00 -3.294274E-02 -2.242161E-04 -8.167207E-02 -1.378144E-03 -2.579691E+00 -1.399684E+00 -7.252523E-02 -1.085979E-03 -3.762646E+00 -2.966415E+00 -3.021298E-02 -1.872587E-04 -7.490441E-02 -1.150985E-03 -2.707136E+00 -1.528526E+00 -7.153411E-02 -1.046460E-03 -3.793295E+00 -2.976791E+00 -2.857458E-02 -1.671752E-04 -7.084247E-02 -1.027542E-03 -3.155079E+00 -2.066218E+00 -9.171950E-02 -1.711836E-03 -4.700403E+00 -4.503318E+00 -3.904100E-02 -3.167906E-04 -9.679096E-02 -1.947152E-03 -2.955891E+00 -1.796192E+00 -8.526700E-02 -1.464085E-03 -4.355866E+00 -3.839684E+00 -3.605221E-02 -2.663621E-04 -8.938111E-02 -1.637194E-03 -3.157638E+00 -2.088634E+00 -8.917486E-02 -1.627414E-03 -4.530493E+00 -4.262890E+00 -3.711278E-02 -2.791427E-04 -9.201048E-02 -1.715750E-03 -3.237824E+00 -2.159909E+00 -9.708289E-02 -1.898400E-03 -4.765807E+00 -4.617662E+00 -4.179332E-02 -3.503645E-04 -1.036145E-01 -2.153514E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.616860E+00 -1.407243E+00 -7.221083E-02 -1.059301E-03 -3.719840E+00 -2.827103E+00 -2.963219E-02 -1.775955E-04 -7.346451E-02 -1.091590E-03 -2.536174E+00 -1.301621E+00 -7.790327E-02 -1.242427E-03 -3.836384E+00 -2.980367E+00 -3.409705E-02 -2.443384E-04 -8.453386E-02 -1.501825E-03 -2.326398E+00 -1.111745E+00 -6.380790E-02 -8.422824E-04 -3.373074E+00 -2.338678E+00 -2.619114E-02 -1.463613E-04 -6.493342E-02 -8.996094E-04 -2.745209E+00 -1.561299E+00 -7.557988E-02 -1.164281E-03 -3.914803E+00 -3.154166E+00 -3.099509E-02 -1.948889E-04 -7.684344E-02 -1.197884E-03 -2.737388E+00 -1.515779E+00 -7.304714E-02 -1.077128E-03 -3.854064E+00 -2.996781E+00 -2.937470E-02 -1.746013E-04 -7.282614E-02 -1.073187E-03 -2.731962E+00 -1.617682E+00 -7.685258E-02 -1.239175E-03 -4.057901E+00 -3.505399E+00 -3.210546E-02 -2.150275E-04 -7.959627E-02 -1.321666E-03 -2.826797E+00 -1.654653E+00 -8.798649E-02 -1.562942E-03 -4.238099E+00 -3.671654E+00 -3.864939E-02 -3.007708E-04 -9.582007E-02 -1.848687E-03 -2.503072E+00 -1.321745E+00 -6.623202E-02 -9.120239E-04 -3.541728E+00 -2.623055E+00 -2.654018E-02 -1.469478E-04 -6.579875E-02 -9.032144E-04 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.383417E+00 -1.171863E+00 -6.968054E-02 -9.924374E-04 -3.486989E+00 -2.493855E+00 -2.962148E-02 -1.817051E-04 -7.343795E-02 -1.116850E-03 -2.666159E+00 -1.492268E+00 -7.417343E-02 -1.141120E-03 -3.912196E+00 -3.186439E+00 -3.075257E-02 -1.953163E-04 -7.624217E-02 -1.200511E-03 -2.689651E+00 -1.483190E+00 -8.007622E-02 -1.328579E-03 -4.015410E+00 -3.294872E+00 -3.443210E-02 -2.525628E-04 -8.536450E-02 -1.552377E-03 -3.141608E+00 -2.000672E+00 -8.238823E-02 -1.366316E-03 -4.442048E+00 -3.976219E+00 -3.282615E-02 -2.177028E-04 -8.138301E-02 -1.338110E-03 -3.294568E+00 -2.201280E+00 -8.370459E-02 -1.449531E-03 -4.567777E+00 -4.247816E+00 -3.258414E-02 -2.266289E-04 -8.078302E-02 -1.392974E-03 -3.058734E+00 -1.911285E+00 -8.780153E-02 -1.572171E-03 -4.531361E+00 -4.177302E+00 -3.703146E-02 -2.828466E-04 -9.180888E-02 -1.738516E-03 -2.639291E+00 -1.470166E+00 -8.380168E-02 -1.469150E-03 -3.995402E+00 -3.337545E+00 -3.720130E-02 -2.907469E-04 -9.222996E-02 -1.787075E-03 -2.360183E+00 -1.196310E+00 -7.336179E-02 -1.123869E-03 -3.552179E+00 -2.637131E+00 -3.222538E-02 -2.218615E-04 -7.989359E-02 -1.363671E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.177844E+00 -9.998272E-01 -6.808817E-02 -9.543925E-04 -3.302614E+00 -2.268097E+00 -3.001326E-02 -1.847730E-04 -7.440926E-02 -1.135706E-03 -2.459342E+00 -1.286534E+00 -6.409323E-02 -8.519553E-04 -3.511461E+00 -2.568245E+00 -2.550853E-02 -1.387171E-04 -6.324108E-02 -8.526242E-04 -2.712538E+00 -1.496273E+00 -7.040893E-02 -1.033599E-03 -3.801423E+00 -2.967673E+00 -2.785218E-02 -1.687241E-04 -6.905150E-02 -1.037062E-03 -3.078971E+00 -1.928690E+00 -8.927133E-02 -1.655293E-03 -4.508330E+00 -4.154031E+00 -3.778191E-02 -3.038622E-04 -9.366939E-02 -1.867688E-03 -3.040055E+00 -1.908677E+00 -8.543146E-02 -1.469528E-03 -4.395363E+00 -3.943052E+00 -3.551022E-02 -2.539139E-04 -8.803740E-02 -1.560681E-03 -2.854688E+00 -1.652859E+00 -8.501906E-02 -1.459424E-03 -4.215336E+00 -3.600073E+00 -3.650039E-02 -2.691434E-04 -9.049224E-02 -1.654289E-03 -2.563883E+00 -1.375196E+00 -8.901196E-02 -1.610331E-03 -4.042903E+00 -3.361278E+00 -4.116155E-02 -3.428545E-04 -1.020482E-01 -2.107354E-03 -2.353136E+00 -1.260383E+00 -7.514099E-02 -1.159881E-03 -3.611322E+00 -2.808437E+00 -3.349306E-02 -2.280172E-04 -8.303643E-02 -1.401507E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.585363E+00 -1.416531E+00 -7.208386E-02 -1.068367E-03 -3.721777E+00 -2.868016E+00 -2.981132E-02 -1.871051E-04 -7.390860E-02 -1.150041E-03 -3.227353E+00 -2.189454E+00 -8.161989E-02 -1.366996E-03 -4.465292E+00 -4.143037E+00 -3.169508E-02 -2.069605E-04 -7.857885E-02 -1.272082E-03 -3.101358E+00 -2.022582E+00 -8.316566E-02 -1.469875E-03 -4.433641E+00 -4.167950E+00 -3.363316E-02 -2.428472E-04 -8.338377E-02 -1.492660E-03 -3.342682E+00 -2.353374E+00 -9.542381E-02 -1.892530E-03 -4.916807E+00 -5.068483E+00 -4.010858E-02 -3.330650E-04 -9.943770E-02 -2.047183E-03 -2.733720E+00 -1.608810E+00 -7.575232E-02 -1.234497E-03 -3.955386E+00 -3.353987E+00 -3.126476E-02 -2.114507E-04 -7.751200E-02 -1.299681E-03 -2.532385E+00 -1.341692E+00 -7.908024E-02 -1.289149E-03 -3.816608E+00 -3.020090E+00 -3.480705E-02 -2.494950E-04 -8.629409E-02 -1.533520E-03 -2.651467E+00 -1.472579E+00 -7.547436E-02 -1.201468E-03 -3.877983E+00 -3.154531E+00 -3.166886E-02 -2.150564E-04 -7.851384E-02 -1.321843E-03 -2.404559E+00 -1.241962E+00 -6.952417E-02 -1.036673E-03 -3.551485E+00 -2.687553E+00 -2.947110E-02 -1.929942E-04 -7.306514E-02 -1.186238E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.740199E+00 -1.663131E+00 -8.719535E-02 -1.596752E-03 -4.146740E+00 -3.682203E+00 -3.870935E-02 -3.136109E-04 -9.596871E-02 -1.927608E-03 -3.006650E+00 -1.972749E+00 -8.846181E-02 -1.643195E-03 -4.449165E+00 -4.222523E+00 -3.779771E-02 -2.999515E-04 -9.370858E-02 -1.843651E-03 -2.669269E+00 -1.482479E+00 -7.250461E-02 -1.097959E-03 -3.815372E+00 -3.039000E+00 -2.952621E-02 -1.837209E-04 -7.320176E-02 -1.129240E-03 -2.906350E+00 -1.760817E+00 -8.559496E-02 -1.527401E-03 -4.338708E+00 -3.888336E+00 -3.663301E-02 -2.834528E-04 -9.082102E-02 -1.742242E-03 -2.633801E+00 -1.566751E+00 -7.851898E-02 -1.276803E-03 -3.867974E+00 -3.237952E+00 -3.370851E-02 -2.331450E-04 -8.357057E-02 -1.433025E-03 -2.946914E+00 -1.857842E+00 -7.586572E-02 -1.217999E-03 -4.089763E+00 -3.522165E+00 -2.980738E-02 -1.901498E-04 -7.389883E-02 -1.168755E-03 -2.884789E+00 -1.801722E+00 -7.517555E-02 -1.168857E-03 -4.085136E+00 -3.522983E+00 -2.985774E-02 -1.859368E-04 -7.402368E-02 -1.142860E-03 -2.740499E+00 -1.588007E+00 -7.592011E-02 -1.232446E-03 -3.959573E+00 -3.327411E+00 -3.134446E-02 -2.121705E-04 -7.770960E-02 -1.304106E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.212799E+00 -1.000035E+00 -7.449165E-02 -1.135538E-03 -3.466616E+00 -2.419923E+00 -3.399202E-02 -2.463541E-04 -8.427346E-02 -1.514215E-03 -2.591189E+00 -1.530310E+00 -7.305643E-02 -1.114250E-03 -3.732882E+00 -3.031120E+00 -3.039294E-02 -1.919600E-04 -7.535057E-02 -1.179882E-03 -2.719836E+00 -1.670890E+00 -8.176774E-02 -1.472662E-03 -4.030045E+00 -3.607044E+00 -3.530219E-02 -2.721266E-04 -8.752165E-02 -1.672625E-03 -2.201534E+00 -1.026489E+00 -7.361463E-02 -1.156634E-03 -3.444005E+00 -2.510736E+00 -3.352726E-02 -2.491193E-04 -8.312121E-02 -1.531211E-03 -2.649820E+00 -1.500516E+00 -6.849773E-02 -9.733415E-04 -3.744876E+00 -2.926356E+00 -2.706771E-02 -1.530408E-04 -6.710661E-02 -9.406650E-04 -2.788908E+00 -1.667764E+00 -7.477958E-02 -1.148212E-03 -4.029335E+00 -3.403340E+00 -3.033277E-02 -1.914118E-04 -7.520139E-02 -1.176512E-03 -2.810664E+00 -1.609682E+00 -6.917229E-02 -9.875658E-04 -3.854296E+00 -3.029615E+00 -2.634304E-02 -1.483398E-04 -6.531000E-02 -9.117703E-04 -2.647586E+00 -1.416013E+00 -7.421099E-02 -1.112815E-03 -3.826931E+00 -2.947306E+00 -3.083732E-02 -1.923794E-04 -7.645229E-02 -1.182459E-03 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 +1.353282E+01 +3.743930E+01 +1.143045E+00 +2.712580E-01 +3.307076E+01 +2.236038E+02 +6.526994E-01 +8.855821E-02 +1.648619E+00 +5.666321E-01 +1.383226E+01 +3.869052E+01 +1.052120E+00 +2.328236E-01 +3.370167E+01 +2.297761E+02 +6.050050E-01 +7.697403E-02 +1.750404E+00 +6.331758E-01 +1.318250E+01 +3.553429E+01 +1.062624E+00 +2.357887E-01 +3.213491E+01 +2.111574E+02 +6.132682E-01 +7.853526E-02 +1.383452E+00 +4.189022E-01 +1.092857E+01 +2.455197E+01 +4.110603E-01 +3.568350E-02 +3.208428E+01 +2.114259E+02 +2.256563E-01 +1.081356E-02 +4.632141E-01 +4.677570E-02 +9.784679E+00 +1.972964E+01 +4.012515E-02 +6.039914E-04 +3.181098E+01 +2.085498E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.927108E+00 +2.035984E+01 +1.000276E-02 +1.000553E-04 +3.229710E+01 +2.155043E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.610209E+01 +5.213849E+01 +1.305253E-01 +4.741512E-03 +3.129504E+01 +1.971406E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.036344E+01 +1.862702E+02 +4.715504E-01 +4.701859E-02 +3.127921E+01 +1.975072E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.325556E+01 +2.242288E+02 +3.406537E-01 +3.172189E-02 +3.424625E+01 +2.377838E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.437896E+01 +2.376465E+02 +3.508672E-01 +2.662723E-02 +3.547702E+01 +2.530698E+02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 tally 2: -3.995283E+01 -3.210141E+02 -3.996387E+01 -3.211916E+02 -6.783537E+00 -9.416330E+00 -6.783789E+00 -9.417032E+00 -1.239468E+02 -3.134204E+03 -1.239468E+02 -3.134204E+03 +1.368605E+01 +3.822585E+01 +1.165647E+00 +2.774076E-01 +3.332128E+01 +2.265711E+02 +6.732988E-01 +9.255825E-02 +1.668893E+00 +5.686505E-01 +1.351185E+01 +3.714397E+01 +1.145268E+00 +2.669523E-01 +3.292797E+01 +2.205691E+02 +6.612158E-01 +8.898397E-02 +1.639208E+00 +5.468718E-01 +1.338220E+01 +3.637873E+01 +1.131564E+00 +2.601061E-01 +3.262172E+01 +2.161754E+02 +6.530550E-01 +8.663476E-02 +1.619062E+00 +5.325002E-01 +1.124444E+01 +2.583638E+01 +4.143035E-01 +3.514380E-02 +3.293951E+01 +2.216808E+02 +2.172466E-01 +9.667606E-03 +5.386005E-01 +5.942191E-02 +1.039401E+01 +2.195361E+01 +5.776981E-02 +6.785830E-04 +3.380760E+01 +2.322412E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.968429E+00 +2.018883E+01 +5.522413E-02 +6.196056E-04 +3.243154E+01 +2.136942E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.599575E+01 +5.164848E+01 +1.369508E-01 +3.787900E-03 +3.062851E+01 +1.892971E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.984125E+01 +1.813760E+02 +3.150772E-01 +2.022590E-02 +3.078896E+01 +1.929299E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.239082E+01 +2.130115E+02 +3.421610E-01 +2.377195E-02 +3.338365E+01 +2.262151E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.394890E+01 +2.331951E+02 +3.584238E-01 +2.599332E-02 +3.503323E+01 +2.483295E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +tally 3: +1.127805E+01 +2.608571E+01 +1.002813E+00 +2.123979E-01 +2.754396E+01 +1.556374E+02 +5.744190E-01 +6.983035E-02 +1.301487E+00 +3.559715E-01 +1.027524E+01 +2.176770E+01 +1.027808E+01 +2.177975E+01 +1.147696E+01 +2.681957E+01 +8.617077E-01 +1.528009E-01 +2.799053E+01 +1.596017E+02 +4.924622E-01 +4.996879E-02 +1.463919E+00 +4.452955E-01 +1.061525E+01 +2.304844E+01 +1.061818E+01 +2.306116E+01 +1.112664E+01 +2.517898E+01 +9.122203E-01 +1.733772E-01 +2.712336E+01 +1.496225E+02 +5.264663E-01 +5.774755E-02 +1.333478E+00 +3.684793E-01 +1.021442E+01 +2.118539E+01 +1.021724E+01 +2.119710E+01 +1.090672E+01 +2.450876E+01 +8.720475E-01 +1.544308E-01 +2.658725E+01 +1.456398E+02 +5.032815E-01 +5.143697E-02 +1.146804E+00 +2.835726E-01 +1.003467E+01 +2.079465E+01 +1.003744E+01 +2.080615E+01 +8.331989E+00 +1.409000E+01 +3.010595E-02 +5.041231E-04 +2.708797E+01 +1.489409E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.301883E+00 +1.399250E+01 +8.302183E+00 +1.399351E+01 +8.140468E+00 +1.380373E+01 +3.007957E-02 +5.030779E-04 +2.646953E+01 +1.459652E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.110389E+00 +1.372142E+01 +8.110683E+00 +1.372241E+01 +8.082005E+00 +1.362698E+01 +1.000276E-02 +1.000553E-04 +2.629420E+01 +1.442386E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.072002E+00 +1.358172E+01 +8.072302E+00 +1.358273E+01 +8.452493E+00 +1.439819E+01 +3.016800E-02 +3.033748E-04 +2.749955E+01 +1.524016E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.422325E+00 +1.429746E+01 +8.422638E+00 +1.429853E+01 +2.414436E+01 +1.174474E+02 +2.911770E-01 +2.007223E-02 +2.492486E+01 +1.250988E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.385318E+01 +1.146286E+02 +2.385318E+01 +1.146286E+02 +2.670358E+01 +1.446298E+02 +4.109267E-01 +3.665787E-02 +2.742207E+01 +1.524808E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.629265E+01 +1.401748E+02 +2.629265E+01 +1.401748E+02 +2.805989E+01 +1.590823E+02 +2.605721E-01 +1.547273E-02 +2.895612E+01 +1.694067E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.779932E+01 +1.561607E+02 +2.779932E+01 +1.561607E+02 +2.858483E+01 +1.648682E+02 +3.007528E-01 +2.029929E-02 +2.949783E+01 +1.755681E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.828408E+01 +1.615023E+02 +2.828408E+01 +1.615023E+02 +tally 4: +1.127805E+01 +2.608571E+01 +9.413263E-01 +1.814958E-01 +2.754396E+01 +1.556374E+02 +5.422850E-01 +6.023145E-02 +1.344903E+00 +3.704722E-01 +1.147696E+01 +2.681957E+01 +9.663242E-01 +1.895497E-01 +2.799053E+01 +1.596017E+02 +5.573458E-01 +6.303283E-02 +1.381910E+00 +3.875298E-01 +1.112664E+01 +2.517898E+01 +9.408395E-01 +1.800284E-01 +2.712336E+01 +1.496225E+02 +5.429832E-01 +5.996291E-02 +1.346171E+00 +3.685618E-01 +1.090672E+01 +2.450876E+01 +9.222434E-01 +1.752364E-01 +2.658725E+01 +1.456398E+02 +5.322509E-01 +5.836681E-02 +1.319563E+00 +3.587514E-01 +8.331989E+00 +1.409000E+01 +4.665612E-02 +4.414425E-04 +2.708797E+01 +1.489409E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.140468E+00 +1.380373E+01 +4.513252E-02 +4.265760E-04 +2.646953E+01 +1.459652E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.082005E+00 +1.362698E+01 +4.477352E-02 +4.182191E-04 +2.629420E+01 +1.442386E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.452493E+00 +1.439819E+01 +4.682599E-02 +4.418878E-04 +2.749955E+01 +1.524016E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.414436E+01 +1.174474E+02 +2.549248E-01 +1.309686E-02 +2.492486E+01 +1.250988E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.670358E+01 +1.446298E+02 +2.827393E-01 +1.621660E-02 +2.742207E+01 +1.524808E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.805989E+01 +1.590823E+02 +2.962491E-01 +1.773226E-02 +2.895612E+01 +1.694067E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.858483E+01 +1.648682E+02 +3.017914E-01 +1.837719E-02 +2.949783E+01 +1.755681E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +tally 5: +1.140031E+01 +2.654804E+01 +9.714892E-01 +1.928147E-01 +2.775330E+01 +1.573327E+02 +5.611798E-01 +6.433919E-02 +1.390960E+00 +3.952699E-01 +1.042894E+01 +2.221679E+01 +1.141545E+01 +2.652638E+01 +9.688838E-01 +1.912040E-01 +2.781363E+01 +1.574484E+02 +5.594851E-01 +6.375914E-02 +1.386962E+00 +3.918154E-01 +1.129668E-01 +2.597945E-03 +1.104472E+01 +2.480364E+01 +9.339121E-01 +1.773447E-01 +2.692364E+01 +1.473920E+02 +5.389851E-01 +5.906905E-02 +1.336259E+00 +3.630677E-01 +1.011089E+01 +2.078670E+01 +1.117137E+01 +2.545891E+01 +9.446221E-01 +1.820299E-01 +2.723240E+01 +1.512859E+02 +5.451662E-01 +6.062956E-02 +1.351583E+00 +3.726594E-01 +1.105108E-01 +2.491359E-03 +8.516856E+00 +1.480571E+01 +4.746789E-02 +4.599371E-04 +2.769452E+01 +1.565558E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.469171E+00 +1.464039E+01 +8.669841E+00 +1.526679E+01 +4.817729E-02 +4.716776E-04 +2.820058E+01 +1.615173E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.126905E-01 +2.579568E-03 +8.322112E+00 +1.408773E+01 +4.610369E-02 +4.323598E-04 +2.707537E+01 +1.491155E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.275818E+00 +1.393144E+01 +8.001626E+00 +1.291919E+01 +4.432823E-02 +3.964967E-04 +2.603269E+01 +1.367468E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.037888E-01 +2.173599E-03 +2.420071E+01 +1.187334E+02 +2.553808E-01 +1.322410E-02 +2.499803E+01 +1.266325E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.394540E+01 +1.162412E+02 +2.599102E+01 +1.379786E+02 +2.747004E-01 +1.541805E-02 +2.675330E+01 +1.460654E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.544592E-02 +4.872035E-05 +2.723238E+01 +1.502761E+02 +2.875125E-01 +1.675068E-02 +2.810218E+01 +1.600291E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.694487E+01 +1.471198E+02 +2.839730E+01 +1.630916E+02 +2.998114E-01 +1.817916E-02 +2.930431E+01 +1.736763E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.688140E-02 +5.763608E-05 +tally 6: +1.027524E+01 +2.176770E+01 +1.027808E+01 +2.177975E+01 +1.301487E+00 +3.559715E-01 +1.061525E+01 +2.304844E+01 +1.061818E+01 +2.306116E+01 +1.463919E+00 +4.452955E-01 +1.021442E+01 +2.118539E+01 +1.021724E+01 +2.119710E+01 +1.333478E+00 +3.684793E-01 +1.003467E+01 +2.079465E+01 +1.003744E+01 +2.080615E+01 +1.146804E+00 +2.835726E-01 +8.301883E+00 +1.399250E+01 +8.302183E+00 +1.399351E+01 +0.000000E+00 +0.000000E+00 +8.110389E+00 +1.372142E+01 +8.110683E+00 +1.372241E+01 +0.000000E+00 +0.000000E+00 +8.072002E+00 +1.358172E+01 +8.072302E+00 +1.358273E+01 +0.000000E+00 +0.000000E+00 +8.422325E+00 +1.429746E+01 +8.422638E+00 +1.429853E+01 +0.000000E+00 +0.000000E+00 +2.385318E+01 +1.146286E+02 +2.385318E+01 +1.146286E+02 +0.000000E+00 +0.000000E+00 +2.629265E+01 +1.401748E+02 +2.629265E+01 +1.401748E+02 +0.000000E+00 +0.000000E+00 +2.779932E+01 +1.561607E+02 +2.779932E+01 +1.561607E+02 +0.000000E+00 +0.000000E+00 +2.828408E+01 +1.615023E+02 +2.828408E+01 +1.615023E+02 +0.000000E+00 +0.000000E+00 diff --git a/tests/test_mg_tallies/test_mg_tallies.py b/tests/test_mg_tallies/test_mg_tallies.py index c9c5e95be2..4e57120bd8 100644 --- a/tests/test_mg_tallies/test_mg_tallies.py +++ b/tests/test_mg_tallies/test_mg_tallies.py @@ -9,32 +9,66 @@ import openmc class MGTalliesTestHarness(PyAPITestHarness): def _build_inputs(self): + """Write input XML files.""" + self._input_set.build_default_materials_and_geometry(as_macro=True) + self._input_set.build_default_settings() + # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) mesh.type = 'regular' - mesh.dimension = [17, 17, 1] + mesh.dimension = [1, 1, 10] mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [21.42, 21.42, 100.0] + mesh.upper_right = [10, 10, 5] # Instantiate some tally filters energy_filter = openmc.EnergyFilter([0.0, 20.0]) energyout_filter = openmc.EnergyoutFilter([0.0, 20.0]) mesh_filter = openmc.MeshFilter(mesh) - mat_filter = openmc.MaterialFilter([1,2,3]) + mat_ids = [mat.id for mat in self._input_set.materials] + mat_filter = openmc.MaterialFilter(mat_ids) - tally1 = openmc.Tally(tally_id=1) - tally1.filters = [mesh_filter] - tally1.scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission'] + tallies = [] - tally2 = openmc.Tally(tally_id=2) - tally2.filters = [mat_filter, energy_filter, energyout_filter] - tally2.scores = ['scatter', 'nu-scatter'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = ['total', 'absorption', 'flux', + 'fission', 'nu-fission'] - self._input_set.tallies = openmc.Tallies([tally1, tally2]) + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = ['total', 'absorption', 'flux', + 'fission', 'nu-fission'] - super(MGTalliesTestHarness, self)._build_inputs() + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = ['total', 'absorption', 'flux', + 'fission', 'nu-fission', 'scatter', + 'nu-scatter'] + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'collision' + tallies[-1].scores = ['total', 'absorption', 'flux', + 'fission', 'nu-fission'] + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = ['total', 'absorption', 'flux', + 'fission', 'nu-fission', 'scatter'] + + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter, + energyout_filter] + tallies[-1].scores = ['scatter', 'nu-scatter', 'nu-fission'] + + self._input_set.tallies = openmc.Tallies(tallies) + + self._input_set.export() def _cleanup(self): super(MGTalliesTestHarness, self)._cleanup() From ea0e706b7081709fbeb51d80119e7459c165795b Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 16:15:17 -0400 Subject: [PATCH 76/82] Ok, fixed the extra whitespace (havent gotten my sublime settings all set since I got the new computer, and, as a bonus, I added nuclidic tallies to the test_mg_tallies test, including a few bugfixes along the way --- src/input_xml.F90 | 2 +- src/mgxs_header.F90 | 16 +- src/output.F90 | 9 +- src/state_point.F90 | 17 +- src/tally.F90 | 27 +- tests/input_set.py | 2 +- tests/test_mg_tallies/inputs_true.dat | 2 +- tests/test_mg_tallies/results_true.dat | 713 +---------------------- tests/test_mg_tallies/test_mg_tallies.py | 80 +-- 9 files changed, 98 insertions(+), 770 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 2719aa68fe..e8b950d917 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3301,7 +3301,7 @@ contains ! Search through nuclides pair_list => nuclide_dict % keys() do while (associated(pair_list)) - if (starts_with(pair_list % key, word)) then + if (trim(pair_list % key) == trim(word)) then word = pair_list % key(1:150) exit end if diff --git a/src/mgxs_header.F90 b/src/mgxs_header.F90 index e223238589..feb4d46a89 100644 --- a/src/mgxs_header.F90 +++ b/src/mgxs_header.F90 @@ -437,9 +437,9 @@ module mgxs_header ! Get temperature as a string temp_str = trim(to_str(temps_to_read % data(t))) // "K" xsdata_grp = open_group(xs_id, trim(temp_str)) + allocate(xs % nu_fission(groups)) + allocate(xs % chi(groups, groups)) if (this % fissionable) then - allocate(xs % nu_fission(groups)) - allocate(xs % chi(groups, groups)) if (object_exists(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi @@ -505,6 +505,9 @@ module mgxs_header &kappa-fission tallies in tallies.xml file!") end if end if + else + xs % nu_fission = ZERO + xs % chi = ZERO end if if (object_exists(xsdata_grp, "absorption")) then @@ -735,9 +738,9 @@ module mgxs_header ! Get temperature as a string temp_str = trim(to_str(temps_to_read % data(t))) // "K" xsdata_grp = open_group(xs_id, trim(temp_str)) + allocate(xs % nu_fission(groups, this % n_azi, this % n_pol)) + allocate(xs % chi(groups, groups, this % n_azi, this % n_pol)) if (this % fissionable) then - allocate(xs % nu_fission(groups, this % n_azi, this % n_pol)) - allocate(xs % chi(groups, groups, this % n_azi, this % n_pol)) if (object_exists(xsdata_grp, "chi")) then ! Chi was provided, that means we need chi and nu-fission vectors ! Get chi @@ -848,6 +851,9 @@ module mgxs_header &kappa-fission tallies in tallies.xml file!") end if end if + else + xs % nu_fission = ZERO + xs % chi = ZERO end if if (object_exists(xsdata_grp, "absorption")) then @@ -1865,7 +1871,7 @@ module mgxs_header integer :: iazi, ipol, t - t = this % index_temp + t = this % index_temp if (present(uvw)) then call find_angle(this % polar, this % azimuthal, uvw, iazi, ipol) diff --git a/src/output.F90 b/src/output.F90 index 03496decbc..8127725a68 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -856,8 +856,13 @@ contains write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & "Total Material" else - write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & - trim(nuclides(i_nuclide) % name) + if (run_CE) then + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + trim(nuclides(i_nuclide) % name) + else + write(UNIT=unit_tally, FMT='(1X,2A,1X,A)') repeat(" ", indent), & + trim(nuclides_MG(i_nuclide) % obj % name) + end if end if indent = indent + 2 diff --git a/src/state_point.F90 b/src/state_point.F90 index 39532652f1..6b7a467d4f 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -251,11 +251,20 @@ contains allocate(str_array(tally % n_nuclide_bins)) NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins if (tally % nuclide_bins(j) > 0) then - i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.') - if (i_xs > 0) then - str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1) + if (run_CE) then + i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.') + if (i_xs > 0) then + str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1) + else + str_array(j) = nuclides(tally % nuclide_bins(j)) % name + end if else - str_array(j) = nuclides(tally % nuclide_bins(j)) % name + i_xs = index(nuclides_MG(tally % nuclide_bins(j)) % obj % name, '.') + if (i_xs > 0) then + str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name(1 : i_xs-1) + else + str_array(j) = nuclides_MG(tally % nuclide_bins(j)) % obj % name + end if end if else str_array(j) = 'total' diff --git a/src/tally.F90 b/src/tally.F90 index b12bc0a970..e1c5769d1d 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -1865,17 +1865,24 @@ contains i_nuclide = t % nuclide_bins(k) - ! Check to see if this nuclide was in the material of our collision. - do m = 1, mat % n_nuclides - if (mat % nuclide(m) == i_nuclide) then - atom_density = mat % atom_density(m) - exit - end if - end do + if (i_nuclide > 0) then + atom_density = -ONE + ! Check to see if this nuclide was in the material of our collision. + do m = 1, mat % n_nuclides + if (mat % nuclide(m) == i_nuclide) then + atom_density = mat % atom_density(m) + exit + end if + end do + else + atom_density = ZERO + end if - ! Determine score for each bin - call score_general(p, t, (k-1)*t % n_score_bins, filter_index, & - i_nuclide, atom_density, filter_weight) + ! If we found the nuclide, determine the score for each bin + if (atom_density >= ZERO) then + call score_general(p, t, (k-1)*t % n_score_bins, filter_index, & + i_nuclide, atom_density, filter_weight) + end if end do NUCLIDE_LOOP diff --git a/tests/input_set.py b/tests/input_set.py index c62fc5914b..e349272144 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -753,7 +753,7 @@ class MGInputSet(InputSet): mats[-1].set_density('atom/b-cm', 1.) mats[-1].add_nuclide(xs[-1].name, 1.0, 'ao') - # Define the materials file. + # Define the materials file self.xs_data = xs self.materials += mats diff --git a/tests/test_mg_tallies/inputs_true.dat b/tests/test_mg_tallies/inputs_true.dat index 6e1b5dd621..4b1863929d 100644 --- a/tests/test_mg_tallies/inputs_true.dat +++ b/tests/test_mg_tallies/inputs_true.dat @@ -1 +1 @@ -051fcc001b79dc016d74e339348e75d1dab0338f3246643fb0032a928dd3660574543e23a6f428ee3b1b174e7e5a9aa64b27a795fa42c80068d13e98cf42a294 \ No newline at end of file +255e71d921bb67f7f4832d1b217f4d19ea3c6bd96f551f1676e3735bd314986cc5f2be064e98c8f938a3f93c28b94487567d28829b4c0d66f8d2f8f5a776f302 \ No newline at end of file diff --git a/tests/test_mg_tallies/results_true.dat b/tests/test_mg_tallies/results_true.dat index 09a041c7d1..67e6cf4056 100644 --- a/tests/test_mg_tallies/results_true.dat +++ b/tests/test_mg_tallies/results_true.dat @@ -1,712 +1 @@ -k-combined: -1.034509E+00 4.099331E-02 -tally 1: -1.353282E+01 -3.743930E+01 -1.143045E+00 -2.712580E-01 -3.307076E+01 -2.236038E+02 -6.526994E-01 -8.855821E-02 -1.648619E+00 -5.666321E-01 -1.383226E+01 -3.869052E+01 -1.052120E+00 -2.328236E-01 -3.370167E+01 -2.297761E+02 -6.050050E-01 -7.697403E-02 -1.750404E+00 -6.331758E-01 -1.318250E+01 -3.553429E+01 -1.062624E+00 -2.357887E-01 -3.213491E+01 -2.111574E+02 -6.132682E-01 -7.853526E-02 -1.383452E+00 -4.189022E-01 -1.092857E+01 -2.455197E+01 -4.110603E-01 -3.568350E-02 -3.208428E+01 -2.114259E+02 -2.256563E-01 -1.081356E-02 -4.632141E-01 -4.677570E-02 -9.784679E+00 -1.972964E+01 -4.012515E-02 -6.039914E-04 -3.181098E+01 -2.085498E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.927108E+00 -2.035984E+01 -1.000276E-02 -1.000553E-04 -3.229710E+01 -2.155043E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.610209E+01 -5.213849E+01 -1.305253E-01 -4.741512E-03 -3.129504E+01 -1.971406E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.036344E+01 -1.862702E+02 -4.715504E-01 -4.701859E-02 -3.127921E+01 -1.975072E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.325556E+01 -2.242288E+02 -3.406537E-01 -3.172189E-02 -3.424625E+01 -2.377838E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.437896E+01 -2.376465E+02 -3.508672E-01 -2.662723E-02 -3.547702E+01 -2.530698E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -tally 2: -1.368605E+01 -3.822585E+01 -1.165647E+00 -2.774076E-01 -3.332128E+01 -2.265711E+02 -6.732988E-01 -9.255825E-02 -1.668893E+00 -5.686505E-01 -1.351185E+01 -3.714397E+01 -1.145268E+00 -2.669523E-01 -3.292797E+01 -2.205691E+02 -6.612158E-01 -8.898397E-02 -1.639208E+00 -5.468718E-01 -1.338220E+01 -3.637873E+01 -1.131564E+00 -2.601061E-01 -3.262172E+01 -2.161754E+02 -6.530550E-01 -8.663476E-02 -1.619062E+00 -5.325002E-01 -1.124444E+01 -2.583638E+01 -4.143035E-01 -3.514380E-02 -3.293951E+01 -2.216808E+02 -2.172466E-01 -9.667606E-03 -5.386005E-01 -5.942191E-02 -1.039401E+01 -2.195361E+01 -5.776981E-02 -6.785830E-04 -3.380760E+01 -2.322412E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -9.968429E+00 -2.018883E+01 -5.522413E-02 -6.196056E-04 -3.243154E+01 -2.136942E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.599575E+01 -5.164848E+01 -1.369508E-01 -3.787900E-03 -3.062851E+01 -1.892971E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.984125E+01 -1.813760E+02 -3.150772E-01 -2.022590E-02 -3.078896E+01 -1.929299E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.239082E+01 -2.130115E+02 -3.421610E-01 -2.377195E-02 -3.338365E+01 -2.262151E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -3.394890E+01 -2.331951E+02 -3.584238E-01 -2.599332E-02 -3.503323E+01 -2.483295E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -tally 3: -1.127805E+01 -2.608571E+01 -1.002813E+00 -2.123979E-01 -2.754396E+01 -1.556374E+02 -5.744190E-01 -6.983035E-02 -1.301487E+00 -3.559715E-01 -1.027524E+01 -2.176770E+01 -1.027808E+01 -2.177975E+01 -1.147696E+01 -2.681957E+01 -8.617077E-01 -1.528009E-01 -2.799053E+01 -1.596017E+02 -4.924622E-01 -4.996879E-02 -1.463919E+00 -4.452955E-01 -1.061525E+01 -2.304844E+01 -1.061818E+01 -2.306116E+01 -1.112664E+01 -2.517898E+01 -9.122203E-01 -1.733772E-01 -2.712336E+01 -1.496225E+02 -5.264663E-01 -5.774755E-02 -1.333478E+00 -3.684793E-01 -1.021442E+01 -2.118539E+01 -1.021724E+01 -2.119710E+01 -1.090672E+01 -2.450876E+01 -8.720475E-01 -1.544308E-01 -2.658725E+01 -1.456398E+02 -5.032815E-01 -5.143697E-02 -1.146804E+00 -2.835726E-01 -1.003467E+01 -2.079465E+01 -1.003744E+01 -2.080615E+01 -8.331989E+00 -1.409000E+01 -3.010595E-02 -5.041231E-04 -2.708797E+01 -1.489409E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.301883E+00 -1.399250E+01 -8.302183E+00 -1.399351E+01 -8.140468E+00 -1.380373E+01 -3.007957E-02 -5.030779E-04 -2.646953E+01 -1.459652E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.110389E+00 -1.372142E+01 -8.110683E+00 -1.372241E+01 -8.082005E+00 -1.362698E+01 -1.000276E-02 -1.000553E-04 -2.629420E+01 -1.442386E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.072002E+00 -1.358172E+01 -8.072302E+00 -1.358273E+01 -8.452493E+00 -1.439819E+01 -3.016800E-02 -3.033748E-04 -2.749955E+01 -1.524016E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.422325E+00 -1.429746E+01 -8.422638E+00 -1.429853E+01 -2.414436E+01 -1.174474E+02 -2.911770E-01 -2.007223E-02 -2.492486E+01 -1.250988E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.385318E+01 -1.146286E+02 -2.385318E+01 -1.146286E+02 -2.670358E+01 -1.446298E+02 -4.109267E-01 -3.665787E-02 -2.742207E+01 -1.524808E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.629265E+01 -1.401748E+02 -2.629265E+01 -1.401748E+02 -2.805989E+01 -1.590823E+02 -2.605721E-01 -1.547273E-02 -2.895612E+01 -1.694067E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.779932E+01 -1.561607E+02 -2.779932E+01 -1.561607E+02 -2.858483E+01 -1.648682E+02 -3.007528E-01 -2.029929E-02 -2.949783E+01 -1.755681E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.828408E+01 -1.615023E+02 -2.828408E+01 -1.615023E+02 -tally 4: -1.127805E+01 -2.608571E+01 -9.413263E-01 -1.814958E-01 -2.754396E+01 -1.556374E+02 -5.422850E-01 -6.023145E-02 -1.344903E+00 -3.704722E-01 -1.147696E+01 -2.681957E+01 -9.663242E-01 -1.895497E-01 -2.799053E+01 -1.596017E+02 -5.573458E-01 -6.303283E-02 -1.381910E+00 -3.875298E-01 -1.112664E+01 -2.517898E+01 -9.408395E-01 -1.800284E-01 -2.712336E+01 -1.496225E+02 -5.429832E-01 -5.996291E-02 -1.346171E+00 -3.685618E-01 -1.090672E+01 -2.450876E+01 -9.222434E-01 -1.752364E-01 -2.658725E+01 -1.456398E+02 -5.322509E-01 -5.836681E-02 -1.319563E+00 -3.587514E-01 -8.331989E+00 -1.409000E+01 -4.665612E-02 -4.414425E-04 -2.708797E+01 -1.489409E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.140468E+00 -1.380373E+01 -4.513252E-02 -4.265760E-04 -2.646953E+01 -1.459652E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.082005E+00 -1.362698E+01 -4.477352E-02 -4.182191E-04 -2.629420E+01 -1.442386E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.452493E+00 -1.439819E+01 -4.682599E-02 -4.418878E-04 -2.749955E+01 -1.524016E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.414436E+01 -1.174474E+02 -2.549248E-01 -1.309686E-02 -2.492486E+01 -1.250988E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.670358E+01 -1.446298E+02 -2.827393E-01 -1.621660E-02 -2.742207E+01 -1.524808E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.805989E+01 -1.590823E+02 -2.962491E-01 -1.773226E-02 -2.895612E+01 -1.694067E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.858483E+01 -1.648682E+02 -3.017914E-01 -1.837719E-02 -2.949783E+01 -1.755681E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -tally 5: -1.140031E+01 -2.654804E+01 -9.714892E-01 -1.928147E-01 -2.775330E+01 -1.573327E+02 -5.611798E-01 -6.433919E-02 -1.390960E+00 -3.952699E-01 -1.042894E+01 -2.221679E+01 -1.141545E+01 -2.652638E+01 -9.688838E-01 -1.912040E-01 -2.781363E+01 -1.574484E+02 -5.594851E-01 -6.375914E-02 -1.386962E+00 -3.918154E-01 -1.129668E-01 -2.597945E-03 -1.104472E+01 -2.480364E+01 -9.339121E-01 -1.773447E-01 -2.692364E+01 -1.473920E+02 -5.389851E-01 -5.906905E-02 -1.336259E+00 -3.630677E-01 -1.011089E+01 -2.078670E+01 -1.117137E+01 -2.545891E+01 -9.446221E-01 -1.820299E-01 -2.723240E+01 -1.512859E+02 -5.451662E-01 -6.062956E-02 -1.351583E+00 -3.726594E-01 -1.105108E-01 -2.491359E-03 -8.516856E+00 -1.480571E+01 -4.746789E-02 -4.599371E-04 -2.769452E+01 -1.565558E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.469171E+00 -1.464039E+01 -8.669841E+00 -1.526679E+01 -4.817729E-02 -4.716776E-04 -2.820058E+01 -1.615173E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.126905E-01 -2.579568E-03 -8.322112E+00 -1.408773E+01 -4.610369E-02 -4.323598E-04 -2.707537E+01 -1.491155E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -8.275818E+00 -1.393144E+01 -8.001626E+00 -1.291919E+01 -4.432823E-02 -3.964967E-04 -2.603269E+01 -1.367468E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.037888E-01 -2.173599E-03 -2.420071E+01 -1.187334E+02 -2.553808E-01 -1.322410E-02 -2.499803E+01 -1.266325E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.394540E+01 -1.162412E+02 -2.599102E+01 -1.379786E+02 -2.747004E-01 -1.541805E-02 -2.675330E+01 -1.460654E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.544592E-02 -4.872035E-05 -2.723238E+01 -1.502761E+02 -2.875125E-01 -1.675068E-02 -2.810218E+01 -1.600291E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.694487E+01 -1.471198E+02 -2.839730E+01 -1.630916E+02 -2.998114E-01 -1.817916E-02 -2.930431E+01 -1.736763E+02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -1.688140E-02 -5.763608E-05 -tally 6: -1.027524E+01 -2.176770E+01 -1.027808E+01 -2.177975E+01 -1.301487E+00 -3.559715E-01 -1.061525E+01 -2.304844E+01 -1.061818E+01 -2.306116E+01 -1.463919E+00 -4.452955E-01 -1.021442E+01 -2.118539E+01 -1.021724E+01 -2.119710E+01 -1.333478E+00 -3.684793E-01 -1.003467E+01 -2.079465E+01 -1.003744E+01 -2.080615E+01 -1.146804E+00 -2.835726E-01 -8.301883E+00 -1.399250E+01 -8.302183E+00 -1.399351E+01 -0.000000E+00 -0.000000E+00 -8.110389E+00 -1.372142E+01 -8.110683E+00 -1.372241E+01 -0.000000E+00 -0.000000E+00 -8.072002E+00 -1.358172E+01 -8.072302E+00 -1.358273E+01 -0.000000E+00 -0.000000E+00 -8.422325E+00 -1.429746E+01 -8.422638E+00 -1.429853E+01 -0.000000E+00 -0.000000E+00 -2.385318E+01 -1.146286E+02 -2.385318E+01 -1.146286E+02 -0.000000E+00 -0.000000E+00 -2.629265E+01 -1.401748E+02 -2.629265E+01 -1.401748E+02 -0.000000E+00 -0.000000E+00 -2.779932E+01 -1.561607E+02 -2.779932E+01 -1.561607E+02 -0.000000E+00 -0.000000E+00 -2.828408E+01 -1.615023E+02 -2.828408E+01 -1.615023E+02 -0.000000E+00 -0.000000E+00 +a78b7997b258f01764aebf601ae7107d7286d79269c1adcaa3c5b58d4f78f7b330cda152f415ad7c9b0622c3dc2b60284bfca74febfd35369c2772a87b9c4d44 \ No newline at end of file diff --git a/tests/test_mg_tallies/test_mg_tallies.py b/tests/test_mg_tallies/test_mg_tallies.py index 4e57120bd8..b9bbcb5542 100644 --- a/tests/test_mg_tallies/test_mg_tallies.py +++ b/tests/test_mg_tallies/test_mg_tallies.py @@ -3,14 +3,14 @@ import os import sys sys.path.insert(0, os.pardir) -from testing_harness import TestHarness, PyAPITestHarness +from testing_harness import HashedPyAPITestHarness import openmc -class MGTalliesTestHarness(PyAPITestHarness): +class MGTalliesTestHarness(HashedPyAPITestHarness): def _build_inputs(self): """Write input XML files.""" - self._input_set.build_default_materials_and_geometry(as_macro=True) + self._input_set.build_default_materials_and_geometry(as_macro=False) self._input_set.build_default_settings() # Instantiate a tally mesh @@ -28,43 +28,55 @@ class MGTalliesTestHarness(PyAPITestHarness): mat_ids = [mat.id for mat in self._input_set.materials] mat_filter = openmc.MaterialFilter(mat_ids) + nuclides = [xs.name for xs in self._input_set.xs_data] + + scores= {False: ['total', 'absorption', 'flux', 'fission', 'nu-fission'], + True: ['total', 'absorption', 'fission', 'nu-fission']} + tallies = [] + for do_nuclides in [False, True]: + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides - tallies.append(openmc.Tally()) - tallies[-1].filters = [mesh_filter] - tallies[-1].estimator = 'analog' - tallies[-1].scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mesh_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides - tallies.append(openmc.Tally()) - tallies[-1].filters = [mesh_filter] - tallies[-1].estimator = 'tracklength' - tallies[-1].scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'analog' + tallies[-1].scores = scores[do_nuclides] + ['scatter', + 'nu-scatter'] + if do_nuclides: + tallies[-1].nuclides = nuclides - tallies.append(openmc.Tally()) - tallies[-1].filters = [mat_filter, energy_filter] - tallies[-1].estimator = 'analog' - tallies[-1].scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission', 'scatter', - 'nu-scatter'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'collision' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides - tallies.append(openmc.Tally()) - tallies[-1].filters = [mat_filter, energy_filter] - tallies[-1].estimator = 'collision' - tallies[-1].scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter] + tallies[-1].estimator = 'tracklength' + tallies[-1].scores = scores[do_nuclides] + if do_nuclides: + tallies[-1].nuclides = nuclides - tallies.append(openmc.Tally()) - tallies[-1].filters = [mat_filter, energy_filter] - tallies[-1].estimator = 'tracklength' - tallies[-1].scores = ['total', 'absorption', 'flux', - 'fission', 'nu-fission', 'scatter'] - - tallies.append(openmc.Tally()) - tallies[-1].filters = [mat_filter, energy_filter, - energyout_filter] - tallies[-1].scores = ['scatter', 'nu-scatter', 'nu-fission'] + tallies.append(openmc.Tally()) + tallies[-1].filters = [mat_filter, energy_filter, + energyout_filter] + tallies[-1].scores = ['scatter', 'nu-scatter', 'nu-fission'] + if do_nuclides: + tallies[-1].nuclides = nuclides self._input_set.tallies = openmc.Tallies(tallies) From 6ae0b1b0e668d4c94e4605b3e29dbe8cfcd61c29 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 16:23:10 -0400 Subject: [PATCH 77/82] Grr --- src/tally.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tally.F90 b/src/tally.F90 index e1c5769d1d..978f26d7ba 100644 --- a/src/tally.F90 +++ b/src/tally.F90 @@ -1867,7 +1867,7 @@ contains if (i_nuclide > 0) then atom_density = -ONE - ! Check to see if this nuclide was in the material of our collision. + ! Check to see if this nuclide was in the material of our collision do m = 1, mat % n_nuclides if (mat % nuclide(m) == i_nuclide) then atom_density = mat % atom_density(m) From fa6a3686605464238be29e6c90318f81af924946 Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 16:38:00 -0400 Subject: [PATCH 78/82] Updating example mgxs.h5 file --- examples/xml/pincell_multigroup/mgxs.h5 | Bin 16496 -> 61488 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/xml/pincell_multigroup/mgxs.h5 b/examples/xml/pincell_multigroup/mgxs.h5 index cbe338c1c7de692a9bed69901f1da186bc1d3348..fe93c44bfa6b3766155356e34bdcd31e9fdb6af0 100644 GIT binary patch literal 61488 zcmeHQ30zItAHS6)Wyv=4Y~$I}L?J5b{-SlPAw-s!iXxR)Df>%|$5;~Ykb-Ym<0MH+}6G76eveP!!)L&}gDDllnWp88);KU|KM?= zriMyFWs^E6YNPAi`-|W2H7^v7O+BJLoBqT7fiSN0A>G5W?X&!Tt>N$ef20qaY7eOT zJWPu*HDZJ$EyV(2qQ*$^*>Q^n5a5Q%8@IfMs6ZmOcrB_>O-Fz|Zpl0#!1kQ9f2IR7 zc$lZRsnHM-CF90I6e!0tdiV${kq%qnyoOomg_P@v!+|*{UKjI)1dH><<8an86mN+6 z5<|rK93xRUa2KK`h){-!=;dR*I2@RS;>qX>X)VsDtB1mN`iK(T44GL{^n5H2hXZX< zJQop)=Z;;qB!- z)zhu4JPu=*MP-WYAu3ywvKcsZv`AcsQDczQOaiHw(1w%=F1HC&swTyE^WnSsx_S9I z`!U5+RC9*0!N277@b&iNd;55}l+{Wx_LbOWl;79I+0W07KV_OXf0nZ!$}eg=sn64G zx|^3P-|bVqjmzpK`F!1-eMBu1)!X=A`J6`ZUETPToNSqY-6s9J-g;&8fww4`;g>ca zFiH3!JxjvkRE?2TBrD+}{gEO9fq4qG5tV0$4~>x;Siy?H|$4NUYz4kFD?J6h~>ZsZsTi&BB0)<~Gqo@X=r_ zgy>zG|5%sd7p1GKtCwZb#QYj+@glRvJOp_ZYWA=4M~139QjFiKNKbIT!Tmk-oamP) z^jm5rUxYm^mxe8ClL-sMIb9E*&V|Vzwjbl2x(`ifZt_`Ok^zGcIOWe8oDGkD+?cqv zNj^Al^Ya|;EdafGyI;Ka^#Y^Q20h1kL_loRQQhae;vsb0V@}Aa?XbydLZcP)e}jx2 z@9mnlN{9UmUADQdTnK&Cn+vXF4Tc{wtdIQcH4k2mo3%SiJroQad5b2Qt%tuFd0jj| zFb=GB9^bDMb%o`36aQO2HBGp;Q#UmqiU#>^vzd?s*}=hE=bQ9{m>c?3tM!X%X?^lI zbwJ>jl^dYP^%(V#2p$-`+|p%0%Mdv9`#Q7!9rr=<2iv?N!zgIhSAXX>xtHLn`NoXx z>3I;CsZr2jbRtYl=@h^2=w3(&+0}j1FAwN$p3v&Sxts9B$HimQ$q8_MbUS{ZJ9nVz zw9czyUb(@Nwi^sH-rj)@yN9*Ea&-=zj(K)%vL_b|ms}jWYjPTxoPK+CJ+%zX!xP-} zVGQt>4|6S0PlKPkw0p$sw+>tly4>*>1i=EUp({GiO9P_Uj2lt*;AK#mZy<`mZVI!z zfF9yb5L+JmjpI)v)C_YV>BoKJF89uX+&)=vmYXkzfE!2JmHavs4)h+>v)i};2rB;j z{VDG-_mGsQLQEq)YW7sUXPOp{l%y@%&W5*?+Ui#>k z|I1u@M2L<5(|28@>Qg}42QEF+5w0xtj5BXN61GK-c(CZ!L3-G_kvG3zSYnR5L4wSs z&P9#i6b!z6@1lp^^I>DFm5%E>-lBJ&(=Hn4&6QdoUBA=*v2nZM-NE$k!y+OebC-s( zzU}|$wGk$L9amUL%{O+=F1I#|*FzW6i^Zo3S3u!(BZI`ONA&7beJxvR8A#2iKEN{1 zwPiL0pWQaWV_h0d?=#mRAhHMSzP{O_SleG}z6OO`es{i`1KQL7I(9KN9m3;boc6B< zaC@+i&B~Q?q~>Ffvyrh~oex}oKxbTg?_m~eEHU14ABLpme$b=kjl0)%l7`35kQ{eT zqh3sIz08`f?D0p&8=I1GO2!+TlJWPjQ7CV7-(;}a5j%YFv`jGTSe&N6z2R`t=JtiHqVCc*GJkWXGX$= zpbkGfnV*4YrcV|=n3)VdvAgPJ80G_SyvHc5lld@)Q+oH8#{#(W-MH)?@nfJ<8;ht> z5CoT#ZrwV0GZLOgA8&HbF$7lD>mI0;a1%7u-Zj%RxmE7*SI@<2SL)G3m|H(EJ;`k^ zbe_AvpH}vLddnZ)g@?8K(V5pS+&#o@=(=$#dly1_6@O^&YIT7!J35a8e%a>dip#>$`FK5p)M zdQ}IIU9A6cz0GMSTLRJ=JFaX#lC1lkY(8C_Y|>sfp9M~K>>!)Z9w)oA_D9)zL+nl> z=968j{M4$`t5T)VtE$7punFoNqM0b9XydHv@Nie*!KlEe{i;Y69%6W8DFq&A6jPL+ zx1X~o6L6mD>&^E;XF8%Ze11gDboTLa?mKy9metGuUy)12gr7ZX<^z`-$^q{AdQ zPy`v*F|7WS!mjku^7Kk_9i>yIyX^CA>E}%0Sf5P9u#(g#fmnKV1u7qpRHed0-h4=v z-L_+&B34)Lsp_q21laQ-v9s=Y--gIj(f7Q_eHiwADb@X?>b;-j-V^n>5IZ*V><7A? ztFj+toYXeTwjX$Mq@uC@5IidTeo~|ns)?*8Q*gMjABrb_p#|1&!pGKkB5!S>lKv7x zir`cJb%-Wj$`IrcqLO~2P@$k^pHJGA{S|^jiKrC9NIN%Tk4t&;iw|CQh-;BjK%f$` z0uW%&FT^fs8jBbHwfmFu_a)i)Hj!ss@#m8|*iOn@Uk8dexQau_F4p^aJ{fN+TL3Oj zPU$b3PZuX=4Uo-8&?z*N&1Z*`OYzM%qA%penuP^oAohgE(j(cW|MyhM`L?q3%1$Zt zs_O6%sPJIa_tSY?yprO9EQT7o4$u4*CwipO^82sF7#|@qA!QXw`mgR-f~q0X{3^D6 zljm2Z3`Fu0J6JW+t7=gc1lWER8dVgWN|N=#gd0P+@?zfZK3ND_-6<2v3#EV{-9zTS`c+H)`tR!QQCA}A&GNuUrIS3Vy0 zN`}Yh@23{qqV6L1Q{~N@hC>lQ8D9#~*(xEb3<37MN$hbr)*~WFWu2EfTB91scLP-C zWz~CL7XAb3kNC2$Ux>buAp3hr!r_QtWk1MBsa=$9KgfAm7S@ydH%7V?GbPDR+)`E*`Z=s=MF zJmuo((lMV;C$YNtMROd9`8*}N6dcFTr;}Ja{G#iOUWmTfhLg8Qaq5wsQmLX-SMcy6zjaK zz81`+Yid^du_IS$ciO ziM!e+Og{+g7KG%#eYhKPE;${Zevty>L1zUsGHs>G*|+d*=(E)k@Z49)Iz)*SfGSZcn6x+}A-=G=!j?&d$8_s@dvK{nBU>@WhKg00`|8@5ntKI2V? z78yrA0L|vS`X?6N2J=m04x9EghBIM{tabzlq~_CY^5}(zS2E~(9*tkWDidx7-_`C` zCl8`t_N|lb_5l1HY&(a1lLyZ;Hr;DH_XP|t%(!8(t_UdWHvI&%f}!Qqhiwv@`oegl zZQB~I*##Yq&owIjI}w})(S_LuFT-xN-|9AN@d$ce7~^)YWdR(2BQQRg6a;-WIzHOH zbpp6O*`8|CU>US-r1$HA_q$=K+0|&v_)uu=`P5AB!!7uu$H6u)*W51m_hG^tM=vrM zy#_Xpy>v+5d>N#_)hXChc%R;X=z>ei?Cw%=xj@g@7o0H-It)HFX~MfH(Ap-V@adbA zbi@6LZ<=(|keV;5-8;QzXV$?_?>vi6-xk7@K0~95-aMqOb~{{1PwpW#U*G%7IZqzO z0H~Ya>2_cr+%55bHLyejG}A1s62=deny<^A8*%IQM#73>?Ydqg!=UMf(6zJozot9Z zY4>2(%K=jJjlL?}JIVARyt>|es=31*c$0LZUb_dzknwcG=Juu1^`*z6HwF9bAH(=> z{yIL&ArBr;ONvWaF#vdB79({+f~D5ic=_I-_L+&Wpg3o5qvd;H+?XOA8}od6lIGK2 z_YChx$Jfc*F{(=@^or@D*Ye#2*xaLSRPxxabn1K;O=`_um>=~j&D_Qn7X03KLgSLV zP&lGZ<`auK@GL2_<99q=Fd1@*-)wL?baeUW$1S~spq198Atw5k^qQ#lb617AfT2#E zl+@T85V`mJEE}^GaBxnvTJEGJutfdk!wi?I|4vWmen$MX4vFyXBZFg|&ZR@|{$`W) zdZj}|mzKjv{+$Lr9&=)^OwWXwLd(r3Tjj&n8Qz60&c1@^tg~Y+&sso&e;3b$d(C0R zYMvnVHzP3iblQ;39Swn|{e~{eoC(%<{--fFZ3&dLviG*R76yY}hn+vX-iVG5>5%VK z*OYE?wBY2A!jP9o=^w1P@0*{0N+&rP?{0M_jDB`)am$~3 zoua*Nces7XERznm+!_wWF;L()eyAsX7zDkyX-2Q>4Q&R!DrhB)r?2xgx7XJjOCK)D z@jQ6`IxNn0*prlX0D65$9v#UugbsfV*YMIWq4##1vnZm;B|6>V^wn_Nt+bYVN6)}{ z$xydfYMepj3E+S0ypr#+0CbLp&DwWpBs3f6V)@MrJ;<9kdB9ZqIP^^)HFrSL1sK$| zm8tgpEzpj)_3&MNKgd+`-5C?A0Z$sP`t9I~1h6ew2b{pmka#WsLXysAc>c#leqNK| zFxGaBUp2*9b+Okb?LLmQ_+wrH(?xoE z^xHc-M0#4^$;aS>VLHtFJ2wjcN`ob%8hszY=;(|X+dtXKef4N-V{((RtP_2AC?34_T&)=8f z&P3hyrT1lc-iV)!FNNrAl@L{i0DImf_BaLqe-=cL%DOMZ{{J&n_hqX0zD$bfBT~#$ zDEgQV^T_kN<7Xp2mHj|C)V5!?{UG;cH1WJb@TlzjG8Fo6jy`_(Nf(Fh{KfS%66-fP zM`PWP(rm@5=~2`#pT_=?(?|qq=38)S7*5QGqsntT+e_zg#BMui!sXJG;xVkvm zWS(q3f{xvM*?e|5*>M4SA^IY~;mAcOp4gK_mLAD2{lBM5&bOShLM#5hOrcWfRn_6a zbwa&IGzofh%DP>gA>^=LuOt3^uT!{ek7AVRmNFqrr zf{bgKGk_y^`4iNE=T>r!FEBO-(9#0@vH2I_;{%; zA-4S>=Vc~Xe+UkheO_j`2GvCN#~g7uFa*UD{Y=IBP59XQPUNjERMM|PND+L>e_kf6 z5$9!DKh+jZsMvN&+t*=_OL_APwI0bu#&5++sVYs;5g_wR3>K7!X?Qq#k)~&Mn^C%Z z1mXMqdZ~C9N+;_j6cYV^TUGTvX5GoCPI>F_Kq6YTP_(b}>Hmwh3zaPfX-(iJ*?e4_ z?6^TTpDs>z-zb~U0w)W@Wb@hMHck|)9`MP=eIs18dGk?3* zoY|mgP?nBzc=&qz@x6UK$e)ilqzuLK6aQeEH=p@0+bC1#_)^kZTzo%P9v)Kd@_6wYJYqbqVnvAa6jTx*$;$6ZTn^04;>6Z7S5<-gLQ~q^GNR2q342-TVnozOr zly+{!9+&dwm&n6NE;4>AR!UWAijDw#elf%Xn_#<6@e;eHOEOBK zl6Db!#ufi}SE)QCg1q&0pcF}~CYtQmkompvi0pc~IJq<)y%5~F2`FswE23mvhp_q+ zXRmRj>h!8K27#y8dPTlV`8afw<+I%8u=Shv%^$}YL4)<_$+zB(f@RldK5xc+mvYqX z9(x)w-=(x_5o(-xH4G~2yNzr5_djeiCm9xOhglB$PC(a2opXz4F94Sg_Xf8)HWF;R zmu7W(qX!W$5?^jKI1Wo5=br15d;v=Ck6*G%um#5I23YC!@`GPSTy2}UUIVn!d#&OL zCBNJF@OoCZu<>v>)$acBJnNhAbAw$)8X?!AbheT0SmwKpOPfv0`A`ktZ9KoHL6^I{ z^HA4GyAH=I2S#rx5TrfGhd(FIy71v>J~%&0?RfiL0o>XN*{01(V7pfQ<9B`PS_~KRBgtJT>6T6qvm|QX^<-0JwJ^)F~@|4VVk87rocn z4c`V_dy{-23S6&F8j@1~6nM25KT|i(77pq?T@usa25oobw=J)3&7(JQJ4GfnO@~nt zCJFa;CPJrQc*Ff?S%Jeto!P#64KV*bdi9IA$p2l8p+jyP>^R8z9n^2$JQ{cUDx4oU zXoG?KI*3?&AaU`2H<;7x7psg#7GRsD)?xRs6Y%}8!2?f(<-qcpam!EH$3Xv$4XH7A zgkTc#FnaxoX0Y>2YA2f;XW^d)J;&bU)L03jRG$h-Cjd4wF1|y_bX$&2GKi9dlek+k_(lg-zx43+^rzQ6Zp0Kn4QR)`@ICQQkT+kQIlvL0kM?fD+el4|;tSsu*xzlb`ER#;@7ChJU+Pa2iy&y(|fLd(COW*CcP zC=?S#(a-g{XT-#n2yk$W&S{Axu?RA*<5~SF##Dm>^7M-B2Wn6{WxA`w0EMu!C_|$z z6B6mPy1IIqYJa+)$T^DOlD9q-Ahv4$t$aM}l?)Fl_wAEVM+vYYlQ(Y~CL?|_zN)#K zRn=E90_=H{*yC`lM?{=TJO58aH3Z`NROkQIeExqP^+)_gMCI8J;U&bUvL6VC+V;z~ zALM)>3+oTTqteg+FQb}>|6Yp2oNFka=%)|XZ^9SO(sv?nZK0BW6+(*OQ~vczc+EKf zPpK`MP_gZlwy(n;m-6P9$m>WhGJY#oN>yo!jsSapA^S2W*sc@#mG}H#_=W3E(e70B zJrd{tH)PAg#mS|q=!MKD+%y!n$Uu~g>kw9d;_Nk!NY1xt#Z~e5N)nYqucXZrY(0@T zPo&%w*QXk%II0H8M1Va{=wfajwlgHN^6vka;_+Nano>p;e*gcLn79%FvfrfhyF`*$ z1eqt|S^X)-RD%LvKTmw^{(s&v1eb{zYLfaS5KFJFK;`4XIgZ+<7Z3w*9j0$H)DDtUm;gO5gv_M>UashEg2nJVNnAKYg%%6TWbkz7u(C3zhV%5K;u6 z^6&pg){OoCyxO7(728f}`#S7#DQ|v>EI@LR@msM{s!CII1laS-$Nhh7*NObfyZ>+h zh3n2h($s3968ry;WsAYZ$)$zph0G`1Cn#+33{f(!LsVs0L`GbD3W@Bg>J6%$&1e>xG5=Sb3&GAg-W zs~GbH7fZ=~DJHH&09ikZ(kYTi5{n@7L_DiM#h7YP;Opm!uigLW#UZ#%#88veCxKXc Nbp4lDM>DknI=KPzbtwru+L}doEA_XhXtU#1xlowV+y9q{M z?C?T}L=Eaff`!L}6h*ecz)K|v=?A8gsaNZVvI1+z^UZCxn|;sAyZ3$G=Xo|3&q)MP zn8g83th$XMprIg!jq0|JlgHsh?=f)Xd_h_;t9Kv{+7DJDM)Iq#<8rJrsFV+DQoa$v zDu?o5obXj!D?CX+teOIrdWmXanX*AE-A{*TrDqgg(UoXWTA_X()BVlEY}*BsdQ-uf^?MTkV%}TO zcPB9P{f+l1tmtn@k^COyQo6dDrykN3ANeV-rYl!%?0@GyF|rh#U0m?~Ieqc<`uKvE z|1@KJ|7*$nRuaeWBWY%W%@JY=;PW&vS){`~+eNVnL4-EaoBY9Qti)ln_(+4nXQCQ> zzxoQQj)xtB+6>yrZYWYe?><;5Oiy)SO&qAR! za9K(r;-=6t%$rMf^<*f;Bs*LjK}M_cNNLCs%o9o}t%ERYIV8kb2uFL-)AUZCIk-_u z{8z$kK2)0-g&JwY{FYi$9$k7Rc+_@0Tp@YNim)+A7!abW%jf(90~ana5a13AF$w}U z1|qi7Lgu`Gz%MtYPT&Qx1I8+P@o+v^?1TVk5936otWCmB;kaFXF)b7hl?&n$7!Gt} z#*n5PW>;}%297vJaiC6Wtt!HpbHY{4Svk_WjG*HO6PxKiC4?9}?UGjMWV^9W&UA}m zXSU96f;$_PdP-;Cmj6=PYeD>xys8jxjUGV;Q0tkDXs1$_bf(?)Q;2bL?sVxL8^Xq$ zB-3J&(O@GqL~9TOd~^hQS)1Yz^EixIw=7FCGF9$9*>rh=gL|{-&NRyMg`<6N%|TKq zTP<%-|72r3wNJ4%LMAA4R2jBDAIDSywB5~cjQ6G-^EDI4lDVFBmjd(oH+a~3oG8e4 JjV;W?p?}8JPhS84 From aaf9b401691e647c29c9c58a34046254a3e30e7c Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Sat, 15 Oct 2016 19:46:18 -0400 Subject: [PATCH 79/82] fixing the python2 test error --- tests/input_set.py | 7 ++++--- tests/test_mg_basic/inputs_true.dat | 2 +- tests/test_mg_basic/results_true.dat | 2 +- tests/test_mg_max_order/inputs_true.dat | 2 +- tests/test_mg_max_order/results_true.dat | 2 +- tests/test_mg_nuclide/inputs_true.dat | 2 +- tests/test_mg_nuclide/results_true.dat | 2 +- tests/test_mg_tallies/inputs_true.dat | 2 +- tests/test_mg_tallies/results_true.dat | 2 +- 9 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/input_set.py b/tests/input_set.py index e349272144..0d5a78bab9 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -1,8 +1,9 @@ +import numpy as np + import openmc from openmc.source import Source from openmc.stats import Box -import numpy as np class InputSet(object): def __init__(self): @@ -765,9 +766,9 @@ class MGInputSet(InputSet): top = openmc.YPlane(y0=10.0, boundary_type='reflective') # for each material add a plane planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')] - dz = 5. / float(len(mats)) + dz = round(5. / float(len(mats)), 4) for i in range(len(mats) - 1): - planes.append(openmc.ZPlane(z0=dz * (i + 1))) + planes.append(openmc.ZPlane(z0=dz * float(i + 1))) planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective')) # Define cells for each material diff --git a/tests/test_mg_basic/inputs_true.dat b/tests/test_mg_basic/inputs_true.dat index 31673c1335..08917ab7db 100644 --- a/tests/test_mg_basic/inputs_true.dat +++ b/tests/test_mg_basic/inputs_true.dat @@ -1 +1 @@ -c657f05432d9668f56e671a463ba08aed47103a33072d3f893146ff24fce6711ec41ba49c7d14a70b076cccb9a526375a4d8c1241e64e8167b8e0e876ae6655c \ No newline at end of file +115218221500e60ea43145875324a9a6800366fcc97357ef4cd8182f9253e114cbe1c7481dd3bdd8d7dce5983e2cb757ae0a2e05ede236d94cba7909703ba7f7 \ No newline at end of file diff --git a/tests/test_mg_basic/results_true.dat b/tests/test_mg_basic/results_true.dat index a367c60266..01b7925469 100644 --- a/tests/test_mg_basic/results_true.dat +++ b/tests/test_mg_basic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.034509E+00 4.099331E-02 +1.160653E+00 6.227102E-02 diff --git a/tests/test_mg_max_order/inputs_true.dat b/tests/test_mg_max_order/inputs_true.dat index 375a7fe215..3056e8cbdf 100644 --- a/tests/test_mg_max_order/inputs_true.dat +++ b/tests/test_mg_max_order/inputs_true.dat @@ -1 +1 @@ -b4adeb6b98d1d6310484c6623dde61ccfb02e0b8b9422c60d94cb65e556f3e2744c94cb3661a94aa365964acb463a6bd93cddf2dd954bfc36e316335b4a058f3 \ No newline at end of file +139d760cd83eab001ed3fd52d7146fb5f30b7021b26ada6a1e425f5446185ac6fa61ac2ac58aa9e895981e10540160b7ae7428c833024679ef1ca762715e2d51 \ No newline at end of file diff --git a/tests/test_mg_max_order/results_true.dat b/tests/test_mg_max_order/results_true.dat index 1fa95fb90a..0e470e2cdb 100644 --- a/tests/test_mg_max_order/results_true.dat +++ b/tests/test_mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.099449E+00 1.956787E-02 +1.098323E+00 1.979833E-02 diff --git a/tests/test_mg_nuclide/inputs_true.dat b/tests/test_mg_nuclide/inputs_true.dat index 5950ad3e49..57aa5d33f0 100644 --- a/tests/test_mg_nuclide/inputs_true.dat +++ b/tests/test_mg_nuclide/inputs_true.dat @@ -1 +1 @@ -130e51d00cd4c00be14b4e722c285ef5725f7f7a25361f48524dc51bb70c0869149adb839199915fe6193273cb957414c073be2a9fda3ed03754967571b73f68 \ No newline at end of file +6d03b988671fe21dfe2a908685536edb3059e5bdda7974ddfa65c7f63cecb7f6b3fce49bc1533ef2787e284121779653cb14a66cfd709258e4b07d8bd7571843 \ No newline at end of file diff --git a/tests/test_mg_nuclide/results_true.dat b/tests/test_mg_nuclide/results_true.dat index a367c60266..01b7925469 100644 --- a/tests/test_mg_nuclide/results_true.dat +++ b/tests/test_mg_nuclide/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.034509E+00 4.099331E-02 +1.160653E+00 6.227102E-02 diff --git a/tests/test_mg_tallies/inputs_true.dat b/tests/test_mg_tallies/inputs_true.dat index 4b1863929d..6b0ff76b15 100644 --- a/tests/test_mg_tallies/inputs_true.dat +++ b/tests/test_mg_tallies/inputs_true.dat @@ -1 +1 @@ -255e71d921bb67f7f4832d1b217f4d19ea3c6bd96f551f1676e3735bd314986cc5f2be064e98c8f938a3f93c28b94487567d28829b4c0d66f8d2f8f5a776f302 \ No newline at end of file +8c496e13f9456bedcc0789ffdca81913596cca3c7867717ced38c3063b6cdc8949bd204c98723b72c1b456e3fc85fc90e6710482b0c74e5e29283902a5d9ed50 \ No newline at end of file diff --git a/tests/test_mg_tallies/results_true.dat b/tests/test_mg_tallies/results_true.dat index 67e6cf4056..b540d9a492 100644 --- a/tests/test_mg_tallies/results_true.dat +++ b/tests/test_mg_tallies/results_true.dat @@ -1 +1 @@ -a78b7997b258f01764aebf601ae7107d7286d79269c1adcaa3c5b58d4f78f7b330cda152f415ad7c9b0622c3dc2b60284bfca74febfd35369c2772a87b9c4d44 \ No newline at end of file +6ab4a178b642f886eea9fddbdf67a8d6d3e0d1968f06ee52d7fd5ecdc1b4a796398e9b3a8c15ac72fb1a011d13a5fcc59a868781d38fb11787e060bb2e602a7b \ No newline at end of file From e1962bd479dad3330cf261b2273d8a6ae123d6ee Mon Sep 17 00:00:00 2001 From: Qingming He <906459647@qq.com> Date: Fri, 14 Oct 2016 22:52:06 -0400 Subject: [PATCH 80/82] add numpy include dirs --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 setup.py diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index 52ffaecf49..da98506d3b --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import glob +import numpy as np try: from setuptools import setup have_setuptools = True @@ -57,7 +58,8 @@ if have_setuptools: # If Cython is present, add resonance reconstruction capability if have_cython: kwargs.update({ - 'ext_modules': cythonize('openmc/data/reconstruct.pyx') + 'ext_modules': cythonize('openmc/data/reconstruct.pyx'), + 'include_dirs': [np.get_include()] }) setup(**kwargs) From 22df8cfe417d7cfe88361bd4cac75c315798f09e Mon Sep 17 00:00:00 2001 From: Adam Nelson Date: Tue, 18 Oct 2016 05:23:50 -0400 Subject: [PATCH 81/82] Incorporated @paulromano comments --- docs/source/io_formats/mgxs_library.rst | 2 +- openmc/mesh.py | 4 ++-- openmc/mgxs/library.py | 2 +- openmc/mgxs_library.py | 9 +++------ 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/source/io_formats/mgxs_library.rst b/docs/source/io_formats/mgxs_library.rst index 2a1e63d435..4e5ea21969 100644 --- a/docs/source/io_formats/mgxs_library.rst +++ b/docs/source/io_formats/mgxs_library.rst @@ -9,7 +9,7 @@ nuclear data is available. In continuous-energy mode, the ``cross_sections.xml`` file contains necessary meta-data for each dataset, including the name and a file system location where the complete library can be found. In multi-group mode, the multi-group meta-data and the -nuclear data itself is contained within an ``mgxs.h5``. This portion of +nuclear data itself is contained within an ``mgxs.h5`` file. This portion of the manual describes the format of the multi-group data library required to be used in the ``mgxs.h5`` file. diff --git a/openmc/mesh.py b/openmc/mesh.py index 014cbc4679..21144469f1 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -286,8 +286,8 @@ class Mesh(object): openmc.XPlane(x0=self.upper_right[0], boundary_type=bc[1])] if len(self.dimension) == 1: - yplanes = [openmc.YPlane(y0=1000., boundary_type='reflective'), - openmc.YPlane(y0=1000., boundary_type='reflective')] + yplanes = [openmc.YPlane(y0=-1e10, boundary_type='reflective'), + openmc.YPlane(y0=1e10, boundary_type='reflective')] else: yplanes = [openmc.YPlane(y0=self.lower_left[1], boundary_type=bc[2]), diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index c03aa78771..eb07e80976 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -1283,7 +1283,7 @@ class Library(object): ('nu-transport' not in self.mgxs_types))): error_flag = True warn('A "nu-transport" MGXS type is required since a "P0" ' - 'correction is applied, but a "nu-transport" MGXS == ' + 'correction is applied, but a "nu-transport" MGXS is ' 'not provided.') elif (((self.correction is None) and ('total' not in self.mgxs_types))): diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 35dff1223a..b62c3ac83f 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1135,19 +1135,16 @@ class XSdata(object): if self.fissionable is not None: grp.attrs['fissionable'] = self.fissionable if self.representation is not None: - grp.attrs['representation'] = np.array(self.representation, - dtype='S') + grp.attrs['representation'] = np.string_(self.representation) if self.representation == 'angle': if self.num_azimuthal is not None: grp.attrs['num_azimuthal'] = self.num_azimuthal if self.num_polar is not None: grp.attrs['num_polar'] = self.num_polar if self.scatter_format is not None: - grp.attrs['scatter_format'] = np.array(self.scatter_format, - dtype='S') + grp.attrs['scatter_format'] = np.string_(self.scatter_format) if self.scatter_shape is not None: - grp.attrs['scatter_shape'] = np.array(self.scatter_shape, - dtype='S') + grp.attrs['scatter_shape'] = np.string_(self.scatter_shape) if self.order is not None: grp.attrs['order'] = self.order From ef9a2b41934314d795ba3abaf2e6965a130086eb Mon Sep 17 00:00:00 2001 From: tjlaboss Date: Tue, 18 Oct 2016 16:57:42 -0400 Subject: [PATCH 82/82] Fixed the placement of a right parenthesis in xsdata path --- scripts/openmc-ace-to-hdf5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/openmc-ace-to-hdf5 b/scripts/openmc-ace-to-hdf5 index dd115d175c..bfc1c1a54d 100755 --- a/scripts/openmc-ace-to-hdf5 +++ b/scripts/openmc-ace-to-hdf5 @@ -108,7 +108,7 @@ elif args.xsdata is not None: for line in xsdata: words = line.split() if len(words) >= 9: - path = os.path.join(os.path.dirname(args.xsdata, words[8])) + path = os.path.join(os.path.dirname(args.xsdata), words[8]) if path not in ace_libraries: ace_libraries.append(path)