Changed PyAPI model and executor to read correct last statepoint after runs with trigger, including new test case

This commit is contained in:
alex-lyons 2020-02-07 16:24:10 +00:00 committed by Paul Romano
parent b7871bdc85
commit 954154fa48
6 changed files with 189 additions and 11 deletions

View file

@ -1,6 +1,7 @@
from collections.abc import Iterable
import subprocess
from numbers import Integral
import re
import subprocess
import openmc
@ -10,6 +11,10 @@ def _run(args, output, cwd):
p = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True)
# Compile a regex object to identify statepoint writes
sp_rxprog = re.compile(r'Creating state point (.+)\.\.\.')
last_statepoint = None
# Capture and re-print OpenMC output in real-time
lines = []
while True:
@ -18,6 +23,11 @@ def _run(args, output, cwd):
if not line and p.poll() is not None:
break
# If a statepoint was written, capture its filename
sp_match = sp_rxprog.search(line)
if sp_match:
last_statepoint = sp_match.group(1)
lines.append(line)
if output:
# If user requested output, print to screen
@ -27,6 +37,7 @@ def _run(args, output, cwd):
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, ' '.join(args),
''.join(lines))
return last_statepoint
def plot_geometry(output=True, openmc_exec='openmc', cwd='.'):
@ -184,6 +195,11 @@ def run(particles=None, threads=None, geometry_debug=False,
event_based : bool, optional
Turns on event-based parallelism, instead of default history-based
Returns
-------
str
Name of the last written statepoint file, or None
Raises
------
subprocess.CalledProcessError
@ -213,4 +229,4 @@ def run(particles=None, threads=None, geometry_debug=False,
if mpi_args is not None:
args = mpi_args + args
_run(args, output, cwd)
return _run(args, output, cwd)

View file

@ -41,6 +41,8 @@ class Model:
Tallies information
plots : openmc.Plots
Plot information
statepoint : openmc.Statepoint
The last statepoint filename written when the model is run
"""
@ -51,6 +53,7 @@ class Model:
self.settings = openmc.Settings()
self.tallies = openmc.Tallies()
self.plots = openmc.Plots()
self.statepoint = None
if geometry is not None:
self.geometry = geometry
@ -197,7 +200,8 @@ class Model:
self.plots.export_to_xml(d)
def run(self, **kwargs):
"""Creates the XML files, runs OpenMC, and returns k-effective
"""Creates the XML files, runs OpenMC, and returns k-effective.
The last statepoint filename is available in model.statepoint
Parameters
----------
@ -210,14 +214,13 @@ class Model:
Combined estimator of k-effective from the statepoint
"""
self.export_to_xml()
openmc.run(**kwargs)
self.statepoint = openmc.run(**kwargs)
n = self.settings.batches
if self.settings.statepoint is not None:
if 'batches' in self.settings.statepoint:
n = self.settings.statepoint['batches'][-1]
with openmc.StatePoint('statepoint.{}.h5'.format(n)) as sp:
return sp.k_combined
keff = None
if self.statepoint:
with openmc.StatePoint(self.statepoint) as sp:
keff = sp.k_combined
return keff

View file

@ -0,0 +1,34 @@
<?xml version='1.0' encoding='utf-8'?>
<geometry>
<cell id="1" material="1" region="-1" universe="1" />
<surface boundary="vacuum" coeffs="0.0 0.0 0.0 10.0" id="1" type="sphere" />
</geometry>
<?xml version='1.0' encoding='utf-8'?>
<materials>
<material depletable="true" id="1">
<density units="g/cm3" value="4.5" />
<nuclide ao="1.0" name="U235" />
</material>
</materials>
<?xml version='1.0' encoding='utf-8'?>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>200</particles>
<batches>10</batches>
<inactive>5</inactive>
<keff_trigger>
<type>std_dev</type>
<threshold>0.002</threshold>
</keff_trigger>
<trigger>
<active>true</active>
<max_batches>1000</max_batches>
<batch_interval>1</batch_interval>
</trigger>
</settings>
<?xml version='1.0' encoding='utf-8'?>
<tallies>
<tally id="1">
<scores>flux</scores>
</tally>
</tallies>

View file

@ -0,0 +1,5 @@
k-combined:
2.909598E-01 6.161987E-03
tally 1:
3.852896E+01
2.976246E+02

View file

@ -0,0 +1,120 @@
import glob
import os
import openmc
import pytest
from tests.testing_harness import PyAPITestHarness
from tests.regression_tests import config
@pytest.fixture
def model():
# Materials
materials = openmc.Materials()
mat = openmc.Material()
mat.set_density('g/cm3', 4.5)
mat.add_nuclide('U235', 1.0)
materials.append(mat)
# Geometry
sph = openmc.Sphere(r=10.0, boundary_type='vacuum')
cell = openmc.Cell(fill=mat, region=-sph)
geometry = openmc.Geometry([cell])
# Settings
settings = openmc.Settings()
settings.run_mode = 'eigenvalue'
settings.batches = 10
settings.inactive = 5
settings.particles = 200
settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.002}
settings.trigger_max_batches = 1000
settings.trigger_batch_interval = 1
settings.trigger_active = True
# Tallies
tallies = openmc.Tallies()
t = openmc.Tally()
t.scores = ['flux']
tallies.append(t)
# Plots (none)
plots = openmc.Plots()
# Put it all together
model = openmc.model.Model(materials=materials,
geometry=geometry,
settings=settings,
tallies=tallies,
plots=plots)
return model
class TriggerStatepointRestartTestHarness(PyAPITestHarness):
def __init__(self, statepoint, model=None):
super().__init__(statepoint, model)
self._restart_sp = None
self._final_sp = None
def _test_output_created(self):
"""Make sure statepoint files have been created."""
spfiles = glob.glob(self._sp_name)
assert len(spfiles) == 2, \
'Two statepoint files should have been created'
if self._final_sp:
# Second restart run
assert spfiles[1] == self._final_sp, \
'Final statepoint names were different'
else:
# First non-restart run
self._restart_sp = spfiles[0]
self._final_sp = spfiles[1]
def execute_test(self):
"""
Perform initial and restart runs using the model.run method,
Check all inputs and outputs which should be the same as those
generated using the normal PyAPITestHarness update methods.
"""
try:
args = {'openmc_exec': config['exe'], 'event_based': config['event']}
if config['mpi']:
args['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']]
# First non-restart run
k_combined_1 = self._model.run(**args)
sp_batchno_1 = 0
with openmc.StatePoint(self._model.statepoint) as sp:
sp_batchno_1 = sp.current_batch
assert sp_batchno_1 > 10
self._write_inputs(self._get_inputs())
self._compare_inputs()
self._test_output_created()
self._write_results(self._get_results())
self._compare_results()
# Second restart run
restart_spfile = glob.glob(os.path.join(os.getcwd(), self._restart_sp))
assert len(restart_spfile) == 1
args['restart_file'] = restart_spfile[0]
k_combined_2 = self._model.run(**args)
sp_batchno_2 = 0
with openmc.StatePoint(self._model.statepoint) as sp:
sp_batchno_2 = sp.current_batch
assert sp_batchno_2 > 10
self._write_inputs(self._get_inputs())
self._compare_inputs()
self._test_output_created()
self._write_results(self._get_results())
self._compare_results()
assert str(k_combined_1) == str(k_combined_2), \
'Different final k_combined after restart'
assert sp_batchno_1 == sp_batchno_2, \
'Different final batch number after restart'
finally:
self._cleanup()
def test_trigger_statepoint_restart(model):
# Assuming we converge within 1000 batches, the statepoint filename
# should include the batch number padded by at least one '0'.
harness = TriggerStatepointRestartTestHarness('statepoint.0*.h5', model)
harness.main()