mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Merge pull request #2291 from pshriwise/model-xml
Support for a single `model.xml` file
This commit is contained in:
commit
3f8f8f6701
32 changed files with 1284 additions and 372 deletions
0
tests/regression_tests/model_xml/__init__.py
Normal file
0
tests/regression_tests/model_xml/__init__.py
Normal 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>
|
||||
23
tests/regression_tests/model_xml/energy_laws_inputs_true.dat
Normal file
23
tests/regression_tests/model_xml/energy_laws_inputs_true.dat
Normal 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>
|
||||
67
tests/regression_tests/model_xml/inputs_true.dat
Normal file
67
tests/regression_tests/model_xml/inputs_true.dat
Normal 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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
100
tests/regression_tests/model_xml/test.py
Normal file
100
tests/regression_tests/model_xml/test.py
Normal 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')
|
||||
|
|
@ -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')
|
||||
Loading…
Add table
Add a link
Reference in a new issue