mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Only instantiate custom source once
In the existing custom_source implementation, the source will only be created once. This is much more efficient than the custom serialized source, where each sampling will create a new instance of the class. As there could be many samples, this introduces an overhead, particularly if the operations to instantiate the class are not trivial. This implementation defines an abstract class, which is then used by the custom classes to allow the custom serialized class to be created based on the plugin, sampled from, and then destroyed. Update documentation and test to reflect this.
This commit is contained in:
parent
8bb10563c1
commit
9c1b318e78
6 changed files with 181 additions and 87 deletions
|
|
@ -472,9 +472,15 @@ attributes/sub-elements:
|
|||
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
|
||||
``sample_source()`` function must take as input an additional character
|
||||
array containing the serialization that OpenMC will have read from this
|
||||
attribute. If the library attribute is not provided then this attribute
|
||||
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 array of integers as an
|
||||
argument. The custom source library must also contain a ``create`` method,
|
||||
which takes a serialized form of the source (as provided to the parameters
|
||||
attribute) as an argument and returns a pointer to an instance of the custom
|
||||
source, and a ``destroy`` method, which takes a pointer to an instance of
|
||||
the custom source as an argument and deletes the memory allocated to the
|
||||
custom source. If the library attribute is not provided then this attribute
|
||||
will be ignored. More documentation on how to build serialized sources can
|
||||
be found in :ref:`serialized_custom_source`.
|
||||
|
||||
|
|
|
|||
|
|
@ -243,47 +243,92 @@ Custom Serialized Sources
|
|||
If the custom source may be used with parameters at a variety of values then it
|
||||
may be necessary to serialize the source to an appropriate format in order to
|
||||
avoid recompiling the source library for each run. This is supported by defining
|
||||
the ``source_sampling`` function with an additional parameter that receives the
|
||||
parameters used to build the source:
|
||||
a class inheriting from ``openmc::CustomSource`` that implements a
|
||||
``sample_source`` function. The class should also have logic to deserialise
|
||||
the parameters provided via the settings.xml file in the
|
||||
:attr:``openmc.Source.parameters`` attribute:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
// you must have external C linkage here
|
||||
extern "C" openmc::Particle::Bank sample_source(uint64_t* seed, const char* parameters) {
|
||||
// function to deserialize the source
|
||||
SerializedSource source = SerializedSource::from_string(parameters);
|
||||
#include <unordered_map>
|
||||
|
||||
openmc::Particle::Bank particle;
|
||||
// wgt
|
||||
particle.particle = openmc::Particle::Type::neutron;
|
||||
particle.wgt = 1.0;
|
||||
// position
|
||||
double angle = 2. * M_PI * openmc::prn(seed);
|
||||
#include "openmc/random_lcg.h"
|
||||
#include "openmc/source.h"
|
||||
#include "openmc/particle.h"
|
||||
|
||||
// get the radius from the serialized form of the source
|
||||
double radius = source.radius();
|
||||
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};
|
||||
class SerializedSource : public openmc::CustomSource {
|
||||
protected:
|
||||
double energy_;
|
||||
|
||||
// get the energy from the serialized form of the source
|
||||
particle.E = source.energy();
|
||||
particle.delayed_group = 0;
|
||||
// Protect the constructor so that the class can only be created by serialisation.
|
||||
SerializedSource(double energy) {
|
||||
energy_ = energy;
|
||||
}
|
||||
|
||||
return particle;
|
||||
}
|
||||
public:
|
||||
// Getters for the values that we want to use in sampling.
|
||||
double energy() { return energy_; }
|
||||
|
||||
The details of the serialization routine, in particular the schema of the source
|
||||
are to be defined by the implementation of the serializable source class. The
|
||||
location of the serialized representation of the source to be used must be
|
||||
provided via the :attr:`openmc.Source.parameters` attribute, along with the
|
||||
custom source library location in :attr:`openmc.Source.library`.
|
||||
// Defines a function that can create a pointer to a new instance of this class
|
||||
// by deserializing from the provided string.
|
||||
static SerializedSource* from_string(const char* parameters) {
|
||||
std::unordered_map<std::string, std::string> parameter_mapping;
|
||||
|
||||
When defining a class to be implemented via this deserialization approach, care
|
||||
must be taken to ensure that unique symbols in the resulting binary are
|
||||
discoverable when the ``sample_source`` function is loaded via ``dlsym``.
|
||||
std::stringstream ss(parameters);
|
||||
std::string parameter;
|
||||
while (std::getline(ss, parameter, ',')) {
|
||||
parameter.erase(0, parameter.find_first_not_of(' '));
|
||||
std::string key = parameter.substr(0, parameter.find_first_of('='));
|
||||
std::string value = parameter.substr(parameter.find_first_of('=') + 1, parameter.length());
|
||||
parameter_mapping[key] = value;
|
||||
}
|
||||
|
||||
return new SerializedSource(std::stod(parameter_mapping["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;
|
||||
|
||||
return particle;
|
||||
}
|
||||
};
|
||||
|
||||
The custom source library function in this case must also define a ``create``
|
||||
method and a ``destroy`` method. The ``create`` method will be used to
|
||||
generate an instance of the custom source, based on the value supplied in
|
||||
the :attr:``openmc.Source.parameters`` attribute. The ``destroy`` method
|
||||
will be used to destroy that instance once the sampling has completed. Both
|
||||
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" SerializedSource* create(const char* serialized_source) {
|
||||
return SerializedSource::from_string(serialized_source);
|
||||
}
|
||||
|
||||
// you must have external C linkage here otherwise
|
||||
// dlopen will not find the file
|
||||
extern "C" void destroy(SerializedSource* source) {
|
||||
delete source;
|
||||
}
|
||||
|
||||
As with the basic custom source functionality, the custom source library
|
||||
location must also be provided in the :attr:`openmc.Source.library`
|
||||
attribute.
|
||||
|
||||
---------------
|
||||
Shannon Entropy
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue