From 7c99c5d941f671c02c15f45b35a241645e677504 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Tue, 23 Jul 2024 14:57:52 -0500 Subject: [PATCH 01/27] update distribution_actual to the distribution.cpp and .h --- include/openmc/distribution.h | 3 +++ src/distribution.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/include/openmc/distribution.h b/include/openmc/distribution.h index e70c803de2f..797c3c18249 100644 --- a/include/openmc/distribution.h +++ b/include/openmc/distribution.h @@ -56,6 +56,7 @@ class DiscreteIndex { // Properties const vector& prob() const { return prob_; } const vector& alias() const { return alias_; } + const vector& prob_actual() const { return prob_actual_; } double integral() const { return integral_; } private: @@ -63,6 +64,7 @@ class DiscreteIndex { //!< mapped to alias method table vector alias_; //!< Alias table double integral_; //!< Integral of distribution + vector prob_actual_; //!< actual probability before the Vose algorithm //! Normalize distribution so that probabilities sum to unity void normalize(); @@ -91,6 +93,7 @@ class Discrete : public Distribution { const vector& x() const { return x_; } const vector& prob() const { return di_.prob(); } const vector& alias() const { return di_.alias(); } + const vector& prob_actual() const { return di_.prob_actual(); } private: vector x_; //!< Possible outcomes diff --git a/src/distribution.cpp b/src/distribution.cpp index 3026630b335..0d87fce801e 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -46,6 +46,9 @@ void DiscreteIndex::init_alias() { normalize(); + // record user input normalized distribution prob_actual for Random Ray + prob_actual_ = prob_; + // The initialization and sampling method is based on Vose // (DOI: 10.1109/32.92917) // Vectors for large and small probabilities based on 1/n From f9b2b77ea8b51828b3f1a7ccc8f73621e53e1021 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 14:32:50 -0500 Subject: [PATCH 02/27] update linear source FC 1 --- .../openmc/random_ray/flat_source_domain.h | 11 +- .../openmc/random_ray/linear_source_domain.h | 13 +- include/openmc/random_ray/random_ray.h | 9 +- .../openmc/random_ray/random_ray_simulation.h | 9 + include/openmc/settings.h | 7 + src/random_ray/flat_source_domain.cpp | 168 ++++++++++++++- src/random_ray/linear_source_domain.cpp | 161 +++++++++++++- src/random_ray/random_ray.cpp | 202 ++++++++++++++++-- src/random_ray/random_ray_simulation.cpp | 102 +++++++++ src/settings.cpp | 6 + 10 files changed, 654 insertions(+), 34 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 33c5661dcd4..9b70dfaa191 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -110,8 +110,12 @@ class FlatSourceDomain { void convert_external_sources(); void count_external_source_regions(); virtual void flux_swap(); - virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; + virtual double evaluate_flux_at_point(Position r, int64_t sr, int g, int ft) const; double compute_fixed_source_normalization_factor() const; + void compute_first_collided_flux(); + void normalize_uncollided_scalar_flux(double number_of_particles); + void update_volume_uncollided_flux(); + void reset_hit(); //---------------------------------------------------------------------------- // Static Data members @@ -125,6 +129,9 @@ class FlatSourceDomain { int64_t n_source_regions_ {0}; // Total number of source regions in the model int64_t n_external_source_regions_ {0}; // Total number of source regions with // non-zero external source terms + bool new_fsr_fc {true}; // Criteria to First Collided Loop + // Check if new cell was hit + int flux_type {0}; // for plotting purposes. // 1D array representing source region starting offset for each OpenMC Cell // in model::cells @@ -144,6 +151,8 @@ class FlatSourceDomain { vector scalar_flux_new_; vector source_; vector external_source_; + vector scalar_uncollided_flux_; + vector scalar_first_collided_flux_; protected: //---------------------------------------------------------------------------- diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index 5010ffddd6f..fccc1fbc944 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -39,15 +39,26 @@ class LinearSourceDomain : public FlatSourceDomain { 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; + double evaluate_flux_at_point(Position r, int64_t sr, int g, int ft) const override; + + void reset_hit(); + void compute_first_collided_flux(); + void normalize_uncollided_scalar_flux(double number_of_particles); //---------------------------------------------------------------------------- // Public Data members + vector source_gradients_; vector flux_moments_old_; vector flux_moments_new_; vector flux_moments_t_; + // First Collided Method + vector flux_moments_uncollided_; + vector flux_moments_first_collided_; + vector external_source_gradients_; + + vector centroid_; vector centroid_iteration_; vector centroid_t_; diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index 913a9af4a75..a40cee12cb8 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -28,10 +28,13 @@ class RandomRay : public Particle { void attenuate_flux(double distance, bool is_active); void attenuate_flux_flat_source(double distance, bool is_active); void attenuate_flux_linear_source(double distance, bool is_active); + void event_advance_ray_first_collided(); + void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain); uint64_t transport_history_based_single_ray(); - + uint64_t transport_history_based_single_ray_first_collided(); + //---------------------------------------------------------------------------- // Static data members static double distance_inactive_; // Inactive (dead zone) ray length @@ -42,6 +45,7 @@ class RandomRay : public Particle { //---------------------------------------------------------------------------- // Public data members vector angular_flux_; + vector angular_flux_initial_; private: //---------------------------------------------------------------------------- @@ -50,6 +54,9 @@ class RandomRay : public Particle { vector delta_moments_; int negroups_; + float ray_threshold {1e-20f}; + + FlatSourceDomain* domain_ {nullptr}; // pointer to domain that has flat source // data needed for ray transport double distance_travelled_ {0}; diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index c1d47821d7a..9c7d3ef06e2 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -30,6 +30,15 @@ class RandomRaySimulation { //---------------------------------------------------------------------------- // Data members + // First collided method variables for automatic n_uncollided_rays + int64_t n_u_hits {0}; + int new_n_rays {settings::n_uncollided_rays}; + int old_n_rays {0}; + double fsr_ratio {0.0}; + int batch_first_collided {1}; + int n_rays_max {1000000}; + bool user_input_rays {false}; + private: // Contains all flat source region data unique_ptr domain_; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index a95f1ced9f1..cc96ad741f1 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -154,6 +154,13 @@ extern "C" int verbosity; //!< How verbose to make output extern double weight_cutoff; //!< Weight cutoff for Russian roulette extern double weight_survive; //!< Survival weight after Russian roulette +// HARDCODED INPUTS - First Collided Flux +extern bool FIRST_COLLIDED_FLUX; //!< First Collided Mode loop +extern bool uncollided_flux_volume; //!< Initial volume estimation loop +extern int n_uncollided_rays; //!< Number of uncollided rays used +extern int n_volume_estimator_rays; //!< Number of rays to estimate volume +extern bool first_collided_mode; //!< Add first collided source in RR + } // namespace settings //============================================================================== diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 8b6cda93f2a..10916cd4d13 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -54,6 +54,8 @@ FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) // Initialize element-wise arrays scalar_flux_new_.assign(n_source_elements_, 0.0); scalar_flux_final_.assign(n_source_elements_, 0.0); + scalar_uncollided_flux_.assign(n_source_elements_,0.0); + scalar_first_collided_flux_.assign(n_source_elements_,0.0); source_.resize(n_source_elements_); external_source_.assign(n_source_elements_, 0.0); tally_task_.resize(n_source_elements_); @@ -114,6 +116,11 @@ void FlatSourceDomain::batch_reset() parallel_fill(was_hit_, 0); } +void FlatSourceDomain::reset_hit() +{ + parallel_fill(was_hit_,0); +} + void FlatSourceDomain::accumulate_iteration_flux() { #pragma omp parallel for @@ -136,6 +143,24 @@ void FlatSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; + // multiply First Collided Flux by volume and attribute it as fixed source + if (settings::first_collided_mode){ +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + double volume = simulation_volume_ * volume_[sr]; + int material = material_[sr]; + if (volume == 0.0f){ + for (int g = 0; g < negroups_; g++) { + external_source_[sr * negroups_ + g] = 0.0f; + } + } else { + for (int g = 0; g < negroups_; g++) { + external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(volume)); + } + } + } + } + // Add scattering source #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { @@ -201,6 +226,7 @@ void FlatSourceDomain::normalize_scalar_flux_and_volumes( 1.0 / (total_active_distance_per_iteration * simulation::current_batch); // Normalize scalar flux to total distance travelled by all rays this iteration +if (!settings::FIRST_COLLIDED_FLUX){ #pragma omp parallel for for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { scalar_flux_new_[e] *= normalization_factor; @@ -215,6 +241,16 @@ void FlatSourceDomain::normalize_scalar_flux_and_volumes( } } + if (settings::FIRST_COLLIDED_FLUX){ +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_[sr] *= (volume_normalization_factor); + } + } +} + + + // Combine transport flux contributions and flat source contributions from the // previous iteration to generate this iteration's estimate of scalar flux. int64_t FlatSourceDomain::add_source_to_scalar_flux() @@ -250,18 +286,30 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux() // transport sweep) float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]/ (sigma_t); /// (sigma_t * volume); + } else { scalar_flux_new_[idx] /= (sigma_t * volume); scalar_flux_new_[idx] += source_[idx]; + } } else if (volume > 0.0) { // 2. If the FSR was not hit this iteration, but has been hit some // previous iteration, then we simply set the new scalar flux to be // equal to the contribution from the flat source alone. + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = 0.0f; + } else { scalar_flux_new_[idx] = source_[idx]; + } } else { // If the FSR was not hit this iteration, and it has never been hit in // any iteration (i.e., volume is zero), then we want to set this to 0 // to avoid dividing anything by a zero volume. + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = 0.0f; + } else { scalar_flux_new_[idx] = 0.0f; + } } } } @@ -270,6 +318,53 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux() return n_hits; } +// Normalize Uncollided Flux +void FlatSourceDomain::normalize_uncollided_scalar_flux(double number_of_particles) +{ + // multiply by simulation volume + float normalization_factor = (1.0)/ number_of_particles; + // Determine Source_total Scailing factor if first collided + + double user_external_source_strength = 0.0; + for (auto& ext_source : model::external_sources) { + user_external_source_strength += ext_source->strength(); + } + //fmt::print("total_source_strength = {}\n", total_source_intensity); + +#pragma omp parallel for +for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { + scalar_uncollided_flux_[e] *= ((user_external_source_strength) * normalization_factor) ; + } +} + +//Compute First Collided flux +void FlatSourceDomain::compute_first_collided_flux() +{ + const int t = 0; + const int a = 0; + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + int material = material_[sr]; + + for (int e_out = 0; e_out < negroups_; e_out++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); + float scatter_fixed_source = 0.0f; + + for (int e_in = 0; e_in < negroups_; e_in++) { + float scalar_flux = scalar_uncollided_flux_[sr * negroups_ + e_in]; + + float sigma_s = data::mg.macro_xs_[material].get_xs( + MgxsType::SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + scatter_fixed_source += sigma_s * scalar_flux; + } + + scalar_first_collided_flux_[sr * negroups_ + e_out] = scatter_fixed_source / sigma_t; + } + } +} + // Generates new estimate of k_eff based on the differences between this // iteration's estimate of the scalar flux and the last iteration's estimate. double FlatSourceDomain::compute_k_eff(double k_eff_old) const @@ -377,6 +472,17 @@ double FlatSourceDomain::compute_k_eff(double k_eff_old) const // be passed back to the caller to alert them that this function doesn't // need to be called for the remainder of the simulation. +void FlatSourceDomain::update_volume_uncollided_flux() +{ + #pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + double volume = volume_[sr] * simulation_volume_; + for (int g = 0; g < negroups_; g++) { + scalar_uncollided_flux_[sr * negroups_ + g] /= volume; + } + } +} + void FlatSourceDomain::convert_source_regions_to_tallies() { openmc::simulation::time_tallies.start(); @@ -566,12 +672,16 @@ void FlatSourceDomain::random_ray_tally() // solves, but useful in fixed source solves for returning the flux shape // with a magnitude that makes sense relative to the fixed source strength. double volume = volume_[sr] * simulation_volume_; - double material = material_[sr]; + float flux = 0.0f; + for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; - double flux = scalar_flux_new_[idx] * source_normalization_factor; - + if (settings::first_collided_mode){ + flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); + } else { + flux = (scalar_flux_new_[idx] * source_normalization_factor) ; + } // Determine numerical score value for (auto& task : tally_task_[idx]) { double score; @@ -752,10 +862,20 @@ void FlatSourceDomain::all_reduce_replicated_source_regions() } double FlatSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g) const + Position r, int64_t sr, int g, int ft) const { - return scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive); + if (ft == 0){ // RR scalar neutron flux + return (scalar_flux_final_[sr * negroups_ + g] / + (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); + } else if (ft == 1){ // Uncollided neutron flux +return scalar_uncollided_flux_[sr * negroups_ + g]; + } else if (ft == 2){ // external source +return external_source_[sr * negroups_ + g]; + } else { + // ??? add error message. + return 0; + } + } // Outputs all basic material, FSR ID, multigroup flux, and @@ -863,7 +983,7 @@ void FlatSourceDomain::output_to_vtk() const for (int i = 0; i < Nx * Ny * Nz; i++) { int64_t fsr = voxel_indices[i]; int64_t source_element = fsr * negroups_ + g; - float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); + float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 0); flux = convert_to_big_endian(flux); std::fwrite(&flux, sizeof(float), 1, plot); } @@ -897,7 +1017,7 @@ void FlatSourceDomain::output_to_vtk() const int mat = material_[fsr]; for (int g = 0; g < negroups_; g++) { int64_t source_element = fsr * negroups_ + g; - float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); + float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 0); float Sigma_f = data::mg.macro_xs_[mat].get_xs( MgxsType::FISSION, g, nullptr, nullptr, nullptr, 0, 0); total_fission += Sigma_f * flux; @@ -906,6 +1026,35 @@ void FlatSourceDomain::output_to_vtk() const std::fwrite(&total_fission, sizeof(float), 1, plot); } + // Plot fixed source + for (int g = 0; g < negroups_; g++) { + std::fprintf(plot, "SCALARS fixed_source_group_%d float\n", g); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int i = 0; i < Nx * Ny * Nz; i++) { + int64_t fsr = voxel_indices[i]; + int mat = material_[fsr]; + float sigma_t = data::mg.macro_xs_[mat].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, 0, 0); + float f_source = evaluate_flux_at_point(voxel_positions[i], fsr, g, 2); + f_source *= sigma_t; + f_source = convert_to_big_endian(f_source); + std::fwrite(&f_source, sizeof(float), 1, plot); + } + } + + // Plot multigroup uncollided flux data + for (int g = 0; g < negroups_; g++) { + std::fprintf(plot, "SCALARS Uncollided_flux_group_%d float\n", g); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int i = 0; i < Nx * Ny * Nz; i++) { + int64_t fsr = voxel_indices[i]; + int64_t source_element = fsr * negroups_ + g; + float uncollided_flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 1); + uncollided_flux = convert_to_big_endian(uncollided_flux); + std::fwrite(&uncollided_flux, sizeof(float), 1, plot); + } + } + std::fclose(plot); } } @@ -974,6 +1123,9 @@ void FlatSourceDomain::count_external_source_regions() for (int e = 0; e < negroups_; e++) { int64_t se = sr * negroups_ + e; total += external_source_[se]; + if (settings::FIRST_COLLIDED_FLUX){ + total += scalar_first_collided_flux_[se]; + } } if (total != 0.f) { n_external_source_regions_++; diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 1603ec24a4e..c64bd3416a7 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -28,6 +28,10 @@ LinearSourceDomain::LinearSourceDomain() : FlatSourceDomain() flux_moments_t_.assign(n_source_elements_, {0.0, 0.0, 0.0}); // Source gradients given by M inverse multiplied by source moments source_gradients_.assign(n_source_elements_, {0.0, 0.0, 0.0}); + external_source_gradients_.assign(n_source_elements_, {0.0, 0.0, 0.0}); + // First Collided method + flux_moments_uncollided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); + flux_moments_first_collided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); centroid_.assign(n_source_regions_, {0.0, 0.0, 0.0}); centroid_iteration_.assign(n_source_regions_, {0.0, 0.0, 0.0}); @@ -50,6 +54,11 @@ void LinearSourceDomain::batch_reset() } } +void LinearSourceDomain::reset_hit() +{ + parallel_fill(was_hit_,0); +} + void LinearSourceDomain::update_neutron_source(double k_eff) { simulation::time_update_src.start(); @@ -63,12 +72,31 @@ void LinearSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; + + #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int material = material_[sr]; MomentMatrix invM = mom_matrix_[sr].inverse(); + // multiply First Collided Flux by volume and attribute it as external_source + // FIX THIS - CHECK MATH ??? + if (settings::first_collided_mode){ + double volume = simulation_volume_ * volume_[sr]; + for (int g = 0; g < negroups_; g++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + if (volume == 0.0f){ + external_source_[sr * negroups_ + g] = 0.0f; + external_source_gradients_[sr * negroups_ + g] = {0.0, 0.0, 0.0}; + } else { + external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(sigma_t * volume)); + external_source_gradients_[sr * negroups_ + g] = (flux_moments_first_collided_[sr * negroups_ + g] /(sigma_t * volume)); + } + } + } + for (int e_out = 0; e_out < negroups_; e_out++) { float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); @@ -115,6 +143,7 @@ void LinearSourceDomain::update_neutron_source(double k_eff) #pragma omp parallel for for (int se = 0; se < n_source_elements_; se++) { source_[se] += external_source_[se]; + source_gradients_[se] += external_source_gradients_[se]; // ??? } } @@ -129,6 +158,7 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( 1.0 / (total_active_distance_per_iteration * simulation::current_batch); // Normalize flux to total distance travelled by all rays this iteration +if (!settings::FIRST_COLLIDED_FLUX){ #pragma omp parallel for for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { scalar_flux_new_[e] *= normalization_factor; @@ -153,6 +183,25 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( } } +// ??? CHECK if need to clear _t_ terms +if (settings::FIRST_COLLIDED_FLUX){ +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + mom_matrix_t_[sr] += mom_matrix_[sr]; + volume_t_[sr] += volume_[sr]; + volume_[sr] *= volume_normalization_factor; + if (volume_t_[sr] > 0.0) { + double inv_volume = 1.0 / volume_t_[sr]; + centroid_[sr] = centroid_t_[sr]; + centroid_[sr] *= inv_volume; + mom_matrix_[sr] = mom_matrix_t_[sr]; + mom_matrix_[sr] *= inv_volume; + } + } +} + +} + int64_t LinearSourceDomain::add_source_to_scalar_flux() { int64_t n_hits = 0; @@ -184,20 +233,37 @@ int64_t LinearSourceDomain::add_source_to_scalar_flux() // the flat source from the previous iteration plus the contributions // from rays passing through the source region (computed during the // transport sweep) + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]; /// (sigma_t * volume); + flux_moments_uncollided_[idx] = flux_moments_new_[idx]; + // Add flux_moments_uncollided ??? + } else { scalar_flux_new_[idx] /= volume; scalar_flux_new_[idx] += source_[idx]; flux_moments_new_[idx] *= (1.0 / volume); + } } else if (volume > 0.0) { // 2. If the FSR was not hit this iteration, but has been hit some // previous iteration, then we simply set the new scalar flux to be // equal to the contribution from the flat source alone. + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = 0.0f; + flux_moments_uncollided_[idx] *= 0.0; + } else { scalar_flux_new_[idx] = source_[idx]; + // ??? flux_moments_new_[idx] = ???? + } } else { // If the FSR was not hit this iteration, and it has never been hit in // any iteration (i.e., volume is zero), then we want to set this to 0 // to avoid dividing anything by a zero volume. + if (settings::FIRST_COLLIDED_FLUX){ + scalar_uncollided_flux_[idx] = 0.0f; + flux_moments_uncollided_[idx] *= 0.0; + } else { scalar_flux_new_[idx] = 0.0f; flux_moments_new_[idx] *= 0.0; + } } } } @@ -205,6 +271,70 @@ int64_t LinearSourceDomain::add_source_to_scalar_flux() return n_hits; } +// Normalize Uncollided Flux +void LinearSourceDomain::normalize_uncollided_scalar_flux(double number_of_particles) +{ + // multiply by simulation volume + float normalization_factor = (1.0)/ number_of_particles; + // Determine Source_total Scailing factor if first collided + + double user_external_source_strength = 0.0; + for (auto& ext_source : model::external_sources) { + user_external_source_strength += ext_source->strength(); + } + //fmt::print("total_source_strength = {}\n", total_source_intensity); + +#pragma omp parallel for +for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { + scalar_uncollided_flux_[e] *= ((user_external_source_strength) * normalization_factor); + flux_moments_uncollided_[e] *= ((user_external_source_strength) * normalization_factor); + } +} + +//Compute First Collided flux +void LinearSourceDomain::compute_first_collided_flux() +{ + const int t = 0; + const int a = 0; + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + + int material = material_[sr]; + MomentMatrix invM = mom_matrix_[sr].inverse(); + + for (int e_out = 0; e_out < negroups_; e_out++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); + + float scatter_flat = 0.0f; + MomentArray scatter_linear = {0.0, 0.0, 0.0}; + + for (int e_in = 0; e_in < negroups_; e_in++) { + // Handles for the flat and linear components of the flux + float flux_flat = scalar_uncollided_flux_[sr * negroups_ + e_in]; + MomentArray flux_linear = flux_moments_uncollided_[sr * negroups_ + e_in]; + + // Handles for cross sections + float sigma_s = data::mg.macro_xs_[material].get_xs( + MgxsType::SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + + // Compute source terms for flat and linear components of the flux + scatter_flat += sigma_s * flux_flat; + scatter_linear += sigma_s * flux_linear; + } + + // Compute the flat source term + scalar_first_collided_flux_[sr * negroups_ + e_out] = + (scatter_flat) / sigma_t; + + // Compute the linear source terms + flux_moments_first_collided_[sr * negroups_ + e_out] = + invM * ((scatter_linear) / sigma_t); + } + } +} + void LinearSourceDomain::flux_swap() { FlatSourceDomain::flux_swap(); @@ -252,18 +382,45 @@ void LinearSourceDomain::all_reduce_replicated_source_regions() } double LinearSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g) const + Position r, int64_t sr, int g, int ft) const { - float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g); + if (flux_type == 0){ // RR neutron flux + float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); Position local_r = r - centroid_[sr]; MomentArray phi_linear = flux_moments_t_[sr * negroups_ + g]; phi_linear *= 1.0 / (settings::n_batches - settings::n_inactive); + phi_linear += flux_moments_uncollided_[sr * negroups_ + g]; // ??? addition MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; return phi_flat + phi_solved.dot(local_r); + } else if (ft == 1){// Uncollided neutron flux + float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); + + Position local_r = r - centroid_[sr]; + MomentArray phi_linear = flux_moments_uncollided_[sr * negroups_ + g]; + + MomentMatrix invM = mom_matrix_[sr].inverse(); + MomentArray phi_solved = invM * phi_linear; + + return phi_flat + phi_solved.dot(local_r); + } else if (ft == 2){ // External Source + float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); + + Position local_r = r - centroid_[sr]; + MomentArray phi_linear = external_source_gradients_[sr * negroups_ + g]; + + MomentMatrix invM = mom_matrix_[sr].inverse(); + MomentArray phi_solved = invM * phi_linear; + + return phi_flat + phi_solved.dot(local_r); + } else { + // ??? add error message. + } } +// CHANGE EVALUATE_FLUX_AT_POINT FOR EXTERNAL SOURCE AND UNCOLLIDED FLUX + } // namespace openmc diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index a5bf6ec1060..e4b0211f485 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -187,7 +187,8 @@ RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), delta_psi_(data::mg.num_energy_groups_), - negroups_(data::mg.num_energy_groups_) + negroups_(data::mg.num_energy_groups_), + angular_flux_initial_(data::mg.num_energy_groups_) { if (source_shape_ == RandomRaySourceShape::LINEAR || source_shape_ == RandomRaySourceShape::LINEAR_XY) { @@ -214,6 +215,19 @@ uint64_t RandomRay::transport_history_based_single_ray() return n_event(); } +// Transports uncollided ray until termination criteria are met +uint64_t RandomRay::transport_history_based_single_ray_first_collided() +{ + using namespace openmc; + while (alive()) { + event_advance_ray_first_collided(); + if (!alive()) + break; + event_cross_surface(); + } + return n_event(); +} + // Transports ray across a single source region void RandomRay::event_advance_ray() { @@ -272,6 +286,31 @@ void RandomRay::event_advance_ray() } } +// Transports uncollided ray across a single region. +void RandomRay::event_advance_ray_first_collided() +{ + // Find the distance to the nearest boundary + boundary() = distance_to_boundary(*this); + double distance = boundary().distance; + + if (distance <= 0.0) { + mark_as_lost("Negative transport distance detected for particle " + + std::to_string(id())); + return; + } + // For Uncollided/First Collided Flux, it is calculated the attenuation + // as the ray advance through the region and a check if the outcoming + // flux reaches the defined threshold. + distance_travelled_ += distance; + attenuate_flux(distance, true); + + // Advance particle + for (int j = 0; j < n_coord(); ++j) { + coord(j).r += distance * coord(j).u; + } + //total_distance_track_ = distance_travelled_; +} + void RandomRay::attenuate_flux(double distance, bool is_active) { switch (source_shape_) { @@ -324,6 +363,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) const int a = 0; // MOC incoming flux attenuation + source contribution/attenuation equation + if (!settings::uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); @@ -334,6 +374,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) delta_psi_[g] = new_delta_psi; angular_flux_[g] -= new_delta_psi; } + } // If ray is in the active phase (not in dead zone), make contributions to // source region bookkeeping @@ -344,19 +385,25 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Accumulate delta psi into new estimate of source region flux for // this iteration - for (int g = 0; g < negroups_; g++) { - domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + if (!settings::uncollided_flux_volume){ + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + } } // If the source region hasn't been hit yet this iteration, // indicate that it now has if (domain_->was_hit_[source_region] == 0) { domain_->was_hit_[source_region] = 1; + // Check if new cell was hit and change for true + domain_->new_fsr_fc = {true}; } // Accomulate volume (ray distance) into this iteration's estimate // of the source region's volume - domain_->volume_[source_region] += distance; + if (!settings::FIRST_COLLIDED_FLUX || settings::uncollided_flux_volume){ + domain_->volume_[source_region] += distance; + } // Tally valid position inside the source region (e.g., midpoint of // the ray) if not done already @@ -368,6 +415,35 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Release lock domain_->lock_[source_region].unlock(); + + // check attenuation in FIRST_ COLLIDED_FLUX + if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + // bool = true to kill ray + // ray is killed by default unless: + bool angular_flux_below_threshold = true; + for (int g = 0; g < negroups_; g++) { + // check if initial angular flux in that energy group is zero, therefore there is no ratio + // kill contidion given in absolute value (smaller than ray_threshold) + if (angular_flux_initial_[g] == 0) { + // If initial angular flux is zero and below threshold, passes as true to kill the ray + if(angular_flux_[g] >= ray_threshold){ + angular_flux_below_threshold = false; + break; + } + // if angular_flux_[g] is less than threshold, it passes as true to kill ray + } else { + // calculate the attenuation of ray (kills if ratio below threshold) + float ratio = angular_flux_[g] / angular_flux_initial_[g]; + if (ratio >= ray_threshold) { + angular_flux_below_threshold = false; + break; + } + } + } + if (angular_flux_below_threshold){ + wgt() = 0.0; + } + } } } @@ -401,9 +477,11 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) const int t = 0; const int a = 0; + Position& centroid = domain->centroid_[source_region]; Position midpoint = r() + u() * (distance / 2.0); + // Determine the local position of the midpoint and the ray origin // relative to the source region's centroid Position rm_local; @@ -425,6 +503,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Linear Source MOC incoming flux attenuation + source // contribution/attenuation equation + if (!settings::uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { // Compute tau, the optical thickness of the ray segment @@ -476,6 +555,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) delta_moments_[g].z = 0.0; } } + } // If ray is in the active phase (not in dead zone), make contributions to // source region bookkeeping @@ -491,24 +571,33 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Accumulate deltas into the new estimate of source region flux for this // iteration - for (int g = 0; g < negroups_; g++) { - domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; - domain->flux_moments_new_[source_element + g] += delta_moments_[g]; + if (!settings::uncollided_flux_volume){ + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + domain->flux_moments_new_[source_element + g] += delta_moments_[g]; + } } // Accumulate the volume (ray segment distance), centroid, and spatial // momement estimates into the running totals for the iteration for this // source region. The centroid and spatial momements estimates are scaled by // the ray segment length as part of length averaging of the estimates. - domain_->volume_[source_region] += distance; - domain->centroid_iteration_[source_region] += midpoint * distance; - moment_matrix_estimate *= distance; - domain->mom_matrix_[source_region] += moment_matrix_estimate; + if (!settings::FIRST_COLLIDED_FLUX || settings::uncollided_flux_volume){ + domain_->volume_[source_region] += distance; + domain->centroid_iteration_[source_region] += midpoint * distance; + // how to compute these ones + moment_matrix_estimate *= distance; + domain->mom_matrix_[source_region] += moment_matrix_estimate; + } + + // If the source region hasn't been hit yet this iteration, // indicate that it now has if (domain_->was_hit_[source_region] == 0) { domain_->was_hit_[source_region] = 1; + // Check if new cell was hit and change for true + domain_->new_fsr_fc = {true}; } // Tally valid position inside the source region (e.g., midpoint of @@ -520,9 +609,39 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Release lock domain_->lock_[source_region].unlock(); + + // check attenuation in FIRST_ COLLIDED_FLUX + if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + // bool = true to kill ray + // ray is killed by default unless: + bool angular_flux_below_threshold = true; + for (int g = 0; g < negroups_; g++) { + // check if initial angular flux in that energy group is zero, therefore there is no ratio + // kill contidion given in absolute value (smaller than ray_threshold) + if (angular_flux_initial_[g] == 0) { + // If initial angular flux is zero and below threshold, passes as true to kill the ray + if(angular_flux_[g] >= ray_threshold){ + angular_flux_below_threshold = false; + break; + } + // if angular_flux_[g] is less than threshold, it passes as true to kill ray + } else { + // calculate the attenuation of ray (kills if ratio below threshold) + float ratio = angular_flux_[g] / angular_flux_initial_[g]; + if (ratio >= ray_threshold) { + angular_flux_below_threshold = false; + break; + } + } + } + if (angular_flux_below_threshold){ + wgt() = 0.0; + } + } } } +//updated void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) { domain_ = domain; @@ -537,18 +656,54 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) // set identifier for particle id() = simulation::work_index[mpi::rank] + ray_id; + if (settings::FIRST_COLLIDED_FLUX){ + simulation::current_batch = 1; + } + // set random number seed int64_t particle_seed = (simulation::current_batch - 1) * settings::n_particles + id(); init_particle_seeds(particle_seed, seeds()); stream() = STREAM_TRACKING; - // Sample from ray source distribution - SourceSite site {ray_source_->sample(current_seed())}; - site.E = lower_bound_index( + // Sample from input Source + if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + auto site = sample_external_source(current_seed()); + site.E = lower_bound_index( + data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); + site.E = negroups_ - site.E - 1.; + //this->from_source(&site); + this->from_source(&site); + + std::unique_ptr& source_handle = model::external_sources[site.source_id]; + //Source* s = model::external_sources[site.source_id].get(); + // Check for independent source + IndependentSource* is = dynamic_cast(source_handle.get()); + //Distribution* energy_dist = is->energy(); + //Discrete* disc = dynamic_cast(energy_dist); + Discrete* energy_external_source = dynamic_cast(is->energy()); + + const auto& discrete_energies = energy_external_source->x(); + const auto& discrete_probs = energy_external_source->prob_actual(); + //for (const auto& prob : discrete_probs) { + // fmt::print("{:.3f}\n", prob); + //} + //double source_strength = is->strength(); + + for (int e = 0; e < discrete_energies.size(); e++) { + int g = data::mg.get_group_index(discrete_energies[e]); + angular_flux_[g] = discrete_probs[e];//source_strength * / sigma_t; + angular_flux_initial_[g] = angular_flux_[g]; + } + + } else { + // Sample from ray source distribution + SourceSite site {ray_source_->sample(current_seed())}; + site.E = lower_bound_index( data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); - site.E = negroups_ - site.E - 1.; - this->from_source(&site); + site.E = negroups_ - site.E - 1.; + this->from_source(&site); + } // Locate ray if (lowest_coord().cell == C_NONE) { @@ -562,15 +717,20 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) cell_born() = lowest_coord().cell; } - // Initialize ray's starting angular flux to starting location's isotropic - // source - int i_cell = lowest_coord().cell; - int64_t source_region_idx = + // initialize ray's starting angular flux spectrum + if(!settings::FIRST_COLLIDED_FLUX){ + // Initialize ray's starting angular flux to starting location's isotropic + // source + int i_cell = lowest_coord().cell; + int64_t source_region_idx = domain_->source_region_offsets_[i_cell] + cell_instance(); - for (int g = 0; g < negroups_; g++) { + for (int g = 0; g < negroups_; g++) { angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + } } } + + } // namespace openmc diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 4bc77645bcd..50e492f58f8 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -259,9 +259,111 @@ RandomRaySimulation::RandomRaySimulation() void RandomRaySimulation::simulate() { if (settings::run_mode == RunMode::FIXED_SOURCE) { + if (settings::FIRST_COLLIDED_FLUX == false){ // Transfer external source user inputs onto random ray source regions domain_->convert_external_sources(); domain_->count_external_source_regions(); + } else { + // FIRST_COLLIDED_FLUX calculation routine: + fmt::print("==============> FIRST COLLIDED SOURCE CONVERSION <=================\n\n"); + + //============================================================================== + // Turn on volume pre calculation + double start_volume_estimation = omp_get_wtime(); + fmt::print("Computing starting volume estimates... \n"); + settings::uncollided_flux_volume = {true}; + + // Pre calculate volume +#pragma omp parallel for schedule(dynamic) \ + reduction(+ : total_geometric_intersections_) + for (int i =0; i< settings::n_volume_estimator_rays; i++){ + RandomRay ray(i, domain_.get()); + total_geometric_intersections_ += + ray.transport_history_based_single_ray(); + } + + // Normalizing the scalar_new_flux and volumes + domain_->normalize_scalar_flux_and_volumes(settings::n_volume_estimator_rays * RandomRay::distance_active_); + + // Print volume estimation simulation time + double end_volume_estimation = omp_get_wtime(); + fmt::print("Volume estimation completed.\n"); + fmt::print("Run time = {:.4f} \n\n", end_volume_estimation-start_volume_estimation); + + // Reset parameters for First Collided Method + settings::uncollided_flux_volume = {false}; + domain_->reset_hit(); + //============================================================================== + // First Collided Transport Loop + // It will operate until (1-3): + // (1) There is no new FSR hits from one (n-1) iteration to the next (n) + // (2) Reached pre-set maximum n_uncollided_rays + // (3) Hit 100% of the FSRs + fmt::print(" Batch Rays Total Source Regions Discovered\n" + " ====== ========== ================================\n"); + + // SET-UP for user input n_uncollided_rays + if (user_input_rays == true){ + new_n_rays = n_rays_max; + } + + while(domain_->new_fsr_fc){ + + // loop will end if no new cell was hit + domain_->new_fsr_fc = {false}; + // Transport sweep over all random rays for the iteration +#pragma omp parallel for schedule(dynamic) \ + reduction(+ : total_geometric_intersections_) + for (int i = old_n_rays; i< new_n_rays; i++){ + RandomRay ray(i, domain_.get()); + total_geometric_intersections_ += + ray.transport_history_based_single_ray_first_collided(); + } + + // add scalar_new_flux calculations + int64_t n_hits = domain_->add_source_to_scalar_flux(); + + // Normalize scalar_uncollided_flux + domain_->normalize_uncollided_scalar_flux(new_n_rays); + + // compute first_collided_fixed_source + domain_->compute_first_collided_flux(); + + // save number of hit FSR + n_u_hits = n_hits; + fsr_ratio = static_cast(n_u_hits) / domain_->n_source_regions_; + + // print results + fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_u_hits); + + // BREAK STATEMENT if Max rays reached or 100% FSR HIT + old_n_rays = new_n_rays; + if (new_n_rays >= n_rays_max) { + //Uncollided rays limit achieved + break; + } else if (fsr_ratio == 1.0){ + //All FSRs hit; + break; + } + + //update for next batch + new_n_rays *= 2; + batch_first_collided++; + } + + // Count fixed source regions + domain_->count_external_source_regions(); + + // reset values for RandomRay iteration + settings::first_collided_mode = {true}; //keep that for adding uncollided flux at the end + settings::FIRST_COLLIDED_FLUX = {false}; //move to regular fixed source RR + simulation::current_batch = 0; //garantee the first batch will be 1 in RR + + // compute First Collided Method simulation time + double first_collided_estimated_time = omp_get_wtime(); + fmt::print(" ====== ========== ================================\n\n"); + fmt::print("First Collided Method run time = {:.4f} \n\n", first_collided_estimated_time-end_volume_estimation); + } } // Random ray power iteration loop diff --git a/src/settings.cpp b/src/settings.cpp index db956abf5ca..2efd83e3405 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -133,6 +133,12 @@ int trigger_batch_interval {1}; int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; +// HARDCODED INPUTS - First Collided Flux +bool FIRST_COLLIDED_FLUX {true}; +int n_uncollided_rays {10000}; +int n_volume_estimator_rays {10000}; +bool first_collided_mode {false}; +bool uncollided_flux_volume {false}; } // namespace settings From 944218cadc0a9f0c9298bb981ae1e10ffbebb904 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 15:26:25 -0500 Subject: [PATCH 03/27] source_id re-added (check) --- include/openmc/particle_data.h | 1 + openmc/lib/core.py | 3 ++- src/initialize.cpp | 7 ++++--- src/random_ray/random_ray.cpp | 7 +------ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/openmc/particle_data.h b/include/openmc/particle_data.h index 164148cce10..78cb6047cb2 100644 --- a/include/openmc/particle_data.h +++ b/include/openmc/particle_data.h @@ -51,6 +51,7 @@ struct SourceSite { ParticleType particle; int64_t parent_id; int64_t progeny_id; + int source_id; }; //! State of a particle used for particle track files diff --git a/openmc/lib/core.py b/openmc/lib/core.py index a9a549fa05a..cfd3fdd8a58 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -26,7 +26,8 @@ class _SourceSite(Structure): ('surf_id', c_int), ('particle', c_int), ('parent_id', c_int64), - ('progeny_id', c_int64)] + ('progeny_id', c_int64), + ('source_id', c_int)] # Define input type for numpy arrays that will be passed into C++ functions diff --git a/src/initialize.cpp b/src/initialize.cpp index cc1eac9cf35..8c263619ab7 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -166,14 +166,15 @@ void initialize_mpi(MPI_Comm intracomm) MPI_Get_address(&b.particle, &disp[7]); MPI_Get_address(&b.parent_id, &disp[8]); MPI_Get_address(&b.progeny_id, &disp[9]); + MPI_Get_address(&b.source_id, &disp[10]); for (int i = 9; i >= 0; --i) { disp[i] -= disp[0]; } - int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; + int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1}; MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; - MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); + MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG, MPI_INT}; + MPI_Type_create_struct(11, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); } #endif // OPENMC_MPI diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index e4b0211f485..cc45f59c1f5 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -672,15 +672,10 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) site.E = lower_bound_index( data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); site.E = negroups_ - site.E - 1.; - //this->from_source(&site); - this->from_source(&site); + from_source(&site); std::unique_ptr& source_handle = model::external_sources[site.source_id]; - //Source* s = model::external_sources[site.source_id].get(); - // Check for independent source IndependentSource* is = dynamic_cast(source_handle.get()); - //Distribution* energy_dist = is->energy(); - //Discrete* disc = dynamic_cast(energy_dist); Discrete* energy_external_source = dynamic_cast(is->energy()); const auto& discrete_energies = energy_external_source->x(); From 074dbdafd4ca79f92048f2952bfb98ee4d3f580b Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 15:28:49 -0500 Subject: [PATCH 04/27] source_id re-added (check1) --- src/source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source.cpp b/src/source.cpp index 15fe8433ba5..1157a1cfc44 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -627,7 +627,7 @@ SourceSite sample_external_source(uint64_t* seed) // Sample source site from i-th source distribution SourceSite site {model::external_sources[i]->sample_with_constraints(seed)}; - + site.source_id = i; // If running in MG, convert site.E to group if (!settings::run_CE) { site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), From 49ff23e19f4369a02a0e40b100a6d45739df95a7 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 16:08:29 -0500 Subject: [PATCH 05/27] tbd_1 --- openmc/lib/core.py | 4 ++-- src/initialize.cpp | 8 ++++---- src/random_ray/linear_source_domain.cpp | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/openmc/lib/core.py b/openmc/lib/core.py index cfd3fdd8a58..0b9b6446dc1 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -26,8 +26,8 @@ class _SourceSite(Structure): ('surf_id', c_int), ('particle', c_int), ('parent_id', c_int64), - ('progeny_id', c_int64), - ('source_id', c_int)] + ('progeny_id', c_int64)] +# ('source_id', c_int)] # Define input type for numpy arrays that will be passed into C++ functions diff --git a/src/initialize.cpp b/src/initialize.cpp index 8c263619ab7..1fe3e79d88e 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -155,7 +155,7 @@ void initialize_mpi(MPI_Comm intracomm) // Create bank datatype SourceSite b; - MPI_Aint disp[10]; + MPI_Aint disp[11]; MPI_Get_address(&b.r, &disp[0]); MPI_Get_address(&b.u, &disp[1]); MPI_Get_address(&b.E, &disp[2]); @@ -167,14 +167,14 @@ void initialize_mpi(MPI_Comm intracomm) MPI_Get_address(&b.parent_id, &disp[8]); MPI_Get_address(&b.progeny_id, &disp[9]); MPI_Get_address(&b.source_id, &disp[10]); - for (int i = 9; i >= 0; --i) { + for (int i = 10; i >= 0; --i) { disp[i] -= disp[0]; } - int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG, MPI_INT}; - MPI_Type_create_struct(11, blocks, disp, types, &mpi::source_site); + MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); } #endif // OPENMC_MPI diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index c64bd3416a7..9db88aeac4b 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -418,6 +418,7 @@ double LinearSourceDomain::evaluate_flux_at_point( return phi_flat + phi_solved.dot(local_r); } else { // ??? add error message. + return 0; } } From d5f157559c8ebf411df32ff47034da3cf1da8345 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 16:11:42 -0500 Subject: [PATCH 06/27] tbd_2 --- src/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.cpp b/src/settings.cpp index 2efd83e3405..4014f67579e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,7 +134,7 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {true}; +bool FIRST_COLLIDED_FLUX {false}; int n_uncollided_rays {10000}; int n_volume_estimator_rays {10000}; bool first_collided_mode {false}; From 9f7f12e9cc812b602ca1a8d43afbffddedd3d258 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 24 Jul 2024 16:22:41 -0500 Subject: [PATCH 07/27] tbd_3 --- src/initialize.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/initialize.cpp b/src/initialize.cpp index 1fe3e79d88e..cc1eac9cf35 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -155,7 +155,7 @@ void initialize_mpi(MPI_Comm intracomm) // Create bank datatype SourceSite b; - MPI_Aint disp[11]; + MPI_Aint disp[10]; MPI_Get_address(&b.r, &disp[0]); MPI_Get_address(&b.u, &disp[1]); MPI_Get_address(&b.E, &disp[2]); @@ -166,14 +166,13 @@ void initialize_mpi(MPI_Comm intracomm) MPI_Get_address(&b.particle, &disp[7]); MPI_Get_address(&b.parent_id, &disp[8]); MPI_Get_address(&b.progeny_id, &disp[9]); - MPI_Get_address(&b.source_id, &disp[10]); - for (int i = 10; i >= 0; --i) { + for (int i = 9; i >= 0; --i) { disp[i] -= disp[0]; } int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG, MPI_INT}; + MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); } From 0267b8001d96944b037c90c07b4aec414148e423 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 25 Jul 2024 18:39:59 -0500 Subject: [PATCH 08/27] flat_source_clean_up_1 --- .../openmc/random_ray/flat_source_domain.h | 6 +- .../openmc/random_ray/linear_source_domain.h | 3 +- include/openmc/random_ray/random_ray.h | 2 + include/openmc/settings.h | 1 - openmc/__init__.py | 4 +- openmc/lib/core.py | 4 +- src/initialize.cpp | 11 +- src/random_ray/flat_source_domain.cpp | 130 ++++++++++-------- src/random_ray/linear_source_domain.cpp | 40 +----- src/random_ray/random_ray.cpp | 19 +-- src/random_ray/random_ray_simulation.cpp | 100 ++++++++------ src/settings.cpp | 6 +- 12 files changed, 170 insertions(+), 156 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 9b70dfaa191..cf71626d574 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -110,12 +110,14 @@ class FlatSourceDomain { void convert_external_sources(); void count_external_source_regions(); virtual void flux_swap(); - virtual double evaluate_flux_at_point(Position r, int64_t sr, int g, int ft) const; + virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; double compute_fixed_source_normalization_factor() const; void compute_first_collided_flux(); void normalize_uncollided_scalar_flux(double number_of_particles); void update_volume_uncollided_flux(); - void reset_hit(); + virtual void update_external_source(); // check if virtual + virtual void compute_uncollided_scalar_flux(); // check if virtual + virtual int64_t check_fsr_hits(); //---------------------------------------------------------------------------- // Static Data members diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index fccc1fbc944..8f5e6ff8b3c 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -39,9 +39,8 @@ class LinearSourceDomain : public FlatSourceDomain { 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, int ft) const override; + double evaluate_flux_at_point(Position r, int64_t sr, int g) const override; - void reset_hit(); void compute_first_collided_flux(); void normalize_uncollided_scalar_flux(double number_of_particles); diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index a40cee12cb8..cd501138dc6 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -42,6 +42,8 @@ class RandomRay : public Particle { static unique_ptr ray_source_; // Starting source for ray sampling static RandomRaySourceShape source_shape_; // Flag for linear source + static bool uncollided_flux_volume; // Flag for Initial Volume estimation + //---------------------------------------------------------------------------- // Public data members vector angular_flux_; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index cc96ad741f1..078c293a180 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -156,7 +156,6 @@ extern double weight_survive; //!< Survival weight after Russian roulette // HARDCODED INPUTS - First Collided Flux extern bool FIRST_COLLIDED_FLUX; //!< First Collided Mode loop -extern bool uncollided_flux_volume; //!< Initial volume estimation loop extern int n_uncollided_rays; //!< Number of uncollided rays used extern int n_volume_estimator_rays; //!< Number of rays to estimate volume extern bool first_collided_mode; //!< Add first collided source in RR diff --git a/openmc/__init__.py b/openmc/__init__.py index 566d287068f..ee0011d82c5 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -40,5 +40,7 @@ from . import examples +__version__ = '0.14.1-dev' -__version__ = importlib.metadata.version("openmc") + +#__version__ = importlib.metadata.version("openmc") diff --git a/openmc/lib/core.py b/openmc/lib/core.py index 0b9b6446dc1..cfd3fdd8a58 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -26,8 +26,8 @@ class _SourceSite(Structure): ('surf_id', c_int), ('particle', c_int), ('parent_id', c_int64), - ('progeny_id', c_int64)] -# ('source_id', c_int)] + ('progeny_id', c_int64), + ('source_id', c_int)] # Define input type for numpy arrays that will be passed into C++ functions diff --git a/src/initialize.cpp b/src/initialize.cpp index cc1eac9cf35..e5de9b9ea39 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -155,7 +155,7 @@ void initialize_mpi(MPI_Comm intracomm) // Create bank datatype SourceSite b; - MPI_Aint disp[10]; + MPI_Aint disp[11]; MPI_Get_address(&b.r, &disp[0]); MPI_Get_address(&b.u, &disp[1]); MPI_Get_address(&b.E, &disp[2]); @@ -166,14 +166,15 @@ void initialize_mpi(MPI_Comm intracomm) MPI_Get_address(&b.particle, &disp[7]); MPI_Get_address(&b.parent_id, &disp[8]); MPI_Get_address(&b.progeny_id, &disp[9]); - for (int i = 9; i >= 0; --i) { + MPI_Get_address(&b.source_id, &disp[10]); + for (int i = 10; i >= 0; --i) { disp[i] -= disp[0]; } - int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; + int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1}; MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, - MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; - MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); + MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG, MPI_INT}; + MPI_Type_create_struct(11, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); } #endif // OPENMC_MPI diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 10916cd4d13..8bf4bc047f5 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -112,14 +112,12 @@ void FlatSourceDomain::batch_reset() // Reset scalar fluxes, iteration volume tallies, and region hit flags to // zero parallel_fill(scalar_flux_new_, 0.0f); - parallel_fill(volume_, 0.0); parallel_fill(was_hit_, 0); + if (!settings::FIRST_COLLIDED_FLUX){ + parallel_fill(volume_, 0.0); + } } -void FlatSourceDomain::reset_hit() -{ - parallel_fill(was_hit_,0); -} void FlatSourceDomain::accumulate_iteration_flux() { @@ -129,22 +127,9 @@ void FlatSourceDomain::accumulate_iteration_flux() } } -// Compute new estimate of scattering + fission sources in each source region -// based on the flux estimate from the previous iteration. -void FlatSourceDomain::update_neutron_source(double k_eff) +// multiply First Collided Flux by volume and attribute it as fixed source +void FlatSourceDomain::update_external_source() { - simulation::time_update_src.start(); - - double inverse_k_eff = 1.0 / k_eff; - - // Temperature and angle indices, if using multiple temperature - // data sets and/or anisotropic data sets. - // TODO: Currently assumes we are only using single temp/single angle data. - const int t = 0; - const int a = 0; - - // multiply First Collided Flux by volume and attribute it as fixed source - if (settings::first_collided_mode){ #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; @@ -159,7 +144,20 @@ void FlatSourceDomain::update_neutron_source(double k_eff) } } } - } +} +// Compute new estimate of scattering + fission sources in each source region +// based on the flux estimate from the previous iteration. +void FlatSourceDomain::update_neutron_source(double k_eff) +{ + simulation::time_update_src.start(); + + double inverse_k_eff = 1.0 / k_eff; + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single angle data. + const int t = 0; + const int a = 0; // Add scattering source #pragma omp parallel for @@ -249,7 +247,47 @@ if (!settings::FIRST_COLLIDED_FLUX){ } } +int64_t FlatSourceDomain::check_fsr_hits() +{ + int64_t n_hits = 0; +#pragma omp parallel for reduction(+ : n_hits) + for (int sr = 0; sr < n_source_regions_; sr++) { + + // Check if this cell was hit this iteration + int was_cell_hit = was_hit_[sr]; + if (was_cell_hit) { + n_hits++; + } + } + + return n_hits; +} + +void FlatSourceDomain::compute_uncollided_scalar_flux() +{ + // Temperature and angle indices, if using multiple temperature + const int t = 0; + const int a = 0; + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + int was_cell_hit = was_hit_[sr]; + double volume = volume_[sr]; + int material = material_[sr]; + + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + if (was_cell_hit) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]/ (sigma_t); + } else { + scalar_uncollided_flux_[idx] = 0.0f; + } + } + } +} // Combine transport flux contributions and flat source contributions from the // previous iteration to generate this iteration's estimate of scalar flux. @@ -286,30 +324,18 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux() // transport sweep) float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]/ (sigma_t); /// (sigma_t * volume); - } else { scalar_flux_new_[idx] /= (sigma_t * volume); scalar_flux_new_[idx] += source_[idx]; - } } else if (volume > 0.0) { // 2. If the FSR was not hit this iteration, but has been hit some // previous iteration, then we simply set the new scalar flux to be // equal to the contribution from the flat source alone. - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = 0.0f; - } else { scalar_flux_new_[idx] = source_[idx]; - } } else { // If the FSR was not hit this iteration, and it has never been hit in // any iteration (i.e., volume is zero), then we want to set this to 0 // to avoid dividing anything by a zero volume. - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = 0.0f; - } else { scalar_flux_new_[idx] = 0.0f; - } } } } @@ -323,17 +349,18 @@ void FlatSourceDomain::normalize_uncollided_scalar_flux(double number_of_particl { // multiply by simulation volume float normalization_factor = (1.0)/ number_of_particles; - // Determine Source_total Scailing factor if first collided - + + // Determine Source_total Scailing factor if first collided double user_external_source_strength = 0.0; for (auto& ext_source : model::external_sources) { user_external_source_strength += ext_source->strength(); } - //fmt::print("total_source_strength = {}\n", total_source_intensity); + + float source_scailing_factor = (user_external_source_strength * normalization_factor); #pragma omp parallel for for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { - scalar_uncollided_flux_[e] *= ((user_external_source_strength) * normalization_factor) ; + scalar_uncollided_flux_[e] *= source_scailing_factor; } } @@ -861,21 +888,19 @@ void FlatSourceDomain::all_reduce_replicated_source_regions() #endif } + +// avoid add scalar_uncollided_flux if not using fixed source - first collided double FlatSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g, int ft) const + Position r, int64_t sr, int g) const { - if (ft == 0){ // RR scalar neutron flux + if(!settings::first_collided_mode){ return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); - } else if (ft == 1){ // Uncollided neutron flux -return scalar_uncollided_flux_[sr * negroups_ + g]; - } else if (ft == 2){ // external source -return external_source_[sr * negroups_ + g]; + (settings::n_batches - settings::n_inactive)); } else { - // ??? add error message. - return 0; + // add uncollided flux if First Collided method is used + return (scalar_flux_final_[sr * negroups_ + g] / + (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); } - } // Outputs all basic material, FSR ID, multigroup flux, and @@ -983,7 +1008,7 @@ void FlatSourceDomain::output_to_vtk() const for (int i = 0; i < Nx * Ny * Nz; i++) { int64_t fsr = voxel_indices[i]; int64_t source_element = fsr * negroups_ + g; - float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 0); + float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); flux = convert_to_big_endian(flux); std::fwrite(&flux, sizeof(float), 1, plot); } @@ -1017,7 +1042,7 @@ void FlatSourceDomain::output_to_vtk() const int mat = material_[fsr]; for (int g = 0; g < negroups_; g++) { int64_t source_element = fsr * negroups_ + g; - float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 0); + float flux = evaluate_flux_at_point(voxel_positions[i], fsr, g); float Sigma_f = data::mg.macro_xs_[mat].get_xs( MgxsType::FISSION, g, nullptr, nullptr, nullptr, 0, 0); total_fission += Sigma_f * flux; @@ -1035,7 +1060,7 @@ void FlatSourceDomain::output_to_vtk() const int mat = material_[fsr]; float sigma_t = data::mg.macro_xs_[mat].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, 0, 0); - float f_source = evaluate_flux_at_point(voxel_positions[i], fsr, g, 2); + float f_source = external_source_[fsr * negroups_ + g]; f_source *= sigma_t; f_source = convert_to_big_endian(f_source); std::fwrite(&f_source, sizeof(float), 1, plot); @@ -1049,7 +1074,7 @@ void FlatSourceDomain::output_to_vtk() const for (int i = 0; i < Nx * Ny * Nz; i++) { int64_t fsr = voxel_indices[i]; int64_t source_element = fsr * negroups_ + g; - float uncollided_flux = evaluate_flux_at_point(voxel_positions[i], fsr, g, 1); + float uncollided_flux = scalar_uncollided_flux_[source_element]; uncollided_flux = convert_to_big_endian(uncollided_flux); std::fwrite(&uncollided_flux, sizeof(float), 1, plot); } @@ -1123,9 +1148,6 @@ void FlatSourceDomain::count_external_source_regions() for (int e = 0; e < negroups_; e++) { int64_t se = sr * negroups_ + e; total += external_source_[se]; - if (settings::FIRST_COLLIDED_FLUX){ - total += scalar_first_collided_flux_[se]; - } } if (total != 0.f) { n_external_source_regions_++; diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 9db88aeac4b..bc593805de5 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -54,11 +54,6 @@ void LinearSourceDomain::batch_reset() } } -void LinearSourceDomain::reset_hit() -{ - parallel_fill(was_hit_,0); -} - void LinearSourceDomain::update_neutron_source(double k_eff) { simulation::time_update_src.start(); @@ -382,46 +377,23 @@ void LinearSourceDomain::all_reduce_replicated_source_regions() } double LinearSourceDomain::evaluate_flux_at_point( - Position r, int64_t sr, int g, int ft) const + Position r, int64_t sr, int g) const { - if (flux_type == 0){ // RR neutron flux - float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); + // RR neutron flux + float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g); Position local_r = r - centroid_[sr]; MomentArray phi_linear = flux_moments_t_[sr * negroups_ + g]; phi_linear *= 1.0 / (settings::n_batches - settings::n_inactive); - phi_linear += flux_moments_uncollided_[sr * negroups_ + g]; // ??? addition - - MomentMatrix invM = mom_matrix_[sr].inverse(); - MomentArray phi_solved = invM * phi_linear; - - return phi_flat + phi_solved.dot(local_r); - } else if (ft == 1){// Uncollided neutron flux - float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); - - Position local_r = r - centroid_[sr]; - MomentArray phi_linear = flux_moments_uncollided_[sr * negroups_ + g]; - - MomentMatrix invM = mom_matrix_[sr].inverse(); - MomentArray phi_solved = invM * phi_linear; - - return phi_flat + phi_solved.dot(local_r); - } else if (ft == 2){ // External Source - float phi_flat = FlatSourceDomain::evaluate_flux_at_point(r, sr, g, ft); - - Position local_r = r - centroid_[sr]; - MomentArray phi_linear = external_source_gradients_[sr * negroups_ + g]; + if (settings::first_collided_mode){ + phi_linear += flux_moments_uncollided_[sr * negroups_ + g]; // ??? addition + } MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; return phi_flat + phi_solved.dot(local_r); - } else { - // ??? add error message. - return 0; - } } -// CHANGE EVALUATE_FLUX_AT_POINT FOR EXTERNAL SOURCE AND UNCOLLIDED FLUX } // namespace openmc diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index cc45f59c1f5..3000416f8f6 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -183,6 +183,7 @@ double RandomRay::distance_inactive_; double RandomRay::distance_active_; unique_ptr RandomRay::ray_source_; RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; +bool RandomRay::uncollided_flux_volume = {false}; RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), @@ -363,7 +364,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) const int a = 0; // MOC incoming flux attenuation + source contribution/attenuation equation - if (!settings::uncollided_flux_volume){ + if (!uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); @@ -385,7 +386,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Accumulate delta psi into new estimate of source region flux for // this iteration - if (!settings::uncollided_flux_volume){ + if (!uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; } @@ -401,7 +402,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Accomulate volume (ray distance) into this iteration's estimate // of the source region's volume - if (!settings::FIRST_COLLIDED_FLUX || settings::uncollided_flux_volume){ + if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume){ domain_->volume_[source_region] += distance; } @@ -417,7 +418,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) domain_->lock_[source_region].unlock(); // check attenuation in FIRST_ COLLIDED_FLUX - if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ // bool = true to kill ray // ray is killed by default unless: bool angular_flux_below_threshold = true; @@ -503,7 +504,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Linear Source MOC incoming flux attenuation + source // contribution/attenuation equation - if (!settings::uncollided_flux_volume){ + if (!uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { // Compute tau, the optical thickness of the ray segment @@ -571,7 +572,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Accumulate deltas into the new estimate of source region flux for this // iteration - if (!settings::uncollided_flux_volume){ + if (!uncollided_flux_volume){ for (int g = 0; g < negroups_; g++) { domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; domain->flux_moments_new_[source_element + g] += delta_moments_[g]; @@ -582,7 +583,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // momement estimates into the running totals for the iteration for this // source region. The centroid and spatial momements estimates are scaled by // the ray segment length as part of length averaging of the estimates. - if (!settings::FIRST_COLLIDED_FLUX || settings::uncollided_flux_volume){ + if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume){ domain_->volume_[source_region] += distance; domain->centroid_iteration_[source_region] += midpoint * distance; // how to compute these ones @@ -611,7 +612,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) domain_->lock_[source_region].unlock(); // check attenuation in FIRST_ COLLIDED_FLUX - if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ // bool = true to kill ray // ray is killed by default unless: bool angular_flux_below_threshold = true; @@ -667,7 +668,7 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) stream() = STREAM_TRACKING; // Sample from input Source - if (settings::FIRST_COLLIDED_FLUX && !settings::uncollided_flux_volume){ + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ auto site = sample_external_source(current_seed()); site.E = lower_bound_index( data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 50e492f58f8..37ae18d989d 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -177,8 +177,13 @@ void validate_random_ray_inputs() // Validate that a domain ID was specified if (is->domain_ids().size() == 0) { + if (!settings::FIRST_COLLIDED_FLUX){ fatal_error("Fixed sources must be specified by domain " "id (cell, material, or universe) in random ray mode."); + } else if (settings::FIRST_COLLIDED_FLUX){ + // + fmt::print("??? add First collided condition and fatal error here\n"); + } } // Check that a discrete energy distribution was used @@ -271,7 +276,7 @@ void RandomRaySimulation::simulate() // Turn on volume pre calculation double start_volume_estimation = omp_get_wtime(); fmt::print("Computing starting volume estimates... \n"); - settings::uncollided_flux_volume = {true}; + RandomRay::uncollided_flux_volume = true; // Pre calculate volume #pragma omp parallel for schedule(dynamic) \ @@ -282,17 +287,17 @@ void RandomRaySimulation::simulate() ray.transport_history_based_single_ray(); } - // Normalizing the scalar_new_flux and volumes - domain_->normalize_scalar_flux_and_volumes(settings::n_volume_estimator_rays * RandomRay::distance_active_); + // Normalizing the scalar_new_flux and volumes + domain_->normalize_scalar_flux_and_volumes(settings::n_volume_estimator_rays * RandomRay::distance_active_); - // Print volume estimation simulation time - double end_volume_estimation = omp_get_wtime(); - fmt::print("Volume estimation completed.\n"); - fmt::print("Run time = {:.4f} \n\n", end_volume_estimation-start_volume_estimation); + // Print volume estimation simulation time + double end_volume_estimation = omp_get_wtime(); + fmt::print("Volume estimation completed.\n"); + fmt::print("Run time = {:.4f} \n\n", end_volume_estimation-start_volume_estimation); - // Reset parameters for First Collided Method - settings::uncollided_flux_volume = {false}; - domain_->reset_hit(); + // Reset parameters for First Collided Method + RandomRay::uncollided_flux_volume = false; + domain_->batch_reset(); //============================================================================== // First Collided Transport Loop // It will operate until (1-3): @@ -302,6 +307,7 @@ void RandomRaySimulation::simulate() fmt::print(" Batch Rays Total Source Regions Discovered\n" " ====== ========== ================================\n"); + //TO-do // SET-UP for user input n_uncollided_rays if (user_input_rays == true){ new_n_rays = n_rays_max; @@ -311,54 +317,53 @@ void RandomRaySimulation::simulate() // loop will end if no new cell was hit domain_->new_fsr_fc = {false}; - // Transport sweep over all random rays for the iteration + // Ray tracing and attenuation #pragma omp parallel for schedule(dynamic) \ reduction(+ : total_geometric_intersections_) for (int i = old_n_rays; i< new_n_rays; i++){ - RandomRay ray(i, domain_.get()); - total_geometric_intersections_ += - ray.transport_history_based_single_ray_first_collided(); - } - - // add scalar_new_flux calculations - int64_t n_hits = domain_->add_source_to_scalar_flux(); - - // Normalize scalar_uncollided_flux - domain_->normalize_uncollided_scalar_flux(new_n_rays); + RandomRay ray(i, domain_.get()); + total_geometric_intersections_ += + ray.transport_history_based_single_ray_first_collided(); + } - // compute first_collided_fixed_source - domain_->compute_first_collided_flux(); - - // save number of hit FSR - n_u_hits = n_hits; - fsr_ratio = static_cast(n_u_hits) / domain_->n_source_regions_; + int64_t n_hits = domain_->check_fsr_hits(); - // print results - fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_u_hits); + // print results + fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits); - // BREAK STATEMENT if Max rays reached or 100% FSR HIT - old_n_rays = new_n_rays; - if (new_n_rays >= n_rays_max) { + // BREAK STATEMENT if Max rays reached or 100% FSR HIT + old_n_rays = new_n_rays; + if (new_n_rays >= n_rays_max) { //Uncollided rays limit achieved + // To-do : if user input max_rays is given, this will cause the batch to end break; - } else if (fsr_ratio == 1.0){ + } else if (static_cast(n_hits) >= domain_->n_source_regions_){ //All FSRs hit; break; - } - - //update for next batch - new_n_rays *= 2; - batch_first_collided++; + } + + // update values for next batch + new_n_rays *= 2; + batch_first_collided++; } - // Count fixed source regions - domain_->count_external_source_regions(); + // Compute scalar_uncollided_flux + domain_->compute_uncollided_scalar_flux(); - // reset values for RandomRay iteration - settings::first_collided_mode = {true}; //keep that for adding uncollided flux at the end - settings::FIRST_COLLIDED_FLUX = {false}; //move to regular fixed source RR + // Normalize scalar_uncollided_flux + domain_->normalize_uncollided_scalar_flux(new_n_rays); + + // compute first_collided_fixed_source - + domain_->compute_first_collided_flux(); + + //make sure all paremeters are + domain_->batch_reset(); // clean-up scalar_flux_new and was_hit (preserves volume) simulation::current_batch = 0; //garantee the first batch will be 1 in RR + // reset values for RandomRay iteration + settings::first_collided_mode = {true}; // add FC contribution to RR + settings::FIRST_COLLIDED_FLUX = {false}; //move to regular fixed source RR calculations + // compute First Collided Method simulation time double first_collided_estimated_time = omp_get_wtime(); fmt::print(" ====== ========== ================================\n\n"); @@ -376,6 +381,11 @@ void RandomRaySimulation::simulate() // Reset total starting particle weight used for normalizing tallies simulation::total_weight = 1.0; + // Update external source if FIRST_COLLIDED_METHOD is used + if (settings::first_collided_mode){ + domain_->update_external_source(); + } + // Update source term (scattering + fission) domain_->update_neutron_source(k_eff_); @@ -440,6 +450,8 @@ void RandomRaySimulation::simulate() finalize_generation(); finalize_batch(); } // End random ray power iteration loop + + domain_->update_volume_uncollided_flux(); } void RandomRaySimulation::reduce_simulation_statistics() @@ -518,8 +530,10 @@ void RandomRaySimulation::print_results_random_ray( fmt::print( " Total Iterations = {}\n", settings::n_batches); fmt::print(" Flat Source Regions (FSRs) = {}\n", n_source_regions); + if(!settings::first_collided_mode){ fmt::print( " FSRs Containing External Sources = {}\n", n_external_source_regions); + } fmt::print(" Total Geometric Intersections = {:.4e}\n", static_cast(total_geometric_intersections)); fmt::print(" Avg per Iteration = {:.4e}\n", diff --git a/src/settings.cpp b/src/settings.cpp index 4014f67579e..48cc5ca7306 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,11 +134,11 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {false}; -int n_uncollided_rays {10000}; +bool FIRST_COLLIDED_FLUX {true}; +int n_uncollided_rays {1000000}; int n_volume_estimator_rays {10000}; bool first_collided_mode {false}; -bool uncollided_flux_volume {false}; + } // namespace settings From 79f4ee26485c0d83d03dd5817200788e5a39c4d3 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Mon, 29 Jul 2024 13:47:34 -0500 Subject: [PATCH 09/27] Linear_source_check_1 --- .../openmc/random_ray/flat_source_domain.h | 7 +- .../openmc/random_ray/linear_source_domain.h | 11 +- .../openmc/random_ray/random_ray_simulation.h | 4 +- src/random_ray/flat_source_domain.cpp | 10 +- src/random_ray/linear_source_domain.cpp | 137 +++++++++++++----- src/random_ray/random_ray.cpp | 25 ++-- src/random_ray/random_ray_simulation.cpp | 46 ++++-- src/settings.cpp | 4 +- 8 files changed, 167 insertions(+), 77 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index cf71626d574..16f38cb5667 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -112,9 +112,10 @@ class FlatSourceDomain { virtual 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 compute_first_collided_flux(); - void normalize_uncollided_scalar_flux(double number_of_particles); - void update_volume_uncollided_flux(); + + virtual void compute_first_collided_flux(); + virtual void normalize_uncollided_scalar_flux(double number_of_particles); + virtual void update_volume_uncollided_flux(); virtual void update_external_source(); // check if virtual virtual void compute_uncollided_scalar_flux(); // check if virtual virtual int64_t check_fsr_hits(); diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index 8f5e6ff8b3c..996532ec813 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -41,12 +41,15 @@ class LinearSourceDomain : public FlatSourceDomain { void flux_swap() override; double evaluate_flux_at_point(Position r, int64_t sr, int g) const override; - void compute_first_collided_flux(); - void normalize_uncollided_scalar_flux(double number_of_particles); - + virtual void update_external_source(); + virtual int64_t check_fsr_hits(); + virtual void compute_uncollided_scalar_flux(); + virtual void compute_first_collided_flux(); + virtual void normalize_uncollided_scalar_flux(double number_of_particles); + virtual void update_volume_uncollided_flux(); //---------------------------------------------------------------------------- // Public Data members - + bool new_fsr_fc {true}; vector source_gradients_; vector flux_moments_old_; diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index 9c7d3ef06e2..f1ee2d04edc 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -31,10 +31,10 @@ class RandomRaySimulation { //---------------------------------------------------------------------------- // Data members // First collided method variables for automatic n_uncollided_rays - int64_t n_u_hits {0}; + int64_t n_hits_new {0}; + int64_t n_hits_old {0}; int new_n_rays {settings::n_uncollided_rays}; int old_n_rays {0}; - double fsr_ratio {0.0}; int batch_first_collided {1}; int n_rays_max {1000000}; bool user_input_rays {false}; diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 8bf4bc047f5..2c718b5ac9f 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -272,7 +272,7 @@ void FlatSourceDomain::compute_uncollided_scalar_flux() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int was_cell_hit = was_hit_[sr]; - double volume = volume_[sr]; + double volume = volume_[sr]; // necessary??? int material = material_[sr]; for (int g = 0; g < negroups_; g++) { @@ -383,7 +383,7 @@ void FlatSourceDomain::compute_first_collided_flux() float scalar_flux = scalar_uncollided_flux_[sr * negroups_ + e_in]; float sigma_s = data::mg.macro_xs_[material].get_xs( - MgxsType::SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + MgxsType::NU_SCATTER, e_in, &e_out, nullptr, nullptr, t, a); scatter_fixed_source += sigma_s * scalar_flux; } @@ -705,7 +705,11 @@ void FlatSourceDomain::random_ray_tally() for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; if (settings::first_collided_mode){ - flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); + if(RandomRay::source_shape_ == RandomRaySourceShape::FLAT){ + flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); + } else { + flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx])); + } } else { flux = (scalar_flux_new_[idx] * source_normalization_factor) ; } diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index bc593805de5..0682f85db8c 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -54,12 +54,24 @@ void LinearSourceDomain::batch_reset() } } -void LinearSourceDomain::update_neutron_source(double k_eff) +int64_t LinearSourceDomain::check_fsr_hits() { - simulation::time_update_src.start(); + int64_t n_hits = 0; +#pragma omp parallel for reduction(+ : n_hits) + for (int sr = 0; sr < n_source_regions_; sr++) { - double inverse_k_eff = 1.0 / k_eff; + // Check if this cell was hit this iteration + int was_cell_hit = was_hit_[sr]; + if (was_cell_hit) { + n_hits++; + } + } + return n_hits; +} + +void LinearSourceDomain::update_external_source() +{ // Temperature and angle indices, if using multiple temperature // data sets and/or anisotropic data sets. // TODO: Currently assumes we are only using single temp/single @@ -67,17 +79,12 @@ void LinearSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; - - #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int material = material_[sr]; - MomentMatrix invM = mom_matrix_[sr].inverse(); // multiply First Collided Flux by volume and attribute it as external_source - // FIX THIS - CHECK MATH ??? - if (settings::first_collided_mode){ double volume = simulation_volume_ * volume_[sr]; for (int g = 0; g < negroups_; g++) { float sigma_t = data::mg.macro_xs_[material].get_xs( @@ -86,11 +93,33 @@ void LinearSourceDomain::update_neutron_source(double k_eff) external_source_[sr * negroups_ + g] = 0.0f; external_source_gradients_[sr * negroups_ + g] = {0.0, 0.0, 0.0}; } else { - external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(sigma_t * volume)); - external_source_gradients_[sr * negroups_ + g] = (flux_moments_first_collided_[sr * negroups_ + g] /(sigma_t * volume)); + external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(volume)); + external_source_gradients_[sr * negroups_ + g] = (flux_moments_first_collided_[sr * negroups_ + g] /(volume)); } - } + } } +} + +void LinearSourceDomain::update_neutron_source(double k_eff) +{ + simulation::time_update_src.start(); + + double inverse_k_eff = 1.0 / k_eff; + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + + + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + + int material = material_[sr]; + MomentMatrix invM = mom_matrix_[sr].inverse(); for (int e_out = 0; e_out < negroups_; e_out++) { float sigma_t = data::mg.macro_xs_[material].get_xs( @@ -176,25 +205,51 @@ if (!settings::FIRST_COLLIDED_FLUX){ mom_matrix_[sr] *= inv_volume; } } -} + } -// ??? CHECK if need to clear _t_ terms +// just fuse to the other IF STATEMENT if (settings::FIRST_COLLIDED_FLUX){ #pragma omp parallel for for (int64_t sr = 0; sr < n_source_regions_; sr++) { - mom_matrix_t_[sr] += mom_matrix_[sr]; - volume_t_[sr] += volume_[sr]; volume_[sr] *= volume_normalization_factor; - if (volume_t_[sr] > 0.0) { - double inv_volume = 1.0 / volume_t_[sr]; - centroid_[sr] = centroid_t_[sr]; + if (volume_[sr] > 0.0) { + double inv_volume = 1.0 / volume_[sr]; + centroid_[sr] = centroid_iteration_[sr]; centroid_[sr] *= inv_volume; - mom_matrix_[sr] = mom_matrix_t_[sr]; + mom_matrix_[sr] = mom_matrix_[sr]; mom_matrix_[sr] *= inv_volume; } } + } + } +void LinearSourceDomain::compute_uncollided_scalar_flux() +{ + // Temperature and angle indices, if using multiple temperature + const int t = 0; + const int a = 0; + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + int was_cell_hit = was_hit_[sr]; + double volume = volume_[sr]; + int material = material_[sr]; + + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + + if (was_cell_hit) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]; + flux_moments_uncollided_[idx] = flux_moments_new_[idx]; + } else { + scalar_uncollided_flux_[idx] = 0.0f; + flux_moments_uncollided_[idx] *= 0.0; + } + } + } } int64_t LinearSourceDomain::add_source_to_scalar_flux() @@ -228,40 +283,24 @@ int64_t LinearSourceDomain::add_source_to_scalar_flux() // the flat source from the previous iteration plus the contributions // from rays passing through the source region (computed during the // transport sweep) - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]; /// (sigma_t * volume); - flux_moments_uncollided_[idx] = flux_moments_new_[idx]; - // Add flux_moments_uncollided ??? - } else { scalar_flux_new_[idx] /= volume; scalar_flux_new_[idx] += source_[idx]; flux_moments_new_[idx] *= (1.0 / volume); - } } else if (volume > 0.0) { // 2. If the FSR was not hit this iteration, but has been hit some // previous iteration, then we simply set the new scalar flux to be // equal to the contribution from the flat source alone. - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = 0.0f; - flux_moments_uncollided_[idx] *= 0.0; - } else { scalar_flux_new_[idx] = source_[idx]; // ??? flux_moments_new_[idx] = ???? - } } else { // If the FSR was not hit this iteration, and it has never been hit in // any iteration (i.e., volume is zero), then we want to set this to 0 // to avoid dividing anything by a zero volume. - if (settings::FIRST_COLLIDED_FLUX){ - scalar_uncollided_flux_[idx] = 0.0f; - flux_moments_uncollided_[idx] *= 0.0; - } else { scalar_flux_new_[idx] = 0.0f; flux_moments_new_[idx] *= 0.0; - } + } } } - } return n_hits; } @@ -279,10 +318,12 @@ void LinearSourceDomain::normalize_uncollided_scalar_flux(double number_of_parti } //fmt::print("total_source_strength = {}\n", total_source_intensity); + float source_scailing_factor = (user_external_source_strength * normalization_factor); + #pragma omp parallel for -for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { - scalar_uncollided_flux_[e] *= ((user_external_source_strength) * normalization_factor); - flux_moments_uncollided_[e] *= ((user_external_source_strength) * normalization_factor); + for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { + scalar_uncollided_flux_[e] *= source_scailing_factor; + flux_moments_uncollided_[e] *= source_scailing_factor; } } @@ -395,5 +436,23 @@ double LinearSourceDomain::evaluate_flux_at_point( return phi_flat + phi_solved.dot(local_r); } +void LinearSourceDomain::update_volume_uncollided_flux() +{ + #pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + double volume = volume_[sr] * simulation_volume_; + if (volume != 0.0f){ + for (int g = 0; g < negroups_; g++) { + scalar_uncollided_flux_[sr * negroups_ + g] /= volume; + flux_moments_uncollided_[sr * negroups_ + g] /= volume; + } + } else { + for (int g = 0; g < negroups_; g++) { + scalar_uncollided_flux_[sr * negroups_ + g] =0.0f; + flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; + } + } + } +} } // namespace openmc diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 3000416f8f6..7ac4a3155b7 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -397,7 +397,7 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) if (domain_->was_hit_[source_region] == 0) { domain_->was_hit_[source_region] = 1; // Check if new cell was hit and change for true - domain_->new_fsr_fc = {true}; + //domain_->new_fsr_fc = {true}; } // Accomulate volume (ray distance) into this iteration's estimate @@ -493,12 +493,22 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // be no estimate of its centroid. We detect this by checking if it has // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. - if (domain->volume_t_[source_region]) { - rm_local = midpoint - centroid; - r0_local = r() - centroid; + if(settings::FIRST_COLLIDED_FLUX){ /// TRIPLE CHECK THIS + if (domain->volume_[source_region] == 0.0) { + rm_local = midpoint - centroid; + r0_local = r() - centroid; + } else { + rm_local = {0.0, 0.0, 0.0}; + r0_local = -u() * 0.5 * distance; + } } else { - rm_local = {0.0, 0.0, 0.0}; - r0_local = -u() * 0.5 * distance; + if (domain->volume_t_[source_region]) { + rm_local = midpoint - centroid; + r0_local = r() - centroid; + } else { + rm_local = {0.0, 0.0, 0.0}; + r0_local = -u() * 0.5 * distance; + } } double distance_2 = distance * distance; @@ -586,7 +596,6 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume){ domain_->volume_[source_region] += distance; domain->centroid_iteration_[source_region] += midpoint * distance; - // how to compute these ones moment_matrix_estimate *= distance; domain->mom_matrix_[source_region] += moment_matrix_estimate; } @@ -597,8 +606,6 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // indicate that it now has if (domain_->was_hit_[source_region] == 0) { domain_->was_hit_[source_region] = 1; - // Check if new cell was hit and change for true - domain_->new_fsr_fc = {true}; } // Tally valid position inside the source region (e.g., midpoint of diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 37ae18d989d..8092fa07e8f 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -277,6 +277,7 @@ void RandomRaySimulation::simulate() double start_volume_estimation = omp_get_wtime(); fmt::print("Computing starting volume estimates... \n"); RandomRay::uncollided_flux_volume = true; + simulation::current_batch = 1; // Pre calculate volume #pragma omp parallel for schedule(dynamic) \ @@ -287,7 +288,7 @@ void RandomRaySimulation::simulate() ray.transport_history_based_single_ray(); } - // Normalizing the scalar_new_flux and volumes + // Normalizing volumes domain_->normalize_scalar_flux_and_volumes(settings::n_volume_estimator_rays * RandomRay::distance_active_); // Print volume estimation simulation time @@ -298,6 +299,9 @@ void RandomRaySimulation::simulate() // Reset parameters for First Collided Method RandomRay::uncollided_flux_volume = false; domain_->batch_reset(); + + + //============================================================================== // First Collided Transport Loop // It will operate until (1-3): @@ -312,11 +316,11 @@ void RandomRaySimulation::simulate() if (user_input_rays == true){ new_n_rays = n_rays_max; } - + while(domain_->new_fsr_fc){ - // loop will end if no new cell was hit - domain_->new_fsr_fc = {false}; + // loop will end if no new cell was hit -> n_new_hits = n_old_hits + //domain_->new_fsr_fc = {false}; // Ray tracing and attenuation #pragma omp parallel for schedule(dynamic) \ reduction(+ : total_geometric_intersections_) @@ -326,25 +330,30 @@ void RandomRaySimulation::simulate() ray.transport_history_based_single_ray_first_collided(); } - int64_t n_hits = domain_->check_fsr_hits(); + int64_t n_hits_new = domain_->check_fsr_hits(); // print results - fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits); + fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); // BREAK STATEMENT if Max rays reached or 100% FSR HIT old_n_rays = new_n_rays; - if (new_n_rays >= n_rays_max) { + if (n_hits_new == n_hits_old){ + domain_->new_fsr_fc = {false}; + break; + } else if (new_n_rays >= n_rays_max) { + domain_->new_fsr_fc = {false}; //Uncollided rays limit achieved // To-do : if user input max_rays is given, this will cause the batch to end - break; - } else if (static_cast(n_hits) >= domain_->n_source_regions_){ - //All FSRs hit; - break; + break; + } else if (static_cast(n_hits_new) >= domain_->n_source_regions_){ + domain_->new_fsr_fc = {false}; + break; } // update values for next batch new_n_rays *= 2; batch_first_collided++; + n_hits_old = n_hits_new; } // Compute scalar_uncollided_flux @@ -356,14 +365,19 @@ void RandomRaySimulation::simulate() // compute first_collided_fixed_source - domain_->compute_first_collided_flux(); - //make sure all paremeters are - domain_->batch_reset(); // clean-up scalar_flux_new and was_hit (preserves volume) - simulation::current_batch = 0; //garantee the first batch will be 1 in RR + if(RandomRay::source_shape_ == RandomRaySourceShape::LINEAR ||RandomRay::source_shape_ == RandomRaySourceShape::LINEAR_XY){ + domain_->update_volume_uncollided_flux(); + domain_->update_external_source(); + } // reset values for RandomRay iteration settings::first_collided_mode = {true}; // add FC contribution to RR settings::FIRST_COLLIDED_FLUX = {false}; //move to regular fixed source RR calculations + //make sure all paremeters are + domain_->batch_reset(); // clean-up scalar_flux_new and was_hit (preserves volume) + simulation::current_batch = 0; //garantee the first batch will be 1 in RR + // compute First Collided Method simulation time double first_collided_estimated_time = omp_get_wtime(); fmt::print(" ====== ========== ================================\n\n"); @@ -382,7 +396,7 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (settings::first_collided_mode){ + if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT && settings::first_collided_mode){ domain_->update_external_source(); } @@ -451,7 +465,9 @@ void RandomRaySimulation::simulate() finalize_batch(); } // End random ray power iteration loop + if(RandomRay::source_shape_ == RandomRaySourceShape::FLAT){ domain_->update_volume_uncollided_flux(); + } } void RandomRaySimulation::reduce_simulation_statistics() diff --git a/src/settings.cpp b/src/settings.cpp index 48cc5ca7306..e1afca0f63f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -135,8 +135,8 @@ double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {1000000}; -int n_volume_estimator_rays {10000}; +int n_uncollided_rays {200000}; +int n_volume_estimator_rays {1000000}; bool first_collided_mode {false}; From 9592b528a62b4e6c2ee764dfe9ba3496a1493adc Mon Sep 17 00:00:00 2001 From: Tomas P Date: Tue, 30 Jul 2024 18:45:23 -0500 Subject: [PATCH 10/27] linear_source_update_3 --- .../openmc/random_ray/flat_source_domain.h | 9 +- .../openmc/random_ray/linear_source_domain.h | 5 +- include/openmc/settings.h | 3 +- src/random_ray/flat_source_domain.cpp | 123 ++++---- src/random_ray/linear_source_domain.cpp | 164 ++++++----- src/random_ray/random_ray.cpp | 269 +++++++++--------- src/random_ray/random_ray_simulation.cpp | 251 ++++++++-------- src/settings.cpp | 7 +- 8 files changed, 452 insertions(+), 379 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 16f38cb5667..be08d98965d 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -113,16 +113,19 @@ class FlatSourceDomain { virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; double compute_fixed_source_normalization_factor() const; + virtual void update_external_linear_source(); virtual void compute_first_collided_flux(); virtual void normalize_uncollided_scalar_flux(double number_of_particles); virtual void update_volume_uncollided_flux(); - virtual void update_external_source(); // check if virtual + virtual void update_external_flat_source(); // check if virtual virtual void compute_uncollided_scalar_flux(); // check if virtual virtual int64_t check_fsr_hits(); + //virtual void uncollided_sum_source(); //---------------------------------------------------------------------------- // Static Data members static bool volume_normalized_flux_tallies_; + static bool first_collided_mode; //---------------------------------------------------------------------------- // Public Data members @@ -134,7 +137,9 @@ class FlatSourceDomain { // non-zero external source terms bool new_fsr_fc {true}; // Criteria to First Collided Loop // Check if new cell was hit - int flux_type {0}; // for plotting purposes. + bool negative_flux_check {false}; // Variable to print warning of negative fluxes + + int flux_type {settings::volume_online_option}; // for plotting purposes. // 1D array representing source region starting offset for each OpenMC Cell // in model::cells diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index 996532ec813..7e82147841f 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -41,15 +41,16 @@ class LinearSourceDomain : public FlatSourceDomain { void flux_swap() override; double evaluate_flux_at_point(Position r, int64_t sr, int g) const override; - virtual void update_external_source(); + void update_external_flat_source(); + virtual void update_external_linear_source(); virtual int64_t check_fsr_hits(); virtual void compute_uncollided_scalar_flux(); virtual void compute_first_collided_flux(); virtual void normalize_uncollided_scalar_flux(double number_of_particles); virtual void update_volume_uncollided_flux(); + //virtual void uncollided_sum_source(); //---------------------------------------------------------------------------- // Public Data members - bool new_fsr_fc {true}; vector source_gradients_; vector flux_moments_old_; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 078c293a180..825e6288e78 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -158,7 +158,8 @@ extern double weight_survive; //!< Survival weight after Russian roulette extern bool FIRST_COLLIDED_FLUX; //!< First Collided Mode loop extern int n_uncollided_rays; //!< Number of uncollided rays used extern int n_volume_estimator_rays; //!< Number of rays to estimate volume -extern bool first_collided_mode; //!< Add first collided source in RR +//extern bool first_collided_mode; //!< Add first collided source in RR +extern int volume_online_option;//! Volume online calculation for FC source } // namespace settings diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 2c718b5ac9f..19eaa7536b8 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -25,6 +25,7 @@ namespace openmc { // Static Variable Declarations bool FlatSourceDomain::volume_normalized_flux_tallies_ {false}; +bool FlatSourceDomain::first_collided_mode {false}; FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) { @@ -54,12 +55,14 @@ FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) // Initialize element-wise arrays scalar_flux_new_.assign(n_source_elements_, 0.0); scalar_flux_final_.assign(n_source_elements_, 0.0); - scalar_uncollided_flux_.assign(n_source_elements_,0.0); - scalar_first_collided_flux_.assign(n_source_elements_,0.0); + scalar_uncollided_flux_.assign(n_source_elements_, 0.0); + scalar_first_collided_flux_.assign(n_source_elements_, 0.0); source_.resize(n_source_elements_); external_source_.assign(n_source_elements_, 0.0); tally_task_.resize(n_source_elements_); volume_task_.resize(n_source_regions_); + // + // scalar_flux_new_per_source_.assign(n_source_elements_, 0.0); if (settings::run_mode == RunMode::EIGENVALUE) { // If in eigenvalue mode, set starting flux to guess of unity @@ -113,12 +116,11 @@ void FlatSourceDomain::batch_reset() // zero parallel_fill(scalar_flux_new_, 0.0f); parallel_fill(was_hit_, 0); - if (!settings::FIRST_COLLIDED_FLUX){ - parallel_fill(volume_, 0.0); + if (!settings::FIRST_COLLIDED_FLUX) { + parallel_fill(volume_, 0.0); } } - void FlatSourceDomain::accumulate_iteration_flux() { #pragma omp parallel for @@ -128,23 +130,29 @@ void FlatSourceDomain::accumulate_iteration_flux() } // multiply First Collided Flux by volume and attribute it as fixed source -void FlatSourceDomain::update_external_source() +void FlatSourceDomain::update_external_flat_source() { -#pragma omp parallel for +#pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; - int material = material_[sr]; - if (volume == 0.0f){ + //int material = material_[sr]; + if (volume == 0.0) { for (int g = 0; g < negroups_; g++) { external_source_[sr * negroups_ + g] = 0.0f; } } else { for (int g = 0; g < negroups_; g++) { - external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(volume)); + external_source_[sr * negroups_ + g] = + (scalar_first_collided_flux_[sr * negroups_ + g] / (volume)); } } } } + +void FlatSourceDomain::update_external_linear_source() +{ + // default empty +} // Compute new estimate of scattering + fission sources in each source region // based on the flux estimate from the previous iteration. void FlatSourceDomain::update_neutron_source(double k_eff) @@ -223,27 +231,28 @@ void FlatSourceDomain::normalize_scalar_flux_and_volumes( double volume_normalization_factor = 1.0 / (total_active_distance_per_iteration * simulation::current_batch); -// Normalize scalar flux to total distance travelled by all rays this iteration -if (!settings::FIRST_COLLIDED_FLUX){ + // Normalize scalar flux to total distance travelled by all rays this + // iteration + if (!settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { - scalar_flux_new_[e] *= normalization_factor; - } + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_flux_new_[e] *= normalization_factor; + } // Accumulate cell-wise ray length tallies collected this iteration, then // update the simulation-averaged cell-wise volume estimates #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_t_[sr] += volume_[sr]; - volume_[sr] = volume_t_[sr] * volume_normalization_factor; + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_t_[sr] += volume_[sr]; + volume_[sr] = volume_t_[sr] * volume_normalization_factor; + } } -} - if (settings::FIRST_COLLIDED_FLUX){ + if (settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_[sr] *= (volume_normalization_factor); - } + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_[sr] *= (volume_normalization_factor); + } } } @@ -281,14 +290,22 @@ void FlatSourceDomain::compute_uncollided_scalar_flux() if (was_cell_hit) { float sigma_t = data::mg.macro_xs_[material].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); - scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]/ (sigma_t); + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx] / (sigma_t); } else { - scalar_uncollided_flux_[idx] = 0.0f; + scalar_uncollided_flux_[idx] = 0.0f; } } } } +// void FlatSourceDomain::uncollided_sum_source() +// { +// #pragma omp parallel for +// for (int64_t e = 0; e < scalar_flux_new_.size(); e++){ +// scalar_flux_new_[e] += scalar_flux_new_per_source_[e]; +// } +// } + // Combine transport flux contributions and flat source contributions from the // previous iteration to generate this iteration's estimate of scalar flux. int64_t FlatSourceDomain::add_source_to_scalar_flux() @@ -345,26 +362,28 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux() } // Normalize Uncollided Flux -void FlatSourceDomain::normalize_uncollided_scalar_flux(double number_of_particles) +void FlatSourceDomain::normalize_uncollided_scalar_flux( + double number_of_particles) { // multiply by simulation volume - float normalization_factor = (1.0)/ number_of_particles; - + float normalization_factor = (1.0) / number_of_particles; + // Determine Source_total Scailing factor if first collided double user_external_source_strength = 0.0; - for (auto& ext_source : model::external_sources) { + for (auto& ext_source : model::external_sources) { user_external_source_strength += ext_source->strength(); - } + } - float source_scailing_factor = (user_external_source_strength * normalization_factor); + float source_scailing_factor = + (user_external_source_strength * normalization_factor); #pragma omp parallel for -for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { - scalar_uncollided_flux_[e] *= source_scailing_factor; + for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { + scalar_uncollided_flux_[e] *= source_scailing_factor; } } -//Compute First Collided flux +// Compute First Collided flux void FlatSourceDomain::compute_first_collided_flux() { const int t = 0; @@ -387,7 +406,8 @@ void FlatSourceDomain::compute_first_collided_flux() scatter_fixed_source += sigma_s * scalar_flux; } - scalar_first_collided_flux_[sr * negroups_ + e_out] = scatter_fixed_source / sigma_t; + scalar_first_collided_flux_[sr * negroups_ + e_out] = + scatter_fixed_source / sigma_t; } } } @@ -501,11 +521,11 @@ double FlatSourceDomain::compute_k_eff(double k_eff_old) const void FlatSourceDomain::update_volume_uncollided_flux() { - #pragma omp parallel for +#pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = volume_[sr] * simulation_volume_; for (int g = 0; g < negroups_; g++) { - scalar_uncollided_flux_[sr * negroups_ + g] /= volume; + scalar_uncollided_flux_[sr * negroups_ + g] /= volume; } } } @@ -701,17 +721,22 @@ void FlatSourceDomain::random_ray_tally() double volume = volume_[sr] * simulation_volume_; double material = material_[sr]; float flux = 0.0f; - + for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; - if (settings::first_collided_mode){ - if(RandomRay::source_shape_ == RandomRaySourceShape::FLAT){ - flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); + if (first_collided_mode) { + if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT) { + flux = + (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); + } else if (settings::volume_online_option == 1) { + flux = + (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] )); } else { - flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx])); + flux = + (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); } } else { - flux = (scalar_flux_new_[idx] * source_normalization_factor) ; + flux = (scalar_flux_new_[idx] * source_normalization_factor); } // Determine numerical score value for (auto& task : tally_task_[idx]) { @@ -892,18 +917,18 @@ void FlatSourceDomain::all_reduce_replicated_source_regions() #endif } - // avoid add scalar_uncollided_flux if not using fixed source - first collided double FlatSourceDomain::evaluate_flux_at_point( Position r, int64_t sr, int g) const { - if(!settings::first_collided_mode){ - return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive)); + if (!first_collided_mode) { + return (scalar_flux_final_[sr * negroups_ + g] / + (settings::n_batches - settings::n_inactive)); } else { // add uncollided flux if First Collided method is used return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); + (settings::n_batches - settings::n_inactive) + + scalar_uncollided_flux_[sr * negroups_ + g]); } } @@ -1064,7 +1089,7 @@ void FlatSourceDomain::output_to_vtk() const int mat = material_[fsr]; float sigma_t = data::mg.macro_xs_[mat].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, 0, 0); - float f_source = external_source_[fsr * negroups_ + g]; + float f_source = external_source_[fsr * negroups_ + g]; f_source *= sigma_t; f_source = convert_to_big_endian(f_source); std::fwrite(&f_source, sizeof(float), 1, plot); diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 0682f85db8c..f8db39c0b73 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -29,9 +29,11 @@ LinearSourceDomain::LinearSourceDomain() : FlatSourceDomain() // Source gradients given by M inverse multiplied by source moments source_gradients_.assign(n_source_elements_, {0.0, 0.0, 0.0}); external_source_gradients_.assign(n_source_elements_, {0.0, 0.0, 0.0}); - // First Collided method + // First Collided method flux_moments_uncollided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); flux_moments_first_collided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); + // + // flux_moments_new_per_source_.assign(n_source_elements_, {0.0, 0.0, 0.0}); centroid_.assign(n_source_regions_, {0.0, 0.0, 0.0}); centroid_iteration_.assign(n_source_regions_, {0.0, 0.0, 0.0}); @@ -50,7 +52,9 @@ void LinearSourceDomain::batch_reset() #pragma omp parallel for for (int64_t sr = 0; sr < n_source_regions_; sr++) { centroid_iteration_[sr] = {0.0, 0.0, 0.0}; + if(!settings::FIRST_COLLIDED_FLUX){ mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + } } } @@ -70,33 +74,40 @@ int64_t LinearSourceDomain::check_fsr_hits() return n_hits; } -void LinearSourceDomain::update_external_source() +void LinearSourceDomain::update_external_flat_source() { - // Temperature and angle indices, if using multiple temperature - // data sets and/or anisotropic data sets. - // TODO: Currently assumes we are only using single temp/single - // angle data. - const int t = 0; - const int a = 0; + FlatSourceDomain::update_external_flat_source(); +} +// void LinearSourceDomain::uncollided_sum_source() +// { +// #pragma omp parallel for +// for (int64_t e = 0; e < scalar_flux_new_.size(); e++){ +// scalar_flux_new_[e] += scalar_flux_new_per_source_[e]; +// flux_moments_new_[e] += flux_moments_new_per_source_[e]; +// } +// } + +void LinearSourceDomain::update_external_linear_source() +{ #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { - int material = material_[sr]; - - // multiply First Collided Flux by volume and attribute it as external_source double volume = simulation_volume_ * volume_[sr]; - for (int g = 0; g < negroups_; g++) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); - if (volume == 0.0f){ - external_source_[sr * negroups_ + g] = 0.0f; - external_source_gradients_[sr * negroups_ + g] = {0.0, 0.0, 0.0}; - } else { - external_source_[sr * negroups_ + g] = (scalar_first_collided_flux_[sr * negroups_ + g] /(volume)); - external_source_gradients_[sr * negroups_ + g] = (flux_moments_first_collided_[sr * negroups_ + g] /(volume)); - } + MomentMatrix invM = mom_matrix_[sr].inverse(); + + // multiply First Collided Flux by volume and attribute it as + // external_source + if (volume == 0.0f) { + for (int g = 0; g < negroups_; g++) { + external_source_gradients_[sr * negroups_ + g] = {0.0, 0.0, 0.0}; + } + } else { + for (int g = 0; g < negroups_; g++) { + external_source_gradients_[sr * negroups_ + g] = + invM * (flux_moments_first_collided_[sr * negroups_ + g] / (volume)); } + } } } @@ -113,8 +124,6 @@ void LinearSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; - - #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { @@ -154,6 +163,10 @@ void LinearSourceDomain::update_neutron_source(double k_eff) source_[sr * negroups_ + e_out] = (scatter_flat + fission_flat * inverse_k_eff) / sigma_t; + // Check for negative source_ values + //if (source_[sr * negroups_ + e_out] < 0.0f) { + // negative_flux_check = {true}; + //} // Compute the linear source terms if (simulation::current_batch > 2) { source_gradients_[sr * negroups_ + e_out] = @@ -162,6 +175,10 @@ void LinearSourceDomain::update_neutron_source(double k_eff) } } + // if(negative_flux_check){ + // warning("source_ has negative values!"); + // } + if (settings::run_mode == RunMode::FIXED_SOURCE) { // Add external source to flat source term if in fixed source mode #pragma omp parallel for @@ -181,47 +198,46 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( double volume_normalization_factor = 1.0 / (total_active_distance_per_iteration * simulation::current_batch); -// Normalize flux to total distance travelled by all rays this iteration -if (!settings::FIRST_COLLIDED_FLUX){ + // Normalize flux to total distance travelled by all rays this iteration + if (!settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { - scalar_flux_new_[e] *= normalization_factor; - flux_moments_new_[e] *= normalization_factor; - } + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_flux_new_[e] *= normalization_factor; + flux_moments_new_[e] *= normalization_factor; + } // Accumulate cell-wise ray length tallies collected this iteration, then // update the simulation-averaged cell-wise volume estimates #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - centroid_t_[sr] += centroid_iteration_[sr]; - mom_matrix_t_[sr] += mom_matrix_[sr]; - volume_t_[sr] += volume_[sr]; - volume_[sr] = volume_t_[sr] * volume_normalization_factor; - if (volume_t_[sr] > 0.0) { - double inv_volume = 1.0 / volume_t_[sr]; - centroid_[sr] = centroid_t_[sr]; - centroid_[sr] *= inv_volume; - mom_matrix_[sr] = mom_matrix_t_[sr]; - mom_matrix_[sr] *= inv_volume; + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + centroid_t_[sr] += centroid_iteration_[sr]; + mom_matrix_t_[sr] += mom_matrix_[sr]; + volume_t_[sr] += volume_[sr]; + volume_[sr] = volume_t_[sr] * volume_normalization_factor; + if (volume_t_[sr] > 0.0) { + double inv_volume = 1.0 / volume_t_[sr]; + centroid_[sr] = centroid_t_[sr]; + centroid_[sr] *= inv_volume; + mom_matrix_[sr] = mom_matrix_t_[sr]; + mom_matrix_[sr] *= inv_volume; + } } } - } -// just fuse to the other IF STATEMENT -if (settings::FIRST_COLLIDED_FLUX){ + // just fuse to the other IF STATEMENT + if (settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_[sr] *= volume_normalization_factor; - if (volume_[sr] > 0.0) { - double inv_volume = 1.0 / volume_[sr]; - centroid_[sr] = centroid_iteration_[sr]; - centroid_[sr] *= inv_volume; - mom_matrix_[sr] = mom_matrix_[sr]; - mom_matrix_[sr] *= inv_volume; + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_[sr] *= volume_normalization_factor; + if (volume_[sr] > 0.0) { + double inv_volume = 1.0 / volume_[sr]; + centroid_[sr] = centroid_iteration_[sr]; + centroid_[sr] *= inv_volume; + mom_matrix_[sr] = mom_matrix_[sr]; + mom_matrix_[sr] *= inv_volume; + } } } - } - } void LinearSourceDomain::compute_uncollided_scalar_flux() @@ -233,7 +249,6 @@ void LinearSourceDomain::compute_uncollided_scalar_flux() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int was_cell_hit = was_hit_[sr]; - double volume = volume_[sr]; int material = material_[sr]; for (int g = 0; g < negroups_; g++) { @@ -299,35 +314,37 @@ int64_t LinearSourceDomain::add_source_to_scalar_flux() scalar_flux_new_[idx] = 0.0f; flux_moments_new_[idx] *= 0.0; } - } } + } return n_hits; } // Normalize Uncollided Flux -void LinearSourceDomain::normalize_uncollided_scalar_flux(double number_of_particles) +void LinearSourceDomain::normalize_uncollided_scalar_flux( + double number_of_particles) { // multiply by simulation volume - float normalization_factor = (1.0)/ number_of_particles; - // Determine Source_total Scailing factor if first collided + float normalization_factor = (1.0) / number_of_particles; + // Determine Source_total Scailing factor if first collided double user_external_source_strength = 0.0; - for (auto& ext_source : model::external_sources) { + for (auto& ext_source : model::external_sources) { user_external_source_strength += ext_source->strength(); - } - //fmt::print("total_source_strength = {}\n", total_source_intensity); + } + // fmt::print("total_source_strength = {}\n", total_source_intensity); - float source_scailing_factor = (user_external_source_strength * normalization_factor); + double source_scailing_factor = + user_external_source_strength * normalization_factor; #pragma omp parallel for for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { - scalar_uncollided_flux_[e] *= source_scailing_factor; - flux_moments_uncollided_[e] *= source_scailing_factor; + scalar_uncollided_flux_[e] *= source_scailing_factor; + flux_moments_uncollided_[e] *= source_scailing_factor; } } -//Compute First Collided flux +// Compute First Collided flux void LinearSourceDomain::compute_first_collided_flux() { const int t = 0; @@ -337,7 +354,7 @@ void LinearSourceDomain::compute_first_collided_flux() for (int sr = 0; sr < n_source_regions_; sr++) { int material = material_[sr]; - MomentMatrix invM = mom_matrix_[sr].inverse(); + // MomentMatrix invM = mom_matrix_[sr].inverse(); for (int e_out = 0; e_out < negroups_; e_out++) { float sigma_t = data::mg.macro_xs_[material].get_xs( @@ -349,7 +366,8 @@ void LinearSourceDomain::compute_first_collided_flux() for (int e_in = 0; e_in < negroups_; e_in++) { // Handles for the flat and linear components of the flux float flux_flat = scalar_uncollided_flux_[sr * negroups_ + e_in]; - MomentArray flux_linear = flux_moments_uncollided_[sr * negroups_ + e_in]; + MomentArray flux_linear = + flux_moments_uncollided_[sr * negroups_ + e_in]; // Handles for cross sections float sigma_s = data::mg.macro_xs_[material].get_xs( @@ -365,8 +383,8 @@ void LinearSourceDomain::compute_first_collided_flux() (scatter_flat) / sigma_t; // Compute the linear source terms - flux_moments_first_collided_[sr * negroups_ + e_out] = - invM * ((scatter_linear) / sigma_t); + flux_moments_first_collided_[sr * negroups_ + e_out] = + ((scatter_linear) / sigma_t); // invM * } } } @@ -426,7 +444,7 @@ double LinearSourceDomain::evaluate_flux_at_point( Position local_r = r - centroid_[sr]; MomentArray phi_linear = flux_moments_t_[sr * negroups_ + g]; phi_linear *= 1.0 / (settings::n_batches - settings::n_inactive); - if (settings::first_collided_mode){ + if (first_collided_mode) { phi_linear += flux_moments_uncollided_[sr * negroups_ + g]; // ??? addition } @@ -438,17 +456,17 @@ double LinearSourceDomain::evaluate_flux_at_point( void LinearSourceDomain::update_volume_uncollided_flux() { - #pragma omp parallel for +#pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = volume_[sr] * simulation_volume_; - if (volume != 0.0f){ + if (volume != 0.0f) { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] /= volume; flux_moments_uncollided_[sr * negroups_ + g] /= volume; } } else { for (int g = 0; g < negroups_; g++) { - scalar_uncollided_flux_[sr * negroups_ + g] =0.0f; + scalar_uncollided_flux_[sr * negroups_ + g] = 0.0f; flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; } } diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 7ac4a3155b7..24112796ede 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -294,22 +294,22 @@ void RandomRay::event_advance_ray_first_collided() boundary() = distance_to_boundary(*this); double distance = boundary().distance; - if (distance <= 0.0) { + if (distance <= 0.0) { mark_as_lost("Negative transport distance detected for particle " + std::to_string(id())); return; } // For Uncollided/First Collided Flux, it is calculated the attenuation - // as the ray advance through the region and a check if the outcoming + // as the ray advance through the region and a check if the outcoming // flux reaches the defined threshold. - distance_travelled_ += distance; - attenuate_flux(distance, true); + distance_travelled_ += distance; + attenuate_flux(distance, true); // Advance particle for (int j = 0; j < n_coord(); ++j) { coord(j).r += distance * coord(j).u; } - //total_distance_track_ = distance_travelled_; + // total_distance_track_ = distance_travelled_; } void RandomRay::attenuate_flux(double distance, bool is_active) @@ -364,17 +364,18 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) const int a = 0; // MOC incoming flux attenuation + source contribution/attenuation equation - if (!uncollided_flux_volume){ - for (int g = 0; g < negroups_; g++) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); - float tau = sigma_t * distance; - float exponential = cjosey_exponential(tau); // exponential = 1 - exp(-tau) - float new_delta_psi = - (angular_flux_[g] - domain_->source_[source_element + g]) * exponential; - delta_psi_[g] = new_delta_psi; - angular_flux_[g] -= new_delta_psi; - } + if (!uncollided_flux_volume) { + for (int g = 0; g < negroups_; g++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + float tau = sigma_t * distance; + float exponential = + cjosey_exponential(tau); // exponential = 1 - exp(-tau) + float new_delta_psi = + (angular_flux_[g] - domain_->source_[source_element + g]) * exponential; + delta_psi_[g] = new_delta_psi; + angular_flux_[g] -= new_delta_psi; + } } // If ray is in the active phase (not in dead zone), make contributions to @@ -384,9 +385,19 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Aquire lock for source region domain_->lock_[source_region].lock(); - // Accumulate delta psi into new estimate of source region flux for - // this iteration - if (!uncollided_flux_volume){ + if (!settings::FIRST_COLLIDED_FLUX) { + // Accumulate delta psi into new estimate of source region flux for + // this iteration + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + } + // Accomulate volume (ray distance) into this iteration's estimate + // of the source region's volume + domain_->volume_[source_region] += distance; + + } else if (uncollided_flux_volume) { + domain_->volume_[source_region] += distance; + } else { for (int g = 0; g < negroups_; g++) { domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; } @@ -396,14 +407,6 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // indicate that it now has if (domain_->was_hit_[source_region] == 0) { domain_->was_hit_[source_region] = 1; - // Check if new cell was hit and change for true - //domain_->new_fsr_fc = {true}; - } - - // Accomulate volume (ray distance) into this iteration's estimate - // of the source region's volume - if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume){ - domain_->volume_[source_region] += distance; } // Tally valid position inside the source region (e.g., midpoint of @@ -413,35 +416,39 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) domain_->position_[source_region] = midpoint; domain_->position_recorded_[source_region] = 1; } - // Release lock domain_->lock_[source_region].unlock(); - // check attenuation in FIRST_ COLLIDED_FLUX - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ + // check attenuation in FIRST_ COLLIDED_FLUX + // There is likely that an extra length of the rebounded ray after vacuum + // BC is being considered here, however, it does not impact volume calculations + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { // bool = true to kill ray // ray is killed by default unless: bool angular_flux_below_threshold = true; - for (int g = 0; g < negroups_; g++) { - // check if initial angular flux in that energy group is zero, therefore there is no ratio - // kill contidion given in absolute value (smaller than ray_threshold) + for (int g = 0; g < negroups_; g++) { + // check if initial angular flux in that energy group is zero, therefore + // there is no ratio kill contidion given in absolute value (smaller + // than ray_threshold) if (angular_flux_initial_[g] == 0) { - // If initial angular flux is zero and below threshold, passes as true to kill the ray - if(angular_flux_[g] >= ray_threshold){ + // If initial angular flux is zero and below threshold, passes as true + // to kill the ray + if (angular_flux_[g] >= ray_threshold) { angular_flux_below_threshold = false; break; } - // if angular_flux_[g] is less than threshold, it passes as true to kill ray + // if angular_flux_[g] is less than threshold, it passes as true to + // kill ray } else { // calculate the attenuation of ray (kills if ratio below threshold) - float ratio = angular_flux_[g] / angular_flux_initial_[g]; + float ratio = angular_flux_[g] / angular_flux_initial_[g]; if (ratio >= ray_threshold) { angular_flux_below_threshold = false; break; } } } - if (angular_flux_below_threshold){ + if (angular_flux_below_threshold) { wgt() = 0.0; } } @@ -478,11 +485,9 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) const int t = 0; const int a = 0; - Position& centroid = domain->centroid_[source_region]; Position midpoint = r() + u() * (distance / 2.0); - // Determine the local position of the midpoint and the ray origin // relative to the source region's centroid Position rm_local; @@ -493,8 +498,8 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // be no estimate of its centroid. We detect this by checking if it has // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. - if(settings::FIRST_COLLIDED_FLUX){ /// TRIPLE CHECK THIS - if (domain->volume_[source_region] == 0.0) { + if (settings::FIRST_COLLIDED_FLUX) { /// TRIPLE CHECK THIS + if (domain->volume_[source_region] != 0.0f) { rm_local = midpoint - centroid; r0_local = r() - centroid; } else { @@ -508,65 +513,66 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) } else { rm_local = {0.0, 0.0, 0.0}; r0_local = -u() * 0.5 * distance; - } + } } double distance_2 = distance * distance; // Linear Source MOC incoming flux attenuation + source // contribution/attenuation equation - if (!uncollided_flux_volume){ - for (int g = 0; g < negroups_; g++) { - - // Compute tau, the optical thickness of the ray segment - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); - float tau = sigma_t * distance; - - // If tau is very small, set it to zero to avoid numerical issues. - // The following computations will still work with tau = 0. - if (tau < 1.0e-8f) { - tau = 0.0f; - } + if (!uncollided_flux_volume) { + for (int g = 0; g < negroups_; g++) { - // Compute linear source terms, spatial and directional (dir), - // calculated from the source gradients dot product with local centroid - // and direction, respectively. - float spatial_source = - domain_->source_[source_element + g] + - rm_local.dot(domain->source_gradients_[source_element + g]); - float dir_source = u().dot(domain->source_gradients_[source_element + g]); - - float gn = exponentialG(tau); - float f1 = 1.0f - tau * gn; - float f2 = (2.0f * gn - f1) * distance_2; - float new_delta_psi = (angular_flux_[g] - spatial_source) * f1 * distance - - 0.5 * dir_source * f2; - - float h1 = f1 - gn; - float g1 = 0.5f - h1; - float g2 = exponentialG2(tau); - g1 = g1 * spatial_source; - g2 = g2 * dir_source * distance * 0.5f; - h1 = h1 * angular_flux_[g]; - h1 = (g1 + g2 + h1) * distance_2; - spatial_source = spatial_source * distance + new_delta_psi; - - // Store contributions for this group into arrays, so that they can - // be accumulated into the source region's estimates inside of the locked - // region. - delta_psi_[g] = new_delta_psi; - delta_moments_[g] = r0_local * spatial_source + u() * h1; - - // Update the angular flux for this group - angular_flux_[g] -= new_delta_psi * sigma_t; - - // If 2D mode is enabled, the z-component of the flux moments is forced - // to zero - if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { - delta_moments_[g].z = 0.0; + // Compute tau, the optical thickness of the ray segment + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + float tau = sigma_t * distance; + + // If tau is very small, set it to zero to avoid numerical issues. + // The following computations will still work with tau = 0. + if (tau < 1.0e-8f) { + tau = 0.0f; + } + + // Compute linear source terms, spatial and directional (dir), + // calculated from the source gradients dot product with local centroid + // and direction, respectively. + float spatial_source = + domain_->source_[source_element + g] + + rm_local.dot(domain->source_gradients_[source_element + g]); + float dir_source = u().dot(domain->source_gradients_[source_element + g]); + + float gn = exponentialG(tau); + float f1 = 1.0f - tau * gn; + float f2 = (2.0f * gn - f1) * distance_2; + float new_delta_psi = + (angular_flux_[g] - spatial_source) * f1 * distance - + 0.5 * dir_source * f2; + + float h1 = f1 - gn; + float g1 = 0.5f - h1; + float g2 = exponentialG2(tau); + g1 = g1 * spatial_source; + g2 = g2 * dir_source * distance * 0.5f; + h1 = h1 * angular_flux_[g]; + h1 = (g1 + g2 + h1) * distance_2; + spatial_source = spatial_source * distance + new_delta_psi; + + // Store contributions for this group into arrays, so that they can + // be accumulated into the source region's estimates inside of the locked + // region. + delta_psi_[g] = new_delta_psi; + delta_moments_[g] = r0_local * spatial_source + u() * h1; + + // Update the angular flux for this group + angular_flux_[g] -= new_delta_psi * sigma_t; + + // If 2D mode is enabled, the z-component of the flux moments is forced + // to zero + if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { + delta_moments_[g].z = 0.0; + } } } - } // If ray is in the active phase (not in dead zone), make contributions to // source region bookkeeping @@ -582,7 +588,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Accumulate deltas into the new estimate of source region flux for this // iteration - if (!uncollided_flux_volume){ + if (!uncollided_flux_volume) { for (int g = 0; g < negroups_; g++) { domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; domain->flux_moments_new_[source_element + g] += delta_moments_[g]; @@ -593,15 +599,13 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // momement estimates into the running totals for the iteration for this // source region. The centroid and spatial momements estimates are scaled by // the ray segment length as part of length averaging of the estimates. - if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume){ + if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume) { domain_->volume_[source_region] += distance; domain->centroid_iteration_[source_region] += midpoint * distance; moment_matrix_estimate *= distance; domain->mom_matrix_[source_region] += moment_matrix_estimate; } - - // If the source region hasn't been hit yet this iteration, // indicate that it now has if (domain_->was_hit_[source_region] == 0) { @@ -618,38 +622,41 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Release lock domain_->lock_[source_region].unlock(); - // check attenuation in FIRST_ COLLIDED_FLUX - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ + // check attenuation in FIRST_ COLLIDED_FLUX + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { // bool = true to kill ray // ray is killed by default unless: bool angular_flux_below_threshold = true; for (int g = 0; g < negroups_; g++) { - // check if initial angular flux in that energy group is zero, therefore there is no ratio - // kill contidion given in absolute value (smaller than ray_threshold) + // check if initial angular flux in that energy group is zero, therefore + // there is no ratio kill contidion given in absolute value (smaller + // than ray_threshold) if (angular_flux_initial_[g] == 0) { - // If initial angular flux is zero and below threshold, passes as true to kill the ray - if(angular_flux_[g] >= ray_threshold){ + // If initial angular flux is zero and below threshold, passes as true + // to kill the ray + if (angular_flux_[g] >= ray_threshold) { angular_flux_below_threshold = false; break; } - // if angular_flux_[g] is less than threshold, it passes as true to kill ray + // if angular_flux_[g] is less than threshold, it passes as true to + // kill ray } else { // calculate the attenuation of ray (kills if ratio below threshold) - float ratio = angular_flux_[g] / angular_flux_initial_[g]; + float ratio = angular_flux_[g] / angular_flux_initial_[g]; if (ratio >= ray_threshold) { angular_flux_below_threshold = false; break; } } } - if (angular_flux_below_threshold){ + if (angular_flux_below_threshold) { wgt() = 0.0; } } } } -//updated +// updated void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) { domain_ = domain; @@ -664,10 +671,10 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) // set identifier for particle id() = simulation::work_index[mpi::rank] + ray_id; - if (settings::FIRST_COLLIDED_FLUX){ + if (settings::FIRST_COLLIDED_FLUX) { simulation::current_batch = 1; - } - + } + // set random number seed int64_t particle_seed = (simulation::current_batch - 1) * settings::n_particles + id(); @@ -675,35 +682,35 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) stream() = STREAM_TRACKING; // Sample from input Source - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume){ + if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { auto site = sample_external_source(current_seed()); - site.E = lower_bound_index( - data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); + site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), + data::mg.rev_energy_bins_.end(), site.E); site.E = negroups_ - site.E - 1.; from_source(&site); - std::unique_ptr& source_handle = model::external_sources[site.source_id]; - IndependentSource* is = dynamic_cast(source_handle.get()); + std::unique_ptr& source_handle = + model::external_sources[site.source_id]; + IndependentSource* is = + dynamic_cast(source_handle.get()); Discrete* energy_external_source = dynamic_cast(is->energy()); + // double strength_factor = is->strength(); + const auto& discrete_energies = energy_external_source->x(); const auto& discrete_probs = energy_external_source->prob_actual(); - //for (const auto& prob : discrete_probs) { - // fmt::print("{:.3f}\n", prob); - //} - //double source_strength = is->strength(); - - for (int e = 0; e < discrete_energies.size(); e++) { - int g = data::mg.get_group_index(discrete_energies[e]); - angular_flux_[g] = discrete_probs[e];//source_strength * / sigma_t; - angular_flux_initial_[g] = angular_flux_[g]; - } + + for (int e = 0; e < discrete_energies.size(); e++) { + int g = data::mg.get_group_index(discrete_energies[e]); + angular_flux_[g] = discrete_probs[e]; // source_strength * / sigma_t; + angular_flux_initial_[g] = angular_flux_[g]; + } } else { // Sample from ray source distribution SourceSite site {ray_source_->sample(current_seed())}; - site.E = lower_bound_index( - data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); + site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), + data::mg.rev_energy_bins_.end(), site.E); site.E = negroups_ - site.E - 1.; this->from_source(&site); } @@ -721,19 +728,17 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) } // initialize ray's starting angular flux spectrum - if(!settings::FIRST_COLLIDED_FLUX){ + if (!settings::FIRST_COLLIDED_FLUX) { // Initialize ray's starting angular flux to starting location's isotropic // source int i_cell = lowest_coord().cell; int64_t source_region_idx = - domain_->source_region_offsets_[i_cell] + cell_instance(); + domain_->source_region_offsets_[i_cell] + cell_instance(); for (int g = 0; g < negroups_; g++) { - angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; } } } - - } // namespace openmc diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 8092fa07e8f..e2294cc9b83 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -177,10 +177,10 @@ void validate_random_ray_inputs() // Validate that a domain ID was specified if (is->domain_ids().size() == 0) { - if (!settings::FIRST_COLLIDED_FLUX){ - fatal_error("Fixed sources must be specified by domain " - "id (cell, material, or universe) in random ray mode."); - } else if (settings::FIRST_COLLIDED_FLUX){ + if (!settings::FIRST_COLLIDED_FLUX) { + fatal_error("Fixed sources must be specified by domain " + "id (cell, material, or universe) in random ray mode."); + } else if (settings::FIRST_COLLIDED_FLUX) { // fmt::print("??? add First collided condition and fatal error here\n"); } @@ -253,6 +253,8 @@ RandomRaySimulation::RandomRaySimulation() domain_ = make_unique(); break; case RandomRaySourceShape::LINEAR: + domain_ = make_unique(); + break; case RandomRaySourceShape::LINEAR_XY: domain_ = make_unique(); break; @@ -264,124 +266,132 @@ RandomRaySimulation::RandomRaySimulation() void RandomRaySimulation::simulate() { if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (settings::FIRST_COLLIDED_FLUX == false){ - // Transfer external source user inputs onto random ray source regions - domain_->convert_external_sources(); - domain_->count_external_source_regions(); + if (settings::FIRST_COLLIDED_FLUX == false) { + // Transfer external source user inputs onto random ray source regions + domain_->convert_external_sources(); + domain_->count_external_source_regions(); } else { - // FIRST_COLLIDED_FLUX calculation routine: - fmt::print("==============> FIRST COLLIDED SOURCE CONVERSION <=================\n\n"); - - //============================================================================== - // Turn on volume pre calculation - double start_volume_estimation = omp_get_wtime(); - fmt::print("Computing starting volume estimates... \n"); - RandomRay::uncollided_flux_volume = true; - simulation::current_batch = 1; - - // Pre calculate volume + // FIRST_COLLIDED_FLUX calculation routine: + fmt::print("==============> FIRST COLLIDED SOURCE CONVERSION " + "<=================\n\n"); + + //============================================================================== + // Turn on volume pre calculation + double start_volume_estimation = omp_get_wtime(); + fmt::print("Computing starting volume estimates... \n"); + RandomRay::uncollided_flux_volume = true; + simulation::current_batch = 1; + + // Pre calculate volume #pragma omp parallel for schedule(dynamic) \ reduction(+ : total_geometric_intersections_) - for (int i =0; i< settings::n_volume_estimator_rays; i++){ - RandomRay ray(i, domain_.get()); - total_geometric_intersections_ += - ray.transport_history_based_single_ray(); - } - - // Normalizing volumes - domain_->normalize_scalar_flux_and_volumes(settings::n_volume_estimator_rays * RandomRay::distance_active_); - - // Print volume estimation simulation time - double end_volume_estimation = omp_get_wtime(); - fmt::print("Volume estimation completed.\n"); - fmt::print("Run time = {:.4f} \n\n", end_volume_estimation-start_volume_estimation); - - // Reset parameters for First Collided Method - RandomRay::uncollided_flux_volume = false; - domain_->batch_reset(); - - - - //============================================================================== - // First Collided Transport Loop - // It will operate until (1-3): - // (1) There is no new FSR hits from one (n-1) iteration to the next (n) - // (2) Reached pre-set maximum n_uncollided_rays - // (3) Hit 100% of the FSRs - fmt::print(" Batch Rays Total Source Regions Discovered\n" - " ====== ========== ================================\n"); - - //TO-do - // SET-UP for user input n_uncollided_rays - if (user_input_rays == true){ - new_n_rays = n_rays_max; - } - - while(domain_->new_fsr_fc){ - - // loop will end if no new cell was hit -> n_new_hits = n_old_hits - //domain_->new_fsr_fc = {false}; - // Ray tracing and attenuation -#pragma omp parallel for schedule(dynamic) \ - reduction(+ : total_geometric_intersections_) - for (int i = old_n_rays; i< new_n_rays; i++){ + for (int i = 0; i < settings::n_volume_estimator_rays; i++) { RandomRay ray(i, domain_.get()); total_geometric_intersections_ += - ray.transport_history_based_single_ray_first_collided(); + ray.transport_history_based_single_ray(); } - int64_t n_hits_new = domain_->check_fsr_hits(); - - // print results - fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); - - // BREAK STATEMENT if Max rays reached or 100% FSR HIT - old_n_rays = new_n_rays; - if (n_hits_new == n_hits_old){ - domain_->new_fsr_fc = {false}; - break; - } else if (new_n_rays >= n_rays_max) { - domain_->new_fsr_fc = {false}; - //Uncollided rays limit achieved - // To-do : if user input max_rays is given, this will cause the batch to end - break; - } else if (static_cast(n_hits_new) >= domain_->n_source_regions_){ - domain_->new_fsr_fc = {false}; - break; - } - - // update values for next batch - new_n_rays *= 2; - batch_first_collided++; - n_hits_old = n_hits_new; - } - - // Compute scalar_uncollided_flux - domain_->compute_uncollided_scalar_flux(); + // fmt::print("simulation_batch = {:}", simulation::current_batch); + // Normalizing volumes + domain_->normalize_scalar_flux_and_volumes( + settings::n_volume_estimator_rays * RandomRay::distance_active_); + + // Print volume estimation simulation time + double end_volume_estimation = omp_get_wtime(); + fmt::print("Volume estimation completed.\n"); + fmt::print("Run time = {:.4f} \n\n", + end_volume_estimation - start_volume_estimation); + + // Reset parameters for First Collided Method + RandomRay::uncollided_flux_volume = false; + domain_->batch_reset(); + + //============================================================================== + // First Collided Transport Loop + // It will operate until (1-3): + // (1) There is no new FSR hits from one (n-1) iteration to the next (n) + // (2) Reached pre-set maximum n_uncollided_rays + // (3) Hit 100% of the FSRs + fmt::print(" Batch Rays Total Source Regions Discovered\n" + " ====== ========== ================================\n"); + while (domain_->new_fsr_fc) { + + // Ray tracing and attenuation +#pragma omp parallel for schedule(dynamic) \ + reduction(+ : total_geometric_intersections_) + for (int i = old_n_rays; i < new_n_rays; i++) { + RandomRay ray(i, domain_.get()); + total_geometric_intersections_ += + ray.transport_history_based_single_ray_first_collided(); + } - // Normalize scalar_uncollided_flux - domain_->normalize_uncollided_scalar_flux(new_n_rays); + int64_t n_hits_new = domain_->check_fsr_hits(); - // compute first_collided_fixed_source - - domain_->compute_first_collided_flux(); + // print results + fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, + n_hits_new); - if(RandomRay::source_shape_ == RandomRaySourceShape::LINEAR ||RandomRay::source_shape_ == RandomRaySourceShape::LINEAR_XY){ - domain_->update_volume_uncollided_flux(); - domain_->update_external_source(); - } + // BREAK STATEMENT if Max rays reached or 100% FSR HIT - // reset values for RandomRay iteration - settings::first_collided_mode = {true}; // add FC contribution to RR - settings::FIRST_COLLIDED_FLUX = {false}; //move to regular fixed source RR calculations + if (n_hits_new == n_hits_old) { + domain_->new_fsr_fc = {false}; + } else if (new_n_rays >= n_rays_max) { + domain_->new_fsr_fc = {false}; + } else if (static_cast(n_hits_new) >= + domain_->n_source_regions_) { + domain_->new_fsr_fc = {false}; + } + // Section to add in n_source_calculations + // domain_->normalize_uncollided_scalar_flux(new_n_rays); + // domain_->uncollided_sum_source(); + + // update values for next batch + old_n_rays = new_n_rays; + new_n_rays *= 2; + batch_first_collided++; + n_hits_old = n_hits_new; + } - //make sure all paremeters are - domain_->batch_reset(); // clean-up scalar_flux_new and was_hit (preserves volume) - simulation::current_batch = 0; //garantee the first batch will be 1 in RR + // fmt::print("old_n_rays = {:} and new_n_rays = {:}\n", old_n_rays, + // new_n_rays); + // Compute scalar_uncollided_flux + domain_->compute_uncollided_scalar_flux(); + + // Normalize scalar_uncollided_flux + domain_->normalize_uncollided_scalar_flux(old_n_rays); + + // compute first_collided_fixed_source - + domain_->compute_first_collided_flux(); + + // Compute external source a priori. + if (settings::volume_online_option == 1) { + domain_->update_external_linear_source(); + domain_->update_external_flat_source(); // comment if option 2 + domain_->update_volume_uncollided_flux(); // comment if option 2 + fmt::print("Flux and moments are calculated a priori to RR \n"); + } else if (settings::volume_online_option == 2) { + domain_->update_external_linear_source(); + fmt::print("Moments are calculated a priori to RR \n"); + } else { + fmt::print("Flux and moments are updated online in RR \n"); + } - // compute First Collided Method simulation time - double first_collided_estimated_time = omp_get_wtime(); - fmt::print(" ====== ========== ================================\n\n"); - fmt::print("First Collided Method run time = {:.4f} \n\n", first_collided_estimated_time-end_volume_estimation); + // Reset Terms to RR method + domain_->batch_reset(); // clean-up of key variables (preserves volume) + simulation::current_batch = 0; // garantee the first batch will be 1 in RR + + // reset values for RandomRay iteration + domain_->first_collided_mode = {true}; // add FC contribution to RR + settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations + + // fmt::print("first_collided_mode = {:}\n", + // domain_->first_collided_mode); + // compute First Collided Method simulation time + double first_collided_estimated_time = omp_get_wtime(); + fmt::print( + " ====== ========== ================================\n\n"); + fmt::print("First Collided Method run time = {:.4f} \n\n", + first_collided_estimated_time - end_volume_estimation); } } @@ -396,10 +406,15 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT && settings::first_collided_mode){ - domain_->update_external_source(); - } + if (domain_->first_collided_mode) { + if (settings::volume_online_option == 2) { + domain_->update_external_flat_source(); + } else if (settings::volume_online_option == 3) { + domain_->update_external_flat_source(); + domain_->update_external_linear_source(); + } + } // Update source term (scattering + fission) domain_->update_neutron_source(k_eff_); @@ -465,8 +480,10 @@ void RandomRaySimulation::simulate() finalize_batch(); } // End random ray power iteration loop - if(RandomRay::source_shape_ == RandomRaySourceShape::FLAT){ - domain_->update_volume_uncollided_flux(); + if (domain_->first_collided_mode) { + if (settings::volume_online_option != 1) { + domain_->update_volume_uncollided_flux(); + } } } @@ -546,9 +563,9 @@ void RandomRaySimulation::print_results_random_ray( fmt::print( " Total Iterations = {}\n", settings::n_batches); fmt::print(" Flat Source Regions (FSRs) = {}\n", n_source_regions); - if(!settings::first_collided_mode){ - fmt::print( - " FSRs Containing External Sources = {}\n", n_external_source_regions); + if (!domain_->first_collided_mode) { + fmt::print( + " FSRs Containing External Sources = {}\n", n_external_source_regions); } fmt::print(" Total Geometric Intersections = {:.4e}\n", static_cast(total_geometric_intersections)); diff --git a/src/settings.cpp b/src/settings.cpp index e1afca0f63f..648fa92b3a5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -135,9 +135,10 @@ double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {200000}; -int n_volume_estimator_rays {1000000}; -bool first_collided_mode {false}; +int n_uncollided_rays {10000}; +int n_volume_estimator_rays {10000}; +//bool first_collided_mode {false}; +int volume_online_option {2}; } // namespace settings From a51c4ab66afa780bff3a10535846ad2d3dcd5a20 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 1 Aug 2024 17:27:46 -0500 Subject: [PATCH 11/27] linear_source_fix_final_1 --- .../openmc/random_ray/flat_source_domain.h | 3 +- .../openmc/random_ray/linear_source_domain.h | 4 +- src/random_ray/flat_source_domain.cpp | 36 ++++---- src/random_ray/linear_source_domain.cpp | 90 +++++++++++-------- src/random_ray/random_ray.cpp | 2 +- src/random_ray/random_ray_simulation.cpp | 32 +++---- src/settings.cpp | 7 +- 7 files changed, 94 insertions(+), 80 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index be08d98965d..bf3d986d5a0 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -120,7 +120,8 @@ class FlatSourceDomain { virtual void update_external_flat_source(); // check if virtual virtual void compute_uncollided_scalar_flux(); // check if virtual virtual int64_t check_fsr_hits(); - //virtual void uncollided_sum_source(); + virtual void uncollided_moments(); + virtual void batch_reset_fc(); //---------------------------------------------------------------------------- // Static Data members diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index 7e82147841f..4412ce83af1 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -48,7 +48,9 @@ class LinearSourceDomain : public FlatSourceDomain { virtual void compute_first_collided_flux(); virtual void normalize_uncollided_scalar_flux(double number_of_particles); virtual void update_volume_uncollided_flux(); - //virtual void uncollided_sum_source(); + virtual void uncollided_moments(); + virtual void batch_reset_fc(); + //---------------------------------------------------------------------------- // Public Data members diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 19eaa7536b8..f14e1207fdb 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -116,9 +116,16 @@ void FlatSourceDomain::batch_reset() // zero parallel_fill(scalar_flux_new_, 0.0f); parallel_fill(was_hit_, 0); - if (!settings::FIRST_COLLIDED_FLUX) { - parallel_fill(volume_, 0.0); - } + parallel_fill(volume_, 0.0); +} + +void FlatSourceDomain::batch_reset_fc() +{ + parallel_fill(scalar_flux_new_, 0.0f); + parallel_fill(was_hit_, 0); + //if (!RandomRay::uncollided_flux_volume) { + // parallel_fill(volume_, 0.0); + //} } void FlatSourceDomain::accumulate_iteration_flux() @@ -136,14 +143,14 @@ void FlatSourceDomain::update_external_flat_source() for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; //int material = material_[sr]; - if (volume == 0.0) { + if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { - external_source_[sr * negroups_ + g] = 0.0f; + external_source_[sr * negroups_ + g] = + (scalar_first_collided_flux_[sr * negroups_ + g] / (volume)); } } else { for (int g = 0; g < negroups_; g++) { - external_source_[sr * negroups_ + g] = - (scalar_first_collided_flux_[sr * negroups_ + g] / (volume)); + external_source_[sr * negroups_ + g] = 0.0f; } } } @@ -281,7 +288,6 @@ void FlatSourceDomain::compute_uncollided_scalar_flux() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int was_cell_hit = was_hit_[sr]; - double volume = volume_[sr]; // necessary??? int material = material_[sr]; for (int g = 0; g < negroups_; g++) { @@ -298,14 +304,6 @@ void FlatSourceDomain::compute_uncollided_scalar_flux() } } -// void FlatSourceDomain::uncollided_sum_source() -// { -// #pragma omp parallel for -// for (int64_t e = 0; e < scalar_flux_new_.size(); e++){ -// scalar_flux_new_[e] += scalar_flux_new_per_source_[e]; -// } -// } - // Combine transport flux contributions and flat source contributions from the // previous iteration to generate this iteration's estimate of scalar flux. int64_t FlatSourceDomain::add_source_to_scalar_flux() @@ -519,6 +517,12 @@ double FlatSourceDomain::compute_k_eff(double k_eff_old) const // be passed back to the caller to alert them that this function doesn't // need to be called for the remainder of the simulation. +void FlatSourceDomain::uncollided_moments() +{ + // empty +} + + void FlatSourceDomain::update_volume_uncollided_flux() { #pragma omp parallel for diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index f8db39c0b73..da151b48c5f 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -52,8 +52,23 @@ void LinearSourceDomain::batch_reset() #pragma omp parallel for for (int64_t sr = 0; sr < n_source_regions_; sr++) { centroid_iteration_[sr] = {0.0, 0.0, 0.0}; - if(!settings::FIRST_COLLIDED_FLUX){ mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + } +} + +void LinearSourceDomain::batch_reset_fc() +{ + FlatSourceDomain::batch_reset_fc(); +#pragma omp parallel for + for (int64_t se = 0; se < n_source_elements_; se++) { + flux_moments_new_[se] = {0.0, 0.0, 0.0}; + } + if (!RandomRay::uncollided_flux_volume) { +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + centroid_iteration_[sr] = {0.0, 0.0, 0.0}; + centroid_[sr] = {0.0, 0.0, 0.0}; + //mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; } } } @@ -79,15 +94,6 @@ void LinearSourceDomain::update_external_flat_source() FlatSourceDomain::update_external_flat_source(); } -// void LinearSourceDomain::uncollided_sum_source() -// { -// #pragma omp parallel for -// for (int64_t e = 0; e < scalar_flux_new_.size(); e++){ -// scalar_flux_new_[e] += scalar_flux_new_per_source_[e]; -// flux_moments_new_[e] += flux_moments_new_per_source_[e]; -// } -// } - void LinearSourceDomain::update_external_linear_source() { #pragma omp parallel for @@ -98,14 +104,14 @@ void LinearSourceDomain::update_external_linear_source() // multiply First Collided Flux by volume and attribute it as // external_source - if (volume == 0.0f) { + if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { - external_source_gradients_[sr * negroups_ + g] = {0.0, 0.0, 0.0}; + external_source_gradients_[sr * negroups_ + g] = + (flux_moments_first_collided_[sr * negroups_ + g] / (volume)); } } else { for (int g = 0; g < negroups_; g++) { - external_source_gradients_[sr * negroups_ + g] = - invM * (flux_moments_first_collided_[sr * negroups_ + g] / (volume)); + external_source_gradients_[sr * negroups_ + g] *= 0.0; } } } @@ -124,6 +130,7 @@ void LinearSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; + // if (simulation::current_batch != 1 || !first_collided_mode) { #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { @@ -163,10 +170,6 @@ void LinearSourceDomain::update_neutron_source(double k_eff) source_[sr * negroups_ + e_out] = (scatter_flat + fission_flat * inverse_k_eff) / sigma_t; - // Check for negative source_ values - //if (source_[sr * negroups_ + e_out] < 0.0f) { - // negative_flux_check = {true}; - //} // Compute the linear source terms if (simulation::current_batch > 2) { source_gradients_[sr * negroups_ + e_out] = @@ -174,10 +177,7 @@ void LinearSourceDomain::update_neutron_source(double k_eff) } } } - - // if(negative_flux_check){ - // warning("source_ has negative values!"); - // } + //} if (settings::run_mode == RunMode::FIXED_SOURCE) { // Add external source to flat source term if in fixed source mode @@ -233,7 +233,6 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( double inv_volume = 1.0 / volume_[sr]; centroid_[sr] = centroid_iteration_[sr]; centroid_[sr] *= inv_volume; - mom_matrix_[sr] = mom_matrix_[sr]; mom_matrix_[sr] *= inv_volume; } } @@ -242,21 +241,14 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( void LinearSourceDomain::compute_uncollided_scalar_flux() { - // Temperature and angle indices, if using multiple temperature - const int t = 0; - const int a = 0; - #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int was_cell_hit = was_hit_[sr]; - int material = material_[sr]; for (int g = 0; g < negroups_; g++) { int64_t idx = (sr * negroups_) + g; if (was_cell_hit) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]; flux_moments_uncollided_[idx] = flux_moments_new_[idx]; } else { @@ -354,7 +346,7 @@ void LinearSourceDomain::compute_first_collided_flux() for (int sr = 0; sr < n_source_regions_; sr++) { int material = material_[sr]; - // MomentMatrix invM = mom_matrix_[sr].inverse(); + MomentMatrix invM = mom_matrix_[sr].inverse(); for (int e_out = 0; e_out < negroups_; e_out++) { float sigma_t = data::mg.macro_xs_[material].get_xs( @@ -371,7 +363,7 @@ void LinearSourceDomain::compute_first_collided_flux() // Handles for cross sections float sigma_s = data::mg.macro_xs_[material].get_xs( - MgxsType::SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + MgxsType::NU_SCATTER, e_in, &e_out, nullptr, nullptr, t, a); // Compute source terms for flat and linear components of the flux scatter_flat += sigma_s * flux_flat; @@ -384,7 +376,26 @@ void LinearSourceDomain::compute_first_collided_flux() // Compute the linear source terms flux_moments_first_collided_[sr * negroups_ + e_out] = - ((scatter_linear) / sigma_t); // invM * + invM * ((scatter_linear) / sigma_t); + } + } +} +// Does this make sense? +void LinearSourceDomain::uncollided_moments() +{ +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + int was_cell_hit = was_hit_[sr]; + double volume = volume_[sr]; + MomentMatrix invM = mom_matrix_[sr].inverse(); + + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + if (volume > 0.0) { + flux_moments_uncollided_[idx] = invM * flux_moments_uncollided_[idx]; + } else { + flux_moments_uncollided_[idx] *= 0.0; + } } } } @@ -444,13 +455,14 @@ double LinearSourceDomain::evaluate_flux_at_point( Position local_r = r - centroid_[sr]; MomentArray phi_linear = flux_moments_t_[sr * negroups_ + g]; phi_linear *= 1.0 / (settings::n_batches - settings::n_inactive); - if (first_collided_mode) { - phi_linear += flux_moments_uncollided_[sr * negroups_ + g]; // ??? addition - } MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; + if (first_collided_mode) { + phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; + } + return phi_flat + phi_solved.dot(local_r); } @@ -459,10 +471,10 @@ void LinearSourceDomain::update_volume_uncollided_flux() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = volume_[sr] * simulation_volume_; - if (volume != 0.0f) { + if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { - scalar_uncollided_flux_[sr * negroups_ + g] /= volume; - flux_moments_uncollided_[sr * negroups_ + g] /= volume; + scalar_uncollided_flux_[sr * negroups_ + g] *= (1.0 / volume); + flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); } } else { for (int g = 0; g < negroups_; g++) { diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 24112796ede..69ccffa7ff8 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -499,7 +499,7 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. if (settings::FIRST_COLLIDED_FLUX) { /// TRIPLE CHECK THIS - if (domain->volume_[source_region] != 0.0f) { + if (domain->volume_[source_region] > 0.0) { rm_local = midpoint - centroid; r0_local = r() - centroid; } else { diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index e2294cc9b83..2faa5dbde1c 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -303,8 +303,9 @@ void RandomRaySimulation::simulate() end_volume_estimation - start_volume_estimation); // Reset parameters for First Collided Method + domain_->batch_reset_fc(); RandomRay::uncollided_flux_volume = false; - domain_->batch_reset(); + //============================================================================== // First Collided Transport Loop @@ -332,7 +333,6 @@ void RandomRaySimulation::simulate() n_hits_new); // BREAK STATEMENT if Max rays reached or 100% FSR HIT - if (n_hits_new == n_hits_old) { domain_->new_fsr_fc = {false}; } else if (new_n_rays >= n_rays_max) { @@ -341,9 +341,6 @@ void RandomRaySimulation::simulate() domain_->n_source_regions_) { domain_->new_fsr_fc = {false}; } - // Section to add in n_source_calculations - // domain_->normalize_uncollided_scalar_flux(new_n_rays); - // domain_->uncollided_sum_source(); // update values for next batch old_n_rays = new_n_rays; @@ -352,15 +349,13 @@ void RandomRaySimulation::simulate() n_hits_old = n_hits_new; } - // fmt::print("old_n_rays = {:} and new_n_rays = {:}\n", old_n_rays, - // new_n_rays); // Compute scalar_uncollided_flux domain_->compute_uncollided_scalar_flux(); // Normalize scalar_uncollided_flux domain_->normalize_uncollided_scalar_flux(old_n_rays); - // compute first_collided_fixed_source - + // compute first_collided_fixed_source domain_->compute_first_collided_flux(); // Compute external source a priori. @@ -368,25 +363,24 @@ void RandomRaySimulation::simulate() domain_->update_external_linear_source(); domain_->update_external_flat_source(); // comment if option 2 domain_->update_volume_uncollided_flux(); // comment if option 2 - fmt::print("Flux and moments are calculated a priori to RR \n"); + fmt::print("Flux and moments are calculated a priori to RR \n\n"); } else if (settings::volume_online_option == 2) { domain_->update_external_linear_source(); - fmt::print("Moments are calculated a priori to RR \n"); + fmt::print("Moments are calculated a priori to RR \n\n"); } else { - fmt::print("Flux and moments are updated online in RR \n"); + fmt::print("Flux and moments are updated online in RR \n\n"); } - // Reset Terms to RR method - domain_->batch_reset(); // clean-up of key variables (preserves volume) - simulation::current_batch = 0; // garantee the first batch will be 1 in RR + // apply invM*uncollided flux? + domain_->uncollided_moments(); // reset values for RandomRay iteration + domain_->batch_reset_fc(); // clean-up of key variables (preserves volume) domain_->first_collided_mode = {true}; // add FC contribution to RR settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations - - // fmt::print("first_collided_mode = {:}\n", - // domain_->first_collided_mode); - // compute First Collided Method simulation time + simulation::current_batch = 0; // garantee the first batch will be 1 in RR + + // compute First Collided Method simulation time double first_collided_estimated_time = omp_get_wtime(); fmt::print( " ====== ========== ================================\n\n"); @@ -416,6 +410,7 @@ void RandomRaySimulation::simulate() } } // Update source term (scattering + fission) + domain_->update_neutron_source(k_eff_); // Reset scalar fluxes, iteration volume tallies, and region hit flags to @@ -503,6 +498,7 @@ void RandomRaySimulation::reduce_simulation_statistics() void RandomRaySimulation::output_simulation_results() const { + fmt::print("first_colllided_mode ={:}\n", domain_->first_collided_mode); // Print random ray results if (mpi::master) { print_results_random_ray(total_geometric_intersections_, diff --git a/src/settings.cpp b/src/settings.cpp index 648fa92b3a5..b7a1e6aec4f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -135,10 +135,9 @@ double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {10000}; -int n_volume_estimator_rays {10000}; -//bool first_collided_mode {false}; -int volume_online_option {2}; +int n_uncollided_rays {100000}; +int n_volume_estimator_rays {1000000}; +int volume_online_option {3}; } // namespace settings From e6f5e61e7d32ddffc37b522cd00e5592f925bcde Mon Sep 17 00:00:00 2001 From: Tomas P Date: Fri, 2 Aug 2024 15:49:49 -0500 Subject: [PATCH 12/27] Linear_source_Final_2 --- src/random_ray/linear_source_domain.cpp | 12 ++++++------ src/random_ray/random_ray_simulation.cpp | 1 - src/settings.cpp | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index da151b48c5f..f850bcc5077 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -107,7 +107,7 @@ void LinearSourceDomain::update_external_linear_source() if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { external_source_gradients_[sr * negroups_ + g] = - (flux_moments_first_collided_[sr * negroups_ + g] / (volume)); + (flux_moments_first_collided_[sr * negroups_ + g] * (1.0 / volume)); } } else { for (int g = 0; g < negroups_; g++) { @@ -386,13 +386,13 @@ void LinearSourceDomain::uncollided_moments() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { int was_cell_hit = was_hit_[sr]; - double volume = volume_[sr]; + double volume = volume_[sr] * simulation_volume_; MomentMatrix invM = mom_matrix_[sr].inverse(); for (int g = 0; g < negroups_; g++) { int64_t idx = (sr * negroups_) + g; if (volume > 0.0) { - flux_moments_uncollided_[idx] = invM * flux_moments_uncollided_[idx]; + flux_moments_uncollided_[idx] = invM * flux_moments_uncollided_[idx] * (1.0/ volume); } else { flux_moments_uncollided_[idx] *= 0.0; } @@ -460,7 +460,7 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentArray phi_solved = invM * phi_linear; if (first_collided_mode) { - phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; + phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; } return phi_flat + phi_solved.dot(local_r); @@ -474,12 +474,12 @@ void LinearSourceDomain::update_volume_uncollided_flux() if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] *= (1.0 / volume); - flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); + //flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); } } else { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] = 0.0f; - flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; + //flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; } } } diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 2faa5dbde1c..8e498ec7417 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -498,7 +498,6 @@ void RandomRaySimulation::reduce_simulation_statistics() void RandomRaySimulation::output_simulation_results() const { - fmt::print("first_colllided_mode ={:}\n", domain_->first_collided_mode); // Print random ray results if (mpi::master) { print_results_random_ray(total_geometric_intersections_, diff --git a/src/settings.cpp b/src/settings.cpp index b7a1e6aec4f..1544c26c644 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -136,7 +136,7 @@ double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux bool FIRST_COLLIDED_FLUX {true}; int n_uncollided_rays {100000}; -int n_volume_estimator_rays {1000000}; +int n_volume_estimator_rays {100000}; int volume_online_option {3}; From df622b0f7cfe65685ef3fe63e299d302844f89da Mon Sep 17 00:00:00 2001 From: Tomas P Date: Sat, 3 Aug 2024 15:37:05 -0500 Subject: [PATCH 13/27] fixes in pure RR input --- src/random_ray/flat_source_domain.cpp | 2 +- src/random_ray/linear_source_domain.cpp | 20 +++++++++++--------- src/settings.cpp | 6 +++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index f14e1207fdb..a6f452a6113 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -1121,7 +1121,7 @@ void FlatSourceDomain::apply_external_source_to_source_region( Discrete* discrete, double strength_factor, int64_t source_region) { const auto& discrete_energies = discrete->x(); - const auto& discrete_probs = discrete->prob(); + const auto& discrete_probs = discrete->prob_actual(); for (int e = 0; e < discrete_energies.size(); e++) { int g = data::mg.get_group_index(discrete_energies[e]); diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index f850bcc5077..c9d1bab651e 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -68,7 +68,7 @@ void LinearSourceDomain::batch_reset_fc() for (int64_t sr = 0; sr < n_source_regions_; sr++) { centroid_iteration_[sr] = {0.0, 0.0, 0.0}; centroid_[sr] = {0.0, 0.0, 0.0}; - //mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + // mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; } } } @@ -130,7 +130,6 @@ void LinearSourceDomain::update_neutron_source(double k_eff) const int t = 0; const int a = 0; - // if (simulation::current_batch != 1 || !first_collided_mode) { #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { @@ -177,14 +176,16 @@ void LinearSourceDomain::update_neutron_source(double k_eff) } } } - //} + if (settings::run_mode == RunMode::FIXED_SOURCE) { // Add external source to flat source term if in fixed source mode #pragma omp parallel for for (int se = 0; se < n_source_elements_; se++) { source_[se] += external_source_[se]; - source_gradients_[se] += external_source_gradients_[se]; // ??? + if (first_collided_mode) { + source_gradients_[se] += external_source_gradients_[se]; // ??? + } } } @@ -376,7 +377,7 @@ void LinearSourceDomain::compute_first_collided_flux() // Compute the linear source terms flux_moments_first_collided_[sr * negroups_ + e_out] = - invM * ((scatter_linear) / sigma_t); + invM * ((scatter_linear) / sigma_t); } } } @@ -392,7 +393,8 @@ void LinearSourceDomain::uncollided_moments() for (int g = 0; g < negroups_; g++) { int64_t idx = (sr * negroups_) + g; if (volume > 0.0) { - flux_moments_uncollided_[idx] = invM * flux_moments_uncollided_[idx] * (1.0/ volume); + flux_moments_uncollided_[idx] = + invM * flux_moments_uncollided_[idx] * (1.0 / volume); } else { flux_moments_uncollided_[idx] *= 0.0; } @@ -460,7 +462,7 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentArray phi_solved = invM * phi_linear; if (first_collided_mode) { - phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; + phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; } return phi_flat + phi_solved.dot(local_r); @@ -474,12 +476,12 @@ void LinearSourceDomain::update_volume_uncollided_flux() if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] *= (1.0 / volume); - //flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); + // flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); } } else { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] = 0.0f; - //flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; + // flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; } } } diff --git a/src/settings.cpp b/src/settings.cpp index 1544c26c644..29218c185c6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,9 +134,9 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {100000}; -int n_volume_estimator_rays {100000}; +bool FIRST_COLLIDED_FLUX {false}; +int n_uncollided_rays {10000}; +int n_volume_estimator_rays {10000}; int volume_online_option {3}; From 94081cfa9f77d0814140a681e2a947d0faa61d0c Mon Sep 17 00:00:00 2001 From: Tomas P Date: Mon, 5 Aug 2024 10:13:16 -0500 Subject: [PATCH 14/27] test_1 --- src/settings.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/settings.cpp b/src/settings.cpp index 29218c185c6..865662e9693 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,10 +134,10 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {false}; -int n_uncollided_rays {10000}; -int n_volume_estimator_rays {10000}; -int volume_online_option {3}; +bool FIRST_COLLIDED_FLUX {true}; +int n_uncollided_rays {100000}; +int n_volume_estimator_rays {100000}; +int volume_online_option {1}; } // namespace settings From 3ab0ffe90982dea0b2a7692ad467939c04654fca Mon Sep 17 00:00:00 2001 From: Tomas P Date: Mon, 5 Aug 2024 17:46:21 -0500 Subject: [PATCH 15/27] code_clean_up_1 --- .../openmc/random_ray/flat_source_domain.h | 2 - .../openmc/random_ray/random_ray_simulation.h | 7 + include/openmc/settings.h | 3 +- include/openmc/timer.h | 1 + src/output.cpp | 7 +- src/random_ray/flat_source_domain.cpp | 18 +- src/random_ray/linear_source_domain.cpp | 31 +-- src/random_ray/random_ray.cpp | 64 +++-- src/random_ray/random_ray_simulation.cpp | 229 ++++++++---------- src/settings.cpp | 6 +- src/timer.cpp | 2 + 11 files changed, 179 insertions(+), 191 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index bf3d986d5a0..0cc41bcf69e 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -140,8 +140,6 @@ class FlatSourceDomain { // Check if new cell was hit bool negative_flux_check {false}; // Variable to print warning of negative fluxes - int flux_type {settings::volume_online_option}; // for plotting purposes. - // 1D array representing source region starting offset for each OpenMC Cell // in model::cells vector source_region_offsets_; diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index f1ee2d04edc..06513a7486e 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -27,6 +27,7 @@ class RandomRaySimulation { void print_results_random_ray(uint64_t total_geometric_intersections, double avg_miss_rate, int negroups, int64_t n_source_regions, int64_t n_external_source_regions) const; + void first_collided_source_simulation(); //---------------------------------------------------------------------------- // Data members @@ -39,6 +40,10 @@ class RandomRaySimulation { int n_rays_max {1000000}; bool user_input_rays {false}; + // volume estimation timer + double time_volume_fc {0}; + + private: // Contains all flat source region data unique_ptr domain_; @@ -52,6 +57,8 @@ class RandomRaySimulation { // Tracks the total number of geometric intersections by all rays for // reporting uint64_t total_geometric_intersections_ {0}; + uint64_t total_geometric_intersections_volume_ {0}; + uint64_t total_geometric_intersections_fcs_ {0}; // Number of energy groups int negroups_; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 825e6288e78..2f9fb399162 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -158,8 +158,7 @@ extern double weight_survive; //!< Survival weight after Russian roulette extern bool FIRST_COLLIDED_FLUX; //!< First Collided Mode loop extern int n_uncollided_rays; //!< Number of uncollided rays used extern int n_volume_estimator_rays; //!< Number of rays to estimate volume -//extern bool first_collided_mode; //!< Add first collided source in RR -extern int volume_online_option;//! Volume online calculation for FC source +//extern int volume_online_option;//! Volume online calculation for FC source } // namespace settings diff --git a/include/openmc/timer.h b/include/openmc/timer.h index d928aad4560..5cffa82cc51 100644 --- a/include/openmc/timer.h +++ b/include/openmc/timer.h @@ -32,6 +32,7 @@ extern Timer time_event_surface_crossing; extern Timer time_event_collision; extern Timer time_event_death; extern Timer time_update_src; +extern Timer time_first_collided; } // namespace simulation diff --git a/src/output.cpp b/src/output.cpp index 5fdbea1304e..4f7733c8fa6 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -376,13 +376,16 @@ void print_build_info() void print_columns() { - if (settings::entropy_on) { + if (settings::FIRST_COLLIDED_FLUX){ + fmt::print(" Batch Rays Total Source Regions Discovered\n" + " ====== ======= =================================\n"); + } else if (settings::entropy_on) { fmt::print(" Bat./Gen. k Entropy Average k \n" " ========= ======== ======== ====================\n"); } else { fmt::print(" Bat./Gen. k Average k\n" " ========= ======== ====================\n"); - } + } } //============================================================================== diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index a6f452a6113..48155fdde4a 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -123,9 +123,6 @@ void FlatSourceDomain::batch_reset_fc() { parallel_fill(scalar_flux_new_, 0.0f); parallel_fill(was_hit_, 0); - //if (!RandomRay::uncollided_flux_volume) { - // parallel_fill(volume_, 0.0); - //} } void FlatSourceDomain::accumulate_iteration_flux() @@ -142,7 +139,7 @@ void FlatSourceDomain::update_external_flat_source() #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; - //int material = material_[sr]; + if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { external_source_[sr * negroups_ + g] = @@ -522,7 +519,6 @@ void FlatSourceDomain::uncollided_moments() // empty } - void FlatSourceDomain::update_volume_uncollided_flux() { #pragma omp parallel for @@ -729,16 +725,8 @@ void FlatSourceDomain::random_ray_tally() for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; if (first_collided_mode) { - if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT) { - flux = - (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); - } else if (settings::volume_online_option == 1) { - flux = - (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] )); - } else { - flux = - (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); - } + flux = + (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); } else { flux = (scalar_flux_new_[idx] * source_normalization_factor); } diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index c9d1bab651e..2122f6e0e59 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -68,7 +68,7 @@ void LinearSourceDomain::batch_reset_fc() for (int64_t sr = 0; sr < n_source_regions_; sr++) { centroid_iteration_[sr] = {0.0, 0.0, 0.0}; centroid_[sr] = {0.0, 0.0, 0.0}; - // mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; } } } @@ -170,22 +170,21 @@ void LinearSourceDomain::update_neutron_source(double k_eff) (scatter_flat + fission_flat * inverse_k_eff) / sigma_t; // Compute the linear source terms - if (simulation::current_batch > 2) { + if (simulation::current_batch > 10) { source_gradients_[sr * negroups_ + e_out] = invM * ((scatter_linear + fission_linear * inverse_k_eff) / sigma_t); } } } - if (settings::run_mode == RunMode::FIXED_SOURCE) { // Add external source to flat source term if in fixed source mode #pragma omp parallel for for (int se = 0; se < n_source_elements_; se++) { source_[se] += external_source_[se]; - if (first_collided_mode) { - source_gradients_[se] += external_source_gradients_[se]; // ??? - } + //if (first_collided_mode) { + // source_gradients_[se] += external_source_gradients_[se]; + //} } } @@ -223,10 +222,8 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( mom_matrix_[sr] *= inv_volume; } } - } - - // just fuse to the other IF STATEMENT - if (settings::FIRST_COLLIDED_FLUX) { + } else { + // IF First_Collided_Method #pragma omp parallel for for (int64_t sr = 0; sr < n_source_regions_; sr++) { volume_[sr] *= volume_normalization_factor; @@ -319,13 +316,12 @@ void LinearSourceDomain::normalize_uncollided_scalar_flux( { // multiply by simulation volume float normalization_factor = (1.0) / number_of_particles; - // Determine Source_total Scailing factor if first collided + // Determine Source_total Scailing factor if first collided double user_external_source_strength = 0.0; for (auto& ext_source : model::external_sources) { user_external_source_strength += ext_source->strength(); } - // fmt::print("total_source_strength = {}\n", total_source_intensity); double source_scailing_factor = user_external_source_strength * normalization_factor; @@ -381,12 +377,11 @@ void LinearSourceDomain::compute_first_collided_flux() } } } -// Does this make sense? + void LinearSourceDomain::uncollided_moments() { #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { - int was_cell_hit = was_hit_[sr]; double volume = volume_[sr] * simulation_volume_; MomentMatrix invM = mom_matrix_[sr].inverse(); @@ -461,9 +456,9 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; - if (first_collided_mode) { - phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; - } + //if (first_collided_mode) { + // phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; + //} return phi_flat + phi_solved.dot(local_r); } @@ -476,12 +471,10 @@ void LinearSourceDomain::update_volume_uncollided_flux() if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] *= (1.0 / volume); - // flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); } } else { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] = 0.0f; - // flux_moments_uncollided_[sr * negroups_ + g] *= 0.0; } } } diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 69ccffa7ff8..fcd0f57d859 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -421,7 +421,8 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // check attenuation in FIRST_ COLLIDED_FLUX // There is likely that an extra length of the rebounded ray after vacuum - // BC is being considered here, however, it does not impact volume calculations + // BC is being considered here, however, it does not impact volume + // calculations if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { // bool = true to kill ray // ray is killed by default unless: @@ -498,7 +499,9 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // be no estimate of its centroid. We detect this by checking if it has // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. - if (settings::FIRST_COLLIDED_FLUX) { /// TRIPLE CHECK THIS + + // First collided source works on volume_ instead of volume_t_ + if (settings::FIRST_COLLIDED_FLUX) { if (domain->volume_[source_region] > 0.0) { rm_local = midpoint - centroid; r0_local = r() - centroid; @@ -536,26 +539,43 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Compute linear source terms, spatial and directional (dir), // calculated from the source gradients dot product with local centroid // and direction, respectively. - float spatial_source = - domain_->source_[source_element + g] + - rm_local.dot(domain->source_gradients_[source_element + g]); - float dir_source = u().dot(domain->source_gradients_[source_element + g]); - - float gn = exponentialG(tau); - float f1 = 1.0f - tau * gn; - float f2 = (2.0f * gn - f1) * distance_2; - float new_delta_psi = - (angular_flux_[g] - spatial_source) * f1 * distance - - 0.5 * dir_source * f2; - - float h1 = f1 - gn; - float g1 = 0.5f - h1; - float g2 = exponentialG2(tau); - g1 = g1 * spatial_source; - g2 = g2 * dir_source * distance * 0.5f; - h1 = h1 * angular_flux_[g]; - h1 = (g1 + g2 + h1) * distance_2; - spatial_source = spatial_source * distance + new_delta_psi; + float h1 = 0.0f; + float spatial_source = 0.0f; + float dir_source = 0.0f; + float new_delta_psi = 0.0f; + + if (!settings::FIRST_COLLIDED_FLUX) { + spatial_source = + domain_->source_[source_element + g] + + rm_local.dot(domain->source_gradients_[source_element + g]); + dir_source = u().dot(domain->source_gradients_[source_element + g]); + + float gn = exponentialG(tau); + float f1 = 1.0f - tau * gn; + float f2 = (2.0f * gn - f1) * distance_2; + new_delta_psi = + (angular_flux_[g] - spatial_source) * f1 * distance - + 0.5 * dir_source * f2; + + h1 = f1 - gn; + float g1 = 0.5f - h1; + float g2 = exponentialG2(tau); + g1 = g1 * spatial_source; + g2 = g2 * dir_source * distance * 0.5f; + h1 = h1 * angular_flux_[g]; + h1 = (g1 + g2 + h1) * distance_2; + spatial_source = spatial_source * distance + new_delta_psi; + + } else { + float gn = exponentialG(tau); + float f1 = 1.0f - tau * gn; + new_delta_psi = (angular_flux_[g]) * f1 * distance; + + h1 = f1 - gn; + h1 = h1 * angular_flux_[g]; + h1 = (h1)*distance_2; + spatial_source = new_delta_psi; + } // Store contributions for this group into arrays, so that they can // be accumulated into the source region's estimates inside of the locked diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 8e498ec7417..33f1781228d 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -271,124 +271,9 @@ void RandomRaySimulation::simulate() domain_->convert_external_sources(); domain_->count_external_source_regions(); } else { - // FIRST_COLLIDED_FLUX calculation routine: - fmt::print("==============> FIRST COLLIDED SOURCE CONVERSION " - "<=================\n\n"); - - //============================================================================== - // Turn on volume pre calculation - double start_volume_estimation = omp_get_wtime(); - fmt::print("Computing starting volume estimates... \n"); - RandomRay::uncollided_flux_volume = true; - simulation::current_batch = 1; - - // Pre calculate volume -#pragma omp parallel for schedule(dynamic) \ - reduction(+ : total_geometric_intersections_) - for (int i = 0; i < settings::n_volume_estimator_rays; i++) { - RandomRay ray(i, domain_.get()); - total_geometric_intersections_ += - ray.transport_history_based_single_ray(); - } - - // fmt::print("simulation_batch = {:}", simulation::current_batch); - // Normalizing volumes - domain_->normalize_scalar_flux_and_volumes( - settings::n_volume_estimator_rays * RandomRay::distance_active_); - - // Print volume estimation simulation time - double end_volume_estimation = omp_get_wtime(); - fmt::print("Volume estimation completed.\n"); - fmt::print("Run time = {:.4f} \n\n", - end_volume_estimation - start_volume_estimation); - - // Reset parameters for First Collided Method - domain_->batch_reset_fc(); - RandomRay::uncollided_flux_volume = false; - - - //============================================================================== - // First Collided Transport Loop - // It will operate until (1-3): - // (1) There is no new FSR hits from one (n-1) iteration to the next (n) - // (2) Reached pre-set maximum n_uncollided_rays - // (3) Hit 100% of the FSRs - fmt::print(" Batch Rays Total Source Regions Discovered\n" - " ====== ========== ================================\n"); - while (domain_->new_fsr_fc) { - - // Ray tracing and attenuation -#pragma omp parallel for schedule(dynamic) \ - reduction(+ : total_geometric_intersections_) - for (int i = old_n_rays; i < new_n_rays; i++) { - RandomRay ray(i, domain_.get()); - total_geometric_intersections_ += - ray.transport_history_based_single_ray_first_collided(); - } - - int64_t n_hits_new = domain_->check_fsr_hits(); - - // print results - fmt::print(" {:6} {:10} {:}\n", batch_first_collided, new_n_rays, - n_hits_new); - - // BREAK STATEMENT if Max rays reached or 100% FSR HIT - if (n_hits_new == n_hits_old) { - domain_->new_fsr_fc = {false}; - } else if (new_n_rays >= n_rays_max) { - domain_->new_fsr_fc = {false}; - } else if (static_cast(n_hits_new) >= - domain_->n_source_regions_) { - domain_->new_fsr_fc = {false}; - } - - // update values for next batch - old_n_rays = new_n_rays; - new_n_rays *= 2; - batch_first_collided++; - n_hits_old = n_hits_new; - } - - // Compute scalar_uncollided_flux - domain_->compute_uncollided_scalar_flux(); - - // Normalize scalar_uncollided_flux - domain_->normalize_uncollided_scalar_flux(old_n_rays); - - // compute first_collided_fixed_source - domain_->compute_first_collided_flux(); - - // Compute external source a priori. - if (settings::volume_online_option == 1) { - domain_->update_external_linear_source(); - domain_->update_external_flat_source(); // comment if option 2 - domain_->update_volume_uncollided_flux(); // comment if option 2 - fmt::print("Flux and moments are calculated a priori to RR \n\n"); - } else if (settings::volume_online_option == 2) { - domain_->update_external_linear_source(); - fmt::print("Moments are calculated a priori to RR \n\n"); - } else { - fmt::print("Flux and moments are updated online in RR \n\n"); - } - - // apply invM*uncollided flux? - domain_->uncollided_moments(); - - // reset values for RandomRay iteration - domain_->batch_reset_fc(); // clean-up of key variables (preserves volume) - domain_->first_collided_mode = {true}; // add FC contribution to RR - settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations - simulation::current_batch = 0; // garantee the first batch will be 1 in RR - - // compute First Collided Method simulation time - double first_collided_estimated_time = omp_get_wtime(); - fmt::print( - " ====== ========== ================================\n\n"); - fmt::print("First Collided Method run time = {:.4f} \n\n", - first_collided_estimated_time - end_volume_estimation); + first_collided_source_simulation(); } } - // Random ray power iteration loop while (simulation::current_batch < settings::n_batches) { @@ -402,12 +287,8 @@ void RandomRaySimulation::simulate() // Update external source if FIRST_COLLIDED_METHOD is used if (domain_->first_collided_mode) { - if (settings::volume_online_option == 2) { - domain_->update_external_flat_source(); - } else if (settings::volume_online_option == 3) { - domain_->update_external_flat_source(); - domain_->update_external_linear_source(); - } + domain_->update_external_flat_source(); + // domain_->update_external_linear_source(); } // Update source term (scattering + fission) @@ -476,9 +357,7 @@ void RandomRaySimulation::simulate() } // End random ray power iteration loop if (domain_->first_collided_mode) { - if (settings::volume_online_option != 1) { - domain_->update_volume_uncollided_flux(); - } + domain_->update_volume_uncollided_flux(); } } @@ -580,6 +459,10 @@ void RandomRaySimulation::print_results_random_ray( show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); show_time("Total simulation time", time_total.elapsed()); + if (domain_->first_collided_mode) { + show_time("Volume estimation time", RandomRaySimulation::time_volume_fc, 1); + show_time("First Collided Source time", time_first_collided.elapsed(), 1); + } show_time("Transport sweep only", time_transport.elapsed(), 1); show_time("Source update only", time_update_src.elapsed(), 1); show_time("Tally conversion only", time_tallies.elapsed(), 1); @@ -601,4 +484,100 @@ void RandomRaySimulation::print_results_random_ray( } } +void RandomRaySimulation::first_collided_source_simulation() +{ + header("FIRST COLLIDED SOURCE METHOD", 3); + simulation::time_first_collided.start(); + + // Turn on volume estimation + // Volume estimation is necessary to scale the first collided source + // accordingly Estimation of linear moments in linear source has direct impact + // into final solution accuracy. + fmt::print("Initial volume estimation..."); + RandomRay::uncollided_flux_volume = true; + simulation::current_batch = 1; + + // Calculate volume +#pragma omp parallel for schedule(dynamic) \ + reduction(+ : total_geometric_intersections_volume_) + for (int i = 0; i < settings::n_volume_estimator_rays; i++) { + RandomRay ray(i, domain_.get()); + total_geometric_intersections_volume_ += + ray.transport_history_based_single_ray(); + } + + // Normalizing volumes + domain_->normalize_scalar_flux_and_volumes( + settings::n_volume_estimator_rays * RandomRay::distance_active_); + + // Reset parameters for First Collided Source Method + domain_->batch_reset_fc(); + RandomRay::uncollided_flux_volume = false; + + // print volume estimation time + time_volume_fc = simulation::time_first_collided.elapsed(); + fmt::print("completed.\n\n"); + + //============================================================================== + + // First Collided Source - Transport Loop + // It will operate until meet any criteria (1-3): + // (1) There is no new FSR hits from batch_first_collided (n-1) to the next + // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs + print_columns(); + while (domain_->new_fsr_fc) { + + // Ray tracing and attenuation +#pragma omp parallel for \ + reduction(+ : total_geometric_intersections_fcs_) + for (int i = old_n_rays; i < new_n_rays; i++) { + RandomRay ray(i, domain_.get()); + total_geometric_intersections_fcs_ += + ray.transport_history_based_single_ray_first_collided(); + } + + int64_t n_hits_new = domain_->check_fsr_hits(); + + // BREAK STATEMENT + if (n_hits_new == n_hits_old) { + domain_->new_fsr_fc = {false}; // Condition (1) + } else if (new_n_rays >= n_rays_max) { + domain_->new_fsr_fc = {false}; // Condition (2) + } else if (static_cast(n_hits_new) >= domain_->n_source_regions_) { + domain_->new_fsr_fc = {false}; // Condition (3) + } + + // print results + fmt::print( + " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); + + // update values for next batch + n_hits_old = n_hits_new; + old_n_rays = new_n_rays; + new_n_rays *= 2; + batch_first_collided++; + } + + // Compute scalar_uncollided_flux + domain_->compute_uncollided_scalar_flux(); + + // Normalize scalar_uncollided_flux + domain_->normalize_uncollided_scalar_flux(old_n_rays); + + // compute first_collided_fixed_source + domain_->compute_first_collided_flux(); + + // apply invM*uncollided flux? + // domain_->uncollided_moments(); + + // reset values for RandomRay iteration + domain_->batch_reset_fc(); // clean-up of key variables (preserves volume) + domain_->first_collided_mode = {true}; // add FC contribution to RR + settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations + simulation::current_batch = 0; // garantee the first batch will be 1 in RR + + // compute First Collided Method simulation time + simulation::time_first_collided.stop(); + fmt::print("\n"); +} } // namespace openmc diff --git a/src/settings.cpp b/src/settings.cpp index 865662e9693..23dcb862af4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -135,10 +135,8 @@ double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {100000}; -int n_volume_estimator_rays {100000}; -int volume_online_option {1}; - +int n_uncollided_rays {2560000}; +int n_volume_estimator_rays {10000}; } // namespace settings diff --git a/src/timer.cpp b/src/timer.cpp index 6d692d4fbf6..7694f660d2e 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -27,6 +27,7 @@ Timer time_event_surface_crossing; Timer time_event_collision; Timer time_event_death; Timer time_update_src; +Timer time_first_collided; } // namespace simulation @@ -87,6 +88,7 @@ void reset_timers() simulation::time_event_collision.reset(); simulation::time_event_death.reset(); simulation::time_update_src.reset(); + simulation::time_first_collided.reset(); } } // namespace openmc From ff96678af4489bcb861970ad9e4664aca932c201 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Tue, 6 Aug 2024 08:24:54 -0500 Subject: [PATCH 16/27] code clean-up_2 --- src/random_ray/linear_source_domain.cpp | 6 +----- src/random_ray/random_ray.cpp | 17 +++++++++++------ src/random_ray/random_ray_simulation.cpp | 6 +++--- src/settings.cpp | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 2122f6e0e59..cf53fa97f6d 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -32,8 +32,6 @@ LinearSourceDomain::LinearSourceDomain() : FlatSourceDomain() // First Collided method flux_moments_uncollided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); flux_moments_first_collided_.assign(n_source_elements_, {0.0, 0.0, 0.0}); - // - // flux_moments_new_per_source_.assign(n_source_elements_, {0.0, 0.0, 0.0}); centroid_.assign(n_source_regions_, {0.0, 0.0, 0.0}); centroid_iteration_.assign(n_source_regions_, {0.0, 0.0, 0.0}); @@ -100,10 +98,8 @@ void LinearSourceDomain::update_external_linear_source() for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; - MomentMatrix invM = mom_matrix_[sr].inverse(); - // multiply First Collided Flux by volume and attribute it as - // external_source + // DIvide by volume and attribute it as external_source if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { external_source_gradients_[sr * negroups_ + g] = diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index fcd0f57d859..a2f105b4b1f 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -553,9 +553,8 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) float gn = exponentialG(tau); float f1 = 1.0f - tau * gn; float f2 = (2.0f * gn - f1) * distance_2; - new_delta_psi = - (angular_flux_[g] - spatial_source) * f1 * distance - - 0.5 * dir_source * f2; + new_delta_psi = (angular_flux_[g] - spatial_source) * f1 * distance - + 0.5 * dir_source * f2; h1 = f1 - gn; float g1 = 0.5f - h1; @@ -748,15 +747,21 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) } // initialize ray's starting angular flux spectrum - if (!settings::FIRST_COLLIDED_FLUX) { + if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume) { // Initialize ray's starting angular flux to starting location's isotropic // source int i_cell = lowest_coord().cell; int64_t source_region_idx = domain_->source_region_offsets_[i_cell] + cell_instance(); - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + if (!settings::FIRST_COLLIDED_FLUX) { + for (int g = 0; g < negroups_; g++) { + angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + } + } else { + for (int g = 0; g < negroups_; g++) { + angular_flux_[g] = 1.0; + } } } } diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 33f1781228d..db1d7c418e0 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -285,13 +285,12 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (domain_->first_collided_mode) { domain_->update_external_flat_source(); // domain_->update_external_linear_source(); } - // Update source term (scattering + fission) + // Update source term (scattering + fission) domain_->update_neutron_source(k_eff_); // Reset scalar fluxes, iteration volume tallies, and region hit flags to @@ -491,7 +490,7 @@ void RandomRaySimulation::first_collided_source_simulation() // Turn on volume estimation // Volume estimation is necessary to scale the first collided source - // accordingly Estimation of linear moments in linear source has direct impact + // accordingly. Estimation of linear moments in linear source has direct impact // into final solution accuracy. fmt::print("Initial volume estimation..."); RandomRay::uncollided_flux_volume = true; @@ -580,4 +579,5 @@ void RandomRaySimulation::first_collided_source_simulation() simulation::time_first_collided.stop(); fmt::print("\n"); } + } // namespace openmc diff --git a/src/settings.cpp b/src/settings.cpp index 23dcb862af4..f5bfe56cb8c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,8 +134,8 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {2560000}; +bool FIRST_COLLIDED_FLUX {false}; +int n_uncollided_rays {1280000}; int n_volume_estimator_rays {10000}; } // namespace settings From e6162d07a3eefb2b660208e02c80c2f63d1af1b4 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 7 Aug 2024 13:41:50 -0500 Subject: [PATCH 17/27] update_2 --- .../openmc/random_ray/flat_source_domain.h | 8 +- .../openmc/random_ray/linear_source_domain.h | 16 +- include/openmc/random_ray/random_ray.h | 7 +- src/random_ray/flat_source_domain.cpp | 220 +++++------ src/random_ray/linear_source_domain.cpp | 126 ++---- src/random_ray/random_ray.cpp | 360 ++++++------------ src/random_ray/random_ray_simulation.cpp | 73 ++-- src/settings.cpp | 6 +- 8 files changed, 311 insertions(+), 505 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 0cc41bcf69e..3698da0796b 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -113,13 +113,13 @@ class FlatSourceDomain { virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; double compute_fixed_source_normalization_factor() const; - virtual void update_external_linear_source(); + virtual void compute_first_collided_flux(); virtual void normalize_uncollided_scalar_flux(double number_of_particles); virtual void update_volume_uncollided_flux(); - virtual void update_external_flat_source(); // check if virtual - virtual void compute_uncollided_scalar_flux(); // check if virtual - virtual int64_t check_fsr_hits(); + virtual void compute_first_collided_external_source(); + virtual void compute_uncollided_scalar_flux(); + int64_t check_fsr_hits(); virtual void uncollided_moments(); virtual void batch_reset_fc(); diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index 4412ce83af1..d6c73767511 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -41,15 +41,13 @@ class LinearSourceDomain : public FlatSourceDomain { void flux_swap() override; double evaluate_flux_at_point(Position r, int64_t sr, int g) const override; - void update_external_flat_source(); - virtual void update_external_linear_source(); - virtual int64_t check_fsr_hits(); - virtual void compute_uncollided_scalar_flux(); - virtual void compute_first_collided_flux(); - virtual void normalize_uncollided_scalar_flux(double number_of_particles); - virtual void update_volume_uncollided_flux(); - virtual void uncollided_moments(); - virtual void batch_reset_fc(); + void compute_first_collided_external_source() override; + void compute_uncollided_scalar_flux() override; + void compute_first_collided_flux() override; + void normalize_uncollided_scalar_flux(double number_of_particles) override; + void update_volume_uncollided_flux() override; + void uncollided_moments() override; + void batch_reset_fc() override; //---------------------------------------------------------------------------- // Public Data members diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index cd501138dc6..085dabaf609 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -20,7 +20,7 @@ class RandomRay : public Particle { //---------------------------------------------------------------------------- // Constructors RandomRay(); - RandomRay(uint64_t ray_id, FlatSourceDomain* domain); + RandomRay(uint64_t ray_id, FlatSourceDomain* domain, bool uncollided_ray); //---------------------------------------------------------------------------- // Methods @@ -31,9 +31,8 @@ class RandomRay : public Particle { void event_advance_ray_first_collided(); - void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain); + void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain,bool uncollided_ray); uint64_t transport_history_based_single_ray(); - uint64_t transport_history_based_single_ray_first_collided(); //---------------------------------------------------------------------------- // Static data members @@ -42,7 +41,7 @@ class RandomRay : public Particle { static unique_ptr ray_source_; // Starting source for ray sampling static RandomRaySourceShape source_shape_; // Flag for linear source - static bool uncollided_flux_volume; // Flag for Initial Volume estimation + static bool no_volume_calc; // Flag for FCS flux calculation //---------------------------------------------------------------------------- // Public data members diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 48155fdde4a..fb0e6435b4f 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -57,7 +57,7 @@ FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) scalar_flux_final_.assign(n_source_elements_, 0.0); scalar_uncollided_flux_.assign(n_source_elements_, 0.0); scalar_first_collided_flux_.assign(n_source_elements_, 0.0); - source_.resize(n_source_elements_); + source_.assign(n_source_elements_, 0.0); external_source_.assign(n_source_elements_, 0.0); tally_task_.resize(n_source_elements_); volume_task_.resize(n_source_regions_); @@ -123,6 +123,9 @@ void FlatSourceDomain::batch_reset_fc() { parallel_fill(scalar_flux_new_, 0.0f); parallel_fill(was_hit_, 0); + if(RandomRay::no_volume_calc){ + parallel_fill(volume_t_, 0.0); + } } void FlatSourceDomain::accumulate_iteration_flux() @@ -133,30 +136,22 @@ void FlatSourceDomain::accumulate_iteration_flux() } } -// multiply First Collided Flux by volume and attribute it as fixed source -void FlatSourceDomain::update_external_flat_source() +int64_t FlatSourceDomain::check_fsr_hits() { -#pragma omp parallel for + int64_t n_hits = 0; +#pragma omp parallel for reduction(+ : n_hits) for (int sr = 0; sr < n_source_regions_; sr++) { - double volume = simulation_volume_ * volume_[sr]; - if (volume > 0.0) { - for (int g = 0; g < negroups_; g++) { - external_source_[sr * negroups_ + g] = - (scalar_first_collided_flux_[sr * negroups_ + g] / (volume)); - } - } else { - for (int g = 0; g < negroups_; g++) { - external_source_[sr * negroups_ + g] = 0.0f; - } + // Check if this cell was hit this iteration + int was_cell_hit = was_hit_[sr]; + if (was_cell_hit) { + n_hits++; } } -} -void FlatSourceDomain::update_external_linear_source() -{ - // default empty + return n_hits; } + // Compute new estimate of scattering + fission sources in each source region // based on the flux estimate from the previous iteration. void FlatSourceDomain::update_neutron_source(double k_eff) @@ -237,70 +232,128 @@ void FlatSourceDomain::normalize_scalar_flux_and_volumes( // Normalize scalar flux to total distance travelled by all rays this // iteration - if (!settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { - scalar_flux_new_[e] *= normalization_factor; - } + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_flux_new_[e] *= normalization_factor; + } // Accumulate cell-wise ray length tallies collected this iteration, then // update the simulation-averaged cell-wise volume estimates #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_t_[sr] += volume_[sr]; - volume_[sr] = volume_t_[sr] * volume_normalization_factor; - } + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_t_[sr] += volume_[sr]; + volume_[sr] = volume_t_[sr] * volume_normalization_factor; } +} + +void FlatSourceDomain::compute_uncollided_scalar_flux() +{ + // Temperature and angle indices, if using multiple temperature + const int t = 0; + const int a = 0; - if (settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_[sr] *= (volume_normalization_factor); + for (int sr = 0; sr < n_source_regions_; sr++) { + int was_cell_hit = was_hit_[sr]; + int material = material_[sr]; + + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + + if (was_cell_hit) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + scalar_uncollided_flux_[idx] = scalar_flux_new_[idx] / (sigma_t); + } } } } -int64_t FlatSourceDomain::check_fsr_hits() +// Normalize Uncollided Flux +void FlatSourceDomain::normalize_uncollided_scalar_flux( + double number_of_particles) { - int64_t n_hits = 0; -#pragma omp parallel for reduction(+ : n_hits) - for (int sr = 0; sr < n_source_regions_; sr++) { + // multiply by simulation volume + float normalization_factor = (1.0) / number_of_particles; - // Check if this cell was hit this iteration - int was_cell_hit = was_hit_[sr]; - if (was_cell_hit) { - n_hits++; - } + // Determine Source_total Scailing factor if first collided + double user_external_source_strength = 0.0; + for (auto& ext_source : model::external_sources) { + user_external_source_strength += ext_source->strength(); } - return n_hits; + float source_scailing_factor = + (user_external_source_strength * normalization_factor); + +#pragma omp parallel for + for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { + scalar_uncollided_flux_[e] *= source_scailing_factor; + } } -void FlatSourceDomain::compute_uncollided_scalar_flux() +// Compute First Collided flux +void FlatSourceDomain::compute_first_collided_flux() { - // Temperature and angle indices, if using multiple temperature const int t = 0; const int a = 0; #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { - int was_cell_hit = was_hit_[sr]; int material = material_[sr]; - for (int g = 0; g < negroups_; g++) { - int64_t idx = (sr * negroups_) + g; + for (int e_out = 0; e_out < negroups_; e_out++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); + float scatter_fixed_source = 0.0f; - if (was_cell_hit) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); - scalar_uncollided_flux_[idx] = scalar_flux_new_[idx] / (sigma_t); - } else { - scalar_uncollided_flux_[idx] = 0.0f; + for (int e_in = 0; e_in < negroups_; e_in++) { + float scalar_flux = scalar_uncollided_flux_[sr * negroups_ + e_in]; + + float sigma_s = data::mg.macro_xs_[material].get_xs( + MgxsType::NU_SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + scatter_fixed_source += sigma_s * scalar_flux; + } + + scalar_first_collided_flux_[sr * negroups_ + e_out] = + scatter_fixed_source / sigma_t; + } + } +} + +void FlatSourceDomain::uncollided_moments() +{ + // empty +} + +// Normalize First Collided Flux by volume and assign as fixed source +//compute_first_collided_external_source +void FlatSourceDomain::compute_first_collided_external_source() +{ +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + //check here + double volume = simulation_volume_ * volume_[sr]; + + if (volume > 0.0) { + for (int g = 0; g < negroups_; g++) { + external_source_[sr * negroups_ + g] = + (scalar_first_collided_flux_[sr * negroups_ + g] / (volume)); } } } } +void FlatSourceDomain::update_volume_uncollided_flux() +{ +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + double volume = volume_[sr] * simulation_volume_; + for (int g = 0; g < negroups_; g++) { + scalar_uncollided_flux_[sr * negroups_ + g] /= volume; + } + } +} + // Combine transport flux contributions and flat source contributions from the // previous iteration to generate this iteration's estimate of scalar flux. int64_t FlatSourceDomain::add_source_to_scalar_flux() @@ -356,57 +409,6 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux() return n_hits; } -// Normalize Uncollided Flux -void FlatSourceDomain::normalize_uncollided_scalar_flux( - double number_of_particles) -{ - // multiply by simulation volume - float normalization_factor = (1.0) / number_of_particles; - - // Determine Source_total Scailing factor if first collided - double user_external_source_strength = 0.0; - for (auto& ext_source : model::external_sources) { - user_external_source_strength += ext_source->strength(); - } - - float source_scailing_factor = - (user_external_source_strength * normalization_factor); - -#pragma omp parallel for - for (int64_t e = 0; e < scalar_uncollided_flux_.size(); e++) { - scalar_uncollided_flux_[e] *= source_scailing_factor; - } -} - -// Compute First Collided flux -void FlatSourceDomain::compute_first_collided_flux() -{ - const int t = 0; - const int a = 0; - -#pragma omp parallel for - for (int sr = 0; sr < n_source_regions_; sr++) { - int material = material_[sr]; - - for (int e_out = 0; e_out < negroups_; e_out++) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); - float scatter_fixed_source = 0.0f; - - for (int e_in = 0; e_in < negroups_; e_in++) { - float scalar_flux = scalar_uncollided_flux_[sr * negroups_ + e_in]; - - float sigma_s = data::mg.macro_xs_[material].get_xs( - MgxsType::NU_SCATTER, e_in, &e_out, nullptr, nullptr, t, a); - scatter_fixed_source += sigma_s * scalar_flux; - } - - scalar_first_collided_flux_[sr * negroups_ + e_out] = - scatter_fixed_source / sigma_t; - } - } -} - // Generates new estimate of k_eff based on the differences between this // iteration's estimate of the scalar flux and the last iteration's estimate. double FlatSourceDomain::compute_k_eff(double k_eff_old) const @@ -514,22 +516,6 @@ double FlatSourceDomain::compute_k_eff(double k_eff_old) const // be passed back to the caller to alert them that this function doesn't // need to be called for the remainder of the simulation. -void FlatSourceDomain::uncollided_moments() -{ - // empty -} - -void FlatSourceDomain::update_volume_uncollided_flux() -{ -#pragma omp parallel for - for (int sr = 0; sr < n_source_regions_; sr++) { - double volume = volume_[sr] * simulation_volume_; - for (int g = 0; g < negroups_; g++) { - scalar_uncollided_flux_[sr * negroups_ + g] /= volume; - } - } -} - void FlatSourceDomain::convert_source_regions_to_tallies() { openmc::simulation::time_tallies.start(); diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index cf53fa97f6d..d5bfb2d97c4 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -61,54 +61,32 @@ void LinearSourceDomain::batch_reset_fc() for (int64_t se = 0; se < n_source_elements_; se++) { flux_moments_new_[se] = {0.0, 0.0, 0.0}; } - if (!RandomRay::uncollided_flux_volume) { + if (RandomRay::no_volume_calc) { #pragma omp parallel for for (int64_t sr = 0; sr < n_source_regions_; sr++) { centroid_iteration_[sr] = {0.0, 0.0, 0.0}; centroid_[sr] = {0.0, 0.0, 0.0}; + centroid_t_[sr] = {0.0, 0.0, 0.0}; mom_matrix_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + mom_matrix_t_[sr] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; } } } -int64_t LinearSourceDomain::check_fsr_hits() -{ - int64_t n_hits = 0; -#pragma omp parallel for reduction(+ : n_hits) - for (int sr = 0; sr < n_source_regions_; sr++) { - - // Check if this cell was hit this iteration - int was_cell_hit = was_hit_[sr]; - if (was_cell_hit) { - n_hits++; - } - } - - return n_hits; -} - -void LinearSourceDomain::update_external_flat_source() -{ - FlatSourceDomain::update_external_flat_source(); -} - -void LinearSourceDomain::update_external_linear_source() +void LinearSourceDomain::compute_first_collided_external_source() { + FlatSourceDomain::compute_first_collided_external_source(); #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { double volume = simulation_volume_ * volume_[sr]; - // DIvide by volume and attribute it as external_source + // Normalize by volume and attribute it as external_source if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { external_source_gradients_[sr * negroups_ + g] = (flux_moments_first_collided_[sr * negroups_ + g] * (1.0 / volume)); } - } else { - for (int g = 0; g < negroups_; g++) { - external_source_gradients_[sr * negroups_ + g] *= 0.0; - } } } } @@ -178,9 +156,7 @@ void LinearSourceDomain::update_neutron_source(double k_eff) #pragma omp parallel for for (int se = 0; se < n_source_elements_; se++) { source_[se] += external_source_[se]; - //if (first_collided_mode) { - // source_gradients_[se] += external_source_gradients_[se]; - //} + source_gradients_[se] += external_source_gradients_[se]; } } @@ -195,40 +171,26 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( 1.0 / (total_active_distance_per_iteration * simulation::current_batch); // Normalize flux to total distance travelled by all rays this iteration - if (!settings::FIRST_COLLIDED_FLUX) { #pragma omp parallel for - for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { - scalar_flux_new_[e] *= normalization_factor; - flux_moments_new_[e] *= normalization_factor; - } + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_flux_new_[e] *= normalization_factor; + flux_moments_new_[e] *= normalization_factor; + } // Accumulate cell-wise ray length tallies collected this iteration, then // update the simulation-averaged cell-wise volume estimates #pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - centroid_t_[sr] += centroid_iteration_[sr]; - mom_matrix_t_[sr] += mom_matrix_[sr]; - volume_t_[sr] += volume_[sr]; - volume_[sr] = volume_t_[sr] * volume_normalization_factor; - if (volume_t_[sr] > 0.0) { - double inv_volume = 1.0 / volume_t_[sr]; - centroid_[sr] = centroid_t_[sr]; - centroid_[sr] *= inv_volume; - mom_matrix_[sr] = mom_matrix_t_[sr]; - mom_matrix_[sr] *= inv_volume; - } - } - } else { - // IF First_Collided_Method -#pragma omp parallel for - for (int64_t sr = 0; sr < n_source_regions_; sr++) { - volume_[sr] *= volume_normalization_factor; - if (volume_[sr] > 0.0) { - double inv_volume = 1.0 / volume_[sr]; - centroid_[sr] = centroid_iteration_[sr]; - centroid_[sr] *= inv_volume; - mom_matrix_[sr] *= inv_volume; - } + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + centroid_t_[sr] += centroid_iteration_[sr]; + mom_matrix_t_[sr] += mom_matrix_[sr]; + volume_t_[sr] += volume_[sr]; + volume_[sr] = volume_t_[sr] * volume_normalization_factor; + if (volume_t_[sr] > 0.0) { + double inv_volume = 1.0 / volume_t_[sr]; + centroid_[sr] = centroid_t_[sr]; + centroid_[sr] *= inv_volume; + mom_matrix_[sr] = mom_matrix_t_[sr]; + mom_matrix_[sr] *= inv_volume; } } } @@ -236,20 +198,9 @@ void LinearSourceDomain::normalize_scalar_flux_and_volumes( void LinearSourceDomain::compute_uncollided_scalar_flux() { #pragma omp parallel for - for (int sr = 0; sr < n_source_regions_; sr++) { - int was_cell_hit = was_hit_[sr]; - - for (int g = 0; g < negroups_; g++) { - int64_t idx = (sr * negroups_) + g; - - if (was_cell_hit) { - scalar_uncollided_flux_[idx] = scalar_flux_new_[idx]; - flux_moments_uncollided_[idx] = flux_moments_new_[idx]; - } else { - scalar_uncollided_flux_[idx] = 0.0f; - flux_moments_uncollided_[idx] *= 0.0; - } - } + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_uncollided_flux_[e] = scalar_flux_new_[e]; + flux_moments_uncollided_[e] = flux_moments_new_[e]; } } @@ -311,7 +262,7 @@ void LinearSourceDomain::normalize_uncollided_scalar_flux( double number_of_particles) { // multiply by simulation volume - float normalization_factor = (1.0) / number_of_particles; + float normalization_factor = (1.0f) / number_of_particles; // Determine Source_total Scailing factor if first collided double user_external_source_strength = 0.0; @@ -378,17 +329,11 @@ void LinearSourceDomain::uncollided_moments() { #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { - double volume = volume_[sr] * simulation_volume_; MomentMatrix invM = mom_matrix_[sr].inverse(); for (int g = 0; g < negroups_; g++) { int64_t idx = (sr * negroups_) + g; - if (volume > 0.0) { - flux_moments_uncollided_[idx] = - invM * flux_moments_uncollided_[idx] * (1.0 / volume); - } else { - flux_moments_uncollided_[idx] *= 0.0; - } + flux_moments_uncollided_[idx] = invM * flux_moments_uncollided_[idx]; } } } @@ -420,9 +365,9 @@ void LinearSourceDomain::all_reduce_replicated_source_regions() // We are going to assume we can safely cast Position, MomentArray, // and MomentMatrix to contiguous arrays of doubles for the MPI // allreduce operation. This is a safe assumption as typically - // compilers will at most pad to 8 byte boundaries. If a new FP32 MomentArray - // type is introduced, then there will likely be padding, in which case this - // function will need to become more complex. + // compilers will at most pad to 8 byte boundaries. If a new FP32 + // MomentArray type is introduced, then there will likely be padding, in + // which case this function will need to become more complex. if (sizeof(MomentArray) != 3 * sizeof(double) || sizeof(MomentMatrix) != 6 * sizeof(double)) { fatal_error("Unexpected buffer padding in linear source domain reduction."); @@ -452,9 +397,9 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; - //if (first_collided_mode) { - // phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; - //} + if (first_collided_mode) { + phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; + } return phi_flat + phi_solved.dot(local_r); } @@ -467,10 +412,7 @@ void LinearSourceDomain::update_volume_uncollided_flux() if (volume > 0.0) { for (int g = 0; g < negroups_; g++) { scalar_uncollided_flux_[sr * negroups_ + g] *= (1.0 / volume); - } - } else { - for (int g = 0; g < negroups_; g++) { - scalar_uncollided_flux_[sr * negroups_ + g] = 0.0f; + flux_moments_uncollided_[sr * negroups_ + g] *= (1.0 / volume); } } } diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index a2f105b4b1f..a5376604823 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -183,7 +183,7 @@ double RandomRay::distance_inactive_; double RandomRay::distance_active_; unique_ptr RandomRay::ray_source_; RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; -bool RandomRay::uncollided_flux_volume = {false}; +bool RandomRay::no_volume_calc = {false}; RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), @@ -197,9 +197,11 @@ RandomRay::RandomRay() } } -RandomRay::RandomRay(uint64_t ray_id, FlatSourceDomain* domain) : RandomRay() +RandomRay::RandomRay( + uint64_t ray_id, FlatSourceDomain* domain, bool uncollided_ray) + : RandomRay() { - initialize_ray(ray_id, domain); + initialize_ray(ray_id, domain, uncollided_ray); } // Transports ray until termination criteria are met @@ -207,7 +209,11 @@ uint64_t RandomRay::transport_history_based_single_ray() { using namespace openmc; while (alive()) { - event_advance_ray(); + if (no_volume_calc) { + event_advance_ray_first_collided(); + } else { + event_advance_ray(); + } if (!alive()) break; event_cross_surface(); @@ -216,19 +222,6 @@ uint64_t RandomRay::transport_history_based_single_ray() return n_event(); } -// Transports uncollided ray until termination criteria are met -uint64_t RandomRay::transport_history_based_single_ray_first_collided() -{ - using namespace openmc; - while (alive()) { - event_advance_ray_first_collided(); - if (!alive()) - break; - event_cross_surface(); - } - return n_event(); -} - // Transports ray across a single source region void RandomRay::event_advance_ray() { @@ -309,7 +302,22 @@ void RandomRay::event_advance_ray_first_collided() for (int j = 0; j < n_coord(); ++j) { coord(j).r += distance * coord(j).u; } - // total_distance_track_ = distance_travelled_; + // bool = true to kill ray + // ray is killed by default unless: + bool angular_flux_below_threshold = true; + for (int g = 0; g < negroups_; g++) { + if (angular_flux_initial_[g] > 0) { + // calculate the attenuation of ray (kills if ratio below threshold) + float ratio = angular_flux_[g] / angular_flux_initial_[g]; + if (ratio >= ray_threshold) { + angular_flux_below_threshold = false; + break; + } + } + } + if (angular_flux_below_threshold) { + wgt() = 0.0; + } } void RandomRay::attenuate_flux(double distance, bool is_active) @@ -364,18 +372,15 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) const int a = 0; // MOC incoming flux attenuation + source contribution/attenuation equation - if (!uncollided_flux_volume) { - for (int g = 0; g < negroups_; g++) { - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); - float tau = sigma_t * distance; - float exponential = - cjosey_exponential(tau); // exponential = 1 - exp(-tau) - float new_delta_psi = - (angular_flux_[g] - domain_->source_[source_element + g]) * exponential; - delta_psi_[g] = new_delta_psi; - angular_flux_[g] -= new_delta_psi; - } + for (int g = 0; g < negroups_; g++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + float tau = sigma_t * distance; + float exponential = cjosey_exponential(tau); // exponential = 1 - exp(-tau) + float new_delta_psi = + (angular_flux_[g] - domain_->source_[source_element + g]) * exponential; + delta_psi_[g] = new_delta_psi; + angular_flux_[g] -= new_delta_psi; } // If ray is in the active phase (not in dead zone), make contributions to @@ -385,22 +390,15 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) // Aquire lock for source region domain_->lock_[source_region].lock(); - if (!settings::FIRST_COLLIDED_FLUX) { - // Accumulate delta psi into new estimate of source region flux for - // this iteration - for (int g = 0; g < negroups_; g++) { - domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; - } - // Accomulate volume (ray distance) into this iteration's estimate - // of the source region's volume - domain_->volume_[source_region] += distance; - - } else if (uncollided_flux_volume) { + // Accumulate delta psi into new estimate of source region flux for + // this iteration + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + } + // Accomulate volume (ray distance) into this iteration's estimate + // of the source region's volume + if (!no_volume_calc) { domain_->volume_[source_region] += distance; - } else { - for (int g = 0; g < negroups_; g++) { - domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; - } } // If the source region hasn't been hit yet this iteration, @@ -418,41 +416,6 @@ void RandomRay::attenuate_flux_flat_source(double distance, bool is_active) } // Release lock domain_->lock_[source_region].unlock(); - - // check attenuation in FIRST_ COLLIDED_FLUX - // There is likely that an extra length of the rebounded ray after vacuum - // BC is being considered here, however, it does not impact volume - // calculations - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { - // bool = true to kill ray - // ray is killed by default unless: - bool angular_flux_below_threshold = true; - for (int g = 0; g < negroups_; g++) { - // check if initial angular flux in that energy group is zero, therefore - // there is no ratio kill contidion given in absolute value (smaller - // than ray_threshold) - if (angular_flux_initial_[g] == 0) { - // If initial angular flux is zero and below threshold, passes as true - // to kill the ray - if (angular_flux_[g] >= ray_threshold) { - angular_flux_below_threshold = false; - break; - } - // if angular_flux_[g] is less than threshold, it passes as true to - // kill ray - } else { - // calculate the attenuation of ray (kills if ratio below threshold) - float ratio = angular_flux_[g] / angular_flux_initial_[g]; - if (ratio >= ray_threshold) { - angular_flux_below_threshold = false; - break; - } - } - } - if (angular_flux_below_threshold) { - wgt() = 0.0; - } - } } } @@ -499,17 +462,6 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // be no estimate of its centroid. We detect this by checking if it has // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. - - // First collided source works on volume_ instead of volume_t_ - if (settings::FIRST_COLLIDED_FLUX) { - if (domain->volume_[source_region] > 0.0) { - rm_local = midpoint - centroid; - r0_local = r() - centroid; - } else { - rm_local = {0.0, 0.0, 0.0}; - r0_local = -u() * 0.5 * distance; - } - } else { if (domain->volume_t_[source_region]) { rm_local = midpoint - centroid; r0_local = r() - centroid; @@ -517,79 +469,60 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) rm_local = {0.0, 0.0, 0.0}; r0_local = -u() * 0.5 * distance; } - } double distance_2 = distance * distance; // Linear Source MOC incoming flux attenuation + source // contribution/attenuation equation - if (!uncollided_flux_volume) { - for (int g = 0; g < negroups_; g++) { + for (int g = 0; g < negroups_; g++) { - // Compute tau, the optical thickness of the ray segment - float sigma_t = data::mg.macro_xs_[material].get_xs( - MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); - float tau = sigma_t * distance; + // Compute tau, the optical thickness of the ray segment + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + float tau = sigma_t * distance; - // If tau is very small, set it to zero to avoid numerical issues. - // The following computations will still work with tau = 0. - if (tau < 1.0e-8f) { - tau = 0.0f; - } - - // Compute linear source terms, spatial and directional (dir), - // calculated from the source gradients dot product with local centroid - // and direction, respectively. - float h1 = 0.0f; - float spatial_source = 0.0f; - float dir_source = 0.0f; - float new_delta_psi = 0.0f; - - if (!settings::FIRST_COLLIDED_FLUX) { - spatial_source = - domain_->source_[source_element + g] + - rm_local.dot(domain->source_gradients_[source_element + g]); - dir_source = u().dot(domain->source_gradients_[source_element + g]); - - float gn = exponentialG(tau); - float f1 = 1.0f - tau * gn; - float f2 = (2.0f * gn - f1) * distance_2; - new_delta_psi = (angular_flux_[g] - spatial_source) * f1 * distance - - 0.5 * dir_source * f2; - - h1 = f1 - gn; - float g1 = 0.5f - h1; - float g2 = exponentialG2(tau); - g1 = g1 * spatial_source; - g2 = g2 * dir_source * distance * 0.5f; - h1 = h1 * angular_flux_[g]; - h1 = (g1 + g2 + h1) * distance_2; - spatial_source = spatial_source * distance + new_delta_psi; - - } else { - float gn = exponentialG(tau); - float f1 = 1.0f - tau * gn; - new_delta_psi = (angular_flux_[g]) * f1 * distance; - - h1 = f1 - gn; - h1 = h1 * angular_flux_[g]; - h1 = (h1)*distance_2; - spatial_source = new_delta_psi; - } - - // Store contributions for this group into arrays, so that they can - // be accumulated into the source region's estimates inside of the locked - // region. - delta_psi_[g] = new_delta_psi; - delta_moments_[g] = r0_local * spatial_source + u() * h1; - - // Update the angular flux for this group - angular_flux_[g] -= new_delta_psi * sigma_t; + // If tau is very small, set it to zero to avoid numerical issues. + // The following computations will still work with tau = 0. + if (tau < 1.0e-8f) { + tau = 0.0f; + } - // If 2D mode is enabled, the z-component of the flux moments is forced - // to zero - if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { - delta_moments_[g].z = 0.0; - } + // Compute linear source terms, spatial and directional (dir), + // calculated from the source gradients dot product with local centroid + // and direction, respectively. + + float spatial_source = + domain_->source_[source_element + g] + + rm_local.dot(domain->source_gradients_[source_element + g]); + float dir_source = u().dot(domain->source_gradients_[source_element + g]); + + float gn = exponentialG(tau); + float f1 = 1.0f - tau * gn; + float f2 = (2.0f * gn - f1) * distance_2; + float new_delta_psi = (angular_flux_[g] - spatial_source) * f1 * distance - + 0.5 * dir_source * f2; + + float h1 = f1 - gn; + float g1 = 0.5f - h1; + float g2 = exponentialG2(tau); + g1 = g1 * spatial_source; + g2 = g2 * dir_source * distance * 0.5f; + h1 = h1 * angular_flux_[g]; + h1 = (g1 + g2 + h1) * distance_2; + spatial_source = spatial_source * distance + new_delta_psi; + + // Store contributions for this group into arrays, so that they can + // be accumulated into the source region's estimates inside of the locked + // region. + delta_psi_[g] = new_delta_psi; + delta_moments_[g] = r0_local * spatial_source + u() * h1; + + // Update the angular flux for this group + angular_flux_[g] -= new_delta_psi * sigma_t; + + // If 2D mode is enabled, the z-component of the flux moments is forced + // to zero + if (source_shape_ == RandomRaySourceShape::LINEAR_XY) { + delta_moments_[g].z = 0.0; } } @@ -607,18 +540,17 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Accumulate deltas into the new estimate of source region flux for this // iteration - if (!uncollided_flux_volume) { + for (int g = 0; g < negroups_; g++) { domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; domain->flux_moments_new_[source_element + g] += delta_moments_[g]; } - } // Accumulate the volume (ray segment distance), centroid, and spatial // momement estimates into the running totals for the iteration for this // source region. The centroid and spatial momements estimates are scaled by // the ray segment length as part of length averaging of the estimates. - if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume) { + if (!no_volume_calc) { domain_->volume_[source_region] += distance; domain->centroid_iteration_[source_region] += midpoint * distance; moment_matrix_estimate *= distance; @@ -641,42 +573,12 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Release lock domain_->lock_[source_region].unlock(); - // check attenuation in FIRST_ COLLIDED_FLUX - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { - // bool = true to kill ray - // ray is killed by default unless: - bool angular_flux_below_threshold = true; - for (int g = 0; g < negroups_; g++) { - // check if initial angular flux in that energy group is zero, therefore - // there is no ratio kill contidion given in absolute value (smaller - // than ray_threshold) - if (angular_flux_initial_[g] == 0) { - // If initial angular flux is zero and below threshold, passes as true - // to kill the ray - if (angular_flux_[g] >= ray_threshold) { - angular_flux_below_threshold = false; - break; - } - // if angular_flux_[g] is less than threshold, it passes as true to - // kill ray - } else { - // calculate the attenuation of ray (kills if ratio below threshold) - float ratio = angular_flux_[g] / angular_flux_initial_[g]; - if (ratio >= ray_threshold) { - angular_flux_below_threshold = false; - break; - } - } - } - if (angular_flux_below_threshold) { - wgt() = 0.0; - } - } } } // updated -void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) +void RandomRay::initialize_ray( + uint64_t ray_id, FlatSourceDomain* domain, bool uncollided_ray) { domain_ = domain; @@ -690,49 +592,23 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) // set identifier for particle id() = simulation::work_index[mpi::rank] + ray_id; - if (settings::FIRST_COLLIDED_FLUX) { - simulation::current_batch = 1; - } - // set random number seed int64_t particle_seed = (simulation::current_batch - 1) * settings::n_particles + id(); init_particle_seeds(particle_seed, seeds()); stream() = STREAM_TRACKING; - // Sample from input Source - if (settings::FIRST_COLLIDED_FLUX && !uncollided_flux_volume) { - auto site = sample_external_source(current_seed()); - site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), - data::mg.rev_energy_bins_.end(), site.E); - site.E = negroups_ - site.E - 1.; - from_source(&site); - - std::unique_ptr& source_handle = - model::external_sources[site.source_id]; - IndependentSource* is = - dynamic_cast(source_handle.get()); - Discrete* energy_external_source = dynamic_cast(is->energy()); - - // double strength_factor = is->strength(); - - const auto& discrete_energies = energy_external_source->x(); - const auto& discrete_probs = energy_external_source->prob_actual(); - - for (int e = 0; e < discrete_energies.size(); e++) { - int g = data::mg.get_group_index(discrete_energies[e]); - angular_flux_[g] = discrete_probs[e]; // source_strength * / sigma_t; - angular_flux_initial_[g] = angular_flux_[g]; - } - + // Sample ray from input source distribution + SourceSite site; + if (uncollided_ray) { + site = sample_external_source(current_seed()); } else { - // Sample from ray source distribution - SourceSite site {ray_source_->sample(current_seed())}; - site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), - data::mg.rev_energy_bins_.end(), site.E); - site.E = negroups_ - site.E - 1.; - this->from_source(&site); + site = ray_source_->sample(current_seed()); } + site.E = lower_bound_index( + data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); + site.E = negroups_ - site.E - 1.; + from_source(&site); // Locate ray if (lowest_coord().cell == C_NONE) { @@ -746,22 +622,32 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) cell_born() = lowest_coord().cell; } - // initialize ray's starting angular flux spectrum - if (!settings::FIRST_COLLIDED_FLUX || uncollided_flux_volume) { + // Initialize angular flux spectrum from source input + if (uncollided_ray) { + Source* source_handle = model::external_sources[site.source_id].get(); + IndependentSource* is = dynamic_cast(source_handle); + Discrete* energy_external_source = dynamic_cast(is->energy()); + + const auto& discrete_energies = energy_external_source->x(); + const auto& discrete_probs = energy_external_source->prob_actual(); + + std::fill(angular_flux_.begin(), angular_flux_.end(), 0.0f); + std::fill(angular_flux_initial_.begin(), angular_flux_initial_.end(), 0.0f); + + for (int e = 0; e < discrete_energies.size(); e++) { + int g = data::mg.get_group_index(discrete_energies[e]); + angular_flux_[g] = discrete_probs[e]; + angular_flux_initial_[g] = angular_flux_[g]; + } + } else { // Initialize ray's starting angular flux to starting location's isotropic // source int i_cell = lowest_coord().cell; int64_t source_region_idx = domain_->source_region_offsets_[i_cell] + cell_instance(); - if (!settings::FIRST_COLLIDED_FLUX) { - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; - } - } else { - for (int g = 0; g < negroups_; g++) { - angular_flux_[g] = 1.0; - } + for (int g = 0; g < negroups_; g++) { + angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; } } } diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index db1d7c418e0..99249e0233c 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -285,9 +285,8 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (domain_->first_collided_mode) { - domain_->update_external_flat_source(); - // domain_->update_external_linear_source(); + if (settings::FIRST_COLLIDED_FLUX) { + domain_->compute_first_collided_external_source(); } // Update source term (scattering + fission) @@ -304,7 +303,7 @@ void RandomRaySimulation::simulate() #pragma omp parallel for schedule(dynamic) \ reduction(+ : total_geometric_intersections_) for (int i = 0; i < simulation::work_per_rank; i++) { - RandomRay ray(i, domain_.get()); + RandomRay ray(i, domain_.get(), false); total_geometric_intersections_ += ray.transport_history_based_single_ray(); } @@ -355,7 +354,7 @@ void RandomRaySimulation::simulate() finalize_batch(); } // End random ray power iteration loop - if (domain_->first_collided_mode) { + if (settings::FIRST_COLLIDED_FLUX) { domain_->update_volume_uncollided_flux(); } } @@ -457,11 +456,12 @@ void RandomRaySimulation::print_results_random_ray( header("Timing Statistics", 4); show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); - show_time("Total simulation time", time_total.elapsed()); - if (domain_->first_collided_mode) { - show_time("Volume estimation time", RandomRaySimulation::time_volume_fc, 1); - show_time("First Collided Source time", time_first_collided.elapsed(), 1); + if (domain_->first_collided_mode) { + show_time( + "Volume estimation time", RandomRaySimulation::time_volume_fc); + show_time("First Collided Source time", time_first_collided.elapsed()); } + show_time("Total simulation time", time_total.elapsed()); show_time("Transport sweep only", time_transport.elapsed(), 1); show_time("Source update only", time_update_src.elapsed(), 1); show_time("Tally conversion only", time_tallies.elapsed(), 1); @@ -487,22 +487,17 @@ void RandomRaySimulation::first_collided_source_simulation() { header("FIRST COLLIDED SOURCE METHOD", 3); simulation::time_first_collided.start(); - - // Turn on volume estimation - // Volume estimation is necessary to scale the first collided source - // accordingly. Estimation of linear moments in linear source has direct impact - // into final solution accuracy. - fmt::print("Initial volume estimation..."); - RandomRay::uncollided_flux_volume = true; simulation::current_batch = 1; + fmt::print("Initial volume estimation..."); + // Volume estimation is necessary to scale the first collided source + // accordingly. Estimation of linear moments in linear source has direct + // impact into final solution accuracy. - // Calculate volume -#pragma omp parallel for schedule(dynamic) \ - reduction(+ : total_geometric_intersections_volume_) + // Ray tracing - volume calculation +#pragma omp parallel for schedule(dynamic) for (int i = 0; i < settings::n_volume_estimator_rays; i++) { - RandomRay ray(i, domain_.get()); - total_geometric_intersections_volume_ += - ray.transport_history_based_single_ray(); + RandomRay ray(i, domain_.get(), false); + ray.transport_history_based_single_ray(); } // Normalizing volumes @@ -511,32 +506,34 @@ void RandomRaySimulation::first_collided_source_simulation() // Reset parameters for First Collided Source Method domain_->batch_reset_fc(); - RandomRay::uncollided_flux_volume = false; + RandomRay::no_volume_calc = true; // print volume estimation time time_volume_fc = simulation::time_first_collided.elapsed(); fmt::print("completed.\n\n"); //============================================================================== - // First Collided Source - Transport Loop // It will operate until meet any criteria (1-3): - // (1) There is no new FSR hits from batch_first_collided (n-1) to the next + // (1) There isn't new FSR hits from batch_first_collided (n-1) to the next // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs print_columns(); + while (domain_->new_fsr_fc) { // Ray tracing and attenuation -#pragma omp parallel for \ - reduction(+ : total_geometric_intersections_fcs_) +#pragma omp parallel for for (int i = old_n_rays; i < new_n_rays; i++) { - RandomRay ray(i, domain_.get()); - total_geometric_intersections_fcs_ += - ray.transport_history_based_single_ray_first_collided(); + RandomRay ray(i, domain_.get(), true); + ray.transport_history_based_single_ray(); } int64_t n_hits_new = domain_->check_fsr_hits(); + // print results + fmt::print( + " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); + // BREAK STATEMENT if (n_hits_new == n_hits_old) { domain_->new_fsr_fc = {false}; // Condition (1) @@ -546,10 +543,6 @@ void RandomRaySimulation::first_collided_source_simulation() domain_->new_fsr_fc = {false}; // Condition (3) } - // print results - fmt::print( - " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); - // update values for next batch n_hits_old = n_hits_new; old_n_rays = new_n_rays; @@ -566,14 +559,16 @@ void RandomRaySimulation::first_collided_source_simulation() // compute first_collided_fixed_source domain_->compute_first_collided_flux(); - // apply invM*uncollided flux? - // domain_->uncollided_moments(); + // apply invM*uncollided flux + domain_->uncollided_moments(); // reset values for RandomRay iteration - domain_->batch_reset_fc(); // clean-up of key variables (preserves volume) - domain_->first_collided_mode = {true}; // add FC contribution to RR - settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations + domain_->batch_reset_fc(); // clean-up of key variables (preserves just volume_) + RandomRay::no_volume_calc = {false}; + + //settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations simulation::current_batch = 0; // garantee the first batch will be 1 in RR + domain_->first_collided_mode = {true}; // add FC contribution to RR // compute First Collided Method simulation time simulation::time_first_collided.stop(); diff --git a/src/settings.cpp b/src/settings.cpp index f5bfe56cb8c..4472b1f6f4e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -134,9 +134,9 @@ int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; // HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {false}; -int n_uncollided_rays {1280000}; -int n_volume_estimator_rays {10000}; +bool FIRST_COLLIDED_FLUX {true}; +int n_uncollided_rays {160000}; +int n_volume_estimator_rays {100000}; } // namespace settings From d69c6960fe3725536469fc54bbb4532c3653ccca Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 7 Aug 2024 14:22:10 -0500 Subject: [PATCH 18/27] changes in python input for first_collided_source method --- openmc/settings.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/openmc/settings.py b/openmc/settings.py index ce97f138f24..5862d1ae135 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -164,6 +164,19 @@ class Settings: cm/cm^3. When disabled, flux tallies will be reported in units of cm (i.e., total distance traveled by neutrons in the spatial tally region). + :first_collided_source: + Boolean that indicates if first collided source method (FSC) is + used to initialize the external source input. Default is 'False'. + :first_collided_rays: + Number of rays (int) used to generate the first collided source. + If not provided, the method will automatically run enough rays to + adequately converge the first collided source, via an iterative + doubling process. If provided, the method will run the exact + prescribed amount. + :first_collided_volume_rays: + Number of rays (int) used to estimate the initial volume for the + first collied source calculation. If not provided, it will use the + same number of rays as the main random ray solver stage. .. versionadded:: 0.15.0 resonance_scattering : dict @@ -1096,6 +1109,14 @@ def random_ray(self, random_ray: dict): ('flat', 'linear', 'linear_xy')) elif key == 'volume_normalized_flux_tallies': cv.check_type('volume normalized flux tallies', random_ray[key], bool) + elif key == 'first_collided_source': + cv.check_type('first_collided_source', random_ray[key], bool) + elif key == 'first_collided_rays': + cv.check_type('first_collided_rays', random_ray[key], int) + cv.check_greater_than('first_collided_rays',random_ray[key], 0) + elif key == 'first_collided_volume_rays': + cv.check_type('first_collided_volume_rays', random_ray[key], int) + cv.check_greater_than('first_collided_volume_rays',random_ray[key], 0) else: raise ValueError(f'Unable to set random ray to "{key}" which is ' 'unsupported by OpenMC') @@ -1895,6 +1916,12 @@ def _random_ray_from_xml_element(self, root): self.random_ray['volume_normalized_flux_tallies'] = ( child.text in ('true', '1') ) + elif child.tag == 'first_collided_source': + self.random_ray['first_collided_source'] = ( + child.text in ('true', '1') + ) + elif child.tag in ('first_collided_rays', 'first_collided_volume_rays'): + self.random_ray[child.tag] = int(child.text) def to_xml_element(self, mesh_memo=None): """Create a 'settings' element to be written to an XML file. From b190bd30dca5aa5fefb16b9d5d2f6af91c15b1c4 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 7 Aug 2024 14:46:14 -0500 Subject: [PATCH 19/27] UI updates in settings and random_rays_simulation file --- src/random_ray/random_ray_simulation.cpp | 36 +++++++++++------------- src/settings.cpp | 20 +++++++++++++ 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 99249e0233c..32a46c8e76b 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -166,26 +166,22 @@ void validate_random_ray_inputs() "random ray mode"); } - // Check for isotropic source - UnitSphereDistribution* angle_dist = is->angle(); - Isotropic* id = dynamic_cast(angle_dist); - if (!id) { - fatal_error( - "Invalid source definition -- only isotropic external sources are " - "allowed in random ray mode."); - } + if (!first_collided_source_) { + // Check for isotropic source + UnitSphereDistribution* angle_dist = is->angle(); + Isotropic* id = dynamic_cast(angle_dist); + if (!id) { + fatal_error( + "Invalid source definition -- only isotropic external sources are " + "allowed in random ray mode."); + } - // Validate that a domain ID was specified - if (is->domain_ids().size() == 0) { - if (!settings::FIRST_COLLIDED_FLUX) { + // Validate that a domain ID was specified + if (is->domain_ids().size() == 0) { fatal_error("Fixed sources must be specified by domain " "id (cell, material, or universe) in random ray mode."); - } else if (settings::FIRST_COLLIDED_FLUX) { - // - fmt::print("??? add First collided condition and fatal error here\n"); } } - // Check that a discrete energy distribution was used Distribution* d = is->energy(); Discrete* dd = dynamic_cast(d); @@ -456,9 +452,8 @@ void RandomRaySimulation::print_results_random_ray( header("Timing Statistics", 4); show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); - if (domain_->first_collided_mode) { - show_time( - "Volume estimation time", RandomRaySimulation::time_volume_fc); + if (domain_->first_collided_mode) { + show_time("Volume estimation time", RandomRaySimulation::time_volume_fc); show_time("First Collided Source time", time_first_collided.elapsed()); } show_time("Total simulation time", time_total.elapsed()); @@ -563,10 +558,11 @@ void RandomRaySimulation::first_collided_source_simulation() domain_->uncollided_moments(); // reset values for RandomRay iteration - domain_->batch_reset_fc(); // clean-up of key variables (preserves just volume_) + domain_ + ->batch_reset_fc(); // clean-up of key variables (preserves just volume_) RandomRay::no_volume_calc = {false}; - //settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations + // settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations simulation::current_batch = 0; // garantee the first batch will be 1 in RR domain_->first_collided_mode = {true}; // add FC contribution to RR diff --git a/src/settings.cpp b/src/settings.cpp index 4472b1f6f4e..0832e4a2884 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -290,6 +290,26 @@ void get_run_parameters(pugi::xml_node node_base) FlatSourceDomain::volume_normalized_flux_tallies_ = get_node_value_bool(random_ray_node, "volume_normalized_flux_tallies"); } + if (check_for_node(random_ray_node, "first_collided_source")) { + RandomRaySimulation::first_collided_source_ = + get_node_value_bool(random_ray_node, "first_collided_source"); + + if (check_for_node(random_ray_node, "first_collided_rays")) { + RandomRaySimulation::first_collided_rays_ = + std::stoi(get_node_value(random_ray_node, "first_collided_rays")); + if (RandomRaySimulation::first_collided_rays_ <= 0) { + fatal_error("Number of first collided rays must be greater than 0"); + } + } + if (check_for_node(random_ray_node, "first_collided_volume_rays")) { + RandomRaySimulation::first_collided_volume_rays_ = std::stoi( + get_node_value(random_ray_node, "first_collided_volume_rays")); + if (RandomRaySimulation::first_collided_volume_rays_ <= 0) { + fatal_error("Number of rays for first collided initial volume " + "estimation must be greater than 0"); + } + } + } } } From f5acc0a20029339355cc9d3f9b87772f374d4335 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Wed, 7 Aug 2024 16:13:27 -0500 Subject: [PATCH 20/27] working input setup --- .../openmc/random_ray/flat_source_domain.h | 1 - include/openmc/random_ray/random_ray.h | 4 ++ .../openmc/random_ray/random_ray_simulation.h | 13 +++--- src/output.cpp | 3 +- src/random_ray/flat_source_domain.cpp | 11 +++-- src/random_ray/linear_source_domain.cpp | 2 +- src/random_ray/random_ray.cpp | 3 ++ src/random_ray/random_ray_simulation.cpp | 43 ++++++++++--------- src/settings.cpp | 15 +++---- 9 files changed, 49 insertions(+), 46 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 3698da0796b..020a8337ae2 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -126,7 +126,6 @@ class FlatSourceDomain { //---------------------------------------------------------------------------- // Static Data members static bool volume_normalized_flux_tallies_; - static bool first_collided_mode; //---------------------------------------------------------------------------- // Public Data members diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index 085dabaf609..383eb803605 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -41,6 +41,10 @@ class RandomRay : public Particle { static unique_ptr ray_source_; // Starting source for ray sampling static RandomRaySourceShape source_shape_; // Flag for linear source + static bool first_collided_source_; + static int first_collided_rays_; + static int first_collided_volume_rays_; + static bool no_volume_calc; // Flag for FCS flux calculation //---------------------------------------------------------------------------- diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index 06513a7486e..21b87300b3b 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -31,17 +31,16 @@ class RandomRaySimulation { //---------------------------------------------------------------------------- // Data members - // First collided method variables for automatic n_uncollided_rays + // First collided method variables for automatic first_collided_rays_ int64_t n_hits_new {0}; int64_t n_hits_old {0}; - int new_n_rays {settings::n_uncollided_rays}; + int new_n_rays {1000}; int old_n_rays {0}; int batch_first_collided {1}; - int n_rays_max {1000000}; - bool user_input_rays {false}; + int n_rays_max {10000000}; - // volume estimation timer - double time_volume_fc {0}; + // Initial volume estimation timer - First Collided Source Method + double time_volume_fc; private: @@ -57,8 +56,6 @@ class RandomRaySimulation { // Tracks the total number of geometric intersections by all rays for // reporting uint64_t total_geometric_intersections_ {0}; - uint64_t total_geometric_intersections_volume_ {0}; - uint64_t total_geometric_intersections_fcs_ {0}; // Number of energy groups int negroups_; diff --git a/src/output.cpp b/src/output.cpp index 4f7733c8fa6..b207fe6724a 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -32,6 +32,7 @@ #include "openmc/nuclide.h" #include "openmc/plot.h" #include "openmc/random_ray/flat_source_domain.h" +#include "openmc/random_ray/random_ray.h" #include "openmc/reaction.h" #include "openmc/settings.h" #include "openmc/simulation.h" @@ -376,7 +377,7 @@ void print_build_info() void print_columns() { - if (settings::FIRST_COLLIDED_FLUX){ + if (RandomRay::first_collided_source_){ fmt::print(" Batch Rays Total Source Regions Discovered\n" " ====== ======= =================================\n"); } else if (settings::entropy_on) { diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index fb0e6435b4f..8bceb7b6aa2 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -25,7 +25,6 @@ namespace openmc { // Static Variable Declarations bool FlatSourceDomain::volume_normalized_flux_tallies_ {false}; -bool FlatSourceDomain::first_collided_mode {false}; FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) { @@ -710,7 +709,7 @@ void FlatSourceDomain::random_ray_tally() for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; - if (first_collided_mode) { + if (RandomRay::first_collided_source_) { flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); } else { @@ -899,14 +898,14 @@ void FlatSourceDomain::all_reduce_replicated_source_regions() double FlatSourceDomain::evaluate_flux_at_point( Position r, int64_t sr, int g) const { - if (!first_collided_mode) { + if (RandomRay::first_collided_source_) { return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive)); + (settings::n_batches - settings::n_inactive) + + scalar_uncollided_flux_[sr * negroups_ + g]); } else { // add uncollided flux if First Collided method is used return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive) + - scalar_uncollided_flux_[sr * negroups_ + g]); + (settings::n_batches - settings::n_inactive)); } } diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index d5bfb2d97c4..6e6e0593b4a 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -397,7 +397,7 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; - if (first_collided_mode) { + if (RandomRay::first_collided_source_) { phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; } diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index a5376604823..57e6617589c 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -184,6 +184,9 @@ double RandomRay::distance_active_; unique_ptr RandomRay::ray_source_; RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; bool RandomRay::no_volume_calc = {false}; +bool RandomRay::first_collided_source_ {false}; +int RandomRay::first_collided_rays_ {-1}; +int RandomRay::first_collided_volume_rays_ {-1}; RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 32a46c8e76b..121f8ad9495 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -166,7 +166,7 @@ void validate_random_ray_inputs() "random ray mode"); } - if (!first_collided_source_) { + if (!RandomRay::first_collided_source_) { // Check for isotropic source UnitSphereDistribution* angle_dist = is->angle(); Isotropic* id = dynamic_cast(angle_dist); @@ -262,7 +262,7 @@ RandomRaySimulation::RandomRaySimulation() void RandomRaySimulation::simulate() { if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (settings::FIRST_COLLIDED_FLUX == false) { + if (!RandomRay::first_collided_source_) { // Transfer external source user inputs onto random ray source regions domain_->convert_external_sources(); domain_->count_external_source_regions(); @@ -281,7 +281,7 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (settings::FIRST_COLLIDED_FLUX) { + if (RandomRay::first_collided_source_) { domain_->compute_first_collided_external_source(); } @@ -350,7 +350,7 @@ void RandomRaySimulation::simulate() finalize_batch(); } // End random ray power iteration loop - if (settings::FIRST_COLLIDED_FLUX) { + if (RandomRay::first_collided_source_) { domain_->update_volume_uncollided_flux(); } } @@ -431,7 +431,7 @@ void RandomRaySimulation::print_results_random_ray( fmt::print( " Total Iterations = {}\n", settings::n_batches); fmt::print(" Flat Source Regions (FSRs) = {}\n", n_source_regions); - if (!domain_->first_collided_mode) { + if (!RandomRay::first_collided_source_) { fmt::print( " FSRs Containing External Sources = {}\n", n_external_source_regions); } @@ -452,7 +452,7 @@ void RandomRaySimulation::print_results_random_ray( header("Timing Statistics", 4); show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); - if (domain_->first_collided_mode) { + if (RandomRay::first_collided_source_) { show_time("Volume estimation time", RandomRaySimulation::time_volume_fc); show_time("First Collided Source time", time_first_collided.elapsed()); } @@ -487,17 +487,20 @@ void RandomRaySimulation::first_collided_source_simulation() // Volume estimation is necessary to scale the first collided source // accordingly. Estimation of linear moments in linear source has direct // impact into final solution accuracy. + if (RandomRay::first_collided_volume_rays_ == -1) { + RandomRay::first_collided_volume_rays_ = settings::n_particles; + } // Ray tracing - volume calculation #pragma omp parallel for schedule(dynamic) - for (int i = 0; i < settings::n_volume_estimator_rays; i++) { + for (int i = 0; i < RandomRay::first_collided_volume_rays_; i++) { RandomRay ray(i, domain_.get(), false); ray.transport_history_based_single_ray(); } // Normalizing volumes domain_->normalize_scalar_flux_and_volumes( - settings::n_volume_estimator_rays * RandomRay::distance_active_); + RandomRay::first_collided_volume_rays_ * RandomRay::distance_active_); // Reset parameters for First Collided Source Method domain_->batch_reset_fc(); @@ -513,8 +516,12 @@ void RandomRaySimulation::first_collided_source_simulation() // (1) There isn't new FSR hits from batch_first_collided (n-1) to the next // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs print_columns(); + if (!RandomRay::first_collided_rays_ == -1) { + new_n_rays = RandomRay::first_collided_rays_; + n_rays_max = new_n_rays; + } - while (domain_->new_fsr_fc) { + while (old_n_rays < n_rays_max) { // Condition (2) // Ray tracing and attenuation #pragma omp parallel for @@ -528,21 +535,20 @@ void RandomRaySimulation::first_collided_source_simulation() // print results fmt::print( " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); + + // update values for next batch + batch_first_collided++; + old_n_rays = new_n_rays; + new_n_rays *= 2; // BREAK STATEMENT if (n_hits_new == n_hits_old) { - domain_->new_fsr_fc = {false}; // Condition (1) - } else if (new_n_rays >= n_rays_max) { - domain_->new_fsr_fc = {false}; // Condition (2) + break; // Condition (1) } else if (static_cast(n_hits_new) >= domain_->n_source_regions_) { - domain_->new_fsr_fc = {false}; // Condition (3) + break; // Condition (3) } - // update values for next batch n_hits_old = n_hits_new; - old_n_rays = new_n_rays; - new_n_rays *= 2; - batch_first_collided++; } // Compute scalar_uncollided_flux @@ -561,10 +567,7 @@ void RandomRaySimulation::first_collided_source_simulation() domain_ ->batch_reset_fc(); // clean-up of key variables (preserves just volume_) RandomRay::no_volume_calc = {false}; - - // settings::FIRST_COLLIDED_FLUX = {false}; // regular RR calculations simulation::current_batch = 0; // garantee the first batch will be 1 in RR - domain_->first_collided_mode = {true}; // add FC contribution to RR // compute First Collided Method simulation time simulation::time_first_collided.stop(); diff --git a/src/settings.cpp b/src/settings.cpp index 0832e4a2884..30710066dca 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -25,6 +25,7 @@ #include "openmc/plot.h" #include "openmc/random_lcg.h" #include "openmc/random_ray/random_ray.h" +#include "openmc/random_ray/random_ray_simulation.h" #include "openmc/simulation.h" #include "openmc/source.h" #include "openmc/string_utils.h" @@ -133,10 +134,6 @@ int trigger_batch_interval {1}; int verbosity {7}; double weight_cutoff {0.25}; double weight_survive {1.0}; -// HARDCODED INPUTS - First Collided Flux -bool FIRST_COLLIDED_FLUX {true}; -int n_uncollided_rays {160000}; -int n_volume_estimator_rays {100000}; } // namespace settings @@ -291,20 +288,20 @@ void get_run_parameters(pugi::xml_node node_base) get_node_value_bool(random_ray_node, "volume_normalized_flux_tallies"); } if (check_for_node(random_ray_node, "first_collided_source")) { - RandomRaySimulation::first_collided_source_ = + RandomRay::first_collided_source_ = get_node_value_bool(random_ray_node, "first_collided_source"); if (check_for_node(random_ray_node, "first_collided_rays")) { - RandomRaySimulation::first_collided_rays_ = + RandomRay::first_collided_rays_ = std::stoi(get_node_value(random_ray_node, "first_collided_rays")); - if (RandomRaySimulation::first_collided_rays_ <= 0) { + if (RandomRay::first_collided_rays_ <= 0) { fatal_error("Number of first collided rays must be greater than 0"); } } if (check_for_node(random_ray_node, "first_collided_volume_rays")) { - RandomRaySimulation::first_collided_volume_rays_ = std::stoi( + RandomRay::first_collided_volume_rays_ = std::stoi( get_node_value(random_ray_node, "first_collided_volume_rays")); - if (RandomRaySimulation::first_collided_volume_rays_ <= 0) { + if (RandomRay::first_collided_volume_rays_ <= 0) { fatal_error("Number of rays for first collided initial volume " "estimation must be greater than 0"); } From e47046d0f2f1e4184f4bbc614531f384e3367f01 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 8 Aug 2024 10:35:47 -0500 Subject: [PATCH 21/27] regression tests added (2) --- src/random_ray/linear_source_domain.cpp | 1 + src/random_ray/random_ray.cpp | 24 +- src/random_ray/random_ray_simulation.cpp | 14 +- .../random_ray_first_collided/__init__.py | 0 .../flat/inputs_true.dat | 245 +++++++++++++++++ .../flat/results_true.dat | 9 + .../linear/inputs_true.dat | 245 +++++++++++++++++ .../linear/results_true.dat | 9 + .../random_ray_first_collided/test.py | 36 +++ .../__init__.py | 0 .../inputs_true.dat | 246 ++++++++++++++++++ .../results_true.dat | 9 + .../random_ray_first_collided_rays/test.py | 35 +++ 13 files changed, 856 insertions(+), 17 deletions(-) create mode 100644 tests/regression_tests/random_ray_first_collided/__init__.py create mode 100644 tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided/flat/results_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided/linear/results_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided/test.py create mode 100644 tests/regression_tests/random_ray_first_collided_rays/__init__.py create mode 100644 tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided_rays/results_true.dat create mode 100644 tests/regression_tests/random_ray_first_collided_rays/test.py diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 6e6e0593b4a..1b4fe4e7840 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -327,6 +327,7 @@ void LinearSourceDomain::compute_first_collided_flux() void LinearSourceDomain::uncollided_moments() { + #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { MomentMatrix invM = mom_matrix_[sr].inverse(); diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 57e6617589c..a8b52834bc2 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -465,13 +465,13 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // be no estimate of its centroid. We detect this by checking if it has // any accumulated volume. If its volume is zero, just use the midpoint // of the ray as the region's centroid. - if (domain->volume_t_[source_region]) { - rm_local = midpoint - centroid; - r0_local = r() - centroid; - } else { - rm_local = {0.0, 0.0, 0.0}; - r0_local = -u() * 0.5 * distance; - } + if (domain->volume_t_[source_region]) { + rm_local = midpoint - centroid; + r0_local = r() - centroid; + } else { + rm_local = {0.0, 0.0, 0.0}; + r0_local = -u() * 0.5 * distance; + } double distance_2 = distance * distance; // Linear Source MOC incoming flux attenuation + source @@ -544,10 +544,10 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Accumulate deltas into the new estimate of source region flux for this // iteration - for (int g = 0; g < negroups_; g++) { - domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; - domain->flux_moments_new_[source_element + g] += delta_moments_[g]; - } + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + domain->flux_moments_new_[source_element + g] += delta_moments_[g]; + } // Accumulate the volume (ray segment distance), centroid, and spatial // momement estimates into the running totals for the iteration for this @@ -575,7 +575,6 @@ void RandomRay::attenuate_flux_linear_source(double distance, bool is_active) // Release lock domain_->lock_[source_region].unlock(); - } } @@ -651,6 +650,7 @@ void RandomRay::initialize_ray( for (int g = 0; g < negroups_; g++) { angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + // check for zero angular_flux_[g] causing ray to die? } } } diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 121f8ad9495..d3a59942a02 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -480,7 +480,11 @@ void RandomRaySimulation::print_results_random_ray( void RandomRaySimulation::first_collided_source_simulation() { - header("FIRST COLLIDED SOURCE METHOD", 3); + if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT) { + header("FIRST COLLIDED SOURCE METHOD - Flat source", 3); + } else { + header("FIRST COLLIDED SOURCE METHOD - Linear source", 3); + } simulation::time_first_collided.start(); simulation::current_batch = 1; fmt::print("Initial volume estimation..."); @@ -492,7 +496,7 @@ void RandomRaySimulation::first_collided_source_simulation() } // Ray tracing - volume calculation -#pragma omp parallel for schedule(dynamic) +#pragma omp parallel for for (int i = 0; i < RandomRay::first_collided_volume_rays_; i++) { RandomRay ray(i, domain_.get(), false); ray.transport_history_based_single_ray(); @@ -516,9 +520,9 @@ void RandomRaySimulation::first_collided_source_simulation() // (1) There isn't new FSR hits from batch_first_collided (n-1) to the next // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs print_columns(); - if (!RandomRay::first_collided_rays_ == -1) { + if (RandomRay::first_collided_rays_ != -1) { new_n_rays = RandomRay::first_collided_rays_; - n_rays_max = new_n_rays; + n_rays_max = RandomRay::first_collided_rays_; } while (old_n_rays < n_rays_max) { // Condition (2) @@ -535,7 +539,7 @@ void RandomRaySimulation::first_collided_source_simulation() // print results fmt::print( " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); - + // update values for next batch batch_first_collided++; old_n_rays = new_n_rays; diff --git a/tests/regression_tests/random_ray_first_collided/__init__.py b/tests/regression_tests/random_ray_first_collided/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat b/tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat new file mode 100644 index 00000000000..ab1616862f8 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat @@ -0,0 +1,245 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + 2.5 2.5 2.5 + 12 12 12 + 0.0 0.0 0.0 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + + + + + + + + + + fixed source + 90 + 10 + 5 + + + 0.0 0.0 0.0 5.0 5.0 5.0 + + + 100.0 1.0 + + + multi-group + + 500.0 + 100.0 + + + 0.0 0.0 0.0 30.0 30.0 30.0 + + + True + flat + True + + + + + 1 + + + 2 + + + 3 + + + 3 + flux + tracklength + + + 2 + flux + tracklength + + + 1 + flux + tracklength + + + diff --git a/tests/regression_tests/random_ray_first_collided/flat/results_true.dat b/tests/regression_tests/random_ray_first_collided/flat/results_true.dat new file mode 100644 index 00000000000..da1c06f01bf --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided/flat/results_true.dat @@ -0,0 +1,9 @@ +tally 1: +5.237694E-01 +5.603795E-02 +tally 2: +2.626249E-02 +1.379769E-04 +tally 3: +1.832107E-03 +6.713236E-07 diff --git a/tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat b/tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat new file mode 100644 index 00000000000..f097feaa487 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat @@ -0,0 +1,245 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + 2.5 2.5 2.5 + 12 12 12 + 0.0 0.0 0.0 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + + + + + + + + + + fixed source + 90 + 10 + 5 + + + 0.0 0.0 0.0 5.0 5.0 5.0 + + + 100.0 1.0 + + + multi-group + + 500.0 + 100.0 + + + 0.0 0.0 0.0 30.0 30.0 30.0 + + + True + linear + True + + + + + 1 + + + 2 + + + 3 + + + 3 + flux + tracklength + + + 2 + flux + tracklength + + + 1 + flux + tracklength + + + diff --git a/tests/regression_tests/random_ray_first_collided/linear/results_true.dat b/tests/regression_tests/random_ray_first_collided/linear/results_true.dat new file mode 100644 index 00000000000..0aa82ed27aa --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided/linear/results_true.dat @@ -0,0 +1,9 @@ +tally 1: +1.684540E-01 +9.991864E-01 +tally 2: +-3.623011E-02 +3.710201E-04 +tally 3: +2.184070E-03 +9.589758E-07 diff --git a/tests/regression_tests/random_ray_first_collided/test.py b/tests/regression_tests/random_ray_first_collided/test.py new file mode 100644 index 00000000000..d2ba7a2cb49 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided/test.py @@ -0,0 +1,36 @@ +import os + +import numpy as np +import openmc +from openmc.utility_funcs import change_directory +from openmc.examples import random_ray_three_region_cube +import pytest + +from tests.testing_harness import TolerantPyAPITestHarness + + +class MGXSTestHarness(TolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +@pytest.mark.parametrize("shape", ["flat", "linear"]) +def test_random_ray_first_collided(shape): + with change_directory(shape): + openmc.reset_auto_ids() + model = random_ray_three_region_cube() + model.settings.random_ray['source_shape'] = shape + model.settings.random_ray['first_collided_source'] = True + strengths = [1.0] # Good - fast group appears largest (besides most thermal) + midpoints = [100.0] + energy_dist = openmc.stats.Discrete(x=midpoints,p=strengths) + lower_left_src = [0.0, 0.0, 0.0] + upper_right_src = [5.0, 5.0, 5.0] + spatial_distribution = openmc.stats.Box(lower_left_src, upper_right_src, only_fissionable=False) + source = openmc.IndependentSource(space=spatial_distribution, energy=energy_dist, strength = 3.14) + model.settings.source = [source] + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() \ No newline at end of file diff --git a/tests/regression_tests/random_ray_first_collided_rays/__init__.py b/tests/regression_tests/random_ray_first_collided_rays/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat b/tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat new file mode 100644 index 00000000000..ec56c9e93b8 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat @@ -0,0 +1,246 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + 2.5 2.5 2.5 + 12 12 12 + 0.0 0.0 0.0 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 + + + + + + + + + + fixed source + 90 + 10 + 5 + + + 0.0 0.0 0.0 5.0 5.0 5.0 + + + 100.0 1.0 + + + multi-group + + 500.0 + 100.0 + + + 0.0 0.0 0.0 30.0 30.0 30.0 + + + True + True + 1246 + 2000 + + + + + 1 + + + 2 + + + 3 + + + 3 + flux + tracklength + + + 2 + flux + tracklength + + + 1 + flux + tracklength + + + diff --git a/tests/regression_tests/random_ray_first_collided_rays/results_true.dat b/tests/regression_tests/random_ray_first_collided_rays/results_true.dat new file mode 100644 index 00000000000..aa2fc17f380 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided_rays/results_true.dat @@ -0,0 +1,9 @@ +tally 1: +5.179652E-01 +5.485090E-02 +tally 2: +2.634285E-02 +1.388239E-04 +tally 3: +1.832152E-03 +6.713564E-07 diff --git a/tests/regression_tests/random_ray_first_collided_rays/test.py b/tests/regression_tests/random_ray_first_collided_rays/test.py new file mode 100644 index 00000000000..9e476d5c3e8 --- /dev/null +++ b/tests/regression_tests/random_ray_first_collided_rays/test.py @@ -0,0 +1,35 @@ +import os + +import numpy as np +import openmc +from openmc.utility_funcs import change_directory +from openmc.examples import random_ray_three_region_cube +import pytest + +from tests.testing_harness import TolerantPyAPITestHarness + + +class MGXSTestHarness(TolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def test_random_ray_first_collided_rays(): + openmc.reset_auto_ids() + model = random_ray_three_region_cube() + model.settings.random_ray['first_collided_source'] = True + model.settings.random_ray['first_collided_rays'] = 1246 + model.settings.random_ray['first_collided_volume_rays'] = 2000 + strengths = [1.0] + midpoints = [100.0] + energy_dist = openmc.stats.Discrete(x=midpoints,p=strengths) + lower_left_src = [0.0, 0.0, 0.0] + upper_right_src = [5.0, 5.0, 5.0] + spatial_distribution = openmc.stats.Box(lower_left_src, upper_right_src, only_fissionable=False) + source = openmc.IndependentSource(space=spatial_distribution, energy=energy_dist, strength = 3.14) + model.settings.source = [source] + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() \ No newline at end of file From d88b9656e09f034e9a1c3bb667c8d0426361c27b Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 8 Aug 2024 15:56:59 -0500 Subject: [PATCH 22/27] fix naming to fist_collision_ and some documentation --- docs/source/methods/random_ray.rst | 104 ++++++++++++++++++ docs/source/usersguide/random_ray.rst | 27 +++++ include/openmc/random_ray/random_ray.h | 6 +- .../openmc/random_ray/random_ray_simulation.h | 4 +- include/openmc/settings.h | 6 - openmc/settings.py | 28 ++--- src/output.cpp | 2 +- src/random_ray/flat_source_domain.cpp | 4 +- src/random_ray/linear_source_domain.cpp | 2 +- src/random_ray/random_ray.cpp | 6 +- src/random_ray/random_ray_simulation.cpp | 34 +++--- src/settings.cpp | 24 ++-- .../__init__.py | 0 .../flat/inputs_true.dat | 2 +- .../flat/results_true.dat | 2 +- .../linear/inputs_true.dat | 2 +- .../linear/results_true.dat | 2 +- .../test.py | 4 +- .../__init__.py | 0 .../inputs_true.dat | 6 +- .../results_true.dat | 2 +- .../test.py | 8 +- 22 files changed, 200 insertions(+), 75 deletions(-) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/__init__.py (100%) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/flat/inputs_true.dat (99%) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/flat/results_true.dat (87%) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/linear/inputs_true.dat (99%) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/linear/results_true.dat (87%) rename tests/regression_tests/{random_ray_first_collided => random_ray_first_collision}/test.py (91%) rename tests/regression_tests/{random_ray_first_collided_rays => random_ray_first_collision_rays}/__init__.py (100%) rename tests/regression_tests/{random_ray_first_collided_rays => random_ray_first_collision_rays}/inputs_true.dat (97%) rename tests/regression_tests/{random_ray_first_collided_rays => random_ray_first_collision_rays}/results_true.dat (87%) rename tests/regression_tests/{random_ray_first_collided_rays => random_ray_first_collision_rays}/test.py (80%) diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst index 9f8eb84d80e..347f603eb19 100644 --- a/docs/source/methods/random_ray.rst +++ b/docs/source/methods/random_ray.rst @@ -994,6 +994,107 @@ random ray and Monte Carlo, however. develop the scattering source by way of inactive batches before beginning active batches. + +.. _usersguide_fixed_source_first_collision_source_methods: + +---------------------------------- +First Collision Source Method +---------------------------------- + +In cases that the fixed source is not a well defined volumetric source (e.g. point source), +there is the need to preprocess the source into volumetric sources in order to be computed by the +random ray solver. One possible way is through the First Collision Source Method (FCS), which works as a +preconditioner of the source, distributing the source contribution throghout the domain. This is +not a new method `Alcouffe `_, and has been recently implemented in other +neutron transport codes (`Ragusa `_, `Falabino `_). + +The FCS works generating uncollided neutron angular fluxes :math:`\psi^{\text{un}}_{g}` at the source that travel through +the domain interacting with the media, being naturally attenuated in the process. Neutrons that experience +any collision are treated as first collided neutrons and will be used to estimate the volumetric neutron +fixed source at that cell. Once the FCS preprocess stage is complete, the fixed volumetric source will be +added to each iteration of the random ray solver. The remaining uncollided flux that have not interacted +at any point of the preprocessing stage is added to the final solution at the end of the neutron transport code. + +The FCS has a very similar mathematical formulation to the regular Random Ray method. The formulation for +the method with flat source will be provided. The neutron transport equation for the uncollided rays can be +described as in Equation :eq:`moc_final`, however without any pre-existing source terms: + +.. math:: + :label: fcs_moc_final + + \psi_g^{\text{un}}(s, \mathbf{\Omega}) = \psi_g^{\text{un}}(\mathbf{r_0}, \mathbf{\Omega}) e^{-\int_0^s ds^\prime \Sigma_{t_g}(s^\prime)}. + +The analytical solution for this ODE is a simple attenuation problem: + +.. math:: + :label: fcs_moc_sol + + \psi_g^{\text{un}}(s) = \psi_g(0) e^{-\Sigma_{t,i,g} s} . + +For convenience, we can also write this equation in terms of the incoming and +outgoing angular flux (:math:`\psi_g^{in}` and :math:`\psi_g^{out}`) + +.. math:: + :label: fcs_fsr_attenuation_in_out + + \psi_g^{out} = \psi_g^{in} e^{-\Sigma_{t,i,g} \ell_r}. + + +Equation :eq:`fcs_fsr_attenuation_in_out` can be rearranged in terms of :math:`\Delta \psi_{r,g}`: + +.. math:: + :label: fcs_difference + + \Delta\psi_{r,g}^{\text{un}} =\psi_{r,g}^{in} - \psi_{r,g}^{out} = \psi_{r,g}^{in}\big(1-e^{-\Sigma_{t,i,g}l_r}\big) . + +The average angular flux can be computed substitute :eq:`average` into :eq:`fcs_moc_final` +and obtain: + +.. math:: + :label: fcs_average_solved + + \overline{\psi}_{r,i,g}^{\text{un}} = - \frac{\psi_{r,g}^{out} - \psi_{r,g}^{in}}{\ell_r \Sigma_{t,i,g}}. + +Which can also be described in terms of :math:`\Delta \psi_{r,g}`: + +.. math:: + :label: fcs_average_solved_difference + + \overline{\psi}_{r,i,g}^{\text{un}} = \frac{\Delta \psi_{r,g}^{\text{un}}}{\ell_r \Sigma_{t,i,g}}. + +Similarly to Equation :eq:`discretized`, the scalar flux in cell :math:`i` can be defined as the summation +of the contributions of the angular fluxes traveling through it. However, in this method, there is the need +to differentiate how the volume is estimated. In the Random Ray method, the rays are being generated uniforminly +across the domain and the volume estimation is unbiased. Nonetheless, angular fluxes have a specific and non well-distributed +birth location. + +.. math:: + :label: fcs_discretized + + \phi^{\text{un}}(i,g) = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}^{un}}{V_i} . + +To avoid bias in the volume estimation, it is added an initial volume estimation stage +to compute the volume of each cell prior running FCS, using the same method presented in +the Random Ray method. This volume estimation can be improvde with the random ray solver, +requiring a fast and rough initial estimate. Substituting Equation :eq:`fcs_average_solved_difference` +into Equation :eq:`fcs_discretized`, we obtain the equation for the uncollided angular flux: + +.. math:: + :label: fcs_uncollided_flux + + \phi^{\text{un}}(i,g) = \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,i,g}^{\text{un}}}{\Sigma_{t,i,g} V_i} . + +The fixed-source term can be calculated as the first collided flux that undergo scattering events: + +.. math:: + :label: fcs_first_collided_flux + + Q_\text{fixed}(i,g) = \phi^{\text{FCS}}(i,g) = \sum_{g'}^{G}\Sigma_s(i,g,g') \phi^{\text{un}} (i,g') . + +The fixed-source :math:`Q_\text{fixed}` will be treated as a fixed volumetric source for all remaining Random Ray +iterations, as presented in Eq :eq:`fixed_source_update`. + + --------------------------- Fundamental Sources of Bias --------------------------- @@ -1048,6 +1149,9 @@ in random ray particle transport are: .. _Cosgrove-2023: https://doi.org/10.1080/00295639.2023.2270618 .. _Ferrer-2016: https://doi.org/10.13182/NSE15-6 .. _Gunow-2018: https://dspace.mit.edu/handle/1721.1/119030 +.. _Alcouffe-1989: https://doi.org/10.13182/NSE90-A23749 +.. _Ragusa-2016: https://www.osti.gov/biblio/1364492 +.. _Falabino-2022: https://doi.org/10.1016/j.jcp.2022.111156 .. only:: html diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 117d5e23fb5..bda5d8ca6f1 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -475,6 +475,33 @@ as:: which will greatly improve the quality of the linear source term in 2D simulations. +----------------------------- +First Collision Source Method +----------------------------- + +First Collision Source method (FCS) is supported within the fixed source random ray +solver. The preprocessing stage can be toggle by setting the ``first_collision_source`` +field in the :attr:`openmc.Settings.random_ray` dictionary to ``True`` as:: + + settings.random_ray['first_collision_source'] = True + +The method has two input variables: number of rays for initial volume estimation +and number of uncollided rays used in FCS. + +The user can define the amount of uncollided rays used in the FCS mode by setting the +``first_collision_rays`` field in the :attr:`openmc.Settings.random_ray` dictionary +to ``value`` as:: + + settings.random_ray['first_collision_rays'] = 1000 + +If not provided, the solver will run the default procedure to iteratively generate more +rays until: + +- **(1)** All cells are hit. +- **(1)** No extra cells were hit with extra rays. +- **(1)** Maximum value reached (default :math:`= 1e7` rays). + + --------------------------------- Fixed Source and Eigenvalue Modes --------------------------------- diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index 383eb803605..1ee42089201 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -41,9 +41,9 @@ class RandomRay : public Particle { static unique_ptr ray_source_; // Starting source for ray sampling static RandomRaySourceShape source_shape_; // Flag for linear source - static bool first_collided_source_; - static int first_collided_rays_; - static int first_collided_volume_rays_; + static bool first_collision_source_; + static int first_collision_rays_; + static int first_collision_volume_rays_; static bool no_volume_calc; // Flag for FCS flux calculation diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index 21b87300b3b..3d1922f8a58 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -27,11 +27,11 @@ class RandomRaySimulation { void print_results_random_ray(uint64_t total_geometric_intersections, double avg_miss_rate, int negroups, int64_t n_source_regions, int64_t n_external_source_regions) const; - void first_collided_source_simulation(); + void first_collision_source_simulation(); //---------------------------------------------------------------------------- // Data members - // First collided method variables for automatic first_collided_rays_ + // First collided method variables for automatic first_collision_rays_ int64_t n_hits_new {0}; int64_t n_hits_old {0}; int new_n_rays {1000}; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 2f9fb399162..a95f1ced9f1 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -154,12 +154,6 @@ extern "C" int verbosity; //!< How verbose to make output extern double weight_cutoff; //!< Weight cutoff for Russian roulette extern double weight_survive; //!< Survival weight after Russian roulette -// HARDCODED INPUTS - First Collided Flux -extern bool FIRST_COLLIDED_FLUX; //!< First Collided Mode loop -extern int n_uncollided_rays; //!< Number of uncollided rays used -extern int n_volume_estimator_rays; //!< Number of rays to estimate volume -//extern int volume_online_option;//! Volume online calculation for FC source - } // namespace settings //============================================================================== diff --git a/openmc/settings.py b/openmc/settings.py index 5862d1ae135..1343ba4036c 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -164,16 +164,16 @@ class Settings: cm/cm^3. When disabled, flux tallies will be reported in units of cm (i.e., total distance traveled by neutrons in the spatial tally region). - :first_collided_source: + :first_collision_source: Boolean that indicates if first collided source method (FSC) is used to initialize the external source input. Default is 'False'. - :first_collided_rays: + :first_collision_rays: Number of rays (int) used to generate the first collided source. If not provided, the method will automatically run enough rays to adequately converge the first collided source, via an iterative doubling process. If provided, the method will run the exact prescribed amount. - :first_collided_volume_rays: + :first_collision_volume_rays: Number of rays (int) used to estimate the initial volume for the first collied source calculation. If not provided, it will use the same number of rays as the main random ray solver stage. @@ -1109,14 +1109,14 @@ def random_ray(self, random_ray: dict): ('flat', 'linear', 'linear_xy')) elif key == 'volume_normalized_flux_tallies': cv.check_type('volume normalized flux tallies', random_ray[key], bool) - elif key == 'first_collided_source': - cv.check_type('first_collided_source', random_ray[key], bool) - elif key == 'first_collided_rays': - cv.check_type('first_collided_rays', random_ray[key], int) - cv.check_greater_than('first_collided_rays',random_ray[key], 0) - elif key == 'first_collided_volume_rays': - cv.check_type('first_collided_volume_rays', random_ray[key], int) - cv.check_greater_than('first_collided_volume_rays',random_ray[key], 0) + elif key == 'first_collision_source': + cv.check_type('first_collision_source', random_ray[key], bool) + elif key == 'first_collision_rays': + cv.check_type('first_collision_rays', random_ray[key], int) + cv.check_greater_than('first_collision_rays',random_ray[key], 0) + elif key == 'first_collision_volume_rays': + cv.check_type('first_collision_volume_rays', random_ray[key], int) + cv.check_greater_than('first_collision_volume_rays',random_ray[key], 0) else: raise ValueError(f'Unable to set random ray to "{key}" which is ' 'unsupported by OpenMC') @@ -1916,11 +1916,11 @@ def _random_ray_from_xml_element(self, root): self.random_ray['volume_normalized_flux_tallies'] = ( child.text in ('true', '1') ) - elif child.tag == 'first_collided_source': - self.random_ray['first_collided_source'] = ( + elif child.tag == 'first_collision_source': + self.random_ray['first_collision_source'] = ( child.text in ('true', '1') ) - elif child.tag in ('first_collided_rays', 'first_collided_volume_rays'): + elif child.tag in ('first_collision_rays', 'first_collision_volume_rays'): self.random_ray[child.tag] = int(child.text) def to_xml_element(self, mesh_memo=None): diff --git a/src/output.cpp b/src/output.cpp index b207fe6724a..2b1104aa929 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -377,7 +377,7 @@ void print_build_info() void print_columns() { - if (RandomRay::first_collided_source_){ + if (RandomRay::first_collision_source_){ fmt::print(" Batch Rays Total Source Regions Discovered\n" " ====== ======= =================================\n"); } else if (settings::entropy_on) { diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 8bceb7b6aa2..932d1692902 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -709,7 +709,7 @@ void FlatSourceDomain::random_ray_tally() for (int g = 0; g < negroups_; g++) { int idx = sr * negroups_ + g; - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { flux = (scalar_flux_new_[idx] + (scalar_uncollided_flux_[idx] / volume)); } else { @@ -898,7 +898,7 @@ void FlatSourceDomain::all_reduce_replicated_source_regions() double FlatSourceDomain::evaluate_flux_at_point( Position r, int64_t sr, int g) const { - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { return (scalar_flux_final_[sr * negroups_ + g] / (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index 1b4fe4e7840..c46346ea010 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -398,7 +398,7 @@ double LinearSourceDomain::evaluate_flux_at_point( MomentMatrix invM = mom_matrix_[sr].inverse(); MomentArray phi_solved = invM * phi_linear; - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { phi_solved += flux_moments_uncollided_[sr * negroups_ + g]; } diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index a8b52834bc2..8ad6719fc68 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -184,9 +184,9 @@ double RandomRay::distance_active_; unique_ptr RandomRay::ray_source_; RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; bool RandomRay::no_volume_calc = {false}; -bool RandomRay::first_collided_source_ {false}; -int RandomRay::first_collided_rays_ {-1}; -int RandomRay::first_collided_volume_rays_ {-1}; +bool RandomRay::first_collision_source_ {false}; +int RandomRay::first_collision_rays_ {-1}; +int RandomRay::first_collision_volume_rays_ {-1}; RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index d3a59942a02..70512052a9f 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -166,7 +166,7 @@ void validate_random_ray_inputs() "random ray mode"); } - if (!RandomRay::first_collided_source_) { + if (!RandomRay::first_collision_source_) { // Check for isotropic source UnitSphereDistribution* angle_dist = is->angle(); Isotropic* id = dynamic_cast(angle_dist); @@ -262,12 +262,12 @@ RandomRaySimulation::RandomRaySimulation() void RandomRaySimulation::simulate() { if (settings::run_mode == RunMode::FIXED_SOURCE) { - if (!RandomRay::first_collided_source_) { + if (!RandomRay::first_collision_source_) { // Transfer external source user inputs onto random ray source regions domain_->convert_external_sources(); domain_->count_external_source_regions(); } else { - first_collided_source_simulation(); + first_collision_source_simulation(); } } // Random ray power iteration loop @@ -281,7 +281,7 @@ void RandomRaySimulation::simulate() simulation::total_weight = 1.0; // Update external source if FIRST_COLLIDED_METHOD is used - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { domain_->compute_first_collided_external_source(); } @@ -350,7 +350,7 @@ void RandomRaySimulation::simulate() finalize_batch(); } // End random ray power iteration loop - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { domain_->update_volume_uncollided_flux(); } } @@ -431,7 +431,7 @@ void RandomRaySimulation::print_results_random_ray( fmt::print( " Total Iterations = {}\n", settings::n_batches); fmt::print(" Flat Source Regions (FSRs) = {}\n", n_source_regions); - if (!RandomRay::first_collided_source_) { + if (!RandomRay::first_collision_source_) { fmt::print( " FSRs Containing External Sources = {}\n", n_external_source_regions); } @@ -452,7 +452,7 @@ void RandomRaySimulation::print_results_random_ray( header("Timing Statistics", 4); show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); - if (RandomRay::first_collided_source_) { + if (RandomRay::first_collision_source_) { show_time("Volume estimation time", RandomRaySimulation::time_volume_fc); show_time("First Collided Source time", time_first_collided.elapsed()); } @@ -478,12 +478,12 @@ void RandomRaySimulation::print_results_random_ray( } } -void RandomRaySimulation::first_collided_source_simulation() +void RandomRaySimulation::first_collision_source_simulation() { if (RandomRay::source_shape_ == RandomRaySourceShape::FLAT) { - header("FIRST COLLIDED SOURCE METHOD - Flat source", 3); + header("FIRST COLLISION SOURCE METHOD - Flat source", 3); } else { - header("FIRST COLLIDED SOURCE METHOD - Linear source", 3); + header("FIRST COLLISION SOURCE METHOD - Linear source", 3); } simulation::time_first_collided.start(); simulation::current_batch = 1; @@ -491,20 +491,20 @@ void RandomRaySimulation::first_collided_source_simulation() // Volume estimation is necessary to scale the first collided source // accordingly. Estimation of linear moments in linear source has direct // impact into final solution accuracy. - if (RandomRay::first_collided_volume_rays_ == -1) { - RandomRay::first_collided_volume_rays_ = settings::n_particles; + if (RandomRay::first_collision_volume_rays_ == -1) { + RandomRay::first_collision_volume_rays_ = settings::n_particles; } // Ray tracing - volume calculation #pragma omp parallel for - for (int i = 0; i < RandomRay::first_collided_volume_rays_; i++) { + for (int i = 0; i < RandomRay::first_collision_volume_rays_; i++) { RandomRay ray(i, domain_.get(), false); ray.transport_history_based_single_ray(); } // Normalizing volumes domain_->normalize_scalar_flux_and_volumes( - RandomRay::first_collided_volume_rays_ * RandomRay::distance_active_); + RandomRay::first_collision_volume_rays_ * RandomRay::distance_active_); // Reset parameters for First Collided Source Method domain_->batch_reset_fc(); @@ -520,9 +520,9 @@ void RandomRaySimulation::first_collided_source_simulation() // (1) There isn't new FSR hits from batch_first_collided (n-1) to the next // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs print_columns(); - if (RandomRay::first_collided_rays_ != -1) { - new_n_rays = RandomRay::first_collided_rays_; - n_rays_max = RandomRay::first_collided_rays_; + if (RandomRay::first_collision_rays_ != -1) { + new_n_rays = RandomRay::first_collision_rays_; + n_rays_max = RandomRay::first_collision_rays_; } while (old_n_rays < n_rays_max) { // Condition (2) diff --git a/src/settings.cpp b/src/settings.cpp index 30710066dca..06a31cb6b6b 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -287,21 +287,21 @@ void get_run_parameters(pugi::xml_node node_base) FlatSourceDomain::volume_normalized_flux_tallies_ = get_node_value_bool(random_ray_node, "volume_normalized_flux_tallies"); } - if (check_for_node(random_ray_node, "first_collided_source")) { - RandomRay::first_collided_source_ = - get_node_value_bool(random_ray_node, "first_collided_source"); - - if (check_for_node(random_ray_node, "first_collided_rays")) { - RandomRay::first_collided_rays_ = - std::stoi(get_node_value(random_ray_node, "first_collided_rays")); - if (RandomRay::first_collided_rays_ <= 0) { + if (check_for_node(random_ray_node, "first_collision_source")) { + RandomRay::first_collision_source_ = + get_node_value_bool(random_ray_node, "first_collision_source"); + + if (check_for_node(random_ray_node, "first_collision_rays")) { + RandomRay::first_collision_rays_ = + std::stoi(get_node_value(random_ray_node, "first_collision_rays")); + if (RandomRay::first_collision_rays_ <= 0) { fatal_error("Number of first collided rays must be greater than 0"); } } - if (check_for_node(random_ray_node, "first_collided_volume_rays")) { - RandomRay::first_collided_volume_rays_ = std::stoi( - get_node_value(random_ray_node, "first_collided_volume_rays")); - if (RandomRay::first_collided_volume_rays_ <= 0) { + if (check_for_node(random_ray_node, "first_collision_volume_rays")) { + RandomRay::first_collision_volume_rays_ = std::stoi( + get_node_value(random_ray_node, "first_collision_volume_rays")); + if (RandomRay::first_collision_volume_rays_ <= 0) { fatal_error("Number of rays for first collided initial volume " "estimation must be greater than 0"); } diff --git a/tests/regression_tests/random_ray_first_collided/__init__.py b/tests/regression_tests/random_ray_first_collision/__init__.py similarity index 100% rename from tests/regression_tests/random_ray_first_collided/__init__.py rename to tests/regression_tests/random_ray_first_collision/__init__.py diff --git a/tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat b/tests/regression_tests/random_ray_first_collision/flat/inputs_true.dat similarity index 99% rename from tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat rename to tests/regression_tests/random_ray_first_collision/flat/inputs_true.dat index ab1616862f8..0ab42bac23c 100644 --- a/tests/regression_tests/random_ray_first_collided/flat/inputs_true.dat +++ b/tests/regression_tests/random_ray_first_collision/flat/inputs_true.dat @@ -213,7 +213,7 @@ True flat - True + True diff --git a/tests/regression_tests/random_ray_first_collided/flat/results_true.dat b/tests/regression_tests/random_ray_first_collision/flat/results_true.dat similarity index 87% rename from tests/regression_tests/random_ray_first_collided/flat/results_true.dat rename to tests/regression_tests/random_ray_first_collision/flat/results_true.dat index da1c06f01bf..4a51b64a825 100644 --- a/tests/regression_tests/random_ray_first_collided/flat/results_true.dat +++ b/tests/regression_tests/random_ray_first_collision/flat/results_true.dat @@ -1,5 +1,5 @@ tally 1: -5.237694E-01 +5.237693E-01 5.603795E-02 tally 2: 2.626249E-02 diff --git a/tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat b/tests/regression_tests/random_ray_first_collision/linear/inputs_true.dat similarity index 99% rename from tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat rename to tests/regression_tests/random_ray_first_collision/linear/inputs_true.dat index f097feaa487..b3dff653b3e 100644 --- a/tests/regression_tests/random_ray_first_collided/linear/inputs_true.dat +++ b/tests/regression_tests/random_ray_first_collision/linear/inputs_true.dat @@ -213,7 +213,7 @@ True linear - True + True diff --git a/tests/regression_tests/random_ray_first_collided/linear/results_true.dat b/tests/regression_tests/random_ray_first_collision/linear/results_true.dat similarity index 87% rename from tests/regression_tests/random_ray_first_collided/linear/results_true.dat rename to tests/regression_tests/random_ray_first_collision/linear/results_true.dat index 0aa82ed27aa..58587cf74fe 100644 --- a/tests/regression_tests/random_ray_first_collided/linear/results_true.dat +++ b/tests/regression_tests/random_ray_first_collision/linear/results_true.dat @@ -1,5 +1,5 @@ tally 1: -1.684540E-01 +1.684539E-01 9.991864E-01 tally 2: -3.623011E-02 diff --git a/tests/regression_tests/random_ray_first_collided/test.py b/tests/regression_tests/random_ray_first_collision/test.py similarity index 91% rename from tests/regression_tests/random_ray_first_collided/test.py rename to tests/regression_tests/random_ray_first_collision/test.py index d2ba7a2cb49..9481e83048c 100644 --- a/tests/regression_tests/random_ray_first_collided/test.py +++ b/tests/regression_tests/random_ray_first_collision/test.py @@ -18,12 +18,12 @@ def _cleanup(self): @pytest.mark.parametrize("shape", ["flat", "linear"]) -def test_random_ray_first_collided(shape): +def test_random_ray_first_collision(shape): with change_directory(shape): openmc.reset_auto_ids() model = random_ray_three_region_cube() model.settings.random_ray['source_shape'] = shape - model.settings.random_ray['first_collided_source'] = True + model.settings.random_ray['first_collision_source'] = True strengths = [1.0] # Good - fast group appears largest (besides most thermal) midpoints = [100.0] energy_dist = openmc.stats.Discrete(x=midpoints,p=strengths) diff --git a/tests/regression_tests/random_ray_first_collided_rays/__init__.py b/tests/regression_tests/random_ray_first_collision_rays/__init__.py similarity index 100% rename from tests/regression_tests/random_ray_first_collided_rays/__init__.py rename to tests/regression_tests/random_ray_first_collision_rays/__init__.py diff --git a/tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat b/tests/regression_tests/random_ray_first_collision_rays/inputs_true.dat similarity index 97% rename from tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat rename to tests/regression_tests/random_ray_first_collision_rays/inputs_true.dat index ec56c9e93b8..53d98f04f22 100644 --- a/tests/regression_tests/random_ray_first_collided_rays/inputs_true.dat +++ b/tests/regression_tests/random_ray_first_collision_rays/inputs_true.dat @@ -212,9 +212,9 @@ True - True - 1246 - 2000 + True + 1246 + 2000 diff --git a/tests/regression_tests/random_ray_first_collided_rays/results_true.dat b/tests/regression_tests/random_ray_first_collision_rays/results_true.dat similarity index 87% rename from tests/regression_tests/random_ray_first_collided_rays/results_true.dat rename to tests/regression_tests/random_ray_first_collision_rays/results_true.dat index aa2fc17f380..481d3fa224d 100644 --- a/tests/regression_tests/random_ray_first_collided_rays/results_true.dat +++ b/tests/regression_tests/random_ray_first_collision_rays/results_true.dat @@ -1,6 +1,6 @@ tally 1: 5.179652E-01 -5.485090E-02 +5.485091E-02 tally 2: 2.634285E-02 1.388239E-04 diff --git a/tests/regression_tests/random_ray_first_collided_rays/test.py b/tests/regression_tests/random_ray_first_collision_rays/test.py similarity index 80% rename from tests/regression_tests/random_ray_first_collided_rays/test.py rename to tests/regression_tests/random_ray_first_collision_rays/test.py index 9e476d5c3e8..6bdfdaf5e61 100644 --- a/tests/regression_tests/random_ray_first_collided_rays/test.py +++ b/tests/regression_tests/random_ray_first_collision_rays/test.py @@ -17,12 +17,12 @@ def _cleanup(self): os.remove(f) -def test_random_ray_first_collided_rays(): +def test_random_ray_first_collision_rays(): openmc.reset_auto_ids() model = random_ray_three_region_cube() - model.settings.random_ray['first_collided_source'] = True - model.settings.random_ray['first_collided_rays'] = 1246 - model.settings.random_ray['first_collided_volume_rays'] = 2000 + model.settings.random_ray['first_collision_source'] = True + model.settings.random_ray['first_collision_rays'] = 1246 + model.settings.random_ray['first_collision_volume_rays'] = 2000 strengths = [1.0] midpoints = [100.0] energy_dist = openmc.stats.Discrete(x=midpoints,p=strengths) From 07a97a26f21782a1743d39116a72bb47b55db772 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 8 Aug 2024 16:34:51 -0500 Subject: [PATCH 23/27] completed documentation --- docs/source/methods/random_ray.rst | 13 ++++++++++--- docs/source/usersguide/random_ray.rst | 14 +++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst index 347f603eb19..6ecb1fbaffc 100644 --- a/docs/source/methods/random_ray.rst +++ b/docs/source/methods/random_ray.rst @@ -1005,7 +1005,7 @@ In cases that the fixed source is not a well defined volumetric source (e.g. poi there is the need to preprocess the source into volumetric sources in order to be computed by the random ray solver. One possible way is through the First Collision Source Method (FCS), which works as a preconditioner of the source, distributing the source contribution throghout the domain. This is -not a new method `Alcouffe `_, and has been recently implemented in other +not a new method (`Alcouffe `_), and has been recently implemented in other neutron transport codes (`Ragusa `_, `Falabino `_). The FCS works generating uncollided neutron angular fluxes :math:`\psi^{\text{un}}_{g}` at the source that travel through @@ -1075,8 +1075,15 @@ birth location. To avoid bias in the volume estimation, it is added an initial volume estimation stage to compute the volume of each cell prior running FCS, using the same method presented in -the Random Ray method. This volume estimation can be improvde with the random ray solver, -requiring a fast and rough initial estimate. Substituting Equation :eq:`fcs_average_solved_difference` +the Random Ray method. + +In the case o flat source, the volume estimation can be improvde with the random ray solver, +allowing a fast and rough initial estimate. However, linear source requires a more carefull procedure. +Linear source requires calculating angular flux moments, that depend on the estimated +cell's spatial moments and centroids. If a poor estimation is made, innaccurate gradients will be +carried throughout the calculation and impact the accuracy of the method. + +Substituting Equation :eq:`fcs_average_solved_difference` into Equation :eq:`fcs_discretized`, we obtain the equation for the uncollided angular flux: .. math:: diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index bda5d8ca6f1..438312be0dc 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -497,10 +497,18 @@ to ``value`` as:: If not provided, the solver will run the default procedure to iteratively generate more rays until: -- **(1)** All cells are hit. -- **(1)** No extra cells were hit with extra rays. -- **(1)** Maximum value reached (default :math:`= 1e7` rays). +* All cells are hit. +* No extra cells were hit with additional rays. +* Maximum value reached (default :math:`= 1e7` rays). +The user can also define the amount of rays for initial volume estimation by setting the +``first_collision_volume_rays`` field in the :attr:`openmc.Settings.random_ray` dictionary +to ``value`` as:: + + settings.random_ray['first_collision_volume_rays'] = 2000 + +If not provided, the solver will use the same amount of rays used for a regular batch in +the random ray solver (:attr:`settings::n_particles`). --------------------------------- Fixed Source and Eigenvalue Modes From a79c4ec08e78f76dde736de3b7fc9a7226f7a75f Mon Sep 17 00:00:00 2001 From: Tomas P Date: Thu, 8 Aug 2024 17:06:49 -0500 Subject: [PATCH 24/27] added linear plotting component to external_source_ and scalar_uncollided_flux --- .../openmc/random_ray/flat_source_domain.h | 10 ++++-- .../openmc/random_ray/linear_source_domain.h | 5 ++- src/random_ray/flat_source_domain.cpp | 36 +++++++++++++++---- src/random_ray/linear_source_domain.cpp | 24 +++++++++++++ 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 020a8337ae2..5376393dd51 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -112,16 +112,19 @@ class FlatSourceDomain { virtual void flux_swap(); virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const; double compute_fixed_source_normalization_factor() const; - virtual void compute_first_collided_flux(); virtual void normalize_uncollided_scalar_flux(double number_of_particles); virtual void update_volume_uncollided_flux(); virtual void compute_first_collided_external_source(); - virtual void compute_uncollided_scalar_flux(); + virtual void compute_uncollided_scalar_flux(); int64_t check_fsr_hits(); virtual void uncollided_moments(); virtual void batch_reset_fc(); + virtual double evaluate_uncollided_flux_at_point( + Position r, int64_t sr, int g) const; + virtual double evaluate_external_source_at_point( + Position r, int64_t sr, int g) const; //---------------------------------------------------------------------------- // Static Data members @@ -137,7 +140,8 @@ class FlatSourceDomain { // non-zero external source terms bool new_fsr_fc {true}; // Criteria to First Collided Loop // Check if new cell was hit - bool negative_flux_check {false}; // Variable to print warning of negative fluxes + bool negative_flux_check { + false}; // Variable to print warning of negative fluxes // 1D array representing source region starting offset for each OpenMC Cell // in model::cells diff --git a/include/openmc/random_ray/linear_source_domain.h b/include/openmc/random_ray/linear_source_domain.h index d6c73767511..eb18ca30a4e 100644 --- a/include/openmc/random_ray/linear_source_domain.h +++ b/include/openmc/random_ray/linear_source_domain.h @@ -48,6 +48,10 @@ class LinearSourceDomain : public FlatSourceDomain { void update_volume_uncollided_flux() override; void uncollided_moments() override; void batch_reset_fc() override; + double evaluate_uncollided_flux_at_point( + Position r, int64_t sr, int g) const override; + double evaluate_external_source_at_point( + Position r, int64_t sr, int g) const override; //---------------------------------------------------------------------------- // Public Data members @@ -61,7 +65,6 @@ class LinearSourceDomain : public FlatSourceDomain { vector flux_moments_first_collided_; vector external_source_gradients_; - vector centroid_; vector centroid_iteration_; vector centroid_t_; diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index 932d1692902..ead3d338bd5 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -122,7 +122,7 @@ void FlatSourceDomain::batch_reset_fc() { parallel_fill(scalar_flux_new_, 0.0f); parallel_fill(was_hit_, 0); - if(RandomRay::no_volume_calc){ + if (RandomRay::no_volume_calc) { parallel_fill(volume_t_, 0.0); } } @@ -325,12 +325,12 @@ void FlatSourceDomain::uncollided_moments() } // Normalize First Collided Flux by volume and assign as fixed source -//compute_first_collided_external_source +// compute_first_collided_external_source void FlatSourceDomain::compute_first_collided_external_source() { #pragma omp parallel for for (int sr = 0; sr < n_source_regions_; sr++) { - //check here + // check here double volume = simulation_volume_ * volume_[sr]; if (volume > 0.0) { @@ -900,12 +900,32 @@ double FlatSourceDomain::evaluate_flux_at_point( { if (RandomRay::first_collision_source_) { return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive) + + (settings::n_batches - settings::n_inactive) + scalar_uncollided_flux_[sr * negroups_ + g]); } else { // add uncollided flux if First Collided method is used return (scalar_flux_final_[sr * negroups_ + g] / - (settings::n_batches - settings::n_inactive)); + (settings::n_batches - settings::n_inactive)); + } +} + +double FlatSourceDomain::evaluate_uncollided_flux_at_point( + Position r, int64_t sr, int g) const +{ + if (RandomRay::first_collision_source_) { + return scalar_uncollided_flux_[sr * negroups_ + g]; + } else { + return 0; + } +} + +double FlatSourceDomain::evaluate_external_source_at_point( + Position r, int64_t sr, int g) const +{ + if (RandomRay::first_collision_source_) { + return external_source_[sr * negroups_ + g]; + } else { + return 0; } } @@ -1066,7 +1086,8 @@ void FlatSourceDomain::output_to_vtk() const int mat = material_[fsr]; float sigma_t = data::mg.macro_xs_[mat].get_xs( MgxsType::TOTAL, g, nullptr, nullptr, nullptr, 0, 0); - float f_source = external_source_[fsr * negroups_ + g]; + float f_source = + evaluate_external_source_at_point(voxel_positions[i], fsr, g); f_source *= sigma_t; f_source = convert_to_big_endian(f_source); std::fwrite(&f_source, sizeof(float), 1, plot); @@ -1080,7 +1101,8 @@ void FlatSourceDomain::output_to_vtk() const for (int i = 0; i < Nx * Ny * Nz; i++) { int64_t fsr = voxel_indices[i]; int64_t source_element = fsr * negroups_ + g; - float uncollided_flux = scalar_uncollided_flux_[source_element]; + float uncollided_flux = + evaluate_uncollided_flux_at_point(voxel_positions[i], fsr, g); uncollided_flux = convert_to_big_endian(uncollided_flux); std::fwrite(&uncollided_flux, sizeof(float), 1, plot); } diff --git a/src/random_ray/linear_source_domain.cpp b/src/random_ray/linear_source_domain.cpp index c46346ea010..62539e2b908 100644 --- a/src/random_ray/linear_source_domain.cpp +++ b/src/random_ray/linear_source_domain.cpp @@ -405,6 +405,30 @@ double LinearSourceDomain::evaluate_flux_at_point( return phi_flat + phi_solved.dot(local_r); } +double LinearSourceDomain::evaluate_uncollided_flux_at_point( + Position r, int64_t sr, int g) const +{ + // Uncollided flux + float phi_flat = FlatSourceDomain::evaluate_uncollided_flux_at_point(r, sr, g); + + Position local_r = r - centroid_[sr]; + MomentArray phi_linear = flux_moments_uncollided_[sr * negroups_ + g]; + + return phi_flat + phi_linear.dot(local_r); +} + +double LinearSourceDomain::evaluate_external_source_at_point( + Position r, int64_t sr, int g) const +{ + // External source + float phi_flat = FlatSourceDomain::evaluate_external_source_at_point(r, sr, g); + + Position local_r = r - centroid_[sr]; + MomentArray phi_linear = external_source_gradients_[sr * negroups_ + g]; + + return phi_flat + phi_linear.dot(local_r); +} + void LinearSourceDomain::update_volume_uncollided_flux() { #pragma omp parallel for From 3d47f1b60db989990a0d871248e7dea8fbbd5447 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Fri, 9 Aug 2024 11:43:18 -0500 Subject: [PATCH 25/27] allocating correctly some function variables --- .../openmc/random_ray/flat_source_domain.h | 4 ---- include/openmc/random_ray/random_ray.h | 4 ---- .../openmc/random_ray/random_ray_simulation.h | 11 +--------- src/random_ray/flat_source_domain.cpp | 4 +--- src/random_ray/moment_matrix.cpp | 2 +- src/random_ray/random_ray.cpp | 9 ++++++-- src/random_ray/random_ray_simulation.cpp | 21 +++++++++++++++++-- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 5376393dd51..3819810e7dd 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -138,10 +138,6 @@ class FlatSourceDomain { int64_t n_source_regions_ {0}; // Total number of source regions in the model int64_t n_external_source_regions_ {0}; // Total number of source regions with // non-zero external source terms - bool new_fsr_fc {true}; // Criteria to First Collided Loop - // Check if new cell was hit - bool negative_flux_check { - false}; // Variable to print warning of negative fluxes // 1D array representing source region starting offset for each OpenMC Cell // in model::cells diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index 1ee42089201..c8a8f27b2fa 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -29,8 +29,6 @@ class RandomRay : public Particle { void attenuate_flux_flat_source(double distance, bool is_active); void attenuate_flux_linear_source(double distance, bool is_active); void event_advance_ray_first_collided(); - - void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain,bool uncollided_ray); uint64_t transport_history_based_single_ray(); @@ -59,8 +57,6 @@ class RandomRay : public Particle { vector delta_moments_; int negroups_; - float ray_threshold {1e-20f}; - FlatSourceDomain* domain_ {nullptr}; // pointer to domain that has flat source // data needed for ray transport diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index 3d1922f8a58..52db67a3990 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -31,18 +31,9 @@ class RandomRaySimulation { //---------------------------------------------------------------------------- // Data members - // First collided method variables for automatic first_collision_rays_ - int64_t n_hits_new {0}; - int64_t n_hits_old {0}; - int new_n_rays {1000}; - int old_n_rays {0}; - int batch_first_collided {1}; - int n_rays_max {10000000}; - - // Initial volume estimation timer - First Collided Source Method + // Initial volume estimation timer - First Collided Source Method double time_volume_fc; - private: // Contains all flat source region data unique_ptr domain_; diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index ead3d338bd5..57bc9062133 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -320,9 +320,7 @@ void FlatSourceDomain::compute_first_collided_flux() } void FlatSourceDomain::uncollided_moments() -{ - // empty -} +{ } // Normalize First Collided Flux by volume and assign as fixed source // compute_first_collided_external_source diff --git a/src/random_ray/moment_matrix.cpp b/src/random_ray/moment_matrix.cpp index 0324a14943b..547d24b27c3 100644 --- a/src/random_ray/moment_matrix.cpp +++ b/src/random_ray/moment_matrix.cpp @@ -25,7 +25,7 @@ MomentMatrix MomentMatrix::inverse() const // Check if the determinant is zero double det = determinant(); - if (det < std::abs(1.0e-10)) { + if (det < std::abs(1.0e-6)) { // Set the inverse to zero. In effect, this will // result in all the linear terms of the source becoming // zero, leaving just the flat source. diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index 8ad6719fc68..7d4b050695e 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -305,8 +305,13 @@ void RandomRay::event_advance_ray_first_collided() for (int j = 0; j < n_coord(); ++j) { coord(j).r += distance * coord(j).u; } - // bool = true to kill ray - // ray is killed by default unless: + + // Terminate ray threshold + float ray_threshold = 1e-20f; + + // Check if angular flux is not zero or above threshold + // Do not terminate the ray if any of these conditions are met + // terminate otherwise bool angular_flux_below_threshold = true; for (int g = 0; g < negroups_; g++) { if (angular_flux_initial_[g] > 0) { diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index 70512052a9f..009809b434a 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -485,12 +485,15 @@ void RandomRaySimulation::first_collision_source_simulation() } else { header("FIRST COLLISION SOURCE METHOD - Linear source", 3); } + simulation::time_first_collided.start(); simulation::current_batch = 1; fmt::print("Initial volume estimation..."); // Volume estimation is necessary to scale the first collided source // accordingly. Estimation of linear moments in linear source has direct // impact into final solution accuracy. + + // Check if number of volume rays were provided or set default if (RandomRay::first_collision_volume_rays_ == -1) { RandomRay::first_collision_volume_rays_ = settings::n_particles; } @@ -519,7 +522,21 @@ void RandomRaySimulation::first_collision_source_simulation() // It will operate until meet any criteria (1-3): // (1) There isn't new FSR hits from batch_first_collided (n-1) to the next // (n) (2) Reached pre-set maximum n_uncollided_rays (3) Hit 100% of the FSRs + + // Prepare column header print_columns(); + + // Default values + int new_n_rays = 1000; + int n_rays_max = 10000000; + + // initialize loop variables + int64_t n_hits_old = 0; + int64_t n_hits_new = 0; + int batch_first_collided = 1; + int old_n_rays = 0; + + // Check if number of rays were provided and update limit for loop if (RandomRay::first_collision_rays_ != -1) { new_n_rays = RandomRay::first_collision_rays_; n_rays_max = RandomRay::first_collision_rays_; @@ -536,11 +553,11 @@ void RandomRaySimulation::first_collision_source_simulation() int64_t n_hits_new = domain_->check_fsr_hits(); - // print results + // Print results fmt::print( " {:6} {:10} {:}\n", batch_first_collided, new_n_rays, n_hits_new); - // update values for next batch + // Update values for next batch batch_first_collided++; old_n_rays = new_n_rays; new_n_rays *= 2; From e850f6de6d843f6fd5348100492146013c69b352 Mon Sep 17 00:00:00 2001 From: Tomas P Date: Fri, 9 Aug 2024 15:59:47 -0500 Subject: [PATCH 26/27] text review --- docs/source/methods/random_ray.rst | 28 +++++++++++++-------------- docs/source/usersguide/random_ray.rst | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst index 6ecb1fbaffc..be9e10429da 100644 --- a/docs/source/methods/random_ray.rst +++ b/docs/source/methods/random_ray.rst @@ -1001,22 +1001,22 @@ random ray and Monte Carlo, however. First Collision Source Method ---------------------------------- -In cases that the fixed source is not a well defined volumetric source (e.g. point source), -there is the need to preprocess the source into volumetric sources in order to be computed by the +In cases where the fixed source is not a well-defined volumetric source (e.g. point source), +there is the need to preprocess the source into volumetric sources to be computed by the random ray solver. One possible way is through the First Collision Source Method (FCS), which works as a -preconditioner of the source, distributing the source contribution throghout the domain. This is +preconditioner of the source, distributing the source contribution throughout the domain. This is not a new method (`Alcouffe `_), and has been recently implemented in other neutron transport codes (`Ragusa `_, `Falabino `_). -The FCS works generating uncollided neutron angular fluxes :math:`\psi^{\text{un}}_{g}` at the source that travel through +The FCS works by generating uncollided neutron angular fluxes :math:`\psi^{\text{un}}_{g}` at the source that travels through the domain interacting with the media, being naturally attenuated in the process. Neutrons that experience any collision are treated as first collided neutrons and will be used to estimate the volumetric neutron fixed source at that cell. Once the FCS preprocess stage is complete, the fixed volumetric source will be -added to each iteration of the random ray solver. The remaining uncollided flux that have not interacted +added to each iteration of the random ray solver. The remaining uncollided flux that has not interacted at any point of the preprocessing stage is added to the final solution at the end of the neutron transport code. The FCS has a very similar mathematical formulation to the regular Random Ray method. The formulation for -the method with flat source will be provided. The neutron transport equation for the uncollided rays can be +the method with flat sources will be provided. The neutron transport equation for the uncollided rays can be described as in Equation :eq:`moc_final`, however without any pre-existing source terms: .. math:: @@ -1064,8 +1064,8 @@ Which can also be described in terms of :math:`\Delta \psi_{r,g}`: Similarly to Equation :eq:`discretized`, the scalar flux in cell :math:`i` can be defined as the summation of the contributions of the angular fluxes traveling through it. However, in this method, there is the need -to differentiate how the volume is estimated. In the Random Ray method, the rays are being generated uniforminly -across the domain and the volume estimation is unbiased. Nonetheless, angular fluxes have a specific and non well-distributed +to differentiate how the volume is estimated. In the Random Ray method, the rays are generated uniformly +across the domain and the volume estimation is unbiased. Nonetheless, angular fluxes have a specific and non-well-distributed birth location. .. math:: @@ -1074,13 +1074,13 @@ birth location. \phi^{\text{un}}(i,g) = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}^{un}}{V_i} . To avoid bias in the volume estimation, it is added an initial volume estimation stage -to compute the volume of each cell prior running FCS, using the same method presented in +to compute the volume of each cell before running FCS, using the same method presented in the Random Ray method. -In the case o flat source, the volume estimation can be improvde with the random ray solver, -allowing a fast and rough initial estimate. However, linear source requires a more carefull procedure. +In the case of flat sources, the volume estimation can be improved with the random ray solver, +allowing a fast and rough initial estimate. However, linear sources require a more careful procedure. Linear source requires calculating angular flux moments, that depend on the estimated -cell's spatial moments and centroids. If a poor estimation is made, innaccurate gradients will be +cell's spatial moments and centroids. If a poor estimation is made, inaccurate gradients will be carried throughout the calculation and impact the accuracy of the method. Substituting Equation :eq:`fcs_average_solved_difference` @@ -1091,14 +1091,14 @@ into Equation :eq:`fcs_discretized`, we obtain the equation for the uncollided a \phi^{\text{un}}(i,g) = \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,i,g}^{\text{un}}}{\Sigma_{t,i,g} V_i} . -The fixed-source term can be calculated as the first collided flux that undergo scattering events: +The fixed-source term can be calculated as the first collided flux that undergoes scattering events: .. math:: :label: fcs_first_collided_flux Q_\text{fixed}(i,g) = \phi^{\text{FCS}}(i,g) = \sum_{g'}^{G}\Sigma_s(i,g,g') \phi^{\text{un}} (i,g') . -The fixed-source :math:`Q_\text{fixed}` will be treated as a fixed volumetric source for all remaining Random Ray +The fixed source :math:`Q_\text{fixed}` will be treated as a fixed volumetric source for all remaining Random Ray iterations, as presented in Eq :eq:`fixed_source_update`. diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 438312be0dc..50fec11f8f9 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -479,13 +479,13 @@ simulations. First Collision Source Method ----------------------------- -First Collision Source method (FCS) is supported within the fixed source random ray +The First Collision Source method (FCS) is supported within the fixed source random ray solver. The preprocessing stage can be toggle by setting the ``first_collision_source`` field in the :attr:`openmc.Settings.random_ray` dictionary to ``True`` as:: settings.random_ray['first_collision_source'] = True -The method has two input variables: number of rays for initial volume estimation +The method has two input variables: the number of rays for initial volume estimation and number of uncollided rays used in FCS. The user can define the amount of uncollided rays used in the FCS mode by setting the From b4fc15532ad63d6a638be7c82fc717f696f5c5da Mon Sep 17 00:00:00 2001 From: Tomas P Date: Fri, 9 Aug 2024 16:04:53 -0500 Subject: [PATCH 27/27] fix the __init__.py --- openmc/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/__init__.py b/openmc/__init__.py index ee0011d82c5..3c594fffa6a 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -40,7 +40,7 @@ from . import examples -__version__ = '0.14.1-dev' +#__version__ = '0.14.1-dev' -#__version__ = importlib.metadata.version("openmc") +__version__ = importlib.metadata.version("openmc")