From e53fc07b07e8a2bc74399b064681da19145c1083 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 1 Jun 2015 14:35:53 +0700 Subject: [PATCH] Modify openmc.cmfd.CMFDFile to include several properties that were missing. Also make various things in the module more Pythonic. --- docs/source/usersguide/input.rst | 18 +- openmc/cmfd.py | 315 +++++++++++++++++++++---------- 2 files changed, 225 insertions(+), 108 deletions(-) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index 22a4b33e29..5b6bee8c63 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -1666,6 +1666,15 @@ The ```` element controls what batch CMFD calculations should begin. *Default*: 1 +```` Element +------------------------ + +The ```` element controls whether :math:`\widehat{D}` nonlinear +CMFD parameters should be reset to zero before solving CMFD eigenproblem. +It can be turned on with "true" and off with "false". + + *Default*: false + ```` Element --------------------- @@ -1682,15 +1691,6 @@ The ```` element sets one additional CMFD output column. Options are: *Default*: balance -```` Element ------------------------- - -The ```` element controls whether :math:`\widehat{D}` nonlinear -CMFD parameters should be reset to zero before solving CMFD eigenproblem. -It can be turned on with "true" and off with "false". - - *Default*: false - ```` Element ------------------------- diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 010f5a09ad..88d87f2442 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -54,7 +54,6 @@ class CMFDMesh(object): """ def __init__(self): - self._lower_left = None self._upper_right = None self._dimension = None @@ -93,7 +92,6 @@ class CMFDMesh(object): @lower_left.setter def lower_left(self, lower_left): - if not isinstance(lower_left, (tuple, list, np.ndarray)): msg = 'Unable to set CMFD Mesh with lower_left {0} which is ' \ 'not a Python list, tuple or NumPy array'.format(lower_left) @@ -105,7 +103,6 @@ class CMFDMesh(object): raise ValueError(msg) for coord in lower_left: - if not is_integer(coord) and not is_float(coord): msg = 'Unable to set CMFD Mesh with lower_left {0} which is ' \ 'not an integer or a floating point value'.format(coord) @@ -127,7 +124,6 @@ class CMFDMesh(object): raise ValueError(msg) for coord in upper_right: - if not is_integer(coord) and not is_float(coord): msg = 'Unable to set CMFD Mesh with upper_right {0} which ' \ 'is not an integer or floating point value'.format(coord) @@ -137,7 +133,6 @@ class CMFDMesh(object): @dimension.setter def dimension(self, dimension): - if not isinstance(dimension, (tuple, list, np.ndarray)): msg = 'Unable to set CMFD Mesh with dimension {0} which is ' \ 'not a Python list, tuple or NumPy array'.format(dimension) @@ -149,7 +144,6 @@ class CMFDMesh(object): raise ValueError(msg) for dim in dimension: - if not is_integer(dim): msg = 'Unable to set CMFD Mesh with dimension {0} which ' \ 'is a non-integer'.format(dim) @@ -159,9 +153,7 @@ class CMFDMesh(object): @width.setter def width(self, width): - if not width is None: - if not isinstance(width, (tuple, list, np.ndarray)): msg = 'Unable to set CMFD Mesh with width {0} which ' \ 'is not a Python list, tuple or NumPy array'.format(width) @@ -173,7 +165,6 @@ class CMFDMesh(object): raise ValueError(msg) for dim in width: - if not is_integer(dim) and not is_float(dim): msg = 'Unable to set CMFD Mesh with width {0} which is ' \ 'not an integer or floating point value'.format(width) @@ -183,19 +174,16 @@ class CMFDMesh(object): @energy.setter def energy(self, energy): - if not isinstance(energy, (tuple, list, np.ndarray)): msg = 'Unable to set CMFD Mesh energy to {0} which is not ' \ 'a Python tuple/list or NumPy array'.format(energy) raise ValueError(msg) for e in energy: - if not is_integer(e) and not is_float(e): msg = 'Unable to set CMFD Mesh energy to {0} which is not ' \ 'an integer or floating point value'.format(e) raise ValueError(msg) - elif e < 0: msg = 'Unable to set CMFD Mesh energy to {0} which is ' \ 'is a negative integer'.format(e) @@ -205,7 +193,6 @@ class CMFDMesh(object): @albedo.setter def albedo(self, albedo): - if not isinstance(albedo, (tuple, list, np.ndarray)): msg = 'Unable to set CMFD Mesh albedo to {0} which is not ' \ 'a Python tuple/list or NumPy array'.format(albedo) @@ -217,12 +204,10 @@ class CMFDMesh(object): raise ValueError(msg) for a in albedo: - if not is_integer(a) and not is_float(a): msg = 'Unable to set CMFD Mesh albedo to {0} which is not ' \ 'an integer or floating point value'.format(a) raise ValueError(msg) - elif a < 0 or a > 1: msg = 'Unable to set CMFD Mesh albedo to {0} which is ' \ 'is not in [0,1]'.format(a) @@ -239,7 +224,6 @@ class CMFDMesh(object): raise ValueError(msg) for m in map: - if m != 1 and m != 2: msg = 'Unable to set CMFD Mesh map to {0} which is ' \ 'is not 1 or 2'.format(m) @@ -250,77 +234,31 @@ class CMFDMesh(object): def _get_xml_element(self): element = ET.Element("mesh") - if len(self._lower_left) == 2: - subelement = ET.SubElement(element, "lower_left") - subelement.text = '{0} {1}'.format(self._lower_left[0], - self._lower_left[1]) - else: - subelement = ET.SubElement(element, "lower_left") - subelement.text = '{0} {1} {2}'.format(self._lower_left[0], - self._lower_left[1], - self._lower_left[2]) + subelement = ET.SubElement(element, "lower_left") + subelement.text = ' '.join(map(str, self._lower_left)) if not self._upper_right is None: - if len(self._upper_right) == 2: - subelement = ET.SubElement(element, "upper_right") - subelement.text = '{0} {1}'.format(self._upper_right[0], - self._upper_right[1]) - else: - subelement = ET.SubElement(element, "upper_right") - subelement.text = '{0} {1} {2}'.format(self._upper_right[0], - self._upper_right[1], - self._upper_right[2]) + subelement = ET.SubElement(element, "upper_right") + subelement.text = ' '.join(map(str, self._upper_right)) - if len(self._dimension) == 2: - subelement = ET.SubElement(element, "dimension") - subelement.text = '{0} {1}'.format(self._dimension[0], - self._dimension[1]) - else: - subelement = ET.SubElement(element, "dimension") - subelement.text = '{0} {1} {2}'.format(self._dimension[0], - self._dimension[1], - self._dimension[2]) + subelement = ET.SubElement(element, "dimension") + subelement.text = ' '.join(map(str, self._dimension)) if not self._width is None: - if len(self._width) == 2: - subelement = ET.SubElement(element, "width") - subelement.text = '{0} {1}'.format(self._width[0], - self._width[1]) - else: - subelement = ET.SubElement(element, "width") - subelement.text = '{0} {1} {2}'.format(self._width[0], - self._width[1], - self._width[2]) + subelement = ET.SubElement(element, "width") + subelement.text = ' '.join(map(str, self._width)) if not self._energy is None: - subelement = ET.SubElement(element, "energy") - - energy = '' - for e in self._energy: - energy += '{0} '.format(e) - - subelement.set("energy", energy.rstrip(' ')) + subelement.text = ' '.join(map(str, self._energy)) if not self._albedo is None: - subelement = ET.SubElement(element, "albedo") - - albedo = '' - for a in self._albedo: - albedo += '{0} '.format(a) - - subelement.set("albedo", albedo.rstrip(' ')) + subelement.text = ' '.join(map(str, self._albedo)) if not self._map is None: - subelement = ET.SubElement(element, "map") - - map = '' - for m in self._map: - map += '{0} '.format(m) - - subelement.set("map", map.rstrip(' ')) + subelement.text = ' '.join(map(str, self._map)) return element @@ -333,6 +271,9 @@ class CMFDFile(object): ---------- begin : int Batch number at which CMFD calculations should begin + dhat_reset : bool + Indicate whether :math:`\widehat{D}` nonlinear CMFD parameters should be + reset to zero before solving CMFD eigenproblem. display : {'balance', 'dominance', 'entropy', 'source'} Set one additional CMFD output column. Options are: @@ -343,9 +284,17 @@ class CMFDFile(object): * "entropy" - prints the *entropy* of the CMFD predicted fission source. * "source" - prints the RMS [%] between the OpenMC fission source and CMFD fission source. + downscatter : bool + Indicate whether an effective downscatter cross section should be used + when using 2-group CMFD. feedback : bool Indicate or not the CMFD diffusion result is used to adjust the weight of fission source neutrons on the next OpenMC batch. Defaults to False. + gauss_seidel_tolerance : tuple or list or ndarray of float + Two parameters specifying the absolute inner tolerance and the relative + inner tolerance for Gauss-Seidel iterations when performing CMFD. + ktol : float + Tolerance on the eigenvalue when performing CMFD power iteration cmfd_mesh : CMFDMesh Structured mesh to be used for acceleration norm : float @@ -354,6 +303,16 @@ class CMFDFile(object): View convergence of power iteration during CMFD acceleration run_adjoint : bool Perform adjoint calculation on the last batch + shift : float + Optional Wielandt shift parameter for accelerating power iterations. By + default, it is very large so there is effectively no impact. + spectral : float + Optional spectral radius that can be used to accelerate the convergence + of Gauss-Seidel iterations during CMFD power iteration. + stol : float + Tolerance on the fission source when performing CMFD power iteration + tally_reset : list of int + List of batch numbers at which CMFD tallies should be reset write_matrices : bool Write sparse matrices that are used during CMFD acceleration (loss, production) to file @@ -361,14 +320,21 @@ class CMFDFile(object): """ def __init__(self): - self._begin = None + self._dhat_reset = None self._display = None + self._downscatter = None self._feedback = None + self._gauss_seidel_tolerance = None + self._ktol = None self._cmfd_mesh = None self._norm = None self._power_monitor = None self._run_adjoint = None + self._shift = None + self._spectral = None + self._stol = None + self._tally_reset = None self._write_matrices = None self._cmfd_file = ET.Element("cmfd") @@ -378,14 +344,30 @@ class CMFDFile(object): def begin(self): return self._begin + @property + def dhat_reset(self): + return self._dhat_reset + @property def display(self): return self._display + @property + def downscatter(self): + return self._downscatter + @property def feedback(self): return self._feedback + @property + def gauss_seidel_tolerance(self): + return self._gauss_seidel_tolerance + + @property + def ktol(self): + return self._ktol + @property def cmfd_mesh(self): return self._cmfd_mesh @@ -403,8 +385,20 @@ class CMFDFile(object): return self._run_adjoint @property - def solver(self): - return self._solver + def shift(self): + return self._shift + + @property + def spectral(self): + return self._spectral + + @property + def stol(self): + return self._stol + + @property + def tally_reset(self): + return self._tally_reset @property def write_matrices(self): @@ -412,7 +406,6 @@ class CMFDFile(object): @begin.setter def begin(self, begin): - if not is_integer(begin): msg = 'Unable to set CMFD begin batch to a non-integer ' \ 'value {0}'.format(begin) @@ -425,9 +418,17 @@ class CMFDFile(object): self._begin = begin + @dhat_reset.setter + def dhat_reset(self, dhat_reset): + if not isinstance(dhat_reset, bool): + msg = 'Unable to set Dhat reset to {0} which is ' \ + 'a non-boolean value'.format(dhat_reset) + raise ValueError(msg) + + self._dhat_reset = dhat_reset + @display.setter def display(self, display): - if not is_string(display): msg = 'Unable to set CMFD display to a non-string ' \ 'value'.format(display) @@ -440,9 +441,17 @@ class CMFDFile(object): self._display = display + @downscatter.setter + def downscatter(self, downscatter): + if not isinstance(downscatter, bool): + msg = 'Unable to set downscatter to {0} which is ' \ + 'a non-boolean value'.format(downscatter) + raise ValueError(msg) + + self._downscatter = downscatter + @feedback.setter def feedback(self, feedback): - if not isinstance(feedback, bool): msg = 'Unable to set CMFD feedback to {0} which is ' \ 'a non-boolean value'.format(feedback) @@ -450,9 +459,38 @@ class CMFDFile(object): self._feedback = feedback + @gauss_seidel_tolerance.setter + def gauss_seidel_tolerance(self, gauss_seidel_tolerance): + if not isinstance(gauss_seidel_tolerance, (float, list, np.ndarray)): + msg = 'Unable to set Gauss-Seidel tolerance to {0} which is ' \ + 'not a Python tuple/list or NumPy array'.format( + gauss_seidel_tolerance) + raise ValueError(msg) + + if len(gauss_seidel_tolerance) != 2: + msg = 'Unable to set Gauss-Seidel tolerance with {0} since ' \ + 'it must be of length 2'.format(width) + raise ValueError(msg) + + for t in gauss_seidel_tolerance: + if not is_integer(t) and not is_float(t): + msg = 'Unable to set Gauss-Seidel tolerance with {0} which ' \ + 'is not an integer or floating point value'.format(t) + raise ValueError(msg) + + self._gauss_seidel_tolerance = gauss_seidel_tolerance + + @ktol.setter + def ktol(self, ktol): + if not is_integer(ktol) and not is_float(ktol): + msg = 'Unable to set the eigenvalue tolerance to {0} which is ' \ + 'not an integer or floating point value'.format(ktol) + raise ValueError(msg) + + self._ktol = ktol + @cmfd_mesh.setter def cmfd_mesh(self, mesh): - if not isinstance(mesh, CMFDMesh): msg = 'Unable to set CMFD mesh to {0} which is not a ' \ 'CMFDMesh object'.format(mesh) @@ -462,7 +500,6 @@ class CMFDFile(object): @norm.setter def norm(self, norm): - if not is_integer(norm) and not is_float(norm): msg = 'Unable to set the CMFD norm to {0} which is not ' \ 'an integer or floating point value'.format(norm) @@ -472,7 +509,6 @@ class CMFDFile(object): @power_monitor.setter def power_monitor(self, power_monitor): - if not isinstance(power_monitor, bool): msg = 'Unable to set CMFD power monitor to {0} which is a ' \ 'non-boolean value'.format(power_monitor) @@ -482,7 +518,6 @@ class CMFDFile(object): @run_adjoint.setter def run_adjoint(self, run_adjoint): - if not isinstance(run_adjoint, bool): msg = 'Unable to set CMFD run adjoint to {0} which is a ' \ 'non-boolean value'.format(run_adjoint) @@ -490,9 +525,51 @@ class CMFDFile(object): self._run_adjoint = run_adjoint + @shift.setter + def shift(self, shift): + if not is_integer(shift) and not is_float(shift): + msg = 'Unable to set the Wielandt shift to {0} which is ' \ + 'not an integer or floating point value'.format(shift) + raise ValueError(msg) + + self._shift = shift + + @spectral.setter + def spectral(self, spectral): + if not is_integer(spectral) and not is_float(spectral): + msg = 'Unable to set the spectral radius to {0} which is ' \ + 'not an integer or floating point value'.format(spectral) + raise ValueError(msg) + + self._spectral = spectral + + @stol.setter + def stol(self, stol): + if not is_integer(stol) and not is_float(stol): + msg = 'Unable to set the fission source tolerance to {0} which ' \ + 'is not an integer or floating point value'.format(stol) + raise ValueError(msg) + + self._stol = stol + + @tally_reset.setter + def tally_reset(self, tally_reset): + if not isinstance(tally_reset, (tuple, list, np.ndarray)): + msg = 'Unable to set tally reset batches to {0} which is ' \ + 'not a Python tuple/list or NumPy array'.format( + tally_reset) + raise ValueError(msg) + + for t in tally_reset: + if not is_integer(t): + msg = 'Unable to set tally reset batch to {0} which ' \ + 'is not an integer'.format(t) + raise ValueError(msg) + + self._tally_reset = tally_reset + @write_matrices.setter def write_matrices(self, write_matrices): - if not isinstance(write_matrices, bool): msg = 'Unable to set CMFD write matrices to {0} which is a ' \ 'non-boolean value'.format(write_matrices) @@ -501,52 +578,84 @@ class CMFDFile(object): self._write_matrices = write_matrices def _create_begin_subelement(self): - if not self._begin is None: element = ET.SubElement(self._cmfd_file, "begin") - element.text = '{0}'.format(str(self._begin)) + element.text = str(self._begin) + + def _create_dhat_reset_subelement(self): + if not self._dhat_reset is None: + element = ET.SubElement(self._cmfd_file, "dhat_reset") + element.text = str(self._dhat_reset).lower() def _create_display_subelement(self): - if not self._display is None: element = ET.SubElement(self._cmfd_file, "display") - element.text = '{0}'.format(str(self._display)) + element.text = str(self._display) + + def _create_downscatter_subelement(self): + if not self._downscatter is None: + element = ET.SubElement(self._cmfd_file, "downscatter") + element.text = str(self._downscatter).lower() def _create_feedback_subelement(self): - if not self._feedback is None: element = ET.SubElement(self._cmfd_file, "feeback") - element.text = '{0}'.format(str(self._feedback).lower()) + element.text = str(self._feedback).lower() + + def _create_gauss_seidel_tolerance_subelement(self): + if not self._gauss_seidel_tolerance is None: + element = ET.SubElement(self._cmfd_file, "gauss_seidel_tolerance") + element.text = ' '.join(map(str, self._gauss_seidel_tolerance)) + + def _create_ktol_subelement(self): + if not self._ktol is None: + element = ET.SubElement(self._ktol, "ktol") + element.text = str(self._ktol) def _create_mesh_subelement(self): - if not self._mesh is None: xml_element = self._mesh._get_xml_element() self._cmfd_file.append(xml_element) def _create_norm_subelement(self): - if not self._norm is None: element = ET.SubElement(self._cmfd_file, "norm") - element.text = '{0}'.format(str(self._norm)) + element.text = str(self._norm) def _create_power_monitor_subelement(self): - if not self._power_monitor is None: element = ET.SubElement(self._cmfd_file, "power_monitor") - element.text = '{0}'.format(str(self._power_monitor).lower()) + element.text = str(self._power_monitor).lower() def _create_run_adjoint_subelement(self): - if not self._run_adjoint is None: element = ET.SubElement(self._cmfd_file, "run_adjoint") - element.text = '{0}'.format(str(self._run_adjoint).lower()) + element.text = str(self._run_adjoint).lower() + + def _create_shift_subelement(self): + if not self._shift is None: + element = ET.SubElement(self._shift, "shift") + element.text = str(self._shift) + + def _create_spectral_subelement(self): + if not self._spectral is None: + element = ET.SubElement(self._spectral, "spectral") + element.text = str(self._spectral) + + def _create_stol_subelement(self): + if not self._stol is None: + element = ET.SubElement(self._stol, "stol") + element.text = str(self._stol) + + def _create_tally_reset_subelement(self): + if not self._tally_reset is None: + element = ET.SubElement(self._tally_reset, "tally_reset") + element.text = ' '.join(map(str, self._tally_reset)) def _create_write_matrices_subelement(self): - if not self._write_matrices is None: element = ET.SubElement(self._cmfd_file, "write_matrices") - element.text = '{0}'.format(str(self._write_matrices).lower()) + element.text = str(self._write_matrices).lower() def export_to_xml(self): """Create a cmfd.xml file using the class data that can be used for an OpenMC @@ -555,12 +664,20 @@ class CMFDFile(object): """ self._create_begin_subelement() + self._create_dhat_reset_subelement() self._create_display_subelement() + self._create_downscatter_subelement() self._create_feedback_subelement() + self._create_gauss_seidel_tolerance_subelement() + self._create_ktol_subelement() self._create_mesh_subelement() self._create_norm_subelement() self._create_power_monitor_subelement() self._create_run_adjoint_subelement() + self._create_shift_subelement() + self._create_spectral_subelement() + self._create_stol_subelement() + self._create_tally_reset_subelement() self._create_write_matrices_subelement() # Clean the indentation in the file to be user-readable