mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-28 22:26:08 -04:00
Remove old source_sampling custom source method
Custom sources are now created only through the new class-based method, which supports parameterization. New method also slightly adjusted to create the source as managed by a unique_ptr. Examples and tests updated to align with this approach. Documentation updated.
This commit is contained in:
parent
475656e6e0
commit
821e7d9825
10 changed files with 177 additions and 151 deletions
|
|
@ -462,25 +462,23 @@ attributes/sub-elements:
|
|||
:library:
|
||||
If this attribute is given, it indicates that the source is to be
|
||||
instantiated from an externally compiled source function. This source can be
|
||||
as complex as is required to define the source for your problem. The only
|
||||
requirement is that there is a function called ``sample_source()``. More
|
||||
documentation on how to build sources can be found in :ref:`custom_source`.
|
||||
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``;
|
||||
* The class must implement a function called ``sample_source()``;
|
||||
* There must be a ``create_openmc_source()`` function that creates the source
|
||||
as a unique pointer. This function can be used to pass parameters through to
|
||||
the source from the XML, if needed.
|
||||
|
||||
More documentation on how to build sources can be found in :ref:`custom_source`.
|
||||
|
||||
*Default*: None
|
||||
|
||||
:parameters:
|
||||
If this attribute is given, it indicates that the source is to be
|
||||
instantiated from an externally compiled source function, with parameters
|
||||
defined by the string provided in this attribute. In this case, the
|
||||
custom source library must define a class that inherits from the
|
||||
``openmc::CustomSource`` abstract class. This class must implement a
|
||||
``sample_source()`` function, which takes an unsigned integer pointer as an
|
||||
argument. The custom source library must also contain an
|
||||
``openmc_create_source`` method, which takes the value provided to the
|
||||
parameters attribute as an argument and returns a pointer to an instance of
|
||||
the custom source. If the library attribute is not provided then this
|
||||
attribute will be ignored. More documentation on how to build parametrized
|
||||
sources can be found in :ref:`parameterized_custom_source`.
|
||||
If this attribute is given, it provides the parameters to pass through to the
|
||||
class generated using the ``library`` parameter . More documentation on how to
|
||||
build parametrized sources can be found in :ref:`parameterized_custom_source`.
|
||||
|
||||
*Default*: None
|
||||
|
||||
|
|
|
|||
|
|
@ -182,42 +182,55 @@ Custom Sources
|
|||
|
||||
It is often the case that one may wish to simulate a complex source distribution
|
||||
that is not possible to represent with the classes described above. For these
|
||||
situations, it is possible to define a complex source with an externally defined
|
||||
source function that is loaded at runtime. A simple example source is shown
|
||||
situations, it is possible to define a complex source class containing an externally
|
||||
defined source function that is loaded at runtime. A simple example source is shown
|
||||
below.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
// you must have external C linkage here
|
||||
extern "C" openmc::Particle::Bank sample_source(uint64_t* seed) {
|
||||
openmc::Particle::Bank particle;
|
||||
// weight
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = 3.0;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
return particle;
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// weight
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = 3.0;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
return particle;
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source() {
|
||||
return std::unique_ptr<Source> (new Source());
|
||||
}
|
||||
|
||||
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 function signature must be declared ``extern "C"``.
|
||||
.. note:: The source class must inherit from ``openmc::CustomSource`` and
|
||||
implement a ``sample_source()`` function.
|
||||
|
||||
.. note:: You should only use the openmc::prn() random number generator
|
||||
.. note:: The ``openmc_create_source()`` function signature must be declared
|
||||
``extern "C"``.
|
||||
|
||||
.. note:: You should only use the ``openmc::prn()`` random number generator.
|
||||
|
||||
In order to build your external source, you will need to link it against the
|
||||
OpenMC shared library. This can be done by writing a CMakeLists.txt file:
|
||||
|
|
@ -240,61 +253,53 @@ used for sampling source particles at runtime.
|
|||
Custom Parameterized Sources
|
||||
----------------------------
|
||||
|
||||
If the custom source may be used with parameters at a variety of values then it
|
||||
may be necessary to represent those parameters as a string in order to avoid
|
||||
recompiling the source library for each run. This is supported by defining a
|
||||
class inheriting from ``openmc::CustomSource`` that implements a
|
||||
``sample_source`` function:
|
||||
Some custom sources may have values (parameters) that can be changed between
|
||||
runs. This is supported by using the ``create_custom_source()`` function to
|
||||
pass parameters defined in the :attr:`openmc.Source.parameters` attribute to
|
||||
the source class when it is created:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class ParameterizedSource : public openmc::CustomSource {
|
||||
public:
|
||||
double energy;
|
||||
|
||||
ParameterizedSource(double energy) {
|
||||
this->energy = energy;
|
||||
}
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
double energy;
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed) {
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
particle.r.x = 0.0;
|
||||
particle.r.y = 0.0;
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = this->energy;
|
||||
particle.delayed_group = 0;
|
||||
Source(double energy)
|
||||
{
|
||||
this->energy = energy;
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// weight
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
particle.r.x = 0.0;
|
||||
particle.r.y = 0.0;
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = this->energy;
|
||||
particle.delayed_group = 0;
|
||||
|
||||
return particle;
|
||||
}
|
||||
};
|
||||
|
||||
The custom source library function in this case must also define an
|
||||
``openmc_create_source`` method, which will be used to generate an instance of
|
||||
the custom source, based on the value supplied in the
|
||||
:attr:``openmc.Source.parameters`` attribute. The
|
||||
``openmc_create_source`` method must be defined with ``extern "C"``:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// you must have external C linkage here otherwise
|
||||
// dlopen will not find the file
|
||||
extern "C" ParameterizedSource* openmc_create_source(const char* parameter) {
|
||||
return new ParameterizedSource(atof(parameter));
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(const char* parameter) {
|
||||
return std::unique_ptr<Source> (new Source(atof(parameter)));
|
||||
}
|
||||
|
||||
As with the basic custom source functionality, the custom source library
|
||||
location must also be provided in the :attr:`openmc.Source.library`
|
||||
attribute.
|
||||
location must be provided in the :attr:`openmc.Source.library` attribute.
|
||||
|
||||
---------------
|
||||
Shannon Entropy
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
#include <cmath> // for M_PI
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
// you must have external C linkage here otherwise
|
||||
// dlopen will not find the file
|
||||
extern "C" openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2. * M_PI * openmc::prn(seed);
|
||||
double radius = 3.0;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
return particle;
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = 3.0;
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
particle.r.z = 0.0;
|
||||
// angle
|
||||
particle.u = {1.0, 0.0, 0.0};
|
||||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
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()
|
||||
{
|
||||
return std::unique_ptr<Source> (new Source());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
#include <cmath> // for M_PI
|
||||
#include <memory> // for unique_ptr
|
||||
#include <unordered_map>
|
||||
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class ParameterizedSource : public openmc::CustomSource {
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
protected:
|
||||
double radius_;
|
||||
double energy_;
|
||||
|
||||
// Protect the constructor so that the class can only be created by serialisation.
|
||||
ParameterizedSource(double radius, double energy) {
|
||||
// Protect the constructor as we only want the class to be created by the from_string method.
|
||||
Source(double radius, double energy)
|
||||
{
|
||||
radius_ = radius;
|
||||
energy_ = energy;
|
||||
}
|
||||
|
|
@ -21,9 +24,10 @@ class ParameterizedSource : public openmc::CustomSource {
|
|||
double radius() { return radius_; }
|
||||
double energy() { return energy_; }
|
||||
|
||||
// Defines a function that can create a pointer to a new instance of this class
|
||||
// by deserializing from the provided string.
|
||||
static ParameterizedSource* from_string(const char* parameters) {
|
||||
// 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(const char* parameters)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> parameter_mapping;
|
||||
|
||||
std::stringstream ss(parameters);
|
||||
|
|
@ -35,17 +39,20 @@ class ParameterizedSource : public openmc::CustomSource {
|
|||
parameter_mapping[key] = value;
|
||||
}
|
||||
|
||||
return new ParameterizedSource(std::stod(parameter_mapping["radius"]), std::stod(parameter_mapping["energy"]));
|
||||
return std::unique_ptr<Source> (
|
||||
new Source(std::stod(parameter_mapping["radius"]), std::stod(parameter_mapping["energy"]))
|
||||
);
|
||||
}
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed) {
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2. * M_PI * openmc::prn(seed);
|
||||
double angle = 2.0 * M_PI * openmc::prn(seed);
|
||||
double radius = this->radius();
|
||||
particle.r.x = radius * std::cos(angle);
|
||||
particle.r.y = radius * std::sin(angle);
|
||||
|
|
@ -59,9 +66,10 @@ class ParameterizedSource : public openmc::CustomSource {
|
|||
}
|
||||
};
|
||||
|
||||
// A function to create a pointer to an instance of this class when generated
|
||||
// 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" ParameterizedSource* openmc_create_source(const char* parameters) {
|
||||
return ParameterizedSource::from_string(parameters);
|
||||
extern "C" std::unique_ptr<Source> openmc_create_source(const char* parameters)
|
||||
{
|
||||
return Source::from_string(parameters);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class CustomSource {
|
|||
virtual Particle::Bank sample_source(uint64_t* seed) = 0;
|
||||
};
|
||||
|
||||
typedef CustomSource* create_custom_source_t(const char* parameters);
|
||||
typedef std::unique_ptr<CustomSource> create_custom_source_t(const char* parameters);
|
||||
|
||||
//==============================================================================
|
||||
// Functions
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#endif
|
||||
|
||||
#include <algorithm> // for move
|
||||
#include <memory> // for unique_ptr
|
||||
|
||||
#ifdef HAS_DYNAMIC_LINKING
|
||||
#include <dlfcn.h> // for dlopen, dlsym, dlclose, dlerror
|
||||
|
|
@ -45,11 +46,8 @@ std::vector<SourceDistribution> external_sources;
|
|||
namespace {
|
||||
|
||||
void* custom_source_library;
|
||||
using sample_t = Particle::Bank (*)(uint64_t* seed);
|
||||
sample_t custom_source_function;
|
||||
|
||||
std::string custom_source_parameters;
|
||||
CustomSource* custom_source;
|
||||
std::string custom_source_parameters = "";
|
||||
std::unique_ptr<CustomSource> custom_source;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -374,17 +372,11 @@ void load_custom_source_library()
|
|||
// reset errors
|
||||
dlerror();
|
||||
|
||||
if (custom_source_parameters.empty()) {
|
||||
// get the function from the library
|
||||
using sample_t = Particle::Bank (*)(uint64_t* seed);
|
||||
custom_source_function = reinterpret_cast<sample_t>(dlsym(custom_source_library, "sample_source"));
|
||||
} else {
|
||||
// get the function to create the CustomSource from the library
|
||||
create_custom_source_t* create_custom_source = (create_custom_source_t*) dlsym(custom_source_library, "openmc_create_source");
|
||||
// get the function to create the CustomSource from the library
|
||||
create_custom_source_t* create_custom_source = (create_custom_source_t*) dlsym(custom_source_library, "openmc_create_source");
|
||||
|
||||
// create a pointer to an instance of the CustomSource
|
||||
custom_source = create_custom_source(custom_source_parameters.c_str());
|
||||
}
|
||||
// create a pointer to an instance of the CustomSource
|
||||
custom_source = create_custom_source(custom_source_parameters.c_str());
|
||||
|
||||
// check for any dlsym errors
|
||||
auto dlsym_error = dlerror();
|
||||
|
|
@ -401,9 +393,9 @@ void load_custom_source_library()
|
|||
|
||||
void close_custom_source_library()
|
||||
{
|
||||
if (custom_source) {
|
||||
// delete the CustomSource if it exists
|
||||
delete custom_source;
|
||||
if (custom_source.get()) {
|
||||
// Make sure the custom source is destroyed before we close it's libary.
|
||||
custom_source.reset();
|
||||
}
|
||||
|
||||
#ifdef HAS_DYNAMIC_LINKING
|
||||
|
|
@ -416,12 +408,8 @@ void close_custom_source_library()
|
|||
|
||||
Particle::Bank sample_custom_source_library(uint64_t* seed)
|
||||
{
|
||||
if (custom_source_parameters.empty()) {
|
||||
return custom_source_function(seed);
|
||||
} else {
|
||||
// sample from the instance of the CustomSource
|
||||
return custom_source->sample_source(seed);
|
||||
}
|
||||
// sample from the instance of the CustomSource
|
||||
return custom_source->sample_source(seed);
|
||||
}
|
||||
|
||||
void fill_source_bank_custom_source()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
// you must have external C linkage here otherwise
|
||||
// dlopen will not find the file
|
||||
extern "C" openmc::Particle::Bank sample_source(uint64_t *seed) {
|
||||
class Source : openmc::CustomSource
|
||||
{
|
||||
openmc::Particle::Bank sample_source(uint64_t *seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
|
|
@ -20,4 +23,13 @@ extern "C" openmc::Particle::Bank sample_source(uint64_t *seed) {
|
|||
particle.E = 14.08e6;
|
||||
particle.delayed_group = 0;
|
||||
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()
|
||||
{
|
||||
return std::unique_ptr<Source> (new Source());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,5 +19,5 @@
|
|||
<particles>1000</particles>
|
||||
<batches>10</batches>
|
||||
<inactive>0</inactive>
|
||||
<source library="build/libparameterized_source.so" parameters="energy=1e3" strength="1.0" />
|
||||
<source library="build/libsource.so" parameters="1e3" strength="1.0" />
|
||||
</settings>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
class ParameterizedSource : public openmc::CustomSource {
|
||||
class Source : public openmc::CustomSource
|
||||
{
|
||||
public:
|
||||
double energy;
|
||||
|
||||
ParameterizedSource(double energy) {
|
||||
Source(double energy)
|
||||
{
|
||||
this->energy = energy;
|
||||
}
|
||||
|
||||
// Samples from an instance of this class.
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed) {
|
||||
openmc::Particle::Bank sample_source(uint64_t* seed)
|
||||
{
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
|
|
@ -28,8 +31,10 @@ class ParameterizedSource : public openmc::CustomSource {
|
|||
}
|
||||
};
|
||||
|
||||
// you must have external C linkage here otherwise
|
||||
// dlopen will not find the file
|
||||
extern "C" ParameterizedSource* openmc_create_source(const char* parameter) {
|
||||
return new ParameterizedSource(atof(parameter));
|
||||
// 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(const char* parameter)
|
||||
{
|
||||
return std::unique_ptr<Source> (new Source(atof(parameter)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ def compile_source(request):
|
|||
f.write(textwrap.dedent("""
|
||||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
||||
project(openmc_sources CXX)
|
||||
add_library(parameterized_source SHARED parameterized_source_sampling.cpp)
|
||||
add_library(source SHARED parameterized_source_sampling.cpp)
|
||||
find_package(OpenMC REQUIRED HINTS {})
|
||||
target_link_libraries(parameterized_source OpenMC::libopenmc)
|
||||
target_link_libraries(source OpenMC::libopenmc)
|
||||
""".format(openmc_dir)))
|
||||
|
||||
# Create temporary build directory and change to there
|
||||
|
|
@ -63,8 +63,8 @@ def model():
|
|||
|
||||
# custom source from shared library
|
||||
source = openmc.Source()
|
||||
source.library = 'build/libparameterized_source.so'
|
||||
source.parameters = 'energy=1e3'
|
||||
source.library = 'build/libsource.so'
|
||||
source.parameters = '1e3'
|
||||
model.settings.source = source
|
||||
|
||||
return model
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue