2018-07-17 06:43:35 -05:00
|
|
|
#include "openmc/simulation.h"
|
|
|
|
|
|
2018-08-20 14:40:32 -05:00
|
|
|
#include "openmc/capi.h"
|
2018-10-12 08:01:23 -05:00
|
|
|
#include "openmc/eigenvalue.h"
|
2018-07-17 06:43:35 -05:00
|
|
|
#include "openmc/message_passing.h"
|
2018-08-24 12:35:21 -05:00
|
|
|
#include "openmc/settings.h"
|
2018-10-11 09:35:51 -05:00
|
|
|
#include "openmc/tallies/tally.h"
|
2018-09-07 17:26:57 -04:00
|
|
|
#include "openmc/tallies/tally_filter.h"
|
2018-04-12 07:45:47 -05:00
|
|
|
|
2018-04-26 22:26:29 -05:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2018-04-12 07:45:47 -05:00
|
|
|
// OPENMC_RUN encompasses all the main logic where iterations are performed
|
|
|
|
|
// over the batches, generations, and histories in a fixed source or k-eigenvalue
|
|
|
|
|
// calculation.
|
|
|
|
|
|
2018-09-07 17:26:57 -04:00
|
|
|
int openmc_run()
|
|
|
|
|
{
|
2018-04-12 07:45:47 -05:00
|
|
|
openmc_simulation_init();
|
|
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
|
int status = 0;
|
|
|
|
|
while (status == 0 && err == 0) {
|
|
|
|
|
err = openmc_next_batch(&status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
openmc_simulation_finalize();
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2018-09-07 17:26:57 -04:00
|
|
|
|
|
|
|
|
namespace openmc {
|
|
|
|
|
|
2018-08-23 21:38:23 -05:00
|
|
|
//==============================================================================
|
|
|
|
|
// Global variables
|
|
|
|
|
//==============================================================================
|
|
|
|
|
|
2018-10-09 22:34:08 -05:00
|
|
|
namespace simulation {
|
|
|
|
|
|
2018-10-10 07:17:52 -05:00
|
|
|
int current_batch;
|
|
|
|
|
int current_gen;
|
|
|
|
|
int64_t current_work;
|
|
|
|
|
double keff {1.0};
|
|
|
|
|
double keff_std;
|
|
|
|
|
double k_col_abs {0.0};
|
|
|
|
|
double k_col_tra {0.0};
|
|
|
|
|
double k_abs_tra {0.0};
|
|
|
|
|
double log_spacing;
|
|
|
|
|
int n_lost_particles {0};
|
|
|
|
|
bool need_depletion_rx {false};
|
|
|
|
|
int restart_batch;
|
|
|
|
|
bool satisfy_triggers {false};
|
|
|
|
|
bool simulation_initialized {false};
|
|
|
|
|
int total_gen {0};
|
|
|
|
|
int64_t work;
|
|
|
|
|
|
|
|
|
|
std::vector<double> k_generation;
|
2018-07-17 06:43:35 -05:00
|
|
|
std::vector<int64_t> work_index;
|
|
|
|
|
|
2018-10-10 07:17:52 -05:00
|
|
|
// Threadprivate variables
|
|
|
|
|
bool trace; //!< flag to show debug information
|
|
|
|
|
#ifdef _OPENMP
|
|
|
|
|
int n_threads {-1}; //!< number of OpenMP threads
|
|
|
|
|
int thread_id; //!< ID of a given thread
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-10-09 22:34:08 -05:00
|
|
|
} // namespace simulation
|
|
|
|
|
|
2018-08-23 21:38:23 -05:00
|
|
|
//==============================================================================
|
2018-10-12 08:01:23 -05:00
|
|
|
// Non-member functions
|
2018-08-23 21:38:23 -05:00
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
|
|
void openmc_simulation_init_c()
|
2018-09-07 17:26:57 -04:00
|
|
|
{
|
2018-08-23 21:38:23 -05:00
|
|
|
// Determine how much work each process should do
|
|
|
|
|
calculate_work();
|
2018-09-10 16:19:25 -04:00
|
|
|
|
|
|
|
|
// Allocate array for matching filter bins
|
2018-09-07 17:26:57 -04:00
|
|
|
#pragma omp parallel
|
|
|
|
|
{
|
|
|
|
|
filter_matches.resize(n_filters);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-12 08:01:23 -05:00
|
|
|
void initialize_generation()
|
|
|
|
|
{
|
|
|
|
|
if (settings::run_mode == RUN_MODE_EIGENVALUE) {
|
|
|
|
|
// Reset number of fission bank sites
|
|
|
|
|
n_bank = 0;
|
|
|
|
|
|
|
|
|
|
// Count source sites if using uniform fission source weighting
|
|
|
|
|
if (settings::ufs_on) ufs_count_sites();
|
|
|
|
|
|
|
|
|
|
// Store current value of tracklength k
|
|
|
|
|
keff_generation = global_tallies()(K_TRACKLENGTH, RESULT_VALUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-17 19:56:59 -04:00
|
|
|
extern "C" void
|
|
|
|
|
openmc_simulation_finalize_c()
|
|
|
|
|
{
|
|
|
|
|
#pragma omp parallel
|
|
|
|
|
{
|
|
|
|
|
filter_matches.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-10 07:17:52 -05:00
|
|
|
int overall_generation()
|
|
|
|
|
{
|
|
|
|
|
using namespace simulation;
|
|
|
|
|
return settings::gen_per_batch*(current_batch - 1) + current_gen;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-17 06:43:35 -05:00
|
|
|
void calculate_work()
|
|
|
|
|
{
|
|
|
|
|
// Determine minimum amount of particles to simulate on each processor
|
2018-08-24 12:35:21 -05:00
|
|
|
int64_t min_work = settings::n_particles / mpi::n_procs;
|
2018-07-17 06:43:35 -05:00
|
|
|
|
|
|
|
|
// Determine number of processors that have one extra particle
|
2018-08-24 12:35:21 -05:00
|
|
|
int64_t remainder = settings::n_particles % mpi::n_procs;
|
2018-07-17 06:43:35 -05:00
|
|
|
|
|
|
|
|
int64_t i_bank = 0;
|
2018-10-11 12:55:33 -05:00
|
|
|
simulation::work_index.resize(mpi::n_procs + 1);
|
|
|
|
|
simulation::work_index[0] = 0;
|
2018-07-17 06:43:35 -05:00
|
|
|
for (int i = 0; i < mpi::n_procs; ++i) {
|
|
|
|
|
// Number of particles for rank i
|
|
|
|
|
int64_t work_i = i < remainder ? min_work + 1 : min_work;
|
|
|
|
|
|
|
|
|
|
// Set number of particles
|
2018-10-09 22:34:08 -05:00
|
|
|
if (mpi::rank == i) simulation::work = work_i;
|
2018-07-17 06:43:35 -05:00
|
|
|
|
|
|
|
|
// Set index into source bank for rank i
|
|
|
|
|
i_bank += work_i;
|
2018-10-11 12:55:33 -05:00
|
|
|
simulation::work_index[i + 1] = i_bank;
|
2018-07-17 06:43:35 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-26 22:26:29 -05:00
|
|
|
#ifdef OPENMC_MPI
|
|
|
|
|
void broadcast_results() {
|
2018-10-11 09:35:51 -05:00
|
|
|
// Broadcast tally results so that each process has access to results
|
|
|
|
|
for (int i = 1; i <= n_tallies; ++i) {
|
|
|
|
|
// Create a new datatype that consists of all values for a given filter
|
|
|
|
|
// bin and then use that to broadcast. This is done to minimize the
|
|
|
|
|
// chance of the 'count' argument of MPI_BCAST exceeding 2**31
|
|
|
|
|
auto results = tally_results(i);
|
|
|
|
|
|
|
|
|
|
auto shape = results.shape();
|
|
|
|
|
int count_per_filter = shape[1] * shape[2];
|
|
|
|
|
MPI_Datatype result_block;
|
|
|
|
|
MPI_Type_contiguous(count_per_filter, MPI_DOUBLE, &result_block);
|
|
|
|
|
MPI_Type_commit(&result_block);
|
|
|
|
|
MPI_Bcast(results.data(), shape[0], result_block, 0, mpi::intracomm);
|
|
|
|
|
MPI_Type_free(&result_block);
|
2018-09-07 17:26:57 -04:00
|
|
|
}
|
2018-04-26 22:26:29 -05:00
|
|
|
|
|
|
|
|
// Also broadcast global tally results
|
2018-10-11 09:35:51 -05:00
|
|
|
auto gt = global_tallies();
|
|
|
|
|
MPI_Bcast(gt.data(), gt.size(), MPI_DOUBLE, 0, mpi::intracomm);
|
2018-04-26 22:26:29 -05:00
|
|
|
|
|
|
|
|
// These guys are needed so that non-master processes can calculate the
|
|
|
|
|
// combined estimate of k-effective
|
|
|
|
|
double temp[] {simulation::k_col_abs, simulation::k_col_tra,
|
|
|
|
|
simulation::k_abs_tra};
|
|
|
|
|
MPI_Bcast(temp, 3, MPI_DOUBLE, 0, mpi::intracomm);
|
|
|
|
|
simulation::k_col_abs = temp[0];
|
|
|
|
|
simulation::k_col_tra = temp[1];
|
|
|
|
|
simulation::k_abs_tra = temp[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void broadcast_triggers()
|
|
|
|
|
{
|
|
|
|
|
MPI_Bcast(&simulation::satisfy_triggers, 1, MPI_C_BOOL, 0, mpi::intracomm);
|
2018-09-07 17:26:57 -04:00
|
|
|
}
|
2018-04-26 22:26:29 -05:00
|
|
|
#endif
|
|
|
|
|
|
2018-10-12 08:01:23 -05:00
|
|
|
//==============================================================================
|
|
|
|
|
// Fortran compatibility
|
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
|
|
extern "C" double k_generation(int i) { return simulation::k_generation.at(i - 1); }
|
|
|
|
|
extern "C" int k_generation_size() { return simulation::k_generation.size(); }
|
|
|
|
|
extern "C" void k_generation_clear() { simulation::k_generation.clear(); }
|
|
|
|
|
extern "C" void k_generation_reserve(int i) { simulation::k_generation.reserve(i); }
|
2018-10-15 07:45:26 -05:00
|
|
|
extern "C" int64_t work_index(int rank) { return simulation::work_index[rank]; }
|
2018-09-07 17:26:57 -04:00
|
|
|
|
|
|
|
|
} // namespace openmc
|