Skip to content

Commit 4943fa3

Browse files
paulromanoGuySten
andauthored
Avoid negative heating values during pair production and bremsstrahlung (#3426)
Co-authored-by: GuySten <guyste@post.bgu.ac.il>
1 parent dadc4fe commit 4943fa3

7 files changed

Lines changed: 88 additions & 32 deletions

File tree

docs/source/methods/energy_deposition.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,17 @@ interactions, the energy-balance KERMA coefficient is
4747
4848
where :math:`\bar{E}_{i, r, n}` is the average energy of secondary neutrons and
4949
:math:`\bar{E}_{i, r, \gamma}` is the average energy of secondary photons. For
50-
photon and charged particle interactions, the :math:`Q` value is zero and thus
51-
the KERMA coefficient is
50+
photon and charged particle interactions the KERMA coefficient is
5251

5352
.. math::
5453
:label: energy-balance-photon
5554
56-
k_{i, r}(E) = \left(E - \sum\limits_x \bar{E}_{i, r, x}
55+
k_{i, r}(E) = \left(E + Q_{i, r} - \sum\limits_x \bar{E}_{i, r, x}
5756
\right)\sigma_{i, r}(E).
5857
58+
where the :math:`Q` value is zero for all interactions except for pair
59+
production and positron annihilation.
60+
5961
-------
6062
Fission
6163
-------

include/openmc/particle_data.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,8 @@ class ParticleData : public GeometryState {
573573
bool& fission() { return fission_; } // true if implicit fission
574574
int& event_nuclide() { return event_nuclide_; } // index of collision nuclide
575575
const int& event_nuclide() const { return event_nuclide_; }
576-
int& event_mt() { return event_mt_; } // MT number of collision
576+
int& event_mt() { return event_mt_; } // MT number of collision
577+
const int& event_mt() const { return event_mt_; }
577578
int& delayed_group() { return delayed_group_; } // delayed group
578579
const int& parent_nuclide() const { return parent_nuclide_; }
579580
int& parent_nuclide() { return parent_nuclide_; } // Parent nuclide

src/bremsstrahlung.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost)
112112
std::pow(a * (c - c_l) / (std::exp(w_l) * p_l) + 1.0, 1.0 / a);
113113

114114
if (w > settings::energy_cutoff[photon]) {
115+
// If the energy of the secondary photon is larger than the remaining
116+
// energy of the primary particle, adjust it to the remaining energy
117+
if (*E_lost + w > p.E()) {
118+
w = p.E() - *E_lost;
119+
}
120+
115121
// Create secondary photon
116122
p.create_secondary(p.wgt(), p.u(), w, ParticleType::photon);
117123
*E_lost += w;

src/tallies/tally_scoring.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,20 @@ double score_neutron_heating(const Particle& p, const Tally& tally, double flux,
325325
return score;
326326
}
327327

328+
//! Helper function to obtain reaction Q value for photons and charged particles
329+
double get_reaction_q_value(const Particle& p)
330+
{
331+
if (p.type() == ParticleType::photon && p.event_mt() == PAIR_PROD) {
332+
// pair production
333+
return -2 * MASS_ELECTRON_EV;
334+
} else if (p.type() == ParticleType::positron) {
335+
// positron annihilation
336+
return 2 * MASS_ELECTRON_EV;
337+
} else {
338+
return 0.0;
339+
}
340+
}
341+
328342
//! Helper function to obtain particle heating [eV]
329343

330344
double score_particle_heating(const Particle& p, const Tally& tally,
@@ -335,14 +349,17 @@ double score_particle_heating(const Particle& p, const Tally& tally,
335349
p, tally, flux, rxn_bin, i_nuclide, atom_density);
336350
if (i_nuclide == -1 || i_nuclide == p.event_nuclide() ||
337351
p.event_nuclide() == -1) {
352+
// For pair production and positron annihilation, we need to account for the
353+
// reaction Q value
354+
double Q = get_reaction_q_value(p);
355+
338356
// Get the pre-collision energy of the particle.
339357
auto E = p.E_last();
340-
// The energy deposited is the difference between the pre-collision
341-
// and post-collision energy...
342-
double score = E - p.E();
343-
// ...less the energy of any secondary particles since they will be
344-
// transported individually later
345-
score -= p.bank_second_E();
358+
359+
// The energy deposited is the sum of the incident energy and the reaction
360+
// Q-value less the energy of any outgoing particles
361+
double score = E + Q - p.E() - p.bank_second_E();
362+
346363
score *= p.wgt_last();
347364

348365
// if no event_nuclide (charged particle) scale energy deposition by

tests/regression_tests/photon_production/results_true.dat

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ tally 3:
5555
1.846062E-07
5656
2.297000E-01
5757
5.276209E-02
58-
7.055982E+03
59-
4.978688E+07
58+
4.196651E+00
59+
1.761188E+01
6060
0.000000E+00
6161
0.000000E+00
6262
2.297000E-01
6363
5.276209E-02
64-
7.055982E+03
65-
4.978688E+07
64+
4.196651E+00
65+
1.761188E+01
6666
0.000000E+00
6767
0.000000E+00
6868
0.000000E+00
@@ -79,14 +79,14 @@ tally 3:
7979
0.000000E+00
8080
0.000000E+00
8181
0.000000E+00
82-
7.692488E+03
83-
5.917437E+07
82+
1.474427E+04
83+
2.173936E+08
8484
0.000000E+00
8585
0.000000E+00
8686
0.000000E+00
8787
0.000000E+00
88-
7.692488E+03
89-
5.917437E+07
88+
1.474427E+04
89+
2.173936E+08
9090
0.000000E+00
9191
0.000000E+00
9292
tally 4:
@@ -104,14 +104,14 @@ tally 4:
104104
0.000000E+00
105105
2.297000E-01
106106
5.276209E-02
107-
7.055982E+03
108-
4.978688E+07
107+
4.196651E+00
108+
1.761188E+01
109109
0.000000E+00
110110
0.000000E+00
111111
2.297000E-01
112112
5.276209E-02
113-
7.055982E+03
114-
4.978688E+07
113+
4.196651E+00
114+
1.761188E+01
115115
0.000000E+00
116116
0.000000E+00
117117
0.000000E+00
@@ -134,7 +134,7 @@ tally 4:
134134
0.000000E+00
135135
0.000000E+00
136136
0.000000E+00
137-
7.692488E+03
138-
5.917437E+07
137+
1.474427E+04
138+
2.173936E+08
139139
0.000000E+00
140140
0.000000E+00

tests/regression_tests/photon_production_fission/results_true.dat

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ tally 2:
3232
0.000000E+00
3333
0.000000E+00
3434
0.000000E+00
35-
2.479234E+06
36-
2.052367E+12
35+
1.675918E+05
36+
9.365733E+09
3737
0.000000E+00
3838
0.000000E+00
3939
0.000000E+00
4040
0.000000E+00
41-
2.479234E+06
42-
2.052367E+12
41+
1.675918E+05
42+
9.365733E+09
4343
0.000000E+00
4444
0.000000E+00
4545
tally 3:
@@ -57,13 +57,13 @@ tally 3:
5757
0.000000E+00
5858
0.000000E+00
5959
0.000000E+00
60-
2.479234E+06
61-
2.052367E+12
60+
1.675918E+05
61+
9.365733E+09
6262
0.000000E+00
6363
0.000000E+00
6464
0.000000E+00
6565
0.000000E+00
66-
2.479234E+06
67-
2.052367E+12
66+
1.675918E+05
67+
9.365733E+09
6868
0.000000E+00
6969
0.000000E+00
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import openmc
2+
3+
4+
def test_negative_positron_heating():
5+
m = openmc.Material()
6+
m.add_element('Li', 1.0)
7+
m.set_density('g/cm3', 10.0)
8+
9+
surf = openmc.Sphere(r=100.0, boundary_type='reflective')
10+
cell = openmc.Cell(fill=m, region=-surf)
11+
model = openmc.Model()
12+
model.geometry = openmc.Geometry([cell])
13+
model.settings.run_mode = 'fixed source'
14+
model.settings.source = openmc.IndependentSource(
15+
space=openmc.stats.Point(),
16+
energy=openmc.stats.Discrete([5.0e6], [1.0]),
17+
particle='photon',
18+
)
19+
model.settings.particles = 7
20+
model.settings.batches = 1
21+
model.settings.electron_treatment = 'led'
22+
model.settings.seed = 513836
23+
24+
tally = openmc.Tally()
25+
tally.filters = [openmc.ParticleFilter(['photon', 'electron', 'positron'])]
26+
tally.scores = ['heating']
27+
model.tallies = openmc.Tallies([tally])
28+
model.run(apply_tally_results=True)
29+
30+
assert (tally.mean >= 0.0).all(), "Negative heating detected"

0 commit comments

Comments
 (0)