mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Upgrading tests of model, and adding better file management, Model.calculate_volumes method and Model.plot_geometry method. These last two still need to be tested as well as Model.deplete
This commit is contained in:
parent
d45af5a4ef
commit
e62ba9b85a
5 changed files with 396 additions and 87 deletions
|
|
@ -1,10 +1,25 @@
|
|||
from collections.abc import Iterable
|
||||
from numbers import Integral
|
||||
import subprocess
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
import openmc
|
||||
|
||||
|
||||
@contextmanager
|
||||
def change_directory(working_dir):
|
||||
"""A context manager for executing in a provided working directory"""
|
||||
start_dir = Path().absolute()
|
||||
try:
|
||||
Path.mkdir(working_dir, exist_ok=True)
|
||||
os.chdir(working_dir)
|
||||
yield
|
||||
finally:
|
||||
os.chdir(start_dir)
|
||||
|
||||
|
||||
def _run(args, output, cwd):
|
||||
# Launch a subprocess
|
||||
p = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE,
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ def import_properties(filename):
|
|||
See Also
|
||||
--------
|
||||
openmc.lib.export_properties
|
||||
|
||||
mat
|
||||
"""
|
||||
_dll.openmc_properties_import(filename.encode())
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from pathlib import Path
|
|||
from numbers import Integral
|
||||
import time
|
||||
import warnings
|
||||
import subprocess
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
|
@ -450,8 +451,8 @@ class Model:
|
|||
mats_group = fh['materials']
|
||||
n_cells = mats_group.attrs['n_materials']
|
||||
if n_cells != len(materials):
|
||||
raise ValueError("Number of materials in properties file doesn't "
|
||||
"match current model.")
|
||||
raise ValueError("Number of materials in properties file "
|
||||
"doesn't match current model.")
|
||||
|
||||
# Update material densities
|
||||
for name, group in mats_group.items():
|
||||
|
|
@ -518,65 +519,208 @@ class Model:
|
|||
tstart = time.time()
|
||||
last_statepoint = None
|
||||
|
||||
if self.C_init:
|
||||
# Handle the openmc.run kwargs
|
||||
# First dont allow ones that must be set via init
|
||||
for arg_name, arg, default in zip(
|
||||
['threads', 'geometry_debug', 'restart_file', 'tracks', 'cwd'],
|
||||
[threads, geometry_debug, restart_file, tracks, cwd],
|
||||
[None, False, None, False, '.']):
|
||||
if arg != default:
|
||||
msg = "{} must be set via Model.c_init(...)".format(
|
||||
arg_name)
|
||||
# Operate in the provided working directory
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
if self.C_init:
|
||||
# Handle the run options as applicable
|
||||
# First dont allow ones that must be set via init
|
||||
for arg_name, arg, default in zip(
|
||||
['threads', 'geometry_debug', 'restart_file', 'tracks'],
|
||||
[threads, geometry_debug, restart_file, tracks],
|
||||
[None, False, None, False]):
|
||||
if arg != default:
|
||||
msg = "{} must be set via Model.c_init(...)".format(
|
||||
arg_name)
|
||||
raise ValueError(msg)
|
||||
|
||||
if particles is not None:
|
||||
init_particles = openmc.lib.settings.particles
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
openmc.lib.settings.particles = particles
|
||||
|
||||
# If we dont want output, make the verbosity quiet
|
||||
if not output:
|
||||
init_verbosity = openmc.lib.settings.verbosity
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = 1
|
||||
|
||||
# Event-based can be set at init-time or on a case-basis.
|
||||
# Handle the argument here.
|
||||
# TODO This will be dealt with in a future change to the C-API
|
||||
|
||||
# Then run using the C-API
|
||||
openmc.lib.run()
|
||||
|
||||
# Reset changes for the openmc.run kwargs handling
|
||||
if particles is not None:
|
||||
openmc.lib.settings.particles = init_particles
|
||||
if not output:
|
||||
# Then re-set the initial verbosity
|
||||
openmc.lib.settings.verbosity = init_verbosity
|
||||
|
||||
else:
|
||||
# Then run via the command line
|
||||
self.export_to_xml()
|
||||
openmc.run(particles, threads, geometry_debug, restart_file,
|
||||
tracks, output, Path('.'), openmc_exec, mpi_args,
|
||||
event_based)
|
||||
|
||||
# Get output directory and return the last statepoint written
|
||||
if self.settings.output and 'path' in self.settings.output:
|
||||
output_dir = Path(self.settings.output['path'])
|
||||
else:
|
||||
output_dir = Path.cwd()
|
||||
for sp in output_dir.glob('statepoint.*.h5'):
|
||||
mtime = sp.stat().st_mtime
|
||||
if mtime >= tstart: # >= allows for poor clock resolution
|
||||
tstart = mtime
|
||||
last_statepoint = sp
|
||||
return last_statepoint
|
||||
|
||||
def calculate_volume(self, threads=None, output=True, cwd='.',
|
||||
openmc_exec='openmc', mpi_args=None,
|
||||
apply_volumes=True):
|
||||
"""Runs an OpenMC stochastic volume calculation and, if requested,
|
||||
applies volumes to the model
|
||||
|
||||
Parameters
|
||||
----------
|
||||
threads : int, optional
|
||||
Number of OpenMP threads. If OpenMC is compiled with OpenMP
|
||||
threading enabled, the default is implementation-dependent but is
|
||||
usually equal to the number of hardware threads available (or a
|
||||
value set by the :envvar:`OMP_NUM_THREADS` environment variable).
|
||||
This currenty only applies to the case when not using the C-API.
|
||||
output : bool, optional
|
||||
Capture OpenMC output from standard out
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
This only applies to the case when not using the C-API.
|
||||
mpi_args : list of str, optional
|
||||
MPI execute command and any additional MPI arguments to pass,
|
||||
e.g. ['mpiexec', '-n', '8'].
|
||||
This only applies to the case when not using the C-API.
|
||||
cwd : str, optional
|
||||
Path to working directory to run in. Defaults to the current
|
||||
working directory.
|
||||
apply_volumes : bool, optional
|
||||
Whether apply the volume calculation results from this calculation
|
||||
to the model. Defaults to applying the volumes.
|
||||
"""
|
||||
|
||||
if len(self.settings.volume_calculation) == 0:
|
||||
# Then there is no volume calculation specified
|
||||
raise ValueError("The Settings.volume_calculation attribute must"
|
||||
" be specified before executing this method!")
|
||||
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
if self.C_init:
|
||||
if threads is not None:
|
||||
msg = "Threads must be set via Model.c_init(...)"
|
||||
raise ValueError(msg)
|
||||
if mpi_args is not None:
|
||||
msg = "The MPI environment must be set otherwise such as" \
|
||||
"with the call to mpi4py"
|
||||
raise ValueError(msg)
|
||||
|
||||
if particles is not None:
|
||||
init_particles = openmc.lib.settings.particles
|
||||
if isinstance(particles, Integral) and particles > 0:
|
||||
openmc.lib.settings.particles = particles
|
||||
|
||||
# Now lets handle the ones we can handle
|
||||
if not output:
|
||||
init_verbosity = openmc.lib.settings.verbosity
|
||||
# Apply the output settings
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = 1
|
||||
init_verbosity = openmc.lib.settings.verbosity
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = 1
|
||||
|
||||
# Event-based can be set at init-time or on a case-basis. Handle
|
||||
# the case-basis here.
|
||||
# TODO This will be dealt with in a future change to the C-API
|
||||
# Compute the volumes
|
||||
openmc.lib.calculate_volumes()
|
||||
|
||||
# Then run using the C-API
|
||||
openmc.lib.run()
|
||||
# Reset the output verbosity
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = init_verbosity
|
||||
else:
|
||||
openmc.calculate_volumes(threads=threads, output=output,
|
||||
openmc_exec=openmc_exec,
|
||||
mpi_args=mpi_args)
|
||||
|
||||
# Reset changes for the openmc.run kwargs handling
|
||||
if particles is not None:
|
||||
openmc.lib.settings.particles = init_particles
|
||||
if output is not None:
|
||||
openmc.lib.settings.verbosity = init_verbosity
|
||||
# Now we apply the volumes
|
||||
if apply_volumes:
|
||||
# Load the results
|
||||
f_names = \
|
||||
["volume_{}.h5".format(i + 1)
|
||||
for i in range(len(self.settings.volume_calculations))]
|
||||
vol_calcs = [openmc.VolumeCalculation.load_results(f_name)
|
||||
for f_name in f_names]
|
||||
# And now we can add them to the model
|
||||
for vol_calc in vol_calcs:
|
||||
# First add them to the Python side
|
||||
self.geometry.add_volume_information(vol_calc)
|
||||
|
||||
else:
|
||||
# Then run via the command line
|
||||
self.export_to_xml()
|
||||
openmc.run(particles, threads, geometry_debug, restart_file,
|
||||
tracks, output, cwd, openmc_exec, mpi_args, event_based)
|
||||
# And now repeat for the C-API
|
||||
if vol_calc.domain == 'material':
|
||||
# Then we can do this in the C-API
|
||||
for domain_id in vol_calc.domains:
|
||||
self.update_material_volumes(
|
||||
[domain_id], vol_calc.volumes[domain_id])
|
||||
|
||||
# Get output directory and return the last statepoint written this run
|
||||
if self.settings.output and 'path' in self.settings.output:
|
||||
output_dir = Path(self.settings.output['path'])
|
||||
else:
|
||||
output_dir = Path.cwd()
|
||||
for sp in output_dir.glob('statepoint.*.h5'):
|
||||
mtime = sp.stat().st_mtime
|
||||
if mtime >= tstart: # >= allows for poor clock resolution
|
||||
tstart = mtime
|
||||
last_statepoint = sp
|
||||
return last_statepoint
|
||||
def plot_geometry(self, output=True, cwd='.', openmc_exec='openmc',
|
||||
convert=True, convert_exec='convert'):
|
||||
"""Creates plot images as specified by the Model.plots attribute
|
||||
|
||||
If convert is True, this function requires that a program is installed
|
||||
to convert PPM files to PNG files. Typically, that would be
|
||||
`ImageMagick <https://www.imagemagick.org>`_ which includes a
|
||||
`convert` command.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
output : bool, optional
|
||||
Capture OpenMC output from standard out
|
||||
cwd : str, optional
|
||||
Path to working directory to run in. Defaults to the current
|
||||
working directory.
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable. Defaults to 'openmc'.
|
||||
This only applies to the case when not using the C-API.
|
||||
convert : bool, optional
|
||||
Whether or not to attempt to convert from PPM to PNG
|
||||
convert_exec : str, optional
|
||||
Command that can convert PPM files into PNG files
|
||||
"""
|
||||
|
||||
if len(self.plots) == 0:
|
||||
# Then there is no volume calculation specified
|
||||
raise ValueError("The Model.plots attribute must be specified "
|
||||
"before executing this method!")
|
||||
|
||||
with openmc.change_directory(Path(cwd)):
|
||||
if self.C_init:
|
||||
# Apply the output settings
|
||||
if not output:
|
||||
init_verbosity = openmc.lib.settings.verbosity
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = 1
|
||||
|
||||
# Compute the volumes
|
||||
openmc.lib.plot_geometry()
|
||||
|
||||
# Reset the output verbosity
|
||||
if not output:
|
||||
openmc.lib.settings.verbosity = init_verbosity
|
||||
else:
|
||||
openmc.plot_geometry(output=output, openmc_exec=openmc_exec)
|
||||
|
||||
if convert:
|
||||
for p in self.plots:
|
||||
if p.filename is not None:
|
||||
ppm_file = f'{p.filename}.ppm'
|
||||
else:
|
||||
ppm_file = f'plot_{p.id}.ppm'
|
||||
png_file = ppm_file.replace('.ppm', '.png')
|
||||
subprocess.check_call([convert_exec, ppm_file, png_file])
|
||||
|
||||
def _change_py_C_attribs(self, names_or_ids, value, obj_type, attrib_name,
|
||||
density_units='atom/b-cm'):
|
||||
# Method to do the same work whether it is a cell or material and
|
||||
# a temperature or volume
|
||||
check_type('names_or_ids', names_or_ids, Iterable, (np.int, int, str))
|
||||
check_type('names_or_ids', names_or_ids, Iterable, (Integral, str))
|
||||
check_type('obj_type', obj_type, str)
|
||||
obj_type = obj_type.lower()
|
||||
check_value('obj_type', obj_type, ('material', 'cell'))
|
||||
|
|
@ -588,7 +732,11 @@ class Model:
|
|||
# The C-API has no way to set cell volume so lets raise an exception
|
||||
if obj_type == 'cell' and attrib_name == 'volume':
|
||||
raise NotImplementedError(
|
||||
'Setting a Cell volume is not yet supported!')
|
||||
'Setting a Cell volume is not supported!')
|
||||
# Same with setting temperatures, TODO: update C-API for this
|
||||
if obj_type == 'material' and attrib_name == 'temperature':
|
||||
raise NotImplementedError(
|
||||
'Setting a Material temperature is not yet supported!')
|
||||
# And some items just dont make sense
|
||||
if obj_type == 'cell' and attrib_name == 'density':
|
||||
raise ValueError('Cannot set a Cell density!')
|
||||
|
|
@ -610,12 +758,13 @@ class Model:
|
|||
# only values that have actual ids
|
||||
ids = [None] * len(names_or_ids)
|
||||
for i, name_or_id in enumerate(names_or_ids):
|
||||
if isinstance(name_or_id, (int, np.int)):
|
||||
if isinstance(name_or_id, Integral):
|
||||
if name_or_id in by_id:
|
||||
ids[i] = int(name_or_id)
|
||||
msg = '{} ID {} is not present in the model!'.format(
|
||||
obj_type.capitalize(), name_or_id)
|
||||
raise InvalidIDError(msg)
|
||||
else:
|
||||
msg = '{} ID {} is not present in the model!'.format(
|
||||
obj_type.capitalize(), name_or_id)
|
||||
raise InvalidIDError(msg)
|
||||
elif isinstance(name_or_id, str):
|
||||
if name_or_id in by_name:
|
||||
ids[i] = by_name[name_or_id].id
|
||||
|
|
@ -636,7 +785,7 @@ class Model:
|
|||
elif attrib_name == 'temperature':
|
||||
obj.temperature = value
|
||||
elif attrib_name == 'density':
|
||||
obj.set_density(value, density_units)
|
||||
obj.set_density(density_units, value)
|
||||
# Next lets keep what is in C-API memory up to date as well
|
||||
if self.C_init:
|
||||
C_obj = C_by_id[id_]
|
||||
|
|
@ -645,9 +794,9 @@ class Model:
|
|||
elif attrib_name == 'translation':
|
||||
C_obj.translation = value
|
||||
elif attrib_name == 'volume':
|
||||
C_obj.set_volume = value
|
||||
C_obj.volume = value
|
||||
elif attrib_name == 'temperature':
|
||||
C_obj.set_temperature = value
|
||||
C_obj.set_temperature(value)
|
||||
elif attrib_name == 'density':
|
||||
C_obj.set_density(value, density_units)
|
||||
|
||||
|
|
@ -685,7 +834,7 @@ class Model:
|
|||
|
||||
self._change_py_C_attribs(names_or_ids, vector, 'cell', 'translation')
|
||||
|
||||
def update_densities(self, names_or_ids, density, density_units):
|
||||
def update_densities(self, names_or_ids, density, density_units='atom/b-cm'):
|
||||
"""Update the density of a given set of materials to a new value
|
||||
|
||||
Parameters
|
||||
|
|
@ -695,8 +844,8 @@ class Model:
|
|||
This parameter can include a mix of names and ids.
|
||||
density : float
|
||||
The density to apply in the units specified by `density_units`
|
||||
density_units : {'atom/b-cm', 'g/cm3'}
|
||||
Units for `density`
|
||||
density_units : {'atom/b-cm', 'g/cm3'}, optional
|
||||
Units for `density`. Defaults to 'atom/b-cm'
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -734,3 +883,18 @@ class Model:
|
|||
|
||||
self._change_py_C_attribs(names_or_ids, temperature, 'material',
|
||||
'temperature')
|
||||
|
||||
def update_material_volumes(self, names_or_ids, volume):
|
||||
"""Update the volume of a set of materials to the given value
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names_or_ids : Iterable of str or int
|
||||
The material names (if str) or id (if int) that are to be updated.
|
||||
This parameter can include a mix of names and ids.
|
||||
volume : float
|
||||
The volume to apply in units of cm^3
|
||||
|
||||
"""
|
||||
|
||||
self._change_py_C_attribs(names_or_ids, volume, 'material', 'volume')
|
||||
|
|
|
|||
|
|
@ -28,10 +28,13 @@ def pin_model_attributes():
|
|||
pitch = 1.25984
|
||||
fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR')
|
||||
clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR')
|
||||
box = openmc.model.rectangular_prism(pitch, pitch, boundary_type='reflective')
|
||||
box = openmc.model.rectangular_prism(pitch, pitch,
|
||||
boundary_type='reflective')
|
||||
|
||||
# Define cells
|
||||
fuel = openmc.Cell(name='fuel', fill=uo2, region=-fuel_or)
|
||||
fuel_inf_cell = openmc.Cell(name='inf fuel', fill=uo2)
|
||||
fuel_inf_univ = openmc.Universe(cells=[fuel_inf_cell])
|
||||
fuel = openmc.Cell(name='fuel', fill=fuel_inf_univ, region=-fuel_or)
|
||||
clad = openmc.Cell(fill=zirc, region=+fuel_or & -clad_or)
|
||||
water = openmc.Cell(fill=borated_water, region=+clad_or & box)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Type
|
||||
import numpy as np
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import openmc
|
||||
|
|
@ -6,7 +6,7 @@ import openmc.lib
|
|||
|
||||
|
||||
def test_init(run_in_tmpdir, pin_model_attributes):
|
||||
mats, geom, settings, tals, plots, chain, fission_q, _ = \
|
||||
mats, geom, settings, tals, plots, chain, fission_q, _ = \
|
||||
pin_model_attributes
|
||||
|
||||
openmc.reset_auto_ids()
|
||||
|
|
@ -44,13 +44,16 @@ def test_init(run_in_tmpdir, pin_model_attributes):
|
|||
assert test_model._materials_by_id == {1: mats[0], 2: mats[1], 3: mats[2]}
|
||||
assert test_model._materials_by_name == {'UO2': mats[0], 'Zirc': mats[1],
|
||||
'Borated water': mats[2]}
|
||||
assert test_model._cells_by_id == {1: geom.root_universe.cells[1],
|
||||
2: geom.root_universe.cells[2],
|
||||
3: geom.root_universe.cells[3]}
|
||||
# The last cell is the one that contains the infinite fuel
|
||||
assert test_model._cells_by_id == \
|
||||
{2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3],
|
||||
4: geom.root_universe.cells[4],
|
||||
1: geom.root_universe.cells[2].fill.cells[1]}
|
||||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': geom.root_universe.cells[1], '': geom.root_universe.cells[3]}
|
||||
'fuel': geom.root_universe.cells[2], '': geom.root_universe.cells[4],
|
||||
'inf fuel': geom.root_universe.cells[2].fill.cells[1]}
|
||||
assert test_model.C_init is False
|
||||
|
||||
# Finally test the parameter type checking by passing bad types and
|
||||
|
|
@ -79,13 +82,16 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
test_model = openmc.Model.from_xml()
|
||||
assert test_model.geometry.root_universe.cells.keys() == \
|
||||
geom.root_universe.cells.keys()
|
||||
assert [c.fill.name for c in test_model.geometry.root_universe.cells.values()] == \
|
||||
assert [c.fill.name for c in
|
||||
test_model.geometry.root_universe.cells.values()] == \
|
||||
[c.fill.name for c in geom.root_universe.cells.values()]
|
||||
assert [mat.name for mat in test_model.materials] == [mat.name for mat in mats]
|
||||
assert [mat.name for mat in test_model.materials] == \
|
||||
[mat.name for mat in mats]
|
||||
# We will assume the attributes of settings that are custom objects are
|
||||
# OK if the others are so we dotn need to implement explicit comparisons
|
||||
no_test = ['_source', '_entropy_mesh']
|
||||
assert sorted(k for k in test_model.settings.__dict__.keys() if k not in no_test) == \
|
||||
assert sorted(k for k in test_model.settings.__dict__.keys()
|
||||
if k not in no_test) == \
|
||||
sorted(k for k in settings.__dict__.keys() if k not in no_test)
|
||||
keys = sorted(k for k in settings.__dict__.keys() if k not in no_test)
|
||||
for ref_k in keys:
|
||||
|
|
@ -100,15 +106,17 @@ def test_from_xml(run_in_tmpdir, pin_model_attributes):
|
|||
assert test_model._materials_by_name == {
|
||||
'UO2': test_model.materials[0], 'Zirc': test_model.materials[1],
|
||||
'Borated water': test_model.materials[2]}
|
||||
assert test_model._cells_by_id == {\
|
||||
1: test_model.geometry.root_universe.cells[1],
|
||||
assert test_model._cells_by_id == {
|
||||
2: test_model.geometry.root_universe.cells[2],
|
||||
3: test_model.geometry.root_universe.cells[3]}
|
||||
3: test_model.geometry.root_universe.cells[3],
|
||||
4: test_model.geometry.root_universe.cells[4],
|
||||
1: test_model.geometry.root_universe.cells[2].fill.cells[1]}
|
||||
# No cell name for 2 and 3, so we expect a blank name to be assigned to
|
||||
# cell 3 due to overwriting
|
||||
assert test_model._cells_by_name == {
|
||||
'fuel': test_model.geometry.root_universe.cells[1],
|
||||
'': test_model.geometry.root_universe.cells[3]}
|
||||
'fuel': test_model.geometry.root_universe.cells[2],
|
||||
'': test_model.geometry.root_universe.cells[4],
|
||||
'inf fuel': test_model.geometry.root_universe.cells[2].fill.cells[1]}
|
||||
assert test_model.C_init is False
|
||||
|
||||
|
||||
|
|
@ -163,13 +171,26 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
cell.set_temperature(600.0)
|
||||
cell.fill.set_density(5.0, 'g/cm3')
|
||||
openmc.lib.export_properties()
|
||||
|
||||
# Import properties to existing model
|
||||
model.import_properties("properties.h5")
|
||||
|
||||
# Check to see that values are assigned to the C and python representations
|
||||
# First python
|
||||
cell = model.geometry.get_all_cells()[1]
|
||||
assert cell.temperature == [600.0]
|
||||
assert cell.fill.get_mass_density() == pytest.approx(5.0)
|
||||
# Now C
|
||||
assert openmc.lib.cells[1].get_temperature() == 600.
|
||||
assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0)
|
||||
|
||||
# Clear the C-API
|
||||
openmc.lib.finalize()
|
||||
|
||||
# Import properties to existing model and re-export to new directory
|
||||
model.import_properties("properties.h5")
|
||||
# Verify the attributes survived by exporting to XML and re-creating
|
||||
model.export_to_xml("with_properties")
|
||||
|
||||
# Load model with properties and confirm temperature/density has been changed
|
||||
# Load model with properties and confirm temperature/density changed
|
||||
model_with_properties = openmc.Model.from_xml(
|
||||
'with_properties/geometry.xml',
|
||||
'with_properties/materials.xml',
|
||||
|
|
@ -183,10 +204,6 @@ def test_import_properties(run_in_tmpdir, mpi_intracomm):
|
|||
def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
# Set the depletion module to use the test intracomm as the depletion mods
|
||||
# intracomm is the one that init uses. We will not perturb system state
|
||||
# outside of this test by re-setting the openmc.deplete.comm to what it was
|
||||
# before when we exist
|
||||
|
||||
# This case will run by getting the k-eff and tallies for command-line and
|
||||
# C-API execution modes and ensuring they give the same result.
|
||||
|
|
@ -196,6 +213,10 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
cli_flux = sp.get_tally(id=1).get_values()[0, 0, 0]
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
# Set the depletion module to use the test intracomm as the depletion
|
||||
# module's intracomm is the one that init uses. We will not perturb
|
||||
# system state outside of this test by re-setting the
|
||||
# openmc.deplete.comm to what it was before when we exist
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
|
|
@ -205,8 +226,8 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
C_flux = sp.get_tally(id=1).get_values()[0, 0, 0]
|
||||
|
||||
# and lets compare results
|
||||
assert (C_keff - cli_keff) < 1e-15
|
||||
assert (C_flux - cli_flux) < 1e-13
|
||||
assert abs(C_keff - cli_keff) < 1e-15
|
||||
assert abs(C_flux - cli_flux) < 1e-13
|
||||
|
||||
# Now we should make sure that the flags for items which should be handled
|
||||
# by init are properly set
|
||||
|
|
@ -218,8 +239,6 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
test_model.run(restart_file='1.h5')
|
||||
with pytest.raises(ValueError):
|
||||
test_model.run(tracks=True)
|
||||
with pytest.raises(ValueError):
|
||||
test_model.run(cwd='hi')
|
||||
|
||||
test_model.clear_C_api()
|
||||
|
||||
|
|
@ -228,3 +247,111 @@ def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
|||
openmc.deplete.comm = orig_comm
|
||||
|
||||
|
||||
def test_py_C_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
|
||||
mats, geom, settings, tals, plots, _, _, _ = pin_model_attributes
|
||||
test_model = openmc.Model(geom, mats, settings, tals, plots)
|
||||
|
||||
if mpi_intracomm is not None:
|
||||
# Set the depletion module to use the test intracomm as the depletion
|
||||
# module's intracomm is the one that init uses. We will not perturb
|
||||
# system state outside of this test by re-setting the
|
||||
# openmc.deplete.comm to what it was before when we exist
|
||||
orig_comm = openmc.deplete.comm
|
||||
openmc.deplete.comm = mpi_intracomm
|
||||
test_model.init_C_api()
|
||||
|
||||
# Now we can call rotate_cells, translate_cells, update_densities,
|
||||
# update_cell_temperatures, and update_material_temperatures and make sure
|
||||
# the changes have taken hold.
|
||||
# For each we will first try bad inputs to make sure we get the right
|
||||
# errors and then we do a good one which calls the material by name and
|
||||
# then id to make sure it worked
|
||||
|
||||
# The rotate_cells and translate_cells will work on the cell named fill, as
|
||||
# it is filled with a universe and thus the operation will be valid
|
||||
|
||||
# First rotate_cells
|
||||
with pytest.raises(TypeError):
|
||||
# Make sure it tells us we have a bad names_or_ids type
|
||||
test_model.rotate_cells(None, (0, 0, 90))
|
||||
with pytest.raises(TypeError):
|
||||
test_model.rotate_cells([None], (0, 0, 90))
|
||||
with pytest.raises(openmc.exceptions.InvalidIDError):
|
||||
# Make sure it tells us we had a bad id
|
||||
test_model.rotate_cells([7200], (0, 0, 90))
|
||||
with pytest.raises(openmc.exceptions.InvalidIDError):
|
||||
# Make sure it tells us we had a bad id
|
||||
test_model.rotate_cells(['bad_name'], (0, 0, 90))
|
||||
# Now a good one
|
||||
assert np.all(openmc.lib.cells[2].rotation == (0., 0., 0.))
|
||||
test_model.rotate_cells([2], (0, 0, 90))
|
||||
assert np.all(openmc.lib.cells[2].rotation == (0., 0., 90.))
|
||||
|
||||
# And same thing by name
|
||||
test_model.rotate_cells(['fuel'], (0, 0, 180))
|
||||
|
||||
# Now translate_cells. We dont need to re-check the TypeErrors/bad ids,
|
||||
# because the other functions use the same hidden method as rotate_cells
|
||||
assert np.all(openmc.lib.cells[2].translation == (0., 0., 0.))
|
||||
test_model.translate_cells([2], (0, 0, 10))
|
||||
assert np.all(openmc.lib.cells[2].translation == (0., 0., 10.))
|
||||
|
||||
# Now lets do the density updates.
|
||||
# Check initial conditions
|
||||
assert abs(openmc.lib.materials[1].get_density(
|
||||
'atom/b-cm') - 0.06891296988603757) < 1e-13
|
||||
mat_a_dens = np.sum(
|
||||
[v[1] for v in test_model.materials[0].
|
||||
get_nuclide_atom_densities().values()])
|
||||
assert abs(mat_a_dens - 0.06891296988603757) < 1e-8
|
||||
# Change the density
|
||||
test_model.update_densities(['UO2'], 2.)
|
||||
assert abs(openmc.lib.materials[1].get_density('atom/b-cm') - 2.) < 1e-13
|
||||
mat_a_dens = np.sum(
|
||||
[v[1] for v in test_model.materials[0].
|
||||
get_nuclide_atom_densities().values()])
|
||||
assert abs(mat_a_dens - 2.) < 1e-8
|
||||
|
||||
# Now lets do the cell temperature updates.
|
||||
# Check initial conditions
|
||||
|
||||
assert test_model._cells_by_id == \
|
||||
{2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3],
|
||||
4: geom.root_universe.cells[4],
|
||||
1: geom.root_universe.cells[2].fill.cells[1]}
|
||||
assert abs(openmc.lib.cells[3].get_temperature() - 293.6) < 1e-13
|
||||
assert test_model.geometry.root_universe.cells[3].temperature is None
|
||||
# Change the temperature
|
||||
test_model.update_cell_temperatures([3], 600.)
|
||||
assert abs(openmc.lib.cells[3].get_temperature() - 600.) < 1e-13
|
||||
assert abs(test_model.geometry.root_universe.cells[3].temperature -
|
||||
600.) < 1e-13
|
||||
|
||||
# Now lets do the material temperature updates.
|
||||
# Check initial conditions
|
||||
with pytest.raises(NotImplementedError):
|
||||
test_model.update_material_temperatures(['UO2'], 600.)
|
||||
# TODO: When C-API material.set_temperature is implemented, uncomment below
|
||||
# assert abs(openmc.lib.materials[1].temperature - 293.6) < 1e-13
|
||||
# # The temperature on the material will be None because its just the
|
||||
# # default assert test_model.materials[0].temperature is None
|
||||
# # Change the temperature
|
||||
# test_model.update_material_temperatures(['UO2'], 600.)
|
||||
# assert abs(openmc.lib.materials[1].temperature - 600.) < 1e-13
|
||||
# assert abs(test_model.materials[0].temperature - 600.) < 1e-13
|
||||
|
||||
# And finally material volume
|
||||
# import pdb; pdb.set_trace()
|
||||
assert abs(openmc.lib.materials[1].volume - 0.4831931368640985) < 1e-13
|
||||
# The temperature on the material will be None because its just the default
|
||||
assert abs(test_model.materials[0].volume - 0.4831931368640985) < 1e-13
|
||||
# Change the temperature
|
||||
test_model.update_material_volumes(['UO2'], 2.)
|
||||
assert abs(openmc.lib.materials[1].volume - 2.) < 1e-13
|
||||
assert abs(test_model.materials[0].volume - 2.) < 1e-13
|
||||
|
||||
test_model.clear_C_api()
|
||||
|
||||
# And before done, reset the deplete communicator
|
||||
if mpi_intracomm is not None:
|
||||
openmc.deplete.comm = orig_comm
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue