Detailed Usage#
The endf package provides both low-level and high-level interfaces to
ENDF files. The low-level interface can be used when you simply need access to
the raw data in an ENDF file and you know exactly what you are looking for
(usually with a copy of the ENDF-6 format manual open next to you). The
high-level interface can be used if you are a normal human and you just want to,
say, look at a cross section for a specific reaction.
Low-level Interface#
To read an ENDF file with a single material, simply pass the filename to the
Material class:
import endf
mat = endf.Material('n-092_U_235.endf')
The section_text attribute holds a dictionary mapping
(MF, MT) to the section of text from the ENDF file:
>>> print(mat.section_text[12, 75])
9.223500+4 2.330248+2 2 2 25 0922812 75
4.386000+5 0.000000+0 0 0 3 1922812 75
0.000000+0 1.000000+0 1.000000+0 922812 75
The section_data attribute also holds a dictionary with
keys that are (MF, MT) pairs, but the values are dictionaries that hold the
individual pieces of data from the ENDF file:
>>> mat.section_data[3, 16]
{'ZA': 92235,
'AWR': 233.0248,
'QM': -5298000.0,
'QI': -5298000.0,
'LR': 0,
'sigma': <Tabulated1D: 39 points, 1 regions>}
Note that indexing the Material object directly is equivalent to
indexing the section_data attribute:
>>> mat[3, 16]
{'ZA': 92235,
'AWR': 233.0248,
'QM': -5298000.0,
'QI': -5298000.0,
'LR': 0,
'sigma': <Tabulated1D: 39 points, 1 regions>}
Tabulated1D Objects#
As the above example shows, whenever a TAB1 record is encountered in an ENDF
file, it is represented as a Tabulated1D object. The raw x and
y values can be accessed through the x and
y attributes. For example, if you wanted to make a
log-log plot of a cross section:
import matplotlib.pyplot as plt
xs = mat.section_data[3, 16]['sigma']
plt.loglog(xs.x, xs.y, marker='.', label='(n,2n)')
plt.show()
The Tabulated1D acts like a function; you can pass it a given
value of the independent variable and it will return the corresponding value of
the dependent variable, interpolating between tabulated points where necessary.
For example, if you wanted to know the cross section at 9.5 MeV:
>>> xs(9.5e6)
0.7428240476190476
Passing a list, array, or other iterable of values will return a numpy
array of corresponding values:
>>> energies = numpy.linspace(6.0e6, 8.0e6, 10)
>>> xs(energies)
array([0.183841 , 0.25245628, 0.3152985 , 0.3550485 , 0.3947985 ,
0.43081767, 0.463106 , 0.49255778, 0.52108125, 0.55290937])
High-level Interface#
While this form is more useful, it still may be a little too “raw”. The
Material class has an interpret() method
that returns a class based on the ENDF sublibrary type. For example,
incident-neutron data will result in an instance of the
endf.IncidentNeutron class. These “interpreted” classes provide a much
more intuitive interface to data within an ENDF (or ACE) file.
Incident Neutron Data#
The IncidentNeutron class provides the high-level interface to
ENDF incident neutron sublibrary files. You can get an instance of this class
either by calling the endf.Material.interpret() method:
mat = endf.Material('n-092_U_235.endf')
u235 = mat.interpret()
or by directly passing a filename to the endf.IncidentNeutron.from_endf()
method:
>>> u235 = endf.IncidentNeutron.from_endf('n-092_U_235.endf')
>>> u235
<IncidentNeutron: U235, 85 reactions>
Most incident neutron data is collected into the
reactions attribute, which is a dictionary that
maps the MT value to an instance of the Reaction class:
>>> u235.reactions
{1: <Reaction: MT=1 (n,total)>,
2: <Reaction: MT=2 (n,elastic)>,
4: <Reaction: MT=4 (n,level)>,
5: <Reaction: MT=5 (n,misc)>,
16: <Reaction: MT=16 (n,2n)>,
17: <Reaction: MT=17 (n,3n)>,
18: <Reaction: MT=18 (n,fission)>,
...
835: <Reaction: MT=835 (n,a35)>}
To look at data for a specific reaction then, you can index the
reactions attribute:
>>> u235.reactions[16]
<Reaction: MT=16 (n,2n)>
Alteratively, you can pass the MT value as an index to
IncidentNeutron directly:
>>> u235[16]
<Reaction: MT=16 (n,2n)>
or even use the name of the reaction as an index:
>>> u235['n,2n']
<Reaction: MT=16 (n,2n)>
The Reaction class has several attributes, including
xs (cross section), products
(reaction products), q_reaction (reaction Q-value) and
q_massdiff (mass-difference Q value). The
xs attribute is a dictionary mapping a temperature to the
integral cross section:
>>> n2n = u235['n,2n']
>>> n2n.xs
{'0K': <Tabulated1D: 39 points, 1 regions>}
For data that originates from an ENDF file, the cross sections are always
present at 0 K. However, the IncidentNeutron class can also be
used for ACE data. In that case, cross sections can be present at temperatures
other than 0 K.
The products attribute gives a list of reaction products
as Product objects:
>>> n2n.products
[<Product: neutron, emission=prompt, yield=2.0>,
<Product: U234, emission=prompt, yield=1.0>,
<Product: photon, emission=prompt, yield=tabulated>]
The yield of a given product is accessed through the
yield_ attribute:
>>> photon = n2n.products[-1]
>>> photon.yield_
<Tabulated1D: 39 points, 1 regions>
ACE Files#
Working with ACE files is conceptually similar to ENDF files. A low-level
interface provides access to the raw data within an ACE file (the NXS, JXS,
and XSS arrays) and the same high-level interface classes, e.g.,
endf.IncidentNeutron can be used to more easily inspect data. If you
have an ACE file with a single table within it, you can load it with the
endf.ace.get_table() function, which returns a endf.ace.Table
object:
>>> table = endf.ace.get_table('80198.710nc')
>>> table
<ACE Table: 80198.710nc at 293.6 K>
Raw access to the underlying arrays in the ACE file is provided via the
nxs, jxs, and
xss attributes:
>>> table.nxs
array([ 0, 172118, 80198, 3180, 34, 25, 97, 4,
0, 0, 80, 198, 0, 0, 0, 0,
0])
Note that each of these arrays is prepended with an extra zero at the beginning so that the indexing follows the Fortran 1-based indexing that is referenced in the ACE format manual.
As with the Material class, the Table class
has a interpret() that returns a corresponding high-level
interface class. For continuous-energy neutron data, this method will return an
IncidentNeutron object:
>>> hg198 = table.interpret()
>>> hg198
<IncidentNeutron: Hg198, 38 reactions>
From this point, the interface follows exactly as is shown in High-level Interface.