mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-26 13:15:39 -04:00
Merge pull request #647 from paulromano/periodic
Add periodic boundary conditions
This commit is contained in:
commit
af82534e8d
12 changed files with 333 additions and 34 deletions
|
|
@ -897,11 +897,19 @@ Each ``<surface>`` element can have the following attributes or sub-elements:
|
|||
*Default*: None
|
||||
|
||||
:boundary:
|
||||
The boundary condition for the surface. This can be "transmission",
|
||||
"vacuum", or "reflective".
|
||||
The boundary condition for the surface. This can be "transmission",
|
||||
"vacuum", "reflective", or "periodic". Periodic boundary conditions can
|
||||
only be applied to x-, y-, and z-planes. Only axis-aligned periodicity is
|
||||
supported, i.e., x-planes can only be paired with x-planes. Specify which
|
||||
planes are periodic and the code will automatically identify which planes
|
||||
are paired together.
|
||||
|
||||
*Default*: "transmission"
|
||||
|
||||
:periodic_surface_id:
|
||||
If a periodic boundary condition is applied, this attribute identifies the
|
||||
``id`` of the corresponding periodic sufrace.
|
||||
|
||||
The following quadratic surfaces can be modeled:
|
||||
|
||||
:x-plane:
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ class Surface(object):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
freely pass through the surface. Note that periodic boundary conditions
|
||||
can only be applied to x-, y-, and z-planes, and only axis-aligned
|
||||
periodicity is supported.
|
||||
name : str, optional
|
||||
Name of the surface. If not specified, the name will be the empty
|
||||
string.
|
||||
|
|
@ -193,7 +195,7 @@ class Plane(Surface):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -218,9 +220,12 @@ class Plane(Surface):
|
|||
The 'C' parameter for the plane
|
||||
d : float
|
||||
The 'D' parameter for the plane
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
periodic_surface : openmc.Surface
|
||||
If a periodic boundary condition is used, the surface with which this
|
||||
one is periodic with
|
||||
coefficients : dict
|
||||
Dictionary of surface coefficients
|
||||
id : int
|
||||
|
|
@ -238,6 +243,7 @@ class Plane(Surface):
|
|||
|
||||
self._type = 'plane'
|
||||
self._coeff_keys = ['A', 'B', 'C', 'D']
|
||||
self._periodic_surface = None
|
||||
self.a = A
|
||||
self.b = B
|
||||
self.c = C
|
||||
|
|
@ -259,6 +265,10 @@ class Plane(Surface):
|
|||
def d(self):
|
||||
return self.coefficients['D']
|
||||
|
||||
@property
|
||||
def periodic_surface(self):
|
||||
return self._periodic_surface
|
||||
|
||||
@a.setter
|
||||
def a(self, A):
|
||||
check_type('A coefficient', A, Real)
|
||||
|
|
@ -279,6 +289,21 @@ class Plane(Surface):
|
|||
check_type('D coefficient', D, Real)
|
||||
self._coefficients['D'] = D
|
||||
|
||||
@periodic_surface.setter
|
||||
def periodic_surface(self, periodic_surface):
|
||||
check_type('periodic surface', periodic_surface, Plane)
|
||||
self._periodic_surface = periodic_surface
|
||||
periodic_surface._periodic_surface = self
|
||||
|
||||
def create_xml_subelement(self):
|
||||
element = super(Plane, self).create_xml_subelement()
|
||||
|
||||
# Add periodic surface pair information
|
||||
if self.boundary_type == 'periodic':
|
||||
if self.periodic_surface is not None:
|
||||
element.set("periodic_surface_id", str(self.periodic_surface.id))
|
||||
return element
|
||||
|
||||
|
||||
class XPlane(Plane):
|
||||
"""A plane perpendicular to the x axis of the form :math:`x - x_0 = 0`
|
||||
|
|
@ -291,7 +316,8 @@ class XPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
freely pass through the surface. Only axis-aligned periodicity is
|
||||
supported, i.e., x-planes can only be paired with x-planes.
|
||||
x0 : float, optional
|
||||
Location of the plane. Defaults to 0.
|
||||
name : str, optional
|
||||
|
|
@ -304,6 +330,9 @@ class XPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
periodic_surface : openmc.Surface
|
||||
If a periodic boundary condition is used, the surface with which this
|
||||
one is periodic with
|
||||
coefficients : dict
|
||||
Dictionary of surface coefficients
|
||||
id : int
|
||||
|
|
@ -375,7 +404,8 @@ class YPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
freely pass through the surface. Only axis-aligned periodicity is
|
||||
supported, i.e., x-planes can only be paired with x-planes.
|
||||
y0 : float, optional
|
||||
Location of the plane
|
||||
name : str, optional
|
||||
|
|
@ -388,6 +418,9 @@ class YPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
periodic_surface : openmc.Surface
|
||||
If a periodic boundary condition is used, the surface with which this
|
||||
one is periodic with
|
||||
coefficients : dict
|
||||
Dictionary of surface coefficients
|
||||
id : int
|
||||
|
|
@ -460,7 +493,8 @@ class ZPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
freely pass through the surface. Only axis-aligned periodicity is
|
||||
supported, i.e., x-planes can only be paired with x-planes.
|
||||
z0 : float, optional
|
||||
Location of the plane. Defaults to 0.
|
||||
name : str, optional
|
||||
|
|
@ -473,6 +507,9 @@ class ZPlane(Plane):
|
|||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
periodic_surface : openmc.Surface
|
||||
If a periodic boundary condition is used, the surface with which this
|
||||
one is periodic with
|
||||
coefficients : dict
|
||||
Dictionary of surface coefficients
|
||||
id : int
|
||||
|
|
@ -542,7 +579,7 @@ class Cylinder(Surface):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -556,7 +593,7 @@ class Cylinder(Surface):
|
|||
----------
|
||||
r : float
|
||||
Radius of the cylinder
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -598,7 +635,7 @@ class XCylinder(Cylinder):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -618,7 +655,7 @@ class XCylinder(Cylinder):
|
|||
y-coordinate of the center of the cylinder
|
||||
z0 : float
|
||||
z-coordinate of the center of the cylinder
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -701,7 +738,7 @@ class YCylinder(Cylinder):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -721,7 +758,7 @@ class YCylinder(Cylinder):
|
|||
x-coordinate of the center of the cylinder
|
||||
z0 : float
|
||||
z-coordinate of the center of the cylinder
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -804,7 +841,7 @@ class ZCylinder(Cylinder):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -824,7 +861,7 @@ class ZCylinder(Cylinder):
|
|||
x-coordinate of the center of the cylinder
|
||||
y0 : float
|
||||
y-coordinate of the center of the cylinder
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -906,7 +943,7 @@ class Sphere(Surface):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -931,7 +968,7 @@ class Sphere(Surface):
|
|||
z-coordinate of the center of the sphere
|
||||
R : float
|
||||
Radius of the sphere
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -1034,7 +1071,7 @@ class Cone(Surface):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -1059,7 +1096,7 @@ class Cone(Surface):
|
|||
z-coordinate of the apex
|
||||
R2 : float
|
||||
Parameter related to the aperature
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -1131,7 +1168,7 @@ class XCone(Cone):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -1156,7 +1193,7 @@ class XCone(Cone):
|
|||
z-coordinate of the apex
|
||||
R2 : float
|
||||
Parameter related to the aperature
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -1187,7 +1224,7 @@ class YCone(Cone):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -1212,7 +1249,7 @@ class YCone(Cone):
|
|||
z-coordinate of the apex
|
||||
R2 : float
|
||||
Parameter related to the aperature
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
@ -1243,7 +1280,7 @@ class ZCone(Cone):
|
|||
surface_id : int, optional
|
||||
Unique identifier for the surface. If not specified, an identifier will
|
||||
automatically be assigned.
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}, optional
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}, optional
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface. Defaults to transmissive boundary condition where particles
|
||||
freely pass through the surface.
|
||||
|
|
@ -1268,7 +1305,7 @@ class ZCone(Cone):
|
|||
z-coordinate of the apex
|
||||
R2 : float
|
||||
Parameter related to the aperature
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'}
|
||||
boundary_type : {'transmission, 'vacuum', 'reflective'}
|
||||
Boundary condition that defines the behavior for particles hitting the
|
||||
surface.
|
||||
coefficients : dict
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ contains
|
|||
real(8) :: v ! y-component of direction
|
||||
real(8) :: w ! z-component of direction
|
||||
real(8) :: norm ! "norm" of surface normal
|
||||
real(8) :: xyz(3) ! Saved global coordinate
|
||||
integer :: i_surface ! index in surfaces
|
||||
logical :: found ! particle found in universe?
|
||||
class(Surface), pointer :: surf
|
||||
|
|
@ -432,12 +433,13 @@ contains
|
|||
|
||||
! Score surface currents since reflection causes the direction of the
|
||||
! particle to change -- artificially move the particle slightly back in
|
||||
! case the surface crossing in coincident with a mesh boundary
|
||||
! case the surface crossing is coincident with a mesh boundary
|
||||
|
||||
if (active_current_tallies % size() > 0) then
|
||||
xyz = p % coord(1) % xyz
|
||||
p % coord(1) % xyz = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw
|
||||
call score_surface_current(p)
|
||||
p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
p % coord(1) % xyz = xyz
|
||||
end if
|
||||
|
||||
! Reflect particle off surface
|
||||
|
|
@ -475,6 +477,70 @@ contains
|
|||
&// trim(to_str(surf%id)))
|
||||
end if
|
||||
return
|
||||
elseif (surf % bc == BC_PERIODIC .and. run_mode /= MODE_PLOTTING) then
|
||||
! =======================================================================
|
||||
! PERIODIC BOUNDARY
|
||||
|
||||
! Do not handle periodic boundary conditions on lower universes
|
||||
if (p % n_coord /= 1) then
|
||||
call handle_lost_particle(p, "Cannot transfer particle " &
|
||||
// trim(to_str(p % id)) // " across surface in a lower universe.&
|
||||
& Boundary conditions must be applied to universe 0.")
|
||||
return
|
||||
end if
|
||||
|
||||
! Score surface currents since reflection causes the direction of the
|
||||
! particle to change -- artificially move the particle slightly back in
|
||||
! case the surface crossing is coincident with a mesh boundary
|
||||
|
||||
if (active_current_tallies % size() > 0) then
|
||||
xyz = p % coord(1) % xyz
|
||||
p % coord(1) % xyz = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw
|
||||
call score_surface_current(p)
|
||||
p % coord(1) % xyz = xyz
|
||||
end if
|
||||
|
||||
select type (surf)
|
||||
type is (SurfaceXPlane)
|
||||
select type (opposite => surfaces(surf % i_periodic) % obj)
|
||||
type is (SurfaceXPlane)
|
||||
p % coord(1) % xyz(1) = opposite % x0
|
||||
end select
|
||||
|
||||
type is (SurfaceYPlane)
|
||||
select type (opposite => surfaces(surf % i_periodic) % obj)
|
||||
type is (SurfaceYPlane)
|
||||
p % coord(1) % xyz(2) = opposite % y0
|
||||
end select
|
||||
|
||||
type is (SurfaceZPlane)
|
||||
select type (opposite => surfaces(surf % i_periodic) % obj)
|
||||
type is (SurfaceZPlane)
|
||||
p % coord(1) % xyz(3) = opposite % z0
|
||||
end select
|
||||
end select
|
||||
|
||||
! Reassign particle's surface
|
||||
p % surface = sign(surf % i_periodic, p % surface)
|
||||
|
||||
! Figure out what cell particle is in now
|
||||
p % n_coord = 1
|
||||
call find_cell(p, found)
|
||||
if (.not. found) then
|
||||
call handle_lost_particle(p, "Couldn't find particle after hitting &
|
||||
&periodic boundary on surface " // trim(to_str(surf%id)) // ".")
|
||||
return
|
||||
end if
|
||||
|
||||
! Set previous coordinate going slightly past surface crossing
|
||||
p % last_xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw
|
||||
|
||||
! Diagnostic message
|
||||
if (verbosity >= 10 .or. trace) then
|
||||
call write_message(" Hit periodic boundary on surface " &
|
||||
// trim(to_str(surf%id)))
|
||||
end if
|
||||
return
|
||||
end if
|
||||
|
||||
! ==========================================================================
|
||||
|
|
|
|||
|
|
@ -1113,6 +1113,8 @@ contains
|
|||
integer :: universe_num
|
||||
integer :: n_cells_in_univ
|
||||
integer :: coeffs_reqd
|
||||
integer :: i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax
|
||||
real(8) :: xmin, xmax, ymin, ymax, zmin, zmax
|
||||
integer, allocatable :: temp_int_array(:)
|
||||
real(8) :: phi, theta, psi
|
||||
real(8), allocatable :: coeffs(:)
|
||||
|
|
@ -1391,6 +1393,13 @@ contains
|
|||
call fatal_error("No surfaces found in geometry.xml!")
|
||||
end if
|
||||
|
||||
xmin = INFINITY
|
||||
xmax = -INFINITY
|
||||
ymin = INFINITY
|
||||
ymax = -INFINITY
|
||||
zmin = INFINITY
|
||||
zmax = -INFINITY
|
||||
|
||||
! Allocate cells array
|
||||
allocate(surfaces(n_surfaces))
|
||||
|
||||
|
|
@ -1482,10 +1491,28 @@ contains
|
|||
select type(s)
|
||||
type is (SurfaceXPlane)
|
||||
s%x0 = coeffs(1)
|
||||
|
||||
! Determine outer surfaces
|
||||
xmin = min(xmin, s % x0)
|
||||
xmax = max(xmax, s % x0)
|
||||
if (xmin == s % x0) i_xmin = i
|
||||
if (xmax == s % x0) i_xmax = i
|
||||
type is (SurfaceYPlane)
|
||||
s%y0 = coeffs(1)
|
||||
|
||||
! Determine outer surfaces
|
||||
ymin = min(ymin, s % y0)
|
||||
ymax = max(ymax, s % y0)
|
||||
if (ymin == s % y0) i_ymin = i
|
||||
if (ymax == s % y0) i_ymax = i
|
||||
type is (SurfaceZPlane)
|
||||
s%z0 = coeffs(1)
|
||||
|
||||
! Determine outer surfaces
|
||||
zmin = min(zmin, s % z0)
|
||||
zmax = max(zmax, s % z0)
|
||||
if (zmin == s % z0) i_zmin = i
|
||||
if (zmax == s % z0) i_zmax = i
|
||||
type is (SurfacePlane)
|
||||
s%A = coeffs(1)
|
||||
s%B = coeffs(2)
|
||||
|
|
@ -1552,11 +1579,19 @@ contains
|
|||
case ('reflective', 'reflect', 'reflecting')
|
||||
s%bc = BC_REFLECT
|
||||
boundary_exists = .true.
|
||||
case ('periodic')
|
||||
s%bc = BC_PERIODIC
|
||||
boundary_exists = .true.
|
||||
|
||||
! Check for specification of periodic surface
|
||||
if (check_for_node(node_surf, "periodic_surface_id")) then
|
||||
call get_node_value(node_surf, "periodic_surface_id", &
|
||||
s % i_periodic)
|
||||
end if
|
||||
case default
|
||||
call fatal_error("Unknown boundary condition '" // trim(word) // &
|
||||
&"' specified on surface " // trim(to_str(s%id)))
|
||||
end select
|
||||
|
||||
! Add surface to dictionary
|
||||
call surface_dict % add_key(s%id, i)
|
||||
end do
|
||||
|
|
@ -1567,6 +1602,67 @@ contains
|
|||
call fatal_error("No boundary conditions were applied to any surfaces!")
|
||||
end if
|
||||
|
||||
! Determine opposite side for periodic boundaries
|
||||
do i = 1, size(surfaces)
|
||||
if (surfaces(i) % obj % bc == BC_PERIODIC) then
|
||||
select type (surf => surfaces(i) % obj)
|
||||
type is (SurfaceXPlane)
|
||||
if (surf % i_periodic == NONE) then
|
||||
if (i == i_xmin) then
|
||||
surf % i_periodic = i_xmax
|
||||
elseif (i == i_xmax) then
|
||||
surf % i_periodic = i_xmin
|
||||
else
|
||||
call fatal_error("Periodic boundary condition applied to &
|
||||
&interior surface.")
|
||||
end if
|
||||
else
|
||||
surf % i_periodic = surface_dict % get_key(surf % i_periodic)
|
||||
end if
|
||||
|
||||
type is (SurfaceYPlane)
|
||||
if (surf % i_periodic == NONE) then
|
||||
if (i == i_ymin) then
|
||||
surf % i_periodic = i_ymax
|
||||
elseif (i == i_ymax) then
|
||||
surf % i_periodic = i_ymin
|
||||
else
|
||||
call fatal_error("Periodic boundary condition applied to &
|
||||
&interior surface.")
|
||||
end if
|
||||
else
|
||||
surf % i_periodic = surface_dict % get_key(surf % i_periodic)
|
||||
end if
|
||||
|
||||
type is (SurfaceZPlane)
|
||||
if (surf % i_periodic == NONE) then
|
||||
if (i == i_zmin) then
|
||||
surf % i_periodic = i_zmax
|
||||
elseif (i == i_zmax) then
|
||||
surf % i_periodic = i_zmin
|
||||
else
|
||||
call fatal_error("Periodic boundary condition applied to &
|
||||
&interior surface.")
|
||||
end if
|
||||
else
|
||||
surf % i_periodic = surface_dict % get_key(surf % i_periodic)
|
||||
end if
|
||||
|
||||
class default
|
||||
call fatal_error("Periodic boundary condition applied to &
|
||||
&non-planar surface.")
|
||||
end select
|
||||
|
||||
! Make sure opposite surface is also periodic
|
||||
associate (surf => surfaces(i) % obj)
|
||||
if (surfaces(surf % i_periodic) % obj % bc /= BC_PERIODIC) then
|
||||
call fatal_error("Could not find matching surface for periodic &
|
||||
&boundary on surface " // trim(to_str(surf % id)) // ".")
|
||||
end if
|
||||
end associate
|
||||
end if
|
||||
end do
|
||||
|
||||
! ==========================================================================
|
||||
! READ LATTICES FROM GEOMETRY.XML
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ element geometry {
|
|||
(element type { xsd:string { maxLength = "15" } } |
|
||||
attribute type { xsd:string { maxLength = "15" } }) &
|
||||
(element coeffs { list { xsd:double+ } } | attribute coeffs { list { xsd:double+ } }) &
|
||||
(element boundary { ( "transmit" | "reflective" | "vacuum" ) } |
|
||||
attribute boundary { ( "transmit" | "reflective" | "vacuum" ) })?
|
||||
(element boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) } |
|
||||
attribute boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) })? &
|
||||
(element periodic_surface_id { xsd:int } | attribute periodic_surface_id { xsd:int })?
|
||||
}*
|
||||
|
||||
& element lattice {
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@
|
|||
<value>transmit</value>
|
||||
<value>reflective</value>
|
||||
<value>vacuum</value>
|
||||
<value>periodic</value>
|
||||
</choice>
|
||||
</element>
|
||||
<attribute name="boundary">
|
||||
|
|
@ -180,10 +181,21 @@
|
|||
<value>transmit</value>
|
||||
<value>reflective</value>
|
||||
<value>vacuum</value>
|
||||
<value>periodic</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</choice>
|
||||
</optional>
|
||||
<optional>
|
||||
<choice>
|
||||
<element name="periodic_surface_id">
|
||||
<data type="int"/>
|
||||
</element>
|
||||
<attribute name="periodic_surface_id">
|
||||
<data type="int"/>
|
||||
</attribute>
|
||||
</choice>
|
||||
</optional>
|
||||
</interleave>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
module surface_header
|
||||
|
||||
use constants, only: ONE, TWO, ZERO, HALF, INFINITY, FP_COINCIDENT
|
||||
use constants, only: NONE, ONE, TWO, ZERO, HALF, INFINITY, FP_COINCIDENT
|
||||
|
||||
implicit none
|
||||
|
||||
|
|
@ -15,7 +15,8 @@ module surface_header
|
|||
neighbor_pos(:), & ! List of cells on positive side
|
||||
neighbor_neg(:) ! List of cells on negative side
|
||||
integer :: bc ! Boundary condition
|
||||
character(len=104) :: name = "" ! User-defined name
|
||||
integer :: i_periodic = NONE ! Index of corresponding periodic surface
|
||||
character(len=104) :: name = "" ! User-defined name
|
||||
contains
|
||||
procedure :: sense
|
||||
procedure :: reflect
|
||||
|
|
|
|||
1
tests/test_periodic/inputs_true.dat
Normal file
1
tests/test_periodic/inputs_true.dat
Normal file
|
|
@ -0,0 +1 @@
|
|||
af589996f2930337afe34ba9894098ff5efe3b29b6e927117220b718bf29b630ffdbc931754d465a8e8100125a8aa997dbe10aab322b43f69d59710573996a6d
|
||||
2
tests/test_periodic/results_true.dat
Normal file
2
tests/test_periodic/results_true.dat
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
k-combined:
|
||||
1.040109E+00 6.527490E-02
|
||||
14
tests/test_periodic/tallies.xml
Normal file
14
tests/test_periodic/tallies.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0"?>
|
||||
<tallies>
|
||||
<mesh id="1">
|
||||
<type>regular</type>
|
||||
<lower_left>-200. -1e50</lower_left>
|
||||
<upper_right>200. 1e50</upper_right>
|
||||
<dimension>50 1</dimension>
|
||||
</mesh>
|
||||
<tally id="1">
|
||||
<estimator>collision</estimator>
|
||||
<filter type="mesh" bins="1" />
|
||||
<scores>fission</scores>
|
||||
</tally>
|
||||
</tallies>
|
||||
60
tests/test_periodic/test_periodic.py
Normal file
60
tests/test_periodic/test_periodic.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.pardir)
|
||||
from testing_harness import PyAPITestHarness
|
||||
import openmc
|
||||
|
||||
|
||||
class PeriodicTest(PyAPITestHarness):
|
||||
def _build_inputs(self):
|
||||
# Define materials
|
||||
water = openmc.Material(1)
|
||||
water.add_nuclide('H-1', 2.0)
|
||||
water.add_nuclide('O-16', 1.0)
|
||||
water.add_s_alpha_beta('HH2O', '71t')
|
||||
water.set_density('g/cc', 1.0)
|
||||
|
||||
fuel = openmc.Material(2)
|
||||
fuel.add_nuclide('U-235', 1.0)
|
||||
fuel.set_density('g/cc', 4.5)
|
||||
|
||||
materials = openmc.Materials((water, fuel))
|
||||
materials.default_xs = '71c'
|
||||
materials.export_to_xml()
|
||||
|
||||
# Define geometry
|
||||
x_min = openmc.XPlane(1, x0=-5., boundary_type='periodic')
|
||||
x_max = openmc.XPlane(2, x0=5., boundary_type='periodic')
|
||||
x_max.periodic_surface = x_min
|
||||
|
||||
y_min = openmc.YPlane(3, y0=-5., boundary_type='periodic')
|
||||
y_max = openmc.YPlane(4, y0=5., boundary_type='periodic')
|
||||
|
||||
z_min = openmc.ZPlane(5, z0=-5., boundary_type='reflective')
|
||||
z_max = openmc.ZPlane(6, z0=5., boundary_type='reflective')
|
||||
z_cyl = openmc.ZCylinder(7, x0=-2.5, y0=2.5, R=2.0)
|
||||
|
||||
outside_cyl = openmc.Cell(1, fill=water, region=(
|
||||
+x_min & -x_max & +y_min & -y_max & +z_min & -z_max & +z_cyl))
|
||||
inside_cyl = openmc.Cell(2, fill=fuel, region=+z_min & -z_max & -z_cyl)
|
||||
root_universe = openmc.Universe(0, cells=(outside_cyl, inside_cyl))
|
||||
|
||||
geometry = openmc.Geometry()
|
||||
geometry.root_universe = root_universe
|
||||
geometry.export_to_xml()
|
||||
|
||||
# Define settings
|
||||
settings = openmc.Settings()
|
||||
settings.particles = 1000
|
||||
settings.batches = 4
|
||||
settings.inactive = 0
|
||||
settings.source = openmc.Source(space=openmc.stats.Box(
|
||||
*outside_cyl.region.bounding_box))
|
||||
settings.export_to_xml()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
harness = PeriodicTest('statepoint.4.h5')
|
||||
harness.main()
|
||||
|
|
@ -133,9 +133,10 @@ class TestHarness(object):
|
|||
|
||||
def _cleanup(self):
|
||||
"""Delete statepoints, tally, and test files."""
|
||||
output = glob.glob(os.path.join(os.getcwd(), 'statepoint.*.*'))
|
||||
output = glob.glob(os.path.join(os.getcwd(), 'statepoint.*.h5'))
|
||||
output.append(os.path.join(os.getcwd(), 'tallies.out'))
|
||||
output.append(os.path.join(os.getcwd(), 'results_test.dat'))
|
||||
output.append(os.path.join(os.getcwd(), 'summary.h5'))
|
||||
for f in output:
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue