From bb45f220d4418d1f5ecaf75f4f0b180e4975ca85 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Wed, 19 Dec 2018 02:04:11 -0500 Subject: [PATCH] clean up CMFD testing harness, adjoint logic, use run_in_memory --- openmc/capi/core.py | 9 +- openmc/cmfd.py | 182 ++++++++------------ tests/regression_tests/cmfd_feed/test.py | 45 ++--- tests/regression_tests/cmfd_feed_2g/test.py | 24 +-- tests/regression_tests/cmfd_feed_ng/test.py | 24 +-- tests/regression_tests/cmfd_nofeed/test.py | 23 +-- tests/testing_harness.py | 29 +++- 7 files changed, 122 insertions(+), 214 deletions(-) diff --git a/openmc/capi/core.py b/openmc/capi/core.py index ef606d635..540413e7b 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -141,6 +141,7 @@ def find_material(xyz): else: return mats[instance.value] + def hard_reset(): """Reset tallies, timers, and pseudo-random number generator state.""" _dll.openmc_hard_reset() @@ -330,7 +331,7 @@ def statepoint_write(filename=None, write_source=True): @contextmanager -def run_in_memory(intracomm=None): +def run_in_memory(**kwargs): """Provides context manager for calling OpenMC shared library functions. This function is intended to be used in a 'with' statement and ensures that @@ -346,11 +347,11 @@ def run_in_memory(intracomm=None): Parameters ---------- - intracomm : mpi4py.MPI.Intracomm or None - MPI intracommunicator + **kwargs + All keyword arguments are passed to :func:`init`. """ - init(intracomm=intracomm) + init(**kwargs) try: yield finally: diff --git a/openmc/cmfd.py b/openmc/cmfd.py index bbfc63569..167331cd2 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -608,7 +608,7 @@ class CMFDRun(object): check_length('Gauss-Seidel tolerance', gauss_seidel_tolerance, 2) self._gauss_seidel_tolerance = gauss_seidel_tolerance - def run(self, intracomm=None, **kwargs): + def run(self, **kwargs): """Run OpenMC with coarse mesh finite difference acceleration This method is called by user to run CMFD once instance variables of @@ -616,65 +616,61 @@ class CMFDRun(object): Parameters ---------- - intracomm : mpi4py.MPI.Intracomm or None - MPI intercommunicator to pass through C API. Set to MPI.COMM_WORLD - by default **kwargs - All keyword arguments are passed to :func:`openmc.capi.init`. + All keyword arguments are passed to + :func:`openmc.capi.run_in_memory`. """ # Store intracomm for part of CMFD routine where MPI reduce and # broadcast calls are made - if intracomm is not None: - self._intracomm = intracomm - elif intracomm is None and have_mpi: + if 'intracomm' in kwargs.keys() and kwargs['intracomm'] is not None: + self._intracomm = kwargs['intracomm'] + elif have_mpi: self._intracomm = MPI.COMM_WORLD - # Run and pass arguments to C API init function - openmc.capi.init(intracomm=self._intracomm, **kwargs) + # Run and pass arguments to C API run_in_memory function + with openmc.capi.run_in_memory(**kwargs): + # Configure CMFD parameters and tallies + self._configure_cmfd() - # Configure CMFD parameters and tallies - self._configure_cmfd() + # Set up CMFD coremap + self._set_coremap() - # Set up CMFD coremap - self._set_coremap() + # Compute and store array indices used to build cross section + # arrays + self._precompute_array_indices() - # Compute and store array indices used to build cross section arrays - self._precompute_array_indices() + # Compute and store row and column indices used to build CMFD + # matrices + self._precompute_matrix_indices() - # Compute and store row and column indices used to build CMFD matrices - self._precompute_matrix_indices() + # Initialize all variables used for linear solver in C++ + self._initialize_linsolver() - # Initialize all variables used for linear solver in C++ - self._initialize_linsolver() + # Initialize simulation + openmc.capi.simulation_init() - # Initialize simulation - openmc.capi.simulation_init() + status = 0 + while status == 0: + # Initialize CMFD batch + self._cmfd_init_batch() - status = 0 - while status == 0: - # Initialize CMFD batch - self._cmfd_init_batch() + # Run next batch + status = openmc.capi.next_batch() - # Run next batch - status = openmc.capi.next_batch() + # Perform CMFD calculation if on + if self._cmfd_on: + self._execute_cmfd() - # Perform CMFD calculation if on - if self._cmfd_on: - self._execute_cmfd() + # Write CMFD output if CMFD on for current batch + if openmc.capi.master(): + self._write_cmfd_output() - # Write CMFD output if CMFD on for current batch - if openmc.capi.master(): - self._write_cmfd_output() + # Finalize simuation + openmc.capi.simulation_finalize() - # Finalize simuation - openmc.capi.simulation_finalize() - - # Print out CMFD timing statistics - self._write_cmfd_timing_stats() - - # Finalize and free memory - openmc.capi.finalize() + # Print out CMFD timing statistics + self._write_cmfd_timing_stats() def _initialize_linsolver(self): # Determine number of rows in CMFD matrix @@ -703,15 +699,19 @@ class CMFDRun(object): # Display value of additional fields based on display dict outstr += '\n' if self._display['dominance']: - outstr += '{:>11s}Dom Rat: {:0.5f}\n'.format('', self._dom[-1]) + outstr += ('{:>11s}Dom Rat: {:0.5f}\n' + .format('', self._dom[-1])) if self._display['entropy']: - outstr += '{:>11s}CMFD Ent: {:0.5f}\n'.format('', self._entropy[-1]) + outstr += ('{:>11s}CMFD Ent: {:0.5f}\n' + .format('', self._entropy[-1])) if self._display['source']: - outstr += '{:>11s}RMS Src: {:0.5f}\n'.format('', self._src_cmp[-1]) + outstr += ('{:>11s}RMS Src: {:0.5f}\n' + .format('', self._src_cmp[-1])) if self._display['balance']: - outstr += '{:>11s}RMS Bal: {:0.5f}\n'.format('', self._balance[-1]) + outstr += ('{:>11s}RMS Bal: {:0.5f}\n' + .format('', self._balance[-1])) - print('{:s}'.format(outstr)) + print(outstr) sys.stdout.flush() def _write_cmfd_timing_stats(self): @@ -926,12 +926,29 @@ class CMFDRun(object): # Start timer for build time_start_buildcmfd = time.time() - # Build loss and production matrices - loss, prod = self._build_matrices(physical_adjoint) + # Build the loss and production matrices + if not adjoint: + # Build matrices without adjoint calculation + loss = self._build_loss_matrix(False) + prod = self._build_prod_matrix(False) + else: + # Build adjoint matrices by running adjoint calculation + if self._adjoint_type == 'physical': + loss = self._build_loss_matrix(True) + prod = self._build_prod_matrix(True) + # Build adjoint matrices as transpose of non-adjoint matrices + else: + loss = self._build_loss_matrix(False).transpose() + prod = self._build_prod_matrix(False).transpose() - # Check for mathematical adjoint calculation - if adjoint and self._adjoint_type == 'math': - loss, prod = self._compute_adjoint(loss, prod) + # Write out the matrices. + if self._write_matrices: + if not adjoint: + self._write_matrix(loss, 'loss') + self._write_matrix(prod, 'prod') + else: + self._write_matrix(loss, 'adj_loss') + self._write_matrix(prod, 'adj_prod') # Stop timer for build time_stop_buildcmfd = time.time() @@ -1237,67 +1254,6 @@ class CMFDRun(object): return sites_outside[0] - def _build_matrices(self, adjoint): - """Build loss and production matrices and write these matrices - - Parameters - ---------- - adjoint : bool - Whether or not to run an adjoint calculation - - Returns - ------- - loss : scipy.sparse.spmatrix - Sparse matrix storing elements of CMFD loss matrix - prod : scipy.sparse.spmatrix - Sparse matrix storing elements of CMFD production matrix - - """ - # Build loss and production matrices - loss = self._build_loss_matrix(adjoint) - prod = self._build_prod_matrix(adjoint) - - # Write out matrices - if self._write_matrices: - if adjoint: - self._write_matrix(loss, 'adj_loss') - self._write_matrix(prod, 'adj_prod') - else: - self._write_matrix(loss, 'loss') - self._write_matrix(prod, 'prod') - - return loss, prod - - def _compute_adjoint(self, loss, prod): - """Computes a mathematical adjoint of the CMFD problem by transposing - production and loss matrices passed in as arguments - - Parameters - ---------- - loss : scipy.sparse.spmatrix - Sparse matrix storing elements of CMFD loss matrix - prod : scipy.sparse.spmatrix - Sparse matrix storing elements of CMFD production matrix - - Returns - ------- - loss : scipy.sparse.spmatrix - Sparse matrix storing elements of adjoint CMFD loss matrix - prod : scipy.sparse.spmatrix - Sparse matrix storing elements of adjoint CMFD production matrix - - """ - # Transpose matrices - loss = np.transpose(loss) - prod = np.transpose(prod) - - # Write out matrices - if self._write_matrices: - self._write_matrix(loss, 'adj_loss') - self._write_matrix(prod, 'adj_prod') - - return loss, prod - def _build_loss_matrix(self, adjoint): # Extract spatial and energy indices and define matrix dimension ng = self._indices[3] diff --git a/tests/regression_tests/cmfd_feed/test.py b/tests/regression_tests/cmfd_feed/test.py index f19a9aede..04ac442e0 100644 --- a/tests/regression_tests/cmfd_feed/test.py +++ b/tests/regression_tests/cmfd_feed/test.py @@ -3,11 +3,12 @@ from openmc import cmfd import numpy as np import scipy.sparse -def test_cmfd_physical_adjoint(): - """ Test physical adjoint functionality of CMFD - This test runs CMFD with a physical adjoint calculation and asserts that the - adjoint k-effective and flux vector are equal to the non-adjoint +def test_cmfd_physical_adjoint(): + """Test physical adjoint functionality of CMFD + + This test runs CMFD with a physical adjoint calculation and asserts that + the adjoint k-effective and flux vector are equal to the non-adjoint k-effective and flux vector at the last batch (equivalent for 1 group problems). @@ -31,11 +32,12 @@ def test_cmfd_physical_adjoint(): assert(np.all(cmfd_run._phi == cmfd_run._adj_phi)) assert(cmfd_run._adj_keff == cmfd_run._keff) -def test_cmfd_math_adjoint(): - """ Test mathematical adjoint functionality of CMFD - This test runs CMFD with a mathematical adjoint calculation and asserts that - the adjoint k-effective and flux vector are equal to the non-adjoint +def test_cmfd_math_adjoint(): + """Test mathematical adjoint functionality of CMFD + + This test runs CMFD with a mathematical adjoint calculation and asserts + that the adjoint k-effective and flux vector are equal to the non-adjoint k-effective and flux vector at the last batch (equivalent for 1 group problems). @@ -59,8 +61,9 @@ def test_cmfd_math_adjoint(): assert(np.all(cmfd_run._phi == cmfd_run._adj_phi)) assert(cmfd_run._adj_keff == cmfd_run._keff) + def test_cmfd_write_matrices(): - """ Test write matrices functionality of CMFD + """Test write matrices functionality of CMFD This test runs CMFD with feedback and loads the loss/production matrices and flux vector that are saved to disk, and checks to make sure these @@ -111,8 +114,9 @@ def test_cmfd_write_matrices(): assert(np.all(np.isclose(flux_np, cmfd_run._phi))) assert(np.all(np.isclose(flux_np, flux_dat))) + def test_cmfd_feed(): - """ Test 1 group CMFD solver with CMFD feedback""" + """Test 1 group CMFD solver with CMFD feedback""" # Initialize and set CMFD mesh cmfd_mesh = cmfd.CMFDMesh() cmfd_mesh.lower_left = -10.0, -1.0, -1.0 @@ -129,25 +133,6 @@ def test_cmfd_feed(): cmfd_run.gauss_seidel_tolerance = [1.e-15, 1.e-20] cmfd_run.run() - # Create output string of all CMFD results to pass into testing harness - outstr = 'cmfd indices\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.indices]) - outstr += '\nk cmfd\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.k_cmfd]) - outstr += '\ncmfd entropy\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.entropy]) - outstr += '\ncmfd balance\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.balance]) - outstr += '\ncmfd dominance ratio\n' - outstr += '\n'.join(['{0:10.3E}'.format(x) for x in cmfd_run.dom]) - outstr += '\ncmfd openmc source comparison\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.src_cmp]) - outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run._cmfd_src, np.product(cmfd_run.indices), - order='F') - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) - outstr += '\n' - # Initialize and run CMFD test harness - harness = CMFDTestHarness('statepoint.20.h5', cmfd_results=outstr) + harness = CMFDTestHarness('statepoint.20.h5', cmfd_run) harness.main() diff --git a/tests/regression_tests/cmfd_feed_2g/test.py b/tests/regression_tests/cmfd_feed_2g/test.py index 4efe4c4dd..22cc7e160 100644 --- a/tests/regression_tests/cmfd_feed_2g/test.py +++ b/tests/regression_tests/cmfd_feed_2g/test.py @@ -2,8 +2,9 @@ from tests.testing_harness import CMFDTestHarness from openmc import cmfd import numpy as np + def test_cmfd_feed_2g(): - """ Test 2 group CMFD solver results with CMFD feedback""" + """Test 2 group CMFD solver results with CMFD feedback""" # Initialize and set CMFD mesh cmfd_mesh = cmfd.CMFDMesh() cmfd_mesh.lower_left = -1.25984, -1.25984, -1.0 @@ -22,25 +23,6 @@ def test_cmfd_feed_2g(): cmfd_run.gauss_seidel_tolerance = [1.e-15, 1.e-20] cmfd_run.run() - # Create output string of all CMFD results to pass into testing harness - outstr = 'cmfd indices\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.indices]) - outstr += '\nk cmfd\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.k_cmfd]) - outstr += '\ncmfd entropy\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.entropy]) - outstr += '\ncmfd balance\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.balance]) - outstr += '\ncmfd dominance ratio\n' - outstr += '\n'.join(['{0:10.3E}'.format(x) for x in cmfd_run.dom]) - outstr += '\ncmfd openmc source comparison\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.src_cmp]) - outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run._cmfd_src, np.product(cmfd_run.indices), - order='F') - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) - outstr += '\n' - # Initialize and run CMFD test harness - harness = CMFDTestHarness('statepoint.20.h5', cmfd_results=outstr) + harness = CMFDTestHarness('statepoint.20.h5', cmfd_run) harness.main() diff --git a/tests/regression_tests/cmfd_feed_ng/test.py b/tests/regression_tests/cmfd_feed_ng/test.py index 74fbe0a64..db0b44f3e 100644 --- a/tests/regression_tests/cmfd_feed_ng/test.py +++ b/tests/regression_tests/cmfd_feed_ng/test.py @@ -2,8 +2,9 @@ from tests.testing_harness import CMFDTestHarness from openmc import cmfd import numpy as np + def test_cmfd_feed_ng(): - """ Test n group CMFD solver with CMFD feedback""" + """Test n group CMFD solver with CMFD feedback""" # Initialize and set CMFD mesh cmfd_mesh = cmfd.CMFDMesh() cmfd_mesh.lower_left = -1.25984, -1.25984, -1.0 @@ -23,25 +24,6 @@ def test_cmfd_feed_ng(): cmfd_run.gauss_seidel_tolerance = [1.e-15, 1.e-20] cmfd_run.run() - # Create output string of all CMFD results to pass into testing harness - outstr = 'cmfd indices\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.indices]) - outstr += '\nk cmfd\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.k_cmfd]) - outstr += '\ncmfd entropy\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.entropy]) - outstr += '\ncmfd balance\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.balance]) - outstr += '\ncmfd dominance ratio\n' - outstr += '\n'.join(['{0:10.3E}'.format(x) for x in cmfd_run.dom]) - outstr += '\ncmfd openmc source comparison\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.src_cmp]) - outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run._cmfd_src, np.product(cmfd_run.indices), - order='F') - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) - outstr += '\n' - # Initialize and run CMFD test harness - harness = CMFDTestHarness('statepoint.20.h5', cmfd_results=outstr) + harness = CMFDTestHarness('statepoint.20.h5', cmfd_run) harness.main() diff --git a/tests/regression_tests/cmfd_nofeed/test.py b/tests/regression_tests/cmfd_nofeed/test.py index 1d6896cc9..36f693026 100644 --- a/tests/regression_tests/cmfd_nofeed/test.py +++ b/tests/regression_tests/cmfd_nofeed/test.py @@ -4,7 +4,7 @@ import numpy as np def test_cmfd_nofeed(): - """ Test 1 group CMFD solver without CMFD feedback""" + """Test 1 group CMFD solver without CMFD feedback""" # Initialize and set CMFD mesh cmfd_mesh = cmfd.CMFDMesh() cmfd_mesh.lower_left = -10.0, -1.0, -1.0 @@ -21,25 +21,6 @@ def test_cmfd_nofeed(): cmfd_run.gauss_seidel_tolerance = [1.e-15, 1.e-20] cmfd_run.run() - # Create output string of all CMFD results to pass into testing harness - outstr = 'cmfd indices\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.indices]) - outstr += '\nk cmfd\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.k_cmfd]) - outstr += '\ncmfd entropy\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.entropy]) - outstr += '\ncmfd balance\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.balance]) - outstr += '\ncmfd dominance ratio\n' - outstr += '\n'.join(['{0:10.3E}'.format(x) for x in cmfd_run.dom]) - outstr += '\ncmfd openmc source comparison\n' - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.src_cmp]) - outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.product(cmfd_run.indices), - order='F') - outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) - outstr += '\n' - # Initialize and run CMFD test harness - harness = CMFDTestHarness('statepoint.20.h5', cmfd_results=outstr) + harness = CMFDTestHarness('statepoint.20.h5', cmfd_run) harness.main() diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 408ddf187..d8baf3206 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -133,9 +133,30 @@ class HashedTestHarness(TestHarness): class CMFDTestHarness(TestHarness): """Specialized TestHarness for running OpenMC CMFD tests.""" - def __init__(self, statepoint_name, cmfd_results=None): + def __init__(self, statepoint_name, cmfd_run): self._sp_name = statepoint_name - self._cmfd_results = cmfd_results + self._create_cmfd_result_str(cmfd_run) + + def _create_cmfd_result_str(self, cmfd_run): + """Create CMFD result string from variables of CMFDRun instance""" + outstr = 'cmfd indices\n' + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.indices]) + outstr += '\nk cmfd\n' + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.k_cmfd]) + outstr += '\ncmfd entropy\n' + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.entropy]) + outstr += '\ncmfd balance\n' + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.balance]) + outstr += '\ncmfd dominance ratio\n' + outstr += '\n'.join(['{0:10.3E}'.format(x) for x in cmfd_run.dom]) + outstr += '\ncmfd openmc source comparison\n' + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfd_run.src_cmp]) + outstr += '\ncmfd source\n' + cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.product(cmfd_run.indices), + order='F') + outstr += '\n'.join(['{0:12.6E}'.format(x) for x in cmfdsrc]) + outstr += '\n' + self._cmfdrun_results = outstr def execute_test(self): """Don't call _run_openmc as OpenMC will be called through C API for @@ -145,7 +166,7 @@ class CMFDTestHarness(TestHarness): try: self._test_output_created() results = self._get_results() - results += self._cmfd_results + results += self._cmfdrun_results self._write_results(results) self._compare_results() finally: @@ -159,7 +180,7 @@ class CMFDTestHarness(TestHarness): try: self._test_output_created() results = self._get_results() - results += self._cmfd_results + results += self._cmfdrun_results self._write_results(results) self._overwrite_results() finally: