Merge pull request #1940 from ojschumann/time-src

Time distribution for source.
This commit is contained in:
Paul Romano 2022-01-12 10:31:53 -06:00 committed by GitHub
commit 34ec14c5ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 15 deletions

View file

@ -174,10 +174,11 @@ create an instance of :class:`openmc.Source` and use it to set the
varying source strengths, :attr:`Settings.source` should be set to a list of
:class:`openmc.Source` objects.
The :class:`openmc.Source` class has three main attributes that one can set:
The :class:`openmc.Source` class has four main attributes that one can set:
:attr:`Source.space`, which defines the spatial distribution,
:attr:`Source.angle`, which defines the angular distribution, and
:attr:`Source.energy`, which defines the energy distribution.
:attr:`Source.angle`, which defines the angular distribution,
:attr:`Source.energy`, which defines the energy distribution, and
:attr:`Source.time`, which defines the time distribution.
The spatial distribution can be set equal to a sub-class of
:class:`openmc.stats.Spatial`; common choices are :class:`openmc.stats.Point` or
@ -210,14 +211,23 @@ distribution. This could be a probability mass function
specified, a Watt fission spectrum with :math:`a` = 0.988 MeV and :math:`b` =
2.249 MeV :sup:`-1` is used.
The time distribution can be set equal to any univariate probability
distribution. This could be a probability mass function
(:class:`openmc.stats.Discrete`), a uniform distribution
(:class:`openmc.stats.Uniform`), or a tabular distribution
(:class:`openmc.stats.Tabular`). By default, if no time distribution is
specified, particles are started at :math:`t=0`.
As an example, to create an isotropic, 10 MeV monoenergetic source uniformly
distributed over a cube centered at the origin with an edge length of 10 cm, one
distributed over a cube centered at the origin with an edge length of 10 cm, and
emitting a pulse of particles from 0 to 10 µs, one
would run::
source = openmc.Source()
source.space = openmc.stats.Box((-5, -5, -5), (5, 5, 5))
source.angle = openmc.stats.Isotropic()
source.energy = openmc.stats.Discrete([10.0e6], [1.0])
source.time = openmc.stats.Uniform(0, 1e-6)
settings.source = source
The :class:`openmc.Source` class also has a :attr:`Source.strength` attribute

View file

@ -42,13 +42,13 @@ public:
};
//==============================================================================
//! Source composed of independent spatial, angle, and energy distributions
//! Source composed of independent spatial, angle, energy, and time distributions
//==============================================================================
class IndependentSource : public Source {
public:
// Constructors
IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy);
IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time);
explicit IndependentSource(pugi::xml_node node);
//! Sample from the external source distribution
@ -64,6 +64,7 @@ public:
SpatialDistribution* space() const { return space_.get(); }
UnitSphereDistribution* angle() const { return angle_.get(); }
Distribution* energy() const { return energy_.get(); }
Distribution* time() const { return time_.get(); }
private:
ParticleType particle_ {ParticleType::neutron}; //!< Type of particle emitted
@ -71,6 +72,7 @@ private:
UPtrSpace space_; //!< Spatial distribution
UPtrAngle angle_; //!< Angular distribution
UPtrDist energy_; //!< Energy distribution
UPtrDist time_; //!< Time distribution
};
//==============================================================================

View file

@ -22,6 +22,8 @@ class Source:
Angular distribution of source sites
energy : openmc.stats.Univariate
Energy distribution of source sites
time : openmc.stats.Univariate
time distribution of source sites
filename : str
Source file from which sites should be sampled
library : str
@ -43,6 +45,8 @@ class Source:
Angular distribution of source sites
energy : openmc.stats.Univariate or None
Energy distribution of source sites
time : openmc.stats.Univariate or None
time distribution of source sites
file : str or None
Source file from which sites should be sampled
library : str or None
@ -56,11 +60,12 @@ class Source:
"""
def __init__(self, space=None, angle=None, energy=None, filename=None,
def __init__(self, space=None, angle=None, energy=None, time=None, filename=None,
library=None, parameters=None, strength=1.0, particle='neutron'):
self._space = None
self._angle = None
self._energy = None
self._time = None
self._file = None
self._library = None
self._parameters = None
@ -71,6 +76,8 @@ class Source:
self.angle = angle
if energy is not None:
self.energy = energy
if time is not None:
self.time = time
if filename is not None:
self.file = filename
if library is not None:
@ -104,6 +111,10 @@ class Source:
def energy(self):
return self._energy
@property
def time(self):
return self._time
@property
def strength(self):
return self._strength
@ -142,6 +153,11 @@ class Source:
cv.check_type('energy distribution', energy, Univariate)
self._energy = energy
@time.setter
def time(self, time):
cv.check_type('time distribution', time, Univariate)
self._time = time
@strength.setter
def strength(self, strength):
cv.check_type('source strength', strength, Real)
@ -178,6 +194,8 @@ class Source:
element.append(self.angle.to_xml_element())
if self.energy is not None:
element.append(self.energy.to_xml_element('energy'))
if self.time is not None:
element.append(self.time.to_xml_element('time'))
return element
@classmethod
@ -229,6 +247,10 @@ class Source:
if energy is not None:
source.energy = Univariate.from_xml_element(energy)
time = elem.find('time')
if time is not None:
source.time = Univariate.from_xml_element(time)
return source

View file

@ -459,9 +459,12 @@ void read_settings_xml()
// If no source specified, default to isotropic point source at origin with
// Watt spectrum
if (model::external_sources.empty()) {
double T[] {0.0};
double p[] {1.0};
model::external_sources.push_back(make_unique<IndependentSource>(
UPtrSpace {new SpatialPoint({0.0, 0.0, 0.0})},
UPtrAngle {new Isotropic()}, UPtrDist {new Watt(0.988e6, 2.249e-6)}));
UPtrAngle {new Isotropic()}, UPtrDist {new Watt(0.988e6, 2.249e-6)},
UPtrDist {new Discrete(T, p, 1)}));
}
// Check if we want to write out source

View file

@ -46,11 +46,12 @@ vector<unique_ptr<Source>> external_sources;
// IndependentSource implementation
//==============================================================================
IndependentSource::IndependentSource(
UPtrSpace space, UPtrAngle angle, UPtrDist energy)
: space_ {std::move(space)}, angle_ {std::move(angle)}, energy_ {
std::move(energy)}
{}
IndependentSource::IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time)
: space_{std::move(space)},
angle_{std::move(angle)},
energy_{std::move(energy)},
time_{std::move(time)}
{ }
IndependentSource::IndependentSource(pugi::xml_node node)
{
@ -140,6 +141,17 @@ IndependentSource::IndependentSource(pugi::xml_node node)
// Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
energy_ = UPtrDist {new Watt(0.988e6, 2.249e-6)};
}
// Determine external source time distribution
if (check_for_node(node, "time")) {
pugi::xml_node node_dist = node.child("time");
time_ = distribution_from_xml(node_dist);
} else {
// Default to a Constant time T=0
double T[] {0.0};
double p[] {1.0};
time_ = UPtrDist {new Discrete{T, p, 1}};
}
}
}
@ -224,6 +236,9 @@ SourceSite IndependentSource::sample(uint64_t* seed) const
break;
}
// Sample particle creation time
site.time = time_->sample(seed);
return site;
}

View file

@ -121,6 +121,7 @@
</dist>
</pair>
</energy>
<time parameters="2 5" type="uniform" />
</source>
<source strength="0.1">
<space origin="1.0 1.0 0.0" type="cylindrical">
@ -144,5 +145,6 @@
</dist>
</pair>
</energy>
<time parameters="2 5" type="uniform" />
</source>
</settings>

View file

@ -65,14 +65,16 @@ class SourceTestHarness(PyAPITestHarness):
energy3 = openmc.stats.Tabular(E, p, interpolation='histogram')
energy4 = openmc.stats.Mixture([1, 2, 3], [energy1, energy2, energy3])
time1 = openmc.stats.Uniform(2, 5)
source1 = openmc.Source(spatial1, angle1, energy1, strength=0.3)
source2 = openmc.Source(spatial2, angle2, energy2, strength=0.1)
source3 = openmc.Source(spatial3, angle3, energy3, strength=0.1)
source4 = openmc.Source(spatial4, angle3, energy3, strength=0.1)
source5 = openmc.Source(spatial5, angle3, energy3, strength=0.1)
source6 = openmc.Source(spatial5, angle3, energy4, strength=0.1)
source7 = openmc.Source(spatial6, angle3, energy4, strength=0.1)
source8 = openmc.Source(spatial7, angle3, energy4, strength=0.1)
source7 = openmc.Source(spatial6, angle3, energy4, time1, strength=0.1)
source8 = openmc.Source(spatial7, angle3, energy4, time1, strength=0.1)
settings = openmc.Settings()
settings.batches = 10