From 64ae9949263aa9e9944b795b4397d1a3d0fe5719 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 14 Aug 2018 16:22:40 -0400 Subject: [PATCH 01/76] Add check_cell_overlap to C++ --- CMakeLists.txt | 1 + src/cell.cpp | 5 +++++ src/geometry.F90 | 14 ++++++++++++- src/geometry.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ src/geometry.h | 5 +++++ src/output.F90 | 9 +++++++++ 6 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/geometry.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c94f4df5f..673a71492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,6 +386,7 @@ add_library(libopenmc SHARED src/cell.cpp src/initialize.cpp src/finalize.cpp + src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp src/lattice.cpp diff --git a/src/cell.cpp b/src/cell.cpp index acf1473bb..2bcea24f6 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -7,8 +7,10 @@ #include "constants.h" #include "error.h" +#include "geometry.h" #include "hdf5_interface.h" #include "lattice.h" +#include "settings.h" #include "surface.h" #include "xml_interface.h" @@ -460,6 +462,9 @@ read_cells(pugi::xml_node *node) global_universes[it->second]->cells.push_back(i); } } + + // Allocate the cell overlap count if necessary. + if (openmc_check_overlaps) overlap_check_count.resize(n_cells, 0); } //============================================================================== diff --git a/src/geometry.F90 b/src/geometry.F90 index 5bf0012a3..aa2689e35 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -31,7 +31,14 @@ module geometry 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 function count_universe_instances + + function check_cell_overlap_c(p) bind(C, name="check_cell_overlap") & + result(is_overlapping) + import Particle, C_BOOL + type(Particle), intent(in) :: p + logical(C_BOOL) :: is_overlapping + end function check_cell_overlap_c end interface contains @@ -60,6 +67,9 @@ contains integer :: index_cell ! index in cells array type(Cell), pointer :: c ! pointer to cell type(Universe), pointer :: univ ! universe to search in + logical :: overlap_c + + overlap_c = check_cell_overlap_c(p) ! loop through each coordinate level n_coord = p % n_coord @@ -76,6 +86,7 @@ contains if (cell_contains(c, p)) then ! the particle should only be contained in one cell per level if (index_cell /= p % coord(j) % cell) then + if (.not. overlap_c) call fatal_error("Cell overlap disagreement") call fatal_error("Overlapping cells detected: " & &// trim(to_str(cells(index_cell) % id())) // ", " & &// trim(to_str(cells(p % coord(j) % cell) % id())) & @@ -88,6 +99,7 @@ contains end do end do + if (overlap_c) call fatal_error("Cell overlap disagreement") end subroutine check_cell_overlap diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 000000000..3c38e6716 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,52 @@ +#include "geometry.h" + +#include + +#include "cell.h" +#include "error.h" +#include "particle.h" + +//TODO: remove this include +#include + + +namespace openmc { + +std::vector overlap_check_count; + +extern "C" bool +check_cell_overlap(Particle* p) { + int n_coord = p->n_coord; + + // loop through each coordinate level + for (int j = 0; j < n_coord; j++) { + //p->n_coord = j + 1; + Universe& univ {*global_universes[p->coord[j].universe - 1]}; + int n = univ.cells.size(); + + // loop through each cell on this level + for (int i = 0; i < n; i++) { + int index_cell = univ.cells[i]; + Cell& c {*global_cells[index_cell]}; + + if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { + //TODO: off-by-one indexing + if (index_cell != p->coord[j].cell - 1) { + std::stringstream err_msg; + err_msg << "Overlapping cells detected: " << c.id << ", " + << global_cells[p->coord[j].cell-1]->id << " on universe " + << univ.id; + fatal_error(err_msg); + } + ++overlap_check_count[index_cell]; + } + } + } + + return false; +} + +extern "C" int64_t get_overlap_check_count(int i) +{return overlap_check_count[i];} + +} // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index 09e7eda8e..7d345b102 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -1,10 +1,15 @@ #ifndef OPENMC_GEOMETRY_H #define OPENMC_GEOMETRY_H +#include +#include + namespace openmc { extern "C" int openmc_root_universe; +extern std::vector overlap_check_count; + } // namespace openmc #endif // OPENMC_GEOMETRY_H diff --git a/src/output.F90 b/src/output.F90 index 49dc380a9..760a30503 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -628,6 +628,14 @@ contains subroutine print_overlap_check + interface + function get_overlap_check_count(index_cell) result(count) bind(C) + import C_INT, C_INT64_T + integer(C_INT), intent(in), value :: index_cell + integer(C_INT64_T) :: count + end function get_overlap_check_count + end interface + integer :: i, j integer :: num_sparse = 0 @@ -638,6 +646,7 @@ contains do i = 1, n_cells write(ou,101) cells(i) % id(), overlap_check_cnt(i) + write(ou,101) cells(i) % id(), get_overlap_check_count(i-1) if (overlap_check_cnt(i) < 10) num_sparse = num_sparse + 1 end do write(ou,*) From 5d9cb16dff15dce7e43cfeb984d13ad758f6589e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 14 Aug 2018 19:04:05 -0400 Subject: [PATCH 02/76] Move all cell overlap code to C++ --- CMakeLists.txt | 1 + src/geometry.F90 | 60 ++----------------------------------- src/geometry.cpp | 3 -- src/output.F90 | 45 ---------------------------- src/output.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/output.h | 26 ++++++++++++++++ src/settings.h | 3 +- src/simulation.F90 | 16 +++++----- 8 files changed, 114 insertions(+), 115 deletions(-) create mode 100644 src/output.cpp create mode 100644 src/output.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 673a71492..7543a541d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ add_library(libopenmc SHARED src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp + src/output.cpp src/particle.cpp src/plot.cpp src/position.cpp diff --git a/src/geometry.F90 b/src/geometry.F90 index aa2689e35..5d715e98b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -33,12 +33,10 @@ module geometry integer(C_INT) :: count end function count_universe_instances - function check_cell_overlap_c(p) bind(C, name="check_cell_overlap") & - result(is_overlapping) - import Particle, C_BOOL + subroutine check_cell_overlap(p) bind(C) + import Particle type(Particle), intent(in) :: p - logical(C_BOOL) :: is_overlapping - end function check_cell_overlap_c + end subroutine check_cell_overlap end interface contains @@ -51,58 +49,6 @@ contains p%coord(p%n_coord)%uvw, p%surface) end function 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 -!=============================================================================== - - subroutine check_cell_overlap(p) - - type(Particle), intent(inout) :: p - - integer :: i ! cell loop index on a level - integer :: j ! coordinate level index - integer :: n_coord ! saved number of coordinate levels - integer :: n ! number of cells to search on a level - integer :: index_cell ! index in cells array - type(Cell), pointer :: c ! pointer to cell - type(Universe), pointer :: univ ! universe to search in - logical :: overlap_c - - overlap_c = check_cell_overlap_c(p) - - ! loop through each coordinate level - n_coord = p % n_coord - do j = 1, n_coord - p % n_coord = j - univ => universes(p % coord(j) % universe) - n = size(univ % cells) - - ! loop through each cell on this level - do i = 1, n - index_cell = univ % cells(i) - c => cells(index_cell) - - if (cell_contains(c, p)) then - ! the particle should only be contained in one cell per level - if (index_cell /= p % coord(j) % cell) then - if (.not. overlap_c) call fatal_error("Cell overlap disagreement") - call fatal_error("Overlapping cells detected: " & - &// 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 - - overlap_check_cnt(index_cell) = overlap_check_cnt(index_cell) + 1 - - end if - - end do - end do - if (overlap_c) call fatal_error("Cell overlap disagreement") - - end subroutine check_cell_overlap - !=============================================================================== ! FIND_CELL determines what cell a source particle is in within a particular ! universe. If the base universe is passed, the particle should be found as long diff --git a/src/geometry.cpp b/src/geometry.cpp index 3c38e6716..7c0dd28bc 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -46,7 +46,4 @@ check_cell_overlap(Particle* p) { return false; } -extern "C" int64_t get_overlap_check_count(int i) -{return overlap_check_count[i];} - } // namespace openmc diff --git a/src/output.F90 b/src/output.F90 index 760a30503..62b3ee082 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -622,51 +622,6 @@ contains end subroutine print_results -!=============================================================================== -! PRINT_OVERLAP_DEBUG displays information regarding overlap checking results -!=============================================================================== - - subroutine print_overlap_check - - interface - function get_overlap_check_count(index_cell) result(count) bind(C) - import C_INT, C_INT64_T - integer(C_INT), intent(in), value :: index_cell - integer(C_INT64_T) :: count - end function get_overlap_check_count - end interface - - integer :: i, j - integer :: num_sparse = 0 - - ! display header block for geometry debugging section - call header("Cell Overlap Check Summary", 1) - - 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(), get_overlap_check_count(i-1) - if (overlap_check_cnt(i) < 10) num_sparse = num_sparse + 1 - end do - write(ou,*) - write(ou,'(1X,A)') 'There were ' // trim(to_str(num_sparse)) // & - ' cells with less than 10 overlap checks' - j = 0 - 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())) - if (modulo(j,8) == 0) write(ou,*) - end if - end do - write(ou,*) - -100 format (1X,A,T15,A) -101 format (1X,I8,T15,I12) - - end subroutine print_overlap_check - !=============================================================================== ! WRITE_TALLIES creates an output file and writes out the mean values of all ! tallies and their standard deviations diff --git a/src/output.cpp b/src/output.cpp new file mode 100644 index 000000000..9c1c85a9e --- /dev/null +++ b/src/output.cpp @@ -0,0 +1,75 @@ +#include "output.h" + +#include // for std::transform +#include // for strlen +#include // for setw +#include +#include + +#include "cell.h" +#include "geometry.h" +#include "message_passing.h" +#include "openmc.h" +#include "settings.h" + + +namespace openmc { + +void +header(const char* msg, int level) { + // Determine how many times to repeat the '=' character. + int n_prefix = (63 - strlen(msg)) / 2; + int n_suffix = n_prefix; + if ((strlen(msg) % 2) == 0) ++n_suffix; + + // Convert to uppercase. + std::string upper(msg); + std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper); + + // Add ===> <=== markers. + std::stringstream out; + out << ' '; + for (int i = 0; i < n_prefix; i++) out << '='; + out << "> " << upper << " <"; + for (int i = 0; i < n_suffix; i++) out << '='; + + // Print header based on verbosity level. + if (openmc_verbosity >= level) { + std::cout << out.str() << std::endl << std::endl; + } +} + +//============================================================================== + +extern "C" void +print_overlap_check() { +#ifdef OPENMC_MPI + std::vector temp(overlap_check_count); + int err = MPI_Reduce(temp.data(), overlap_check_count.data(), + overlap_check_count.size(), MPI_LONG, MPI_SUM, 0, + mpi::intracomm); +#endif + + if (openmc_master) { + header("cell overlap check summary", 1); + std::cout << " Cell ID No. Overlap Checks" << std::endl; + + std::vector sparse_cell_ids; + for (int i = 0; i < n_cells; i++) { + std::cout << " " << std::setw(8) << global_cells[i]->id << std::setw(17) + << overlap_check_count[i] << std::endl;; + if (overlap_check_count[i] < 10) { + sparse_cell_ids.push_back(global_cells[i]->id); + } + } + + std::cout << std::endl << " There were " << sparse_cell_ids.size() + << " cells with less than 10 overlap checks" << std::endl; + for (auto id : sparse_cell_ids) { + std::cout << " " << id; + } + std::cout << std::endl; + } +} + +} // namespace openmc diff --git a/src/output.h b/src/output.h new file mode 100644 index 000000000..cabd39ede --- /dev/null +++ b/src/output.h @@ -0,0 +1,26 @@ +//! \file output.h +//! Functions for ASCII output. + +#ifndef OPENMC_OUTPUT_H +#define OPENMC_OUTPUT_H + + +namespace openmc { + +//============================================================================== +//! Display a header block. +//! +//! \param msg The main text of the header +//! \param level The lowest verbosity level at which this header is printed +//============================================================================== + +void header(const char* msg, int level); + +//============================================================================== +//! Display information regarding cell overlap checking. +//============================================================================== + +extern "C" void print_overlap_check(); + +} // namespace openmc +#endif // OPENMC_OUTPUT_H diff --git a/src/settings.h b/src/settings.h index c203aafde..2bdd3bb5b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -19,6 +19,7 @@ extern "C" bool openmc_check_overlaps; extern "C" bool openmc_particle_restart_run; extern "C" bool openmc_restart_run; extern "C" bool openmc_write_all_tracks; +extern "C" int openmc_verbosity; // Defined in .cpp // TODO: Make strings instead of char* once Fortran is gone @@ -40,4 +41,4 @@ extern "C" void read_settings(pugi::xml_node* root); } // namespace openmc -#endif // OPENMC_SETTINGS_H \ No newline at end of file +#endif // OPENMC_SETTINGS_H diff --git a/src/simulation.F90 b/src/simulation.F90 index 00d558d14..5c0118530 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -24,7 +24,7 @@ module simulation use nuclide_header, only: micro_xs, n_nuclides use output, only: header, print_columns, & print_batch_keff, print_generation, print_runtime, & - print_results, print_overlap_check, write_tallies + print_results, write_tallies use particle_header use photon_header, only: micro_photon_xs, n_elements use random_lcg, only: set_particle_seed @@ -498,7 +498,6 @@ contains integer :: n ! size of arrays integer :: mpi_err ! MPI error code integer :: count_per_filter ! number of result values for one filter bin - integer(8) :: temp real(8) :: tempr(3) ! temporary array for communication #ifdef OPENMC_MPIF08 type(MPI_Datatype) :: result_block @@ -507,6 +506,11 @@ contains #endif #endif + interface + subroutine print_overlap_check() bind(C) + end subroutine print_overlap_check + end interface + err = 0 ! Skip if simulation was never run @@ -559,12 +563,6 @@ contains k_col_abs = tempr(1) k_col_tra = tempr(2) k_abs_tra = tempr(3) - - if (check_overlaps) then - call MPI_REDUCE(overlap_check_cnt, temp, n_cells, MPI_INTEGER8, & - MPI_SUM, 0, mpi_intracomm, mpi_err) - overlap_check_cnt = temp - end if #endif ! Write tally results to tallies.out @@ -576,8 +574,8 @@ contains if (master) then if (verbosity >= 6) call print_runtime() if (verbosity >= 4) call print_results() - if (check_overlaps) call print_overlap_check() end if + if (check_overlaps) call print_overlap_check() ! Reset flags need_depletion_rx = .false. From 1b3bbba41e30dc92a58aafefc06e41a47409b5bf Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Wed, 15 Aug 2018 11:49:17 -0400 Subject: [PATCH 03/76] Start implementing C++ find_cell --- src/geometry.F90 | 62 ++++++++------------------------------- src/geometry.cpp | 59 +++++++++++++++++++++++++++++++++++-- src/geometry.h | 1 + src/input_xml.F90 | 5 ---- src/settings.h | 4 ++- src/simulation_header.F90 | 6 +--- 6 files changed, 74 insertions(+), 63 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 5d715e98b..4a033c323 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -37,6 +37,15 @@ module geometry import Particle type(Particle), intent(in) :: p end subroutine check_cell_overlap + + function find_cell_c(p, n_search_cells, search_cells) & + bind(C, name="find_cell") result(found) + import Particle, C_INT, C_BOOL + type(Particle), intent(in) :: p + integer(C_INT), intent(in), value :: n_search_cells + integer(C_INT), intent(in), optional :: search_cells(n_search_cells) + logical(C_BOOL) :: found + end function find_cell_c end interface contains @@ -60,64 +69,19 @@ contains type(Particle), intent(inout) :: p logical, intent(inout) :: found integer, optional :: search_cells(:) - integer :: i ! index over cells integer :: j, k ! coordinate level index integer :: offset ! instance # of a distributed cell integer :: distribcell_index integer :: i_xyz(3) ! indices in lattice - integer :: n ! number of cells to search integer :: i_cell ! index in cells array - integer :: i_universe ! index in universes array - logical :: use_search_cells ! use cells provided as argument - do j = p % n_coord + 1, MAX_COORD - call reset_coord(p % coord(j)) - end do - j = p % n_coord - - ! Determine universe (if not yet set, use root universe) - i_universe = p % coord(j) % universe - if (i_universe == C_NONE) then - p % coord(j) % universe = root_universe - i_universe = root_universe - end if - - ! set size of list to search if (present(search_cells)) then - use_search_cells = .true. - n = size(search_cells) + found = find_cell_c(p, size(search_cells), search_cells-1) else - use_search_cells = .false. - n = size(universes(i_universe) % cells) + found = find_cell_c(p, 0) end if - - found = .false. - CELL_LOOP: do i = 1, n - ! select cells based on whether we are searching a universe or a provided - ! list of cells (this would be for lists of neighbor cells) - 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 - else - i_cell = universes(i_universe) % cells(i) - end if - - ! Move on to the next cell if the particle is not inside this cell - if (cell_contains(cells(i_cell), p)) then - ! Set cell on this level - p % coord(j) % cell = i_cell - - ! Show cell information on trace - if (verbosity >= 10 .or. trace) then - call write_message(" Entering cell " // trim(to_str(& - cells(i_cell) % id()))) - end if - - found = .true. - exit - end if - end do CELL_LOOP + j = p % n_coord + i_cell = p % coord(j) % cell if (found) then associate(c => cells(i_cell)) diff --git a/src/geometry.cpp b/src/geometry.cpp index 7c0dd28bc..4c31fe85d 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -3,8 +3,10 @@ #include #include "cell.h" +#include "constants.h" #include "error.h" #include "particle.h" +#include "settings.h" //TODO: remove this include #include @@ -20,14 +22,13 @@ check_cell_overlap(Particle* p) { // loop through each coordinate level for (int j = 0; j < n_coord; j++) { - //p->n_coord = j + 1; - Universe& univ {*global_universes[p->coord[j].universe - 1]}; + Universe& univ = *global_universes[p->coord[j].universe - 1]; int n = univ.cells.size(); // loop through each cell on this level for (int i = 0; i < n; i++) { int index_cell = univ.cells[i]; - Cell& c {*global_cells[index_cell]}; + Cell& c = *global_cells[index_cell]; if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { //TODO: off-by-one indexing @@ -46,4 +47,56 @@ check_cell_overlap(Particle* p) { return false; } +//============================================================================== + +extern "C" bool +find_cell(Particle* p, int n_search_cells, int* search_cells) { + for (int i = p->n_coord; i < MAX_COORD; i++) { + p->coord[i].reset(); + } + + // Determine universe (if not yet set, use root universe) + int i_universe = p->coord[p->n_coord-1].universe; + if (i_universe == C_NONE) { + p->coord[p->n_coord-1].universe = openmc_root_universe; + i_universe = openmc_root_universe; + } + //TODO: off-by-one indexing + --i_universe; + + // If not given a set of search cells, search all cells in the uninverse. + if (n_search_cells == 0) { + search_cells = global_universes[i_universe]->cells.data(); + n_search_cells = global_universes[i_universe]->cells.size(); + } + + // Find which cell of this universe the particle is in. + bool found = false; + for (int i = 0; i < n_search_cells; i++) { + int32_t i_cell = search_cells[i]; + + // Make sure the search cell is in the same universe + //TODO: off-by-one indexing + if (global_cells[i_cell]->universe - 1 != i_universe) continue; + + Position r {p->coord[p->n_coord-1].xyz}; + Direction u {p->coord[p->n_coord-1].uvw}; + int32_t surf = p->surface; + if (global_cells[i_cell]->contains(r, u, surf)) { + //TODO: off-by-one indexing + p->coord[p->n_coord-1].cell = i_cell + 1; + + if (openmc_verbosity >= 10 || openmc_trace) { + std::stringstream msg; + msg << " Entering cell " << global_cells[i_cell]->id; + write_message(msg, 1); + } + found = true; + break; + } + } + + return found; +} + } // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index 7d345b102..e02a17b98 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -8,6 +8,7 @@ namespace openmc { extern "C" int openmc_root_universe; +//TODO: free this memory extern std::vector overlap_check_count; } // namespace openmc diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e81bb92f7..e4302478f 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1086,11 +1086,6 @@ contains ! Allocate cells array allocate(cells(n_cells)) - if (check_overlaps) then - allocate(overlap_check_cnt(n_cells)) - overlap_check_cnt = 0 - end if - n_universes = 0 do i = 1, n_cells c => cells(i) diff --git a/src/settings.h b/src/settings.h index 2bdd3bb5b..ff6b1cf3b 100644 --- a/src/settings.h +++ b/src/settings.h @@ -18,8 +18,10 @@ namespace openmc { extern "C" bool openmc_check_overlaps; extern "C" bool openmc_particle_restart_run; extern "C" bool openmc_restart_run; -extern "C" bool openmc_write_all_tracks; +extern "C" bool openmc_trace; extern "C" int openmc_verbosity; +extern "C" bool openmc_write_all_tracks; +#pragma omp threadprivate(openmc_trace) // Defined in .cpp // TODO: Make strings instead of char* once Fortran is gone diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 60bed6425..340569402 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -67,10 +67,7 @@ module simulation_header integer :: restart_batch - ! Flag for enabling cell overlap checking during transport - integer(8), allocatable :: overlap_check_cnt(:) - - logical :: trace + logical(C_BOOL), bind(C, name='openmc_trace') :: trace !$omp threadprivate(trace, thread_id, current_work) @@ -90,7 +87,6 @@ contains !=============================================================================== subroutine free_memory_simulation() - if (allocated(overlap_check_cnt)) deallocate(overlap_check_cnt) if (allocated(entropy_p)) deallocate(entropy_p) if (allocated(source_frac)) deallocate(source_frac) if (allocated(work_index)) deallocate(work_index) From 43c554583a7606c50d6f5623fca41c649daa9b4a Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 19 Aug 2018 14:57:28 -0400 Subject: [PATCH 04/76] Move cell temperatures to C++ --- openmc/capi/cell.py | 2 +- src/api.F90 | 1 - src/cell.cpp | 63 ++++++++++++++++++ src/cell.h | 8 ++- src/geometry.F90 | 8 +-- src/geometry_aux.cpp | 31 +++++++++ src/geometry_aux.h | 6 ++ src/geometry_header.F90 | 140 ++++++++++------------------------------ src/input_xml.F90 | 87 +++---------------------- src/material.cpp | 4 ++ src/material.h | 5 ++ src/mgxs_data.F90 | 6 +- src/settings.F90 | 2 +- src/settings.h | 1 + src/summary.F90 | 7 +- 15 files changed, 171 insertions(+), 200 deletions(-) diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py index 4b994ac16..1a4c8996f 100644 --- a/openmc/capi/cell.py +++ b/openmc/capi/cell.py @@ -141,7 +141,7 @@ class Cell(_FortranObjectWithID): Which instance of the cell """ - _dll.openmc_cell_set_temperature(self._index, T, instance) + _dll.openmc_cell_set_temperature(self._index, T, c_int32(instance)) class _CellMapping(Mapping): diff --git a/src/api.F90 b/src/api.F90 index fd9733896..c8bea6583 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -38,7 +38,6 @@ module openmc_api public :: openmc_cell_filter_get_bins public :: openmc_cell_get_id public :: openmc_cell_set_id - public :: openmc_cell_set_temperature public :: openmc_energy_filter_get_bins public :: openmc_energy_filter_set_bins public :: openmc_extend_filters diff --git a/src/cell.cpp b/src/cell.cpp index 457d4050b..da5998b90 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -259,6 +259,36 @@ Cell::Cell(pugi::xml_node cell_node) } } + // Read the temperature element which may be distributed like materials. + if (check_for_node(cell_node, "temperature")) { + sqrtkT = get_node_array(cell_node, "temperature"); + sqrtkT.shrink_to_fit(); + + // Make sure this is a material-filled cell. + if (material.size() == 0) { + std::stringstream err_msg; + err_msg << "Cell " << id << " was specified with a temperature but " + "no material. Temperature specification is only valid for cells " + "filled with a material."; + fatal_error(err_msg); + } + + // Make sure all temperatures are non-negative. + for (auto T : sqrtkT) { + if (T < 0) { + std::stringstream err_msg; + err_msg << "Cell " << id + << " was specified with a negative temperature"; + fatal_error(err_msg); + } + } + + // Convert to sqrt(k*T). + for (auto& T : sqrtkT) { + T = std::sqrt(K_BOLTZMANN * T); + } + } + // Read the region specification. std::string region_spec; if (check_for_node(cell_node, "region")) { @@ -539,6 +569,35 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, return 0; } +//TODO: make sure data is loaded for this temperature +extern "C" int +openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance) +{ + if (index >= 1 && index <= global_cells.size()) { + //TODO: off-by-one + Cell& c {*global_cells[index - 1]}; + + if (instance) { + if (*instance >= 0 && *instance < c.sqrtkT.size()) { + c.sqrtkT[*instance] = std::sqrt(K_BOLTZMANN * T); + } else { + strcpy(openmc_err_msg, "Distribcell instance is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + } else { + for (auto& T_ : c.sqrtkT) { + T_ = std::sqrt(K_BOLTZMANN * T); + } + } + + } else { + strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + return 0; +} + //============================================================================== // Fortran compatibility functions //============================================================================== @@ -568,6 +627,10 @@ extern "C" { return mat + 1; } + int cell_sqrtkT_size(Cell* c) {return c->sqrtkT.size();} + + double cell_sqrtkT(Cell* c, int i) {return c->sqrtkT[i];} + 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 0b42a656c..42b34ae40 100644 --- a/src/cell.h +++ b/src/cell.h @@ -66,9 +66,15 @@ public: //! \brief Material(s) within this cell. //! - //! May be multiple materials for distribcell. C_NONE signifies a universe. + //! May be multiple materials for distribcell. std::vector material; + //! \brief Temperature(s) within this cell. + //! + //! The stored values are actually sqrt(k_Boltzmann * T) for each temperature + //! T. The units are sqrt(eV). + std::vector sqrtkT; + //! Definition of spatial region as Boolean expression of half-spaces std::vector region; //! Reverse Polish notation for region expression diff --git a/src/geometry.F90 b/src/geometry.F90 index e1e8dc7a1..60c4948bb 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -94,7 +94,7 @@ contains p % last_sqrtkT = p % sqrtkT ! Get distributed offset - if (c % material_size() > 1 .or. size(c % sqrtkT) > 1) then + if (c % material_size() > 1 .or. c % sqrtkT_size() > 1) then ! Distributed instances of this cell have different ! materials/temperatures. Determine which instance this is for ! assigning the matching material/temperature. @@ -133,10 +133,10 @@ contains end if ! Save the temperature - if (size(c % sqrtkT) > 1) then - p % sqrtkT = c % sqrtkT(offset + 1) + if (c % sqrtkT_size() > 1) then + p % sqrtkT = c % sqrtkT(offset) else - p % sqrtkT = c % sqrtkT(1) + p % sqrtkT = c % sqrtkT(0) end if elseif (c % type() == FILL_UNIVERSE) then CELL_TYPE diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 2b795d607..93c08fbe1 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -10,6 +10,7 @@ #include "geometry.h" #include "lattice.h" #include "material.h" +#include "settings.h" namespace openmc { @@ -78,6 +79,36 @@ adjust_indices() //============================================================================== +void +assign_temperatures() +{ + for (Cell* c : global_cells) { + // Ignore non-material cells and cells with defined temperature. + if (c->material.size() == 0) continue; + if (c->sqrtkT.size() > 0) continue; + + c->sqrtkT.reserve(c->material.size()); + for (auto i_mat : c->material) { + if (i_mat == MATERIAL_VOID) { + // Set void region to 0K. + c->sqrtkT.push_back(0); + + } else { + if (global_materials[i_mat]->temperature >= 0) { + // This material has a default temperature; use that value. + auto T = global_materials[i_mat]->temperature; + c->sqrtkT.push_back(std::sqrt(K_BOLTZMANN * T)); + } else { + // Use the global default temperature. + c->sqrtkT.push_back(std::sqrt(K_BOLTZMANN * temperature_default)); + } + } + } + } +} + +//============================================================================== + int32_t find_root_universe() { diff --git a/src/geometry_aux.h b/src/geometry_aux.h index fb5940d1c..fdc6a16b7 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -15,6 +15,12 @@ namespace openmc { extern "C" void adjust_indices(); +//============================================================================== +//! Assign defaults to cells with undefined temperatures. +//============================================================================== + +extern "C" void assign_temperatures(); + //============================================================================== //! Figure out which Universe is the root universe. //! diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 7714601a4..f7f533bd7 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -75,6 +75,21 @@ module geometry_header integer(C_INT32_T) :: mat end function cell_material_c + function cell_sqrtkT_size_c(cell_ptr) bind(C, name='cell_sqrtkT_size') & + result(n) + import C_PTR, C_INT + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT) :: n + end function cell_sqrtkT_size_c + + function cell_sqrtkT_c(cell_ptr, i) bind(C, name='cell_sqrtkT') & + result(sqrtkT) + import C_PTR, C_INT, C_DOUBLE + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT), intent(in), value :: i + real(C_DOUBLE) :: sqrtkT + end function cell_sqrtkT_c + function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple) import C_PTR, C_BOOL type(C_PTR), intent(in), value :: cell_ptr @@ -253,9 +268,6 @@ module geometry_header ! Boolean expression of half-spaces integer :: distribcell_index ! Index corresponding to this cell in ! distribcell arrays - real(8), allocatable :: sqrtkT(:) ! Square root of k_Boltzmann * - ! temperature in eV. Multiple for - ! distribcell ! Rotation matrix and translation vector real(8), allocatable :: translation(:) @@ -272,6 +284,8 @@ module geometry_header procedure :: n_instances => cell_n_instances procedure :: material_size => cell_material_size procedure :: material => cell_material + procedure :: sqrtkT_size => cell_sqrtkT_size + procedure :: sqrtkT => cell_sqrtkT procedure :: simple => cell_simple procedure :: distance => cell_distance procedure :: offset => cell_offset @@ -413,6 +427,19 @@ contains mat = cell_material_c(this % ptr, i) end function cell_material + function cell_sqrtkT_size(this) result(n) + class(Cell), intent(in) :: this + integer :: n + n = cell_sqrtkT_size_c(this % ptr) + end function cell_sqrtkT_size + + function cell_sqrtkT(this, i) result(sqrtkT) + class(Cell), intent(in) :: this + integer, intent(in) :: i + real(C_DOUBLE) :: sqrtkT + sqrtkT = cell_sqrtkT_c(this % ptr, i) + end function cell_sqrtkT + function cell_simple(this) result(simple) class(Cell), intent(in) :: this logical(C_BOOL) :: simple @@ -470,10 +497,10 @@ contains if (cells(i) % material(j) == MATERIAL_VOID) cycle ! Get temperature of cell (rounding to nearest integer) - if (size(cells(i) % sqrtkT) > 1) then - temperature = cells(i) % sqrtkT(j)**2 / K_BOLTZMANN + if (cells(i) % sqrtkT_size() > 1) then + temperature = cells(i) % sqrtkT(j-1)**2 / K_BOLTZMANN else - temperature = cells(i) % sqrtkT(1)**2 / K_BOLTZMANN + temperature = cells(i) % sqrtkT(0)**2 / K_BOLTZMANN end if i_material = cells(i) % material(j) @@ -626,105 +653,4 @@ contains end if end function openmc_cell_set_id - - function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) - ! Set the temperature of a cell - integer(C_INT32_T), value, intent(in) :: index ! index in cells - real(C_DOUBLE), value, intent(in) :: T ! temperature - integer(C_INT32_T), optional, intent(in) :: instance ! cell instance - - integer(C_INT) :: err ! error code - integer :: j ! looping variable - integer :: n ! number of cell instances - integer :: material_index ! material index in materials array - integer :: num_nuclides ! num nuclides in material - integer :: nuclide_index ! index of nuclide in nuclides array - real(8) :: min_temp ! min common-denominator avail temp - real(8) :: max_temp ! max common-denominator avail temp - real(8) :: temp ! actual temp we'll assign - logical :: outside_low ! lower than available data - logical :: outside_high ! higher than available data - - outside_low = .false. - outside_high = .false. - - err = E_UNASSIGNED - - if (index >= 1 .and. index <= size(cells)) then - - ! error if the cell is filled with another universe - if (cells(index) % fill() /= C_NONE) then - err = E_GEOMETRY - call set_errmsg("Cannot set temperature on a cell filled & - &with a universe.") - else - ! find which material is associated with this cell (material_index - ! is the index into the materials array) - if (present(instance)) then - material_index = cells(index) % material(instance + 1) - else - material_index = cells(index) % material(1) - end if - - ! number of nuclides associated with this material - num_nuclides = size(materials(material_index) % nuclide) - - min_temp = ZERO - max_temp = INFINITY - - do j = 1, num_nuclides - nuclide_index = materials(material_index) % nuclide(j) - min_temp = max(min_temp, minval(nuclides(nuclide_index) % kTs)) - max_temp = min(max_temp, maxval(nuclides(nuclide_index) % kTs)) - end do - - ! adjust the temperature to be within bounds if necessary - if (K_BOLTZMANN * T < min_temp) then - outside_low = .true. - temp = min_temp / K_BOLTZMANN - else if (K_BOLTZMANN * T > max_temp) then - outside_high = .true. - temp = max_temp / K_BOLTZMANN - else - temp = T - end if - - associate (c => cells(index)) - if (allocated(c % sqrtkT)) then - n = size(c % sqrtkT) - if (present(instance) .and. n > 1) then - if (instance >= 0 .and. instance < n) then - c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * temp) - err = 0 - end if - else - c % sqrtkT(:) = sqrt(K_BOLTZMANN * temp) - err = 0 - end if - end if - end associate - - ! Assign error codes for outside of temperature bounds provided the - ! temperature was changed correctly. This needs to be done after - ! changing the temperature based on the logical structure above. - if (err == 0) then - if (outside_low) then - err = E_WARNING - call set_errmsg("Nuclear data has not been loaded beyond lower & - &bound of T=" // trim(to_str(T)) // " K.") - else if (outside_high) then - err = E_WARNING - call set_errmsg("Nuclear data has not been loaded beyond upper & - &bound of T=" // trim(to_str(T)) // " K.") - end if - end if - - end if - - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in cells array is out of bounds.") - end if - end function openmc_cell_set_temperature - end module geometry_header diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 3a1c2fac2..6c26da0b0 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -56,6 +56,9 @@ module input_xml integer(C_INT), intent(in), value :: n_maps end subroutine allocate_offset_tables + subroutine assign_temperatures() bind(C) + end subroutine assign_temperatures + 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 @@ -178,7 +181,7 @@ contains call neighbor_lists() ! Assign temperatures to cells that don't have temperatures already assigned - call assign_temperatures(material_temps) + call assign_temperatures() ! Determine desired txemperatures for each nuclide and S(a,b) table call get_temperatures(nuc_temps, sab_temps) @@ -1203,40 +1206,6 @@ contains call get_node_array(node_cell, "translation", c % translation) end if - ! Read cell temperatures. If the temperature is not specified, set it to - ! a negative number for now. During initialization we'll replace - ! negatives with the temperature from the material data. - if (check_for_node(node_cell, "temperature")) then - n = node_word_count(node_cell, "temperature") - if (n > 0) then - ! Make sure this is a "normal" cell. - if (c % fill() /= C_NONE) call fatal_error("Cell " & - // trim(to_str(c % id())) // " was specified with a temperature & - &but no material. Temperature specification is only valid for & - &cells filled with a material.") - - ! Copy in temperatures - allocate(c % sqrtkT(n)) - call get_node_array(node_cell, "temperature", c % sqrtkT) - - ! 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 & - &temperature. All cell temperatures must be non-negative.") - end do - - ! Convert to sqrt(kT) - c % sqrtkT(:) = sqrt(K_BOLTZMANN * c % sqrtkT(:)) - else - allocate(c % sqrtkT(1)) - c % sqrtkT(1) = -1.0 - end if - else - allocate(c % sqrtkT(1)) - c % sqrtkT = -1.0 - end if - ! Add cell to dictionary call cell_dict % set(c % id(), i) @@ -3796,46 +3765,6 @@ contains end subroutine read_ce_cross_sections -!=============================================================================== -! ASSIGN_TEMPERATURES If any cells have undefined temperatures, try to find -! their temperatures from material or global default temperatures -!=============================================================================== - - subroutine assign_temperatures(material_temps) - real(8), intent(in) :: material_temps(:) - - integer :: i, j - integer :: i_material - - do i = 1, n_cells - ! Ignore non-normal cells and cells with defined temperature. - if (cells(i) % fill() /= C_NONE) cycle - if (cells(i) % sqrtkT(1) >= ZERO) cycle - - ! Set the number of temperatures equal to the number of materials. - deallocate(cells(i) % sqrtkT) - allocate(cells(i) % sqrtkT(cells(i) % material_size())) - - ! Check each of the cell materials for temperature data. - do j = 1, cells(i) % material_size() - ! Arbitrarily set void regions to 0K. - if (cells(i) % material(j) == MATERIAL_VOID) then - cells(i) % sqrtkT(j) = ZERO - cycle - end if - - ! Use material default or global default temperature - i_material = cells(i) % material(j) - if (material_temps(i_material) >= ZERO) then - cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * & - material_temps(i_material)) - else - cells(i) % sqrtkT(j) = sqrt(K_BOLTZMANN * temperature_default) - end if - end do - end do - end subroutine assign_temperatures - !=============================================================================== ! READ_MULTIPOLE_DATA checks for the existence of a multipole library in the ! directory and loads it using multipole_read @@ -3908,7 +3837,7 @@ contains ! Find all cells with multiple (distributed) materials or temperatures. do i = 1, n_cells - if (cells(i) % material_size() > 1 .or. size(cells(i) % sqrtkT) > 1) then + if (cells(i) % material_size() > 1 .or. cells(i) % sqrtkT_size() > 1) then call cell_list % add(i) end if end do @@ -3926,10 +3855,10 @@ contains &equal one or the number of instances.") end if end if - if (size(c % sqrtkT) > 1) then - if (size(c % sqrtkT) /= c % n_instances()) then + if (c % sqrtkT_size() > 1) then + if (c % sqrtkT_size() /= c % n_instances()) then call fatal_error("Cell " // trim(to_str(c % id())) // " was & - &specified with " // trim(to_str(size(c % sqrtkT))) & + &specified with " // trim(to_str(c % sqrtkT_size())) & // " temperatures but has " // trim(to_str(c % n_instances()))& // " distributed instances. The number of temperatures must & &equal one or the number of instances.") diff --git a/src/material.cpp b/src/material.cpp index c9ef47f07..f98a2c40a 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -27,6 +27,10 @@ Material::Material(pugi::xml_node material_node) } else { fatal_error("Must specify id of material in materials XML file."); } + + if (check_for_node(material_node, "temperature")) { + temperature = std::stod(get_node_value(material_node, "temperature")); + } } //============================================================================== diff --git a/src/material.h b/src/material.h index 0a9a099a4..3ccaf1e0b 100644 --- a/src/material.h +++ b/src/material.h @@ -26,6 +26,11 @@ class Material public: int32_t id; //!< Unique ID + //! \brief Default temperature for cells containing this material. + //! + //! A negative value indicates no default temperature was specified. + double temperature {-1}; + Material() {}; explicit Material(pugi::xml_node material_node); diff --git a/src/mgxs_data.F90 b/src/mgxs_data.F90 index b95c3a877..03a0e9402 100644 --- a/src/mgxs_data.F90 +++ b/src/mgxs_data.F90 @@ -160,10 +160,10 @@ contains if (cells(i) % material(j) == MATERIAL_VOID) cycle ! Get temperature of cell (rounding to nearest integer) - if (size(cells(i) % sqrtkT) > 1) then - kT = cells(i) % sqrtkT(j)**2 + if (cells(i) % sqrtkT_size() > 1) then + kT = cells(i) % sqrtkT(j-1)**2 else - kT = cells(i) % sqrtkT(1)**2 + kT = cells(i) % sqrtkT(0)**2 end if i_material = cells(i) % material(j) diff --git a/src/settings.F90 b/src/settings.F90 index 972eba1d5..cb0a55622 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -21,7 +21,7 @@ module settings integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST logical :: temperature_multipole = .false. real(C_DOUBLE) :: temperature_tolerance = 10.0_8 - real(8) :: temperature_default = 293.6_8 + real(C_DOUBLE), bind(C) :: temperature_default = 293.6_8 real(8) :: temperature_range(2) = [ZERO, ZERO] integer :: n_log_bins ! number of bins for logarithmic grid diff --git a/src/settings.h b/src/settings.h index ff6b1cf3b..5c7bf2c84 100644 --- a/src/settings.h +++ b/src/settings.h @@ -21,6 +21,7 @@ extern "C" bool openmc_restart_run; extern "C" bool openmc_trace; extern "C" int openmc_verbosity; extern "C" bool openmc_write_all_tracks; +extern "C" double temperature_default; #pragma omp threadprivate(openmc_trace) // Defined in .cpp diff --git a/src/summary.F90 b/src/summary.F90 index 13bc42663..6c311e982 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -218,9 +218,10 @@ contains deallocate(cell_materials) end if - allocate(cell_temperatures(size(c % sqrtkT))) - cell_temperatures(:) = c % sqrtkT(:) - cell_temperatures(:) = cell_temperatures(:)**2 / K_BOLTZMANN + allocate(cell_temperatures(c % sqrtkT_size())) + do j = 1, c % sqrtkT_size() + cell_temperatures(j) = c % sqrtkT(j-1)**2 / K_BOLTZMANN + end do call write_dataset(cell_group, "temperature", cell_temperatures) deallocate(cell_temperatures) From ef8bf2b8204df6f2cf76861ce9d924f64346b2fa Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 19 Aug 2018 18:39:28 -0400 Subject: [PATCH 05/76] Move Cell.distribcell_index to C++ --- src/cell.cpp | 3 +- src/cell.h | 4 + src/geometry.F90 | 2 +- src/geometry_aux.cpp | 100 +++++++++++++++++------ src/geometry_aux.h | 13 +-- src/geometry_header.F90 | 16 +++- src/input_xml.F90 | 81 ++++-------------- src/tallies/tally_filter_distribcell.F90 | 4 +- 8 files changed, 114 insertions(+), 109 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index da5998b90..a68ab9d0b 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -4,7 +4,6 @@ #include #include -#include "constants.h" #include "error.h" #include "geometry.h" #include "hdf5_interface.h" @@ -617,6 +616,8 @@ extern "C" { int32_t cell_n_instances(Cell* c) {return c->n_instances;} + int cell_distribcell_index(Cell* c) {return c->distribcell_index;} + int cell_material_size(Cell* c) {return c->material.size();} //TODO: off-by-one diff --git a/src/cell.h b/src/cell.h index 42b34ae40..8b7c3a78b 100644 --- a/src/cell.h +++ b/src/cell.h @@ -7,6 +7,7 @@ #include #include +#include "constants.h" #include "hdf5.h" #include "pugixml.hpp" @@ -64,6 +65,9 @@ public: int32_t fill; //!< Universe # filling this cell int32_t n_instances{0}; //!< Number of instances of this cell + //! \brief Index corresponding to this cell in distribcell arrays + int distribcell_index{C_NONE}; + //! \brief Material(s) within this cell. //! //! May be multiple materials for distribcell. diff --git a/src/geometry.F90 b/src/geometry.F90 index 60c4948bb..f717810bb 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -98,7 +98,7 @@ contains ! Distributed instances of this cell have different ! materials/temperatures. Determine which instance this is for ! assigning the matching material/temperature. - distribcell_index = c % distribcell_index + distribcell_index = c % distribcell_index() offset = 0 do k = 1, p % n_coord if (cells(p % coord(k) % cell) % type() == FILL_UNIVERSE) then diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 93c08fbe1..6d7d5badb 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -153,17 +153,90 @@ find_root_universe() //============================================================================== void -allocate_offset_tables(int n_maps) +prepare_distribcell(int32_t* filter_cell_list, int n) { + // Read the list of cells contained in distribcell filters from Fortran. + std::unordered_set distribcells; + for (int i = 0; i < n; i++) { + distribcells.insert(filter_cell_list[i]); + } + + // Find all cells with distributed materials or temperatures. Make sure that + // the number of materials/temperatures matches the number of cell instances. + for (int i = 0; i < global_cells.size(); i++) { + Cell& c {*global_cells[i]}; + + if (c.material.size() > 1) { + if (c.material.size() != c.n_instances) { + std::stringstream err_msg; + err_msg << "Cell " << c.id << " was specified with " + << c.material.size() << " materials but has " << c.n_instances + << " distributed instances. The number of materials must equal " + "one or the number of instances."; + fatal_error(err_msg); + } + distribcells.insert(i); + } + + if (c.sqrtkT.size() > 1) { + if (c.sqrtkT.size() != c.n_instances) { + std::stringstream err_msg; + err_msg << "Cell " << c.id << " was specified with " + << c.sqrtkT.size() << " temperatures but has " << c.n_instances + << " distributed instances. The number of temperatures must equal " + "one or the number of instances."; + fatal_error(err_msg); + } + distribcells.insert(i); + } + } + + // Search through universes for distributed cells and assign each one a + // unique distribcell array index. + //TODO: off-by-one + int distribcell_index = 1; + std::vector target_univ_ids; + for (Universe* u : global_universes) { + for (auto cell_indx : u->cells) { + if (distribcells.find(cell_indx) != distribcells.end()) { + global_cells[cell_indx]->distribcell_index = distribcell_index; + target_univ_ids.push_back(u->id); + ++distribcell_index; + } + } + } + + // Allocate the cell and lattice offset tables. + int n_maps = target_univ_ids.size(); for (Cell* c : global_cells) { if (c->type != FILL_MATERIAL) { c->offset.resize(n_maps, C_NONE); } } - for (Lattice* lat : lattices_c) { lat->allocate_offset_table(n_maps); } + + // Fill the cell and lattice offset tables. + for (int map = 0; map < target_univ_ids.size(); map++) { + auto target_univ_id = target_univ_ids[map]; + 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 = *global_cells[cell_indx]; + + if (c.type == FILL_UNIVERSE) { + c.offset[map] = offset; + 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]; + offset = lat.fill_offset_table(offset, target_univ_id, map); + } + } + } + } } //============================================================================== @@ -221,29 +294,6 @@ 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 : global_universes) { - int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation. - for (int32_t cell_indx : univ->cells) { - Cell& c = *global_cells[cell_indx]; - - if (c.type == FILL_UNIVERSE) { - c.offset[map] = offset; - 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]; - offset = lat.fill_offset_table(offset, target_univ_id, map); - } - } - } -} - -//============================================================================== - std::string distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, const Universe& search_univ, int32_t offset) diff --git a/src/geometry_aux.h b/src/geometry_aux.h index fdc6a16b7..e3fd034c6 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -32,10 +32,10 @@ extern "C" void assign_temperatures(); extern "C" int32_t find_root_universe(); //============================================================================== -//! Allocate storage in Lattice and Cell objects for distribcell offset tables. +//! Populate all data structures needed for distribcells. //============================================================================== -extern "C" void allocate_offset_tables(int n_maps); +extern "C" void prepare_distribcell(int32_t* filter_cell_list, int n); //============================================================================== //! Recursively search through the geometry and count cell instances. @@ -59,15 +59,6 @@ extern "C" void count_cell_instances(int32_t univ_indx); 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); - //============================================================================== //! 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. diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index f7f533bd7..272966b33 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -60,6 +60,13 @@ module geometry_header integer(C_INT32_T) :: n_instances end function cell_n_instances_c + function cell_distribcell_index_c(cell_ptr) & + bind(C, name='cell_distribcell_index') result(distribcell_index) + import C_PTR, C_INT + type(C_PTR), intent(in), value :: cell_ptr + integer(C_INT) :: distribcell_index + end function cell_distribcell_index_c + function cell_material_size_c(cell_ptr) bind(C, name='cell_material_size') & result(n) import C_PTR, C_INT @@ -266,8 +273,6 @@ module geometry_header integer, allocatable :: region(:) ! Definition of spatial region as ! Boolean expression of half-spaces - integer :: distribcell_index ! Index corresponding to this cell in - ! distribcell arrays ! Rotation matrix and translation vector real(8), allocatable :: translation(:) @@ -282,6 +287,7 @@ module geometry_header procedure :: universe => cell_universe procedure :: fill => cell_fill procedure :: n_instances => cell_n_instances + procedure :: distribcell_index => cell_distribcell_index procedure :: material_size => cell_material_size procedure :: material => cell_material procedure :: sqrtkT_size => cell_sqrtkT_size @@ -414,6 +420,12 @@ contains n_instances = cell_n_instances_c(this % ptr) end function cell_n_instances + function cell_distribcell_index(this) result(distribcell_index) + class(Cell), intent(in) :: this + integer(C_INT) :: distribcell_index + distribcell_index = cell_distribcell_index_c(this % ptr) + end function cell_distribcell_index + function cell_material_size(this) result(n) class(Cell), intent(in) :: this integer(C_INT) :: n diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 6c26da0b0..7d8a8393d 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -51,25 +51,21 @@ module input_xml subroutine adjust_indices() bind(C) end subroutine adjust_indices - 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 assign_temperatures() bind(C) end subroutine assign_temperatures - 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 count_cell_instances + subroutine prepare_distribcell_c(cell_list, n) & + bind(C, name="prepare_distribcell") + import C_INT32_T, C_INT + integer(C_INT), intent(in), value :: n + integer(C_INT32_T), intent(in) :: cell_list(n) + end subroutine prepare_distribcell_c + subroutine read_surfaces(node_ptr) bind(C) import C_PTR type(C_PTR) :: node_ptr @@ -1007,7 +1003,7 @@ contains subroutine read_geometry_xml() integer :: i, j, k - integer :: n, n_mats, n_rlats, n_hlats + integer :: n, n_rlats, n_hlats integer :: id integer :: univ_id integer :: n_cells_in_univ @@ -1015,7 +1011,6 @@ contains logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename - character(MAX_WORD_LEN), allocatable :: sarray(:) character(:), allocatable :: region_spec type(Cell), pointer :: c class(Lattice), pointer :: lat @@ -1100,9 +1095,6 @@ contains c % ptr = cell_pointer(i - 1) - ! Initialize distribcell instances and distribcell index - c % distribcell_index = NONE - ! Get pointer to i-th cell node node_cell = node_cell_list(i) @@ -3821,9 +3813,9 @@ contains subroutine prepare_distribcell() - integer :: i, j, k + integer :: i, j type(SetInt) :: cell_list ! distribcells to track - type(ListInt) :: univ_list ! universes containing distribcells + integer(C_INT32_T), allocatable :: cell_list_c(:) ! Find all cells listed in a distribcell filter. do i = 1, n_tallies @@ -3835,56 +3827,11 @@ contains end do end do - ! Find all cells with multiple (distributed) materials or temperatures. - do i = 1, n_cells - if (cells(i) % material_size() > 1 .or. cells(i) % sqrtkT_size() > 1) then - call cell_list % add(i) - end if - end do - - ! 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 (c % material_size() > 1) then - if (c % material_size() /= c % n_instances()) then - call fatal_error("Cell " // trim(to_str(c % id())) // " was & - &specified with " // trim(to_str(c % material_size())) & - // " 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 (c % sqrtkT_size() > 1) then - if (c % sqrtkT_size() /= c % n_instances()) then - call fatal_error("Cell " // trim(to_str(c % id())) // " was & - &specified with " // trim(to_str(c % sqrtkT_size())) & - // " 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 - end if - end associate - end do - - ! Search through universes for distributed cells and assign each one a - ! unique distribcell array index. - k = 1 - do i = 1, n_universes - do j = 1, size(universes(i) % cells) - if (cell_list % contains(universes(i) % cells(j))) then - cells(universes(i) % cells(j)) % distribcell_index = k - call univ_list % append(universes(i) % id) - k = k + 1 - end if - end do - end do - - ! 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) + allocate(cell_list_c(cell_list % size())) + do i = 1, cell_list % size() + cell_list_c(i) = cell_list % get_item(i) - 1 end do + call prepare_distribcell_c(cell_list_c, cell_list % size()) end subroutine prepare_distribcell diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index c9564083d..9ef282126 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -54,7 +54,7 @@ contains integer :: distribcell_index, offset, i - distribcell_index = cells(this % cell) % distribcell_index + 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 @@ -154,7 +154,7 @@ contains end interface ! Get the distribcell index for this cell - map = cells(i_cell) % distribcell_index + map = cells(i_cell) % distribcell_index() path_len = distribcell_path_len(i_cell-1, map-1, target_offset, & root_universe-1) From cb5db790d776fe6fb96c29c0d73b32aabe5c76ad Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 12:24:08 -0400 Subject: [PATCH 06/76] Move FILL_MATERIAL chunk of find_cell to C++ --- src/geometry.F90 | 60 ++--------------------------------------------- src/geometry.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++--- src/geometry.h | 17 +++++++++++++- 3 files changed, 76 insertions(+), 62 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index f717810bb..29e03bbb5 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -69,9 +69,7 @@ contains type(Particle), intent(inout) :: p logical, intent(inout) :: found integer, optional :: search_cells(:) - integer :: j, k ! coordinate level index - integer :: offset ! instance # of a distributed cell - integer :: distribcell_index + integer :: j ! coordinate level index integer :: i_xyz(3) ! indices in lattice integer :: i_cell ! index in cells array @@ -85,61 +83,7 @@ contains if (found) then associate(c => cells(i_cell)) - CELL_TYPE: if (c % type() == FILL_MATERIAL) then - ! ====================================================================== - ! AT LOWEST UNIVERSE, TERMINATE SEARCH - - ! Save previous material and temperature - p % last_material = p % material - p % last_sqrtkT = p % sqrtkT - - ! Get distributed offset - if (c % material_size() > 1 .or. c % sqrtkT_size() > 1) then - ! Distributed instances of this cell have different - ! materials/temperatures. Determine which instance this is for - ! assigning the matching material/temperature. - distribcell_index = c % distribcell_index() - 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-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 - 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 - - ! Keep track of which instance of the cell the particle is in - p % cell_instance = offset + 1 - else - p % cell_instance = 1 - end if - - ! Save the material - if (c % material_size() > 1) then - p % material = c % material(offset + 1) - else - p % material = c % material(1) - end if - - ! Save the temperature - if (c % sqrtkT_size() > 1) then - p % sqrtkT = c % sqrtkT(offset) - else - p % sqrtkT = c % sqrtkT(0) - end if - - elseif (c % type() == FILL_UNIVERSE) then CELL_TYPE + CELL_TYPE: if (c % type() == FILL_UNIVERSE) then ! ====================================================================== ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL diff --git a/src/geometry.cpp b/src/geometry.cpp index 4c31fe85d..7131a4513 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -5,7 +5,7 @@ #include "cell.h" #include "constants.h" #include "error.h" -#include "particle.h" +#include "lattice.h" #include "settings.h" //TODO: remove this include @@ -16,6 +16,8 @@ namespace openmc { std::vector overlap_check_count; +//============================================================================== + extern "C" bool check_cell_overlap(Particle* p) { int n_coord = p->n_coord; @@ -72,10 +74,11 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { // Find which cell of this universe the particle is in. bool found = false; + int32_t i_cell; for (int i = 0; i < n_search_cells; i++) { - int32_t i_cell = search_cells[i]; + i_cell = search_cells[i]; - // Make sure the search cell is in the same universe + // Make sure the search cell is in the same universe. //TODO: off-by-one indexing if (global_cells[i_cell]->universe - 1 != i_universe) continue; @@ -96,6 +99,58 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { } } + if (found) { + Cell& c {*global_cells[i_cell]}; + if (c.type == FILL_MATERIAL) { + // Find the distribcell instance number. + if (c.material.size() > 1 || c.sqrtkT.size() > 1) { + //===================================================================== + //! Found a material cell which means this is the lowest coord level. + + //TODO: off-by-one indexing + int distribcell_index = c.distribcell_index - 1; + int offset = 0; + for (int i = 0; i < p->n_coord; i++) { + Cell& c_i {*global_cells[p->coord[i].cell-1]}; + if (c_i.type == FILL_UNIVERSE) { + offset += c_i.offset[distribcell_index]; + } else if (c_i.type == FILL_LATTICE) { + Lattice& lat {*lattices_c[p->coord[i+1].lattice-1]}; + int i_xyz[3] {p->coord[i+1].lattice_x, + p->coord[i+1].lattice_y, + p->coord[i+1].lattice_z}; + if (lat.are_valid_indices(i_xyz)) { + offset += lat.offset(distribcell_index, i_xyz); + } + } + } + p->cell_instance = offset + 1; + } else { + p->cell_instance = 1; + } + + // Set the material and temperature. + p->last_material = p->material; + int32_t mat; + if (c.material.size() > 1) { + mat = c.material[p->cell_instance-1]; + } else { + mat = c.material[0]; + } + if (mat == MATERIAL_VOID) { + p->material = MATERIAL_VOID; + } else { + p->material = mat + 1; + } + p->last_sqrtkT = p->sqrtkT; + if (c.sqrtkT.size() > 1) { + p->sqrtkT = c.sqrtkT[p->cell_instance-1]; + } else { + p->sqrtkT = c.sqrtkT[0]; + } + } + } + return found; } diff --git a/src/geometry.h b/src/geometry.h index e02a17b98..b73ae314c 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -4,13 +4,28 @@ #include #include +#include "particle.h" + namespace openmc { extern "C" int openmc_root_universe; -//TODO: free this memory extern std::vector overlap_check_count; +//============================================================================== +//! Check for overlapping cells at the particle's position. +//============================================================================== + +extern "C" bool +check_cell_overlap(Particle* p); + +//============================================================================== +//! Locate the particle in the geometry tree and set its geometry data fields. +//============================================================================== + +extern "C" bool +find_cell(Particle* p, int n_search_cells, int* search_cells); + } // namespace openmc #endif // OPENMC_GEOMETRY_H From 2ed0fceb7d4eb919e8b40b870727225c69a02ea4 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 14:31:31 -0400 Subject: [PATCH 07/76] Make translation and rotation tests more thorough --- tests/regression_tests/rotation/geometry.xml | 10 +++++----- tests/regression_tests/rotation/materials.xml | 7 ++++++- tests/regression_tests/rotation/results_true.dat | 2 +- tests/regression_tests/translation/geometry.xml | 10 +++++----- tests/regression_tests/translation/materials.xml | 7 ++++++- tests/regression_tests/translation/results_true.dat | 2 +- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/tests/regression_tests/rotation/geometry.xml b/tests/regression_tests/rotation/geometry.xml index 222617877..f32461706 100644 --- a/tests/regression_tests/rotation/geometry.xml +++ b/tests/regression_tests/rotation/geometry.xml @@ -1,11 +1,11 @@ - - - + + - - + + + diff --git a/tests/regression_tests/rotation/materials.xml b/tests/regression_tests/rotation/materials.xml index 2472a7471..160c9c678 100644 --- a/tests/regression_tests/rotation/materials.xml +++ b/tests/regression_tests/rotation/materials.xml @@ -2,8 +2,13 @@ - + + + + + + diff --git a/tests/regression_tests/rotation/results_true.dat b/tests/regression_tests/rotation/results_true.dat index 5cb3925a6..7598a4a47 100644 --- a/tests/regression_tests/rotation/results_true.dat +++ b/tests/regression_tests/rotation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.943619E-01 3.309646E-03 +4.240695E-01 8.013236E-03 diff --git a/tests/regression_tests/translation/geometry.xml b/tests/regression_tests/translation/geometry.xml index e2cdf2391..6c6343865 100644 --- a/tests/regression_tests/translation/geometry.xml +++ b/tests/regression_tests/translation/geometry.xml @@ -1,11 +1,11 @@ - - - + + - - + + + diff --git a/tests/regression_tests/translation/materials.xml b/tests/regression_tests/translation/materials.xml index 2472a7471..160c9c678 100644 --- a/tests/regression_tests/translation/materials.xml +++ b/tests/regression_tests/translation/materials.xml @@ -2,8 +2,13 @@ - + + + + + + diff --git a/tests/regression_tests/translation/results_true.dat b/tests/regression_tests/translation/results_true.dat index 5cb3925a6..a50311034 100644 --- a/tests/regression_tests/translation/results_true.dat +++ b/tests/regression_tests/translation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.943619E-01 3.309646E-03 +4.101355E-01 1.577552E-02 From cddf39b201eb152f89a3ebed536fd36ba1797c39 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 19:52:07 -0400 Subject: [PATCH 08/76] Move FILL_UNIVERSE chunk of find_cell to C++ --- src/cell.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++ src/cell.h | 10 +++++++ src/geometry.F90 | 22 --------------- src/geometry.cpp | 48 ++++++++++++++++++++++++++++++-- src/input_xml.F90 | 22 --------------- src/position.h | 19 ++++++++++++- src/summary.F90 | 11 -------- 7 files changed, 144 insertions(+), 59 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index a68ab9d0b..9786a89fc 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -317,6 +317,65 @@ Cell::Cell(pugi::xml_node cell_node) break; } } + + // Read the translation vector. + if (check_for_node(cell_node, "translation")) { + if (fill == C_NONE) { + std::stringstream err_msg; + err_msg << "Cannot apply a translation to cell " << id + << " because it is not filled with another universe"; + fatal_error(err_msg); + } + + auto xyz {get_node_array(cell_node, "translation")}; + if (xyz.size() != 3) { + std::stringstream err_msg; + err_msg << "Non-3D translation vector applied to cell " << id; + fatal_error(err_msg); + } + translation = xyz; + } + + // Read the rotation transform. + if (check_for_node(cell_node, "rotation")) { + if (fill == C_NONE) { + std::stringstream err_msg; + err_msg << "Cannot apply a rotation to cell " << id + << " because it is not filled with another universe"; + fatal_error(err_msg); + } + + auto rot {get_node_array(cell_node, "rotation")}; + if (rot.size() != 3) { + std::stringstream err_msg; + err_msg << "Non-3D rotation vector applied to cell " << id; + fatal_error(err_msg); + } + + // Store the rotation angles. + rotation.reserve(12); + rotation.push_back(rot[0]); + rotation.push_back(rot[1]); + rotation.push_back(rot[2]); + + // Compute and store the rotation matrix. + auto phi = -rot[0] * PI / 180.0; + auto theta = -rot[1] * PI / 180.0; + auto psi = -rot[2] * PI / 180.0; + rotation.push_back(std::cos(theta) * std::cos(psi)); + rotation.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation.push_back(std::cos(theta) * std::sin(psi)); + rotation.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation.push_back(-std::sin(theta)); + rotation.push_back(std::sin(phi) * std::cos(theta)); + rotation.push_back(std::cos(phi) * std::cos(theta)); + } } //============================================================================== @@ -393,6 +452,18 @@ Cell::to_hdf5(hid_t cell_group) const } write_string(cell_group, "region", region_spec.str(), false); } + + if (type == FILL_UNIVERSE) { + write_dataset(cell_group, "fill_type", "universe"); + write_dataset(cell_group, "fill", global_universes[fill]->id); + if (translation != 0) { + write_dataset(cell_group, "translation", translation); + } + if (!rotation.empty()) { + std::array rot {rotation[0], rotation[1], rotation[2]}; + write_dataset(cell_group, "rotation", rot); + } + } } //============================================================================== diff --git a/src/cell.h b/src/cell.h index 8b7c3a78b..4f3a8978f 100644 --- a/src/cell.h +++ b/src/cell.h @@ -85,6 +85,16 @@ public: std::vector rpn; bool simple; //!< Does the region contain only intersections? + Position translation {0, 0, 0}; //!< Translation vector for filled universe + + //! \brief Rotational tranfsormation of the filled universe. + // + //! The vector is empty if there is no rotation. Otherwise, the first three + //! values are the rotation angles respectively about the x-, y-, and z-, axes + //! in degrees. The next 9 values give the rotation matrix in row-major + //! order. + std::vector rotation; + std::vector offset; //!< Distribcell offset table Cell() {}; diff --git a/src/geometry.F90 b/src/geometry.F90 index 29e03bbb5..817da18de 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -84,30 +84,8 @@ contains if (found) then associate(c => cells(i_cell)) CELL_TYPE: if (c % type() == FILL_UNIVERSE) then - ! ====================================================================== - ! CELL CONTAINS LOWER UNIVERSE, RECURSIVELY FIND CELL - - ! Store lower level coordinates - p % coord(j + 1) % xyz = p % coord(j) % xyz - p % coord(j + 1) % uvw = p % coord(j) % uvw - - ! Move particle to next level and set universe j = j + 1 p % n_coord = j - p % coord(j) % universe = c % fill() + 1 - - ! Apply translation - if (allocated(c % translation)) then - p % coord(j) % xyz = p % coord(j) % xyz - c % translation - end if - - ! Apply rotation - if (allocated(c % rotation_matrix)) then - p % coord(j) % xyz = matmul(c % rotation_matrix, p % coord(j) % xyz) - p % coord(j) % uvw = matmul(c % rotation_matrix, p % coord(j) % uvw) - p % coord(j) % rotated = .true. - end if - call find_cell(p, found) j = p % n_coord diff --git a/src/geometry.cpp b/src/geometry.cpp index 7131a4513..695afe0be 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -102,11 +102,11 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { if (found) { Cell& c {*global_cells[i_cell]}; if (c.type == FILL_MATERIAL) { + //======================================================================= + //! Found a material cell which means this is the lowest coord level. + // Find the distribcell instance number. if (c.material.size() > 1 || c.sqrtkT.size() > 1) { - //===================================================================== - //! Found a material cell which means this is the lowest coord level. - //TODO: off-by-one indexing int distribcell_index = c.distribcell_index - 1; int offset = 0; @@ -148,6 +148,48 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { } else { p->sqrtkT = c.sqrtkT[0]; } + + } else if (c.type == FILL_UNIVERSE) { + //======================================================================== + //! Found a lower universe, update this coord level then search the next. + + // Add another coordinate level. + //++p->n_coord; + p->coord[p->n_coord].universe = c.fill + 1; + + // Set the position and direction. + for (int i = 0; i < 3; i++) { + p->coord[p->n_coord].xyz[i] = p->coord[p->n_coord-1].xyz[i]; + p->coord[p->n_coord].uvw[i] = p->coord[p->n_coord-1].uvw[i]; + } + + // Apply translation. + p->coord[p->n_coord].xyz[0] -= c.translation.x; + p->coord[p->n_coord].xyz[1] -= c.translation.y; + p->coord[p->n_coord].xyz[2] -= c.translation.z; + + // Apply rotation. + if (!c.rotation.empty()) { + auto x = p->coord[p->n_coord].xyz[0]; + auto y = p->coord[p->n_coord].xyz[1]; + auto z = p->coord[p->n_coord].xyz[2]; + p->coord[p->n_coord].xyz[0] = x*c.rotation[3] + y*c.rotation[4] + + z*c.rotation[5]; + p->coord[p->n_coord].xyz[1] = x*c.rotation[6] + y*c.rotation[7] + + z*c.rotation[8]; + p->coord[p->n_coord].xyz[2] = x*c.rotation[9] + y*c.rotation[10] + + z*c.rotation[11]; + auto u = p->coord[p->n_coord].uvw[0]; + auto v = p->coord[p->n_coord].uvw[1]; + auto w = p->coord[p->n_coord].uvw[2]; + p->coord[p->n_coord].uvw[0] = u*c.rotation[3] + v*c.rotation[4] + + w*c.rotation[5]; + p->coord[p->n_coord].uvw[1] = u*c.rotation[6] + v*c.rotation[7] + + w*c.rotation[8]; + p->coord[p->n_coord].uvw[2] = u*c.rotation[9] + v*c.rotation[10] + + w*c.rotation[11]; + p->coord[p->n_coord].rotated = true; + } } } diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 7d8a8393d..27b8be946 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1176,28 +1176,6 @@ contains cos(phi)*cos(theta) /), (/ 3,3 /)) end if - ! Translation vector - 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() == 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") - end if - - ! Read number of translation parameters - 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())) - end if - - ! Copy translation vector - allocate(c % translation(3)) - call get_node_array(node_cell, "translation", c % translation) - end if - ! Add cell to dictionary call cell_dict % set(c % id(), i) diff --git a/src/position.h b/src/position.h index 808e0bcf6..62af3a122 100644 --- a/src/position.h +++ b/src/position.h @@ -1,6 +1,8 @@ #ifndef OPENMC_POSITION_H #define OPENMC_POSITION_H +#include + namespace openmc { //============================================================================== @@ -12,6 +14,7 @@ struct Position { Position() = default; Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; + Position(const std::vector xyz) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; // Unary operators Position& operator+=(Position); @@ -63,6 +66,20 @@ inline Position operator*(Position a, Position b) { return a *= b; } inline Position operator*(Position a, double b) { return a *= b; } inline Position operator*(double a, Position b) { return b *= a; } +inline bool operator==(Position a, Position b) +{return a.x == b.x && a.y == b.y && a.z == b.z;} +inline bool operator==(Position a, double b) +{return a.x == b && a.y == b && a.z == b;} +inline bool operator==(double a, Position b) +{return a == b.x && a == b.y && a == b.z;} + +inline bool operator!=(Position a, Position b) +{return a.x != b.x || a.y != b.y || a.z != b.z;} +inline bool operator!=(Position a, double b) +{return a.x != b || a.y != b || a.z != b;} +inline bool operator!=(double a, Position b) +{return a != b.x || a != b.y || a != b.z;} + //============================================================================== //! Type representing a vector direction in Cartesian coordinates //============================================================================== @@ -71,4 +88,4 @@ using Direction = Position; } // namespace openmc -#endif // OPENMC_POSITION_H \ No newline at end of file +#endif // OPENMC_POSITION_H diff --git a/src/summary.F90 b/src/summary.F90 index 6c311e982..e2cc5f786 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -225,17 +225,6 @@ contains call write_dataset(cell_group, "temperature", cell_temperatures) deallocate(cell_temperatures) - case (FILL_UNIVERSE) - call write_dataset(cell_group, "fill_type", "universe") - call write_dataset(cell_group, "fill", universes(c%fill()+1)%id) - - if (allocated(c%translation)) then - call write_dataset(cell_group, "translation", c%translation) - end if - if (allocated(c%rotation)) then - call write_dataset(cell_group, "rotation", c%rotation) - end if - case (FILL_LATTICE) call write_dataset(cell_group, "fill_type", "lattice") ! Do not access the 'lattices' array with 'c % fill() + 1' directly; it From 918735732a7acf9f9453555ea4dcafe2f8f5d0d4 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 20:39:55 -0400 Subject: [PATCH 09/76] Move FILL_LATTICE chunk of find_cell to C++ --- src/geometry.F90 | 63 ----------------------------------------- src/geometry.cpp | 57 +++++++++++++++++++++++++++++++++---- src/geometry_header.F90 | 15 ---------- src/lattice.cpp | 2 -- src/lattice.h | 21 ++++++++++++++ 5 files changed, 73 insertions(+), 85 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index 817da18de..dcaabb9dd 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -65,78 +65,15 @@ contains !=============================================================================== recursive subroutine find_cell(p, found, search_cells) - type(Particle), intent(inout) :: p logical, intent(inout) :: found integer, optional :: search_cells(:) - integer :: j ! coordinate level index - integer :: i_xyz(3) ! indices in lattice - integer :: i_cell ! index in cells array if (present(search_cells)) then found = find_cell_c(p, size(search_cells), search_cells-1) else found = find_cell_c(p, 0) end if - j = p % n_coord - i_cell = p % coord(j) % cell - - if (found) then - associate(c => cells(i_cell)) - CELL_TYPE: if (c % type() == FILL_UNIVERSE) then - j = j + 1 - p % n_coord = j - call find_cell(p, found) - j = p % n_coord - - elseif (c % type() == FILL_LATTICE) then CELL_TYPE - ! ====================================================================== - ! CELL CONTAINS LATTICE, RECURSIVELY FIND CELL - - 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) - - ! Store lower level coordinates - p % coord(j + 1) % xyz = lat % get_local_xyz(p % coord(j) % xyz, i_xyz) - p % coord(j + 1) % uvw = p % coord(j) % uvw - - ! set particle lattice indices - 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) - - ! Set the next lowest coordinate level. - if (lat % are_valid_indices(i_xyz)) then - ! Particle is inside the lattice. - p % coord(j + 1) % universe = & - lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1 - - else - ! Particle is outside the lattice. - 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() + 1 - end if - end if - end associate - - ! Move particle to next level and search for the lower cells. - j = j + 1 - p % n_coord = j - - call find_cell(p, found) - j = p % n_coord - - end if CELL_TYPE - end associate - end if end subroutine find_cell diff --git a/src/geometry.cpp b/src/geometry.cpp index 695afe0be..e400a2245 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -8,9 +8,6 @@ #include "lattice.h" #include "settings.h" -//TODO: remove this include -#include - namespace openmc { @@ -153,8 +150,7 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { //======================================================================== //! Found a lower universe, update this coord level then search the next. - // Add another coordinate level. - //++p->n_coord; + // Set the lower coordinate level universe. p->coord[p->n_coord].universe = c.fill + 1; // Set the position and direction. @@ -190,6 +186,57 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { + w*c.rotation[11]; p->coord[p->n_coord].rotated = true; } + + // Update the coordinate level and recurse. + ++p->n_coord; + find_cell(p, 0, nullptr); + + } else if (c.type == FILL_LATTICE) { + //======================================================================== + //! Found a lower lattice, update this coord level then search the next. + + Lattice& lat {*lattices_c[c.fill]}; + + // Determine lattice indices. + Position r {p->coord[p->n_coord-1].xyz}; + Direction u {p->coord[p->n_coord-1].uvw}; + r += TINY_BIT * u; + auto i_xyz = lat.get_indices(r); + + // Store lower level coordinates. + r = lat.get_local_position(p->coord[p->n_coord-1].xyz, i_xyz); + p->coord[p->n_coord].xyz[0] = r.x; + p->coord[p->n_coord].xyz[1] = r.y; + p->coord[p->n_coord].xyz[2] = r.z; + p->coord[p->n_coord].uvw[0] = u.x; + p->coord[p->n_coord].uvw[1] = u.y; + p->coord[p->n_coord].uvw[2] = u.z; + + // Set lattice indices. + p->coord[p->n_coord].lattice = c.fill + 1; + p->coord[p->n_coord].lattice_x = i_xyz[0]; + p->coord[p->n_coord].lattice_y = i_xyz[1]; + p->coord[p->n_coord].lattice_z = i_xyz[2]; + + // Set the lower coordinate level universe. + if (lat.are_valid_indices(i_xyz)) { + p->coord[p->n_coord].universe = lat[i_xyz] + 1; + } else { + if (lat.outer != NO_OUTER_UNIVERSE) { + p->coord[p->n_coord].universe = lat.outer + 1; + } else { + std::stringstream err_msg; + err_msg << "Particle " << p->id << " is outside lattice " + << lat.id << " but the lattice has no defined outer " + "universe."; + warning(err_msg); + found = false; + } + } + + // Update the coordinate level and recurse. + ++p->n_coord; + find_cell(p, 0, nullptr); } } diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 272966b33..23700d829 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -191,13 +191,6 @@ module geometry_header 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 - 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) import C_PTR, C_INT32_t, C_INT @@ -238,7 +231,6 @@ module geometry_header 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 @@ -275,7 +267,6 @@ module geometry_header ! Boolean expression of half-spaces ! Rotation matrix and translation vector - real(8), allocatable :: translation(:) real(8), allocatable :: rotation(:) real(8), allocatable :: rotation_matrix(:,:) @@ -370,12 +361,6 @@ contains 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 - 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/lattice.cpp b/src/lattice.cpp index e2871d9e1..8797d0fba 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -923,8 +923,6 @@ extern "C" { 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);} int32_t lattice_universe(Lattice *lat, const int i_xyz[3]) diff --git a/src/lattice.h b/src/lattice.h index 94d7b4387..df7c699d8 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -54,6 +54,13 @@ public: virtual int32_t& operator[](const int i_xyz[3]) = 0; + int32_t& + operator[](std::array i_xyz) + { + int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; + return operator[](i_xyz_); + } + virtual LatticeIter begin(); LatticeIter end(); @@ -76,6 +83,13 @@ public: //! otherwise. virtual bool are_valid_indices(const int i_xyz[3]) const = 0; + bool + are_valid_indices(std::array i_xyz) const + { + int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; + return are_valid_indices(i_xyz_); + } + //! \brief Find the next lattice surface crossing //! \param r A 3D Cartesian coordinate. //! \param u A 3D Cartesian direction. @@ -98,6 +112,13 @@ public: virtual Position get_local_position(Position r, const int i_xyz[3]) const = 0; + Position + get_local_position(Position r, std::array i_xyz) const + { + int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; + return get_local_position(r, i_xyz_); + } + //! \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 From c98142dd239c249330356793c93c09af5dccec76 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 22:45:28 -0400 Subject: [PATCH 10/76] Move cross_lattice to C++ --- src/geometry.F90 | 82 +++++------------------------------------------- src/geometry.cpp | 64 ++++++++++++++++++++++++++++++++++++- src/geometry.h | 11 +++++-- src/particle.h | 10 +++++- 4 files changed, 89 insertions(+), 78 deletions(-) diff --git a/src/geometry.F90 b/src/geometry.F90 index dcaabb9dd..09f7066be 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -41,11 +41,18 @@ module geometry function find_cell_c(p, n_search_cells, search_cells) & bind(C, name="find_cell") result(found) import Particle, C_INT, C_BOOL - type(Particle), intent(in) :: p + type(Particle), intent(inout) :: p integer(C_INT), intent(in), value :: n_search_cells integer(C_INT), intent(in), optional :: search_cells(n_search_cells) logical(C_BOOL) :: found end function find_cell_c + + subroutine cross_lattice(p, lattice_translation) & + bind(C, name="cross_lattice") + import Particle, C_INT + type(Particle), intent(inout) :: p + integer(C_INT), intent(in) :: lattice_translation(3) + end subroutine cross_lattice end interface contains @@ -77,79 +84,6 @@ contains end subroutine find_cell -!=============================================================================== -! CROSS_LATTICE moves a particle into a new lattice element -!=============================================================================== - - subroutine cross_lattice(p, lattice_translation) - - type(Particle), intent(inout) :: p - integer, intent(in) :: lattice_translation(3) - integer :: j - integer :: i_xyz(3) ! indices in lattice - logical :: found ! particle found in cell? - class(Lattice), pointer :: lat - - j = p % n_coord - lat => lattices(p % coord(j) % lattice) % obj - - if (verbosity >= 10 .or. trace) then - 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)) // ")") - end if - - ! Set the lattice indices. - p % coord(j) % lattice_x = p % coord(j) % lattice_x + lattice_translation(1) - p % coord(j) % lattice_y = p % coord(j) % lattice_y + lattice_translation(2) - p % coord(j) % lattice_z = p % coord(j) % lattice_z + lattice_translation(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 - - ! Set the new coordinate position. - p % coord(j) % xyz = lat % get_local_xyz(p % coord(j - 1) % xyz, i_xyz) - - OUTSIDE_LAT: if (.not. lat % are_valid_indices(i_xyz)) then - ! The particle is outside the lattice. Search for it from base coord - p % n_coord = 1 - call find_cell(p, found) - if (.not. found) then - if (p % alive) then ! Particle may have been killed in find_cell - call particle_mark_as_lost(p, "Could not locate particle " & - // trim(to_str(p % id)) // " after crossing a lattice boundary.") - return - end if - end if - - else OUTSIDE_LAT - - ! Find cell in next lattice element - p % coord(j) % universe = & - lat % get([i_xyz(1), i_xyz(2), i_xyz(3)]) + 1 - - call find_cell(p, found) - if (.not. found) then - ! In some circumstances, a particle crossing the corner of a cell may - ! not be able to be found in the next universe. In this scenario we cut - ! off all lower-level coordinates and search from universe zero - - ! Remove lower coordinates - p % n_coord = 1 - - ! Search for particle - call find_cell(p, found) - if (.not. found) then - call particle_mark_as_lost(p, "Could not locate particle " // & - trim(to_str(p % id)) // " after crossing a lattice boundary.") - return - end if - end if - end if OUTSIDE_LAT - - end subroutine cross_lattice - !=============================================================================== ! DISTANCE_TO_BOUNDARY calculates the distance to the nearest boundary for a ! particle 'p' traveling in a certain direction. For a cell in a subuniverse diff --git a/src/geometry.cpp b/src/geometry.cpp index e400a2245..85cefb7e2 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -1,5 +1,6 @@ #include "geometry.h" +#include #include #include "cell.h" @@ -230,7 +231,7 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { << lat.id << " but the lattice has no defined outer " "universe."; warning(err_msg); - found = false; + return false; } } @@ -243,4 +244,65 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { return found; } +//============================================================================== + +extern "C" void +cross_lattice(Particle* p, int lattice_translation[3]) +{ + Lattice& lat {*lattices_c[p->coord[p->n_coord-1].lattice-1]}; + + if (openmc_verbosity >= 10 || openmc_trace) { + std::stringstream msg; + msg << " Crossing lattice " << lat.id << ". Current position (" + << p->coord[p->n_coord-1].lattice_x << "," + << p->coord[p->n_coord-1].lattice_y << "," + << p->coord[p->n_coord-1].lattice_z << ")"; + write_message(msg, 1); + } + + // Set the lattice indices. + p->coord[p->n_coord-1].lattice_x += lattice_translation[0]; + p->coord[p->n_coord-1].lattice_y += lattice_translation[1]; + p->coord[p->n_coord-1].lattice_z += lattice_translation[2]; + std::array i_xyz {p->coord[p->n_coord-1].lattice_x, + p->coord[p->n_coord-1].lattice_y, + p->coord[p->n_coord-1].lattice_z}; + + // Set the new coordinate position. + auto r = lat.get_local_position(p->coord[p->n_coord-2].xyz, i_xyz); + p->coord[p->n_coord-1].xyz[0] = r.x; + p->coord[p->n_coord-1].xyz[1] = r.y; + p->coord[p->n_coord-1].xyz[2] = r.z; + + if (!lat.are_valid_indices(i_xyz)) { + // The particle is outside the lattice. Search for it from the base coords. + p->n_coord = 1; + bool found = find_cell(p, 0, nullptr); + if (!found && p->alive) { + std::stringstream err_msg; + err_msg << "Could not locate particle " << p->id + << " after crossing a lattice boundary"; + p->mark_as_lost(err_msg); + } + + } else { + // Find cell in next lattice element. + p->coord[p->n_coord-1].universe = lat[i_xyz] + 1; + bool found = find_cell(p, 0, nullptr); + + if (!found) { + // A particle crossing the corner of a lattice tile may not be found. In + // this case, search for it from the base coords. + p->n_coord = 1; + bool found = find_cell(p, 0, nullptr); + if (!found && p->alive) { + std::stringstream err_msg; + err_msg << "Could not locate particle " << p->id + << " after crossing a lattice boundary"; + p->mark_as_lost(err_msg); + } + } + } +} + } // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index b73ae314c..47162c73e 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -13,19 +13,26 @@ extern "C" int openmc_root_universe; extern std::vector overlap_check_count; //============================================================================== -//! Check for overlapping cells at the particle's position. +//! Check for overlapping cells at a particle's position. //============================================================================== extern "C" bool check_cell_overlap(Particle* p); //============================================================================== -//! Locate the particle in the geometry tree and set its geometry data fields. +//! Locate a particle in the geometry tree and set its geometry data fields. //============================================================================== extern "C" bool find_cell(Particle* p, int n_search_cells, int* search_cells); +//============================================================================== +//! Move a particle into a new lattice tile. +//============================================================================== + +extern "C" void +cross_lattice(Particle* p, int lattice_translation[3]); + } // namespace openmc #endif // OPENMC_GEOMETRY_H diff --git a/src/particle.h b/src/particle.h index b53397171..e03af3d69 100644 --- a/src/particle.h +++ b/src/particle.h @@ -4,8 +4,10 @@ //! \file particle.h //! \brief Particle type -#include #include +#include +#include +#include #include "openmc.h" @@ -152,6 +154,12 @@ extern "C" { //! \param message A warning message to display void mark_as_lost(const char* message); + void mark_as_lost(const std::string& message) + {mark_as_lost(message.c_str());} + + void mark_as_lost(const std::stringstream& message) + {mark_as_lost(message.str());} + //! create a particle restart HDF5 file void write_restart(); }; From bc1c1e491628741fb8457d5a1ecc69d9c259b541 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 20 Aug 2018 23:42:51 -0400 Subject: [PATCH 11/76] Move neighbor lists to C++ --- src/cell.cpp | 18 -------- src/cell.h | 7 ++++ src/geometry.F90 | 92 +++++------------------------------------ src/geometry.cpp | 27 ++++++++---- src/geometry.h | 2 +- src/geometry_aux.cpp | 28 +++++++++++++ src/geometry_aux.h | 6 +++ src/geometry_header.F90 | 6 --- src/input_xml.F90 | 44 +------------------- src/string.F90 | 92 ----------------------------------------- src/surface.h | 5 ++- src/surface_header.F90 | 3 -- src/tracking.F90 | 17 +------- 13 files changed, 79 insertions(+), 268 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index 9786a89fc..c22813ea7 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -17,17 +17,6 @@ namespace openmc { -//============================================================================== -// Constants -//============================================================================== - -// TODO: Convert to enum -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}; - //============================================================================== // Global variables //============================================================================== @@ -705,13 +694,6 @@ extern "C" { bool cell_simple(Cell* c) {return c->simple;} - bool cell_contains(Cell* c, double xyz[3], double uvw[3], int32_t on_surface) - { - Position r {xyz}; - Direction u {uvw}; - return c->contains(r, u, on_surface); - } - void cell_distance(Cell* c, double xyz[3], double uvw[3], int32_t on_surface, double* min_dist, int32_t* i_surf) { diff --git a/src/cell.h b/src/cell.h index 4f3a8978f..a10c407f0 100644 --- a/src/cell.h +++ b/src/cell.h @@ -25,6 +25,13 @@ extern "C" int FILL_MATERIAL; extern "C" int FILL_UNIVERSE; extern "C" int FILL_LATTICE; +// TODO: Convert to enum +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}; + //============================================================================== // Global variables //============================================================================== diff --git a/src/geometry.F90 b/src/geometry.F90 index 09f7066be..dcd44360b 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -15,16 +15,6 @@ module geometry implicit none interface - function cell_contains_c(cell_ptr, xyz, uvw, on_surface) & - bind(C, name="cell_contains") result(in_cell) - 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 @@ -38,12 +28,11 @@ module geometry type(Particle), intent(in) :: p end subroutine check_cell_overlap - function find_cell_c(p, n_search_cells, search_cells) & + function find_cell_c(p, search_surf) & bind(C, name="find_cell") result(found) import Particle, C_INT, C_BOOL type(Particle), intent(inout) :: p - integer(C_INT), intent(in), value :: n_search_cells - integer(C_INT), intent(in), optional :: search_cells(n_search_cells) + integer(C_INT), intent(in), value :: search_surf logical(C_BOOL) :: found end function find_cell_c @@ -53,31 +42,26 @@ module geometry type(Particle), intent(inout) :: p integer(C_INT), intent(in) :: lattice_translation(3) end subroutine cross_lattice + + subroutine neighbor_lists() bind(C) + end subroutine neighbor_lists end interface contains - function cell_contains(c, p) result(in_cell) - type(Cell), intent(in) :: c - type(Particle), intent(in) :: p - logical :: in_cell - 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 - !=============================================================================== ! FIND_CELL determines what cell a source particle is in within a particular ! universe. If the base universe is passed, the particle should be found as long ! as it's within the geometry !=============================================================================== - recursive subroutine find_cell(p, found, search_cells) - type(Particle), intent(inout) :: p - logical, intent(inout) :: found - integer, optional :: search_cells(:) + subroutine find_cell(p, found, search_surf) + type(Particle), intent(inout) :: p + logical, intent(inout) :: found + integer, optional, intent(in) :: search_surf - if (present(search_cells)) then - found = find_cell_c(p, size(search_cells), search_cells-1) + if (present(search_surf)) then + found = find_cell_c(p, search_surf) else found = find_cell_c(p, 0) end if @@ -201,58 +185,4 @@ contains end subroutine distance_to_boundary -!=============================================================================== -! NEIGHBOR_LISTS builds a list of neighboring cells to each surface to speed up -! searches when a cell boundary is crossed. -!=============================================================================== - - subroutine neighbor_lists() - - integer :: i ! index in cells/surfaces array - integer :: j ! index in region specification - integer :: k ! surface half-space spec - integer :: n ! size of vector - type(VectorInt), allocatable :: neighbor_pos(:) - type(VectorInt), allocatable :: neighbor_neg(:) - - call write_message("Building neighboring cells lists for each surface...", & - 6) - - allocate(neighbor_pos(n_surfaces)) - allocate(neighbor_neg(n_surfaces)) - - do i = 1, n_cells - do j = 1, size(cells(i)%region) - ! Get token from region specification and skip any tokens that - ! correspond to operators rather than regions - k = cells(i)%region(j) - if (abs(k) >= OP_UNION) cycle - - ! Add this cell ID to neighbor list for k-th surface - if (k > 0) then - call neighbor_pos(abs(k))%push_back(i) - else - call neighbor_neg(abs(k))%push_back(i) - end if - end do - end do - - do i = 1, n_surfaces - ! Copy positive neighbors to Surface instance - n = neighbor_pos(i)%size() - if (n > 0) then - allocate(surfaces(i)%neighbor_pos(n)) - surfaces(i)%neighbor_pos(:) = neighbor_pos(i)%data(1:n) - end if - - ! Copy negative neighbors to Surface instance - n = neighbor_neg(i)%size() - if (n > 0) then - allocate(surfaces(i)%neighbor_neg(n)) - surfaces(i)%neighbor_neg(:) = neighbor_neg(i)%data(1:n) - end if - end do - - end subroutine neighbor_lists - end module geometry diff --git a/src/geometry.cpp b/src/geometry.cpp index 85cefb7e2..87bf0abfd 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -8,6 +8,7 @@ #include "error.h" #include "lattice.h" #include "settings.h" +#include "surface.h" namespace openmc { @@ -50,7 +51,7 @@ check_cell_overlap(Particle* p) { //============================================================================== extern "C" bool -find_cell(Particle* p, int n_search_cells, int* search_cells) { +find_cell(Particle* p, int search_surf) { for (int i = p->n_coord; i < MAX_COORD; i++) { p->coord[i].reset(); } @@ -64,8 +65,18 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { //TODO: off-by-one indexing --i_universe; - // If not given a set of search cells, search all cells in the uninverse. - if (n_search_cells == 0) { + // If a surface was indicated, only search cells from the neighbor list of + // that surface. + int* search_cells; + int n_search_cells; + if (search_surf > 0) { + search_cells = global_surfaces[search_surf-1]->neighbor_pos.data(); + n_search_cells = global_surfaces[search_surf-1]->neighbor_pos.size(); + } else if (search_surf < 0) { + search_cells = global_surfaces[-search_surf-1]->neighbor_neg.data(); + n_search_cells = global_surfaces[-search_surf-1]->neighbor_neg.size(); + } else { + // No surface was indicated, search all cells in the universe. search_cells = global_universes[i_universe]->cells.data(); n_search_cells = global_universes[i_universe]->cells.size(); } @@ -190,7 +201,7 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { // Update the coordinate level and recurse. ++p->n_coord; - find_cell(p, 0, nullptr); + find_cell(p, 0); } else if (c.type == FILL_LATTICE) { //======================================================================== @@ -237,7 +248,7 @@ find_cell(Particle* p, int n_search_cells, int* search_cells) { // Update the coordinate level and recurse. ++p->n_coord; - find_cell(p, 0, nullptr); + find_cell(p, 0); } } @@ -277,7 +288,7 @@ cross_lattice(Particle* p, int lattice_translation[3]) if (!lat.are_valid_indices(i_xyz)) { // The particle is outside the lattice. Search for it from the base coords. p->n_coord = 1; - bool found = find_cell(p, 0, nullptr); + bool found = find_cell(p, 0); if (!found && p->alive) { std::stringstream err_msg; err_msg << "Could not locate particle " << p->id @@ -288,13 +299,13 @@ cross_lattice(Particle* p, int lattice_translation[3]) } else { // Find cell in next lattice element. p->coord[p->n_coord-1].universe = lat[i_xyz] + 1; - bool found = find_cell(p, 0, nullptr); + bool found = find_cell(p, 0); if (!found) { // A particle crossing the corner of a lattice tile may not be found. In // this case, search for it from the base coords. p->n_coord = 1; - bool found = find_cell(p, 0, nullptr); + bool found = find_cell(p, 0); if (!found && p->alive) { std::stringstream err_msg; err_msg << "Could not locate particle " << p->id diff --git a/src/geometry.h b/src/geometry.h index 47162c73e..9a13ae220 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -24,7 +24,7 @@ check_cell_overlap(Particle* p); //============================================================================== extern "C" bool -find_cell(Particle* p, int n_search_cells, int* search_cells); +find_cell(Particle* p, int search_surf); //============================================================================== //! Move a particle into a new lattice tile. diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 6d7d5badb..6ca3b6d3b 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -11,6 +11,7 @@ #include "lattice.h" #include "material.h" #include "settings.h" +#include "surface.h" namespace openmc { @@ -152,6 +153,33 @@ find_root_universe() //============================================================================== +void +neighbor_lists() +{ + write_message("Building neighboring cells lists for each surface...", 6); + + for (int i = 0; i < global_cells.size(); i++) { + for (auto token : global_cells[i]->region) { + // Skip operator tokens. + if (std::abs(token) >= OP_UNION) continue; + + // This token is a surface index. Add the cell to the surface's list. + if (token > 0) { + global_surfaces[std::abs(token)-1]->neighbor_pos.push_back(i); + } else { + global_surfaces[std::abs(token)-1]->neighbor_neg.push_back(i); + } + } + } + + for (Surface* surf : global_surfaces) { + surf->neighbor_pos.shrink_to_fit(); + surf->neighbor_neg.shrink_to_fit(); + } +} + +//============================================================================== + void prepare_distribcell(int32_t* filter_cell_list, int n) { diff --git a/src/geometry_aux.h b/src/geometry_aux.h index e3fd034c6..3511a84be 100644 --- a/src/geometry_aux.h +++ b/src/geometry_aux.h @@ -31,6 +31,12 @@ extern "C" void assign_temperatures(); extern "C" int32_t find_root_universe(); +//!============================================================================= +//! Build a list of neighboring cells to each surface to speed up tracking. +//!============================================================================= + +extern "C" void neighbor_lists(); + //============================================================================== //! Populate all data structures needed for distribcells. //============================================================================== diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 23700d829..0223a63ff 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -212,9 +212,6 @@ module geometry_header type Universe integer :: id ! Unique ID integer, allocatable :: cells(:) ! List of cells within - real(8) :: x0 ! Translation in x-coordinate - real(8) :: y0 ! Translation in y-coordinate - real(8) :: z0 ! Translation in z-coordinate end type Universe !=============================================================================== @@ -263,9 +260,6 @@ module geometry_header type Cell type(C_PTR) :: ptr - integer, allocatable :: region(:) ! Definition of spatial region as - ! Boolean expression of half-spaces - ! Rotation matrix and translation vector real(8), allocatable :: rotation(:) real(8), allocatable :: rotation_matrix(:,:) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 27b8be946..bea0ed637 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -31,7 +31,7 @@ module input_xml use source_header use stl_vector, only: VectorInt, VectorReal, VectorChar use string, only: to_lower, to_str, str_to_int, str_to_real, & - starts_with, ends_with, tokenize, split_string, & + starts_with, ends_with, split_string, & zero_padded, to_c_string use summary, only: write_summary use tally @@ -1002,16 +1002,14 @@ contains subroutine read_geometry_xml() - integer :: i, j, k + integer :: i, j integer :: n, n_rlats, n_hlats - integer :: id integer :: univ_id integer :: n_cells_in_univ real(8) :: phi, theta, psi logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename - character(:), allocatable :: region_spec type(Cell), pointer :: c class(Lattice), pointer :: lat type(XMLDocument) :: doc @@ -1021,7 +1019,6 @@ contains type(XMLNode), allocatable :: node_cell_list(:) type(XMLNode), allocatable :: node_rlat_list(:) type(XMLNode), allocatable :: node_hlat_list(:) - type(VectorInt) :: tokens type(VectorInt) :: univ_ids ! List of all universe IDs type(DictIntInt) :: cells_in_univ_dict ! Used to count how many cells each ! universe contains @@ -1104,43 +1101,6 @@ contains // to_str(c % id())) 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 & - &disallowed in a future release. Use 'region' instead. The & - &openmc-update-inputs utility can be used to automatically & - &update geometry.xml files.") - region_spec = node_value_string(node_cell, "surfaces") - call get_node_value(node_cell, "surfaces", region_spec) - elseif (check_for_node(node_cell, "region")) then - region_spec = node_value_string(node_cell, "region") - else - region_spec = '' - end if - - if (len_trim(region_spec) > 0) then - ! Create surfaces array from string - call tokenize(region_spec, tokens) - - ! Convert user IDs to surface indices - do j = 1, tokens % size() - id = tokens % data(j) - if (id < OP_UNION) then - if (surface_dict % has(abs(id))) then - k = surface_dict % get(abs(id)) - tokens % data(j) = sign(k, id) - end if - end if - end do - - ! Copy region spec and RPN form to cell arrays - allocate(c % region(tokens%size())) - c % region(:) = tokens%data(1:tokens%size()) - - call tokens%clear() - end if - if (.not. allocated(c%region)) allocate(c%region(0)) - ! Rotation matrix if (check_for_node(node_cell, "rotation")) then ! Rotations can only be applied to cells that are being filled with diff --git a/src/string.F90 b/src/string.F90 index 71d9d6e96..90b51d7aa 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -64,98 +64,6 @@ contains end subroutine split_string -!=============================================================================== -! TOKENIZE takes a string that includes logical expressions for a list of -! bounding surfaces in a cell and splits it into separate tokens. The characters -! (, ), |, and ~ count as separate tokens since they represent operators. -!=============================================================================== - - subroutine tokenize(string, tokens) - character(*), intent(in) :: string - type(VectorInt), intent(inout) :: tokens - - integer :: i ! current index - integer :: i_start ! starting index of word - integer :: token - character(len=len_trim(string)) :: string_ - - ! Remove leading blanks - string_ = adjustl(string) - - i_start = 0 - i = 1 - do while (i <= len_trim(string_)) - ! Check for special characters - if (index('()|~ ', string_(i:i)) > 0) then - ! If the special character appears immediately after a non-operator, - ! create a token with the surface half-space - if (i_start > 0) then - call tokens%push_back(int(str_to_int(& - string_(i_start:i - 1)), 4)) - end if - - select case (string_(i:i)) - case ('(') - call tokens%push_back(OP_LEFT_PAREN) - case (')') - if (tokens%size() > 0) then - token = tokens%data(tokens%size()) - if (token >= OP_UNION .and. token < OP_RIGHT_PAREN) then - call fatal_error("Right parentheses cannot follow an operator in & - ®ion specification: " // trim(string)) - end if - end if - call tokens%push_back(OP_RIGHT_PAREN) - case ('|') - if (tokens%size() > 0) then - token = tokens%data(tokens%size()) - if (.not. (token < OP_UNION .or. token == OP_RIGHT_PAREN)) then - call fatal_error("Union cannot follow an operator in region & - &specification: " // trim(string)) - end if - end if - call tokens%push_back(OP_UNION) - case ('~') - call tokens%push_back(OP_COMPLEMENT) - case (' ') - ! Find next non-space character - do while (string_(i+1:i+1) == ' ') - i = i + 1 - end do - - ! If previous token is a halfspace or right parenthesis and next token - ! is not a left parenthese or union operator, that implies that the - ! whitespace is to be interpreted as an intersection operator - if (i_start > 0 .or. tokens%data(tokens%size()) == OP_RIGHT_PAREN) then - if (index(')|', string_(i+1:i+1)) == 0) then - call tokens%push_back(OP_INTERSECTION) - end if - end if - end select - - i_start = 0 - else - ! Check for invalid characters - if (index('-+0123456789', string_(i:i)) == 0) then - call fatal_error("Invalid character '" // string_(i:i) // "' in & - ®ion specification.") - end if - - ! If we haven't yet reached the start of a word, start a new word - if (i_start == 0) i_start = i - end if - - i = i + 1 - end do - - ! If we've reached the end and we're still in a word, create a token from it - ! and add it to the list - if (i_start > 0) then - call tokens%push_back(int(str_to_int(& - string_(i_start:len_trim(string_))), 4)) - end if - end subroutine tokenize - !=============================================================================== ! CONCATENATE takes an array of words and concatenates them together in one ! string with a single space between words diff --git a/src/surface.h b/src/surface.h index 746db5c3b..c9d8648d8 100644 --- a/src/surface.h +++ b/src/surface.h @@ -58,11 +58,12 @@ class Surface { public: int id; //!< Unique ID - //int neighbor_pos[], //!< List of cells on positive side - // neighbor_neg[]; //!< List of cells on negative side int bc; //!< Boundary condition std::string name; //!< User-defined name + std::vector neighbor_pos; //!< List of cells on positive side + std::vector neighbor_neg; //!< List of cells on negative side + explicit Surface(pugi::xml_node surf_node); virtual ~Surface() {} diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 4a5834ec2..401ac90aa 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -84,9 +84,6 @@ module surface_header !=============================================================================== type :: Surface - integer, allocatable :: & - neighbor_pos(:), & ! List of cells on positive side - neighbor_neg(:) ! List of cells on negative side type(C_PTR) :: ptr contains diff --git a/src/tracking.F90 b/src/tracking.F90 index dd0c26b43..e9568fe54 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -467,21 +467,8 @@ contains ! ========================================================================== ! SEARCH NEIGHBOR LISTS FOR NEXT CELL - if (p % surface > 0 .and. allocated(surf%neighbor_pos)) then - ! If coming from negative side of surface, search all the neighboring - ! cells on the positive side - - call find_cell(p, found, surf%neighbor_pos) - if (found) return - - elseif (p % surface < 0 .and. allocated(surf%neighbor_neg)) then - ! If coming from positive side of surface, search all the neighboring - ! cells on the negative side - - call find_cell(p, found, surf%neighbor_neg) - if (found) return - - end if + call find_cell(p, found, p % surface) + if (found) return ! ========================================================================== ! COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS From 8bb17a481ea02cde00f657109c74e526195f4252 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 21 Aug 2018 11:02:14 -0400 Subject: [PATCH 12/76] Move distance_to_boundary to C++ --- src/cell.cpp | 12 ---- src/geometry.F90 | 127 ++++------------------------------------ src/geometry.cpp | 99 +++++++++++++++++++++++++++++++ src/geometry.h | 8 +++ src/geometry_header.F90 | 57 ------------------ src/lattice.cpp | 16 ++--- src/lattice.h | 12 ++++ 7 files changed, 133 insertions(+), 198 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index c22813ea7..a3a5d9fde 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -692,18 +692,6 @@ extern "C" { double cell_sqrtkT(Cell* c, int i) {return c->sqrtkT[i];} - bool cell_simple(Cell* c) {return c->simple;} - - void cell_distance(Cell* c, double xyz[3], double uvw[3], int32_t on_surface, - double* min_dist, int32_t* i_surf) - { - Position r {xyz}; - Direction u {uvw}; - std::pair out = c->distance(r, u, on_surface); - *min_dist = out.first; - *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);} diff --git a/src/geometry.F90 b/src/geometry.F90 index dcd44360b..b5dee81fa 100644 --- a/src/geometry.F90 +++ b/src/geometry.F90 @@ -43,6 +43,16 @@ module geometry integer(C_INT), intent(in) :: lattice_translation(3) end subroutine cross_lattice + subroutine distance_to_boundary(p, dist, surface_crossed, & + lattice_translation, next_level) bind(C) + import Particle, C_DOUBLE, C_INT + type(Particle), intent(inout) :: p + real(C_DOUBLE), intent(out) :: dist + integer(C_INT), intent(out) :: surface_crossed + integer(C_INT), intent(out) :: lattice_translation(3) + integer(C_INT), intent(out) :: next_level + end subroutine distance_to_boundary + subroutine neighbor_lists() bind(C) end subroutine neighbor_lists end interface @@ -68,121 +78,4 @@ contains end subroutine find_cell -!=============================================================================== -! DISTANCE_TO_BOUNDARY calculates the distance to the nearest boundary for a -! particle 'p' traveling in a certain direction. For a cell in a subuniverse -! that has a parent cell, also include the surfaces of the edge of the universe. -!=============================================================================== - - subroutine distance_to_boundary(p, dist, surface_crossed, lattice_translation, & - next_level) - type(Particle), intent(inout) :: p - real(8), intent(out) :: dist - integer, intent(out) :: surface_crossed - integer, intent(out) :: lattice_translation(3) - integer, intent(out) :: next_level - - integer :: j - 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) :: xyz_t(3) ! local particle coordinates - real(8) :: d_lat ! distance to lattice boundary - real(8) :: d_surf ! distance to surface - real(8) :: xyz_cross(3) ! coordinates at projected surface crossing - real(8) :: surf_uvw(3) ! surface normal direction - type(Cell), pointer :: c - class(Lattice), pointer :: lat - - ! inialize distance to infinity (huge) - dist = INFINITY - d_lat = INFINITY - d_surf = INFINITY - lattice_translation(:) = [0, 0, 0] - - next_level = 0 - - ! Loop over each universe level - LEVEL_LOOP: do j = 1, p % n_coord - - ! get pointer to cell on this level - c => cells(p % coord(j) % cell) - - ! ======================================================================= - ! FIND MINIMUM DISTANCE TO SURFACE IN THIS CELL - - call c % distance(p % coord(j) % xyz, p % coord(j) % uvw, p % surface, & - d_surf, level_surf_cross) - - ! ======================================================================= - ! FIND MINIMUM DISTANCE TO LATTICE SURFACES - - 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, & - i_xyz, d_lat, level_lat_trans) - - type is (HexLattice) LAT_TYPE - 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 - call particle_mark_as_lost(p, "Particle " // trim(to_str(p % id)) & - //" had a negative distance to a lattice boundary. d = " & - //trim(to_str(d_lat))) - end if - end if LAT_COORD - - ! If the boundary on this lattice level is coincident with a boundary on - ! a higher level then we need to make sure that the higher level boundary - ! is selected. This logic must include consideration of floating point - ! precision. - if (d_surf < d_lat) then - if ((dist - d_surf)/dist >= FP_REL_PRECISION) then - dist = d_surf - - ! If the cell is not simple, it is possible that both the negative and - ! 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 - 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 - surface_crossed = abs(level_surf_cross) - else - surface_crossed = -abs(level_surf_cross) - end if - else - surface_crossed = level_surf_cross - end if - - lattice_translation(:) = [0, 0, 0] - next_level = j - end if - else - if ((dist - d_lat)/dist >= FP_REL_PRECISION) then - dist = d_lat - surface_crossed = NONE - lattice_translation(:) = level_lat_trans - next_level = j - end if - end if - - end do LEVEL_LOOP - - end subroutine distance_to_boundary - end module geometry diff --git a/src/geometry.cpp b/src/geometry.cpp index 87bf0abfd..e7cbdd804 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -15,6 +15,8 @@ namespace openmc { std::vector overlap_check_count; +constexpr int F90_NONE {0}; //TODO: replace usage of this with C_NONE + //============================================================================== extern "C" bool @@ -316,4 +318,101 @@ cross_lattice(Particle* p, int lattice_translation[3]) } } +//============================================================================== + +extern "C" void +distance_to_boundary(Particle* p, double* dist, int* surface_crossed, + int lattice_translation[3], int* next_level) +{ + *dist = INFINITY; + double d_lat = INFINITY; + double d_surf = INFINITY; + lattice_translation[0] = 0; + lattice_translation[1] = 0; + lattice_translation[2] = 0; + int32_t level_surf_cross; + std::array level_lat_trans; + + // Loop over each coordinate level. + for (int i = 0; i < p->n_coord; i++) { + Position r {p->coord[i].xyz}; + Direction u {p->coord[i].uvw}; + Cell& c {*global_cells[p->coord[i].cell-1]}; + + // Find the oncoming surface in this cell and the distance to it. + auto surface_distance = c.distance(r, u, p->surface); + d_surf = surface_distance.first; + level_surf_cross = surface_distance.second; + + // Find the distance to the next lattice tile crossing. + if (p->coord[i].lattice != F90_NONE) { + Lattice& lat {*lattices_c[p->coord[i].lattice-1]}; + std::array i_xyz {p->coord[i].lattice_x, p->coord[i].lattice_y, + p->coord[i].lattice_z}; + //TODO: refactor so both lattice use the same position argument (which + //also means the lat.type attribute can be removed) + std::pair> lattice_distance; + switch (lat.type) { + case LatticeType::rect: + lattice_distance = lat.distance(r, u, i_xyz); + break; + case LatticeType::hex: + Position r_hex {p->coord[i-1].xyz[0], p->coord[i-1].xyz[1], + p->coord[i].xyz[2]}; + lattice_distance = lat.distance(r_hex, u, i_xyz); + break; + } + d_lat = lattice_distance.first; + level_lat_trans = lattice_distance.second; + + if (d_lat < 0) { + std::stringstream err_msg; + err_msg << "Particle " << p->id + << " had a negative distance to a lattice boundary"; + p->mark_as_lost(err_msg); + } + } + + // If the boundary on this coordinate level is coincident with a boundary on + // a higher level then we need to make sure that the higher level boundary + // is selected. This logic must consider floating point precision. + if (d_surf < d_lat) { + if (*dist == INFINITY || ((*dist) - d_surf)/(*dist) >= FP_REL_PRECISION) { + *dist = d_surf; + + // If the cell is not simple, it is possible that both the negative and + // 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 (c.simple) { + *surface_crossed = level_surf_cross; + } else { + Position r_hit = r + d_surf * u; + Surface& surf {*global_surfaces[std::abs(level_surf_cross)-1]}; + Direction norm = surf.normal(r_hit); + if (u.dot(norm) > 0) { + *surface_crossed = std::abs(level_surf_cross); + } else { + *surface_crossed = -std::abs(level_surf_cross); + } + } + + lattice_translation[0] = 0; + lattice_translation[1] = 0; + lattice_translation[2] = 0; + *next_level = i + 1; + } + } else { + if (*dist == INFINITY || ((*dist) - d_lat)/(*dist) >= FP_REL_PRECISION) { + *dist = d_lat; + *surface_crossed = F90_NONE; + lattice_translation[0] = level_lat_trans[0]; + lattice_translation[1] = level_lat_trans[1]; + lattice_translation[2] = level_lat_trans[2]; + *next_level = i + 1; + } + } + } +} + } // namespace openmc diff --git a/src/geometry.h b/src/geometry.h index 9a13ae220..742818579 100644 --- a/src/geometry.h +++ b/src/geometry.h @@ -33,6 +33,14 @@ find_cell(Particle* p, int search_surf); extern "C" void cross_lattice(Particle* p, int lattice_translation[3]); +//============================================================================== +//! Find the next boundary a particle will intersect. +//============================================================================== + +extern "C" void +distance_to_boundary(Particle* p, double* dist, int* surface_crossed, + int lattice_translation[3], int* next_level); + } // namespace openmc #endif // OPENMC_GEOMETRY_H diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 0223a63ff..504534d30 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -97,23 +97,6 @@ module geometry_header real(C_DOUBLE) :: sqrtkT end function cell_sqrtkT_c - function cell_simple_c(cell_ptr) bind(C, name='cell_simple') result(simple) - import C_PTR, C_BOOL - type(C_PTR), intent(in), value :: cell_ptr - 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") - import C_PTR, C_INT32_T, C_DOUBLE - 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 - function cell_offset_c(cell_ptr, map) bind(C, name="cell_offset") & result(offset) import C_PTR, C_INT, C_INT32_T @@ -148,17 +131,6 @@ module geometry_header 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') - import C_PTR, C_INT, C_DOUBLE - 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 - subroutine lattice_get_indices_c(lat_ptr, xyz, i_xyz) & bind(C, name='lattice_get_indices') import C_PTR, C_INT, C_DOUBLE @@ -223,7 +195,6 @@ module geometry_header contains 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 @@ -277,8 +248,6 @@ module geometry_header procedure :: material => cell_material procedure :: sqrtkT_size => cell_sqrtkT_size procedure :: sqrtkT => cell_sqrtkT - procedure :: simple => cell_simple - procedure :: distance => cell_distance procedure :: offset => cell_offset procedure :: to_hdf5 => cell_to_hdf5 @@ -314,16 +283,6 @@ contains 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) - 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, 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) @@ -431,22 +390,6 @@ contains sqrtkT = cell_sqrtkT_c(this % ptr, i) end function cell_sqrtkT - 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 - function cell_offset(this, map) result(offset) class(Cell), intent(in) :: this integer(C_INT), intent(in) :: map diff --git a/src/lattice.cpp b/src/lattice.cpp index 8797d0fba..46f88e351 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -137,6 +137,8 @@ Lattice::to_hdf5(hid_t lattices_group) const RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} { + type = LatticeType::rect; + // 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)}; @@ -399,6 +401,8 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const HexLattice::HexLattice(pugi::xml_node lat_node) : Lattice {lat_node} { + type = LatticeType::hex; + // Read the number of lattice cells in each dimension. n_rings = std::stoi(get_node_value(lat_node, "n_rings")); if (check_for_node(lat_node, "n_axial")) { @@ -889,18 +893,6 @@ extern "C" { 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]) - { - Position r {xyz}; - Direction u {uvw}; - std::pair> ld {lat->distance(r, u, i_xyz)}; - *d = ld.first; - lattice_trans[0] = ld.second[0]; - lattice_trans[1] = ld.second[1]; - lattice_trans[2] = ld.second[2]; - } - void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3]) { Position r {xyz}; diff --git a/src/lattice.h b/src/lattice.h index df7c699d8..758acfa82 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -22,6 +22,10 @@ namespace openmc { constexpr int32_t NO_OUTER_UNIVERSE{-1}; +enum class LatticeType { + rect, hex +}; + //============================================================================== // Global variables //============================================================================== @@ -44,6 +48,7 @@ class Lattice public: int32_t id; //!< Universe ID number std::string name; //!< User-defined name + LatticeType type; 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 @@ -100,6 +105,13 @@ public: distance(Position r, Direction u, const int i_xyz[3]) const = 0; + std::pair> + distance(Position r, Direction u, std::array i_xyz) const + { + int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; + return distance(r, u, i_xyz_); + } + //! \brief Find the lattice tile indices for a given point. //! \param r A 3D Cartesian coordinate. //! \return An array containing the indices of a lattice tile. From 041e3e7cbb5bf74ebb60d319cbc5a9f07111b3bd Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 23 Aug 2018 11:01:37 -0500 Subject: [PATCH 13/76] Check hash value for equality --- openmc/filter_expansion.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 7debebd6b..67a9117a9 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -19,7 +19,7 @@ class ExpansionFilter(Filter): if type(self) is not type(other): return False else: - return self.bins == other.bins + return hash(self) == hash(other) @property def order(self): @@ -390,6 +390,9 @@ class ZernikeFilter(ExpansionFilter): def __hash__(self): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tOrder', self.order) + string += '{: <16}=\t{}\n'.format('\tX', self.x) + string += '{: <16}=\t{}\n'.format('\tY', self.y) + string += '{: <16}=\t{}\n'.format('\tR', self.r) return hash(string) def __repr__(self): From be075618d995d1b2cbd643cba5c7e7f4e85b23e6 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 23 Aug 2018 11:50:12 -0500 Subject: [PATCH 14/76] Fix code style --- openmc/filter_expansion.py | 8 ++++---- openmc/polynomial.py | 10 +++++++--- tests/unit_tests/test_polynomials.py | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 67a9117a9..59457b685 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -325,8 +325,8 @@ class ZernikeFilter(ExpansionFilter): This filter allows scores to be multiplied by Zernike polynomials of the particle's position normalized to a given unit circle, up to a - user-specified order. The standard Zernike polynomials follow the definition by - Born and Wolf, *Principles of Optics* and are defined as + user-specified order. The standard Zernike polynomials follow the + definition by Born and Wolf, *Principles of Optics* and are defined as .. math:: Z_n^m(\rho, \theta) = R_n^m(\rho) \cos (m\theta), \quad m > 0 @@ -342,7 +342,7 @@ class ZernikeFilter(ExpansionFilter): \frac{n+m}{2} - k)! (\frac{n-m}{2} - k)!} \rho^{n-2k}. With this definition, the integral of :math:`(Z_n^m)^2` over the unit disk - is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where + is :math:`\frac{\epsilon_m\pi}{2n+2}` for each polynomial where :math:`\epsilon_m` is 2 if :math:`m` equals 0 and 1 otherwise. Specifying a filter with order N tallies moments for all :math:`n` from 0 @@ -488,7 +488,7 @@ class ZernikeRadialFilter(ZernikeFilter): is :math:`\frac{\pi}{n+1}`. If there is only radial dependency, the polynomials are integrated over - the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) + the azimuthal angles. The only terms left are :math:`Z_n^{0}(\rho, \theta) = R_n^{0}(\rho)`. Note that :math:`n` could only be even orders. Therefore, for a radial Zernike polynomials up to order of :math:`n`, there are :math:`\frac{n}{2} + 1` terms in total. The indexing is from the diff --git a/openmc/polynomial.py b/openmc/polynomial.py index b12065997..3552819f6 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -1,9 +1,10 @@ import numpy as np import openmc import openmc.capi as capi +from collections import Iterable -def legendre_from_expcoef(coef, domain= (-1,1)): +def legendre_from_expcoef(coef, domain=(-1, 1)): """Return a Legendre series object based on expansion coefficients. Given a list of coefficients from FET tally and a array of down, return @@ -73,5 +74,8 @@ class ZernikeRadial(Polynomial): return self._order def __call__(self, r): - zn_rad = capi.calc_zn_rad(self.order, r) - return np.sum(self._norm_coef * zn_rad) + if isinstance(r, Iterable): + return [np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r_i)) + for r_i in r] + else: + return np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r)) diff --git a/tests/unit_tests/test_polynomials.py b/tests/unit_tests/test_polynomials.py index 52c30bb00..82b400b3b 100644 --- a/tests/unit_tests/test_polynomials.py +++ b/tests/unit_tests/test_polynomials.py @@ -27,3 +27,21 @@ def test_zernike_radial(): test_vals = zn_rad(rho) assert ref_vals == test_vals + + rho = [0.2, 0.5] + # Reference solution from running the Fortran implementation + raw_zn1 = np.array([ + 1.00000000e+00, -9.20000000e-01, 7.69600000e-01, + -5.66720000e-01, 3.35219200e-01, -1.01747000e-01]) + raw_zn2 = np.array([ + 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, + 4.37500000e-01, -2.89062500e-01, -8.98437500e-02]) + + ref_vals = [np.sum(norm_coeff * raw_zn1), np.sum(norm_coeff * raw_zn2)] + + test_vals = zn_rad(rho) + + print(ref_vals) + print(test_vals) + + assert np.allclose(ref_vals, test_vals) From 57674ce33b4bb5c3c597a5567d4be624e0d04793 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 23 Aug 2018 12:12:04 -0500 Subject: [PATCH 15/76] Delete leftovers --- tests/unit_tests/test_polynomials.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/unit_tests/test_polynomials.py b/tests/unit_tests/test_polynomials.py index 82b400b3b..f6ac2711f 100644 --- a/tests/unit_tests/test_polynomials.py +++ b/tests/unit_tests/test_polynomials.py @@ -41,7 +41,4 @@ def test_zernike_radial(): test_vals = zn_rad(rho) - print(ref_vals) - print(test_vals) - assert np.allclose(ref_vals, test_vals) From 44cb9a990f9d8a74e5459685390a6bd35076882a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 16 Jul 2018 10:50:23 -0500 Subject: [PATCH 16/76] Add XML node ctors for multivariate distributions --- include/openmc/distribution_multi.h | 9 ++++-- include/openmc/distribution_spatial.h | 3 +- src/distribution_multi.cpp | 43 +++++++++++++++++++++++++-- src/distribution_spatial.cpp | 3 +- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/include/openmc/distribution_multi.h b/include/openmc/distribution_multi.h index c93f22d7b..9a5f9e93b 100644 --- a/include/openmc/distribution_multi.h +++ b/include/openmc/distribution_multi.h @@ -3,6 +3,8 @@ #include +#include "pugixml.hpp" + #include "openmc/distribution.h" #include "openmc/position.h" @@ -16,14 +18,15 @@ namespace openmc { class UnitSphereDistribution { public: UnitSphereDistribution() { }; - explicit UnitSphereDistribution(Direction u) : u_ref{u} { }; + explicit UnitSphereDistribution(Direction u) : u_ref_{u} { }; + explicit UnitSphereDistribution(pugi::xml_node node); virtual ~UnitSphereDistribution() = default; //! Sample a direction from the distribution //! \return Direction sampled virtual Direction sample() const = 0; - Direction u_ref {0.0, 0.0, 1.0}; //!< reference direction + Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction }; //============================================================================== @@ -33,6 +36,7 @@ public: class PolarAzimuthal : public UnitSphereDistribution { public: PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi); + explicit PolarAzimuthal(pugi::xml_node node); //! Sample a direction from the distribution //! \return Direction sampled @@ -62,6 +66,7 @@ public: class Monodirectional : public UnitSphereDistribution { public: Monodirectional(Direction u) : UnitSphereDistribution{u} { }; + explicit Monodirectional(pugi::xml_node node) : UnitSphereDistribution{node} { }; //! Sample a direction from the distribution //! \return Sampled direction diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index bda4e8cf0..753496211 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -43,7 +43,7 @@ private: class SpatialBox : public SpatialDistribution { public: - explicit SpatialBox(pugi::xml_node node); + explicit SpatialBox(pugi::xml_node node, bool fission=false); //! Sample a position from the distribution //! \return Sampled position @@ -60,6 +60,7 @@ private: class SpatialPoint : public SpatialDistribution { public: + SpatialPoint() : r_{} { }; explicit SpatialPoint(pugi::xml_node node); //! Sample a position from the distribution diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index 20ee074a8..d4a728c71 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -4,11 +4,30 @@ #include // for sqrt, sin, cos, max #include "openmc/constants.h" +#include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/random_lcg.h" +#include "openmc/xml_interface.h" namespace openmc { +//============================================================================== +// UnitSphereDistribution implementation +//============================================================================== + +UnitSphereDistribution::UnitSphereDistribution(pugi::xml_node node) +{ + // Read reference directional unit vector + if (check_for_node(node, "reference_uvw")) { + auto u_ref = get_node_array(node, "reference_uvw"); + if (u_ref.size() != 3) + fatal_error("Angular distribution reference direction must have " + "three parameters specified."); + u_ref_ = Direction(u_ref.data()); + } +} + + //============================================================================== // PolarAzimuthal implementation //============================================================================== @@ -16,15 +35,33 @@ namespace openmc { PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) : UnitSphereDistribution{u}, mu_{std::move(mu)}, phi_{std::move(phi)} { } +PolarAzimuthal::PolarAzimuthal(pugi::xml_node node) + : UnitSphereDistribution{node} +{ + if (check_for_node(node, "mu")) { + pugi::xml_node node_dist = node.child("mu"); + mu_ = distribution_from_xml(node_dist); + } else { + mu_ = UPtrDist{new Uniform(-1., 1.)}; + } + + if (check_for_node(node, "phi")) { + pugi::xml_node node_dist = node.child("phi"); + phi_ = distribution_from_xml(node_dist); + } else { + phi_ = UPtrDist{new Uniform(0.0, 2.0*PI)}; + } +} + Direction PolarAzimuthal::sample() const { // Sample cosine of polar angle double mu = mu_->sample(); - if (mu == 1.0) return u_ref; + if (mu == 1.0) return u_ref_; // Sample azimuthal angle double phi = phi_->sample(); - return rotate_angle(u_ref, mu, &phi); + return rotate_angle(u_ref_, mu, &phi); } //============================================================================== @@ -45,7 +82,7 @@ Direction Isotropic::sample() const Direction Monodirectional::sample() const { - return u_ref; + return u_ref_; } } // namespace openmc diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index ad61861e5..15098407b 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -55,7 +55,8 @@ Position CartesianIndependent::sample() const // SpatialBox implementation //============================================================================== -SpatialBox::SpatialBox(pugi::xml_node node) +SpatialBox::SpatialBox(pugi::xml_node node, bool fission) + : only_fissionable_{fission} { // Read lower-right/upper-left coordinates auto params = get_node_array(node, "parameters"); From b92677e70b6bec782dafd3ffebaa9708f756f0ad Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 17 Jul 2018 06:43:35 -0500 Subject: [PATCH 17/76] Convert source distributions to C++ --- CMakeLists.txt | 6 +- include/openmc/capi.h | 3 +- include/openmc/distribution.h | 3 + include/openmc/distribution_multi.h | 2 + include/openmc/distribution_spatial.h | 8 +- include/openmc/file_utils.h | 17 ++ include/openmc/mgxs_interface.h | 1 + include/openmc/nuclide.h | 5 + include/openmc/particle.h | 2 +- include/openmc/settings.h | 3 + include/openmc/simulation.h | 11 + include/openmc/source.h | 54 ++++ src/api.F90 | 9 +- src/distribution_multivariate.F90 | 257 ----------------- src/distribution_univariate.F90 | 373 ------------------------- src/error.F90 | 3 +- src/initialize.cpp | 1 - src/input_xml.F90 | 59 ++-- src/material_header.F90 | 16 ++ src/mgxs_interface.F90 | 13 +- src/nuclide.cpp | 16 ++ src/settings.F90 | 7 +- src/settings.cpp | 22 ++ src/simulation.F90 | 19 +- src/simulation.cpp | 39 +++ src/simulation_header.F90 | 2 +- src/source.F90 | 141 ---------- src/source.cpp | 355 +++++++++++++++++++++++ src/source_header.F90 | 388 -------------------------- src/tallies/tally_header.F90 | 10 +- src/xml_interface.F90 | 11 + 31 files changed, 629 insertions(+), 1227 deletions(-) create mode 100644 include/openmc/file_utils.h create mode 100644 include/openmc/source.h delete mode 100644 src/distribution_multivariate.F90 delete mode 100644 src/distribution_univariate.F90 create mode 100644 src/nuclide.cpp delete mode 100644 src/source.F90 create mode 100644 src/source.cpp delete mode 100644 src/source_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a6176a8..fd3c58631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,8 +299,6 @@ add_library(libopenmc SHARED src/cmfd_solver.F90 src/constants.F90 src/dict_header.F90 - src/distribution_multivariate.F90 - src/distribution_univariate.F90 src/eigenvalue.F90 src/endf.F90 src/endf_header.F90 @@ -341,8 +339,6 @@ add_library(libopenmc SHARED src/settings.F90 src/simulation_header.F90 src/simulation.F90 - src/source.F90 - src/source_header.F90 src/state_point.F90 src/stl_vector.F90 src/string.F90 @@ -400,6 +396,7 @@ add_library(libopenmc SHARED src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp + src/nuclide.cpp src/particle.cpp src/plot.cpp src/position.cpp @@ -414,6 +411,7 @@ add_library(libopenmc SHARED src/scattdata.cpp src/settings.cpp src/simulation.cpp + src/source.cpp src/state_point.cpp src/string_functions.cpp src/surface.cpp diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 8fd89334d..bc4371592 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -30,7 +30,6 @@ extern "C" { int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_extend_materials(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end); - int openmc_extend_sources(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_filter_get_id(int32_t index, int32_t* id); int openmc_filter_get_type(int32_t index, char* type); @@ -57,6 +56,7 @@ extern "C" { int openmc_material_add_nuclide(int32_t index, const char name[], double density); int openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n); int openmc_material_get_id(int32_t index, int32_t* id); + int openmc_material_get_fissionable(int32_t index, bool* fissionable); int openmc_material_get_volume(int32_t index, double* volume); int openmc_material_set_density(int32_t index, double density); int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density); @@ -84,7 +84,6 @@ extern "C" { int openmc_simulation_finalize(); int openmc_simulation_init(); int openmc_source_bank(struct Bank** ptr, int64_t* n); - int openmc_source_set_strength(int32_t index, double strength); int openmc_spatial_legendre_filter_get_order(int32_t index, int* order); int openmc_spatial_legendre_filter_get_params(int32_t index, int* axis, double* min, double* max); int openmc_spatial_legendre_filter_set_order(int32_t index, int order); diff --git a/include/openmc/distribution.h b/include/openmc/distribution.h index ed71a1ee2..b8ebcabf4 100644 --- a/include/openmc/distribution.h +++ b/include/openmc/distribution.h @@ -36,6 +36,9 @@ public: //! Sample a value from the distribution //! \return Sampled value double sample() const; + + const std::vector& x() const { return x_; } + const std::vector& p() const { return p_; } private: std::vector x_; //!< Possible outcomes std::vector p_; //!< Probability of each outcome diff --git a/include/openmc/distribution_multi.h b/include/openmc/distribution_multi.h index 9a5f9e93b..487f52831 100644 --- a/include/openmc/distribution_multi.h +++ b/include/openmc/distribution_multi.h @@ -73,6 +73,8 @@ public: Direction sample() const; }; +using UPtrAngle = std::unique_ptr; + } // namespace openmc #endif // DISTRIBUTION_MULTI_H diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index 753496211..e94005f0f 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -1,4 +1,4 @@ -#ifndef OPENMC_DISTRIBTUION_SPATIAL_H +#ifndef OPENMC_DISTRIBUTION_SPATIAL_H #define OPENMC_DISTRIBUTION_SPATIAL_H #include "pugixml.hpp" @@ -48,10 +48,11 @@ public: //! Sample a position from the distribution //! \return Sampled position Position sample() const; + bool only_fissionable() const { return only_fissionable_; } private: Position lower_left_; //!< Lower-left coordinates of box Position upper_right_; //!< Upper-right coordinates of box - bool only_fissionable {false}; //!< Only accept sites in fissionable region? + bool only_fissionable_ {false}; //!< Only accept sites in fissionable region? }; //============================================================================== @@ -61,6 +62,7 @@ private: class SpatialPoint : public SpatialDistribution { public: SpatialPoint() : r_{} { }; + SpatialPoint(Position r) : r_{r} { }; explicit SpatialPoint(pugi::xml_node node); //! Sample a position from the distribution @@ -70,6 +72,8 @@ private: Position r_; //!< Single position at which sites are generated }; +using UPtrSpace = std::unique_ptr; + } // namespace openmc #endif // OPENMC_DISTRIBUTION_SPATIAL_H diff --git a/include/openmc/file_utils.h b/include/openmc/file_utils.h new file mode 100644 index 000000000..0a24cb547 --- /dev/null +++ b/include/openmc/file_utils.h @@ -0,0 +1,17 @@ +#ifndef OPENMC_FILE_UTILS_H +#define OPENMC_FILE_UTILS_H + +#include // for ifstream +#include + +namespace openmc { + +inline bool file_exists(const std::string& filename) +{ + std::ifstream s {filename}; + return s.good(); +} + +} + +#endif // OPENMC_FILE_UTILS_H \ No newline at end of file diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index e5f56e997..02a43fece 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -16,6 +16,7 @@ namespace openmc { extern std::vector nuclides_MG; extern std::vector macro_xs; +extern "C" int num_energy_groups; //============================================================================== // Mgxs data loading interface methods diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index 60769139f..8a19791ba 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -1,10 +1,15 @@ #ifndef OPENMC_NUCLIDE_H #define OPENMC_NUCLIDE_H +#include + #include "openmc/constants.h" namespace openmc { +extern std::array energy_min; +extern std::array energy_max; + //=============================================================================== //! Cached microscopic cross sections for a particular nuclide at the current //! energy diff --git a/include/openmc/particle.h b/include/openmc/particle.h index f351d1186..d186cdfd4 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -33,7 +33,7 @@ constexpr double REL_MAX_LOST_PARTICLES {1.0e-6}; //! Particle types enum class ParticleType { - neutron, photon, electron, positron + neutron = 1, photon = 2, electron = 3, positron = 4 }; extern "C" { diff --git a/include/openmc/settings.h b/include/openmc/settings.h index ea4dfebdc..49e0ab69e 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -18,8 +18,11 @@ namespace openmc { // Defined on Fortran side extern "C" bool openmc_check_overlaps; extern "C" bool openmc_particle_restart_run; +extern "C" bool openmc_photon_transport; extern "C" bool openmc_restart_run; +extern "C" bool openmc_run_CE; extern "C" bool openmc_write_all_tracks; +extern "C" bool openmc_write_initial_source; // Defined in .cpp // TODO: Make strings instead of char* once Fortran is gone diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 14bb56f27..a1350c936 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -2,12 +2,23 @@ #define OPENMC_SIMULATION_H #include +#include + +namespace openmc { extern "C" int openmc_current_batch; extern "C" int openmc_current_gen; extern "C" int64_t openmc_current_work; extern "C" int openmc_n_lost_particles; +extern "C" int openmc_total_gen; + +extern std::vector work_index; #pragma omp threadprivate(openmc_current_work) +extern "C" void openmc_simulation_init_c(); +void calculate_work(); + +} // namespace openmc + #endif // OPENMC_SIMULATION_H diff --git a/include/openmc/source.h b/include/openmc/source.h new file mode 100644 index 000000000..ac5f69a2f --- /dev/null +++ b/include/openmc/source.h @@ -0,0 +1,54 @@ +#ifndef OPENMC_SOURCE_H +#define OPENMC_SOURCE_H + +#include +#include + +#include "pugixml.hpp" + +#include "openmc/distribution_multi.h" +#include "openmc/distribution_spatial.h" +#include "openmc/capi.h" +#include "openmc/particle.h" + +namespace openmc { + +//============================================================================== +//! External source distribution +//============================================================================== + +class SourceDistribution { +public: + SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy); + explicit SourceDistribution(pugi::xml_node node); + + Bank sample() const; + double strength() const { return strength_; } +private: + ParticleType particle_ {ParticleType::neutron}; + double strength_ {1.0}; + UPtrSpace space_; + UPtrAngle angle_; + UPtrDist energy_; +}; + +//============================================================================== +// Global variables +//============================================================================== + +extern std::vector external_sources; + +//============================================================================== +// Functions +//============================================================================== + +//! Initialize source bank from file/distribution +extern "C" void initialize_source(); + +//! Sample a site from all external source distributions in proportion to their +//! source strength +extern "C" Bank sample_external_source(); + +} // namespace openmc + +#endif // OPENMC_SOURCE_H diff --git a/src/api.F90 b/src/api.F90 index 76be2f446..bfa1314c6 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -20,7 +20,6 @@ module openmc_api use random_lcg, only: openmc_get_seed, openmc_set_seed use settings use simulation_header - use source_header, only: openmc_extend_sources, openmc_source_set_strength use state_point, only: openmc_statepoint_write use tally_header use tally_filter_header @@ -44,7 +43,6 @@ module openmc_api public :: openmc_extend_filters public :: openmc_extend_cells public :: openmc_extend_materials - public :: openmc_extend_sources public :: openmc_extend_tallies public :: openmc_filter_get_id public :: openmc_filter_get_type @@ -83,7 +81,6 @@ module openmc_api public :: openmc_simulation_finalize public :: openmc_simulation_init public :: openmc_source_bank - public :: openmc_source_set_strength public :: openmc_tally_allocate public :: openmc_tally_get_estimator public :: openmc_tally_get_id @@ -301,12 +298,16 @@ contains use plot_header use sab_header use settings - use source_header use surface_header use tally_derivative_header use trigger_header use volume_header + interface + subroutine free_memory_source() bind(C) + end subroutine + end interface + call free_memory_geometry() call free_memory_surfaces() call free_memory_material() diff --git a/src/distribution_multivariate.F90 b/src/distribution_multivariate.F90 deleted file mode 100644 index 19db1c297..000000000 --- a/src/distribution_multivariate.F90 +++ /dev/null @@ -1,257 +0,0 @@ -module distribution_multivariate - - use constants, only: ONE, TWO, PI - use distribution_univariate - use error, only: fatal_error - use random_lcg, only: prn - use math, only: rotate_angle - use xml_interface - - implicit none - -!=============================================================================== -! UNITSPHEREDISTRIBUTION type defines a probability density function for points -! on the unit sphere. Extensions of this type are used to sample angular -! distributions for starting sources -!=============================================================================== - - type, abstract :: UnitSphereDistribution - real(8) :: reference_uvw(3) - contains - procedure(unitsphere_distribution_sample_), deferred :: sample - end type UnitSphereDistribution - - abstract interface - function unitsphere_distribution_sample_(this) result(uvw) - import UnitSphereDistribution - class(UnitSphereDistribution), intent(in) :: this - real(8) :: uvw(3) - end function unitsphere_distribution_sample_ - end interface - -!=============================================================================== -! Derived classes of UnitSphereDistribution -!=============================================================================== - - ! Explicit distribution of polar and azimuthal angles - type, extends(UnitSphereDistribution) :: PolarAzimuthal - class(Distribution), allocatable :: mu - class(Distribution), allocatable :: phi - contains - procedure :: sample => polar_azimuthal_sample - end type PolarAzimuthal - - ! Uniform distribution on the unit sphere - type, extends(UnitSphereDistribution) :: Isotropic - contains - procedure :: sample => isotropic_sample - end type Isotropic - - ! Monodirectional distribution - type, extends(UnitSphereDistribution) :: Monodirectional - contains - procedure :: sample => monodirectional_sample - end type Monodirectional - -!=============================================================================== -! SPATIALDISTRIBUTION type defines a probability density function for arbitrary -! points in Euclidean space. -!=============================================================================== - - type, abstract :: SpatialDistribution - contains - procedure(spatial_distribution_from_xml_), deferred :: from_xml - procedure(spatial_distribution_sample_), deferred :: sample - end type SpatialDistribution - - abstract interface - subroutine spatial_distribution_from_xml_(this, node) - import SpatialDistribution, XMLNode - class(SpatialDistribution), intent(inout) :: this - type(XMLNode), intent(in) :: node - end subroutine spatial_distribution_from_xml_ - - function spatial_distribution_sample_(this) result(xyz) - import SpatialDistribution - class(SpatialDistribution), intent(in) :: this - real(8) :: xyz(3) - end function spatial_distribution_sample_ - end interface - - type, extends(SpatialDistribution) :: CartesianIndependent - class(Distribution), allocatable :: x - class(Distribution), allocatable :: y - class(Distribution), allocatable :: z - contains - procedure :: from_xml => cartesian_independent_from_xml - procedure :: sample => cartesian_independent_sample - end type CartesianIndependent - - type, extends(SpatialDistribution) :: SpatialBox - real(8) :: lower_left(3) - real(8) :: upper_right(3) - logical :: only_fissionable = .false. - contains - procedure :: from_xml => spatial_box_from_xml - procedure :: sample => spatial_box_sample - end type SpatialBox - - type, extends(SpatialDistribution) :: SpatialPoint - real(8) :: xyz(3) - contains - procedure :: from_xml => spatial_point_from_xml - procedure :: sample => spatial_point_sample - end type SpatialPoint - -contains - - function polar_azimuthal_sample(this) result(uvw) - class(PolarAzimuthal), intent(in) :: this - real(8) :: uvw(3) - - real(8) :: mu ! cosine of polar angle - real(8) :: phi ! azimuthal angle - - ! Sample cosine of polar angle - mu = this % mu % sample() - if (mu == ONE) then - uvw(:) = this % reference_uvw - else - ! Sample azimuthal angle - phi = this % phi % sample() - uvw = rotate_angle(this % reference_uvw, mu, phi) - end if - end function polar_azimuthal_sample - - function isotropic_sample(this) result(uvw) - class(Isotropic), intent(in) :: this - real(8) :: uvw(3) - - real(8) :: phi - real(8) :: mu - - phi = TWO*PI*prn() - mu = TWO*prn() - ONE - uvw(1) = mu - uvw(2) = sqrt(ONE - mu*mu) * cos(phi) - uvw(3) = sqrt(ONE - mu*mu) * sin(phi) - end function isotropic_sample - - function monodirectional_sample(this) result(uvw) - class(Monodirectional), intent(in) :: this - real(8) :: uvw(3) - - uvw(:) = this % reference_uvw - end function monodirectional_sample - - subroutine cartesian_independent_from_xml(this, node) - class(CartesianIndependent), intent(inout) :: this - type(XMLNode), intent(in) :: node - - type(XMLNode) :: node_dist - - ! Read distribution for x coordinate - if (check_for_node(node, "x")) then - node_dist = node % child("x") - call distribution_from_xml(this % x, node_dist) - else - allocate(Discrete :: this % x) - select type (dist => this % x) - type is (Discrete) - allocate(dist % x(1), dist % p(1)) - dist % x(1) = ZERO - dist % p(1) = ONE - end select - end if - - ! Read distribution for y coordinate - if (check_for_node(node, "y")) then - node_dist = node % child("y") - call distribution_from_xml(this % y, node_dist) - else - allocate(Discrete :: this % y) - select type (dist => this % y) - type is (Discrete) - allocate(dist % x(1), dist % p(1)) - dist % x(1) = ZERO - dist % p(1) = ONE - end select - end if - - if (check_for_node(node, "z")) then - node_dist = node % child("z") - call distribution_from_xml(this % z, node_dist) - else - allocate(Discrete :: this % z) - select type (dist => this % z) - type is (Discrete) - allocate(dist % x(1), dist % p(1)) - dist % x(1) = ZERO - dist % p(1) = ONE - end select - end if - - end subroutine cartesian_independent_from_xml - - function cartesian_independent_sample(this) result(xyz) - class(CartesianIndependent), intent(in) :: this - real(8) :: xyz(3) - - xyz(1) = this % x % sample() - xyz(2) = this % y % sample() - xyz(3) = this % z % sample() - end function cartesian_independent_sample - - subroutine spatial_box_from_xml(this, node) - class(SpatialBox), intent(inout) :: this - type(XMLNode), intent(in) :: node - - real(8), allocatable :: temp_real(:) - - ! Make sure correct number of parameters are given - if (node_word_count(node, "parameters") /= 6) then - call fatal_error('Box/fission spatial source must have & - &six parameters specified.') - end if - - ! Read lower-right/upper-left coordinates - allocate(temp_real(6)) - call get_node_array(node, "parameters", temp_real) - this % lower_left(:) = temp_real(1:3) - this % upper_right(:) = temp_real(4:6) - deallocate(temp_real) - end subroutine spatial_box_from_xml - - function spatial_box_sample(this) result(xyz) - class(SpatialBox), intent(in) :: this - real(8) :: xyz(3) - - integer :: i - real(8) :: r(3) - - r = [ (prn(), i = 1,3) ] - xyz(:) = this % lower_left + r*(this % upper_right - this % lower_left) - end function spatial_box_sample - - subroutine spatial_point_from_xml(this, node) - class(SpatialPoint), intent(inout) :: this - type(XMLNode), intent(in) :: node - - ! Make sure correct number of parameters are given - if (node_word_count(node, "parameters") /= 3) then - call fatal_error('Point spatial source must have & - &three parameters specified.') - end if - - ! Read location of point source - call get_node_array(node, "parameters", this % xyz) - end subroutine spatial_point_from_xml - - function spatial_point_sample(this) result(xyz) - class(SpatialPoint), intent(in) :: this - real(8) :: xyz(3) - - xyz(:) = this % xyz - end function spatial_point_sample - -end module distribution_multivariate diff --git a/src/distribution_univariate.F90 b/src/distribution_univariate.F90 deleted file mode 100644 index 3842db95c..000000000 --- a/src/distribution_univariate.F90 +++ /dev/null @@ -1,373 +0,0 @@ -module distribution_univariate - - use constants, only: ZERO, ONE, HALF, HISTOGRAM, LINEAR_LINEAR, & - MAX_LINE_LEN, MAX_WORD_LEN - use error, only: fatal_error - use random_lcg, only: prn - use math, only: maxwell_spectrum, watt_spectrum - use pugixml - use string, only: to_lower - use xml_interface - - implicit none - -!=============================================================================== -! DISTRIBUTION type defines a probability density function -!=============================================================================== - - type, abstract :: Distribution - contains - procedure(distribution_sample_), deferred :: sample - end type Distribution - - type DistributionContainer - class(Distribution), allocatable :: obj - end type DistributionContainer - - abstract interface - function distribution_sample_(this) result(x) - import Distribution - class(Distribution), intent(in) :: this - real(8) :: x - end function distribution_sample_ - end interface - -!=============================================================================== -! Derived classes of Distribution -!=============================================================================== - - ! Discrete distribution - type, extends(Distribution) :: Discrete - real(8), allocatable :: x(:) - real(8), allocatable :: p(:) - contains - procedure :: sample => discrete_sample - procedure :: initialize => discrete_initialize - end type Discrete - - ! Uniform distribution over the interval [a,b] - type, extends(Distribution) :: Uniform - real(8) :: a - real(8) :: b - contains - procedure :: sample => uniform_sample - end type Uniform - - ! Maxwellian distribution of form c*E*exp(-E/a) - type, extends(Distribution) :: Maxwell - real(8) :: theta - contains - procedure :: sample => maxwell_sample - end type Maxwell - - ! Watt fission spectrum with form c*exp(-E/a)*sinh(sqrt(b*E)) - type, extends(Distribution) :: Watt - real(8) :: a - real(8) :: b - contains - procedure :: sample => watt_sample - end type Watt - - ! Histogram or linear-linear interpolated tabular distribution - type, extends(Distribution) :: Tabular - integer :: interpolation - real(8), allocatable :: x(:) ! tabulated independent variable - real(8), allocatable :: p(:) ! tabulated probability density - real(8), allocatable :: c(:) ! cumulative distribution at tabulated values - contains - procedure :: sample => tabular_sample - procedure :: initialize => tabular_initialize - end type Tabular - - type, extends(Distribution) :: Equiprobable - real(8), allocatable :: x(:) - contains - procedure :: sample => equiprobable_sample - end type Equiprobable - -contains - - function discrete_sample(this) result(x) - class(Discrete), intent(in) :: this - real(8) :: x - - integer :: i ! loop counter - integer :: n ! size of distribution - real(8) :: c ! cumulative frequency - real(8) :: xi ! sampled CDF value - - n = size(this%x) - if (n > 1) then - xi = prn() - c = ZERO - do i = 1, size(this%x) - c = c + this%p(i) - if (xi < c) exit - end do - x = this%x(i) - else - x = this%x(1) - end if - end function discrete_sample - - subroutine discrete_initialize(this, x, p) - class(Discrete), intent(inout) :: this - real(8), intent(in) :: x(:) - real(8), intent(in) :: p(:) - - integer :: n - - ! Check length of x, p arrays - if (size(x) /= size(p)) then - call fatal_error('Tabulated probabilities not of same length as & - &independent variable.') - end if - - ! Copy probability density function - n = size(x) - allocate(this%x(n), this%p(n)) - this%x(:) = x(:) - this%p(:) = p(:) - - ! Normalize density function - this%p(:) = this%p(:)/sum(this%p) - end subroutine - - function uniform_sample(this) result(x) - class(Uniform), intent(in) :: this - real(8) :: x - - x = this%a + prn()*(this%b - this%a) - end function uniform_sample - - function maxwell_sample(this) result(x) - class(Maxwell), intent(in) :: this - real(8) :: x - - x = maxwell_spectrum(this%theta) - end function maxwell_sample - - function watt_sample(this) result(x) - class(Watt), intent(in) :: this - real(8) :: x - - x = watt_spectrum(this%a, this%b) - end function watt_sample - - function tabular_sample(this) result(x) - class(Tabular), intent(in) :: this - real(8) :: x - - integer :: i - real(8) :: c ! sampled cumulative frequency - real(8) :: m ! slope of PDF - real(8) :: x_i, x_i1 ! i-th and (i+1)th x values - real(8) :: c_i, c_i1 ! i-th and (i+1)th cumulative distribution values - real(8) :: p_i, p_i1 ! i-th and (i+1)th probability density values - - ! Sample value of CDF - c = prn() - - ! Find first CDF bin which is above the sampled value - c_i = this%c(1) - do i = 1, size(this%c) - 1 - c_i1 = this%c(i + 1) - if (c <= c_i1) exit - c_i = c_i1 - end do - - ! Determine bounding PDF values - x_i = this%x(i) - p_i = this%p(i) - - if (this%interpolation == HISTOGRAM) then - ! Histogram interpolation - if (p_i > ZERO) then - x = x_i + (c - c_i)/p_i - else - x = x_i - end if - else - ! Linear-linear interpolation - x_i1 = this%x(i + 1) - p_i1 = this%p(i + 1) - - m = (p_i1 - p_i)/(x_i1 - x_i) - if (m == ZERO) then - x = x_i + (c - c_i)/p_i - else - x = x_i + (sqrt(max(ZERO, p_i*p_i + 2*m*(c - c_i))) - p_i)/m - end if - end if - end function tabular_sample - - subroutine tabular_initialize(this, x, p, interp) - class(Tabular), intent(inout) :: this - real(8), intent(in) :: x(:) - real(8), intent(in) :: p(:) - integer, intent(in) :: interp - - integer :: i - integer :: n - - ! Check interpolation parameter - if (interp /= HISTOGRAM .and. interp /= LINEAR_LINEAR) then - call fatal_error('Only histogram and linear-linear interpolation for tabular & - &distribution is supported.') - end if - - ! Check length of x, p arrays - if (size(x) /= size(p)) then - call fatal_error('Tabulated probabilities not of same length as & - &independent variable.') - end if - - ! Copy probability density function and interpolation parameter - n = size(x) - allocate(this%x(n), this%p(n), this%c(n)) - this%interpolation = interp - this%x(:) = x(:) - this%p(:) = p(:) - - ! Calculate cumulative distribution function - this%c(1) = ZERO - do i = 2, n - if (this%interpolation == HISTOGRAM) then - this%c(i) = this%c(i-1) + this%p(i-1)*(this%x(i) - this%x(i-1)) - elseif (this%interpolation == LINEAR_LINEAR) then - this%c(i) = this%c(i-1) + HALF*(this%p(i-1) + this%p(i)) * & - (this%x(i) - this%x(i-1)) - end if - end do - - ! Normalize density and distribution functions - this%p(:) = this%p(:)/this%c(n) - this%c(:) = this%c(:)/this%c(n) - end subroutine tabular_initialize - - function equiprobable_sample(this) result(x) - class(Equiprobable), intent(in) :: this - real(8) :: x - - integer :: i - integer :: n - real(8) :: r - real(8) :: xl, xr - - n = size(this%x) - - r = prn() - i = 1 + int((n - 1)*r) - - xl = this%x(i) - xr = this%x(i+1) - x = xl + ((n - 1)*r - i + ONE) * (xr - xl) - end function equiprobable_sample - - subroutine distribution_from_xml(dist, node_dist) - class(Distribution), allocatable, intent(inout) :: dist - type(XMLNode), intent(in) :: node_dist - - character(MAX_WORD_LEN) :: type - character(MAX_LINE_LEN) :: temp_str - integer :: n - integer :: temp_int - real(8), allocatable :: temp_real(:) - - if (check_for_node(node_dist, "type")) then - ! Determine type of distribution - call get_node_value(node_dist, "type", type) - - ! Determine number of parameters specified - if (check_for_node(node_dist, "parameters")) then - n = node_word_count(node_dist, "parameters") - else - n = 0 - end if - - ! Allocate extension of Distribution - select case (to_lower(type)) - case ('uniform') - allocate(Uniform :: dist) - if (n /= 2) then - call fatal_error('Uniform distribution must have two & - ¶meters specified.') - end if - - case ('maxwell') - allocate(Maxwell :: dist) - if (n /= 1) then - call fatal_error('Maxwell energy distribution must have one & - ¶meter specified.') - end if - - case ('watt') - allocate(Watt :: dist) - if (n /= 2) then - call fatal_error('Watt energy distribution must have two & - ¶meters specified.') - end if - - case ('discrete') - allocate(Discrete :: dist) - - case ('tabular') - allocate(Tabular :: dist) - - case default - call fatal_error('Invalid distribution type: ' // trim(type) // '.') - - end select - - ! Read parameters and interpolation for distribution - select type (dist) - type is (Uniform) - allocate(temp_real(2)) - call get_node_array(node_dist, "parameters", temp_real) - dist%a = temp_real(1) - dist%b = temp_real(2) - deallocate(temp_real) - - type is (Maxwell) - call get_node_value(node_dist, "parameters", dist%theta) - - type is (Watt) - allocate(temp_real(2)) - call get_node_array(node_dist, "parameters", temp_real) - dist%a = temp_real(1) - dist%b = temp_real(2) - deallocate(temp_real) - - type is (Discrete) - allocate(temp_real(n)) - call get_node_array(node_dist, "parameters", temp_real) - call dist%initialize(temp_real(1:n/2), temp_real(n/2+1:n)) - deallocate(temp_real) - - type is (Tabular) - ! Read interpolation - if (check_for_node(node_dist, "interpolation")) then - call get_node_value(node_dist, "interpolation", temp_str) - select case(to_lower(temp_str)) - case ('histogram') - temp_int = HISTOGRAM - case ('linear-linear') - temp_int = LINEAR_LINEAR - case default - call fatal_error("Unknown interpolation type for distribution: " & - // trim(temp_str)) - end select - else - temp_int = HISTOGRAM - end if - - ! Read and initialize tabular distribution - allocate(temp_real(n)) - call get_node_array(node_dist, "parameters", temp_real) - call dist%initialize(temp_real(1:n/2), temp_real(n/2+1:n), temp_int) - deallocate(temp_real) - end select - end if - end subroutine distribution_from_xml - -end module distribution_univariate diff --git a/src/error.F90 b/src/error.F90 index 82b142b51..c00006c8d 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -270,8 +270,9 @@ contains character(kind=C_CHAR), intent(in) :: message(message_len) integer(C_INT), intent(in), value :: level character(message_len+1) :: message_out + ! Using * in the internal write adds an extra space at the beginning write(message_out, *) message - call write_message(message_out, level) + call write_message(message_out(2:), level) end subroutine write_message_from_c end module error diff --git a/src/initialize.cpp b/src/initialize.cpp index 59e13512e..21ab93b72 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a2b1a1fd9..1d7979041 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -7,8 +7,6 @@ module input_xml use cmfd_header, only: cmfd_mesh use constants use dict_header, only: DictIntInt, DictCharInt, DictEntryCI - use distribution_multivariate - use distribution_univariate use endf, only: reaction_name use error, only: fatal_error, warning, write_message, openmc_err_msg use geometry, only: neighbor_lists @@ -28,7 +26,6 @@ module input_xml use surface_header use set_header, only: SetChar use settings - use source_header use stl_vector, only: VectorInt, VectorReal, VectorChar use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, tokenize, split_string, & @@ -102,6 +99,13 @@ module input_xml integer(C_INT32_T), intent(in), value :: univ integer(C_INT) :: n end function maximum_levels + + subroutine set_particle_energy_bounds(particle, E_min, E_max) bind(C) + import C_INT, C_DOUBLE + integer(C_INT), value :: particle + real(C_DOUBLE), value :: E_min + real(C_DOUBLE), value :: E_max + end subroutine end interface contains @@ -212,7 +216,6 @@ contains integer, allocatable :: temp_int_array(:) integer :: n_tracks logical :: file_exists - character(MAX_WORD_LEN) :: type character(MAX_LINE_LEN) :: filename type(XMLDocument) :: doc type(XMLNode) :: root @@ -227,7 +230,6 @@ contains type(XMLNode) :: node_vol type(XMLNode) :: node_tab_leg type(XMLNode), allocatable :: node_mesh_list(:) - type(XMLNode), allocatable :: node_source_list(:) type(XMLNode), allocatable :: node_vol_list(:) ! Check if settings.xml exists @@ -456,46 +458,13 @@ contains ! ========================================================================== ! EXTERNAL SOURCE - ! Get point to list of elements and make sure there is at least one - call get_node_list(root, "source", node_source_list) - n = size(node_source_list) - - if (n == 0) then - ! Default source is isotropic point source at origin with Watt spectrum - allocate(external_source(1)) - external_source % particle = NEUTRON - external_source % strength = ONE - - allocate(SpatialPoint :: external_source(1) % space) - select type (space => external_source(1) % space) - type is (SpatialPoint) - space % xyz(:) = [ZERO, ZERO, ZERO] - end select - - allocate(Isotropic :: external_source(1) % angle) - external_source(1) % angle % reference_uvw(:) = [ZERO, ZERO, ONE] - - allocate(Watt :: external_source(1) % energy) - select type(energy => external_source(1) % energy) - type is (Watt) - energy % a = 0.988e6_8 - energy % b = 2.249e-6_8 - end select - else - ! Allocate array for sources - allocate(external_source(n)) - end if + ! Handled on C++ side ! Check if we want to write out source if (check_for_node(root, "write_initial_source")) then call get_node_value(root, "write_initial_source", write_initial_source) end if - ! Read each source - do i = 1, n - call external_source(i) % from_xml(node_source_list(i), path_source) - end do - ! Survival biasing if (check_for_node(root, "survival_biasing")) then call get_node_value(root, "survival_biasing", survival_biasing) @@ -1004,7 +973,7 @@ contains subroutine read_geometry_xml() integer :: i, j, k - integer :: n, n_mats, n_rlats, n_hlats + integer :: n, n_rlats, n_hlats integer :: id integer :: univ_id integer :: n_cells_in_univ @@ -1012,7 +981,6 @@ contains logical :: file_exists logical :: boundary_exists character(MAX_LINE_LEN) :: filename - character(MAX_WORD_LEN), allocatable :: sarray(:) character(:), allocatable :: region_spec type(Cell), pointer :: c class(Lattice), pointer :: lat @@ -1473,7 +1441,6 @@ contains character(3) :: element ! name of element, e.g. Zr character(MAX_WORD_LEN) :: units ! units on density character(MAX_LINE_LEN) :: filename ! absolute path to materials.xml - character(MAX_LINE_LEN) :: temp_str ! temporary string when reading character(MAX_WORD_LEN), allocatable :: sarray(:) real(8) :: val ! value entered for density real(8) :: temp_dble ! temporary double prec. real @@ -3479,6 +3446,8 @@ contains ! Get the minimum and maximum energies energy_min(NEUTRON) = energy_bins(num_energy_groups + 1) energy_max(NEUTRON) = energy_bins(1) + call set_particle_energy_bounds(NEUTRON, energy_min(NEUTRON), & + energy_max(NEUTRON)) ! Get the datasets present in the library call get_groups(file_id, names) @@ -3639,6 +3608,8 @@ contains nuclides(i_nuclide) % grid(1) % energy(1)) energy_max(NEUTRON) = min(energy_max(NEUTRON), nuclides(i_nuclide) % & grid(1) % energy(size(nuclides(i_nuclide) % grid(1) % energy))) + call set_particle_energy_bounds(NEUTRON, energy_min(NEUTRON), & + energy_max(NEUTRON)) end if ! Add name and alias to dictionary @@ -3672,6 +3643,8 @@ contains energy_max(PHOTON) = min(energy_max(PHOTON), & exp(elements(i_element) % energy(size(elements(i_element) & % energy)))) + call set_particle_energy_bounds(PHOTON, energy_min(PHOTON), & + energy_max(PHOTON)) end if ! Add element to set @@ -3713,6 +3686,8 @@ contains if (size(ttb_e_grid) >= 1) then energy_min(PHOTON) = max(energy_min(PHOTON), ttb_e_grid(1)) energy_max(PHOTON) = min(energy_max(PHOTON), ttb_e_grid(size(ttb_e_grid))) + call set_particle_energy_bounds(PHOTON, energy_min(PHOTON), & + energy_max(PHOTON)) end if ! Take logarithm of energies since they are log-log interpolated diff --git a/src/material_header.F90 b/src/material_header.F90 index 1f48168af..71e6ec5f1 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -678,6 +678,22 @@ contains end function openmc_material_get_id + function openmc_material_get_fissionable(index, fissionable) result(err) bind(C) + ! returns whether a material is fissionable + integer(C_INT32_T), value :: index + logical(C_BOOL), intent(out) :: fissionable + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(materials)) then + fissionable = materials(index) % fissionable + err = 0 + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in materials array is out of bounds.") + end if + end function openmc_material_get_fissionable + + function openmc_material_set_id(index, id) result(err) bind(C) ! Set the ID of a material integer(C_INT32_T), value, intent(in) :: index diff --git a/src/mgxs_interface.F90 b/src/mgxs_interface.F90 index 2a579e930..9dccc9230 100644 --- a/src/mgxs_interface.F90 +++ b/src/mgxs_interface.F90 @@ -147,7 +147,7 @@ module mgxs_interface end interface ! Number of energy groups - integer(C_INT) :: num_energy_groups + integer(C_INT), bind(C) :: num_energy_groups ! Number of delayed groups integer(C_INT) :: num_delayed_groups @@ -159,6 +159,13 @@ module mgxs_interface real(8), allocatable :: energy_bin_avg(:) ! Energy group structure with increasing energy - real(8), allocatable :: rev_energy_bins(:) + real(C_DOUBLE), allocatable, target :: rev_energy_bins(:) -end module mgxs_interface \ No newline at end of file +contains + + function rev_energy_bins_ptr() result(ptr) bind(C) + type(C_PTR) :: ptr + ptr = C_LOC(rev_energy_bins(1)) + end function + +end module mgxs_interface diff --git a/src/nuclide.cpp b/src/nuclide.cpp new file mode 100644 index 000000000..f7f5399ba --- /dev/null +++ b/src/nuclide.cpp @@ -0,0 +1,16 @@ +#include "openmc/nuclide.h" + +namespace openmc { + +// Order corresponds to ParticleType enum +std::array energy_min {0.0, 0.0}; +std::array energy_max {INFTY, INFTY}; + +extern "C" void +set_particle_energy_bounds(int particle, double E_min, double E_max) +{ + energy_min[particle - 1] = E_min; + energy_max[particle - 1] = E_max; +} + +} // namespace openmc diff --git a/src/settings.F90 b/src/settings.F90 index 972eba1d5..dfe4afbe3 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -9,7 +9,7 @@ module settings ! ============================================================================ ! ENERGY TREATMENT RELATED VARIABLES - logical(C_BOOL) :: run_CE = .true. ! Run in CE mode? + logical(C_BOOL), bind(C, name='openmc_run_CE') :: run_CE = .true. ! Run in CE mode? ! ============================================================================ ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES @@ -26,7 +26,7 @@ module settings integer :: n_log_bins ! number of bins for logarithmic grid - logical :: photon_transport = .false. + logical(C_BOOL), bind(C, name='openmc_photon_transport') :: photon_transport = .false. integer :: electron_treatment = ELECTRON_TTB ! ============================================================================ @@ -104,7 +104,8 @@ module settings particle_restart_run = .false. ! Write out initial source - logical :: write_initial_source = .false. + logical(C_BOOL), bind(C, name='openmc_write_initial_source') :: & + write_initial_source = .false. ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE logical :: create_fission_neutrons = .true. diff --git a/src/settings.cpp b/src/settings.cpp index b23013c31..aafa0fb23 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2,7 +2,11 @@ #include "openmc/capi.h" #include "openmc/constants.h" +#include "openmc/distribution.h" +#include "openmc/distribution_multi.h" +#include "openmc/distribution_spatial.h" #include "openmc/error.h" +#include "openmc/source.h" #include "openmc/string_utils.h" #include "openmc/xml_interface.h" @@ -98,6 +102,24 @@ void read_settings(pugi::xml_node* root) temperature_range[0] = range[0]; temperature_range[1] = range[1]; } + + // ========================================================================== + // EXTERNAL SOURCE + + // Get point to list of elements and make sure there is at least one + for (pugi::xml_node node : root->children("source")) { + external_sources.emplace_back(node); + } + + // If no source specified, default to isotropic point source at origin with Watt spectrum + if (external_sources.empty()) { + SourceDistribution source { + UPtrSpace{new SpatialPoint({0.0, 0.0, 0.0})}, + UPtrAngle{new Isotropic()}, + UPtrDist{new Watt(0.988, 2.249e-6)} + }; + external_sources.push_back(std::move(source)); + } } } // namespace openmc diff --git a/src/simulation.F90 b/src/simulation.F90 index df6bf13ba..b5d24180c 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -30,7 +30,6 @@ module simulation use random_lcg, only: set_particle_seed use settings use simulation_header - use source, only: initialize_source, sample_external_source use state_point, only: openmc_statepoint_write, write_source_point, load_state_point use string, only: to_str use tally, only: accumulate_tallies, setup_active_tallies, & @@ -52,6 +51,19 @@ module simulation integer(C_INT), parameter :: STATUS_EXIT_MAX_BATCH = 1 integer(C_INT), parameter :: STATUS_EXIT_ON_TRIGGER = 2 + interface + subroutine openmc_simulation_init_c() bind(C) + end subroutine + + subroutine initialize_source() bind(C) + end subroutine + + function sample_external_source() result(site) bind(C) + import Bank + type(Bank) :: site + end function + end interface + contains !=============================================================================== @@ -298,7 +310,7 @@ contains do i = 1, work call set_particle_seed((total_gen + overall_generation()) * & n_particles + work_index(rank) + i) - call sample_external_source(source_bank(i)) + source_bank(i) = sample_external_source() end do end if end if @@ -425,6 +437,9 @@ contains ! Skip if simulation has already been initialized if (simulation_initialized) return + ! Call initialization on C++ side + call openmc_simulation_init_c() + ! Set up tally procedure pointers call init_tally_routines() diff --git a/src/simulation.cpp b/src/simulation.cpp index e1dd0ac93..19cc78d19 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -1,4 +1,7 @@ +#include "openmc/simulation.h" + #include "openmc/capi.h" +#include "openmc/message_passing.h" // OPENMC_RUN encompasses all the main logic where iterations are performed // over the batches, generations, and histories in a fixed source or k-eigenvalue @@ -16,3 +19,39 @@ int openmc_run() { openmc_simulation_finalize(); return err; } + +namespace openmc { + +std::vector work_index; + +void calculate_work() +{ + // Determine minimum amount of particles to simulate on each processor + int64_t min_work = n_particles/mpi::n_procs; + + // Determine number of processors that have one extra particle + int64_t remainder = n_particles % mpi::n_procs; + + int64_t i_bank = 0; + work_index.reserve(mpi::n_procs); + work_index.push_back(0); + for (int i = 0; i < mpi::n_procs; ++i) { + // Number of particles for rank i + int64_t work_i = i < remainder ? min_work + 1 : min_work; + + // Set number of particles + if (mpi::rank == i) openmc_work = work_i; + + // Set index into source bank for rank i + i_bank += work_i; + work_index.push_back(i_bank); + } +} + +void openmc_simulation_init_c() +{ + // Determine how much work each process should do + calculate_work(); +} + +} // namespace openmc diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 60bed6425..7addf9b2c 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -22,7 +22,7 @@ module simulation_header integer(C_INT), bind(C, name='openmc_current_batch') :: current_batch ! current batch integer(C_INT), bind(C, name='openmc_current_gen') :: current_gen ! current generation within a batch - integer :: total_gen = 0 ! total number of generations simulated + integer(C_INT), bind(C, name='openmc_total_gen') :: total_gen = 0 ! total number of generations simulated logical(C_BOOL), bind(C, name='openmc_simulation_initialized') :: & simulation_initialized = .false. logical :: need_depletion_rx ! need to calculate depletion reaction rx? diff --git a/src/source.F90 b/src/source.F90 deleted file mode 100644 index a6b6a92ac..000000000 --- a/src/source.F90 +++ /dev/null @@ -1,141 +0,0 @@ -module source - -#ifdef OPENMC_MPI - use message_passing -#endif - - use algorithm, only: binary_search - use bank_header, only: Bank, source_bank - use constants - use distribution_univariate, only: Discrete - use distribution_multivariate, only: SpatialBox - use error, only: fatal_error - use geometry, only: find_cell - use hdf5_interface - use math - use message_passing, only: rank - use mgxs_interface, only: rev_energy_bins, num_energy_groups - use output, only: write_message - use particle_header, only: Particle - use random_lcg, only: prn, set_particle_seed, prn_set_stream - use settings - use simulation_header - use source_header, only: external_source - use string, only: to_str - use state_point, only: read_source_bank, write_source_bank - - implicit none - -contains - -!=============================================================================== -! INITIALIZE_SOURCE initializes particles in the source bank -!=============================================================================== - - subroutine initialize_source() - - integer(8) :: i ! loop index over bank sites - integer(8) :: id ! particle id - integer(HID_T) :: file_id - character(MAX_WORD_LEN) :: filetype - character(MAX_FILE_LEN) :: filename - type(Bank), pointer :: src ! source bank site - - call write_message("Initializing source particles...", 5) - - if (path_source /= '') then - ! Read the source from a binary file instead of sampling from some - ! assumed source distribution - - call write_message('Reading source file from ' // trim(path_source) & - &// '...', 6) - - ! Open the binary file - file_id = file_open(path_source, 'r', parallel=.true.) - - ! Read the file type - call read_attribute(filetype, file_id, "filetype") - - ! Check to make sure this is a source file - if (filetype /= 'source' .and. filetype /= 'statepoint') then - call fatal_error("Specified starting source file not a source file & - &type.") - end if - - ! Read in the source bank - call read_source_bank(file_id, work_index, source_bank) - - ! Close file - call file_close(file_id) - - else - ! Generation source sites from specified distribution in user input - do i = 1, work - ! Get pointer to source bank site - src => source_bank(i) - - ! initialize random number seed - id = total_gen*n_particles + work_index(rank) + i - call set_particle_seed(id) - - ! sample external source distribution - call sample_external_source(src) - end do - end if - - ! Write out initial source - if (write_initial_source) then - call write_message('Writing out initial source...', 5) - filename = trim(path_output) // 'initial_source.h5' - file_id = file_open(filename, 'w', parallel=.true.) - call write_source_bank(file_id, work_index, source_bank) - call file_close(file_id) - end if - - end subroutine initialize_source - -!=============================================================================== -! SAMPLE_EXTERNAL_SOURCE samples the user-specified external source and stores -! the position, angle, and energy in a Bank type. -!=============================================================================== - - subroutine sample_external_source(site) - type(Bank), intent(inout) :: site ! source site - - integer :: i ! dummy loop index - integer :: n_source ! number of source distributions - real(8) :: c ! cumulative frequency - real(8) :: xi - - ! Set the random number generator to the source stream. - call prn_set_stream(STREAM_SOURCE) - - ! Sample from among multiple source distributions - n_source = size(external_source) - if (n_source > 1) then - xi = prn()*sum(external_source(:) % strength) - c = ZERO - do i = 1, n_source - c = c + external_source(i) % strength - if (xi < c) exit - end do - else - i = 1 - end if - - ! Sample source site from i-th source distribution - site = external_source(i) % sample() - - ! If running in MG, convert site % E to group - if (.not. run_CE) then - site % E = real(binary_search(rev_energy_bins, num_energy_groups + 1, & - site % E), 8) - site % E = num_energy_groups + 1 - site % E - end if - - ! Set the random number generator back to the tracking stream. - call prn_set_stream(STREAM_TRACKING) - - end subroutine sample_external_source - -end module source diff --git a/src/source.cpp b/src/source.cpp new file mode 100644 index 000000000..e01c9795e --- /dev/null +++ b/src/source.cpp @@ -0,0 +1,355 @@ +#include "openmc/source.h" + +#include // for move +#include // for stringstream + +#include "xtensor/xadapt.hpp" + +#include "openmc/cell.h" +#include "openmc/error.h" +#include "openmc/file_utils.h" +#include "openmc/hdf5_interface.h" +#include "openmc/material.h" +#include "openmc/message_passing.h" +#include "openmc/mgxs_interface.h" +#include "openmc/nuclide.h" +#include "openmc/capi.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" +#include "openmc/settings.h" +#include "openmc/simulation.h" +#include "openmc/state_point.h" +#include "openmc/xml_interface.h" + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +std::vector external_sources; + +//============================================================================== +// SourceDistribution implementation +//============================================================================== + +SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy) + : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { } + +SourceDistribution::SourceDistribution(pugi::xml_node node) +{ + // Check for particle type + if (check_for_node(node, "particle")) { + auto temp_str = get_node_value(node, "particle", true, true); + if (temp_str == "neutron") { + particle_ = ParticleType::neutron; + } else if (temp_str == "photon") { + particle_ = ParticleType::photon; + openmc_photon_transport = true; + } else { + fatal_error(std::string("Unknown source particle type: ") + temp_str); + } + } + + // Check for source strength + if (check_for_node(node, "strength")) { + strength_ = std::stod(get_node_value(node, "strength")); + } + + // Check for external source file + if (check_for_node(node, "file")) { + // Copy path of source file + path_source = get_node_value(node, "file", false, true); + + // Check if source file exists + if (!file_exists(path_source)) { + std::stringstream msg; + msg << "Source file '" << path_source << "' does not exist."; + fatal_error(msg); + } + + } else { + + // Spatial distribution for external source + if (check_for_node(node, "space")) { + // Get pointer to spatial distribution + pugi::xml_node node_space = node.child("space"); + + // Check for type of spatial distribution and read + std::string type; + if (check_for_node(node_space, "type")) + type = get_node_value(node_space, "type", true, true); + if (type == "cartesian") { + space_ = UPtrSpace{new CartesianIndependent(node_space)}; + } else if (type == "box") { + space_ = UPtrSpace{new SpatialBox(node_space)}; + } else if (type == "fission") { + space_ = UPtrSpace{new SpatialBox(node_space, true)}; + } else if (type == "point") { + space_ = UPtrSpace{new SpatialPoint(node_space)}; + } else { + std::stringstream msg; + msg << "Invalid spatial distribution for external source: " << type; + fatal_error(msg); + } + + } else { + // If no spatial distribution specified, make it a point source + space_ = UPtrSpace{new SpatialPoint()}; + } + + // Determine external source angular distribution + if (check_for_node(node, "angle")) { + // Get pointer to angular distribution + pugi::xml_node node_angle = node.child("angle"); + + // Check for type of angular distribution + std::string type; + if (check_for_node(node_angle, "type")) + type = get_node_value(node_angle, "type", true, true); + if (type == "isotropic") { + angle_ = UPtrAngle{new Isotropic()}; + } else if (type == "monodirectional") { + angle_ = UPtrAngle{new Monodirectional(node_angle)}; + } else if (type == "mu-phi") { + angle_ = UPtrAngle{new PolarAzimuthal(node_angle)}; + } else { + std::stringstream msg; + msg << "Invalid angular distribution for external source: " << type; + fatal_error(msg); + } + + } else { + angle_ = UPtrAngle{new Isotropic()}; + } + + // Determine external source energy distribution + if (check_for_node(node, "energy")) { + pugi::xml_node node_dist = node.child("energy"); + energy_ = distribution_from_xml(node_dist); + } else { + // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 + energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)}; + } + } +} + + +Bank SourceDistribution::sample() const +{ + Bank site; + + // Set weight to one by default + site.wgt = 1.0; + + // Repeat sampling source location until a good site has been found + bool found = false; + int n_reject = 0; + static int n_accept = 0; + while (!found) { + // Set particle type + site.particle = static_cast(particle_); + + // Sample spatial distribution + Position r = space_->sample(); + site.xyz[0] = r.x; + site.xyz[1] = r.y; + site.xyz[2] = r.z; + + // Now search to see if location exists in geometry + int32_t cell_index, instance; + int err = openmc_find_cell(site.xyz, &cell_index, &instance); + found = (err != OPENMC_E_GEOMETRY); + + // Check if spatial site is in fissionable material + if (found) { + auto space_box = dynamic_cast(space_.get()); + if (space_box) { + if (space_box->only_fissionable()) { + // Determine material + auto c = global_cells[cell_index - 1]; + int32_t mat_index = c->material[instance]; + auto m = global_materials[mat_index]; + + if (mat_index == MATERIAL_VOID) { + found = false; + } else { + bool fissionable; + openmc_material_get_fissionable(mat_index + 1, &fissionable); + if (!fissionable) found = false; + } + } + } + } + + // Check for rejection + if (!found) { + ++n_reject; + if (n_reject >= EXTSRC_REJECT_THRESHOLD && + static_cast(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) { + fatal_error("More than 95% of external source sites sampled were " + "rejected. Please check your external source definition."); + } + } + } + + // Increment number of accepted samples + ++n_accept; + + // Sample angle + Direction u = angle_->sample(); + site.uvw[0] = u.x; + site.uvw[1] = u.y; + site.uvw[2] = u.z; + + // Check for monoenergetic source above maximum particle energy + auto p = static_cast(particle_); + auto energy_ptr = dynamic_cast(energy_.get()); + if (energy_ptr) { + auto energies = xt::adapt(energy_ptr->x()); + if (xt::any(energies > energy_max[p-1])) { + fatal_error("Source energy above range of energies of at least " + "one cross section table"); + } else if (xt::any(energies < energy_min[p-1])) { + fatal_error("Source energy below range of energies of at least " + "one cross section table"); + } + } + + while (true) { + // Sample energy spectrum + site.E = energy_->sample(); + + // Resample if energy falls outside minimum or maximum particle energy + if (site.E < energy_max[p-1] && site.E > energy_min[p-1]) break; + } + + // Set delayed group + site.delayed_group = 0; + + return site; +} + +//============================================================================== +// Non-member functions +//============================================================================== + +void initialize_source() +{ + write_message("Initializing source particles...", 5); + + // Get pointer to source bank + Bank* source_bank; + int64_t n; + openmc_source_bank(&source_bank, &n); + + if (path_source != "") { + // Read the source from a binary file instead of sampling from some + // assumed source distribution + + std::stringstream msg; + msg << "Reading source file from " << path_source << "..."; + write_message(msg, 6); + + // Open the binary file + hid_t file_id = file_open(path_source, 'r', true); + + // Read the file type + std::string filetype; + read_attribute(file_id, "filetype", filetype); + + // Check to make sure this is a source file + if (filetype != "source" && filetype != "statepoint") { + fatal_error("Specified starting source file not a source file type."); + } + + // Read in the source bank + read_source_bank(file_id, work_index.data(), source_bank); + + // Close file + file_close(file_id); + + } else { + // Generation source sites from specified distribution in user input + for (int64_t i = 0; i < openmc_work; ++i) { + // initialize random number seed + int64_t id = openmc_total_gen*n_particles + work_index[openmc::mpi::rank] + i + 1; + set_particle_seed(id); + + // sample external source distribution + source_bank[i] = sample_external_source(); + } + } + + // Write out initial source + if (openmc_write_initial_source) { + write_message("Writing out initial source...", 5); + std::string filename = path_output + "initial_source.h5"; + hid_t file_id = file_open(filename, 'w', true); + write_source_bank(file_id, work_index.data(), source_bank); + file_close(file_id); + } +} + +extern "C" double* rev_energy_bins_ptr(); + +Bank sample_external_source() +{ + // Set the random number generator to the source stream. + prn_set_stream(STREAM_SOURCE); + + // Determine total source strength + double total_strength = 0.0; + for (auto& s : external_sources) + total_strength += s.strength(); + + // Sample from among multiple source distributions + auto n_source = external_sources.size(); + int i = 0; + if (n_source > 1) { + double xi = prn()*total_strength; + double c = 0.0; + for (i = 0; i < external_sources.size(); ++i) { + c += external_sources[i].strength(); + if (xi < c) break; + } + } + + // Sample source site from i-th source distribution + Bank site {external_sources[i].sample()}; + + // If running in MG, convert site % E to group + if (!openmc_run_CE) { + // Get pointer to rev_energy_bins array on Fortran side + double* rev_energy_bins = rev_energy_bins_ptr(); + + int n = num_energy_groups + 1; + site.E = lower_bound_index(rev_energy_bins, rev_energy_bins + n, site.E); + site.E = num_energy_groups - site.E; + } + + // Set the random number generator back to the tracking stream. + prn_set_stream(STREAM_TRACKING); + + return site; +} + +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" void free_memory_source() +{ + external_sources.clear(); +} + +extern "C" double total_source_strength() +{ + double strength = 0.0; + for (const auto& s : external_sources) { + strength += s.strength(); + } + return strength; +} + +} // namespace openmc diff --git a/src/source_header.F90 b/src/source_header.F90 deleted file mode 100644 index 163ae1c19..000000000 --- a/src/source_header.F90 +++ /dev/null @@ -1,388 +0,0 @@ -module source_header - - use, intrinsic :: ISO_C_BINDING - - use bank_header, only: Bank - use constants - use distribution_univariate - use distribution_multivariate - use error - use geometry, only: find_cell - use material_header, only: materials - use nuclide_header, only: energy_min, energy_max - use particle_header - use settings, only: photon_transport - use string, only: to_lower - use xml_interface - - implicit none - private - public :: free_memory_source - public :: openmc_extend_sources - public :: openmc_source_set_strength - - integer :: n_accept = 0 ! Number of samples accepted - integer :: n_reject = 0 ! Number of samples rejected - -!=============================================================================== -! SOURCEDISTRIBUTION describes an external source of particles for a -! fixed-source problem or for the starting source in a k eigenvalue problem -!=============================================================================== - - type, public :: SourceDistribution - integer :: particle ! particle type - real(8) :: strength = ONE ! source strength - class(SpatialDistribution), allocatable :: space ! spatial distribution - class(UnitSphereDistribution), allocatable :: angle ! angle distribution - class(Distribution), allocatable :: energy ! energy distribution - contains - procedure :: from_xml - procedure :: sample - end type SourceDistribution - - ! Number of external source distributions - integer(C_INT32_T), public, bind(C) :: n_sources = 0 - - ! External source distributions - type(SourceDistribution), public, allocatable :: external_source(:) - -contains - - subroutine from_xml(this, node, path_source) - class(SourceDistribution), intent(inout) :: this - type(XMLNode), intent(in) :: node - character(MAX_FILE_LEN), intent(out) :: path_source - - integer :: n - logical :: file_exists - character(MAX_WORD_LEN) :: type, temp_str - type(XMLNode) :: node_space - type(XMLNode) :: node_angle - type(XMLNode) :: node_dist - - ! Check for particle type - if (check_for_node(node, "particle")) then - call get_node_value(node, "particle", temp_str) - select case (to_lower(temp_str)) - case ('neutron') - this % particle = NEUTRON - case ('photon') - this % particle = PHOTON - photon_transport = .true. - case default - call fatal_error('Unknown source particle type: ' // trim(temp_str)) - end select - else - this % particle = NEUTRON - end if - - ! Check for source strength - if (check_for_node(node, "strength")) then - call get_node_value(node, "strength", this % strength) - end if - - ! Check for external source file - if (check_for_node(node, "file")) then - ! Copy path of source file - call get_node_value(node, "file", path_source) - - ! Check if source file exists - inquire(FILE=path_source, EXIST=file_exists) - if (.not. file_exists) then - call fatal_error("Source file '" // trim(path_source) & - // "' does not exist!") - end if - - else - - ! Spatial distribution for external source - if (check_for_node(node, "space")) then - - ! Get pointer to spatial distribution - node_space = node % child("space") - - ! Check for type of spatial distribution - type = '' - if (check_for_node(node_space, "type")) & - call get_node_value(node_space, "type", type) - select case (to_lower(type)) - case ('cartesian') - allocate(CartesianIndependent :: this % space) - - case ('box') - allocate(SpatialBox :: this % space) - - case ('fission') - allocate(SpatialBox :: this % space) - select type(space => this % space) - type is (SpatialBox) - space % only_fissionable = .true. - end select - - case ('point') - allocate(SpatialPoint :: this % space) - - case default - call fatal_error("Invalid spatial distribution for external source: "& - // trim(type)) - end select - - ! Read spatial distribution from XML - call this % space % from_xml(node_space) - - else - ! If no spatial distribution specified, make it a point source - allocate(SpatialPoint :: this % space) - select type (space => this % space) - type is (SpatialPoint) - space % xyz(:) = [ZERO, ZERO, ZERO] - end select - end if - - ! Determine external source angular distribution - if (check_for_node(node, "angle")) then - - ! Get pointer to angular distribution - node_angle = node % child("angle") - - ! Check for type of angular distribution - type = '' - if (check_for_node(node_angle, "type")) & - call get_node_value(node_angle, "type", type) - select case (to_lower(type)) - case ('isotropic') - allocate(Isotropic :: this % angle) - - case ('monodirectional') - allocate(Monodirectional :: this % angle) - - case ('mu-phi') - allocate(PolarAzimuthal :: this % angle) - - case default - call fatal_error("Invalid angular distribution for external source: "& - // trim(type)) - end select - - ! Read reference directional unit vector - if (check_for_node(node_angle, "reference_uvw")) then - n = node_word_count(node_angle, "reference_uvw") - if (n /= 3) then - call fatal_error('Angular distribution reference direction must have & - &three parameters specified.') - end if - call get_node_array(node_angle, "reference_uvw", & - this % angle % reference_uvw) - else - ! By default, set reference unit vector to be positive z-direction - this % angle % reference_uvw(:) = [ZERO, ZERO, ONE] - end if - - ! Read parameters for angle distribution - select type (angle => this % angle) - type is (Monodirectional) - call get_node_array(node_angle, "reference_uvw", & - this % angle % reference_uvw) - - type is (PolarAzimuthal) - if (check_for_node(node_angle, "mu")) then - node_dist = node_angle % child("mu") - call distribution_from_xml(angle % mu, node_dist) - else - allocate(Uniform :: angle%mu) - select type (mu => angle%mu) - type is (Uniform) - mu % a = -ONE - mu % b = ONE - end select - end if - - if (check_for_node(node_angle, "phi")) then - node_dist = node_angle % child("phi") - call distribution_from_xml(angle % phi, node_dist) - else - allocate(Uniform :: angle%phi) - select type (phi => angle%phi) - type is (Uniform) - phi % a = ZERO - phi % b = TWO*PI - end select - end if - end select - - else - ! Set default angular distribution isotropic - allocate(Isotropic :: this % angle) - this % angle % reference_uvw(:) = [ZERO, ZERO, ONE] - end if - - ! Determine external source energy distribution - if (check_for_node(node, "energy")) then - node_dist = node % child("energy") - call distribution_from_xml(this % energy, node_dist) - else - ! Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 - allocate(Watt :: this % energy) - select type(energy => this % energy) - type is (Watt) - energy % a = 0.988e6_8 - energy % b = 2.249e-6_8 - end select - end if - end if - - end subroutine from_xml - - function sample(this) result(site) - class(SourceDistribution), intent(in) :: this - type(Bank) :: site - - logical :: found ! Does the source particle exist within geometry? - type(Particle) :: p ! Temporary particle for using find_cell - - ! Set weight to one by default - site % wgt = ONE - - ! Repeat sampling source location until a good site has been found - found = .false. - do while (.not. found) - ! Set particle defaults - call particle_initialize(p) - - ! Set particle type - site % particle = this % particle - - ! Sample spatial distribution - site % xyz(:) = this % space % sample() - - ! Fill p with needed data - p % coord(1) % xyz(:) = site % xyz - p % coord(1) % uvw(:) = [ ONE, ZERO, ZERO ] - - ! Now search to see if location exists in geometry - call find_cell(p, found) - - ! Check if spatial site is in fissionable material - if (found) then - select type (space => this % space) - type is (SpatialBox) - if (space % only_fissionable) then - if (p % material == MATERIAL_VOID) then - found = .false. - elseif (.not. materials(p % material) % fissionable) then - found = .false. - end if - end if - end select - end if - - ! Check for rejection - if (.not. found) then - n_reject = n_reject + 1 - if (n_reject >= EXTSRC_REJECT_THRESHOLD .and. & - real(n_accept, 8)/n_reject <= EXTSRC_REJECT_FRACTION) then - call fatal_error("More than 95% of external source sites sampled & - &were rejected. Please check your external source definition.") - end if - end if - end do - - ! Increment number of accepted samples - n_accept = n_accept + 1 - - call particle_clear(p) - - ! Sample angle - site % uvw(:) = this % angle % sample() - - ! Check for monoenergetic source above maximum particle energy - select type (energy => this % energy) - type is (Discrete) - if (any(energy % x > energy_max(this % particle))) then - call fatal_error("Source energy above range of energies of at least & - &one cross section table") - else if (any(energy % x < energy_min(this % particle))) then - call fatal_error("Source energy below range of energies of at least & - &one cross section table") - end if - end select - - do - ! Sample energy spectrum - site % E = this % energy % sample() - - ! Resample if energy falls outside minimum or maximum particle energy - if (site % E < energy_max(this % particle) .and. & - site % E > energy_min(this % particle)) exit - end do - - ! Set delayed group - site % delayed_group = 0 - - end function sample - -!=============================================================================== -! FREE_MEMORY_SOURCE deallocates global arrays defined in this module -!=============================================================================== - - subroutine free_memory_source() - n_sources = 0 - if (allocated(external_source)) deallocate(external_source) - end subroutine free_memory_source - -!=============================================================================== -! C API FUNCTIONS -!=============================================================================== - - function openmc_extend_sources(n, index_start, index_end) result(err) bind(C) - ! Extend the external_source array by n elements - 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_INT) :: err - - type(SourceDistribution), allocatable :: temp(:) ! temporary array - - if (n_sources == 0) then - ! Allocate external_source array - allocate(external_source(n)) - else - ! Allocate external_source array with increased size - allocate(temp(n_sources + n)) - - ! Copy original source array to temporary array - temp(1:n_sources) = external_source - - ! Move allocation from temporary array - call move_alloc(FROM=temp, TO=external_source) - end if - - ! Return indices in external_source array - if (present(index_start)) index_start = n_sources + 1 - if (present(index_end)) index_end = n_sources + n - n_sources = n_sources + n - - err = 0 - end function openmc_extend_sources - - - function openmc_source_set_strength(index, strength) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: index - real(C_DOUBLE), value, intent(in) :: strength - integer(C_INT) :: err - - if (index >= 1 .and. index <= n_sources) then - if (strength > ZERO) then - external_source(index) % strength = strength - err = 0 - else - err = E_INVALID_ARGUMENT - call set_errmsg("Source strength must be positive.") - end if - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in external source array is out of bounds.") - end if - end function openmc_source_set_strength - -end module source_header diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 32f094f89..367214a93 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -9,7 +9,6 @@ module tally_header use message_passing, only: n_procs use nuclide_header, only: nuclide_dict use settings, only: reduce_tallies, run_mode - use source_header, only: external_source use stl_vector, only: VectorInt use string, only: to_lower, to_f_string, str_to_int, to_str use tally_filter_header, only: TallyFilterContainer, filters, n_filters @@ -169,6 +168,13 @@ contains real(C_DOUBLE) :: val real(C_DOUBLE) :: total_source + interface + function total_source_strength() result(strength) bind(C) + import C_DOUBLE + real(C_DOUBLE) :: strength + end function + end interface + ! Increment number of realizations if (reduce_tallies) then this % n_realizations = this % n_realizations + 1 @@ -178,7 +184,7 @@ contains ! Calculate total source strength for normalization if (run_mode == MODE_FIXEDSOURCE) then - total_source = sum(external_source(:) % strength) + total_source = total_source_strength() else total_source = ONE end if diff --git a/src/xml_interface.F90 b/src/xml_interface.F90 index 0e08f75d1..7aa86556b 100644 --- a/src/xml_interface.F90 +++ b/src/xml_interface.F90 @@ -18,6 +18,7 @@ module xml_interface interface get_node_value module procedure get_node_value_bool + module procedure get_node_value_cbool module procedure get_node_value_integer module procedure get_node_value_long module procedure get_node_value_double @@ -118,6 +119,16 @@ contains end if end subroutine get_node_value_bool + subroutine get_node_value_cbool(node, name, val) + type(XMLNode), intent(in) :: node + character(*), intent(in) :: name + logical(kind=C_BOOL), intent(out) :: val + + logical :: val_ + call get_node_value_bool(node, name, val_) + val = val_ + end subroutine get_node_value_cbool + !=============================================================================== ! GET_NODE_VALUE_INTEGER returns a integer value from an attribute or node !=============================================================================== From c3b7ebd40c020f4800791d5bb199d190b04bdb6a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 23 Aug 2018 13:40:38 -0500 Subject: [PATCH 18/76] Remove path_source on Fortran side --- src/settings.F90 | 1 - src/simulation.F90 | 13 +++++-------- src/simulation_header.F90 | 4 ++-- src/source.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/settings.F90 b/src/settings.F90 index dfe4afbe3..710a87e1e 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -121,7 +121,6 @@ module settings character(MAX_FILE_LEN) :: path_input ! Path to input file character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml character(MAX_FILE_LEN) :: path_multipole ! Path to wmp library - character(MAX_FILE_LEN) :: path_source = '' ! Path to binary source character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart diff --git a/src/simulation.F90 b/src/simulation.F90 index b5d24180c..d5ca165b5 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -253,7 +253,10 @@ contains subroutine finalize_generation() - integer(8) :: i + interface + subroutine fill_source_bank_fixedsource() bind(C) + end subroutine + end interface ! Update global tallies with the omp private accumulation variables !$omp parallel @@ -306,13 +309,7 @@ contains elseif (run_mode == MODE_FIXEDSOURCE) then ! For fixed-source mode, we need to sample the external source - if (path_source == '') then - do i = 1, work - call set_particle_seed((total_gen + overall_generation()) * & - n_particles + work_index(rank) + i) - source_bank(i) = sample_external_source() - end do - end if + call fill_source_bank_fixedsource() end if end subroutine finalize_generation diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 7addf9b2c..d7040b8d5 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -80,8 +80,8 @@ contains ! OVERALL_GENERATION determines the overall generation number !=============================================================================== - pure function overall_generation() result(gen) - integer :: gen + pure function overall_generation() result(gen) bind(C) + integer(C_INT) :: gen gen = gen_per_batch*(current_batch - 1) + current_gen end function overall_generation diff --git a/src/source.cpp b/src/source.cpp index e01c9795e..c3869fcf4 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -352,4 +352,28 @@ extern "C" double total_source_strength() return strength; } +// Needed in fill_source_bank_fixedsource +extern "C" int overall_generation(); + +//! Fill source bank at end of generation for fixed source simulations +extern "C" void fill_source_bank_fixedsource() +{ + if (path_source.empty()) { + // Get pointer to source bank + Bank* source_bank; + int64_t n; + openmc_source_bank(&source_bank, &n); + + for (int64_t i = 0; i < openmc_work; ++i) { + // initialize random number seed + int64_t id = (openmc_total_gen + overall_generation())*n_particles + + work_index[openmc::mpi::rank] + i + 1; + set_particle_seed(id); + + // sample external source distribution + source_bank[i] = sample_external_source(); + } + } +} + } // namespace openmc From d4a6e8d827afe5b110747702e7808b296439f2c6 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 23 Aug 2018 15:33:19 -0500 Subject: [PATCH 19/76] Update --- openmc/polynomial.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/polynomial.py b/openmc/polynomial.py index 3552819f6..8bcb74f68 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -1,7 +1,7 @@ import numpy as np import openmc import openmc.capi as capi -from collections import Iterable +from collections.abc import Iterable def legendre_from_expcoef(coef, domain=(-1, 1)): From 83d64397d15353620cceaf6c7504ae733f1b975c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 23 Aug 2018 21:38:23 -0500 Subject: [PATCH 20/76] Add doxygen comments where needed --- include/openmc/distribution.h | 1 + include/openmc/distribution_spatial.h | 2 ++ include/openmc/file_utils.h | 7 +++++-- include/openmc/nuclide.h | 9 +++++++++ include/openmc/simulation.h | 14 ++++++++++++++ include/openmc/source.h | 19 ++++++++++++++----- src/nuclide.cpp | 9 ++++++++- src/simulation.cpp | 20 ++++++++++++++------ 8 files changed, 67 insertions(+), 14 deletions(-) diff --git a/include/openmc/distribution.h b/include/openmc/distribution.h index b8ebcabf4..6db3c1618 100644 --- a/include/openmc/distribution.h +++ b/include/openmc/distribution.h @@ -37,6 +37,7 @@ public: //! \return Sampled value double sample() const; + // Properties const std::vector& x() const { return x_; } const std::vector& p() const { return p_; } private: diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index e94005f0f..248f03588 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -48,6 +48,8 @@ public: //! Sample a position from the distribution //! \return Sampled position Position sample() const; + + // Properties bool only_fissionable() const { return only_fissionable_; } private: Position lower_left_; //!< Lower-left coordinates of box diff --git a/include/openmc/file_utils.h b/include/openmc/file_utils.h index 0a24cb547..f9c23468d 100644 --- a/include/openmc/file_utils.h +++ b/include/openmc/file_utils.h @@ -6,12 +6,15 @@ namespace openmc { +//! Determine if a file exists +//! \param[in] filename Path to file +//! \return Whether file exists inline bool file_exists(const std::string& filename) { std::ifstream s {filename}; return s.good(); } -} +} // namespace openmc -#endif // OPENMC_FILE_UTILS_H \ No newline at end of file +#endif // OPENMC_FILE_UTILS_H diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index 8a19791ba..e3d43450d 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -1,3 +1,6 @@ +//! \file nuclide.h +//! \brief Nuclide type and other associated types/data + #ifndef OPENMC_NUCLIDE_H #define OPENMC_NUCLIDE_H @@ -7,6 +10,12 @@ namespace openmc { +//============================================================================== +// Global variables +//============================================================================== + +// Minimum/maximum transport energy for each particle type. Order corresponds to +// that of the ParticleType enum extern std::array energy_min; extern std::array energy_max; diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index a1350c936..daf7393fb 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -1,3 +1,6 @@ +//! \file simulation.h +//! \brief Variables/functions related to a running simulation + #ifndef OPENMC_SIMULATION_H #define OPENMC_SIMULATION_H @@ -6,6 +9,10 @@ namespace openmc { +//============================================================================== +// Global variables +//============================================================================== + extern "C" int openmc_current_batch; extern "C" int openmc_current_gen; extern "C" int64_t openmc_current_work; @@ -16,7 +23,14 @@ extern std::vector work_index; #pragma omp threadprivate(openmc_current_work) +//============================================================================== +// Functions +//============================================================================== + +//! Initialize simulation extern "C" void openmc_simulation_init_c(); + +//! Determine number of particles to transport per process void calculate_work(); } // namespace openmc diff --git a/include/openmc/source.h b/include/openmc/source.h index ac5f69a2f..2e8c9491a 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -1,3 +1,6 @@ +//! \file source.h +//! \brief External source distributions + #ifndef OPENMC_SOURCE_H #define OPENMC_SOURCE_H @@ -19,17 +22,22 @@ namespace openmc { class SourceDistribution { public: + // Constructors SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy); explicit SourceDistribution(pugi::xml_node node); + //! Sample from the external source distribution + //! \return Sampled site Bank sample() const; + + // Properties double strength() const { return strength_; } private: - ParticleType particle_ {ParticleType::neutron}; - double strength_ {1.0}; - UPtrSpace space_; - UPtrAngle angle_; - UPtrDist energy_; + ParticleType particle_ {ParticleType::neutron}; //!< Type of particle emitted + double strength_ {1.0}; //!< Source strength + UPtrSpace space_; //!< Spatial distribution + UPtrAngle angle_; //!< Angular distribution + UPtrDist energy_; //!< Energy distribution }; //============================================================================== @@ -47,6 +55,7 @@ extern "C" void initialize_source(); //! Sample a site from all external source distributions in proportion to their //! source strength +//! \return Sampled source site extern "C" Bank sample_external_source(); } // namespace openmc diff --git a/src/nuclide.cpp b/src/nuclide.cpp index f7f5399ba..79e2289ae 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -2,10 +2,17 @@ namespace openmc { -// Order corresponds to ParticleType enum +//============================================================================== +// Global variables +//============================================================================== + std::array energy_min {0.0, 0.0}; std::array energy_max {INFTY, INFTY}; +//============================================================================== +// Fortran compatibility functions +//============================================================================== + extern "C" void set_particle_energy_bounds(int particle, double E_min, double E_max) { diff --git a/src/simulation.cpp b/src/simulation.cpp index 19cc78d19..3514f4a47 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -22,8 +22,22 @@ int openmc_run() { namespace openmc { +//============================================================================== +// Global variables +//============================================================================== + std::vector work_index; +//============================================================================== +// Functions +//============================================================================== + +void openmc_simulation_init_c() +{ + // Determine how much work each process should do + calculate_work(); +} + void calculate_work() { // Determine minimum amount of particles to simulate on each processor @@ -48,10 +62,4 @@ void calculate_work() } } -void openmc_simulation_init_c() -{ - // Determine how much work each process should do - calculate_work(); -} - } // namespace openmc From 7b3185306628509baec37b061fd24c20970caab6 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 21 Aug 2018 12:10:01 -0400 Subject: [PATCH 21/76] Remove Universe type from Fortran --- src/cell.cpp | 27 ++++++++++++++++++++++ src/cell.h | 5 +++- src/geometry_header.F90 | 17 +++++--------- src/hdf5_interface.h | 13 +++++++++++ src/input_xml.F90 | 24 +------------------ src/output.F90 | 5 ++-- src/summary.F90 | 33 ++++++++------------------- src/tallies/tally_filter_universe.F90 | 4 ++-- src/volume_calc.F90 | 4 ++-- 9 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index a3a5d9fde..e6dbb348d 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -182,6 +182,28 @@ generate_rpn(int32_t cell_id, std::vector infix) return rpn; } +//============================================================================== +// Universe implementation +//============================================================================== + +void +Universe::to_hdf5(hid_t universes_group) const +{ + // Create a group for this universe. + std::stringstream group_name; + group_name << "universe " << id; + auto group = create_group(universes_group, group_name); + + // Write the contained cells. + if (cells.size() > 0) { + std::vector cell_ids; + for (auto i_cell : cells) cell_ids.push_back(global_cells[i_cell]->id); + write_dataset(group, "cells", cell_ids); + } + + close_group(group); +} + //============================================================================== // Cell implementation //============================================================================== @@ -704,6 +726,11 @@ extern "C" { } n_cells = global_cells.size(); } + + int32_t universe_id(int i_univ) {return global_universes[i_univ]->id;} + + void universes_to_hdf5(hid_t universes_group) + {for (Universe* u : global_universes) u->to_hdf5(universes_group);} } diff --git a/src/cell.h b/src/cell.h index a10c407f0..72b09f7a8 100644 --- a/src/cell.h +++ b/src/cell.h @@ -55,7 +55,10 @@ class Universe public: int32_t id; //!< Unique ID std::vector cells; //!< Cells within this universe - //double x0, y0, z0; //!< Translation coordinates. + + //! \brief Write universe 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 504534d30..df59e3410 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -16,6 +16,12 @@ module geometry_header implicit none interface + function universe_id(universe_ind) bind(C) result(id) + import C_INT, C_INT32_T + integer(C_INT), intent(in), value :: universe_ind + integer(C_INT32_T) :: id + end function universe_id + function cell_pointer(cell_ind) bind(C) result(ptr) import C_PTR, C_INT32_T integer(C_INT32_T), intent(in), value :: cell_ind @@ -177,15 +183,6 @@ module geometry_header end subroutine extend_cells_c end interface -!=============================================================================== -! UNIVERSE defines a geometry that fills all phase space -!=============================================================================== - - type Universe - integer :: id ! Unique ID - integer, allocatable :: cells(:) ! List of cells within - end type Universe - !=============================================================================== ! LATTICE abstract type for ordered array of universes. !=============================================================================== @@ -260,7 +257,6 @@ module geometry_header integer(C_INT32_T), bind(C) :: n_universes ! # of universes type(Cell), allocatable, target :: cells(:) - type(Universe), allocatable, target :: universes(:) type(LatticeContainer), allocatable, target :: lattices(:) ! Dictionaries which map user IDs to indices in the global arrays @@ -483,7 +479,6 @@ contains n_universes = 0 if (allocated(cells)) deallocate(cells) - if (allocated(universes)) deallocate(universes) if (allocated(lattices)) deallocate(lattices) call cell_dict % clear() diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 65a9e2c99..e749a8e1b 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -36,7 +36,13 @@ bool using_mpio_device(hid_t obj_id); //============================================================================== hid_t create_group(hid_t parent_id, const std::string& name); + +inline hid_t create_group(hid_t parent_id, const std::stringstream& name) +{return create_group(parent_id, name.str());} + + hid_t file_open(const std::string& filename, char mode, bool parallel=false); + void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); @@ -314,6 +320,13 @@ write_dataset(hid_t obj_id, const char* name, const std::array& buffer) write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); } +template inline void +write_dataset(hid_t obj_id, const char* name, const std::vector& buffer) +{ + hsize_t dims[] {buffer.size()}; + write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); +} + inline void write_dataset(hid_t obj_id, const char* name, Position r) { diff --git a/src/input_xml.F90 b/src/input_xml.F90 index bea0ed637..e938a456b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1002,7 +1002,7 @@ contains subroutine read_geometry_xml() - integer :: i, j + integer :: i integer :: n, n_rlats, n_hlats integer :: univ_id integer :: n_cells_in_univ @@ -1205,30 +1205,8 @@ contains ! SETUP UNIVERSES ! Allocate universes, universe cell arrays, and assign base universe - allocate(universes(n_universes)) - do i = 1, n_universes - associate (u => universes(i)) - u % id = univ_ids % data(i) - - ! Allocate cell list - n_cells_in_univ = cells_in_univ_dict % get(u % id) - allocate(u % cells(n_cells_in_univ)) - u % cells(:) = 0 - end associate - end do root_universe = find_root_universe() + 1 - do i = 1, n_cells - ! Get index in universes array - 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 - associate (u => universes(j)) - u % cells(find(u % cells, 0)) = i - end associate - end do - ! Clear dictionary call cells_in_univ_dict%clear() diff --git a/src/output.F90 b/src/output.F90 index 62b3ee082..78614269d 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -211,7 +211,6 @@ contains integer :: i ! index for coordinate levels type(Cell), pointer :: c - type(Universe), pointer :: u class(Lattice), pointer :: l ! display type of particle @@ -239,8 +238,8 @@ contains ! Print universe for this level if (p % coord(i) % universe /= NONE) then - u => universes(p % coord(i) % universe) - write(ou,*) ' Universe = ' // trim(to_str(u % id)) + write(ou,*) ' Universe = ' & + // trim(to_str(universe_id(p % coord(i) % universe-1))) end if ! Print information on lattice diff --git a/src/summary.F90 b/src/summary.F90 index e2cc5f786..e7823a6aa 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -163,16 +163,22 @@ contains integer :: i, j, cell_fill integer, allocatable :: cell_materials(:) - integer, allocatable :: cell_ids(:) real(8), allocatable :: cell_temperatures(:) integer(HID_T) :: geom_group integer(HID_T) :: cells_group, cell_group integer(HID_T) :: surfaces_group - integer(HID_T) :: universes_group, univ_group + integer(HID_T) :: universes_group integer(HID_T) :: lattices_group type(Cell), pointer :: c class(Lattice), pointer :: lat + interface + subroutine universes_to_hdf5(universes_group) bind(C) + import HID_T + integer(HID_T), intent(in), value :: universes_group + end subroutine universes_to_hdf5 + end interface + ! Use H5LT interface to write number of geometry objects geom_group = create_group(file_id, "geometry") call write_attribute(geom_group, "n_cells", n_cells) @@ -254,29 +260,8 @@ contains ! ========================================================================== ! WRITE INFORMATION ON UNIVERSES - ! Create universes group (nothing directly written here) then close universes_group = create_group(geom_group, "universes") - - ! Write information on each universe - UNIVERSE_LOOP: do i = 1, n_universes - associate (u => universes(i)) - univ_group = create_group(universes_group, "universe " // & - trim(to_str(u%id))) - - ! Write list of cells in this universe - 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() - end do - call write_dataset(univ_group, "cells", cell_ids) - deallocate(cell_ids) - end if - - call close_group(univ_group) - end associate - end do UNIVERSE_LOOP - + call universes_to_hdf5(universes_group) call close_group(universes_group) ! ========================================================================== diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 index 0dc5aefe1..2bfc38208 100644 --- a/src/tallies/tally_filter_universe.F90 +++ b/src/tallies/tally_filter_universe.F90 @@ -78,7 +78,7 @@ contains allocate(universe_ids(size(this % universes))) do i = 1, size(this % universes) - universe_ids(i) = universes(this % universes(i)) % id + universe_ids(i) = universe_id(this % universes(i)-1) end do call write_dataset(filter_group, "bins", universe_ids) end subroutine to_statepoint_universe @@ -112,7 +112,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Universe " // to_str(universes(this % universes(bin)) % id) + label = "Universe " // to_str(universe_id(this % universes(bin)-1)) end function text_label_universe end module tally_filter_universe diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index e0c3e8859..93774f98c 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -9,7 +9,7 @@ module volume_calc use constants use error, only: write_message use geometry, only: find_cell - use geometry_header, only: universes, cells + use geometry_header, only: cells, universe_id use hdf5_interface, only: file_open, file_close, write_attribute, & create_group, close_group, write_dataset, HID_T use output, only: header, time_stamp @@ -216,7 +216,7 @@ contains elseif (this % domain_type == FILTER_UNIVERSE) then do level = 1, p % n_coord do i_domain = 1, size(this % domain_id) - if (universes(p % coord(level) % universe) % id == & + if (universe_id(p % coord(level) % universe - 1) == & this % domain_id(i_domain)) then i_material = p % material call check_hit(i_domain, i_material, indices, hits, n_mat) From d38b3f771484bd9d2502e9d20c48498d61f7b59e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 15:53:58 -0500 Subject: [PATCH 22/76] Address @smharper comments --- src/source.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/source.cpp b/src/source.cpp index c3869fcf4..70240b10d 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -304,12 +304,11 @@ Bank sample_external_source() total_strength += s.strength(); // Sample from among multiple source distributions - auto n_source = external_sources.size(); int i = 0; - if (n_source > 1) { + if (external_sources.size() > 1) { double xi = prn()*total_strength; double c = 0.0; - for (i = 0; i < external_sources.size(); ++i) { + for (; i < external_sources.size(); ++i) { c += external_sources[i].strength(); if (xi < c) break; } From 4ad072584307c6b8aa0332a28004172d8b17d3cc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 09:38:13 -0500 Subject: [PATCH 23/76] Put variables in settings.h into settings namespace --- include/openmc/settings.h | 26 +++++++++++++++----------- src/initialize.cpp | 24 ++++++++++++------------ src/particle.cpp | 3 ++- src/settings.F90 | 17 +++++++---------- src/settings.cpp | 14 ++++++++++---- src/source.cpp | 22 +++++++++++----------- src/thermal.cpp | 4 ++-- 7 files changed, 59 insertions(+), 51 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 49e0ab69e..be56e0b60 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -15,21 +15,23 @@ namespace openmc { // Global variable declarations //============================================================================== +namespace settings { + // Defined on Fortran side -extern "C" bool openmc_check_overlaps; -extern "C" bool openmc_particle_restart_run; -extern "C" bool openmc_photon_transport; -extern "C" bool openmc_restart_run; -extern "C" bool openmc_run_CE; -extern "C" bool openmc_write_all_tracks; -extern "C" bool openmc_write_initial_source; +extern "C" bool check_overlaps; +extern "C" bool particle_restart_run; +extern "C" bool photon_transport; +extern "C" bool restart_run; +extern "C" bool run_CE; +extern "C" bool write_all_tracks; +extern "C" bool write_initial_source; // Defined in .cpp // TODO: Make strings instead of char* once Fortran is gone -extern "C" char* openmc_path_input; -extern "C" char* openmc_path_statepoint; -extern "C" char* openmc_path_sourcepoint; -extern "C" char* openmc_path_particle_restart; +extern "C" char* path_input; +extern "C" char* path_statepoint; +extern "C" char* path_sourcepoint; +extern "C" char* path_particle_restart; extern std::string path_cross_sections; extern std::string path_multipole; extern std::string path_output; @@ -41,6 +43,8 @@ extern double temperature_tolerance; extern double temperature_default; extern std::array temperature_range; +} // namespace settings + //============================================================================== //! Read settings from XML file //! \param[in] root XML node for diff --git a/src/initialize.cpp b/src/initialize.cpp index 21ab93b72..dfbf41834 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -109,7 +109,7 @@ parse_command_line(int argc, char* argv[]) if (arg[0] == '-') { if (arg == "-p" || arg == "--plot") { openmc_run_mode = RUN_MODE_PLOTTING; - openmc_check_overlaps = true; + settings::check_overlaps = true; } else if (arg == "-n" || arg == "--particles") { i += 1; @@ -127,11 +127,11 @@ parse_command_line(int argc, char* argv[]) // Set path and flag for type of run if (filetype == "statepoint") { - openmc_path_statepoint = argv[i]; - openmc_restart_run = true; + settings::path_statepoint = argv[i]; + settings::restart_run = true; } else if (filetype == "particle restart") { - openmc_path_particle_restart = argv[i]; - openmc_particle_restart_run = true; + settings::path_particle_restart = argv[i]; + settings::particle_restart_run = true; } else { std::stringstream msg; msg << "Unrecognized file after restart flag: " << filetype << "."; @@ -140,7 +140,7 @@ parse_command_line(int argc, char* argv[]) } // If its a restart run check for additional source file - if (openmc_restart_run && i + 1 < argc) { + if (settings::restart_run && i + 1 < argc) { // Check if it has extension we can read if (ends_with(argv[i+1], ".h5")) { @@ -156,21 +156,21 @@ parse_command_line(int argc, char* argv[]) } // It is a source file - openmc_path_sourcepoint = argv[i+1]; + settings::path_sourcepoint = argv[i+1]; i += 1; } else { // Source is in statepoint file - openmc_path_sourcepoint = openmc_path_statepoint; + settings::path_sourcepoint = settings::path_statepoint; } } else { // Source is assumed to be in statepoint file - openmc_path_sourcepoint = openmc_path_statepoint; + settings::path_sourcepoint = settings::path_statepoint; } } else if (arg == "-g" || arg == "--geometry-debug") { - openmc_check_overlaps = true; + settings::check_overlaps = true; } else if (arg == "-c" || arg == "--volume") { openmc_run_mode = RUN_MODE_VOLUME; } else if (arg == "-s" || arg == "--threads") { @@ -200,7 +200,7 @@ parse_command_line(int argc, char* argv[]) return OPENMC_E_UNASSIGNED; } else if (arg == "-t" || arg == "--track") { - openmc_write_all_tracks = true; + settings::write_all_tracks = true; } else { std::cerr << "Unknown option: " << argv[i] << '\n'; @@ -213,7 +213,7 @@ parse_command_line(int argc, char* argv[]) } // Determine directory where XML input files are - if (argc > 1 && last_flag < argc) openmc_path_input = argv[last_flag + 1]; + if (argc > 1 && last_flag < argc) settings::path_input = argv[last_flag + 1]; return 0; } diff --git a/src/particle.cpp b/src/particle.cpp index 51331cea0..3dda0e7c9 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -148,7 +148,8 @@ Particle::write_restart() // Set up file name std::stringstream filename; - filename << path_output << "particle_" << openmc_current_batch << '_' << id << ".h5"; + filename << settings::path_output << "particle_" << openmc_current_batch + << '_' << id << ".h5"; #pragma omp critical (WriteParticleRestart) { diff --git a/src/settings.F90 b/src/settings.F90 index 710a87e1e..da514757d 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -9,7 +9,7 @@ module settings ! ============================================================================ ! ENERGY TREATMENT RELATED VARIABLES - logical(C_BOOL), bind(C, name='openmc_run_CE') :: run_CE = .true. ! Run in CE mode? + logical(C_BOOL), bind(C, name='run_CE') :: run_CE = .true. ! Run in CE mode? ! ============================================================================ ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES @@ -26,7 +26,7 @@ module settings integer :: n_log_bins ! number of bins for logarithmic grid - logical(C_BOOL), bind(C, name='openmc_photon_transport') :: photon_transport = .false. + logical(C_BOOL), bind(C) :: photon_transport = .false. integer :: electron_treatment = ELECTRON_TTB ! ============================================================================ @@ -81,13 +81,13 @@ module settings integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE ! Restart run - logical(C_BOOL), bind(C, name='openmc_restart_run') :: restart_run = .false. + logical(C_BOOL), bind(C) :: restart_run = .false. ! The verbosity controls how much information will be printed to the screen ! and in logs integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7 - logical(C_BOOL), bind(C, name='openmc_check_overlaps') :: check_overlaps = .false. + logical(C_BOOL), bind(C) :: check_overlaps = .false. ! Trace for single particle integer :: trace_batch @@ -95,17 +95,14 @@ module settings integer(8) :: trace_particle ! Particle tracks - logical(C_BOOL), bind(C, name='openmc_write_all_tracks') :: & - write_all_tracks = .false. + logical(C_BOOL), bind(C) :: write_all_tracks = .false. integer, allocatable :: track_identifiers(:,:) ! Particle restart run - logical(C_BOOL), bind(C, name='openmc_particle_restart_run') :: & - particle_restart_run = .false. + logical(C_BOOL), bind(C) :: particle_restart_run = .false. ! Write out initial source - logical(C_BOOL), bind(C, name='openmc_write_initial_source') :: & - write_initial_source = .false. + logical(C_BOOL), bind(C) :: write_initial_source = .false. ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE logical :: create_fission_neutrons = .true. diff --git a/src/settings.cpp b/src/settings.cpp index aafa0fb23..d3896f063 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -16,10 +16,12 @@ namespace openmc { // Global variables //============================================================================== -char* openmc_path_input; -char* openmc_path_statepoint; -char* openmc_path_sourcepoint; -char* openmc_path_particle_restart; +namespace settings { + +char* path_input; +char* path_statepoint; +char* path_sourcepoint; +char* path_particle_restart; std::string path_cross_sections; std::string path_multipole; std::string path_output; @@ -31,12 +33,16 @@ double temperature_tolerance {10.0}; double temperature_default {293.6}; std::array temperature_range {0.0, 0.0}; +} // namespace settings + //============================================================================== // Functions //============================================================================== void read_settings(pugi::xml_node* root) { + using namespace settings; + // Look for deprecated cross_sections.xml file in settings.xml if (check_for_node(*root, "cross_sections")) { warning("Setting cross_sections in settings.xml has been deprecated." diff --git a/src/source.cpp b/src/source.cpp index 70240b10d..8f28fcf73 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -45,7 +45,7 @@ SourceDistribution::SourceDistribution(pugi::xml_node node) particle_ = ParticleType::neutron; } else if (temp_str == "photon") { particle_ = ParticleType::photon; - openmc_photon_transport = true; + settings::photon_transport = true; } else { fatal_error(std::string("Unknown source particle type: ") + temp_str); } @@ -59,12 +59,12 @@ SourceDistribution::SourceDistribution(pugi::xml_node node) // Check for external source file if (check_for_node(node, "file")) { // Copy path of source file - path_source = get_node_value(node, "file", false, true); + settings::path_source = get_node_value(node, "file", false, true); // Check if source file exists - if (!file_exists(path_source)) { + if (!file_exists(settings::path_source)) { std::stringstream msg; - msg << "Source file '" << path_source << "' does not exist."; + msg << "Source file '" << settings::path_source << "' does not exist."; fatal_error(msg); } @@ -243,16 +243,16 @@ void initialize_source() int64_t n; openmc_source_bank(&source_bank, &n); - if (path_source != "") { + if (settings::path_source != "") { // Read the source from a binary file instead of sampling from some // assumed source distribution std::stringstream msg; - msg << "Reading source file from " << path_source << "..."; + msg << "Reading source file from " << settings::path_source << "..."; write_message(msg, 6); // Open the binary file - hid_t file_id = file_open(path_source, 'r', true); + hid_t file_id = file_open(settings::path_source, 'r', true); // Read the file type std::string filetype; @@ -282,9 +282,9 @@ void initialize_source() } // Write out initial source - if (openmc_write_initial_source) { + if (settings::write_initial_source) { write_message("Writing out initial source...", 5); - std::string filename = path_output + "initial_source.h5"; + std::string filename = settings::path_output + "initial_source.h5"; hid_t file_id = file_open(filename, 'w', true); write_source_bank(file_id, work_index.data(), source_bank); file_close(file_id); @@ -318,7 +318,7 @@ Bank sample_external_source() Bank site {external_sources[i].sample()}; // If running in MG, convert site % E to group - if (!openmc_run_CE) { + if (!settings::run_CE) { // Get pointer to rev_energy_bins array on Fortran side double* rev_energy_bins = rev_energy_bins_ptr(); @@ -357,7 +357,7 @@ extern "C" int overall_generation(); //! Fill source bank at end of generation for fixed source simulations extern "C" void fill_source_bank_fixedsource() { - if (path_source.empty()) { + if (settings::path_source.empty()) { // Get pointer to source bank Bank* source_bank; int64_t n; diff --git a/src/thermal.cpp b/src/thermal.cpp index b63d2e6d1..229aa35bc 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -153,10 +153,10 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, // Determine temperature for S(a,b) table double kT = sqrtkT*sqrtkT; int i; - if (temperature_method == TEMPERATURE_NEAREST) { + if (settings::temperature_method == TEMPERATURE_NEAREST) { // If using nearest temperature, do linear search on temperature for (i = 0; i < kTs_.size(); ++i) { - if (abs(kTs_[i] - kT) < K_BOLTZMANN*temperature_tolerance) { + if (abs(kTs_[i] - kT) < K_BOLTZMANN*settings::temperature_tolerance) { break; } } From 268b865cd361e290915aee44cf2b1a6915c2c6d4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 09:51:34 -0500 Subject: [PATCH 24/76] Move definitions for several variables from Fortran to C++ --- include/openmc/settings.h | 19 ++++++++++--------- src/settings.F90 | 16 ++++++++-------- src/settings.cpp | 8 ++++++++ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index be56e0b60..ccaaa1508 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -17,16 +17,16 @@ namespace openmc { namespace settings { -// Defined on Fortran side -extern "C" bool check_overlaps; -extern "C" bool particle_restart_run; -extern "C" bool photon_transport; -extern "C" bool restart_run; -extern "C" bool run_CE; -extern "C" bool write_all_tracks; -extern "C" bool write_initial_source; +// Boolean flags +extern "C" bool check_overlaps; //!< check overlaps in geometry? +extern "C" bool particle_restart_run; //!< particle restart run? +extern "C" bool photon_transport; //!< photon transport turned on? +extern "C" bool restart_run; //!< restart run? +extern "C" bool run_CE; //!< run with continuous-energy data? +extern "C" bool write_all_tracks; //!< write track files for every particle? +extern "C" bool write_initial_source; //!< write out initial source file? -// Defined in .cpp +// Paths to various files // TODO: Make strings instead of char* once Fortran is gone extern "C" char* path_input; extern "C" char* path_statepoint; @@ -37,6 +37,7 @@ extern std::string path_multipole; extern std::string path_output; extern std::string path_source; +// Temperature settings extern int temperature_method; extern bool temperature_multipole; extern double temperature_tolerance; diff --git a/src/settings.F90 b/src/settings.F90 index da514757d..2ebb4da57 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -9,13 +9,13 @@ module settings ! ============================================================================ ! ENERGY TREATMENT RELATED VARIABLES - logical(C_BOOL), bind(C, name='run_CE') :: run_CE = .true. ! Run in CE mode? + logical(C_BOOL), bind(C, name='run_CE') :: run_CE ! Run in CE mode? ! ============================================================================ ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES ! Unreoslved resonance probablity tables - logical :: urr_ptables_on = .true. + logical(C_BOOL) :: urr_ptables_on = .true. ! Default temperature and method for choosing temperatures integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST @@ -26,7 +26,7 @@ module settings integer :: n_log_bins ! number of bins for logarithmic grid - logical(C_BOOL), bind(C) :: photon_transport = .false. + logical(C_BOOL), bind(C) :: photon_transport integer :: electron_treatment = ELECTRON_TTB ! ============================================================================ @@ -81,13 +81,13 @@ module settings integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE ! Restart run - logical(C_BOOL), bind(C) :: restart_run = .false. + logical(C_BOOL), bind(C) :: restart_run ! The verbosity controls how much information will be printed to the screen ! and in logs integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7 - logical(C_BOOL), bind(C) :: check_overlaps = .false. + logical(C_BOOL), bind(C) :: check_overlaps ! Trace for single particle integer :: trace_batch @@ -95,14 +95,14 @@ module settings integer(8) :: trace_particle ! Particle tracks - logical(C_BOOL), bind(C) :: write_all_tracks = .false. + logical(C_BOOL), bind(C) :: write_all_tracks integer, allocatable :: track_identifiers(:,:) ! Particle restart run - logical(C_BOOL), bind(C) :: particle_restart_run = .false. + logical(C_BOOL), bind(C) :: particle_restart_run ! Write out initial source - logical(C_BOOL), bind(C) :: write_initial_source = .false. + logical(C_BOOL), bind(C) :: write_initial_source ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE logical :: create_fission_neutrons = .true. diff --git a/src/settings.cpp b/src/settings.cpp index d3896f063..fc517b0c5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -18,6 +18,14 @@ namespace openmc { namespace settings { +bool check_overlaps {false}; +bool particle_restart_run {false}; +bool photon_transport {false}; +bool restart_run {false}; +bool run_CE {true}; +bool write_all_tracks {false}; +bool write_initial_source {false}; + char* path_input; char* path_statepoint; char* path_sourcepoint; From a2345891b9f330a4ee6c61fc40caf94a927e89af Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 10:55:36 -0500 Subject: [PATCH 25/76] Move easy global settings to settings.h/cpp --- include/openmc/settings.h | 55 ++++++++++++++++++++++++-------- src/settings.F90 | 66 +++++++++++++++++++-------------------- src/settings.cpp | 48 ++++++++++++++++++++++------ 3 files changed, 114 insertions(+), 55 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index ccaaa1508..aa4b93656 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -5,6 +5,7 @@ //! \brief Settings for OpenMC #include +#include #include #include "pugixml.hpp" @@ -18,13 +19,32 @@ namespace openmc { namespace settings { // Boolean flags -extern "C" bool check_overlaps; //!< check overlaps in geometry? -extern "C" bool particle_restart_run; //!< particle restart run? -extern "C" bool photon_transport; //!< photon transport turned on? -extern "C" bool restart_run; //!< restart run? -extern "C" bool run_CE; //!< run with continuous-energy data? -extern "C" bool write_all_tracks; //!< write track files for every particle? -extern "C" bool write_initial_source; //!< write out initial source file? +extern "C" bool assume_separate; //!< assume tallies are spatially separate? +extern "C" bool check_overlaps; //!< check overlaps in geometry? +extern "C" bool cmfd_run; //!< use CMFD? +extern "C" bool confidence_intervals; //!< use confidence intervals for results? +extern "C" bool create_fission_neutrons; //!< create fission neutrons (fixed source)? +extern "C" bool entropy_on; //!< calculate Shannon entropy? +extern "C" bool legendre_to_tabular; //!< convert Legendre distributions to tabular? +extern "C" bool output_summary; //!< write summary.h5? +extern "C" bool output_tallies; //!< write tallies.out? +extern "C" bool particle_restart_run; //!< particle restart run? +extern "C" bool photon_transport; //!< photon transport turned on? +extern "C" bool reduce_tallies; //!< reduce tallies at end of batch? +extern "C" bool res_scat_on; //!< use resonance upscattering method? +extern "C" bool restart_run; //!< restart run? +extern "C" bool run_CE; //!< run with continuous-energy data? +extern "C" bool source_latest; //!< write latest source at each batch? +extern "C" bool source_separate; //!< write source to separate file? +extern "C" bool source_write; //!< write source in HDF5 files? +extern "C" bool survival_biasing; //!< use survival biasing? +extern "C" bool temperature_multipole; //!< use multipole data? +extern "C" bool trigger_on; //!< tally triggers enabled? +extern "C" bool trigger_predict; //!< predict batches for triggers? +extern "C" bool ufs_on; //!< uniform fission site method on? +extern "C" bool urr_ptables_on; //!< use unresolved resonance prob. tables? +extern "C" bool write_all_tracks; //!< write track files for every particle? +extern "C" bool write_initial_source; //!< write out initial source file? // Paths to various files // TODO: Make strings instead of char* once Fortran is gone @@ -37,12 +57,21 @@ extern std::string path_multipole; extern std::string path_output; extern std::string path_source; -// Temperature settings -extern int temperature_method; -extern bool temperature_multipole; -extern double temperature_tolerance; -extern double temperature_default; -extern std::array temperature_range; +extern "C" int32_t index_entropy_mesh; //!< Index of entropy mesh in global mesh array +extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh array + +extern "C" int electron_treatment; //!< how to treat secondary electrons +extern "C" double energy_cutoff[4]; //!< Energy cutoff in [eV] for each particle type +extern "C" int legendre_to_tabular_points; //!< number of points to convert Legendres +extern "C" int temperature_method; //!< method for choosing temperatures +extern "C" int res_scat_method; //!< resonance upscattering method +extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering +extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering +extern "C" double temperature_tolerance; //!< Tolerance in [K] on choosing temperatures +extern "C" double temperature_default; //!< Default T in [K] +extern "C" double temperature_range[2]; //!< Min/max T in [K] over which to load xs +extern "C" double weight_cutoff; //!< Weight cutoff for Russian roulette +extern "C" double weight_survive; //!< Survival weight after Russian roulette } // namespace settings diff --git a/src/settings.F90 b/src/settings.F90 index 2ebb4da57..8c862d9b9 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -15,19 +15,19 @@ module settings ! CONTINUOUS-ENERGY CROSS SECTION RELATED VARIABLES ! Unreoslved resonance probablity tables - logical(C_BOOL) :: urr_ptables_on = .true. + logical(C_BOOL), bind(C) :: urr_ptables_on ! Default temperature and method for choosing temperatures - integer(C_INT) :: temperature_method = TEMPERATURE_NEAREST - logical :: temperature_multipole = .false. - real(C_DOUBLE) :: temperature_tolerance = 10.0_8 - real(8) :: temperature_default = 293.6_8 - real(8) :: temperature_range(2) = [ZERO, ZERO] + integer(C_INT), bind(C) :: temperature_method + logical(C_BOOL), bind(C) :: temperature_multipole + real(C_DOUBLE), bind(C) :: temperature_tolerance + real(C_DOUBLE), bind(C) :: temperature_default + real(C_DOUBLE), bind(C) :: temperature_range(2) integer :: n_log_bins ! number of bins for logarithmic grid logical(C_BOOL), bind(C) :: photon_transport - integer :: electron_treatment = ELECTRON_TTB + integer(C_INT), bind(C) :: electron_treatment ! ============================================================================ ! MULTI-GROUP CROSS SECTION RELATED VARIABLES @@ -36,19 +36,19 @@ module settings integer(C_INT) :: max_order ! Whether or not to convert Legendres to tabulars - logical :: legendre_to_tabular = .true. + logical(C_BOOL), bind(C) :: legendre_to_tabular ! Number of points to use in the Legendre to tabular conversion - integer(C_INT) :: legendre_to_tabular_points = C_NONE + integer(C_INT), bind(C) :: legendre_to_tabular_points ! ============================================================================ ! SIMULATION VARIABLES ! Assume all tallies are spatially distinct - logical :: assume_separate = .false. + logical(C_BOOL), bind(C) :: assume_separate ! Use confidence intervals for results instead of standard deviations - logical :: confidence_intervals = .false. + logical(C_BOOL), bind(C) :: confidence_intervals integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation integer(C_INT32_T), bind(C) :: n_batches ! # of batches @@ -57,25 +57,25 @@ module settings integer :: n_max_batches ! max # of batches integer :: n_batch_interval = 1 ! batch interval for triggers - logical :: pred_batches = .false. ! predict batches for triggers - logical :: trigger_on = .false. ! flag for turning triggers on/off + logical(C_BOOL), bind(C, name='trigger_predict') :: pred_batches ! predict batches for triggers + logical(C_BOOL), bind(C) :: trigger_on ! flag for turning triggers on/off - logical :: entropy_on = .false. - integer :: index_entropy_mesh = -1 + logical(C_BOOL), bind(C) :: entropy_on + integer(C_INT32_T), bind(C) :: index_entropy_mesh - logical :: ufs = .false. - integer :: index_ufs_mesh = -1 + logical(C_BOOL), bind(C, name='ufs_on') :: ufs + integer(C_INT32_T), bind(C) :: index_ufs_mesh ! Write source at end of simulation - logical :: source_separate = .false. - logical :: source_write = .true. - logical :: source_latest = .false. + logical(C_BOOL), bind(C) :: source_separate + logical(C_BOOL), bind(C) :: source_write + logical(C_BOOL), bind(C) :: source_latest ! Variance reduction settins - logical :: survival_biasing = .false. - real(8) :: weight_cutoff = 0.25_8 - real(8) :: energy_cutoff(4) = [ZERO, 1000.0_8, ZERO, ZERO] - real(8) :: weight_survive = ONE + logical(C_BOOL), bind(C) :: survival_biasing + real(C_DOUBLE), bind(C) :: weight_cutoff + real(C_DOUBLE), bind(C) :: energy_cutoff(4) + real(C_DOUBLE) :: weight_survive ! Mode to run in (fixed source, eigenvalue, plotting, etc) integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE @@ -105,7 +105,7 @@ module settings logical(C_BOOL), bind(C) :: write_initial_source ! Whether create fission neutrons or not. Only applied for MODE_FIXEDSOURCE - logical :: create_fission_neutrons = .true. + logical(C_BOOL), bind(C) :: create_fission_neutrons ! Information about state points to be written integer :: n_state_points = 0 @@ -124,21 +124,21 @@ module settings character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory ! Various output options - logical :: output_summary = .true. - logical :: output_tallies = .true. + logical(C_BOOL), bind(C) :: output_summary + logical(C_BOOL), bind(C) :: output_tallies ! Resonance scattering settings - logical :: res_scat_on = .false. ! is resonance scattering treated? - integer :: res_scat_method = RES_SCAT_ARES ! resonance scattering method - real(8) :: res_scat_energy_min = 0.01_8 - real(8) :: res_scat_energy_max = 1000.0_8 + logical(C_BOOL), bind(C) :: res_scat_on ! is resonance scattering treated? + integer(C_INT), bind(C) :: res_scat_method ! resonance scattering method + real(C_DOUBLE), bind(C) :: res_scat_energy_min + real(C_DOUBLE), bind(C) :: res_scat_energy_max character(10), allocatable :: res_scat_nuclides(:) ! Is CMFD active - logical :: cmfd_run = .false. + logical(C_BOOL), bind(C) :: cmfd_run ! No reduction at end of batch - logical :: reduce_tallies = .true. + logical(C_BOOL), bind(C) :: reduce_tallies contains diff --git a/src/settings.cpp b/src/settings.cpp index fc517b0c5..8c0027aa0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -18,13 +18,33 @@ namespace openmc { namespace settings { -bool check_overlaps {false}; -bool particle_restart_run {false}; -bool photon_transport {false}; -bool restart_run {false}; -bool run_CE {true}; -bool write_all_tracks {false}; -bool write_initial_source {false}; +// Default values for boolean flags +bool assume_separate {false}; +bool check_overlaps {false}; +bool cmfd_run {false}; +bool confidence_intervals {false}; +bool create_fission_neutrons {true}; +bool entropy_on {false}; +bool legendre_to_tabular {true}; +bool output_summary {true}; +bool output_tallies {true}; +bool particle_restart_run {false}; +bool photon_transport {false}; +bool reduce_tallies {true}; +bool res_scat_on {false}; +bool restart_run {false}; +bool run_CE {true}; +bool source_latest {false}; +bool source_separate {false}; +bool source_write {true}; +bool survival_biasing {false}; +bool temperature_multipole {false}; +bool trigger_on {false}; +bool trigger_predict {false}; +bool ufs_on {false}; +bool urr_ptables_on {true}; +bool write_all_tracks {false}; +bool write_initial_source {false}; char* path_input; char* path_statepoint; @@ -35,11 +55,21 @@ std::string path_multipole; std::string path_output; std::string path_source; +int32_t index_entropy_mesh {-1}; +int32_t index_ufs_mesh {-1}; + +int electron_treatment {ELECTRON_TTB}; +double energy_cutoff[4] {0.0, 1000.0, 0.0, 0.0}; +int legendre_to_tabular_points {C_NONE}; +int res_scat_method {RES_SCAT_ARES}; +double res_scat_energy_min {0.01}; +double res_scat_energy_max {1000.0}; int temperature_method {TEMPERATURE_NEAREST}; -bool temperature_multipole {false}; double temperature_tolerance {10.0}; double temperature_default {293.6}; -std::array temperature_range {0.0, 0.0}; +double temperature_range[2] {0.0, 0.0}; +double weight_cutoff {0.25}; +double weight_survive {1.0}; } // namespace settings From bb69f52311f49346be35cc29adb267ad23298ca4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 11:04:17 -0500 Subject: [PATCH 26/76] Move run_mode and verbosity out of C API --- include/openmc/capi.h | 2 -- include/openmc/settings.h | 2 ++ openmc/capi/settings.py | 6 +++--- src/initialize.cpp | 4 ++-- src/main.cpp | 3 ++- src/particle.cpp | 4 ++-- src/settings.F90 | 4 ++-- src/settings.cpp | 4 +++- 8 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index bc4371592..500f38da5 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -152,9 +152,7 @@ extern "C" { extern int32_t n_surfaces; extern int32_t n_tallies; extern int32_t n_universes; - extern int openmc_run_mode; extern bool openmc_simulation_initialized; - extern int openmc_verbosity; // Variables that are shared by necessity (can be removed from public header // later) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index aa4b93656..640fac7d6 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -67,9 +67,11 @@ extern "C" int temperature_method; //!< method for choosing temperatures extern "C" int res_scat_method; //!< resonance upscattering method extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering +extern "C" int run_mode; //!< Run mode (eigenvalue, fixed src, etc.) extern "C" double temperature_tolerance; //!< Tolerance in [K] on choosing temperatures extern "C" double temperature_default; //!< Default T in [K] extern "C" double temperature_range[2]; //!< Min/max T in [K] over which to load xs +extern "C" int verbosity; //!< How verbose to make output extern "C" double weight_cutoff; //!< Weight cutoff for Russian roulette extern "C" double weight_survive; //!< Survival weight after Russian roulette diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py index d706112c4..1063d6463 100644 --- a/openmc/capi/settings.py +++ b/openmc/capi/settings.py @@ -20,11 +20,11 @@ class _Settings(object): generations_per_batch = _DLLGlobal(c_int32, 'gen_per_batch') inactive = _DLLGlobal(c_int32, 'n_inactive') particles = _DLLGlobal(c_int64, 'n_particles') - verbosity = _DLLGlobal(c_int, 'openmc_verbosity') + verbosity = _DLLGlobal(c_int, 'verbosity') @property def run_mode(self): - i = c_int.in_dll(_dll, 'openmc_run_mode').value + i = c_int.in_dll(_dll, 'run_mode').value try: return _RUN_MODES[i] except KeyError: @@ -32,7 +32,7 @@ class _Settings(object): @run_mode.setter def run_mode(self, mode): - current_idx = c_int.in_dll(_dll, 'openmc_run_mode') + current_idx = c_int.in_dll(_dll, 'run_mode') for idx, mode_value in _RUN_MODES.items(): if mode_value == mode: current_idx.value = idx diff --git a/src/initialize.cpp b/src/initialize.cpp index dfbf41834..35f872816 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -108,7 +108,7 @@ parse_command_line(int argc, char* argv[]) std::string arg {argv[i]}; if (arg[0] == '-') { if (arg == "-p" || arg == "--plot") { - openmc_run_mode = RUN_MODE_PLOTTING; + settings::run_mode = RUN_MODE_PLOTTING; settings::check_overlaps = true; } else if (arg == "-n" || arg == "--particles") { @@ -172,7 +172,7 @@ parse_command_line(int argc, char* argv[]) } else if (arg == "-g" || arg == "--geometry-debug") { settings::check_overlaps = true; } else if (arg == "-c" || arg == "--volume") { - openmc_run_mode = RUN_MODE_VOLUME; + settings::run_mode = RUN_MODE_VOLUME; } else if (arg == "-s" || arg == "--threads") { // Read number of threads i += 1; diff --git a/src/main.cpp b/src/main.cpp index 54b78d38d..a6b12123e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #endif #include "openmc/capi.h" #include "openmc/error.h" +#include "openmc/settings.h" int main(int argc, char* argv[]) { @@ -23,7 +24,7 @@ int main(int argc, char* argv[]) { } // start problem based on mode - switch (openmc_run_mode) { + switch (openmc::settings::run_mode) { case RUN_MODE_FIXEDSOURCE: case RUN_MODE_EIGENVALUE: err = openmc_run(); diff --git a/src/particle.cpp b/src/particle.cpp index 3dda0e7c9..6c5d24113 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -144,7 +144,7 @@ void Particle::write_restart() { // Dont write another restart file if in particle restart mode - if (openmc_run_mode == RUN_MODE_PARTICLE) return; + if (settings::run_mode == RUN_MODE_PARTICLE) return; // Set up file name std::stringstream filename; @@ -169,7 +169,7 @@ Particle::write_restart() write_dataset(file_id, "generations_per_batch", gen_per_batch); write_dataset(file_id, "current_generation", openmc_current_gen); write_dataset(file_id, "n_particles", n_particles); - switch (openmc_run_mode) { + switch (settings::run_mode) { case RUN_MODE_FIXEDSOURCE: write_dataset(file_id, "run_mode", "fixed source"); break; diff --git a/src/settings.F90 b/src/settings.F90 index 8c862d9b9..a7530b1b5 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -78,14 +78,14 @@ module settings real(C_DOUBLE) :: weight_survive ! Mode to run in (fixed source, eigenvalue, plotting, etc) - integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE + integer(C_INT), bind(C) :: run_mode ! Restart run logical(C_BOOL), bind(C) :: restart_run ! The verbosity controls how much information will be printed to the screen ! and in logs - integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7 + integer(C_INT), bind(C) :: verbosity logical(C_BOOL), bind(C) :: check_overlaps diff --git a/src/settings.cpp b/src/settings.cpp index 8c0027aa0..46932aadb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -64,10 +64,12 @@ int legendre_to_tabular_points {C_NONE}; int res_scat_method {RES_SCAT_ARES}; double res_scat_energy_min {0.01}; double res_scat_energy_max {1000.0}; +int run_mode; int temperature_method {TEMPERATURE_NEAREST}; double temperature_tolerance {10.0}; double temperature_default {293.6}; double temperature_range[2] {0.0, 0.0}; +int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; @@ -92,7 +94,7 @@ void read_settings(pugi::xml_node* root) } // Look for deprecated windowed_multipole file in settings.xml - if (openmc_run_mode != RUN_MODE_PLOTTING) { + if (run_mode != RUN_MODE_PLOTTING) { if (check_for_node(*root, "multipole_library")) { warning("Setting multipole_library in settings.xml has been " "deprecated. The multipole_library is now set in materials.xml and" From 13341ba59bf4f88826225fa8a10255b436e4911e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 12:28:45 -0500 Subject: [PATCH 27/76] Move more definitions of settings variables to C++ --- include/openmc/settings.h | 9 ++++++++- src/settings.F90 | 16 ++++++++-------- src/settings.cpp | 7 +++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 640fac7d6..d7220a042 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -63,14 +63,21 @@ extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh ar extern "C" int electron_treatment; //!< how to treat secondary electrons extern "C" double energy_cutoff[4]; //!< Energy cutoff in [eV] for each particle type extern "C" int legendre_to_tabular_points; //!< number of points to convert Legendres -extern "C" int temperature_method; //!< method for choosing temperatures +extern "C" int max_order; //!< Maximum Legendre order for multigroup data +extern "C" int n_log_bins; //!< number of bins for logarithmic energy grid +extern "C" int n_max_batches; //!< Maximum number of batches extern "C" int res_scat_method; //!< resonance upscattering method extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering extern "C" int run_mode; //!< Run mode (eigenvalue, fixed src, etc.) +extern "C" int temperature_method; //!< method for choosing temperatures extern "C" double temperature_tolerance; //!< Tolerance in [K] on choosing temperatures extern "C" double temperature_default; //!< Default T in [K] extern "C" double temperature_range[2]; //!< Min/max T in [K] over which to load xs +extern "C" int trace_batch; //!< Batch to trace particle on +extern "C" int trace_gen; //!< Generation to trace particle on +extern "C" int64_t trace_particle; //!< Particle ID to enable trace on +extern "C" int trigger_batch_interval; //!< Batch interval for triggers extern "C" int verbosity; //!< How verbose to make output extern "C" double weight_cutoff; //!< Weight cutoff for Russian roulette extern "C" double weight_survive; //!< Survival weight after Russian roulette diff --git a/src/settings.F90 b/src/settings.F90 index a7530b1b5..e6c50e8d7 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -24,7 +24,7 @@ module settings real(C_DOUBLE), bind(C) :: temperature_default real(C_DOUBLE), bind(C) :: temperature_range(2) - integer :: n_log_bins ! number of bins for logarithmic grid + integer(C_INT), bind(C) :: n_log_bins ! number of bins for logarithmic grid logical(C_BOOL), bind(C) :: photon_transport integer(C_INT), bind(C) :: electron_treatment @@ -33,7 +33,7 @@ module settings ! MULTI-GROUP CROSS SECTION RELATED VARIABLES ! Maximum Data Order - integer(C_INT) :: max_order + integer(C_INT), bind(C) :: max_order ! Whether or not to convert Legendres to tabulars logical(C_BOOL), bind(C) :: legendre_to_tabular @@ -55,8 +55,8 @@ module settings integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches integer(C_INT32_T), bind(C) :: gen_per_batch = 1 ! # of generations per batch - integer :: n_max_batches ! max # of batches - integer :: n_batch_interval = 1 ! batch interval for triggers + integer(C_INT), bind(C) :: n_max_batches ! max # of batches + integer(C_INT), bind(C, name='trigger_batch_interval') :: n_batch_interval ! batch interval for triggers logical(C_BOOL), bind(C, name='trigger_predict') :: pred_batches ! predict batches for triggers logical(C_BOOL), bind(C) :: trigger_on ! flag for turning triggers on/off @@ -75,7 +75,7 @@ module settings logical(C_BOOL), bind(C) :: survival_biasing real(C_DOUBLE), bind(C) :: weight_cutoff real(C_DOUBLE), bind(C) :: energy_cutoff(4) - real(C_DOUBLE) :: weight_survive + real(C_DOUBLE), bind(C) :: weight_survive ! Mode to run in (fixed source, eigenvalue, plotting, etc) integer(C_INT), bind(C) :: run_mode @@ -90,9 +90,9 @@ module settings logical(C_BOOL), bind(C) :: check_overlaps ! Trace for single particle - integer :: trace_batch - integer :: trace_gen - integer(8) :: trace_particle + integer(C_INT), bind(C) :: trace_batch + integer(C_INT), bind(C) :: trace_gen + integer(C_INT64_T), bind(C) :: trace_particle ! Particle tracks logical(C_BOOL), bind(C) :: write_all_tracks diff --git a/src/settings.cpp b/src/settings.cpp index 46932aadb..3beceabbb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -61,6 +61,9 @@ int32_t index_ufs_mesh {-1}; int electron_treatment {ELECTRON_TTB}; double energy_cutoff[4] {0.0, 1000.0, 0.0, 0.0}; int legendre_to_tabular_points {C_NONE}; +int max_order; +int n_log_bins; +int n_max_batches; int res_scat_method {RES_SCAT_ARES}; double res_scat_energy_min {0.01}; double res_scat_energy_max {1000.0}; @@ -69,6 +72,10 @@ int temperature_method {TEMPERATURE_NEAREST}; double temperature_tolerance {10.0}; double temperature_default {293.6}; double temperature_range[2] {0.0, 0.0}; +int trace_batch; +int trace_gen; +int64_t trace_particle; +int trigger_batch_interval {1}; int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; From d1cc9fd9c65c075097c4aac6d0108ad970e7cd2d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 12:35:21 -0500 Subject: [PATCH 28/76] Move number of batches, generations, particles to settings.h --- include/openmc/capi.h | 11 ----------- include/openmc/constants.h | 7 +++++++ include/openmc/settings.h | 6 ++++++ src/initialize.cpp | 3 ++- src/main.cpp | 11 ++++++----- src/particle.cpp | 6 +++--- src/settings.F90 | 8 ++++---- src/settings.cpp | 5 +++++ src/simulation.cpp | 5 +++-- src/source.cpp | 7 ++++--- src/state_point.cpp | 5 +++-- 11 files changed, 43 insertions(+), 31 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 500f38da5..7fd79fccf 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -135,16 +135,12 @@ extern "C" { extern char openmc_err_msg[256]; extern double openmc_keff; extern double openmc_keff_std; - extern int32_t gen_per_batch; - extern int32_t n_batches; extern int32_t n_cells; extern int32_t n_filters; - extern int32_t n_inactive; extern int32_t n_lattices; extern int32_t n_materials; extern int32_t n_meshes; extern int n_nuclides; - extern int64_t n_particles; extern int32_t n_plots; extern int32_t n_realizations; extern int32_t n_sab_tables; @@ -162,13 +158,6 @@ extern "C" { extern int openmc_rank; extern int64_t openmc_work; - // Run modes - const int RUN_MODE_FIXEDSOURCE = 1; - const int RUN_MODE_EIGENVALUE = 2; - const int RUN_MODE_PLOTTING = 3; - const int RUN_MODE_PARTICLE = 4; - const int RUN_MODE_VOLUME = 5; - #ifdef __cplusplus } #endif diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 12dc21b71..ab31781e2 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -431,6 +431,13 @@ enum class Interpolation { histogram, lin_lin, lin_log, log_lin, log_log }; +// Run modes +constexpr int RUN_MODE_FIXEDSOURCE {1}; +constexpr int RUN_MODE_EIGENVALUE {2}; +constexpr int RUN_MODE_PLOTTING {3}; +constexpr int RUN_MODE_PARTICLE {4}; +constexpr int RUN_MODE_VOLUME {5}; + } // namespace openmc #endif // OPENMC_CONSTANTS_H diff --git a/include/openmc/settings.h b/include/openmc/settings.h index d7220a042..f800e39f1 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -60,12 +60,18 @@ extern std::string path_source; extern "C" int32_t index_entropy_mesh; //!< Index of entropy mesh in global mesh array extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh array +extern "C" int32_t n_batches; //!< number of (inactive+active) batches +extern "C" int32_t n_inactive; //!< number of inactive batches +extern "C" int32_t gen_per_batch; //!< number of generations per batch +extern "C" int64_t n_particles; //!< number of particles per generation + extern "C" int electron_treatment; //!< how to treat secondary electrons extern "C" double energy_cutoff[4]; //!< Energy cutoff in [eV] for each particle type extern "C" int legendre_to_tabular_points; //!< number of points to convert Legendres extern "C" int max_order; //!< Maximum Legendre order for multigroup data extern "C" int n_log_bins; //!< number of bins for logarithmic energy grid extern "C" int n_max_batches; //!< Maximum number of batches + extern "C" int res_scat_method; //!< resonance upscattering method extern "C" double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering extern "C" double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering diff --git a/src/initialize.cpp b/src/initialize.cpp index 35f872816..d2cdc6c5a 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -10,6 +10,7 @@ #endif #include "openmc/capi.h" +#include "openmc/constants.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" #include "openmc/message_passing.h" @@ -113,7 +114,7 @@ parse_command_line(int argc, char* argv[]) } else if (arg == "-n" || arg == "--particles") { i += 1; - n_particles = std::stoll(argv[i]); + settings::n_particles = std::stoll(argv[i]); } else if (arg == "-r" || arg == "--restart") { i += 1; diff --git a/src/main.cpp b/src/main.cpp index a6b12123e..f4e2d3f8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "mpi.h" #endif #include "openmc/capi.h" +#include "openmc/constants.h" #include "openmc/error.h" #include "openmc/settings.h" @@ -25,17 +26,17 @@ int main(int argc, char* argv[]) { // start problem based on mode switch (openmc::settings::run_mode) { - case RUN_MODE_FIXEDSOURCE: - case RUN_MODE_EIGENVALUE: + case openmc::RUN_MODE_FIXEDSOURCE: + case openmc::RUN_MODE_EIGENVALUE: err = openmc_run(); break; - case RUN_MODE_PLOTTING: + case openmc::RUN_MODE_PLOTTING: err = openmc_plot_geometry(); break; - case RUN_MODE_PARTICLE: + case openmc::RUN_MODE_PARTICLE: if (openmc_master) err = openmc_particle_restart(); break; - case RUN_MODE_VOLUME: + case openmc::RUN_MODE_VOLUME: err = openmc_calculate_volumes(); break; } diff --git a/src/particle.cpp b/src/particle.cpp index 6c5d24113..01fea65ff 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -130,7 +130,7 @@ Particle::mark_as_lost(const char* message) openmc_n_lost_particles += 1; // Count the total number of simulated particles (on this processor) - auto n = openmc_current_batch * gen_per_batch * openmc_work; + auto n = openmc_current_batch * settings::gen_per_batch * openmc_work; // Abort the simulation if the maximum number of lost particles has been // reached @@ -166,9 +166,9 @@ Particle::write_restart() // Write data to file write_dataset(file_id, "current_batch", openmc_current_batch); - write_dataset(file_id, "generations_per_batch", gen_per_batch); + write_dataset(file_id, "generations_per_batch", settings::gen_per_batch); write_dataset(file_id, "current_generation", openmc_current_gen); - write_dataset(file_id, "n_particles", n_particles); + write_dataset(file_id, "n_particles", settings::n_particles); switch (settings::run_mode) { case RUN_MODE_FIXEDSOURCE: write_dataset(file_id, "run_mode", "fixed source"); diff --git a/src/settings.F90 b/src/settings.F90 index e6c50e8d7..ec7bbf2c8 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -50,10 +50,10 @@ module settings ! Use confidence intervals for results instead of standard deviations logical(C_BOOL), bind(C) :: confidence_intervals - integer(C_INT64_T), bind(C) :: n_particles = 0 ! # of particles per generation - integer(C_INT32_T), bind(C) :: n_batches ! # of batches - integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches - integer(C_INT32_T), bind(C) :: gen_per_batch = 1 ! # of generations per batch + integer(C_INT64_T), bind(C) :: n_particles ! # of particles per generation + integer(C_INT32_T), bind(C) :: n_batches ! # of batches + integer(C_INT32_T), bind(C) :: n_inactive ! # of inactive batches + integer(C_INT32_T), bind(C) :: gen_per_batch ! # of generations per batch integer(C_INT), bind(C) :: n_max_batches ! max # of batches integer(C_INT), bind(C, name='trigger_batch_interval') :: n_batch_interval ! batch interval for triggers diff --git a/src/settings.cpp b/src/settings.cpp index 3beceabbb..2805a2098 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -58,6 +58,11 @@ std::string path_source; int32_t index_entropy_mesh {-1}; int32_t index_ufs_mesh {-1}; +int32_t n_batches; +int32_t n_inactive; +int32_t gen_per_batch {1}; +int64_t n_particles {0}; + int electron_treatment {ELECTRON_TTB}; double energy_cutoff[4] {0.0, 1000.0, 0.0, 0.0}; int legendre_to_tabular_points {C_NONE}; diff --git a/src/simulation.cpp b/src/simulation.cpp index 3514f4a47..74a3c14fc 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -2,6 +2,7 @@ #include "openmc/capi.h" #include "openmc/message_passing.h" +#include "openmc/settings.h" // OPENMC_RUN encompasses all the main logic where iterations are performed // over the batches, generations, and histories in a fixed source or k-eigenvalue @@ -41,10 +42,10 @@ void openmc_simulation_init_c() void calculate_work() { // Determine minimum amount of particles to simulate on each processor - int64_t min_work = n_particles/mpi::n_procs; + int64_t min_work = settings::n_particles / mpi::n_procs; // Determine number of processors that have one extra particle - int64_t remainder = n_particles % mpi::n_procs; + int64_t remainder = settings::n_particles % mpi::n_procs; int64_t i_bank = 0; work_index.reserve(mpi::n_procs); diff --git a/src/source.cpp b/src/source.cpp index 8f28fcf73..23939d796 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -273,7 +273,8 @@ void initialize_source() // Generation source sites from specified distribution in user input for (int64_t i = 0; i < openmc_work; ++i) { // initialize random number seed - int64_t id = openmc_total_gen*n_particles + work_index[openmc::mpi::rank] + i + 1; + int64_t id = openmc_total_gen*settings::n_particles + + work_index[openmc::mpi::rank] + i + 1; set_particle_seed(id); // sample external source distribution @@ -365,8 +366,8 @@ extern "C" void fill_source_bank_fixedsource() for (int64_t i = 0; i < openmc_work; ++i) { // initialize random number seed - int64_t id = (openmc_total_gen + overall_generation())*n_particles + - work_index[openmc::mpi::rank] + i + 1; + int64_t id = (openmc_total_gen + overall_generation()) * + settings::n_particles + work_index[openmc::mpi::rank] + i + 1; set_particle_seed(id); // sample external source distribution diff --git a/src/state_point.cpp b/src/state_point.cpp index 1e4c8bdfd..dba0fe1b8 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -10,6 +10,7 @@ #include "openmc/capi.h" #include "openmc/error.h" #include "openmc/message_passing.h" +#include "openmc/settings.h" namespace openmc { @@ -39,7 +40,7 @@ write_source_bank(hid_t group_id, int64_t* work_index, Bank* source_bank) #ifdef PHDF5 // Set size of total dataspace for all procs and rank - hsize_t dims[] {static_cast(n_particles)}; + hsize_t dims[] {static_cast(settings::n_particles)}; hid_t dspace = H5Screate_simple(1, dims, nullptr); hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); @@ -69,7 +70,7 @@ write_source_bank(hid_t group_id, int64_t* work_index, Bank* source_bank) if (openmc_master) { // Create dataset big enough to hold all source sites - hsize_t dims[] {static_cast(n_particles)}; + hsize_t dims[] {static_cast(settings::n_particles)}; hid_t dspace = H5Screate_simple(1, dims, nullptr); hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); From 93f36b574d2a319bad1802ef3336d42314cebcff Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 12:58:21 -0500 Subject: [PATCH 29/76] Fix C binding names on paths --- src/initialize.F90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/initialize.F90 b/src/initialize.F90 index d5ce32b31..fac8f918c 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -17,10 +17,10 @@ module initialize implicit none - type(C_PTR), bind(C) :: openmc_path_input - type(C_PTR), bind(C) :: openmc_path_statepoint - type(C_PTR), bind(C) :: openmc_path_sourcepoint - type(C_PTR), bind(C) :: openmc_path_particle_restart + type(C_PTR), bind(C, name='path_input') :: openmc_path_input + type(C_PTR), bind(C, name='path_statepoint') :: openmc_path_statepoint + type(C_PTR), bind(C, name='path_sourcepoint') :: openmc_path_sourcepoint + type(C_PTR), bind(C, name='path_particle_restart') :: openmc_path_particle_restart contains From 3be4e09e8e26cfee0b4b80d993a4132b8a461913 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 24 Aug 2018 17:14:11 -0400 Subject: [PATCH 30/76] Use 0-based indexing for universes --- src/cell.cpp | 3 +-- src/geometry.cpp | 15 ++++++--------- src/geometry_aux.cpp | 3 +-- src/input_xml.F90 | 8 ++++---- src/output.F90 | 2 +- src/tallies/tally_filter_distribcell.F90 | 4 ++-- src/tallies/tally_filter_universe.F90 | 2 +- src/volume_calc.F90 | 2 +- 8 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index e6dbb348d..30df8da55 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -439,8 +439,7 @@ Cell::to_hdf5(hid_t cell_group) const write_string(cell_group, "name", name, false); } - //TODO: Fix the off-by-one indexing. - write_dataset(cell_group, "universe", global_universes[universe-1]->id); + write_dataset(cell_group, "universe", global_universes[universe]->id); // Write the region specification. if (!region.empty()) { diff --git a/src/geometry.cpp b/src/geometry.cpp index e7cbdd804..c7c9a4199 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -25,7 +25,7 @@ check_cell_overlap(Particle* p) { // loop through each coordinate level for (int j = 0; j < n_coord; j++) { - Universe& univ = *global_universes[p->coord[j].universe - 1]; + Universe& univ = *global_universes[p->coord[j].universe]; int n = univ.cells.size(); // loop through each cell on this level @@ -64,8 +64,6 @@ find_cell(Particle* p, int search_surf) { p->coord[p->n_coord-1].universe = openmc_root_universe; i_universe = openmc_root_universe; } - //TODO: off-by-one indexing - --i_universe; // If a surface was indicated, only search cells from the neighbor list of // that surface. @@ -90,8 +88,7 @@ find_cell(Particle* p, int search_surf) { i_cell = search_cells[i]; // Make sure the search cell is in the same universe. - //TODO: off-by-one indexing - if (global_cells[i_cell]->universe - 1 != i_universe) continue; + if (global_cells[i_cell]->universe != i_universe) continue; Position r {p->coord[p->n_coord-1].xyz}; Direction u {p->coord[p->n_coord-1].uvw}; @@ -165,7 +162,7 @@ find_cell(Particle* p, int search_surf) { //! Found a lower universe, update this coord level then search the next. // Set the lower coordinate level universe. - p->coord[p->n_coord].universe = c.fill + 1; + p->coord[p->n_coord].universe = c.fill; // Set the position and direction. for (int i = 0; i < 3; i++) { @@ -234,10 +231,10 @@ find_cell(Particle* p, int search_surf) { // Set the lower coordinate level universe. if (lat.are_valid_indices(i_xyz)) { - p->coord[p->n_coord].universe = lat[i_xyz] + 1; + p->coord[p->n_coord].universe = lat[i_xyz]; } else { if (lat.outer != NO_OUTER_UNIVERSE) { - p->coord[p->n_coord].universe = lat.outer + 1; + p->coord[p->n_coord].universe = lat.outer; } else { std::stringstream err_msg; err_msg << "Particle " << p->id << " is outside lattice " @@ -300,7 +297,7 @@ cross_lattice(Particle* p, int lattice_translation[3]) } else { // Find cell in next lattice element. - p->coord[p->n_coord-1].universe = lat[i_xyz] + 1; + p->coord[p->n_coord-1].universe = lat[i_xyz]; bool found = find_cell(p, 0); if (!found) { diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 6ca3b6d3b..6fd5021fa 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -62,8 +62,7 @@ adjust_indices() 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; + c->universe = search->second; } else { std::stringstream err_msg; err_msg << "Could not find universe " << c->universe diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e938a456b..1a9a234f5 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -170,7 +170,7 @@ contains ! Perform some final operations to set up the geometry call adjust_indices() - call count_cell_instances(root_universe-1) + call count_cell_instances(root_universe) ! After reading input and basic geometry setup is complete, build lists of ! neighboring cells for efficient tracking @@ -185,7 +185,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(root_universe - 1) > MAX_COORD) then + if (maximum_levels(root_universe) > 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.") @@ -1146,7 +1146,7 @@ contains if (.not. cells_in_univ_dict % has(univ_id)) then n_universes = n_universes + 1 n_cells_in_univ = 1 - call universe_dict % set(univ_id, n_universes) + call universe_dict % set(univ_id, n_universes - 1) call univ_ids % push_back(univ_id) else n_cells_in_univ = 1 + cells_in_univ_dict % get(univ_id) @@ -1205,7 +1205,7 @@ contains ! SETUP UNIVERSES ! Allocate universes, universe cell arrays, and assign base universe - root_universe = find_root_universe() + 1 + root_universe = find_root_universe() ! Clear dictionary call cells_in_univ_dict%clear() diff --git a/src/output.F90 b/src/output.F90 index 78614269d..e45968ffc 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -239,7 +239,7 @@ contains ! Print universe for this level if (p % coord(i) % universe /= NONE) then write(ou,*) ' Universe = ' & - // trim(to_str(universe_id(p % coord(i) % universe-1))) + // trim(to_str(universe_id(p % coord(i) % universe))) end if ! Print information on lattice diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index 9ef282126..f59d155ea 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -157,9 +157,9 @@ contains map = cells(i_cell) % distribcell_index() path_len = distribcell_path_len(i_cell-1, map-1, target_offset, & - root_universe-1) + root_universe) allocate(path_c(path_len)) - call distribcell_path(i_cell-1, map-1, target_offset, root_universe-1, & + call distribcell_path(i_cell-1, map-1, target_offset, root_universe, & path_c) do i = 1, min(path_len, MAX_LINE_LEN) if (path_c(i) == C_NULL_CHAR) exit diff --git a/src/tallies/tally_filter_universe.F90 b/src/tallies/tally_filter_universe.F90 index 2bfc38208..39c1449b3 100644 --- a/src/tallies/tally_filter_universe.F90 +++ b/src/tallies/tally_filter_universe.F90 @@ -112,7 +112,7 @@ contains integer, intent(in) :: bin character(MAX_LINE_LEN) :: label - label = "Universe " // to_str(universe_id(this % universes(bin)-1)) + label = "Universe " // to_str(universe_id(this % universes(bin))) end function text_label_universe end module tally_filter_universe diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index 93774f98c..c291f1ff7 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -216,7 +216,7 @@ contains elseif (this % domain_type == FILTER_UNIVERSE) then do level = 1, p % n_coord do i_domain = 1, size(this % domain_id) - if (universe_id(p % coord(level) % universe - 1) == & + if (universe_id(p % coord(level) % universe) == & this % domain_id(i_domain)) then i_material = p % material call check_hit(i_domain, i_material, indices, hits, n_mat) From 92f9c09a816501b1fa623781c206028fccda44a6 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 24 Aug 2018 17:56:49 -0400 Subject: [PATCH 31/76] Use 0-based indexing for cells in LocalCoord --- src/api.F90 | 2 +- src/geometry.cpp | 12 +++++------- src/output.F90 | 4 ++-- src/particle.cpp | 6 +++--- src/plot.F90 | 6 +++--- src/tallies/tally_filter_cell.F90 | 2 +- src/tallies/tally_filter_cellborn.F90 | 2 +- src/tallies/tally_filter_cellfrom.F90 | 2 +- src/tallies/tally_filter_distribcell.F90 | 8 ++++---- src/tracking.F90 | 8 ++++---- src/volume_calc.F90 | 2 +- 11 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/api.F90 b/src/api.F90 index c8bea6583..72acec064 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -206,7 +206,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 + 1) % id() elseif (rtype == 2) then if (p % material == MATERIAL_VOID) then id = 0 diff --git a/src/geometry.cpp b/src/geometry.cpp index c7c9a4199..9aac3f314 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -34,11 +34,10 @@ check_cell_overlap(Particle* p) { Cell& c = *global_cells[index_cell]; if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { - //TODO: off-by-one indexing - if (index_cell != p->coord[j].cell - 1) { + if (index_cell != p->coord[j].cell) { std::stringstream err_msg; err_msg << "Overlapping cells detected: " << c.id << ", " - << global_cells[p->coord[j].cell-1]->id << " on universe " + << global_cells[p->coord[j].cell]->id << " on universe " << univ.id; fatal_error(err_msg); } @@ -94,8 +93,7 @@ find_cell(Particle* p, int search_surf) { Direction u {p->coord[p->n_coord-1].uvw}; int32_t surf = p->surface; if (global_cells[i_cell]->contains(r, u, surf)) { - //TODO: off-by-one indexing - p->coord[p->n_coord-1].cell = i_cell + 1; + p->coord[p->n_coord-1].cell = i_cell; if (openmc_verbosity >= 10 || openmc_trace) { std::stringstream msg; @@ -119,7 +117,7 @@ find_cell(Particle* p, int search_surf) { int distribcell_index = c.distribcell_index - 1; int offset = 0; for (int i = 0; i < p->n_coord; i++) { - Cell& c_i {*global_cells[p->coord[i].cell-1]}; + Cell& c_i {*global_cells[p->coord[i].cell]}; if (c_i.type == FILL_UNIVERSE) { offset += c_i.offset[distribcell_index]; } else if (c_i.type == FILL_LATTICE) { @@ -334,7 +332,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, for (int i = 0; i < p->n_coord; i++) { Position r {p->coord[i].xyz}; Direction u {p->coord[i].uvw}; - Cell& c {*global_cells[p->coord[i].cell-1]}; + Cell& c {*global_cells[p->coord[i].cell]}; // Find the oncoming surface in this cell and the distance to it. auto surface_distance = c.distance(r, u, p->surface); diff --git a/src/output.F90 b/src/output.F90 index e45968ffc..0f23c67bd 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -231,8 +231,8 @@ contains write(ou,*) ' Level ' // trim(to_str(i - 1)) ! Print cell for this level - if (p % coord(i) % cell /= NONE) then - c => cells(p % coord(i) % cell) + if (p % coord(i) % cell /= C_NONE) then + c => cells(p % coord(i) % cell + 1) write(ou,*) ' Cell = ' // trim(to_str(c % id())) end if diff --git a/src/particle.cpp b/src/particle.cpp index e46d06c01..5dbfb2483 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -19,8 +19,8 @@ namespace openmc { void LocalCoord::reset() { - cell = 0; - universe = 0; + cell = C_NONE; + universe = C_NONE; lattice = 0; lattice_x = 0; lattice_y = 0; @@ -67,7 +67,7 @@ Particle::initialize() // clear attributes surface = 0; - cell_born = 0; + cell_born = C_NONE; material = 0; last_material = 0; last_sqrtkT = 0; diff --git a/src/plot.F90 b/src/plot.F90 index 2fd898206..517c27fa1 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -84,7 +84,7 @@ contains else if (pl % color_by == PLOT_COLOR_MATS) then ! Assign color based on material - associate (c => cells(p % coord(j) % cell)) + associate (c => cells(p % coord(j) % cell + 1)) if (c % type() == FILL_UNIVERSE) then ! If we stopped on a middle universe level, treat as if not found rgb = pl % not_found % rgb @@ -100,8 +100,8 @@ contains end associate 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() + rgb = pl % colors(p % coord(j) % cell + 1) % rgb + id = cells(p % coord(j) % cell + 1) % id() else rgb = 0 id = -1 diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 index be3746707..a394ed122 100644 --- a/src/tallies/tally_filter_cell.F90 +++ b/src/tallies/tally_filter_cell.F90 @@ -59,7 +59,7 @@ contains ! Iterate over coordinate levels to see with cells match do i = 1, p % n_coord - val = this % map % get(p % coord(i) % cell) + val = this % map % get(p % coord(i) % cell + 1) if (val /= EMPTY) then call match % bins % push_back(val) call match % weights % push_back(ONE) diff --git a/src/tallies/tally_filter_cellborn.F90 b/src/tallies/tally_filter_cellborn.F90 index a373c2d4e..37bf04202 100644 --- a/src/tallies/tally_filter_cellborn.F90 +++ b/src/tallies/tally_filter_cellborn.F90 @@ -55,7 +55,7 @@ contains integer :: val - val = this % map % get(p % cell_born) + val = this % map % get(p % cell_born + 1) if (val /= EMPTY) then call match % bins % push_back(val) call match % weights % push_back(ONE) diff --git a/src/tallies/tally_filter_cellfrom.F90 b/src/tallies/tally_filter_cellfrom.F90 index 83a3179d2..a99aa6883 100644 --- a/src/tallies/tally_filter_cellfrom.F90 +++ b/src/tallies/tally_filter_cellfrom.F90 @@ -42,7 +42,7 @@ contains ! Starting one coordinate level deeper, find the next bin. do i = 1, p % last_n_coord - val = this % map % get(p % last_cell(i)) + val = this % map % get(p % last_cell(i) + 1) if (val /= EMPTY) then call match % bins % push_back(val) call match % weights % push_back(ONE) diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index f59d155ea..48b223a43 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -57,10 +57,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 - offset = offset + cells(p % coord(i) % cell) & + if (cells(p % coord(i) % cell + 1) % type() == FILL_UNIVERSE) then + offset = offset + cells(p % coord(i) % cell + 1) & % offset(distribcell_index-1) - elseif (cells(p % coord(i) % cell) % type() == FILL_LATTICE) then + elseif (cells(p % coord(i) % cell + 1) % type() == FILL_LATTICE) then if (lattices(p % coord(i + 1) % lattice) % obj & % are_valid_indices([& p % coord(i + 1) % lattice_x, & @@ -73,7 +73,7 @@ contains p % coord(i + 1) % lattice_z]) end if end if - if (this % cell == p % coord(i) % cell) then + if (this % cell == p % coord(i) % cell + 1) then call match % bins % push_back(offset + 1) call match % weights % push_back(ONE) return diff --git a/src/tracking.F90 b/src/tracking.F90 index e9568fe54..d93ac9ab9 100644 --- a/src/tracking.F90 +++ b/src/tracking.F90 @@ -91,7 +91,7 @@ contains ! If the cell hasn't been determined based on the particle's location, ! initiate a search for the current cell. This generally happens at the ! beginning of the history and again for any secondary particles - if (p % coord(p % n_coord) % cell == NONE) then + if (p % coord(p % n_coord) % cell == C_NONE) then call find_cell(p, found_cell) if (.not. found_cell) then call particle_mark_as_lost(p, "Could not find the cell containing" & @@ -100,7 +100,7 @@ contains end if ! set birth cell attribute - if (p % cell_born == NONE) p % cell_born = p % coord(p % n_coord) % cell + if (p % cell_born == C_NONE) p % cell_born = p % coord(p % n_coord) % cell end if ! Write particle track. @@ -183,7 +183,7 @@ contains end do p % last_n_coord = p % n_coord - p % coord(p % n_coord) % cell = NONE + p % coord(p % n_coord) % cell = C_NONE if (any(lattice_translation /= 0)) then ! Particle crosses lattice boundary p % surface = ERROR_INT @@ -251,7 +251,7 @@ contains do j = 1, p % n_coord - 1 if (p % coord(j + 1) % rotated) then ! If next level is rotated, apply rotation matrix - p % coord(j + 1) % uvw = matmul(cells(p % coord(j) % cell) % & + p % coord(j + 1) % uvw = matmul(cells(p % coord(j) % cell + 1) % & rotation_matrix, p % coord(j) % uvw) else ! Otherwise, copy this level's direction diff --git a/src/volume_calc.F90 b/src/volume_calc.F90 index c291f1ff7..f7ded7361 100644 --- a/src/volume_calc.F90 +++ b/src/volume_calc.F90 @@ -205,7 +205,7 @@ 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() & + if (cells(p % coord(level) % cell + 1) % id() & == this % domain_id(i_domain)) then i_material = p % material call check_hit(i_domain, i_material, indices, hits, n_mat) From 243eae1244971bafd8926faac7491afda693b7ef Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 24 Aug 2018 19:06:04 -0400 Subject: [PATCH 32/76] Move all summary.h5 geometry writing to C++ --- CMakeLists.txt | 1 + src/cell.cpp | 51 +++++++++++++--- src/hdf5_interface.cpp | 2 + src/hdf5_interface.h | 2 +- src/summary.F90 | 132 +++-------------------------------------- src/summary.cpp | 36 +++++++++++ 6 files changed, 89 insertions(+), 135 deletions(-) create mode 100644 src/summary.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a449e7484..d69a7c7f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -420,6 +420,7 @@ add_library(libopenmc SHARED src/simulation.cpp src/state_point.cpp src/string_functions.cpp + src/summary.cpp src/surface.cpp src/xml_interface.cpp src/xsdata.cpp) diff --git a/src/cell.cpp b/src/cell.cpp index 30df8da55..c6f7b3ab9 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -433,13 +433,18 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const //============================================================================== void -Cell::to_hdf5(hid_t cell_group) const +Cell::to_hdf5(hid_t cells_group) const { + // Create a group for this cell. + std::stringstream group_name; + group_name << "cell " << id; + auto group = create_group(cells_group, group_name); + if (!name.empty()) { - write_string(cell_group, "name", name, false); + write_string(group, "name", name, false); } - write_dataset(cell_group, "universe", global_universes[universe]->id); + write_dataset(group, "universe", global_universes[universe]->id); // Write the region specification. if (!region.empty()) { @@ -460,20 +465,48 @@ Cell::to_hdf5(hid_t cell_group) const << copysign(global_surfaces[abs(token)-1]->id, token); } } - write_string(cell_group, "region", region_spec.str(), false); + write_string(group, "region", region_spec.str(), false); } - if (type == FILL_UNIVERSE) { - write_dataset(cell_group, "fill_type", "universe"); - write_dataset(cell_group, "fill", global_universes[fill]->id); + // Write fill information. + if (type == FILL_MATERIAL) { + write_dataset(group, "fill_type", "material"); + std::vector mat_ids; + for (auto i_mat : material) { + if (i_mat != MATERIAL_VOID) { + mat_ids.push_back(global_materials[i_mat]->id); + } else { + mat_ids.push_back(MATERIAL_VOID); + } + } + if (mat_ids.size() == 1) { + write_dataset(group, "material", mat_ids[0]); + } else { + write_dataset(group, "material", mat_ids); + } + + std::vector temps; + for (auto sqrtkT_val : sqrtkT) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(group, "temperature", temps); + + } else if (type == FILL_UNIVERSE) { + write_dataset(group, "fill_type", "universe"); + write_dataset(group, "fill", global_universes[fill]->id); if (translation != 0) { - write_dataset(cell_group, "translation", translation); + write_dataset(group, "translation", translation); } if (!rotation.empty()) { std::array rot {rotation[0], rotation[1], rotation[2]}; - write_dataset(cell_group, "rotation", rot); + write_dataset(group, "rotation", rot); } + + } else if (type == FILL_LATTICE) { + write_dataset(group, "fill_type", "lattice"); + write_dataset(group, "lattice", lattices_c[fill]->id); } + + close_group(group); } //============================================================================== diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 5d6926479..643859620 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -899,6 +899,8 @@ using_mpio_device(hid_t obj_id) template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_INT; template<> +const hid_t H5TypeMap::type_id = H5T_NATIVE_ULONG; +template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_INT64; template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_DOUBLE; diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index e749a8e1b..8eccaa016 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -281,7 +281,7 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray& arr, bool indep template inline void write_attribute(hid_t obj_id, const char* name, T buffer) { - write_attr(obj_id, name, 0, nullptr, H5TypeMap::type_id, &buffer); + write_attr(obj_id, 0, nullptr, name, H5TypeMap::type_id, &buffer); } inline void diff --git a/src/summary.F90 b/src/summary.F90 index e7823a6aa..9d3b7bc8f 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -29,6 +29,13 @@ contains subroutine write_summary() + interface + subroutine write_geometry(file_id) bind(C) + import HID_T + integer(HID_T), intent(in), value :: file_id + end subroutine write_geometry + end interface + integer(HID_T) :: file_id ! Display output message @@ -154,131 +161,6 @@ contains end subroutine write_nuclides -!=============================================================================== -! WRITE_GEOMETRY -!=============================================================================== - - subroutine write_geometry(file_id) - integer(HID_T), intent(in) :: file_id - - integer :: i, j, cell_fill - integer, allocatable :: cell_materials(:) - real(8), allocatable :: cell_temperatures(:) - integer(HID_T) :: geom_group - integer(HID_T) :: cells_group, cell_group - integer(HID_T) :: surfaces_group - integer(HID_T) :: universes_group - integer(HID_T) :: lattices_group - type(Cell), pointer :: c - class(Lattice), pointer :: lat - - interface - subroutine universes_to_hdf5(universes_group) bind(C) - import HID_T - integer(HID_T), intent(in), value :: universes_group - end subroutine universes_to_hdf5 - end interface - - ! Use H5LT interface to write number of geometry objects - geom_group = create_group(file_id, "geometry") - 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", size(lattices)) - - ! ========================================================================== - ! WRITE INFORMATION ON CELLS - - ! Create a cell group (nothing directly written in this group) then close - cells_group = create_group(geom_group, "cells") - - ! 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()))) - - call c % to_hdf5(cell_group) - - ! Write information on what fills this cell - select case (c%type()) - case (FILL_MATERIAL) - call write_dataset(cell_group, "fill_type", "material") - - if (c % material_size() == 1) then - if (c % material(1) == MATERIAL_VOID) then - call write_dataset(cell_group, "material", MATERIAL_VOID) - else - call write_dataset(cell_group, "material", & - materials(c % material(1)) % id()) - end if - else - allocate(cell_materials(c % material_size())) - do j = 1, c % material_size() - if (c % material(j) == MATERIAL_VOID) then - cell_materials(j) = MATERIAL_VOID - else - cell_materials(j) = materials(c % material(j)) % id() - end if - end do - call write_dataset(cell_group, "material", cell_materials) - deallocate(cell_materials) - end if - - allocate(cell_temperatures(c % sqrtkT_size())) - do j = 1, c % sqrtkT_size() - cell_temperatures(j) = c % sqrtkT(j-1)**2 / K_BOLTZMANN - end do - call write_dataset(cell_group, "temperature", cell_temperatures) - deallocate(cell_temperatures) - - case (FILL_LATTICE) - call write_dataset(cell_group, "fill_type", "lattice") - ! 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) - end do CELL_LOOP - - call close_group(cells_group) - - ! ========================================================================== - ! WRITE INFORMATION ON SURFACES - - ! Create surfaces group - surfaces_group = create_group(geom_group, "surfaces") - - ! Write information on each surface - SURFACE_LOOP: do i = 1, n_surfaces - call surfaces(i) % to_hdf5(surfaces_group) - end do SURFACE_LOOP - - call close_group(surfaces_group) - - ! ========================================================================== - ! WRITE INFORMATION ON UNIVERSES - - universes_group = create_group(geom_group, "universes") - call universes_to_hdf5(universes_group) - call close_group(universes_group) - - ! ========================================================================== - ! WRITE INFORMATION ON LATTICES - - lattices_group = create_group(geom_group, "lattices") - - do i = 1, size(lattices) - lat => lattices(i)%obj - call lat % to_hdf5(lattices_group) - end do - - call close_group(lattices_group) - call close_group(geom_group) - - end subroutine write_geometry - !=============================================================================== ! WRITE_MATERIALS !=============================================================================== diff --git a/src/summary.cpp b/src/summary.cpp new file mode 100644 index 000000000..a7344e7b4 --- /dev/null +++ b/src/summary.cpp @@ -0,0 +1,36 @@ +#include "cell.h" +#include "hdf5_interface.h" +#include "lattice.h" +#include "surface.h" + + +namespace openmc { + +extern "C" void +write_geometry(hid_t file_id) { + auto geom_group = create_group(file_id, "geometry"); + write_attribute(geom_group, "n_cells", global_cells.size()); + write_attribute(geom_group, "n_surfaces", global_surfaces.size()); + write_attribute(geom_group, "n_universes", global_universes.size()); + write_attribute(geom_group, "n_lattices", lattices_c.size()); + + auto cells_group = create_group(geom_group, "cells"); + for (Cell* c : global_cells) c->to_hdf5(cells_group); + close_group(cells_group); + + auto surfaces_group = create_group(geom_group, "surfaces"); + for (Surface* surf : global_surfaces) surf->to_hdf5(surfaces_group); + close_group(surfaces_group); + + auto universes_group = create_group(geom_group, "universes"); + for (Universe* u : global_universes) u->to_hdf5(universes_group); + close_group(universes_group); + + auto lattices_group = create_group(geom_group, "lattices"); + for (Lattice* lat : lattices_c) lat->to_hdf5(lattices_group); + close_group(lattices_group); + + close_group(geom_group); +} + +} // namespace openmc From fe790e2c726b794a97f8d7b8044e1b5098aa8729 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Fri, 24 Aug 2018 19:48:10 -0400 Subject: [PATCH 33/76] Cleanup --- src/cell.cpp | 2 - src/geometry_header.F90 | 103 +---------------------- src/input_xml.F90 | 12 +-- src/lattice.cpp | 54 ++++-------- src/lattice.h | 43 +++------- src/output.F90 | 2 +- src/surface.cpp | 11 --- src/surface_header.F90 | 32 ------- src/tallies/tally_filter_distribcell.F90 | 5 +- 9 files changed, 35 insertions(+), 229 deletions(-) diff --git a/src/cell.cpp b/src/cell.cpp index c6f7b3ab9..83516eba6 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -748,8 +748,6 @@ extern "C" { 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) { global_cells.reserve(global_cells.size() + n); diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index df59e3410..b58b5415b 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -111,12 +111,6 @@ module geometry_header 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 - type(C_PTR), intent(in), value :: cell_ptr - integer(HID_T), intent(in), value :: group - end subroutine cell_to_hdf5_c - function lattice_pointer(lat_ind) bind(C) result(ptr) import C_PTR, C_INT32_T integer(C_INT32_T), intent(in), value :: lat_ind @@ -137,29 +131,6 @@ module geometry_header logical(C_BOOL) :: is_valid end function lattice_are_valid_indices_c - subroutine lattice_get_indices_c(lat_ptr, xyz, i_xyz) & - bind(C, name='lattice_get_indices') - import C_PTR, C_INT, C_DOUBLE - 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_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 - 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') - import HID_T, C_PTR - 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 @@ -169,14 +140,6 @@ module geometry_header integer(C_INT32_T) :: offset end function lattice_offset_c - function lattice_universe_c(lat_ptr, i_xyz) & - bind(C, name='lattice_universe') result(univ) - import C_PTR, C_INT32_t, C_INT - 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 - subroutine extend_cells_c(n) bind(C) import C_INT32_t integer(C_INT32_T), intent(in), value :: n @@ -187,40 +150,14 @@ module geometry_header ! LATTICE abstract type for ordered array of universes. !=============================================================================== - type, abstract :: Lattice + type :: Lattice type(C_PTR) :: ptr contains procedure :: id => lattice_id procedure :: are_valid_indices => lattice_are_valid_indices - procedure :: get => lattice_get - procedure :: get_indices => lattice_get_indices - procedure :: get_local_xyz => lattice_get_local_xyz procedure :: offset => lattice_offset - procedure :: to_hdf5 => lattice_to_hdf5 end type Lattice -!=============================================================================== -! RECTLATTICE extends LATTICE for rectilinear arrays. -!=============================================================================== - - type, extends(Lattice) :: RectLattice - end type RectLattice - -!=============================================================================== -! HEXLATTICE extends LATTICE for hexagonal (sometimes called triangular) arrays. -!=============================================================================== - - type, extends(Lattice) :: HexLattice - end type HexLattice - -!=============================================================================== -! LATTICECONTAINER pointer array for storing lattices -!=============================================================================== - - type LatticeContainer - class(Lattice), allocatable :: obj - end type LatticeContainer - !=============================================================================== ! CELL defines a closed volume by its bounding surfaces !=============================================================================== @@ -246,7 +183,6 @@ module geometry_header procedure :: sqrtkT_size => cell_sqrtkT_size procedure :: sqrtkT => cell_sqrtkT procedure :: offset => cell_offset - procedure :: to_hdf5 => cell_to_hdf5 end type Cell @@ -257,7 +193,7 @@ module geometry_header integer(C_INT32_T), bind(C) :: n_universes ! # of universes type(Cell), allocatable, target :: cells(:) - type(LatticeContainer), allocatable, target :: lattices(:) + type(Lattice), allocatable, target :: lattices(:) ! Dictionaries which map user IDs to indices in the global arrays type(DictIntInt) :: cell_dict @@ -279,29 +215,6 @@ contains is_valid = lattice_are_valid_indices_c(this % ptr, i_xyz) end function lattice_are_valid_indices - 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) - integer(C_INT) :: i_xyz(3) - 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 - function lattice_offset(this, map, i_xyz) result(offset) class(Lattice), intent(in) :: this integer(C_INT), intent(in) :: map @@ -310,12 +223,6 @@ contains offset = lattice_offset_c(this % ptr, map, i_xyz) end function lattice_offset - 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 cell_id(this) result(id) @@ -393,12 +300,6 @@ contains 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 - 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/input_xml.F90 b/src/input_xml.F90 index 1a9a234f5..cbdc54fec 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1170,11 +1170,8 @@ contains allocate(lattices(n_rlats + n_hlats)) RECT_LATTICES: do i = 1, n_rlats - allocate(RectLattice::lattices(i) % obj) - lat => lattices(i) % obj + lat => lattices(i) lat % ptr = lattice_pointer(i - 1) - select type(lat) - type is (RectLattice) ! Get pointer to i-th lattice node_lat = node_rlat_list(i) @@ -1182,15 +1179,11 @@ contains ! Add lattice to dictionary call lattice_dict % set(lat % id(), i) - end select end do RECT_LATTICES HEX_LATTICES: do i = 1, n_hlats - allocate(HexLattice::lattices(n_rlats + i) % obj) - lat => lattices(n_rlats + i) % obj + lat => lattices(n_rlats + i) lat % ptr = lattice_pointer(n_rlats + i - 1) - select type (lat) - type is (HexLattice) ! Get pointer to i-th lattice node_lat = node_hlat_list(i) @@ -1198,7 +1191,6 @@ contains ! Add lattice to dictionary call lattice_dict % set(lat % id(), n_rlats + i) - end select end do HEX_LATTICES ! ========================================================================== diff --git a/src/lattice.cpp b/src/lattice.cpp index 46f88e351..241c4dedc 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -206,7 +206,7 @@ RectLattice::RectLattice(pugi::xml_node lat_node) //============================================================================== int32_t& -RectLattice::operator[](const int i_xyz[3]) +RectLattice::operator[](std::array i_xyz) { int indx = nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]; return universes[indx]; @@ -225,7 +225,8 @@ RectLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -RectLattice::distance(Position r, Direction u, const int i_xyz[3]) const +RectLattice::distance(Position r, Direction u, const std::array& i_xyz) +const { // Get short aliases to the coordinates. double x = r.x; @@ -299,7 +300,8 @@ RectLattice::get_indices(Position r) const //============================================================================== Position -RectLattice::get_local_position(Position r, const int i_xyz[3]) const +RectLattice::get_local_position(Position r, const std::array i_xyz) +const { r.x -= (lower_left.x + (i_xyz[0] + 0.5)*pitch.x); r.y -= (lower_left.y + (i_xyz[1] + 0.5)*pitch.y); @@ -549,7 +551,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node) //============================================================================== int32_t& -HexLattice::operator[](const int i_xyz[3]) +HexLattice::operator[](std::array i_xyz) { int indx = (2*n_rings-1)*(2*n_rings-1) * i_xyz[2] + (2*n_rings-1) * i_xyz[1] @@ -580,7 +582,8 @@ HexLattice::are_valid_indices(const int i_xyz[3]) const //============================================================================== std::pair> -HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const +HexLattice::distance(Position r, Direction u, const std::array& i_xyz) +const { // Compute the direction on the hexagonal basis. double beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0; @@ -598,10 +601,10 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge Position r_t; if (beta_dir > 0) { - const int i_xyz_t[3] {i_xyz[0]+1, i_xyz[1], i_xyz[2]}; + const std::array i_xyz_t {i_xyz[0]+1, i_xyz[1], i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } else { - const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1], i_xyz[2]}; + const std::array i_xyz_t {i_xyz[0]-1, i_xyz[1], i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } double beta = r_t.x * std::sqrt(3.0) / 2.0 + r_t.y / 2.0; @@ -617,10 +620,10 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const // 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]}; + const std::array i_xyz_t {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } else { - const int i_xyz_t[3] {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]}; + const std::array i_xyz_t {i_xyz[0]-1, i_xyz[1]+1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } double gamma = r_t.x * std::sqrt(3.0) / 2.0 - r_t.y / 2.0; @@ -639,10 +642,10 @@ HexLattice::distance(Position r, Direction u, const int i_xyz[3]) const // Upper and lower sides. edge = -copysign(0.5*pitch[0], u.y); if (u.y > 0) { - const int i_xyz_t[3] {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; + const std::array i_xyz_t {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } else { - const int i_xyz_t[3] {i_xyz[0], i_xyz[1]-1, i_xyz[2]}; + const std::array i_xyz_t {i_xyz[0], i_xyz[1]-1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); } if ((std::abs(r_t.y - edge) > FP_PRECISION) && u.y != 0) { @@ -719,7 +722,7 @@ HexLattice::get_indices(Position r) const 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}; + const std::array i_xyz {out[0] + j, out[1] + i, 0}; Position r_t = get_local_position(r, i_xyz); double d = r_t.x*r_t.x + r_t.y*r_t.y; if (d < d_min) { @@ -747,7 +750,8 @@ HexLattice::get_indices(Position r) const //============================================================================== Position -HexLattice::get_local_position(Position r, const int i_xyz[3]) const +HexLattice::get_local_position(Position r, const std::array i_xyz) +const { // x_l = x_g - (center + pitch_x*cos(30)*index_x) r.x -= (center.x + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]); @@ -893,32 +897,8 @@ extern "C" { bool lattice_are_valid_indices(Lattice *lat, const int i_xyz[3]) {return lat->are_valid_indices(i_xyz);} - void lattice_get_indices(Lattice *lat, const double xyz[3], int i_xyz[3]) - { - Position r {xyz}; - std::array inds = lat->get_indices(r); - i_xyz[0] = inds[0]; - i_xyz[1] = inds[1]; - 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]) - { - Position global {global_xyz}; - Position local = lat->get_local_position(global, i_xyz); - local_xyz[0] = local.x; - local_xyz[1] = local.y; - local_xyz[2] = local.z; - } - int32_t lattice_offset(Lattice *lat, int map, const int i_xyz[3]) {return lat->offset(map, i_xyz);} - - 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 758acfa82..163b86e85 100644 --- a/src/lattice.h +++ b/src/lattice.h @@ -57,14 +57,7 @@ public: virtual ~Lattice() {} - virtual int32_t& operator[](const int i_xyz[3]) = 0; - - int32_t& - operator[](std::array i_xyz) - { - int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; - return operator[](i_xyz_); - } + virtual int32_t& operator[](std::array i_xyz) = 0; virtual LatticeIter begin(); LatticeIter end(); @@ -98,20 +91,13 @@ public: //! \brief Find the next lattice surface crossing //! \param r A 3D Cartesian coordinate. //! \param u A 3D Cartesian direction. - //! \param i_xyz[3] The indices for a lattice tile. + //! \param i_xyz 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(Position r, Direction u, const int i_xyz[3]) const + distance(Position r, Direction u, const std::array& i_xyz) const = 0; - std::pair> - distance(Position r, Direction u, std::array i_xyz) const - { - int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; - return distance(r, u, i_xyz_); - } - //! \brief Find the lattice tile indices for a given point. //! \param r A 3D Cartesian coordinate. //! \return An array containing the indices of a lattice tile. @@ -119,17 +105,10 @@ public: //! \brief Get coordinates local to a lattice tile. //! \param r A 3D Cartesian coordinate. - //! \param i_xyz[3] The indices for a lattice tile. + //! \param i_xyz The indices for a lattice tile. //! \return Local 3D Cartesian coordinates. virtual Position - get_local_position(Position r, const int i_xyz[3]) const = 0; - - Position - get_local_position(Position r, std::array i_xyz) const - { - int i_xyz_[3] {i_xyz[0], i_xyz[1], i_xyz[2]}; - return get_local_position(r, i_xyz_); - } + get_local_position(Position r, const std::array i_xyz) const = 0; //! \brief Check flattened lattice index. //! \param indx The index for a lattice tile. @@ -223,17 +202,17 @@ class RectLattice : public Lattice public: explicit RectLattice(pugi::xml_node lat_node); - int32_t& operator[](const int i_xyz[3]); + int32_t& operator[](std::array i_xyz); bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(Position r, Direction u, const int i_xyz[3]) const; + distance(Position r, Direction u, const std::array& i_xyz) const; std::array get_indices(Position r) const; Position - get_local_position(Position r, const int i_xyz[3]) const; + get_local_position(Position r, const std::array i_xyz) const; int32_t& offset(int map, const int i_xyz[3]); @@ -259,7 +238,7 @@ class HexLattice : public Lattice public: explicit HexLattice(pugi::xml_node lat_node); - int32_t& operator[](const int i_xyz[3]); + int32_t& operator[](std::array i_xyz); LatticeIter begin(); @@ -268,12 +247,12 @@ public: bool are_valid_indices(const int i_xyz[3]) const; std::pair> - distance(Position r, Direction u, const int i_xyz[3]) const; + distance(Position r, Direction u, const std::array& i_xyz) const; std::array get_indices(Position r) const; Position - get_local_position(Position r, const int i_xyz[3]) const; + get_local_position(Position r, const std::array i_xyz) const; bool is_valid_index(int indx) const; diff --git a/src/output.F90 b/src/output.F90 index 0f23c67bd..a4d734154 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -244,7 +244,7 @@ contains ! Print information on lattice if (p % coord(i) % lattice /= NONE) then - l => lattices(p % coord(i) % lattice) % obj + l => lattices(p % coord(i) % lattice) write(ou,*) ' Lattice = ' // trim(to_str(l % id())) write(ou,*) ' Lattice position = (' // trim(to_str(& p % coord(i) % lattice_x)) // ',' // trim(to_str(& diff --git a/src/surface.cpp b/src/surface.cpp index 421c43d48..5ae390035 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1228,17 +1228,6 @@ extern "C" { uvw[2] = u.z; } - void surface_normal(Surface* surf, double xyz[3], double uvw[3]) - { - Position r {xyz}; - Direction u = surf->normal(r); - uvw[0] = u.x; - uvw[1] = u.y; - uvw[2] = u.z; - } - - void surface_to_hdf5(Surface* surf, hid_t group) {surf->to_hdf5(group);} - int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic;} bool diff --git a/src/surface_header.F90 b/src/surface_header.F90 index 401ac90aa..9d7e11461 100644 --- a/src/surface_header.F90 +++ b/src/surface_header.F90 @@ -38,23 +38,6 @@ module surface_header real(C_DOUBLE), intent(inout) :: uvw(3); end subroutine surface_reflect_c - pure subroutine surface_normal_c(surf_ptr, xyz, uvw) & - bind(C, name='surface_normal') - use ISO_C_BINDING - implicit none - type(C_PTR), intent(in), value :: surf_ptr - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(out) :: uvw(3); - end subroutine surface_normal_c - - subroutine surface_to_hdf5_c(surf_ptr, group) & - bind(C, name='surface_to_hdf5') - import C_PTR, HID_T - implicit none - type(C_PTR), intent(in), value :: surf_ptr - integer(HID_T), intent(in), value :: group - end subroutine surface_to_hdf5_c - pure function surface_i_periodic_c(surf_ptr) & bind(C, name="surface_i_periodic") result(i_periodic) use ISO_C_BINDING @@ -91,8 +74,6 @@ module surface_header procedure :: id => surface_id procedure :: bc => surface_bc procedure :: reflect => surface_reflect - procedure :: normal => surface_normal - procedure :: to_hdf5 => surface_to_hdf5 procedure :: i_periodic => surface_i_periodic procedure :: periodic_translate => surface_periodic @@ -126,19 +107,6 @@ contains call surface_reflect_c(this % ptr, xyz, uvw) end subroutine surface_reflect - pure subroutine surface_normal(this, xyz, uvw) - class(Surface), intent(in) :: this - real(C_DOUBLE), intent(in) :: xyz(3); - real(C_DOUBLE), intent(out) :: uvw(3); - call surface_normal_c(this % ptr, xyz, uvw) - end subroutine surface_normal - - subroutine surface_to_hdf5(this, group) - class(Surface), intent(in) :: this - integer(HID_T), intent(in) :: group - call surface_to_hdf5_c(this % ptr, group) - end subroutine surface_to_hdf5 - pure function surface_i_periodic(this) result(i_periodic) class(Surface), intent(in) :: this integer(C_INT) :: i_periodic diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index 48b223a43..ae4e09023 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -61,12 +61,11 @@ contains offset = offset + cells(p % coord(i) % cell + 1) & % offset(distribcell_index-1) elseif (cells(p % coord(i) % cell + 1) % type() == FILL_LATTICE) then - if (lattices(p % coord(i + 1) % lattice) % obj & - % are_valid_indices([& + if (lattices(p % coord(i + 1) % lattice) % 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 = offset + lattices(p % coord(i + 1) % lattice) & % offset(distribcell_index - 1, & [p % coord(i + 1) % lattice_x, & p % coord(i + 1) % lattice_y, & From f20496c9065bb8c0438ba037df2ac06bc7a2afb9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Aug 2018 15:47:47 -0500 Subject: [PATCH 34/76] Convert most of read_settings_xml to C++ --- include/openmc/settings.h | 17 +- src/api.F90 | 4 +- src/initialize.F90 | 47 ++- src/initialize.cpp | 17 +- src/input_xml.F90 | 528 +---------------------------- src/output.F90 | 2 +- src/settings.cpp | 585 ++++++++++++++++++++++++++++++--- src/tallies/trigger_header.F90 | 10 +- 8 files changed, 610 insertions(+), 600 deletions(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index f800e39f1..be8661f4d 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -47,15 +47,14 @@ extern "C" bool write_all_tracks; //!< write track files for every partic extern "C" bool write_initial_source; //!< write out initial source file? // Paths to various files -// TODO: Make strings instead of char* once Fortran is gone -extern "C" char* path_input; -extern "C" char* path_statepoint; -extern "C" char* path_sourcepoint; -extern "C" char* path_particle_restart; -extern std::string path_cross_sections; -extern std::string path_multipole; -extern std::string path_output; +extern std::string path_cross_sections; //!< path to cross_sections.xml +extern std::string path_input; //!< directory where main .xml files resides +extern std::string path_multipole; //!< directory containing multipole files +extern std::string path_output; //!< directory where output files are written +extern std::string path_particle_restart; //!< path to a particle restart file extern std::string path_source; +extern std::string path_sourcepoint; //!< path to a source file +extern std::string path_statepoint; //!< path to a statepoint file extern "C" int32_t index_entropy_mesh; //!< Index of entropy mesh in global mesh array extern "C" int32_t index_ufs_mesh; //!< Index of UFS mesh in global mesh array @@ -95,7 +94,7 @@ extern "C" double weight_survive; //!< Survival weight after Russian roul //! \param[in] root XML node for //============================================================================== -extern "C" void read_settings(pugi::xml_node* root); +extern "C" void read_settings_xml(); } // namespace openmc diff --git a/src/api.F90 b/src/api.F90 index bfa1314c6..33f464fa3 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -133,7 +133,7 @@ contains legendre_to_tabular_points = C_NONE n_batch_interval = 1 n_lost_particles = 0 - n_particles = 0 + n_particles = -1 n_source_points = 0 n_state_points = 0 n_tallies = 0 @@ -150,7 +150,7 @@ contains restart_run = .false. root_universe = -1 run_CE = .true. - run_mode = NONE + run_mode = -1 satisfy_triggers = .false. call openmc_set_seed(DEFAULT_SEED) source_latest = .false. diff --git a/src/initialize.F90 b/src/initialize.F90 index fac8f918c..0dbaa83bf 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -17,10 +17,28 @@ module initialize implicit none - type(C_PTR), bind(C, name='path_input') :: openmc_path_input - type(C_PTR), bind(C, name='path_statepoint') :: openmc_path_statepoint - type(C_PTR), bind(C, name='path_sourcepoint') :: openmc_path_sourcepoint - type(C_PTR), bind(C, name='path_particle_restart') :: openmc_path_particle_restart + interface + function openmc_path_input() result(ptr) bind(C) + import C_PTR + type(C_PTR) :: ptr + end function + function openmc_path_output() result(ptr) bind(C) + import C_PTR + type(C_PTR) :: ptr + end function + function openmc_path_particle_restart() result(ptr) bind(C) + import C_PTR + type(C_PTR) :: ptr + end function + function openmc_path_statepoint() result(ptr) bind(C) + import C_PTR + type(C_PTR) :: ptr + end function + function openmc_path_sourcepoint() result(ptr) bind(C) + import C_PTR + type(C_PTR) :: ptr + end function + end interface contains @@ -164,29 +182,24 @@ contains end function is_null end interface - if (.not. is_null(openmc_path_input)) then - call c_f_pointer(openmc_path_input, string, [255]) + if (.not. is_null(openmc_path_input())) then + call c_f_pointer(openmc_path_input(), string, [255]) path_input = to_f_string(string) else path_input = '' end if - if (.not. is_null(openmc_path_statepoint)) then - call c_f_pointer(openmc_path_statepoint, string, [255]) + if (.not. is_null(openmc_path_statepoint())) then + call c_f_pointer(openmc_path_statepoint(), string, [255]) path_state_point = to_f_string(string) end if - if (.not. is_null(openmc_path_sourcepoint)) then - call c_f_pointer(openmc_path_sourcepoint, string, [255]) + if (.not. is_null(openmc_path_sourcepoint())) then + call c_f_pointer(openmc_path_sourcepoint(), string, [255]) path_source_point = to_f_string(string) end if - if (.not. is_null(openmc_path_particle_restart)) then - call c_f_pointer(openmc_path_particle_restart, string, [255]) + if (.not. is_null(openmc_path_particle_restart())) then + call c_f_pointer(openmc_path_particle_restart(), string, [255]) path_particle_restart = to_f_string(string) end if - - ! Add slash at end of directory if it isn't there - if (len_trim(path_input) > 0 .and. .not. ends_with(path_input, "/")) then - path_input = trim(path_input) // "/" - end if end subroutine read_command_line end module initialize diff --git a/src/initialize.cpp b/src/initialize.cpp index d2cdc6c5a..2c6840151 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -15,6 +15,7 @@ #include "openmc/hdf5_interface.h" #include "openmc/message_passing.h" #include "openmc/settings.h" +#include "openmc/string_utils.h" // data/functions from Fortran side extern "C" void print_usage(); @@ -93,13 +94,6 @@ void initialize_mpi(MPI_Comm intracomm) #endif // OPENMC_MPI -inline bool ends_with(std::string const& value, std::string const& ending) -{ - if (ending.size() > value.size()) return false; - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); -} - - int parse_command_line(int argc, char* argv[]) { @@ -214,7 +208,14 @@ parse_command_line(int argc, char* argv[]) } // Determine directory where XML input files are - if (argc > 1 && last_flag < argc) settings::path_input = argv[last_flag + 1]; + if (argc > 1 && last_flag < argc - 1) { + settings::path_input = std::string(argv[last_flag + 1]); + + // Add slash at end of directory if it isn't there + if (!ends_with(settings::path_input, "/")) { + settings::path_input += "/"; + } + } return 0; } diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 1d7979041..6c1452e12 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -22,7 +22,7 @@ module input_xml use output, only: title, header, print_plot use photon_header use plot_header - use random_lcg, only: prn, openmc_set_seed + use random_lcg, only: prn use surface_header use set_header, only: SetChar use settings @@ -79,10 +79,8 @@ module input_xml type(C_PTR) :: node_ptr end subroutine read_lattices - subroutine read_settings(node_ptr) bind(C) - import C_PTR - type(C_PTR) :: node_ptr - end subroutine read_settings + subroutine read_settings_xml() bind(C) + end subroutine read_settings_xml subroutine read_materials(node_ptr) bind(C) import C_PTR @@ -203,7 +201,8 @@ contains ! for errors and placing properly-formatted data in the right data structures !=============================================================================== - subroutine read_settings_xml() + subroutine read_settings_xml_f(root_ptr) bind(C) + type(C_PTR), value :: root_ptr character(MAX_LINE_LEN) :: temp_str integer :: i @@ -211,303 +210,25 @@ contains integer :: temp_int integer :: temp_int_array3(3) integer(C_INT32_T) :: i_start, i_end - integer(C_INT64_T) :: seed integer(C_INT) :: err integer, allocatable :: temp_int_array(:) integer :: n_tracks - logical :: file_exists - character(MAX_LINE_LEN) :: filename - type(XMLDocument) :: doc type(XMLNode) :: root - type(XMLNode) :: node_mode - type(XMLNode) :: node_cutoff type(XMLNode) :: node_entropy type(XMLNode) :: node_ufs type(XMLNode) :: node_sp - type(XMLNode) :: node_output type(XMLNode) :: node_res_scat - type(XMLNode) :: node_trigger type(XMLNode) :: node_vol - type(XMLNode) :: node_tab_leg type(XMLNode), allocatable :: node_mesh_list(:) type(XMLNode), allocatable :: node_vol_list(:) - ! Check if settings.xml exists - filename = trim(path_input) // "settings.xml" - inquire(FILE=filename, EXIST=file_exists) - if (.not. file_exists) then - if (run_mode /= MODE_PLOTTING) then - call fatal_error("Settings XML file '" // trim(filename) // "' does & - ¬ exist! In order to run OpenMC, you first need a set of input & - &files; at a minimum, this includes settings.xml, geometry.xml, & - &and materials.xml. Please consult the user's guide at & - &http://openmc.readthedocs.io for further information.") - else - ! The settings.xml file is optional if we just want to make a plot. - return - end if - end if + ! Get proper XMLNode type given pointer + root % ptr = root_ptr - ! Parse settings.xml file - call doc % load_file(filename) - root = doc % document_element() - - ! Read settings from C++ side - call read_settings(root % ptr) - - ! Verbosity - if (check_for_node(root, "verbosity")) then - call get_node_value(root, "verbosity", verbosity) - end if - - ! To this point, we haven't displayed any output since we didn't know what - ! the verbosity is. Now that we checked for it, show the title if necessary - if (master) then - if (verbosity >= 2) call title() - end if - call write_message("Reading settings XML file...", 5) - - ! Find if a multi-group or continuous-energy simulation is desired - if (check_for_node(root, "energy_mode")) then - call get_node_value(root, "energy_mode", temp_str) - temp_str = trim(to_lower(temp_str)) - if (temp_str == "mg" .or. temp_str == "multi-group") then - run_CE = .false. - else if (temp_str == "ce" .or. temp_str == "continuous-energy") then - run_CE = .true. - end if - end if - - ! Look for deprecated cross_sections.xml file in settings.xml - if (check_for_node(root, "cross_sections")) then - call warning("Setting cross_sections in settings.xml has been deprecated.& - & The cross_sections are now set in materials.xml and the & - &cross_sections input to materials.xml and the OPENMC_CROSS_SECTIONS& - & environment variable will take precendent over setting & - &cross_sections in settings.xml.") - call get_node_value(root, "cross_sections", path_cross_sections) - end if - - ! Look for deprecated windowed_multipole file in settings.xml - if (run_mode /= MODE_PLOTTING) then - if (check_for_node(root, "multipole_library")) then - call warning("Setting multipole_library in settings.xml has been & - &deprecated. The multipole_library is now set in materials.xml and& - & the multipole_library input to materials.xml and the & - &OPENMC_MULTIPOLE_LIBRARY environment variable will take & - &precendent over setting multipole_library in settings.xml.") - call get_node_value(root, "multipole_library", path_multipole) - end if - if (.not. ends_with(path_multipole, "/")) & - path_multipole = trim(path_multipole) // "/" - end if - - if (.not. run_CE) then - ! Scattering Treatments - if (check_for_node(root, "max_order")) then - call get_node_value(root, "max_order", max_order) - else - ! Set to default of largest int - 1, which means to use whatever is - ! contained in library. - ! This is largest int - 1 because for legendre scattering, a value of - ! 1 is added to the order; adding 1 to huge(0) gets you the largest - ! negative integer, which is not what we want. - max_order = huge(0) - 1 - end if - else - max_order = 0 - end if - - ! Check for a trigger node and get trigger information - if (check_for_node(root, "trigger")) then - node_trigger = root % child("trigger") - - ! Check if trigger(s) are to be turned on - call get_node_value(node_trigger, "active", trigger_on) - - if (trigger_on) then - if (check_for_node(node_trigger, "max_batches") )then - call get_node_value(node_trigger, "max_batches", n_max_batches) - else - call fatal_error("The max_batches must be specified with triggers") - end if - - ! Get the batch interval to check triggers - if (.not. check_for_node(node_trigger, "batch_interval"))then - pred_batches = .true. - else - call get_node_value(node_trigger, "batch_interval", temp_int) - n_batch_interval = temp_int - if (n_batch_interval <= 0) then - call fatal_error("The batch interval must be greater than zero") - end if - end if - end if - end if - - ! Check run mode if it hasn't been set from the command line - if (run_mode == NONE) then - if (check_for_node(root, "run_mode")) then - call get_node_value(root, "run_mode", temp_str) - select case (to_lower(temp_str)) - case ("eigenvalue") - run_mode = MODE_EIGENVALUE - case ("fixed source") - run_mode = MODE_FIXEDSOURCE - case ("plot") - run_mode = MODE_PLOTTING - case ("particle restart") - run_mode = MODE_PARTICLE - case ("volume") - run_mode = MODE_VOLUME - case default - call fatal_error("Unrecognized run mode: " // & - trim(temp_str) // ".") - end select - - ! Assume XML specifics , , etc. directly - node_mode = root - else - call warning(" should be specified.") - - ! Make sure that either eigenvalue or fixed source was specified - node_mode = root % child("eigenvalue") - if (node_mode % associated()) then - if (run_mode == NONE) run_mode = MODE_EIGENVALUE - else - node_mode = root % child("fixed_source") - if (node_mode % associated()) then - if (run_mode == NONE) run_mode = MODE_FIXEDSOURCE - else - call fatal_error(" or not specified.") - end if - end if - end if - end if - - if (run_mode == MODE_EIGENVALUE .or. run_mode == MODE_FIXEDSOURCE) then - ! Read run parameters - call get_run_parameters(node_mode) - - ! Check number of active batches, inactive batches, and particles - if (n_batches <= n_inactive) then - call fatal_error("Number of active batches must be greater than zero.") - elseif (n_inactive < 0) then - call fatal_error("Number of inactive batches must be non-negative.") - elseif (n_particles <= 0) then - call fatal_error("Number of particles must be greater than zero.") - end if - end if - - ! Copy random number seed if specified - if (check_for_node(root, "seed")) then - call get_node_value(root, "seed", seed) - call openmc_set_seed(seed) - end if - - ! Check for electron treatment - if (check_for_node(root, "electron_treatment")) then - call get_node_value(root, "electron_treatment", temp_str) - select case (to_lower(temp_str)) - case ("led") - electron_treatment = ELECTRON_LED - case ("ttb") - electron_treatment = ELECTRON_TTB - case default - call fatal_error("Unrecognized electron treatment: " // & - trim(temp_str) // ".") - end select - end if - - ! Check for photon transport - if (check_for_node(root, "photon_transport")) then - call get_node_value(root, "photon_transport", photon_transport) - - if (.not. run_CE .and. photon_transport) then - call fatal_error("Photon transport is not currently supported & - &in Multi-group mode") - end if - end if - - ! Number of bins for logarithmic grid - if (check_for_node(root, "log_grid_bins")) then - call get_node_value(root, "log_grid_bins", n_log_bins) - if (n_log_bins < 1) then - call fatal_error("Number of bins for logarithmic grid must be & - &greater than zero.") - end if - else - n_log_bins = 8000 - end if - - ! Number of OpenMP threads - if (check_for_node(root, "threads")) then -#ifdef _OPENMP - if (n_threads == NONE) then - call get_node_value(root, "threads", n_threads) - if (n_threads < 1) then - call fatal_error("Invalid number of threads: " // to_str(n_threads)) - end if - call omp_set_num_threads(n_threads) - end if -#else - if (master) call warning("Ignoring number of threads.") -#endif - end if - - ! ========================================================================== - ! EXTERNAL SOURCE - - ! Handled on C++ side - - ! Check if we want to write out source - if (check_for_node(root, "write_initial_source")) then - call get_node_value(root, "write_initial_source", write_initial_source) - end if - - ! Survival biasing - if (check_for_node(root, "survival_biasing")) then - call get_node_value(root, "survival_biasing", survival_biasing) - end if - - ! Probability tables - if (check_for_node(root, "ptables")) then - call get_node_value(root, "ptables", urr_ptables_on) - end if - - ! Cutoffs - if (check_for_node(root, "cutoff")) then - node_cutoff = root % child("cutoff") - if (check_for_node(node_cutoff, "weight")) then - call get_node_value(node_cutoff, "weight", weight_cutoff) - end if - if (check_for_node(node_cutoff, "weight_avg")) then - call get_node_value(node_cutoff, "weight_avg", weight_survive) - end if - if (check_for_node(node_cutoff, "energy_neutron")) then - call get_node_value(node_cutoff, "energy_neutron", energy_cutoff(1)) - elseif (check_for_node(node_cutoff, "energy")) then - call warning("The use of an cutoff is deprecated and should & - &be replaced by .") - call get_node_value(node_cutoff, "energy", energy_cutoff(1)) - end if - if (check_for_node(node_cutoff, "energy_photon")) then - call get_node_value(node_cutoff, "energy_photon", energy_cutoff(2)) - end if - if (check_for_node(node_cutoff, "energy_electron")) then - call get_node_value(node_cutoff, "energy_electron", energy_cutoff(3)) - end if - if (check_for_node(node_cutoff, "energy_positron")) then - call get_node_value(node_cutoff, "energy_positron", energy_cutoff(4)) - end if - end if - - ! Particle trace - if (check_for_node(root, "trace")) then - call get_node_array(root, "trace", temp_int_array3) - trace_batch = temp_int_array3(1) - trace_gen = temp_int_array3(2) - trace_particle = int(temp_int_array3(3), 8) + if (run_mode == MODE_EIGENVALUE) then + ! Preallocate space for keff and entropy by generation + call k_generation % reserve(n_max_batches*gen_per_batch) + call entropy % reserve(n_max_batches*gen_per_batch) end if ! Particle tracks @@ -694,22 +415,9 @@ contains call sourcepoint_batch % add(statepoint_batch % get_item(i)) end do end if - - ! Check if the user has specified to write binary source file - if (check_for_node(node_sp, "separate")) then - call get_node_value(node_sp, "separate", source_separate) - end if - if (check_for_node(node_sp, "write")) then - call get_node_value(node_sp, "write", source_write) - end if - if (check_for_node(node_sp, "overwrite_latest")) then - call get_node_value(node_sp, "overwrite_latest", source_latest) - source_separate = source_latest - end if else ! If no tag was present, by default we keep source bank in ! statepoint file and write it out at statepoints intervals - source_separate = .false. n_source_points = n_state_points do i = 1, n_state_points call sourcepoint_batch % add(statepoint_batch % get_item(i)) @@ -729,91 +437,10 @@ contains end do end if - ! Check if the user has specified to not reduce tallies at the end of every - ! batch - if (check_for_node(root, "no_reduce")) then - call get_node_value(root, "no_reduce", reduce_tallies) - end if - - ! Check if the user has specified to use confidence intervals for - ! uncertainties rather than standard deviations - if (check_for_node(root, "confidence_intervals")) then - call get_node_value(root, "confidence_intervals", confidence_intervals) - end if - - ! Check for output options - if (check_for_node(root, "output")) then - - ! Get pointer to output node - node_output = root % child("output") - - ! Check for summary option - if (check_for_node(node_output, "summary")) then - call get_node_value(node_output, "summary", output_summary) - end if - - ! Check for ASCII tallies output option - if (check_for_node(node_output, "tallies")) then - call get_node_value(node_output, "tallies", output_tallies) - end if - - ! Set output directory if a path has been specified - if (check_for_node(node_output, "path")) then - call get_node_value(node_output, "path", path_output) - if (.not. ends_with(path_output, "/")) & - path_output = trim(path_output) // "/" - end if - end if - - ! Check for cmfd run - if (check_for_node(root, "run_cmfd")) then - call get_node_value(root, "run_cmfd", cmfd_run) - end if - ! Resonance scattering parameters if (check_for_node(root, "resonance_scattering")) then node_res_scat = root % child("resonance_scattering") - ! See if resonance scattering is enabled - if (check_for_node(node_res_scat, "enable")) then - call get_node_value(node_res_scat, "enable", res_scat_on) - else - res_scat_on = .true. - end if - - ! Determine what method is used - if (check_for_node(node_res_scat, "method")) then - call get_node_value(node_res_scat, "method", temp_str) - select case(to_lower(temp_str)) - case ('ares') - res_scat_method = RES_SCAT_ARES - case ('dbrc') - res_scat_method = RES_SCAT_DBRC - case ('wcm') - res_scat_method = RES_SCAT_WCM - case default - call fatal_error("Unrecognized resonance elastic scattering method: " & - // trim(temp_str) // ".") - end select - end if - - ! Minimum energy for resonance scattering - if (check_for_node(node_res_scat, "energy_min")) then - call get_node_value(node_res_scat, "energy_min", res_scat_energy_min) - end if - if (res_scat_energy_min < ZERO) then - call fatal_error("Lower resonance scattering energy bound is negative") - end if - - ! Maximum energy for resonance scattering - if (check_for_node(node_res_scat, "energy_max")) then - call get_node_value(node_res_scat, "energy_max", res_scat_energy_max) - end if - if (res_scat_energy_max < res_scat_energy_min) then - call fatal_error("Upper resonance scattering energy bound is below the & - &lower resonance scattering energy bound.") - end if - ! Get nuclides that resonance scattering should be applied to if (check_for_node(node_res_scat, "nuclides")) then n = node_word_count(node_res_scat, "nuclides") @@ -832,138 +459,7 @@ contains call volume_calcs(i) % from_xml(node_vol) end do - ! Get temperature settings - if (check_for_node(root, "temperature_default")) then - call get_node_value(root, "temperature_default", temperature_default) - end if - if (check_for_node(root, "temperature_method")) then - call get_node_value(root, "temperature_method", temp_str) - select case (to_lower(temp_str)) - case ('nearest') - temperature_method = TEMPERATURE_NEAREST - case ('interpolation') - temperature_method = TEMPERATURE_INTERPOLATION - case default - call fatal_error("Unknown temperature method: " // trim(temp_str)) - end select - end if - if (check_for_node(root, "temperature_tolerance")) then - call get_node_value(root, "temperature_tolerance", temperature_tolerance) - end if - if (check_for_node(root, "temperature_multipole")) then - call get_node_value(root, "temperature_multipole", temperature_multipole) - end if - if (check_for_node(root, "temperature_range")) then - call get_node_array(root, "temperature_range", temperature_range) - end if - - ! Check for tabular_legendre options - if (check_for_node(root, "tabular_legendre")) then - - ! Get pointer to tabular_legendre node - node_tab_leg = root % child("tabular_legendre") - - ! Check for enable option - if (check_for_node(node_tab_leg, "enable")) then - call get_node_value(node_tab_leg, "enable", legendre_to_tabular) - end if - - ! Check for the number of points - if (check_for_node(node_tab_leg, "num_points")) then - call get_node_value(node_tab_leg, "num_points", & - legendre_to_tabular_points) - if (legendre_to_tabular_points <= 1 .and. (.not. run_CE)) then - call fatal_error("The 'num_points' subelement/attribute of the & - &'tabular_legendre' element must contain a value greater than 1") - end if - end if - end if - - ! Check whether create fission sites - if (run_mode == MODE_FIXEDSOURCE) then - if (check_for_node(root, "create_fission_neutrons")) then - call get_node_value(root, "create_fission_neutrons", & - create_fission_neutrons) - end if - end if - - ! Close settings XML file - call doc % clear() - - end subroutine read_settings_xml - -!=============================================================================== -! GET_RUN_PARAMETERS -!=============================================================================== - - subroutine get_run_parameters(node_base) - type(XMLNode), intent(in) :: node_base - - character(MAX_LINE_LEN) :: temp_str - type(XMLNode) :: node_keff_trigger - - ! Check number of particles - if (.not. check_for_node(node_base, "particles")) then - call fatal_error("Need to specify number of particles.") - end if - - ! Get number of particles if it wasn't specified as a command-line argument - if (n_particles == 0) then - call get_node_value(node_base, "particles", n_particles) - end if - - ! Get number of basic batches - call get_node_value(node_base, "batches", n_batches) - if (.not. trigger_on) then - n_max_batches = n_batches - end if - n_inactive = 0 - gen_per_batch = 1 - - ! Get number of inactive batches - if (run_mode == MODE_EIGENVALUE) then - call get_node_value(node_base, "inactive", n_inactive) - if (check_for_node(node_base, "generations_per_batch")) then - call get_node_value(node_base, "generations_per_batch", gen_per_batch) - end if - - ! Preallocate space for keff and entropy by generation - call k_generation % reserve(n_max_batches*gen_per_batch) - call entropy % reserve(n_max_batches*gen_per_batch) - - ! Get the trigger information for keff - if (check_for_node(node_base, "keff_trigger")) then - node_keff_trigger = node_base % child("keff_trigger") - - if (check_for_node(node_keff_trigger, "type")) then - call get_node_value(node_keff_trigger, "type", temp_str) - temp_str = trim(to_lower(temp_str)) - - select case (temp_str) - case ('std_dev') - keff_trigger % trigger_type = STANDARD_DEVIATION - case ('variance') - keff_trigger % trigger_type = VARIANCE - case ('rel_err') - keff_trigger % trigger_type = RELATIVE_ERROR - case default - call fatal_error("Unrecognized keff trigger type " // temp_str) - end select - - else - call fatal_error("Specify keff trigger type in settings XML") - end if - - if (check_for_node(node_keff_trigger, "threshold")) then - call get_node_value(node_keff_trigger, "threshold", & - keff_trigger % threshold) - else - call fatal_error("Specify keff trigger threshold in settings XML") - end if - end if - end if - - end subroutine get_run_parameters + end subroutine read_settings_xml_f !=============================================================================== ! READ_GEOMETRY_XML reads data from a geometry.xml file and parses it, checking diff --git a/src/output.F90 b/src/output.F90 index 49dc380a9..56d1ecfcc 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -41,7 +41,7 @@ contains ! developers, version, and date/time which the problem was run. !=============================================================================== - subroutine title() + subroutine title() bind(C) #ifdef _OPENMP use omp_lib diff --git a/src/settings.cpp b/src/settings.cpp index 2805a2098..860e57626 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,11 +1,19 @@ #include "openmc/settings.h" +#include // for numeric_limits +#include +#include + +#include + #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/distribution.h" #include "openmc/distribution_multi.h" #include "openmc/distribution_spatial.h" #include "openmc/error.h" +#include "openmc/file_utils.h" +#include "openmc/random_lcg.h" #include "openmc/source.h" #include "openmc/string_utils.h" #include "openmc/xml_interface.h" @@ -46,33 +54,33 @@ bool urr_ptables_on {true}; bool write_all_tracks {false}; bool write_initial_source {false}; -char* path_input; -char* path_statepoint; -char* path_sourcepoint; -char* path_particle_restart; std::string path_cross_sections; +std::string path_input; std::string path_multipole; std::string path_output; +std::string path_particle_restart; std::string path_source; +std::string path_sourcepoint; +std::string path_statepoint; int32_t index_entropy_mesh {-1}; int32_t index_ufs_mesh {-1}; int32_t n_batches; -int32_t n_inactive; +int32_t n_inactive {0}; int32_t gen_per_batch {1}; -int64_t n_particles {0}; +int64_t n_particles {-1}; int electron_treatment {ELECTRON_TTB}; double energy_cutoff[4] {0.0, 1000.0, 0.0, 0.0}; int legendre_to_tabular_points {C_NONE}; -int max_order; -int n_log_bins; +int max_order {0}; +int n_log_bins {8000}; int n_max_batches; int res_scat_method {RES_SCAT_ARES}; double res_scat_energy_min {0.01}; double res_scat_energy_max {1000.0}; -int run_mode; +int run_mode {-1}; int temperature_method {TEMPERATURE_NEAREST}; double temperature_tolerance {10.0}; double temperature_default {293.6}; @@ -85,87 +93,316 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; +// TODO: Move to separate file +struct KTrigger { + int type; + double threshold; +}; +extern "C" KTrigger keff_trigger; + } // namespace settings //============================================================================== // Functions //============================================================================== -void read_settings(pugi::xml_node* root) +void get_run_parameters(pugi::xml_node node_base) { using namespace settings; + using namespace pugi; + + // Check number of particles + if (!check_for_node(node_base, "particles")) { + fatal_error("Need to specify number of particles."); + } + + // Get number of particles if it wasn't specified as a command-line argument + if (n_particles == -1) { + n_particles = std::stoll(get_node_value(node_base, "particles")); + } + + // Get number of basic batches + if (check_for_node(node_base, "batches")) { + n_batches = std::stoi(get_node_value(node_base, "batches")); + } + if (!trigger_on) n_max_batches = n_batches; + + // Get number of inactive batches + if (run_mode == RUN_MODE_EIGENVALUE) { + if (check_for_node(node_base, "inactive")) { + n_inactive = std::stoi(get_node_value(node_base, "inactive")); + } + if (check_for_node(node_base, "generations_per_batch")) { + gen_per_batch = std::stoi(get_node_value(node_base, "generations_per_batch")); + } + + // TODO: Preallocate space for keff and entropy by generation + + // TODO: Read keff_trigger information + // Get the trigger information for keff + if (check_for_node(node_base, "keff_trigger")) { + xml_node node_keff_trigger = node_base.child("keff_trigger"); + + if (check_for_node(node_keff_trigger, "type")) { + auto temp = get_node_value(node_keff_trigger, "type", true, true); + if (temp == "std_dev") { + keff_trigger.type = STANDARD_DEVIATION; + } else if (temp == "variance") { + keff_trigger.type = VARIANCE; + } else if ( temp == "rel_err") { + keff_trigger.type = RELATIVE_ERROR; + } else { + fatal_error("Unrecognized keff trigger type " + temp); + } + } else { + fatal_error("Specify keff trigger type in settings XML"); + } + + if (check_for_node(node_keff_trigger, "threshold")) { + keff_trigger.threshold = std::stod(get_node_value( + node_keff_trigger, "threshold")); + } else { + fatal_error("Specify keff trigger threshold in settings XML"); + } + } + } +} + +extern "C" void title(); +extern "C" void read_settings_xml_f(pugi::xml_node_struct* root_ptr); + +extern "C" void +read_settings_xml() +{ + using namespace settings; + using namespace pugi; + + // Check if settings.xml exists + std::string filename = std::string(path_input) + "settings.xml"; + if (!file_exists(filename)) { + if (run_mode != RUN_MODE_PLOTTING) { + std::stringstream msg; + msg << "Settings XML file '" << filename << "' does not exist! In order " + "to run OpenMC, you first need a set of input files; at a minimum, this " + "includes settings.xml, geometry.xml, and materials.xml. Please consult " + "the user's guide at http://openmc.readthedocs.io for further " + "information."; + fatal_error(msg); + } else { + // The settings.xml file is optional if we just want to make a plot. + return; + } + } + + // Parse settings.xml file + xml_document doc; + auto result = doc.load_file("settings.xml"); + if (!result) { + fatal_error("Error processing settings.xml file."); + } + + // Get root element + xml_node root = doc.document_element(); + + // Verbosity + if (check_for_node(root, "verbosity")) { + verbosity = std::stoi(get_node_value(root, "verbosity")); + } + + // To this point, we haven't displayed any output since we didn't know what + // the verbosity is. Now that we checked for it, show the title if necessary + if (openmc_master) { + if (verbosity >= 2) title(); + } + write_message("Reading settings XML file...", 5); + + // Find if a multi-group or continuous-energy simulation is desired + if (check_for_node(root, "energy_mode")) { + std::string temp_str = get_node_value(root, "energy_mode", true, true); + if (temp_str == "mg" || temp_str == "multi-group") { + run_CE = false; + } else if (temp_str == "ce" || temp_str == "continuous-energy") { + run_CE = true; + } + } // Look for deprecated cross_sections.xml file in settings.xml - if (check_for_node(*root, "cross_sections")) { + if (check_for_node(root, "cross_sections")) { warning("Setting cross_sections in settings.xml has been deprecated." " The cross_sections are now set in materials.xml and the " "cross_sections input to materials.xml and the OPENMC_CROSS_SECTIONS" " environment variable will take precendent over setting " "cross_sections in settings.xml."); - path_cross_sections = get_node_value(*root, "cross_sections"); + path_cross_sections = get_node_value(root, "cross_sections"); } // Look for deprecated windowed_multipole file in settings.xml if (run_mode != RUN_MODE_PLOTTING) { - if (check_for_node(*root, "multipole_library")) { + if (check_for_node(root, "multipole_library")) { warning("Setting multipole_library in settings.xml has been " "deprecated. The multipole_library is now set in materials.xml and" " the multipole_library input to materials.xml and the " "OPENMC_MULTIPOLE_LIBRARY environment variable will take " "precendent over setting multipole_library in settings.xml."); - path_multipole = get_node_value(*root, "multipole_library"); + path_multipole = get_node_value(root, "multipole_library"); } if (!ends_with(path_multipole, "/")) { path_multipole += "/"; } } - // Check for output options - if (check_for_node(*root, "output")) { + if (!run_CE) { + // Scattering Treatments + if (check_for_node(root, "max_order")) { + max_order = std::stoi(get_node_value(root, "max_order")); + } else { + // Set to default of largest int - 1, which means to use whatever is + // contained in library. + // This is largest int - 1 because for legendre scattering, a value of + // 1 is added to the order; adding 1 to huge(0) gets you the largest + // negative integer, which is not what we want. + max_order = std::numeric_limits::max() - 1; + } + } - // Get pointer to output node - pugi::xml_node node_output = root->child("output"); + // Check for a trigger node and get trigger information + if (check_for_node(root, "trigger")) { + xml_node node_trigger = root.child("trigger"); - // Set output directory if a path has been specified - if (check_for_node(node_output, "path")) { - path_output = get_node_value(node_output, "path"); - if (!ends_with(path_output, "/")) { - path_output += "/"; + // Check if trigger(s) are to be turned on + trigger_on = get_node_value_bool(node_trigger, "active"); + + if (trigger_on) { + if (check_for_node(node_trigger, "max_batches") ){ + n_max_batches = std::stoi(get_node_value(node_trigger, "max_batches")); + } else { + fatal_error(" must be specified with triggers"); + } + + // Get the batch interval to check triggers + if (!check_for_node(node_trigger, "batch_interval")){ + trigger_predict = true; + } else { + trigger_batch_interval = std::stoi(get_node_value(node_trigger, "batch_interval")); + if (trigger_batch_interval <= 0) { + fatal_error("Trigger batch interval must be greater than zero"); + } } } } - // Get temperature settings - if (check_for_node(*root, "temperature_default")) { - temperature_default = std::stod(get_node_value(*root, "temperature_default")); - } - if (check_for_node(*root, "temperature_method")) { - auto temp_str = get_node_value(*root, "temperature_method", true, true); - if (temp_str == "nearest") { - temperature_method = TEMPERATURE_NEAREST; - } else if (temp_str == "interpolation") { - temperature_method = TEMPERATURE_INTERPOLATION; + // Check run mode if it hasn't been set from the command line + xml_node node_mode; + if (run_mode == -1) { + if (check_for_node(root, "run_mode")) { + std::string temp_str = get_node_value(root, "run_mode", true, true); + if (temp_str == "eigenvalue") { + run_mode = RUN_MODE_EIGENVALUE; + } else if (temp_str == "fixed source") { + run_mode = RUN_MODE_FIXEDSOURCE; + } else if (temp_str == "plot") { + run_mode = RUN_MODE_PLOTTING; + } else if (temp_str == "particle restart") { + run_mode = RUN_MODE_PARTICLE; + } else if (temp_str == "volume") { + run_mode = RUN_MODE_VOLUME; + } else { + fatal_error("Unrecognized run mode: " + temp_str); + } + + // Assume XML specifies , , etc. directly + node_mode = root; } else { - fatal_error("Unknown temperature method: " + temp_str); + warning(" should be specified."); + + // Make sure that either eigenvalue or fixed source was specified + node_mode = root.child("eigenvalue"); + if (node_mode) { + if (run_mode == -1) run_mode = RUN_MODE_EIGENVALUE; + } else { + node_mode = root.child("fixed_source"); + if (node_mode) { + if (run_mode == -1) run_mode = RUN_MODE_FIXEDSOURCE; + } else { + fatal_error(" or not specified."); + } + } } } - if (check_for_node(*root, "temperature_tolerance")) { - temperature_tolerance = std::stod(get_node_value(*root, "temperature_tolerance")); + + if (run_mode == RUN_MODE_EIGENVALUE || run_mode == RUN_MODE_FIXEDSOURCE) { + // Read run parameters + get_run_parameters(node_mode); + + // Check number of active batches, inactive batches, and particles + if (n_batches <= n_inactive) { + fatal_error("Number of active batches must be greater than zero."); + } else if (n_inactive < 0) { + fatal_error("Number of inactive batches must be non-negative."); + } else if (n_particles <= 0) { + fatal_error("Number of particles must be greater than zero."); + } } - if (check_for_node(*root, "temperature_multipole")) { - temperature_multipole = get_node_value_bool(*root, "temperature_multipole"); + + // Copy random number seed if specified + if (check_for_node(root, "seed")) { + auto seed = std::stoll(get_node_value(root, "seed")); + openmc_set_seed(seed); } - if (check_for_node(*root, "temperature_range")) { - auto range = get_node_array(*root, "temperature_range"); - temperature_range[0] = range[0]; - temperature_range[1] = range[1]; + + // Check for electron treatment + if (check_for_node(root, "electron_treatment")) { + auto temp_str = get_node_value(root, "electron_treatment", true, true); + if (temp_str == "led") { + electron_treatment = ELECTRON_LED; + } else if (temp_str == "ttb") { + electron_treatment = ELECTRON_TTB; + } else { + fatal_error("Unrecognized electron treatment: " + temp_str + "."); + } + } + + // Check for photon transport + if (check_for_node(root, "photon_transport")) { + photon_transport = get_node_value_bool(root, "photon_transport"); + + if (!run_CE && photon_transport) { + fatal_error("Photon transport is not currently supported in " + "multigroup mode"); + } + } + + // Number of bins for logarithmic grid + if (check_for_node(root, "log_grid_bins")) { + n_log_bins = std::stoi(get_node_value(root, "log_grid_bins")); + if (n_log_bins < 1) { + fatal_error("Number of bins for logarithmic grid must be greater " + "than zero."); + } + } + + // Number of OpenMP threads + if (check_for_node(root, "threads")) { +#ifdef _OPENMP + if (openmc_n_threads == 0) { + openmc_n_threads = std::stoi(get_node_value(root, "threads")); + if (openmc_n_threads < 1) { + std::stringstream msg; + msg << "Invalid number of threads: " << openmc_n_threads; + fatal_error(msg); + } + omp_set_num_threads(openmc_n_threads); + } +#else + if (openmc_master) warning("Ignoring number of threads."); +#endif } // ========================================================================== // EXTERNAL SOURCE // Get point to list of elements and make sure there is at least one - for (pugi::xml_node node : root->children("source")) { + for (pugi::xml_node node : root.children("source")) { external_sources.emplace_back(node); } @@ -178,6 +415,268 @@ void read_settings(pugi::xml_node* root) }; external_sources.push_back(std::move(source)); } + + // Check if we want to write out source + if (check_for_node(root, "write_initial_source")) { + write_initial_source = get_node_value_bool(root, "write_initial_source"); + } + + // Survival biasing + if (check_for_node(root, "survival_biasing")) { + survival_biasing = get_node_value_bool(root, "survival_biasing"); + } + + // Probability tables + if (check_for_node(root, "ptables")) { + urr_ptables_on = get_node_value_bool(root, "ptables"); + } + + // Cutoffs + if (check_for_node(root, "cutoff")) { + xml_node node_cutoff = root.child("cutoff"); + if (check_for_node(node_cutoff, "weight")) { + weight_cutoff = std::stod(get_node_value(node_cutoff, "weight")); + } + if (check_for_node(node_cutoff, "weight_avg")) { + weight_survive = std::stod(get_node_value(node_cutoff, "weight_avg")); + } + if (check_for_node(node_cutoff, "energy_neutron")) { + energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy_neutron")); + } else if (check_for_node(node_cutoff, "energy")) { + warning("The use of an cutoff is deprecated and should " + "be replaced by ."); + energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy")); + } + if (check_for_node(node_cutoff, "energy_photon")) { + energy_cutoff[1] = std::stod(get_node_value(node_cutoff, "energy_photon")); + } + if (check_for_node(node_cutoff, "energy_electron")) { + energy_cutoff[2] = std::stof(get_node_value(node_cutoff, "energy_electron")); + } + if (check_for_node(node_cutoff, "energy_positron")) { + energy_cutoff[3] = std::stod(get_node_value(node_cutoff, "energy_positron")); + } + } + + // Particle trace + if (check_for_node(root, "trace")) { + auto temp = get_node_array(root, "trace"); + trace_batch = temp.at(0); + trace_gen = temp.at(1); + trace_particle = temp.at(2); + } + + // Particle tracks + if (check_for_node(root, "track")) { + // Get values and make sure there are three per particle + auto temp = get_node_array(root, "track"); + if (temp.size() % 3 != 0) { + fatal_error("Number of integers specified in 'track' is not " + "divisible by 3. Please provide 3 integers per particle to be " + "tracked."); + } + + // Reshape into track_identifiers + //allocate(track_identifiers(3, n_tracks/3)) + //track_identifiers = reshape(temp_int_array, [3, n_tracks/3]) + } + + // TODO: Read meshes + + // TODO: Read + + + // Check if the user has specified to write source points + if (check_for_node(root, "source_point")) { + // Get source_point node + xml_node node_sp = root.child("source_point"); + + // TODO: Read source point batches + + // Check if the user has specified to write binary source file + if (check_for_node(node_sp, "separate")) { + source_separate = get_node_value_bool(node_sp, "separate"); + } + if (check_for_node(node_sp, "write")) { + source_write = get_node_value_bool(node_sp, "write"); + } + if (check_for_node(node_sp, "overwrite_latest")) { + source_latest = get_node_value_bool(node_sp, "overwrite_latest"); + source_separate = source_latest; + } + } else { + // If no tag was present, by default we keep source bank in + // statepoint file and write it out at statepoints intervals + source_separate = false; + // TODO: add defaults + } + + // TODO: Check source points are subset + + // Check if the user has specified to not reduce tallies at the end of every + // batch + if (check_for_node(root, "no_reduce")) { + reduce_tallies = get_node_value_bool(root, "no_reduce"); + } + + // Check if the user has specified to use confidence intervals for + // uncertainties rather than standard deviations + if (check_for_node(root, "confidence_intervals")) { + confidence_intervals = get_node_value_bool(root, "confidence_intervals"); + } + + // Check for output options + if (check_for_node(root, "output")) { + // Get pointer to output node + pugi::xml_node node_output = root.child("output"); + + // Check for summary option + if (check_for_node(node_output, "summary")) { + output_summary = get_node_value_bool(node_output, "summary"); + } + + // Check for ASCII tallies output option + if (check_for_node(node_output, "tallies")) { + output_tallies = get_node_value_bool(node_output, "tallies"); + } + + // Set output directory if a path has been specified + if (check_for_node(node_output, "path")) { + path_output = get_node_value(node_output, "path"); + if (!ends_with(path_output, "/")) { + path_output += "/"; + } + } + } + + // Check for cmfd run + if (check_for_node(root, "run_cmfd")) { + cmfd_run = get_node_value_bool(root, "run_cmfd"); + } + + // Resonance scattering parameters + if (check_for_node(root, "resonance_scattering")) { + xml_node node_res_scat = root.child("resonance_scattering"); + + // See if resonance scattering is enabled + if (check_for_node(node_res_scat, "enable")) { + res_scat_on = get_node_value_bool(node_res_scat, "enable"); + } else { + res_scat_on = true; + } + + // Determine what method is used + if (check_for_node(node_res_scat, "method")) { + auto temp = get_node_value(node_res_scat, "method", true, true); + if (temp == "ares") { + res_scat_method = RES_SCAT_ARES; + } else if (temp == "dbrc") { + res_scat_method = RES_SCAT_DBRC; + } else if (temp == "wcm") { + res_scat_method = RES_SCAT_WCM; + } else { + fatal_error("Unrecognized resonance elastic scattering method: " + + temp + "."); + } + } + + // Minimum energy for resonance scattering + if (check_for_node(node_res_scat, "energy_min")) { + res_scat_energy_min = std::stod(get_node_value(node_res_scat, "energy_min")); + } + if (res_scat_energy_min < 0.0) { + fatal_error("Lower resonance scattering energy bound is negative"); + } + + // Maximum energy for resonance scattering + if (check_for_node(node_res_scat, "energy_max")) { + res_scat_energy_max = std::stod(get_node_value(node_res_scat, "energy_max")); + } + if (res_scat_energy_max < res_scat_energy_min) { + fatal_error("Upper resonance scattering energy bound is below the" + "lower resonance scattering energy bound."); + } + + // TODO: Get resonance scattering nuclides + } + + // TODO: Get volume calculations + + // Get temperature settings + if (check_for_node(root, "temperature_default")) { + temperature_default = std::stod(get_node_value(root, "temperature_default")); + } + if (check_for_node(root, "temperature_method")) { + auto temp = get_node_value(root, "temperature_method", true, true); + if (temp == "nearest") { + temperature_method = TEMPERATURE_NEAREST; + } else if (temp == "interpolation") { + temperature_method = TEMPERATURE_INTERPOLATION; + } else { + fatal_error("Unknown temperature method: " + temp); + } + } + if (check_for_node(root, "temperature_tolerance")) { + temperature_tolerance = std::stod(get_node_value(root, "temperature_tolerance")); + } + if (check_for_node(root, "temperature_multipole")) { + temperature_multipole = get_node_value_bool(root, "temperature_multipole"); + } + if (check_for_node(root, "temperature_range")) { + auto range = get_node_array(root, "temperature_range"); + temperature_range[0] = range.at(0); + temperature_range[1] = range.at(1); + } + + // Check for tabular_legendre options + if (check_for_node(root, "tabular_legendre")) { + // Get pointer to tabular_legendre node + xml_node node_tab_leg = root.child("tabular_legendre"); + + // Check for enable option + if (check_for_node(node_tab_leg, "enable")) { + legendre_to_tabular = get_node_value_bool(node_tab_leg, "enable"); + } + + // Check for the number of points + if (check_for_node(node_tab_leg, "num_points")) { + legendre_to_tabular_points = std::stoi(get_node_value( + node_tab_leg, "num_points")); + if (legendre_to_tabular_points <= 1 && !run_CE) { + fatal_error("The 'num_points' subelement/attribute of the " + " element must contain a value greater than 1"); + } + } + } + + // Check whether create fission sites + if (run_mode == RUN_MODE_FIXEDSOURCE) { + if (check_for_node(root, "create_fission_neutrons")) { + create_fission_neutrons = get_node_value_bool(root, "create_fission_neutrons"); + } + } + + // Read remaining settings from Fortran side + read_settings_xml_f(root.internal_object()); +} + +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" { + const char* openmc_path_input() { + return settings::path_input.c_str(); + } + const char* openmc_path_statepoint() { + return settings::path_statepoint.c_str(); + } + const char* openmc_path_sourcepoint() { + return settings::path_sourcepoint.c_str(); + } + const char* openmc_path_particle_restart() { + return settings::path_particle_restart.c_str(); + } } } // namespace openmc diff --git a/src/tallies/trigger_header.F90 b/src/tallies/trigger_header.F90 index 87507224a..8b3bdbff2 100644 --- a/src/tallies/trigger_header.F90 +++ b/src/tallies/trigger_header.F90 @@ -1,5 +1,7 @@ module trigger_header + use, intrinsic :: ISO_C_BINDING + use constants, only: NONE, N_FILTER_TYPES, ZERO implicit none @@ -22,11 +24,11 @@ module trigger_header !=============================================================================== ! KTRIGGER describes a user-specified precision trigger for k-effective !=============================================================================== - type, public :: KTrigger - integer :: trigger_type = 0 - real(8) :: threshold = ZERO + type, public, bind(C) :: KTrigger + integer(C_INT) :: trigger_type = 0 + real(C_DOUBLE) :: threshold = ZERO end type KTrigger - type(KTrigger), public :: keff_trigger ! trigger for k-effective + type(KTrigger), public, bind(C) :: keff_trigger ! trigger for k-effective end module trigger_header From de38aa5a63d01d664dc53098b1f628d08c2c0530 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 27 Aug 2018 17:07:22 -0400 Subject: [PATCH 35/76] Address #1061 comments --- docs/source/io_formats/geometry.rst | 2 +- include/openmc/cell.h | 2 +- include/openmc/geometry.h | 16 ++++++++++++- include/openmc/position.h | 8 ------- include/openmc/settings.h | 2 -- include/openmc/simulation.h | 3 ++- openmc/cell.py | 2 +- src/cell.cpp | 2 +- src/geometry.cpp | 37 +++++++++++++---------------- src/output.cpp | 12 +++++----- 10 files changed, 43 insertions(+), 43 deletions(-) diff --git a/docs/source/io_formats/geometry.rst b/docs/source/io_formats/geometry.rst index 16ce8e655..94511842d 100644 --- a/docs/source/io_formats/geometry.rst +++ b/docs/source/io_formats/geometry.rst @@ -201,7 +201,7 @@ Each ```` element can have the following attributes or sub-elements: .. math:: - \left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi + + \left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ diff --git a/include/openmc/cell.h b/include/openmc/cell.h index c9227c7d6..033474025 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -7,10 +7,10 @@ #include #include -#include "constants.h" #include "hdf5.h" #include "pugixml.hpp" +#include "openmc/constants.h" #include "openmc/position.h" diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 742818579..f045209ee 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -4,10 +4,15 @@ #include #include -#include "particle.h" +#include "openmc/particle.h" + namespace openmc { +//============================================================================== +// Global variables +//============================================================================== + extern "C" int openmc_root_universe; extern std::vector overlap_check_count; @@ -21,6 +26,15 @@ check_cell_overlap(Particle* p); //============================================================================== //! Locate a particle in the geometry tree and set its geometry data fields. +//! +//! \param p A particle to be located. This function will populate the +//! geometry-dependent data fields of the particle. +//! \param search_surf A surface that the particle is expected to be on. This +//! value should be the signed, 1-based index of a surface. If positive, the +//! cells on the positive half-space of the surface will be searched. If +//! negative, the negative half-space will be searched. +//! \return True if the particle's location could be found and ascribed to a +//! valid geometry coordinate stack. //============================================================================== extern "C" bool diff --git a/include/openmc/position.h b/include/openmc/position.h index 62af3a122..97ab6f0e6 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -68,17 +68,9 @@ inline Position operator*(double a, Position b) { return b *= a; } inline bool operator==(Position a, Position b) {return a.x == b.x && a.y == b.y && a.z == b.z;} -inline bool operator==(Position a, double b) -{return a.x == b && a.y == b && a.z == b;} -inline bool operator==(double a, Position b) -{return a == b.x && a == b.y && a == b.z;} inline bool operator!=(Position a, Position b) {return a.x != b.x || a.y != b.y || a.z != b.z;} -inline bool operator!=(Position a, double b) -{return a.x != b || a.y != b || a.z != b;} -inline bool operator!=(double a, Position b) -{return a != b.x || a != b.y || a != b.z;} //============================================================================== //! Type representing a vector direction in Cartesian coordinates diff --git a/include/openmc/settings.h b/include/openmc/settings.h index d3b964ac2..66c6b53c0 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -19,11 +19,9 @@ namespace openmc { extern "C" bool openmc_check_overlaps; extern "C" bool openmc_particle_restart_run; extern "C" bool openmc_restart_run; -extern "C" bool openmc_trace; extern "C" int openmc_verbosity; extern "C" bool openmc_write_all_tracks; extern "C" double temperature_default; -#pragma omp threadprivate(openmc_trace) // Defined in .cpp // TODO: Make strings instead of char* once Fortran is gone diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 14bb56f27..b3239be68 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -7,7 +7,8 @@ extern "C" int openmc_current_batch; extern "C" int openmc_current_gen; extern "C" int64_t openmc_current_work; extern "C" int openmc_n_lost_particles; +extern "C" bool openmc_trace; -#pragma omp threadprivate(openmc_current_work) +#pragma omp threadprivate(openmc_current_work, openmc_trace) #endif // OPENMC_SIMULATION_H diff --git a/openmc/cell.py b/openmc/cell.py index 492bdeeb6..8503deffa 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -57,7 +57,7 @@ class Cell(IDManagerMixin): .. math:: - \left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\theta \sin\psi + \left [ \begin{array}{ccc} \cos\theta \cos\psi & -\cos\phi \sin\psi + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta \cos\psi \\ \cos\theta \sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi diff --git a/src/cell.cpp b/src/cell.cpp index ed82da15b..956fff6e9 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -494,7 +494,7 @@ Cell::to_hdf5(hid_t cells_group) const } else if (type == FILL_UNIVERSE) { write_dataset(group, "fill_type", "universe"); write_dataset(group, "fill", global_universes[fill]->id); - if (translation != 0) { + if (translation != Position(0, 0, 0)) { write_dataset(group, "translation", translation); } if (!rotation.empty()) { diff --git a/src/geometry.cpp b/src/geometry.cpp index d9b9642f5..681526097 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -7,7 +7,7 @@ #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/lattice.h" -#include "openmc/settings.h" +#include "openmc/simulation.h" #include "openmc/surface.h" @@ -23,16 +23,14 @@ extern "C" bool check_cell_overlap(Particle* p) { int n_coord = p->n_coord; - // loop through each coordinate level + // Loop through each coordinate level for (int j = 0; j < n_coord; j++) { Universe& univ = *global_universes[p->coord[j].universe]; int n = univ.cells.size(); - // loop through each cell on this level - for (int i = 0; i < n; i++) { - int index_cell = univ.cells[i]; + // Loop through each cell on this level + for (auto index_cell : univ.cells) { Cell& c = *global_cells[index_cell]; - if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { if (index_cell != p->coord[j].cell) { std::stringstream err_msg; @@ -65,26 +63,23 @@ find_cell(Particle* p, int search_surf) { } // If a surface was indicated, only search cells from the neighbor list of - // that surface. - int* search_cells; - int n_search_cells; + // that surface. The surface index is signed, and the sign signifies whether + // the positive or negative side of the surface should be searched. + const std::vector* search_cells; if (search_surf > 0) { - search_cells = global_surfaces[search_surf-1]->neighbor_pos.data(); - n_search_cells = global_surfaces[search_surf-1]->neighbor_pos.size(); + search_cells = &global_surfaces[search_surf-1]->neighbor_pos; } else if (search_surf < 0) { - search_cells = global_surfaces[-search_surf-1]->neighbor_neg.data(); - n_search_cells = global_surfaces[-search_surf-1]->neighbor_neg.size(); + search_cells = &global_surfaces[-search_surf-1]->neighbor_neg; } else { // No surface was indicated, search all cells in the universe. - search_cells = global_universes[i_universe]->cells.data(); - n_search_cells = global_universes[i_universe]->cells.size(); + search_cells = &global_universes[i_universe]->cells; } // Find which cell of this universe the particle is in. bool found = false; int32_t i_cell; - for (int i = 0; i < n_search_cells; i++) { - i_cell = search_cells[i]; + for (int i = 0; i < search_cells->size(); i++) { + i_cell = (*search_cells)[i]; // Make sure the search cell is in the same universe. if (global_cells[i_cell]->universe != i_universe) continue; @@ -155,6 +150,8 @@ find_cell(Particle* p, int search_surf) { p->sqrtkT = c.sqrtkT[0]; } + return true; + } else if (c.type == FILL_UNIVERSE) { //======================================================================== //! Found a lower universe, update this coord level then search the next. @@ -198,7 +195,7 @@ find_cell(Particle* p, int search_surf) { // Update the coordinate level and recurse. ++p->n_coord; - find_cell(p, 0); + return find_cell(p, 0); } else if (c.type == FILL_LATTICE) { //======================================================================== @@ -245,11 +242,9 @@ find_cell(Particle* p, int search_surf) { // Update the coordinate level and recurse. ++p->n_coord; - find_cell(p, 0); + return find_cell(p, 0); } } - - return found; } //============================================================================== diff --git a/src/output.cpp b/src/output.cpp index 89b4c8557..b8530dd3b 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -46,29 +46,29 @@ print_overlap_check() { #ifdef OPENMC_MPI std::vector temp(overlap_check_count); int err = MPI_Reduce(temp.data(), overlap_check_count.data(), - overlap_check_count.size(), MPI_LONG, MPI_SUM, 0, + overlap_check_count.size(), MPI_INT64_T, MPI_SUM, 0, mpi::intracomm); #endif if (openmc_master) { header("cell overlap check summary", 1); - std::cout << " Cell ID No. Overlap Checks" << std::endl; + std::cout << " Cell ID No. Overlap Checks\n"; std::vector sparse_cell_ids; for (int i = 0; i < n_cells; i++) { std::cout << " " << std::setw(8) << global_cells[i]->id << std::setw(17) - << overlap_check_count[i] << std::endl;; + << overlap_check_count[i] << "\n"; if (overlap_check_count[i] < 10) { sparse_cell_ids.push_back(global_cells[i]->id); } } - std::cout << std::endl << " There were " << sparse_cell_ids.size() - << " cells with less than 10 overlap checks" << std::endl; + std::cout << "\n There were " << sparse_cell_ids.size() + << " cells with less than 10 overlap checks\n"; for (auto id : sparse_cell_ids) { std::cout << " " << id; } - std::cout << std::endl; + std::cout << "\n"; } } From 260bf843e85e3cb3d8c4f90ea84771c9004dcaaf Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 27 Aug 2018 18:45:02 -0400 Subject: [PATCH 36/76] Add trailing underscores to class attributes --- include/openmc/cell.h | 34 ++-- include/openmc/lattice.h | 72 ++++----- include/openmc/surface.h | 40 +++-- src/cell.cpp | 218 +++++++++++++------------- src/geometry.cpp | 98 ++++++------ src/geometry_aux.cpp | 176 ++++++++++----------- src/lattice.cpp | 328 +++++++++++++++++++-------------------- src/output.cpp | 4 +- src/surface.cpp | 258 +++++++++++++++--------------- 9 files changed, 612 insertions(+), 616 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 033474025..fddfb1adb 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -53,8 +53,8 @@ extern std::unordered_map universe_map; class Universe { public: - int32_t id; //!< Unique ID - std::vector cells; //!< Cells within this universe + int32_t id_; //!< Unique ID + std::vector cells_; //!< Cells within this universe //! \brief Write universe information to an HDF5 group. //! \param group_id An HDF5 group id. @@ -68,34 +68,34 @@ public: 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 - int32_t n_instances{0}; //!< Number of instances of this cell + 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 + int32_t n_instances_{0}; //!< Number of instances of this cell //! \brief Index corresponding to this cell in distribcell arrays - int distribcell_index{C_NONE}; + int distribcell_index_{C_NONE}; //! \brief Material(s) within this cell. //! //! May be multiple materials for distribcell. - std::vector material; + std::vector material_; //! \brief Temperature(s) within this cell. //! //! The stored values are actually sqrt(k_Boltzmann * T) for each temperature //! T. The units are sqrt(eV). - std::vector sqrtkT; + std::vector sqrtkT_; //! Definition of spatial region as Boolean expression of half-spaces - std::vector region; + std::vector region_; //! Reverse Polish notation for region expression - std::vector rpn; - bool simple; //!< Does the region contain only intersections? + std::vector rpn_; + bool simple_; //!< Does the region contain only intersections? - Position translation {0, 0, 0}; //!< Translation vector for filled universe + Position translation_ {0, 0, 0}; //!< Translation vector for filled universe //! \brief Rotational tranfsormation of the filled universe. // @@ -103,9 +103,9 @@ public: //! values are the rotation angles respectively about the x-, y-, and z-, axes //! in degrees. The next 9 values give the rotation matrix in row-major //! order. - std::vector rotation; + std::vector rotation_; - std::vector offset; //!< Distribcell offset table + std::vector offset_; //!< Distribcell offset table Cell() {}; diff --git a/include/openmc/lattice.h b/include/openmc/lattice.h index 04381d218..10f6b4617 100644 --- a/include/openmc/lattice.h +++ b/include/openmc/lattice.h @@ -46,12 +46,12 @@ class ReverseLatticeIter; class Lattice { public: - int32_t id; //!< Universe ID number - std::string name; //!< User-defined name - LatticeType type; - 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 + LatticeType type_; + 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); @@ -70,7 +70,7 @@ public: //! Allocate offset table for distribcell. void allocate_offset_table(int n_maps) - {offsets.resize(n_maps * universes.size(), C_NONE);} + {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); @@ -115,7 +115,7 @@ public: //! \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());} //! \brief Get the distribcell offset for a lattice tile. //! \param The map index for the target cell. @@ -134,7 +134,7 @@ public: 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; }; @@ -146,31 +146,31 @@ protected: class LatticeIter { public: - int indx; //!< An index to a Lattice universes or offsets array. + int indx_; //!< An index to a Lattice universes or offsets array. - LatticeIter(Lattice &lat_, int indx_) - : lat(lat_), - indx(indx_) + LatticeIter(Lattice &lat, int indx) + : lat_(lat), + 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);} - int32_t& operator*() {return lat.universes[indx];} + int32_t& operator*() {return lat_.universes_[indx_];} LatticeIter& operator++() { - while (indx < lat.universes.size()) { - ++indx; - if (lat.is_valid_index(indx)) return *this; + while (indx_ < lat_.universes_.size()) { + ++indx_; + if (lat_.is_valid_index(indx_)) return *this; } - indx = lat.universes.size(); + indx_ = lat_.universes_.size(); return *this; } protected: - Lattice ⪫ + Lattice& lat_; }; //============================================================================== @@ -180,17 +180,17 @@ protected: class ReverseLatticeIter : public LatticeIter { public: - ReverseLatticeIter(Lattice &lat_, int indx_) - : LatticeIter {lat_, indx_} + ReverseLatticeIter(Lattice &lat, int indx) + : LatticeIter {lat, indx} {} ReverseLatticeIter& operator++() { - while (indx > -1) { - --indx; - if (lat.is_valid_index(indx)) return *this; + while (indx_ > -1) { + --indx_; + if (lat_.is_valid_index(indx_)) return *this; } - indx = -1; + indx_ = -1; return *this; } }; @@ -221,14 +221,14 @@ public: void to_hdf5_inner(hid_t group_id) const; private: - std::array n_cells; //!< Number of cells along each axis - Position lower_left; //!< Global lower-left corner of the lattice - Position pitch; //!< Lattice tile width along each axis + std::array n_cells_; //!< Number of cells along each axis + Position lower_left_; //!< Global lower-left corner of the lattice + Position pitch_; //!< Lattice tile width along each axis // Convenience aliases - int &nx {n_cells[0]}; - int &ny {n_cells[1]}; - int &nz {n_cells[2]}; + int &nx {n_cells_[0]}; + int &ny {n_cells_[1]}; + int &nz {n_cells_[2]}; }; //============================================================================== @@ -263,10 +263,10 @@ public: void to_hdf5_inner(hid_t group_id) const; private: - int n_rings; //!< Number of radial tile positions - int n_axial; //!< Number of axial tile positions - Position 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 + Position center_; //!< Global center of lattice + std::array pitch_; //!< Lattice tile width and height }; } // namespace openmc diff --git a/include/openmc/surface.h b/include/openmc/surface.h index df149b4a2..16f75b907 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -57,12 +57,12 @@ struct BoundingBox class Surface { public: - int id; //!< Unique ID - int bc; //!< Boundary condition - std::string name; //!< User-defined name + int id_; //!< Unique ID + int bc_; //!< Boundary condition + std::string name_; //!< User-defined name - std::vector neighbor_pos; //!< List of cells on positive side - std::vector neighbor_neg; //!< List of cells on negative side + std::vector neighbor_pos_; //!< List of cells on positive side + std::vector neighbor_neg_; //!< List of cells on negative side explicit Surface(pugi::xml_node surf_node); @@ -121,7 +121,7 @@ protected: class PeriodicSurface : public Surface { public: - int i_periodic{C_NONE}; //!< Index of corresponding periodic surface + int i_periodic_{C_NONE}; //!< Index of corresponding periodic surface explicit PeriodicSurface(pugi::xml_node surf_node); @@ -148,7 +148,7 @@ public: class SurfaceXPlane : public PeriodicSurface { - double x0; + double x0_; public: explicit SurfaceXPlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -168,7 +168,7 @@ public: class SurfaceYPlane : public PeriodicSurface { - double y0; + double y0_; public: explicit SurfaceYPlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -188,7 +188,7 @@ public: class SurfaceZPlane : public PeriodicSurface { - double z0; + double z0_; public: explicit SurfaceZPlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -208,7 +208,7 @@ public: class SurfacePlane : public PeriodicSurface { - double A, B, C, D; + double A_, B_, C_, D_; public: explicit SurfacePlane(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -229,7 +229,7 @@ public: class SurfaceXCylinder : public Surface { - double y0, z0, radius; + double y0_, z0_, radius_; public: explicit SurfaceXCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -247,7 +247,7 @@ public: class SurfaceYCylinder : public Surface { - double x0, z0, radius; + double x0_, z0_, radius_; public: explicit SurfaceYCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -265,7 +265,7 @@ public: class SurfaceZCylinder : public Surface { - double x0, y0, radius; + double x0_, y0_, radius_; public: explicit SurfaceZCylinder(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -283,7 +283,7 @@ public: class SurfaceSphere : public Surface { - double x0, y0, z0, radius; + double x0_, y0_, z0_, radius_; public: explicit SurfaceSphere(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -301,7 +301,7 @@ public: class SurfaceXCone : public Surface { - double x0, y0, z0, radius_sq; + double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceXCone(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -319,7 +319,7 @@ public: class SurfaceYCone : public Surface { - double x0, y0, z0, radius_sq; + double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceYCone(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -337,7 +337,7 @@ public: class SurfaceZCone : public Surface { - double x0, y0, z0, radius_sq; + double x0_, y0_, z0_, radius_sq_; public: explicit SurfaceZCone(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -355,7 +355,7 @@ public: class SurfaceQuadric : public Surface { // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 - double A, B, C, D, E, F, G, H, J, K; + double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; public: explicit SurfaceQuadric(pugi::xml_node surf_node); double evaluate(Position r) const; @@ -374,10 +374,6 @@ extern "C" { int surface_bc(Surface* surf); bool surface_sense(Surface* surf, double xyz[3], double uvw[3]); void surface_reflect(Surface* surf, double xyz[3], double uvw[3]); - double surface_distance(Surface* surf, double xyz[3], double uvw[3], - bool coincident); - void surface_normal(Surface* surf, double xyz[3], double uvw[3]); - void surface_to_hdf5(Surface* surf, hid_t group); int surface_i_periodic(PeriodicSurface* surf); bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], double uvw[3]); diff --git a/src/cell.cpp b/src/cell.cpp index 956fff6e9..c6b39f314 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -192,13 +192,13 @@ Universe::to_hdf5(hid_t universes_group) const { // Create a group for this universe. std::stringstream group_name; - group_name << "universe " << id; + group_name << "universe " << id_; auto group = create_group(universes_group, group_name); // Write the contained cells. - if (cells.size() > 0) { + if (cells_.size() > 0) { std::vector cell_ids; - for (auto i_cell : cells) cell_ids.push_back(global_cells[i_cell]->id); + for (auto i_cell : cells_) cell_ids.push_back(global_cells[i_cell]->id_); write_dataset(group, "cells", cell_ids); } @@ -212,19 +212,19 @@ Universe::to_hdf5(hid_t universes_group) const Cell::Cell(pugi::xml_node cell_node) { if (check_for_node(cell_node, "id")) { - id = std::stoi(get_node_value(cell_node, "id")); + id_ = std::stoi(get_node_value(cell_node, "id")); } else { fatal_error("Must specify id of cell in geometry XML file."); } if (check_for_node(cell_node, "name")) { - name = get_node_value(cell_node, "name"); + name_ = get_node_value(cell_node, "name"); } if (check_for_node(cell_node, "universe")) { - universe = std::stoi(get_node_value(cell_node, "universe")); + universe_ = std::stoi(get_node_value(cell_node, "universe")); } else { - universe = 0; + universe_ = 0; } // Make sure that either material or fill was specified, but not both. @@ -232,20 +232,20 @@ Cell::Cell(pugi::xml_node cell_node) bool material_present = check_for_node(cell_node, "material"); if (!(fill_present || material_present)) { std::stringstream err_msg; - err_msg << "Neither material nor fill was specified for cell " << id; + err_msg << "Neither material nor fill was specified for cell " << id_; fatal_error(err_msg); } if (fill_present && material_present) { std::stringstream err_msg; - err_msg << "Cell " << id << " has both a material and a fill specified; " + err_msg << "Cell " << id_ << " has both a material and a fill specified; " << "only one can be specified per cell"; fatal_error(err_msg); } if (fill_present) { - fill = std::stoi(get_node_value(cell_node, "fill")); + fill_ = std::stoi(get_node_value(cell_node, "fill")); } else { - fill = C_NONE; + fill_ = C_NONE; } // Read the material element. There can be zero materials (filled with a @@ -255,47 +255,47 @@ Cell::Cell(pugi::xml_node cell_node) std::vector mats {get_node_array(cell_node, "material", true)}; if (mats.size() > 0) { - material.reserve(mats.size()); + material_.reserve(mats.size()); for (std::string mat : mats) { if (mat.compare("void") == 0) { - material.push_back(MATERIAL_VOID); + material_.push_back(MATERIAL_VOID); } else { - material.push_back(std::stoi(mat)); + material_.push_back(std::stoi(mat)); } } } else { std::stringstream err_msg; - err_msg << "An empty material element was specified for cell " << id; + err_msg << "An empty material element was specified for cell " << id_; fatal_error(err_msg); } } // Read the temperature element which may be distributed like materials. if (check_for_node(cell_node, "temperature")) { - sqrtkT = get_node_array(cell_node, "temperature"); - sqrtkT.shrink_to_fit(); + sqrtkT_ = get_node_array(cell_node, "temperature"); + sqrtkT_.shrink_to_fit(); // Make sure this is a material-filled cell. - if (material.size() == 0) { + if (material_.size() == 0) { std::stringstream err_msg; - err_msg << "Cell " << id << " was specified with a temperature but " + err_msg << "Cell " << id_ << " was specified with a temperature but " "no material. Temperature specification is only valid for cells " "filled with a material."; fatal_error(err_msg); } // Make sure all temperatures are non-negative. - for (auto T : sqrtkT) { + for (auto T : sqrtkT_) { if (T < 0) { std::stringstream err_msg; - err_msg << "Cell " << id + err_msg << "Cell " << id_ << " was specified with a negative temperature"; fatal_error(err_msg); } } // Convert to sqrt(k*T). - for (auto& T : sqrtkT) { + for (auto& T : sqrtkT_) { T = std::sqrt(K_BOLTZMANN * T); } } @@ -307,34 +307,34 @@ Cell::Cell(pugi::xml_node cell_node) } // Get a tokenized representation of the region specification. - region = tokenize(region_spec); - region.shrink_to_fit(); + region_ = tokenize(region_spec); + region_.shrink_to_fit(); // Convert user IDs to surface indices. - for (auto &r : region) { + for (auto& r : region_) { if (r < OP_UNION) { r = copysign(surface_map[abs(r)] + 1, r); } } // Convert the infix region spec to RPN. - rpn = generate_rpn(id, region); - rpn.shrink_to_fit(); + rpn_ = generate_rpn(id_, region_); + rpn_.shrink_to_fit(); // Check if this is a simple cell. - simple = true; - for (int32_t token : rpn) { + simple_ = true; + for (int32_t token : rpn_) { if ((token == OP_COMPLEMENT) || (token == OP_UNION)) { - simple = false; + simple_ = false; break; } } // Read the translation vector. if (check_for_node(cell_node, "translation")) { - if (fill == C_NONE) { + if (fill_ == C_NONE) { std::stringstream err_msg; - err_msg << "Cannot apply a translation to cell " << id + err_msg << "Cannot apply a translation to cell " << id_ << " because it is not filled with another universe"; fatal_error(err_msg); } @@ -342,17 +342,17 @@ Cell::Cell(pugi::xml_node cell_node) auto xyz {get_node_array(cell_node, "translation")}; if (xyz.size() != 3) { std::stringstream err_msg; - err_msg << "Non-3D translation vector applied to cell " << id; + err_msg << "Non-3D translation vector applied to cell " << id_; fatal_error(err_msg); } - translation = xyz; + translation_ = xyz; } // Read the rotation transform. if (check_for_node(cell_node, "rotation")) { - if (fill == C_NONE) { + if (fill_ == C_NONE) { std::stringstream err_msg; - err_msg << "Cannot apply a rotation to cell " << id + err_msg << "Cannot apply a rotation to cell " << id_ << " because it is not filled with another universe"; fatal_error(err_msg); } @@ -360,33 +360,33 @@ Cell::Cell(pugi::xml_node cell_node) auto rot {get_node_array(cell_node, "rotation")}; if (rot.size() != 3) { std::stringstream err_msg; - err_msg << "Non-3D rotation vector applied to cell " << id; + err_msg << "Non-3D rotation vector applied to cell " << id_; fatal_error(err_msg); } // Store the rotation angles. - rotation.reserve(12); - rotation.push_back(rot[0]); - rotation.push_back(rot[1]); - rotation.push_back(rot[2]); + rotation_.reserve(12); + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); // Compute and store the rotation matrix. auto phi = -rot[0] * PI / 180.0; auto theta = -rot[1] * PI / 180.0; auto psi = -rot[2] * PI / 180.0; - rotation.push_back(std::cos(theta) * std::cos(psi)); - rotation.push_back(-std::cos(phi) * std::sin(psi) - + std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation.push_back(std::sin(phi) * std::sin(psi) - + std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation.push_back(std::cos(theta) * std::sin(psi)); - rotation.push_back(std::cos(phi) * std::cos(psi) - + std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation.push_back(-std::sin(phi) * std::cos(psi) - + std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation.push_back(-std::sin(theta)); - rotation.push_back(std::sin(phi) * std::cos(theta)); - rotation.push_back(std::cos(phi) * std::cos(theta)); + rotation_.push_back(std::cos(theta) * std::cos(psi)); + rotation_.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::cos(theta) * std::sin(psi)); + rotation_.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(theta)); + rotation_.push_back(std::sin(phi) * std::cos(theta)); + rotation_.push_back(std::cos(phi) * std::cos(theta)); } } @@ -395,7 +395,7 @@ Cell::Cell(pugi::xml_node cell_node) bool Cell::contains(Position r, Direction u, int32_t on_surface) const { - if (simple) { + if (simple_) { return contains_simple(r, u, on_surface); } else { return contains_complex(r, u, on_surface); @@ -410,7 +410,7 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const double min_dist {INFTY}; int32_t i_surf {std::numeric_limits::max()}; - for (int32_t token : rpn) { + for (int32_t token : rpn_) { // Ignore this token if it corresponds to an operator rather than a region. if (token >= OP_UNION) continue; @@ -438,19 +438,19 @@ Cell::to_hdf5(hid_t cells_group) const { // Create a group for this cell. std::stringstream group_name; - group_name << "cell " << id; + group_name << "cell " << id_; auto group = create_group(cells_group, group_name); - if (!name.empty()) { - write_string(group, "name", name, false); + if (!name_.empty()) { + write_string(group, "name", name_, false); } - write_dataset(group, "universe", global_universes[universe]->id); + write_dataset(group, "universe", global_universes[universe_]->id_); // Write the region specification. - if (!region.empty()) { + if (!region_.empty()) { std::stringstream region_spec {}; - for (int32_t token : region) { + for (int32_t token : region_) { if (token == OP_LEFT_PAREN) { region_spec << " ("; } else if (token == OP_RIGHT_PAREN) { @@ -463,17 +463,17 @@ Cell::to_hdf5(hid_t cells_group) const } else { // Note the off-by-one indexing region_spec << " " - << copysign(global_surfaces[abs(token)-1]->id, token); + << copysign(global_surfaces[abs(token)-1]->id_, token); } } write_string(group, "region", region_spec.str(), false); } // Write fill information. - if (type == FILL_MATERIAL) { + if (type_ == FILL_MATERIAL) { write_dataset(group, "fill_type", "material"); std::vector mat_ids; - for (auto i_mat : material) { + for (auto i_mat : material_) { if (i_mat != MATERIAL_VOID) { mat_ids.push_back(global_materials[i_mat]->id); } else { @@ -487,24 +487,24 @@ Cell::to_hdf5(hid_t cells_group) const } std::vector temps; - for (auto sqrtkT_val : sqrtkT) + for (auto sqrtkT_val : sqrtkT_) temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); write_dataset(group, "temperature", temps); - } else if (type == FILL_UNIVERSE) { + } else if (type_ == FILL_UNIVERSE) { write_dataset(group, "fill_type", "universe"); - write_dataset(group, "fill", global_universes[fill]->id); - if (translation != Position(0, 0, 0)) { - write_dataset(group, "translation", translation); + write_dataset(group, "fill", global_universes[fill_]->id_); + if (translation_ != Position(0, 0, 0)) { + write_dataset(group, "translation", translation_); } - if (!rotation.empty()) { - std::array rot {rotation[0], rotation[1], rotation[2]}; + if (!rotation_.empty()) { + std::array rot {rotation_[0], rotation_[1], rotation_[2]}; write_dataset(group, "rotation", rot); } - } else if (type == FILL_LATTICE) { + } else if (type_ == FILL_LATTICE) { write_dataset(group, "fill_type", "lattice"); - write_dataset(group, "lattice", lattices_c[fill]->id); + write_dataset(group, "lattice", lattices_c[fill_]->id_); } close_group(group); @@ -515,7 +515,7 @@ Cell::to_hdf5(hid_t cells_group) const bool Cell::contains_simple(Position r, Direction u, int32_t on_surface) const { - for (int32_t 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 @@ -541,10 +541,10 @@ Cell::contains_complex(Position r, Direction u, 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()]; + bool stack[rpn_.size()]; int i_stack = -1; - for (int32_t 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. @@ -606,15 +606,15 @@ read_cells(pugi::xml_node* node) // Populate the Universe vector and map. for (int i = 0; i < global_cells.size(); i++) { - int32_t uid = global_cells[i]->universe; + 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); + global_universes.back()->id_ = uid; + global_universes.back()->cells_.push_back(i); universe_map[uid] = global_universes.size() - 1; } else { - global_universes[it->second]->cells.push_back(i); + global_universes[it->second]->cells_.push_back(i); } } global_universes.shrink_to_fit(); @@ -633,12 +633,12 @@ openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) if (index >= 1 && index <= global_cells.size()) { //TODO: off-by-one Cell& c {*global_cells[index - 1]}; - *type = c.type; - if (c.type == FILL_MATERIAL) { - *indices = c.material.data(); - *n = c.material.size(); + *type = c.type_; + if (c.type_ == FILL_MATERIAL) { + *indices = c.material_.data(); + *n = c.material_.size(); } else { - *indices = &c.fill; + *indices = &c.fill_; *n = 1; } } else { @@ -656,25 +656,25 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, //TODO: off-by-one Cell& c {*global_cells[index - 1]}; if (type == FILL_MATERIAL) { - c.type = FILL_MATERIAL; - c.material.clear(); + c.type_ = FILL_MATERIAL; + c.material_.clear(); for (int i = 0; i < n; i++) { int i_mat = indices[i]; if (i_mat == MATERIAL_VOID) { - c.material.push_back(MATERIAL_VOID); + c.material_.push_back(MATERIAL_VOID); } else if (i_mat >= 1 && i_mat <= global_materials.size()) { //TODO: off-by-one - c.material.push_back(i_mat - 1); + c.material_.push_back(i_mat - 1); } else { set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } } - c.material.shrink_to_fit(); + c.material_.shrink_to_fit(); } else if (type == FILL_UNIVERSE) { - c.type = FILL_UNIVERSE; + c.type_ = FILL_UNIVERSE; } else { - c.type = FILL_LATTICE; + c.type_ = FILL_LATTICE; } } else { set_errmsg("Index in cells array is out of bounds."); @@ -692,14 +692,14 @@ openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance) Cell& c {*global_cells[index - 1]}; if (instance) { - if (*instance >= 0 && *instance < c.sqrtkT.size()) { - c.sqrtkT[*instance] = std::sqrt(K_BOLTZMANN * T); + if (*instance >= 0 && *instance < c.sqrtkT_.size()) { + c.sqrtkT_[*instance] = std::sqrt(K_BOLTZMANN * T); } else { strcpy(openmc_err_msg, "Distribcell instance is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } } else { - for (auto& T_ : c.sqrtkT) { + for (auto& T_ : c.sqrtkT_) { T_ = std::sqrt(K_BOLTZMANN * T); } } @@ -719,35 +719,35 @@ openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance) extern "C" { Cell* cell_pointer(int32_t cell_ind) {return global_cells[cell_ind];} - int32_t cell_id(Cell* c) {return c->id;} + int32_t cell_id(Cell* c) {return c->id_;} - void cell_set_id(Cell* c, int32_t id) {c->id = id;} + void cell_set_id(Cell* c, int32_t id) {c->id_ = id;} - int cell_type(Cell* c) {return c->type;} + int cell_type(Cell* c) {return c->type_;} - int32_t cell_universe(Cell* c) {return c->universe;} + int32_t cell_universe(Cell* c) {return c->universe_;} - int32_t cell_fill(Cell* c) {return c->fill;} + int32_t cell_fill(Cell* c) {return c->fill_;} - int32_t cell_n_instances(Cell* c) {return c->n_instances;} + int32_t cell_n_instances(Cell* c) {return c->n_instances_;} - int cell_distribcell_index(Cell* c) {return c->distribcell_index;} + int cell_distribcell_index(Cell* c) {return c->distribcell_index_;} - int cell_material_size(Cell* c) {return c->material.size();} + int cell_material_size(Cell* c) {return c->material_.size();} //TODO: off-by-one int32_t cell_material(Cell* c, int i) { - int32_t mat = c->material[i-1]; + int32_t mat = c->material_[i-1]; if (mat == MATERIAL_VOID) return MATERIAL_VOID; return mat + 1; } - int cell_sqrtkT_size(Cell* c) {return c->sqrtkT.size();} + int cell_sqrtkT_size(Cell* c) {return c->sqrtkT_.size();} - double cell_sqrtkT(Cell* c, int i) {return c->sqrtkT[i];} + double cell_sqrtkT(Cell* c, int i) {return c->sqrtkT_[i];} - int32_t cell_offset(Cell* c, int map) {return c->offset[map];} + int32_t cell_offset(Cell* c, int map) {return c->offset_[map];} void extend_cells_c(int32_t n) { @@ -758,7 +758,7 @@ extern "C" { n_cells = global_cells.size(); } - int32_t universe_id(int i_univ) {return global_universes[i_univ]->id;} + int32_t universe_id(int i_univ) {return global_universes[i_univ]->id_;} void universes_to_hdf5(hid_t universes_group) {for (Universe* u : global_universes) u->to_hdf5(universes_group);} diff --git a/src/geometry.cpp b/src/geometry.cpp index 681526097..1999738d5 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -26,17 +26,17 @@ check_cell_overlap(Particle* p) { // Loop through each coordinate level for (int j = 0; j < n_coord; j++) { Universe& univ = *global_universes[p->coord[j].universe]; - int n = univ.cells.size(); + int n = univ.cells_.size(); // Loop through each cell on this level - for (auto index_cell : univ.cells) { + for (auto index_cell : univ.cells_) { Cell& c = *global_cells[index_cell]; if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { if (index_cell != p->coord[j].cell) { std::stringstream err_msg; - err_msg << "Overlapping cells detected: " << c.id << ", " - << global_cells[p->coord[j].cell]->id << " on universe " - << univ.id; + err_msg << "Overlapping cells detected: " << c.id_ << ", " + << global_cells[p->coord[j].cell]->id_ << " on universe " + << univ.id_; fatal_error(err_msg); } ++overlap_check_count[index_cell]; @@ -67,12 +67,12 @@ find_cell(Particle* p, int search_surf) { // the positive or negative side of the surface should be searched. const std::vector* search_cells; if (search_surf > 0) { - search_cells = &global_surfaces[search_surf-1]->neighbor_pos; + search_cells = &global_surfaces[search_surf-1]->neighbor_pos_; } else if (search_surf < 0) { - search_cells = &global_surfaces[-search_surf-1]->neighbor_neg; + search_cells = &global_surfaces[-search_surf-1]->neighbor_neg_; } else { // No surface was indicated, search all cells in the universe. - search_cells = &global_universes[i_universe]->cells; + search_cells = &global_universes[i_universe]->cells_; } // Find which cell of this universe the particle is in. @@ -82,7 +82,7 @@ find_cell(Particle* p, int search_surf) { i_cell = (*search_cells)[i]; // Make sure the search cell is in the same universe. - if (global_cells[i_cell]->universe != i_universe) continue; + if (global_cells[i_cell]->universe_ != i_universe) continue; Position r {p->coord[p->n_coord-1].xyz}; Direction u {p->coord[p->n_coord-1].uvw}; @@ -92,7 +92,7 @@ find_cell(Particle* p, int search_surf) { if (openmc_verbosity >= 10 || openmc_trace) { std::stringstream msg; - msg << " Entering cell " << global_cells[i_cell]->id; + msg << " Entering cell " << global_cells[i_cell]->id_; write_message(msg, 1); } found = true; @@ -102,20 +102,20 @@ find_cell(Particle* p, int search_surf) { if (found) { Cell& c {*global_cells[i_cell]}; - if (c.type == FILL_MATERIAL) { + if (c.type_ == FILL_MATERIAL) { //======================================================================= //! Found a material cell which means this is the lowest coord level. // Find the distribcell instance number. - if (c.material.size() > 1 || c.sqrtkT.size() > 1) { + if (c.material_.size() > 1 || c.sqrtkT_.size() > 1) { //TODO: off-by-one indexing - int distribcell_index = c.distribcell_index - 1; + int distribcell_index = c.distribcell_index_ - 1; int offset = 0; for (int i = 0; i < p->n_coord; i++) { Cell& c_i {*global_cells[p->coord[i].cell]}; - if (c_i.type == FILL_UNIVERSE) { - offset += c_i.offset[distribcell_index]; - } else if (c_i.type == FILL_LATTICE) { + if (c_i.type_ == FILL_UNIVERSE) { + offset += c_i.offset_[distribcell_index]; + } else if (c_i.type_ == FILL_LATTICE) { Lattice& lat {*lattices_c[p->coord[i+1].lattice-1]}; int i_xyz[3] {p->coord[i+1].lattice_x, p->coord[i+1].lattice_y, @@ -133,10 +133,10 @@ find_cell(Particle* p, int search_surf) { // Set the material and temperature. p->last_material = p->material; int32_t mat; - if (c.material.size() > 1) { - mat = c.material[p->cell_instance-1]; + if (c.material_.size() > 1) { + mat = c.material_[p->cell_instance-1]; } else { - mat = c.material[0]; + mat = c.material_[0]; } if (mat == MATERIAL_VOID) { p->material = MATERIAL_VOID; @@ -144,20 +144,20 @@ find_cell(Particle* p, int search_surf) { p->material = mat + 1; } p->last_sqrtkT = p->sqrtkT; - if (c.sqrtkT.size() > 1) { - p->sqrtkT = c.sqrtkT[p->cell_instance-1]; + if (c.sqrtkT_.size() > 1) { + p->sqrtkT = c.sqrtkT_[p->cell_instance-1]; } else { - p->sqrtkT = c.sqrtkT[0]; + p->sqrtkT = c.sqrtkT_[0]; } return true; - } else if (c.type == FILL_UNIVERSE) { + } else if (c.type_ == FILL_UNIVERSE) { //======================================================================== //! Found a lower universe, update this coord level then search the next. // Set the lower coordinate level universe. - p->coord[p->n_coord].universe = c.fill; + p->coord[p->n_coord].universe = c.fill_; // Set the position and direction. for (int i = 0; i < 3; i++) { @@ -166,30 +166,30 @@ find_cell(Particle* p, int search_surf) { } // Apply translation. - p->coord[p->n_coord].xyz[0] -= c.translation.x; - p->coord[p->n_coord].xyz[1] -= c.translation.y; - p->coord[p->n_coord].xyz[2] -= c.translation.z; + p->coord[p->n_coord].xyz[0] -= c.translation_.x; + p->coord[p->n_coord].xyz[1] -= c.translation_.y; + p->coord[p->n_coord].xyz[2] -= c.translation_.z; // Apply rotation. - if (!c.rotation.empty()) { + if (!c.rotation_.empty()) { auto x = p->coord[p->n_coord].xyz[0]; auto y = p->coord[p->n_coord].xyz[1]; auto z = p->coord[p->n_coord].xyz[2]; - p->coord[p->n_coord].xyz[0] = x*c.rotation[3] + y*c.rotation[4] - + z*c.rotation[5]; - p->coord[p->n_coord].xyz[1] = x*c.rotation[6] + y*c.rotation[7] - + z*c.rotation[8]; - p->coord[p->n_coord].xyz[2] = x*c.rotation[9] + y*c.rotation[10] - + z*c.rotation[11]; + p->coord[p->n_coord].xyz[0] = x*c.rotation_[3] + y*c.rotation_[4] + + z*c.rotation_[5]; + p->coord[p->n_coord].xyz[1] = x*c.rotation_[6] + y*c.rotation_[7] + + z*c.rotation_[8]; + p->coord[p->n_coord].xyz[2] = x*c.rotation_[9] + y*c.rotation_[10] + + z*c.rotation_[11]; auto u = p->coord[p->n_coord].uvw[0]; auto v = p->coord[p->n_coord].uvw[1]; auto w = p->coord[p->n_coord].uvw[2]; - p->coord[p->n_coord].uvw[0] = u*c.rotation[3] + v*c.rotation[4] - + w*c.rotation[5]; - p->coord[p->n_coord].uvw[1] = u*c.rotation[6] + v*c.rotation[7] - + w*c.rotation[8]; - p->coord[p->n_coord].uvw[2] = u*c.rotation[9] + v*c.rotation[10] - + w*c.rotation[11]; + p->coord[p->n_coord].uvw[0] = u*c.rotation_[3] + v*c.rotation_[4] + + w*c.rotation_[5]; + p->coord[p->n_coord].uvw[1] = u*c.rotation_[6] + v*c.rotation_[7] + + w*c.rotation_[8]; + p->coord[p->n_coord].uvw[2] = u*c.rotation_[9] + v*c.rotation_[10] + + w*c.rotation_[11]; p->coord[p->n_coord].rotated = true; } @@ -197,11 +197,11 @@ find_cell(Particle* p, int search_surf) { ++p->n_coord; return find_cell(p, 0); - } else if (c.type == FILL_LATTICE) { + } else if (c.type_ == FILL_LATTICE) { //======================================================================== //! Found a lower lattice, update this coord level then search the next. - Lattice& lat {*lattices_c[c.fill]}; + Lattice& lat {*lattices_c[c.fill_]}; // Determine lattice indices. Position r {p->coord[p->n_coord-1].xyz}; @@ -219,7 +219,7 @@ find_cell(Particle* p, int search_surf) { p->coord[p->n_coord].uvw[2] = u.z; // Set lattice indices. - p->coord[p->n_coord].lattice = c.fill + 1; + p->coord[p->n_coord].lattice = c.fill_ + 1; p->coord[p->n_coord].lattice_x = i_xyz[0]; p->coord[p->n_coord].lattice_y = i_xyz[1]; p->coord[p->n_coord].lattice_z = i_xyz[2]; @@ -228,12 +228,12 @@ find_cell(Particle* p, int search_surf) { if (lat.are_valid_indices(i_xyz)) { p->coord[p->n_coord].universe = lat[i_xyz]; } else { - if (lat.outer != NO_OUTER_UNIVERSE) { - p->coord[p->n_coord].universe = lat.outer; + if (lat.outer_ != NO_OUTER_UNIVERSE) { + p->coord[p->n_coord].universe = lat.outer_; } else { std::stringstream err_msg; err_msg << "Particle " << p->id << " is outside lattice " - << lat.id << " but the lattice has no defined outer " + << lat.id_ << " but the lattice has no defined outer " "universe."; warning(err_msg); return false; @@ -256,7 +256,7 @@ cross_lattice(Particle* p, int lattice_translation[3]) if (openmc_verbosity >= 10 || openmc_trace) { std::stringstream msg; - msg << " Crossing lattice " << lat.id << ". Current position (" + msg << " Crossing lattice " << lat.id_ << ". Current position (" << p->coord[p->n_coord-1].lattice_x << "," << p->coord[p->n_coord-1].lattice_y << "," << p->coord[p->n_coord-1].lattice_z << ")"; @@ -342,7 +342,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, //TODO: refactor so both lattice use the same position argument (which //also means the lat.type attribute can be removed) std::pair> lattice_distance; - switch (lat.type) { + switch (lat.type_) { case LatticeType::rect: lattice_distance = lat.distance(r, u, i_xyz); break; @@ -374,7 +374,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, // 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 (c.simple) { + if (c.simple_) { *surface_crossed = level_surf_cross; } else { Position r_hit = r + d_surf * u; diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index c55baf4b0..768b2dd4e 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,25 +23,25 @@ adjust_indices() { // Adjust material/fill idices. for (Cell* c : global_cells) { - if (c->fill != C_NONE) { - int32_t id = c->fill; + if (c->fill_ != C_NONE) { + int32_t id = c->fill_; 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; + c->type_ = FILL_UNIVERSE; + c->fill_ = search_univ->second; } else if (search_lat != lattice_map.end()) { - c->type = FILL_LATTICE; - c->fill = search_lat->second; + c->type_ = FILL_LATTICE; + c->fill_ = search_lat->second; } else { std::stringstream err_msg; - err_msg << "Specified fill " << id << " on cell " << c->id + err_msg << "Specified fill " << id << " on cell " << c->id_ << " is neither a universe nor a lattice."; fatal_error(err_msg); } } else { - c->type = FILL_MATERIAL; - for (auto it = c->material.begin(); it != c->material.end(); it++) { + c->type_ = FILL_MATERIAL; + for (auto it = c->material_.begin(); it != c->material_.end(); it++) { int32_t mid = *it; if (mid != MATERIAL_VOID) { auto search = material_map.find(mid); @@ -50,7 +50,7 @@ adjust_indices() } else { std::stringstream err_msg; err_msg << "Could not find material " << mid - << " specified on cell " << c->id; + << " specified on cell " << c->id_; fatal_error(err_msg); } } @@ -60,13 +60,13 @@ adjust_indices() // Change cell.universe values from IDs to indices. for (Cell* c : global_cells) { - auto search = universe_map.find(c->universe); + auto search = universe_map.find(c->universe_); if (search != universe_map.end()) { - c->universe = search->second; + c->universe_ = search->second; } else { std::stringstream err_msg; - err_msg << "Could not find universe " << c->universe - << " specified on cell " << c->id; + err_msg << "Could not find universe " << c->universe_ + << " specified on cell " << c->id_; fatal_error(err_msg); } } @@ -84,23 +84,23 @@ assign_temperatures() { for (Cell* c : global_cells) { // Ignore non-material cells and cells with defined temperature. - if (c->material.size() == 0) continue; - if (c->sqrtkT.size() > 0) continue; + if (c->material_.size() == 0) continue; + if (c->sqrtkT_.size() > 0) continue; - c->sqrtkT.reserve(c->material.size()); - for (auto i_mat : c->material) { + c->sqrtkT_.reserve(c->material_.size()); + for (auto i_mat : c->material_) { if (i_mat == MATERIAL_VOID) { // Set void region to 0K. - c->sqrtkT.push_back(0); + c->sqrtkT_.push_back(0); } else { if (global_materials[i_mat]->temperature_ >= 0) { // This material has a default temperature; use that value. auto T = global_materials[i_mat]->temperature_; - c->sqrtkT.push_back(std::sqrt(K_BOLTZMANN * T)); + c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T)); } else { // Use the global default temperature. - c->sqrtkT.push_back(std::sqrt(K_BOLTZMANN * temperature_default)); + c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temperature_default)); } } } @@ -115,7 +115,7 @@ find_root_universe() // Find all the universes listed as a cell fill. std::unordered_set fill_univ_ids; for (Cell* c : global_cells) { - fill_univ_ids.insert(c->fill); + fill_univ_ids.insert(c->fill_); } // Find all the universes contained in a lattice. @@ -123,8 +123,8 @@ find_root_universe() 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); + if (lat->outer_ != NO_OUTER_UNIVERSE) { + fill_univ_ids.insert(lat->outer_); } } @@ -132,7 +132,7 @@ find_root_universe() bool root_found {false}; int32_t root_univ; for (int32_t i = 0; i < global_universes.size(); i++) { - auto search = fill_univ_ids.find(global_universes[i]->id); + 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 " @@ -158,22 +158,22 @@ neighbor_lists() write_message("Building neighboring cells lists for each surface...", 6); for (int i = 0; i < global_cells.size(); i++) { - for (auto token : global_cells[i]->region) { + for (auto token : global_cells[i]->region_) { // Skip operator tokens. if (std::abs(token) >= OP_UNION) continue; // This token is a surface index. Add the cell to the surface's list. if (token > 0) { - global_surfaces[std::abs(token)-1]->neighbor_pos.push_back(i); + global_surfaces[std::abs(token)-1]->neighbor_pos_.push_back(i); } else { - global_surfaces[std::abs(token)-1]->neighbor_neg.push_back(i); + global_surfaces[std::abs(token)-1]->neighbor_neg_.push_back(i); } } } for (Surface* surf : global_surfaces) { - surf->neighbor_pos.shrink_to_fit(); - surf->neighbor_neg.shrink_to_fit(); + surf->neighbor_pos_.shrink_to_fit(); + surf->neighbor_neg_.shrink_to_fit(); } } @@ -193,11 +193,11 @@ prepare_distribcell(int32_t* filter_cell_list, int n) for (int i = 0; i < global_cells.size(); i++) { Cell& c {*global_cells[i]}; - if (c.material.size() > 1) { - if (c.material.size() != c.n_instances) { + if (c.material_.size() > 1) { + if (c.material_.size() != c.n_instances_) { std::stringstream err_msg; - err_msg << "Cell " << c.id << " was specified with " - << c.material.size() << " materials but has " << c.n_instances + err_msg << "Cell " << c.id_ << " was specified with " + << c.material_.size() << " materials but has " << c.n_instances_ << " distributed instances. The number of materials must equal " "one or the number of instances."; fatal_error(err_msg); @@ -205,13 +205,13 @@ prepare_distribcell(int32_t* filter_cell_list, int n) distribcells.insert(i); } - if (c.sqrtkT.size() > 1) { - if (c.sqrtkT.size() != c.n_instances) { + if (c.sqrtkT_.size() > 1) { + if (c.sqrtkT_.size() != c.n_instances_) { std::stringstream err_msg; - err_msg << "Cell " << c.id << " was specified with " - << c.sqrtkT.size() << " temperatures but has " << c.n_instances - << " distributed instances. The number of temperatures must equal " - "one or the number of instances."; + err_msg << "Cell " << c.id_ << " was specified with " + << c.sqrtkT_.size() << " temperatures but has " << c.n_instances_ + << " distributed instances. The number of temperatures must equal " + "one or the number of instances."; fatal_error(err_msg); } distribcells.insert(i); @@ -224,10 +224,10 @@ prepare_distribcell(int32_t* filter_cell_list, int n) int distribcell_index = 1; std::vector target_univ_ids; for (Universe* u : global_universes) { - for (auto cell_indx : u->cells) { + for (auto cell_indx : u->cells_) { if (distribcells.find(cell_indx) != distribcells.end()) { - global_cells[cell_indx]->distribcell_index = distribcell_index; - target_univ_ids.push_back(u->id); + global_cells[cell_indx]->distribcell_index_ = distribcell_index; + target_univ_ids.push_back(u->id_); ++distribcell_index; } } @@ -236,8 +236,8 @@ prepare_distribcell(int32_t* filter_cell_list, int n) // Allocate the cell and lattice offset tables. int n_maps = target_univ_ids.size(); for (Cell* c : global_cells) { - if (c->type != FILL_MATERIAL) { - c->offset.resize(n_maps, C_NONE); + if (c->type_ != FILL_MATERIAL) { + c->offset_.resize(n_maps, C_NONE); } } for (Lattice* lat : lattices_c) { @@ -249,16 +249,16 @@ prepare_distribcell(int32_t* filter_cell_list, int n) auto target_univ_id = target_univ_ids[map]; 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) { + for (int32_t cell_indx : univ->cells_) { Cell& c = *global_cells[cell_indx]; - if (c.type == FILL_UNIVERSE) { - c.offset[map] = offset; - int32_t search_univ = c.fill; + if (c.type_ == FILL_UNIVERSE) { + c.offset_[map] = offset; + 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]; + } else if (c.type_ == FILL_LATTICE) { + Lattice& lat = *lattices_c[c.fill_]; offset = lat.fill_offset_table(offset, target_univ_id, map); } } @@ -271,17 +271,17 @@ prepare_distribcell(int32_t* filter_cell_list, int n) void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : global_universes[univ_indx]->cells) { + for (int32_t cell_indx : global_universes[univ_indx]->cells_) { Cell& c = *global_cells[cell_indx]; - ++c.n_instances; + ++c.n_instances_; - if (c.type == FILL_UNIVERSE) { + if (c.type_ == FILL_UNIVERSE) { // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill); + count_cell_instances(c.fill_); - } else if (c.type == FILL_LATTICE) { + } else if (c.type_ == FILL_LATTICE) { // This cell contains a lattice. Recurse into the lattice universes. - Lattice& lat = *lattices_c[c.fill]; + Lattice& lat = *lattices_c[c.fill_]; for (auto it = lat.begin(); it != lat.end(); ++it) { count_cell_instances(*it); } @@ -295,20 +295,20 @@ int count_universe_instances(int32_t search_univ, int32_t target_univ_id) { // If this is the target, it can't contain itself. - if (global_universes[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 : global_universes[search_univ]->cells) { + 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; + if (c.type_ == FILL_UNIVERSE) { + 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]; + } else if (c.type_ == FILL_LATTICE) { + 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); @@ -327,14 +327,14 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, { std::stringstream path; - path << "u" << search_univ.id << "->"; + 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) { + for (int32_t cell_indx : search_univ.cells_) { if ((cell_indx == target_cell) && (offset == target_offset)) { Cell& c = *global_cells[cell_indx]; - path << "c" << c.id; + path << "c" << c.id_; return path.str(); } } @@ -343,19 +343,19 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, // cell or lattice cell in this universe. Find which cell contains the // target. std::vector::const_reverse_iterator cell_it - {search_univ.cells.crbegin()}; - for (; cell_it != search_univ.cells.crend(); ++cell_it) { + {search_univ.cells_.crbegin()}; + for (; cell_it != search_univ.cells_.crend(); ++cell_it) { Cell& c = *global_cells[*cell_it]; // Material cells don't contain other cells so ignore them. - if (c.type != FILL_MATERIAL) { + if (c.type_ != FILL_MATERIAL) { int32_t temp_offset; - if (c.type == FILL_UNIVERSE) { - temp_offset = offset + c.offset[map]; + 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]; + 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 @@ -366,24 +366,24 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, // Add the cell to the path string. Cell& c = *global_cells[*cell_it]; - path << "c" << c.id << "->"; + path << "c" << c.id_ << "->"; - if (c.type == FILL_UNIVERSE) { + if (c.type_ == FILL_UNIVERSE) { // Recurse into the fill cell. - offset += c.offset[map]; + offset += c.offset_[map]; path << distribcell_path_inner(target_cell, map, target_offset, - *global_universes[c.fill], offset); + *global_universes[c.fill_], offset); return path.str(); } else { // Recurse into the lattice cell. - Lattice& lat = *lattices_c[c.fill]; - path << "l" << lat.id; + 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]; + 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 << "(" << lat.index_to_string(it.indx_) << ")->"; path << distribcell_path_inner(target_cell, map, target_offset, *global_universes[*it], offset); return path.str(); @@ -424,13 +424,13 @@ maximum_levels(int32_t univ) { int levels_below {0}; - for (int32_t cell_indx : global_universes[univ]->cells) { + 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; + if (c.type_ == FILL_UNIVERSE) { + 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]; + } else if (c.type_ == FILL_LATTICE) { + 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/lattice.cpp b/src/lattice.cpp index 36b0cea61..0975082eb 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -29,17 +29,17 @@ std::unordered_map lattice_map; Lattice::Lattice(pugi::xml_node lat_node) { if (check_for_node(lat_node, "id")) { - id = std::stoi(get_node_value(lat_node, "id")); + id_ = std::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"); + name_ = get_node_value(lat_node, "name"); } if (check_for_node(lat_node, "outer")) { - outer = std::stoi(get_node_value(lat_node, "outer")); + outer_ = std::stoi(get_node_value(lat_node, "outer")); } } @@ -49,10 +49,10 @@ LatticeIter Lattice::begin() {return LatticeIter(*this, 0);} LatticeIter Lattice::end() -{return LatticeIter(*this, universes.size());} +{return LatticeIter(*this, universes_.size());} ReverseLatticeIter Lattice::rbegin() -{return ReverseLatticeIter(*this, universes.size()-1);} +{return ReverseLatticeIter(*this, universes_.size()-1);} ReverseLatticeIter Lattice::rend() {return ReverseLatticeIter(*this, -1);} @@ -71,20 +71,20 @@ Lattice::adjust_indices() } else { std::stringstream err_msg; err_msg << "Invalid universe number " << uid << " specified on " - "lattice " << id; + "lattice " << id_; fatal_error(err_msg); } } // Adjust the index for the outer universe. - if (outer != NO_OUTER_UNIVERSE) { - auto search = universe_map.find(outer); + if (outer_ != NO_OUTER_UNIVERSE) { + auto search = universe_map.find(outer_); if (search != universe_map.end()) { - outer = search->second; + outer_ = search->second; } else { std::stringstream err_msg; - err_msg << "Invalid universe number " << outer << " specified on " - "lattice " << id; + err_msg << "Invalid universe number " << outer_ << " specified on " + "lattice " << id_; fatal_error(err_msg); } } @@ -96,7 +96,7 @@ int32_t Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map) { for (LatticeIter it = begin(); it != end(); ++it) { - offsets[map * universes.size() + it.indx] = offset; + offsets_[map * universes_.size() + it.indx_] = offset; offset += count_universe_instances(*it, target_univ_id); } return offset; @@ -109,19 +109,19 @@ 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); + 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 (!name_.empty()) { + write_string(lat_group, "name", name_, false); } - if (outer != NO_OUTER_UNIVERSE) { - int32_t outer_id = global_universes[outer]->id; + if (outer_ != NO_OUTER_UNIVERSE) { + int32_t outer_id = global_universes[outer_]->id_; write_dataset(lat_group, "outer", outer_id); } else { - write_dataset(lat_group, "outer", outer); + write_dataset(lat_group, "outer", outer_); } // Call subclass-overriden function to fill in other details. @@ -137,21 +137,21 @@ Lattice::to_hdf5(hid_t lattices_group) const RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} { - type = LatticeType::rect; + type_ = LatticeType::rect; // 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] = std::stoi(dimension_words[0]); - n_cells[1] = std::stoi(dimension_words[1]); - n_cells[2] = 1; - is_3d = false; + n_cells_[0] = std::stoi(dimension_words[0]); + n_cells_[1] = std::stoi(dimension_words[1]); + n_cells_[2] = 1; + is_3d_ = false; } else if (dimension_words.size() == 3) { - n_cells[0] = std::stoi(dimension_words[0]); - n_cells[1] = std::stoi(dimension_words[1]); - n_cells[2] = std::stoi(dimension_words[2]); - is_3d = true; + n_cells_[0] = std::stoi(dimension_words[0]); + n_cells_[1] = std::stoi(dimension_words[1]); + n_cells_[2] = std::stoi(dimension_words[2]); + is_3d_ = true; } else { fatal_error("Rectangular lattice must be two or three dimensions."); } @@ -163,9 +163,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] = stod(ll_words[0]); - lower_left[1] = stod(ll_words[1]); - if (is_3d) {lower_left[2] = stod(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")}; @@ -174,9 +174,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] = stod(pitch_words[0]); - pitch[1] = stod(pitch_words[1]); - if (is_3d) {pitch[2] = stod(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. std::string univ_str {get_node_value(lat_node, "universes")}; @@ -191,13 +191,13 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } // Parse the universes. - universes.resize(nx*ny*nz, C_NONE); + 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++) { int indx1 = nx*ny*iz + nx*(ny-iy-1) + ix; int indx2 = nx*ny*iz + nx*iy + ix; - universes[indx1] = std::stoi(univ_words[indx2]); + universes_[indx1] = std::stoi(univ_words[indx2]); } } } @@ -209,7 +209,7 @@ int32_t& RectLattice::operator[](std::array i_xyz) { int indx = nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]; - return universes[indx]; + return universes_[indx]; } //============================================================================== @@ -217,9 +217,9 @@ RectLattice::operator[](std::array i_xyz) 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])); } //============================================================================== @@ -234,8 +234,8 @@ const double z = r.z; // Determine the oncoming edge. - double x0 {copysign(0.5 * pitch[0], u.x)}; - double y0 {copysign(0.5 * pitch[1], u.y)}; + double x0 {copysign(0.5 * pitch_[0], u.x)}; + double y0 {copysign(0.5 * pitch_[1], u.y)}; // Left and right sides double d {INFTY}; @@ -263,8 +263,8 @@ const } // Top and bottom sides - if (is_3d) { - double z0 {copysign(0.5 * pitch[2], u.z)}; + if (is_3d_) { + double z0 {copysign(0.5 * pitch_[2], u.z)}; if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) { double this_d = (z0 - z) / u.z; if (this_d < d) { @@ -286,11 +286,11 @@ const std::array RectLattice::get_indices(Position r) const { - int ix {static_cast(std::ceil((r.x - lower_left.x) / pitch.x))-1}; - int iy {static_cast(std::ceil((r.y - lower_left.y) / pitch.y))-1}; + int ix {static_cast(std::ceil((r.x - lower_left_.x) / pitch_.x))-1}; + int iy {static_cast(std::ceil((r.y - lower_left_.y) / pitch_.y))-1}; int iz; - if (is_3d) { - iz = static_cast(std::ceil((r.z - lower_left.z) / pitch.z))-1; + if (is_3d_) { + iz = static_cast(std::ceil((r.z - lower_left_.z) / pitch_.z))-1; } else { iz = 0; } @@ -303,10 +303,10 @@ Position RectLattice::get_local_position(Position r, const std::array i_xyz) const { - r.x -= (lower_left.x + (i_xyz[0] + 0.5)*pitch.x); - r.y -= (lower_left.y + (i_xyz[1] + 0.5)*pitch.y); - if (is_3d) { - r.z -= (lower_left.z + (i_xyz[2] + 0.5)*pitch.z); + r.x -= (lower_left_.x + (i_xyz[0] + 0.5)*pitch_.x); + r.y -= (lower_left_.y + (i_xyz[1] + 0.5)*pitch_.y); + if (is_3d_) { + r.z -= (lower_left_.z + (i_xyz[2] + 0.5)*pitch_.z); } return r; } @@ -316,7 +316,7 @@ const int32_t& RectLattice::offset(int map, const int i_xyz[3]) { - return offsets[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; + return offsets_[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; } //============================================================================== @@ -330,7 +330,7 @@ RectLattice::index_to_string(int indx) const std::string out {std::to_string(ix)}; out += ','; out += std::to_string(iy); - if (is_3d) { + if (is_3d_) { out += ','; out += std::to_string(iz); } @@ -344,25 +344,25 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const { // Write basic lattice information. write_string(lat_group, "type", "rectangular", false); - if (is_3d) { - write_dataset(lat_group, "pitch", pitch); - write_dataset(lat_group, "lower_left", lower_left); - write_dataset(lat_group, "dimension", n_cells); + if (is_3d_) { + write_dataset(lat_group, "pitch", pitch_); + write_dataset(lat_group, "lower_left", lower_left_); + write_dataset(lat_group, "dimension", n_cells_); } else { - std::array pitch_short {{pitch[0], pitch[1]}}; + std::array pitch_short {{pitch_[0], pitch_[1]}}; write_dataset(lat_group, "pitch", pitch_short); - std::array ll_short {{lower_left[0], lower_left[1]}}; + std::array ll_short {{lower_left_[0], lower_left_[1]}}; write_dataset(lat_group, "lower_left", ll_short); - std::array nc_short {{n_cells[0], n_cells[1]}}; + std::array nc_short {{n_cells_[0], n_cells_[1]}}; write_dataset(lat_group, "dimension", nc_short); } // 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])}; + 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++) { @@ -370,7 +370,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] = global_universes[universes[indx1]]->id; + out[indx2] = global_universes[universes_[indx1]]->id_; } } } @@ -379,15 +379,15 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const 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])}; + 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] = global_universes[universes[indx1]]->id; + out[indx2] = global_universes[universes_[indx1]]->id_; } } @@ -403,54 +403,54 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const HexLattice::HexLattice(pugi::xml_node lat_node) : Lattice {lat_node} { - type = LatticeType::hex; + type_ = LatticeType::hex; // Read the number of lattice cells in each dimension. - n_rings = std::stoi(get_node_value(lat_node, "n_rings")); + n_rings_ = std::stoi(get_node_value(lat_node, "n_rings")); if (check_for_node(lat_node, "n_axial")) { - n_axial = std::stoi(get_node_value(lat_node, "n_axial")); - is_3d = true; + n_axial_ = std::stoi(get_node_value(lat_node, "n_axial")); + is_3d_ = true; } else { - n_axial = 1; - is_3d = false; + 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)) { + 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) { + } 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]);} + 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)) { + 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)) { + } 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]);} + 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 = (3*n_rings*n_rings - 3*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 " + << " universes for a hexagonal lattice with " << n_rings_ + << " rings and " << n_axial_ << " axial levels" << " but " << univ_words.size() << " were specified."; fatal_error(err_msg); } @@ -464,25 +464,25 @@ 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, C_NONE); + 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++) { + for (int m = 0; m < n_axial_; m++) { // Initialize lattice indecies. int i_x = 1; - int i_a = n_rings - 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++) { + 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] = std::stoi(univ_words[input_index]); + 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] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). i_x += 2; @@ -496,7 +496,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node) // 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++) { + 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; @@ -507,11 +507,11 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } // 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] = std::stoi(univ_words[input_index]); + 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] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). i_x += 2; @@ -519,22 +519,22 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } // Return the lattice index to the start of the current row. - i_x -= 2*(n_rings - (k % 2)); - i_a += n_rings - (k % 2); + 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++) { + 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] = std::stoi(univ_words[input_index]); + 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] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). i_x += 2; @@ -542,8 +542,8 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } // Return lattice index to start of current row. - i_x -= 2*(n_rings - k - 1); - i_a += n_rings - k - 1; + i_x -= 2*(n_rings_ - k - 1); + i_a += n_rings_ - k - 1; } } } @@ -553,19 +553,19 @@ HexLattice::HexLattice(pugi::xml_node lat_node) int32_t& HexLattice::operator[](std::array i_xyz) { - int indx = (2*n_rings-1)*(2*n_rings-1) * i_xyz[2] - + (2*n_rings-1) * i_xyz[1] + 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]; + return universes_[indx]; } //============================================================================== LatticeIter HexLattice::begin() -{return LatticeIter(*this, n_rings-1);} +{return LatticeIter(*this, n_rings_-1);} ReverseLatticeIter HexLattice::rbegin() -{return ReverseLatticeIter(*this, universes.size()-n_rings);} +{return ReverseLatticeIter(*this, universes_.size()-n_rings_);} //============================================================================== @@ -573,10 +573,10 @@ 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-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)); + && (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_)); } //============================================================================== @@ -598,7 +598,7 @@ const // Upper-right and lower-left sides. double d {INFTY}; std::array lattice_trans; - double edge = -copysign(0.5*pitch[0], beta_dir); // Oncoming edge + double edge = -copysign(0.5*pitch_[0], beta_dir); // Oncoming edge Position r_t; if (beta_dir > 0) { const std::array i_xyz_t {i_xyz[0]+1, i_xyz[1], i_xyz[2]}; @@ -618,7 +618,7 @@ const } // Lower-right and upper-left sides. - edge = -copysign(0.5*pitch[0], gamma_dir); + edge = -copysign(0.5*pitch_[0], gamma_dir); if (gamma_dir > 0) { const std::array i_xyz_t {i_xyz[0]+1, i_xyz[1]-1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); @@ -640,7 +640,7 @@ const } // Upper and lower sides. - edge = -copysign(0.5*pitch[0], u.y); + edge = -copysign(0.5*pitch_[0], u.y); if (u.y > 0) { const std::array i_xyz_t {i_xyz[0], i_xyz[1]+1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); @@ -661,9 +661,9 @@ const } // Top and bottom sides - if (is_3d) { + if (is_3d_) { double z = r.z; - double z0 {copysign(0.5 * pitch[1], u.z)}; + double z0 {copysign(0.5 * pitch_[1], u.z)}; if ((std::abs(z - z0) > FP_PRECISION) && u.z != 0) { double this_d = (z0 - z) / u.z; if (this_d < d) { @@ -687,13 +687,13 @@ std::array HexLattice::get_indices(Position r) const { // Offset the xyz by the lattice center. - Position r_o {r.x - center.x, r.y - center.y, r.z}; - if (is_3d) {r_o.z -= center.z;} + Position r_o {r.x - center_.x, r.y - center_.y, r.z}; + if (is_3d_) {r_o.z -= center_.z;} // Index the z direction. std::array out; - if (is_3d) { - out[2] = static_cast(std::ceil(r_o.z / pitch[1] + 0.5 * n_axial))-1; + if (is_3d_) { + out[2] = static_cast(std::ceil(r_o.z / pitch_[1] + 0.5 * n_axial_))-1; } else { out[2] = 0; } @@ -702,13 +702,13 @@ HexLattice::get_indices(Position r) const // find the index of the global coordinates to within 4 cells. double alpha = r_o.y - r_o.x / std::sqrt(3.0); out[0] = static_cast(std::floor(r_o.x - / (0.5*std::sqrt(3.0) * pitch[0]))); - out[1] = static_cast(std::floor(alpha / pitch[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 0). - out[0] += n_rings-1; - out[1] += n_rings-1; + 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 @@ -754,12 +754,12 @@ HexLattice::get_local_position(Position r, const std::array i_xyz) const { // x_l = x_g - (center + pitch_x*cos(30)*index_x) - r.x -= (center.x + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings + 1) * pitch[0]); + r.x -= center_.x + 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) - r.y -= (center.y + (i_xyz[1] - n_rings + 1) * pitch[0] - + (i_xyz[0] - n_rings + 1) * pitch[0] / 2.0); - if (is_3d) { - r.z -= center.z - (0.5 * n_axial - i_xyz[2] - 0.5) * pitch[1]; + r.y -= (center_.y + (i_xyz[1] - n_rings_ + 1) * pitch_[0] + + (i_xyz[0] - n_rings_ + 1) * pitch_[0] / 2.0); + if (is_3d_) { + r.z -= center_.z - (0.5 * n_axial_ - i_xyz[2] - 0.5) * pitch_[1]; } return r; @@ -770,9 +770,9 @@ 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 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; @@ -785,10 +785,10 @@ 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]]; + 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]]; } //============================================================================== @@ -796,15 +796,15 @@ HexLattice::offset(int map, const int i_xyz[3]) std::string HexLattice::index_to_string(int indx) const { - int nx {2*n_rings - 1}; - int ny {2*n_rings - 1}; + 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)}; + std::string out {std::to_string(ix - n_rings_ + 1)}; out += ','; - out += std::to_string(iy - n_rings + 1); - if (is_3d) { + out += std::to_string(iy - n_rings_ + 1); + if (is_3d_) { out += ','; out += std::to_string(iz); } @@ -818,36 +818,36 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const { // Write basic lattice information. write_string(lat_group, "type", "hexagonal", false); - write_dataset(lat_group, "n_rings", n_rings); - write_dataset(lat_group, "n_axial", n_axial); - if (is_3d) { - write_dataset(lat_group, "pitch", pitch); - write_dataset(lat_group, "center", center); + write_dataset(lat_group, "n_rings", n_rings_); + write_dataset(lat_group, "n_axial", n_axial_); + if (is_3d_) { + write_dataset(lat_group, "pitch", pitch_); + write_dataset(lat_group, "center", center_); } else { - std::array pitch_short {{pitch[0]}}; + std::array pitch_short {{pitch_[0]}}; write_dataset(lat_group, "pitch", pitch_short); - std::array center_short {{center[0], center[1]}}; + std::array center_short {{center_[0], center_[1]}}; write_dataset(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)}; + 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) { + 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) { + } 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] = global_universes[universes[indx]]->id; + out[indx] = global_universes[universes_[indx]]->id_; } } } @@ -873,7 +873,7 @@ read_lattices(pugi::xml_node *node) // Fill the lattice map. for (int i_lat = 0; i_lat < lattices_c.size(); i_lat++) { - int id = lattices_c[i_lat]->id; + int id = lattices_c[i_lat]->id_; auto in_map = lattice_map.find(id); if (in_map == lattice_map.end()) { lattice_map[id] = i_lat; @@ -892,7 +892,7 @@ read_lattices(pugi::xml_node *node) extern "C" { Lattice* lattice_pointer(int lat_ind) {return lattices_c[lat_ind];} - int32_t lattice_id(Lattice *lat) {return lat->id;} + 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);} diff --git a/src/output.cpp b/src/output.cpp index b8530dd3b..2d7b76753 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -56,10 +56,10 @@ print_overlap_check() { std::vector sparse_cell_ids; for (int i = 0; i < n_cells; i++) { - std::cout << " " << std::setw(8) << global_cells[i]->id << std::setw(17) + std::cout << " " << std::setw(8) << global_cells[i]->id_ << std::setw(17) << overlap_check_count[i] << "\n"; if (overlap_check_count[i] < 10) { - sparse_cell_ids.push_back(global_cells[i]->id); + sparse_cell_ids.push_back(global_cells[i]->id_); } } diff --git a/src/surface.cpp b/src/surface.cpp index 4de0bd0f9..54ff511dc 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -141,38 +141,38 @@ void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, Surface::Surface(pugi::xml_node surf_node) { if (check_for_node(surf_node, "id")) { - id = std::stoi(get_node_value(surf_node, "id")); + id_ = std::stoi(get_node_value(surf_node, "id")); } else { fatal_error("Must specify id of surface in geometry XML file."); } if (check_for_node(surf_node, "name")) { - name = get_node_value(surf_node, "name", false); + name_ = get_node_value(surf_node, "name", false); } if (check_for_node(surf_node, "boundary")) { std::string surf_bc = get_node_value(surf_node, "boundary", true, true); if (surf_bc == "transmission" || surf_bc == "transmit" ||surf_bc.empty()) { - bc = BC_TRANSMIT; + bc_ = BC_TRANSMIT; } else if (surf_bc == "vacuum") { - bc = BC_VACUUM; + bc_ = BC_VACUUM; } else if (surf_bc == "reflective" || surf_bc == "reflect" || surf_bc == "reflecting") { - bc = BC_REFLECT; + bc_ = BC_REFLECT; } else if (surf_bc == "periodic") { - bc = BC_PERIODIC; + bc_ = BC_PERIODIC; } else { std::stringstream err_msg; err_msg << "Unknown boundary condition \"" << surf_bc - << "\" specified on surface " << id; + << "\" specified on surface " << id_; fatal_error(err_msg); } } else { - bc = BC_TRANSMIT; + bc_ = BC_TRANSMIT; } } @@ -211,11 +211,11 @@ void Surface::to_hdf5(hid_t group_id) const { std::string group_name {"surface "}; - group_name += std::to_string(id); + group_name += std::to_string(id_); hid_t surf_group = create_group(group_id, group_name); - switch(bc) { + switch(bc_) { case BC_TRANSMIT : write_string(surf_group, "boundary_type", "transmission", false); break; @@ -230,8 +230,8 @@ Surface::to_hdf5(hid_t group_id) const break; } - if (!name.empty()) { - write_string(surf_group, "name", name, false); + if (!name_.empty()) { + write_string(surf_group, "name", name_, false); } to_hdf5_inner(surf_group); @@ -247,7 +247,7 @@ PeriodicSurface::PeriodicSurface(pugi::xml_node surf_node) : Surface {surf_node} { if (check_for_node(surf_node, "periodic_surface_id")) { - i_periodic = std::stoi(get_node_value(surf_node, "periodic_surface_id")); + i_periodic_ = std::stoi(get_node_value(surf_node, "periodic_surface_id")); } } @@ -273,17 +273,17 @@ axis_aligned_plane_distance(Position r, Direction u, bool coincident, double off SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, id, x0); + read_coeffs(surf_node, id_, x0_); } double SurfaceXPlane::evaluate(Position r) const { - return r.x - x0; + return r.x - x0_; } double SurfaceXPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<0>(r, u, coincident, x0); + return axis_aligned_plane_distance<0>(r, u, coincident, x0_); } Direction SurfaceXPlane::normal(Position r) const @@ -294,7 +294,7 @@ Direction SurfaceXPlane::normal(Position r) const void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-plane", false); - std::array coeffs {{x0}}; + std::array coeffs {{x0_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -303,15 +303,15 @@ bool SurfaceXPlane::periodic_translate(const PeriodicSurface* other, { Direction other_n = other->normal(r); if (other_n.x == 1 and other_n.y == 0 and other_n.z == 0) { - r.x = x0; + r.x = x0_; return false; } else { // Assume the partner is an YPlane (the only supported partner). Use the - // evaluate function to find y0, then adjust position/Direction for rotational - // symmetry. - double y0 = -other->evaluate({0., 0., 0.}); - r.y = r.x - x0 + y0; - r.x = x0; + // evaluate function to find y0, then adjust position/Direction for + // rotational symmetry. + double y0_ = -other->evaluate({0., 0., 0.}); + r.y = r.x - x0_ + y0_; + r.x = x0_; double ux = u.x; u.x = -u.y; @@ -324,7 +324,7 @@ bool SurfaceXPlane::periodic_translate(const PeriodicSurface* other, BoundingBox SurfaceXPlane::bounding_box() const { - return {x0, x0, -INFTY, INFTY, -INFTY, INFTY}; + return {x0_, x0_, -INFTY, INFTY, -INFTY, INFTY}; } //============================================================================== @@ -334,17 +334,17 @@ SurfaceXPlane::bounding_box() const SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, id, y0); + read_coeffs(surf_node, id_, y0_); } double SurfaceYPlane::evaluate(Position r) const { - return r.y - y0; + return r.y - y0_; } double SurfaceYPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<1>(r, u, coincident, y0); + return axis_aligned_plane_distance<1>(r, u, coincident, y0_); } Direction SurfaceYPlane::normal(Position r) const @@ -355,7 +355,7 @@ Direction SurfaceYPlane::normal(Position r) const void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-plane", false); - std::array coeffs {{y0}}; + std::array coeffs {{y0_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -365,15 +365,15 @@ bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other, Direction other_n = other->normal(r); if (other_n.x == 0 and other_n.y == 1 and other_n.z == 0) { // The periodic partner is also aligned along y. Just change the y coord. - r.y = y0; + r.y = y0_; return false; } else { // Assume the partner is an XPlane (the only supported partner). Use the // evaluate function to find x0, then adjust position/Direction for rotational // symmetry. - double x0 = -other->evaluate({0., 0., 0.}); - r.x = r.y - y0 + x0; - r.y = y0; + double x0_ = -other->evaluate({0., 0., 0.}); + r.x = r.y - y0_ + x0_; + r.y = y0_; double ux = u.x; u.x = u.y; @@ -386,7 +386,7 @@ bool SurfaceYPlane::periodic_translate(const PeriodicSurface *other, BoundingBox SurfaceYPlane::bounding_box() const { - return {-INFTY, INFTY, y0, y0, -INFTY, INFTY}; + return {-INFTY, INFTY, y0_, y0_, -INFTY, INFTY}; } //============================================================================== @@ -396,17 +396,17 @@ SurfaceYPlane::bounding_box() const SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, id, z0); + read_coeffs(surf_node, id_, z0_); } double SurfaceZPlane::evaluate(Position r) const { - return r.z - z0; + return r.z - z0_; } double SurfaceZPlane::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_plane_distance<2>(r, u, coincident, z0); + return axis_aligned_plane_distance<2>(r, u, coincident, z0_); } Direction SurfaceZPlane::normal(Position r) const @@ -417,7 +417,7 @@ Direction SurfaceZPlane::normal(Position r) const void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-plane", false); - std::array coeffs {{z0}}; + std::array coeffs {{z0_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -425,14 +425,14 @@ bool SurfaceZPlane::periodic_translate(const PeriodicSurface* other, Position& r, Direction& u) const { // Assume the other plane is aligned along z. Just change the z coord. - r.z = z0; + r.z = z0_; return false; } BoundingBox SurfaceZPlane::bounding_box() const { - return {-INFTY, INFTY, -INFTY, INFTY, z0, z0}; + return {-INFTY, INFTY, -INFTY, INFTY, z0_, z0_}; } //============================================================================== @@ -442,20 +442,20 @@ SurfaceZPlane::bounding_box() const SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : PeriodicSurface(surf_node) { - read_coeffs(surf_node, id, A, B, C, D); + read_coeffs(surf_node, id_, A_, B_, C_, D_); } double SurfacePlane::evaluate(Position r) const { - return A*r.x + B*r.y + C*r.z - D; + return A_*r.x + B_*r.y + C_*r.z - D_; } double SurfacePlane::distance(Position r, Direction u, bool coincident) const { - const double f = A*r.x + B*r.y + C*r.z - D; - const double projection = A*u.x + B*u.y + C*u.z; + const double f = A_*r.x + B_*r.y + C_*r.z - D_; + const double projection = A_*u.x + B_*u.y + C_*u.z; if (coincident or std::abs(f) < FP_COINCIDENT or projection == 0.0) { return INFTY; } else { @@ -468,13 +468,13 @@ SurfacePlane::distance(Position r, Direction u, bool coincident) const Direction SurfacePlane::normal(Position r) const { - return {A, B, C}; + return {A_, B_, C_}; } void SurfacePlane::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "plane", false); - std::array coeffs {{A, B, C, D}}; + std::array coeffs {{A_, B_, C_, D_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -484,12 +484,12 @@ bool SurfacePlane::periodic_translate(const PeriodicSurface* other, Position& r, // This function assumes the other plane shares this plane's normal direction. // Determine the distance to intersection. - double d = evaluate(r) / (A*A + B*B + C*C); + double d = evaluate(r) / (A_*A_ + B_*B_ + C_*C_); // Move the particle that distance along the normal vector. - r.x -= d * A; - r.y -= d * B; - r.z -= d * C; + r.x -= d * A_; + r.y -= d * B_; + r.z -= d * C_; return false; } @@ -582,30 +582,30 @@ axis_aligned_cylinder_normal(Position r, double offset1, double offset2) SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, y0, z0, radius); + read_coeffs(surf_node, id_, y0_, z0_, radius_); } double SurfaceXCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<1, 2>(r, y0, z0, radius); + return axis_aligned_cylinder_evaluate<1, 2>(r, y0_, z0_, radius_); } double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0, z0, - radius); + return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0_, z0_, + radius_); } Direction SurfaceXCylinder::normal(Position r) const { - return axis_aligned_cylinder_normal<0, 1, 2>(r, y0, z0); + return axis_aligned_cylinder_normal<0, 1, 2>(r, y0_, z0_); } void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cylinder", false); - std::array coeffs {{y0, z0, radius}}; + std::array coeffs {{y0_, z0_, radius_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -616,29 +616,29 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, z0, radius); + read_coeffs(surf_node, id_, x0_, z0_, radius_); } double SurfaceYCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 2>(r, x0, z0, radius); + return axis_aligned_cylinder_evaluate<0, 2>(r, x0_, z0_, radius_); } double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0, z0, - radius); + return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0_, z0_, + radius_); } Direction SurfaceYCylinder::normal(Position r) const { - return axis_aligned_cylinder_normal<1, 0, 2>(r, x0, z0); + return axis_aligned_cylinder_normal<1, 0, 2>(r, x0_, z0_); } void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cylinder", false); - std::array coeffs {{x0, z0, radius}}; + std::array coeffs {{x0_, z0_, radius_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -649,29 +649,29 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, radius); + read_coeffs(surf_node, id_, x0_, y0_, radius_); } double SurfaceZCylinder::evaluate(Position r) const { - return axis_aligned_cylinder_evaluate<0, 1>(r, x0, y0, radius); + return axis_aligned_cylinder_evaluate<0, 1>(r, x0_, y0_, radius_); } double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0, y0, - radius); + return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0_, y0_, + radius_); } Direction SurfaceZCylinder::normal(Position r) const { - return axis_aligned_cylinder_normal<2, 0, 1>(r, x0, y0); + return axis_aligned_cylinder_normal<2, 0, 1>(r, x0_, y0_); } void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cylinder", false); - std::array coeffs {{x0, y0, radius}}; + std::array coeffs {{x0_, y0_, radius_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -682,24 +682,24 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, radius); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_); } double SurfaceSphere::evaluate(Position r) const { - const double x = r.x - x0; - const double y = r.y - y0; - const double z = r.z - z0; - return x*x + y*y + z*z - radius*radius; + const double x = r.x - x0_; + const double y = r.y - y0_; + const double z = r.z - z0_; + return x*x + y*y + z*z - radius_*radius_; } double SurfaceSphere::distance(Position r, Direction u, bool coincident) const { - const double x = r.x - x0; - const double y = r.y - y0; - const double z = r.z - z0; + const double x = r.x - x0_; + const double y = r.y - y0_; + const double z = r.z - z0_; const double k = x*u.x + y*u.y + z*u.z; - const double c = x*x + y*y + z*z - radius*radius; + const double c = x*x + y*y + z*z - radius_*radius_; const double quad = k*k - c; if (quad < 0.0) { @@ -733,13 +733,13 @@ double SurfaceSphere::distance(Position r, Direction u, bool coincident) const Direction SurfaceSphere::normal(Position r) const { - return {2.0*(r.x - x0), 2.0*(r.y - y0), 2.0*(r.z - z0)}; + return {2.0*(r.x - x0_), 2.0*(r.y - y0_), 2.0*(r.z - z0_)}; } void SurfaceSphere::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "sphere", false); - std::array coeffs {{x0, y0, z0, radius}}; + std::array coeffs {{x0_, y0_, z0_, radius_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -835,29 +835,29 @@ axis_aligned_cone_normal(Position r, double offset1, double offset2, SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, radius_sq); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceXCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<0, 1, 2>(r, x0, y0, z0, radius_sq); + return axis_aligned_cone_evaluate<0, 1, 2>(r, x0_, y0_, z0_, radius_sq_); } double SurfaceXCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0, y0, z0, - radius_sq); + return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0_, y0_, z0_, + radius_sq_); } Direction SurfaceXCone::normal(Position r) const { - return axis_aligned_cone_normal<0, 1, 2>(r, x0, y0, z0, radius_sq); + return axis_aligned_cone_normal<0, 1, 2>(r, x0_, y0_, z0_, radius_sq_); } void SurfaceXCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "x-cone", false); - std::array coeffs {{x0, y0, z0, radius_sq}}; + std::array coeffs {{x0_, y0_, z0_, radius_sq_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -868,29 +868,29 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, radius_sq); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceYCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<1, 0, 2>(r, y0, x0, z0, radius_sq); + return axis_aligned_cone_evaluate<1, 0, 2>(r, y0_, x0_, z0_, radius_sq_); } double SurfaceYCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0, x0, z0, - radius_sq); + return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0_, x0_, z0_, + radius_sq_); } Direction SurfaceYCone::normal(Position r) const { - return axis_aligned_cone_normal<1, 0, 2>(r, y0, x0, z0, radius_sq); + return axis_aligned_cone_normal<1, 0, 2>(r, y0_, x0_, z0_, radius_sq_); } void SurfaceYCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "y-cone", false); - std::array coeffs {{x0, y0, z0, radius_sq}}; + std::array coeffs {{x0_, y0_, z0_, radius_sq_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -901,29 +901,29 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, x0, y0, z0, radius_sq); + read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); } double SurfaceZCone::evaluate(Position r) const { - return axis_aligned_cone_evaluate<2, 0, 1>(r, z0, x0, y0, radius_sq); + return axis_aligned_cone_evaluate<2, 0, 1>(r, z0_, x0_, y0_, radius_sq_); } double SurfaceZCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0, x0, y0, - radius_sq); + return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0_, x0_, y0_, + radius_sq_); } Direction SurfaceZCone::normal(Position r) const { - return axis_aligned_cone_normal<2, 0, 1>(r, z0, x0, y0, radius_sq); + return axis_aligned_cone_normal<2, 0, 1>(r, z0_, x0_, y0_, radius_sq_); } void SurfaceZCone::to_hdf5_inner(hid_t group_id) const { write_string(group_id, "type", "z-cone", false); - std::array coeffs {{x0, y0, z0, radius_sq}}; + std::array coeffs {{x0_, y0_, z0_, radius_sq_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -934,7 +934,7 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : Surface(surf_node) { - read_coeffs(surf_node, id, A, B, C, D, E, F, G, H, J, K); + read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_); } double @@ -943,9 +943,9 @@ SurfaceQuadric::evaluate(Position r) const const double x = r.x; const double y = r.y; const double z = r.z; - return x*(A*x + D*y + G) + - y*(B*y + E*z + H) + - z*(C*z + F*x + J) + K; + return x*(A_*x + D_*y + G_) + + y*(B_*y + E_*z + H_) + + z*(C_*z + F_*x + J_) + K_; } double @@ -958,11 +958,11 @@ SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const const double &v = ang.y; const double &w = ang.z; - const double a = A*u*u + B*v*v + C*w*w + D*u*v + E*v*w + F*u*w; - const double k = (A*u*x + B*v*y + C*w*z + 0.5*(D*(u*y + v*x) + - E*(v*z + w*y) + F*(w*x + u*z) + G*u + H*v + J*w)); - const double c = A*x*x + B*y*y + C*z*z + D*x*y + E*y*z + F*x*z + G*x + H*y - + J*z + K; + const double a = A_*u*u + B_*v*v + C_*w*w + D_*u*v + E_*v*w + F_*u*w; + const double k = A_*u*x + B_*v*y + C_*w*z + 0.5*(D_*(u*y + v*x) + + E_*(v*z + w*y) + F_*(w*x + u*z) + G_*u + H_*v + J_*w); + const double c = A_*x*x + B_*y*y + C_*z*z + D_*x*y + E_*y*z + F_*x*z + G_*x + + H_*y + J_*z + K_; double quad = k*k - a*c; double d; @@ -1008,15 +1008,15 @@ SurfaceQuadric::normal(Position r) const const double &x = r.x; const double &y = r.y; const double &z = r.z; - return {2.0*A*x + D*y + F*z + G, - 2.0*B*y + D*x + E*z + H, - 2.0*C*z + E*y + F*x + J}; + return {2.0*A_*x + D_*y + F_*z + G_, + 2.0*B_*y + D_*x + E_*z + H_, + 2.0*C_*z + E_*y + F_*x + J_}; } 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}}; + std::array coeffs {{A_, B_, C_, D_, E_, F_, G_, H_, J_, K_}}; write_dataset(group_id, "coefficients", coeffs); } @@ -1086,7 +1086,7 @@ read_surfaces(pugi::xml_node* node) // Fill the surface map. for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - int id = global_surfaces[i_surf]->id; + int id = global_surfaces[i_surf]->id_; auto in_map = surface_map.find(id); if (in_map == surface_map.end()) { surface_map[id] = i_surf; @@ -1102,7 +1102,7 @@ read_surfaces(pugi::xml_node* node) zmin {INFTY}, zmax {-INFTY}; int i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax; for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - if (global_surfaces[i_surf]->bc == BC_PERIODIC) { + if (global_surfaces[i_surf]->bc_ == BC_PERIODIC) { // Downcast to the PeriodicSurface type. Surface* surf_base = global_surfaces[i_surf]; PeriodicSurface* surf = dynamic_cast(surf_base); @@ -1111,7 +1111,7 @@ read_surfaces(pugi::xml_node* node) if (!surf) { std::stringstream err_msg; err_msg << "Periodic boundary condition not supported for surface " - << surf_base->id + << surf_base->id_ << ". Periodic BCs are only supported for planar surfaces."; fatal_error(err_msg); } @@ -1147,7 +1147,7 @@ read_surfaces(pugi::xml_node* node) // Set i_periodic for periodic BC surfaces. for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - if (global_surfaces[i_surf]->bc == BC_PERIODIC) { + if (global_surfaces[i_surf]->bc_ == BC_PERIODIC) { // Downcast to the PeriodicSurface type. Surface* surf_base = global_surfaces[i_surf]; PeriodicSurface* surf = dynamic_cast(surf_base); @@ -1158,48 +1158,48 @@ read_surfaces(pugi::xml_node* node) if (!surf_p) { // This is not a SurfacePlane. - if (surf->i_periodic == C_NONE) { + if (surf->i_periodic_ == C_NONE) { // The user did not specify the matching periodic surface. See if we // can find the partnered surface from the bounding box information. if (i_surf == i_xmin) { - surf->i_periodic = i_xmax; + surf->i_periodic_ = i_xmax; } else if (i_surf == i_xmax) { - surf->i_periodic = i_xmin; + surf->i_periodic_ = i_xmin; } else if (i_surf == i_ymin) { - surf->i_periodic = i_ymax; + surf->i_periodic_ = i_ymax; } else if (i_surf == i_ymax) { - surf->i_periodic = i_ymin; + surf->i_periodic_ = i_ymin; } else if (i_surf == i_zmin) { - surf->i_periodic = i_zmax; + surf->i_periodic_ = i_zmax; } else if (i_surf == i_zmax) { - surf->i_periodic = i_zmin; + surf->i_periodic_ = i_zmin; } else { fatal_error("Periodic boundary condition applied to interior " "surface"); } } else { // Convert the surface id to an index. - surf->i_periodic = surface_map[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 // user didn't specify one. - if (surf->i_periodic == C_NONE) { + if (surf->i_periodic_ == C_NONE) { std::stringstream err_msg; err_msg << "No matching periodic surface specified for periodic " - "boundary condition on surface " << surf->id; + "boundary condition on surface " << surf->id_; fatal_error(err_msg); } else { // Convert the surface id to an index. - surf->i_periodic = surface_map[surf->i_periodic]; + surf->i_periodic_ = surface_map[surf->i_periodic_]; } } // Make sure the opposite surface is also periodic. - if (global_surfaces[surf->i_periodic]->bc != BC_PERIODIC) { + if (global_surfaces[surf->i_periodic_]->bc_ != BC_PERIODIC) { std::stringstream err_msg; err_msg << "Could not find matching surface for periodic boundary " - "condition on surface " << surf->id; + "condition on surface " << surf->id_; fatal_error(err_msg); } } @@ -1213,9 +1213,9 @@ read_surfaces(pugi::xml_node* node) extern "C" { Surface* surface_pointer(int surf_ind) {return global_surfaces[surf_ind];} - int surface_id(Surface* surf) {return surf->id;} + int surface_id(Surface* surf) {return surf->id_;} - int surface_bc(Surface* surf) {return surf->bc;} + int surface_bc(Surface* surf) {return surf->bc_;} void surface_reflect(Surface* surf, double xyz[3], double uvw[3]) { @@ -1228,7 +1228,7 @@ extern "C" { uvw[2] = u.z; } - int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic;} + int surface_i_periodic(PeriodicSurface* surf) {return surf->i_periodic_;} bool surface_periodic(PeriodicSurface* surf, PeriodicSurface* other, double xyz[3], From 0e348e338b9b17f804c081fd5dd19cc5f2dda030 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 27 Aug 2018 19:06:01 -0400 Subject: [PATCH 37/76] Remove global_ prefix from global geometry vectors --- include/openmc/cell.h | 4 +- include/openmc/lattice.h | 2 +- include/openmc/material.h | 2 +- include/openmc/surface.h | 2 +- src/cell.cpp | 68 +++++++++++++-------------- src/geometry.cpp | 34 +++++++------- src/geometry_aux.cpp | 98 +++++++++++++++++++-------------------- src/lattice.cpp | 20 ++++---- src/material.cpp | 28 +++++------ src/output.cpp | 4 +- src/summary.cpp | 16 +++---- src/surface.cpp | 46 +++++++++--------- 12 files changed, 162 insertions(+), 162 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index fddfb1adb..fa5134b60 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -39,11 +39,11 @@ constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; extern "C" int32_t n_cells; class Cell; -extern std::vector global_cells; +extern std::vector cells; extern std::unordered_map cell_map; class Universe; -extern std::vector global_universes; +extern std::vector universes; extern std::unordered_map universe_map; //============================================================================== diff --git a/include/openmc/lattice.h b/include/openmc/lattice.h index 10f6b4617..cacb87abe 100644 --- a/include/openmc/lattice.h +++ b/include/openmc/lattice.h @@ -31,7 +31,7 @@ enum class LatticeType { //============================================================================== class Lattice; -extern std::vector lattices_c; +extern std::vector lattices; extern std::unordered_map lattice_map; diff --git a/include/openmc/material.h b/include/openmc/material.h index 9390ef598..1af6f8597 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -14,7 +14,7 @@ namespace openmc { //============================================================================== class Material; -extern std::vector global_materials; +extern std::vector materials; extern std::unordered_map material_map; //============================================================================== diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 16f75b907..23d5d1543 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -32,7 +32,7 @@ extern "C" const int BC_PERIODIC; extern "C" int32_t n_surfaces; class Surface; -extern std::vector global_surfaces; +extern std::vector surfaces; extern std::map surface_map; diff --git a/src/cell.cpp b/src/cell.cpp index c6b39f314..c0eaa3ebf 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -24,10 +24,10 @@ namespace openmc { int32_t n_cells {0}; -std::vector global_cells; +std::vector cells; std::unordered_map cell_map; -std::vector global_universes; +std::vector universes; std::unordered_map universe_map; //============================================================================== @@ -198,7 +198,7 @@ Universe::to_hdf5(hid_t universes_group) const // Write the contained cells. if (cells_.size() > 0) { std::vector cell_ids; - for (auto i_cell : cells_) cell_ids.push_back(global_cells[i_cell]->id_); + for (auto i_cell : cells_) cell_ids.push_back(cells[i_cell]->id_); write_dataset(group, "cells", cell_ids); } @@ -417,7 +417,7 @@ Cell::distance(Position r, Direction u, int32_t on_surface) const // Calculate the distance to this surface. // Note the off-by-one indexing bool coincident {token == on_surface}; - double d {global_surfaces[abs(token)-1]->distance(r, u, coincident)}; + double d {surfaces[abs(token)-1]->distance(r, u, coincident)}; // Check if this distance is the new minimum. if (d < min_dist) { @@ -445,7 +445,7 @@ Cell::to_hdf5(hid_t cells_group) const write_string(group, "name", name_, false); } - write_dataset(group, "universe", global_universes[universe_]->id_); + write_dataset(group, "universe", universes[universe_]->id_); // Write the region specification. if (!region_.empty()) { @@ -463,7 +463,7 @@ Cell::to_hdf5(hid_t cells_group) const } else { // Note the off-by-one indexing region_spec << " " - << copysign(global_surfaces[abs(token)-1]->id_, token); + << copysign(surfaces[abs(token)-1]->id_, token); } } write_string(group, "region", region_spec.str(), false); @@ -475,7 +475,7 @@ Cell::to_hdf5(hid_t cells_group) const std::vector mat_ids; for (auto i_mat : material_) { if (i_mat != MATERIAL_VOID) { - mat_ids.push_back(global_materials[i_mat]->id); + mat_ids.push_back(materials[i_mat]->id); } else { mat_ids.push_back(MATERIAL_VOID); } @@ -493,7 +493,7 @@ Cell::to_hdf5(hid_t cells_group) const } else if (type_ == FILL_UNIVERSE) { write_dataset(group, "fill_type", "universe"); - write_dataset(group, "fill", global_universes[fill_]->id_); + write_dataset(group, "fill", universes[fill_]->id_); if (translation_ != Position(0, 0, 0)) { write_dataset(group, "translation", translation_); } @@ -504,7 +504,7 @@ Cell::to_hdf5(hid_t cells_group) const } else if (type_ == FILL_LATTICE) { write_dataset(group, "fill_type", "lattice"); - write_dataset(group, "lattice", lattices_c[fill_]->id_); + write_dataset(group, "lattice", lattices[fill_]->id_); } close_group(group); @@ -526,7 +526,7 @@ Cell::contains_simple(Position r, Direction u, int32_t on_surface) const return false; } else { // Note the off-by-one indexing - bool sense = global_surfaces[abs(token)-1]->sense(r, u); + bool sense = surfaces[abs(token)-1]->sense(r, u); if (sense != (token > 0)) {return false;} } } @@ -568,7 +568,7 @@ Cell::contains_complex(Position r, Direction u, int32_t on_surface) const stack[i_stack] = false; } else { // Note the off-by-one indexing - bool sense = global_surfaces[abs(token)-1]->sense(r, u); + bool sense = surfaces[abs(token)-1]->sense(r, u); stack[i_stack] = (sense == (token > 0)); } } @@ -599,25 +599,25 @@ read_cells(pugi::xml_node* node) } // Loop over XML cell elements and populate the array. - global_cells.reserve(n_cells); + cells.reserve(n_cells); for (pugi::xml_node cell_node: node->children("cell")) { - global_cells.push_back(new Cell(cell_node)); + cells.push_back(new Cell(cell_node)); } // Populate the Universe vector and map. - for (int i = 0; i < global_cells.size(); i++) { - int32_t uid = global_cells[i]->universe_; + for (int i = 0; i < cells.size(); i++) { + int32_t uid = 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; + universes.push_back(new Universe()); + universes.back()->id_ = uid; + universes.back()->cells_.push_back(i); + universe_map[uid] = universes.size() - 1; } else { - global_universes[it->second]->cells_.push_back(i); + universes[it->second]->cells_.push_back(i); } } - global_universes.shrink_to_fit(); + universes.shrink_to_fit(); // Allocate the cell overlap count if necessary. if (openmc_check_overlaps) overlap_check_count.resize(n_cells, 0); @@ -630,9 +630,9 @@ read_cells(pugi::xml_node* node) extern "C" int openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) { - if (index >= 1 && index <= global_cells.size()) { + if (index >= 1 && index <= cells.size()) { //TODO: off-by-one - Cell& c {*global_cells[index - 1]}; + Cell& c {*cells[index - 1]}; *type = c.type_; if (c.type_ == FILL_MATERIAL) { *indices = c.material_.data(); @@ -652,9 +652,9 @@ extern "C" int openmc_cell_set_fill(int32_t index, int type, int32_t n, const int32_t* indices) { - if (index >= 1 && index <= global_cells.size()) { + if (index >= 1 && index <= cells.size()) { //TODO: off-by-one - Cell& c {*global_cells[index - 1]}; + Cell& c {*cells[index - 1]}; if (type == FILL_MATERIAL) { c.type_ = FILL_MATERIAL; c.material_.clear(); @@ -662,7 +662,7 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, int i_mat = indices[i]; if (i_mat == MATERIAL_VOID) { c.material_.push_back(MATERIAL_VOID); - } else if (i_mat >= 1 && i_mat <= global_materials.size()) { + } else if (i_mat >= 1 && i_mat <= materials.size()) { //TODO: off-by-one c.material_.push_back(i_mat - 1); } else { @@ -687,9 +687,9 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, extern "C" int openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance) { - if (index >= 1 && index <= global_cells.size()) { + if (index >= 1 && index <= cells.size()) { //TODO: off-by-one - Cell& c {*global_cells[index - 1]}; + Cell& c {*cells[index - 1]}; if (instance) { if (*instance >= 0 && *instance < c.sqrtkT_.size()) { @@ -717,7 +717,7 @@ openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance) //============================================================================== extern "C" { - Cell* cell_pointer(int32_t cell_ind) {return global_cells[cell_ind];} + Cell* cell_pointer(int32_t cell_ind) {return cells[cell_ind];} int32_t cell_id(Cell* c) {return c->id_;} @@ -751,17 +751,17 @@ extern "C" { void extend_cells_c(int32_t n) { - global_cells.reserve(global_cells.size() + n); + cells.reserve(cells.size() + n); for (int32_t i = 0; i < n; i++) { - global_cells.push_back(new Cell()); + cells.push_back(new Cell()); } - n_cells = global_cells.size(); + n_cells = cells.size(); } - int32_t universe_id(int i_univ) {return global_universes[i_univ]->id_;} + int32_t universe_id(int i_univ) {return universes[i_univ]->id_;} void universes_to_hdf5(hid_t universes_group) - {for (Universe* u : global_universes) u->to_hdf5(universes_group);} + {for (Universe* u : universes) u->to_hdf5(universes_group);} } diff --git a/src/geometry.cpp b/src/geometry.cpp index 1999738d5..22e3cbfe3 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -25,17 +25,17 @@ check_cell_overlap(Particle* p) { // Loop through each coordinate level for (int j = 0; j < n_coord; j++) { - Universe& univ = *global_universes[p->coord[j].universe]; + Universe& univ = *universes[p->coord[j].universe]; int n = univ.cells_.size(); // Loop through each cell on this level for (auto index_cell : univ.cells_) { - Cell& c = *global_cells[index_cell]; + Cell& c = *cells[index_cell]; if (c.contains(p->coord[j].xyz, p->coord[j].uvw, p->surface)) { if (index_cell != p->coord[j].cell) { std::stringstream err_msg; err_msg << "Overlapping cells detected: " << c.id_ << ", " - << global_cells[p->coord[j].cell]->id_ << " on universe " + << cells[p->coord[j].cell]->id_ << " on universe " << univ.id_; fatal_error(err_msg); } @@ -67,12 +67,12 @@ find_cell(Particle* p, int search_surf) { // the positive or negative side of the surface should be searched. const std::vector* search_cells; if (search_surf > 0) { - search_cells = &global_surfaces[search_surf-1]->neighbor_pos_; + search_cells = &surfaces[search_surf-1]->neighbor_pos_; } else if (search_surf < 0) { - search_cells = &global_surfaces[-search_surf-1]->neighbor_neg_; + search_cells = &surfaces[-search_surf-1]->neighbor_neg_; } else { // No surface was indicated, search all cells in the universe. - search_cells = &global_universes[i_universe]->cells_; + search_cells = &universes[i_universe]->cells_; } // Find which cell of this universe the particle is in. @@ -82,17 +82,17 @@ find_cell(Particle* p, int search_surf) { i_cell = (*search_cells)[i]; // Make sure the search cell is in the same universe. - if (global_cells[i_cell]->universe_ != i_universe) continue; + if (cells[i_cell]->universe_ != i_universe) continue; Position r {p->coord[p->n_coord-1].xyz}; Direction u {p->coord[p->n_coord-1].uvw}; int32_t surf = p->surface; - if (global_cells[i_cell]->contains(r, u, surf)) { + if (cells[i_cell]->contains(r, u, surf)) { p->coord[p->n_coord-1].cell = i_cell; if (openmc_verbosity >= 10 || openmc_trace) { std::stringstream msg; - msg << " Entering cell " << global_cells[i_cell]->id_; + msg << " Entering cell " << cells[i_cell]->id_; write_message(msg, 1); } found = true; @@ -101,7 +101,7 @@ find_cell(Particle* p, int search_surf) { } if (found) { - Cell& c {*global_cells[i_cell]}; + Cell& c {*cells[i_cell]}; if (c.type_ == FILL_MATERIAL) { //======================================================================= //! Found a material cell which means this is the lowest coord level. @@ -112,11 +112,11 @@ find_cell(Particle* p, int search_surf) { int distribcell_index = c.distribcell_index_ - 1; int offset = 0; for (int i = 0; i < p->n_coord; i++) { - Cell& c_i {*global_cells[p->coord[i].cell]}; + Cell& c_i {*cells[p->coord[i].cell]}; if (c_i.type_ == FILL_UNIVERSE) { offset += c_i.offset_[distribcell_index]; } else if (c_i.type_ == FILL_LATTICE) { - Lattice& lat {*lattices_c[p->coord[i+1].lattice-1]}; + Lattice& lat {*lattices[p->coord[i+1].lattice-1]}; int i_xyz[3] {p->coord[i+1].lattice_x, p->coord[i+1].lattice_y, p->coord[i+1].lattice_z}; @@ -201,7 +201,7 @@ find_cell(Particle* p, int search_surf) { //======================================================================== //! Found a lower lattice, update this coord level then search the next. - Lattice& lat {*lattices_c[c.fill_]}; + Lattice& lat {*lattices[c.fill_]}; // Determine lattice indices. Position r {p->coord[p->n_coord-1].xyz}; @@ -252,7 +252,7 @@ find_cell(Particle* p, int search_surf) { extern "C" void cross_lattice(Particle* p, int lattice_translation[3]) { - Lattice& lat {*lattices_c[p->coord[p->n_coord-1].lattice-1]}; + Lattice& lat {*lattices[p->coord[p->n_coord-1].lattice-1]}; if (openmc_verbosity >= 10 || openmc_trace) { std::stringstream msg; @@ -327,7 +327,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, for (int i = 0; i < p->n_coord; i++) { Position r {p->coord[i].xyz}; Direction u {p->coord[i].uvw}; - Cell& c {*global_cells[p->coord[i].cell]}; + Cell& c {*cells[p->coord[i].cell]}; // Find the oncoming surface in this cell and the distance to it. auto surface_distance = c.distance(r, u, p->surface); @@ -336,7 +336,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, // Find the distance to the next lattice tile crossing. if (p->coord[i].lattice != F90_NONE) { - Lattice& lat {*lattices_c[p->coord[i].lattice-1]}; + Lattice& lat {*lattices[p->coord[i].lattice-1]}; std::array i_xyz {p->coord[i].lattice_x, p->coord[i].lattice_y, p->coord[i].lattice_z}; //TODO: refactor so both lattice use the same position argument (which @@ -378,7 +378,7 @@ distance_to_boundary(Particle* p, double* dist, int* surface_crossed, *surface_crossed = level_surf_cross; } else { Position r_hit = r + d_surf * u; - Surface& surf {*global_surfaces[std::abs(level_surf_cross)-1]}; + Surface& surf {*surfaces[std::abs(level_surf_cross)-1]}; Direction norm = surf.normal(r_hit); if (u.dot(norm) > 0) { *surface_crossed = std::abs(level_surf_cross); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 768b2dd4e..9c1d17b4d 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -22,7 +22,7 @@ void adjust_indices() { // Adjust material/fill idices. - for (Cell* c : global_cells) { + for (Cell* c : cells) { if (c->fill_ != C_NONE) { int32_t id = c->fill_; auto search_univ = universe_map.find(id); @@ -59,7 +59,7 @@ adjust_indices() } // Change cell.universe values from IDs to indices. - for (Cell* c : global_cells) { + for (Cell* c : cells) { auto search = universe_map.find(c->universe_); if (search != universe_map.end()) { c->universe_ = search->second; @@ -72,7 +72,7 @@ adjust_indices() } // Change all lattice universe values from IDs to indices. - for (Lattice* l : lattices_c) { + for (Lattice* l : lattices) { l->adjust_indices(); } } @@ -82,7 +82,7 @@ adjust_indices() void assign_temperatures() { - for (Cell* c : global_cells) { + for (Cell* c : cells) { // Ignore non-material cells and cells with defined temperature. if (c->material_.size() == 0) continue; if (c->sqrtkT_.size() > 0) continue; @@ -94,9 +94,9 @@ assign_temperatures() c->sqrtkT_.push_back(0); } else { - if (global_materials[i_mat]->temperature_ >= 0) { + if (materials[i_mat]->temperature_ >= 0) { // This material has a default temperature; use that value. - auto T = global_materials[i_mat]->temperature_; + auto T = materials[i_mat]->temperature_; c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * T)); } else { // Use the global default temperature. @@ -114,12 +114,12 @@ find_root_universe() { // Find all the universes listed as a cell fill. std::unordered_set fill_univ_ids; - for (Cell* c : global_cells) { + for (Cell* c : cells) { fill_univ_ids.insert(c->fill_); } // Find all the universes contained in a lattice. - for (Lattice* lat : lattices_c) { + for (Lattice* lat : lattices) { for (auto it = lat->begin(); it != lat->end(); ++it) { fill_univ_ids.insert(*it); } @@ -131,8 +131,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 < global_universes.size(); i++) { - auto search = fill_univ_ids.find(global_universes[i]->id_); + for (int32_t i = 0; i < universes.size(); i++) { + auto search = fill_univ_ids.find(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 " @@ -157,21 +157,21 @@ neighbor_lists() { write_message("Building neighboring cells lists for each surface...", 6); - for (int i = 0; i < global_cells.size(); i++) { - for (auto token : global_cells[i]->region_) { + for (int i = 0; i < cells.size(); i++) { + for (auto token : cells[i]->region_) { // Skip operator tokens. if (std::abs(token) >= OP_UNION) continue; // This token is a surface index. Add the cell to the surface's list. if (token > 0) { - global_surfaces[std::abs(token)-1]->neighbor_pos_.push_back(i); + surfaces[std::abs(token)-1]->neighbor_pos_.push_back(i); } else { - global_surfaces[std::abs(token)-1]->neighbor_neg_.push_back(i); + surfaces[std::abs(token)-1]->neighbor_neg_.push_back(i); } } } - for (Surface* surf : global_surfaces) { + for (Surface* surf : surfaces) { surf->neighbor_pos_.shrink_to_fit(); surf->neighbor_neg_.shrink_to_fit(); } @@ -190,8 +190,8 @@ prepare_distribcell(int32_t* filter_cell_list, int n) // Find all cells with distributed materials or temperatures. Make sure that // the number of materials/temperatures matches the number of cell instances. - for (int i = 0; i < global_cells.size(); i++) { - Cell& c {*global_cells[i]}; + for (int i = 0; i < cells.size(); i++) { + Cell& c {*cells[i]}; if (c.material_.size() > 1) { if (c.material_.size() != c.n_instances_) { @@ -223,10 +223,10 @@ prepare_distribcell(int32_t* filter_cell_list, int n) //TODO: off-by-one int distribcell_index = 1; std::vector target_univ_ids; - for (Universe* u : global_universes) { + for (Universe* u : universes) { for (auto cell_indx : u->cells_) { if (distribcells.find(cell_indx) != distribcells.end()) { - global_cells[cell_indx]->distribcell_index_ = distribcell_index; + cells[cell_indx]->distribcell_index_ = distribcell_index; target_univ_ids.push_back(u->id_); ++distribcell_index; } @@ -235,22 +235,22 @@ prepare_distribcell(int32_t* filter_cell_list, int n) // Allocate the cell and lattice offset tables. int n_maps = target_univ_ids.size(); - for (Cell* c : global_cells) { + for (Cell* c : cells) { if (c->type_ != FILL_MATERIAL) { c->offset_.resize(n_maps, C_NONE); } } - for (Lattice* lat : lattices_c) { + for (Lattice* lat : lattices) { lat->allocate_offset_table(n_maps); } // Fill the cell and lattice offset tables. for (int map = 0; map < target_univ_ids.size(); map++) { auto target_univ_id = target_univ_ids[map]; - for (Universe* univ : global_universes) { + for (Universe* univ : universes) { int32_t offset {0}; // TODO: is this a bug? It matches F90 implementation. for (int32_t cell_indx : univ->cells_) { - Cell& c = *global_cells[cell_indx]; + Cell& c = *cells[cell_indx]; if (c.type_ == FILL_UNIVERSE) { c.offset_[map] = offset; @@ -258,7 +258,7 @@ prepare_distribcell(int32_t* filter_cell_list, int n) offset += count_universe_instances(search_univ, target_univ_id); } else if (c.type_ == FILL_LATTICE) { - Lattice& lat = *lattices_c[c.fill_]; + Lattice& lat = *lattices[c.fill_]; offset = lat.fill_offset_table(offset, target_univ_id, map); } } @@ -271,8 +271,8 @@ prepare_distribcell(int32_t* filter_cell_list, int n) void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : global_universes[univ_indx]->cells_) { - Cell& c = *global_cells[cell_indx]; + for (int32_t cell_indx : universes[univ_indx]->cells_) { + Cell& c = *cells[cell_indx]; ++c.n_instances_; if (c.type_ == FILL_UNIVERSE) { @@ -281,7 +281,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_]; + Lattice& lat = *lattices[c.fill_]; for (auto it = lat.begin(); it != lat.end(); ++it) { count_cell_instances(*it); } @@ -295,20 +295,20 @@ int count_universe_instances(int32_t search_univ, int32_t target_univ_id) { // If this is the target, it can't contain itself. - if (global_universes[search_univ]->id_ == target_univ_id) { + if (universes[search_univ]->id_ == target_univ_id) { return 1; } int count {0}; - for (int32_t cell_indx : global_universes[search_univ]->cells_) { - Cell& c = *global_cells[cell_indx]; + for (int32_t cell_indx : universes[search_univ]->cells_) { + Cell& c = *cells[cell_indx]; if (c.type_ == FILL_UNIVERSE) { 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_]; + Lattice& lat = *lattices[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); @@ -333,7 +333,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 = *global_cells[cell_indx]; + Cell& c = *cells[cell_indx]; path << "c" << c.id_; return path.str(); } @@ -345,7 +345,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 = *global_cells[*cell_it]; + Cell& c = *cells[*cell_it]; // Material cells don't contain other cells so ignore them. if (c.type_ != FILL_MATERIAL) { @@ -353,7 +353,7 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, if (c.type_ == FILL_UNIVERSE) { temp_offset = offset + c.offset_[map]; } else { - Lattice& lat = *lattices_c[c.fill_]; + Lattice& lat = *lattices[c.fill_]; int32_t indx = lat.universes_.size()*map + lat.begin().indx_; temp_offset = offset + lat.offsets_[indx]; } @@ -365,18 +365,18 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, } // Add the cell to the path string. - Cell& c = *global_cells[*cell_it]; + Cell& c = *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, - *global_universes[c.fill_], offset); + *universes[c.fill_], offset); return path.str(); } else { // Recurse into the lattice cell. - Lattice& lat = *lattices_c[c.fill_]; + Lattice& lat = *lattices[c.fill_]; path << "l" << lat.id_; for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) { int32_t indx = lat.universes_.size()*map + it.indx_; @@ -385,7 +385,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, - *global_universes[*it], offset); + *universes[*it], offset); return path.str(); } } @@ -398,7 +398,7 @@ int distribcell_path_len(int32_t target_cell, int32_t map, int32_t target_offset, int32_t root_univ) { - Universe& root = *global_universes[root_univ]; + Universe& root = *universes[root_univ]; std::string path_ {distribcell_path_inner(target_cell, map, target_offset, root, 0)}; return path_.size() + 1; @@ -410,7 +410,7 @@ void distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset, int32_t root_univ, char* path) { - Universe& root = *global_universes[root_univ]; + Universe& root = *universes[root_univ]; std::string path_ {distribcell_path_inner(target_cell, map, target_offset, root, 0)}; path_.copy(path, path_.size()); @@ -424,13 +424,13 @@ maximum_levels(int32_t univ) { int levels_below {0}; - for (int32_t cell_indx : global_universes[univ]->cells_) { - Cell& c = *global_cells[cell_indx]; + for (int32_t cell_indx : universes[univ]->cells_) { + Cell& c = *cells[cell_indx]; if (c.type_ == FILL_UNIVERSE) { 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_]; + Lattice& lat = *lattices[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)); @@ -447,17 +447,17 @@ maximum_levels(int32_t univ) void free_memory_geometry_c() { - for (Cell* c : global_cells) {delete c;} - global_cells.clear(); + for (Cell* c : cells) {delete c;} + cells.clear(); cell_map.clear(); n_cells = 0; - for (Universe* u : global_universes) {delete u;} - global_universes.clear(); + for (Universe* u : universes) {delete u;} + universes.clear(); universe_map.clear(); - for (Lattice* lat : lattices_c) {delete lat;} - lattices_c.clear(); + for (Lattice* lat : lattices) {delete lat;} + lattices.clear(); lattice_map.clear(); overlap_check_count.clear(); diff --git a/src/lattice.cpp b/src/lattice.cpp index 0975082eb..21f476850 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -18,7 +18,7 @@ namespace openmc { // Global variables //============================================================================== -std::vector lattices_c; +std::vector lattices; std::unordered_map lattice_map; @@ -118,7 +118,7 @@ Lattice::to_hdf5(hid_t lattices_group) const } if (outer_ != NO_OUTER_UNIVERSE) { - int32_t outer_id = global_universes[outer_]->id_; + int32_t outer_id = universes[outer_]->id_; write_dataset(lat_group, "outer", outer_id); } else { write_dataset(lat_group, "outer", outer_); @@ -370,7 +370,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] = global_universes[universes_[indx1]]->id_; + out[indx2] = universes[universes_[indx1]]->id_; } } } @@ -387,7 +387,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] = global_universes[universes_[indx1]]->id_; + out[indx2] = universes[universes_[indx1]]->id_; } } @@ -847,7 +847,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] = global_universes[universes_[indx]]->id_; + out[indx] = universes[universes_[indx]]->id_; } } } @@ -865,15 +865,15 @@ 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)); + lattices.push_back(new RectLattice(lat_node)); } for (pugi::xml_node lat_node : node->children("hex_lattice")) { - lattices_c.push_back(new HexLattice(lat_node)); + lattices.push_back(new HexLattice(lat_node)); } // Fill the lattice map. - for (int i_lat = 0; i_lat < lattices_c.size(); i_lat++) { - int id = lattices_c[i_lat]->id_; + for (int i_lat = 0; i_lat < lattices.size(); i_lat++) { + int id = lattices[i_lat]->id_; auto in_map = lattice_map.find(id); if (in_map == lattice_map.end()) { lattice_map[id] = i_lat; @@ -890,7 +890,7 @@ read_lattices(pugi::xml_node *node) //============================================================================== extern "C" { - Lattice* lattice_pointer(int lat_ind) {return lattices_c[lat_ind];} + Lattice* lattice_pointer(int lat_ind) {return lattices[lat_ind];} int32_t lattice_id(Lattice *lat) {return lat->id_;} diff --git a/src/material.cpp b/src/material.cpp index 8a74299c4..1a0c2d207 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -13,7 +13,7 @@ namespace openmc { // Global variables //============================================================================== -std::vector global_materials; +std::vector materials; std::unordered_map material_map; //============================================================================== @@ -46,13 +46,13 @@ read_materials(pugi::xml_node* node) { // Loop over XML material elements and populate the array. for (pugi::xml_node material_node : node->children("material")) { - global_materials.push_back(new Material(material_node)); + materials.push_back(new Material(material_node)); } - global_materials.shrink_to_fit(); + materials.shrink_to_fit(); // Populate the material map. - for (int i = 0; i < global_materials.size(); i++) { - int32_t mid = global_materials[i]->id; + for (int i = 0; i < materials.size(); i++) { + int32_t mid = materials[i]->id; auto search = material_map.find(mid); if (search == material_map.end()) { material_map[mid] = i; @@ -71,8 +71,8 @@ read_materials(pugi::xml_node* node) extern "C" int openmc_material_get_volume(int32_t index, double* volume) { - if (index >= 1 && index <= global_materials.size()) { - Material* m = global_materials[index - 1]; + if (index >= 1 && index <= materials.size()) { + Material* m = materials[index - 1]; if (m->volume_ >= 0.0) { *volume = m->volume_; return 0; @@ -91,8 +91,8 @@ openmc_material_get_volume(int32_t index, double* volume) extern "C" int openmc_material_set_volume(int32_t index, double volume) { - if (index >= 1 && index <= global_materials.size()) { - Material* m = global_materials[index - 1]; + if (index >= 1 && index <= materials.size()) { + Material* m = materials[index - 1]; if (volume >= 0.0) { m->volume_ = volume; return 0; @@ -111,7 +111,7 @@ openmc_material_set_volume(int32_t index, double volume) //============================================================================== extern "C" { - Material* material_pointer(int32_t indx) {return global_materials[indx];} + Material* material_pointer(int32_t indx) {return materials[indx];} int32_t material_id(Material* mat) {return mat->id;} @@ -124,16 +124,16 @@ extern "C" { void extend_materials_c(int32_t n) { - global_materials.reserve(global_materials.size() + n); + materials.reserve(materials.size() + n); for (int32_t i = 0; i < n; i++) { - global_materials.push_back(new Material()); + materials.push_back(new Material()); } } void free_memory_material_c() { - for (Material *mat : global_materials) {delete mat;} - global_materials.clear(); + for (Material *mat : materials) {delete mat;} + materials.clear(); material_map.clear(); } } diff --git a/src/output.cpp b/src/output.cpp index 2d7b76753..7964a33c8 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -56,10 +56,10 @@ print_overlap_check() { std::vector sparse_cell_ids; for (int i = 0; i < n_cells; i++) { - std::cout << " " << std::setw(8) << global_cells[i]->id_ << std::setw(17) + std::cout << " " << std::setw(8) << cells[i]->id_ << std::setw(17) << overlap_check_count[i] << "\n"; if (overlap_check_count[i] < 10) { - sparse_cell_ids.push_back(global_cells[i]->id_); + sparse_cell_ids.push_back(cells[i]->id_); } } diff --git a/src/summary.cpp b/src/summary.cpp index a14d6c441..d103e78b9 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -9,25 +9,25 @@ namespace openmc { extern "C" void write_geometry(hid_t file_id) { auto geom_group = create_group(file_id, "geometry"); - write_attribute(geom_group, "n_cells", global_cells.size()); - write_attribute(geom_group, "n_surfaces", global_surfaces.size()); - write_attribute(geom_group, "n_universes", global_universes.size()); - write_attribute(geom_group, "n_lattices", lattices_c.size()); + write_attribute(geom_group, "n_cells", cells.size()); + write_attribute(geom_group, "n_surfaces", surfaces.size()); + write_attribute(geom_group, "n_universes", universes.size()); + write_attribute(geom_group, "n_lattices", lattices.size()); auto cells_group = create_group(geom_group, "cells"); - for (Cell* c : global_cells) c->to_hdf5(cells_group); + for (Cell* c : cells) c->to_hdf5(cells_group); close_group(cells_group); auto surfaces_group = create_group(geom_group, "surfaces"); - for (Surface* surf : global_surfaces) surf->to_hdf5(surfaces_group); + for (Surface* surf : surfaces) surf->to_hdf5(surfaces_group); close_group(surfaces_group); auto universes_group = create_group(geom_group, "universes"); - for (Universe* u : global_universes) u->to_hdf5(universes_group); + for (Universe* u : universes) u->to_hdf5(universes_group); close_group(universes_group); auto lattices_group = create_group(geom_group, "lattices"); - for (Lattice* lat : lattices_c) lat->to_hdf5(lattices_group); + for (Lattice* lat : lattices) lat->to_hdf5(lattices_group); close_group(lattices_group); close_group(geom_group); diff --git a/src/surface.cpp b/src/surface.cpp index 54ff511dc..d7f523ed6 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -27,7 +27,7 @@ extern "C" const int BC_PERIODIC {3}; int32_t n_surfaces; -std::vector global_surfaces; +std::vector surfaces; std::map surface_map; @@ -1032,7 +1032,7 @@ read_surfaces(pugi::xml_node* node) } // Loop over XML surface elements and populate the array. - global_surfaces.reserve(n_surfaces); + surfaces.reserve(n_surfaces); { pugi::xml_node surf_node; int i_surf; @@ -1041,40 +1041,40 @@ read_surfaces(pugi::xml_node* node) std::string surf_type = get_node_value(surf_node, "type", true, true); if (surf_type == "x-plane") { - global_surfaces.push_back(new SurfaceXPlane(surf_node)); + surfaces.push_back(new SurfaceXPlane(surf_node)); } else if (surf_type == "y-plane") { - global_surfaces.push_back(new SurfaceYPlane(surf_node)); + surfaces.push_back(new SurfaceYPlane(surf_node)); } else if (surf_type == "z-plane") { - global_surfaces.push_back(new SurfaceZPlane(surf_node)); + surfaces.push_back(new SurfaceZPlane(surf_node)); } else if (surf_type == "plane") { - global_surfaces.push_back(new SurfacePlane(surf_node)); + surfaces.push_back(new SurfacePlane(surf_node)); } else if (surf_type == "x-cylinder") { - global_surfaces.push_back(new SurfaceXCylinder(surf_node)); + surfaces.push_back(new SurfaceXCylinder(surf_node)); } else if (surf_type == "y-cylinder") { - global_surfaces.push_back(new SurfaceYCylinder(surf_node)); + surfaces.push_back(new SurfaceYCylinder(surf_node)); } else if (surf_type == "z-cylinder") { - global_surfaces.push_back(new SurfaceZCylinder(surf_node)); + surfaces.push_back(new SurfaceZCylinder(surf_node)); } else if (surf_type == "sphere") { - global_surfaces.push_back(new SurfaceSphere(surf_node)); + surfaces.push_back(new SurfaceSphere(surf_node)); } else if (surf_type == "x-cone") { - global_surfaces.push_back(new SurfaceXCone(surf_node)); + surfaces.push_back(new SurfaceXCone(surf_node)); } else if (surf_type == "y-cone") { - global_surfaces.push_back(new SurfaceYCone(surf_node)); + surfaces.push_back(new SurfaceYCone(surf_node)); } else if (surf_type == "z-cone") { - global_surfaces.push_back(new SurfaceZCone(surf_node)); + surfaces.push_back(new SurfaceZCone(surf_node)); } else if (surf_type == "quadric") { - global_surfaces.push_back(new SurfaceQuadric(surf_node)); + surfaces.push_back(new SurfaceQuadric(surf_node)); } else { std::stringstream err_msg; @@ -1086,7 +1086,7 @@ read_surfaces(pugi::xml_node* node) // Fill the surface map. for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - int id = global_surfaces[i_surf]->id_; + int id = surfaces[i_surf]->id_; auto in_map = surface_map.find(id); if (in_map == surface_map.end()) { surface_map[id] = i_surf; @@ -1102,9 +1102,9 @@ read_surfaces(pugi::xml_node* node) zmin {INFTY}, zmax {-INFTY}; int i_xmin, i_xmax, i_ymin, i_ymax, i_zmin, i_zmax; for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - if (global_surfaces[i_surf]->bc_ == BC_PERIODIC) { + if (surfaces[i_surf]->bc_ == BC_PERIODIC) { // Downcast to the PeriodicSurface type. - Surface* surf_base = global_surfaces[i_surf]; + Surface* surf_base = surfaces[i_surf]; PeriodicSurface* surf = dynamic_cast(surf_base); // Make sure this surface inherits from PeriodicSurface. @@ -1147,9 +1147,9 @@ read_surfaces(pugi::xml_node* node) // Set i_periodic for periodic BC surfaces. for (int i_surf = 0; i_surf < n_surfaces; i_surf++) { - if (global_surfaces[i_surf]->bc_ == BC_PERIODIC) { + if (surfaces[i_surf]->bc_ == BC_PERIODIC) { // Downcast to the PeriodicSurface type. - Surface* surf_base = global_surfaces[i_surf]; + Surface* surf_base = surfaces[i_surf]; PeriodicSurface* surf = dynamic_cast(surf_base); // Also try downcasting to the SurfacePlane type (which must be handled @@ -1196,7 +1196,7 @@ read_surfaces(pugi::xml_node* node) } // Make sure the opposite surface is also periodic. - if (global_surfaces[surf->i_periodic_]->bc_ != BC_PERIODIC) { + if (surfaces[surf->i_periodic_]->bc_ != BC_PERIODIC) { std::stringstream err_msg; err_msg << "Could not find matching surface for periodic boundary " "condition on surface " << surf->id_; @@ -1211,7 +1211,7 @@ read_surfaces(pugi::xml_node* node) //============================================================================== extern "C" { - Surface* surface_pointer(int surf_ind) {return global_surfaces[surf_ind];} + Surface* surface_pointer(int surf_ind) {return surfaces[surf_ind];} int surface_id(Surface* surf) {return surf->id_;} @@ -1251,8 +1251,8 @@ extern "C" { void free_memory_surfaces_c() { - for (Surface* surf : global_surfaces) {delete surf;} - global_surfaces.clear(); + for (Surface* surf : surfaces) {delete surf;} + surfaces.clear(); n_surfaces = 0; surface_map.clear(); } From fe24b640af82244b5af8c37e0cc093386dc65859 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 27 Aug 2018 19:31:42 -0400 Subject: [PATCH 38/76] Use 0-based indexing for distribcell --- src/geometry.cpp | 14 ++++++-------- src/geometry_aux.cpp | 3 +-- src/tallies/tally_filter_distribcell.F90 | 8 ++++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/geometry.cpp b/src/geometry.cpp index 22e3cbfe3..2c83e3836 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -108,33 +108,31 @@ find_cell(Particle* p, int search_surf) { // Find the distribcell instance number. if (c.material_.size() > 1 || c.sqrtkT_.size() > 1) { - //TODO: off-by-one indexing - int distribcell_index = c.distribcell_index_ - 1; int offset = 0; for (int i = 0; i < p->n_coord; i++) { Cell& c_i {*cells[p->coord[i].cell]}; if (c_i.type_ == FILL_UNIVERSE) { - offset += c_i.offset_[distribcell_index]; + offset += c_i.offset_[c.distribcell_index_]; } else if (c_i.type_ == FILL_LATTICE) { Lattice& lat {*lattices[p->coord[i+1].lattice-1]}; int i_xyz[3] {p->coord[i+1].lattice_x, p->coord[i+1].lattice_y, p->coord[i+1].lattice_z}; if (lat.are_valid_indices(i_xyz)) { - offset += lat.offset(distribcell_index, i_xyz); + offset += lat.offset(c.distribcell_index_, i_xyz); } } } - p->cell_instance = offset + 1; + p->cell_instance = offset; } else { - p->cell_instance = 1; + p->cell_instance = 0; } // Set the material and temperature. p->last_material = p->material; int32_t mat; if (c.material_.size() > 1) { - mat = c.material_[p->cell_instance-1]; + mat = c.material_[p->cell_instance]; } else { mat = c.material_[0]; } @@ -145,7 +143,7 @@ find_cell(Particle* p, int search_surf) { } p->last_sqrtkT = p->sqrtkT; if (c.sqrtkT_.size() > 1) { - p->sqrtkT = c.sqrtkT_[p->cell_instance-1]; + p->sqrtkT = c.sqrtkT_[p->cell_instance]; } else { p->sqrtkT = c.sqrtkT_[0]; } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 9c1d17b4d..a30479012 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -220,8 +220,7 @@ prepare_distribcell(int32_t* filter_cell_list, int n) // Search through universes for distributed cells and assign each one a // unique distribcell array index. - //TODO: off-by-one - int distribcell_index = 1; + int distribcell_index = 0; std::vector target_univ_ids; for (Universe* u : universes) { for (auto cell_indx : u->cells_) { diff --git a/src/tallies/tally_filter_distribcell.F90 b/src/tallies/tally_filter_distribcell.F90 index ae4e09023..f35ffc3ec 100644 --- a/src/tallies/tally_filter_distribcell.F90 +++ b/src/tallies/tally_filter_distribcell.F90 @@ -59,14 +59,14 @@ contains do i = 1, p % n_coord if (cells(p % coord(i) % cell + 1) % type() == FILL_UNIVERSE) then offset = offset + cells(p % coord(i) % cell + 1) & - % offset(distribcell_index-1) + % offset(distribcell_index) elseif (cells(p % coord(i) % cell + 1) % type() == FILL_LATTICE) then if (lattices(p % coord(i + 1) % lattice) % 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) & - % offset(distribcell_index - 1, & + % offset(distribcell_index, & [p % coord(i + 1) % lattice_x, & p % coord(i + 1) % lattice_y, & p % coord(i + 1) % lattice_z]) @@ -155,10 +155,10 @@ contains ! Get the distribcell index for this cell map = cells(i_cell) % distribcell_index() - path_len = distribcell_path_len(i_cell-1, map-1, target_offset, & + path_len = distribcell_path_len(i_cell-1, map, target_offset, & root_universe) allocate(path_c(path_len)) - call distribcell_path(i_cell-1, map-1, target_offset, root_universe, & + call distribcell_path(i_cell-1, map, target_offset, root_universe, & path_c) do i = 1, min(path_len, MAX_LINE_LEN) if (path_c(i) == C_NULL_CHAR) exit From 1de49c76e0250d32bf1ea349eab67b330f232e8e Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 27 Aug 2018 20:09:48 -0400 Subject: [PATCH 39/76] Fix distribcell index bug --- src/api.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api.F90 b/src/api.F90 index f089555bc..0fa537e52 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -207,7 +207,7 @@ contains if (found) then index = p % coord(p % n_coord) % cell + 1 - instance = p % cell_instance - 1 + instance = p % cell_instance err = 0 else err = E_GEOMETRY From 8b55751d51bb90abd09aab02c6f37b990697b759 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 31 Aug 2018 12:21:00 -0500 Subject: [PATCH 40/76] Make sure find_cell returns false when no cell is found --- src/geometry.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/geometry.cpp b/src/geometry.cpp index 2c83e3836..66441f029 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -243,6 +243,8 @@ find_cell(Particle* p, int search_surf) { return find_cell(p, 0); } } + + return found; } //============================================================================== From 4e92988433229aab4324510d78f9ce28ed954546 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 31 Aug 2018 18:18:01 -0400 Subject: [PATCH 41/76] Saving state --- include/openmc/constants.h | 5 - include/openmc/hdf5_interface.h | 27 +- include/openmc/mgxs.h | 26 +- include/openmc/scattdata.h | 52 +-- include/openmc/xsdata.h | 24 +- src/hdf5_interface.cpp | 192 ++++++++-- src/mgxs.cpp | 172 ++++----- src/scattdata.cpp | 137 +++---- src/xsdata.cpp | 359 ++++++++---------- .../mgxs_library_ce_to_mg/test.py | 9 +- 10 files changed, 536 insertions(+), 467 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 12dc21b71..0b66f355c 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -16,11 +16,6 @@ typedef std::vector double_1dvec; typedef std::vector > double_2dvec; typedef std::vector > > double_3dvec; typedef std::vector > > > double_4dvec; -typedef std::vector > > > > double_5dvec; -typedef std::vector > > > > > double_6dvec; -typedef std::vector int_1dvec; -typedef std::vector > int_2dvec; -typedef std::vector > > int_3dvec; // ============================================================================ // VERSIONING NUMBERS diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 48ce41d0e..74f5ae581 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -46,37 +46,36 @@ hid_t file_open(const std::string& filename, char mode, bool parallel=false); void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have = false); + void read_nd_vector(hid_t obj_id, const char* name, std::vector& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); std::vector attribute_shape(hid_t obj_id, const char* name); diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 40746c291..e80355bee 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -7,6 +7,8 @@ #include #include +#include "xtensor/xtensor.hpp" + #include "openmc/constants.h" #include "openmc/hdf5_interface.h" #include "openmc/xsdata.h" @@ -35,7 +37,7 @@ struct CacheData { class Mgxs { private: - double_1dvec kTs; // temperature in eV (k * T) + xt::xtensor kTs; // temperature in eV (k * T) int scatter_format; // flag for if this is legendre, histogram, or tabular int num_delayed_groups; // number of delayed neutron groups int num_groups; // number of energy groups @@ -44,8 +46,8 @@ class Mgxs { bool is_isotropic; // used to skip search for angle indices if isotropic int n_pol; int n_azi; - double_1dvec polar; - double_1dvec azimuthal; + std::vector polar; + std::vector azimuthal; //! \brief Initializes the Mgxs object metadata //! @@ -62,10 +64,10 @@ class Mgxs { //! @param in_polar Polar angle grid. //! @param in_azimuthal Azimuthal angle grid. void - init(const std::string& in_name, double in_awr, const double_1dvec& in_kTs, + init(const std::string& in_name, double in_awr, const std::vector& in_kTs, bool in_fissionable, int in_scatter_format, int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal); + const std::vector& in_polar, const std::vector& in_azimuthal); //! \brief Initializes the Mgxs object metadata from the HDF5 file //! @@ -80,8 +82,8 @@ class Mgxs { //! @param method Method of choosing nearest temperatures. void metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, const double_1dvec& temperature, - double tolerance, int_1dvec& temps_to_read, int& order_dim, + int in_num_delayed_groups, const std::vector& temperature, + double tolerance, std::vector& temps_to_read, int& order_dim, int& method); //! \brief Performs the actual act of combining the microscopic data for a @@ -93,8 +95,8 @@ class Mgxs { //! corresponds to the temperature of interest. //! @param this_t The temperature index of the macroscopic object. void - combine(const std::vector& micros, const double_1dvec& scalars, - const int_1dvec& micro_ts, int this_t); + combine(const std::vector& micros, const std::vector& scalars, + const std::vector& micro_ts, int this_t); //! \brief Checks to see if this and that are able to be combined //! @@ -128,7 +130,7 @@ class Mgxs { //! provides the number of points to use in the tabular representation. //! @param method Method of choosing nearest temperatures. Mgxs(hid_t xs_id, int energy_groups, - int delayed_groups, const double_1dvec& temperature, double tolerance, + int delayed_groups, const std::vector& temperature, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, int& method); @@ -141,8 +143,8 @@ class Mgxs { //! @param atom_densities Atom densities of those microscopic quantities. //! @param tolerance Tolerance of temperature selection method. //! @param method Method of choosing nearest temperatures. - Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, - const std::vector& micros, const double_1dvec& atom_densities, + Mgxs(const std::string& in_name, const std::vector& mat_kTs, + const std::vector& micros, const std::vector& atom_densities, double tolerance, int& method); //! \brief Provides a cross section value given certain parameters diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index 980238aeb..7e73224b9 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -6,6 +6,8 @@ #include +#include "xtensor/xtensor.hpp" + #include "openmc/constants.h" namespace openmc { @@ -25,23 +27,25 @@ class ScattData { protected: //! \brief Initializes the attributes of the base class. void - base_init(int order, const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_energy, const double_2dvec& in_mult); + base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, + const double_2dvec& in_mult); //! \brief Combines microscopic ScattDatas into a macroscopic one. void base_combine(int max_order, const std::vector& those_scatts, - const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& sparse_mult, double_3dvec& sparse_scatter); + const double_1dvec& scalars, xt::xtensor& in_gmin, + xt::xtensor& in_gmax, double_2dvec& sparse_mult, + double_3dvec& sparse_scatter); public: - double_2dvec energy; // Normalized p0 matrix for sampling Eout - double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) - double_3dvec dist; // Angular distribution - int_1dvec gmin; // minimum outgoing group - int_1dvec gmax; // maximum outgoing group - double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} + double_2dvec energy; // Normalized p0 matrix for sampling Eout + double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) + double_3dvec dist; // Angular distribution + xt::xtensor gmin; // minimum outgoing group + xt::xtensor gmax; // maximum outgoing group + xt::xtensor scattxs; // Isotropic Sigma_{s,g_{in}} //! \brief Calculates the value of normalized f(mu). //! @@ -72,7 +76,7 @@ class ScattData { //! @param in_mult Input sparse multiplicity matrix //! @param coeffs Input sparse scattering matrix virtual void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) = 0; //! \brief Combines the microscopic data. @@ -97,7 +101,7 @@ class ScattData { //! @param max_order If Legendre this is the maximum value of "n" in "Pn" //! requested; ignored otherwise. //! @return The dense scattering matrix. - virtual double_3dvec + virtual xt::xtensor get_matrix(int max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. @@ -142,7 +146,7 @@ class ScattDataLegendre: public ScattData { public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -163,7 +167,7 @@ class ScattDataLegendre: public ScattData { int get_order() {return dist[0][0].size() - 1;}; - double_3dvec + xt::xtensor get_matrix(int max_order); }; @@ -176,14 +180,14 @@ class ScattDataHistogram: public ScattData { protected: - double_1dvec mu; // Angle distribution mu bin boundaries - double dmu; // Quick storage of the spacing between the mu bin points - double_3dvec fmu; // The angular distribution histogram + xt::xtensor mu; // Angle distribution mu bin boundaries + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution histogram public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -199,7 +203,7 @@ class ScattDataHistogram: public ScattData { int get_order() {return dist[0][0].size();}; - double_3dvec + xt::xtensor get_matrix(int max_order); }; @@ -212,9 +216,9 @@ class ScattDataTabular: public ScattData { protected: - double_1dvec mu; // Angle distribution mu grid points - double dmu; // Quick storage of the spacing between the mu points - double_3dvec fmu; // The angular distribution function + xt::xtensor mu; // Angle distribution mu grid points + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution function // Friend convert_legendre_to_tabular so it has access to protected // parameters @@ -225,7 +229,7 @@ class ScattDataTabular: public ScattData { public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -241,7 +245,7 @@ class ScattDataTabular: public ScattData { int get_order() {return dist[0][0].size();}; - double_3dvec get_matrix(int max_order); + xt::xtensor get_matrix(int max_order); }; //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 156708c78..9a602c8b7 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -7,6 +7,8 @@ #include #include +#include "xtensor/xtensor.hpp" + #include "openmc/hdf5_interface.h" #include "openmc/scattdata.h" @@ -35,26 +37,26 @@ class XsData { // The following quantities have the following dimensions: // [angle][incoming group] - double_2dvec total; - double_2dvec absorption; - double_2dvec nu_fission; - double_2dvec prompt_nu_fission; - double_2dvec kappa_fission; - double_2dvec fission; - double_2dvec inverse_velocity; + xt::xtensor total; + xt::xtensor absorption; + xt::xtensor nu_fission; + xt::xtensor prompt_nu_fission; + xt::xtensor kappa_fission; + xt::xtensor fission; + xt::xtensor inverse_velocity; // decay_rate has the following dimensions: // [angle][delayed group] - double_2dvec decay_rate; + xt::xtensor decay_rate; // delayed_nu_fission has the following dimensions: // [angle][incoming group][delayed group] - double_3dvec delayed_nu_fission; + xt::xtensor delayed_nu_fission; // chi_prompt has the following dimensions: // [angle][incoming group][outgoing group] - double_3dvec chi_prompt; + xt::xtensor chi_prompt; // chi_delayed has the following dimensions: // [angle][incoming group][outgoing group][delayed group] - double_4dvec chi_delayed; + xt::xtensor chi_delayed; // scatter has the following dimensions: [angle] std::vector > scatter; diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 5056e5f78..db987cc02 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -5,6 +5,9 @@ #include #include +#include "xtensor/xtensor.hpp" +#include "xtensor/xarray.hpp" + #include "hdf5.h" #include "hdf5_hl.h" #ifdef OPENMC_MPI @@ -474,6 +477,106 @@ read_dataset(hid_t obj_id, const char* name, hid_t mem_type_id, if (name) H5Dclose(dset); } +// //***************************************************************************** + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// read_double(obj_id, name, result.data(), true); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_int(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_int(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +//***************************************************************************** void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) @@ -545,19 +648,38 @@ read_nd_vector(hid_t obj_id, const char* name, std::vector& result, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have) +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); + int dim1 = result.shape()[0]; + double temp_arr[dim1]; + read_double(obj_id, name, temp_arr, true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + result(i) = temp_arr[temp_idx++]; + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; double temp_arr[dim1 * dim2]; read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { - result[i][j] = temp_arr[temp_idx++]; + result(i, j) = temp_arr[temp_idx++]; } } } else if (must_have) { @@ -567,19 +689,19 @@ read_nd_vector(hid_t obj_id, const char* name, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have) +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; int temp_arr[dim1 * dim2]; read_int(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { - result[i][j] = temp_arr[temp_idx++]; + result(i, j) = temp_arr[temp_idx++]; } } } else if (must_have) { @@ -589,14 +711,13 @@ read_nd_vector(hid_t obj_id, const char* name, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; double temp_arr[dim1 * dim2 * dim3]; read_double(obj_id, name, temp_arr, true); @@ -604,7 +725,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { - result[i][j][k] = temp_arr[temp_idx++]; + result(i, j, k) = temp_arr[temp_idx++]; } } } @@ -614,14 +735,13 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; int temp_arr[dim1 * dim2 * dim3]; read_int(obj_id, name, temp_arr, true); @@ -629,7 +749,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { - result[i][j][k] = temp_arr[temp_idx++]; + result(i, j, k) = temp_arr[temp_idx++]; } } } @@ -639,15 +759,14 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); - int dim4 = result[0][0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; + int dim4 = result.shape()[3]; double temp_arr[dim1 * dim2 * dim3 * dim4]; read_double(obj_id, name, temp_arr, true); @@ -656,7 +775,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { for (int l = 0; l < dim4; l++) { - result[i][j][k][l] = temp_arr[temp_idx++]; + result(i, j, k, l) = temp_arr[temp_idx++]; } } } @@ -667,16 +786,15 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); - int dim4 = result[0][0][0].size(); - int dim5 = result[0][0][0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; + int dim4 = result.shape()[3]; + int dim5 = result.shape()[4]; double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5]; read_double(obj_id, name, temp_arr, true); @@ -686,7 +804,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int k = 0; k < dim3; k++) { for (int l = 0; l < dim4; l++) { for (int m = 0; m < dim5; m++) { - result[i][j][k][l][m] = temp_arr[temp_idx++]; + result(i, j, k, l, m) = temp_arr[temp_idx++]; } } } diff --git a/src/mgxs.cpp b/src/mgxs.cpp index eb13a55f6..ed68a12e9 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -3,12 +3,17 @@ #include #include #include -#include +#include #ifdef _OPENMP #include #endif +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xadapt.hpp" +#include "xtensor/xview.hpp" + #include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/random_lcg.h" @@ -28,14 +33,15 @@ std::vector macro_xs; void Mgxs::init(const std::string& in_name, double in_awr, - const double_1dvec& in_kTs, bool in_fissionable, int in_scatter_format, + const std::vector& in_kTs, bool in_fissionable, int in_scatter_format, int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal) + const std::vector& in_polar, const std::vector& in_azimuthal) { // Set the metadata name = in_name; awr = in_awr; - kTs = in_kTs; + //TODO: Remove adapt when in_KTs is an xtensor + kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; num_groups = in_num_groups; @@ -61,8 +67,8 @@ Mgxs::init(const std::string& in_name, double in_awr, void Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, const double_1dvec& temperature, - double tolerance, int_1dvec& temps_to_read, int& order_dim, int& method) + int in_num_delayed_groups, const std::vector& temperature, + double tolerance, std::vector& temps_to_read, int& order_dim, int& method) { // get name char char_name[MAX_WORD_LEN]; @@ -87,7 +93,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, dset_names[i] = new char[151]; } get_datasets(kT_group, dset_names); - double_1dvec available_temps(num_temps); + xt::xarray available_temps(num_temps); for (int i = 0; i < num_temps; i++) { read_double(kT_group, dset_names[i], &available_temps[i], true); @@ -110,24 +116,20 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, switch(method) { case TEMPERATURE_NEAREST: - // Find the minimum difference - for (int i = 0; i < temperature.size(); i++) { - std::valarray temp_diff(available_temps.data(), - available_temps.size()); - temp_diff = std::abs(temp_diff - temperature[i]); - int i_closest = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - - std::begin(temp_diff); + // Determine actual temperatures to read + for (const auto& T : temperature) { + auto i_closest = xt::argmin(xt::abs(available_temps - T))[0]; double temp_actual = available_temps[i_closest]; - - if (std::abs(temp_actual - temperature[i]) < tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(temp_actual)) == temps_to_read.end()) { + if (std::fabs(temp_actual - T) < tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) + == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); - } else { - fatal_error("MGXS Library does not contain cross section for " + - in_name + " at or near " + - std::to_string(std::round(temperature[i])) + " K."); } + } else { + std::stringstream msg; + msg << "MGXS library does not contain cross sections for " + << in_name << " at or near " << std::round(T) << " K."; + fatal_error(msg); } } break; @@ -160,7 +162,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // Get the library's temperatures int n_temperature = temps_to_read.size(); - double_1dvec in_kTs(n_temperature); + std::vector in_kTs(n_temperature); for (int i = 0; i < n_temperature; i++) { std::string temp_str(std::to_string(temps_to_read[i]) + "K"); @@ -254,12 +256,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, } // Set the angular bins to use equally-spaced bins - double_1dvec in_polar(in_n_pol); + std::vector in_polar(in_n_pol); double dangle = PI / in_n_pol; for (int p = 0; p < in_n_pol; p++) { in_polar[p] = (p + 0.5) * dangle; } - double_1dvec in_azimuthal(in_n_azi); + std::vector in_azimuthal(in_n_azi); dangle = 2. * PI / in_n_azi; for (int a = 0; a < in_n_azi; a++) { in_azimuthal[a] = (a + 0.5) * dangle - PI; @@ -274,12 +276,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, //============================================================================== Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups, - const double_1dvec& temperature, double tolerance, int max_order, + const std::vector& temperature, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, int& method) { // Call generic data gathering routine (will populate the metadata) int order_data; - int_1dvec temps_to_read; + std::vector temps_to_read; metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, tolerance, temps_to_read, order_data, method); @@ -310,8 +312,8 @@ Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups, //============================================================================== -Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, - const std::vector& micros, const double_1dvec& atom_densities, +Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, + const std::vector& micros, const std::vector& atom_densities, double tolerance, int& method) { // Get the minimum data needed to initialize: @@ -328,8 +330,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, int in_num_groups = micros[0]->num_groups; int in_num_delayed_groups = micros[0]->num_delayed_groups; bool in_is_isotropic = micros[0]->is_isotropic; - double_1dvec in_polar = micros[0]->polar; - double_1dvec in_azimuthal = micros[0]->azimuthal; + std::vector in_polar = micros[0]->polar; + std::vector in_azimuthal = micros[0]->azimuthal; init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, @@ -345,33 +347,27 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, // Create the list of temperature indices and interpolation factors for // each microscopic data at the material temperature - int_1dvec micro_t(micros.size(), 0); - double_1dvec micro_t_interp(micros.size(), 0.); + std::vector micro_t(micros.size(), 0); + std::vector micro_t_interp(micros.size(), 0.); for (int m = 0; m < micros.size(); m++) { switch(method) { case TEMPERATURE_NEAREST: { - // Find the nearest temperature - std::valarray temp_diff(micros[m]->kTs.data(), - micros[m]->kTs.size()); - temp_diff = std::abs(temp_diff - temp_desired); - micro_t[m] = std::min_element(std::begin(temp_diff), - std::end(temp_diff)) - - std::begin(temp_diff); - double temp_actual = micros[m]->kTs[micro_t[m]]; + micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0]; + auto temp_actual = micros[m]->kTs[micro_t[m]]; if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) { - fatal_error("MGXS Library does not contain cross section for " + - name + " at or near " + - std::to_string(std::round(temp_desired / K_BOLTZMANN)) - + " K."); + std::stringstream msg; + msg << "MGXS Library does not contain cross section for " << name + << " at or near " << std::round(temp_desired / K_BOLTZMANN) << "K."; + fatal_error(msg); } } break; case TEMPERATURE_INTERPOLATION: // Get a list of bounding temperatures for each actual temperature // present in the model - for (int k = 0; k < micros[m]->kTs.size() - 1; k++) { + for (int k = 0; k < micros[m]->kTs.shape()[0] - 1; k++) { if ((micros[m]->kTs[k] <= temp_desired) && (temp_desired < micros[m]->kTs[k + 1])) { micro_t[m] = k; @@ -394,8 +390,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, int num_interp_points = 2; if (method == TEMPERATURE_NEAREST) num_interp_points = 1; for (int interp_point = 0; interp_point < num_interp_points; interp_point++) { - double_1dvec interp(micros.size()); - double_1dvec temp_indices(micros.size()); + std::vector interp(micros.size()); + std::vector temp_indices(micros.size()); for (int m = 0; m < micros.size(); m++) { interp[m] = (1. - micro_t_interp[m]) * atom_densities[m]; temp_indices[m] = micro_t[m] + interp_point; @@ -409,8 +405,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, //============================================================================== void -Mgxs::combine(const std::vector& micros, const double_1dvec& scalars, - const int_1dvec& micro_ts, int this_t) +Mgxs::combine(const std::vector& micros, const std::vector& scalars, + const std::vector& micro_ts, int this_t) { // Build the vector of pointers to the xs objects within micros std::vector those_xs(micros.size()); @@ -441,19 +437,19 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs_t->total[a][gin]; + val = xs_t->total(a, gin); break; case MG_GET_XS_NU_FISSION: - val = fissionable ? xs_t->nu_fission[a][gin] : 0.; + val = fissionable ? xs_t->nu_fission(a, gin) : 0.; break; case MG_GET_XS_ABSORPTION: - val = xs_t->absorption[a][gin]; + val = xs_t->absorption(a, gin);; break; case MG_GET_XS_FISSION: - val = fissionable ? xs_t->fission[a][gin] : 0.; + val = fissionable ? xs_t->fission(a, gin) : 0.; break; case MG_GET_XS_KAPPA_FISSION: - val = fissionable ? xs_t->kappa_fission[a][gin] : 0.; + val = fissionable ? xs_t->kappa_fission(a, gin) : 0.; break; case MG_GET_XS_SCATTER: case MG_GET_XS_SCATTER_MULT: @@ -462,16 +458,16 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_PROMPT_NU_FISSION: - val = fissionable ? xs_t->prompt_nu_fission[a][gin] : 0.; + val = fissionable ? xs_t->prompt_nu_fission(a, gin) : 0.; break; case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs_t->delayed_nu_fission[a][gin][*dg]; + val = xs_t->delayed_nu_fission(a, gin, *dg); } else { val = 0.; - for (auto& num : xs_t->delayed_nu_fission[a][gin]) { - val += num; + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[2]; d++) { + val += xs_t->delayed_nu_fission(a, gin, d); } } } else { @@ -481,12 +477,12 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs_t->chi_prompt[a][gin][*gout]; + val = xs_t->chi_prompt(a, gin, *gout); } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs_t->chi_prompt[a][gin]) { - val += num; + for (int g = 0; g < xs_t->chi_prompt.shape()[2]; g++) { + val += xs_t->chi_prompt(a, gin, g); } } } else { @@ -497,21 +493,21 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs_t->chi_delayed[a][gin][*gout][*dg]; + val = xs_t->chi_delayed(a, gin, *gout, *dg); } else { - val = xs_t->chi_delayed[a][gin][*gout][0]; + val = xs_t->chi_delayed(a, gin, *gout, 0); } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { - val += xs_t->chi_delayed[a][gin][i][*dg]; + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { + val += xs_t->delayed_nu_fission(a, gin, g, *dg); } } else { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { - for (auto& num : xs_t->chi_delayed[a][gin][i]) { - val += num; + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { + val += xs_t->delayed_nu_fission(a, gin, g, d); } } } @@ -521,13 +517,13 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) } break; case MG_GET_XS_INVERSE_VELOCITY: - val = xs_t->inverse_velocity[a][gin]; + val = xs_t->inverse_velocity(a, gin); break; case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { - val = xs_t->decay_rate[a][*dg + 1]; + val = xs_t->decay_rate(a, *dg + 1); } else { - val = xs_t->decay_rate[a][0]; + val = xs_t->decay_rate(a, 0); } break; default: @@ -548,11 +544,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) int tid = 0; #endif XsData* xs_t = &xs[cache[tid].t]; - double nu_fission = xs_t->nu_fission[cache[tid].a][gin]; + double nu_fission = xs_t->nu_fission(cache[tid].a, gin); // Find the probability of having a prompt neutron double prob_prompt = - xs_t->prompt_nu_fission[cache[tid].a][gin]; + xs_t->prompt_nu_fission(cache[tid].a, gin); // sample random numbers double xi_pd = prn() * nu_fission; @@ -568,10 +564,10 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_prompt[cache[tid].a][gin][gout]; + xs_t->chi_prompt(cache[tid].a, gin, gout); while (prob_gout < xi_gout) { gout++; - prob_gout += xs_t->chi_prompt[cache[tid].a][gin][gout]; + prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); } } else { @@ -582,7 +578,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs_t->delayed_nu_fission[cache[tid].a][gin][dg]; + xs_t->delayed_nu_fission(cache[tid].a, gin, dg); } // adjust dg in case of round-off error @@ -591,11 +587,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed(cache[tid].a, gin, gout, dg); while (prob_gout < xi_gout) { gout++; prob_gout += - xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed(cache[tid].a, gin, gout, dg); } } } @@ -630,10 +626,10 @@ Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], set_temperature_index(sqrtkT); set_angle_index(uvw); XsData* xs_t = &xs[cache[tid].t]; - total_xs = xs_t->total[cache[tid].a][gin]; - abs_xs = xs_t->absorption[cache[tid].a][gin]; + total_xs = xs_t->total(cache[tid].a, gin); + abs_xs = xs_t->absorption(cache[tid].a, gin); - nu_fiss_xs = fissionable ? xs_t->nu_fission[cache[tid].a][gin] : 0.; + nu_fiss_xs = fissionable ? xs_t->nu_fission(cache[tid].a, gin) : 0.; } //============================================================================== @@ -662,17 +658,7 @@ Mgxs::set_temperature_index(double sqrtkT) int tid = 0; #endif if (sqrtkT != cache[tid].sqrtkT) { - double kT = sqrtkT * sqrtkT; - - // initialize vector for storage of the differences - std::valarray temp_diff(kTs.data(), kTs.size()); - - // Find the minimum difference of kT and kTs - temp_diff = std::abs(temp_diff - kT); - cache[tid].t = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - - std::begin(temp_diff); - - // store this temperature as the last one used + cache[tid].t = xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0]; cache[tid].sqrtkT = sqrtkT; } } diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 3e18c168f..69eb20d8e 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -4,6 +4,8 @@ #include #include +#include "xtensor/xbuilder.hpp" + #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/math_functions.h" @@ -16,8 +18,8 @@ namespace openmc { //============================================================================== void -ScattData::base_init(int order, const int_1dvec& in_gmin, - const int_1dvec& in_gmax, const double_2dvec& in_energy, +ScattData::base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult) { int groups = in_energy.size(); @@ -53,16 +55,15 @@ ScattData::base_init(int order, const int_1dvec& in_gmin, void ScattData::base_combine(int max_order, const std::vector& those_scatts, const double_1dvec& scalars, - int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, + xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { int groups = those_scatts[0] -> energy.size(); // Now allocate and zero our storage spaces - double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(max_order, 0.))); - double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); - double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + xt::xtensor this_matrix({groups, groups, max_order}, 0.); + xt::xtensor mult_numer({groups, groups}, 0.); + xt::xtensor mult_denom({groups, groups}, 0.); // Build the dense scattering and multiplicity matrices // Get the multiplicity_matrix @@ -80,26 +81,26 @@ ScattData::base_combine(int max_order, ScattData* that = those_scatts[i]; // Build the dense matrix for that object - double_3dvec that_matrix = that->get_matrix(max_order); + xt::xtensor that_matrix = that->get_matrix(max_order); // Now add that to this for the scattering and multiplicity for (int gin = 0; gin < groups; gin++) { // Only spend time adding that's gmin to gmax data since the rest will // be zeros int i_gout = 0; - for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + for (int gout = that->gmin(gin); gout <= that->gmax(gin); gout++) { // Do the scattering matrix for (int l = 0; l < max_order; l++) { - this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + this_matrix(gin, gout, l) += scalars[i] * that_matrix(gin, gout, l); } // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; - mult_numer[gin][gout] += scalars[i] * nuscatt; + double nuscatt = that->scattxs(gin) * that->energy[gin][i_gout]; + mult_numer(gin, gout) += scalars[i] * nuscatt; if (that->mult[gin][i_gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; + mult_denom(gin, gout) += scalars[i] * nuscatt / that->mult[gin][i_gout]; } else { - mult_denom[gin][gout] += scalars[i]; + mult_denom(gin, gout) += scalars[i]; } i_gout++; } @@ -107,16 +108,14 @@ ScattData::base_combine(int max_order, } // Combine mult_numer and mult_denom into the combined multiplicity matrix - double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + xt::xtensor this_mult = xt::ones({groups, groups}); for (int gin = 0; gin < groups; gin++) { for (int gout = 0; gout < groups; gout++) { - if (mult_denom[gin][gout] > 0.) { - this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + if (mult_denom(gin, gout) > 0.) { + this_mult(gin, gout) = mult_numer(gin, gout) / mult_denom(gin, gout); } } } - mult_numer.clear(); - mult_denom.clear(); // We have the data, now we need to convert to a jagged array and then use // the initialize function to store it on the object. @@ -125,8 +124,8 @@ ScattData::base_combine(int max_order, int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { - if (this_matrix[gin][gmin_][l] != 0.) { + for (int l = 0; l < this_matrix.shape()[2]; l++) { + if (this_matrix(gin, gmin_, l) != 0.) { non_zero = true; break; } @@ -136,8 +135,8 @@ ScattData::base_combine(int max_order, int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { - if (this_matrix[gin][gmax_][l] != 0.) { + for (int l = 0; l < this_matrix.shape()[2]; l++) { + if (this_matrix(gin, gmax_, l) != 0.) { non_zero = true; break; } @@ -160,8 +159,11 @@ ScattData::base_combine(int max_order, sparse_mult[gin].resize(gmax_ - gmin_ + 1); int i_gout = 0; for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; - sparse_mult[gin][i_gout] = this_mult[gin][gout]; + sparse_scatter[gin][i_gout].resize(this_matrix.shape()[2]); + for (int l = 0; l < this_matrix.shape()[2]; l++) { + sparse_scatter[gin][i_gout][l] = this_matrix(gin, gout, l); + } + sparse_mult[gin][i_gout] = this_mult(gin, gout); i_gout++; } } @@ -241,8 +243,9 @@ ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu) //============================================================================== void -ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataLegendre::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -252,10 +255,9 @@ ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, // Get the scattering cross section value by summing the un-normalized P0 // coefficient in the variable matrix over all outgoing groups. - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { int num_groups = in_gmax[gin] - in_gmin[gin] + 1; - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < num_groups; i_gout++) { scattxs[gin] += matrix[gin][i_gout][0]; } @@ -401,8 +403,8 @@ ScattDataLegendre::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -418,20 +420,19 @@ ScattDataLegendre::combine(const std::vector& those_scatts, //============================================================================== -double_3dvec +xt::xtensor ScattDataLegendre::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); int order_dim = max_order + 1; - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * dist[gin][i_gout][l]; } } @@ -444,8 +445,9 @@ ScattDataLegendre::get_matrix(int max_order) //============================================================================== void -ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataHistogram::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -455,9 +457,8 @@ ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, // Get the scattering cross section value by summing the distribution // over all the histogram bins in angle and outgoing energy groups - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(), matrix[gin][i_gout].end(), 0.); @@ -484,12 +485,8 @@ ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Build the angular distribution mu values - mu = double_1dvec(order); + mu = xt::linspace(-1., 1., order + 1); dmu = 2. / order; - mu[0] = -1.; - for (int imu = 1; imu < order; imu++) { - mu[imu] = -1. + imu * dmu; - } // Calculate f(mu) and integrate it so we can avoid rejection sampling fmu.resize(groups); @@ -581,21 +578,20 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== -double_3dvec +xt::xtensor ScattDataHistogram::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix = xt::zeros({groups, groups, order_dim}); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } @@ -624,8 +620,8 @@ ScattDataHistogram::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -633,7 +629,7 @@ ScattDataHistogram::combine(const std::vector& those_scatts, // so we use a base class method to sum up xs and create new energy and mult // matrices ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, - sparse_mult, sparse_scatter); + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -644,8 +640,9 @@ ScattDataHistogram::combine(const std::vector& those_scatts, //============================================================================== void -ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataTabular::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -654,19 +651,13 @@ ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, double_3dvec matrix = coeffs; // Build the angular distribution mu values - mu = double_1dvec(order); + mu = xt::linspace(-1., 1., order); dmu = 2. / (order - 1); - mu[0] = -1.; - for (int imu = 1; imu < order - 1; imu++) { - mu[imu] = -1. + imu * dmu; - } - mu[order - 1] = 1.; // Get the scattering cross section value by integrating the distribution // over all mu points and then combining over all outgoing groups - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { for (int imu = 1; imu < order; imu++) { scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + @@ -743,7 +734,7 @@ ScattDataTabular::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.size() - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } @@ -764,7 +755,7 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) sample_energy(gin, gout, i_gout); // Determine the outgoing cosine bin - int NP = this->mu.size(); + int NP = this->mu.shape()[0]; double xi = prn(); double c_k = dist[gin][i_gout][0]; @@ -804,21 +795,20 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== -double_3dvec +xt::xtensor ScattDataTabular::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } @@ -847,8 +837,8 @@ ScattDataTabular::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -856,7 +846,7 @@ ScattDataTabular::combine(const std::vector& those_scatts, // so we use a base class method to sum up xs and create new energy and mult // matrices ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, - sparse_mult, sparse_scatter); + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -885,13 +875,8 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, tab.scattxs = leg.scattxs; // Build mu and dmu - tab.mu = double_1dvec(n_mu); + tab.mu = xt::linspace(-1., 1., n_mu); tab.dmu = 2. / (n_mu - 1); - tab.mu[0] = -1.; - for (int imu = 1; imu < n_mu - 1; imu++) { - tab.mu[imu] = -1. + imu * tab.dmu; - } - tab.mu[n_mu - 1] = 1.; // Calculate f(mu) and integrate it so we can avoid rejection sampling int groups = tab.energy.size(); diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d9863694a..0a48dce2b 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -5,6 +5,9 @@ #include #include +#include "xtensor/xbuilder.hpp" +#include "xtensor/xview.hpp" + #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/math_functions.h" @@ -20,7 +23,7 @@ namespace openmc { XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -28,31 +31,33 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, fatal_error("Invalid scatter_format!"); } // allocate all [temperature][phi][theta][in group] quantities - total = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - absorption = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - inverse_velocity = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + std::vector shape = {n_ang, energy_groups}; + total = xt::zeros(shape); + absorption = xt::zeros(shape); + inverse_velocity = xt::zeros(shape); if (fissionable) { - fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - prompt_nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - kappa_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + fission = xt::zeros(shape); + nu_fission = xt::zeros(shape); + prompt_nu_fission = xt::zeros(shape); + kappa_fission = xt::zeros(shape); } // allocate decay_rate; [temperature][phi][theta][delayed group] - decay_rate = double_2dvec(n_ang, double_1dvec(num_delayed_groups, 0.)); + shape[1] = num_delayed_groups; + decay_rate = xt::zeros(shape); if (fissionable) { + shape = {n_ang, energy_groups, num_delayed_groups}; // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] - delayed_nu_fission = double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(num_delayed_groups, 0.))); + delayed_nu_fission = xt::zeros(shape); - // chi_prompt; [temperature][phi][theta][in group][delayed group] - chi_prompt = double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(energy_groups, 0.))); + // chi_prompt; [temperature][phi][theta][in group][out group] + shape = {n_ang, energy_groups, energy_groups}; + chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][phi][theta][in group][out group][delay group] - chi_delayed = double_4dvec(n_ang, double_3dvec(energy_groups, - double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); + shape = {n_ang, energy_groups, energy_groups, num_delayed_groups}; + chi_delayed = xt::zeros(shape); } @@ -79,8 +84,8 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, { // Reconstruct the dimension information so it doesn't need to be passed int n_ang = n_pol * n_azi; - int energy_groups = total[0].size(); - int delayed_groups = decay_rate[0].size(); + int energy_groups = total.shape()[1]; + int delayed_groups = decay_rate.shape()[1]; // Set the fissionable-specific data if (fissionable) { @@ -100,7 +105,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, // denominator in tally methods for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - if (absorption[a][gin] == 0.) absorption[a][gin] = 1.e-10; + if (absorption(a, gin) == 0.) absorption(a, gin) = 1.e-10; } } @@ -110,7 +115,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, } else { for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - total[a][gin] = absorption[a][gin] + scatter[a]->scattxs[gin]; + total(a, gin) = absorption(a, gin) + scatter[a]->scattxs[gin]; } } } @@ -118,7 +123,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, // Fix if total is 0, since it is in the denominator when tallying for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - if (total[a][gin] == 0.) total[a][gin] = 1.e-10; + if (total(a, gin) == 0.) total(a, gin) = 1.e-10; } } } @@ -129,14 +134,13 @@ void XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int delayed_groups, bool is_isotropic) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); // Set/get beta - double_3dvec temp_beta =double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(delayed_groups, 0.))); + xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); @@ -146,7 +150,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // Beta is input as [delayed group] - double_1dvec temp_arr(n_pol * n_azi * delayed_groups); + std::vector temp_arr({n_pol * n_azi * delayed_groups}); read_nd_vector(xsdata_grp, "beta", temp_arr); // Broadcast to all incoming groups @@ -154,9 +158,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int a = 0; a < n_ang; a++) { for (int dg = 0; dg < delayed_groups; dg++) { // Set the first group index and copy the rest - temp_beta[a][0][dg] = temp_arr[temp_idx++]; + temp_beta(a, 0, dg) = temp_arr[temp_idx++]; for (int gin = 1; gin < energy_groups; gin++) { - temp_beta[a][gin] = temp_beta[a][0]; + temp_beta(a, gin, dg) = temp_beta(a, 0, dg); } } } @@ -170,29 +174,33 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr ({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi", temp_arr); for (int a = 0; a < n_ang; a++) { // First set the first group for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][0][gout] = temp_arr[a][gout]; + chi_prompt(a, 0, gout) = temp_arr(a, gout); } // Now normalize this data - double chi_sum = std::accumulate(chi_prompt[a][0].begin(), - chi_prompt[a][0].end(), - 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, 0, gout); + } + if (chi_sum <= 0.) { fatal_error("Encountered chi for a group that is <= 0!"); } for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][0][gout] /= chi_sum; + chi_prompt(a, 0, gout) /= chi_sum; } // And extend to the remaining incoming groups for (int gin = 1; gin < energy_groups; gin++) { - chi_prompt[a][gin] = chi_prompt[a][0]; + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); + } } // Finally set chi-delayed equal to chi-prompt @@ -200,8 +208,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for(int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = - chi_prompt[a][gin][gout]; + chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } @@ -224,15 +231,18 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * prompt_nu_fission[a][gin]; + delayed_nu_fission(a, gin, dg) = + temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } // Correct the prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[a][gin].begin(), - temp_beta[a][gin].end(), 0.); - prompt_nu_fission[a][gin] *= (1. - beta_sum); + double beta_sum = 0.; + for (int gin = 0; gin < energy_groups; gin++) { + beta_sum += temp_beta(a, gin); + } + + prompt_nu_fission(a, gin) *= (1. - beta_sum); } } } @@ -244,14 +254,17 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Normalize the chi info so the CDF is 1. for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, gin, gout); + } + // Set the vector nu-fission from the matrix nu-fission - prompt_nu_fission[a][gin] = chi_sum; + prompt_nu_fission(a, gin) = chi_sum; if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] /= chi_sum; + chi_prompt(a, gin, gout) /= chi_sum; } } else { fatal_error("Encountered chi for a group that is <= 0!"); @@ -262,8 +275,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = - chi_prompt[a][gin][gout]; + chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } @@ -271,16 +283,17 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Set the delayed-nu-fission and correct prompt-nu-fission with beta for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * - prompt_nu_fission[a][gin]; + delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * + prompt_nu_fission(a, gin); } // Correct prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[a][gin].begin(), - temp_beta[a][gin].end(), 0.); - prompt_nu_fission[a][gin] *= (1. - beta_sum); + double beta_sum = 0.; + for (int dg = 0; dg < delayed_groups; dg++) { + beta_sum += temp_beta(a, gin, dg); + } + prompt_nu_fission(a, gin) *= (1. - beta_sum); } } } @@ -293,21 +306,24 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] = temp_arr[a][gout]; + chi_prompt(a, gin, gout) = temp_arr(a, gout); } // Normalize chi so its CDF goes to 1 - double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, gin, gout); + } + if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] /= chi_sum; + chi_prompt(a, gin, gout) /= chi_sum; } } else { fatal_error("Encountered chi-prompt for a group that is <= 0.!"); @@ -326,13 +342,16 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // chi-delayed is a [in group] vector - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); for (int a = 0; a < n_ang; a++) { // normalize the chi CDF to 1 - double chi_sum = std::accumulate(temp_arr[a].begin(), - temp_arr[a].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += temp_arr(a, gout); + } + if (chi_sum <= 0.) { fatal_error("Encountered chi-delayed for a group that is <= 0!"); } @@ -341,7 +360,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = temp_arr[a][gout] / chi_sum; + chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; } } } @@ -356,12 +375,12 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; for (int gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_delayed[a][gin][gout][dg]; + chi_sum += chi_delayed(a, gin, gout, dg); } if (chi_sum > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[a][gin][gout][dg] /= chi_sum; + chi_delayed(a, gin, gout, dg) /= chi_sum; } } else { fatal_error("Encountered chi-delayed for a group that is <= 0!"); @@ -384,29 +403,30 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // prompt-nu-fission is a [in group] vector - read_nd_vector(xsdata_grp, "prompt-nu-fission", - prompt_nu_fission); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission); } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - double_3dvec temp_arr(n_ang, double_2dvec(energy_groups, - double_1dvec(energy_groups))); + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); // The prompt_nu_fission vector from the matrix form for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - double prompt_sum = std::accumulate(temp_arr[a][gin].begin(), - temp_arr[a][gin].end(), 0.); - prompt_nu_fission[a][gin] = prompt_sum; + double prompt_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + prompt_sum += temp_arr(a, gin, gout); + } + + prompt_nu_fission(a, gin) = prompt_sum; } // The chi_prompt data is just the normalized fission matrix for (int gin= 0; gin < energy_groups; gin++) { - if (prompt_nu_fission[a][gin] > 0.) { + if (prompt_nu_fission(a, gin) > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] = - temp_arr[a][gin][gout] / prompt_nu_fission[a][gin]; + chi_prompt(a, gin, gout) = + temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); } } else { fatal_error("Encountered chi-prompt for a group that is <= 0!"); @@ -429,19 +449,19 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // delayed-nu-fission is an [in group] vector - if (temp_beta[0][0][0] == 0.) { + if (temp_beta(0, 0, 0) == 0.) { fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { // Set delayed-nu-fission using beta - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * temp_arr[a][gin]; + delayed_nu_fission(a, gin, dg) = + temp_beta(a, gin, dg) * temp_arr(a, gin); } } } @@ -451,9 +471,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, delayed_nu_fission); } else if (ndims == 5) { - // This will contain delayed-nu-fision and chi-delayed data - double_4dvec temp_arr(n_ang, double_3dvec(energy_groups, - double_2dvec(energy_groups, double_1dvec(delayed_groups)))); + // This will contain delayed-nu-fission and chi-delayed data + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, + delayed_groups}); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix @@ -463,14 +483,14 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { double gout_sum = 0.; for (int gout = 0; gout < energy_groups; gout++) { - gout_sum += temp_arr[a][gin][gout][dg]; - chi_delayed[a][gin][gout][dg] = temp_arr[a][gin][gout][dg]; + gout_sum += temp_arr(a, gin, gout, dg); + chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); } - delayed_nu_fission[a][gin][dg] = gout_sum; + delayed_nu_fission(a, gin, dg) = gout_sum; // Normalize chi-delayed if (gout_sum > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[a][gin][gout][dg] /= gout_sum; + chi_delayed(a, gin, gout, dg) /= gout_sum; } } else { fatal_error("Encountered chi-delayed for a group that is <= 0!"); @@ -488,10 +508,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Combine prompt_nu_fission and delayed_nu_fission into nu_fission for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - nu_fission[a][gin] = - std::accumulate(delayed_nu_fission[a][gin].begin(), - delayed_nu_fission[a][gin].end(), - prompt_nu_fission[a][gin]); + nu_fission(a, gin) = prompt_nu_fission(a, gin); + for (int dg = 0; dg < delayed_groups; dg++) { + nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); + } } } } @@ -503,94 +523,92 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int scatter_format, int final_scatter_format, int order_data, int max_order, int legendre_to_tabular_points) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); } hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - int_2dvec gmin(n_ang, int_1dvec(energy_groups)); + xt::xtensor gmin({n_ang, energy_groups}); read_nd_vector(scatt_grp, "g_min", gmin, true); - int_2dvec gmax(n_ang, int_1dvec(energy_groups)); + xt::xtensor gmax({n_ang, energy_groups}); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - gmin[a][gin] -= 1; - gmax[a][gin] -= 1; - } - } + gmin -= 1; + gmax -= 1; // Now use this info to find the length of a vector to hold the flattened // data. int length = 0; for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - length += order_data * (gmax[a][gin] - gmin[a][gin] + 1); + length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); } } - double_1dvec temp_arr(length); - read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - // Compare the number of orders given with the max order of the problem; - // strip off the superfluous orders if needed - int order_dim; - if (scatter_format == ANGLE_LEGENDRE) { - order_dim = std::min(order_data - 1, max_order) + 1; - } else { - order_dim = order_data; - } - - // convert the flattened temp_arr to a jagged array for passing to - // scatt data double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); + //temp_arr scope + { + std::vector temp_arr(length); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - input_scatt[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); - for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { - input_scatt[a][gin][i_gout].resize(order_dim); - for (int l = 0; l < order_dim; l++) { - input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; + // Compare the number of orders given with the max order of the problem; + // strip off the superfluous orders if needed + int order_dim; + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = std::min(order_data - 1, max_order) + 1; + } else { + order_dim = order_data; + } + + // convert the flattened temp_arr to a jagged array for passing to + // scatt data + int temp_idx = 0; + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); + for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { + input_scatt[a][gin][i_gout].resize(order_dim); + for (int l = 0; l < order_dim; l++) { + input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; + } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); } - // Adjust index for the orders we didnt take - temp_idx += (order_data - order_dim); } } } - temp_arr.clear(); // Get multiplication matrix double_3dvec temp_mult(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { - temp_arr.resize(length / order_data); + std::vector temp_arr(length / order_data); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data int temp_idx = 0; for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; } } } + temp_arr.clear(); } else { // Use a default: multiplicities are 1.0. for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; } } } } - temp_arr.clear(); close_group(scatt_grp); // Finally, convert the Legendre data to tabular, if needed @@ -598,7 +616,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, final_scatter_format == ANGLE_TABULAR) { for (int a = 0; a < n_ang; a++) { ScattDataLegendre legendre_scatt; - legendre_scatt.init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + legendre_scatt.init(in_gmin, in_gmax, + temp_mult[a], input_scatt[a]); // Now create a tabular version of legendre_scatt convert_legendre_to_tabular(legendre_scatt, @@ -611,7 +632,9 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // We are sticking with the current representation // Initialize the ScattData object with this data for (int a = 0; a < n_ang; a++) { - scatter[a]->init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); + scatter[a]->init(xt::view(gmin, a, xt::all()), + xt::view(gmax, a, xt::all()), + temp_mult[a], input_scatt[a]); } } } @@ -627,70 +650,25 @@ XsData::combine(const std::vector& those_xs, XsData* that = those_xs[i]; if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; - for (int a = 0; a < total.size(); a++) { - for (int gin = 0; gin < total[a].size(); gin++) { - total[a][gin] += scalar * that->total[a][gin]; - absorption[a][gin] += scalar * that->absorption[a][gin]; - if (i == 0) { - inverse_velocity[a][gin] = that->inverse_velocity[a][gin]; - } - if (that->prompt_nu_fission.size() > 0) { - nu_fission[a][gin] += scalar * that->nu_fission[a][gin]; - prompt_nu_fission[a][gin] += - scalar * that->prompt_nu_fission[a][gin]; - kappa_fission[a][gin] += scalar * that->kappa_fission[a][gin]; - fission[a][gin] += scalar * that->fission[a][gin]; - - for (int dg = 0; dg < delayed_nu_fission[a][gin].size(); dg++) { - delayed_nu_fission[a][gin][dg] += - scalar * that->delayed_nu_fission[a][gin][dg]; - } - - for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { - chi_prompt[a][gin][gout] += - scalar * that->chi_prompt[a][gin][gout]; - - for (int dg = 0; dg < chi_delayed[a][gin][gout].size(); dg++) { - chi_delayed[a][gin][gout][dg] += - scalar * that->chi_delayed[a][gin][gout][dg]; - } - } - } - } - - for (int dg = 0; dg < decay_rate[a].size(); dg++) { - decay_rate[a][dg] += scalar * that->decay_rate[a][dg]; - } - - // Normalize chi - if (chi_prompt.size() > 0) { - for (int gin = 0; gin < chi_prompt[a].size(); gin++) { - double norm = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); - if (norm > 0.) { - for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { - chi_prompt[a][gin][gout] /= norm; - } - } - - for (int dg = 0; dg < chi_delayed[a][gin][0].size(); dg++) { - norm = 0.; - for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { - norm += chi_delayed[a][gin][gout][dg]; - } - if (norm > 0.) { - for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { - chi_delayed[a][gin][gout][dg] /= norm; - } - } - } - } - } + total += scalar * that->total; + absorption += scalar * that->absorption; + if (i == 0) { + inverse_velocity = that->inverse_velocity; } + if (that->prompt_nu_fission.shape()[0] > 0) { + nu_fission += scalar * that->nu_fission; + prompt_nu_fission += scalar * that->prompt_nu_fission; + kappa_fission += scalar * that->kappa_fission; + fission += scalar * that->fission; + delayed_nu_fission += scalar * that->delayed_nu_fission; + chi_prompt += scalar * that->chi_prompt; + chi_delayed += scalar * that->chi_delayed; + } + decay_rate += scalar * that->decay_rate; } // Allow the ScattData object to combine itself - for (int a = 0; a < total.size(); a++) { + for (int a = 0; a < total.shape()[0]; a++) { // Build vector of the scattering objects to incorporate std::vector those_scatts(those_xs.size()); for (int i = 0; i < those_xs.size(); i++) { @@ -707,8 +685,7 @@ XsData::combine(const std::vector& those_xs, bool XsData::equiv(const XsData& that) { - return ((absorption.size() == that.absorption.size()) && - (absorption[0].size() == that.absorption[0].size())); + return (absorption.shape() == that.absorption.shape()); } } //namespace openmc diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 72f052e68..473596198 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -71,10 +71,11 @@ class MGXSTestHarness(PyAPITestHarness): openmc.run(openmc_exec=config['exe']) def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) + pass + # super()._cleanup() + # f = 'mgxs.h5' + # if os.path.exists(f): + # os.remove(f) def test_mgxs_library_ce_to_mg(): From 35def7aac244bf6134f6272cbeeedb45a0eddff1 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 1 Sep 2018 11:01:56 -0400 Subject: [PATCH 42/76] Got it all working, next would like to take advantage of the xtensor features to reduce lines of code --- include/openmc/constants.h | 2 - include/openmc/hdf5_interface.h | 4 - include/openmc/scattdata.h | 29 +- include/openmc/xsdata.h | 10 +- src/hdf5_interface.cpp | 112 ------- src/mgxs_interface.cpp | 6 +- src/scattdata.cpp | 78 ++--- src/xsdata.cpp | 282 +++++++++--------- .../mgxs_library_ce_to_mg/test.py | 9 +- 9 files changed, 200 insertions(+), 332 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 0b66f355c..b8c5c8548 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -11,8 +11,6 @@ namespace openmc { -// TODO: Replace with xtensor/other library? -typedef std::vector double_1dvec; typedef std::vector > double_2dvec; typedef std::vector > > double_3dvec; typedef std::vector > > > double_4dvec; diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 74f5ae581..3ab2014c1 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -50,10 +50,6 @@ void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); -void -read_nd_vector(hid_t obj_id, const char* name, std::vector& result, - bool must_have = false); - void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index 7e73224b9..8ea81f252 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -33,8 +33,8 @@ class ScattData { //! \brief Combines microscopic ScattDatas into a macroscopic one. void - base_combine(int max_order, const std::vector& those_scatts, - const double_1dvec& scalars, xt::xtensor& in_gmin, + base_combine(size_t max_order, const std::vector& those_scatts, + const std::vector& scalars, xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter); @@ -85,7 +85,7 @@ class ScattData { //! @param scalars Scalars to multiply the microscopic data by. virtual void combine(const std::vector& those_scatts, - const double_1dvec& scalars) = 0; + const std::vector& scalars) = 0; //! \brief Getter for the dimensionality of the scattering order. //! @@ -93,7 +93,7 @@ class ScattData { //! of points, and for Histogram this is the number of bins. //! //! @return The order. - virtual int + virtual size_t get_order() = 0; //! \brief Builds a dense scattering matrix from the constituent parts @@ -102,7 +102,7 @@ class ScattData { //! requested; ignored otherwise. //! @return The dense scattering matrix. virtual xt::xtensor - get_matrix(int max_order) = 0; + get_matrix(size_t max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. //! @@ -151,7 +151,7 @@ class ScattDataLegendre: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); //! \brief Find the maximal value of the angular distribution to use as a // bounding box with rejection sampling. @@ -164,11 +164,11 @@ class ScattDataLegendre: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size() - 1;}; xt::xtensor - get_matrix(int max_order); + get_matrix(size_t max_order); }; //============================================================================== @@ -192,7 +192,7 @@ class ScattDataHistogram: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); double calc_f(int gin, int gout, double mu); @@ -200,11 +200,11 @@ class ScattDataHistogram: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size();}; xt::xtensor - get_matrix(int max_order); + get_matrix(size_t max_order); }; //============================================================================== @@ -234,7 +234,7 @@ class ScattDataTabular: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); double calc_f(int gin, int gout, double mu); @@ -242,10 +242,11 @@ class ScattDataTabular: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size();}; - xt::xtensor get_matrix(int max_order); + xt::xtensor + get_matrix(size_t max_order); }; //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 9a602c8b7..d156de9d9 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -24,14 +24,14 @@ class XsData { private: //! \brief Reads scattering data from the HDF5 file void - scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, + scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, int scatter_format, int final_scatter_format, int order_data, int max_order, int legendre_to_tabular_points); //! \brief Reads fission data from the HDF5 file void - fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, - int delayed_groups, bool is_isotropic); + fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + size_t delayed_groups, bool is_isotropic); public: @@ -70,7 +70,7 @@ class XsData { //! @param scatter_format The scattering representation of the file. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - XsData(int num_groups, int num_delayed_groups, bool fissionable, + XsData(size_t num_groups, size_t num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi); //! \brief Loads the XsData object from the HDF5 file @@ -103,7 +103,7 @@ class XsData { //! @param micros Microscopic objects to combine. //! @param scalars Scalars to multiply the microscopic data by. void - combine(const std::vector& those_xs, const double_1dvec& scalars); + combine(const std::vector& those_xs, const std::vector& scalars); //! \brief Checks to see if this and that are able to be combined //! diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index db987cc02..52fae8228 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -477,106 +477,6 @@ read_dataset(hid_t obj_id, const char* name, hid_t mem_type_id, if (name) H5Dclose(dset); } -// //***************************************************************************** - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// read_double(obj_id, name, result.data(), true); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_int(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_int(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -//***************************************************************************** void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) @@ -635,18 +535,6 @@ read_complex(hid_t obj_id, const char* name, std::complex* buffer, bool } -void -read_nd_vector(hid_t obj_id, const char* name, std::vector& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - read_double(obj_id, name, result.data(), true); - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index f601f3c71..56f3392ff 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -19,7 +19,7 @@ add_mgxs_c(hid_t file_id, const char* name, int energy_groups, int& method) { // Convert temps to a vector for the from_hdf5 function - double_1dvec temperature(temps, temps + n_temps); + std::vector temperature(temps, temps + n_temps); write_message("Loading " + std::string(name) + " data...", 6); @@ -60,10 +60,10 @@ create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], { if (n_temps > 0) { // // Convert temps to a vector - double_1dvec temperature(temps, temps + n_temps); + std::vector temperature(temps, temps + n_temps); // Convert atom_densities to a vector - double_1dvec atom_densities_vec(atom_densities, + std::vector atom_densities_vec(atom_densities, atom_densities + n_nuclides); // Build array of pointers to nuclides_MG's Mgxs objects needed for this diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 69eb20d8e..0ff7969d1 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -22,7 +22,7 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult) { - int groups = in_energy.size(); + size_t groups = in_energy.size(); gmin = in_gmin; gmax = in_gmax; @@ -53,12 +53,12 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, //============================================================================== void -ScattData::base_combine(int max_order, - const std::vector& those_scatts, const double_1dvec& scalars, +ScattData::base_combine(size_t max_order, + const std::vector& those_scatts, const std::vector& scalars, xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); // Now allocate and zero our storage spaces xt::xtensor this_matrix({groups, groups, max_order}, 0.); @@ -108,7 +108,7 @@ ScattData::base_combine(int max_order, } // Combine mult_numer and mult_denom into the combined multiplicity matrix - xt::xtensor this_mult = xt::ones({groups, groups}); + xt::xtensor this_mult({groups, groups}, 1.); for (int gin = 0; gin < groups; gin++) { for (int gout = 0; gout < groups; gout++) { if (mult_denom(gin, gout) > 0.) { @@ -247,8 +247,8 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -303,7 +303,7 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, void ScattDataLegendre::update_max_val() { - int groups = max_val.size(); + size_t groups = max_val.size(); // Step through the polynomial with fixed number of points to identify the // maximal value int Nmu = 1001; @@ -386,25 +386,25 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) void ScattDataLegendre::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = 0; + size_t max_order = 0; for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataLegendre* that = dynamic_cast(those_scatts[i]); if (!that) { fatal_error("Cannot combine the ScattData objects!"); } - int that_order = that->get_order(); + size_t that_order = that->get_order(); if (that_order > max_order) max_order = that_order; } max_order++; // Add one since this is a Legendre - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -421,11 +421,11 @@ ScattDataLegendre::combine(const std::vector& those_scatts, //============================================================================== xt::xtensor -ScattDataLegendre::get_matrix(int max_order) +ScattDataLegendre::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); - int order_dim = max_order + 1; + size_t groups = energy.size(); + size_t order_dim = max_order + 1; xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { @@ -449,8 +449,8 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -579,13 +579,13 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== xt::xtensor -ScattDataHistogram::get_matrix(int max_order) +ScattDataHistogram::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); + size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations - int order_dim = get_order(); - xt::xtensor matrix = xt::zeros({groups, groups, order_dim}); + size_t order_dim = get_order(); + xt::xtensor matrix({groups, groups, order_dim}, 0); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { @@ -603,10 +603,10 @@ ScattDataHistogram::get_matrix(int max_order) void ScattDataHistogram::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = those_scatts[0]->get_order(); + size_t max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataHistogram* that = dynamic_cast(those_scatts[i]); @@ -618,10 +618,10 @@ ScattDataHistogram::combine(const std::vector& those_scatts, } } - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -644,8 +644,8 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -796,12 +796,12 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== xt::xtensor -ScattDataTabular::get_matrix(int max_order) +ScattDataTabular::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); + size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations - int order_dim = get_order(); + size_t order_dim = get_order(); xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { @@ -820,10 +820,10 @@ ScattDataTabular::get_matrix(int max_order) void ScattDataTabular::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = those_scatts[0]->get_order(); + size_t max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataTabular* that = dynamic_cast(those_scatts[i]); @@ -835,10 +835,10 @@ ScattDataTabular::combine(const std::vector& those_scatts, } } - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -879,7 +879,7 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, tab.dmu = 2. / (n_mu - 1); // Calculate f(mu) and integrate it so we can avoid rejection sampling - int groups = tab.energy.size(); + size_t groups = tab.energy.size(); tab.fmu.resize(groups); for (int gin = 0; gin < groups; gin++) { int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 0a48dce2b..d30bc65f8 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -5,8 +5,10 @@ #include #include -#include "xtensor/xbuilder.hpp" #include "xtensor/xview.hpp" +#include "xtensor/xindex_view.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xbuilder.hpp" #include "openmc/constants.h" #include "openmc/error.h" @@ -20,7 +22,7 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, +XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi) { size_t n_ang = n_pol * n_azi; @@ -63,13 +65,10 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, for (int a = 0; a < n_ang; a++) { if (scatter_format == ANGLE_HISTOGRAM) { - // scatter[a] = std::make_unique(ScattDataHistogram); scatter.emplace_back(new ScattDataHistogram); } else if (scatter_format == ANGLE_TABULAR) { - // scatter[a] = std::make_unique(ScattDataTabular); scatter.emplace_back(new ScattDataTabular); } else if (scatter_format == ANGLE_LEGENDRE) { - // scatter[a] = std::make_unique(ScattDataLegendre); scatter.emplace_back(new ScattDataLegendre); } } @@ -83,13 +82,13 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, int legendre_to_tabular_points, bool is_isotropic, int n_pol, int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed - int n_ang = n_pol * n_azi; - int energy_groups = total.shape()[1]; - int delayed_groups = decay_rate.shape()[1]; + size_t n_ang = n_pol * n_azi; + size_t energy_groups = total.shape()[1]; + size_t delayed_groups = decay_rate.shape()[1]; // Set the fissionable-specific data if (fissionable) { - fission_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, delayed_groups, + fission_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups, is_isotropic); } // Get the non-fission-specific data @@ -98,43 +97,34 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); // Get scattering data - scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, + scatter_from_hdf5(xsdata_grp, n_ang, energy_groups, scatter_format, final_scatter_format, order_data, max_order, legendre_to_tabular_points); // Check absorption to ensure it is not 0 since it is often the // denominator in tally methods - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (absorption(a, gin) == 0.) absorption(a, gin) = 1.e-10; - } - } + xt::filtration(absorption, xt::equal(absorption, 0.)) = 1.e-10; // Get or calculate the total x/s if (object_exists(xsdata_grp, "total")) { read_nd_vector(xsdata_grp, "total", total); } else { - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { total(a, gin) = absorption(a, gin) + scatter[a]->scattxs[gin]; } } } // Fix if total is 0, since it is in the denominator when tallying - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (total(a, gin) == 0.) total(a, gin) = 1.e-10; - } - } + xt::filtration(total, xt::equal(total, 0.)) = 1.e-10; } //============================================================================== void -XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups, bool is_isotropic) +XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + size_t delayed_groups, bool is_isotropic) { - size_t n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); @@ -143,23 +133,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; if (ndims == 3) { // Beta is input as [delayed group] - std::vector temp_arr({n_pol * n_azi * delayed_groups}); + xt::xtensor temp_arr({n_ang * delayed_groups}, 0.); read_nd_vector(xsdata_grp, "beta", temp_arr); // Broadcast to all incoming groups - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { // Set the first group index and copy the rest temp_beta(a, 0, dg) = temp_arr[temp_idx++]; - for (int gin = 1; gin < energy_groups; gin++) { + for (size_t gin = 1; gin < energy_groups; gin++) { temp_beta(a, gin, dg) = temp_beta(a, 0, dg); } } @@ -174,40 +164,40 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - xt::xtensor temp_arr ({n_ang, energy_groups}); + xt::xtensor temp_arr ({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi", temp_arr); - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { // First set the first group - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, 0, gout) = temp_arr(a, gout); } // Now normalize this data double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, 0, gout); } if (chi_sum <= 0.) { fatal_error("Encountered chi for a group that is <= 0!"); } - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, 0, gout) /= chi_sum; } // And extend to the remaining incoming groups - for (int gin = 1; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gin = 1; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); } } // Finally set chi-delayed equal to chi-prompt // Set chi-delayed to chi-prompt - for(int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for(size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } @@ -219,7 +209,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // if nu-fission is a matrix, set chi-prompt and chi-delayed. if (object_exists(xsdata_grp, "nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; @@ -228,9 +218,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); // set delayed-nu-fission and correct prompt-nu-fission with beta - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } @@ -238,7 +228,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Correct the prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { double beta_sum = 0.; - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t gin = 0; gin < energy_groups; gin++) { beta_sum += temp_beta(a, gin); } @@ -252,10 +242,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); // Normalize the chi info so the CDF is 1. - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, gin, gout); } @@ -263,7 +253,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, prompt_nu_fission(a, gin) = chi_sum; if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) /= chi_sum; } } else { @@ -271,18 +261,18 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } - // set chi-delayed to chi-prompt - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + // set all of chi-delayed to chi-prompt + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } // Set the delayed-nu-fission and correct prompt-nu-fission with beta - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } @@ -290,7 +280,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Correct prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { double beta_sum = 0.; - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { beta_sum += temp_beta(a, gin, dg); } prompt_nu_fission(a, gin) *= (1. - beta_sum); @@ -306,23 +296,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = temp_arr(a, gout); } // Normalize chi so its CDF goes to 1 double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, gin, gout); } if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) /= chi_sum; } } else { @@ -335,20 +325,20 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-delayed is provided, set chi-delayed if (object_exists(xsdata_grp, "chi-delayed")) { hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); if (ndims == 3) { // chi-delayed is a [in group] vector - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { // normalize the chi CDF to 1 double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += temp_arr(a, gout); } @@ -357,9 +347,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // set chi-delayed - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; } } @@ -370,16 +360,16 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); // Normalize the chi info so the CDF is 1. - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_delayed(a, gin, gout, dg); } if (chi_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_delayed(a, gin, gout, dg) /= chi_sum; } } else { @@ -396,7 +386,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get prompt-nu-fission, if present if (object_exists(xsdata_grp, "prompt-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); @@ -407,14 +397,14 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); // The prompt_nu_fission vector from the matrix form - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double prompt_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { prompt_sum += temp_arr(a, gin, gout); } @@ -422,9 +412,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // The chi_prompt data is just the normalized fission matrix - for (int gin= 0; gin < energy_groups; gin++) { + for (size_t gin= 0; gin < energy_groups; gin++) { if (prompt_nu_fission(a, gin) > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); } @@ -442,7 +432,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get delayed-nu-fission, if present if (object_exists(xsdata_grp, "delayed-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); close_dataset(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; @@ -453,12 +443,12 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { // Set delayed-nu-fission using beta delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * temp_arr(a, gin); @@ -473,23 +463,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 5) { // This will contain delayed-nu-fission and chi-delayed data xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, - delayed_groups}); + delayed_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix // from the 4D delayed-nu-fission matrix - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double gout_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { gout_sum += temp_arr(a, gin, gout, dg); chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); } delayed_nu_fission(a, gin, dg) = gout_sum; // Normalize chi-delayed if (gout_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_delayed(a, gin, gout, dg) /= gout_sum; } } else { @@ -506,10 +496,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { nu_fission(a, gin) = prompt_nu_fission(a, gin); - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); } } @@ -519,20 +509,19 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, //============================================================================== void -XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int scatter_format, int final_scatter_format, - int order_data, int max_order, int legendre_to_tabular_points) +XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + int scatter_format, int final_scatter_format, int order_data, + int max_order, int legendre_to_tabular_points) { - size_t n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); } hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - xt::xtensor gmin({n_ang, energy_groups}); + xt::xtensor gmin({n_ang, energy_groups}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); - xt::xtensor gmax({n_ang, energy_groups}); + xt::xtensor gmax({n_ang, energy_groups}, 0.); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library @@ -541,42 +530,39 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Now use this info to find the length of a vector to hold the flattened // data. - int length = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + size_t length = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); } } double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); - //temp_arr scope - { - std::vector temp_arr(length); - read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); + xt::xtensor temp_arr({length}, 0.); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - // Compare the number of orders given with the max order of the problem; - // strip off the superfluous orders if needed - int order_dim; - if (scatter_format == ANGLE_LEGENDRE) { - order_dim = std::min(order_data - 1, max_order) + 1; - } else { - order_dim = order_data; - } + // Compare the number of orders given with the max order of the problem; + // strip off the superfluous orders if needed + int order_dim; + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = std::min(order_data - 1, max_order) + 1; + } else { + order_dim = order_data; + } - // convert the flattened temp_arr to a jagged array for passing to - // scatt data - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { - input_scatt[a][gin][i_gout].resize(order_dim); - for (int l = 0; l < order_dim; l++) { - input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; - } - // Adjust index for the orders we didnt take - temp_idx += (order_data - order_dim); + // convert the flattened temp_arr to a jagged array for passing to + // scatt data + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); + for (size_t i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { + input_scatt[a][gin][i_gout].resize(order_dim); + for (size_t l = 0; l < order_dim; l++) { + input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); } } } @@ -584,26 +570,25 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get multiplication matrix double_3dvec temp_mult(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { - std::vector temp_arr(length / order_data); + temp_arr.resize({length / order_data}); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; } } } - temp_arr.clear(); } else { // Use a default: multiplicities are 1.0. - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; } } @@ -614,10 +599,11 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Finally, convert the Legendre data to tabular, if needed if (scatter_format == ANGLE_LEGENDRE && final_scatter_format == ANGLE_TABULAR) { - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { ScattDataLegendre legendre_scatt; xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + legendre_scatt.init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); @@ -631,10 +617,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else { // We are sticking with the current representation // Initialize the ScattData object with this data - for (int a = 0; a < n_ang; a++) { - scatter[a]->init(xt::view(gmin, a, xt::all()), - xt::view(gmax, a, xt::all()), - temp_mult[a], input_scatt[a]); + for (size_t a = 0; a < n_ang; a++) { + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + scatter[a]->init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); } } } @@ -643,10 +629,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, void XsData::combine(const std::vector& those_xs, - const double_1dvec& scalars) + const std::vector& scalars) { // Combine the non-scattering data - for (int i = 0; i < those_xs.size(); i++) { + for (size_t i = 0; i < those_xs.size(); i++) { XsData* that = those_xs[i]; if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; @@ -668,10 +654,10 @@ XsData::combine(const std::vector& those_xs, } // Allow the ScattData object to combine itself - for (int a = 0; a < total.shape()[0]; a++) { + for (size_t a = 0; a < total.shape()[0]; a++) { // Build vector of the scattering objects to incorporate std::vector those_scatts(those_xs.size()); - for (int i = 0; i < those_xs.size(); i++) { + for (size_t i = 0; i < those_xs.size(); i++) { those_scatts[i] = those_xs[i]->scatter[a].get(); } diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 473596198..72f052e68 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -71,11 +71,10 @@ class MGXSTestHarness(PyAPITestHarness): openmc.run(openmc_exec=config['exe']) def _cleanup(self): - pass - # super()._cleanup() - # f = 'mgxs.h5' - # if os.path.exists(f): - # os.remove(f) + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) def test_mgxs_library_ce_to_mg(): From 65ba838cbe9c27d400ef19a00a2d09016310e236 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 2 Sep 2018 14:35:37 -0500 Subject: [PATCH 43/76] Address @smharper comments on #1062 --- src/settings.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 860e57626..b7310c37f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -138,7 +138,6 @@ void get_run_parameters(pugi::xml_node node_base) // TODO: Preallocate space for keff and entropy by generation - // TODO: Read keff_trigger information // Get the trigger information for keff if (check_for_node(node_base, "keff_trigger")) { xml_node node_keff_trigger = node_base.child("keff_trigger"); @@ -149,7 +148,7 @@ void get_run_parameters(pugi::xml_node node_base) keff_trigger.type = STANDARD_DEVIATION; } else if (temp == "variance") { keff_trigger.type = VARIANCE; - } else if ( temp == "rel_err") { + } else if (temp == "rel_err") { keff_trigger.type = RELATIVE_ERROR; } else { fatal_error("Unrecognized keff trigger type " + temp); @@ -257,10 +256,9 @@ read_settings_xml() max_order = std::stoi(get_node_value(root, "max_order")); } else { // Set to default of largest int - 1, which means to use whatever is - // contained in library. - // This is largest int - 1 because for legendre scattering, a value of - // 1 is added to the order; adding 1 to huge(0) gets you the largest - // negative integer, which is not what we want. + // contained in library. This is largest int - 1 because for legendre + // scattering, a value of 1 is added to the order; adding 1 to the largest + // int gets you the largest negative integer, which is not what we want. max_order = std::numeric_limits::max() - 1; } } @@ -293,7 +291,7 @@ read_settings_xml() // Check run mode if it hasn't been set from the command line xml_node node_mode; - if (run_mode == -1) { + if (run_mode == C_NONE) { if (check_for_node(root, "run_mode")) { std::string temp_str = get_node_value(root, "run_mode", true, true); if (temp_str == "eigenvalue") { @@ -318,11 +316,11 @@ read_settings_xml() // Make sure that either eigenvalue or fixed source was specified node_mode = root.child("eigenvalue"); if (node_mode) { - if (run_mode == -1) run_mode = RUN_MODE_EIGENVALUE; + run_mode = RUN_MODE_EIGENVALUE; } else { node_mode = root.child("fixed_source"); if (node_mode) { - if (run_mode == -1) run_mode = RUN_MODE_FIXEDSOURCE; + run_mode = RUN_MODE_FIXEDSOURCE; } else { fatal_error(" or not specified."); } @@ -394,7 +392,8 @@ read_settings_xml() omp_set_num_threads(openmc_n_threads); } #else - if (openmc_master) warning("Ignoring number of threads."); + if (openmc_master) warning("OpenMC was not compiled with OpenMP support; " + "ignoring number of threads."); #endif } @@ -461,6 +460,10 @@ read_settings_xml() // Particle trace if (check_for_node(root, "trace")) { auto temp = get_node_array(root, "trace"); + if (temp.size() != 3) { + fatal_error("Must provide 3 integers for that specify the " + "batch, generation, and particle number."); + } trace_batch = temp.at(0); trace_gen = temp.at(1); trace_particle = temp.at(2); @@ -593,7 +596,7 @@ read_settings_xml() res_scat_energy_max = std::stod(get_node_value(node_res_scat, "energy_max")); } if (res_scat_energy_max < res_scat_energy_min) { - fatal_error("Upper resonance scattering energy bound is below the" + fatal_error("Upper resonance scattering energy bound is below the " "lower resonance scattering energy bound."); } From 6d22b30b5c984702c2ec3a7a46cb69c5de3c2359 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 2 Sep 2018 15:15:28 -0500 Subject: [PATCH 44/76] Remove fission energy release-related flag in get-nndc-data. Make sure BREMX.DAT gets installed. --- scripts/openmc-get-nndc-data | 5 ----- setup.py | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/openmc-get-nndc-data b/scripts/openmc-get-nndc-data index a84a9b282..ff02d3e4c 100755 --- a/scripts/openmc-get-nndc-data +++ b/scripts/openmc-get-nndc-data @@ -148,16 +148,11 @@ if not response or response.lower().startswith('y'): # get a list of all ACE files ace_files = sorted(glob.glob(os.path.join('nndc', '**', '*.ace*'))) -# Get path to fission energy release data -data_dir = os.path.dirname(sys.modules['openmc.data'].__file__) -fer_file = os.path.join(data_dir, 'fission_Q_data_endfb71.h5') - # Call the ace-to-hdf5 conversion script pwd = os.path.dirname(os.path.realpath(__file__)) ace2hdf5 = os.path.join(pwd, 'openmc-ace-to-hdf5') subprocess.call([ace2hdf5, '-d', 'nndc_hdf5', - '--fission_energy_release', fer_file, '--libver', args.libver] + ace_files) # Generate photo interaction library files diff --git a/setup.py b/setup.py index e04bc82f6..cbf564480 100755 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ kwargs = { # Data files and librarries 'package_data': { 'openmc.capi': ['libopenmc.{}'.format(suffix)], - 'openmc.data': ['mass.mas12', '*.h5'] + 'openmc.data': ['mass.mas12', 'BREMX.DAT', '*.h5'] }, # Metadata @@ -52,6 +52,7 @@ kwargs = { 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ], # Required dependencies From d6f94f7ce8e760033be662d5166148efbbeff10f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 2 Sep 2018 18:59:28 -0400 Subject: [PATCH 45/76] added specialized fission-getting methods --- include/openmc/mgxs.h | 10 +- include/openmc/xsdata.h | 36 ++ src/input_xml.F90 | 2 +- src/mgxs.cpp | 10 +- src/xsdata.cpp | 611 ++++++++---------- .../regression_tests/mg_benchmark/__init__.py | 0 .../mg_benchmark/inputs_true.dat | 33 + .../mg_benchmark/results_true.dat | 2 + tests/regression_tests/mg_benchmark/test.py | 167 +++++ .../mg_benchmark_delayed/__init__.py | 0 .../mg_benchmark_delayed/test.py | 175 +++++ 11 files changed, 678 insertions(+), 368 deletions(-) create mode 100644 tests/regression_tests/mg_benchmark/__init__.py create mode 100644 tests/regression_tests/mg_benchmark/inputs_true.dat create mode 100644 tests/regression_tests/mg_benchmark/results_true.dat create mode 100644 tests/regression_tests/mg_benchmark/test.py create mode 100644 tests/regression_tests/mg_benchmark_delayed/__init__.py create mode 100644 tests/regression_tests/mg_benchmark_delayed/test.py diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index e80355bee..cd312ea17 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -159,7 +159,7 @@ class Mgxs { //! @param dg delayed group index; use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(int xstype, int gin, int* gout, double* mu, int* dg); + get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg); //! \brief Samples the fission neutron energy and if prompt or delayed. //! @@ -167,7 +167,7 @@ class Mgxs { //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. void - sample_fission_energy(int gin, int& dg, int& gout); + sample_fission_energy(const int gin, int& dg, int& gout); //! \brief Samples the outgoing energy and angle from a scatter event. //! @@ -176,7 +176,7 @@ class Mgxs { //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. void - sample_scatter(int gin, int& gout, double& mu, double& wgt); + sample_scatter(const int gin, int& gout, double& mu, double& wgt); //! \brief Calculates cross section quantities needed for tracking. //! @@ -187,14 +187,14 @@ class Mgxs { //! @param abs_xs Resultant absorption cross section. //! @param nu_fiss_xs Resultant nu-fission cross section. void - calculate_xs(int gin, double sqrtkT, const double uvw[3], + calculate_xs(const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); //! \brief Sets the temperature index in cache given a temperature //! //! @param sqrtkT Temperature of the material. void - set_temperature_index(double sqrtkT); + set_temperature_index(const double sqrtkT); //! \brief Sets the angle index in cache given a direction //! diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index d156de9d9..780855ecf 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -33,6 +33,42 @@ class XsData { fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, size_t delayed_groups, bool is_isotropic); + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is provided. + void + fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is not provided. + void + fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when no delayed data is provided. + void + fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is provided. + void + fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is not provided. + void + fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when no delayed data is provided. + void + fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups); + public: // The following quantities have the following dimensions: diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 010e09973..289488c34 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -183,7 +183,7 @@ contains ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() - ! Determine desired txemperatures for each nuclide and S(a,b) table + ! Determine desired temperatures for each nuclide and S(a,b) table call get_temperatures(nuc_temps, sab_temps) ! Check to make sure there are not too many nested coordinate levels in the diff --git a/src/mgxs.cpp b/src/mgxs.cpp index ed68a12e9..93b7d43b7 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -423,7 +423,7 @@ Mgxs::combine(const std::vector& micros, const std::vector& scala //============================================================================== double -Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) +Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -535,7 +535,7 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) //============================================================================== void -Mgxs::sample_fission_energy(int gin, int& dg, int& gout) +Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -599,7 +599,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) //============================================================================== void -Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) +Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data @@ -614,7 +614,7 @@ Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) //============================================================================== void -Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], +Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices @@ -649,7 +649,7 @@ Mgxs::equiv(const Mgxs& that) //============================================================================== void -Mgxs::set_temperature_index(double sqrtkT) +Mgxs::set_temperature_index(const double sqrtkT) { // See if we need to find the new index #ifdef _OPENMP diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d30bc65f8..18e474987 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -121,6 +121,241 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, //============================================================================== +void +XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided as nu-fission and chi with a beta for delayed info + + // Get chi + xt::xtensor temp_chi({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + + // Now every incoming group in prompt_chi and delayed_chi is the normalized + // chi we just made + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi(a, gout); + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_chi(a, gout); + } + } + } + } + + // Get nu-fission + xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); + + // Get beta + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + + // Set delayed_nu_fission as beta * nu_fission + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * temp_nufiss(a, gin); + } + } + } +} + +void +XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided separately as prompt + delayed nu-fission and chi + + // Get chi-prompt + xt::xtensor temp_chi_p({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); + + // Get chi-delayed + xt::xtensor temp_chi_d({n_ang, energy_groups, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {1}), xt::all(), + xt::newaxis(), xt::all()); + + // Now assign the prompt and delayed chis by replicating for each incoming group + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi_p(a, gout); + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_chi_d(a, gout, dg); + } + } + } + } + + // Get prompt and delayed nu-fission directly + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); +} + +void +XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups) +{ + // No beta is provided and there is no prompt/delay distinction. + // Therefore, the code only considers the data as prompt. + + // Get chi + xt::xtensor temp_chi({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + + // Now every incoming group in self.chi is the normalized chi we just made + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi(a, gout); + } + } + } + + // Get nu-fission directly + if (object_exists(xsdata_grp, "prompt-nu-fission")) { + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + } else { + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); + } +} + +//============================================================================== + +void +XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided as nu-fission and chi with a beta for delayed info + + // Get nu-fission matrix + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); + + // Get beta + xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_tot) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - xt::sum(temp_beta, {2})); + + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + double out_sum = 0.; + for (size_t gout = 0; gout < energy_groups; gout++) { + out_sum += temp_matrix(a, gin, gout); + } + for (size_t dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * out_sum; + } + } + } + + // Store chi-prompt + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + double beta = 0.; + for (size_t dg = 0; dg < delayed_groups; dg++) { + beta += temp_beta(a, gin, dg); + } + chi_prompt(a, gin, gout) = (1.0 - beta) * temp_matrix(a, gin, gout); + } + } + } + + // Store chi-delayed + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_beta(a, gin, dg) * temp_matrix(a, gin, gout); + } + } + } + } + + //Normalize both + chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::newaxis()); + chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {2}), xt::all(), + xt::newaxis(), xt::all()); +} + +void +XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided separately as prompt + delayed nu-fission and chi + + // Get the prompt nu-fission matrix + xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}); + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); + + // prompt_nu_fission is the sum over outgoing groups + prompt_nu_fission = xt::sum(temp_matrix_p, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix_p / prompt_nu_fission; + + // Get the delayed nu-fission matrix + xt::xtensor temp_matrix_d({n_ang, energy_groups, energy_groups, + delayed_groups}); + read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); + + // delayed_nu_fission is the sum over outgoing groups + delayed_nu_fission = xt::sum(temp_matrix_d, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_delayed = temp_matrix_d / delayed_nu_fission; +} + +void +XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups) +{ + // No beta is provided and there is no prompt/delay distinction. + // Therefore, the code only considers the data as prompt. + + // Get nu-fission matrix + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + if (object_exists(xsdata_grp, "prompt-nu-fission")) { + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); + } else { + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); + } + + // prompt_nu_fission is the sum over outgoing groups + prompt_nu_fission = xt::sum(temp_matrix, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix / prompt_nu_fission; +} + +//============================================================================== + void XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, size_t delayed_groups, bool is_isotropic) @@ -129,369 +364,31 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); - // Set/get beta - xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); - if (object_exists(xsdata_grp, "beta")) { - hid_t xsdata = open_dataset(xsdata_grp, "beta"); - size_t ndims = dataset_ndims(xsdata); - - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // Beta is input as [delayed group] - xt::xtensor temp_arr({n_ang * delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_arr); - - // Broadcast to all incoming groups - size_t temp_idx = 0; - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - // Set the first group index and copy the rest - temp_beta(a, 0, dg) = temp_arr[temp_idx++]; - for (size_t gin = 1; gin < energy_groups; gin++) { - temp_beta(a, gin, dg) = temp_beta(a, 0, dg); - } - } - } - } else if (ndims == 4) { - // Beta is input as [in group][delayed group] - read_nd_vector(xsdata_grp, "beta", temp_beta); - } else { - fatal_error("beta must be provided as a 3D or 4D array!"); - } - } - - // If chi is provided, set chi-prompt and chi-delayed + // Get the data; the strategy for doing so depends on if the data is provided + // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi")) { - xt::xtensor temp_arr ({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - // First set the first group - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, 0, gout) = temp_arr(a, gout); - } - - // Now normalize this data - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, 0, gout); - } - - if (chi_sum <= 0.) { - fatal_error("Encountered chi for a group that is <= 0!"); - } - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, 0, gout) /= chi_sum; - } - - // And extend to the remaining incoming groups - for (size_t gin = 1; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); - } - } - - // Finally set chi-delayed equal to chi-prompt - // Set chi-delayed to chi-prompt - for(size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); - } - } - } - } - } - - // If nu-fission is provided, set prompt- and delayed-nu-fission; - // if nu-fission is a matrix, set chi-prompt and chi-delayed. - if (object_exists(xsdata_grp, "nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // nu-fission is a 3-d array - read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); - - // set delayed-nu-fission and correct prompt-nu-fission with beta - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = - temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); - } - - // Correct the prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = 0.; - for (size_t gin = 0; gin < energy_groups; gin++) { - beta_sum += temp_beta(a, gin); - } - - prompt_nu_fission(a, gin) *= (1. - beta_sum); - } - } - } - - } else if (ndims == 4) { - // nu-fission is a matrix - read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); - - // Normalize the chi info so the CDF is 1. - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, gin, gout); - } - - // Set the vector nu-fission from the matrix nu-fission - prompt_nu_fission(a, gin) = chi_sum; - - if (chi_sum >= 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) /= chi_sum; - } - } else { - fatal_error("Encountered chi for a group that is <= 0!"); - } - } - - // set all of chi-delayed to chi-prompt - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); - } - } - } - - // Set the delayed-nu-fission and correct prompt-nu-fission with beta - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * - prompt_nu_fission(a, gin); - } - - // Correct prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = 0.; - for (size_t dg = 0; dg < delayed_groups; dg++) { - beta_sum += temp_beta(a, gin, dg); - } - prompt_nu_fission(a, gin) *= (1. - beta_sum); - } - } - } + if (delayed_groups == 0) { + fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { - fatal_error("nu-fission must be provided as a 3D or 4D array!"); - } - - close_dataset(xsdata); - } - - // If chi-prompt is provided, set chi-prompt - if (object_exists(xsdata_grp, "chi-prompt")) { - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_arr(a, gout); - } - - // Normalize chi so its CDF goes to 1 - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, gin, gout); - } - - if (chi_sum >= 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) /= chi_sum; - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0.!"); - } + if (object_exists(xsdata_grp, "beta")) { + fission_vector_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); + } else { + fission_vector_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); } } - } - - // If chi-delayed is provided, set chi-delayed - if (object_exists(xsdata_grp, "chi-delayed")) { - hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - close_dataset(xsdata); - - if (ndims == 3) { - // chi-delayed is a [in group] vector - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - // normalize the chi CDF to 1 - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += temp_arr(a, gout); - } - - if (chi_sum <= 0.) { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - - // set chi-delayed - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; - } - } - } - } - } else if (ndims == 4) { - // chi_delayed is a matrix - read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); - - // Normalize the chi info so the CDF is 1. - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_delayed(a, gin, gout, dg); - } - - if (chi_sum > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_delayed(a, gin, gout, dg) /= chi_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - } - } - } + } else { + if (delayed_groups == 0) { + fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { - fatal_error("chi-delayed must be provided as a 3D or 4D array!"); - } - } - - // Get prompt-nu-fission, if present - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - close_dataset(xsdata); - - if (ndims == 3) { - // prompt-nu-fission is a [in group] vector - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission); - } else if (ndims == 4) { - // prompt nu fission is a matrix, - // so set prompt_nu_fiss & chi_prompt - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); - - // The prompt_nu_fission vector from the matrix form - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double prompt_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - prompt_sum += temp_arr(a, gin, gout); - } - - prompt_nu_fission(a, gin) = prompt_sum; - } - - // The chi_prompt data is just the normalized fission matrix - for (size_t gin= 0; gin < energy_groups; gin++) { - if (prompt_nu_fission(a, gin) > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = - temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0!"); - } - } + if (object_exists(xsdata_grp, "beta")) { + fission_matrix_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); + } else { + fission_matrix_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); } - - } else { - fatal_error("prompt-nu-fission must be provided as a 3D or 4D array!"); - } - } - - // Get delayed-nu-fission, if present - if (object_exists(xsdata_grp, "delayed-nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); - size_t ndims = dataset_ndims(xsdata); - close_dataset(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // delayed-nu-fission is an [in group] vector - if (temp_beta(0, 0, 0) == 0.) { - fatal_error("cannot set delayed-nu-fission with a 1D array if " - "beta is not provided"); - } - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - // Set delayed-nu-fission using beta - delayed_nu_fission(a, gin, dg) = - temp_beta(a, gin, dg) * temp_arr(a, gin); - } - } - } - - } else if (ndims == 4) { - read_nd_vector(xsdata_grp, "delayed-nu-fission", - delayed_nu_fission); - - } else if (ndims == 5) { - // This will contain delayed-nu-fission and chi-delayed data - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, - delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - - // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix - // from the 4D delayed-nu-fission matrix - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double gout_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - gout_sum += temp_arr(a, gin, gout, dg); - chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); - } - delayed_nu_fission(a, gin, dg) = gout_sum; - // Normalize chi-delayed - if (gout_sum > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_delayed(a, gin, gout, dg) /= gout_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - } - } - } - - } else { - fatal_error("prompt-nu-fission must be provided as a 3D, 4D, or 5D " - "array!"); } } diff --git a/tests/regression_tests/mg_benchmark/__init__.py b/tests/regression_tests/mg_benchmark/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_benchmark/inputs_true.dat new file mode 100644 index 000000000..8856770dd --- /dev/null +++ b/tests/regression_tests/mg_benchmark/inputs_true.dat @@ -0,0 +1,33 @@ + + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -929.45 -1e+50 -1e+50 929.45 1e+50 1e+50 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_benchmark/results_true.dat new file mode 100644 index 000000000..33e4d68f7 --- /dev/null +++ b/tests/regression_tests/mg_benchmark/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +9.949396E-01 2.047218E-02 diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py new file mode 100644 index 000000000..cc8f5ba34 --- /dev/null +++ b/tests/regression_tests/mg_benchmark/test.py @@ -0,0 +1,167 @@ +import os + +import numpy as np + +import openmc + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version of mat-1 which has a tabular representation of the + # scattering vice Legendre with 33 points + mat_2 = mat_1.convert_scatter_format('tabular', 33) + mat_2.name = 'mat_2' + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version of mat-1 which has a histogram representation of the + # scattering vice Legendre with 33 bins + mat_3 = mat_1.convert_scatter_format('histogram', 33) + mat_3.name = 'mat_3' + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version which uses a fission matrix vice chi & nu-fission + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles + mat_5 = mat_1.convert_representation('angle', 2, 2) + mat_5.name = 'mat_5' + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a copy of mat_1 for testing microscopic cross sections + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.set_nu_fission(np.multiply(nu, fiss)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mat_6.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_6) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +def create_model(): + create_library() + + # # Make Materials + materials_file = openmc.Materials() + + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang'] + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + # Add in the microscopic data + mats.append(openmc.Material(name='micro')) + mats[-1].set_density("sum") + mats[-1].add_nuclide("mat_1", 0.5) + mats[-1].add_nuclide("mat_6", 0.5) + + materials_file += mats + + materials_file.cross_sections = '2g.h5' + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + + model = openmc.model.Model() + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + + return model + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g .h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_benchmark(): + model = create_model() + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_benchmark_delayed/__init__.py b/tests/regression_tests/mg_benchmark_delayed/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py new file mode 100644 index 000000000..f9f04110e --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -0,0 +1,175 @@ +import os + +import numpy as np + +import openmc + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + n_dg = 2 + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + mg_cross_sections_file.num_delayed_groups = n_dg + + beta = np.array([0.003, 0.003]) + one_m_beta = 1. - np.sum(beta) + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + # Make the base data that uses chi & nu-fission vectors with a beta + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.num_delayed_groups = 2 + mat_1.set_beta(beta) + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version that uses prompt and delayed version of nufiss and chi + mat_2 = openmc.XSdata('mat_2', groups) + mat_2.order = 1 + mat_2.num_delayed_groups = 2 + mat_2.set_prompt_nu_fission(one_m_beta * np.multiply(nu, fiss)) + delay_nu_fiss = np.zeros((n_dg, groups.num_groups)) + for dg in range(n_dg): + for g in range(groups.num_groups): + delay_nu_fiss[dg, g] = beta[dg] * nu[g] * fiss[g] + mat_2.set_delayed_nu_fission(delay_nu_fiss) + mat_2.set_absorption(absorption) + mat_2.set_scatter_matrix(scatter) + mat_2.set_total(total) + mat_2.set_chi_prompt(chi) + mat_2.set_chi_delayed(np.stack([chi] * n_dg)) + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version that uses a nu-fission matrix with a beta + mat_3 = openmc.XSdata('mat_3', groups) + mat_3.order = 1 + mat_3.num_delayed_groups = 2 + mat_3.set_beta(beta) + mat_3.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_3.set_absorption(absorption) + mat_3.set_scatter_matrix(scatter) + mat_3.set_total(total) + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version that uses prompt and delayed version of the nufiss matrix + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.num_delayed_groups = 2 + mat_4.set_prompt_nu_fission(one_m_beta * np.outer(np.multiply(nu, fiss), chi)) + delay_nu_fiss = np.zeros((n_dg, groups.num_groups, groups.num_groups)) + for dg in range(n_dg): + for g in range(groups.num_groups): + for go in range(groups.num_groups): + delay_nu_fiss[dg, g, go] = beta[dg] * nu[g] * fiss[g] * chi[go] + mat_4.set_delayed_nu_fission(delay_nu_fiss) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +def create_model(): + create_library() + + # # Make Materials + materials_file = openmc.Materials() + + mat_names = ['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta'] + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + materials_file += mats + + materials_file.cross_sections = '2g.h5' + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + + model = openmc.model.Model() + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + + return model + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g .h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_benchmark(): + model = create_model() + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() From c7fa8c05ce017b2c0fec75d7e9dee2f668a5f79b Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 2 Sep 2018 21:10:01 -0400 Subject: [PATCH 46/76] Added delayed test and made code changes so that we pass the tests --- src/mgxs.cpp | 18 +-- src/xsdata.cpp | 146 +++++++----------- .../mg_benchmark/inputs_true.dat | 37 ++++- .../mg_benchmark/results_true.dat | 2 +- tests/regression_tests/mg_benchmark/test.py | 2 +- .../mg_benchmark_delayed/inputs_true.dat | 51 ++++++ .../mg_benchmark_delayed/results_true.dat | 2 + .../mg_benchmark_delayed/test.py | 2 +- 8 files changed, 154 insertions(+), 106 deletions(-) create mode 100644 tests/regression_tests/mg_benchmark_delayed/inputs_true.dat create mode 100644 tests/regression_tests/mg_benchmark_delayed/results_true.dat diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 93b7d43b7..b9e22780a 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -463,11 +463,11 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs_t->delayed_nu_fission(a, gin, *dg); + val = xs_t->delayed_nu_fission(a, *dg, gin); } else { val = 0.; for (int d = 0; d < xs_t->delayed_nu_fission.shape()[2]; d++) { - val += xs_t->delayed_nu_fission(a, gin, d); + val += xs_t->delayed_nu_fission(a, d, gin); } } } else { @@ -493,21 +493,21 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs_t->chi_delayed(a, gin, *gout, *dg); + val = xs_t->chi_delayed(a, *dg, gin, *gout); } else { - val = xs_t->chi_delayed(a, gin, *gout, 0); + val = xs_t->chi_delayed(a, 0, gin, *gout); } } else { if (dg != nullptr) { val = 0.; for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { - val += xs_t->delayed_nu_fission(a, gin, g, *dg); + val += xs_t->delayed_nu_fission(a, *dg, gin, g); } } else { val = 0.; for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { - val += xs_t->delayed_nu_fission(a, gin, g, d); + val += xs_t->delayed_nu_fission(a, d, gin, g); } } } @@ -578,7 +578,7 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs_t->delayed_nu_fission(cache[tid].a, gin, dg); + xs_t->delayed_nu_fission(cache[tid].a, dg, gin); } // adjust dg in case of round-off error @@ -587,11 +587,11 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_delayed(cache[tid].a, gin, gout, dg); + xs_t->chi_delayed(cache[tid].a, dg, gin, gout); while (prob_gout < xi_gout) { gout++; prob_gout += - xs_t->chi_delayed(cache[tid].a, gin, gout, dg); + xs_t->chi_delayed(cache[tid].a, dg, gin, gout); } } } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 18e474987..fd849b1c7 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -32,7 +32,7 @@ XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable scatter_format != ANGLE_LEGENDRE) { fatal_error("Invalid scatter_format!"); } - // allocate all [temperature][phi][theta][in group] quantities + // allocate all [temperature][angle][in group] quantities std::vector shape = {n_ang, energy_groups}; total = xt::zeros(shape); absorption = xt::zeros(shape); @@ -44,21 +44,21 @@ XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable kappa_fission = xt::zeros(shape); } - // allocate decay_rate; [temperature][phi][theta][delayed group] + // allocate decay_rate; [temperature][angle][delayed group] shape[1] = num_delayed_groups; decay_rate = xt::zeros(shape); if (fissionable) { - shape = {n_ang, energy_groups, num_delayed_groups}; - // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] + shape = {n_ang, num_delayed_groups, energy_groups}; + // allocate delayed_nu_fission; [temperature][angle][delay group][in group] delayed_nu_fission = xt::zeros(shape); - // chi_prompt; [temperature][phi][theta][in group][out group] + // chi_prompt; [temperature][angle][in group][out group] shape = {n_ang, energy_groups, energy_groups}; chi_prompt = xt::zeros(shape); - // chi_delayed; [temperature][phi][theta][in group][out group][delay group] - shape = {n_ang, energy_groups, energy_groups, num_delayed_groups}; + // chi_delayed; [temperature][angle][delay group][in group][out group] + shape = {n_ang, num_delayed_groups, energy_groups, energy_groups}; chi_delayed = xt::zeros(shape); } @@ -136,16 +136,9 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi(a, gout); - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_chi(a, gout); - } - } - } - } + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), + xt::all()); // Get nu-fission xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); @@ -159,13 +152,9 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); // Set delayed_nu_fission as beta * nu_fission - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * temp_nufiss(a, gin); - } - } - } + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } void @@ -179,27 +168,21 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); + temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), + xt::newaxis()); // Get chi-delayed - xt::xtensor temp_chi_d({n_ang, energy_groups, delayed_groups}, 0.); + xt::xtensor temp_chi_d({n_ang, delayed_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {1}), xt::all(), - xt::newaxis(), xt::all()); + temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {2}), xt::all(), + xt::all(), xt::newaxis()); // Now assign the prompt and delayed chis by replicating for each incoming group - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi_p(a, gout); - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_chi_d(a, gout, dg); - } - } - } - } + chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), + xt::all()); // Get prompt and delayed nu-fission directly read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); @@ -246,59 +229,40 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Data is provided as nu-fission and chi with a beta for delayed info // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // Get beta - xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta_sum({n_ang}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); + // prompt_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by (1 - beta_tot) - prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - xt::sum(temp_beta, {2})); + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); // delayed_nu_fission is the sum of this matrix over outgoing groups and // multiplied by beta - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double out_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - out_sum += temp_matrix(a, gin, gout); - } - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * out_sum; - } - } - } + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); // Store chi-prompt - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - double beta = 0.; - for (size_t dg = 0; dg < delayed_groups; dg++) { - beta += temp_beta(a, gin, dg); - } - chi_prompt(a, gin, gout) = (1.0 - beta) * temp_matrix(a, gin, gout); - } - } - } + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * temp_matrix; // Store chi-delayed - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_beta(a, gin, dg) * temp_matrix(a, gin, gout); - } - } - } - } + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); //Normalize both - chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::newaxis()); - chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {2}), xt::all(), - xt::newaxis(), xt::all()); + chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), + xt::all(), xt::newaxis()); + + chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {3}), xt::all(), + xt::all(), xt::all(), xt::newaxis()); } void @@ -308,7 +272,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Data is provided separately as prompt + delayed nu-fission and chi // Get the prompt nu-fission matrix - xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); // prompt_nu_fission is the sum over outgoing groups @@ -316,19 +280,21 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_prompt = temp_matrix_p / prompt_nu_fission; + chi_prompt = temp_matrix_p / + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix - xt::xtensor temp_matrix_d({n_ang, energy_groups, energy_groups, - delayed_groups}); + xt::xtensor temp_matrix_d({n_ang, delayed_groups, energy_groups, + energy_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); // delayed_nu_fission is the sum over outgoing groups - delayed_nu_fission = xt::sum(temp_matrix_d, {2}); + delayed_nu_fission = xt::sum(temp_matrix_d, {3}); // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_delayed = temp_matrix_d / delayed_nu_fission; + chi_delayed = temp_matrix_d / + xt::view(delayed_nu_fission, xt::all(), xt::all(), xt::all(), xt::newaxis()); } void @@ -339,7 +305,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Therefore, the code only considers the data as prompt. // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); if (object_exists(xsdata_grp, "prompt-nu-fission")) { read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); } else { @@ -366,7 +332,8 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, // Get the data; the strategy for doing so depends on if the data is provided // as a nu-fission matrix or a set of chi and nu-fission vectors - if (object_exists(xsdata_grp, "chi")) { + if (object_exists(xsdata_grp, "chi") || + object_exists(xsdata_grp, "chi-prompt")) { if (delayed_groups == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { @@ -393,13 +360,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - nu_fission(a, gin) = prompt_nu_fission(a, gin); - for (size_t dg = 0; dg < delayed_groups; dg++) { - nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); - } - } + if (delayed_groups == 0) { + nu_fission = prompt_nu_fission; + } else { + nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); } } diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_benchmark/inputs_true.dat index 8856770dd..4f2fd3f0b 100644 --- a/tests/regression_tests/mg_benchmark/inputs_true.dat +++ b/tests/regression_tests/mg_benchmark/inputs_true.dat @@ -1,16 +1,47 @@ + + + + + - + + + + + + 2g.h5 - + + + + + + + + + + + + + + + + + + + + + + @@ -20,7 +51,7 @@ 5 - -929.45 -1e+50 -1e+50 929.45 1e+50 1e+50 + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_benchmark/results_true.dat index 33e4d68f7..dede97007 100644 --- a/tests/regression_tests/mg_benchmark/results_true.dat +++ b/tests/regression_tests/mg_benchmark/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.949396E-01 2.047218E-02 +1.005345E+00 1.109180E-02 diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py index cc8f5ba34..97cef92ad 100644 --- a/tests/regression_tests/mg_benchmark/test.py +++ b/tests/regression_tests/mg_benchmark/test.py @@ -156,7 +156,7 @@ def create_model(): class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() - f = '2g .h5' + f = '2g.h5' if os.path.exists(f): os.remove(f) diff --git a/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat b/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat new file mode 100644 index 000000000..e62e65ab1 --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 232.3625 1000.0 1000.0 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_benchmark_delayed/results_true.dat b/tests/regression_tests/mg_benchmark_delayed/results_true.dat new file mode 100644 index 000000000..4b425173d --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +9.928704E-01 2.679667E-02 diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py index f9f04110e..72bd34e1b 100644 --- a/tests/regression_tests/mg_benchmark_delayed/test.py +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -164,7 +164,7 @@ def create_model(): class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() - f = '2g .h5' + f = '2g.h5' if os.path.exists(f): os.remove(f) From c1652bbdec5a2aaa2aa9fc7f0c7cd19f2d94b666 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 06:48:02 -0400 Subject: [PATCH 47/76] Replacing old slab_mg example model with new one that uses a library that follows the library standard. Also had to update tests accordingly. --- openmc/examples.py | 163 ++++++++++-------- tests/1d_mgxs.h5 | Bin 134432 -> 0 bytes tests/regression_tests/mg_basic/__init__.py | 0 .../regression_tests/mg_basic/inputs_true.dat | 97 ----------- .../mg_basic/results_true.dat | 2 - tests/regression_tests/mg_basic/test.py | 9 - tests/regression_tests/mg_benchmark/test.py | 92 ++-------- .../mg_benchmark_delayed/test.py | 83 +-------- tests/regression_tests/mg_convert/test.py | 2 +- .../mg_legendre/inputs_true.dat | 33 ++-- .../mg_legendre/results_true.dat | 2 +- tests/regression_tests/mg_legendre/test.py | 46 ++++- .../mg_max_order/inputs_true.dat | 36 ++-- .../mg_max_order/results_true.dat | 2 +- tests/regression_tests/mg_max_order/test.py | 47 ++++- tests/regression_tests/mg_nuclide/__init__.py | 0 .../mg_nuclide/inputs_true.dat | 97 ----------- .../mg_nuclide/results_true.dat | 2 - tests/regression_tests/mg_nuclide/test.py | 9 - .../mg_survival_biasing/inputs_true.dat | 90 ++-------- .../mg_survival_biasing/results_true.dat | 2 +- .../mg_survival_biasing/test.py | 45 +++++ .../mg_tallies/inputs_true.dat | 122 ++++--------- .../mg_tallies/results_true.dat | 2 +- tests/regression_tests/mg_tallies/test.py | 51 +++++- 25 files changed, 359 insertions(+), 675 deletions(-) delete mode 100644 tests/1d_mgxs.h5 delete mode 100644 tests/regression_tests/mg_basic/__init__.py delete mode 100644 tests/regression_tests/mg_basic/inputs_true.dat delete mode 100644 tests/regression_tests/mg_basic/results_true.dat delete mode 100644 tests/regression_tests/mg_basic/test.py delete mode 100644 tests/regression_tests/mg_nuclide/__init__.py delete mode 100644 tests/regression_tests/mg_nuclide/inputs_true.dat delete mode 100644 tests/regression_tests/mg_nuclide/results_true.dat delete mode 100644 tests/regression_tests/mg_nuclide/test.py diff --git a/openmc/examples.py b/openmc/examples.py index d48d26839..a5138377e 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -1,3 +1,5 @@ +from numbers import Integral + import numpy as np import openmc @@ -538,20 +540,20 @@ def pwr_assembly(): return model -def slab_mg(reps=None, as_macro=True): - """Create a one-group, 1D slab model. +def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'): + """Create a 1D slab model. Parameters ---------- - reps : list, optional - List of angular representations. Each item corresponds to materials and - dictates the angular representation of the multi-group cross - sections---isotropic ('iso') or angle-dependent ('ang'), and if Legendre - scattering or tabular scattering ('mu') is used. Thus, items can be - 'ang', 'ang_mu', 'iso', or 'iso_mu'. + num_regions : int, optional + Number of regions in the problem, each with a unique MGXS dataset. + Defaults to 1. - as_macro : bool, optional - Whether :class:`openmc.Macroscopic` is used + mat_names : Iterable of str, optional + List of the material names to use; defaults to ['mat_1', 'mat_2',...]. + + mgxslib_name : str, optional + MGXS Library file to use; defaults to '2g.h5'. Returns ------- @@ -559,71 +561,82 @@ def slab_mg(reps=None, as_macro=True): One-group, 1D slab model """ + + openmc.check_type('num_regions', num_regions, Integral) + openmc.check_greater_than('num_regions', num_regions, 0) + if mat_names is not None: + openmc.check_length('mat_names', mat_names, num_regions) + openmc.check_iterable_type('mat_names', mat_names, str) + else: + mat_names = [] + for i in range(num_regions): + mat_names.append('mat_' + str(i + 1)) + + # # Make Materials + materials_file = openmc.Materials() + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + materials_file += mats + + materials_file.cross_sections = mgxslib_name + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + model = openmc.model.Model() - - # Define materials needed for 1D/1G slab problem - mat_names = ['uo2', 'clad', 'lwtr'] - mgxs_reps = ['ang', 'ang_mu', 'iso', 'iso_mu'] - - if reps is None: - reps = mgxs_reps - - xs = [] - i = 0 - for mat in mat_names: - for rep in reps: - i += 1 - name = mat + '_' + rep - xs.append(name) - if as_macro: - m = openmc.Material(name=str(i)) - m.set_density('macro', 1.) - m.add_macroscopic(name) - else: - m = openmc.Material(name=str(i)) - m.set_density('atom/b-cm', 1.) - m.add_nuclide(name, 1.0, 'ao') - model.materials.append(m) - - # Define the materials file - model.xs_data = xs - model.materials.cross_sections = "../../1d_mgxs.h5" - - # Define surfaces. - # Assembly/Problem Boundary - left = openmc.XPlane(x0=0.0, boundary_type='reflective') - right = openmc.XPlane(x0=10.0, boundary_type='reflective') - bottom = openmc.YPlane(y0=0.0, boundary_type='reflective') - top = openmc.YPlane(y0=10.0, boundary_type='reflective') - - # for each material add a plane - planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')] - dz = round(5. / float(len(model.materials)), 4) - for i in range(len(model.materials) - 1): - planes.append(openmc.ZPlane(z0=dz * float(i + 1))) - planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective')) - - # Define cells for each material - model.geometry.root_universe = openmc.Universe(name='root universe') - xy = +left & -right & +bottom & -top - for i, mat in enumerate(model.materials): - c = openmc.Cell(fill=mat, region=xy & +planes[i] & -planes[i + 1]) - model.geometry.root_universe.add_cell(c) - - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( - [0.0, 0.0, 0.0], [10.0, 10.0, 5.])) - model.settings.energy_mode = "multi-group" - - plot = openmc.Plot() - plot.filename = 'mat' - plot.origin = (5.0, 5.0, 2.5) - plot.width = (2.5, 2.5) - plot.basis = 'xz' - plot.pixels = (3000, 3000) - plot.color_by = 'material' - model.plots.append(plot) + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + model.xs_data = macros return model diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 deleted file mode 100644 index 0f747345a8da7c1cee71928d337a5c590dcc0e78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134432 zcmeD^2|QQJ_g`5;WoeP3lI#^)6e&j%+GHsSS+W-q5|#D4TCxjSL)Mf^(uUHaO=QU$ zZITkAQYrtdd+&SCwa zbr4ZRE(!_<#q+`N{IP;DfR{rr*JBB~$XFpDb#f6VBGPT?V7JR&z|qNJm#Nb(2Xg|q z01#L|m!U{lIEJvW50iHW29#cGcpwu0<*#(S<8pkQR5zpex)>Usuhxy`EB^5~I>PAl z@#h#2YW~U}yqu2FXaSyRaRhW6G7LHnrN^T9Xxj*ck#YD(2mBTn_&CJn3Y9tnK?Bpz zI1{#SaQu8ZUvA-={tHaJ2#TL`|NS3r_4UdOgwX^m?9sG5^a3w8tr|@i*P<{I!_%FQ zV&Hg+ThS|HGZf<1PIl_R@&qK%wBj5LV&xI62jaE3plQ~*G0bkI zp-F;g@<961uyk<>nlFIiH7TJNXf9%^SD*lg9dOEI|X)XJZK> zh_0}(c67A1+hMZR#{4rLFQTaW>*hiRK1u^CL1p<`?f&XFXl+EPKyKjl;czTL7Auz% zDV3GrU~cbV?r6Tl$;1gMo#c1{j<_SUAKYb6lI5~K$_?`Ue`-}C=WWa_&3BkNnE&}43sMFv!Op?V+yTMsr@tScfJq|$9P{VA{`zow zIX=^i*XL+uV&Bh+etJ0&h(D*Vxs- z6qiqXOulhEdU^jwa(>yz7ziw=4#61G@1OPmaQ-kNdZhn)Fh7zR!SBC6YSgIDkFa9+ zj107X^@RLz&ZDXEe<^>*no+t00u8+}O#Yg_)KgMui2^|p=hUgoYoX0}%*6ed4#B%I zBiw7^#4=7QN45)d?Lan$EWtIZxLbUIDT;XH}5jMAa1gtwwgu@Ap zTSgZUVOgS~7qOBEe4}P8fes=x_ATo0<08R9qipKj#Rz0k;T16?f!#Qs@KhQJXbJa% zqRx^)z=HFRV?ze-R`J}!r;xN8^NPMcGF;kV%X3nl0*tw@ zEgq#(z^rGE*iuF+^oWFPV%$N6B#l%7^M_Pe7m>Qd-;M^S*?c7f_(2&%*7M{_u9yVydD{AXIaUf0(`{7@ihhB_13f22%V1qwa2x{MT}zbbQRE zGmT!Lyla$8)Fk`(3 z>`Ga8Y;K1KoKHAox=Ys+v=2AWBwzFd$%_rbFO|ID5^1yR;hSC%JXv68$QEy~4`LEm z@9_rW>K0MTF(TAnI@IiMO@h8R`wn_7B!hPDb-g4$3h)sZ+oTFo;Xq>zB|(P7qD3&@T${{ z0?l3JZk1&eU^~5e61OoK#`TUlo;R8T8#?&r_+BJ~Gr?rRD1@$fVBR@@J{4k>w?DKO zqrtnZsj0=CG+5%PH$^SY2X+g3$@w?>f_dB14=UIE;OK`rJM?DnhlEJM$Hyx7gK+1j zgs?S1kh|>Vl;GvT5cW|!)qiz3$Ow$vW_>CWF0UW;;%s{itPpy_f5b8Y>ilYh0)i9a z$dtrN|J-D-TAIr~`e_QRjm~{JsxJ*Ho@kgxlQJR6%4U6NP!?z|7B#U^%7*ouG|eX{ z9EX-16&c!0@e(kce0f6l94^I?7lBc`xtFUVTsvjgl8{OuJnTeIXlCB8#daJ^tLf zb-mT#!NayIBfbW@m%R^eQK^LsXV_TZR@6d!ldr74S{)P=Tu{Yz`x zphJt&M_Ei}QZ9zMi`-2WI-57mMvFHg*^hqkH02j-R4!|IUj3m!eKhZlBct|#8q zgQHPZLwsL77+&Fj#KF`6e5pMW1#=UCxp_&)ea-}cMO@~j%kdB`|K8~6%6O1jqP1da zKpfb1+=xAODi%mxTPoL|i-GBTN0lm{h=u@mBev&J2jQHeOziaiQ84+6MfKPNkx&~` zbf{PA<^zlI$YYN;o*8X6Jl2Siq}rf z0-MbwqMYVY2wOs>XloyX`)@^PPdKx|Q?!2KCX;MnQatZ2axfcMC$G79>RdK-nca$b zQjgJFlUB;}@FFbI8coRC!%1YPf> z!<;7v!I|C6KE9U&Ah#@GdzJcr5Iy#Sx~JU_vh?mmd7SnIx&87hxvwL7vFXBUj%7aJ z)#7(5g~taNZiGwwSo=V3-Q-9UUSCLdG8cWR;192CPNyiC2Z1XGAD{i&P>^12$WE|3 z0Qs3b1y{YIK%TkN%F{3gIDKzriN1;h7qQ5=Ls1D(nKeh@P1qr@7<%WSM1X$-c^LN5kePtL>E z%RDg$buf99l|;+Y#S6yD|8ic0uBYJZ=D6RB!*8D_1^vT$6278`5%`k_xJH!4eUbt>DS9s#PGysq8B)}29~zRr7_e1?a zCL}tE{kRS#*f~gWWNxt2lwY9v2@-dG#{5wV{Dxf#~W;Y8f(UX9(?Hsp`60`^X+~yfpZ|| z(bSjoE!wc+F@1cJcmA*<@0THFuyr*0aXFNIQN$*~`1l?1JAWAw_%4Lf+ZWudRAYJ_ zuVk?GF8cK>T(61Y4-Nvq)QdySm%nu%C+k1dlP-f$`g5{Ty~y~-Iw4K&>-7p?wl zf5->VVIe^OUOxUUKXiXFe*FD=?+NG|s|0+X;!u7>(<-!kaXm8PM+^&b|7k?f`w_U^ zQN!d2C*()PIq2W_9*J|H9RD*e^K;+VR#Qdmx5D(oQ2Il5Es8&)Kk$+AdqH~r!G$%S zhRF}kjUOEk@mz=2g!_kSSh{#Unvct;04Co!9=*Kd^!_gJOTP-`6waS-_p^=vp+7|% zR;;FvhlqVX$1D1E z;~`f6P)`nrb*?|-A(2`*=l>oGVA*Nf=ml<1O0jguMl>HE*NPh01OIXGrM(?$UFTcl zZ1%r|Tn%O?=;dT6JK?fvpgfJ(iU0UOqH7+#olwN?bLk93{B`3YF4%a+Eg;&i;T{iZ z(i_Ns`V`)p(#`aD2Bz_KsY2a>`SdB=o>Cd1`o4EO1fPff8DIF;_df9RWYOnwzv{2&*Rml^!RxcKc673{bTF~S82E3` zu@(5^IlSJV8y7J)MhWo5^uthkM5F&uUF0{SM^HZeZhz_Z2p7hH1WbN#e*EaTNTdZ? z6Fv?Lv2>Fanvct;tnolRdU;3h{yu-d^si7(;e7n|xJcnY^s8vYirMsW5k<3MMcyw% z%wX$X^y6|U`(m{XZ8AQ7NBq=ZMg+bKp}2j?#!Az`V0Qn<0Fd8c=h#W_L+|7Bp~2)a z&ke<^_CO*2_e;I_qt>sB|Dm3A!Abjnfv8?&`Qts2?CoDCLkzoJiaWxCpbKF6h5d)x zeC3C)pEd3H3KDWl5xd=ChhE@zjMpAb%VKha>l0mT?17&Iex6*F{t|Na^Y~Fc!Vg5o z|2)U8X@nmG_|fu<@T1?7{rQy|{2UE>{Wg?eWsiJ&r~ilR!4ba-<;U;x7x%01Fq0zI za9zwk;(Wl@yS~?ZRd~6B?PI}Dqr=a!qd%Yyrw2dB4!7^dc){Np4rQMNu=;TL?epah zO#l3`l=!*i;U4#_-i-IhmtFNK83^oL9WK5T);VprhdOTiP%5ngXgdintv}J z|2A$U{fqJA@81tA4MV#N-w!#IAHf@i;^U)X#E%#j;{MZ!p!XwiyW@h%5l+aDil@ki zpf%`X^^L?QP<{wtjQ=yP@^jx0^E`kOkPwN&q4bD-G>SK(N3f3j%>ca~!Q&W(nEc@E z_|b8Uyco15+)r%6(u8<4AD2&EOulhEdU?m`{axUf{uRn8oIl_0Z_EBezlt`jSWO?t zFg`e}$opl88En4-{kR;;zR(iTCgbCG#83TYMBuv+N^f8AbrbBz`>7lQaA%NX(N<=Skd%~K8ro|4U5Fghrbp44v{+|P1+FNwy_5I^$YQKbB z4Q40kJ&A>VT_Yk+| ztm%J$AJ0X#B!SSAis$@2#O+A}UBCZ5_VCU9d3Hi$0?GxPb7<=Ki;L*~Lq2#83!(Y< z^6_uuBF4WMKiCJnH;eD1Z^=Tts|RyHhw>v5PN4YsXc+M$hK0EQG$QEz2;A-jVRD2M z@}uG+8kuMf_E>%2J1&CH!~Q(CZt!#Sm=RKNe3KoPHs(nBuW^a7$lK*RcG()4?6J1p z$|7&*#~Zve4)4?QBdOK4TC5ya0Beo^ITq`|Ejq{q^JZ z*_d0J?=W*P|MNMP&-L0ln3?z2IT*eDZSVj6N$<~%!?0$f^^0NpXehnalY`=q=q;2F zzuRAWy@khN)G+zM`SGLUFp9ZoP5Ah;!qT)nG#{7Greg!~=;a-!_jiF``g16!a6W!} z9LDM&`f;>j#cKLEOv}k(Mcyw%%wX$l^y6|U`@(e=Z8AQ7NBrVnMg+bKp}2j)+!BH( zR;um|^n!u#_wz5sI`lq1{~AmlWgAdD-A1fn41B2>ez#n+%1+Fg#%l~#g zYLDsBKU~Yt6@Ix+qKi@VV*sibS^qevPxsu{>k-3lyIlA>o)vam;~CDuzsDEAvaQbl z{e3(aU)Q5u#dH21YGB#C0)KxW&sD@OBCnwrIF*H1y6HNakLxGG8SH^Uz%Y`li5Q7^ zlRhVZwpTXT>*jdpgUtqduwkz%wVtEENhbhg*V0Q z!%iQ9`56cIQ*4tVWF?QH>5EiYd2^2$IWH4N?L4dy>U0cpvu)0Cxg3Z0ET#t&*-pZ^ zmR5_8Ryj};V%aSoeG2NfDi__4&IMPJlEBWLr=dn+X0RQ99%Kv7xY?GR2dxX1^eQo) z0iAv1k7W5X@aeJMo{gqwz$5fx&Q?V5AL}V*Y*vqe#_qJ_!f+}GZ*1B9>h?Z3XR(@hNwy8- z?MYvt#a<1QDi*Fu=Szhktva5MS`i?zh4IMZP)Qg1*WRo zHloKOz(aq#XYL0o7(d@spB3WE;s)0J4Ao z(x7fRx2(cAcX)J7x_V}TEm&~eHkYlw2R2G6os(v!!5H&onzm;o1QN5Bbl1@!dC?Q@ zSI+LB8A5t3JZ}dqd$RIz(Up5}XUw?OFRaqwY3K9ybCr>h@HC@BRo(~0#HUo>vn*&XvVSdtb35_Y~T9uY#OYMirO({Srix($C511_&~1dP94Hi4^U)#e$F<- z4q|FLUep93^s5RsdH1CO#~jsS#keR~tfA)BxyBc!p2|;GTj~iC{_5ie*VsdJw91t$ z4)@^2)J!C1|Jbu~W9tdZ? z)n_$M2l-4*(tV?Yu1zGbDL^InbJYLbkQ`e zSqGtAfuU>SRzG;zuyefrG%vVXxFleP#7-!VVY(D_`yOnnUMS1in+gxq2n)+;k#J?K z=t|j{K5%vKvbVgWJz&oDP$i3?9bj56J|R`C8bY||RjhuN0y@XfJe$T50dG9HpUhC8 z!iCu$HCwjs1J(=nMJqeDL-<^&wJjFaV3YYNi;W`%Uad`i6a6e4tm{ikE9=QHyK}jE zbHN^{Ske+S!*m-Mz96of5?Bo{buJ6=>Kq0S-q}ajv4?}VPI0D@7#WsIBb^stV^f-{aL z1IdIB;6wo8RVz@fCd*GGt;x$s?!qK*rkyWsq8 zN3s>LlsiQ7+^vT5g-SL|_DQhrVS4G9C81!oGyLxJOGFTrw2ip5zy(^*ldc;bvVy#D zevfl^s$s6HWmdFV5;$iZzsS2f6h?DA@>~9p2)AMn^S_aG0iV|!tGArCg5l#I(h7!y zKQ!1pmVQ1m)Vd1qEwnZGyk%rv1?%141mNo`_^N>--fnDN1yAB}uJ83eH(u^w`)2>` zIlcA{cDD9TbLo%sC77Apn7EpoeQ^Vy?BeSLI6Z^GFZB=aXHpjBkG(57$?$H@}WI-0u!0 zR{~fAaQHvSRS8xUF8ZI7!%eO*8ovPJZBFOSWat2;Fe$5k7~LwA%Y#6+`J*KG5%}`L z(Mhuq=(cFGkRSrLUMk`gM_^y~#xx-WN=+--)DPVqYmd%G;G)Ubtt1h+f7`X9c?fKN zPfJ%o;5mQI{p%3;>N&OA7=c0olvqau&JC~&GeKaMVPJWG{hdWIA6O75V_|#rHK7Cc zdS7;ai$MP~+u7bBu$x8QrW=8!x+|~u-;Z2SH|aeBAKgi*d4)h6ABS~!b1L5;`IVF0 z*7w5=n-p$#A+SkHysQm@c&Cj(R5X4!K7_F{oPKk!95OE3@;$052Tzt6jtda@=#XP7 zTV*+DQ0&_ZOUogyT{$MGq#X9_z3OzYxExwCU5gzrmV=4bzI{r$FWp#;iO`Pj-qVzKlxU)FLcU zEkpu0TLqNHWn7h?Q~?U9&7r~U6%dtRZsPL399Fy{)USI{4!V!-m|bWphfJ*}%cHBy zp04&CLi)bC%Fq+~1 zY>3f@8;XWXlecL@g-U%-qq{cvK5I&`YS{oQt{LsLkJW<@Zv@oEREIBL`*2?R3FD?KHJz;Tk7&h+ESY*sVxPm>&i=gs}g{eu?v ztNZic=NhL=B5>2S1HSVS=;V?m-d}EX(t=7^1lsI9CoG4+l%_@gN_3Aw;K^Bg z^84Zan{Eyh5g2%4VG0idlPxwcpN7Do_P5dk2=tp@m@xx^^WsO}?N2`>=QGbj;MIy$ zi~h93Cy|MQ2wY?Ux-$_t>q&#E5CYv?4hZz)Df3uA>@Uwu`J<080)MyhKGI%#Jx~AL za@6zu_Bian-H%MWgE=L5*L+TX=|34`Xg?Nw={Np#ew1P@92Wc-YMrALi|ga_hLLrS zA1j~3t#tZz4t$>3Qag~+AGNPKts1ST7_0Al@2kdJ@#j9{k$u(ZSXcba8eB>JtbNr( z=_9d+XpfEPBV2NSFG#PCxUlBC(Ct6_(fg(CAE6cF<0BGF=RHC5arrFG8;Cd9emSfe z|9SAG|Alf2=i|4p)7kS3B{$F+1b_P~D}3?sR^i?JH- zn$O9fEmwot33@ph%1&6lMq7i+(}-`j2Qwd&jg-9IiMc7h~=jkwS*3@Hc3^Bl6E6H8F(Ge6l3@$65wFk<{ zgHmaC^x>o>8+SK?FTzF4*~FLuduAGVGY3UONp7~xqI-^@+H0T^G)y4he4!HjMGOO6=8+=)xCxtuEp`@DAb zYmynTeW8;w;^IRkw@*n@qE!Q3s$2EgN9SL1R7!EeahujQTrG|T(P56i>=PXZ6uI0Gke zJ94sZ&+?tXRwlRSK5T)v<-5&u4wXal*m>KhWo5uKk6Ixf(-_d<9;YR@&gTGhenkf#>~8{BKD+A=&(- zR>G<+;PNC%&)uUOwy3GiYHQ8_mMkersl*td)}2&tyXyq=a~8DCNZbi7GSNAk*Bipo zm4U4K7UeL#&2il1#th)Scd)MeP7LrRU1v{@+6CQfALz0uIe>EY!R}ytL&)uWXSP+P z9H#hl`zYPa08WeEqK8LfV3YLT)GpUu(EHkRneQP7SR`Dp$vDLb+21?!cF2r!5DwFC z&fS#(flEeTIJ7MW-aOm>e9O6Au!wx})ukH_AZ#u7q3F61NOp{~ng8Z4?ChFYQ+6yJ z3iQL(txiS5i6;zGb=U8L+1YFv@^>6Srw3dnKQRP>MMdRnyY7O)>M4_ggHyqe_fgJ8 z*(iwEwB5PtssrQ)&mEV^YY!U}SQf}U)q^RyhG&}*{!8*`R!tE}0?A&pQvr`dVI7Ub z^OL>>j6XfuKk>OS$S}Ei?q^Ve_iJAo`aLU$oEOb9d505V8ShdhAID%&>2$TyxVsg) z%i4v61r0!ZPg$b8q%sr-&J2%vRSs;`OWp6~#(_aX7t6gZK@euVUY%+3R+u3y^Ubd*;`@5K%NqhA*k!4J;eJziH>K`Q&>cfiJZj^z zd+lmCv?y__91@2=@S@?O+lE+pmZKNnbt@2jwl(sMxn>58$mlY7X$+=Mvm=@|tOK4? zjMs{UhO2QPVgAAIQ(_QId&T=G z(#9G%8Bnii~Tyg#uvu^bFCuQoh-69=>Tcbe8c4?_AmkL}4*D=;U> z^{z8DhpzDx3X4Rw;ntFLjm^pBP*hg)%1AFBx;9>NIs7OHnnXKyWZblZ<=Krb16e%)r7d<-&}c>aeWy{;F3|t>7ge zQpAza3PO%~kr5fKaBQsVqmXm0@Jj0Z&Z^Q@sBpM@k?&!xMKhMf@8%M&|iQYWmHUVcKj6xk2( zBI<@}1QOSO(sJOE6|z5R+MQ`9l{z4z_B9+77LkWY^Uc zw*z(I8u#ezc32{~Z|{`YcDOZvGtcaRc5v9-L~*3GL*n68l83TAASZ6Cfk&YSoSR2# zd)?>(?gt!lELc53xhnY3QBhBLU!T2L2F`dwD|E`VN*;=RINZ^e1e^j9##B zy#QH9-wVRbH?Oz3<^>{Rn-B48c|$b!=&`#wh|sZ`yhA3x=2|@l; zh+c7e(U@Esc=ZHq$bU|Q3w4(t9y~^aOVbVdi0f(4`s$vJm1Q}Pyhg1iqjP9$`H z^I9tS7*G?txu~%B!A1SR`xMx{?9&^oTngy6MmmiPrNCR$S!p+&Dd0R`e8xOe3N*Ys z}0))5j$p~C>zBO~hwKSi8}O(pc}2)Nx*>m5kq_ugND+D&GH z238GM2zr4lW%}>@7-M*1*g1DN9{ss@Gz>4BAH~4&sbTkK-_ZG&1^>Q(xX=!ZL z0k_v3`UCNJ4bZf#AqxM${&Hg{da%AnDG`d#GVd$n`0I3@kK9Lm0Mu@4--BlhKc z_0X?T4!wQB{pmDJuj8%w@9t-@>cZNHtK`qgpS|yZem{%um;vPA-S7t#z^<&uqIfuV z5SGs7Ky&bU6oC!L_@jvbw-bsOW+|p;@CWgE`>(g3MV1R2sKa_c%bb0J-PQW75Z?N%@QQyGOrPRg zz~hq-!Cp@M=Y8CPIjOHoiW*XI``(E*6Da_JJynJ^My)XOj5=jgP!)71mnM!4%!h;n zHTlZ-+(1J1;nT~7AqBI-m$O*OEQJ|D8-?q(wL<+`21U=1D%gC@b_@e0ABp=JvWiH% z!^ND3??0RhDM)V)cGNRi24UgBiphIhph7Ty-dE_&|3wDP{;Zn{iZD6;^@iz7J1Dlk=e|D!9;goCkc$pXvPoq35WTOOw6j@y!R`YODX^jnUN3NzX$k zBIoMeoyRKnI3MO5f{EISo=|dOP6%IXNWrS~3L||kfN=5AQe`)vLu5?C4t}+Ja3IJb zxpP7RL>`jKoO8hw4yKjJs`iEy+_BrUZ5v4u^A2D&B@8ROB2!|Lr|(ItB&s zVyth|taV;cacoKG3I5Om!NYwnt?|p@(+YQypcgMdZ^Iq~_D}a<=IZ9@3vLy_X>Zr@ zLC?LQ*>Cavz#X9lMVuE5=cy<{C!r|&=Cd}KzJp4+l2#20Q|4-pUQq}+bvyIhZhM0v zv!Uj)`=JFJZgDiuLCR-mu(e*cs~tq^W~rH;uL1MJN3@d~3*p|TNBq2EB*-ALW(6M# zE8yKAUMXn30#u?E4n*DV0L#Z73&WPzf!NlL9O1%?Fm|fDvB6_9?C3RRe4HL$;J;u_ z*|>EpA?KFhM17M^h@YKrR57|97P<6p)0lG!By)K-~D;o zrp)bxj>C6CIzs9|xJ1;wr1BzMVYW4%^o#;6x`CYXcf$*6vkTT=f2#~xiLkKiF>-Fn z!;`ZgO{#-TzOc$Eq>C`Qt-(+`iUL#1U0p713NI)QoqP9!nF=hJ67Y0E0&?C-k8(=* z;ab>TX~ESXe-Wte(K1a+6qs;k-iD8#!U}HBU8yI1U?n`WsNK9C*$-gLn=yLl>RQ-% zT&ZsFsEe>Jar5HrCuC4g=T#Cv6;_}tx2aC$tSU?uTT-vPqyrlA`cf_WYG7~C=|JQ1 zLI|{e5p^Yi45FOYB5AH+1uImF%(+5UpzplVxos1X{RdNzyi_f$fnJN-8z*KK0?Sg? zJV668oL!J9=CCTPz(Uo@w1iO&BK@>k;YB;#E4eZyF`x!YO#4P{4Jd@wY~$n#xyZnE zY<}BrnXrP&&ho1#2uOb!b$P8n(++8Vk)te4Yhb?838N1Vg-|kXXS_)b38Kqi*LQJ+ z6|^UEJ2*KXE2QcshBwW_YEqdT;qsxdXO zVx9`PS|*8i+O@-^(_1ob2-mU5DFCUHVL_q;H31H=Y6%I1uUt`obC21ATE`%>F$bl zSedq3sbEwM^mLt8w_Q>QeQuHKc-={G`!$pJ-bv#jH7=EcQ=ZPo>@O{z(7|A&N_H|lW9*k218205n z(B=P?Nni5gf1NjTeO~#e{|*;377-XV3JqYe643cIBZKVZf5s={pTehMzz>1p#g8$c z`xDm__;(oXXP{ITV!bldI)cU=6d%_kBkKr1MVyCCCG_hExIFPty|Yy4IVsfyE5WypnKW-;1-oyxNwGz^=(Bhv^V+6>Z{d3LBRzj&6GM= z8`+?_y{iuTR12C^7u18o*wsQ4tm@%IOvwF@A@xu#c=GbZ+ z(|UMeXXbk1O+7doRW-!-)q~*`{zn{44ZxS$BT+Cn0hpVYblm4m09eFjPP!Zq(em$& zj;@RcnI&2)mIlOuZO4t+Q>S8q)U~B@{ka&JzIRlq@`-2&U^ilW9(54TDayo7-ya2& zuUJ%%JrD`CF;&NGZbtw?NK#(~`JRKr-KiDfqa&bcbkd?55)lw}?sQyFOaw6Vs6&)- z6f|p^R4^@z1zBl_ebt{5K!DBg&~4Ww5K1?>rCEI#2sK^mRxD|7ieDko?oB#e+NI&) zdN>neR{Dz9PR#n-4C+#?nHT<_6529@+-No z`#@3Ch1DF(e88*4?^Ftp4=~&am-ewnzI#wNInspJ7m}UKMPDlT!z-K9DGKI6;L5?r zXTLTSq*oiV6YLH^ekM=BRj(+JXYRD}G>idG-&4I``CsWSCofe9Z!rWZ>N^m2VZ83@~zx(%EM$YR+4dL%<|Ni>jV*ESHKleM$vIG1YJl^xyeVS~a{T{TRtgIcK>?|Ej zY%%}kPrvA&eXm*IkLU1ufA061^Tbg}tDcR*q2@Pfk|^HD{08f|-we>tZ}9z^J(&F9 z?D*09H9MqGIYj>w2)xqhmF)b1@)?B5H;zXy?>N1`3;c532OY^cf4+Sk(DOgBUo&zp z&WYbeBEC;M2iu23KQ4!|FNF&Rj^B~>v+vVCze*{%eaXfM*1#a^QdBM&kd>$YD|}rI zUr+Mfiz3o6{K4c=))_5F*9C;qfl|IvyU^la>8Co+4JBnjDIUW7}itAbB(g_gAwq{{VaJ zhl61xSArOCa29=T`_GoEVZ@JFBmDU5_nKveM))y+AHu_fAN`i>PkV>QdFb`qP<~bM z7PK|E9vtzjez@u%Ru$lW749`CV$@}0_7Nu*U+?-}`I`MfyTUnlmS{a?fRqnJQ_7Z?@%cjUglTH#5`OTB+i7~>6@Q3P_V3udCJ+wo zUe#ux5e%2BDOsN5!=Rp8dcAC0By5gXy>(_33F-+sos*F7DQiBfiv5^P1Q`eC8JALt zpdqp0_Ok*axbQb?oh%}P{_-v2M;nR2Z4=m`T}K2)=awr*V@Lqfo5VC1l3nSi!t7D?WVG0lq@87yagbLlKHsv_FQjzn=crIOeLIt&e#YuC$Xi%{; zc|95VZnq`phkGSVzEIe8<${}vA81GCzdHKVA8sawEpl8J2qEgPwur9}1}Elg$%@GL zud`jlZuV@7go!HGn~r`U!fVSukMpHOxYHOZ@;sjiDH35@HYO3_pk(L@nNvh?7dq9V zewhekpS{xKLi+#tKAYeb&xvqcg3IppcoHbDWZx_-NrFyZ-IPbjceR;&E$&@I`hSu8 z(PWPz5+q$em-6^E37Fo+PkSLm25*@rpGGS(_~|>9h-V;htVQyrPh>Drao+Ppl>&aF zPaE8hr@)jaPlVZ6sL;y6VYP1u6%P2FX{9})LcJOv$h*;?hs)qoijWT^@AT$3onePXNlkEAt+x#K%{iXAn%7Jj<@#fi;rom9Z+V*%iQy6^6^N?6!5DAAPYW=Eu ziD0~->x~=IZd+gGl2=(o7=LZ;(W!{s?^5Jju@r$@jLuUv5k3T1-=3~=mk8rR8hQ31 za^IL)KHiO!1i52RaKE2}$T`KDk53!vZ}AhSl)Om5`^fO3M;-~X1SPsJw~|2cewX-j z2{N>lX{nzxCqsfyubosD8SGYHk-x!AfojS+j^4GqQI4u~E&>V4L^h6;~p zZHbOfG&lrK9R4Ccu$fI^Jp;2Zq`S_TJzd5Rf=4gh(NW_MzWKZwMJog0=5zJPBPPMX zKhgaHae5eZ=BL~zJ4S-L-+`bp%|yt*c6#4cr2Vz?xaI`K5kay#u}m|V2vt{@<}@RG zICN#s#8^Zh9CKTAOcCM7DJ8}a*$;@YKZbFA=xZVz_%wktdpZdusB?EIuOh+O)zzn0 zTa#eZ*`3R6;z^LN&K0_=mIPIAwp#j4BZEkgNPMgw8Dgf-owwo;8Q7C8mc3{rgNoJL zjtZcF>DVKWdJa*5;n?0-%MTPNBroymK;%E6xQi#Ui3;{dipbZH_J2HGxRC{sf2yXI zZV;m{aK^_cPFv*%*+*qI6g>8aI3L;+evLqwXR}}av_&wSwO&@3D;x%wM8#k6yF|j| ziJT{_s*rxHlk_w{Mg)=y>DFEkWc)`u%%0;%go20RW!?Tn(7nJ@EEhopS%d94#1taz zc#&r4hS-S%#ng?fyAZvhXRw`s=z)zA@3$x*dhiCXeU_v?2`=_>xyHtlK>B1*pGGM% z{x#+~ii{@%Z`H=zEt+ItR?XZvB@)@EA6eiq;{h2Mwxuq0TuOl@b!g5+*p;kuBPyKR9lr2(9TnnsgsqFUr9ryQ9g`0;d?4PpUTY((FHGB?*_5=*4+0)b z+>l1vFTUl%LjR3{aONH%HF0M!>=BvzT2wp?dMgB4lma3_Dq+D2e`Gwzh>I(1Mf%-- zsc%oqULwq&vwts-6A{*%6VybJwBC4yLxlZAxKW`xw{!ZVq=7PZBUTs+a94BtgYeR!^6YBoN4uCe8pd zEEN>n=ZDz8XB$#nDX6wDb~ zP6abI(}3X)8ACX+8>s=cY$5aiKuj3ieLlY6|cdxR-Oj(+VALTRD5o|*^3Kq~$4JFfjRLMkm>&H=|jOc?a_CjYaH}v0U<2#Mm)AyBg>|2FN5I9wPVXh$w9)(R8 zo*O{|*UmnJuqqOWELs^S&V$&yrpEjU8_BThc4>834g!O6!dHAm`~YX($14pfASrlu z)cgw+c<-YlEhtL`UNweXh&35hKRHA{v=@S$?n>H%3LCtMlW15UWf=w-kEE;&L;wwk++rD2BiIxE7v~QL4?%8%%(}9 zL;&OaJPL>$6($R42j55J!Zgk95*rEZkB1R%Dv-d*sgo$W8+kva#nedh3<QoOB`x`hkcNpQSz0{?TXITWgX2pDH-E z?sh;hXiT>}zSc1emcHw*KEMzK=Z`I|JF%4riL5e9Q;~L-&dU}dOhDv&%dCl(AHCt2 z3+p^j1|ldvrL4ckLxd;0651XJ5~0aek5Pq4RIUXY3GPQ z%jUMZ`Gg3Qt~_luo`Lv-jy1Fgh+kl=@6^6H6wwozk8~zfkYL`n8BQgLKU7Q1G+X6P zhFyMLt4O!Va6fF_#C?(!;8H*2y1|zMX{idX0-uoaVD+i?l?xS~2{4YH$xVZ~S!o4us48sRG-ggW;AwWAQ~w7<}3> z?&$IPQP4qnFT=cu2=%i#>?VBh20ddBIi<(maD|pQ-m<|P$XXA&a_@UXaM`i?lkMJ+ ze|`ev4Q50>OfCD)&mck{TUz-Ogbx}$2Dh(U6Jg$`1j}l~Uc7(&T$t|)GM|_&f2Q*l zqEEM%SnNUkgO{Rfn*?o0uCS`irx#s|w?Cq;&V!nTgdj|`*Wgp=lpwuwa8 z`}E98;d*Zf_q-tDbKV=aEKLm$Kkf~81xhE(Kj#fgq&6-(c-0#yFIT+MLGacbOR4ql z@djZnEq*O7B6tS1`ma|dLQtZdl$Z?>=B{;~x*oA7Cd>CGXOs~k+mGN1EXey-%E4Kw zY9tV1bEdKfBWYhj4LjsLGEN(&PdDa}Va1V8tVN!PUGO7!$|CO%o;|FoI}x#m)5|}- zpNsf|>M>&O2WC@Y{bsG8+gGS?^})2aPdsU$X(u)B;cg#reEz~>XMr!cKknV`9_J5X zdC}3=5dUY(^cPq84g|vqKFg=CQ^LURy!?Ef=qLzD-nP2ty*Ie&ZdtOU&>MUL9?L_T zH^j=A%?}LmhEtxlQ3eU#kk@s(?$r@Q4hj#SzJ1Xf%)^dxCe(SuW1`g4d5Am|m>Kyv zNFnynW`kNTqCXvH^1R{mCcZC`{R2mMla1$aYk z9W`agLFBw(t)lpp9B)Vzn@;e)+g!gn_M19#8Nw35+dhv3l-0MpGD++*`bMNFL=X==UkhVi;;GhzgjiA z$s5*MyG+@H$c^^i@gXnxk@-R6!yJj_h#cJSX(u}qfl|z3p^o^?L6e-e`Q1YF1$$ZR z0(KHCU%YFAj4I;)aJ*T&4w)ZP#@N&@yi0K4CJ)O(dPN z*2WsqgL=k#5tkDvuz4%Lp*%Mg4jOQsosvd{+|4UitwH+#VYuXS>-9dcq}$hgRD>^> z7*2XUb0@MJv9*KEHMyVi|GF+)gsh~v0-rI0sEG#Nm20Bqc>qiGUC^3cU&(p zNBrKDC7DgyL^x8#bzW#C5uBPg&-O?3+tQhjLy~n7`!FkW#R6MIUvTP+CL#W@hv4B= zYDW-%VT_>5L1dh}N~llfN9L1TRo=dTFNBQq`IUD(k@@hcz>B?U;Uq}Y@!bCD1_?IQ zywI}bM*8_}%7nuh>b7pldLfWCHpA|I) z@rx&qT`<|UoCs%ALf`h!cS?eFP9(i1Lh;GA*0qyKuzk#YXHO|)-qR&CO9ioS!V3AD zd?+O7^88RwOx3?LW8ijojit-G+;T{ zyirrt2bSyC-8n1a3+DQ(&m@}p!7dH|q*UhpFn#XXg?%Q0Ag8k3fq#22T z_8<4vNam;}={Dawe-kl;dwl0+;rpLr|oX49mI ztl#)ta*#v%^Rn>my~h##<(EXrzlG>=v!mRm*K$eFMB6rVK?5@XS(Vy5W;7YPjUzM~ z7LlQ=@qwDOEg1wAb#>++N7lR8nVjJ{8OCik6=IX3Ktk)$PWinQ2$jue?kS*v?drri zxnfkjQd|UbFk!`hrmK ziYIj;elT5RcB$<2{cw54m{(GW{lCYY=yF6e7-YJA_~gq%p=@WsHpj~m@XWQ|;7|_Y zk1|D#mIx$49dTWkD)L^ilS!{ho)ZbU50lCge1vaM42;WNKs;A@6E5B*%X+q#3ESO@=(pZh{71q^yCw(Gv8z{}YkBRwL1 zpn2&;h5vCsX!v0GX=$M!1l$`dNm%3$;p(CH==J@f|Hi_u*kX)-S=pPo@&*8BfJl1+ z#=Wjs7G!5LQDI?=T#rW<6<$5yR;fq5cUV){Z_OoK|Bs(E9N0tP$Rkef=MV-Of!pGU zG7->y;Pz?Oq$t?i=95o#iG#1|u9>GNFn*=wcS8#4VGHS4y$tnnv|`A|YOKG`6r#1H zqMfpC2cPzA4W3i{75)mSucAJ_i%T2x1&+K)V(n52L|zO&F0_#Xv9=vy0Z4ad*Vv#H z(w&?aD4&u`fu4lc$78(|*vb?iQnSVnm{!hBvLW8PZtU*FqtU3(Ct{CPpnbF0amDoy zxb8>llFQxD&I@3xJ-+b1Kkhq4Q#Yvqn5tqCP`DTXwjxPK&SKneOLP?f*=j2EDsAq$ z7#Rq>cKzcoQ-i?3PU1x$(qFN|rh#7!?SE$)mloa#;9nuRq2^2!IGfP~1S!UWS#RPQ zf0WbV8#im#^`ra?xQ&~&_=0yBrT5}ZU+DG7sVeKh_>R5si&>0c#0ROx-udJUfn4^| ztV|T(Z&sFOM?bDd=w>C8E(LZsudB#&p}^G-m5(|SC~&l@+HAaq0yj7xocpxE501W_ zzE>cFI0Q7Io8nJmd`GgTCa=g3*mFY9+r0OKg!o$L>$z;O^+GvyV(icW66Zci2zwUJC z_UVj86sRnT;=Q>Z;}j`g`!i9m5#=QbiAX=&=m|+Nv|DK|A3O0hk^*As<;rc16oAjR z(aUka`+6G3P4W7{(g#K--s}27NX&y~dGu@St&|FuwqtxN?Klva{b3@@Vxg0{KkzLQ zICC7&cRDVDd+S?&;N_n|;*0Bia(r8<;%BbEuJmOT^@ z(6THrw4lJ<)5%f(NPpkEtXB666nKAU{FVd8bMCLYI2M5PFPyDP%--w=XR|cY4`9EC zvo?oAhQcwxjNev#^Oq!5Z~U_VdqU!EF^kN8WAx?u}43Kpmabh74^X2(R$(lp7(~6 z$MX67frWQeRTbC&(W5=n>ZtdZ_%3sN_r)K)-sm%GBK@QzE9A~y4S-d>Jd_-y|EayX z4BtH}IQTl=YzYViiq^)90hA!HW*3r=M*p8Yw#idqI24lG2iR4H!{L?3E$KY5C`j7z zpcOg;QWanC0%xN<8l?Wb1U%t}*XfY2<|TKP@}H z_KCP3oKg>56@c`2bY5)l!uLC3`?ou?P58mSnJ4jFVn50GgOcaA{=nMRxU#guA2xYr ztuO!T50iR#j-^`#!0;1>*cVj+P;q~&R)RF1dzqiNu0i?#hT9Sdmdy2)YdwR2yYsTg zvFE|yEwoj`sxK4@9J1Hn!M-<}JJl|&-xvk^HY7eWXp4p6V~qQ58&aUFzxZSY>cPns z*3s+M;{Kh@PGH3KR+SVI<6l96EgrLS8zs|X%)u#{f)|#O#)!>Xj}FW(yzTw zfksM!3T^%E(pPR$!KT%zhY}J9JA}nE$iYFdG*3R|1FpZ3Dj(ma_E6ZdmC>oQFC6ai zdT3+_;`)~{ro6ox3##I_ymALH4!`%Eu+nB+uWsWg1(bJ&wv~+gaUXD{x1VIj_{`g) zw*p?JwfY%fvZBV+frWmPCI1{8If1eB_;8Yonmp>Adxunpk*1vw>G!nF8BB zIB^mMDd2vyZn~cjnDQ{Ae&eEb;zs&aqBp=kIn)EZb%AU4VSJ(h#Mll}fN3Lb z=TiqSQq&#I3!Sy#B3ovMZOo6!Cgsw>RU-c(mSZ3pUjpFlPGPZkRT<^jj zedkg?#Cb|dzBcR!1nJNZ>`4EUTeL4-a_s?I_3CYt%d*4c> zB@owt&@Jh-;%vb#1L}2!a}Tx_;kujg&K-J$`<)UR zl6i@r0uBr}-qB;czKyt>%82yam6!3nv%}9?z0=yb{_MH^oyk`y;MT`BI#o=8L%ls; zn{S}qdn?&q>JtSz-w1?rZt;V{_P4xE&VI1rKzHPtJU>t|%_vJ}@P~|2GJ_WSwaH$` zOWzp!gY?Y(@;wEp_gg<2-dY;~?JZ9w+V%xNh^42)nd$)aJC`hpMt}co@@vKQc~t1M zOlvVi{hy(vcDlzP2zZRRlZEm9U)LwM$cZr6kNOtV6 z`U{Df&1Ycz`Ba4YyiFd{zdr9+=j&vIoWAj=`)^#( zd2arvjutNu@7^_<0MYad%HMT$K=w@sj)8|AK&0h9C5hue@~I34?BA;8cj85DTL)Zx zrJNXkuLImY8eO`YI$$*CY}2V59bl$IAnY#dfU#@augqZo)9qFCMoXeQK*zX(XRUh& zEb7(QE-~zYn@sAA1ri-_585+07&<^iMod1Cz609U_!jWhbU^$O9~u^hPH4NB-6*%Z z6Lw_`M@1~{goGq3Gq+D2hzCj2qcMs7LkC(duRiO59GxM>^W7bAoqK7fO-Ba|Z`oSA zxD`LIJD5>A#m(jy3ME_DBUt~K5^kN%)a9}Af##ny4vTSO|Y0D-l;xE35_{?2vH=Mq?kj3 zg_{IBy9JcAi7v3QvjCy(!qgpU7O*lzJp>oj?#;~VZ^bR-~HN8WA7c$ldL#~6-lM9 z!7=rip&}QK;ji9{@!%LFQJc+;qxdDd`#*i|r(9dYk7HwJ#<8D1pPUn9<->8CF&OaT z$UpQ{bpwu`Zm~Q+%~M`u+yB%3ES0}d1#tXN-T!~k{q3Nb*MtA*{f7U>WAoo`nyZt9 ziR~#T8Vh?f%b)-8okIIFE+_x=^Y?is4zAzj=KK8lFXrdZfBtE{nWOc$`~LKgKfUjt zeEvRf{<8m?KmWzg_r>}1pXc{&=KKwRr{jOyh2QMS`TCpx>v%K2<-fgl`L;rT_;0^c z!Tcvb){p+%itoRt@ZGPU|M`D5jtud8J@~x7_z@pqUOwpw-=1iG9?gkw|Kj=KdFP+| z-+labyy_dL=K1sY$1j_XeY?jz=f83C*YV4M-xZ6$;Uz3U^yhE?Jv%keiQm;@{_Y>< zx6X}cXMZUjf5iQM_e=T@eZU{jjrsRYZa?6;{H1#1dHc%J%*E`d2bcDA4bSyo|Aw6zC7Q*mL+_fH$U6- z`)8upw{Pb4XWI|!`RDKYfB)Oxkz84SUz7Qz`I))@YPtGLxJ^IG$#0z#^hv*zr$5e# z|NDF8e?q~J=Y+!di<7?VnfZIop9lXayo+D&=WlPO{_*$`^u+HQm1mxopT=MBSGPa? z^S}Jx7sleLCf7)Ca%D!&;APU2s}C#_8X6opdnE~?XoNx zoC*Dv4lF*fG(R?ag5DR(uiZ;Nhk1=^OQ$<8byC1mU(ft>3+7>&QjMapu2`U5_4QOM z6?VN4XqM6q0>6dfHI7ap@R~KM*k33d);hm`%X1_Wj)y5IM#mHD%uXj{GkQUGYx8y8HQpe$ z5XysYctcEmoXIVFBAnS?Y4U}g1ZN-bS8q8-g3n_*A_|Ada9rm)o!3_~qz-NF&wqn; z>m09mUt?Xynwe3p=35lld!f0w2lFo#%R}n!W1f+>fPO(s6czL~_Pv;K3xeiNC3kf+ zLSQ$I*^S)o;lO-Yh5oQ|B)l1Z(B0D!4RY%q9U~`^;2Kk*w`>^^7%#;CcZGPI+ugot7j+W^d?$-QJmQ||-%htE7NAI5s@=Z#CdIw!5yPX)C)yNhM|K@k12XM!mO>E{mYRF(;cCSm?}`dcHx zg|^{o?MO6SlpSl0ze0kw7mSDn`9#S5*xRjl&KopdO;)I5eZuOn`N7PBb{-KFIJ2Th{iO09u=zo9X#H zLHUG$BI|QcST|9~JNMcPPP1zq_;4BbS@SE_kNb%bYit&EsFMhNhRU&|2og++QKANo z$sju;7RRvI2RMv)8`}}DB8L=Go!*CaN$2DY+A&|vzk^d+@}(c#Xp~`USs4Jc!z#63 zLZ~1?&^=Rj6!VDhaOAt@hQKkJ$*=WW!og^yZP7isNI3VhjqyIxzyB6<{FQVP?6ncs zg?J)})R3JTu6e`em1X{{r@bJ5Eo;BNk0(s2Rk?D_5`f`z3D;U50>~d#VP`iWfO4$xtJC6wm03#vqTt_Mu1bVL$%TFNv_I|lKNg=R! z;qps98sYF^U~u&K?np?t2xi;x3~^+8EpHu3gp4E+nt~c{c$1Y|l6le# zo*O6{2_gM6Rti-!gSf9H^qKFw62Nq&!{aD!0_f~~GgrNu0CvP4#%;0$kaZ1I8jB*p zz@i@Op=tuCy;>r^Ptp@)V;M8nHhY5MYcG$H3@=b#c4Qe7(HkDvUYKCkBf@0VVv*;) zM0k79=D|P+3HvS>u1%67!#VYA2f|XUSH9Jj&-w)Gxpp~EvUmH!#TMpI;nykfs^Ppq z>^(ooVA$BpxFP^V9E!7&voW83>UwLOc@V7FWAo&ES_n8u_n6gbheLNfyq%TD_3xF| z5*>^NmX}S%PT?dFsM+myK8Oetqjc<{6mQfYEY5nzyr6WW?+n%56Uc`Y%%`5}K{Vs=x5MWi=rWe?DuV}yRKm!%~VY&+re=7B!9s!e?Ru`&=4(J^EDdIc>7yD^&`QO#tT(y z-bCnpu#R)?tT)87-Wlap@d7dL=0ja3o)GxdF2Ny#fco>+yJ8>!Pb%SS8XEx)kGt&_ z>Gyz*W!u{vUwFW--Tu$&`3caoqL=WNM1T`+<~q7x2;h)uzUlaFPf)rc)u(6Y1(QK1 zJD!<)!(mHN{>V*4_$&_=9e0GNrWe29r^67$y1s^puT)j_+&;1 z9Jjx~w?H!->dy;mNEk&zp5r6chQ%?E{YLi0)`gd$pf>fPqa? z=EWx-P`|;!uL||U*5}(TA3h+!vxZVP*DOycpuJyjtnLMxU*Ash>3f68f){thwi02{ z?Sthz8;QU@Tq4L}Ljsffg8_?B|8q5{ylQw&hM;lQ_fN4N-Mdt<${*|9vdF4k!l?iH zN#*a}-138nx!Y+g*9E}-MzcG*m#7f3>Y}#2RS>N4xq0_}We6PbUG#rdGrPg#C zMnXP&&cP{$7#K@5PF6I>zO(%|#2U>}4wFS&G?=`he5z3``->;E-0_Z$WA=nyDv>lb zDEB%mpWmomM1XV5wo3-Cc)(H<<;6Ds9?;-fqUV(90b~2ERFB>F0OflEE45_^!0Y55 z>sUkp{mmP)P$b+Zz3#gvMt2(wsju zEGdyrj>EiSF`cVUMnUkQiRa*=t05pG{^rGJ!*Gz85U6)|j0DM!@D_8f7&!i^enFKM z38-uA$Fh`&!0LIvMdbzRJ#D8_yFyRcnY40SQzxG9me(4EabMr7(Js8#;sHIGbLT6< zJ-~&VeMh^F2P76$mTFmeKx;RxZfS}KT#$_G^hSLUzwx1L9omCZJy!;3WIZ9=(|KHx z9@l?ywYl1e7tkJkxsrdv8{`HZs+ZvT({!LBvdowSmc3S4TbGc5H%j9bUmMo#e>tsM zmG1++{#`z0Ay~hbcV}#fig-JN83i3T5O1njc!U46Kim?C%`-Sb1y^U5^Y+F;VA%YK z(Jn3oC|{RyTj_*@`S6tk7fd6ezL|TOJYNiy%N?ij+(iPHC+fa!Qbc&bq-&V;&~r^M_*b_009dxmpxe?z*DGTGi%}jZh>_Vfx`m`7v`pW)I8uF zg{I7t-~l^t2!6TU<^jR&IsBez4=AsAOv8uv0G)}{7pW(n;D5LDxnZLh45=*6yZsd9 zKyiE#Apq^4w>P5>3gG%1G%egYLIM$80{6QFGVFPz=k*ZrDZHAD^1Tp$!R*)v?-R!; zu$tX}$60SbsC4FEqtfON*N@aFH0(t@sb{$_35cU&!J}*K;}-&Vw^ofitA@kAy63qD zX1M;=O5B+uG2nVlHf>Ir1imAtJc?_Gp!RZP87=nlmS;$>v%~drcwnD;#u?A|6`zL= zbs^p9!TKSF9&mOsW1bX~2S}X`@?;xzhn;IrJmK2t0b*MeqGR^qJg<>HcPjGd0Gldd zJpuaJ+D1O29=K~d{e0JXPl$S4)u0~X1@V=$bKb??V5cz?s_R086V54N+N>n#n9M4$ zuOflw+1P_SV#rXrWtpPmDIYN2lgK%&?+bT^?T(IM-Ph;ie#hWF zo4}8Cl`D3ZsDGFXgd;J|XKpKpKrL};<&Z=;q!o-Br>RAP)NmNPAV&8jyt?s5Z)=e)B{#av}HVVLpgY$72WZ{18!UHC7NC#z}~HTdkP#p z!DWFwIm*}zMoUDFJ$3Si{HZT;L<1r?oOhc&`IZRJIfVT8pkG3Bi+GXCgbWw&xQC1E z@PT*i(x-F~mu7Ow3s-%tceDE(NE#PL`=2kV^9|xFg{&x}X7mMsW^(b@Rh5C@Hev)$a0s|w%&CQzV z2W9bT^lrm`&h9!Ew1b{76J)sA5x-BZ{DI~O;@EJ_a6G^| z-esSI#qS}`Mv(W8J+oZ?FzTCjV+SDse5_X<&X*2^YEe<97Vlt4%{K<~s4(c1OqhGt z839>AYBiCFBQS8Ec>W5?8|Mrog~&&QUJ?0L$8Ik$>boy}v&9oU>ON_NEI|9`{OyOI zj-y={T%b!9~H@vX0U!v4)JReq}f<3`cMyyF$yM?BmT_7e7zy8%Wgh#m7DFpAH2&r z6?=jw0AyvJto>X@1!2=*lY-VD@N#Z8Q1%Xml<}}Z&y^9N_|~Z4C^ZTci-YWsE=B#~ z$=sWAfCO4J57>v$59j^JJvMTP2$$&0SJ%Du2AN08OsFN^K(p}iu4zecunFE$d!Nx8 zvL+T@>t5^)Q=RMeN)~zpy^w)E<8E)*X&)W%743*+ul(EZT=a&CwuNlnym-FGIzIYr zM1;$1TikYL6CqV_*SQE55^&^xIqBd^f@b<7*KRH%gZRE0iT-#p82ix;t0O)|^p~za zF|_|hEjTOR_#pmHWY)7ftm8==ajbsF?+0O?#q!Q9OG!*M|%XLm!^HK7)Q>$Sq4G#H5fYgyw&mNRpY&v}L5eOB@dur@PwNnYa4~xCs45YT zI5au%p*>Hg^AFc`#`UDTmbDtM+uVGzT(yM=S2j8|JVAOl60WCu=#xNLhH-Gyc@jL& zgbF$)GTh`~zcq@_!9Sy5W#HPN7XjSCkay2nj!!KV zt`G2pTRVq?$C$x!wR()R98!g?5@g7YQ#vtol?3KYO|n9G4l7Hj$2Bh}f$IL$I+Z>m z6wY3Gb*_#Gt?RPyF1tVk78Y?C*HqlEhd3Vd=2%60jGbz67N57yTs?wZ${ ziY+<*a97YPTBHPVCJqgnE?ADZ0;Ohc!x2HCebja9LsAIrb4_=xT^9}{A6w4*Wn@S^ z^6)Fi7BYCWEoyjq3)h7#UcU(Ku#F7lPnnz~xM#3=vp(wO1g+8@p+`j6e|h<7?`uR5 z6Fxoajr1nC?^=|M@q?SXPSLBfi11o*NKoY#5q9`9&mJ2g!qo2CYbTL@O8Hb)E3Ui9 zv^eSL1riv)zjcBB5eacJ?iS1`lkvGk@-5TJF#SSekvaN35quOsb;K(Zn2I~exd7uH z>RdGH;l2>T%Bgpe3vo9#Hr`!#8|%Ig&+d*vyg7eMszwpwtZrhU^JH}lfXSsfqh|`J zK>2j?)R1xzeDPdIiO>uITj`Gu`ZVDXb8-44E8-LwC)S50w(ZJS1aqQzj8gKfewwL3t=iq~vpz z5Mk3LfMXeB>f@O^zPAxn**Sv;#qZ>Hx};7B4F?7I(i5je>J+iUMIA2tL%b`TzU|jp&3+ZQ%W9|2iBZ5Acs+}pu(-J51smpQw?@K(2 zy-GuZ@ZiRi#VV+0XNc8X(C_5CL3KRbfboa!{p^lXWRTRgYrQ}w14sPj6b>2B5qC7FXuMsJ4RKb& zHmW{Eyp7%I{o^x7u+ntTm=*s!#23(gdgk2r5a_trU`fXj4$gwT_ODUTD#ey&P-w|; za!RP2AJ@g2{%RE+uG5Q~=NcP66TyIQw!012{fzb9Og_}xeS&8k@8N!be`>1}6UI#s zHp?C6Mn3GCeflvr0rz{T$Cg{TFRtD{=qJ=lgt=>j>u)0;SZE*i9FQhK-{t1K$LQzp zav40ktQz(1WaGOT7LA)vMSXq}- zx}S{%2l@(~9vGqi<1Lf*%fR#C8JGRcdlF3hT*`iMjEuORm#SiJl0i)&B6e8J2UO_~ z&t9xSIe6g4y-N^rsH`me79dW~W5z8~4-mJ*j4wKGaP3d{dK*$=7W;!_-Lsv|AN=9M z_6LpxdnyRg4@&CO1wkitWhb5q0adOST+A2`2-wZ3ei7-9{?s{Q)=PqY`83i3Zg}3g zW^CSo`ihgjhF1yW5)qzX)py`}Dw|Fz-8hElxwuoTZ;U&rq;pWX5W;_R*rfEh7QJ*Y-JU-Km=YZ4YBj+yUkU*Mm zdDUL@cd2Rx++Pha-r;|+*bDuBuBxCpx9x~$D7&QfRsrIA-i-hg#5wYGC|N&-aj*@? zm%gyZ`u)O@(6m0ZgD4t4Gqqp+!1cBseZ$Q}7;59+o~Z95c6 zgf}PkRQRoku!@~Xj5a1hklLG_pV4oz*uQFRvnmmiiC*sNE<~W^bT+le{qd#p`nJ>O ziD0T;_Qb4*2)o1fUY}e#`_(`7oy-|@W~?#USMmdqI#rX#}^B9B9Y9?E~;?fMSH zF%#R|E~3NZ16>?Dx-KFvV|H8Jy0?huboSZ#!-}_kLFK(wtPtWi(8LCOPC=ZxSoyCX z55M*U(gjr+eXKhla7gPqWXB}?&qTAVW}iuTT{=PF`@RHXm@#400P_ugrht6>-~(KHit zU1dmwqz>*QEjx%{Xj(pyg#5TA*4lXj`EXtkHtV8a?|$~h;ib6#hc>&!H!L8*jz^+T zBsY=3yMA-s*%Z__(d4p-4LImW7ASoCpv%d%y?Kwjp&G59BjGZoAGe92VToy&vU{^t+Getwg)W)}4V_UJv#2#42OI=NOmz zJbrv%4iWYaoA=Y9oIq#U@>8Cke*2C5B4VNbu2haK!Hw33TLT zM^iBFe|b9a(}#94^sjrnvP%|moVCP!*{`GjBYRgY1@X#q3nnt+aQz1yG`sTL5!Z#A z|F)u%AAGTD=eoYyA9x%JSFhp@05ywAS%&je@Z`UIXGA*)gc7cfF1#HAwD%rQ#`=cC zv3!G9l3^%!H4@dik5S*5?9f%!#rF@}Xq647iQp!dxG%7R2vTLDYZe?wd*0-EZR1gt zd*0V#^$I8#21%yU%0!SXS88lWKFnnZXe;j{g3y7)xUId+>MBDzEHB<8qdFDd$)B&qyFDNOT@HkDx?STCD-nmF%7_Y zu!Ww5?gvjQeA@J$rPnD4@kN$AoTv+dXO^#JGKk^e%Eqd4`v@6k*1SJ`4dsuWOdgcO zc$ky-taI)t5n3MhWt|zqbNT-?vz#BZv0%jv#FII z^}-@G%2N>{)ZIwTympWXhqskmStk=AROW(a3fhB0uQe^q=ZNs=+NDP_VkGEYCdu$1 zm;_1uS2`p=q93p#VIU9Xe|OdE&G+u0{b%rGDHrE=h zZ14pI(p1Gdd&Ftul$BvbT%zGZ;RSApN8;t+H~aO;TV9X4Mbk((LuTlPAl8bJL45A-a6K}CljRZ2ig~`cyULAbJ{YEMm_xs|w z9e2Hn5FAXXeP@T~*jl4(8sx(z@w-qtd`sM zE8>1RWbU}?CqKbw`@8xb93+^j^9sL=_Mqa5(8V11zOVZEPG<#nGOR7%rS}5QzcSff zd8f~jVdIqOo&ZB1xO;2C*<0ub?V1~IRo;#7e|?4?KkM;@S)tcEjd1-P?c60kAr9Sz z#IM3b8t4aWzpYf=7y!=iatz~2sSq963S_e&a5?+1pJgxvinf-zh1iAv3P0k+-|E`en{V5lI zTaVw$Bc#dwHh*4^{Eo{2^ft4+T5&oVQ&xBB@>*io*3x?%+i?7ZaeQQWVqg5T-s=>IhQ{D)sYJq>nM z75hcs`;%5DPFkI^a&$3sv2}8!p;?6&Ectfn&$qx*%b$Pozv~y5;XUYS99~ZE#&+%>VDExfg{O`_>|9$<^|GNH!lfBu=pJ)H&>v_Ka{lBmO_o|=#OL@>X zS>HGpkn?T)E&XMX|83qM`s=&E{D%!c>aY1a%gpccGtZ8HcAaI?m2YzR?f*11P2WF{ z7XDH`6~4>&{JbCKeg1j>Q^sH0b>DXKJb(TdcK-2Sa{e1fe{JUn{H|F2W1Z#Rym?Oi zt{(Gu|1f{)eED%-{?_?&qWG6m^oM=?yI=Z$=mY+EzRbsO=!<^2FaLe(F}uI((eLK= zckcdLj~e_#`Tpb0eyqo=DETG-f1JqchT#A(D4Tc{@}p>oCAN!PyEqN{4GB* z{>C@WId4z?;V1sj*W&;36+ilk3g3wl`|fAV)AoNCkD;mIyKTTTPs>l^ukCfWKmGH+ z{NLaF#Kknv**M8zR z4$R|x@O*#t`SI_M(>9fT=jbmO`+JkCU-RReg#GLCF`CN%Ha?ktUztCKzl8$Rq6D@33GhE9P%2dl+6hNe1rj6!YVVC&ICxcxByX680Be8_QHm~!^eH0^_+1(X)D%Op48-SX`z5qHBIbQ#F>yj zuuY^-(;v9KF4uWdF|Rhhhh+`smDQBIjpm4o0G-nZ6esRSL*;E(#gQxVuqd0{bO;h* zGhKx80BaIlt?g4(qe}t1S5~qc7*e5|pp#YhCJiKH(w=U_ zEkgT@r zt||8Y7BaHlig}DnPVBET!~AlC#U~#=Jd63v6DBVG9%LB(%Aq^tLm6;bMUwVlUZG^%jB~FUjH2Ps>Kth+E4gHyT%wz&?zch ztm2C*!G5*dhPz+(_(UKcO6{b=ooL85wDOQjiHGE2gT(FfiSXpIS78Td5(xPzcP(Q{ z0cNLZ>AdBspi}aAW!mR7=-Mp9kph`8^-kpUA+Bt=_jd0dx4K-g3RpC8B{&~EW>=er zITrwvIzLg#jhTyaDk_mbFDAdlfmu8`NZL1#7%kL*|mH(338gA z8O&yrV0*7MtG^f0-{E?B8}`Ls*ME;j3hQb&yt1DZ(eMEup56YHT|RJm>fK8jOT?F` zj(hwN`(@=!(iO_T$NqZbOY@Ux{o(66zQuMFe_$U02F5fh+$pW0vB7?QM!ZcNyTc%+ghtvC)2Yqbh!e#AE~YFOY_4+qIws^pn&qQdH`fAK!_2ArT&4)FYUFKQ zZc_yNRqNi{H@SePW&`;q;sxZ^Zc{Wxx>oOqlzFdBf(I1;rh%IzIA}uq`gSx4WJ|33 z>@Q$_jl87h{dDXb?t0Wn(9{Peq*e+nn8N)E4(aov}_U)h6wEd||WI9je#;me`w2KTfe(ApUpWSJZROYDZmbo!9~yUQ1Csf&lz zRV#?str9`Rd{pVFP!g;b4p_;uAqBLJv=)6_p9*br*GO-e(_zCs6QM2pGC}!%=R=Qe z*$`$J_32GpE==&cYdWUqgXjeBjScPvP`8f3e1$?0Fl}$y5$8|@(>7nD8+u$o@>6O$ zKh_N_P5c;OTZ(zZm0fO+ZArkt=G}dBtS>t{d@K2MI_BFZRJ_$I$NujuoYMAJvA)Jm zt~2_K4?N#1IO~dewNLuu7EYY^g~gw5?!AqDP}g3!GGN&52V9p_Z_%jXz87ax9n&K`|SGnW)7NpX9=WmHZNF z75P9f<;g+kQvloy8{R3Y7eReU_r9>xMew0?*G|_77jWIHw$J!185$P9etjGJy05WT zpzcQ;nG^ba&vsy4g^hfVo(tBQ6=`)EPWNG*Q8j~b4fabPv-l#!pXdWm+p9(<Eu&jm+6Fp zf@~_(3$714CzK8+qEF6MAYBeE)B4h}a z^||H$7VA0L9h2>`uJUlVfXC(4K43bq>Zm;8iZt#~drEKT3!NU3fkoKIUaeu{@cI!7 zEKSKBxr+UbzogwzetE?o6gN*2`K7UcZ_S`)rCA{K4hrwm*dGj@EsC(`gacxgJEHKYh zQ})XQh6VJy4xP+~GtRp>-z?1o*H7nGPmbh6hWSA$mBa!#YR>*@uVWDmCDSv}#uUNP z8~l$)xoer_q(dq=HT5!lFii)?8{(Q>nVE>oHMNB)G#hgB zH8SEw@<3GZj!y^e73`zzz~xX}0Ha$j969P!1e|>)+V277>qos)}>~ReZ^I3%J zdPz6nj3wgaEKloNjrEL8Uwu7`;_$p<^tfqut4HqQe&79-Dc}^z2b3knmlvpD z|MZ@5Ey@h`L+>3Ph{Ad@1;$#%bXPy<-+Pi;jr9Zv)xs{-Y6QUB8*yfb9|ph{!k8`3~;S6 zBLmA3fi>klWFU42W_`#YLwvdMBcr=MuvzwG6kWFu5Gq)wZR31l!qC6_0`}3g{?g~{ z|BwR5_lqt#(t&!vlW(vj)E`v5NNU&1v7R!^;7A+xE&X7yU0MzMlwLc`aUj?^1SIxH zIL(Gc0t1&Kd;k3ySf#l+J)kZD49;@Qsajrublwi9grX!^WqXx5xhMtrxj2^ERj0y( z;t(;x+;mvE$#z)fOD0%8D)&43G8^RL;<@4@^MFJ76@u?w0c#VcH%_Ak&=OjtHQRuC zuTR*<=Q*zbX^C;?d#<2uFWh`N!v{{X+e#n9I`LvQ-Ta1pG8n8l#qEyrJ{O$*v=HS( z+}u!$f0HjX=5G)w+<|@2kIiQ3eeng5-b#{0Je{H1bv{D)Uge@u1!?yUZL5%{0*|f3<-513;8+nEEzBPbhrLCnS?Lg0Ku&G@a8D#8G&AoHvl0P$%4w9D-l`m1u0`gS_ zb+T9v%szg3I=L?oj=ZPY;Bfs4_$pOTqrR=^?>bp}_-5qfPYnthtxlztjSw3nOWBvHR=981IK9H6u;5(7+3m-`g`Q!p$ z*t$jF-EChAXlriGwcm#Qtw-9!3US?qj2Wnc1O6aO;AG=22!I6d4k#R;g0-YY??tyj zNT5r;K*s)@lU+;h7uJQsaUQFuDcF}f;c1J+a%wC@8YtDXgq(x=$Fv3l@)w~*X|&&X?7bQ`GX|-SZu; z_t*+xpHXy3q(&ix&!xxC?JS1zoYO0Ybc$h-8+~a-+G!|VH2Uxr;sSKk7P#HO{^l2) z6k+{UA8@J6oiozIddXMKzU-@g!R-YJZt5UzR9f9pf(iDA4UK6^lJf&)wk(+wh@t{9=>BTyd#;L?3hRtE{ z#fR_u+14ode3NhC5N{l8l-KuJB6A+Lxqi?vp1cU<8q1e23Q7h_MAGZp3ztFBciE{c zCp}FW`pVdZHwmC=Yr(Tm`A(D@-hIdD0_xYob`T?Wui(=hf*suG1V7C_5%U-9xRDF{h0Br-sYiS-+ z!HL_IeX=YNR4gUt+?a#m(8o0O7gvJeRh@|aDZMZ-{T%SZ=wdi@Mf5iDAfCt}`WGz+ zXXC(HK9n#hk_fko`*lmcT!Jp=&4J#$DX=G-ozS@}6)ty)o)9^f4i>hV7apF;gpu)a zY35hiz)W&j#`_@`&Q}0-CLB0eoshRE#RV;xw zf@c;U@^SG<@SP~>$A0K4soNOB{2m>w3+f6Cj zD>ETbmcJqijjVq_82(b_BnB{b^`F_r;BFfT!73_ zshz{^Nw6rTlT(P{GTaoBJ@i&C4Op#h1`G%pu&$v#GCMg7Ru53XPc|1?$zNlewDUoS z`LSqIP62$l*5H+qR|vvu>YnddR1DW7H%;?PltTC&@yY|6OX1O>7b^Dr?x3NkuKK1v z05W*QUI$50fqVBx)tqGPKR=}8tb~1+OP*HKd$9(9i~vYp%E7-YKJ^}|!n*jSGza)P z13@!bpFO5H2o4_#PxK;}DrnSBELkB3b+8YzcE*j=W9DqQc6gzW~Y zh$GpyT5!o}i74ocTIn`GiUX!3Gtn{8^U&-%qjso!U`gBC4ybz{udz4*mECSi* zgZKT!N+7xIIy+xb8TfO>+jqK@!9{k7u=Q`<;j6mdxsWErdtp($FQys@(HqXF*}$ zr+cTlbKw$Mvvk?pd^mN9ZU4Q50=U(`-LF=;2vklr-+FFP4BFljZ6EKJfEnjp)8Ni> zxTVRbq_DmmE?($9)3gY2mS{Cuw~SK3xJQCJ!X^+RmEO?S-UvYa!ziN<2~>!)6%JR# z^DDiwBQ1Uy`-~e}Ef%Cfe6Z`E>&7+*!@4h5n5Q^HV9CdOdU9D1_u2@cd0iT0Oo#yf7#%Aez9{%;w!v$sa5T(qqpo=t5D$68<2Cua(B3E=d2eg`>_l?`A>u(5;GQ~7X7 z?x`+ETmi@jaz9W~DuP=f5*inEi-BLNJ0!KK1O^qwORTn+gYoFdqnB&SfqSK>&}^MM zER%n@?=|AyDJ|(fsEW9NZ;i(DxyB!PKLBlrG8De&Y~ z&(+SdRPeLxU-F4519bQuKMA;Ifm#x?G;4JZ>{f`sYE90Eh-AT3f>8muaF&=wEGz=M zp@XlOS&CudwbeGW#1c@yw!V7fSQ#Aj$!OqeC<9v+j&?>Hci6w29^ud%{z0#!SYa@u*vcWcy}*tSx#Cc98;w? zn@fp;{!~N9%g^FKQdn~JKG*YLY$Gvo%BDK645$q( zsRGgJ0l5tB+}|-aXHf=X%a`&GEp!LLVD9k$*WQ)KQ@OTl^H3TjnM#Nf3z>)LG9<}R zBwJBYRAy-+p;Fc|EHV!fmMLSFvB_>O4X6~QS++_vD0`Qo&cn(+`+S|w_xpY4+nqm- z^~dwPYu)Qz_w!uu`+M$T-S74IcF<5)$BaL{E&`d`Op@YnP$AKwl6o+Oh7h$csyc>* zA6AXNAfhz_X;W68lIxAY{hrus^Cw5aOY)+u@P{Z&r#{{3ca`|_nx>JaDlu>^P4r{x z#lncK=Bys!3n;svKJDeTL#Wm2UEi@L9tkRww#3*ZAiwElt#eokJ{&Obyuy1JNe-dD zmv?00eMZ)fjB`17o$cgmIWZ4jMaYu2EWi^9it9l7QRr9M2I$-@MxSqbjrsmEIK@o0 zc$0e!y_OG-7Nb;7+#o5oS$#da> z@Hw-mG7@|5_&-#Sje?1!vcd&&AK1=+EE0B^j+Y89$rH)`>qlrR^X97@f~|$>l*-sc zXfa*q>PzB1Ze4nG^wb0tap$g(R7t^w5W{_QOVV-i`8or$=~?JJs$aL7nghxMK7+w4 zxzLn$>VC;Z=Fi#xj_p?Vec)6CR?AGZT;*%Or^rHttQCfHDR(l$j_N{sBbd?4@HbW_A zQz`_1@vL6QMZ<3MMxamD!s|p+U63 zeuHo{cujp9wtCayW?Uwk;vYkJgIw0k`VtG#;pK-fZa4%P?u12l-Eqizd#YHiJsvw5 zhJozwlhN=YBxsd;I__Al>RNT;2)u-YJf!S%aF}XzQ#U3To@E?ywiokp!I(#8F8@*J z@@eKsC=|nU-n|~(Yo%~r_y=RtqjGH7HE+%@Un?M|`dbFyFcV9rTW?%X>_Bg*keGgE z4LI1kN(Mt~U?*w$mUC4gtgl2Lbeu&)z{JB^QmMq=A8Cm;mZ0MHS4D@WTO@vKx%As- zaz7Z$R3Cr95rOwymv{`tB4B@Vvn{ zi+nWM{|M%LCd$*5b8znVx|u?*xwt-W(gK^FM zoSvxKosmNPpS(tP@zx5cFI_19xtWO|?cT&Y3RSr4z+aK)UIVKk$0d`jYLGb;7}8)C zh-V*$t323f_*GM;#A6E$H5#V9zTM%lzf*ejdI1%WcQ2$^yHJrp8JO+eMgybIW_u#3 z*K=LH>vGH22(U3bOOlBnKP{S5yT!oUt#M@35>-g8;wsF z2yakQ^J9lwsd3P6X}-uG9*_I-7R8_^Lz~x0az|(x>nfmRQyX-h ztb-1miQ(ehRcI667}vwO7$Aph& zQoFV%Lo&73Zo>66lCR$BRWEP^7YbGR%=@z8D%8XNdUh_FQropE&GWHf_`&dlz(O=; z$%O>biy)e7BK~oHDLNm`Z*o&C#}i>$g=vQ?&@MJP-8_Mb1Gjg3MRZoee7fjKMadd; zTpgM!z+MBN*EOe;gadJ*r~T#A(}ed*sKrEIk%pL{L+?G9;Sl`LbLO-M6&K^gxXor! zaforxx-Nl+mhl|EfFj*W!Mj8}bmc2N-g^>O-@+-N-eJa=ee zE**@gG76i-V-e)t#FeP%010mxBv~$>7S0}@B(+qdz(lofo7Hd|$ z$V901676^G+34rrgv#`;1Gu>bB8>PN0W!;{K4T!L4pYNrWv zmqWaL-6Nv|6*#sl*`YCn3A%Qyd3s|d+5~xeCa~4O|KzMezTc|Bus$q|UX9kpH? z8B{QKg*>6mpyAGn>keue;n*TWYb;t%#S~#4feqYbe}LkNJc|QI;(2jlgLoP))J*fK zCw$2rH@vSY2Sq{=GCXyQqVOa*$$T(^!~sGSc7r{1bY=9+>llndZiyH+-ZU))hb2dbf?W~3++QRHKP>^JdZ~EPZ)FgC70R9OUqRNX5Y=iACamfM z!lH;DaJ%5lkv%V~;WI*e(pZh5`*w>vx&v@&Wsb=9WGdW+QY=0XQ887;s%w2J;RCbI zX|^+=LZLNnYT3tdh?ooB-s?s~ha_$P?O+<3rrj63PVAw@=^IOZNIo}YcTJA=%qV1k z-h7qr9*z6<&v-gr=n$3@lk#bg!9MeOhYbjiCcCVEfC=GGJT5y!B$W~mz0U4;`3lL9 zo_xXaXiyq@@-ij4Dl?%oMOSF`nQUYZcV(V?#z0A(i*G%9K4fW|uLv(F#PN@AeW{C! zz-=qR;n`4vdl~OIw>Fj`sk@U`z_kJg-4;~@IWeKUCy!Df9LBFX3(O#Y?HFAb^rsm}!SGx5dR z(RXTHHjJO}EL+^h0NbuBH$p$=f%!`G{2#Lmal7c%ej$w_$i^`G7{m|u6uB(Zf3gg9 z5zivYA81H=5x|>k%f#db`x=B8m1s1utKlZsT~S(8k5)zEp}j4N2Ob4rOUu9IhlVkRZo8=@dxKTWLH?XHX7!XI_Ww?I=+?^Zxy{l;$Sh)<;rfcaFKd4)o(uG zQGIP~DLFG9U%Ah0R3-D@IdSQm{NG2Wm4Ee+Fno8H_E&O{S;>bARN{-^jJ9xNi)KjU&HgVss%p8GX)Y(xvO_jxA2k5my3 z+_I@E%`SnQ;LP*ykChRgrKTyB`7yzB(*MAll*aWkZfKx z+4q}=ZM3f9&*F-oUe|H_Pt|`ZSopsF#rZGNzwhurpEqYc@9yT~=D#^`{bqmP9e&%0 z+JE-E`xp-eO@Ku}k@{_@-{UMgDjBOM`i24PS`f*t}#`kBl+w7^lD%PFV=X!4RgF3M_?R*aRkN@ z_=bR9e8d}l;-@Ni9dLRbHU~X7k4MyB)IxZb<9^eQ0#wL}MGsaKfb(-4qu8YY2L@Wt zU+T}txt;L|%boI3@Vwv4yC4tw<%<*T+H$cnpgJXLnAAZ<(mJGPF+kBh+*Z6S2R*;8 z)9@m767f5$o>*{ZW9c!~J7KO_xSKcU`uRm!m{vPv#aohvNKN@@CF5+=UX59!8<_)b zvzkBjbo0PCx%QUqu|n)#>1!FYwFJjo1_}gZk6~AO$sz{}CU|eOiFVy1`Q!s}-t`*Q zh*WB$v~R3IbW!QeVV7Fuh*y$sNR+cJ;)o47U6$i?0mS*8VMFthKPoE|RiGIi3+={IWKZrg80D9ONQ%~;_(e;>Co(D*i)$1@Vw9hp@k1E0^eCe z%1bNg9=kQ9QrR!oJ+#I_=JlK2QOlvSY-r;Qjuo)Y*GU>@9~J558fhSYdPSc!zckoH z1KtfiQHQ9(0axL8DfGQx+%LLH9TtT#+lIKL(B?h&VNit{X0_SvJlY_MpkU@(fqqpe zhdg+2e&;NhR(BV_S5bxBL7R(-;xl2d(|)DZbpf)P@-ipf5r^v%!%20PDq!$d?wMXC zhJ>o-u9QI~bSUNDmAoekT8-i7IYSgwWlm7oxJDEO8w8l!+$pHIl;S65APOr%ro&P* z3euHNoSG3QimHhY3rveB2#gLrQm!k8n5M*yzk4g;(Czft0xb#HW^34}}-his|L%%D~sJX2Ara+a5e>ZH0L z2^D?FubxyWa#sPz;$wT?SphRHMXY>bpad(vQ|~TMHiBO)Uq;eu6>t}m)WEjYc5-4teyn~i-AkoVn< zjJ@fm2=gd=Zq%!W#X}z--%IgZXR!^ua#lxXV{z`O!%J|T z!Zsl|R2``itF$(sS%Q&xYvjewHf59_%+<}yCD6_F&w%Sk@z$6#DnR^BuF>-+vrQ*V zWMj`4ZQJ7F=SDskV`m@T!+ONqXZf*wgYyctJe9D)B90W*{3mZNt2+w#V;;Vip8a)P7TT1T^aYaN&SySn+WWn&xj8%FH@ z$m<{FESve`^I5j;$8wg9`mvm4TYfBO*@Pdt#Q1pXHY2(THBp3Tn2 zPqP1_WWN+Ix9x$WssGW>g-AORlmDpB%6oIbNLkltet)EAC%+; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 0.0 0.0 0.0 10.0 10.0 5.0 - - - multi-group - diff --git a/tests/regression_tests/mg_basic/results_true.dat b/tests/regression_tests/mg_basic/results_true.dat deleted file mode 100644 index ddb57d00b..000000000 --- a/tests/regression_tests/mg_basic/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.073147E+00 1.602384E-02 diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py deleted file mode 100644 index 3c22e6040..000000000 --- a/tests/regression_tests/mg_basic/test.py +++ /dev/null @@ -1,9 +0,0 @@ -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def test_mg_basic(): - model = slab_mg() - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py index 97cef92ad..c29c7ca1f 100644 --- a/tests/regression_tests/mg_benchmark/test.py +++ b/tests/regression_tests/mg_benchmark/test.py @@ -3,6 +3,7 @@ import os import numpy as np import openmc +from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness @@ -73,86 +74,6 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -def create_model(): - create_library() - - # # Make Materials - materials_file = openmc.Materials() - - mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang'] - macros = [] - mats = [] - for i in range(len(mat_names)): - macros.append(openmc.Macroscopic('mat_' + str(i + 1))) - mats.append(openmc.Material(name=mat_names[i])) - mats[-1].set_density('macro', 1.0) - mats[-1].add_macroscopic(macros[-1]) - - # Add in the microscopic data - mats.append(openmc.Material(name='micro')) - mats[-1].set_density("sum") - mats[-1].add_nuclide("mat_1", 0.5) - mats[-1].add_nuclide("mat_6", 0.5) - - materials_file += mats - - materials_file.cross_sections = '2g.h5' - - # # Make Geometry - rad_outer = 929.45 - # Set a cell boundary to exist for every material above (exclude the 0) - rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] - - # Instantiate Universe - root = openmc.Universe(universe_id=0, name='root universe') - cells = [] - - surfs = [] - surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) - for r, rad in enumerate(rads): - if r == len(rads) - 1: - surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) - else: - surfs.append(openmc.XPlane(x0=rad)) - - # Instantiate Cells - cells = [] - for c in range(len(surfs) - 1): - cells.append(openmc.Cell()) - cells[-1].region = (+surfs[c] & -surfs[c + 1]) - cells[-1].fill = mats[c] - - # Register Cells with Universe - root.add_cells(cells) - - # Instantiate a Geometry, register the root Universe, and export to XML - geometry_file = openmc.Geometry(root) - - # # Make Settings - # Instantiate a Settings object, set all runtime parameters - settings_file = openmc.Settings() - settings_file.energy_mode = "multi-group" - settings_file.tabular_legendre = {'enable': False} - settings_file.batches = 10 - settings_file.inactive = 5 - settings_file.particles = 1000 - - # Build source distribution - INF = 1000. - bounds = [0., -INF, -INF, rads[0], INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) - - settings_file.output = {'summary': False} - - model = openmc.model.Model() - model.geometry = geometry_file - model.materials = materials_file - model.settings = settings_file - - return model - - class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() @@ -162,6 +83,15 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_benchmark(): - model = create_model() + create_library() + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', + 'base ang', 'micro'] + model = slab_mg(num_regions=6, mat_names=mat_names) + # Modify the last material to be a microscopic combination of nuclides + model.materials[-1] = openmc.Material(name='micro', material_id=6) + model.materials[-1].set_density("sum") + model.materials[-1].add_nuclide("mat_1", 0.5) + model.materials[-1].add_nuclide("mat_6", 0.5) + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py index 72bd34e1b..6c527bbe3 100644 --- a/tests/regression_tests/mg_benchmark_delayed/test.py +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -3,6 +3,7 @@ import os import numpy as np import openmc +from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness @@ -71,7 +72,8 @@ def create_library(): mat_4 = openmc.XSdata('mat_4', groups) mat_4.order = 1 mat_4.num_delayed_groups = 2 - mat_4.set_prompt_nu_fission(one_m_beta * np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_prompt_nu_fission(one_m_beta * + np.outer(np.multiply(nu, fiss), chi)) delay_nu_fiss = np.zeros((n_dg, groups.num_groups, groups.num_groups)) for dg in range(n_dg): for g in range(groups.num_groups): @@ -87,80 +89,6 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -def create_model(): - create_library() - - # # Make Materials - materials_file = openmc.Materials() - - mat_names = ['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta'] - macros = [] - mats = [] - for i in range(len(mat_names)): - macros.append(openmc.Macroscopic('mat_' + str(i + 1))) - mats.append(openmc.Material(name=mat_names[i])) - mats[-1].set_density('macro', 1.0) - mats[-1].add_macroscopic(macros[-1]) - - materials_file += mats - - materials_file.cross_sections = '2g.h5' - - # # Make Geometry - rad_outer = 929.45 - # Set a cell boundary to exist for every material above (exclude the 0) - rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] - - # Instantiate Universe - root = openmc.Universe(universe_id=0, name='root universe') - cells = [] - - surfs = [] - surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) - for r, rad in enumerate(rads): - if r == len(rads) - 1: - surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) - else: - surfs.append(openmc.XPlane(x0=rad)) - - # Instantiate Cells - cells = [] - for c in range(len(surfs) - 1): - cells.append(openmc.Cell()) - cells[-1].region = (+surfs[c] & -surfs[c + 1]) - cells[-1].fill = mats[c] - - # Register Cells with Universe - root.add_cells(cells) - - # Instantiate a Geometry, register the root Universe, and export to XML - geometry_file = openmc.Geometry(root) - - # # Make Settings - # Instantiate a Settings object, set all runtime parameters - settings_file = openmc.Settings() - settings_file.energy_mode = "multi-group" - settings_file.tabular_legendre = {'enable': False} - settings_file.batches = 10 - settings_file.inactive = 5 - settings_file.particles = 1000 - - # Build source distribution - INF = 1000. - bounds = [0., -INF, -INF, rads[0], INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) - - settings_file.output = {'summary': False} - - model = openmc.model.Model() - model.geometry = geometry_file - model.materials = materials_file - model.settings = settings_file - - return model - - class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() @@ -170,6 +98,9 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_benchmark(): - model = create_model() + create_library() + model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', + 'matrix beta', 'matrix no beta']) + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_convert/test.py b/tests/regression_tests/mg_convert/test.py index 1ace10c80..4cc6b656a 100755 --- a/tests/regression_tests/mg_convert/test.py +++ b/tests/regression_tests/mg_convert/test.py @@ -17,7 +17,7 @@ def build_mgxs_library(convert): # Instantiate the energy group data groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - # Instantiate the 7-group (C5G7) cross section data + # Instantiate the 2-group (C5G7) cross section data uo2_xsdata = openmc.XSdata('UO2', groups) uo2_xsdata.order = 2 uo2_xsdata.set_total([2., 2.]) diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index 754808095..ad3b434e6 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -1,44 +1,31 @@ - - - + - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group false diff --git a/tests/regression_tests/mg_legendre/results_true.dat b/tests/regression_tests/mg_legendre/results_true.dat index d0f8c319e..4a9d98237 100644 --- a/tests/regression_tests/mg_legendre/results_true.dat +++ b/tests/regression_tests/mg_legendre/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.110122E+00 2.549637E-02 +9.934975E-01 2.679669E-02 diff --git a/tests/regression_tests/mg_legendre/test.py b/tests/regression_tests/mg_legendre/test.py index 5a57f758e..b5a05c706 100644 --- a/tests/regression_tests/mg_legendre/test.py +++ b/tests/regression_tests/mg_legendre/test.py @@ -1,10 +1,54 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_legendre(): - model = slab_mg(reps=['iso']) + create_library() + model = slab_mg() model.settings.tabular_legendre = {'enable': False} harness = PyAPITestHarness('statepoint.10.h5', model) diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index 023d468d4..2ac83852c 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -1,44 +1,34 @@ - - - + - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group 1 + + false + diff --git a/tests/regression_tests/mg_max_order/results_true.dat b/tests/regression_tests/mg_max_order/results_true.dat index adfcd44a8..4a9d98237 100644 --- a/tests/regression_tests/mg_max_order/results_true.dat +++ b/tests/regression_tests/mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.074551E+00 1.871525E-02 +9.934975E-01 2.679669E-02 diff --git a/tests/regression_tests/mg_max_order/test.py b/tests/regression_tests/mg_max_order/test.py index 20cc4f805..97d3f57d7 100644 --- a/tests/regression_tests/mg_max_order/test.py +++ b/tests/regression_tests/mg_max_order/test.py @@ -1,10 +1,55 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], + [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 2 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_max_order(): - model = slab_mg(reps=['iso']) + create_library() + model = slab_mg() model.settings.max_order = 1 + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_nuclide/__init__.py b/tests/regression_tests/mg_nuclide/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/mg_nuclide/inputs_true.dat b/tests/regression_tests/mg_nuclide/inputs_true.dat deleted file mode 100644 index e11b9e3f0..000000000 --- a/tests/regression_tests/mg_nuclide/inputs_true.dat +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 0.0 0.0 0.0 10.0 10.0 5.0 - - - multi-group - diff --git a/tests/regression_tests/mg_nuclide/results_true.dat b/tests/regression_tests/mg_nuclide/results_true.dat deleted file mode 100644 index ddb57d00b..000000000 --- a/tests/regression_tests/mg_nuclide/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.073147E+00 1.602384E-02 diff --git a/tests/regression_tests/mg_nuclide/test.py b/tests/regression_tests/mg_nuclide/test.py deleted file mode 100644 index 44206ef28..000000000 --- a/tests/regression_tests/mg_nuclide/test.py +++ /dev/null @@ -1,9 +0,0 @@ -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def test_mg_nuclide(): - model = slab_mg(as_macro=False) - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index 4bc79d48e..5ece3ce9f 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -1,98 +1,34 @@ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group true + + false + diff --git a/tests/regression_tests/mg_survival_biasing/results_true.dat b/tests/regression_tests/mg_survival_biasing/results_true.dat index b20d63288..ebe98679f 100644 --- a/tests/regression_tests/mg_survival_biasing/results_true.dat +++ b/tests/regression_tests/mg_survival_biasing/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.080832E+00 1.336780E-02 +9.979905E-01 6.207495E-03 diff --git a/tests/regression_tests/mg_survival_biasing/test.py b/tests/regression_tests/mg_survival_biasing/test.py index 3c6c77a37..5d75611a9 100644 --- a/tests/regression_tests/mg_survival_biasing/test.py +++ b/tests/regression_tests/mg_survival_biasing/test.py @@ -1,10 +1,55 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_survival_biasing(): + create_library() model = slab_mg() model.settings.survival_biasing = True + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index 7b5067014..a9b821c56 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -1,112 +1,48 @@ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - + - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 2g.h5 + + + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group + + false + - 1 1 10 + 10 1 1 0.0 0.0 0.0 - 10 10 5 + 929.45 1000 1000 1 - 1 2 3 4 5 6 7 8 9 10 11 12 + 1 0.0 20000000.0 @@ -115,10 +51,10 @@ 0.0 20000000.0 - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + 0.0 0.625 20000000.0 - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + 0.0 0.625 20000000.0 5 @@ -170,60 +106,60 @@ 5 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission analog 5 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission scatter nu-scatter analog 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission collision 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 1 2 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 scatter nu-scatter nu-fission 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission scatter nu-scatter analog 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission collision 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 3 4 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 scatter nu-scatter nu-fission diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index 87470bdf4..78a5883fe 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -1 +1 @@ -9183f8b191f2e62334f992acd865d29e3f4e3f871a6df498e280fc4e2d91f2d2d20c732fbd75fa88e2e8c576f86e744f7655af6bb9da66e9b28b1009c8742899 \ No newline at end of file +41ea1f6b17c58a8141921af2f1d044eda93f3a9bca9463ee023af2e9865da613ace90fc8a25b42edde128ed827182ea9df0fe09d9b7887282d0ec092692cf717 \ No newline at end of file diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index 8952cc4ad..26d53c230 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -1,23 +1,66 @@ +import os + +import numpy as np + import openmc from openmc.examples import slab_mg from tests.testing_harness import HashedPyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(HashedPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_tallies(): - model = slab_mg(as_macro=False) + create_library() + model = slab_mg() # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) mesh.type = 'regular' - mesh.dimension = [1, 1, 10] + mesh.dimension = [10, 1, 1] mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [10, 10, 5] + mesh.upper_right = [929.45, 1000, 1000] # Instantiate some tally filters energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) - energies = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + energies = [0.0, 0.625, 20.0e6] matching_energy_filter = openmc.EnergyFilter(energies) matching_eout_filter = openmc.EnergyoutFilter(energies) mesh_filter = openmc.MeshFilter(mesh) From 9e0e8685776333b4d5b289f48aa994a7420d4f1c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 28 Aug 2018 06:59:39 -0500 Subject: [PATCH 48/76] Add C++ version of RegularMesh class --- CMakeLists.txt | 1 + include/openmc/hdf5_interface.h | 9 + include/openmc/mesh.h | 58 +++++ include/openmc/xml_interface.h | 12 ++ src/mesh.cpp | 368 ++++++++++++++++++++++++++++++++ 5 files changed, 448 insertions(+) create mode 100644 include/openmc/mesh.h create mode 100644 src/mesh.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 57d2c6dac..78d1caf4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ add_library(libopenmc SHARED src/lattice.cpp src/material.cpp src/math_functions.cpp + src/mesh.cpp src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 48ce41d0e..944fe75cb 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -347,6 +347,15 @@ write_dataset(hid_t obj_id, const char* name, const std::vector& buffer) write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); } +template inline void +write_dataset(hid_t obj_id, const char* name, const xt::xarray& arr) +{ + auto s = arr.shape(); + std::vector dims {s.cbegin(), s.cend()}; + write_dataset(obj_id, dims.size(), dims.data(), name, H5TypeMap::type_id, + arr.data(), false); +} + inline void write_dataset(hid_t obj_id, const char* name, Position r) { diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h new file mode 100644 index 000000000..151701e0b --- /dev/null +++ b/include/openmc/mesh.h @@ -0,0 +1,58 @@ +#ifndef OPENMC_MESH_H +#define OPENMC_MESH_H + +#include +#include +#include + +#include "hdf5.h" +#include "pugixml.hpp" +#include "xtensor/xarray.hpp" + +#include "openmc/position.h" + +namespace openmc { + +//============================================================================== +//! Tessellation of n-dimensional Euclidean space by congruent squares or cubes +//============================================================================== + +class RegularMesh { +public: + // Constructors + RegularMesh(pugi::xml_node node); + + // Methods + int get_bin(Position r); + int get_bin_from_indices(const int* ijk); + void get_indices(Position r, int* ijk, bool* in_mesh); + void get_indices_from_bin(int bin, int* ijk); + bool intersects(Position r0, Position r1); + void to_hdf5(hid_t group); + + int id_ {-1}; //!< User-specified ID + int n_dimension_; + double volume_frac_; + xt::xarray shape_; + xt::xarray lower_left_; + xt::xarray upper_right_; + xt::xarray width_; + +private: + bool intersects_1d(Position r0, Position r1); + bool intersects_2d(Position r0, Position r1); + bool intersects_3d(Position r0, Position r1); +}; + +//============================================================================== +// Global variables +//============================================================================== + +extern std::vector global_meshes; + +extern std::unordered_map mesh_map; + + +} // namespace openmc + +#endif // OPENMC_MESH_H diff --git a/include/openmc/xml_interface.h b/include/openmc/xml_interface.h index fb87ffdae..85db26faa 100644 --- a/include/openmc/xml_interface.h +++ b/include/openmc/xml_interface.h @@ -1,11 +1,14 @@ #ifndef OPENMC_XML_INTERFACE_H #define OPENMC_XML_INTERFACE_H +#include // for size_t #include // for stringstream #include #include #include "pugixml.hpp" +#include "xtensor/xarray.hpp" +#include "xtensor/xadapt.hpp" namespace openmc { @@ -38,5 +41,14 @@ std::vector get_node_array(pugi::xml_node node, const char* name, return values; } +template +xt::xarray get_node_xarray(pugi::xml_node node, const char* name, + bool lowercase=false) +{ + std::vector v = get_node_array(node, name, lowercase); + std::vector shape = {v.size()}; + return xt::adapt(v, shape); +} + } // namespace openmc #endif // OPENMC_XML_INTERFACE_H diff --git a/src/mesh.cpp b/src/mesh.cpp new file mode 100644 index 000000000..9e4aae096 --- /dev/null +++ b/src/mesh.cpp @@ -0,0 +1,368 @@ +#include "openmc/mesh.h" + +#include // for ceil +#include + +#include "xtensor/xeval.hpp" +#include "xtensor/xmath.hpp" + +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/xml_interface.h" + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +std::vector global_meshes; + +std::unordered_map mesh_map; + +//============================================================================== +// RegularMesh implementation +//============================================================================== + +RegularMesh::RegularMesh(pugi::xml_node node) +{ + // Copy mesh id + if (check_for_node(node, "id")) { + id_ = std::stoi(get_node_value(node, "id")); + + // Check to make sure 'id' hasn't been used + if (mesh_map.find(id_) != mesh_map.end()) { + fatal_error("Two or more meshes use the same unique ID: " + + std::to_string(id_)); + } + } + + // Read mesh type + if (check_for_node(node, "type")) { + auto temp = get_node_value(node, "type", true, true); + if (temp == "regular") { + // TODO: move elsewhere + } else { + fatal_error("Invalid mesh type: " + temp); + } + } + + // Determine number of dimensions for mesh + if (check_for_node(node, "dimension")) { + shape_ = get_node_xarray(node, "dimension"); + int n = n_dimension_ = shape_.size(); + if (n != 1 && n != 2 && n != 3) { + fatal_error("Mesh must be one, two, or three dimensions."); + } + + // Check that dimensions are all greater than zero + if (xt::any(shape_ <= 0)) { + fatal_error("All entries on the element for a tally " + "mesh must be positive."); + } + } + + // Check for lower-left coordinates + if (check_for_node(node, "lower_left")) { + // Read mesh lower-left corner location + lower_left_ = get_node_xarray(node, "lower_left"); + } else { + fatal_error("Must specify on a mesh."); + } + + if (check_for_node(node, "width")) { + // Make sure both upper-right or width were specified + if (check_for_node(node, "upper_right")) { + fatal_error("Cannot specify both and on a mesh."); + } + + width_ = get_node_xarray(node, "width"); + + // Check to ensure width has same dimensions + auto n = width_.size(); + if (n != lower_left_.size()) { + fatal_error("Number of entries on must be the same as " + "the number of entries on ."); + } + + // Check for negative widths + if (xt::any(width_ < 0.0)) { + fatal_error("Cannot have a negative on a tally mesh."); + } + + // Set width and upper right coordinate + upper_right_ = xt::eval(lower_left_ + shape_ * width_); + + } else if (check_for_node(node, "upper_right")) { + upper_right_ = get_node_xarray(node, "upper_right"); + + // Check to ensure width has same dimensions + auto n = upper_right_.size(); + if (n != lower_left_.size()) { + fatal_error("Number of entries on must be the " + "same as the number of entries on ."); + } + + // Check that upper-right is above lower-left + if (xt::any(upper_right_ < lower_left_)) { + fatal_error("The coordinates must be greater than " + "the coordinates on a tally mesh."); + } + + // Set width and upper right coordinate + width_ = xt::eval((upper_right_ - lower_left_) / shape_); + } else { + fatal_error("Must specify either and on a mesh."); + } + + if (shape_.dimension() > 0) { + if (shape_.size() != lower_left_.size()) { + fatal_error("Number of entries on must be the same " + "as the number of entries on ."); + } + + // Set volume fraction + volume_frac_ = 1.0/xt::prod(shape_)(); + } +} + +int RegularMesh::get_bin(Position r) +{ + // Loop over the dimensions of the mesh + for (int i = 0; i < n_dimension_; ++i) { + // Check for cases where particle is outside of mesh + if (r[i] < lower_left_[i]) { + return -1; + } else if (r[i] > upper_right_[i]) { + return -1; + } + } + + // Determine indices + int ijk[n_dimension_]; + bool in_mesh; + get_indices(r, ijk, &in_mesh); + if (!in_mesh) return -1; + + // Convert indices to bin + return get_bin_from_indices(ijk); +} + +int RegularMesh::get_bin_from_indices(const int* ijk) +{ + if (n_dimension_ == 1) { + return ijk[0]; + } else if (n_dimension_ == 2) { + return (ijk[1] - 1)*shape_[0] + ijk[0]; + } else if (n_dimension_ == 3) { + return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0]; + } +} + +void RegularMesh::get_indices(Position r, int* ijk, bool* in_mesh) +{ + // Find particle in mesh + *in_mesh = true; + for (int i = 0; i < n_dimension_; ++i) { + ijk[i] = std::ceil((r[i] - lower_left_[i]) / width_[i]); + + // Check if indices are within bounds + if (ijk[i] < 1 || ijk[i] > shape_[i]) *in_mesh = false; + } +} + +void RegularMesh::get_indices_from_bin(int bin, int* ijk) +{ + if (n_dimension_ == 1) { + ijk[0] = bin; + } else if (n_dimension_ == 2) { + ijk[0] = (bin - 1) % shape_[0] + 1; + ijk[1] = (bin - 1) / shape_[0] + 1; + } else if (n_dimension_ == 3) { + ijk[0] = (bin - 1) % shape_[0] + 1; + ijk[1] = (bin - 1) % (shape_[0] * shape_[1]) / shape_[0] + 1; + ijk[2] = (bin - 1) / (shape_[0] * shape_[1]) + 1; + } +} + +bool RegularMesh::intersects(Position r0, Position r1) +{ + switch(n_dimension_) { + case 1: + return intersects_1d(r0, r1); + case 2: + return intersects_2d(r0, r1); + case 3: + return intersects_3d(r0, r1); + } +} + +bool RegularMesh::intersects_1d(Position r0, Position r1) +{ + // Copy coordinates of mesh lower_left and upper_right + double left = lower_left_[0]; + double right = upper_right_[0]; + + // Check if line intersects either left or right surface + if (r0.x < left) { + return r1.x > left; + } else if (r0.x < right) { + return r1.x < left || r1.x > right; + } else { + return r1.x < right; + } +} + +bool RegularMesh::intersects_2d(Position r0, Position r1) +{ + // Copy coordinates of starting point + double x0 = r0.x; + double y0 = r0.y; + + // Copy coordinates of ending point + double x1 = r1.x; + double y1 = r1.y; + + // Copy coordinates of mesh lower_left + double xm0 = lower_left_[0]; + double ym0 = lower_left_[1]; + + // Copy coordinates of mesh upper_right + double xm1 = upper_right_[0]; + double ym1 = upper_right_[1]; + + // Check if line intersects left surface -- calculate the intersection point y + if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { + double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); + if (yi >= ym0 && yi < ym1) { + return true; + } + } + + // Check if line intersects back surface -- calculate the intersection point + // x + if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) { + double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); + if (xi >= xm0 && xi < xm1) { + return true; + } + } + + // Check if line intersects right surface -- calculate the intersection + // point y + if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { + double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); + if (yi >= ym0 && yi < ym1) { + return true; + } + } + + // Check if line intersects front surface -- calculate the intersection point + // x + if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) { + double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); + if (xi >= xm0 && xi < xm1) { + return true; + } + } + return false; +} + +bool RegularMesh::intersects_3d(Position r0, Position r1) +{ + // Copy coordinates of starting point + double x0 = r0.x; + double y0 = r0.y; + double z0 = r0.z; + + // Copy coordinates of ending point + double x1 = r1.x; + double y1 = r1.y; + double z1 = r1.z; + + // Copy coordinates of mesh lower_left + double xm0 = lower_left_[0]; + double ym0 = lower_left_[1]; + double zm0 = lower_left_[2]; + + // Copy coordinates of mesh upper_right + double xm1 = upper_right_[0]; + double ym1 = upper_right_[1]; + double zm1 = upper_right_[2]; + + // Check if line intersects left surface -- calculate the intersection point + // (y,z) + if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { + double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); + if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { + return true; + } + } + + // Check if line intersects back surface -- calculate the intersection point + // (x,z) + if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) { + double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); + double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0); + if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { + return true; + } + } + + // Check if line intersects bottom surface -- calculate the intersection + // point (x,y) + if ((z0 < zm0 && z1 > zm0) || (z0 > zm0 && z1 < zm0)) { + double xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0); + double yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0); + if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { + return true; + } + } + + // Check if line intersects right surface -- calculate the intersection point + // (y,z) + if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { + double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); + double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); + if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { + return true; + } + } + + // Check if line intersects front surface -- calculate the intersection point + // (x,z) + if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) { + double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); + double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0); + if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { + return true; + } + } + + // Check if line intersects top surface -- calculate the intersection point + // (x,y) + if ((z0 < zm1 && z1 > zm1) || (z0 > zm1 && z1 < zm1)) { + double xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0); + double yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0); + if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { + return true; + } + } + return false; +} + +void RegularMesh::to_hdf5(hid_t group) +{ + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "regular"); + write_dataset(mesh_group, "dimension", shape_); + write_dataset(mesh_group, "lower_left", lower_left_); + write_dataset(mesh_group, "upper_right", upper_right_); + write_dataset(mesh_group, "width", width_); + + close_group(mesh_group); +} + +} // namespace openmc From 19de269ae65dd70bd9f900f018e55262947b01a2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 29 Aug 2018 10:31:13 -0500 Subject: [PATCH 49/76] Populate meshes vector from settings.xml --- include/openmc/mesh.h | 5 ++- src/cmfd_execute.F90 | 1 - src/mesh.cpp | 2 +- src/output.F90 | 1 - src/settings.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 151701e0b..1d75d778d 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -1,7 +1,8 @@ #ifndef OPENMC_MESH_H #define OPENMC_MESH_H -#include +#include // for size_t +#include // for unique_ptr #include #include @@ -48,7 +49,7 @@ private: // Global variables //============================================================================== -extern std::vector global_meshes; +extern std::vector> meshes; extern std::unordered_map mesh_map; diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 7fe153d27..74264a036 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -214,7 +214,6 @@ contains use bank_header, only: source_bank use constants, only: ZERO, ONE use error, only: warning, fatal_error - use mesh_header, only: RegularMesh use mesh, only: count_bank_sites use message_passing use string, only: to_str diff --git a/src/mesh.cpp b/src/mesh.cpp index 9e4aae096..fb9ce2d0d 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -16,7 +16,7 @@ namespace openmc { // Global variables //============================================================================== -std::vector global_meshes; +std::vector> meshes; std::unordered_map mesh_map; diff --git a/src/output.F90 b/src/output.F90 index b4ecf497e..b7b418a39 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -10,7 +10,6 @@ module output use error, only: fatal_error, warning use geometry_header use math, only: t_percentile - use mesh_header, only: RegularMesh, meshes use message_passing, only: master, n_procs use mgxs_interface use nuclide_header diff --git a/src/settings.cpp b/src/settings.cpp index b7310c37f..7e727178a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,7 +1,9 @@ #include "openmc/settings.h" +#include // for ceil, pow #include // for numeric_limits #include +#include // for out_of_range #include #include @@ -13,6 +15,7 @@ #include "openmc/distribution_spatial.h" #include "openmc/error.h" #include "openmc/file_utils.h" +#include "openmc/mesh.h" #include "openmc/random_lcg.h" #include "openmc/source.h" #include "openmc/string_utils.h" @@ -484,7 +487,100 @@ read_settings_xml() //track_identifiers = reshape(temp_int_array, [3, n_tracks/3]) } - // TODO: Read meshes + // Read meshes + for (auto node : root.children("mesh")) { + // Read mesh and add to vector + meshes.emplace_back(new RegularMesh{node}); + + // Map ID to position in vector + mesh_map[meshes.back()->id_] = meshes.size() - 1; + } + + // Shannon Entropy mesh + if (check_for_node(root, "entropy_mesh")) { + int temp = std::stoi(get_node_value(root, "entropy_mesh")); + try { + index_entropy_mesh = mesh_map.at(temp); + } catch (std::out_of_range) { + std::stringstream msg; + msg << "Mesh " << temp << " specified for Shannon entropy does not exist."; + fatal_error(msg); + } + } else if (check_for_node(root, "entropy")) { + warning("Specifying a Shannon entropy mesh via the element " + "is deprecated. Please create a mesh using and then reference " + "it by specifying its ID in an element."); + + // Read entropy mesh from + auto node_entropy = root.child("entropy"); + meshes.emplace_back(new RegularMesh{node_entropy}); + + // Set entropy mesh index + index_entropy_mesh = meshes.size() - 1; + + // Assign ID and set mapping + meshes.back()->id_ = 10000; + mesh_map[10000] = index_entropy_mesh; + } + + if (index_entropy_mesh >= 0) { + auto& m = *meshes[index_entropy_mesh]; + if (m.shape_.dimension() == 0) { + // If the user did not specify how many mesh cells are to be used in + // each direction, we automatically determine an appropriate number of + // cells + int n = std::ceil(std::pow(settings::n_particles / 20, 1.0/3.0)); + m.shape_ = {n, n, n}; + m.n_dimension_ = 3; + + // Calculate width + m.width_ = (m.upper_right_ - m.lower_left_) / m.shape_; + } + + // TODO: Allocate entropy_P + // Allocate space for storing number of fission sites in each mesh cell + //allocate(entropy_p(1, product(m % dimension))) + + // Turn on Shannon entropy calculation + settings::entropy_on = true; + } + + // Uniform fission source weighting mesh + if (check_for_node(root, "ufs_mesh")) { + auto temp = std::stoi(get_node_value(root, "ufs_mesh")); + try { + index_ufs_mesh = mesh_map.at(temp); + } catch (std::out_of_range) { + std::stringstream msg; + msg << "Mesh " << temp << " specified for uniform fission site method " + "does not exist."; + fatal_error(msg); + } + } else if (check_for_node(root, "uniform_fs")) { + warning("Specifying a UFS mesh via the element " + "is deprecated. Please create a mesh using and then reference " + "it by specifying its ID in a element."); + + // Read entropy mesh from + auto node_ufs = root.child("uniform_fs"); + meshes.emplace_back(new RegularMesh{node_ufs}); + + // Set entropy mesh index + index_ufs_mesh = meshes.size() - 1; + + // Assign ID and set mapping + meshes.back()->id_ = 10001; + mesh_map[10001] = index_entropy_mesh; + } + + if (index_ufs_mesh >= 0) { + // Allocate array to store source fraction for UFS + // TODO: Allocate source_frac + //allocate(source_frac(1, product(meshes(index_ufs_mesh) % dimension))) + + // Turn on uniform fission source weighting + settings::ufs_on = true; + } // TODO: Read From b7feb47971837ba1dd5a230d8bddcedc61975ae1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 29 Aug 2018 11:30:21 -0500 Subject: [PATCH 50/76] Add norm method on Position --- include/openmc/position.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/openmc/position.h b/include/openmc/position.h index 97ab6f0e6..d7a13c01e 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -1,6 +1,7 @@ #ifndef OPENMC_POSITION_H #define OPENMC_POSITION_H +#include #include namespace openmc { @@ -46,6 +47,9 @@ struct Position { inline double dot(Position other) { return x*other.x + y*other.y + z*other.z; } + inline double norm() { + return std::sqrt(x*x + y*y + z*z); + } // Data members double x = 0.; From fe76ad695f1d57d7caf03e6f2be915b281726da8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 29 Aug 2018 11:30:32 -0500 Subject: [PATCH 51/76] Add bins_crossed method for RegularMesh --- include/openmc/mesh.h | 3 + src/mesh.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 1d75d778d..7bd5a2c29 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -10,6 +10,7 @@ #include "pugixml.hpp" #include "xtensor/xarray.hpp" +#include "openmc/particle.h" #include "openmc/position.h" namespace openmc { @@ -24,6 +25,8 @@ public: RegularMesh(pugi::xml_node node); // Methods + void bins_crossed(const Particle* p, std::vector& bins, + std::vector& lengths); int get_bin(Position r); int get_bin_from_indices(const int* ijk); void get_indices(Position r, int* ijk, bool* in_mesh); diff --git a/src/mesh.cpp b/src/mesh.cpp index fb9ce2d0d..58a4e776b 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -5,7 +5,10 @@ #include "xtensor/xeval.hpp" #include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xtensor.hpp" +#include "openmc/constants.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" #include "openmc/xml_interface.h" @@ -352,6 +355,157 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) return false; } +void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, + std::vector& lengths) +{ + constexpr int MAX_SEARCH_ITER = 100; + + // ======================================================================== + // Determine if the track intersects the tally mesh. + + // Copy the starting and ending coordinates of the particle. Offset these + // just a bit for the purposes of determining if there was an intersection + // in case the mesh surfaces coincide with lattice/geometric surfaces which + // might produce finite-precision errors. + Position last_r {p->last_xyz}; + Position r {p->coord[0].xyz}; + Direction u {p->coord[0].uvw}; + + Position r0 = last_r + TINY_BIT*u; + Position r1 = r - TINY_BIT*u; + + // Determine indices for starting and ending location. + int n = n_dimension_; + xt::xtensor ijk0 = xt::empty({n}); + bool start_in_mesh; + get_indices(r0, ijk0.data(), &start_in_mesh); + xt::xtensor ijk1 = xt::empty({n}); + bool end_in_mesh; + get_indices(r1, ijk1.data(), &end_in_mesh); + + // If this is the first iteration of the filter loop, check if the track + // intersects any part of the mesh. + if ((!start_in_mesh) && (!end_in_mesh)) { + if (!intersects(r0, r1)) return; + } + + // ======================================================================== + // Figure out which mesh cell to tally. + + // Copy the un-modified coordinates the particle direction. + r0 = Position{p->last_xyz}; + r1 = Position{p->coord[0].xyz}; + + // Compute the length of the entire track. + double total_distance = (r1 - r0).norm(); + + // We are looking for the first valid mesh bin. Check to see if the + // particle starts inside the mesh. + if (!start_in_mesh) { + xt::xtensor d = xt::zeros({n}); + + // The particle does not start in the mesh. Note that we nudged the + // start and end coordinates by a TINY_BIT each so we will have + // difficulty resolving tracks that are less than 2*TINY_BIT in length. + // If the track is that short, it is also insignificant so we can + // safely ignore it in the tallies. + if (total_distance < 2*TINY_BIT) return; + + // The particle does not start in the mesh so keep iterating the ijk0 + // indices to cross the nearest mesh surface until we've found a valid + // bin. MAX_SEARCH_ITER prevents an infinite loop. + int search_iter = 0; + int j; + while (xt::any(ijk0 < 1) || xt::any(ijk0 > shape_)) { + if (search_iter == MAX_SEARCH_ITER) { + warning("Failed to find a mesh intersection on a tally mesh filter."); + return; + } + + for (j = 0; j < n; ++j) { + if (std::abs(u[j]) < FP_PRECISION) { + d(j) = INFTY; + } else if (u[j] > 0) { + double xyz_cross = lower_left_[j] + ijk0(j) * width_[j]; + d(j) = (xyz_cross - r0[j]) / u[j]; + } else { + double xyz_cross = lower_left_[j] + (ijk0(j) - 1) * width_[j]; + d(j) = (xyz_cross - r0[j]) / u[j]; + } + } + + int j = xt::argmin(d)(0); + if (u[j] > 0.0) { + ++ijk0(j); + } else { + --ijk0(j); + } + + ++search_iter; + } + + // Advance position + r0 += d(j) * u; + } + + while (true) { + // ======================================================================== + // Compute the length of the track segment in the appropiate mesh cell and + // return. + + double distance; + int j; + if (ijk0 == ijk1) { + // The track ends in this cell. Use the particle end location rather + // than the mesh surface. + distance = (r1 - r0).norm(); + } else { + // The track exits this cell. Determine the distance to the closest mesh + // surface. + xt::xtensor d = xt::zeros({n}); + for (int j = 0; j < n; ++j) { + if (abs(u[j]) < FP_PRECISION) { + d(j) = INFTY; + } else if (u[j] > 0) { + double xyz_cross = lower_left_[j] + ijk0(j) * width_[j]; + d(j) = (xyz_cross - r0[j]) / u[j]; + } else { + double xyz_cross = lower_left_[j] + (ijk0(j) - 1) * width_[j]; + d(j) = (xyz_cross - r0[j]) / u[j]; + } + } + j = xt::argmin(d)(0); + distance = d(j); + } + + // Assign the next tally bin and the score. + int bin = get_bin_from_indices(ijk0.data()); + bins.push_back(bin); + lengths.push_back(distance / total_distance); + + // Find the next mesh cell that the particle enters. + + // If the particle track ends in that bin, { we are done. + if (ijk0 == ijk1) break; + + // Translate the starting coordintes by the distance to that face. This + // should be the xyz that we computed the distance to in the last + // iteration of the filter loop. + r0 += distance * u; + + // Increment the indices into the next mesh cell. + if (u[j] > 0.0) { + ++ijk0(j); + } else { + --ijk0(j); + } + + // If the next indices are invalid, then the track has left the mesh and + // we are done. + if (xt::any(ijk0 < 1) || xt::any(ijk0 > shape_)) break; + } +} + void RegularMesh::to_hdf5(hid_t group) { hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); From fb22413e8d2ce18130c2f51115e695a85877d90e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 29 Aug 2018 14:33:05 -0500 Subject: [PATCH 52/76] Move mesh C API functions to C++ --- include/openmc/capi.h | 2 +- include/openmc/mesh.h | 2 +- src/api.F90 | 2 +- src/mesh.cpp | 141 +++++++++++++++++++++ src/mesh_header.F90 | 278 ++++++++++-------------------------------- src/settings.cpp | 4 +- 6 files changed, 213 insertions(+), 216 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 7fd79fccf..7ce42aa47 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -71,7 +71,7 @@ extern "C" { int openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n); int openmc_mesh_set_id(int32_t index, int32_t id); int openmc_mesh_set_dimension(int32_t index, int n, const int* dims); - int openmc_mesh_set_params(int32_t index, const double* ll, const double* ur, const double* width, int n); + int openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, const double* width); int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh); int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh); int openmc_next_batch(int* status); diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 7bd5a2c29..71649fa61 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -1,7 +1,6 @@ #ifndef OPENMC_MESH_H #define OPENMC_MESH_H -#include // for size_t #include // for unique_ptr #include #include @@ -22,6 +21,7 @@ namespace openmc { class RegularMesh { public: // Constructors + RegularMesh() = default; RegularMesh(pugi::xml_node node); // Methods diff --git a/src/api.F90 b/src/api.F90 index 75876080d..2a6775a0c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -11,7 +11,7 @@ module openmc_api use hdf5_interface use material_header use math - use mesh_header + use mesh_header, only: free_memory_mesh use message_passing use nuclide_header use initialize, only: openmc_init_f diff --git a/src/mesh.cpp b/src/mesh.cpp index 58a4e776b..8aecd1a22 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,5 +1,6 @@ #include "openmc/mesh.h" +#include // for size_t #include // for ceil #include @@ -8,6 +9,7 @@ #include "xtensor/xsort.hpp" #include "xtensor/xtensor.hpp" +#include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" @@ -519,4 +521,143 @@ void RegularMesh::to_hdf5(hid_t group) close_group(mesh_group); } +//============================================================================== +// C API functions +//============================================================================== + +//! Extend the meshes array by n elements +extern "C" int +openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end) +{ + if (!index_start) *index_start = meshes.size(); + for (int i = 0; i < n; ++i) { + meshes.emplace_back(new RegularMesh{}); + } + if (!index_end) *index_end = meshes.size() - 1; + + return 0; +} + +//! Return the index in the meshes array of a mesh with a given ID +extern "C" int +openmc_get_mesh_index(int32_t id, int32_t* index) +{ + auto pair = mesh_map.find(id); + if (pair == mesh_map.end()) { + set_errmsg("No mesh exists with ID=" + std::to_string(id) + "."); + return OPENMC_E_INVALID_ID; + } + *index = pair->second; + return 0; +} + +// Return the ID of a mesh +extern "C" int +openmc_mesh_get_id(int32_t index, int32_t* id) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *id = meshes[index]->id_; + return 0; +} + +//! Set the ID of a mesh +extern "C" int +openmc_mesh_set_id(int32_t index, int32_t id) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + meshes[index]->id_ = id; + mesh_map[id] = index; + return 0; +} + +//! Get the dimension of a mesh +extern "C" int +openmc_mesh_get_dimension(int32_t index, int** dims, int* n) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *dims = meshes[index]->shape_.data(); + *n = meshes[index]->n_dimension_; + return 0; +} + +//! Set the dimension of a mesh +extern "C" int +openmc_mesh_set_dimension(int32_t index, int n, const int* dims) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + // Copy dimension + std::vector shape = {static_cast(n)}; + auto& m = meshes[index]; + m->shape_ = xt::adapt(dims, n, xt::no_ownership(), shape); + m->n_dimension_ = m->shape_.size(); + + return 0; +} + +//! Get the mesh parameters +extern "C" int +openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + auto& m = meshes[index]; + if (m->lower_left_.dimension() == 0) { + set_errmsg("Mesh parameters have not been set."); + return OPENMC_E_ALLOCATE; + } + + *ll = m->lower_left_.data(); + *ur = m->upper_right_.data(); + *n = m->n_dimension_; + return 0; +} + +//! Set the mesh parameters +extern "C" int +openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, + const double* width) +{ + if (index < 0 || index >= meshes.size()) { + set_errmsg("Index in meshes array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + auto& m = meshes[index]; + std::vector shape = {static_cast(n)}; + if (ll && ur) { + m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); + m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); + m->width_ = (m->upper_right_ - m->lower_left_) / m->shape_; + } else if (ll && width) { + m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); + m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); + m->upper_right_ = m->lower_left_ + m->shape_ * m->width_; + } else if (ur && width) { + m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); + m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); + m->lower_left_ = m->upper_right_ - m->shape_ * m->width_; + } else { + set_errmsg("At least two parameters must be specified."); + return OPENMC_E_INVALID_ARGUMENT; + } + + return 0; +} + } // namespace openmc diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index fb22d2ad3..52c220976 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -52,6 +52,73 @@ module mesh_header ! Dictionary that maps user IDs to indices in 'meshes' type(DictIntInt), public :: mesh_dict + interface + function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C) + import C_INT32_T, C_INT + 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_INT) :: err + end function openmc_extend_meshes + + function openmc_get_mesh_index(id, index) result(err) bind(C) + import C_INT32_T, C_INT + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + end function openmc_get_mesh_index + + function openmc_mesh_get_id(index, id) result(err) bind(C) + import C_INT32_T, C_INT + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + end function openmc_mesh_get_id + + function openmc_mesh_set_id(index, id) result(err) bind(C) + import C_INT32_T, C_INT + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT32_T), value, intent(in) :: id + integer(C_INT) :: err + end function openmc_mesh_set_id + + function openmc_mesh_get_dimension(index, dims, n) result(err) bind(C) + import C_INT32_T, C_PTR, C_INT + integer(C_INT32_T), value, intent(in) :: index + type(C_PTR), intent(out) :: dims + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + end function openmc_mesh_get_dimension + + function openmc_mesh_set_dimension(index, n, dims) result(err) bind(C) + import C_INT32_T, C_INT + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), value, intent(in) :: n + integer(C_INT), intent(in) :: dims(n) + integer(C_INT) :: err + end function openmc_mesh_set_dimension + + function openmc_mesh_get_params(index, ll, ur, width, n) result(err) bind(C) + import C_INT32_T, C_PTR, C_INT + integer(C_INT32_T), value, intent(in) :: index + type(C_PTR), intent(out) :: ll + type(C_PTR), intent(out) :: ur + type(C_PTR), intent(out) :: width + integer(C_INT), intent(out) :: n + integer(C_INT) :: err + end function openmc_mesh_get_params + + function openmc_mesh_set_params(index, n, ll, ur, width) result(err) bind(C) + import C_INT32_T, C_INT, C_DOUBLE + integer(C_INT32_T), value, intent(in) :: index + integer(C_INT), value, intent(in) :: n + real(C_DOUBLE), intent(in), optional :: ll(n) + real(C_DOUBLE), intent(in), optional :: ur(n) + real(C_DOUBLE), intent(in), optional :: width(n) + integer(C_INT) :: err + end function openmc_mesh_set_params + end interface + contains subroutine regular_from_xml(this, node) @@ -562,215 +629,4 @@ contains call mesh_dict % clear() end subroutine free_memory_mesh -!=============================================================================== -! C API FUNCTIONS -!=============================================================================== - - function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C) - ! Extend the meshes array by n elements - 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_INT) :: err - - type(RegularMesh), allocatable :: temp(:) ! temporary meshes array - - if (n_meshes == 0) then - ! Allocate meshes array - allocate(meshes(n)) - else - ! Allocate meshes array with increased size - allocate(temp(n_meshes + n)) - - ! Copy original meshes to temporary array - temp(1:n_meshes) = meshes - - ! Move allocation from temporary array - call move_alloc(FROM=temp, TO=meshes) - end if - - ! Return indices in meshes array - if (present(index_start)) index_start = n_meshes + 1 - if (present(index_end)) index_end = n_meshes + n - n_meshes = n_meshes + n - - err = 0 - end function openmc_extend_meshes - - - function openmc_get_mesh_index(id, index) result(err) bind(C) - ! Return the index in the meshes array of a mesh with a given ID - integer(C_INT32_T), value :: id - integer(C_INT32_T), intent(out) :: index - integer(C_INT) :: err - - if (allocated(meshes)) then - if (mesh_dict % has(id)) then - index = mesh_dict % get(id) - err = 0 - else - err = E_INVALID_ID - call set_errmsg("No mesh exists with ID=" // trim(to_str(id)) // ".") - end if - else - err = E_ALLOCATE - call set_errmsg("Memory has not been allocated for meshes.") - end if - end function openmc_get_mesh_index - - - function openmc_mesh_get_id(index, id) result(err) bind(C) - ! Return the ID of a mesh - integer(C_INT32_T), value :: index - integer(C_INT32_T), intent(out) :: id - integer(C_INT) :: err - - if (index >= 1 .and. index <= size(meshes)) then - id = meshes(index) % id - err = 0 - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_get_id - - - function openmc_mesh_set_id(index, id) result(err) bind(C) - ! Set the ID of a mesh - integer(C_INT32_T), value, intent(in) :: index - integer(C_INT32_T), value, intent(in) :: id - integer(C_INT) :: err - - if (index >= 1 .and. index <= n_meshes) then - meshes(index) % id = id - call mesh_dict % set(id, index) - err = 0 - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_set_id - - - function openmc_mesh_get_dimension(index, dims, n) result(err) bind(C) - ! Get the dimension of a mesh - integer(C_INT32_T), value, intent(in) :: index - type(C_PTR), intent(out) :: dims - integer(C_INT), intent(out) :: n - integer(C_INT) :: err - - if (index >= 1 .and. index <= n_meshes) then - dims = C_LOC(meshes(index) % dimension) - n = meshes(index) % n_dimension - err = 0 - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_get_dimension - - - function openmc_mesh_set_dimension(index, n, dims) result(err) bind(C) - ! Set the dimension of a mesh - integer(C_INT32_T), value, intent(in) :: index - integer(C_INT), value, intent(in) :: n - integer(C_INT), intent(in) :: dims(n) - integer(C_INT) :: err - - if (index >= 1 .and. index <= n_meshes) then - associate (m => meshes(index)) - if (allocated(m % dimension)) deallocate (m % dimension) - if (allocated(m % lower_left)) deallocate (m % lower_left) - if (allocated(m % upper_right)) deallocate (m % upper_right) - if (allocated(m % width)) deallocate (m % width) - - m % n_dimension = n - allocate(m % dimension(n)) - allocate(m % lower_left(n)) - allocate(m % upper_right(n)) - allocate(m % width(n)) - - ! Copy dimension - m % dimension(:) = dims - end associate - err = 0 - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_set_dimension - - - function openmc_mesh_get_params(index, ll, ur, width, n) result(err) bind(C) - ! Get the mesh parameters - integer(C_INT32_T), value, intent(in) :: index - type(C_PTR), intent(out) :: ll - type(C_PTR), intent(out) :: ur - type(C_PTR), intent(out) :: width - integer(C_INT), intent(out) :: n - integer(C_INT) :: err - - err = 0 - if (index >= 1 .and. index <= n_meshes) then - associate (m => meshes(index)) - if (allocated(m % lower_left)) then - ll = C_LOC(m % lower_left(1)) - ur = C_LOC(m % upper_right(1)) - width = C_LOC(m % width(1)) - n = m % n_dimension - else - err = E_ALLOCATE - call set_errmsg("Mesh parameters have not been set.") - end if - end associate - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_get_params - - - function openmc_mesh_set_params(index, n, ll, ur, width) result(err) bind(C) - ! Set the mesh parameters - integer(C_INT32_T), value, intent(in) :: index - integer(C_INT), value, intent(in) :: n - real(C_DOUBLE), intent(in), optional :: ll(n) - real(C_DOUBLE), intent(in), optional :: ur(n) - real(C_DOUBLE), intent(in), optional :: width(n) - integer(C_INT) :: err - - err = 0 - if (index >= 1 .and. index <= n_meshes) then - associate (m => meshes(index)) - if (allocated(m % lower_left)) deallocate (m % lower_left) - if (allocated(m % upper_right)) deallocate (m % upper_right) - if (allocated(m % width)) deallocate (m % width) - - allocate(m % lower_left(n)) - allocate(m % upper_right(n)) - allocate(m % width(n)) - - if (present(ll) .and. present(ur)) then - m % lower_left(:) = ll - m % upper_right(:) = ur - m % width(:) = (ur - ll) / m % dimension - elseif (present(ll) .and. present(width)) then - m % lower_left(:) = ll - m % width(:) = width - m % upper_right(:) = ll + width * m % dimension - elseif (present(ur) .and. present(width)) then - m % upper_right(:) = ur - m % width(:) = width - m % lower_left(:) = ur - width * m % dimension - else - err = E_INVALID_ARGUMENT - call set_errmsg("At least two parameters must be specified.") - end if - end associate - else - err = E_OUT_OF_BOUNDS - call set_errmsg("Index in meshes array is out of bounds.") - end if - end function openmc_mesh_set_params - end module mesh_header diff --git a/src/settings.cpp b/src/settings.cpp index 7e727178a..86f3c1fef 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -501,7 +501,7 @@ read_settings_xml() int temp = std::stoi(get_node_value(root, "entropy_mesh")); try { index_entropy_mesh = mesh_map.at(temp); - } catch (std::out_of_range) { + } catch (const std::out_of_range& e) { std::stringstream msg; msg << "Mesh " << temp << " specified for Shannon entropy does not exist."; fatal_error(msg); @@ -550,7 +550,7 @@ read_settings_xml() auto temp = std::stoi(get_node_value(root, "ufs_mesh")); try { index_ufs_mesh = mesh_map.at(temp); - } catch (std::out_of_range) { + } catch (const std::out_of_range& e) { std::stringstream msg; msg << "Mesh " << temp << " specified for uniform fission site method " "does not exist."; From 6a1d653547b2e5ce65fd1b9f830d2509901b564b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 30 Aug 2018 06:44:37 -0500 Subject: [PATCH 53/76] Convert count_bank_sites, Shannon entropy, UFS to C++ (incomplete) --- include/openmc/capi.h | 1 + include/openmc/eigenvalue.h | 37 ++++++++ include/openmc/mesh.h | 3 + include/openmc/message_passing.h | 1 + src/api.F90 | 4 +- src/bank_header.F90 | 18 +++- src/eigenvalue.F90 | 95 ------------------- src/eigenvalue.cpp | 151 +++++++++++++++++++++++++++++++ src/initialize.cpp | 16 ++-- src/input_xml.F90 | 104 --------------------- src/mesh.cpp | 123 +++++++++++++++++++++++++ src/mesh_header.F90 | 71 +++++++-------- src/message_passing.cpp | 1 + src/output.F90 | 12 ++- src/physics.F90 | 23 ++--- src/physics_mg.F90 | 24 ++--- src/settings.cpp | 8 -- src/simulation.F90 | 12 ++- src/simulation_header.F90 | 9 -- src/state_point.F90 | 48 ++++------ src/summary.F90 | 1 - src/tallies/tally.F90 | 1 - 22 files changed, 438 insertions(+), 325 deletions(-) create mode 100644 include/openmc/eigenvalue.h create mode 100644 src/eigenvalue.cpp diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 7ce42aa47..c155e7bd1 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -37,6 +37,7 @@ extern "C" { int openmc_filter_set_type(int32_t index, const char* type); int openmc_finalize(); int openmc_find_cell(double* xyz, int32_t* index, int32_t* instance); + int openmc_fission_bank(struct Bank** ptr, int64_t* n); int openmc_get_cell_index(int32_t id, int32_t* index); int openmc_get_filter_index(int32_t id, int32_t* index); void openmc_get_filter_next_id(int32_t* id); diff --git a/include/openmc/eigenvalue.h b/include/openmc/eigenvalue.h new file mode 100644 index 000000000..c2e76e26f --- /dev/null +++ b/include/openmc/eigenvalue.h @@ -0,0 +1,37 @@ +#ifndef OPENMC_EIGENVALUE_H +#define OPENMC_EIGENVALUE_H + +#include // for int64_t + +#include "openmc/particle.h" + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +extern std::vector entropy; //!< Shannon entropy at each generation +extern xt::xtensor source_frac; //!< Source fraction for UFS + +extern "C" int64_t n_bank; + +//============================================================================== +// Non-member functions +//============================================================================== + +//! Calculates the Shannon entropy of the fission source distribution to assess +//! source convergence +extern "C" void shannon_entropy(); + +//! Determines the source fraction in each UFS mesh cell and reweights the +//! source bank so that the sum of the weights is equal to n_particles. The +//! 'source_frac' variable is used later to bias the production of fission sites +extern "C" void ufs_count_sites(); + +//! Get UFS weight corresponding to particle's location +extern "C" double ufs_get_weight(const Particle* p); + +} // namespace openmc + +#endif // OPENMC_EIGENVALUE_H diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 71649fa61..51a0a627f 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -34,6 +34,9 @@ public: bool intersects(Position r0, Position r1); void to_hdf5(hid_t group); + xt::xarray count_sites(int64_t n, const Bank* bank, + int n_energy, const double* energies, bool* outside); + int id_ {-1}; //!< User-specified ID int n_dimension_; double volume_frac_; diff --git a/include/openmc/message_passing.h b/include/openmc/message_passing.h index 1dab43139..c910210db 100644 --- a/include/openmc/message_passing.h +++ b/include/openmc/message_passing.h @@ -10,6 +10,7 @@ namespace mpi { extern int rank; extern int n_procs; + extern bool master; #ifdef OPENMC_MPI extern MPI_Datatype bank; diff --git a/src/api.F90 b/src/api.F90 index 2a6775a0c..b39a2f8fa 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -11,7 +11,6 @@ module openmc_api use hdf5_interface use material_header use math - use mesh_header, only: free_memory_mesh use message_passing use nuclide_header use initialize, only: openmc_init_f @@ -305,6 +304,9 @@ contains interface subroutine free_memory_source() bind(C) end subroutine + + subroutine free_memory_mesh() bind(C) + end subroutine free_memory_mesh end interface call free_memory_geometry() diff --git a/src/bank_header.F90 b/src/bank_header.F90 index 2a998740e..c39bf8b78 100644 --- a/src/bank_header.F90 +++ b/src/bank_header.F90 @@ -28,7 +28,7 @@ module bank_header type(Bank), allocatable, target :: master_fission_bank(:) #endif - integer(8) :: n_bank ! # of sites in fission bank + integer(C_INT64_T), bind(C) :: n_bank ! # of sites in fission bank !$omp threadprivate(fission_bank, n_bank) @@ -71,4 +71,20 @@ contains end if end function openmc_source_bank + function openmc_fission_bank(ptr, n) result(err) bind(C) + ! Return a pointer to the source bank + type(C_PTR), intent(out) :: ptr + integer(C_INT64_T), intent(out) :: n + integer(C_INT) :: err + + if (.not. allocated(fission_bank)) then + err = E_ALLOCATE + call set_errmsg("Fission bank has not been allocated.") + else + err = 0 + ptr = C_LOC(fission_bank) + n = size(fission_bank) + end if + end function openmc_fission_bank + end module bank_header diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index d47bc4dab..38284c279 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -294,46 +294,6 @@ contains end subroutine synchronize_bank -!=============================================================================== -! SHANNON_ENTROPY calculates the Shannon entropy of the fission source -! distribution to assess source convergence -!=============================================================================== - - subroutine shannon_entropy() - - integer :: i ! index for mesh elements - real(8) :: entropy_gen ! entropy at this generation - logical :: sites_outside ! were there sites outside entropy box? - - associate (m => meshes(index_entropy_mesh)) - ! count number of fission sites over mesh - call count_bank_sites(m, fission_bank, entropy_p, & - size_bank=n_bank, sites_outside=sites_outside) - - ! display warning message if there were sites outside entropy box - if (sites_outside) then - if (master) call warning("Fission source site(s) outside of entropy box.") - end if - - ! sum values to obtain shannon entropy - if (master) then - ! Normalize to total weight of bank sites - entropy_p = entropy_p / sum(entropy_p) - - entropy_gen = ZERO - do i = 1, size(entropy_p, 2) - if (entropy_p(1,i) > ZERO) then - entropy_gen = entropy_gen - & - entropy_p(1,i) * log(entropy_p(1,i))/log(TWO) - end if - end do - - ! Add value to vector - call entropy % push_back(entropy_gen) - end if - end associate - end subroutine shannon_entropy - !=============================================================================== ! CALCULATE_GENERATION_KEFF collects the single-processor tracklength k's onto ! the master processor and normalizes them. This should work whether or not the @@ -577,61 +537,6 @@ contains end function openmc_get_keff -!=============================================================================== -! COUNT_SOURCE_FOR_UFS determines the source fraction in each UFS mesh cell and -! reweights the source bank so that the sum of the weights is equal to -! n_particles. The 'source_frac' variable is used later to bias the production -! of fission sites -!=============================================================================== - - subroutine count_source_for_ufs() - - real(8) :: total ! total weight in source bank - logical :: sites_outside ! were there sites outside the ufs mesh? -#ifdef OPENMC_MPI - integer :: n ! total number of ufs mesh cells - integer :: mpi_err ! MPI error code -#endif - - associate (m => meshes(index_ufs_mesh)) - - if (current_batch == 1 .and. current_gen == 1) then - ! On the first generation, just assume that the source is already evenly - ! distributed so that effectively the production of fission sites is not - ! biased - - source_frac = m % volume_frac - - else - ! count number of source sites in each ufs mesh cell - call count_bank_sites(m, source_bank, source_frac, & - sites_outside=sites_outside, size_bank=work) - - ! Check for sites outside of the mesh - if (master .and. sites_outside) then - call fatal_error("Source sites outside of the UFS mesh!") - end if - -#ifdef OPENMC_MPI - ! Send source fraction to all processors - n = product(m % dimension) - call MPI_BCAST(source_frac, n, MPI_REAL8, 0, mpi_intracomm, mpi_err) -#endif - - ! Normalize to total weight to get fraction of source in each cell - total = sum(source_frac) - source_frac = source_frac / total - - ! Since the total starting weight is not equal to n_particles, we need to - ! renormalize the weight of the source sites - - source_bank % wgt = source_bank % wgt * n_particles / total - end if - - end associate - - end subroutine count_source_for_ufs - #ifdef _OPENMP !=============================================================================== ! JOIN_BANK_FROM_THREADS joins threadprivate fission banks into a single fission diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp new file mode 100644 index 000000000..9ce5b9ef8 --- /dev/null +++ b/src/eigenvalue.cpp @@ -0,0 +1,151 @@ +#include "openmc/eigenvalue.h" + +#include "xtensor/xmath.hpp" +#include "xtensor/xtensor.hpp" +#include "xtensor/xview.hpp" + +#include "openmc/capi.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/mesh.h" +#include "openmc/message_passing.h" +#include "openmc/settings.h" +#include "openmc/simulation.h" + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +std::vector entropy; +xt::xtensor source_frac; + +//============================================================================== +// Non-member functions +//============================================================================== + +void shannon_entropy() +{ + // Get pointer to entropy mesh + auto& m = meshes[settings::index_entropy_mesh]; + + // Get pointer to fission bank + Bank* fission_bank; + int64_t n; + openmc_fission_bank(&fission_bank, &n); + + // Get source weight in each mesh bin + bool sites_outside; + xt::xtensor p = m->count_sites( + n_bank, fission_bank, 0, nullptr, &sites_outside); + + // display warning message if there were sites outside entropy box + if (sites_outside) { + if (mpi::master) warning("Fission source site(s) outside of entropy box."); + } + + // sum values to obtain shannon entropy + if (mpi::master) { + // Normalize to total weight of bank sites + p /= xt::sum(p); + + double H = 0.0; + for (auto p_i : p) { + if (p_i > 0.0) { + H -= p_i * std::log(p_i)/std::log(2.0); + } + } + + // Add value to vector + entropy.push_back(H); + } +} + +void ufs_count_sites() +{ + auto &m = meshes[settings::index_ufs_mesh]; + + if (openmc_current_batch == 1 && openmc_current_gen == 1) { + // On the first generation, just assume that the source is already evenly + // distributed so that effectively the production of fission sites is not + // biased + + auto s = xt::view(source_frac, xt::all()); + s = m->volume_frac_; + + } else { + // Get pointer to source bank + Bank* source_bank; + int64_t n; + openmc_source_bank(&source_bank, &n); + + + // count number of source sites in each ufs mesh cell + bool sites_outside; + source_frac = m->count_sites(openmc_work, source_bank, 0, nullptr, + &sites_outside); + + // Check for sites outside of the mesh + if (mpi::master && sites_outside) { + fatal_error("Source sites outside of the UFS mesh!"); + } + +#ifdef OPENMC_MPI + // Send source fraction to all processors + int n = xt::prod(m->shape_)(); + MPI_Bcast(source_frac.data(), n, MPI_DOUBLE, 0, mpi::intracomm) +#endif + + // Normalize to total weight to get fraction of source in each cell + double total = xt::sum(source_frac)(); + source_frac /= total; + + // Since the total starting weight is not equal to n_particles, we need to + // renormalize the weight of the source sites + for (int i = 0; i < openmc_work; ++i) { + source_bank[i].wgt *= settings::n_particles / total; + } + } +} + +double ufs_get_weight(const Particle* p) +{ + auto& m = meshes[settings::index_entropy_mesh]; + + // Determine indices on ufs mesh for current location + // TODO: off by one + int mesh_bin = m->get_bin({p->coord[0].xyz}) - 1; + if (mesh_bin < 0) { + p->write_restart(); + fatal_error("Source site outside UFS mesh!"); + } + + if (source_frac(mesh_bin) != 0.0) { + return m->volume_frac_ / source_frac(mesh_bin); + } else { + return 1.0; + } +} + +extern "C" void entropy_to_hdf5(hid_t group) +{ + if (settings::entropy_on) { + write_dataset(group, "entropy", entropy); + } +} + +extern "C" void entropy_from_hdf5(hid_t group) +{ + if (settings::entropy_on) { + read_dataset(group, "entropy", entropy); + } +} + +extern "C" double entropy_c(int i) +{ + return entropy.at(i - 1); +} + + +} // namespace openmc diff --git a/src/initialize.cpp b/src/initialize.cpp index 2c6840151..19fc82c85 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -61,7 +61,7 @@ namespace openmc { #ifdef OPENMC_MPI void initialize_mpi(MPI_Comm intracomm) { - openmc::mpi::intracomm = intracomm; + mpi::intracomm = intracomm; // Initialize MPI int flag; @@ -69,13 +69,13 @@ void initialize_mpi(MPI_Comm intracomm) if (!flag) MPI_Init(nullptr, nullptr); // Determine number of processes and rank for each - MPI_Comm_size(intracomm, &openmc::mpi::n_procs); - MPI_Comm_rank(intracomm, &openmc::mpi::rank); + MPI_Comm_size(intracomm, &mpi::n_procs); + MPI_Comm_rank(intracomm, &mpi::rank); // Set variable for Fortran side - openmc_n_procs = openmc::mpi::n_procs; - openmc_rank = openmc::mpi::rank; - openmc_master = (openmc::mpi::rank == 0); + openmc_n_procs = mpi::n_procs; + openmc_rank = mpi::rank; + openmc_master = mpi::master = (mpi::rank == 0); // Create bank datatype Bank b; @@ -88,8 +88,8 @@ void initialize_mpi(MPI_Comm intracomm) }; int blocks[] {1, 3, 3, 1, 1}; MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_INT}; - MPI_Type_create_struct(5, blocks, disp, types, &openmc::mpi::bank); - MPI_Type_commit(&openmc::mpi::bank); + MPI_Type_create_struct(5, blocks, disp, types, &mpi::bank); + MPI_Type_commit(&mpi::bank); } #endif // OPENMC_MPI diff --git a/src/input_xml.F90 b/src/input_xml.F90 index ffee75450..61b320804 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -249,110 +249,6 @@ contains track_identifiers = reshape(temp_int_array, [3, n_tracks/3]) end if - ! Read meshes - call get_node_list(root, "mesh", node_mesh_list) - - ! Check for user meshes and allocate - n = size(node_mesh_list) - if (n > 0) then - err = openmc_extend_meshes(n, i_start, i_end) - end if - - do i = 1, n - associate (m => meshes(i_start + i - 1)) - ! Instantiate mesh from XML node - call m % from_xml(node_mesh_list(i)) - - ! Add mesh to dictionary - call mesh_dict % set(m % id, i_start + i - 1) - end associate - end do - - ! Shannon Entropy mesh - if (check_for_node(root, "entropy_mesh")) then - call get_node_value(root, "entropy_mesh", temp_int) - if (mesh_dict % has(temp_int)) then - index_entropy_mesh = mesh_dict % get(temp_int) - else - call fatal_error("Mesh " // to_str(temp_int) // " specified for & - &Shannon entropy does not exist.") - end if - elseif (check_for_node(root, "entropy")) then - call warning("Specifying a Shannon entropy mesh via the element & - &is deprecated. Please create a mesh using and then reference & - &it by specifying its ID in an element.") - - ! Get pointer to entropy node - node_entropy = root % child("entropy") - - err = openmc_extend_meshes(1, index_entropy_mesh) - - associate (m => meshes(index_entropy_mesh)) - ! Assign ID - m % id = 10000 - - call m % from_xml(node_entropy) - end associate - end if - - if (index_entropy_mesh > 0) then - associate(m => meshes(index_entropy_mesh)) - if (.not. allocated(m % dimension)) then - ! If the user did not specify how many mesh cells are to be used in - ! each direction, we automatically determine an appropriate number of - ! cells - m % n_dimension = 3 - allocate(m % dimension(3)) - m % dimension = ceiling((n_particles/20)**(ONE/THREE)) - - ! Calculate width - m % width = (m % upper_right - m % lower_left) / m % dimension - end if - - ! Allocate space for storing number of fission sites in each mesh cell - allocate(entropy_p(1, product(m % dimension))) - end associate - - ! Turn on Shannon entropy calculation - entropy_on = .true. - end if - - ! Uniform fission source weighting mesh - if (check_for_node(root, "ufs_mesh")) then - call get_node_value(root, "ufs_mesh", temp_int) - if (mesh_dict % has(temp_int)) then - index_ufs_mesh = mesh_dict % get(temp_int) - else - call fatal_error("Mesh " // to_str(temp_int) // " specified for & - &uniform fission site method does not exist.") - end if - elseif (check_for_node(root, "uniform_fs")) then - call warning("Specifying a UFS mesh via the element & - &is deprecated. Please create a mesh using and then reference & - &it by specifying its ID in a element.") - - ! Get pointer to ufs node - node_ufs = root % child("uniform_fs") - - err = openmc_extend_meshes(1, index_ufs_mesh) - - ! Allocate mesh object and coordinates on mesh - associate (m => meshes(index_ufs_mesh)) - ! Assign ID - m % id = 10001 - - call m % from_xml(node_ufs) - end associate - end if - - if (index_ufs_mesh > 0) then - ! Allocate array to store source fraction for UFS - allocate(source_frac(1, product(meshes(index_ufs_mesh) % dimension))) - - ! Turn on uniform fission source weighting - ufs = .true. - end if - ! Check if the user has specified to write state points if (check_for_node(root, "state_point")) then diff --git a/src/mesh.cpp b/src/mesh.cpp index 8aecd1a22..47f03ad3d 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,9 +1,14 @@ #include "openmc/mesh.h" +#include // for copy #include // for size_t #include // for ceil #include +#ifdef OPENMC_MPI +#include "mpi.h" +#endif +#include "xtensor/xbuilder.hpp" #include "xtensor/xeval.hpp" #include "xtensor/xmath.hpp" #include "xtensor/xsort.hpp" @@ -13,6 +18,8 @@ #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" +#include "openmc/message_passing.h" +#include "openmc/search.h" #include "openmc/xml_interface.h" namespace openmc { @@ -521,6 +528,76 @@ void RegularMesh::to_hdf5(hid_t group) close_group(mesh_group); } +xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, + int n_energy, const double* energies, bool* outside) +{ + // Determine shape of array for counts + int m = xt::prod(shape_)(); + std::vector shape; + if (n_energy > 0) { + shape = {m, n_energy}; + } else { + shape = {m}; + } + + // Create array of zeros + xt::xarray cnt {shape, 0.0}; + bool outside_ = false; + + for (int64_t i = 0; i < n; ++i) { + // determine scoring bin for entropy mesh + int mesh_bin = get_bin({bank[i].xyz}); + + // if outside mesh, skip particle + if (mesh_bin < 0) { + outside_ = true; + continue; + } + + if (n_energy > 0) { + double E = bank[i].E; + int e_bin; + if (E >= energies[0] && E <= energies[n_energy - 1]) { + // determine energy bin + int e_bin = lower_bound_index(energies, energies + n_energy, E); + + // Add to appropriate bin + cnt(mesh_bin, e_bin) += bank[i].wgt; + } + } else { + // Add to appropriate bin + cnt(mesh_bin) += bank[i].wgt; + } + } + + // Create copy of count data + int total = cnt.size(); + double* cnt_reduced = new double[total]; + +#ifdef OPENMC_MPI + // collect values from all processors + MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, + mpi::intracomm); + if (outside) { + MPI_Reduce(&outside_, outside, 1, MPI_BOOL, MPI_LOR, 0, mpi::intracomm); + } + + // Check if there were sites outside the mesh for any processor + MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, & + mpi_intracomm, mpi_err) + end if +#else + std::copy(cnt.data(), cnt.data() + total, cnt_reduced); + if (outside) *outside = outside_; +#endif + + // Adapt reduced values in array back into an xarray + auto arr = xt::adapt(cnt_reduced, total, xt::acquire_ownership(), shape); + xt::xarray counts = arr; + + return counts; +} + //============================================================================== // C API functions //============================================================================== @@ -660,4 +737,50 @@ openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, return 0; } +//============================================================================== +// Fortran compatibility +//============================================================================== + +extern "C" { + int32_t mesh_id(RegularMesh* m) { return m->id_; } + + double mesh_volume_frac(RegularMesh* m) { return m->volume_frac_; } + + int mesh_n_dimension(RegularMesh* m) { return m->n_dimension_; } + + double* mesh_lower_left(RegularMesh* m) { return m->lower_left_.data(); } + + int mesh_get_bin(RegularMesh* m, const double* xyz) + { + return m->get_bin({xyz}); + } + + void meshes_to_hdf5(hid_t group) + { + // Write number of meshes + hid_t meshes_group = create_group(group, "meshes"); + int32_t n_meshes = meshes.size(); + write_attribute(meshes_group, "n_meshes", n_meshes); + + if (n_meshes > 0) { + // Write IDs of meshes + std::vector ids; + for (const auto& m : meshes) { + m->to_hdf5(meshes_group); + ids.push_back(m->id_); + } + write_attribute(meshes_group, "ids", ids); + } + + close_group(meshes_group); + } + + void free_memory_mesh() + { + meshes.clear(); + mesh_map.clear(); + } +} + + } // namespace openmc diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 52c220976..8a8d16c08 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -11,7 +11,6 @@ module mesh_header implicit none private - public :: free_memory_mesh public :: openmc_extend_meshes public :: openmc_get_mesh_index public :: openmc_mesh_get_id @@ -27,22 +26,23 @@ module mesh_header !=============================================================================== type, public :: RegularMesh - integer :: id = -1 ! user-specified id - integer :: type = MESH_REGULAR ! rectangular, hexagonal + type(C_PTR) :: ptr integer(C_INT) :: n_dimension ! rank of mesh - real(8) :: volume_frac ! volume fraction of each cell integer(C_INT), allocatable :: dimension(:) ! number of cells in each direction real(C_DOUBLE), allocatable :: lower_left(:) ! lower-left corner of mesh real(C_DOUBLE), allocatable :: upper_right(:) ! upper-right corner of mesh real(C_DOUBLE), allocatable :: width(:) ! width of each mesh cell contains + procedure :: id => regular_id + procedure :: volume_frac => regular_volume_frac + + procedure :: from_xml => regular_from_xml procedure :: get_bin => regular_get_bin procedure :: get_indices => regular_get_indices procedure :: get_bin_from_indices => regular_get_bin_from_indices procedure :: get_indices_from_bin => regular_get_indices_from_bin procedure :: intersects => regular_intersects - procedure :: to_hdf5 => regular_to_hdf5 end type RegularMesh integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes @@ -121,6 +121,36 @@ module mesh_header contains + function regular_id(this) result(id) + class(RegularMesh), intent(in) :: this + integer(C_INT32_T) :: id + + interface + function mesh_id(ptr) result(id) bind(C) + import C_PTR, C_INT32_T + type(C_PTR), value :: ptr + integer(C_INT32_T) :: id + end function + end interface + + id = mesh_id(this % ptr) + end function + + function regular_volume_frac(this) result(volume_frac) + class(RegularMesh), intent(in) :: this + real(C_DOUBLE) :: volume_frac + + interface + function mesh_volume_frac(ptr) result(volume_frac) bind(C) + import C_PTR, C_DOUBLE + type(C_PTR), value :: ptr + real(C_DOUBLE) :: volume_frac + end function + end interface + + volume_frac = mesh_volume_frac(this % ptr) + end function + subroutine regular_from_xml(this, node) class(RegularMesh), intent(inout) :: this type(XMLNode), intent(in) :: node @@ -598,35 +628,4 @@ contains end function mesh_intersects_3d -!=============================================================================== -! TO_HDF5 writes the mesh data to an HDF5 group -!=============================================================================== - - subroutine regular_to_hdf5(this, group) - class(RegularMesh), intent(in) :: this - integer(HID_T), intent(in) :: group - - integer(HID_T) :: mesh_group - - mesh_group = create_group(group, "mesh " // trim(to_str(this % id))) - - call write_dataset(mesh_group, "type", "regular") - call write_dataset(mesh_group, "dimension", this % dimension) - call write_dataset(mesh_group, "lower_left", this % lower_left) - call write_dataset(mesh_group, "upper_right", this % upper_right) - call write_dataset(mesh_group, "width", this % width) - - call close_group(mesh_group) - end subroutine regular_to_hdf5 - -!=============================================================================== -! FREE_MEMORY_MESH deallocates global arrays defined in this module -!=============================================================================== - - subroutine free_memory_mesh() - n_meshes = 0 - if (allocated(meshes)) deallocate(meshes) - call mesh_dict % clear() - end subroutine free_memory_mesh - end module mesh_header diff --git a/src/message_passing.cpp b/src/message_passing.cpp index aac677c6e..ec2fc2d68 100644 --- a/src/message_passing.cpp +++ b/src/message_passing.cpp @@ -5,6 +5,7 @@ namespace mpi { int rank {0}; int n_procs {1}; +bool master {false}; #ifdef OPENMC_MPI MPI_Comm intracomm; diff --git a/src/output.F90 b/src/output.F90 index b7b418a39..e28695667 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -33,6 +33,14 @@ module output integer :: ou = OUTPUT_UNIT integer :: eu = ERROR_UNIT + interface + function entropy(i) result(h) bind(C, name='entropy_c') + import C_INT, C_DOUBLE + integer(C_INT), value :: i + real(C_DOUBLE) :: h + end function + end interface + contains !=============================================================================== @@ -335,7 +343,7 @@ contains ! write out entropy info if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') & - entropy % data(i) + entropy(i) if (n > 1) then write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5," +/-",F8.5)', ADVANCE='NO') & @@ -369,7 +377,7 @@ contains ! write out entropy info if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') & - entropy % data(i) + entropy(i) ! write out accumulated k-effective if after first active batch if (n > 1) then diff --git a/src/physics.F90 b/src/physics.F90 index 992e48767..f7d80261a 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -1187,6 +1187,14 @@ contains real(8) :: weight ! weight adjustment for ufs method type(Nuclide), pointer :: nuc + interface + function ufs_get_weight(p) result(weight) bind(C) + import Particle, C_DOUBLE + type(Particle), intent(in) :: p + real(C_DOUBLE) :: WEIGHT + end function + end interface + ! Get pointers nuc => nuclides(i_nuclide) @@ -1196,20 +1204,7 @@ contains ! the expected number of fission sites produced if (ufs) then - associate (m => meshes(index_ufs_mesh)) - ! Determine indices on ufs mesh for current location - call m % get_bin(p % coord(1) % xyz, mesh_bin) - if (mesh_bin == NO_BIN_FOUND) then - call particle_write_restart(p) - call fatal_error("Source site outside UFS mesh!") - end if - - if (source_frac(1, mesh_bin) /= ZERO) then - weight = m % volume_frac / source_frac(1, mesh_bin) - else - weight = ONE - end if - end associate + weight = ufs_get_weight(p) else weight = ONE end if diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 40df6e1cb..84695153c 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -174,27 +174,21 @@ contains real(8) :: phi ! fission neutron azimuthal angle real(8) :: weight ! weight adjustment for ufs method + interface + function ufs_get_weight(p) result(weight) bind(C) + import Particle, C_DOUBLE + type(Particle), intent(in) :: p + real(C_DOUBLE) :: WEIGHT + end function + end interface + ! TODO: Heat generation from fission ! If uniform fission source weighting is turned on, we increase of decrease ! the expected number of fission sites produced if (ufs) then - associate (m => meshes(index_ufs_mesh)) - ! Determine indices on ufs mesh for current location - call m % get_bin(p % coord(1) % xyz, mesh_bin) - - if (mesh_bin == NO_BIN_FOUND) then - call particle_write_restart(p) - call fatal_error("Source site outside UFS mesh!") - end if - - if (source_frac(1, mesh_bin) /= ZERO) then - weight = m % volume_frac / source_frac(1, mesh_bin) - else - weight = ONE - end if - end associate + weight = ufs_get_weight(p) else weight = ONE end if diff --git a/src/settings.cpp b/src/settings.cpp index 86f3c1fef..7b00b9eca 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -537,10 +537,6 @@ read_settings_xml() m.width_ = (m.upper_right_ - m.lower_left_) / m.shape_; } - // TODO: Allocate entropy_P - // Allocate space for storing number of fission sites in each mesh cell - //allocate(entropy_p(1, product(m % dimension))) - // Turn on Shannon entropy calculation settings::entropy_on = true; } @@ -574,10 +570,6 @@ read_settings_xml() } if (index_ufs_mesh >= 0) { - // Allocate array to store source fraction for UFS - // TODO: Allocate source_frac - //allocate(source_frac(1, product(meshes(index_ufs_mesh) % dimension))) - // Turn on uniform fission source weighting settings::ufs_on = true; } diff --git a/src/simulation.F90 b/src/simulation.F90 index d334b46b8..8b7cfdb27 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -10,7 +10,7 @@ module simulation use cmfd_execute, only: cmfd_init_batch, cmfd_tally_init, execute_cmfd use cmfd_header, only: cmfd_on use constants, only: ZERO - use eigenvalue, only: count_source_for_ufs, calculate_average_keff, & + use eigenvalue, only: calculate_average_keff, & calculate_generation_keff, shannon_entropy, & synchronize_bank, keff_generation, k_sum #ifdef _OPENMP @@ -234,12 +234,17 @@ contains subroutine initialize_generation() + interface + subroutine ufs_count_sites() bind(C) + end subroutine + end interface + if (run_mode == MODE_EIGENVALUE) then ! Reset number of fission bank sites n_bank = 0 ! Count source sites if using uniform fission source weighting - if (ufs) call count_source_for_ufs() + if (ufs) call ufs_count_sites() ! Store current value of tracklength k keff_generation = global_tallies(RESULT_VALUE, K_TRACKLENGTH) @@ -256,6 +261,9 @@ contains interface subroutine fill_source_bank_fixedsource() bind(C) end subroutine + + subroutine shannon_entropy() bind(C) + end subroutine end interface ! Update global tallies with the omp private accumulation variables diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 0e38b76f2..9b7c68cd4 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -47,13 +47,6 @@ module simulation_header real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength - ! Shannon entropy - type(VectorReal) :: entropy ! shannon entropy at each generation - real(8), allocatable :: entropy_p(:,:) ! % of source sites in each cell - - ! Uniform fission source weighting - real(8), allocatable :: source_frac(:,:) - ! ============================================================================ ! PARALLEL PROCESSING VARIABLES @@ -87,8 +80,6 @@ contains !=============================================================================== subroutine free_memory_simulation() - if (allocated(entropy_p)) deallocate(entropy_p) - if (allocated(source_frac)) deallocate(source_frac) if (allocated(work_index)) deallocate(work_index) call k_generation % clear() diff --git a/src/state_point.F90 b/src/state_point.F90 index bc6474de2..b7f4e1377 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -20,7 +20,6 @@ module state_point use endf, only: reaction_name use error, only: fatal_error, warning, write_message use hdf5_interface - use mesh_header, only: RegularMesh, meshes, n_meshes use message_passing use mgxs_interface use nuclide_header, only: nuclides @@ -79,6 +78,17 @@ contains character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name logical :: parallel + interface + subroutine meshes_to_hdf5(group) bind(C) + import HID_T + integer(HID_T), value :: group + end subroutine + subroutine entropy_to_hdf5(group) bind(C) + import HID_T + integer(HID_T), value :: group + end subroutine + end interface + err = 0 ! Set the filename @@ -163,9 +173,7 @@ contains call write_dataset(file_id, "generations_per_batch", gen_per_batch) k = k_generation % size() call write_dataset(file_id, "k_generation", k_generation % data(1:k)) - if (entropy_on) then - call write_dataset(file_id, "entropy", entropy % data(1:k)) - end if + call entropy_to_hdf5() call write_dataset(file_id, "k_col_abs", k_col_abs) call write_dataset(file_id, "k_col_tra", k_col_tra) call write_dataset(file_id, "k_abs_tra", k_abs_tra) @@ -192,26 +200,8 @@ contains tallies_group = create_group(file_id, "tallies") - ! Write number of meshes - meshes_group = create_group(tallies_group, "meshes") - call write_attribute(meshes_group, "n_meshes", n_meshes) - - if (n_meshes > 0) then - ! Write IDs of meshes - allocate(id_array(n_meshes)) - do i = 1, n_meshes - id_array(i) = meshes(i) % id - end do - call write_attribute(meshes_group, "ids", id_array) - deallocate(id_array) - - ! Write information for meshes - MESH_LOOP: do i = 1, n_meshes - call meshes(i) % to_hdf5(meshes_group) - end do MESH_LOOP - end if - - call close_group(meshes_group) + ! Write meshes + call meshes_to_hdf5(tallies_group) ! Write information for derivatives. if (size(tally_derivs) > 0) then @@ -641,6 +631,11 @@ contains logical :: source_present character(MAX_WORD_LEN) :: word + interface + subroutine entropy_from_hdf5() bind(C) + end subroutine + end interface + ! Write message call write_message("Loading state point " // trim(path_state_point) & // "...", 5) @@ -722,10 +717,7 @@ contains call k_generation % resize(n) call read_dataset(k_generation % data(1:n), file_id, "k_generation") - if (entropy_on) then - call entropy % resize(n) - call read_dataset(entropy % data(1:n), file_id, "entropy") - end if + call entropy_from_hdf5() call read_dataset(k_col_abs, file_id, "k_col_abs") call read_dataset(k_col_tra, file_id, "k_col_tra") call read_dataset(k_abs_tra, file_id, "k_abs_tra") diff --git a/src/summary.F90 b/src/summary.F90 index 750a9899f..0fafd7e5d 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -6,7 +6,6 @@ module summary use geometry_header use hdf5_interface use material_header, only: Material, n_materials, openmc_material_get_volume - use mesh_header, only: RegularMesh use message_passing use mgxs_interface use nuclide_header diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 9967606d1..a618f351e 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -8,7 +8,6 @@ module tally use error, only: fatal_error use geometry_header use math, only: t_percentile - use mesh_header, only: RegularMesh, meshes use message_passing use mgxs_interface use nuclide_header From 18f9f91833f8267796f63d7dde826c177300c0d0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 30 Aug 2018 09:57:26 -0500 Subject: [PATCH 54/76] Read meshes from tallies file --- include/openmc/mesh.h | 8 ++++++++ include/openmc/output.h | 2 ++ include/openmc/settings.h | 5 ++--- src/input_xml.F90 | 31 ++++++++++--------------------- src/mesh.cpp | 15 +++++++++++++++ src/settings.cpp | 14 ++------------ 6 files changed, 39 insertions(+), 36 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 51a0a627f..28f9c3eac 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -51,6 +51,14 @@ private: bool intersects_3d(Position r0, Position r1); }; +//============================================================================== +// Non-member functions +//============================================================================== + +//! Read meshes from either settings/tallies +//! \param[in] root XML node +extern "C" void read_meshes(pugi::xml_node* root); + //============================================================================== // Global variables //============================================================================== diff --git a/include/openmc/output.h b/include/openmc/output.h index cabd39ede..1ba5d6599 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -22,5 +22,7 @@ void header(const char* msg, int level); extern "C" void print_overlap_check(); +extern "C" void title(); + } // namespace openmc #endif // OPENMC_OUTPUT_H diff --git a/include/openmc/settings.h b/include/openmc/settings.h index be8661f4d..e5684c7ae 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -89,13 +89,12 @@ extern "C" double weight_survive; //!< Survival weight after Russian roul } // namespace settings -//============================================================================== //! Read settings from XML file //! \param[in] root XML node for -//============================================================================== - extern "C" void read_settings_xml(); +extern "C" void read_settings_xml_f(pugi::xml_node_struct* root_ptr); + } // namespace openmc #endif // OPENMC_SETTINGS_H diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 61b320804..bfd604f9e 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -65,17 +65,17 @@ module input_xml subroutine read_surfaces(node_ptr) bind(C) import C_PTR - type(C_PTR) :: node_ptr + type(C_PTR), value :: node_ptr end subroutine read_surfaces subroutine read_cells(node_ptr) bind(C) import C_PTR - type(C_PTR) :: node_ptr + type(C_PTR), value :: node_ptr end subroutine read_cells subroutine read_lattices(node_ptr) bind(C) import C_PTR - type(C_PTR) :: node_ptr + type(C_PTR), value :: node_ptr end subroutine read_lattices subroutine read_settings_xml() bind(C) @@ -83,9 +83,14 @@ module input_xml subroutine read_materials(node_ptr) bind(C) import C_PTR - type(C_PTR) :: node_ptr + type(C_PTR), value :: node_ptr end subroutine read_materials + subroutine read_meshes(node_ptr) bind(C) + import C_PTR + type(C_PTR), value :: node_ptr + end subroutine + function find_root_universe() bind(C) result(root) import C_INT32_T integer(C_INT32_T) :: root @@ -1202,9 +1207,6 @@ contains ! ========================================================================== ! DETERMINE SIZE OF ARRAYS AND ALLOCATE - ! Get pointer list to XML - call get_node_list(root, "mesh", node_mesh_list) - ! Get pointer list to XML call get_node_list(root, "filter", node_filt_list) @@ -1220,20 +1222,7 @@ contains ! READ MESH DATA ! Check for user meshes and allocate - n = size(node_mesh_list) - if (n > 0) then - err = openmc_extend_meshes(n, i_start, i_end) - end if - - do i = 1, n - m => meshes(i_start + i - 1) - - ! Instantiate mesh from XML node - call m % from_xml(node_mesh_list(i)) - - ! Add mesh to dictionary - call mesh_dict % set(m % id, i_start + i - 1) - end do + call read_meshes() ! We only need the mesh info for plotting if (run_mode == MODE_PLOTTING) then diff --git a/src/mesh.cpp b/src/mesh.cpp index 47f03ad3d..113968242 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -737,6 +737,21 @@ openmc_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, return 0; } +//============================================================================== +// Non-member functions +//============================================================================== + +void read_meshes(pugi::xml_node* root) +{ + for (auto node : root->children("mesh")) { + // Read mesh and add to vector + meshes.emplace_back(new RegularMesh{node}); + + // Map ID to position in vector + mesh_map[meshes.back()->id_] = meshes.size() - 1; + } +} + //============================================================================== // Fortran compatibility //============================================================================== diff --git a/src/settings.cpp b/src/settings.cpp index 7b00b9eca..4883d07a3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -170,11 +170,7 @@ void get_run_parameters(pugi::xml_node node_base) } } -extern "C" void title(); -extern "C" void read_settings_xml_f(pugi::xml_node_struct* root_ptr); - -extern "C" void -read_settings_xml() +void read_settings_xml() { using namespace settings; using namespace pugi; @@ -488,13 +484,7 @@ read_settings_xml() } // Read meshes - for (auto node : root.children("mesh")) { - // Read mesh and add to vector - meshes.emplace_back(new RegularMesh{node}); - - // Map ID to position in vector - mesh_map[meshes.back()->id_] = meshes.size() - 1; - } + read_meshes(&root); // Shannon Entropy mesh if (check_for_node(root, "entropy_mesh")) { From 666553da2775084bb0598910abd27399e042d039 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 30 Aug 2018 10:38:53 -0500 Subject: [PATCH 55/76] Add bindings on RegularMesh Fortran type --- src/mesh.cpp | 25 +- src/mesh_header.F90 | 581 ++++++++++---------------------------------- src/plot.F90 | 85 +++---- src/plot_header.F90 | 3 +- 4 files changed, 196 insertions(+), 498 deletions(-) diff --git a/src/mesh.cpp b/src/mesh.cpp index 113968242..9c955fae7 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -757,19 +757,42 @@ void read_meshes(pugi::xml_node* root) //============================================================================== extern "C" { + RegularMesh* mesh_ptr(int i) { return meshes[i-1].get(); } + int32_t mesh_id(RegularMesh* m) { return m->id_; } double mesh_volume_frac(RegularMesh* m) { return m->volume_frac_; } int mesh_n_dimension(RegularMesh* m) { return m->n_dimension_; } - double* mesh_lower_left(RegularMesh* m) { return m->lower_left_.data(); } + int mesh_dimension(RegularMesh* m, int i) { return m->shape_(i - 1); } + + double mesh_lower_left(RegularMesh* m, int i) { return m->lower_left_(i - 1); } + + double mesh_upper_right(RegularMesh* m, int i) { return m->upper_right_(i - 1); } + + double mesh_width(RegularMesh* m, int i) { return m->width_(i - 1); } int mesh_get_bin(RegularMesh* m, const double* xyz) { return m->get_bin({xyz}); } + int mesh_get_bin_from_indices(RegularMesh* m, const int* ijk) + { + return m->get_bin_from_indices(ijk); + } + + void mesh_get_indices(RegularMesh* m, const double* xyz, int* ijk, bool* in_mesh) + { + m->get_indices({xyz}, ijk, in_mesh); + } + + void mesh_get_indices_from_bin(RegularMesh* m, int bin, int* ijk) + { + m->get_indices_from_bin(bin, ijk); + } + void meshes_to_hdf5(hid_t group) { // Write number of meshes diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 8a8d16c08..591263000 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -27,28 +27,22 @@ module mesh_header type, public :: RegularMesh type(C_PTR) :: ptr - integer(C_INT) :: n_dimension ! rank of mesh - integer(C_INT), allocatable :: dimension(:) ! number of cells in each direction - real(C_DOUBLE), allocatable :: lower_left(:) ! lower-left corner of mesh - real(C_DOUBLE), allocatable :: upper_right(:) ! upper-right corner of mesh - real(C_DOUBLE), allocatable :: width(:) ! width of each mesh cell contains procedure :: id => regular_id procedure :: volume_frac => regular_volume_frac + procedure :: n_dimension => regular_n_dimension + procedure :: lower_left => regular_lower_left + procedure :: upper_right => regular_upper_right + procedure :: width => regular_width - - procedure :: from_xml => regular_from_xml procedure :: get_bin => regular_get_bin procedure :: get_indices => regular_get_indices procedure :: get_bin_from_indices => regular_get_bin_from_indices procedure :: get_indices_from_bin => regular_get_indices_from_bin - procedure :: intersects => regular_intersects end type RegularMesh integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes - type(RegularMesh), public, allocatable, target :: meshes(:) - ! Dictionary that maps user IDs to indices in 'meshes' type(DictIntInt), public :: mesh_dict @@ -117,167 +111,143 @@ module mesh_header real(C_DOUBLE), intent(in), optional :: width(n) integer(C_INT) :: err end function openmc_mesh_set_params + + function mesh_id(ptr) result(id) bind(C) + import C_PTR, C_INT32_T + type(C_PTR), value :: ptr + integer(C_INT32_T) :: id + end function + + function mesh_volume_frac(ptr) result(volume_frac) bind(C) + import C_PTR, C_DOUBLE + type(C_PTR), value :: ptr + real(C_DOUBLE) :: volume_frac + end function + + function mesh_n_dimension(ptr) result(n) bind(C) + import C_PTR, C_INT + type(C_PTR), value :: ptr + integer(C_INT) :: n + end function + + function mesh_dimension(ptr, i) result(d) bind(C) + import C_PTR, C_INT + type(C_PTR), value :: ptr + integer(C_INT), value :: i + integer(C_INT) :: d + end function + + function mesh_lower_left(ptr, i) result(ll) bind(C) + import C_PTR, C_INT, C_DOUBLE + type(C_PTR), value :: ptr + integer(C_INT), value :: i + real(C_DOUBLE) :: ll + end function + + function mesh_upper_right(ptr, i) result(ur) bind(C) + import C_PTR, C_INT, C_DOUBLE + type(C_PTR), value :: ptr + integer(C_INT), value :: i + real(C_DOUBLE) :: ur + end function + + function mesh_width(ptr, i) result(w) bind(C) + import C_PTR, C_INT, C_DOUBLE + type(C_PTR), value :: ptr + integer(C_INT), value :: i + real(C_DOUBLE) :: w + end function + + function mesh_get_bin(ptr, xyz) result(bin) bind(C) + import C_PTR, C_DOUBLE, C_INT + type(C_PTR), value :: ptr + real(C_DOUBLE), intent(in) :: xyz(*) + integer(C_INT) :: bin + end function + + function mesh_get_bin_from_indices(ptr, ijk) result(bin) bind(C) + import C_PTR, C_INT + type(C_PTR), value :: ptr + integer(C_INT), intent(in) :: ijk(*) + integer(C_INT) :: bin + end function + + subroutine mesh_get_indices(ptr, xyz, ijk, in_mesh) bind(C) + import C_PTR, C_DOUBLE, C_INT, C_BOOL + type(C_PTR), value :: ptr + real(C_DOUBLE), intent(in) :: xyz(*) + integer(C_INT), intent(out) :: ijk(*) + logical(C_BOOL), intent(out) :: in_mesh + end subroutine + + subroutine mesh_get_indices_from_bin(ptr, bin, ijk) bind(C) + import C_PTR, C_INT + type(C_PTR), value :: ptr + integer(C_INT), value :: bin + integer(C_INT), intent(out) :: ijk(*) + end subroutine + + function mesh_ptr(i) result(ptr) bind(C) + import C_INT, C_PTR + integer(C_INT), value :: i + type(C_PTR) :: ptr + end function end interface contains + function meshes(i) result(m) + integer, intent(in) :: i + type(RegularMesh) :: m + + m % ptr = mesh_ptr(i) + end function + function regular_id(this) result(id) class(RegularMesh), intent(in) :: this integer(C_INT32_T) :: id - - interface - function mesh_id(ptr) result(id) bind(C) - import C_PTR, C_INT32_T - type(C_PTR), value :: ptr - integer(C_INT32_T) :: id - end function - end interface - id = mesh_id(this % ptr) end function function regular_volume_frac(this) result(volume_frac) class(RegularMesh), intent(in) :: this real(C_DOUBLE) :: volume_frac - - interface - function mesh_volume_frac(ptr) result(volume_frac) bind(C) - import C_PTR, C_DOUBLE - type(C_PTR), value :: ptr - real(C_DOUBLE) :: volume_frac - end function - end interface - volume_frac = mesh_volume_frac(this % ptr) end function - subroutine regular_from_xml(this, node) - class(RegularMesh), intent(inout) :: this - type(XMLNode), intent(in) :: node + function regular_n_dimension(this) result(n) + class(RegularMesh), intent(in) :: this + integer(C_INT) :: n + n = mesh_n_dimension(this % ptr) + end function - integer :: n - character(MAX_LINE_LEN) :: temp_str + function regular_dimension(this, i) result(d) + class(RegularMesh), intent(in) :: this + integer(C_INT), intent(in) :: i + integer(C_INT) :: d + d = mesh_dimension(this % ptr, i) + end function - ! Copy mesh id - if (check_for_node(node, "id")) then - call get_node_value(node, "id", this % id) + function regular_lower_left(this, i) result(ll) + class(RegularMesh), intent(in) :: this + integer(C_INT), intent(in) :: i + real(C_DOUBLE) :: ll + ll = mesh_lower_left(this % ptr, i) + end function - ! Check to make sure 'id' hasn't been used - if (mesh_dict % has(this % id)) then - call fatal_error("Two or more meshes use the same unique ID: " & - // to_str(this % id)) - end if - end if + function regular_upper_right(this, i) result(ur) + class(RegularMesh), intent(in) :: this + integer(C_INT), intent(in) :: i + real(C_DOUBLE) :: ur + ur = mesh_upper_right(this % ptr, i) + end function - ! Read mesh type - if (check_for_node(node, "type")) then - call get_node_value(node, "type", temp_str) - select case (to_lower(temp_str)) - case ('rect', 'rectangle', 'rectangular') - call warning("Mesh type '" // trim(temp_str) // "' is deprecated. & - &Please use 'regular' instead.") - this % type = MESH_REGULAR - case ('regular') - this % type = MESH_REGULAR - case default - call fatal_error("Invalid mesh type: " // trim(temp_str)) - end select - else - this % type = MESH_REGULAR - end if - - ! Determine number of dimensions for mesh - if (check_for_node(node, "dimension")) then - n = node_word_count(node, "dimension") - if (n /= 1 .and. n /= 2 .and. n /= 3) then - call fatal_error("Mesh must be one, two, or three dimensions.") - end if - this % n_dimension = n - - ! Allocate attribute arrays - allocate(this % dimension(n)) - - ! Check that dimensions are all greater than zero - call get_node_array(node, "dimension", this % dimension) - if (any(this % dimension <= 0)) then - call fatal_error("All entries on the element for a tally & - &mesh must be positive.") - end if - end if - - ! Check for lower-left coordinates - if (check_for_node(node, "lower_left")) then - n = node_word_count(node, "lower_left") - allocate(this % lower_left(n)) - - ! Read mesh lower-left corner location - call get_node_array(node, "lower_left", this % lower_left) - else - call fatal_error("Must specify on a mesh.") - end if - - if (check_for_node(node, "width")) then - ! Make sure both upper-right or width were specified - if (check_for_node(node, "upper_right")) then - call fatal_error("Cannot specify both and on a & - &mesh.") - end if - - n = node_word_count(node, "width") - allocate(this % width(n)) - allocate(this % upper_right(n)) - - ! Check to ensure width has same dimensions - if (n /= size(this % lower_left)) then - call fatal_error("Number of entries on must be the same as & - &the number of entries on .") - end if - - ! Check for negative widths - call get_node_array(node, "width", this % width) - if (any(this % width < ZERO)) then - call fatal_error("Cannot have a negative on a tally mesh.") - end if - - ! Set width and upper right coordinate - this % upper_right = this % lower_left + this % dimension * this % width - - elseif (check_for_node(node, "upper_right")) then - n = node_word_count(node, "upper_right") - allocate(this % upper_right(n)) - allocate(this % width(n)) - - ! Check to ensure width has same dimensions - if (n /= size(this % lower_left)) then - call fatal_error("Number of entries on must be the & - &same as the number of entries on .") - end if - - ! Check that upper-right is above lower-left - call get_node_array(node, "upper_right", this % upper_right) - if (any(this % upper_right < this % lower_left)) then - call fatal_error("The coordinates must be greater than & - &the coordinates on a tally mesh.") - end if - - ! Set width and upper right coordinate - this % width = (this % upper_right - this % lower_left) / this % dimension - else - call fatal_error("Must specify either and on a & - &mesh.") - end if - - if (allocated(this % dimension)) then - if (size(this % dimension) /= size(this % lower_left)) then - call fatal_error("Number of entries on must be the same & - &as the number of entries on .") - end if - - ! Set volume fraction - this % volume_frac = ONE/real(product(this % dimension),8) - end if - - end subroutine regular_from_xml + function regular_width(this, i) result(w) + class(RegularMesh), intent(in) :: this + integer(C_INT), intent(in) :: i + real(C_DOUBLE) :: w + w = mesh_width(this % ptr, i) + end function !=============================================================================== ! GET_MESH_BIN determines the tally bin for a particle in a structured mesh @@ -288,38 +258,8 @@ contains real(8), intent(in) :: xyz(:) ! coordinates integer, intent(out) :: bin ! tally bin - integer :: n ! size of mesh - integer :: d ! mesh dimension index - integer :: ijk(3) ! indices in mesh - logical :: in_mesh ! was given coordinate in mesh at all? - - ! Get number of dimensions - n = this % n_dimension - - ! Loop over the dimensions of the mesh - do d = 1, n - - ! Check for cases where particle is outside of mesh - if (xyz(d) < this % lower_left(d)) then - bin = NO_BIN_FOUND - return - elseif (xyz(d) > this % upper_right(d)) then - bin = NO_BIN_FOUND - return - end if - end do - - ! Determine indices - call this % get_indices(xyz, ijk, in_mesh) - - ! Convert indices to bin - if (in_mesh) then - bin = this % get_bin_from_indices(ijk) - else - bin = NO_BIN_FOUND - end if - - end subroutine regular_get_bin + bin = mesh_get_bin(this % ptr, xyz) + end subroutine !=============================================================================== ! GET_MESH_INDICES determines the indices of a particle in a structured mesh @@ -331,18 +271,10 @@ contains integer, intent(out) :: ijk(:) ! indices in mesh logical, intent(out) :: in_mesh ! were given coords in mesh? - ! Find particle in mesh - ijk(:this % n_dimension) = ceiling((xyz(:this % n_dimension) - & - this % lower_left)/this % width) - - ! Determine if particle is in mesh - if (any(ijk(:this % n_dimension) < 1) .or. & - any(ijk(:this % n_dimension) > this % dimension)) then - in_mesh = .false. - else - in_mesh = .true. - end if + logical(C_BOOL) :: in_mesh_ + call mesh_get_indices(this % ptr, xyz, ijk, in_mesh_) + in_mesh = in_mesh_ end subroutine regular_get_indices !=============================================================================== @@ -355,15 +287,7 @@ contains integer, intent(in) :: ijk(:) integer :: bin - if (this % n_dimension == 1) then - bin = ijk(1) - elseif (this % n_dimension == 2) then - bin = (ijk(2) - 1) * this % dimension(1) + ijk(1) - elseif (this % n_dimension == 3) then - bin = ((ijk(3) - 1) * this % dimension(2) + (ijk(2) - 1)) & - * this % dimension(1) + ijk(1) - end if - + bin = mesh_get_bin_from_indices(this % ptr, ijk) end function regular_get_bin_from_indices !=============================================================================== @@ -376,256 +300,7 @@ contains integer, intent(in) :: bin integer, intent(out) :: ijk(:) - if (this % n_dimension == 1) then - ijk(1) = bin - else if (this % n_dimension == 2) then - ijk(1) = mod(bin - 1, this % dimension(1)) + 1 - ijk(2) = (bin - 1)/this % dimension(1) + 1 - else if (this % n_dimension == 3) then - ijk(1) = mod(bin - 1, this % dimension(1)) + 1 - ijk(2) = mod(bin - 1, this % dimension(1) * this % dimension(2)) & - / this % dimension(1) + 1 - ijk(3) = (bin - 1)/(this % dimension(1) * this % dimension(2)) + 1 - end if - + call mesh_get_indices_from_bin(this % ptr, bin, ijk) end subroutine regular_get_indices_from_bin -!=============================================================================== -! MESH_INTERSECTS determines if a line between xyz0 and xyz1 intersects the -! outer boundary of the given mesh. This is important for determining whether a -! track will score to a mesh tally. -!=============================================================================== - - pure function regular_intersects(this, xyz0, xyz1) result(intersects) - class(RegularMesh), intent(in) :: this - real(8), intent(in) :: xyz0(:) - real(8), intent(in) :: xyz1(:) - logical :: intersects - - select case(this % n_dimension) - case (1) - intersects = mesh_intersects_1d(this, xyz0, xyz1) - case (2) - intersects = mesh_intersects_2d(this, xyz0, xyz1) - case (3) - intersects = mesh_intersects_3d(this, xyz0, xyz1) - end select - end function regular_intersects - - pure function mesh_intersects_1d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(:) - real(8), intent(in) :: xyz1(:) - logical :: intersects - - real(8) :: x0 ! track start point - real(8) :: x1 ! track end point - real(8) :: xm0 ! lower-left coordinates of mesh - real(8) :: xm1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - - ! Copy coordinates of ending point - x1 = xyz1(1) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - intersects = .true. - return - end if - - ! Check if line intersects right surface - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - intersects = .true. - return - end if - - end function mesh_intersects_1d - - pure function mesh_intersects_2d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(:) - real(8), intent(in) :: xyz1(:) - logical :: intersects - - real(8) :: x0, y0 ! track start point - real(8) :: x1, y1 ! track end point - real(8) :: xi, yi ! track intersection point with mesh - real(8) :: xm0, ym0 ! lower-left coordinates of mesh - real(8) :: xm1, ym1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - y0 = xyz0(2) - - ! Copy coordinates of ending point - x1 = xyz1(1) - y1 = xyz1(2) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - ym0 = m % lower_left(2) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - ym1 = m % upper_right(2) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface -- calculate the intersection point - ! y - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects back surface -- calculate the intersection point - ! x - if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then - xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects right surface -- calculate the intersection - ! point y - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects front surface -- calculate the intersection point - ! x - if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then - xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1) then - intersects = .true. - return - end if - end if - - end function mesh_intersects_2d - - pure function mesh_intersects_3d(m, xyz0, xyz1) result(intersects) - type(RegularMesh), intent(in) :: m - real(8), intent(in) :: xyz0(:) - real(8), intent(in) :: xyz1(:) - logical :: intersects - - real(8) :: x0, y0, z0 ! track start point - real(8) :: x1, y1, z1 ! track end point - real(8) :: xi, yi, zi ! track intersection point with mesh - real(8) :: xm0, ym0, zm0 ! lower-left coordinates of mesh - real(8) :: xm1, ym1, zm1 ! upper-right coordinates of mesh - - ! Copy coordinates of starting point - x0 = xyz0(1) - y0 = xyz0(2) - z0 = xyz0(3) - - ! Copy coordinates of ending point - x1 = xyz1(1) - y1 = xyz1(2) - z1 = xyz1(3) - - ! Copy coordinates of mesh lower_left - xm0 = m % lower_left(1) - ym0 = m % lower_left(2) - zm0 = m % lower_left(3) - - ! Copy coordinates of mesh upper_right - xm1 = m % upper_right(1) - ym1 = m % upper_right(2) - zm1 = m % upper_right(3) - - ! Set default value for intersects - intersects = .false. - - ! Check if line intersects left surface -- calculate the intersection point - ! (y,z) - if ((x0 < xm0 .and. x1 > xm0) .or. (x0 > xm0 .and. x1 < xm0)) then - yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0) - zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects back surface -- calculate the intersection point - ! (x,z) - if ((y0 < ym0 .and. y1 > ym0) .or. (y0 > ym0 .and. y1 < ym0)) then - xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0) - zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects bottom surface -- calculate the intersection - ! point (x,y) - if ((z0 < zm0 .and. z1 > zm0) .or. (z0 > zm0 .and. z1 < zm0)) then - xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0) - yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0) - if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects right surface -- calculate the intersection point - ! (y,z) - if ((x0 < xm1 .and. x1 > xm1) .or. (x0 > xm1 .and. x1 < xm1)) then - yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0) - zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0) - if (yi >= ym0 .and. yi < ym1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects front surface -- calculate the intersection point - ! (x,z) - if ((y0 < ym1 .and. y1 > ym1) .or. (y0 > ym1 .and. y1 < ym1)) then - xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0) - zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0) - if (xi >= xm0 .and. xi < xm1 .and. zi >= zm0 .and. zi < zm1) then - intersects = .true. - return - end if - end if - - ! Check if line intersects top surface -- calculate the intersection point - ! (x,y) - if ((z0 < zm1 .and. z1 > zm1) .or. (z0 > zm1 .and. z1 < zm1)) then - xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0) - yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0) - if (xi >= xm0 .and. xi < xm1 .and. yi >= ym0 .and. yi < ym1) then - intersects = .true. - return - end if - end if - - end function mesh_intersects_3d - end module mesh_header diff --git a/src/plot.F90 b/src/plot.F90 index 517c27fa1..b8f3db079 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -9,6 +9,7 @@ module plot use hdf5_interface use output, only: time_stamp use material_header, only: materials + use mesh_header, only: meshes use particle_header use plot_header use progress_header, only: ProgressBar @@ -184,7 +185,7 @@ contains !$omp end parallel do ! Draw tally mesh boundaries on the image if requested - if (associated(pl % meshlines_mesh)) call draw_mesh_lines(pl, data) + if (pl % index_meshlines_mesh >= 0) call draw_mesh_lines(pl, data) ! Write out the ppm to a file call output_ppm(pl, data) @@ -214,6 +215,7 @@ contains real(8) :: xyz_ur_plot(3) ! upper right xyz of plot image real(8) :: xyz_ll(3) ! lower left xyz real(8) :: xyz_ur(3) ! upper right xyz + type(RegularMesh) :: m rgb(:) = pl % meshlines_color % rgb @@ -239,57 +241,56 @@ contains width = xyz_ur_plot - xyz_ll_plot - associate (m => pl % meshlines_mesh) - call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh) - call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh) + m = meshes(pl % index_meshlines_mesh) + call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh) + call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh) - ! sweep through all meshbins on this plane and draw borders - do i = ijk_ll(outer), ijk_ur(outer) - do j = ijk_ll(inner), ijk_ur(inner) - ! check if we're in the mesh for this ijk - if (i > 0 .and. i <= m % dimension(outer) .and. & - j > 0 .and. j <= m % dimension(inner)) then + ! sweep through all meshbins on this plane and draw borders + do i = ijk_ll(outer), ijk_ur(outer) + do j = ijk_ll(inner), ijk_ur(inner) + ! check if we're in the mesh for this ijk + if (i > 0 .and. i <= m % dimension(outer) .and. & + j > 0 .and. j <= m % dimension(inner)) then - ! get xyz's of lower left and upper right of this mesh cell - xyz_ll(outer) = m % lower_left(outer) + m % width(outer) * (i - 1) - xyz_ll(inner) = m % lower_left(inner) + m % width(inner) * (j - 1) - xyz_ur(outer) = m % lower_left(outer) + m % width(outer) * i - xyz_ur(inner) = m % lower_left(inner) + m % width(inner) * j + ! get xyz's of lower left and upper right of this mesh cell + xyz_ll(outer) = m % lower_left(outer) + m % width(outer) * (i - 1) + xyz_ll(inner) = m % lower_left(inner) + m % width(inner) * (j - 1) + xyz_ur(outer) = m % lower_left(outer) + m % width(outer) * i + xyz_ur(inner) = m % lower_left(inner) + m % width(inner) * j - ! map the xyz ranges to pixel ranges + ! map the xyz ranges to pixel ranges - frac = (xyz_ll(outer) - xyz_ll_plot(outer)) / width(outer) - outrange(1) = int(frac * real(pl % pixels(1), 8)) - frac = (xyz_ur(outer) - xyz_ll_plot(outer)) / width(outer) - outrange(2) = int(frac * real(pl % pixels(1), 8)) + frac = (xyz_ll(outer) - xyz_ll_plot(outer)) / width(outer) + outrange(1) = int(frac * real(pl % pixels(1), 8)) + frac = (xyz_ur(outer) - xyz_ll_plot(outer)) / width(outer) + outrange(2) = int(frac * real(pl % pixels(1), 8)) - frac = (xyz_ur(inner) - xyz_ll_plot(inner)) / width(inner) - inrange(1) = int((ONE - frac) * real(pl % pixels(2), 8)) - frac = (xyz_ll(inner) - xyz_ll_plot(inner)) / width(inner) - inrange(2) = int((ONE - frac) * real(pl % pixels(2), 8)) + frac = (xyz_ur(inner) - xyz_ll_plot(inner)) / width(inner) + inrange(1) = int((ONE - frac) * real(pl % pixels(2), 8)) + frac = (xyz_ll(inner) - xyz_ll_plot(inner)) / width(inner) + inrange(2) = int((ONE - frac) * real(pl % pixels(2), 8)) - ! draw lines - do out_ = outrange(1), outrange(2) - do plus = 0, pl % meshlines_width - data(:, out_ + 1, inrange(1) + plus + 1) = rgb - data(:, out_ + 1, inrange(2) + plus + 1) = rgb - data(:, out_ + 1, inrange(1) - plus + 1) = rgb - data(:, out_ + 1, inrange(2) - plus + 1) = rgb - end do + ! draw lines + do out_ = outrange(1), outrange(2) + do plus = 0, pl % meshlines_width + data(:, out_ + 1, inrange(1) + plus + 1) = rgb + data(:, out_ + 1, inrange(2) + plus + 1) = rgb + data(:, out_ + 1, inrange(1) - plus + 1) = rgb + data(:, out_ + 1, inrange(2) - plus + 1) = rgb end do - do in_ = inrange(1), inrange(2) - do plus = 0, pl % meshlines_width - data(:, outrange(1) + plus + 1, in_ + 1) = rgb - data(:, outrange(2) + plus + 1, in_ + 1) = rgb - data(:, outrange(1) - plus + 1, in_ + 1) = rgb - data(:, outrange(2) - plus + 1, in_ + 1) = rgb - end do + end do + do in_ = inrange(1), inrange(2) + do plus = 0, pl % meshlines_width + data(:, outrange(1) + plus + 1, in_ + 1) = rgb + data(:, outrange(2) + plus + 1, in_ + 1) = rgb + data(:, outrange(1) - plus + 1, in_ + 1) = rgb + data(:, outrange(2) - plus + 1, in_ + 1) = rgb end do + end do - end if - end do + end if end do - end associate + end do end subroutine draw_mesh_lines diff --git a/src/plot_header.F90 b/src/plot_header.F90 index 1091bd73a..761481b33 100644 --- a/src/plot_header.F90 +++ b/src/plot_header.F90 @@ -4,7 +4,6 @@ module plot_header use constants use dict_header, only: DictIntInt - use mesh_header, only: RegularMesh implicit none @@ -31,7 +30,7 @@ module plot_header integer :: pixels(3) ! pixel width/height of plot slice integer :: meshlines_width ! pixel width of meshlines integer :: level ! universe depth to plot the cells of - type(RegularMesh), pointer :: meshlines_mesh => null() ! mesh to plot + integer :: index_meshlines_mesh = -1 ! index of mesh to plot type(ObjectColor) :: meshlines_color ! Color for meshlines type(ObjectColor) :: not_found ! color for positions where no cell found type(ObjectColor), allocatable :: colors(:) ! colors of cells/mats From 21a79eefd910ceb2ca3aecb0da4894261b909d9f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 30 Aug 2018 10:51:05 -0500 Subject: [PATCH 56/76] Remove some uses of mesh_dict --- src/input_xml.F90 | 15 ++++++--------- src/tallies/tally_filter_mesh.F90 | 22 +++++++++++----------- src/tallies/tally_filter_meshsurface.F90 | 22 ++++++++++------------ 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index bfd604f9e..be12870ad 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2064,6 +2064,7 @@ contains integer :: i, j integer :: n_cols, col_id, n_comp, n_masks, n_meshlines integer :: meshid + integer(C_INT) :: err, idx integer, allocatable :: iarray(:) logical :: file_exists ! does plots.xml file exist? character(MAX_LINE_LEN) :: filename ! absolute path to plots.xml @@ -2386,7 +2387,7 @@ contains // trim(to_str(pl % id))) end if - pl % meshlines_mesh => meshes(index_ufs_mesh) + pl % index_meshlines_mesh = index_ufs_mesh case ('cmfd') @@ -2404,7 +2405,7 @@ contains // trim(to_str(pl % id))) end if - pl % meshlines_mesh => meshes(index_entropy_mesh) + pl % index_meshlines_mesh = index_entropy_mesh case ('tally') @@ -2417,17 +2418,13 @@ contains end if ! Check if the specified tally mesh exists - if (mesh_dict % has(meshid)) then - pl % meshlines_mesh => meshes(mesh_dict % get(meshid)) - if (meshes(meshid) % type /= MESH_REGULAR) then - call fatal_error("Non-rectangular mesh specified in & - &meshlines for plot " // trim(to_str(pl % id))) - end if - else + err = openmc_get_mesh_index(meshid, idx) + if (err /= 0) then call fatal_error("Could not find mesh " & // trim(to_str(meshid)) // " specified in meshlines for & &plot " // trim(to_str(pl % id))) end if + pl % index_meshlines_mesh = idx case default call fatal_error("Invalid type for meshlines on plot " & diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index 486569da6..28eafcaaf 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -5,7 +5,7 @@ module tally_filter_mesh use constants use dict_header, only: EMPTY use error - use mesh_header, only: RegularMesh, meshes, n_meshes, mesh_dict + use mesh_header use hdf5_interface use particle_header, only: Particle use string, only: to_str @@ -38,10 +38,11 @@ contains class(MeshFilter), intent(inout) :: this type(XMLNode), intent(in) :: node - integer :: i_mesh + integer :: i integer :: id integer :: n - integer :: val + integer(C_INT) :: err + type(RegularMesh) :: m n = node_word_count(node, "bins") @@ -52,19 +53,18 @@ contains call get_node_value(node, "bins", id) ! Get pointer to mesh - val = mesh_dict % get(id) - if (val /= EMPTY) then - i_mesh = val - else + err = openmc_get_mesh_index(id, this % mesh) + if (err /= 0) then call fatal_error("Could not find mesh " // trim(to_str(id)) & // " specified on filter.") end if ! Determine number of bins - this % n_bins = product(meshes(i_mesh) % dimension) - - ! Store the index of the mesh - this % mesh = i_mesh + m = meshes(this % mesh) + this % n_bins = 1 + do i = 1, m % n_dimension() + this % n_bins = this % n_bins * m % dimension(i) + end do end subroutine from_xml subroutine get_all_bins_mesh(this, p, estimator, match) diff --git a/src/tallies/tally_filter_meshsurface.F90 b/src/tallies/tally_filter_meshsurface.F90 index 801d4252c..c7363a2db 100644 --- a/src/tallies/tally_filter_meshsurface.F90 +++ b/src/tallies/tally_filter_meshsurface.F90 @@ -5,7 +5,7 @@ module tally_filter_meshsurface use constants use dict_header, only: EMPTY use error - use mesh_header, only: RegularMesh, meshes, n_meshes, mesh_dict + use mesh_header use hdf5_interface use particle_header, only: Particle use string, only: to_str @@ -38,11 +38,11 @@ contains class(MeshSurfaceFilter), intent(inout) :: this type(XMLNode), intent(in) :: node - integer :: i_mesh + integer :: i integer :: id integer :: n integer :: n_dim - integer :: val + type(RegularMesh) :: m n = node_word_count(node, "bins") @@ -53,20 +53,18 @@ contains call get_node_value(node, "bins", id) ! Get pointer to mesh - val = mesh_dict % get(id) - if (val /= EMPTY) then - i_mesh = val - else + err = openmc_get_mesh_index(id, this % mesh) + if (err /= 0) then call fatal_error("Could not find mesh " // trim(to_str(id)) & // " specified on filter.") end if ! Determine number of bins - n_dim = meshes(i_mesh) % n_dimension - this % n_bins = 4*n_dim*product(meshes(i_mesh) % dimension) - - ! Store the index of the mesh - this % mesh = i_mesh + m = meshes(this % mesh) + this % n_bins = 4 * m % n_dimension() + do i = 1, m % n_dimension() + this % n_bins = this % n_bins * m % dimension(i) + end do end subroutine from_xml subroutine get_all_bins(this, p, estimator, match) From 04e48224e6ce8272acd05080fded3326ad774159 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 30 Aug 2018 14:22:55 -0500 Subject: [PATCH 57/76] Almost complete mesh conversion --- CMakeLists.txt | 1 + include/openmc/eigenvalue.h | 4 + include/openmc/hdf5_interface.h | 8 + include/openmc/particle.h | 2 +- src/cmfd_data.F90 | 7 +- src/cmfd_header.F90 | 3 +- src/cmfd_input.F90 | 110 +------- src/eigenvalue.F90 | 1 - src/eigenvalue.cpp | 5 + src/input_xml.F90 | 12 +- src/mesh.cpp | 6 +- src/mesh_header.F90 | 42 ++- src/particle.cpp | 2 +- src/physics.F90 | 1 - src/physics_mg.F90 | 1 - src/plot.F90 | 6 +- src/settings.cpp | 1 + src/simulation.F90 | 5 +- src/simulation_header.F90 | 10 +- src/state_point.F90 | 2 +- src/tallies/tally_filter_mesh.F90 | 277 ++++++++++---------- src/tallies/tally_filter_meshsurface.F90 | 309 ++++++++++++----------- src/tallies/trigger.F90 | 11 +- 23 files changed, 380 insertions(+), 446 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78d1caf4d..713bf7c07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,7 @@ add_library(libopenmc SHARED src/distribution_energy.cpp src/distribution_multi.cpp src/distribution_spatial.cpp + src/eigenvalue.cpp src/endf.cpp src/initialize.cpp src/finalize.cpp diff --git a/include/openmc/eigenvalue.h b/include/openmc/eigenvalue.h index c2e76e26f..cc879461e 100644 --- a/include/openmc/eigenvalue.h +++ b/include/openmc/eigenvalue.h @@ -2,6 +2,9 @@ #define OPENMC_EIGENVALUE_H #include // for int64_t +#include + +#include "xtensor/xtensor.hpp" #include "openmc/particle.h" @@ -15,6 +18,7 @@ extern std::vector entropy; //!< Shannon entropy at each generation extern xt::xtensor source_frac; //!< Source fraction for UFS extern "C" int64_t n_bank; +#pragma omp threadprivate(n_bank) //============================================================================== // Non-member functions diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 944fe75cb..b53703fc9 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -317,6 +317,14 @@ write_attribute(hid_t obj_id, const char* name, const std::array& buffer) write_attr(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data()); } +template inline void +write_attribute(hid_t obj_id, const char* name, const std::vector& buffer) +{ + hsize_t dims[] {buffer.size()}; + write_attr(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data()); +} + + //============================================================================== // Templates/overloads for write_dataset //============================================================================== diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 846d2e5a6..298b2878a 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -161,7 +161,7 @@ extern "C" { {mark_as_lost(message.str());} //! create a particle restart HDF5 file - void write_restart(); + void write_restart() const; }; diff --git a/src/cmfd_data.F90 b/src/cmfd_data.F90 index ce4825426..ec07a4d04 100644 --- a/src/cmfd_data.F90 +++ b/src/cmfd_data.F90 @@ -80,7 +80,7 @@ contains integer :: i_mesh ! flattend index for mesh logical :: energy_filters! energy filters present real(8) :: flux ! temp variable for flux - type(RegularMesh), pointer :: m ! pointer for mesh object + type(RegularMesh) :: m ! pointer for mesh object ! Extract spatial and energy indices from object nx = cmfd % indices(1) @@ -99,7 +99,7 @@ contains select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => meshes(filt % mesh) + m = meshes(filt % mesh) end select ! Set mesh widths @@ -354,9 +354,6 @@ contains ! Normalize openmc source distribution cmfd % openmc_src = cmfd % openmc_src/sum(cmfd % openmc_src)*cmfd%norm - ! Nullify all pointers - if (associated(m)) nullify(m) - end subroutine compute_xs !=============================================================================== diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index 2e6162b49..eafba7b8a 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -95,7 +95,8 @@ module cmfd_header ! Main object type(cmfd_type), public :: cmfd - type(RegularMesh), public, pointer :: cmfd_mesh => null() + integer, public :: index_cmfd_mesh + type(RegularMesh), public :: cmfd_mesh ! Pointers for different tallies type(TallyContainer), public, pointer :: cmfd_tallies(:) => null() diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index de73bc03f..3208ad9d0 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -3,7 +3,7 @@ module cmfd_input use, intrinsic :: ISO_C_BINDING use cmfd_header - use mesh_header, only: mesh_dict + use mesh_header use mgxs_interface, only: energy_bins, num_energy_groups use tally use tally_header @@ -241,7 +241,7 @@ contains use constants, only: MAX_LINE_LEN use error, only: fatal_error, warning - use mesh_header, only: RegularMesh, openmc_extend_meshes + use mesh_header use string use tally, only: openmc_tally_allocate use tally_header, only: openmc_extend_tallies @@ -266,112 +266,22 @@ contains integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array real(C_DOUBLE), allocatable :: energies(:) - type(RegularMesh), pointer :: m type(XMLNode) :: node_mesh - err = openmc_extend_meshes(1, i_start) + ! Read CMFD mesh + call read_meshes(root % ptr) - ! Allocate mesh - cmfd_mesh => meshes(i_start) - m => meshes(i_start) + ! Get index of cmfd mesh and set ID + i_start = n_meshes() - 1 + err = openmc_mesh_set_id(i_start, i_start) - ! Set mesh id - m % id = i_start - - ! Set mesh type to rectangular - m % type = MESH_REGULAR + ! Save reference to CMFD mesh + index_cmfd_mesh = i_start + cmfd_mesh = meshes(i_start) ! Get pointer to mesh XML node node_mesh = root % child("mesh") - ! Determine number of dimensions for mesh - n = node_word_count(node_mesh, "dimension") - if (n /= 2 .and. n /= 3) then - call fatal_error("Mesh must be two or three dimensions.") - end if - m % n_dimension = n - - ! Allocate attribute arrays - allocate(m % dimension(n)) - allocate(m % lower_left(n)) - allocate(m % width(n)) - allocate(m % upper_right(n)) - - ! Check that dimensions are all greater than zero - call get_node_array(node_mesh, "dimension", iarray3(1:n)) - if (any(iarray3(1:n) <= 0)) then - call fatal_error("All entries on the element for a tally mesh& - & must be positive.") - end if - - ! Read dimensions in each direction - m % dimension = iarray3(1:n) - - ! Read mesh lower-left corner location - if (m % n_dimension /= node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the same as & - &the number of entries on .") - end if - call get_node_array(node_mesh, "lower_left", m % lower_left) - - ! Make sure both upper-right or width were specified - if (check_for_node(node_mesh, "upper_right") .and. & - check_for_node(node_mesh, "width")) then - call fatal_error("Cannot specify both and on a & - &tally mesh.") - end if - - ! Make sure either upper-right or width was specified - if (.not.check_for_node(node_mesh, "upper_right") .and. & - .not.check_for_node(node_mesh, "width")) then - call fatal_error("Must specify either and on a & - &tally mesh.") - end if - - if (check_for_node(node_mesh, "width")) then - ! Check to ensure width has same dimensions - if (node_word_count(node_mesh, "width") /= & - node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the same as the & - &number of entries on .") - end if - - ! Check for negative widths - call get_node_array(node_mesh, "width", rarray3(1:n)) - if (any(rarray3(1:n) < ZERO)) then - call fatal_error("Cannot have a negative on a tally mesh.") - end if - - ! Set width and upper right coordinate - m % width = rarray3(1:n) - m % upper_right = m % lower_left + m % dimension * m % width - - elseif (check_for_node(node_mesh, "upper_right")) then - ! Check to ensure width has same dimensions - if (node_word_count(node_mesh, "upper_right") /= & - node_word_count(node_mesh, "lower_left")) then - call fatal_error("Number of entries on must be the same & - &as the number of entries on .") - end if - - ! Check that upper-right is above lower-left - call get_node_array(node_mesh, "upper_right", rarray3(1:n)) - if (any(rarray3(1:n) < m % lower_left)) then - call fatal_error("The coordinates must be greater than & - &the coordinates on a tally mesh.") - end if - - ! Set upper right coordinate and width - m % upper_right = rarray3(1:n) - m % width = (m % upper_right - m % lower_left) / real(m % dimension, 8) - end if - - ! Set volume fraction - m % volume_frac = ONE/real(product(m % dimension),8) - - ! Add mesh to dictionary - call mesh_dict % set(m % id, i_start) - ! Determine number of filters energy_filters = check_for_node(node_mesh, "energy") n = merge(5, 3, energy_filters) diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 38284c279..14fe59110 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -7,7 +7,6 @@ module eigenvalue use error, only: fatal_error, warning use math, only: t_percentile use mesh, only: count_bank_sites - use mesh_header, only: RegularMesh, meshes use message_passing use random_lcg, only: prn, set_particle_seed, advance_prn_seed use settings diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 9ce5b9ef8..ef4159e78 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -147,5 +147,10 @@ extern "C" double entropy_c(int i) return entropy.at(i - 1); } +extern "C" double entropy_clear() +{ + entropy.clear(); +} + } // namespace openmc diff --git a/src/input_xml.F90 b/src/input_xml.F90 index be12870ad..c3fedd881 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -4,7 +4,7 @@ module input_xml use algorithm, only: find use cmfd_input, only: configure_cmfd - use cmfd_header, only: cmfd_mesh + use cmfd_header, only: index_cmfd_mesh use constants use dict_header, only: DictIntInt, DictCharInt, DictEntryCI use endf, only: reaction_name @@ -86,11 +86,6 @@ module input_xml type(C_PTR), value :: node_ptr end subroutine read_materials - subroutine read_meshes(node_ptr) bind(C) - import C_PTR - type(C_PTR), value :: node_ptr - end subroutine - function find_root_universe() bind(C) result(root) import C_INT32_T integer(C_INT32_T) :: root @@ -232,7 +227,6 @@ contains if (run_mode == MODE_EIGENVALUE) then ! Preallocate space for keff and entropy by generation call k_generation % reserve(n_max_batches*gen_per_batch) - call entropy % reserve(n_max_batches*gen_per_batch) end if ! Particle tracks @@ -1222,7 +1216,7 @@ contains ! READ MESH DATA ! Check for user meshes and allocate - call read_meshes() + call read_meshes(root % ptr) ! We only need the mesh info for plotting if (run_mode == MODE_PLOTTING) then @@ -2396,7 +2390,7 @@ contains &meshlines on plot " // trim(to_str(pl % id))) end if - pl % meshlines_mesh => cmfd_mesh + pl % index_meshlines_mesh = index_cmfd_mesh case ('entropy') diff --git a/src/mesh.cpp b/src/mesh.cpp index 9c955fae7..a4526e5b6 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -532,10 +532,10 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, int n_energy, const double* energies, bool* outside) { // Determine shape of array for counts - int m = xt::prod(shape_)(); + std::size_t m = xt::prod(shape_)(); std::vector shape; if (n_energy > 0) { - shape = {m, n_energy}; + shape = {m, static_cast(n_energy)}; } else { shape = {m}; } @@ -757,6 +757,8 @@ void read_meshes(pugi::xml_node* root) //============================================================================== extern "C" { + int n_meshes() { return meshes.size(); } + RegularMesh* mesh_ptr(int i) { return meshes[i-1].get(); } int32_t mesh_id(RegularMesh* m) { return m->id_; } diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 591263000..2a6abee7d 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -2,35 +2,20 @@ module mesh_header use, intrinsic :: ISO_C_BINDING - use constants - use dict_header, only: DictIntInt - use error - use hdf5_interface - use string, only: to_str, to_lower - use xml_interface - implicit none - private - public :: openmc_extend_meshes - public :: openmc_get_mesh_index - public :: openmc_mesh_get_id - public :: openmc_mesh_get_dimension - public :: openmc_mesh_get_params - public :: openmc_mesh_set_id - public :: openmc_mesh_set_dimension - public :: openmc_mesh_set_params !=============================================================================== ! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by ! congruent squares or cubes !=============================================================================== - type, public :: RegularMesh + type :: RegularMesh type(C_PTR) :: ptr contains procedure :: id => regular_id procedure :: volume_frac => regular_volume_frac procedure :: n_dimension => regular_n_dimension + procedure :: dimension => regular_dimension procedure :: lower_left => regular_lower_left procedure :: upper_right => regular_upper_right procedure :: width => regular_width @@ -41,11 +26,6 @@ module mesh_header procedure :: get_indices_from_bin => regular_get_indices_from_bin end type RegularMesh - integer(C_INT32_T), public, bind(C) :: n_meshes = 0 ! # of structured meshes - - ! Dictionary that maps user IDs to indices in 'meshes' - type(DictIntInt), public :: mesh_dict - interface function openmc_extend_meshes(n, index_start, index_end) result(err) bind(C) import C_INT32_T, C_INT @@ -158,21 +138,21 @@ module mesh_header real(C_DOUBLE) :: w end function - function mesh_get_bin(ptr, xyz) result(bin) bind(C) + pure function mesh_get_bin(ptr, xyz) result(bin) bind(C) import C_PTR, C_DOUBLE, C_INT type(C_PTR), value :: ptr real(C_DOUBLE), intent(in) :: xyz(*) integer(C_INT) :: bin end function - function mesh_get_bin_from_indices(ptr, ijk) result(bin) bind(C) + pure function mesh_get_bin_from_indices(ptr, ijk) result(bin) bind(C) import C_PTR, C_INT type(C_PTR), value :: ptr integer(C_INT), intent(in) :: ijk(*) integer(C_INT) :: bin end function - subroutine mesh_get_indices(ptr, xyz, ijk, in_mesh) bind(C) + pure subroutine mesh_get_indices(ptr, xyz, ijk, in_mesh) bind(C) import C_PTR, C_DOUBLE, C_INT, C_BOOL type(C_PTR), value :: ptr real(C_DOUBLE), intent(in) :: xyz(*) @@ -180,7 +160,7 @@ module mesh_header logical(C_BOOL), intent(out) :: in_mesh end subroutine - subroutine mesh_get_indices_from_bin(ptr, bin, ijk) bind(C) + pure subroutine mesh_get_indices_from_bin(ptr, bin, ijk) bind(C) import C_PTR, C_INT type(C_PTR), value :: ptr integer(C_INT), value :: bin @@ -192,6 +172,16 @@ module mesh_header integer(C_INT), value :: i type(C_PTR) :: ptr end function + + subroutine read_meshes(node_ptr) bind(C) + import C_PTR + type(C_PTR), value :: node_ptr + end subroutine + + function n_meshes() result(n) bind(C) + import C_INT + integer(C_INT) :: n + end function end interface contains diff --git a/src/particle.cpp b/src/particle.cpp index 729a860eb..ca57c2faa 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -141,7 +141,7 @@ Particle::mark_as_lost(const char* message) } void -Particle::write_restart() +Particle::write_restart() const { // Dont write another restart file if in particle restart mode if (settings::run_mode == RUN_MODE_PARTICLE) return; diff --git a/src/physics.F90 b/src/physics.F90 index f7d80261a..f1a0d7c57 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -6,7 +6,6 @@ module physics use error, only: fatal_error, warning, write_message use material_header, only: Material, materials use math - use mesh_header, only: meshes use message_passing use nuclide_header use particle_header diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index 84695153c..bcafc4314 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -7,7 +7,6 @@ module physics_mg use error, only: fatal_error, warning, write_message use material_header, only: Material, materials use math, only: rotate_angle - use mesh_header, only: meshes use mgxs_interface use message_passing use nuclide_header, only: material_xs diff --git a/src/plot.F90 b/src/plot.F90 index b8f3db079..bfc8bc225 100644 --- a/src/plot.F90 +++ b/src/plot.F90 @@ -9,7 +9,7 @@ module plot use hdf5_interface use output, only: time_stamp use material_header, only: materials - use mesh_header, only: meshes + use mesh_header, only: meshes, RegularMesh use particle_header use plot_header use progress_header, only: ProgressBar @@ -242,8 +242,8 @@ contains width = xyz_ur_plot - xyz_ll_plot m = meshes(pl % index_meshlines_mesh) - call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension), in_mesh) - call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension), in_mesh) + call m % get_indices(xyz_ll_plot, ijk_ll(:m % n_dimension()), in_mesh) + call m % get_indices(xyz_ur_plot, ijk_ur(:m % n_dimension()), in_mesh) ! sweep through all meshbins on this plane and draw borders do i = ijk_ll(outer), ijk_ur(outer) diff --git a/src/settings.cpp b/src/settings.cpp index 4883d07a3..db6aee7f5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -16,6 +16,7 @@ #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/mesh.h" +#include "openmc/output.h" #include "openmc/random_lcg.h" #include "openmc/source.h" #include "openmc/string_utils.h" diff --git a/src/simulation.F90 b/src/simulation.F90 index 8b7cfdb27..3ca5d9623 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -10,8 +10,7 @@ module simulation use cmfd_execute, only: cmfd_init_batch, cmfd_tally_init, execute_cmfd use cmfd_header, only: cmfd_on use constants, only: ZERO - use eigenvalue, only: calculate_average_keff, & - calculate_generation_keff, shannon_entropy, & + use eigenvalue, only: calculate_average_keff, calculate_generation_keff, & synchronize_bank, keff_generation, k_sum #ifdef _OPENMP use eigenvalue, only: join_bank_from_threads @@ -479,7 +478,7 @@ contains ! will potentially populate k_generation and entropy) current_batch = 0 call k_generation % clear() - call entropy % clear() + call entropy_clear() need_depletion_rx = .false. ! If this is a restart run, load the state point data and binary source diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 9b7c68cd4..ad5513c61 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -64,6 +64,12 @@ module simulation_header !$omp threadprivate(trace, thread_id, current_work) + interface + subroutine entropy_clear() bind(C) + end subroutine + end interface + + contains !=============================================================================== @@ -80,12 +86,12 @@ contains !=============================================================================== subroutine free_memory_simulation() + if (allocated(work_index)) deallocate(work_index) call k_generation % clear() call k_generation % shrink_to_fit() - call entropy % clear() - call entropy % shrink_to_fit() + call entropy_clear() end subroutine free_memory_simulation end module simulation_header diff --git a/src/state_point.F90 b/src/state_point.F90 index b7f4e1377..d20456d7b 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -173,7 +173,7 @@ contains call write_dataset(file_id, "generations_per_batch", gen_per_batch) k = k_generation % size() call write_dataset(file_id, "k_generation", k_generation % data(1:k)) - call entropy_to_hdf5() + call entropy_to_hdf5(file_id) call write_dataset(file_id, "k_col_abs", k_col_abs) call write_dataset(file_id, "k_col_tra", k_col_tra) call write_dataset(file_id, "k_abs_tra", k_abs_tra) diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index 28eafcaaf..3e8eaa1c6 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -92,155 +92,154 @@ contains real(8) :: distance ! distance traveled in mesh cell logical :: start_in_mesh ! starting coordinates inside mesh? logical :: end_in_mesh ! ending coordinates inside mesh? - type(RegularMesh), pointer :: m + type(RegularMesh) :: m ! Get a pointer to the mesh. - m => meshes(this % mesh) - n = m % n_dimension + m = meshes(this % mesh) if (estimator /= ESTIMATOR_TRACKLENGTH) then ! If this is an analog or collision tally, then there can only be one ! valid mesh bin. call m % get_bin(p % coord(1) % xyz, bin) - if (bin /= NO_BIN_FOUND) then + if (bin >= 0) then call match % bins % push_back(bin) call match % weights % push_back(ONE) end if return end if - ! A track can span multiple mesh bins so we need to handle a lot of - ! intersection logic for tracklength tallies. + ! ! A track can span multiple mesh bins so we need to handle a lot of + ! ! intersection logic for tracklength tallies. - ! ======================================================================== - ! Determine if the track intersects the tally mesh. + ! ! ======================================================================== + ! ! Determine if the track intersects the tally mesh. - ! Copy the starting and ending coordinates of the particle. Offset these - ! just a bit for the purposes of determining if there was an intersection - ! in case the mesh surfaces coincide with lattice/geometric surfaces which - ! might produce finite-precision errors. - xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw - xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw + ! ! Copy the starting and ending coordinates of the particle. Offset these + ! ! just a bit for the purposes of determining if there was an intersection + ! ! in case the mesh surfaces coincide with lattice/geometric surfaces which + ! ! might produce finite-precision errors. + ! xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw + ! xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw - ! Determine indices for starting and ending location. - call m % get_indices(xyz0, ijk0(:n), start_in_mesh) - call m % get_indices(xyz1, ijk1(:n), end_in_mesh) + ! ! Determine indices for starting and ending location. + ! call m % get_indices(xyz0, ijk0(:n), start_in_mesh) + ! call m % get_indices(xyz1, ijk1(:n), end_in_mesh) - ! If this is the first iteration of the filter loop, check if the track - ! intersects any part of the mesh. - if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (.not. m % intersects(xyz0, xyz1)) return - end if + ! ! If this is the first iteration of the filter loop, check if the track + ! ! intersects any part of the mesh. + ! if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then + ! if (.not. m % intersects(xyz0, xyz1)) return + ! end if - ! ======================================================================== - ! Figure out which mesh cell to tally. + ! ! ======================================================================== + ! ! Figure out which mesh cell to tally. - ! Copy the un-modified coordinates the particle direction. - xyz0 = p % last_xyz - xyz1 = p % coord(1) % xyz - uvw = p % coord(1) % uvw + ! ! Copy the un-modified coordinates the particle direction. + ! xyz0 = p % last_xyz + ! xyz1 = p % coord(1) % xyz + ! uvw = p % coord(1) % uvw - ! Compute the length of the entire track. - total_distance = sqrt(sum((xyz1 - xyz0)**2)) + ! ! Compute the length of the entire track. + ! total_distance = sqrt(sum((xyz1 - xyz0)**2)) - ! We are looking for the first valid mesh bin. Check to see if the - ! particle starts inside the mesh. - if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then - ! The particle does not start in the mesh. Note that we nudged the - ! start and end coordinates by a TINY_BIT each so we will have - ! difficulty resolving tracks that are less than 2*TINY_BIT in length. - ! If the track is that short, it is also insignificant so we can - ! safely ignore it in the tallies. - if (total_distance < 2*TINY_BIT) return + ! ! We are looking for the first valid mesh bin. Check to see if the + ! ! particle starts inside the mesh. + ! if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then + ! ! The particle does not start in the mesh. Note that we nudged the + ! ! start and end coordinates by a TINY_BIT each so we will have + ! ! difficulty resolving tracks that are less than 2*TINY_BIT in length. + ! ! If the track is that short, it is also insignificant so we can + ! ! safely ignore it in the tallies. + ! if (total_distance < 2*TINY_BIT) return - ! The particle does not start in the mesh so keep iterating the ijk0 - ! indices to cross the nearest mesh surface until we've found a valid - ! bin. MAX_SEARCH_ITER prevents an infinite loop. - search_iter = 0 - do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) - if (search_iter == MAX_SEARCH_ITER) then - call warning("Failed to find a mesh intersection on a tally mesh & - &filter.") - return - end if + ! ! The particle does not start in the mesh so keep iterating the ijk0 + ! ! indices to cross the nearest mesh surface until we've found a valid + ! ! bin. MAX_SEARCH_ITER prevents an infinite loop. + ! search_iter = 0 + ! do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) + ! if (search_iter == MAX_SEARCH_ITER) then + ! call warning("Failed to find a mesh intersection on a tally mesh & + ! &filter.") + ! return + ! end if - do j = 1, n - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:n), 1) - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if + ! do j = 1, n + ! if (abs(uvw(j)) < FP_PRECISION) then + ! d(j) = INFINITY + ! else if (uvw(j) > 0) then + ! xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) + ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) + ! else + ! xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) + ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) + ! end if + ! end do + ! j = minloc(d(:n), 1) + ! if (uvw(j) > ZERO) then + ! ijk0(j) = ijk0(j) + 1 + ! else + ! ijk0(j) = ijk0(j) - 1 + ! end if - search_iter = search_iter + 1 - end do - distance = d(j) - xyz0 = xyz0 + distance * uvw - end if + ! search_iter = search_iter + 1 + ! end do + ! distance = d(j) + ! xyz0 = xyz0 + distance * uvw + ! end if - do - ! ======================================================================== - ! Compute the length of the track segment in the appropiate mesh cell and - ! return. + ! do + ! ! ======================================================================== + ! ! Compute the length of the track segment in the appropiate mesh cell and + ! ! return. - if (all(ijk0(:n) == ijk1(:n))) then - ! The track ends in this cell. Use the particle end location rather - ! than the mesh surface. - distance = sqrt(sum((xyz1 - xyz0)**2)) - else - ! The track exits this cell. Determine the distance to the closest mesh - ! surface. - do j = 1, n - if (abs(uvw(j)) < FP_PRECISION) then - d(j) = INFINITY - else if (uvw(j) > 0) then - xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - else - xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - d(j) = (xyz_cross - xyz0(j)) / uvw(j) - end if - end do - j = minloc(d(:n), 1) - distance = d(j) - end if + ! if (all(ijk0(:n) == ijk1(:n))) then + ! ! The track ends in this cell. Use the particle end location rather + ! ! than the mesh surface. + ! distance = sqrt(sum((xyz1 - xyz0)**2)) + ! else + ! ! The track exits this cell. Determine the distance to the closest mesh + ! ! surface. + ! do j = 1, n + ! if (abs(uvw(j)) < FP_PRECISION) then + ! d(j) = INFINITY + ! else if (uvw(j) > 0) then + ! xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) + ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) + ! else + ! xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) + ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) + ! end if + ! end do + ! j = minloc(d(:n), 1) + ! distance = d(j) + ! end if - ! Assign the next tally bin and the score. - bin = m % get_bin_from_indices(ijk0(:n)) - call match % bins % push_back(bin) - call match % weights % push_back(distance / total_distance) + ! ! Assign the next tally bin and the score. + ! bin = m % get_bin_from_indices(ijk0(:n)) + ! call match % bins % push_back(bin) + ! call match % weights % push_back(distance / total_distance) - ! Find the next mesh cell that the particle enters. + ! ! Find the next mesh cell that the particle enters. - ! If the particle track ends in that bin, then we are done. - if (all(ijk0(:n) == ijk1(:n))) exit + ! ! If the particle track ends in that bin, then we are done. + ! if (all(ijk0(:n) == ijk1(:n))) exit - ! Translate the starting coordintes by the distance to that face. This - ! should be the xyz that we computed the distance to in the last - ! iteration of the filter loop. - xyz0 = xyz0 + distance * uvw + ! ! Translate the starting coordintes by the distance to that face. This + ! ! should be the xyz that we computed the distance to in the last + ! ! iteration of the filter loop. + ! xyz0 = xyz0 + distance * uvw - ! Increment the indices into the next mesh cell. - if (uvw(j) > ZERO) then - ijk0(j) = ijk0(j) + 1 - else - ijk0(j) = ijk0(j) - 1 - end if + ! ! Increment the indices into the next mesh cell. + ! if (uvw(j) > ZERO) then + ! ijk0(j) = ijk0(j) + 1 + ! else + ! ijk0(j) = ijk0(j) - 1 + ! end if - ! If the next indices are invalid, then the track has left the mesh and - ! we are done. - if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit - end do + ! ! If the next indices are invalid, then the track has left the mesh and + ! ! we are done. + ! if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit + ! end do end subroutine get_all_bins_mesh @@ -248,9 +247,12 @@ contains class(MeshFilter), intent(in) :: this integer(HID_T), intent(in) :: filter_group + type(RegularMesh) :: m + + m = meshes(this % mesh) call write_dataset(filter_group, "type", "mesh") call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", meshes(this % mesh) % id) + call write_dataset(filter_group, "bins", m % id()) end subroutine to_statepoint_mesh function text_label_mesh(this, bin) result(label) @@ -259,20 +261,20 @@ contains character(MAX_LINE_LEN) :: label integer, allocatable :: ijk(:) + type(RegularMesh) :: m - associate (m => meshes(this % mesh)) - allocate(ijk(m % n_dimension)) - call m % get_indices_from_bin(bin, ijk) - if (m % n_dimension == 1) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" - elseif (m % n_dimension == 2) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ")" - elseif (m % n_dimension == 3) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" - end if - end associate + m = meshes(this % mesh) + allocate(ijk(m % n_dimension())) + call m % get_indices_from_bin(bin, ijk) + if (m % n_dimension() == 1) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" + elseif (m % n_dimension() == 2) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ")" + elseif (m % n_dimension() == 3) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" + end if end function text_label_mesh !=============================================================================== @@ -304,18 +306,25 @@ contains integer(C_INT32_T), value, intent(in) :: index_mesh integer(C_INT) :: err + type(RegularMesh) :: m + integer :: i + err = verify_filter(index) if (err == 0) then select type (f => filters(index) % obj) type is (MeshFilter) - if (index_mesh >= 1 .and. index_mesh <= n_meshes) then + if (index_mesh >= 0 .and. index_mesh < n_meshes()) then f % mesh = index_mesh - f % n_bins = product(meshes(index_mesh) % dimension) + f % n_bins = 1 + m = meshes(index_mesh) + do i = 1, m % n_dimension() + f % n_bins = f % n_bins * m % dimension(i) + end do else err = E_OUT_OF_BOUNDS call set_errmsg("Index in 'meshes' array is out of bounds.") end if - class default + class default err = E_INVALID_TYPE call set_errmsg("Tried to set mesh on a non-mesh filter.") end select diff --git a/src/tallies/tally_filter_meshsurface.F90 b/src/tallies/tally_filter_meshsurface.F90 index c7363a2db..d1500b8b3 100644 --- a/src/tallies/tally_filter_meshsurface.F90 +++ b/src/tallies/tally_filter_meshsurface.F90 @@ -42,6 +42,7 @@ contains integer :: id integer :: n integer :: n_dim + integer(C_INT) :: err type(RegularMesh) :: m n = node_word_count(node, "bins") @@ -90,133 +91,130 @@ contains real(8) :: distance ! actual distance traveled logical :: start_in_mesh ! particle's starting xyz in mesh? logical :: end_in_mesh ! particle's ending xyz in mesh? + type(RegularMesh) :: m - ! Copy starting and ending location of particle - xyz0 = p % last_xyz_current - xyz1 = p % coord(1) % xyz + ! ! Copy starting and ending location of particle + ! xyz0 = p % last_xyz_current + ! xyz1 = p % coord(1) % xyz - associate (m => meshes(this % mesh)) - n_dim = m % n_dimension + ! m = meshes(this % mesh) + ! n_dim = m % n_dimension() - ! Determine indices for starting and ending location - call m % get_indices(xyz0, ijk0, start_in_mesh) - call m % get_indices(xyz1, ijk1, end_in_mesh) + ! ! Determine indices for starting and ending location + ! call m % get_indices(xyz0, ijk0, start_in_mesh) + ! call m % get_indices(xyz1, ijk1, end_in_mesh) - ! Check to see if start or end is in mesh -- if not, check if track still - ! intersects with mesh - if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - if (.not. m % intersects(xyz0, xyz1)) return - end if + ! ! Check to see if start or end is in mesh -- if not, check if track still + ! ! intersects with mesh + ! if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then + ! !if (.not. m % intersects(xyz0, xyz1)) return + ! end if - ! Calculate number of surface crossings - n_cross = sum(abs(ijk1(:n_dim) - ijk0(:n_dim))) - if (n_cross == 0) return + ! ! Calculate number of surface crossings + ! n_cross = sum(abs(ijk1(:n_dim) - ijk0(:n_dim))) + ! if (n_cross == 0) return - ! Copy particle's direction - uvw = p % coord(1) % uvw + ! ! Copy particle's direction + ! uvw = p % coord(1) % uvw - ! Bounding coordinates - do d1 = 1, n_dim - if (uvw(d1) > 0) then - xyz_cross(d1) = m % lower_left(d1) + ijk0(d1) * m % width(d1) - else - xyz_cross(d1) = m % lower_left(d1) + (ijk0(d1) - 1) * m % width(d1) - end if - end do + ! ! Bounding coordinates + ! do d1 = 1, n_dim + ! if (uvw(d1) > 0) then + ! xyz_cross(d1) = m % lower_left(d1) + ijk0(d1) * m % width(d1) + ! else + ! xyz_cross(d1) = m % lower_left(d1) + (ijk0(d1) - 1) * m % width(d1) + ! end if + ! end do - do j = 1, n_cross - ! Set the distances to infinity - d = INFINITY + ! do j = 1, n_cross + ! ! Set the distances to infinity + ! d = INFINITY - ! Calculate distance to each bounding surface. We need to treat - ! special case where the cosine of the angle is zero since this would - ! result in a divide-by-zero. - do d1 = 1, n_dim - if (uvw(d1) == 0) then - d(d1) = INFINITY - else - d(d1) = (xyz_cross(d1) - xyz0(d1))/uvw(d1) - end if - end do + ! ! Calculate distance to each bounding surface. We need to treat + ! ! special case where the cosine of the angle is zero since this would + ! ! result in a divide-by-zero. + ! do d1 = 1, n_dim + ! if (uvw(d1) == 0) then + ! d(d1) = INFINITY + ! else + ! d(d1) = (xyz_cross(d1) - xyz0(d1))/uvw(d1) + ! end if + ! end do - ! Determine the closest bounding surface of the mesh cell by - ! calculating the minimum distance. Then use the minimum distance and - ! direction of the particle to determine which surface was crossed. - distance = minval(d) + ! ! Determine the closest bounding surface of the mesh cell by + ! ! calculating the minimum distance. Then use the minimum distance and + ! ! direction of the particle to determine which surface was crossed. + ! distance = minval(d) - ! Loop over the dimensions - do d1 = 1, n_dim + ! ! Loop over the dimensions + ! do d1 = 1, n_dim - ! Check whether distance is the shortest distance - if (distance == d(d1)) then + ! ! Check whether distance is the shortest distance + ! if (distance == d(d1)) then - ! Check whether particle is moving in positive d1 direction - if (uvw(d1) > 0) then + ! ! Check whether particle is moving in positive d1 direction + ! if (uvw(d1) > 0) then - ! Outward current on d1 max surface - if (all(ijk0(:n_dim) >= 1) .and. & - all(ijk0(:n_dim) <= m % dimension)) then - i_surf = d1 * 4 - 1 - i_mesh = m % get_bin_from_indices(ijk0) - i_bin = 4*n_dim*(i_mesh - 1) + i_surf + ! ! Outward current on d1 max surface + ! if (all(ijk0(:n_dim) >= 1) .and. & + ! all(ijk0(:n_dim) <= m % dimension)) then + ! i_surf = d1 * 4 - 1 + ! i_mesh = m % get_bin_from_indices(ijk0) + ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - call match % bins % push_back(i_bin) - call match % weights % push_back(ONE) - end if + ! call match % bins % push_back(i_bin) + ! call match % weights % push_back(ONE) + ! end if - ! Advance position - ijk0(d1) = ijk0(d1) + 1 - xyz_cross(d1) = xyz_cross(d1) + m % width(d1) + ! ! Advance position + ! ijk0(d1) = ijk0(d1) + 1 + ! xyz_cross(d1) = xyz_cross(d1) + m % width(d1) - ! If the particle crossed the surface, tally the inward current on - ! d1 min surface - if (all(ijk0(:n_dim) >= 1) .and. & - all(ijk0(:n_dim) <= m % dimension)) then - i_surf = d1 * 4 - 2 - i_mesh = m % get_bin_from_indices(ijk0) - i_bin = 4*n_dim*(i_mesh - 1) + i_surf + ! ! If the particle crossed the surface, tally the inward current on + ! ! d1 min surface + ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then + ! i_surf = d1 * 4 - 2 + ! i_mesh = m % get_bin_from_indices(ijk0) + ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - call match % bins % push_back(i_bin) - call match % weights % push_back(ONE) - end if + ! call match % bins % push_back(i_bin) + ! call match % weights % push_back(ONE) + ! end if - else - ! The particle is moving in the negative d1 direction + ! else + ! ! The particle is moving in the negative d1 direction - ! Outward current on d1 min surface - if (all(ijk0(:n_dim) >= 1) .and. & - all(ijk0(:n_dim) <= m % dimension)) then - i_surf = d1 * 4 - 3 - i_mesh = m % get_bin_from_indices(ijk0) - i_bin = 4*n_dim*(i_mesh - 1) + i_surf + ! ! Outward current on d1 min surface + ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then + ! i_surf = d1 * 4 - 3 + ! i_mesh = m % get_bin_from_indices(ijk0) + ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - call match % bins % push_back(i_bin) - call match % weights % push_back(ONE) - end if + ! call match % bins % push_back(i_bin) + ! call match % weights % push_back(ONE) + ! end if - ! Advance position - ijk0(d1) = ijk0(d1) - 1 - xyz_cross(d1) = xyz_cross(d1) - m % width(d1) + ! ! Advance position + ! ijk0(d1) = ijk0(d1) - 1 + ! xyz_cross(d1) = xyz_cross(d1) - m % width(d1) - ! If the particle crossed the surface, tally the inward current on - ! d1 max surface - if (all(ijk0(:n_dim) >= 1) .and. & - all(ijk0(:n_dim) <= m % dimension)) then - i_surf = d1 * 4 - i_mesh = m % get_bin_from_indices(ijk0) - i_bin = 4*n_dim*(i_mesh - 1) + i_surf + ! ! If the particle crossed the surface, tally the inward current on + ! ! d1 max surface + ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then + ! i_surf = d1 * 4 + ! i_mesh = m % get_bin_from_indices(ijk0) + ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - call match % bins % push_back(i_bin) - call match % weights % push_back(ONE) - end if - end if - end if - end do + ! call match % bins % push_back(i_bin) + ! call match % weights % push_back(ONE) + ! end if + ! end if + ! end if + ! end do - ! Calculate new coordinates - xyz0 = xyz0 + distance * uvw - end do - end associate + ! ! Calculate new coordinates + ! xyz0 = xyz0 + distance * uvw + ! end do end subroutine get_all_bins @@ -224,9 +222,12 @@ contains class(MeshSurfaceFilter), intent(in) :: this integer(HID_T), intent(in) :: filter_group + type(RegularMesh) :: m + + m = meshes(this % mesh) call write_dataset(filter_group, "type", "meshsurface") call write_dataset(filter_group, "n_bins", this % n_bins) - call write_dataset(filter_group, "bins", meshes(this % mesh) % id) + call write_dataset(filter_group, "bins", m % id()) end subroutine to_statepoint function text_label(this, bin) result(label) @@ -238,55 +239,55 @@ contains integer :: i_surf integer :: n_dim integer, allocatable :: ijk(:) + type(RegularMesh) :: m - associate (m => meshes(this % mesh)) - n_dim = m % n_dimension - allocate(ijk(n_dim)) + m = meshes(this % mesh) + n_dim = m % n_dimension() + allocate(ijk(n_dim)) - ! Get flattend mesh index and surface index - i_mesh = (bin - 1) / (4*n_dim) + 1 - i_surf = mod(bin - 1, 4*n_dim) + 1 + ! Get flattend mesh index and surface index + i_mesh = (bin - 1) / (4*n_dim) + 1 + i_surf = mod(bin - 1, 4*n_dim) + 1 - ! Get mesh index part of label - call m % get_indices_from_bin(i_mesh, ijk) - if (m % n_dimension == 1) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" - elseif (m % n_dimension == 2) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ")" - elseif (m % n_dimension == 3) then - label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & - trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" - end if + ! Get mesh index part of label + call m % get_indices_from_bin(i_mesh, ijk) + if (m % n_dimension() == 1) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ")" + elseif (m % n_dimension() == 2) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ")" + elseif (m % n_dimension() == 3) then + label = "Mesh Index (" // trim(to_str(ijk(1))) // ", " // & + trim(to_str(ijk(2))) // ", " // trim(to_str(ijk(3))) // ")" + end if - ! Get surface part of label - select case (i_surf) - case (OUT_LEFT) - label = trim(label) // " Outgoing, x-min" - case (IN_LEFT) - label = trim(label) // " Incoming, x-min" - case (OUT_RIGHT) - label = trim(label) // " Outgoing, x-max" - case (IN_RIGHT) - label = trim(label) // " Incoming, x-max" - case (OUT_BACK) - label = trim(label) // " Outgoing, y-min" - case (IN_BACK) - label = trim(label) // " Incoming, y-min" - case (OUT_FRONT) - label = trim(label) // " Outgoing, y-max" - case (IN_FRONT) - label = trim(label) // " Incoming, y-max" - case (OUT_BOTTOM) - label = trim(label) // " Outgoing, z-min" - case (IN_BOTTOM) - label = trim(label) // " Incoming, z-min" - case (OUT_TOP) - label = trim(label) // " Outgoing, z-max" - case (IN_TOP) - label = trim(label) // " Incoming, z-max" - end select - end associate + ! Get surface part of label + select case (i_surf) + case (OUT_LEFT) + label = trim(label) // " Outgoing, x-min" + case (IN_LEFT) + label = trim(label) // " Incoming, x-min" + case (OUT_RIGHT) + label = trim(label) // " Outgoing, x-max" + case (IN_RIGHT) + label = trim(label) // " Incoming, x-max" + case (OUT_BACK) + label = trim(label) // " Outgoing, y-min" + case (IN_BACK) + label = trim(label) // " Incoming, y-min" + case (OUT_FRONT) + label = trim(label) // " Outgoing, y-max" + case (IN_FRONT) + label = trim(label) // " Incoming, y-max" + case (OUT_BOTTOM) + label = trim(label) // " Outgoing, z-min" + case (IN_BOTTOM) + label = trim(label) // " Incoming, z-min" + case (OUT_TOP) + label = trim(label) // " Outgoing, z-max" + case (IN_TOP) + label = trim(label) // " Incoming, z-max" + end select end function text_label !=============================================================================== @@ -318,16 +319,22 @@ contains integer(C_INT32_T), value, intent(in) :: index_mesh integer(C_INT) :: err + integer :: i integer :: n_dim + type(RegularMesh) :: m err = verify_filter(index) if (err == 0) then select type (f => filters(index) % obj) type is (MeshSurfaceFilter) - if (index_mesh >= 1 .and. index_mesh <= n_meshes) then + if (index_mesh >= 0 .and. index_mesh < n_meshes()) then f % mesh = index_mesh - n_dim = meshes(index_mesh) % n_dimension - f % n_bins = 4*n_dim*product(meshes(index_mesh) % dimension) + m = meshes(index_mesh) + n_dim = m % n_dimension() + f % n_bins = 4*n_dim + do i = 1, n_dim + f % n_bins = f % n_bins * m % dimension(i) + end do else err = E_OUT_OF_BOUNDS call set_errmsg("Index in 'meshes' array is out of bounds.") diff --git a/src/tallies/trigger.F90 b/src/tallies/trigger.F90 index 2cb3bf819..27aa5ec50 100644 --- a/src/tallies/trigger.F90 +++ b/src/tallies/trigger.F90 @@ -257,14 +257,14 @@ contains logical :: print_ebin ! should incoming energy bin be displayed? real(8) :: rel_err = ZERO ! temporary relative error of result real(8) :: std_dev = ZERO ! temporary standard deviration of result - type(RegularMesh), pointer :: m ! surface current mesh + type(RegularMesh) :: m ! surface current mesh ! Get pointer to mesh i_filter_mesh = t % filter(t % find_filter(FILTER_MESH)) i_filter_surf = t % filter(t % find_filter(FILTER_SURFACE)) select type(filt => filters(i_filter_mesh) % obj) type is (MeshFilter) - m => meshes(filt % mesh) + m = meshes(filt % mesh) end select ! initialize bins array @@ -285,8 +285,11 @@ contains end if ! Get the dimensions and number of cells in the mesh - n_dim = m % n_dimension - n_cells = product(m % dimension) + n_dim = m % n_dimension() + n_cells = 1 + do j = 1, n_dim + n_cells = n_cells * m % dimension(j) + end do ! Loop over all the mesh cells do i = 1, n_cells From 5566fc36b631f883844d2cc0ed077cca6d7dd2bd Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 09:25:21 -0400 Subject: [PATCH 58/76] renaming mg_benchmark* to mg_basic* --- tests/regression_tests/{mg_benchmark => mg_basic}/__init__.py | 0 tests/regression_tests/{mg_benchmark => mg_basic}/inputs_true.dat | 0 .../regression_tests/{mg_benchmark => mg_basic}/results_true.dat | 0 tests/regression_tests/{mg_benchmark => mg_basic}/test.py | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/__init__.py | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/inputs_true.dat | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/results_true.dat | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/test.py | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression_tests/{mg_benchmark => mg_basic}/__init__.py (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/inputs_true.dat (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/results_true.dat (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/test.py (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/__init__.py (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/inputs_true.dat (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/results_true.dat (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/test.py (100%) diff --git a/tests/regression_tests/mg_benchmark/__init__.py b/tests/regression_tests/mg_basic/__init__.py similarity index 100% rename from tests/regression_tests/mg_benchmark/__init__.py rename to tests/regression_tests/mg_basic/__init__.py diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark/inputs_true.dat rename to tests/regression_tests/mg_basic/inputs_true.dat diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_basic/results_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark/results_true.dat rename to tests/regression_tests/mg_basic/results_true.dat diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_basic/test.py similarity index 100% rename from tests/regression_tests/mg_benchmark/test.py rename to tests/regression_tests/mg_basic/test.py diff --git a/tests/regression_tests/mg_benchmark_delayed/__init__.py b/tests/regression_tests/mg_basic_delayed/__init__.py similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/__init__.py rename to tests/regression_tests/mg_basic_delayed/__init__.py diff --git a/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/inputs_true.dat rename to tests/regression_tests/mg_basic_delayed/inputs_true.dat diff --git a/tests/regression_tests/mg_benchmark_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/results_true.dat rename to tests/regression_tests/mg_basic_delayed/results_true.dat diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/test.py rename to tests/regression_tests/mg_basic_delayed/test.py From 3385c8b0a20e0aa27ca2f138ba98813c08babc69 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 14:15:25 -0400 Subject: [PATCH 59/76] some small potential bug fixes and code cleanup --- src/scattdata.cpp | 10 ++-------- src/xsdata.cpp | 19 +++++-------------- tests/regression_tests/mg_basic/test.py | 2 +- .../regression_tests/mg_basic_delayed/test.py | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 0ff7969d1..1069ef6e9 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -109,13 +109,7 @@ ScattData::base_combine(size_t max_order, // Combine mult_numer and mult_denom into the combined multiplicity matrix xt::xtensor this_mult({groups, groups}, 1.); - for (int gin = 0; gin < groups; gin++) { - for (int gout = 0; gout < groups; gout++) { - if (mult_denom(gin, gout) > 0.) { - this_mult(gin, gout) = mult_numer(gin, gout) / mult_denom(gin, gout); - } - } - } + this_mult = xt::nan_to_num(mult_numer / mult_denom); // We have the data, now we need to convert to a jagged array and then use // the initialize function to store it on the object. @@ -531,7 +525,7 @@ ScattDataHistogram::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.size() - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index fd849b1c7..cd53b826e 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "xtensor/xview.hpp" #include "xtensor/xindex_view.hpp" @@ -204,13 +205,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in self.chi is the normalized chi we just made - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi(a, gout); - } - } - } + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly if (object_exists(xsdata_grp, "prompt-nu-fission")) { @@ -317,7 +312,8 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_prompt = temp_matrix / prompt_nu_fission; + chi_prompt = temp_matrix / xt::view(prompt_nu_fission, xt::all(), xt::all(), + xt::newaxis()); } //============================================================================== @@ -391,12 +387,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, // Now use this info to find the length of a vector to hold the flattened // data. - size_t length = 0; - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); - } - } + size_t length = order_data * xt::sum(gmax - gmin + 1)(); double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); xt::xtensor temp_arr({length}, 0.); diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py index c29c7ca1f..7b456bb9d 100644 --- a/tests/regression_tests/mg_basic/test.py +++ b/tests/regression_tests/mg_basic/test.py @@ -82,7 +82,7 @@ class MGXSTestHarness(PyAPITestHarness): os.remove(f) -def test_mg_benchmark(): +def test_mg_basic(): create_library() mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang', 'micro'] diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index 6c527bbe3..8fbcaca49 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -97,7 +97,7 @@ class MGXSTestHarness(PyAPITestHarness): os.remove(f) -def test_mg_benchmark(): +def test_mg_basic_delayed(): create_library() model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta']) From 2c20dc0f8333687f9c1e23a2f641a90e8213fad2 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 14:27:04 -0400 Subject: [PATCH 60/76] super minor edit --- src/scattdata.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 1069ef6e9..8d7138624 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -551,7 +551,6 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) if (xi < dist[gin][i_gout][0]) { imu = 0; } else { - // TODO lower_bound? + 1? imu = std::upper_bound(dist[gin][i_gout].begin(), dist[gin][i_gout].end(), xi) - dist[gin][i_gout].begin(); From be16cb750d05d405ade845fdf8a9954836d3aa9e Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 15:15:05 -0400 Subject: [PATCH 61/76] Added supportfor group-wise betas --- include/openmc/xsdata.h | 4 +- src/xsdata.cpp | 118 +++++++++++++----- .../mg_basic_delayed/inputs_true.dat | 22 +++- .../mg_basic_delayed/results_true.dat | 2 +- .../regression_tests/mg_basic_delayed/test.py | 29 ++++- 5 files changed, 131 insertions(+), 44 deletions(-) diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 780855ecf..0bdeaf818 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -37,7 +37,7 @@ class XsData { // the HDF5 file when beta is provided. void fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups); + size_t energy_groups, size_t delayed_groups, bool is_isotropic); //! \brief Reads fission data formatted as chi and nu-fission vectors from // the HDF5 file when beta is not provided. @@ -55,7 +55,7 @@ class XsData { // the HDF5 file when beta is provided. void fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups); + size_t energy_groups, size_t delayed_groups, bool is_isotropic); //! \brief Reads fission data formatted as a nu-fission matrix from // the HDF5 file when beta is not provided. diff --git a/src/xsdata.cpp b/src/xsdata.cpp index cd53b826e..d89fb1172 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "xtensor/xview.hpp" #include "xtensor/xindex_view.hpp" @@ -124,7 +123,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, void XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups) + size_t energy_groups, size_t delayed_groups, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -145,17 +144,35 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); - // Get beta - xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_beta, true); + // Get beta (strategy will depend upon the number of dimensions in beta) + hid_t beta_dset = open_dataset(xsdata_grp, "beta"); + int beta_ndims = dataset_ndims(beta_dset); + close_dataset(beta_dset); + int ndim_target = 1; + if (!is_isotropic) ndim_target += 2; + if (beta_ndims == ndim_target) { + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - // Set prompt_nu_fission = (1. - beta_total)*nu_fission - prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); - // Set delayed_nu_fission as beta * nu_fission - delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + } else if (beta_ndims == ndim_target + 1) { + xt::xtensor temp_beta({n_ang, delayed_groups, energy_groups}, + 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = temp_beta * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + } } void @@ -219,7 +236,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, void XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups) + size_t energy_groups, size_t delayed_groups, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -227,32 +244,65 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); - // Get beta - xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_beta, true); + // Get beta (strategy will depend upon the number of dimensions in beta) + hid_t beta_dset = open_dataset(xsdata_grp, "beta"); + int beta_ndims = dataset_ndims(beta_dset); + close_dataset(beta_dset); + int ndim_target = 1; + if (!is_isotropic) ndim_target += 2; + if (beta_ndims == ndim_target) { + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - xt::xtensor temp_beta_sum({n_ang}, 0.); - temp_beta_sum = xt::sum(temp_beta, {1}); + xt::xtensor temp_beta_sum({n_ang}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); - // prompt_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by (1 - beta_sum) - prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); - // delayed_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by beta - delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + // Store chi-prompt + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), + xt::newaxis()) * temp_matrix; - // Store chi-prompt - chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * temp_matrix; + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); - // Store chi-delayed - chi_delayed = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * - xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); - //Normalize both + } else if (beta_ndims == ndim_target + 1) { + xt::xtensor temp_beta({n_ang, delayed_groups, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + xt::xtensor temp_beta_sum({n_ang, energy_groups}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); + + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); + + // Store chi-prompt + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::all(), + xt::newaxis()) * temp_matrix; + + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = temp_beta * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + } + + //Normalize both chis chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); @@ -335,7 +385,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } else { if (object_exists(xsdata_grp, "beta")) { fission_vector_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, - delayed_groups); + delayed_groups, is_isotropic); } else { fission_vector_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups); @@ -347,7 +397,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } else { if (object_exists(xsdata_grp, "beta")) { fission_matrix_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, - delayed_groups); + delayed_groups, is_isotropic); } else { fission_matrix_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups); diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index e62e65ab1..9fb7afe7e 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -4,11 +4,15 @@ + + - - - - + + + + + + @@ -29,6 +33,14 @@ + + + + + + + + @@ -38,7 +50,7 @@ 5 - 0.0 -1000.0 -1000.0 232.3625 1000.0 1000.0 + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_basic_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat index 4b425173d..85312b8e1 100644 --- a/tests/regression_tests/mg_basic_delayed/results_true.dat +++ b/tests/regression_tests/mg_basic_delayed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.928704E-01 2.679667E-02 +1.003463E+00 2.173155E-02 diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index 8fbcaca49..f0474a567 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -85,6 +85,29 @@ def create_library(): mat_4.set_total(total) mg_cross_sections_file.add_xsdata(mat_4) + # Make the base data that uses chi & nu-fiss vectors with a group-wise beta + mat_5 = openmc.XSdata('mat_5', groups) + mat_5.order = 1 + mat_5.num_delayed_groups = 2 + mat_5.set_beta(np.stack([beta] * groups.num_groups)) + mat_5.set_nu_fission(np.multiply(nu, fiss)) + mat_5.set_absorption(absorption) + mat_5.set_scatter_matrix(scatter) + mat_5.set_total(total) + mat_5.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a version that uses a nu-fission matrix with a group-wise beta + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.num_delayed_groups = 2 + mat_6.set_beta(np.stack([beta] * groups.num_groups)) + mat_6.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mg_cross_sections_file.add_xsdata(mat_6) + # Write the file mg_cross_sections_file.export_to_hdf5('2g.h5') @@ -99,8 +122,10 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_basic_delayed(): create_library() - model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', - 'matrix beta', 'matrix no beta']) + model = slab_mg(num_regions=6, mat_names=['vec beta', 'vec no beta', + 'matrix beta', 'matrix no beta', + 'vec group beta', + 'matrix group beta']) harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() From cd1dfc0d199a122ea479405f9f2825211d99733c Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 15:34:41 -0400 Subject: [PATCH 62/76] Final cleanup --- src/xsdata.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d89fb1172..56783a672 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -225,11 +225,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); - } else { - read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); - } + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); } //============================================================================== @@ -351,11 +347,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); - } else { - read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); - } + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // prompt_nu_fission is the sum over outgoing groups prompt_nu_fission = xt::sum(temp_matrix, {2}); From a10ef739baf5e9a5d8ad390e9250d3b85f01b962 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 3 Sep 2018 14:01:59 -0500 Subject: [PATCH 63/76] Bindings for bins_crossed --- include/openmc/mesh.h | 7 ++ src/input_xml.F90 | 8 +- src/mesh.cpp | 51 +++++++--- src/mesh_header.F90 | 2 +- src/output.F90 | 9 ++ src/simulation.F90 | 8 ++ src/stl_vector.F90 | 26 +++++ src/tallies/tally_filter_header.F90 | 4 +- src/tallies/tally_filter_mesh.F90 | 148 +++------------------------- 9 files changed, 107 insertions(+), 156 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 28f9c3eac..47258edd8 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -1,3 +1,6 @@ +//! \file mesh.h +//! \brief Mesh types used for tallies, Shannon entropy, CMFD, etc. + #ifndef OPENMC_MESH_H #define OPENMC_MESH_H @@ -59,6 +62,10 @@ private: //! \param[in] root XML node extern "C" void read_meshes(pugi::xml_node* root); +//! Write mesh data to an HDF5 group +//! \param[in] group HDF5 group +extern "C" void meshes_to_hdf5(hid_t group); + //============================================================================== // Global variables //============================================================================== diff --git a/src/input_xml.F90 b/src/input_xml.F90 index c3fedd881..4766650bf 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -65,17 +65,17 @@ module input_xml subroutine read_surfaces(node_ptr) bind(C) import C_PTR - type(C_PTR), value :: node_ptr + type(C_PTR) :: node_ptr end subroutine read_surfaces subroutine read_cells(node_ptr) bind(C) import C_PTR - type(C_PTR), value :: node_ptr + type(C_PTR) :: node_ptr end subroutine read_cells subroutine read_lattices(node_ptr) bind(C) import C_PTR - type(C_PTR), value :: node_ptr + type(C_PTR) :: node_ptr end subroutine read_lattices subroutine read_settings_xml() bind(C) @@ -83,7 +83,7 @@ module input_xml subroutine read_materials(node_ptr) bind(C) import C_PTR - type(C_PTR), value :: node_ptr + type(C_PTR) :: node_ptr end subroutine read_materials function find_root_universe() bind(C) result(root) diff --git a/src/mesh.cpp b/src/mesh.cpp index a4526e5b6..3749c5585 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -752,14 +752,38 @@ void read_meshes(pugi::xml_node* root) } } +void meshes_to_hdf5(hid_t group) +{ + // Write number of meshes + hid_t meshes_group = create_group(group, "meshes"); + int32_t n_meshes = meshes.size(); + write_attribute(meshes_group, "n_meshes", n_meshes); + + if (n_meshes > 0) { + // Write IDs of meshes + std::vector ids; + for (const auto& m : meshes) { + m->to_hdf5(meshes_group); + ids.push_back(m->id_); + } + write_attribute(meshes_group, "ids", ids); + } + + close_group(meshes_group); +} + //============================================================================== // Fortran compatibility //============================================================================== extern "C" { + // Declaration of Fortran procedures + void vector_int_push_back(void* ptr, int value); + void vector_real_push_back(void* ptr, double value); + int n_meshes() { return meshes.size(); } - RegularMesh* mesh_ptr(int i) { return meshes[i-1].get(); } + RegularMesh* mesh_ptr(int i) { return meshes.at(i).get(); } int32_t mesh_id(RegularMesh* m) { return m->id_; } @@ -795,24 +819,19 @@ extern "C" { m->get_indices_from_bin(bin, ijk); } - void meshes_to_hdf5(hid_t group) + void mesh_bins_crossed(RegularMesh* m, const Particle* p, void* match_bins, + void* match_weights) { - // Write number of meshes - hid_t meshes_group = create_group(group, "meshes"); - int32_t n_meshes = meshes.size(); - write_attribute(meshes_group, "n_meshes", n_meshes); + // Get bins crossed + std::vector bins; + std::vector lengths; + m->bins_crossed(p, bins, lengths); - if (n_meshes > 0) { - // Write IDs of meshes - std::vector ids; - for (const auto& m : meshes) { - m->to_hdf5(meshes_group); - ids.push_back(m->id_); - } - write_attribute(meshes_group, "ids", ids); + // Call bindings for VectorInt and VectorReal on Fortran side + for (int i = 0; i < bins.size(); ++i) { + vector_int_push_back(match_bins, bins[i]); + vector_real_push_back(match_weights, lengths[i]); } - - close_group(meshes_group); } void free_memory_mesh() diff --git a/src/mesh_header.F90 b/src/mesh_header.F90 index 2a6abee7d..d7e26fc6b 100644 --- a/src/mesh_header.F90 +++ b/src/mesh_header.F90 @@ -175,7 +175,7 @@ module mesh_header subroutine read_meshes(node_ptr) bind(C) import C_PTR - type(C_PTR), value :: node_ptr + type(C_PTR) :: node_ptr end subroutine function n_meshes() result(n) bind(C) diff --git a/src/output.F90 b/src/output.F90 index e28695667..4363731f0 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -660,6 +660,10 @@ contains if (n_tallies == 0) return allocate(matches(n_filters)) + do i = 1, n_filters + allocate(matches(i) % bins) + allocate(matches(i) % weights) + end do ! Initialize names for scores score_names(abs(SCORE_FLUX)) = "Flux" @@ -855,6 +859,11 @@ contains close(UNIT=unit_tally) + do i = 1, n_filters + deallocate(matches(i) % bins) + deallocate(matches(i) % weights) + end do + end subroutine write_tallies !=============================================================================== diff --git a/src/simulation.F90 b/src/simulation.F90 index 3ca5d9623..176dfb921 100644 --- a/src/simulation.F90 +++ b/src/simulation.F90 @@ -472,6 +472,10 @@ contains ! Allocate array for matching filter bins allocate(filter_matches(n_filters)) + do i = 1, n_filters + allocate(filter_matches(i) % bins) + allocate(filter_matches(i) % weights) + end do !$omp end parallel ! Reset global variables -- this is done before loading state point (as that @@ -557,6 +561,10 @@ contains deallocate(materials(i) % mat_nuclide_index) end do !$omp parallel + do i = 1, size(filter_matches) + deallocate(filter_matches(i) % bins) + deallocate(filter_matches(i) % weights) + end do deallocate(micro_xs, micro_photon_xs, filter_matches) !$omp end parallel diff --git a/src/stl_vector.F90 b/src/stl_vector.F90 index 06f487dc1..156290781 100644 --- a/src/stl_vector.F90 +++ b/src/stl_vector.F90 @@ -35,6 +35,8 @@ module stl_vector ! ! size -- Returns the number of elements in the vector. + use, intrinsic :: ISO_C_BINDING + implicit none private @@ -521,4 +523,28 @@ contains size = this%size_ end function size_char +!=============================================================================== +! Procedures to be called from C++ +!=============================================================================== + + subroutine vector_int_push_back(ptr, val) bind(C) + type(C_PTR), value :: ptr + integer(C_INT), value :: val + + type(VectorInt), pointer :: vec + + call C_F_POINTER(ptr, vec) + call vec % push_back(val) + end subroutine + + subroutine vector_real_push_back(ptr, val) bind(C) + type(C_PTR), value :: ptr + real(C_DOUBLE), value :: val + + type(VectorReal), pointer :: vec + + call C_F_POINTER(ptr, vec) + call vec % push_back(val) + end subroutine + end module stl_vector diff --git a/src/tallies/tally_filter_header.F90 b/src/tallies/tally_filter_header.F90 index e57423ddf..d6aef4abd 100644 --- a/src/tallies/tally_filter_header.F90 +++ b/src/tallies/tally_filter_header.F90 @@ -28,8 +28,8 @@ module tally_filter_header type, public :: TallyFilterMatch ! Index of the bin and weight being used in the current filter combination integer :: i_bin - type(VectorInt) :: bins - type(VectorReal) :: weights + type(VectorInt), pointer :: bins + type(VectorReal), pointer :: weights ! Indicates whether all valid bins for this filter have been found logical :: bins_present = .false. diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index 3e8eaa1c6..bc770b199 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -93,6 +93,17 @@ contains logical :: start_in_mesh ! starting coordinates inside mesh? logical :: end_in_mesh ! ending coordinates inside mesh? type(RegularMesh) :: m + type(C_PTR) :: ptr_bins, ptr_weights + + interface + subroutine mesh_bins_crossed(m, p, bins, weights) bind(C) + import C_PTR, Particle + type(C_PTR), value :: m + type(Particle), intent(in) :: p + type(C_PTR), value :: bins + type(C_PTR), value :: weights + end subroutine + end interface ! Get a pointer to the mesh. m = meshes(this % mesh) @@ -106,141 +117,12 @@ contains call match % weights % push_back(ONE) end if return + else + ptr_bins = C_LOC(match % bins) + ptr_weights = C_LOC(match % weights) + call mesh_bins_crossed(m % ptr, p, ptr_bins, ptr_weights) end if - ! ! A track can span multiple mesh bins so we need to handle a lot of - ! ! intersection logic for tracklength tallies. - - ! ! ======================================================================== - ! ! Determine if the track intersects the tally mesh. - - ! ! Copy the starting and ending coordinates of the particle. Offset these - ! ! just a bit for the purposes of determining if there was an intersection - ! ! in case the mesh surfaces coincide with lattice/geometric surfaces which - ! ! might produce finite-precision errors. - ! xyz0 = p % last_xyz + TINY_BIT * p % coord(1) % uvw - ! xyz1 = p % coord(1) % xyz - TINY_BIT * p % coord(1) % uvw - - ! ! Determine indices for starting and ending location. - ! call m % get_indices(xyz0, ijk0(:n), start_in_mesh) - ! call m % get_indices(xyz1, ijk1(:n), end_in_mesh) - - ! ! If this is the first iteration of the filter loop, check if the track - ! ! intersects any part of the mesh. - ! if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - ! if (.not. m % intersects(xyz0, xyz1)) return - ! end if - - ! ! ======================================================================== - ! ! Figure out which mesh cell to tally. - - ! ! Copy the un-modified coordinates the particle direction. - ! xyz0 = p % last_xyz - ! xyz1 = p % coord(1) % xyz - ! uvw = p % coord(1) % uvw - - ! ! Compute the length of the entire track. - ! total_distance = sqrt(sum((xyz1 - xyz0)**2)) - - ! ! We are looking for the first valid mesh bin. Check to see if the - ! ! particle starts inside the mesh. - ! if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) then - ! ! The particle does not start in the mesh. Note that we nudged the - ! ! start and end coordinates by a TINY_BIT each so we will have - ! ! difficulty resolving tracks that are less than 2*TINY_BIT in length. - ! ! If the track is that short, it is also insignificant so we can - ! ! safely ignore it in the tallies. - ! if (total_distance < 2*TINY_BIT) return - - ! ! The particle does not start in the mesh so keep iterating the ijk0 - ! ! indices to cross the nearest mesh surface until we've found a valid - ! ! bin. MAX_SEARCH_ITER prevents an infinite loop. - ! search_iter = 0 - ! do while (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) - ! if (search_iter == MAX_SEARCH_ITER) then - ! call warning("Failed to find a mesh intersection on a tally mesh & - ! &filter.") - ! return - ! end if - - ! do j = 1, n - ! if (abs(uvw(j)) < FP_PRECISION) then - ! d(j) = INFINITY - ! else if (uvw(j) > 0) then - ! xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) - ! else - ! xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) - ! end if - ! end do - ! j = minloc(d(:n), 1) - ! if (uvw(j) > ZERO) then - ! ijk0(j) = ijk0(j) + 1 - ! else - ! ijk0(j) = ijk0(j) - 1 - ! end if - - ! search_iter = search_iter + 1 - ! end do - ! distance = d(j) - ! xyz0 = xyz0 + distance * uvw - ! end if - - ! do - ! ! ======================================================================== - ! ! Compute the length of the track segment in the appropiate mesh cell and - ! ! return. - - ! if (all(ijk0(:n) == ijk1(:n))) then - ! ! The track ends in this cell. Use the particle end location rather - ! ! than the mesh surface. - ! distance = sqrt(sum((xyz1 - xyz0)**2)) - ! else - ! ! The track exits this cell. Determine the distance to the closest mesh - ! ! surface. - ! do j = 1, n - ! if (abs(uvw(j)) < FP_PRECISION) then - ! d(j) = INFINITY - ! else if (uvw(j) > 0) then - ! xyz_cross = m % lower_left(j) + ijk0(j) * m % width(j) - ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) - ! else - ! xyz_cross = m % lower_left(j) + (ijk0(j) - 1) * m % width(j) - ! d(j) = (xyz_cross - xyz0(j)) / uvw(j) - ! end if - ! end do - ! j = minloc(d(:n), 1) - ! distance = d(j) - ! end if - - ! ! Assign the next tally bin and the score. - ! bin = m % get_bin_from_indices(ijk0(:n)) - ! call match % bins % push_back(bin) - ! call match % weights % push_back(distance / total_distance) - - ! ! Find the next mesh cell that the particle enters. - - ! ! If the particle track ends in that bin, then we are done. - ! if (all(ijk0(:n) == ijk1(:n))) exit - - ! ! Translate the starting coordintes by the distance to that face. This - ! ! should be the xyz that we computed the distance to in the last - ! ! iteration of the filter loop. - ! xyz0 = xyz0 + distance * uvw - - ! ! Increment the indices into the next mesh cell. - ! if (uvw(j) > ZERO) then - ! ijk0(j) = ijk0(j) + 1 - ! else - ! ijk0(j) = ijk0(j) - 1 - ! end if - - ! ! If the next indices are invalid, then the track has left the mesh and - ! ! we are done. - ! if (any(ijk0(:n) < 1) .or. any(ijk0(:n) > m % dimension)) exit - ! end do - end subroutine get_all_bins_mesh subroutine to_statepoint_mesh(this, filter_group) From 8af84064ca2f14a783b122153dde1b105ed687b9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 4 Sep 2018 07:01:27 -0500 Subject: [PATCH 64/76] Implement surface_bins_crossed for mesh --- include/openmc/mesh.h | 1 + src/mesh.cpp | 141 ++++++++++++++++++++- src/tallies/tally_filter_meshsurface.F90 | 154 +++-------------------- 3 files changed, 155 insertions(+), 141 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 47258edd8..c81756491 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -30,6 +30,7 @@ public: // Methods void bins_crossed(const Particle* p, std::vector& bins, std::vector& lengths); + void surface_bins_crossed(const Particle* p, std::vector& bins); int get_bin(Position r); int get_bin_from_indices(const int* ijk); void get_indices(Position r, int* ijk, bool* in_mesh); diff --git a/src/mesh.cpp b/src/mesh.cpp index 3749c5585..88aa6af12 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,6 +1,6 @@ #include "openmc/mesh.h" -#include // for copy +#include // for copy, min #include // for size_t #include // for ceil #include @@ -515,6 +515,130 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } } +void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins) +{ + // ======================================================================== + // Determine if the track intersects the tally mesh. + + // Copy the starting and ending coordinates of the particle. + Position r0 {p->last_xyz_current}; + Position r1 {p->coord[0].xyz}; + Direction u {p->coord[0].uvw}; + + // Determine indices for starting and ending location. + int n = n_dimension_; + xt::xtensor ijk0 = xt::empty({n}); + bool start_in_mesh; + get_indices(r0, ijk0.data(), &start_in_mesh); + xt::xtensor ijk1 = xt::empty({n}); + bool end_in_mesh; + get_indices(r1, ijk1.data(), &end_in_mesh); + + // If this is the first iteration of the filter loop, check if the track + // intersects any part of the mesh. + if ((!start_in_mesh) && (!end_in_mesh)) { + if (!intersects(r0, r1)) return; + } + + // ======================================================================== + // Figure out which mesh cell to tally. + + // Calculate number of surface crossings + int n_cross = xt::sum(xt::abs(ijk1 - ijk0))(); + if (n_cross == 0) return; + + // Bounding coordinates + Position xyz_cross; + for (int i = 0; i < n; ++i) { + if (u[i] > 0.0) { + xyz_cross[i] = lower_left_[i] + ijk0[i] * width_[i]; + } else { + xyz_cross[i] = lower_left_[i] + (ijk0[i] - 1) * width_[i]; + } + } + + for (int j = 0; j < n_cross; ++j) { + // Set the distances to infinity + Position d {INFTY, INFTY, INFTY}; + + // Determine closest bounding surface. We need to treat + // special case where the cosine of the angle is zero since this would + // result in a divide-by-zero. + double distance = INFTY; + for (int i = 0; i < n; ++i) { + if (u[i] == 0) { + d[i] = INFINITY; + } else { + d[i] = (xyz_cross[i] - r0[i])/u[i]; + } + distance = std::min(distance, d[i]); + } + + // Loop over the dimensions + for (int i = 0; i < n; ++i) { + // Check whether distance is the shortest distance + if (distance == d[i]) { + + // Check whether particle is moving in positive i direction + if (u[i] > 0) { + + // Outward current on i max surface + if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) { + int i_surf = 4*i + 3; + int i_mesh = get_bin_from_indices(ijk0.data()); + int i_bin = 4*n*(i_mesh - 1) + i_surf; + + bins.push_back(i_bin); + } + + // Advance position + ++ijk0[i]; + xyz_cross[i] += width_[i]; + + // If the particle crossed the surface, tally the inward current on + // i min surface + if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) { + int i_surf = 4*i + 2; + int i_mesh = get_bin_from_indices(ijk0.data()); + int i_bin = 4*n*(i_mesh - 1) + i_surf; + + bins.push_back(i_bin); + } + + } else { + // The particle is moving in the negative i direction + + // Outward current on i min surface + if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_) ){ + int i_surf = 4*i + 1; + int i_mesh = get_bin_from_indices(ijk0.data()); + int i_bin = 4*n*(i_mesh - 1) + i_surf; + + bins.push_back(i_bin); + } + + // Advance position + --ijk0[i]; + xyz_cross[i] -= width_[i]; + + // If the particle crossed the surface, tally the inward current on + // i max surface + if (xt::all(ijk0 >= 1) && xt::all(ijk0 <= shape_)) { + int i_surf = 4*i + 4; + int i_mesh = get_bin_from_indices(ijk0.data()); + int i_bin = 4*n*(i_mesh - 1) + i_surf; + + bins.push_back(i_bin); + } + } + } + } + + // Calculate new coordinates + r0 += distance * u; + } +} + void RegularMesh::to_hdf5(hid_t group) { hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); @@ -585,7 +709,6 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, // Check if there were sites outside the mesh for any processor MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, & mpi_intracomm, mpi_err) - end if #else std::copy(cnt.data(), cnt.data() + total, cnt_reduced); if (outside) *outside = outside_; @@ -834,6 +957,20 @@ extern "C" { } } + void mesh_surface_bins_crossed(RegularMesh* m, const Particle* p, + void* match_bins, void* match_weights) + { + // Get surface bins crossed + std::vector bins; + m->surface_bins_crossed(p, bins); + + // Call bindings for VectorInt and VectorReal + for (auto b : bins) { + vector_int_push_back(match_bins, b); + vector_real_push_back(match_weights, 1.0); + } + } + void free_memory_mesh() { meshes.clear(); diff --git a/src/tallies/tally_filter_meshsurface.F90 b/src/tallies/tally_filter_meshsurface.F90 index d1500b8b3..f08bc35ef 100644 --- a/src/tallies/tally_filter_meshsurface.F90 +++ b/src/tallies/tally_filter_meshsurface.F90 @@ -3,7 +3,6 @@ module tally_filter_meshsurface use, intrinsic :: ISO_C_BINDING use constants - use dict_header, only: EMPTY use error use mesh_header use hdf5_interface @@ -41,7 +40,6 @@ contains integer :: i integer :: id integer :: n - integer :: n_dim integer(C_INT) :: err type(RegularMesh) :: m @@ -74,147 +72,25 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - integer :: j ! loop indices - integer :: n_dim ! num dimensions of the mesh - integer :: d1 ! dimension index - integer :: ijk0(3) ! indices of starting coordinates - integer :: ijk1(3) ! indices of ending coordinates - integer :: n_cross ! number of surface crossings - integer :: i_mesh ! flattened mesh bin index - integer :: i_surf ! surface index (1--12) - integer :: i_bin ! actual index for filter - real(8) :: uvw(3) ! cosine of angle of particle - real(8) :: xyz0(3) ! starting/intermediate coordinates - real(8) :: xyz1(3) ! ending coordinates of particle - real(8) :: xyz_cross(3) ! coordinates of bounding surfaces - real(8) :: d(3) ! distance to each bounding surface - real(8) :: distance ! actual distance traveled - logical :: start_in_mesh ! particle's starting xyz in mesh? - logical :: end_in_mesh ! particle's ending xyz in mesh? type(RegularMesh) :: m + type(C_PTR) :: ptr_bins, ptr_weights - ! ! Copy starting and ending location of particle - ! xyz0 = p % last_xyz_current - ! xyz1 = p % coord(1) % xyz + interface + subroutine mesh_surface_bins_crossed(m, p, bins, weights) bind(C) + import C_PTR, Particle + type(C_PTR), value :: m + type(Particle), intent(in) :: p + type(C_PTR), value :: bins + type(C_PTR), value :: weights + end subroutine + end interface - ! m = meshes(this % mesh) - ! n_dim = m % n_dimension() + ! Get a pointer to the mesh. + m = meshes(this % mesh) - ! ! Determine indices for starting and ending location - ! call m % get_indices(xyz0, ijk0, start_in_mesh) - ! call m % get_indices(xyz1, ijk1, end_in_mesh) - - ! ! Check to see if start or end is in mesh -- if not, check if track still - ! ! intersects with mesh - ! if ((.not. start_in_mesh) .and. (.not. end_in_mesh)) then - ! !if (.not. m % intersects(xyz0, xyz1)) return - ! end if - - ! ! Calculate number of surface crossings - ! n_cross = sum(abs(ijk1(:n_dim) - ijk0(:n_dim))) - ! if (n_cross == 0) return - - ! ! Copy particle's direction - ! uvw = p % coord(1) % uvw - - ! ! Bounding coordinates - ! do d1 = 1, n_dim - ! if (uvw(d1) > 0) then - ! xyz_cross(d1) = m % lower_left(d1) + ijk0(d1) * m % width(d1) - ! else - ! xyz_cross(d1) = m % lower_left(d1) + (ijk0(d1) - 1) * m % width(d1) - ! end if - ! end do - - ! do j = 1, n_cross - ! ! Set the distances to infinity - ! d = INFINITY - - ! ! Calculate distance to each bounding surface. We need to treat - ! ! special case where the cosine of the angle is zero since this would - ! ! result in a divide-by-zero. - ! do d1 = 1, n_dim - ! if (uvw(d1) == 0) then - ! d(d1) = INFINITY - ! else - ! d(d1) = (xyz_cross(d1) - xyz0(d1))/uvw(d1) - ! end if - ! end do - - ! ! Determine the closest bounding surface of the mesh cell by - ! ! calculating the minimum distance. Then use the minimum distance and - ! ! direction of the particle to determine which surface was crossed. - ! distance = minval(d) - - ! ! Loop over the dimensions - ! do d1 = 1, n_dim - - ! ! Check whether distance is the shortest distance - ! if (distance == d(d1)) then - - ! ! Check whether particle is moving in positive d1 direction - ! if (uvw(d1) > 0) then - - ! ! Outward current on d1 max surface - ! if (all(ijk0(:n_dim) >= 1) .and. & - ! all(ijk0(:n_dim) <= m % dimension)) then - ! i_surf = d1 * 4 - 1 - ! i_mesh = m % get_bin_from_indices(ijk0) - ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - - ! call match % bins % push_back(i_bin) - ! call match % weights % push_back(ONE) - ! end if - - ! ! Advance position - ! ijk0(d1) = ijk0(d1) + 1 - ! xyz_cross(d1) = xyz_cross(d1) + m % width(d1) - - ! ! If the particle crossed the surface, tally the inward current on - ! ! d1 min surface - ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then - ! i_surf = d1 * 4 - 2 - ! i_mesh = m % get_bin_from_indices(ijk0) - ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - - ! call match % bins % push_back(i_bin) - ! call match % weights % push_back(ONE) - ! end if - - ! else - ! ! The particle is moving in the negative d1 direction - - ! ! Outward current on d1 min surface - ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then - ! i_surf = d1 * 4 - 3 - ! i_mesh = m % get_bin_from_indices(ijk0) - ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - - ! call match % bins % push_back(i_bin) - ! call match % weights % push_back(ONE) - ! end if - - ! ! Advance position - ! ijk0(d1) = ijk0(d1) - 1 - ! xyz_cross(d1) = xyz_cross(d1) - m % width(d1) - - ! ! If the particle crossed the surface, tally the inward current on - ! ! d1 max surface - ! if (all(ijk0(:n_dim) >= 1)) then ! .and. all(ijk0(:n_dim) <= m % dimension)) then - ! i_surf = d1 * 4 - ! i_mesh = m % get_bin_from_indices(ijk0) - ! i_bin = 4*n_dim*(i_mesh - 1) + i_surf - - ! call match % bins % push_back(i_bin) - ! call match % weights % push_back(ONE) - ! end if - ! end if - ! end if - ! end do - - ! ! Calculate new coordinates - ! xyz0 = xyz0 + distance * uvw - ! end do + ptr_bins = C_LOC(match % bins) + ptr_weights = C_LOC(match % weights) + call mesh_surface_bins_crossed(m % ptr, p, ptr_bins, ptr_weights) end subroutine get_all_bins From 1b42fa20c6e2ec5cefb955f677c927c19677e0d5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 4 Sep 2018 07:26:57 -0500 Subject: [PATCH 65/76] Make sure to use std::fabs --- src/mesh.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh.cpp b/src/mesh.cpp index 88aa6af12..87d5f1e28 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -432,9 +432,9 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } for (j = 0; j < n; ++j) { - if (std::abs(u[j]) < FP_PRECISION) { + if (std::fabs(u[j]) < FP_PRECISION) { d(j) = INFTY; - } else if (u[j] > 0) { + } else if (u[j] > 0.0) { double xyz_cross = lower_left_[j] + ijk0(j) * width_[j]; d(j) = (xyz_cross - r0[j]) / u[j]; } else { @@ -473,7 +473,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, // surface. xt::xtensor d = xt::zeros({n}); for (int j = 0; j < n; ++j) { - if (abs(u[j]) < FP_PRECISION) { + if (std::fabs(u[j]) < FP_PRECISION) { d(j) = INFTY; } else if (u[j] > 0) { double xyz_cross = lower_left_[j] + ijk0(j) * width_[j]; From 829b4c4f913e7aeb069ec35de16c046687d4f83c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 06:35:38 -0500 Subject: [PATCH 66/76] Use C++ based count_sites for CMFD. Fix several bugs --- CMakeLists.txt | 1 + src/cmfd_execute.F90 | 18 ++++++++++++++---- src/cmfd_execute.cpp | 34 ++++++++++++++++++++++++++++++++++ src/cmfd_header.F90 | 8 +++++--- src/eigenvalue.F90 | 1 - src/eigenvalue.cpp | 1 - src/mesh.cpp | 6 +++--- src/message_passing.cpp | 2 +- src/settings.cpp | 2 +- 9 files changed, 59 insertions(+), 14 deletions(-) create mode 100644 src/cmfd_execute.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 713bf7c07..f4ff9ae56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -380,6 +380,7 @@ add_library(libopenmc SHARED src/tallies/trigger.F90 src/tallies/trigger_header.F90 src/cell.cpp + src/cmfd_execute.cpp src/distribution.cpp src/distribution_angle.cpp src/distribution_energy.cpp diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 74264a036..6709f782a 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -223,7 +223,7 @@ contains integer :: nx ! maximum number of cells in x direction integer :: ny ! maximum number of cells in y direction integer :: nz ! maximum number of cells in z direction - integer :: ng ! maximum number of energy groups + integer(C_INT) :: ng ! maximum number of energy groups integer :: i ! iteration counter integer :: g ! index for group integer :: ijk(3) ! spatial bin location @@ -231,12 +231,22 @@ contains integer :: mesh_bin ! mesh bin of soruce particle integer :: n_groups ! number of energy groups real(8) :: norm ! normalization factor - logical :: outside ! any source sites outside mesh + logical(C_BOOL) :: outside ! any source sites outside mesh logical :: in_mesh ! source site is inside mesh #ifdef OPENMC_MPI integer :: mpi_err #endif + interface + subroutine cmfd_populate_sourcecounts(ng, energies, source_counts, outside) bind(C) + import C_INT, C_DOUBLE, C_BOOL + integer(C_INT), value :: ng + real(C_DOUBLE), intent(in) :: energies + real(C_DOUBLE), intent(out) :: source_counts + logical(C_BOOL), intent(out) :: outside + end subroutine + end interface + ! Get maximum of spatial and group indices nx = cmfd % indices(1) ny = cmfd % indices(2) @@ -260,8 +270,8 @@ contains cmfd%weightfactors = ONE ! Count bank sites in mesh and reverse due to egrid structure - call count_bank_sites(cmfd_mesh, source_bank, cmfd%sourcecounts, & - cmfd % egrid, sites_outside=outside, size_bank=work) + call cmfd_populate_sourcecounts(ng + 1, cmfd % egrid(1), & + cmfd % sourcecounts(1,1), outside) ! Check for sites outside of the mesh if (master .and. outside) then diff --git a/src/cmfd_execute.cpp b/src/cmfd_execute.cpp new file mode 100644 index 000000000..7774cfe1d --- /dev/null +++ b/src/cmfd_execute.cpp @@ -0,0 +1,34 @@ +#include // for copy +#include +#include + +#include "xtensor/xarray.hpp" +#include "xtensor/xio.hpp" + +#include "openmc/capi.h" +#include "openmc/mesh.h" + +namespace openmc { + +extern "C" int index_cmfd_mesh; + +extern "C" void +cmfd_populate_sourcecounts(int n_energy, const double* energies, + double* source_counts, bool* outside) +{ + // Get pointer to source bank + Bank* source_bank; + int64_t n; + openmc_source_bank(&source_bank, &n); + + // Get source counts in each mesh bin / energy bin + auto& m = meshes.at(index_cmfd_mesh); + xt::xarray counts = m->count_sites(openmc_work, source_bank, n_energy, energies, outside); + + std::cout << counts << "\n"; + + // Copy data from the xarray into the source counts array + std::copy(counts.begin(), counts.end(), source_counts); +} + +} // namespace openmc diff --git a/src/cmfd_header.F90 b/src/cmfd_header.F90 index eafba7b8a..e5e5cc423 100644 --- a/src/cmfd_header.F90 +++ b/src/cmfd_header.F90 @@ -1,5 +1,7 @@ module cmfd_header + use, intrinsic :: ISO_C_BINDING + use constants, only: CMFD_NOACCEL, ZERO, ONE use mesh_header, only: RegularMesh use set_header, only: SetInt @@ -24,7 +26,7 @@ module cmfd_header integer :: mat_dim = CMFD_NOACCEL ! Energy grid - real(8), allocatable :: egrid(:) + real(C_DOUBLE), allocatable :: egrid(:) ! Cross sections real(8), allocatable :: totalxs(:,:,:,:) @@ -53,7 +55,7 @@ module cmfd_header real(8), allocatable :: openmc_src(:,:,:,:) ! Source sites in each mesh box - real(8), allocatable :: sourcecounts(:,:) + real(C_DOUBLE), allocatable :: sourcecounts(:,:) ! Weight adjustment factors real(8), allocatable :: weightfactors(:,:,:,:) @@ -95,7 +97,7 @@ module cmfd_header ! Main object type(cmfd_type), public :: cmfd - integer, public :: index_cmfd_mesh + integer(C_INT), public, bind(C) :: index_cmfd_mesh type(RegularMesh), public :: cmfd_mesh ! Pointers for different tallies diff --git a/src/eigenvalue.F90 b/src/eigenvalue.F90 index 14fe59110..bd2a20b41 100644 --- a/src/eigenvalue.F90 +++ b/src/eigenvalue.F90 @@ -6,7 +6,6 @@ module eigenvalue use constants, only: ZERO use error, only: fatal_error, warning use math, only: t_percentile - use mesh, only: count_bank_sites use message_passing use random_lcg, only: prn, set_particle_seed, advance_prn_seed use settings diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index ef4159e78..fa995e6a0 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -80,7 +80,6 @@ void ufs_count_sites() int64_t n; openmc_source_bank(&source_bank, &n); - // count number of source sites in each ufs mesh cell bool sites_outside; source_frac = m->count_sites(openmc_work, source_bank, 0, nullptr, diff --git a/src/mesh.cpp b/src/mesh.cpp index 87d5f1e28..58f166f62 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -659,7 +659,7 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, std::size_t m = xt::prod(shape_)(); std::vector shape; if (n_energy > 0) { - shape = {m, static_cast(n_energy)}; + shape = {m, static_cast(n_energy - 1)}; } else { shape = {m}; } @@ -670,7 +670,8 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, for (int64_t i = 0; i < n; ++i) { // determine scoring bin for entropy mesh - int mesh_bin = get_bin({bank[i].xyz}); + // TODO: off-by-one + int mesh_bin = get_bin({bank[i].xyz}) - 1; // if outside mesh, skip particle if (mesh_bin < 0) { @@ -680,7 +681,6 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, if (n_energy > 0) { double E = bank[i].E; - int e_bin; if (E >= energies[0] && E <= energies[n_energy - 1]) { // determine energy bin int e_bin = lower_bound_index(energies, energies + n_energy, E); diff --git a/src/message_passing.cpp b/src/message_passing.cpp index ec2fc2d68..dc287e3b3 100644 --- a/src/message_passing.cpp +++ b/src/message_passing.cpp @@ -5,7 +5,7 @@ namespace mpi { int rank {0}; int n_procs {1}; -bool master {false}; +bool master {true}; #ifdef OPENMC_MPI MPI_Comm intracomm; diff --git a/src/settings.cpp b/src/settings.cpp index db6aee7f5..7da8b3166 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -520,7 +520,7 @@ void read_settings_xml() // If the user did not specify how many mesh cells are to be used in // each direction, we automatically determine an appropriate number of // cells - int n = std::ceil(std::pow(settings::n_particles / 20, 1.0/3.0)); + int n = std::ceil(std::pow(settings::n_particles / 20.0, 1.0/3.0)); m.shape_ = {n, n, n}; m.n_dimension_ = 3; From 49cb5da76906344ad2989236808e5fedeb22559a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 07:02:55 -0500 Subject: [PATCH 67/76] Fix bug in UFS --- src/eigenvalue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index fa995e6a0..71ce1c295 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -110,7 +110,7 @@ void ufs_count_sites() double ufs_get_weight(const Particle* p) { - auto& m = meshes[settings::index_entropy_mesh]; + auto& m = meshes[settings::index_ufs_mesh]; // Determine indices on ufs mesh for current location // TODO: off by one From 7a6d36c279799581834fb740be9f666f748483a6 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 09:08:16 -0500 Subject: [PATCH 68/76] Cosmetic changes --- src/mesh.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh.cpp b/src/mesh.cpp index 58f166f62..c173cabe1 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -394,7 +394,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, // If this is the first iteration of the filter loop, check if the track // intersects any part of the mesh. - if ((!start_in_mesh) && (!end_in_mesh)) { + if (!start_in_mesh && !end_in_mesh) { if (!intersects(r0, r1)) return; } @@ -402,8 +402,8 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, // Figure out which mesh cell to tally. // Copy the un-modified coordinates the particle direction. - r0 = Position{p->last_xyz}; - r1 = Position{p->coord[0].xyz}; + r0 = last_r; + r1 = r; // Compute the length of the entire track. double total_distance = (r1 - r0).norm(); @@ -536,7 +536,7 @@ void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins // If this is the first iteration of the filter loop, check if the track // intersects any part of the mesh. - if ((!start_in_mesh) && (!end_in_mesh)) { + if (!start_in_mesh && !end_in_mesh) { if (!intersects(r0, r1)) return; } From f1fb400f925fbb9429b9f46f3004c2583cf43f69 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 11:23:20 -0500 Subject: [PATCH 69/76] Fix last mesh bugs (all tests pass now) --- CMakeLists.txt | 1 - openmc/capi/mesh.py | 6 +- src/cmfd_execute.F90 | 1 - src/mesh.F90 | 106 ------------------------------ src/mesh.cpp | 7 +- src/tallies/tally_filter_mesh.F90 | 18 ----- 6 files changed, 8 insertions(+), 131 deletions(-) delete mode 100644 src/mesh.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index f4ff9ae56..d6821c414 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,7 +312,6 @@ add_library(libopenmc SHARED src/material_header.F90 src/math.F90 src/matrix_header.F90 - src/mesh.F90 src/mesh_header.F90 src/message_passing.F90 src/mgxs_data.F90 diff --git a/openmc/capi/mesh.py b/openmc/capi/mesh.py index 091c5194b..70a4345b0 100644 --- a/openmc/capi/mesh.py +++ b/openmc/capi/mesh.py @@ -41,6 +41,8 @@ _dll.openmc_mesh_set_params.errcheck = _error_handler _dll.openmc_get_mesh_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_mesh_index.restype = c_int _dll.openmc_get_mesh_index.errcheck = _error_handler +_dll.n_meshes.argtypes = [] +_dll.n_meshes.restype = c_int class Mesh(_FortranObjectWithID): @@ -172,10 +174,10 @@ class _MeshMapping(Mapping): def __iter__(self): for i in range(len(self)): - yield Mesh(index=i + 1).id + yield Mesh(index=i).id def __len__(self): - return c_int32.in_dll(_dll, 'n_meshes').value + return _dll.n_meshes() def __repr__(self): return repr(dict(self)) diff --git a/src/cmfd_execute.F90 b/src/cmfd_execute.F90 index 6709f782a..18f5ebec1 100644 --- a/src/cmfd_execute.F90 +++ b/src/cmfd_execute.F90 @@ -214,7 +214,6 @@ contains use bank_header, only: source_bank use constants, only: ZERO, ONE use error, only: warning, fatal_error - use mesh, only: count_bank_sites use message_passing use string, only: to_str diff --git a/src/mesh.F90 b/src/mesh.F90 deleted file mode 100644 index 790dc7d88..000000000 --- a/src/mesh.F90 +++ /dev/null @@ -1,106 +0,0 @@ -module mesh - - use algorithm, only: binary_search - use bank_header, only: bank - use constants - use mesh_header - use message_passing - - implicit none - -contains - -!=============================================================================== -! COUNT_BANK_SITES determines the number of fission bank sites in each cell of a -! given mesh as well as an optional energy group structure. This can be used for -! a variety of purposes (Shannon entropy, CMFD, uniform fission source -! weighting) -!=============================================================================== - - subroutine count_bank_sites(m, bank_array, cnt, energies, size_bank, & - sites_outside) - - type(RegularMesh), intent(in) :: m ! mesh to count sites - type(Bank), intent(in) :: bank_array(:) ! fission or source bank - real(8), intent(out) :: cnt(:,:) ! weight of sites in each - ! cell and energy group - real(8), intent(in), optional :: energies(:) ! energy grid to search - integer(8), intent(in), optional :: size_bank ! # of bank sites (on each proc) - logical, intent(inout), optional :: sites_outside ! were there sites outside mesh? - real(8), allocatable :: cnt_(:,:) - - integer :: i ! loop index for local fission sites - integer :: n_sites ! size of bank array - integer :: n ! number of energy groups / size - integer :: mesh_bin ! mesh bin - integer :: e_bin ! energy bin -#ifdef OPENMC_MPI - integer :: mpi_err ! MPI error code -#endif - logical :: outside ! was any site outside mesh? - - ! initialize variables - allocate(cnt_(size(cnt,1), size(cnt,2))) - cnt_ = ZERO - outside = .false. - - ! Set size of bank - if (present(size_bank)) then - n_sites = int(size_bank,4) - else - n_sites = size(bank_array) - end if - - ! Determine number of energies in group structure - if (present(energies)) then - n = size(energies) - 1 - else - n = 1 - end if - - ! loop over fission sites and count how many are in each mesh box - FISSION_SITES: do i = 1, n_sites - ! determine scoring bin for entropy mesh - call m % get_bin(bank_array(i) % xyz, mesh_bin) - - ! if outside mesh, skip particle - if (mesh_bin == NO_BIN_FOUND) then - outside = .true. - cycle - end if - - ! determine energy bin - if (present(energies)) then - if (bank_array(i) % E < energies(1)) then - e_bin = 1 - elseif (bank_array(i) % E > energies(n + 1)) then - e_bin = n - else - e_bin = binary_search(energies, n + 1, bank_array(i) % E) - end if - else - e_bin = 1 - end if - - ! add to appropriate mesh box - cnt_(e_bin, mesh_bin) = cnt_(e_bin, mesh_bin) + bank_array(i) % wgt - end do FISSION_SITES - -#ifdef OPENMC_MPI - ! collect values from all processors - n = size(cnt_) - call MPI_REDUCE(cnt_, cnt, n, MPI_REAL8, MPI_SUM, 0, mpi_intracomm, mpi_err) - - ! Check if there were sites outside the mesh for any processor - if (present(sites_outside)) then - call MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, & - mpi_intracomm, mpi_err) - end if -#else - sites_outside = outside - cnt = cnt_ -#endif - - end subroutine count_bank_sites - -end module mesh diff --git a/src/mesh.cpp b/src/mesh.cpp index c173cabe1..f2bd7fe79 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -443,7 +443,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } } - int j = xt::argmin(d)(0); + j = xt::argmin(d)(0); if (u[j] > 0.0) { ++ijk0(j); } else { @@ -729,11 +729,11 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, extern "C" int openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end) { - if (!index_start) *index_start = meshes.size(); + if (index_start) *index_start = meshes.size(); for (int i = 0; i < n; ++i) { meshes.emplace_back(new RegularMesh{}); } - if (!index_end) *index_end = meshes.size() - 1; + if (index_end) *index_end = meshes.size() - 1; return 0; } @@ -824,6 +824,7 @@ openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, *ll = m->lower_left_.data(); *ur = m->upper_right_.data(); + *width = m->width_.data(); *n = m->n_dimension_; return 0; } diff --git a/src/tallies/tally_filter_mesh.F90 b/src/tallies/tally_filter_mesh.F90 index bc770b199..dda0bc0ce 100644 --- a/src/tallies/tally_filter_mesh.F90 +++ b/src/tallies/tally_filter_mesh.F90 @@ -73,25 +73,7 @@ contains integer, intent(in) :: estimator type(TallyFilterMatch), intent(inout) :: match - integer, parameter :: MAX_SEARCH_ITER = 100 ! Maximum number of times we can - ! can loop while trying to find - ! the first intersection. - - integer :: j ! loop index for direction - integer :: n - integer :: ijk0(3) ! indices of starting coordinates - integer :: ijk1(3) ! indices of ending coordinates - integer :: search_iter ! loop count for intersection search integer :: bin - real(8) :: uvw(3) ! cosine of angle of particle - real(8) :: xyz0(3) ! starting/intermediate coordinates - real(8) :: xyz1(3) ! ending coordinates of particle - real(8) :: xyz_cross ! coordinates of next boundary - real(8) :: d(3) ! distance to each bounding surface - real(8) :: total_distance ! distance of entire particle track - real(8) :: distance ! distance traveled in mesh cell - logical :: start_in_mesh ! starting coordinates inside mesh? - logical :: end_in_mesh ! ending coordinates inside mesh? type(RegularMesh) :: m type(C_PTR) :: ptr_bins, ptr_weights From 50dcae177225b4ddd86eef7515caf3758da244a2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 12:27:18 -0500 Subject: [PATCH 70/76] Add Doxygen comments, remove unused variables --- include/openmc/capi.h | 1 - include/openmc/mesh.h | 62 ++++++++++++++++++++++++++++++++++++---- src/cmfd_input.F90 | 2 -- src/input_xml.F90 | 10 ------- src/multipole_header.F90 | 4 +-- src/nuclide_header.F90 | 1 - src/physics.F90 | 1 - src/physics_mg.F90 | 1 - src/settings.cpp | 13 ++++----- src/state_point.F90 | 2 +- 10 files changed, 64 insertions(+), 33 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index c155e7bd1..c48b212bd 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -140,7 +140,6 @@ extern "C" { extern int32_t n_filters; extern int32_t n_lattices; extern int32_t n_materials; - extern int32_t n_meshes; extern int n_nuclides; extern int32_t n_plots; extern int32_t n_realizations; diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index c81756491..dca028287 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -28,26 +28,76 @@ public: RegularMesh(pugi::xml_node node); // Methods + + //! Determine which bins were crossed by a particle + //! + //! \param[in] p Particle to check + //! \param[out] bins Bins that were crossed + //! \param[out] lengths Fraction of tracklength in each bin void bins_crossed(const Particle* p, std::vector& bins, std::vector& lengths); + + //! Determine which surface bins were crossed by a particle + //! + //! \param[in] p Particle to check + //! \param[out] bins Surface bins that were crossed void surface_bins_crossed(const Particle* p, std::vector& bins); + + //! Get bin at a given position in space + //! + //! \param[in] r Position to get bin for + //! \return Mesh bin int get_bin(Position r); + + //! Get bin given mesh indices + //! + //! \param[in] Array of mesh indices + //! \return Mesh bin int get_bin_from_indices(const int* ijk); + + //! Get mesh indices given a position + //! + //! \param[in] r Position to get indices for + //! \param[out] ijk Array of mesh indices + //! \param[out] in_mesh Whether position is in mesh void get_indices(Position r, int* ijk, bool* in_mesh); + + //! Get mesh indices corresponding to a mesh bin + //! + //! \param[in] bin Mesh bin + //! \param[out] ijk Mesh indices void get_indices_from_bin(int bin, int* ijk); + + //! Check if a line connected by two points intersects the mesh + //! + //! \param[in] r0 Starting position + //! \param[in] r1 Ending position + //! \return Whether line connecting r0 and r1 intersects mesh bool intersects(Position r0, Position r1); + + //! Write mesh data to an HDF5 group + //! + //! \param[in] group HDF5 group void to_hdf5(hid_t group); + //! Count number of bank sites in each mesh bin / energy bin + //! + //! \param[in] n Number of bank sites + //! \param[in] bank Array of bank sites + //! \param[in] n_energy Number of energies + //! \param[in] energies Array of energies + //! \param[out] Whether any bank sites are outside the mesh + //! \return Array indicating number of sites in each mesh/energy bin xt::xarray count_sites(int64_t n, const Bank* bank, int n_energy, const double* energies, bool* outside); int id_ {-1}; //!< User-specified ID - int n_dimension_; - double volume_frac_; - xt::xarray shape_; - xt::xarray lower_left_; - xt::xarray upper_right_; - xt::xarray width_; + int n_dimension_; //!< Number of dimensions + double volume_frac_; //!< Volume fraction of each mesh element + xt::xarray shape_; //!< Number of mesh elements in each dimension + xt::xarray lower_left_; //!< Lower-left coordinates of mesh + xt::xarray upper_right_; //!< Upper-right coordinates of mesh + xt::xarray width_; //!< Width of each mesh element private: bool intersects_1d(Position r0, Position r1); diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 3208ad9d0..d1e0f6a9a 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -263,8 +263,6 @@ contains integer :: i_filt ! index in filters array integer :: filt_id integer :: tally_id - integer :: iarray3(3) ! temp integer array - real(8) :: rarray3(3) ! temp double array real(C_DOUBLE), allocatable :: energies(:) type(XMLNode) :: node_mesh diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 4766650bf..e756a6aa5 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -203,22 +203,14 @@ contains subroutine read_settings_xml_f(root_ptr) bind(C) type(C_PTR), value :: root_ptr - character(MAX_LINE_LEN) :: temp_str integer :: i integer :: n - integer :: temp_int - integer :: temp_int_array3(3) - integer(C_INT32_T) :: i_start, i_end - integer(C_INT) :: err integer, allocatable :: temp_int_array(:) integer :: n_tracks type(XMLNode) :: root - type(XMLNode) :: node_entropy - type(XMLNode) :: node_ufs type(XMLNode) :: node_sp type(XMLNode) :: node_res_scat type(XMLNode) :: node_vol - type(XMLNode), allocatable :: node_mesh_list(:) type(XMLNode), allocatable :: node_vol_list(:) ! Get proper XMLNode type given pointer @@ -1164,13 +1156,11 @@ contains character(MAX_WORD_LEN), allocatable :: sarray(:) type(DictCharInt) :: trigger_scores type(TallyFilterContainer), pointer :: f - type(RegularMesh), pointer :: m type(XMLDocument) :: doc type(XMLNode) :: root type(XMLNode) :: node_tal type(XMLNode) :: node_filt type(XMLNode) :: node_trigger - type(XMLNode), allocatable :: node_mesh_list(:) type(XMLNode), allocatable :: node_tal_list(:) type(XMLNode), allocatable :: node_filt_list(:) type(XMLNode), allocatable :: node_trigger_list(:) diff --git a/src/multipole_header.F90 b/src/multipole_header.F90 index 05eb62e1a..64610e471 100644 --- a/src/multipole_header.F90 +++ b/src/multipole_header.F90 @@ -1,7 +1,6 @@ module multipole_header use constants - use dict_header, only: DictIntInt use error, only: fatal_error use hdf5_interface @@ -74,12 +73,11 @@ contains character(len=*), intent(in) :: filename character(len=10) :: version - integer :: i, n_poles, n_residues, n_windows + integer :: n_poles, n_residues, n_windows integer(HSIZE_T) :: dims_1d(1), dims_2d(2), dims_3d(3) integer(HID_T) :: file_id integer(HID_T) :: group_id integer(HID_T) :: dset - type(DictIntInt) :: l_val_dict ! Open file for reading and move into the /isotope group file_id = file_open(filename, 'r', parallel=.true.) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 481419fdc..47a2d700a 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -600,7 +600,6 @@ contains integer :: i, j, k, l integer :: t - integer :: m integer :: n integer :: n_grid integer :: i_fission diff --git a/src/physics.F90 b/src/physics.F90 index f1a0d7c57..29a806495 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -1181,7 +1181,6 @@ contains integer :: nu_d(MAX_DELAYED_GROUPS) ! number of delayed neutrons born integer :: i ! loop index integer :: nu ! actual number of neutrons produced - integer :: mesh_bin ! mesh bin for source site real(8) :: nu_t ! total nu real(8) :: weight ! weight adjustment for ufs method type(Nuclide), pointer :: nuc diff --git a/src/physics_mg.F90 b/src/physics_mg.F90 index bcafc4314..1d60b371e 100644 --- a/src/physics_mg.F90 +++ b/src/physics_mg.F90 @@ -167,7 +167,6 @@ contains integer :: dg ! delayed group integer :: gout ! group out integer :: nu ! actual number of neutrons produced - integer :: mesh_bin ! mesh bin for source site real(8) :: nu_t ! total nu real(8) :: mu ! fission neutron angular cosine real(8) :: phi ! fission neutron azimuthal angle diff --git a/src/settings.cpp b/src/settings.cpp index 7da8b3166..007c515b0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -3,7 +3,6 @@ #include // for ceil, pow #include // for numeric_limits #include -#include // for out_of_range #include #include @@ -490,13 +489,13 @@ void read_settings_xml() // Shannon Entropy mesh if (check_for_node(root, "entropy_mesh")) { int temp = std::stoi(get_node_value(root, "entropy_mesh")); - try { - index_entropy_mesh = mesh_map.at(temp); - } catch (const std::out_of_range& e) { + if (mesh_map.find(temp) == mesh_map.end()) { std::stringstream msg; msg << "Mesh " << temp << " specified for Shannon entropy does not exist."; fatal_error(msg); } + index_entropy_mesh = mesh_map.at(temp); + } else if (check_for_node(root, "entropy")) { warning("Specifying a Shannon entropy mesh via the element " "is deprecated. Please create a mesh using and then reference " @@ -535,14 +534,14 @@ void read_settings_xml() // Uniform fission source weighting mesh if (check_for_node(root, "ufs_mesh")) { auto temp = std::stoi(get_node_value(root, "ufs_mesh")); - try { - index_ufs_mesh = mesh_map.at(temp); - } catch (const std::out_of_range& e) { + if (mesh_map.find(temp) == mesh_map.end()) { std::stringstream msg; msg << "Mesh " << temp << " specified for uniform fission site method " "does not exist."; fatal_error(msg); } + index_ufs_mesh = mesh_map.at(temp); + } else if (check_for_node(root, "uniform_fs")) { warning("Specifying a UFS mesh via the element " "is deprecated. Please create a mesh using and then reference " diff --git a/src/state_point.F90 b/src/state_point.F90 index d20456d7b..526066c52 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -67,7 +67,7 @@ contains integer :: i_xs integer, allocatable :: id_array(:) integer(HID_T) :: file_id - integer(HID_T) :: cmfd_group, tallies_group, tally_group, meshes_group, & + integer(HID_T) :: cmfd_group, tallies_group, tally_group, & filters_group, filter_group, derivs_group, & deriv_group, runtime_group integer(C_INT) :: ignored_err From 6174461daa08b36972b56d7af81ec1ba81300eea Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 13:50:19 -0500 Subject: [PATCH 71/76] Fix MPI-related bugs --- src/eigenvalue.cpp | 4 ++-- src/mesh.cpp | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 71ce1c295..d4f629e06 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -92,8 +92,8 @@ void ufs_count_sites() #ifdef OPENMC_MPI // Send source fraction to all processors - int n = xt::prod(m->shape_)(); - MPI_Bcast(source_frac.data(), n, MPI_DOUBLE, 0, mpi::intracomm) + int n_bins = xt::prod(m->shape_)(); + MPI_Bcast(source_frac.data(), n_bins, MPI_DOUBLE, 0, mpi::intracomm); #endif // Normalize to total weight to get fraction of source in each cell diff --git a/src/mesh.cpp b/src/mesh.cpp index f2bd7fe79..b922408de 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -702,13 +702,11 @@ xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, // collect values from all processors MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); - if (outside) { - MPI_Reduce(&outside_, outside, 1, MPI_BOOL, MPI_LOR, 0, mpi::intracomm); - } // Check if there were sites outside the mesh for any processor - MPI_REDUCE(outside, sites_outside, 1, MPI_LOGICAL, MPI_LOR, 0, & - mpi_intracomm, mpi_err) + if (outside) { + MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm); + } #else std::copy(cnt.data(), cnt.data() + total, cnt_reduced); if (outside) *outside = outside_; From 7807c169c4ad5a1269ed2d464571d819b8d054fa Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 15:06:49 -0500 Subject: [PATCH 72/76] Try using coveralls-python instead of python-coveralls --- tools/ci/travis-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh index 5ad238169..88c59d051 100755 --- a/tools/ci/travis-install.sh +++ b/tools/ci/travis-install.sh @@ -22,4 +22,4 @@ python tools/ci/travis-install.py pip install -e .[test] # For uploading to coveralls -pip install python-coveralls +pip install coveralls From 4b56c86c50129e840ffd5202bb2b3e9f41ba4c28 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Wed, 5 Sep 2018 20:46:33 -0400 Subject: [PATCH 73/76] Cleaning up code, resolving @paulromano comments --- include/openmc/constants.h | 6 +++--- include/openmc/hdf5_interface.h | 3 --- include/openmc/mgxs.h | 10 +++++----- include/openmc/xsdata.h | 2 +- src/hdf5_interface.cpp | 30 ------------------------------ src/mgxs.cpp | 10 +++++----- src/xsdata.cpp | 25 +++++++++++++------------ 7 files changed, 27 insertions(+), 59 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index b8c5c8548..c77817a14 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -11,9 +11,9 @@ namespace openmc { -typedef std::vector > double_2dvec; -typedef std::vector > > double_3dvec; -typedef std::vector > > > double_4dvec; +using double_2dvec = std::vector>; +using double_3dvec = std::vector>>; +using double_4dvec = std::vector>>>; // ============================================================================ // VERSIONING NUMBERS diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 3ab2014c1..b791c8d72 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -70,9 +70,6 @@ void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); std::vector attribute_shape(hid_t obj_id, const char* name); std::vector dataset_names(hid_t group_id); diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index cd312ea17..e80355bee 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -159,7 +159,7 @@ class Mgxs { //! @param dg delayed group index; use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg); + get_xs(int xstype, int gin, int* gout, double* mu, int* dg); //! \brief Samples the fission neutron energy and if prompt or delayed. //! @@ -167,7 +167,7 @@ class Mgxs { //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. void - sample_fission_energy(const int gin, int& dg, int& gout); + sample_fission_energy(int gin, int& dg, int& gout); //! \brief Samples the outgoing energy and angle from a scatter event. //! @@ -176,7 +176,7 @@ class Mgxs { //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. void - sample_scatter(const int gin, int& gout, double& mu, double& wgt); + sample_scatter(int gin, int& gout, double& mu, double& wgt); //! \brief Calculates cross section quantities needed for tracking. //! @@ -187,14 +187,14 @@ class Mgxs { //! @param abs_xs Resultant absorption cross section. //! @param nu_fiss_xs Resultant nu-fission cross section. void - calculate_xs(const int gin, const double sqrtkT, const double uvw[3], + calculate_xs(int gin, double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); //! \brief Sets the temperature index in cache given a temperature //! //! @param sqrtkT Temperature of the material. void - set_temperature_index(const double sqrtkT); + set_temperature_index(double sqrtkT); //! \brief Sets the angle index in cache given a direction //! diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 0bdeaf818..fa75b10aa 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -94,7 +94,7 @@ class XsData { // [angle][incoming group][outgoing group][delayed group] xt::xtensor chi_delayed; // scatter has the following dimensions: [angle] - std::vector > scatter; + std::vector> scatter; XsData() = default; diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 52fae8228..514cf6966 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -673,36 +673,6 @@ read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, } } -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int dim4 = result.shape()[3]; - int dim5 = result.shape()[4]; - double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - for (int l = 0; l < dim4; l++) { - for (int m = 0; m < dim5; m++) { - result(i, j, k, l, m) = temp_arr[temp_idx++]; - } - } - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index b9e22780a..12c73fab4 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -423,7 +423,7 @@ Mgxs::combine(const std::vector& micros, const std::vector& scala //============================================================================== double -Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) +Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -535,7 +535,7 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) //============================================================================== void -Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) +Mgxs::sample_fission_energy(int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -599,7 +599,7 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) //============================================================================== void -Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) +Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data @@ -614,7 +614,7 @@ Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) //============================================================================== void -Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], +Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices @@ -649,7 +649,7 @@ Mgxs::equiv(const Mgxs& that) //============================================================================== void -Mgxs::set_temperature_index(const double sqrtkT) +Mgxs::set_temperature_index(double sqrtkT) { // See if we need to find the new index #ifdef _OPENMP diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 56783a672..8abc1edfd 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -132,7 +132,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made @@ -186,16 +186,15 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), - xt::newaxis()); + temp_chi_p /= xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); // Get chi-delayed xt::xtensor temp_chi_d({n_ang, delayed_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {2}), xt::all(), - xt::all(), xt::newaxis()); + temp_chi_d /= xt::view(xt::sum(temp_chi_d, {2}), + xt::all(), xt::all(), xt::newaxis()); // Now assign the prompt and delayed chis by replicating for each incoming group chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); @@ -203,8 +202,10 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::all()); // Get prompt and delayed nu-fission directly - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); - read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, + true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", + delayed_nu_fission, true); } void @@ -219,7 +220,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in self.chi is the normalized chi we just made chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); @@ -299,11 +300,11 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, } //Normalize both chis - chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), - xt::all(), xt::newaxis()); + chi_prompt /= xt::view(xt::sum(chi_prompt, {2}), + xt::all(), xt::all(), xt::newaxis()); - chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {3}), xt::all(), - xt::all(), xt::all(), xt::newaxis()); + chi_delayed /= xt::view(xt::sum(chi_delayed, {3}), + xt::all(), xt::all(), xt::all(), xt::newaxis()); } void From e971ebbfe6320d546209e1ff248ddcebebee4594 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 5 Sep 2018 20:12:08 -0500 Subject: [PATCH 74/76] Use coveralls-python instead of python-coveralls --- tools/ci/travis-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh index 5ad238169..88c59d051 100755 --- a/tools/ci/travis-install.sh +++ b/tools/ci/travis-install.sh @@ -22,4 +22,4 @@ python tools/ci/travis-install.py pip install -e .[test] # For uploading to coveralls -pip install python-coveralls +pip install coveralls From 4c47d868b4e5d481dc391aba26674199a99dbc7a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 6 Sep 2018 10:19:41 -0500 Subject: [PATCH 75/76] Make sure RegularMesh methods are const. Address other comments by @smharper --- include/openmc/mesh.h | 24 ++++++++++++------------ src/mesh.cpp | 39 +++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index dca028287..3d31fb489 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -35,50 +35,50 @@ public: //! \param[out] bins Bins that were crossed //! \param[out] lengths Fraction of tracklength in each bin void bins_crossed(const Particle* p, std::vector& bins, - std::vector& lengths); + std::vector& lengths) const; //! Determine which surface bins were crossed by a particle //! //! \param[in] p Particle to check //! \param[out] bins Surface bins that were crossed - void surface_bins_crossed(const Particle* p, std::vector& bins); + void surface_bins_crossed(const Particle* p, std::vector& bins) const; //! Get bin at a given position in space //! //! \param[in] r Position to get bin for //! \return Mesh bin - int get_bin(Position r); + int get_bin(Position r) const; //! Get bin given mesh indices //! //! \param[in] Array of mesh indices //! \return Mesh bin - int get_bin_from_indices(const int* ijk); + int get_bin_from_indices(const int* ijk) const; //! Get mesh indices given a position //! //! \param[in] r Position to get indices for //! \param[out] ijk Array of mesh indices //! \param[out] in_mesh Whether position is in mesh - void get_indices(Position r, int* ijk, bool* in_mesh); + void get_indices(Position r, int* ijk, bool* in_mesh) const; //! Get mesh indices corresponding to a mesh bin //! //! \param[in] bin Mesh bin //! \param[out] ijk Mesh indices - void get_indices_from_bin(int bin, int* ijk); + void get_indices_from_bin(int bin, int* ijk) const; //! Check if a line connected by two points intersects the mesh //! //! \param[in] r0 Starting position //! \param[in] r1 Ending position //! \return Whether line connecting r0 and r1 intersects mesh - bool intersects(Position r0, Position r1); + bool intersects(Position r0, Position r1) const; //! Write mesh data to an HDF5 group //! //! \param[in] group HDF5 group - void to_hdf5(hid_t group); + void to_hdf5(hid_t group) const; //! Count number of bank sites in each mesh bin / energy bin //! @@ -89,7 +89,7 @@ public: //! \param[out] Whether any bank sites are outside the mesh //! \return Array indicating number of sites in each mesh/energy bin xt::xarray count_sites(int64_t n, const Bank* bank, - int n_energy, const double* energies, bool* outside); + int n_energy, const double* energies, bool* outside) const; int id_ {-1}; //!< User-specified ID int n_dimension_; //!< Number of dimensions @@ -100,9 +100,9 @@ public: xt::xarray width_; //!< Width of each mesh element private: - bool intersects_1d(Position r0, Position r1); - bool intersects_2d(Position r0, Position r1); - bool intersects_3d(Position r0, Position r1); + bool intersects_1d(Position r0, Position r1) const; + bool intersects_2d(Position r0, Position r1) const; + bool intersects_3d(Position r0, Position r1) const; }; //============================================================================== diff --git a/src/mesh.cpp b/src/mesh.cpp index b922408de..c1bd830a6 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -138,7 +138,7 @@ RegularMesh::RegularMesh(pugi::xml_node node) } } -int RegularMesh::get_bin(Position r) +int RegularMesh::get_bin(Position r) const { // Loop over the dimensions of the mesh for (int i = 0; i < n_dimension_; ++i) { @@ -160,7 +160,7 @@ int RegularMesh::get_bin(Position r) return get_bin_from_indices(ijk); } -int RegularMesh::get_bin_from_indices(const int* ijk) +int RegularMesh::get_bin_from_indices(const int* ijk) const { if (n_dimension_ == 1) { return ijk[0]; @@ -171,7 +171,7 @@ int RegularMesh::get_bin_from_indices(const int* ijk) } } -void RegularMesh::get_indices(Position r, int* ijk, bool* in_mesh) +void RegularMesh::get_indices(Position r, int* ijk, bool* in_mesh) const { // Find particle in mesh *in_mesh = true; @@ -183,7 +183,7 @@ void RegularMesh::get_indices(Position r, int* ijk, bool* in_mesh) } } -void RegularMesh::get_indices_from_bin(int bin, int* ijk) +void RegularMesh::get_indices_from_bin(int bin, int* ijk) const { if (n_dimension_ == 1) { ijk[0] = bin; @@ -192,12 +192,12 @@ void RegularMesh::get_indices_from_bin(int bin, int* ijk) ijk[1] = (bin - 1) / shape_[0] + 1; } else if (n_dimension_ == 3) { ijk[0] = (bin - 1) % shape_[0] + 1; - ijk[1] = (bin - 1) % (shape_[0] * shape_[1]) / shape_[0] + 1; + ijk[1] = ((bin - 1) % (shape_[0] * shape_[1])) / shape_[0] + 1; ijk[2] = (bin - 1) / (shape_[0] * shape_[1]) + 1; } } -bool RegularMesh::intersects(Position r0, Position r1) +bool RegularMesh::intersects(Position r0, Position r1) const { switch(n_dimension_) { case 1: @@ -209,7 +209,7 @@ bool RegularMesh::intersects(Position r0, Position r1) } } -bool RegularMesh::intersects_1d(Position r0, Position r1) +bool RegularMesh::intersects_1d(Position r0, Position r1) const { // Copy coordinates of mesh lower_left and upper_right double left = lower_left_[0]; @@ -225,7 +225,7 @@ bool RegularMesh::intersects_1d(Position r0, Position r1) } } -bool RegularMesh::intersects_2d(Position r0, Position r1) +bool RegularMesh::intersects_2d(Position r0, Position r1) const { // Copy coordinates of starting point double x0 = r0.x; @@ -280,7 +280,7 @@ bool RegularMesh::intersects_2d(Position r0, Position r1) return false; } -bool RegularMesh::intersects_3d(Position r0, Position r1) +bool RegularMesh::intersects_3d(Position r0, Position r1) const { // Copy coordinates of starting point double x0 = r0.x; @@ -365,7 +365,7 @@ bool RegularMesh::intersects_3d(Position r0, Position r1) } void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, - std::vector& lengths) + std::vector& lengths) const { constexpr int MAX_SEARCH_ITER = 100; @@ -392,8 +392,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, bool end_in_mesh; get_indices(r1, ijk1.data(), &end_in_mesh); - // If this is the first iteration of the filter loop, check if the track - // intersects any part of the mesh. + // Check if the track intersects any part of the mesh. if (!start_in_mesh && !end_in_mesh) { if (!intersects(r0, r1)) return; } @@ -459,8 +458,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, while (true) { // ======================================================================== - // Compute the length of the track segment in the appropiate mesh cell and - // return. + // Compute the length of the track segment in the each mesh cell and return double distance; int j; @@ -492,9 +490,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, bins.push_back(bin); lengths.push_back(distance / total_distance); - // Find the next mesh cell that the particle enters. - - // If the particle track ends in that bin, { we are done. + // If the particle track ends in that bin, then we are done. if (ijk0 == ijk1) break; // Translate the starting coordintes by the distance to that face. This @@ -515,7 +511,7 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } } -void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins) +void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins) const { // ======================================================================== // Determine if the track intersects the tally mesh. @@ -534,8 +530,7 @@ void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins bool end_in_mesh; get_indices(r1, ijk1.data(), &end_in_mesh); - // If this is the first iteration of the filter loop, check if the track - // intersects any part of the mesh. + // Check if the track intersects any part of the mesh. if (!start_in_mesh && !end_in_mesh) { if (!intersects(r0, r1)) return; } @@ -639,7 +634,7 @@ void RegularMesh::surface_bins_crossed(const Particle* p, std::vector& bins } } -void RegularMesh::to_hdf5(hid_t group) +void RegularMesh::to_hdf5(hid_t group) const { hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); @@ -653,7 +648,7 @@ void RegularMesh::to_hdf5(hid_t group) } xt::xarray RegularMesh::count_sites(int64_t n, const Bank* bank, - int n_energy, const double* energies, bool* outside) + int n_energy, const double* energies, bool* outside) const { // Determine shape of array for counts std::size_t m = xt::prod(shape_)(); From 1cf1deb9f0f3420b5966b18d9714a72d52affa3c Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 8 Sep 2018 06:44:49 -0400 Subject: [PATCH 76/76] Templatized read_nd_vector --- include/openmc/hdf5_interface.h | 62 ++++++++------ src/hdf5_interface.cpp | 140 -------------------------------- 2 files changed, 36 insertions(+), 166 deletions(-) diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index b791c8d72..2f5d7cb52 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -14,6 +14,7 @@ #include "xtensor/xarray.hpp" #include "openmc/position.h" +#include "openmc/error.h" namespace openmc { @@ -46,31 +47,6 @@ hid_t file_open(const std::string& filename, char mode, bool parallel=false); void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - - std::vector attribute_shape(hid_t obj_id, const char* name); std::vector dataset_names(hid_t group_id); void ensure_exists(hid_t group_id, const char* name); @@ -228,7 +204,7 @@ read_attribute(hid_t obj_id, const char* name, std::vector& vec) } //============================================================================== -// Templates/overloads for read_dataset +// Templates/overloads for read_dataset and related methods //============================================================================== template @@ -286,6 +262,40 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray& arr, bool indep close_dataset(dset); } + +template +void read_dataset_as_shape(hid_t obj_id, const char* name, + xt::xtensor& arr, bool indep=false) +{ + hid_t dset = open_dataset(obj_id, name); + + // Allocate new array to read data into + std::size_t size = 1; + for (const auto x : arr.shape()) + size *= x; + T* buffer = new T[size]; + + // Read data from attribute + read_dataset(dset, nullptr, H5TypeMap::type_id, buffer, indep); + + // Adapt into xarray + arr = xt::adapt(buffer, size, xt::acquire_ownership(), arr.shape()); + + close_dataset(dset); +} + + +template +void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have=false) +{ + if (object_exists(obj_id, name)) { + read_dataset_as_shape(obj_id, name, result, true); + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + //============================================================================== // Templates/overloads for write_attribute //============================================================================== diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 514cf6966..4badc0441 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -14,7 +14,6 @@ #include "mpi.h" #include "openmc/message_passing.h" #endif -#include "openmc/error.h" namespace openmc { @@ -535,145 +534,6 @@ read_complex(hid_t obj_id, const char* name, std::complex* buffer, bool } -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - double temp_arr[dim1]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - result(i) = temp_arr[temp_idx++]; - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - double temp_arr[dim1 * dim2]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - result(i, j) = temp_arr[temp_idx++]; - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int temp_arr[dim1 * dim2]; - read_int(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - result(i, j) = temp_arr[temp_idx++]; - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - double temp_arr[dim1 * dim2 * dim3]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - result(i, j, k) = temp_arr[temp_idx++]; - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int temp_arr[dim1 * dim2 * dim3]; - read_int(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - result(i, j, k) = temp_arr[temp_idx++]; - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int dim4 = result.shape()[3]; - double temp_arr[dim1 * dim2 * dim3 * dim4]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - for (int l = 0; l < dim4; l++) { - result(i, j, k, l) = temp_arr[temp_idx++]; - } - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) {