mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 21:55:41 -04:00
Merge pull request #1706 from paulromano/sourcefile-improve
Refactoring of source classes
This commit is contained in:
commit
bf1c35e23e
15 changed files with 250 additions and 260 deletions
|
|
@ -465,7 +465,7 @@ attributes/sub-elements:
|
|||
as complex as is required to define the source for your problem. The library
|
||||
has a few basic requirements:
|
||||
|
||||
* It must contain a class that inherits from ``openmc::CustomSource``;
|
||||
* It must contain a class that inherits from ``openmc::Source``;
|
||||
* The class must implement a function called ``sample()``;
|
||||
* There must be an ``openmc_create_source()`` function that creates the source
|
||||
as a unique pointer. This function can be used to pass parameters through to
|
||||
|
|
|
|||
|
|
@ -194,9 +194,9 @@ below.
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource
|
||||
class CustomSource : public openmc::Source
|
||||
{
|
||||
openmc::Particle::Bank sample(uint64_t* seed)
|
||||
openmc::Particle::Bank sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// weight
|
||||
|
|
@ -216,16 +216,16 @@ below.
|
|||
}
|
||||
};
|
||||
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameters)
|
||||
extern "C" std::unique_ptr<CustomSource> openmc_create_source(std::string parameters)
|
||||
{
|
||||
return std::make_unique<Source>();
|
||||
return std::make_unique<CustomSource>();
|
||||
}
|
||||
|
||||
The above source creates monodirectional 14.08 MeV neutrons that are distributed
|
||||
in a ring with a 3 cm radius. This routine is not particularly complex, but
|
||||
should serve as an example upon which to build more complicated sources.
|
||||
|
||||
.. note:: The source class must inherit from ``openmc::CustomSource`` and
|
||||
.. note:: The source class must inherit from ``openmc::Source`` and
|
||||
implement a ``sample()`` function.
|
||||
|
||||
.. note:: The ``openmc_create_source()`` function signature must be declared
|
||||
|
|
@ -266,12 +266,12 @@ the source class when it is created:
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource {
|
||||
class CustomSource : public openmc::Source {
|
||||
public:
|
||||
Source(double energy) : energy_{energy} { }
|
||||
CustomSource(double energy) : energy_{energy} { }
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample(uint64_t* seed)
|
||||
openmc::Particle::Bank sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// weight
|
||||
|
|
@ -293,9 +293,9 @@ the source class when it is created:
|
|||
double energy_;
|
||||
};
|
||||
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameter) {
|
||||
extern "C" std::unique_ptr<CustomSource> openmc_create_source(std::string parameter) {
|
||||
double energy = std::stod(parameter);
|
||||
return std::make_unique<Source>(energy);
|
||||
return std::make_unique<CustomSource>(energy);
|
||||
}
|
||||
|
||||
As with the basic custom source functionality, the custom source library
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource
|
||||
class RingSource : public openmc::Source
|
||||
{
|
||||
openmc::Particle::Bank sample(uint64_t* seed)
|
||||
openmc::Particle::Bank sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
|
|
@ -30,7 +30,7 @@ class Source : public openmc::CustomSource
|
|||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameters)
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(std::string parameters)
|
||||
{
|
||||
return std::make_unique<Source>();
|
||||
return std::make_unique<RingSource>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
class RingSource : public openmc::Source {
|
||||
public:
|
||||
Source(double radius, double energy) : radius_(radius), energy_(energy) { }
|
||||
RingSource(double radius, double energy) : radius_(radius), energy_(energy) { }
|
||||
|
||||
// Defines a function that can create a unique pointer to a new instance of this class
|
||||
// by extracting the parameters from the provided string.
|
||||
static std::unique_ptr<Source> from_string(std::string parameters)
|
||||
static std::unique_ptr<RingSource> from_string(std::string parameters)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> parameter_mapping;
|
||||
|
||||
|
|
@ -28,11 +27,11 @@ class Source : public openmc::CustomSource
|
|||
|
||||
double radius = std::stod(parameter_mapping["radius"]);
|
||||
double energy = std::stod(parameter_mapping["energy"]);
|
||||
return std::make_unique<Source>(radius, energy);
|
||||
return std::make_unique<RingSource>(radius, energy);
|
||||
}
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample(uint64_t* seed)
|
||||
openmc::Particle::Bank sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
|
|
@ -60,7 +59,7 @@ class Source : public openmc::CustomSource
|
|||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameters)
|
||||
extern "C" std::unique_ptr<RingSource> openmc_create_source(std::string parameters)
|
||||
{
|
||||
return Source::from_string(parameters);
|
||||
return RingSource::from_string(parameters);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ extern std::string path_cross_sections; //!< path to cross_sections.xml
|
|||
extern std::string path_input; //!< directory where main .xml files resides
|
||||
extern std::string path_output; //!< directory where output files are written
|
||||
extern std::string path_particle_restart; //!< path to a particle restart file
|
||||
extern std::string path_source;
|
||||
extern std::string path_source_library; //!< path to the source shared object
|
||||
extern std::string path_sourcepoint; //!< path to a source file
|
||||
extern "C" std::string path_statepoint; //!< path to a statepoint file
|
||||
|
||||
|
|
|
|||
|
|
@ -19,32 +19,47 @@ namespace openmc {
|
|||
// Global variables
|
||||
//==============================================================================
|
||||
|
||||
class SourceDistribution;
|
||||
class Source;
|
||||
|
||||
namespace model {
|
||||
|
||||
extern std::vector<SourceDistribution> external_sources;
|
||||
extern std::vector<std::unique_ptr<Source>> external_sources;
|
||||
|
||||
} // namespace model
|
||||
|
||||
//==============================================================================
|
||||
//! External source distribution
|
||||
//! Abstract source interface
|
||||
//==============================================================================
|
||||
|
||||
class SourceDistribution {
|
||||
class Source {
|
||||
public:
|
||||
virtual ~Source() = default;
|
||||
|
||||
// Methods that must be implemented
|
||||
virtual Particle::Bank sample(uint64_t* seed) const = 0;
|
||||
|
||||
// Methods that can be overridden
|
||||
virtual double strength() const { return 1.0; }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
//! Source composed of independent spatial, angle, and energy distributions
|
||||
//==============================================================================
|
||||
|
||||
class IndependentSource : public Source {
|
||||
public:
|
||||
// Constructors
|
||||
SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy);
|
||||
explicit SourceDistribution(pugi::xml_node node);
|
||||
IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy);
|
||||
explicit IndependentSource(pugi::xml_node node);
|
||||
|
||||
//! Sample from the external source distribution
|
||||
//! \param[inout] seed Pseudorandom seed pointer
|
||||
//! \return Sampled site
|
||||
Particle::Bank sample(uint64_t* seed) const;
|
||||
Particle::Bank sample(uint64_t* seed) const override;
|
||||
|
||||
// Properties
|
||||
Particle::Type particle_type() const { return particle_; }
|
||||
double strength() const { return strength_; }
|
||||
double strength() const override { return strength_; }
|
||||
|
||||
// Make observing pointers available
|
||||
SpatialDistribution* space() const { return space_.get(); }
|
||||
|
|
@ -59,14 +74,45 @@ private:
|
|||
UPtrDist energy_; //!< Energy distribution
|
||||
};
|
||||
|
||||
class CustomSource {
|
||||
public:
|
||||
virtual ~CustomSource() {}
|
||||
//==============================================================================
|
||||
//! Source composed of particles read from a file
|
||||
//==============================================================================
|
||||
|
||||
virtual Particle::Bank sample(uint64_t* seed) = 0;
|
||||
class FileSource : public Source {
|
||||
public:
|
||||
// Constructors
|
||||
explicit FileSource(std::string path);
|
||||
|
||||
// Methods
|
||||
Particle::Bank sample(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
std::vector<Particle::Bank> sites_; //!< Source sites from a file
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<CustomSource> create_custom_source_t(std::string parameters);
|
||||
//==============================================================================
|
||||
//! Wrapper for custom sources that manages opening/closing shared library
|
||||
//==============================================================================
|
||||
|
||||
class CustomSourceWrapper : public Source {
|
||||
public:
|
||||
// Constructors, destructors
|
||||
CustomSourceWrapper(std::string path, std::string parameters);
|
||||
~CustomSourceWrapper();
|
||||
|
||||
// Defer implementation to custom source library
|
||||
Particle::Bank sample(uint64_t* seed) const override
|
||||
{
|
||||
return custom_source_->sample(seed);
|
||||
}
|
||||
|
||||
double strength() const override { return custom_source_->strength(); }
|
||||
private:
|
||||
void* shared_library_; //!< library from dlopen
|
||||
std::unique_ptr<Source> custom_source_;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Source> create_custom_source_t(std::string parameters);
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
|
|
@ -81,18 +127,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
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@
|
|||
#define OPENMC_STATE_POINT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "hdf5.h"
|
||||
|
||||
#include "openmc/capi.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
void load_state_point();
|
||||
void write_source_point(const char* filename);
|
||||
void write_source_bank(hid_t group_id);
|
||||
void read_source_bank(hid_t group_id);
|
||||
void read_source_bank(hid_t group_id, std::vector<Particle::Bank>& sites, bool distribute);
|
||||
void write_tally_results_nr(hid_t file_id);
|
||||
void restart_set_keff();
|
||||
|
||||
|
|
|
|||
|
|
@ -73,8 +73,6 @@ std::string path_cross_sections;
|
|||
std::string path_input;
|
||||
std::string path_output;
|
||||
std::string path_particle_restart;
|
||||
std::string path_source;
|
||||
std::string path_source_library;
|
||||
std::string path_sourcepoint;
|
||||
std::string path_statepoint;
|
||||
|
||||
|
|
@ -421,17 +419,31 @@ 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.emplace_back(node);
|
||||
if (check_for_node(node, "file")) {
|
||||
auto path = get_node_value(node, "file", false, true);
|
||||
model::external_sources.push_back(std::make_unique<FileSource>(path));
|
||||
} else 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<IndependentSource>(node));
|
||||
}
|
||||
}
|
||||
|
||||
// If no source specified, default to isotropic point source at origin with Watt spectrum
|
||||
if (model::external_sources.empty()) {
|
||||
SourceDistribution source {
|
||||
model::external_sources.push_back(std::make_unique<IndependentSource>(
|
||||
UPtrSpace{new SpatialPoint({0.0, 0.0, 0.0})},
|
||||
UPtrAngle{new Isotropic()},
|
||||
UPtrDist{new Watt(0.988e6, 2.249e-6)}
|
||||
};
|
||||
model::external_sources.push_back(std::move(source));
|
||||
));
|
||||
}
|
||||
|
||||
// Check if we want to write out source
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
263
src/source.cpp
263
src/source.cpp
|
|
@ -39,27 +39,18 @@ namespace openmc {
|
|||
|
||||
namespace model {
|
||||
|
||||
std::vector<SourceDistribution> external_sources;
|
||||
std::vector<std::unique_ptr<Source>> external_sources;
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void* custom_source_library;
|
||||
std::string custom_source_parameters;
|
||||
std::unique_ptr<CustomSource> custom_source;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// SourceDistribution implementation
|
||||
// IndependentSource implementation
|
||||
//==============================================================================
|
||||
|
||||
SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
|
||||
IndependentSource::IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
|
||||
: space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }
|
||||
|
||||
SourceDistribution::SourceDistribution(pugi::xml_node node)
|
||||
IndependentSource::IndependentSource(pugi::xml_node node)
|
||||
{
|
||||
// Check for particle type
|
||||
if (check_for_node(node, "particle")) {
|
||||
|
|
@ -81,24 +72,7 @@ SourceDistribution::SourceDistribution(pugi::xml_node node)
|
|||
|
||||
// Check for external source file
|
||||
if (check_for_node(node, "file")) {
|
||||
// Copy path of source file
|
||||
settings::path_source = get_node_value(node, "file", false, true);
|
||||
|
||||
// Check if source file exists
|
||||
if (!file_exists(settings::path_source)) {
|
||||
fatal_error(fmt::format("Source file '{}' does not exist.",
|
||||
settings::path_source));
|
||||
}
|
||||
} 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
|
||||
|
|
@ -167,8 +141,7 @@ SourceDistribution::SourceDistribution(pugi::xml_node node)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Particle::Bank SourceDistribution::sample(uint64_t* seed) const
|
||||
Particle::Bank IndependentSource::sample(uint64_t* seed) const
|
||||
{
|
||||
Particle::Bank site;
|
||||
|
||||
|
|
@ -185,10 +158,10 @@ Particle::Bank SourceDistribution::sample(uint64_t* seed) const
|
|||
|
||||
// Sample spatial distribution
|
||||
site.r = space_->sample(seed);
|
||||
double xyz[] {site.r.x, site.r.y, site.r.z};
|
||||
|
||||
// Now search to see if location exists in geometry
|
||||
int32_t cell_index, instance;
|
||||
double xyz[] {site.r.x, site.r.y, site.r.z};
|
||||
int err = openmc_find_cell(xyz, &cell_index, &instance);
|
||||
found = (err != OPENMC_E_GEOMETRY);
|
||||
|
||||
|
|
@ -256,6 +229,94 @@ Particle::Bank SourceDistribution::sample(uint64_t* seed) const
|
|||
return site;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// FileSource implementation
|
||||
//==============================================================================
|
||||
|
||||
FileSource::FileSource(std::string path)
|
||||
{
|
||||
// Check if source file exists
|
||||
if (!file_exists(path)) {
|
||||
fatal_error(fmt::format("Source file '{}' does not exist.", path));
|
||||
}
|
||||
|
||||
// Read the source from a binary file instead of sampling from some
|
||||
// assumed source distribution
|
||||
write_message(6, "Reading source file from {}...", path);
|
||||
|
||||
// Open the binary file
|
||||
hid_t file_id = file_open(path, 'r', true);
|
||||
|
||||
// Check to make sure this is a source file
|
||||
std::string filetype;
|
||||
read_attribute(file_id, "filetype", filetype);
|
||||
if (filetype != "source" && filetype != "statepoint") {
|
||||
fatal_error("Specified starting source file not a source file type.");
|
||||
}
|
||||
|
||||
// Read in the source particles
|
||||
read_source_bank(file_id, sites_, false);
|
||||
|
||||
// Close file
|
||||
file_close(file_id);
|
||||
}
|
||||
|
||||
Particle::Bank FileSource::sample(uint64_t* seed) const
|
||||
{
|
||||
size_t i_site = sites_.size()*prn(seed);
|
||||
return sites_[i_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
|
||||
//==============================================================================
|
||||
|
|
@ -264,47 +325,16 @@ void initialize_source()
|
|||
{
|
||||
write_message("Initializing source particles...", 5);
|
||||
|
||||
if (!settings::path_source.empty()) {
|
||||
// Read the source from a binary file instead of sampling from some
|
||||
// assumed source distribution
|
||||
// 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);
|
||||
|
||||
write_message(6, "Reading source file from {}...", settings::path_source);
|
||||
|
||||
// Open the binary file
|
||||
hid_t file_id = file_open(settings::path_source, 'r', true);
|
||||
|
||||
// Read the file type
|
||||
std::string filetype;
|
||||
read_attribute(file_id, "filetype", filetype);
|
||||
|
||||
// Check to make sure this is a source file
|
||||
if (filetype != "source" && filetype != "statepoint") {
|
||||
fatal_error("Specified starting source file not a source file type.");
|
||||
}
|
||||
|
||||
// Read in the source bank
|
||||
read_source_bank(file_id);
|
||||
|
||||
// Close file
|
||||
file_close(file_id);
|
||||
} else if (!settings::path_source_library.empty()) {
|
||||
|
||||
write_message(6, "Sampling library source {}...", settings::path_source);
|
||||
|
||||
fill_source_bank_custom_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
|
||||
|
|
@ -319,15 +349,10 @@ 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)
|
||||
total_strength += s.strength();
|
||||
total_strength += s->strength();
|
||||
|
||||
// Sample from among multiple source distributions
|
||||
int i = 0;
|
||||
|
|
@ -335,13 +360,13 @@ Particle::Bank sample_external_source(uint64_t* seed)
|
|||
double xi = prn(seed)*total_strength;
|
||||
double c = 0.0;
|
||||
for (; i < model::external_sources.size(); ++i) {
|
||||
c += model::external_sources[i].strength();
|
||||
c += model::external_sources[i]->strength();
|
||||
if (xi < c) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sample source site from i-th source distribution
|
||||
Particle::Bank site {model::external_sources[i].sample(seed)};
|
||||
Particle::Bank site {model::external_sources[i]->sample(seed)};
|
||||
|
||||
// If running in MG, convert site.E to group
|
||||
if (!settings::run_CE) {
|
||||
|
|
@ -358,80 +383,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 CustomSource 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 CustomSource
|
||||
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 CustomSource
|
||||
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
|
||||
|
|
|
|||
|
|
@ -485,11 +485,11 @@ void load_state_point()
|
|||
+ "...", 5);
|
||||
|
||||
// Open source file
|
||||
file_id = file_open(settings::path_source.c_str(), 'r', true);
|
||||
file_id = file_open(settings::path_sourcepoint.c_str(), 'r', true);
|
||||
}
|
||||
|
||||
// Read source
|
||||
read_source_bank(file_id);
|
||||
read_source_bank(file_id, simulation::source_bank, true);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -653,43 +653,51 @@ write_source_bank(hid_t group_id)
|
|||
}
|
||||
|
||||
|
||||
void read_source_bank(hid_t group_id)
|
||||
void read_source_bank(hid_t group_id, std::vector<Particle::Bank>& sites, bool distribute)
|
||||
{
|
||||
hid_t banktype = h5banktype();
|
||||
|
||||
// Open the dataset
|
||||
hid_t dset = H5Dopen(group_id, "source_bank", H5P_DEFAULT);
|
||||
|
||||
// Create another data space but for each proc individually
|
||||
hsize_t dims[] {static_cast<hsize_t>(simulation::work_per_rank)};
|
||||
hid_t memspace = H5Screate_simple(1, dims, nullptr);
|
||||
|
||||
// Make sure source bank is big enough
|
||||
hid_t dspace = H5Dget_space(dset);
|
||||
hsize_t dims_all[1];
|
||||
H5Sget_simple_extent_dims(dspace, dims_all, nullptr);
|
||||
if (simulation::work_index[mpi::n_procs] > dims_all[0]) {
|
||||
fatal_error("Number of source sites in source file is less "
|
||||
"than number of source particles per generation.");
|
||||
}
|
||||
hsize_t n_sites;
|
||||
H5Sget_simple_extent_dims(dspace, &n_sites, nullptr);
|
||||
|
||||
// Select hyperslab for each process
|
||||
hsize_t start[] {static_cast<hsize_t>(simulation::work_index[mpi::rank])};
|
||||
H5Sselect_hyperslab(dspace, H5S_SELECT_SET, start, nullptr, dims, nullptr);
|
||||
// Make sure vector is big enough in case where we're reading entire source on
|
||||
// each process
|
||||
if (!distribute) sites.resize(n_sites);
|
||||
|
||||
hid_t memspace;
|
||||
if (distribute) {
|
||||
if (simulation::work_index[mpi::n_procs] > n_sites) {
|
||||
fatal_error("Number of source sites in source file is less "
|
||||
"than number of source particles per generation.");
|
||||
}
|
||||
|
||||
// Create another data space but for each proc individually
|
||||
hsize_t n_sites_local = simulation::work_per_rank;
|
||||
memspace = H5Screate_simple(1, &n_sites_local, nullptr);
|
||||
|
||||
// Select hyperslab for each process
|
||||
hsize_t offset = simulation::work_index[mpi::rank];
|
||||
H5Sselect_hyperslab(dspace, H5S_SELECT_SET, &offset, nullptr, &n_sites_local, nullptr);
|
||||
} else {
|
||||
memspace = H5S_ALL;
|
||||
}
|
||||
|
||||
#ifdef PHDF5
|
||||
// Read data in parallel
|
||||
hid_t plist = H5Pcreate(H5P_DATASET_XFER);
|
||||
H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE);
|
||||
H5Dread(dset, banktype, memspace, dspace, plist, simulation::source_bank.data());
|
||||
H5Dread(dset, banktype, memspace, dspace, plist, sites.data());
|
||||
H5Pclose(plist);
|
||||
#else
|
||||
H5Dread(dset, banktype, memspace, dspace, H5P_DEFAULT, simulation::source_bank.data());
|
||||
H5Dread(dset, banktype, memspace, dspace, H5P_DEFAULT, sites.data());
|
||||
#endif
|
||||
|
||||
// Close all ids
|
||||
H5Sclose(dspace);
|
||||
H5Sclose(memspace);
|
||||
if (distribute) H5Sclose(memspace);
|
||||
H5Dclose(dset);
|
||||
H5Tclose(banktype);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -632,7 +632,7 @@ void Tally::accumulate()
|
|||
double total_source = 0.0;
|
||||
if (settings::run_mode == RunMode::FIXED_SOURCE) {
|
||||
for (const auto& s : model::external_sources) {
|
||||
total_source += s.strength();
|
||||
total_source += s->strength();
|
||||
}
|
||||
} else {
|
||||
total_source = 1.0;
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : openmc::CustomSource
|
||||
class CustomSource : public openmc::Source
|
||||
{
|
||||
openmc::Particle::Bank sample(uint64_t *seed)
|
||||
openmc::Particle::Bank sample(uint64_t *seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
|
||||
|
||||
particle.r.x = 0.;
|
||||
particle.r.y = 0.;
|
||||
particle.r.z = 0.;
|
||||
|
|
@ -22,14 +22,14 @@ class Source : openmc::CustomSource
|
|||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
return particle;
|
||||
return particle;
|
||||
}
|
||||
};
|
||||
|
||||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameters)
|
||||
extern "C" std::unique_ptr<CustomSource> openmc_create_source(std::string parameters)
|
||||
{
|
||||
return std::make_unique<Source>();
|
||||
return std::make_unique<CustomSource>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
k-combined:
|
||||
2.939525E-01 6.311780E-03
|
||||
3.080726E-01 9.554124E-03
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource {
|
||||
class CustomSource : public openmc::Source {
|
||||
public:
|
||||
Source(double energy) : energy_(energy) { }
|
||||
CustomSource(double energy) : energy_(energy) { }
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample(uint64_t* seed)
|
||||
openmc::Particle::Bank sample(uint64_t* seed) const
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
|
|
@ -31,8 +31,8 @@ class Source : public openmc::CustomSource {
|
|||
// A function to create a unique pointer to an instance of this class when generated
|
||||
// via a plugin call using dlopen/dlsym.
|
||||
// You must have external C linkage here otherwise dlopen will not find the file
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(std::string parameter)
|
||||
extern "C" std::unique_ptr<CustomSource> openmc_create_source(std::string parameter)
|
||||
{
|
||||
double energy = std::stod(parameter);
|
||||
return std::make_unique<Source>(energy);
|
||||
return std::make_unique<CustomSource>(energy);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue