clean up CMFD testing harness, adjoint logic, use run_in_memory

This commit is contained in:
Shikhar Kumar 2018-12-19 02:04:11 -05:00
parent b87515b7fb
commit bb45f220d4
7 changed files with 122 additions and 214 deletions

View file

@ -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:

View file

@ -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]

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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: