#include "openmc/distribution_angle.h" #include // for abs, copysign #include "openmc/tensor.h" #include "openmc/endf.h" #include "openmc/hdf5_interface.h" #include "openmc/math_functions.h" #include "openmc/random_lcg.h" #include "openmc/search.h" #include "openmc/vector.h" // for vector namespace openmc { //============================================================================== // AngleDistribution implementation //============================================================================== AngleDistribution::AngleDistribution(hid_t group) { // Get incoming energies read_dataset(group, "energy", energy_); int n_energy = energy_.size(); // Get outgoing energy distribution data vector offsets; vector interp; hid_t dset = open_dataset(group, "mu"); read_attribute(dset, "offsets", offsets); read_attribute(dset, "interpolation", interp); tensor::Tensor temp; read_dataset(dset, temp); close_dataset(dset); for (int i = 0; i < n_energy; ++i) { // Determine number of outgoing energies int j = offsets[i]; int n; if (i < n_energy - 1) { n = offsets[i + 1] - j; } else { n = temp.shape(1) - j; } // Create and initialize tabular distribution tensor::View xs = temp.slice(0, tensor::range(j, j + n)); tensor::View ps = temp.slice(1, tensor::range(j, j + n)); tensor::View cs = temp.slice(2, tensor::range(j, j + n)); vector x {xs.begin(), xs.end()}; vector p {ps.begin(), ps.end()}; vector c {cs.begin(), cs.end()}; // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later // time, we can remove the CDF values from the HDF5 library and // reconstruct them using the PDF Tabular* mudist = new Tabular {x.data(), p.data(), n, int2interp(interp[i]), c.data()}; distribution_.emplace_back(mudist); } } double AngleDistribution::sample(double E, uint64_t* seed) const { // Find energy bin and calculate interpolation factor int i; double r; get_energy_index(energy_, E, i, r); // Sample between the ith and (i+1)th bin if (r > prn(seed)) ++i; // Sample i-th distribution double mu = distribution_[i]->sample(seed).first; // Make sure mu is in range [-1,1] and return if (std::abs(mu) > 1.0) mu = std::copysign(1.0, mu); return mu; } double AngleDistribution::evaluate(double E, double mu) const { // Find energy bin and calculate interpolation factor int i; double r; get_energy_index(energy_, E, i, r); return r * distribution_[i + 1]->evaluate(mu) + (1.0 - r) * distribution_[i]->evaluate(mu); } } // namespace openmc