From 5bf2644394d67d507a256d13761aacbffcfd27ad Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 4 Aug 2014 22:52:32 -0400 Subject: [PATCH 01/48] Started writing OO surface derived types. --- src/surface.F90 | 1073 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1073 insertions(+) create mode 100644 src/surface.F90 diff --git a/src/surface.F90 b/src/surface.F90 new file mode 100644 index 0000000000..abf71a450a --- /dev/null +++ b/src/surface.F90 @@ -0,0 +1,1073 @@ +module surface_header + + use constants, only: ONE, TWO, ZERO, INFINITY, FP_COINCIDENT + + implicit none + + type, abstract :: Surface + integer :: id ! Unique ID + integer, allocatable :: & + neighbor_pos(:), & ! List of cells on positive side + neighbor_neg(:) ! List of cells on negative side + integer :: bc ! Boundary condition + contains + procedure(iEvaluate), deferred :: evaluate + procedure(iDistance), deferred :: distance + procedure(iReflect), deferred :: reflect + end type Surface + + type, extends(Surface) :: SurfaceXPlane + ! x = x0 + real(8) :: x0 + contains + procedure :: evaluate => x_plane_evaluate + procedure :: reflect => x_plane_reflect + procedure :: distance => x_plane_distance + end type SurfaceXPlane + + type, extends(Surface) :: SurfaceYPlane + ! y = y0 + real(8) :: y0 + contains + procedure :: evaluate => y_plane_evaluate + procedure :: reflect => y_plane_reflect + procedure :: distance => y_plane_distance + end type SurfaceYPlane + + type, extends(Surface) :: SurfaceZPlane + ! z = z0 + real(8) :: z0 + contains + procedure :: evaluate => z_plane_evaluate + procedure :: reflect => z_plane_reflect + procedure :: distance => z_plane_distance + end type SurfaceZPlane + + type, extends(Surface) :: SurfacePlane + ! Ax + By + Cz = D + real(8) :: A + real(8) :: B + real(8) :: C + real(8) :: D + contains + procedure :: evaluate => plane_evaluate + procedure :: reflect => plane_reflect + procedure :: distance => plane_distance + end type SurfacePlane + + type, extends(Surface) :: SurfaceXCylinder + ! (y - y0)^2 + (z - z0)^2 = R^2 + real(8) :: y0 + real(8) :: z0 + real(8) :: r + contains + procedure :: evaluate => x_cylinder_evaluate + procedure :: reflect => x_cylinder_reflect + procedure :: distance => x_cylinder_distance + end type SurfaceXCylinder + + type, extends(Surface) :: SurfaceYCylinder + ! (x - x0)^2 + (z - z0)^2 = R^2 + real(8) :: x0 + real(8) :: z0 + real(8) :: r + contains + procedure :: evaluate => y_cylinder_evaluate + procedure :: reflect => y_cylinder_reflect + procedure :: distance => y_cylinder_distance + end type SurfaceYCylinder + + type, extends(Surface) :: SurfaceZCylinder + ! (x - x0)^2 + (y - y0)^2 = R^2 + real(8) :: x0 + real(8) :: y0 + real(8) :: r + contains + procedure :: evaluate => z_cylinder_evaluate + procedure :: reflect => z_cylinder_reflect + procedure :: distance => z_cylinder_distance + end type SurfaceZCylinder + + type, extends(Surface) :: SurfaceSphere + ! (x - x0)^2 + (y - y0)^2 + (z - z0)^2 = R^2 + real(8) :: x0 + real(8) :: y0 + real(8) :: z0 + real(8) :: r + contains + procedure :: evaluate => sphere_evaluate + procedure :: reflect => sphere_reflect + procedure :: distance => sphere_distance + end type SurfaceSphere + + type, extends(Surface) :: SurfaceXCone + ! (y - y0)^2 + (z - z0)^2 = R^2*(x - x0)^2 + real(8) :: x0 + real(8) :: y0 + real(8) :: z0 + real(8) :: r2 + contains + procedure :: evaluate => x_cone_evaluate + procedure :: reflect => x_cone_reflect + procedure :: distance => x_cone_distance + end type SurfaceXCone + + type, extends(Surface) :: SurfaceYCone + ! (x - x0)^2 + (z - z0)^2 = R^2*(y - y0)^2 + real(8) :: x0 + real(8) :: y0 + real(8) :: z0 + real(8) :: r2 + contains + procedure :: evaluate => y_cone_evaluate + procedure :: reflect => y_cone_reflect + procedure :: distance => y_cone_distance + end type SurfaceYCone + + type, extends(Surface) :: SurfaceZCone + ! (x - x0)^2 + (y - y0)^2 = R^2*(z - z0)^2 + real(8) :: x0 + real(8) :: y0 + real(8) :: z0 + real(8) :: r2 + contains + procedure :: evaluate => z_cone_evaluate + procedure :: reflect => z_cone_reflect + procedure :: distance => z_cone_distance + end type SurfaceZCone + + abstract interface + pure function iEvaluate(this, xyz) result(f) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + end function iEvaluate + + pure function iDistance(this, xyz, uvw) result(d) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + end function iDistance + + subroutine iReflect(this, xyz, uvw) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + end subroutine iReflect + end interface + +contains + +!=============================================================================== +! X_PLANE_EVALUATE +!=============================================================================== + + pure function x_plane_evaluate(this, xyz) result(f) + + class(SurfaceXPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + f = xyz(1) - this%x0 + + end function x_plane_evaluate + +!=============================================================================== +! X_PLANE_DISTANCE +!=============================================================================== + + pure function x_plane_distance(this, xyz, uvw) result(d) + + class(SurfaceXPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + if (uvw(1) == ZERO) then + d = INFINITY + else + d = (this%x0 - xyz(1))/uvw(1) + if (d < ZERO) d = INFINITY + end if + + end function x_plane_distance + +!=============================================================================== +! X_PLANE_REFLECT +!=============================================================================== + + subroutine x_plane_reflect(this, xyz, uvw) + + class(SurfaceXPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + uvw(1) = -uvw(1) + + end subroutine x_plane_reflect + +!=============================================================================== +! Y_PLANE_EVALUATE +!=============================================================================== + + pure function y_plane_evaluate(this, xyz) result(f) + + class(SurfaceYPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + f = xyz(2) - this%y0 + + end function y_plane_evaluate + +!=============================================================================== +! Y_PLANE_DISTANCE +!=============================================================================== + + pure function y_plane_distance(this, xyz, uvw) result(d) + + class(SurfaceYPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + if (uvw(2) == ZERO) then + d = INFINITY + else + d = (this%y0 - xyz(2))/uvw(2) + if (d < ZERO) d = INFINITY + end if + + end function y_plane_distance + +!=============================================================================== +! Y_PLANE_REFLECT +!=============================================================================== + + subroutine y_plane_reflect(this, xyz, uvw) + + class(SurfaceYPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + uvw(2) = -uvw(2) + + end subroutine y_plane_reflect + +!=============================================================================== +! Z_PLANE_EVALUATE +!=============================================================================== + + pure function z_plane_evaluate(this, xyz) result(f) + + class(SurfaceZPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + f = xyz(3) - this%z0 + + end function z_plane_evaluate + +!=============================================================================== +! Z_PLANE_DISTANCE +!=============================================================================== + + pure function z_plane_distance(this, xyz, uvw) result(d) + + class(SurfaceZPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + if (uvw(3) == ZERO) then + d = INFINITY + else + d = (this%z0 - xyz(3))/uvw(3) + if (d < ZERO) d = INFINITY + end if + + end function z_plane_distance + +!=============================================================================== +! Z_PLANE_REFLECT +!=============================================================================== + + subroutine z_plane_reflect(this, xyz, uvw) + + class(SurfaceZPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + uvw(3) = -uvw(3) + + end subroutine z_plane_reflect + +!=============================================================================== +! PLANE_EVALUATE +!=============================================================================== + + pure function plane_evaluate(this, xyz) result(f) + + class(SurfacePlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D + + end function plane_evaluate + +!=============================================================================== +! PLANE_DISTANCE +!=============================================================================== + + pure function plane_distance(this, xyz, uvw) result(d) + + class(SurfacePlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: tmp + + tmp = this%A*uvw(1) + this%B*uvw(2) + this%C*uvw(3) + if (tmp == ZERO) then + d = INFINITY + else + d = -(this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D)/tmp + if (d < ZERO) d = INFINITY + end if + + end function plane_distance + +!=============================================================================== +! PLANE_REFLECT +!=============================================================================== + + subroutine plane_reflect(this, xyz, uvw) + + class(SurfacePlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: n(3) + + ! Construct normal vector + n(:) = [this%A, this%B, this%C] + + ! Reflect direction according to normal + uvw = uvw - TWO*dot_product(n, uvw)/dot_product(n, n) * n + + end subroutine plane_reflect + +!=============================================================================== +! X_CYLINDER_EVALUATE +!=============================================================================== + + pure function x_cylinder_evaluate(this, xyz) result(f) + + class(SurfaceXCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: y, z + + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + f = y*y + z*z - this%r*this%r + + end function x_cylinder_evaluate + +!=============================================================================== +! X_CYLINDER_DISTANCE +!=============================================================================== + + pure function x_cylinder_distance(this, xyz, uvw) result(d) + + class(SurfaceXCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: y, z, k, a, c, quad + + a = ONE - uvw(1)*uvw(1) ! v^2 + w^2 + if (a == ZERO) then + d = INFINITY + else + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + k = y*uvw(2) + z*uvw(3) + c = y*y + z*z - this%r*this%r + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cylinder + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cylinder, thus one distance is positive/negative + ! and the other is zero. The sign of k determines if we are facing in or + ! out + + if (k >= ZERO) then + d = INFINITY + else + d = (-k + sqrt(quad))/a + end if + + elseif (c < ZERO) then + ! particle is inside the cylinder, thus one distance must be negative + ! and one must be positive. The positive distance will be the one with + ! negative sign on sqrt(quad) + + d = (-k + sqrt(quad))/a + + else + ! particle is outside the cylinder, thus both distances are either + ! positive or negative. If positive, the smaller distance is the one + ! with positive sign on sqrt(quad) + + d = (-k - sqrt(quad))/a + if (d < ZERO) d = INFINITY + + end if + end if + + + end function x_cylinder_distance + +!=============================================================================== +! X_CYLINDER_REFLECT +!=============================================================================== + + subroutine x_cylinder_reflect(this, xyz, uvw) + + class(SurfaceXCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: y, z, r, dot_prod + + ! Find y-y0, z-z0 and dot product of direction and surface normal + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + dot_prod = uvw(2)*y + uvw(3)*z + + ! Reflect direction according to normal + uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) + uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) + + + end subroutine x_cylinder_reflect + +!=============================================================================== +! Y_CYLINDER_EVALUATE +!=============================================================================== + + pure function y_cylinder_evaluate(this, xyz) result(f) + + class(SurfaceYCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, z + + x = xyz(1) - this%x0 + z = xyz(3) - this%z0 + f = x*x + z*z - this%r*this%r + + end function y_cylinder_evaluate + +!=============================================================================== +! Y_CYLINDER_DISTANCE +!=============================================================================== + + pure function y_cylinder_distance(this, xyz, uvw) result(d) + + class(SurfaceYCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, z, k, a, c, quad + + a = ONE - uvw(2)*uvw(2) ! u^2 + w^2 + if (a == ZERO) then + d = INFINITY + else + x = xyz(1) - this%x0 + z = xyz(3) - this%z0 + k = x*uvw(1) + z*uvw(3) + c = x*x + z*z - this%r*this%r + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cylinder + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cylinder, thus one distance is positive/negative + ! and the other is zero. The sign of k determines if we are facing in or + ! out + + if (k >= ZERO) then + d = INFINITY + else + d = (-k + sqrt(quad))/a + end if + + elseif (c < ZERO) then + ! particle is inside the cylinder, thus one distance must be negative + ! and one must be positive. The positive distance will be the one with + ! negative sign on sqrt(quad) + + d = (-k + sqrt(quad))/a + + else + ! particle is outside the cylinder, thus both distances are either + ! positive or negative. If positive, the smaller distance is the one + ! with positive sign on sqrt(quad) + + d = (-k - sqrt(quad))/a + if (d < ZERO) d = INFINITY + + end if + end if + + + end function y_cylinder_distance + +!=============================================================================== +! Y_CYLINDER_REFLECT +!=============================================================================== + + subroutine y_cylinder_reflect(this, xyz, uvw) + + class(SurfaceYCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: x, z, r, dot_prod + + ! Find x-x0, z-z0 and dot product of direction and surface normal + x = xyz(1) - this%x0 + z = xyz(3) - this%z0 + dot_prod = uvw(1)*x + uvw(3)*z + + ! Reflect direction according to normal + uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) + uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) + + + end subroutine y_cylinder_reflect + +!=============================================================================== +! Z_CYLINDER_EVALUATE +!=============================================================================== + + pure function z_cylinder_evaluate(this, xyz) result(f) + + class(SurfaceZCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, y + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + f = x*x + y*y - this%r*this%r + + end function z_cylinder_evaluate + +!=============================================================================== +! Z_CYLINDER_DISTANCE +!=============================================================================== + + pure function z_cylinder_distance(this, xyz, uvw) result(d) + + class(SurfaceZCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, y, k, a, c, quad + + a = ONE - uvw(3)*uvw(3) ! u^2 + v^2 + if (a == ZERO) then + d = INFINITY + else + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + k = x*uvw(1) + y*uvw(2) + c = x*x + y*y - this%r*this%r + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cylinder + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cylinder, thus one distance is positive/negative + ! and the other is zero. The sign of k determines if we are facing in or + ! out + + if (k >= ZERO) then + d = INFINITY + else + d = (-k + sqrt(quad))/a + end if + + elseif (c < ZERO) then + ! particle is inside the cylinder, thus one distance must be negative + ! and one must be positive. The positive distance will be the one with + ! negative sign on sqrt(quad) + + d = (-k + sqrt(quad))/a + + else + ! particle is outside the cylinder, thus both distances are either + ! positive or negative. If positive, the smaller distance is the one + ! with positive sign on sqrt(quad) + + d = (-k - sqrt(quad))/a + if (d < ZERO) d = INFINITY + + end if + end if + + + end function z_cylinder_distance + +!=============================================================================== +! Z_CYLINDER_REFLECT +!=============================================================================== + + subroutine z_cylinder_reflect(this, xyz, uvw) + + class(SurfaceZCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: x, y, r, dot_prod + + ! Find x-x0, y-y0 and dot product of direction and surface normal + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + dot_prod = uvw(1)*x + uvw(2)*y + + ! Reflect direction according to normal + uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) + uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) + + end subroutine z_cylinder_reflect + +!=============================================================================== +! SPHERE_EVALUATE +!=============================================================================== + + pure function sphere_evaluate(this, xyz) result(f) + + class(SurfaceSphere), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, y, z + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + f = x*x + y*y + z*z - this%r*this%r + + end function sphere_evaluate + +!=============================================================================== +! SPHERE_DISTANCE +!=============================================================================== + + pure function sphere_distance(this, xyz, uvw) result(d) + + class(SurfaceSphere), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, y, z, k, c, quad + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + k = x*uvw(1) + y*uvw(2) + z*uvw(3) + c = x*x + y*y + z*z - this%r*this%r + quad = k*k - c + + if (quad < ZERO) then + ! no intersection with sphere + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the sphere, thus one distance is positive/negative and + ! the other is zero. The sign of k determines if we are facing in or out + + if (k >= ZERO) then + d = INFINITY + else + d = -k + sqrt(quad) + end if + + elseif (c < ZERO) then + ! particle is inside the sphere, thus one distance must be negative and + ! one must be positive. The positive distance will be the one with + ! negative sign on sqrt(quad) + + d = -k + sqrt(quad) + + else + ! particle is outside the sphere, thus both distances are either positive + ! or negative. If positive, the smaller distance is the one with positive + ! sign on sqrt(quad) + + d = -k - sqrt(quad) + if (d < ZERO) d = INFINITY + + end if + + end function sphere_distance + +!=============================================================================== +! SPHERE_REFLECT +!=============================================================================== + + subroutine sphere_reflect(this, xyz, uvw) + + class(SurfaceSphere), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: n(3) + + ! Determine surface surface normal + n(:) = xyz - [this%x0, this%y0, this%z0] + + ! Reflect direction according to normal + uvw = uvw - TWO*dot_product(uvw, n)/(this%r*this%r) * n + + end subroutine sphere_reflect + +!=============================================================================== +! X_CONE_EVALUATE +!=============================================================================== + + pure function x_cone_evaluate(this, xyz) result(f) + + class(SurfaceXCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, y, z + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + f = y*y + z*z - this%r2*x*x + + end function x_cone_evaluate + +!=============================================================================== +! X_CONE_DISTANCE +!=============================================================================== + + pure function x_cone_distance(this, xyz, uvw) result(d) + + class(SurfaceXCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, y, z, k, a, b, c, quad + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + a = uvw(2)*uvw(2) + uvw(3)*uvw(3) - this%r2*uvw(1)*uvw(1) + k = y*uvw(2) + z*uvw(3) - this%r2*x*uvw(1) + c = y*y + z*z - this%r2*x*x + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cone + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cone, thus one distance is positive/negative and the + ! other is zero. The sign of k determines which distance is zero and which + ! is not. + + if (k >= ZERO) then + d = (-k - sqrt(quad))/a + else + d = (-k + sqrt(quad))/a + end if + + else + ! calculate both solutions to the quadratic + quad = sqrt(quad) + d = (-k - quad)/a + b = (-k + quad)/a + + ! determine the smallest positive solution + if (d < ZERO) then + if (b > ZERO) then + d = b + end if + else + if (b > ZERO) d = min(d, b) + end if + end if + + ! If the distance was negative, set boundary distance to infinity + if (d <= ZERO) d = INFINITY + + end function x_cone_distance + +!=============================================================================== +! X_CONE_REFLECT +!=============================================================================== + + subroutine x_cone_reflect(this, xyz, uvw) + + class(SurfaceXCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: x, y, z, r, dot_prod + + ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + r = this%r2 + dot_prod = (uvw(2)*y + uvw(3)*z - r*uvw(1)*x)/((r + ONE)*r*x*x) + + ! Reflect direction according to normal + uvw(1) = uvw(1) + TWO*dot_prod*r*x + uvw(2) = uvw(2) - TWO*dot_prod*y + uvw(3) = uvw(3) - TWO*dot_prod*z + + end subroutine x_cone_reflect + +!=============================================================================== +! Y_CONE_EVALUATE +!=============================================================================== + + pure function y_cone_evaluate(this, xyz) result(f) + + class(SurfaceYCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, y, z + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + f = x*x + z*z - this%r2*y*y + + end function y_cone_evaluate + +!=============================================================================== +! Y_CONE_DISTANCE +!=============================================================================== + + pure function y_cone_distance(this, xyz, uvw) result(d) + + class(SurfaceYCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, y, z, k, a, b, c, quad + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + a = uvw(1)*uvw(1) + uvw(3)*uvw(3) - this%r2*uvw(2)*uvw(2) + k = x*uvw(1) + z*uvw(3) - this%r2*y*uvw(2) + c = x*x + z*z - this%r2*y*y + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cone + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cone, thus one distance is positive/negative and the + ! other is zero. The sign of k determines which distance is zero and which + ! is not. + + if (k >= ZERO) then + d = (-k - sqrt(quad))/a + else + d = (-k + sqrt(quad))/a + end if + + else + ! calculate both solutions to the quadratic + quad = sqrt(quad) + d = (-k - quad)/a + b = (-k + quad)/a + + ! determine the smallest positive solution + if (d < ZERO) then + if (b > ZERO) then + d = b + end if + else + if (b > ZERO) d = min(d, b) + end if + end if + + ! If the distance was negative, set boundary distance to infinity + if (d <= ZERO) d = INFINITY + + end function y_cone_distance + +!=============================================================================== +! Y_CONE_REFLECT +!=============================================================================== + + subroutine y_cone_reflect(this, xyz, uvw) + + class(SurfaceYCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: x, y, z, r, dot_prod + + ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + r = this%r2 + dot_prod = (uvw(1)*x + uvw(3)*z - r*uvw(2)*y)/((r + ONE)*r*y*y) + + ! Reflect direction according to normal + uvw(1) = uvw(1) - TWO*dot_prod*x + uvw(2) = uvw(2) + TWO*dot_prod*r*y + uvw(3) = uvw(3) - TWO*dot_prod*z + + end subroutine y_cone_reflect + +!=============================================================================== +! Z_CONE_EVALUATE +!=============================================================================== + + pure function z_cone_evaluate(this, xyz) result(f) + + class(SurfaceZCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + + real(8) :: x, y, z + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + f = x*x + y*y - this%r2*z*z + + end function z_cone_evaluate + +!=============================================================================== +! Z_CONE_DISTANCE +!=============================================================================== + + pure function z_cone_distance(this, xyz, uvw) result(d) + + class(SurfaceZCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d + + real(8) :: x, y, z, k, a, b, c, quad + + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + a = uvw(1)*uvw(1) + uvw(2)*uvw(2) - this%r2*uvw(3)*uvw(3) + k = x*uvw(1) + y*uvw(2) - this%r2*z*uvw(3) + c = x*x + y*y - this%r2*z*z + quad = k*k - a*c + + if (quad < ZERO) then + ! no intersection with cone + + d = INFINITY + + elseif (abs(c) < FP_COINCIDENT) then + ! particle is on the cone, thus one distance is positive/negative and the + ! other is zero. The sign of k determines which distance is zero and which + ! is not. + + if (k >= ZERO) then + d = (-k - sqrt(quad))/a + else + d = (-k + sqrt(quad))/a + end if + + else + ! calculate both solutions to the quadratic + quad = sqrt(quad) + d = (-k - quad)/a + b = (-k + quad)/a + + ! determine the smallest positive solution + if (d < ZERO) then + if (b > ZERO) then + d = b + end if + else + if (b > ZERO) d = min(d, b) + end if + end if + + ! If the distance was negative, set boundary distance to infinity + if (d <= ZERO) d = INFINITY + + end function z_cone_distance + +!=============================================================================== +! Z_CONE_REFLECT +!=============================================================================== + + subroutine z_cone_reflect(this, xyz, uvw) + + class(SurfaceZCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: x, y, z, r, dot_prod + + ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + r = this%r2 + dot_prod = (uvw(1)*x + uvw(2)*y - r*uvw(3)*z)/((r + ONE)*r*z*z) + + ! Reflect direction according to normal + uvw(1) = uvw(1) - TWO*dot_prod*x + uvw(2) = uvw(2) - TWO*dot_prod*y + uvw(3) = uvw(3) + TWO*dot_prod*r*z + + end subroutine z_cone_reflect + +end module surface_header From e143915ea311a303317b49a61b6774bb6a422cd6 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Sep 2015 18:17:33 +0700 Subject: [PATCH 02/48] Added surface normal functions. --- src/surface.F90 | 450 ++++++++++++++++++++++-------------------------- 1 file changed, 206 insertions(+), 244 deletions(-) diff --git a/src/surface.F90 b/src/surface.F90 index abf71a450a..1ebf822d39 100644 --- a/src/surface.F90 +++ b/src/surface.F90 @@ -5,15 +5,16 @@ module surface_header implicit none type, abstract :: Surface - integer :: id ! Unique ID - integer, allocatable :: & - neighbor_pos(:), & ! List of cells on positive side - neighbor_neg(:) ! List of cells on negative side - integer :: bc ! Boundary condition - contains - procedure(iEvaluate), deferred :: evaluate - procedure(iDistance), deferred :: distance - procedure(iReflect), deferred :: reflect + integer :: id ! Unique ID + integer, allocatable :: & + neighbor_pos(:), & ! List of cells on positive side + neighbor_neg(:) ! List of cells on negative side + integer :: bc ! Boundary condition + contains + procedure(iEvaluate), deferred :: evaluate + procedure(iDistance), deferred :: distance + procedure(iReflect), deferred :: reflect + procedure(iNormal), deferred :: normal end type Surface type, extends(Surface) :: SurfaceXPlane @@ -23,6 +24,7 @@ module surface_header procedure :: evaluate => x_plane_evaluate procedure :: reflect => x_plane_reflect procedure :: distance => x_plane_distance + procedure :: normal => x_plane_normal end type SurfaceXPlane type, extends(Surface) :: SurfaceYPlane @@ -32,6 +34,7 @@ module surface_header procedure :: evaluate => y_plane_evaluate procedure :: reflect => y_plane_reflect procedure :: distance => y_plane_distance + procedure :: normal => y_plane_normal end type SurfaceYPlane type, extends(Surface) :: SurfaceZPlane @@ -41,6 +44,7 @@ module surface_header procedure :: evaluate => z_plane_evaluate procedure :: reflect => z_plane_reflect procedure :: distance => z_plane_distance + procedure :: normal => z_plane_normal end type SurfaceZPlane type, extends(Surface) :: SurfacePlane @@ -53,6 +57,7 @@ module surface_header procedure :: evaluate => plane_evaluate procedure :: reflect => plane_reflect procedure :: distance => plane_distance + procedure :: normal => plane_normal end type SurfacePlane type, extends(Surface) :: SurfaceXCylinder @@ -64,6 +69,7 @@ module surface_header procedure :: evaluate => x_cylinder_evaluate procedure :: reflect => x_cylinder_reflect procedure :: distance => x_cylinder_distance + procedure :: normal => x_cylinder_normal end type SurfaceXCylinder type, extends(Surface) :: SurfaceYCylinder @@ -75,6 +81,7 @@ module surface_header procedure :: evaluate => y_cylinder_evaluate procedure :: reflect => y_cylinder_reflect procedure :: distance => y_cylinder_distance + procedure :: normal => y_cylinder_normal end type SurfaceYCylinder type, extends(Surface) :: SurfaceZCylinder @@ -86,6 +93,7 @@ module surface_header procedure :: evaluate => z_cylinder_evaluate procedure :: reflect => z_cylinder_reflect procedure :: distance => z_cylinder_distance + procedure :: normal => z_cylinder_normal end type SurfaceZCylinder type, extends(Surface) :: SurfaceSphere @@ -98,6 +106,7 @@ module surface_header procedure :: evaluate => sphere_evaluate procedure :: reflect => sphere_reflect procedure :: distance => sphere_distance + procedure :: normal => sphere_normal end type SurfaceSphere type, extends(Surface) :: SurfaceXCone @@ -110,6 +119,7 @@ module surface_header procedure :: evaluate => x_cone_evaluate procedure :: reflect => x_cone_reflect procedure :: distance => x_cone_distance + procedure :: normal => x_cone_normal end type SurfaceXCone type, extends(Surface) :: SurfaceYCone @@ -122,6 +132,7 @@ module surface_header procedure :: evaluate => y_cone_evaluate procedure :: reflect => y_cone_reflect procedure :: distance => y_cone_distance + procedure :: normal => y_cone_normal end type SurfaceYCone type, extends(Surface) :: SurfaceZCone @@ -134,6 +145,7 @@ module surface_header procedure :: evaluate => z_cone_evaluate procedure :: reflect => z_cone_reflect procedure :: distance => z_cone_distance + procedure :: normal => z_cone_normal end type SurfaceZCone abstract interface @@ -158,34 +170,34 @@ module surface_header real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) end subroutine iReflect + + pure function iNormal(this, xyz) result(uvw) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + end function iNormal end interface contains !=============================================================================== -! X_PLANE_EVALUATE +! SurfaceXPlane Implementation !=============================================================================== pure function x_plane_evaluate(this, xyz) result(f) - class(SurfaceXPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f f = xyz(1) - this%x0 - end function x_plane_evaluate -!=============================================================================== -! X_PLANE_DISTANCE -!=============================================================================== - pure function x_plane_distance(this, xyz, uvw) result(d) - class(SurfaceXPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d if (uvw(1) == ZERO) then d = INFINITY @@ -193,47 +205,41 @@ contains d = (this%x0 - xyz(1))/uvw(1) if (d < ZERO) d = INFINITY end if - end function x_plane_distance -!=============================================================================== -! X_PLANE_REFLECT -!=============================================================================== - subroutine x_plane_reflect(this, xyz, uvw) - - class(SurfaceXPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceXPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) uvw(1) = -uvw(1) - end subroutine x_plane_reflect + pure function x_plane_normal(this, xyz) result(uvw) + class(SurfaceXPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(:) = [1, 0, 0] + end function x_plane_normal + !=============================================================================== -! Y_PLANE_EVALUATE +! SurfaceYPlane Implementation !=============================================================================== pure function y_plane_evaluate(this, xyz) result(f) - class(SurfaceYPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f f = xyz(2) - this%y0 - end function y_plane_evaluate -!=============================================================================== -! Y_PLANE_DISTANCE -!=============================================================================== - pure function y_plane_distance(this, xyz, uvw) result(d) - class(SurfaceYPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d if (uvw(2) == ZERO) then d = INFINITY @@ -241,25 +247,26 @@ contains d = (this%y0 - xyz(2))/uvw(2) if (d < ZERO) d = INFINITY end if - end function y_plane_distance -!=============================================================================== -! Y_PLANE_REFLECT -!=============================================================================== - subroutine y_plane_reflect(this, xyz, uvw) - class(SurfaceYPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) uvw(2) = -uvw(2) - end subroutine y_plane_reflect + pure function y_plane_normal(this, xyz) result(uvw) + class(SurfaceYPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(:) = [0, 1, 0] + end function y_plane_normal + !=============================================================================== -! Z_PLANE_EVALUATE +! SurfaceZPlane Implementation !=============================================================================== pure function z_plane_evaluate(this, xyz) result(f) @@ -272,16 +279,11 @@ contains end function z_plane_evaluate -!=============================================================================== -! Z_PLANE_DISTANCE -!=============================================================================== - pure function z_plane_distance(this, xyz, uvw) result(d) - class(SurfaceZPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d if (uvw(3) == ZERO) then d = INFINITY @@ -289,47 +291,41 @@ contains d = (this%z0 - xyz(3))/uvw(3) if (d < ZERO) d = INFINITY end if - end function z_plane_distance -!=============================================================================== -! Z_PLANE_REFLECT -!=============================================================================== - subroutine z_plane_reflect(this, xyz, uvw) - - class(SurfaceZPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceZPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) uvw(3) = -uvw(3) - end subroutine z_plane_reflect + pure function z_plane_normal(this, xyz) result(uvw) + class(SurfaceZPlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(:) = [0, 0, 1] + end function z_plane_normal + !=============================================================================== -! PLANE_EVALUATE +! SurfacePlane Implementation !=============================================================================== pure function plane_evaluate(this, xyz) result(f) - class(SurfacePlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D - end function plane_evaluate -!=============================================================================== -! PLANE_DISTANCE -!=============================================================================== - pure function plane_distance(this, xyz, uvw) result(d) - class(SurfacePlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: tmp @@ -340,15 +336,9 @@ contains d = -(this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D)/tmp if (d < ZERO) d = INFINITY end if - end function plane_distance -!=============================================================================== -! PLANE_REFLECT -!=============================================================================== - subroutine plane_reflect(this, xyz, uvw) - class(SurfacePlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) @@ -360,33 +350,33 @@ contains ! Reflect direction according to normal uvw = uvw - TWO*dot_product(n, uvw)/dot_product(n, n) * n - end subroutine plane_reflect + pure function plane_normal(this, xyz) result(uvw) + class(SurfacePlane), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(:) = [this%A, this%B, this%C] + end function plane_normal + !=============================================================================== -! X_CYLINDER_EVALUATE +! SurfaceXCylinder Implementation !=============================================================================== pure function x_cylinder_evaluate(this, xyz) result(f) - class(SurfaceXCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: y, z y = xyz(2) - this%y0 z = xyz(3) - this%z0 f = y*y + z*z - this%r*this%r - end function x_cylinder_evaluate -!=============================================================================== -! X_CYLINDER_DISTANCE -!=============================================================================== - pure function x_cylinder_distance(this, xyz, uvw) result(d) - class(SurfaceXCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) @@ -437,16 +427,9 @@ contains end if end if - - end function x_cylinder_distance -!=============================================================================== -! X_CYLINDER_REFLECT -!=============================================================================== - subroutine x_cylinder_reflect(this, xyz, uvw) - class(SurfaceXCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) @@ -461,38 +444,39 @@ contains ! Reflect direction according to normal uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) - - end subroutine x_cylinder_reflect + pure function x_cylinder_normal(this, xyz) result(uvw) + class(SurfaceXCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = ZERO + uvw(2) = TWO*(xyz(2) - this%y0) + uvw(3) = TWO*(xyz(3) - this%z0) + end function x_cylinder_normal + !=============================================================================== -! Y_CYLINDER_EVALUATE +! SurfaceYCylinder Implementation !=============================================================================== pure function y_cylinder_evaluate(this, xyz) result(f) - class(SurfaceYCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, z x = xyz(1) - this%x0 z = xyz(3) - this%z0 f = x*x + z*z - this%r*this%r - end function y_cylinder_evaluate -!=============================================================================== -! Y_CYLINDER_DISTANCE -!=============================================================================== - pure function y_cylinder_distance(this, xyz, uvw) result(d) - class(SurfaceYCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: x, z, k, a, c, quad @@ -539,19 +523,12 @@ contains end if end if - - end function y_cylinder_distance -!=============================================================================== -! Y_CYLINDER_REFLECT -!=============================================================================== - subroutine y_cylinder_reflect(this, xyz, uvw) - - class(SurfaceYCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceYCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) real(8) :: x, z, r, dot_prod @@ -563,34 +540,35 @@ contains ! Reflect direction according to normal uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) - - end subroutine y_cylinder_reflect + pure function y_cylinder_normal(this, xyz) result(uvw) + class(SurfaceYCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = TWO*(xyz(1) - this%x0) + uvw(2) = ZERO + uvw(3) = TWO*(xyz(3) - this%z0) + end function y_cylinder_normal + !=============================================================================== -! Z_CYLINDER_EVALUATE +! SurfaceZCylinder Implementation !=============================================================================== pure function z_cylinder_evaluate(this, xyz) result(f) - class(SurfaceZCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, y x = xyz(1) - this%x0 y = xyz(2) - this%y0 f = x*x + y*y - this%r*this%r - end function z_cylinder_evaluate -!=============================================================================== -! Z_CYLINDER_DISTANCE -!=============================================================================== - pure function z_cylinder_distance(this, xyz, uvw) result(d) - class(SurfaceZCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) @@ -641,19 +619,12 @@ contains end if end if - - end function z_cylinder_distance -!=============================================================================== -! Z_CYLINDER_REFLECT -!=============================================================================== - subroutine z_cylinder_reflect(this, xyz, uvw) - - class(SurfaceZCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceZCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) real(8) :: x, y, r, dot_prod @@ -665,18 +636,26 @@ contains ! Reflect direction according to normal uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) - end subroutine z_cylinder_reflect + pure function z_cylinder_normal(this, xyz) result(uvw) + class(SurfaceZCylinder), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = TWO*(xyz(1) - this%x0) + uvw(2) = TWO*(xyz(2) - this%y0) + uvw(3) = ZERO + end function z_cylinder_normal + !=============================================================================== -! SPHERE_EVALUATE +! SphereImplementation !=============================================================================== pure function sphere_evaluate(this, xyz) result(f) - class(SurfaceSphere), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, y, z @@ -684,19 +663,13 @@ contains y = xyz(2) - this%y0 z = xyz(3) - this%z0 f = x*x + y*y + z*z - this%r*this%r - end function sphere_evaluate -!=============================================================================== -! SPHERE_DISTANCE -!=============================================================================== - pure function sphere_distance(this, xyz, uvw) result(d) - class(SurfaceSphere), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: x, y, z, k, c, quad @@ -738,15 +711,9 @@ contains if (d < ZERO) d = INFINITY end if - end function sphere_distance -!=============================================================================== -! SPHERE_REFLECT -!=============================================================================== - subroutine sphere_reflect(this, xyz, uvw) - class(SurfaceSphere), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) @@ -758,18 +725,24 @@ contains ! Reflect direction according to normal uvw = uvw - TWO*dot_product(uvw, n)/(this%r*this%r) * n - end subroutine sphere_reflect + pure function sphere_normal(this, xyz) result(uvw) + class(SurfaceSphere), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(:) = TWO*(xyz - [this%x0, this%y0, this%z0]) + end function sphere_normal + !=============================================================================== -! X_CONE_EVALUATE +! SurfaceXCone Implementation !=============================================================================== pure function x_cone_evaluate(this, xyz) result(f) - class(SurfaceXCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, y, z @@ -777,19 +750,13 @@ contains y = xyz(2) - this%y0 z = xyz(3) - this%z0 f = y*y + z*z - this%r2*x*x - end function x_cone_evaluate -!=============================================================================== -! X_CONE_DISTANCE -!=============================================================================== - pure function x_cone_distance(this, xyz, uvw) result(d) - class(SurfaceXCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -835,15 +802,9 @@ contains ! If the distance was negative, set boundary distance to infinity if (d <= ZERO) d = INFINITY - end function x_cone_distance -!=============================================================================== -! X_CONE_REFLECT -!=============================================================================== - subroutine x_cone_reflect(this, xyz, uvw) - class(SurfaceXCone), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) @@ -861,18 +822,26 @@ contains uvw(1) = uvw(1) + TWO*dot_prod*r*x uvw(2) = uvw(2) - TWO*dot_prod*y uvw(3) = uvw(3) - TWO*dot_prod*z - end subroutine x_cone_reflect + pure function x_cone_normal(this, xyz) result(uvw) + class(SurfaceXCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = -TWO*this%r2*(xyz(1) - this%x0) + uvw(2) = TWO*(xyz(2) - this%y0) + uvw(3) = TWO*(xyz(3) - this%z0) + end function x_cone_normal + !=============================================================================== -! Y_CONE_EVALUATE +! SurfaceYCone Implementation !=============================================================================== pure function y_cone_evaluate(this, xyz) result(f) - class(SurfaceYCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, y, z @@ -880,19 +849,13 @@ contains y = xyz(2) - this%y0 z = xyz(3) - this%z0 f = x*x + z*z - this%r2*y*y - end function y_cone_evaluate -!=============================================================================== -! Y_CONE_DISTANCE -!=============================================================================== - pure function y_cone_distance(this, xyz, uvw) result(d) - class(SurfaceYCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -938,18 +901,12 @@ contains ! If the distance was negative, set boundary distance to infinity if (d <= ZERO) d = INFINITY - end function y_cone_distance -!=============================================================================== -! Y_CONE_REFLECT -!=============================================================================== - subroutine y_cone_reflect(this, xyz, uvw) - - class(SurfaceYCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceYCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) real(8) :: x, y, z, r, dot_prod @@ -964,18 +921,26 @@ contains uvw(1) = uvw(1) - TWO*dot_prod*x uvw(2) = uvw(2) + TWO*dot_prod*r*y uvw(3) = uvw(3) - TWO*dot_prod*z - end subroutine y_cone_reflect + pure function y_cone_normal(this, xyz) result(uvw) + class(SurfaceYCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = TWO*(xyz(1) - this%x0) + uvw(2) = -TWO*this%r2*(xyz(2) - this%y0) + uvw(3) = TWO*(xyz(3) - this%z0) + end function y_cone_normal + !=============================================================================== -! Z_CONE_EVALUATE +! SurfaceZConeImplementation !=============================================================================== pure function z_cone_evaluate(this, xyz) result(f) - class(SurfaceZCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f real(8) :: x, y, z @@ -983,19 +948,13 @@ contains y = xyz(2) - this%y0 z = xyz(3) - this%z0 f = x*x + y*y - this%r2*z*z - end function z_cone_evaluate -!=============================================================================== -! Z_CONE_DISTANCE -!=============================================================================== - pure function z_cone_distance(this, xyz, uvw) result(d) - class(SurfaceZCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -1041,18 +1000,12 @@ contains ! If the distance was negative, set boundary distance to infinity if (d <= ZERO) d = INFINITY - end function z_cone_distance -!=============================================================================== -! Z_CONE_REFLECT -!=============================================================================== - subroutine z_cone_reflect(this, xyz, uvw) - - class(SurfaceZCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(SurfaceZCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) real(8) :: x, y, z, r, dot_prod @@ -1067,7 +1020,16 @@ contains uvw(1) = uvw(1) - TWO*dot_prod*x uvw(2) = uvw(2) - TWO*dot_prod*y uvw(3) = uvw(3) + TWO*dot_prod*r*z - end subroutine z_cone_reflect + pure function z_cone_normal(this, xyz) result(uvw) + class(SurfaceZCone), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + + uvw(1) = TWO*(xyz(1) - this%x0) + uvw(2) = TWO*(xyz(2) - this%y0) + uvw(3) = -TWO*this%r2*(xyz(3) - this%z0) + end function z_cone_normal + end module surface_header From 257d44584f11f5b21c81d441fcca25a07a021cd1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Sep 2015 18:38:04 +0700 Subject: [PATCH 03/48] Moved surface.F90 to surface_header.F90 --- src/{surface.F90 => surface_header.F90} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{surface.F90 => surface_header.F90} (100%) diff --git a/src/surface.F90 b/src/surface_header.F90 similarity index 100% rename from src/surface.F90 rename to src/surface_header.F90 From 2dead7437a7c16da8b429a855995602973925960 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Sep 2015 19:35:13 +0700 Subject: [PATCH 04/48] Add new procedures in geometry module using polymorphic surfaces --- src/geometry.F90 | 484 ++++++++++++++++++++++++++++++++++++++++- src/global.F90 | 2 + src/input_xml.F90 | 80 ++++++- src/surface_header.F90 | 52 +++-- 4 files changed, 583 insertions(+), 35 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 39d95817ba..7696a82054 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -8,6 +8,7 @@ module geometry use output, only: write_message use particle_header, only: LocalCoord, Particle use particle_restart_write, only: write_particle_restart + use surface_header use string, only: to_str use tally, only: score_surface_current @@ -21,10 +22,9 @@ contains !=============================================================================== function simple_cell_contains(c, p) result(in_cell) - - type(Cell), pointer :: c + type(Cell), intent(in) :: c type(Particle), intent(inout) :: p - logical :: in_cell + logical :: in_cell integer :: i ! index of surfaces in cell integer :: i_surface ! index in surfaces array (with sign) @@ -62,10 +62,8 @@ contains ! If we've reached here, then the sense matched on every surface or there ! are no surfaces. in_cell = .true. - end function simple_cell_contains - !=============================================================================== ! CHECK_CELL_OVERLAP checks for overlapping cells at the current particle's ! position using simple_cell_contains and the LocalCoord's built up by find_cell @@ -554,6 +552,163 @@ contains end subroutine cross_surface + subroutine cross_surface_new(p, last_cell) + type(Particle), intent(inout) :: p + integer, intent(in) :: last_cell ! last cell particle was in + + real(8) :: u ! x-component of direction + real(8) :: v ! y-component of direction + real(8) :: w ! z-component of direction + real(8) :: norm ! "norm" of surface normal + integer :: i_surface ! index in surfaces + logical :: found ! particle found in universe? + class(Surface2), pointer :: surf + + i_surface = abs(p % surface) + surf => surfaces_c(i_surface)%obj + if (verbosity >= 10 .or. trace) then + call write_message(" Crossing surface " // trim(to_str(surf % id))) + end if + + if (surf % bc == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then + ! ======================================================================= + ! PARTICLE LEAKS OUT OF PROBLEM + + ! Kill particle + p % alive = .false. + + ! Score any surface current tallies -- note that the particle is moved + ! forward slightly so that if the mesh boundary is on the surface, it is + ! still processed + + if (active_current_tallies % size() > 0) then + ! TODO: Find a better solution to score surface currents than + ! physically moving the particle forward slightly + + p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw + call score_surface_current(p) + end if + + ! Score to global leakage tally + if (tallies_on) then + global_tally_leakage = global_tally_leakage + p % wgt + end if + + ! Display message + if (verbosity >= 10 .or. trace) then + call write_message(" Leaked out of surface " & + &// trim(to_str(surf % id))) + end if + return + + elseif (surf % bc == BC_REFLECT .and. (run_mode /= MODE_PLOTTING)) then + ! ======================================================================= + ! PARTICLE REFLECTS FROM SURFACE + + ! Do not handle reflective boundary conditions on lower universes + if (p % n_coord /= 1) then + call handle_lost_particle(p, "Cannot reflect particle " & + &// trim(to_str(p % id)) // " off surface in a lower universe.") + 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 in coincident with a mesh boundary + + if (active_current_tallies % size() > 0) then + 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 + end if + + ! Reflect particle off surface + call surf%reflect(p%coord(1)%xyz, p%coord(1)%uvw) + + ! Make sure new particle direction is normalized + u = p%coord(1)%uvw(1) + v = p%coord(1)%uvw(2) + w = p%coord(1)%uvw(3) + norm = sqrt(u*u + v*v + w*w) + p%coord(1)%uvw(:) = [u, v, w] / norm + + ! Reassign particle's cell and surface + p % coord(1) % cell = last_cell + p % surface = -p % surface + + ! If a reflective surface is coincident with a lattice or universe + ! boundary, it is necessary to redetermine the particle's coordinates in + ! the lower universes. + + p % n_coord = 1 + call find_cell(p, found) + if (.not. found) then + call handle_lost_particle(p, "Couldn't find particle after reflecting& + & from surface.") + 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(" Reflected from surface " & + &// trim(to_str(surf%id))) + end if + return + end if + + ! ========================================================================== + ! SEARCH NEIGHBOR LISTS FOR NEXT CELL + + if (p % surface > 0 .and. allocated(surf%neighbor_pos)) then + ! If coming from negative side of surface, search all the neighboring + ! cells on the positive side + + call find_cell(p, found, surf%neighbor_pos) + if (found) return + + elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then + ! If coming from positive side of surface, search all the neighboring + ! cells on the negative side + + call find_cell(p, found, surf%neighbor_neg) + if (found) return + + end if + + ! ========================================================================== + ! COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS + + ! Remove lower coordinate levels and assignment of surface + p % surface = NONE + p % n_coord = 1 + call find_cell(p, found) + + if (run_mode /= MODE_PLOTTING .and. (.not. found)) then + ! If a cell is still not found, there are two possible causes: 1) there is + ! a void in the model, and 2) the particle hit a surface at a tangent. If + ! the particle is really traveling tangent to a surface, if we move it + ! forward a tiny bit it should fix the problem. + + p % n_coord = 1 + p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw + call find_cell(p, found) + + ! Couldn't find next cell anywhere! This probably means there is an actual + ! undefined region in the geometry. + + if (.not. found) then + call handle_lost_particle(p, "After particle " // trim(to_str(p % id)) & + // " crossed surface " // trim(to_str(surf%id)) & + // " it could not be located in any cell and it did not leak.") + return + end if + end if + + end subroutine cross_surface_new + !=============================================================================== ! CROSS_LATTICE moves a particle into a new lattice element !=============================================================================== @@ -1329,6 +1484,293 @@ contains end subroutine distance_to_boundary + subroutine distance_to_boundary_new(p, dist, surface_crossed, lattice_translation, & + next_level) + type(Particle), intent(inout) :: p + real(8), intent(out) :: dist + integer, intent(out) :: surface_crossed + integer, intent(out) :: lattice_translation(3) + integer, intent(out) :: next_level + + integer :: i ! index for surface in cell + integer :: j + integer :: index_surf ! index in surfaces array (with sign) + integer :: i_xyz(3) ! lattice indices + integer :: level_surf_cross ! surface crossed on current level + integer :: level_lat_trans(3) ! lattice translation on current level + real(8) :: x,y,z ! particle coordinates + real(8) :: xyz_t(3) ! local particle coordinates + real(8) :: beta, gama ! skewed particle coordiantes + real(8) :: u,v,w ! particle directions + real(8) :: beta_dir ! skewed particle direction + real(8) :: gama_dir ! skewed particle direction + real(8) :: edge ! distance to oncoming edge + real(8) :: d ! evaluated distance + real(8) :: d_lat ! distance to lattice boundary + real(8) :: d_surf ! distance to surface + real(8) :: x0,y0,z0 ! coefficients for surface + type(Cell), pointer :: cl + class(Surface2), pointer :: surf + class(Lattice), pointer :: lat + + ! inialize distance to infinity (huge) + dist = INFINITY + d_lat = INFINITY + d_surf = INFINITY + lattice_translation(:) = [0, 0, 0] + + next_level = 0 + + ! Loop over each universe level + LEVEL_LOOP: do j = 1, p % n_coord + + ! get pointer to cell on this level + cl => cells(p % coord(j) % cell) + + ! copy directional cosines + u = p % coord(j) % uvw(1) + v = p % coord(j) % uvw(2) + w = p % coord(j) % uvw(3) + + ! ======================================================================= + ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL + + SURFACE_LOOP: do i = 1, cl % n_surfaces + ! check for operators + index_surf = abs(index_surf) + if (index_surf >= OP_DIFFERENCE) cycle + + ! Calculate distance to surface + surf => surfaces_c(index_surf)%obj + d = surf%distance(p%coord(j)%xyz, p%coord(j)%uvw) + + ! Check is calculated distance is new minimum + if (d < d_surf) then + if (abs(d - d_surf)/d_surf >= FP_PRECISION) then + d_surf = d + level_surf_cross = -cl % surfaces(i) + end if + end if + end do SURFACE_LOOP + + ! ======================================================================= + ! FIND MINIMUM DISTANCE TO LATTICE SURFACES + + LAT_COORD: if (p % coord(j) % lattice /= NONE) then + lat => lattices(p % coord(j) % lattice) % obj + + LAT_TYPE: select type(lat) + + type is (RectLattice) + ! copy local coordinates + x = p % coord(j) % xyz(1) + y = p % coord(j) % xyz(2) + z = p % coord(j) % xyz(3) + + ! determine oncoming edge + x0 = sign(lat % pitch(1) * HALF, u) + y0 = sign(lat % pitch(2) * HALF, v) + + ! left and right sides + if (abs(x - x0) < FP_PRECISION) then + d = INFINITY + elseif (u == ZERO) then + d = INFINITY + else + d = (x0 - x)/u + end if + + d_lat = d + if (u > 0) then + level_lat_trans(:) = [1, 0, 0] + else + level_lat_trans(:) = [-1, 0, 0] + end if + + ! front and back sides + if (abs(y - y0) < FP_PRECISION) then + d = INFINITY + elseif (v == ZERO) then + d = INFINITY + else + d = (y0 - y)/v + end if + + if (d < d_lat) then + d_lat = d + if (v > 0) then + level_lat_trans(:) = [0, 1, 0] + else + level_lat_trans(:) = [0, -1, 0] + end if + end if + + if (lat % is_3d) then + z0 = sign(lat % pitch(3) * HALF, w) + + ! top and bottom sides + if (abs(z - z0) < FP_PRECISION) then + d = INFINITY + elseif (w == ZERO) then + d = INFINITY + else + d = (z0 - z)/w + end if + + if (d < d_lat) then + d_lat = d + if (w > 0) then + level_lat_trans(:) = [0, 0, 1] + else + level_lat_trans(:) = [0, 0, -1] + end if + end if + end if + + type is (HexLattice) LAT_TYPE + ! Copy local coordinates. + z = p % coord(j) % xyz(3) + i_xyz(1) = p % coord(j) % lattice_x + i_xyz(2) = p % coord(j) % lattice_y + i_xyz(3) = p % coord(j) % lattice_z + + ! Compute velocities along the hexagonal axes. + beta_dir = u*sqrt(THREE)/TWO + v/TWO + gama_dir = u*sqrt(THREE)/TWO - v/TWO + + ! Note that hexagonal lattice distance calculations are performed + ! using the particle's coordinates relative to the neighbor lattice + ! cells, not relative to the particle's current cell. This is done + ! because there is significant disagreement between neighboring cells + ! on where the lattice boundary is due to the worse finite precision + ! of hex lattices. + + ! Upper right and lower left sides. + edge = -sign(lat % pitch(1)/TWO, beta_dir) ! Oncoming edge + if (beta_dir > ZERO) then + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, 0, 0]) + else + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 0, 0]) + end if + beta = xyz_t(1)*sqrt(THREE)/TWO + xyz_t(2)/TWO + if (abs(beta - edge) < FP_PRECISION) then + d = INFINITY + else if (beta_dir == ZERO) then + d = INFINITY + else + d = (edge - beta)/beta_dir + end if + + d_lat = d + if (beta_dir > 0) then + level_lat_trans(:) = [1, 0, 0] + else + level_lat_trans(:) = [-1, 0, 0] + end if + + ! Lower right and upper left sides. + edge = -sign(lat % pitch(1)/TWO, gama_dir) ! Oncoming edge + if (gama_dir > ZERO) then + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, -1, 0]) + else + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 1, 0]) + end if + gama = xyz_t(1)*sqrt(THREE)/TWO - xyz_t(2)/TWO + if (abs(gama - edge) < FP_PRECISION) then + d = INFINITY + else if (gama_dir == ZERO) then + d = INFINITY + else + d = (edge - gama)/gama_dir + end if + + if (d < d_lat) then + d_lat = d + if (gama_dir > 0) then + level_lat_trans(:) = [1, -1, 0] + else + level_lat_trans(:) = [-1, 1, 0] + end if + end if + + ! Upper and lower sides. + edge = -sign(lat % pitch(1)/TWO, v) ! Oncoming edge + if (v > ZERO) then + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, 1, 0]) + else + xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, -1, 0]) + end if + if (abs(xyz_t(2) - edge) < FP_PRECISION) then + d = INFINITY + else if (v == ZERO) then + d = INFINITY + else + d = (edge - xyz_t(2))/v + end if + + if (d < d_lat) then + d_lat = d + if (v > 0) then + level_lat_trans(:) = [0, 1, 0] + else + level_lat_trans(:) = [0, -1, 0] + end if + end if + + ! Top and bottom sides. + if (lat % is_3d) then + z0 = sign(lat % pitch(2) * HALF, w) + + if (abs(z - z0) < FP_PRECISION) then + d = INFINITY + elseif (w == ZERO) then + d = INFINITY + else + d = (z0 - z)/w + end if + + if (d < d_lat) then + d_lat = d + if (w > 0) then + level_lat_trans(:) = [0, 0, 1] + else + level_lat_trans(:) = [0, 0, -1] + end if + end if + end if + end select LAT_TYPE + + if (d_lat < ZERO) then + call handle_lost_particle(p, "Particle " // trim(to_str(p % id)) & + //" had a negative distance to a lattice boundary. d = " & + //trim(to_str(d_lat))) + end if + end if LAT_COORD + + ! If the boundary on this lattice level is coincident with a boundary on + ! a higher level then we need to make sure that the higher level boundary + ! is selected. This logic must include consideration of floating point + ! precision. + if (d_surf < d_lat) then + if ((dist - d_surf)/dist >= FP_REL_PRECISION) then + dist = d_surf + surface_crossed = level_surf_cross + lattice_translation(:) = [0, 0, 0] + next_level = j + end if + else + if ((dist - d_lat)/dist >= FP_REL_PRECISION) then + dist = d_lat + surface_crossed = None + lattice_translation(:) = level_lat_trans + next_level = j + end if + end if + + end do LEVEL_LOOP + + end subroutine distance_to_boundary_new + !=============================================================================== ! SENSE determines whether a point is on the 'positive' or 'negative' side of a ! surface. This routine is crucial for determining what cell a particular point @@ -1456,6 +1898,34 @@ contains end function sense + recursive function sense_new(p, surf) result(s) + type(Particle), intent(inout) :: p + class(Surface2), intent(in) :: surf ! surface + logical :: s ! sense of particle + + integer :: j + real(8) :: func ! surface function evaluated at point + + j = p%n_coord + + ! Evaluate the surface equation at the particle's coordinates to determine + ! which side the particle is on + func = surf%evaluate(p%coord(j)%xyz) + + ! Check which side of surface the point is on + if (abs(func) < FP_COINCIDENT) then + ! Particle may be coincident with this surface. Artifically move the + ! particle forward a tiny bit. + p%coord(j)%xyz = p%coord(j)%xyz + TINY_BIT * p%coord(j)%uvw + s = sense_new(p, surf) + elseif (func > 0) then + s = .true. + else + s = .false. + end if + + end function sense_new + !=============================================================================== ! NEIGHBOR_LISTS builds a list of neighboring cells to each surface to speed up ! searches when a cell boundary is crossed. @@ -1501,9 +1971,11 @@ contains surf => surfaces(i) if (count_positive(i) > 0) then allocate(surf%neighbor_pos(count_positive(i))) + allocate(surfaces_c(i)%obj%neighbor_pos(count_positive(i))) end if if (count_negative(i) > 0) then allocate(surf%neighbor_neg(count_negative(i))) + allocate(surfaces_c(i)%obj%neighbor_neg(count_negative(i))) end if end do @@ -1524,9 +1996,11 @@ contains if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 surf%neighbor_pos(count_positive(i_surface)) = i + surfaces_c(i_surface)%obj%neighbor_pos(count_positive(i_surface)) = i else count_negative(i_surface) = count_negative(i_surface) + 1 surf%neighbor_neg(count_negative(i_surface)) = i + surfaces_c(i_surface)%obj%neighbor_neg(count_negative(i_surface)) = i end if end do end do diff --git a/src/global.F90 b/src/global.F90 index 398b72e140..246fa3f3ae 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -11,6 +11,7 @@ module global use mesh_header, only: RegularMesh use plot_header, only: ObjectPlot use set_header, only: SetInt + use surface_header, only: SurfaceContainer use source_header, only: ExtSource use tally_header, only: TallyObject, TallyMap, TallyResult use trigger_header, only: KTrigger @@ -31,6 +32,7 @@ module global type(Universe), allocatable, target :: universes(:) type(LatticeContainer), allocatable, target :: lattices(:) type(Surface), allocatable, target :: surfaces(:) + type(SurfaceContainer), allocatable, target :: surfaces_c(:) type(Material), allocatable, target :: materials(:) type(ObjectPlot), allocatable, target :: plots(:) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 3899d43f0e..57769d33ac 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -12,6 +12,7 @@ module input_xml use output, only: write_message use plot_header use random_lcg, only: prn + use surface_header use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with use tally_header, only: TallyObject, TallyFilter @@ -987,13 +988,14 @@ contains integer :: coeffs_reqd integer, allocatable :: temp_int_array(:) real(8) :: phi, theta, psi + real(8), allocatable :: coeffs(:) logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word - type(Cell), pointer :: c => null() - type(Surface), pointer :: s => null() - class(Lattice), pointer :: lat => null() + type(Cell), pointer :: c + type(Surface), pointer :: s + class(Lattice), pointer :: lat type(Node), pointer :: doc => null() type(Node), pointer :: node_cell => null() type(Node), pointer :: node_surf => null() @@ -1220,6 +1222,7 @@ contains ! Allocate cells array allocate(surfaces(n_surfaces)) + allocate(surfaces_c(n_surfaces)) do i = 1, n_surfaces s => surfaces(i) @@ -1253,39 +1256,51 @@ contains case ('x-plane') s % type = SURF_PX coeffs_reqd = 1 + allocate(SurfaceXPlane :: surfaces_c(i)%obj) case ('y-plane') s % type = SURF_PY coeffs_reqd = 1 + allocate(SurfaceYPlane :: surfaces_c(i)%obj) case ('z-plane') s % type = SURF_PZ coeffs_reqd = 1 + allocate(SurfaceZPlane :: surfaces_c(i)%obj) case ('plane') s % type = SURF_PLANE coeffs_reqd = 4 + allocate(SurfacePlane :: surfaces_c(i)%obj) case ('x-cylinder') s % type = SURF_CYL_X coeffs_reqd = 3 + allocate(SurfaceXCylinder :: surfaces_c(i)%obj) case ('y-cylinder') s % type = SURF_CYL_Y coeffs_reqd = 3 + allocate(SurfaceYCylinder :: surfaces_c(i)%obj) case ('z-cylinder') s % type = SURF_CYL_Z coeffs_reqd = 3 + allocate(SurfaceZCylinder :: surfaces_c(i)%obj) case ('sphere') s % type = SURF_SPHERE coeffs_reqd = 4 + allocate(SurfaceSphere :: surfaces_c(i)%obj) case ('x-cone') s % type = SURF_CONE_X coeffs_reqd = 4 + allocate(SurfaceXCone :: surfaces_c(i)%obj) case ('y-cone') s % type = SURF_CONE_Y coeffs_reqd = 4 + allocate(SurfaceYCone :: surfaces_c(i)%obj) case ('z-cone') s % type = SURF_CONE_Z coeffs_reqd = 4 + allocate(SurfaceZCone :: surfaces_c(i)%obj) case default call fatal_error("Invalid surface type: " // trim(word)) end select + surfaces_c(i)%obj%id = s%id ! Check to make sure that the proper number of coefficients ! have been specified for the given type of surface. Then copy @@ -1298,11 +1313,62 @@ contains elseif (n > coeffs_reqd) then call fatal_error("Too many coefficients specified for surface: " & &// trim(to_str(s % id))) - else - allocate(s % coeffs(n)) - call get_node_array(node_surf, "coeffs", s % coeffs) end if + allocate(coeffs(n)) + allocate(s%coeffs(n)) + call get_node_array(node_surf, "coeffs", coeffs) + s%coeffs(:) = coeffs(:) + + select type(sp => surfaces_c(i)%obj) + type is (SurfaceXPlane) + sp%x0 = coeffs(1) + type is (SurfaceYPlane) + sp%y0 = coeffs(1) + type is (SurfaceZPlane) + sp%z0 = coeffs(1) + type is (SurfacePlane) + sp%A = coeffs(1) + sp%B = coeffs(2) + sp%C = coeffs(3) + sp%D = coeffs(4) + type is (SurfaceXCylinder) + sp%y0 = coeffs(1) + sp%z0 = coeffs(2) + sp%r = coeffs(3) + type is (SurfaceYCylinder) + sp%x0 = coeffs(1) + sp%z0 = coeffs(2) + sp%r = coeffs(3) + type is (SurfaceZCylinder) + sp%x0 = coeffs(1) + sp%y0 = coeffs(2) + sp%r = coeffs(3) + type is (SurfaceSphere) + sp%x0 = coeffs(1) + sp%y0 = coeffs(2) + sp%z0 = coeffs(3) + sp%r = coeffs(4) + type is (SurfaceXCone) + sp%x0 = coeffs(1) + sp%y0 = coeffs(2) + sp%z0 = coeffs(3) + sp%r2 = coeffs(4) + type is (SurfaceYCone) + sp%x0 = coeffs(1) + sp%y0 = coeffs(2) + sp%z0 = coeffs(3) + sp%r2 = coeffs(4) + type is (SurfaceZCone) + sp%x0 = coeffs(1) + sp%y0 = coeffs(2) + sp%z0 = coeffs(3) + sp%r2 = coeffs(4) + end select + + ! No longer need coefficients + deallocate(coeffs) + ! Boundary conditions word = '' if (check_for_node(node_surf, "boundary")) & @@ -1321,6 +1387,8 @@ contains &"' specified on surface " // trim(to_str(s % id))) end select + surfaces_c(i)%obj%bc = s%bc + ! Add surface to dictionary call surface_dict % add_key(s % id, i) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 1ebf822d39..442c670f58 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -4,7 +4,7 @@ module surface_header implicit none - type, abstract :: Surface + type, abstract :: Surface2 integer :: id ! Unique ID integer, allocatable :: & neighbor_pos(:), & ! List of cells on positive side @@ -15,9 +15,13 @@ module surface_header procedure(iDistance), deferred :: distance procedure(iReflect), deferred :: reflect procedure(iNormal), deferred :: normal - end type Surface + end type Surface2 - type, extends(Surface) :: SurfaceXPlane + type :: SurfaceContainer + class(Surface2), allocatable :: obj + end type SurfaceContainer + + type, extends(Surface2) :: SurfaceXPlane ! x = x0 real(8) :: x0 contains @@ -27,7 +31,7 @@ module surface_header procedure :: normal => x_plane_normal end type SurfaceXPlane - type, extends(Surface) :: SurfaceYPlane + type, extends(Surface2) :: SurfaceYPlane ! y = y0 real(8) :: y0 contains @@ -37,7 +41,7 @@ module surface_header procedure :: normal => y_plane_normal end type SurfaceYPlane - type, extends(Surface) :: SurfaceZPlane + type, extends(Surface2) :: SurfaceZPlane ! z = z0 real(8) :: z0 contains @@ -47,7 +51,7 @@ module surface_header procedure :: normal => z_plane_normal end type SurfaceZPlane - type, extends(Surface) :: SurfacePlane + type, extends(Surface2) :: SurfacePlane ! Ax + By + Cz = D real(8) :: A real(8) :: B @@ -60,7 +64,7 @@ module surface_header procedure :: normal => plane_normal end type SurfacePlane - type, extends(Surface) :: SurfaceXCylinder + type, extends(Surface2) :: SurfaceXCylinder ! (y - y0)^2 + (z - z0)^2 = R^2 real(8) :: y0 real(8) :: z0 @@ -72,7 +76,7 @@ module surface_header procedure :: normal => x_cylinder_normal end type SurfaceXCylinder - type, extends(Surface) :: SurfaceYCylinder + type, extends(Surface2) :: SurfaceYCylinder ! (x - x0)^2 + (z - z0)^2 = R^2 real(8) :: x0 real(8) :: z0 @@ -84,7 +88,7 @@ module surface_header procedure :: normal => y_cylinder_normal end type SurfaceYCylinder - type, extends(Surface) :: SurfaceZCylinder + type, extends(Surface2) :: SurfaceZCylinder ! (x - x0)^2 + (y - y0)^2 = R^2 real(8) :: x0 real(8) :: y0 @@ -96,7 +100,7 @@ module surface_header procedure :: normal => z_cylinder_normal end type SurfaceZCylinder - type, extends(Surface) :: SurfaceSphere + type, extends(Surface2) :: SurfaceSphere ! (x - x0)^2 + (y - y0)^2 + (z - z0)^2 = R^2 real(8) :: x0 real(8) :: y0 @@ -109,7 +113,7 @@ module surface_header procedure :: normal => sphere_normal end type SurfaceSphere - type, extends(Surface) :: SurfaceXCone + type, extends(Surface2) :: SurfaceXCone ! (y - y0)^2 + (z - z0)^2 = R^2*(x - x0)^2 real(8) :: x0 real(8) :: y0 @@ -122,7 +126,7 @@ module surface_header procedure :: normal => x_cone_normal end type SurfaceXCone - type, extends(Surface) :: SurfaceYCone + type, extends(Surface2) :: SurfaceYCone ! (x - x0)^2 + (z - z0)^2 = R^2*(y - y0)^2 real(8) :: x0 real(8) :: y0 @@ -135,7 +139,7 @@ module surface_header procedure :: normal => y_cone_normal end type SurfaceYCone - type, extends(Surface) :: SurfaceZCone + type, extends(Surface2) :: SurfaceZCone ! (x - x0)^2 + (y - y0)^2 = R^2*(z - z0)^2 real(8) :: x0 real(8) :: y0 @@ -150,30 +154,30 @@ module surface_header abstract interface pure function iEvaluate(this, xyz) result(f) - import Surface - class(Surface), intent(in) :: this + import Surface2 + class(Surface2), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: f end function iEvaluate pure function iDistance(this, xyz, uvw) result(d) - import Surface - class(Surface), intent(in) :: this + import Surface2 + class(Surface2), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) real(8) :: d end function iDistance subroutine iReflect(this, xyz, uvw) - import Surface - class(Surface), intent(in) :: this + import Surface2 + class(Surface2), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) end subroutine iReflect pure function iNormal(this, xyz) result(uvw) - import Surface - class(Surface), intent(in) :: this + import Surface2 + class(Surface2), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: uvw(3) end function iNormal @@ -434,7 +438,7 @@ contains real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) - real(8) :: y, z, r, dot_prod + real(8) :: y, z, dot_prod ! Find y-y0, z-z0 and dot product of direction and surface normal y = xyz(2) - this%y0 @@ -530,7 +534,7 @@ contains real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) - real(8) :: x, z, r, dot_prod + real(8) :: x, z, dot_prod ! Find x-x0, z-z0 and dot product of direction and surface normal x = xyz(1) - this%x0 @@ -626,7 +630,7 @@ contains real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) - real(8) :: x, y, r, dot_prod + real(8) :: x, y, dot_prod ! Find x-x0, y-y0 and dot product of direction and surface normal x = xyz(1) - this%x0 From e3843c473827ce6ff9896c3290dbf9a4c10221eb Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 22 Sep 2015 22:53:20 +0700 Subject: [PATCH 05/48] Fix a few consistency issues. Move to new versions of sense/cross_surface --- src/geometry.F90 | 6 ++---- src/surface_header.F90 | 40 +++++++++++++++++++++++++++------------- src/tracking.F90 | 4 ++-- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 7696a82054..9b4ca0dde0 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -30,7 +30,6 @@ contains integer :: i_surface ! index in surfaces array (with sign) logical :: specified_sense ! specified sense of surface in list logical :: actual_sense ! sense of particle wrt surface - type(Surface), pointer :: s SURFACE_LOOP: do i = 1, c % n_surfaces ! Lookup surface @@ -48,8 +47,7 @@ contains ! Determine the specified sense of the surface in the cell and the actual ! sense of the particle with respect to the surface - s => surfaces(abs(i_surface)) - actual_sense = sense(p, s) + actual_sense = sense_new(p, surfaces_c(abs(i_surface))%obj) specified_sense = (c % surfaces(i) > 0) ! Compare sense of point to specified sense @@ -1537,7 +1535,7 @@ contains SURFACE_LOOP: do i = 1, cl % n_surfaces ! check for operators - index_surf = abs(index_surf) + index_surf = abs(cl%surfaces(i)) if (index_surf >= OP_DIFFERENCE) cycle ! Calculate distance to surface diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 442c670f58..ff7454352b 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -203,10 +203,13 @@ contains real(8), intent(in) :: uvw(3) real(8) :: d - if (uvw(1) == ZERO) then + real(8) :: f + + f = this%x0 - xyz(1) + if (abs(f) < FP_COINCIDENT .or. uvw(1) == ZERO) then d = INFINITY else - d = (this%x0 - xyz(1))/uvw(1) + d = f/uvw(1) if (d < ZERO) d = INFINITY end if end function x_plane_distance @@ -245,10 +248,13 @@ contains real(8), intent(in) :: uvw(3) real(8) :: d - if (uvw(2) == ZERO) then + real(8) :: f + + f = this%y0 - xyz(2) + if (abs(f) < FP_COINCIDENT .or. uvw(2) == ZERO) then d = INFINITY else - d = (this%y0 - xyz(2))/uvw(2) + d = f/uvw(2) if (d < ZERO) d = INFINITY end if end function y_plane_distance @@ -289,10 +295,13 @@ contains real(8), intent(in) :: uvw(3) real(8) :: d - if (uvw(3) == ZERO) then + real(8) :: f + + f = this%z0 - xyz(3) + if (abs(f) < FP_COINCIDENT .or. uvw(3) == ZERO) then d = INFINITY else - d = (this%z0 - xyz(3))/uvw(3) + d = f/uvw(3) if (d < ZERO) d = INFINITY end if end function z_plane_distance @@ -331,13 +340,15 @@ contains real(8), intent(in) :: uvw(3) real(8) :: d + real(8) :: f real(8) :: tmp + f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D tmp = this%A*uvw(1) + this%B*uvw(2) + this%C*uvw(3) - if (tmp == ZERO) then + if (abs(f) < FP_COINCIDENT .or. tmp == ZERO) then d = INFINITY else - d = -(this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D)/tmp + d = -f/tmp if (d < ZERO) d = INFINITY end if end function plane_distance @@ -722,13 +733,16 @@ contains real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) - real(8) :: n(3) + real(8) :: x, y, z, dot_prod - ! Determine surface surface normal - n(:) = xyz - [this%x0, this%y0, this%z0] + x = xyz(1) - this%x0 + y = xyz(2) - this%y0 + z = xyz(3) - this%z0 + dot_prod = uvw(1)*x + uvw(2)*y + uvw(3)*z - ! Reflect direction according to normal - uvw = uvw - TWO*dot_product(uvw, n)/(this%r*this%r) * n + uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) + uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) + uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) end subroutine sphere_reflect pure function sphere_normal(this, xyz) result(uvw) diff --git a/src/tracking.F90 b/src/tracking.F90 index 81f01b4110..b2faa8d22a 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -3,7 +3,7 @@ module tracking use constants, only: MODE_EIGENVALUE use cross_section, only: calculate_xs use error, only: fatal_error, warning - use geometry, only: find_cell, distance_to_boundary, cross_surface, & + use geometry, only: find_cell, distance_to_boundary, cross_surface_new, & cross_lattice, check_cell_overlap use geometry_header, only: Universe, BASE_UNIVERSE use global @@ -129,7 +129,7 @@ contains else ! Particle crosses surface p % surface = surface_crossed - call cross_surface(p, last_cell) + call cross_surface_new(p, last_cell) p % event = EVENT_SURFACE end if else From 1e99f09187447b8dbfd8dead0b8c20f6137d5229 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 08:18:20 +0700 Subject: [PATCH 06/48] Add 'coincident' argument to distance routines. When a particle is advanced to a surface, due to limited precision it may appear as though the particle's position is not exactly coincident (as tested by the sense of the particle with respect to the surface). Thus, the only sure way of making sure that distance() returns the correct value is to pass it an argument indicating whether the particle is coincident with the surface. --- src/geometry.F90 | 9 ++++- src/surface_header.F90 | 86 ++++++++++++++++++++++++------------------ src/tracking.F90 | 4 +- 3 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 9b4ca0dde0..e4df72fb0f 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -1507,6 +1507,7 @@ contains real(8) :: d_lat ! distance to lattice boundary real(8) :: d_surf ! distance to surface real(8) :: x0,y0,z0 ! coefficients for surface + logical :: coincident ! is particle on surface? type(Cell), pointer :: cl class(Surface2), pointer :: surf class(Lattice), pointer :: lat @@ -1535,12 +1536,16 @@ contains SURFACE_LOOP: do i = 1, cl % n_surfaces ! check for operators - index_surf = abs(cl%surfaces(i)) + index_surf = cl%surfaces(i) + coincident = (index_surf == p % surface) + + ! check for operators + index_surf = abs(index_surf) if (index_surf >= OP_DIFFERENCE) cycle ! Calculate distance to surface surf => surfaces_c(index_surf)%obj - d = surf%distance(p%coord(j)%xyz, p%coord(j)%uvw) + d = surf%distance(p%coord(j)%xyz, p%coord(j)%uvw, coincident) ! Check is calculated distance is new minimum if (d < d_surf) then diff --git a/src/surface_header.F90 b/src/surface_header.F90 index ff7454352b..c4a1a921f1 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -156,23 +156,24 @@ module surface_header pure function iEvaluate(this, xyz) result(f) import Surface2 class(Surface2), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f + real(8), intent(in) :: xyz(3) + real(8) :: f end function iEvaluate - pure function iDistance(this, xyz, uvw) result(d) + pure function iDistance(this, xyz, uvw, coincident) result(d) import Surface2 class(Surface2), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident + real(8) :: d end function iDistance subroutine iReflect(this, xyz, uvw) import Surface2 - class(Surface2), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) + class(Surface2), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) end subroutine iReflect pure function iNormal(this, xyz) result(uvw) @@ -197,16 +198,17 @@ contains f = xyz(1) - this%x0 end function x_plane_evaluate - pure function x_plane_distance(this, xyz, uvw) result(d) + pure function x_plane_distance(this, xyz, uvw, coincident) result(d) class(SurfaceXPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: f f = this%x0 - xyz(1) - if (abs(f) < FP_COINCIDENT .or. uvw(1) == ZERO) then + if (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(1) == ZERO) then d = INFINITY else d = f/uvw(1) @@ -242,16 +244,17 @@ contains f = xyz(2) - this%y0 end function y_plane_evaluate - pure function y_plane_distance(this, xyz, uvw) result(d) + pure function y_plane_distance(this, xyz, uvw, coincident) result(d) class(SurfaceYPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: f f = this%y0 - xyz(2) - if (abs(f) < FP_COINCIDENT .or. uvw(2) == ZERO) then + if (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(2) == ZERO) then d = INFINITY else d = f/uvw(2) @@ -289,16 +292,17 @@ contains end function z_plane_evaluate - pure function z_plane_distance(this, xyz, uvw) result(d) + pure function z_plane_distance(this, xyz, uvw, coincident) result(d) class(SurfaceZPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: f f = this%z0 - xyz(3) - if (abs(f) < FP_COINCIDENT .or. uvw(3) == ZERO) then + if (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(3) == ZERO) then d = INFINITY else d = f/uvw(3) @@ -334,10 +338,11 @@ contains f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D end function plane_evaluate - pure function plane_distance(this, xyz, uvw) result(d) + pure function plane_distance(this, xyz, uvw, coincident) result(d) class(SurfacePlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: f @@ -345,7 +350,7 @@ contains f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D tmp = this%A*uvw(1) + this%B*uvw(2) + this%C*uvw(3) - if (abs(f) < FP_COINCIDENT .or. tmp == ZERO) then + if (coincident .or. abs(f) < FP_COINCIDENT .or. tmp == ZERO) then d = INFINITY else d = -f/tmp @@ -391,11 +396,12 @@ contains f = y*y + z*z - this%r*this%r end function x_cylinder_evaluate - pure function x_cylinder_distance(this, xyz, uvw) result(d) + pure function x_cylinder_distance(this, xyz, uvw, coincident) result(d) class(SurfaceXCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident + real(8) :: d real(8) :: y, z, k, a, c, quad @@ -414,7 +420,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cylinder, thus one distance is positive/negative ! and the other is zero. The sign of k determines if we are facing in or ! out @@ -487,10 +493,11 @@ contains f = x*x + z*z - this%r*this%r end function y_cylinder_evaluate - pure function y_cylinder_distance(this, xyz, uvw) result(d) + pure function y_cylinder_distance(this, xyz, uvw, coincident) result(d) class(SurfaceYCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: x, z, k, a, c, quad @@ -510,7 +517,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cylinder, thus one distance is positive/negative ! and the other is zero. The sign of k determines if we are facing in or ! out @@ -583,11 +590,12 @@ contains f = x*x + y*y - this%r*this%r end function z_cylinder_evaluate - pure function z_cylinder_distance(this, xyz, uvw) result(d) + pure function z_cylinder_distance(this, xyz, uvw, coincident) result(d) class(SurfaceZCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - real(8) :: d + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident + real(8) :: d real(8) :: x, y, k, a, c, quad @@ -606,7 +614,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cylinder, thus one distance is positive/negative ! and the other is zero. The sign of k determines if we are facing in or ! out @@ -680,10 +688,11 @@ contains f = x*x + y*y + z*z - this%r*this%r end function sphere_evaluate - pure function sphere_distance(this, xyz, uvw) result(d) + pure function sphere_distance(this, xyz, uvw, coincident) result(d) class(SurfaceSphere), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: x, y, z, k, c, quad @@ -700,7 +709,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the sphere, thus one distance is positive/negative and ! the other is zero. The sign of k determines if we are facing in or out @@ -770,10 +779,11 @@ contains f = y*y + z*z - this%r2*x*x end function x_cone_evaluate - pure function x_cone_distance(this, xyz, uvw) result(d) + pure function x_cone_distance(this, xyz, uvw, coincident) result(d) class(SurfaceXCone), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -791,7 +801,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cone, thus one distance is positive/negative and the ! other is zero. The sign of k determines which distance is zero and which ! is not. @@ -869,10 +879,11 @@ contains f = x*x + z*z - this%r2*y*y end function y_cone_evaluate - pure function y_cone_distance(this, xyz, uvw) result(d) + pure function y_cone_distance(this, xyz, uvw, coincident) result(d) class(SurfaceYCone), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -890,7 +901,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cone, thus one distance is positive/negative and the ! other is zero. The sign of k determines which distance is zero and which ! is not. @@ -968,10 +979,11 @@ contains f = x*x + y*y - this%r2*z*z end function z_cone_evaluate - pure function z_cone_distance(this, xyz, uvw) result(d) + pure function z_cone_distance(this, xyz, uvw, coincident) result(d) class(SurfaceZCone), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident real(8) :: d real(8) :: x, y, z, k, a, b, c, quad @@ -989,7 +1001,7 @@ contains d = INFINITY - elseif (abs(c) < FP_COINCIDENT) then + elseif (coincident .or. abs(c) < FP_COINCIDENT) then ! particle is on the cone, thus one distance is positive/negative and the ! other is zero. The sign of k determines which distance is zero and which ! is not. diff --git a/src/tracking.F90 b/src/tracking.F90 index b2faa8d22a..3669a61e85 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -3,7 +3,7 @@ module tracking use constants, only: MODE_EIGENVALUE use cross_section, only: calculate_xs use error, only: fatal_error, warning - use geometry, only: find_cell, distance_to_boundary, cross_surface_new, & + use geometry, only: find_cell, distance_to_boundary_new, cross_surface_new, & cross_lattice, check_cell_overlap use geometry_header, only: Universe, BASE_UNIVERSE use global @@ -86,7 +86,7 @@ contains if (p % material /= p % last_material) call calculate_xs(p) ! Find the distance to the nearest boundary - call distance_to_boundary(p, d_boundary, surface_crossed, & + call distance_to_boundary_new(p, d_boundary, surface_crossed, & lattice_translation, next_level) ! Sample a distance to collision From 8d765d76bd8897048525fa7d8ace4bfe5176f95a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 08:24:15 +0700 Subject: [PATCH 07/48] Remove old geometry routines --- src/geometry.F90 | 1111 +--------------------------------------------- src/tracking.F90 | 6 +- 2 files changed, 8 insertions(+), 1109 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index e4df72fb0f..c9f4927f29 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -47,7 +47,7 @@ contains ! Determine the specified sense of the surface in the cell and the actual ! sense of the particle with respect to the surface - actual_sense = sense_new(p, surfaces_c(abs(i_surface))%obj) + actual_sense = sense(p, surfaces_c(abs(i_surface))%obj) specified_sense = (c % surfaces(i) > 0) ! Compare sense of point to specified sense @@ -269,288 +269,6 @@ contains !=============================================================================== subroutine cross_surface(p, last_cell) - - type(Particle), intent(inout) :: p - integer, intent(in) :: last_cell ! last cell particle was in - - real(8) :: x ! x-x0 for sphere - real(8) :: y ! y-y0 for sphere - real(8) :: z ! z-z0 for sphere - real(8) :: R ! radius of sphere - real(8) :: u ! x-component of direction - real(8) :: v ! y-component of direction - real(8) :: w ! z-component of direction - real(8) :: n1 ! x-component of surface normal - real(8) :: n2 ! y-component of surface normal - real(8) :: n3 ! z-component of surface normal - real(8) :: dot_prod ! dot product of direction and normal - real(8) :: norm ! "norm" of surface normal - integer :: i_surface ! index in surfaces - logical :: found ! particle found in universe? - type(Surface), pointer :: surf - - i_surface = abs(p % surface) - surf => surfaces(i_surface) - if (verbosity >= 10 .or. trace) then - call write_message(" Crossing surface " // trim(to_str(surf % id))) - end if - - if (surf % bc == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then - ! ======================================================================= - ! PARTICLE LEAKS OUT OF PROBLEM - - ! Kill particle - p % alive = .false. - - ! Score any surface current tallies -- note that the particle is moved - ! forward slightly so that if the mesh boundary is on the surface, it is - ! still processed - - if (active_current_tallies % size() > 0) then - ! TODO: Find a better solution to score surface currents than - ! physically moving the particle forward slightly - - p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw - call score_surface_current(p) - end if - - ! Score to global leakage tally - if (tallies_on) then - global_tally_leakage = global_tally_leakage + p % wgt - end if - - ! Display message - if (verbosity >= 10 .or. trace) then - call write_message(" Leaked out of surface " & - &// trim(to_str(surf % id))) - end if - return - - elseif (surf % bc == BC_REFLECT .and. (run_mode /= MODE_PLOTTING)) then - ! ======================================================================= - ! PARTICLE REFLECTS FROM SURFACE - - ! Do not handle reflective boundary conditions on lower universes - if (p % n_coord /= 1) then - call handle_lost_particle(p, "Cannot reflect particle " & - &// trim(to_str(p % id)) // " off surface in a lower universe.") - 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 in coincident with a mesh boundary - - if (active_current_tallies % size() > 0) then - 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 - end if - - ! Copy particle's direction cosines - u = p % coord(1) % uvw(1) - v = p % coord(1) % uvw(2) - w = p % coord(1) % uvw(3) - - select case (surf%type) - case (SURF_PX) - u = -u - - case (SURF_PY) - v = -v - - case (SURF_PZ) - w = -w - - case (SURF_PLANE) - ! Find surface coefficients and norm of vector normal to surface - n1 = surf % coeffs(1) - n2 = surf % coeffs(2) - n3 = surf % coeffs(3) - norm = n1*n1 + n2*n2 + n3*n3 - dot_prod = u*n1 + v*n2 + w*n3 - - ! Reflect direction according to normal - u = u - 2*dot_prod*n1/norm - v = v - 2*dot_prod*n2/norm - w = w - 2*dot_prod*n3/norm - - case (SURF_CYL_X) - ! Find y-y0, z-z0 and dot product of direction and surface normal - y = p % coord(1) % xyz(2) - surf % coeffs(1) - z = p % coord(1) % xyz(3) - surf % coeffs(2) - R = surf % coeffs(3) - dot_prod = v*y + w*z - - ! Reflect direction according to normal - v = v - 2*dot_prod*y/(R*R) - w = w - 2*dot_prod*z/(R*R) - - case (SURF_CYL_Y) - ! Find x-x0, z-z0 and dot product of direction and surface normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - z = p % coord(1) % xyz(3) - surf % coeffs(2) - R = surf % coeffs(3) - dot_prod = u*x + w*z - - ! Reflect direction according to normal - u = u - 2*dot_prod*x/(R*R) - w = w - 2*dot_prod*z/(R*R) - - case (SURF_CYL_Z) - ! Find x-x0, y-y0 and dot product of direction and surface normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - y = p % coord(1) % xyz(2) - surf % coeffs(2) - R = surf % coeffs(3) - dot_prod = u*x + v*y - - ! Reflect direction according to normal - u = u - 2*dot_prod*x/(R*R) - v = v - 2*dot_prod*y/(R*R) - - case (SURF_SPHERE) - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface - ! normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - y = p % coord(1) % xyz(2) - surf % coeffs(2) - z = p % coord(1) % xyz(3) - surf % coeffs(3) - R = surf % coeffs(4) - dot_prod = u*x + v*y + w*z - - ! Reflect direction according to normal - u = u - 2*dot_prod*x/(R*R) - v = v - 2*dot_prod*y/(R*R) - w = w - 2*dot_prod*z/(R*R) - - case (SURF_CONE_X) - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface - ! normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - y = p % coord(1) % xyz(2) - surf % coeffs(2) - z = p % coord(1) % xyz(3) - surf % coeffs(3) - R = surf % coeffs(4) - dot_prod = (v*y + w*z - R*u*x)/((R + ONE)*R*x*x) - - ! Reflect direction according to normal - u = u + 2*dot_prod*R*x - v = v - 2*dot_prod*y - w = w - 2*dot_prod*z - - case (SURF_CONE_Y) - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface - ! normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - y = p % coord(1) % xyz(2) - surf % coeffs(2) - z = p % coord(1) % xyz(3) - surf % coeffs(3) - R = surf % coeffs(4) - dot_prod = (u*x + w*z - R*v*y)/((R + ONE)*R*y*y) - - ! Reflect direction according to normal - u = u - 2*dot_prod*x - v = v + 2*dot_prod*R*y - w = w - 2*dot_prod*z - - case (SURF_CONE_Z) - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface - ! normal - x = p % coord(1) % xyz(1) - surf % coeffs(1) - y = p % coord(1) % xyz(2) - surf % coeffs(2) - z = p % coord(1) % xyz(3) - surf % coeffs(3) - R = surf % coeffs(4) - dot_prod = (u*x + v*y - R*w*z)/((R + ONE)*R*z*z) - - ! Reflect direction according to normal - u = u - 2*dot_prod*x - v = v - 2*dot_prod*y - w = w + 2*dot_prod*R*z - - case default - call fatal_error("Reflection not supported for surface " & - &// trim(to_str(surf % id))) - end select - - ! Set new particle direction - norm = sqrt(u*u + v*v + w*w) - p % coord(1) % uvw = [u, v, w] / norm - - ! Reassign particle's cell and surface - p % coord(1) % cell = last_cell - p % surface = -p % surface - - ! If a reflective surface is coincident with a lattice or universe - ! boundary, it is necessary to redetermine the particle's coordinates in - ! the lower universes. - - p % n_coord = 1 - call find_cell(p, found) - if (.not. found) then - call handle_lost_particle(p, "Couldn't find particle after reflecting& - & from surface.") - 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(" Reflected from surface " & - &// trim(to_str(surf%id))) - end if - return - end if - - ! ========================================================================== - ! SEARCH NEIGHBOR LISTS FOR NEXT CELL - - if (p % surface > 0 .and. allocated(surf % neighbor_pos)) then - ! If coming from negative side of surface, search all the neighboring - ! cells on the positive side - - call find_cell(p, found, surf % neighbor_pos) - if (found) return - - elseif (p % surface < 0 .and. allocated(surf % neighbor_neg)) then - ! If coming from positive side of surface, search all the neighboring - ! cells on the negative side - - call find_cell(p, found, surf % neighbor_neg) - if (found) return - - end if - - ! ========================================================================== - ! COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS - - ! Remove lower coordinate levels and assignment of surface - p % surface = NONE - p % n_coord = 1 - call find_cell(p, found) - - if (run_mode /= MODE_PLOTTING .and. (.not. found)) then - ! If a cell is still not found, there are two possible causes: 1) there is - ! a void in the model, and 2) the particle hit a surface at a tangent. If - ! the particle is really traveling tangent to a surface, if we move it - ! forward a tiny bit it should fix the problem. - - p % n_coord = 1 - p % coord(1) % xyz = p % coord(1) % xyz + TINY_BIT * p % coord(1) % uvw - call find_cell(p, found) - - ! Couldn't find next cell anywhere! This probably means there is an actual - ! undefined region in the geometry. - - if (.not. found) then - call handle_lost_particle(p, "After particle " // trim(to_str(p % id)) & - &// " crossed surface " // trim(to_str(surfaces(i_surface) % id)) & - &// " it could not be located in any cell and it did not leak.") - return - end if - end if - - end subroutine cross_surface - - subroutine cross_surface_new(p, last_cell) type(Particle), intent(inout) :: p integer, intent(in) :: last_cell ! last cell particle was in @@ -705,7 +423,7 @@ contains end if end if - end subroutine cross_surface_new + end subroutine cross_surface !=============================================================================== ! CROSS_LATTICE moves a particle into a new lattice element @@ -786,704 +504,6 @@ contains subroutine distance_to_boundary(p, dist, surface_crossed, lattice_translation, & next_level) - - type(Particle), intent(inout) :: p - real(8), intent(out) :: dist - integer, intent(out) :: surface_crossed - integer, intent(out) :: lattice_translation(3) - integer, intent(out) :: next_level - - integer :: i ! index for surface in cell - integer :: j - integer :: index_surf ! index in surfaces array (with sign) - integer :: i_xyz(3) ! lattice indices - integer :: level_surf_cross ! surface crossed on current level - integer :: level_lat_trans(3) ! lattice translation on current level - real(8) :: x,y,z ! particle coordinates - real(8) :: xyz_t(3) ! local particle coordinates - real(8) :: beta, gama ! skewed particle coordiantes - real(8) :: u,v,w ! particle directions - real(8) :: beta_dir ! skewed particle direction - real(8) :: gama_dir ! skewed particle direction - real(8) :: edge ! distance to oncoming edge - real(8) :: d ! evaluated distance - real(8) :: d_lat ! distance to lattice boundary - real(8) :: d_surf ! distance to surface - real(8) :: x0,y0,z0 ! coefficients for surface - real(8) :: r ! radius for quadratic surfaces - real(8) :: tmp ! dot product of surface normal with direction - real(8) :: a,b,c,k ! quadratic equation coefficients - real(8) :: quad ! discriminant of quadratic equation - logical :: on_surface ! is particle on surface? - type(Cell), pointer :: cl - type(Surface), pointer :: surf - class(Lattice), pointer :: lat - - ! inialize distance to infinity (huge) - dist = INFINITY - d_lat = INFINITY - d_surf = INFINITY - lattice_translation(:) = [0, 0, 0] - - next_level = 0 - - ! Loop over each universe level - LEVEL_LOOP: do j = 1, p % n_coord - - ! get pointer to cell on this level - cl => cells(p % coord(j) % cell) - - ! copy directional cosines - u = p % coord(j) % uvw(1) - v = p % coord(j) % uvw(2) - w = p % coord(j) % uvw(3) - - ! ======================================================================= - ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL - - SURFACE_LOOP: do i = 1, cl % n_surfaces - - ! copy local coordinates of particle - x = p % coord(j) % xyz(1) - y = p % coord(j) % xyz(2) - z = p % coord(j) % xyz(3) - - ! check for coincident surface -- note that we can't skip the - ! calculation in general because a particle could be on one side of a - ! cylinder and still have a positive distance to the other - - index_surf = cl % surfaces(i) - if (index_surf == p % surface) then - on_surface = .true. - else - on_surface = .false. - end if - - ! check for operators - index_surf = abs(index_surf) - if (index_surf >= OP_DIFFERENCE) cycle - - ! get pointer to surface - surf => surfaces(index_surf) - - ! TODO: Can probably combines a lot of the cases to reduce repetition - ! since the algorithm is the same for (x-plane, y-plane, z-plane), - ! (x-cylinder, y-cylinder, z-cylinder), etc. - - select case (surf % type) - case (SURF_PX) - if (on_surface .or. u == ZERO) then - d = INFINITY - else - x0 = surf % coeffs(1) - d = (x0 - x)/u - if (d < ZERO) d = INFINITY - end if - - case (SURF_PY) - if (on_surface .or. v == ZERO) then - d = INFINITY - else - y0 = surf % coeffs(1) - d = (y0 - y)/v - if (d < ZERO) d = INFINITY - end if - - case (SURF_PZ) - if (on_surface .or. w == ZERO) then - d = INFINITY - else - z0 = surf % coeffs(1) - d = (z0 - z)/w - if (d < ZERO) d = INFINITY - end if - - case (SURF_PLANE) - A = surf % coeffs(1) - B = surf % coeffs(2) - C = surf % coeffs(3) - D = surf % coeffs(4) - - tmp = A*u + B*v + C*w - if (on_surface .or. tmp == ZERO) then - d = INFINITY - else - d = -(A*x + B*y + C*z - D)/tmp - if (d < ZERO) d = INFINITY - end if - - case (SURF_CYL_X) - a = ONE - u*u ! v^2 + w^2 - if (a == ZERO) then - d = INFINITY - else - y0 = surf % coeffs(1) - z0 = surf % coeffs(2) - r = surf % coeffs(3) - - y = y - y0 - z = z - z0 - k = y*v + z*w - c = y*y + z*z - r*r - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cylinder - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cylinder, thus one distance is - ! positive/negative and the other is zero. The sign of k - ! determines if we are facing in or out - - if (k >= ZERO) then - d = INFINITY - else - d = (-k + sqrt(quad))/a - end if - - elseif (c < ZERO) then - ! particle is inside the cylinder, thus one distance must be - ! negative and one must be positive. The positive distance - ! will be the one with negative sign on sqrt(quad) - - d = (-k + sqrt(quad))/a - - else - ! particle is outside the cylinder, thus both distances are - ! either positive or negative. If positive, the smaller - ! distance is the one with positive sign on sqrt(quad) - - d = (-k - sqrt(quad))/a - if (d < ZERO) d = INFINITY - - end if - end if - - case (SURF_CYL_Y) - a = ONE - v*v ! u^2 + w^2 - if (a == ZERO) then - d = INFINITY - else - x0 = surf % coeffs(1) - z0 = surf % coeffs(2) - r = surf % coeffs(3) - - x = x - x0 - z = z - z0 - k = x*u + z*w - c = x*x + z*z - r*r - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cylinder - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cylinder, thus one distance is - ! positive/negative and the other is zero. The sign of k - ! determines if we are facing in or out - - if (k >= ZERO) then - d = INFINITY - else - d = (-k + sqrt(quad))/a - end if - - elseif (c < ZERO) then - ! particle is inside the cylinder, thus one distance must be - ! negative and one must be positive. The positive distance - ! will be the one with negative sign on sqrt(quad) - - d = (-k + sqrt(quad))/a - - else - ! particle is outside the cylinder, thus both distances are - ! either positive or negative. If positive, the smaller - ! distance is the one with positive sign on sqrt(quad) - - d = (-k - sqrt(quad))/a - if (d < ZERO) d = INFINITY - - end if - end if - - case (SURF_CYL_Z) - a = ONE - w*w ! u^2 + v^2 - if (a == ZERO) then - d = INFINITY - else - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - r = surf % coeffs(3) - - x = x - x0 - y = y - y0 - k = x*u + y*v - c = x*x + y*y - r*r - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cylinder - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cylinder, thus one distance is - ! positive/negative and the other is zero. The sign of k - ! determines if we are facing in or out - - if (k >= ZERO) then - d = INFINITY - else - d = (-k + sqrt(quad))/a - end if - - elseif (c < ZERO) then - ! particle is inside the cylinder, thus one distance must be - ! negative and one must be positive. The positive distance - ! will be the one with negative sign on sqrt(quad) - - d = (-k + sqrt(quad))/a - - else - ! particle is outside the cylinder, thus both distances are - ! either positive or negative. If positive, the smaller - ! distance is the one with positive sign on sqrt(quad) - - d = (-k - sqrt(quad))/a - if (d <= ZERO) d = INFINITY - - end if - end if - - case (SURF_SPHERE) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - - x = x - x0 - y = y - y0 - z = z - z0 - k = x*u + y*v + z*w - c = x*x + y*y + z*z - r*r - quad = k*k - c - - if (quad < ZERO) then - ! no intersection with sphere - - d = INFINITY - - elseif (on_surface) then - ! particle is on the sphere, thus one distance is - ! positive/negative and the other is zero. The sign of k - ! determines if we are facing in or out - - if (k >= ZERO) then - d = INFINITY - else - d = -k + sqrt(quad) - end if - - elseif (c < ZERO) then - ! particle is inside the sphere, thus one distance must be - ! negative and one must be positive. The positive distance will - ! be the one with negative sign on sqrt(quad) - - d = -k + sqrt(quad) - - else - ! particle is outside the sphere, thus both distances are either - ! positive or negative. If positive, the smaller distance is the - ! one with positive sign on sqrt(quad) - - d = -k - sqrt(quad) - if (d < ZERO) d = INFINITY - - end if - - case (SURF_CONE_X) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - - x = x - x0 - y = y - y0 - z = z - z0 - a = v*v + w*w - r*u*u - k = y*v + z*w - r*x*u - c = y*y + z*z - r*x*x - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cone - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cone, thus one distance is positive/negative - ! and the other is zero. The sign of k determines which distance is - ! zero and which is not. - - if (k >= ZERO) then - d = (-k - sqrt(quad))/a - else - d = (-k + sqrt(quad))/a - end if - - else - ! calculate both solutions to the quadratic - quad = sqrt(quad) - d = (-k - quad)/a - b = (-k + quad)/a - - ! determine the smallest positive solution - if (d < ZERO) then - if (b > ZERO) then - d = b - end if - else - if (b > ZERO) d = min(d, b) - end if - end if - - ! If the distance was negative, set boundary distance to infinity - if (d <= ZERO) d = INFINITY - - case (SURF_CONE_Y) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - - x = x - x0 - y = y - y0 - z = z - z0 - a = u*u + w*w - r*v*v - k = x*u + z*w - r*y*v - c = x*x + z*z - r*y*y - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cone - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cone, thus one distance is positive/negative - ! and the other is zero. The sign of k determines which distance is - ! zero and which is not. - - if (k >= ZERO) then - d = (-k - sqrt(quad))/a - else - d = (-k + sqrt(quad))/a - end if - - else - ! calculate both solutions to the quadratic - quad = sqrt(quad) - d = (-k - quad)/a - b = (-k + quad)/a - - ! determine the smallest positive solution - if (d < ZERO) then - if (b > ZERO) then - d = b - end if - else - if (b > ZERO) d = min(d, b) - end if - end if - - ! If the distance was negative, set boundary distance to infinity - if (d <= ZERO) d = INFINITY - - case (SURF_CONE_Z) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - - x = x - x0 - y = y - y0 - z = z - z0 - a = u*u + v*v - r*w*w - k = x*u + y*v - r*z*w - c = x*x + y*y - r*z*z - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with cone - - d = INFINITY - - elseif (on_surface) then - ! particle is on the cone, thus one distance is positive/negative - ! and the other is zero. The sign of k determines which distance is - ! zero and which is not. - - if (k >= ZERO) then - d = (-k - sqrt(quad))/a - else - d = (-k + sqrt(quad))/a - end if - - else - ! calculate both solutions to the quadratic - quad = sqrt(quad) - d = (-k - quad)/a - b = (-k + quad)/a - - ! determine the smallest positive solution - if (d < ZERO) then - if (b > ZERO) then - d = b - end if - else - if (b > ZERO) d = min(d, b) - end if - end if - - ! If the distance was negative, set boundary distance to infinity - if (d <= ZERO) d = INFINITY - - end select - - ! Check is calculated distance is new minimum - if (d < d_surf) then - if (abs(d - d_surf)/d_surf >= FP_PRECISION) then - d_surf = d - level_surf_cross = -cl % surfaces(i) - end if - end if - - end do SURFACE_LOOP - - ! ======================================================================= - ! FIND MINIMUM DISTANCE TO LATTICE SURFACES - - LAT_COORD: if (p % coord(j) % lattice /= NONE) then - lat => lattices(p % coord(j) % lattice) % obj - - LAT_TYPE: select type(lat) - - type is (RectLattice) - ! copy local coordinates - x = p % coord(j) % xyz(1) - y = p % coord(j) % xyz(2) - z = p % coord(j) % xyz(3) - - ! determine oncoming edge - x0 = sign(lat % pitch(1) * HALF, u) - y0 = sign(lat % pitch(2) * HALF, v) - - ! left and right sides - if (abs(x - x0) < FP_PRECISION) then - d = INFINITY - elseif (u == ZERO) then - d = INFINITY - else - d = (x0 - x)/u - end if - - d_lat = d - if (u > 0) then - level_lat_trans(:) = [1, 0, 0] - else - level_lat_trans(:) = [-1, 0, 0] - end if - - ! front and back sides - if (abs(y - y0) < FP_PRECISION) then - d = INFINITY - elseif (v == ZERO) then - d = INFINITY - else - d = (y0 - y)/v - end if - - if (d < d_lat) then - d_lat = d - if (v > 0) then - level_lat_trans(:) = [0, 1, 0] - else - level_lat_trans(:) = [0, -1, 0] - end if - end if - - if (lat % is_3d) then - z0 = sign(lat % pitch(3) * HALF, w) - - ! top and bottom sides - if (abs(z - z0) < FP_PRECISION) then - d = INFINITY - elseif (w == ZERO) then - d = INFINITY - else - d = (z0 - z)/w - end if - - if (d < d_lat) then - d_lat = d - if (w > 0) then - level_lat_trans(:) = [0, 0, 1] - else - level_lat_trans(:) = [0, 0, -1] - end if - end if - end if - - type is (HexLattice) LAT_TYPE - ! Copy local coordinates. - z = p % coord(j) % xyz(3) - i_xyz(1) = p % coord(j) % lattice_x - i_xyz(2) = p % coord(j) % lattice_y - i_xyz(3) = p % coord(j) % lattice_z - - ! Compute velocities along the hexagonal axes. - beta_dir = u*sqrt(THREE)/TWO + v/TWO - gama_dir = u*sqrt(THREE)/TWO - v/TWO - - ! Note that hexagonal lattice distance calculations are performed - ! using the particle's coordinates relative to the neighbor lattice - ! cells, not relative to the particle's current cell. This is done - ! because there is significant disagreement between neighboring cells - ! on where the lattice boundary is due to the worse finite precision - ! of hex lattices. - - ! Upper right and lower left sides. - edge = -sign(lat % pitch(1)/TWO, beta_dir) ! Oncoming edge - if (beta_dir > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, 0, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 0, 0]) - end if - beta = xyz_t(1)*sqrt(THREE)/TWO + xyz_t(2)/TWO - if (abs(beta - edge) < FP_PRECISION) then - d = INFINITY - else if (beta_dir == ZERO) then - d = INFINITY - else - d = (edge - beta)/beta_dir - end if - - d_lat = d - if (beta_dir > 0) then - level_lat_trans(:) = [1, 0, 0] - else - level_lat_trans(:) = [-1, 0, 0] - end if - - ! Lower right and upper left sides. - edge = -sign(lat % pitch(1)/TWO, gama_dir) ! Oncoming edge - if (gama_dir > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, -1, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 1, 0]) - end if - gama = xyz_t(1)*sqrt(THREE)/TWO - xyz_t(2)/TWO - if (abs(gama - edge) < FP_PRECISION) then - d = INFINITY - else if (gama_dir == ZERO) then - d = INFINITY - else - d = (edge - gama)/gama_dir - end if - - if (d < d_lat) then - d_lat = d - if (gama_dir > 0) then - level_lat_trans(:) = [1, -1, 0] - else - level_lat_trans(:) = [-1, 1, 0] - end if - end if - - ! Upper and lower sides. - edge = -sign(lat % pitch(1)/TWO, v) ! Oncoming edge - if (v > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, 1, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, -1, 0]) - end if - if (abs(xyz_t(2) - edge) < FP_PRECISION) then - d = INFINITY - else if (v == ZERO) then - d = INFINITY - else - d = (edge - xyz_t(2))/v - end if - - if (d < d_lat) then - d_lat = d - if (v > 0) then - level_lat_trans(:) = [0, 1, 0] - else - level_lat_trans(:) = [0, -1, 0] - end if - end if - - ! Top and bottom sides. - if (lat % is_3d) then - z0 = sign(lat % pitch(2) * HALF, w) - - if (abs(z - z0) < FP_PRECISION) then - d = INFINITY - elseif (w == ZERO) then - d = INFINITY - else - d = (z0 - z)/w - end if - - if (d < d_lat) then - d_lat = d - if (w > 0) then - level_lat_trans(:) = [0, 0, 1] - else - level_lat_trans(:) = [0, 0, -1] - end if - end if - end if - end select LAT_TYPE - - if (d_lat < ZERO) then - call handle_lost_particle(p, "Particle " // trim(to_str(p % id)) & - //" had a negative distance to a lattice boundary. d = " & - //trim(to_str(d_lat))) - end if - end if LAT_COORD - - ! If the boundary on this lattice level is coincident with a boundary on - ! a higher level then we need to make sure that the higher level boundary - ! is selected. This logic must include consideration of floating point - ! precision. - if (d_surf < d_lat) then - if ((dist - d_surf)/dist >= FP_REL_PRECISION) then - dist = d_surf - surface_crossed = level_surf_cross - lattice_translation(:) = [0, 0, 0] - next_level = j - end if - else - if ((dist - d_lat)/dist >= FP_REL_PRECISION) then - dist = d_lat - surface_crossed = None - lattice_translation(:) = level_lat_trans - next_level = j - end if - end if - - end do LEVEL_LOOP - - end subroutine distance_to_boundary - - subroutine distance_to_boundary_new(p, dist, surface_crossed, lattice_translation, & - next_level) type(Particle), intent(inout) :: p real(8), intent(out) :: dist integer, intent(out) :: surface_crossed @@ -1772,7 +792,7 @@ contains end do LEVEL_LOOP - end subroutine distance_to_boundary_new + end subroutine distance_to_boundary !=============================================================================== ! SENSE determines whether a point is on the 'positive' or 'negative' side of a @@ -1781,127 +801,6 @@ contains !=============================================================================== recursive function sense(p, surf) result(s) - - type(Particle), intent(inout) :: p - type(Surface), pointer :: surf ! surface - logical :: s ! sense of particle - - integer :: j - real(8) :: x,y,z ! coordinates of particle - real(8) :: func ! surface function evaluated at point - real(8) :: A ! coefficient on x for plane - real(8) :: B ! coefficient on y for plane - real(8) :: C ! coefficient on z for plane - real(8) :: D ! coefficient for plane - real(8) :: x0,y0,z0 ! coefficients for quadratic surfaces / box - real(8) :: r ! radius for quadratic surfaces - - j = p % n_coord - x = p % coord(j) % xyz(1) - y = p % coord(j) % xyz(2) - z = p % coord(j) % xyz(3) - - select case (surf % type) - case (SURF_PX) - x0 = surf % coeffs(1) - func = x - x0 - - case (SURF_PY) - y0 = surf % coeffs(1) - func = y - y0 - - case (SURF_PZ) - z0 = surf % coeffs(1) - func = z - z0 - - case (SURF_PLANE) - A = surf % coeffs(1) - B = surf % coeffs(2) - C = surf % coeffs(3) - D = surf % coeffs(4) - func = A*x + B*y + C*z - D - - case (SURF_CYL_X) - y0 = surf % coeffs(1) - z0 = surf % coeffs(2) - r = surf % coeffs(3) - y = y - y0 - z = z - z0 - func = y*y + z*z - r*r - - case (SURF_CYL_Y) - x0 = surf % coeffs(1) - z0 = surf % coeffs(2) - r = surf % coeffs(3) - x = x - x0 - z = z - z0 - func = x*x + z*z - r*r - - case (SURF_CYL_Z) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - r = surf % coeffs(3) - x = x - x0 - y = y - y0 - func = x*x + y*y - r*r - - case (SURF_SPHERE) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - x = x - x0 - y = y - y0 - z = z - z0 - func = x*x + y*y + z*z - r*r - - case (SURF_CONE_X) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - x = x - x0 - y = y - y0 - z = z - z0 - func = y*y + z*z - r*x*x - - case (SURF_CONE_Y) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - x = x - x0 - y = y - y0 - z = z - z0 - func = x*x + z*z - r*y*y - - case (SURF_CONE_Z) - x0 = surf % coeffs(1) - y0 = surf % coeffs(2) - z0 = surf % coeffs(3) - r = surf % coeffs(4) - x = x - x0 - y = y - y0 - z = z - z0 - func = x*x + y*y - r*z*z - - end select - - ! Check which side of surface the point is on - if (abs(func) < FP_COINCIDENT) then - ! Particle may be coincident with this surface. Artifically move the - ! particle forward a tiny bit. - p % coord(j) % xyz = p % coord(j) % xyz + TINY_BIT * p % coord(j) % uvw - s = sense(p, surf) - elseif (func > 0) then - s = .true. - else - s = .false. - end if - - end function sense - - recursive function sense_new(p, surf) result(s) type(Particle), intent(inout) :: p class(Surface2), intent(in) :: surf ! surface logical :: s ! sense of particle @@ -1920,14 +819,14 @@ contains ! Particle may be coincident with this surface. Artifically move the ! particle forward a tiny bit. p%coord(j)%xyz = p%coord(j)%xyz + TINY_BIT * p%coord(j)%uvw - s = sense_new(p, surf) + s = sense(p, surf) elseif (func > 0) then s = .true. else s = .false. end if - end function sense_new + end function sense !=============================================================================== ! NEIGHBOR_LISTS builds a list of neighboring cells to each surface to speed up diff --git a/src/tracking.F90 b/src/tracking.F90 index 3669a61e85..81f01b4110 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -3,7 +3,7 @@ module tracking use constants, only: MODE_EIGENVALUE use cross_section, only: calculate_xs use error, only: fatal_error, warning - use geometry, only: find_cell, distance_to_boundary_new, cross_surface_new, & + use geometry, only: find_cell, distance_to_boundary, cross_surface, & cross_lattice, check_cell_overlap use geometry_header, only: Universe, BASE_UNIVERSE use global @@ -86,7 +86,7 @@ contains if (p % material /= p % last_material) call calculate_xs(p) ! Find the distance to the nearest boundary - call distance_to_boundary_new(p, d_boundary, surface_crossed, & + call distance_to_boundary(p, d_boundary, surface_crossed, & lattice_translation, next_level) ! Sample a distance to collision @@ -129,7 +129,7 @@ contains else ! Particle crosses surface p % surface = surface_crossed - call cross_surface_new(p, last_cell) + call cross_surface(p, last_cell) p % event = EVENT_SURFACE end if else From 7a8d32c2e9042ec2b4b420477345d9891ec7ce97 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 08:48:07 +0700 Subject: [PATCH 08/48] Remove Surface type and old surfaces array --- src/geometry.F90 | 11 +---- src/geometry_header.F90 | 16 ------- src/global.F90 | 5 +-- src/input_xml.F90 | 73 ++++++++++++-------------------- src/output.F90 | 14 +++---- src/summary.F90 | 92 ++++++++++++++++++++++++++++------------- src/surface_header.F90 | 6 +++ 7 files changed, 105 insertions(+), 112 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index c9f4927f29..944ca6a8d2 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -2,7 +2,7 @@ module geometry use constants use error, only: fatal_error, warning - use geometry_header, only: Cell, Surface, Universe, Lattice, & + use geometry_header, only: Cell, Universe, Lattice, & &RectLattice, HexLattice use global use output, only: write_message @@ -841,8 +841,7 @@ contains integer, allocatable :: count_positive(:) ! # of cells on positive side integer, allocatable :: count_negative(:) ! # of cells on negative side logical :: positive ! positive side specified in surface list - type(Cell), pointer :: c - type(Surface), pointer :: surf + type(Cell), pointer :: c call write_message("Building neighboring cells lists for each surface...", & &4) @@ -870,13 +869,10 @@ contains ! allocate neighbor lists for each surface do i = 1, n_surfaces - surf => surfaces(i) if (count_positive(i) > 0) then - allocate(surf%neighbor_pos(count_positive(i))) allocate(surfaces_c(i)%obj%neighbor_pos(count_positive(i))) end if if (count_negative(i) > 0) then - allocate(surf%neighbor_neg(count_negative(i))) allocate(surfaces_c(i)%obj%neighbor_neg(count_negative(i))) end if end do @@ -894,14 +890,11 @@ contains positive = (i_surface > 0) i_surface = abs(i_surface) - surf => surfaces(i_surface) if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 - surf%neighbor_pos(count_positive(i_surface)) = i surfaces_c(i_surface)%obj%neighbor_pos(count_positive(i_surface)) = i else count_negative(i_surface) = count_negative(i_surface) + 1 - surf%neighbor_neg(count_negative(i_surface)) = i surfaces_c(i_surface)%obj%neighbor_neg(count_negative(i_surface)) = i end if end do diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 93e5dd1fdb..13d806e8cf 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -113,22 +113,6 @@ module geometry_header class(Lattice), allocatable :: obj end type LatticeContainer -!=============================================================================== -! SURFACE type defines a first- or second-order surface that can be used to -! construct closed volumes (cells) -!=============================================================================== - - type Surface - integer :: id ! Unique ID - character(len=52) :: name = "" ! User-defined name - integer :: type ! Type of surface - real(8), allocatable :: coeffs(:) ! Definition of surface - integer, allocatable :: & - neighbor_pos(:), & ! List of cells on positive side - neighbor_neg(:) ! List of cells on negative side - integer :: bc ! Boundary condition - end type Surface - !=============================================================================== ! CELL defines a closed volume by its bounding surfaces !=============================================================================== diff --git a/src/global.F90 b/src/global.F90 index 246fa3f3ae..44e470005b 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -6,7 +6,7 @@ module global use cmfd_header use constants use dict_header, only: DictCharInt, DictIntInt - use geometry_header, only: Cell, Universe, Lattice, LatticeContainer, Surface + use geometry_header, only: Cell, Universe, Lattice, LatticeContainer use material_header, only: Material use mesh_header, only: RegularMesh use plot_header, only: ObjectPlot @@ -31,7 +31,6 @@ module global type(Cell), allocatable, target :: cells(:) type(Universe), allocatable, target :: universes(:) type(LatticeContainer), allocatable, target :: lattices(:) - type(Surface), allocatable, target :: surfaces(:) type(SurfaceContainer), allocatable, target :: surfaces_c(:) type(Material), allocatable, target :: materials(:) type(ObjectPlot), allocatable, target :: plots(:) @@ -420,7 +419,7 @@ contains if (allocated(cells)) deallocate(cells) if (allocated(universes)) deallocate(universes) if (allocated(lattices)) deallocate(lattices) - if (allocated(surfaces)) deallocate(surfaces) + if (allocated(surfaces_c)) deallocate(surfaces_c) if (allocated(materials)) deallocate(materials) if (allocated(plots)) deallocate(plots) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 57769d33ac..ed9ae67c7b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -5,7 +5,7 @@ module input_xml use dict_header, only: DictIntInt, ElemKeyValueCI use energy_grid, only: grid_method, n_log_bins use error, only: fatal_error, warning - use geometry_header, only: Cell, Surface, Lattice, RectLattice, HexLattice + use geometry_header, only: Cell, Lattice, RectLattice, HexLattice use global use list_header, only: ListChar, ListReal use mesh_header, only: RegularMesh @@ -994,7 +994,6 @@ contains character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word type(Cell), pointer :: c - type(Surface), pointer :: s class(Lattice), pointer :: lat type(Node), pointer :: doc => null() type(Node), pointer :: node_cell => null() @@ -1221,86 +1220,71 @@ contains end if ! Allocate cells array - allocate(surfaces(n_surfaces)) allocate(surfaces_c(n_surfaces)) do i = 1, n_surfaces - s => surfaces(i) - ! Get pointer to i-th surface node call get_list_item(node_surf_list, i, node_surf) - ! Copy data into cells - if (check_for_node(node_surf, "id")) then - call get_node_value(node_surf, "id", s % id) - else - call fatal_error("Must specify id of surface in geometry XML file.") - end if - - ! Check to make sure 'id' hasn't been used - if (surface_dict % has_key(s % id)) then - call fatal_error("Two or more surfaces use the same unique ID: " & - &// to_str(s % id)) - end if - - ! Copy surface name - if (check_for_node(node_surf, "name")) then - call get_node_value(node_surf, "name", s % name) - end if - ! Copy and interpret surface type word = '' if (check_for_node(node_surf, "type")) & call get_node_value(node_surf, "type", word) select case(to_lower(word)) case ('x-plane') - s % type = SURF_PX coeffs_reqd = 1 allocate(SurfaceXPlane :: surfaces_c(i)%obj) case ('y-plane') - s % type = SURF_PY coeffs_reqd = 1 allocate(SurfaceYPlane :: surfaces_c(i)%obj) case ('z-plane') - s % type = SURF_PZ coeffs_reqd = 1 allocate(SurfaceZPlane :: surfaces_c(i)%obj) case ('plane') - s % type = SURF_PLANE coeffs_reqd = 4 allocate(SurfacePlane :: surfaces_c(i)%obj) case ('x-cylinder') - s % type = SURF_CYL_X coeffs_reqd = 3 allocate(SurfaceXCylinder :: surfaces_c(i)%obj) case ('y-cylinder') - s % type = SURF_CYL_Y coeffs_reqd = 3 allocate(SurfaceYCylinder :: surfaces_c(i)%obj) case ('z-cylinder') - s % type = SURF_CYL_Z coeffs_reqd = 3 allocate(SurfaceZCylinder :: surfaces_c(i)%obj) case ('sphere') - s % type = SURF_SPHERE coeffs_reqd = 4 allocate(SurfaceSphere :: surfaces_c(i)%obj) case ('x-cone') - s % type = SURF_CONE_X coeffs_reqd = 4 allocate(SurfaceXCone :: surfaces_c(i)%obj) case ('y-cone') - s % type = SURF_CONE_Y coeffs_reqd = 4 allocate(SurfaceYCone :: surfaces_c(i)%obj) case ('z-cone') - s % type = SURF_CONE_Z coeffs_reqd = 4 allocate(SurfaceZCone :: surfaces_c(i)%obj) case default call fatal_error("Invalid surface type: " // trim(word)) end select - surfaces_c(i)%obj%id = s%id + + ! Copy data into cells + if (check_for_node(node_surf, "id")) then + call get_node_value(node_surf, "id", surfaces_c(i)%obj%id) + else + call fatal_error("Must specify id of surface in geometry XML file.") + end if + + ! Check to make sure 'id' hasn't been used + if (surface_dict % has_key(surfaces_c(i)%obj%id)) then + call fatal_error("Two or more surfaces use the same unique ID: " & + &// to_str(surfaces_c(i)%obj%id)) + end if + + ! Copy surface name + if (check_for_node(node_surf, "name")) then + call get_node_value(node_surf, "name", surfaces_c(i)%obj%name) + end if ! Check to make sure that the proper number of coefficients ! have been specified for the given type of surface. Then copy @@ -1309,16 +1293,14 @@ contains n = get_arraysize_double(node_surf, "coeffs") if (n < coeffs_reqd) then call fatal_error("Not enough coefficients specified for surface: " & - &// trim(to_str(s % id))) + &// trim(to_str(surfaces_c(i)%obj%id))) elseif (n > coeffs_reqd) then call fatal_error("Too many coefficients specified for surface: " & - &// trim(to_str(s % id))) + &// trim(to_str(surfaces_c(i)%obj%id))) end if allocate(coeffs(n)) - allocate(s%coeffs(n)) call get_node_array(node_surf, "coeffs", coeffs) - s%coeffs(:) = coeffs(:) select type(sp => surfaces_c(i)%obj) type is (SurfaceXPlane) @@ -1375,23 +1357,20 @@ contains call get_node_value(node_surf, "boundary", word) select case (to_lower(word)) case ('transmission', 'transmit', '') - s % bc = BC_TRANSMIT + surfaces_c(i)%obj%bc = BC_TRANSMIT case ('vacuum') - s % bc = BC_VACUUM + surfaces_c(i)%obj%bc = BC_VACUUM boundary_exists = .true. case ('reflective', 'reflect', 'reflecting') - s % bc = BC_REFLECT + surfaces_c(i)%obj%bc = BC_REFLECT boundary_exists = .true. case default call fatal_error("Unknown boundary condition '" // trim(word) // & - &"' specified on surface " // trim(to_str(s % id))) + &"' specified on surface " // trim(to_str(surfaces_c(i)%obj%id))) end select - surfaces_c(i)%obj%bc = s%bc - ! Add surface to dictionary - call surface_dict % add_key(s % id, i) - + call surface_dict % add_key(surfaces_c(i)%obj%id, i) end do ! Check to make sure a boundary condition was applied to at least one diff --git a/src/output.F90 b/src/output.F90 index 1a841a777a..5e1d7120b0 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -6,7 +6,7 @@ module output use constants use endf, only: reaction_name use error, only: fatal_error, warning - use geometry_header, only: Cell, Universe, Surface, Lattice, RectLattice, & + use geometry_header, only: Cell, Universe, Lattice, RectLattice, & HexLattice, BASE_UNIVERSE use global use math, only: t_percentile @@ -254,10 +254,9 @@ contains type(Particle), intent(in) :: p integer :: i ! index for coordinate levels - type(Cell), pointer :: c => null() - type(Surface), pointer :: s => null() - type(Universe), pointer :: u => null() - class(Lattice), pointer :: l => null() + type(Cell), pointer :: c + type(Universe), pointer :: u + class(Lattice), pointer :: l ! display type of particle select case (p % type) @@ -304,8 +303,7 @@ contains ! Print surface if (p % surface /= NONE) then - s => surfaces(abs(p % surface)) - write(ou,*) ' Surface = ' // to_str(sign(s % id, p % surface)) + write(ou,*) ' Surface = ' // to_str(sign(surfaces_c(i)%obj%id, p % surface)) end if ! Display weight, energy, grid index, and interpolation factor @@ -1385,7 +1383,7 @@ contains univ, bin-1, offset, label) case (FILTER_SURFACE) i = t % filters(i_filter) % int_bins(bin) - label = to_str(surfaces(i) % id) + label = to_str(surfaces_c(i)%obj%id) case (FILTER_MESH) m => meshes(t % filters(i_filter) % int_bins(1)) allocate(ijk(m % n_dimension)) diff --git a/src/summary.F90 b/src/summary.F90 index b93bf120c6..ad5a3c8b95 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -3,13 +3,14 @@ module summary use ace_header, only: Reaction, UrrData, Nuclide use constants use endf, only: reaction_name - use geometry_header, only: Cell, Surface, Universe, Lattice, RectLattice, & + use geometry_header, only: Cell, Universe, Lattice, RectLattice, & &HexLattice use global use hdf5_interface use material_header, only: Material use mesh_header, only: RegularMesh use output, only: time_stamp + use surface_header use string, only: to_str use tally_header, only: TallyObject @@ -112,8 +113,9 @@ contains integer(HID_T) :: surfaces_group, surface_group integer(HID_T) :: universes_group, univ_group integer(HID_T) :: lattices_group, lattice_group + real(8), allocatable :: coeffs(:) type(Cell), pointer :: c - type(Surface), pointer :: s + class(Surface2), pointer :: s type(Universe), pointer :: u class(Lattice), pointer :: lat @@ -178,7 +180,7 @@ contains allocate(surface_ids(c%n_surfaces)) do j = 1, c%n_surfaces k = c%surfaces(j) - surface_ids(j) = sign(surfaces(abs(k))%id, k) + surface_ids(j) = sign(surfaces_c(abs(k))%obj%id, k) end do call write_dataset(cell_group, "surfaces", surface_ids) deallocate(surface_ids) @@ -197,7 +199,7 @@ contains ! Write information on each surface SURFACE_LOOP: do i = 1, n_surfaces - s => surfaces(i) + s => surfaces_c(i)%obj surface_group = create_group(surfaces_group, "surface " // & trim(to_str(s%id))) @@ -208,33 +210,65 @@ contains call write_dataset(surface_group, "name", s%name) ! Write surface type - select case (s%type) - case (SURF_PX) + select type (s) + type is (SurfaceXPlane) call write_dataset(surface_group, "type", "x-plane") - case (SURF_PY) - call write_dataset(surface_group, "type", "y-plane") - case (SURF_PZ) - call write_dataset(surface_group, "type", "z-plane") - case (SURF_PLANE) - call write_dataset(surface_group, "type", "plane") - case (SURF_CYL_X) - call write_dataset(surface_group, "type", "x-cylinder") - case (SURF_CYL_Y) - call write_dataset(surface_group, "type", "y-cylinder") - case (SURF_CYL_Z) - call write_dataset(surface_group, "type", "z-cylinder") - case (SURF_SPHERE) - call write_dataset(surface_group, "type", "sphere") - case (SURF_CONE_X) - call write_dataset(surface_group, "type", "x-cone") - case (SURF_CONE_Y) - call write_dataset(surface_group, "type", "y-cone") - case (SURF_CONE_Z) - call write_dataset(surface_group, "type", "z-cone") - end select + allocate(coeffs(1)) + coeffs(1) = s%x0 - ! Write coefficients for surface - call write_dataset(surface_group, "coefficients", s%coeffs) + type is (SurfaceYPlane) + call write_dataset(surface_group, "type", "y-plane") + allocate(coeffs(1)) + coeffs(1) = s%y0 + + type is (SurfaceZPlane) + call write_dataset(surface_group, "type", "z-plane") + allocate(coeffs(1)) + coeffs(1) = s%z0 + + type is (SurfacePlane) + call write_dataset(surface_group, "type", "plane") + allocate(coeffs(4)) + coeffs(:) = [s%A, s%B, s%C, s%D] + + type is (SurfaceXCylinder) + call write_dataset(surface_group, "type", "x-cylinder") + allocate(coeffs(3)) + coeffs(:) = [s%y0, s%z0, s%r] + + type is (SurfaceYCylinder) + call write_dataset(surface_group, "type", "y-cylinder") + allocate(coeffs(3)) + coeffs(:) = [s%x0, s%z0, s%r] + + type is (SurfaceZCylinder) + call write_dataset(surface_group, "type", "z-cylinder") + allocate(coeffs(3)) + coeffs(:) = [s%x0, s%y0, s%r] + + type is (SurfaceSphere) + call write_dataset(surface_group, "type", "sphere") + allocate(coeffs(4)) + coeffs(:) = [s%x0, s%y0, s%z0, s%r] + + type is (SurfaceXCone) + call write_dataset(surface_group, "type", "x-cone") + allocate(coeffs(4)) + coeffs(:) = [s%x0, s%y0, s%z0, s%r2] + + type is (SurfaceYCone) + call write_dataset(surface_group, "type", "y-cone") + allocate(coeffs(4)) + coeffs(:) = [s%x0, s%y0, s%z0, s%r2] + + type is (SurfaceZCone) + call write_dataset(surface_group, "type", "z-cone") + allocate(coeffs(4)) + coeffs(:) = [s%x0, s%y0, s%z0, s%r2] + + end select + call write_dataset(surface_group, "coefficients", coeffs) + deallocate(coeffs) ! Write boundary condition select case (s%bc) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index c4a1a921f1..2f02278d9f 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -4,12 +4,18 @@ module surface_header implicit none +!=============================================================================== +! SURFACE type defines a first- or second-order surface that can be used to +! construct closed volumes (cells) +!=============================================================================== + type, abstract :: Surface2 integer :: id ! Unique ID integer, allocatable :: & neighbor_pos(:), & ! List of cells on positive side neighbor_neg(:) ! List of cells on negative side integer :: bc ! Boundary condition + character(len=52) :: name = "" ! User-defined name contains procedure(iEvaluate), deferred :: evaluate procedure(iDistance), deferred :: distance From 01c934be918680ffaa4f447099a6e09913c451b1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 09:21:08 +0700 Subject: [PATCH 09/48] Renamed Surface2 and surfaces_c to Surface and surfaces --- src/geometry.F90 | 20 +++---- src/global.F90 | 14 ++--- src/input_xml.F90 | 115 +++++++++++++++++++++-------------------- src/output.F90 | 4 +- src/summary.F90 | 6 +-- src/surface_header.F90 | 44 ++++++++-------- 6 files changed, 103 insertions(+), 100 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 944ca6a8d2..8639ede581 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -47,7 +47,7 @@ contains ! Determine the specified sense of the surface in the cell and the actual ! sense of the particle with respect to the surface - actual_sense = sense(p, surfaces_c(abs(i_surface))%obj) + actual_sense = sense(p, surfaces(abs(i_surface))%obj) specified_sense = (c % surfaces(i) > 0) ! Compare sense of point to specified sense @@ -278,10 +278,10 @@ contains real(8) :: norm ! "norm" of surface normal integer :: i_surface ! index in surfaces logical :: found ! particle found in universe? - class(Surface2), pointer :: surf + class(Surface), pointer :: surf i_surface = abs(p % surface) - surf => surfaces_c(i_surface)%obj + surf => surfaces(i_surface)%obj if (verbosity >= 10 .or. trace) then call write_message(" Crossing surface " // trim(to_str(surf % id))) end if @@ -529,7 +529,7 @@ contains real(8) :: x0,y0,z0 ! coefficients for surface logical :: coincident ! is particle on surface? type(Cell), pointer :: cl - class(Surface2), pointer :: surf + class(Surface), pointer :: surf class(Lattice), pointer :: lat ! inialize distance to infinity (huge) @@ -564,7 +564,7 @@ contains if (index_surf >= OP_DIFFERENCE) cycle ! Calculate distance to surface - surf => surfaces_c(index_surf)%obj + surf => surfaces(index_surf)%obj d = surf%distance(p%coord(j)%xyz, p%coord(j)%uvw, coincident) ! Check is calculated distance is new minimum @@ -802,7 +802,7 @@ contains recursive function sense(p, surf) result(s) type(Particle), intent(inout) :: p - class(Surface2), intent(in) :: surf ! surface + class(Surface), intent(in) :: surf ! surface logical :: s ! sense of particle integer :: j @@ -870,10 +870,10 @@ contains ! allocate neighbor lists for each surface do i = 1, n_surfaces if (count_positive(i) > 0) then - allocate(surfaces_c(i)%obj%neighbor_pos(count_positive(i))) + allocate(surfaces(i)%obj%neighbor_pos(count_positive(i))) end if if (count_negative(i) > 0) then - allocate(surfaces_c(i)%obj%neighbor_neg(count_negative(i))) + allocate(surfaces(i)%obj%neighbor_neg(count_negative(i))) end if end do @@ -892,10 +892,10 @@ contains if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 - surfaces_c(i_surface)%obj%neighbor_pos(count_positive(i_surface)) = i + surfaces(i_surface)%obj%neighbor_pos(count_positive(i_surface)) = i else count_negative(i_surface) = count_negative(i_surface) + 1 - surfaces_c(i_surface)%obj%neighbor_neg(count_negative(i_surface)) = i + surfaces(i_surface)%obj%neighbor_neg(count_negative(i_surface)) = i end if end do end do diff --git a/src/global.F90 b/src/global.F90 index 44e470005b..87d7278296 100644 --- a/src/global.F90 +++ b/src/global.F90 @@ -28,12 +28,12 @@ module global ! GEOMETRY-RELATED VARIABLES ! Main arrays - type(Cell), allocatable, target :: cells(:) - type(Universe), allocatable, target :: universes(:) - type(LatticeContainer), allocatable, target :: lattices(:) - type(SurfaceContainer), allocatable, target :: surfaces_c(:) - type(Material), allocatable, target :: materials(:) - type(ObjectPlot), allocatable, target :: plots(:) + type(Cell), allocatable, target :: cells(:) + type(Universe), allocatable, target :: universes(:) + type(LatticeContainer), allocatable, target :: lattices(:) + type(SurfaceContainer), allocatable, target :: surfaces(:) + type(Material), allocatable, target :: materials(:) + type(ObjectPlot), allocatable, target :: plots(:) ! Size of main arrays integer :: n_cells ! # of cells @@ -419,7 +419,7 @@ contains if (allocated(cells)) deallocate(cells) if (allocated(universes)) deallocate(universes) if (allocated(lattices)) deallocate(lattices) - if (allocated(surfaces_c)) deallocate(surfaces_c) + if (allocated(surfaces)) deallocate(surfaces) if (allocated(materials)) deallocate(materials) if (allocated(plots)) deallocate(plots) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index ed9ae67c7b..308bdc66b0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -994,6 +994,7 @@ contains character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word type(Cell), pointer :: c + class(Surface), pointer :: s class(Lattice), pointer :: lat type(Node), pointer :: doc => null() type(Node), pointer :: node_cell => null() @@ -1220,7 +1221,7 @@ contains end if ! Allocate cells array - allocate(surfaces_c(n_surfaces)) + allocate(surfaces(n_surfaces)) do i = 1, n_surfaces ! Get pointer to i-th surface node @@ -1233,57 +1234,59 @@ contains select case(to_lower(word)) case ('x-plane') coeffs_reqd = 1 - allocate(SurfaceXPlane :: surfaces_c(i)%obj) + allocate(SurfaceXPlane :: surfaces(i)%obj) case ('y-plane') coeffs_reqd = 1 - allocate(SurfaceYPlane :: surfaces_c(i)%obj) + allocate(SurfaceYPlane :: surfaces(i)%obj) case ('z-plane') coeffs_reqd = 1 - allocate(SurfaceZPlane :: surfaces_c(i)%obj) + allocate(SurfaceZPlane :: surfaces(i)%obj) case ('plane') coeffs_reqd = 4 - allocate(SurfacePlane :: surfaces_c(i)%obj) + allocate(SurfacePlane :: surfaces(i)%obj) case ('x-cylinder') coeffs_reqd = 3 - allocate(SurfaceXCylinder :: surfaces_c(i)%obj) + allocate(SurfaceXCylinder :: surfaces(i)%obj) case ('y-cylinder') coeffs_reqd = 3 - allocate(SurfaceYCylinder :: surfaces_c(i)%obj) + allocate(SurfaceYCylinder :: surfaces(i)%obj) case ('z-cylinder') coeffs_reqd = 3 - allocate(SurfaceZCylinder :: surfaces_c(i)%obj) + allocate(SurfaceZCylinder :: surfaces(i)%obj) case ('sphere') coeffs_reqd = 4 - allocate(SurfaceSphere :: surfaces_c(i)%obj) + allocate(SurfaceSphere :: surfaces(i)%obj) case ('x-cone') coeffs_reqd = 4 - allocate(SurfaceXCone :: surfaces_c(i)%obj) + allocate(SurfaceXCone :: surfaces(i)%obj) case ('y-cone') coeffs_reqd = 4 - allocate(SurfaceYCone :: surfaces_c(i)%obj) + allocate(SurfaceYCone :: surfaces(i)%obj) case ('z-cone') coeffs_reqd = 4 - allocate(SurfaceZCone :: surfaces_c(i)%obj) + allocate(SurfaceZCone :: surfaces(i)%obj) case default call fatal_error("Invalid surface type: " // trim(word)) end select + s => surfaces(i)%obj + ! Copy data into cells if (check_for_node(node_surf, "id")) then - call get_node_value(node_surf, "id", surfaces_c(i)%obj%id) + call get_node_value(node_surf, "id", s%id) else call fatal_error("Must specify id of surface in geometry XML file.") end if ! Check to make sure 'id' hasn't been used - if (surface_dict % has_key(surfaces_c(i)%obj%id)) then + if (surface_dict % has_key(s%id)) then call fatal_error("Two or more surfaces use the same unique ID: " & - &// to_str(surfaces_c(i)%obj%id)) + &// to_str(s%id)) end if ! Copy surface name if (check_for_node(node_surf, "name")) then - call get_node_value(node_surf, "name", surfaces_c(i)%obj%name) + call get_node_value(node_surf, "name", s%name) end if ! Check to make sure that the proper number of coefficients @@ -1293,59 +1296,59 @@ contains n = get_arraysize_double(node_surf, "coeffs") if (n < coeffs_reqd) then call fatal_error("Not enough coefficients specified for surface: " & - &// trim(to_str(surfaces_c(i)%obj%id))) + &// trim(to_str(s%id))) elseif (n > coeffs_reqd) then call fatal_error("Too many coefficients specified for surface: " & - &// trim(to_str(surfaces_c(i)%obj%id))) + &// trim(to_str(s%id))) end if allocate(coeffs(n)) call get_node_array(node_surf, "coeffs", coeffs) - select type(sp => surfaces_c(i)%obj) + select type(s) type is (SurfaceXPlane) - sp%x0 = coeffs(1) + s%x0 = coeffs(1) type is (SurfaceYPlane) - sp%y0 = coeffs(1) + s%y0 = coeffs(1) type is (SurfaceZPlane) - sp%z0 = coeffs(1) + s%z0 = coeffs(1) type is (SurfacePlane) - sp%A = coeffs(1) - sp%B = coeffs(2) - sp%C = coeffs(3) - sp%D = coeffs(4) + s%A = coeffs(1) + s%B = coeffs(2) + s%C = coeffs(3) + s%D = coeffs(4) type is (SurfaceXCylinder) - sp%y0 = coeffs(1) - sp%z0 = coeffs(2) - sp%r = coeffs(3) + s%y0 = coeffs(1) + s%z0 = coeffs(2) + s%r = coeffs(3) type is (SurfaceYCylinder) - sp%x0 = coeffs(1) - sp%z0 = coeffs(2) - sp%r = coeffs(3) + s%x0 = coeffs(1) + s%z0 = coeffs(2) + s%r = coeffs(3) type is (SurfaceZCylinder) - sp%x0 = coeffs(1) - sp%y0 = coeffs(2) - sp%r = coeffs(3) + s%x0 = coeffs(1) + s%y0 = coeffs(2) + s%r = coeffs(3) type is (SurfaceSphere) - sp%x0 = coeffs(1) - sp%y0 = coeffs(2) - sp%z0 = coeffs(3) - sp%r = coeffs(4) + s%x0 = coeffs(1) + s%y0 = coeffs(2) + s%z0 = coeffs(3) + s%r = coeffs(4) type is (SurfaceXCone) - sp%x0 = coeffs(1) - sp%y0 = coeffs(2) - sp%z0 = coeffs(3) - sp%r2 = coeffs(4) + s%x0 = coeffs(1) + s%y0 = coeffs(2) + s%z0 = coeffs(3) + s%r2 = coeffs(4) type is (SurfaceYCone) - sp%x0 = coeffs(1) - sp%y0 = coeffs(2) - sp%z0 = coeffs(3) - sp%r2 = coeffs(4) + s%x0 = coeffs(1) + s%y0 = coeffs(2) + s%z0 = coeffs(3) + s%r2 = coeffs(4) type is (SurfaceZCone) - sp%x0 = coeffs(1) - sp%y0 = coeffs(2) - sp%z0 = coeffs(3) - sp%r2 = coeffs(4) + s%x0 = coeffs(1) + s%y0 = coeffs(2) + s%z0 = coeffs(3) + s%r2 = coeffs(4) end select ! No longer need coefficients @@ -1357,20 +1360,20 @@ contains call get_node_value(node_surf, "boundary", word) select case (to_lower(word)) case ('transmission', 'transmit', '') - surfaces_c(i)%obj%bc = BC_TRANSMIT + s%bc = BC_TRANSMIT case ('vacuum') - surfaces_c(i)%obj%bc = BC_VACUUM + s%bc = BC_VACUUM boundary_exists = .true. case ('reflective', 'reflect', 'reflecting') - surfaces_c(i)%obj%bc = BC_REFLECT + s%bc = BC_REFLECT boundary_exists = .true. case default call fatal_error("Unknown boundary condition '" // trim(word) // & - &"' specified on surface " // trim(to_str(surfaces_c(i)%obj%id))) + &"' specified on surface " // trim(to_str(s%id))) end select ! Add surface to dictionary - call surface_dict % add_key(surfaces_c(i)%obj%id, i) + call surface_dict % add_key(s%id, i) end do ! Check to make sure a boundary condition was applied to at least one diff --git a/src/output.F90 b/src/output.F90 index 5e1d7120b0..c88f3bd79e 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -303,7 +303,7 @@ contains ! Print surface if (p % surface /= NONE) then - write(ou,*) ' Surface = ' // to_str(sign(surfaces_c(i)%obj%id, p % surface)) + write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%obj%id, p % surface)) end if ! Display weight, energy, grid index, and interpolation factor @@ -1383,7 +1383,7 @@ contains univ, bin-1, offset, label) case (FILTER_SURFACE) i = t % filters(i_filter) % int_bins(bin) - label = to_str(surfaces_c(i)%obj%id) + label = to_str(surfaces(i)%obj%id) case (FILTER_MESH) m => meshes(t % filters(i_filter) % int_bins(1)) allocate(ijk(m % n_dimension)) diff --git a/src/summary.F90 b/src/summary.F90 index ad5a3c8b95..587f00b6b7 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -115,7 +115,7 @@ contains integer(HID_T) :: lattices_group, lattice_group real(8), allocatable :: coeffs(:) type(Cell), pointer :: c - class(Surface2), pointer :: s + class(Surface), pointer :: s type(Universe), pointer :: u class(Lattice), pointer :: lat @@ -180,7 +180,7 @@ contains allocate(surface_ids(c%n_surfaces)) do j = 1, c%n_surfaces k = c%surfaces(j) - surface_ids(j) = sign(surfaces_c(abs(k))%obj%id, k) + surface_ids(j) = sign(surfaces(abs(k))%obj%id, k) end do call write_dataset(cell_group, "surfaces", surface_ids) deallocate(surface_ids) @@ -199,7 +199,7 @@ contains ! Write information on each surface SURFACE_LOOP: do i = 1, n_surfaces - s => surfaces_c(i)%obj + s => surfaces(i)%obj surface_group = create_group(surfaces_group, "surface " // & trim(to_str(s%id))) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 2f02278d9f..43b6c58322 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -9,7 +9,7 @@ module surface_header ! construct closed volumes (cells) !=============================================================================== - type, abstract :: Surface2 + type, abstract :: Surface integer :: id ! Unique ID integer, allocatable :: & neighbor_pos(:), & ! List of cells on positive side @@ -21,13 +21,13 @@ module surface_header procedure(iDistance), deferred :: distance procedure(iReflect), deferred :: reflect procedure(iNormal), deferred :: normal - end type Surface2 + end type Surface type :: SurfaceContainer - class(Surface2), allocatable :: obj + class(Surface), allocatable :: obj end type SurfaceContainer - type, extends(Surface2) :: SurfaceXPlane + type, extends(Surface) :: SurfaceXPlane ! x = x0 real(8) :: x0 contains @@ -37,7 +37,7 @@ module surface_header procedure :: normal => x_plane_normal end type SurfaceXPlane - type, extends(Surface2) :: SurfaceYPlane + type, extends(Surface) :: SurfaceYPlane ! y = y0 real(8) :: y0 contains @@ -47,7 +47,7 @@ module surface_header procedure :: normal => y_plane_normal end type SurfaceYPlane - type, extends(Surface2) :: SurfaceZPlane + type, extends(Surface) :: SurfaceZPlane ! z = z0 real(8) :: z0 contains @@ -57,7 +57,7 @@ module surface_header procedure :: normal => z_plane_normal end type SurfaceZPlane - type, extends(Surface2) :: SurfacePlane + type, extends(Surface) :: SurfacePlane ! Ax + By + Cz = D real(8) :: A real(8) :: B @@ -70,7 +70,7 @@ module surface_header procedure :: normal => plane_normal end type SurfacePlane - type, extends(Surface2) :: SurfaceXCylinder + type, extends(Surface) :: SurfaceXCylinder ! (y - y0)^2 + (z - z0)^2 = R^2 real(8) :: y0 real(8) :: z0 @@ -82,7 +82,7 @@ module surface_header procedure :: normal => x_cylinder_normal end type SurfaceXCylinder - type, extends(Surface2) :: SurfaceYCylinder + type, extends(Surface) :: SurfaceYCylinder ! (x - x0)^2 + (z - z0)^2 = R^2 real(8) :: x0 real(8) :: z0 @@ -94,7 +94,7 @@ module surface_header procedure :: normal => y_cylinder_normal end type SurfaceYCylinder - type, extends(Surface2) :: SurfaceZCylinder + type, extends(Surface) :: SurfaceZCylinder ! (x - x0)^2 + (y - y0)^2 = R^2 real(8) :: x0 real(8) :: y0 @@ -106,7 +106,7 @@ module surface_header procedure :: normal => z_cylinder_normal end type SurfaceZCylinder - type, extends(Surface2) :: SurfaceSphere + type, extends(Surface) :: SurfaceSphere ! (x - x0)^2 + (y - y0)^2 + (z - z0)^2 = R^2 real(8) :: x0 real(8) :: y0 @@ -119,7 +119,7 @@ module surface_header procedure :: normal => sphere_normal end type SurfaceSphere - type, extends(Surface2) :: SurfaceXCone + type, extends(Surface) :: SurfaceXCone ! (y - y0)^2 + (z - z0)^2 = R^2*(x - x0)^2 real(8) :: x0 real(8) :: y0 @@ -132,7 +132,7 @@ module surface_header procedure :: normal => x_cone_normal end type SurfaceXCone - type, extends(Surface2) :: SurfaceYCone + type, extends(Surface) :: SurfaceYCone ! (x - x0)^2 + (z - z0)^2 = R^2*(y - y0)^2 real(8) :: x0 real(8) :: y0 @@ -145,7 +145,7 @@ module surface_header procedure :: normal => y_cone_normal end type SurfaceYCone - type, extends(Surface2) :: SurfaceZCone + type, extends(Surface) :: SurfaceZCone ! (x - x0)^2 + (y - y0)^2 = R^2*(z - z0)^2 real(8) :: x0 real(8) :: y0 @@ -160,15 +160,15 @@ module surface_header abstract interface pure function iEvaluate(this, xyz) result(f) - import Surface2 - class(Surface2), intent(in) :: this + import Surface + class(Surface), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: f end function iEvaluate pure function iDistance(this, xyz, uvw, coincident) result(d) - import Surface2 - class(Surface2), intent(in) :: this + import Surface + class(Surface), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) logical, intent(in) :: coincident @@ -176,15 +176,15 @@ module surface_header end function iDistance subroutine iReflect(this, xyz, uvw) - import Surface2 - class(Surface2), intent(in) :: this + import Surface + class(Surface), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) end subroutine iReflect pure function iNormal(this, xyz) result(uvw) - import Surface2 - class(Surface2), intent(in) :: this + import Surface + class(Surface), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: uvw(3) end function iNormal From bdf929c5214ccd3eaedec55c3dd0b21da86e08e9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 09:35:06 +0700 Subject: [PATCH 10/48] Make sense() a bound procedure of type(Surface) --- src/geometry.F90 | 38 +++----------------------------------- src/surface_header.F90 | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 8639ede581..62afc3fb3b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -30,6 +30,7 @@ contains integer :: i_surface ! index in surfaces array (with sign) logical :: specified_sense ! specified sense of surface in list logical :: actual_sense ! sense of particle wrt surface + class(Surface), pointer :: s SURFACE_LOOP: do i = 1, c % n_surfaces ! Lookup surface @@ -47,7 +48,8 @@ contains ! Determine the specified sense of the surface in the cell and the actual ! sense of the particle with respect to the surface - actual_sense = sense(p, surfaces(abs(i_surface))%obj) + s => surfaces(abs(i_surface))%obj + actual_sense = s%sense(p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) specified_sense = (c % surfaces(i) > 0) ! Compare sense of point to specified sense @@ -794,40 +796,6 @@ contains end subroutine distance_to_boundary -!=============================================================================== -! SENSE determines whether a point is on the 'positive' or 'negative' side of a -! surface. This routine is crucial for determining what cell a particular point -! is in. -!=============================================================================== - - recursive function sense(p, surf) result(s) - type(Particle), intent(inout) :: p - class(Surface), intent(in) :: surf ! surface - logical :: s ! sense of particle - - integer :: j - real(8) :: func ! surface function evaluated at point - - j = p%n_coord - - ! Evaluate the surface equation at the particle's coordinates to determine - ! which side the particle is on - func = surf%evaluate(p%coord(j)%xyz) - - ! Check which side of surface the point is on - if (abs(func) < FP_COINCIDENT) then - ! Particle may be coincident with this surface. Artifically move the - ! particle forward a tiny bit. - p%coord(j)%xyz = p%coord(j)%xyz + TINY_BIT * p%coord(j)%uvw - s = sense(p, surf) - elseif (func > 0) then - s = .true. - else - s = .false. - end if - - end function sense - !=============================================================================== ! NEIGHBOR_LISTS builds a list of neighboring cells to each surface to speed up ! searches when a cell boundary is crossed. diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 43b6c58322..9ba0e0d01a 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -1,6 +1,6 @@ module surface_header - use constants, only: ONE, TWO, ZERO, INFINITY, FP_COINCIDENT + use constants, only: ONE, TWO, ZERO, INFINITY, FP_COINCIDENT, TINY_BIT implicit none @@ -17,6 +17,7 @@ module surface_header integer :: bc ! Boundary condition character(len=52) :: name = "" ! User-defined name contains + procedure :: sense procedure(iEvaluate), deferred :: evaluate procedure(iDistance), deferred :: distance procedure(iReflect), deferred :: reflect @@ -192,6 +193,38 @@ module surface_header contains +!=============================================================================== +! SENSE determines whether a point is on the 'positive' or 'negative' side of a +! surface. This routine is crucial for determining what cell a particular point +! is in. +!=============================================================================== + + recursive function sense(this, xyz, uvw) result(s) + class(Surface), intent(in) :: this ! surface + real(8), intent(inout) :: xyz(3) + real(8), intent(in) :: uvw(3) + logical :: s ! sense of particle + + real(8) :: f ! surface function evaluated at point + + ! Evaluate the surface equation at the particle's coordinates to determine + ! which side the particle is on + f = this%evaluate(xyz) + + ! Check which side of surface the point is on + if (abs(f) < FP_COINCIDENT) then + ! Particle may be coincident with this surface. Artifically move the + ! particle forward a tiny bit. + xyz(:) = xyz + TINY_BIT * uvw + s = this%sense(xyz, uvw) + elseif (f > 0) then + s = .true. + else + s = .false. + end if + + end function sense + !=============================================================================== ! SurfaceXPlane Implementation !=============================================================================== From cde3d7a00ad894aefe5e82f1e3a3c11da75c55b9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Sep 2015 21:26:22 +0700 Subject: [PATCH 11/48] Make reflect(...) a bound procedure of Surface directly. This obviates the need to have an implementation of reflect(...) for each surface. As long as the surface has a defined normal vector, it can be used to reflect a particle off the surface. --- src/surface_header.F90 | 213 ++---------------- tests/test_reflective_sphere/results_true.dat | 2 +- 2 files changed, 26 insertions(+), 189 deletions(-) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 9ba0e0d01a..402e028ea1 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -18,9 +18,9 @@ module surface_header character(len=52) :: name = "" ! User-defined name contains procedure :: sense + procedure :: reflect procedure(iEvaluate), deferred :: evaluate procedure(iDistance), deferred :: distance - procedure(iReflect), deferred :: reflect procedure(iNormal), deferred :: normal end type Surface @@ -33,7 +33,6 @@ module surface_header real(8) :: x0 contains procedure :: evaluate => x_plane_evaluate - procedure :: reflect => x_plane_reflect procedure :: distance => x_plane_distance procedure :: normal => x_plane_normal end type SurfaceXPlane @@ -43,7 +42,6 @@ module surface_header real(8) :: y0 contains procedure :: evaluate => y_plane_evaluate - procedure :: reflect => y_plane_reflect procedure :: distance => y_plane_distance procedure :: normal => y_plane_normal end type SurfaceYPlane @@ -53,7 +51,6 @@ module surface_header real(8) :: z0 contains procedure :: evaluate => z_plane_evaluate - procedure :: reflect => z_plane_reflect procedure :: distance => z_plane_distance procedure :: normal => z_plane_normal end type SurfaceZPlane @@ -66,7 +63,6 @@ module surface_header real(8) :: D contains procedure :: evaluate => plane_evaluate - procedure :: reflect => plane_reflect procedure :: distance => plane_distance procedure :: normal => plane_normal end type SurfacePlane @@ -78,7 +74,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => x_cylinder_evaluate - procedure :: reflect => x_cylinder_reflect procedure :: distance => x_cylinder_distance procedure :: normal => x_cylinder_normal end type SurfaceXCylinder @@ -90,7 +85,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => y_cylinder_evaluate - procedure :: reflect => y_cylinder_reflect procedure :: distance => y_cylinder_distance procedure :: normal => y_cylinder_normal end type SurfaceYCylinder @@ -102,7 +96,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => z_cylinder_evaluate - procedure :: reflect => z_cylinder_reflect procedure :: distance => z_cylinder_distance procedure :: normal => z_cylinder_normal end type SurfaceZCylinder @@ -115,7 +108,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => sphere_evaluate - procedure :: reflect => sphere_reflect procedure :: distance => sphere_distance procedure :: normal => sphere_normal end type SurfaceSphere @@ -128,7 +120,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => x_cone_evaluate - procedure :: reflect => x_cone_reflect procedure :: distance => x_cone_distance procedure :: normal => x_cone_normal end type SurfaceXCone @@ -141,7 +132,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => y_cone_evaluate - procedure :: reflect => y_cone_reflect procedure :: distance => y_cone_distance procedure :: normal => y_cone_normal end type SurfaceYCone @@ -154,7 +144,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => z_cone_evaluate - procedure :: reflect => z_cone_reflect procedure :: distance => z_cone_distance procedure :: normal => z_cone_normal end type SurfaceZCone @@ -176,13 +165,6 @@ module surface_header real(8) :: d end function iDistance - subroutine iReflect(this, xyz, uvw) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - end subroutine iReflect - pure function iNormal(this, xyz) result(uvw) import Surface class(Surface), intent(in) :: this @@ -225,6 +207,27 @@ contains end function sense + subroutine reflect(this, xyz, uvw) + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(inout) :: uvw(3) + + real(8) :: projection + real(8) :: magnitude + real(8) :: n(3) + + ! Construct normal vector + n(:) = this%normal(xyz) + + ! Determine projection of direction onto normal and squared magnitude of + ! normal + projection = n(1)*uvw(1) + n(2)*uvw(2) + n(3)*uvw(3) + magnitude = n(1)*n(1) + n(2)*n(2) + n(3)*n(3) + + ! Reflect direction according to normal + uvw(:) = uvw - TWO*projection/magnitude * n + end subroutine reflect + !=============================================================================== ! SurfaceXPlane Implementation !=============================================================================== @@ -255,20 +258,12 @@ contains end if end function x_plane_distance - subroutine x_plane_reflect(this, xyz, uvw) - class(SurfaceXPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - uvw(1) = -uvw(1) - end subroutine x_plane_reflect - pure function x_plane_normal(this, xyz) result(uvw) class(SurfaceXPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: uvw(3) - uvw(:) = [1, 0, 0] + uvw(:) = [ONE, ZERO, ZERO] end function x_plane_normal !=============================================================================== @@ -301,20 +296,12 @@ contains end if end function y_plane_distance - subroutine y_plane_reflect(this, xyz, uvw) - class(SurfaceYPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - uvw(2) = -uvw(2) - end subroutine y_plane_reflect - pure function y_plane_normal(this, xyz) result(uvw) class(SurfaceYPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: uvw(3) - uvw(:) = [0, 1, 0] + uvw(:) = [ZERO, ONE, ZERO] end function y_plane_normal !=============================================================================== @@ -349,20 +336,12 @@ contains end if end function z_plane_distance - subroutine z_plane_reflect(this, xyz, uvw) - class(SurfaceZPlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - uvw(3) = -uvw(3) - end subroutine z_plane_reflect - pure function z_plane_normal(this, xyz) result(uvw) class(SurfaceZPlane), intent(in) :: this real(8), intent(in) :: xyz(3) real(8) :: uvw(3) - uvw(:) = [0, 0, 1] + uvw(:) = [ZERO, ZERO, ONE] end function z_plane_normal !=============================================================================== @@ -397,20 +376,6 @@ contains end if end function plane_distance - subroutine plane_reflect(this, xyz, uvw) - class(SurfacePlane), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: n(3) - - ! Construct normal vector - n(:) = [this%A, this%B, this%C] - - ! Reflect direction according to normal - uvw = uvw - TWO*dot_product(n, uvw)/dot_product(n, n) * n - end subroutine plane_reflect - pure function plane_normal(this, xyz) result(uvw) class(SurfacePlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -489,23 +454,6 @@ contains end if end function x_cylinder_distance - subroutine x_cylinder_reflect(this, xyz, uvw) - class(SurfaceXCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: y, z, dot_prod - - ! Find y-y0, z-z0 and dot product of direction and surface normal - y = xyz(2) - this%y0 - z = xyz(3) - this%z0 - dot_prod = uvw(2)*y + uvw(3)*z - - ! Reflect direction according to normal - uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) - uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) - end subroutine x_cylinder_reflect - pure function x_cylinder_normal(this, xyz) result(uvw) class(SurfaceXCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -586,23 +534,6 @@ contains end if end function y_cylinder_distance - subroutine y_cylinder_reflect(this, xyz, uvw) - class(SurfaceYCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, z, dot_prod - - ! Find x-x0, z-z0 and dot product of direction and surface normal - x = xyz(1) - this%x0 - z = xyz(3) - this%z0 - dot_prod = uvw(1)*x + uvw(3)*z - - ! Reflect direction according to normal - uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) - uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) - end subroutine y_cylinder_reflect - pure function y_cylinder_normal(this, xyz) result(uvw) class(SurfaceYCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -683,23 +614,6 @@ contains end if end function z_cylinder_distance - subroutine z_cylinder_reflect(this, xyz, uvw) - class(SurfaceZCylinder), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, y, dot_prod - - ! Find x-x0, y-y0 and dot product of direction and surface normal - x = xyz(1) - this%x0 - y = xyz(2) - this%y0 - dot_prod = uvw(1)*x + uvw(2)*y - - ! Reflect direction according to normal - uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) - uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) - end subroutine z_cylinder_reflect - pure function z_cylinder_normal(this, xyz) result(uvw) class(SurfaceZCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -776,23 +690,6 @@ contains end if end function sphere_distance - subroutine sphere_reflect(this, xyz, uvw) - class(SurfaceSphere), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, y, z, dot_prod - - x = xyz(1) - this%x0 - y = xyz(2) - this%y0 - z = xyz(3) - this%z0 - dot_prod = uvw(1)*x + uvw(2)*y + uvw(3)*z - - uvw(1) = uvw(1) - TWO*dot_prod*x/(this%r*this%r) - uvw(2) = uvw(2) - TWO*dot_prod*y/(this%r*this%r) - uvw(3) = uvw(3) - TWO*dot_prod*z/(this%r*this%r) - end subroutine sphere_reflect - pure function sphere_normal(this, xyz) result(uvw) class(SurfaceSphere), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -871,26 +768,6 @@ contains if (d <= ZERO) d = INFINITY end function x_cone_distance - subroutine x_cone_reflect(this, xyz, uvw) - class(SurfaceXCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, y, z, r, dot_prod - - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal - x = xyz(1) - this%x0 - y = xyz(2) - this%y0 - z = xyz(3) - this%z0 - r = this%r2 - dot_prod = (uvw(2)*y + uvw(3)*z - r*uvw(1)*x)/((r + ONE)*r*x*x) - - ! Reflect direction according to normal - uvw(1) = uvw(1) + TWO*dot_prod*r*x - uvw(2) = uvw(2) - TWO*dot_prod*y - uvw(3) = uvw(3) - TWO*dot_prod*z - end subroutine x_cone_reflect - pure function x_cone_normal(this, xyz) result(uvw) class(SurfaceXCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -971,26 +848,6 @@ contains if (d <= ZERO) d = INFINITY end function y_cone_distance - subroutine y_cone_reflect(this, xyz, uvw) - class(SurfaceYCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, y, z, r, dot_prod - - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal - x = xyz(1) - this%x0 - y = xyz(2) - this%y0 - z = xyz(3) - this%z0 - r = this%r2 - dot_prod = (uvw(1)*x + uvw(3)*z - r*uvw(2)*y)/((r + ONE)*r*y*y) - - ! Reflect direction according to normal - uvw(1) = uvw(1) - TWO*dot_prod*x - uvw(2) = uvw(2) + TWO*dot_prod*r*y - uvw(3) = uvw(3) - TWO*dot_prod*z - end subroutine y_cone_reflect - pure function y_cone_normal(this, xyz) result(uvw) class(SurfaceYCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -1071,26 +928,6 @@ contains if (d <= ZERO) d = INFINITY end function z_cone_distance - subroutine z_cone_reflect(this, xyz, uvw) - class(SurfaceZCone), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(inout) :: uvw(3) - - real(8) :: x, y, z, r, dot_prod - - ! Find x-x0, y-y0, z-z0 and dot product of direction and surface normal - x = xyz(1) - this%x0 - y = xyz(2) - this%y0 - z = xyz(3) - this%z0 - r = this%r2 - dot_prod = (uvw(1)*x + uvw(2)*y - r*uvw(3)*z)/((r + ONE)*r*z*z) - - ! Reflect direction according to normal - uvw(1) = uvw(1) - TWO*dot_prod*x - uvw(2) = uvw(2) - TWO*dot_prod*y - uvw(3) = uvw(3) + TWO*dot_prod*r*z - end subroutine z_cone_reflect - pure function z_cone_normal(this, xyz) result(uvw) class(SurfaceZCone), intent(in) :: this real(8), intent(in) :: xyz(3) diff --git a/tests/test_reflective_sphere/results_true.dat b/tests/test_reflective_sphere/results_true.dat index f25a72dc95..91dd20fba8 100644 --- a/tests/test_reflective_sphere/results_true.dat +++ b/tests/test_reflective_sphere/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.271012E+00 3.466350E-03 +2.271012E+00 3.466351E-03 From dce591b037e8bd48dc2df907fad729595143d1a5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 12:56:13 +0700 Subject: [PATCH 12/48] Improve check for coincidence in sense(). The previous solution was to move the particle forward artificially and then call sense() recursively. A better way is to look at the projection of the particle's direction on the surface normal from which the sign determines which side the particle will be on when it moves forward. This enables us to make sense() a pure non-recursive function. --- src/surface_header.F90 | 22 ++++++++++------------ tests/test_plot_basis/results_true.dat | 2 +- tests/test_plot_mask/results_true.dat | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 402e028ea1..8941fed725 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -1,6 +1,6 @@ module surface_header - use constants, only: ONE, TWO, ZERO, INFINITY, FP_COINCIDENT, TINY_BIT + use constants, only: ONE, TWO, ZERO, INFINITY, FP_COINCIDENT implicit none @@ -178,12 +178,13 @@ contains !=============================================================================== ! SENSE determines whether a point is on the 'positive' or 'negative' side of a ! surface. This routine is crucial for determining what cell a particular point -! is in. +! is in. The positive side is indicated by a returned value of .true. and the +! negative side is indicated by a returned value of .false. !=============================================================================== - recursive function sense(this, xyz, uvw) result(s) + pure function sense(this, xyz, uvw) result(s) class(Surface), intent(in) :: this ! surface - real(8), intent(inout) :: xyz(3) + real(8), intent(in) :: xyz(3) real(8), intent(in) :: uvw(3) logical :: s ! sense of particle @@ -195,16 +196,13 @@ contains ! Check which side of surface the point is on if (abs(f) < FP_COINCIDENT) then - ! Particle may be coincident with this surface. Artifically move the - ! particle forward a tiny bit. - xyz(:) = xyz + TINY_BIT * uvw - s = this%sense(xyz, uvw) - elseif (f > 0) then - s = .true. + ! Particle may be coincident with this surface. To determine the sense, we + ! look at the direction of the particle relative to the surface normal (by + ! default in the positive direction) via their dot product. + s = (dot_product(uvw, this%normal(xyz)) > ZERO) else - s = .false. + s = (f > ZERO) end if - end function sense subroutine reflect(this, xyz, uvw) diff --git a/tests/test_plot_basis/results_true.dat b/tests/test_plot_basis/results_true.dat index ae588fd4f3..b1d5dc8534 100644 --- a/tests/test_plot_basis/results_true.dat +++ b/tests/test_plot_basis/results_true.dat @@ -1 +1 @@ -6a2400a95ea5baee432dd04a85252818d682004dc80b225b99c4bbc7cfd20d8523bd8e5df8a272df288cb2f300e5eee55f7ffa7b4d28ea64f92b78839ab0e86b \ No newline at end of file +368e0135c136d5c8a2dabb4c8085279dc7ac0bd81b2ec905bdf11ecb5fe99803868631cdff0b3ddec941323bcc661747d4c16edfd4f8d38582155bd6fd7e82e8 \ No newline at end of file diff --git a/tests/test_plot_mask/results_true.dat b/tests/test_plot_mask/results_true.dat index 1076324545..a1e323203d 100644 --- a/tests/test_plot_mask/results_true.dat +++ b/tests/test_plot_mask/results_true.dat @@ -1 +1 @@ -d888a734d6e69c5ca92457dc865c4defd8a1d8a1d4a01e0c8e7c528dde25d96df1283da37889dac0857329051958be2f2b491f2fd2bc22c8424a60ec6cda04bd \ No newline at end of file +a7cb65bf40c84c0540d45ff292c398f9ae51b3d9396e88b9b4e5cdf05e8730f409bddb53aec6d396058194c6293c5bd3ef39efd0b0f30f2423f696193c85176c \ No newline at end of file From 6e58fe8a0de23dca0dcdad4d75b552b7928b3d89 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 13:07:54 +0700 Subject: [PATCH 13/48] Added stl_vector module that mimics C++ std::vector --- src/stl_vector.F90 | 319 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 src/stl_vector.F90 diff --git a/src/stl_vector.F90 b/src/stl_vector.F90 new file mode 100644 index 0000000000..f5c11ff37f --- /dev/null +++ b/src/stl_vector.F90 @@ -0,0 +1,319 @@ +module stl_vector + + ! This module provides derived types that are meant to mimic the + ! std::vector type in C++ + + implicit none + private + + real(8), parameter :: GROWTH_FACTOR = 1.5 + + type, public :: VectorInt + integer, private :: size_ = 0 + integer, private :: capacity_ = 0 + integer, allocatable :: data(:) + contains + procedure :: capacity => capacity_int + procedure :: clear => clear_int + generic :: initialize => & + initialize_fill_int + procedure, private :: initialize_fill_int + procedure :: pop_back => pop_back_int + procedure :: push_back => push_back_int + procedure :: reserve => reserve_int + procedure :: resize => resize_int + procedure :: shrink_to_fit => shrink_to_fit_int + procedure :: size => size_int + end type VectorInt + + type, public :: VectorReal + integer, private :: size_ = 0 + integer, private :: capacity_ = 0 + real(8), allocatable :: data(:) + contains + procedure :: capacity => capacity_real + procedure :: clear => clear_real + generic :: initialize => & + initialize_fill_real + procedure, private :: initialize_fill_real + procedure :: pop_back => pop_back_real + procedure :: push_back => push_back_real + procedure :: reserve => reserve_real + procedure :: resize => resize_real + procedure :: shrink_to_fit => shrink_to_fit_real + procedure :: size => size_real + end type VectorReal + +contains + +!=============================================================================== +! Implementation of VectorInt +!=============================================================================== + + pure function capacity_int(this) result(capacity) + class(VectorInt), intent(in) :: this + integer :: capacity + + capacity = this%capacity_ + end function capacity_int + + subroutine clear_int(this) + class(VectorInt), intent(inout) :: this + + ! Since integer is trivially destructible, we only need to set size to zero + ! and can leave capacity as is + this%size_ = 0 + end subroutine clear_int + + subroutine initialize_fill_int(this, n, val) + class(VectorInt), intent(inout) :: this + integer, intent(in) :: n + integer, optional, intent(in) :: val + + integer :: val_ + + ! If no value given, fill the vector with zeros + if (present(val)) then + val_ = val + else + val_ = 0 + end if + + if (allocated(this%data)) deallocate(this%data) + + allocate(this%data(n), SOURCE=val_) + this%size_ = n + this%capacity_ = n + end subroutine initialize_fill_int + + subroutine pop_back_int(this) + class(VectorInt), intent(inout) :: this + if (this%size_ > 0) this%size_ = this%size_ - 1 + end subroutine pop_back_int + + subroutine push_back_int(this, val) + class(VectorInt), intent(inout) :: this + integer, intent(in) :: val + + integer :: capacity + integer, allocatable :: data(:) + + if (this%capacity_ == this%size_) then + ! Create new data array that is GROWTH_FACTOR larger. Note that + if (this%capacity_ == 0) then + capacity = 8 + else + capacity = int(GROWTH_FACTOR*this%capacity_) + end if + allocate(data(capacity)) + + ! Copy existing elements + if (this%size_ > 0) data(1:this%size_) = this%data + + ! Move allocation + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = capacity + end if + + ! Increase size of vector by one and set new element + this%size_ = this%size_ + 1 + this%data(this%size_) = val + end subroutine push_back_int + + subroutine reserve_int(this, n) + class(VectorInt), intent(inout) :: this + integer, intent(in) :: n + + integer, allocatable :: data(:) + + if (n > this%capacity_) then + allocate(data(n)) + + ! Copy existing elements + if (this%size_ > 0) data(1:this%size_) = this%data(1:this%size_) + + ! Move allocation + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = n + end if + end subroutine reserve_int + + subroutine resize_int(this, n, val) + class(VectorInt), intent(inout) :: this + integer, intent(in) :: n + integer, intent(in), optional :: val + + if (n < this%size_) then + this%size_ = n + elseif (n > this%size_) then + ! If requested size is greater than capacity, first reserve that many + ! elements + if (n > this%capacity_) call this%reserve(n) + + ! Fill added elements with specified value and increase size + if (present(val)) this%data(this%size_ + 1 : n) = val + this%size_ = n + end if + + end subroutine resize_int + + subroutine shrink_to_fit_int(this) + class(VectorInt), intent(inout) :: this + + integer, allocatable :: data(:) + + if (this%capacity_ > this%size_) then + if (this%size_ > 0) then + allocate(data(this%size_)) + data(:) = this%data(1:this%size_) + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = this%size_ + else + if (allocated(this%data)) deallocate(this%data) + end if + end if + end subroutine shrink_to_fit_int + + pure function size_int(this) result(size) + class(VectorInt), intent(in) :: this + integer :: size + + size = this%size_ + end function size_int + +!=============================================================================== +! Implementation of VectorReal +!=============================================================================== + + pure function capacity_real(this) result(capacity) + class(VectorReal), intent(in) :: this + integer :: capacity + + capacity = this%capacity_ + end function capacity_real + + subroutine clear_real(this) + class(VectorReal), intent(inout) :: this + + ! Since integer is trivially destructible, we only need to set size to zero + ! and can leave capacity as is + this%size_ = 0 + end subroutine clear_real + + subroutine initialize_fill_real(this, n, val) + class(VectorReal), intent(inout) :: this + integer, intent(in) :: n + real(8), optional, intent(in) :: val + + real(8) :: val_ + + ! If no value given, fill the vector with zeros + if (present(val)) then + val_ = val + else + val_ = 0 + end if + + if (allocated(this%data)) deallocate(this%data) + + allocate(this%data(n), SOURCE=val_) + this%size_ = n + this%capacity_ = n + end subroutine initialize_fill_real + + subroutine pop_back_real(this) + class(VectorReal), intent(inout) :: this + if (this%size_ > 0) this%size_ = this%size_ - 1 + end subroutine pop_back_real + + subroutine push_back_real(this, val) + class(VectorReal), intent(inout) :: this + real(8), intent(in) :: val + + integer :: capacity + real(8), allocatable :: data(:) + + if (this%capacity_ == this%size_) then + ! Create new data array that is GROWTH_FACTOR larger. Note that + if (this%capacity_ == 0) then + capacity = 8 + else + capacity = int(GROWTH_FACTOR*this%capacity_) + end if + allocate(data(capacity)) + + ! Copy existing elements + if (this%size_ > 0) data(1:this%size_) = this%data + + ! Move allocation + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = capacity + end if + + ! Increase size of vector by one and set new element + this%size_ = this%size_ + 1 + this%data(this%size_) = val + end subroutine push_back_real + + subroutine reserve_real(this, n) + class(VectorReal), intent(inout) :: this + integer, intent(in) :: n + + real(8), allocatable :: data(:) + + if (n > this%capacity_) then + allocate(data(n)) + + ! Copy existing elements + if (this%size_ > 0) data(1:this%size_) = this%data(1:this%size_) + + ! Move allocation + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = n + end if + end subroutine reserve_real + + subroutine resize_real(this, n, val) + class(VectorReal), intent(inout) :: this + integer, intent(in) :: n + real(8), intent(in), optional :: val + + if (n < this%size_) then + this%size_ = n + elseif (n > this%size_) then + ! If requested size is greater than capacity, first reserve that many + ! elements + if (n > this%capacity_) call this%reserve(n) + + ! Fill added elements with specified value and increase size + if (present(val)) this%data(this%size_ + 1 : n) = val + this%size_ = n + end if + + end subroutine resize_real + + subroutine shrink_to_fit_real(this) + class(VectorReal), intent(inout) :: this + + real(8), allocatable :: data(:) + + if (this%capacity_ > this%size_) then + if (this%size_ > 0) then + allocate(data(this%size_)) + data(:) = this%data(1:this%size_) + call move_alloc(FROM=data, TO=this%data) + this%capacity_ = this%size_ + else + if (allocated(this%data)) deallocate(this%data) + end if + end if + end subroutine shrink_to_fit_real + + pure function size_real(this) result(size) + class(VectorReal), intent(in) :: this + integer :: size + + size = this%size_ + end function size_real + +end module stl_vector From da0d13e18c4b6829034d58e2da280455aa9c8463 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 23 Sep 2015 13:12:31 +0700 Subject: [PATCH 14/48] Update constants for surface half-space operators --- src/constants.F90 | 9 +++++---- src/geometry.F90 | 2 +- src/initialize.F90 | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index 53891cdaa6..6e14a47ea3 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -87,10 +87,11 @@ module constants ! Logical operators for cell definitions integer, parameter :: & - OP_LEFT_PAREN = huge(0), & ! Left parentheses - OP_RIGHT_PAREN = huge(0) - 1, & ! Right parentheses - OP_UNION = huge(0) - 2, & ! Union operator - OP_DIFFERENCE = huge(0) - 3 ! Difference operator + OP_LEFT_PAREN = huge(0), & ! Left parentheses + OP_RIGHT_PAREN = huge(0) - 1, & ! Right parentheses + OP_COMPLEMENT = huge(0) - 2, & ! Complement operator (~) + OP_INTERSECTION = huge(0) - 3, & ! Intersection operator + OP_UNION = huge(0) - 4 ! Union operator (^) ! Cell types integer, parameter :: & diff --git a/src/geometry.F90 b/src/geometry.F90 index 62afc3fb3b..2cde01e023 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -563,7 +563,7 @@ contains ! check for operators index_surf = abs(index_surf) - if (index_surf >= OP_DIFFERENCE) cycle + if (index_surf >= OP_UNION) cycle ! Calculate distance to surface surf => surfaces(index_surf)%obj diff --git a/src/initialize.F90 b/src/initialize.F90 index 86242c7533..3671a40af7 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -573,7 +573,7 @@ contains c => cells(i) do j = 1, c%n_surfaces id = c%surfaces(j) - if (id < OP_DIFFERENCE) then + if (id < OP_UNION) then if (surface_dict%has_key(abs(id))) then i_array = surface_dict%get_key(abs(id)) c%surfaces(j) = sign(i_array, id) From acf2e51272db99028630dca1bf1a3fcd64e6d209 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 24 Sep 2015 13:55:11 +0700 Subject: [PATCH 15/48] Partial support for cells defined with union and complement operators. The Python API still has no concept of operators. The Summary class has a hack to at least be able to read a summary file for now, basically skipping any operators that are present. --- openmc/summary.py | 17 +++--- src/geometry.F90 | 109 +++++++++++++++++++++--------------- src/geometry_header.F90 | 11 ++-- src/initialize.F90 | 10 +++- src/input_xml.F90 | 116 ++++++++++++++++++++++++++++++++++++--- src/relaxng/geometry.rnc | 2 +- src/relaxng/geometry.rng | 12 +--- src/string.F90 | 110 ++++++++++++++++++++++--------------- src/summary.F90 | 31 +++++++---- 9 files changed, 286 insertions(+), 132 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index 2ae7464846..c2c02da18a 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -213,7 +213,7 @@ class Summary(object): fill = self._f['geometry/cells'][key]['lattice'].value if 'surfaces' in self._f['geometry/cells'][key].keys(): - surfaces = self._f['geometry/cells'][key]['surfaces'][...] + surfaces = self._f['geometry/cells'][key]['surfaces'].value.decode() else: surfaces = [] @@ -241,12 +241,15 @@ class Summary(object): self._cell_fills[index] = (fill_type, fill) # Iterate over all Surfaces and add them to the Cell - for surface_halfspace in surfaces: - - halfspace = np.sign(surface_halfspace) - surface_id = abs(surface_halfspace) - surface = self.get_surface_by_id(surface_id) - cell.add_surface(surface, halfspace) + for token in surfaces.split(): + try: + surface_halfspace = int(token) + halfspace = np.sign(surface_halfspace) + surface_id = abs(surface_halfspace) + surface = self.get_surface_by_id(surface_id) + cell.add_surface(surface, halfspace) + except ValueError: + pass # Add the Cell to the global dictionary of all Cells self.cells[index] = cell diff --git a/src/geometry.F90 b/src/geometry.F90 index 2cde01e023..9e40155e52 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -17,56 +17,77 @@ module geometry contains !=============================================================================== -! SIMPLE_CELL_CONTAINS determines whether a given the current coordinates of the -! particle are inside a cell defined as the intersection of a series of surfaces +! CELL_CONTAINS determines if a cell contains the particle at a given +! location. The bounds of the cell are detemined by a logical expression +! involving surface half-spaces. At initialization, the expression was converted +! to RPN notation. In cell_contains, we evaluate the RPN expression using a +! stack, similar to how a RPN calculator would work. !=============================================================================== - function simple_cell_contains(c, p) result(in_cell) + pure function cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c - type(Particle), intent(inout) :: p + type(Particle), intent(in) :: p logical :: in_cell - integer :: i ! index of surfaces in cell - integer :: i_surface ! index in surfaces array (with sign) - logical :: specified_sense ! specified sense of surface in list + integer :: i + integer :: token + logical :: b1, b2 + integer :: i_stack logical :: actual_sense ! sense of particle wrt surface - class(Surface), pointer :: s + logical :: stack(size(c%rpn)) - SURFACE_LOOP: do i = 1, c % n_surfaces - ! Lookup surface - i_surface = c % surfaces(i) - - ! Check if the particle is currently on the specified surface - if (i_surface == p % surface) then - ! Particle is heading into the cell - cycle - elseif (i_surface == -p % surface) then - ! Particle is heading out of the cell - in_cell = .false. - return + i_stack = 0 + do i = 1, size(c%rpn) + token = c%rpn(i) + if (token < OP_UNION) then + ! If the token is not an operator, evaluate the sense of particle with + ! respect to the surface and see if the token matches the sense. If the + ! particle's surface attribute is set and matches the token, that + ! overrides the determination based on sense(). + i_stack = i_stack + 1 + if (token == p%surface) then + stack(i_stack) = .true. + elseif (-token == p%surface) then + stack(i_stack) = .false. + else + actual_sense = surfaces(abs(token))%obj%sense(& + p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) + stack(i_stack) = (actual_sense .eqv. (token > 0)) + end if + else + ! If the token is a binary operator (intersection/union), apply it to + ! the last two items on the stack. If the token is a unary operator + ! (complement), apply it to the last item on the stack. + b1 = stack(i_stack) + select case (token) + case (OP_UNION) + b2 = stack(i_stack - 1) + stack(i_stack - 1) = b1 .or. b2 + i_stack = i_stack - 1 + case (OP_INTERSECTION) + b2 = stack(i_stack - 1) + stack(i_stack - 1) = b1 .and. b2 + i_stack = i_stack - 1 + case (OP_COMPLEMENT) + stack(i_stack) = .not. b1 + end select end if + end do - ! Determine the specified sense of the surface in the cell and the actual - ! sense of the particle with respect to the surface - s => surfaces(abs(i_surface))%obj - actual_sense = s%sense(p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) - specified_sense = (c % surfaces(i) > 0) - - ! Compare sense of point to specified sense - if (actual_sense .neqv. specified_sense) then - in_cell = .false. - return - end if - end do SURFACE_LOOP - - ! If we've reached here, then the sense matched on every surface or there - ! are no surfaces. - in_cell = .true. - end function simple_cell_contains + if (i_stack == 1) then + ! The one remaining logical on the stack indicates whether the particle is + ! in the cell. + in_cell = stack(i_stack) + else + ! This case occurs if there is no surface specification since i_stack will + ! still be zero. + in_cell = .true. + end if + end function cell_contains !=============================================================================== ! CHECK_CELL_OVERLAP checks for overlapping cells at the current particle's -! position using simple_cell_contains and the LocalCoord's built up by find_cell +! position using cell_contains and the LocalCoord's built up by find_cell !=============================================================================== subroutine check_cell_overlap(p) @@ -93,7 +114,7 @@ contains index_cell = univ % cells(i) c => cells(index_cell) - if (simple_cell_contains(c, p)) then + if (cell_contains(c, p)) then ! the particle should only be contained in one cell per level if (index_cell /= p % coord(j) % cell) then call fatal_error("Overlapping cells detected: " & @@ -162,7 +183,7 @@ contains c => cells(index_cell) ! Move on to the next cell if the particle is not inside this cell - if (.not. simple_cell_contains(c, p)) cycle + if (.not. cell_contains(c, p)) cycle ! Set cell on this level p % coord(j) % cell = index_cell @@ -556,7 +577,7 @@ contains ! ======================================================================= ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL - SURFACE_LOOP: do i = 1, cl % n_surfaces + SURFACE_LOOP: do i = 1, size(cl%surfaces) ! check for operators index_surf = cl%surfaces(i) coincident = (index_surf == p % surface) @@ -823,10 +844,11 @@ contains c => cells(i) ! loop over each surface specification - do j = 1, c % n_surfaces + do j = 1, size(c%surfaces) i_surface = c % surfaces(j) positive = (i_surface > 0) i_surface = abs(i_surface) + if (i_surface >= OP_UNION) cycle if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 else @@ -853,10 +875,11 @@ contains c => cells(i) ! loop over each surface specification - do j = 1, c % n_surfaces + do j = 1, size(c%surfaces) i_surface = c % surfaces(j) positive = (i_surface > 0) i_surface = abs(i_surface) + if (i_surface >= OP_UNION) cycle if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 13d806e8cf..c8c99783f3 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -128,14 +128,13 @@ module geometry_header ! the geom integer :: material ! Material within cell (0 for ! universe) - integer :: n_surfaces ! Number of surfaces within integer, allocatable :: offset (:) ! Distribcell offset for tally ! counter - integer, allocatable :: & - & surfaces(:) ! List of surfaces bounding cell - ! -- note that parentheses, union, - ! etc operators will be listed here - ! too + integer, allocatable :: surfaces(:) ! List of surfaces bounding cell -- + ! note that parentheses, union, etc + ! operators will be listed here too + integer, allocatable :: rpn(:) ! Reverse Polish notation for surface + ! expression ! Rotation matrix and translation vector real(8), allocatable :: translation(:) diff --git a/src/initialize.F90 b/src/initialize.F90 index 3671a40af7..d46fd8d48a 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -571,7 +571,7 @@ contains ! ADJUST SURFACE LIST FOR EACH CELL c => cells(i) - do j = 1, c%n_surfaces + do j = 1, size(c%surfaces) id = c%surfaces(j) if (id < OP_UNION) then if (surface_dict%has_key(abs(id))) then @@ -584,6 +584,14 @@ contains end if end do + do j = 1, size(c%rpn) + id = c%rpn(j) + if (id < OP_UNION) then + i_array = surface_dict%get_key(abs(id)) + c%rpn(j) = sign(i_array, id) + end if + end do + ! ======================================================================= ! ADJUST UNIVERSE INDEX FOR EACH CELL diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 308bdc66b0..156d33ce46 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -13,8 +13,9 @@ module input_xml use plot_header use random_lcg, only: prn use surface_header + use stl_vector, only: VectorInt use string, only: to_lower, to_str, str_to_int, str_to_real, & - starts_with, ends_with + starts_with, ends_with, tokenize use tally_header, only: TallyObject, TallyFilter use tally_initialize, only: add_tallies use xml_interface @@ -993,6 +994,7 @@ contains logical :: boundary_exists character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word + character(MAX_LINE_LEN) :: surface_spec type(Cell), pointer :: c class(Surface), pointer :: s class(Lattice), pointer :: lat @@ -1004,6 +1006,8 @@ contains type(NodeList), pointer :: node_surf_list => null() type(NodeList), pointer :: node_rlat_list => null() type(NodeList), pointer :: node_hlat_list => null() + type(VectorInt) :: tokens + type(VectorInt) :: rpn ! Display output message call write_message("Reading geometry XML file...", 5) @@ -1116,16 +1120,26 @@ contains ! Allocate array for surfaces and copy if (check_for_node(node_cell, "surfaces")) then - n = get_arraysize_integer(node_cell, "surfaces") - else - n = 0 - end if - c % n_surfaces = n + call get_node_value(node_cell, "surfaces", surface_spec) + if (len_trim(surface_spec) > 0) then + ! Create surfaces array from string + call tokenize(surface_spec, tokens) - if (n > 0) then - allocate(c % surfaces(n)) - call get_node_array(node_cell, "surfaces", c % surfaces) + ! Use shunting-yard algorithm to determine RPN for surface algorithm + call generate_rpn(tokens, rpn) + + ! Copy surface spec and RPN form to cell arrays + allocate(c % surfaces(tokens%size())) + allocate(c % rpn(rpn%size())) + c % surfaces(:) = tokens%data(1:tokens%size()) + c % rpn(:) = rpn%data(1:rpn%size()) + + call tokens%clear() + call rpn%clear() + end if end if + if (.not. allocated(c%surfaces)) allocate(c%surfaces(0)) + if (.not. allocated(c%rpn)) allocate(c%rpn(0)) ! Rotation matrix if (check_for_node(node_cell, "rotation")) then @@ -4766,4 +4780,88 @@ contains end subroutine expand_natural_element +!=============================================================================== +! GENERATE_RPN implements the shunting-yard algorithm to generate a Reverse +! polish notation (RPN) expression for the surface specification of a cell given +! the infix notation. +!=============================================================================== + + subroutine generate_rpn(tokens, output) + type(VectorInt), intent(in) :: tokens ! infix notation + type(VectorInt), intent(inout) :: output ! RPN notation + + integer :: i + integer :: token + integer :: op + type(VectorInt) :: stack + + do i = 1, tokens%size() + token = tokens%data(i) + + if (token < OP_UNION) then + ! If token is not an operator, add it to output + call output%push_back(token) + + elseif (token < OP_RIGHT_PAREN) then + ! Regular operators union, intersection, complement + do while (stack%size() > 0) + op = stack%data(stack%size()) + + if (op < OP_RIGHT_PAREN .and. & + ((token == OP_COMPLEMENT .and. token < op) .or. & + (token /= OP_COMPLEMENT .and. token <= op))) then + ! While there is an operator, op, on top of the stack, if the token + ! is left-associative and its precedence is less than or equal to + ! that of op or if the token is right-associative and its precedence + ! is less than that of op, move op to the output queue and push the + ! token on to the stack. Note that only complement is + ! right-associative. + call output%push_back(op) + call stack%pop_back() + else + exit + end if + end do + + call stack%push_back(token) + + elseif (token == OP_LEFT_PAREN) then + ! If the token is a left parenthesis, push it onto the stack + call stack%push_back(token) + + else + ! If the token is a right parenthesis, move operators from the stack to + ! the output queue until reaching the left parenthesis. + do + ! If we run out of operators without finding a left parenthesis, it + ! means there are mismatched parentheses. + if (stack%size() == 0) then + call fatal_error('Mimatched parentheses in surface specification') + end if + + op = stack%data(stack%size()) + if (op == OP_LEFT_PAREN) exit + call output%push_back(op) + call stack%pop_back() + end do + + ! Pop the left parenthesis. + call stack%pop_back() + end if + end do + + ! While there are operators on the stack, move them to the output queue + do while (stack%size() > 0) + op = stack%data(stack%size()) + + ! If the operator is a parenthesis, it is mismatched + if (op >= OP_RIGHT_PAREN) then + call fatal_error('Mimatched parentheses in surface specification') + end if + + call output%push_back(op) + call stack%pop_back() + end do + end subroutine generate_rpn + end module input_xml diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index 82f1f15b32..07a02af9ea 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -9,7 +9,7 @@ element geometry { (element material { ( xsd:int | "void" ) } | attribute material { ( xsd:int | "void" ) }) ) & - (element surfaces { list { xsd:int* } } | attribute surfaces { list { xsd:int* } })? & + (element surfaces { xsd:string } | attribute surfaces { xsd:string })? & (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? }* diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng index 9bd573b346..6a68aa721e 100644 --- a/src/relaxng/geometry.rng +++ b/src/relaxng/geometry.rng @@ -63,18 +63,10 @@ - - - - - + - - - - - + diff --git a/src/string.F90 b/src/string.F90 index 5f57bb3855..2d690dded5 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -1,8 +1,10 @@ module string - use constants, only: MAX_WORDS, MAX_LINE_LEN, ERROR_INT, ERROR_REAL + use constants, only: MAX_WORDS, MAX_LINE_LEN, ERROR_INT, ERROR_REAL, & + OP_LEFT_PAREN, OP_RIGHT_PAREN, OP_COMPLEMENT, OP_INTERSECTION, OP_UNION use error, only: fatal_error, warning use global, only: master + use stl_vector, only: VectorInt implicit none @@ -63,63 +65,81 @@ contains end subroutine split_string !=============================================================================== -! SPLIT_STRING_WL takes a string that includes logical expressions for a list of -! bounding surfaces in a cell and splits it into separate words. The characters -! (, ), :, and # count as separate words since they represent operators. -! -! Arguments: -! string = input line -! words = array of words -! n = number of words +! TOKENIZE takes a string that includes logical expressions for a list of +! bounding surfaces in a cell and splits it into separate tokens. The characters +! (, ), ^, and ~ count as separate tokens since they represent operators. !=============================================================================== - subroutine split_string_wl(string, words, n) + subroutine tokenize(string, tokens) + character(*), intent(in) :: string + type(VectorInt), intent(inout) :: tokens - character(*), intent(in) :: string - character(*), intent(out) :: words(MAX_WORDS) - integer, intent(out) :: n + integer :: i ! current index + integer :: i_start ! starting index of word + character(len=len_trim(string)) :: string_ - character(1) :: chr ! current character - integer :: i ! current index - integer :: i_start ! starting index of word - integer :: i_end ! ending index of word + ! Remove leading blanks + string_ = adjustl(string) i_start = 0 - i_end = 0 - n = 0 - do i = 1, len_trim(string) - chr = string(i:i) - + i = 1 + do while (i <= len_trim(string_)) ! Check for special characters - if (index('():#', chr) > 0) then + if (index('()^~ ', string_(i:i)) > 0) then + ! If the special character appears immediately after a non-operator, + ! create a token with the surface half-space if (i_start > 0) then - i_end = i - 1 - n = n + 1 - words(n) = string(i_start:i_end) + call tokens%push_back(int(str_to_int(& + string_(i_start:i - 1)), 4)) end if - n = n + 1 - words(n) = chr + + select case (string_(i:i)) + case ('(') + call tokens%push_back(OP_LEFT_PAREN) + case (')') + call tokens%push_back(OP_RIGHT_PAREN) + case ('^') + call tokens%push_back(OP_UNION) + case ('~') + call tokens%push_back(OP_COMPLEMENT) + case (' ') + ! Find next non-space character + do while (string_(i+1:i+1) == ' ') + i = i + 1 + end do + + ! If previous token is not an operator and next token is not a left + ! parenthese or union operator, that implies that the whitespace is to + ! be interpreted as an intersection operator + if (i_start > 0) then + if (index(')^', string_(i+1:i+1)) == 0) then + call tokens%push_back(OP_INTERSECTION) + end if + end if + end select + i_start = 0 - i_end = 0 - cycle + else + ! Check for invalid characters + if (index('-0123456789', string_(i:i)) == 0) then + call fatal_error("Invalid character '" // string_(i:i) // "' in & + &surface specification.") + end if + + ! If we haven't yet reached the start of a word, start a new word + if (i_start == 0) i_start = i end if - if ((i_start == 0) .and. (chr /= ' ')) then - i_start = i - end if - if (i_start > 0) then - if (chr == ' ') i_end = i - 1 - if (i == len_trim(string)) i_end = i - if (i_end > 0) then - n = n + 1 - words(n) = string(i_start:i_end) - ! reset indices - i_start = 0 - i_end = 0 - end if - end if + i = i + 1 end do - end subroutine split_string_wl + + ! If we've reached the end and we're still in a word, create a token from it + ! and add it to the list + if (i_start > 0) then + call tokens%push_back(int(str_to_int(& + string_(i_start:len_trim(string_))), 4)) + end if + end subroutine tokenize !=============================================================================== ! CONCATENATE takes an array of words and concatenates them together in one diff --git a/src/summary.F90 b/src/summary.F90 index 587f00b6b7..49fe802305 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -107,13 +107,13 @@ contains integer :: i, j, k, m integer, allocatable :: lattice_universes(:,:,:) - integer, allocatable :: surface_ids(:) integer(HID_T) :: geom_group integer(HID_T) :: cells_group, cell_group integer(HID_T) :: surfaces_group, surface_group integer(HID_T) :: universes_group, univ_group integer(HID_T) :: lattices_group, lattice_group real(8), allocatable :: coeffs(:) + character(MAX_LINE_LEN) :: surface_spec type(Cell), pointer :: c class(Surface), pointer :: s type(Universe), pointer :: u @@ -176,15 +176,26 @@ contains end select ! Write list of bounding surfaces - if (c%n_surfaces > 0) then - allocate(surface_ids(c%n_surfaces)) - do j = 1, c%n_surfaces - k = c%surfaces(j) - surface_ids(j) = sign(surfaces(abs(k))%obj%id, k) - end do - call write_dataset(cell_group, "surfaces", surface_ids) - deallocate(surface_ids) - end if + surface_spec = "" + do j = 1, size(c%surfaces) + k = c%surfaces(j) + if (k < OP_UNION) then + surface_spec = trim(surface_spec) // " " // to_str(& + sign(surfaces(abs(k))%obj%id, k)) + else + select case(k) + case (OP_LEFT_PAREN) + surface_spec = trim(surface_spec) // " (" + case (OP_RIGHT_PAREN) + surface_spec = trim(surface_spec) // " (" + case (OP_COMPLEMENT) + surface_spec = trim(surface_spec) // " ~" + case (OP_UNION) + surface_spec = trim(surface_spec) // " ^" + end select + end if + end do + call write_dataset(cell_group, "surfaces", adjustl(surface_spec)) call close_group(cell_group) end do CELL_LOOP From 1cfff776a5791085c5d5173b2a31a94ccb792156 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 25 Sep 2015 20:28:08 +0700 Subject: [PATCH 16/48] Started adding changes in Python API for complex cells. --- openmc/region.py | 105 ++++++++++++++++++++++++++++++++++++++++++++++ openmc/surface.py | 79 +++++++++++++++++++++++++++++++--- 2 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 openmc/region.py diff --git a/openmc/region.py b/openmc/region.py new file mode 100644 index 0000000000..5dd8c6eb41 --- /dev/null +++ b/openmc/region.py @@ -0,0 +1,105 @@ +from abc import ABCMeta, abstractmethod +from collections import Iterable + +from openmc.checkvalue import check_type + + +class Region(object): + __metaclass__ = ABCMeta + + @abstractmethod + def __str__(self): + return '' + + +class Intersection(Region): + """Intersection of two or more regions. + + Parameters + ---------- + *nodes + Regions to take the intersection of + + Attributes + ---------- + nodes : tuple of Region + Regions to take the intersection of + + """ + + def __init__(self, *nodes): + self.nodes = nodes + + @property + def nodes(self): + return self._nodes + + @nodes.setter + def nodes(self, nodes): + check_type('nodes', nodes, Iterable, Region) + self._nodes = nodes + + def __str__(self): + return '(' + ' '.join(map(str, self.nodes)) + ')' + + +class Union(Region): + """Union of two or more regions. + + Parameters + ---------- + *nodes + Regions to take the union of + + Attributes + ---------- + nodes : tuple of Region + Regions to take the union of + + """ + + def __init__(self, *nodes): + self.nodes = nodes + + @property + def nodes(self): + return self._nodes + + @nodes.setter + def nodes(self, nodes): + check_type('nodes', nodes, Iterable, Region) + self._nodes = nodes + + def __str__(self): + return '(' + ' ^ '.join(map(str, self.nodes)) + ')' + + +class Complement(Region): + """Complement of a region. + + Parameters + ---------- + node : Region + Region to take the complement of + + Attributes + ---------- + node : Region + Regions to take the complement of + + """ + + def __init__(self, node): + self.node = node + + @property + def node(self): + return self._node + + @node.setter + def node(self, node): + check_type('node', node, Region) + self._node = node + + def __str__(self): + return '~' + str(self.node) diff --git a/openmc/surface.py b/openmc/surface.py index 653754d303..0be62fbf5a 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,6 +4,7 @@ from xml.etree import ElementTree as ET import sys from openmc.checkvalue import check_type, check_value, check_greater_than +from openmc.region import Region if sys.version_info[0] >= 3: basestring = str @@ -38,17 +39,23 @@ class Surface(object): Attributes ---------- - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface, e.g. 'x-plane' boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} Boundary condition that defines the behavior for particles hitting the surface. coeffs : dict Dictionary of surface coefficients + id : int + Unique identifier for the surface + name : str + Name of the surface + negative : Halfspace + Negative half-space of the surface, i.e., if :math:`f(x,y,z) = 0` is the + equation for the sufrace, the region for which :math:`f(x,y,z) < 0`. + positive : Halfspace + Positive half-space of the surface, i.e., if :math:`f(x,y,z) = 0` is the + equation for the sufrace, the region for which :math:`f(x,y,z) > 0`. + type : str + Type of the surface, e.g. 'x-plane' """ @@ -88,6 +95,14 @@ class Surface(object): def coeffs(self): return self._coeffs + @property + def negative(self): + return Halfspace(self, '-') + + @property + def positive(self): + return Halfspace(self, '+') + @id.setter def id(self, surface_id): if surface_id is None: @@ -937,3 +952,55 @@ class ZCone(Cone): R2, name=name) self._type = 'z-cone' + + +class Halfspace(Region): + """A positive or negative half-space region. + + A half-space is either of the two parts into which a two-dimension surface + divides the three-dimensional Euclidean space. If the equation of the + surface is :math:`f(x,y,z) = 0`, the region for which :math:`f(x,y,z) < 0` + is referred to as the negative half-space and the region for which + :math:`f(x,y,z) > 0` is referred to as the positive half-space. + + Parameters + ---------- + surface : Surface + Surface which divides Euclidean space. + side : {'+', '-'} + Indicates whether the positive or negative half-space is used. + + Attributes + ---------- + surface : Surface + Surface which divides Euclidean space. + side : {'+', '-'} + Indicates whether the positive or negative half-space is used. + + """ + + def __init__(self, surface, side): + self.surface = surface + self.side = side + + @property + def surface(self): + return self._surface + + @surface.setter + def surface(self, surface): + check_type('surface', surface, Surface) + self._surface = surface + + @property + def side(self): + return self._side + + @side.setter + def side(self, side): + check_value('side', side, ('+', '-')) + self._side = side + + def __str__(self): + return '-' + str(self.surface.id) if self.side == '-' \ + else str(self.surface.id) From 7681995ef190be2957a3d367a2823e7f8a26edb7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 25 Sep 2015 21:43:31 +0700 Subject: [PATCH 17/48] Add region attribute to Cell and use it in lieu of surfaces --- openmc/region.py | 4 +- openmc/universe.py | 100 +++++++++++++++++++++------------------------ 2 files changed, 48 insertions(+), 56 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index 5dd8c6eb41..d75b349803 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -28,7 +28,7 @@ class Intersection(Region): """ def __init__(self, *nodes): - self.nodes = nodes + self.nodes = list(nodes) @property def nodes(self): @@ -59,7 +59,7 @@ class Union(Region): """ def __init__(self, *nodes): - self.nodes = nodes + self.nodes = list(nodes) @property def nodes(self): diff --git a/openmc/universe.py b/openmc/universe.py index bab10f5df7..79cb90fd00 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -8,6 +8,8 @@ import numpy as np import openmc import openmc.checkvalue as cv +from openmc.surface import Halfspace +from openmc.region import Region, Intersection, Complement if sys.version_info[0] >= 3: basestring = str @@ -45,10 +47,8 @@ class Cell(object): Name of the cell fill : Material or Universe or Lattice or 'void' Indicates what the region of space is filled with - surfaces : dict - Dictionary whose keys are surface IDs and values are 2-tuples of a - Surface object and an integer identify whether the positive or negative - half-space is to be used + region : openmc.region.Region + Region of space that is assigned to the cell. rotation : ndarray If the cell is filled with a universe, this array specifies the angles in degrees about the x, y, and z axes that the filled universe should be @@ -67,7 +67,7 @@ class Cell(object): self.name = name self._fill = None self._type = None - self._surfaces = {} + self._region = None self._rotation = None self._translation = None self._offsets = None @@ -89,8 +89,8 @@ class Cell(object): return self._fill @property - def surfaces(self): - return self._surfaces + def region(self): + return self._region @property def rotation(self): @@ -163,6 +163,11 @@ class Cell(object): cv.check_type('cell offsets', offsets, Iterable) self._offsets = offsets + @region.setter + def region(self, region): + cv.check_type('cell region', region, Region) + self._region = region + def add_surface(self, surface, halfspace): """Add a half-space to the list of half-spaces whose intersection defines the cell. @@ -186,28 +191,17 @@ class Cell(object): '"{2}" since it is not +/-1'.format(surface, self._id, halfspace) raise ValueError(msg) - # If the Cell does not already contain the Surface, add it - if surface._id not in self._surfaces: - self._surfaces[surface._id] = (surface, halfspace) - - def remove_surface(self, surface): - """Remove the half-space associated with a particular surface. - - Parameters - ---------- - surface : openmc.surface.Surface - Surface to remove from definition - - """ - - if not isinstance(surface, openmc.Surface): - msg = 'Unable to remove Surface "{0}" from Cell ID="{1}" since it is ' \ - 'not a Surface object'.format(surface, self._id) - raise ValueError(msg) - - # If the Cell contains the Surface, delete it - if surface._id in self._surfaces: - del self._surfaces[surface._id] + # If no region has been assigned, simply use the half-space. Otherwise, + # take the intersection of the current region and the half-space + # specified + region = surface.positive if halfspace == 1 else surface.negative + if self.region is None: + self.region = region + else: + if isinstance(self.region, Intersection): + self.region.nodes.append(region) + else: + self.region = Intersection(self.region, region) def get_offset(self, path, filter_offset): # Get the current element and remove it from the list @@ -301,13 +295,7 @@ class Cell(object): else: string += '{0: <16}{1}{2}\n'.format('\tFill', '=\t', self._fill) - string += '{0: <16}{1}\n'.format('\tSurfaces', '=\t') - - for surface_id in self._surfaces: - halfspace = self._surfaces[surface_id][1] - string += '{0} '.format(halfspace * surface_id) - - string = string.rstrip(' ') + '\n' + string += '{0: <16}{1}{2}\n'.format('\tRegion', '=\t', self._region) string += '{0: <16}{1}{2}\n'.format('\tRotation', '=\t', self._rotation) @@ -338,26 +326,30 @@ class Cell(object): element.set("fill", str(self._fill)) self._fill.create_xml_subelement(xml_element) - if self._surfaces is not None: - surfaces = '' + if self.region is not None: + # Set the surfaces attribute with the region specification + element.set("surfaces", str(self.region)) - for surface_id in self._surfaces: - # Determine if XML element already includes this Surface - path = './surface[@id=\'{0}\']'.format(surface_id) - test = xml_element.find(path) + # Only surfaces that appear in a region are added to the geometry + # file, so the appropriate check is performed here. First we create + # a function which is called recursively to navigate through the CSG + # tree. When it reaches a leaf (a Halfspace), it creates a + # element for the corresponding surface if none has been created + # thus far. + def create_surface_elements(node, element): + if isinstance(node, Halfspace): + path = './surface[@id=\'{0}\']'.format(node.surface.id) + if xml_element.find(path) is None: + surface_subelement = node.surface.create_xml_subelement() + xml_element.append(surface_subelement) + elif isinstance(node, Complement): + create_surface_elements(node.node, element) + else: + for subnode in node.nodes: + create_surface_elements(subnode, element) - # If the element does not contain the Surface subelement - if test is None: - # Create the XML subelement for this Surface - surface = self._surfaces[surface_id][0] - surface_subelement = surface.create_xml_subelement() - xml_element.append(surface_subelement) - - # Append the halfspace and Surface ID - halfspace = self._surfaces[surface_id][1] - surfaces += '{0} '.format(halfspace * surface_id) - - element.set("surfaces", surfaces.rstrip(' ')) + # Call the recursive function from the top node + create_surface_elements(self.region, xml_element) if self._translation is not None: element.set("translation", ' '.join(map(str, self._translation))) From 671b5c7a821f8e4e785849992c202c73430177e7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 26 Sep 2015 09:36:39 +0700 Subject: [PATCH 18/48] Rename surfaces attribute of to region. --- openmc/summary.py | 8 +++---- src/geometry.F90 | 16 +++++++------- src/geometry_header.F90 | 7 +++--- src/initialize.F90 | 8 +++---- src/input_xml.F90 | 48 +++++++++++++++++++++++----------------- src/relaxng/geometry.rnc | 2 +- src/relaxng/geometry.rng | 4 ++-- src/summary.F90 | 20 ++++++++--------- 8 files changed, 60 insertions(+), 53 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index c2c02da18a..3522e707d4 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -212,10 +212,10 @@ class Summary(object): else: fill = self._f['geometry/cells'][key]['lattice'].value - if 'surfaces' in self._f['geometry/cells'][key].keys(): - surfaces = self._f['geometry/cells'][key]['surfaces'].value.decode() + if 'region' in self._f['geometry/cells'][key].keys(): + region = self._f['geometry/cells'][key]['region'].value.decode() else: - surfaces = [] + region = [] # Create this Cell cell = openmc.Cell(cell_id=cell_id, name=name) @@ -241,7 +241,7 @@ class Summary(object): self._cell_fills[index] = (fill_type, fill) # Iterate over all Surfaces and add them to the Cell - for token in surfaces.split(): + for token in region.split(): try: surface_halfspace = int(token) halfspace = np.sign(surface_halfspace) diff --git a/src/geometry.F90 b/src/geometry.F90 index 9e40155e52..a7a36a5351 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -577,9 +577,9 @@ contains ! ======================================================================= ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL - SURFACE_LOOP: do i = 1, size(cl%surfaces) + SURFACE_LOOP: do i = 1, size(cl%region) ! check for operators - index_surf = cl%surfaces(i) + index_surf = cl%region(i) coincident = (index_surf == p % surface) ! check for operators @@ -594,7 +594,7 @@ contains if (d < d_surf) then if (abs(d - d_surf)/d_surf >= FP_PRECISION) then d_surf = d - level_surf_cross = -cl % surfaces(i) + level_surf_cross = -cl % region(i) end if end if end do SURFACE_LOOP @@ -843,9 +843,9 @@ contains do i = 1, n_cells c => cells(i) - ! loop over each surface specification - do j = 1, size(c%surfaces) - i_surface = c % surfaces(j) + ! loop over each region specification + do j = 1, size(c%region) + i_surface = c % region(j) positive = (i_surface > 0) i_surface = abs(i_surface) if (i_surface >= OP_UNION) cycle @@ -875,8 +875,8 @@ contains c => cells(i) ! loop over each surface specification - do j = 1, size(c%surfaces) - i_surface = c % surfaces(j) + do j = 1, size(c%region) + i_surface = c % region(j) positive = (i_surface > 0) i_surface = abs(i_surface) if (i_surface >= OP_UNION) cycle diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index c8c99783f3..c9889a5c82 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -130,10 +130,9 @@ module geometry_header ! universe) integer, allocatable :: offset (:) ! Distribcell offset for tally ! counter - integer, allocatable :: surfaces(:) ! List of surfaces bounding cell -- - ! note that parentheses, union, etc - ! operators will be listed here too - integer, allocatable :: rpn(:) ! Reverse Polish notation for surface + integer, allocatable :: region(:) ! Definition of spatial region as + ! Boolean expression of half-spaces + integer, allocatable :: rpn(:) ! Reverse Polish notation for region ! expression ! Rotation matrix and translation vector diff --git a/src/initialize.F90 b/src/initialize.F90 index d46fd8d48a..16a6a17b03 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -568,15 +568,15 @@ contains do i = 1, n_cells ! ======================================================================= - ! ADJUST SURFACE LIST FOR EACH CELL + ! ADJUST REGION SPECIFICATION FOR EACH CELL c => cells(i) - do j = 1, size(c%surfaces) - id = c%surfaces(j) + do j = 1, size(c%region) + id = c%region(j) if (id < OP_UNION) then if (surface_dict%has_key(abs(id))) then i_array = surface_dict%get_key(abs(id)) - c%surfaces(j) = sign(i_array, id) + c%region(j) = sign(i_array, id) else call fatal_error("Could not find surface " // trim(to_str(abs(id)))& &// " specified on cell " // trim(to_str(c%id))) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 156d33ce46..f074898f23 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -994,7 +994,7 @@ contains logical :: boundary_exists character(MAX_LINE_LEN) :: filename character(MAX_WORD_LEN) :: word - character(MAX_LINE_LEN) :: surface_spec + character(MAX_LINE_LEN) :: region_spec type(Cell), pointer :: c class(Surface), pointer :: s class(Lattice), pointer :: lat @@ -1118,27 +1118,35 @@ contains call fatal_error("Cannot specify material and fill simultaneously") end if - ! Allocate array for surfaces and copy + ! Check for region specification (also under deprecated name surfaces) + region_spec = '' if (check_for_node(node_cell, "surfaces")) then - call get_node_value(node_cell, "surfaces", surface_spec) - if (len_trim(surface_spec) > 0) then - ! Create surfaces array from string - call tokenize(surface_spec, tokens) - - ! Use shunting-yard algorithm to determine RPN for surface algorithm - call generate_rpn(tokens, rpn) - - ! Copy surface spec and RPN form to cell arrays - allocate(c % surfaces(tokens%size())) - allocate(c % rpn(rpn%size())) - c % surfaces(:) = tokens%data(1:tokens%size()) - c % rpn(:) = rpn%data(1:rpn%size()) - - call tokens%clear() - call rpn%clear() - end if + call warning("The use of 'surfaces' is deprecated and will be & + &disallowed in a future release. Use 'region' instead. The & + &openmc-update-inputs utility can be used to automatically & + &update geometry.xml files.") + call get_node_value(node_cell, "surfaces", region_spec) + elseif (check_for_node(node_cell, "region")) then + call get_node_value(node_cell, "region", region_spec) end if - if (.not. allocated(c%surfaces)) allocate(c%surfaces(0)) + + if (len_trim(region_spec) > 0) then + ! Create surfaces array from string + call tokenize(region_spec, tokens) + + ! Use shunting-yard algorithm to determine RPN for surface algorithm + call generate_rpn(tokens, rpn) + + ! Copy surface spec and RPN form to cell arrays + allocate(c % region(tokens%size())) + allocate(c % rpn(rpn%size())) + c % region(:) = tokens%data(1:tokens%size()) + c % rpn(:) = rpn%data(1:rpn%size()) + + call tokens%clear() + call rpn%clear() + end if + if (.not. allocated(c%region)) allocate(c%region(0)) if (.not. allocated(c%rpn)) allocate(c%rpn(0)) ! Rotation matrix diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc index 07a02af9ea..2a8d07b8c0 100644 --- a/src/relaxng/geometry.rnc +++ b/src/relaxng/geometry.rnc @@ -9,7 +9,7 @@ element geometry { (element material { ( xsd:int | "void" ) } | attribute material { ( xsd:int | "void" ) }) ) & - (element surfaces { xsd:string } | attribute surfaces { xsd:string })? & + (element region { xsd:string } | attribute region { xsd:string })? & (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? }* diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng index 6a68aa721e..fcb310d0b3 100644 --- a/src/relaxng/geometry.rng +++ b/src/relaxng/geometry.rng @@ -62,10 +62,10 @@ - + - + diff --git a/src/summary.F90 b/src/summary.F90 index 49fe802305..1edb645432 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -113,7 +113,7 @@ contains integer(HID_T) :: universes_group, univ_group integer(HID_T) :: lattices_group, lattice_group real(8), allocatable :: coeffs(:) - character(MAX_LINE_LEN) :: surface_spec + character(MAX_LINE_LEN) :: region_spec type(Cell), pointer :: c class(Surface), pointer :: s type(Universe), pointer :: u @@ -176,26 +176,26 @@ contains end select ! Write list of bounding surfaces - surface_spec = "" - do j = 1, size(c%surfaces) - k = c%surfaces(j) + region_spec = "" + do j = 1, size(c%region) + k = c%region(j) if (k < OP_UNION) then - surface_spec = trim(surface_spec) // " " // to_str(& + region_spec = trim(region_spec) // " " // to_str(& sign(surfaces(abs(k))%obj%id, k)) else select case(k) case (OP_LEFT_PAREN) - surface_spec = trim(surface_spec) // " (" + region_spec = trim(region_spec) // " (" case (OP_RIGHT_PAREN) - surface_spec = trim(surface_spec) // " (" + region_spec = trim(region_spec) // " )" case (OP_COMPLEMENT) - surface_spec = trim(surface_spec) // " ~" + region_spec = trim(region_spec) // " ~" case (OP_UNION) - surface_spec = trim(surface_spec) // " ^" + region_spec = trim(region_spec) // " ^" end select end if end do - call write_dataset(cell_group, "surfaces", adjustl(surface_spec)) + call write_dataset(cell_group, "region", adjustl(region_spec)) call close_group(cell_group) end do CELL_LOOP From dc118afd2dd3ade4e8dae9b1c461aa1506dda78b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 26 Sep 2015 19:52:07 +0700 Subject: [PATCH 19/48] Add Region.from_expression method --- openmc/region.py | 126 ++++++++++++++++++++++++++++++++++++++++++++++ openmc/summary.py | 15 ++---- 2 files changed, 131 insertions(+), 10 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index d75b349803..e39d38b040 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -11,6 +11,132 @@ class Region(object): def __str__(self): return '' + @classmethod + def from_expression(cls, expression, surfaces): + """Generate a region given an infix expression. + + Parameters + ---------- + expression : str + Boolean expression relating surface half-spaces. The possible + operators are union '^', intersection ' ', and complement '~'. For + example, '(1 -2) ^ 3 ~(4 -5)'. + surfaces : dict + Dictionary whose keys are suface IDs that appear in the Boolean + expression and whose values are Surface objects. + + """ + + # Convert the string expression into a list of tokens, i.e., operators + # and surface half-spaces, representing the expression in infix + # notation. + i = 0 + i_start = -1 + tokens = [] + while i < len(expression): + if expression[i] in '()^~ ': + # If special character appears immediately after a non-operator, + # create a token with the apporpriate half-space + if i_start >= 0: + j = int(expression[i_start:i]) + if j < 0: + tokens.append(surfaces[abs(j)].negative) + else: + tokens.append(surfaces[abs(j)].positive) + + if expression[i] in '()^~': + # For everything other than intersection, add the operator + # to the list of tokens + tokens.append(expression[i]) + else: + # For spaces, we need to check the context further. If it + # doesn't appear before a right parentheses or union, it is + # interpreted to be as an intersection operator + while expression[i+1] == ' ': + i += 1 + + if i_start >= 0 and expression[i+1] not in ')^': + tokens.append(' ') + + i_start = -1 + else: + # Check for invalid characters + if expression[i] not in '-0123456789': + raise SyntaxError('Invalid character in expression') + + # If we haven't yet reached the start of a word, start one + if i_start < 0: + i_start = i + i += 1 + + # If we've reached the end and we're still in a word, create a + # half-space token and add it to the list + if i_start >= 0: + j = int(expression[i_start:]) + if j < 0: + tokens.append(surfaces[abs(j)].negative) + else: + tokens.append(surfaces[abs(j)].positive) + + # This function is used below to apply an operator to operands on the + # output queue during the shunting yard algorithm. + def apply_operator(output, operator): + r2 = output.pop() + if operator == ' ': + r1 = output.pop() + output.append(Intersection(r1, r2)) + elif operator == '^': + r1 = output.pop() + output.append(Union(r1, r2)) + elif operator == '~': + output.append(Complement(r2)) + + + # The following is an implementation of the shunting yard algorithm to + # generate an abstract syntax tree for the region expression. + output = [] + stack = [] + precedence = {'^': 1, ' ': 2, '~': 3} + associativity = {'^': 'left', ' ': 'left', '~': 'right'} + for token in tokens: + if token in (' ', '^', '~'): + # Normal operators + while stack: + op = stack[-1] + if (op not in ('(', ')') and + ((associativity[token] == 'right' and + precedence[token] < precedence[op]) or + (associativity[token] == 'left' and + precedence[token] <= precedence[op]))): + apply_operator(output, stack.pop()) + else: + break + stack.append(token) + elif token == '(': + # Left parentheses + stack.append(token) + elif token == ')': + # Right parentheses + while stack[-1] != '(': + apply_operator(output, stack.pop()) + if len(stack) == 0: + raise SyntaxError('Mismatched parentheses in ' + 'region specification.') + stack.pop() + else: + # Surface halfspaces + output.append(token) + while stack: + if stack[-1] in '()': + raise SyntaxError('Mismatched parentheses in region ' + 'specification.') + apply_operator(output, stack.pop()) + + # Since we are generating an abstract syntax tree rather than a reverse + # Polish notation expression, the output queue should have a single item + # at the end + return output[0] + class Intersection(Region): """Intersection of two or more regions. diff --git a/openmc/summary.py b/openmc/summary.py index 3522e707d4..7a7a9457c7 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -1,6 +1,7 @@ import numpy as np import openmc +from openmc.region import Region class Summary(object): @@ -240,16 +241,10 @@ class Summary(object): # Store Cell fill information for after Universe/Lattice creation self._cell_fills[index] = (fill_type, fill) - # Iterate over all Surfaces and add them to the Cell - for token in region.split(): - try: - surface_halfspace = int(token) - halfspace = np.sign(surface_halfspace) - surface_id = abs(surface_halfspace) - surface = self.get_surface_by_id(surface_id) - cell.add_surface(surface, halfspace) - except ValueError: - pass + # Generate Region object given infix expression + if region: + cell.region = Region.from_expression( + region, {s.id: s for s in self.surfaces.values()}) # Add the Cell to the global dictionary of all Cells self.cells[index] = cell From 697e3c557bf9e2809666a29122b4feb74628cedc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 27 Sep 2015 16:08:02 +0700 Subject: [PATCH 20/48] Join intersection/union of multiple half-spaces when possible. --- openmc/region.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index e39d38b040..025babba89 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -84,14 +84,27 @@ class Region(object): r2 = output.pop() if operator == ' ': r1 = output.pop() - output.append(Intersection(r1, r2)) + if isinstance(r1, Intersection) and hasattr(r2, 'surface'): + r1.nodes.append(r2) + output.append(r1) + elif isinstance(r2, Intersection) and hasattr(r1, 'surface'): + r2.nodes.insert(0, r1) + output.append(r2) + else: + output.append(Intersection(r1, r2)) elif operator == '^': r1 = output.pop() - output.append(Union(r1, r2)) + if isinstance(r1, Union) and hasattr(r2, 'surface'): + r1.nodes.append(r2) + output.append(r1) + elif isinstance(r2, Union) and hasattr(r1, 'surface'): + r2.nodes.insert(0, r1) + output.append(r2) + else: + output.append(Union(r1, r2)) elif operator == '~': output.append(Complement(r2)) - # The following is an implementation of the shunting yard algorithm to # generate an abstract syntax tree for the region expression. output = [] From b92198ebc66c08aa24f2359a1003b7c6fbe4cfa7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 11:57:27 +0700 Subject: [PATCH 21/48] Update user's guide documentation with description of region --- docs/source/usersguide/input.rst | 40 +++++++++++++++++++++----------- src/geometry.F90 | 4 ++-- src/input_xml.F90 | 8 +++---- src/string.F90 | 2 +- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index b4d153f184..fbc74de4af 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -720,9 +720,8 @@ Geometry Specification -- geometry.xml The geometry in OpenMC is described using `constructive solid geometry`_ (CSG), also sometimes referred to as combinatorial geometry. CSG allows a user to create complex objects using Boolean operators on a set of simpler surfaces. In -the geometry model, each unique closed volume in defined by its bounding -surfaces. In OpenMC, most `quadratic surfaces`_ can be modeled and used as -bounding surfaces. +the geometry model, each unique volume is defined by its bounding surfaces. In +OpenMC, most `quadratic surfaces`_ can be modeled and used as bounding surfaces. Every geometry.xml must have an XML declaration at the beginning of the file and a root element named geometry. Within the root element the user can define any @@ -745,7 +744,7 @@ number of cells, surfaces, and lattices. Let us look at the following example: 1 0 1 - -1 + -1 @@ -763,7 +762,7 @@ could be written as: - + @@ -787,7 +786,8 @@ Each ```` element can have the following attributes or sub-elements: :type: The type of the surfaces. This can be "x-plane", "y-plane", "z-plane", - "plane", "x-cylinder", "y-cylinder", "z-cylinder", or "sphere". + "plane", "x-cylinder", "y-cylinder", "z-cylinder", "sphere", "x-cone", + "y-cone", or "z-cone". *Default*: None @@ -891,15 +891,29 @@ Each ```` element can have the following attributes or sub-elements: *Default*: None - :surfaces: - A list of the ``ids`` for surfaces that bound this cell, e.g. if the cell - is on the negative side of surface 3 and the positive side of surface 5, the - bounding surfaces would be given as "-3 5". + :region: + A Boolean expression of half-spaces that defines the spatial region which + the cell occupies. Each half-space is identified by the unique ID of the + surface prefixed by `-` or `+` to indicate that it is the negative or + positive half-space, respectively. The `+` sign for a positive half-space + can be omitted. Valid Boolean operators are parentheses, union `^`, + complement `~`, and intersection. Intersection is implicit and indicated by + the presence of whitespace. The order of operator precedence is parentheses, + complement, intersection, and then union. - .. note:: The surface attribute/element can be omitted to make a cell fill - its entire universe. + As an example, the following code gives a cell that is the union of the + negative half-space of surface 3 and the complement of the intersection of + the positive half-space of surface 5 and the negative half-space of surface + 2: - *Default*: No surfaces + .. code-block:: xml + + + + .. note:: The ``region`` attribute/element can be omitted to make a cell + fill its entire universe. + + *Default*: A region filling all space. :rotation: If the cell is filled with a universe, this element specifies the angles in diff --git a/src/geometry.F90 b/src/geometry.F90 index a7a36a5351..2039703421 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -79,7 +79,7 @@ contains ! in the cell. in_cell = stack(i_stack) else - ! This case occurs if there is no surface specification since i_stack will + ! This case occurs if there is no region specification since i_stack will ! still be zero. in_cell = .true. end if @@ -874,7 +874,7 @@ contains do i = 1, n_cells c => cells(i) - ! loop over each surface specification + ! loop through the region specification do j = 1, size(c%region) i_surface = c % region(j) positive = (i_surface > 0) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index f074898f23..50a76afe1b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1137,7 +1137,7 @@ contains ! Use shunting-yard algorithm to determine RPN for surface algorithm call generate_rpn(tokens, rpn) - ! Copy surface spec and RPN form to cell arrays + ! Copy region spec and RPN form to cell arrays allocate(c % region(tokens%size())) allocate(c % rpn(rpn%size())) c % region(:) = tokens%data(1:tokens%size()) @@ -4790,7 +4790,7 @@ contains !=============================================================================== ! GENERATE_RPN implements the shunting-yard algorithm to generate a Reverse -! polish notation (RPN) expression for the surface specification of a cell given +! Polish notation (RPN) expression for the region specification of a cell given ! the infix notation. !=============================================================================== @@ -4844,7 +4844,7 @@ contains ! If we run out of operators without finding a left parenthesis, it ! means there are mismatched parentheses. if (stack%size() == 0) then - call fatal_error('Mimatched parentheses in surface specification') + call fatal_error('Mimatched parentheses in region specification') end if op = stack%data(stack%size()) @@ -4864,7 +4864,7 @@ contains ! If the operator is a parenthesis, it is mismatched if (op >= OP_RIGHT_PAREN) then - call fatal_error('Mimatched parentheses in surface specification') + call fatal_error('Mimatched parentheses in region specification') end if call output%push_back(op) diff --git a/src/string.F90 b/src/string.F90 index 2d690dded5..213627892b 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -123,7 +123,7 @@ contains ! Check for invalid characters if (index('-0123456789', string_(i:i)) == 0) then call fatal_error("Invalid character '" // string_(i:i) // "' in & - &surface specification.") + ®ion specification.") end if ! If we haven't yet reached the start of a word, start a new word From c237f700adcd8436b5db01a4bb84f3e72f34f9f0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 14:02:20 +0700 Subject: [PATCH 22/48] Fix bug in tokenize algorithm The algorithm was failing to add intersections after right parentheses when appropriate. --- openmc/region.py | 13 +++++++++---- src/string.F90 | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index 025babba89..a89658c03f 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -27,6 +27,9 @@ class Region(object): """ + # Strip leading and trailing whitespace + expression = expression.strip() + # Convert the string expression into a list of tokens, i.e., operators # and surface half-spaces, representing the expression in infix # notation. @@ -49,13 +52,15 @@ class Region(object): # to the list of tokens tokens.append(expression[i]) else: - # For spaces, we need to check the context further. If it - # doesn't appear before a right parentheses or union, it is - # interpreted to be as an intersection operator + # Find next non-space character while expression[i+1] == ' ': i += 1 - if i_start >= 0 and expression[i+1] not in ')^': + # If previous token is a halfspace or right parenthesis and next token + # is not a left parenthese or union operator, that implies that the + # whitespace is to be interpreted as an intersection operator + if (i_start >= 0 or tokens[-1] == ')') and \ + expression[i+1] not in ')^': tokens.append(' ') i_start = -1 diff --git a/src/string.F90 b/src/string.F90 index 213627892b..b505aa869b 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -108,10 +108,10 @@ contains i = i + 1 end do - ! If previous token is not an operator and next token is not a left - ! parenthese or union operator, that implies that the whitespace is to - ! be interpreted as an intersection operator - if (i_start > 0) then + ! If previous token is a halfspace or right parenthesis and next token + ! is not a left parenthese or union operator, that implies that the + ! whitespace is to be interpreted as an intersection operator + if (i_start > 0 .or. tokens%data(tokens%size()) == OP_RIGHT_PAREN) then if (index(')^', string_(i+1:i+1)) == 0) then call tokens%push_back(OP_INTERSECTION) end if From 98d745d9ced8bb124288a049797553361e67eb6b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 14:07:38 +0700 Subject: [PATCH 23/48] Add test with complex cells --- tests/test_complex_cell/geometry.xml | 24 ++++++++++++++++++++ tests/test_complex_cell/materials.xml | 23 +++++++++++++++++++ tests/test_complex_cell/results_true.dat | 11 +++++++++ tests/test_complex_cell/settings.xml | 16 +++++++++++++ tests/test_complex_cell/tallies.xml | 7 ++++++ tests/test_complex_cell/test_complex_cell.py | 10 ++++++++ 6 files changed, 91 insertions(+) create mode 100644 tests/test_complex_cell/geometry.xml create mode 100644 tests/test_complex_cell/materials.xml create mode 100644 tests/test_complex_cell/results_true.dat create mode 100644 tests/test_complex_cell/settings.xml create mode 100644 tests/test_complex_cell/tallies.xml create mode 100755 tests/test_complex_cell/test_complex_cell.py diff --git a/tests/test_complex_cell/geometry.xml b/tests/test_complex_cell/geometry.xml new file mode 100644 index 0000000000..1609dad104 --- /dev/null +++ b/tests/test_complex_cell/geometry.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_complex_cell/materials.xml b/tests/test_complex_cell/materials.xml new file mode 100644 index 0000000000..60ec996735 --- /dev/null +++ b/tests/test_complex_cell/materials.xml @@ -0,0 +1,23 @@ + + + + 71c + + + + + + + + + + + + + + + + + + + diff --git a/tests/test_complex_cell/results_true.dat b/tests/test_complex_cell/results_true.dat new file mode 100644 index 0000000000..56e7e409f0 --- /dev/null +++ b/tests/test_complex_cell/results_true.dat @@ -0,0 +1,11 @@ +k-combined: +2.651570E-01 2.116381E-03 +tally 1: +2.639097E+00 +1.394398E+00 +2.743740E+00 +1.506124E+00 +1.041248E+00 +2.177204E-01 +1.087210E-01 +2.365126E-03 diff --git a/tests/test_complex_cell/settings.xml b/tests/test_complex_cell/settings.xml new file mode 100644 index 0000000000..a6fd5da19e --- /dev/null +++ b/tests/test_complex_cell/settings.xml @@ -0,0 +1,16 @@ + + + + + 10 + 5 + 1000 + + + + + -4 -4 -4 4 4 4 + + + + diff --git a/tests/test_complex_cell/tallies.xml b/tests/test_complex_cell/tallies.xml new file mode 100644 index 0000000000..d1a7d387ee --- /dev/null +++ b/tests/test_complex_cell/tallies.xml @@ -0,0 +1,7 @@ + + + + + total + + diff --git a/tests/test_complex_cell/test_complex_cell.py b/tests/test_complex_cell/test_complex_cell.py new file mode 100755 index 0000000000..1777db993e --- /dev/null +++ b/tests/test_complex_cell/test_complex_cell.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +import sys +sys.path.insert(0, '..') +from testing_harness import TestHarness + + +if __name__ == '__main__': + harness = TestHarness('statepoint.10.*', True) + harness.main() From 975771fbfe656df0cad72264fd777ec0c4487b0d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 14:48:29 +0700 Subject: [PATCH 24/48] Combine multiple intersections/unions when parsing region expressions --- openmc/region.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openmc/region.py b/openmc/region.py index a89658c03f..c54d8d3abc 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -95,6 +95,9 @@ class Region(object): elif isinstance(r2, Intersection) and hasattr(r1, 'surface'): r2.nodes.insert(0, r1) output.append(r2) + elif isinstance(r1, Intersection) and isinstance(r2, Intersection): + r1.nodes += r2.nodes + output.append(r1) else: output.append(Intersection(r1, r2)) elif operator == '^': @@ -105,6 +108,9 @@ class Region(object): elif isinstance(r2, Union) and hasattr(r1, 'surface'): r2.nodes.insert(0, r1) output.append(r2) + elif isinstance(r1, Union) and isinstance(r2, Union): + r1.nodes += r2.nodes + output.append(r1) else: output.append(Union(r1, r2)) elif operator == '~': From 6beee729cb28285bad294d292062a513216e0306 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 15:55:02 +0700 Subject: [PATCH 25/48] Update summary file format changing surfaces -> region --- docs/source/usersguide/output/summary.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/output/summary.rst b/docs/source/usersguide/output/summary.rst index 9ced8448a3..d37b2172fa 100644 --- a/docs/source/usersguide/output/summary.rst +++ b/docs/source/usersguide/output/summary.rst @@ -117,9 +117,9 @@ The current revision of the summary file format is 1. Unique ID of the lattice which fills the cell. Only present if fill_type is set to 'lattice'. -**/geometry/cells/cell /surfaces** (*int[]*) +**/geometry/cells/cell /region** (*char[]*) - Surface specification for the cell. + Region specification for the cell. **/geometry/surfaces/surface /index** (*int*) From f093429cedfc765d22ecf562e8417519470f42fd Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 16:53:27 +0700 Subject: [PATCH 26/48] Update example Python inputs, fix exporting to XML for --- examples/python/basic/build-xml.py | 11 ++++---- .../python/lattice/hexagonal/build-xml.py | 15 ++++++----- examples/python/lattice/nested/build-xml.py | 25 ++++++++----------- examples/python/lattice/simple/build-xml.py | 22 ++++++++-------- examples/python/pincell/build-xml.py | 17 +++++-------- examples/python/reflective/build-xml.py | 13 ++++------ openmc/universe.py | 4 +-- 7 files changed, 46 insertions(+), 61 deletions(-) diff --git a/examples/python/basic/build-xml.py b/examples/python/basic/build-xml.py index fb850f3add..865740e13b 100644 --- a/examples/python/basic/build-xml.py +++ b/examples/python/basic/build-xml.py @@ -1,5 +1,5 @@ import openmc - +from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -55,11 +55,10 @@ cell3 = openmc.Cell(cell_id=101, name='cell 3') cell4 = openmc.Cell(cell_id=2, name='cell 4') # Register Surfaces with Cells -cell1.add_surface(surface=surf2, halfspace=-1) -cell2.add_surface(surface=surf1, halfspace=-1) -cell3.add_surface(surface=surf1, halfspace=+1) -cell4.add_surface(surface=surf2, halfspace=+1) -cell4.add_surface(surface=surf3, halfspace=-1) +cell1.region = surf2.negative +cell2.region = surf1.negative +cell3.region = surf1.positive +cell4.region = Intersection(surf2.positive, surf3.negative) # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/lattice/hexagonal/build-xml.py b/examples/python/lattice/hexagonal/build-xml.py index 5cf8eed062..b042e830ad 100644 --- a/examples/python/lattice/hexagonal/build-xml.py +++ b/examples/python/lattice/hexagonal/build-xml.py @@ -1,4 +1,5 @@ import openmc +from openmc.region import Intersection ############################################################################### @@ -68,14 +69,12 @@ cell5 = openmc.Cell(cell_id=600, name='cell 5') cell6 = openmc.Cell(cell_id=601, name='cell 6') # Register Surfaces with Cells -cell1.add_surface(left, halfspace=+1) -cell1.add_surface(right, halfspace=-1) -cell1.add_surface(bottom, halfspace=+1) -cell1.add_surface(top, halfspace=-1) -cell2.add_surface(fuel_surf, halfspace=-1) -cell3.add_surface(fuel_surf, halfspace=+1) -cell5.add_surface(fuel_surf, halfspace=-1) -cell6.add_surface(fuel_surf, halfspace=+1) +cell1.region = Intersection(left.positive, right.negative, + bottom.positive, top.negative) +cell2.region = fuel_surf.negative +cell3.region = fuel_surf.positive +cell5.region = fuel_surf.negative +cell6.region = fuel_surf.positive # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/lattice/nested/build-xml.py b/examples/python/lattice/nested/build-xml.py index 24b5554c0f..f4bc7d1ac9 100644 --- a/examples/python/lattice/nested/build-xml.py +++ b/examples/python/lattice/nested/build-xml.py @@ -1,4 +1,5 @@ import openmc +from openmc.region import Intersection ############################################################################### @@ -67,20 +68,16 @@ cell7 = openmc.Cell(cell_id=301, name='cell 7') cell8 = openmc.Cell(cell_id=302, name='cell 8') # Register Surfaces with Cells -cell1.add_surface(left, halfspace=+1) -cell1.add_surface(right, halfspace=-1) -cell1.add_surface(bottom, halfspace=+1) -cell1.add_surface(top, halfspace=-1) -cell2.add_surface(left, halfspace=+1) -cell2.add_surface(right, halfspace=-1) -cell2.add_surface(bottom, halfspace=+1) -cell2.add_surface(top, halfspace=-1) -cell3.add_surface(fuel1, halfspace=-1) -cell4.add_surface(fuel1, halfspace=+1) -cell5.add_surface(fuel2, halfspace=-1) -cell6.add_surface(fuel2, halfspace=+1) -cell7.add_surface(fuel3, halfspace=-1) -cell8.add_surface(fuel3, halfspace=+1) +cell1.region = Intersection(left.positive, right.negative, + bottom.positive, top.negative) +cell2.region = Intersection(left.positive, right.negative, + bottom.positive, top.negative) +cell3.region = fuel1.negative +cell4.region = fuel1.positive +cell5.region = fuel2.negative +cell6.region = fuel2.positive +cell7.region = fuel3.negative +cell8.region = fuel3.positive # Register Materials with Cells cell3.fill = fuel diff --git a/examples/python/lattice/simple/build-xml.py b/examples/python/lattice/simple/build-xml.py index 57e1f17292..155cfa1cbf 100644 --- a/examples/python/lattice/simple/build-xml.py +++ b/examples/python/lattice/simple/build-xml.py @@ -1,5 +1,5 @@ import openmc - +from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -65,17 +65,15 @@ cell5 = openmc.Cell(cell_id=202, name='cell 5') cell6 = openmc.Cell(cell_id=301, name='cell 6') cell7 = openmc.Cell(cell_id=302, name='cell 7') -# Register Surfaces with Cells -cell1.add_surface(left, halfspace=+1) -cell1.add_surface(right, halfspace=-1) -cell1.add_surface(bottom, halfspace=+1) -cell1.add_surface(top, halfspace=-1) -cell2.add_surface(fuel1, halfspace=-1) -cell3.add_surface(fuel1, halfspace=+1) -cell4.add_surface(fuel2, halfspace=-1) -cell5.add_surface(fuel2, halfspace=+1) -cell6.add_surface(fuel3, halfspace=-1) -cell7.add_surface(fuel3, halfspace=+1) +# Register Regions with Cells +cell1.region = Intersection(left.positive, right.negative, + bottom.positive, top.negative) +cell2.region = fuel1.negative +cell3.region = fuel1.positive +cell4.region = fuel2.negative +cell5.region = fuel2.positive +cell6.region = fuel3.negative +cell7.region = fuel3.positive # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index fc9663b900..d37024db3e 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -1,5 +1,5 @@ import openmc - +from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -133,16 +133,11 @@ clad = openmc.Cell(cell_id=3, name='cell 3') water = openmc.Cell(cell_id=4, name='cell 4') # Register Surfaces with Cells -fuel.add_surface(fuel_or, halfspace=-1) -gap.add_surface(fuel_or, halfspace=+1) -gap.add_surface(clad_ir, halfspace=-1) -clad.add_surface(clad_ir, halfspace=+1) -clad.add_surface(clad_or, halfspace=-1) -water.add_surface(clad_or, halfspace=+1) -water.add_surface(left, halfspace=+1) -water.add_surface(right, halfspace=-1) -water.add_surface(bottom, halfspace=+1) -water.add_surface(top, halfspace=-1) +fuel.region = fuel_or.negative +gap.region = Intersection(fuel_or.positive, clad_ir.negative) +clad.region = Intersection(clad_ir.positive, clad_or.negative) +water.region = Intersection(clad_or.positive, left.positive, right.negative, + bottom.positive, top.negative) # Register Materials with Cells fuel.fill = uo2 diff --git a/examples/python/reflective/build-xml.py b/examples/python/reflective/build-xml.py index 9a182903e1..5a3e861e60 100644 --- a/examples/python/reflective/build-xml.py +++ b/examples/python/reflective/build-xml.py @@ -1,5 +1,5 @@ import openmc - +from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -52,13 +52,10 @@ surf6.boundary_type = 'reflective' # Instantiate Cell cell = openmc.Cell(cell_id=1, name='cell 1') -# Register Surfaces with Cell -cell.add_surface(surface=surf1, halfspace=+1) -cell.add_surface(surface=surf2, halfspace=-1) -cell.add_surface(surface=surf3, halfspace=+1) -cell.add_surface(surface=surf4, halfspace=-1) -cell.add_surface(surface=surf5, halfspace=+1) -cell.add_surface(surface=surf6, halfspace=-1) +# Register Region with Cell +cell.region = Intersection(surf1.positive, surf2.negative, + surf3.positive, surf4.negative, + surf5.positive, surf6.negative) # Register Material with Cell cell.fill = fuel diff --git a/openmc/universe.py b/openmc/universe.py index 79cb90fd00..e9a693bc43 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -327,8 +327,8 @@ class Cell(object): self._fill.create_xml_subelement(xml_element) if self.region is not None: - # Set the surfaces attribute with the region specification - element.set("surfaces", str(self.region)) + # Set the region attribute with the region specification + element.set("region", str(self.region)) # Only surfaces that appear in a region are added to the geometry # file, so the appropriate check is performed here. First we create From adfa0288ce22a01c1cfe3220cb4713638357ff68 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 16:54:48 +0700 Subject: [PATCH 27/48] Update all geometry.xml files to use 'region' --- examples/xml/basic/geometry.xml | 6 +- examples/xml/lattice/nested/geometry.xml | 16 ++-- examples/xml/lattice/simple/geometry.xml | 14 ++-- examples/xml/pincell/geometry.xml | 8 +- tests/test_basic/geometry.xml | 2 +- tests/test_confidence_intervals/geometry.xml | 2 +- tests/test_density_atombcm/geometry.xml | 2 +- tests/test_density_atomcm3/geometry.xml | 2 +- tests/test_density_kgm3/geometry.xml | 2 +- tests/test_density_sum/geometry.xml | 2 +- .../test_eigenvalue_genperbatch/geometry.xml | 2 +- .../test_eigenvalue_no_inactive/geometry.xml | 2 +- tests/test_energy_grid/geometry.xml | 2 +- tests/test_entropy/geometry.xml | 2 +- tests/test_filter_cell/geometry.xml | 56 ++++++------- tests/test_filter_cellborn/geometry.xml | 56 ++++++------- .../case-1/geometry.xml | 6 +- .../case-2/geometry.xml | 18 ++--- .../case-3/geometry.xml | 56 ++++++------- .../case-4/geometry.xml | 8 +- tests/test_filter_energy/geometry.xml | 56 ++++++------- tests/test_filter_energyout/geometry.xml | 56 ++++++------- tests/test_filter_group_transfer/geometry.xml | 56 ++++++------- tests/test_filter_material/geometry.xml | 56 ++++++------- tests/test_filter_mesh_2d/geometry.xml | 56 ++++++------- tests/test_filter_mesh_3d/geometry.xml | 56 ++++++------- tests/test_filter_universe/geometry.xml | 56 ++++++------- tests/test_fixed_source/geometry.xml | 2 +- tests/test_infinite_cell/geometry.xml | 4 +- tests/test_lattice/geometry.xml | 72 ++++++++--------- tests/test_lattice_hex/geometry.xml | 28 +++---- tests/test_lattice_mixed/geometry.xml | 28 +++---- tests/test_lattice_multiple/geometry.xml | 56 ++++++------- tests/test_many_scores/geometry.xml | 56 ++++++------- tests/test_natural_element/geometry.xml | 66 +++++++-------- tests/test_output/geometry.xml | 2 +- .../test_particle_restart_eigval/geometry.xml | 2 +- .../test_particle_restart_fixed/geometry.xml | 2 +- tests/test_plot_background/geometry.xml | 2 +- tests/test_plot_basis/geometry.xml | 6 +- tests/test_plot_colspec/geometry.xml | 2 +- tests/test_plot_mask/geometry.xml | 6 +- tests/test_ptables_off/geometry.xml | 2 +- tests/test_reflective_cone/geometry.xml | 2 +- tests/test_reflective_cylinder/geometry.xml | 2 +- tests/test_reflective_plane/geometry.xml | 2 +- tests/test_reflective_sphere/geometry.xml | 2 +- tests/test_resonance_scattering/geometry.xml | 2 +- tests/test_rotation/geometry.xml | 4 +- tests/test_salphabeta/geometry.xml | 6 +- tests/test_salphabeta_multiple/geometry.xml | 66 +++++++-------- tests/test_score_MT/geometry.xml | 56 ++++++------- tests/test_score_absorption/geometry.xml | 56 ++++++------- tests/test_score_current/geometry.xml | 56 ++++++------- tests/test_score_events/geometry.xml | 56 ++++++------- tests/test_score_fission/geometry.xml | 56 ++++++------- tests/test_score_flux/geometry.xml | 56 ++++++------- tests/test_score_flux_yn/geometry.xml | 56 ++++++------- tests/test_score_kappafission/geometry.xml | 56 ++++++------- tests/test_score_nufission/geometry.xml | 56 ++++++------- tests/test_score_nuscatter/geometry.xml | 56 ++++++------- tests/test_score_nuscatter_n/geometry.xml | 56 ++++++------- tests/test_score_nuscatter_pn/geometry.xml | 56 ++++++------- tests/test_score_nuscatter_yn/geometry.xml | 56 ++++++------- tests/test_score_scatter/geometry.xml | 56 ++++++------- tests/test_score_scatter_n/geometry.xml | 56 ++++++------- tests/test_score_scatter_pn/geometry.xml | 56 ++++++------- tests/test_score_scatter_yn/geometry.xml | 56 ++++++------- tests/test_score_total/geometry.xml | 56 ++++++------- tests/test_score_total_yn/geometry.xml | 56 ++++++------- tests/test_seed/geometry.xml | 2 +- tests/test_source_angle_mono/geometry.xml | 2 +- tests/test_source_energy_maxwell/geometry.xml | 2 +- tests/test_source_energy_mono/geometry.xml | 2 +- tests/test_source_file/geometry.xml | 2 +- tests/test_source_point/geometry.xml | 2 +- tests/test_sourcepoint_batch/geometry.xml | 2 +- tests/test_sourcepoint_interval/geometry.xml | 2 +- tests/test_sourcepoint_latest/geometry.xml | 2 +- tests/test_sourcepoint_restart/geometry.xml | 2 +- tests/test_statepoint_batch/geometry.xml | 2 +- tests/test_statepoint_interval/geometry.xml | 2 +- tests/test_statepoint_restart/geometry.xml | 2 +- tests/test_statepoint_sourcesep/geometry.xml | 2 +- tests/test_survival_biasing/geometry.xml | 2 +- tests/test_tally_assumesep/geometry.xml | 56 ++++++------- tests/test_tally_nuclides/geometry.xml | 4 +- tests/test_trace/geometry.xml | 2 +- tests/test_track_output/geometry.xml | 80 +++++++++---------- tests/test_translation/geometry.xml | 4 +- .../test_trigger_batch_interval/geometry.xml | 4 +- .../geometry.xml | 4 +- tests/test_trigger_no_status/geometry.xml | 4 +- tests/test_trigger_tallies/geometry.xml | 4 +- tests/test_uniform_fs/geometry.xml | 2 +- tests/test_union_energy_grids/geometry.xml | 2 +- tests/test_universe/geometry.xml | 4 +- tests/test_void/geometry.xml | 30 +++---- 98 files changed, 1186 insertions(+), 1186 deletions(-) diff --git a/examples/xml/basic/geometry.xml b/examples/xml/basic/geometry.xml index e9483306c0..b7de2c1346 100644 --- a/examples/xml/basic/geometry.xml +++ b/examples/xml/basic/geometry.xml @@ -2,9 +2,9 @@ - - - + + + diff --git a/examples/xml/lattice/nested/geometry.xml b/examples/xml/lattice/nested/geometry.xml index 9df9b9e931..324f71cb36 100644 --- a/examples/xml/lattice/nested/geometry.xml +++ b/examples/xml/lattice/nested/geometry.xml @@ -1,14 +1,14 @@ - - - - - - - - + + + + + + + + diff --git a/examples/xml/lattice/simple/geometry.xml b/examples/xml/lattice/simple/geometry.xml index c1f8d78644..bda7246c79 100644 --- a/examples/xml/lattice/simple/geometry.xml +++ b/examples/xml/lattice/simple/geometry.xml @@ -1,13 +1,13 @@ - - - - - - - + + + + + + + 4 4 diff --git a/examples/xml/pincell/geometry.xml b/examples/xml/pincell/geometry.xml index 53cb2f15dc..f67f9e74c2 100644 --- a/examples/xml/pincell/geometry.xml +++ b/examples/xml/pincell/geometry.xml @@ -19,9 +19,9 @@ - - - - + + + + diff --git a/tests/test_basic/geometry.xml b/tests/test_basic/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_basic/geometry.xml +++ b/tests/test_basic/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_confidence_intervals/geometry.xml b/tests/test_confidence_intervals/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_confidence_intervals/geometry.xml +++ b/tests/test_confidence_intervals/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_density_atombcm/geometry.xml b/tests/test_density_atombcm/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_density_atombcm/geometry.xml +++ b/tests/test_density_atombcm/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_density_atomcm3/geometry.xml b/tests/test_density_atomcm3/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_density_atomcm3/geometry.xml +++ b/tests/test_density_atomcm3/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_density_kgm3/geometry.xml b/tests/test_density_kgm3/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_density_kgm3/geometry.xml +++ b/tests/test_density_kgm3/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_density_sum/geometry.xml b/tests/test_density_sum/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_density_sum/geometry.xml +++ b/tests/test_density_sum/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_eigenvalue_genperbatch/geometry.xml b/tests/test_eigenvalue_genperbatch/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_eigenvalue_genperbatch/geometry.xml +++ b/tests/test_eigenvalue_genperbatch/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_eigenvalue_no_inactive/geometry.xml b/tests/test_eigenvalue_no_inactive/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_eigenvalue_no_inactive/geometry.xml +++ b/tests/test_eigenvalue_no_inactive/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_energy_grid/geometry.xml b/tests/test_energy_grid/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_energy_grid/geometry.xml +++ b/tests/test_energy_grid/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_entropy/geometry.xml b/tests/test_entropy/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_entropy/geometry.xml +++ b/tests/test_entropy/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_filter_cell/geometry.xml b/tests/test_filter_cell/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_cell/geometry.xml +++ b/tests/test_filter_cell/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_cellborn/geometry.xml b/tests/test_filter_cellborn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_cellborn/geometry.xml +++ b/tests/test_filter_cellborn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_distribcell/case-1/geometry.xml b/tests/test_filter_distribcell/case-1/geometry.xml index 507559615e..34e636e9fc 100644 --- a/tests/test_filter_distribcell/case-1/geometry.xml +++ b/tests/test_filter_distribcell/case-1/geometry.xml @@ -1,9 +1,9 @@ - - - + + + diff --git a/tests/test_filter_distribcell/case-2/geometry.xml b/tests/test_filter_distribcell/case-2/geometry.xml index b6797d65d0..e3aeedd645 100644 --- a/tests/test_filter_distribcell/case-2/geometry.xml +++ b/tests/test_filter_distribcell/case-2/geometry.xml @@ -1,15 +1,15 @@ - - - - - - - - - + + + + + + + + + 2 2 diff --git a/tests/test_filter_distribcell/case-3/geometry.xml b/tests/test_filter_distribcell/case-3/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_distribcell/case-3/geometry.xml +++ b/tests/test_filter_distribcell/case-3/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_distribcell/case-4/geometry.xml b/tests/test_filter_distribcell/case-4/geometry.xml index 4c2a7fd5e4..c835218bc0 100644 --- a/tests/test_filter_distribcell/case-4/geometry.xml +++ b/tests/test_filter_distribcell/case-4/geometry.xml @@ -1,9 +1,9 @@ - - - - + + + + 1.0 3 diff --git a/tests/test_filter_energy/geometry.xml b/tests/test_filter_energy/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_energy/geometry.xml +++ b/tests/test_filter_energy/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_energyout/geometry.xml b/tests/test_filter_energyout/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_energyout/geometry.xml +++ b/tests/test_filter_energyout/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_group_transfer/geometry.xml b/tests/test_filter_group_transfer/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_group_transfer/geometry.xml +++ b/tests/test_filter_group_transfer/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_material/geometry.xml b/tests/test_filter_material/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_material/geometry.xml +++ b/tests/test_filter_material/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_mesh_2d/geometry.xml b/tests/test_filter_mesh_2d/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_mesh_2d/geometry.xml +++ b/tests/test_filter_mesh_2d/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_mesh_3d/geometry.xml b/tests/test_filter_mesh_3d/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_mesh_3d/geometry.xml +++ b/tests/test_filter_mesh_3d/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_filter_universe/geometry.xml b/tests/test_filter_universe/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_filter_universe/geometry.xml +++ b/tests/test_filter_universe/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_fixed_source/geometry.xml b/tests/test_fixed_source/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_fixed_source/geometry.xml +++ b/tests/test_fixed_source/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_infinite_cell/geometry.xml b/tests/test_infinite_cell/geometry.xml index e3f63354c6..90bd2233be 100644 --- a/tests/test_infinite_cell/geometry.xml +++ b/tests/test_infinite_cell/geometry.xml @@ -1,7 +1,7 @@ - + @@ -13,5 +13,5 @@ - + diff --git a/tests/test_lattice/geometry.xml b/tests/test_lattice/geometry.xml index 89af5f1968..809cd6fbb1 100644 --- a/tests/test_lattice/geometry.xml +++ b/tests/test_lattice/geometry.xml @@ -40,11 +40,11 @@ - - - - - + + + + + @@ -85,38 +85,38 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/tests/test_lattice_hex/geometry.xml b/tests/test_lattice_hex/geometry.xml index 8b5915dcdb..cfe39849cb 100644 --- a/tests/test_lattice_hex/geometry.xml +++ b/tests/test_lattice_hex/geometry.xml @@ -14,29 +14,29 @@ - - - - - - - + + + + + + + - - - + + + - - - + + + @@ -194,6 +194,6 @@ + region="-1001 -1002 -1003 -1004 -1005 -1006 1007 -1008"/> diff --git a/tests/test_lattice_mixed/geometry.xml b/tests/test_lattice_mixed/geometry.xml index 524e4d9289..41aa05d411 100644 --- a/tests/test_lattice_mixed/geometry.xml +++ b/tests/test_lattice_mixed/geometry.xml @@ -15,29 +15,29 @@ - - - - - - - + + + + + + + - - - + + + - - - + + + @@ -151,6 +151,6 @@ + region="-1001 -1002 -1003 -1004 -1005 -1006 1007 -1008"/> diff --git a/tests/test_lattice_multiple/geometry.xml b/tests/test_lattice_multiple/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_lattice_multiple/geometry.xml +++ b/tests/test_lattice_multiple/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_many_scores/geometry.xml b/tests/test_many_scores/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_many_scores/geometry.xml +++ b/tests/test_many_scores/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_natural_element/geometry.xml b/tests/test_natural_element/geometry.xml index 2d427d8cb3..b6b4bd817b 100644 --- a/tests/test_natural_element/geometry.xml +++ b/tests/test_natural_element/geometry.xml @@ -45,50 +45,50 @@ - - + + - - + + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + diff --git a/tests/test_output/geometry.xml b/tests/test_output/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_output/geometry.xml +++ b/tests/test_output/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_particle_restart_eigval/geometry.xml b/tests/test_particle_restart_eigval/geometry.xml index 52fea4df64..c86e016c6e 100644 --- a/tests/test_particle_restart_eigval/geometry.xml +++ b/tests/test_particle_restart_eigval/geometry.xml @@ -4,6 +4,6 @@ - + diff --git a/tests/test_particle_restart_fixed/geometry.xml b/tests/test_particle_restart_fixed/geometry.xml index 52fea4df64..c86e016c6e 100644 --- a/tests/test_particle_restart_fixed/geometry.xml +++ b/tests/test_particle_restart_fixed/geometry.xml @@ -4,6 +4,6 @@ - + diff --git a/tests/test_plot_background/geometry.xml b/tests/test_plot_background/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_plot_background/geometry.xml +++ b/tests/test_plot_background/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_plot_basis/geometry.xml b/tests/test_plot_basis/geometry.xml index ac00ebaf51..83619d9f78 100644 --- a/tests/test_plot_basis/geometry.xml +++ b/tests/test_plot_basis/geometry.xml @@ -6,8 +6,8 @@ - - - + + + diff --git a/tests/test_plot_colspec/geometry.xml b/tests/test_plot_colspec/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_plot_colspec/geometry.xml +++ b/tests/test_plot_colspec/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_plot_mask/geometry.xml b/tests/test_plot_mask/geometry.xml index ac00ebaf51..83619d9f78 100644 --- a/tests/test_plot_mask/geometry.xml +++ b/tests/test_plot_mask/geometry.xml @@ -6,8 +6,8 @@ - - - + + + diff --git a/tests/test_ptables_off/geometry.xml b/tests/test_ptables_off/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_ptables_off/geometry.xml +++ b/tests/test_ptables_off/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_reflective_cone/geometry.xml b/tests/test_reflective_cone/geometry.xml index 5453e16155..f5499fbb61 100644 --- a/tests/test_reflective_cone/geometry.xml +++ b/tests/test_reflective_cone/geometry.xml @@ -2,6 +2,6 @@ - + diff --git a/tests/test_reflective_cylinder/geometry.xml b/tests/test_reflective_cylinder/geometry.xml index ce1082f3d6..e6aed65daf 100644 --- a/tests/test_reflective_cylinder/geometry.xml +++ b/tests/test_reflective_cylinder/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_reflective_plane/geometry.xml b/tests/test_reflective_plane/geometry.xml index 4544414365..0dc5c29ab5 100644 --- a/tests/test_reflective_plane/geometry.xml +++ b/tests/test_reflective_plane/geometry.xml @@ -8,6 +8,6 @@ - + diff --git a/tests/test_reflective_sphere/geometry.xml b/tests/test_reflective_sphere/geometry.xml index 5f36d2396f..0dc98eba69 100644 --- a/tests/test_reflective_sphere/geometry.xml +++ b/tests/test_reflective_sphere/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_resonance_scattering/geometry.xml b/tests/test_resonance_scattering/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_resonance_scattering/geometry.xml +++ b/tests/test_resonance_scattering/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_rotation/geometry.xml b/tests/test_rotation/geometry.xml index 7306dabdef..2226178771 100644 --- a/tests/test_rotation/geometry.xml +++ b/tests/test_rotation/geometry.xml @@ -5,7 +5,7 @@ - - + + diff --git a/tests/test_salphabeta/geometry.xml b/tests/test_salphabeta/geometry.xml index ef05988425..f9caa6c883 100644 --- a/tests/test_salphabeta/geometry.xml +++ b/tests/test_salphabeta/geometry.xml @@ -6,8 +6,8 @@ - - - + + + diff --git a/tests/test_salphabeta_multiple/geometry.xml b/tests/test_salphabeta_multiple/geometry.xml index 63f69f7438..13eb601660 100644 --- a/tests/test_salphabeta_multiple/geometry.xml +++ b/tests/test_salphabeta_multiple/geometry.xml @@ -45,52 +45,52 @@ - + - + - - + + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - + + + diff --git a/tests/test_score_MT/geometry.xml b/tests/test_score_MT/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_MT/geometry.xml +++ b/tests/test_score_MT/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_absorption/geometry.xml b/tests/test_score_absorption/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_absorption/geometry.xml +++ b/tests/test_score_absorption/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_current/geometry.xml b/tests/test_score_current/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_current/geometry.xml +++ b/tests/test_score_current/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_events/geometry.xml b/tests/test_score_events/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_events/geometry.xml +++ b/tests/test_score_events/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_fission/geometry.xml b/tests/test_score_fission/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_fission/geometry.xml +++ b/tests/test_score_fission/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_flux/geometry.xml b/tests/test_score_flux/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_flux/geometry.xml +++ b/tests/test_score_flux/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_flux_yn/geometry.xml b/tests/test_score_flux_yn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_flux_yn/geometry.xml +++ b/tests/test_score_flux_yn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_kappafission/geometry.xml b/tests/test_score_kappafission/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_kappafission/geometry.xml +++ b/tests/test_score_kappafission/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_nufission/geometry.xml b/tests/test_score_nufission/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_nufission/geometry.xml +++ b/tests/test_score_nufission/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_nuscatter/geometry.xml b/tests/test_score_nuscatter/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_nuscatter/geometry.xml +++ b/tests/test_score_nuscatter/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_nuscatter_n/geometry.xml b/tests/test_score_nuscatter_n/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_nuscatter_n/geometry.xml +++ b/tests/test_score_nuscatter_n/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_nuscatter_pn/geometry.xml b/tests/test_score_nuscatter_pn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_nuscatter_pn/geometry.xml +++ b/tests/test_score_nuscatter_pn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_nuscatter_yn/geometry.xml b/tests/test_score_nuscatter_yn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_nuscatter_yn/geometry.xml +++ b/tests/test_score_nuscatter_yn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_scatter/geometry.xml b/tests/test_score_scatter/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_scatter/geometry.xml +++ b/tests/test_score_scatter/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_scatter_n/geometry.xml b/tests/test_score_scatter_n/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_scatter_n/geometry.xml +++ b/tests/test_score_scatter_n/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_scatter_pn/geometry.xml b/tests/test_score_scatter_pn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_scatter_pn/geometry.xml +++ b/tests/test_score_scatter_pn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_scatter_yn/geometry.xml b/tests/test_score_scatter_yn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_scatter_yn/geometry.xml +++ b/tests/test_score_scatter_yn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_total/geometry.xml b/tests/test_score_total/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_total/geometry.xml +++ b/tests/test_score_total/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_score_total_yn/geometry.xml b/tests/test_score_total_yn/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_score_total_yn/geometry.xml +++ b/tests/test_score_total_yn/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_seed/geometry.xml b/tests/test_seed/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_seed/geometry.xml +++ b/tests/test_seed/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_source_angle_mono/geometry.xml b/tests/test_source_angle_mono/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_source_angle_mono/geometry.xml +++ b/tests/test_source_angle_mono/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_source_energy_maxwell/geometry.xml b/tests/test_source_energy_maxwell/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_source_energy_maxwell/geometry.xml +++ b/tests/test_source_energy_maxwell/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_source_energy_mono/geometry.xml b/tests/test_source_energy_mono/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_source_energy_mono/geometry.xml +++ b/tests/test_source_energy_mono/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_source_file/geometry.xml b/tests/test_source_file/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_source_file/geometry.xml +++ b/tests/test_source_file/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_source_point/geometry.xml b/tests/test_source_point/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_source_point/geometry.xml +++ b/tests/test_source_point/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_sourcepoint_batch/geometry.xml b/tests/test_sourcepoint_batch/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_sourcepoint_batch/geometry.xml +++ b/tests/test_sourcepoint_batch/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_sourcepoint_interval/geometry.xml b/tests/test_sourcepoint_interval/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_sourcepoint_interval/geometry.xml +++ b/tests/test_sourcepoint_interval/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_sourcepoint_latest/geometry.xml b/tests/test_sourcepoint_latest/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_sourcepoint_latest/geometry.xml +++ b/tests/test_sourcepoint_latest/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_sourcepoint_restart/geometry.xml b/tests/test_sourcepoint_restart/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_sourcepoint_restart/geometry.xml +++ b/tests/test_sourcepoint_restart/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_statepoint_batch/geometry.xml b/tests/test_statepoint_batch/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_statepoint_batch/geometry.xml +++ b/tests/test_statepoint_batch/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_statepoint_interval/geometry.xml b/tests/test_statepoint_interval/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_statepoint_interval/geometry.xml +++ b/tests/test_statepoint_interval/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_statepoint_restart/geometry.xml b/tests/test_statepoint_restart/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_statepoint_restart/geometry.xml +++ b/tests/test_statepoint_restart/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_statepoint_sourcesep/geometry.xml b/tests/test_statepoint_sourcesep/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_statepoint_sourcesep/geometry.xml +++ b/tests/test_statepoint_sourcesep/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_survival_biasing/geometry.xml b/tests/test_survival_biasing/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_survival_biasing/geometry.xml +++ b/tests/test_survival_biasing/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_tally_assumesep/geometry.xml b/tests/test_tally_assumesep/geometry.xml index b85dd04df9..f6f067aadd 100644 --- a/tests/test_tally_assumesep/geometry.xml +++ b/tests/test_tally_assumesep/geometry.xml @@ -21,50 +21,50 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - + - + - + diff --git a/tests/test_tally_nuclides/geometry.xml b/tests/test_tally_nuclides/geometry.xml index 65954a7853..7c3aefe888 100644 --- a/tests/test_tally_nuclides/geometry.xml +++ b/tests/test_tally_nuclides/geometry.xml @@ -4,7 +4,7 @@ - - + + diff --git a/tests/test_trace/geometry.xml b/tests/test_trace/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_trace/geometry.xml +++ b/tests/test_trace/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_track_output/geometry.xml b/tests/test_track_output/geometry.xml index 3b5a493115..5b16fe26cd 100644 --- a/tests/test_track_output/geometry.xml +++ b/tests/test_track_output/geometry.xml @@ -15,22 +15,22 @@ - - + + - - - + + + - - + + - + @@ -56,7 +56,7 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - + @@ -80,10 +80,10 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - + + + + @@ -107,10 +107,10 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - + + + + @@ -136,7 +136,7 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - + @@ -160,10 +160,10 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - + + + + @@ -187,10 +187,10 @@ 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - - - - + + + + @@ -214,10 +214,10 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - + + + + @@ -242,10 +242,10 @@ 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - - - - + + + + @@ -269,10 +269,10 @@ 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - + + + + @@ -299,7 +299,7 @@ - - + + diff --git a/tests/test_translation/geometry.xml b/tests/test_translation/geometry.xml index 1390691dcf..e2cdf23916 100644 --- a/tests/test_translation/geometry.xml +++ b/tests/test_translation/geometry.xml @@ -5,7 +5,7 @@ - - + + diff --git a/tests/test_trigger_batch_interval/geometry.xml b/tests/test_trigger_batch_interval/geometry.xml index 65954a7853..7c3aefe888 100644 --- a/tests/test_trigger_batch_interval/geometry.xml +++ b/tests/test_trigger_batch_interval/geometry.xml @@ -4,7 +4,7 @@ - - + + diff --git a/tests/test_trigger_no_batch_interval/geometry.xml b/tests/test_trigger_no_batch_interval/geometry.xml index 65954a7853..7c3aefe888 100644 --- a/tests/test_trigger_no_batch_interval/geometry.xml +++ b/tests/test_trigger_no_batch_interval/geometry.xml @@ -4,7 +4,7 @@ - - + + diff --git a/tests/test_trigger_no_status/geometry.xml b/tests/test_trigger_no_status/geometry.xml index 65954a7853..7c3aefe888 100644 --- a/tests/test_trigger_no_status/geometry.xml +++ b/tests/test_trigger_no_status/geometry.xml @@ -4,7 +4,7 @@ - - + + diff --git a/tests/test_trigger_tallies/geometry.xml b/tests/test_trigger_tallies/geometry.xml index 65954a7853..7c3aefe888 100644 --- a/tests/test_trigger_tallies/geometry.xml +++ b/tests/test_trigger_tallies/geometry.xml @@ -4,7 +4,7 @@ - - + + diff --git a/tests/test_uniform_fs/geometry.xml b/tests/test_uniform_fs/geometry.xml index b9b880d08a..90cf354614 100644 --- a/tests/test_uniform_fs/geometry.xml +++ b/tests/test_uniform_fs/geometry.xml @@ -8,6 +8,6 @@ - + diff --git a/tests/test_union_energy_grids/geometry.xml b/tests/test_union_energy_grids/geometry.xml index 612e46132e..bc56030e18 100644 --- a/tests/test_union_energy_grids/geometry.xml +++ b/tests/test_union_energy_grids/geometry.xml @@ -3,6 +3,6 @@ - + diff --git a/tests/test_universe/geometry.xml b/tests/test_universe/geometry.xml index a0b8b2f4fc..03f507bec0 100644 --- a/tests/test_universe/geometry.xml +++ b/tests/test_universe/geometry.xml @@ -5,7 +5,7 @@ - - + + diff --git a/tests/test_void/geometry.xml b/tests/test_void/geometry.xml index 99b78586a5..48a72c7c31 100644 --- a/tests/test_void/geometry.xml +++ b/tests/test_void/geometry.xml @@ -21,20 +21,20 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + From 463991ce86760b479c6a6443f4ebed21d67d3683 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 17:01:33 +0700 Subject: [PATCH 28/48] Update Jupyter notebooks in documentation --- .../pythonapi/examples/pandas-dataframes.ipynb | 18 ++++++++---------- .../pythonapi/examples/post-processing.ipynb | 18 ++++++++---------- .../pythonapi/examples/tally-arithmetic.ipynb | 18 ++++++++---------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/docs/source/pythonapi/examples/pandas-dataframes.ipynb b/docs/source/pythonapi/examples/pandas-dataframes.ipynb index cb63e2ac39..357f10620f 100644 --- a/docs/source/pythonapi/examples/pandas-dataframes.ipynb +++ b/docs/source/pythonapi/examples/pandas-dataframes.ipynb @@ -26,6 +26,7 @@ "import openmc\n", "from openmc.statepoint import StatePoint\n", "from openmc.summary import Summary\n", + "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -172,20 +173,20 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.add_surface(fuel_outer_radius, halfspace=-1)\n", + "fuel_cell.region = fuel_outer_radius.negative\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.add_surface(fuel_outer_radius, halfspace=+1)\n", - "clad_cell.add_surface(clad_outer_radius, halfspace=-1)\n", + "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", + " clad_outer_radius.negative)\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator_cell.add_surface(clad_outer_radius, halfspace=+1)\n", + "moderator_cell.region = clad_outer_radius.positive\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -232,12 +233,9 @@ "root_cell.fill = assembly\n", "\n", "# Add boundary planes\n", - "root_cell.add_surface(min_x, halfspace=+1)\n", - "root_cell.add_surface(max_x, halfspace=-1)\n", - "root_cell.add_surface(min_y, halfspace=+1)\n", - "root_cell.add_surface(max_y, halfspace=-1)\n", - "root_cell.add_surface(min_z, halfspace=+1)\n", - "root_cell.add_surface(max_z, halfspace=-1)\n", + "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", + " min_y.positive, max_y.negative,\n", + " min_z.positive, max_z.negative)\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", diff --git a/docs/source/pythonapi/examples/post-processing.ipynb b/docs/source/pythonapi/examples/post-processing.ipynb index 1bd7ee49a6..e83c5bb8a1 100644 --- a/docs/source/pythonapi/examples/post-processing.ipynb +++ b/docs/source/pythonapi/examples/post-processing.ipynb @@ -21,6 +21,7 @@ "\n", "import openmc\n", "from openmc.statepoint import StatePoint\n", + "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -167,20 +168,20 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.add_surface(fuel_outer_radius, halfspace=-1)\n", + "fuel_cell.region = fuel_outer_radius.negative\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.add_surface(fuel_outer_radius, halfspace=+1)\n", - "clad_cell.add_surface(clad_outer_radius, halfspace=-1)\n", + "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", + " clad_outer_radius.negative)\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator_cell.add_surface(clad_outer_radius, halfspace=+1)\n", + "moderator.region = clad_outer_radius.positive\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -204,12 +205,9 @@ "root_cell.fill = pin_cell_universe\n", "\n", "# Add boundary planes\n", - "root_cell.add_surface(min_x, halfspace=+1)\n", - "root_cell.add_surface(max_x, halfspace=-1)\n", - "root_cell.add_surface(min_y, halfspace=+1)\n", - "root_cell.add_surface(max_y, halfspace=-1)\n", - "root_cell.add_surface(min_z, halfspace=+1)\n", - "root_cell.add_surface(max_z, halfspace=-1)\n", + "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", + " min_y.positive, max_y.negative,\n", + " min_z.positive, max_z.negative)\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", diff --git a/docs/source/pythonapi/examples/tally-arithmetic.ipynb b/docs/source/pythonapi/examples/tally-arithmetic.ipynb index 2f32f3d9a7..b5ba328a05 100644 --- a/docs/source/pythonapi/examples/tally-arithmetic.ipynb +++ b/docs/source/pythonapi/examples/tally-arithmetic.ipynb @@ -36,6 +36,7 @@ "import openmc\n", "from openmc.statepoint import StatePoint\n", "from openmc.summary import Summary\n", + "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -182,20 +183,20 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.add_surface(fuel_outer_radius, halfspace=-1)\n", + "fuel_cell.region = fuel_outer_radius.negative\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.add_surface(fuel_outer_radius, halfspace=+1)\n", - "clad_cell.add_surface(clad_outer_radius, halfspace=-1)\n", + "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", + " clad_outer_radius.negative)\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator_cell.add_surface(clad_outer_radius, halfspace=+1)\n", + "moderator_cell.region = clad_outer_radius.positive\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -219,12 +220,9 @@ "root_cell.fill = pin_cell_universe\n", "\n", "# Add boundary planes\n", - "root_cell.add_surface(min_x, halfspace=+1)\n", - "root_cell.add_surface(max_x, halfspace=-1)\n", - "root_cell.add_surface(min_y, halfspace=+1)\n", - "root_cell.add_surface(max_y, halfspace=-1)\n", - "root_cell.add_surface(min_z, halfspace=+1)\n", - "root_cell.add_surface(max_z, halfspace=-1)\n", + "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", + " min_y.positive, max_y.negative,\n", + " min_z.positive, max_z.negative)\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", From 6c6676cc14861abb84b732ac607d59df9c60b80e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Sep 2015 19:01:10 +0700 Subject: [PATCH 29/48] Have openmc-update-inputs change 'surfaces' to 'region' --- examples/xml/basic/geometry.xml | 4 ++-- examples/xml/reflective/geometry.xml | 8 ++++---- scripts/openmc-update-inputs | 27 ++++++++++++++++++--------- tests/test_cmfd_feed/geometry.xml | 4 ++-- tests/test_cmfd_nofeed/geometry.xml | 4 ++-- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/examples/xml/basic/geometry.xml b/examples/xml/basic/geometry.xml index b7de2c1346..b30884f8ca 100644 --- a/examples/xml/basic/geometry.xml +++ b/examples/xml/basic/geometry.xml @@ -5,11 +5,11 @@ - + - + diff --git a/examples/xml/reflective/geometry.xml b/examples/xml/reflective/geometry.xml index 664ef0705f..51cdf1ecb0 100644 --- a/examples/xml/reflective/geometry.xml +++ b/examples/xml/reflective/geometry.xml @@ -5,15 +5,15 @@ 0 1 - 1 -2 3 -4 5 -6 + 1 -2 3 -4 5 -6 - + - + - + diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index f2e5308d02..1ff70d0505 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -1,14 +1,15 @@ #!/usr/bin/env python """Update OpenMC's input XML files to the latest format. -Usage information can be obtained by running 'update_inputs.py --help': +Usage information can be obtained by running 'openmc-update-inputs --help': -usage: update_lattices.py [-h] IN [IN ...] +usage: openmc-update-inputs [-h] IN [IN ...] -Update lattices in geometry.xml files to the latest format. This will remove -'outside' attributes/elements and replace them with 'outer' attributes. Note -that this script will not delete the given files; it will append '.original' -to the given files and write new ones. +Update geometry.xml files to the latest format. This will remove 'outside' +attributes/elements from lattices and replace them with 'outer' attributes. For +'cell' elements, any 'surfaces' attributes/elements will be renamed +'region'. Note that this script will not delete the given files; it will append +'.original' to the given files and write new ones. positional arguments: IN Input geometry.xml file(s). @@ -173,9 +174,6 @@ def update_geometry(geometry_root): root = geometry_root was_updated = False - # Ignore files that do not contain lattices. - if all([child.tag != 'lattice' for child in root]): return False - # Get a set of already-used universe and cell ids. uids = get_universe_ids(root) cids = get_cell_ids(root) @@ -233,6 +231,17 @@ def update_geometry(geometry_root): del lat.attrib['width'] was_updated = True + # Change 'surfaces' to 'region' in cell definitions + for cell in root.iter('cell'): + elem = cell.find('surfaces') + if elem is not None: + elem.tag = 'region' + was_updated = True + if 'surfaces' in cell.attrib: + cell.attrib['region'] = cell.attrib['surfaces'] + del cell.attrib['surfaces'] + was_updated = True + return was_updated diff --git a/tests/test_cmfd_feed/geometry.xml b/tests/test_cmfd_feed/geometry.xml index 57c4aa2285..73ea679c4c 100644 --- a/tests/test_cmfd_feed/geometry.xml +++ b/tests/test_cmfd_feed/geometry.xml @@ -4,7 +4,7 @@ 0 - -1 2 -3 4 -5 6 + -1 2 -3 4 -5 6 1 @@ -39,5 +39,5 @@ -1 reflective - + diff --git a/tests/test_cmfd_nofeed/geometry.xml b/tests/test_cmfd_nofeed/geometry.xml index 57c4aa2285..73ea679c4c 100644 --- a/tests/test_cmfd_nofeed/geometry.xml +++ b/tests/test_cmfd_nofeed/geometry.xml @@ -4,7 +4,7 @@ 0 - -1 2 -3 4 -5 6 + -1 2 -3 4 -5 6 1 @@ -39,5 +39,5 @@ -1 reflective - + From e37d63498676d0fc3219dbe4bd6c73573dbb256b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 29 Sep 2015 15:07:39 +0700 Subject: [PATCH 30/48] Fix OpenCG compatibility module to work with simple cells --- openmc/opencg_compatible.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/openmc/opencg_compatible.py b/openmc/opencg_compatible.py index 65e980c003..9439a6eaf4 100644 --- a/openmc/opencg_compatible.py +++ b/openmc/opencg_compatible.py @@ -9,6 +9,8 @@ except ImportError: raise ImportError(msg) import openmc +from openmc.region import Intersection +from openmc.surface import Halfspace # A dictionary of all OpenMC Materials created @@ -480,12 +482,24 @@ def get_opencg_cell(openmc_cell): if openmc_cell._translation is not None: opencg_cell.setTranslation(openmc_cell._translation) - surfaces = openmc_cell._surfaces - - for surface_id in surfaces: - surface = surfaces[surface_id][0] - halfspace = surfaces[surface_id][1] + # Add surfaces to OpenCG cell from OpenMC cell region. Right now this only + # works if the region is a single half-space or an intersection of + # half-spaces, i.e., no complex cells. + region = openmc_cell.region + if isinstance(region, Halfspace): + surface = region.surface + halfspace = -1 if region.side == '-' else 1 opencg_cell.addSurface(get_opencg_surface(surface), halfspace) + elif isinstance(region, Intersection): + for node in region.nodes: + if not isinstance(node, Halfspace): + raise NotImplementedError("Complex cells not yet supported " + "in OpenCG.") + surface = node.surface + halfspace = -1 if node.side == '-' else 1 + opencg_cell.addSurface(get_opencg_surface(surface), halfspace) + else: + raise NotImplementedError("Complex cells not yet supported in OpenCG.") # Add the OpenMC Cell to the global collection of all OpenMC Cells OPENMC_CELLS[cell_id] = openmc_cell From 817494798ef844f5c83cbac5b8ad85183ededad8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 29 Sep 2015 15:37:31 +0700 Subject: [PATCH 31/48] Add better description in stl_vector module --- src/stl_vector.F90 | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/stl_vector.F90 b/src/stl_vector.F90 index f5c11ff37f..8038628fb6 100644 --- a/src/stl_vector.F90 +++ b/src/stl_vector.F90 @@ -1,7 +1,39 @@ module stl_vector ! This module provides derived types that are meant to mimic the - ! std::vector type in C++ + ! std::vector type in C++. The vector type has numerous advantages over + ! simple arrays and linked lists in that storage can grow and shrink + ! dynamically, yet it is still contiguous in memory. Vectors can be filled + ! element-by-element with automatic memory allocation in amortized constant + ! time. In the implementation here, we grow the vector by a factor of 1.5 each + ! time the capacity is exceed. + ! + ! The member functions which have been implemented here are: + ! + ! capacity -- Returns the size of the storage space currently allocated for + ! the vector + ! + ! clear -- Remove all elements from the vector, leaving it with a size of + ! 0. Note that this doesn't imply that storage is deallocated. + ! + ! initialize -- Set the storage size of the vector and optionally fill it with + ! a particular value. + ! + ! pop_back -- Remove the last element of the vector, reducing the size by one. + ! + ! push_back -- Add a new element at the end of the vector. This increases the + ! size of the vector by one. Note that the underlying storage is + ! reallocated only if the size exceeds the capacity. + ! + ! reserve -- Requests that the capacity of the vector be a certain size. + ! + ! resize -- Resize the vector so it contains n elements. If n is larger than + ! the current size, an optional fill value can be used to set the + ! extra elements. + ! + ! shrink_to_fit -- Request that the capacity be reduced to fit the size. + ! + ! size -- Returns the number of elements in the vector. implicit none private @@ -195,8 +227,8 @@ contains subroutine clear_real(this) class(VectorReal), intent(inout) :: this - ! Since integer is trivially destructible, we only need to set size to zero - ! and can leave capacity as is + ! Since real is trivially destructible, we only need to set size to zero and + ! can leave capacity as is this%size_ = 0 end subroutine clear_real From e70a5af63e66eb611dad57271643b3d3c37a300e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 29 Sep 2015 15:39:54 +0700 Subject: [PATCH 32/48] Make Region.from_expression a @staticmethod rather than @classmethod --- openmc/region.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index c54d8d3abc..f1926cdc2a 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -11,8 +11,8 @@ class Region(object): def __str__(self): return '' - @classmethod - def from_expression(cls, expression, surfaces): + @staticmethod + def from_expression(expression, surfaces): """Generate a region given an infix expression. Parameters From d05b2a0f769e031a0763921073aa3a1afeda0445 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 29 Sep 2015 15:56:36 +0700 Subject: [PATCH 33/48] Make reflect() pure and add a comment describing it --- src/surface_header.F90 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 8941fed725..18ad030a2e 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -205,7 +205,14 @@ contains end if end function sense - subroutine reflect(this, xyz, uvw) +!=============================================================================== +! REFLECT determines the direction a particle will travel if it is specularly +! reflected from the surface at a given position and direction. The position is +! needed because the reflection is performed using the surface normal, which +! depends on the position for second-order surfaces. +!=============================================================================== + + pure subroutine reflect(this, xyz, uvw) class(Surface), intent(in) :: this real(8), intent(in) :: xyz(3) real(8), intent(inout) :: uvw(3) From bece870f8514f4c853e52c524a0bc2615544959e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 29 Sep 2015 17:18:12 +0700 Subject: [PATCH 34/48] Split cell_contains into simple_cell_contains and complex_cell_contains. The simple_cell_contains function is optimized to take advantage of the fact that short circuit evaluation can be used. --- src/geometry.F90 | 58 ++++++++++++++++++++++++++++++++++++++--- src/geometry_header.F90 | 1 + src/input_xml.F90 | 7 +++++ 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 2039703421..aec506df60 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -20,8 +20,14 @@ contains ! CELL_CONTAINS determines if a cell contains the particle at a given ! location. The bounds of the cell are detemined by a logical expression ! involving surface half-spaces. At initialization, the expression was converted -! to RPN notation. In cell_contains, we evaluate the RPN expression using a -! stack, similar to how a RPN calculator would work. +! to RPN notation. +! +! The function is split into two cases, one for simple cells (those involving +! only the intersection of half-spaces) and one for complex cells. Simple cells +! can be evaluated with short circuit evaluation, i.e., as soon as we know that +! one half-space is not satisfied, we can exit. This provides a performance +! benefit for the common case. In complex_cell_contains, we evaluate the RPN +! expression using a stack, similar to how a RPN calculator would work. !=============================================================================== pure function cell_contains(c, p) result(in_cell) @@ -29,6 +35,52 @@ contains type(Particle), intent(in) :: p logical :: in_cell + if (c%simple) then + in_cell = simple_cell_contains(c, p) + else + in_cell = complex_cell_contains(c, p) + end if + end function cell_contains + + pure function simple_cell_contains(c, p) result(in_cell) + type(Cell), intent(in) :: c + type(Particle), intent(in) :: p + logical :: in_cell + + integer :: i + integer :: token + logical :: actual_sense ! sense of particle wrt surface + + in_cell = .true. + do i = 1, size(c%rpn) + token = c%rpn(i) + if (token < OP_UNION) then + ! If the token is not an operator, evaluate the sense of particle with + ! respect to the surface and see if the token matches the sense. If the + ! particle's surface attribute is set and matches the token, that + ! overrides the determination based on sense(). + if (token == p%surface) then + cycle + elseif (-token == p%surface) then + in_cell = .false. + exit + else + actual_sense = surfaces(abs(token))%obj%sense(& + p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) + if (actual_sense .neqv. (token > 0)) then + in_cell = .false. + exit + end if + end if + end if + end do + end function simple_cell_contains + + pure function complex_cell_contains(c, p) result(in_cell) + type(Cell), intent(in) :: c + type(Particle), intent(in) :: p + logical :: in_cell + integer :: i integer :: token logical :: b1, b2 @@ -83,7 +135,7 @@ contains ! still be zero. in_cell = .true. end if - end function cell_contains + end function complex_cell_contains !=============================================================================== ! CHECK_CELL_OVERLAP checks for overlapping cells at the current particle's diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index c9889a5c82..20e437cac7 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -134,6 +134,7 @@ module geometry_header ! Boolean expression of half-spaces integer, allocatable :: rpn(:) ! Reverse Polish notation for region ! expression + logical :: simple ! Is the region simple (intersections only) ! Rotation matrix and translation vector real(8), allocatable :: translation(:) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 50a76afe1b..8a77eaf354 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1149,6 +1149,13 @@ contains if (.not. allocated(c%region)) allocate(c%region(0)) if (.not. allocated(c%rpn)) allocate(c%rpn(0)) + ! Check if this is a simple cell + if (any(c%rpn == OP_COMPLEMENT) .or. any(c%rpn == OP_UNION)) then + c%simple = .false. + else + c%simple = .true. + end if + ! Rotation matrix if (check_for_node(node_cell, "rotation")) then ! Rotations can only be applied to cells that are being filled with From df44be36325fa0a120272cf086880253858566be Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 2 Oct 2015 11:33:04 +0700 Subject: [PATCH 35/48] Fix bug in XPlane.x0 --- openmc/surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/surface.py b/openmc/surface.py index 0be62fbf5a..98ec903c7c 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -287,7 +287,7 @@ class XPlane(Plane): @property def x0(self): - return self.coeff['x0'] + return self._coeffs['x0'] @x0.setter def x0(self, x0): From 8414295b4670b1fdae03879c4427ca674412d2ce Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 2 Oct 2015 11:33:24 +0700 Subject: [PATCH 36/48] Expand check on combining parentheses --- openmc/region.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index f1926cdc2a..26da5355dd 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -83,16 +83,19 @@ class Region(object): else: tokens.append(surfaces[abs(j)].positive) - # This function is used below to apply an operator to operands on the + # The functions below are used to apply an operator to operands on the # output queue during the shunting yard algorithm. + def can_be_combined(region): + return isinstance(region, Complement) or hasattr(region, 'surface') + def apply_operator(output, operator): r2 = output.pop() if operator == ' ': r1 = output.pop() - if isinstance(r1, Intersection) and hasattr(r2, 'surface'): + if isinstance(r1, Intersection) and can_be_combined(r2): r1.nodes.append(r2) output.append(r1) - elif isinstance(r2, Intersection) and hasattr(r1, 'surface'): + elif isinstance(r2, Intersection) and can_be_combined(r1): r2.nodes.insert(0, r1) output.append(r2) elif isinstance(r1, Intersection) and isinstance(r2, Intersection): @@ -102,10 +105,10 @@ class Region(object): output.append(Intersection(r1, r2)) elif operator == '^': r1 = output.pop() - if isinstance(r1, Union) and hasattr(r2, 'surface'): + if isinstance(r1, Union) and can_be_combined(r2): r1.nodes.append(r2) output.append(r1) - elif isinstance(r2, Union) and hasattr(r1, 'surface'): + elif isinstance(r2, Union) and can_be_combined(r1): r2.nodes.insert(0, r1) output.append(r2) elif isinstance(r1, Union) and isinstance(r2, Union): From 52fe3f5b76b0ce36141d442c8bc50fe87a31f592 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 2 Oct 2015 14:00:12 +0700 Subject: [PATCH 37/48] Respond to @smharper comments on #463 --- openmc/region.py | 3 ++- src/geometry.F90 | 46 +++++++++++++++++++++++----------------------- src/initialize.F90 | 5 +++++ src/summary.F90 | 24 +++++++++++------------- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/openmc/region.py b/openmc/region.py index 26da5355dd..cb745b7f8c 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -67,7 +67,8 @@ class Region(object): else: # Check for invalid characters if expression[i] not in '-0123456789': - raise SyntaxError('Invalid character in expression') + raise SyntaxError("Invalid character '{}' in expression" + .format(expression[i])) # If we haven't yet reached the start of a word, start one if i_start < 0: diff --git a/src/geometry.F90 b/src/geometry.F90 index aec506df60..e1e1b1f44e 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -83,7 +83,6 @@ contains integer :: i integer :: token - logical :: b1, b2 integer :: i_stack logical :: actual_sense ! sense of particle wrt surface logical :: stack(size(c%rpn)) @@ -91,7 +90,20 @@ contains i_stack = 0 do i = 1, size(c%rpn) token = c%rpn(i) - if (token < OP_UNION) then + + ! If the token is a binary operator (intersection/union), apply it to + ! the last two items on the stack. If the token is a unary operator + ! (complement), apply it to the last item on the stack. + select case (token) + case (OP_UNION) + stack(i_stack - 1) = stack(i_stack - 1) .or. stack(i_stack) + i_stack = i_stack - 1 + case (OP_INTERSECTION) + stack(i_stack - 1) = stack(i_stack - 1) .and. stack(i_stack) + i_stack = i_stack - 1 + case (OP_COMPLEMENT) + stack(i_stack) = .not. stack(i_stack) + case default ! If the token is not an operator, evaluate the sense of particle with ! respect to the surface and see if the token matches the sense. If the ! particle's surface attribute is set and matches the token, that @@ -106,24 +118,7 @@ contains p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) stack(i_stack) = (actual_sense .eqv. (token > 0)) end if - else - ! If the token is a binary operator (intersection/union), apply it to - ! the last two items on the stack. If the token is a unary operator - ! (complement), apply it to the last item on the stack. - b1 = stack(i_stack) - select case (token) - case (OP_UNION) - b2 = stack(i_stack - 1) - stack(i_stack - 1) = b1 .or. b2 - i_stack = i_stack - 1 - case (OP_INTERSECTION) - b2 = stack(i_stack - 1) - stack(i_stack - 1) = b1 .and. b2 - i_stack = i_stack - 1 - case (OP_COMPLEMENT) - stack(i_stack) = .not. b1 - end select - end if + end select end do if (i_stack == 1) then @@ -630,11 +625,11 @@ contains ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL SURFACE_LOOP: do i = 1, size(cl%region) - ! check for operators index_surf = cl%region(i) coincident = (index_surf == p % surface) - ! check for operators + ! ignore this token if it corresponds to an operator rather than a + ! region. index_surf = abs(index_surf) if (index_surf >= OP_UNION) cycle @@ -642,7 +637,7 @@ contains surf => surfaces(index_surf)%obj d = surf%distance(p%coord(j)%xyz, p%coord(j)%uvw, coincident) - ! Check is calculated distance is new minimum + ! Check if calculated distance is new minimum if (d < d_surf) then if (abs(d - d_surf)/d_surf >= FP_PRECISION) then d_surf = d @@ -899,8 +894,11 @@ contains do j = 1, size(c%region) i_surface = c % region(j) positive = (i_surface > 0) + + ! Skip any tokens that correspond to operators rather than regions i_surface = abs(i_surface) if (i_surface >= OP_UNION) cycle + if (positive) then count_positive(i_surface) = count_positive(i_surface) + 1 else @@ -930,6 +928,8 @@ contains do j = 1, size(c%region) i_surface = c % region(j) positive = (i_surface > 0) + + ! Skip any tokens that correspond to operators rather than regions i_surface = abs(i_surface) if (i_surface >= OP_UNION) cycle diff --git a/src/initialize.F90 b/src/initialize.F90 index 16a6a17b03..ca92595c2a 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -573,6 +573,9 @@ contains c => cells(i) do j = 1, size(c%region) id = c%region(j) + ! Make sure that only regions are checked. Since OP_UNION is the + ! operator with the lowest integer value, anything below it must denote + ! a half-space if (id < OP_UNION) then if (surface_dict%has_key(abs(id))) then i_array = surface_dict%get_key(abs(id)) @@ -584,8 +587,10 @@ contains end if end do + ! Also adjust the indices in the reverse Polish notation do j = 1, size(c%rpn) id = c%rpn(j) + ! Again, make sure that only regions are checked if (id < OP_UNION) then i_array = surface_dict%get_key(abs(id)) c%rpn(j) = sign(i_array, id) diff --git a/src/summary.F90 b/src/summary.F90 index 1edb645432..ab69f35ccb 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -179,21 +179,19 @@ contains region_spec = "" do j = 1, size(c%region) k = c%region(j) - if (k < OP_UNION) then + select case(k) + case (OP_LEFT_PAREN) + region_spec = trim(region_spec) // " (" + case (OP_RIGHT_PAREN) + region_spec = trim(region_spec) // " )" + case (OP_COMPLEMENT) + region_spec = trim(region_spec) // " ~" + case (OP_UNION) + region_spec = trim(region_spec) // " ^" + case default region_spec = trim(region_spec) // " " // to_str(& sign(surfaces(abs(k))%obj%id, k)) - else - select case(k) - case (OP_LEFT_PAREN) - region_spec = trim(region_spec) // " (" - case (OP_RIGHT_PAREN) - region_spec = trim(region_spec) // " )" - case (OP_COMPLEMENT) - region_spec = trim(region_spec) // " ~" - case (OP_UNION) - region_spec = trim(region_spec) // " ^" - end select - end if + end select end do call write_dataset(cell_group, "region", adjustl(region_spec)) From f0da87cde034704ab1a08d31bde7bb60eafa9a11 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 2 Oct 2015 22:05:19 +0700 Subject: [PATCH 38/48] Fix writing of region specification in summary file. --- src/summary.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/summary.F90 b/src/summary.F90 index ab69f35ccb..56c31452b4 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -186,6 +186,7 @@ contains region_spec = trim(region_spec) // " )" case (OP_COMPLEMENT) region_spec = trim(region_spec) // " ~" + case (OP_INTERSECTION) case (OP_UNION) region_spec = trim(region_spec) // " ^" case default From 71dfde8d12942170a9a8d91796ab40a6e9becaaf Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 3 Oct 2015 09:26:50 +0700 Subject: [PATCH 39/48] Adopt shorthand notation for half-spaces and regions in Python API Surfaces now have __neg__ and __pos__ operators, and regions have __and__, __or__, and __invert__. This makes the syntax for complex regions much less bulky. --- docs/source/usersguide/input.rst | 4 ++-- openmc/region.py | 29 ++++++++++++++++++---------- openmc/surface.py | 20 ++++++------------- src/string.F90 | 8 ++++---- tests/test_complex_cell/geometry.xml | 2 +- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/docs/source/usersguide/input.rst b/docs/source/usersguide/input.rst index fbc74de4af..91751596ae 100644 --- a/docs/source/usersguide/input.rst +++ b/docs/source/usersguide/input.rst @@ -896,7 +896,7 @@ Each ```` element can have the following attributes or sub-elements: the cell occupies. Each half-space is identified by the unique ID of the surface prefixed by `-` or `+` to indicate that it is the negative or positive half-space, respectively. The `+` sign for a positive half-space - can be omitted. Valid Boolean operators are parentheses, union `^`, + can be omitted. Valid Boolean operators are parentheses, union `|`, complement `~`, and intersection. Intersection is implicit and indicated by the presence of whitespace. The order of operator precedence is parentheses, complement, intersection, and then union. @@ -908,7 +908,7 @@ Each ```` element can have the following attributes or sub-elements: .. code-block:: xml - + .. note:: The ``region`` attribute/element can be omitted to make a cell fill its entire universe. diff --git a/openmc/region.py b/openmc/region.py index cb745b7f8c..c4e1e2143b 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -7,6 +7,15 @@ from openmc.checkvalue import check_type class Region(object): __metaclass__ = ABCMeta + def __and__(self, other): + return Intersection(self, other) + + def __or__(self, other): + return Union(self, other) + + def __invert__(self): + return Complement(self) + @abstractmethod def __str__(self): return '' @@ -19,8 +28,8 @@ class Region(object): ---------- expression : str Boolean expression relating surface half-spaces. The possible - operators are union '^', intersection ' ', and complement '~'. For - example, '(1 -2) ^ 3 ~(4 -5)'. + operators are union '|', intersection ' ', and complement '~'. For + example, '(1 -2) | 3 ~(4 -5)'. surfaces : dict Dictionary whose keys are suface IDs that appear in the Boolean expression and whose values are Surface objects. @@ -37,7 +46,7 @@ class Region(object): i_start = -1 tokens = [] while i < len(expression): - if expression[i] in '()^~ ': + if expression[i] in '()|~ ': # If special character appears immediately after a non-operator, # create a token with the apporpriate half-space if i_start >= 0: @@ -47,7 +56,7 @@ class Region(object): else: tokens.append(surfaces[abs(j)].positive) - if expression[i] in '()^~': + if expression[i] in '()|~': # For everything other than intersection, add the operator # to the list of tokens tokens.append(expression[i]) @@ -60,7 +69,7 @@ class Region(object): # is not a left parenthese or union operator, that implies that the # whitespace is to be interpreted as an intersection operator if (i_start >= 0 or tokens[-1] == ')') and \ - expression[i+1] not in ')^': + expression[i+1] not in ')|': tokens.append(' ') i_start = -1 @@ -104,7 +113,7 @@ class Region(object): output.append(r1) else: output.append(Intersection(r1, r2)) - elif operator == '^': + elif operator == '|': r1 = output.pop() if isinstance(r1, Union) and can_be_combined(r2): r1.nodes.append(r2) @@ -124,10 +133,10 @@ class Region(object): # generate an abstract syntax tree for the region expression. output = [] stack = [] - precedence = {'^': 1, ' ': 2, '~': 3} - associativity = {'^': 'left', ' ': 'left', '~': 'right'} + precedence = {'|': 1, ' ': 2, '~': 3} + associativity = {'|': 'left', ' ': 'left', '~': 'right'} for token in tokens: - if token in (' ', '^', '~'): + if token in (' ', '|', '~'): # Normal operators while stack: op = stack[-1] @@ -225,7 +234,7 @@ class Union(Region): self._nodes = nodes def __str__(self): - return '(' + ' ^ '.join(map(str, self.nodes)) + ')' + return '(' + ' | '.join(map(str, self.nodes)) + ')' class Complement(Region): diff --git a/openmc/surface.py b/openmc/surface.py index 98ec903c7c..a5763d9cf2 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -48,12 +48,6 @@ class Surface(object): Unique identifier for the surface name : str Name of the surface - negative : Halfspace - Negative half-space of the surface, i.e., if :math:`f(x,y,z) = 0` is the - equation for the sufrace, the region for which :math:`f(x,y,z) < 0`. - positive : Halfspace - Positive half-space of the surface, i.e., if :math:`f(x,y,z) = 0` is the - equation for the sufrace, the region for which :math:`f(x,y,z) > 0`. type : str Type of the surface, e.g. 'x-plane' @@ -75,6 +69,12 @@ class Surface(object): # proper order self._coeff_keys = [] + def __neg__(self): + return Halfspace(self, '-') + + def __pos__(self): + return Halfspace(self, '+') + @property def id(self): return self._id @@ -95,14 +95,6 @@ class Surface(object): def coeffs(self): return self._coeffs - @property - def negative(self): - return Halfspace(self, '-') - - @property - def positive(self): - return Halfspace(self, '+') - @id.setter def id(self, surface_id): if surface_id is None: diff --git a/src/string.F90 b/src/string.F90 index b505aa869b..91a255a361 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -67,7 +67,7 @@ contains !=============================================================================== ! TOKENIZE takes a string that includes logical expressions for a list of ! bounding surfaces in a cell and splits it into separate tokens. The characters -! (, ), ^, and ~ count as separate tokens since they represent operators. +! (, ), |, and ~ count as separate tokens since they represent operators. !=============================================================================== subroutine tokenize(string, tokens) @@ -85,7 +85,7 @@ contains i = 1 do while (i <= len_trim(string_)) ! Check for special characters - if (index('()^~ ', string_(i:i)) > 0) then + if (index('()|~ ', string_(i:i)) > 0) then ! If the special character appears immediately after a non-operator, ! create a token with the surface half-space if (i_start > 0) then @@ -98,7 +98,7 @@ contains call tokens%push_back(OP_LEFT_PAREN) case (')') call tokens%push_back(OP_RIGHT_PAREN) - case ('^') + case ('|') call tokens%push_back(OP_UNION) case ('~') call tokens%push_back(OP_COMPLEMENT) @@ -112,7 +112,7 @@ contains ! is not a left parenthese or union operator, that implies that the ! whitespace is to be interpreted as an intersection operator if (i_start > 0 .or. tokens%data(tokens%size()) == OP_RIGHT_PAREN) then - if (index(')^', string_(i+1:i+1)) == 0) then + if (index(')|', string_(i+1:i+1)) == 0) then call tokens%push_back(OP_INTERSECTION) end if end if diff --git a/tests/test_complex_cell/geometry.xml b/tests/test_complex_cell/geometry.xml index 1609dad104..18e304fe0e 100644 --- a/tests/test_complex_cell/geometry.xml +++ b/tests/test_complex_cell/geometry.xml @@ -18,7 +18,7 @@ - + From b9024f2d8ef0558049a51b873798f59fde6d083b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 3 Oct 2015 09:55:58 +0700 Subject: [PATCH 40/48] Update example inputs and Jupyter notebooks --- .../examples/pandas-dataframes.ipynb | 55 ++++++++-------- .../pythonapi/examples/post-processing.ipynb | 66 +++++++++---------- .../pythonapi/examples/tally-arithmetic.ipynb | 43 ++++++------ examples/python/basic/build-xml.py | 11 ++-- .../python/lattice/hexagonal/build-xml.py | 14 ++-- examples/python/lattice/nested/build-xml.py | 21 +++--- examples/python/lattice/simple/build-xml.py | 18 +++-- examples/python/pincell/build-xml.py | 12 ++-- examples/python/reflective/build-xml.py | 7 +- openmc/region.py | 8 +-- openmc/universe.py | 2 +- 11 files changed, 117 insertions(+), 140 deletions(-) diff --git a/docs/source/pythonapi/examples/pandas-dataframes.ipynb b/docs/source/pythonapi/examples/pandas-dataframes.ipynb index 357f10620f..15b778662a 100644 --- a/docs/source/pythonapi/examples/pandas-dataframes.ipynb +++ b/docs/source/pythonapi/examples/pandas-dataframes.ipynb @@ -26,7 +26,6 @@ "import openmc\n", "from openmc.statepoint import StatePoint\n", "from openmc.summary import Summary\n", - "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -173,20 +172,19 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.region = fuel_outer_radius.negative\n", + "fuel_cell.region = -fuel_outer_radius\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", - " clad_outer_radius.negative)\n", + "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator_cell.region = clad_outer_radius.positive\n", + "moderator_cell.region = +clad_outer_radius\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -233,9 +231,7 @@ "root_cell.fill = assembly\n", "\n", "# Add boundary planes\n", - "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", - " min_y.positive, max_y.negative,\n", - " min_z.positive, max_z.negative)\n", + "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", @@ -372,7 +368,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JFQMbBgd4EXAAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMjFUMTA6MjU6\nMjYrMDc6MDAKj62JAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTIxVDEwOjI1OjI2KzA3OjAw\ne9IVNQAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98KAwIzOzFd628AAAPZSURBVGje7Zs7buMwEIZ9iey5\n0gyNjQpXKTYudIScgkdQYTfut1idwkdQkQNsYQO2Qj0sPiVK+mlQDmwgwIcgg8Cc4fCTSK5W4OeF\nkM8rHv+2I/rgxPZEPZgR7XtQxKdXYuUXJSUnBQ/9WCgo4vOSJ+WFUvF7E08mlia+rn7VcKXP8sRs\nzFX8b2MdX2y6v1Tw6MZUw4H4ojfIjD8mvn/qRL5p4+vvlMqvp2EhR8WBzfiz20hXORmP9fi/bM9E\neUFvV5H/0yRkeSbiGRfFJErxD9ENdz7Mbhig/h89fvtFdMiI/ePUIXV4lXju8K3DKv9NThOZ3q2K\nmUy6grxFES8rjeyic+FFQav+ncg3fXjH+Ts+/iibztFqOiZuZP/Z3OafPX40NGgST2r+uvQkXXp6\ncKvmr+r0e1Eef5um3+JHP3IFF1D/seNZJgaDmvY0Gav1s+2f1fqpIcublfKGt6apotG/NVx3SInW\ntLX+7Vg/Pv1YqOsnun6JSVdOXT/X7vk75f938QP+8OmSBs0fXtymMhJbf8qlPynYmpKCh7OB1fzN\nalOj1sl0ZAruHLiA+RM73pDe/VjMVP89+aTXwjyc/x5n+u991895/utrJTy8/06TXh0r/5JOa2Jm\nYmqi4r/vUm/H4wLmT+z4anhr05X+q6KUXhtzr/9qSff5L5uMT//V/NdU4YuBTPa/8P67l/6r44ds\n+hYuoP5jx9ciy6XTWlibBrmx8V/TdMfjkP+6pOsu/lvM9N90sf7r+f6m/65n+S8p/itN15v0UkW3\n/+48+PRfJX6S9Joo4g+G/1qYG9KroqP/WypcuvyXPf13wH89/hHef7MB6R3Cqn55U4rv4kfH3zaS\ngQuYP7HjVf89tXrbO+hfLdr+Ozv/SP1dgtQ/Ov8C+i/3+q/Zf2D/HWi6bjT6rym9I/v/03/b+LHS\n4cTg/utTsV7/net/Afzz4f0XGX84/2j9xZ4/sePR/of2X7D/o+vPo/sv6h9B/Bfxr9j1Hz2eN/hO\n8/wfff4A848+f/1A/530/I0+/8PvH9D3H9HnT+R49P0b+v4PfP/4E/wXfP8Mvf9G37/D/ovuP8Se\nP7Hj0f0vdP8tqP9O339cyv7p3P1fdP8Z3v9G999j13/seMax8x/o+ZN7+O+E8zdP/8XOf8Hnz9Dz\nb7HnT+x49PxlCp7/BM+fOv13wvnXBfivt2lMvD8TyH/Hnb+Gz3+j589jz5/Y8ej9h4D+W7qQmf57\nefqv239n3T+C7z+h969i13/seMax+3/o/cMcu/8Y2H9n3p+J6r98pv8m4fwXuH+M3n+OO3++AX9c\nlR+4PhbRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEwLTAzVDA5OjUxOjEzKzA3OjAwBMrIlQAA\nACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0xMC0wM1QwOTo1MToxMyswNzowMHWXcCkAAAAASUVORK5C\nYII=\n", "text/plain": [ "" ] @@ -561,8 +557,9 @@ " Copyright: 2011-2015 Massachusetts Institute of Technology\n", " License: http://mit-crpg.github.io/openmc/license.html\n", " Version: 0.7.0\n", - " Git SHA1: b167d70c877c516deca785801b9fa6f53fb0985b\n", - " Date/Time: 2015-09-21 10:27:06\n", + " Git SHA1: 71dfde8d12942170a9a8d91796ab40a6e9becaaf\n", + " Date/Time: 2015-10-03 09:52:00\n", + " OpenMP Threads: 4\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -629,20 +626,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 4.4100E-01 seconds\n", - " Reading cross sections = 1.7900E-01 seconds\n", - " Total time in simulation = 1.2656E+01 seconds\n", - " Time in transport only = 1.2642E+01 seconds\n", - " Time in inactive batches = 2.0300E+00 seconds\n", - " Time in active batches = 1.0626E+01 seconds\n", - " Time synchronizing fission bank = 4.0000E-03 seconds\n", + " Total time for initialization = 3.9200E-01 seconds\n", + " Reading cross sections = 1.3900E-01 seconds\n", + " Total time in simulation = 3.8950E+00 seconds\n", + " Time in transport only = 3.7970E+00 seconds\n", + " Time in inactive batches = 5.0500E-01 seconds\n", + " Time in active batches = 3.3900E+00 seconds\n", + " Time synchronizing fission bank = 3.0000E-03 seconds\n", " Sampling source sites = 3.0000E-03 seconds\n", - " SEND/RECV source sites = 1.0000E-03 seconds\n", + " SEND/RECV source sites = 0.0000E+00 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", " Total time for finalization = 0.0000E+00 seconds\n", - " Total time elapsed = 1.3110E+01 seconds\n", - " Calculation Rate (inactive) = 6157.64 neutrons/second\n", - " Calculation Rate (active) = 3529.08 neutrons/second\n", + " Total time elapsed = 4.2970E+00 seconds\n", + " Calculation Rate (inactive) = 24752.5 neutrons/second\n", + " Calculation Rate (active) = 11061.9 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -1083,7 +1080,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1106,7 +1103,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 27, @@ -1117,7 +1114,7 @@ "data": { "image/png": "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\nEvx/rHWCrxSlro8AAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2374,7 +2371,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 38, @@ -2385,7 +2382,7 @@ "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY8AAAEZCAYAAABvpam5AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztvX2cFOWZ7/29hnFcFBQR4xsEDWKcCWiGGMWQSHLiMIgu\nHpn1GFkjGI+aZ5cYdTDAQ+IxKyxrTlBDPKv4EiEJrEkk7o4LzmDy5IzLJDEREdQZjZhofCUCMfGF\nZMS5nj+qeqa6uqq7qrurX2au7+fTn+mqvu+7rqruuX/3fV33i6gqhmEYhhGHmnIbYBiGYVQfJh6G\nYRhGbEw8DMMwjNiYeBiGYRixMfEwDMMwYmPiYRiGYcTGxMMwCkRElojIXeW2wzBKiYmHUZGIyCdF\n5Oci8qaI7BGRLSJyaoFlzheR//KdWyMiNxZSrqquUNXLCykjDBHpE5G3ReQtEXlFRFaJSG3EvDeI\nyPeSsMswTDyMikNEDgH+E/gWcBhwLPB14K/ltCsIERlWgsucrKojgTOBOcAVJbimYWTFxMOoRE4E\nVFV/oA5/UdWHVfXJVAIRuVxEukXkzyLytIg0uucXi8hOz/n/7p6vB24HznBb8X8UkcuBucBX3HP/\n4aY9RkQ2iMgfROS3IvIlz3VvEJH7ReR7IvInYL63hS8ix7m9hUtE5EUReUNE/l9P/uEislZE9rr2\nf0VEXoryUFT1eaALaPCU9y0R+b2I/ElEHhORT7rnZwJLgAvde9vmnj9URO4RkVdF5GURuVFEatzP\nThCRTre394aI3Bf3izOGDiYeRiXyLPC+61KaKSKHeT8UkQuA/wV8XlUPAWYDe9yPdwKfdM9/Hfi+\niBypqj3AF4FfqOpIVT1MVe8C1gE3uefOcyvSB4FtwDHAZ4GrRWSGx4TZwI9U9VA3f9AaP9NwRPCz\nwPUi8mH3/P8CPggcDzQBF4fkT7tl975PAj4F/Mrz2a+AU3B6aOuBH4lInaq2A/8M3OfeW6Obfg3Q\nC0wAGoEZwP90P7sRaFfVUTi9vVU57DKGMCYeRsWhqm8Bn8SpVO8C/iAi/yEiH3CT/E+cCn+rm/55\nVf29+/5+VX3dff9D4DngdDefhFzSe/7jwBhVXaaq+1X1d8DdwOc8aX6uqm3uNf4SUu7XVfWvqroD\n2I5TwQNcAPyzqv5JVV/Bcc2F2ZXicRF5G+gG7lfV76Y+UNV1qvpHVe1T1ZuBA4GUUIm3bBE5Ejgb\nuEZV96nqG8CtnnvrBY4TkWNVtVdVf57DLmMIY+JhVCSq+oyqXqqq44BJOL2AW92PxwLPB+Vz3UXb\nXLfUH928h8e49HjgmFR+t4wlwAc8aV6OUM7rnvfvAiPc98cAXjdVlLIaVXUEcCFwiYiMT30gIgtd\n99ebrq2HAmNCyhkPHAC85rm3O4Aj3M+/giM2vxKRp0Tk0gi2GUOUSKM2DKOcqOqzIrKWgUDxS8AJ\n/nRupXon8N9w3FPq+vpTre8g95D/3O+B36nqiWHmBOSJszT1a8A44Bn3eFzUjKr6IxE5D7gBuFRE\nPgVcB/w3VX0aQET2En6/L+EMOjhcVfsCyt+F+4xFZBrwExHpVNXfRrXRGDpYz8OoOETkwyJyrYgc\n6x6PAy4CfuEmuRtYKCJTxOEEEfkgcDBOhbkbqHFbzpM8Re8CxorIAb5zH/Ic/wp4yw1kDxeRYSIy\nSQaGCQe5mHK5nbz8EFgiIqPc+1tAPPH5F+AiERkLjAT2A7tFpE5ErgcO8aR9HccNJQCq+hqwGbhZ\nREaKSI2ITBCRM8GJJbnlArzp2pUhMoYBJh5GZfIWTpziUdfX/wtgB9AKTlwDWI4TIP4z8GPgMFXt\nBla66V/HEY4tnnJ/CjwNvC4if3DP3QM0uG6cH7st8nOBjwK/Bd7A6c2kKuWwnof6jsP4JxxX1e9w\nKvIf4cQawkgrS1WfAv4/4Fqg3X39BngB2IfTc0rxI/fvHhF5zH1/CVCHEz/Z66Y5yv3sVOCXIvIW\n8B/AVar6QhbbjCGMJLkZlDtc8FZgGHC3qt4UkGYVThDvXWC+qqaGFH4ZJzAqwF2q+q3EDDWMMiEi\n/w/wP1T1M+W2xTDikFjPQ5zJU7cBM3HGpV8kzlh7b5pZwAmqOhHH13q7e34SjnB8HGeUyrkiMiEp\nWw2jVIjIUSIyzXUZfRinB/FAue0yjLgk6bY6Ddipqi+o6nvAfcB5vjSzgbUAqvooMEpEjgLqgUfd\nyWHvA504M2sNo9qpwxnh9GccN9q/A/9aVosMIw+SHG11LJlDEk+PkOYY4ElgmYiMBv4CnEP6xCjD\nqErc+SiTy22HYRRKkuIRNZiSMVJFVZ8RkZtwAorv4Mz2tVEfhmEYFUKS4vEK6WPYx5E5IcqfZqx7\nDlX9DvAdABH5Z9JHkeCeTy7abxiGMYhR1ThDzDNIMubxGDBRnIXi6nBmx7b50rThDB1ERKYCb7oT\nlUgtReGO3z8fZ1hmBqpata85c+aU3Qazv/x2DEX7q9n2wWB/MUis56Gq+0VkAdCBM1T3HlXtEZEr\n3c9Xq+omEZklIjtx3FPe5RDuF5HDgfeAf1DVPydlq2EYhhGPRJcnUdWHgId851b7jheE5D0zQdMM\nwzCMArAZ5mWkvr4+d6IKxuwvL9VsfzXbDtVvfzEw8SgjDQ0NuRNVMGZ/ealm+6vZdqh++4uBiYdh\nGIYRGxMPwzAMIzYmHoZhGEZsTDwMwzCM2Jh4GIZhGLEx8TAMwzBiY+JhGIZhxMbEwzAMw4iNiYdh\nGIYRGxMPwzAMIzYmHoZhGEZsTDwMwzCM2Jh4GIZhGLEx8TAMwzBik6h4iMhMEXlGRJ4TkUUhaVa5\nn28XkUbP+SUi8rSIPCki60XkwCRtNQzDMKKTmHiIyDDgNmAm0ABcJCL1vjSzgBNUdSJwBXC7e/44\n4HJgiqpOxtnG9nNJ2WoYhmHEI8mex2nATlV9QVXfA+4DzvOlmQ2sBVDVR4FRInIk8GecvcsPEpFa\n4CDglQRtNQzDMGKQpHgcC7zkOX7ZPZczjaruBVYCvwdeBd5U1Z8kaKthGIYRg9oEy9aI6STjhMgE\n4GrgOOBPwI9E5O9VdZ0/bUtLS//7+vr6qtoesqurq9wmFITZX16q2f5qth2qz/7u7m56enqKWmaS\n4vEKMM5zPA6nZ5EtzVj33KeBn6vqHgAR+THwCSBDPDZs2FA8i8vA3Llzy21CQZj95aWa7a9m26G6\n7RfJaLPHJkm31WPARBE5TkTqgAuBNl+aNuASABGZiuOe2gU8C0wVkeHi3OVZQHeCthqGYRgxSKzn\noar7RWQB0IEzWuoeVe0RkSvdz1er6iYRmSUiO4F3gEvdz54Qke/iCFAf8DhwZ1K2GoZhGPFI0m2F\nqj4EPOQ7t9p3vCAk7zeAbyRnnWEYhpEvNsPcMAzDiI2Jh2EYhhEbEw/DMAwjNiYehmEYRmxMPAzD\nMIzYmHgYhmEYsTHxMAzDMGJj4mEYhmHExsTDMAzDiI2Jh2EYhhEbE48qoqOjgxkzWpgxo4WOjo5y\nm2MYxhAm0bWtjOLR0dHB+efPY9++mwDYsmUeDzywlubm5jJbZhjGUMTEo0pYufJOVzjmAbBvn3PO\nxMMwjHJgbivDMAwjNtbzqBJaW69gy5Z57NvnHA8fvojW1rXlNcowjCGLiUeV0NzczAMPrGXlSmdP\nrNZWi3cYhlE+EhUPEZkJ3Iqzk+DdqnpTQJpVwNnAu8B8Vd0mIh8G7vMk+xDwNVVdlaS9lU5zc7MJ\nhmEYFUFi4iEiw4DbcPYffwX4tYi0qWqPJ80s4ARVnSgipwO3A1NV9Vmg0U1T4+Z/IClbDcMwjHgk\nGTA/Ddipqi+o6ns4PYnzfGlmA2sBVPVRYJSIHOlLcxbwvKq+lKCthmEYRgySFI9jAW+F/7J7Llea\nsb40nwPWF906wzAMI2+SjHloxHQSlk9E6oC/BRaFZW5pael/X19fT0NDQwwTy0tXV1fktDt27GDj\nxkcAOOecMzn55JOTMisyceyvRMz+8lHNtkP12d/d3U1PT0/uhDFIUjxeAcZ5jsfh9CyypRnrnktx\nNrBVVd8Iu8iGDRsKNLO8zJ07N2eajo4OVq1a0z+7/PnnF1XM7PIo9lcyZn/5qGbbobrtF/G32eOT\npHg8BkwUkeOAV4ELgYt8adqABcB9IjIVeFNVd3k+vwj4twRtrFg6Ojr6h+Xu3r3LZpcbhlFRJCYe\nqrpfRBYAHThDde9R1R4RudL9fLWqbhKRWSKyE3gHuDSVX0QOxgmWX56UjZWKfx2rmpprgCfLa5Rh\nGIaHROd5qOpDwEO+c6t9xwtC8r4DjEnOusrFv45VXx/U1LTS1zcZsNnlhmGUH5thXiWccsokxoxp\nA2x2uWEY5cfEowIJWsdqxQoTDMMwKgcTjwrE1rEyDKPSMfGoUGwdK8MwKhnbz8MwDMOIjYmHYRiG\nERsTD8MwDCM2Jh6GYRhGbEw8DMMwjNiYeBiGYRixMfEYBHR0dDBjRgszZrTQ0dFRbnMMwxgC2DyP\nKsO72m5r6xUAaYsobtkyr2KWazcMY/Bi4lFF+Ffb3bJlHieddIIt124YRskx8agi/Kvt7tsHL754\nY3mNMgxjSGIxjypn/PixDB++CFgLrHWXa78iLY3FRAzDKDbW86giwlbbBUIXUQxydVlMxDCMQklU\nPERkJnArzk6Cd6vqTQFpVuHsVf4uMF9Vt7nnRwF3Ax8BFPiCqv4ySXsrnWyr7YaJQZCry2IihmEU\nSmLiISLDgNtwtpJ9Bfi1iLSpao8nzSzgBFWdKCKnA7cDU92PvwVsUtW/E5Fa4OCkbK0mbLVdwzAq\ngSRjHqcBO1X1BVV9D7gPOM+XZjaOsx5VfRQYJSJHisihwKdU9TvuZ/tV9U8J2jpoaW29ImdMJAyL\nlRiGEUaSbqtjgZc8xy8Dp0dIMxZ4H3hDRO4FTgG2Al9W1XeTM3dwku/GUhYrMQwjG0mKh0ZMJwH5\naoEpwAJV/bWI3AosBq73Z25pael/X19fT0NDQ37WloGurq6SXWv+fOc57dmzh/Xr1+dMv2LFbRmx\nkoULv86ePXv605TS/iQw+8tHNdsO1Wd/d3c3PT09uRPGIEnxeAUY5zkeh9OzyJZmrHtOgJdV9dfu\n+ftxxCODDRs2FMXYcjF37txymxDImjUbeOqp9HNHH310hr2Van9UzP7yUc22Q3XbL+Jvs8cnyZjH\nY8BEETlOROqAC4E2X5o24BIAEZkKvKmqu1T1deAlETnRTXcW8HSCtho+ComVGIYx+ElMPFR1P7AA\n6AC6gR+oao+IXCkiV7ppNgG/FZGdwGrgHzxFfAlYJyLbgZOBf07K1mqmWEFtfzmpWElTUxtNTW0W\n7zAMI41E53mo6kPAQ75zq33HC0Lybgc+npx11U+xgtrZykmVtXz5cubO/UcArr32UpYuXVrEOzEM\no9qwGeZVTLEmAOYqZ/ny5Xz1q98AVgHw1a9eBcDxxx9flPswDKP6sLWtjJzcfPO9OMIxz32tcs8Z\nhjFUMfGoYuIEtYNiI6lzu3fvoq7uukjlGIZhgLmtqpqoEwCDYhpLl36J5cu/3X+uru5qGhvvZcyY\nwzPKufbaS/tdVQ5Xce21X0nuxgzDqHhMPKqcKGtdBcU0br75xrRzvb0wZkwbmzdnzptJBcdvvtnZ\nO+Taa7/C0qVLI002NAxjcGLiMYhJbVm7det2oLDg9tKlS22ElWEY/Zh4DFLSXVWzgZTbaTI1Ndfw\nt387mx/+cFHa3iCtrWvLZK1hGNWGiccgxe+qcrgWOJG+vi/wwx9+n6VLv0RnpzPpP+qCiYZhGGDi\nMcQ4EfgFAPv2TaazMzjGYRiGkQsbqjtI8Q/jram5BpiWkc727DAMIx+s5zFI8Q/jnT691R2aOxlw\nYhzTp38pcAhvZ+fjgCNAlerKSg0GgMq20zAGKyYeg5SgyvXUU09NmxMSNIT3+utb6etbCZR+A6io\ngmAbVRlG+THxGIQsX76c669fSV/fLQB0dn6Oj3zkFHcC4EClnKqovfT1TaTQtbKyESYQcQShWGt6\nGYaRPyYeg4yOjg6uv/4WVzjmAR309taybdulQHql3Np6BVu2zOsfrityNaqXJWpbmECYIBhGdWHi\nMchYufJOt/eQ4k7gmwRVyt64yO7de3jyyffYv38t4MRF6uquo7X1e0W1bUAglrNv3wGce+4l3HDD\nVbmypuEXPZujYhilJ1HxEJGZwK3AMOBuVb0pIM0q4GzgXWC+qm5zz78A/Bl4H3hPVU9L0tbBxTRg\nkfv+1awpUyIyY0YL+/f/H+AoHMF5lY985MSEWv7LAWeJ9/37nSXe5807n+HDo01ajLqml2EYyZHX\nUF0RuStCmmHAbcBMoAG4SETqfWlmASeo6kTgCuB2z8cKfFpVG004MgkbYusM0f0+cDFwByJPU1vb\nSvQVc5uBDcA0du58qahDeAeGD9+Bf4n3Bx/cEmvnwubmZjZv3sDmzRtMOAyjDGTtebgCcJWq3uL7\naHVQeh+nATtV9QW3rPuA84AeT5rZOLUaqvqoiIwSkSNVdVfKhAjXGXLk2vlvoFV+DK2tNwDkbKW3\ntl5BZ+fn6e0FeBK4i7feWsXDDxdvNFPKtnPPvYT9+4M/NyEwjOogq3io6vsiMhe4xXf+sQhlHwu8\n5Dl+GTg9QppjgV04PY+fiMj7wGpVzdnbGSrkCi4HVcK5KuXm5mY+8pET2bbtX4C9OJ3Fo4Dmogav\nm5ubueGGq2yJd8OocqLEPLaIyG3AD4B3UidV9fEc+TSiDWG9i0+q6qsicgTwsIg8o6r/FbFMI292\n4wTYwRGn4geiw5Z4t4l/hlE9RBGPRhwh+Cff+c/kyPcKMM5zPA6nZ5EtzVj3HKr6qvv3DRF5AMcN\nliEeLS0t/e/r6+tpaGjIYVbl0NXVlVe+KVMm0tm50HUxQV3dQqZMuazg/TX++Mc/4x2Z5XADdXU7\nA8vv6upix44dbNz4CADnnHMmJ598cqRrHX/88Xz72wM/qcWLF3PLLffQ2+sIV2fnxVxzzWWRy8uH\nfJ9/pVDN9lez7VB99nd3d9PT05M7YRxUNfSFM0rq2mxpsuStBZ4HjgPqgCeAel+aWcAm9/1U4Jfu\n+4OAke77g4EuYEbANbSaWbduXd5529vbtalpjjY1zdH29vai5G9qmqOwRkHd1xodPXpCaPmLFi3S\n4cOPdPOs0eHDj8zLlrBrNzXNyausqBTy/CuBara/mm1XrX773bozdr3ufUWJeVwE3JyHKO0XkQVA\nhytC96hqj4hc6X6+WlU3icgsEdmJ4xK71M1+FPBjEUmJ0DpV3RzXhsFMIcHlsIB70PyJ9evDA+Ub\nNz4Se2KfuaYMY3CQT8xDcFQrV8wDVX0IeMh3brXveEFAvt8CH41gm5EHYQH3zZs3JDp/ItsoMZv4\nZxjVRZIxD6MKidqj6ejo4O2336amppW+vieByTkr/GyjxGzin2FUFznFQ1U/XQI7jBISpZWfzb3k\n70HU1FzDKac0sGLFQIWfj3vK5nkYRvWQUzxE5Cic9SSOVdWZItIAnKGq9yRunZEIuVr5uVa49fcg\n+vpgzJi2/s/9q/pmi6mYa8owqpMobqs1wL3AUvf4OeCHgIlHFZOtlV/ICreZq/qWLqZiGEbpiCIe\nY1T1ByKyGEBV3xORgMUljKFCth5E5qq+6ZhryjAGB1EWRnxbRA5PHYjIVOBPyZlkxCGJPcj9+5/7\nF1NMub0mTVrdv4ghwIwZLWzduh1nhZn0/dOzL8ZoGEa1EaXn0Qo8CHxIRH4OHAH8XaJWGZGIux1r\n1CB2lJFPzc3N7Nmzh7lz5/rsmA1cBTQBd1BT8xz/9E+t1tswjEFGlNFWW0VkOvBhnDkez6pqb+KW\nGTmJE5uIKzRx3Et+OwBGjvwaBxxQx/jxkzj11FPj3ZhhGBVPpP08VPU9VX1KVZ804ahO0it4R0SC\n9jAvFu+88y57936Nbdsu5fzz50VyqSXhgjMMIxlsG9oqplKGvvrtqKm5hr6+LxB32ZI4PSPDMMqL\niUcVE2dWdpJCk7JjyZIbefHF13nvvRG89Va8MgoZHmwYRukx8ahyosYmCln+I2qg/Zlndvb3HJyg\nOURZtsQwjOojL/EQkW2q2lhsY4xkyWeORVR3UlDQfPToG/nYx34XSagqxQVnGEY08hIPE46hQyHu\npI997BQ2b96Qdi6sF2MLIxpGdWFuqyFGUvtphPUcvNebPn0Ky5d/O7QXM9hnn9teJsZgIlQ8RORt\nwvchV1U9JBmTjKTIZ0RTVHdSUM8BSLveT38afxTWYMFGkxmDjVDxUNURhRYuIjOBW3F2ErxbVW8K\nSLMKOBt4F5ivqts8nw0DHgNeVtW/LdSeoU4+Lqg47iR/z2HGjJaM1XfhjmLcSigdHR0sWbKCF198\nmfHjj2LFiq9VRAVto8mMwUYkt5WIfAo4QVXvFZEjgBGq+rsceYYBtwFnAa8AvxaRNlXt8aSZ5ZY7\nUUROB27H2cs8xZeBbmBknJsy4pHLnVJMd1JNzXP09Tm9krhB8TA7U+d3797Fk08+w/79KwHYu3ch\ns2d/jra2+6ySNowiE2U/jxuAU4ETcZZmrwPWAZ/IkfU0YKeqvuCWcx9wHtDjSTMbZ/U8VPVRERkl\nIkeq6i4RGQvMwtlL5NoY92SEEOSCmj79SzndKfn66oOut3TpNXR2trmfxxsuHGQneF1jdwAr8Y74\n6u39KnPn/iPr1/+fsgqIjSYzBhtReh7n42xFuxVAVV8RkSgurWOBlzzHLwOnR0hzLLALuAW4DrDY\nSpEIckHlcqd0dHQwe/bn6O09CYDOzugt+TCX19KlA2miClOYnc771Pm2gJxj2bv3i5x/fnljDDaa\nzBhsRBGPv6pqn4gAICIHRyw7LNjuR/zHInIu8AdV3SYin45YjhEBvwsq1/pWc+d+nt7ePuCLAPT2\nLmTJkhsjV3ze66XWrgJHKB577DF346iJwLQiBJGvAC72HC8Ergba2Lfv+Fh2J8FgH01mDC2iiMeP\nRGQ1MEpErgC+ANwdId8rwDjP8TicnkW2NGPdcy3AbDcm8jfAISLyXVW9xH+RlpaW/vf19fU0NDRE\nMK0y6OrqKrcJTJkykc7OhfS6y12KXM2oUU2sX7+eO+64g7173wNW4XUF/eY3X2X9+vWx7N+xYwe3\n3HIPvb3fBOBnP/sfvP++oPotN8Ui9u27mIULv86ePXty2llXt5ApUy4DSDtfW9vL6NHL2L37Tfr6\npgPfBhxX1xNPXM3ixYs5+eSTgdzPf8eOHWzc+AgA55xzZn++SiGp308p7rsSfvuFUG32d3d309PT\nkzthHFQ19IXTK/ggMAP4pvtqypbHk7cWeB44DidO8gRQ70szC9jkvp8K/DKgnOnAgyHX0Gpm3bp1\n5TZBVVWXLVumNTWHK0xVaNXhw4/U9vZ2ra39gHtujYK6rzXa2DhdVePZ39Q0x1dOZrkwVZua5oSW\n0d7erk1Nc7SpaY62t7f3n2tsnKYjRhytI0d+UBsbp2t7e7u2t7e795Rpe6qMRYsWZb3W8OFHuvnX\n9D+TSiKJ30+p7rtSfvv5Uu32u3Vnzno82ytKz2OTqk4CNscUpf0isgDowBmqe4+q9ojIle7nq1V1\nk4jMEpGdwDvApWHFxbm2EY/Ozsfp6xsINO/bN9njzpqGsytgiqtYseKHidhRU/Mcra03hH7ud/sM\nBNEvBp4FVrBtG/3xjVNOmcS2bellbN/+lHuvTo/lM5/5TKAraagOrR2q923EJ6t4qKqKyFYROU1V\nfxW3cFV9CHjId26173hBjjI6gc641zYK5+///mzWrr0LuBxnJNMznHXWaRkVSZSgt3+0UV3dM8B1\n/e6mmppr+PznZ7Ny5Z2sXHlnpFFdAxVdG06nOL3CW7FiiSsuA9fwTlLs7bWK0TDyJUrPYypwsYi8\niNM7AEdXKssBbORNtmGkmzd38tpraxg2rIaLLz6PNWvWpOWNOnM6c7TRfcBAwH769NasS5fkg/+a\nu3c3sG3b5MC0fgEcqkNrh+p9G3mQy6+FE7PIeBXqLyvGC4t5FA1/PCGK73vdunUBsYw1WeMWYeRT\nzoCNrQpjcvrp/fdUVzcm670GxVgKJSxuk891kvr9JHHffirpt58P1W4/pYh5qDvJzxjc5FpapBJ9\n396exe7dHwbuZcyYw0PnUPh7IlOmXEZzc3PovW7evKGo9xvUS1u69EtF73EVig0pNqJgq+oaBVEs\nN0e+5QRVdP75JP5lTFLng4YEp9i6dTsdHR1FrUSDgtE333xjxYu0YQRh4mEEks9qurt37wFO6K+g\n41SAcWZg+5d537DhIV588XXGjx9LS0tTYEseyGj1X3XVfObOnZtxr7CQvXvnlX1Wei527NjBmjXO\nfinTp0+hs/NxoPDl3m3peCMShfq9yvnCYh6JsmzZMh09eoKOHj1Bly1blvG51/5C5wcExVyC/O7+\n68BBCqP7j0VGuTGQ9NhJUExl0qQz0sodPXqCO/+kvaD4TbZ79D+jZcuW5fXc2tvbta5ujOc5HOLe\nd2FzM2yeRzSq3X6KEPMouwAUZLyJR2JEDZinKCRwnhnIPkLr6kYFXjvqZEPvcUoAncp1jvtqTROP\nzLLbFU7S2toP9E88LAbFCpgHPW/nvgoTvWINgMhFJf/2o1Dt9hdDPMxtNUSI64oI8s8vWbIiEReG\n/1rO3I87yDcO4F32Ha5i797LgReAu3CWWnHO19enlzfgvnrSTVvH/v3fZNs2mD3781x//ZcLdg0F\nxWgsQG1UJYWqTzlfWM8jEvm4IoJbtqPTWuHFclsFX2tqYOs3l9uqru4IXbZsmTY1zfH0NtRtlYe7\nrbz3MeC+8qZv1ZqawxJ350TF3Fblpdrtx9xWJh5RyKycW3X06AlZ3STO2lCHZa2c/PbnOz/AqQiP\n6L9Wbe3hoW4r/3WWLVumjY3TdPToCRnupfT7LlQ8Mt1jSbhz4rBo0aK051CsuRlxvsdC5qiUYj5J\nUph4mHiUlfKIR7tGmVCnqtrYOM2tNL0t+IGKs1j2O+Ixyr3WVK2rG1WUyjC9Fd3qCuDAfS9atChD\niBw7TlJyrUksAAAcJElEQVQ4OO05iYyuOPEo5u8nn4q8kF7KokWLKn7hyWyYeJh4lJXyuK2it6AH\n8gXnKZb9YUHaYrRM/eLgLc9fgYmM8LjAWhVG6LBhR2hj4/S8R0UlSTHFO597KyS4PmnSGRl5vSse\nl/vZ5sLEw8SjrJTyB5iqRB2XTPR/+NSS50H+/mLZ39g4PcOmCRM+GqtCy0doMiuwTJEcPXpCQddI\nkqTFO6l8qsHiMbCEfmWIczZMPEw8yko5foD5tjKDKs4g+/MZiuq4x7zB3zE6YsTRoS3Txsbp2tg4\nLdY6XEF25BaPVh058oORxaLYPaVcZZRbPIrptnIaJ5mu0UrFxMPEo6yU6wdYrBZ0UMA8n0lwTuWV\nPgcjqIfkbZk6YuNsXBXUc/FXPEG2XXDBBb6RW3+jcJgrIi3qj5Hk6vkU6taKW0ac30+277wQ23NN\nJM1mu9cmpwFRWTGlbJh4mHiUlWr/AfrtD2rBRnGTRRGdoJZpagRVlGuEzTAf2EXxJPUO+XVEJHpl\nVozJdXHLiNPzyyUOpQ6YR2l4mNsqOYohHolOEhSRmcCtODsJ3q2qNwWkWQWcDbwLzFfVbSLyNzgb\nQB2Is4Xtf6jqkiRtNUqPd+Li0qVforOzDRhY1+rUU0+NtBfH+PFHsW/forwWZxzYRbENWMzAXu13\nZKTdunU7M2a05D1BMOk1o8JW7b355ntzLr6Yz0TFYu46GGdtszjYOl0JUqj6hL1wBGMnzv4fB5B7\nD/PT8exhDhzk/q0Ffgl8MuAaRVXjUlPtrZdC3FZxW5qZw25HK0zSurpR/eVlazkHXS81T8Lbiwmb\nFJhrEl6u+4na+i/EbRXUcxFJueGK7xIauF67+/ymamPjtEh5S/HbT7I3U+3/u1Sy2wo4A2j3HC8G\nFvvS3AFc6Dl+BjjSl+Yg4NdAQ8A1ivpAS021/wALCZjn4+ZJjfxyFj8cmFEex83itSPldw/bUCpz\npnr2SjKbgEW930IC5mGrAsAyhUxRL0Zw35kXMyb291GK337Q8yjWcOBq/9+tdPH4O+Auz/HFwLd9\naR4EPuE5/gnwMR3ouTwBvAV8I+QaxX2iJabaf4CF2F+O4aF+UvanKuzGxmn9lYtX+BzxOElhYBa8\nyKj+EV9RKuKweFBY+igiEtTzS+8tpURxjit8U/sD28VqkUcdrBBlpF6xCXrmxRoO7F+ap5KGcEeh\nGOKRZMxDI6aToHyq+j7wURE5FOgQkU+r6v/1Z25pael/X19fT0NDQ37WloGurq7Eyt6xYwcbNz4C\nwDnnnMnJJxd/y/lC7J8yZSKdnQvdRRChrm4hU6Zcxvr167Pme+211wLP5coXhNf++fNb0j7bs2cP\nixcv5pZb7qG395vAN4H/Tcq/rwrbtt0BzObhh68CLgcm09l5Mddcc1nG8/bfb2rPkNmzM9Pv2LHD\nc11Cywx6/uPGHcWLL94BHAOsBV4HuoDXqavbyeWXX8Z9923MiFUsXPj10M2xsv2W3nuvNyO99/sI\nu5e33nor8FrFxP/MRa6mr+8yot53NlLPPsp3VYr/xVx0d3fT09NT3EILVZ+wFzCVdLfVEmCRL80d\nwOc8xxluK/f814CFAeeLJ8VlIMk9qIvRsszVoirU/myzv7PlKdbIoVz2p/v0D89oxXqXQI+yHPpA\nLyb7niFRe1dBPY/Gxulu67q1343knRMTp/xUmYXEcsKu5V2XK8nWelLDgVPPPtezrNRRZFS426oW\neB4nYF5H7oD5VNyAOTAGGOW+Hw48Anw24BpFf6ilJCnxKIZrJ8qPPunlMcJEoFhzFqKLR2oeindO\nyJg0AYi6l0aU7yYf8fDfd03NYdrYOC3y4IHc7rbweE/cWE9j47S0FYG9MZgg12GxKGZFHlU8iulm\nLSYVLR6OfZwNPIsz6mqJe+5K4EpPmtvcz7cDU9xzk4HHXcHZAVwXUn7RH2opqWTxiFJGmP1xK/2w\nCibp9ZZyPf+ByiY1WilVgU5SGOERkujLoUepwJYtW6beCYpwSMYEvPZ2Z4Z86lnG/c5TvRRnNeJg\nkVH1TuBMF6ZC5oIExUkGekvRFu3MFqfKZU+2fP7faNhvNtVzamycnnUF6Cg9k3LESypePJJ+mXgE\nU4wWVr7ika0XEWZTWDA5V4s3qt1hI2yyPf+BSma6TpjQEDBst0VhqtbUHK7z5s2LVQHkctcNVNgD\nM+5zuULiumSi/kacIHymyy5OY8RfQQaPCpuqQcvmh41ICxshF/X5R/mNhu1o6YwySx9hNmFCQ9q2\nAF6Rqq09PC3tQC8ru/AkiYmHiUcohbZo8nVbhYlONjEKb53Gb/FGrQDC7A+zx9k3xGmpT5gwOSOO\nkMoX55k7s9szF5zM9ayC4iaNjdNjNRji9FSijKjKRlBrPn0jq0Pd7zrzOo2N0zPKGrj//GIYcX6j\nQZuSZaZLnxOU/ptrVWfDMme7gdraQ9N+j373Z6lcWiYeJh6Jkk/APB/xCLrWQIs3vAUexe5sLfKw\n5x/We8k3cBz0HLO16KO2jB1hbU/LF1W8osQyotxbru/AiW8ckZH3ggsucO/fu47YSepfIDPlUgsq\ny1lCJvf8myjfb6onkJ94ZE7CHMiXW5CKsfd8XEw8TDzKSrHcVmFMmDA5sDKJQzbRiiMeudbPCrvO\nwNpZUxVa+0c/Be9WmN7DCHZnZVZEcSZKpnBa/9En+MVZADH9uw6+x8wVjVu1tvYD6m8spIt2UCU9\nIu0eamsPj907TfUs/c8jbEdLf88pqBEQXTxaFcZqahM0c1uZeERiMIqHavyAeRhBLcGRI8fFcsVl\nE604bqtcMYWwoH/wpL2p/WISxy0XLB5jIwlq0LOP6o6KK/zpdgaLavBmUJmDJNKfe9D95xeP8T+P\ngWeR3osJ+81ecMEF/WJ61lln5XBbHdL/XmS0u2RMq++zeKslFIqJh4lHYkSp6JO2P9wHHS+4GHYv\nUQLmXjdatuHEQcHPcDdIasb3mH4xqak5PFKLPkiMclWWYbYH2eePMajGH72Xnj5422P/fh51daPc\nfVrS92oJLislwIcpjM9LPDKfa3QRyozZpA+gWLZsWcagCH9DoqbmMB05clzBtueLiYeJRyJEbWkm\nbX+mj7+4wcW49ucSlJRLKlUBBrm6nLWmUvfg7FsSpyfld4NFEdFwH3/mJlxBvZi44pH5XEb1P5PU\nyDfv/vFhcZGgspw9Vw71VdzRWu9ho9yc5+Cfx3NoqJgHN2qyxy3ycYUmiYmHiUciRK0sSrUyalOT\nd3HC4v2jRbU/rOeSO7Ce7pYQGaU1NQdqym2Vr487Zc+kSWdEyp99EEPuAQlxhvUGVc7BQjsmaywn\nbDDFhAkfzUg7fPjRacNkw55Ztu/FH3iHk0IHPQT3KCeod/BClO8g37lMxcDEw8QjEZIUj3yHEOcT\ncM913Sj2Z7tutNbkQO/CCcoOtLDzDXSn7mPRokWR8xQ6iCHX95arrGy/qTg9m7BnHq/3lVn5i3g3\nAsscxebvSdXWetOnXGljQhsEudyecf8fCsXEw8QjEZJyWyUhAIVcN4r92Sq2uIH1uO6f8PtwfP4i\noyPFSVKumSgzqnOdDys/V88w272HzXfJ/gzSK+54QfxMd9HIkeNC1x3LtL1VDzxwjDs6bJL659vk\nelalFoogTDxMPBIjmwsiRVz7C6088yXsuoWKh2q0OEhq9vHIkR/MKCsVHPY+2+xusugjtPIV6zhu\nqqgxqTC3lV8Qo8zYb2+PtsBksK2p5zdaU0vKeOeTBN13tgEA5ZrkVygmHiYeiZOtIhkK4pFPBewd\ngVVbe7CnsvEPzRyVESgOc20NVJhjs7bwo9x3vs8rSrpso+GCXG5BZYTtuZEr7pDr3vw9HBilcFKa\nqylIuNN/A6kh1gNxorB7rqSehh8TDxOPxMlWkZTabZUvhbitUvn9vYsolYLz7PwT2wZiIEEV4PDh\nx2ScmzBhsm9mdbTWbjnEI+rosWyr0gbN6g6KOzjPJPpQ53zjJaoDv4ERI45Wf89jxIijA91+5QqG\nR8HEw8QjcYopHqrla43lGzAPKidqpRAsHtljII47Jf3csGFHBKTL3drNd8fAfN1WcSpI7y6O3jKc\nnkFmzyroWfkXrCzmel5h5Dc3ZmAXx0oREBMPE4/EKabbqtLIx/44FVB7e/YlQNrbgyb9jc1o2Q4b\nljmBrbb2A2lDddvbMzeCSrnB8h1kECdgHrf8oG1cg1YwzrZYZNg8iWyDAArtDcTvlbWrf//4ShAQ\nEw8Tj5IQ9s9YLfaHkY/9UVueKZxKfVroPARndJZ31nmrioxQ71yQCRMaMgSlsXFaaOvdP9Q0CqXo\nEQbFPFKkT35s0Zqaw9OeV/DItuDvItcCloWIadRl1AfsDe95lhMTDxOPslIt9hdT/KLOyo5jW9Ai\nff4Yi1NhpU8uzB43mBNYUQU9C38gOTUjvJhCEjTayruvBRzsE7/MCYu5RrZFWYOsOLYfoePH10fq\nlZVzFnk2qkI8gJnu3uTP+fcw96RZ5X6+HWh0z40DfgY8DTwFXBWQr8iPtLRUS+UbRjXYX2y328Bw\n2XjLxOeyMVdrOFvMJizoHNTqDhKq9HWdgteiymV/tt5VsI2tPpedf1vfqZGeq/+5pLuLoi/Tno2g\n5ztp0hmR8lZq4LzixQMY5m4xexxwQIR9zE/37GN+FPBR9/0Idztbf96iP9RSUg2VbzYKsb9UgfMk\nAv6VUhlkCzoHbS0bHjfwulbijaDKFdcJv3bQ8upzPO+jb3Wby57a2sMDN++KSiHikbKp0obsVoN4\nnAG0e44XA4t9ae4ALvQcPwMcGVDWvwOf9Z0r5vMsOUNVPEpZARdbPFSTqQzyKTMo6Jwtf7h4eCce\nBlXqkzRsRnuuEWVe+7zf+cByIN7rpMpx4jz5Er6acWtGLCUKQb9Xf8ymEgUiG9UgHn8H3OU5vhj4\nti/Ng8AnPMc/AT7mS3Mc8CIwwne+qA+01AxV8SjGkMmoVMNosXzFtBjzbAaG86aWPBmZtue2M3R4\nIEAskr52U1TxSF0/VcFecMEFviB/aifBzAUj41bMwW686Ro06infUWV+4a6U3mhUiiEetSSLRkwn\nYflEZARwP/BlVX3bn7GlpaX/fX19PQ0NDXmYWR66urrKbUJB5Gv/a6+9Fnhu/fr1hZoUyFVXzWfj\nxtUAnHPOfPbs2cP69etj2b9jxw42bnzELeNMTj755KLZt2LFbezbdxMwD4B9+2Dhwq+zZ8+erNf3\n2x/FRv+zOP744zn33DPZtOkHAMyaNZMPfehDbNy4mu7u5+jr+wCOw8CxTTXdtilTJvKzn/2E/fsX\n9l+jtvZapky5PPD7nD/f+X/t6upKs+Www07h8cd/B7zNrFlN/d/Rjh07uOWWe+jt/SYAnZ0Xc801\nl2V9/lOmTKSzcyG9vakzC4EPA+nP+ItfvI5XX30tctkp2/fs2ZP27KN8f+Wmu7ubnp6e4hZaqPpk\newFTSXdbLcEXNMdxW33Oc9zvtsKJk3QAV4eUX0wxLjmV0vLNl2pwW2UjzgzzJO3N1RMLu34+rd8o\nI5ZS+ZyRS5nupSCXVK6AuZ+otufbS80cWpvZOxpw2cUf/OC1v5Q96WJBFbitaoHncdxOdeQOmE9l\nIGAuwHeBW7KUX+RHWlqGqnioVoaPOKr9SVcOuSr+sOtnVmDZK8I4cyVS6Z21uQbcVsXaKjVq5VuM\nZ58SN//kw7D5M3Htr5TGUByKIR41xe3HpKOq+4EFbu+hG/iBqvaIyJUicqWbZhPwWxHZCawG/sHN\nPg0nRvIZEdnmvmYmaa9ROpqbm9m8eQObN2+gubm53OaUlebmZh54YC1NTW00NbXxwANrYz+T3bt3\nAXcBr7qvu9xzA6xceafHvTKPfftu4sUXX84oa/v2p+jo6KC5uZn//M8NNDZ+hNGjb6Sx8V7a2r6X\n07aOjg5mzGhhxowWOjo6Yt1Hiq1btzNjRgvTp09h+PBFwFpgLcOHL6K19YpYZTU3N/P441vYtOnf\n0p7xIYccAXyT1PNw3tfGvodifH9VSaHqU84X1vMoK0PF/nK3LKO4rSZMmJzRip4wYXJaOUGteH+L\nPOq+6HFt9ZOt5e4EzwtfYiUXYb2aKPdQ7b99Kt1tlfTLxKO8DCX7y+1myzZJUFUDZzKPHj0ho4yg\nSjFziZT83XJR3Uz+Z5+6vyS2Gw4j7HlEuYdq/+0XQzySHm1lGIOC5ubmsroicl1//Pix7N2bec5f\nxgMPrGXlyjsBaG0dcK+cf/489u37IvC66xpaW1T7c5G6vxkzWnj44cklu2bQ80gdG9kx8TCMQcCK\nFUuYPfvz/cNT6+quY8WK72WkCxKhbKISl+nTp/DTn15DX59zHFeIWluvYMuWeezbl1/+uAQ9j1Lb\nUK2YeBjGIKC5uZm2tu95BCB7YLujo8OT9oqi9Kw6OjpYvvzb9PV9AbiDmprnWLr0mljlFlPI8qUS\nbKgGTDwMY5AQVQA6OjpcN9VNAGzZMq8oI4TSR3NBX99aOjvbWLo0XjnldhFWig2VjomHYQwx/JX8\nvn3OOassjTiYeBiGURQsVjC0MPEwjCFGUpW8xQqGFiYehjHESLKSt1jB0MHEwzCGINVSyQeNCjMq\nAxMPwzAqkqRGhRnFwcTDMIyKxEaFVTaJrqprGIZhDE6s52EYRkViQ38rGxMPwzAqEhv6W9mYeBiG\nUbFUy6iwoUjiMQ8RmSkiz4jIcyKyKCTNKvfz7SLS6Dn/HRHZJSJPJm2nYRiGEZ1ExUNEhgG3ATOB\nBuAiEan3pZkFnKCqE4ErgNs9H9/r5jUMwzAqiKR7HqcBO1X1BVV9D7gPOM+XZjbOBsWo6qPAKBE5\nyj3+L+CPCdtoGIZhxCRp8TgWeMlz/LJ7Lm4awzAMo4JIOmCuEdNJnvloaWnpf19fX09DQ0PUrGWn\nq6ur3CYUhNlfXqrZ/mq2HarP/u7ubnp6eopaZtLi8QowznM8DqdnkS3NWPdcJDZs2JC3cZXA3Llz\ny21CQZj95aWa7a9m26G67Rfxt9fjk7Tb6jFgoogcJyJ1wIVAmy9NG3AJgIhMBd5U1V0J22UYhmEU\nQKLioar7gQVAB9AN/EBVe0TkShG50k2zCfitiOwEVgP/kMovIv8G/Bw4UUReEpFLk7TXMAzDiEbi\nkwRV9SHgId+51b7jBSF5L0rQNMMwDCNPbGFEwzAMIzYmHoZhGEZsTDwMwzCM2Jh4GIZhGLEx8TAM\nwzBiY+JhGIZhxMbEwzAMw4iNiYdhGIYRGxMPwzAMIzYmHoZhGEZsTDwMwzCM2Jh4GIZhGLEx8TAM\nwzBiY+JhGIZhxMbEwzAMw4hNouIhIjNF5BkReU5EFoWkWeV+vl1EGuPkNQzDMMpDYuIhIsOA24CZ\nQANwkYjU+9LMAk5Q1YnAFcDtUfMOBrq7u8ttQkGY/eWlmu2vZtuh+u0vBkn2PE4DdqrqC6r6HnAf\ncJ4vzWxgLYCqPgqMEpGjIuatenp6esptQkGY/eWlmu2vZtuh+u0vBkmKx7HAS57jl91zUdIcEyGv\nYRiGUSaSFA+NmE4StMEwDMNIgNoEy34FGOc5HofTg8iWZqyb5oAIeQEQqW7tMfvLi9lfPqrZdqh+\n+wslSfF4DJgoIscBrwIXAhf50rQBC4D7RGQq8Kaq7hKRPRHyoqpD+9szDMMoE4mJh6ruF5EFQAcw\nDLhHVXtE5Er389WquklEZonITuAd4NJseZOy1TAMw4iHqEYNTRiGYRiGQ8XPMBeR0SLysIj8RkQ2\ni8iokHSBkwpF5H+LSI87CfHHInJoieyu6gmS+dovIuNE5Gci8rSIPCUiV5XW8sKevfvZMBHZJiIP\nlsbiDNsK+e2MEpH73d98t+sOLikF2r/E/e08KSLrReTA0lneb0NW+0XkJBH5hYj8RURa4+QtBfna\nH/t/V1Ur+gV8A/iK+34R8C8BaYYBO4HjcILtTwD17mdNQI37/l+C8idgc6g9njSzgE3u+9OBX0bN\nW+H2HwV81H0/Ani2lPYXYrvn82uBdUBbKZ97MezHmTf1Bfd9LXBotdjv5vktcKB7/ANgXgXafwRw\nKrAMaI2Tt8Ltj/W/W/E9DzwTCd2//z0gTeikQlV9WFX73HSP4ozoSppqnyCZr/1HqurrqvqEe/5t\noAdn3k6pyNt2ABEZi1O53U15hpHnbb/bq/6Uqn7H/Wy/qv6phLZDYc//z8B7wEEiUgschDMis5Tk\ntF9V31DVx1xbY+UtAXnbH/d/txrE40hV3eW+3wUcGZAmyoREgC8Am4prXiDVPkEyX/vThNkdLdeI\nI9qlopBnD3ALcB3QR3ko5NkfD7whIveKyOMicpeIHJSotZnk/fxVdS+wEvg9zijLN1X1JwnaGkTU\nuqTYeYtFUWyI8r9bEeLhxjSeDHjN9qZTpz8VFOHPGfUXkaVAr6quL5LZ2aj2CZL52t+fT0RGAPcD\nX3ZbMaUiX9tFRM4F/qCq2wI+LxWFPPtaYArwr6o6BWcE4+Ii2haFvH/7IjIBuBrH5XIMMEJE/r54\npkWikBFElTD6qGAbov7vJjnPIzKq2hT2mYjsEpGjVPV1ETka+ENAsqwTEkVkPo4r4rPFsTgnJZkg\nmSD52v8KgIgcAGwAvq+q/56gnUEUYnsLMFucBTv/BjhERL6rqpckaK+fQuwX4GVV/bV7/n5KLx6F\n2P9p4OequgdARH4MfAIn/lQqotifRN5iUZANsf53SxnMyTMA9A1gkft+McEB81rgeZwWSx3pAfOZ\nwNPAmBLaHGqPJ403aDiVgaBhzrwVbr8A3wVuKdPvJW/bfWmmAw9Wm/3AI8CJ7vsbgJuqxX7go8BT\nwHD3d7QW+MdKs9+T9gbSA85V8b+bxf5Y/7sl/cfI82GMBn4C/AbYDIxyzx8DbPSkOxtndMBOYInn\n/HPAi8A29/WvJbI7wx7gSuBKT5rb3M+3A1Ny3UuJn3te9gOfxIkXPOF55jOrwXZfGdMpw2irIvx2\nTgF+7Z7/MSUebVUE+7+C09h7Ekc8Dqg0+3FGJb0E/An4I06MZkRY3mqxP+7/rk0SNAzDMGJTEQFz\nwzAMo7ow8TAMwzBiY+JhGIZhxMbEwzAMw4iNiYdhGIYRGxMPwzAMIzYmHoZhGEZsTDwMwzCM2Jh4\nGEYOROQ4d3Ode0XkWRFZJyIzRKRLnE3KPi4iB4vId0TkUXdF29mevI+IyFb3dYZ7/tMi8n9F5Efu\nxk3fL+9dGkY8bIa5YeTAXZ76OZy1l7pxl/9Q1ctckbjUPd+tquvE2e3yUZwlrRXoU9W/ishEYL2q\nflxEPg38O9AAvAZ0AdepaldJb84w8qQiVtU1jCrgd6r6NICIPI2z3ho4C/kdh7My7GwRWeiePxBn\nRdPXgdtE5BTgfWCip8xfqeqrbplPuOWYeBhVgYmHYUTjr573fUCv530tsB+Yo6rPeTOJyA3Aa6r6\neREZBvwlpMz3sf9Ho4qwmIdhFIcO4KrUgYg0um8Pwel9AFyCs8e0YVQ9Jh6GEQ1/cFB9728EDhCR\nHSLyFPB197N/Bea5bqkPA2+HlBF0bBgViwXMDcMwjNhYz8MwDMOIjYmHYRiGERsTD8MwDCM2Jh6G\nYRhGbEw8DMMwjNiYeBiGYRixMfEwDMMwYmPiYRiGYcTm/wc+m36HSPvANgAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -2412,7 +2409,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 39, @@ -2423,7 +2420,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/docs/source/pythonapi/examples/post-processing.ipynb b/docs/source/pythonapi/examples/post-processing.ipynb index e83c5bb8a1..1d4e578283 100644 --- a/docs/source/pythonapi/examples/post-processing.ipynb +++ b/docs/source/pythonapi/examples/post-processing.ipynb @@ -21,7 +21,6 @@ "\n", "import openmc\n", "from openmc.statepoint import StatePoint\n", - "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -168,20 +167,19 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.region = fuel_outer_radius.negative\n", + "fuel_cell.region = -fuel_outer_radius\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", - " clad_outer_radius.negative)\n", + "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator.region = clad_outer_radius.positive\n", + "moderator_cell.region = +clad_outer_radius\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -205,9 +203,7 @@ "root_cell.fill = pin_cell_universe\n", "\n", "# Add boundary planes\n", - "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", - " min_y.positive, max_y.negative,\n", - " min_z.positive, max_z.negative)\n", + "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", @@ -340,7 +336,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JEwAiCb5uYN4AAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMThUMjE6MTc6\nMDErMDc6MDA/DItCAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTE4VDIxOjE3OjAxKzA3OjAw\nTlEz/gAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98KAwIrNs33D4sAAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMTAtMDNUMDk6NDE6\nNDYrMDc6MDDfnDaWAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTEwLTAzVDA5OjQxOjQ2KzA3OjAw\nrsGOKgAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] @@ -452,8 +448,8 @@ " Copyright: 2011-2015 Massachusetts Institute of Technology\n", " License: http://mit-crpg.github.io/openmc/license.html\n", " Version: 0.7.0\n", - " Git SHA1: 3df61825cc8c93656ed1458c34fca14000884e73\n", - " Date/Time: 2015-09-19 07:34:09\n", + " Git SHA1: 71dfde8d12942170a9a8d91796ab40a6e9becaaf\n", + " Date/Time: 2015-10-03 09:43:54\n", " OpenMP Threads: 4\n", "\n", " ===========================================================================\n", @@ -589,20 +585,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 3.6600E-01 seconds\n", - " Reading cross sections = 1.1500E-01 seconds\n", - " Total time in simulation = 8.1308E+01 seconds\n", - " Time in transport only = 8.1157E+01 seconds\n", - " Time in inactive batches = 2.1600E+00 seconds\n", - " Time in active batches = 7.9148E+01 seconds\n", - " Time synchronizing fission bank = 1.6000E-02 seconds\n", - " Sampling source sites = 9.0000E-03 seconds\n", - " SEND/RECV source sites = 7.0000E-03 seconds\n", - " Time accumulating tallies = 1.0000E-02 seconds\n", - " Total time for finalization = 1.6400E-01 seconds\n", - " Total time elapsed = 8.1856E+01 seconds\n", - " Calculation Rate (inactive) = 23148.1 neutrons/second\n", - " Calculation Rate (active) = 5685.55 neutrons/second\n", + " Total time for initialization = 4.3100E-01 seconds\n", + " Reading cross sections = 1.3800E-01 seconds\n", + " Total time in simulation = 1.1654E+02 seconds\n", + " Time in transport only = 1.1510E+02 seconds\n", + " Time in inactive batches = 3.7070E+00 seconds\n", + " Time in active batches = 1.1283E+02 seconds\n", + " Time synchronizing fission bank = 1.0000E-02 seconds\n", + " Sampling source sites = 6.0000E-03 seconds\n", + " SEND/RECV source sites = 4.0000E-03 seconds\n", + " Time accumulating tallies = 6.0000E-03 seconds\n", + " Total time for finalization = 2.7600E-01 seconds\n", + " Total time elapsed = 1.1727E+02 seconds\n", + " Calculation Rate (inactive) = 13488.0 neutrons/second\n", + " Calculation Rate (active) = 3988.19 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", @@ -680,8 +676,8 @@ "\tName =\t\n", "\tFilters =\t\n", " \t\tmesh\t[10000]\n", - "\tNuclides =\t-1 \n", - "\tScores =\t['flux', 'fission']\n", + "\tNuclides =\ttotal \n", + "\tScores =\t[u'flux', u'fission']\n", "\tEstimator =\ttracklength\n", "\n" ] @@ -815,8 +811,8 @@ "\tName =\t\n", "\tFilters =\t\n", " \t\tmesh\t[10000]\n", - "\tNuclides =\t-1 \n", - "\tScores =\t['flux']\n", + "\tNuclides =\ttotal \n", + "\tScores =\t[u'flux']\n", "\tEstimator =\ttracklength\n", "\n" ] @@ -859,7 +855,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 24, @@ -870,7 +866,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -902,7 +898,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1016,7 +1012,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 28, @@ -1027,7 +1023,7 @@ "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEUCAYAAAA8+dFZAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGeRJREFUeJzt3X20ZFV55/Hvz8YXUBL6Jo4O0IojELtdOgENsGJmxBdc\npFVQOhFoEpUZBY0dXyaZMK6oMOOsTHSiImHJ4BIVDQ0qEAdHEF9BaR0UQVT6grAcMrysIcRu3yAq\nL8/8UXWhKG7VrXO7zq26t7+ftWp1nX32OfXUprof9tn77JOqQpKkUT1i0gFIkpYXE4ckqREThySp\nEROHJKkRE4ckqREThySpkVYTR5LDk1yf5MYkJ82z/2lJvpHkF0n+rMmxkqTJSFv3cSRZBdwAvBC4\nDfgWcGxVzfbUeTzwZOBlwPaqes+ox0qSJqPNHsdBwE1VdXNV3QOcBxzZW6Gq7qyqq4B7mh4rSZqM\nNhPHXsAtPdu3dsvaPlaS1KI2E8eOXANzHRRJmlK7tHju24A1Pdtr6PQcxnZsEhOMJC1CVWWxx7bZ\n47gK2C/JPkkeBRwNXDSgbv8XGPnYqmr9dfLJJ7d+3EJ1B+1vUt5f1r991FFHTW1bNjl2lHq25/ja\nc9j+UdptlLKlaMsdac+l+Lu+I+3Zv72jWutxVNW9STYBlwKrgLOqajbJid39ZyZ5Ip0ZU78G3J/k\nTcC6qvr5fMe2FetCDj300NaPW6juoP1NyvvLFvu9dsSOfOaox45Sz/YcX3sO2z9KuzUpa9s0/10f\ntG8Sv83WpuMuhSS1nOOfNhs2bOCCCy6YdBgrhu05PrbleCWhpvRSlZaZtWvXTjqEFcX2HB/bcrqY\nOPSAdevWTTqEFcX2HB/bcrqYOCRJjZg4JEmNmDgkSY2YOCRJjZg4JEmNmDgkSY2YOCRJjZg4JEmN\nmDgkSY2YOCRJjZg4JK14MzOQzP+amZl0dMtPmw9ykqSpsH07DFpIO4teI3bnZY9DktSIiUOS1IiJ\nQ5LUiIlDktSIiUPSsuHsqOngrCpJy4azo6aDPQ5JUiMmDklSIyYOSVIjJg5JUiMmDklSIyYOSZqH\nU38HczquJM3Dqb+D2eOQJDVi4pAkNWLikCQ1YuKQJDVi4pAkNWLikCQ1YuKQJDVi4pAkNWLikCQ1\n0mriSHJ4kuuT3JjkpAF1TuvuvzbJAT3lb01yXZLvJdmc5NFtxipJGk1riSPJKuB04HBgHXBskrV9\n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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -1078,7 +1074,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, diff --git a/docs/source/pythonapi/examples/tally-arithmetic.ipynb b/docs/source/pythonapi/examples/tally-arithmetic.ipynb index b5ba328a05..7b850a2ebb 100644 --- a/docs/source/pythonapi/examples/tally-arithmetic.ipynb +++ b/docs/source/pythonapi/examples/tally-arithmetic.ipynb @@ -36,7 +36,6 @@ "import openmc\n", "from openmc.statepoint import StatePoint\n", "from openmc.summary import Summary\n", - "from openmc.region import Intersection\n", "\n", "%matplotlib inline" ] @@ -183,20 +182,19 @@ "# Create fuel Cell\n", "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", "fuel_cell.fill = fuel\n", - "fuel_cell.region = fuel_outer_radius.negative\n", + "fuel_cell.region = -fuel_outer_radius\n", "pin_cell_universe.add_cell(fuel_cell)\n", "\n", "# Create a clad Cell\n", "clad_cell = openmc.Cell(name='1.6% Clad')\n", "clad_cell.fill = zircaloy\n", - "clad_cell.region = Intersection(fuel_outer_radius.positive,\n", - " clad_outer_radius.negative)\n", + "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", "pin_cell_universe.add_cell(clad_cell)\n", "\n", "# Create a moderator Cell\n", "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", "moderator_cell.fill = water\n", - "moderator_cell.region = clad_outer_radius.positive\n", + "moderator_cell.region = +clad_outer_radius\n", "pin_cell_universe.add_cell(moderator_cell)" ] }, @@ -220,9 +218,7 @@ "root_cell.fill = pin_cell_universe\n", "\n", "# Add boundary planes\n", - "root_cell.region = Intersection(min_x.positive, max_x.negative,\n", - " min_y.positive, max_y.negative,\n", - " min_z.positive, max_z.negative)\n", + "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", "\n", "# Create root Universe\n", "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", @@ -356,7 +352,7 @@ "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98JFQMZGiFPL70AAALKSURBVGje7dpLcqQwDAbgHHE2\nYeEj+D4cwQucBUfo+3CEXoSp8OhuhF70T4qpKXmdr21LogK2Pj7A8QmNP+HDhw8fPnz48Kf6VH9G\n+66vy+je8k19jnf8C5dXIPv86ms56lPdjvaYbyodx3ze+XLE76cXFiD4zPji99z0/AJ4n1lfvJ6f\nnl0A6x+578efMSg1wPr172/jPO5yFXM+Ef78gdblM+WPHyguP//t1/g6pA0wfln+ho/fwgYYn19C\n/xwDvwHGc9OvC+hs37DTrwuwfWanXxdQTC9Mvyygs3wjTL8uwPJpn/tNDbSGz7T0SBEWw4vLXzbQ\n6b6RoveIoO6TvPxlA63qs7z8ZQPF9F+SH22vbX8OQKf5Rtv+EgDNJ3X58wZaxWd1+fMGiuFvir8b\nvjp8J/tGy/6jAmRvhW8fwL3vVT+o3grfPoB7r/IpALI3tz8FoJN84/NV873hB8UnM3xzANtf8nb4\ndwmg3grfFEDJO8JPE0i9Ff4pAYL3pI8mkHor/HMCeO9JH00g9SafEsh7T/ppARBvp48UwJnelT5S\nACd7O31TAlnvKx9SQCd7B58KgPO+8iMFuPWe9E8F8BveWX7bAjzX9y4//Jve+fhsH6Ctv7n8PTzj\nvY/v9gEOHz58+PBX+6v/f/wPvnd54f3j6venE/yl769Xv7+j3x/o98/V32/o9+fl389Xnx+g5x/o\n+Qt6/oOeP6HnX+j5G3z+h54/ouefV5/foufP6Pk3ev4On/+j9w/o/Qd6/4Le/6D3T/D9V67Y/ZsV\nQBq+s+8f0ftP+P41axXguP9NWgDuu/Cdfv+N3r/D9/9TAID+A7T/Ae2/gPs/0P4TtP8F7r9J3AIO\n9P+g/Udw/9Oygbf7r9D+L7j/DO1/Q/vv4P4/tP8Q7n9E+y/h/k+0/xTuf4X7b+H+X7T/+BPuf3aM\n8OHDhw8fPnz4w/4vzcvgeY10sY0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDktMjFUMTA6MDg6\nNTcrMDc6MDALr51VAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA5LTIxVDEwOjA4OjU3KzA3OjAw\nevIl6QAAAABJRU5ErkJggg==\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJN\nAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEX///9yEhLpgJFNv8Tq\nQYT7AAAAAWJLR0QAiAUdSAAAAAd0SU1FB98KAwI1HbUKyRQAAAPZSURBVGje7Zs7buMwEIZ9iey5\n0gyNjQpXKTYudIScgkdQYTfut1idwkdQkQNsYQO2Qj0sPiVK+mlQDmwgwIcgg8Cc4fCTSK5W4OeF\nkM8rHv+2I/rgxPZEPZgR7XtQxKdXYuUXJSUnBQ/9WCgo4vOSJ+WFUvF7E08mlia+rn7VcKXP8sRs\nzFX8b2MdX2y6v1Tw6MZUw4H4ojfIjD8mvn/qRL5p4+vvlMqvp2EhR8WBzfiz20hXORmP9fi/bM9E\neUFvV5H/0yRkeSbiGRfFJErxD9ENdz7Mbhig/h89fvtFdMiI/ePUIXV4lXju8K3DKv9NThOZ3q2K\nmUy6grxFES8rjeyic+FFQav+ncg3fXjH+Ts+/iibztFqOiZuZP/Z3OafPX40NGgST2r+uvQkXXp6\ncKvmr+r0e1Eef5um3+JHP3IFF1D/seNZJgaDmvY0Gav1s+2f1fqpIcublfKGt6apotG/NVx3SInW\ntLX+7Vg/Pv1YqOsnun6JSVdOXT/X7vk75f938QP+8OmSBs0fXtymMhJbf8qlPynYmpKCh7OB1fzN\nalOj1sl0ZAruHLiA+RM73pDe/VjMVP89+aTXwjyc/x5n+u991895/utrJTy8/06TXh0r/5JOa2Jm\nYmqi4r/vUm/H4wLmT+z4anhr05X+q6KUXhtzr/9qSff5L5uMT//V/NdU4YuBTPa/8P67l/6r44ds\n+hYuoP5jx9ciy6XTWlibBrmx8V/TdMfjkP+6pOsu/lvM9N90sf7r+f6m/65n+S8p/itN15v0UkW3\n/+48+PRfJX6S9Joo4g+G/1qYG9KroqP/WypcuvyXPf13wH89/hHef7MB6R3Cqn55U4rv4kfH3zaS\ngQuYP7HjVf89tXrbO+hfLdr+Ozv/SP1dgtQ/Ov8C+i/3+q/Zf2D/HWi6bjT6rym9I/v/03/b+LHS\n4cTg/utTsV7/net/Afzz4f0XGX84/2j9xZ4/sePR/of2X7D/o+vPo/sv6h9B/Bfxr9j1Hz2eN/hO\n8/wfff4A848+f/1A/530/I0+/8PvH9D3H9HnT+R49P0b+v4PfP/4E/wXfP8Mvf9G37/D/ovuP8Se\nP7Hj0f0vdP8tqP9O339cyv7p3P1fdP8Z3v9G999j13/seMax8x/o+ZN7+O+E8zdP/8XOf8Hnz9Dz\nb7HnT+x49PxlCp7/BM+fOv13wvnXBfivt2lMvD8TyH/Hnb+Gz3+j589jz5/Y8ej9h4D+W7qQmf57\nefqv239n3T+C7z+h969i13/seMax+3/o/cMcu/8Y2H9n3p+J6r98pv8m4fwXuH+M3n+OO3++AX9c\nlR+4PhbRAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE1LTEwLTAzVDA5OjUxOjU5KzA3OjAwJPCZIQAA\nACV0RVh0ZGF0ZTptb2RpZnkAMjAxNS0xMC0wM1QwOTo1MTo1OSswNzowMFWtIZ0AAAAASUVORK5C\nYII=\n", "text/plain": [ "" ] @@ -567,8 +563,9 @@ " Copyright: 2011-2015 Massachusetts Institute of Technology\n", " License: http://mit-crpg.github.io/openmc/license.html\n", " Version: 0.7.0\n", - " Git SHA1: b167d70c877c516deca785801b9fa6f53fb0985b\n", - " Date/Time: 2015-09-21 10:25:26\n", + " Git SHA1: 71dfde8d12942170a9a8d91796ab40a6e9becaaf\n", + " Date/Time: 2015-10-03 09:53:29\n", + " OpenMP Threads: 4\n", "\n", " ===========================================================================\n", " ========================> INITIALIZATION <=========================\n", @@ -623,20 +620,20 @@ "\n", " =======================> TIMING STATISTICS <=======================\n", "\n", - " Total time for initialization = 9.1800E-01 seconds\n", - " Reading cross sections = 6.5800E-01 seconds\n", - " Total time in simulation = 1.7037E+01 seconds\n", - " Time in transport only = 1.7024E+01 seconds\n", - " Time in inactive batches = 2.8600E+00 seconds\n", - " Time in active batches = 1.4177E+01 seconds\n", - " Time synchronizing fission bank = 4.0000E-03 seconds\n", - " Sampling source sites = 4.0000E-03 seconds\n", + " Total time for initialization = 3.7200E-01 seconds\n", + " Reading cross sections = 1.2400E-01 seconds\n", + " Total time in simulation = 4.7110E+00 seconds\n", + " Time in transport only = 4.6510E+00 seconds\n", + " Time in inactive batches = 6.1900E-01 seconds\n", + " Time in active batches = 4.0920E+00 seconds\n", + " Time synchronizing fission bank = 2.0000E-03 seconds\n", + " Sampling source sites = 2.0000E-03 seconds\n", " SEND/RECV source sites = 0.0000E+00 seconds\n", " Time accumulating tallies = 0.0000E+00 seconds\n", - " Total time for finalization = 1.0000E-03 seconds\n", - " Total time elapsed = 1.7971E+01 seconds\n", - " Calculation Rate (inactive) = 4370.63 neutrons/second\n", - " Calculation Rate (active) = 2645.13 neutrons/second\n", + " Total time for finalization = 2.0000E-03 seconds\n", + " Total time elapsed = 5.0950E+00 seconds\n", + " Calculation Rate (inactive) = 20193.9 neutrons/second\n", + " Calculation Rate (active) = 9164.22 neutrons/second\n", "\n", " ============================> RESULTS <============================\n", "\n", diff --git a/examples/python/basic/build-xml.py b/examples/python/basic/build-xml.py index 865740e13b..488603d33f 100644 --- a/examples/python/basic/build-xml.py +++ b/examples/python/basic/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -54,11 +53,11 @@ cell2 = openmc.Cell(cell_id=100, name='cell 2') cell3 = openmc.Cell(cell_id=101, name='cell 3') cell4 = openmc.Cell(cell_id=2, name='cell 4') -# Register Surfaces with Cells -cell1.region = surf2.negative -cell2.region = surf1.negative -cell3.region = surf1.positive -cell4.region = Intersection(surf2.positive, surf3.negative) +# Use surface half-spaces to define regions +cell1.region = -surf2 +cell2.region = -surf1 +cell3.region = +surf1 +cell4.region = +surf2 & -surf3 # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/lattice/hexagonal/build-xml.py b/examples/python/lattice/hexagonal/build-xml.py index b042e830ad..5fa0f9b1b9 100644 --- a/examples/python/lattice/hexagonal/build-xml.py +++ b/examples/python/lattice/hexagonal/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### @@ -68,13 +67,12 @@ cell4 = openmc.Cell(cell_id=500, name='cell 4') cell5 = openmc.Cell(cell_id=600, name='cell 5') cell6 = openmc.Cell(cell_id=601, name='cell 6') -# Register Surfaces with Cells -cell1.region = Intersection(left.positive, right.negative, - bottom.positive, top.negative) -cell2.region = fuel_surf.negative -cell3.region = fuel_surf.positive -cell5.region = fuel_surf.negative -cell6.region = fuel_surf.positive +# Use surface half-spaces to define regions +cell1.region = +left & -right & +bottom & -top +cell2.region = -fuel_surf +cell3.region = +fuel_surf +cell5.region = -fuel_surf +cell6.region = +fuel_surf # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/lattice/nested/build-xml.py b/examples/python/lattice/nested/build-xml.py index f4bc7d1ac9..501b3ee4b4 100644 --- a/examples/python/lattice/nested/build-xml.py +++ b/examples/python/lattice/nested/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### @@ -67,17 +66,15 @@ cell6 = openmc.Cell(cell_id=202, name='cell 6') cell7 = openmc.Cell(cell_id=301, name='cell 7') cell8 = openmc.Cell(cell_id=302, name='cell 8') -# Register Surfaces with Cells -cell1.region = Intersection(left.positive, right.negative, - bottom.positive, top.negative) -cell2.region = Intersection(left.positive, right.negative, - bottom.positive, top.negative) -cell3.region = fuel1.negative -cell4.region = fuel1.positive -cell5.region = fuel2.negative -cell6.region = fuel2.positive -cell7.region = fuel3.negative -cell8.region = fuel3.positive +# Use surface half-space to define regions +cell1.region = +left & -right & +bottom & -top +cell2.region = +left & -right & +bottom & -top +cell3.region = -fuel1 +cell4.region = +fuel1 +cell5.region = -fuel2 +cell6.region = +fuel2 +cell7.region = -fuel3 +cell8.region = +fuel3 # Register Materials with Cells cell3.fill = fuel diff --git a/examples/python/lattice/simple/build-xml.py b/examples/python/lattice/simple/build-xml.py index 155cfa1cbf..00fbea22a4 100644 --- a/examples/python/lattice/simple/build-xml.py +++ b/examples/python/lattice/simple/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -65,15 +64,14 @@ cell5 = openmc.Cell(cell_id=202, name='cell 5') cell6 = openmc.Cell(cell_id=301, name='cell 6') cell7 = openmc.Cell(cell_id=302, name='cell 7') -# Register Regions with Cells -cell1.region = Intersection(left.positive, right.negative, - bottom.positive, top.negative) -cell2.region = fuel1.negative -cell3.region = fuel1.positive -cell4.region = fuel2.negative -cell5.region = fuel2.positive -cell6.region = fuel3.negative -cell7.region = fuel3.positive +# Use surface half-spaces to define regions +cell1.region = +left & -right & +bottom & -top +cell2.region = -fuel1 +cell3.region = +fuel1 +cell4.region = -fuel2 +cell5.region = +fuel2 +cell6.region = -fuel3 +cell7.region = +fuel3 # Register Materials with Cells cell2.fill = fuel diff --git a/examples/python/pincell/build-xml.py b/examples/python/pincell/build-xml.py index d37024db3e..b3bb932dc8 100644 --- a/examples/python/pincell/build-xml.py +++ b/examples/python/pincell/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -132,12 +131,11 @@ gap = openmc.Cell(cell_id=2, name='cell 2') clad = openmc.Cell(cell_id=3, name='cell 3') water = openmc.Cell(cell_id=4, name='cell 4') -# Register Surfaces with Cells -fuel.region = fuel_or.negative -gap.region = Intersection(fuel_or.positive, clad_ir.negative) -clad.region = Intersection(clad_ir.positive, clad_or.negative) -water.region = Intersection(clad_or.positive, left.positive, right.negative, - bottom.positive, top.negative) +# Use surface half-spaces to define regions +fuel.region = -fuel_or +gap.region = +fuel_or & -clad_ir +clad.region = +clad_ir & -clad_or +water.region = +clad_or & +left & -right & +bottom & -top # Register Materials with Cells fuel.fill = uo2 diff --git a/examples/python/reflective/build-xml.py b/examples/python/reflective/build-xml.py index 5a3e861e60..9eab4aec32 100644 --- a/examples/python/reflective/build-xml.py +++ b/examples/python/reflective/build-xml.py @@ -1,5 +1,4 @@ import openmc -from openmc.region import Intersection ############################################################################### # Simulation Input File Parameters @@ -52,10 +51,8 @@ surf6.boundary_type = 'reflective' # Instantiate Cell cell = openmc.Cell(cell_id=1, name='cell 1') -# Register Region with Cell -cell.region = Intersection(surf1.positive, surf2.negative, - surf3.positive, surf4.negative, - surf5.positive, surf6.negative) +# Use surface half-spaces to define region +cell.region = +surf1 & -surf2 & +surf3 & -surf4 & +surf5 & -surf6 # Register Material with Cell cell.fill = fuel diff --git a/openmc/region.py b/openmc/region.py index c4e1e2143b..24a21c3970 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -52,9 +52,9 @@ class Region(object): if i_start >= 0: j = int(expression[i_start:i]) if j < 0: - tokens.append(surfaces[abs(j)].negative) + tokens.append(-surfaces[abs(j)]) else: - tokens.append(surfaces[abs(j)].positive) + tokens.append(+surfaces[abs(j)]) if expression[i] in '()|~': # For everything other than intersection, add the operator @@ -89,9 +89,9 @@ class Region(object): if i_start >= 0: j = int(expression[i_start:]) if j < 0: - tokens.append(surfaces[abs(j)].negative) + tokens.append(-surfaces[abs(j)]) else: - tokens.append(surfaces[abs(j)].positive) + tokens.append(+surfaces[abs(j)]) # The functions below are used to apply an operator to operands on the # output queue during the shunting yard algorithm. diff --git a/openmc/universe.py b/openmc/universe.py index e9a693bc43..c03e1305c6 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -194,7 +194,7 @@ class Cell(object): # If no region has been assigned, simply use the half-space. Otherwise, # take the intersection of the current region and the half-space # specified - region = surface.positive if halfspace == 1 else surface.negative + region = +surface if halfspace == 1 else -surface if self.region is None: self.region = region else: From 81ed29cc3825cf7fae1bcecfa4f11b8dd860b3de Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 3 Oct 2015 10:01:00 +0700 Subject: [PATCH 41/48] Add deprecation warning for Cell.add_surface() --- openmc/universe.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openmc/universe.py b/openmc/universe.py index c03e1305c6..d7988c8d90 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -3,6 +3,7 @@ from collections import OrderedDict, Iterable from numbers import Real, Integral from xml.etree import ElementTree as ET import sys +import warnings import numpy as np @@ -181,6 +182,12 @@ class Cell(object): """ + warnings.simplefilter('always', DeprecationWarning) + warnings.warn("Cell.add_surface(...) has been deprecated and may be " + "removed in a future version. The region for a Cell " + "should be defined using the region property directly.", + DeprecationWarning) + if not isinstance(surface, openmc.Surface): msg = 'Unable to add Surface "{0}" to Cell ID="{1}" since it is ' \ 'not a Surface object'.format(surface, self._id) From e3436d625bb1063b59225f955a1c6afc22fd2981 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 3 Oct 2015 17:58:50 +0700 Subject: [PATCH 42/48] Respond to more @smharper comments on #463 Move abstract interface block in surface_header. Make error messages more informative. Add description in openmc-update-inputs epilog. --- scripts/openmc-update-inputs | 5 +-- src/input_xml.F90 | 11 +++--- src/string.F90 | 15 ++++++++ src/surface_header.F90 | 68 +++++++++++++++++++++--------------- 4 files changed, 64 insertions(+), 35 deletions(-) diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index 1ff70d0505..2a8097854d 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -36,9 +36,10 @@ they will be moved to a new file with '.original' appended to their name. Formatting changes that will be made: -geometry.xml: Lattices containing 'outside' attributes/tags will be replaced +geometry.xml: Lattices containing 'outside' attributes/tags will be replaced with lattices containing 'outer' attributes, and the appropriate - cells/universes will be added. + cells/universes will be added. Any 'surfaces' attributes/elements on a cell + will be renamed 'region'. """ diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 8a77eaf354..7c6ac4cb72 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1135,7 +1135,7 @@ contains call tokenize(region_spec, tokens) ! Use shunting-yard algorithm to determine RPN for surface algorithm - call generate_rpn(tokens, rpn) + call generate_rpn(c%id, tokens, rpn) ! Copy region spec and RPN form to cell arrays allocate(c % region(tokens%size())) @@ -4801,7 +4801,8 @@ contains ! the infix notation. !=============================================================================== - subroutine generate_rpn(tokens, output) + subroutine generate_rpn(cell_id, tokens, output) + integer, intent(in) :: cell_id type(VectorInt), intent(in) :: tokens ! infix notation type(VectorInt), intent(inout) :: output ! RPN notation @@ -4851,7 +4852,8 @@ contains ! If we run out of operators without finding a left parenthesis, it ! means there are mismatched parentheses. if (stack%size() == 0) then - call fatal_error('Mimatched parentheses in region specification') + call fatal_error('Mimatched parentheses in region specification & + &for cell ' // trim(to_str(cell_id)) // '.') end if op = stack%data(stack%size()) @@ -4871,7 +4873,8 @@ contains ! If the operator is a parenthesis, it is mismatched if (op >= OP_RIGHT_PAREN) then - call fatal_error('Mimatched parentheses in region specification') + call fatal_error('Mimatched parentheses in region specification & + &for cell ' // trim(to_str(cell_id)) // '.') end if call output%push_back(op) diff --git a/src/string.F90 b/src/string.F90 index 91a255a361..45db59c875 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -76,6 +76,7 @@ contains integer :: i ! current index integer :: i_start ! starting index of word + integer :: token character(len=len_trim(string)) :: string_ ! Remove leading blanks @@ -97,8 +98,22 @@ contains case ('(') call tokens%push_back(OP_LEFT_PAREN) case (')') + if (tokens%size() > 0) then + token = tokens%data(tokens%size()) + if (token >= OP_UNION .and. token < OP_RIGHT_PAREN) then + call fatal_error("Right parentheses cannot follow an operator in & + ®ion specification: " // trim(string)) + end if + end if call tokens%push_back(OP_RIGHT_PAREN) case ('|') + if (tokens%size() > 0) then + token = tokens%data(tokens%size()) + if (.not. (token < OP_UNION .or. token == OP_RIGHT_PAREN)) then + call fatal_error("Union cannot follow an operator in region & + &specification: " // trim(string)) + end if + end if call tokens%push_back(OP_UNION) case ('~') call tokens%push_back(OP_COMPLEMENT) diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 18ad030a2e..6fc1bbc237 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -24,10 +24,45 @@ module surface_header procedure(iNormal), deferred :: normal end type Surface + abstract interface + pure function iEvaluate(this, xyz) result(f) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: f + end function iEvaluate + + pure function iDistance(this, xyz, uvw, coincident) result(d) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8), intent(in) :: uvw(3) + logical, intent(in) :: coincident + real(8) :: d + end function iDistance + + pure function iNormal(this, xyz) result(uvw) + import Surface + class(Surface), intent(in) :: this + real(8), intent(in) :: xyz(3) + real(8) :: uvw(3) + end function iNormal + end interface + +!=============================================================================== +! SURFACECONTAINER allows us to store an array of different types of surfaces +!=============================================================================== + type :: SurfaceContainer class(Surface), allocatable :: obj end type SurfaceContainer +!=============================================================================== +! All the derived types below are extensions of the abstract Surface type. They +! inherent the reflect() and sense() type-bound procedures and must implement +! evaluate(), distance(), and normal() +!=============================================================================== + type, extends(Surface) :: SurfaceXPlane ! x = x0 real(8) :: x0 @@ -148,31 +183,6 @@ module surface_header procedure :: normal => z_cone_normal end type SurfaceZCone - abstract interface - pure function iEvaluate(this, xyz) result(f) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f - end function iEvaluate - - pure function iDistance(this, xyz, uvw, coincident) result(d) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - logical, intent(in) :: coincident - real(8) :: d - end function iDistance - - pure function iNormal(this, xyz) result(uvw) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: uvw(3) - end function iNormal - end interface - contains !=============================================================================== @@ -369,14 +379,14 @@ contains real(8) :: d real(8) :: f - real(8) :: tmp + real(8) :: projection f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D - tmp = this%A*uvw(1) + this%B*uvw(2) + this%C*uvw(3) - if (coincident .or. abs(f) < FP_COINCIDENT .or. tmp == ZERO) then + projection = this%A*uvw(1) + this%B*uvw(2) + this%C*uvw(3) + if (coincident .or. abs(f) < FP_COINCIDENT .or. projection == ZERO) then d = INFINITY else - d = -f/tmp + d = -f/projection if (d < ZERO) d = INFINITY end if end function plane_distance From fa8bbfd43f4183bda869725d4d77812971c839af Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 4 Oct 2015 09:36:37 +0700 Subject: [PATCH 43/48] Make sure region specification gets written correctly in summary.h5 --- src/summary.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/summary.F90 b/src/summary.F90 index 56c31452b4..5a37eed8fb 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -188,7 +188,7 @@ contains region_spec = trim(region_spec) // " ~" case (OP_INTERSECTION) case (OP_UNION) - region_spec = trim(region_spec) // " ^" + region_spec = trim(region_spec) // " |" case default region_spec = trim(region_spec) // " " // to_str(& sign(surfaces(abs(k))%obj%id, k)) From a611b69500a4876d25c463fbf313a0ac9dc9ab86 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 4 Oct 2015 11:10:38 +0700 Subject: [PATCH 44/48] Add 'boxes' example input files --- examples/python/boxes/build-xml.py | 118 +++++++++++++++++++++++++++++ examples/xml/boxes/geometry.xml | 39 ++++++++++ examples/xml/boxes/materials.xml | 23 ++++++ examples/xml/boxes/settings.xml | 16 ++++ 4 files changed, 196 insertions(+) create mode 100644 examples/python/boxes/build-xml.py create mode 100644 examples/xml/boxes/geometry.xml create mode 100644 examples/xml/boxes/materials.xml create mode 100644 examples/xml/boxes/settings.xml diff --git a/examples/python/boxes/build-xml.py b/examples/python/boxes/build-xml.py new file mode 100644 index 0000000000..fcbe242eee --- /dev/null +++ b/examples/python/boxes/build-xml.py @@ -0,0 +1,118 @@ +import openmc + +############################################################################### +# Simulation Input File Parameters +############################################################################### + +# OpenMC simulation parameters +batches = 15 +inactive = 5 +particles = 10000 + + +############################################################################### +# Exporting to OpenMC materials.xml File +############################################################################### + +# Instantiate some Nuclides +h1 = openmc.Nuclide('H-1') +o16 = openmc.Nuclide('O-16') +u235 = openmc.Nuclide('U-235') +u238 = openmc.Nuclide('U-238') + +# Instantiate some Materials and register the appropriate Nuclides +fuel1 = openmc.Material(material_id=1, name='fuel') +fuel1.set_density('g/cc', 4.5) +fuel1.add_nuclide(u235, 1.) + +fuel2 = openmc.Material(material_id=2, name='depleted fuel') +fuel2.set_density('g/cc', 4.5) +fuel2.add_nuclide(u238, 1.) + +moderator = openmc.Material(material_id=3, name='moderator') +moderator.set_density('g/cc', 1.0) +moderator.add_nuclide(h1, 2.) +moderator.add_nuclide(o16, 1.) +moderator.add_s_alpha_beta('HH2O', '71t') + +# Instantiate a MaterialsFile, register all Materials, and export to XML +materials_file = openmc.MaterialsFile() +materials_file.default_xs = '71c' +materials_file.add_materials([fuel1, fuel2, moderator]) +materials_file.export_to_xml() + + +############################################################################### +# Exporting to OpenMC geometry.xml File +############################################################################### + +# Instantiate planar surfaces +x1 = openmc.XPlane(surface_id=1, x0=-10) +x2 = openmc.XPlane(surface_id=2, x0=-7) +x3 = openmc.XPlane(surface_id=3, x0=-4) +x4 = openmc.XPlane(surface_id=4, x0=4) +x5 = openmc.XPlane(surface_id=5, x0=7) +x6 = openmc.XPlane(surface_id=6, x0=10) +y1 = openmc.YPlane(surface_id=11, y0=-10) +y2 = openmc.YPlane(surface_id=12, y0=-7) +y3 = openmc.YPlane(surface_id=13, y0=-4) +y4 = openmc.YPlane(surface_id=14, y0=4) +y5 = openmc.YPlane(surface_id=15, y0=7) +y6 = openmc.YPlane(surface_id=16, y0=10) +z1 = openmc.ZPlane(surface_id=21, z0=-10) +z2 = openmc.ZPlane(surface_id=22, z0=-7) +z3 = openmc.ZPlane(surface_id=23, z0=-4) +z4 = openmc.ZPlane(surface_id=24, z0=4) +z5 = openmc.ZPlane(surface_id=25, z0=7) +z6 = openmc.ZPlane(surface_id=26, z0=10) + +# Set vacuum boundary conditions on outside +for surface in [x1, x6, y1, y6, z1, z6]: + surface.boundary_type = 'vacuum' + +# Instantiate Cells +inner_box = openmc.Cell(cell_id=1, name='inner box') +middle_box = openmc.Cell(cell_id=2, name='middle box') +outer_box = openmc.Cell(cell_id=3, name='outer box') + +# Use each set of six planes to create solid cube regions. We can then use these +# to create cubic shells. +inner_cube = +x3 & -x4 & +y3 & -y4 & +z3 & -z4 +middle_cube = +x2 & -x5 & +y2 & -y5 & +z2 & -z5 +outer_cube = +x1 & -x6 & +y1 & -y6 & +z1 & -z6 + +# Use surface half-spaces to define regions +inner_box.region = inner_cube +middle_box.region = middle_cube & ~inner_cube +outer_box.region = outer_cube & ~middle_cube + +# Register Materials with Cells +inner_box.fill = fuel1 +middle_box.fill = fuel2 +outer_box.fill = moderator + +# Instantiate root universe +root = openmc.Universe(universe_id=0, name='root universe') +root.add_cells([inner_box, middle_box, outer_box]) + +# Instantiate a Geometry and register the root Universe +geometry = openmc.Geometry() +geometry.root_universe = root + +# Instantiate a GeometryFile, register Geometry, and export to XML +geometry_file = openmc.GeometryFile() +geometry_file.geometry = geometry +geometry_file.export_to_xml() + + +############################################################################### +# Exporting to OpenMC settings.xml File +############################################################################### + +# Instantiate a SettingsFile, set all runtime parameters, and export to XML +settings_file = openmc.SettingsFile() +settings_file.batches = batches +settings_file.inactive = inactive +settings_file.particles = particles +settings_file.set_source_space('point', [0., 0., 0.]) +settings_file.export_to_xml() diff --git a/examples/xml/boxes/geometry.xml b/examples/xml/boxes/geometry.xml new file mode 100644 index 0000000000..29867f01ff --- /dev/null +++ b/examples/xml/boxes/geometry.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/xml/boxes/materials.xml b/examples/xml/boxes/materials.xml new file mode 100644 index 0000000000..c6a591d2a4 --- /dev/null +++ b/examples/xml/boxes/materials.xml @@ -0,0 +1,23 @@ + + + + 71c + + + + + + + + + + + + + + + + + + + diff --git a/examples/xml/boxes/settings.xml b/examples/xml/boxes/settings.xml new file mode 100644 index 0000000000..0ac26ec4d4 --- /dev/null +++ b/examples/xml/boxes/settings.xml @@ -0,0 +1,16 @@ + + + + + + 15 + 5 + 10000 + + + + + + + + From 4c2e0f5f82a3f19e65d3a18ed69a82af6f8c8f21 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 4 Oct 2015 21:47:52 +0700 Subject: [PATCH 45/48] Add examples in docstrings for Halfspace, Intersection, Union, and Complement --- openmc/region.py | 40 ++++++++++++++++++++++++++++++++++++++++ openmc/surface.py | 10 ++++++++++ 2 files changed, 50 insertions(+) diff --git a/openmc/region.py b/openmc/region.py index 24a21c3970..5baac22dd2 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -5,6 +5,15 @@ from openmc.checkvalue import check_type class Region(object): + """Region of space that can be assigned to a cell. + + Region is an abstract base class that is inherited by Halfspace, + Intersection, Union, and Complement. Each of those respective classes are + typically not instantiated directly but rather are created through operators + of the Surface and Region classes. + + """ + __metaclass__ = ABCMeta def __and__(self, other): @@ -178,6 +187,17 @@ class Region(object): class Intersection(Region): """Intersection of two or more regions. + Instances of Intersection are generally created via the __and__ operator + applied to two instances of Region. This is illustrated in the following + example: + + >>> equator = openmc.surface.ZPlane(z0=0.0) + >>> earth = openmc.surface.Sphere(R=637.1e6) + >>> northern_hemisphere = -earth & +equator + >>> southern_hemisphere = -earth & -equator + >>> type(northern_hemisphere) + + Parameters ---------- *nodes @@ -209,6 +229,14 @@ class Intersection(Region): class Union(Region): """Union of two or more regions. + Instances of Union are generally created via the __or__ operator applied to + two instances of Region. This is illustrated in the following example: + + >>> s1 = openmc.surface.ZPlane(z0=0.0) + >>> s2 = openmc.surface.Sphere(R=637.1e6) + >>> type(-s2 | +s1) + + Parameters ---------- *nodes @@ -240,6 +268,18 @@ class Union(Region): class Complement(Region): """Complement of a region. + The Complement of an existing Region can be created by using the __invert__ + operator as the following example demonstrates: + + >>> xl = openmc.surface.XPlane(x0=-10.0) + >>> xr = openmc.surface.XPlane(x0=10.0) + >>> yl = openmc.surface.YPlane(y0=-10.0) + >>> yr = openmc.surface.YPlane(y0=10.0) + >>> inside_box = +xl & -xr & +yl & -yl + >>> outside_box = ~inside_box + >>> type(outside_box) + + Parameters ---------- node : Region diff --git a/openmc/surface.py b/openmc/surface.py index 74f4fd7805..66376c2a0c 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -958,6 +958,16 @@ class Halfspace(Region): is referred to as the negative half-space and the region for which :math:`f(x,y,z) > 0` is referred to as the positive half-space. + Instances of Halfspace are generally not instantiated directly. Rather, they + can be created from an existing Surface through the __neg__ and __pos__ + operators, as the following example demonstrates: + + >>> sphere = openmc.surface.Sphere(surface_id=1, R=10.0) + >>> inside_sphere = -sphere + >>> outside_sphere = +sphere + >>> type(inside_sphere) + + Parameters ---------- surface : Surface From bb4608cf13ad8c1ecfd2c05614bd66210aeb2244 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 5 Oct 2015 07:32:48 +0700 Subject: [PATCH 46/48] Fix 'boxes' example to have complement and union --- examples/python/boxes/build-xml.py | 18 +++++++++++++++++- examples/xml/boxes/geometry.xml | 4 ++-- examples/xml/boxes/materials.xml | 2 +- examples/xml/boxes/plots.xml | 9 +++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 examples/xml/boxes/plots.xml diff --git a/examples/python/boxes/build-xml.py b/examples/python/boxes/build-xml.py index fcbe242eee..4bac9fff4d 100644 --- a/examples/python/boxes/build-xml.py +++ b/examples/python/boxes/build-xml.py @@ -80,10 +80,11 @@ outer_box = openmc.Cell(cell_id=3, name='outer box') inner_cube = +x3 & -x4 & +y3 & -y4 & +z3 & -z4 middle_cube = +x2 & -x5 & +y2 & -y5 & +z2 & -z5 outer_cube = +x1 & -x6 & +y1 & -y6 & +z1 & -z6 +outside_inner_cube = -x3 | +x4 | -y3 | +y4 | -z3 | +z4 # Use surface half-spaces to define regions inner_box.region = inner_cube -middle_box.region = middle_cube & ~inner_cube +middle_box.region = middle_cube & outside_inner_cube outer_box.region = outer_cube & ~middle_cube # Register Materials with Cells @@ -116,3 +117,18 @@ settings_file.inactive = inactive settings_file.particles = particles settings_file.set_source_space('point', [0., 0., 0.]) settings_file.export_to_xml() + +############################################################################### +# Exporting to OpenMC plots.xml File +############################################################################### + +plot = openmc.Plot(plot_id=1) +plot.origin = [0, 0, 0] +plot.width = [20, 20] +plot.pixels = [200, 200] +plot.color = 'cell' + +# Instantiate a PlotsFile, add Plot, and export to XML +plot_file = openmc.PlotsFile() +plot_file.add_plot(plot) +plot_file.export_to_xml() diff --git a/examples/xml/boxes/geometry.xml b/examples/xml/boxes/geometry.xml index 29867f01ff..abe4924e66 100644 --- a/examples/xml/boxes/geometry.xml +++ b/examples/xml/boxes/geometry.xml @@ -31,9 +31,9 @@ - + - + diff --git a/examples/xml/boxes/materials.xml b/examples/xml/boxes/materials.xml index c6a591d2a4..6f6114a7da 100644 --- a/examples/xml/boxes/materials.xml +++ b/examples/xml/boxes/materials.xml @@ -15,8 +15,8 @@ - + diff --git a/examples/xml/boxes/plots.xml b/examples/xml/boxes/plots.xml new file mode 100644 index 0000000000..b7a3093d25 --- /dev/null +++ b/examples/xml/boxes/plots.xml @@ -0,0 +1,9 @@ + + + + cell + 0. 0. 0. + 20. 20. + 200 200 + + From cfb17517eb3d3fefa2edced5529c15f7455e3800 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 5 Oct 2015 07:45:55 +0700 Subject: [PATCH 47/48] Overload __invert__ for Halfspace (return opposite Halfspace) --- openmc/surface.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openmc/surface.py b/openmc/surface.py index 66376c2a0c..afa426fa3b 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -988,6 +988,9 @@ class Halfspace(Region): self.surface = surface self.side = side + def __invert__(self): + return -self.surface if self.side == '+' else +self.surface + @property def surface(self): return self._surface From 1ad6602b5c5f331a2d8d30d28f7df4c87ba5cf86 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 5 Oct 2015 08:25:39 +0700 Subject: [PATCH 48/48] Convert input_set to use region property and fix error in cell 2 --- tests/input_set.py | 98 ++++++------------- tests/test_filter_cell/inputs_true.dat | 2 +- tests/test_filter_cellborn/inputs_true.dat | 2 +- tests/test_filter_energy/inputs_true.dat | 2 +- tests/test_filter_energyout/inputs_true.dat | 2 +- .../inputs_true.dat | 2 +- tests/test_filter_material/inputs_true.dat | 2 +- tests/test_filter_universe/inputs_true.dat | 2 +- tests/test_score_MT/inputs_true.dat | 2 +- tests/test_score_absorption/inputs_true.dat | 2 +- tests/test_score_events/inputs_true.dat | 2 +- tests/test_score_fission/inputs_true.dat | 2 +- tests/test_score_flux/inputs_true.dat | 2 +- tests/test_score_flux_yn/inputs_true.dat | 2 +- tests/test_score_kappafission/inputs_true.dat | 2 +- tests/test_score_nufission/inputs_true.dat | 2 +- tests/test_score_nuscatter/inputs_true.dat | 2 +- tests/test_score_nuscatter_n/inputs_true.dat | 2 +- tests/test_score_nuscatter_pn/inputs_true.dat | 2 +- tests/test_score_nuscatter_yn/inputs_true.dat | 2 +- tests/test_score_scatter/inputs_true.dat | 2 +- tests/test_score_scatter_n/inputs_true.dat | 2 +- tests/test_score_scatter_pn/inputs_true.dat | 2 +- tests/test_score_scatter_yn/inputs_true.dat | 2 +- tests/test_score_total/inputs_true.dat | 2 +- tests/test_score_total_yn/inputs_true.dat | 2 +- tests/test_score_total_yn/results_true.dat | 2 +- 27 files changed, 56 insertions(+), 94 deletions(-) diff --git a/tests/input_set.py b/tests/input_set.py index 0af9345d9a..87b857f4a9 100644 --- a/tests/input_set.py +++ b/tests/input_set.py @@ -296,56 +296,52 @@ class InputSet(object): fuel_cold = openmc.Universe(name='Fuel pin, cladding, cold water', universe_id=1) c21 = openmc.Cell(cell_id=21) - c21.add_surface(s1, -1) + c21.region = -s1 c21.fill = fuel c22 = openmc.Cell(cell_id=22) - c22.add_surface(s1, +1) - c22.add_surface(s2, -1) + c22.region = +s1 & -s2 c22.fill = clad c23 = openmc.Cell(cell_id=23) - c23.add_surface(s2, +1) + c23.region = +s2 c23.fill = cold_water fuel_cold.add_cells((c21, c22, c23)) tube_cold = openmc.Universe(name='Instrumentation guide tube, ' 'cold water', universe_id=2) c24 = openmc.Cell(cell_id=24) - c24.add_surface(s3, -1) + c24.region = -s3 c24.fill = cold_water c25 = openmc.Cell(cell_id=25) - c25.add_surface(s3, +1) - c25.add_surface(s4, -1) + c25.region = +s3 & -s4 c25.fill = clad c26 = openmc.Cell(cell_id=26) - c26.add_surface(s4, +1) + c26.region = +s4 c26.fill = cold_water tube_cold.add_cells((c24, c25, c26)) fuel_hot = openmc.Universe(name='Fuel pin, cladding, hot water', universe_id=3) c27 = openmc.Cell(cell_id=27) - c27.add_surface(s1, -1) + c27.region = -s1 c27.fill = fuel c28 = openmc.Cell(cell_id=28) - c28.add_surface(s1, +1) - c28.add_surface(s2, -1) + c28.region = +s1 & -s2 c28.fill = clad c29 = openmc.Cell(cell_id=29) - c29.add_surface(s2, +1) + c29.region = +s2 c29.fill = hot_water fuel_hot.add_cells((c27, c28, c29)) tube_hot = openmc.Universe(name='Instrumentation guide tube, hot water', universe_id=4) c30 = openmc.Cell(cell_id=30) - c30.add_surface(s3, -1) + c30.region = -s3 c30.fill = hot_water c31 = openmc.Cell(cell_id=31) - c31.add_surface(s3, +1) - c31.add_surface(s4, -1) + c31.region = +s3 & -s4 c31.fill = clad c32 = openmc.Cell(cell_id=32) - c32.add_surface(s4, +1) + c32.region = +s4 c32.fill = hot_water tube_hot.add_cells((c30, c31, c32)) @@ -419,33 +415,27 @@ class InputSet(object): [fuel_hot]*17 ] # Define assemblies. - fa_cw = openmc.Universe(name='Water assembly (cold)', - universe_id=5) + fa_cw = openmc.Universe(name='Water assembly (cold)', universe_id=5) c50 = openmc.Cell(cell_id=50) - c50.add_surface(s34, +1) - c50.add_surface(s35, -1) + c50.region = +s34 & -s35 c50.fill = cold_water fa_cw.add_cells((c50, )) - fa_hw = openmc.Universe(name='Water assembly (hot)', - universe_id=7) + fa_hw = openmc.Universe(name='Water assembly (hot)', universe_id=7) c70 = openmc.Cell(cell_id=70) - c70.add_surface(s35, +1) - c70.add_surface(s36, -1) + c70.region = +s35 & -s36 c70.fill = hot_water fa_hw.add_cells((c70, )) fa_cold = openmc.Universe(name='Fuel assembly (cold)', universe_id=6) c60 = openmc.Cell(cell_id=60) - c60.add_surface(s34, +1) - c60.add_surface(s35, -1) + c60.region = +s34 & -s35 c60.fill = l100 fa_cold.add_cells((c60, )) fa_hot = openmc.Universe(name='Fuel assembly (hot)', universe_id=8) c80 = openmc.Cell(cell_id=80) - c80.add_surface(s35, +1) - c80.add_surface(s36, -1) + c80.region = +s35 & -s36 c80.fill = l101 fa_hot.add_cells((c80, )) @@ -509,79 +499,51 @@ class InputSet(object): # Define root universe. root = openmc.Universe(universe_id=0, name='root universe') c1 = openmc.Cell(cell_id=1) - c1.add_surface(s6, -1) - c1.add_surface(s34, +1) - c1.add_surface(s35, -1) + c1.region = -s6 & +s34 & -s35 c1.fill = l200 c2 = openmc.Cell(cell_id=2) - c2.add_surface(s6, -1) - c1.add_surface(s35, +1) - c2.add_surface(s36, -1) + c2.region = -s6 & +s35 & -s36 c2.fill = l201 c3 = openmc.Cell(cell_id=3) - c3.add_surface(s7, -1) - c3.add_surface(s31, +1) - c3.add_surface(s32, -1) + c3.region = -s7 & +s31 & -s32 c3.fill = bot_plate c4 = openmc.Cell(cell_id=4) - c4.add_surface(s5, -1) - c4.add_surface(s32, +1) - c4.add_surface(s33, -1) + c4.region = -s5 & +s32 & -s33 c4.fill = bot_nozzle c5 = openmc.Cell(cell_id=5) - c5.add_surface(s5, -1) - c5.add_surface(s33, +1) - c5.add_surface(s34, -1) + c5.region = -s5 & +s33 & -s34 c5.fill = bot_fa c6 = openmc.Cell(cell_id=6) - c6.add_surface(s5, -1) - c6.add_surface(s36, +1) - c6.add_surface(s37, -1) + c6.region = -s5 & +s36 & -s37 c6.fill = top_fa c7 = openmc.Cell(cell_id=7) - c7.add_surface(s5, -1) - c7.add_surface(s37, +1) - c7.add_surface(s38, -1) + c7.region = -s5 & +s37 & -s38 c7.fill = top_nozzle c8 = openmc.Cell(cell_id=8) - c8.add_surface(s7, -1) - c8.add_surface(s38, +1) - c8.add_surface(s39, -1) + c8.region = -s7 & +s38 & -s39 c8.fill = upper_rad_ref c9 = openmc.Cell(cell_id=9) - c9.add_surface(s6, +1) - c9.add_surface(s7, -1) - c9.add_surface(s32, +1) - c9.add_surface(s38, -1) + c9.region = +s6 & -s7 & +s32 & -s38 c9.fill = bot_nozzle c10 = openmc.Cell(cell_id=10) - c10.add_surface(s7, +1) - c10.add_surface(s8, -1) - c10.add_surface(s31, +1) - c10.add_surface(s39, -1) + c10.region = +s7 & -s8 & +s31 & -s39 c10.fill = rpv_steel c11 = openmc.Cell(cell_id=11) - c11.add_surface(s5, +1) - c11.add_surface(s6, -1) - c11.add_surface(s32, +1) - c11.add_surface(s34, -1) + c11.region = +s5 & -s6 & +s32 & -s34 c11.fill = lower_rad_ref c12 = openmc.Cell(cell_id=12) - c12.add_surface(s5, +1) - c12.add_surface(s6, -1) - c12.add_surface(s36, +1) - c12.add_surface(s38, -1) + c12.region = +s5 & -s6 & +s36 & -s38 c12.fill = upper_rad_ref root.add_cells((c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12)) diff --git a/tests/test_filter_cell/inputs_true.dat b/tests/test_filter_cell/inputs_true.dat index 7cf1c07c2f..2320ff6ab4 100644 --- a/tests/test_filter_cell/inputs_true.dat +++ b/tests/test_filter_cell/inputs_true.dat @@ -1 +1 @@ -3b06e27fa039762b59076bb9431ef003e69ef32f8d01bcf908fe85f59bf7127bd8b94bf2f895b1b63e9fcdbd97aeaf4b02bc02e7bd029bfd85263c68498ce562 \ No newline at end of file +caae173f01f7073d634a68a5c4ce97177423e13596a863976e1c40303dc8c05afed457d5a1aa0ae73627ec953143e4f9c1f45bdbd3b0cca76433062467d59777 \ No newline at end of file diff --git a/tests/test_filter_cellborn/inputs_true.dat b/tests/test_filter_cellborn/inputs_true.dat index 3379e4b26a..5aef4cbb06 100644 --- a/tests/test_filter_cellborn/inputs_true.dat +++ b/tests/test_filter_cellborn/inputs_true.dat @@ -1 +1 @@ -6dd7d019587330bbf9c19bae7ad1d888331858b68bd77218315d5fa7b85df7fb97cb208daed584a780592cf9840e67ea3777ccbde502f3861798aac95722be9c \ No newline at end of file +2f24eb86cda981982a8db5bb110c72e9cef542c06e15b748c1c7e459f96b0d8ba0978b51dffc006e813cd2e2ae1fa0357336f8322ae263189841afde01f0327b \ No newline at end of file diff --git a/tests/test_filter_energy/inputs_true.dat b/tests/test_filter_energy/inputs_true.dat index 58da3ba3e0..b120e9fd62 100644 --- a/tests/test_filter_energy/inputs_true.dat +++ b/tests/test_filter_energy/inputs_true.dat @@ -1 +1 @@ -bc9f43ff6368da544942b93ecfb2561911071c44524e35608fcb92c1262fe5543e09525414a87cd647fbc50113d64ff867730e5f4391f31b096abd7a0543b474 \ No newline at end of file +49835200052ee1a4c9583a7bb4e9430de7d01a6d7a8d4f63ae37be9bbac4fd8c7ed9135ecbc4ab4cb075fd4d77b322265783463dd07c127decceee8c9fe25bfd \ No newline at end of file diff --git a/tests/test_filter_energyout/inputs_true.dat b/tests/test_filter_energyout/inputs_true.dat index 4cfce0b49d..7096648e6c 100644 --- a/tests/test_filter_energyout/inputs_true.dat +++ b/tests/test_filter_energyout/inputs_true.dat @@ -1 +1 @@ -74c55768b2b0f5696d5bff9d36a3639c6d858bf2984d799c8b46908b897af11e691b1f9f05646d52fcee046de3bfee11e35b9b379b2967abb0922f60168017b7 \ No newline at end of file +183b4a06cbd0930cfa4f28d0c385cf3ae93ab97c171580c2ba9eec0e4b716102ad83f510d62258ef6769c446e72e1d5ba9f630b171ee239ec04c9bbd1e56742e \ No newline at end of file diff --git a/tests/test_filter_group_transfer/inputs_true.dat b/tests/test_filter_group_transfer/inputs_true.dat index f98d11bd2b..813bb43c18 100644 --- a/tests/test_filter_group_transfer/inputs_true.dat +++ b/tests/test_filter_group_transfer/inputs_true.dat @@ -1 +1 @@ -dd69e0768aa7a4e28efd20adc6a607337c9a15682fa307b1aa2459595f90a523f1fa6e4e4f6db1d74e52a2287ef4efa85d77b1751cd1a2d2e6618385cf7f4607 \ No newline at end of file +461a6a4ec3b0b6dc7199c09fa8f527e51cc7a1ea4281a708f8b7bcdbb12f7162027928dfcef68a24eaf6c06037a68e151df9aac9eac6ce56617466f2f5270b71 \ No newline at end of file diff --git a/tests/test_filter_material/inputs_true.dat b/tests/test_filter_material/inputs_true.dat index 0610b45c44..aaa4a4939f 100644 --- a/tests/test_filter_material/inputs_true.dat +++ b/tests/test_filter_material/inputs_true.dat @@ -1 +1 @@ -91dd096441a7f01689ed605b7b3322c63a90c4802d73450acd825b715a8163fc892b4971e4b8b0d5a179eb51ad22bcc886f3935e7ab734d0fedebaf679415816 \ No newline at end of file +2fbd0986abff08126680925284929cf67bdad0cd564775197b78065ce3b0e6ad8094f5ca4d14ea69347db69a6cdcc9796a095178ae9b14a927b101f32f3cd0ec \ No newline at end of file diff --git a/tests/test_filter_universe/inputs_true.dat b/tests/test_filter_universe/inputs_true.dat index cf1c7db55b..7cda1ab848 100644 --- a/tests/test_filter_universe/inputs_true.dat +++ b/tests/test_filter_universe/inputs_true.dat @@ -1 +1 @@ -f3dc4c28827ca9035d2d1a39f4adef794f0e27b8c95776485e419b9610aefc6c268e6a1d5889d8170ec9400fc3a4a52bc69cd94e5056078aee7405e0bc62bad5 \ No newline at end of file +51fcaf0aa527d1fd1022e5f312d4d25cd9bacc5fc9792d9f7702ee97cac43700a31f25be767a2cff769c37b5e1cdf3f922467977a9958fa34561e2a102bf8537 \ No newline at end of file diff --git a/tests/test_score_MT/inputs_true.dat b/tests/test_score_MT/inputs_true.dat index 7b56862ea3..3789a69cba 100644 --- a/tests/test_score_MT/inputs_true.dat +++ b/tests/test_score_MT/inputs_true.dat @@ -1 +1 @@ -6ba3ebe9d50584343b012b7a935a0f75b8366659600d4de050a8e4e48405f8da36682e8ab5f495f69b646fc72e176755c0a3540f235806c73d5ebc4fc67db107 \ No newline at end of file +63295b9d510370e65e63a3db627d47d286f5479e53c8eabeda9a5cb25ffe35becb636835aadad11691e34c23292fe11b5f688daee76d76ceac4b5dfd2f9ede4c \ No newline at end of file diff --git a/tests/test_score_absorption/inputs_true.dat b/tests/test_score_absorption/inputs_true.dat index ad2d1f40ea..c4c133600a 100644 --- a/tests/test_score_absorption/inputs_true.dat +++ b/tests/test_score_absorption/inputs_true.dat @@ -1 +1 @@ -a2be808e033014c9d748a0ec503ab6ad498f6b70250c8136bfcb9dc8f5580e69fc0bc1c6acab428c139edf64f51237ba07495b0275a19f509bf3bd20fa298e4e \ No newline at end of file +482760c362f56e453ce4b466083e77f84a461e636330d7cc2cb1cf7facced678a57a7c785ff9d039b3f575396cb435f99df05d6fa207f553c28ed3ce4f8151b3 \ No newline at end of file diff --git a/tests/test_score_events/inputs_true.dat b/tests/test_score_events/inputs_true.dat index 1d2c8447cd..bb0fef8e5d 100644 --- a/tests/test_score_events/inputs_true.dat +++ b/tests/test_score_events/inputs_true.dat @@ -1 +1 @@ -493830fe4598d5a2e31d4b79aceb79390bfa0bd7e08681ef36d5978a72de3cd7bcdbc06147061664614ed8e069be82d01e880e8e8cb629d3bd7aa1223850c8e6 \ No newline at end of file +a97ae7049ac8c30b838987a3e87cbe5ff70b004ee0434e6204931def46c4c099bfef06e74658dab1114cc1035d3f404211a9bc94ef96e9cfb5b788da39d17bbd \ No newline at end of file diff --git a/tests/test_score_fission/inputs_true.dat b/tests/test_score_fission/inputs_true.dat index 0abc63556a..d90ca274ee 100644 --- a/tests/test_score_fission/inputs_true.dat +++ b/tests/test_score_fission/inputs_true.dat @@ -1 +1 @@ -e94e6338c6aadaebd6f3cdad768b53908e470dc6d650a170703b21bf0140313559ce2af78f6b8bd13498dc5019ce02603ec6ba7c68731dfa05ca4a540f159625 \ No newline at end of file +5a0461d03b0d9653ee35fded4be23e9b8316e3b7e21d352f822bc1f9763c03e9edab922bdc431f30d2a647c4216d45deba396bf56203027a328b7b28d970e0b8 \ No newline at end of file diff --git a/tests/test_score_flux/inputs_true.dat b/tests/test_score_flux/inputs_true.dat index fe2b65dfe1..2e7358c49e 100644 --- a/tests/test_score_flux/inputs_true.dat +++ b/tests/test_score_flux/inputs_true.dat @@ -1 +1 @@ -23454cbb568dd5f8569f228b3d0e6d180144279005521ad009d6a99384db79330b274edc431133f5e304a6750bef2b85bfc5af46258a75ce3f0673dd0ec0c54c \ No newline at end of file +33b7b97f55a337d7001e7927517db6d36d512efec01fa5512c80bbc76b0b581f691a72a3810251aa97491b8cdf25a8ddcc9c9b3e3f54ccc6c315a84e715567d3 \ No newline at end of file diff --git a/tests/test_score_flux_yn/inputs_true.dat b/tests/test_score_flux_yn/inputs_true.dat index 9b9313a6ab..c7a1a1b52e 100644 --- a/tests/test_score_flux_yn/inputs_true.dat +++ b/tests/test_score_flux_yn/inputs_true.dat @@ -1 +1 @@ -977c9d76d335d79fa561f9eab8a575a118f900818759b96b6fbdbf8d06a012a44d5892bbb22292f9b730745d86859ffcba6b16b59096eff587fca2a5d6629cf5 \ No newline at end of file +b1a63345fc721f87c8fc25babb06741b585ee5dff5f29bb6debfbabb2ad57cb762d98c14e544df998a27bc725fb2704092fcdde54315ff832dff96c3641551d0 \ No newline at end of file diff --git a/tests/test_score_kappafission/inputs_true.dat b/tests/test_score_kappafission/inputs_true.dat index 86939274b8..ecb42ddb46 100644 --- a/tests/test_score_kappafission/inputs_true.dat +++ b/tests/test_score_kappafission/inputs_true.dat @@ -1 +1 @@ -8dd415b571ad51a62f2394d149f6c417d63babd4e85a1ff6f1cac267c4f4bcd0642ba0b24da39ff926bee4aea7dbbe0371face03d2009d8d74e7ac31c7c45000 \ No newline at end of file +57e4aa7550789aec0fcbc4a8917e9d28b1f1ae098a09cde95b757fd87d0dd3924c1bb9d4b23c59cd3793446fb6bbc8af4e1bb46323d70d5e5acd13db1167f545 \ No newline at end of file diff --git a/tests/test_score_nufission/inputs_true.dat b/tests/test_score_nufission/inputs_true.dat index 4e6018f99c..52f7765fa7 100644 --- a/tests/test_score_nufission/inputs_true.dat +++ b/tests/test_score_nufission/inputs_true.dat @@ -1 +1 @@ -0e60125f41bbc362703886097b2bc7297ff0aae6365d4653771b86b1aab2de43a924d81b3d73afb781733b2919f30089373f74da4a96f94f988eb04ddf482e85 \ No newline at end of file +a42b2e165f59d3f499865d5db1e7db9b4cb25e48290f94080e569a9efc0b437d75cbb5773ac564f6cc95b19521fb7bc97a3eb641b491828c90cd086dc0c06a4b \ No newline at end of file diff --git a/tests/test_score_nuscatter/inputs_true.dat b/tests/test_score_nuscatter/inputs_true.dat index 6ae99b4a17..80840f900d 100644 --- a/tests/test_score_nuscatter/inputs_true.dat +++ b/tests/test_score_nuscatter/inputs_true.dat @@ -1 +1 @@ -c74fb5e4e8caecd11642231b55cb9442264da220329fd6a1c9959214342acd5efb4ef23368b0b018f0388a6102bce65226f6161d32f3613128d8c3762a3f6f9e \ No newline at end of file +764d3ba6b1bc86b462d44151242bd18fa5f0200b831bb7537cf881b728622799eb95a457f88a503487bfd30095c1fa995818d50a6bc41dd182009772c010e82b \ No newline at end of file diff --git a/tests/test_score_nuscatter_n/inputs_true.dat b/tests/test_score_nuscatter_n/inputs_true.dat index c7924a247a..c63f891d26 100644 --- a/tests/test_score_nuscatter_n/inputs_true.dat +++ b/tests/test_score_nuscatter_n/inputs_true.dat @@ -1 +1 @@ -c184ef2764fa23db32253ec4c23d36cf842f173a0a57c93cb165faf771f2ff23346756160ba5793c558448283eb0917d23e3871753ea2b7e3e24f14d6cf4179f \ No newline at end of file +17541e365f35ebd25134465a02d9a66e46536c4e3f5769da62137ec94ee7c8fb46ef38b9039aa6430261329a4e1b0ce677174323563e5be2f1368dc0c552e312 \ No newline at end of file diff --git a/tests/test_score_nuscatter_pn/inputs_true.dat b/tests/test_score_nuscatter_pn/inputs_true.dat index 30a894dafb..ef53ee8f65 100644 --- a/tests/test_score_nuscatter_pn/inputs_true.dat +++ b/tests/test_score_nuscatter_pn/inputs_true.dat @@ -1 +1 @@ -79d74ffe32f564b83bdde94048f57233454881f3b55413e9b5e30ce4b9813ff6436dca98d691d941d5f31947f2215dcb656369c2b32e6240e1424e6aad96395e \ No newline at end of file +8ae1b048b90a049d9ed42336a0a2e8f7a250a14d889cc15e0c2831ed71617a78b92570480a15f936f2dd623c75f55693e38c69041c3cae24aba082409b51bc9f \ No newline at end of file diff --git a/tests/test_score_nuscatter_yn/inputs_true.dat b/tests/test_score_nuscatter_yn/inputs_true.dat index 9a8a934b17..632a144031 100644 --- a/tests/test_score_nuscatter_yn/inputs_true.dat +++ b/tests/test_score_nuscatter_yn/inputs_true.dat @@ -1 +1 @@ -fd7b5b66e5d5e705da488651445d75240b05dcc1d243b2d2e8b8a729c8220221cdfa1eccfeca30897a006caaceae3e8c7449392b5027b290cb388b33e86ff2a3 \ No newline at end of file +205e5cac8129797b815f0e79dad6c41a1876157ba69fcffecf67c3603dc36ded5f0168f9961d51fcb7dc7db6d732e7a3e8f82d04947aa0309df56bb8333d4bc9 \ No newline at end of file diff --git a/tests/test_score_scatter/inputs_true.dat b/tests/test_score_scatter/inputs_true.dat index d7a6f4719a..35557cd3c5 100644 --- a/tests/test_score_scatter/inputs_true.dat +++ b/tests/test_score_scatter/inputs_true.dat @@ -1 +1 @@ -8b5e7c3825ef033d12c0574595b16559981ed3dd0ced8609c461cd0e81f1f2ef28195e0a6f6886fcbae64185dfe96001fa12d3d472f6446a3135d3bd6ef83394 \ No newline at end of file +b5baba05419ce120bd22d935af9cdd6d206ad5dc5cae5991a9d160c70bb029f2d87040fa4e19f7190de64b908ac6a41a8b28db4a4f3883ec16e529b1449e983d \ No newline at end of file diff --git a/tests/test_score_scatter_n/inputs_true.dat b/tests/test_score_scatter_n/inputs_true.dat index 68febf4bc5..e6e3a395bd 100644 --- a/tests/test_score_scatter_n/inputs_true.dat +++ b/tests/test_score_scatter_n/inputs_true.dat @@ -1 +1 @@ -414d0faeba75d27e4785faa9812f5eac6aa108e7fd3c1388d51ae8e0d7fddd25e9f61e51afdaa70874a32e1c3d2815d82b5c79636b1ccb0d6767144fcf6f813a \ No newline at end of file +a153add0502ff0fd4b0670f01679e104be1bb05941e73fb35e426c7f1e41a6144c7eb81fdba0d62ea3f39c7c6798028ff6d5df8c7a50b3e3f9e9bfe72fd48c2f \ No newline at end of file diff --git a/tests/test_score_scatter_pn/inputs_true.dat b/tests/test_score_scatter_pn/inputs_true.dat index 53b1d21608..3878939c50 100644 --- a/tests/test_score_scatter_pn/inputs_true.dat +++ b/tests/test_score_scatter_pn/inputs_true.dat @@ -1 +1 @@ -f83e5a272e78dba7a4b3412aa264300efbeae641de0bbcae3febe7ba5fa6668dbf9364fdc7f1c431ab9c58aaf019ae41d98ee69d4dd035d6b5e0188e7d181b20 \ No newline at end of file +fe56d58827d1803c1a49391711ad682be4a7cbc51519248812554f66e3e46266edc179f4254291a5f455751d3cdc13a17bbd103b9810c8818f36e4d283b503be \ No newline at end of file diff --git a/tests/test_score_scatter_yn/inputs_true.dat b/tests/test_score_scatter_yn/inputs_true.dat index 6e5210212e..1ae9f6047d 100644 --- a/tests/test_score_scatter_yn/inputs_true.dat +++ b/tests/test_score_scatter_yn/inputs_true.dat @@ -1 +1 @@ -c90d836355fcbe14112c16f8743b9180371400c022b19f693881d91924788555ed1507a1936b4d241a63564a7661f380c5d0568d398fa8a20a25f41c5b7c4fb8 \ No newline at end of file +d80a9e8befab978bc84a231437a2b96c8f6dba81984c9e82a79360feb26bc9875b661131dbaa2deeb66b0aa50a39b2e738303bc40c5c65ee1995cf52f687ae46 \ No newline at end of file diff --git a/tests/test_score_total/inputs_true.dat b/tests/test_score_total/inputs_true.dat index 975588a1ac..c8b979c725 100644 --- a/tests/test_score_total/inputs_true.dat +++ b/tests/test_score_total/inputs_true.dat @@ -1 +1 @@ -90633c6010148c10c363ed3b2e9de3213468c51dea6153dff4bb18eadc579041d967e4835023d10b6d8c42fe81017238d119f24cae754d0621698547464b16f3 \ No newline at end of file +8813917cab656135c4eebfdbe5f0d95e6a9409a2b36df1dfb483bdd193a3c0978727918a58399b259b82a7d51ae3f1801148bd978603fec11f27acdbf89520e2 \ No newline at end of file diff --git a/tests/test_score_total_yn/inputs_true.dat b/tests/test_score_total_yn/inputs_true.dat index 72173a0319..b2818f8568 100644 --- a/tests/test_score_total_yn/inputs_true.dat +++ b/tests/test_score_total_yn/inputs_true.dat @@ -1 +1 @@ -def382a2f9efec93baf521911ab89e0d73ceadba486f9bb306e9cf82ffc1c67b72498c153519e05b516ff54db431430b2b25b80675961697e19774455711a5f8 \ No newline at end of file +4dbbd9cec921d2420e7567533c833afbe94335073aa760d1fd937adb695191b3ab7c070ec0d32721dddb4a46054e68322cf6a058420e20e439eb1d44f09f4be4 \ No newline at end of file diff --git a/tests/test_score_total_yn/results_true.dat b/tests/test_score_total_yn/results_true.dat index a64aa49cc3..81bef81d22 100644 --- a/tests/test_score_total_yn/results_true.dat +++ b/tests/test_score_total_yn/results_true.dat @@ -288,7 +288,7 @@ tally 2: 1.155268E-03 6.855877E-02 4.048417E-03 --2.701969E-05 +-2.701967E-05 1.279041E-03 -2.197636E-02 2.843662E-04