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.