Merge pull request #1462 from paulromano/ttb-heating-fix

Consistent treatment of energy deposition for photon-electron calculations
This commit is contained in:
Amanda Lund 2020-01-28 17:38:45 -06:00 committed by GitHub
commit fbbbe8f95b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 177 additions and 267 deletions

View file

@ -22,9 +22,9 @@ from .function import Tabulated1D
# Constants
MASS_ELECTRON_EV = 0.5109989461e6 # Electron mass energy
PLANCK_C = 1.2398419739062977e4 # Planck's constant times c in eV-Angstroms
FINE_STRUCTURE = 137.035999139 # Inverse fine structure constant
MASS_ELECTRON_EV = 0.5109989461e6 # Electron mass energy
PLANCK_C = 1.2398419739062977e4 # Planck's constant times c in eV-Angstroms
FINE_STRUCTURE = 137.035999139 # Inverse fine structure constant
CM_PER_ANGSTROM = 1.0e-8
# classical electron radius in cm
R0 = CM_PER_ANGSTROM * PLANCK_C / (2.0 * pi * FINE_STRUCTURE * MASS_ELECTRON_EV)
@ -33,7 +33,7 @@ R0 = CM_PER_ANGSTROM * PLANCK_C / (2.0 * pi * FINE_STRUCTURE * MASS_ELECTRON_EV)
_SUBSHELLS = [None, 'K', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5',
'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2', 'O3',
'O4', 'O5', 'O6', 'O7', 'O8', 'O9', 'P1', 'P2', 'P3', 'P4',
'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11','Q1', 'Q2', 'Q3']
'P5', 'P6', 'P7', 'P8', 'P9', 'P10', 'P11', 'Q1', 'Q2', 'Q3']
_REACTION_NAME = {
501: ('Total photon interaction', 'total'),
@ -391,49 +391,6 @@ class AtomicRelaxation(EqualityMixin):
_SUBSHELLS, range(len(_SUBSHELLS)))
group.create_dataset('transitions', data=df.values.astype(float))
def energy_fluorescence(self, shell):
"""Compute expected energy of fluorescent photons for the shell
Parameters
----------
shell : str
The subshell to compute
Returns
-------
float
Energy of fluorescent photons
"""
if shell not in self.binding_energy:
raise KeyError('Invalid shell {}.'.format(shell))
if shell in self._e_fluorescence:
# Already computed
return self._e_fluorescence[shell]
e = 0.0
if shell not in self.transitions or self.transitions[shell].empty:
e = self.binding_energy[shell]
else:
df = self.transitions[shell]
for primary, secondary, energy, prob in df.itertuples(index=False):
e_row = 0.0
if secondary is None:
# Fluorescent photon release in radiative transition
e_row += energy
else:
# Fill the hole left by auger electron
e_row += self.energy_fluorescence(secondary)
# Fill the photoelectron hole
e_row += self.energy_fluorescence(primary)
# Expected fluorescent photon energy
e += e_row * prob
self._e_fluorescence[shell] = e
return e
class IncidentPhoton(EqualityMixin):
r"""Photon interaction data.
@ -699,9 +656,6 @@ class IncidentPhoton(EqualityMixin):
# Add bremsstrahlung DCS data
data._add_bremsstrahlung()
# Add heating cross sections
data._compute_heating()
return data
@classmethod
@ -917,10 +871,10 @@ class IncidentPhoton(EqualityMixin):
for j in range(k):
# Cubic spline interpolation in log energy and linear DCS
cs = CubicSpline(logx, y[:,j])
cs = CubicSpline(logx, y[:, j])
# Get scaled DCS values (millibarns) on new energy grid
dcs[:,j] = cs(log_energy)
dcs[:, j] = cs(log_energy)
_BREMSSTRAHLUNG[i]['dcs'] = dcs
@ -929,83 +883,6 @@ class IncidentPhoton(EqualityMixin):
self.bremsstrahlung['photon_energy'] = _BREMSSTRAHLUNG['photon_energy']
self.bremsstrahlung.update(_BREMSSTRAHLUNG[self.atomic_number])
def _compute_heating(self):
r"""Compute heating cross sections (KERMA)
Photon energy is deposited as energy loss in three reactions:
incoherent scattering, pair production and photoelectric effect.
The point-wise heating cross section is calculated as:
.. math::
\begin{aligned}
\sigma_{Hx}(E) &= (E - \overline{E}_x(E)) \cdot \sigma_x(E), x \in \left\{I, PP, PE \right\} \\
\overline{E}_I(E) &= \frac {\int E' \sigma_I (E,E',\mu) d\mu} {\int \sigma_I (E,E',\mu) d\mu} \\
\overline{E}_{PP} &= 2 m_e c^2 = 1.022 \times 10^6 eV \\
\overline{E}_{PE} &= E(\text{fluorescent photons})
\end{aligned}
The differential cross section representation for incoherent
scattering can be found in the theory manual.
"""
# Determine a union energy grid
energy = np.array([])
for mt in (504, 515, 517, 522):
if mt in self:
energy = np.union1d(energy, self[mt].xs.x)
heating_xs = np.zeros_like(energy)
# Incoherent scattering
if 504 in self:
rx = self[504]
def dsigma_dmu(mu, E):
k = E / MASS_ELECTRON_EV
krat = 1.0 / (1.0 + k * (1.0 - mu))
x = E * sqrt(0.5 * (1.0 - mu)) / PLANCK_C
return pi * R0*R0 * krat*krat * (krat + 1/krat +
mu*mu - 1.0) * rx.scattering_factor(x)
def eout_dsigma_dmu(mu, E):
Eout = E / (1.0 + E / MASS_ELECTRON_EV * (1.0 - mu))
return Eout * dsigma_dmu(mu, E)
def eout_average(E):
integral_sigma = quad(dsigma_dmu, -1.0, 1.0,
args=(E,), epsabs=0.0, epsrel=1e-3)[0]
integral_sigma_e = quad(eout_dsigma_dmu, -1.0, 1.0,
args=(E,), epsabs=0.0, epsrel=1e-3)[0]
return integral_sigma_e / integral_sigma
e_out = np.vectorize(eout_average)(energy)
heating_xs += (energy - e_out) * rx.xs(energy)
# Pair production, electron field
if 515 in self:
heating_xs += (energy - 2*MASS_ELECTRON_EV)*self[515].xs(energy)
# Pair production, nuclear field
if 517 in self:
heating_xs += (energy - 2*MASS_ELECTRON_EV)*self[517].xs(energy)
# Photoelectric effect
if 522 in self:
# Account for fluorescent photons
for mt, rx in self.reactions.items():
if mt >= 534 and mt <= 572:
shell = _REACTION_NAME[mt][1]
relax_data = self.atomic_relaxation
if relax_data is not None:
e_f = relax_data.energy_fluorescence(shell)
else:
e_f = 0.0
heating_xs += (energy - e_f) * rx.xs(energy)
heat_rx = PhotonReaction(525)
heat_rx.xs = Tabulated1D(energy, heating_xs, [energy.size], [5])
self.reactions[525] = heat_rx
class PhotonReaction(EqualityMixin):
"""Photon-induced reaction

View file

@ -1,6 +1,6 @@
#include "openmc/output.h"
#include <algorithm> // for std::transform
#include <algorithm> // for transform, max
#include <cstring> // for strlen
#include <ctime> // for time, localtime
#include <iomanip> // for setw, setprecision, put_time
@ -527,8 +527,8 @@ std::pair<double, double>
mean_stdev(const double* x, int n)
{
double mean = x[static_cast<int>(TallyResult::SUM)] / n;
double stdev = n > 1 ? std::sqrt((x[static_cast<int>(TallyResult::SUM_SQ)]/n
- mean*mean)/(n - 1)) : 0.0;
double stdev = n > 1 ? std::sqrt(std::max(0.0, (
x[static_cast<int>(TallyResult::SUM_SQ)]/n - mean*mean)/(n - 1))) : 0.0;
return {mean, stdev};
}

View file

@ -363,15 +363,6 @@ Tally::Tally(pugi::xml_node node)
break;
}
}
} else {
const auto& f = model::tally_filters[particle_filter_index].get();
auto pf = dynamic_cast<ParticleFilter*>(f);
for (auto p : pf->particles()) {
if (p == Particle::Type::electron ||
p == Particle::Type::positron) {
estimator_ = TallyEstimator::ANALOG;
}
}
}
} else {
if (particle_filter_index >= 0) {
@ -440,9 +431,9 @@ Tally::Tally(pugi::xml_node node)
estimator_ = TallyEstimator::ANALOG;
} else if (est == "tracklength" || est == "track-length"
|| est == "pathlength" || est == "path-length") {
// If the estimator was set to an analog estimator, this means the
// tally needs post-collision information
if (estimator_ == TallyEstimator::ANALOG) {
// If the estimator was set to an analog/collision estimator, this means
// the tally needs post-collision information
if (estimator_ == TallyEstimator::ANALOG || estimator_ == TallyEstimator::COLLISION) {
throw std::runtime_error{"Cannot use track-length estimator for tally "
+ std::to_string(id_)};
}
@ -654,6 +645,10 @@ Tally::set_scores(const std::vector<std::string>& scores)
fatal_error("Cannot tally currents without surface type filters");
}
break;
case HEATING:
if (settings::photon_transport) estimator_ = TallyEstimator::COLLISION;
break;
}
scores_.push_back(score);

View file

@ -158,16 +158,18 @@ score_fission_delayed_dg(int i_tally, int d_bin, double score, int score_index,
// Determine the filter scoring index
auto filter_index = 0;
double filter_weight = 1.;
for (auto i = 0; i < tally.filters().size(); ++i) {
auto i_filt = tally.filters(i);
auto& match {filter_matches[i_filt]};
auto i_bin = match.i_bin_;
filter_index += match.bins_[i_bin] * tally.strides(i);
filter_weight *= match.weights_[i_bin];
}
// Update the tally result
#pragma omp atomic
tally.results_(filter_index, score_index, TallyResult::VALUE) += score;
tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight;
// Reset the original delayed group bin
dg_match.bins_[i_bin] = original_bin;
@ -384,18 +386,19 @@ score_fission_eout(Particle* p, int i_tally, int i_score, int score_bin)
|| (score_bin == SCORE_PROMPT_NU_FISSION && g == 0)) {
// Find the filter scoring index for this filter combination
//TODO: should this include a weight?
int filter_index = 0;
double filter_weight = 1.0;
for (auto j = 0; j < tally.filters().size(); ++j) {
auto i_filt = tally.filters(j);
auto& match {p->filter_matches_[i_filt]};
auto i_bin = match.i_bin_;
filter_index += match.bins_[i_bin] * tally.strides(j);
filter_weight *= match.weights_[i_bin];
}
// Update tally results
#pragma omp atomic
tally.results_(filter_index, i_score, TallyResult::VALUE) += score;
tally.results_(filter_index, i_score, TallyResult::VALUE) += score*filter_weight;
} else if (score_bin == SCORE_DELAYED_NU_FISSION && g != 0) {
@ -458,8 +461,8 @@ score_fission_eout(Particle* p, int i_tally, int i_score, int score_bin)
//! is not used for analog tallies.
void
score_general_ce(Particle* p, int i_tally, int start_index,
int filter_index, int i_nuclide, double atom_density, double flux)
score_general_ce(Particle* p, int i_tally, int start_index, int filter_index,
double filter_weight, int i_nuclide, double atom_density, double flux)
{
Tally& tally {*model::tallies[i_tally]};
@ -469,12 +472,9 @@ score_general_ce(Particle* p, int i_tally, int start_index,
for (auto i = 0; i < tally.scores_.size(); ++i) {
auto score_bin = tally.scores_[i];
auto score_index = start_index + i;
double score;
double score = 0.0;
switch (score_bin) {
case SCORE_FLUX:
if (tally.estimator_ == TallyEstimator::ANALOG) {
// All events score to a flux bin. We actually use a collision estimator
@ -514,7 +514,11 @@ score_general_ce(Particle* p, int i_tally, int start_index,
} else {
if (i_nuclide >= 0) {
score = p->neutron_xs_[i_nuclide].total * atom_density * flux;
if (p->type_ == Particle::Type::neutron) {
score = p->neutron_xs_[i_nuclide].total * atom_density * flux;
} else if (p->type_ == Particle::Type::photon) {
score = p->photon_xs_[i_nuclide].total * atom_density * flux;
}
} else {
score = p->macro_xs_.total * flux;
}
@ -1136,8 +1140,9 @@ score_general_ce(Particle* p, int i_tally, int start_index,
case SCORE_EVENTS:
// Simply count the number of scoring events
score = 1.;
break;
#pragma omp atomic
tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0;
continue;
case ELASTIC:
@ -1214,55 +1219,22 @@ score_general_ce(Particle* p, int i_tally, int start_index,
case HEATING:
score = 0.;
if (p->type_ == Particle::Type::neutron) {
score = score_neutron_heating(p, tally, flux, HEATING,
i_nuclide, atom_density);
} else if (p->type_ == Particle::Type::photon) {
if (tally.estimator_ == TallyEstimator::ANALOG) {
// Score direct energy deposition in the collision
score = E - p->E_;
// We need to substract the energy of the secondary particles since
// they will be transported individually later
for (auto i = 0; i < p->n_bank_second_; ++i) {
auto i_bank = p->secondary_bank_.size() - p->n_bank_second_ + i;
const auto& bank = p->secondary_bank_[i_bank];
if (bank.particle == Particle::Type::photon ||
bank.particle == Particle::Type::neutron) {
score -= bank.E;
} else if (bank.particle == Particle::Type::positron) {
// Annihilation of the positron will produce two new photons
score -= 2*MASS_ELECTRON_EV;
}
}
score *= p->wgt_last_ * flux;
} else {
// Calculate photon heating cross section on-the-fly
if (i_nuclide >= 0) {
// Find the element corresponding to the nuclide
auto name = data::nuclides[i_nuclide]->name_;
std::string element = to_element(name);
int i_element = data::element_map[element];
auto& heating {data::elements[i_element].heating_};
auto i_grid = p->photon_xs_[i_element].index_grid;
auto f = p->photon_xs_[i_element].interp_factor;
score = std::exp(heating(i_grid) + f * (heating(i_grid+1) -
heating(i_grid))) * atom_density * flux;
} else {
if (p->material_ != MATERIAL_VOID) {
const Material& material {*model::materials[p->material_]};
for (auto i = 0; i < material.nuclide_.size(); ++i) {
auto i_element = material.element_[i];
auto atom_density = material.atom_density_(i);
auto& heating {data::elements[i_element].heating_};
auto i_grid = p->photon_xs_[i_element].index_grid;
auto f = p->photon_xs_[i_element].interp_factor;
score += std::exp(heating(i_grid) + f * (heating(i_grid+1) -
heating(i_grid))) * atom_density * flux;
}
}
}
} else {
// The energy deposited is the difference between the pre-collision and
// post-collision energy...
score = E - p->E_;
// ...less the energy of any secondary particles since they will be
// transported individually later
const auto& bank = p->secondary_bank_;
for (auto it = bank.end() - p->n_bank_second_; it < bank.end(); ++it) {
score -= it->E;
}
score *= p->wgt_last_;
}
break;
@ -1332,7 +1304,7 @@ score_general_ce(Particle* p, int i_tally, int start_index,
// Update tally results
#pragma omp atomic
tally.results_(filter_index, score_index, TallyResult::VALUE) += score;
tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight;
}
}
@ -1342,8 +1314,8 @@ score_general_ce(Particle* p, int i_tally, int start_index,
//! argument is really just used for filter weights.
void
score_general_mg(Particle* p, int i_tally, int start_index,
int filter_index, int i_nuclide, double atom_density, double flux)
score_general_mg(Particle* p, int i_tally, int start_index, int filter_index,
double filter_weight, int i_nuclide, double atom_density, double flux)
{
auto& tally {*model::tallies[i_tally]};
@ -1984,8 +1956,9 @@ score_general_mg(Particle* p, int i_tally, int start_index,
case SCORE_EVENTS:
// Simply count the number of scoring events
score = 1.;
break;
#pragma omp atomic
tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0;
continue;
default:
@ -1994,7 +1967,7 @@ score_general_mg(Particle* p, int i_tally, int start_index,
// Update tally results
#pragma omp atomic
tally.results_(filter_index, score_index, TallyResult::VALUE) += score;
tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight;
}
}
@ -2002,7 +1975,7 @@ score_general_mg(Particle* p, int i_tally, int start_index,
void
score_all_nuclides(Particle* p, int i_tally, double flux,
int filter_index)
int filter_index, double filter_weight)
{
const Tally& tally {*model::tallies[i_tally]};
const Material& material {*model::materials[p->material_]};
@ -2015,10 +1988,10 @@ score_all_nuclides(Particle* p, int i_tally, double flux,
//TODO: consider replacing this "if" with pointers or templates
if (settings::run_CE) {
score_general_ce(p, i_tally, i_nuclide*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux);
filter_weight, i_nuclide, atom_density, flux);
} else {
score_general_mg(p, i_tally, i_nuclide*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux);
filter_weight, i_nuclide, atom_density, flux);
}
}
@ -2029,15 +2002,22 @@ score_all_nuclides(Particle* p, int i_tally, double flux,
//TODO: consider replacing this "if" with pointers or templates
if (settings::run_CE) {
score_general_ce(p, i_tally, n_nuclides*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux);
filter_weight, i_nuclide, atom_density, flux);
} else {
score_general_mg(p, i_tally, n_nuclides*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux);
filter_weight, i_nuclide, atom_density, flux);
}
}
void score_analog_tally_ce(Particle* p)
{
// Since electrons/positrons are not transported, we assign a flux of zero.
// Note that the heating score does NOT use the flux and will be non-zero for
// electrons/positrons.
double flux =
(p->type_ == Particle::Type::neutron || p->type_ == Particle::Type::photon) ?
1.0 : 0.0;
for (auto i_tally : model::active_analog_tallies) {
const Tally& tally {*model::tallies[i_tally]};
@ -2063,7 +2043,7 @@ void score_analog_tally_ce(Particle* p)
// density argument for score_general is not used for analog tallies.
if (i_nuclide == p->event_nuclide_ || i_nuclide == -1)
score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, -1., filter_weight);
filter_weight, i_nuclide, -1.0, flux);
}
} else {
@ -2072,12 +2052,12 @@ void score_analog_tally_ce(Particle* p)
// bins correspond to nuclide indices. First, tally the nuclide.
auto i = p->event_nuclide_;
score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index,
-1, -1., filter_weight);
filter_weight, -1, -1.0, flux);
// Now tally the total material.
i = tally.nuclides_.size();
score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index,
-1, -1., filter_weight);
filter_weight, -1, -1.0, flux);
}
}
@ -2122,7 +2102,7 @@ void score_analog_tally_mg(Particle* p)
}
score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, atom_density, filter_weight);
filter_weight, i_nuclide, atom_density, 1.0);
}
}
@ -2162,7 +2142,8 @@ score_tracklength_tally(Particle* p, double distance)
// Loop over nuclide bins.
if (tally.all_nuclides_) {
if (p->material_ != MATERIAL_VOID)
score_all_nuclides(p, i_tally, flux*filter_weight, filter_index);
score_all_nuclides(p, i_tally, flux*filter_weight, filter_index,
filter_weight);
} else {
for (auto i = 0; i < tally.nuclides_.size(); ++i) {
@ -2180,10 +2161,10 @@ score_tracklength_tally(Particle* p, double distance)
//TODO: consider replacing this "if" with pointers or templates
if (settings::run_CE) {
score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux*filter_weight);
filter_weight, i_nuclide, atom_density, flux);
} else {
score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux*filter_weight);
filter_weight, i_nuclide, atom_density, flux);
}
}
}
@ -2205,11 +2186,13 @@ score_tracklength_tally(Particle* p, double distance)
void score_collision_tally(Particle* p)
{
// Determine the collision estimate of the flux
double flux;
if (!settings::survival_biasing) {
flux = p->wgt_last_ / p->macro_xs_.total;
} else {
flux = (p->wgt_last_ + p->wgt_absorb_) / p->macro_xs_.total;
double flux = 0.0;
if (p->type_ == Particle::Type::neutron || p->type_ == Particle::Type::photon) {
if (!settings::survival_biasing) {
flux = p->wgt_last_ / p->macro_xs_.total;
} else {
flux = (p->wgt_last_ + p->wgt_absorb_) / p->macro_xs_.total;
}
}
for (auto i_tally : model::active_collision_tallies) {
@ -2229,7 +2212,8 @@ void score_collision_tally(Particle* p)
// Loop over nuclide bins.
if (tally.all_nuclides_) {
score_all_nuclides(p, i_tally, flux*filter_weight, filter_index);
score_all_nuclides(p, i_tally, flux*filter_weight, filter_index,
filter_weight);
} else {
for (auto i = 0; i < tally.nuclides_.size(); ++i) {
@ -2245,10 +2229,10 @@ void score_collision_tally(Particle* p)
//TODO: consider replacing this "if" with pointers or templates
if (settings::run_CE) {
score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux*filter_weight);
filter_weight, i_nuclide, atom_density, flux);
} else {
score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index,
i_nuclide, atom_density, flux*filter_weight);
filter_weight, i_nuclide, atom_density, flux);
}
}
}

View file

@ -41,7 +41,7 @@
<bins>1</bins>
</filter>
<filter id="2" type="particle">
<bins>photon</bins>
<bins>neutron photon electron positron</bins>
</filter>
<tally id="1">
<filters>1 2</filters>
@ -50,7 +50,7 @@
<tally id="2">
<filters>2</filters>
<nuclides>Al27 total</nuclides>
<scores>total heating</scores>
<scores>total</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="3">

View file

@ -1,30 +1,92 @@
tally 1:
8.601000E-01
7.397720E-01
9.403000E-01
8.841641E-01
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
tally 2:
1.819886E-01
3.311985E-02
1.960159E+05
3.842224E+10
1.249805E+00
1.562013E+00
1.249805E+00
1.562013E+00
8.281718E-01
6.858685E-01
1.960159E+05
3.842224E+10
8.281718E-01
6.858685E-01
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
tally 3:
1.799069E-01
3.236650E-02
1.945225E+05
3.783901E+10
1.248100E+00
1.557754E+00
2.024868E+06
4.100089E+12
1.248100E+00
1.557754E+00
2.024868E+06
4.100089E+12
8.242000E-01
6.793056E-01
1.945225E+05
3.783901E+10
5.827819E+03
3.396348E+07
8.242000E-01
6.793056E-01
5.827819E+03
3.396348E+07
0.000000E+00
0.000000E+00
1.834863E+05
3.366722E+10
0.000000E+00
0.000000E+00
1.834863E+05
3.366722E+10
0.000000E+00
0.000000E+00
5.938849E+03
3.526993E+07
0.000000E+00
0.000000E+00
5.938849E+03
3.526993E+07
tally 4:
1.248100E+00
1.557754E+00
2.024868E+06
4.100089E+12
1.248100E+00
1.557754E+00
2.024868E+06
4.100089E+12
2.308000E-01
5.326864E-02
1.988563E+05
3.954384E+10
5.822937E+03
3.390660E+07
8.242000E-01
6.793056E-01
1.988612E+05
3.954578E+10
5.827819E+03
3.396348E+07
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
1.834863E+05
3.366722E+10
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
5.938849E+03
3.526993E+07

