Merge pull request #2291 from pshriwise/model-xml

Support for a single `model.xml` file
This commit is contained in:
Paul Romano 2022-12-24 13:33:27 -06:00 committed by GitHub
commit 3f8f8f6701
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 1284 additions and 372 deletions

View file

@ -0,0 +1,38 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<material depletable="true" id="1">
<density units="g/cc" value="10.0" />
<nuclide ao="1.0" name="U235" />
</material>
<material id="2">
<density units="g/cc" value="0.1" />
<nuclide ao="0.1" name="H1" />
</material>
</materials>
<geometry>
<cell id="1" material="1" region="-1" universe="1" />
<cell id="2" material="2" region="1" universe="1" />
<cell fill="1" id="3" region="2 -3 4 -5 6 -8" rotation="10 20 30" universe="2" />
<cell fill="1" id="4" region="2 -3 4 -5 8 -7" translation="0 0 15" universe="2" />
<surface coeffs="1.0 0.0 0.0 5.0" id="1" type="sphere" />
<surface boundary="vacuum" coeffs="-7.5" id="2" name="minimum x" type="x-plane" />
<surface boundary="vacuum" coeffs="7.5" id="3" name="maximum x" type="x-plane" />
<surface boundary="vacuum" coeffs="-7.5" id="4" name="minimum y" type="y-plane" />
<surface boundary="vacuum" coeffs="7.5" id="5" name="maximum y" type="y-plane" />
<surface boundary="vacuum" coeffs="-7.5" id="6" type="z-plane" />
<surface boundary="vacuum" coeffs="22.5" id="7" type="z-plane" />
<surface coeffs="7.5" id="8" type="z-plane" />
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>10000</particles>
<batches>10</batches>
<inactive>5</inactive>
<source strength="1.0">
<space type="box">
<parameters>-4.0 -4.0 -4.0 4.0 4.0 4.0</parameters>
</space>
</source>
</settings>
</model>

View file

@ -0,0 +1,23 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<material depletable="true" id="1">
<density units="g/cm3" value="20.0" />
<nuclide ao="1.0" name="U233" />
<nuclide ao="1.0" name="Am244" />
<nuclide ao="1.0" name="H2" />
<nuclide ao="1.0" name="Na23" />
<nuclide ao="1.0" name="Ta181" />
</material>
</materials>
<geometry>
<cell id="1" material="1" region="-1" universe="1" />
<surface boundary="reflective" coeffs="0.0 0.0 0.0 100.0" id="1" type="sphere" />
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>1000</particles>
<batches>10</batches>
<inactive>5</inactive>
</settings>
</model>

View file

@ -0,0 +1,67 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<material id="6">
<density units="g/cm3" value="2.6989" />
<nuclide ao="1.0" name="Al27" />
</material>
</materials>
<geometry>
<cell id="12" material="void" region="-16 17 -18" universe="10" />
<cell id="13" material="6" region="-16 18 -19" universe="10" />
<cell id="14" material="void" region="~(-16 17 -19)" universe="10" />
<surface id="16" type="x-cylinder" boundary="vacuum" coeffs="0.0 0.0 1.0" />
<surface id="17" type="x-plane" boundary="vacuum" coeffs="-1.0" />
<surface id="18" type="x-plane" coeffs="1.0" />
<surface id="19" type="x-plane" boundary="vacuum" coeffs="1000000000.0" />
</geometry>
<settings>
<run_mode>fixed source</run_mode>
<particles>10000</particles>
<batches>1</batches>
<source strength="1.0">
<space type="point">
<parameters>0 0 0</parameters>
</space>
<angle type="monodirectional" reference_uvw="1.0 0.0 0.0" />
<energy type="discrete">
<parameters>14000000.0 1.0</parameters>
</energy>
</source>
<electron_treatment>ttb</electron_treatment>
<photon_transport>true</photon_transport>
<cutoff>
<energy_photon>1000.0</energy_photon>
</cutoff>
</settings>
<tallies>
<filter id="1" type="surface">
<bins>16</bins>
</filter>
<filter id="2" type="particle">
<bins>neutron photon electron positron</bins>
</filter>
<tally id="1">
<filters>1 2</filters>
<scores>current</scores>
</tally>
<tally id="2">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total (n,gamma)</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="3">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total heating (n,gamma)</scores>
<estimator>collision</estimator>
</tally>
<tally id="4">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total heating (n,gamma)</scores>
<estimator>analog</estimator>
</tally>
</tallies>
</model>

View file

@ -0,0 +1,53 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<material depletable="true" id="1" name="UO2">
<density units="g/cm3" value="10.0" />
<nuclide ao="1.0" name="U235" />
<nuclide ao="2.0" name="O16" />
</material>
<material id="2" name="light water">
<density units="g/cm3" value="1.0" />
<nuclide ao="2.0" name="H1" />
<nuclide ao="1.0" name="O16" />
<sab name="c_H_in_H2O" />
</material>
</materials>
<geometry>
<cell id="1" material="1" region="-1" universe="1" />
<cell id="2" material="2" region="1" universe="1" />
<cell id="3" material="1" region="-2" universe="2" />
<cell id="4" material="2" region="2" universe="2" />
<cell fill="3" id="5" universe="4" />
<cell fill="5" id="6" region="3 -4 5 -6" universe="6" />
<lattice id="3">
<pitch>1.2 1.2</pitch>
<outer>1</outer>
<dimension>2 2</dimension>
<lower_left>-1.2 -1.2</lower_left>
<universes>
2 1
1 1 </universes>
</lattice>
<lattice id="5">
<pitch>2.4 2.4</pitch>
<dimension>2 2</dimension>
<lower_left>-2.4 -2.4</lower_left>
<universes>
4 4
4 4 </universes>
</lattice>
<surface coeffs="0.0 0.0 0.4" id="1" type="z-cylinder" />
<surface coeffs="0.0 0.0 0.5" id="2" type="z-cylinder" />
<surface boundary="reflective" coeffs="-2.4" id="3" name="minimum x" type="x-plane" />
<surface boundary="reflective" coeffs="2.4" id="4" name="maximum x" type="x-plane" />
<surface boundary="reflective" coeffs="-2.4" id="5" name="minimum y" type="y-plane" />
<surface boundary="reflective" coeffs="2.4" id="6" name="maximum y" type="y-plane" />
</geometry>
<settings>
<run_mode>eigenvalue</run_mode>
<particles>1000</particles>
<batches>10</batches>
<inactive>5</inactive>
</settings>
</model>

View file

@ -0,0 +1,67 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<material id="1">
<density units="g/cm3" value="2.6989" />
<nuclide ao="1.0" name="Al27" />
</material>
</materials>
<geometry>
<cell id="1" material="void" region="-1 2 -3" universe="1" />
<cell id="2" material="1" region="-1 3 -4" universe="1" />
<cell id="3" material="void" region="~(-1 2 -4)" universe="1" />
<surface boundary="vacuum" coeffs="0.0 0.0 1.0" id="1" type="x-cylinder" />
<surface boundary="vacuum" coeffs="-1.0" id="2" type="x-plane" />
<surface coeffs="1.0" id="3" type="x-plane" />
<surface boundary="vacuum" coeffs="1000000000.0" id="4" type="x-plane" />
</geometry>
<settings>
<run_mode>fixed source</run_mode>
<particles>10000</particles>
<batches>1</batches>
<source strength="1.0">
<space type="point">
<parameters>0 0 0</parameters>
</space>
<angle reference_uvw="1.0 0.0 0.0" type="monodirectional" />
<energy type="discrete">
<parameters>14000000.0 1.0</parameters>
</energy>
</source>
<electron_treatment>ttb</electron_treatment>
<photon_transport>true</photon_transport>
<cutoff>
<energy_photon>1000.0</energy_photon>
</cutoff>
</settings>
<tallies>
<filter id="1" type="surface">
<bins>1</bins>
</filter>
<filter id="2" type="particle">
<bins>neutron photon electron positron</bins>
</filter>
<tally id="1">
<filters>1 2</filters>
<scores>current</scores>
</tally>
<tally id="2">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total (n,gamma)</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="3">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total heating (n,gamma)</scores>
<estimator>collision</estimator>
</tally>
<tally id="4">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total heating (n,gamma)</scores>
<estimator>analog</estimator>
</tally>
</tallies>
</model>

View file

@ -0,0 +1,100 @@
from difflib import unified_diff
import glob
import filecmp
import os
from pathlib import Path
import openmc
import pytest
from tests.testing_harness import PyAPITestHarness, colorize
# use a few models from other tests to make sure the same results are
# produced when using a single model.xml file as input
from ..adj_cell_rotation.test import model as adj_cell_rotation_model
from ..lattice_multiple.test import model as lattice_multiple_model
from ..energy_laws.test import model as energy_laws_model
from ..photon_production.test import model as photon_production_model
class ModelXMLTestHarness(PyAPITestHarness):
"""Accept a results file to check against and assume inputs_true is the contents of a model.xml file.
"""
def __init__(self, model=None, inputs_true=None, results_true=None):
statepoint_name = f'statepoint.{model.settings.batches}.h5'
super().__init__(statepoint_name, model, inputs_true)
self.results_true = 'results_true.dat' if results_true is None else results_true
def _build_inputs(self):
self._model.export_to_model_xml()
def _get_inputs(self):
return open('model.xml').read()
def _compare_results(self):
"""Make sure the current results agree with the reference."""
compare = filecmp.cmp('results_test.dat', self.results_true)
if not compare:
expected = open(self.results_true).readlines()
actual = open('results_test.dat').readlines()
diff = unified_diff(expected, actual, self.results_true,
'results_test.dat')
print('Result differences:')
print(''.join(colorize(diff)))
os.rename('results_test.dat', 'results_error.dat')
assert compare, 'Results do not agree'
def _cleanup(self):
super()._cleanup()
if os.path.exists('model.xml'):
os.remove('model.xml')
test_names = [
'adj_cell_rotation',
'lattice_multiple',
'energy_laws',
'photon_production'
]
@pytest.mark.parametrize("test_name", test_names, ids=lambda test: test)
def test_model_xml(test_name, request):
openmc.reset_auto_ids()
test_path = '../' + test_name
results = test_path + "/results_true.dat"
inputs = test_name + "_inputs_true.dat"
model_name = test_name + "_model"
harness = ModelXMLTestHarness(request.getfixturevalue(model_name), inputs, results)
harness.main()
def test_input_arg(run_in_tmpdir):
pincell = openmc.examples.pwr_pin_cell()
pincell.settings.particles = 100
# export to separate XML files and run
pincell.export_to_xml()
openmc.run()
# make sure the executable isn't falling back on the separate XMLs
for f in glob.glob('*.xml'):
os.remove(f)
# now export to a single XML file with a custom name
pincell.export_to_model_xml('pincell.xml')
assert Path('pincell.xml').exists()
# run by specifying that single file
openmc.run(path_input='pincell.xml')
# check that this works for plotting too
openmc.plot_geometry(path_input='pincell.xml')
# now ensure we get an error for an incorrect filename,
# even in the presence of other, valid XML files
pincell.export_to_model_xml()
with pytest.raises(RuntimeError, match='ex-em-ell.xml'):
openmc.run(path_input='ex-em-ell.xml')

View file

@ -1,5 +1,6 @@
from math import pi
from pathlib import Path
import os
import numpy as np
import pytest
@ -529,3 +530,40 @@ def test_calc_volumes(run_in_tmpdir, pin_model_attributes, mpi_intracomm):
assert openmc.lib.materials[3].volume == mats[2].volume
test_model.finalize_lib()
def test_model_xml(run_in_tmpdir):
# load a model from examples
pwr_model = openmc.examples.pwr_core()
# export to separate XMLs manually
pwr_model.settings.export_to_xml('settings_ref.xml')
pwr_model.materials.export_to_xml('materials_ref.xml')
pwr_model.geometry.export_to_xml('geometry_ref.xml')
# now write and read a model.xml file
pwr_model.export_to_model_xml()
new_model = openmc.Model.from_model_xml()
# make sure we can also export this again to separate
# XML files
new_model.export_to_xml()
def test_single_xml_exec(run_in_tmpdir):
pincell_model = openmc.examples.pwr_pin_cell()
pincell_model.export_to_model_xml('pwr_pincell.xml')
openmc.run(path_input='pwr_pincell.xml')
with pytest.raises(RuntimeError, match='ex-em-ell.xml'):
openmc.run(path_input='ex-em-ell.xml')
# test that a file in a different directory can be used
os.mkdir('inputs')
pincell_model.export_to_model_xml('./inputs/pincell.xml')
openmc.run(path_input='./inputs/pincell.xml')
with pytest.raises(RuntimeError, match='input_dir'):
openmc.run(path_input='input_dir/pincell.xml')