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)