Add wrapper class for custom sources

This commit is contained in:
Paul Romano 2020-10-22 15:50:30 -05:00
parent 713469bf59
commit 3f62fab565
4 changed files with 95 additions and 142 deletions

View file

@ -71,6 +71,28 @@ private:
std::vector<Particle::Bank> sites_; //!< Source sites from a file
};
//==============================================================================
//! Wrapper for custom sources that manages opening/closing shared library
//==============================================================================
class CustomSourceWrapper : public SourceDistribution {
public:
// Constructors, destructors
CustomSourceWrapper(std::string path, std::string parameters);
~CustomSourceWrapper();
// Defer implementation to custom source library
Particle::Bank sample(uint64_t* seed) override
{
return custom_source_->sample(seed);
}
double strength() const override { return custom_source_->strength(); }
private:
void* shared_library_; //!< library from dlopen
std::unique_ptr<SourceDistribution> custom_source_;
};
typedef std::unique_ptr<SourceDistribution> create_custom_source_t(std::string parameters);
//==============================================================================
@ -86,18 +108,6 @@ extern "C" void initialize_source();
//! \return Sampled source site
Particle::Bank sample_external_source(uint64_t* seed);
//! Sample a site from custom source library
Particle::Bank sample_custom_source_library(uint64_t* seed);
//! Load custom source library
void load_custom_source_library();
//! Release custom source library
void close_custom_source_library();
//! Fill source bank at the end of a generation for dlopen based source simulation
void fill_source_bank_custom_source();
void free_memory_source();
} // namespace openmc

View file

@ -420,7 +420,19 @@ void read_settings_xml()
// Get point to list of <source> elements and make sure there is at least one
for (pugi::xml_node node : root.children("source")) {
model::external_sources.push_back(std::make_unique<IndependentSourceDistribution>(node));
if (check_for_node(node, "library")) {
// Get shared library path and parameters
auto path = get_node_value(node, "library", false, true);
std::string parameters;
if (check_for_node(node, "parameters")) {
parameters = get_node_value(node, "parameters", false, true);
}
// Create custom source
model::external_sources.push_back(std::make_unique<CustomSourceWrapper>(path, parameters));
} else {
model::external_sources.push_back(std::make_unique<IndependentSourceDistribution>(node));
}
}
// If no source specified, default to isotropic point source at origin with Watt spectrum

View file

