diff --git a/include/openmc/source.h b/include/openmc/source.h index f1fe40a39..59f1151f9 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -71,6 +71,28 @@ private: std::vector 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 custom_source_; +}; + typedef std::unique_ptr 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 diff --git a/src/settings.cpp b/src/settings.cpp index 8b0cd5300..55dc04aa6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -420,7 +420,19 @@ void read_settings_xml() // Get point to list of 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(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(path, parameters)); + } else { + model::external_sources.push_back(std::make_unique(node)); + } } // If no source specified, default to isotropic point source at origin with Watt spectrum diff --git a/src/simulation.cpp b/src/simulation.cpp index c95c0386c..1e35adeee 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -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(); diff --git a/src/source.cpp b/src/source.cpp index dc75a0c81..e19ccc832 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -43,17 +43,8 @@ std::vector> external_sources; } -namespace { - -void* custom_source_library; -std::string custom_source_parameters; -std::unique_ptr 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( + 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( - 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