mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 06:05:58 -04:00
Merge pull request #548 from smharper/distribcell_mats
Distributed materials
This commit is contained in:
commit
ab3d0e4931
16 changed files with 405 additions and 175 deletions
|
|
@ -891,7 +891,9 @@ Each ``<cell>`` 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <uid>/material** (*int*)
|
||||
**/geometry/cells/cell <uid>/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 <uid>/offset** (*int[]*)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
! ======================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -982,8 +982,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
|
||||
|
|
@ -994,6 +993,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
|
||||
|
|
@ -1086,36 +1086,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
|
||||
|
||||
|
|
|
|||
14
src/plot.F90
14
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
|
||||
|
|
|
|||
|
|
@ -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+ } })? &
|
||||
|
|
|
|||
|
|
@ -47,16 +47,20 @@
|
|||
</choice>
|
||||
<choice>
|
||||
<element name="material">
|
||||
<choice>
|
||||
<data type="int"/>
|
||||
<value>void</value>
|
||||
</choice>
|
||||
<oneOrMore>
|
||||
<choice>
|
||||
<data type="int"/>
|
||||
<value>void</value>
|
||||
</choice>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
<attribute name="material">
|
||||
<choice>
|
||||
<data type="int"/>
|
||||
<value>void</value>
|
||||
</choice>
|
||||
<oneOrMore>
|
||||
<choice>
|
||||
<data type="int"/>
|
||||
<value>void</value>
|
||||
</choice>
|
||||
</oneOrMore>
|
||||
</attribute>
|
||||
</choice>
|
||||
</choice>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
1
tests/test_distribmat/inputs_true.dat
Normal file
1
tests/test_distribmat/inputs_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
83a9f1412b1ddfdd8b9fa8c7e8b44be8137dc6aa785d44c3eea9f0928242475aea4ba73ba4eef01afdf63bd1bff18116e40b798eeafab50c856186de4c68d5a6
|
||||
11
tests/test_distribmat/results_true.dat
Normal file
11
tests/test_distribmat/results_true.dat
Normal file
|
|
@ -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
|
||||
134
tests/test_distribmat/test_distribmat.py
Normal file
134
tests/test_distribmat/test_distribmat.py
Normal file
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue