From 43201a55ad74abdb802d81364c6c4c393598d147 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 3 Nov 2022 14:57:53 -0500 Subject: [PATCH 1/3] DepcodeSerpent->SerpentDepcode; DepcodeOpenMC->OpenMCDepcode --- doc/installation.rst | 4 +- doc/releasenotes/v0.5.0.rst | 4 +- saltproc/app.py | 6 +- saltproc/depcode.py | 12 +- saltproc/openmc_deplete.py | 2 +- tests/conftest.py | 12 +- .../basic_reprocessing/test.py | 4 +- .../file_interface_openmc/test.py | 78 +++++----- .../file_interface_serpent/test.py | 50 +++---- .../run_no_reprocessing/test.py | 2 +- tests/unit_tests/test_depcode_serpent.py | 136 +++++++++--------- tests/unit_tests/test_materialflow.py | 12 +- tests/unit_tests/test_process.py | 4 +- tests/unit_tests/test_separator.py | 4 +- tests/unit_tests/test_sparger.py | 4 +- 15 files changed, 167 insertions(+), 167 deletions(-) diff --git a/doc/installation.rst b/doc/installation.rst index bad18ce2d..33dbf564e 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -95,7 +95,7 @@ The unit tests check that the individual functions and classes of the ``saltproc module return the correct type of variables and correct values, where applicable. The regression tests run a full SaltProc simulation and check the final result with a precalculated result. -The ``DepcodeSerpent`` integration tests require the `JEFF 3.1.2 cross section library`_ as well +The ``SerpentDepcode`` integration tests require the `JEFF 3.1.2 cross section library`_ as well as neutron induces and spontaneous fission product yield data from JEFF 3.3. The publicly available versions of JEFF 3.1.2 cannot be used with Serpent right out of the box due to `Serpent's notation for isomeric states`_. The scripts in @@ -104,7 +104,7 @@ We recommend using them for your convenience. See the `README`_ for more information. .. - The ``DepcodeOpenmc`` integration tests require... + The ``OpenMCDepcode`` integration tests require... .. _Serpent's notation for isomeric states: https://serpent.vtt.fi/mediawiki/index.php/Installing_and_running_Serpent#Setting_up_the_data_libraries .. _JEFF 3.1.2 cross section library: https://www.oecd-nea.org/dbforms/data/eva/evatapes/jeff_31/JEFF312/ diff --git a/doc/releasenotes/v0.5.0.rst b/doc/releasenotes/v0.5.0.rst index d253b8821..3cee61738 100644 --- a/doc/releasenotes/v0.5.0.rst +++ b/doc/releasenotes/v0.5.0.rst @@ -115,13 +115,13 @@ Python API Changes - ``template_inputfile_path`` → ``template_input_file_path`` - Changed `iter_inputfile` and `iter_matfile` to be attributes instead of parameters - - ``DepcodeSerpent`` + - ``DepcodeSerpent`` → ``SerpentDepcode`` - ``template_inputfile_path`` → ``template_input_file_path`` - Changed `iter_inputfile` and `iter_matfile` to be attributes instead of parameters - - ``DepcodeOpenmc`` is a ``Depcode`` subclass that interfaces with ``openmc``. This class implements the following functions + - ``OpenMCDepcode`` is a ``Depcode`` subclass that interfaces with ``openmc``. This class implements the following functions - ``run_depcode()`` - ``switch_to_next_geometry()`` diff --git a/saltproc/app.py b/saltproc/app.py index 0781847ca..0cd1b5404 100644 --- a/saltproc/app.py +++ b/saltproc/app.py @@ -10,7 +10,7 @@ import networkx as nx import pydotplus -from saltproc import DepcodeSerpent, DepcodeOpenMC, Simulation, Reactor +from saltproc import SerpentDepcode, OpenMCDepcode, Simulation, Reactor from saltproc import Process, Sparger, Separator, Materialflow @@ -240,9 +240,9 @@ def _create_depcode_object(depcode_input): """Helper function for `run()` """ codename = depcode_input['codename'] if codename == 'serpent': - depcode = DepcodeSerpent + depcode = SerpentDepcode elif codename == 'openmc': - depcode = DepcodeOpenMC + depcode = OpenMCDepcode else: raise ValueError( f'{depcode_input["codename"]} is not a supported depletion code') diff --git a/saltproc/depcode.py b/saltproc/depcode.py index 2b5dd75d0..a15fee9ba 100644 --- a/saltproc/depcode.py +++ b/saltproc/depcode.py @@ -170,7 +170,7 @@ def write_mat_file(self, dep_dict, dep_end_time): """ -class DepcodeOpenMC(Depcode): +class OpenMCDepcode(Depcode): """Class contains information about input, output, geometry, and template files for running OpenMC depletion simulations. Also contains neutrons population, active, and inactive cycles. @@ -204,7 +204,7 @@ def __init__(self, npop=50, active_cycles=20, inactive_cycles=20): - """Initializes the DepcodeOpenMC object. + """Initializes the OpenMCDepcode object. Parameters ---------- @@ -483,7 +483,7 @@ def write_saltproc_openmc_tallies(self, materials, geometry): del tallies -class DepcodeSerpent(Depcode): +class SerpentDepcode(Depcode): """Class contains information about input, output, geometry, and template files for running Serpent2 depletion simulations. Also contains neutrons population, active, and inactive cycles. @@ -513,7 +513,7 @@ def __init__(self, npop=50, active_cycles=20, inactive_cycles=20): - """Initializes the DepcodeSerpent object. + """Initializes the SerpentDepcode object. Parameters ---------- @@ -778,7 +778,7 @@ def read_dep_comp(self, read_at_end=False): def read_depcode_info(self): """Parses initial simulation info data from Serpent2 output and stores - it in the `DepcodeSerpent` object's ``sim_info`` attributes. + it in the `SerpentDepcode` object's ``sim_info`` attributes. """ res = serpent.parse_res(self.iter_inputfile + "_res.m") depcode_name, depcode_ver = res['VERSION'][0].decode('utf-8').split() @@ -799,7 +799,7 @@ def read_depcode_info(self): def read_depcode_step_param(self): """Parses data from Serpent2 output for each step and stores it in - `DepcodeSerpent` object's ``param`` attributes. + `SerpentDepcode` object's ``param`` attributes. """ res = serpent.parse_res(self.iter_inputfile + "_res.m") self.param['keff_bds'] = res['IMP_KEFF'][0] diff --git a/saltproc/openmc_deplete.py b/saltproc/openmc_deplete.py index 0636855c1..ed3aaa679 100644 --- a/saltproc/openmc_deplete.py +++ b/saltproc/openmc_deplete.py @@ -17,7 +17,7 @@ def parse_arguments(): tallies : str Path to openmc tallies `.xml` file depletion_settings : str - Path to the DepcodeOpenMC depletion_settings file + Path to the OpenMCDepcode depletion_settings file """ parser = argparse.ArgumentParser() diff --git a/tests/conftest.py b/tests/conftest.py index 9d287fbd7..0e79f3c35 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,8 +23,8 @@ def path_test_file(cwd): @pytest.fixture(scope='session') -def depcode_serpent(cwd): - """DepcodeSerpent object for unit tests""" +def serpent_depcode(cwd): + """SerpentDepcode object for unit tests""" saltproc_input = (cwd / 'serpent_data' / 'tap_input.json').as_posix() _, _, _, object_input = read_main_input(saltproc_input) depcode = _create_depcode_object(object_input[0]) @@ -34,8 +34,8 @@ def depcode_serpent(cwd): @pytest.fixture(scope='session') -def depcode_openmc(cwd): - """DepcodeOpenMC object for unit tests""" +def openmc_depcode(cwd): + """OpenMCDepcode object for unit tests""" saltproc_input = (cwd / 'openmc_data' / 'tap_input.json').as_posix() _, _, _, object_input = read_main_input(saltproc_input) depcode = _create_depcode_object(object_input[0]) @@ -59,11 +59,11 @@ def depcode_openmc(cwd): @pytest.fixture(scope='session') -def simulation(cwd, depcode_serpent): +def simulation(cwd, serpent_depcode): """Simulation object for unit tests""" simulation = Simulation( sim_name='test_simulation', - sim_depcode=depcode_serpent, + sim_depcode=serpent_depcode, core_number=1, node_number=1, db_path=( diff --git a/tests/integration_tests/basic_reprocessing/test.py b/tests/integration_tests/basic_reprocessing/test.py index 7dca97952..1fe2eb367 100644 --- a/tests/integration_tests/basic_reprocessing/test.py +++ b/tests/integration_tests/basic_reprocessing/test.py @@ -5,10 +5,10 @@ def test_reprocessing_and_refill( - depcode_serpent, + serpent_depcode, proc_test_file, path_test_file): - mats = depcode_serpent.read_dep_comp(True) + mats = serpent_depcode.read_dep_comp(True) waste_streams, extracted_mass = reprocess_materials(mats, proc_test_file, path_test_file) diff --git a/tests/integration_tests/file_interface_openmc/test.py b/tests/integration_tests/file_interface_openmc/test.py index fd124935f..c32f8931f 100644 --- a/tests/integration_tests/file_interface_openmc/test.py +++ b/tests/integration_tests/file_interface_openmc/test.py @@ -22,12 +22,12 @@ def msr(scope='module'): return reactor -def test_write_depcode_input(depcode_openmc, msr): +def test_write_depcode_input(openmc_depcode, msr): # OpenMC input_materials = openmc.Materials.from_xml( - depcode_openmc.template_input_file_path['materials']) + openmc_depcode.template_input_file_path['materials']) input_geometry = openmc.Geometry.from_xml( - depcode_openmc.geo_files[0], + openmc_depcode.geo_files[0], materials=input_materials) input_cells = input_geometry.get_all_cells() @@ -35,16 +35,16 @@ def test_write_depcode_input(depcode_openmc, msr): input_surfaces = input_geometry.get_all_surfaces() input_universes = input_geometry.get_all_universes() - depcode_openmc.write_depcode_input(msr, + openmc_depcode.write_depcode_input(msr, 0, False) # Load in the iter_ objects - iter_materials = openmc.Materials.from_xml(depcode_openmc.iter_matfile) + iter_materials = openmc.Materials.from_xml(openmc_depcode.iter_matfile) iter_geometry = openmc.Geometry.from_xml( - depcode_openmc.iter_inputfile['geometry'], + openmc_depcode.iter_inputfile['geometry'], materials=iter_materials) iter_settings = openmc.Settings.from_xml( - depcode_openmc.iter_inputfile['settings']) + openmc_depcode.iter_inputfile['settings']) iter_cells = iter_geometry.get_all_cells() iter_lattices = iter_geometry.get_all_lattices() @@ -60,45 +60,45 @@ def test_write_depcode_input(depcode_openmc, msr): 'univs': (input_universes, iter_universes)} _check_openmc_iterables_equal(assertion_dict) - assert iter_settings.inactive == depcode_openmc.inactive_cycles - assert iter_settings.batches == depcode_openmc.active_cycles + \ - depcode_openmc.inactive_cycles - assert iter_settings.particles == depcode_openmc.npop + assert iter_settings.inactive == openmc_depcode.inactive_cycles + assert iter_settings.batches == openmc_depcode.active_cycles + \ + openmc_depcode.inactive_cycles + assert iter_settings.particles == openmc_depcode.npop del iter_materials, iter_geometry del input_materials, input_geometry -def test_write_depletion_settings(depcode_openmc, msr): +def test_write_depletion_settings(openmc_depcode, msr): """ - Unit test for `Depcodedepcode_openmc.write_depletion_settings` + Unit test for `Depcodeopenmc_depcode.write_depletion_settings` """ - depcode_openmc.write_depletion_settings(msr, 0) - with open(depcode_openmc.iter_inputfile['depletion_settings']) as f: + openmc_depcode.write_depletion_settings(msr, 0) + with open(openmc_depcode.iter_inputfile['depletion_settings']) as f: j = json.load(f) assert j['directory'] == Path( - depcode_openmc.iter_inputfile['settings']).parents[0].as_posix() + openmc_depcode.iter_inputfile['settings']).parents[0].as_posix() assert j['timesteps'][0] == msr.dep_step_length_cumulative[0] assert j['operator_kwargs']['chain_file'] == \ - depcode_openmc.template_input_file_path['chain_file'] + openmc_depcode.template_input_file_path['chain_file'] assert j['integrator_kwargs']['power'] == msr.power_levels[0] assert j['integrator_kwargs']['timestep_units'] == 'd' -def test_write_saltproc_openmc_tallies(depcode_openmc): +def test_write_saltproc_openmc_tallies(openmc_depcode): """ - Unit test for `DepcodeOpenMC.write_saltproc_openmc_tallies` + Unit test for `OpenMCDepcode.write_saltproc_openmc_tallies` """ mat = openmc.Materials.from_xml( - depcode_openmc.template_input_file_path['materials']) + openmc_depcode.template_input_file_path['materials']) geo = openmc.Geometry.from_xml( - depcode_openmc.geo_files[0], mat) - depcode_openmc.write_saltproc_openmc_tallies(mat, geo) + openmc_depcode.geo_files[0], mat) + openmc_depcode.write_saltproc_openmc_tallies(mat, geo) del mat, geo - tallies = openmc.Tallies.from_xml(depcode_openmc.iter_inputfile['tallies']) + tallies = openmc.Tallies.from_xml(openmc_depcode.iter_inputfile['tallies']) - # now write asserts statements based on the depcode_openmc.Tallies API and + # now write asserts statements based on the openmc_depcode.Tallies API and # what we expect our tallies to be assert len(tallies) == 5 tal0 = tallies[0] @@ -126,21 +126,21 @@ def test_write_saltproc_openmc_tallies(depcode_openmc): assert tal4.scores[0] == 'heating' -def test_switch_to_next_geometry(depcode_openmc): +def test_switch_to_next_geometry(openmc_depcode): # OpenMC mat = openmc.Materials.from_xml( - depcode_openmc.template_input_file_path['materials']) + openmc_depcode.template_input_file_path['materials']) expected_geometry = openmc.Geometry.from_xml( - depcode_openmc.geo_files[0], mat) + openmc_depcode.geo_files[0], mat) expected_cells = expected_geometry.get_all_cells() expected_lattices = expected_geometry.get_all_lattices() expected_surfaces = expected_geometry.get_all_surfaces() expected_universes = expected_geometry.get_all_universes() del expected_geometry - depcode_openmc.switch_to_next_geometry() + openmc_depcode.switch_to_next_geometry() switched_geometry = openmc.Geometry.from_xml( - depcode_openmc.iter_inputfile['geometry'], mat) + openmc_depcode.iter_inputfile['geometry'], mat) switched_cells = switched_geometry.get_all_cells() switched_lattices = switched_geometry.get_all_lattices() @@ -207,17 +207,17 @@ def _check_openmc_objects_equal(object1, object2): Parameters ---------- - object1 : depcode_openmc.Surface, \ - depcode_openmc.Universe, \ - depcode_openmc.Cell, \ - depcode_openmc.Material, \ - depcode_openmc.Lattice + object1 : openmc_depcode.Surface, \ + openmc_depcode.Universe, \ + openmc_depcode.Cell, \ + openmc_depcode.Material, \ + openmc_depcode.Lattice First openmc object to compare - object2 : depcode_openmc.Surface, \ - depcode_openmc.Universe, \ - depcode_openmc.Cell, \ - depcode_openmc.Material, \ - depcode_openmc.Lattice + object2 : openmc_depcode.Surface, \ + openmc_depcode.Universe, \ + openmc_depcode.Cell, \ + openmc_depcode.Material, \ + openmc_depcode.Lattice Second openmc object to compare """ diff --git a/tests/integration_tests/file_interface_serpent/test.py b/tests/integration_tests/file_interface_serpent/test.py index 01e8627e8..573aedfd8 100644 --- a/tests/integration_tests/file_interface_serpent/test.py +++ b/tests/integration_tests/file_interface_serpent/test.py @@ -22,33 +22,33 @@ def msr(scope='module'): return reactor -def test_iter_input_from_template(depcode_serpent, msr): - file = depcode_serpent.template_input_file_path - file_data = depcode_serpent.read_plaintext_file(file) +def test_iter_input_from_template(serpent_depcode, msr): + file = serpent_depcode.template_input_file_path + file_data = serpent_depcode.read_plaintext_file(file) # change_sim_par - file_data = depcode_serpent.change_sim_par(file_data) + file_data = serpent_depcode.change_sim_par(file_data) assert file_data[18] == 'set pop %i %i %i\n' % ( - depcode_serpent.npop, - depcode_serpent.active_cycles, - depcode_serpent.inactive_cycles) + serpent_depcode.npop, + serpent_depcode.active_cycles, + serpent_depcode.inactive_cycles) # insert_path_to_geometry - file_data = depcode_serpent.insert_path_to_geometry(file_data) + file_data = serpent_depcode.insert_path_to_geometry(file_data) assert file_data[5].split('/')[-1] == 'tap_geometry_base.ini"\n' # create_iter_matfile - file_data = depcode_serpent.create_iter_matfile(file_data) + file_data = serpent_depcode.create_iter_matfile(file_data) assert file_data[0].split()[-1] == '\"' + \ - depcode_serpent.iter_matfile + '\"' - remove(depcode_serpent.iter_matfile) + serpent_depcode.iter_matfile + '\"' + remove(serpent_depcode.iter_matfile) # replace_burnup_parameters time = msr.dep_step_length_cumulative.copy() time.insert(0, 0.0) depsteps = np.diff(time) for idx in range(len(msr.power_levels)): - file_data = depcode_serpent.replace_burnup_parameters(file_data, + file_data = serpent_depcode.replace_burnup_parameters(file_data, msr, idx) @@ -57,13 +57,13 @@ def test_iter_input_from_template(depcode_serpent, msr): assert file_data[8].split()[5] == str("%7.5E" % depsteps[idx]) -def test_write_iter_files(depcode_serpent, msr): - mats = depcode_serpent.read_dep_comp(True) +def test_write_iter_files(serpent_depcode, msr): + mats = serpent_depcode.read_dep_comp(True) # write_mat_file - depcode_serpent.write_mat_file(mats, 12.0) - file = depcode_serpent.iter_matfile - file_data = depcode_serpent.read_plaintext_file(file) + serpent_depcode.write_mat_file(mats, 12.0) + file = serpent_depcode.iter_matfile + file_data = serpent_depcode.read_plaintext_file(file) assert file_data[0] == '% Material compositions (after 12.000000 days)\n' if 'fuel' in file_data[3]: assert file_data[3].split()[-1] == '2.27175E+07' @@ -74,15 +74,15 @@ def test_write_iter_files(depcode_serpent, msr): elif 'ctrlPois' in file_data[3]: assert file_data[3].split()[-1] == '1.11635E+04' assert file_data[4] == ' 1001.09c -1.21000137902945E-35\n' - remove(depcode_serpent.iter_matfile) + remove(serpent_depcode.iter_matfile) # write_depcode_input - depcode_serpent.write_depcode_input(msr, + serpent_depcode.write_depcode_input(msr, 0, False) - file = depcode_serpent.iter_inputfile - file_data = depcode_serpent.read_plaintext_file(file) + file = serpent_depcode.iter_inputfile + file_data = serpent_depcode.read_plaintext_file(file) assert file_data[0] == 'include "./serpent_iter_mat.ini"\n' assert file_data[8].split()[2] == '1.250000000E+09' assert file_data[8].split()[4] == 'daystep' @@ -90,10 +90,10 @@ def test_write_iter_files(depcode_serpent, msr): assert file_data[20] == 'set pop 50 20 20\n' # switch_to_next_geometry - depcode_serpent.geo_files += ['../../examples/406.inp', + serpent_depcode.geo_files += ['../../examples/406.inp', '../../examples/988.inp'] - depcode_serpent.switch_to_next_geometry() - file_data = depcode_serpent.read_plaintext_file(file) + serpent_depcode.switch_to_next_geometry() + file_data = serpent_depcode.read_plaintext_file(file) assert file_data[5].split('/')[-1] == '406.inp"\n' - remove(depcode_serpent.iter_inputfile) + remove(serpent_depcode.iter_inputfile) diff --git a/tests/integration_tests/run_no_reprocessing/test.py b/tests/integration_tests/run_no_reprocessing/test.py index cf7ab07a7..1ecf281ac 100644 --- a/tests/integration_tests/run_no_reprocessing/test.py +++ b/tests/integration_tests/run_no_reprocessing/test.py @@ -8,7 +8,7 @@ from pyne import serpent from saltproc import app -from saltproc import DepcodeSerpent, Simulation, Reactor +from saltproc import SerpentDepcode, Simulation, Reactor @pytest.fixture diff --git a/tests/unit_tests/test_depcode_serpent.py b/tests/unit_tests/test_depcode_serpent.py index bbf3a0582..06ad3f919 100644 --- a/tests/unit_tests/test_depcode_serpent.py +++ b/tests/unit_tests/test_depcode_serpent.py @@ -2,88 +2,88 @@ import pytest import numpy as np -from saltproc import DepcodeSerpent - - -def test_create_nuclide_name_map_zam_to_serpent(depcode_serpent): - depcode_serpent.create_nuclide_name_map_zam_to_serpent() - assert depcode_serpent.iso_map[380880] == '38088.09c' - assert depcode_serpent.iso_map[962400] == '96240.09c' - assert depcode_serpent.iso_map[952421] == '95342.09c' - assert depcode_serpent.iso_map[340831] == '340831' - assert depcode_serpent.iso_map[300732] == '300732' - assert depcode_serpent.iso_map[511262] == '511262' - assert depcode_serpent.iso_map[420931] == '420931' - assert depcode_serpent.iso_map[410911] == '410911' - - -def test_convert_nuclide_name_serpent_to_zam(depcode_serpent): - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(47310) == 471101 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(95342) == 952421 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(61348) == 611481 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(52327) == 521271 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(1001) == 1001 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(1002) == 1002 - assert depcode_serpent.convert_nuclide_name_serpent_to_zam(48315) == 481151 - - -def test_read_plaintext_file(depcode_serpent): - template_str = depcode_serpent.read_plaintext_file( - depcode_serpent.template_input_file_path) +from saltproc import SerpentDepcode + + +def test_create_nuclide_name_map_zam_to_serpent(serpent_depcode): + serpent_depcode.create_nuclide_name_map_zam_to_serpent() + assert serpent_depcode.iso_map[380880] == '38088.09c' + assert serpent_depcode.iso_map[962400] == '96240.09c' + assert serpent_depcode.iso_map[952421] == '95342.09c' + assert serpent_depcode.iso_map[340831] == '340831' + assert serpent_depcode.iso_map[300732] == '300732' + assert serpent_depcode.iso_map[511262] == '511262' + assert serpent_depcode.iso_map[420931] == '420931' + assert serpent_depcode.iso_map[410911] == '410911' + + +def test_convert_nuclide_name_serpent_to_zam(serpent_depcode): + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(47310) == 471101 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(95342) == 952421 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(61348) == 611481 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(52327) == 521271 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(1001) == 1001 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(1002) == 1002 + assert serpent_depcode.convert_nuclide_name_serpent_to_zam(48315) == 481151 + + +def test_read_plaintext_file(serpent_depcode): + template_str = serpent_depcode.read_plaintext_file( + serpent_depcode.template_input_file_path) assert template_str[6] == '%therm zrh_h 900 hzr05.32t hzr06.32t\n' assert template_str[18] == 'set pop 30 20 10\n' assert template_str[22] == 'set bumode 2\n' assert template_str[23] == 'set pcc 1\n' -def test_get_nuc_name(depcode_serpent): - assert depcode_serpent.get_nuc_name('92235.09c')[0] == 'U235' - assert depcode_serpent.get_nuc_name('38088.09c')[0] == 'Sr88' - assert depcode_serpent.get_nuc_name('95342.09c')[0] == 'Am242m1' - assert depcode_serpent.get_nuc_name('61348.03c')[0] == 'Pm148m1' - assert depcode_serpent.get_nuc_name('20060')[0] == 'He6' - assert depcode_serpent.get_nuc_name('110241')[0] == 'Na24m1' - assert depcode_serpent.get_nuc_name('170381')[0] == 'Cl38m1' - assert depcode_serpent.get_nuc_name('310741')[0] == 'Ga74m1' - assert depcode_serpent.get_nuc_name('290702')[0] == 'Cu70m2' - assert depcode_serpent.get_nuc_name('250621')[0] == 'Mn62m1' - assert depcode_serpent.get_nuc_name('300732')[0] == 'Zn73m2' - assert depcode_serpent.get_nuc_name('370981')[0] == 'Rb98m1' - assert depcode_serpent.get_nuc_name('390972')[0] == 'Y97m2' - assert depcode_serpent.get_nuc_name('491142')[0] == 'In114m2' - - -def test_read_depcode_info(depcode_serpent): - depcode_serpent.read_depcode_info() - assert depcode_serpent.sim_info['depcode_name'] == 'Serpent' - assert depcode_serpent.sim_info['depcode_version'] == '2.1.31' - assert depcode_serpent.sim_info['title'] == 'Untitled' - assert depcode_serpent.sim_info['depcode_input_filename'] == \ +def test_get_nuc_name(serpent_depcode): + assert serpent_depcode.get_nuc_name('92235.09c')[0] == 'U235' + assert serpent_depcode.get_nuc_name('38088.09c')[0] == 'Sr88' + assert serpent_depcode.get_nuc_name('95342.09c')[0] == 'Am242m1' + assert serpent_depcode.get_nuc_name('61348.03c')[0] == 'Pm148m1' + assert serpent_depcode.get_nuc_name('20060')[0] == 'He6' + assert serpent_depcode.get_nuc_name('110241')[0] == 'Na24m1' + assert serpent_depcode.get_nuc_name('170381')[0] == 'Cl38m1' + assert serpent_depcode.get_nuc_name('310741')[0] == 'Ga74m1' + assert serpent_depcode.get_nuc_name('290702')[0] == 'Cu70m2' + assert serpent_depcode.get_nuc_name('250621')[0] == 'Mn62m1' + assert serpent_depcode.get_nuc_name('300732')[0] == 'Zn73m2' + assert serpent_depcode.get_nuc_name('370981')[0] == 'Rb98m1' + assert serpent_depcode.get_nuc_name('390972')[0] == 'Y97m2' + assert serpent_depcode.get_nuc_name('491142')[0] == 'In114m2' + + +def test_read_depcode_info(serpent_depcode): + serpent_depcode.read_depcode_info() + assert serpent_depcode.sim_info['depcode_name'] == 'Serpent' + assert serpent_depcode.sim_info['depcode_version'] == '2.1.31' + assert serpent_depcode.sim_info['title'] == 'Untitled' + assert serpent_depcode.sim_info['depcode_input_filename'] == \ '/home/andrei2/Desktop/git/saltproc/develop/saltproc/data/saltproc_tap' - assert depcode_serpent.sim_info['depcode_working_dir'] == \ + assert serpent_depcode.sim_info['depcode_working_dir'] == \ '/home/andrei2/Desktop/git/saltproc/develop/saltproc' - assert depcode_serpent.sim_info['xs_data_path'] == \ + assert serpent_depcode.sim_info['xs_data_path'] == \ '/home/andrei2/serpent/xsdata/jeff312/sss_jeff312.xsdata' - assert depcode_serpent.sim_info['MPI_tasks'] == 1 - assert depcode_serpent.sim_info['OMP_threads'] == 4 - assert depcode_serpent.sim_info['memory_optimization_mode'] == 4 - assert depcode_serpent.sim_info['depletion_timestep'] == 3.0 + assert serpent_depcode.sim_info['MPI_tasks'] == 1 + assert serpent_depcode.sim_info['OMP_threads'] == 4 + assert serpent_depcode.sim_info['memory_optimization_mode'] == 4 + assert serpent_depcode.sim_info['depletion_timestep'] == 3.0 -def test_read_depcode_step_param(depcode_serpent): - depcode_serpent.read_depcode_step_param() - assert depcode_serpent.param['memory_usage'] == [10552.84] - assert depcode_serpent.param['execution_time'] == [81.933] - assert depcode_serpent.param['keff_bds'][0] == 1.00651e+00 - assert depcode_serpent.param['keff_eds'][0] == 1.00569e+00 - assert depcode_serpent.param['fission_mass_bds'] == [70081] - assert depcode_serpent.param['fission_mass_eds'] == [70077.1] - assert depcode_serpent.param['breeding_ratio'][1] == 5.20000e-04 +def test_read_depcode_step_param(serpent_depcode): + serpent_depcode.read_depcode_step_param() + assert serpent_depcode.param['memory_usage'] == [10552.84] + assert serpent_depcode.param['execution_time'] == [81.933] + assert serpent_depcode.param['keff_bds'][0] == 1.00651e+00 + assert serpent_depcode.param['keff_eds'][0] == 1.00569e+00 + assert serpent_depcode.param['fission_mass_bds'] == [70081] + assert serpent_depcode.param['fission_mass_eds'] == [70077.1] + assert serpent_depcode.param['breeding_ratio'][1] == 5.20000e-04 -def test_read_dep_comp(depcode_serpent): - mats = depcode_serpent.read_dep_comp(True) +def test_read_dep_comp(serpent_depcode): + mats = serpent_depcode.read_dep_comp(True) assert mats['fuel']['U235'] == 3499538.3359278883 assert mats['fuel']['U238'] == 66580417.24509208 assert mats['fuel']['F19'] == 37145139.35897285 diff --git a/tests/unit_tests/test_materialflow.py b/tests/unit_tests/test_materialflow.py index 0c49756ba..5180857c2 100644 --- a/tests/unit_tests/test_materialflow.py +++ b/tests/unit_tests/test_materialflow.py @@ -1,14 +1,14 @@ """Test Materialflow functions""" -def test_get_mass(depcode_serpent): - mats = depcode_serpent.read_dep_comp(True) +def test_get_mass(serpent_depcode): + mats = serpent_depcode.read_dep_comp(True) assert mats['fuel'].get_mass() == 112683343.50000001 assert mats['ctrlPois'].get_mass() == 65563.2355 -def test_scale_matflow(depcode_serpent): - mats = depcode_serpent.read_dep_comp(True) +def test_scale_matflow(serpent_depcode): + mats = serpent_depcode.read_dep_comp(True) scale_factor = 0.7 scaled_matflow = mats['fuel'].scale_matflow(scale_factor) assert scaled_matflow[922350000] == scale_factor * 3499538.3359278883 @@ -17,8 +17,8 @@ def test_scale_matflow(depcode_serpent): assert scaled_matflow[30070000] == scale_factor * 5449107.821098938 -def test_copy_pymat_attrs(depcode_serpent): - mats = depcode_serpent.read_dep_comp(True) +def test_copy_pymat_attrs(serpent_depcode): + mats = serpent_depcode.read_dep_comp(True) target_mat = mats['fuel'] target_mat.copy_pymat_attrs(mats['ctrlPois']) assert target_mat.density == 5.873 diff --git a/tests/unit_tests/test_process.py b/tests/unit_tests/test_process.py index cb67bf933..f9b372a5f 100644 --- a/tests/unit_tests/test_process.py +++ b/tests/unit_tests/test_process.py @@ -14,8 +14,8 @@ def process(): return process -def test_process_material(depcode_serpent, process): - mats = depcode_serpent.read_dep_comp(True) +def test_process_material(serpent_depcode, process): + mats = serpent_depcode.read_dep_comp(True) thru, waste = process.process_material(mats['fuel']) np.testing.assert_almost_equal(waste[541350000], 19.79776930513891) np.testing.assert_almost_equal(waste[541360000], 176.44741987005173) diff --git a/tests/unit_tests/test_separator.py b/tests/unit_tests/test_separator.py index 73a5c4a73..64725ecce 100644 --- a/tests/unit_tests/test_separator.py +++ b/tests/unit_tests/test_separator.py @@ -14,8 +14,8 @@ def separator(): return separator -def test_rem_elements(depcode_serpent, separator): - mats = depcode_serpent.read_dep_comp(True) +def test_rem_elements(serpent_depcode, separator): + mats = serpent_depcode.read_dep_comp(True) thru, waste = separator.process_material(mats['fuel']) np.testing.assert_almost_equal(waste[541350000], 19.5320018359295) np.testing.assert_almost_equal(waste[541360000], 174.0787699729534) diff --git a/tests/unit_tests/test_sparger.py b/tests/unit_tests/test_sparger.py index a45381b86..cf0ce047f 100644 --- a/tests/unit_tests/test_sparger.py +++ b/tests/unit_tests/test_sparger.py @@ -14,8 +14,8 @@ def sparger(): return sparger -def test_rem_elements(depcode_serpent, sparger): - mats = depcode_serpent.read_dep_comp(True) +def test_rem_elements(serpent_depcode, sparger): + mats = serpent_depcode.read_dep_comp(True) thru, waste = sparger.process_material(mats['fuel']) np.testing.assert_almost_equal(waste[541350000], 8.061014535231715) np.testing.assert_almost_equal(waste[541360000], 71.8437109936129) From acc6e21afac7ceec8be4dc327fd421434df122c3 Mon Sep 17 00:00:00 2001 From: yardasol Date: Thu, 3 Nov 2022 15:08:14 -0500 Subject: [PATCH 2/3] split up depcode.py into three files --- saltproc/__init__.py | 4 +- saltproc/abc.py | 163 +++++++ saltproc/openmc_depcode.py | 326 +++++++++++++ saltproc/{depcode.py => serpent_depcode.py} | 480 +------------------- 4 files changed, 495 insertions(+), 478 deletions(-) create mode 100644 saltproc/abc.py create mode 100644 saltproc/openmc_depcode.py rename saltproc/{depcode.py => serpent_depcode.py} (55%) diff --git a/saltproc/__init__.py b/saltproc/__init__.py index c136bd49b..fbff3d385 100644 --- a/saltproc/__init__.py +++ b/saltproc/__init__.py @@ -6,7 +6,9 @@ from __future__ import absolute_import, division, print_function from .version import __version__ # noqa from .materialflow import * -from .depcode import * +from .abc import * +from .serpent_depcode import * +from .openmc_depcode import * from .simulation import * from .process import * from .reactor import * diff --git a/saltproc/abc.py b/saltproc/abc.py new file mode 100644 index 000000000..2438ee1e2 --- /dev/null +++ b/saltproc/abc.py @@ -0,0 +1,163 @@ +from abc import ABC, abstractmethod + +class Depcode(ABC): + """Abstract class for interfacing with monte-carlo particle transport + codes. Contains information about input, output, geometry, and template + files for running depletion simulations. Also contains neutron + population, active, and inactive cycles. Contains methods to read template + and output files, and write new input files for the depletion code. + + Attributes + ----------- + param : dict of str to type + Holds depletion step parameter information. Parameter names are keys + and parameter values are values. + sim_info : dict of str to type + Holds simulation settings information. Setting names are keys + and setting values are values. + iter_inputfile : str + Path to depletion code input file for depletion code rerunning. + iter_matfile : str + Path to iterative, rewritable material file for depletion code + rerunning. This file is modified during the simulation. + + """ + + def __init__(self, + codename, + exec_path, + template_input_file_path, + geo_files=None, + npop=50, + active_cycles=20, + inactive_cycles=20): + """Initializes the Depcode object. + + Parameters + ---------- + codename : str + Name of depletion code. + exec_path : str + Path to depletion code executable. + template_input_file_path : str or dict of str to str + Path(s) to depletion code input file(s), or a dictionary where + the input type (e.g. material, geometry, settings, etc.) as a + string are keys, and the path to the input file are values. + Type depends on depletion code in use. + geo_files : str or list, optional + Path to file that contains the reactor geometry. + List of `str` if reactivity control by + switching geometry is `On` or just `str` otherwise. + npop : int, optional + Size of neutron population per cycle for Monte Carlo. + active_cycles : int, optional + Number of active cycles. + inactive_cycles : int, optional + Number of inactive cycles. + + """ + self.codename = codename + self.exec_path = exec_path + self.template_input_file_path = template_input_file_path + self.geo_files = geo_files + self.npop = npop + self.active_cycles = active_cycles + self.inactive_cycles = inactive_cycles + self.param = {} + self.sim_info = {} + self.iter_inputfile = './iter_input' + self.iter_matfile = './iter_mat' + + @abstractmethod + def read_depcode_info(self): + """Parses initial depletion code info data from depletion code + output and stores it in the `Depcode` object's ``sim_info`` attribute. + """ + + @abstractmethod + def read_depcode_step_param(self): + """Parses data from depletion code output for each step and stores + it in `Depcode` object's ``param`` attributes. + """ + + @abstractmethod + def read_dep_comp(self, read_at_end=False): + """Reads the depleted material data from the depcode simulation + and returns a dictionary with a `Materialflow` object for each + burnable material. + + Parameters + ---------- + read_at_end : bool, optional + Controls at which moment in the depletion step to read the data. + If `True`, the function reads data at the end of the + depletion step. Otherwise, the function reads data at the + beginning of the depletion step. + + Returns + ------- + mats : dict of str to Materialflow + Dictionary that contains `Materialflow` objects. + + ``key`` + Name of burnable material. + ``value`` + `Materialflow` object holding composition and properties. + + """ + + @abstractmethod + def run_depcode(self, cores, nodes): + """Runs depletion code as a subprocess with the given parameters. + + Parameters + ---------- + cores : int + Number of cores to use for depletion code run. + nodes : int + Number of nodes to use for depletion code run. + """ + + @abstractmethod + def switch_to_next_geometry(self): + """Changes the geometry used in the depletion code simulation to the + next geometry file in ``geo_files`` + """ + + @abstractmethod + def write_depcode_input(self, reactor, dep_step, restart): + """ Writes prepared data into depletion code input file(s). + + Parameters + ---------- + reactor : Reactor + Contains information about power load curve and cumulative + depletion time for the integration test. + dep_step : int + Current depletion time step. + restart : bool + Is the current simulation restarted? + """ + + @abstractmethod + def write_mat_file(self, dep_dict, dep_end_time): + """Writes the iteration input file containing the burnable materials + composition used in depletion runs and updated after each depletion + step. + + Parameters + ---------- + dep_dict : dict of str to Materialflow + Dictionary that contains `Materialflow` objects. + + ``key`` + Name of burnable material. + ``value`` + `Materialflow` object holding composition and properties. + dep_end_time : float + Current time at the end of the depletion step (d). + + """ + + + diff --git a/saltproc/openmc_depcode.py b/saltproc/openmc_depcode.py new file mode 100644 index 000000000..67ec1c250 --- /dev/null +++ b/saltproc/openmc_depcode.py @@ -0,0 +1,326 @@ +import subprocess +import os +import shutil +import re +import json + +from pyne import nucname as pyname +from pyne import serpent +import openmc + +from saltproc import Materialflow +from saltproc.abc import Depcode + +class OpenMCDepcode(Depcode): + """Class contains information about input, output, geometry, and + template files for running OpenMC depletion simulations. + Also contains neutrons population, active, and inactive cycles. + Contains methods to read template and output files, + write new input files for OpenMC. + + Attributes + ---------- + param : dict of str to type + Holds depletion step parameter information. Parameter names are keys + and parameter values are values. + sim_info : dict of str to type + Holds simulation settings information. Setting names are keys + and setting values are values. + iter_inputfile : dict of str to str + Paths to OpenMC input files for OpenMC rerunning. + iter_matfile : str + Path to iterative, rewritable material file for OpenMC + rerunning. This file is modified during the simulation. + + + + """ + + def __init__(self, + exec_path="openmc_deplete.py", + template_input_file_path={"geometry": "./geometry.xml", + "settings": "./settings.xml", + "chain_file": "./chain_simple.xml"}, + geo_files=None, + npop=50, + active_cycles=20, + inactive_cycles=20): + """Initializes the OpenMCDepcode object. + + Parameters + ---------- + exec_path : str + Path to OpenMC depletion script. + template_input_file_path : dict of str to str + Path to user input files (``.xml`` file for geometry, + material, and settings) for OpenMC. File type as strings + are keys (e.g. 'geometry', 'settings', 'material'), and + file path as strings are values. + geo_files : str or list, optional + Path to file that contains the reactor geometry. + List of `str` if reactivity control by + switching geometry is `On` or just `str` otherwise. + npop : int, optional + Size of neutron population per cycle for Monte Carlo. + active_cycles : int, optional + Number of active cycles. + inactive_cycles : int, optional + Number of inactive cycles. + + """ + super().__init__("openmc", + exec_path, + template_input_file_path, + geo_files, + npop, + active_cycles, + inactive_cycles) + self.iter_inputfile = {'geometry': './geometry.xml', + 'settings': './settings.xml'}, + self.iter_matfile = './materials.xml' + + def read_depcode_info(self): + """Parses initial OpenMC simulation info from the OpenMC output files + and stores it in the `Depcode` object's ``sim_info`` attribute. + """ + + def read_depcode_step_param(self): + """Parses data from OpenMC depletion output for each step and stores + it in `Depcode` object's ``param`` attributes. + """ + + def read_dep_comp(self, read_at_end=False): + """Reads the depleted material data from the OpenMC depletion + simulation and returns a dictionary with a `Materialflow` object for + each burnable material. + + Parameters + ---------- + read_at_end : bool, optional + Controls at which moment in the depletion step to read the data. + If `True`, the function reads data at the end of the + depletion step. Otherwise, the function reads data at the + beginning of the depletion step. + + Returns + ------- + mats : dict of str to Materialflow + Dictionary that contains `Materialflow` objects. + + ``key`` + Name of burnable material. + ``value`` + `Materialflow` object holding composition and properties. + + """ + + def run_depcode(self, cores, nodes): + """Runs OpenMC depletion simulation as a subprocess with the given + parameters. + + Parameters + ---------- + cores : int + Number of cores to use for depletion code run. + nodes : int + Number of nodes to use for depletion code run. + """ + # need to add flow control for plots option + args = ( + 'mpiexec', + '-n', + str(nodes), + 'python', + './deplete_openmc.py' + '-mat', + self.iter_matfile, + '-geo', + self.iter_inputfile['geometry'], + '-set', + self.iter_inputfile['settings'], + '-tal', + self.iter_inputfile['tallies'], + '-dep', + self.iter_inputfile['depletion_settings']) + + print('Running %s' % (self.codename)) + # TODO: Need to figure out how to adapt this to openmc + try: + subprocess.check_output( + args, + cwd=os.path.split(self.template_inputfile_path)[0], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as error: + print(error.output.decode("utf-8")) + raise RuntimeError('\n %s RUN FAILED\n see error message above' + % (self.codename)) + print('Finished OpenMC Run') + + def switch_to_next_geometry(self): + """Switches the geometry file for the OpenMC depletion simulation to + the next geometry file in `geo_files`. + """ + mats = openmc.Materials.from_xml(self.iter_matfile) + next_geometry = openmc.Geometry.from_xml( + path=self.geo_files.pop(0), + materials=mats) + next_geometry.export_to_xml(path=self.iter_inputfile['geometry']) + del mats, next_geometry + + def write_depcode_input(self, reactor, dep_step, restart): + """ Writes prepared data into OpenMC input file(s). + + Parameters + ---------- + reactor : Reactor + Contains information about power load curve and cumulative + depletion time for the integration test. + dep_step : int + Current depletion time step. + restart : bool + Is the current simulation restarted? + """ + + if dep_step == 0 and not restart: + materials = openmc.Materials.from_xml( + self.template_input_file_path['materials']) + geometry = openmc.Geometry.from_xml( + self.geo_files[0], materials=materials) + settings = openmc.Settings.from_xml( + self.template_input_file_path['settings']) + settings.particles = self.npop + settings.inactive = self.inactive_cycles + settings.batches = self.active_cycles + self.inactive_cycles + else: + materials = openmc.Materials.from_xml(self.iter_matfile) + geometry = openmc.Geometry.from_xml( + self.iter_inputfile['geometry'], materials=materials) + settings = openmc.Settings.from_xml( + self.iter_inputfile['settings']) + + materials.export_to_xml(self.iter_matfile) + geometry.export_to_xml(self.iter_inputfile['geometry']) + settings.export_to_xml(self.iter_inputfile['settings']) + self.write_depletion_settings(reactor, dep_step) + self.write_saltproc_openmc_tallies(materials, geometry) + del materials, geometry, settings + + def write_depletion_settings(self, reactor, current_depstep_idx): + """Write the depeletion settings for the ``openmc.deplete`` + module. + + Parameters + ---------- + reactor : Reactor + Contains information about power load curve and cumulative + depletion time for the integration test. + current_depstep_idx : int + Current depletion step. + + """ + depletion_settings = {} + current_depstep_power = reactor.power_levels[current_depstep_idx] + + # Get current depletion step length + if current_depstep_idx == 0: + current_depstep = reactor.dep_step_length_cumulative[0] + else: + current_depstep = \ + reactor.dep_step_length_cumulative[current_depstep_idx] - \ + reactor.dep_step_length_cumulative[current_depstep_idx - 1] + + out_path = os.path.dirname(self.iter_inputfile['settings']) + depletion_settings['directory'] = out_path + depletion_settings['timesteps'] = [current_depstep] + + operator_kwargs = {} + + try: + operator_kwargs['chain_file'] = \ + self.template_input_file_path['chain_file'] + except KeyError: + raise SyntaxError("No chain file defined. Please provide \ + a chain file in your saltproc input file") + + integrator_kwargs = {} + integrator_kwargs['power'] = current_depstep_power + integrator_kwargs['timestep_units'] = 'd' # days + + depletion_settings['operator_kwargs'] = operator_kwargs + depletion_settings['integrator_kwargs'] = integrator_kwargs + + self.iter_inputfile['depletion_settings'] = \ + os.path.join(out_path, 'depletion_settings.json') + json_dep_settings = json.JSONEncoder().encode(depletion_settings) + with open(self.iter_inputfile['depletion_settings'], 'w') as f: + f.writelines(json_dep_settings) + + def write_mat_file(self, dep_dict, dep_end_time): + """Writes the iteration input file containing the burnable materials + composition used in OpenMC depletion runs and updated after each + depletion step. + + Parameters + ---------- + dep_dict : dict of str to Materialflow + Dictionary that contains `Materialflow` objects. + + ``key`` + Name of burnable material. + ``value`` + `Materialflow` object holding composition and properties. + dep_end_time : float + Current time at the end of the depletion step (d). + + """ + + def write_saltproc_openmc_tallies(self, materials, geometry): + """ + Write tallies for calculating burnup and delayed neutron + parameters. + + Parameters + ---------- + materials : `openmc.Materials` object + The materials for the depletion simulation + geometry : `openmc.Geometry` object + The geometry for the depletion simulation + + """ + tallies = openmc.Tallies() + + tally = openmc.Tally(name='delayed-fission-neutrons') + tally.filters = [openmc.DelayedGroupFilter([1, 2, 3, 4, 5, 6])] + tally.scores = ['delayed-nu-fission'] + tallies.append(tally) + + tally = openmc.Tally(name='total-fission-neutrons') + tally.filters = [openmc.UniverseFilter(geometry.root_universe)] + tally.scores = ['nu-fission'] + tallies.append(tally) + + tally = openmc.Tally(name='precursor-decay-constants') + tally.filters = [openmc.DelayedGroupFilter([1, 2, 3, 4, 5, 6])] + tally.scores = ['decay-rate'] + tallies.append(tally) + + tally = openmc.Tally(name='fission-energy') + tally.filters = [openmc.UniverseFilter(geometry.root_universe)] + tally.scores = [ + 'fission-q-recoverable', + 'fission-q-prompt', + 'kappa-fission'] + tallies.append(tally) + + tally = openmc.Tally(name='normalization-factor') + tally.filters = [openmc.UniverseFilter(geometry.root_universe)] + tally.scores = ['heating'] + tallies.append(tally) + + out_path = os.path.dirname(self.iter_inputfile['settings']) + self.iter_inputfile['tallies'] = \ + os.path.join(out_path, 'tallies.xml') + tallies.export_to_xml(self.iter_inputfile['tallies']) + del tallies + + diff --git a/saltproc/depcode.py b/saltproc/serpent_depcode.py similarity index 55% rename from saltproc/depcode.py rename to saltproc/serpent_depcode.py index a15fee9ba..aecdddbe5 100644 --- a/saltproc/depcode.py +++ b/saltproc/serpent_depcode.py @@ -1,487 +1,13 @@ -from saltproc import Materialflow import subprocess import os import shutil import re + from pyne import nucname as pyname from pyne import serpent -import openmc -import json -from abc import ABC, abstractmethod - - -class Depcode(ABC): - """Abstract class for interfacing with monte-carlo particle transport - codes. Contains information about input, output, geometry, and template - files for running depletion simulations. Also contains neutron - population, active, and inactive cycles. Contains methods to read template - and output files, and write new input files for the depletion code. - - Attributes - ----------- - param : dict of str to type - Holds depletion step parameter information. Parameter names are keys - and parameter values are values. - sim_info : dict of str to type - Holds simulation settings information. Setting names are keys - and setting values are values. - iter_inputfile : str - Path to depletion code input file for depletion code rerunning. - iter_matfile : str - Path to iterative, rewritable material file for depletion code - rerunning. This file is modified during the simulation. - - """ - - def __init__(self, - codename, - exec_path, - template_input_file_path, - geo_files=None, - npop=50, - active_cycles=20, - inactive_cycles=20): - """Initializes the Depcode object. - - Parameters - ---------- - codename : str - Name of depletion code. - exec_path : str - Path to depletion code executable. - template_input_file_path : str or dict of str to str - Path(s) to depletion code input file(s), or a dictionary where - the input type (e.g. material, geometry, settings, etc.) as a - string are keys, and the path to the input file are values. - Type depends on depletion code in use. - geo_files : str or list, optional - Path to file that contains the reactor geometry. - List of `str` if reactivity control by - switching geometry is `On` or just `str` otherwise. - npop : int, optional - Size of neutron population per cycle for Monte Carlo. - active_cycles : int, optional - Number of active cycles. - inactive_cycles : int, optional - Number of inactive cycles. - - """ - self.codename = codename - self.exec_path = exec_path - self.template_input_file_path = template_input_file_path - self.geo_files = geo_files - self.npop = npop - self.active_cycles = active_cycles - self.inactive_cycles = inactive_cycles - self.param = {} - self.sim_info = {} - self.iter_inputfile = './iter_input' - self.iter_matfile = './iter_mat' - - @abstractmethod - def read_depcode_info(self): - """Parses initial depletion code info data from depletion code - output and stores it in the `Depcode` object's ``sim_info`` attribute. - """ - - @abstractmethod - def read_depcode_step_param(self): - """Parses data from depletion code output for each step and stores - it in `Depcode` object's ``param`` attributes. - """ - - @abstractmethod - def read_dep_comp(self, read_at_end=False): - """Reads the depleted material data from the depcode simulation - and returns a dictionary with a `Materialflow` object for each - burnable material. - - Parameters - ---------- - read_at_end : bool, optional - Controls at which moment in the depletion step to read the data. - If `True`, the function reads data at the end of the - depletion step. Otherwise, the function reads data at the - beginning of the depletion step. - - Returns - ------- - mats : dict of str to Materialflow - Dictionary that contains `Materialflow` objects. - - ``key`` - Name of burnable material. - ``value`` - `Materialflow` object holding composition and properties. - - """ - - @abstractmethod - def run_depcode(self, cores, nodes): - """Runs depletion code as a subprocess with the given parameters. - - Parameters - ---------- - cores : int - Number of cores to use for depletion code run. - nodes : int - Number of nodes to use for depletion code run. - """ - - @abstractmethod - def switch_to_next_geometry(self): - """Changes the geometry used in the depletion code simulation to the - next geometry file in ``geo_files`` - """ - - @abstractmethod - def write_depcode_input(self, reactor, dep_step, restart): - """ Writes prepared data into depletion code input file(s). - - Parameters - ---------- - reactor : Reactor - Contains information about power load curve and cumulative - depletion time for the integration test. - dep_step : int - Current depletion time step. - restart : bool - Is the current simulation restarted? - """ - - @abstractmethod - def write_mat_file(self, dep_dict, dep_end_time): - """Writes the iteration input file containing the burnable materials - composition used in depletion runs and updated after each depletion - step. - - Parameters - ---------- - dep_dict : dict of str to Materialflow - Dictionary that contains `Materialflow` objects. - - ``key`` - Name of burnable material. - ``value`` - `Materialflow` object holding composition and properties. - dep_end_time : float - Current time at the end of the depletion step (d). - - """ - - -class OpenMCDepcode(Depcode): - """Class contains information about input, output, geometry, and - template files for running OpenMC depletion simulations. - Also contains neutrons population, active, and inactive cycles. - Contains methods to read template and output files, - write new input files for OpenMC. - - Attributes - ---------- - param : dict of str to type - Holds depletion step parameter information. Parameter names are keys - and parameter values are values. - sim_info : dict of str to type - Holds simulation settings information. Setting names are keys - and setting values are values. - iter_inputfile : dict of str to str - Paths to OpenMC input files for OpenMC rerunning. - iter_matfile : str - Path to iterative, rewritable material file for OpenMC - rerunning. This file is modified during the simulation. - - - - """ - - def __init__(self, - exec_path="openmc_deplete.py", - template_input_file_path={"geometry": "./geometry.xml", - "settings": "./settings.xml", - "chain_file": "./chain_simple.xml"}, - geo_files=None, - npop=50, - active_cycles=20, - inactive_cycles=20): - """Initializes the OpenMCDepcode object. - - Parameters - ---------- - exec_path : str - Path to OpenMC depletion script. - template_input_file_path : dict of str to str - Path to user input files (``.xml`` file for geometry, - material, and settings) for OpenMC. File type as strings - are keys (e.g. 'geometry', 'settings', 'material'), and - file path as strings are values. - geo_files : str or list, optional - Path to file that contains the reactor geometry. - List of `str` if reactivity control by - switching geometry is `On` or just `str` otherwise. - npop : int, optional - Size of neutron population per cycle for Monte Carlo. - active_cycles : int, optional - Number of active cycles. - inactive_cycles : int, optional - Number of inactive cycles. - - """ - super().__init__("openmc", - exec_path, - template_input_file_path, - geo_files, - npop, - active_cycles, - inactive_cycles) - self.iter_inputfile = {'geometry': './geometry.xml', - 'settings': './settings.xml'}, - self.iter_matfile = './materials.xml' - - def read_depcode_info(self): - """Parses initial OpenMC simulation info from the OpenMC output files - and stores it in the `Depcode` object's ``sim_info`` attribute. - """ - - def read_depcode_step_param(self): - """Parses data from OpenMC depletion output for each step and stores - it in `Depcode` object's ``param`` attributes. - """ - - def read_dep_comp(self, read_at_end=False): - """Reads the depleted material data from the OpenMC depletion - simulation and returns a dictionary with a `Materialflow` object for - each burnable material. - - Parameters - ---------- - read_at_end : bool, optional - Controls at which moment in the depletion step to read the data. - If `True`, the function reads data at the end of the - depletion step. Otherwise, the function reads data at the - beginning of the depletion step. - - Returns - ------- - mats : dict of str to Materialflow - Dictionary that contains `Materialflow` objects. - - ``key`` - Name of burnable material. - ``value`` - `Materialflow` object holding composition and properties. - - """ - - def run_depcode(self, cores, nodes): - """Runs OpenMC depletion simulation as a subprocess with the given - parameters. - - Parameters - ---------- - cores : int - Number of cores to use for depletion code run. - nodes : int - Number of nodes to use for depletion code run. - """ - # need to add flow control for plots option - args = ( - 'mpiexec', - '-n', - str(nodes), - 'python', - './deplete_openmc.py' - '-mat', - self.iter_matfile, - '-geo', - self.iter_inputfile['geometry'], - '-set', - self.iter_inputfile['settings'], - '-tal', - self.iter_inputfile['tallies'], - '-dep', - self.iter_inputfile['depletion_settings']) - - print('Running %s' % (self.codename)) - # TODO: Need to figure out how to adapt this to openmc - try: - subprocess.check_output( - args, - cwd=os.path.split(self.template_inputfile_path)[0], - stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as error: - print(error.output.decode("utf-8")) - raise RuntimeError('\n %s RUN FAILED\n see error message above' - % (self.codename)) - print('Finished OpenMC Run') - - def switch_to_next_geometry(self): - """Switches the geometry file for the OpenMC depletion simulation to - the next geometry file in `geo_files`. - """ - mats = openmc.Materials.from_xml(self.iter_matfile) - next_geometry = openmc.Geometry.from_xml( - path=self.geo_files.pop(0), - materials=mats) - next_geometry.export_to_xml(path=self.iter_inputfile['geometry']) - del mats, next_geometry - - def write_depcode_input(self, reactor, dep_step, restart): - """ Writes prepared data into OpenMC input file(s). - - Parameters - ---------- - reactor : Reactor - Contains information about power load curve and cumulative - depletion time for the integration test. - dep_step : int - Current depletion time step. - restart : bool - Is the current simulation restarted? - """ - - if dep_step == 0 and not restart: - materials = openmc.Materials.from_xml( - self.template_input_file_path['materials']) - geometry = openmc.Geometry.from_xml( - self.geo_files[0], materials=materials) - settings = openmc.Settings.from_xml( - self.template_input_file_path['settings']) - settings.particles = self.npop - settings.inactive = self.inactive_cycles - settings.batches = self.active_cycles + self.inactive_cycles - else: - materials = openmc.Materials.from_xml(self.iter_matfile) - geometry = openmc.Geometry.from_xml( - self.iter_inputfile['geometry'], materials=materials) - settings = openmc.Settings.from_xml( - self.iter_inputfile['settings']) - - materials.export_to_xml(self.iter_matfile) - geometry.export_to_xml(self.iter_inputfile['geometry']) - settings.export_to_xml(self.iter_inputfile['settings']) - self.write_depletion_settings(reactor, dep_step) - self.write_saltproc_openmc_tallies(materials, geometry) - del materials, geometry, settings - - def write_depletion_settings(self, reactor, current_depstep_idx): - """Write the depeletion settings for the ``openmc.deplete`` - module. - - Parameters - ---------- - reactor : Reactor - Contains information about power load curve and cumulative - depletion time for the integration test. - current_depstep_idx : int - Current depletion step. - - """ - depletion_settings = {} - current_depstep_power = reactor.power_levels[current_depstep_idx] - - # Get current depletion step length - if current_depstep_idx == 0: - current_depstep = reactor.dep_step_length_cumulative[0] - else: - current_depstep = \ - reactor.dep_step_length_cumulative[current_depstep_idx] - \ - reactor.dep_step_length_cumulative[current_depstep_idx - 1] - - out_path = os.path.dirname(self.iter_inputfile['settings']) - depletion_settings['directory'] = out_path - depletion_settings['timesteps'] = [current_depstep] - - operator_kwargs = {} - - try: - operator_kwargs['chain_file'] = \ - self.template_input_file_path['chain_file'] - except KeyError: - raise SyntaxError("No chain file defined. Please provide \ - a chain file in your saltproc input file") - - integrator_kwargs = {} - integrator_kwargs['power'] = current_depstep_power - integrator_kwargs['timestep_units'] = 'd' # days - - depletion_settings['operator_kwargs'] = operator_kwargs - depletion_settings['integrator_kwargs'] = integrator_kwargs - - self.iter_inputfile['depletion_settings'] = \ - os.path.join(out_path, 'depletion_settings.json') - json_dep_settings = json.JSONEncoder().encode(depletion_settings) - with open(self.iter_inputfile['depletion_settings'], 'w') as f: - f.writelines(json_dep_settings) - - def write_mat_file(self, dep_dict, dep_end_time): - """Writes the iteration input file containing the burnable materials - composition used in OpenMC depletion runs and updated after each - depletion step. - - Parameters - ---------- - dep_dict : dict of str to Materialflow - Dictionary that contains `Materialflow` objects. - - ``key`` - Name of burnable material. - ``value`` - `Materialflow` object holding composition and properties. - dep_end_time : float - Current time at the end of the depletion step (d). - - """ - - def write_saltproc_openmc_tallies(self, materials, geometry): - """ - Write tallies for calculating burnup and delayed neutron - parameters. - - Parameters - ---------- - materials : `openmc.Materials` object - The materials for the depletion simulation - geometry : `openmc.Geometry` object - The geometry for the depletion simulation - - """ - tallies = openmc.Tallies() - - tally = openmc.Tally(name='delayed-fission-neutrons') - tally.filters = [openmc.DelayedGroupFilter([1, 2, 3, 4, 5, 6])] - tally.scores = ['delayed-nu-fission'] - tallies.append(tally) - - tally = openmc.Tally(name='total-fission-neutrons') - tally.filters = [openmc.UniverseFilter(geometry.root_universe)] - tally.scores = ['nu-fission'] - tallies.append(tally) - - tally = openmc.Tally(name='precursor-decay-constants') - tally.filters = [openmc.DelayedGroupFilter([1, 2, 3, 4, 5, 6])] - tally.scores = ['decay-rate'] - tallies.append(tally) - - tally = openmc.Tally(name='fission-energy') - tally.filters = [openmc.UniverseFilter(geometry.root_universe)] - tally.scores = [ - 'fission-q-recoverable', - 'fission-q-prompt', - 'kappa-fission'] - tallies.append(tally) - - tally = openmc.Tally(name='normalization-factor') - tally.filters = [openmc.UniverseFilter(geometry.root_universe)] - tally.scores = ['heating'] - tallies.append(tally) - - out_path = os.path.dirname(self.iter_inputfile['settings']) - self.iter_inputfile['tallies'] = \ - os.path.join(out_path, 'tallies.xml') - tallies.export_to_xml(self.iter_inputfile['tallies']) - del tallies +from saltproc import Materialflow +from saltproc.abc import Depcode class SerpentDepcode(Depcode): """Class contains information about input, output, geometry, and From 5edaf3a685757e10a655320b30deb77f5d42e409 Mon Sep 17 00:00:00 2001 From: yardasol Date: Mon, 7 Nov 2022 10:15:58 -0600 Subject: [PATCH 3/3] use array_almost_equal --- tests/integration_tests/run_no_reprocessing/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration_tests/run_no_reprocessing/test.py b/tests/integration_tests/run_no_reprocessing/test.py index 1ecf281ac..20e49f49f 100644 --- a/tests/integration_tests/run_no_reprocessing/test.py +++ b/tests/integration_tests/run_no_reprocessing/test.py @@ -46,7 +46,7 @@ def test_integration_2step_saltproc_no_reproc_heavy(setup): test_fuel_mdens = test_result['MAT_fuel_MDENS'][:, -1] test_mdens_error = np.array(ref_fuel_mdens - test_fuel_mdens) - np.testing.assert_array_equal(test_mdens_error, ref_mdens_error) + np.testing.assert_array_almost_equal(test_mdens_error, ref_mdens_error) # Cleaning after testing out_file_list = glob.glob(cwd + '/_test*') for file in out_file_list: