#ifndef OPENMC_RANDOM_RAY_SOURCE_REGION_H #define OPENMC_RANDOM_RAY_SOURCE_REGION_H #include "openmc/openmp_interface.h" #include "openmc/position.h" #include "openmc/random_ray/moment_matrix.h" #include "openmc/settings.h" namespace openmc { //---------------------------------------------------------------------------- // Helper Functions // The hash_combine function is the standard hash combine function from boost // that is typically used for combining multiple hash values into a single hash // as is needed for larger objects being stored in a hash map. The function is // taken from: // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine // which carries the following license: // // Boost Software License - Version 1.0 - August 17th, 2003 // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. inline void hash_combine(size_t& seed, const size_t v) { seed ^= (v + 0x9e3779b9 + (seed << 6) + (seed >> 2)); } //---------------------------------------------------------------------------- // Helper Structs and Classes // A mapping object that is used to map between a specific random ray // source region and an OpenMC native tally bin that it should score to // every iteration. struct TallyTask { int tally_idx; int64_t filter_idx; int score_idx; int score_type; TallyTask(int tally_idx, int64_t filter_idx, int score_idx, int score_type) : tally_idx(tally_idx), filter_idx(filter_idx), score_idx(score_idx), score_type(score_type) {} TallyTask() = default; // Comparison and Hash operators are defined to allow usage of the // TallyTask struct as a key in an unordered_set bool operator==(const TallyTask& other) const { return tally_idx == other.tally_idx && filter_idx == other.filter_idx && score_idx == other.score_idx && score_type == other.score_type; } struct HashFunctor { size_t operator()(const TallyTask& task) const { size_t seed = 0; hash_combine(seed, task.tally_idx); hash_combine(seed, task.filter_idx); hash_combine(seed, task.score_idx); hash_combine(seed, task.score_type); return seed; } }; }; // The SourceRegionKey combines a base source region (i.e., a material // filled cell instance) with a mesh bin. This key is used as a handle // for dynamically discovered source regions when subdividing source // regions with meshes. class SourceRegionKey { public: int64_t base_source_region_id; int64_t mesh_bin; SourceRegionKey() = default; SourceRegionKey(int64_t source_region, int64_t bin) : base_source_region_id(source_region), mesh_bin(bin) {} // Equality operator required by the unordered_map bool operator==(const SourceRegionKey& other) const { return base_source_region_id == other.base_source_region_id && mesh_bin == other.mesh_bin; } // Less than operator required by std::sort bool operator<(const SourceRegionKey& other) const { if (base_source_region_id < other.base_source_region_id) { return true; } else if (base_source_region_id > other.base_source_region_id) { return false; } else { return mesh_bin < other.mesh_bin; } } // Hashing functor required by the unordered_map struct HashFunctor { size_t operator()(const SourceRegionKey& key) const { size_t seed = 0; hash_combine(seed, key.base_source_region_id); hash_combine(seed, key.mesh_bin); return seed; } }; }; // Forward declaration of SourceRegion class SourceRegion; class SourceRegionHandle { public: //---------------------------------------------------------------------------- // Constructors SourceRegionHandle(SourceRegion& sr); SourceRegionHandle() = default; // All fields are commented/described in the SourceRegion class definition // below //---------------------------------------------------------------------------- // Public Data members int negroups_; bool is_numerical_fp_artifact_ {false}; bool is_linear_ {false}; // Scalar fields int* material_; int* temperature_idx_; double* density_mult_; int* is_small_; int* n_hits_; int* birthday_; OpenMPMutex* lock_; double* volume_; double* volume_t_; double* volume_sq_; double* volume_sq_t_; double* volume_naive_; int* position_recorded_; int* external_source_present_; Position* position_; Position* centroid_; Position* centroid_iteration_; Position* centroid_t_; MomentMatrix* mom_matrix_; MomentMatrix* mom_matrix_t_; // A set of volume tally tasks. This more complicated data structure is // convenient for ensuring that volumes are only tallied once per source // region, regardless of how many energy groups are used for tallying. std::unordered_set* volume_task_; // Mesh that subdivides this source region int* mesh_; int64_t* parent_sr_; // Energy group-wise 1D arrays double* scalar_flux_old_; double* scalar_flux_new_; float* source_; float* external_source_; double* scalar_flux_final_; MomentArray* source_gradients_; MomentArray* flux_moments_old_; MomentArray* flux_moments_new_; MomentArray* flux_moments_t_; // 2D array representing values for all energy groups x tally // tasks. Each group may have a different number of tally tasks // associated with it, necessitating the use of a jagged array. vector* tally_task_; //---------------------------------------------------------------------------- // Public Accessors int& material() { return *material_; } const int material() const { return *material_; } double& density_mult() { return *density_mult_; } const double density_mult() const { return *density_mult_; } int& temperature_idx() { return *temperature_idx_; } const int temperature_idx() const { return *temperature_idx_; } int& is_small() { return *is_small_; } const int is_small() const { return *is_small_; } int& n_hits() { return *n_hits_; } const int n_hits() const { return *n_hits_; } void lock() { lock_->lock(); } void unlock() { lock_->unlock(); } double& volume() { return *volume_; } const double volume() const { return *volume_; } double& volume_t() { return *volume_t_; } const double volume_t() const { return *volume_t_; } double& volume_sq() { return *volume_sq_; } const double volume_sq() const { return *volume_sq_; } double& volume_sq_t() { return *volume_sq_t_; } const double volume_sq_t() const { return *volume_sq_t_; } double& volume_naive() { return *volume_naive_; } const double volume_naive() const { return *volume_naive_; } int& position_recorded() { return *position_recorded_; } const int position_recorded() const { return *position_recorded_; } int& external_source_present() { return *external_source_present_; } const int external_source_present() const { return *external_source_present_; } Position& position() { return *position_; } const Position position() const { return *position_; } Position& centroid() { return *centroid_; } const Position centroid() const { return *centroid_; } Position& centroid_iteration() { return *centroid_iteration_; } const Position centroid_iteration() const { return *centroid_iteration_; } Position& centroid_t() { return *centroid_t_; } const Position centroid_t() const { return *centroid_t_; } MomentMatrix& mom_matrix() { return *mom_matrix_; } const MomentMatrix mom_matrix() const { return *mom_matrix_; } MomentMatrix& mom_matrix_t() { return *mom_matrix_t_; } const MomentMatrix mom_matrix_t() const { return *mom_matrix_t_; } std::unordered_set& volume_task() { return *volume_task_; } const std::unordered_set& volume_task() const { return *volume_task_; } int& mesh() { return *mesh_; } const int mesh() const { return *mesh_; } int64_t& parent_sr() { return *parent_sr_; } const int64_t parent_sr() const { return *parent_sr_; } double& scalar_flux_old(int g) { return scalar_flux_old_[g]; } const double scalar_flux_old(int g) const { return scalar_flux_old_[g]; } double& scalar_flux_new(int g) { return scalar_flux_new_[g]; } const double scalar_flux_new(int g) const { return scalar_flux_new_[g]; } double& scalar_flux_final(int g) { return scalar_flux_final_[g]; } const double scalar_flux_final(int g) const { return scalar_flux_final_[g]; } float& source(int g) { return source_[g]; } const float source(int g) const { return source_[g]; } float& external_source(int g) { return external_source_[g]; } const float external_source(int g) const { return external_source_[g]; } MomentArray& source_gradients(int g) { return source_gradients_[g]; } const MomentArray source_gradients(int g) const { return source_gradients_[g]; } MomentArray& flux_moments_old(int g) { return flux_moments_old_[g]; } const MomentArray flux_moments_old(int g) const { return flux_moments_old_[g]; } MomentArray& flux_moments_new(int g) { return flux_moments_new_[g]; } const MomentArray flux_moments_new(int g) const { return flux_moments_new_[g]; } MomentArray& flux_moments_t(int g) { return flux_moments_t_[g]; } const MomentArray flux_moments_t(int g) const { return flux_moments_t_[g]; } vector& tally_task(int g) { return tally_task_[g]; } const vector& tally_task(int g) const { return tally_task_[g]; } }; // class SourceRegionHandle class SourceRegion { public: //---------------------------------------------------------------------------- // Constructors SourceRegion(int negroups, bool is_linear); SourceRegion() = default; //---------------------------------------------------------------------------- // Public Data members //--------------------------------------- // Scalar fields int material_ {0}; //!< Index in openmc::model::materials array int temperature_idx_ { 0}; //!< Index into the MGXS array representing temperature double density_mult_ {1.0}; //!< A density multiplier queried from the cell //!< corresponding to the source region. OpenMPMutex lock_; double volume_ { 0.0}; //!< Volume (computed from the sum of ray crossing lengths) double volume_t_ {0.0}; //!< Volume totaled over all iterations double volume_sq_ {0.0}; //!< Volume squared double volume_sq_t_ {0.0}; //!< Volume squared totaled over all iterations double volume_naive_ {0.0}; //!< Volume as integrated from this iteration only int position_recorded_ {0}; //!< Has the position been recorded yet? int external_source_present_ { 0}; //!< Is an external source present in this region? int is_small_ {0}; //!< Is it "small", receiving < 1.5 hits per iteration? int n_hits_ {0}; //!< Number of total hits (ray crossings) // Mesh that subdivides this source region int mesh_ {C_NONE}; //!< Index in openmc::model::meshes array that subdivides //!< this source region int64_t parent_sr_ {C_NONE}; //!< Index of a parent source region Position position_ { 0.0, 0.0, 0.0}; //!< A position somewhere inside the region Position centroid_ {0.0, 0.0, 0.0}; //!< The centroid Position centroid_iteration_ { 0.0, 0.0, 0.0}; //!< The centroid integrated from this iteration only Position centroid_t_ { 0.0, 0.0, 0.0}; //!< The centroid accumulated over all iterations MomentMatrix mom_matrix_ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< The spatial moment matrix MomentMatrix mom_matrix_t_ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; //!< The spatial moment matrix accumulated over all iterations // A set of volume tally tasks. This more complicated data structure is // convenient for ensuring that volumes are only tallied once per source // region, regardless of how many energy groups are used for tallying. std::unordered_set volume_task_; //--------------------------------------- // Energy group-wise 1D arrays vector scalar_flux_old_; //!< The scalar flux from the previous iteration vector scalar_flux_new_; //!< The scalar flux from the current iteration vector source_; //!< The total source term (fission + scattering + external) vector external_source_; //!< The external source term vector scalar_flux_final_; //!< The scalar flux accumulated over all //!< active iterations (used for plotting, //!< or computing adjoint sources) vector source_gradients_; //!< The linear source gradients vector flux_moments_old_; //!< The linear flux moments from the previous iteration vector flux_moments_new_; //!< The linear flux moments from the current iteration vector flux_moments_t_; //!< The linear flux moments accumulated over all active //!< iterations (used for plotting) //--------------------------------------- // 2D array representing values for all energy groups x tally // tasks. Each group may have a different number of tally tasks // associated with it, necessitating the use of a jagged array. vector> tally_task_; }; // class SourceRegion class SourceRegionContainer { public: //---------------------------------------------------------------------------- // Constructors SourceRegionContainer(int negroups, bool is_linear) : negroups_(negroups), is_linear_(is_linear) {} SourceRegionContainer() = default; //---------------------------------------------------------------------------- // Public Accessors int& material(int64_t sr) { return material_[sr]; } const int material(int64_t sr) const { return material_[sr]; } int& temperature_idx(int64_t sr) { return temperature_idx_[sr]; } const int temperature_idx(int64_t sr) const { return temperature_idx_[sr]; } double& density_mult(int64_t sr) { return density_mult_[sr]; } const double density_mult(int64_t sr) const { return density_mult_[sr]; } int& is_small(int64_t sr) { return is_small_[sr]; } const int is_small(int64_t sr) const { return is_small_[sr]; } int& n_hits(int64_t sr) { return n_hits_[sr]; } const int n_hits(int64_t sr) const { return n_hits_[sr]; } OpenMPMutex& lock(int64_t sr) { return lock_[sr]; } const OpenMPMutex& lock(int64_t sr) const { return lock_[sr]; } double& volume(int64_t sr) { return volume_[sr]; } const double volume(int64_t sr) const { return volume_[sr]; } double& volume_t(int64_t sr) { return volume_t_[sr]; } const double volume_t(int64_t sr) const { return volume_t_[sr]; } double& volume_sq(int64_t sr) { return volume_sq_[sr]; } const double volume_sq(int64_t sr) const { return volume_sq_[sr]; } double& volume_sq_t(int64_t sr) { return volume_sq_t_[sr]; } const double volume_sq_t(int64_t sr) const { return volume_sq_t_[sr]; } double& volume_naive(int64_t sr) { return volume_naive_[sr]; } const double volume_naive(int64_t sr) const { return volume_naive_[sr]; } int& position_recorded(int64_t sr) { return position_recorded_[sr]; } const int position_recorded(int64_t sr) const { return position_recorded_[sr]; } int& external_source_present(int64_t sr) { return external_source_present_[sr]; } const int external_source_present(int64_t sr) const { return external_source_present_[sr]; } Position& position(int64_t sr) { return position_[sr]; } const Position position(int64_t sr) const { return position_[sr]; } Position& centroid(int64_t sr) { return centroid_[sr]; } const Position centroid(int64_t sr) const { return centroid_[sr]; } Position& centroid_iteration(int64_t sr) { return centroid_iteration_[sr]; } const Position centroid_iteration(int64_t sr) const { return centroid_iteration_[sr]; } Position& centroid_t(int64_t sr) { return centroid_t_[sr]; } const Position centroid_t(int64_t sr) const { return centroid_t_[sr]; } MomentMatrix& mom_matrix(int64_t sr) { return mom_matrix_[sr]; } const MomentMatrix mom_matrix(int64_t sr) const { return mom_matrix_[sr]; } MomentMatrix& mom_matrix_t(int64_t sr) { return mom_matrix_t_[sr]; } const MomentMatrix mom_matrix_t(int64_t sr) const { return mom_matrix_t_[sr]; } MomentArray& source_gradients(int64_t sr, int g) { return source_gradients_[index(sr, g)]; } const MomentArray source_gradients(int64_t sr, int g) const { return source_gradients_[index(sr, g)]; } MomentArray& source_gradients(int64_t se) { return source_gradients_[se]; } const MomentArray source_gradients(int64_t se) const { return source_gradients_[se]; } MomentArray& flux_moments_old(int64_t sr, int g) { return flux_moments_old_[index(sr, g)]; } const MomentArray flux_moments_old(int64_t sr, int g) const { return flux_moments_old_[index(sr, g)]; } MomentArray& flux_moments_old(int64_t se) { return flux_moments_old_[se]; } const MomentArray flux_moments_old(int64_t se) const { return flux_moments_old_[se]; } MomentArray& flux_moments_new(int64_t sr, int g) { return flux_moments_new_[index(sr, g)]; } const MomentArray flux_moments_new(int64_t sr, int g) const { return flux_moments_new_[index(sr, g)]; } MomentArray& flux_moments_new(int64_t se) { return flux_moments_new_[se]; } const MomentArray flux_moments_new(int64_t se) const { return flux_moments_new_[se]; } MomentArray& flux_moments_t(int64_t sr, int g) { return flux_moments_t_[index(sr, g)]; } const MomentArray flux_moments_t(int64_t sr, int g) const { return flux_moments_t_[index(sr, g)]; } MomentArray& flux_moments_t(int64_t se) { return flux_moments_t_[se]; } const MomentArray flux_moments_t(int64_t se) const { return flux_moments_t_[se]; } double& scalar_flux_old(int64_t sr, int g) { return scalar_flux_old_[index(sr, g)]; } const double scalar_flux_old(int64_t sr, int g) const { return scalar_flux_old_[index(sr, g)]; } double& scalar_flux_old(int64_t se) { return scalar_flux_old_[se]; } const double scalar_flux_old(int64_t se) const { return scalar_flux_old_[se]; } double& scalar_flux_new(int64_t sr, int g) { return scalar_flux_new_[index(sr, g)]; } const double scalar_flux_new(int64_t sr, int g) const { return scalar_flux_new_[index(sr, g)]; } double& scalar_flux_new(int64_t se) { return scalar_flux_new_[se]; } const double scalar_flux_new(int64_t se) const { return scalar_flux_new_[se]; } double& scalar_flux_final(int64_t sr, int g) { return scalar_flux_final_[index(sr, g)]; } const double scalar_flux_final(int64_t sr, int g) const { return scalar_flux_final_[index(sr, g)]; } double& scalar_flux_final(int64_t se) { return scalar_flux_final_[se]; } const double scalar_flux_final(int64_t se) const { return scalar_flux_final_[se]; } float& source(int64_t sr, int g) { return source_[index(sr, g)]; } const float source(int64_t sr, int g) const { return source_[index(sr, g)]; } float& source(int64_t se) { return source_[se]; } const float source(int64_t se) const { return source_[se]; } float& external_source(int64_t sr, int g) { return external_source_[index(sr, g)]; } const float external_source(int64_t sr, int g) const { return external_source_[index(sr, g)]; } float& external_source(int64_t se) { return external_source_[se]; } const float external_source(int64_t se) const { return external_source_[se]; } vector& tally_task(int64_t sr, int g) { return tally_task_[index(sr, g)]; } const vector& tally_task(int64_t sr, int g) const { return tally_task_[index(sr, g)]; } vector& tally_task(int64_t se) { return tally_task_[se]; } const vector& tally_task(int64_t se) const { return tally_task_[se]; } std::unordered_set& volume_task(int64_t sr) { return volume_task_[sr]; } const std::unordered_set& volume_task( int64_t sr) const { return volume_task_[sr]; } int& mesh(int64_t sr) { return mesh_[sr]; } const int mesh(int64_t sr) const { return mesh_[sr]; } int64_t& parent_sr(int64_t sr) { return parent_sr_[sr]; } const int64_t parent_sr(int64_t sr) const { return parent_sr_[sr]; } //---------------------------------------------------------------------------- // Public Methods void push_back(const SourceRegion& sr); void assign(int n_source_regions, const SourceRegion& source_region); void flux_swap(); int64_t n_source_regions() const { return n_source_regions_; } int64_t n_source_elements() const { return n_source_regions_ * negroups_; } int& negroups() { return negroups_; } const int negroups() const { return negroups_; } bool& is_linear() { return is_linear_; } const bool is_linear() const { return is_linear_; } SourceRegionHandle get_source_region_handle(int64_t sr); void adjoint_reset(); private: //---------------------------------------------------------------------------- // Private Data Members int64_t n_source_regions_ {0}; int negroups_ {0}; bool is_linear_ {false}; // SoA storage for scalar fields (one item per source region) vector material_; vector temperature_idx_; vector density_mult_; vector is_small_; vector n_hits_; vector mesh_; vector parent_sr_; vector lock_; vector volume_; vector volume_t_; vector volume_sq_; vector volume_sq_t_; vector volume_naive_; vector position_recorded_; vector external_source_present_; vector position_; vector centroid_; vector centroid_iteration_; vector centroid_t_; vector mom_matrix_; vector mom_matrix_t_; // A set of volume tally tasks. This more complicated data structure is // convenient for ensuring that volumes are only tallied once per source // region, regardless of how many energy groups are used for tallying. vector> volume_task_; // SoA energy group-wise 2D arrays flattened to 1D vector scalar_flux_old_; vector scalar_flux_new_; vector scalar_flux_final_; vector source_; vector external_source_; vector source_gradients_; vector flux_moments_old_; vector flux_moments_new_; vector flux_moments_t_; // SoA 3D array representing values for all source regions x energy groups x // tally tasks. The outer two dimensions (source regions and energy groups) // are flattened to 1D. Each group may have a different number of tally tasks // associated with it, necessitating the use of a jagged array for the inner // dimension. vector> tally_task_; //---------------------------------------------------------------------------- // Private Methods // Helper function for indexing inline int64_t index(int64_t sr, int g) const { return sr * negroups_ + g; } }; } // namespace openmc #endif // OPENMC_RANDOM_RAY_SOURCE_REGION_H