Random Ray Source Region Refactor (#3288)

This commit is contained in:
John Tramm 2025-02-11 11:23:26 -06:00 committed by GitHub
parent 27ce2ceee3
commit 04393200cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 832 additions and 460 deletions

View file

@ -36,13 +36,15 @@ inline int thread_num()
class OpenMPMutex {
public:
OpenMPMutex()
void init()
{
#ifdef _OPENMP
omp_init_lock(&mutex_);
#endif
}
OpenMPMutex() { init(); }
~OpenMPMutex()
{
#ifdef _OPENMP
@ -62,14 +64,10 @@ public:
// rather, it produces two different mutexes.
// Copy constructor
OpenMPMutex(const OpenMPMutex& other) { OpenMPMutex(); }
OpenMPMutex(const OpenMPMutex& other) { init(); }
// Copy assignment operator
OpenMPMutex& operator=(const OpenMPMutex& other)
{
OpenMPMutex();
return *this;
}
OpenMPMutex& operator=(const OpenMPMutex& other) { return *this; }
//! Lock the mutex.
//

View file

@ -4,83 +4,12 @@
#include "openmc/constants.h"
#include "openmc/openmp_interface.h"
#include "openmc/position.h"
#include "openmc/random_ray/source_region.h"
#include "openmc/source.h"
#include <unordered_set>
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
// 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;
int filter_idx;
int score_idx;
int score_type;
TallyTask(int tally_idx, int 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 FlatSourceDomain class encompasses data and methods for storing
* scalar flux and source region for all flat source regions in a
@ -108,15 +37,16 @@ public:
void random_ray_tally();
virtual void accumulate_iteration_flux();
void output_to_vtk() const;
virtual void all_reduce_replicated_source_regions();
void all_reduce_replicated_source_regions();
void convert_external_sources();
void count_external_source_regions();
void set_adjoint_sources(const vector<double>& forward_flux);
virtual void flux_swap();
void flux_swap();
virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const;
double compute_fixed_source_normalization_factor() const;
void flatten_xs();
void transpose_scattering_matrix();
void serialize_final_fluxes(vector<double>& flux);
//----------------------------------------------------------------------------
// Static Data members
@ -129,7 +59,6 @@ public:
//----------------------------------------------------------------------------
// Public Data members
bool mapped_all_tallies_ {false}; // If all source regions have been visited
int64_t n_source_regions_ {0}; // Total number of source regions in the model
@ -140,22 +69,6 @@ public:
// in model::cells
vector<int64_t> source_region_offsets_;
// 1D arrays representing values for all source regions
vector<OpenMPMutex> lock_;
vector<double> volume_;
vector<double> volume_t_;
vector<int> position_recorded_;
vector<Position> position_;
// 2D arrays stored in 1D representing values for all source regions x energy
// groups
vector<double> scalar_flux_old_;
vector<double> scalar_flux_new_;
vector<float> source_;
vector<float> external_source_;
vector<bool> external_source_present_;
vector<double> scalar_flux_final_;
// 2D arrays stored in 1D representing values for all materials x energy
// groups
int n_materials_;
@ -168,20 +81,22 @@ public:
// groups x energy groups
vector<double> sigma_s_;
// The abstract container holding all source region-specific data
SourceRegionContainer source_regions_;
protected:
//----------------------------------------------------------------------------
// Methods
void apply_external_source_to_source_region(
Discrete* discrete, double strength_factor, int64_t source_region);
Discrete* discrete, double strength_factor, int64_t sr);
void apply_external_source_to_cell_instances(int32_t i_cell,
Discrete* discrete, double strength_factor, int target_material_id,
const vector<int32_t>& instances);
void apply_external_source_to_cell_and_children(int32_t i_cell,
Discrete* discrete, double strength_factor, int32_t target_material_id);
virtual void set_flux_to_flux_plus_source(
int64_t idx, double volume, int material, int g);
void set_flux_to_source(int64_t idx);
virtual void set_flux_to_old_flux(int64_t idx);
virtual void set_flux_to_flux_plus_source(int64_t sr, double volume, int g);
void set_flux_to_source(int64_t sr, int g);
virtual void set_flux_to_old_flux(int64_t sr, int g);
//----------------------------------------------------------------------------
// Private data members
@ -193,20 +108,6 @@ protected:
simulation_volume_; // Total physical volume of the simulation domain, as
// defined by the 3D box of the random ray source
// 2D array representing values for all source elements x tally
// tasks
vector<vector<TallyTask>> tally_task_;
// 1D array representing values for all source regions, with each region
// containing 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<std::unordered_set<TallyTask, TallyTask::HashFunctor>> volume_task_;
// 1D arrays representing values for all source regions
vector<int> material_;
vector<double> volume_naive_;
// Volumes for each tally and bin/score combination. This intermediate data
// structure is used when tallying quantities that must be normalized by
// volume (i.e., flux). The vector is index by tally index, while the inner 2D
@ -250,15 +151,6 @@ T convert_to_big_endian(T in)
return out;
}
template<typename T>
void parallel_fill(vector<T>& arr, T value)
{
#pragma omp parallel for schedule(static)
for (int i = 0; i < arr.size(); i++) {
arr[i] = value;
}
}
} // namespace openmc
#endif // OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H

View file

@ -18,48 +18,22 @@ namespace openmc {
class LinearSourceDomain : public FlatSourceDomain {
public:
//----------------------------------------------------------------------------
// Constructors
LinearSourceDomain();
//----------------------------------------------------------------------------
// Methods
void update_neutron_source(double k_eff) override;
double compute_k_eff(double k_eff_old) const;
void normalize_scalar_flux_and_volumes(
double total_active_distance_per_iteration) override;
void batch_reset() override;
void convert_source_regions_to_tallies();
void reset_tally_volumes();
void random_ray_tally();
void accumulate_iteration_flux() override;
void output_to_vtk() const;
void all_reduce_replicated_source_regions() override;
void convert_external_sources();
void count_external_source_regions();
void flux_swap() override;
double evaluate_flux_at_point(Position r, int64_t sr, int g) const override;
//----------------------------------------------------------------------------
// Public Data members
vector<MomentArray> source_gradients_;
vector<MomentArray> flux_moments_old_;
vector<MomentArray> flux_moments_new_;
vector<MomentArray> flux_moments_t_;
vector<Position> centroid_;
vector<Position> centroid_iteration_;
vector<Position> centroid_t_;
vector<MomentMatrix> mom_matrix_;
vector<MomentMatrix> mom_matrix_t_;
protected:
//----------------------------------------------------------------------------
// Methods
void set_flux_to_flux_plus_source(
int64_t idx, double volume, int material, int g) override;
void set_flux_to_old_flux(int64_t idx) override;
void set_flux_to_flux_plus_source(int64_t sr, double volume, int g) override;
void set_flux_to_old_flux(int64_t sr, int g) override;
}; // class LinearSourceDomain

View file

@ -0,0 +1,400 @@
#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
// 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;
int filter_idx;
int score_idx;
int score_type;
TallyTask(int tally_idx, int 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;
}
};
};
class SourceRegion {
public:
//----------------------------------------------------------------------------
// Constructors
SourceRegion(int negroups, bool is_linear);
SourceRegion() = default;
//----------------------------------------------------------------------------
// Public Data members
// Scalar fields
int material_ {0};
OpenMPMutex lock_;
double volume_ {0.0};
double volume_t_ {0.0};
double volume_naive_ {0.0};
int position_recorded_ {0};
int external_source_present_ {0};
Position position_ {0.0, 0.0, 0.0};
Position centroid_ {0.0, 0.0, 0.0};
Position centroid_iteration_ {0.0, 0.0, 0.0};
Position centroid_t_ {0.0, 0.0, 0.0};
MomentMatrix mom_matrix_ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
MomentMatrix mom_matrix_t_ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
// 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<TallyTask, TallyTask::HashFunctor> volume_task_;
// Energy group-wise 1D arrays
vector<double> scalar_flux_old_;
vector<double> scalar_flux_new_;
vector<float> source_;
vector<float> external_source_;
vector<double> scalar_flux_final_;
vector<MomentArray> source_gradients_;
vector<MomentArray> flux_moments_old_;
vector<MomentArray> flux_moments_new_;
vector<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<vector<TallyTask>> 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]; }
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_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<TallyTask>& tally_task(int64_t sr, int g)
{
return tally_task_[index(sr, g)];
}
const vector<TallyTask>& tally_task(int64_t sr, int g) const
{
return tally_task_[index(sr, g)];
}
vector<TallyTask>& tally_task(int64_t se) { return tally_task_[se]; }
const vector<TallyTask>& tally_task(int64_t se) const
{
return tally_task_[se];
}
std::unordered_set<TallyTask, TallyTask::HashFunctor>& volume_task(int64_t sr)
{
return volume_task_[sr];
}
const std::unordered_set<TallyTask, TallyTask::HashFunctor>& volume_task(
int64_t sr) const
{
return volume_task_[sr];
}
//----------------------------------------------------------------------------
// Public Methods
void push_back(const SourceRegion& sr);
void assign(int n_source_regions, const SourceRegion& source_region);
void flux_swap();
void mpi_sync_ranks(bool reduce_position);
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<int> material_;
vector<OpenMPMutex> lock_;
vector<double> volume_;
vector<double> volume_t_;
vector<double> volume_naive_;
vector<int> position_recorded_;
vector<int> external_source_present_;
vector<Position> position_;
vector<Position> centroid_;
vector<Position> centroid_iteration_;
vector<Position> centroid_t_;
vector<MomentMatrix> mom_matrix_;
vector<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.
vector<std::unordered_set<TallyTask, TallyTask::HashFunctor>> volume_task_;
// SoA energy group-wise 2D arrays flattened to 1D
vector<double> scalar_flux_old_;
vector<double> scalar_flux_new_;
vector<double> scalar_flux_final_;
vector<float> source_;
vector<float> external_source_;
vector<MomentArray> source_gradients_;
vector<MomentArray> flux_moments_old_;
vector<MomentArray> flux_moments_new_;
vector<MomentArray> 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<vector<TallyTask>> tally_task_;
//----------------------------------------------------------------------------
// Private Methods
// Helper function for indexing
inline int index(int64_t sr, int g) const { return sr * negroups_ + g; }
};
} // namespace openmc
#endif // OPENMC_RANDOM_RAY_SOURCE_REGION_H