diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index b969454981..2c14cf7f84 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -955,7 +955,9 @@ Each ```` element can have the following attributes or sub-elements: :material: The ``id`` of the material that this cell contains. If the cell should - contain no material, this can also be set to "void". + contain no material, this can also be set to "void". A list of materials + can be specified for the "distributed material" feature. This will give each + unique instance of the cell its own material. .. note:: If a material is specified, no fill should be given. diff --git a/docs/source/usersguide/output/summary.rst b/docs/source/usersguide/output/summary.rst index 66a5cad154..83602e5065 100644 --- a/docs/source/usersguide/output/summary.rst +++ b/docs/source/usersguide/output/summary.rst @@ -91,10 +91,12 @@ The current revision of the summary file format is 1. Type of fill for the cell. Can be 'normal', 'universe', or 'lattice'. -**/geometry/cells/cell /material** (*int*) +**/geometry/cells/cell /material** (*int* or *int[]*) - Unique ID of the material assigned to the cell. This dataset is present only - if fill_type is set to 'normal'. + Unique ID of the material(s) assigned to the cell. This dataset is present + only if fill_type is set to 'normal'. The value '-1' signifies void + material. The data is an array if the cell uses distributed materials, + otherwise it is a scalar. **/geometry/cells/cell /offset** (*int[]*) diff --git a/openmc/geometry.py b/openmc/geometry.py index fc8e19f071..9788671f5c 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,4 +1,4 @@ -from collections import OrderedDict +from collections import Iterable, OrderedDict from xml.etree import ElementTree as ET import openmc @@ -140,7 +140,10 @@ class Geometry(object): materials = set() for cell in material_cells: - materials.add(cell._fill) + if isinstance(cell.fill, Iterable): + for m in cell.fill: materials.add(m) + else: + materials.add(cell.fill) materials = list(materials) materials.sort(key=lambda x: x.id) diff --git a/openmc/summary.py b/openmc/summary.py index 46fec01d50..ad1dd67cae 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -1,3 +1,4 @@ +from collections import Iterable import numpy as np import re @@ -477,10 +478,14 @@ class Summary(object): # Retrieve the object corresponding to the fill type and ID if fill_type == 'normal': - if fill_id > 0: - fill = self.get_material_by_id(fill_id) + if isinstance(fill_id, Iterable): + fill = [self.get_material_by_id(mat) if mat > 0 else 'void' + for mat in fill_id] else: - fill = 'void' + if fill_id > 0: + fill = self.get_material_by_id(fill_id) + else: + fill = 'void' elif fill_type == 'universe': fill = self.get_universe_by_id(fill_id) else: diff --git a/openmc/universe.py b/openmc/universe.py index 8417f27c71..ccd0cb27c3 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -50,7 +50,7 @@ class Cell(object): Unique identifier for the cell name : str Name of the cell - fill : Material or Universe or Lattice or 'void' + fill : Material or Universe or Lattice or 'void' or iterable of Material Indicates what the region of space is filled with region : openmc.region.Region Region of space that is assigned to the cell. @@ -112,6 +112,12 @@ class Cell(object): if isinstance(self._fill, openmc.Material): string += '{0: <16}{1}{2}\n'.format('\tMaterial', '=\t', self._fill._id) + elif isinstance(self._fill, Iterable): + string += '{0: <16}{1}'.format('\tMaterial', '=\t') + string += '[' + string += ', '.join(['void' if m == 'void' else str(m.id) + for m in self.fill]) + string += ']\n' elif isinstance(self._fill, (Universe, Lattice)): string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t', self._fill._id) @@ -205,6 +211,11 @@ class Cell(object): elif isinstance(fill, openmc.Material): self._type = 'normal' + elif isinstance(fill, Iterable): + cv.check_type('cell.fill', fill, Iterable, + (openmc.Material, basestring)) + self._type = 'normal' + elif isinstance(fill, Universe): self._type = 'fill' @@ -394,6 +405,10 @@ class Cell(object): if isinstance(self._fill, openmc.Material): element.set("material", str(self._fill._id)) + elif isinstance(self._fill, Iterable): + element.set("material", ' '.join([m if m == 'void' else str(m.id) + for m in self.fill])) + elif isinstance(self._fill, (Universe, Lattice)): element.set("fill", str(self._fill._id)) self._fill.create_xml_subelement(xml_element) diff --git a/src/constants.F90 b/src/constants.F90 index d51b039bbe..1238677195 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -139,6 +139,9 @@ module constants ! Maximum number of lost particles integer, parameter :: MAX_LOST_PARTICLES = 10 + ! Maximum number of lost particles, relative to the total number of particles + real(8), parameter :: REL_MAX_LOST_PARTICLES = 1e-6_8 + ! ============================================================================ ! CROSS SECTION RELATED CONSTANTS diff --git a/src/geometry.F90 b/src/geometry.F90 index 94f8876ed4..8a38f982b5 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -193,7 +193,9 @@ contains logical, intent(inout) :: found integer, optional :: search_cells(:) integer :: i ! index over cells - integer :: j ! coordinate level index + integer :: j, k ! coordinate level index + integer :: offset ! instance # of a distributed cell + integer :: distribcell_index integer :: i_xyz(3) ! indices in lattice integer :: n ! number of cells to search integer :: index_cell ! index in cells array @@ -246,9 +248,36 @@ contains ! ====================================================================== ! AT LOWEST UNIVERSE, TERMINATE SEARCH - ! set material + ! Set the particle material p % last_material = p % material - p % material = c % material + if (size(c % material) == 1) then + ! Only one material for this cell; assign that one to the particle. + p % material = c % material(1) + else + ! Distributed instances of this cell have different materials. + ! Determine which instance this is and assign the matching material. + distribcell_index = c % distribcell_index + offset = 0 + do k = 1, p % n_coord + if (cells(p % coord(k) % cell) % type == CELL_FILL) then + offset = offset + cells(p % coord(k) % cell) % & + offset(distribcell_index) + elseif (cells(p % coord(k) % cell) % type == CELL_LATTICE) then + if (lattices(p % coord(k + 1) % lattice) % obj & + % are_valid_indices([& + p % coord(k + 1) % lattice_x, & + p % coord(k + 1) % lattice_y, & + p % coord(k + 1) % lattice_z])) then + offset = offset + lattices(p % coord(k + 1) % lattice) % obj % & + offset(distribcell_index, & + p % coord(k + 1) % lattice_x, & + p % coord(k + 1) % lattice_y, & + p % coord(k + 1) % lattice_z) + end if + end if + end do + p % material = c % material(offset + 1) + end if elseif (c % type == CELL_FILL) then CELL_TYPE ! ====================================================================== @@ -950,6 +979,8 @@ contains type(Particle), intent(inout) :: p character(*) :: message + integer(8) :: tot_n_particles + ! Print warning and write lost particle file call warning(message) call write_particle_restart(p) @@ -959,9 +990,13 @@ contains !$omp atomic n_lost_particles = n_lost_particles + 1 + ! Count the total number of simulated particles (on this processor) + tot_n_particles = n_batches * gen_per_batch * work + ! Abort the simulation if the maximum number of lost particles has been ! reached - if (n_lost_particles == MAX_LOST_PARTICLES) then + if (n_lost_particles >= MAX_LOST_PARTICLES .and. & + n_lost_particles >= REL_MAX_LOST_PARTICLES * tot_n_particles) then call fatal_error("Maximum number of lost particles has been reached.") end if diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 3dad3ba395..519b15bff4 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -126,9 +126,10 @@ module geometry_header integer :: fill ! universe # filling this cell integer :: instances ! number of instances of this cell in ! the geom - integer :: material ! Material within cell (0 for - ! universe) - integer, allocatable :: offset (:) ! Distribcell offset for tally + integer, allocatable :: material(:) ! Material within cell. Multiple + ! materials for distribcell + ! instances. 0 signifies a universe + integer, allocatable :: offset(:) ! Distribcell offset for tally ! counter integer, allocatable :: region(:) ! Definition of spatial region as ! Boolean expression of half-spaces diff --git a/src/initialize.F90 b/src/initialize.F90 index 30654be9d2..de681fb949 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -614,31 +614,33 @@ contains ! ======================================================================= ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL - id = c%material - if (id == MATERIAL_VOID) then - c%type = CELL_NORMAL - elseif (id /= 0) then - if (material_dict%has_key(id)) then - c%type = CELL_NORMAL - c%material = material_dict%get_key(id) - else - call fatal_error("Could not find material " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c%id))) - end if - else - id = c%fill - if (universe_dict%has_key(id)) then - c%type = CELL_FILL - c%fill = universe_dict%get_key(id) - elseif (lattice_dict%has_key(id)) then - lid = lattice_dict%get_key(id) - c%type = CELL_LATTICE - c%fill = lid + if (c % material(1) == NONE) then + id = c % fill + if (universe_dict % has_key(id)) then + c % type = CELL_FILL + c % fill = universe_dict % get_key(id) + elseif (lattice_dict % has_key(id)) then + lid = lattice_dict % get_key(id) + c % type = CELL_LATTICE + c % fill = lid else call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& - &// trim(to_str(c%id)) // " is neither a universe nor a & + // trim(to_str(c % id)) // " is neither a universe nor a & &lattice.") end if + else + do j = 1, size(c % material) + id = c % material(j) + if (id == MATERIAL_VOID) then + c % type = CELL_NORMAL + else if (material_dict % has_key(id)) then + c % type = CELL_NORMAL + c % material(j) = material_dict % get_key(id) + else + call fatal_error("Could not find material " // trim(to_str(id)) & + // " specified on cell " // trim(to_str(c % id))) + end if + end do end if end do @@ -943,86 +945,82 @@ contains subroutine prepare_distribcell() - integer :: i, j ! Tally, filter loop counters - integer :: n_filt ! Number of filters originally in tally - logical :: count_all ! Count all cells - type(TallyObject), pointer :: t ! Current tally - type(Universe), pointer :: univ ! Pointer to universe - type(Cell), pointer :: c ! Pointer to cell + integer :: i, j ! Tally, filter loop counters + logical :: distribcell_active ! Does simulation use distribcell? integer, allocatable :: univ_list(:) ! Target offsets integer, allocatable :: counts(:,:) ! Target count logical, allocatable :: found(:,:) ! Target found - count_all = .false. + ! Assume distribcell is not needed until proven otherwise. + distribcell_active = .false. - ! Loop over tallies + ! We need distribcell if any tallies have distribcell filters. do i = 1, n_tallies - - ! Get pointer to tally - t => tallies(i) - - n_filt = t%n_filters - - ! Loop over the filters to determine how many additional filters - ! need to be added to this tally - do j = 1, t%n_filters - - ! Determine type of filter - if (t%filters(j)%type == FILTER_DISTRIBCELL) then - count_all = .true. - if (size(t%filters(j)%int_bins) > 1) then + do j = 1, tallies(i) % n_filters + if (tallies(i) % filters(j) % type == FILTER_DISTRIBCELL) then + distribcell_active = .true. + if (size(tallies(i) % filters(j) % int_bins) > 1) then call fatal_error("A distribcell filter was specified with & &multiple bins. This feature is not supported.") end if end if - end do - end do - if (count_all) then - - univ => universes(BASE_UNIVERSE) - - ! sum the number of occurrences of all cells - call count_instance(univ) - - ! Loop over tallies - do i = 1, n_tallies - - ! Get pointer to tally - t => tallies(i) - - ! Initialize the filters - do j = 1, t%n_filters - - ! Set the number of bins to the number of instances of the cell - if (t%filters(j)%type == FILTER_DISTRIBCELL) then - c => cells(t%filters(j)%int_bins(1)) - t%filters(j)%n_bins = c%instances - end if - - end do + ! We also need distribcell if any distributed materials are present. + if (.not. distribcell_active) then + do i = 1, n_cells + if (size(cells(i) % material) > 1) then + distribcell_active = .true. + exit + end if end do - end if + ! If distribcell isn't used in this simulation then no more work left to do. + if (.not. distribcell_active) return + + ! Count the number of instances of each cell. + call count_instance(universes(BASE_UNIVERSE)) + + ! Set the number of bins in all distribcell filters. + do i = 1, n_tallies + do j = 1, tallies(i) % n_filters + associate (filt => tallies(i) % filters(j)) + if (filt % type == FILTER_DISTRIBCELL) then + ! Set the number of bins to the number of instances of the cell. + filt % n_bins = cells(filt % int_bins(1)) % instances + end if + end associate + end do + end do + + ! Make sure the number of materials matches the number of cell instances for + ! distributed materials. + do i = 1, n_cells + associate (c => cells(i)) + if (size(c % material) > 1) then + if (size(c % material) /= c % instances) then + call fatal_error("Cell " // trim(to_str(c % id)) // " was & + &specified with " // trim(to_str(size(c % material))) & + // " materials but has " // trim(to_str(c % instances)) & + // " distributed instances. The number of materials must & + &equal one or the number of instances.") + end if + end if + end associate + end do + ! Allocate offset maps at each level in the geometry call allocate_offsets(univ_list, counts, found) ! Calculate offsets for each target distribcell do i = 1, n_maps do j = 1, n_universes - univ => universes(j) - call calc_offsets(univ_list(i), i, univ, counts, found) + call calc_offsets(univ_list(i), i, universes(j), counts, found) end do end do - ! Deallocate temporary target variable arrays - deallocate(counts) - deallocate(found) - deallocate(univ_list) - end subroutine prepare_distribcell !=============================================================================== @@ -1036,38 +1034,33 @@ contains integer, intent(out), allocatable :: counts(:,:) ! Target count logical, intent(out), allocatable :: found(:,:) ! Target found - integer :: i, j, k, l, m ! Loop counters - type(SetInt) :: cell_list ! distribells to track - type(Universe), pointer :: univ ! pointer to universe - class(Lattice), pointer :: lat ! pointer to lattice - type(TallyObject), pointer :: t ! pointer to tally - type(TallyFilter), pointer :: filter ! pointer to filter + integer :: i, j, k ! Loop counters + type(SetInt) :: cell_list ! distribells to track ! Begin gathering list of cells in distribcell tallies n_maps = 0 - ! Populate list of distribcells to track + ! List all cells referenced in distribcell filters. do i = 1, n_tallies - t => tallies(i) - - do j = 1, t % n_filters - filter => t % filters(j) - - if (filter % type == FILTER_DISTRIBCELL) then - if (.not. cell_list % contains(filter % int_bins(1))) then - call cell_list % add(filter % int_bins(1)) - end if + do j = 1, tallies(i) % n_filters + if (tallies(i) % filters(j) % type == FILTER_DISTRIBCELL) then + call cell_list % add(tallies(i) % filters(j) % int_bins(1)) end if - end do end do + ! List all cells with multiple (distributed) materials. + do i = 1, n_cells + if (size(cells(i) % material) > 1) then + call cell_list % add(i) + end if + end do + ! Compute the number of unique universes containing these distribcells ! to determine the number of offset tables to allocate do i = 1, n_universes - univ => universes(i) - do j = 1, univ % n_cells - if (cell_list % contains(univ % cells(j))) then + do j = 1, universes(i) % n_cells + if (cell_list % contains(universes(i) % cells(j))) then n_maps = n_maps + 1 end if end do @@ -1076,24 +1069,23 @@ contains ! Allocate the list of offset tables for each unique universe allocate(univ_list(n_maps)) - ! Allocate list to accumulate target distribccell counts in each universe + ! Allocate list to accumulate target distribcell counts in each universe allocate(counts(n_universes, n_maps)) + counts(:,:) = 0 ! Allocate list to track if target distribcells are found in each universe allocate(found(n_universes, n_maps)) - - counts(:,:) = 0 found(:,:) = .false. - k = 1 + ! Search through universes for distributed cells and assign each one a ! unique distribcell array index. + k = 1 do i = 1, n_universes - univ => universes(i) - do j = 1, univ % n_cells - if (cell_list % contains(univ % cells(j))) then - cells(univ % cells(j)) % distribcell_index = k - univ_list(k) = univ % id + do j = 1, universes(i) % n_cells + if (cell_list % contains(universes(i) % cells(j))) then + cells(universes(i) % cells(j)) % distribcell_index = k + univ_list(k) = universes(i) % id k = k + 1 end if end do @@ -1101,29 +1093,31 @@ contains ! Allocate the offset tables for lattices do i = 1, n_lattices - lat => lattices(i) % obj + associate(lat => lattices(i) % obj) + select type(lat) - select type(lat) - - type is (RectLattice) - allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & - lat % n_cells(3))) - type is (HexLattice) - allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & - 2 * lat % n_rings - 1, lat % n_axial)) - end select - - lat % offset(:, :, :, :) = 0 + type is (RectLattice) + allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & + lat % n_cells(3))) + type is (HexLattice) + allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & + 2 * lat % n_rings - 1, lat % n_axial)) + end select + lat % offset(:, :, :, :) = 0 + end associate end do ! Allocate offset table for fill cells do i = 1, n_cells - if (cells(i) % material == NONE) then + if (cells(i) % type /= CELL_NORMAL) then allocate(cells(i) % offset(n_maps)) end if end do + ! Free up memory + call cell_list % clear() + end subroutine allocate_offsets end module initialize diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c10398d341..d8224742b0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1059,8 +1059,7 @@ contains subroutine read_geometry_xml() integer :: i, j, k, m, i_x, i_a, input_index - integer :: n - integer :: n_x, n_y, n_z, n_rings, n_rlats, n_hlats + integer :: n, n_mats, n_x, n_y, n_z, n_rings, n_rlats, n_hlats integer :: universe_num integer :: n_cells_in_univ integer :: coeffs_reqd @@ -1071,6 +1070,7 @@ contains logical :: boundary_exists character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word + character(MAX_WORD_LEN), allocatable :: sarray(:) character(REGION_SPEC_LEN) :: region_spec type(Cell), pointer :: c class(Surface), pointer :: s @@ -1163,36 +1163,50 @@ contains end if ! Read material - word = '' - if (check_for_node(node_cell, "material")) & - call get_node_value(node_cell, "material", word) - select case(to_lower(word)) - case ('void') - c % material = MATERIAL_VOID + if (check_for_node(node_cell, "material")) then + n_mats = get_arraysize_string(node_cell, "material") - case ('') - ! This case is called if no material was specified - c % material = NONE + if (n_mats > 0) then + allocate(sarray(n_mats)) + call get_node_array(node_cell, "material", sarray) - case default - c % material = int(str_to_int(word), 4) + allocate(c % material(n_mats)) + do j = 1, n_mats + select case(trim(to_lower(sarray(j)))) + case ('void') + c % material(j) = MATERIAL_VOID + case default + c % material(j) = int(str_to_int(sarray(j)), 4) - ! Check for error - if (c % material == ERROR_INT) then - call fatal_error("Invalid material specified on cell " & - &// to_str(c % id)) + ! Check for error + if (c % material(j) == ERROR_INT) then + call fatal_error("Invalid material specified on cell " & + // to_str(c % id)) + end if + end select + end do + + deallocate(sarray) + + else + allocate(c % material(1)) + c % material(1) = NONE end if - end select + + else + allocate(c % material(1)) + c % material(1) = NONE + end if ! Check to make sure that either material or fill was specified - if (c % material == NONE .and. c % fill == NONE) then + if (c % material(1) == NONE .and. c % fill == NONE) then call fatal_error("Neither material nor fill was specified for cell " & - &// trim(to_str(c % id))) + // trim(to_str(c % id))) end if ! Check to make sure that both material and fill haven't been ! specified simultaneously - if (c % material /= NONE .and. c % fill /= NONE) then + if (c % material(1) /= NONE .and. c % fill /= NONE) then call fatal_error("Cannot specify material and fill simultaneously") end if diff --git a/src/plot.F90 b/src/plot.F90 index a5497bc203..75d0bc9442 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -82,17 +82,17 @@ contains if (pl % color_by == PLOT_COLOR_MATS) then ! Assign color based on material c => cells(p % coord(j) % cell) - if (c % material == MATERIAL_VOID) then - ! By default, color void cells white - rgb = 255 - id = -1 - else if (c % type == CELL_FILL) then + if (c % type == CELL_FILL) then ! If we stopped on a middle universe level, treat as if not found rgb = pl % not_found % rgb id = -1 + else if (p % material == MATERIAL_VOID) then + ! By default, color void cells white + rgb = 255 + id = -1 else - rgb = pl % colors(c % material) % rgb - id = materials(c % material) % id + rgb = pl % colors(p % material) % rgb + id = materials(p % material) % id end if else if (pl % color_by == PLOT_COLOR_CELLS) then ! Assign color based on cell diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index 2a8d07b8c0..8d25789f5a 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -6,8 +6,8 @@ element geometry { (element universe { xsd:int } | attribute universe { xsd:int })? & ( (element fill { xsd:int } | attribute fill { xsd:int }) | - (element material { ( xsd:int | "void" ) } | - attribute material { ( xsd:int | "void" ) }) + (element material { ( xsd:int | "void" )+ } | + attribute material { ( xsd:int | "void" )+ }) ) & (element region { xsd:string } | attribute region { xsd:string })? & (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng index fcb310d0b3..d40401b281 100644 --- a/src/relaxng/geometry.rng +++ b/src/relaxng/geometry.rng @@ -47,16 +47,20 @@ - - - void - + + + + void + + - - - void - + + + + void + + diff --git a/src/summary.F90 b/src/summary.F90 index 8708d0b56f..c06d2549c2 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -107,6 +107,7 @@ contains integer :: i, j, k, m integer, allocatable :: lattice_universes(:,:,:) + integer, allocatable :: cell_materials(:) integer(HID_T) :: geom_group integer(HID_T) :: cells_group, cell_group integer(HID_T) :: surfaces_group, surface_group @@ -150,10 +151,24 @@ contains select case (c%type) case (CELL_NORMAL) call write_dataset(cell_group, "fill_type", "normal") - if (c%material == MATERIAL_VOID) then - call write_dataset(cell_group, "material", -1) + if (size(c % material) == 1) then + if (c % material(1) == MATERIAL_VOID) then + call write_dataset(cell_group, "material", MATERIAL_VOID) + else + call write_dataset(cell_group, "material", & + materials(c % material(1)) % id) + end if else - call write_dataset(cell_group, "material", materials(c%material)%id) + allocate(cell_materials(size(c % material))) + do j = 1, size(c % material) + if (c % material(j) == MATERIAL_VOID) then + cell_materials(j) = MATERIAL_VOID + else + cell_materials(j) = materials(c % material(j)) % id + end if + end do + call write_dataset(cell_group, "material", cell_materials) + deallocate(cell_materials) end if case (CELL_FILL) diff --git a/tests/test_distribmat/inputs_true.dat b/tests/test_distribmat/inputs_true.dat new file mode 100644 index 0000000000..9d0a70c471 --- /dev/null +++ b/tests/test_distribmat/inputs_true.dat @@ -0,0 +1 @@ +83a9f1412b1ddfdd8b9fa8c7e8b44be8137dc6aa785d44c3eea9f0928242475aea4ba73ba4eef01afdf63bd1bff18116e40b798eeafab50c856186de4c68d5a6 \ No newline at end of file diff --git a/tests/test_distribmat/results_true.dat b/tests/test_distribmat/results_true.dat new file mode 100644 index 0000000000..70464fbc6c --- /dev/null +++ b/tests/test_distribmat/results_true.dat @@ -0,0 +1,11 @@ +k-combined: +1.309285E+00 1.263629E-02 +Cell + ID = 11 + Name = + Material = [2, 3, void, 2] + Region = -10000 + Rotation = None + Translation = None + Offset = None + Distribcell index= 1 diff --git a/tests/test_distribmat/test_distribmat.py b/tests/test_distribmat/test_distribmat.py new file mode 100644 index 0000000000..b1252a8e7b --- /dev/null +++ b/tests/test_distribmat/test_distribmat.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python + +import os +import sys +sys.path.insert(0, os.pardir) +from testing_harness import TestHarness, PyAPITestHarness +import openmc + + +class DistribmatTestHarness(PyAPITestHarness): + def _build_inputs(self): + #################### + # Materials + #################### + + moderator = openmc.Material(material_id=1) + moderator.set_density('g/cc', 1.0) + moderator.add_nuclide('H-1', 2.0) + moderator.add_nuclide('O-16', 1.0) + + dense_fuel = openmc.Material(material_id=2) + dense_fuel.set_density('g/cc', 4.5) + dense_fuel.add_nuclide('U-235', 1.0) + + light_fuel = openmc.Material(material_id=3) + light_fuel.set_density('g/cc', 2.0) + light_fuel.add_nuclide('U-235', 1.0) + + mats_file = openmc.MaterialsFile() + mats_file.default_xs = '71c' + mats_file.add_materials([moderator, dense_fuel, light_fuel]) + mats_file.export_to_xml() + + + #################### + # Geometry + #################### + + c1 = openmc.Cell(cell_id=1) + c1.fill = moderator + mod_univ = openmc.Universe(universe_id=1) + mod_univ.add_cell(c1) + + r0 = openmc.ZCylinder(R=0.3) + c11 = openmc.Cell(cell_id=11) + c11.region = -r0 + c11.fill = [dense_fuel, light_fuel, 'void', dense_fuel] + c12 = openmc.Cell(cell_id=12) + c12.region = +r0 + c12.fill = moderator + fuel_univ = openmc.Universe(universe_id=11) + fuel_univ.add_cells((c11, c12)) + + lat = openmc.RectLattice(lattice_id=101) + lat.dimension = [2, 2] + lat.lower_left = [-2.0, -2.0] + lat.pitch = [2.0, 2.0] + lat.universes = [[fuel_univ]*2]*2 + lat.outer = mod_univ + + x0 = openmc.XPlane(x0=-3.0) + x1 = openmc.XPlane(x0=3.0) + y0 = openmc.YPlane(y0=-3.0) + y1 = openmc.YPlane(y0=3.0) + for s in [x0, x1, y0, y1]: + s.boundary_type = 'reflective' + c101 = openmc.Cell(cell_id=101) + c101.region = +x0 & -x1 & +y0 & -y1 + c101.fill = lat + root_univ = openmc.Universe(universe_id=0) + root_univ.add_cell(c101) + + geometry = openmc.Geometry() + geometry.root_universe = root_univ + geo_file = openmc.GeometryFile() + geo_file.geometry = geometry + geo_file.export_to_xml() + + + #################### + # Settings + #################### + + sets_file = openmc.SettingsFile() + sets_file.batches = 5 + sets_file.inactive = 0 + sets_file.particles = 1000 + sets_file.set_source_space('box', [-1, -1, -1, 1, 1, 1]) + sets_file.output = {'summary': True} + sets_file.export_to_xml() + + + #################### + # Plots + #################### + + plots_file = openmc.PlotsFile() + + plot = openmc.Plot(plot_id=1) + plot.basis = 'xy' + plot.color = 'cell' + plot.filename = 'cellplot' + plot.origin = (0, 0, 0) + plot.width = (7, 7) + plot.pixels = (400, 400) + plots_file.add_plot(plot) + + plot = openmc.Plot(plot_id=2) + plot.basis = 'xy' + plot.color = 'mat' + plot.filename = 'matplot' + plot.origin = (0, 0, 0) + plot.width = (7, 7) + plot.pixels = (400, 400) + plots_file.add_plot(plot) + + plots_file.export_to_xml() + + def _get_results(self): + outstr = super(DistribmatTestHarness, self)._get_results() + su = openmc.Summary('summary.h5') + outstr += str(su.get_cell_by_id(11)) + return outstr + + def _cleanup(self): + f = os.path.join(os.getcwd(), 'plots.xml') + if os.path.exists(f): + os.remove(f) + super(DistribmatTestHarness, self)._cleanup() + + +if __name__ == '__main__': + harness = DistribmatTestHarness('statepoint.5.*') + harness.main()