View file

@ -42,13 +42,13 @@ def model():
model.settings.source = source
surface_filter = openmc.SurfaceFilter(cyl)
particle_filter = openmc.ParticleFilter('photon')
particle_filter = openmc.ParticleFilter(['neutron', 'photon', 'electron', 'positron'])
current_tally = openmc.Tally()
current_tally.filters = [surface_filter, particle_filter]
current_tally.scores = ['current']
tally_tracklength = openmc.Tally()
tally_tracklength.filters = [particle_filter]
tally_tracklength.scores = ['total', 'heating']
tally_tracklength.scores = ['total'] # heating doesn't work with tracklength
tally_tracklength.nuclides = ['Al27', 'total']
tally_tracklength.estimator = 'tracklength'
tally_collision = openmc.Tally()

View file

@ -31,7 +31,7 @@
<tally id="1">
<filters>1</filters>
<nuclides>U235 total</nuclides>
<scores>fission heating heating-local</scores>
<scores>fission heating-local</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="2">

View file

@ -3,26 +3,18 @@ k-combined:
tally 1:
2.600054E+00
2.253433E+00
4.390171E+08
6.424554E+16
0.000000E+00
0.000000E+00
2.600054E+00
2.253433E+00
4.390171E+08
6.424554E+16
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
4.764667E+07
7.568912E+14
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
4.764667E+07
7.568912E+14
0.000000E+00
0.000000E+00
tally 2:
@ -40,14 +32,14 @@ tally 2:
0.000000E+00
0.000000E+00
0.000000E+00
4.749088E+07
7.519602E+14
2.921131E+06
2.853657E+12
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
4.749088E+07
7.519602E+14
2.921131E+06
2.853657E+12
0.000000E+00
0.000000E+00
tally 3:
@ -65,13 +57,13 @@ tally 3:
0.000000E+00
0.000000E+00
0.000000E+00
4.729796E+07
7.458273E+14
2.780823E+06
2.586737E+12
0.000000E+00
0.000000E+00
0.000000E+00
0.000000E+00
4.743827E+07
7.502589E+14
2.921131E+06
2.853657E+12
0.000000E+00
0.000000E+00

View file

@ -25,7 +25,7 @@ def model():
particle_filter = openmc.ParticleFilter(['neutron', 'photon'])
tally_tracklength = openmc.Tally()
tally_tracklength.filters = [particle_filter]
tally_tracklength.scores = ['fission', 'heating', 'heating-local']
tally_tracklength.scores = ['fission', 'heating-local']
tally_tracklength.nuclides = ['U235', 'total']
tally_tracklength.estimator = 'tracklength'
tally_collision = openmc.Tally()
@ -43,6 +43,6 @@ def model():
return model
def test_photon_production(model):
def test_photon_production_fission(model):
harness = PyAPITestHarness('statepoint.5.h5', model)
harness.main()

View file

@ -1 +1 @@
67a1b19f5ee0260a5efd99e0712c5dc8c770b04bcb70aad5c47cdc67e8ea2f9148a9d122598d0f0d2bc2f2ae0222e1a78c8fed10dfb49866123a137b6c1c1264
4d9e4a6d4891d02fac2222e0c8665033f0c955ac0082e0c6851c7674a6e967721bad8b77bf0d6c243736128a77a274b4664af54ab10462416ef6c4d18e7218ca