@ -121,12 +121,6 @@ int openmc_simulation_init()
}
}
// If fixed source and using custom source library then need to load
if (settings::run_mode == RunMode::FIXED_SOURCE &&
!settings::path_source_library.empty()) {
load_custom_source_library();
}
// Display header
if (mpi::master) {
if (settings::run_mode == RunMode::FIXED_SOURCE) {
@ -173,12 +167,6 @@ int openmc_simulation_finalize()
t->active_ = false;
}
// If fixed source and using custom source library then need to close
if (settings::run_mode == RunMode::FIXED_SOURCE &&
!settings::path_source_library.empty()) {
close_custom_source_library();
}
// Stop timers and show timing statistics
simulation::time_finalize.stop();
simulation::time_total.stop();

View file

@ -43,17 +43,8 @@ std::vector<std::unique_ptr<SourceDistribution>> external_sources;
}
namespace {
void* custom_source_library;
std::string custom_source_parameters;
std::unique_ptr<SourceDistribution> custom_source;
}
//==============================================================================
// SourceDistribution implementation
// IndependentSourceDistribution implementation
//==============================================================================
IndependentSourceDistribution::IndependentSourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
@ -111,16 +102,6 @@ IndependentSourceDistribution::IndependentSourceDistribution(pugi::xml_node node
// Close file
file_close(file_id);
} else if (check_for_node(node, "library")) {
settings::path_source_library = get_node_value(node, "library", false, true);
if (!file_exists(settings::path_source_library)) {
fatal_error(fmt::format("Source library '{}' does not exist.",
settings::path_source_library));
}
if (check_for_node(node, "parameters")) {
custom_source_parameters = get_node_value(node, "parameters", false, true);
}
} else {
// Spatial distribution for external source
@ -189,7 +170,6 @@ IndependentSourceDistribution::IndependentSourceDistribution(pugi::xml_node node
}
}
Particle::Bank IndependentSourceDistribution::sample(uint64_t* seed)
{
Particle::Bank site;
@ -285,6 +265,56 @@ Particle::Bank IndependentSourceDistribution::sample(uint64_t* seed)
return site;
}
//==============================================================================
// CustomSourceWrapper implementation
//==============================================================================
CustomSourceWrapper::CustomSourceWrapper(std::string path, std::string parameters)
{
#ifdef HAS_DYNAMIC_LINKING
// Open the library
shared_library_ = dlopen(path.c_str(), RTLD_LAZY);
if (!shared_library_) {
fatal_error("Couldn't open source library " + path);
}
// reset errors
dlerror();
// get the function to create the custom source from the library
auto create_custom_source = reinterpret_cast<create_custom_source_t*>(
dlsym(shared_library_, "openmc_create_source"));
// check for any dlsym errors
auto dlsym_error = dlerror();
if (dlsym_error) {
std::string error_msg = fmt::format("Couldn't open the openmc_create_source symbol: {}", dlsym_error);
dlclose(shared_library_);
fatal_error(error_msg);
}
// create a pointer to an instance of the custom source
custom_source_ = create_custom_source(parameters);
#else
fatal_error("Custom source libraries have not yet been implemented for "
"non-POSIX systems");
#endif
}
CustomSourceWrapper::~CustomSourceWrapper()
{
// Make sure custom source is cleared before closing shared library
if (custom_source_.get()) custom_source_.reset();
#ifdef HAS_DYNAMIC_LINKING
dlclose(shared_library_);
#else
fatal_error("Custom source libraries have not yet been implemented for "
"non-POSIX systems");
#endif
}
//==============================================================================
// Non-member functions
//==============================================================================
@ -293,22 +323,16 @@ void initialize_source()
{
write_message("Initializing source particles...", 5);
if (!settings::path_source_library.empty()) {
write_message(6, "Sampling library source {}...", settings::path_source_library);
fill_source_bank_custom_source();
// Generation source sites from specified distribution in user input
#pragma omp parallel for
for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
// initialize random number seed
int64_t id = simulation::total_gen*settings::n_particles +
simulation::work_index[mpi::rank] + i + 1;
uint64_t seed = init_seed(id, STREAM_SOURCE);
} else {
// Generation source sites from specified distribution in user input
#pragma omp parallel for
for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
// initialize random number seed
int64_t id = simulation::total_gen*settings::n_particles +
simulation::work_index[mpi::rank] + i + 1;
uint64_t seed = init_seed(id, STREAM_SOURCE);
// sample external source distribution
simulation::source_bank[i] = sample_external_source(&seed);
}
// sample external source distribution
simulation::source_bank[i] = sample_external_source(&seed);
}
// Write out initial source
@ -323,11 +347,6 @@ void initialize_source()
Particle::Bank sample_external_source(uint64_t* seed)
{
// return values from custom source if using
if (!settings::path_source_library.empty()) {
return sample_custom_source_library(seed);
}
// Determine total source strength
double total_strength = 0.0;
for (auto& s : model::external_sources)
@ -362,80 +381,4 @@ void free_memory_source()
model::external_sources.clear();
}
void load_custom_source_library()
{
#ifdef HAS_DYNAMIC_LINKING
// Open the library
custom_source_library = dlopen(settings::path_source_library.c_str(), RTLD_LAZY);
if (!custom_source_library) {
fatal_error("Couldn't open source library " + settings::path_source_library);
}
// reset errors
dlerror();
// get the function to create the custom source from the library
auto create_custom_source = reinterpret_cast<create_custom_source_t*>(
dlsym(custom_source_library, "openmc_create_source"));
// check for any dlsym errors
auto dlsym_error = dlerror();
if (dlsym_error) {
std::string error_msg = fmt::format("Couldn't open the openmc_create_source symbol: {}", dlsym_error);
dlclose(custom_source_library);
fatal_error(error_msg);
}
// create a pointer to an instance of the custom source
custom_source = create_custom_source(custom_source_parameters);
#else
fatal_error("Custom source libraries have not yet been implemented for "
"non-POSIX systems");
#endif
}
void close_custom_source_library()
{
if (custom_source.get()) {
// Make sure the custom source is destroyed before we close it's libary.
custom_source.reset();
}
#ifdef HAS_DYNAMIC_LINKING
dlclose(custom_source_library);
#else
fatal_error("Custom source libraries have not yet been implemented for "
"non-POSIX systems");
#endif
}
Particle::Bank sample_custom_source_library(uint64_t* seed)
{
// sample from the instance of the custom source
return custom_source->sample(seed);
}
void fill_source_bank_custom_source()
{
// Load the custom library
load_custom_source_library();
// Generation source sites from specified distribution in the
// library source
for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
// initialize random number seed
int64_t id = (simulation::total_gen + overall_generation()) *
settings::n_particles + simulation::work_index[mpi::rank] + i + 1;
uint64_t seed = init_seed(id, STREAM_SOURCE);
// sample custom library source
simulation::source_bank[i] = sample_custom_source_library(&seed);
}
// release the library
close_custom_source_library();
}
} // namespace openmc