# Copyright 2019 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Energy group structures for multigroup neutronics calculations.
"""
import copy
import itertools
import math
import numpy
from armi import runLog
from armi.utils.mathematics import findNearestValue
from .const import (
FAST_FLUX_THRESHOLD_EV,
MAXIMUM_XS_LIBRARY_ENERGY,
ULTRA_FINE_GROUP_LETHARGY_WIDTH,
HIGH_ENERGY_EV,
)
[docs]def getFastFluxGroupCutoff(eGrpStruc):
"""Given a constant "fast" energy threshold, return which ARMI energy group index contains this threshold."""
gThres = -1
for g, eV in enumerate(eGrpStruc):
if eV < FAST_FLUX_THRESHOLD_EV:
gThres = g
break
dE = eGrpStruc[gThres - 1] - eGrpStruc[gThres] # eV
fastFluxFracInG = (eGrpStruc[gThres - 1] - FAST_FLUX_THRESHOLD_EV) / dE
return gThres - 1, fastFluxFracInG
def _flatten(*numbers):
result = []
for item in numbers:
if isinstance(item, int):
result.append(item)
else:
result.extend(item)
return result
def _create_anl_energies_with_group_lethargies(*group_lethargies):
anl_energy_max = MAXIMUM_XS_LIBRARY_ENERGY
en = anl_energy_max
energies = []
for ee in _flatten(*group_lethargies):
energies.append(en)
en *= math.e ** (-ee * ULTRA_FINE_GROUP_LETHARGY_WIDTH)
return energies
[docs]def getGroupStructure(name):
"""
Return descending neutron energy group upper bounds in eV for a given structure name.
Notes
-----
Copy of the group structure is return so that modifications of the energy bounds does
not propagate back to the `GROUP_STRUCTURE` dictionary.
"""
try:
return copy.copy(GROUP_STRUCTURE[name])
except KeyError as ke:
runLog.error(
'Could not find groupStructure with the name "{}".\n'
"Choose one of: {}".format(name, ", ".join(GROUP_STRUCTURE.keys()))
)
raise ke
[docs]def getGroupStructureType(neutronEnergyBoundsInEv):
"""
Return neutron energy group structure name for a given set of neutron energy group bounds in eV.
"""
neutronEnergyBoundsInEv = numpy.array(neutronEnergyBoundsInEv)
for groupStructureType in GROUP_STRUCTURE:
refNeutronEnergyBoundsInEv = numpy.array(getGroupStructure(groupStructureType))
if len(refNeutronEnergyBoundsInEv) != len(neutronEnergyBoundsInEv):
continue
if numpy.allclose(refNeutronEnergyBoundsInEv, neutronEnergyBoundsInEv, 1e-5):
return groupStructureType
raise ValueError(
"Neutron energy group structure type does not exist for the given neutron energy bounds: {}".format(
neutronEnergyBoundsInEv
)
)
GROUP_STRUCTURE = {}
"""
Energy groups for use in multigroup neutronics.
Values are the upper bound of each energy in eV from highest energy to lowest
(because neutrons typically downscatter...)
"""
GROUP_STRUCTURE["2"] = [HIGH_ENERGY_EV, 6.25e-01]
# Nuclear Reactor Engineering: Reactor Systems Engineering, Vol. 1
GROUP_STRUCTURE["4gGlasstoneSesonske"] = [HIGH_ENERGY_EV, 5.00e04, 5.00e02, 6.25e-01]
# http://serpent.vtt.fi/mediawiki/index.php/CASMO_4-group_structure
GROUP_STRUCTURE["CASMO4"] = [HIGH_ENERGY_EV, 8.21e05, 5.53e03, 6.25e-01]
GROUP_STRUCTURE["CASMO12"] = [
HIGH_ENERGY_EV,
2.23e06,
8.21e05,
5.53e03,
4.81e01,
4.00e00,
6.25e-01,
3.50e-01,
2.80e-01,
1.40e-01,
5.80e-02,
3.00e-02,
]
# For typically for use with MCNP will need conversion to MeV,
# and ordering from low to high.
GROUP_STRUCTURE["CINDER63"] = [
2.5000e07,
2.0000e07,
1.6905e07,
1.4918e07,
1.0000e07,
6.0650e06,
4.9658e06,
3.6788e06,
2.8651e06,
2.2313e06,
1.7377e06,
1.3534e06,
1.1080e06,
8.2085e05,
6.3928e05,
4.9790e05,
3.8870e05,
3.0200e05,
1.8320e05,
1.1110e05,
6.7380e04,
4.0870e04,
2.5540e04,
1.9890e04,
1.5030e04,
9.1190e03,
5.5310e03,
3.3550e03,
2.8400e03,
2.4040e03,
2.0350e03,
1.2340e03,
7.4850e02,
4.5400e02,
2.7540e02,
1.6700e02,
1.0130e02,
6.1440e01,
3.7270e01,
2.2600e01,
1.3710e01,
8.3150e00,
5.0430e00,
3.0590e00,
1.8550e00,
1.1250e00,
6.8300e-01,
4.1400e-01,
2.5100e-01,
1.5200e-01,
1.0000e-01,
8.0000e-02,
6.7000e-02,
5.8000e-02,
5.0000e-02,
4.2000e-02,
3.5000e-02,
3.0000e-02,
2.5000e-02,
2.0000e-02,
1.5000e-02,
1.0000e-02,
5.0000e-03,
]
# fmt: off
# Group structures below here are derived from Appendix E in
# https://www.osti.gov/biblio/1483949-mc2-multigroup-cross-section-generation-code-fast-reactor-analysis-nuclear
GROUP_STRUCTURE["ANL9"] = _create_anl_energies_with_group_lethargies(
222, 120, itertools.repeat(180, 5), 540, 300
)
GROUP_STRUCTURE["ANL33"] = _create_anl_energies_with_group_lethargies(
42, itertools.repeat(60, 28), 90, 240, 29, 1
)
GROUP_STRUCTURE["ANL70"] = _create_anl_energies_with_group_lethargies(
42, itertools.repeat(30, 67), 29, 1
)
GROUP_STRUCTURE["ANL116"] = _create_anl_energies_with_group_lethargies(
15*[6] + [3] + 2*[6] + [3] + [12] + 3*[6] + 3*[12] + 2*[6] + 2*[12] + [4] + [6] + [2] +
[12] + 2*[6] + [12] + 2*[6] +2*[12] + [6] + [12] + 2*[6] + 6*[12] + [6] + 4*[12] + 4*[6] +
5*[12] + [6] + 3*[12] + [6] + 2*[30] + 2*[15] + [30] + 4*[15] + [18] + [12] + 5*[30] +
[24] + [12] + [24] + [19] + [11] + [18] + [24] + 3*[18] + 2*[12] + 14*[60] + 2*[30] + [29] + [1]
)
GROUP_STRUCTURE["ANL230"] = _create_anl_energies_with_group_lethargies(
[
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 3, 3,
6, 6, 6, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 6, 6,
6, 6, 2, 2, 1, 1, 2, 2, 2, 6, 6, 3, 3, 3, 3, 6, 6, 3, 3,
3, 3, 6, 6, 6, 6, 3, 3, 6, 6, 6, 3, 2, 1, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3,
6, 6, 6, 6, 6, 6, 6, 15, 15, 15, 15, 9, 6, 6, 9, 15, 15, 15, 3,
3, 9, 15, 9, 6, 3, 3, 9, 3, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 12, 12, 6, 6, 12, 12, 12, 7, 5, 6, 6, 12, 12, 12, 12, 6, 6, 12,
12, 6, 6, 6, 6, 6, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 6, 24, 10, 20,
29, 1,
]
)
# Reactor agnostic. Similar to ANL1041 but with 6 UFGs grouped together.
# More likely to not error out on memory than 703
GROUP_STRUCTURE["348"] = _create_anl_energies_with_group_lethargies(
itertools.repeat(6, 346), 5, 1
)
# Note that at one point the MC2 manual was inconsistent with the code itself
GROUP_STRUCTURE["ANL703"] = _create_anl_energies_with_group_lethargies(
[
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
1,
]
)
GROUP_STRUCTURE["ANL1041"] = _create_anl_energies_with_group_lethargies(
itertools.repeat(2, 1041)
)
GROUP_STRUCTURE["ANL2082"] = _create_anl_energies_with_group_lethargies(
itertools.repeat(1, 2082)
)
# fmt: on
def _create_multigroup_structures_on_finegroup_energies(
multigroup_energy_bounds, finegroup_energy_bounds
):
"""Set energy group bounds to the nearest ultra-fine group boundaries."""
modifiedEnergyBounds = set()
modifiedEnergyBounds.add(max(finegroup_energy_bounds))
for energyBound in multigroup_energy_bounds[1:]:
modifiedEnergyBounds.add(findNearestValue(finegroup_energy_bounds, energyBound))
return sorted(modifiedEnergyBounds, reverse=True)
def _create_anl_energies_with_group_energies(group_energy_bounds):
"""Set energy group bounds to the nearest ultra-fine group boundaries."""
ufgEnergies = _create_anl_energies_with_group_lethargies(itertools.repeat(1, 2082))
return _create_multigroup_structures_on_finegroup_energies(
group_energy_bounds, ufgEnergies
)
"""
Taken from Section A3.1 SHEM-361 in
Ngeleka, Tholakele Prisca. "Examination and improvement of the SHEM energy
group structure for HTR and deep burn HTR design and analysis." (2012).
"""
GROUP_STRUCTURE["SHEM361"] = [
19640300,
14918200,
13840300,
11618300,
9999990,
9048360,
8187300,
7408170,
6703190,
6065300,
4965850,
4065690,
3328710,
2725310,
2231300,
1901390,
1636540,
1405770,
1336940,
1286960,
1162050,
1051150,
951119,
860006,
706511,
578443,
494002,
456021,
412501,
383884,
320646,
267826,
230014,
195008,
164999,
140000,
122773,
115624,
94664.5,
82297.4,
67379.4,
55165.6,
49915.9,
40867.7,
36978.6,
33459.6,
29281,
27394.4,
26100.1,
24999.1,
22699.4,
18584.7,
16200.5,
14899.7,
13603.7,
11137.7,
9118.81,
7465.85,
6112.52,
5004.51,
4097.35,
3481.07,
2996.18,
2700.24,
2397.29,
2084.1,
1811.83,
1586.2,
1343.58,
1134.67,
1064.32,
982.494,
909.681,
832.218,
748.517,
677.287,
646.837,
612.834,
600.099,
592.941,
577.146,
539.204,
501.746,
453.999,
419.094,
390.76,
371.703,
353.575,
335.323,
319.928,
295.922,
288.327,
284.888,
276.468,
268.297,
256.748,
241.796,
235.59,
224.325,
212.108,
200.958,
195.996,
193.078,
190.204,
188.877,
187.559,
186.251,
184.952,
183.295,
175.229,
167.519,
163.056,
154.176,
146.657,
139.504,
132.701,
126.229,
120.554,
117.577,
116.524,
115.48,
112.854,
110.288,
105.646,
103.038,
102.115,
101.605,
101.098,
100.594,
97.3287,
93.3256,
88.7741,
83.9393,
79.3679,
76.3322,
73.5595,
71.8869,
69.0682,
66.8261,
66.4929,
66.1612,
65.8312,
65.5029,
65.046,
64.5923,
63.6306,
62.3083,
59.925,
57.0595,
54.06,
52.9895,
51.7847,
49.2591,
47.5173,
46.2053,
45.2904,
44.1721,
43.1246,
42.1441,
41.227,
39.7295,
38.7874,
37.7919,
37.3038,
36.8588,
36.4191,
36.0568,
35.698,
34.5392,
33.0855,
31.693,
27.8852,
24.6578,
22.5356,
22.3788,
22.1557,
22.0011,
21.7018,
21.4859,
21.336,
21.2296,
21.1448,
21.0604,
20.9763,
20.7676,
20.6847,
20.6021,
20.5199,
20.4175,
20.2751,
20.0734,
19.5974,
19.3927,
19.1997,
19.0848,
17.9591,
17.759,
17.5648,
17.4457,
16.8305,
16.5501,
16.0498,
15.7792,
14.8662,
14.7301,
14.5952,
14.4702,
14.2505,
14.0496,
13.546,
13.3297,
12.6,
12.4721,
12.3086,
12.1302,
11.9795,
11.8153,
11.7094,
11.5894,
11.2694,
11.0529,
10.8038,
10.5793,
9.50002,
9.14031,
8.97995,
8.80038,
8.67369,
8.52407,
8.30032,
8.13027,
7.97008,
7.83965,
7.73994,
7.60035,
7.38015,
7.13987,
6.99429,
6.91778,
6.87021,
6.83526,
6.8107,
6.79165,
6.77605,
6.75981,
6.74225,
6.71668,
6.63126,
6.60611,
6.58829,
6.57184,
6.55609,
6.53907,
6.51492,
6.48178,
6.43206,
6.35978,
6.28016,
6.16011,
6.05991,
5.96014,
5.80021,
5.72015,
5.61979,
5.53004,
5.48817,
5.41025,
5.38003,
5.32011,
5.21008,
5.10997,
4.93323,
4.76785,
4.4198,
4.30981,
4.21983,
4,
3.88217,
3.71209,
3.54307,
3.14211,
2.88405,
2.77512,
2.74092,
2.7199,
2.70012,
2.64004,
2.62005,
2.59009,
2.55,
2.46994,
2.33006,
2.27299,
2.21709,
2.15695,
2.0701,
1.98992,
1.90008,
1.77997,
1.66895,
1.58803,
1.51998,
1.44397,
1.41001,
1.38098,
1.33095,
1.29304,
1.25094,
1.21397,
1.16999,
1.14797,
1.12997,
1.11605,
1.10395,
1.09198,
1.07799,
1.03499,
1.02101,
1.00904,
0.996501,
0.981959,
0.96396,
0.944022,
0.919978,
0.880024,
0.800371,
0.719999,
0.624999,
0.594993,
0.55499,
0.520011,
0.475017,
0.431579,
0.390001,
0.352994,
0.325008,
0.305012,
0.279989,
0.254997,
0.231192,
0.20961,
0.190005,
0.161895,
0.137999,
0.119995,
0.104298,
0.0897968,
0.0764969,
0.0651999,
0.0554982,
0.0473019,
0.0402999,
0.0343998,
0.0292989,
0.0249394,
0.0200104,
0.01483,
0.0104505,
0.00714526,
0.00455602,
0.0024999,
]
# Energy bounds of ARMI33 and ARMI45 are modified to the nearest ultra-fine group boundaries
GROUP_STRUCTURE["ARMI33"] = _create_anl_energies_with_group_energies(
[
1.4190e07,
1.0000e07,
6.0650e06,
3.6780e06,
2.2313e06,
1.3530e06,
8.2080e05,
4.9787e05,
3.0190e05,
1.8310e05,
1.1109e05,
6.7370e04,
4.0860e04,
2.4788e04,
1.5030e04,
9.1180e03,
5.5308e03,
3.3540e03,
2.0340e03,
1.2341e03,
7.4850e02,
4.5390e02,
3.0432e02,
1.4860e02,
9.1660e01,
6.7904e01,
4.0160e01,
2.2600e01,
1.3709e01,
8.3150e00,
4.0000e00,
5.4000e-01,
4.1400e-01,
]
)
# Energy bounds of SHEM33_361 is ANL33 modified to the nearest SHEM361 fine group boundaries
GROUP_STRUCTURE["SHEM33_361"] = _create_multigroup_structures_on_finegroup_energies(
GROUP_STRUCTURE["ANL33"], GROUP_STRUCTURE["SHEM361"]
)
GROUP_STRUCTURE["ARMI45"] = _create_anl_energies_with_group_energies(
[
1.419e07,
1.000e07,
6.065e06,
4.966e06,
3.679e06,
2.865e06,
2.231e06,
1.738e06,
1.353e06,
1.108e06,
8.209e05,
6.393e05,
4.979e05,
3.887e05,
3.020e05,
1.832e05,
1.111e05,
6.738e04,
4.087e04,
2.554e04,
1.989e04,
1.503e04,
9.119e03,
5.531e03,
3.355e03,
2.840e03,
2.404e03,
2.035e03,
1.234e03,
7.485e02,
4.540e02,
2.754e02,
1.670e02,
1.013e02,
6.144e01,
3.727e01,
2.260e01,
1.371e01,
8.315e00,
5.043e00,
3.059e00,
1.855e00,
1.125e00,
6.830e-01,
4.140e-01,
]
)