From 42df6d37a6718645d60771b7650acf54111a611f Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 3 Feb 2018 16:27:33 -0500 Subject: [PATCH 01/41] Begin implementing C++ Cells; remove F90 Cell id --- CMakeLists.txt | 2 + src/api.F90 | 2 +- src/cell.cpp | 88 ++++++++++++++++++++++++ src/cell.h | 70 +++++++++++++++++++ src/error.h | 6 +- src/geometry.F90 | 6 +- src/geometry_header.F90 | 50 +++++++++++++- src/hdf5_interface.h | 12 ++-- src/input_xml.F90 | 53 +++++++------- src/output.F90 | 6 +- src/plot.F90 | 2 +- src/summary.F90 | 4 +- src/surface.h | 3 + src/tallies/tally_filter_cell.F90 | 4 +- src/tallies/tally_filter_cellborn.F90 | 4 +- src/tallies/tally_filter_cellfrom.F90 | 4 +- src/tallies/tally_filter_distribcell.F90 | 6 +- src/volume_calc.F90 | 3 +- src/xml_interface.h | 4 +- 19 files changed, 270 insertions(+), 59 deletions(-) create mode 100644 src/cell.cpp create mode 100644 src/cell.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5b2168fe..c1228c4939 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,6 +435,8 @@ set(LIBOPENMC_FORTRAN_SRC src/tallies/trigger_header.F90 ) set(LIBOPENMC_CXX_SRC + src/cell.cpp + src/cell.h src/error.h src/hdf5_interface.h src/random_lcg.cpp diff --git a/src/api.F90 b/src/api.F90 index f07e5e38a5..de44fb2521 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -205,7 +205,7 @@ contains if (found) then if (rtype == 1) then - id = cells(p % coord(p % n_coord) % cell) % id + id = cells(p % coord(p % n_coord) % cell) % id() elseif (rtype == 2) then if (p % material == MATERIAL_VOID) then id = 0 diff --git a/src/cell.cpp b/src/cell.cpp new file mode 100644 index 0000000000..21713471a0 --- /dev/null +++ b/src/cell.cpp @@ -0,0 +1,88 @@ +#include "cell.h" + +#include + +#include "error.h" +#include "hdf5_interface.h" +#include "xml_interface.h" + +//TODO: remove this include +#include + + +namespace openmc { + +//============================================================================== +// Cell implementation +//============================================================================== + +Cell::Cell(pugi::xml_node cell_node) +{ + if (check_for_node(cell_node, "id")) { + id = stoi(get_node_value(cell_node, "id")); + } else { + fatal_error("Must specify id of cell in geometry XML file."); + } + + //TODO: don't automatically lowercase cell and surface names + if (check_for_node(cell_node, "name")) { + name = get_node_value(cell_node, "name"); + } +} + +void +Cell::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(surf_group, "boundary_type", "transmission"); + break; + case BC_VACUUM : + write_string(surf_group, "boundary_type", "vacuum"); + break; + case BC_REFLECT : + write_string(surf_group, "boundary_type", "reflective"); + break; + case BC_PERIODIC : + write_string(surf_group, "boundary_type", "periodic"); + break; + } + + if (!name.empty()) { + write_string(surf_group, "name", name); + } + + to_hdf5_inner(surf_group); + + close_group(surf_group); +*/ +} + +//============================================================================== + +extern "C" void +read_cells(pugi::xml_node *node) +{ + // Count the number of cells. + for (pugi::xml_node cell_node: node->children("cell")) {n_cells++;} + if (n_cells == 0) { + fatal_error("No cells found in geometry.xml!"); + } + + // Allocate the vector of Cells. + cells_c.reserve(n_cells); + + // Loop over XML cell elements and populate the array. + for (pugi::xml_node cell_node: node->children("cell")) { + cells_c.push_back(Cell(cell_node)); + } + +} + +} // namespace openmc diff --git a/src/cell.h b/src/cell.h new file mode 100644 index 0000000000..90ca923e3d --- /dev/null +++ b/src/cell.h @@ -0,0 +1,70 @@ +#ifndef CELL_H +#define CELL_H + +#include +#include +#include +#include + +#include "hdf5.h" +#include "pugixml/pugixml.hpp" + + +namespace openmc { + +//============================================================================== +// Module constants +//============================================================================== + +//============================================================================== +// Global variables +//============================================================================== + +// Braces force n_cells to be defined here, not just declared. +extern "C" {int32_t n_cells {0};} + +class Cell; +//Cell *cells_c; +std::vector cells_c; + +std::map cell_dict; + +//============================================================================== +//! A geometry primitive that links surfaces, universes, and materials +//============================================================================== + +class Cell +{ +public: + int32_t id; //!< Unique ID + std::string name{""}; //!< User-defined name + + explicit Cell(pugi::xml_node cell_node); + + //! Write all information needed to reconstruct the cell to an HDF5 group. + //! @param group_id An HDF5 group id. + void to_hdf5(hid_t group_id) const; +}; + +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" void read_cells(pugi::xml_node *node); + +extern "C" Cell* cell_pointer(int cell_ind) {return &cells_c[cell_ind];} + +extern "C" int32_t cell_id(Cell *c) {return c->id;} + +extern "C" void cell_set_id(Cell *c, int32_t id) {c->id = id;} + +//extern "C" void free_memory_cells_c() +//{ +// delete cells_c; +// cells_c = nullptr; +// n_cells = 0; +// cell_dict.clear(); +//} + +} // namespace openmc +#endif // CELL_H diff --git a/src/error.h b/src/error.h index 4c3373b3e3..eedf9c8f58 100644 --- a/src/error.h +++ b/src/error.h @@ -12,19 +12,19 @@ namespace openmc { extern "C" void fatal_error_from_c(const char *message, int message_len); -void fatal_error(const char *message) +inline void fatal_error(const char *message) { fatal_error_from_c(message, strlen(message)); } -void fatal_error(const std::string &message) +inline void fatal_error(const std::string &message) { fatal_error_from_c(message.c_str(), message.length()); } -void fatal_error(const std::stringstream &message) +inline void fatal_error(const std::stringstream &message) { std::string out {message.str()}; fatal_error_from_c(out.c_str(), out.length()); diff --git a/src/geometry.F90 b/src/geometry.F90 index 0bacd7b5d1..630c57c049 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -166,8 +166,8 @@ contains ! the particle should only be contained in one cell per level if (index_cell /= p % coord(j) % cell) then call fatal_error("Overlapping cells detected: " & - &// trim(to_str(cells(index_cell) % id)) // ", " & - &// trim(to_str(cells(p % coord(j) % cell) % id)) & + &// trim(to_str(cells(index_cell) % id())) // ", " & + &// trim(to_str(cells(p % coord(j) % cell) % id())) & &// " on universe " // trim(to_str(univ % id))) end if @@ -236,7 +236,7 @@ contains ! Show cell information on trace if (verbosity >= 10 .or. trace) then call write_message(" Entering cell " // trim(to_str(& - cells(i_cell) % id))) + cells(i_cell) % id()))) end if found = .true. diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index e71916d096..b938dddec6 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -14,6 +14,29 @@ module geometry_header implicit none + interface + function cell_pointer_c(cell_ind) bind(C, name='cell_pointer') result(ptr) + use ISO_C_BINDING + implicit none + integer(C_INT), intent(in), value :: cell_ind + type(C_PTR) :: ptr + end function cell_pointer_c + + function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T) :: id + end function cell_id_c + + subroutine cell_set_id_c(cell_ptr, id) bind(C, name='cell_set_id') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T), intent(in), value :: id + end subroutine cell_set_id_c + end interface + !=============================================================================== ! UNIVERSE defines a geometry that fills all phase space !=============================================================================== @@ -125,7 +148,8 @@ module geometry_header !=============================================================================== type Cell - integer :: id ! Unique ID + type(C_PTR) :: ptr + character(len=104) :: name = "" ! User-defined name integer :: type ! Type of cell (normal, universe, ! lattice) @@ -154,6 +178,12 @@ module geometry_header real(8), allocatable :: translation(:) real(8), allocatable :: rotation(:) real(8), allocatable :: rotation_matrix(:,:) + + contains + + procedure :: id => cell_id + procedure :: set_id => cell_set_id + end type Cell ! array index of the root universe @@ -341,6 +371,20 @@ contains end if end function get_local_hex +!=============================================================================== + + function cell_id(this) result(id) + class(Cell), intent(in) :: this + integer(C_INT32_T) :: id + id = cell_id_c(this % ptr) + end function cell_id + + subroutine cell_set_id(this, id) + class(Cell), intent(in) :: this + integer(C_INT32_T), intent(in) :: id + call cell_set_id_c(this % ptr, id) + end subroutine cell_set_id + !=============================================================================== ! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table ! appears at in the model. Later, this list is used to determine the actual @@ -514,7 +558,7 @@ contains integer(C_INT) :: err if (index >= 1 .and. index <= size(cells)) then - id = cells(index) % id + id = cells(index) % id() err = 0 else err = E_OUT_OF_BOUNDS @@ -577,7 +621,7 @@ contains integer(C_INT) :: err if (index >= 1 .and. index <= n_cells) then - cells(index) % id = id + call cells(index) % set_id(id) call cell_dict % set(id, index) err = 0 else diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 7ec9ada9b6..89dce7ab23 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -12,7 +12,7 @@ namespace openmc { -hid_t +inline hid_t create_group(hid_t parent_id, char const *name) { hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); @@ -26,14 +26,14 @@ create_group(hid_t parent_id, char const *name) } -hid_t +inline hid_t create_group(hid_t parent_id, const std::string &name) { return create_group(parent_id, name.c_str()); } -void +inline void close_group(hid_t group_id) { herr_t err = H5Gclose(group_id); @@ -43,7 +43,7 @@ close_group(hid_t group_id) } -template void +template inline void write_double_1D(hid_t group_id, char const *name, std::array &buffer) { @@ -61,7 +61,7 @@ write_double_1D(hid_t group_id, char const *name, } -void +inline void write_string(hid_t group_id, char const *name, char const *buffer) { size_t buffer_len = strlen(buffer); @@ -81,7 +81,7 @@ write_string(hid_t group_id, char const *name, char const *buffer) } -void +inline void write_string(hid_t group_id, char const *name, const std::string &buffer) { write_string(group_id, name, buffer.c_str()); diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 0b7790a51c..a9d6874000 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -49,11 +49,17 @@ module input_xml save interface - subroutine read_surfaces(node_ptr) bind(C, name='read_surfaces') + subroutine read_surfaces(node_ptr) bind(C) use ISO_C_BINDING implicit none type(C_PTR) :: node_ptr end subroutine read_surfaces + + subroutine read_cells(node_ptr) bind(C) + use ISO_C_BINDING + implicit none + type(C_PTR) :: node_ptr + end subroutine read_cells end interface contains @@ -989,6 +995,8 @@ contains ! ========================================================================== ! READ CELLS FROM GEOMETRY.XML + call read_cells(root % ptr) + ! Get pointer to list of XML call get_node_list(root, "cell", node_cell_list) @@ -1012,6 +1020,8 @@ contains do i = 1, n_cells c => cells(i) + c % ptr = cell_pointer_c(i - 1) + ! Initialize distribcell instances and distribcell index c % instances = 0 c % distribcell_index = NONE @@ -1019,13 +1029,6 @@ contains ! Get pointer to i-th cell node node_cell = node_cell_list(i) - ! Copy data into cells - if (check_for_node(node_cell, "id")) then - call get_node_value(node_cell, "id", c % id) - else - call fatal_error("Must specify id of cell in geometry XML file.") - end if - ! Copy cell name if (check_for_node(node_cell, "name")) then call get_node_value(node_cell, "name", c % name) @@ -1045,9 +1048,9 @@ contains end if ! Check to make sure 'id' hasn't been used - if (cell_dict % has(c % id)) then + if (cell_dict % has(c % id())) then call fatal_error("Two or more cells use the same unique ID: " & - // to_str(c % id)) + // to_str(c % id())) end if ! Read material @@ -1069,7 +1072,7 @@ contains ! Check for error if (c % material(j) == ERROR_INT) then call fatal_error("Invalid material specified on cell " & - // to_str(c % id)) + // to_str(c % id())) end if end select end do @@ -1089,7 +1092,7 @@ contains ! Check to make sure that either material or fill was specified if (c % material(1) == NONE .and. c % fill == NONE) then call fatal_error("Neither material nor fill was specified for cell " & - // trim(to_str(c % id))) + // trim(to_str(c % id()))) end if ! Check to make sure that both material and fill haven't been @@ -1128,7 +1131,7 @@ contains end do ! Use shunting-yard algorithm to determine RPN for surface algorithm - call generate_rpn(c%id, tokens, rpn) + call generate_rpn(c%id(), tokens, rpn) ! Copy region spec and RPN form to cell arrays allocate(c % region(tokens%size())) @@ -1155,14 +1158,14 @@ contains ! another universe if (c % fill == NONE) then call fatal_error("Cannot apply a rotation to cell " // trim(to_str(& - &c % id)) // " because it is not filled with another universe") + &c % id())) // " because it is not filled with another universe") end if ! Read number of rotation parameters n = node_word_count(node_cell, "rotation") if (n /= 3) then call fatal_error("Incorrect number of rotation parameters on cell " & - // to_str(c % id)) + // to_str(c % id())) end if ! Copy rotation angles in x,y,z directions @@ -1190,7 +1193,7 @@ contains ! another universe if (c % fill == NONE) then call fatal_error("Cannot apply a translation to cell " & - // trim(to_str(c % id)) // " because it is not filled with & + // trim(to_str(c % id())) // " because it is not filled with & &another universe") end if @@ -1198,7 +1201,7 @@ contains n = node_word_count(node_cell, "translation") if (n /= 3) then call fatal_error("Incorrect number of translation parameters on & - &cell " // to_str(c % id)) + &cell " // to_str(c % id())) end if ! Copy translation vector @@ -1214,7 +1217,7 @@ contains if (n > 0) then ! Make sure this is a "normal" cell. if (c % material(1) == NONE) call fatal_error("Cell " & - // trim(to_str(c % id)) // " was specified with a temperature & + // trim(to_str(c % id())) // " was specified with a temperature & &but no material. Temperature specification is only valid for & &cells filled with a material.") @@ -1225,7 +1228,7 @@ contains ! Make sure all temperatues are positive do j = 1, size(c % sqrtkT) if (c % sqrtkT(j) < ZERO) call fatal_error("Cell " & - // trim(to_str(c % id)) // " was specified with a negative & + // trim(to_str(c % id())) // " was specified with a negative & &temperature. All cell temperatures must be non-negative.") end do @@ -1241,7 +1244,7 @@ contains end if ! Add cell to dictionary - call cell_dict % set(c % id, i) + call cell_dict % set(c % id(), i) ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the @@ -4408,7 +4411,7 @@ contains c % universe = universe_dict % get(id) else call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c % id))) + &// " specified on cell " // trim(to_str(c % id()))) end if ! ======================================================================= @@ -4425,7 +4428,7 @@ contains c % fill = lid else call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& - // trim(to_str(c % id)) // " is neither a universe nor a & + // trim(to_str(c % id())) // " is neither a universe nor a & &lattice.") end if else @@ -4438,7 +4441,7 @@ contains c % material(j) = material_dict % get(id) else call fatal_error("Could not find material " // trim(to_str(id)) & - // " specified on cell " // trim(to_str(c % id))) + // " specified on cell " // trim(to_str(c % id()))) end if end do end if @@ -4551,7 +4554,7 @@ contains associate (c => cells(i)) if (size(c % material) > 1) then if (size(c % material) /= c % instances) then - call fatal_error("Cell " // trim(to_str(c % id)) // " was & + call fatal_error("Cell " // trim(to_str(c % id())) // " was & &specified with " // trim(to_str(size(c % material))) & // " materials but has " // trim(to_str(c % instances)) & // " distributed instances. The number of materials must & @@ -4560,7 +4563,7 @@ contains end if if (size(c % sqrtkT) > 1) then if (size(c % sqrtkT) /= c % instances) then - call fatal_error("Cell " // trim(to_str(c % id)) // " was & + call fatal_error("Cell " // trim(to_str(c % id())) // " was & &specified with " // trim(to_str(size(c % sqrtkT))) & // " temperatures but has " // trim(to_str(c % instances)) & // " distributed instances. The number of temperatures must & diff --git a/src/output.F90 b/src/output.F90 index 316fe95941..c8efcecbc3 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -234,7 +234,7 @@ contains ! Print cell for this level if (p % coord(i) % cell /= NONE) then c => cells(p % coord(i) % cell) - write(ou,*) ' Cell = ' // trim(to_str(c % id)) + write(ou,*) ' Cell = ' // trim(to_str(c % id())) end if ! Print universe for this level @@ -633,7 +633,7 @@ contains write(ou,100) 'Cell ID','No. Overlap Checks' do i = 1, n_cells - write(ou,101) cells(i) % id, overlap_check_cnt(i) + write(ou,101) cells(i) % id(), overlap_check_cnt(i) if (overlap_check_cnt(i) < 10) num_sparse = num_sparse + 1 end do write(ou,*) @@ -643,7 +643,7 @@ contains do i = 1, n_cells if (overlap_check_cnt(i) < 10) then j = j + 1 - write(ou,'(1X,A8)', advance='no') trim(to_str(cells(i) % id)) + write(ou,'(1X,A8)', advance='no') trim(to_str(cells(i) % id())) if (modulo(j,8) == 0) write(ou,*) end if end do diff --git a/src/plot.F90 b/src/plot.F90 index 5eb894ce8d..d0c024f1a3 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -101,7 +101,7 @@ contains else if (pl % color_by == PLOT_COLOR_CELLS) then ! Assign color based on cell rgb = pl % colors(p % coord(j) % cell) % rgb - id = cells(p % coord(j) % cell) % id + id = cells(p % coord(j) % cell) % id() else rgb = 0 id = -1 diff --git a/src/summary.F90 b/src/summary.F90 index 3aeb42178b..d21b192a30 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -145,7 +145,7 @@ contains ! Write information on each cell CELL_LOOP: do i = 1, n_cells c => cells(i) - cell_group = create_group(cells_group, "cell " // trim(to_str(c%id))) + cell_group = create_group(cells_group, "cell " // trim(to_str(c%id()))) ! Write name for this cell call write_dataset(cell_group, "name", c%name) @@ -260,7 +260,7 @@ contains if (size(u % cells) > 0) then allocate(cell_ids(size(u % cells))) do j = 1, size(u % cells) - cell_ids(j) = cells(u % cells(j)) % id + cell_ids(j) = cells(u % cells(j)) % id() end do call write_dataset(univ_group, "cells", cell_ids) deallocate(cell_ids) diff --git a/src/surface.h b/src/surface.h index 627a8fbae2..33139ace12 100644 --- a/src/surface.h +++ b/src/surface.h @@ -108,6 +108,7 @@ public: //! Write all information needed to reconstruct the surface to an HDF5 group. //! @param group_id An HDF5 group id. + //TODO: this probably needs to include i_periodic for PeriodicSurface void to_hdf5(hid_t group_id) const; protected: @@ -384,6 +385,8 @@ public: // Fortran compatibility functions //============================================================================== +extern "C" void read_surfaces(pugi::xml_node *node); + extern "C" Surface* surface_pointer(int surf_ind) {return surfaces_c[surf_ind];} extern "C" int surface_id(Surface *surf) {return surf->id;} diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 index 8d2b93d282..34fba208a3 100644 --- a/src/tallies/tally_filter_cell.F90 +++ b/src/tallies/tally_filter_cell.F90 @@ -81,7 +81,7 @@ contains allocate(cell_ids(size(this % cells))) do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id + cell_ids(i) = cells(this % cells(i)) % id() end do call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cell @@ -115,7 +115,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Cell " // to_str(cells(this % cells(bin)) % id) + label = "Cell " // to_str(cells(this % cells(bin)) % id()) end function text_label_cell end module tally_filter_cell diff --git a/src/tallies/tally_filter_cellborn.F90 b/src/tallies/tally_filter_cellborn.F90 index 450858b6b8..c22c59c6b8 100644 --- a/src/tallies/tally_filter_cellborn.F90 +++ b/src/tallies/tally_filter_cellborn.F90 @@ -76,7 +76,7 @@ contains call write_dataset(filter_group, "n_bins", this % n_bins) allocate(cell_ids(size(this % cells))) do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id + cell_ids(i) = cells(this % cells(i)) % id() end do call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cellborn @@ -110,7 +110,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Birth Cell " // to_str(cells(this % cells(bin)) % id) + label = "Birth Cell " // to_str(cells(this % cells(bin)) % id()) end function text_label_cellborn end module tally_filter_cellborn diff --git a/src/tallies/tally_filter_cellfrom.F90 b/src/tallies/tally_filter_cellfrom.F90 index 16cb294d56..2a6040c6ee 100644 --- a/src/tallies/tally_filter_cellfrom.F90 +++ b/src/tallies/tally_filter_cellfrom.F90 @@ -66,7 +66,7 @@ contains allocate(cell_ids(size(this % cells))) do i = 1, size(this % cells) - cell_ids(i) = cells(this % cells(i)) % id + cell_ids(i) = cells(this % cells(i)) % id() end do call write_dataset(filter_group, "bins", cell_ids) end subroutine to_statepoint_cell_from @@ -76,7 +76,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Cell from " // to_str(cells(this % cells(bin)) % id) + label = "Cell from " // to_str(cells(this % cells(bin)) % id()) end function text_label_cell_from end module tally_filter_cellfrom diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index 3cb34efe4c..310af1cb6b 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -90,7 +90,7 @@ contains call write_dataset(filter_group, "type", "distribcell") call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", cells(this % cell) % id) + call write_dataset(filter_group, "bins", cells(this % cell) % id()) end subroutine to_statepoint_distribcell subroutine initialize_distribcell(this) @@ -175,7 +175,7 @@ contains ! geometry stack if (univ % cells(i) == i_cell .and. offset == target_offset) then c => cells(univ % cells(i)) - path = trim(path) // "->c" // to_str(c % id) + path = trim(path) // "->c" // to_str(c % id()) return end if end do @@ -243,7 +243,7 @@ contains cell_index = univ % cells(i) c => cells(cell_index) - path = trim(path) // "->c" // to_str(c%id) + path = trim(path) // "->c" // to_str(c%id()) ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index 07dc5b4184..4a7d0ce23f 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -202,7 +202,8 @@ contains elseif (this % domain_type == FILTER_CELL) THEN do level = 1, p % n_coord do i_domain = 1, size(this % domain_id) - if (cells(p % coord(level) % cell) % id == this % domain_id(i_domain)) then + if (cells(p % coord(level) % cell) % id() & + == this % domain_id(i_domain)) then i_material = p % material call check_hit(i_domain, i_material, indices, hits, n_mat) end if diff --git a/src/xml_interface.h b/src/xml_interface.h index 778497562b..8dd1cf5808 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -10,14 +10,14 @@ namespace openmc { -bool +inline bool check_for_node(pugi::xml_node node, const char *name) { return node.attribute(name) || node.child(name); } -std::string +inline std::string 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*. From 3b5c8495e122a8b84e37faf4fc6fa648dad3fd1d Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 3 Feb 2018 21:19:46 -0500 Subject: [PATCH 02/41] Move Cell % universe to C++ --- src/cell.cpp | 42 +++++++++++++++--------------------- src/cell.h | 8 +++++++ src/geometry.F90 | 2 +- src/geometry_header.F90 | 48 +++++++++++++++++++++++++++++++++++++++-- src/hdf5_interface.h | 30 ++++++++++++++++++++++++++ src/input_xml.F90 | 18 ++++------------ src/summary.F90 | 5 ++--- 7 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 21713471a0..2b2943fc4a 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1,6 +1,7 @@ #include "cell.h" #include +#include #include "error.h" #include "hdf5_interface.h" @@ -28,40 +29,31 @@ Cell::Cell(pugi::xml_node cell_node) if (check_for_node(cell_node, "name")) { name = get_node_value(cell_node, "name"); } + + if (check_for_node(cell_node, "universe")) { + universe = stoi(get_node_value(cell_node, "universe")); + } else { + universe = 0; + } } void -Cell::to_hdf5(hid_t group_id) const +//Cell::to_hdf5(hid_t group_id) const +Cell::to_hdf5(hid_t cell_group) 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(surf_group, "boundary_type", "transmission"); - break; - case BC_VACUUM : - write_string(surf_group, "boundary_type", "vacuum"); - break; - case BC_REFLECT : - write_string(surf_group, "boundary_type", "reflective"); - break; - case BC_PERIODIC : - write_string(surf_group, "boundary_type", "periodic"); - break; - } +// std::string group_name {"surface "}; +// group_name += std::to_string(id); +// +// hid_t surf_group = create_group(group_id, group_name); if (!name.empty()) { - write_string(surf_group, "name", name); + write_string(cell_group, "name", name); } - to_hdf5_inner(surf_group); + //TODO: Lookup universe id in universe_dict + //write_int(cell_group, "universe", universe); - close_group(surf_group); -*/ +// close_group(cell_group); } //============================================================================== diff --git a/src/cell.h b/src/cell.h index 90ca923e3d..7aa2d4bb31 100644 --- a/src/cell.h +++ b/src/cell.h @@ -38,6 +38,7 @@ class Cell public: int32_t id; //!< Unique ID std::string name{""}; //!< User-defined name + int32_t universe; //!< Universe # this cell is in explicit Cell(pugi::xml_node cell_node); @@ -58,6 +59,13 @@ extern "C" int32_t cell_id(Cell *c) {return c->id;} extern "C" void cell_set_id(Cell *c, int32_t id) {c->id = id;} +extern "C" int32_t cell_universe(Cell *c) {return c->universe;} + +extern "C" void cell_set_universe(Cell *c, int32_t universe) +{c->universe = universe;} + +extern "C" void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} + //extern "C" void free_memory_cells_c() //{ // delete cells_c; diff --git a/src/geometry.F90 b/src/geometry.F90 index 630c57c049..cdf286c740 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -223,7 +223,7 @@ contains if (use_search_cells) then i_cell = search_cells(i) ! check to make sure search cell is in same universe - if (cells(i_cell) % universe /= i_universe) cycle + if (cells(i_cell) % universe() /= i_universe) cycle else i_cell = universes(i_universe) % cells(i) end if diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index b938dddec6..8c900430fb 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -1,6 +1,7 @@ module geometry_header use, intrinsic :: ISO_C_BINDING + use hdf5 use algorithm, only: find use constants, only: HALF, TWO, THREE, INFINITY, K_BOLTZMANN, & @@ -35,6 +36,30 @@ module geometry_header type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T), intent(in), value :: id end subroutine cell_set_id_c + + function cell_universe_c(cell_ptr) bind(C, name='cell_universe') & + result(universe) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T) :: universe + end function cell_universe_c + + subroutine cell_set_universe_c(cell_ptr, universe) & + bind(C, name='cell_set_universe') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T), intent(in), value :: universe + end subroutine cell_set_universe_c + + subroutine cell_to_hdf5_c(cell_ptr, group) bind(C, name='cell_to_hdf5') + use ISO_C_BINDING + use hdf5 + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(HID_T), intent(in), value :: group + end subroutine cell_to_hdf5_c end interface !=============================================================================== @@ -150,10 +175,8 @@ module geometry_header type Cell type(C_PTR) :: ptr - character(len=104) :: name = "" ! User-defined name integer :: type ! Type of cell (normal, universe, ! lattice) - integer :: universe ! universe # this cell is in integer :: fill ! universe # filling this cell integer :: instances ! number of instances of this cell in ! the geom @@ -183,6 +206,9 @@ module geometry_header procedure :: id => cell_id procedure :: set_id => cell_set_id + procedure :: universe => cell_universe + procedure :: set_universe => cell_set_universe + procedure :: to_hdf5 => cell_to_hdf5 end type Cell @@ -385,6 +411,24 @@ contains call cell_set_id_c(this % ptr, id) end subroutine cell_set_id + function cell_universe(this) result(universe) + class(Cell), intent(in) :: this + integer(C_INT32_T) :: universe + universe = cell_universe_c(this % ptr) + end function cell_universe + + subroutine cell_set_universe(this, universe) + class(Cell), intent(in) :: this + integer(C_INT32_T), intent(in) :: universe + call cell_set_universe_c(this % ptr, universe) + end subroutine cell_set_universe + + subroutine cell_to_hdf5(this, group) + class(Cell), intent(in) :: this + integer(HID_T), intent(in) :: group + call cell_to_hdf5_c(this % ptr, group) + end subroutine cell_to_hdf5 + !=============================================================================== ! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table ! appears at in the model. Later, this list is used to determine the actual diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 89dce7ab23..f5a3028551 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -43,6 +43,36 @@ close_group(hid_t group_id) } +inline void +write_int(hid_t group_id, char const *name, int32_t buffer) +{ + hid_t dataspace = H5Screate(H5S_SCALAR); + + hid_t dataset = H5Dcreate(group_id, name, H5T_NATIVE_INT32, dataspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + + H5Dwrite(dataset, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL, H5P_DEFAULT, &buffer); + + H5Sclose(dataspace); + H5Dclose(dataset); +} + + +//inline void +//write_double(hid_t group_id, char const *name, double buffer) +//{ +// hid_t dataspace = H5Screate(H5S_SCALAR); +// +// 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); +// +// H5Sclose(dataspace); +// H5Dclose(dataset); +//} + + template inline void write_double_1D(hid_t group_id, char const *name, std::array &buffer) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a9d6874000..7679fde2d0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1029,16 +1029,6 @@ contains ! Get pointer to i-th cell node node_cell = node_cell_list(i) - ! Copy cell name - if (check_for_node(node_cell, "name")) then - call get_node_value(node_cell, "name", c % name) - end if - - if (check_for_node(node_cell, "universe")) then - call get_node_value(node_cell, "universe", c % universe) - else - c % universe = 0 - end if if (check_for_node(node_cell, "fill")) then call get_node_value(node_cell, "fill", c % fill) if (find(fill_univ_ids, c % fill) == -1) & @@ -1249,7 +1239,7 @@ contains ! For cells, we also need to check if there's a new universe -- ! also for every cell add 1 to the count of cells for the ! specified universe - univ_id = c % universe + univ_id = c % universe() if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 n_cells_in_univ = 1 @@ -1623,7 +1613,7 @@ contains do i = 1, n_cells ! Get index in universes array - j = universe_dict % get(cells(i) % universe) + j = universe_dict % get(cells(i) % universe()) ! Set the first zero entry in the universe cells array to the index in the ! global cells array @@ -4406,9 +4396,9 @@ contains ! ADJUST UNIVERSE INDEX FOR EACH CELL associate (c => cells(i)) - id = c % universe + id = c % universe() if (universe_dict % has(id)) then - c % universe = universe_dict % get(id) + call c % set_universe(universe_dict % get(id)) else call fatal_error("Could not find universe " // trim(to_str(id)) & &// " specified on cell " // trim(to_str(c % id()))) diff --git a/src/summary.F90 b/src/summary.F90 index d21b192a30..3aa8514242 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -147,11 +147,10 @@ contains c => cells(i) cell_group = create_group(cells_group, "cell " // trim(to_str(c%id()))) - ! Write name for this cell - call write_dataset(cell_group, "name", c%name) + call c % to_hdf5(cell_group) ! Write universe for this cell - call write_dataset(cell_group, "universe", universes(c%universe)%id) + call write_dataset(cell_group, "universe", universes(c%universe())%id) ! Write information on what fills this cell select case (c%type) From a7c86c0ec6e195ccb8afacc46541900b8f474468 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 4 Feb 2018 17:44:04 -0500 Subject: [PATCH 03/41] Translate cell_contains to C++ --- src/cell.cpp | 322 +++++++++++++++++++++++++++++++++++++++- src/cell.h | 59 ++++---- src/geometry.F90 | 130 +++------------- src/geometry_header.F90 | 18 ++- src/input_xml.F90 | 102 ------------- src/output.F90 | 2 +- src/surface.cpp | 60 ++++++++ src/surface.h | 62 +------- src/surface_header.F90 | 19 --- src/tracking.F90 | 6 +- 10 files changed, 455 insertions(+), 325 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 2b2943fc4a..8d3cc832e3 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1,10 +1,14 @@ #include "cell.h" +#include +#include +#include #include #include #include "error.h" #include "hdf5_interface.h" +#include "surface.h" #include "xml_interface.h" //TODO: remove this include @@ -13,6 +17,178 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; +constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; +constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; +constexpr int32_t OP_INTERSECTION {std::numeric_limits::max() - 3}; +constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; + +//============================================================================== +//! Convert region specification string to integer tokens. +//! +//! The characters (, ), |, and ~ count as separate tokens since they represent +//! operators. +//============================================================================== + +std::vector +tokenize(const std::string region_spec) { + // Check for an empty region_spec first. + if (region_spec.empty()) { + std::vector tokens; + return tokens; + } + + // Make a regex expression that matches halfspace tokens and every operator + // except for intersection (whitespace). + std::string re {"\\+?-?\\d+" // Matches halfspaces like 1, -13, and +42 + "|\\(|\\)" // Matches left and right parentheses + "|\\||~"}; // Matches | and ~ + + // Make another regex that includes whitespce, and use it to make sure there + // are no invalid characters. + { + std::string re_invalid {re + "|\\s+"}; + std::regex re_invalid_ {re_invalid}; + auto words_begin = std::sregex_token_iterator(region_spec.begin(), + region_spec.end(), re_invalid_, -1); + auto words_end = std::sregex_token_iterator(); + for (auto it = words_begin; it != words_end; it++) { + std::string match = it->str(); + if (match.length() > 0) { + std::stringstream err_msg; + err_msg << "Region specification contains invalid character(s): \"" + << match << "\""; + fatal_error(err_msg); + } + } + } + + // Use the regex to parse the string and convert all halfspaces and operators + // (except intersection) into integer tokens. + std::vector tokens; + std::regex re_(re); + auto words_begin = std::sregex_iterator(region_spec.begin(), + region_spec.end(), re_); + auto words_end = std::sregex_iterator(); + for (auto it = words_begin; it != words_end; it++) { + std::regex re_half("\\+?-?\\d+"); + if (std::regex_match(it->str(), re_half)) { + tokens.push_back(stoi(it->str())); + } else if (it->str() == "(") { + tokens.push_back(OP_LEFT_PAREN); + } else if (it->str() == ")") { + tokens.push_back(OP_RIGHT_PAREN); + } else if (it->str() == "|") { + tokens.push_back(OP_UNION); + } else if (it->str() == "~") { + tokens.push_back(OP_COMPLEMENT); + } + } + + // Add in intersection operators where a missing operator is needed. + int i = 0; + while (i < tokens.size()-1) { + bool left_compat {(tokens[i] < OP_UNION) || (tokens[i] == OP_RIGHT_PAREN)}; + bool right_compat {(tokens[i+1] < OP_UNION) + || (tokens[i+1] == OP_LEFT_PAREN) + || (tokens[i+1] == OP_COMPLEMENT)}; + if (left_compat && right_compat) { + tokens.insert(tokens.begin()+i+1, OP_INTERSECTION); + } + i++; + } + + return tokens; +} + +//============================================================================== +//! Convert infix region specification to Reverse Polish Notation (RPN) +//! +//! This function uses the shunting-yard algorithm. +//============================================================================== + +std::vector +generate_rpn(int32_t cell_id, std::vector infix) +{ + std::vector rpn; + std::vector stack; + + for (int32_t token : infix) { + if (token < OP_UNION) { + // If token is not an operator, add it to output + rpn.push_back(token); + + } else if (token < OP_RIGHT_PAREN) { + // Regular operators union, intersection, complement + while (stack.size() > 0) { + int op = stack.back(); + + if (op < OP_RIGHT_PAREN && + ((token == OP_COMPLEMENT && token < op) || + (token != OP_COMPLEMENT && token <= op))) { + // While there is an operator, op, on top of the stack, if the token + // is left-associative and its precedence is less than or equal to + // that of op or if the token is right-associative and its precedence + // is less than that of op, move op to the output queue and push the + // token on to the stack. Note that only complement is + // right-associative. + rpn.push_back(op); + stack.pop_back(); + } else { + break; + } + } + + stack.push_back(token); + + } else if (token == OP_LEFT_PAREN) { + // If the token is a left parenthesis, push it onto the stack + stack.push_back(token); + + } else { + // If the token is a right parenthesis, move operators from the stack to + // the output queue until reaching the left parenthesis. + for (auto it = stack.rbegin(); *it != OP_LEFT_PAREN; it++) { + // If we run out of operators without finding a left parenthesis, it + // means there are mismatched parentheses. + if (it == stack.rend()) { + std::stringstream err_msg; + err_msg << "Mismatched parentheses in region specification for cell " + << cell_id; + fatal_error(err_msg); + } + + rpn.push_back(stack.back()); + stack.pop_back(); + } + + // Pop the left parenthesis. + stack.pop_back(); + } + } + + while (stack.size() > 0) { + int op = stack.back(); + + // If the operator is a parenthesis it is mismatched. + if (op >= OP_RIGHT_PAREN) { + std::stringstream err_msg; + err_msg << "Mismatched parentheses in region specification for cell " + << cell_id; + fatal_error(err_msg); + } + + rpn.push_back(stack.back()); + stack.pop_back(); + } + + return rpn; +} + //============================================================================== // Cell implementation //============================================================================== @@ -35,10 +211,49 @@ Cell::Cell(pugi::xml_node cell_node) } else { universe = 0; } + + std::string region_spec {""}; + if (check_for_node(cell_node, "region")) { + region_spec = get_node_value(cell_node, "region"); + } + + // Get a tokenized representation of the region specification. + region = tokenize(region_spec); + region.shrink_to_fit(); + + // Convert user IDs to surface indices. + // Note that the index has 1 added to it in order to preserve the sign. + for (auto it = region.begin(); it != region.end(); it++) { + if (*it < OP_UNION) { + *it = copysign(surface_dict[abs(*it)]+1, *it); + } + } + + // Convert the infix region spec to RPN. + rpn = generate_rpn(id, region); + rpn.shrink_to_fit(); + + // Check if this is a simple cell. + simple = true; + for (int token : rpn) { + if ((token == OP_COMPLEMENT) || (token == OP_UNION)) { + simple = false; + break; + } + } +} + +bool +Cell::contains(const double xyz[3], const double uvw[3], int on_surface) const +{ + if (simple) { + return contains_simple(xyz, uvw, on_surface); + } else { + return contains_complex(xyz, uvw, on_surface); + } } void -//Cell::to_hdf5(hid_t group_id) const Cell::to_hdf5(hid_t cell_group) const { // std::string group_name {"surface "}; @@ -56,6 +271,79 @@ Cell::to_hdf5(hid_t cell_group) const // close_group(cell_group); } +bool +Cell::contains_simple(const double xyz[3], const double uvw[3], int on_surface) +const +{ + for (int token : rpn) { + if (token < OP_UNION) { + // If the token is not an operator, evaluate the sense of particle with + // respect to the surface and see if the token matches the sense. If the + // particle's surface attribute is set and matches the token, that + // overrides the determination based on sense(). + if (token == on_surface) { + } else if (-token == on_surface) { + return false; + } else { + // Note the off-by-one indexing + bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw); + if (sense != (token > 0)) {return false;} + } + } + } + return true; +} + +bool +Cell::contains_complex(const double xyz[3], const double uvw[3], int on_surface) +const +{ + // Make a stack of booleans. We don't know how big it needs to be, but we do + // know that rpn.size() is an upper-bound. + bool stack[rpn.size()]; + int i_stack = -1; + + for (int token : rpn) { + // If the token is a binary operator (intersection/union), apply it to + // the last two items on the stack. If the token is a unary operator + // (complement), apply it to the last item on the stack. + if (token == OP_UNION) { + stack[i_stack-1] = stack[i_stack-1] || stack[i_stack]; + i_stack --; + } else if (token == OP_INTERSECTION) { + stack[i_stack-1] = stack[i_stack-1] && stack[i_stack]; + i_stack --; + } else if (token == OP_COMPLEMENT) { + stack[i_stack] = !stack[i_stack]; + } else { + // If the token is not an operator, evaluate the sense of particle with + // respect to the surface and see if the token matches the sense. If the + // particle's surface attribute is set and matches the token, that + // overrides the determination based on sense(). + i_stack ++; + if (token == on_surface) { + stack[i_stack] = true; + } else if (-token == on_surface) { + stack[i_stack] = false; + } else { + // Note the off-by-one indexing + bool sense = surfaces_c[abs(token)-1]->sense(xyz, uvw);; + stack[i_stack] = (sense == (token > 0)); + } + } + } + + if (i_stack == 0) { + // The one remaining bool on the stack indicates whether the particle is + // in the cell. + return stack[i_stack]; + } else { + // This case occurs if there is no region specification since i_stack will + // still be -1. + return true; + } +} + //============================================================================== extern "C" void @@ -74,7 +362,37 @@ read_cells(pugi::xml_node *node) for (pugi::xml_node cell_node: node->children("cell")) { cells_c.push_back(Cell(cell_node)); } - } +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" { + Cell* cell_pointer(int cell_ind) {return &cells_c[cell_ind];} + + int32_t cell_id(Cell *c) {return c->id;} + + void cell_set_id(Cell *c, int32_t id) {c->id = id;} + + int32_t cell_universe(Cell *c) {return c->universe;} + + void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;} + + bool cell_simple(Cell *c) {return c->simple;} + + bool cell_contains(Cell *c, double xyz[3], double uvw[3], int on_surface) + {return c->contains(xyz, uvw, on_surface);} + + void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} +} + +//extern "C" void free_memory_cells_c() +//{ +// delete cells_c; +// cells_c = nullptr; +// n_cells = 0; +// cell_dict.clear(); +//} + } // namespace openmc diff --git a/src/cell.h b/src/cell.h index 7aa2d4bb31..0531c23d07 100644 --- a/src/cell.h +++ b/src/cell.h @@ -40,39 +40,44 @@ public: std::string name{""}; //!< User-defined name int32_t universe; //!< Universe # this cell is in + //! Definition of spatial region as Boolean expression of half-spaces + std::vector region; + //! Reverse Polish notation for region expression + std::vector rpn; + bool simple; //!< Does the region contain only intersections? + explicit Cell(pugi::xml_node cell_node); + //! Determine if a cell contains the particle at a given location. + //! + //! The bounds of the cell are detemined by a logical expression involving + //! surface half-spaces. At initialization, the expression was converted + //! to RPN notation. + //! + //! The function is split into two cases, one for simple cells (those + //! involving only the intersection of half-spaces) and one for complex cells. + //! Simple cells can be evaluated with short circuit evaluation, i.e., as soon + //! as we know that one half-space is not satisfied, we can exit. This + //! provides a performance benefit for the common case. In + //! contains_complex, we evaluate the RPN expression using a stack, similar to //! how a RPN calculator would work. + //! @param xyz[3] The 3D Cartesian coordinate to check. + //! @param uvw[3] A direction used to "break ties" the coordinates are very + //! close to a surface. + //! @param on_surface The signed index of a surface that the coordinate is + //! known to be on. This index takes precedence over surface sense + //! calculations. + bool contains(const double xyz[3], const double uvw[3], int on_surface) const; + //! Write all information needed to reconstruct the cell to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; + +protected: + bool contains_simple(const double xyz[3], const double uvw[3], + int on_surface) const; + bool contains_complex(const double xyz[3], const double uvw[3], + int on_surface) const; }; -//============================================================================== -// Fortran compatibility functions -//============================================================================== - -extern "C" void read_cells(pugi::xml_node *node); - -extern "C" Cell* cell_pointer(int cell_ind) {return &cells_c[cell_ind];} - -extern "C" int32_t cell_id(Cell *c) {return c->id;} - -extern "C" void cell_set_id(Cell *c, int32_t id) {c->id = id;} - -extern "C" int32_t cell_universe(Cell *c) {return c->universe;} - -extern "C" void cell_set_universe(Cell *c, int32_t universe) -{c->universe = universe;} - -extern "C" void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} - -//extern "C" void free_memory_cells_c() -//{ -// delete cells_c; -// cells_c = nullptr; -// n_cells = 0; -// cell_dict.clear(); -//} - } // namespace openmc #endif // CELL_H diff --git a/src/geometry.F90 b/src/geometry.F90 index cdf286c740..84f11ecc29 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -14,125 +14,29 @@ module geometry implicit none + interface + function cell_contains_c(cell_ptr, xyz, uvw, on_surface) & + bind(C, name="cell_contains") result(in_cell) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT), intent(in), value :: on_surface + logical(C_BOOL) :: in_cell + end function cell_contains_c + end interface + contains -!=============================================================================== -! CELL_CONTAINS determines if a cell contains the particle at a given -! location. The bounds of the cell are detemined by a logical expression -! involving surface half-spaces. At initialization, the expression was converted -! to RPN notation. -! -! The function is split into two cases, one for simple cells (those involving -! only the intersection of half-spaces) and one for complex cells. Simple cells -! can be evaluated with short circuit evaluation, i.e., as soon as we know that -! one half-space is not satisfied, we can exit. This provides a performance -! benefit for the common case. In complex_cell_contains, we evaluate the RPN -! expression using a stack, similar to how a RPN calculator would work. -!=============================================================================== - - pure function cell_contains(c, p) result(in_cell) + function cell_contains(c, p) result(in_cell) type(Cell), intent(in) :: c type(Particle), intent(in) :: p logical :: in_cell - - if (c%simple) then - in_cell = simple_cell_contains(c, p) - else - in_cell = complex_cell_contains(c, p) - end if + in_cell = cell_contains_c(c%ptr, p%coord(p%n_coord)%xyz, & + p%coord(p%n_coord)%uvw, p%surface) end function cell_contains - pure function simple_cell_contains(c, p) result(in_cell) - type(Cell), intent(in) :: c - type(Particle), intent(in) :: p - logical :: in_cell - - integer :: i - integer :: token - logical :: actual_sense ! sense of particle wrt surface - - in_cell = .true. - do i = 1, size(c%rpn) - token = c%rpn(i) - if (token < OP_UNION) then - ! If the token is not an operator, evaluate the sense of particle with - ! respect to the surface and see if the token matches the sense. If the - ! particle's surface attribute is set and matches the token, that - ! overrides the determination based on sense(). - if (token == p%surface) then - cycle - elseif (-token == p%surface) then - in_cell = .false. - exit - else - actual_sense = surfaces(abs(token)) % sense( & - p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) - if (actual_sense .neqv. (token > 0)) then - in_cell = .false. - exit - end if - end if - end if - end do - end function simple_cell_contains - - pure function complex_cell_contains(c, p) result(in_cell) - type(Cell), intent(in) :: c - type(Particle), intent(in) :: p - logical :: in_cell - - integer :: i - integer :: token - integer :: i_stack - logical :: actual_sense ! sense of particle wrt surface - logical :: stack(size(c%rpn)) - - i_stack = 0 - do i = 1, size(c%rpn) - token = c%rpn(i) - - ! If the token is a binary operator (intersection/union), apply it to - ! the last two items on the stack. If the token is a unary operator - ! (complement), apply it to the last item on the stack. - select case (token) - case (OP_UNION) - stack(i_stack - 1) = stack(i_stack - 1) .or. stack(i_stack) - i_stack = i_stack - 1 - case (OP_INTERSECTION) - stack(i_stack - 1) = stack(i_stack - 1) .and. stack(i_stack) - i_stack = i_stack - 1 - case (OP_COMPLEMENT) - stack(i_stack) = .not. stack(i_stack) - case default - ! If the token is not an operator, evaluate the sense of particle with - ! respect to the surface and see if the token matches the sense. If the - ! particle's surface attribute is set and matches the token, that - ! overrides the determination based on sense(). - i_stack = i_stack + 1 - if (token == p%surface) then - stack(i_stack) = .true. - elseif (-token == p%surface) then - stack(i_stack) = .false. - else - actual_sense = surfaces(abs(token)) % sense( & - p%coord(p%n_coord)%xyz, p%coord(p%n_coord)%uvw) - stack(i_stack) = (actual_sense .eqv. (token > 0)) - end if - end select - - end do - - if (i_stack == 1) then - ! The one remaining logical on the stack indicates whether the particle is - ! in the cell. - in_cell = stack(i_stack) - else - ! This case occurs if there is no region specification since i_stack will - ! still be zero. - in_cell = .true. - end if - end function complex_cell_contains - !=============================================================================== ! CHECK_CELL_OVERLAP checks for overlapping cells at the current particle's ! position using cell_contains and the LocalCoord's built up by find_cell @@ -737,7 +641,7 @@ contains ! positive half-space were given in the region specification. Thus, we ! have to explicitly check which half-space the particle would be ! traveling into if the surface is crossed - if (.not. c % simple) then + if (.not. c % simple()) then xyz_cross(:) = p % coord(j) % xyz + d_surf*p % coord(j) % uvw call surfaces(abs(level_surf_cross)) % normal(xyz_cross, surf_uvw) if (dot_product(p % coord(j) % uvw, surf_uvw) > ZERO) then diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 8c900430fb..5c200c02d9 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -53,6 +53,13 @@ module geometry_header integer(C_INT32_T), intent(in), value :: universe end subroutine cell_set_universe_c + function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + logical(C_BOOL) :: simple + end function cell_simple_c + subroutine cell_to_hdf5_c(cell_ptr, group) bind(C, name='cell_to_hdf5') use ISO_C_BINDING use hdf5 @@ -187,10 +194,6 @@ module geometry_header ! counter integer, allocatable :: region(:) ! Definition of spatial region as ! Boolean expression of half-spaces - integer, allocatable :: rpn(:) ! Reverse Polish notation for region - ! expression - logical :: simple ! Is the region simple (intersections - ! only) integer :: distribcell_index ! Index corresponding to this cell in ! distribcell arrays real(8), allocatable :: sqrtkT(:) ! Square root of k_Boltzmann * @@ -208,6 +211,7 @@ module geometry_header procedure :: set_id => cell_set_id procedure :: universe => cell_universe procedure :: set_universe => cell_set_universe + procedure :: simple => cell_simple procedure :: to_hdf5 => cell_to_hdf5 end type Cell @@ -429,6 +433,12 @@ contains call cell_to_hdf5_c(this % ptr, group) end subroutine cell_to_hdf5 + function cell_simple(this) result(simple) + class(Cell), intent(in) :: this + logical(C_BOOL) :: simple + simple = cell_simple_c(this % ptr) + end function cell_simple + !=============================================================================== ! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table ! appears at in the model. Later, this list is used to determine the actual diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7679fde2d0..71b3b8d640 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -942,7 +942,6 @@ contains type(XMLNode), allocatable :: node_rlat_list(:) type(XMLNode), allocatable :: node_hlat_list(:) type(VectorInt) :: tokens - type(VectorInt) :: rpn type(VectorInt) :: fill_univ_ids ! List of fill universe IDs type(VectorInt) :: univ_ids ! List of all universe IDs type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each @@ -1120,27 +1119,13 @@ contains end if end do - ! Use shunting-yard algorithm to determine RPN for surface algorithm - call generate_rpn(c%id(), tokens, rpn) - ! Copy region spec and RPN form to cell arrays allocate(c % region(tokens%size())) - allocate(c % rpn(rpn%size())) c % region(:) = tokens%data(1:tokens%size()) - c % rpn(:) = rpn%data(1:rpn%size()) call tokens%clear() - call rpn%clear() end if if (.not. allocated(c%region)) allocate(c%region(0)) - if (.not. allocated(c%rpn)) allocate(c%rpn(0)) - - ! Check if this is a simple cell - if (any(c%rpn == OP_COMPLEMENT) .or. any(c%rpn == OP_UNION)) then - c%simple = .false. - else - c%simple = .true. - end if ! Rotation matrix if (check_for_node(node_cell, "rotation")) then @@ -3982,93 +3967,6 @@ contains end subroutine read_mg_cross_sections_header -!=============================================================================== -! GENERATE_RPN implements the shunting-yard algorithm to generate a Reverse -! Polish notation (RPN) expression for the region specification of a cell given -! the infix notation. -!=============================================================================== - - subroutine generate_rpn(cell_id, tokens, output) - integer, intent(in) :: cell_id - type(VectorInt), intent(in) :: tokens ! infix notation - type(VectorInt), intent(inout) :: output ! RPN notation - - integer :: i - integer :: token - integer :: op - type(VectorInt) :: stack - - do i = 1, tokens%size() - token = tokens%data(i) - - if (token < OP_UNION) then - ! If token is not an operator, add it to output - call output%push_back(token) - - elseif (token < OP_RIGHT_PAREN) then - ! Regular operators union, intersection, complement - do while (stack%size() > 0) - op = stack%data(stack%size()) - - if (op < OP_RIGHT_PAREN .and. & - ((token == OP_COMPLEMENT .and. token < op) .or. & - (token /= OP_COMPLEMENT .and. token <= op))) then - ! While there is an operator, op, on top of the stack, if the token - ! is left-associative and its precedence is less than or equal to - ! that of op or if the token is right-associative and its precedence - ! is less than that of op, move op to the output queue and push the - ! token on to the stack. Note that only complement is - ! right-associative. - call output%push_back(op) - call stack%pop_back() - else - exit - end if - end do - - call stack%push_back(token) - - elseif (token == OP_LEFT_PAREN) then - ! If the token is a left parenthesis, push it onto the stack - call stack%push_back(token) - - else - ! If the token is a right parenthesis, move operators from the stack to - ! the output queue until reaching the left parenthesis. - do - ! If we run out of operators without finding a left parenthesis, it - ! means there are mismatched parentheses. - if (stack%size() == 0) then - call fatal_error('Mimatched parentheses in region specification & - &for cell ' // trim(to_str(cell_id)) // '.') - end if - - op = stack%data(stack%size()) - if (op == OP_LEFT_PAREN) exit - call output%push_back(op) - call stack%pop_back() - end do - - ! Pop the left parenthesis. - call stack%pop_back() - end if - end do - - ! While there are operators on the stack, move them to the output queue - do while (stack%size() > 0) - op = stack%data(stack%size()) - - ! If the operator is a parenthesis, it is mismatched - if (op >= OP_RIGHT_PAREN) then - call fatal_error('Mimatched parentheses in region specification & - &for cell ' // trim(to_str(cell_id)) // '.') - end if - - call output%push_back(op) - call stack%pop_back() - end do - end subroutine generate_rpn - !=============================================================================== ! NORMALIZE_AO Normalize the nuclide atom percents !=============================================================================== diff --git a/src/output.F90 b/src/output.F90 index c8efcecbc3..483d171cae 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -258,7 +258,7 @@ contains end do ! Print surface - if (p % surface /= NONE) then + if (p % surface /= ERROR_INT) then write(ou,*) ' Surface = ' // to_str(sign(surfaces(i)%id(), p % surface)) end if diff --git a/src/surface.cpp b/src/surface.cpp index 9abfd23d2e..64c9568ba6 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -11,6 +11,26 @@ namespace openmc { +//============================================================================== +// Module constant definitions +//============================================================================== + +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 variables +//============================================================================== + +// Braces force n_surfaces to be defined here, not just declared. +extern "C" {int32_t n_surfaces {0};} + +Surface **surfaces_c; + +std::map surface_dict; + //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== @@ -1232,4 +1252,44 @@ read_surfaces(pugi::xml_node *node) } } +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" { + Surface* surface_pointer(int surf_ind) {return surfaces_c[surf_ind];} + + int surface_id(Surface *surf) {return surf->id;} + + int surface_bc(Surface *surf) {return surf->bc;} + + void surface_reflect(Surface *surf, double xyz[3], double uvw[3]) + {surf->reflect(xyz, uvw);} + + double + surface_distance(Surface *surf, double xyz[3], double uvw[3], bool coincident) + {return surf->distance(xyz, uvw, coincident);} + + void surface_normal(Surface *surf, double xyz[3], double uvw[3]) + {return surf->normal(xyz, uvw);} + + void surface_to_hdf5(Surface *surf, hid_t group) {surf->to_hdf5(group);} + + int surface_i_periodic(PeriodicSurface *surf) {return surf->i_periodic;} + + bool + surface_periodic(PeriodicSurface *surf, PeriodicSurface *other, double xyz[3], + double uvw[3]) + {return surf->periodic_translate(other, xyz, uvw);} + + void free_memory_surfaces_c() + { + for (int i = 0; i < n_surfaces; i++) {delete surfaces_c[i];} + delete surfaces_c; + surfaces_c = nullptr; + n_surfaces = 0; + surface_dict.clear(); + } +} + } // namespace openmc diff --git a/src/surface.h b/src/surface.h index 33139ace12..046610daa1 100644 --- a/src/surface.h +++ b/src/surface.h @@ -12,13 +12,13 @@ namespace openmc { //============================================================================== -// Module constants +// Module constant declarations (defined in .cpp) //============================================================================== -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; +extern "C" const int BC_VACUUM; +extern "C" const int BC_REFLECT; +extern "C" const int BC_PERIODIC; //============================================================================== // Constants that should eventually be moved out of this file @@ -32,13 +32,12 @@ constexpr int C_NONE {-1}; // Global variables //============================================================================== -// Braces force n_surfaces to be defined here, not just declared. -extern "C" {int32_t n_surfaces {0};} +extern "C" int32_t n_surfaces; class Surface; -Surface **surfaces_c; +extern Surface **surfaces_c; -std::map surface_dict; +extern std::map surface_dict; //============================================================================== //! Coordinates for an axis-aligned cube that bounds a geometric object. @@ -381,50 +380,5 @@ public: void to_hdf5_inner(hid_t group_id) const; }; -//============================================================================== -// Fortran compatibility functions -//============================================================================== - -extern "C" void read_surfaces(pugi::xml_node *node); - -extern "C" Surface* surface_pointer(int surf_ind) {return surfaces_c[surf_ind];} - -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(Surface *surf, double xyz[3], double uvw[3], bool coincident) -{return surf->distance(xyz, uvw, coincident);} - -extern "C" void surface_normal(Surface *surf, double xyz[3], double uvw[3]) -{return surf->normal(xyz, uvw);} - -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(PeriodicSurface *surf, PeriodicSurface *other, double xyz[3], - double uvw[3]) -{return surf->periodic_translate(other, xyz, uvw);} - -extern "C" void free_memory_surfaces_c() -{ - for (int i = 0; i < n_surfaces; i++) {delete surfaces_c[i];} - delete surfaces_c; - 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 9ed89a14e9..991decc3cc 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -30,16 +30,6 @@ module surface_header 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 @@ -116,7 +106,6 @@ module surface_header procedure :: id => surface_id procedure :: bc => surface_bc - procedure :: sense => surface_sense procedure :: reflect => surface_reflect procedure :: distance => surface_distance procedure :: normal => surface_normal @@ -147,14 +136,6 @@ contains 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); diff --git a/src/tracking.F90 b/src/tracking.F90 index 127da02226..7a7f1fd94d 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -173,7 +173,7 @@ contains p % coord(p % n_coord) % cell = NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary - p % surface = NONE + p % surface = ERROR_INT call cross_lattice(p, lattice_translation) p % event = EVENT_LATTICE else @@ -202,7 +202,7 @@ contains if (active_current_tallies % size() > 0) call score_surface_current(p) ! Clear surface component - p % surface = NONE + p % surface = ERROR_INT if (run_CE) then call collision(p) @@ -472,7 +472,7 @@ contains ! COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS ! Remove lower coordinate levels and assignment of surface - p % surface = NONE + p % surface = ERROR_INT p % n_coord = 1 call find_cell(p, found) From 41f84bddc8037f88123c7de5d19519679330ac3e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 4 Feb 2018 21:11:12 -0500 Subject: [PATCH 04/41] Move all surface distance calls to C++ --- src/cell.cpp | 93 +++++++++++++++++++++++++++++++++-------- src/cell.h | 14 +++---- src/geometry.F90 | 36 ++++------------ src/geometry_header.F90 | 39 +++++++++++++---- src/summary.F90 | 22 ---------- src/surface.cpp | 4 -- src/surface_header.F90 | 21 ---------- 7 files changed, 121 insertions(+), 108 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 8d3cc832e3..83942cf73f 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -21,11 +21,13 @@ namespace openmc { // Constants //============================================================================== -constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; -constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; -constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; -constexpr int32_t OP_INTERSECTION {std::numeric_limits::max() - 3}; -constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; +constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; +constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; +constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; +constexpr int32_t OP_INTERSECTION {std::numeric_limits::max() - 3}; +constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; + +extern "C" double FP_PRECISION; //============================================================================== //! Convert region specification string to integer tokens. @@ -125,7 +127,7 @@ generate_rpn(int32_t cell_id, std::vector infix) } else if (token < OP_RIGHT_PAREN) { // Regular operators union, intersection, complement while (stack.size() > 0) { - int op = stack.back(); + int32_t op = stack.back(); if (op < OP_RIGHT_PAREN && ((token == OP_COMPLEMENT && token < op) || @@ -172,7 +174,7 @@ generate_rpn(int32_t cell_id, std::vector infix) } while (stack.size() > 0) { - int op = stack.back(); + int32_t op = stack.back(); // If the operator is a parenthesis it is mismatched. if (op >= OP_RIGHT_PAREN) { @@ -235,7 +237,7 @@ Cell::Cell(pugi::xml_node cell_node) // Check if this is a simple cell. simple = true; - for (int token : rpn) { + for (int32_t token : rpn) { if ((token == OP_COMPLEMENT) || (token == OP_UNION)) { simple = false; break; @@ -244,7 +246,8 @@ Cell::Cell(pugi::xml_node cell_node) } bool -Cell::contains(const double xyz[3], const double uvw[3], int on_surface) const +Cell::contains(const double xyz[3], const double uvw[3], + int32_t on_surface) const { if (simple) { return contains_simple(xyz, uvw, on_surface); @@ -253,6 +256,35 @@ Cell::contains(const double xyz[3], const double uvw[3], int on_surface) const } } +std::pair +Cell::distance(const double xyz[3], const double uvw[3], + int32_t on_surface) const +{ + double min_dist {INFTY}; + int32_t i_surf {std::numeric_limits::max()}; + + for (int32_t token : rpn) { + // Ignore this token if it corresponds to an operator rather than a region. + if (token >= OP_UNION) {continue;} + + // Calculate the distance to this surface. + // Note the off-by-one indexing + bool coincident {token == on_surface}; + double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)}; + //std::cout << token << " " << on_surface << " " << coincident << std::endl; + + // Check if this distance is the new minimum. + if (d < min_dist) { + if (std::abs(d - min_dist) / min_dist >= FP_PRECISION) { + min_dist = d; + i_surf = -token; + } + } + } + + return {min_dist, i_surf}; +} + void Cell::to_hdf5(hid_t cell_group) const { @@ -268,14 +300,33 @@ Cell::to_hdf5(hid_t cell_group) const //TODO: Lookup universe id in universe_dict //write_int(cell_group, "universe", universe); + // Write the region specification. + std::stringstream region_spec {}; + for (int32_t token : region) { + if (token == OP_LEFT_PAREN) { + region_spec << " ("; + } else if (token == OP_RIGHT_PAREN) { + region_spec << " )"; + } else if (token == OP_COMPLEMENT) { + region_spec << " ~"; + } else if (token == OP_INTERSECTION) { + } else if (token == OP_UNION) { + region_spec << " |"; + } else { + // Note the off-by-one indexing + region_spec << " " << copysign(surfaces_c[abs(token)-1]->id, token); + } + } + write_string(cell_group, "region", region_spec.str()); + // close_group(cell_group); } bool -Cell::contains_simple(const double xyz[3], const double uvw[3], int on_surface) -const +Cell::contains_simple(const double xyz[3], const double uvw[3], + int32_t on_surface) const { - for (int token : rpn) { + for (int32_t token : rpn) { if (token < OP_UNION) { // If the token is not an operator, evaluate the sense of particle with // respect to the surface and see if the token matches the sense. If the @@ -295,15 +346,15 @@ const } bool -Cell::contains_complex(const double xyz[3], const double uvw[3], int on_surface) -const +Cell::contains_complex(const double xyz[3], const double uvw[3], + int32_t on_surface) const { // Make a stack of booleans. We don't know how big it needs to be, but we do // know that rpn.size() is an upper-bound. bool stack[rpn.size()]; int i_stack = -1; - for (int token : rpn) { + for (int32_t token : rpn) { // If the token is a binary operator (intersection/union), apply it to // the last two items on the stack. If the token is a unary operator // (complement), apply it to the last item on the stack. @@ -369,7 +420,7 @@ read_cells(pugi::xml_node *node) //============================================================================== extern "C" { - Cell* cell_pointer(int cell_ind) {return &cells_c[cell_ind];} + Cell* cell_pointer(int32_t cell_ind) {return &cells_c[cell_ind];} int32_t cell_id(Cell *c) {return c->id;} @@ -381,9 +432,17 @@ extern "C" { bool cell_simple(Cell *c) {return c->simple;} - bool cell_contains(Cell *c, double xyz[3], double uvw[3], int on_surface) + bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface) {return c->contains(xyz, uvw, on_surface);} + void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface, + double &min_dist, int32_t &i_surf) + { + std::pair out = c->distance(xyz, uvw, on_surface); + min_dist = out.first; + i_surf = out.second; + } + void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} } diff --git a/src/cell.h b/src/cell.h index 0531c23d07..5f9369e559 100644 --- a/src/cell.h +++ b/src/cell.h @@ -12,10 +12,6 @@ namespace openmc { -//============================================================================== -// Module constants -//============================================================================== - //============================================================================== // Global variables //============================================================================== @@ -66,7 +62,11 @@ public: //! @param on_surface The signed index of a surface that the coordinate is //! known to be on. This index takes precedence over surface sense //! calculations. - bool contains(const double xyz[3], const double uvw[3], int on_surface) const; + bool + contains(const double xyz[3], const double uvw[3], int32_t on_surface) const; + + std::pair + distance(const double xyz[3], const double uvw[3], int32_t on_surface) const; //! Write all information needed to reconstruct the cell to an HDF5 group. //! @param group_id An HDF5 group id. @@ -74,9 +74,9 @@ public: protected: bool contains_simple(const double xyz[3], const double uvw[3], - int on_surface) const; + int32_t on_surface) const; bool contains_complex(const double xyz[3], const double uvw[3], - int on_surface) const; + int32_t on_surface) const; }; } // namespace openmc diff --git a/src/geometry.F90 b/src/geometry.F90 index 84f11ecc29..74e9731fff 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -19,11 +19,11 @@ module geometry bind(C, name="cell_contains") result(in_cell) use ISO_C_BINDING implicit none - type(C_PTR), intent(in), value :: cell_ptr - real(C_DOUBLE), intent(in) :: xyz(3) - real(C_DOUBLE), intent(in) :: uvw(3) - integer(C_INT), intent(in), value :: on_surface - logical(C_BOOL) :: in_cell + type(C_PTR), intent(in), value :: cell_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT32_T), intent(in), value :: on_surface + logical(C_BOOL) :: in_cell end function cell_contains_c end interface @@ -368,9 +368,7 @@ contains integer, intent(out) :: lattice_translation(3) integer, intent(out) :: next_level - integer :: i ! index for surface in cell integer :: j - integer :: index_surf ! index in surfaces array (with sign) integer :: i_xyz(3) ! lattice indices integer :: level_surf_cross ! surface crossed on current level integer :: level_lat_trans(3) ! lattice translation on current level @@ -387,7 +385,6 @@ contains 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(Lattice), pointer :: lat @@ -413,27 +410,8 @@ contains ! ======================================================================= ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL - SURFACE_LOOP: do i = 1, size(c % region) - index_surf = c % region(i) - coincident = (index_surf == p % surface) - - ! ignore this token if it corresponds to an operator rather than a - ! region. - index_surf = abs(index_surf) - if (index_surf >= OP_UNION) cycle - - ! Calculate distance to surface - 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 - if (d < d_surf) then - if (abs(d - d_surf)/d_surf >= FP_PRECISION) then - d_surf = d - level_surf_cross = -c % region(i) - end if - end if - end do SURFACE_LOOP + call c % distance(p % coord(j) % xyz, p % coord(j) % uvw, p % surface, & + d_surf, level_surf_cross) ! ======================================================================= ! FIND MINIMUM DISTANCE TO LATTICE SURFACES diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 5c200c02d9..32511ea3d7 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -19,8 +19,8 @@ module geometry_header function cell_pointer_c(cell_ind) bind(C, name='cell_pointer') result(ptr) use ISO_C_BINDING implicit none - integer(C_INT), intent(in), value :: cell_ind - type(C_PTR) :: ptr + integer(C_INT32_T), intent(in), value :: cell_ind + type(C_PTR) :: ptr end function cell_pointer_c function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) @@ -60,6 +60,18 @@ module geometry_header logical(C_BOOL) :: simple end function cell_simple_c + subroutine cell_distance_c(cell_ptr, xyz, uvw, on_surface, min_dist, & + i_surf) bind(C, name="cell_distance") + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: cell_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT32_T), intent(in), value :: on_surface + real(C_DOUBLE), intent(out) :: min_dist + integer(C_INT32_T), intent(out) :: i_surf + end subroutine cell_distance_c + subroutine cell_to_hdf5_c(cell_ptr, group) bind(C, name='cell_to_hdf5') use ISO_C_BINDING use hdf5 @@ -212,6 +224,7 @@ module geometry_header procedure :: universe => cell_universe procedure :: set_universe => cell_set_universe procedure :: simple => cell_simple + procedure :: distance => cell_distance procedure :: to_hdf5 => cell_to_hdf5 end type Cell @@ -427,18 +440,28 @@ contains call cell_set_universe_c(this % ptr, universe) end subroutine cell_set_universe - subroutine cell_to_hdf5(this, group) - class(Cell), intent(in) :: this - integer(HID_T), intent(in) :: group - call cell_to_hdf5_c(this % ptr, group) - end subroutine cell_to_hdf5 - function cell_simple(this) result(simple) class(Cell), intent(in) :: this logical(C_BOOL) :: simple simple = cell_simple_c(this % ptr) end function cell_simple + subroutine cell_distance(this, xyz, uvw, on_surface, min_dist, i_surf) + class(Cell), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT32_T), intent(in) :: on_surface + real(C_DOUBLE), intent(out) :: min_dist + integer(C_INT32_T), intent(out) :: i_surf + call cell_distance_c(this % ptr, xyz, uvw, on_surface, min_dist, i_surf) + end subroutine cell_distance + + subroutine cell_to_hdf5(this, group) + class(Cell), intent(in) :: this + integer(HID_T), intent(in) :: group + call cell_to_hdf5_c(this % ptr, group) + end subroutine cell_to_hdf5 + !=============================================================================== ! GET_TEMPERATURES returns a list of temperatures that each nuclide/S(a,b) table ! appears at in the model. Later, this list is used to determine the actual diff --git a/src/summary.F90 b/src/summary.F90 index 3aa8514242..5e5ab778a0 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -125,7 +125,6 @@ contains 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(Lattice), pointer :: lat @@ -204,27 +203,6 @@ contains call write_dataset(cell_group, "lattice", lattices(c%fill)%obj%id) end select - ! Write list of bounding surfaces - region_spec = "" - do j = 1, size(c%region) - k = c%region(j) - select case(k) - case (OP_LEFT_PAREN) - region_spec = trim(region_spec) // " (" - case (OP_RIGHT_PAREN) - region_spec = trim(region_spec) // " )" - case (OP_COMPLEMENT) - region_spec = trim(region_spec) // " ~" - case (OP_INTERSECTION) - case (OP_UNION) - region_spec = trim(region_spec) // " |" - case default - region_spec = trim(region_spec) // " " // to_str(& - sign(surfaces(abs(k))%id(), k)) - end select - end do - call write_dataset(cell_group, "region", adjustl(region_spec)) - call close_group(cell_group) end do CELL_LOOP diff --git a/src/surface.cpp b/src/surface.cpp index 64c9568ba6..32b1a3ce60 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1266,10 +1266,6 @@ extern "C" { void surface_reflect(Surface *surf, double xyz[3], double uvw[3]) {surf->reflect(xyz, uvw);} - double - surface_distance(Surface *surf, double xyz[3], double uvw[3], bool coincident) - {return surf->distance(xyz, uvw, coincident);} - void surface_normal(Surface *surf, double xyz[3], double uvw[3]) {return surf->normal(xyz, uvw);} diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 991decc3cc..67f6cd06cb 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -39,17 +39,6 @@ module surface_header 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 @@ -107,7 +96,6 @@ module surface_header procedure :: id => surface_id procedure :: bc => surface_bc procedure :: reflect => surface_reflect - procedure :: distance => surface_distance procedure :: normal => surface_normal procedure :: to_hdf5 => surface_to_hdf5 procedure :: i_periodic => surface_i_periodic @@ -143,15 +131,6 @@ contains 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); From 197e91cf90dae5e620d61637a02e734df6ccc871 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 4 Feb 2018 23:15:32 -0500 Subject: [PATCH 05/41] Add skeleton of C++ lattices --- CMakeLists.txt | 2 + src/cell.cpp | 32 +++---- src/cell.h | 13 +++ src/geometry.F90 | 4 +- src/geometry_header.F90 | 44 ++++++++- src/input_xml.F90 | 60 ++++--------- src/lattice.cpp | 109 +++++++++++++++++++++++ src/lattice.h | 77 ++++++++++++++++ src/output.F90 | 2 +- src/summary.F90 | 7 +- src/tallies/tally_filter_distribcell.F90 | 4 +- 11 files changed, 286 insertions(+), 68 deletions(-) create mode 100644 src/lattice.cpp create mode 100644 src/lattice.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c1228c4939..ef9daabd28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -439,6 +439,8 @@ set(LIBOPENMC_CXX_SRC src/cell.h src/error.h src/hdf5_interface.h + src/lattice.cpp + src/lattice.h src/random_lcg.cpp src/random_lcg.h src/surface.cpp diff --git a/src/cell.cpp b/src/cell.cpp index 83942cf73f..427e30890d 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -301,23 +301,25 @@ Cell::to_hdf5(hid_t cell_group) const //write_int(cell_group, "universe", universe); // Write the region specification. - std::stringstream region_spec {}; - for (int32_t token : region) { - if (token == OP_LEFT_PAREN) { - region_spec << " ("; - } else if (token == OP_RIGHT_PAREN) { - region_spec << " )"; - } else if (token == OP_COMPLEMENT) { - region_spec << " ~"; - } else if (token == OP_INTERSECTION) { - } else if (token == OP_UNION) { - region_spec << " |"; - } else { - // Note the off-by-one indexing - region_spec << " " << copysign(surfaces_c[abs(token)-1]->id, token); + if (!region.empty()) { + std::stringstream region_spec {}; + for (int32_t token : region) { + if (token == OP_LEFT_PAREN) { + region_spec << " ("; + } else if (token == OP_RIGHT_PAREN) { + region_spec << " )"; + } else if (token == OP_COMPLEMENT) { + region_spec << " ~"; + } else if (token == OP_INTERSECTION) { + } else if (token == OP_UNION) { + region_spec << " |"; + } else { + // Note the off-by-one indexing + region_spec << " " << copysign(surfaces_c[abs(token)-1]->id, token); + } } + write_string(cell_group, "region", region_spec.str()); } - write_string(cell_group, "region", region_spec.str()); // close_group(cell_group); } diff --git a/src/cell.h b/src/cell.h index 5f9369e559..59cec17291 100644 --- a/src/cell.h +++ b/src/cell.h @@ -25,6 +25,19 @@ std::vector cells_c; std::map cell_dict; +//============================================================================== +//! A geometry primitive that fills all space and contains cells. +//============================================================================== + +class Universe +{ + public: + int32_t id; //! Unique ID + int32_t type; + std::vector cells; //! Cells within this universe + double x0, y0, z0; //! Translation coordinates. +}; + //============================================================================== //! A geometry primitive that links surfaces, universes, and materials //============================================================================== diff --git a/src/geometry.F90 b/src/geometry.F90 index 74e9731fff..1f241f66d4 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -260,7 +260,7 @@ contains ! Particle is outside the lattice. if (lat % outer == NO_OUTER_UNIVERSE) then call p % mark_as_lost("Particle " // trim(to_str(p %id)) & - // " is outside lattice " // trim(to_str(lat % id)) & + // " is outside lattice " // trim(to_str(lat % id())) & // " but the lattice has no defined outer universe.") return else @@ -299,7 +299,7 @@ contains lat => lattices(p % coord(j) % lattice) % obj if (verbosity >= 10 .or. trace) then - call write_message(" Crossing lattice " // trim(to_str(lat % id)) & + call write_message(" Crossing lattice " // trim(to_str(lat % id())) & &// ". Current position (" // trim(to_str(p % coord(j) % lattice_x)) & &// "," // trim(to_str(p % coord(j) % lattice_y)) // "," & &// trim(to_str(p % coord(j) % lattice_z)) // ")") diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 32511ea3d7..ad34c735ca 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -79,6 +79,29 @@ module geometry_header type(C_PTR), intent(in), value :: cell_ptr integer(HID_T), intent(in), value :: group end subroutine cell_to_hdf5_c + + function lattice_pointer_c(lat_ind) bind(C, name='lattice_pointer') & + result(ptr) + use ISO_C_BINDING + implicit none + integer(C_INT32_T), intent(in), value :: lat_ind + type(C_PTR) :: ptr + end function lattice_pointer_c + + function lattice_id_c(lat_ptr) bind(C, name='lattice_id') result(id) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + integer(C_INT32_T) :: id + end function lattice_id_c + + subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5') + use ISO_C_BINDING + use hdf5 + implicit none + type(C_PTR), intent(in), value :: lat_ptr + integer(HID_T), intent(in), value :: group + end subroutine lattice_to_hdf5_c end interface !=============================================================================== @@ -99,8 +122,9 @@ module geometry_header !=============================================================================== type, abstract :: Lattice - integer :: id ! Universe number for lattice - character(len=104) :: name = "" ! User-defined name + type(C_PTR) :: ptr + + !integer :: id ! Universe number for lattice real(8), allocatable :: pitch(:) ! Pitch along each axis integer, allocatable :: universes(:,:,:) ! Specified universes integer :: outside ! Material to fill area outside @@ -108,6 +132,10 @@ module geometry_header logical :: is_3d ! Lattice has cells on z axis integer, allocatable :: offset(:,:,:,:) ! Distribcell offsets contains + + procedure :: id => lattice_id + procedure :: to_hdf5 => lattice_to_hdf5 + procedure(lattice_are_valid_indices_), deferred :: are_valid_indices procedure(lattice_get_indices_), deferred :: get_indices procedure(lattice_get_local_xyz_), deferred :: get_local_xyz @@ -247,6 +275,18 @@ module geometry_header contains + function lattice_id(this) result(id) + class(Lattice), intent(in) :: this + integer(C_INT32_T) :: id + id = lattice_id_c(this % ptr) + end function lattice_id + + subroutine lattice_to_hdf5(this, group) + class(Lattice), intent(in) :: this + integer(HID_T), intent(in) :: group + call lattice_to_hdf5_c(this % ptr, group) + end subroutine lattice_to_hdf5 + !=============================================================================== function valid_inds_rect(this, i_xyz) result(is_valid) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 71b3b8d640..78dd0bb877 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -60,6 +60,12 @@ module input_xml implicit none type(C_PTR) :: node_ptr end subroutine read_cells + + subroutine read_lattices(node_ptr) bind(C) + use ISO_C_BINDING + implicit none + type(C_PTR) :: node_ptr + end subroutine read_lattices end interface contains @@ -1240,6 +1246,8 @@ contains ! ========================================================================== ! READ LATTICES FROM GEOMETRY.XML + call read_lattices(root % ptr) + ! Get pointer to list of XML call get_node_list(root, "lattice", node_rlat_list) call get_node_list(root, "hex_lattice", node_hlat_list) @@ -1253,30 +1261,13 @@ contains RECT_LATTICES: do i = 1, n_rlats allocate(RectLattice::lattices(i) % obj) lat => lattices(i) % obj + lat % ptr = lattice_pointer_c(i - 1) select type(lat) type is (RectLattice) ! Get pointer to i-th lattice node_lat = node_rlat_list(i) - ! ID of lattice - if (check_for_node(node_lat, "id")) then - call get_node_value(node_lat, "id", lat % id) - else - call fatal_error("Must specify id of lattice in geometry XML file.") - end if - - ! Check to make sure 'id' hasn't been used - if (lattice_dict % has(lat % id)) then - call fatal_error("Two or more lattices use the same unique ID: " & - // to_str(lat % id)) - end if - - ! Copy lattice name - if (check_for_node(node_lat, "name")) then - call get_node_value(node_lat, "name", lat % name) - end if - ! Read number of lattice cells in each dimension n = node_word_count(node_lat, "dimension") if (n == 2) then @@ -1341,7 +1332,7 @@ contains n = node_word_count(node_lat, "universes") if (n /= n_x*n_y*n_z) then call fatal_error("Number of universes on does not match & - &size of lattice " // trim(to_str(lat % id)) // ".") + &size of lattice " // trim(to_str(lat % id())) // ".") end if allocate(temp_int_array(n)) @@ -1377,7 +1368,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % set(lat % id, i) + call lattice_dict % set(lat % id(), i) end select end do RECT_LATTICES @@ -1385,30 +1376,13 @@ contains HEX_LATTICES: do i = 1, n_hlats allocate(HexLattice::lattices(n_rlats + i) % obj) lat => lattices(n_rlats + i) % obj + lat % ptr = lattice_pointer_c(n_rlats + i - 1) select type (lat) type is (HexLattice) ! Get pointer to i-th lattice node_lat = node_hlat_list(i) - ! ID of lattice - if (check_for_node(node_lat, "id")) then - call get_node_value(node_lat, "id", lat % id) - else - call fatal_error("Must specify id of lattice in geometry XML file.") - end if - - ! Check to make sure 'id' hasn't been used - if (lattice_dict % has(lat % id)) then - call fatal_error("Two or more lattices use the same unique ID: " & - // to_str(lat % id)) - end if - - ! Copy lattice name - if (check_for_node(node_lat, "name")) then - call get_node_value(node_lat, "name", lat % name) - end if - ! Read number of lattice cells in each dimension call get_node_value(node_lat, "n_rings", lat % n_rings) if (check_for_node(node_lat, "n_axial")) then @@ -1454,7 +1428,7 @@ contains n = node_word_count(node_lat, "universes") if (n /= (3*n_rings**2 - 3*n_rings + 1)*n_z) then call fatal_error("Number of universes on does not match & - &size of lattice " // trim(to_str(lat % id)) // ".") + &size of lattice " // trim(to_str(lat % id())) // ".") end if allocate(temp_int_array(n)) @@ -1564,7 +1538,7 @@ contains end if ! Add lattice to dictionary - call lattice_dict % set(lat % id, n_rlats + i) + call lattice_dict % set(lat % id(), n_rlats + i) end select end do HEX_LATTICES @@ -4353,7 +4327,7 @@ contains else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id))) + &// trim(to_str(lat % id()))) end if end do end do @@ -4374,7 +4348,7 @@ contains else call fatal_error("Invalid universe number " & &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id))) + &// trim(to_str(lat % id()))) end if end do end do @@ -4388,7 +4362,7 @@ contains else call fatal_error("Invalid universe number " & &// trim(to_str(lat % outer)) & - &// " specified on lattice " // trim(to_str(lat % id))) + &// " specified on lattice " // trim(to_str(lat % id()))) end if end if diff --git a/src/lattice.cpp b/src/lattice.cpp new file mode 100644 index 0000000000..73758b1104 --- /dev/null +++ b/src/lattice.cpp @@ -0,0 +1,109 @@ +#include "lattice.h" + +#include +#include + +#include "error.h" +#include "hdf5_interface.h" +#include "xml_interface.h" + +//TODO: remove this include +#include + + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +// Braces force n_lattices to be defined here, not just declared. +//extern "C" {int32_t n_lattices {0};} + +//Lattice **lattices_c; +std::vector lattices_c; + +std::map lattice_dict; + +//============================================================================== +// Lattice implementation +//============================================================================== + +Lattice::Lattice(pugi::xml_node lat_node) +{ + if (check_for_node(lat_node, "id")) { + id = stoi(get_node_value(lat_node, "id")); + } else { + fatal_error("Must specify id of lattice in geometry XML file."); + } + + if (check_for_node(lat_node, "name")) { + name = get_node_value(lat_node, "name"); + } +} + +void +Lattice::to_hdf5(hid_t lat_group) const +{ + if (!name.empty()) { + write_string(lat_group, "name", name); + } +} + +//============================================================================== +// RectLattice implementation +//============================================================================== + +RectLattice::RectLattice(pugi::xml_node lat_node) + : Lattice {lat_node} +{ +} + +//============================================================================== +// HexLattice implementation +//============================================================================== + +HexLattice::HexLattice(pugi::xml_node lat_node) + : Lattice {lat_node} +{ +} + +//============================================================================== + +extern "C" void +read_lattices(pugi::xml_node *node) +{ + for (pugi::xml_node lat_node: node->children("lattice")) { + lattices_c.push_back(new RectLattice(lat_node)); + } + for (pugi::xml_node lat_node: node->children("hex_lattice")) { + lattices_c.push_back(new HexLattice(lat_node)); + } + + // Fill the lattice dictionary. + for (int i_lat = 0; i_lat < lattices_c.size(); i_lat++) { + int id = lattices_c[i_lat]->id; + auto in_dict = lattice_dict.find(id); + if (in_dict == lattice_dict.end()) { + lattice_dict[id] = i_lat; + } else { + std::stringstream err_msg; + err_msg << "Two or more lattices use the same unique ID: " << id; + fatal_error(err_msg); + } + } +} + +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" { + Lattice* lattice_pointer(int lat_ind) {return lattices_c[lat_ind];} + + int32_t lattice_id(Lattice *lat) {return lat->id;} + + void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} +} + +} // namespace openmc diff --git a/src/lattice.h b/src/lattice.h new file mode 100644 index 0000000000..d8e1ba39ac --- /dev/null +++ b/src/lattice.h @@ -0,0 +1,77 @@ +#ifndef LATTICE_H +#define LATTICE_H + +#include +#include +#include +#include + +#include "hdf5.h" +#include "pugixml/pugixml.hpp" + + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +//extern "C" int32_t n_lattice; + +class Lattice; +//extern Lattice **lattices_c; +extern std::vector lattices_c; + +extern std::map lattice_dict; + +//============================================================================== +//! Abstract type for ordered array of universes +//============================================================================== + +class Lattice +{ +public: + int32_t id; //! Universe ID number + std::string name; //! User-defined name + //std::vector pitch; //! Pitch along each basis + //std::vector universes; //! Universes filling each lattice tile + //int32_t outer; //! Universe tiled outside the lattice + //std::vector offset; //! Distribcell offsets + + explicit Lattice(pugi::xml_node lat_node); + + virtual ~Lattice() {} + + //virtual bool are_valid_indices(const int i_xyz[3]) const = 0; + + //virtual void get_indices(const double global_xyz[3], int i_xyz[3]) const = 0; + + //virtual void get_local_xyz(const double global_xyz[3], const int i_xyz[3], + // double local_xyz[3]) const = 0; + + //! Write all information needed to reconstruct the lattice to an HDF5 group. + //! @param group_id An HDF5 group id. + void to_hdf5(hid_t group_id) const; +}; + +//============================================================================== +//============================================================================== + +class RectLattice : public Lattice +{ +public: + explicit RectLattice(pugi::xml_node lat_node); + + virtual ~RectLattice() {} +}; + +class HexLattice : public Lattice +{ +public: + explicit HexLattice(pugi::xml_node lat_node); + + virtual ~HexLattice() {} +}; + +} // namespace openmc +#endif // LATTICE_H diff --git a/src/output.F90 b/src/output.F90 index 483d171cae..81f6e12925 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -246,7 +246,7 @@ contains ! Print information on lattice if (p % coord(i) % lattice /= NONE) then l => lattices(p % coord(i) % lattice) % obj - write(ou,*) ' Lattice = ' // trim(to_str(l % id)) + write(ou,*) ' Lattice = ' // trim(to_str(l % id())) write(ou,*) ' Lattice position = (' // trim(to_str(& p % coord(i) % lattice_x)) // ',' // trim(to_str(& p % coord(i) % lattice_y)) // ')' diff --git a/src/summary.F90 b/src/summary.F90 index 5e5ab778a0..59bb904475 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -200,7 +200,7 @@ contains case (FILL_LATTICE) call write_dataset(cell_group, "fill_type", "lattice") - call write_dataset(cell_group, "lattice", lattices(c%fill)%obj%id) + call write_dataset(cell_group, "lattice", lattices(c%fill)%obj%id()) end select call close_group(cell_group) @@ -258,10 +258,11 @@ contains ! Write information on each lattice LATTICE_LOOP: do i = 1, n_lattices lat => lattices(i)%obj - lattice_group = create_group(lattices_group, "lattice " // trim(to_str(lat%id))) + lattice_group = create_group(lattices_group, "lattice " // trim(to_str(lat%id()))) + + call lat % to_hdf5(lattice_group) ! Write name, pitch, and outer universe - call write_dataset(lattice_group, "name", lat%name) call write_dataset(lattice_group, "pitch", lat%pitch) if (lat % outer > 0) then call write_dataset(lattice_group, "outer", universes(lat % outer) % id) diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index 310af1cb6b..e7a9645ae5 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -270,7 +270,7 @@ contains type is (RectLattice) ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id) + path = trim(path) // "->l" // to_str(lat%id()) n_x = lat % n_cells(1) n_y = lat % n_cells(2) @@ -332,7 +332,7 @@ contains type is (HexLattice) ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id) + path = trim(path) // "->l" // to_str(lat%id()) n_z = lat % n_axial n_y = 2 * lat % n_rings - 1 From e13c60ed4195b94d1f9afc1c355005cc9b36b6f0 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 7 Feb 2018 12:24:25 -0500 Subject: [PATCH 06/41] Fill in C++ RectLattice constructor --- src/lattice.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++++ src/lattice.h | 27 +++++++++++++---- src/xml_interface.h | 15 ++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 73758b1104..006b7bbdd7 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -57,6 +57,76 @@ Lattice::to_hdf5(hid_t lat_group) const RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} { + // Read the number of lattice cells in each dimension. + std::string dimension_str{get_node_value(lat_node, "dimension")}; + std::vector dimension_words{split(dimension_str)}; + if (dimension_words.size() == 2) { + n_cells[0] = stoi(dimension_words[0]); + n_cells[1] = stoi(dimension_words[1]); + n_cells[2] = 1; + is_3d = false; + } else if (dimension_words.size() == 3) { + n_cells[0] = stoi(dimension_words[0]); + n_cells[1] = stoi(dimension_words[1]); + n_cells[2] = stoi(dimension_words[2]); + is_3d = true; + } else { + fatal_error("Rectangular lattice must be two or three dimensions."); + } + + // Read the lattice lower-left location. + std::string ll_str{get_node_value(lat_node, "lower_left")}; + std::vector ll_words{split(ll_str)}; + if (ll_words.size() != dimension_words.size()) { + fatal_error("Number of entries on must be the same as the " + "number of entries on ."); + } + lower_left[0] = stoi(ll_words[0]); + lower_left[1] = stoi(ll_words[1]); + if (is_3d) {lower_left[2] = stoi(ll_words[2]);} + + // Read the lattice pitches. + std::string pitch_str{get_node_value(lat_node, "pitch")}; + std::vector pitch_words{split(pitch_str)}; + if (pitch_words.size() != dimension_words.size()) { + fatal_error("Number of entries on must be the same as the " + "number of entries on ."); + } + pitch[0] = stoi(pitch_words[0]); + pitch[1] = stoi(pitch_words[1]); + if (is_3d) {pitch[2] = stoi(pitch_words[2]);} + + // Read the universes and make sure the correct number was specified. + int nx = n_cells[0]; + int ny = n_cells[1]; + int nz = n_cells[2]; + std::string univ_str{get_node_value(lat_node, "universes")}; + std::vector univ_words{split(univ_str)}; + if (univ_words.size() != nx*ny*nz) { + std::stringstream err_msg; + err_msg << "Expected " << nx*ny*nz + << " universes for a rectangular lattice of size " + << nx << "x" << ny << "x" << nz << " but " << univ_words.size() + << " were specified."; + fatal_error(err_msg); + } + + // Parse the universes. + universes.resize(nx*ny*nz, -1); + for (int iz = 0; iz < nz; iz++) { + for (int iy = ny-1; iy > -1; iy--) { + for (int ix = 0; ix < nx; ix++) { + int indx1 = nx*ny*iz + nx*(ny-iy-1) + ix; + int indx2 = nx*ny*iz + nx*iy + ix; + universes[indx1] = stoi(univ_words[indx2]); + } + } + } + + // Read the outer universe for the area outside the lattice. + if (check_for_node(lat_node, "outer")) { + outer = stoi(get_node_value(lat_node, "outer")); + } } //============================================================================== diff --git a/src/lattice.h b/src/lattice.h index d8e1ba39ac..05b642e202 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -1,6 +1,7 @@ #ifndef LATTICE_H #define LATTICE_H +#include #include #include #include @@ -12,6 +13,12 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +constexpr int32_t NO_OUTER_UNIVERSE{-1}; + //============================================================================== // Global variables //============================================================================== @@ -31,12 +38,12 @@ extern std::map lattice_dict; class Lattice { public: - int32_t id; //! Universe ID number - std::string name; //! User-defined name - //std::vector pitch; //! Pitch along each basis - //std::vector universes; //! Universes filling each lattice tile - //int32_t outer; //! Universe tiled outside the lattice - //std::vector offset; //! Distribcell offsets + int32_t id; //! Universe ID number + std::string name; //! User-defined name + //std::vector pitch; //! Pitch along each basis + std::vector universes; //! Universes filling each lattice tile + int32_t outer{NO_OUTER_UNIVERSE}; //! Universe tiled outside the lattice + //std::vector offset; //! Distribcell offsets explicit Lattice(pugi::xml_node lat_node); @@ -52,6 +59,9 @@ public: //! Write all information needed to reconstruct the lattice to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; + +protected: + bool is_3d; //! Has divisions along the z-axis }; //============================================================================== @@ -63,6 +73,11 @@ public: explicit RectLattice(pugi::xml_node lat_node); virtual ~RectLattice() {} + +protected: + std::array n_cells; //! Number of cells along each axis + std::array lower_left; //! Global lower-left corner of the lattice + std::array pitch; //! Lattice tile width along each axis }; class HexLattice : public Lattice diff --git a/src/xml_interface.h b/src/xml_interface.h index 8dd1cf5808..b619dce223 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -2,14 +2,29 @@ #define XML_INTERFACE_H #include // for std::transform +#include #include #include +#include #include "pugixml/pugixml.hpp" namespace openmc { +inline std::vector +split(const std::string in) +{ + std::vector out; + std::regex re("\\S+"); + for (auto it = std::sregex_iterator(in.begin(), in.end(), re); + it != std::sregex_iterator(); + it++) { + out.push_back(it->str()); + } + return out; +} + inline bool check_for_node(pugi::xml_node node, const char *name) { From 8b31730ec442d23963ba51747b9514b582c37dbb Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 7 Feb 2018 13:32:10 -0500 Subject: [PATCH 07/41] Update Travis GCC to v5 for C++11 regex --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index de83325e03..667594f66c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,13 @@ python: - "3.6" addons: apt: + sources: + - ubuntu-toolchain-r-test packages: - gfortran - mpich - libmpich-dev + - g++-5 cache: directories: - $HOME/nndc_hdf5 From 0f49193b2935ce02b8cf020fa941d88338d9cb82 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 7 Feb 2018 16:37:36 -0500 Subject: [PATCH 08/41] Remove C++ regex to support GCC < 4.9 --- .travis.yml | 3 -- src/cell.cpp | 67 ++++++++++++++++++--------------------------- src/xml_interface.h | 24 ++++++++++++---- 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index 667594f66c..de83325e03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,13 +7,10 @@ python: - "3.6" addons: apt: - sources: - - ubuntu-toolchain-r-test packages: - gfortran - mpich - libmpich-dev - - g++-5 cache: directories: - $HOME/nndc_hdf5 diff --git a/src/cell.cpp b/src/cell.cpp index 427e30890d..6b37a68077 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -39,55 +38,41 @@ extern "C" double FP_PRECISION; std::vector tokenize(const std::string region_spec) { // Check for an empty region_spec first. + std::vector tokens; if (region_spec.empty()) { - std::vector tokens; return tokens; } - // Make a regex expression that matches halfspace tokens and every operator - // except for intersection (whitespace). - std::string re {"\\+?-?\\d+" // Matches halfspaces like 1, -13, and +42 - "|\\(|\\)" // Matches left and right parentheses - "|\\||~"}; // Matches | and ~ + // Split the region_spec into words delimited by whitespace. This removes + // intersection operators but we'll add them back later. + std::vector words{split(region_spec)}; - // Make another regex that includes whitespce, and use it to make sure there - // are no invalid characters. - { - std::string re_invalid {re + "|\\s+"}; - std::regex re_invalid_ {re_invalid}; - auto words_begin = std::sregex_token_iterator(region_spec.begin(), - region_spec.end(), re_invalid_, -1); - auto words_end = std::sregex_token_iterator(); - for (auto it = words_begin; it != words_end; it++) { - std::string match = it->str(); - if (match.length() > 0) { - std::stringstream err_msg; - err_msg << "Region specification contains invalid character(s): \"" - << match << "\""; - fatal_error(err_msg); - } - } - } - - // Use the regex to parse the string and convert all halfspaces and operators - // (except intersection) into integer tokens. - std::vector tokens; - std::regex re_(re); - auto words_begin = std::sregex_iterator(region_spec.begin(), - region_spec.end(), re_); - auto words_end = std::sregex_iterator(); - for (auto it = words_begin; it != words_end; it++) { - std::regex re_half("\\+?-?\\d+"); - if (std::regex_match(it->str(), re_half)) { - tokens.push_back(stoi(it->str())); - } else if (it->str() == "(") { + // Iterate over words in the region_spec. + for (std::string word : words) { + // First check to see if this word represents an operator token. + if (word == "(") { tokens.push_back(OP_LEFT_PAREN); - } else if (it->str() == ")") { + } else if (word == ")") { tokens.push_back(OP_RIGHT_PAREN); - } else if (it->str() == "|") { + } else if (word == "|") { tokens.push_back(OP_UNION); - } else if (it->str() == "~") { + } else if (word == "~") { tokens.push_back(OP_COMPLEMENT); + + } else { + // This word might represent a halfspace. Check to make sure we recognize + // all the characters in it. + for (char c : word) { + if (!std::isdigit(c) && c != '-') { + std::stringstream err_msg; + err_msg << "Region specification contains invalid character, \"" + << c << "\""; + fatal_error(err_msg); + } + } + + // It's a halfspace. Convert to integer token. + tokens.push_back(stoi(word)); } } diff --git a/src/xml_interface.h b/src/xml_interface.h index b619dce223..7ccd991b01 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -2,7 +2,6 @@ #define XML_INTERFACE_H #include // for std::transform -#include #include #include #include @@ -12,19 +11,32 @@ namespace openmc { + inline std::vector split(const std::string in) { std::vector out; - std::regex re("\\S+"); - for (auto it = std::sregex_iterator(in.begin(), in.end(), re); - it != std::sregex_iterator(); - it++) { - out.push_back(it->str()); + + for (int i = 0; i < in.size(); ) { + // Increment i until we find a non-whitespace character. + if (std::isspace(in[i])) { + i++; + + } else { + // Find the next whitespace character at j. + int j = i + 1; + while (j < in.size() && std::isspace(in[j]) == 0) {j++;} + + // Push-back everything between i and j. + out.push_back(in.substr(i, j-i)); + i = j + 1; // j is whitespace so leapfrog to j+1 + } } + return out; } + inline bool check_for_node(pugi::xml_node node, const char *name) { From 98af5ed6becda38858f0d0b6baff65b64effd1da Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 14 Feb 2018 12:20:49 -0500 Subject: [PATCH 09/41] Fix complex cell tokenization --- src/cell.cpp | 53 ++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 6b37a68077..e7b76a9943 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -43,36 +43,41 @@ tokenize(const std::string region_spec) { return tokens; } - // Split the region_spec into words delimited by whitespace. This removes - // intersection operators but we'll add them back later. - std::vector words{split(region_spec)}; - - // Iterate over words in the region_spec. - for (std::string word : words) { - // First check to see if this word represents an operator token. - if (word == "(") { + // Parse all halfspaces and operators except for intersection (whitespace). + for (int i = 0; i < region_spec.size(); ) { + if (region_spec[i] == '(') { tokens.push_back(OP_LEFT_PAREN); - } else if (word == ")") { + i++; + + } else if (region_spec[i] == ')') { tokens.push_back(OP_RIGHT_PAREN); - } else if (word == "|") { + i++; + + } else if (region_spec[i] == '|') { tokens.push_back(OP_UNION); - } else if (word == "~") { + i++; + + } else if (region_spec[i] == '~') { tokens.push_back(OP_COMPLEMENT); + i++; + + } else if (region_spec[i] == '-' || region_spec[i] == '+' + || std::isdigit(region_spec[i])) { + // This is the start of a halfspace specification. Iterate j until we + // find the end, then push-back everything between i and j. + int j = i + 1; + while (j < region_spec.size() && std::isdigit(region_spec[j])) {j++;} + tokens.push_back(std::stoi(region_spec.substr(i, j-i))); + i = j; + + } else if (std::isspace(region_spec[i])) { + i++; } else { - // This word might represent a halfspace. Check to make sure we recognize - // all the characters in it. - for (char c : word) { - if (!std::isdigit(c) && c != '-') { - std::stringstream err_msg; - err_msg << "Region specification contains invalid character, \"" - << c << "\""; - fatal_error(err_msg); - } - } - - // It's a halfspace. Convert to integer token. - tokens.push_back(stoi(word)); + std::stringstream err_msg; + err_msg << "Region specification contains invalid character, \"" + << region_spec[i] << "\""; + fatal_error(err_msg); } } From 11336f875f67e8fca8c0ded359d7b66d2316cb22 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 14 Feb 2018 17:48:24 -0500 Subject: [PATCH 10/41] Add C++ RectLattice distance_to_boundary --- src/geometry.F90 | 66 +----------------------------- src/geometry_header.F90 | 21 ++++++++++ src/lattice.cpp | 89 ++++++++++++++++++++++++++++++++++++++--- src/lattice.h | 24 +++++++++-- 4 files changed, 127 insertions(+), 73 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 1f241f66d4..a6965cffb9 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -422,70 +422,8 @@ contains LAT_TYPE: select type(lat) type is (RectLattice) - ! copy local coordinates - x = p % coord(j) % xyz(1) - y = p % coord(j) % xyz(2) - z = p % coord(j) % xyz(3) - - ! determine oncoming edge - x0 = sign(lat % pitch(1) * HALF, u) - y0 = sign(lat % pitch(2) * HALF, v) - - ! left and right sides - if (abs(x - x0) < FP_PRECISION) then - d = INFINITY - elseif (u == ZERO) then - d = INFINITY - else - d = (x0 - x)/u - end if - - d_lat = d - if (u > 0) then - level_lat_trans(:) = [1, 0, 0] - else - level_lat_trans(:) = [-1, 0, 0] - end if - - ! front and back sides - if (abs(y - y0) < FP_PRECISION) then - d = INFINITY - elseif (v == ZERO) then - d = INFINITY - else - d = (y0 - y)/v - end if - - if (d < d_lat) then - d_lat = d - if (v > 0) then - level_lat_trans(:) = [0, 1, 0] - else - level_lat_trans(:) = [0, -1, 0] - end if - end if - - if (lat % is_3d) then - z0 = sign(lat % pitch(3) * HALF, w) - - ! top and bottom sides - if (abs(z - z0) < FP_PRECISION) then - d = INFINITY - elseif (w == ZERO) then - d = INFINITY - else - d = (z0 - z)/w - end if - - if (d < d_lat) then - d_lat = d - if (w > 0) then - level_lat_trans(:) = [0, 0, 1] - else - level_lat_trans(:) = [0, 0, -1] - end if - end if - end if + call lat % distance(p % coord(j) % xyz, p % coord(j) % uvw, & + d_lat, level_lat_trans) type is (HexLattice) LAT_TYPE ! Copy local coordinates. diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index ad34c735ca..101bf8f9a1 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -95,6 +95,17 @@ module geometry_header integer(C_INT32_T) :: id end function lattice_id_c + subroutine lattice_distance_c(lat_ptr, xyz, uvw, d, lattice_trans) & + bind(C, name='lattice_distance') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + real(C_DOUBLE), intent(out) :: d + integer(C_INT), intent(out) :: lattice_trans(3) + end subroutine lattice_distance_c + subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5') use ISO_C_BINDING use hdf5 @@ -134,6 +145,7 @@ module geometry_header contains procedure :: id => lattice_id + procedure :: distance => lattice_distance procedure :: to_hdf5 => lattice_to_hdf5 procedure(lattice_are_valid_indices_), deferred :: are_valid_indices @@ -281,6 +293,15 @@ contains id = lattice_id_c(this % ptr) end function lattice_id + subroutine lattice_distance(this, xyz, uvw, d, lattice_trans) + class(Lattice), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3) + real(C_DOUBLE), intent(in) :: uvw(3) + real(C_DOUBLE), intent(out) :: d + integer(C_INT), intent(out) :: lattice_trans(3) + call lattice_distance_c(this % ptr, xyz, uvw, d, lattice_trans) + end subroutine lattice_distance + subroutine lattice_to_hdf5(this, group) class(Lattice), intent(in) :: this integer(HID_T), intent(in) :: group diff --git a/src/lattice.cpp b/src/lattice.cpp index 006b7bbdd7..236e6d0bae 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -7,6 +7,9 @@ #include "hdf5_interface.h" #include "xml_interface.h" +//TODO: this is only inlcuded for constants that should be moved elsewhere +//#include "surface.h" + //TODO: remove this include #include @@ -81,9 +84,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node) fatal_error("Number of entries on must be the same as the " "number of entries on ."); } - lower_left[0] = stoi(ll_words[0]); - lower_left[1] = stoi(ll_words[1]); - if (is_3d) {lower_left[2] = stoi(ll_words[2]);} + lower_left[0] = stod(ll_words[0]); + lower_left[1] = stod(ll_words[1]); + if (is_3d) {lower_left[2] = stod(ll_words[2]);} // Read the lattice pitches. std::string pitch_str{get_node_value(lat_node, "pitch")}; @@ -92,9 +95,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node) fatal_error("Number of entries on must be the same as the " "number of entries on ."); } - pitch[0] = stoi(pitch_words[0]); - pitch[1] = stoi(pitch_words[1]); - if (is_3d) {pitch[2] = stoi(pitch_words[2]);} + pitch[0] = stod(pitch_words[0]); + pitch[1] = stod(pitch_words[1]); + if (is_3d) {pitch[2] = stod(pitch_words[2]);} // Read the universes and make sure the correct number was specified. int nx = n_cells[0]; @@ -129,6 +132,65 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } } +std::pair> +RectLattice::distance(const double xyz[3], const double uvw[3]) const +{ + // Get short aliases to the coordinates. + double x {xyz[0]}; + double y {xyz[1]}; + double z {xyz[2]}; + double u {uvw[0]}; + double v {uvw[1]}; + + // Determine the oncoming edge. + double x0 {copysign(0.5 * pitch[0], u)}; + double y0 {copysign(0.5 * pitch[1], v)}; + + // Left and right sides + double d {INFTY}; + std::array lattice_trans; + if ((std::abs(x - x0) > FP_PRECISION) && u != 0) { + d = (x0 - x) / u; + if (u > 0) { + lattice_trans = {1, 0, 0}; + } else { + lattice_trans = {-1, 0, 0}; + } + } + + // Front and back sides + if ((std::abs(y - y0) > FP_PRECISION) && v != 0) { + double this_d = (y0 - y) / v; + if (this_d < d) { + d = this_d; + if (v > 0) { + lattice_trans = {0, 1, 0}; + } else { + lattice_trans = {0, -1, 0}; + } + } + } + + // Top and bottom sides + if (is_3d) { + double w {uvw[2]}; + double z0 {copysign(0.5 * pitch[2], w)}; + if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { + double this_d = (z0 - z) / w; + if (this_d < d) { + d = this_d; + if (w > 0) { + lattice_trans = {0, 0, 1}; + } else { + lattice_trans = {0, 0, -1}; + } + } + } + } + + return {d, lattice_trans}; +} + //============================================================================== // HexLattice implementation //============================================================================== @@ -138,6 +200,11 @@ HexLattice::HexLattice(pugi::xml_node lat_node) { } +std::pair> +HexLattice::distance(const double xyz[3], const double uvw[3]) const +{ +} + //============================================================================== extern "C" void @@ -173,6 +240,16 @@ extern "C" { int32_t lattice_id(Lattice *lat) {return lat->id;} + void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3], + double *d, int lattice_trans[3]) + { + std::pair> ld {lat->distance(xyz, uvw)}; + *d = ld.first; + lattice_trans[0] = ld.second[0]; + lattice_trans[1] = ld.second[1]; + lattice_trans[2] = ld.second[2]; + } + void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} } diff --git a/src/lattice.h b/src/lattice.h index 05b642e202..1825f396b2 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -3,6 +3,7 @@ #include #include +#include // For numeric_limits #include #include #include @@ -13,6 +14,14 @@ namespace openmc { +//============================================================================== +// Constants that should eventually be moved out of this file +//============================================================================== + +extern "C" double FP_PRECISION; +constexpr double INFTY{std::numeric_limits::max()}; +constexpr int C_NONE {-1}; + //============================================================================== // Constants //============================================================================== @@ -51,6 +60,9 @@ public: //virtual bool are_valid_indices(const int i_xyz[3]) const = 0; + virtual std::pair> + distance(const double xyz[3], const double uvw[3]) const = 0; + //virtual void get_indices(const double global_xyz[3], int i_xyz[3]) const = 0; //virtual void get_local_xyz(const double global_xyz[3], const int i_xyz[3], @@ -74,10 +86,13 @@ public: virtual ~RectLattice() {} + std::pair> + distance(const double xyz[3], const double uvw[3]) const; + protected: - std::array n_cells; //! Number of cells along each axis - std::array lower_left; //! Global lower-left corner of the lattice - std::array pitch; //! Lattice tile width along each axis + std::array n_cells; //! Number of cells along each axis + std::array lower_left; //! Global lower-left corner of the lattice + std::array pitch; //! Lattice tile width along each axis }; class HexLattice : public Lattice @@ -86,6 +101,9 @@ public: explicit HexLattice(pugi::xml_node lat_node); virtual ~HexLattice() {} + + std::pair> + distance(const double xyz[3], const double uvw[3]) const; }; } // namespace openmc From 81cc98010bbd6264570ae06dbba3484e63222075 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 15 Feb 2018 14:55:06 -0500 Subject: [PATCH 11/41] Implement a C++ HexLattice constructor --- src/lattice.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++---- src/lattice.h | 6 ++ 2 files changed, 160 insertions(+), 13 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 236e6d0bae..463619a9fc 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -43,6 +43,10 @@ Lattice::Lattice(pugi::xml_node lat_node) if (check_for_node(lat_node, "name")) { name = get_node_value(lat_node, "name"); } + + if (check_for_node(lat_node, "outer")) { + outer = stoi(get_node_value(lat_node, "outer")); + } } void @@ -61,8 +65,8 @@ RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} { // Read the number of lattice cells in each dimension. - std::string dimension_str{get_node_value(lat_node, "dimension")}; - std::vector dimension_words{split(dimension_str)}; + std::string dimension_str {get_node_value(lat_node, "dimension")}; + std::vector dimension_words {split(dimension_str)}; if (dimension_words.size() == 2) { n_cells[0] = stoi(dimension_words[0]); n_cells[1] = stoi(dimension_words[1]); @@ -78,8 +82,8 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } // Read the lattice lower-left location. - std::string ll_str{get_node_value(lat_node, "lower_left")}; - std::vector ll_words{split(ll_str)}; + std::string ll_str {get_node_value(lat_node, "lower_left")}; + std::vector ll_words {split(ll_str)}; if (ll_words.size() != dimension_words.size()) { fatal_error("Number of entries on must be the same as the " "number of entries on ."); @@ -89,8 +93,8 @@ RectLattice::RectLattice(pugi::xml_node lat_node) if (is_3d) {lower_left[2] = stod(ll_words[2]);} // Read the lattice pitches. - std::string pitch_str{get_node_value(lat_node, "pitch")}; - std::vector pitch_words{split(pitch_str)}; + std::string pitch_str {get_node_value(lat_node, "pitch")}; + std::vector pitch_words {split(pitch_str)}; if (pitch_words.size() != dimension_words.size()) { fatal_error("Number of entries on must be the same as the " "number of entries on ."); @@ -103,8 +107,8 @@ RectLattice::RectLattice(pugi::xml_node lat_node) int nx = n_cells[0]; int ny = n_cells[1]; int nz = n_cells[2]; - std::string univ_str{get_node_value(lat_node, "universes")}; - std::vector univ_words{split(univ_str)}; + std::string univ_str {get_node_value(lat_node, "universes")}; + std::vector univ_words {split(univ_str)}; if (univ_words.size() != nx*ny*nz) { std::stringstream err_msg; err_msg << "Expected " << nx*ny*nz @@ -125,11 +129,6 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } } } - - // Read the outer universe for the area outside the lattice. - if (check_for_node(lat_node, "outer")) { - outer = stoi(get_node_value(lat_node, "outer")); - } } std::pair> @@ -198,6 +197,148 @@ RectLattice::distance(const double xyz[3], const double uvw[3]) const HexLattice::HexLattice(pugi::xml_node lat_node) : Lattice {lat_node} { + // Read the number of lattice cells in each dimension. + n_rings = stoi(get_node_value(lat_node, "n_rings")); + if (check_for_node(lat_node, "n_axial")) { + n_axial = stoi(get_node_value(lat_node, "n_axial")); + is_3d = true; + } else { + n_axial = 1; + is_3d = false; + } + + // Read the lattice center. + std::string center_str {get_node_value(lat_node, "center")}; + std::vector center_words {split(center_str)}; + if (is_3d && (center_words.size() != 3)) { + fatal_error("A hexagonal lattice with must have
" + "specified by 3 numbers."); + } else if (!is_3d && center_words.size() != 2) { + fatal_error("A hexagonal lattice without must have
" + "specified by 2 numbers."); + } + center[0] = stod(center_words[0]); + center[1] = stod(center_words[1]); + if (is_3d) {center[2] = stod(center_words[2]);} + + // Read the lattice pitches. + std::string pitch_str {get_node_value(lat_node, "pitch")}; + std::vector pitch_words {split(pitch_str)}; + if (is_3d && (pitch_words.size() != 2)) { + fatal_error("A hexagonal lattice with must have " + "specified by 2 numbers."); + } else if (!is_3d && (pitch_words.size() != 1)) { + fatal_error("A hexagonal lattice without must have
" + "specified by 1 number."); + } + pitch[0] = stod(pitch_words[0]); + if (is_3d) {pitch[1] = stod(pitch_words[1]);} + + // Read the universes and make sure the correct number was specified. + //int n_univ = (2*n_rings - 1) * (2*n_rings - 1) * n_axial; + int n_univ = (3*n_rings*n_rings - 3*n_rings + 1) * n_axial; + std::string univ_str {get_node_value(lat_node, "universes")}; + std::vector univ_words {split(univ_str)}; + if (univ_words.size() != n_univ) { + std::stringstream err_msg; + err_msg << "Expected " << n_univ + << " universes for a hexagonal lattice with " << n_rings + << " rings and " << n_axial << " axial levels" << " but " + << univ_words.size() << " were specified."; + fatal_error(err_msg); + } + + // Parse the universes. + // Universes in hexagonal lattices are stored in a manner that represents + // a skewed coordinate system: (x, alpha) rather than (x, y). There is + // no obvious, direct relationship between the order of universes in the + // input and the order that they will be stored in the skewed array so + // the following code walks a set of index values across the skewed array + // in a manner that matches the input order. Note that i_x = 0, i_a = 0 + // corresponds to the center of the hexagonal lattice. + + universes.resize((2*n_rings-1) * (2*n_rings-1) * n_axial, -1); + int input_index = 0; + for (int m = 0; m < n_axial; m++) { + // Initialize lattice indecies. + int i_x = 1; + int i_a = n_rings - 1; + + // Map upper triangular region of hexagonal lattice which is found in the + // first n_rings-1 rows of the input. + for (int k = 0; k < n_rings-1; k++) { + // Walk the index to lower-left neighbor of last row start. + i_x -= 1; + + // Iterate over the input columns. + for (int j = 0; j < k+1; j++) { + int indx = (2*n_rings-1)*(2*n_rings-1) * m + + (2*n_rings-1) * (i_a+n_rings-1) + + (i_x+n_rings-1); + universes[indx] = stoi(univ_words[input_index]); + input_index++; + // Walk the index to the right neighbor (which is not adjacent). + i_x += 2; + i_a -= 1; + } + + // Return the lattice index to the start of the current row. + i_x -= 2 * (k+1); + i_a += (k+1); + } + + // Map the middle square region of the hexagonal lattice which is found in + // the next 2*n_rings-1 rows of the input. + for (int k = 0; k < 2*n_rings-1; k++) { + if ((k % 2) == 0) { + // Walk the index to the lower-left neighbor of the last row start. + i_x -= 1; + } else { + // Walk the index to the lower-right neighbor of the last row start. + i_x += 1; + i_a -= 1; + } + + // Iterate over the input columns. + for (int j = 0; j < n_rings - (k % 2); j++) { + int indx = (2*n_rings-1)*(2*n_rings-1) * m + + (2*n_rings-1) * (i_a+n_rings-1) + + (i_x+n_rings-1); + universes[indx] = stoi(univ_words[input_index]); + input_index++; + // Walk the index to the right neighbor (which is not adjacent). + i_x += 2; + i_a -= 1; + } + + // Return the lattice index to the start of the current row. + i_x -= 2*(n_rings - (k % 2)); + i_a += n_rings - (k % 2); + } + + // Map the lower triangular region of the hexagonal lattice. + for (int k = 0; k < n_rings-1; k++) { + // Walk the index to the lower-right neighbor of the last row start. + i_x += 1; + i_a -= 1; + + // Iterate over the input columns. + for (int j = 0; j < n_rings-k-1; j++) { + int indx = (2*n_rings-1)*(2*n_rings-1) * m + + (2*n_rings-1) * (i_a+n_rings-1) + + (i_x+n_rings-1); + universes[indx] = stoi(univ_words[input_index]); + input_index++; + // Walk the index to the right neighbor (which is not adjacent). + i_x += 2; + i_a -= 1; + } + + // Return lattice index to start of current row. + i_x -= 2*(n_rings - k - 1); + i_a += n_rings - k - 1; + } + } } std::pair> diff --git a/src/lattice.h b/src/lattice.h index 1825f396b2..18dbd53a40 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -104,6 +104,12 @@ public: std::pair> distance(const double xyz[3], const double uvw[3]) const; + +protected: + int n_rings; //! Number of radial tile positions + int n_axial; //! Number of axial tile positions + std::array center; //! Global center of lattice + std::array pitch; //! Lattice tile width and height }; } // namespace openmc From ec14970cafb936ed3fac4df2f08a895d22f9d2bf Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 16 Feb 2018 15:22:08 -0500 Subject: [PATCH 12/41] Add C++ HexLattice distance_to_boundary --- src/geometry.F90 | 134 +++------------------------------------- src/geometry_header.F90 | 8 ++- src/lattice.cpp | 127 +++++++++++++++++++++++++++++++++++-- src/lattice.h | 10 ++- 4 files changed, 145 insertions(+), 134 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index a6965cffb9..fff18d6c85 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -372,17 +372,9 @@ contains integer :: i_xyz(3) ! lattice indices integer :: level_surf_cross ! surface crossed on current level integer :: level_lat_trans(3) ! lattice translation on current level - real(8) :: x,y,z ! particle coordinates real(8) :: xyz_t(3) ! local particle coordinates - real(8) :: beta, gama ! skewed particle coordiantes - real(8) :: u,v,w ! particle directions - real(8) :: beta_dir ! skewed particle direction - real(8) :: gama_dir ! skewed particle direction - real(8) :: edge ! distance to oncoming edge - real(8) :: d ! evaluated distance real(8) :: d_lat ! distance to lattice boundary real(8) :: d_surf ! distance to surface - real(8) :: x0,y0,z0 ! coefficients for surface real(8) :: xyz_cross(3) ! coordinates at projected surface crossing real(8) :: surf_uvw(3) ! surface normal direction type(Cell), pointer :: c @@ -402,11 +394,6 @@ contains ! get pointer to cell on this level c => cells(p % coord(j) % cell) - ! copy directional cosines - u = p % coord(j) % uvw(1) - v = p % coord(j) % uvw(2) - w = p % coord(j) % uvw(3) - ! ======================================================================= ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL @@ -419,123 +406,22 @@ contains LAT_COORD: if (p % coord(j) % lattice /= NONE) then lat => lattices(p % coord(j) % lattice) % obj + i_xyz(1) = p % coord(j) % lattice_x + i_xyz(2) = p % coord(j) % lattice_y + i_xyz(3) = p % coord(j) % lattice_z + LAT_TYPE: select type(lat) type is (RectLattice) call lat % distance(p % coord(j) % xyz, p % coord(j) % uvw, & - d_lat, level_lat_trans) + i_xyz, d_lat, level_lat_trans) type is (HexLattice) LAT_TYPE - ! Copy local coordinates. - z = p % coord(j) % xyz(3) - i_xyz(1) = p % coord(j) % lattice_x - i_xyz(2) = p % coord(j) % lattice_y - i_xyz(3) = p % coord(j) % lattice_z - - ! Compute velocities along the hexagonal axes. - beta_dir = u*sqrt(THREE)/TWO + v/TWO - gama_dir = u*sqrt(THREE)/TWO - v/TWO - - ! Note that hexagonal lattice distance calculations are performed - ! using the particle's coordinates relative to the neighbor lattice - ! cells, not relative to the particle's current cell. This is done - ! because there is significant disagreement between neighboring cells - ! on where the lattice boundary is due to the worse finite precision - ! of hex lattices. - - ! Upper right and lower left sides. - edge = -sign(lat % pitch(1)/TWO, beta_dir) ! Oncoming edge - if (beta_dir > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, 0, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 0, 0]) - end if - beta = xyz_t(1)*sqrt(THREE)/TWO + xyz_t(2)/TWO - if (abs(beta - edge) < FP_PRECISION) then - d = INFINITY - else if (beta_dir == ZERO) then - d = INFINITY - else - d = (edge - beta)/beta_dir - end if - - d_lat = d - if (beta_dir > 0) then - level_lat_trans(:) = [1, 0, 0] - else - level_lat_trans(:) = [-1, 0, 0] - end if - - ! Lower right and upper left sides. - edge = -sign(lat % pitch(1)/TWO, gama_dir) ! Oncoming edge - if (gama_dir > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[1, -1, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[-1, 1, 0]) - end if - gama = xyz_t(1)*sqrt(THREE)/TWO - xyz_t(2)/TWO - if (abs(gama - edge) < FP_PRECISION) then - d = INFINITY - else if (gama_dir == ZERO) then - d = INFINITY - else - d = (edge - gama)/gama_dir - end if - - if (d < d_lat) then - d_lat = d - if (gama_dir > 0) then - level_lat_trans(:) = [1, -1, 0] - else - level_lat_trans(:) = [-1, 1, 0] - end if - end if - - ! Upper and lower sides. - edge = -sign(lat % pitch(1)/TWO, v) ! Oncoming edge - if (v > ZERO) then - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, 1, 0]) - else - xyz_t = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz+[0, -1, 0]) - end if - if (abs(xyz_t(2) - edge) < FP_PRECISION) then - d = INFINITY - else if (v == ZERO) then - d = INFINITY - else - d = (edge - xyz_t(2))/v - end if - - if (d < d_lat) then - d_lat = d - if (v > 0) then - level_lat_trans(:) = [0, 1, 0] - else - level_lat_trans(:) = [0, -1, 0] - end if - end if - - ! Top and bottom sides. - if (lat % is_3d) then - z0 = sign(lat % pitch(2) * HALF, w) - - if (abs(z - z0) < FP_PRECISION) then - d = INFINITY - elseif (w == ZERO) then - d = INFINITY - else - d = (z0 - z)/w - end if - - if (d < d_lat) then - d_lat = d - if (w > 0) then - level_lat_trans(:) = [0, 0, 1] - else - level_lat_trans(:) = [0, 0, -1] - end if - end if - end if + xyz_t(1) = p % coord(j-1) % xyz(1) + xyz_t(2) = p % coord(j-1) % xyz(2) + xyz_t(3) = p % coord(j) % xyz(3) + call lat % distance(xyz_t, p % coord(j) % uvw, & + i_xyz, d_lat, level_lat_trans) end select LAT_TYPE if (d_lat < ZERO) then diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 101bf8f9a1..0cc08f5e6a 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -95,13 +95,14 @@ module geometry_header integer(C_INT32_T) :: id end function lattice_id_c - subroutine lattice_distance_c(lat_ptr, xyz, uvw, d, lattice_trans) & + subroutine lattice_distance_c(lat_ptr, xyz, uvw, i_xyz, d, lattice_trans) & bind(C, name='lattice_distance') use ISO_C_BINDING implicit none type(C_PTR), intent(in), value :: lat_ptr real(C_DOUBLE), intent(in) :: xyz(3) real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT), intent(in) :: i_xyz(3) real(C_DOUBLE), intent(out) :: d integer(C_INT), intent(out) :: lattice_trans(3) end subroutine lattice_distance_c @@ -293,13 +294,14 @@ contains id = lattice_id_c(this % ptr) end function lattice_id - subroutine lattice_distance(this, xyz, uvw, d, lattice_trans) + subroutine lattice_distance(this, xyz, uvw, i_xyz, d, lattice_trans) class(Lattice), intent(in) :: this real(C_DOUBLE), intent(in) :: xyz(3) real(C_DOUBLE), intent(in) :: uvw(3) + integer(C_INT), intent(in) :: i_xyz(3) real(C_DOUBLE), intent(out) :: d integer(C_INT), intent(out) :: lattice_trans(3) - call lattice_distance_c(this % ptr, xyz, uvw, d, lattice_trans) + call lattice_distance_c(this % ptr, xyz, uvw, i_xyz, d, lattice_trans) end subroutine lattice_distance subroutine lattice_to_hdf5(this, group) diff --git a/src/lattice.cpp b/src/lattice.cpp index 463619a9fc..4730990349 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -132,7 +132,8 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } std::pair> -RectLattice::distance(const double xyz[3], const double uvw[3]) const +RectLattice::distance(const double xyz[3], const double uvw[3], + const int i_xyz[3]) const { // Get short aliases to the coordinates. double x {xyz[0]}; @@ -342,8 +343,126 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } std::pair> -HexLattice::distance(const double xyz[3], const double uvw[3]) const +HexLattice::distance(const double xyz[3], const double uvw[3], + const int i_xyz[3]) const { + // Compute the direction on the hexagonal basis. + double beta_dir = uvw[0] * std::sqrt(3.0) / 2.0 + uvw[1] / 2.0; + double gamma_dir = uvw[0] * std::sqrt(3.0) / 2.0 - uvw[1] / 2.0; + + // Note that hexagonal lattice distance calculations are performed + // using the particle's coordinates relative to the neighbor lattice + // cells, not relative to the particle's current cell. This is done + // because there is significant disagreement between neighboring cells + // on where the lattice boundary is due to finite precision issues. + + // Upper-right and lower-left sides. + double d {INFTY}; + std::array lattice_trans; + double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge + std::array xyz_t; + if (beta_dir > 0) { + const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1], i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } else { + const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1], i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } + double beta = xyz_t[0] * std::sqrt(3.0) / 2.0 + xyz_t[1] / 2.0; + if ((std::abs(beta - edge) > FP_PRECISION) && beta_dir != 0) { + d = (edge - beta) / beta_dir; + if (beta_dir > 0) { + lattice_trans = {1, 0, 0}; + } else { + lattice_trans = {-1, 0, 0}; + } + } + + // Lower-right and upper-left sides. + edge = -copysign(0.5*pitch[0], gamma_dir); + if (gamma_dir > 0) { + const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } else { + const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } + double gamma = xyz_t[0] * std::sqrt(3.0) / 2.0 - xyz_t[1] / 2.0; + if ((std::abs(gamma - edge) > FP_PRECISION) && gamma_dir != 0) { + double this_d = (edge - gamma) / gamma_dir; + if (this_d < d) { + if (gamma_dir > 0) { + lattice_trans = {1, -1, 0}; + } else { + lattice_trans = {-1, 1, 0}; + } + d = this_d; + } + } + + // Upper and lower sides. + edge = -copysign(0.5*pitch[0], uvw[1]); + if (uvw[1] > 0) { + const int i_xyz_t[3] {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } else { + const int i_xyz_t[3] {i_xyz[0], i_xyz[1]-1, i_xyz[2]}; + xyz_t = get_local_xyz(xyz, i_xyz_t); + } + if ((std::abs(xyz_t[1] - edge) > FP_PRECISION) && uvw[1] != 0) { + double this_d = (edge - xyz_t[1]) / uvw[1]; + if (this_d < d) { + if (uvw[1] > 0) { + lattice_trans = {0, 1, 0}; + } else { + lattice_trans = {0, -1, 0}; + } + d = this_d; + } + } + + // Top and bottom sides + if (is_3d) { + double z {xyz[2]}; + double w {uvw[2]}; + double z0 {copysign(0.5 * pitch[1], w)}; + if ((std::abs(z - z0) > FP_PRECISION) && w != 0) { + double this_d = (z0 - z) / w; + if (this_d < d) { + d = this_d; + if (w > 0) { + lattice_trans = {0, 0, 1}; + } else { + lattice_trans = {0, 0, -1}; + } + d = this_d; + } + } + } + + return {d, lattice_trans}; +} + +std::array +HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const +{ + std::array local_xyz; + + // x_l = x_g - (center + pitch_x*cos(30)*index_x) + local_xyz[0] = global_xyz[0] - (center[0] + + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings) * pitch[0]); + // y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y) + local_xyz[1] = global_xyz[1] - (center[1] + + (i_xyz[1] - n_rings) * pitch[0] + + (i_xyz[0] - n_rings) * pitch[0] / 2.0); + if (is_3d) { + local_xyz[2] = global_xyz[2] - center[2] + + (0.5 * n_axial - i_xyz[2] + 0.5) * pitch[1]; + } else { + local_xyz[2] = global_xyz[2]; + } + + return local_xyz; } //============================================================================== @@ -382,9 +501,9 @@ extern "C" { int32_t lattice_id(Lattice *lat) {return lat->id;} void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3], - double *d, int lattice_trans[3]) + const int i_xyz[3], double *d, int lattice_trans[3]) { - std::pair> ld {lat->distance(xyz, uvw)}; + std::pair> ld {lat->distance(xyz, uvw, i_xyz)}; *d = ld.first; lattice_trans[0] = ld.second[0]; lattice_trans[1] = ld.second[1]; diff --git a/src/lattice.h b/src/lattice.h index 18dbd53a40..2a4aa8865f 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -61,7 +61,8 @@ public: //virtual bool are_valid_indices(const int i_xyz[3]) const = 0; virtual std::pair> - distance(const double xyz[3], const double uvw[3]) const = 0; + distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const + = 0; //virtual void get_indices(const double global_xyz[3], int i_xyz[3]) const = 0; @@ -87,7 +88,7 @@ public: virtual ~RectLattice() {} std::pair> - distance(const double xyz[3], const double uvw[3]) const; + distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; protected: std::array n_cells; //! Number of cells along each axis @@ -103,7 +104,10 @@ public: virtual ~HexLattice() {} std::pair> - distance(const double xyz[3], const double uvw[3]) const; + distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; + + std::array + get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; protected: int n_rings; //! Number of radial tile positions From efc77b74fe1ed7d70179581bdf7f9d4c3cbd0409 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 16 Feb 2018 17:49:42 -0500 Subject: [PATCH 13/41] Move lattice get_indices and are_valid to C++ --- src/geometry_header.F90 | 177 ++++++++-------------------------------- src/lattice.cpp | 121 ++++++++++++++++++++++++++- src/lattice.h | 27 +++++- 3 files changed, 178 insertions(+), 147 deletions(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 0cc08f5e6a..c58ab1d6cd 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -95,6 +95,15 @@ module geometry_header integer(C_INT32_T) :: id end function lattice_id_c + function lattice_are_valid_indices_c(lat_ptr, i_xyz) & + bind(C, name='lattice_are_valid_indices') result (is_valid) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + integer(C_INT), intent(in) :: i_xyz(3) + logical(C_BOOL) :: is_valid + end function lattice_are_valid_indices_c + subroutine lattice_distance_c(lat_ptr, xyz, uvw, i_xyz, d, lattice_trans) & bind(C, name='lattice_distance') use ISO_C_BINDING @@ -107,6 +116,15 @@ module geometry_header integer(C_INT), intent(out) :: lattice_trans(3) end subroutine lattice_distance_c + subroutine lattice_get_indices_c(lat_ptr, xyz, i_xyz) & + bind(C, name='lattice_get_indices') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + real(C_DOUBLE), intent(in) :: xyz(3) + integer(C_INT), intent(out) :: i_xyz(3) + end subroutine lattice_get_indices_c + subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5') use ISO_C_BINDING use hdf5 @@ -146,37 +164,16 @@ module geometry_header contains procedure :: id => lattice_id + procedure :: are_valid_indices => lattice_are_valid_indices procedure :: distance => lattice_distance + procedure :: get_indices => lattice_get_indices procedure :: to_hdf5 => lattice_to_hdf5 - procedure(lattice_are_valid_indices_), deferred :: are_valid_indices - procedure(lattice_get_indices_), deferred :: get_indices procedure(lattice_get_local_xyz_), deferred :: get_local_xyz end type Lattice abstract interface -!=============================================================================== -! ARE_VALID_INDICES returns .true. if the given lattice indices fit within the -! bounds of the lattice. Returns false otherwise. - - function lattice_are_valid_indices_(this, i_xyz) result(is_valid) - import Lattice - class(Lattice), intent(in) :: this - integer, intent(in) :: i_xyz(3) - logical :: is_valid - end function lattice_are_valid_indices_ - -!=============================================================================== -! GET_INDICES returns the indices in a lattice for the given global xyz. - - function lattice_get_indices_(this, global_xyz) result(i_xyz) - import Lattice - class(Lattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer :: i_xyz(3) - end function lattice_get_indices_ - !=============================================================================== ! GET_LOCAL_XYZ returns the translated local version of the given global xyz. @@ -199,8 +196,6 @@ module geometry_header contains - procedure :: are_valid_indices => valid_inds_rect - procedure :: get_indices => get_inds_rect procedure :: get_local_xyz => get_local_rect end type RectLattice @@ -215,8 +210,6 @@ module geometry_header contains - procedure :: are_valid_indices => valid_inds_hex - procedure :: get_indices => get_inds_hex procedure :: get_local_xyz => get_local_hex end type HexLattice @@ -294,6 +287,13 @@ contains id = lattice_id_c(this % ptr) end function lattice_id + function lattice_are_valid_indices(this, i_xyz) result (is_valid) + class(Lattice), intent(in) :: this + integer(C_INT), intent(in) :: i_xyz(3) + logical(C_BOOL) :: is_valid + is_valid = lattice_are_valid_indices_c(this % ptr, i_xyz) + end function lattice_are_valid_indices + subroutine lattice_distance(this, xyz, uvw, i_xyz, d, lattice_trans) class(Lattice), intent(in) :: this real(C_DOUBLE), intent(in) :: xyz(3) @@ -304,128 +304,19 @@ contains call lattice_distance_c(this % ptr, xyz, uvw, i_xyz, d, lattice_trans) end subroutine lattice_distance + function lattice_get_indices(this, xyz) result(i_xyz) + class(Lattice), intent(in) :: this + real(C_DOUBLE), intent(in) :: xyz(3) + integer(C_INT) :: i_xyz(3) + call lattice_get_indices_c(this % ptr, xyz, i_xyz) + end function lattice_get_indices + subroutine lattice_to_hdf5(this, group) class(Lattice), intent(in) :: this integer(HID_T), intent(in) :: group call lattice_to_hdf5_c(this % ptr, group) end subroutine lattice_to_hdf5 -!=============================================================================== - - function valid_inds_rect(this, i_xyz) result(is_valid) - class(RectLattice), intent(in) :: this - integer, intent(in) :: i_xyz(3) - logical :: is_valid - - is_valid = all(i_xyz > 0 .and. i_xyz <= this % n_cells) - end function valid_inds_rect - -!=============================================================================== - - function valid_inds_hex(this, i_xyz) result(is_valid) - class(HexLattice), intent(in) :: this - integer, intent(in) :: i_xyz(3) - logical :: is_valid - - is_valid = (all(i_xyz > 0) .and. & - &i_xyz(1) < 2*this % n_rings .and. & - &i_xyz(2) < 2*this % n_rings .and. & - &i_xyz(1) + i_xyz(2) > this % n_rings .and. & - &i_xyz(1) + i_xyz(2) < 3*this % n_rings .and. & - &i_xyz(3) <= this % n_axial) - end function valid_inds_hex - -!=============================================================================== - - function get_inds_rect(this, global_xyz) result(i_xyz) - class(RectLattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer :: i_xyz(3) - - real(8) :: xyz(3) ! global_xyz alias - - xyz = global_xyz - - i_xyz(1) = ceiling((xyz(1) - this % lower_left(1))/this % pitch(1)) - i_xyz(2) = ceiling((xyz(2) - this % lower_left(2))/this % pitch(2)) - if (this % is_3d) then - i_xyz(3) = ceiling((xyz(3) - this % lower_left(3))/this % pitch(3)) - else - i_xyz(3) = 1 - end if - end function get_inds_rect - -!=============================================================================== - - function get_inds_hex(this, global_xyz) result(i_xyz) - class(HexLattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer :: i_xyz(3) - - real(8) :: xyz(3) ! global xyz relative to the center - real(8) :: alpha ! Skewed coord axis - real(8) :: xyz_t(3) ! Local xyz - real(8) :: d, d_min ! Squared distance from cell centers - integer :: i, j, k ! Iterators - integer :: k_min ! Minimum distance index - - xyz(1) = global_xyz(1) - this % center(1) - xyz(2) = global_xyz(2) - this % center(2) - - ! Index z direction. - if (this % is_3d) then - xyz(3) = global_xyz(3) - this % center(3) - i_xyz(3) = ceiling(xyz(3)/this % pitch(2) + HALF*this % n_axial) - else - xyz(3) = global_xyz(3) - i_xyz(3) = 1 - end if - - ! Convert coordinates into skewed bases. The (x, alpha) basis is used to - ! find the index of the global coordinates to within 4 cells. - alpha = xyz(2) - xyz(1) / sqrt(THREE) - i_xyz(1) = floor(xyz(1) / (sqrt(THREE) / TWO * this % pitch(1))) - i_xyz(2) = floor(alpha / this % pitch(1)) - - ! Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but - ! the array is offset so that the indices never go below 1). - i_xyz(1) = i_xyz(1) + this % n_rings - i_xyz(2) = i_xyz(2) + this % n_rings - - ! Calculate the (squared) distance between the particle and the centers of - ! the four possible cells. Regular hexagonal tiles form a centroidal - ! Voronoi tessellation so the global xyz should be in the hexagonal cell - ! that it is closest to the center of. This method is used over a - ! method that uses the remainders of the floor divisions above because it - ! provides better finite precision performance. Squared distances are - ! used becasue they are more computationally efficient than normal - ! distances. - k = 1 - d_min = INFINITY - do i = 0, 1 - do j = 0, 1 - xyz_t = this % get_local_xyz(global_xyz, i_xyz + [j, i, 0]) - d = xyz_t(1)**2 + xyz_t(2)**2 - if (d < d_min) then - d_min = d - k_min = k - end if - k = k + 1 - end do - end do - - ! Select the minimum squared distance which corresponds to the cell the - ! coordinates are in. - if (k_min == 2) then - i_xyz(1) = i_xyz(1) + 1 - else if (k_min == 3) then - i_xyz(2) = i_xyz(2) + 1 - else if (k_min == 4) then - i_xyz(1) = i_xyz(1) + 1 - i_xyz(2) = i_xyz(2) + 1 - end if - end function get_inds_hex - !=============================================================================== function get_local_rect(this, global_xyz, i_xyz) result(local_xyz) diff --git a/src/lattice.cpp b/src/lattice.cpp index 4730990349..82f15401de 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -131,6 +131,18 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } } +//============================================================================== + +bool +RectLattice::are_valid_indices(const int i_xyz[3]) const +{ + return ( (i_xyz[0] > 0) && (i_xyz[0] <= n_cells[0]) + && (i_xyz[1] > 0) && (i_xyz[1] <= n_cells[1]) + && (i_xyz[2] > 0) && (i_xyz[2] <= n_cells[2])); +} + +//============================================================================== + std::pair> RectLattice::distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const @@ -191,6 +203,22 @@ RectLattice::distance(const double xyz[3], const double uvw[3], return {d, lattice_trans}; } +//============================================================================== + +std::array +RectLattice::get_indices(const double xyz[3]) const +{ + int ix {static_cast(std::ceil((xyz[0] - lower_left[0]) / pitch[0]))}; + int iy {static_cast(std::ceil((xyz[1] - lower_left[1]) / pitch[1]))}; + int iz; + if (is_3d) { + iz = static_cast(std::ceil((xyz[2] - lower_left[2]) / pitch[2])); + } else { + iz = 1; + } + return {ix, iy, iz}; +} + //============================================================================== // HexLattice implementation //============================================================================== @@ -229,7 +257,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node) fatal_error("A hexagonal lattice with must have " "specified by 2 numbers."); } else if (!is_3d && (pitch_words.size() != 1)) { - fatal_error("A hexagonal lattice without must have
" + fatal_error("A hexagonal lattice without must have " "specified by 1 number."); } pitch[0] = stod(pitch_words[0]); @@ -342,6 +370,18 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } } +//============================================================================== + +bool +HexLattice::are_valid_indices(const int i_xyz[3]) const +{ + return ((i_xyz[0] > 0) && (i_xyz[1] > 0) && (i_xyz[2] > 0) + && (i_xyz[0] < 2*n_rings) && (i_xyz[1] < 2*n_rings) + && (i_xyz[0] + i_xyz[1] > n_rings) + && (i_xyz[0] + i_xyz[1] < 3*n_rings) + && (i_xyz[2] <= n_axial)); +} + std::pair> HexLattice::distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const @@ -443,6 +483,74 @@ HexLattice::distance(const double xyz[3], const double uvw[3], return {d, lattice_trans}; } +//============================================================================== + +std::array +HexLattice::get_indices(const double xyz[3]) const +{ + // Offset the xyz by the lattice center. + double xyz_o[3] {xyz[0] - center[0], xyz[1] - center[1], xyz[2]}; + if (is_3d) {xyz_o[2] -= center[2];} + + // Index the z direction. + std::array out; + if (is_3d) { + out[2] = static_cast(std::ceil(xyz_o[2] / pitch[1] + 0.5 * n_axial)); + } else { + out[2] = 1; + } + + // Convert coordinates into skewed bases. The (x, alpha) basis is used to + // find the index of the global coordinates to within 4 cells. + double alpha = xyz_o[1] - xyz_o[0] / std::sqrt(3.0); + out[0] = static_cast(std::floor(xyz_o[0] + / (0.5*std::sqrt(3.0) * pitch[0]))); + out[1] = static_cast(std::floor(alpha / pitch[0])); + + // Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but + // the array is offset so that the indices never go below 1). + out[0] += n_rings; + out[1] += n_rings; + + // Calculate the (squared) distance between the particle and the centers of + // the four possible cells. Regular hexagonal tiles form a Voronoi + // tessellation so the xyz should be in the hexagonal cell that it is closest + // to the center of. This method is used over a method that uses the + // remainders of the floor divisions above because it provides better finite + // precision performance. Squared distances are used becasue they are more + // computationally efficient than normal distances. + int k {1}; + int k_min {1}; + double d_min {INFTY}; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + int i_xyz[3] {out[0] + j, out[1] + i, 0}; + std::array xyz_t = get_local_xyz(xyz, i_xyz); + double d = xyz_t[0]*xyz_t[0] + xyz_t[1]*xyz_t[1]; + if (d < d_min) { + d_min = d; + k_min = k; + } + k++; + } + } + + // Select the minimum squared distance which corresponds to the cell the + // coordinates are in. + if (k_min == 2) { + out[0] += 1; + } else if (k_min == 3) { + out[1] += 1; + } else if (k_min == 4) { + out[0] += 1; + out[1] += 1; + } + + return out; +} + +//============================================================================== + std::array HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const { @@ -500,6 +608,9 @@ extern "C" { int32_t lattice_id(Lattice *lat) {return lat->id;} + bool lattice_are_valid_indices(Lattice *lat, const int i_xyz[3]) + {return lat->are_valid_indices(i_xyz);} + void lattice_distance(Lattice *lat, const double xyz[3], const double uvw[3], const int i_xyz[3], double *d, int lattice_trans[3]) { @@ -510,6 +621,14 @@ extern "C" { lattice_trans[2] = ld.second[2]; } + void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3]) + { + std::array inds {lat->get_indices(xyz)}; + i_xyz[0] = inds[0]; + i_xyz[1] = inds[1]; + i_xyz[2] = inds[2]; + } + void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} } diff --git a/src/lattice.h b/src/lattice.h index 2a4aa8865f..81b0c2bdf3 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -58,13 +58,26 @@ public: virtual ~Lattice() {} - //virtual bool are_valid_indices(const int i_xyz[3]) const = 0; + //! Check lattice indices. + //! @param i_xyz[3] The indices for a lattice tile. + //! @return true if the given indices fit within the lattice bounds. False + //! otherwise. + virtual bool are_valid_indices(const int i_xyz[3]) const = 0; + //! Find the next lattice surface crossing + //! @param xyz[3] A 3D Cartesian coordinate. + //! @param uvw[3] A 3D Cartesian direction. + //! @param i_xyz[3] The indices for a lattice tile. + //! @return The distance to the next crossing and an array indicating how the + //! lattice indices would change after crossing that boundary. virtual std::pair> distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const - = 0; + = 0; - //virtual void get_indices(const double global_xyz[3], int i_xyz[3]) const = 0; + //! Find the lattice tile indices for a given point. + //! @param xyz[3] A 3D Cartesian coordinate. + //! @return An array containing the indices of a lattice tile. + virtual std::array get_indices(const double xyz[3]) const = 0; //virtual void get_local_xyz(const double global_xyz[3], const int i_xyz[3], // double local_xyz[3]) const = 0; @@ -87,9 +100,13 @@ public: virtual ~RectLattice() {} + bool are_valid_indices(const int i_xyz[3]) const; + std::pair> distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; + std::array get_indices(const double xyz[3]) const; + protected: std::array n_cells; //! Number of cells along each axis std::array lower_left; //! Global lower-left corner of the lattice @@ -103,9 +120,13 @@ public: virtual ~HexLattice() {} + bool are_valid_indices(const int i_xyz[3]) const; + std::pair> distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const; + std::array get_indices(const double xyz[3]) const; + std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; From ad4a5da040ef69325d990bbd4320fa0310a4f08c Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 16 Feb 2018 18:25:52 -0500 Subject: [PATCH 14/41] Move lattice get_local_xyz to C++ --- src/geometry_header.F90 | 95 +++++++++-------------------------------- src/lattice.cpp | 27 ++++++++++++ src/lattice.h | 11 ++++- 3 files changed, 56 insertions(+), 77 deletions(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index c58ab1d6cd..f5d79d0a6e 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -125,6 +125,16 @@ module geometry_header integer(C_INT), intent(out) :: i_xyz(3) end subroutine lattice_get_indices_c + subroutine lattice_get_local_xyz_c(lat_ptr, global_xyz, i_xyz, local_xyz) & + bind(C, name='lattice_get_local_xyz') + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + real(C_DOUBLE), intent(in) :: global_xyz(3) + integer(C_INT), intent(in) :: i_xyz(3) + real(C_DOUBLE), intent(out) :: local_xyz(3) + end subroutine lattice_get_local_xyz_c + subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5') use ISO_C_BINDING use hdf5 @@ -167,25 +177,10 @@ module geometry_header procedure :: are_valid_indices => lattice_are_valid_indices procedure :: distance => lattice_distance procedure :: get_indices => lattice_get_indices + procedure :: get_local_xyz => lattice_get_local_xyz procedure :: to_hdf5 => lattice_to_hdf5 - - procedure(lattice_get_local_xyz_), deferred :: get_local_xyz end type Lattice - abstract interface - -!=============================================================================== -! GET_LOCAL_XYZ returns the translated local version of the given global xyz. - - function lattice_get_local_xyz_(this, global_xyz, i_xyz) result(local_xyz) - import Lattice - class(Lattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer, intent(in) :: i_xyz(3) - real(8) :: local_xyz(3) - end function lattice_get_local_xyz_ - end interface - !=============================================================================== ! RECTLATTICE extends LATTICE for rectilinear arrays. !=============================================================================== @@ -193,10 +188,6 @@ module geometry_header type, extends(Lattice) :: RectLattice integer :: n_cells(3) ! Number of cells along each axis real(8), allocatable :: lower_left(:) ! Global lower-left corner of lat - - contains - - procedure :: get_local_xyz => get_local_rect end type RectLattice !=============================================================================== @@ -207,10 +198,6 @@ module geometry_header integer :: n_rings ! Number of radial ring cell positoins integer :: n_axial ! Number of axial cell positions real(8), allocatable :: center(:) ! Global center of lattice - - contains - - procedure :: get_local_xyz => get_local_hex end type HexLattice !=============================================================================== @@ -311,63 +298,21 @@ contains call lattice_get_indices_c(this % ptr, xyz, i_xyz) end function lattice_get_indices + function lattice_get_local_xyz(this, global_xyz, i_xyz) & + result(local_xyz) + class(Lattice), intent(in) :: this + real(C_DOUBLE), intent(in) :: global_xyz(3) + integer(C_INT), intent(in) :: i_xyz(3) + real(C_DOUBLE) :: local_xyz(3) + call lattice_get_local_xyz_c(this % ptr, global_xyz, i_xyz, local_xyz) + end function lattice_get_local_xyz + subroutine lattice_to_hdf5(this, group) class(Lattice), intent(in) :: this integer(HID_T), intent(in) :: group call lattice_to_hdf5_c(this % ptr, group) end subroutine lattice_to_hdf5 -!=============================================================================== - - function get_local_rect(this, global_xyz, i_xyz) result(local_xyz) - class(RectLattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer, intent(in) :: i_xyz(3) - real(8) :: local_xyz(3) - - real(8) :: xyz(3) ! global_xyz alias - - xyz = global_xyz - - local_xyz(1) = xyz(1) - (this % lower_left(1) + & - (i_xyz(1) - HALF)*this % pitch(1)) - local_xyz(2) = xyz(2) - (this % lower_left(2) + & - (i_xyz(2) - HALF)*this % pitch(2)) - if (this % is_3d) then - local_xyz(3) = xyz(3) - (this % lower_left(3) + & - (i_xyz(3) - HALF)*this % pitch(3)) - else - local_xyz(3) = xyz(3) - end if - end function get_local_rect - -!=============================================================================== - - function get_local_hex(this, global_xyz, i_xyz) result(local_xyz) - class(HexLattice), intent(in) :: this - real(8), intent(in) :: global_xyz(3) - integer, intent(in) :: i_xyz(3) - real(8) :: local_xyz(3) - - real(8) :: xyz(3) ! global_xyz alias - - xyz = global_xyz - - ! x_l = x_g - (center + pitch_x*cos(30)*index_x) - local_xyz(1) = xyz(1) - (this % center(1) + & - sqrt(THREE) / TWO * (i_xyz(1) - this % n_rings) * this % pitch(1)) - ! y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y) - local_xyz(2) = xyz(2) - (this % center(2) + & - (i_xyz(2) - this % n_rings) * this % pitch(1) + & - (i_xyz(1) - this % n_rings) * this % pitch(1) / TWO) - if (this % is_3d) then - local_xyz(3) = xyz(3) - this % center(3) & - + (HALF*this % n_axial - i_xyz(3) + HALF) * this % pitch(2) - else - local_xyz(3) = xyz(3) - end if - end function get_local_hex - !=============================================================================== function cell_id(this) result(id) diff --git a/src/lattice.cpp b/src/lattice.cpp index 82f15401de..fd89cbf1e7 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -219,6 +219,22 @@ RectLattice::get_indices(const double xyz[3]) const return {ix, iy, iz}; } +//============================================================================== + +std::array +RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const +{ + std::array local_xyz; + local_xyz[0] = global_xyz[0] - (lower_left[0] + (i_xyz[0] - 0.5)*pitch[0]); + local_xyz[1] = global_xyz[1] - (lower_left[1] + (i_xyz[1] - 0.5)*pitch[1]); + if (is_3d) { + local_xyz[2] = global_xyz[2] - (lower_left[2] + (i_xyz[2] - 0.5)*pitch[2]); + } else { + local_xyz[2] = global_xyz[2]; + } + return local_xyz; +} + //============================================================================== // HexLattice implementation //============================================================================== @@ -573,6 +589,8 @@ HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const return local_xyz; } +//============================================================================== +// Non-method functions //============================================================================== extern "C" void @@ -629,6 +647,15 @@ extern "C" { i_xyz[2] = inds[2]; } + void lattice_get_local_xyz(Lattice *lat, const double global_xyz[3], + const int i_xyz[3], double local_xyz[3]) + { + std::array xyz {lat->get_local_xyz(global_xyz, i_xyz)}; + local_xyz[0] = xyz[0]; + local_xyz[1] = xyz[1]; + local_xyz[2] = xyz[2]; + } + void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} } diff --git a/src/lattice.h b/src/lattice.h index 81b0c2bdf3..9ade739c02 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -79,8 +79,12 @@ public: //! @return An array containing the indices of a lattice tile. virtual std::array get_indices(const double xyz[3]) const = 0; - //virtual void get_local_xyz(const double global_xyz[3], const int i_xyz[3], - // double local_xyz[3]) const = 0; + //! Get coordinates local to a lattice tile. + //! @param global_xyz[3] A 3D Cartesian coordinate. + //! @param i_xyz[3] The indices for a lattice tile. + //! @return Local 3D Cartesian coordinates. + virtual std::array + get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const = 0; //! Write all information needed to reconstruct the lattice to an HDF5 group. //! @param group_id An HDF5 group id. @@ -107,6 +111,9 @@ public: std::array get_indices(const double xyz[3]) const; + std::array + get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + protected: std::array n_cells; //! Number of cells along each axis std::array lower_left; //! Global lower-left corner of the lattice From 4c36446ffeda245e5741cfa9abeb671e898c14b8 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 17 Feb 2018 17:32:35 -0500 Subject: [PATCH 15/41] Remove array initializer braces to support GCC-4.8 --- src/lattice.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index fd89cbf1e7..2902e3e475 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -1,5 +1,6 @@ #include "lattice.h" +#include #include #include @@ -7,9 +8,6 @@ #include "hdf5_interface.h" #include "xml_interface.h" -//TODO: this is only inlcuded for constants that should be moved elsewhere -//#include "surface.h" - //TODO: remove this include #include @@ -641,7 +639,7 @@ extern "C" { void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3]) { - std::array inds {lat->get_indices(xyz)}; + std::array inds = lat->get_indices(xyz); i_xyz[0] = inds[0]; i_xyz[1] = inds[1]; i_xyz[2] = inds[2]; @@ -650,7 +648,7 @@ extern "C" { void lattice_get_local_xyz(Lattice *lat, const double global_xyz[3], const int i_xyz[3], double local_xyz[3]) { - std::array xyz {lat->get_local_xyz(global_xyz, i_xyz)}; + std::array xyz = lat->get_local_xyz(global_xyz, i_xyz); local_xyz[0] = xyz[0]; local_xyz[1] = xyz[1]; local_xyz[2] = xyz[2]; From 762313943d8bb07c5e55a70ead1d5fbfa493d33e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 28 Feb 2018 13:22:03 -0500 Subject: [PATCH 16/41] Add C++ code for openmc_extend_cells --- src/cell.cpp | 13 +++++++++++-- src/cell.h | 5 +++-- src/geometry_header.F90 | 14 +++++++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index e7b76a9943..fe04f8c69f 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -403,7 +403,7 @@ read_cells(pugi::xml_node *node) // Loop over XML cell elements and populate the array. for (pugi::xml_node cell_node: node->children("cell")) { - cells_c.push_back(Cell(cell_node)); + cells_c.push_back(new Cell(cell_node)); } } @@ -412,7 +412,7 @@ read_cells(pugi::xml_node *node) //============================================================================== extern "C" { - Cell* cell_pointer(int32_t cell_ind) {return &cells_c[cell_ind];} + Cell* cell_pointer(int32_t cell_ind) {return cells_c[cell_ind];} int32_t cell_id(Cell *c) {return c->id;} @@ -436,6 +436,15 @@ extern "C" { } void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} + + void extend_cells_c(int32_t n) + { + cells_c.reserve(cells_c.size() + n); + for (int32_t i = 0; i < n; i++) { + cells_c.push_back(new Cell()); + } + n_cells = cells_c.size(); + } } //extern "C" void free_memory_cells_c() diff --git a/src/cell.h b/src/cell.h index 59cec17291..de5e25aa75 100644 --- a/src/cell.h +++ b/src/cell.h @@ -20,8 +20,7 @@ namespace openmc { extern "C" {int32_t n_cells {0};} class Cell; -//Cell *cells_c; -std::vector cells_c; +std::vector cells_c; std::map cell_dict; @@ -55,6 +54,8 @@ public: std::vector rpn; bool simple; //!< Does the region contain only intersections? + Cell() {}; + explicit Cell(pugi::xml_node cell_node); //! Determine if a cell contains the particle at a given location. diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index f5d79d0a6e..af63cad7f4 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -142,6 +142,12 @@ module geometry_header type(C_PTR), intent(in), value :: lat_ptr integer(HID_T), intent(in), value :: group end subroutine lattice_to_hdf5_c + + subroutine extend_cells_c(n) bind(C) + use ISO_C_BINDING + implicit none + integer(C_INT32_T), intent(in), value :: n + end subroutine extend_cells_c end interface !=============================================================================== @@ -452,6 +458,7 @@ contains integer(C_INT32_T), value, intent(in) :: n integer(C_INT32_T), optional, intent(out) :: index_start integer(C_INT32_T), optional, intent(out) :: index_end + integer(C_INT32_T) :: i integer(C_INT) :: err type(Cell), allocatable :: temp(:) ! temporary cells array @@ -473,7 +480,12 @@ contains ! Return indices in cells array if (present(index_start)) index_start = n_cells + 1 if (present(index_end)) index_end = n_cells + n - n_cells = n_cells + n + + ! Extend the C++ cells array and get pointers to the C++ objects + call extend_cells_c(n) + do i = n_cells - n, n_cells + cells(i) % ptr = cell_pointer_c(i - 1) + end do err = 0 end function openmc_extend_cells From a69baeaed55d8a738e25907ebd1380ee9a0e5333 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 2 Mar 2018 02:12:31 -0500 Subject: [PATCH 17/41] Populate C++ Universe vector --- src/cell.cpp | 21 +++++++++++++++++++++ src/cell.h | 10 +++++++--- src/constants.h | 13 +++++++++++++ src/surface.h | 10 ++-------- 4 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 src/constants.h diff --git a/src/cell.cpp b/src/cell.cpp index fe04f8c69f..136f36e06c 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -5,6 +5,7 @@ #include #include +#include "constants.h" #include "error.h" #include "hdf5_interface.h" #include "surface.h" @@ -204,6 +205,12 @@ Cell::Cell(pugi::xml_node cell_node) universe = 0; } + if (check_for_node(cell_node, "fill")) { + fill = stoi(get_node_value(cell_node, "fill")); + } else { + fill = C_NONE; + } + std::string region_spec {""}; if (check_for_node(cell_node, "region")) { region_spec = get_node_value(cell_node, "region"); @@ -405,6 +412,20 @@ read_cells(pugi::xml_node *node) for (pugi::xml_node cell_node: node->children("cell")) { cells_c.push_back(new Cell(cell_node)); } + + // Populate the Universe vector and dictionary. + for (Cell *c : cells_c) { + int32_t uid = c->universe; + auto it = universe_dict.find(uid); + if (it == universe_dict.end()) { + universes_c.push_back(new Universe()); + universes_c.back()->id = uid; + universes_c.back()->cells.push_back(c); + universe_dict[uid] = universes_c.size() - 1; + } else { + universes_c[it->second]->cells.push_back(c); + } + } } //============================================================================== diff --git a/src/cell.h b/src/cell.h index de5e25aa75..8b540be35a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -21,8 +21,11 @@ extern "C" {int32_t n_cells {0};} class Cell; std::vector cells_c; +std::map cell_dict; -std::map cell_dict; +class Universe; +std::vector universes_c; +std::map universe_dict; //============================================================================== //! A geometry primitive that fills all space and contains cells. @@ -30,10 +33,10 @@ std::map cell_dict; class Universe { - public: +public: int32_t id; //! Unique ID int32_t type; - std::vector cells; //! Cells within this universe + std::vector cells; //! Cells within this universe double x0, y0, z0; //! Translation coordinates. }; @@ -47,6 +50,7 @@ public: int32_t id; //!< Unique ID std::string name{""}; //!< User-defined name int32_t universe; //!< Universe # this cell is in + int32_t fill; //!< Universe # filling this cell //! Definition of spatial region as Boolean expression of half-spaces std::vector region; diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 0000000000..b725809fe0 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,13 @@ +#ifndef CONSTANTS_H +#define CONSTANTS_H + + +namespace openmc{ + +extern "C" double FP_COINCIDENT; +constexpr double INFTY{std::numeric_limits::max()}; +constexpr int C_NONE {-1}; + +} // namespace openmc + +#endif // CONSTANTS_H diff --git a/src/surface.h b/src/surface.h index 046610daa1..2be21c0636 100644 --- a/src/surface.h +++ b/src/surface.h @@ -8,6 +8,8 @@ #include "hdf5.h" #include "pugixml/pugixml.hpp" +#include "constants.h" + namespace openmc { @@ -20,14 +22,6 @@ extern "C" const int BC_VACUUM; extern "C" const int BC_REFLECT; extern "C" const int BC_PERIODIC; -//============================================================================== -// Constants that should eventually be moved out of this file -//============================================================================== - -extern "C" double FP_COINCIDENT; -constexpr double INFTY{std::numeric_limits::max()}; -constexpr int C_NONE {-1}; - //============================================================================== // Global variables //============================================================================== From 735c59650b78a791b90145db69b94fa5e0d6cba5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 29 Apr 2018 15:39:14 -0400 Subject: [PATCH 18/41] Adjust cell universe indices from C++ --- src/cell.cpp | 22 ++++++++++++++++++++-- src/cell.h | 3 ++- src/input_xml.F90 | 19 ++++++++----------- src/summary.F90 | 3 --- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 136f36e06c..ed16a566a3 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -294,8 +294,8 @@ Cell::to_hdf5(hid_t cell_group) const write_string(cell_group, "name", name); } - //TODO: Lookup universe id in universe_dict - //write_int(cell_group, "universe", universe); + //TODO: Fix the off-by-one indexing. + write_int(cell_group, "universe", universes_c[universe-1]->id); // Write the region specification. if (!region.empty()) { @@ -428,6 +428,24 @@ read_cells(pugi::xml_node *node) } } +extern "C" void +adjust_indices_c() +{ + // Change cell.universe values from IDs to indices. + for (Cell *c : cells_c) { + auto it = universe_dict.find(c->universe); + if (it != universe_dict.end()) { + //TODO: Remove this off-by-one indexing. + c->universe = it->second + 1; + } else { + std::stringstream err_msg; + err_msg << "Could not find universe " << c->universe + << " specified on cell " << c->id; + fatal_error(err_msg); + } + } +} + //============================================================================== // Fortran compatibility functions //============================================================================== diff --git a/src/cell.h b/src/cell.h index 8b540be35a..99ca2caf4a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -73,7 +73,8 @@ public: //! Simple cells can be evaluated with short circuit evaluation, i.e., as soon //! as we know that one half-space is not satisfied, we can exit. This //! provides a performance benefit for the common case. In - //! contains_complex, we evaluate the RPN expression using a stack, similar to //! how a RPN calculator would work. + //! contains_complex, we evaluate the RPN expression using a stack, similar to + //! how a RPN calculator would work. //! @param xyz[3] The 3D Cartesian coordinate to check. //! @param uvw[3] A direction used to "break ties" the coordinates are very //! close to a surface. diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 78dd0bb877..6457f587cc 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -49,6 +49,11 @@ module input_xml save interface + subroutine adjust_indices_c() bind(C) + use ISO_C_BINDING + implicit none + end subroutine adjust_indices_c + subroutine read_surfaces(node_ptr) bind(C) use ISO_C_BINDING implicit none @@ -4263,18 +4268,10 @@ contains integer :: id ! user-specified id class(Lattice), pointer :: lat => null() - do i = 1, n_cells - ! ======================================================================= - ! ADJUST UNIVERSE INDEX FOR EACH CELL - associate (c => cells(i)) + call adjust_indices_c() - id = c % universe() - if (universe_dict % has(id)) then - call c % set_universe(universe_dict % get(id)) - else - call fatal_error("Could not find universe " // trim(to_str(id)) & - &// " specified on cell " // trim(to_str(c % id()))) - end if + do i = 1, n_cells + associate (c => cells(i)) ! ======================================================================= ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL diff --git a/src/summary.F90 b/src/summary.F90 index 59bb904475..e2ef1a2c14 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -148,9 +148,6 @@ contains call c % to_hdf5(cell_group) - ! Write universe for this cell - call write_dataset(cell_group, "universe", universes(c%universe())%id) - ! Write information on what fills this cell select case (c%type) case (FILL_MATERIAL) From 98009a268d1a1d735822baa23170de0c8a8e6ceb Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 29 Apr 2018 20:23:41 -0400 Subject: [PATCH 19/41] Remove Fortran lattice % universes --- src/cell.cpp | 19 +++ src/cell.h | 11 +- src/constants.h | 3 +- src/geometry.F90 | 22 ++-- src/geometry_header.F90 | 19 ++- src/input_xml.F90 | 145 ++--------------------- src/lattice.cpp | 66 +++++++++++ src/lattice.h | 23 ++-- src/summary.F90 | 4 +- src/tallies/tally_filter_distribcell.F90 | 8 +- 10 files changed, 152 insertions(+), 168 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index ed16a566a3..56d7c45ca2 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -8,6 +8,7 @@ #include "constants.h" #include "error.h" #include "hdf5_interface.h" +#include "lattice.h" #include "surface.h" #include "xml_interface.h" @@ -29,6 +30,19 @@ constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; extern "C" double FP_PRECISION; +//============================================================================== +// Global variables +//============================================================================== + +// Braces force n_cells to be defined here, not just declared. +extern "C" {int32_t n_cells {0};} + +std::vector cells_c; +std::map cell_dict; + +std::vector universes_c; +std::map universe_dict; + //============================================================================== //! Convert region specification string to integer tokens. //! @@ -444,6 +458,11 @@ adjust_indices_c() fatal_error(err_msg); } } + + // Change all lattice universe values from IDs to indices. + for (Lattice *l : lattices_c) { + l->adjust_indices(); + } } //============================================================================== diff --git a/src/cell.h b/src/cell.h index 99ca2caf4a..5c06d81200 100644 --- a/src/cell.h +++ b/src/cell.h @@ -16,16 +16,15 @@ namespace openmc { // Global variables //============================================================================== -// Braces force n_cells to be defined here, not just declared. -extern "C" {int32_t n_cells {0};} +extern "C" int32_t n_cells; class Cell; -std::vector cells_c; -std::map cell_dict; +extern std::vector cells_c; +extern std::map cell_dict; class Universe; -std::vector universes_c; -std::map universe_dict; +extern std::vector universes_c; +extern std::map universe_dict; //============================================================================== //! A geometry primitive that fills all space and contains cells. diff --git a/src/constants.h b/src/constants.h index b725809fe0..8cc837a735 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,7 +5,8 @@ namespace openmc{ extern "C" double FP_COINCIDENT; -constexpr double INFTY{std::numeric_limits::max()}; +extern "C" double FP_PRECISION; +constexpr double INFTY {std::numeric_limits::max()}; constexpr int C_NONE {-1}; } // namespace openmc diff --git a/src/geometry.F90 b/src/geometry.F90 index fff18d6c85..3fd5859f7f 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -254,7 +254,7 @@ contains if (lat % are_valid_indices(i_xyz)) then ! Particle is inside the lattice. p % coord(j + 1) % universe = & - lat % universes(i_xyz(1), i_xyz(2), i_xyz(3)) + lat % get([i_xyz(1)-1, i_xyz(2)-1, i_xyz(3)-1]) + 1 else ! Particle is outside the lattice. @@ -331,7 +331,8 @@ contains else OUTSIDE_LAT ! Find cell in next lattice element - p % coord(j) % universe = lat % universes(i_xyz(1), i_xyz(2), i_xyz(3)) + p % coord(j) % universe = & + lat % get([i_xyz(1)-1, i_xyz(2)-1, i_xyz(3)-1]) + 1 call find_cell(p, found) if (.not. found) then @@ -591,7 +592,7 @@ contains do k = 1, lat % n_cells(2) do m = 1, lat % n_cells(3) lat % offset(map, j, k, m) = offset - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) offset = offset + & count_target(next_univ, counts, found, univ_id, map) end do @@ -612,7 +613,7 @@ contains cycle else lat % offset(map, j, k, m) = offset - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) offset = offset + & count_target(next_univ, counts, found, univ_id, map) end if @@ -707,7 +708,7 @@ contains do j = 1, lat % n_cells(1) do k = 1, lat % n_cells(2) do m = 1, lat % n_cells(3) - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) ! Found target - stop since target cannot contain itself if (next_univ % id == univ_id) then @@ -735,7 +736,7 @@ contains else if (j + k > 3*lat % n_rings - 1) then cycle else - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) ! Found target - stop since target cannot contain itself if (next_univ % id == univ_id) then @@ -799,7 +800,7 @@ contains do j = 1, lat % n_cells(1) do k = 1, lat % n_cells(2) do m = 1, lat % n_cells(3) - call count_instance(universes(lat % universes(j, k, m))) + call count_instance(universes(lat % get([j-1, k-1, m-1])+1)) end do end do end do @@ -817,7 +818,8 @@ contains else if (j + k > 3*lat % n_rings - 1) then cycle else - call count_instance(universes(lat % universes(j, k, m))) + call count_instance(universes(lat % get([j-1, k-1, m-1]) & + + 1)) end if end do end do @@ -874,7 +876,7 @@ contains do j = 1, lat % n_cells(1) do k = 1, lat % n_cells(2) do m = 1, lat % n_cells(3) - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) levels_below = max(levels_below, maximum_levels(next_univ)) end do end do @@ -893,7 +895,7 @@ contains else if (j + k > 3*lat % n_rings - 1) then cycle else - next_univ => universes(lat % universes(j, k, m)) + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) levels_below = max(levels_below, maximum_levels(next_univ)) end if end do diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index af63cad7f4..ddd9e4c2d2 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -148,6 +148,15 @@ module geometry_header implicit none integer(C_INT32_T), intent(in), value :: n end subroutine extend_cells_c + + function lattice_universe_c(lat_ptr, i_xyz) & + bind(C, name='lattice_universe') result(univ) + use ISO_C_BINDING + implicit none + type(C_PTR), intent(in), value :: lat_ptr + integer(C_INT), intent(in) :: i_xyz(3) + integer(C_INT32_T) :: univ + end function lattice_universe_c end interface !=============================================================================== @@ -170,9 +179,7 @@ module geometry_header type, abstract :: Lattice type(C_PTR) :: ptr - !integer :: id ! Universe number for lattice real(8), allocatable :: pitch(:) ! Pitch along each axis - integer, allocatable :: universes(:,:,:) ! Specified universes integer :: outside ! Material to fill area outside integer :: outer ! universe to tile outside the lat logical :: is_3d ! Lattice has cells on z axis @@ -182,6 +189,7 @@ module geometry_header procedure :: id => lattice_id procedure :: are_valid_indices => lattice_are_valid_indices procedure :: distance => lattice_distance + procedure :: get => lattice_get procedure :: get_indices => lattice_get_indices procedure :: get_local_xyz => lattice_get_local_xyz procedure :: to_hdf5 => lattice_to_hdf5 @@ -297,6 +305,13 @@ contains call lattice_distance_c(this % ptr, xyz, uvw, i_xyz, d, lattice_trans) end subroutine lattice_distance + function lattice_get(this, i_xyz) result(univ) + class(Lattice), intent(in) :: this + integer(C_INT), intent(in) :: i_xyz(3) + integer(C_INT32_T) :: univ + univ = lattice_universe_c(this % ptr, i_xyz) + end function lattice_get + function lattice_get_indices(this, xyz) result(i_xyz) class(Lattice), intent(in) :: this real(C_DOUBLE), intent(in) :: xyz(3) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6457f587cc..a3bc6b8260 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1331,7 +1331,6 @@ contains n_x = lat % n_cells(1) n_y = lat % n_cells(2) n_z = lat % n_cells(3) - allocate(lat % universes(n_x, n_y, n_z)) ! Check that number of universes matches size n = node_word_count(node_lat, "universes") @@ -1340,21 +1339,16 @@ contains &size of lattice " // trim(to_str(lat % id())) // ".") end if - allocate(temp_int_array(n)) - call get_node_array(node_lat, "universes", temp_int_array) - ! Read universes - do m = 1, n_z + do m = 0, n_z-1 do k = 0, n_y - 1 - do j = 1, n_x - lat % universes(j, n_y - k, m) = & - temp_int_array(j + n_x*k + n_x*n_y*(m-1)) - if (find(fill_univ_ids, lat % universes(j, n_y - k, m)) == -1) & - call fill_univ_ids % push_back(lat % universes(j, n_y - k, m)) + do j = 0, n_x - 1 + univ_id = lat % get([j, k, m]) + if (find(fill_univ_ids, univ_id) == -1) & + call fill_univ_ids % push_back(univ_id) end do end do end do - deallocate(temp_int_array) ! Read outer universe for area outside lattice. lat % outer = NO_OUTER_UNIVERSE @@ -1427,7 +1421,6 @@ contains ! Copy number of dimensions n_rings = lat % n_rings n_z = lat % n_axial - allocate(lat % universes(2*n_rings - 1, 2*n_rings - 1, n_z)) ! Check that number of universes matches size n = node_word_count(node_lat, "universes") @@ -1440,91 +1433,15 @@ contains call get_node_array(node_lat, "universes", temp_int_array) ! Read universes - ! Universes in hexagonal lattices are stored in a manner that represents - ! a skewed coordinate system: (x, alpha) rather than (x, y). There is - ! no obvious, direct relationship between the order of universes in the - ! input and the order that they will be stored in the skewed array so - ! the following code walks a set of index values across the skewed array - ! in a manner that matches the input order. Note that i_x = 0, i_a = 0 - ! corresponds to the center of the hexagonal lattice. - - input_index = 1 - do m = 1, n_z - ! Initialize lattice indecies. - i_x = 1 - i_a = n_rings - 1 - - ! Map upper triangular region of hexagonal lattice. - do k = 1, n_rings-1 - ! Walk index to lower-left neighbor of last row start. - i_x = i_x - 1 - do j = 1, k - ! Place universe in array. - lat % universes(i_x + n_rings, i_a + n_rings, m) = & - temp_int_array(input_index) - if (find(fill_univ_ids, temp_int_array(input_index)) == -1) & - call fill_univ_ids % push_back(temp_int_array(input_index)) - ! Walk index to closest non-adjacent right neighbor. - i_x = i_x + 2 - i_a = i_a - 1 - ! Increment XML array index. - input_index = input_index + 1 + do m = 0, n_z-1 + do k = 0, 2*n_rings-2 + do j = 0, 2*n_rings-2 + univ_id = lat % get([j, k, m]) + if (find(fill_univ_ids, univ_id) == -1) & + call fill_univ_ids % push_back(univ_id) end do - ! Return lattice index to start of current row. - i_x = i_x - 2*k - i_a = i_a + k - end do - - ! Map middle square region of hexagonal lattice. - do k = 1, 2*n_rings - 1 - if (mod(k, 2) == 1) then - ! Walk index to lower-left neighbor of last row start. - i_x = i_x - 1 - else - ! Walk index to lower-right neighbor of last row start - i_x = i_x + 1 - i_a = i_a - 1 - end if - do j = 1, n_rings - mod(k-1, 2) - ! Place universe in array. - lat % universes(i_x + n_rings, i_a + n_rings, m) = & - temp_int_array(input_index) - if (find(fill_univ_ids, temp_int_array(input_index)) == -1) & - call fill_univ_ids % push_back(temp_int_array(input_index)) - ! Walk index to closest non-adjacent right neighbor. - i_x = i_x + 2 - i_a = i_a - 1 - ! Increment XML array index. - input_index = input_index + 1 - end do - ! Return lattice index to start of current row. - i_x = i_x - 2*(n_rings - mod(k-1, 2)) - i_a = i_a + n_rings - mod(k-1, 2) - end do - - ! Map lower triangular region of hexagonal lattice. - do k = 1, n_rings-1 - ! Walk index to lower-right neighbor of last row start. - i_x = i_x + 1 - i_a = i_a - 1 - do j = 1, n_rings - k - ! Place universe in array. - lat % universes(i_x + n_rings, i_a + n_rings, m) = & - temp_int_array(input_index) - if (find(fill_univ_ids, temp_int_array(input_index)) == -1) & - call fill_univ_ids % push_back(temp_int_array(input_index)) - ! Walk index to closest non-adjacent right neighbor. - i_x = i_x + 2 - i_a = i_a - 1 - ! Increment XML array index. - input_index = input_index + 1 - end do - ! Return lattice index to start of current row. - i_x = i_x - 2*(n_rings - k) - i_a = i_a + n_rings - k end do end do - deallocate(temp_int_array) ! Read outer universe for area outside lattice. lat % outer = NO_OUTER_UNIVERSE @@ -4312,46 +4229,6 @@ contains do i = 1, n_lattices lat => lattices(i) % obj - select type (lat) - - type is (RectLattice) - do m = 1, lat % n_cells(3) - do k = 1, lat % n_cells(2) - do j = 1, lat % n_cells(1) - id = lat % universes(j,k,m) - if (universe_dict % has(id)) then - lat % universes(j,k,m) = universe_dict % get(id) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id()))) - end if - end do - end do - end do - - type is (HexLattice) - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (j + k < lat % n_rings + 1) then - cycle - else if (j + k > 3*lat % n_rings - 1) then - cycle - end if - id = lat % universes(j, k, m) - if (universe_dict % has(id)) then - lat % universes(j, k, m) = universe_dict % get(id) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(id)) // " specified on lattice " & - &// trim(to_str(lat % id()))) - end if - end do - end do - end do - - end select if (lat % outer /= NO_OUTER_UNIVERSE) then if (universe_dict % has(lat % outer)) then diff --git a/src/lattice.cpp b/src/lattice.cpp index 2902e3e475..9a716f76b2 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -4,6 +4,8 @@ #include #include +#include "cell.h" +#include "constants.h" #include "error.h" #include "hdf5_interface.h" #include "xml_interface.h" @@ -131,6 +133,36 @@ RectLattice::RectLattice(pugi::xml_node lat_node) //============================================================================== +int32_t& +RectLattice::operator[](const int i_xyz[3]) +{ + int nx = n_cells[0]; + int ny = n_cells[1]; + int nz = n_cells[2]; + int indx = nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]; + return universes[indx]; +} + +//============================================================================== + +void +RectLattice::adjust_indices() +{ + int nx = n_cells[0]; + int ny = n_cells[1]; + int nz = n_cells[2]; + for (int iz = 0; iz < nz; iz++) { + for (int iy = 0; iy < ny; iy++) { + for (int ix = 0; ix < nx; ix++) { + int indx = nx*ny*iz + nx*iy + ix; + universes[indx] = universe_dict[universes[indx]]; + } + } + } +} + +//============================================================================== + bool RectLattice::are_valid_indices(const int i_xyz[3]) const { @@ -386,6 +418,37 @@ HexLattice::HexLattice(pugi::xml_node lat_node) //============================================================================== +int32_t& +HexLattice::operator[](const int i_xyz[3]) +{ + int indx = (2*n_rings-1)*(2*n_rings-1) * i_xyz[2] + + (2*n_rings-1) * i_xyz[1] + + i_xyz[0]; + return universes[indx]; +} + +//============================================================================== + +void +HexLattice::adjust_indices() +{ + for (int iz = 0; iz < n_axial; iz++) { + for (int ia = 0; ia < 2*n_rings-1; ia++) { + for (int ix = 0; ix < 2*n_rings-1; ix++) { + int i_xyz[3] {ix+1, ia+1, iz+1}; + if (are_valid_indices(i_xyz)) { + int indx = (2*n_rings-1)*(2*n_rings-1) * iz + + (2*n_rings-1) * ia + + ix; + universes[indx] = universe_dict[universes[indx]]; + } + } + } + } +} + +//============================================================================== + bool HexLattice::are_valid_indices(const int i_xyz[3]) const { @@ -655,6 +718,9 @@ extern "C" { } void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} + + int32_t lattice_universe(Lattice *lat, const int i_xyz[3]) + {return (*lat)[i_xyz];} } } // namespace openmc diff --git a/src/lattice.h b/src/lattice.h index 9ade739c02..b21dc56040 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -15,15 +15,7 @@ namespace openmc { //============================================================================== -// Constants that should eventually be moved out of this file -//============================================================================== - -extern "C" double FP_PRECISION; -constexpr double INFTY{std::numeric_limits::max()}; -constexpr int C_NONE {-1}; - -//============================================================================== -// Constants +// Module constants //============================================================================== constexpr int32_t NO_OUTER_UNIVERSE{-1}; @@ -58,6 +50,11 @@ public: virtual ~Lattice() {} + virtual int32_t& operator[](const int i_xyz[3]) = 0; + + //! Convert internal universe values from IDs to indices using universe_dict. + virtual void adjust_indices() = 0; + //! Check lattice indices. //! @param i_xyz[3] The indices for a lattice tile. //! @return true if the given indices fit within the lattice bounds. False @@ -104,6 +101,10 @@ public: virtual ~RectLattice() {} + int32_t& operator[](const int i_xyz[3]); + + void adjust_indices(); + bool are_valid_indices(const int i_xyz[3]) const; std::pair> @@ -127,6 +128,10 @@ public: virtual ~HexLattice() {} + int32_t& operator[](const int i_xyz[3]); + + void adjust_indices(); + bool are_valid_indices(const int i_xyz[3]) const; std::pair> diff --git a/src/summary.F90 b/src/summary.F90 index e2ef1a2c14..834b2661a9 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -288,7 +288,7 @@ contains do k = 0, lat%n_cells(2) - 1 do m = 1, lat%n_cells(3) lattice_universes(j, k+1, m) = & - universes(lat%universes(j, lat%n_cells(2) - k, m))%id + universes(lat%get([j-1, lat%n_cells(2)-k-1, m-1])+1)%id end do end do end do @@ -319,7 +319,7 @@ contains lattice_universes(j,k,m) = -1 cycle end if - lattice_universes(j,k,m) = universes(lat%universes(j,k,m))%id + lattice_universes(j,k,m) = universes(lat%get([j-1,k-1,m-1])+1)%id end do end do end do diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index e7a9645ae5..39f8db5af4 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -289,7 +289,7 @@ contains ! This is last lattice cell, so target must be here lat_offset = lat % offset(map, k, l, m) offset = offset + lat_offset - next_univ => universes(lat % universes(k, l, m)) + next_univ => universes(lat % get([k-1, l-1, m-1])+1) if (lat % is_3d) then path = trim(path) // "(" // trim(to_str(k-1)) // & "," // trim(to_str(l-1)) // "," // & @@ -310,7 +310,7 @@ contains ! Target is at this lattice position lat_offset = lat % offset(map, old_k, old_l, old_m) offset = offset + lat_offset - next_univ => universes(lat % universes(old_k, old_l, old_m)) + next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) if (lat % is_3d) then path = trim(path) // "(" // trim(to_str(old_k-1)) // & "," // trim(to_str(old_l-1)) // "," // & @@ -359,7 +359,7 @@ contains ! This is last lattice cell, so target must be here lat_offset = lat % offset(map, k, l, m) offset = offset + lat_offset - next_univ => universes(lat % universes(k, l, m)) + next_univ => universes(lat % get([k-1, l-1, m-1])+1) if (lat % is_3d) then path = trim(path) // "(" // & trim(to_str(k - lat % n_rings)) // "," // & @@ -382,7 +382,7 @@ contains ! Target is at this lattice position lat_offset = lat % offset(map, old_k, old_l, old_m) offset = offset + lat_offset - next_univ => universes(lat % universes(old_k, old_l, old_m)) + next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) if (lat % is_3d) then path = trim(path) // "(" // & trim(to_str(old_k - lat % n_rings)) // "," // & From f217e2fc746061e4c09857a1f2da91cb9c32777e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 29 Apr 2018 21:21:39 -0400 Subject: [PATCH 20/41] Clean up lattice code --- src/geometry.F90 | 71 +++++++++++++---------------------------- src/geometry_header.F90 | 1 - src/hdf5_interface.h | 2 +- src/input_xml.F90 | 46 +------------------------- src/lattice.cpp | 28 ++++++++++++++++ src/lattice.h | 6 ++++ src/summary.F90 | 1 - 7 files changed, 58 insertions(+), 97 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 3fd5859f7f..a98ae8b95d 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -605,13 +605,7 @@ contains do m = 1, lat % n_axial do k = 1, 2*lat % n_rings - 1 do j = 1, 2*lat % n_rings - 1 - ! This array location is never used - if (j + k < lat % n_rings + 1) then - cycle - ! This array location is never used - else if (j + k > 3*lat % n_rings - 1) then - cycle - else + if (lat % are_valid_indices([j, k, m])) then lat % offset(map, j, k, m) = offset next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) offset = offset + & @@ -729,13 +723,7 @@ contains do m = 1, lat % n_axial do k = 1, 2*lat % n_rings - 1 do j = 1, 2*lat % n_rings - 1 - ! This array location is never used - if (j + k < lat % n_rings + 1) then - cycle - ! This array location is never used - else if (j + k > 3*lat % n_rings - 1) then - cycle - else + if (lat % are_valid_indices([j, k, m])) then next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) ! Found target - stop since target cannot contain itself @@ -811,13 +799,7 @@ contains do m = 1, lat % n_axial do k = 1, 2*lat % n_rings - 1 do j = 1, 2*lat % n_rings - 1 - ! This array location is never used - if (j + k < lat % n_rings + 1) then - cycle - ! This array location is never used - else if (j + k > 3*lat % n_rings - 1) then - cycle - else + if (lat % are_valid_indices([j, k, m])) then call count_instance(universes(lat % get([j-1, k-1, m-1]) & + 1)) end if @@ -844,6 +826,7 @@ contains integer :: levels ! maximum number of levels for this universe integer :: i ! index over cells + integer :: nx, ny, nz ! lattice shape integer :: j, k, m ! indices in lattice integer :: levels_below ! max levels below this universe type(Cell), pointer :: c ! pointer to current cell @@ -871,39 +854,29 @@ contains select type (lat) type is (RectLattice) - - ! Loop over lattice coordinates - do j = 1, lat % n_cells(1) - do k = 1, lat % n_cells(2) - do m = 1, lat % n_cells(3) - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - levels_below = max(levels_below, maximum_levels(next_univ)) - end do - end do - end do + nx = lat % n_cells(1) + ny = lat % n_cells(2) + nz = lat % n_cells(3) type is (HexLattice) - - ! Loop over lattice coordinates - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - ! This array location is never used - if (j + k < lat % n_rings + 1) then - cycle - ! This array location is never used - else if (j + k > 3*lat % n_rings - 1) then - cycle - else - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - levels_below = max(levels_below, maximum_levels(next_univ)) - end if - end do - end do - end do + nx = 2 * lat % n_rings - 1 + ny = 2 * lat % n_rings - 1 + nz = lat % n_axial end select + ! Loop over lattice coordinates + do j = 1, nx + do k = 1, ny + do m = 1, nz + if (lat % are_valid_indices([j, k, m])) then + next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) + levels_below = max(levels_below, maximum_levels(next_univ)) + end if + end do + end do + end do + end if end do diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index ddd9e4c2d2..117d3feaf4 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -179,7 +179,6 @@ module geometry_header type, abstract :: Lattice type(C_PTR) :: ptr - real(8), allocatable :: pitch(:) ! Pitch along each axis integer :: outside ! Material to fill area outside integer :: outer ! universe to tile outside the lat logical :: is_3d ! Lattice has cells on z axis diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index f5a3028551..0b2e030c48 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -75,7 +75,7 @@ write_int(hid_t group_id, char const *name, int32_t buffer) template inline void write_double_1D(hid_t group_id, char const *name, - std::array &buffer) + const std::array &buffer) { hsize_t dims[1]{array_len}; hid_t dataspace = H5Screate_simple(1, dims, NULL); diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a3bc6b8260..26e2ff0a3b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -931,12 +931,11 @@ contains subroutine read_geometry_xml() - integer :: i, j, k, m, i_x, i_a, input_index + integer :: i, j, k, m integer :: n, n_mats, n_x, n_y, n_z, n_rings, n_rlats, n_hlats integer :: id integer :: univ_id integer :: n_cells_in_univ - integer, allocatable :: temp_int_array(:) real(8) :: phi, theta, psi logical :: file_exists logical :: boundary_exists @@ -1295,31 +1294,6 @@ contains allocate(lat % lower_left(n)) call get_node_array(node_lat, "lower_left", lat % lower_left) - ! Read lattice pitches. - ! TODO: Remove this deprecation warning in a future release. - if (check_for_node(node_lat, "width")) then - call warning("The use of 'width' is deprecated and will be disallowed & - &in a future release. Use 'pitch' instead. The utility openmc/& - &src/utils/update_inputs.py can be used to automatically update & - &geometry.xml files.") - if (node_word_count(node_lat, "width") /= n) then - call fatal_error("Number of entries on must be the same as & - &the number of entries on .") - end if - - else if (node_word_count(node_lat, "pitch") /= n) then - call fatal_error("Number of entries on must be the same as & - &the number of entries on .") - end if - - allocate(lat % pitch(n)) - ! TODO: Remove the 'width' code in a future release. - if (check_for_node(node_lat, "width")) then - call get_node_array(node_lat, "width", lat % pitch) - else - call get_node_array(node_lat, "pitch", lat % pitch) - end if - ! TODO: Remove deprecation warning in a future release. if (check_for_node(node_lat, "type")) then call warning("The use of 'type' is no longer needed. The utility & @@ -1405,19 +1379,6 @@ contains allocate(lat % center(n)) call get_node_array(node_lat, "center", lat % center) - ! Read lattice pitches - n = node_word_count(node_lat, "pitch") - if (lat % is_3d .and. n /= 2) then - call fatal_error("A hexagonal lattice with must have & - &specified by 2 numbers.") - else if ((.not. lat % is_3d) .and. n /= 1) then - call fatal_error("A hexagonal lattice without must have & - & specified by 1 number.") - end if - - allocate(lat % pitch(n)) - call get_node_array(node_lat, "pitch", lat % pitch) - ! Copy number of dimensions n_rings = lat % n_rings n_z = lat % n_axial @@ -1429,9 +1390,6 @@ contains &size of lattice " // trim(to_str(lat % id())) // ".") end if - allocate(temp_int_array(n)) - call get_node_array(node_lat, "universes", temp_int_array) - ! Read universes do m = 0, n_z-1 do k = 0, 2*n_rings-2 @@ -4179,8 +4137,6 @@ contains integer :: i ! index for various purposes integer :: j ! index for various purposes - integer :: k ! loop index for lattices - integer :: m ! loop index for lattices integer :: lid ! lattice IDs integer :: id ! user-specified id class(Lattice), pointer :: lat => null() diff --git a/src/lattice.cpp b/src/lattice.cpp index 9a716f76b2..cda5dff372 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -55,6 +55,8 @@ Lattice::to_hdf5(hid_t lat_group) const if (!name.empty()) { write_string(lat_group, "name", name); } + + to_hdf5_inner(lat_group); } //============================================================================== @@ -265,6 +267,19 @@ RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const return local_xyz; } +//============================================================================== + +void +RectLattice::to_hdf5_inner(hid_t lat_group) const +{ + if (is_3d) { + write_double_1D(lat_group, "pitch", pitch); + } else { + std::array out {{pitch[0], pitch[1]}}; + write_double_1D(lat_group, "pitch", out); + } +} + //============================================================================== // HexLattice implementation //============================================================================== @@ -650,6 +665,19 @@ HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const return local_xyz; } +//============================================================================== + +void +HexLattice::to_hdf5_inner(hid_t lat_group) const +{ + if (is_3d) { + write_double_1D(lat_group, "pitch", pitch); + } else { + std::array out {{pitch[0]}}; + write_double_1D(lat_group, "pitch", out); + } +} + //============================================================================== // Non-method functions //============================================================================== diff --git a/src/lattice.h b/src/lattice.h index b21dc56040..78d83a2cbd 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -89,6 +89,8 @@ public: protected: bool is_3d; //! Has divisions along the z-axis + + virtual void to_hdf5_inner(hid_t group_id) const = 0; }; //============================================================================== @@ -115,6 +117,8 @@ public: std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + void to_hdf5_inner(hid_t group_id) const; + protected: std::array n_cells; //! Number of cells along each axis std::array lower_left; //! Global lower-left corner of the lattice @@ -142,6 +146,8 @@ public: std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + void to_hdf5_inner(hid_t group_id) const; + protected: int n_rings; //! Number of radial tile positions int n_axial; //! Number of axial tile positions diff --git a/src/summary.F90 b/src/summary.F90 index 834b2661a9..160f3bfbda 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -260,7 +260,6 @@ contains call lat % to_hdf5(lattice_group) ! Write name, pitch, and outer universe - call write_dataset(lattice_group, "pitch", lat%pitch) if (lat % outer > 0) then call write_dataset(lattice_group, "outer", universes(lat % outer) % id) else From 42e1148fa68bce7442e5767281093ee54fa722e9 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 10 May 2018 00:12:22 -0400 Subject: [PATCH 21/41] Move most lattice summary.h5 writing to C++ --- src/geometry_header.F90 | 2 - src/hdf5_interface.h | 10 ++++- src/input_xml.F90 | 22 ----------- src/lattice.cpp | 87 +++++++++++++++++++++++++++++++++++++++-- src/lattice.h | 1 - src/summary.F90 | 65 +----------------------------- 6 files changed, 93 insertions(+), 94 deletions(-) diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 025fd69c55..02f9b7e82d 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -198,7 +198,6 @@ module geometry_header type, extends(Lattice) :: RectLattice integer :: n_cells(3) ! Number of cells along each axis - real(8), allocatable :: lower_left(:) ! Global lower-left corner of lat end type RectLattice !=============================================================================== @@ -208,7 +207,6 @@ module geometry_header type, extends(Lattice) :: HexLattice integer :: n_rings ! Number of radial ring cell positoins integer :: n_axial ! Number of axial cell positions - real(8), allocatable :: center(:) ! Global center of lattice end type HexLattice !=============================================================================== diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 66757df8ee..232d2f6e7d 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -98,8 +98,16 @@ write_int(hid_t group_id, char const *name, int32_t buffer) H5Dclose(dataset); } +template void +write_int(hid_t group_id, char const *name, + const std::array &buffer, bool indep) +{ + hsize_t dims[1] {array_len}; + write_dataset(group_id, 1, dims, name, H5T_NATIVE_INT, buffer.data(), indep); +} -template inline void + +template void write_double_1D(hid_t group_id, char const *name, const std::array &buffer) { diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 717e2cada8..4d48e8d144 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1284,15 +1284,6 @@ contains call fatal_error("Rectangular lattice must be two or three dimensions.") end if - ! Read lattice lower-left location - if (node_word_count(node_lat, "lower_left") /= n) then - call fatal_error("Number of entries on must be the same & - &as the number of entries on .") - end if - - allocate(lat % lower_left(n)) - call get_node_array(node_lat, "lower_left", lat % lower_left) - ! TODO: Remove deprecation warning in a future release. if (check_for_node(node_lat, "type")) then call warning("The use of 'type' is no longer needed. The utility & @@ -1365,19 +1356,6 @@ contains lat % is_3d = .false. end if - ! Read lattice lower-left location - n = node_word_count(node_lat, "center") - if (lat % is_3d .and. n /= 3) then - call fatal_error("A hexagonal lattice with must have & - &
specified by 3 numbers.") - else if ((.not. lat % is_3d) .and. n /= 2) then - call fatal_error("A hexagonal lattice without must have & - &
specified by 2 numbers.") - end if - - allocate(lat % center(n)) - call get_node_array(node_lat, "center", lat % center) - ! Copy number of dimensions n_rings = lat % n_rings n_z = lat % n_axial diff --git a/src/lattice.cpp b/src/lattice.cpp index a28d7efe79..5723b2280a 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -272,11 +272,57 @@ RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const void RectLattice::to_hdf5_inner(hid_t lat_group) const { + // Write basic lattice information. + write_string(lat_group, "type", "rectangular", false); if (is_3d) { write_double_1D(lat_group, "pitch", pitch); + write_double_1D(lat_group, "lower_left", lower_left); + write_int(lat_group, "dimension", n_cells, false); } else { - std::array out {{pitch[0], pitch[1]}}; - write_double_1D(lat_group, "pitch", out); + std::array pitch_short {{pitch[0], pitch[1]}}; + write_double_1D(lat_group, "pitch", pitch_short); + std::array ll_short {{lower_left[0], lower_left[1]}}; + write_double_1D(lat_group, "lower_left", ll_short); + std::array nc_short {{n_cells[0], n_cells[1]}}; + write_int(lat_group, "dimension", nc_short, false); + } + + // Write the universe ids. The convention here is to switch the ordering on + // the y-axis to match the way universes are input in a text file. + if (is_3d) { + hsize_t nx {static_cast(n_cells[0])}; + hsize_t ny {static_cast(n_cells[1])}; + hsize_t nz {static_cast(n_cells[2])}; + int out[nx*ny*nz]; + + for (int m = 0; m < nz; m++) { + for (int k = 0; k < ny; k++) { + for (int j = 0; j < nx; j++) { + int indx1 = nx*ny*m + nx*k + j; + int indx2 = nx*ny*m + nx*(ny-k-1) + j; + out[indx2] = universes_c[universes[indx1]]->id; + } + } + } + + hsize_t dims[3] {nz, ny, nx}; + write_int(lat_group, 3, dims, "universes", out, false); + + } else { + hsize_t nx {static_cast(n_cells[0])}; + hsize_t ny {static_cast(n_cells[1])}; + int out[nx*ny]; + + for (int k = 0; k < ny; k++) { + for (int j = 0; j < nx; j++) { + int indx1 = nx*k + j; + int indx2 = nx*(ny-k-1) + j; + out[indx2] = universes_c[universes[indx1]]->id; + } + } + + hsize_t dims[3] {1, ny, nx}; + write_int(lat_group, 3, dims, "universes", out, false); } } @@ -670,12 +716,45 @@ HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const void HexLattice::to_hdf5_inner(hid_t lat_group) const { + // Write basic lattice information. + write_string(lat_group, "type", "hexagonal", false); + write_int(lat_group, 0, nullptr, "n_rings", &n_rings, false); + write_int(lat_group, 0, nullptr, "n_axial", &n_axial, false); if (is_3d) { write_double_1D(lat_group, "pitch", pitch); + write_double_1D(lat_group, "center", center); } else { - std::array out {{pitch[0]}}; - write_double_1D(lat_group, "pitch", out); + std::array pitch_short {{pitch[0]}}; + write_double_1D(lat_group, "pitch", pitch_short); + std::array center_short {{center[0], center[1]}}; + write_double_1D(lat_group, "center", center_short); } + + // Write the universe ids. + hsize_t nx {static_cast(2*n_rings - 1)}; + hsize_t ny {static_cast(2*n_rings - 1)}; + hsize_t nz {static_cast(n_axial)}; + int out[nx*ny*nz]; + + for (int m = 0; m < nz; m++) { + for (int k = 0; k < ny; k++) { + for (int j = 0; j < nx; j++) { + int indx = nx*ny*m + nx*k + j; + if (j + k < n_rings - 1) { + // This array position is never used; put a -1 to indicate this. + out[indx] = -1; + } else if (j + k > 3*n_rings - 3) { + // This array position is never used; put a -1 to indicate this. + out[indx] = -1; + } else { + out[indx] = universes_c[universes[indx]]->id; + } + } + } + } + + hsize_t dims[3] {nz, ny, nx}; + write_int(lat_group, 3, dims, "universes", out, false); } //============================================================================== diff --git a/src/lattice.h b/src/lattice.h index 78d83a2cbd..8bdf469c30 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -41,7 +41,6 @@ class Lattice public: int32_t id; //! Universe ID number std::string name; //! User-defined name - //std::vector pitch; //! Pitch along each basis std::vector universes; //! Universes filling each lattice tile int32_t outer{NO_OUTER_UNIVERSE}; //! Universe tiled outside the lattice //std::vector offset; //! Distribcell offsets diff --git a/src/summary.F90 b/src/summary.F90 index 4ff27963ec..22de03e7b4 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -160,8 +160,7 @@ contains subroutine write_geometry(file_id) integer(HID_T), intent(in) :: file_id - integer :: i, j, k, m - integer, allocatable :: lattice_universes(:,:,:) + integer :: i, j integer, allocatable :: cell_materials(:) integer, allocatable :: cell_ids(:) real(8), allocatable :: cell_temperatures(:) @@ -311,68 +310,6 @@ contains call write_dataset(lattice_group, "outer", lat % outer) end if - select type (lat) - type is (RectLattice) - ! Write lattice type. - call write_dataset(lattice_group, "type", "rectangular") - - ! Write lattice dimensions, lower left corner, and pitch - if (lat % is_3d) then - call write_dataset(lattice_group, "dimension", lat % n_cells) - call write_dataset(lattice_group, "lower_left", lat % lower_left) - else - call write_dataset(lattice_group, "dimension", lat % n_cells(1:2)) - call write_dataset(lattice_group, "lower_left", lat % lower_left) - end if - - ! Write lattice universes. - allocate(lattice_universes(lat%n_cells(1), lat%n_cells(2), & - &lat%n_cells(3))) - do j = 1, lat%n_cells(1) - do k = 0, lat%n_cells(2) - 1 - do m = 1, lat%n_cells(3) - lattice_universes(j, k+1, m) = & - universes(lat%get([j-1, lat%n_cells(2)-k-1, m-1])+1)%id - end do - end do - end do - - type is (HexLattice) - ! Write lattice type. - call write_dataset(lattice_group, "type", "hexagonal") - - ! Write number of lattice cells. - call write_dataset(lattice_group, "n_rings", lat%n_rings) - call write_dataset(lattice_group, "n_axial", lat%n_axial) - - ! Write lattice center - call write_dataset(lattice_group, "center", lat%center) - - ! Write lattice universes. - allocate(lattice_universes(2*lat%n_rings - 1, 2*lat%n_rings - 1, & - &lat%n_axial)) - do m = 1, lat%n_axial - do k = 1, 2*lat%n_rings - 1 - do j = 1, 2*lat%n_rings - 1 - if (j + k < lat%n_rings + 1) then - ! This array position is never used; put a -1 to indicate this - lattice_universes(j,k,m) = -1 - cycle - else if (j + k > 3*lat%n_rings - 1) then - ! This array position is never used; put a -1 to indicate this - lattice_universes(j,k,m) = -1 - cycle - end if - lattice_universes(j,k,m) = universes(lat%get([j-1,k-1,m-1])+1)%id - end do - end do - end do - end select - - ! Write lattice universes - call write_dataset(lattice_group, "universes", lattice_universes) - deallocate(lattice_universes) - call close_group(lattice_group) end do LATTICE_LOOP From 1dfa82530dcca5c407f53a01891acfc2f703c18e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 10 May 2018 18:50:02 -0400 Subject: [PATCH 22/41] Move lattice outer to C++ --- src/geometry.F90 | 4 +-- src/geometry_header.F90 | 26 ++++++++++----- src/input_xml.F90 | 49 ++++------------------------- src/lattice.cpp | 70 +++++++++++++++++++++++++++++++++++++++-- src/summary.F90 | 21 +++---------- 5 files changed, 98 insertions(+), 72 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 0d4fea0049..35e4d3ca57 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -258,14 +258,14 @@ contains else ! Particle is outside the lattice. - if (lat % outer == NO_OUTER_UNIVERSE) then + if (lat % outer() == NO_OUTER_UNIVERSE) then call warning("Particle " // trim(to_str(p %id)) & // " is outside lattice " // trim(to_str(lat % id())) & // " but the lattice has no defined outer universe.") found = .false. return else - p % coord(j + 1) % universe = lat % outer + p % coord(j + 1) % universe = lat % outer() + 1 end if end if end associate diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 02f9b7e82d..ebce31c455 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -141,11 +141,12 @@ module geometry_header integer(HID_T), intent(in), value :: group end subroutine lattice_to_hdf5_c - subroutine extend_cells_c(n) bind(C) - import C_INT32_t - implicit none - integer(C_INT32_T), intent(in), value :: n - end subroutine extend_cells_c + function lattice_outer_c(lat_ptr) bind(C, name='lattice_outer') & + result(outer) + import C_PTR, C_INT32_T + type(C_PTR), intent(in), value :: lat_ptr + integer(C_INT32_T) :: outer + end function lattice_outer_c function lattice_universe_c(lat_ptr, i_xyz) & bind(C, name='lattice_universe') result(univ) @@ -155,6 +156,12 @@ module geometry_header integer(C_INT), intent(in) :: i_xyz(3) integer(C_INT32_T) :: univ end function lattice_universe_c + + subroutine extend_cells_c(n) bind(C) + import C_INT32_t + implicit none + integer(C_INT32_T), intent(in), value :: n + end subroutine extend_cells_c end interface !=============================================================================== @@ -177,8 +184,6 @@ module geometry_header type, abstract :: Lattice type(C_PTR) :: ptr - integer :: outside ! Material to fill area outside - integer :: outer ! universe to tile outside the lat logical :: is_3d ! Lattice has cells on z axis integer, allocatable :: offset(:,:,:,:) ! Distribcell offsets contains @@ -189,6 +194,7 @@ module geometry_header procedure :: get => lattice_get procedure :: get_indices => lattice_get_indices procedure :: get_local_xyz => lattice_get_local_xyz + procedure :: outer => lattice_outer procedure :: to_hdf5 => lattice_to_hdf5 end type Lattice @@ -323,6 +329,12 @@ contains call lattice_get_local_xyz_c(this % ptr, global_xyz, i_xyz, local_xyz) end function lattice_get_local_xyz + function lattice_outer(this) result(outer) + class(Lattice), intent(in) :: this + integer(C_INT32_T) :: outer + outer = lattice_outer_c(this % ptr) + end function lattice_outer + subroutine lattice_to_hdf5(this, group) class(Lattice), intent(in) :: this integer(HID_T), intent(in) :: group diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 4d48e8d144..c6aa8a142d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1315,19 +1315,10 @@ contains end do ! Read outer universe for area outside lattice. - lat % outer = NO_OUTER_UNIVERSE if (check_for_node(node_lat, "outer")) then - call get_node_value(node_lat, "outer", lat % outer) - if (find(fill_univ_ids, lat % outer) == -1) & - call fill_univ_ids % push_back(lat % outer) - end if - - ! Check for 'outside' nodes which are no longer supported. - if (check_for_node(node_lat, "outside")) then - call fatal_error("The use of 'outside' in lattices is no longer & - &supported. Instead, use 'outer' which defines a universe rather & - &than a material. The utility openmc/src/utils/update_inputs.py & - &can be used automatically replace 'outside' with 'outer'.") + call get_node_value(node_lat, "outer", univ_id) + if (find(fill_univ_ids, univ_id) == -1) & + call fill_univ_ids % push_back(univ_id) end if ! Add lattice to dictionary @@ -1379,19 +1370,10 @@ contains end do ! Read outer universe for area outside lattice. - lat % outer = NO_OUTER_UNIVERSE if (check_for_node(node_lat, "outer")) then - call get_node_value(node_lat, "outer", lat % outer) - if (find(fill_univ_ids, lat % outer) == -1) & - call fill_univ_ids % push_back(lat % outer) - end if - - ! Check for 'outside' nodes which are no longer supported. - if (check_for_node(node_lat, "outside")) then - call fatal_error("The use of 'outside' in lattices is no longer & - &supported. Instead, use 'outer' which defines a universe rather & - &than a material. The utility openmc/src/utils/update_inputs.py & - &can be used automatically replace 'outside' with 'outer'.") + call get_node_value(node_lat, "outer", univ_id) + if (find(fill_univ_ids, univ_id) == -1) & + call fill_univ_ids % push_back(univ_id) end if ! Add lattice to dictionary @@ -3875,7 +3857,6 @@ contains integer :: j ! index for various purposes integer :: lid ! lattice IDs integer :: id ! user-specified id - class(Lattice), pointer :: lat => null() call adjust_indices_c() @@ -3916,24 +3897,6 @@ contains end associate end do - ! ========================================================================== - ! ADJUST UNIVERSE INDICES FOR EACH LATTICE - - do i = 1, n_lattices - lat => lattices(i) % obj - - if (lat % outer /= NO_OUTER_UNIVERSE) then - if (universe_dict % has(lat % outer)) then - lat % outer = universe_dict % get(lat % outer) - else - call fatal_error("Invalid universe number " & - &// trim(to_str(lat % outer)) & - &// " specified on lattice " // trim(to_str(lat % id()))) - end if - end if - - end do - end subroutine adjust_indices !=============================================================================== diff --git a/src/lattice.cpp b/src/lattice.cpp index 5723b2280a..7d2b517949 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -50,13 +50,29 @@ Lattice::Lattice(pugi::xml_node lat_node) } void -Lattice::to_hdf5(hid_t lat_group) const +Lattice::to_hdf5(hid_t lattices_group) const { + // Make a group for the lattice. + std::string group_name {"lattice "}; + group_name += std::to_string(id); + hid_t lat_group = create_group(lattices_group, group_name); + + // Write the name and outer universe. if (!name.empty()) { write_string(lat_group, "name", name, false); } + if (outer != NO_OUTER_UNIVERSE) { + int32_t outer_id = universes_c[outer]->id; + write_int(lat_group, 0, nullptr, "outer", &outer_id, false); + } else { + write_int(lat_group, 0, nullptr, "outer", &outer, false); + } + + // Call subclass-overriden function to fill in other details. to_hdf5_inner(lat_group); + + close_group(lat_group); } //============================================================================== @@ -150,6 +166,7 @@ RectLattice::operator[](const int i_xyz[3]) void RectLattice::adjust_indices() { + // Adjust the indices for the universes array. int nx = n_cells[0]; int ny = n_cells[1]; int nz = n_cells[2]; @@ -157,10 +174,32 @@ RectLattice::adjust_indices() for (int iy = 0; iy < ny; iy++) { for (int ix = 0; ix < nx; ix++) { int indx = nx*ny*iz + nx*iy + ix; - universes[indx] = universe_dict[universes[indx]]; + int uid = universes[indx]; + auto search = universe_dict.find(uid); + if (search != universe_dict.end()) { + universes[indx] = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << uid << " specified on " + "lattice " << id; + fatal_error(err_msg); + } } } } + + // Adjust the index for the outer universe. + if (outer != NO_OUTER_UNIVERSE) { + auto search = universe_dict.find(outer); + if (search != universe_dict.end()) { + outer = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << outer << " specified on " + "lattice " << id; + fatal_error(err_msg); + } + } } //============================================================================== @@ -493,6 +532,7 @@ HexLattice::operator[](const int i_xyz[3]) void HexLattice::adjust_indices() { + // Adjust the indices for the universes array. for (int iz = 0; iz < n_axial; iz++) { for (int ia = 0; ia < 2*n_rings-1; ia++) { for (int ix = 0; ix < 2*n_rings-1; ix++) { @@ -501,11 +541,33 @@ HexLattice::adjust_indices() int indx = (2*n_rings-1)*(2*n_rings-1) * iz + (2*n_rings-1) * ia + ix; - universes[indx] = universe_dict[universes[indx]]; + int uid = universes[indx]; + auto search = universe_dict.find(uid); + if (search != universe_dict.end()) { + universes[indx] = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << uid << " specified on " + "lattice " << id; + fatal_error(err_msg); + } } } } } + + // Adjust the index for the outer universe. + if (outer != NO_OUTER_UNIVERSE) { + auto search = universe_dict.find(outer); + if (search != universe_dict.end()) { + outer = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << outer << " specified on " + "lattice " << id; + fatal_error(err_msg); + } + } } //============================================================================== @@ -824,6 +886,8 @@ extern "C" { local_xyz[2] = xyz[2]; } + int32_t lattice_outer(Lattice *lat) {return lat->outer;} + void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} int32_t lattice_universe(Lattice *lat, const int i_xyz[3]) diff --git a/src/summary.F90 b/src/summary.F90 index 22de03e7b4..fb934726e7 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -168,7 +168,7 @@ contains integer(HID_T) :: cells_group, cell_group integer(HID_T) :: surfaces_group integer(HID_T) :: universes_group, univ_group - integer(HID_T) :: lattices_group, lattice_group + integer(HID_T) :: lattices_group type(Cell), pointer :: c class(Lattice), pointer :: lat @@ -293,25 +293,12 @@ contains ! ========================================================================== ! WRITE INFORMATION ON LATTICES - ! Create lattices group (nothing directly written here) then close lattices_group = create_group(geom_group, "lattices") - ! Write information on each lattice - LATTICE_LOOP: do i = 1, n_lattices + do i = 1, n_lattices lat => lattices(i)%obj - lattice_group = create_group(lattices_group, "lattice " // trim(to_str(lat%id()))) - - call lat % to_hdf5(lattice_group) - - ! Write name, pitch, and outer universe - if (lat % outer > 0) then - call write_dataset(lattice_group, "outer", universes(lat % outer) % id) - else - call write_dataset(lattice_group, "outer", lat % outer) - end if - - call close_group(lattice_group) - end do LATTICE_LOOP + call lat % to_hdf5(lattices_group) + end do call close_group(lattices_group) call close_group(geom_group) From 366bd36107280531fe5b31fcc12913159e1e1f13 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 10 May 2018 23:17:19 -0400 Subject: [PATCH 23/41] Add lattice iterators --- src/lattice.cpp | 110 +++++++++++++++++++++++++++++++----------------- src/lattice.h | 58 +++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 38 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 7d2b517949..93c53d88a2 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -167,24 +167,16 @@ void RectLattice::adjust_indices() { // Adjust the indices for the universes array. - int nx = n_cells[0]; - int ny = n_cells[1]; - int nz = n_cells[2]; - for (int iz = 0; iz < nz; iz++) { - for (int iy = 0; iy < ny; iy++) { - for (int ix = 0; ix < nx; ix++) { - int indx = nx*ny*iz + nx*iy + ix; - int uid = universes[indx]; - auto search = universe_dict.find(uid); - if (search != universe_dict.end()) { - universes[indx] = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << uid << " specified on " - "lattice " << id; - fatal_error(err_msg); - } - } + for (auto it = this->begin(); it != this->end(); ++it) { + int uid = *it; + auto search = universe_dict.find(uid); + if (search != universe_dict.end()) { + *it = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << uid << " specified on " + "lattice " << id; + fatal_error(err_msg); } } @@ -529,30 +521,34 @@ HexLattice::operator[](const int i_xyz[3]) //============================================================================== +HexLatticeIter +HexLattice::begin() +{ + return HexLatticeIter(*this, n_rings-1, 0, 0); +} + +HexLatticeIter +HexLattice::end() +{ + return HexLatticeIter(*this, n_rings, 2*n_rings-2, n_axial-1); +} + +//============================================================================== + void HexLattice::adjust_indices() { // Adjust the indices for the universes array. - for (int iz = 0; iz < n_axial; iz++) { - for (int ia = 0; ia < 2*n_rings-1; ia++) { - for (int ix = 0; ix < 2*n_rings-1; ix++) { - int i_xyz[3] {ix+1, ia+1, iz+1}; - if (are_valid_indices(i_xyz)) { - int indx = (2*n_rings-1)*(2*n_rings-1) * iz - + (2*n_rings-1) * ia - + ix; - int uid = universes[indx]; - auto search = universe_dict.find(uid); - if (search != universe_dict.end()) { - universes[indx] = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << uid << " specified on " - "lattice " << id; - fatal_error(err_msg); - } - } - } + for (auto it = this->begin(); it != this->end(); ++it) { + int uid = *it; + auto search = universe_dict.find(uid); + if (search != universe_dict.end()) { + *it = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << uid << " specified on lattice " + << id; + fatal_error(err_msg); } } @@ -819,6 +815,44 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const write_int(lat_group, 3, dims, "universes", out, false); } +//============================================================================== +// HexLatticeIter implementation +//============================================================================== + +HexLatticeIter& +HexLatticeIter::operator++() +{ + while (iz < nz) { + if (iy >= ny) { + // This axial layer is finished. Move to the next one. + ++iz; + iy = 0; + ix = n_rings - 2; + } else { + ++ix; + if (ix + iy < n_rings - 1) { + // We're in the lower-left dead zone. Keep iterating ix. + } else if (ix >= nx) { + // End of this row. Move to the next. + ix = -1; + ++iy; + } else if (ix + iy > 3*n_rings - 3) { + // We're in the upper-right dead zone. Move to the next row. + ix = -1; + ++iy; + } else { + return *this; + } + } + } + + // We've passed the end of the lattice. Return an end iterator. + ix = n_rings; + iy = 2*n_rings-2; + iz = nz-1; + return *this; +} + //============================================================================== // Non-method functions //============================================================================== diff --git a/src/lattice.h b/src/lattice.h index 8bdf469c30..da07df5115 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -104,6 +104,9 @@ public: int32_t& operator[](const int i_xyz[3]); + std::vector::iterator begin() {return universes.begin();} + std::vector::iterator end() {return universes.end();} + void adjust_indices(); bool are_valid_indices(const int i_xyz[3]) const; @@ -124,6 +127,11 @@ protected: std::array pitch; //! Lattice tile width along each axis }; +//============================================================================== +//============================================================================== + +class HexLatticeIter; + class HexLattice : public Lattice { public: @@ -133,6 +141,9 @@ public: int32_t& operator[](const int i_xyz[3]); + HexLatticeIter begin(); + HexLatticeIter end(); + void adjust_indices(); bool are_valid_indices(const int i_xyz[3]) const; @@ -152,6 +163,53 @@ protected: int n_axial; //! Number of axial tile positions std::array center; //! Global center of lattice std::array pitch; //! Lattice tile width and height + + friend class HexLatticeIter; +}; + +class HexLatticeIter +{ +public: + HexLatticeIter(HexLattice &lat_, int ix_, int iy_, int iz_) + : lat(lat_), + n_rings(lat_.n_rings), + nx(2*lat_.n_rings-1), + ny(2*lat_.n_rings-1), + nz(lat_.n_axial), + ix(ix_), + iy(iy_), + iz(iz_) + {} + + bool operator==(const HexLatticeIter &rhs) + { + return (&lat == &rhs.lat) && (ix == rhs.ix) && (iy == rhs.iy) + && (iz == rhs.iz); + }; + + bool operator!=(const HexLatticeIter &rhs) + { + return !(*this == rhs); + }; + + int32_t& operator*() + { + int indx = nx*ny*iz + nx*iy + ix; + return lat.universes[indx]; + } + + HexLatticeIter& operator++(); + + HexLatticeIter operator++(int) + { + HexLatticeIter clone(*this); + ++(*this); + return clone; + } + +private: + HexLattice ⪫ + int n_rings, nx, ny, nz, ix, iy, iz; }; } // namespace openmc From a0fd4e703f1d8b88fd88e4dd78166359cf8f4df5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 May 2018 01:28:38 -0400 Subject: [PATCH 24/41] Make lattice iteration polymorphic --- src/lattice.cpp | 178 ++++++++++++++++++------------------------------ src/lattice.h | 115 +++++++++++++++---------------- 2 files changed, 122 insertions(+), 171 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 93c53d88a2..024e4cb483 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -49,6 +49,55 @@ Lattice::Lattice(pugi::xml_node lat_node) } } +//============================================================================== + +LatticeIter +Lattice::begin() +{ + return LatticeIter(*this, 0); +} + +LatticeIter +Lattice::end() +{ + return LatticeIter(*this, universes.size()); +} + +//============================================================================== + +void +Lattice::adjust_indices() +{ + // Adjust the indices for the universes array. + for (auto it = begin(); it != end(); ++it) { + int uid = *it; + auto search = universe_dict.find(uid); + if (search != universe_dict.end()) { + *it = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << uid << " specified on " + "lattice " << id; + fatal_error(err_msg); + } + } + + // Adjust the index for the outer universe. + if (outer != NO_OUTER_UNIVERSE) { + auto search = universe_dict.find(outer); + if (search != universe_dict.end()) { + outer = search->second; + } else { + std::stringstream err_msg; + err_msg << "Invalid universe number " << outer << " specified on " + "lattice " << id; + fatal_error(err_msg); + } + } +} + +//============================================================================== + void Lattice::to_hdf5(hid_t lattices_group) const { @@ -163,39 +212,6 @@ RectLattice::operator[](const int i_xyz[3]) //============================================================================== -void -RectLattice::adjust_indices() -{ - // Adjust the indices for the universes array. - for (auto it = this->begin(); it != this->end(); ++it) { - int uid = *it; - auto search = universe_dict.find(uid); - if (search != universe_dict.end()) { - *it = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << uid << " specified on " - "lattice " << id; - fatal_error(err_msg); - } - } - - // Adjust the index for the outer universe. - if (outer != NO_OUTER_UNIVERSE) { - auto search = universe_dict.find(outer); - if (search != universe_dict.end()) { - outer = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << outer << " specified on " - "lattice " << id; - fatal_error(err_msg); - } - } -} - -//============================================================================== - bool RectLattice::are_valid_indices(const int i_xyz[3]) const { @@ -521,49 +537,10 @@ HexLattice::operator[](const int i_xyz[3]) //============================================================================== -HexLatticeIter +LatticeIter HexLattice::begin() { - return HexLatticeIter(*this, n_rings-1, 0, 0); -} - -HexLatticeIter -HexLattice::end() -{ - return HexLatticeIter(*this, n_rings, 2*n_rings-2, n_axial-1); -} - -//============================================================================== - -void -HexLattice::adjust_indices() -{ - // Adjust the indices for the universes array. - for (auto it = this->begin(); it != this->end(); ++it) { - int uid = *it; - auto search = universe_dict.find(uid); - if (search != universe_dict.end()) { - *it = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << uid << " specified on lattice " - << id; - fatal_error(err_msg); - } - } - - // Adjust the index for the outer universe. - if (outer != NO_OUTER_UNIVERSE) { - auto search = universe_dict.find(outer); - if (search != universe_dict.end()) { - outer = search->second; - } else { - std::stringstream err_msg; - err_msg << "Invalid universe number " << outer << " specified on " - "lattice " << id; - fatal_error(err_msg); - } - } + return LatticeIter(*this, n_rings-1); } //============================================================================== @@ -771,6 +748,21 @@ HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const //============================================================================== +bool +HexLattice::is_valid_index(int indx) const +{ + int nx {2*n_rings - 1}; + int ny {2*n_rings - 1}; + int nz {n_axial}; + int iz = indx / (nx * ny); + int iy = (indx - nx*ny*iz) / nx; + int ix = indx - nx*ny*iz - nx*iy; + int i_xyz[3] {ix+1, iy+1, iz+1}; // TODO: fix this off-by-one + return are_valid_indices(i_xyz); +} + +//============================================================================== + void HexLattice::to_hdf5_inner(hid_t lat_group) const { @@ -815,44 +807,6 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const write_int(lat_group, 3, dims, "universes", out, false); } -//============================================================================== -// HexLatticeIter implementation -//============================================================================== - -HexLatticeIter& -HexLatticeIter::operator++() -{ - while (iz < nz) { - if (iy >= ny) { - // This axial layer is finished. Move to the next one. - ++iz; - iy = 0; - ix = n_rings - 2; - } else { - ++ix; - if (ix + iy < n_rings - 1) { - // We're in the lower-left dead zone. Keep iterating ix. - } else if (ix >= nx) { - // End of this row. Move to the next. - ix = -1; - ++iy; - } else if (ix + iy > 3*n_rings - 3) { - // We're in the upper-right dead zone. Move to the next row. - ix = -1; - ++iy; - } else { - return *this; - } - } - } - - // We've passed the end of the lattice. Return an end iterator. - ix = n_rings; - iy = 2*n_rings-2; - iz = nz-1; - return *this; -} - //============================================================================== // Non-method functions //============================================================================== diff --git a/src/lattice.h b/src/lattice.h index da07df5115..938294ae4d 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -36,6 +36,8 @@ extern std::map lattice_dict; //! Abstract type for ordered array of universes //============================================================================== +class LatticeIter; + class Lattice { public: @@ -51,8 +53,11 @@ public: virtual int32_t& operator[](const int i_xyz[3]) = 0; + virtual LatticeIter begin(); + LatticeIter end(); + //! Convert internal universe values from IDs to indices using universe_dict. - virtual void adjust_indices() = 0; + void adjust_indices(); //! Check lattice indices. //! @param i_xyz[3] The indices for a lattice tile. @@ -82,6 +87,15 @@ public: virtual std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const = 0; + //! Check flattened lattice index. + //! @param indx The index for a lattice tile. + //! @return true if the given index fit within the lattice bounds. False + //! otherwise. + virtual bool is_valid_index(int indx) const + { + return (indx > 0) && (indx < universes.size()); + } + //! Write all information needed to reconstruct the lattice to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; @@ -92,6 +106,44 @@ protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; }; +class LatticeIter +{ +public: + LatticeIter(Lattice &lat_, int indx_) + : lat(lat_), + indx(indx_) + {} + + bool operator==(const LatticeIter &rhs) + { + return (&lat == &rhs.lat) && (indx == rhs.indx); + } + + bool operator!=(const LatticeIter &rhs) + { + return !(*this == rhs); + } + + int32_t& operator*() + { + return lat.universes[indx]; + } + + LatticeIter& operator++() + { + while (indx < lat.universes.size()) { + ++indx; + if (lat.is_valid_index(indx)) return *this; + } + indx = lat.universes.size(); + return *this; + } + + int indx; +private: + Lattice ⪫ +}; + //============================================================================== //============================================================================== @@ -104,11 +156,6 @@ public: int32_t& operator[](const int i_xyz[3]); - std::vector::iterator begin() {return universes.begin();} - std::vector::iterator end() {return universes.end();} - - void adjust_indices(); - bool are_valid_indices(const int i_xyz[3]) const; std::pair> @@ -130,8 +177,6 @@ protected: //============================================================================== //============================================================================== -class HexLatticeIter; - class HexLattice : public Lattice { public: @@ -141,10 +186,7 @@ public: int32_t& operator[](const int i_xyz[3]); - HexLatticeIter begin(); - HexLatticeIter end(); - - void adjust_indices(); + LatticeIter begin(); bool are_valid_indices(const int i_xyz[3]) const; @@ -156,6 +198,8 @@ public: std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + bool is_valid_index(int indx) const; + void to_hdf5_inner(hid_t group_id) const; protected: @@ -163,53 +207,6 @@ protected: int n_axial; //! Number of axial tile positions std::array center; //! Global center of lattice std::array pitch; //! Lattice tile width and height - - friend class HexLatticeIter; -}; - -class HexLatticeIter -{ -public: - HexLatticeIter(HexLattice &lat_, int ix_, int iy_, int iz_) - : lat(lat_), - n_rings(lat_.n_rings), - nx(2*lat_.n_rings-1), - ny(2*lat_.n_rings-1), - nz(lat_.n_axial), - ix(ix_), - iy(iy_), - iz(iz_) - {} - - bool operator==(const HexLatticeIter &rhs) - { - return (&lat == &rhs.lat) && (ix == rhs.ix) && (iy == rhs.iy) - && (iz == rhs.iz); - }; - - bool operator!=(const HexLatticeIter &rhs) - { - return !(*this == rhs); - }; - - int32_t& operator*() - { - int indx = nx*ny*iz + nx*iy + ix; - return lat.universes[indx]; - } - - HexLatticeIter& operator++(); - - HexLatticeIter operator++(int) - { - HexLatticeIter clone(*this); - ++(*this); - return clone; - } - -private: - HexLattice ⪫ - int n_rings, nx, ny, nz, ix, iy, iz; }; } // namespace openmc From e19fc61f1df9efef4e728a96ad0569ff23b768e3 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 May 2018 02:00:13 -0400 Subject: [PATCH 25/41] Find the root universe from C++ --- src/cell.cpp | 46 ++++++++++++++++++++++ src/input_xml.F90 | 97 ++++++----------------------------------------- 2 files changed, 57 insertions(+), 86 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 368d57b03a..5bfd9104d2 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "constants.h" #include "error.h" @@ -442,6 +443,51 @@ read_cells(pugi::xml_node *node) } } +//============================================================================== + +extern "C" int32_t +find_root_universe() +{ + // Find all the universes listed as a cell fill. + std::unordered_set fill_univ_ids; + for (Cell *c : cells_c) { + fill_univ_ids.insert(c->fill); + } + + // Find all the universes contained in a lattice. + for (Lattice *lat : lattices_c) { + for (auto it = lat->begin(); it != lat->end(); ++it) { + fill_univ_ids.insert(*it); + } + if (lat->outer != NO_OUTER_UNIVERSE) { + fill_univ_ids.insert(lat->outer); + } + } + + // Figure out which universe is not in the set. This is the root universe. + bool root_found {false}; + int32_t root_univ; + for (int32_t i = 0; i < universes_c.size(); i++) { + auto search = fill_univ_ids.find(universes_c[i]->id); + if (search == fill_univ_ids.end()) { + if (root_found) { + fatal_error("Two or more universes are not used as fill universes, so " + "it is not possible to distinguish which one is the root " + "universe."); + } else { + root_found = true; + root_univ = i; + } + } + } + if (!root_found) fatal_error("Could not find a root universe. Make sure " + "there are no circular dependencies in the geometry."); + + return root_univ; +} + +//============================================================================== + extern "C" void adjust_indices_c() { diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c6aa8a142d..09da2d1f44 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -49,27 +49,27 @@ module input_xml interface subroutine adjust_indices_c() bind(C) - use ISO_C_BINDING - implicit none end subroutine adjust_indices_c subroutine read_surfaces(node_ptr) bind(C) - use ISO_C_BINDING - implicit none + import C_PTR type(C_PTR) :: node_ptr end subroutine read_surfaces subroutine read_cells(node_ptr) bind(C) - use ISO_C_BINDING - implicit none + import C_PTR type(C_PTR) :: node_ptr end subroutine read_cells subroutine read_lattices(node_ptr) bind(C) - use ISO_C_BINDING - implicit none + import C_PTR type(C_PTR) :: node_ptr end subroutine read_lattices + + function find_root_universe() bind(C) result(root) + import C_INT32_T + integer(C_INT32_T) :: root + end function find_root_universe end interface contains @@ -930,8 +930,8 @@ contains subroutine read_geometry_xml() - integer :: i, j, k, m - integer :: n, n_mats, n_x, n_y, n_z, n_rings, n_rlats, n_hlats + integer :: i, j, k + integer :: n, n_mats, n_z, n_rings, n_rlats, n_hlats integer :: id integer :: univ_id integer :: n_cells_in_univ @@ -951,7 +951,6 @@ contains type(XMLNode), allocatable :: node_rlat_list(:) type(XMLNode), allocatable :: node_hlat_list(:) type(VectorInt) :: tokens - type(VectorInt) :: fill_univ_ids ! List of fill universe IDs type(VectorInt) :: univ_ids ! List of all universe IDs type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains @@ -1039,8 +1038,6 @@ contains if (check_for_node(node_cell, "fill")) then call get_node_value(node_cell, "fill", c % fill) - if (find(fill_univ_ids, c % fill) == -1) & - call fill_univ_ids % push_back(c % fill) else c % fill = NONE end if @@ -1284,43 +1281,6 @@ contains call fatal_error("Rectangular lattice must be two or three dimensions.") end if - ! TODO: Remove deprecation warning in a future release. - if (check_for_node(node_lat, "type")) then - call warning("The use of 'type' is no longer needed. The utility & - &openmc/src/utils/update_inputs.py can be used to automatically & - &update geometry.xml files.") - end if - - ! Copy number of dimensions - n_x = lat % n_cells(1) - n_y = lat % n_cells(2) - n_z = lat % n_cells(3) - - ! Check that number of universes matches size - n = node_word_count(node_lat, "universes") - if (n /= n_x*n_y*n_z) then - call fatal_error("Number of universes on does not match & - &size of lattice " // trim(to_str(lat % id())) // ".") - end if - - ! Read universes - do m = 0, n_z-1 - do k = 0, n_y - 1 - do j = 0, n_x - 1 - univ_id = lat % get([j, k, m]) - if (find(fill_univ_ids, univ_id) == -1) & - call fill_univ_ids % push_back(univ_id) - end do - end do - end do - - ! Read outer universe for area outside lattice. - if (check_for_node(node_lat, "outer")) then - call get_node_value(node_lat, "outer", univ_id) - if (find(fill_univ_ids, univ_id) == -1) & - call fill_univ_ids % push_back(univ_id) - end if - ! Add lattice to dictionary call lattice_dict % set(lat % id(), i) @@ -1351,31 +1311,6 @@ contains n_rings = lat % n_rings n_z = lat % n_axial - ! Check that number of universes matches size - n = node_word_count(node_lat, "universes") - if (n /= (3*n_rings**2 - 3*n_rings + 1)*n_z) then - call fatal_error("Number of universes on does not match & - &size of lattice " // trim(to_str(lat % id())) // ".") - end if - - ! Read universes - do m = 0, n_z-1 - do k = 0, 2*n_rings-2 - do j = 0, 2*n_rings-2 - univ_id = lat % get([j, k, m]) - if (find(fill_univ_ids, univ_id) == -1) & - call fill_univ_ids % push_back(univ_id) - end do - end do - end do - - ! Read outer universe for area outside lattice. - if (check_for_node(node_lat, "outer")) then - call get_node_value(node_lat, "outer", univ_id) - if (find(fill_univ_ids, univ_id) == -1) & - call fill_univ_ids % push_back(univ_id) - end if - ! Add lattice to dictionary call lattice_dict % set(lat % id(), n_rlats + i) @@ -1395,19 +1330,9 @@ contains n_cells_in_univ = cells_in_univ_dict % get(u % id) allocate(u % cells(n_cells_in_univ)) u % cells(:) = 0 - - ! Check whether universe is a fill universe - if (find(fill_univ_ids, u % id) == -1) then - if (root_universe > 0) then - call fatal_error("Two or more universes are not used as fill & - &universes, so it is not possible to distinguish which one & - &is the root universe.") - else - root_universe = i - end if - end if end associate end do + root_universe = find_root_universe() + 1 do i = 1, n_cells ! Get index in universes array From 110ff69cac8d75181f0f2bef8a861f9f4f868c9f Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 May 2018 17:20:25 -0400 Subject: [PATCH 26/41] Move cell%type to C++ --- CMakeLists.txt | 1 + src/cell.cpp | 82 +++--------------- src/cell.h | 13 +++ src/constants.F90 | 3 + src/constants.h | 2 + src/geometry.F90 | 30 +++---- src/geometry_aux.cpp | 104 +++++++++++++++++++++++ src/geometry_header.F90 | 38 +++++++-- src/input_xml.F90 | 10 +-- src/plot.F90 | 2 +- src/summary.F90 | 2 +- src/tallies/tally_filter_distribcell.F90 | 16 ++-- 12 files changed, 194 insertions(+), 109 deletions(-) create mode 100644 src/geometry_aux.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d2a4348fda..dff755999f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,6 +435,7 @@ set(LIBOPENMC_CXX_SRC src/cell.cpp src/initialize.cpp src/finalize.cpp + src/geometry_aux.cpp src/hdf5_interface.cpp src/lattice.cpp src/message_passing.cpp diff --git a/src/cell.cpp b/src/cell.cpp index 5bfd9104d2..a3f55d5226 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "constants.h" #include "error.h" @@ -226,6 +225,15 @@ Cell::Cell(pugi::xml_node cell_node) fill = C_NONE; } + if (check_for_node(cell_node, "material")) { + //TODO: read material ids. + material.push_back(C_NONE+1); + material.shrink_to_fit(); + } else { + material.push_back(C_NONE); + material.shrink_to_fit(); + } + std::string region_spec {""}; if (check_for_node(cell_node, "region")) { region_spec = get_node_value(cell_node, "region"); @@ -443,74 +451,6 @@ read_cells(pugi::xml_node *node) } } -//============================================================================== - -extern "C" int32_t -find_root_universe() -{ - // Find all the universes listed as a cell fill. - std::unordered_set fill_univ_ids; - for (Cell *c : cells_c) { - fill_univ_ids.insert(c->fill); - } - - // Find all the universes contained in a lattice. - for (Lattice *lat : lattices_c) { - for (auto it = lat->begin(); it != lat->end(); ++it) { - fill_univ_ids.insert(*it); - } - if (lat->outer != NO_OUTER_UNIVERSE) { - fill_univ_ids.insert(lat->outer); - } - } - - // Figure out which universe is not in the set. This is the root universe. - bool root_found {false}; - int32_t root_univ; - for (int32_t i = 0; i < universes_c.size(); i++) { - auto search = fill_univ_ids.find(universes_c[i]->id); - if (search == fill_univ_ids.end()) { - if (root_found) { - fatal_error("Two or more universes are not used as fill universes, so " - "it is not possible to distinguish which one is the root " - "universe."); - } else { - root_found = true; - root_univ = i; - } - } - } - if (!root_found) fatal_error("Could not find a root universe. Make sure " - "there are no circular dependencies in the geometry."); - - return root_univ; -} - -//============================================================================== - -extern "C" void -adjust_indices_c() -{ - // Change cell.universe values from IDs to indices. - for (Cell *c : cells_c) { - auto it = universe_dict.find(c->universe); - if (it != universe_dict.end()) { - //TODO: Remove this off-by-one indexing. - c->universe = it->second + 1; - } else { - std::stringstream err_msg; - err_msg << "Could not find universe " << c->universe - << " specified on cell " << c->id; - fatal_error(err_msg); - } - } - - // Change all lattice universe values from IDs to indices. - for (Lattice *l : lattices_c) { - l->adjust_indices(); - } -} - //============================================================================== // Fortran compatibility functions //============================================================================== @@ -522,6 +462,10 @@ extern "C" { void cell_set_id(Cell *c, int32_t id) {c->id = id;} + int cell_type(Cell *c) {return c->type;} + + void cell_set_type(Cell *c, int type) {c->type = type;} + int32_t cell_universe(Cell *c) {return c->universe;} void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;} diff --git a/src/cell.h b/src/cell.h index 5c06d81200..231bb8ea78 100644 --- a/src/cell.h +++ b/src/cell.h @@ -12,6 +12,14 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +extern "C" int FILL_MATERIAL; +extern "C" int FILL_UNIVERSE; +extern "C" int FILL_LATTICE; + //============================================================================== // Global variables //============================================================================== @@ -48,9 +56,14 @@ class Cell public: int32_t id; //!< Unique ID std::string name{""}; //!< User-defined name + int type; //!< Material, universe, or lattice int32_t universe; //!< Universe # this cell is in int32_t fill; //!< Universe # filling this cell + //! Material within this cell. May be multiple materials for distribcell. + //! C_NONE signifies a universe. + std::vector material; + //! Definition of spatial region as Boolean expression of half-spaces std::vector region; //! Reverse Polish notation for region expression diff --git a/src/constants.F90 b/src/constants.F90 index d1893bf9e1..dbd4181dae 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -113,6 +113,9 @@ module constants FILL_MATERIAL = 1, & ! Cell with a specified material FILL_UNIVERSE = 2, & ! Cell filled by a separate universe FILL_LATTICE = 3 ! Cell filled with a lattice + integer(C_INT), bind(C, name='FILL_MATERIAL') :: FILL_MATERIAL_C = FILL_MATERIAL + integer(C_INT), bind(C, name='FILL_UNIVERSE') :: FILL_UNIVERSE_C = FILL_UNIVERSE + integer(C_INT), bind(C, name='FILL_LATTICE') :: FILL_LATTICE_C = FILL_LATTICE ! Void material integer, parameter :: MATERIAL_VOID = -1 diff --git a/src/constants.h b/src/constants.h index 8cc837a735..685fbcfd72 100644 --- a/src/constants.h +++ b/src/constants.h @@ -1,6 +1,8 @@ #ifndef CONSTANTS_H #define CONSTANTS_H +#include + namespace openmc{ diff --git a/src/geometry.F90 b/src/geometry.F90 index 35e4d3ca57..05ad98b86b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -150,7 +150,7 @@ contains if (found) then associate(c => cells(i_cell)) - CELL_TYPE: if (c % type == FILL_MATERIAL) then + CELL_TYPE: if (c % type() == FILL_MATERIAL) then ! ====================================================================== ! AT LOWEST UNIVERSE, TERMINATE SEARCH @@ -166,10 +166,10 @@ contains distribcell_index = c % distribcell_index offset = 0 do k = 1, p % n_coord - if (cells(p % coord(k) % cell) % type == FILL_UNIVERSE) then + if (cells(p % coord(k) % cell) % type() == FILL_UNIVERSE) then offset = offset + cells(p % coord(k) % cell) % & offset(distribcell_index) - elseif (cells(p % coord(k) % cell) % type == FILL_LATTICE) then + elseif (cells(p % coord(k) % cell) % type() == FILL_LATTICE) then if (lattices(p % coord(k + 1) % lattice) % obj & % are_valid_indices([& p % coord(k + 1) % lattice_x, & @@ -204,7 +204,7 @@ contains p % sqrtkT = c % sqrtkT(1) end if - elseif (c % type == FILL_UNIVERSE) then CELL_TYPE + elseif (c % type() == FILL_UNIVERSE) then CELL_TYPE ! ====================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL @@ -232,7 +232,7 @@ contains call find_cell(p, found) j = p % n_coord - elseif (c % type == FILL_LATTICE) then CELL_TYPE + elseif (c % type() == FILL_LATTICE) then CELL_TYPE ! ====================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL @@ -561,11 +561,11 @@ contains ! ==================================================================== ! AT LOWEST UNIVERSE, TERMINATE SEARCH - if (c % type == FILL_MATERIAL) then + if (c % type() == FILL_MATERIAL) then ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - elseif (c % type == FILL_UNIVERSE) then + elseif (c % type() == FILL_UNIVERSE) then ! Set offset for the cell on this level c % offset(map) = offset @@ -579,7 +579,7 @@ contains ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then + elseif (c % type() == FILL_LATTICE) then ! Set current lattice lat => lattices(c % fill) % obj @@ -671,11 +671,11 @@ contains ! ==================================================================== ! AT LOWEST UNIVERSE, TERMINATE SEARCH - if (c % type == FILL_MATERIAL) then + if (c % type() == FILL_MATERIAL) then ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - elseif (c % type == FILL_UNIVERSE) then + elseif (c % type() == FILL_UNIVERSE) then next_univ => universes(c % fill) @@ -690,7 +690,7 @@ contains ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then + elseif (c % type() == FILL_LATTICE) then ! Set current lattice lat => lattices(c % fill) % obj @@ -771,13 +771,13 @@ contains ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type == FILL_UNIVERSE) then + if (c % type() == FILL_UNIVERSE) then call count_instance(universes(c % fill)) ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then + elseif (c % type() == FILL_LATTICE) then ! Set current lattice associate (lat => lattices(c % fill) % obj) @@ -840,14 +840,14 @@ contains ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type == FILL_UNIVERSE) then + if (c % type() == FILL_UNIVERSE) then next_univ => universes(c % fill) levels_below = max(levels_below, maximum_levels(next_univ)) ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then + elseif (c % type() == FILL_LATTICE) then ! Set current lattice lat => lattices(c % fill) % obj diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp new file mode 100644 index 0000000000..2064bda02d --- /dev/null +++ b/src/geometry_aux.cpp @@ -0,0 +1,104 @@ +#include +#include + +#include "cell.h" +#include "constants.h" +#include "error.h" +#include "lattice.h" + +#include //TODO: remove this + + +namespace openmc { + +extern "C" int32_t +find_root_universe() +{ + // Find all the universes listed as a cell fill. + std::unordered_set fill_univ_ids; + for (Cell *c : cells_c) { + fill_univ_ids.insert(c->fill); + } + + // Find all the universes contained in a lattice. + for (Lattice *lat : lattices_c) { + for (auto it = lat->begin(); it != lat->end(); ++it) { + fill_univ_ids.insert(*it); + } + if (lat->outer != NO_OUTER_UNIVERSE) { + fill_univ_ids.insert(lat->outer); + } + } + + // Figure out which universe is not in the set. This is the root universe. + bool root_found {false}; + int32_t root_univ; + for (int32_t i = 0; i < universes_c.size(); i++) { + auto search = fill_univ_ids.find(universes_c[i]->id); + if (search == fill_univ_ids.end()) { + if (root_found) { + fatal_error("Two or more universes are not used as fill universes, so " + "it is not possible to distinguish which one is the root " + "universe."); + } else { + root_found = true; + root_univ = i; + } + } + } + if (!root_found) fatal_error("Could not find a root universe. Make sure " + "there are no circular dependencies in the geometry."); + + return root_univ; +} + +//============================================================================== + +extern "C" void +adjust_indices_c() +{ + // Adjust material/fill idices. + for (Cell *c : cells_c) { + if (c->material[0] == C_NONE) { + int32_t id = c->fill; + auto search_univ = universe_dict.find(id); + auto search_lat = lattice_dict.find(id); + if (search_univ != universe_dict.end()) { + c->type = FILL_UNIVERSE; + c->fill = search_univ->second + 1; //TODO: off-by-one + } else if (search_lat != lattice_dict.end()) { + c->type = FILL_LATTICE; + c->fill = search_lat->second + 1; //TODO: off-by-one + } else { + std::stringstream err_msg; + err_msg << "Specified fill " << id << " on cell " << c->id + << " is neither a universe nor a lattice."; + fatal_error(err_msg); + } + } else { + //TODO: materials + c->type = FILL_MATERIAL; + } + } + + // Change cell.universe values from IDs to indices. + for (Cell *c : cells_c) { + auto search = universe_dict.find(c->universe); + if (search != universe_dict.end()) { + //TODO: Remove this off-by-one indexing. + c->universe = search->second + 1; + } else { + std::stringstream err_msg; + err_msg << "Could not find universe " << c->universe + << " specified on cell " << c->id; + fatal_error(err_msg); + } + } + + // Change all lattice universe values from IDs to indices. + for (Lattice *l : lattices_c) { + l->adjust_indices(); + } +} + +} // namespace openmc diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index ebce31c455..309076bbe3 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -37,6 +37,20 @@ module geometry_header integer(C_INT32_T), intent(in), value :: id end subroutine cell_set_id_c + function cell_type_c(cell_ptr) bind(C, name='cell_type') result(type) + import C_PTR, C_INT + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT) :: type + end function cell_type_c + + subroutine cell_set_type_c(cell_ptr, type) bind(C, name='cell_set_type') + import C_PTR, C_INT + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT), intent(in), value :: type + end subroutine cell_set_type_c + function cell_universe_c(cell_ptr) bind(C, name='cell_universe') & result(universe) import C_PTR, C_INT32_T @@ -230,8 +244,6 @@ module geometry_header type Cell type(C_PTR) :: ptr - integer :: type ! Type of cell (normal, universe, - ! lattice) integer :: fill ! universe # filling this cell integer :: instances ! number of instances of this cell in ! the geom @@ -257,6 +269,8 @@ module geometry_header procedure :: id => cell_id procedure :: set_id => cell_set_id + procedure :: type => cell_type + procedure :: set_type => cell_set_type procedure :: universe => cell_universe procedure :: set_universe => cell_set_universe procedure :: simple => cell_simple @@ -355,6 +369,18 @@ contains call cell_set_id_c(this % ptr, id) end subroutine cell_set_id + function cell_type(this) result(type) + class(Cell), intent(in) :: this + integer(C_INT) :: type + type = cell_type_c(this % ptr) + end function cell_type + + subroutine cell_set_type(this, type) + class(Cell), intent(in) :: this + integer(C_INT), intent(in) :: type + call cell_set_type_c(this % ptr, type) + end subroutine cell_set_type + function cell_universe(this) result(universe) class(Cell), intent(in) :: this integer(C_INT32_T) :: universe @@ -544,7 +570,7 @@ contains err = 0 if (index >= 1 .and. index <= size(cells)) then associate (c => cells(index)) - type = c % type + type = c % type() select case (type) case (FILL_MATERIAL) n = size(c % material) @@ -595,7 +621,7 @@ contains if (allocated(c % material)) deallocate(c % material) allocate(c % material(n)) - c % type = FILL_MATERIAL + call c % set_type(FILL_MATERIAL) do i = 1, n j = indices(i) if ((j >= 1 .and. j <= n_materials) .or. j == MATERIAL_VOID) then @@ -607,9 +633,9 @@ contains end if end do case (FILL_UNIVERSE) - c % type = FILL_UNIVERSE + call c % set_type(FILL_UNIVERSE) case (FILL_LATTICE) - c % type = FILL_LATTICE + call c % set_type(FILL_LATTICE) end select end associate else diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 09da2d1f44..71408defb0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3794,24 +3794,16 @@ contains if (c % material(1) == NONE) then id = c % fill if (universe_dict % has(id)) then - c % type = FILL_UNIVERSE c % fill = universe_dict % get(id) elseif (lattice_dict % has(id)) then lid = lattice_dict % get(id) - c % type = FILL_LATTICE c % fill = lid - else - call fatal_error("Specified fill " // trim(to_str(id)) // " on cell "& - // trim(to_str(c % id())) // " is neither a universe nor a & - &lattice.") end if else do j = 1, size(c % material) id = c % material(j) if (id == MATERIAL_VOID) then - c % type = FILL_MATERIAL else if (material_dict % has(id)) then - c % type = FILL_MATERIAL c % material(j) = material_dict % get(id) else call fatal_error("Could not find material " // trim(to_str(id)) & @@ -3989,7 +3981,7 @@ contains ! Allocate offset table for fill cells do i = 1, n_cells - if (cells(i) % type /= FILL_MATERIAL) then + if (cells(i) % type() /= FILL_MATERIAL) then allocate(cells(i) % offset(n_maps)) end if end do diff --git a/src/plot.F90 b/src/plot.F90 index 2613acd9d4..789ad0ee9b 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -85,7 +85,7 @@ contains if (pl % color_by == PLOT_COLOR_MATS) then ! Assign color based on material associate (c => cells(p % coord(j) % cell)) - if (c % type == FILL_UNIVERSE) then + if (c % type() == FILL_UNIVERSE) then ! If we stopped on a middle universe level, treat as if not found rgb = pl % not_found % rgb id = -1 diff --git a/src/summary.F90 b/src/summary.F90 index fb934726e7..964ec34a35 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -193,7 +193,7 @@ contains call c % to_hdf5(cell_group) ! Write information on what fills this cell - select case (c%type) + select case (c%type()) case (FILL_MATERIAL) call write_dataset(cell_group, "fill_type", "material") diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index dd12e808cb..0c369e154a 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -58,10 +58,10 @@ contains distribcell_index = cells(this % cell) % distribcell_index offset = 0 do i = 1, p % n_coord - if (cells(p % coord(i) % cell) % type == FILL_UNIVERSE) then + if (cells(p % coord(i) % cell) % type() == FILL_UNIVERSE) then offset = offset + cells(p % coord(i) % cell) % & offset(distribcell_index) - elseif (cells(p % coord(i) % cell) % type == FILL_LATTICE) then + elseif (cells(p % coord(i) % cell) % type() == FILL_LATTICE) then if (lattices(p % coord(i + 1) % lattice) % obj & % are_valid_indices([& p % coord(i + 1) % lattice_x, & @@ -197,20 +197,20 @@ contains c => cells(univ % cells(j)) ! Skip normal cells which do not have offsets - if (c % type == FILL_MATERIAL) cycle + if (c % type() == FILL_MATERIAL) cycle ! Break loop once we've found the next cell with an offset exit end do ! Ensure we didn't just end the loop by iteration - if (c % type /= FILL_MATERIAL) then + if (c % type() /= FILL_MATERIAL) then ! There are more cells in this universe that it could be in later_cell = .true. ! Two cases, lattice or fill cell - if (c % type == FILL_UNIVERSE) then + if (c % type() == FILL_UNIVERSE) then temp_offset = c % offset(map) ! Get the offset of the first lattice location @@ -227,7 +227,7 @@ contains end if end if - if (n == 1 .and. c % type /= FILL_MATERIAL) then + if (n == 1 .and. c % type() /= FILL_MATERIAL) then this_cell = .true. end if @@ -245,7 +245,7 @@ contains ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type == FILL_UNIVERSE) then + if (c % type() == FILL_UNIVERSE) then ! Enter this cell to update the current offset offset = c % offset(map) + offset @@ -256,7 +256,7 @@ contains ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type == FILL_LATTICE) then + elseif (c % type() == FILL_LATTICE) then ! Set current lattice lat => lattices(c % fill) % obj From 5419403e10c6490bd7762ea39e5c4cce5acfa934 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 May 2018 18:11:08 -0400 Subject: [PATCH 27/41] Move cell instance counting to C++ --- src/cell.cpp | 10 ++- src/cell.h | 3 +- src/geometry.F90 | 66 -------------- src/geometry_aux.cpp | 109 ++++++++++++++--------- src/geometry_header.F90 | 17 +++- src/input_xml.F90 | 19 ++-- src/tallies/tally_filter_distribcell.F90 | 2 +- 7 files changed, 101 insertions(+), 125 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index a3f55d5226..6d7e598eba 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -437,16 +437,16 @@ read_cells(pugi::xml_node *node) } // Populate the Universe vector and dictionary. - for (Cell *c : cells_c) { - int32_t uid = c->universe; + for (int i = 0; i < cells_c.size(); i++) { + int32_t uid = cells_c[i]->universe; auto it = universe_dict.find(uid); if (it == universe_dict.end()) { universes_c.push_back(new Universe()); universes_c.back()->id = uid; - universes_c.back()->cells.push_back(c); + universes_c.back()->cells.push_back(i); universe_dict[uid] = universes_c.size() - 1; } else { - universes_c[it->second]->cells.push_back(c); + universes_c[it->second]->cells.push_back(i); } } } @@ -470,6 +470,8 @@ extern "C" { void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;} + int32_t cell_n_instances(Cell *c) {return c->n_instances;} + bool cell_simple(Cell *c) {return c->simple;} bool cell_contains(Cell *c, double xyz[3], double uvw[3], int32_t on_surface) diff --git a/src/cell.h b/src/cell.h index 231bb8ea78..fff8b749c3 100644 --- a/src/cell.h +++ b/src/cell.h @@ -43,7 +43,7 @@ class Universe public: int32_t id; //! Unique ID int32_t type; - std::vector cells; //! Cells within this universe + std::vector cells; //! Cells within this universe double x0, y0, z0; //! Translation coordinates. }; @@ -59,6 +59,7 @@ public: int type; //!< Material, universe, or lattice int32_t universe; //!< Universe # this cell is in int32_t fill; //!< Universe # filling this cell + int32_t n_instances{0}; //!< Number of instances of this cell //! Material within this cell. May be multiple materials for distribcell. //! C_NONE signifies a universe. diff --git a/src/geometry.F90 b/src/geometry.F90 index 05ad98b86b..be2e2be84d 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -750,72 +750,6 @@ contains end function count_target -!=============================================================================== -! COUNT_INSTANCE recursively totals the number of occurrences of all cells -! beginning with the universe given. -!=============================================================================== - - recursive subroutine count_instance(univ) - - type(Universe), intent(in) :: univ ! universe to search through - - integer :: i ! index over cells - integer :: j, k, m ! indices in lattice - integer :: n ! number of cells to search - - n = size(univ % cells) - - do i = 1, n - associate (c => cells(univ % cells(i))) - c % instances = c % instances + 1 - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type() == FILL_UNIVERSE) then - - call count_instance(universes(c % fill)) - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_LATTICE) then - - ! Set current lattice - associate (lat => lattices(c % fill) % obj) - - select type (lat) - type is (RectLattice) - - ! Loop over lattice coordinates - do j = 1, lat % n_cells(1) - do k = 1, lat % n_cells(2) - do m = 1, lat % n_cells(3) - call count_instance(universes(lat % get([j-1, k-1, m-1])+1)) - end do - end do - end do - - type is (HexLattice) - - ! Loop over lattice coordinates - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (lat % are_valid_indices([j, k, m])) then - call count_instance(universes(lat % get([j-1, k-1, m-1]) & - + 1)) - end if - end do - end do - end do - - end select - end associate - end if - end associate - end do - - end subroutine count_instance - !=============================================================================== ! MAXIMUM_LEVELS determines the maximum number of nested coordinate levels in ! the geometry diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 2064bda02d..ec4da6f12a 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -11,49 +11,6 @@ namespace openmc { -extern "C" int32_t -find_root_universe() -{ - // Find all the universes listed as a cell fill. - std::unordered_set fill_univ_ids; - for (Cell *c : cells_c) { - fill_univ_ids.insert(c->fill); - } - - // Find all the universes contained in a lattice. - for (Lattice *lat : lattices_c) { - for (auto it = lat->begin(); it != lat->end(); ++it) { - fill_univ_ids.insert(*it); - } - if (lat->outer != NO_OUTER_UNIVERSE) { - fill_univ_ids.insert(lat->outer); - } - } - - // Figure out which universe is not in the set. This is the root universe. - bool root_found {false}; - int32_t root_univ; - for (int32_t i = 0; i < universes_c.size(); i++) { - auto search = fill_univ_ids.find(universes_c[i]->id); - if (search == fill_univ_ids.end()) { - if (root_found) { - fatal_error("Two or more universes are not used as fill universes, so " - "it is not possible to distinguish which one is the root " - "universe."); - } else { - root_found = true; - root_univ = i; - } - } - } - if (!root_found) fatal_error("Could not find a root universe. Make sure " - "there are no circular dependencies in the geometry."); - - return root_univ; -} - -//============================================================================== - extern "C" void adjust_indices_c() { @@ -101,4 +58,70 @@ adjust_indices_c() } } +//============================================================================== + +extern "C" int32_t +find_root_universe() +{ + // Find all the universes listed as a cell fill. + std::unordered_set fill_univ_ids; + for (Cell *c : cells_c) { + fill_univ_ids.insert(c->fill); + } + + // Find all the universes contained in a lattice. + for (Lattice *lat : lattices_c) { + for (auto it = lat->begin(); it != lat->end(); ++it) { + fill_univ_ids.insert(*it); + } + if (lat->outer != NO_OUTER_UNIVERSE) { + fill_univ_ids.insert(lat->outer); + } + } + + // Figure out which universe is not in the set. This is the root universe. + bool root_found {false}; + int32_t root_univ; + for (int32_t i = 0; i < universes_c.size(); i++) { + auto search = fill_univ_ids.find(universes_c[i]->id); + if (search == fill_univ_ids.end()) { + if (root_found) { + fatal_error("Two or more universes are not used as fill universes, so " + "it is not possible to distinguish which one is the root " + "universe."); + } else { + root_found = true; + root_univ = i; + } + } + } + if (!root_found) fatal_error("Could not find a root universe. Make sure " + "there are no circular dependencies in the geometry."); + + return root_univ; +} + +//============================================================================== + +extern "C" void +count_instances(int32_t univ_indx) +{ + for (int32_t cell_indx : universes_c[univ_indx]->cells) { + Cell &c {*cells_c[cell_indx]}; + ++c.n_instances; + + if (c.type == FILL_UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_instances(c.fill-1); // TODO: off-by-one + + } else if (c.type == FILL_LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice &lat {*lattices_c[c.fill-1]}; // TODO: off-by-one + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_instances(*it); + } + } + } +} + } // namespace openmc diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 309076bbe3..012e976afe 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -67,6 +67,14 @@ module geometry_header integer(C_INT32_T), intent(in), value :: universe end subroutine cell_set_universe_c + function cell_n_instances_c(cell_ptr) bind(C, name='cell_n_instances') & + result(n_instances) + import C_PTR, C_INT32_T + implicit none + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T) :: n_instances + end function cell_n_instances_c + function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple) import C_PTR, C_BOOL implicit none @@ -245,8 +253,6 @@ module geometry_header type(C_PTR) :: ptr integer :: fill ! universe # filling this cell - integer :: instances ! number of instances of this cell in - ! the geom integer, allocatable :: material(:) ! Material within cell. Multiple ! materials for distribcell ! instances. 0 signifies a universe @@ -273,6 +279,7 @@ module geometry_header procedure :: set_type => cell_set_type procedure :: universe => cell_universe procedure :: set_universe => cell_set_universe + procedure :: n_instances => cell_n_instances procedure :: simple => cell_simple procedure :: distance => cell_distance procedure :: to_hdf5 => cell_to_hdf5 @@ -393,6 +400,12 @@ contains call cell_set_universe_c(this % ptr, universe) end subroutine cell_set_universe + function cell_n_instances(this) result(n_instances) + class(Cell), intent(in) :: this + integer(C_INT32_T) :: n_instances + n_instances = cell_n_instances_c(this % ptr) + end function cell_n_instances + function cell_simple(this) result(simple) class(Cell), intent(in) :: this logical(C_BOOL) :: simple diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 71408defb0..e43906c9af 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,8 +11,7 @@ module input_xml use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning, write_message, openmc_err_msg - use geometry, only: calc_offsets, maximum_levels, count_instance, & - neighbor_lists + use geometry, only: calc_offsets, maximum_levels, neighbor_lists use geometry_header use hdf5_interface use list_header, only: ListChar, ListInt, ListReal @@ -51,6 +50,11 @@ module input_xml subroutine adjust_indices_c() bind(C) end subroutine adjust_indices_c + subroutine count_instances_c(univ_indx) bind(C, name='count_instances') + import C_INT32_T + integer(C_INT32_T), intent(in), value :: univ_indx + end subroutine + subroutine read_surfaces(node_ptr) bind(C) import C_PTR type(C_PTR) :: node_ptr @@ -139,7 +143,7 @@ contains ! Perform some final operations to set up the geometry call adjust_indices() - call count_instance(universes(root_universe)) + call count_instances_c(root_universe-1) ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking @@ -1030,7 +1034,6 @@ contains c % ptr = cell_pointer_c(i - 1) ! Initialize distribcell instances and distribcell index - c % instances = 0 c % distribcell_index = NONE ! Get pointer to i-th cell node @@ -3861,19 +3864,19 @@ contains do i = 1, n_cells associate (c => cells(i)) if (size(c % material) > 1) then - if (size(c % material) /= c % instances) then + if (size(c % material) /= c % n_instances()) then call fatal_error("Cell " // trim(to_str(c % id())) // " was & &specified with " // trim(to_str(size(c % material))) & - // " materials but has " // trim(to_str(c % instances)) & + // " materials but has " // trim(to_str(c % n_instances())) & // " distributed instances. The number of materials must & &equal one or the number of instances.") end if end if if (size(c % sqrtkT) > 1) then - if (size(c % sqrtkT) /= c % instances) then + if (size(c % sqrtkT) /= c % n_instances()) then call fatal_error("Cell " // trim(to_str(c % id())) // " was & &specified with " // trim(to_str(size(c % sqrtkT))) & - // " temperatures but has " // trim(to_str(c % instances)) & + // " temperatures but has " // trim(to_str(c % n_instances())) & // " distributed instances. The number of temperatures must & &equal one or the number of instances.") end if diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index 0c369e154a..2b44f3503b 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -102,7 +102,7 @@ contains val = cell_dict % get(id) if (val /= EMPTY) then this % cell = val - this % n_bins = cells(this % cell) % instances + this % n_bins = cells(this % cell) % n_instances() else call fatal_error("Could not find cell " // trim(to_str(id)) & &// " specified on tally filter.") From df6e2a2cef68fdd221dd338690532fb49cbb392b Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 11 May 2018 22:43:27 -0400 Subject: [PATCH 28/41] Move count_target (distribcell) to C++ --- src/geometry.F90 | 172 ++++--------------------------------------- src/geometry_aux.cpp | 61 ++++++++++++++- src/input_xml.F90 | 23 ++---- 3 files changed, 79 insertions(+), 177 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index be2e2be84d..ed5906032b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -17,14 +17,21 @@ module geometry interface function cell_contains_c(cell_ptr, xyz, uvw, on_surface) & bind(C, name="cell_contains") result(in_cell) - use ISO_C_BINDING - implicit none + import C_PTR, C_DOUBLE, C_INT32_T, C_BOOL type(C_PTR), intent(in), value :: cell_ptr real(C_DOUBLE), intent(in) :: xyz(3) real(C_DOUBLE), intent(in) :: uvw(3) integer(C_INT32_T), intent(in), value :: on_surface logical(C_BOOL) :: in_cell end function cell_contains_c + + function count_universe_instances(search_univ, target_univ_id) bind(C) & + result(count) + import C_INT32_T, C_INT + integer(C_INT32_T), intent(in), value :: search_univ + integer(C_INT32_T), intent(in), value :: target_univ_id + integer(C_INT) :: count + end function end interface contains @@ -532,27 +539,22 @@ contains ! routine is called once upon initialization. !=============================================================================== - subroutine calc_offsets(univ_id, map, univ, counts, found) + subroutine calc_offsets(univ_id, map, univ) integer, intent(in) :: univ_id ! target universe ID integer, intent(in) :: map ! map index in vector of maps type(Universe), intent(in) :: univ ! universe searching in - integer, intent(inout) :: counts(:,:) ! target count - logical, intent(inout) :: found(:,:) ! target found integer :: i ! index over cells integer :: j, k, m ! indices in lattice - integer :: n ! number of cells to search integer :: offset ! total offset for a given cell integer :: cell_index ! index in cells array type(Cell), pointer :: c ! pointer to current cell - type(Universe), pointer :: next_univ ! next universe to cycle through class(Lattice), pointer :: lat ! pointer to current lattice - n = size(univ % cells) offset = 0 - do i = 1, n + do i = 1, size(univ % cells) cell_index = univ % cells(i) @@ -566,16 +568,8 @@ contains ! ==================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL elseif (c % type() == FILL_UNIVERSE) then - ! Set offset for the cell on this level c % offset(map) = offset - - ! Count contents of this cell - next_univ => universes(c % fill) - offset = offset + count_target(next_univ, counts, found, univ_id, map) - - ! Move into the next universe - next_univ => universes(c % fill) - c => cells(cell_index) + offset = offset + count_universe_instances(c % fill - 1, univ_id) ! ==================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL @@ -587,30 +581,24 @@ contains select type (lat) type is (RectLattice) - - ! Loop over lattice coordinates do j = 1, lat % n_cells(1) do k = 1, lat % n_cells(2) do m = 1, lat % n_cells(3) lat % offset(map, j, k, m) = offset - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - offset = offset + & - count_target(next_univ, counts, found, univ_id, map) + offset = offset + count_universe_instances(& + lat % get([j-1, k-1, m-1]), univ_id) end do end do end do type is (HexLattice) - - ! Loop over lattice coordinates do m = 1, lat % n_axial do k = 1, 2*lat % n_rings - 1 do j = 1, 2*lat % n_rings - 1 if (lat % are_valid_indices([j, k, m])) then lat % offset(map, j, k, m) = offset - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - offset = offset + & - count_target(next_univ, counts, found, univ_id, map) + offset = offset + count_universe_instances(& + lat % get([j-1, k-1, m-1]), univ_id) end if end do end do @@ -622,134 +610,6 @@ contains end subroutine calc_offsets -!=============================================================================== -! COUNT_TARGET recursively totals the numbers of occurances of a given -! universe ID beginning with the universe given. -!=============================================================================== - - recursive function count_target(univ, counts, found, univ_id, map) result(count) - - type(Universe), intent(in) :: univ ! universe to search through - integer, intent(inout) :: counts(:,:) ! target count - logical, intent(inout) :: found(:,:) ! target found - integer, intent(in) :: univ_id ! target universe ID - integer, intent(in) :: map ! current map - - integer :: i ! index over cells - integer :: j, k, m ! indices in lattice - integer :: n ! number of cells to search - integer :: cell_index ! index in cells array - integer :: count ! number of times target located - type(Cell), pointer :: c ! pointer to current cell - type(Universe), pointer :: next_univ ! next univ to loop through - class(Lattice), pointer :: lat ! pointer to current lattice - - ! Don't research places already checked - if (found(universe_dict % get(univ % id), map)) then - count = counts(universe_dict % get(univ % id), map) - return - end if - - ! If this is the target, it can't contain itself. - ! Count = 1, then quit - if (univ % id == univ_id) then - count = 1 - counts(universe_dict % get(univ % id), map) = 1 - found(universe_dict % get(univ % id), map) = .true. - return - end if - - count = 0 - n = size(univ % cells) - - do i = 1, n - - cell_index = univ % cells(i) - - ! get pointer to cell - c => cells(cell_index) - - ! ==================================================================== - ! AT LOWEST UNIVERSE, TERMINATE SEARCH - if (c % type() == FILL_MATERIAL) then - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_UNIVERSE) then - - next_univ => universes(c % fill) - - ! Found target - stop since target cannot contain itself - if (next_univ % id == univ_id) then - count = count + 1 - return - end if - - count = count + count_target(next_univ, counts, found, univ_id, map) - c => cells(cell_index) - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_LATTICE) then - - ! Set current lattice - lat => lattices(c % fill) % obj - - select type (lat) - - type is (RectLattice) - - ! Loop over lattice coordinates - do j = 1, lat % n_cells(1) - do k = 1, lat % n_cells(2) - do m = 1, lat % n_cells(3) - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - - ! Found target - stop since target cannot contain itself - if (next_univ % id == univ_id) then - count = count + 1 - cycle - end if - - count = count + & - count_target(next_univ, counts, found, univ_id, map) - - end do - end do - end do - - type is (HexLattice) - - ! Loop over lattice coordinates - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (lat % are_valid_indices([j, k, m])) then - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - - ! Found target - stop since target cannot contain itself - if (next_univ % id == univ_id) then - count = count + 1 - cycle - end if - - count = count + & - count_target(next_univ, counts, found, univ_id, map) - end if - end do - end do - end do - - end select - - end if - end do - - counts(universe_dict % get(univ % id), map) = count - found(universe_dict % get(univ % id), map) = .true. - - end function count_target - !=============================================================================== ! MAXIMUM_LEVELS determines the maximum number of nested coordinate levels in ! the geometry diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index ec4da6f12a..906845cb93 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -1,3 +1,6 @@ +//! \file geometry_aux.cpp +//! Auxilary functions for geometry initialization and general data handling. + #include #include @@ -11,6 +14,10 @@ namespace openmc { +//============================================================================== +//! Replace Universe, Lattice, and Material IDs with indices. +//============================================================================== + extern "C" void adjust_indices_c() { @@ -58,6 +65,12 @@ adjust_indices_c() } } +//============================================================================== +//! Figure out which Universe is the root universe. +//! +//! This function looks for a universe that is not listed in a Cell::fill or in +//! a Lattice. +//! @return The index of the root universe. //============================================================================== extern "C" int32_t @@ -101,10 +114,17 @@ find_root_universe() return root_univ; } +//============================================================================== +//! Recursively search through the geometry and count cell instances. +//! +//! This function will update the Cell::n_instances value for each cell in the +//! geometry. +//! @param univ_indx The index of the universe to begin searching from (probably +//! the root universe). //============================================================================== extern "C" void -count_instances(int32_t univ_indx) +count_cell_instances(int32_t univ_indx) { for (int32_t cell_indx : universes_c[univ_indx]->cells) { Cell &c {*cells_c[cell_indx]}; @@ -112,16 +132,51 @@ count_instances(int32_t univ_indx) if (c.type == FILL_UNIVERSE) { // This cell contains another universe. Recurse into that universe. - count_instances(c.fill-1); // TODO: off-by-one + count_cell_instances(c.fill-1); // TODO: off-by-one } else if (c.type == FILL_LATTICE) { // This cell contains a lattice. Recurse into the lattice universes. Lattice &lat {*lattices_c[c.fill-1]}; // TODO: off-by-one for (auto it = lat.begin(); it != lat.end(); ++it) { - count_instances(*it); + count_cell_instances(*it); } } } } +//============================================================================== +//! Recursively search through universes and count the number of instances of +//! the target universe in the geometry tree. +//! @param search_univ The index of the universe to begin searching from. +//! @param target_univ_id The ID of the universe to be counted. +//============================================================================== + +extern "C" int +count_universe_instances(int32_t search_univ, int32_t target_univ_id) +{ + // If this is the target, it can't contain itself. + if (universes_c[search_univ]->id == target_univ_id) { + return 1; + } + + int count {0}; + for (int32_t cell_indx : universes_c[search_univ]->cells) { + Cell &c {*cells_c[cell_indx]}; + + if (c.type == FILL_UNIVERSE) { + int32_t next_univ = c.fill - 1; // TODO: off-by-one + count += count_universe_instances(next_univ, target_univ_id); + + } else if (c.type == FILL_LATTICE) { + Lattice &lat {*lattices_c[c.fill - 1]}; //TODO: off-by-one + for (auto it = lat.begin(); it != lat.end(); ++it) { + int32_t next_univ = *it; + count += count_universe_instances(next_univ, target_univ_id); + } + } + } + + return count; +} + } // namespace openmc diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e43906c9af..44a161f470 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -50,7 +50,7 @@ module input_xml subroutine adjust_indices_c() bind(C) end subroutine adjust_indices_c - subroutine count_instances_c(univ_indx) bind(C, name='count_instances') + subroutine count_cell_instances(univ_indx) bind(C) import C_INT32_T integer(C_INT32_T), intent(in), value :: univ_indx end subroutine @@ -143,7 +143,7 @@ contains ! Perform some final operations to set up the geometry call adjust_indices() - call count_instances_c(root_universe-1) + call count_cell_instances(root_universe-1) ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking @@ -3829,8 +3829,6 @@ contains integer :: i, j ! Tally, filter loop counters logical :: distribcell_active ! Does simulation use distribcell? integer, allocatable :: univ_list(:) ! Target offsets - integer, allocatable :: counts(:,:) ! Target count - logical, allocatable :: found(:,:) ! Target found ! Assume distribcell is not needed until proven otherwise. distribcell_active = .false. @@ -3885,12 +3883,12 @@ contains end do ! Allocate offset maps at each level in the geometry - call allocate_offsets(univ_list, counts, found) + call allocate_offsets(univ_list) ! Calculate offsets for each target distribcell do i = 1, n_maps do j = 1, n_universes - call calc_offsets(univ_list(i), i, universes(j), counts, found) + call calc_offsets(univ_list(i), i, universes(j)) end do end do @@ -3901,11 +3899,9 @@ contains ! memory for distribcell offset tables !=============================================================================== - recursive subroutine allocate_offsets(univ_list, counts, found) + recursive subroutine allocate_offsets(univ_list) integer, intent(out), allocatable :: univ_list(:) ! Target offsets - integer, intent(out), allocatable :: counts(:,:) ! Target count - logical, intent(out), allocatable :: found(:,:) ! Target found integer :: i, j, k ! Loop counters type(SetInt) :: cell_list ! distribells to track @@ -3943,15 +3939,6 @@ contains ! Allocate the list of offset tables for each unique universe allocate(univ_list(n_maps)) - ! Allocate list to accumulate target distribcell counts in each universe - allocate(counts(n_universes, n_maps)) - counts(:,:) = 0 - - ! Allocate list to track if target distribcells are found in each universe - allocate(found(n_universes, n_maps)) - found(:,:) = .false. - - ! Search through universes for distributed cells and assign each one a ! unique distribcell array index. k = 1 From 4b78c65f6960ba49cad98202d3a629810d394527 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 16 May 2018 20:36:45 -0400 Subject: [PATCH 29/41] Remove reference brace-initialization for GCC 4.8 --- src/geometry_aux.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 906845cb93..911e53c281 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -127,7 +127,7 @@ extern "C" void count_cell_instances(int32_t univ_indx) { for (int32_t cell_indx : universes_c[univ_indx]->cells) { - Cell &c {*cells_c[cell_indx]}; + Cell &c = *cells_c[cell_indx]; ++c.n_instances; if (c.type == FILL_UNIVERSE) { @@ -136,7 +136,7 @@ count_cell_instances(int32_t univ_indx) } else if (c.type == FILL_LATTICE) { // This cell contains a lattice. Recurse into the lattice universes. - Lattice &lat {*lattices_c[c.fill-1]}; // TODO: off-by-one + Lattice &lat = *lattices_c[c.fill-1]; // TODO: off-by-one for (auto it = lat.begin(); it != lat.end(); ++it) { count_cell_instances(*it); } @@ -161,14 +161,14 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id) int count {0}; for (int32_t cell_indx : universes_c[search_univ]->cells) { - Cell &c {*cells_c[cell_indx]}; + Cell &c = *cells_c[cell_indx]; if (c.type == FILL_UNIVERSE) { int32_t next_univ = c.fill - 1; // TODO: off-by-one count += count_universe_instances(next_univ, target_univ_id); } else if (c.type == FILL_LATTICE) { - Lattice &lat {*lattices_c[c.fill - 1]}; //TODO: off-by-one + Lattice &lat = *lattices_c[c.fill - 1]; //TODO: off-by-one for (auto it = lat.begin(); it != lat.end(); ++it) { int32_t next_univ = *it; count += count_universe_instances(next_univ, target_univ_id); From 9da5e36daf5d9a6e489794c625d62283fc27d330 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 21 May 2018 16:32:44 -0400 Subject: [PATCH 30/41] Move distribcell offsets to C++ --- src/cell.cpp | 2 + src/cell.h | 2 + src/geometry.F90 | 92 +++--------------------- src/geometry_aux.cpp | 68 +++++++++++------- src/geometry_aux.h | 66 +++++++++++++++++ src/geometry_header.F90 | 49 +++++++++---- src/input_xml.F90 | 44 ++++-------- src/lattice.cpp | 48 +++++++++++++ src/lattice.h | 40 +++++++---- src/summary.F90 | 5 -- src/tallies/tally_filter_distribcell.F90 | 34 ++++----- 11 files changed, 265 insertions(+), 185 deletions(-) create mode 100644 src/geometry_aux.h diff --git a/src/cell.cpp b/src/cell.cpp index 6d7e598eba..1d630b3d4f 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -485,6 +485,8 @@ extern "C" { i_surf = out.second; } + int32_t cell_offset(Cell *c, int map) {return c->offset[map];} + void cell_to_hdf5(Cell *c, hid_t group) {c->to_hdf5(group);} void extend_cells_c(int32_t n) diff --git a/src/cell.h b/src/cell.h index fff8b749c3..2b03e1cd0a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -71,6 +71,8 @@ public: std::vector rpn; bool simple; //!< Does the region contain only intersections? + std::vector offset; //!< Distribcell offset table + Cell() {}; explicit Cell(pugi::xml_node cell_node); diff --git a/src/geometry.F90 b/src/geometry.F90 index d053625877..c3b647a822 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -26,7 +26,7 @@ module geometry end function cell_contains_c function count_universe_instances(search_univ, target_univ_id) bind(C) & - result(count) + result(count) import C_INT32_T, C_INT integer(C_INT32_T), intent(in), value :: search_univ integer(C_INT32_T), intent(in), value :: target_univ_id @@ -174,19 +174,19 @@ contains offset = 0 do k = 1, p % n_coord if (cells(p % coord(k) % cell) % type() == FILL_UNIVERSE) then - offset = offset + cells(p % coord(k) % cell) % & - offset(distribcell_index) + offset = offset + cells(p % coord(k) % cell) & + % offset(distribcell_index-1) elseif (cells(p % coord(k) % cell) % type() == FILL_LATTICE) then if (lattices(p % coord(k + 1) % lattice) % obj & % are_valid_indices([& p % coord(k + 1) % lattice_x, & p % coord(k + 1) % lattice_y, & p % coord(k + 1) % lattice_z])) then - offset = offset + lattices(p % coord(k + 1) % lattice) % obj % & - offset(distribcell_index, & - p % coord(k + 1) % lattice_x, & - p % coord(k + 1) % lattice_y, & - p % coord(k + 1) % lattice_z) + offset = offset + lattices(p % coord(k + 1) % lattice) % obj & + % offset(distribcell_index - 1, & + [p % coord(k + 1) % lattice_x - 1, & + p % coord(k + 1) % lattice_y - 1, & + p % coord(k + 1) % lattice_z - 1]) end if end if end do @@ -534,82 +534,6 @@ contains end subroutine neighbor_lists -!=============================================================================== -! CALC_OFFSETS calculates and stores the offsets in all fill cells. This -! routine is called once upon initialization. -!=============================================================================== - - subroutine calc_offsets(univ_id, map, univ) - - integer, intent(in) :: univ_id ! target universe ID - integer, intent(in) :: map ! map index in vector of maps - type(Universe), intent(in) :: univ ! universe searching in - - integer :: i ! index over cells - integer :: j, k, m ! indices in lattice - integer :: offset ! total offset for a given cell - integer :: cell_index ! index in cells array - type(Cell), pointer :: c ! pointer to current cell - class(Lattice), pointer :: lat ! pointer to current lattice - - offset = 0 - - do i = 1, size(univ % cells) - - cell_index = univ % cells(i) - - ! get pointer to cell - c => cells(cell_index) - - ! ==================================================================== - ! AT LOWEST UNIVERSE, TERMINATE SEARCH - if (c % type() == FILL_MATERIAL) then - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_UNIVERSE) then - c % offset(map) = offset - offset = offset + count_universe_instances(c % fill - 1, univ_id) - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_LATTICE) then - - ! Set current lattice - lat => lattices(c % fill) % obj - - select type (lat) - - type is (RectLattice) - do m = 1, lat % n_cells(3) - do k = 1, lat % n_cells(2) - do j = 1, lat % n_cells(1) - lat % offset(map, j, k, m) = offset - offset = offset + count_universe_instances(& - lat % get([j-1, k-1, m-1]), univ_id) - end do - end do - end do - - type is (HexLattice) - do m = 1, lat % n_axial - do k = 1, 2*lat % n_rings - 1 - do j = 1, 2*lat % n_rings - 1 - if (lat % are_valid_indices([j, k, m])) then - lat % offset(map, j, k, m) = offset - offset = offset + count_universe_instances(& - lat % get([j-1, k-1, m-1]), univ_id) - end if - end do - end do - end do - end select - - end if - end do - - end subroutine calc_offsets - !=============================================================================== ! MAXIMUM_LEVELS determines the maximum number of nested coordinate levels in ! the geometry diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 911e53c281..0685542409 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -1,5 +1,4 @@ -//! \file geometry_aux.cpp -//! Auxilary functions for geometry initialization and general data handling. +#include "geometry_aux.h" #include #include @@ -14,11 +13,9 @@ namespace openmc { -//============================================================================== -//! Replace Universe, Lattice, and Material IDs with indices. //============================================================================== -extern "C" void +void adjust_indices_c() { // Adjust material/fill idices. @@ -65,15 +62,9 @@ adjust_indices_c() } } -//============================================================================== -//! Figure out which Universe is the root universe. -//! -//! This function looks for a universe that is not listed in a Cell::fill or in -//! a Lattice. -//! @return The index of the root universe. //============================================================================== -extern "C" int32_t +int32_t find_root_universe() { // Find all the universes listed as a cell fill. @@ -115,15 +106,24 @@ find_root_universe() } //============================================================================== -//! Recursively search through the geometry and count cell instances. -//! -//! This function will update the Cell::n_instances value for each cell in the -//! geometry. -//! @param univ_indx The index of the universe to begin searching from (probably -//! the root universe). + +void +allocate_offset_tables(int n_maps) +{ + for (Cell *c : cells_c) { + if (c->type != FILL_MATERIAL) { + c->offset.resize(n_maps, C_NONE); + } + } + + for (Lattice *lat : lattices_c) { + lat->allocate_offset_table(n_maps); + } +} + //============================================================================== -extern "C" void +void count_cell_instances(int32_t univ_indx) { for (int32_t cell_indx : universes_c[univ_indx]->cells) { @@ -144,14 +144,9 @@ count_cell_instances(int32_t univ_indx) } } -//============================================================================== -//! Recursively search through universes and count the number of instances of -//! the target universe in the geometry tree. -//! @param search_univ The index of the universe to begin searching from. -//! @param target_univ_id The ID of the universe to be counted. //============================================================================== -extern "C" int +int count_universe_instances(int32_t search_univ, int32_t target_univ_id) { // If this is the target, it can't contain itself. @@ -179,4 +174,27 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id) return count; } +//============================================================================== + +void +fill_offset_tables(int32_t target_univ_id, int map) +{ + for (Universe *univ : universes_c) { + int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation. + for (int32_t cell_indx : univ->cells) { + Cell &c = *cells_c[cell_indx]; + + if (c.type == FILL_UNIVERSE) { + c.offset[map] = offset; + int32_t search_univ = c.fill - 1; // TODO: off-by-one + offset += count_universe_instances(search_univ, target_univ_id); + + } else if (c.type == FILL_LATTICE) { + Lattice &lat = *lattices_c[c.fill - 1]; // TODO: off-by-one + offset = lat.fill_offset_table(offset, target_univ_id, map); + } + } + } +} + } // namespace openmc diff --git a/src/geometry_aux.h b/src/geometry_aux.h new file mode 100644 index 0000000000..0a0500794b --- /dev/null +++ b/src/geometry_aux.h @@ -0,0 +1,66 @@ +//! \file geometry_aux.h +//! Auxilary functions for geometry initialization and general data handling. + +#ifndef GEOMETRY_AUX_H +#define GEOMETRY_AUX_H + +#include + + +namespace openmc { + +//============================================================================== +//! Replace Universe, Lattice, and Material IDs with indices. +//============================================================================== + +extern "C" void adjust_indices_c(); + +//============================================================================== +//! Figure out which Universe is the root universe. +//! +//! This function looks for a universe that is not listed in a Cell::fill or in +//! a Lattice. +//! @return The index of the root universe. +//============================================================================== + +extern "C" int32_t find_root_universe(); + +//============================================================================== +//! Allocate storage in Lattice and Cell objects for distribcell offset tables. +//============================================================================== + +extern "C" void allocate_offset_tables(int n_maps); + +//============================================================================== +//! Recursively search through the geometry and count cell instances. +//! +//! This function will update the Cell::n_instances value for each cell in the +//! geometry. +//! @param univ_indx The index of the universe to begin searching from (probably +//! the root universe). +//============================================================================== + +extern "C" void count_cell_instances(int32_t univ_indx); + +//============================================================================== +//! Recursively search through universes and count universe instances. +//! @param search_univ The index of the universe to begin searching from. +//! @param target_univ_id The ID of the universe to be counted. +//! @return The number of instances of target_univ_id in the geometry tree under +//! search_univ. +//============================================================================== + +extern "C" int +count_universe_instances(int32_t search_univ, int32_t target_univ_id); + +//============================================================================== +//! Populate Cell and Lattice distribcell offset tables. +//! @param target_univ_id The ID of the universe to be counted. +//! @param map The index of the distribcell map that defines the offsets for the +//! target universe. +//============================================================================== + +extern "C" void fill_offset_tables(int32_t target_univ_id, int map); + +} // namespace openmc +#endif // GEOMETRY_AUX_H diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 012e976afe..fc70a8eeca 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -68,7 +68,7 @@ module geometry_header end subroutine cell_set_universe_c function cell_n_instances_c(cell_ptr) bind(C, name='cell_n_instances') & - result(n_instances) + result(n_instances) import C_PTR, C_INT32_T implicit none type(C_PTR), intent(in), value :: cell_ptr @@ -94,9 +94,16 @@ module geometry_header integer(C_INT32_T), intent(out) :: i_surf end subroutine cell_distance_c + function cell_offset_c(cell_ptr, map) bind(C, name="cell_offset") & + result(offset) + import C_PTR, C_INT, C_INT32_T + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT), intent(in), value :: map + integer(C_INT32_T) :: offset + end function cell_offset_c + subroutine cell_to_hdf5_c(cell_ptr, group) bind(C, name='cell_to_hdf5') import HID_T, C_PTR - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(HID_T), intent(in), value :: group end subroutine cell_to_hdf5_c @@ -104,14 +111,12 @@ module geometry_header function lattice_pointer_c(lat_ind) bind(C, name='lattice_pointer') & result(ptr) import C_PTR, C_INT32_T - implicit none integer(C_INT32_T), intent(in), value :: lat_ind type(C_PTR) :: ptr end function lattice_pointer_c function lattice_id_c(lat_ptr) bind(C, name='lattice_id') result(id) import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: lat_ptr integer(C_INT32_T) :: id end function lattice_id_c @@ -119,7 +124,6 @@ module geometry_header function lattice_are_valid_indices_c(lat_ptr, i_xyz) & bind(C, name='lattice_are_valid_indices') result (is_valid) import C_PTR, C_INT, C_BOOL - implicit none type(C_PTR), intent(in), value :: lat_ptr integer(C_INT), intent(in) :: i_xyz(3) logical(C_BOOL) :: is_valid @@ -128,7 +132,6 @@ module geometry_header subroutine lattice_distance_c(lat_ptr, xyz, uvw, i_xyz, d, lattice_trans) & bind(C, name='lattice_distance') import C_PTR, C_INT, C_DOUBLE - implicit none type(C_PTR), intent(in), value :: lat_ptr real(C_DOUBLE), intent(in) :: xyz(3) real(C_DOUBLE), intent(in) :: uvw(3) @@ -140,7 +143,6 @@ module geometry_header subroutine lattice_get_indices_c(lat_ptr, xyz, i_xyz) & bind(C, name='lattice_get_indices') import C_PTR, C_INT, C_DOUBLE - implicit none type(C_PTR), intent(in), value :: lat_ptr real(C_DOUBLE), intent(in) :: xyz(3) integer(C_INT), intent(out) :: i_xyz(3) @@ -149,7 +151,6 @@ module geometry_header subroutine lattice_get_local_xyz_c(lat_ptr, global_xyz, i_xyz, local_xyz) & bind(C, name='lattice_get_local_xyz') import C_PTR, C_INT, C_DOUBLE - implicit none type(C_PTR), intent(in), value :: lat_ptr real(C_DOUBLE), intent(in) :: global_xyz(3) integer(C_INT), intent(in) :: i_xyz(3) @@ -158,11 +159,19 @@ module geometry_header subroutine lattice_to_hdf5_c(lat_ptr, group) bind(C, name='lattice_to_hdf5') import HID_T, C_PTR - implicit none type(C_PTR), intent(in), value :: lat_ptr integer(HID_T), intent(in), value :: group end subroutine lattice_to_hdf5_c + function lattice_offset_c(lat_ptr, map, i_xyz) & + bind(C, name='lattice_offset') result(offset) + import C_PTR, C_INT, C_INT32_T + type(C_PTR), intent(in), value :: lat_ptr + integer(C_INT), intent(in), value :: map + integer(C_INT), intent(in) :: i_xyz(3) + integer(C_INT32_T) :: offset + end function lattice_offset_c + function lattice_outer_c(lat_ptr) bind(C, name='lattice_outer') & result(outer) import C_PTR, C_INT32_T @@ -173,7 +182,6 @@ module geometry_header function lattice_universe_c(lat_ptr, i_xyz) & bind(C, name='lattice_universe') result(univ) import C_PTR, C_INT32_t, C_INT - implicit none type(C_PTR), intent(in), value :: lat_ptr integer(C_INT), intent(in) :: i_xyz(3) integer(C_INT32_T) :: univ @@ -181,7 +189,6 @@ module geometry_header subroutine extend_cells_c(n) bind(C) import C_INT32_t - implicit none integer(C_INT32_T), intent(in), value :: n end subroutine extend_cells_c end interface @@ -207,7 +214,6 @@ module geometry_header type(C_PTR) :: ptr logical :: is_3d ! Lattice has cells on z axis - integer, allocatable :: offset(:,:,:,:) ! Distribcell offsets contains procedure :: id => lattice_id @@ -216,6 +222,7 @@ module geometry_header procedure :: get => lattice_get procedure :: get_indices => lattice_get_indices procedure :: get_local_xyz => lattice_get_local_xyz + procedure :: offset => lattice_offset procedure :: outer => lattice_outer procedure :: to_hdf5 => lattice_to_hdf5 end type Lattice @@ -256,8 +263,6 @@ module geometry_header integer, allocatable :: material(:) ! Material within cell. Multiple ! materials for distribcell ! instances. 0 signifies a universe - integer, allocatable :: offset(:) ! Distribcell offset for tally - ! counter integer, allocatable :: region(:) ! Definition of spatial region as ! Boolean expression of half-spaces integer :: distribcell_index ! Index corresponding to this cell in @@ -282,6 +287,7 @@ module geometry_header procedure :: n_instances => cell_n_instances procedure :: simple => cell_simple procedure :: distance => cell_distance + procedure :: offset => cell_offset procedure :: to_hdf5 => cell_to_hdf5 end type Cell @@ -350,6 +356,14 @@ contains call lattice_get_local_xyz_c(this % ptr, global_xyz, i_xyz, local_xyz) end function lattice_get_local_xyz + function lattice_offset(this, map, i_xyz) result(offset) + class(Lattice), intent(in) :: this + integer(C_INT), intent(in) :: map + integer(C_INT), intent(in) :: i_xyz(3) + integer(C_INT32_T) :: offset + offset = lattice_offset_c(this % ptr, map, i_xyz) + end function lattice_offset + function lattice_outer(this) result(outer) class(Lattice), intent(in) :: this integer(C_INT32_T) :: outer @@ -422,6 +436,13 @@ contains call cell_distance_c(this % ptr, xyz, uvw, on_surface, min_dist, i_surf) end subroutine cell_distance + function cell_offset(this, map) result(offset) + class(Cell), intent(in) :: this + integer(C_INT), intent(in) :: map + integer(C_INT32_T) :: offset + offset = cell_offset_c(this % ptr, map) + end function cell_offset + subroutine cell_to_hdf5(this, group) class(Cell), intent(in) :: this integer(HID_T), intent(in) :: group diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 44a161f470..c68ed4a8c0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,7 +11,7 @@ module input_xml use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning, write_message, openmc_err_msg - use geometry, only: calc_offsets, maximum_levels, neighbor_lists + use geometry, only: maximum_levels, neighbor_lists use geometry_header use hdf5_interface use list_header, only: ListChar, ListInt, ListReal @@ -50,10 +50,21 @@ module input_xml subroutine adjust_indices_c() bind(C) end subroutine adjust_indices_c + subroutine allocate_offset_tables(n_maps) bind(C) + import C_INT + integer(C_INT), intent(in), value :: n_maps + end subroutine allocate_offset_tables + + subroutine fill_offset_tables(target_univ_id, map) bind(C) + import C_INT32_T, C_INT + integer(C_INT32_T), intent(in), value :: target_univ_id + integer(C_INT), intent(in), value :: map + end subroutine fill_offset_tables + subroutine count_cell_instances(univ_indx) bind(C) import C_INT32_T integer(C_INT32_T), intent(in), value :: univ_indx - end subroutine + end subroutine count_cell_instances subroutine read_surfaces(node_ptr) bind(C) import C_PTR @@ -3884,12 +3895,11 @@ contains ! Allocate offset maps at each level in the geometry call allocate_offsets(univ_list) + call allocate_offset_tables(n_maps) ! Calculate offsets for each target distribcell do i = 1, n_maps - do j = 1, n_universes - call calc_offsets(univ_list(i), i, universes(j)) - end do + call fill_offset_tables(univ_list(i), i-1) end do end subroutine prepare_distribcell @@ -3952,30 +3962,6 @@ contains end do end do - ! Allocate the offset tables for lattices - do i = 1, n_lattices - associate(lat => lattices(i) % obj) - select type(lat) - - type is (RectLattice) - allocate(lat % offset(n_maps, lat % n_cells(1), lat % n_cells(2), & - lat % n_cells(3))) - type is (HexLattice) - allocate(lat % offset(n_maps, 2 * lat % n_rings - 1, & - 2 * lat % n_rings - 1, lat % n_axial)) - end select - - lat % offset(:, :, :, :) = 0 - end associate - end do - - ! Allocate offset table for fill cells - do i = 1, n_cells - if (cells(i) % type() /= FILL_MATERIAL) then - allocate(cells(i) % offset(n_maps)) - end if - end do - ! Free up memory call cell_list % clear() diff --git a/src/lattice.cpp b/src/lattice.cpp index 024e4cb483..7bb5fb6bb7 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -7,6 +7,7 @@ #include "cell.h" #include "constants.h" #include "error.h" +#include "geometry_aux.h" #include "hdf5_interface.h" #include "xml_interface.h" @@ -98,6 +99,26 @@ Lattice::adjust_indices() //============================================================================== +void +Lattice::allocate_offset_table(int n_maps) +{ + offsets.resize(n_maps * universes.size(), C_NONE); +} + +//============================================================================== + +int32_t +Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map) +{ + for (auto it = begin(); it != end(); ++it) { + offsets[map * universes.size() + it.indx] = offset; + offset += count_universe_instances(*it, target_univ_id); + } + return offset; +} + +//============================================================================== + void Lattice::to_hdf5(hid_t lattices_group) const { @@ -316,6 +337,17 @@ RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const //============================================================================== +int32_t& +RectLattice::offset(int map, const int i_xyz[3]) +{ + int nx = n_cells[0]; + int ny = n_cells[1]; + int nz = n_cells[2]; + return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; +} + +//============================================================================== + void RectLattice::to_hdf5_inner(hid_t lat_group) const { @@ -763,6 +795,17 @@ HexLattice::is_valid_index(int indx) const //============================================================================== +int32_t& +HexLattice::offset(int map, const int i_xyz[3]) +{ + int nx = 2*n_rings - 1; + int ny = 2*n_rings - 1; + int nz = n_axial; + return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; +} + +//============================================================================== + void HexLattice::to_hdf5_inner(hid_t lat_group) const { @@ -874,6 +917,11 @@ extern "C" { local_xyz[2] = xyz[2]; } + int32_t lattice_offset(Lattice *lat, int map, const int i_xyz[3]) + { + return lat->offset(map, i_xyz); + } + int32_t lattice_outer(Lattice *lat) {return lat->outer;} void lattice_to_hdf5(Lattice *lat, hid_t group) {lat->to_hdf5(group);} diff --git a/src/lattice.h b/src/lattice.h index 938294ae4d..9b55025b58 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -41,11 +41,11 @@ class LatticeIter; class Lattice { public: - int32_t id; //! Universe ID number - std::string name; //! User-defined name - std::vector universes; //! Universes filling each lattice tile - int32_t outer{NO_OUTER_UNIVERSE}; //! Universe tiled outside the lattice - //std::vector offset; //! Distribcell offsets + int32_t id; //!< Universe ID number + std::string name; //!< User-defined name + std::vector universes; //!< Universes filling each lattice tile + int32_t outer{NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice + std::vector offsets; //!< Distribcell offset table explicit Lattice(pugi::xml_node lat_node); @@ -59,6 +59,11 @@ public: //! Convert internal universe values from IDs to indices using universe_dict. void adjust_indices(); + //! Allocate offset table for distribcell. + void allocate_offset_table(int n_maps); + + int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map); + //! Check lattice indices. //! @param i_xyz[3] The indices for a lattice tile. //! @return true if the given indices fit within the lattice bounds. False @@ -96,6 +101,13 @@ public: return (indx > 0) && (indx < universes.size()); } + //! Get the distribcell offset for a lattice tile. + //! @param The map index for the target cell. + //! @param i_xyz[3] The indices for a lattice tile. + //! @return Distribcell offset i.e. the largest instance number for the target + //! cell found in the geometry tree under this lattice tile. + virtual int32_t& offset(int map, const int i_xyz[3]) = 0; + //! Write all information needed to reconstruct the lattice to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; @@ -166,12 +178,14 @@ public: std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const; + int32_t& offset(int map, const int i_xyz[3]); + void to_hdf5_inner(hid_t group_id) const; protected: - std::array n_cells; //! Number of cells along each axis - std::array lower_left; //! Global lower-left corner of the lattice - std::array pitch; //! Lattice tile width along each axis + std::array n_cells; //!< Number of cells along each axis + std::array lower_left; //!< Global lower-left corner of the lattice + std::array pitch; //!< Lattice tile width along each axis }; //============================================================================== @@ -200,13 +214,15 @@ public: bool is_valid_index(int indx) const; + int32_t& offset(int map, const int i_xyz[3]); + void to_hdf5_inner(hid_t group_id) const; protected: - int n_rings; //! Number of radial tile positions - int n_axial; //! Number of axial tile positions - std::array center; //! Global center of lattice - std::array pitch; //! Lattice tile width and height + int n_rings; //!< Number of radial tile positions + int n_axial; //!< Number of axial tile positions + std::array center; //!< Global center of lattice + std::array pitch; //!< Lattice tile width and height }; } // namespace openmc diff --git a/src/summary.F90 b/src/summary.F90 index 964ec34a35..1d33491230 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -226,11 +226,6 @@ contains case (FILL_UNIVERSE) call write_dataset(cell_group, "fill_type", "universe") call write_dataset(cell_group, "fill", universes(c%fill)%id) - if (allocated(c%offset)) then - if (size(c%offset) > 0) then - call write_dataset(cell_group, "offset", c%offset) - end if - end if if (allocated(c%translation)) then call write_dataset(cell_group, "translation", c%translation) diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index d804fe0ea0..ce2549f58a 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -59,19 +59,19 @@ contains offset = 0 do i = 1, p % n_coord if (cells(p % coord(i) % cell) % type() == FILL_UNIVERSE) then - offset = offset + cells(p % coord(i) % cell) % & - offset(distribcell_index) + offset = offset + cells(p % coord(i) % cell) & + % offset(distribcell_index-1) elseif (cells(p % coord(i) % cell) % type() == FILL_LATTICE) then if (lattices(p % coord(i + 1) % lattice) % obj & % are_valid_indices([& p % coord(i + 1) % lattice_x, & p % coord(i + 1) % lattice_y, & p % coord(i + 1) % lattice_z])) then - offset = offset + lattices(p % coord(i + 1) % lattice) % obj % & - offset(distribcell_index, & - p % coord(i + 1) % lattice_x, & - p % coord(i + 1) % lattice_y, & - p % coord(i + 1) % lattice_z) + offset = offset + lattices(p % coord(i + 1) % lattice) % obj & + % offset(distribcell_index - 1, & + [p % coord(i + 1) % lattice_x - 1, & + p % coord(i + 1) % lattice_y - 1, & + p % coord(i + 1) % lattice_z - 1]) end if end if if (this % cell == p % coord(i) % cell) then @@ -211,12 +211,12 @@ contains ! Two cases, lattice or fill cell if (c % type() == FILL_UNIVERSE) then - temp_offset = c % offset(map) + temp_offset = c % offset(map-1) ! Get the offset of the first lattice location else lat => lattices(c % fill) % obj - temp_offset = lat % offset(map, 1, 1, 1) + temp_offset = lat % offset(map-1, [0, 0, 0]) end if ! If the final offset is in the range of offset - temp_offset+offset @@ -248,7 +248,7 @@ contains if (c % type() == FILL_UNIVERSE) then ! Enter this cell to update the current offset - offset = c % offset(map) + offset + offset = c % offset(map-1) + offset next_univ => universes(c % fill) call find_offset(i_cell, next_univ, target_offset, offset, path) @@ -282,10 +282,11 @@ contains do l = 1, n_y do k = 1, n_x - if (target_offset >= lat % offset(map, k, l, m) + offset) then + if (target_offset >= lat % offset(map-1, [k-1, l-1, m-1]) & + + offset) then if (k == n_x .and. l == n_y .and. m == n_z) then ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map, k, l, m) + lat_offset = lat % offset(map-1, [k-1, l-1, m-1]) offset = offset + lat_offset next_univ => universes(lat % get([k-1, l-1, m-1])+1) if (lat % is_3d) then @@ -306,7 +307,7 @@ contains end if else ! Target is at this lattice position - lat_offset = lat % offset(map, old_k, old_l, old_m) + lat_offset = lat % offset(map-1, [old_k-1, old_l-1, old_m-1]) offset = offset + lat_offset next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) if (lat % is_3d) then @@ -352,10 +353,11 @@ contains cycle end if - if (target_offset >= lat % offset(map, k, l, m) + offset) then + if (target_offset >= lat % offset(map-1, [k-1, l-1, m-1]) & + + offset) then if (k == lat % n_rings .and. l == n_y .and. m == n_z) then ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map, k, l, m) + lat_offset = lat % offset(map-1, [k-1, l-1, m-1]) offset = offset + lat_offset next_univ => universes(lat % get([k-1, l-1, m-1])+1) if (lat % is_3d) then @@ -378,7 +380,7 @@ contains end if else ! Target is at this lattice position - lat_offset = lat % offset(map, old_k, old_l, old_m) + lat_offset = lat % offset(map-1, [old_k-1, old_l-1, old_m-1]) offset = offset + lat_offset next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) if (lat % is_3d) then From 8598d99c32c92b2a268adc8d18c7cb949b447805 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 21 May 2018 16:55:44 -0400 Subject: [PATCH 31/41] Separate regression and unit tests in CI script --- tools/ci/travis-script.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/ci/travis-script.sh b/tools/ci/travis-script.sh index ee445b517f..6dfbc95106 100755 --- a/tools/ci/travis-script.sh +++ b/tools/ci/travis-script.sh @@ -8,7 +8,9 @@ fi # Run regression and unit tests if [[ $MPI == 'y' ]]; then - pytest --cov=openmc -v --mpi tests + pytest --cov=openmc -v --mpi tests/regression_tests + pytest --cov=openmc -v --mpi tests/unit_tests else - pytest --cov=openmc -v tests + pytest --cov=openmc -v tests/regression_tests + pytest --cov=openmc -v tests/unit_tests fi From d9c24371b6f94327de9a11000bf085910106c07e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 21 May 2018 17:23:35 -0400 Subject: [PATCH 32/41] Simplify distribcell initialization --- src/input_xml.F90 | 105 ++++++++------------------------------ src/nuclide_header.F90 | 1 - src/simulation_header.F90 | 3 -- 3 files changed, 21 insertions(+), 88 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c68ed4a8c0..b708974b86 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -3837,39 +3837,29 @@ contains subroutine prepare_distribcell() - integer :: i, j ! Tally, filter loop counters - logical :: distribcell_active ! Does simulation use distribcell? - integer, allocatable :: univ_list(:) ! Target offsets + integer :: i, j, k + type(SetInt) :: cell_list ! distribcells to track + type(ListInt) :: univ_list ! universes containing distribcells - ! Assume distribcell is not needed until proven otherwise. - distribcell_active = .false. - - ! We need distribcell if any tallies have distribcell filters. + ! Find all cells listed in a distribcell filter. do i = 1, n_tallies do j = 1, size(tallies(i) % obj % filter) select type(filt => filters(tallies(i) % obj % filter(j)) % obj) type is (DistribcellFilter) - distribcell_active = .true. + call cell_list % add(filt % cell) end select end do end do - ! We also need distribcell if any distributed materials or distributed - ! temperatues are present. - if (.not. distribcell_active) then - do i = 1, n_cells - if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then - distribcell_active = .true. - exit - end if - end do - end if + ! Find all cells with multiple (distributed) materials or temperatures. + do i = 1, n_cells + if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then + call cell_list % add(i) + end if + end do - ! If distribcell isn't used in this simulation then no more work left to do. - if (.not. distribcell_active) return - - ! Make sure the number of materials and temperatures matches the number of - ! cell instances. + ! Make sure the number of distributed materials and temperatures matches the + ! number of respective cell instances. do i = 1, n_cells associate (c => cells(i)) if (size(c % material) > 1) then @@ -3885,7 +3875,7 @@ contains if (size(c % sqrtkT) /= c % n_instances()) then call fatal_error("Cell " // trim(to_str(c % id())) // " was & &specified with " // trim(to_str(size(c % sqrtkT))) & - // " temperatures but has " // trim(to_str(c % n_instances())) & + // " temperatures but has " // trim(to_str(c % n_instances()))& // " distributed instances. The number of temperatures must & &equal one or the number of instances.") end if @@ -3893,62 +3883,6 @@ contains end associate end do - ! Allocate offset maps at each level in the geometry - call allocate_offsets(univ_list) - call allocate_offset_tables(n_maps) - - ! Calculate offsets for each target distribcell - do i = 1, n_maps - call fill_offset_tables(univ_list(i), i-1) - end do - - end subroutine prepare_distribcell - -!=============================================================================== -! ALLOCATE_OFFSETS determines the number of maps needed and allocates required -! memory for distribcell offset tables -!=============================================================================== - - recursive subroutine allocate_offsets(univ_list) - - integer, intent(out), allocatable :: univ_list(:) ! Target offsets - - integer :: i, j, k ! Loop counters - type(SetInt) :: cell_list ! distribells to track - - ! Begin gathering list of cells in distribcell tallies - n_maps = 0 - - ! List all cells referenced in distribcell filters. - do i = 1, n_tallies - do j = 1, size(tallies(i) % obj % filter) - select type(filt => filters(tallies(i) % obj % filter(j)) % obj) - type is (DistribcellFilter) - call cell_list % add(filt % cell) - end select - end do - end do - - ! List all cells with multiple (distributed) materials or temperatures. - do i = 1, n_cells - if (size(cells(i) % material) > 1 .or. size(cells(i) % sqrtkT) > 1) then - call cell_list % add(i) - end if - end do - - ! Compute the number of unique universes containing these distribcells - ! to determine the number of offset tables to allocate - do i = 1, n_universes - do j = 1, size(universes(i) % cells) - if (cell_list % contains(universes(i) % cells(j))) then - n_maps = n_maps + 1 - end if - end do - end do - - ! Allocate the list of offset tables for each unique universe - allocate(univ_list(n_maps)) - ! Search through universes for distributed cells and assign each one a ! unique distribcell array index. k = 1 @@ -3956,15 +3890,18 @@ contains do j = 1, size(universes(i) % cells) if (cell_list % contains(universes(i) % cells(j))) then cells(universes(i) % cells(j)) % distribcell_index = k - univ_list(k) = universes(i) % id + call univ_list % append(universes(i) % id) k = k + 1 end if end do end do - ! Free up memory - call cell_list % clear() + ! Allocate and fill cell and lattice offset tables. + call allocate_offset_tables(univ_list % size()) + do i = 1, univ_list % size() + call fill_offset_tables(univ_list % get_item(i), i-1) + end do - end subroutine allocate_offsets + end subroutine prepare_distribcell end module input_xml diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index ebabe5cdbc..17880f6e1b 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -10,7 +10,6 @@ module nuclide_header use endf_header, only: Function1D, Polynomial, Tabulated1D use error use hdf5_interface - use list_header, only: ListInt use math, only: faddeeva, w_derivative, & broaden_wmp_polynomials use multipole_header, only: FORM_RM, FORM_MLBW, MP_EA, RM_RT, RM_RA, & diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 8fe5e2da1f..806bcc65e8 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -72,9 +72,6 @@ module simulation_header logical :: trace - ! Number of distribcell maps - integer :: n_maps - !$omp threadprivate(trace, thread_id, current_work) contains From 53e6a8d766cf91fa4d7ccbcd7b25d2f73bde7525 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 21 May 2018 19:36:07 -0400 Subject: [PATCH 33/41] Move maximum_levels to C++ --- src/geometry.F90 | 69 -------------------------------------------- src/geometry_aux.cpp | 26 +++++++++++++++++ src/geometry_aux.h | 9 ++++++ src/input_xml.F90 | 10 +++++-- 4 files changed, 43 insertions(+), 71 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index c3b647a822..7fdd03ad8b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -534,73 +534,4 @@ contains end subroutine neighbor_lists -!=============================================================================== -! MAXIMUM_LEVELS determines the maximum number of nested coordinate levels in -! the geometry -!=============================================================================== - - recursive function maximum_levels(univ) result(levels) - - type(Universe), intent(in) :: univ ! universe to search through - integer :: levels ! maximum number of levels for this universe - - integer :: i ! index over cells - integer :: nx, ny, nz ! lattice shape - integer :: j, k, m ! indices in lattice - integer :: levels_below ! max levels below this universe - type(Cell), pointer :: c ! pointer to current cell - type(Universe), pointer :: next_univ ! next universe to loop through - class(Lattice), pointer :: lat ! pointer to current lattice - - levels_below = 0 - do i = 1, size(univ % cells) - c => cells(univ % cells(i)) - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - if (c % type() == FILL_UNIVERSE) then - - next_univ => universes(c % fill) - levels_below = max(levels_below, maximum_levels(next_univ)) - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_LATTICE) then - - ! Set current lattice - lat => lattices(c % fill) % obj - - select type (lat) - - type is (RectLattice) - nx = lat % n_cells(1) - ny = lat % n_cells(2) - nz = lat % n_cells(3) - - type is (HexLattice) - nx = 2 * lat % n_rings - 1 - ny = 2 * lat % n_rings - 1 - nz = lat % n_axial - - end select - - ! Loop over lattice coordinates - do j = 1, nx - do k = 1, ny - do m = 1, nz - if (lat % are_valid_indices([j, k, m])) then - next_univ => universes(lat % get([j-1, k-1, m-1]) + 1) - levels_below = max(levels_below, maximum_levels(next_univ)) - end if - end do - end do - end do - - end if - end do - - levels = 1 + levels_below - - end function maximum_levels - end module geometry diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 0685542409..6efe1cf99e 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -1,5 +1,6 @@ #include "geometry_aux.h" +#include // for std::max #include #include @@ -197,4 +198,29 @@ fill_offset_tables(int32_t target_univ_id, int map) } } +//============================================================================== + +int +maximum_levels(int32_t univ) +{ + int levels_below {0}; + + for (int32_t cell_indx : universes_c[univ]->cells) { + Cell &c = *cells_c[cell_indx]; + if (c.type == FILL_UNIVERSE) { + int32_t next_univ = c.fill - 1; // TODO: off-by-one + levels_below = std::max(levels_below, maximum_levels(next_univ)); + } else if (c.type == FILL_LATTICE) { + Lattice &lat = *lattices_c[c.fill - 1]; //TODO: off-by-one + for (auto it = lat.begin(); it != lat.end(); ++it) { + int32_t next_univ = *it; + levels_below = std::max(levels_below, maximum_levels(next_univ)); + } + } + } + + ++levels_below; + return levels_below; +} + } // namespace openmc diff --git a/src/geometry_aux.h b/src/geometry_aux.h index 0a0500794b..877f51e4e0 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -62,5 +62,14 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id); extern "C" void fill_offset_tables(int32_t target_univ_id, int map); +//============================================================================== +//! Determine the maximum number of nested coordinate levels in the geometry. +//! @param univ The index of the universe to begin seraching from (probably the +//! root universe). +//! @return The number of coordinate levels. +//============================================================================== + +extern "C" int maximum_levels(int32_t univ); + } // namespace openmc #endif // GEOMETRY_AUX_H diff --git a/src/input_xml.F90 b/src/input_xml.F90 index b708974b86..d325928a66 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -11,7 +11,7 @@ module input_xml use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning, write_message, openmc_err_msg - use geometry, only: maximum_levels, neighbor_lists + use geometry, only: neighbor_lists use geometry_header use hdf5_interface use list_header, only: ListChar, ListInt, ListReal @@ -85,6 +85,12 @@ module input_xml import C_INT32_T integer(C_INT32_T) :: root end function find_root_universe + + function maximum_levels(univ) bind(C) result(n) + import C_INT32_T, C_INT + integer(C_INT32_T), intent(in), value :: univ + integer(C_INT) :: n + end function maximum_levels end interface contains @@ -169,7 +175,7 @@ contains ! Check to make sure there are not too many nested coordinate levels in the ! geometry since the coordinate list is statically allocated for performance ! reasons - if (maximum_levels(universes(root_universe)) > MAX_COORD) then + if (maximum_levels(root_universe - 1) > MAX_COORD) then call fatal_error("Too many nested coordinate levels in the geometry. & &Try increasing the maximum number of coordinate levels by & &providing the CMake -Dmaxcoord= option.") From 07ded4e7be55edc6bcdd5dcb9df8f2e5d79aad65 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 21 May 2018 21:25:22 -0400 Subject: [PATCH 34/41] Remove cell % fill from F90 --- src/cell.cpp | 19 +++++++++++++ src/constants.F90 | 1 + src/geometry.F90 | 6 ++--- src/geometry_aux.cpp | 20 +++++++------- src/geometry_header.F90 | 34 +++++++++++++++--------- src/input_xml.F90 | 33 +++-------------------- src/summary.F90 | 9 ++++--- src/tallies/tally_filter_distribcell.F90 | 6 ++--- 8 files changed, 66 insertions(+), 62 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 1d630b3d4f..82138a83f7 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -234,6 +234,21 @@ Cell::Cell(pugi::xml_node cell_node) material.shrink_to_fit(); } + // Make sure that either material or fill was specified. + if ((material[0] == C_NONE) && (fill == C_NONE)) { + std::stringstream err_msg; + err_msg << "Neither material nor fill was specified for cell " << id; + fatal_error(err_msg); + } + + // Make sure that material and fill haven't been specified simultaneously. + if ((material[0] != C_NONE) && (fill != C_NONE)) { + std::stringstream err_msg; + err_msg << "Cell " << id << " has both a material and a fill specified; " + << "only one can be specified per cell"; + fatal_error(err_msg); + } + std::string region_spec {""}; if (check_for_node(cell_node, "region")) { region_spec = get_node_value(cell_node, "region"); @@ -470,6 +485,10 @@ extern "C" { void cell_set_universe(Cell *c, int32_t universe) {c->universe = universe;} + int32_t cell_fill(Cell *c) {return c->fill;} + + int32_t* cell_fill_ptr(Cell *c) {return &c->fill;} + int32_t cell_n_instances(Cell *c) {return c->n_instances;} bool cell_simple(Cell *c) {return c->simple;} diff --git a/src/constants.F90 b/src/constants.F90 index dbd4181dae..d75ee4e54a 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -421,6 +421,7 @@ module constants ! indicates that an array index hasn't been set integer, parameter :: NONE = 0 + integer, parameter :: C_NONE = -1 ! Codes for read errors -- better hope these numbers are never used in an ! input file! diff --git a/src/geometry.F90 b/src/geometry.F90 index 7fdd03ad8b..44f138e104 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -222,7 +222,7 @@ contains ! Move particle to next level and set universe j = j + 1 p % n_coord = j - p % coord(j) % universe = c % fill + p % coord(j) % universe = c % fill() + 1 ! Apply translation if (allocated(c % translation)) then @@ -243,7 +243,7 @@ contains ! ====================================================================== ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - associate (lat => lattices(c % fill) % obj) + associate (lat => lattices(c % fill() + 1) % obj) ! Determine lattice indices i_xyz = lat % get_indices(p % coord(j) % xyz + TINY_BIT * p % coord(j) % uvw) @@ -252,7 +252,7 @@ contains p % coord(j + 1) % uvw = p % coord(j) % uvw ! set particle lattice indices - p % coord(j + 1) % lattice = c % fill + p % coord(j + 1) % lattice = c % fill() + 1 p % coord(j + 1) % lattice_x = i_xyz(1) p % coord(j + 1) % lattice_y = i_xyz(2) p % coord(j + 1) % lattice_z = i_xyz(3) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 6efe1cf99e..2bf379a6d4 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -27,10 +27,10 @@ adjust_indices_c() auto search_lat = lattice_dict.find(id); if (search_univ != universe_dict.end()) { c->type = FILL_UNIVERSE; - c->fill = search_univ->second + 1; //TODO: off-by-one + c->fill = search_univ->second; } else if (search_lat != lattice_dict.end()) { c->type = FILL_LATTICE; - c->fill = search_lat->second + 1; //TODO: off-by-one + c->fill = search_lat->second; } else { std::stringstream err_msg; err_msg << "Specified fill " << id << " on cell " << c->id @@ -133,11 +133,11 @@ count_cell_instances(int32_t univ_indx) if (c.type == FILL_UNIVERSE) { // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill-1); // TODO: off-by-one + count_cell_instances(c.fill); } else if (c.type == FILL_LATTICE) { // This cell contains a lattice. Recurse into the lattice universes. - Lattice &lat = *lattices_c[c.fill-1]; // TODO: off-by-one + Lattice &lat = *lattices_c[c.fill]; for (auto it = lat.begin(); it != lat.end(); ++it) { count_cell_instances(*it); } @@ -160,11 +160,11 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id) Cell &c = *cells_c[cell_indx]; if (c.type == FILL_UNIVERSE) { - int32_t next_univ = c.fill - 1; // TODO: off-by-one + int32_t next_univ = c.fill; count += count_universe_instances(next_univ, target_univ_id); } else if (c.type == FILL_LATTICE) { - Lattice &lat = *lattices_c[c.fill - 1]; //TODO: off-by-one + Lattice &lat = *lattices_c[c.fill]; for (auto it = lat.begin(); it != lat.end(); ++it) { int32_t next_univ = *it; count += count_universe_instances(next_univ, target_univ_id); @@ -187,11 +187,11 @@ fill_offset_tables(int32_t target_univ_id, int map) if (c.type == FILL_UNIVERSE) { c.offset[map] = offset; - int32_t search_univ = c.fill - 1; // TODO: off-by-one + int32_t search_univ = c.fill; offset += count_universe_instances(search_univ, target_univ_id); } else if (c.type == FILL_LATTICE) { - Lattice &lat = *lattices_c[c.fill - 1]; // TODO: off-by-one + Lattice &lat = *lattices_c[c.fill]; offset = lat.fill_offset_table(offset, target_univ_id, map); } } @@ -208,10 +208,10 @@ maximum_levels(int32_t univ) for (int32_t cell_indx : universes_c[univ]->cells) { Cell &c = *cells_c[cell_indx]; if (c.type == FILL_UNIVERSE) { - int32_t next_univ = c.fill - 1; // TODO: off-by-one + int32_t next_univ = c.fill; levels_below = std::max(levels_below, maximum_levels(next_univ)); } else if (c.type == FILL_LATTICE) { - Lattice &lat = *lattices_c[c.fill - 1]; //TODO: off-by-one + Lattice &lat = *lattices_c[c.fill]; for (auto it = lat.begin(); it != lat.end(); ++it) { int32_t next_univ = *it; levels_below = std::max(levels_below, maximum_levels(next_univ)); diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index fc70a8eeca..d019e8fce6 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -18,35 +18,30 @@ module geometry_header interface function cell_pointer_c(cell_ind) bind(C, name='cell_pointer') result(ptr) import C_PTR, C_INT32_T - implicit none integer(C_INT32_T), intent(in), value :: cell_ind type(C_PTR) :: ptr end function cell_pointer_c function cell_id_c(cell_ptr) bind(C, name='cell_id') result(id) import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T) :: id end function cell_id_c subroutine cell_set_id_c(cell_ptr, id) bind(C, name='cell_set_id') import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T), intent(in), value :: id end subroutine cell_set_id_c function cell_type_c(cell_ptr) bind(C, name='cell_type') result(type) import C_PTR, C_INT - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT) :: type end function cell_type_c subroutine cell_set_type_c(cell_ptr, type) bind(C, name='cell_set_type') import C_PTR, C_INT - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT), intent(in), value :: type end subroutine cell_set_type_c @@ -54,7 +49,6 @@ module geometry_header function cell_universe_c(cell_ptr) bind(C, name='cell_universe') & result(universe) import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T) :: universe end function cell_universe_c @@ -62,22 +56,31 @@ module geometry_header subroutine cell_set_universe_c(cell_ptr, universe) & bind(C, name='cell_set_universe') import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T), intent(in), value :: universe end subroutine cell_set_universe_c + function cell_fill_c(cell_ptr) bind(C, name="cell_fill") result(fill) + import C_PTR, C_INT32_T + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT32_T) :: fill + end function cell_fill_c + + function cell_fill_ptr(cell_ptr) bind(C) result(fill_ptr) + import C_PTR + type(C_PTR), intent(in), value :: cell_ptr + type(C_PTR) :: fill_ptr + end function cell_fill_ptr + function cell_n_instances_c(cell_ptr) bind(C, name='cell_n_instances') & result(n_instances) import C_PTR, C_INT32_T - implicit none type(C_PTR), intent(in), value :: cell_ptr integer(C_INT32_T) :: n_instances end function cell_n_instances_c function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple) import C_PTR, C_BOOL - implicit none type(C_PTR), intent(in), value :: cell_ptr logical(C_BOOL) :: simple end function cell_simple_c @@ -85,7 +88,6 @@ module geometry_header subroutine cell_distance_c(cell_ptr, xyz, uvw, on_surface, min_dist, & i_surf) bind(C, name="cell_distance") import C_PTR, C_INT32_T, C_DOUBLE - implicit none type(C_PTR), intent(in), value :: cell_ptr real(C_DOUBLE), intent(in) :: xyz(3) real(C_DOUBLE), intent(in) :: uvw(3) @@ -259,7 +261,6 @@ module geometry_header type Cell type(C_PTR) :: ptr - integer :: fill ! universe # filling this cell integer, allocatable :: material(:) ! Material within cell. Multiple ! materials for distribcell ! instances. 0 signifies a universe @@ -284,6 +285,7 @@ module geometry_header procedure :: set_type => cell_set_type procedure :: universe => cell_universe procedure :: set_universe => cell_set_universe + procedure :: fill => cell_fill procedure :: n_instances => cell_n_instances procedure :: simple => cell_simple procedure :: distance => cell_distance @@ -414,6 +416,12 @@ contains call cell_set_universe_c(this % ptr, universe) end subroutine cell_set_universe + function cell_fill(this) result(fill) + class(Cell), intent(in) :: this + integer(C_INT32_T) :: fill + fill = cell_fill_c(this % ptr) + end function cell_fill + function cell_n_instances(this) result(n_instances) class(Cell), intent(in) :: this integer(C_INT32_T) :: n_instances @@ -611,7 +619,7 @@ contains indices = C_LOC(c % material(1)) case (FILL_UNIVERSE, FILL_LATTICE) n = 1 - indices = C_LOC(c % fill) + indices = cell_fill_ptr(c % ptr) end select end associate else @@ -723,7 +731,7 @@ contains if (index >= 1 .and. index <= size(cells)) then ! error if the cell is filled with another universe - if (cells(index) % fill /= NONE) then + if (cells(index) % fill() /= C_NONE) then err = E_GEOMETRY call set_errmsg("Cannot set temperature on a cell filled & &with a universe.") diff --git a/src/input_xml.F90 b/src/input_xml.F90 index d325928a66..501a43a57d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1056,12 +1056,6 @@ contains ! Get pointer to i-th cell node node_cell = node_cell_list(i) - if (check_for_node(node_cell, "fill")) then - call get_node_value(node_cell, "fill", c % fill) - else - c % fill = NONE - end if - ! Check to make sure 'id' hasn't been used if (cell_dict % has(c % id())) then call fatal_error("Two or more cells use the same unique ID: " & @@ -1104,18 +1098,6 @@ contains c % material(1) = NONE end if - ! Check to make sure that either material or fill was specified - if (c % material(1) == NONE .and. c % fill == NONE) then - call fatal_error("Neither material nor fill was specified for cell " & - // trim(to_str(c % id()))) - end if - - ! Check to make sure that both material and fill haven't been - ! specified simultaneously - if (c % material(1) /= NONE .and. c % fill /= NONE) then - call fatal_error("Cannot specify material and fill simultaneously") - end if - ! Check for region specification (also under deprecated name surfaces) if (check_for_node(node_cell, "surfaces")) then call warning("The use of 'surfaces' is deprecated and will be & @@ -1157,7 +1139,7 @@ contains if (check_for_node(node_cell, "rotation")) then ! Rotations can only be applied to cells that are being filled with ! another universe - if (c % fill == NONE) then + if (c % fill() == C_NONE) then call fatal_error("Cannot apply a rotation to cell " // trim(to_str(& &c % id())) // " because it is not filled with another universe") end if @@ -1192,7 +1174,7 @@ contains if (check_for_node(node_cell, "translation")) then ! Translations can only be applied to cells that are being filled with ! another universe - if (c % fill == NONE) then + if (c % fill() == C_NONE) then call fatal_error("Cannot apply a translation to cell " & // trim(to_str(c % id())) // " because it is not filled with & &another universe") @@ -3800,7 +3782,6 @@ contains integer :: i ! index for various purposes integer :: j ! index for various purposes - integer :: lid ! lattice IDs integer :: id ! user-specified id call adjust_indices_c() @@ -3811,15 +3792,7 @@ contains ! ======================================================================= ! ADJUST MATERIAL/FILL POINTERS FOR EACH CELL - if (c % material(1) == NONE) then - id = c % fill - if (universe_dict % has(id)) then - c % fill = universe_dict % get(id) - elseif (lattice_dict % has(id)) then - lid = lattice_dict % get(id) - c % fill = lid - end if - else + if (c % material(1) /= NONE) then do j = 1, size(c % material) id = c % material(j) if (id == MATERIAL_VOID) then diff --git a/src/summary.F90 b/src/summary.F90 index 1d33491230..3b01ddfc9d 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -160,7 +160,7 @@ contains subroutine write_geometry(file_id) integer(HID_T), intent(in) :: file_id - integer :: i, j + integer :: i, j, cell_fill integer, allocatable :: cell_materials(:) integer, allocatable :: cell_ids(:) real(8), allocatable :: cell_temperatures(:) @@ -225,7 +225,7 @@ contains case (FILL_UNIVERSE) call write_dataset(cell_group, "fill_type", "universe") - call write_dataset(cell_group, "fill", universes(c%fill)%id) + call write_dataset(cell_group, "fill", universes(c%fill()+1)%id) if (allocated(c%translation)) then call write_dataset(cell_group, "translation", c%translation) @@ -236,7 +236,10 @@ contains case (FILL_LATTICE) call write_dataset(cell_group, "fill_type", "lattice") - call write_dataset(cell_group, "lattice", lattices(c%fill)%obj%id()) + ! Do not access the 'lattices' array with 'c % fill() + 1' directly; it + ! causes a segfault in GCC 7.3.0 + cell_fill = c % fill() + 1 + call write_dataset(cell_group, "lattice", lattices(cell_fill)%obj%id()) end select call close_group(cell_group) diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index ce2549f58a..fa0a6b2963 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -215,7 +215,7 @@ contains ! Get the offset of the first lattice location else - lat => lattices(c % fill) % obj + lat => lattices(c % fill() + 1) % obj temp_offset = lat % offset(map-1, [0, 0, 0]) end if @@ -250,7 +250,7 @@ contains ! Enter this cell to update the current offset offset = c % offset(map-1) + offset - next_univ => universes(c % fill) + next_univ => universes(c % fill() + 1) call find_offset(i_cell, next_univ, target_offset, offset, path) return @@ -259,7 +259,7 @@ contains elseif (c % type() == FILL_LATTICE) then ! Set current lattice - lat => lattices(c % fill) % obj + lat => lattices(c % fill() + 1) % obj select type (lat) From 9bf2eaa42e559e57cbb82e02384920fec3134d67 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Thu, 24 May 2018 12:53:09 -0400 Subject: [PATCH 35/41] Simplify distribcell find_offset logic --- src/tallies/tally_filter_distribcell.F90 | 328 +++++++---------------- 1 file changed, 98 insertions(+), 230 deletions(-) diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index fa0a6b2963..e121cae5e7 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -139,17 +139,11 @@ contains character(*), intent(inout) :: path ! Path to offset integer :: map ! Index in maps vector - integer :: i, j ! Index over cells + integer :: i ! Index over cells integer :: k, l, m ! Indices in lattice - integer :: old_k, old_l, old_m ! Previous indices in lattice integer :: n_x, n_y, n_z ! Lattice cell array dimensions - integer :: n ! Number of cells to search - integer :: cell_index ! Index in cells array - integer :: lat_offset ! Offset from lattice integer :: temp_offset ! Looped sum of offsets integer :: i_univ ! index in universes array - logical :: this_cell = .false. ! Advance in this cell? - logical :: later_cell = .false. ! Fill cells after this one? type(Cell), pointer :: c ! Pointer to current cell type(Universe), pointer :: next_univ ! Next universe to loop through class(Lattice), pointer :: lat ! Pointer to current lattice @@ -157,8 +151,6 @@ contains ! Get the distribcell index for this cell map = cells(i_cell) % distribcell_index - n = size(univ % cells) - ! Write to the geometry stack i_univ = universe_dict % get(univ % id) if (i_univ == root_universe) then @@ -168,7 +160,7 @@ contains end if ! Look through all cells in this universe - do i = 1, n + do i = 1, size(univ % cells) ! If the cell matches the goal and the offset matches final, write to the ! geometry stack if (univ % cells(i) == i_cell .and. offset == target_offset) then @@ -178,234 +170,110 @@ contains end if end do - ! Find the fill cell or lattice cell that we need to enter - do i = 1, n - - later_cell = .false. - + ! Find the fill cell or lattice cell that contains the target offset. + do i = size(univ % cells), 2, -1 c => cells(univ % cells(i)) - this_cell = .false. + ! Material cells don't contain other cells so ignore them. + if (c % type() /= FILL_MATERIAL) then - ! If we got here, we still think the target is in this universe - ! or further down, but it's not this exact cell. - ! Compare offset to next cell to see if we should enter this cell - if (i /= n) then - - do j = i+1, n - - c => cells(univ % cells(j)) - - ! Skip normal cells which do not have offsets - if (c % type() == FILL_MATERIAL) cycle - - ! Break loop once we've found the next cell with an offset - exit - end do - - ! Ensure we didn't just end the loop by iteration - if (c % type() /= FILL_MATERIAL) then - - ! There are more cells in this universe that it could be in - later_cell = .true. - - ! Two cases, lattice or fill cell - if (c % type() == FILL_UNIVERSE) then - temp_offset = c % offset(map-1) - - ! Get the offset of the first lattice location - else - lat => lattices(c % fill() + 1) % obj - temp_offset = lat % offset(map-1, [0, 0, 0]) - end if - - ! If the final offset is in the range of offset - temp_offset+offset - ! then the goal is in this cell - if (target_offset < temp_offset + offset) then - this_cell = .true. - end if - end if - end if - - if (n == 1 .and. c % type() /= FILL_MATERIAL) then - this_cell = .true. - end if - - if (.not. later_cell) then - this_cell = .true. - end if - - ! Get pointer to THIS cell because target must be in this cell - if (this_cell) then - - cell_index = univ % cells(i) - c => cells(cell_index) - - path = trim(path) // "->c" // to_str(c%id()) - - ! ==================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL if (c % type() == FILL_UNIVERSE) then - - ! Enter this cell to update the current offset - offset = c % offset(map-1) + offset - - next_univ => universes(c % fill() + 1) - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - - ! ==================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - elseif (c % type() == FILL_LATTICE) then - - ! Set current lattice + temp_offset = offset + c % offset(map-1) + else + ! Get the offset of the first lattice location lat => lattices(c % fill() + 1) % obj - - select type (lat) - - ! ================================================================== - ! RECTANGULAR LATTICES - type is (RectLattice) - - ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id()) - - n_x = lat % n_cells(1) - n_y = lat % n_cells(2) - n_z = lat % n_cells(3) - old_m = 1 - old_l = 1 - old_k = 1 - - ! Loop over lattice coordinates - do m = 1, n_z - do l = 1, n_y - do k = 1, n_x - - if (target_offset >= lat % offset(map-1, [k-1, l-1, m-1]) & - + offset) then - if (k == n_x .and. l == n_y .and. m == n_z) then - ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map-1, [k-1, l-1, m-1]) - offset = offset + lat_offset - next_univ => universes(lat % get([k-1, l-1, m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // "," // & - trim(to_str(m-1)) // ")" - else - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - else - old_m = m - old_l = l - old_k = k - cycle - end if - else - ! Target is at this lattice position - lat_offset = lat % offset(map-1, [old_k-1, old_l-1, old_m-1]) - offset = offset + lat_offset - next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // trim(to_str(old_k-1)) // & - "," // trim(to_str(old_l-1)) // "," // & - trim(to_str(old_m-1)) // ")" - else - path = trim(path) // "(" // trim(to_str(old_k-1)) // & - "," // trim(to_str(old_l-1)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - - end do - end do - end do - - ! ================================================================== - ! HEXAGONAL LATTICES - type is (HexLattice) - - ! Write to the geometry stack - path = trim(path) // "->l" // to_str(lat%id()) - - n_z = lat % n_axial - n_y = 2 * lat % n_rings - 1 - n_x = 2 * lat % n_rings - 1 - old_m = 1 - old_l = 1 - old_k = 1 - - ! Loop over lattice coordinates - do m = 1, n_z - do l = 1, n_y - do k = 1, n_x - - ! This array position is never used - if (k + l < lat % n_rings + 1) then - cycle - ! This array position is never used - else if (k + l > 3*lat % n_rings - 1) then - cycle - end if - - if (target_offset >= lat % offset(map-1, [k-1, l-1, m-1]) & - + offset) then - if (k == lat % n_rings .and. l == n_y .and. m == n_z) then - ! This is last lattice cell, so target must be here - lat_offset = lat % offset(map-1, [k-1, l-1, m-1]) - offset = offset + lat_offset - next_univ => universes(lat % get([k-1, l-1, m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // "," // & - trim(to_str(m - 1)) // ")" - else - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - else - old_m = m - old_l = l - old_k = k - cycle - end if - else - ! Target is at this lattice position - lat_offset = lat % offset(map-1, [old_k-1, old_l-1, old_m-1]) - offset = offset + lat_offset - next_univ => universes(lat % get([old_k-1, old_l-1, old_m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // & - trim(to_str(old_k - lat % n_rings)) // "," // & - trim(to_str(old_l - lat % n_rings)) // "," // & - trim(to_str(old_m - 1)) // ")" - else - path = trim(path) // "(" // & - trim(to_str(old_k - lat % n_rings)) // "," // & - trim(to_str(old_l - lat % n_rings)) // ")" - end if - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - - end do - end do - end do - - end select - + temp_offset = offset + lat % offset(map-1, [0, 0, 0]) end if + + ! The desired cell is the first cell that gives an offset smaller or + ! equal to the target offset. + if (temp_offset <= target_offset) exit end if end do + + ! Add the cell to the path string. + c => cells(univ % cells(i)) + path = trim(path) // "->c" // to_str(c%id()) + + if (c % type() == FILL_UNIVERSE) then + ! Recurse into the fill cell. + offset = c % offset(map-1) + offset + next_univ => universes(c % fill() + 1) + call find_offset(i_cell, next_univ, target_offset, offset, path) + + elseif (c % type() == FILL_LATTICE) then + ! Recurse into the lattice cell. + lat => lattices(c % fill() + 1) % obj + select type (lat) + + type is (RectLattice) + path = trim(path) // "->l" // to_str(lat%id()) + + n_x = lat % n_cells(1) + n_y = lat % n_cells(2) + n_z = lat % n_cells(3) + + do m = n_z, 1, -1 + do l = n_y, 1, -1 + do k = n_x, 1, -1 + temp_offset = offset + lat % offset(map-1, [k-1, l-1, m-1]) + if (temp_offset <= target_offset) then + next_univ => universes(lat % get([k-1, l-1, m-1])+1) + if (lat % is_3d) then + path = trim(path) // "(" // trim(to_str(k-1)) // & + "," // trim(to_str(l-1)) // "," // & + trim(to_str(m-1)) // ")" + else + path = trim(path) // "(" // trim(to_str(k-1)) // & + "," // trim(to_str(l-1)) // ")" + end if + offset = temp_offset + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + end if + end do + end do + end do + + type is (HexLattice) + path = trim(path) // "->l" // to_str(lat%id()) + + n_z = lat % n_axial + n_y = 2 * lat % n_rings - 1 + n_x = 2 * lat % n_rings - 1 + + do m = n_z, 1, -1 + do l = n_y, 1, -1 + do k = n_x, 1, -1 + if (k + l < lat % n_rings + 1) then + cycle + else if (k + l > 3*lat % n_rings - 1) then + cycle + end if + temp_offset = offset + lat % offset(map-1, [k-1, l-1, m-1]) + if (temp_offset <= target_offset) then + next_univ => universes(lat % get([k-1, l-1, m-1])+1) + if (lat % is_3d) then + path = trim(path) // "(" // & + trim(to_str(k - lat % n_rings)) // "," // & + trim(to_str(l - lat % n_rings)) // "," // & + trim(to_str(m - 1)) // ")" + else + path = trim(path) // "(" // & + trim(to_str(k - lat % n_rings)) // "," // & + trim(to_str(l - lat % n_rings)) // ")" + end if + offset = temp_offset + call find_offset(i_cell, next_univ, target_offset, offset, path) + return + end if + end do + end do + end do + + end select + + end if end subroutine find_offset end module tally_filter_distribcell From af4525a1ebf3058172739e81c739089e2d40be43 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 25 May 2018 20:32:17 -0400 Subject: [PATCH 36/41] Move find_offset (distribcell) to C++ --- src/geometry_aux.cpp | 97 +++++++++++++ src/geometry_aux.h | 31 ++++ src/geometry_header.F90 | 7 - src/input_xml.F90 | 29 +--- src/lattice.cpp | 72 +++++++++- src/lattice.h | 54 ++++++- src/summary.F90 | 1 - src/tallies/tally_filter_distribcell.F90 | 175 +++++------------------ 8 files changed, 276 insertions(+), 190 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 2bf379a6d4..a51e5b8a80 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -200,6 +200,103 @@ fill_offset_tables(int32_t target_univ_id, int map) //============================================================================== +std::string +distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, + const Universe &search_univ, int32_t offset) +{ + std::stringstream path; + + path << "u" << search_univ.id << "->"; + + // Check to see if this universe directly contains the target cell. If so, + // write to the path and return. + for (int32_t cell_indx : search_univ.cells) { + if ((cell_indx == target_cell) && (offset == target_offset)) { + Cell &c = *cells_c[cell_indx]; + path << "c" << c.id; + return path.str(); + } + } + + // The target must be further down the geometry tree and contained in a fill + // cell or lattice cell in this universe. Find which cell contains the + // target. + auto cell_it {search_univ.cells.rbegin()}; + for (; cell_it != search_univ.cells.rend(); ++cell_it) { + Cell &c = *cells_c[*cell_it]; + + // Material cells don't contain other cells so ignore them. + if (c.type != FILL_MATERIAL) { + int32_t temp_offset; + if (c.type == FILL_UNIVERSE) { + temp_offset = offset + c.offset[map]; + } else { + Lattice &lat = *lattices_c[c.fill]; + int32_t indx = lat.universes.size()*map + lat.begin().indx; + temp_offset = offset + lat.offsets[indx]; + } + + // The desired cell is the first cell that gives an offset smaller or + // equal to the target offset. + if (temp_offset <= target_offset) break; + } + } + + // Add the cell to the path string. + Cell &c = *cells_c[*cell_it]; + path << "c" << c.id << "->"; + + if (c.type == FILL_UNIVERSE) { + // Recurse into the fill cell. + offset += c.offset[map]; + path << distribcell_path_inner(target_cell, map, target_offset, + *universes_c[c.fill], offset); + return path.str(); + } else { + // Recurse into the lattice cell. + Lattice &lat = *lattices_c[c.fill]; + path << "l" << lat.id; + for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) { + int32_t indx = lat.universes.size()*map + it.indx; + int32_t temp_offset = offset + lat.offsets[indx]; + if (temp_offset <= target_offset) { + offset = temp_offset; + path << "(" << lat.index_to_string(it.indx) << ")->"; + path << distribcell_path_inner(target_cell, map, target_offset, + *universes_c[*it], offset); + return path.str(); + } + } + } +} + +//============================================================================== + +int +distribcell_path_len(int32_t target_cell, int32_t map, int32_t target_offset, + int32_t root_univ) +{ + Universe &root = *universes_c[root_univ]; + std::string path_ {distribcell_path_inner(target_cell, map, target_offset, + root, 0)}; + return path_.size() + 1; +} + +//============================================================================== + +void +distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset, + int32_t root_univ, char *path) +{ + Universe &root = *universes_c[root_univ]; + std::string path_ {distribcell_path_inner(target_cell, map, target_offset, + root, 0)}; + path_.copy(path, path_.size()); + path[path_.size()] = '\0'; +} + +//============================================================================== + int maximum_levels(int32_t univ) { diff --git a/src/geometry_aux.h b/src/geometry_aux.h index 877f51e4e0..7d2c3cd9af 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -62,6 +62,37 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id); extern "C" void fill_offset_tables(int32_t target_univ_id, int map); +//============================================================================== +//! Find the length necessary for a string to contain a distribcell path. +//! @param target_cell The index of the Cell in the global Cell array. +//! @param map The index of the distribcell mapping corresponding to the target +//! cell. +//! @param target_offset An instance number for a distributed cell. +//! @param root_univ The index of the root Universe in the global Universe +//! array. +//! @return The size of a character array needed to fit the distribcell path. +//============================================================================== + +extern "C" int +distribcell_path_len(int32_t target_cell, int32_t map, int32_t target_offset, + int32_t root_univ); + +//============================================================================== +//! Build a character array representing the path to a distribcell instance. +//! @param target_cell The index of the Cell in the global Cell array. +//! @param map The index of the distribcell mapping corresponding to the target +//! cell. +//! @param target_offset An instance number for a distributed cell. +//! @param root_univ The index of the root Universe in the global Universe +//! array. +//! @param[out] path The unique traversal through the geometry tree that leads +//! to the desired instance of the target cell. +//============================================================================== + +extern "C" void +distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset, + int32_t root_univ, char *path); + //============================================================================== //! Determine the maximum number of nested coordinate levels in the geometry. //! @param univ The index of the universe to begin seraching from (probably the diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index d019e8fce6..8f95c4a7d1 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -201,7 +201,6 @@ module geometry_header type Universe integer :: id ! Unique ID - integer :: type ! Type integer, allocatable :: cells(:) ! List of cells within real(8) :: x0 ! Translation in x-coordinate real(8) :: y0 ! Translation in y-coordinate @@ -214,10 +213,7 @@ module geometry_header type, abstract :: Lattice type(C_PTR) :: ptr - - logical :: is_3d ! Lattice has cells on z axis contains - procedure :: id => lattice_id procedure :: are_valid_indices => lattice_are_valid_indices procedure :: distance => lattice_distance @@ -234,7 +230,6 @@ module geometry_header !=============================================================================== type, extends(Lattice) :: RectLattice - integer :: n_cells(3) ! Number of cells along each axis end type RectLattice !=============================================================================== @@ -242,8 +237,6 @@ module geometry_header !=============================================================================== type, extends(Lattice) :: HexLattice - integer :: n_rings ! Number of radial ring cell positoins - integer :: n_axial ! Number of axial cell positions end type HexLattice !=============================================================================== diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 501a43a57d..96cb2f7548 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -952,7 +952,7 @@ contains subroutine read_geometry_xml() integer :: i, j, k - integer :: n, n_mats, n_z, n_rings, n_rlats, n_hlats + integer :: n, n_mats, n_rlats, n_hlats integer :: id integer :: univ_id integer :: n_cells_in_univ @@ -1270,19 +1270,6 @@ contains ! Get pointer to i-th lattice node_lat = node_rlat_list(i) - ! Read number of lattice cells in each dimension - n = node_word_count(node_lat, "dimension") - if (n == 2) then - call get_node_array(node_lat, "dimension", lat % n_cells(1:2)) - lat % n_cells(3) = 1 - lat % is_3d = .false. - else if (n == 3) then - call get_node_array(node_lat, "dimension", lat % n_cells) - lat % is_3d = .true. - else - call fatal_error("Rectangular lattice must be two or three dimensions.") - end if - ! Add lattice to dictionary call lattice_dict % set(lat % id(), i) @@ -1299,20 +1286,6 @@ contains ! Get pointer to i-th lattice node_lat = node_hlat_list(i) - ! Read number of lattice cells in each dimension - call get_node_value(node_lat, "n_rings", lat % n_rings) - if (check_for_node(node_lat, "n_axial")) then - call get_node_value(node_lat, "n_axial", lat % n_axial) - lat % is_3d = .true. - else - lat % n_axial = 1 - lat % is_3d = .false. - end if - - ! Copy number of dimensions - n_rings = lat % n_rings - n_z = lat % n_axial - ! Add lattice to dictionary call lattice_dict % set(lat % id(), n_rlats + i) diff --git a/src/lattice.cpp b/src/lattice.cpp index 7bb5fb6bb7..f5d0ba272d 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -21,10 +21,6 @@ namespace openmc { // Global variables //============================================================================== -// Braces force n_lattices to be defined here, not just declared. -//extern "C" {int32_t n_lattices {0};} - -//Lattice **lattices_c; std::vector lattices_c; std::map lattice_dict; @@ -66,6 +62,20 @@ Lattice::end() //============================================================================== +ReverseLatticeIter +Lattice::rbegin() +{ + return ReverseLatticeIter(*this, universes.size()-1); +} + +ReverseLatticeIter +Lattice::rend() +{ + return ReverseLatticeIter(*this, -1); +} + +//============================================================================== + void Lattice::adjust_indices() { @@ -348,6 +358,26 @@ RectLattice::offset(int map, const int i_xyz[3]) //============================================================================== +std::string +RectLattice::index_to_string(int indx) const +{ + int nx {n_cells[0]}; + int ny {n_cells[1]}; + int iz {indx / (nx * ny)}; + int iy {(indx - nx * ny * iz) / nx}; + int ix {indx - nx * ny * iz - nx * iy}; + std::string out {std::to_string(ix)}; + out += ','; + out += std::to_string(iy); + if (is_3d) { + out += ','; + out += std::to_string(iz); + } + return out; +} + +//============================================================================== + void RectLattice::to_hdf5_inner(hid_t lat_group) const { @@ -577,6 +607,14 @@ HexLattice::begin() //============================================================================== +ReverseLatticeIter +HexLattice::rbegin() +{ + return ReverseLatticeIter(*this, universes.size()-n_rings); +} + +//============================================================================== + bool HexLattice::are_valid_indices(const int i_xyz[3]) const { @@ -798,14 +836,34 @@ HexLattice::is_valid_index(int indx) const int32_t& HexLattice::offset(int map, const int i_xyz[3]) { - int nx = 2*n_rings - 1; - int ny = 2*n_rings - 1; - int nz = n_axial; + int nx {2*n_rings - 1}; + int ny {2*n_rings - 1}; + int nz {n_axial}; return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; } //============================================================================== +std::string +HexLattice::index_to_string(int indx) const +{ + int nx {2*n_rings - 1}; + int ny {2*n_rings - 1}; + int iz {indx / (nx * ny)}; + int iy {(indx - nx * ny * iz) / nx}; + int ix {indx - nx * ny * iz - nx * iy}; + std::string out {std::to_string(ix - n_rings + 1)}; + out += ','; + out += std::to_string(iy - n_rings + 1); + if (is_3d) { + out += ','; + out += std::to_string(iz); + } + return out; +} + +//============================================================================== + void HexLattice::to_hdf5_inner(hid_t lat_group) const { diff --git a/src/lattice.h b/src/lattice.h index 9b55025b58..3161a24739 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -33,11 +33,13 @@ extern std::vector lattices_c; extern std::map lattice_dict; //============================================================================== -//! Abstract type for ordered array of universes +//! Abstract type for ordered array of universes. //============================================================================== class LatticeIter; +class ReverseLatticeIter; + class Lattice { public: @@ -56,6 +58,9 @@ public: virtual LatticeIter begin(); LatticeIter end(); + virtual ReverseLatticeIter rbegin(); + ReverseLatticeIter rend(); + //! Convert internal universe values from IDs to indices using universe_dict. void adjust_indices(); @@ -98,7 +103,7 @@ public: //! otherwise. virtual bool is_valid_index(int indx) const { - return (indx > 0) && (indx < universes.size()); + return (indx >= 0) && (indx < universes.size()); } //! Get the distribcell offset for a lattice tile. @@ -108,6 +113,11 @@ public: //! cell found in the geometry tree under this lattice tile. virtual int32_t& offset(int map, const int i_xyz[3]) = 0; + //! Convert an array index to a useful human-readable string. + //! @param indx The index for a lattice tile. + //! @return A string representing the lattice tile. + virtual std::string index_to_string(int indx) const = 0; + //! Write all information needed to reconstruct the lattice to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; @@ -118,9 +128,16 @@ protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; }; +//============================================================================== +//! An iterator over lattice universes. +//============================================================================== + class LatticeIter { public: + + int indx; //!< An index to a Lattice universes or offsets array. + LatticeIter(Lattice &lat_, int indx_) : lat(lat_), indx(indx_) @@ -128,7 +145,7 @@ public: bool operator==(const LatticeIter &rhs) { - return (&lat == &rhs.lat) && (indx == rhs.indx); + return (indx == rhs.indx); } bool operator!=(const LatticeIter &rhs) @@ -151,11 +168,32 @@ public: return *this; } - int indx; -private: +protected: Lattice ⪫ }; +//============================================================================== +//! A reverse iterator over lattice universes. +//============================================================================== + +class ReverseLatticeIter : public LatticeIter +{ +public: + ReverseLatticeIter(Lattice &lat_, int indx_) + : LatticeIter {lat_, indx_} + {} + + ReverseLatticeIter& operator++() + { + while (indx > -1) { + --indx; + if (lat.is_valid_index(indx)) return *this; + } + indx = -1; + return *this; + } +}; + //============================================================================== //============================================================================== @@ -180,6 +218,8 @@ public: int32_t& offset(int map, const int i_xyz[3]); + std::string index_to_string(int indx) const; + void to_hdf5_inner(hid_t group_id) const; protected: @@ -202,6 +242,8 @@ public: LatticeIter begin(); + ReverseLatticeIter rbegin(); + bool are_valid_indices(const int i_xyz[3]) const; std::pair> @@ -216,6 +258,8 @@ public: int32_t& offset(int map, const int i_xyz[3]); + std::string index_to_string(int indx) const; + void to_hdf5_inner(hid_t group_id) const; protected: diff --git a/src/summary.F90 b/src/summary.F90 index 3b01ddfc9d..464c0c6cfa 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -15,7 +15,6 @@ module summary use surface_header use string, only: to_str use tally_header, only: TallyObject - use tally_filter_distribcell, only: find_offset implicit none private diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index e121cae5e7..d6643190cd 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -14,7 +14,6 @@ module tally_filter_distribcell implicit none private - public :: find_offset !=============================================================================== ! DISTRIBCELLFILTER specifies which distributed geometric cells tally events @@ -114,13 +113,8 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - integer :: offset - type(Universe), pointer :: univ - - univ => universes(root_universe) - offset = 0 label = '' - call find_offset(this % cell, univ, bin-1, offset, label) + call find_offset(this % cell, bin-1, label) label = "Distributed Cell " // label end function text_label_distribcell @@ -130,150 +124,47 @@ contains ! the target cell with the given offset !=============================================================================== - recursive subroutine find_offset(i_cell, univ, target_offset, offset, path) - + subroutine find_offset(i_cell, target_offset, path) integer, intent(in) :: i_cell ! The target cell index - type(Universe), intent(in) :: univ ! Universe to begin search - integer, intent(in) :: target_offset ! Target offset - integer, intent(inout) :: offset ! Current offset - character(*), intent(inout) :: path ! Path to offset + integer, intent(in) :: target_offset ! Target offset + character(*), intent(inout) :: path ! Path to offset integer :: map ! Index in maps vector integer :: i ! Index over cells - integer :: k, l, m ! Indices in lattice - integer :: n_x, n_y, n_z ! Lattice cell array dimensions - integer :: temp_offset ! Looped sum of offsets - integer :: i_univ ! index in universes array - type(Cell), pointer :: c ! Pointer to current cell - type(Universe), pointer :: next_univ ! Next universe to loop through - class(Lattice), pointer :: lat ! Pointer to current lattice + + integer(C_INT) :: path_len + character(kind=C_CHAR), allocatable, target :: path_c(:) + + interface + function distribcell_path_len(target_cell, map, target_offset, root_univ)& + bind(C) result(len) + import C_INT32_T, C_INT + integer(C_INT32_T), intent(in), value :: target_cell, map, & + target_offset, root_univ + integer(C_INT) :: len + end function distribcell_path_len + + subroutine distribcell_path(target_cell, map, target_offset, root_univ, & + path) bind(C) + import C_INT32_T, C_CHAR + integer(C_INT32_T), intent(in), value :: target_cell, map, & + target_offset, root_univ + character(kind=C_CHAR), intent(out) :: path(*) + end subroutine distribcell_path + end interface ! Get the distribcell index for this cell map = cells(i_cell) % distribcell_index - ! Write to the geometry stack - i_univ = universe_dict % get(univ % id) - if (i_univ == root_universe) then - path = trim(path) // "u" // to_str(univ%id) - else - path = trim(path) // "->u" // to_str(univ%id) - end if - - ! Look through all cells in this universe - do i = 1, size(univ % cells) - ! If the cell matches the goal and the offset matches final, write to the - ! geometry stack - if (univ % cells(i) == i_cell .and. offset == target_offset) then - c => cells(univ % cells(i)) - path = trim(path) // "->c" // to_str(c % id()) - return - end if + path_len = distribcell_path_len(i_cell-1, map-1, target_offset, & + root_universe-1) + allocate(path_c(path_len)) + call distribcell_path(i_cell-1, map-1, target_offset, root_universe-1, & + path_c) + do i = 1, min(path_len, MAX_LINE_LEN) + if (path_c(i) == C_NULL_CHAR) exit + path(i:i) = path_c(i) end do - - ! Find the fill cell or lattice cell that contains the target offset. - do i = size(univ % cells), 2, -1 - c => cells(univ % cells(i)) - - ! Material cells don't contain other cells so ignore them. - if (c % type() /= FILL_MATERIAL) then - - if (c % type() == FILL_UNIVERSE) then - temp_offset = offset + c % offset(map-1) - else - ! Get the offset of the first lattice location - lat => lattices(c % fill() + 1) % obj - temp_offset = offset + lat % offset(map-1, [0, 0, 0]) - end if - - ! The desired cell is the first cell that gives an offset smaller or - ! equal to the target offset. - if (temp_offset <= target_offset) exit - end if - end do - - ! Add the cell to the path string. - c => cells(univ % cells(i)) - path = trim(path) // "->c" // to_str(c%id()) - - if (c % type() == FILL_UNIVERSE) then - ! Recurse into the fill cell. - offset = c % offset(map-1) + offset - next_univ => universes(c % fill() + 1) - call find_offset(i_cell, next_univ, target_offset, offset, path) - - elseif (c % type() == FILL_LATTICE) then - ! Recurse into the lattice cell. - lat => lattices(c % fill() + 1) % obj - select type (lat) - - type is (RectLattice) - path = trim(path) // "->l" // to_str(lat%id()) - - n_x = lat % n_cells(1) - n_y = lat % n_cells(2) - n_z = lat % n_cells(3) - - do m = n_z, 1, -1 - do l = n_y, 1, -1 - do k = n_x, 1, -1 - temp_offset = offset + lat % offset(map-1, [k-1, l-1, m-1]) - if (temp_offset <= target_offset) then - next_univ => universes(lat % get([k-1, l-1, m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // "," // & - trim(to_str(m-1)) // ")" - else - path = trim(path) // "(" // trim(to_str(k-1)) // & - "," // trim(to_str(l-1)) // ")" - end if - offset = temp_offset - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - end do - end do - end do - - type is (HexLattice) - path = trim(path) // "->l" // to_str(lat%id()) - - n_z = lat % n_axial - n_y = 2 * lat % n_rings - 1 - n_x = 2 * lat % n_rings - 1 - - do m = n_z, 1, -1 - do l = n_y, 1, -1 - do k = n_x, 1, -1 - if (k + l < lat % n_rings + 1) then - cycle - else if (k + l > 3*lat % n_rings - 1) then - cycle - end if - temp_offset = offset + lat % offset(map-1, [k-1, l-1, m-1]) - if (temp_offset <= target_offset) then - next_univ => universes(lat % get([k-1, l-1, m-1])+1) - if (lat % is_3d) then - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // "," // & - trim(to_str(m - 1)) // ")" - else - path = trim(path) // "(" // & - trim(to_str(k - lat % n_rings)) // "," // & - trim(to_str(l - lat % n_rings)) // ")" - end if - offset = temp_offset - call find_offset(i_cell, next_univ, target_offset, offset, path) - return - end if - end do - end do - end do - - end select - - end if end subroutine find_offset end module tally_filter_distribcell From 4614db8e2c2db1118befa0525b71a090822e8542 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 25 May 2018 21:22:54 -0400 Subject: [PATCH 37/41] Use const reverse iter for GCC 4.8 --- src/geometry_aux.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index a51e5b8a80..e79a00264b 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -221,8 +221,9 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, // The target must be further down the geometry tree and contained in a fill // cell or lattice cell in this universe. Find which cell contains the // target. - auto cell_it {search_univ.cells.rbegin()}; - for (; cell_it != search_univ.cells.rend(); ++cell_it) { + std::vector::const_reverse_iterator cell_it + {search_univ.cells.crbegin()}; + for (; cell_it != search_univ.cells.crend(); ++cell_it) { Cell &c = *cells_c[*cell_it]; // Material cells don't contain other cells so ignore them. From d78c5619de374c0fbec7f00a4e27e5f7835055ce Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sat, 26 May 2018 13:55:05 -0400 Subject: [PATCH 38/41] Consistently use 0-based indexing for lattices --- src/geometry.F90 | 10 ++--- src/lattice.cpp | 50 ++++++++++++------------ src/tallies/tally_filter_distribcell.F90 | 6 +-- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 44f138e104..457fdf3786 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -184,9 +184,9 @@ contains p % coord(k + 1) % lattice_z])) then offset = offset + lattices(p % coord(k + 1) % lattice) % obj & % offset(distribcell_index - 1, & - [p % coord(k + 1) % lattice_x - 1, & - p % coord(k + 1) % lattice_y - 1, & - p % coord(k + 1) % lattice_z - 1]) + [p % coord(k + 1) % lattice_x, & + p % coord(k + 1) % lattice_y, & + p % coord(k + 1) % lattice_z]) end if end if end do @@ -261,7 +261,7 @@ contains if (lat % are_valid_indices(i_xyz)) then ! Particle is inside the lattice. p % coord(j + 1) % universe = & - lat % get([i_xyz(1)-1, i_xyz(2)-1, i_xyz(3)-1]) + 1 + lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1 else ! Particle is outside the lattice. @@ -340,7 +340,7 @@ contains ! Find cell in next lattice element p % coord(j) % universe = & - lat % get([i_xyz(1)-1, i_xyz(2)-1, i_xyz(3)-1]) + 1 + lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1 call find_cell(p, found) if (.not. found) then diff --git a/src/lattice.cpp b/src/lattice.cpp index f5d0ba272d..0e20d20791 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -246,9 +246,9 @@ RectLattice::operator[](const int i_xyz[3]) bool RectLattice::are_valid_indices(const int i_xyz[3]) const { - return ( (i_xyz[0] > 0) && (i_xyz[0] <= n_cells[0]) - && (i_xyz[1] > 0) && (i_xyz[1] <= n_cells[1]) - && (i_xyz[2] > 0) && (i_xyz[2] <= n_cells[2])); + return ( (i_xyz[0] >= 0) && (i_xyz[0] < n_cells[0]) + && (i_xyz[1] >= 0) && (i_xyz[1] < n_cells[1]) + && (i_xyz[2] >= 0) && (i_xyz[2] < n_cells[2])); } //============================================================================== @@ -318,13 +318,13 @@ RectLattice::distance(const double xyz[3], const double uvw[3], std::array RectLattice::get_indices(const double xyz[3]) const { - int ix {static_cast(std::ceil((xyz[0] - lower_left[0]) / pitch[0]))}; - int iy {static_cast(std::ceil((xyz[1] - lower_left[1]) / pitch[1]))}; + int ix {static_cast(std::ceil((xyz[0] - lower_left[0]) / pitch[0]))-1}; + int iy {static_cast(std::ceil((xyz[1] - lower_left[1]) / pitch[1]))-1}; int iz; if (is_3d) { - iz = static_cast(std::ceil((xyz[2] - lower_left[2]) / pitch[2])); + iz = static_cast(std::ceil((xyz[2] - lower_left[2]) / pitch[2]))-1; } else { - iz = 1; + iz = 0; } return {ix, iy, iz}; } @@ -335,10 +335,10 @@ std::array RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const { std::array local_xyz; - local_xyz[0] = global_xyz[0] - (lower_left[0] + (i_xyz[0] - 0.5)*pitch[0]); - local_xyz[1] = global_xyz[1] - (lower_left[1] + (i_xyz[1] - 0.5)*pitch[1]); + local_xyz[0] = global_xyz[0] - (lower_left[0] + (i_xyz[0] + 0.5)*pitch[0]); + local_xyz[1] = global_xyz[1] - (lower_left[1] + (i_xyz[1] + 0.5)*pitch[1]); if (is_3d) { - local_xyz[2] = global_xyz[2] - (lower_left[2] + (i_xyz[2] - 0.5)*pitch[2]); + local_xyz[2] = global_xyz[2] - (lower_left[2] + (i_xyz[2] + 0.5)*pitch[2]); } else { local_xyz[2] = global_xyz[2]; } @@ -618,11 +618,11 @@ HexLattice::rbegin() bool HexLattice::are_valid_indices(const int i_xyz[3]) const { - return ((i_xyz[0] > 0) && (i_xyz[1] > 0) && (i_xyz[2] > 0) - && (i_xyz[0] < 2*n_rings) && (i_xyz[1] < 2*n_rings) - && (i_xyz[0] + i_xyz[1] > n_rings) - && (i_xyz[0] + i_xyz[1] < 3*n_rings) - && (i_xyz[2] <= n_axial)); + return ((i_xyz[0] >= 0) && (i_xyz[1] >= 0) && (i_xyz[2] >= 0) + && (i_xyz[0] < 2*n_rings-1) && (i_xyz[1] < 2*n_rings-1) + && (i_xyz[0] + i_xyz[1] > n_rings-2) + && (i_xyz[0] + i_xyz[1] < 3*n_rings-2) + && (i_xyz[2] < n_axial)); } std::pair> @@ -738,9 +738,9 @@ HexLattice::get_indices(const double xyz[3]) const // Index the z direction. std::array out; if (is_3d) { - out[2] = static_cast(std::ceil(xyz_o[2] / pitch[1] + 0.5 * n_axial)); + out[2] = static_cast(std::ceil(xyz_o[2] / pitch[1] + 0.5 * n_axial))-1; } else { - out[2] = 1; + out[2] = 0; } // Convert coordinates into skewed bases. The (x, alpha) basis is used to @@ -751,9 +751,9 @@ HexLattice::get_indices(const double xyz[3]) const out[1] = static_cast(std::floor(alpha / pitch[0])); // Add offset to indices (the center cell is (i_x, i_alpha) = (0, 0) but - // the array is offset so that the indices never go below 1). - out[0] += n_rings; - out[1] += n_rings; + // the array is offset so that the indices never go below 0). + out[0] += n_rings-1; + out[1] += n_rings-1; // Calculate the (squared) distance between the particle and the centers of // the four possible cells. Regular hexagonal tiles form a Voronoi @@ -801,14 +801,14 @@ HexLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const // x_l = x_g - (center + pitch_x*cos(30)*index_x) local_xyz[0] = global_xyz[0] - (center[0] - + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings) * pitch[0]); + + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]); // y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y) local_xyz[1] = global_xyz[1] - (center[1] - + (i_xyz[1] - n_rings) * pitch[0] - + (i_xyz[0] - n_rings) * pitch[0] / 2.0); + + (i_xyz[1] - n_rings + 1) * pitch[0] + + (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0); if (is_3d) { local_xyz[2] = global_xyz[2] - center[2] - + (0.5 * n_axial - i_xyz[2] + 0.5) * pitch[1]; + + (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1]; } else { local_xyz[2] = global_xyz[2]; } @@ -827,7 +827,7 @@ HexLattice::is_valid_index(int indx) const int iz = indx / (nx * ny); int iy = (indx - nx*ny*iz) / nx; int ix = indx - nx*ny*iz - nx*iy; - int i_xyz[3] {ix+1, iy+1, iz+1}; // TODO: fix this off-by-one + int i_xyz[3] {ix, iy, iz}; return are_valid_indices(i_xyz); } diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index d6643190cd..c9564083da 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -68,9 +68,9 @@ contains p % coord(i + 1) % lattice_z])) then offset = offset + lattices(p % coord(i + 1) % lattice) % obj & % offset(distribcell_index - 1, & - [p % coord(i + 1) % lattice_x - 1, & - p % coord(i + 1) % lattice_y - 1, & - p % coord(i + 1) % lattice_z - 1]) + [p % coord(i + 1) % lattice_x, & + p % coord(i + 1) % lattice_y, & + p % coord(i + 1) % lattice_z]) end if end if if (this % cell == p % coord(i) % cell) then From 7f7af84e64e804b8ca2860965f65e1f9d2257f28 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 27 May 2018 13:38:16 -0400 Subject: [PATCH 39/41] Miscellaneous cleanup --- docs/source/devguide/styleguide.rst | 7 +- src/cell.cpp | 34 +++++----- src/cell.h | 23 ++++--- src/geometry_header.F90 | 2 - src/hdf5_interface.h | 20 +----- src/input_xml.F90 | 3 +- src/lattice.cpp | 102 ++++++++-------------------- src/lattice.h | 80 +++++++++------------- src/summary.F90 | 4 +- src/surface.cpp | 24 +++---- 10 files changed, 114 insertions(+), 185 deletions(-) diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index 89d5673943..ccf6bf5217 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -219,8 +219,8 @@ Curly braces For a function definition, the opening and closing braces should each be on their own lines. This helps distinguish function code from the argument list. -If the entire function fits on one line, then the braces can be on the same -line. e.g.: +If the entire function fits on one or two lines, then the braces can be on the +same line. e.g.: .. code-block:: C++ @@ -238,6 +238,9 @@ line. e.g.: int return_one() {return 1;} + int return_one() + {return 1;} + For a conditional, the opening brace should be on the same line as the end of the conditional statement. If there is a following ``else if`` or ``else`` statement, the closing brace should be on the same line as that following diff --git a/src/cell.cpp b/src/cell.cpp index 82138a83f7..cdbb446172 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -12,9 +12,6 @@ #include "surface.h" #include "xml_interface.h" -//TODO: remove this include -#include - namespace openmc { @@ -34,14 +31,13 @@ extern "C" double FP_PRECISION; // Global variables //============================================================================== -// Braces force n_cells to be defined here, not just declared. -extern "C" {int32_t n_cells {0};} +int32_t n_cells {0}; std::vector cells_c; -std::map cell_dict; +std::unordered_map cell_dict; std::vector universes_c; -std::map universe_dict; +std::unordered_map universe_dict; //============================================================================== //! Convert region specification string to integer tokens. @@ -249,6 +245,7 @@ Cell::Cell(pugi::xml_node cell_node) fatal_error(err_msg); } + // Read the region specification. std::string region_spec {""}; if (check_for_node(cell_node, "region")) { region_spec = get_node_value(cell_node, "region"); @@ -280,6 +277,8 @@ Cell::Cell(pugi::xml_node cell_node) } } +//============================================================================== + bool Cell::contains(const double xyz[3], const double uvw[3], int32_t on_surface) const @@ -291,6 +290,8 @@ Cell::contains(const double xyz[3], const double uvw[3], } } +//============================================================================== + std::pair Cell::distance(const double xyz[3], const double uvw[3], int32_t on_surface) const @@ -306,7 +307,6 @@ Cell::distance(const double xyz[3], const double uvw[3], // Note the off-by-one indexing bool coincident {token == on_surface}; double d {surfaces_c[abs(token)-1]->distance(xyz, uvw, coincident)}; - //std::cout << token << " " << on_surface << " " << coincident << std::endl; // Check if this distance is the new minimum. if (d < min_dist) { @@ -320,20 +320,18 @@ Cell::distance(const double xyz[3], const double uvw[3], return {min_dist, i_surf}; } +//============================================================================== + void Cell::to_hdf5(hid_t cell_group) const { -// std::string group_name {"surface "}; -// group_name += std::to_string(id); -// -// hid_t surf_group = create_group(group_id, group_name); - if (!name.empty()) { write_string(cell_group, "name", name, false); } //TODO: Fix the off-by-one indexing. - write_int(cell_group, "universe", universes_c[universe-1]->id); + write_int(cell_group, 0, nullptr, "universe", &universes_c[universe-1]->id, + false); // Write the region specification. if (!region.empty()) { @@ -355,10 +353,10 @@ Cell::to_hdf5(hid_t cell_group) const } write_string(cell_group, "region", region_spec.str(), false); } - -// close_group(cell_group); } +//============================================================================== + bool Cell::contains_simple(const double xyz[3], const double uvw[3], int32_t on_surface) const @@ -382,6 +380,8 @@ Cell::contains_simple(const double xyz[3], const double uvw[3], return true; } +//============================================================================== + bool Cell::contains_complex(const double xyz[3], const double uvw[3], int32_t on_surface) const @@ -432,6 +432,8 @@ Cell::contains_complex(const double xyz[3], const double uvw[3], } } +//============================================================================== +// Non-method functions //============================================================================== extern "C" void diff --git a/src/cell.h b/src/cell.h index 2b03e1cd0a..f55c8e6fd4 100644 --- a/src/cell.h +++ b/src/cell.h @@ -1,9 +1,9 @@ #ifndef CELL_H #define CELL_H -#include #include #include +#include #include #include "hdf5.h" @@ -28,11 +28,11 @@ extern "C" int32_t n_cells; class Cell; extern std::vector cells_c; -extern std::map cell_dict; +extern std::unordered_map cell_dict; class Universe; extern std::vector universes_c; -extern std::map universe_dict; +extern std::unordered_map universe_dict; //============================================================================== //! A geometry primitive that fills all space and contains cells. @@ -41,10 +41,9 @@ extern std::map universe_dict; class Universe { public: - int32_t id; //! Unique ID - int32_t type; - std::vector cells; //! Cells within this universe - double x0, y0, z0; //! Translation coordinates. + int32_t id; //!< Unique ID + std::vector cells; //!< Cells within this universe + //double x0, y0, z0; //!< Translation coordinates. }; //============================================================================== @@ -61,8 +60,9 @@ public: int32_t fill; //!< Universe # filling this cell int32_t n_instances{0}; //!< Number of instances of this cell - //! Material within this cell. May be multiple materials for distribcell. - //! C_NONE signifies a universe. + //! \brief Material(s) within this cell. + //! + //! May be multiple materials for distribcell. C_NONE signifies a universe. std::vector material; //! Definition of spatial region as Boolean expression of half-spaces @@ -77,7 +77,7 @@ public: explicit Cell(pugi::xml_node cell_node); - //! Determine if a cell contains the particle at a given location. + //! \brief Determine if a cell contains the particle at a given location. //! //! The bounds of the cell are detemined by a logical expression involving //! surface half-spaces. At initialization, the expression was converted @@ -99,10 +99,11 @@ public: bool contains(const double xyz[3], const double uvw[3], int32_t on_surface) const; + //! Find the oncoming boundary of this cell. std::pair distance(const double xyz[3], const double uvw[3], int32_t on_surface) const; - //! Write all information needed to reconstruct the cell to an HDF5 group. + //! \brief Write cell information to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 8f95c4a7d1..d633b67005 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -292,7 +292,6 @@ module geometry_header integer(C_INT32_T), bind(C) :: n_cells ! # of cells integer(C_INT32_T), bind(C) :: n_universes ! # of universes - integer(C_INT32_T), bind(C) :: n_lattices ! # of lattices type(Cell), allocatable, target :: cells(:) type(Universe), allocatable, target :: universes(:) @@ -520,7 +519,6 @@ contains n_cells = 0 n_universes = 0 - n_lattices = 0 if (allocated(cells)) deallocate(cells) if (allocated(universes)) deallocate(universes) diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 232d2f6e7d..353d0137af 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -84,20 +84,6 @@ void write_string(hid_t group_id, const char* name, const std::string& buffer, b extern "C" void write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, const double* results); -inline void -write_int(hid_t group_id, char const *name, int32_t buffer) -{ - hid_t dataspace = H5Screate(H5S_SCALAR); - - hid_t dataset = H5Dcreate(group_id, name, H5T_NATIVE_INT32, dataspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - - H5Dwrite(dataset, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL, H5P_DEFAULT, &buffer); - - H5Sclose(dataspace); - H5Dclose(dataset); -} - template void write_int(hid_t group_id, char const *name, const std::array &buffer, bool indep) @@ -108,12 +94,12 @@ write_int(hid_t group_id, char const *name, template void -write_double_1D(hid_t group_id, char const *name, - const std::array &buffer) +write_double(hid_t group_id, char const *name, + const std::array &buffer, bool indep) { hsize_t dims[1] {array_len}; write_dataset(group_id, 1, dims, name, H5T_NATIVE_DOUBLE, - buffer.data(), false); + buffer.data(), indep); } } // namespace openmc diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 96cb2f7548..e24f3fe253 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1257,8 +1257,7 @@ contains ! Allocate lattices array n_rlats = size(node_rlat_list) n_hlats = size(node_hlat_list) - n_lattices = n_rlats + n_hlats - allocate(lattices(n_lattices)) + allocate(lattices(n_rlats + n_hlats)) RECT_LATTICES: do i = 1, n_rlats allocate(RectLattice::lattices(i) % obj) diff --git a/src/lattice.cpp b/src/lattice.cpp index 0e20d20791..2d9bf02c58 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -5,15 +5,11 @@ #include #include "cell.h" -#include "constants.h" #include "error.h" #include "geometry_aux.h" #include "hdf5_interface.h" #include "xml_interface.h" -//TODO: remove this include -#include - namespace openmc { @@ -23,7 +19,7 @@ namespace openmc { std::vector lattices_c; -std::map lattice_dict; +std::unordered_map lattice_dict; //============================================================================== // Lattice implementation @@ -48,31 +44,17 @@ Lattice::Lattice(pugi::xml_node lat_node) //============================================================================== -LatticeIter -Lattice::begin() -{ - return LatticeIter(*this, 0); -} +LatticeIter Lattice::begin() +{return LatticeIter(*this, 0);} -LatticeIter -Lattice::end() -{ - return LatticeIter(*this, universes.size()); -} +LatticeIter Lattice::end() +{return LatticeIter(*this, universes.size());} -//============================================================================== +ReverseLatticeIter Lattice::rbegin() +{return ReverseLatticeIter(*this, universes.size()-1);} -ReverseLatticeIter -Lattice::rbegin() -{ - return ReverseLatticeIter(*this, universes.size()-1); -} - -ReverseLatticeIter -Lattice::rend() -{ - return ReverseLatticeIter(*this, -1); -} +ReverseLatticeIter Lattice::rend() +{return ReverseLatticeIter(*this, -1);} //============================================================================== @@ -80,7 +62,7 @@ void Lattice::adjust_indices() { // Adjust the indices for the universes array. - for (auto it = begin(); it != end(); ++it) { + for (LatticeIter it = begin(); it != end(); ++it) { int uid = *it; auto search = universe_dict.find(uid); if (search != universe_dict.end()) { @@ -109,18 +91,10 @@ Lattice::adjust_indices() //============================================================================== -void -Lattice::allocate_offset_table(int n_maps) -{ - offsets.resize(n_maps * universes.size(), C_NONE); -} - -//============================================================================== - int32_t Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map) { - for (auto it = begin(); it != end(); ++it) { + for (LatticeIter it = begin(); it != end(); ++it) { offsets[map * universes.size() + it.indx] = offset; offset += count_universe_instances(*it, target_univ_id); } @@ -202,9 +176,6 @@ RectLattice::RectLattice(pugi::xml_node lat_node) if (is_3d) {pitch[2] = stod(pitch_words[2]);} // Read the universes and make sure the correct number was specified. - int nx = n_cells[0]; - int ny = n_cells[1]; - int nz = n_cells[2]; std::string univ_str {get_node_value(lat_node, "universes")}; std::vector univ_words {split(univ_str)}; if (univ_words.size() != nx*ny*nz) { @@ -217,7 +188,7 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } // Parse the universes. - universes.resize(nx*ny*nz, -1); + universes.resize(nx*ny*nz, C_NONE); for (int iz = 0; iz < nz; iz++) { for (int iy = ny-1; iy > -1; iy--) { for (int ix = 0; ix < nx; ix++) { @@ -234,9 +205,6 @@ RectLattice::RectLattice(pugi::xml_node lat_node) int32_t& RectLattice::operator[](const int i_xyz[3]) { - int nx = n_cells[0]; - int ny = n_cells[1]; - int nz = n_cells[2]; int indx = nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]; return universes[indx]; } @@ -350,9 +318,6 @@ RectLattice::get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const int32_t& RectLattice::offset(int map, const int i_xyz[3]) { - int nx = n_cells[0]; - int ny = n_cells[1]; - int nz = n_cells[2]; return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; } @@ -361,8 +326,6 @@ RectLattice::offset(int map, const int i_xyz[3]) std::string RectLattice::index_to_string(int indx) const { - int nx {n_cells[0]}; - int ny {n_cells[1]}; int iz {indx / (nx * ny)}; int iy {(indx - nx * ny * iz) / nx}; int ix {indx - nx * ny * iz - nx * iy}; @@ -384,14 +347,14 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const // Write basic lattice information. write_string(lat_group, "type", "rectangular", false); if (is_3d) { - write_double_1D(lat_group, "pitch", pitch); - write_double_1D(lat_group, "lower_left", lower_left); + write_double(lat_group, "pitch", pitch, false); + write_double(lat_group, "lower_left", lower_left, false); write_int(lat_group, "dimension", n_cells, false); } else { std::array pitch_short {{pitch[0], pitch[1]}}; - write_double_1D(lat_group, "pitch", pitch_short); + write_double(lat_group, "pitch", pitch_short, false); std::array ll_short {{lower_left[0], lower_left[1]}}; - write_double_1D(lat_group, "lower_left", ll_short); + write_double(lat_group, "lower_left", ll_short, false); std::array nc_short {{n_cells[0], n_cells[1]}}; write_int(lat_group, "dimension", nc_short, false); } @@ -480,7 +443,6 @@ HexLattice::HexLattice(pugi::xml_node lat_node) if (is_3d) {pitch[1] = stod(pitch_words[1]);} // Read the universes and make sure the correct number was specified. - //int n_univ = (2*n_rings - 1) * (2*n_rings - 1) * n_axial; int n_univ = (3*n_rings*n_rings - 3*n_rings + 1) * n_axial; std::string univ_str {get_node_value(lat_node, "universes")}; std::vector univ_words {split(univ_str)}; @@ -502,7 +464,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node) // in a manner that matches the input order. Note that i_x = 0, i_a = 0 // corresponds to the center of the hexagonal lattice. - universes.resize((2*n_rings-1) * (2*n_rings-1) * n_axial, -1); + universes.resize((2*n_rings-1) * (2*n_rings-1) * n_axial, C_NONE); int input_index = 0; for (int m = 0; m < n_axial; m++) { // Initialize lattice indecies. @@ -599,19 +561,11 @@ HexLattice::operator[](const int i_xyz[3]) //============================================================================== -LatticeIter -HexLattice::begin() -{ - return LatticeIter(*this, n_rings-1); -} +LatticeIter HexLattice::begin() +{return LatticeIter(*this, n_rings-1);} -//============================================================================== - -ReverseLatticeIter -HexLattice::rbegin() -{ - return ReverseLatticeIter(*this, universes.size()-n_rings); -} +ReverseLatticeIter HexLattice::rbegin() +{return ReverseLatticeIter(*this, universes.size()-n_rings);} //============================================================================== @@ -625,6 +579,8 @@ HexLattice::are_valid_indices(const int i_xyz[3]) const && (i_xyz[2] < n_axial)); } +//============================================================================== + std::pair> HexLattice::distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const @@ -872,13 +828,13 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const write_int(lat_group, 0, nullptr, "n_rings", &n_rings, false); write_int(lat_group, 0, nullptr, "n_axial", &n_axial, false); if (is_3d) { - write_double_1D(lat_group, "pitch", pitch); - write_double_1D(lat_group, "center", center); + write_double(lat_group, "pitch", pitch, false); + write_double(lat_group, "center", center, false); } else { std::array pitch_short {{pitch[0]}}; - write_double_1D(lat_group, "pitch", pitch_short); + write_double(lat_group, "pitch", pitch_short, false); std::array center_short {{center[0], center[1]}}; - write_double_1D(lat_group, "center", center_short); + write_double(lat_group, "center", center_short, false); } // Write the universe ids. @@ -976,9 +932,7 @@ extern "C" { } int32_t lattice_offset(Lattice *lat, int map, const int i_xyz[3]) - { - return lat->offset(map, i_xyz); - } + {return lat->offset(map, i_xyz);} int32_t lattice_outer(Lattice *lat) {return lat->outer;} diff --git a/src/lattice.h b/src/lattice.h index 3161a24739..909029aa90 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -3,11 +3,11 @@ #include #include -#include // For numeric_limits -#include #include +#include #include +#include "constants.h" #include "hdf5.h" #include "pugixml/pugixml.hpp" @@ -24,30 +24,27 @@ constexpr int32_t NO_OUTER_UNIVERSE{-1}; // Global variables //============================================================================== -//extern "C" int32_t n_lattice; - class Lattice; -//extern Lattice **lattices_c; extern std::vector lattices_c; -extern std::map lattice_dict; +extern std::unordered_map lattice_dict; //============================================================================== -//! Abstract type for ordered array of universes. +//! \class Lattice +//! \brief Abstract type for ordered array of universes. //============================================================================== class LatticeIter; - class ReverseLatticeIter; class Lattice { public: - int32_t id; //!< Universe ID number - std::string name; //!< User-defined name - std::vector universes; //!< Universes filling each lattice tile - int32_t outer{NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice - std::vector offsets; //!< Distribcell offset table + int32_t id; //!< Universe ID number + std::string name; //!< User-defined name + std::vector universes; //!< Universes filling each lattice tile + int32_t outer {NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice + std::vector offsets; //!< Distribcell offset table explicit Lattice(pugi::xml_node lat_node); @@ -65,17 +62,19 @@ public: void adjust_indices(); //! Allocate offset table for distribcell. - void allocate_offset_table(int n_maps); + void allocate_offset_table(int n_maps) + {offsets.resize(n_maps * universes.size(), C_NONE);} + //! Populate the distribcell offset tables. int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map); - //! Check lattice indices. + //! \brief Check lattice indices. //! @param i_xyz[3] The indices for a lattice tile. //! @return true if the given indices fit within the lattice bounds. False //! otherwise. virtual bool are_valid_indices(const int i_xyz[3]) const = 0; - //! Find the next lattice surface crossing + //! \brief Find the next lattice surface crossing //! @param xyz[3] A 3D Cartesian coordinate. //! @param uvw[3] A 3D Cartesian direction. //! @param i_xyz[3] The indices for a lattice tile. @@ -85,45 +84,43 @@ public: distance(const double xyz[3], const double uvw[3], const int i_xyz[3]) const = 0; - //! Find the lattice tile indices for a given point. + //! \brief Find the lattice tile indices for a given point. //! @param xyz[3] A 3D Cartesian coordinate. //! @return An array containing the indices of a lattice tile. virtual std::array get_indices(const double xyz[3]) const = 0; - //! Get coordinates local to a lattice tile. + //! \brief Get coordinates local to a lattice tile. //! @param global_xyz[3] A 3D Cartesian coordinate. //! @param i_xyz[3] The indices for a lattice tile. //! @return Local 3D Cartesian coordinates. virtual std::array get_local_xyz(const double global_xyz[3], const int i_xyz[3]) const = 0; - //! Check flattened lattice index. + //! \brief Check flattened lattice index. //! @param indx The index for a lattice tile. //! @return true if the given index fit within the lattice bounds. False //! otherwise. virtual bool is_valid_index(int indx) const - { - return (indx >= 0) && (indx < universes.size()); - } + {return (indx >= 0) && (indx < universes.size());} - //! Get the distribcell offset for a lattice tile. + //! \brief Get the distribcell offset for a lattice tile. //! @param The map index for the target cell. //! @param i_xyz[3] The indices for a lattice tile. //! @return Distribcell offset i.e. the largest instance number for the target //! cell found in the geometry tree under this lattice tile. virtual int32_t& offset(int map, const int i_xyz[3]) = 0; - //! Convert an array index to a useful human-readable string. + //! \brief Convert an array index to a useful human-readable string. //! @param indx The index for a lattice tile. //! @return A string representing the lattice tile. virtual std::string index_to_string(int indx) const = 0; - //! Write all information needed to reconstruct the lattice to an HDF5 group. + //! \brief Write lattice information to an HDF5 group. //! @param group_id An HDF5 group id. void to_hdf5(hid_t group_id) const; protected: - bool is_3d; //! Has divisions along the z-axis + bool is_3d; //!< Has divisions along the z-axis? virtual void to_hdf5_inner(hid_t group_id) const = 0; }; @@ -135,7 +132,6 @@ protected: class LatticeIter { public: - int indx; //!< An index to a Lattice universes or offsets array. LatticeIter(Lattice &lat_, int indx_) @@ -143,20 +139,11 @@ public: indx(indx_) {} - bool operator==(const LatticeIter &rhs) - { - return (indx == rhs.indx); - } + bool operator==(const LatticeIter &rhs) {return (indx == rhs.indx);} - bool operator!=(const LatticeIter &rhs) - { - return !(*this == rhs); - } + bool operator!=(const LatticeIter &rhs) {return !(*this == rhs);} - int32_t& operator*() - { - return lat.universes[indx]; - } + int32_t& operator*() {return lat.universes[indx];} LatticeIter& operator++() { @@ -194,7 +181,6 @@ public: } }; -//============================================================================== //============================================================================== class RectLattice : public Lattice @@ -202,8 +188,6 @@ class RectLattice : public Lattice public: explicit RectLattice(pugi::xml_node lat_node); - virtual ~RectLattice() {} - int32_t& operator[](const int i_xyz[3]); bool are_valid_indices(const int i_xyz[3]) const; @@ -222,13 +206,17 @@ public: void to_hdf5_inner(hid_t group_id) const; -protected: +private: std::array n_cells; //!< Number of cells along each axis std::array lower_left; //!< Global lower-left corner of the lattice std::array pitch; //!< Lattice tile width along each axis + + // Convenience aliases + int &nx {n_cells[0]}; + int &ny {n_cells[1]}; + int &nz {n_cells[2]}; }; -//============================================================================== //============================================================================== class HexLattice : public Lattice @@ -236,8 +224,6 @@ class HexLattice : public Lattice public: explicit HexLattice(pugi::xml_node lat_node); - virtual ~HexLattice() {} - int32_t& operator[](const int i_xyz[3]); LatticeIter begin(); @@ -262,7 +248,7 @@ public: void to_hdf5_inner(hid_t group_id) const; -protected: +private: int n_rings; //!< Number of radial tile positions int n_axial; //!< Number of axial tile positions std::array center; //!< Global center of lattice diff --git a/src/summary.F90 b/src/summary.F90 index 464c0c6cfa..02352db7cd 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -176,7 +176,7 @@ contains call write_attribute(geom_group, "n_cells", n_cells) call write_attribute(geom_group, "n_surfaces", n_surfaces) call write_attribute(geom_group, "n_universes", n_universes) - call write_attribute(geom_group, "n_lattices", n_lattices) + call write_attribute(geom_group, "n_lattices", size(lattices)) ! ========================================================================== ! WRITE INFORMATION ON CELLS @@ -292,7 +292,7 @@ contains lattices_group = create_group(geom_group, "lattices") - do i = 1, n_lattices + do i = 1, size(lattices) lat => lattices(i)%obj call lat % to_hdf5(lattices_group) end do diff --git a/src/surface.cpp b/src/surface.cpp index 7dea2b7df0..1155559fd3 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -318,7 +318,7 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-plane", false); std::array coeffs {{x0}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } bool SurfaceXPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -383,7 +383,7 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-plane", false); std::array coeffs {{y0}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } bool SurfaceYPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -449,7 +449,7 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-plane", false); std::array coeffs {{z0}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } bool SurfaceZPlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -510,7 +510,7 @@ void SurfacePlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "plane", false); std::array coeffs {{A, B, C, D}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } bool SurfacePlane::periodic_translate(PeriodicSurface *other, double xyz[3], @@ -642,7 +642,7 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cylinder", false); std::array coeffs {{y0, z0, r}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -676,7 +676,7 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cylinder", false); std::array coeffs {{x0, z0, r}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -710,7 +710,7 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cylinder", false); std::array coeffs {{x0, y0, r}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -781,7 +781,7 @@ void SurfaceSphere::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "sphere", false); std::array coeffs {{x0, y0, z0, r}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -898,7 +898,7 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cone", false); std::array coeffs {{x0, y0, z0, r_sq}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -932,7 +932,7 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cone", false); std::array coeffs {{x0, y0, z0, r_sq}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -966,7 +966,7 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cone", false); std::array coeffs {{x0, y0, z0, r_sq}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== @@ -1060,7 +1060,7 @@ void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "quadric", false); std::array coeffs {{A, B, C, D, E, F, G, H, J, K}}; - write_double_1D(group_id, "coefficients", coeffs); + write_double(group_id, "coefficients", coeffs, false); } //============================================================================== From 3d5e9b4dc2062494d8ccf8cab511c42e6a345ddd Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 27 May 2018 14:54:51 -0400 Subject: [PATCH 40/41] Add deallocation for C++ geometry globals --- src/cell.cpp | 7 ------- src/geometry_aux.cpp | 19 +++++++++++++++++++ src/geometry_aux.h | 6 ++++++ src/geometry_header.F90 | 6 ++++++ tools/ci/travis-script.sh | 6 ++---- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index cdbb446172..8cdc7b6f64 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -520,12 +520,5 @@ extern "C" { } } -//extern "C" void free_memory_cells_c() -//{ -// delete cells_c; -// cells_c = nullptr; -// n_cells = 0; -// cell_dict.clear(); -//} } // namespace openmc diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index e79a00264b..dc31edf7e4 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -321,4 +321,23 @@ maximum_levels(int32_t univ) return levels_below; } +//============================================================================== + +void +free_memory_geometry_c() +{ + for (Cell *c : cells_c) {delete c;} + cells_c.clear(); + cell_dict.clear(); + n_cells = 0; + + for (Universe *u : universes_c) {delete u;} + universes_c.clear(); + universe_dict.clear(); + + for (Lattice *lat : lattices_c) {delete lat;} + lattices_c.clear(); + lattice_dict.clear(); +} + } // namespace openmc diff --git a/src/geometry_aux.h b/src/geometry_aux.h index 7d2c3cd9af..b998ad32c9 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -102,5 +102,11 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset, extern "C" int maximum_levels(int32_t univ); +//============================================================================== +//! Deallocates global vectors and maps for cells, universes, and lattices. +//============================================================================== + +extern "C" void free_memory_geometry_c(); + } // namespace openmc #endif // GEOMETRY_AUX_H diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index d633b67005..758fc54da7 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -516,6 +516,12 @@ contains !=============================================================================== subroutine free_memory_geometry() + interface + subroutine free_memory_geometry_c() bind(C) + end subroutine free_memory_geometry_c + end interface + + call free_memory_geometry_c() n_cells = 0 n_universes = 0 diff --git a/tools/ci/travis-script.sh b/tools/ci/travis-script.sh index 6dfbc95106..ee445b517f 100755 --- a/tools/ci/travis-script.sh +++ b/tools/ci/travis-script.sh @@ -8,9 +8,7 @@ fi # Run regression and unit tests if [[ $MPI == 'y' ]]; then - pytest --cov=openmc -v --mpi tests/regression_tests - pytest --cov=openmc -v --mpi tests/unit_tests + pytest --cov=openmc -v --mpi tests else - pytest --cov=openmc -v tests/regression_tests - pytest --cov=openmc -v tests/unit_tests + pytest --cov=openmc -v tests fi From 4b403c6b7bb3decfee10d77bb16c20f744cc81b5 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 11 Jun 2018 15:00:18 -0400 Subject: [PATCH 41/41] Address #1012 comments --- src/cell.cpp | 59 +++++++++++++++++------------------ src/cell.h | 10 +++--- src/geometry_aux.cpp | 72 +++++++++++++++++++++---------------------- src/lattice.cpp | 31 ++++++++++--------- src/lattice.h | 4 +-- src/string_utils.h | 35 +++++++++++++++++++++ src/surface.cpp | 16 +++++----- src/surface.h | 4 +-- src/xml_interface.cpp | 24 --------------- src/xml_interface.h | 2 -- 10 files changed, 132 insertions(+), 125 deletions(-) create mode 100644 src/string_utils.h diff --git a/src/cell.cpp b/src/cell.cpp index 8cdc7b6f64..e4388e7012 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -33,11 +33,11 @@ extern "C" double FP_PRECISION; int32_t n_cells {0}; -std::vector cells_c; -std::unordered_map cell_dict; +std::vector global_cells; +std::unordered_map cell_map; -std::vector universes_c; -std::unordered_map universe_dict; +std::vector global_universes; +std::unordered_map universe_map; //============================================================================== //! Convert region specification string to integer tokens. @@ -246,7 +246,7 @@ Cell::Cell(pugi::xml_node cell_node) } // Read the region specification. - std::string region_spec {""}; + std::string region_spec; if (check_for_node(cell_node, "region")) { region_spec = get_node_value(cell_node, "region"); } @@ -256,10 +256,9 @@ Cell::Cell(pugi::xml_node cell_node) region.shrink_to_fit(); // Convert user IDs to surface indices. - // Note that the index has 1 added to it in order to preserve the sign. - for (auto it = region.begin(); it != region.end(); it++) { - if (*it < OP_UNION) { - *it = copysign(surface_dict[abs(*it)]+1, *it); + for (auto &r : region) { + if (r < OP_UNION) { + r = copysign(surface_map[abs(r)] + 1, r); } } @@ -330,8 +329,8 @@ Cell::to_hdf5(hid_t cell_group) const } //TODO: Fix the off-by-one indexing. - write_int(cell_group, 0, nullptr, "universe", &universes_c[universe-1]->id, - false); + write_int(cell_group, 0, nullptr, "universe", + &global_universes[universe-1]->id, false); // Write the region specification. if (!region.empty()) { @@ -446,24 +445,24 @@ read_cells(pugi::xml_node *node) } // Allocate the vector of Cells. - cells_c.reserve(n_cells); + global_cells.reserve(n_cells); // Loop over XML cell elements and populate the array. for (pugi::xml_node cell_node: node->children("cell")) { - cells_c.push_back(new Cell(cell_node)); + global_cells.push_back(new Cell(cell_node)); } - // Populate the Universe vector and dictionary. - for (int i = 0; i < cells_c.size(); i++) { - int32_t uid = cells_c[i]->universe; - auto it = universe_dict.find(uid); - if (it == universe_dict.end()) { - universes_c.push_back(new Universe()); - universes_c.back()->id = uid; - universes_c.back()->cells.push_back(i); - universe_dict[uid] = universes_c.size() - 1; + // Populate the Universe vector and map. + for (int i = 0; i < global_cells.size(); i++) { + int32_t uid = global_cells[i]->universe; + auto it = universe_map.find(uid); + if (it == universe_map.end()) { + global_universes.push_back(new Universe()); + global_universes.back()->id = uid; + global_universes.back()->cells.push_back(i); + universe_map[uid] = global_universes.size() - 1; } else { - universes_c[it->second]->cells.push_back(i); + global_universes[it->second]->cells.push_back(i); } } } @@ -473,7 +472,7 @@ read_cells(pugi::xml_node *node) //============================================================================== extern "C" { - Cell* cell_pointer(int32_t cell_ind) {return cells_c[cell_ind];} + Cell* cell_pointer(int32_t cell_ind) {return global_cells[cell_ind];} int32_t cell_id(Cell *c) {return c->id;} @@ -499,11 +498,11 @@ extern "C" { {return c->contains(xyz, uvw, on_surface);} void cell_distance(Cell *c, double xyz[3], double uvw[3], int32_t on_surface, - double &min_dist, int32_t &i_surf) + double *min_dist, int32_t *i_surf) { std::pair out = c->distance(xyz, uvw, on_surface); - min_dist = out.first; - i_surf = out.second; + *min_dist = out.first; + *i_surf = out.second; } int32_t cell_offset(Cell *c, int map) {return c->offset[map];} @@ -512,11 +511,11 @@ extern "C" { void extend_cells_c(int32_t n) { - cells_c.reserve(cells_c.size() + n); + global_cells.reserve(global_cells.size() + n); for (int32_t i = 0; i < n; i++) { - cells_c.push_back(new Cell()); + global_cells.push_back(new Cell()); } - n_cells = cells_c.size(); + n_cells = global_cells.size(); } } diff --git a/src/cell.h b/src/cell.h index f55c8e6fd4..a2f72c8337 100644 --- a/src/cell.h +++ b/src/cell.h @@ -27,12 +27,12 @@ extern "C" int FILL_LATTICE; extern "C" int32_t n_cells; class Cell; -extern std::vector cells_c; -extern std::unordered_map cell_dict; +extern std::vector global_cells; +extern std::unordered_map cell_map; class Universe; -extern std::vector universes_c; -extern std::unordered_map universe_dict; +extern std::vector global_universes; +extern std::unordered_map universe_map; //============================================================================== //! A geometry primitive that fills all space and contains cells. @@ -54,7 +54,7 @@ class Cell { public: int32_t id; //!< Unique ID - std::string name{""}; //!< User-defined name + std::string name; //!< User-defined name int type; //!< Material, universe, or lattice int32_t universe; //!< Universe # this cell is in int32_t fill; //!< Universe # filling this cell diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index dc31edf7e4..3f36cf299a 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -9,8 +9,6 @@ #include "error.h" #include "lattice.h" -#include //TODO: remove this - namespace openmc { @@ -20,15 +18,15 @@ void adjust_indices_c() { // Adjust material/fill idices. - for (Cell *c : cells_c) { + for (Cell *c : global_cells) { if (c->material[0] == C_NONE) { int32_t id = c->fill; - auto search_univ = universe_dict.find(id); - auto search_lat = lattice_dict.find(id); - if (search_univ != universe_dict.end()) { + auto search_univ = universe_map.find(id); + auto search_lat = lattice_map.find(id); + if (search_univ != universe_map.end()) { c->type = FILL_UNIVERSE; c->fill = search_univ->second; - } else if (search_lat != lattice_dict.end()) { + } else if (search_lat != lattice_map.end()) { c->type = FILL_LATTICE; c->fill = search_lat->second; } else { @@ -44,9 +42,9 @@ adjust_indices_c() } // Change cell.universe values from IDs to indices. - for (Cell *c : cells_c) { - auto search = universe_dict.find(c->universe); - if (search != universe_dict.end()) { + for (Cell *c : global_cells) { + auto search = universe_map.find(c->universe); + if (search != universe_map.end()) { //TODO: Remove this off-by-one indexing. c->universe = search->second + 1; } else { @@ -70,7 +68,7 @@ find_root_universe() { // Find all the universes listed as a cell fill. std::unordered_set fill_univ_ids; - for (Cell *c : cells_c) { + for (Cell *c : global_cells) { fill_univ_ids.insert(c->fill); } @@ -87,8 +85,8 @@ find_root_universe() // Figure out which universe is not in the set. This is the root universe. bool root_found {false}; int32_t root_univ; - for (int32_t i = 0; i < universes_c.size(); i++) { - auto search = fill_univ_ids.find(universes_c[i]->id); + for (int32_t i = 0; i < global_universes.size(); i++) { + auto search = fill_univ_ids.find(global_universes[i]->id); if (search == fill_univ_ids.end()) { if (root_found) { fatal_error("Two or more universes are not used as fill universes, so " @@ -111,7 +109,7 @@ find_root_universe() void allocate_offset_tables(int n_maps) { - for (Cell *c : cells_c) { + for (Cell *c : global_cells) { if (c->type != FILL_MATERIAL) { c->offset.resize(n_maps, C_NONE); } @@ -127,8 +125,8 @@ allocate_offset_tables(int n_maps) void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : universes_c[univ_indx]->cells) { - Cell &c = *cells_c[cell_indx]; + for (int32_t cell_indx : global_universes[univ_indx]->cells) { + Cell &c = *global_cells[cell_indx]; ++c.n_instances; if (c.type == FILL_UNIVERSE) { @@ -151,13 +149,13 @@ int count_universe_instances(int32_t search_univ, int32_t target_univ_id) { // If this is the target, it can't contain itself. - if (universes_c[search_univ]->id == target_univ_id) { + if (global_universes[search_univ]->id == target_univ_id) { return 1; } int count {0}; - for (int32_t cell_indx : universes_c[search_univ]->cells) { - Cell &c = *cells_c[cell_indx]; + for (int32_t cell_indx : global_universes[search_univ]->cells) { + Cell &c = *global_cells[cell_indx]; if (c.type == FILL_UNIVERSE) { int32_t next_univ = c.fill; @@ -180,10 +178,10 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id) void fill_offset_tables(int32_t target_univ_id, int map) { - for (Universe *univ : universes_c) { + for (Universe *univ : global_universes) { int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation. for (int32_t cell_indx : univ->cells) { - Cell &c = *cells_c[cell_indx]; + Cell &c = *global_cells[cell_indx]; if (c.type == FILL_UNIVERSE) { c.offset[map] = offset; @@ -212,7 +210,7 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, // write to the path and return. for (int32_t cell_indx : search_univ.cells) { if ((cell_indx == target_cell) && (offset == target_offset)) { - Cell &c = *cells_c[cell_indx]; + Cell &c = *global_cells[cell_indx]; path << "c" << c.id; return path.str(); } @@ -224,7 +222,7 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, std::vector::const_reverse_iterator cell_it {search_univ.cells.crbegin()}; for (; cell_it != search_univ.cells.crend(); ++cell_it) { - Cell &c = *cells_c[*cell_it]; + Cell &c = *global_cells[*cell_it]; // Material cells don't contain other cells so ignore them. if (c.type != FILL_MATERIAL) { @@ -244,14 +242,14 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, } // Add the cell to the path string. - Cell &c = *cells_c[*cell_it]; + Cell &c = *global_cells[*cell_it]; path << "c" << c.id << "->"; if (c.type == FILL_UNIVERSE) { // Recurse into the fill cell. offset += c.offset[map]; path << distribcell_path_inner(target_cell, map, target_offset, - *universes_c[c.fill], offset); + *global_universes[c.fill], offset); return path.str(); } else { // Recurse into the lattice cell. @@ -264,7 +262,7 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, offset = temp_offset; path << "(" << lat.index_to_string(it.indx) << ")->"; path << distribcell_path_inner(target_cell, map, target_offset, - *universes_c[*it], offset); + *global_universes[*it], offset); return path.str(); } } @@ -277,7 +275,7 @@ int distribcell_path_len(int32_t target_cell, int32_t map, int32_t target_offset, int32_t root_univ) { - Universe &root = *universes_c[root_univ]; + Universe &root = *global_universes[root_univ]; std::string path_ {distribcell_path_inner(target_cell, map, target_offset, root, 0)}; return path_.size() + 1; @@ -289,7 +287,7 @@ void distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset, int32_t root_univ, char *path) { - Universe &root = *universes_c[root_univ]; + Universe &root = *global_universes[root_univ]; std::string path_ {distribcell_path_inner(target_cell, map, target_offset, root, 0)}; path_.copy(path, path_.size()); @@ -303,8 +301,8 @@ maximum_levels(int32_t univ) { int levels_below {0}; - for (int32_t cell_indx : universes_c[univ]->cells) { - Cell &c = *cells_c[cell_indx]; + for (int32_t cell_indx : global_universes[univ]->cells) { + Cell &c = *global_cells[cell_indx]; if (c.type == FILL_UNIVERSE) { int32_t next_univ = c.fill; levels_below = std::max(levels_below, maximum_levels(next_univ)); @@ -326,18 +324,18 @@ maximum_levels(int32_t univ) void free_memory_geometry_c() { - for (Cell *c : cells_c) {delete c;} - cells_c.clear(); - cell_dict.clear(); + for (Cell *c : global_cells) {delete c;} + global_cells.clear(); + cell_map.clear(); n_cells = 0; - for (Universe *u : universes_c) {delete u;} - universes_c.clear(); - universe_dict.clear(); + for (Universe *u : global_universes) {delete u;} + global_universes.clear(); + universe_map.clear(); for (Lattice *lat : lattices_c) {delete lat;} lattices_c.clear(); - lattice_dict.clear(); + lattice_map.clear(); } } // namespace openmc diff --git a/src/lattice.cpp b/src/lattice.cpp index 2d9bf02c58..959ab932e4 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -8,6 +8,7 @@ #include "error.h" #include "geometry_aux.h" #include "hdf5_interface.h" +#include "string_utils.h" #include "xml_interface.h" @@ -19,7 +20,7 @@ namespace openmc { std::vector lattices_c; -std::unordered_map lattice_dict; +std::unordered_map lattice_map; //============================================================================== // Lattice implementation @@ -64,8 +65,8 @@ Lattice::adjust_indices() // Adjust the indices for the universes array. for (LatticeIter it = begin(); it != end(); ++it) { int uid = *it; - auto search = universe_dict.find(uid); - if (search != universe_dict.end()) { + auto search = universe_map.find(uid); + if (search != universe_map.end()) { *it = search->second; } else { std::stringstream err_msg; @@ -77,8 +78,8 @@ Lattice::adjust_indices() // Adjust the index for the outer universe. if (outer != NO_OUTER_UNIVERSE) { - auto search = universe_dict.find(outer); - if (search != universe_dict.end()) { + auto search = universe_map.find(outer); + if (search != universe_map.end()) { outer = search->second; } else { std::stringstream err_msg; @@ -117,7 +118,7 @@ Lattice::to_hdf5(hid_t lattices_group) const } if (outer != NO_OUTER_UNIVERSE) { - int32_t outer_id = universes_c[outer]->id; + int32_t outer_id = global_universes[outer]->id; write_int(lat_group, 0, nullptr, "outer", &outer_id, false); } else { write_int(lat_group, 0, nullptr, "outer", &outer, false); @@ -372,7 +373,7 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const for (int j = 0; j < nx; j++) { int indx1 = nx*ny*m + nx*k + j; int indx2 = nx*ny*m + nx*(ny-k-1) + j; - out[indx2] = universes_c[universes[indx1]]->id; + out[indx2] = global_universes[universes[indx1]]->id; } } } @@ -389,7 +390,7 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const for (int j = 0; j < nx; j++) { int indx1 = nx*k + j; int indx2 = nx*(ny-k-1) + j; - out[indx2] = universes_c[universes[indx1]]->id; + out[indx2] = global_universes[universes[indx1]]->id; } } @@ -854,7 +855,7 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const // This array position is never used; put a -1 to indicate this. out[indx] = -1; } else { - out[indx] = universes_c[universes[indx]]->id; + out[indx] = global_universes[universes[indx]]->id; } } } @@ -871,19 +872,19 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const extern "C" void read_lattices(pugi::xml_node *node) { - for (pugi::xml_node lat_node: node->children("lattice")) { + for (pugi::xml_node lat_node : node->children("lattice")) { lattices_c.push_back(new RectLattice(lat_node)); } - for (pugi::xml_node lat_node: node->children("hex_lattice")) { + for (pugi::xml_node lat_node : node->children("hex_lattice")) { lattices_c.push_back(new HexLattice(lat_node)); } - // Fill the lattice dictionary. + // Fill the lattice map. for (int i_lat = 0; i_lat < lattices_c.size(); i_lat++) { int id = lattices_c[i_lat]->id; - auto in_dict = lattice_dict.find(id); - if (in_dict == lattice_dict.end()) { - lattice_dict[id] = i_lat; + auto in_map = lattice_map.find(id); + if (in_map == lattice_map.end()) { + lattice_map[id] = i_lat; } else { std::stringstream err_msg; err_msg << "Two or more lattices use the same unique ID: " << id; diff --git a/src/lattice.h b/src/lattice.h index 909029aa90..19749ce4f0 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -27,7 +27,7 @@ constexpr int32_t NO_OUTER_UNIVERSE{-1}; class Lattice; extern std::vector lattices_c; -extern std::unordered_map lattice_dict; +extern std::unordered_map lattice_map; //============================================================================== //! \class Lattice @@ -58,7 +58,7 @@ public: virtual ReverseLatticeIter rbegin(); ReverseLatticeIter rend(); - //! Convert internal universe values from IDs to indices using universe_dict. + //! Convert internal universe values from IDs to indices using universe_map. void adjust_indices(); //! Allocate offset table for distribcell. diff --git a/src/string_utils.h b/src/string_utils.h new file mode 100644 index 0000000000..e2cb773ab1 --- /dev/null +++ b/src/string_utils.h @@ -0,0 +1,35 @@ +#ifndef STRING_UTILS_H +#define STRING_UTILS_H + +#include +#include + + +namespace openmc { + +std::vector +split(const std::string &in) +{ + std::vector out; + + for (int i = 0; i < in.size(); ) { + // Increment i until we find a non-whitespace character. + if (std::isspace(in[i])) { + i++; + + } else { + // Find the next whitespace character at j. + int j = i + 1; + while (j < in.size() && std::isspace(in[j]) == 0) {j++;} + + // Push-back everything between i and j. + out.push_back(in.substr(i, j-i)); + i = j + 1; // j is whitespace so leapfrog to j+1 + } + } + + return out; +} + +} // namespace openmc +#endif // STRING_UTILS_H diff --git a/src/surface.cpp b/src/surface.cpp index 1155559fd3..56e57a854f 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -28,7 +28,7 @@ int32_t n_surfaces; Surface **surfaces_c; -std::map surface_dict; +std::map surface_map; //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element @@ -1129,12 +1129,12 @@ read_surfaces(pugi::xml_node *node) } } - // Fill the surface dictionary. + // Fill the surface map. 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; + auto in_map = surface_map.find(id); + if (in_map == surface_map.end()) { + surface_map[id] = i_surf; } else { std::stringstream err_msg; err_msg << "Two or more surfaces use the same unique ID: " << id; @@ -1224,7 +1224,7 @@ read_surfaces(pugi::xml_node *node) } } else { // Convert the surface id to an index. - surf->i_periodic = surface_dict[surf->i_periodic]; + surf->i_periodic = surface_map[surf->i_periodic]; } } else { // This is a SurfacePlane. We won't try to find it's partner if the @@ -1236,7 +1236,7 @@ read_surfaces(pugi::xml_node *node) fatal_error(err_msg); } else { // Convert the surface id to an index. - surf->i_periodic = surface_dict[surf->i_periodic]; + surf->i_periodic = surface_map[surf->i_periodic]; } } @@ -1283,7 +1283,7 @@ extern "C" { delete surfaces_c; surfaces_c = nullptr; n_surfaces = 0; - surface_dict.clear(); + surface_map.clear(); } } diff --git a/src/surface.h b/src/surface.h index 99c51d7473..1d8cc6ac7b 100644 --- a/src/surface.h +++ b/src/surface.h @@ -31,7 +31,7 @@ extern "C" int32_t n_surfaces; class Surface; extern Surface **surfaces_c; -extern std::map surface_dict; +extern std::map surface_map; //============================================================================== //! Coordinates for an axis-aligned cube that bounds a geometric object. @@ -58,7 +58,7 @@ public: //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 + std::string name; //!< User-defined name explicit Surface(pugi::xml_node surf_node); diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index 77859ede8c..b4fcc524c6 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -35,28 +35,4 @@ get_node_value(pugi::xml_node node, const char *name) return value; } -std::vector -split(const std::string in) -{ - std::vector out; - - for (int i = 0; i < in.size(); ) { - // Increment i until we find a non-whitespace character. - if (std::isspace(in[i])) { - i++; - - } else { - // Find the next whitespace character at j. - int j = i + 1; - while (j < in.size() && std::isspace(in[j]) == 0) {j++;} - - // Push-back everything between i and j. - out.push_back(in.substr(i, j-i)); - i = j + 1; // j is whitespace so leapfrog to j+1 - } - } - - return out; -} - } // namespace openmc diff --git a/src/xml_interface.h b/src/xml_interface.h index 41252ed611..b6f9e3246d 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -17,7 +17,5 @@ check_for_node(pugi::xml_node node, const char *name) std::string get_node_value(pugi::xml_node node, const char *name); -std::vector split(const std::string in); - } // namespace openmc #endif // XML_INTERFACE_H