mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 05:35:49 -04:00
Merge pull request #2215 from pshriwise/eff-log
Additional interpolation types for EnergyFunctionFilter
This commit is contained in:
commit
e535d17ae0
9 changed files with 394 additions and 20 deletions
|
|
@ -80,7 +80,7 @@ The current version of the statepoint file format is 17.0.
|
|||
dimension.
|
||||
- **Unstructured Mesh Only:**
|
||||
- **filename** (*char[]*) -- Name of the mesh file.
|
||||
- **library** (*char[]*) -- Mesh library used to represent the
|
||||
- **library** (*char[]*) -- Mesh library used to represent the
|
||||
mesh ("moab" or "libmesh").
|
||||
- **length_multiplier** (*double*) Scaling factor applied to the mesh.
|
||||
- **volumes** (*double[]*) -- Volume of each mesh cell.
|
||||
|
|
@ -109,6 +109,9 @@ The current version of the statepoint file format is 17.0.
|
|||
- **y** (*double[]*) -- Interpolant values for energyfunction
|
||||
interpolation. Only used for 'energyfunction' filters.
|
||||
|
||||
:Attributes: - **interpolation** (*int*) -- Interpolation type. Only used for
|
||||
'energyfunction' filters.
|
||||
|
||||
**/tallies/derivatives/derivative <id>/**
|
||||
|
||||
:Datasets: - **independent variable** (*char[]*) -- Independent variable of
|
||||
|
|
|
|||
|
|
@ -318,7 +318,11 @@ enum class Interpolation {
|
|||
lin_lin = 2,
|
||||
lin_log = 3,
|
||||
log_lin = 4,
|
||||
log_log = 5
|
||||
log_log = 5,
|
||||
// skip 6 b/c ENDF-6 reserves this value for
|
||||
// "special one-dimensional interpolation law"
|
||||
quadratic = 7,
|
||||
cubic = 8
|
||||
};
|
||||
|
||||
enum class RunMode {
|
||||
|
|
|
|||
95
include/openmc/interpolate.h
Normal file
95
include/openmc/interpolate.h
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#ifndef OPENMC_INTERPOLATE_H
|
||||
#define OPENMC_INTERPOLATE_H
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "openmc/search.h"
|
||||
|
||||
namespace openmc {
|
||||
|
||||
inline double interpolate_lin_lin(
|
||||
double x0, double x1, double y0, double y1, double x)
|
||||
{
|
||||
return y0 + (x - x0) / (x1 - x0) * (y1 - y0);
|
||||
}
|
||||
|
||||
inline double interpolate_lin_log(
|
||||
double x0, double x1, double y0, double y1, double x)
|
||||
{
|
||||
return y0 + std::log(x / x0) / std::log(x1 / x0) * (y1 - y0);
|
||||
}
|
||||
|
||||
inline double interpolate_log_lin(
|
||||
double x0, double x1, double y0, double y1, double x)
|
||||
{
|
||||
return y0 * std::exp((x - x0) / (x1 - x0) * std::log(y1 / y0));
|
||||
}
|
||||
|
||||
inline double interpolate_log_log(
|
||||
double x0, double x1, double y0, double y1, double x)
|
||||
{
|
||||
double f = std::log(x / x0) / std::log(x1 / x0);
|
||||
return y0 * std::exp(f * std::log(y1 / y0));
|
||||
}
|
||||
|
||||
inline double interpolate_lagrangian(gsl::span<const double> xs,
|
||||
gsl::span<const double> ys, int idx, double x, int order)
|
||||
{
|
||||
double output {0.0};
|
||||
|
||||
for (int i = 0; i < order + 1; i++) {
|
||||
double numerator {1.0};
|
||||
double denominator {1.0};
|
||||
for (int j = 0; j < order + 1; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
numerator *= (x - xs[idx + j]);
|
||||
denominator *= (xs[idx + i] - xs[idx + j]);
|
||||
}
|
||||
output += (numerator / denominator) * ys[i];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
double interpolate(gsl::span<const double> xs, gsl::span<const double> ys,
|
||||
double x, Interpolation i = Interpolation::lin_lin)
|
||||
{
|
||||
int idx = lower_bound_index(xs.begin(), xs.end(), x);
|
||||
|
||||
if (idx == xs.size())
|
||||
idx--;
|
||||
|
||||
switch (i) {
|
||||
case Interpolation::histogram:
|
||||
return ys[idx];
|
||||
case Interpolation::lin_lin:
|
||||
return interpolate_lin_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x);
|
||||
case Interpolation::log_log:
|
||||
return interpolate_log_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x);
|
||||
case Interpolation::lin_log:
|
||||
return interpolate_lin_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x);
|
||||
case Interpolation::log_lin:
|
||||
return interpolate_log_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x);
|
||||
case Interpolation::quadratic:
|
||||
// move back one point if x is in the last interval of the x-grid
|
||||
if (idx == xs.size() - 2 && idx > 0)
|
||||
idx--;
|
||||
return interpolate_lagrangian(xs, ys, idx, x, 2);
|
||||
case Interpolation::cubic:
|
||||
// if x is not in the first interval of the x-grid, move back one
|
||||
if (idx > 0)
|
||||
idx--;
|
||||
// if the index was the last interval of the x-grid, move it back one more
|
||||
if (idx == xs.size() - 3)
|
||||
idx--;
|
||||
return interpolate_lagrangian(xs, ys, idx, x, 3);
|
||||
default:
|
||||
fatal_error("Unsupported interpolation");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openmc
|
||||
|
||||
#endif
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef OPENMC_TALLIES_FILTER_ENERGYFUNC_H
|
||||
#define OPENMC_TALLIES_FILTER_ENERGYFUNC_H
|
||||
|
||||
#include "openmc/constants.h"
|
||||
#include "openmc/tallies/filter.h"
|
||||
#include "openmc/vector.h"
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ public:
|
|||
|
||||
const vector<double>& energy() const { return energy_; }
|
||||
const vector<double>& y() const { return y_; }
|
||||
Interpolation interpolation_;
|
||||
void set_data(gsl::span<const double> energy, gsl::span<const double> y);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1875,6 +1875,9 @@ class EnergyFunctionFilter(Filter):
|
|||
A grid of energy values in [eV]
|
||||
y : iterable of Real
|
||||
A grid of interpolant values in [eV]
|
||||
interpolation : str
|
||||
Interpolation scheme: {'histogram', 'linear-linear', 'linear-log',
|
||||
'log-linear', 'log-log', 'quadratic', 'cubic'}
|
||||
filter_id : int
|
||||
Unique identifier for the filter
|
||||
|
||||
|
|
@ -1884,6 +1887,9 @@ class EnergyFunctionFilter(Filter):
|
|||
A grid of energy values in [eV]
|
||||
y : iterable of Real
|
||||
A grid of interpolant values in [eV]
|
||||
interpolation : str
|
||||
Interpolation scheme: {'histogram', 'linear-linear', 'linear-log',
|
||||
'log-linear', 'log-log', 'quadratic', 'cubic'}
|
||||
id : int
|
||||
Unique identifier for the filter
|
||||
num_bins : Integral
|
||||
|
|
@ -1891,14 +1897,25 @@ class EnergyFunctionFilter(Filter):
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, energy, y, filter_id=None):
|
||||
# keys selected to match those in function.py where possible
|
||||
# skip 6 b/c ENDF-6 reserves this value for
|
||||
# "special one-dimensional interpolation law"
|
||||
INTERPOLATION_SCHEMES = {1: 'histogram', 2: 'linear-linear',
|
||||
3: 'linear-log', 4: 'log-linear',
|
||||
5: 'log-log', 7: 'quadratic',
|
||||
8: 'cubic'}
|
||||
|
||||
def __init__(self, energy, y, interpolation='linear-linear', filter_id=None):
|
||||
self.energy = energy
|
||||
self.y = y
|
||||
self.id = filter_id
|
||||
self.interpolation = interpolation
|
||||
|
||||
def __eq__(self, other):
|
||||
if type(self) is not type(other):
|
||||
return False
|
||||
elif not self.interpolation == other.interpolation:
|
||||
return False
|
||||
elif not all(self.energy == other.energy):
|
||||
return False
|
||||
else:
|
||||
|
|
@ -1932,12 +1949,14 @@ class EnergyFunctionFilter(Filter):
|
|||
string = type(self).__name__ + '\n'
|
||||
string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy)
|
||||
string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y)
|
||||
string += '{: <16}=\t{}\n'.format('\tInterpolation', self.interpolation)
|
||||
return hash(string)
|
||||
|
||||
def __repr__(self):
|
||||
string = type(self).__name__ + '\n'
|
||||
string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy)
|
||||
string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y)
|
||||
string += '{: <16}=\t{}\n'.format('\tInterpolation', self.interpolation)
|
||||
string += '{: <16}=\t{}\n'.format('\tID', self.id)
|
||||
return string
|
||||
|
||||
|
|
@ -1949,10 +1968,16 @@ class EnergyFunctionFilter(Filter):
|
|||
+ group['type'][()].decode() + " instead")
|
||||
|
||||
energy = group['energy'][()]
|
||||
y = group['y'][()]
|
||||
y_grp = group['y']
|
||||
y = y_grp[()]
|
||||
filter_id = int(group.name.split('/')[-1].lstrip('filter '))
|
||||
|
||||
return cls(energy, y, filter_id=filter_id)
|
||||
out = cls(energy, y, filter_id=filter_id)
|
||||
if 'interpolation' in y_grp.attrs:
|
||||
out.interpolation = \
|
||||
cls.INTERPOLATION_SCHEMES[y_grp.attrs['interpolation'][()]]
|
||||
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def from_tabulated1d(cls, tab1d):
|
||||
|
|
@ -1974,10 +1999,11 @@ class EnergyFunctionFilter(Filter):
|
|||
if tab1d.n_regions > 1:
|
||||
raise ValueError('Only Tabulated1Ds with a single interpolation '
|
||||
'region are supported')
|
||||
if tab1d.interpolation[0] != 2:
|
||||
raise ValueError('Only linear-linear Tabulated1Ds are supported')
|
||||
|
||||
return cls(tab1d.x, tab1d.y)
|
||||
interpolation_val = tab1d.interpolation[0]
|
||||
if interpolation_val not in cls.INTERPOLATION_SCHEMES.keys():
|
||||
raise ValueError('Only histogram, linear-linear, linear-log, log-linear, and '
|
||||
'log-log Tabulated1Ds are supported')
|
||||
return cls(tab1d.x, tab1d.y, cls.INTERPOLATION_SCHEMES[interpolation_val])
|
||||
|
||||
@property
|
||||
def energy(self):
|
||||
|
|
@ -1987,6 +2013,10 @@ class EnergyFunctionFilter(Filter):
|
|||
def y(self):
|
||||
return self._y
|
||||
|
||||
@property
|
||||
def interpolation(self):
|
||||
return self._interpolation
|
||||
|
||||
@property
|
||||
def bins(self):
|
||||
raise AttributeError('EnergyFunctionFilters have no bins.')
|
||||
|
|
@ -2021,6 +2051,19 @@ class EnergyFunctionFilter(Filter):
|
|||
def bins(self, bins):
|
||||
raise RuntimeError('EnergyFunctionFilters have no bins.')
|
||||
|
||||
@interpolation.setter
|
||||
def interpolation(self, val):
|
||||
cv.check_type('interpolation', val, str)
|
||||
cv.check_value('interpolation', val, self.INTERPOLATION_SCHEMES.values())
|
||||
|
||||
if val == 'quadratic' and len(self.energy) < 3:
|
||||
raise ValueError('Quadratic interpolation requires 3 or more values.')
|
||||
|
||||
if val == 'cubic' and len(self.energy) < 4:
|
||||
raise ValueError('Cubic interpolation requires 3 or more values.')
|
||||
|
||||
self._interpolation = val
|
||||
|
||||
def to_xml_element(self):
|
||||
"""Return XML Element representing the Filter.
|
||||
|
||||
|
|
@ -2040,6 +2083,9 @@ class EnergyFunctionFilter(Filter):
|
|||
subelement = ET.SubElement(element, 'y')
|
||||
subelement.text = ' '.join(str(y) for y in self.y)
|
||||
|
||||
subelement = ET.SubElement(element, 'interpolation')
|
||||
subelement.text = self.interpolation
|
||||
|
||||
return element
|
||||
|
||||
@classmethod
|
||||
|
|
@ -2047,7 +2093,10 @@ class EnergyFunctionFilter(Filter):
|
|||
filter_id = int(elem.get('id'))
|
||||
energy = [float(x) for x in get_text(elem, 'energy').split()]
|
||||
y = [float(x) for x in get_text(elem, 'y').split()]
|
||||
return cls(energy, y, filter_id=filter_id)
|
||||
out = cls(energy, y, filter_id=filter_id)
|
||||
if elem.find('interpolation') is not None:
|
||||
out.interpolation = elem.find('interpolation')
|
||||
return out
|
||||
|
||||
def can_merge(self, other):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <fmt/core.h>
|
||||
|
||||
#include "openmc/error.h"
|
||||
#include "openmc/interpolate.h"
|
||||
#include "openmc/search.h"
|
||||
#include "openmc/settings.h"
|
||||
#include "openmc/xml_interface.h"
|
||||
|
|
@ -25,6 +26,40 @@ void EnergyFunctionFilter::from_xml(pugi::xml_node node)
|
|||
|
||||
auto y = get_node_array<double>(node, "y");
|
||||
|
||||
// default to linear-linear interpolation
|
||||
interpolation_ = Interpolation::lin_lin;
|
||||
if (check_for_node(node, "interpolation")) {
|
||||
std::string interpolation = get_node_value(node, "interpolation");
|
||||
if (interpolation == "histogram") {
|
||||
interpolation_ = Interpolation::histogram;
|
||||
} else if (interpolation == "linear-linear") {
|
||||
interpolation_ = Interpolation::lin_lin;
|
||||
} else if (interpolation == "linear-log") {
|
||||
interpolation_ = Interpolation::lin_log;
|
||||
} else if (interpolation == "log-linear") {
|
||||
interpolation_ = Interpolation::log_lin;
|
||||
} else if (interpolation == "log-log") {
|
||||
interpolation_ = Interpolation::log_log;
|
||||
} else if (interpolation == "quadratic") {
|
||||
if (energy.size() < 3)
|
||||
fatal_error(
|
||||
fmt::format("Quadratic interpolation on EnergyFunctionFilter {} "
|
||||
"requires at least 3 data points.",
|
||||
id()));
|
||||
interpolation_ = Interpolation::quadratic;
|
||||
} else if (interpolation == "cubic") {
|
||||
if (energy.size() < 4)
|
||||
fatal_error(fmt::format("Cubic interpolation on EnergyFunctionFilter "
|
||||
"{} requires at least 4 data points.",
|
||||
id()));
|
||||
interpolation_ = Interpolation::cubic;
|
||||
} else {
|
||||
fatal_error(fmt::format(
|
||||
"Found invalid interpolation type '{}' on EnergyFunctionFilter {}.",
|
||||
interpolation, id()));
|
||||
}
|
||||
}
|
||||
|
||||
this->set_data(energy, y);
|
||||
}
|
||||
|
||||
|
|
@ -55,15 +90,12 @@ void EnergyFunctionFilter::get_all_bins(
|
|||
const Particle& p, TallyEstimator estimator, FilterMatch& match) const
|
||||
{
|
||||
if (p.E_last() >= energy_.front() && p.E_last() <= energy_.back()) {
|
||||
// Search for the incoming energy bin.
|
||||
auto i = lower_bound_index(energy_.begin(), energy_.end(), p.E_last());
|
||||
|
||||
// Compute the interpolation factor between the nearest bins.
|
||||
double f = (p.E_last() - energy_[i]) / (energy_[i + 1] - energy_[i]);
|
||||
double w = interpolate(energy_, y_, p.E_last(), interpolation_);
|
||||
|
||||
// Interpolate on the lin-lin grid.
|
||||
match.bins_.push_back(0);
|
||||
match.weights_.push_back((1 - f) * y_[i] + f * y_[i + 1]);
|
||||
match.weights_.push_back(w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,6 +104,9 @@ void EnergyFunctionFilter::to_statepoint(hid_t filter_group) const
|
|||
Filter::to_statepoint(filter_group);
|
||||
write_dataset(filter_group, "energy", energy_);
|
||||
write_dataset(filter_group, "y", y_);
|
||||
hid_t y_dataset = open_dataset(filter_group, "y");
|
||||
write_attribute<int>(y_dataset, "interpolation", static_cast<int>(interpolation_));
|
||||
close_dataset(y_dataset);
|
||||
}
|
||||
|
||||
std::string EnergyFunctionFilter::text_label(int bin) const
|
||||
|
|
|
|||
|
|
@ -22,6 +22,42 @@
|
|||
<filter id="1" type="energyfunction">
|
||||
<energy>1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0</energy>
|
||||
<y>0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48</y>
|
||||
<interpolation>linear-linear</interpolation>
|
||||
</filter>
|
||||
<filter id="3" type="energyfunction">
|
||||
<energy>1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0</energy>
|
||||
<y>0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48</y>
|
||||
<interpolation>log-log</interpolation>
|
||||
</filter>
|
||||
<filter id="4" type="energyfunction">
|
||||
<energy>1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0</energy>
|
||||
<y>0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48</y>
|
||||
<interpolation>linear-log</interpolation>
|
||||
</filter>
|
||||
<filter id="5" type="energyfunction">
|
||||
<energy>1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0</energy>
|
||||
<y>0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48</y>
|
||||
<interpolation>log-linear</interpolation>
|
||||
</filter>
|
||||
<filter id="6" type="energyfunction">
|
||||
<energy>0.0 5000000.0 10000000.0 15000000.0</energy>
|
||||
<y>0.2 0.7 0.7 0.2</y>
|
||||
<interpolation>linear-linear</interpolation>
|
||||
</filter>
|
||||
<filter id="7" type="energyfunction">
|
||||
<energy>0.0 5000000.0 10000000.0 15000000.0</energy>
|
||||
<y>0.2 0.7 0.7 0.2</y>
|
||||
<interpolation>quadratic</interpolation>
|
||||
</filter>
|
||||
<filter id="8" type="energyfunction">
|
||||
<energy>0.0 5000000.0 10000000.0 15000000.0</energy>
|
||||
<y>0.2 0.7 0.7 0.2</y>
|
||||
<interpolation>cubic</interpolation>
|
||||
</filter>
|
||||
<filter id="9" type="energyfunction">
|
||||
<energy>0.0 5000000.0 10000000.0 15000000.0</energy>
|
||||
<y>0.2 0.7 0.7 0.2</y>
|
||||
<interpolation>histogram</interpolation>
|
||||
</filter>
|
||||
<tally id="1">
|
||||
<nuclides>Am241</nuclides>
|
||||
|
|
@ -32,4 +68,39 @@
|
|||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="3">
|
||||
<filters>3</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="4">
|
||||
<filters>4</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="5">
|
||||
<filters>5</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="6">
|
||||
<filters>6</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="7">
|
||||
<filters>7</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="8">
|
||||
<filters>8</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
<tally id="9">
|
||||
<filters>9</filters>
|
||||
<nuclides>Am241</nuclides>
|
||||
<scores>(n,gamma)</scores>
|
||||
</tally>
|
||||
</tallies>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,10 @@
|
|||
energyfunction nuclide score mean std. dev.
|
||||
0 d2effa26cb3cf2 Am241 ((n,gamma) / (n,gamma)) 1.74e-01 6.83e-03
|
||||
0 448ee8dfd19c4f Am241 ((n,gamma) / (n,gamma)) 1.74e-01 6.83e-03
|
||||
energyfunction nuclide score mean std. dev.
|
||||
0 37e006ae6b2e74 Am241 (n,gamma) 8.16e-02 2.24e-03
|
||||
energyfunction nuclide score mean std. dev.
|
||||
0 b4e2ac84068d2d Am241 (n,gamma) 8.19e-02 2.25e-03
|
||||
energyfunction nuclide score mean std. dev.
|
||||
0 dacf88242512ea Am241 (n,gamma) 7.95e-02 2.19e-03
|
||||
energyfunction nuclide score mean std. dev.
|
||||
0 fe168c70d9e078 Am241 (n,gamma) 1.06e-01 2.96e-03
|
||||
|
|
|
|||
|
|
@ -28,20 +28,66 @@ def model():
|
|||
# Make an EnergyFunctionFilter directly from the x and y lists.
|
||||
filt1 = openmc.EnergyFunctionFilter(x, y)
|
||||
|
||||
# check interpolatoin property setter
|
||||
assert filt1.interpolation == 'linear-linear'
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
filt1.interpolation = '🥏'
|
||||
|
||||
# Also make a filter with the .from_tabulated1d constructor. Make sure
|
||||
# the filters are identical.
|
||||
tab1d = openmc.data.Tabulated1D(x, y)
|
||||
filt2 = openmc.EnergyFunctionFilter.from_tabulated1d(tab1d)
|
||||
assert filt1 == filt2, 'Error with the .from_tabulated1d constructor'
|
||||
|
||||
filt3 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt3.interpolation = 'log-log'
|
||||
|
||||
filt4 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt4.interpolation = 'linear-log'
|
||||
|
||||
filt5 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt5.interpolation = 'log-linear'
|
||||
|
||||
# define a trapezoidal function for comparison
|
||||
x = [0.0, 5e6, 1e7, 1.5e7]
|
||||
y = [0.2, 0.7, 0.7, 0.2]
|
||||
|
||||
filt6 = openmc.EnergyFunctionFilter(x, y)
|
||||
|
||||
filt7 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt7.interpolation = 'quadratic'
|
||||
|
||||
filt8 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt8.interpolation = 'cubic'
|
||||
|
||||
filt9 = openmc.EnergyFunctionFilter(x, y)
|
||||
filt9.interpolation = 'histogram'
|
||||
|
||||
filters = [filt1, filt3, filt4, filt5, filt6, filt7, filt8, filt9]
|
||||
# Make tallies
|
||||
tallies = [openmc.Tally(), openmc.Tally()]
|
||||
tallies = [openmc.Tally() for _ in range(len(filters) + 1)]
|
||||
for t in tallies:
|
||||
t.scores = ['(n,gamma)']
|
||||
t.nuclides = ['Am241']
|
||||
tallies[1].filters = [filt1]
|
||||
|
||||
for t, f in zip(tallies[1:], filters):
|
||||
t.filters = [f]
|
||||
|
||||
model.tallies.extend(tallies)
|
||||
|
||||
interpolation_vals = \
|
||||
list(openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES.keys())
|
||||
for i_val in interpolation_vals:
|
||||
# breakpoint here is fake and unused
|
||||
t1d = openmc.data.Tabulated1D(x,
|
||||
y,
|
||||
breakpoints=[1],
|
||||
interpolation=[i_val])
|
||||
f = openmc.EnergyFunctionFilter.from_tabulated1d(t1d)
|
||||
assert f.interpolation == \
|
||||
openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES[i_val]
|
||||
|
||||
return model
|
||||
|
||||
|
||||
|
|
@ -50,13 +96,74 @@ class FilterEnergyFunHarness(PyAPITestHarness):
|
|||
# Read the statepoint file.
|
||||
sp = openmc.StatePoint(self._sp_name)
|
||||
|
||||
dataframes_string = ""
|
||||
# Use tally arithmetic to compute the branching ratio.
|
||||
br_tally = sp.tallies[2] / sp.tallies[1]
|
||||
dataframes_string += br_tally.get_pandas_dataframe().to_string() + '\n'
|
||||
|
||||
for t_id in (3, 4, 5, 6):
|
||||
ef_tally = sp.tallies[t_id]
|
||||
dataframes_string += ef_tally.get_pandas_dataframe().to_string() + '\n'
|
||||
|
||||
# Output the tally in a Pandas DataFrame.
|
||||
return br_tally.get_pandas_dataframe().to_string() + '\n'
|
||||
return dataframes_string
|
||||
|
||||
def _compare_results(self):
|
||||
super()._compare_results()
|
||||
|
||||
# Read the statepoint file.
|
||||
sp = openmc.StatePoint(self._sp_name)
|
||||
|
||||
# statepoint file round-trip checks
|
||||
|
||||
# linear-linear interpolation tally
|
||||
sp_lin_lin_tally = sp.get_tally(id=2)
|
||||
sp_lin_lin_filt = sp_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
|
||||
model_lin_lin_tally = self._model.tallies[1]
|
||||
model_lin_lin_filt = model_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
|
||||
assert sp_lin_lin_filt.interpolation == 'linear-linear'
|
||||
assert all(sp_lin_lin_filt.energy == model_lin_lin_filt.energy)
|
||||
assert all(sp_lin_lin_filt.y == model_lin_lin_filt.y)
|
||||
|
||||
# log-log interpolation tally
|
||||
sp_log_log_tally = sp.get_tally(id=3)
|
||||
sp_log_log_filt = sp_log_log_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
|
||||
model_log_log_tally = self._model.tallies[2]
|
||||
model_log_log_filt = model_log_log_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
|
||||
assert sp_log_log_filt.interpolation == 'log-log'
|
||||
assert all(sp_log_log_filt.energy == model_log_log_filt.energy)
|
||||
assert all(sp_log_log_filt.y == model_log_log_filt.y)
|
||||
|
||||
# because the values of y are monotonically increasing,
|
||||
# we expect the log-log tally to have a higher value
|
||||
assert all(sp_lin_lin_tally.mean < sp_log_log_tally.mean)
|
||||
|
||||
sp_lin_log_tally = self._model.tallies[3]
|
||||
sp_lin_log_filt = sp_lin_log_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
assert sp_lin_log_filt.interpolation == 'linear-log'
|
||||
|
||||
sp_log_lin_tally = self._model.tallies[4]
|
||||
sp_log_lin_filt = sp_log_lin_tally.find_filter(openmc.EnergyFunctionFilter)
|
||||
assert sp_log_lin_filt.interpolation == 'log-linear'
|
||||
|
||||
# check that the cubic interpolation provides a higher value
|
||||
# than linear-linear
|
||||
contrived_lin_lin_tally = sp.get_tally(id=6)
|
||||
contrived_quadratic_tally = sp.get_tally(id=7)
|
||||
contrived_cubic_tally = sp.get_tally(id=8)
|
||||
|
||||
assert all(contrived_lin_lin_tally.mean < contrived_quadratic_tally.mean)
|
||||
assert all(contrived_lin_lin_tally.mean < contrived_cubic_tally.mean)
|
||||
|
||||
# check that the histogram tally is less than the quadratic/cubic interpolations
|
||||
histogram_tally = sp.get_tally(id=9)
|
||||
assert all(histogram_tally.mean < contrived_quadratic_tally.mean)
|
||||
assert all(histogram_tally.mean < contrived_cubic_tally.mean)
|
||||
|
||||
def test_filter_energyfun(model):
|
||||
harness = FilterEnergyFunHarness('statepoint.5.h5', model)
|
||||
harness.main()
|
||||
harness.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue