def __init__(self, filename): # A user may not have h5py, but they can still use the rest of the # Python API so we'll only try to import h5py if the user actually inits # a Summary object. import h5py if h5py.__version__ == '2.6.0': raise ImportError("h5py 2.6.0 has a known bug which makes it " "incompatible with OpenMC's HDF5 files. " "Please switch to a different version.") openmc.reset_auto_ids() if not filename.endswith(('.h5', '.hdf5')): msg = 'Unable to open "{0}" which is not an HDF5 summary file' raise ValueError(msg) self._f = h5py.File(filename, 'r') self._openmc_geometry = None self._opencg_geometry = None self._read_metadata() self._read_nuclides() self._read_geometry() self._read_tallies() self._f.close()
def pincell_model(): """Set up a model to test with and delete files when done""" openmc.reset_auto_ids() pincell = openmc.examples.pwr_pin_cell() pincell.settings.verbosity = 1 # Add a tally filter1 = openmc.MaterialFilter(pincell.materials) filter2 = openmc.EnergyFilter([0.0, 1.0, 1.0e3, 20.0e6]) mat_tally = openmc.Tally() mat_tally.filters = [filter1, filter2] mat_tally.nuclides = ['U235', 'U238'] mat_tally.scores = ['total', 'elastic', '(n,gamma)'] pincell.tallies.append(mat_tally) # Add an expansion tally zernike_tally = openmc.Tally() filter3 = openmc.ZernikeFilter(5, r=.63) cells = pincell.geometry.root_universe.cells filter4 = openmc.CellFilter(list(cells.values())) zernike_tally.filters = [filter3, filter4] zernike_tally.scores = ['fission'] pincell.tallies.append(zernike_tally) # Add an energy function tally energyfunc_tally = openmc.Tally() energyfunc_filter = openmc.EnergyFunctionFilter([0.0, 20e6], [0.0, 20e6]) energyfunc_tally.scores = ['fission'] energyfunc_tally.filters = [energyfunc_filter] pincell.tallies.append(energyfunc_tally) # Write XML files in tmpdir with cdtemp(): pincell.export_to_xml() yield
def test_init(run_in_tmpdir, pin_model_attributes, mpi_intracomm): mats, geom, settings, tals, plots, _, _ = \ pin_model_attributes openmc.reset_auto_ids() # Check blank initialization of a model test_model = openmc.Model() assert test_model.geometry.root_universe is None assert len(test_model.materials) == 0 ref_settings = openmc.Settings() assert sorted(test_model.settings.__dict__.keys()) == \ sorted(ref_settings.__dict__.keys()) for ref_k, ref_v in ref_settings.__dict__.items(): assert test_model.settings.__dict__[ref_k] == ref_v assert len(test_model.tallies) == 0 assert len(test_model.plots) == 0 assert test_model._materials_by_id == {} assert test_model._materials_by_name == {} assert test_model._cells_by_id == {} assert test_model._cells_by_name == {} assert test_model.is_initialized is False # Now check proper init of an actual model. Assume no interference between # parameters and so we can apply them all at once instead of testing one # parameter initialization at a time test_model = openmc.Model(geom, mats, settings, tals, plots) assert test_model.geometry is geom assert test_model.materials is mats assert test_model.settings is settings assert test_model.tallies is tals assert test_model.plots is plots assert test_model._materials_by_id == {1: mats[0], 2: mats[1], 3: mats[2]} assert test_model._materials_by_name == { 'UO2': {mats[0]}, 'Zirc': {mats[1]}, 'Borated water': {mats[2]} } # The last cell is the one that contains the infinite fuel assert test_model._cells_by_id == \ {2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3], 4: geom.root_universe.cells[4], 1: geom.root_universe.cells[2].fill.cells[1]} # No cell name for 2 and 3, so we expect a blank name to be assigned to # cell 3 due to overwriting assert test_model._cells_by_name == { 'fuel': {geom.root_universe.cells[2]}, '': {geom.root_universe.cells[3], geom.root_universe.cells[4]}, 'inf fuel': {geom.root_universe.cells[2].fill.cells[1]} } assert test_model.is_initialized is False # Finally test the parameter type checking by passing bad types and # obtaining the right exception types def_params = [geom, mats, settings, tals, plots] for i in range(len(def_params)): args = def_params.copy() # Try an integer, as that is a bad type for all arguments args[i] = i with pytest.raises(TypeError): test_model = openmc.Model(*args)
def setup_regression_test(request): # Reset autogenerated IDs assigned to OpenMC objects openmc.reset_auto_ids() # Change to test directory olddir = request.fspath.dirpath().chdir() try: yield finally: olddir.chdir()
def model(request): openmc.reset_auto_ids() marker = request.node.get_closest_marker("surf_source_op") surf_source_op = marker.args[0] openmc_model = openmc.model.Model() # Materials # None # Geometry # Concentric void spheres # - Innermost sphere to bank surface sources # - Second shell to tally cell flux # - Outermost sphere as vacuum boundary sph_1 = openmc.Sphere(r=1.0) # Surface to bank/write sources. sph_2 = openmc.Sphere(r=2.0) sph_3 = openmc.Sphere(r=2.5) sph_4 = openmc.Sphere(r=4.0, boundary_type='vacuum') cell_1 = openmc.Cell(region=-sph_1) cell_2 = openmc.Cell(region=+sph_1 & -sph_2) cell_3 = openmc.Cell(region=+sph_2 & -sph_3) # Cell to tally flux. cell_4 = openmc.Cell(region=+sph_3 & -sph_4) root = openmc.Universe(cells=[cell_1, cell_2, cell_3, cell_4]) openmc_model.geometry = openmc.Geometry(root) # Settings openmc_model.settings.run_mode = 'fixed source' openmc_model.settings.particles = 1000 openmc_model.settings.batches = 10 openmc_model.settings.seed = 1 if surf_source_op == 'write': point = openmc.stats.Point((0, 0, 0)) pt_src = openmc.Source(space=point) openmc_model.settings.source = pt_src openmc_model.settings.surf_source_write = { 'surface_ids': [1], 'max_particles': 1000 } elif surf_source_op == 'read': openmc_model.settings.surf_source_read = { 'path': 'surface_source_true.h5' } # Tallies tal = openmc.Tally() cell_filter = openmc.CellFilter(cell_3) tal.filters = [cell_filter] tal.scores = ['flux'] openmc_model.tallies.append(tal) return openmc_model
def pincell_model_w_univ(): """Set up a model to test with and delete files when done""" openmc.reset_auto_ids() pincell = openmc.examples.pwr_pin_cell() clad_univ = openmc.Universe(cells=[openmc.Cell(fill=pincell.materials[1])]) pincell.geometry.root_universe.cells[2].fill = clad_univ pincell.settings.verbosity = 1 # Write XML files in tmpdir with cdtemp(): pincell.export_to_xml() yield
def __call__(self, vec, power): """Runs a simulation. Simulation will abort under the following circumstances: 1) No energy is computed using OpenMC tallies. Parameters ---------- vec : list of numpy.ndarray Total atoms to be used in function. power : float Power of the reactor in [W] Returns ------- openmc.deplete.OperatorResult Eigenvalue and reaction rates resulting from transport operator """ # Reset results in OpenMC openmc.lib.reset() # If the source rate is zero, return zero reaction rates without running # a transport solve if power == 0.0: rates = self.reaction_rates.copy() rates.fill(0.0) return OperatorResult(ufloat(0.0, 0.0), rates) # Prevent OpenMC from complaining about re-creating tallies openmc.reset_auto_ids() # Update status self.number.set_density(vec) # Update material compositions and tally nuclides self._update_materials() nuclides = self._get_tally_nuclides() self._rate_helper.nuclides = nuclides self._energy_helper.nuclides = nuclides self._yield_helper.update_tally_nuclides(nuclides) # Run OpenMC openmc.lib.run() openmc.lib.reset_timers() # Extract results op_result = self._unpack_tallies_and_normalize(power) return copy.deepcopy(op_result)
def __init__(self, filename): # A user may not have h5py, but they can still use the rest of the # Python API so we'll only try to import h5py if the user actually inits # a Summary object. import h5py openmc.reset_auto_ids() if not filename.endswith(('.h5', '.hdf5')): msg = 'Unable to open "{0}" which is not an HDF5 summary file' raise ValueError(msg) self._f = h5py.File(filename, 'r') self.openmc_geometry = None self.opencg_geometry = None self._read_metadata() self._read_geometry() self._read_tallies()
def __init__(self, filename): # A user may not have h5py, but they can still use the rest of the # Python API so we'll only try to import h5py if the user actually inits # a Summary object. import h5py openmc.reset_auto_ids() if not filename.endswith(('.h5', '.hdf5')): msg = 'Unable to open "{0}" which is not an HDF5 summary file' raise ValueError(msg) self._f = h5py.File(filename, 'r') self._openmc_geometry = None self._opencg_geometry = None self._read_metadata() self._read_geometry() self._read_tallies()
def test_import_properties(run_in_tmpdir, mpi_intracomm): """Test importing properties on the Model class """ # Create PWR pin cell model and write XML files openmc.reset_auto_ids() model = openmc.examples.pwr_pin_cell() model.init_lib(output=False, intracomm=mpi_intracomm) # Change fuel temperature and density and export properties cell = openmc.lib.cells[1] cell.set_temperature(600.0) cell.fill.set_density(5.0, 'g/cm3') openmc.lib.export_properties(output=False) # Import properties to existing model model.import_properties("properties.h5") # Check to see that values are assigned to the C and python representations # First python cell = model.geometry.get_all_cells()[1] assert cell.temperature == [600.0] assert cell.fill.get_mass_density() == pytest.approx(5.0) # Now C assert openmc.lib.cells[1].get_temperature() == 600. assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0) # Clear the C API openmc.lib.finalize() # Verify the attributes survived by exporting to XML and re-creating model.export_to_xml("with_properties") # Load model with properties and confirm temperature/density changed model_with_properties = openmc.Model.from_xml( 'with_properties/geometry.xml', 'with_properties/materials.xml', 'with_properties/settings.xml') cell = model_with_properties.geometry.get_all_cells()[1] assert cell.temperature == [600.0] assert cell.fill.get_mass_density() == pytest.approx(5.0)
def __init__(self, filename): openmc.reset_auto_ids() if not filename.endswith(('.h5', '.hdf5')): msg = 'Unable to open "{0}" which is not an HDF5 summary file' raise ValueError(msg) self._f = h5py.File(filename, 'r') cv.check_filetype_version(self._f, 'summary', _VERSION_SUMMARY) self._geometry = openmc.Geometry() self._fast_materials = {} self._fast_surfaces = {} self._fast_cells = {} self._fast_universes = {} self._fast_lattices = {} self._materials = openmc.Materials() self._nuclides = {} self._read_nuclides() self._read_geometry()
def test_unstructured_mesh(test_opts): openmc.reset_auto_ids() # skip the test if the library is not enabled if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): pytest.skip("DAGMC (and MOAB) mesh not enbaled in this build.") if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): pytest.skip("LibMesh is not enabled in this build.") # skip the tracklength test for libmesh if test_opts['library'] == 'libmesh' and \ test_opts['estimator'] == 'tracklength': pytest.skip("Tracklength tallies are not supported using libmesh.") ### Materials ### materials = openmc.Materials() fuel_mat = openmc.Material(name="fuel") fuel_mat.add_nuclide("U235", 1.0) fuel_mat.set_density('g/cc', 4.5) materials.append(fuel_mat) zirc_mat = openmc.Material(name="zircaloy") zirc_mat.add_element("Zr", 1.0) zirc_mat.set_density("g/cc", 5.77) materials.append(zirc_mat) water_mat = openmc.Material(name="water") water_mat.add_nuclide("H1", 2.0) water_mat.add_nuclide("O16", 1.0) water_mat.set_density("atom/b-cm", 0.07416) materials.append(water_mat) materials.export_to_xml() ### Geometry ### fuel_min_x = openmc.XPlane(-5.0, name="minimum x") fuel_max_x = openmc.XPlane(5.0, name="maximum x") fuel_min_y = openmc.YPlane(-5.0, name="minimum y") fuel_max_y = openmc.YPlane(5.0, name="maximum y") fuel_min_z = openmc.ZPlane(-5.0, name="minimum z") fuel_max_z = openmc.ZPlane(5.0, name="maximum z") fuel_cell = openmc.Cell(name="fuel") fuel_cell.region = +fuel_min_x & -fuel_max_x & \ +fuel_min_y & -fuel_max_y & \ +fuel_min_z & -fuel_max_z fuel_cell.fill = fuel_mat clad_min_x = openmc.XPlane(-6.0, name="minimum x") clad_max_x = openmc.XPlane(6.0, name="maximum x") clad_min_y = openmc.YPlane(-6.0, name="minimum y") clad_max_y = openmc.YPlane(6.0, name="maximum y") clad_min_z = openmc.ZPlane(-6.0, name="minimum z") clad_max_z = openmc.ZPlane(6.0, name="maximum z") clad_cell = openmc.Cell(name="clad") clad_cell.region = (-fuel_min_x | +fuel_max_x | -fuel_min_y | +fuel_max_y | -fuel_min_z | +fuel_max_z) & \ (+clad_min_x & -clad_max_x & +clad_min_y & -clad_max_y & +clad_min_z & -clad_max_z) clad_cell.fill = zirc_mat if test_opts['external_geom']: bounds = (15, 15, 15) else: bounds = (10, 10, 10) water_min_x = openmc.XPlane(x0=-bounds[0], name="minimum x", boundary_type='vacuum') water_max_x = openmc.XPlane(x0=bounds[0], name="maximum x", boundary_type='vacuum') water_min_y = openmc.YPlane(y0=-bounds[1], name="minimum y", boundary_type='vacuum') water_max_y = openmc.YPlane(y0=bounds[1], name="maximum y", boundary_type='vacuum') water_min_z = openmc.ZPlane(z0=-bounds[2], name="minimum z", boundary_type='vacuum') water_max_z = openmc.ZPlane(z0=bounds[2], name="maximum z", boundary_type='vacuum') water_cell = openmc.Cell(name="water") water_cell.region = (-clad_min_x | +clad_max_x | -clad_min_y | +clad_max_y | -clad_min_z | +clad_max_z) & \ (+water_min_x & -water_max_x & +water_min_y & -water_max_y & +water_min_z & -water_max_z) water_cell.fill = water_mat # create a containing universe geometry = openmc.Geometry([fuel_cell, clad_cell, water_cell]) ### Tallies ### # create meshes and mesh filters regular_mesh = openmc.RegularMesh() regular_mesh.dimension = (10, 10, 10) regular_mesh.lower_left = (-10.0, -10.0, -10.0) regular_mesh.upper_right = (10.0, 10.0, 10.0) regular_mesh_filter = openmc.MeshFilter(mesh=regular_mesh) if test_opts['holes']: mesh_filename = "test_mesh_tets_w_holes.e" else: mesh_filename = "test_mesh_tets.e" uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_opts['library']) uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) # create tallies tallies = openmc.Tallies() regular_mesh_tally = openmc.Tally(name="regular mesh tally") regular_mesh_tally.filters = [regular_mesh_filter] regular_mesh_tally.scores = ['flux'] regular_mesh_tally.estimator = test_opts['estimator'] tallies.append(regular_mesh_tally) uscd_tally = openmc.Tally(name="unstructured mesh tally") uscd_tally.filters = [uscd_filter] uscd_tally.scores = ['flux'] uscd_tally.estimator = test_opts['estimator'] tallies.append(uscd_tally) ### Settings ### settings = openmc.Settings() settings.run_mode = 'fixed source' settings.particles = 1000 settings.batches = 10 # source setup r = openmc.stats.Uniform(a=0.0, b=0.0) theta = openmc.stats.Discrete(x=[0.0], p=[1.0]) phi = openmc.stats.Discrete(x=[0.0], p=[1.0]) space = openmc.stats.SphericalIndependent(r, theta, phi) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) source = openmc.Source(space=space, energy=energy) settings.source = source model = openmc.model.Model(geometry=geometry, materials=materials, tallies=tallies, settings=settings) harness = UnstructuredMeshTest('statepoint.10.h5', model, test_opts['inputs_true'], test_opts['holes']) harness.main()
def model(): openmc.reset_auto_ids() model = openmc.Model() # materials (M4 steel alloy) m4 = openmc.Material() m4.set_density('g/cc', 2.3) m4.add_nuclide('H1', 0.168018676) m4.add_nuclide("H2", 1.93244e-05) m4.add_nuclide("O16", 0.561814465) m4.add_nuclide("O17", 0.00021401) m4.add_nuclide("Na23", 0.021365) m4.add_nuclide("Al27", 0.021343) m4.add_nuclide("Si28", 0.187439342) m4.add_nuclide("Si29", 0.009517714) m4.add_nuclide("Si30", 0.006273944) m4.add_nuclide("Ca40", 0.018026179) m4.add_nuclide("Ca42", 0.00012031) m4.add_nuclide("Ca43", 2.51033e-05) m4.add_nuclide("Ca44", 0.000387892) m4.add_nuclide("Ca46", 7.438e-07) m4.add_nuclide("Ca48", 3.47727e-05) m4.add_nuclide("Fe54", 0.000248179) m4.add_nuclide("Fe56", 0.003895875) m4.add_nuclide("Fe57", 8.99727e-05) m4.add_nuclide("Fe58", 1.19737e-05) s0 = openmc.Sphere(r=240) s1 = openmc.Sphere(r=250, boundary_type='vacuum') c0 = openmc.Cell(fill=m4, region=-s0) c1 = openmc.Cell(region=+s0 & -s1) model.geometry = openmc.Geometry([c0, c1]) # settings settings = model.settings settings.run_mode = 'fixed source' settings.particles = 500 settings.batches = 2 settings.max_splits = 100 settings.photon_transport = True space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) settings.source = openmc.Source(space=space, energy=energy) # tally mesh = openmc.RegularMesh() mesh.lower_left = (-240, -240, -240) mesh.upper_right = (240, 240, 240) mesh.dimension = (3, 5, 7) mesh_filter = openmc.MeshFilter(mesh) e_bnds = [0.0, 0.5, 2E7] energy_filter = openmc.EnergyFilter(e_bnds) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally = openmc.Tally() tally.filters = [mesh_filter, energy_filter, particle_filter] tally.scores = ['flux'] model.tallies.append(tally) return model
def __init__(self, geometry, settings, chain_file=None, prev_results=None, diff_burnable_mats=False, energy_mode="fission-q", fission_q=None, dilute_initial=1.0e3, fission_yield_mode="constant", fission_yield_opts=None): if fission_yield_mode not in self._fission_helpers: raise KeyError( "fission_yield_mode must be one of {}, not {}".format( ", ".join(self._fission_helpers), fission_yield_mode)) if energy_mode == "energy-deposition": if fission_q is not None: warn("Fission Q dictionary not used if energy deposition " "is used") fission_q = None elif energy_mode != "fission-q": raise ValueError( "energy_mode {} not supported. Must be energy-deposition " "or fission-q".format(energy_mode)) super().__init__(chain_file, fission_q, dilute_initial, prev_results) self.round_number = False self.prev_res = None self.settings = settings self.geometry = geometry self.diff_burnable_mats = diff_burnable_mats # Differentiate burnable materials with multiple instances if self.diff_burnable_mats: self._differentiate_burnable_mats() # Clear out OpenMC, create task lists, distribute openmc.reset_auto_ids() self.burnable_mats, volume, nuclides = self._get_burnable_mats() self.local_mats = _distribute(self.burnable_mats) # Generate map from local materials => material index self._mat_index_map = { lm: self.burnable_mats.index(lm) for lm in self.local_mats } if self.prev_res is not None: # Reload volumes into geometry prev_results[-1].transfer_volumes(geometry) # Store previous results in operator # Distribute reaction rates according to those tracked # on this process if comm.size == 1: self.prev_res = prev_results else: self.prev_res = ResultsList() mat_indexes = _distribute(range(len(self.burnable_mats))) for res_obj in prev_results: new_res = res_obj.distribute(self.local_mats, mat_indexes) self.prev_res.append(new_res) # Determine which nuclides have incident neutron data self.nuclides_with_data = self._get_nuclides_with_data() # Select nuclides with data that are also in the chain self._burnable_nucs = [ nuc.name for nuc in self.chain.nuclides if nuc.name in self.nuclides_with_data ] # Extract number densities from the geometry / previous depletion run self._extract_number(self.local_mats, volume, nuclides, self.prev_res) # Create reaction rates array self.reaction_rates = ReactionRates(self.local_mats, self._burnable_nucs, self.chain.reactions) # Get classes to assist working with tallies self._rate_helper = DirectReactionRateHelper( self.reaction_rates.n_nuc, self.reaction_rates.n_react) if energy_mode == "fission-q": self._energy_helper = ChainFissionHelper() else: score = "heating" if settings.photon_transport else "heating-local" self._energy_helper = EnergyScoreHelper(score) # Select and create fission yield helper fission_helper = self._fission_helpers[fission_yield_mode] fission_yield_opts = ({} if fission_yield_opts is None else fission_yield_opts) self._yield_helper = fission_helper.from_operator( self, **fission_yield_opts)
def clean_up_openmc(): """ Resets all automatic indexing in OpenMC, as these get in the way. """ openmc.reset_auto_ids()
def main(): parser = argparse.ArgumentParser() parser.add_argument('-l', '--benchmarks', type=pathlib.Path, default=pathlib.Path('benchmarks/lists/pst-short'), help='List of benchmarks to run.') parser.add_argument('-c', '--code', choices=['openmc', 'mcnp'], default='openmc', help='Code used to run benchmarks.') parser.add_argument('-x', '--cross-sections', type=str, default=os.getenv('OPENMC_CROSS_SECTIONS'), help='OpenMC cross sections XML file.') parser.add_argument('-s', '--suffix', type=str, default='70c', help='MCNP cross section suffix') parser.add_argument('-p', '--particles', type=int, default=10000, help='Number of source particles.') parser.add_argument('-b', '--batches', type=int, default=150, help='Number of batches.') parser.add_argument('-i', '--inactive', type=int, default=50, help='Number of inactive batches.') parser.add_argument('-m', '--max-batches', type=int, default=10000, help='Maximum number of batches.') parser.add_argument('-t', '--threshold', type=float, default=0.0001, help='Value of the standard deviation trigger on ' 'eigenvalue.') parser.add_argument('-o', '--output-name', type=str, help='Base filename for plot.') parser.add_argument('-f', '--output-format', type=str, default='png', help='File format for plot.') args = parser.parse_args() # Create timestamp current_time = time.localtime() timestamp = time.strftime("%Y-%m-%d-%H%M%S", current_time) # Check that executable exists executable = 'mcnp6' if args.code == 'mcnp' else 'openmc' if not shutil.which(executable, os.X_OK): msg = f'Unable to locate executable {executable} in path.' raise IOError(msg) # Create directory and set filename for results os.makedirs('results', exist_ok=True) outfile = f'results/{timestamp}.csv' # Get a copy of the benchmarks repository if not pathlib.Path('benchmarks').is_dir(): repo = 'https://github.com/mit-crpg/benchmarks.git' subprocess.run(['git', 'clone', repo], check=True) # Get the list of benchmarks to run if not args.benchmarks.is_file(): msg = f'Unable to locate benchmark list {args.benchmarks}.' raise IOError(msg) with open(args.benchmarks) as f: benchmarks = f.read().split() # Prepare and run benchmarks for benchmark in benchmarks: path = pathlib.Path('benchmarks') / benchmark if args.code == 'openmc': openmc.reset_auto_ids() # Remove old statepoint files for f in path.glob('statepoint.*.h5'): os.remove(f) # Modify settings settings = openmc.Settings.from_xml(path / 'settings.xml') settings.particles = args.particles settings.inactive = args.inactive settings.batches = args.batches settings.keff_trigger = {'type': 'std_dev', 'threshold': args.threshold} settings.trigger_active = True settings.trigger_max_batches = args.max_batches settings.output = {'tallies': False} settings.export_to_xml(path) # Set path to cross sections XML materials = openmc.Materials.from_xml(path / 'materials.xml') materials.cross_sections = args.cross_sections materials.export_to_xml(path / 'materials.xml') # Run benchmark openmc.run(cwd=path) # Read k-effective mean and standard deviation from statepoint filename = list(path.glob('statepoint.*.h5'))[0] with openmc.StatePoint(filename) as sp: mean = sp.k_combined.nominal_value stdev = sp.k_combined.std_dev elif args.code == 'mcnp': # Read input file with open(path / 'input', 'r') as f: lines = f.readlines() # Update criticality source card line = f'kcode {args.particles} 1 {args.inactive} {args.batches}\n' for i in range(len(lines)): if lines[i].strip().startswith('kcode'): lines[i] = line break # Update cross section suffix match = '(7[0-4]c)|(8[0-6]c)' if not re.match(match, args.suffix): msg = f'Unsupported cross section suffix {args.suffix}.' raise ValueError(msg) lines = [re.sub(match, args.suffix, x) for x in lines] # Write new input file with open(path / 'input', 'w') as f: f.write(''.join(lines)) # Remove old MCNP output files for f in ('outp', 'runtpe', 'srctp'): try: os.remove(path / f) except OSError: pass # Run benchmark and capture and print output arg_list = [executable, 'inp=input'] p = subprocess.Popen( args=arg_list, cwd=path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True ) while True: line = p.stdout.readline() if not line and p.poll() is not None: break print(line, end='') # Read k-effective mean and standard deviation from output with open(path / 'outp', 'r') as f: line = f.readline() while not line.strip().startswith('col/abs/trk len'): line = f.readline() words = line.split() mean = float(words[2]) stdev = float(words[3]) # Write results words = benchmark.split('/') name = words[1] case = words[3] if len(words) > 3 else '' line = '{}, {}, {}, {}'.format(name, case, mean, stdev) if benchmark != benchmarks[-1]: line += '\n' with open(outfile, 'a') as f: f.write(line) plot(outfile, output_name=args.output_name, output_format=args.output_format)
def main(): parser = argparse.ArgumentParser() parser.add_argument('-l', '--benchmarks', type=Path, default=Path('benchmarks/lists/pst-short'), help='List of benchmarks to run.') parser.add_argument('-c', '--code', choices=['openmc', 'mcnp'], default='openmc', help='Code used to run benchmarks.') parser.add_argument('-x', '--cross-sections', type=str, default=os.getenv('OPENMC_CROSS_SECTIONS'), help='OpenMC cross sections XML file.') parser.add_argument('-s', '--suffix', type=str, default='70c', help='MCNP cross section suffix') parser.add_argument('-p', '--particles', type=int, default=10000, help='Number of source particles.') parser.add_argument('-b', '--batches', type=int, default=150, help='Number of batches.') parser.add_argument('-i', '--inactive', type=int, default=50, help='Number of inactive batches.') parser.add_argument('-m', '--max-batches', type=int, default=10000, help='Maximum number of batches.') parser.add_argument( '-t', '--threshold', type=float, default=0.0001, help='Value of the standard deviation trigger on eigenvalue.') parser.add_argument( '--mpi-args', default="", help="MPI execute command and any additional MPI arguments") args = parser.parse_args() # Create timestamp timestamp = time.strftime("%Y-%m-%d-%H%M%S") # Check that executable exists executable = 'mcnp6' if args.code == 'mcnp' else 'openmc' if not shutil.which(executable, os.X_OK): msg = f'Unable to locate executable {executable} in path.' raise IOError(msg) mpi_args = args.mpi_args.split() # Create directory and set filename for results results_dir = Path('results') results_dir.mkdir(exist_ok=True) outfile = results_dir / f'{timestamp}.csv' # Get a copy of the benchmarks repository if not Path('benchmarks').is_dir(): repo = 'https://github.com/mit-crpg/benchmarks.git' subprocess.run(['git', 'clone', repo], check=True) # Get the list of benchmarks to run if not args.benchmarks.is_file(): msg = f'Unable to locate benchmark list {args.benchmarks}.' raise IOError(msg) with open(args.benchmarks) as f: benchmarks = [Path(line) for line in f.read().split()] # Set cross sections if args.cross_sections is not None: os.environ["OPENMC_CROSS_SECTIONS"] = args.cross_sections # Prepare and run benchmarks for i, benchmark in enumerate(benchmarks): print(f"{i + 1} {benchmark} ", end="", flush=True) path = 'benchmarks' / benchmark if args.code == 'openmc': openmc.reset_auto_ids() # Remove old statepoint files for f in path.glob('statepoint.*.h5'): os.remove(f) # Modify settings settings = openmc.Settings.from_xml(path / 'settings.xml') settings.particles = args.particles settings.inactive = args.inactive settings.batches = args.batches settings.keff_trigger = { 'type': 'std_dev', 'threshold': args.threshold } settings.trigger_active = True settings.trigger_max_batches = args.max_batches settings.output = {'tallies': False} settings.export_to_xml(path) # Re-generate materials if Python script is present genmat_script = path / "generate_materials.py" if genmat_script.is_file(): subprocess.run(["python", "generate_materials.py"], cwd=path) # Run benchmark proc = subprocess.run( mpi_args + ["openmc"], cwd=path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, ) # Determine last statepoint t_last = 0 last_statepoint = None for sp in path.glob('statepoint.*.h5'): mtime = sp.stat().st_mtime if mtime >= t_last: t_last = mtime last_statepoint = sp # Read k-effective mean and standard deviation from statepoint if last_statepoint is not None: with openmc.StatePoint(last_statepoint) as sp: mean = sp.k_combined.nominal_value stdev = sp.k_combined.std_dev else: # Read input file with open(path / 'input', 'r') as f: lines = f.readlines() # Update criticality source card line = f'kcode {args.particles} 1 {args.inactive} {args.batches}\n' for i in range(len(lines)): if lines[i].strip().startswith('kcode'): lines[i] = line break # Update cross section suffix match = '(7[0-4]c)|(8[0-6]c)' if not re.match(match, args.suffix): msg = f'Unsupported cross section suffix {args.suffix}.' raise ValueError(msg) lines = [re.sub(match, args.suffix, x) for x in lines] # Write new input file with open(path / 'input', 'w') as f: f.write(''.join(lines)) # Remove old MCNP output files for f in ('outp', 'runtpe', 'srctp'): try: os.remove(path / f) except OSError: pass # Run benchmark and capture and print output arg_list = mpi_args + [executable, 'inp=input'] proc = subprocess.run(arg_list, cwd=path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) # Read k-effective mean and standard deviation from output with open(path / 'outp', 'r') as f: line = f.readline() while not line.strip().startswith('col/abs/trk len'): line = f.readline() words = line.split() mean = float(words[2]) stdev = float(words[3]) # Write output to file with open(path / f"output_{timestamp}", "w") as fh: fh.write(proc.stdout) if proc.returncode != 0: mean = stdev = "" print() else: # Display k-effective print(f"{mean:.5f} ± {stdev:.5f}") # Write results words = str(benchmark).split('/') name = words[1] case = '/' + words[3] if len(words) > 3 else '' line = f'{name}{case},{mean},{stdev}\n' with open(outfile, 'a') as f: f.write(line)
def reset(): openmc.reset_auto_ids()
def __init__(self, geometry, settings, chain_file=None, prev_results=None, diff_burnable_mats=False, normalization_mode="fission-q", fission_q=None, dilute_initial=1.0e3, fission_yield_mode="constant", fission_yield_opts=None, reaction_rate_mode="direct", reaction_rate_opts=None, reduce_chain=False, reduce_chain_level=None): check_value('fission yield mode', fission_yield_mode, self._fission_helpers.keys()) check_value('normalization mode', normalization_mode, ('energy-deposition', 'fission-q', 'source-rate')) if normalization_mode != "fission-q": if fission_q is not None: warn("Fission Q dictionary will not be used") fission_q = None super().__init__(chain_file, fission_q, dilute_initial, prev_results) self.round_number = False self.settings = settings self.geometry = geometry self.diff_burnable_mats = diff_burnable_mats # Reduce the chain before we create more materials if reduce_chain: all_isotopes = set() for material in geometry.get_all_materials().values(): if not material.depletable: continue for name, _dens_percent, _dens_type in material.nuclides: all_isotopes.add(name) self.chain = self.chain.reduce(all_isotopes, reduce_chain_level) # Differentiate burnable materials with multiple instances if self.diff_burnable_mats: self._differentiate_burnable_mats() # Clear out OpenMC, create task lists, distribute openmc.reset_auto_ids() self.burnable_mats, volume, nuclides = self._get_burnable_mats() self.local_mats = _distribute(self.burnable_mats) # Generate map from local materials => material index self._mat_index_map = { lm: self.burnable_mats.index(lm) for lm in self.local_mats } if self.prev_res is not None: # Reload volumes into geometry prev_results[-1].transfer_volumes(geometry) # Store previous results in operator # Distribute reaction rates according to those tracked # on this process if comm.size == 1: self.prev_res = prev_results else: self.prev_res = ResultsList() mat_indexes = _distribute(range(len(self.burnable_mats))) for res_obj in prev_results: new_res = res_obj.distribute(self.local_mats, mat_indexes) self.prev_res.append(new_res) # Determine which nuclides have incident neutron data self.nuclides_with_data = self._get_nuclides_with_data() # Select nuclides with data that are also in the chain self._burnable_nucs = [ nuc.name for nuc in self.chain.nuclides if nuc.name in self.nuclides_with_data ] # Extract number densities from the geometry / previous depletion run self._extract_number(self.local_mats, volume, nuclides, self.prev_res) # Create reaction rates array self.reaction_rates = ReactionRates(self.local_mats, self._burnable_nucs, self.chain.reactions) # Get classes to assist working with tallies if reaction_rate_mode == "direct": self._rate_helper = DirectReactionRateHelper( self.reaction_rates.n_nuc, self.reaction_rates.n_react) elif reaction_rate_mode == "flux": if reaction_rate_opts is None: reaction_rate_opts = {} # Ensure energy group boundaries were specified if 'energies' not in reaction_rate_opts: raise ValueError( "Energy group boundaries must be specified in the " "reaction_rate_opts argument when reaction_rate_mode is" "set to 'flux'.") self._rate_helper = FluxCollapseHelper(self.reaction_rates.n_nuc, self.reaction_rates.n_react, **reaction_rate_opts) else: raise ValueError("Invalid reaction rate mode.") if normalization_mode == "fission-q": self._normalization_helper = ChainFissionHelper() elif normalization_mode == "energy-deposition": score = "heating" if settings.photon_transport else "heating-local" self._normalization_helper = EnergyScoreHelper(score) else: self._normalization_helper = SourceRateHelper() # Select and create fission yield helper fission_helper = self._fission_helpers[fission_yield_mode] fission_yield_opts = ({} if fission_yield_opts is None else fission_yield_opts) self._yield_helper = fission_helper.from_operator( self, **fission_yield_opts)