Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serpent material temps #178

Merged
merged 14 commits into from
Jan 9, 2023
6 changes: 4 additions & 2 deletions doc/releasenotes/v0.5.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,15 @@ Python API Changes
- ``write_mat_file()`` → ``update_depletable_materials()``
- ``get_nuc_name()`` → ``convert_nuclide_code_to_name()``
- ``convert_nuclide_name_serpent_to_zam()`` → ``convert_nuclide_code_to_zam()``
- ``change_sim_par()`` → (deleted)
- (new function) → ``get_neutron_settings()``
- ``create_iter_matfile()`` → ``create_runtime_matfile()``
- ``replace_burnup_parameters()`` → ``set_power_load()``
- ``write_depcode_input()`` → ``write_runtime_input()``
- ``iter_inputfile`` → ``runtime_inputfile``
- ``iter_matfile`` → ``runtime_matfile``
- ``change_sim_par()`` → (deleted)
- (new function) → ``get_neutron_settings()``
- (new function) → ``_get_burnable_materials_file()``
- (new function) → ``_get_burnable_material_card_data()``


- ``OpenMCDepcode`` is a ``Depcode`` subclass that interfaces with ``openmc``. This class implements the following functions
Expand Down
68 changes: 49 additions & 19 deletions saltproc/serpent_depcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class SerpentDepcode(Depcode):
inactive_cycles : int
Number of inactive cycles.


"""

def __init__(self,
Expand Down Expand Up @@ -95,7 +94,7 @@ def get_neutron_settings(self, file_lines):

def create_runtime_matfile(self, file_lines):
"""Creates the runtime material file tracking burnable materials
ans inserts the path to this file in the Serpent2 runtime input file
and inserts the path to this file in the Serpent2 runtime input file

Parameters
----------
Expand All @@ -108,6 +107,20 @@ def create_runtime_matfile(self, file_lines):
Serpent2 runtime input file with updated material file path.

"""
burnable_materials_path, absolute_path = self._get_burnable_materials_file(file_lines)

# Create data directory
Path.mkdir(Path(self.runtime_matfile).parents[0], exist_ok=True)

# Get material cards
flines = self.read_plaintext_file(absolute_path)
self._get_burnable_material_card_data(flines)

# Create file with path for SaltProc rewritable iterative material file
shutil.copy2(absolute_path, self.runtime_matfile)
return [line.replace(burnable_materials_path, self.runtime_matfile) for line in file_lines]

def _get_burnable_materials_file(self, file_lines):
runtime_dir = Path(self.template_input_file_path).parents[0]
include_card = [line for line in file_lines if line.startswith("include ")]
if not include_card:
Expand All @@ -119,17 +132,30 @@ def create_runtime_matfile(self, file_lines):
absolute_path = (runtime_dir / burnable_materials_path)
else:
absolute_path = Path(burnable_materials_path)
with open(absolute_path) as f:
if 'mat ' not in f.read():
raise IOError('Template file '
f'{self.template_input_file_path} includes '
'no file with materials description')
# Create data directory
Path.mkdir(Path(self.runtime_matfile).parents[0], exist_ok=True)

# Create file with path for SaltProc rewritable iterative material file
shutil.copy2(absolute_path, self.runtime_matfile)
return [line.replace(burnable_materials_path, self.runtime_matfile) for line in file_lines]
with open(absolute_path) as f:
if 'mat ' not in f.read():
raise IOError('Template file '
f'{self.template_input_file_path} includes '
'no file with materials description')
return burnable_materials_path, absolute_path.resolve()

def _get_burnable_material_card_data(self, file_lines):
# Get data for matfile
mat_cards = \
[line.split() for line in file_lines if line.startswith("mat ")]

for card in mat_cards:
if 'fix' not in card:
raise IOError(f'"mat" card for burnable material "{card[1]}"'
' does not have a "fix" option. Burnable materials'
' in SaltProc must include the "fix" option. See'
' the serpent wiki for more information:'
' https://serpent.vtt.fi/mediawiki/index.php/Input_syntax_manual#mat')
# Get volume indices
card_volume_idx = [(card.index('vol') + 1) for card in mat_cards]
mat_names = [card[1] for card in mat_cards]
mat_data = zip(mat_cards, card_volume_idx)#, mat_extensions)
self._burnable_material_card_data = dict(zip(mat_names, mat_data))

def convert_nuclide_code_to_name(self, nuc_code):
"""Converts Serpent2 nuclide code to symbolic nuclide name.
Expand Down Expand Up @@ -520,13 +546,17 @@ def update_depletable_materials(self, mats, dep_end_time):
f.write('%% Material compositions (after %f days)\n\n'
% dep_end_time)
nuc_code_map = self.map_nuclide_code_zam_to_serpent()
if not(hasattr(self, '_burnable_material_card_data')):
lines = self.read_plaintext_file(self.template_input_file_path)
_, abs_src_matfile = self.get_burnable_materials_file(lines)
file_lines = self.read_plaintext_file(abs_src_matfile)
self._get_burnable_material_card_data(file_lines)
for name, mat in mats.items():
f.write('mat %s %5.9E burn 1 fix %3s %4i vol %7.5E\n' %
(name,
-mat.density,
'09c',
mat.temp,
mat.vol))
mat_card, card_volume_idx = self._burnable_material_card_data[name]
mat_card[2] = str(-mat.density)
mat_card[card_volume_idx] = "%7.5E" % mat.vol
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a hardcoded value. Is this the case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this is string formatting

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was thinking. Just wanted to make sure it wasn't hard coding any values.

f.write(" ".join(mat_card))
f.write("\n")
for nuc_code, mass_fraction in mat.comp.items():
zam_code = pyname.zzaaam(nuc_code)
f.write(' %9s %7.14E\n' %
Expand Down
47 changes: 47 additions & 0 deletions tests/integration_tests/file_interface_serpent/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,53 @@ def test_runtime_input_from_template(serpent_depcode, msr):
file_data = serpent_depcode.create_runtime_matfile(file_data)
assert file_data[0].split()[-1] == '\"' + \
serpent_depcode.runtime_matfile + '\"'

# get_burnable_material_card_data
burnable_material_card_data = {'fuel':
(['mat',
'fuel',
'-4.960200000E+00',
'rgb',
'253',
'231',
'37',
'burn',
'1',
'fix',
'09c',
'900',
'vol',
'4.435305E+7',
'%',
'just',
'core',
'volume',
'2.27175E+07'], 13),
'ctrlPois':
(['mat',
'ctrlPois',
'-2.52',
'burn',
'1',
'fix',
'09c',
'900',
'rgb',
'255',
'128',
'0',
'vol',
'1.11635E+04'], 13)}

for ref_key, test_key in \
zip(serpent_depcode._burnable_material_card_data.keys(),
burnable_material_card_data.keys()):
assert ref_key == test_key
ref_data = serpent_depcode._burnable_material_card_data[ref_key]
test_data = burnable_material_card_data[test_key]
np.testing.assert_array_equal(np.array(ref_data, dtype=object),
np.array(test_data, dtype=object))

remove(serpent_depcode.runtime_matfile)

# set_power_load
Expand Down
33 changes: 33 additions & 0 deletions tests/unit_tests/test_serpent_depcode.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Test SerpentDepcode functions"""
import pytest
import numpy as np
import tempfile
from pathlib import Path

from saltproc import SerpentDepcode

Expand Down Expand Up @@ -35,6 +37,37 @@ def test_get_neutron_settings(serpent_depcode):
assert serpent_depcode.active_cycles == 20
assert serpent_depcode.inactive_cycles == 20

def test_get_burnable_materials_file(serpent_depcode):
err1 = (f'Template file {serpent_depcode.template_input_file_path}'
' has no <include "material_file"> statements')

with pytest.raises(IOError, match=err1):
lines_no_include = ['this line does not start with include']
serpent_depcode._get_burnable_materials_file(lines_no_include)

with tempfile.NamedTemporaryFile(mode='w+') as tf:
tf.write('some junk')
old_template = serpent_depcode.template_input_file_path
serpent_depcode.template_input_file_path = tf.name

err2 = (f'Template file {serpent_depcode.template_input_file_path}'
' includes no file with materials description')
with pytest.raises(IOError, match=err2):
lines_bad_matfile = [f'include "{tf.name}"']
serpent_depcode._get_burnable_materials_file(lines_bad_matfile)
serpent_depcode.template_input_file_path = old_template

def test_get_burnable_material_card_data(serpent_depcode):
bad_mat_cards = ['mat fuel -9.2 burn 1 fix 09c',
'mat blanket -9.1 burn 1']

err = ('"mat" card for burnable material "blanket" does not have a "fix"'
' option. Burnable materials in SaltProc must include the "fix"'
' option. See the serpent wiki for more information:'
' https://serpent.vtt.fi/mediawiki/index.php/Input_syntax_manual#mat')
with pytest.raises(IOError, match=err):
serpent_depcode._get_burnable_material_card_data(bad_mat_cards)


def test_read_plaintext_file(serpent_depcode):
template_str = serpent_depcode.read_plaintext_file(
Expand Down