From 91ccc4da0051a3d1f75286bbc4c2305cd720867f Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 8 Aug 2017 18:10:53 -0400 Subject: [PATCH 01/21] Implement z planes and cylinders in C++ --- CMakeLists.txt | 5 +- src/geometry.F90 | 47 +++++++- src/input_xml.F90 | 9 ++ src/surface_header.C | 280 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 src/surface_header.C diff --git a/CMakeLists.txt b/CMakeLists.txt index c5150745b..200d836fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -436,7 +436,10 @@ set(LIBOPENMC_FORTRAN_SRC ) set(LIBOPENMC_CXX_SRC src/random_lcg.h - src/random_lcg.cpp) + src/random_lcg.cpp + src/surface_header.C + src/pugixml/pugixml.hpp + src/pugixml/pugixml.cpp) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) add_executable(${program} src/main.F90) diff --git a/src/geometry.F90 b/src/geometry.F90 index ced62e681..bc1eca2ae 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -10,8 +10,33 @@ module geometry use stl_vector, only: VectorInt use string, only: to_str + use, intrinsic :: ISO_C_BINDING + implicit none + interface + function surface_sense_c(surf_ind, xyz, uvw) & + bind(C, name='surface_sense') result(sense) + use ISO_C_BINDING + implicit none + integer(C_INT), value :: surf_ind; + real(C_DOUBLE) :: xyz(3); + real(C_DOUBLE) :: uvw(3); + logical(C_BOOL) :: sense; + end function surface_sense_c + + function surface_distance_c(surf_ind, xyz, uvw, coincident) & + bind(C, name='surface_distance') result(d) + use ISO_C_BINDING + implicit none + integer(C_INT), value :: surf_ind; + real(C_DOUBLE) :: xyz(3); + real(C_DOUBLE) :: uvw(3); + logical(C_BOOL), value :: coincident; + real(C_DOUBLE) :: d; + end function surface_distance_c + end interface + contains !=============================================================================== @@ -28,7 +53,8 @@ contains ! expression using a stack, similar to how a RPN calculator would work. !=============================================================================== - pure function cell_contains(c, p) result(in_cell) + !pure function cell_contains(c, p) result(in_cell) + function cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c type(Particle), intent(in) :: p logical :: in_cell @@ -40,7 +66,8 @@ contains end if end function cell_contains - pure function simple_cell_contains(c, p) result(in_cell) + !pure function simple_cell_contains(c, p) result(in_cell) + function simple_cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c type(Particle), intent(in) :: p logical :: in_cell @@ -48,6 +75,7 @@ contains integer :: i integer :: token logical :: actual_sense ! sense of particle wrt surface + logical :: alt_sense in_cell = .true. do i = 1, size(c%rpn) @@ -65,6 +93,15 @@ contains else actual_sense = surfaces(abs(token))%obj%sense(& p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) + alt_sense = surface_sense_c(abs(token)-1, & + p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) + if (actual_sense .neqv. alt_sense) then + write(*, *) surfaces(abs(token)) % obj % id + write(*, *) p % coord (p % n_coord) % xyz + write(*, *) p % coord (p % n_coord) % uvw + write(*, *) actual_sense, alt_sense + call fatal_error("") + end if if (actual_sense .neqv. (token > 0)) then in_cell = .false. exit @@ -484,6 +521,7 @@ contains type(Cell), pointer :: c class(Surface), pointer :: surf class(Lattice), pointer :: lat + real(8) :: d_alt ! inialize distance to infinity (huge) dist = INFINITY @@ -519,6 +557,11 @@ contains ! Calculate distance to surface surf => surfaces(index_surf) % obj d = surf % distance(p % coord(j) % xyz, p % coord(j) % uvw, coincident) + d_alt = surface_distance_c(index_surf-1, p % coord(j) % xyz, & + p % coord(j) % uvw, logical(coincident, kind=C_BOOL)) + if (d /= d_alt) then + write(*, *) d, d_alt + end if ! Check if calculated distance is new minimum if (d < d_surf) then diff --git a/src/input_xml.F90 b/src/input_xml.F90 index bd56422cb..4994ff76b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -48,6 +48,14 @@ module input_xml implicit none save + interface + subroutine read_surfaces(node_ptr) bind(C, name='read_surfaces') + use ISO_C_BINDING + implicit none + type(C_PTR) :: node_ptr + end subroutine read_surfaces + end interface + contains !=============================================================================== @@ -966,6 +974,7 @@ contains ! get pointer to list of xml call get_node_list(root, "surface", node_surf_list) + call read_surfaces(root % ptr) ! Get number of tags n_surfaces = size(node_surf_list) diff --git a/src/surface_header.C b/src/surface_header.C new file mode 100644 index 000000000..08287da88 --- /dev/null +++ b/src/surface_header.C @@ -0,0 +1,280 @@ +#include // For strcmp +#include +#include // For numeric_limits +#include // For fabs +#include "pugixml/pugixml.hpp" + +//============================================================================== +// Constants +//============================================================================== + +const double FP_COINCIDENT = 1e-12; +const double INFTY = std::numeric_limits::max(); + +//============================================================================== +// Global array of surfaces +//============================================================================== + +class Surface; +Surface **surfaces_c; + +//============================================================================== +// SURFACE type defines a first- or second-order surface that can be used to +// construct closed volumes (cells) +//============================================================================== + +class Surface +{ + int id; // Unique ID + int neighbor_pos[], // List of cells on positive side + neighbor_neg[]; // List of cells on negative side + int bc; // Boundary condition + //TODO: swith that zero to a NONE constant. + int i_periodic = 0; // Index of corresponding periodic surface + char name[104]; // User-defined name + +public: + bool sense(double xyz[3], double uvw[3]); + void reflect(double xyz[3], double uvw[3]); + virtual double evaluate(double xyz[3]) = 0; + virtual double distance(double xyz[3], double uvw[3], bool coincident) = 0; + virtual void normal(double xyz[3], double uvw[3]) = 0; +}; + +bool +Surface::sense(double xyz[3], double uvw[3]) +{ + // Evaluate the surface equation at the particle's coordinates to determine + // which side the particle is on. + const double f = evaluate(xyz); + + // Check which side of surface the point is on. + bool s; + if (fabs(f) < FP_COINCIDENT) + { + // 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. + double norm[3]; + normal(xyz, norm); + s = (uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0); + } + else + { + s = (f > 0.0); + } + return s; +} + +void +Surface::reflect(double xyz[3], double uvw[3]) +{ + + // Determine projection of direction onto normal and squared magnitude of + // normal. + double norm[3]; + normal(xyz, norm); + const double projection = norm[0]*uvw[0] + norm[1]*uvw[1] + norm[2]*uvw[2]; + const double magnitude = norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]; + + // Reflect direction according to normal. + uvw[0] -= 2.0 * projection / magnitude * norm[0]; + uvw[1] -= 2.0 * projection / magnitude * norm[1]; + uvw[2] -= 2.0 * projection / magnitude * norm[2]; +} + +//============================================================================== + +class SurfaceZPlane : public Surface +{ + double z0; +public: + SurfaceZPlane(pugi::xml_node surf_node); + double evaluate(double xyz[3]); + double distance(double xyz[3], double uvw[3], bool coincident); + void normal(double xyz[3], double uvw[3]); +}; + +SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) +{ + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf", &z0); + if (stat != 1) + { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +double +SurfaceZPlane::evaluate(double xyz[3]) +{ + double f = xyz[2] - z0; + return f; +} + +double +SurfaceZPlane::distance(double xyz[3], double uvw[3], bool coincident) +{ + double f = z0 - xyz[2]; + double d; + if (coincident or fabs(f) < FP_COINCIDENT or uvw[2] == 0.0) + { + d = INFTY; + } + else + { + d = f / uvw[2]; + if (d < 0.0) d = INFTY; + } + return d; +} + +void +SurfaceZPlane::normal(double xyz[3], double uvw[3]) +{ + uvw[0] = 0.0; + uvw[1] = 0.0; + uvw[2] = 1.0; +} + +//============================================================================== + +class SurfaceZCylinder : public Surface +{ + double x0, y0, r; +public: + SurfaceZCylinder(pugi::xml_node surf_node); + double evaluate(double xyz[3]); + double distance(double xyz[3], double uvw[3], bool coincident); + void normal(double xyz[3], double uvw[3]); +}; + +SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) +{ + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &y0, &r); + if (stat != 3) + { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +double +SurfaceZCylinder::evaluate(double xyz[3]) +{ + const double x = xyz[0] - x0; + const double y = xyz[1] - y0; + double f = x*x + y*y - r*r; + return f; +} + +double +SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) +{ + double a = 1.0 - uvw[2]*uvw[2]; // u^2 + v^2 + + if (a == 0.0) return INFTY; + + double x = xyz[0] - x0; + double y = xyz[1] - y0; + double k = x*uvw[0] + y*uvw[1]; + double c = x*x + y*y - r*r; + double quad = k*k - a*c; + + if (quad < 0.0) + { + // No intersection with cylinder. + return INFTY; + } + else if (coincident or fabs(c) < FP_COINCIDENT) + { + // 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 >= 0.0) return INFTY; + else return (-k + sqrt(quad)) / a; + } + else if (c < 0.0) + { + // 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) + return (-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) + + double d = (-k - sqrt(quad)) / a; + if (d < 0.0) return INFTY; + return d; + } +} + +void +SurfaceZCylinder::normal(double xyz[3], double uvw[3]) +{ + uvw[0] = 2.0 * (xyz[0] - x0); + uvw[1] = 2.0 * (xyz[1] - y0); + uvw[2] = 0.0; +} + +//============================================================================== + +extern "C" void +read_surfaces(pugi::xml_node *node) +{ + // Count the number of surfaces. + int n_surfaces = 0; + for (pugi::xml_node surf_node = node->child("surface"); surf_node; + surf_node = surf_node.next_sibling("surface")) + { + n_surfaces += 1; + } + + // Allocate the array of Surface pointers. + surfaces_c = new Surface* [n_surfaces]; + + // Loop over XML surface elements and populate the array. + { + pugi::xml_node surf_node; + int i_surf; + for (surf_node = node->child("surface"), i_surf = 0; surf_node; + surf_node = surf_node.next_sibling("surface"), i_surf++) + { + if (surf_node.attribute("type")) + { + const pugi::char_t *surf_type = surf_node.attribute("type").value(); + if (strcmp(surf_type, "z-cylinder") == 0) + { + surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); + } + else if (strcmp(surf_type, "z-plane") == 0) + { + surfaces_c[i_surf] = new SurfaceZPlane(surf_node); + } + else + { + std::cout << "Call error or handle uppercase here!" << std::endl; + std::cout << surf_type << std::endl; + } + } + } + } +} + +//============================================================================== + +extern "C" bool +surface_sense(int surf_ind, double xyz[3], double uvw[3]) +{ + return surfaces_c[surf_ind]->sense(xyz, uvw); +} + +extern "C" double +surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) +{ + return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); +} From c5708e6932b37f34a29274dbc6c98a34e74c66cf Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 18 Jan 2018 21:16:50 -0500 Subject: [PATCH 02/21] Move brackets to match proposed C++ styleguide --- src/surface_header.C | 90 +++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 60 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 08287da88..34ac7cf33 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -23,8 +23,7 @@ Surface **surfaces_c; // construct closed volumes (cells) //============================================================================== -class Surface -{ +class Surface { int id; // Unique ID int neighbor_pos[], // List of cells on positive side neighbor_neg[]; // List of cells on negative side @@ -42,34 +41,28 @@ public: }; bool -Surface::sense(double xyz[3], double uvw[3]) -{ +Surface::sense(double xyz[3], double uvw[3]) { // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. const double f = evaluate(xyz); // Check which side of surface the point is on. bool s; - if (fabs(f) < FP_COINCIDENT) - { + if (fabs(f) < FP_COINCIDENT) { // 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. double norm[3]; normal(xyz, norm); s = (uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0); - } - else - { + } else { s = (f > 0.0); } return s; } void -Surface::reflect(double xyz[3], double uvw[3]) -{ - +Surface::reflect(double xyz[3], double uvw[3]) { // Determine projection of direction onto normal and squared magnitude of // normal. double norm[3]; @@ -85,8 +78,7 @@ Surface::reflect(double xyz[3], double uvw[3]) //============================================================================== -class SurfaceZPlane : public Surface -{ +class SurfaceZPlane : public Surface { double z0; public: SurfaceZPlane(pugi::xml_node surf_node); @@ -95,26 +87,22 @@ public: void normal(double xyz[3], double uvw[3]); }; -SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) -{ +SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) { const char *coeffs = surf_node.attribute("coeffs").value(); int stat = sscanf(coeffs, "%lf", &z0); - if (stat != 1) - { + if (stat != 1) { std::cout << "Something went wrong reading surface coeffs!" << std::endl; } } double -SurfaceZPlane::evaluate(double xyz[3]) -{ +SurfaceZPlane::evaluate(double xyz[3]) { double f = xyz[2] - z0; return f; } double -SurfaceZPlane::distance(double xyz[3], double uvw[3], bool coincident) -{ +SurfaceZPlane::distance(double xyz[3], double uvw[3], bool coincident) { double f = z0 - xyz[2]; double d; if (coincident or fabs(f) < FP_COINCIDENT or uvw[2] == 0.0) @@ -130,8 +118,7 @@ SurfaceZPlane::distance(double xyz[3], double uvw[3], bool coincident) } void -SurfaceZPlane::normal(double xyz[3], double uvw[3]) -{ +SurfaceZPlane::normal(double xyz[3], double uvw[3]) { uvw[0] = 0.0; uvw[1] = 0.0; uvw[2] = 1.0; @@ -139,8 +126,7 @@ SurfaceZPlane::normal(double xyz[3], double uvw[3]) //============================================================================== -class SurfaceZCylinder : public Surface -{ +class SurfaceZCylinder : public Surface { double x0, y0, r; public: SurfaceZCylinder(pugi::xml_node surf_node); @@ -149,19 +135,16 @@ public: void normal(double xyz[3], double uvw[3]); }; -SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) -{ +SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { const char *coeffs = surf_node.attribute("coeffs").value(); int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &y0, &r); - if (stat != 3) - { + if (stat != 3) { std::cout << "Something went wrong reading surface coeffs!" << std::endl; } } double -SurfaceZCylinder::evaluate(double xyz[3]) -{ +SurfaceZCylinder::evaluate(double xyz[3]) { const double x = xyz[0] - x0; const double y = xyz[1] - y0; double f = x*x + y*y - r*r; @@ -169,8 +152,7 @@ SurfaceZCylinder::evaluate(double xyz[3]) } double -SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) -{ +SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) { double a = 1.0 - uvw[2]*uvw[2]; // u^2 + v^2 if (a == 0.0) return INFTY; @@ -181,32 +163,27 @@ SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) double c = x*x + y*y - r*r; double quad = k*k - a*c; - if (quad < 0.0) - { + if (quad < 0.0) { // No intersection with cylinder. return INFTY; - } - else if (coincident or fabs(c) < FP_COINCIDENT) - { + + } else if (coincident or fabs(c) < FP_COINCIDENT) { // 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 >= 0.0) return INFTY; else return (-k + sqrt(quad)) / a; - } - else if (c < 0.0) - { + + } else if (c < 0.0) { // 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) return (-k + sqrt(quad)) / a; - } - else - { + + } 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) - double d = (-k - sqrt(quad)) / a; if (d < 0.0) return INFTY; return d; @@ -214,8 +191,7 @@ SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) } void -SurfaceZCylinder::normal(double xyz[3], double uvw[3]) -{ +SurfaceZCylinder::normal(double xyz[3], double uvw[3]) { uvw[0] = 2.0 * (xyz[0] - x0); uvw[1] = 2.0 * (xyz[1] - y0); uvw[2] = 0.0; @@ -224,13 +200,11 @@ SurfaceZCylinder::normal(double xyz[3], double uvw[3]) //============================================================================== extern "C" void -read_surfaces(pugi::xml_node *node) -{ +read_surfaces(pugi::xml_node *node) { // Count the number of surfaces. int n_surfaces = 0; for (pugi::xml_node surf_node = node->child("surface"); surf_node; - surf_node = surf_node.next_sibling("surface")) - { + surf_node = surf_node.next_sibling("surface")) { n_surfaces += 1; } @@ -242,10 +216,8 @@ read_surfaces(pugi::xml_node *node) pugi::xml_node surf_node; int i_surf; for (surf_node = node->child("surface"), i_surf = 0; surf_node; - surf_node = surf_node.next_sibling("surface"), i_surf++) - { - if (surf_node.attribute("type")) - { + surf_node = surf_node.next_sibling("surface"), i_surf++) { + if (surf_node.attribute("type")) { const pugi::char_t *surf_type = surf_node.attribute("type").value(); if (strcmp(surf_type, "z-cylinder") == 0) { @@ -268,13 +240,11 @@ read_surfaces(pugi::xml_node *node) //============================================================================== extern "C" bool -surface_sense(int surf_ind, double xyz[3], double uvw[3]) -{ +surface_sense(int surf_ind, double xyz[3], double uvw[3]) { return surfaces_c[surf_ind]->sense(xyz, uvw); } extern "C" double -surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) -{ +surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) { return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); } From 4cd335f6a93b21d5010e9f9981093a05a5d8435e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 Aug 2017 22:05:33 -0400 Subject: [PATCH 03/21] Add x-, y- planes and cylinders to C++ Introudce templated generic functions to reduce code repetition for surfaces --- src/surface_header.C | 358 +++++++++++++++++++++++++++++++++---------- 1 file changed, 276 insertions(+), 82 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 34ac7cf33..f62be77ab 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -33,36 +33,34 @@ class Surface { char name[104]; // User-defined name public: - bool sense(double xyz[3], double uvw[3]); - void reflect(double xyz[3], double uvw[3]); - virtual double evaluate(double xyz[3]) = 0; - virtual double distance(double xyz[3], double uvw[3], bool coincident) = 0; - virtual void normal(double xyz[3], double uvw[3]) = 0; + bool sense(const double xyz[3], const double uvw[3]) const; + void reflect(const double xyz[3], double uvw[3]) const; + virtual double evaluate(const double xyz[3]) const = 0; + virtual double distance(const double xyz[3], const double uvw[3], + bool coincident) const = 0; + virtual void normal(const double xyz[3], double uvw[3]) const = 0; }; bool -Surface::sense(double xyz[3], double uvw[3]) { +Surface::sense(const double xyz[3], const double uvw[3]) const { // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. const double f = evaluate(xyz); // Check which side of surface the point is on. - bool s; if (fabs(f) < FP_COINCIDENT) { // 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. double norm[3]; normal(xyz, norm); - s = (uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0); - } else { - s = (f > 0.0); + return uvw[0] * norm[0] + uvw[1] * norm[1] + uvw[2] * norm[2] > 0.0; } - return s; + return f > 0.0; } void -Surface::reflect(double xyz[3], double uvw[3]) { +Surface::reflect(const double xyz[3], double uvw[3]) const { // Determine projection of direction onto normal and squared magnitude of // normal. double norm[3]; @@ -76,15 +74,113 @@ Surface::reflect(double xyz[3], double uvw[3]) { uvw[2] -= 2.0 * projection / magnitude * norm[2]; } +//============================================================================== +// Generic functions for X-, Y-, and Z-, planes +//============================================================================== + +template double +axis_aligned_plane_evaluate(const double xyz[3], double offset) { + return xyz[i] - offset;} + +template double +axis_aligned_plane_distance(const double xyz[3], const double uvw[3], + bool coincident, double offset) { + const double f = offset - xyz[i]; + if (coincident or fabs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY; + const double d = f / uvw[i]; + if (d < 0.0) return INFTY; + return d; +} + +template void +axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { + uvw[i1] = 1.0; + uvw[i2] = 0.0; + uvw[i3] = 0.0; +} + +//============================================================================== +// SurfaceXPlane +//============================================================================== + +class SurfaceXPlane : public Surface { + double x0; +public: + SurfaceXPlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + const bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf", &x0); + if (stat != 1) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double SurfaceXPlane::evaluate(const double xyz[3]) const { + return axis_aligned_plane_evaluate<0>(xyz, x0); +} + +inline double SurfaceXPlane::distance(const double xyz[3], const double uvw[3], + bool coincident) const { + return axis_aligned_plane_distance<0>(xyz, uvw, coincident, x0); +} + +inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); +} + +//============================================================================== +// SurfaceYPlane +//============================================================================== + +class SurfaceYPlane : public Surface { + double y0; +public: + SurfaceYPlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf", &y0); + if (stat != 1) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double SurfaceYPlane::evaluate(const double xyz[3]) const { + return axis_aligned_plane_evaluate<1>(xyz, y0); +} + +inline double SurfaceYPlane::distance(const double xyz[3], const double uvw[3], + bool coincident) const { + return axis_aligned_plane_distance<1>(xyz, uvw, coincident, y0); +} + +inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); +} + +//============================================================================== +// SurfaceZPlane //============================================================================== class SurfaceZPlane : public Surface { double z0; public: SurfaceZPlane(pugi::xml_node surf_node); - double evaluate(double xyz[3]); - double distance(double xyz[3], double uvw[3], bool coincident); - void normal(double xyz[3], double uvw[3]); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; }; SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) { @@ -95,73 +191,49 @@ SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) { } } -double -SurfaceZPlane::evaluate(double xyz[3]) { - double f = xyz[2] - z0; - return f; +inline double SurfaceZPlane::evaluate(const double xyz[3]) const { + return axis_aligned_plane_evaluate<2>(xyz, z0); } -double -SurfaceZPlane::distance(double xyz[3], double uvw[3], bool coincident) { - double f = z0 - xyz[2]; - double d; - if (coincident or fabs(f) < FP_COINCIDENT or uvw[2] == 0.0) - { - d = INFTY; - } - else - { - d = f / uvw[2]; - if (d < 0.0) d = INFTY; - } - return d; +inline double SurfaceZPlane::distance(const double xyz[3], const double uvw[3], + bool coincident) const { + return axis_aligned_plane_distance<2>(xyz, uvw, coincident, z0); } -void -SurfaceZPlane::normal(double xyz[3], double uvw[3]) { - uvw[0] = 0.0; - uvw[1] = 0.0; - uvw[2] = 1.0; +inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); } +//============================================================================== +// SurfacePlane //============================================================================== -class SurfaceZCylinder : public Surface { - double x0, y0, r; -public: - SurfaceZCylinder(pugi::xml_node surf_node); - double evaluate(double xyz[3]); - double distance(double xyz[3], double uvw[3], bool coincident); - void normal(double xyz[3], double uvw[3]); -}; +// TODO -SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &y0, &r); - if (stat != 3) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } +//============================================================================== +// Generic functions for X-, Y-, and Z-, cylinders +//============================================================================== + +template double +axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, + double offset2, double radius) { + const double xyz1 = xyz[i1] - offset1; + const double xyz2 = xyz[i2] - offset2; + return xyz1*xyz1 + xyz2*xyz2 - radius*radius; } -double -SurfaceZCylinder::evaluate(double xyz[3]) { - const double x = xyz[0] - x0; - const double y = xyz[1] - y0; - double f = x*x + y*y - r*r; - return f; -} - -double -SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) { - double a = 1.0 - uvw[2]*uvw[2]; // u^2 + v^2 +template double +axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], + double offset1, double offset2, double radius, bool coincident) { + const double a = 1.0 - uvw[i1]*uvw[i1]; // u^2 + v^2 if (a == 0.0) return INFTY; - double x = xyz[0] - x0; - double y = xyz[1] - y0; - double k = x*uvw[0] + y*uvw[1]; - double c = x*x + y*y - r*r; - double quad = k*k - a*c; + const double xyz2 = xyz[i2] - offset1; + const double xyz3 = xyz[i3] - offset2; + const double k = xyz2 * uvw[i2] + xyz3 * uvw[i3]; + const double c = xyz2*xyz2 + xyz3*xyz3 - radius*radius; + const double quad = k*k - a*c; if (quad < 0.0) { // No intersection with cylinder. @@ -190,11 +262,123 @@ SurfaceZCylinder::distance(double xyz[3], double uvw[3], bool coincident) { } } -void -SurfaceZCylinder::normal(double xyz[3], double uvw[3]) { - uvw[0] = 2.0 * (xyz[0] - x0); - uvw[1] = 2.0 * (xyz[1] - y0); - uvw[2] = 0.0; +template void +axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, + double offset2) { + uvw[i2] = 2.0 * (xyz[i2] - offset1); + uvw[i3] = 2.0 * (xyz[i3] - offset2); + uvw[i1] = 0.0; +} + +//============================================================================== +// SurfaceXCylinder +//============================================================================== + +class SurfaceXCylinder : public Surface { + double y0, z0, r; +public: + SurfaceXCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf", &y0, &z0, &r); + if (stat != 3) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double +SurfaceXCylinder::evaluate(const double xyz[3]) const { + return axis_aligned_cylinder_evaluate<1, 2>(xyz, y0, z0, r); +} + +inline double SurfaceXCylinder::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cylinder_distance<0, 1, 2>(xyz, uvw, coincident, y0, z0, + r); +} + +inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cylinder_normal<0, 1, 2>(xyz, uvw, y0, z0); +} + +//============================================================================== +// SurfaceYCylinder +//============================================================================== + +class SurfaceYCylinder : public Surface { + double x0, z0, r; +public: + SurfaceYCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &z0, &r); + if (stat != 3) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double +SurfaceYCylinder::evaluate(const double xyz[3]) const { + return axis_aligned_cylinder_evaluate<0, 2>(xyz, x0, z0, r); +} + +inline double SurfaceYCylinder::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cylinder_distance<1, 0, 2>(xyz, uvw, coincident, x0, z0, + r); +} + +inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, x0, z0); +} + +//============================================================================== +// SurfaceZCylinder +//============================================================================== + +class SurfaceZCylinder : public Surface { + double x0, y0, r; +public: + SurfaceZCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &y0, &r); + if (stat != 3) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double +SurfaceZCylinder::evaluate(const double xyz[3]) const { + return axis_aligned_cylinder_evaluate<0, 1>(xyz, x0, y0, r); +} + +inline double SurfaceZCylinder::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cylinder_distance<2, 0, 1>(xyz, uvw, coincident, x0, y0, + r); +} + +inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); } //============================================================================== @@ -219,16 +403,26 @@ read_surfaces(pugi::xml_node *node) { surf_node = surf_node.next_sibling("surface"), i_surf++) { if (surf_node.attribute("type")) { const pugi::char_t *surf_type = surf_node.attribute("type").value(); - if (strcmp(surf_type, "z-cylinder") == 0) - { - surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); - } - else if (strcmp(surf_type, "z-plane") == 0) - { + + if (strcmp(surf_type, "x-plane") == 0) { + surfaces_c[i_surf] = new SurfaceXPlane(surf_node); + + } else if (strcmp(surf_type, "y-plane") == 0) { + surfaces_c[i_surf] = new SurfaceYPlane(surf_node); + + } else if (strcmp(surf_type, "z-plane") == 0) { surfaces_c[i_surf] = new SurfaceZPlane(surf_node); - } - else - { + + } else if (strcmp(surf_type, "x-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); + + } else if (strcmp(surf_type, "y-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceYCylinder(surf_node); + + } else if (strcmp(surf_type, "z-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); + + } else { std::cout << "Call error or handle uppercase here!" << std::endl; std::cout << surf_type << std::endl; } From 303ee3486e001e7ea3452775fc4ee142022b7320 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 Aug 2017 22:38:38 -0400 Subject: [PATCH 04/21] Add SurfaceSphere to C++ --- src/surface_header.C | 113 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index f62be77ab..42fb948af 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -243,20 +243,23 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], // 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 >= 0.0) return INFTY; - else return (-k + sqrt(quad)) / a; + if (k >= 0.0) { + return INFTY; + } else { + return (-k + sqrt(quad)) / a; + } } else if (c < 0.0) { // 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) + // negative sign on sqrt(quad). return (-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) - double d = (-k - sqrt(quad)) / a; + // with positive sign on sqrt(quad). + const double d = (-k - sqrt(quad)) / a; if (d < 0.0) return INFTY; return d; } @@ -381,6 +384,103 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); } +//============================================================================== +// SurfaceSphere +//============================================================================== + +class SurfaceSphere : public Surface { + double x0, y0, z0, r; +public: + SurfaceSphere(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +double SurfaceSphere::evaluate(const double xyz[3]) const { + const double x = xyz[0] - x0; + const double y = xyz[1] - y0; + const double z = xyz[2] - z0; + return x*x + y*y + z*z - r*r; +} + +double SurfaceSphere::distance(const double xyz[3], const double uvw[3], + bool coincident) const { + const double x = xyz[0] - x0; + const double y = xyz[1] - y0; + const double z = xyz[2] - z0; + const double k = x*uvw[0] + y*uvw[1] + z*uvw[2]; + const double c = x*x + y*y + z*z - r*r; + const double quad = k*k - c; + + if (quad < 0.0) { + // No intersection with sphere. + return INFTY; + + } else if (coincident or fabs(c) < FP_COINCIDENT) { + // 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 >= 0.0) { + return INFTY; + } else { + return -k + sqrt(quad); + } + + } else if (c < 0.0) { + // 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) + return -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). + const double d = -k - sqrt(quad); + if (d < 0.0) return INFTY; + return d; + } +} + +inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const { + uvw[0] = 2.0 * (xyz[0] - x0); + uvw[1] = 2.0 * (xyz[1] - y0); + uvw[2] = 2.0 * (xyz[2] - z0); +} + +//============================================================================== +// SurfaceXCone +//============================================================================== + +// TODO + +//============================================================================== +// SurfaceYCone +//============================================================================== + +// TODO + +//============================================================================== +// SurfaceZCone +//============================================================================== + +// TODO + +//============================================================================== +// SurfaceQuadric +//============================================================================== + +// TODO + //============================================================================== extern "C" void @@ -422,6 +522,9 @@ read_surfaces(pugi::xml_node *node) { } else if (strcmp(surf_type, "z-cylinder") == 0) { surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); + } else if (strcmp(surf_type, "sphere") == 0) { + surfaces_c[i_surf] = new SurfaceSphere(surf_node); + } else { std::cout << "Call error or handle uppercase here!" << std::endl; std::cout << surf_type << std::endl; From 2d0938284b28db1e007797c2ad5368404d2fd6f2 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 12 Aug 2017 17:29:44 -0400 Subject: [PATCH 05/21] Add remaining surfaces to C++ --- src/surface_header.C | 355 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 340 insertions(+), 15 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 42fb948af..397be2cff 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -75,7 +75,7 @@ Surface::reflect(const double xyz[3], double uvw[3]) const { } //============================================================================== -// Generic functions for X-, Y-, and Z-, planes +// Generic functions for x-, y-, and z-, planes //============================================================================== template double @@ -104,6 +104,7 @@ axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { //============================================================================== class SurfaceXPlane : public Surface { + // x = x0 double x0; public: SurfaceXPlane(pugi::xml_node surf_node); @@ -139,6 +140,7 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const { //============================================================================== class SurfaceYPlane : public Surface { + // y = y0 double y0; public: SurfaceYPlane(pugi::xml_node surf_node); @@ -174,6 +176,7 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const { //============================================================================== class SurfaceZPlane : public Surface { + // z = z0 double z0; public: SurfaceZPlane(pugi::xml_node surf_node); @@ -208,10 +211,53 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const { // SurfacePlane //============================================================================== -// TODO +class SurfacePlane : public Surface { + // Ax + By + Cz = D + double A, B, C, D; +public: + SurfacePlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + const bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfacePlane::SurfacePlane(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &A, &B, &C, &D); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +double +SurfacePlane::evaluate(const double xyz[3]) const { + return A*xyz[0] + B*xyz[1] + C*xyz[2] - D; +} + +double +SurfacePlane::distance(const double xyz[3], const double uvw[3], + bool coincident) const { + const double f = A*xyz[0] + B*xyz[1] + C*xyz[2] - D; + const double projection = A*uvw[0] + B*uvw[1] + C*uvw[2]; + if (coincident or fabs(f) < FP_COINCIDENT or projection == 0.0) { + return INFTY; + } else { + const double d = -f / projection; + if (d < 0.0) return INFTY; + return d; + } +} + +void +SurfacePlane::normal(const double xyz[3], double uvw[3]) const { + uvw[0] = A; + uvw[1] = B; + uvw[2] = C; +} //============================================================================== -// Generic functions for X-, Y-, and Z-, cylinders +// Generic functions for x-, y-, and z-, cylinders //============================================================================== template double @@ -224,9 +270,8 @@ axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, template double axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], - double offset1, double offset2, double radius, bool coincident) { + bool coincident, double offset1, double offset2, double radius) { const double a = 1.0 - uvw[i1]*uvw[i1]; // u^2 + v^2 - if (a == 0.0) return INFTY; const double xyz2 = xyz[i2] - offset1; @@ -277,7 +322,10 @@ axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, // SurfaceXCylinder //============================================================================== +// TODO: Test this implementation! + class SurfaceXCylinder : public Surface { + // (y - y0)^2 + (z - z0)^2 = R^2 double y0, z0, r; public: SurfaceXCylinder(pugi::xml_node surf_node); @@ -295,8 +343,7 @@ SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) { } } -inline double -SurfaceXCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceXCylinder::evaluate(const double xyz[3]) const { return axis_aligned_cylinder_evaluate<1, 2>(xyz, y0, z0, r); } @@ -314,7 +361,10 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const { // SurfaceYCylinder //============================================================================== +// TODO: Test this implementation! + class SurfaceYCylinder : public Surface { + // (x - x0)^2 + (z - z0)^2 = R^2 double x0, z0, r; public: SurfaceYCylinder(pugi::xml_node surf_node); @@ -332,8 +382,7 @@ SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) { } } -inline double -SurfaceYCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceYCylinder::evaluate(const double xyz[3]) const { return axis_aligned_cylinder_evaluate<0, 2>(xyz, x0, z0, r); } @@ -352,6 +401,7 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const { //============================================================================== class SurfaceZCylinder : public Surface { + // (x - x0)^2 + (y - y0)^2 = R^2 double x0, y0, r; public: SurfaceZCylinder(pugi::xml_node surf_node); @@ -369,8 +419,7 @@ SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { } } -inline double -SurfaceZCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceZCylinder::evaluate(const double xyz[3]) const { return axis_aligned_cylinder_evaluate<0, 1>(xyz, x0, y0, r); } @@ -389,6 +438,7 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { //============================================================================== class SurfaceSphere : public Surface { + // (x - x0)^2 + (y - y0)^2 + (z - z0)^2 = R^2 double x0, y0, z0, r; public: SurfaceSphere(pugi::xml_node surf_node); @@ -457,29 +507,289 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const { uvw[2] = 2.0 * (xyz[2] - z0); } +//============================================================================== +// Generic functions for x-, y-, and z-, cones +//============================================================================== + +template double +axis_aligned_cone_evaluate(const double xyz[3], double offset1, + double offset2, double offset3, double radius_sq) { + const double xyz1 = xyz[i1] - offset1; + const double xyz2 = xyz[i2] - offset2; + const double xyz3 = xyz[i3] - offset3; + return xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1; +} + +template double +axis_aligned_cone_distance(const double xyz[3], const double uvw[3], + bool coincident, double offset1, double offset2, double offset3, + double radius_sq) { + const double xyz1 = xyz[i1] - offset1; + const double xyz2 = xyz[i2] - offset2; + const double xyz3 = xyz[i3] - offset3; + const double a = uvw[i2]*uvw[i2] + uvw[i3]*uvw[i3] + - radius_sq*uvw[i1]*uvw[i1]; + const double k = xyz2*uvw[i2] + xyz3*uvw[i3] - radius_sq*xyz1*uvw[i1]; + const double c = xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1; + double quad = k*k - a*c; + + double d; + + if (quad < 0.0) { + // No intersection with cone. + return INFTY; + + } else if (coincident or fabs(c) < FP_COINCIDENT) { + // Particle is on the cone, 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 >= 0.0) { + d = (-k - sqrt(quad)) / a; + } else { + d = (-k + sqrt(quad)) / a; + } + + } else { + // Calculate both solutions to the quadratic. + quad = sqrt(quad); + d = (-k - quad) / a; + const double b = (-k + quad) / a; + + // Determine the smallest positive solution. + if (d < 0.0) { + if (b > 0.0) d = b; + } else { + if (b > 0.0) { + if (b < d) d = b; + } + } + } + + // If the distance was negative, set boundary distance to infinity. + if (d <= 0.0) return INFTY; + return d; +} + +template void +axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, + double offset2, double offset3, double radius_sq) { + uvw[i1] = -2.0 * radius_sq * (xyz[i1] - offset1); + uvw[i2] = 2.0 * (xyz[i2] - offset2); + uvw[i3] = 2.0 * (xyz[i3] - offset3); +} + //============================================================================== // SurfaceXCone //============================================================================== -// TODO +// TODO: Test this implementation! + +class SurfaceXCone : public Surface { + // (y - y0)^2 + (z - z0)^2 = R^2*(x - x0)^2 + double x0, y0, z0, r_sq; +public: + SurfaceXCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double SurfaceXCone::evaluate(const double xyz[3]) const { + return axis_aligned_cone_evaluate<0, 1, 2>(xyz, x0, y0, z0, r_sq); +} + +inline double SurfaceXCone::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cone_distance<0, 1, 2>(xyz, uvw, coincident, x0, y0, z0, + r_sq); +} + +inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_sq); +} //============================================================================== // SurfaceYCone //============================================================================== -// TODO +// TODO: Test this implementation! + +class SurfaceYCone : public Surface { + // (x - x0)^2 + (z - z0)^2 = R^2*(y - y0)^2 + double x0, y0, z0, r_sq; +public: + SurfaceYCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double SurfaceYCone::evaluate(const double xyz[3]) const { + return axis_aligned_cone_evaluate<1, 0, 2>(xyz, y0, x0, z0, r_sq); +} + +inline double SurfaceYCone::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cone_distance<1, 0, 2>(xyz, uvw, coincident, y0, x0, z0, + r_sq); +} + +inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_sq); +} //============================================================================== // SurfaceZCone //============================================================================== -// TODO +class SurfaceZCone : public Surface { + // (x - x0)^2 + (y - y0)^2 = R^2*(z - z0)^2 + double x0, y0, z0, r_sq; +public: + SurfaceZCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +inline double SurfaceZCone::evaluate(const double xyz[3]) const { + return axis_aligned_cone_evaluate<2, 0, 1>(xyz, z0, x0, y0, r_sq); +} + +inline double SurfaceZCone::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + return axis_aligned_cone_distance<2, 0, 1>(xyz, uvw, coincident, z0, x0, y0, + r_sq); +} + +inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const { + axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_sq); +} //============================================================================== // SurfaceQuadric //============================================================================== -// TODO +class SurfaceQuadric : public Surface { + // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 + double A, B, C, D, E, F, G, H, J, K; +public: + SurfaceQuadric(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; +}; + +SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) { + const char *coeffs = surf_node.attribute("coeffs").value(); + int stat = sscanf(coeffs, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + &A, &B, &C, &D, &E, &F, &G, &H, &J, &K); + if (stat != 10) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +double +SurfaceQuadric::evaluate(const double xyz[3]) const { + const double &x = xyz[0]; + const double &y = xyz[1]; + const double &z = xyz[2]; + return x*(A*x + D*y + G) + + y*(B*y + E*z + H) + + z*(C*z + F*x + J) + K; +} + +double +SurfaceQuadric::distance(const double xyz[3], + const double uvw[3], bool coincident) const { + const double &x = xyz[0]; + const double &y = xyz[1]; + const double &z = xyz[2]; + const double &u = uvw[0]; + const double &v = uvw[1]; + const double &w = uvw[2]; + + const double a = A*u*u + B*v*v + C*w*w + D*u*v + E*v*w + F*u*w; + const double k = (A*u*x + B*v*y + C*w*z + 0.5*(D*(u*y + v*x) + + E*(v*z + w*y) + F*(w*x + u*z) + G*u + H*v + J*w)); + const double c = A*x*x + B*y*y + C*z*z + D*x*y + E*y*z + F*x*z + G*x + H*y + + J*z + K; + double quad = k*k - a*c; + + double d; + + if (quad < 0.0) { + // No intersection with surface. + return INFTY; + + } else if (coincident or fabs(c) < FP_COINCIDENT) { + // Particle is on the surface, 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 >= 0.0) { + d = (-k - sqrt(quad)) / a; + } else { + d = (-k + sqrt(quad)) / a; + } + + } else { + // Calculate both solutions to the quadratic. + quad = sqrt(quad); + d = (-k - quad) / a; + double b = (-k + quad) / a; + + // Determine the smallest positive solution. + if (d < 0.0) { + if (b > 0.0) d = b; + } else { + if (b > 0.0) { + if (b < d) d = b; + } + } + } + + // If the distance was negative, set boundary distance to infinity. + if (d <= 0.0) return INFTY; + return d; +} + +void +SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const { + const double &x = xyz[0]; + const double &y = xyz[1]; + const double &z = xyz[2]; + uvw[0] = 2.0*A*x + D*y + F*z + G; + uvw[1] = 2.0*B*y + D*x + E*z + H; + uvw[2] = 2.0*C*z + E*y + F*x + J; +} //============================================================================== @@ -513,6 +823,9 @@ read_surfaces(pugi::xml_node *node) { } else if (strcmp(surf_type, "z-plane") == 0) { surfaces_c[i_surf] = new SurfaceZPlane(surf_node); + } else if (strcmp(surf_type, "plane") == 0) { + surfaces_c[i_surf] = new SurfacePlane(surf_node); + } else if (strcmp(surf_type, "x-cylinder") == 0) { surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); @@ -525,6 +838,18 @@ read_surfaces(pugi::xml_node *node) { } else if (strcmp(surf_type, "sphere") == 0) { surfaces_c[i_surf] = new SurfaceSphere(surf_node); + } else if (strcmp(surf_type, "x-cone") == 0) { + surfaces_c[i_surf] = new SurfaceXCone(surf_node); + + } else if (strcmp(surf_type, "y-cone") == 0) { + surfaces_c[i_surf] = new SurfaceYCone(surf_node); + + } else if (strcmp(surf_type, "z-cone") == 0) { + surfaces_c[i_surf] = new SurfaceZCone(surf_node); + + } else if (strcmp(surf_type, "quadric") == 0) { + surfaces_c[i_surf] = new SurfaceQuadric(surf_node); + } else { std::cout << "Call error or handle uppercase here!" << std::endl; std::cout << surf_type << std::endl; From d4a1f1834b42c78f574525e564a09a537071b3ca Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 2 Sep 2017 18:44:06 -0400 Subject: [PATCH 06/21] Handle both XML nodes and attributes in C++ surfs --- src/surface_header.C | 213 +++++++++++++++++++++++++------------------ 1 file changed, 123 insertions(+), 90 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 397be2cff..3ac3d3c53 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -18,6 +18,82 @@ const double INFTY = std::numeric_limits::max(); class Surface; Surface **surfaces_c; +//============================================================================== +// Helper functions +//============================================================================== + +void read_coeffs(pugi::xml_node surf_node, double &c1) +{ + const char *coeffs; + if (surf_node.attribute("coeffs")) { + coeffs = surf_node.attribute("coeffs").value(); + } else if (surf_node.child("coeffs")) { + coeffs = surf_node.child_value("coeffs"); + } else { + std::cout << "ERROR: Found a surface with no coefficients" << std::endl; + } + + int stat = sscanf(coeffs, "%lf", &c1); + if (stat != 1) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3) +{ + const char *coeffs; + if (surf_node.attribute("coeffs")) { + coeffs = surf_node.attribute("coeffs").value(); + } else if (surf_node.child("coeffs")) { + coeffs = surf_node.child_value("coeffs"); + } else { + std::cout << "ERROR: Found a surface with no coefficients" << std::endl; + } + + int stat = sscanf(coeffs, "%lf %lf %lf", &c1, &c2, &c3); + if (stat != 3) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, + double &c4) +{ + const char *coeffs; + if (surf_node.attribute("coeffs")) { + coeffs = surf_node.attribute("coeffs").value(); + } else if (surf_node.child("coeffs")) { + coeffs = surf_node.child_value("coeffs"); + } else { + std::cout << "ERROR: Found a surface with no coefficients" << std::endl; + } + + int stat = sscanf(coeffs, "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); + if (stat != 4) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + +void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, + double &c4, double &c5, double &c6, double &c7, double &c8, + double &c9, double &c10) +{ + const char *coeffs; + if (surf_node.attribute("coeffs")) { + coeffs = surf_node.attribute("coeffs").value(); + } else if (surf_node.child("coeffs")) { + coeffs = surf_node.child_value("coeffs"); + } else { + std::cout << "ERROR: Found a surface with no coefficients" << std::endl; + } + + int stat = sscanf(coeffs, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); + if (stat != 10) { + std::cout << "Something went wrong reading surface coeffs!" << std::endl; + } +} + //============================================================================== // SURFACE type defines a first- or second-order surface that can be used to // construct closed volumes (cells) @@ -115,11 +191,7 @@ public: }; SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf", &x0); - if (stat != 1) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0); } inline double SurfaceXPlane::evaluate(const double xyz[3]) const { @@ -151,11 +223,7 @@ public: }; SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf", &y0); - if (stat != 1) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, y0); } inline double SurfaceYPlane::evaluate(const double xyz[3]) const { @@ -187,11 +255,7 @@ public: }; SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf", &z0); - if (stat != 1) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, z0); } inline double SurfaceZPlane::evaluate(const double xyz[3]) const { @@ -223,11 +287,7 @@ public: }; SurfacePlane::SurfacePlane(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &A, &B, &C, &D); - if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, A, B, C, D); } double @@ -336,11 +396,7 @@ public: }; SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf", &y0, &z0, &r); - if (stat != 3) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, y0, z0, r); } inline double SurfaceXCylinder::evaluate(const double xyz[3]) const { @@ -375,11 +431,7 @@ public: }; SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &z0, &r); - if (stat != 3) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, z0, r); } inline double SurfaceYCylinder::evaluate(const double xyz[3]) const { @@ -412,11 +464,7 @@ public: }; SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf", &x0, &y0, &r); - if (stat != 3) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, y0, r); } inline double SurfaceZCylinder::evaluate(const double xyz[3]) const { @@ -449,11 +497,7 @@ public: }; SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r); - if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, y0, z0, r); } double SurfaceSphere::evaluate(const double xyz[3]) const { @@ -596,11 +640,7 @@ public: }; SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); - if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, y0, z0, r_sq); } inline double SurfaceXCone::evaluate(const double xyz[3]) const { @@ -635,11 +675,7 @@ public: }; SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); - if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, y0, z0, r_sq); } inline double SurfaceYCone::evaluate(const double xyz[3]) const { @@ -672,11 +708,7 @@ public: }; SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &x0, &y0, &z0, &r_sq); - if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, x0, y0, z0, r_sq); } inline double SurfaceZCone::evaluate(const double xyz[3]) const { @@ -709,12 +741,7 @@ public: }; SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) { - const char *coeffs = surf_node.attribute("coeffs").value(); - int stat = sscanf(coeffs, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &A, &B, &C, &D, &E, &F, &G, &H, &J, &K); - if (stat != 10) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; - } + read_coeffs(surf_node, A, B, C, D, E, F, G, H, J, K); } double @@ -811,49 +838,55 @@ read_surfaces(pugi::xml_node *node) { int i_surf; for (surf_node = node->child("surface"), i_surf = 0; surf_node; surf_node = surf_node.next_sibling("surface"), i_surf++) { + const pugi::char_t *surf_type; if (surf_node.attribute("type")) { - const pugi::char_t *surf_type = surf_node.attribute("type").value(); + surf_type = surf_node.attribute("type").value(); + } else if (surf_node.child("type")) { + surf_type = surf_node.child_value("type"); + } else { + std::cout << "ERROR: Found a surface with no type attribute/node" + << std::endl; + } - if (strcmp(surf_type, "x-plane") == 0) { - surfaces_c[i_surf] = new SurfaceXPlane(surf_node); + if (strcmp(surf_type, "x-plane") == 0) { + surfaces_c[i_surf] = new SurfaceXPlane(surf_node); - } else if (strcmp(surf_type, "y-plane") == 0) { - surfaces_c[i_surf] = new SurfaceYPlane(surf_node); + } else if (strcmp(surf_type, "y-plane") == 0) { + surfaces_c[i_surf] = new SurfaceYPlane(surf_node); - } else if (strcmp(surf_type, "z-plane") == 0) { - surfaces_c[i_surf] = new SurfaceZPlane(surf_node); + } else if (strcmp(surf_type, "z-plane") == 0) { + surfaces_c[i_surf] = new SurfaceZPlane(surf_node); - } else if (strcmp(surf_type, "plane") == 0) { - surfaces_c[i_surf] = new SurfacePlane(surf_node); + } else if (strcmp(surf_type, "plane") == 0) { + surfaces_c[i_surf] = new SurfacePlane(surf_node); - } else if (strcmp(surf_type, "x-cylinder") == 0) { - surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); + } else if (strcmp(surf_type, "x-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); - } else if (strcmp(surf_type, "y-cylinder") == 0) { - surfaces_c[i_surf] = new SurfaceYCylinder(surf_node); + } else if (strcmp(surf_type, "y-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceYCylinder(surf_node); - } else if (strcmp(surf_type, "z-cylinder") == 0) { - surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); + } else if (strcmp(surf_type, "z-cylinder") == 0) { + surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); - } else if (strcmp(surf_type, "sphere") == 0) { - surfaces_c[i_surf] = new SurfaceSphere(surf_node); + } else if (strcmp(surf_type, "sphere") == 0) { + surfaces_c[i_surf] = new SurfaceSphere(surf_node); - } else if (strcmp(surf_type, "x-cone") == 0) { - surfaces_c[i_surf] = new SurfaceXCone(surf_node); + } else if (strcmp(surf_type, "x-cone") == 0) { + surfaces_c[i_surf] = new SurfaceXCone(surf_node); - } else if (strcmp(surf_type, "y-cone") == 0) { - surfaces_c[i_surf] = new SurfaceYCone(surf_node); + } else if (strcmp(surf_type, "y-cone") == 0) { + surfaces_c[i_surf] = new SurfaceYCone(surf_node); - } else if (strcmp(surf_type, "z-cone") == 0) { - surfaces_c[i_surf] = new SurfaceZCone(surf_node); + } else if (strcmp(surf_type, "z-cone") == 0) { + surfaces_c[i_surf] = new SurfaceZCone(surf_node); - } else if (strcmp(surf_type, "quadric") == 0) { - surfaces_c[i_surf] = new SurfaceQuadric(surf_node); + } else if (strcmp(surf_type, "quadric") == 0) { + surfaces_c[i_surf] = new SurfaceQuadric(surf_node); - } else { - std::cout << "Call error or handle uppercase here!" << std::endl; - std::cout << surf_type << std::endl; - } + } else { + std::cout << "Call error or handle uppercase here!" << std::endl; + std::cout << surf_type << std::endl; } } } From 57dbb70d0c2b123cb2938eba7187204bd9fe9991 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 2 Sep 2017 19:12:46 -0400 Subject: [PATCH 07/21] Add test code for C++ surface normals --- src/geometry.F90 | 18 ++++++++++++++++++ src/surface_header.C | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/src/geometry.F90 b/src/geometry.F90 index bc1eca2ae..8a449a284 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -35,6 +35,15 @@ module geometry logical(C_BOOL), value :: coincident; real(C_DOUBLE) :: d; end function surface_distance_c + + subroutine surface_normal_c(surf_ind, xyz, uvw) & + bind(C, name='surface_normal') + use ISO_C_BINDING + implicit none + integer(C_INT), value :: surf_ind; + real(C_DOUBLE) :: xyz(3); + real(C_DOUBLE) :: uvw(3); + end subroutine surface_normal_c end interface contains @@ -76,6 +85,7 @@ contains integer :: token logical :: actual_sense ! sense of particle wrt surface logical :: alt_sense + real(8) :: uvw1(3), uvw2(3) in_cell = .true. do i = 1, size(c%rpn) @@ -102,6 +112,14 @@ contains write(*, *) actual_sense, alt_sense call fatal_error("") end if + uvw1 = surfaces(abs(token))%obj%normal(p%coord(p%n_coord)%xyz) + call surface_normal_c(abs(token)-1, p%coord(p%n_coord)%xyz, uvw2) + if (.not. all(uvw1 - uvw2 == ZERO)) then + write(*, *) "Surface normals don't match" + write(*, *) uvw1 + write(*, *) uvw2 + call fatal_error("") + end if if (actual_sense .neqv. (token > 0)) then in_cell = .false. exit diff --git a/src/surface_header.C b/src/surface_header.C index 3ac3d3c53..43209fc80 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -903,3 +903,8 @@ extern "C" double surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) { return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); } + +extern "C" void +surface_normal(int surf_ind, double xyz[3], double uvw[3]) { + return surfaces_c[surf_ind]->normal(xyz, uvw); +} From 3752fea1e9e3c45baf5aebf410ebc595f032596f Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 3 Sep 2017 13:28:04 -0400 Subject: [PATCH 08/21] Use Doxygen-style comments for C++ surface code --- src/surface_header.C | 195 ++++++++++++++++++++++++++++--------------- 1 file changed, 126 insertions(+), 69 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 43209fc80..297335827 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -1,9 +1,12 @@ #include // For strcmp -#include #include // For numeric_limits #include // For fabs + #include "pugixml/pugixml.hpp" +// DEBUGGING +#include + //============================================================================== // Constants //============================================================================== @@ -19,20 +22,24 @@ class Surface; Surface **surfaces_c; //============================================================================== -// Helper functions +// Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== +const char* get_coeff_str(pugi::xml_node surf_node) +{ + if (surf_node.attribute("coeffs")) { + return surf_node.attribute("coeffs").value(); + } else if (surf_node.child("coeffs")) { + return surf_node.child_value("coeffs"); + } else { + std::cout << "ERROR: Found a surface with no coefficients" << std::endl; + return NULL; + } +} + void read_coeffs(pugi::xml_node surf_node, double &c1) { - const char *coeffs; - if (surf_node.attribute("coeffs")) { - coeffs = surf_node.attribute("coeffs").value(); - } else if (surf_node.child("coeffs")) { - coeffs = surf_node.child_value("coeffs"); - } else { - std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - } - + const char *coeffs = get_coeff_str(surf_node); int stat = sscanf(coeffs, "%lf", &c1); if (stat != 1) { std::cout << "Something went wrong reading surface coeffs!" << std::endl; @@ -41,15 +48,7 @@ void read_coeffs(pugi::xml_node surf_node, double &c1) void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3) { - const char *coeffs; - if (surf_node.attribute("coeffs")) { - coeffs = surf_node.attribute("coeffs").value(); - } else if (surf_node.child("coeffs")) { - coeffs = surf_node.child_value("coeffs"); - } else { - std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - } - + const char *coeffs = get_coeff_str(surf_node); int stat = sscanf(coeffs, "%lf %lf %lf", &c1, &c2, &c3); if (stat != 3) { std::cout << "Something went wrong reading surface coeffs!" << std::endl; @@ -59,15 +58,7 @@ void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3) void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, double &c4) { - const char *coeffs; - if (surf_node.attribute("coeffs")) { - coeffs = surf_node.attribute("coeffs").value(); - } else if (surf_node.child("coeffs")) { - coeffs = surf_node.child_value("coeffs"); - } else { - std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - } - + const char *coeffs = get_coeff_str(surf_node); int stat = sscanf(coeffs, "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); if (stat != 4) { std::cout << "Something went wrong reading surface coeffs!" << std::endl; @@ -78,15 +69,7 @@ void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, double &c4, double &c5, double &c6, double &c7, double &c8, double &c9, double &c10) { - const char *coeffs; - if (surf_node.attribute("coeffs")) { - coeffs = surf_node.attribute("coeffs").value(); - } else if (surf_node.child("coeffs")) { - coeffs = surf_node.child_value("coeffs"); - } else { - std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - } - + const char *coeffs = get_coeff_str(surf_node); int stat = sscanf(coeffs, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); if (stat != 10) { @@ -95,25 +78,52 @@ void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, } //============================================================================== -// SURFACE type defines a first- or second-order surface that can be used to -// construct closed volumes (cells) +//! A geometry primitive used to define regions of 3D space. //============================================================================== class Surface { - int id; // Unique ID - int neighbor_pos[], // List of cells on positive side - neighbor_neg[]; // List of cells on negative side - int bc; // Boundary condition - //TODO: swith that zero to a NONE constant. - int i_periodic = 0; // Index of corresponding periodic surface - char name[104]; // User-defined name - public: + int id; //!< Unique ID + int neighbor_pos[], //!< List of cells on positive side + neighbor_neg[]; //!< List of cells on negative side + int bc; //!< Boundary condition + //TODO: switch that zero to a NONE constant. + int i_periodic = 0; //!< Index of corresponding periodic surface + char name[104]; //!< User-defined name + + //! Determine which side of a surface a point lies on. + //! @param xyz[3] The 3D Cartesian coordinate of a point. + //! @param uvw[3] A direction used to "break ties" and pick a sense when the + //! point is very close to the surface. + //! @return True if the point is on the "positive" side of the surface and + //! false otherwise. bool sense(const double xyz[3], const double uvw[3]) const; + + //! Determine the direction of a ray reflected from the surface. + //! @param xyz[3] The point at which the ray is incident. + //! @param uvw[3] A direction. This is both an input and an output parameter. + //! It specifies the icident direction on input and the reflected direction + //! on output. void reflect(const double xyz[3], double uvw[3]) const; + + //! Evaluate the equation describing the surface. + //! + //! Surfaces can be described by some function f(x, y, z) = 0. This member + //! function evaluates that mathematical function. + //! @param xyz[3] A 3D Cartesian coordinate. virtual double evaluate(const double xyz[3]) const = 0; + + //! Compute the distance between a point and the surface along a ray. + //! @param xyz[3] A 3D Cartesian coordinate. + //! @param uvw[3] The direction of the ray. + //! @param coincident A hint to the code that the given point should lie + //! exactly on the surface. virtual double distance(const double xyz[3], const double uvw[3], bool coincident) const = 0; + + //! Compute the local outward normal direction of the surface. + //! @param xyz[3] A 3D Cartesian coordinate. + //! @param uvw[3] This output argument provides the normal. virtual void normal(const double xyz[3], double uvw[3]) const = 0; }; @@ -151,13 +161,16 @@ Surface::reflect(const double xyz[3], double uvw[3]) const { } //============================================================================== -// Generic functions for x-, y-, and z-, planes +// Generic functions for x-, y-, and z-, planes. //============================================================================== +// The template parameter indicates the axis normal to the plane. template double axis_aligned_plane_evaluate(const double xyz[3], double offset) { - return xyz[i] - offset;} + return xyz[i] - offset; +} +// The template parameter indicates the axis normal to the plane. template double axis_aligned_plane_distance(const double xyz[3], const double uvw[3], bool coincident, double offset) { @@ -168,6 +181,8 @@ axis_aligned_plane_distance(const double xyz[3], const double uvw[3], return d; } +// The first template parameter indicates the axis normal to the plane. The +// other two parameters indicate the other two axes. template void axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { uvw[i1] = 1.0; @@ -177,10 +192,12 @@ axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { //============================================================================== // SurfaceXPlane +//! A plane perpendicular to the x-axis. +// +//! The plane is described by the equation \f$x - x_0 = 0\f$ //============================================================================== class SurfaceXPlane : public Surface { - // x = x0 double x0; public: SurfaceXPlane(pugi::xml_node surf_node); @@ -209,10 +226,12 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceYPlane +//! A plane perpendicular to the y-axis. +// +//! The plane is described by the equation \f$y - y_0 = 0\f$ //============================================================================== class SurfaceYPlane : public Surface { - // y = y0 double y0; public: SurfaceYPlane(pugi::xml_node surf_node); @@ -241,10 +260,12 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceZPlane +//! A plane perpendicular to the z-axis. +// +//! The plane is described by the equation \f$z - z_0 = 0\f$ //============================================================================== class SurfaceZPlane : public Surface { - // z = z0 double z0; public: SurfaceZPlane(pugi::xml_node surf_node); @@ -273,10 +294,12 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfacePlane +//! A general plane. +// +//! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ //============================================================================== class SurfacePlane : public Surface { - // Ax + By + Cz = D double A, B, C, D; public: SurfacePlane(pugi::xml_node surf_node); @@ -320,6 +343,9 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const { // Generic functions for x-, y-, and z-, cylinders //============================================================================== +// The template parameters indicate the axes perpendicular to the axis of the +// cylinder. offset1 and offset2 should correspond with i1 and i2, +// respectively. template double axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, double offset2, double radius) { @@ -328,6 +354,9 @@ axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, return xyz1*xyz1 + xyz2*xyz2 - radius*radius; } +// The first template parameter indicates which axis the cylinder is aligned to. +// The other two parameters indicate the other two axes. offset1 and offset2 +// should correspond with i2 and i3, respectively. template double axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], bool coincident, double offset1, double offset2, double radius) { @@ -370,6 +399,9 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], } } +// The first template parameter indicates which axis the cylinder is aligned to. +// The other two parameters indicate the other two axes. offset1 and offset2 +// should correspond with i2 and i3, respectively. template void axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, double offset2) { @@ -380,12 +412,13 @@ axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, //============================================================================== // SurfaceXCylinder +//! A cylinder aligned along the x-axis. +// +//! The cylinder is described by the equation +//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -// TODO: Test this implementation! - class SurfaceXCylinder : public Surface { - // (y - y0)^2 + (z - z0)^2 = R^2 double y0, z0, r; public: SurfaceXCylinder(pugi::xml_node surf_node); @@ -415,12 +448,13 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceYCylinder +//! A cylinder aligned along the y-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -// TODO: Test this implementation! - class SurfaceYCylinder : public Surface { - // (x - x0)^2 + (z - z0)^2 = R^2 double x0, z0, r; public: SurfaceYCylinder(pugi::xml_node surf_node); @@ -450,10 +484,13 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceZCylinder +//! A cylinder aligned along the z-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ //============================================================================== class SurfaceZCylinder : public Surface { - // (x - x0)^2 + (y - y0)^2 = R^2 double x0, y0, r; public: SurfaceZCylinder(pugi::xml_node surf_node); @@ -483,10 +520,13 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceSphere +//! A sphere. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== class SurfaceSphere : public Surface { - // (x - x0)^2 + (y - y0)^2 + (z - z0)^2 = R^2 double x0, y0, z0, r; public: SurfaceSphere(pugi::xml_node surf_node); @@ -555,6 +595,9 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const { // Generic functions for x-, y-, and z-, cones //============================================================================== +// The first template parameter indicates which axis the cone is aligned to. +// The other two parameters indicate the other two axes. offset1, offset2, +// and offset3 should correspond with i1, i2, and i3, respectively. template double axis_aligned_cone_evaluate(const double xyz[3], double offset1, double offset2, double offset3, double radius_sq) { @@ -564,6 +607,9 @@ axis_aligned_cone_evaluate(const double xyz[3], double offset1, return xyz2*xyz2 + xyz3*xyz3 - radius_sq*xyz1*xyz1; } +// The first template parameter indicates which axis the cone is aligned to. +// The other two parameters indicate the other two axes. offset1, offset2, +// and offset3 should correspond with i1, i2, and i3, respectively. template double axis_aligned_cone_distance(const double xyz[3], const double uvw[3], bool coincident, double offset1, double offset2, double offset3, @@ -614,6 +660,9 @@ axis_aligned_cone_distance(const double xyz[3], const double uvw[3], return d; } +// The first template parameter indicates which axis the cone is aligned to. +// The other two parameters indicate the other two axes. offset1, offset2, +// and offset3 should correspond with i1, i2, and i3, respectively. template void axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, double offset2, double offset3, double radius_sq) { @@ -624,12 +673,13 @@ axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, //============================================================================== // SurfaceXCone +//! A cone aligned along the x-axis. +// +//! The cylinder is described by the equation +//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ //============================================================================== -// TODO: Test this implementation! - class SurfaceXCone : public Surface { - // (y - y0)^2 + (z - z0)^2 = R^2*(x - x0)^2 double x0, y0, z0, r_sq; public: SurfaceXCone(pugi::xml_node surf_node); @@ -659,12 +709,13 @@ inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceYCone +//! A cone aligned along the y-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ //============================================================================== -// TODO: Test this implementation! - class SurfaceYCone : public Surface { - // (x - x0)^2 + (z - z0)^2 = R^2*(y - y0)^2 double x0, y0, z0, r_sq; public: SurfaceYCone(pugi::xml_node surf_node); @@ -694,10 +745,13 @@ inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceZCone +//! A cone aligned along the z-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ //============================================================================== class SurfaceZCone : public Surface { - // (x - x0)^2 + (y - y0)^2 = R^2*(z - z0)^2 double x0, y0, z0, r_sq; public: SurfaceZCone(pugi::xml_node surf_node); @@ -727,6 +781,9 @@ inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const { //============================================================================== // SurfaceQuadric +//! A general surface described by a quadratic equation. +// +//! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ //============================================================================== class SurfaceQuadric : public Surface { From 72cb25e6776280fef9eb4d42e6cf712a9a36cf91 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 11 Sep 2017 16:42:40 -0400 Subject: [PATCH 09/21] Use consistent brace placement in C++ --- src/surface_header.C | 228 ++++++++++++++++++++++++++++--------------- 1 file changed, 152 insertions(+), 76 deletions(-) diff --git a/src/surface_header.C b/src/surface_header.C index 297335827..6992c2e2a 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -81,7 +81,8 @@ void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, //! A geometry primitive used to define regions of 3D space. //============================================================================== -class Surface { +class Surface +{ public: int id; //!< Unique ID int neighbor_pos[], //!< List of cells on positive side @@ -128,7 +129,8 @@ public: }; bool -Surface::sense(const double xyz[3], const double uvw[3]) const { +Surface::sense(const double xyz[3], const double uvw[3]) const +{ // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. const double f = evaluate(xyz); @@ -146,7 +148,8 @@ Surface::sense(const double xyz[3], const double uvw[3]) const { } void -Surface::reflect(const double xyz[3], double uvw[3]) const { +Surface::reflect(const double xyz[3], double uvw[3]) const +{ // Determine projection of direction onto normal and squared magnitude of // normal. double norm[3]; @@ -166,14 +169,16 @@ Surface::reflect(const double xyz[3], double uvw[3]) const { // The template parameter indicates the axis normal to the plane. template double -axis_aligned_plane_evaluate(const double xyz[3], double offset) { +axis_aligned_plane_evaluate(const double xyz[3], double offset) +{ return xyz[i] - offset; } // The template parameter indicates the axis normal to the plane. template double axis_aligned_plane_distance(const double xyz[3], const double uvw[3], - bool coincident, double offset) { + bool coincident, double offset) +{ const double f = offset - xyz[i]; if (coincident or fabs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY; const double d = f / uvw[i]; @@ -184,7 +189,8 @@ axis_aligned_plane_distance(const double xyz[3], const double uvw[3], // The first template parameter indicates the axis normal to the plane. The // other two parameters indicate the other two axes. template void -axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { +axis_aligned_plane_normal(const double xyz[3], double uvw[3]) +{ uvw[i1] = 1.0; uvw[i2] = 0.0; uvw[i3] = 0.0; @@ -197,7 +203,8 @@ axis_aligned_plane_normal(const double xyz[3], double uvw[3]) { //! The plane is described by the equation \f$x - x_0 = 0\f$ //============================================================================== -class SurfaceXPlane : public Surface { +class SurfaceXPlane : public Surface +{ double x0; public: SurfaceXPlane(pugi::xml_node surf_node); @@ -207,20 +214,24 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) { +SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0); } -inline double SurfaceXPlane::evaluate(const double xyz[3]) const { +inline double SurfaceXPlane::evaluate(const double xyz[3]) const +{ return axis_aligned_plane_evaluate<0>(xyz, x0); } inline double SurfaceXPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const { + bool coincident) const +{ return axis_aligned_plane_distance<0>(xyz, uvw, coincident, x0); } -inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); } @@ -231,7 +242,8 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const { //! The plane is described by the equation \f$y - y_0 = 0\f$ //============================================================================== -class SurfaceYPlane : public Surface { +class SurfaceYPlane : public Surface +{ double y0; public: SurfaceYPlane(pugi::xml_node surf_node); @@ -241,20 +253,24 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) { +SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) +{ read_coeffs(surf_node, y0); } -inline double SurfaceYPlane::evaluate(const double xyz[3]) const { +inline double SurfaceYPlane::evaluate(const double xyz[3]) const +{ return axis_aligned_plane_evaluate<1>(xyz, y0); } inline double SurfaceYPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const { + bool coincident) const +{ return axis_aligned_plane_distance<1>(xyz, uvw, coincident, y0); } -inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); } @@ -265,7 +281,8 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const { //! The plane is described by the equation \f$z - z_0 = 0\f$ //============================================================================== -class SurfaceZPlane : public Surface { +class SurfaceZPlane : public Surface +{ double z0; public: SurfaceZPlane(pugi::xml_node surf_node); @@ -275,20 +292,24 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) { +SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) +{ read_coeffs(surf_node, z0); } -inline double SurfaceZPlane::evaluate(const double xyz[3]) const { +inline double SurfaceZPlane::evaluate(const double xyz[3]) const +{ return axis_aligned_plane_evaluate<2>(xyz, z0); } inline double SurfaceZPlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const { + bool coincident) const +{ return axis_aligned_plane_distance<2>(xyz, uvw, coincident, z0); } -inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); } @@ -299,7 +320,8 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const { //! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ //============================================================================== -class SurfacePlane : public Surface { +class SurfacePlane : public Surface +{ double A, B, C, D; public: SurfacePlane(pugi::xml_node surf_node); @@ -309,18 +331,21 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfacePlane::SurfacePlane(pugi::xml_node surf_node) { +SurfacePlane::SurfacePlane(pugi::xml_node surf_node) +{ read_coeffs(surf_node, A, B, C, D); } double -SurfacePlane::evaluate(const double xyz[3]) const { +SurfacePlane::evaluate(const double xyz[3]) const +{ return A*xyz[0] + B*xyz[1] + C*xyz[2] - D; } double SurfacePlane::distance(const double xyz[3], const double uvw[3], - bool coincident) const { + bool coincident) const +{ const double f = A*xyz[0] + B*xyz[1] + C*xyz[2] - D; const double projection = A*uvw[0] + B*uvw[1] + C*uvw[2]; if (coincident or fabs(f) < FP_COINCIDENT or projection == 0.0) { @@ -333,7 +358,8 @@ SurfacePlane::distance(const double xyz[3], const double uvw[3], } void -SurfacePlane::normal(const double xyz[3], double uvw[3]) const { +SurfacePlane::normal(const double xyz[3], double uvw[3]) const +{ uvw[0] = A; uvw[1] = B; uvw[2] = C; @@ -348,7 +374,8 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const { // respectively. template double axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, - double offset2, double radius) { + double offset2, double radius) +{ const double xyz1 = xyz[i1] - offset1; const double xyz2 = xyz[i2] - offset2; return xyz1*xyz1 + xyz2*xyz2 - radius*radius; @@ -359,7 +386,8 @@ axis_aligned_cylinder_evaluate(const double xyz[3], double offset1, // should correspond with i2 and i3, respectively. template double axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], - bool coincident, double offset1, double offset2, double radius) { + bool coincident, double offset1, double offset2, double radius) +{ const double a = 1.0 - uvw[i1]*uvw[i1]; // u^2 + v^2 if (a == 0.0) return INFTY; @@ -404,7 +432,8 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], // should correspond with i2 and i3, respectively. template void axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, - double offset2) { + double offset2) +{ uvw[i2] = 2.0 * (xyz[i2] - offset1); uvw[i3] = 2.0 * (xyz[i3] - offset2); uvw[i1] = 0.0; @@ -418,7 +447,8 @@ axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceXCylinder : public Surface { +class SurfaceXCylinder : public Surface +{ double y0, z0, r; public: SurfaceXCylinder(pugi::xml_node surf_node); @@ -428,21 +458,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) { +SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) +{ read_coeffs(surf_node, y0, z0, r); } -inline double SurfaceXCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceXCylinder::evaluate(const double xyz[3]) const +{ return axis_aligned_cylinder_evaluate<1, 2>(xyz, y0, z0, r); } inline double SurfaceXCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cylinder_distance<0, 1, 2>(xyz, uvw, coincident, y0, z0, r); } -inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cylinder_normal<0, 1, 2>(xyz, uvw, y0, z0); } @@ -454,7 +488,8 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const { //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceYCylinder : public Surface { +class SurfaceYCylinder : public Surface +{ double x0, z0, r; public: SurfaceYCylinder(pugi::xml_node surf_node); @@ -464,21 +499,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) { +SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, z0, r); } -inline double SurfaceYCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceYCylinder::evaluate(const double xyz[3]) const +{ return axis_aligned_cylinder_evaluate<0, 2>(xyz, x0, z0, r); } inline double SurfaceYCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cylinder_distance<1, 0, 2>(xyz, uvw, coincident, x0, z0, r); } -inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, x0, z0); } @@ -490,7 +529,8 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const { //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceZCylinder : public Surface { +class SurfaceZCylinder : public Surface +{ double x0, y0, r; public: SurfaceZCylinder(pugi::xml_node surf_node); @@ -500,21 +540,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) { +SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, y0, r); } -inline double SurfaceZCylinder::evaluate(const double xyz[3]) const { +inline double SurfaceZCylinder::evaluate(const double xyz[3]) const +{ return axis_aligned_cylinder_evaluate<0, 1>(xyz, x0, y0, r); } inline double SurfaceZCylinder::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cylinder_distance<2, 0, 1>(xyz, uvw, coincident, x0, y0, r); } -inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); } @@ -526,7 +570,8 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const { //! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceSphere : public Surface { +class SurfaceSphere : public Surface +{ double x0, y0, z0, r; public: SurfaceSphere(pugi::xml_node surf_node); @@ -536,11 +581,13 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) { +SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, y0, z0, r); } -double SurfaceSphere::evaluate(const double xyz[3]) const { +double SurfaceSphere::evaluate(const double xyz[3]) const +{ const double x = xyz[0] - x0; const double y = xyz[1] - y0; const double z = xyz[2] - z0; @@ -548,7 +595,8 @@ double SurfaceSphere::evaluate(const double xyz[3]) const { } double SurfaceSphere::distance(const double xyz[3], const double uvw[3], - bool coincident) const { + bool coincident) const +{ const double x = xyz[0] - x0; const double y = xyz[1] - y0; const double z = xyz[2] - z0; @@ -585,7 +633,8 @@ double SurfaceSphere::distance(const double xyz[3], const double uvw[3], } } -inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const +{ uvw[0] = 2.0 * (xyz[0] - x0); uvw[1] = 2.0 * (xyz[1] - y0); uvw[2] = 2.0 * (xyz[2] - z0); @@ -600,7 +649,8 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const { // and offset3 should correspond with i1, i2, and i3, respectively. template double axis_aligned_cone_evaluate(const double xyz[3], double offset1, - double offset2, double offset3, double radius_sq) { + double offset2, double offset3, double radius_sq) +{ const double xyz1 = xyz[i1] - offset1; const double xyz2 = xyz[i2] - offset2; const double xyz3 = xyz[i3] - offset3; @@ -613,7 +663,8 @@ axis_aligned_cone_evaluate(const double xyz[3], double offset1, template double axis_aligned_cone_distance(const double xyz[3], const double uvw[3], bool coincident, double offset1, double offset2, double offset3, - double radius_sq) { + double radius_sq) +{ const double xyz1 = xyz[i1] - offset1; const double xyz2 = xyz[i2] - offset2; const double xyz3 = xyz[i3] - offset3; @@ -665,7 +716,8 @@ axis_aligned_cone_distance(const double xyz[3], const double uvw[3], // and offset3 should correspond with i1, i2, and i3, respectively. template void axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, - double offset2, double offset3, double radius_sq) { + double offset2, double offset3, double radius_sq) +{ uvw[i1] = -2.0 * radius_sq * (xyz[i1] - offset1); uvw[i2] = 2.0 * (xyz[i2] - offset2); uvw[i3] = 2.0 * (xyz[i3] - offset3); @@ -679,7 +731,8 @@ axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ //============================================================================== -class SurfaceXCone : public Surface { +class SurfaceXCone : public Surface +{ double x0, y0, z0, r_sq; public: SurfaceXCone(pugi::xml_node surf_node); @@ -689,21 +742,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) { +SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, y0, z0, r_sq); } -inline double SurfaceXCone::evaluate(const double xyz[3]) const { +inline double SurfaceXCone::evaluate(const double xyz[3]) const +{ return axis_aligned_cone_evaluate<0, 1, 2>(xyz, x0, y0, z0, r_sq); } inline double SurfaceXCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cone_distance<0, 1, 2>(xyz, uvw, coincident, x0, y0, z0, r_sq); } -inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_sq); } @@ -715,7 +772,8 @@ inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const { //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ //============================================================================== -class SurfaceYCone : public Surface { +class SurfaceYCone : public Surface +{ double x0, y0, z0, r_sq; public: SurfaceYCone(pugi::xml_node surf_node); @@ -725,21 +783,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) { +SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, y0, z0, r_sq); } -inline double SurfaceYCone::evaluate(const double xyz[3]) const { +inline double SurfaceYCone::evaluate(const double xyz[3]) const +{ return axis_aligned_cone_evaluate<1, 0, 2>(xyz, y0, x0, z0, r_sq); } inline double SurfaceYCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cone_distance<1, 0, 2>(xyz, uvw, coincident, y0, x0, z0, r_sq); } -inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_sq); } @@ -751,7 +813,8 @@ inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const { //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ //============================================================================== -class SurfaceZCone : public Surface { +class SurfaceZCone : public Surface +{ double x0, y0, z0, r_sq; public: SurfaceZCone(pugi::xml_node surf_node); @@ -761,21 +824,25 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) { +SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) +{ read_coeffs(surf_node, x0, y0, z0, r_sq); } -inline double SurfaceZCone::evaluate(const double xyz[3]) const { +inline double SurfaceZCone::evaluate(const double xyz[3]) const +{ return axis_aligned_cone_evaluate<2, 0, 1>(xyz, z0, x0, y0, r_sq); } inline double SurfaceZCone::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ return axis_aligned_cone_distance<2, 0, 1>(xyz, uvw, coincident, z0, x0, y0, r_sq); } -inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const { +inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const +{ axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_sq); } @@ -786,7 +853,8 @@ inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const { //! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ //============================================================================== -class SurfaceQuadric : public Surface { +class SurfaceQuadric : public Surface +{ // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 double A, B, C, D, E, F, G, H, J, K; public: @@ -797,12 +865,14 @@ public: void normal(const double xyz[3], double uvw[3]) const; }; -SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) { +SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) +{ read_coeffs(surf_node, A, B, C, D, E, F, G, H, J, K); } double -SurfaceQuadric::evaluate(const double xyz[3]) const { +SurfaceQuadric::evaluate(const double xyz[3]) const +{ const double &x = xyz[0]; const double &y = xyz[1]; const double &z = xyz[2]; @@ -813,7 +883,8 @@ SurfaceQuadric::evaluate(const double xyz[3]) const { double SurfaceQuadric::distance(const double xyz[3], - const double uvw[3], bool coincident) const { + const double uvw[3], bool coincident) const +{ const double &x = xyz[0]; const double &y = xyz[1]; const double &z = xyz[2]; @@ -866,7 +937,8 @@ SurfaceQuadric::distance(const double xyz[3], } void -SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const { +SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const +{ const double &x = xyz[0]; const double &y = xyz[1]; const double &z = xyz[2]; @@ -878,7 +950,8 @@ SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const { //============================================================================== extern "C" void -read_surfaces(pugi::xml_node *node) { +read_surfaces(pugi::xml_node *node) +{ // Count the number of surfaces. int n_surfaces = 0; for (pugi::xml_node surf_node = node->child("surface"); surf_node; @@ -952,16 +1025,19 @@ read_surfaces(pugi::xml_node *node) { //============================================================================== extern "C" bool -surface_sense(int surf_ind, double xyz[3], double uvw[3]) { +surface_sense(int surf_ind, double xyz[3], double uvw[3]) +{ return surfaces_c[surf_ind]->sense(xyz, uvw); } extern "C" double -surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) { +surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) +{ return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); } extern "C" void -surface_normal(int surf_ind, double xyz[3], double uvw[3]) { +surface_normal(int surf_ind, double xyz[3], double uvw[3]) +{ return surfaces_c[surf_ind]->normal(xyz, uvw); } From 163b6e3de5a7235e1152926880e5474ec44af8fb Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 11 Oct 2017 16:58:00 -0400 Subject: [PATCH 10/21] Remove Fortran code for surface distance and sense --- src/geometry.F90 | 67 ++--- src/surface_header.C | 2 +- src/surface_header.F90 | 560 +---------------------------------------- 3 files changed, 23 insertions(+), 606 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 8a449a284..873582dec 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -15,34 +15,34 @@ module geometry implicit none interface - function surface_sense_c(surf_ind, xyz, uvw) & + pure function surface_sense_c(surf_ind, xyz, uvw) & bind(C, name='surface_sense') result(sense) use ISO_C_BINDING implicit none - integer(C_INT), value :: surf_ind; - real(C_DOUBLE) :: xyz(3); - real(C_DOUBLE) :: uvw(3); - logical(C_BOOL) :: sense; + integer(C_INT), intent(in), value :: surf_ind; + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(in) :: uvw(3); + logical(C_BOOL) :: sense; end function surface_sense_c - function surface_distance_c(surf_ind, xyz, uvw, coincident) & + pure function surface_distance_c(surf_ind, xyz, uvw, coincident) & bind(C, name='surface_distance') result(d) use ISO_C_BINDING implicit none - integer(C_INT), value :: surf_ind; - real(C_DOUBLE) :: xyz(3); - real(C_DOUBLE) :: uvw(3); - logical(C_BOOL), value :: coincident; - real(C_DOUBLE) :: d; + integer(C_INT), intent(in), value :: surf_ind; + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(in) :: uvw(3); + logical(C_BOOL), intent(in), value :: coincident; + real(C_DOUBLE) :: d; end function surface_distance_c - subroutine surface_normal_c(surf_ind, xyz, uvw) & + pure subroutine surface_normal_c(surf_ind, xyz, uvw) & bind(C, name='surface_normal') use ISO_C_BINDING implicit none - integer(C_INT), value :: surf_ind; - real(C_DOUBLE) :: xyz(3); - real(C_DOUBLE) :: uvw(3); + integer(C_INT), intent(in), value :: surf_ind; + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(out) :: uvw(3); end subroutine surface_normal_c end interface @@ -62,8 +62,7 @@ contains ! expression using a stack, similar to how a RPN calculator would work. !=============================================================================== - !pure function cell_contains(c, p) result(in_cell) - function cell_contains(c, p) result(in_cell) + pure function cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c type(Particle), intent(in) :: p logical :: in_cell @@ -75,8 +74,7 @@ contains end if end function cell_contains - !pure function simple_cell_contains(c, p) result(in_cell) - function simple_cell_contains(c, p) result(in_cell) + pure function simple_cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c type(Particle), intent(in) :: p logical :: in_cell @@ -84,8 +82,6 @@ contains integer :: i integer :: token logical :: actual_sense ! sense of particle wrt surface - logical :: alt_sense - real(8) :: uvw1(3), uvw2(3) in_cell = .true. do i = 1, size(c%rpn) @@ -101,25 +97,8 @@ contains in_cell = .false. exit else - actual_sense = surfaces(abs(token))%obj%sense(& + actual_sense = surface_sense_c(abs(token)-1, & p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) - alt_sense = surface_sense_c(abs(token)-1, & - p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) - if (actual_sense .neqv. alt_sense) then - write(*, *) surfaces(abs(token)) % obj % id - write(*, *) p % coord (p % n_coord) % xyz - write(*, *) p % coord (p % n_coord) % uvw - write(*, *) actual_sense, alt_sense - call fatal_error("") - end if - uvw1 = surfaces(abs(token))%obj%normal(p%coord(p%n_coord)%xyz) - call surface_normal_c(abs(token)-1, p%coord(p%n_coord)%xyz, uvw2) - if (.not. all(uvw1 - uvw2 == ZERO)) then - write(*, *) "Surface normals don't match" - write(*, *) uvw1 - write(*, *) uvw2 - call fatal_error("") - end if if (actual_sense .neqv. (token > 0)) then in_cell = .false. exit @@ -167,7 +146,7 @@ contains elseif (-token == p%surface) then stack(i_stack) = .false. else - actual_sense = surfaces(abs(token))%obj%sense(& + actual_sense = surface_sense_c(abs(token)-1, & p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) stack(i_stack) = (actual_sense .eqv. (token > 0)) end if @@ -539,7 +518,6 @@ contains type(Cell), pointer :: c class(Surface), pointer :: surf class(Lattice), pointer :: lat - real(8) :: d_alt ! inialize distance to infinity (huge) dist = INFINITY @@ -573,13 +551,8 @@ contains if (index_surf >= OP_UNION) cycle ! Calculate distance to surface - surf => surfaces(index_surf) % obj - d = surf % distance(p % coord(j) % xyz, p % coord(j) % uvw, coincident) - d_alt = surface_distance_c(index_surf-1, p % coord(j) % xyz, & + d = surface_distance_c(index_surf-1, p % coord(j) % xyz, & p % coord(j) % uvw, logical(coincident, kind=C_BOOL)) - if (d /= d_alt) then - write(*, *) d, d_alt - end if ! Check if calculated distance is new minimum if (d < d_surf) then diff --git a/src/surface_header.C b/src/surface_header.C index 6992c2e2a..cf200e5e4 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -33,7 +33,7 @@ const char* get_coeff_str(pugi::xml_node surf_node) return surf_node.child_value("coeffs"); } else { std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - return NULL; + return nullptr; } } diff --git a/src/surface_header.F90 b/src/surface_header.F90 index ed4ef86e0..b0da37c1e 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -21,10 +21,8 @@ module surface_header integer :: i_periodic = NONE ! Index of corresponding periodic surface character(len=104) :: name = "" ! User-defined name contains - procedure :: sense procedure :: reflect procedure(surface_evaluate_), deferred :: evaluate - procedure(surface_distance_), deferred :: distance procedure(surface_normal_), deferred :: normal end type Surface @@ -36,15 +34,6 @@ module surface_header real(8) :: f end function surface_evaluate_ - pure function surface_distance_(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 surface_distance_ - pure function surface_normal_(this, xyz) result(uvw) import Surface class(Surface), intent(in) :: this @@ -63,8 +52,8 @@ module surface_header !=============================================================================== ! 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() +! inherent the reflect() type-bound procedure and must implement evaluate(), +! and normal() !=============================================================================== type, extends(Surface) :: SurfaceXPlane @@ -72,7 +61,6 @@ module surface_header real(8) :: x0 contains procedure :: evaluate => x_plane_evaluate - procedure :: distance => x_plane_distance procedure :: normal => x_plane_normal end type SurfaceXPlane @@ -81,7 +69,6 @@ module surface_header real(8) :: y0 contains procedure :: evaluate => y_plane_evaluate - procedure :: distance => y_plane_distance procedure :: normal => y_plane_normal end type SurfaceYPlane @@ -90,7 +77,6 @@ module surface_header real(8) :: z0 contains procedure :: evaluate => z_plane_evaluate - procedure :: distance => z_plane_distance procedure :: normal => z_plane_normal end type SurfaceZPlane @@ -102,7 +88,6 @@ module surface_header real(8) :: D contains procedure :: evaluate => plane_evaluate - procedure :: distance => plane_distance procedure :: normal => plane_normal end type SurfacePlane @@ -113,7 +98,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => x_cylinder_evaluate - procedure :: distance => x_cylinder_distance procedure :: normal => x_cylinder_normal end type SurfaceXCylinder @@ -124,7 +108,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => y_cylinder_evaluate - procedure :: distance => y_cylinder_distance procedure :: normal => y_cylinder_normal end type SurfaceYCylinder @@ -135,7 +118,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => z_cylinder_evaluate - procedure :: distance => z_cylinder_distance procedure :: normal => z_cylinder_normal end type SurfaceZCylinder @@ -147,7 +129,6 @@ module surface_header real(8) :: r contains procedure :: evaluate => sphere_evaluate - procedure :: distance => sphere_distance procedure :: normal => sphere_normal end type SurfaceSphere @@ -159,7 +140,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => x_cone_evaluate - procedure :: distance => x_cone_distance procedure :: normal => x_cone_normal end type SurfaceXCone @@ -171,7 +151,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => y_cone_evaluate - procedure :: distance => y_cone_distance procedure :: normal => y_cone_normal end type SurfaceYCone @@ -183,7 +162,6 @@ module surface_header real(8) :: r2 contains procedure :: evaluate => z_cone_evaluate - procedure :: distance => z_cone_distance procedure :: normal => z_cone_normal end type SurfaceZCone @@ -192,7 +170,6 @@ module surface_header real(8) :: A, B, C, D, E, F, G, H, J, K contains procedure :: evaluate => quadric_evaluate - procedure :: distance => quadric_distance procedure :: normal => quadric_normal end type SurfaceQuadric @@ -205,36 +182,6 @@ 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. The positive side is indicated by a returned value of .true. and the -! negative side is indicated by a returned value of .false. -!=============================================================================== - - pure function sense(this, xyz, uvw) result(s) - class(Surface), intent(in) :: this ! surface - real(8), intent(in) :: 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. 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 = (f > ZERO) - end if - end function sense - !=============================================================================== ! 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 @@ -275,24 +222,6 @@ contains f = xyz(1) - this%x0 end function x_plane_evaluate - 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 (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(1) == ZERO) then - d = INFINITY - else - d = f/uvw(1) - if (d < ZERO) d = INFINITY - end if - end function x_plane_distance - pure function x_plane_normal(this, xyz) result(uvw) class(SurfaceXPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -313,24 +242,6 @@ contains f = xyz(2) - this%y0 end function y_plane_evaluate - 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 (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(2) == ZERO) then - d = INFINITY - else - d = f/uvw(2) - if (d < ZERO) d = INFINITY - end if - end function y_plane_distance - pure function y_plane_normal(this, xyz) result(uvw) class(SurfaceYPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -353,24 +264,6 @@ contains end function z_plane_evaluate - 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 (coincident .or. abs(f) < FP_COINCIDENT .or. uvw(3) == ZERO) then - d = INFINITY - else - d = f/uvw(3) - if (d < ZERO) d = INFINITY - end if - end function z_plane_distance - pure function z_plane_normal(this, xyz) result(uvw) class(SurfaceZPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -391,26 +284,6 @@ 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, 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 - real(8) :: projection - - f = this%A*xyz(1) + this%B*xyz(2) + this%C*xyz(3) - this%D - 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/projection - if (d < ZERO) d = INFINITY - end if - end function plane_distance - pure function plane_normal(this, xyz) result(uvw) class(SurfacePlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -435,60 +308,6 @@ contains f = y*y + z*z - this%r*this%r end function x_cylinder_evaluate - 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) - logical, intent(in) :: coincident - 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 (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 - - 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 - pure function x_cylinder_normal(this, xyz) result(uvw) class(SurfaceXCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -515,60 +334,6 @@ contains f = x*x + z*z - this%r*this%r end function y_cylinder_evaluate - 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 - - 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 (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 - - 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 - pure function y_cylinder_normal(this, xyz) result(uvw) class(SurfaceYCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -595,60 +360,6 @@ contains f = x*x + y*y - this%r*this%r end function z_cylinder_evaluate - 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) - logical, intent(in) :: coincident - 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 (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 - - 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 - pure function z_cylinder_normal(this, xyz) result(uvw) class(SurfaceZCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -676,55 +387,6 @@ contains f = x*x + y*y + z*z - this%r*this%r end function sphere_evaluate - 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 - - 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 (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 - - 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 - pure function sphere_normal(this, xyz) result(uvw) class(SurfaceSphere), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -750,59 +412,6 @@ contains f = y*y + z*z - this%r2*x*x end function x_cone_evaluate - 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 - - 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 (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. - - 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 - pure function x_cone_normal(this, xyz) result(uvw) class(SurfaceXCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -830,59 +439,6 @@ contains f = x*x + z*z - this%r2*y*y end function y_cone_evaluate - 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 - - 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 (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. - - 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 - pure function y_cone_normal(this, xyz) result(uvw) class(SurfaceYCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -910,59 +466,6 @@ contains f = x*x + y*y - this%r2*z*z end function z_cone_evaluate - 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 - - 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 (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. - - 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 - pure function z_cone_normal(this, xyz) result(uvw) class(SurfaceZCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -989,65 +492,6 @@ contains end associate end function quadric_evaluate - pure function quadric_distance(this, xyz, uvw, coincident) result(d) - class(SurfaceQuadric), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8), intent(in) :: uvw(3) - logical, intent(in) :: coincident - real(8) :: d - - real(8) :: a, k, c - real(8) :: quad, b - - associate (x => xyz(1), y => xyz(2), z => xyz(3), & - u => uvw(1), v => uvw(2), w => uvw(3)) - - a = this%A*u*u + this%B*v*v + this%C*w*w + this%D*u*v + this%E*v*w + & - this%F*u*w - k = (this%A*u*x + this%B*v*y + this%C*w*z + HALF*(this%D*(u*y + v*x) + & - this%E*(v*z + w*y) + this%F*(w*x + u*z) + this%G*u + this%H*v + & - this%J*w)) - c = this%A*x*x + this%B*y*y + this%C*z*z + this%D*x*y + this%E*y*z + & - this%F*x*z + this%G*x + this%H*y + this%J*z + this%K - quad = k*k - a*c - - if (quad < ZERO) then - ! no intersection with surface - - d = INFINITY - - elseif (coincident .or. abs(c) < FP_COINCIDENT) then - ! particle is on the surface, 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 associate - end function quadric_distance - pure function quadric_normal(this, xyz) result(uvw) class(SurfaceQuadric), intent(in) :: this real(8), intent(in) :: xyz(3) From 38aa76c9dc9cdab0c10f35c2355d20f9842b65bc Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 19 Jan 2018 00:54:39 -0500 Subject: [PATCH 11/21] Implement C++ periodic BCs --- src/geometry.F90 | 11 +++ src/surface_header.C | 136 +++++++++++++++++++++++++++++++++-- src/surface_header.F90 | 157 +---------------------------------------- src/tracking.F90 | 63 +---------------- 4 files changed, 145 insertions(+), 222 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 873582dec..a0a19f1bf 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -44,6 +44,17 @@ module geometry real(C_DOUBLE), intent(in) :: xyz(3); real(C_DOUBLE), intent(out) :: uvw(3); end subroutine surface_normal_c + + function surface_periodic_c(surf_ind1, surf_ind2, xyz, uvw) & + bind(C, name="surface_periodic") result(rotational) + use ISO_C_BINDING + implicit none + integer(C_INT), intent(in), value :: surf_ind1; + integer(C_INT), intent(in), value :: surf_ind2; + real(C_DOUBLE), intent(inout) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + logical(C_BOOL) :: rotational + end function surface_periodic_c end interface contains diff --git a/src/surface_header.C b/src/surface_header.C index cf200e5e4..23fe5adb3 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -5,6 +5,7 @@ #include "pugixml/pugixml.hpp" // DEBUGGING +#include #include //============================================================================== @@ -89,14 +90,14 @@ public: neighbor_neg[]; //!< List of cells on negative side int bc; //!< Boundary condition //TODO: switch that zero to a NONE constant. - int i_periodic = 0; //!< Index of corresponding periodic surface + //int i_periodic = 0; //!< Index of corresponding periodic surface char name[104]; //!< User-defined name //! Determine which side of a surface a point lies on. //! @param xyz[3] The 3D Cartesian coordinate of a point. //! @param uvw[3] A direction used to "break ties" and pick a sense when the //! point is very close to the surface. - //! @return True if the point is on the "positive" side of the surface and + //! @return true if the point is on the "positive" side of the surface and //! false otherwise. bool sense(const double xyz[3], const double uvw[3]) const; @@ -163,6 +164,29 @@ Surface::reflect(const double xyz[3], double uvw[3]) const uvw[2] -= 2.0 * projection / magnitude * norm[2]; } +//============================================================================== +//! A `Surface` that supports periodic boundary conditions. +//! +//! Translational periodicity is supported for the `XPlane`, `YPlane`, `ZPlane`, +//! and `Plane` types. Rotational periodicity is supported for +//! `XPlane`-`YPlane` pairs. +//============================================================================== + +class PeriodicSurface : public Surface +{ +public: + //! Translate a particle onto this surface from a periodic partner surface. + //! @param other A pointer to the partner surface in this periodic BC. + //! @param xyz[3] A point on the partner surface that will be translated onto + //! this surface. + //! @param uvw[3] A direction that will be rotated for systems with rotational + //! periodicity. + //! @return true if this surface and its partner make a rotationally-periodic + //! boundary condition. + virtual bool periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const = 0; +}; + //============================================================================== // Generic functions for x-, y-, and z-, planes. //============================================================================== @@ -203,7 +227,7 @@ axis_aligned_plane_normal(const double xyz[3], double uvw[3]) //! The plane is described by the equation \f$x - x_0 = 0\f$ //============================================================================== -class SurfaceXPlane : public Surface +class SurfaceXPlane : public PeriodicSurface { double x0; public: @@ -212,6 +236,8 @@ public: double distance(const double xyz[3], const double uvw[3], const bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; }; SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) @@ -235,6 +261,32 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); } +bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const +{ + double other_norm[3]; + other->normal(xyz, other_norm); + if (other_norm[0] == 1 and other_norm[1] == 0 and other_norm[2] == 0) { + xyz[0] = x0; + return false; + } else { + // Assume the partner is an YPlane (the only supported partner). Use the + // evaluate function to find y0, then adjust xyz and uvw for rotational + // symmetry. + double xyz_test[3] {0, 0, 0}; + double y0 = -other->evaluate(xyz_test); + xyz[1] = xyz[0] - x0 + y0; + xyz[0] = x0; + xyz[2] = xyz[2]; + + double u = uvw[0]; + uvw[0] = -uvw[1]; + uvw[1] = u; + + return true; + } +}; + //============================================================================== // SurfaceYPlane //! A plane perpendicular to the y-axis. @@ -242,7 +294,7 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const //! The plane is described by the equation \f$y - y_0 = 0\f$ //============================================================================== -class SurfaceYPlane : public Surface +class SurfaceYPlane : public PeriodicSurface { double y0; public: @@ -251,6 +303,8 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; }; SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) @@ -274,6 +328,32 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); } +bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const +{ + double other_norm[3]; + other->normal(xyz, other_norm); + if (other_norm[0] == 0 and other_norm[1] == 1 and other_norm[2] == 0) { + // The periodic partner is also aligned along y. Just change the y coord. + xyz[1] = y0; + return false; + } else { + // Assume the partner is an XPlane (the only supported partner). Use the + // evaluate function to find x0, then adjust xyz and uvw for rotational + // symmetry. + double xyz_test[3] {0, 0, 0}; + double x0 = -other->evaluate(xyz_test); + xyz[0] = xyz[1] - y0 + x0; + xyz[1] = y0; + + double u = uvw[0]; + uvw[0] = uvw[1]; + uvw[1] = -u; + + return true; + } +}; + //============================================================================== // SurfaceZPlane //! A plane perpendicular to the z-axis. @@ -281,7 +361,7 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const //! The plane is described by the equation \f$z - z_0 = 0\f$ //============================================================================== -class SurfaceZPlane : public Surface +class SurfaceZPlane : public PeriodicSurface { double z0; public: @@ -290,6 +370,8 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; }; SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) @@ -313,6 +395,14 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); } +bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const +{ + // Assume the other plane is aligned along z. Just change the z coord. + xyz[2] = z0; + return false; +}; + //============================================================================== // SurfacePlane //! A general plane. @@ -320,7 +410,7 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const //! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ //============================================================================== -class SurfacePlane : public Surface +class SurfacePlane : public PeriodicSurface { double A, B, C, D; public: @@ -329,6 +419,8 @@ public: double distance(const double xyz[3], const double uvw[3], const bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; }; SurfacePlane::SurfacePlane(pugi::xml_node surf_node) @@ -365,6 +457,22 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const uvw[2] = C; } +bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const +{ + // This function assumes the other plane shares this plane's normal direction. + + // Determine the distance to intersection. + double d = evaluate(xyz) / (A*A + B*B + C*C); + + // Move the particle that distance along the normal vector. + xyz[0] -= d * A; + xyz[1] -= d * B; + xyz[2] -= d * C; + + return false; +} + //============================================================================== // Generic functions for x-, y-, and z-, cylinders //============================================================================== @@ -1041,3 +1149,19 @@ surface_normal(int surf_ind, double xyz[3], double uvw[3]) { return surfaces_c[surf_ind]->normal(xyz, uvw); } + +extern "C" bool +surface_periodic(int surf_ind1, int surf_ind2, double xyz[3], double uvw[3]) +{ + // Hopefully this function has only been called on a pair of surfaces that + // support periodic BCs (checking should have been done when reading the + // geometry XML). Downcast the surfaces to the PeriodicSurface type so we + // can call the periodic_translate method. + Surface *surf1_gen = surfaces_c[surf_ind1]; + PeriodicSurface *surf1 = dynamic_cast(surf1_gen); + Surface *surf2_gen = surfaces_c[surf_ind2]; + PeriodicSurface *surf2 = dynamic_cast(surf2_gen); + + // Call the type-bound methods. + return surf2->periodic_translate(surf1, xyz, uvw); +} diff --git a/src/surface_header.F90 b/src/surface_header.F90 index b0da37c1e..d9a00170b 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -22,18 +22,10 @@ module surface_header character(len=104) :: name = "" ! User-defined name contains procedure :: reflect - procedure(surface_evaluate_), deferred :: evaluate procedure(surface_normal_), deferred :: normal end type Surface abstract interface - pure function surface_evaluate_(this, xyz) result(f) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f - end function surface_evaluate_ - pure function surface_normal_(this, xyz) result(uvw) import Surface class(Surface), intent(in) :: this @@ -52,15 +44,13 @@ module surface_header !=============================================================================== ! All the derived types below are extensions of the abstract Surface type. They -! inherent the reflect() type-bound procedure and must implement evaluate(), -! and normal() +! inherent the reflect() type-bound procedure and must implement normal() !=============================================================================== type, extends(Surface) :: SurfaceXPlane ! x = x0 real(8) :: x0 contains - procedure :: evaluate => x_plane_evaluate procedure :: normal => x_plane_normal end type SurfaceXPlane @@ -68,7 +58,6 @@ module surface_header ! y = y0 real(8) :: y0 contains - procedure :: evaluate => y_plane_evaluate procedure :: normal => y_plane_normal end type SurfaceYPlane @@ -76,7 +65,6 @@ module surface_header ! z = z0 real(8) :: z0 contains - procedure :: evaluate => z_plane_evaluate procedure :: normal => z_plane_normal end type SurfaceZPlane @@ -87,7 +75,6 @@ module surface_header real(8) :: C real(8) :: D contains - procedure :: evaluate => plane_evaluate procedure :: normal => plane_normal end type SurfacePlane @@ -97,7 +84,6 @@ module surface_header real(8) :: z0 real(8) :: r contains - procedure :: evaluate => x_cylinder_evaluate procedure :: normal => x_cylinder_normal end type SurfaceXCylinder @@ -107,7 +93,6 @@ module surface_header real(8) :: z0 real(8) :: r contains - procedure :: evaluate => y_cylinder_evaluate procedure :: normal => y_cylinder_normal end type SurfaceYCylinder @@ -117,7 +102,6 @@ module surface_header real(8) :: y0 real(8) :: r contains - procedure :: evaluate => z_cylinder_evaluate procedure :: normal => z_cylinder_normal end type SurfaceZCylinder @@ -128,7 +112,6 @@ module surface_header real(8) :: z0 real(8) :: r contains - procedure :: evaluate => sphere_evaluate procedure :: normal => sphere_normal end type SurfaceSphere @@ -139,7 +122,6 @@ module surface_header real(8) :: z0 real(8) :: r2 contains - procedure :: evaluate => x_cone_evaluate procedure :: normal => x_cone_normal end type SurfaceXCone @@ -150,7 +132,6 @@ module surface_header real(8) :: z0 real(8) :: r2 contains - procedure :: evaluate => y_cone_evaluate procedure :: normal => y_cone_normal end type SurfaceYCone @@ -161,7 +142,6 @@ module surface_header real(8) :: z0 real(8) :: r2 contains - procedure :: evaluate => z_cone_evaluate procedure :: normal => z_cone_normal end type SurfaceZCone @@ -169,7 +149,6 @@ module surface_header ! Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 real(8) :: A, B, C, D, E, F, G, H, J, K contains - procedure :: evaluate => quadric_evaluate procedure :: normal => quadric_normal end type SurfaceQuadric @@ -214,14 +193,6 @@ contains ! 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 - - f = xyz(1) - this%x0 - end function x_plane_evaluate - pure function x_plane_normal(this, xyz) result(uvw) class(SurfaceXPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -234,14 +205,6 @@ contains ! 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 - - f = xyz(2) - this%y0 - end function y_plane_evaluate - pure function y_plane_normal(this, xyz) result(uvw) class(SurfaceYPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -254,16 +217,6 @@ contains ! SurfaceZPlane Implementation !=============================================================================== - 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 - pure function z_plane_normal(this, xyz) result(uvw) class(SurfaceZPlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -276,14 +229,6 @@ contains ! SurfacePlane Implementation !=============================================================================== - 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 - pure function plane_normal(this, xyz) result(uvw) class(SurfacePlane), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -296,18 +241,6 @@ contains ! 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) :: 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 - pure function x_cylinder_normal(this, xyz) result(uvw) class(SurfaceXCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -322,18 +255,6 @@ contains ! 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) :: 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 - pure function y_cylinder_normal(this, xyz) result(uvw) class(SurfaceYCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -348,18 +269,6 @@ contains ! 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) :: 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 - pure function z_cylinder_normal(this, xyz) result(uvw) class(SurfaceZCylinder), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -374,19 +283,6 @@ contains ! SurfaceSphere Implementation !=============================================================================== - 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 - pure function sphere_normal(this, xyz) result(uvw) class(SurfaceSphere), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -399,19 +295,6 @@ contains ! 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) :: 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 - pure function x_cone_normal(this, xyz) result(uvw) class(SurfaceXCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -426,19 +309,6 @@ contains ! 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) :: 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 - pure function y_cone_normal(this, xyz) result(uvw) class(SurfaceYCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -453,19 +323,6 @@ contains ! SurfaceZCone Implementation !=============================================================================== - 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 - pure function z_cone_normal(this, xyz) result(uvw) class(SurfaceZCone), intent(in) :: this real(8), intent(in) :: xyz(3) @@ -480,18 +337,6 @@ contains ! SurfaceQuadric Implementation !=============================================================================== - pure function quadric_evaluate(this, xyz) result(f) - class(SurfaceQuadric), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: f - - associate (x => xyz(1), y => xyz(2), z => xyz(3)) - f = x*(this%A*x + this%D*y + this%G) + & - y*(this%B*y + this%E*z + this%H) + & - z*(this%C*z + this%F*x + this%J) + this%K - end associate - end function quadric_evaluate - pure function quadric_normal(this, xyz) result(uvw) class(SurfaceQuadric), intent(in) :: this real(8), intent(in) :: xyz(3) diff --git a/src/tracking.F90 b/src/tracking.F90 index 65769a7f1..4f0f110bc 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -5,7 +5,7 @@ module tracking use error, only: fatal_error, warning, write_message use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice, & - check_cell_overlap + check_cell_overlap, surface_periodic_c use message_passing use mgxs_header use nuclide_header @@ -290,7 +290,6 @@ contains real(8) :: v ! y-component of direction real(8) :: w ! z-component of direction real(8) :: norm ! "norm" of surface normal - real(8) :: d ! distance between point and plane real(8) :: xyz(3) ! Saved global coordinate integer :: i_surface ! index in surfaces logical :: rotational ! if rotational periodic BC applied @@ -412,64 +411,8 @@ contains p % coord(1) % xyz = xyz end if - rotational = .false. - select type (surf) - type is (SurfaceXPlane) - select type (opposite => surfaces(surf % i_periodic) % obj) - type is (SurfaceXPlane) - p % coord(1) % xyz(1) = opposite % x0 - type is (SurfaceYPlane) - rotational = .true. - - ! Rotate direction - u = p % coord(1) % uvw(1) - v = p % coord(1) % uvw(2) - p % coord(1) % uvw(1) = v - p % coord(1) % uvw(2) = -u - - ! Rotate position - p % coord(1) % xyz(1) = surf % x0 + p % coord(1) % xyz(2) - opposite % y0 - p % coord(1) % xyz(2) = opposite % y0 - end select - - type is (SurfaceYPlane) - select type (opposite => surfaces(surf % i_periodic) % obj) - type is (SurfaceYPlane) - p % coord(1) % xyz(2) = opposite % y0 - type is (SurfaceXPlane) - rotational = .true. - - ! Rotate direction - u = p % coord(1) % uvw(1) - v = p % coord(1) % uvw(2) - p % coord(1) % uvw(1) = -v - p % coord(1) % uvw(2) = u - - ! Rotate position - p % coord(1) % xyz(2) = surf % y0 + p % coord(1) % xyz(1) - opposite % x0 - p % coord(1) % xyz(1) = opposite % x0 - end select - - type is (SurfaceZPlane) - select type (opposite => surfaces(surf % i_periodic) % obj) - type is (SurfaceZPlane) - p % coord(1) % xyz(3) = opposite % z0 - end select - - type is (SurfacePlane) - select type (opposite => surfaces(surf % i_periodic) % obj) - type is (SurfacePlane) - ! Get surface normal for opposite plane - xyz(:) = opposite % normal(p % coord(1) % xyz) - - ! Determine distance to plane - norm = xyz(1)*xyz(1) + xyz(2)*xyz(2) + xyz(3)*xyz(3) - d = opposite % evaluate(p % coord(1) % xyz) / norm - - ! Move particle along normal vector based on distance - p % coord(1) % xyz(:) = p % coord(1) % xyz(:) - d*xyz - end select - end select + rotational = surface_periodic_c(i_surface-1, surf % i_periodic-1, & + p % coord(1) % xyz, p % coord(1) % uvw) ! Reassign particle's surface if (rotational) then From 7af296902bbb9ae7b0409eafb5060feacfb1d2ec Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 19 Jan 2018 01:27:04 -0500 Subject: [PATCH 12/21] Remove Fortran surface reflection code --- src/geometry.F90 | 15 ++- src/surface_header.C | 14 ++- src/surface_header.F90 | 226 +---------------------------------------- src/tracking.F90 | 5 +- 4 files changed, 26 insertions(+), 234 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index a0a19f1bf..c19a6c8dd 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -25,6 +25,15 @@ module geometry logical(C_BOOL) :: sense; end function surface_sense_c + pure subroutine surface_reflect_c(surf_ind, xyz, uvw) & + bind(C, name='surface_reflect') + use ISO_C_BINDING + implicit none + integer(C_INT), intent(in), value :: surf_ind; + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + end subroutine surface_reflect_c + pure function surface_distance_c(surf_ind, xyz, uvw, coincident) & bind(C, name='surface_distance') result(d) use ISO_C_BINDING @@ -525,6 +534,7 @@ contains real(8) :: d_surf ! distance to surface real(8) :: x0,y0,z0 ! coefficients for surface real(8) :: xyz_cross(3) ! coordinates at projected surface crossing + real(8) :: surf_uvw(3) ! surface normal direction logical :: coincident ! is particle on surface? type(Cell), pointer :: c class(Surface), pointer :: surf @@ -782,9 +792,8 @@ contains ! traveling into if the surface is crossed if (.not. c % simple) then xyz_cross(:) = p % coord(j) % xyz + d_surf*p % coord(j) % uvw - surf => surfaces(abs(level_surf_cross)) % obj - if (dot_product(p % coord(j) % uvw, & - surf % normal(xyz_cross)) > ZERO) then + call surface_normal_c(abs(level_surf_cross)-1, xyz_cross, surf_uvw) + if (dot_product(p % coord(j) % uvw, surf_uvw) > ZERO) then surface_crossed = abs(level_surf_cross) else surface_crossed = -abs(level_surf_cross) diff --git a/src/surface_header.C b/src/surface_header.C index 23fe5adb3..45fb62399 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -233,8 +233,8 @@ class SurfaceXPlane : public PeriodicSurface public: SurfaceXPlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - const bool coincident) const; + double distance(const double xyz[3], const double uvw[3], bool coincident) + const; void normal(const double xyz[3], double uvw[3]) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; @@ -416,8 +416,8 @@ class SurfacePlane : public PeriodicSurface public: SurfacePlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - const bool coincident) const; + double distance(const double xyz[3], const double uvw[3], bool coincident) + const; void normal(const double xyz[3], double uvw[3]) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; @@ -1138,6 +1138,12 @@ surface_sense(int surf_ind, double xyz[3], double uvw[3]) return surfaces_c[surf_ind]->sense(xyz, uvw); } +extern "C" void +surface_reflect(int surf_ind, double xyz[3], double uvw[3]) +{ + surfaces_c[surf_ind]->reflect(xyz, uvw); +} + extern "C" double surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) { diff --git a/src/surface_header.F90 b/src/surface_header.F90 index d9a00170b..d63290387 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -2,7 +2,7 @@ module surface_header use, intrinsic :: ISO_C_BINDING - use constants, only: NONE, ONE, TWO, ZERO, HALF, INFINITY, FP_COINCIDENT + use constants, only: NONE use dict_header, only: DictIntInt implicit none @@ -20,20 +20,8 @@ module surface_header integer :: bc ! Boundary condition integer :: i_periodic = NONE ! Index of corresponding periodic surface character(len=104) :: name = "" ! User-defined name - contains - procedure :: reflect - procedure(surface_normal_), deferred :: normal end type Surface - abstract interface - pure function surface_normal_(this, xyz) result(uvw) - import Surface - class(Surface), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: uvw(3) - end function surface_normal_ - end interface - !=============================================================================== ! SURFACECONTAINER allows us to store an array of different types of surfaces !=============================================================================== @@ -50,22 +38,16 @@ module surface_header type, extends(Surface) :: SurfaceXPlane ! x = x0 real(8) :: x0 - contains - procedure :: normal => x_plane_normal end type SurfaceXPlane type, extends(Surface) :: SurfaceYPlane ! y = y0 real(8) :: y0 - contains - procedure :: normal => y_plane_normal end type SurfaceYPlane type, extends(Surface) :: SurfaceZPlane ! z = z0 real(8) :: z0 - contains - procedure :: normal => z_plane_normal end type SurfaceZPlane type, extends(Surface) :: SurfacePlane @@ -74,8 +56,6 @@ module surface_header real(8) :: B real(8) :: C real(8) :: D - contains - procedure :: normal => plane_normal end type SurfacePlane type, extends(Surface) :: SurfaceXCylinder @@ -83,8 +63,6 @@ module surface_header real(8) :: y0 real(8) :: z0 real(8) :: r - contains - procedure :: normal => x_cylinder_normal end type SurfaceXCylinder type, extends(Surface) :: SurfaceYCylinder @@ -92,8 +70,6 @@ module surface_header real(8) :: x0 real(8) :: z0 real(8) :: r - contains - procedure :: normal => y_cylinder_normal end type SurfaceYCylinder type, extends(Surface) :: SurfaceZCylinder @@ -101,8 +77,6 @@ module surface_header real(8) :: x0 real(8) :: y0 real(8) :: r - contains - procedure :: normal => z_cylinder_normal end type SurfaceZCylinder type, extends(Surface) :: SurfaceSphere @@ -111,8 +85,6 @@ module surface_header real(8) :: y0 real(8) :: z0 real(8) :: r - contains - procedure :: normal => sphere_normal end type SurfaceSphere type, extends(Surface) :: SurfaceXCone @@ -121,8 +93,6 @@ module surface_header real(8) :: y0 real(8) :: z0 real(8) :: r2 - contains - procedure :: normal => x_cone_normal end type SurfaceXCone type, extends(Surface) :: SurfaceYCone @@ -131,8 +101,6 @@ module surface_header real(8) :: y0 real(8) :: z0 real(8) :: r2 - contains - procedure :: normal => y_cone_normal end type SurfaceYCone type, extends(Surface) :: SurfaceZCone @@ -141,15 +109,11 @@ module surface_header real(8) :: y0 real(8) :: z0 real(8) :: r2 - contains - procedure :: normal => z_cone_normal end type SurfaceZCone type, extends(Surface) :: SurfaceQuadric ! Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 real(8) :: A, B, C, D, E, F, G, H, J, K - contains - procedure :: normal => quadric_normal end type SurfaceQuadric integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces @@ -161,194 +125,6 @@ module surface_header contains -!=============================================================================== -! 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) - - 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 -!=============================================================================== - - 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(:) = [ONE, ZERO, ZERO] - end function x_plane_normal - -!=============================================================================== -! SurfaceYPlane Implementation -!=============================================================================== - - 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(:) = [ZERO, ONE, ZERO] - end function y_plane_normal - -!=============================================================================== -! SurfaceZPlane Implementation -!=============================================================================== - - 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(:) = [ZERO, ZERO, ONE] - end function z_plane_normal - -!=============================================================================== -! SurfacePlane Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceXCylinder Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceYCylinder Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceZCylinder Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceSphere Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceXCone Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceYCone Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceZCone Implementation -!=============================================================================== - - 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 - -!=============================================================================== -! SurfaceQuadric Implementation -!=============================================================================== - - pure function quadric_normal(this, xyz) result(uvw) - class(SurfaceQuadric), intent(in) :: this - real(8), intent(in) :: xyz(3) - real(8) :: uvw(3) - - associate (x => xyz(1), y => xyz(2), z => xyz(3)) - uvw(1) = TWO*this%A*x + this%D*y + this%F*z + this%G - uvw(2) = TWO*this%B*y + this%D*x + this%E*z + this%H - uvw(3) = TWO*this%C*z + this%E*y + this%F*x + this%J - end associate - end function quadric_normal - !=============================================================================== ! FREE_MEMORY_SURFACES deallocates global arrays defined in this module !=============================================================================== diff --git a/src/tracking.F90 b/src/tracking.F90 index 4f0f110bc..d616212ec 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -5,7 +5,8 @@ module tracking use error, only: fatal_error, warning, write_message use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice, & - check_cell_overlap, surface_periodic_c + check_cell_overlap, surface_reflect_c, & + surface_periodic_c use message_passing use mgxs_header use nuclide_header @@ -354,7 +355,7 @@ contains end if ! Reflect particle off surface - call surf%reflect(p%coord(1)%xyz, p%coord(1)%uvw) + call surface_reflect_c(i_surface-1, p%coord(1)%xyz, p%coord(1)%uvw) ! Make sure new particle direction is normalized u = p%coord(1)%uvw(1) From 57991b271db4828e8fbc92fbdf78b5892f83fb7d Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 19 Jan 2018 18:12:57 -0500 Subject: [PATCH 13/21] Start moving surface->summary.h5 to C++ --- CMakeLists.txt | 5 +- src/api.F90 | 2 +- src/cmfd_execute.F90 | 8 +- src/eigenvalue.F90 | 18 ++-- src/error.F90 | 4 +- src/geometry.F90 | 1 - src/hdf5_interface.F90 | 4 +- src/hdf5_interface.h | 47 ++++++++++ src/initialize.F90 | 12 +-- src/input_xml.F90 | 80 +++-------------- src/main.F90 | 8 +- src/mesh.F90 | 4 +- src/message_passing.F90 | 6 +- src/output.F90 | 2 +- src/simulation.F90 | 8 +- src/source.F90 | 2 +- src/state_point.F90 | 18 ++-- src/summary.F90 | 92 +++----------------- src/surface_header.C | 184 +++++++++++++++++++++++++++++++++++++++- src/surface_header.F90 | 45 ---------- src/tallies/tally.F90 | 4 +- src/tallies/trigger.F90 | 2 +- src/volume_calc.F90 | 6 +- 23 files changed, 311 insertions(+), 251 deletions(-) create mode 100644 src/hdf5_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 200d836fe..58fb55e79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,14 +48,14 @@ add_definitions(-DMAX_COORD=${maxcoord}) set(MPI_ENABLED FALSE) if($ENV{FC} MATCHES "(mpi[^/]*|ftn)$") message("-- Detected MPI wrapper: $ENV{FC}") - add_definitions(-DMPI) + add_definitions(-DOPENMC_MPI) set(MPI_ENABLED TRUE) endif() # Check for Fortran 2008 MPI interface if(MPI_ENABLED AND mpif08) message("-- Using Fortran 2008 MPI bindings") - add_definitions(-DMPIF08) + add_definitions(-DOPENMC_MPIF08) endif() #=============================================================================== @@ -435,6 +435,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/trigger_header.F90 ) set(LIBOPENMC_CXX_SRC + src/hdf5_interface.h src/random_lcg.h src/random_lcg.cpp src/surface_header.C diff --git a/src/api.F90 b/src/api.F90 index eb9a99695..5d56b857c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -171,7 +171,7 @@ contains ! Close FORTRAN interface. call h5close_f(err) -#ifdef MPI +#ifdef OPENMC_MPI ! Free all MPI types call MPI_TYPE_FREE(MPI_BANK, err) #endif diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 9cdb751a4..af8d57a80 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -105,7 +105,7 @@ contains real(8) :: hxyz(3) ! cell dimensions of current ijk cell real(8) :: vol ! volume of cell real(8),allocatable :: source(:,:,:,:) ! tmp source array for entropy -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif @@ -197,7 +197,7 @@ contains end if -#ifdef MPI +#ifdef OPENMC_MPI ! Broadcast full source to all procs call MPI_BCAST(cmfd % cmfd_src, n, MPI_REAL8, 0, mpi_intracomm, mpi_err) #endif @@ -234,7 +234,7 @@ contains real(8) :: norm ! normalization factor logical :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err #endif @@ -291,7 +291,7 @@ contains if (.not. cmfd_feedback) return ! Broadcast weight factors to all procs -#ifdef MPI +#ifdef OPENMC_MPI call MPI_BCAST(cmfd % weightfactors, ng*nx*ny*nz, MPI_REAL8, 0, & mpi_intracomm, mpi_err) #endif diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 27ae4063e..7a11d1fb4 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -42,11 +42,11 @@ contains type(Bank), save, allocatable :: & & temp_sites(:) ! local array of extra sites on each node -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code integer(8) :: n ! number of sites to send/recv integer :: neighbor ! processor to send/recv data from -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 type(MPI_Request) :: request(20) #else integer :: request(20) ! communication request for send/recving sites @@ -66,7 +66,7 @@ contains ! fission bank its own sites starts in order to ensure reproducibility by ! skipping ahead to the proper seed. -#ifdef MPI +#ifdef OPENMC_MPI start = 0_8 call MPI_EXSCAN(n_bank, start, 1, MPI_INTEGER8, MPI_SUM, & mpi_intracomm, mpi_err) @@ -148,7 +148,7 @@ contains ! neighboring processors, we have to perform an ALLGATHER to determine the ! indices for all processors -#ifdef MPI +#ifdef OPENMC_MPI ! First do an exclusive scan to get the starting indices for start = 0_8 call MPI_EXSCAN(index_temp, start, 1, MPI_INTEGER8, MPI_SUM, & @@ -191,7 +191,7 @@ contains call time_bank_sample % stop() call time_bank_sendrecv % start() -#ifdef MPI +#ifdef OPENMC_MPI ! ========================================================================== ! SEND BANK SITES TO NEIGHBORS @@ -343,14 +343,14 @@ contains subroutine calculate_generation_keff() real(8) :: keff_reduced -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif ! Get keff for this generation by subtracting off the starting value keff_generation = global_tallies(RESULT_VALUE, K_TRACKLENGTH) - keff_generation -#ifdef MPI +#ifdef OPENMC_MPI ! Combine values across all processors call MPI_ALLREDUCE(keff_generation, keff_reduced, 1, MPI_REAL8, & MPI_SUM, mpi_intracomm, mpi_err) @@ -584,7 +584,7 @@ contains real(8) :: total ! total weight in source bank logical :: sites_outside ! were there sites outside the ufs mesh? -#ifdef MPI +#ifdef OPENMC_MPI integer :: n ! total number of ufs mesh cells integer :: mpi_err ! MPI error code #endif @@ -608,7 +608,7 @@ contains call fatal_error("Source sites outside of the UFS mesh!") end if -#ifdef MPI +#ifdef OPENMC_MPI ! Send source fraction to all processors n = product(m % dimension) call MPI_BCAST(source_frac, n, MPI_REAL8, 0, mpi_intracomm, mpi_err) diff --git a/src/error.F90 b/src/error.F90 index 27004d729..ae02e0897 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -128,7 +128,7 @@ contains integer :: line_wrap ! length of line integer :: length ! length of message integer :: indent ! length of indentation -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err #endif @@ -180,7 +180,7 @@ contains end if end do -#ifdef MPI +#ifdef OPENMC_MPI ! Abort MPI call MPI_ABORT(mpi_intracomm, code, mpi_err) #endif diff --git a/src/geometry.F90 b/src/geometry.F90 index c19a6c8dd..f1feb3ba3 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -537,7 +537,6 @@ contains real(8) :: surf_uvw(3) ! surface normal direction logical :: coincident ! is particle on surface? type(Cell), pointer :: c - class(Surface), pointer :: surf class(Lattice), pointer :: lat ! inialize distance to infinity (huge) diff --git a/src/hdf5_interface.F90 b/src/hdf5_interface.F90 index e8c39b923..410149d9e 100644 --- a/src/hdf5_interface.F90 +++ b/src/hdf5_interface.F90 @@ -124,7 +124,7 @@ contains ! Setup file access property list with parallel I/O access call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) #ifdef PHDF5 -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 call h5pset_fapl_mpio_f(plist, mpi_intracomm%MPI_VAL, & MPI_INFO_NULL%MPI_VAL, hdf5_err) #else @@ -174,7 +174,7 @@ contains ! Setup file access property list with parallel I/O access call h5pcreate_f(H5P_FILE_ACCESS_F, plist, hdf5_err) #ifdef PHDF5 -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 call h5pset_fapl_mpio_f(plist, mpi_intracomm%MPI_VAL, & MPI_INFO_NULL%MPI_VAL, hdf5_err) #else diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h new file mode 100644 index 000000000..38bb7d88b --- /dev/null +++ b/src/hdf5_interface.h @@ -0,0 +1,47 @@ +#ifndef HDF5_INTERFACE_H +#define HDF5_INTERFACE_H + +#include // For std::array +#include // For strlen + +#include "hdf5.h" + + +template void +write_double_1D(hid_t group_id, char const *name, + std::array &buffer) +{ + hsize_t dims[1]{array_len}; + hid_t dataspace = H5Screate_simple(1, dims, NULL); + + hid_t dataset = H5Dcreate(group_id, name, H5T_NATIVE_DOUBLE, dataspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + H5Dwrite(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + &buffer[0]); + + H5Sclose(dataspace); + H5Dclose(dataset); +} + + +void +write_string(hid_t group_id, char const *name, char const *buffer) +{ + size_t buffer_len = strlen(buffer); + hid_t datatype = H5Tcopy(H5T_C_S1); + H5Tset_size(datatype, buffer_len); + + hid_t dataspace = H5Screate(H5S_SCALAR); + + hid_t dataset = H5Dcreate(group_id, name, datatype, dataspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + H5Dwrite(dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); + + H5Tclose(datatype); + H5Sclose(dataspace); + H5Dclose(dataset); +} + +#endif //HDF5_INTERFACE_H diff --git a/src/initialize.F90 b/src/initialize.F90 index dd7894f96..2af93627e 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -52,8 +52,8 @@ contains ! Copy the communicator to a new variable. This is done to avoid changing ! the signature of this subroutine. If MPI is being used but no communicator ! was passed, assume MPI_COMM_WORLD. -#ifdef MPI -#ifdef MPIF08 +#ifdef OPENMC_MPI +#ifdef OPENMC_MPIF08 type(MPI_Comm), intent(in) :: comm ! MPI intracommunicator if (present(intracomm)) then comm % MPI_VAL = intracomm @@ -74,7 +74,7 @@ contains call time_total%start() call time_initialize%start() -#ifdef MPI +#ifdef OPENMC_MPI ! Setup MPI call initialize_mpi(comm) #endif @@ -108,7 +108,7 @@ contains end subroutine openmc_init -#ifdef MPI +#ifdef OPENMC_MPI !=============================================================================== ! INITIALIZE_MPI starts up the Message Passing Interface (MPI) and determines ! the number of processors the problem is being run with as well as the rank of @@ -116,7 +116,7 @@ contains !=============================================================================== subroutine initialize_mpi(intracomm) -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 type(MPI_Comm), intent(in) :: intracomm ! MPI intracommunicator #else integer, intent(in) :: intracomm ! MPI intracommunicator @@ -124,7 +124,7 @@ contains integer :: mpi_err ! MPI error code integer :: bank_blocks(5) ! Count for each datatype -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 type(MPI_Datatype) :: bank_types(5) #else integer :: bank_types(5) ! Datatypes diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 4994ff76b..462b9708f 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -54,7 +54,7 @@ module input_xml implicit none type(C_PTR) :: node_ptr end subroutine read_surfaces - end interface + end interface contains @@ -1081,77 +1081,23 @@ contains select type(s) type is (SurfaceXPlane) - s%x0 = coeffs(1) - ! Determine outer surfaces - xmin = min(xmin, s % x0) - xmax = max(xmax, s % x0) - if (xmin == s % x0) i_xmin = i - if (xmax == s % x0) i_xmax = i + xmin = min(xmin, coeffs(1)) + xmax = max(xmax, coeffs(1)) + if (xmin == coeffs(1)) i_xmin = i + if (xmax == coeffs(1)) i_xmax = i type is (SurfaceYPlane) - s%y0 = coeffs(1) - ! Determine outer surfaces - ymin = min(ymin, s % y0) - ymax = max(ymax, s % y0) - if (ymin == s % y0) i_ymin = i - if (ymax == s % y0) i_ymax = i + ymin = min(ymin, coeffs(1)) + ymax = max(ymax, coeffs(1)) + if (ymin == coeffs(1)) i_ymin = i + if (ymax == coeffs(1)) i_ymax = i type is (SurfaceZPlane) - s%z0 = coeffs(1) - ! Determine outer surfaces - zmin = min(zmin, s % z0) - zmax = max(zmax, s % z0) - if (zmin == s % z0) i_zmin = i - if (zmax == s % z0) i_zmax = i - type is (SurfacePlane) - s%A = coeffs(1) - s%B = coeffs(2) - s%C = coeffs(3) - s%D = coeffs(4) - type is (SurfaceXCylinder) - s%y0 = coeffs(1) - s%z0 = coeffs(2) - s%r = coeffs(3) - type is (SurfaceYCylinder) - s%x0 = coeffs(1) - s%z0 = coeffs(2) - s%r = coeffs(3) - type is (SurfaceZCylinder) - s%x0 = coeffs(1) - s%y0 = coeffs(2) - s%r = coeffs(3) - type is (SurfaceSphere) - s%x0 = coeffs(1) - s%y0 = coeffs(2) - s%z0 = coeffs(3) - s%r = coeffs(4) - type is (SurfaceXCone) - s%x0 = coeffs(1) - s%y0 = coeffs(2) - s%z0 = coeffs(3) - s%r2 = coeffs(4) - type is (SurfaceYCone) - s%x0 = coeffs(1) - s%y0 = coeffs(2) - s%z0 = coeffs(3) - s%r2 = coeffs(4) - type is (SurfaceZCone) - s%x0 = coeffs(1) - s%y0 = coeffs(2) - s%z0 = coeffs(3) - s%r2 = coeffs(4) - type is (SurfaceQuadric) - s%A = coeffs(1) - s%B = coeffs(2) - s%C = coeffs(3) - s%D = coeffs(4) - s%E = coeffs(5) - s%F = coeffs(6) - s%G = coeffs(7) - s%H = coeffs(8) - s%J = coeffs(9) - s%K = coeffs(10) + zmin = min(zmin, coeffs(1)) + zmax = max(zmax, coeffs(1)) + if (zmin == coeffs(1)) i_zmin = i + if (zmax == coeffs(1)) i_zmax = i end select ! No longer need coefficients diff --git a/src/main.F90 b/src/main.F90 index d8e52643c..120bdd1e0 100644 --- a/src/main.F90 +++ b/src/main.F90 @@ -9,13 +9,13 @@ program main implicit none -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif ! Initialize run -- when run with MPI, pass communicator -#ifdef MPI -#ifdef MPIF08 +#ifdef OPENMC_MPI +#ifdef OPENMC_MPIF08 call openmc_init(MPI_COMM_WORLD % MPI_VAL) #else call openmc_init(MPI_COMM_WORLD) @@ -39,7 +39,7 @@ program main ! finalize run call openmc_finalize() -#ifdef MPI +#ifdef OPENMC_MPI ! If MPI is in use and enabled, terminate it call MPI_FINALIZE(mpi_err) #endif diff --git a/src/mesh.F90 b/src/mesh.F90 index e997890a4..790dc7d88 100644 --- a/src/mesh.F90 +++ b/src/mesh.F90 @@ -34,7 +34,7 @@ contains integer :: n ! number of energy groups / size integer :: mesh_bin ! mesh bin integer :: e_bin ! energy bin -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif logical :: outside ! was any site outside mesh? @@ -86,7 +86,7 @@ contains cnt_(e_bin, mesh_bin) = cnt_(e_bin, mesh_bin) + bank_array(i) % wgt end do FISSION_SITES -#ifdef MPI +#ifdef OPENMC_MPI ! collect values from all processors n = size(cnt_) call MPI_REDUCE(cnt_, cnt, n, MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err) diff --git a/src/message_passing.F90 b/src/message_passing.F90 index 0f2b94d1a..7391a632c 100644 --- a/src/message_passing.F90 +++ b/src/message_passing.F90 @@ -1,7 +1,7 @@ module message_passing -#ifdef MPI -#ifdef MPIF08 +#ifdef OPENMC_MPI +#ifdef OPENMC_MPIF08 use mpi_f08 #else use mpi @@ -16,7 +16,7 @@ module message_passing integer :: rank = 0 ! rank of process logical :: master = .true. ! master process? logical :: mpi_enabled = .false. ! is MPI in use and initialized? -#ifdef MPIF08 +#ifdef OPENMC_MPIF08 type(MPI_Datatype) :: MPI_BANK ! MPI datatype for fission bank type(MPI_Comm) :: mpi_intracomm ! MPI intra-communicator #else diff --git a/src/output.F90 b/src/output.F90 index 9a144721d..1b7cae121 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -88,7 +88,7 @@ contains ! Write the date and time write(UNIT=OUTPUT_UNIT, FMT='(9X,"Date/Time | ",A)') time_stamp() -#ifdef MPI +#ifdef OPENMC_MPI ! Write number of processors write(UNIT=OUTPUT_UNIT, FMT='(5X,"MPI Processes | ",A)') & trim(to_str(n_procs)) diff --git a/src/simulation.F90 b/src/simulation.F90 index ef29e7832..24e9b29fc 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -320,7 +320,7 @@ contains subroutine finalize_batch() -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code #endif @@ -342,7 +342,7 @@ contains ! Check_triggers if (master) call check_triggers() -#ifdef MPI +#ifdef OPENMC_MPI call MPI_BCAST(satisfy_triggers, 1, MPI_LOGICAL, 0, & mpi_intracomm, mpi_err) #endif @@ -469,7 +469,7 @@ contains subroutine openmc_simulation_finalize() bind(C) integer :: i ! loop index -#ifdef MPI +#ifdef OPENMC_MPI integer :: n ! size of arrays integer :: mpi_err ! MPI error code integer(8) :: temp @@ -494,7 +494,7 @@ contains ! Increment total number of generations total_gen = total_gen + current_batch*gen_per_batch -#ifdef MPI +#ifdef OPENMC_MPI ! Broadcast tally results so that each process has access to results if (allocated(tallies)) then do i = 1, size(tallies) diff --git a/src/source.F90 b/src/source.F90 index 557120e97..5beecd887 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -1,7 +1,7 @@ module source use hdf5, only: HID_T -#ifdef MPI +#ifdef OPENMC_MPI use message_passing #endif diff --git a/src/state_point.F90 b/src/state_point.F90 index f7a892898..ba7bcef19 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -523,7 +523,7 @@ contains integer(HID_T) :: tallies_group, tally_group real(8), allocatable :: tally_temp(:,:,:) ! contiguous array of results real(8), target :: global_temp(3,N_GLOBAL_TALLIES) -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code real(8) :: dummy ! temporary receive buffer for non-root reduces #endif @@ -543,7 +543,7 @@ contains end if -#ifdef MPI +#ifdef OPENMC_MPI ! Reduce global tallies n_bins = size(global_tallies) call MPI_REDUCE(global_tallies, global_temp, n_bins, MPI_REAL8, MPI_SUM, & @@ -586,7 +586,7 @@ contains ! The MPI_IN_PLACE specifier allows the master to copy values into ! a receive buffer without having a temporary variable -#ifdef MPI +#ifdef OPENMC_MPI call MPI_REDUCE(MPI_IN_PLACE, tally_temp, n_bins, MPI_REAL8, & MPI_SUM, 0, mpi_intracomm, mpi_err) #endif @@ -610,7 +610,7 @@ contains deallocate(dummy_tally % results) else ! Receive buffer not significant at other processors -#ifdef MPI +#ifdef OPENMC_MPI call MPI_REDUCE(tally_temp, dummy, n_bins, MPI_REAL8, MPI_SUM, & 0, mpi_intracomm, mpi_err) #endif @@ -849,7 +849,7 @@ contains integer(HID_T) :: plist ! property list #else integer :: i -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code type(Bank), allocatable, target :: temp_source(:) #endif @@ -897,7 +897,7 @@ contains dspace, dset, hdf5_err) ! Save source bank sites since the souce_bank array is overwritten below -#ifdef MPI +#ifdef OPENMC_MPI allocate(temp_source(work)) temp_source(:) = source_bank(:) #endif @@ -907,7 +907,7 @@ contains dims(1) = work_index(i+1) - work_index(i) call h5screate_simple_f(1, dims, memspace, hdf5_err) -#ifdef MPI +#ifdef OPENMC_MPI ! Receive source sites from other processes if (i > 0) then call MPI_RECV(source_bank, int(dims(1)), MPI_BANK, i, i, & @@ -933,12 +933,12 @@ contains call h5dclose_f(dset, hdf5_err) ! Restore state of source bank -#ifdef MPI +#ifdef OPENMC_MPI source_bank(:) = temp_source(:) deallocate(temp_source) #endif else -#ifdef MPI +#ifdef OPENMC_MPI call MPI_SEND(source_bank, int(work), MPI_BANK, 0, rank, & mpi_intracomm, mpi_err) #endif diff --git a/src/summary.F90 b/src/summary.F90 index 0f45ef1bb..ca7276407 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -24,6 +24,17 @@ module summary public :: write_summary + interface + subroutine surface_to_hdf5_c(surf_ind, group) & + bind(C, name='surface_to_hdf5') + use ISO_C_BINDING + use hdf5 + implicit none + integer(C_INT), intent(in), value :: surf_ind + integer(HID_T), intent(in), value :: group + end subroutine surface_to_hdf5_c + end interface + contains !=============================================================================== @@ -125,7 +136,6 @@ 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(:) character(:), allocatable :: region_spec type(Cell), pointer :: c class(Surface), pointer :: s @@ -245,87 +255,11 @@ contains surface_group = create_group(surfaces_group, "surface " // & trim(to_str(s%id))) + call surface_to_hdf5_c(i-1, surface_group) + ! Write name for this surface call write_dataset(surface_group, "name", s%name) - ! Write surface type - select type (s) - type is (SurfaceXPlane) - call write_dataset(surface_group, "type", "x-plane") - allocate(coeffs(1)) - coeffs(1) = s%x0 - - 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] - - type is (SurfaceQuadric) - call write_dataset(surface_group, "type", "quadric") - allocate(coeffs(10)) - coeffs(:) = [s%A, s%B, s%C, s%D, s%E, s%F, s%G, s%H, s%J, s%K] - - end select - call write_dataset(surface_group, "coefficients", coeffs) - deallocate(coeffs) - - ! Write boundary type - select case (s%bc) - case (BC_TRANSMIT) - call write_dataset(surface_group, "boundary_type", "transmission") - case (BC_VACUUM) - call write_dataset(surface_group, "boundary_type", "vacuum") - case (BC_REFLECT) - call write_dataset(surface_group, "boundary_type", "reflective") - case (BC_PERIODIC) - call write_dataset(surface_group, "boundary_type", "periodic") - end select - call close_group(surface_group) end do SURFACE_LOOP diff --git a/src/surface_header.C b/src/surface_header.C index 45fb62399..db53c8982 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -1,8 +1,12 @@ +#include // For std::array #include // For strcmp #include // For numeric_limits #include // For fabs #include "pugixml/pugixml.hpp" +#include "hdf5.h" + +#include "hdf5_interface.h" // DEBUGGING #include @@ -15,6 +19,11 @@ const double FP_COINCIDENT = 1e-12; const double INFTY = std::numeric_limits::max(); +const int BC_TRANSMIT{0}; +const int BC_VACUUM{1}; +const int BC_REFLECT{2}; +const int BC_PERIODIC{3}; + //============================================================================== // Global array of surfaces //============================================================================== @@ -127,6 +136,13 @@ public: //! @param xyz[3] A 3D Cartesian coordinate. //! @param uvw[3] This output argument provides the normal. virtual void normal(const double xyz[3], double uvw[3]) const = 0; + + //! Write all information needed to reconstruct the surface to an HDF5 group. + //! @param group_id An HDF5 group id. + virtual void to_hdf5(hid_t group_id) const = 0; + +protected: + void write_bc_to_hdf5(hid_t group_id) const; }; bool @@ -164,6 +180,25 @@ Surface::reflect(const double xyz[3], double uvw[3]) const uvw[2] -= 2.0 * projection / magnitude * norm[2]; } +void +Surface::write_bc_to_hdf5(hid_t group_id) const +{ + switch(bc) { + case BC_TRANSMIT : + write_string(group_id, "boundary_type", "transmission"); + break; + case BC_VACUUM : + write_string(group_id, "boundary_type", "vacuum"); + break; + case BC_REFLECT : + write_string(group_id, "boundary_type", "reflective"); + break; + case BC_PERIODIC : + write_string(group_id, "boundary_type", "periodic"); + break; + } +} + //============================================================================== //! A `Surface` that supports periodic boundary conditions. //! @@ -236,6 +271,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; @@ -261,6 +297,14 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); } +void SurfaceXPlane::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "x-plane"); + std::array coeffs{{x0}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const { @@ -285,7 +329,7 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], return true; } -}; +} //============================================================================== // SurfaceYPlane @@ -303,6 +347,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; @@ -328,6 +373,14 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); } +void SurfaceYPlane::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "y-plane"); + std::array coeffs{{y0}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const { @@ -352,7 +405,7 @@ bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], return true; } -}; +} //============================================================================== // SurfaceZPlane @@ -370,6 +423,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; @@ -395,13 +449,21 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); } +void SurfaceZPlane::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "z-plane"); + std::array coeffs{{z0}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const { // Assume the other plane is aligned along z. Just change the z coord. xyz[2] = z0; return false; -}; +} //============================================================================== // SurfacePlane @@ -419,6 +481,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; @@ -457,6 +520,14 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const uvw[2] = C; } +void SurfacePlane::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "plane"); + std::array coeffs{{A, B, C, D}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const { @@ -564,6 +635,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) @@ -588,6 +660,15 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const axis_aligned_cylinder_normal<0, 1, 2>(xyz, uvw, y0, z0); } + +void SurfaceXCylinder::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "x-cylinder"); + std::array coeffs{{y0, z0, r}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceYCylinder //! A cylinder aligned along the y-axis. @@ -605,6 +686,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) @@ -629,6 +711,14 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, x0, z0); } +void SurfaceYCylinder::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "y-cylinder"); + std::array coeffs{{x0, z0, r}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceZCylinder //! A cylinder aligned along the z-axis. @@ -646,6 +736,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) @@ -670,6 +761,14 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); } +void SurfaceZCylinder::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "z-cylinder"); + std::array coeffs{{x0, y0, r}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceSphere //! A sphere. @@ -687,6 +786,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) @@ -748,6 +848,14 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const uvw[2] = 2.0 * (xyz[2] - z0); } +void SurfaceSphere::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "sphere"); + std::array coeffs{{x0, y0, z0, r}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // Generic functions for x-, y-, and z-, cones //============================================================================== @@ -848,6 +956,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) @@ -872,6 +981,14 @@ inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_sq); } +void SurfaceXCone::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "x-cone"); + std::array coeffs{{x0, y0, z0, r_sq}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceYCone //! A cone aligned along the y-axis. @@ -889,6 +1006,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) @@ -913,6 +1031,14 @@ inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_sq); } +void SurfaceYCone::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "y-cone"); + std::array coeffs{{x0, y0, z0, r_sq}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceZCone //! A cone aligned along the z-axis. @@ -930,6 +1056,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) @@ -954,6 +1081,14 @@ inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_sq); } +void SurfaceZCone::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "z-cone"); + std::array coeffs{{x0, y0, z0, r_sq}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== // SurfaceQuadric //! A general surface described by a quadratic equation. @@ -971,6 +1106,7 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5(hid_t group_id) const; }; SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) @@ -1055,6 +1191,14 @@ SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const uvw[2] = 2.0*C*z + E*y + F*x + J; } +void SurfaceQuadric::to_hdf5(hid_t group_id) const +{ + write_string(group_id, "type", "quadric"); + std::array coeffs{{A, B, C, D, E, F, G, H, J, K}}; + write_double_1D(group_id, "coefficients", coeffs); + write_bc_to_hdf5(group_id); +} + //============================================================================== extern "C" void @@ -1084,6 +1228,7 @@ read_surfaces(pugi::xml_node *node) } else { std::cout << "ERROR: Found a surface with no type attribute/node" << std::endl; + //TODO: call fatal_error } if (strcmp(surf_type, "x-plane") == 0) { @@ -1125,6 +1270,33 @@ read_surfaces(pugi::xml_node *node) } else { std::cout << "Call error or handle uppercase here!" << std::endl; std::cout << surf_type << std::endl; + //TODO: call fatal_error + } + + const pugi::char_t *surf_bc{""}; + if (surf_node.attribute("boundary")) { + surf_bc = surf_node.attribute("boundary").value(); + } else if (surf_node.child("boundary")) { + surf_bc = surf_node.attribute("boundary").value(); + } + + if (strcmp(surf_bc, "transmission") == 0 + or strcmp(surf_bc, "transmit") == 0 + or strcmp(surf_bc, "") == 0) { + surfaces_c[i_surf]->bc = BC_TRANSMIT; + + } else if (strcmp(surf_bc, "vacuum") == 0) { + surfaces_c[i_surf]->bc = BC_VACUUM; + + } else if (strcmp(surf_bc, "reflective") == 0 + or strcmp(surf_bc, "reflect") == 0 + or strcmp(surf_bc, "reflecting") == 0) { + surfaces_c[i_surf]->bc = BC_REFLECT; + } else if (strcmp(surf_bc, "periodic") == 0) { + surfaces_c[i_surf]->bc = BC_PERIODIC; + } else { + std::cout << "Unknown boundary condition" << std::endl; + //TODO: call fatal_error } } } @@ -1156,6 +1328,12 @@ surface_normal(int surf_ind, double xyz[3], double uvw[3]) return surfaces_c[surf_ind]->normal(xyz, uvw); } +extern "C" void +surface_to_hdf5(int surf_ind, hid_t group) +{ + surfaces_c[surf_ind]->to_hdf5(group); +} + extern "C" bool surface_periodic(int surf_ind1, int surf_ind2, double xyz[3], double uvw[3]) { diff --git a/src/surface_header.F90 b/src/surface_header.F90 index d63290387..98e2423b6 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -36,84 +36,39 @@ module surface_header !=============================================================================== type, extends(Surface) :: SurfaceXPlane - ! x = x0 - real(8) :: x0 end type SurfaceXPlane type, extends(Surface) :: SurfaceYPlane - ! y = y0 - real(8) :: y0 end type SurfaceYPlane type, extends(Surface) :: SurfaceZPlane - ! z = z0 - real(8) :: z0 end type SurfaceZPlane type, extends(Surface) :: SurfacePlane - ! Ax + By + Cz = D - real(8) :: A - real(8) :: B - real(8) :: C - real(8) :: D end type SurfacePlane type, extends(Surface) :: SurfaceXCylinder - ! (y - y0)^2 + (z - z0)^2 = R^2 - real(8) :: y0 - real(8) :: z0 - real(8) :: r end type SurfaceXCylinder type, extends(Surface) :: SurfaceYCylinder - ! (x - x0)^2 + (z - z0)^2 = R^2 - real(8) :: x0 - real(8) :: z0 - real(8) :: r end type SurfaceYCylinder type, extends(Surface) :: SurfaceZCylinder - ! (x - x0)^2 + (y - y0)^2 = R^2 - real(8) :: x0 - real(8) :: y0 - real(8) :: r 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 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 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 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 end type SurfaceZCone type, extends(Surface) :: SurfaceQuadric - ! Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 - real(8) :: A, B, C, D, E, F, G, H, J, K end type SurfaceQuadric integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 7684a36aa..7c234f173 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -4241,7 +4241,7 @@ contains real(C_DOUBLE) :: k_tra ! Copy of batch tracklength estimate of keff real(C_DOUBLE) :: val -#ifdef MPI +#ifdef OPENMC_MPI ! Combine tally results onto master process if (reduce_tallies) call reduce_tally_results() #endif @@ -4289,7 +4289,7 @@ contains ! REDUCE_TALLY_RESULTS collects all the results from tallies onto one processor !=============================================================================== -#ifdef MPI +#ifdef OPENMC_MPI subroutine reduce_tally_results() integer :: i diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 9e9b06d20..ee2259ed4 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -2,7 +2,7 @@ module trigger use, intrinsic :: ISO_C_BINDING -#ifdef MPI +#ifdef OPENMC_MPI use message_passing #endif diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index 5985a236b..07dc5b418 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -136,7 +136,7 @@ contains integer :: total_hits ! total hits for a single domain (summed over materials) integer :: min_samples ! minimum number of samples per process integer :: remainder ! leftover samples from uneven divide -#ifdef MPI +#ifdef OPENMC_MPI integer :: mpi_err ! MPI error code integer :: m ! index over materials integer :: n ! number of materials @@ -279,7 +279,7 @@ contains total_hits = 0 if (master) then -#ifdef MPI +#ifdef OPENMC_MPI do j = 1, n_procs - 1 call MPI_RECV(n, 1, MPI_INTEGER, j, 0, mpi_intracomm, & MPI_STATUS_IGNORE, mpi_err) @@ -341,7 +341,7 @@ contains end do else -#ifdef MPI +#ifdef OPENMC_MPI n = master_indices(i_domain) % size() allocate(data(2*n)) do k = 0, n - 1 From 7624888df34577b9ed735039ff5b33bab8c0e44c Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 23 Jan 2018 12:37:28 -0500 Subject: [PATCH 14/21] Finish C++ surface->summary.h5 capability --- CMakeLists.txt | 1 + src/constants.F90 | 15 ++- src/error.F90 | 8 ++ src/error.h | 21 ++++ src/hdf5_interface.h | 44 +++++++- src/summary.F90 | 11 +- src/surface_header.C | 263 +++++++++++++++++++++++++++---------------- 7 files changed, 243 insertions(+), 120 deletions(-) create mode 100644 src/error.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 58fb55e79..e59713755 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,6 +435,7 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/trigger_header.F90 ) set(LIBOPENMC_CXX_SRC + src/error.h src/hdf5_interface.h src/random_lcg.h src/random_lcg.cpp diff --git a/src/constants.F90 b/src/constants.F90 index 331a644f0..3334a4cc7 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -43,9 +43,9 @@ module constants real(8), parameter :: TINY_BIT = 1e-8_8 ! User for precision in geometry - real(8), parameter :: FP_PRECISION = 1e-14_8 - real(8), parameter :: FP_REL_PRECISION = 1e-5_8 - real(8), parameter :: FP_COINCIDENT = 1e-12_8 + real(C_DOUBLE), bind(C, name='FP_PRECISION') :: FP_PRECISION = 1e-14_8 + real(C_DOUBLE), bind(C, name='FP_REL_PRECISION') :: FP_REL_PRECISION = 1e-5_8 + real(C_DOUBLE), bind(C, name='FP_COINCIDENT') :: FP_COINCIDENT = 1e-12_8 ! Maximum number of collisions/crossings integer, parameter :: MAX_EVENTS = 1000000 @@ -95,11 +95,10 @@ module constants ! GEOMETRY-RELATED CONSTANTS ! Boundary conditions - integer, parameter :: & - BC_TRANSMIT = 0, & ! Transmission boundary condition (default) - BC_VACUUM = 1, & ! Vacuum boundary condition - BC_REFLECT = 2, & ! Reflecting boundary condition - BC_PERIODIC = 3 ! Periodic boundary condition + integer(C_INT), bind(C, name="BC_TRANSMIT") :: BC_TRANSMIT + integer(C_INT), bind(C, name="BC_VACUUM") :: BC_VACUUM + integer(C_INT), bind(C, name="BC_REFLECT") :: BC_REFLECT + integer(C_INT), bind(C, name="BC_PERIODIC") :: BC_PERIODIC ! Logical operators for cell definitions integer, parameter :: & diff --git a/src/error.F90 b/src/error.F90 index ae02e0897..cba137291 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -194,6 +194,14 @@ contains end subroutine fatal_error + subroutine fatal_error_from_c(message, message_len) bind(C) + integer(C_INT), intent(in), value :: message_len + character(C_CHAR), intent(in) :: message(message_len) + character(message_len+1) :: message_out + write(message_out, *) message + call fatal_error(message_out) + end subroutine + !=============================================================================== ! WRITE_MESSAGE displays an informational message to the log file and the ! standard output stream. diff --git a/src/error.h b/src/error.h new file mode 100644 index 000000000..77f0252e1 --- /dev/null +++ b/src/error.h @@ -0,0 +1,21 @@ +#ifndef ERROR_H +#define ERROR_H + +#include + + +extern "C" void fatal_error_from_c(const char *message, int message_len); + + +void fatal_error(const char *message) +{ + fatal_error_from_c(message, strlen(message)); +} + + +void fatal_error(const std::string &message) +{ + fatal_error_from_c(message.c_str(), message.length()); +} + +#endif // ERROR_H diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 38bb7d88b..2cded21f6 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -1,11 +1,44 @@ #ifndef HDF5_INTERFACE_H #define HDF5_INTERFACE_H -#include // For std::array -#include // For strlen +#include +#include #include "hdf5.h" +#include "error.h" + + +hid_t +create_group(hid_t parent_id, char const *name) +{ + hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (out < 0) { + std::string err_msg{"Failed to create HDF5 group \""}; + err_msg += name; + err_msg += "\""; + fatal_error(err_msg); + } + return out; +} + + +hid_t +create_group(hid_t parent_id, const std::string &name) +{ + return create_group(parent_id, name.c_str()); +} + + +void +close_group(hid_t group_id) +{ + herr_t err = H5Gclose(group_id); + if (err < 0) { + fatal_error("Failed to close HDF5 group"); + } +} + template void write_double_1D(hid_t group_id, char const *name, @@ -44,4 +77,11 @@ write_string(hid_t group_id, char const *name, char const *buffer) H5Dclose(dataset); } + +void +write_string(hid_t group_id, char const *name, const std::string &buffer) +{ + write_string(group_id, name, buffer.c_str()); +} + #endif //HDF5_INTERFACE_H diff --git a/src/summary.F90 b/src/summary.F90 index ca7276407..77bded983 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -251,16 +251,7 @@ contains ! Write information on each surface SURFACE_LOOP: do i = 1, n_surfaces - s => surfaces(i)%obj - surface_group = create_group(surfaces_group, "surface " // & - trim(to_str(s%id))) - - call surface_to_hdf5_c(i-1, surface_group) - - ! Write name for this surface - call write_dataset(surface_group, "name", s%name) - - call close_group(surface_group) + call surface_to_hdf5_c(i-1, surfaces_group) end do SURFACE_LOOP call close_group(surfaces_group) diff --git a/src/surface_header.C b/src/surface_header.C index db53c8982..4cfda86ef 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -1,3 +1,4 @@ +#include // for std::transform #include // For std::array #include // For strcmp #include // For numeric_limits @@ -6,23 +7,61 @@ #include "pugixml/pugixml.hpp" #include "hdf5.h" +#include "error.h" #include "hdf5_interface.h" // DEBUGGING #include #include +bool +check_for_node(const pugi::xml_node &node, const char *name) +{ + if (node.attribute(name)) { + return true; + } else if (node.child(name)) { + return true; + } else { + return false; + } +} + +std::string +get_node_value(const pugi::xml_node &node, const char *name) +{ + const pugi::char_t *value_char; + if (node.attribute(name)) { + value_char = node.attribute(name).value(); + } else if (node.child(name)) { + value_char = node.child_value(name); + } else { + std::string err_msg("Node \""); + err_msg += name; + err_msg += "\" is not a memeber of the \""; + err_msg += node.name(); + err_msg += "\" XML node"; + fatal_error(err_msg); + } + + std::string value(value_char); + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + return value; +} + //============================================================================== // Constants //============================================================================== -const double FP_COINCIDENT = 1e-12; -const double INFTY = std::numeric_limits::max(); +//extern "C" const double FP_COINCIDENT{1e-12}; +//extern "C" const double INFTY{std::numeric_limits::max()}; +extern "C" double FP_COINCIDENT; +//extern "C" double INFTY; +const double INFTY{std::numeric_limits::max()}; -const int BC_TRANSMIT{0}; -const int BC_VACUUM{1}; -const int BC_REFLECT{2}; -const int BC_PERIODIC{3}; +extern "C" const int BC_TRANSMIT{0}; +extern "C" const int BC_VACUUM{1}; +extern "C" const int BC_REFLECT{2}; +extern "C" const int BC_PERIODIC{3}; //============================================================================== // Global array of surfaces @@ -95,12 +134,14 @@ class Surface { public: int id; //!< Unique ID - int neighbor_pos[], //!< List of cells on positive side - neighbor_neg[]; //!< List of cells on negative side + //int neighbor_pos[], //!< List of cells on positive side + // neighbor_neg[]; //!< List of cells on negative side int bc; //!< Boundary condition //TODO: switch that zero to a NONE constant. //int i_periodic = 0; //!< Index of corresponding periodic surface - char name[104]; //!< User-defined name + std::string name{""}; //!< User-defined name + + Surface(pugi::xml_node surf_node); //! Determine which side of a surface a point lies on. //! @param xyz[3] The 3D Cartesian coordinate of a point. @@ -139,12 +180,54 @@ public: //! Write all information needed to reconstruct the surface to an HDF5 group. //! @param group_id An HDF5 group id. - virtual void to_hdf5(hid_t group_id) const = 0; + void to_hdf5(hid_t group_id) const; protected: - void write_bc_to_hdf5(hid_t group_id) const; + virtual void to_hdf5_inner(hid_t group_id) const = 0; }; +Surface::Surface(pugi::xml_node surf_node) +{ + if (check_for_node(surf_node, "id")) { + id = stoi(get_node_value(surf_node, "id")); + } else { + fatal_error("Must specify id of surface in geometry XML file."); + } + //TODO: check for duplicate IDs + + if (check_for_node(surf_node, "name")) { + name = get_node_value(surf_node, "name"); + } + + if (check_for_node(surf_node, "boundary")) { + std::string surf_bc = get_node_value(surf_node, "boundary"); + + if (surf_bc.compare("transmission") == 0 + or surf_bc.compare("transmit") == 0 + or surf_bc.compare("") == 0) { + bc = BC_TRANSMIT; + + } else if (surf_bc.compare("vacuum") == 0) { + bc = BC_VACUUM; + + } else if (surf_bc.compare("reflective") == 0 + or surf_bc.compare("reflect") == 0 + or surf_bc.compare("reflecting") == 0) { + bc = BC_REFLECT; + } else if (surf_bc.compare("periodic") == 0) { + bc = BC_PERIODIC; + } else { + std::string err_msg("Unknown boundary condition \""); + err_msg += surf_bc + "\" specified on surface " + std::to_string(id); + fatal_error(err_msg); + } + + } else { + bc = BC_TRANSMIT; + } + +} + bool Surface::sense(const double xyz[3], const double uvw[3]) const { @@ -181,22 +264,35 @@ Surface::reflect(const double xyz[3], double uvw[3]) const } void -Surface::write_bc_to_hdf5(hid_t group_id) const +Surface::to_hdf5(hid_t group_id) const { + std::string group_name{"surface "}; + group_name += std::to_string(id); + + hid_t surf_group = create_group(group_id, group_name); + switch(bc) { case BC_TRANSMIT : - write_string(group_id, "boundary_type", "transmission"); + write_string(surf_group, "boundary_type", "transmission"); break; case BC_VACUUM : - write_string(group_id, "boundary_type", "vacuum"); + write_string(surf_group, "boundary_type", "vacuum"); break; case BC_REFLECT : - write_string(group_id, "boundary_type", "reflective"); + write_string(surf_group, "boundary_type", "reflective"); break; case BC_PERIODIC : - write_string(group_id, "boundary_type", "periodic"); + write_string(surf_group, "boundary_type", "periodic"); break; } + + if (name.compare("")) { + write_string(surf_group, "name", name); + } + + to_hdf5_inner(surf_group); + + close_group(surf_group); } //============================================================================== @@ -210,6 +306,8 @@ Surface::write_bc_to_hdf5(hid_t group_id) const class PeriodicSurface : public Surface { public: + PeriodicSurface(pugi::xml_node surf_node) : Surface(surf_node) {} + //! Translate a particle onto this surface from a periodic partner surface. //! @param other A pointer to the partner surface in this periodic BC. //! @param xyz[3] A point on the partner surface that will be translated onto @@ -271,12 +369,13 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) + : PeriodicSurface(surf_node) { read_coeffs(surf_node, x0); } @@ -297,12 +396,11 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<0, 1, 2>(xyz, uvw); } -void SurfaceXPlane::to_hdf5(hid_t group_id) const +void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-plane"); std::array coeffs{{x0}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -347,12 +445,13 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) + : PeriodicSurface(surf_node) { read_coeffs(surf_node, y0); } @@ -373,12 +472,11 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<1, 0, 2>(xyz, uvw); } -void SurfaceYPlane::to_hdf5(hid_t group_id) const +void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-plane"); std::array coeffs{{y0}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -423,12 +521,13 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) + : PeriodicSurface(surf_node) { read_coeffs(surf_node, z0); } @@ -449,12 +548,11 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const axis_aligned_plane_normal<2, 0, 1>(xyz, uvw); } -void SurfaceZPlane::to_hdf5(hid_t group_id) const +void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-plane"); std::array coeffs{{z0}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -481,12 +579,13 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; }; SurfacePlane::SurfacePlane(pugi::xml_node surf_node) + : PeriodicSurface(surf_node) { read_coeffs(surf_node, A, B, C, D); } @@ -520,12 +619,11 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const uvw[2] = C; } -void SurfacePlane::to_hdf5(hid_t group_id) const +void SurfacePlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "plane"); std::array coeffs{{A, B, C, D}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -635,10 +733,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, y0, z0, r); } @@ -661,12 +760,11 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const } -void SurfaceXCylinder::to_hdf5(hid_t group_id) const +void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cylinder"); std::array coeffs{{y0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -686,10 +784,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, z0, r); } @@ -711,12 +810,11 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const axis_aligned_cylinder_normal<1, 0, 2>(xyz, uvw, x0, z0); } -void SurfaceYCylinder::to_hdf5(hid_t group_id) const +void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cylinder"); std::array coeffs{{x0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -736,10 +834,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, y0, r); } @@ -761,12 +860,11 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const axis_aligned_cylinder_normal<2, 0, 1>(xyz, uvw, x0, y0); } -void SurfaceZCylinder::to_hdf5(hid_t group_id) const +void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cylinder"); std::array coeffs{{x0, y0, r}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -786,10 +884,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, y0, z0, r); } @@ -848,12 +947,11 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const uvw[2] = 2.0 * (xyz[2] - z0); } -void SurfaceSphere::to_hdf5(hid_t group_id) const +void SurfaceSphere::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "sphere"); std::array coeffs{{x0, y0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -956,10 +1054,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, y0, z0, r_sq); } @@ -981,12 +1080,11 @@ inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<0, 1, 2>(xyz, uvw, x0, y0, z0, r_sq); } -void SurfaceXCone::to_hdf5(hid_t group_id) const +void SurfaceXCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cone"); std::array coeffs{{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -1006,10 +1104,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, y0, z0, r_sq); } @@ -1031,12 +1130,11 @@ inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<1, 0, 2>(xyz, uvw, y0, x0, z0, r_sq); } -void SurfaceYCone::to_hdf5(hid_t group_id) const +void SurfaceYCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cone"); std::array coeffs{{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -1056,10 +1154,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, x0, y0, z0, r_sq); } @@ -1081,12 +1180,11 @@ inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const axis_aligned_cone_normal<2, 0, 1>(xyz, uvw, z0, x0, y0, r_sq); } -void SurfaceZCone::to_hdf5(hid_t group_id) const +void SurfaceZCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cone"); std::array coeffs{{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -1106,10 +1204,11 @@ public: double distance(const double xyz[3], const double uvw[3], bool coincident) const; void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const; }; SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) + : Surface(surf_node) { read_coeffs(surf_node, A, B, C, D, E, F, G, H, J, K); } @@ -1191,12 +1290,11 @@ SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const uvw[2] = 2.0*C*z + E*y + F*x + J; } -void SurfaceQuadric::to_hdf5(hid_t group_id) const +void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "quadric"); std::array coeffs{{A, B, C, D, E, F, G, H, J, K}}; write_double_1D(group_id, "coefficients", coeffs); - write_bc_to_hdf5(group_id); } //============================================================================== @@ -1220,51 +1318,42 @@ read_surfaces(pugi::xml_node *node) int i_surf; for (surf_node = node->child("surface"), i_surf = 0; surf_node; surf_node = surf_node.next_sibling("surface"), i_surf++) { - const pugi::char_t *surf_type; - if (surf_node.attribute("type")) { - surf_type = surf_node.attribute("type").value(); - } else if (surf_node.child("type")) { - surf_type = surf_node.child_value("type"); - } else { - std::cout << "ERROR: Found a surface with no type attribute/node" - << std::endl; - //TODO: call fatal_error - } + std::string surf_type = get_node_value(surf_node, "type"); - if (strcmp(surf_type, "x-plane") == 0) { + if (surf_type.compare("x-plane") == 0) { surfaces_c[i_surf] = new SurfaceXPlane(surf_node); - } else if (strcmp(surf_type, "y-plane") == 0) { + } else if (surf_type.compare("y-plane") == 0) { surfaces_c[i_surf] = new SurfaceYPlane(surf_node); - } else if (strcmp(surf_type, "z-plane") == 0) { + } else if (surf_type.compare("z-plane") == 0) { surfaces_c[i_surf] = new SurfaceZPlane(surf_node); - } else if (strcmp(surf_type, "plane") == 0) { + } else if (surf_type.compare("plane") == 0) { surfaces_c[i_surf] = new SurfacePlane(surf_node); - } else if (strcmp(surf_type, "x-cylinder") == 0) { + } else if (surf_type.compare("x-cylinder") == 0) { surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); - } else if (strcmp(surf_type, "y-cylinder") == 0) { + } else if (surf_type.compare("y-cylinder") == 0) { surfaces_c[i_surf] = new SurfaceYCylinder(surf_node); - } else if (strcmp(surf_type, "z-cylinder") == 0) { + } else if (surf_type.compare("z-cylinder") == 0) { surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); - } else if (strcmp(surf_type, "sphere") == 0) { + } else if (surf_type.compare("sphere") == 0) { surfaces_c[i_surf] = new SurfaceSphere(surf_node); - } else if (strcmp(surf_type, "x-cone") == 0) { + } else if (surf_type.compare("x-cone") == 0) { surfaces_c[i_surf] = new SurfaceXCone(surf_node); - } else if (strcmp(surf_type, "y-cone") == 0) { + } else if (surf_type.compare("y-cone") == 0) { surfaces_c[i_surf] = new SurfaceYCone(surf_node); - } else if (strcmp(surf_type, "z-cone") == 0) { + } else if (surf_type.compare("z-cone") == 0) { surfaces_c[i_surf] = new SurfaceZCone(surf_node); - } else if (strcmp(surf_type, "quadric") == 0) { + } else if (surf_type.compare("quadric") == 0) { surfaces_c[i_surf] = new SurfaceQuadric(surf_node); } else { @@ -1272,32 +1361,6 @@ read_surfaces(pugi::xml_node *node) std::cout << surf_type << std::endl; //TODO: call fatal_error } - - const pugi::char_t *surf_bc{""}; - if (surf_node.attribute("boundary")) { - surf_bc = surf_node.attribute("boundary").value(); - } else if (surf_node.child("boundary")) { - surf_bc = surf_node.attribute("boundary").value(); - } - - if (strcmp(surf_bc, "transmission") == 0 - or strcmp(surf_bc, "transmit") == 0 - or strcmp(surf_bc, "") == 0) { - surfaces_c[i_surf]->bc = BC_TRANSMIT; - - } else if (strcmp(surf_bc, "vacuum") == 0) { - surfaces_c[i_surf]->bc = BC_VACUUM; - - } else if (strcmp(surf_bc, "reflective") == 0 - or strcmp(surf_bc, "reflect") == 0 - or strcmp(surf_bc, "reflecting") == 0) { - surfaces_c[i_surf]->bc = BC_REFLECT; - } else if (strcmp(surf_bc, "periodic") == 0) { - surfaces_c[i_surf]->bc = BC_PERIODIC; - } else { - std::cout << "Unknown boundary condition" << std::endl; - //TODO: call fatal_error - } } } } From afe2f619c8dd855e9ff0503e4eb9af944b2fba3d Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 23 Jan 2018 15:21:21 -0500 Subject: [PATCH 15/21] Improve surface coeff error handling --- src/input_xml.F90 | 7 --- src/surface_header.C | 134 ++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 46 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 462b9708f..3f22522c2 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1068,13 +1068,6 @@ contains ! surface coordinates. n = node_word_count(node_surf, "coeffs") - if (n < coeffs_reqd) then - call fatal_error("Not enough coefficients specified for surface: " & - // trim(to_str(s%id))) - elseif (n > coeffs_reqd) then - call fatal_error("Too many coefficients specified for surface: " & - // trim(to_str(s%id))) - end if allocate(coeffs(n)) call get_node_array(node_surf, "coeffs", coeffs) diff --git a/src/surface_header.C b/src/surface_header.C index 4cfda86ef..565352623 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -74,55 +74,111 @@ Surface **surfaces_c; // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== -const char* get_coeff_str(pugi::xml_node surf_node) +int word_count(const std::string &text) { - if (surf_node.attribute("coeffs")) { - return surf_node.attribute("coeffs").value(); - } else if (surf_node.child("coeffs")) { - return surf_node.child_value("coeffs"); - } else { - std::cout << "ERROR: Found a surface with no coefficients" << std::endl; - return nullptr; + bool in_word = false; + int count{0}; + for (auto c = text.begin(); c != text.end(); c++) { + switch(*c) { + case ' ' : + case '\t' : + case '\r' : + case '\n' : + if (in_word) { + in_word = false; + count++; + } + break; + default : + in_word = true; + } } + if (in_word) count++; + return count; } -void read_coeffs(pugi::xml_node surf_node, double &c1) +void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1) { - const char *coeffs = get_coeff_str(surf_node); - int stat = sscanf(coeffs, "%lf", &c1); + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 1) { + std::string err_msg{"Surface "}; + err_msg += std::to_string(surf_id); + err_msg += " expects 1 coeff but was given "; + err_msg += std::to_string(n_words); + fatal_error(err_msg); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf", &c1); if (stat != 1) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; + fatal_error("Something went wrong reading surface coeffs"); } } -void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3) +void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, + double &c3) { - const char *coeffs = get_coeff_str(surf_node); - int stat = sscanf(coeffs, "%lf %lf %lf", &c1, &c2, &c3); + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 3) { + std::string err_msg{"Surface "}; + err_msg += std::to_string(surf_id); + err_msg += " expects 3 coeffs but was given "; + err_msg += std::to_string(n_words); + fatal_error(err_msg); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf", &c1, &c2, &c3); if (stat != 3) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; + fatal_error("Something went wrong reading surface coeffs"); } } -void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, - double &c4) +void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, + double &c3, double &c4) { - const char *coeffs = get_coeff_str(surf_node); - int stat = sscanf(coeffs, "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 4) { + std::string err_msg{"Surface "}; + err_msg += std::to_string(surf_id); + err_msg += " expects 4 coeffs but was given "; + err_msg += std::to_string(n_words); + fatal_error(err_msg); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); if (stat != 4) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; + fatal_error("Something went wrong reading surface coeffs"); } } -void read_coeffs(pugi::xml_node surf_node, double &c1, double &c2, double &c3, - double &c4, double &c5, double &c6, double &c7, double &c8, - double &c9, double &c10) +void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, + double &c3, double &c4, double &c5, double &c6, double &c7, + double &c8, double &c9, double &c10) { - const char *coeffs = get_coeff_str(surf_node); - int stat = sscanf(coeffs, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + // Check the given number of coefficients. + std::string coeffs = get_node_value(surf_node, "coeffs"); + int n_words = word_count(coeffs); + if (n_words != 10) { + std::string err_msg{"Surface "}; + err_msg += std::to_string(surf_id); + err_msg += " expects 10 coeffs but was given "; + err_msg += std::to_string(n_words); + fatal_error(err_msg); + } + + // Parse the coefficients. + int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); if (stat != 10) { - std::cout << "Something went wrong reading surface coeffs!" << std::endl; + fatal_error("Something went wrong reading surface coeffs"); } } @@ -377,7 +433,7 @@ public: SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, x0); + read_coeffs(surf_node, id, x0); } inline double SurfaceXPlane::evaluate(const double xyz[3]) const @@ -453,7 +509,7 @@ public: SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, y0); + read_coeffs(surf_node, id, y0); } inline double SurfaceYPlane::evaluate(const double xyz[3]) const @@ -529,7 +585,7 @@ public: SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, z0); + read_coeffs(surf_node, id, z0); } inline double SurfaceZPlane::evaluate(const double xyz[3]) const @@ -587,7 +643,7 @@ public: SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, A, B, C, D); + read_coeffs(surf_node, id, A, B, C, D); } double @@ -739,7 +795,7 @@ public: SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, y0, z0, r); + read_coeffs(surf_node, id, y0, z0, r); } inline double SurfaceXCylinder::evaluate(const double xyz[3]) const @@ -790,7 +846,7 @@ public: SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, z0, r); + read_coeffs(surf_node, id, x0, z0, r); } inline double SurfaceYCylinder::evaluate(const double xyz[3]) const @@ -840,7 +896,7 @@ public: SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, y0, r); + read_coeffs(surf_node, id, x0, y0, r); } inline double SurfaceZCylinder::evaluate(const double xyz[3]) const @@ -890,7 +946,7 @@ public: SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, y0, z0, r); + read_coeffs(surf_node, id, x0, y0, z0, r); } double SurfaceSphere::evaluate(const double xyz[3]) const @@ -1060,7 +1116,7 @@ public: SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, r_sq); } inline double SurfaceXCone::evaluate(const double xyz[3]) const @@ -1110,7 +1166,7 @@ public: SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, r_sq); } inline double SurfaceYCone::evaluate(const double xyz[3]) const @@ -1160,7 +1216,7 @@ public: SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, x0, y0, z0, r_sq); + read_coeffs(surf_node, id, x0, y0, z0, r_sq); } inline double SurfaceZCone::evaluate(const double xyz[3]) const @@ -1210,7 +1266,7 @@ public: SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, A, B, C, D, E, F, G, H, J, K); + read_coeffs(surf_node, id, A, B, C, D, E, F, G, H, J, K); } double From 164e6c0ef4c7732a6245da2597fb6ff229deefe5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 23 Jan 2018 18:29:05 -0500 Subject: [PATCH 16/21] Move more Surface implementation to C++ --- src/geometry.F90 | 20 ++- src/input_xml.F90 | 168 +--------------------- src/output.F90 | 2 +- src/summary.F90 | 5 +- src/surface_header.C | 201 +++++++++++++++++++++++++-- src/surface_header.F90 | 55 +------- src/tallies/tally_filter_surface.F90 | 2 +- src/tracking.F90 | 12 +- 8 files changed, 217 insertions(+), 248 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index f1feb3ba3..d1519f8d2 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -54,16 +54,24 @@ module geometry real(C_DOUBLE), intent(out) :: uvw(3); end subroutine surface_normal_c - function surface_periodic_c(surf_ind1, surf_ind2, xyz, uvw) & + function surface_periodic_c(surf_ind1, xyz, uvw) & bind(C, name="surface_periodic") result(rotational) use ISO_C_BINDING implicit none integer(C_INT), intent(in), value :: surf_ind1; - integer(C_INT), intent(in), value :: surf_ind2; real(C_DOUBLE), intent(inout) :: xyz(3); real(C_DOUBLE), intent(inout) :: uvw(3); logical(C_BOOL) :: rotational end function surface_periodic_c + + function surface_i_periodic_c(surf_ind) bind(C, name="surface_i_periodic") & + result(i_periodic) + use ISO_C_BINDING + implicit none + integer(C_INT), intent(in), value :: surf_ind + integer(C_INT) :: i_periodic + end function + end interface contains @@ -857,15 +865,15 @@ contains ! Copy positive neighbors to Surface instance n = neighbor_pos(i)%size() if (n > 0) then - allocate(surfaces(i)%obj%neighbor_pos(n)) - surfaces(i)%obj%neighbor_pos(:) = neighbor_pos(i)%data(1:n) + allocate(surfaces(i)%neighbor_pos(n)) + surfaces(i)%neighbor_pos(:) = neighbor_pos(i)%data(1:n) end if ! Copy negative neighbors to Surface instance n = neighbor_neg(i)%size() if (n > 0) then - allocate(surfaces(i)%obj%neighbor_neg(n)) - surfaces(i)%obj%neighbor_neg(:) = neighbor_neg(i)%data(1:n) + allocate(surfaces(i)%neighbor_neg(n)) + surfaces(i)%neighbor_neg(:) = neighbor_neg(i)%data(1:n) end if end do diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 3f22522c2..9b6e1c6fc 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -919,12 +919,8 @@ contains integer :: id integer :: univ_id integer :: n_cells_in_univ - integer :: coeffs_reqd - integer :: i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax - real(8) :: xmin, xmax, ymin, ymax, zmin, zmax integer, allocatable :: temp_int_array(:) real(8) :: phi, theta, psi - real(8), allocatable :: coeffs(:) logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename @@ -984,13 +980,6 @@ contains call fatal_error("No surfaces found in geometry.xml!") end if - xmin = INFINITY - xmax = -INFINITY - ymin = INFINITY - ymax = -INFINITY - zmin = INFINITY - zmax = -INFINITY - ! Allocate cells array allocate(surfaces(n_surfaces)) @@ -998,52 +987,7 @@ contains ! Get pointer to i-th surface node node_surf = node_surf_list(i) - ! 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') - coeffs_reqd = 1 - allocate(SurfaceXPlane :: surfaces(i)%obj) - case ('y-plane') - coeffs_reqd = 1 - allocate(SurfaceYPlane :: surfaces(i)%obj) - case ('z-plane') - coeffs_reqd = 1 - allocate(SurfaceZPlane :: surfaces(i)%obj) - case ('plane') - coeffs_reqd = 4 - allocate(SurfacePlane :: surfaces(i)%obj) - case ('x-cylinder') - coeffs_reqd = 3 - allocate(SurfaceXCylinder :: surfaces(i)%obj) - case ('y-cylinder') - coeffs_reqd = 3 - allocate(SurfaceYCylinder :: surfaces(i)%obj) - case ('z-cylinder') - coeffs_reqd = 3 - allocate(SurfaceZCylinder :: surfaces(i)%obj) - case ('sphere') - coeffs_reqd = 4 - allocate(SurfaceSphere :: surfaces(i)%obj) - case ('x-cone') - coeffs_reqd = 4 - allocate(SurfaceXCone :: surfaces(i)%obj) - case ('y-cone') - coeffs_reqd = 4 - allocate(SurfaceYCone :: surfaces(i)%obj) - case ('z-cone') - coeffs_reqd = 4 - allocate(SurfaceZCone :: surfaces(i)%obj) - case ('quadric') - coeffs_reqd = 10 - allocate(SurfaceQuadric :: surfaces(i)%obj) - case default - call fatal_error("Invalid surface type: " // trim(word)) - end select - - s => surfaces(i)%obj + s => surfaces(i) ! Copy data into cells if (check_for_node(node_surf, "id")) then @@ -1058,44 +1002,10 @@ contains // 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 - ! Check to make sure that the proper number of coefficients ! have been specified for the given type of surface. Then copy ! surface coordinates. - n = node_word_count(node_surf, "coeffs") - - allocate(coeffs(n)) - call get_node_array(node_surf, "coeffs", coeffs) - - select type(s) - type is (SurfaceXPlane) - ! Determine outer surfaces - xmin = min(xmin, coeffs(1)) - xmax = max(xmax, coeffs(1)) - if (xmin == coeffs(1)) i_xmin = i - if (xmax == coeffs(1)) i_xmax = i - type is (SurfaceYPlane) - ! Determine outer surfaces - ymin = min(ymin, coeffs(1)) - ymax = max(ymax, coeffs(1)) - if (ymin == coeffs(1)) i_ymin = i - if (ymax == coeffs(1)) i_ymax = i - type is (SurfaceZPlane) - ! Determine outer surfaces - zmin = min(zmin, coeffs(1)) - zmax = max(zmax, coeffs(1)) - if (zmin == coeffs(1)) i_zmin = i - if (zmax == coeffs(1)) i_zmax = i - end select - - ! No longer need coefficients - deallocate(coeffs) - ! Boundary conditions word = '' if (check_for_node(node_surf, "boundary")) & @@ -1112,12 +1022,6 @@ contains case ('periodic') s%bc = BC_PERIODIC boundary_exists = .true. - - ! Check for specification of periodic surface - if (check_for_node(node_surf, "periodic_surface_id")) then - call get_node_value(node_surf, "periodic_surface_id", & - s % i_periodic) - end if case default call fatal_error("Unknown boundary condition '" // trim(word) // & &"' specified on surface " // trim(to_str(s%id))) @@ -1134,76 +1038,6 @@ contains end if end if - ! Determine opposite side for periodic boundaries - do i = 1, size(surfaces) - if (surfaces(i) % obj % bc == BC_PERIODIC) then - select type (surf => surfaces(i) % obj) - type is (SurfaceXPlane) - if (surf % i_periodic == NONE) then - if (i == i_xmin) then - surf % i_periodic = i_xmax - elseif (i == i_xmax) then - surf % i_periodic = i_xmin - else - call fatal_error("Periodic boundary condition applied to & - &interior surface.") - end if - else - surf % i_periodic = surface_dict % get(surf % i_periodic) - end if - - type is (SurfaceYPlane) - if (surf % i_periodic == NONE) then - if (i == i_ymin) then - surf % i_periodic = i_ymax - elseif (i == i_ymax) then - surf % i_periodic = i_ymin - else - call fatal_error("Periodic boundary condition applied to & - &interior surface.") - end if - else - surf % i_periodic = surface_dict % get(surf % i_periodic) - end if - - type is (SurfaceZPlane) - if (surf % i_periodic == NONE) then - if (i == i_zmin) then - surf % i_periodic = i_zmax - elseif (i == i_zmax) then - surf % i_periodic = i_zmin - else - call fatal_error("Periodic boundary condition applied to & - &interior surface.") - end if - else - surf % i_periodic = surface_dict % get(surf % i_periodic) - end if - - type is (SurfacePlane) - if (surf % i_periodic == NONE) then - call fatal_error("No matching periodic surface specified for & - &periodic boundary condition on surface " // & - trim(to_str(surf % id)) // ".") - else - surf % i_periodic = surface_dict % get(surf % i_periodic) - end if - - class default - call fatal_error("Periodic boundary condition applied to & - &non-planar surface.") - end select - - ! Make sure opposite surface is also periodic - associate (surf => surfaces(i) % obj) - if (surfaces(surf % i_periodic) % obj % bc /= BC_PERIODIC) then - call fatal_error("Could not find matching surface for periodic & - &boundary on surface " // trim(to_str(surf % id)) // ".") - end if - end associate - end if - end do - ! ========================================================================== ! READ CELLS FROM GEOMETRY.XML diff --git a/src/output.F90 b/src/output.F90 index 1b7cae121..4113eea47 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -259,7 +259,7 @@ contains ! Print surface if (p % surface /= NONE) then - write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%obj%id, p % surface)) + write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%id, p % surface)) end if ! Display weight, energy, grid index, and interpolation factor diff --git a/src/summary.F90 b/src/summary.F90 index 77bded983..9b82a0396 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -133,12 +133,11 @@ contains real(8), allocatable :: cell_temperatures(:) integer(HID_T) :: geom_group integer(HID_T) :: cells_group, cell_group - integer(HID_T) :: surfaces_group, surface_group + integer(HID_T) :: surfaces_group integer(HID_T) :: universes_group, univ_group integer(HID_T) :: lattices_group, lattice_group character(:), allocatable :: region_spec type(Cell), pointer :: c - class(Surface), pointer :: s class(Lattice), pointer :: lat ! Use H5LT interface to write number of geometry objects @@ -233,7 +232,7 @@ contains region_spec = trim(region_spec) // " |" case default region_spec = trim(region_spec) // " " // to_str(& - sign(surfaces(abs(k))%obj%id, k)) + sign(surfaces(abs(k))%id, k)) end select end do call write_dataset(cell_group, "region", adjustl(region_spec)) diff --git a/src/surface_header.C b/src/surface_header.C index 565352623..afea2b43d 100644 --- a/src/surface_header.C +++ b/src/surface_header.C @@ -1,7 +1,8 @@ #include // for std::transform -#include // For std::array +#include #include // For strcmp #include // For numeric_limits +#include #include // For fabs #include "pugixml/pugixml.hpp" @@ -45,6 +46,7 @@ get_node_value(const pugi::xml_node &node, const char *name) std::string value(value_char); std::transform(value.begin(), value.end(), value.begin(), ::tolower); + //TODO: trim whitespace return value; } @@ -57,6 +59,7 @@ get_node_value(const pugi::xml_node &node, const char *name) extern "C" double FP_COINCIDENT; //extern "C" double INFTY; const double INFTY{std::numeric_limits::max()}; +const int C_NONE{-1}; extern "C" const int BC_TRANSMIT{0}; extern "C" const int BC_VACUUM{1}; @@ -70,6 +73,8 @@ extern "C" const int BC_PERIODIC{3}; class Surface; Surface **surfaces_c; +std::map surface_dict; + //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== @@ -182,6 +187,19 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, } } +//============================================================================== +//============================================================================== + +struct BoundingBox +{ + double xmin; + double xmax; + double ymin; + double ymax; + double zmin; + double zmax; +}; + //============================================================================== //! A geometry primitive used to define regions of 3D space. //============================================================================== @@ -193,8 +211,6 @@ public: //int neighbor_pos[], //!< List of cells on positive side // neighbor_neg[]; //!< List of cells on negative side int bc; //!< Boundary condition - //TODO: switch that zero to a NONE constant. - //int i_periodic = 0; //!< Index of corresponding periodic surface std::string name{""}; //!< User-defined name Surface(pugi::xml_node surf_node); @@ -249,7 +265,6 @@ Surface::Surface(pugi::xml_node surf_node) } else { fatal_error("Must specify id of surface in geometry XML file."); } - //TODO: check for duplicate IDs if (check_for_node(surf_node, "name")) { name = get_node_value(surf_node, "name"); @@ -362,7 +377,9 @@ Surface::to_hdf5(hid_t group_id) const class PeriodicSurface : public Surface { public: - PeriodicSurface(pugi::xml_node surf_node) : Surface(surf_node) {} + int i_periodic{C_NONE}; //!< Index of corresponding periodic surface + + PeriodicSurface(pugi::xml_node surf_node); //! Translate a particle onto this surface from a periodic partner surface. //! @param other A pointer to the partner surface in this periodic BC. @@ -374,8 +391,18 @@ public: //! boundary condition. virtual bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const = 0; + + virtual struct BoundingBox bounding_box() const = 0; }; +PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) + : Surface(surf_node) +{ + if (check_for_node(surf_node, "periodic_surface_id")) { + i_periodic = stoi(get_node_value(surf_node, "periodic_surface_id")); + } +} + //============================================================================== // Generic functions for x-, y-, and z-, planes. //============================================================================== @@ -428,6 +455,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; + struct BoundingBox bounding_box() const; }; SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) @@ -485,6 +513,13 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], } } +struct BoundingBox +SurfaceXPlane::bounding_box() const +{ + struct BoundingBox out{x0, x0, -INFTY, INFTY, -INFTY, INFTY}; + return out; +} + //============================================================================== // SurfaceYPlane //! A plane perpendicular to the y-axis. @@ -504,6 +539,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; + struct BoundingBox bounding_box() const; }; SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) @@ -561,6 +597,13 @@ bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], } } +struct BoundingBox +SurfaceYPlane::bounding_box() const +{ + struct BoundingBox out{-INFTY, INFTY, y0, y0, -INFTY, INFTY}; + return out; +} + //============================================================================== // SurfaceZPlane //! A plane perpendicular to the z-axis. @@ -580,6 +623,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; + struct BoundingBox bounding_box() const; }; SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) @@ -619,6 +663,13 @@ bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], return false; } +struct BoundingBox +SurfaceZPlane::bounding_box() const +{ + struct BoundingBox out{-INFTY, INFTY, -INFTY, INFTY, z0, z0}; + return out; +} + //============================================================================== // SurfacePlane //! A general plane. @@ -638,6 +689,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; + struct BoundingBox bounding_box() const; }; SurfacePlane::SurfacePlane(pugi::xml_node surf_node) @@ -698,6 +750,13 @@ bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], return false; } +struct BoundingBox +SurfacePlane::bounding_box() const +{ + struct BoundingBox out{-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY}; + return out; +} + //============================================================================== // Generic functions for x-, y-, and z-, cylinders //============================================================================== @@ -1359,10 +1418,10 @@ extern "C" void read_surfaces(pugi::xml_node *node) { // Count the number of surfaces. - int n_surfaces = 0; + int n_surfaces{0}; for (pugi::xml_node surf_node = node->child("surface"); surf_node; surf_node = surf_node.next_sibling("surface")) { - n_surfaces += 1; + n_surfaces++; } // Allocate the array of Surface pointers. @@ -1413,12 +1472,125 @@ read_surfaces(pugi::xml_node *node) surfaces_c[i_surf] = new SurfaceQuadric(surf_node); } else { - std::cout << "Call error or handle uppercase here!" << std::endl; + std::cout << "Call error here!" << std::endl; std::cout << surf_type << std::endl; //TODO: call fatal_error } } } + + // Fill the surface dictionary. + for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { + int id = surfaces_c[i_surf]->id; + auto in_dict = surface_dict.find(id); + if (in_dict == surface_dict.end()) { + surface_dict[id] = i_surf; + } else { + std::string err_msg{"Two or more surfaces use the same unique ID: "}; + err_msg += std::to_string(id); + fatal_error(err_msg); + } + } + + // Find the global bounding box (of periodic BC surfaces). + double xmin{INFTY}, xmax{-INFTY}, ymin{INFTY}, ymax{-INFTY}, + zmin{INFTY}, zmax{-INFTY}; + int i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax; + for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { + if (surfaces_c[i_surf]->bc == BC_PERIODIC) { + // Downcast to the PeriodicSurface type. + Surface *surf_base = surfaces_c[i_surf]; + PeriodicSurface *surf = dynamic_cast(surf_base); + //TODO: check for null pointer + + // See if this surface makes part of the global bounding box. + struct BoundingBox bb = surf->bounding_box(); + if (bb.xmin > -INFTY and bb.xmin < xmin) { + xmin = bb.xmin; + i_xmin = i_surf; + } + if (bb.xmax < INFTY and bb.xmax > xmax) { + xmax = bb.xmax; + i_xmax = i_surf; + } + if (bb.ymin > -INFTY and bb.ymin < ymin) { + ymin = bb.ymin; + i_ymin = i_surf; + } + if (bb.ymax < INFTY and bb.ymax > ymax) { + ymax = bb.ymax; + i_ymax = i_surf; + } + if (bb.zmin > -INFTY and bb.zmin < zmin) { + zmin = bb.zmin; + i_zmin = i_surf; + } + if (bb.zmax < INFTY and bb.zmax > zmax) { + zmax = bb.zmax; + i_zmax = i_surf; + } + } + } + + // Set i_periodic for periodic BC surfaces. + for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { + if (surfaces_c[i_surf]->bc == BC_PERIODIC) { + // Downcast to the PeriodicSurface type. + Surface *surf_base = surfaces_c[i_surf]; + PeriodicSurface *surf = dynamic_cast(surf_base); + + // Also try downcasting to the SurfacePlane type (which must be handled + // differently). + SurfacePlane *surf_p = dynamic_cast(surf); + + if (surf_p == NULL) { + // This is not a SurfacePlane. + if (surf->i_periodic == C_NONE) { + // The user did not specify the matching periodic surface. See if we + // can find the partnered surface from the bounding box information. + if (i_surf == i_xmin) { + surf->i_periodic = i_xmax; + } else if (i_surf == i_xmax) { + surf->i_periodic = i_xmin; + } else if (i_surf == i_ymin) { + surf->i_periodic = i_ymax; + } else if (i_surf == i_ymax) { + surf->i_periodic = i_ymin; + } else if (i_surf == i_zmin) { + surf->i_periodic = i_zmax; + } else if (i_surf == i_zmax) { + surf->i_periodic = i_zmin; + } else { + fatal_error("Periodic boundary condition applied to interior " + "surface"); + } + } else { + // Convert the surface id to an index. + surf->i_periodic = surface_dict[surf->i_periodic]; + } + } else { + // This is a SurfacePlane. We won't try to find it's partner if the + // user didn't specify one. + if (surf->i_periodic == C_NONE) { + std::string err_msg{"No matching periodic surface specified for " + "periodic boundary condition on surface "}; + err_msg += std::to_string(surf->id); + fatal_error(err_msg); + } else { + // Convert the surface id to an index. + surf->i_periodic = surface_dict[surf->i_periodic]; + } + } + + // Make sure the opposite surface is also periodic. + if (surfaces_c[surf->i_periodic]->bc != BC_PERIODIC) { + std::string err_msg{"Could not find matching surface for periodic " + "boundary condition on surface "}; + err_msg += std::to_string(surf->id); + fatal_error(err_msg); + } + } + } } //============================================================================== @@ -1454,17 +1626,24 @@ surface_to_hdf5(int surf_ind, hid_t group) } extern "C" bool -surface_periodic(int surf_ind1, int surf_ind2, double xyz[3], double uvw[3]) +surface_periodic(int surf_ind1, double xyz[3], double uvw[3]) { - // Hopefully this function has only been called on a pair of surfaces that + // Hopefully this function has only been called for a pair of surfaces that // support periodic BCs (checking should have been done when reading the // geometry XML). Downcast the surfaces to the PeriodicSurface type so we // can call the periodic_translate method. Surface *surf1_gen = surfaces_c[surf_ind1]; PeriodicSurface *surf1 = dynamic_cast(surf1_gen); - Surface *surf2_gen = surfaces_c[surf_ind2]; + Surface *surf2_gen = surfaces_c[surf1->i_periodic]; PeriodicSurface *surf2 = dynamic_cast(surf2_gen); // Call the type-bound methods. return surf2->periodic_translate(surf1, xyz, uvw); } + +extern "C" int +surface_i_periodic(int surf_ind) +{ + PeriodicSurface *surf = dynamic_cast(surfaces_c[surf_ind]); + return surf->i_periodic; +} diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 98e2423b6..ffe0a6db4 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -12,68 +12,17 @@ module surface_header ! construct closed volumes (cells) !=============================================================================== - type, abstract :: Surface + type :: 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 - integer :: i_periodic = NONE ! Index of corresponding periodic surface - character(len=104) :: name = "" ! User-defined name end type Surface -!=============================================================================== -! 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() type-bound procedure and must implement normal() -!=============================================================================== - - type, extends(Surface) :: SurfaceXPlane - end type SurfaceXPlane - - type, extends(Surface) :: SurfaceYPlane - end type SurfaceYPlane - - type, extends(Surface) :: SurfaceZPlane - end type SurfaceZPlane - - type, extends(Surface) :: SurfacePlane - end type SurfacePlane - - type, extends(Surface) :: SurfaceXCylinder - end type SurfaceXCylinder - - type, extends(Surface) :: SurfaceYCylinder - end type SurfaceYCylinder - - type, extends(Surface) :: SurfaceZCylinder - end type SurfaceZCylinder - - type, extends(Surface) :: SurfaceSphere - end type SurfaceSphere - - type, extends(Surface) :: SurfaceXCone - end type SurfaceXCone - - type, extends(Surface) :: SurfaceYCone - end type SurfaceYCone - - type, extends(Surface) :: SurfaceZCone - end type SurfaceZCone - - type, extends(Surface) :: SurfaceQuadric - end type SurfaceQuadric - integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces - type(SurfaceContainer), allocatable, target :: surfaces(:) + type(Surface), allocatable, target :: surfaces(:) ! Dictionary that maps user IDs to indices in 'surfaces' type(DictIntInt) :: surface_dict diff --git a/src/tallies/tally_filter_surface.F90 b/src/tallies/tally_filter_surface.F90 index daecd8891..6a2afa3ec 100644 --- a/src/tallies/tally_filter_surface.F90 +++ b/src/tallies/tally_filter_surface.F90 @@ -105,7 +105,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Surface " // to_str(surfaces(this % surfaces(bin)) % obj % id) + label = "Surface " // to_str(surfaces(this % surfaces(bin)) % id) end function text_label_surface end module tally_filter_surface diff --git a/src/tracking.F90 b/src/tracking.F90 index d616212ec..98bca2a27 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -6,7 +6,7 @@ module tracking use geometry_header, only: cells use geometry, only: find_cell, distance_to_boundary, cross_lattice, & check_cell_overlap, surface_reflect_c, & - surface_periodic_c + surface_periodic_c, surface_i_periodic_c use message_passing use mgxs_header use nuclide_header @@ -298,7 +298,7 @@ contains class(Surface), pointer :: surf i_surface = abs(p % surface) - surf => surfaces(i_surface)%obj + surf => surfaces(i_surface) if (verbosity >= 10 .or. trace) then call write_message(" Crossing surface " // trim(to_str(surf % id))) end if @@ -412,14 +412,14 @@ contains p % coord(1) % xyz = xyz end if - rotational = surface_periodic_c(i_surface-1, surf % i_periodic-1, & - p % coord(1) % xyz, p % coord(1) % uvw) + rotational = surface_periodic_c(i_surface-1, p % coord(1) % xyz, & + p % coord(1) % uvw) ! Reassign particle's surface if (rotational) then - p % surface = surf % i_periodic + p % surface = surface_i_periodic_c(i_surface-1) + 1 else - p % surface = sign(surf % i_periodic, p % surface) + p % surface = sign(surface_i_periodic_c(i_surface-1) + 1, p % surface) end if ! Figure out what cell particle is in now From 983cbd48c65df2eb5578dd52d423caed915c26c2 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 23 Jan 2018 22:26:48 -0500 Subject: [PATCH 17/21] Clean up C++ surface file structure --- CMakeLists.txt | 10 +- src/error.h | 1 + src/{surface_header.C => surface.cpp} | 473 ++------------------------ src/surface.h | 431 +++++++++++++++++++++++ src/xml_interface.h | 52 +++ 5 files changed, 517 insertions(+), 450 deletions(-) rename src/{surface_header.C => surface.cpp} (72%) create mode 100644 src/surface.h create mode 100644 src/xml_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e59713755..625f00136 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -437,11 +437,13 @@ set(LIBOPENMC_FORTRAN_SRC set(LIBOPENMC_CXX_SRC src/error.h src/hdf5_interface.h - src/random_lcg.h src/random_lcg.cpp - src/surface_header.C - src/pugixml/pugixml.hpp - src/pugixml/pugixml.cpp) + src/random_lcg.h + src/surface.cpp + src/surface.h + src/xml_interface.h + src/pugixml/pugixml.cpp + src/pugixml/pugixml.hpp) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) add_executable(${program} src/main.F90) diff --git a/src/error.h b/src/error.h index 77f0252e1..0fd78a6c5 100644 --- a/src/error.h +++ b/src/error.h @@ -1,6 +1,7 @@ #ifndef ERROR_H #define ERROR_H +#include #include diff --git a/src/surface_header.C b/src/surface.cpp similarity index 72% rename from src/surface_header.C rename to src/surface.cpp index afea2b43d..ed111b037 100644 --- a/src/surface_header.C +++ b/src/surface.cpp @@ -1,79 +1,11 @@ -#include // for std::transform #include -#include // For strcmp -#include // For numeric_limits -#include #include // For fabs -#include "pugixml/pugixml.hpp" -#include "hdf5.h" - #include "error.h" #include "hdf5_interface.h" +#include "xml_interface.h" -// DEBUGGING -#include -#include - -bool -check_for_node(const pugi::xml_node &node, const char *name) -{ - if (node.attribute(name)) { - return true; - } else if (node.child(name)) { - return true; - } else { - return false; - } -} - -std::string -get_node_value(const pugi::xml_node &node, const char *name) -{ - const pugi::char_t *value_char; - if (node.attribute(name)) { - value_char = node.attribute(name).value(); - } else if (node.child(name)) { - value_char = node.child_value(name); - } else { - std::string err_msg("Node \""); - err_msg += name; - err_msg += "\" is not a memeber of the \""; - err_msg += node.name(); - err_msg += "\" XML node"; - fatal_error(err_msg); - } - - std::string value(value_char); - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - //TODO: trim whitespace - return value; -} - -//============================================================================== -// Constants -//============================================================================== - -//extern "C" const double FP_COINCIDENT{1e-12}; -//extern "C" const double INFTY{std::numeric_limits::max()}; -extern "C" double FP_COINCIDENT; -//extern "C" double INFTY; -const double INFTY{std::numeric_limits::max()}; -const int C_NONE{-1}; - -extern "C" const int BC_TRANSMIT{0}; -extern "C" const int BC_VACUUM{1}; -extern "C" const int BC_REFLECT{2}; -extern "C" const int BC_PERIODIC{3}; - -//============================================================================== -// Global array of surfaces -//============================================================================== - -class Surface; -Surface **surfaces_c; - -std::map surface_dict; +#include "surface.h" //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element @@ -84,18 +16,13 @@ int word_count(const std::string &text) bool in_word = false; int count{0}; for (auto c = text.begin(); c != text.end(); c++) { - switch(*c) { - case ' ' : - case '\t' : - case '\r' : - case '\n' : - if (in_word) { - in_word = false; - count++; - } - break; - default : - in_word = true; + if (std::isspace(*c)) { + if (in_word) { + in_word = false; + count++; + } + } else { + in_word = true; } } if (in_word) count++; @@ -188,76 +115,9 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, } //============================================================================== +// Surface implementation //============================================================================== -struct BoundingBox -{ - double xmin; - double xmax; - double ymin; - double ymax; - double zmin; - double zmax; -}; - -//============================================================================== -//! A geometry primitive used to define regions of 3D space. -//============================================================================== - -class Surface -{ -public: - int id; //!< Unique ID - //int neighbor_pos[], //!< List of cells on positive side - // neighbor_neg[]; //!< List of cells on negative side - int bc; //!< Boundary condition - std::string name{""}; //!< User-defined name - - Surface(pugi::xml_node surf_node); - - //! Determine which side of a surface a point lies on. - //! @param xyz[3] The 3D Cartesian coordinate of a point. - //! @param uvw[3] A direction used to "break ties" and pick a sense when the - //! point is very close to the surface. - //! @return true if the point is on the "positive" side of the surface and - //! false otherwise. - bool sense(const double xyz[3], const double uvw[3]) const; - - //! Determine the direction of a ray reflected from the surface. - //! @param xyz[3] The point at which the ray is incident. - //! @param uvw[3] A direction. This is both an input and an output parameter. - //! It specifies the icident direction on input and the reflected direction - //! on output. - void reflect(const double xyz[3], double uvw[3]) const; - - //! Evaluate the equation describing the surface. - //! - //! Surfaces can be described by some function f(x, y, z) = 0. This member - //! function evaluates that mathematical function. - //! @param xyz[3] A 3D Cartesian coordinate. - virtual double evaluate(const double xyz[3]) const = 0; - - //! Compute the distance between a point and the surface along a ray. - //! @param xyz[3] A 3D Cartesian coordinate. - //! @param uvw[3] The direction of the ray. - //! @param coincident A hint to the code that the given point should lie - //! exactly on the surface. - virtual double distance(const double xyz[3], const double uvw[3], - bool coincident) const = 0; - - //! Compute the local outward normal direction of the surface. - //! @param xyz[3] A 3D Cartesian coordinate. - //! @param uvw[3] This output argument provides the normal. - virtual void normal(const double xyz[3], double uvw[3]) const = 0; - - //! Write all information needed to reconstruct the surface to an HDF5 group. - //! @param group_id An HDF5 group id. - void to_hdf5(hid_t group_id) const; - -protected: - virtual void to_hdf5_inner(hid_t group_id) const = 0; -}; - Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { @@ -367,34 +227,9 @@ Surface::to_hdf5(hid_t group_id) const } //============================================================================== -//! A `Surface` that supports periodic boundary conditions. -//! -//! Translational periodicity is supported for the `XPlane`, `YPlane`, `ZPlane`, -//! and `Plane` types. Rotational periodicity is supported for -//! `XPlane`-`YPlane` pairs. +// PeriodicSurface implementation //============================================================================== -class PeriodicSurface : public Surface -{ -public: - int i_periodic{C_NONE}; //!< Index of corresponding periodic surface - - PeriodicSurface(pugi::xml_node surf_node); - - //! Translate a particle onto this surface from a periodic partner surface. - //! @param other A pointer to the partner surface in this periodic BC. - //! @param xyz[3] A point on the partner surface that will be translated onto - //! this surface. - //! @param uvw[3] A direction that will be rotated for systems with rotational - //! periodicity. - //! @return true if this surface and its partner make a rotationally-periodic - //! boundary condition. - virtual bool periodic_translate(PeriodicSurface *other, double xyz[3], - double uvw[3]) const = 0; - - virtual struct BoundingBox bounding_box() const = 0; -}; - PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) : Surface(surf_node) { @@ -437,27 +272,9 @@ axis_aligned_plane_normal(const double xyz[3], double uvw[3]) } //============================================================================== -// SurfaceXPlane -//! A plane perpendicular to the x-axis. -// -//! The plane is described by the equation \f$x - x_0 = 0\f$ +// SurfaceXPlane implementation //============================================================================== -class SurfaceXPlane : public PeriodicSurface -{ - double x0; -public: - SurfaceXPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], bool coincident) - const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) - const; - struct BoundingBox bounding_box() const; -}; - SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { @@ -521,27 +338,9 @@ SurfaceXPlane::bounding_box() const } //============================================================================== -// SurfaceYPlane -//! A plane perpendicular to the y-axis. -// -//! The plane is described by the equation \f$y - y_0 = 0\f$ +// SurfaceYPlane implementation //============================================================================== -class SurfaceYPlane : public PeriodicSurface -{ - double y0; -public: - SurfaceYPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) - const; - struct BoundingBox bounding_box() const; -}; - SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { @@ -605,27 +404,9 @@ SurfaceYPlane::bounding_box() const } //============================================================================== -// SurfaceZPlane -//! A plane perpendicular to the z-axis. -// -//! The plane is described by the equation \f$z - z_0 = 0\f$ +// SurfaceZPlane implementation //============================================================================== -class SurfaceZPlane : public PeriodicSurface -{ - double z0; -public: - SurfaceZPlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) - const; - struct BoundingBox bounding_box() const; -}; - SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { @@ -671,27 +452,9 @@ SurfaceZPlane::bounding_box() const } //============================================================================== -// SurfacePlane -//! A general plane. -// -//! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ +// SurfacePlane implementation //============================================================================== -class SurfacePlane : public PeriodicSurface -{ - double A, B, C, D; -public: - SurfacePlane(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], bool coincident) - const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; - bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) - const; - struct BoundingBox bounding_box() const; -}; - SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { @@ -832,25 +595,9 @@ axis_aligned_cylinder_normal(const double xyz[3], double uvw[3], double offset1, } //============================================================================== -// SurfaceXCylinder -//! A cylinder aligned along the x-axis. -// -//! The cylinder is described by the equation -//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +// SurfaceXCylinder implementation //============================================================================== -class SurfaceXCylinder : public Surface -{ - double y0, z0, r; -public: - SurfaceXCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : Surface(surf_node) { @@ -883,25 +630,9 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceYCylinder -//! A cylinder aligned along the y-axis. -// -//! The cylinder is described by the equation -//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +// SurfaceYCylinder implementation //============================================================================== -class SurfaceYCylinder : public Surface -{ - double x0, z0, r; -public: - SurfaceYCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : Surface(surf_node) { @@ -933,25 +664,9 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceZCylinder -//! A cylinder aligned along the z-axis. -// -//! The cylinder is described by the equation -//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ +// SurfaceZCylinder implementation //============================================================================== -class SurfaceZCylinder : public Surface -{ - double x0, y0, r; -public: - SurfaceZCylinder(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : Surface(surf_node) { @@ -983,25 +698,9 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceSphere -//! A sphere. -// -//! The cylinder is described by the equation -//! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +// SurfaceSphere implementation //============================================================================== -class SurfaceSphere : public Surface -{ - double x0, y0, z0, r; -public: - SurfaceSphere(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : Surface(surf_node) { @@ -1153,25 +852,9 @@ axis_aligned_cone_normal(const double xyz[3], double uvw[3], double offset1, } //============================================================================== -// SurfaceXCone -//! A cone aligned along the x-axis. -// -//! The cylinder is described by the equation -//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ +// SurfaceXCone implementation //============================================================================== -class SurfaceXCone : public Surface -{ - double x0, y0, z0, r_sq; -public: - SurfaceXCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : Surface(surf_node) { @@ -1203,25 +886,9 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceYCone -//! A cone aligned along the y-axis. -// -//! The cylinder is described by the equation -//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ +// SurfaceYCone implementation //============================================================================== -class SurfaceYCone : public Surface -{ - double x0, y0, z0, r_sq; -public: - SurfaceYCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : Surface(surf_node) { @@ -1253,25 +920,9 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceZCone -//! A cone aligned along the z-axis. -// -//! The cylinder is described by the equation -//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ +// SurfaceZCone implementation //============================================================================== -class SurfaceZCone : public Surface -{ - double x0, y0, z0, r_sq; -public: - SurfaceZCone(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : Surface(surf_node) { @@ -1303,25 +954,9 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const } //============================================================================== -// SurfaceQuadric -//! A general surface described by a quadratic equation. -// -//! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ +// SurfaceQuadric implementation //============================================================================== -class SurfaceQuadric : public Surface -{ - // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 - double A, B, C, D, E, F, G, H, J, K; -public: - SurfaceQuadric(pugi::xml_node surf_node); - double evaluate(const double xyz[3]) const; - double distance(const double xyz[3], const double uvw[3], - bool coincident) const; - void normal(const double xyz[3], double uvw[3]) const; - void to_hdf5_inner(hid_t group_id) const; -}; - SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : Surface(surf_node) { @@ -1472,9 +1107,10 @@ read_surfaces(pugi::xml_node *node) surfaces_c[i_surf] = new SurfaceQuadric(surf_node); } else { - std::cout << "Call error here!" << std::endl; - std::cout << surf_type << std::endl; - //TODO: call fatal_error + std::string err_msg{"Invalid surface type, \""}; + err_msg += surf_type; + err_msg += "\""; + fatal_error(err_msg); } } } @@ -1592,58 +1228,3 @@ read_surfaces(pugi::xml_node *node) } } } - -//============================================================================== - -extern "C" bool -surface_sense(int surf_ind, double xyz[3], double uvw[3]) -{ - return surfaces_c[surf_ind]->sense(xyz, uvw); -} - -extern "C" void -surface_reflect(int surf_ind, double xyz[3], double uvw[3]) -{ - surfaces_c[surf_ind]->reflect(xyz, uvw); -} - -extern "C" double -surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) -{ - return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); -} - -extern "C" void -surface_normal(int surf_ind, double xyz[3], double uvw[3]) -{ - return surfaces_c[surf_ind]->normal(xyz, uvw); -} - -extern "C" void -surface_to_hdf5(int surf_ind, hid_t group) -{ - surfaces_c[surf_ind]->to_hdf5(group); -} - -extern "C" bool -surface_periodic(int surf_ind1, double xyz[3], double uvw[3]) -{ - // Hopefully this function has only been called for a pair of surfaces that - // support periodic BCs (checking should have been done when reading the - // geometry XML). Downcast the surfaces to the PeriodicSurface type so we - // can call the periodic_translate method. - Surface *surf1_gen = surfaces_c[surf_ind1]; - PeriodicSurface *surf1 = dynamic_cast(surf1_gen); - Surface *surf2_gen = surfaces_c[surf1->i_periodic]; - PeriodicSurface *surf2 = dynamic_cast(surf2_gen); - - // Call the type-bound methods. - return surf2->periodic_translate(surf1, xyz, uvw); -} - -extern "C" int -surface_i_periodic(int surf_ind) -{ - PeriodicSurface *surf = dynamic_cast(surfaces_c[surf_ind]); - return surf->i_periodic; -} diff --git a/src/surface.h b/src/surface.h new file mode 100644 index 000000000..22eb798dc --- /dev/null +++ b/src/surface.h @@ -0,0 +1,431 @@ +#ifndef SURFACE_H +#define SURFACE_H + +#include +#include // For numeric_limits + +#include "hdf5.h" +#include "pugixml/pugixml.hpp" + +//============================================================================== +// Module constants +//============================================================================== + +extern "C" const int BC_TRANSMIT{0}; +extern "C" const int BC_VACUUM{1}; +extern "C" const int BC_REFLECT{2}; +extern "C" const int BC_PERIODIC{3}; + +//============================================================================== +// Constants that should eventually be moved out of this file +//============================================================================== + +extern "C" double FP_COINCIDENT; +const double INFTY{std::numeric_limits::max()}; +const int C_NONE{-1}; + +//============================================================================== +// Global variables +//============================================================================== + +class Surface; +Surface **surfaces_c; + +std::map surface_dict; + +//============================================================================== +//! Coordinates for an axis-aligned cube that bounds a geometric object. +//============================================================================== + +struct BoundingBox +{ + double xmin; + double xmax; + double ymin; + double ymax; + double zmin; + double zmax; +}; + +//============================================================================== +//! A geometry primitive used to define regions of 3D space. +//============================================================================== + +class Surface +{ +public: + int id; //!< Unique ID + //int neighbor_pos[], //!< List of cells on positive side + // neighbor_neg[]; //!< List of cells on negative side + int bc; //!< Boundary condition + std::string name{""}; //!< User-defined name + + Surface(pugi::xml_node surf_node); + + //! Determine which side of a surface a point lies on. + //! @param xyz[3] The 3D Cartesian coordinate of a point. + //! @param uvw[3] A direction used to "break ties" and pick a sense when the + //! point is very close to the surface. + //! @return true if the point is on the "positive" side of the surface and + //! false otherwise. + bool sense(const double xyz[3], const double uvw[3]) const; + + //! Determine the direction of a ray reflected from the surface. + //! @param xyz[3] The point at which the ray is incident. + //! @param uvw[3] A direction. This is both an input and an output parameter. + //! It specifies the icident direction on input and the reflected direction + //! on output. + void reflect(const double xyz[3], double uvw[3]) const; + + //! Evaluate the equation describing the surface. + //! + //! Surfaces can be described by some function f(x, y, z) = 0. This member + //! function evaluates that mathematical function. + //! @param xyz[3] A 3D Cartesian coordinate. + virtual double evaluate(const double xyz[3]) const = 0; + + //! Compute the distance between a point and the surface along a ray. + //! @param xyz[3] A 3D Cartesian coordinate. + //! @param uvw[3] The direction of the ray. + //! @param coincident A hint to the code that the given point should lie + //! exactly on the surface. + virtual double distance(const double xyz[3], const double uvw[3], + bool coincident) const = 0; + + //! Compute the local outward normal direction of the surface. + //! @param xyz[3] A 3D Cartesian coordinate. + //! @param uvw[3] This output argument provides the normal. + virtual void normal(const double xyz[3], double uvw[3]) const = 0; + + //! Write all information needed to reconstruct the surface to an HDF5 group. + //! @param group_id An HDF5 group id. + void to_hdf5(hid_t group_id) const; + +protected: + virtual void to_hdf5_inner(hid_t group_id) const = 0; +}; + +//============================================================================== +//! A `Surface` that supports periodic boundary conditions. +//! +//! Translational periodicity is supported for the `XPlane`, `YPlane`, `ZPlane`, +//! and `Plane` types. Rotational periodicity is supported for +//! `XPlane`-`YPlane` pairs. +//============================================================================== + +class PeriodicSurface : public Surface +{ +public: + int i_periodic{C_NONE}; //!< Index of corresponding periodic surface + + PeriodicSurface(pugi::xml_node surf_node); + + //! Translate a particle onto this surface from a periodic partner surface. + //! @param other A pointer to the partner surface in this periodic BC. + //! @param xyz[3] A point on the partner surface that will be translated onto + //! this surface. + //! @param uvw[3] A direction that will be rotated for systems with rotational + //! periodicity. + //! @return true if this surface and its partner make a rotationally-periodic + //! boundary condition. + virtual bool periodic_translate(PeriodicSurface *other, double xyz[3], + double uvw[3]) const = 0; + + //! Get the bounding box for this surface. + virtual struct BoundingBox bounding_box() const = 0; +}; + +//============================================================================== +//! A plane perpendicular to the x-axis. +// +//! The plane is described by the equation \f$x - x_0 = 0\f$ +//============================================================================== + +class SurfaceXPlane : public PeriodicSurface +{ + double x0; +public: + SurfaceXPlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], bool coincident) + const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; + struct BoundingBox bounding_box() const; +}; + +//============================================================================== +//! A plane perpendicular to the y-axis. +// +//! The plane is described by the equation \f$y - y_0 = 0\f$ +//============================================================================== + +class SurfaceYPlane : public PeriodicSurface +{ + double y0; +public: + SurfaceYPlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; + struct BoundingBox bounding_box() const; +}; + +//============================================================================== +//! A plane perpendicular to the z-axis. +// +//! The plane is described by the equation \f$z - z_0 = 0\f$ +//============================================================================== + +class SurfaceZPlane : public PeriodicSurface +{ + double z0; +public: + SurfaceZPlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; + struct BoundingBox bounding_box() const; +}; + +//============================================================================== +//! A general plane. +// +//! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ +//============================================================================== + +class SurfacePlane : public PeriodicSurface +{ + double A, B, C, D; +public: + SurfacePlane(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], bool coincident) + const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; + bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) + const; + struct BoundingBox bounding_box() const; +}; + +//============================================================================== +//! A cylinder aligned along the x-axis. +// +//! The cylinder is described by the equation +//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +//============================================================================== + +class SurfaceXCylinder : public Surface +{ + double y0, z0, r; +public: + SurfaceXCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A cylinder aligned along the y-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +//============================================================================== + +class SurfaceYCylinder : public Surface +{ + double x0, z0, r; +public: + SurfaceYCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A cylinder aligned along the z-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ +//============================================================================== + +class SurfaceZCylinder : public Surface +{ + double x0, y0, r; +public: + SurfaceZCylinder(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A sphere. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ +//============================================================================== + +class SurfaceSphere : public Surface +{ + double x0, y0, z0, r; +public: + SurfaceSphere(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A cone aligned along the x-axis. +// +//! The cylinder is described by the equation +//! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ +//============================================================================== + +class SurfaceXCone : public Surface +{ + double x0, y0, z0, r_sq; +public: + SurfaceXCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A cone aligned along the y-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ +//============================================================================== + +class SurfaceYCone : public Surface +{ + double x0, y0, z0, r_sq; +public: + SurfaceYCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A cone aligned along the z-axis. +// +//! The cylinder is described by the equation +//! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ +//============================================================================== + +class SurfaceZCone : public Surface +{ + double x0, y0, z0, r_sq; +public: + SurfaceZCone(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +//! A general surface described by a quadratic equation. +// +//! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ +//============================================================================== + +class SurfaceQuadric : public Surface +{ + // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 + double A, B, C, D, E, F, G, H, J, K; +public: + SurfaceQuadric(pugi::xml_node surf_node); + double evaluate(const double xyz[3]) const; + double distance(const double xyz[3], const double uvw[3], + bool coincident) const; + void normal(const double xyz[3], double uvw[3]) const; + void to_hdf5_inner(hid_t group_id) const; +}; + +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" bool +surface_sense(int surf_ind, double xyz[3], double uvw[3]) +{ + return surfaces_c[surf_ind]->sense(xyz, uvw); +} + +extern "C" void +surface_reflect(int surf_ind, double xyz[3], double uvw[3]) +{ + surfaces_c[surf_ind]->reflect(xyz, uvw); +} + +extern "C" double +surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) +{ + return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); +} + +extern "C" void +surface_normal(int surf_ind, double xyz[3], double uvw[3]) +{ + return surfaces_c[surf_ind]->normal(xyz, uvw); +} + +extern "C" void +surface_to_hdf5(int surf_ind, hid_t group) +{ + surfaces_c[surf_ind]->to_hdf5(group); +} + +extern "C" bool +surface_periodic(int surf_ind1, double xyz[3], double uvw[3]) +{ + // Hopefully this function has only been called for a pair of surfaces that + // support periodic BCs (checking should have been done when reading the + // geometry XML). Downcast the surfaces to the PeriodicSurface type so we + // can call the periodic_translate method. + Surface *surf1_gen = surfaces_c[surf_ind1]; + PeriodicSurface *surf1 = dynamic_cast(surf1_gen); + Surface *surf2_gen = surfaces_c[surf1->i_periodic]; + PeriodicSurface *surf2 = dynamic_cast(surf2_gen); + + // Call the type-bound methods. + return surf2->periodic_translate(surf1, xyz, uvw); +} + +extern "C" int +surface_i_periodic(int surf_ind) +{ + PeriodicSurface *surf = dynamic_cast(surfaces_c[surf_ind]); + return surf->i_periodic; +} + +#endif // SURFACE_H diff --git a/src/xml_interface.h b/src/xml_interface.h new file mode 100644 index 000000000..fbc82e056 --- /dev/null +++ b/src/xml_interface.h @@ -0,0 +1,52 @@ +#ifndef XML_INTERFACE_H +#define XML_INTERFACE_H + +#include // for std::transform +#include + +#include "pugixml/pugixml.hpp" + + +bool +check_for_node(const pugi::xml_node &node, const char *name) +{ + if (node.attribute(name)) { + return true; + } else if (node.child(name)) { + return true; + } else { + return false; + } +} + + +std::string +get_node_value(const pugi::xml_node &node, const char *name) +{ + // Search for either an attribute or child tag and get the data as a char*. + const pugi::char_t *value_char; + if (node.attribute(name)) { + value_char = node.attribute(name).value(); + } else if (node.child(name)) { + value_char = node.child_value(name); + } else { + std::string err_msg("Node \""); + err_msg += name; + err_msg += "\" is not a memeber of the \""; + err_msg += node.name(); + err_msg += "\" XML node"; + fatal_error(err_msg); + } + + // Convert to lowercase string. + std::string value(value_char); + std::transform(value.begin(), value.end(), value.begin(), ::tolower); + + // Remove whitespace. + value.erase(0, value.find_first_not_of(" \t\r\n")); + value.erase(value.find_last_not_of(" \t\r\n") + 1); + + return value; +} + +#endif // XML_INTERFACE_H From 75501a08e931ed64011205bbd612e708eb0bb670 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 24 Jan 2018 11:56:20 -0500 Subject: [PATCH 18/21] Add C++ Surface pointers to Fortran Surfaces --- src/geometry.F90 | 68 +--------- src/input_xml.F90 | 60 +-------- src/output.F90 | 2 +- src/summary.F90 | 15 +-- src/surface.cpp | 13 +- src/surface.h | 72 +++++------ src/surface_header.F90 | 180 ++++++++++++++++++++++++++- src/tallies/tally_filter_surface.F90 | 2 +- src/tracking.F90 | 43 ++++--- 9 files changed, 252 insertions(+), 203 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index d1519f8d2..0bacd7b5d 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -14,66 +14,6 @@ module geometry implicit none - interface - pure function surface_sense_c(surf_ind, xyz, uvw) & - bind(C, name='surface_sense') result(sense) - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind; - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(in) :: uvw(3); - logical(C_BOOL) :: sense; - end function surface_sense_c - - pure subroutine surface_reflect_c(surf_ind, xyz, uvw) & - bind(C, name='surface_reflect') - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind; - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(inout) :: uvw(3); - end subroutine surface_reflect_c - - pure function surface_distance_c(surf_ind, xyz, uvw, coincident) & - bind(C, name='surface_distance') result(d) - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind; - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(in) :: uvw(3); - logical(C_BOOL), intent(in), value :: coincident; - real(C_DOUBLE) :: d; - end function surface_distance_c - - pure subroutine surface_normal_c(surf_ind, xyz, uvw) & - bind(C, name='surface_normal') - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind; - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(out) :: uvw(3); - end subroutine surface_normal_c - - function surface_periodic_c(surf_ind1, xyz, uvw) & - bind(C, name="surface_periodic") result(rotational) - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind1; - real(C_DOUBLE), intent(inout) :: xyz(3); - real(C_DOUBLE), intent(inout) :: uvw(3); - logical(C_BOOL) :: rotational - end function surface_periodic_c - - function surface_i_periodic_c(surf_ind) bind(C, name="surface_i_periodic") & - result(i_periodic) - use ISO_C_BINDING - implicit none - integer(C_INT), intent(in), value :: surf_ind - integer(C_INT) :: i_periodic - end function - - end interface - contains !=============================================================================== @@ -125,7 +65,7 @@ contains in_cell = .false. exit else - actual_sense = surface_sense_c(abs(token)-1, & + actual_sense = surfaces(abs(token)) % sense( & p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) if (actual_sense .neqv. (token > 0)) then in_cell = .false. @@ -174,7 +114,7 @@ contains elseif (-token == p%surface) then stack(i_stack) = .false. else - actual_sense = surface_sense_c(abs(token)-1, & + actual_sense = surfaces(abs(token)) % sense( & p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) stack(i_stack) = (actual_sense .eqv. (token > 0)) end if @@ -579,7 +519,7 @@ contains if (index_surf >= OP_UNION) cycle ! Calculate distance to surface - d = surface_distance_c(index_surf-1, p % coord(j) % xyz, & + d = surfaces(index_surf) % distance(p % coord(j) % xyz, & p % coord(j) % uvw, logical(coincident, kind=C_BOOL)) ! Check if calculated distance is new minimum @@ -799,7 +739,7 @@ contains ! traveling into if the surface is crossed if (.not. c % simple) then xyz_cross(:) = p % coord(j) % xyz + d_surf*p % coord(j) % uvw - call surface_normal_c(abs(level_surf_cross)-1, xyz_cross, surf_uvw) + call surfaces(abs(level_surf_cross)) % normal(xyz_cross, surf_uvw) if (dot_product(p % coord(j) % uvw, surf_uvw) > ZERO) then surface_crossed = abs(level_surf_cross) else diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 9b6e1c6fc..55eeca9e1 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -924,19 +924,15 @@ contains logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename - character(MAX_WORD_LEN) :: word character(MAX_WORD_LEN), allocatable :: sarray(:) character(:), allocatable :: region_spec type(Cell), pointer :: c - class(Surface), pointer :: s class(Lattice), pointer :: lat type(XMLDocument) :: doc type(XMLNode) :: root type(XMLNode) :: node_cell - type(XMLNode) :: node_surf type(XMLNode) :: node_lat type(XMLNode), allocatable :: node_cell_list(:) - type(XMLNode), allocatable :: node_surf_list(:) type(XMLNode), allocatable :: node_rlat_list(:) type(XMLNode), allocatable :: node_hlat_list(:) type(VectorInt) :: tokens @@ -968,66 +964,18 @@ contains ! applied to a surface boundary_exists = .false. - ! get pointer to list of xml - call get_node_list(root, "surface", node_surf_list) call read_surfaces(root % ptr) - ! Get number of tags - n_surfaces = size(node_surf_list) - - ! Check for no surfaces - if (n_surfaces == 0) then - call fatal_error("No surfaces found in geometry.xml!") - end if - - ! Allocate cells array + ! Allocate surfaces array allocate(surfaces(n_surfaces)) do i = 1, n_surfaces - ! Get pointer to i-th surface node - node_surf = node_surf_list(i) + surfaces(i) % ptr = surface_pointer_c(i - 1); - s => surfaces(i) + if (surfaces(i) % bc() /= BC_TRANSMIT) boundary_exists = .true. - ! 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(s%id)) then - call fatal_error("Two or more surfaces use the same unique ID: " & - // to_str(s%id)) - end if - - ! Check to make sure that the proper number of coefficients - ! have been specified for the given type of surface. Then copy - ! surface coordinates. - - ! Boundary conditions - word = '' - if (check_for_node(node_surf, "boundary")) & - call get_node_value(node_surf, "boundary", word) - select case (to_lower(word)) - case ('transmission', 'transmit', '') - s%bc = BC_TRANSMIT - case ('vacuum') - s%bc = BC_VACUUM - boundary_exists = .true. - case ('reflective', 'reflect', 'reflecting') - s%bc = BC_REFLECT - boundary_exists = .true. - case ('periodic') - s%bc = BC_PERIODIC - boundary_exists = .true. - case default - call fatal_error("Unknown boundary condition '" // trim(word) // & - &"' specified on surface " // trim(to_str(s%id))) - end select ! Add surface to dictionary - call surface_dict % set(s%id, i) + call surface_dict % set(surfaces(i) % 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 4113eea47..316fe9594 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -259,7 +259,7 @@ contains ! Print surface if (p % surface /= NONE) then - write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%id, p % surface)) + write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%id(), p % surface)) end if ! Display weight, energy, grid index, and interpolation factor diff --git a/src/summary.F90 b/src/summary.F90 index 9b82a0396..3aeb42178 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -24,17 +24,6 @@ module summary public :: write_summary - interface - subroutine surface_to_hdf5_c(surf_ind, group) & - bind(C, name='surface_to_hdf5') - use ISO_C_BINDING - use hdf5 - implicit none - integer(C_INT), intent(in), value :: surf_ind - integer(HID_T), intent(in), value :: group - end subroutine surface_to_hdf5_c - end interface - contains !=============================================================================== @@ -232,7 +221,7 @@ contains region_spec = trim(region_spec) // " |" case default region_spec = trim(region_spec) // " " // to_str(& - sign(surfaces(abs(k))%id, k)) + sign(surfaces(abs(k))%id(), k)) end select end do call write_dataset(cell_group, "region", adjustl(region_spec)) @@ -250,7 +239,7 @@ contains ! Write information on each surface SURFACE_LOOP: do i = 1, n_surfaces - call surface_to_hdf5_c(i-1, surfaces_group) + call surfaces(i) % to_hdf5(surfaces_group) end do SURFACE_LOOP call close_group(surfaces_group) diff --git a/src/surface.cpp b/src/surface.cpp index ed111b037..369334d50 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1053,11 +1053,13 @@ extern "C" void read_surfaces(pugi::xml_node *node) { // Count the number of surfaces. - int n_surfaces{0}; for (pugi::xml_node surf_node = node->child("surface"); surf_node; surf_node = surf_node.next_sibling("surface")) { n_surfaces++; } + if (n_surfaces == 0) { + fatal_error("No surfaces found in geometry.xml!"); + } // Allocate the array of Surface pointers. surfaces_c = new Surface* [n_surfaces]; @@ -1137,7 +1139,14 @@ read_surfaces(pugi::xml_node *node) // Downcast to the PeriodicSurface type. Surface *surf_base = surfaces_c[i_surf]; PeriodicSurface *surf = dynamic_cast(surf_base); - //TODO: check for null pointer + + // Make sure this surface inherits from PeriodicSurface. + if (surf == NULL) { + std::string err_msg{"Periodic boundary condition not supported for " + "surface "}; + err_msg += std::to_string(surf_base->id); + err_msg += ". Periodic BCs are only supported for planar surfaces."; + } // See if this surface makes part of the global bounding box. struct BoundingBox bb = surf->bounding_box(); diff --git a/src/surface.h b/src/surface.h index 22eb798dc..469d88486 100644 --- a/src/surface.h +++ b/src/surface.h @@ -28,6 +28,8 @@ const int C_NONE{-1}; // Global variables //============================================================================== +int n_surfaces{0}; + class Surface; Surface **surfaces_c; @@ -375,57 +377,43 @@ public: // Fortran compatibility functions //============================================================================== -extern "C" bool -surface_sense(int surf_ind, double xyz[3], double uvw[3]) -{ - return surfaces_c[surf_ind]->sense(xyz, uvw); -} +extern "C" Surface* surface_pointer(int surf_ind) {return surfaces_c[surf_ind];} -extern "C" void -surface_reflect(int surf_ind, double xyz[3], double uvw[3]) -{ - surfaces_c[surf_ind]->reflect(xyz, uvw); -} +extern "C" int surface_id(Surface *surf) {return surf->id;} + +extern "C" int surface_bc(Surface *surf) {return surf->bc;} + +extern "C" bool surface_sense(Surface *surf, double xyz[3], double uvw[3]) +{return surf->sense(xyz, uvw);} + +extern "C" void surface_reflect(Surface *surf, double xyz[3], double uvw[3]) +{surf->reflect(xyz, uvw);} extern "C" double -surface_distance(int surf_ind, double xyz[3], double uvw[3], bool coincident) -{ - return surfaces_c[surf_ind]->distance(xyz, uvw, coincident); -} +surface_distance(Surface *surf, double xyz[3], double uvw[3], bool coincident) +{return surf->distance(xyz, uvw, coincident);} -extern "C" void -surface_normal(int surf_ind, double xyz[3], double uvw[3]) -{ - return surfaces_c[surf_ind]->normal(xyz, uvw); -} +extern "C" void surface_normal(Surface *surf, double xyz[3], double uvw[3]) +{return surf->normal(xyz, uvw);} -extern "C" void -surface_to_hdf5(int surf_ind, hid_t group) -{ - surfaces_c[surf_ind]->to_hdf5(group); -} +extern "C" void surface_to_hdf5(Surface *surf, hid_t group) +{surf->to_hdf5(group);} + +extern "C" int surface_i_periodic(PeriodicSurface *surf) +{return surf->i_periodic;} extern "C" bool -surface_periodic(int surf_ind1, double xyz[3], double uvw[3]) -{ - // Hopefully this function has only been called for a pair of surfaces that - // support periodic BCs (checking should have been done when reading the - // geometry XML). Downcast the surfaces to the PeriodicSurface type so we - // can call the periodic_translate method. - Surface *surf1_gen = surfaces_c[surf_ind1]; - PeriodicSurface *surf1 = dynamic_cast(surf1_gen); - Surface *surf2_gen = surfaces_c[surf1->i_periodic]; - PeriodicSurface *surf2 = dynamic_cast(surf2_gen); +surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, double xyz[3], + double uvw[3]) +{return surf->periodic_translate(other, xyz, uvw);} - // Call the type-bound methods. - return surf2->periodic_translate(surf1, xyz, uvw); -} - -extern "C" int -surface_i_periodic(int surf_ind) +extern "C" void free_memory_surfaces_c() { - PeriodicSurface *surf = dynamic_cast(surfaces_c[surf_ind]); - return surf->i_periodic; + for (int i = 0; i < n_surfaces; i++) {delete surfaces_c[i];} + delete surfaces_c; + surfaces_c = NULL; + n_surfaces = 0; + surface_dict.clear(); } #endif // SURFACE_H diff --git a/src/surface_header.F90 b/src/surface_header.F90 index ffe0a6db4..8985e8406 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -1,26 +1,132 @@ module surface_header use, intrinsic :: ISO_C_BINDING + use hdf5 - use constants, only: NONE use dict_header, only: DictIntInt implicit none + interface + pure function surface_pointer_c(surf_ind) & + bind(C, name='surface_pointer') result(ptr) + use ISO_C_BINDING + implicit none + integer(C_INT), intent(in), value :: surf_ind + type(C_PTR) :: ptr + end function surface_pointer_c + + pure function surface_id_c(surf_ptr) bind(C, name='surface_id') result(id) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + integer(C_INT) :: id + end function surface_id_c + + pure function surface_bc_c(surf_ptr) bind(C, name='surface_bc') result(bc) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + integer(C_INT) :: bc + end function surface_bc_c + + pure function surface_sense_c(surf_ptr, xyz, uvw) & + bind(C, name='surface_sense') result(sense) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + logical(C_BOOL) :: sense + end function surface_sense_c + + pure subroutine surface_reflect_c(surf_ptr, xyz, uvw) & + bind(C, name='surface_reflect') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + end subroutine surface_reflect_c + + pure function surface_distance_c(surf_ptr, xyz, uvw, coincident) & + bind(C, name='surface_distance') result(d) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(in) :: uvw(3); + logical(C_BOOL), intent(in), value :: coincident; + real(C_DOUBLE) :: d; + end function surface_distance_c + + pure subroutine surface_normal_c(surf_ptr, xyz, uvw) & + bind(C, name='surface_normal') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(out) :: uvw(3); + end subroutine surface_normal_c + + subroutine surface_to_hdf5_c(surf_ptr, group) & + bind(C, name='surface_to_hdf5') + use ISO_C_BINDING + use hdf5 + implicit none + type(C_PTR), intent(in), value :: surf_ptr + integer(HID_T), intent(in), value :: group + end subroutine surface_to_hdf5_c + + pure function surface_i_periodic_c(surf_ptr) & + bind(C, name="surface_i_periodic") result(i_periodic) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + integer(C_INT) :: i_periodic + end function surface_i_periodic_c + + function surface_periodic_c(surf_ptr, other_ptr, xyz, uvw) & + bind(C, name="surface_periodic") result(rotational) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: surf_ptr + type(C_PTR), intent(in), value :: other_ptr + real(C_DOUBLE), intent(inout) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + logical(C_BOOL) :: rotational + end function surface_periodic_c + + subroutine free_memory_surfaces_c() bind(C) + end subroutine free_memory_surfaces_c + end interface + !=============================================================================== ! SURFACE type defines a first- or second-order surface that can be used to ! construct closed volumes (cells) !=============================================================================== type :: 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 + type(C_PTR) :: ptr + + contains + + procedure :: id => surface_id + procedure :: bc => surface_bc + procedure :: sense => surface_sense + procedure :: reflect => surface_reflect + procedure :: distance => surface_distance + procedure :: normal => surface_normal + procedure :: to_hdf5 => surface_to_hdf5 + procedure :: i_periodic => surface_i_periodic + procedure :: periodic_translate => surface_periodic + end type Surface - integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces + integer(C_INT), bind(C) :: n_surfaces ! # of surfaces type(Surface), allocatable, target :: surfaces(:) @@ -29,14 +135,78 @@ module surface_header contains + pure function surface_id(this) result(id) + class(Surface), intent(in) :: this + integer(C_INT) :: id + id = surface_id_c(this % ptr) + end function surface_id + + pure function surface_bc(this) result(bc) + class(Surface), intent(in) :: this + integer(C_INT) :: bc + bc = surface_bc_c(this % ptr) + end function surface_bc + + pure function surface_sense(this, xyz, uvw) result(sense) + class(Surface), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + logical(C_BOOL) :: sense + sense = surface_sense_c(this % ptr, xyz, uvw) + end function surface_sense + + pure subroutine surface_reflect(this, xyz, uvw) + class(Surface), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + call surface_reflect_c(this % ptr, xyz, uvw) + end subroutine surface_reflect + + pure function surface_distance(this, xyz, uvw, coincident) result(d) + class(Surface), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(in) :: uvw(3); + logical(C_BOOL), intent(in) :: coincident; + real(C_DOUBLE) :: d; + d = surface_distance_c(this % ptr, xyz, uvw, coincident) + end function surface_distance + + pure subroutine surface_normal(this, xyz, uvw) + class(Surface), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3); + real(C_DOUBLE), intent(out) :: uvw(3); + call surface_normal_c(this % ptr, xyz, uvw) + end subroutine surface_normal + + subroutine surface_to_hdf5(this, group) + class(Surface), intent(in) :: this + integer(HID_T), intent(in) :: group + call surface_to_hdf5_c(this % ptr, group) + end subroutine surface_to_hdf5 + + pure function surface_i_periodic(this) result(i_periodic) + class(Surface), intent(in) :: this + integer(C_INT) :: i_periodic + i_periodic = surface_i_periodic_c(this % ptr) + end function surface_i_periodic + + function surface_periodic(this, other, xyz, uvw) result(rotational) + class(Surface), intent(in) :: this + class(Surface), intent(in) :: other + real(C_DOUBLE), intent(inout) :: xyz(3); + real(C_DOUBLE), intent(inout) :: uvw(3); + logical(C_BOOL) :: rotational + rotational = surface_periodic_c(this % ptr, other % ptr, xyz, uvw) + end function surface_periodic + !=============================================================================== ! FREE_MEMORY_SURFACES deallocates global arrays defined in this module !=============================================================================== subroutine free_memory_surfaces() - n_surfaces = 0 if (allocated(surfaces)) deallocate(surfaces) call surface_dict % clear() + call free_memory_surfaces_c() end subroutine free_memory_surfaces end module surface_header diff --git a/src/tallies/tally_filter_surface.F90 b/src/tallies/tally_filter_surface.F90 index 6a2afa3ec..df3bf3603 100644 --- a/src/tallies/tally_filter_surface.F90 +++ b/src/tallies/tally_filter_surface.F90 @@ -105,7 +105,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Surface " // to_str(surfaces(this % surfaces(bin)) % id) + label = "Surface " // to_str(surfaces(this % surfaces(bin)) % id()) end function text_label_surface end module tally_filter_surface diff --git a/src/tracking.F90 b/src/tracking.F90 index 98bca2a27..75555c797 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -4,9 +4,8 @@ module tracking use cross_section, only: calculate_xs use error, only: fatal_error, warning, write_message use geometry_header, only: cells - use geometry, only: find_cell, distance_to_boundary, cross_lattice, & - check_cell_overlap, surface_reflect_c, & - surface_periodic_c, surface_i_periodic_c + use geometry, only: find_cell, distance_to_boundary, cross_lattice,& + check_cell_overlap use message_passing use mgxs_header use nuclide_header @@ -296,14 +295,15 @@ contains logical :: rotational ! if rotational periodic BC applied logical :: found ! particle found in universe? class(Surface), pointer :: surf + class(Surface), pointer :: surf2 ! periodic partner surface 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))) + call write_message(" Crossing surface " // trim(to_str(surf % id()))) end if - if (surf % bc == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then + if (surf % bc() == BC_VACUUM .and. (run_mode /= MODE_PLOTTING)) then ! ======================================================================= ! PARTICLE LEAKS OUT OF PROBLEM @@ -328,11 +328,11 @@ contains ! Display message if (verbosity >= 10 .or. trace) then call write_message(" Leaked out of surface " & - &// trim(to_str(surf % id))) + &// trim(to_str(surf % id()))) end if return - elseif (surf % bc == BC_REFLECT .and. (run_mode /= MODE_PLOTTING)) then + elseif (surf % bc() == BC_REFLECT .and. (run_mode /= MODE_PLOTTING)) then ! ======================================================================= ! PARTICLE REFLECTS FROM SURFACE @@ -355,7 +355,7 @@ contains end if ! Reflect particle off surface - call surface_reflect_c(i_surface-1, p%coord(1)%xyz, p%coord(1)%uvw) + call surf % reflect(p%coord(1)%xyz, p%coord(1)%uvw) ! Make sure new particle direction is normalized u = p%coord(1)%uvw(1) @@ -376,7 +376,7 @@ contains call find_cell(p, found) if (.not. found) then call p % mark_as_lost("Couldn't find particle after reflecting& - & from surface " // trim(to_str(surf % id)) // ".") + & from surface " // trim(to_str(surf % id())) // ".") return end if @@ -386,10 +386,10 @@ contains ! Diagnostic message if (verbosity >= 10 .or. trace) then call write_message(" Reflected from surface " & - &// trim(to_str(surf%id))) + &// trim(to_str(surf%id()))) end if return - elseif (surf % bc == BC_PERIODIC .and. run_mode /= MODE_PLOTTING) then + elseif (surf % bc() == BC_PERIODIC .and. run_mode /= MODE_PLOTTING) then ! ======================================================================= ! PERIODIC BOUNDARY @@ -404,7 +404,6 @@ contains ! Score surface currents since reflection causes the direction of the ! particle to change -- artificially move the particle slightly back in ! case the surface crossing is coincident with a mesh boundary - if (active_current_tallies % size() > 0) then xyz = p % coord(1) % xyz p % coord(1) % xyz = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw @@ -412,14 +411,19 @@ contains p % coord(1) % xyz = xyz end if - rotational = surface_periodic_c(i_surface-1, p % coord(1) % xyz, & - p % coord(1) % uvw) + ! Get a pointer to the partner periodic surface. Offset the index to + ! correct for C vs. Fortran indexing. + surf2 => surfaces(surf % i_periodic() + 1) + + ! Adjust the particle's location and direction. + rotational = surf2 % periodic_translate(surf, p % coord(1) % xyz, & + p % coord(1) % uvw) ! Reassign particle's surface if (rotational) then - p % surface = surface_i_periodic_c(i_surface-1) + 1 + p % surface = surf % i_periodic() + 1 else - p % surface = sign(surface_i_periodic_c(i_surface-1) + 1, p % surface) + p % surface = sign(surf % i_periodic() + 1, p % surface) end if ! Figure out what cell particle is in now @@ -427,7 +431,8 @@ contains call find_cell(p, found) if (.not. found) then call p % mark_as_lost("Couldn't find particle after hitting & - &periodic boundary on surface " // trim(to_str(surf % id)) // ".") + &periodic boundary on surface " // trim(to_str(surf % id())) & + // ".") return end if @@ -437,7 +442,7 @@ contains ! Diagnostic message if (verbosity >= 10 .or. trace) then call write_message(" Hit periodic boundary on surface " & - // trim(to_str(surf%id))) + // trim(to_str(surf%id()))) end if return end if @@ -484,7 +489,7 @@ contains if (.not. found) then call p % mark_as_lost("After particle " // trim(to_str(p % id)) & - // " crossed surface " // trim(to_str(surf % id)) & + // " crossed surface " // trim(to_str(surf % id())) & // " it could not be located in any cell and it did not leak.") return end if From 52905d4364bfead5d1c11fb1acbcd7128d08b95d Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 31 Jan 2018 15:28:36 -0500 Subject: [PATCH 19/21] Address #959 comments --- src/error.F90 | 6 +- src/error.h | 12 +++ src/hdf5_interface.h | 4 + src/random_lcg.cpp | 5 ++ src/random_lcg.h | 4 + src/surface.cpp | 188 ++++++++++++++++++++--------------------- src/surface.h | 24 ++++-- src/surface_header.F90 | 2 +- src/xml_interface.h | 24 +++--- 9 files changed, 147 insertions(+), 122 deletions(-) diff --git a/src/error.F90 b/src/error.F90 index cba137291..0a5af302d 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -195,9 +195,9 @@ contains end subroutine fatal_error subroutine fatal_error_from_c(message, message_len) bind(C) - integer(C_INT), intent(in), value :: message_len - character(C_CHAR), intent(in) :: message(message_len) - character(message_len+1) :: message_out + integer(C_INT), intent(in), value :: message_len + character(kind=C_CHAR), intent(in) :: message(message_len) + character(message_len+1) :: message_out write(message_out, *) message call fatal_error(message_out) end subroutine diff --git a/src/error.h b/src/error.h index 0fd78a6c5..4c3373b3e 100644 --- a/src/error.h +++ b/src/error.h @@ -3,6 +3,10 @@ #include #include +#include + + +namespace openmc { extern "C" void fatal_error_from_c(const char *message, int message_len); @@ -19,4 +23,12 @@ void fatal_error(const std::string &message) fatal_error_from_c(message.c_str(), message.length()); } + +void fatal_error(const std::stringstream &message) +{ + std::string out {message.str()}; + fatal_error_from_c(out.c_str(), out.length()); +} + +} // namespace openmc #endif // ERROR_H diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 2cded21f6..7ec9ada9b 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -9,6 +9,9 @@ #include "error.h" +namespace openmc { + + hid_t create_group(hid_t parent_id, char const *name) { @@ -84,4 +87,5 @@ write_string(hid_t group_id, char const *name, const std::string &buffer) write_string(group_id, name, buffer.c_str()); } +} // namespace openmc #endif //HDF5_INTERFACE_H diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index 047bda8e5..2dcdd86a3 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -2,6 +2,9 @@ #include +namespace openmc { + + // Constants extern "C" const int N_STREAMS {5}; extern "C" const int STREAM_TRACKING {0}; @@ -143,3 +146,5 @@ openmc_set_seed(int64_t new_seed) } return 0; } + +} // namespace openmc diff --git a/src/random_lcg.h b/src/random_lcg.h index 04191254f..cd065474e 100644 --- a/src/random_lcg.h +++ b/src/random_lcg.h @@ -3,6 +3,9 @@ #include + +namespace openmc { + //============================================================================== // Module constants. //============================================================================== @@ -82,4 +85,5 @@ extern "C" void prn_set_stream(int n); extern "C" int openmc_set_seed(int64_t new_seed); +} // namespace openmc #endif // RANDOM_LCG_H diff --git a/src/surface.cpp b/src/surface.cpp index 369334d50..16f333f7e 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1,11 +1,15 @@ +#include "surface.h" + #include -#include // For fabs +#include #include "error.h" #include "hdf5_interface.h" #include "xml_interface.h" +#include -#include "surface.h" + +namespace openmc { //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element @@ -14,7 +18,7 @@ int word_count(const std::string &text) { bool in_word = false; - int count{0}; + int count {0}; for (auto c = text.begin(); c != text.end(); c++) { if (std::isspace(*c)) { if (in_word) { @@ -35,10 +39,9 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1) std::string coeffs = get_node_value(surf_node, "coeffs"); int n_words = word_count(coeffs); if (n_words != 1) { - std::string err_msg{"Surface "}; - err_msg += std::to_string(surf_id); - err_msg += " expects 1 coeff but was given "; - err_msg += std::to_string(n_words); + std::stringstream err_msg; + err_msg << "Surface " << surf_id << " expects 1 coeff but was given " + << n_words; fatal_error(err_msg); } @@ -56,10 +59,9 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, std::string coeffs = get_node_value(surf_node, "coeffs"); int n_words = word_count(coeffs); if (n_words != 3) { - std::string err_msg{"Surface "}; - err_msg += std::to_string(surf_id); - err_msg += " expects 3 coeffs but was given "; - err_msg += std::to_string(n_words); + std::stringstream err_msg; + err_msg << "Surface " << surf_id << " expects 3 coeffs but was given " + << n_words; fatal_error(err_msg); } @@ -77,10 +79,9 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, std::string coeffs = get_node_value(surf_node, "coeffs"); int n_words = word_count(coeffs); if (n_words != 4) { - std::string err_msg{"Surface "}; - err_msg += std::to_string(surf_id); - err_msg += " expects 4 coeffs but was given "; - err_msg += std::to_string(n_words); + std::stringstream err_msg; + err_msg << "Surface " << surf_id << " expects 4 coeffs but was given " + << n_words; fatal_error(err_msg); } @@ -99,10 +100,9 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, std::string coeffs = get_node_value(surf_node, "coeffs"); int n_words = word_count(coeffs); if (n_words != 10) { - std::string err_msg{"Surface "}; - err_msg += std::to_string(surf_id); - err_msg += " expects 10 coeffs but was given "; - err_msg += std::to_string(n_words); + std::stringstream err_msg; + err_msg << "Surface " << surf_id << " expects 10 coeffs but was given " + << n_words; fatal_error(err_msg); } @@ -133,23 +133,21 @@ Surface::Surface(pugi::xml_node surf_node) if (check_for_node(surf_node, "boundary")) { std::string surf_bc = get_node_value(surf_node, "boundary"); - if (surf_bc.compare("transmission") == 0 - or surf_bc.compare("transmit") == 0 - or surf_bc.compare("") == 0) { + if (surf_bc == "transmission" || surf_bc == "transmit" ||surf_bc.empty()) { bc = BC_TRANSMIT; - } else if (surf_bc.compare("vacuum") == 0) { + } else if (surf_bc == "vacuum") { bc = BC_VACUUM; - } else if (surf_bc.compare("reflective") == 0 - or surf_bc.compare("reflect") == 0 - or surf_bc.compare("reflecting") == 0) { + } else if (surf_bc == "reflective" || surf_bc == "reflect" + || surf_bc == "reflecting") { bc = BC_REFLECT; - } else if (surf_bc.compare("periodic") == 0) { + } else if (surf_bc == "periodic") { bc = BC_PERIODIC; } else { - std::string err_msg("Unknown boundary condition \""); - err_msg += surf_bc + "\" specified on surface " + std::to_string(id); + std::stringstream err_msg; + err_msg << "Unknown boundary condition \"" << surf_bc + << "\" specified on surface " << id; fatal_error(err_msg); } @@ -167,7 +165,7 @@ Surface::sense(const double xyz[3], const double uvw[3]) const const double f = evaluate(xyz); // Check which side of surface the point is on. - if (fabs(f) < FP_COINCIDENT) { + if (std::abs(f) < FP_COINCIDENT) { // 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. @@ -197,7 +195,7 @@ Surface::reflect(const double xyz[3], double uvw[3]) const void Surface::to_hdf5(hid_t group_id) const { - std::string group_name{"surface "}; + std::string group_name {"surface "}; group_name += std::to_string(id); hid_t surf_group = create_group(group_id, group_name); @@ -217,7 +215,7 @@ Surface::to_hdf5(hid_t group_id) const break; } - if (name.compare("")) { + if (!name.empty()) { write_string(surf_group, "name", name); } @@ -231,7 +229,7 @@ Surface::to_hdf5(hid_t group_id) const //============================================================================== PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) - : Surface(surf_node) + : Surface {surf_node} { if (check_for_node(surf_node, "periodic_surface_id")) { i_periodic = stoi(get_node_value(surf_node, "periodic_surface_id")); @@ -255,7 +253,7 @@ axis_aligned_plane_distance(const double xyz[3], const double uvw[3], bool coincident, double offset) { const double f = offset - xyz[i]; - if (coincident or fabs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY; + if (coincident or std::abs(f) < FP_COINCIDENT or uvw[i] == 0.0) return INFTY; const double d = f / uvw[i]; if (d < 0.0) return INFTY; return d; @@ -300,7 +298,7 @@ inline void SurfaceXPlane::normal(const double xyz[3], double uvw[3]) const void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-plane"); - std::array coeffs{{x0}}; + std::array coeffs {{x0}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -320,7 +318,6 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], double y0 = -other->evaluate(xyz_test); xyz[1] = xyz[0] - x0 + y0; xyz[0] = x0; - xyz[2] = xyz[2]; double u = uvw[0]; uvw[0] = -uvw[1]; @@ -330,10 +327,10 @@ bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], } } -struct BoundingBox +BoundingBox SurfaceXPlane::bounding_box() const { - struct BoundingBox out{x0, x0, -INFTY, INFTY, -INFTY, INFTY}; + BoundingBox out {x0, x0, -INFTY, INFTY, -INFTY, INFTY}; return out; } @@ -366,7 +363,7 @@ inline void SurfaceYPlane::normal(const double xyz[3], double uvw[3]) const void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-plane"); - std::array coeffs{{y0}}; + std::array coeffs {{y0}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -396,10 +393,10 @@ bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], } } -struct BoundingBox +BoundingBox SurfaceYPlane::bounding_box() const { - struct BoundingBox out{-INFTY, INFTY, y0, y0, -INFTY, INFTY}; + BoundingBox out {-INFTY, INFTY, y0, y0, -INFTY, INFTY}; return out; } @@ -432,7 +429,7 @@ inline void SurfaceZPlane::normal(const double xyz[3], double uvw[3]) const void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-plane"); - std::array coeffs{{z0}}; + std::array coeffs {{z0}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -444,10 +441,10 @@ bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], return false; } -struct BoundingBox +BoundingBox SurfaceZPlane::bounding_box() const { - struct BoundingBox out{-INFTY, INFTY, -INFTY, INFTY, z0, z0}; + BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, z0, z0}; return out; } @@ -473,7 +470,7 @@ SurfacePlane::distance(const double xyz[3], const double uvw[3], { const double f = A*xyz[0] + B*xyz[1] + C*xyz[2] - D; const double projection = A*uvw[0] + B*uvw[1] + C*uvw[2]; - if (coincident or fabs(f) < FP_COINCIDENT or projection == 0.0) { + if (coincident or std::abs(f) < FP_COINCIDENT or projection == 0.0) { return INFTY; } else { const double d = -f / projection; @@ -493,7 +490,7 @@ SurfacePlane::normal(const double xyz[3], double uvw[3]) const void SurfacePlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "plane"); - std::array coeffs{{A, B, C, D}}; + std::array coeffs {{A, B, C, D}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -513,10 +510,10 @@ bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], return false; } -struct BoundingBox +BoundingBox SurfacePlane::bounding_box() const { - struct BoundingBox out{-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY}; + BoundingBox out {-INFTY, INFTY, -INFTY, INFTY, -INFTY, INFTY}; return out; } @@ -556,7 +553,7 @@ axis_aligned_cylinder_distance(const double xyz[3], const double uvw[3], // No intersection with cylinder. return INFTY; - } else if (coincident or fabs(c) < FP_COINCIDENT) { + } else if (coincident or std::abs(c) < FP_COINCIDENT) { // 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. @@ -625,7 +622,7 @@ inline void SurfaceXCylinder::normal(const double xyz[3], double uvw[3]) const void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cylinder"); - std::array coeffs{{y0, z0, r}}; + std::array coeffs {{y0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -659,7 +656,7 @@ inline void SurfaceYCylinder::normal(const double xyz[3], double uvw[3]) const void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cylinder"); - std::array coeffs{{x0, z0, r}}; + std::array coeffs {{x0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -693,7 +690,7 @@ inline void SurfaceZCylinder::normal(const double xyz[3], double uvw[3]) const void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cylinder"); - std::array coeffs{{x0, y0, r}}; + std::array coeffs {{x0, y0, r}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -729,7 +726,7 @@ double SurfaceSphere::distance(const double xyz[3], const double uvw[3], // No intersection with sphere. return INFTY; - } else if (coincident or fabs(c) < FP_COINCIDENT) { + } else if (coincident or std::abs(c) < FP_COINCIDENT) { // 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 >= 0.0) { @@ -764,7 +761,7 @@ inline void SurfaceSphere::normal(const double xyz[3], double uvw[3]) const void SurfaceSphere::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "sphere"); - std::array coeffs{{x0, y0, z0, r}}; + std::array coeffs {{x0, y0, z0, r}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -808,7 +805,7 @@ axis_aligned_cone_distance(const double xyz[3], const double uvw[3], // No intersection with cone. return INFTY; - } else if (coincident or fabs(c) < FP_COINCIDENT) { + } else if (coincident or std::abs(c) < FP_COINCIDENT) { // Particle is on the cone, thus one distance is positive/negative // and the other is zero. The sign of k determines if we are facing in or // out. @@ -881,7 +878,7 @@ inline void SurfaceXCone::normal(const double xyz[3], double uvw[3]) const void SurfaceXCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cone"); - std::array coeffs{{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -915,7 +912,7 @@ inline void SurfaceYCone::normal(const double xyz[3], double uvw[3]) const void SurfaceYCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cone"); - std::array coeffs{{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -949,7 +946,7 @@ inline void SurfaceZCone::normal(const double xyz[3], double uvw[3]) const void SurfaceZCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cone"); - std::array coeffs{{x0, y0, z0, r_sq}}; + std::array coeffs {{x0, y0, z0, r_sq}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -998,7 +995,7 @@ SurfaceQuadric::distance(const double xyz[3], // No intersection with surface. return INFTY; - } else if (coincident or fabs(c) < FP_COINCIDENT) { + } else if (coincident or std::abs(c) < FP_COINCIDENT) { // Particle is on the surface, thus one distance is positive/negative and // the other is zero. The sign of k determines which distance is zero and // which is not. @@ -1043,7 +1040,7 @@ SurfaceQuadric::normal(const double xyz[3], double uvw[3]) const void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "quadric"); - std::array coeffs{{A, B, C, D, E, F, G, H, J, K}}; + std::array coeffs {{A, B, C, D, E, F, G, H, J, K}}; write_double_1D(group_id, "coefficients", coeffs); } @@ -1053,10 +1050,7 @@ extern "C" void read_surfaces(pugi::xml_node *node) { // Count the number of surfaces. - for (pugi::xml_node surf_node = node->child("surface"); surf_node; - surf_node = surf_node.next_sibling("surface")) { - n_surfaces++; - } + for (pugi::xml_node surf_node: node->children("surface")) {n_surfaces++;} if (n_surfaces == 0) { fatal_error("No surfaces found in geometry.xml!"); } @@ -1072,46 +1066,45 @@ read_surfaces(pugi::xml_node *node) surf_node = surf_node.next_sibling("surface"), i_surf++) { std::string surf_type = get_node_value(surf_node, "type"); - if (surf_type.compare("x-plane") == 0) { + if (surf_type == "x-plane") { surfaces_c[i_surf] = new SurfaceXPlane(surf_node); - } else if (surf_type.compare("y-plane") == 0) { + } else if (surf_type == "y-plane") { surfaces_c[i_surf] = new SurfaceYPlane(surf_node); - } else if (surf_type.compare("z-plane") == 0) { + } else if (surf_type == "z-plane") { surfaces_c[i_surf] = new SurfaceZPlane(surf_node); - } else if (surf_type.compare("plane") == 0) { + } else if (surf_type == "plane") { surfaces_c[i_surf] = new SurfacePlane(surf_node); - } else if (surf_type.compare("x-cylinder") == 0) { + } else if (surf_type == "x-cylinder") { surfaces_c[i_surf] = new SurfaceXCylinder(surf_node); - } else if (surf_type.compare("y-cylinder") == 0) { + } else if (surf_type == "y-cylinder") { surfaces_c[i_surf] = new SurfaceYCylinder(surf_node); - } else if (surf_type.compare("z-cylinder") == 0) { + } else if (surf_type == "z-cylinder") { surfaces_c[i_surf] = new SurfaceZCylinder(surf_node); - } else if (surf_type.compare("sphere") == 0) { + } else if (surf_type == "sphere") { surfaces_c[i_surf] = new SurfaceSphere(surf_node); - } else if (surf_type.compare("x-cone") == 0) { + } else if (surf_type == "x-cone") { surfaces_c[i_surf] = new SurfaceXCone(surf_node); - } else if (surf_type.compare("y-cone") == 0) { + } else if (surf_type == "y-cone") { surfaces_c[i_surf] = new SurfaceYCone(surf_node); - } else if (surf_type.compare("z-cone") == 0) { + } else if (surf_type == "z-cone") { surfaces_c[i_surf] = new SurfaceZCone(surf_node); - } else if (surf_type.compare("quadric") == 0) { + } else if (surf_type == "quadric") { surfaces_c[i_surf] = new SurfaceQuadric(surf_node); } else { - std::string err_msg{"Invalid surface type, \""}; - err_msg += surf_type; - err_msg += "\""; + std::stringstream err_msg; + err_msg << "Invalid surface type, \"" << surf_type << "\""; fatal_error(err_msg); } } @@ -1124,15 +1117,15 @@ read_surfaces(pugi::xml_node *node) if (in_dict == surface_dict.end()) { surface_dict[id] = i_surf; } else { - std::string err_msg{"Two or more surfaces use the same unique ID: "}; - err_msg += std::to_string(id); + std::stringstream err_msg; + err_msg << "Two or more surfaces use the same unique ID: " << id; fatal_error(err_msg); } } // Find the global bounding box (of periodic BC surfaces). - double xmin{INFTY}, xmax{-INFTY}, ymin{INFTY}, ymax{-INFTY}, - zmin{INFTY}, zmax{-INFTY}; + double xmin {INFTY}, xmax {-INFTY}, ymin {INFTY}, ymax {-INFTY}, + zmin {INFTY}, zmax {-INFTY}; int i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax; for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { if (surfaces_c[i_surf]->bc == BC_PERIODIC) { @@ -1141,15 +1134,16 @@ read_surfaces(pugi::xml_node *node) PeriodicSurface *surf = dynamic_cast(surf_base); // Make sure this surface inherits from PeriodicSurface. - if (surf == NULL) { - std::string err_msg{"Periodic boundary condition not supported for " - "surface "}; - err_msg += std::to_string(surf_base->id); - err_msg += ". Periodic BCs are only supported for planar surfaces."; + if (!surf) { + std::stringstream err_msg; + err_msg << "Periodic boundary condition not supported for surface " + << surf_base->id + << ". Periodic BCs are only supported for planar surfaces."; + fatal_error(err_msg); } // See if this surface makes part of the global bounding box. - struct BoundingBox bb = surf->bounding_box(); + BoundingBox bb = surf->bounding_box(); if (bb.xmin > -INFTY and bb.xmin < xmin) { xmin = bb.xmin; i_xmin = i_surf; @@ -1188,7 +1182,7 @@ read_surfaces(pugi::xml_node *node) // differently). SurfacePlane *surf_p = dynamic_cast(surf); - if (surf_p == NULL) { + if (!surf_p) { // This is not a SurfacePlane. if (surf->i_periodic == C_NONE) { // The user did not specify the matching periodic surface. See if we @@ -1217,9 +1211,9 @@ read_surfaces(pugi::xml_node *node) // This is a SurfacePlane. We won't try to find it's partner if the // user didn't specify one. if (surf->i_periodic == C_NONE) { - std::string err_msg{"No matching periodic surface specified for " - "periodic boundary condition on surface "}; - err_msg += std::to_string(surf->id); + std::stringstream err_msg; + err_msg << "No matching periodic surface specified for periodic " + "boundary condition on surface " << surf->id; fatal_error(err_msg); } else { // Convert the surface id to an index. @@ -1229,11 +1223,13 @@ read_surfaces(pugi::xml_node *node) // Make sure the opposite surface is also periodic. if (surfaces_c[surf->i_periodic]->bc != BC_PERIODIC) { - std::string err_msg{"Could not find matching surface for periodic " - "boundary condition on surface "}; - err_msg += std::to_string(surf->id); + std::stringstream err_msg; + err_msg << "Could not find matching surface for periodic boundary " + "condition on surface " << surf->id; fatal_error(err_msg); } } } } + +} // namespace openmc diff --git a/src/surface.h b/src/surface.h index 469d88486..72cfd6202 100644 --- a/src/surface.h +++ b/src/surface.h @@ -3,32 +3,37 @@ #include #include // For numeric_limits +#include #include "hdf5.h" #include "pugixml/pugixml.hpp" + +namespace openmc { + //============================================================================== // Module constants //============================================================================== -extern "C" const int BC_TRANSMIT{0}; -extern "C" const int BC_VACUUM{1}; -extern "C" const int BC_REFLECT{2}; -extern "C" const int BC_PERIODIC{3}; +extern "C" const int BC_TRANSMIT {0}; +extern "C" const int BC_VACUUM {1}; +extern "C" const int BC_REFLECT {2}; +extern "C" const int BC_PERIODIC {3}; //============================================================================== // Constants that should eventually be moved out of this file //============================================================================== extern "C" double FP_COINCIDENT; -const double INFTY{std::numeric_limits::max()}; -const int C_NONE{-1}; +constexpr double INFTY{std::numeric_limits::max()}; +constexpr int C_NONE {-1}; //============================================================================== // Global variables //============================================================================== -int n_surfaces{0}; +// Braces force n_surfaces to be defined here, not just declared. +extern "C" {int32_t n_surfaces {0};} class Surface; Surface **surfaces_c; @@ -64,6 +69,8 @@ public: Surface(pugi::xml_node surf_node); + virtual ~Surface() {} + //! Determine which side of a surface a point lies on. //! @param xyz[3] The 3D Cartesian coordinate of a point. //! @param uvw[3] A direction used to "break ties" and pick a sense when the @@ -411,9 +418,10 @@ extern "C" void free_memory_surfaces_c() { for (int i = 0; i < n_surfaces; i++) {delete surfaces_c[i];} delete surfaces_c; - surfaces_c = NULL; + surfaces_c = nullptr; n_surfaces = 0; surface_dict.clear(); } +} // namespace openmc #endif // SURFACE_H diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 8985e8406..9ed89a14e 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -126,7 +126,7 @@ module surface_header end type Surface - integer(C_INT), bind(C) :: n_surfaces ! # of surfaces + integer(C_INT32_T), bind(C) :: n_surfaces ! # of surfaces type(Surface), allocatable, target :: surfaces(:) diff --git a/src/xml_interface.h b/src/xml_interface.h index fbc82e056..778497562 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -2,26 +2,23 @@ #define XML_INTERFACE_H #include // for std::transform +#include #include #include "pugixml/pugixml.hpp" +namespace openmc { + bool -check_for_node(const pugi::xml_node &node, const char *name) +check_for_node(pugi::xml_node node, const char *name) { - if (node.attribute(name)) { - return true; - } else if (node.child(name)) { - return true; - } else { - return false; - } + return node.attribute(name) || node.child(name); } std::string -get_node_value(const pugi::xml_node &node, const char *name) +get_node_value(pugi::xml_node node, const char *name) { // Search for either an attribute or child tag and get the data as a char*. const pugi::char_t *value_char; @@ -30,11 +27,9 @@ get_node_value(const pugi::xml_node &node, const char *name) } else if (node.child(name)) { value_char = node.child_value(name); } else { - std::string err_msg("Node \""); - err_msg += name; - err_msg += "\" is not a memeber of the \""; - err_msg += node.name(); - err_msg += "\" XML node"; + std::stringstream err_msg; + err_msg << "Node \"" << name << "\" is not a member of the \"" + << node.name() << "\" XML node"; fatal_error(err_msg); } @@ -49,4 +44,5 @@ get_node_value(const pugi::xml_node &node, const char *name) return value; } +} // namespace openmc #endif // XML_INTERFACE_H From 48ac683a0cec3724c80629ac549a0eb4a4f7b4d1 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 31 Jan 2018 17:52:52 -0500 Subject: [PATCH 20/21] Remove C++/Fortran interoperable "seed" --- openmc/capi/settings.py | 5 ++--- src/api.F90 | 10 +++++----- src/initialize.F90 | 3 +-- src/input_xml.F90 | 2 +- src/random_lcg.F90 | 13 ++++++++----- src/random_lcg.cpp | 5 +++-- src/random_lcg.h | 8 +++++++- src/state_point.F90 | 6 ++++-- tests/unit_tests/test_capi.py | 10 +++++----- 9 files changed, 36 insertions(+), 26 deletions(-) diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py index eede6cf47..1063d6463 100644 --- a/openmc/capi/settings.py +++ b/openmc/capi/settings.py @@ -11,8 +11,7 @@ _RUN_MODES = {1: 'fixed source', 5: 'volume'} _dll.openmc_set_seed.argtypes = [c_int64] -_dll.openmc_set_seed.restype = c_int -_dll.openmc_set_seed.errcheck = _error_handler +_dll.openmc_get_seed.restype = c_int64 class _Settings(object): @@ -43,7 +42,7 @@ class _Settings(object): @property def seed(self): - return c_int64.in_dll(_dll, 'seed').value + return _dll.openmc_get_seed() @seed.setter def seed(self, seed): diff --git a/src/api.F90 b/src/api.F90 index 5d56b857c..f07e5e38a 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -18,7 +18,7 @@ module openmc_api use initialize, only: openmc_init use particle_header, only: Particle use plot, only: openmc_plot_geometry - use random_lcg, only: seed, openmc_set_seed + use random_lcg, only: openmc_get_seed, openmc_set_seed use settings use simulation_header use source_header, only: openmc_extend_sources, openmc_source_set_strength @@ -60,6 +60,7 @@ module openmc_api public :: openmc_get_filter_next_id public :: openmc_get_material_index public :: openmc_get_nuclide_index + public :: openmc_get_seed public :: openmc_get_tally_index public :: openmc_global_tallies public :: openmc_hard_reset @@ -79,6 +80,7 @@ module openmc_api public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run + public :: openmc_set_seed public :: openmc_simulation_finalize public :: openmc_simulation_init public :: openmc_source_bank @@ -142,7 +144,7 @@ contains run_CE = .true. run_mode = NONE satisfy_triggers = .false. - seed = 1_8 + call openmc_set_seed(DEFAULT_SEED) source_latest = .false. source_separate = .false. source_write = .true. @@ -228,8 +230,6 @@ contains !=============================================================================== subroutine openmc_hard_reset() bind(C) - integer :: err - ! Reset all tallies and timers call openmc_reset() @@ -238,7 +238,7 @@ contains total_gen = 0 ! Reset the random number generator state - err = openmc_set_seed(1_8) + call openmc_set_seed(DEFAULT_SEED) end subroutine openmc_hard_reset !=============================================================================== diff --git a/src/initialize.F90 b/src/initialize.F90 index 2af93627e..7b699b9cb 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -44,7 +44,6 @@ contains subroutine openmc_init(intracomm) bind(C) integer, intent(in), optional :: intracomm ! MPI intracommunicator - integer :: err #ifdef _OPENMP character(MAX_WORD_LEN) :: envvar #endif @@ -95,7 +94,7 @@ contains ! Initialize random number generator -- if the user specifies a seed, it ! will be re-initialized later - err = openmc_set_seed(DEFAULT_SEED) + call openmc_set_seed(DEFAULT_SEED) ! Read XML input files call read_input_xml() diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 55eeca9e1..0b7790a51 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -349,7 +349,7 @@ contains ! Copy random number seed if specified if (check_for_node(root, "seed")) then call get_node_value(root, "seed", seed) - err = openmc_set_seed(seed) + call openmc_set_seed(seed) end if ! Number of bins for logarithmic grid diff --git a/src/random_lcg.F90 b/src/random_lcg.F90 index 839bd729a..d64717cf4 100644 --- a/src/random_lcg.F90 +++ b/src/random_lcg.F90 @@ -4,8 +4,6 @@ module random_lcg implicit none - integer(C_INT64_T), bind(C) :: seed - interface function prn() result(pseudo_rn) bind(C) use ISO_C_BINDING @@ -38,11 +36,16 @@ module random_lcg integer(C_INT), value :: n end subroutine prn_set_stream - function openmc_set_seed(new_seed) result(err) bind(C) + function openmc_get_seed() result(seed) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT64_T) :: seed + end function openmc_get_seed + + subroutine openmc_set_seed(new_seed) bind(C) use ISO_C_BINDING implicit none integer(C_INT64_T), value :: new_seed - integer(C_INT) :: err - end function openmc_set_seed + end subroutine openmc_set_seed end interface end module random_lcg diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index 2dcdd86a3..2a57316cb 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -133,7 +133,9 @@ prn_set_stream(int i) // API FUNCTIONS //============================================================================== -extern "C" int +extern "C" int64_t openmc_get_seed() {return seed;} + +extern "C" void openmc_set_seed(int64_t new_seed) { seed = new_seed; @@ -144,7 +146,6 @@ openmc_set_seed(int64_t new_seed) } prn_set_stream(STREAM_TRACKING); } - return 0; } } // namespace openmc diff --git a/src/random_lcg.h b/src/random_lcg.h index cd065474e..29b3fca47 100644 --- a/src/random_lcg.h +++ b/src/random_lcg.h @@ -77,13 +77,19 @@ extern "C" void prn_set_stream(int n); // API FUNCTIONS //============================================================================== +//============================================================================== +//! Get OpenMC's master seed. +//============================================================================== + +extern "C" int64_t openmc_get_seed(); + //============================================================================== //! Set OpenMC's master seed. //! @param new_seed The master seed. All other seeds will be derived from this //! one. //============================================================================== -extern "C" int openmc_set_seed(int64_t new_seed); +extern "C" void openmc_set_seed(int64_t new_seed); } // namespace openmc #endif // RANDOM_LCG_H diff --git a/src/state_point.F90 b/src/state_point.F90 index ba7bcef19..980a7333c 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -26,7 +26,7 @@ module state_point use mgxs_header, only: nuclides_MG use nuclide_header, only: nuclides use output, only: time_stamp - use random_lcg, only: seed + use random_lcg, only: openmc_get_seed, openmc_set_seed use settings use simulation_header use string, only: to_str, count_digits, zero_padded, to_f_string @@ -97,7 +97,7 @@ contains call write_attribute(file_id, "path", path_input) ! Write out random number seed - call write_dataset(file_id, "seed", seed) + call write_dataset(file_id, "seed", openmc_get_seed()) ! Write run information if (run_CE) then @@ -642,6 +642,7 @@ contains integer :: n integer :: int_array(3) integer, allocatable :: array(:) + integer(C_INT64_T) :: seed integer(HID_T) :: file_id integer(HID_T) :: cmfd_group integer(HID_T) :: tallies_group @@ -672,6 +673,7 @@ contains ! Read and overwrite random number seed call read_dataset(seed, file_id, "seed") + call openmc_set_seed(seed) ! It is not impossible for a state point to be generated from a CE run but ! to be loaded in to an MG run (or vice versa), check to prevent that. diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index ba9ac5c9e..cd24314ad 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -29,11 +29,11 @@ def pincell_model(): yield # Delete generated files - files = ['geometry.xml', 'materials.xml', 'settings.xml', 'tallies.xml', - 'statepoint.10.h5', 'summary.h5', 'test_sp.h5'] - for f in files: - if os.path.exists(f): - os.remove(f) + #files = ['geometry.xml', 'materials.xml', 'settings.xml', 'tallies.xml', + # 'statepoint.10.h5', 'summary.h5', 'test_sp.h5'] + #for f in files: + # if os.path.exists(f): + # os.remove(f) @pytest.fixture(scope='module') From 7acf3f91dbb74c7ca0aad9bedfc2cdc14c2c2463 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 2 Feb 2018 19:56:23 -0500 Subject: [PATCH 21/21] Address #959 comments --- src/surface.cpp | 2 +- src/surface.h | 38 +++++++++++++++++------------------ tests/unit_tests/test_capi.py | 10 ++++----- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/surface.cpp b/src/surface.cpp index 16f333f7e..9abfd23d2 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1,12 +1,12 @@ #include "surface.h" #include +#include #include #include "error.h" #include "hdf5_interface.h" #include "xml_interface.h" -#include namespace openmc { diff --git a/src/surface.h b/src/surface.h index 72cfd6202..627a8fbae 100644 --- a/src/surface.h +++ b/src/surface.h @@ -67,7 +67,7 @@ public: int bc; //!< Boundary condition std::string name{""}; //!< User-defined name - Surface(pugi::xml_node surf_node); + explicit Surface(pugi::xml_node surf_node); virtual ~Surface() {} @@ -127,7 +127,7 @@ class PeriodicSurface : public Surface public: int i_periodic{C_NONE}; //!< Index of corresponding periodic surface - PeriodicSurface(pugi::xml_node surf_node); + explicit PeriodicSurface(pugi::xml_node surf_node); //! Translate a particle onto this surface from a periodic partner surface. //! @param other A pointer to the partner surface in this periodic BC. @@ -141,7 +141,7 @@ public: double uvw[3]) const = 0; //! Get the bounding box for this surface. - virtual struct BoundingBox bounding_box() const = 0; + virtual BoundingBox bounding_box() const = 0; }; //============================================================================== @@ -154,7 +154,7 @@ class SurfaceXPlane : public PeriodicSurface { double x0; public: - SurfaceXPlane(pugi::xml_node surf_node); + explicit SurfaceXPlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -162,7 +162,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; - struct BoundingBox bounding_box() const; + BoundingBox bounding_box() const; }; //============================================================================== @@ -175,7 +175,7 @@ class SurfaceYPlane : public PeriodicSurface { double y0; public: - SurfaceYPlane(pugi::xml_node surf_node); + explicit SurfaceYPlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -183,7 +183,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; - struct BoundingBox bounding_box() const; + BoundingBox bounding_box() const; }; //============================================================================== @@ -196,7 +196,7 @@ class SurfaceZPlane : public PeriodicSurface { double z0; public: - SurfaceZPlane(pugi::xml_node surf_node); + explicit SurfaceZPlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -204,7 +204,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; - struct BoundingBox bounding_box() const; + BoundingBox bounding_box() const; }; //============================================================================== @@ -217,7 +217,7 @@ class SurfacePlane : public PeriodicSurface { double A, B, C, D; public: - SurfacePlane(pugi::xml_node surf_node); + explicit SurfacePlane(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -225,7 +225,7 @@ public: void to_hdf5_inner(hid_t group_id) const; bool periodic_translate(PeriodicSurface *other, double xyz[3], double uvw[3]) const; - struct BoundingBox bounding_box() const; + BoundingBox bounding_box() const; }; //============================================================================== @@ -239,7 +239,7 @@ class SurfaceXCylinder : public Surface { double y0, z0, r; public: - SurfaceXCylinder(pugi::xml_node surf_node); + explicit SurfaceXCylinder(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -258,7 +258,7 @@ class SurfaceYCylinder : public Surface { double x0, z0, r; public: - SurfaceYCylinder(pugi::xml_node surf_node); + explicit SurfaceYCylinder(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -277,7 +277,7 @@ class SurfaceZCylinder : public Surface { double x0, y0, r; public: - SurfaceZCylinder(pugi::xml_node surf_node); + explicit SurfaceZCylinder(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -296,7 +296,7 @@ class SurfaceSphere : public Surface { double x0, y0, z0, r; public: - SurfaceSphere(pugi::xml_node surf_node); + explicit SurfaceSphere(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -315,7 +315,7 @@ class SurfaceXCone : public Surface { double x0, y0, z0, r_sq; public: - SurfaceXCone(pugi::xml_node surf_node); + explicit SurfaceXCone(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -334,7 +334,7 @@ class SurfaceYCone : public Surface { double x0, y0, z0, r_sq; public: - SurfaceYCone(pugi::xml_node surf_node); + explicit SurfaceYCone(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -353,7 +353,7 @@ class SurfaceZCone : public Surface { double x0, y0, z0, r_sq; public: - SurfaceZCone(pugi::xml_node surf_node); + explicit SurfaceZCone(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; @@ -372,7 +372,7 @@ class SurfaceQuadric : public Surface // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 double A, B, C, D, E, F, G, H, J, K; public: - SurfaceQuadric(pugi::xml_node surf_node); + explicit SurfaceQuadric(pugi::xml_node surf_node); double evaluate(const double xyz[3]) const; double distance(const double xyz[3], const double uvw[3], bool coincident) const; diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index cd24314ad..ba9ac5c9e 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -29,11 +29,11 @@ def pincell_model(): yield # Delete generated files - #files = ['geometry.xml', 'materials.xml', 'settings.xml', 'tallies.xml', - # 'statepoint.10.h5', 'summary.h5', 'test_sp.h5'] - #for f in files: - # if os.path.exists(f): - # os.remove(f) + files = ['geometry.xml', 'materials.xml', 'settings.xml', 'tallies.xml', + 'statepoint.10.h5', 'summary.h5', 'test_sp.h5'] + for f in files: + if os.path.exists(f): + os.remove(f) @pytest.fixture(scope='module')