diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index e9bb5ef53..0aa058cdb 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -661,6 +661,17 @@ methods like "nearest" and "interpolation" in the resolved resonance range. *Default*: False +------------------------------- +```` Element +------------------------------- + +The ```` element specifies a minimum and maximum temperature +in Kelvin above and below which cross sections should be loaded for all nuclides +and thermal scattering tables. This can be used for multi-physics simulations +where the temperatures might change from one iteration to the next. + + *Default*: None + .. _temperature_tolerance: ----------------------------------- diff --git a/openmc/settings.py b/openmc/settings.py index b1ff4c0c6..3efdf1ab7 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -125,13 +125,16 @@ class Settings(object): temperature : dict Defines a default temperature and method for treating intermediate temperatures at which nuclear data doesn't exist. Accepted keys are - 'default', 'method', 'tolerance', and 'multipole'. The value for - 'default' should be a float representing the default temperature in + 'default', 'method', 'range', 'tolerance', and 'multipole'. The value + for 'default' should be a float representing the default temperature in Kelvin. The value for 'method' should be 'nearest' or 'interpolation'. If the method is 'nearest', 'tolerance' indicates a range of temperature - within which cross sections may be used. 'multipole' is a boolean - indicating whether or not the windowed multipole method should be used - to evaluate resolved resonance cross sections. + within which cross sections may be used. The value for 'range' should be + a pair a minimum and maximum temperatures which are used to indicate + that cross sections be loaded at all temperatures within the + range. 'multipole' is a boolean indicating whether or not the windowed + multipole method should be used to evaluate resolved resonance cross + sections. threads : int Number of OpenMP threads trace : tuple or list @@ -639,7 +642,8 @@ class Settings(object): cv.check_type('temperature settings', temperature, Mapping) for key, value in temperature.items(): cv.check_value('temperature key', key, - ['default', 'method', 'tolerance', 'multipole']) + ['default', 'method', 'tolerance', 'multipole', + 'range']) if key == 'default': cv.check_type('default temperature', value, Real) elif key == 'method': @@ -649,6 +653,11 @@ class Settings(object): cv.check_type('temperature tolerance', value, Real) elif key == 'multipole': cv.check_type('temperature multipole', value, bool) + elif key == 'range': + cv.check_length('temperature range', value, 2) + for T in value: + cv.check_type('temperature', T, Real) + self._temperature = temperature @threads.setter @@ -999,6 +1008,8 @@ class Settings(object): "temperature_{}".format(key)) if isinstance(value, bool): element.text = str(value).lower() + elif key == 'range': + element.text = ' '.join(str(T) for T in value) else: element.text = str(value) diff --git a/src/global.F90 b/src/global.F90 index 96df26cf6..1574f1f43 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -106,6 +106,7 @@ module global logical :: temperature_multipole = .false. real(8) :: temperature_tolerance = 10.0_8 real(8) :: temperature_default = 293.6_8 + real(8) :: temperature_range(2) = [ZERO, ZERO] ! ============================================================================ ! MULTI-GROUP CROSS SECTION RELATED VARIABLES diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 5ff4d119e..cc06e3f81 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -951,6 +951,9 @@ contains if (check_for_node(root, "temperature_multipole")) then call get_node_value(root, "temperature_multipole", temperature_multipole) end if + if (check_for_node(root, "temperature_range")) then + call get_node_array(root, "temperature_range", temperature_range) + end if ! Check for tabular_legendre options if (check_for_node(root, "tabular_legendre")) then @@ -5273,7 +5276,8 @@ contains ! Read nuclide data from HDF5 group_id = open_group(file_id, name) call nuclides(i_nuclide) % from_hdf5(group_id, nuc_temps(i_nuclide), & - temperature_method, temperature_tolerance, master) + temperature_method, temperature_tolerance, temperature_range, & + master) call close_group(group_id) call file_close(file_id) @@ -5325,7 +5329,7 @@ contains ! Read S(a,b) data from HDF5 group_id = open_group(file_id, name) call sab_tables(i_sab) % from_hdf5(group_id, sab_temps(i_sab), & - temperature_method, temperature_tolerance) + temperature_method, temperature_tolerance, temperature_range) call close_group(group_id) call file_close(file_id) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index ea6eab328..a55e9c841 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -168,12 +168,13 @@ module nuclide_header end subroutine nuclide_clear subroutine nuclide_from_hdf5(this, group_id, temperature, method, tolerance, & - master) + minmax, master) class(Nuclide), intent(inout) :: this integer(HID_T), intent(in) :: group_id - type(VectorReal), intent(in) :: temperature ! list of desired temperatures + type(VectorReal), intent(in) :: temperature ! list of desired temperatures integer, intent(inout) :: method real(8), intent(in) :: tolerance + real(8), intent(in) :: minmax(2) ! range of temperatures logical, intent(in) :: master ! if this is the master proc integer :: i @@ -233,7 +234,18 @@ module nuclide_header method = TEMPERATURE_NEAREST end if - ! Determine actual temperatures to read + ! Determine actual temperatures to read -- start by checking whether a + ! temperature range was given, in which case all temperatures in the range + ! are loaded irrespective of what temperatures actually appear in the model + if (minmax(2) > ZERO) then + do i = 1, size(temps_available) + temp_actual = temps_available(i) + if (minmax(1) <= temp_actual .and. temp_actual <= minmax(2)) then + call temps_to_read % push_back(nint(temp_actual)) + end if + end do + end if + select case (method) case (TEMPERATURE_NEAREST) ! Find nearest temperatures diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc index a0f100cd8..23a0cfd4b 100644 --- a/src/relaxng/settings.rnc +++ b/src/relaxng/settings.rnc @@ -116,6 +116,8 @@ element settings { element temperature_multipole { xsd:boolean }? & + element temperature_range { list { xsd:double, xsd:double } }? & + element temperature_tolerance { xsd:double }? & element threads { xsd:positiveInteger }? & diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng index 2a9a170f9..e75dc7c15 100644 --- a/src/relaxng/settings.rng +++ b/src/relaxng/settings.rng @@ -517,6 +517,14 @@ + + + + + + + + diff --git a/src/sab_header.F90 b/src/sab_header.F90 index 1d64711b8..e0b79f248 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -80,12 +80,14 @@ module sab_header contains - subroutine salphabeta_from_hdf5(this, group_id, temperature, method, tolerance) + subroutine salphabeta_from_hdf5(this, group_id, temperature, method, & + tolerance, minmax) class(SAlphaBeta), intent(inout) :: this integer(HID_T), intent(in) :: group_id type(VectorReal), intent(in) :: temperature ! list of temperatures integer, intent(in) :: method real(8), intent(in) :: tolerance + real(8), intent(in) :: minmax(2) integer :: i, j integer :: t @@ -143,6 +145,18 @@ contains end do call sort(temps_available) + ! Determine actual temperatures to read -- start by checking whether a + ! temperature range was given, in which case all temperatures in the range + ! are loaded irrespective of what temperatures actually appear in the model + if (minmax(2) > ZERO) then + do i = 1, size(temps_available) + temp_actual = temps_available(i) + if (minmax(1) <= temp_actual .and. temp_actual <= minmax(2)) then + call temps_to_read % push_back(nint(temp_actual)) + end if + end do + end if + select case (method) case (TEMPERATURE_NEAREST) ! Determine actual temperatures to read