mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-29 06:35:48 -04:00
Source biasing capabilities (#3460)
Co-authored-by: Paul Romano <paul.k.romano@gmail.com>
This commit is contained in:
parent
37e2feb34b
commit
0486e433d2
24 changed files with 2003 additions and 252 deletions
|
|
@ -15,6 +15,17 @@
|
|||
|
||||
namespace openmc {
|
||||
|
||||
//==============================================================================
|
||||
// Helper function for computing importance weights from biased sampling
|
||||
//==============================================================================
|
||||
|
||||
//! Compute importance weights for biased sampling
|
||||
//! \param p Unnormalized original probability vector
|
||||
//! \param b Unnormalized bias probability vector
|
||||
//! \return Vector of importance weights (p_norm[i] / b_norm[i])
|
||||
vector<double> compute_importance_weights(
|
||||
const vector<double>& p, const vector<double>& b);
|
||||
|
||||
//==============================================================================
|
||||
//! Abstract class representing a univariate probability distribution
|
||||
//==============================================================================
|
||||
|
|
@ -22,11 +33,41 @@ namespace openmc {
|
|||
class Distribution {
|
||||
public:
|
||||
virtual ~Distribution() = default;
|
||||
virtual double sample(uint64_t* seed) const = 0;
|
||||
|
||||
//! Sample a value from the distribution, handling biasing automatically
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return (sampled value, importance weight)
|
||||
virtual std::pair<double, double> sample(uint64_t* seed) const;
|
||||
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
virtual double evaluate(double x) const;
|
||||
|
||||
//! Return integral of distribution
|
||||
//! \return Integral of distribution
|
||||
virtual double integral() const { return 1.0; };
|
||||
|
||||
//! Set bias distribution
|
||||
virtual void set_bias(std::unique_ptr<Distribution> bias)
|
||||
{
|
||||
bias_ = std::move(bias);
|
||||
}
|
||||
|
||||
const Distribution* bias() const { return bias_.get(); }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
virtual double sample_unbiased(uint64_t* seed) const = 0;
|
||||
|
||||
//! Read bias distribution from XML
|
||||
//! \param node XML node that may contain a bias child element
|
||||
void read_bias_from_xml(pugi::xml_node node);
|
||||
|
||||
// Biasing distribution
|
||||
unique_ptr<Distribution> bias_;
|
||||
};
|
||||
|
||||
using UPtrDist = unique_ptr<Distribution>;
|
||||
|
|
@ -50,7 +91,7 @@ public:
|
|||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
//! \return Sampled index
|
||||
size_t sample(uint64_t* seed) const;
|
||||
|
||||
// Properties
|
||||
|
|
@ -67,7 +108,7 @@ private:
|
|||
//! Normalize distribution so that probabilities sum to unity
|
||||
void normalize();
|
||||
|
||||
//! Initialize alias tables for distribution
|
||||
//! Initialize alias table for sampling
|
||||
void init_alias();
|
||||
};
|
||||
|
||||
|
|
@ -82,20 +123,30 @@ public:
|
|||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! \return (sampled value, sample weight)
|
||||
std::pair<double, double> sample(uint64_t* seed) const override;
|
||||
|
||||
double integral() const override { return di_.integral(); };
|
||||
|
||||
//! Override set_bias as no-op (bias handled in constructor)
|
||||
void set_bias(std::unique_ptr<Distribution> bias) override {}
|
||||
|
||||
// Properties
|
||||
const vector<double>& x() const { return x_; }
|
||||
const vector<double>& prob() const { return di_.prob(); }
|
||||
const vector<size_t>& alias() const { return di_.alias(); }
|
||||
const vector<double>& weight() const { return weight_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
vector<double> x_; //!< Possible outcomes
|
||||
DiscreteIndex di_; //!< discrete probability distribution of
|
||||
//!< outcome indices
|
||||
vector<double> x_; //!< Possible outcomes
|
||||
vector<double> weight_; //!< Importance weights (empty if unbiased)
|
||||
DiscreteIndex di_; //!< Discrete probability distribution of outcome indices
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -107,14 +158,20 @@ public:
|
|||
explicit Uniform(pugi::xml_node node);
|
||||
Uniform(double a, double b) : a_ {a}, b_ {b} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double a() const { return a_; }
|
||||
double b() const { return b_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
double a_; //!< Lower bound of distribution
|
||||
double b_; //!< Upper bound of distribution
|
||||
|
|
@ -131,15 +188,21 @@ public:
|
|||
: offset_ {std::pow(a, n + 1)}, span_ {std::pow(b, n + 1) - offset_},
|
||||
ninv_ {1 / (n + 1)} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double a() const { return std::pow(offset_, ninv_); }
|
||||
double b() const { return std::pow(offset_ + span_, ninv_); }
|
||||
double n() const { return 1 / ninv_ - 1; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
//! Store processed values in object to allow for faster sampling
|
||||
double offset_; //!< a^(n+1)
|
||||
|
|
@ -156,13 +219,19 @@ public:
|
|||
explicit Maxwell(pugi::xml_node node);
|
||||
Maxwell(double theta) : theta_ {theta} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double theta() const { return theta_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
double theta_; //!< Factor in exponential [eV]
|
||||
};
|
||||
|
|
@ -176,14 +245,20 @@ public:
|
|||
explicit Watt(pugi::xml_node node);
|
||||
Watt(double a, double b) : a_ {a}, b_ {b} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double a() const { return a_; }
|
||||
double b() const { return b_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
double a_; //!< Factor in exponential [eV]
|
||||
double b_; //!< Factor in square root [1/eV]
|
||||
|
|
@ -200,14 +275,20 @@ public:
|
|||
Normal(double mean_value, double std_dev)
|
||||
: mean_value_ {mean_value}, std_dev_ {std_dev} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
double mean_value() const { return mean_value_; }
|
||||
double std_dev() const { return std_dev_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
double mean_value_; //!< middle of distribution [eV]
|
||||
double std_dev_; //!< standard deviation [eV]
|
||||
|
|
@ -223,10 +304,10 @@ public:
|
|||
Tabular(const double* x, const double* p, int n, Interpolation interp,
|
||||
const double* c = nullptr);
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
// properties
|
||||
vector<double>& x() { return x_; }
|
||||
|
|
@ -235,6 +316,12 @@ public:
|
|||
Interpolation interp() const { return interp_; }
|
||||
double integral() const override { return integral_; };
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
vector<double> x_; //!< tabulated independent variable
|
||||
vector<double> p_; //!< tabulated probability density
|
||||
|
|
@ -259,13 +346,19 @@ public:
|
|||
explicit Equiprobable(pugi::xml_node node);
|
||||
Equiprobable(const double* x, int n) : x_ {x, x + n} {};
|
||||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! Evaluate probability density, f(x), at a point
|
||||
//! \param x Point to evaluate f(x)
|
||||
//! \return f(x)
|
||||
double evaluate(double x) const override;
|
||||
|
||||
const vector<double>& x() const { return x_; }
|
||||
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
vector<double> x_; //! Possible outcomes
|
||||
};
|
||||
|
|
@ -280,18 +373,25 @@ public:
|
|||
|
||||
//! Sample a value from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample(uint64_t* seed) const override;
|
||||
//! \return (sampled value, sample weight)
|
||||
std::pair<double, double> sample(uint64_t* seed) const override;
|
||||
|
||||
double integral() const override { return integral_; }
|
||||
|
||||
private:
|
||||
// Storrage for probability + distribution
|
||||
using DistPair = std::pair<double, UPtrDist>;
|
||||
//! Override set_bias as no-op (bias handled in constructor)
|
||||
void set_bias(std::unique_ptr<Distribution> bias) override {}
|
||||
|
||||
vector<DistPair>
|
||||
distribution_; //!< sub-distributions + cummulative probabilities
|
||||
double integral_; //!< integral of distribution
|
||||
protected:
|
||||
//! Sample a value (unbiased) from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled value
|
||||
double sample_unbiased(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
vector<UPtrDist> distribution_; //!< Sub-distributions
|
||||
vector<double> weight_; //!< Importance weights for component selection
|
||||
DiscreteIndex di_; //!< Discrete probability distribution of indices
|
||||
double integral_; //!< Integral of distribution
|
||||
};
|
||||
|
||||
} // namespace openmc
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ public:
|
|||
|
||||
//! Sample a direction from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Direction sampled
|
||||
virtual Direction sample(uint64_t* seed) const = 0;
|
||||
//! \return (sampled Direction, sample weight)
|
||||
virtual std::pair<Direction, double> sample(uint64_t* seed) const = 0;
|
||||
|
||||
Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction
|
||||
};
|
||||
|
|
@ -43,14 +43,28 @@ public:
|
|||
|
||||
//! Sample a direction from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Direction sampled
|
||||
Direction sample(uint64_t* seed) const override;
|
||||
//! \return (sampled Direction, sample weight)
|
||||
std::pair<Direction, double> sample(uint64_t* seed) const override;
|
||||
|
||||
//! Sample a direction and return evaluation of the PDF for biased sampling.
|
||||
//! Note that bias distributions are intended to return unit-weight samples.
|
||||
//! \param seed Pseudorandom number seed points
|
||||
//! \return (sampled Direction, value of the PDF at this Direction)
|
||||
std::pair<Direction, double> sample_as_bias(uint64_t* seed) const;
|
||||
|
||||
// Observing pointers
|
||||
Distribution* mu() const { return mu_.get(); }
|
||||
Distribution* phi() const { return phi_.get(); }
|
||||
|
||||
private:
|
||||
//! Common sampling implementation
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \param return_pdf If true, return PDF evaluation; if false, return
|
||||
//! importance weight
|
||||
//! \return (sampled Direction, weight or PDF value)
|
||||
std::pair<Direction, double> sample_impl(
|
||||
uint64_t* seed, bool return_pdf) const;
|
||||
|
||||
Direction v_ref_ {1.0, 0.0, 0.0}; //!< reference direction
|
||||
Direction w_ref_;
|
||||
UPtrDist mu_; //!< Distribution of polar angle
|
||||
|
|
@ -66,11 +80,24 @@ Direction isotropic_direction(uint64_t* seed);
|
|||
class Isotropic : public UnitSphereDistribution {
|
||||
public:
|
||||
Isotropic() {};
|
||||
explicit Isotropic(pugi::xml_node node);
|
||||
|
||||
//! Sample a direction from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled direction
|
||||
Direction sample(uint64_t* seed) const override;
|
||||
//! \return (sampled direction, sample weight)
|
||||
std::pair<Direction, double> sample(uint64_t* seed) const override;
|
||||
|
||||
// Set or get bias distribution
|
||||
void set_bias(std::unique_ptr<PolarAzimuthal> bias)
|
||||
{
|
||||
bias_ = std::move(bias);
|
||||
}
|
||||
|
||||
const PolarAzimuthal* bias() const { return bias_.get(); }
|
||||
|
||||
protected:
|
||||
// Biasing distribution
|
||||
unique_ptr<PolarAzimuthal> bias_;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -85,8 +112,8 @@ public:
|
|||
|
||||
//! Sample a direction from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled direction
|
||||
Direction sample(uint64_t* seed) const override;
|
||||
//! \return (sampled direction, sample weight)
|
||||
std::pair<Direction, double> sample(uint64_t* seed) const override;
|
||||
};
|
||||
|
||||
using UPtrAngle = unique_ptr<UnitSphereDistribution>;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ public:
|
|||
virtual ~SpatialDistribution() = default;
|
||||
|
||||
//! Sample a position from the distribution
|
||||
virtual Position sample(uint64_t* seed) const = 0;
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled (position, importance weight)
|
||||
virtual std::pair<Position, double> sample(uint64_t* seed) const = 0;
|
||||
|
||||
static unique_ptr<SpatialDistribution> create(pugi::xml_node node);
|
||||
};
|
||||
|
|
@ -34,8 +36,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
// Observer pointers
|
||||
Distribution* x() const { return x_.get(); }
|
||||
|
|
@ -58,8 +60,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
Distribution* r() const { return r_.get(); }
|
||||
Distribution* phi() const { return phi_.get(); }
|
||||
|
|
@ -83,8 +85,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
Distribution* r() const { return r_.get(); }
|
||||
Distribution* cos_theta() const { return cos_theta_.get(); }
|
||||
|
|
@ -109,8 +111,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
//! Sample the mesh for an element and position within that element
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
|
|
@ -133,8 +135,8 @@ public:
|
|||
|
||||
private:
|
||||
int32_t mesh_idx_ {C_NONE};
|
||||
DiscreteIndex elem_idx_dist_; //!< Distribution of
|
||||
//!< mesh element indices
|
||||
DiscreteIndex elem_idx_dist_; //!< Distribution of mesh element indices
|
||||
vector<double> weight_; //!< Importance weights (empty if unbiased)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -149,12 +151,13 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
std::vector<Position> point_cloud_;
|
||||
DiscreteIndex point_idx_dist_; //!< Distribution of Position indices
|
||||
vector<double> weight_; //!< Importance weights (empty if unbiased)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -167,8 +170,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
// Properties
|
||||
bool only_fissionable() const { return only_fissionable_; }
|
||||
|
|
@ -193,8 +196,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return Sampled (position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
Position r() const { return r_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -217,8 +217,8 @@ public:
|
|||
|
||||
//! Sample a position from the distribution
|
||||
//! \param seed Pseudorandom number seed pointer
|
||||
//! \return Sampled position
|
||||
Position sample(uint64_t* seed) const override;
|
||||
//! \return (sampled position, importance weight)
|
||||
std::pair<Position, double> sample(uint64_t* seed) const override;
|
||||
|
||||
private:
|
||||
int32_t mesh_index_ {C_NONE}; //!< Index in global meshes array
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue