<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Copyright (c) 2017-2020 Serpent-Tools developer team, GTRC
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Data files are not included with the python package, but can be downloaded from the GitHub repository. For this tutorial, the files are placed in the directory identified with the SERPENT_TOOLS_DATA environment variable.
Step1:  Results Reader
Basic operations
This notebook demonstrates the capabilities of the serpentTools to read Serpent results files. SERPENT [1] produces a result file (i.e. _res.m), containing general results (e.g. k-eff), metadata (e.g. title) and homogenized cross-sections. The homogenized cross-section sets are printed in the results file for all the requested universes. The ResultsReader is capable of reading this file, and storing the data inside univ objects. Each such object has methods and attributes that should ease the analyses.
Step2:  Metadata
metadata is a collective data that describes the problem. These are values that do not change over burnup and across homogenized universes. The following data is included
Step3:  Results Data
Results are stored as a function of time/burnup/index and include integral parameters of the system.
Results, such as k-eff, total flux, and execution times are included in .resdata. Some results include values and uncertainities (e.g. criticality) and some just the values (e.g. CPU resources).
Step4:  Values are presented in similar fashion as if they were read in to Matlab, with one exception. Serpent currently appends a new row for each burnup step, but also for each homogenized universe. This results in repetition of many quantities as Serpent loops over group constant data. The ResultsReader understands Serpent outputs and knows when to append "new" result data to avoid repetition. 
The structure of the data is otherwise identical to Matlab. For many quantities, the first column indicates expected value, while the second column contains relative uncertainties. For a better reference, please consult the Serpent wiki on structure of the main output file.
Step5:  Data in the resdata dictionary can be obtained by indexing directly into the reader with
Step6:  Plotting Results Data
The ResultsReader has a versatile plot method, used to plot primary time-dependent data from the result file. With it, one can plot
data from one or more quanties against various metrics of time. Control over formatting axis, legend placement, and label formatting is easily yielded to the user.
Step7:  Pass a dictionary of {variable
Step8:  Using the right argument, quantities can be plotted on the left and right y-axis. Similar formatting options are available
Step9:  Homogenized Universes
Universe data is stored for each state point in the universes dictionary. Keys are UnivTuple representing ('univ',burnup, step, time)
'univ'
Step10:  Results, such as infinite cross-sections, b1-leakage corrected cross-sections, kinetic parameters, are included in .universes. All the results include values and uncertainties.
Step11:  One can directly index into the universes dictionary to obtain data for a specific universe.
Step12:  However this requires knowledge of all four parameters which may be difficult. The getUniv method retrieves a specific universe that matches universe id and time of interest. 
While all four identifers, (universe id, burnup, step, and time) can be provided, the latter three are usually redundant.
Step13:  Working with homogenized universe data
Each state contains the same data fields, which can be obatined by using the following attributes on the HomogUniv objects
Step14:  Uncertainties can be obtained by using the infUnc, b1Unc, and gcUnc dictionaries. Uncertainties are relative, as they appear in the output files.
Step15:  Serpent also outputs the B1 cross-sections. However, the user must enable the B1 option by setting the fum card. If this card is not enabled by the user, the B1_ variables will all be zeros.
Step16:  Data that does not contain the prefix INF_ or B1_ is stored under the gc and gcUnc fields. Criticality, kinetic, and other variables are stored under this field.
Step17:  Macro- and micro-group structures are stored directly in the universe in MeV as they appear in the Serpent output files. This means that the macro-group structure is in order of descending energy, while micro-group are in order of increasing energy.
Step18:  Plotting universes
HomogUniv objects can plot group constants using their plot method. This method has a range of formatting options, with defaults corresponding to plotting macroscopic cross sections. This is manifested in the default y axis label, but can be easily adjusted.
Step19:  Macroscopic and microscopic quantities, such as micro-group flux, can be plotted on the same figure.
Note The units and presentation of the micro- and macro-group fluxes are dissimilar, and the units do not agree with that of the assumed group constants. This will adjust the default y-label, as demonstrated below.
Step20:  For plotting data from multiple universes, pass the returned matplotlib.axes.Axes object, on which the plot was drawn, into the plot method for the next universe. The labelFmt argument can be used to differentiate between plotted data. The following strings are replaced when creating the labels
Step21:  User Defined Settings
The user is able to filter the required information by using the settings option.
A detailed description on how to use the settings can be found on
Step22:  The rc object and various xs.* settings can be used to control the ResultsReader. Specifically, these settings can be used to store only specific bits of information. Here, we will store the version of Serpent, various cross sections, eigenvalues, and burnup data.
Step23:  Further, instruct the reader to only read infinite medium cross sections, not critical spectrum B1 cross sections.
<ASSISTANT_TASK:>
Python Code:
import os
resFile = os.path.join(
    os.environ["SERPENT_TOOLS_DATA"],
    "InnerAssembly_res.m")
Explanation: Copyright (c) 2017-2020 Serpent-Tools developer team, GTRC
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Data files are not included with the python package, but can be downloaded from the GitHub repository. For this tutorial, the files are placed in the directory identified with the SERPENT_TOOLS_DATA environment variable.
End of explanation
import numpy as np
import serpentTools
from serpentTools.settings import rc
rc['serpentVersion'] = '2.1.30'
res = serpentTools.read(resFile)
Explanation: Results Reader
Basic operations
This notebook demonstrates the capabilities of the serpentTools to read Serpent results files. SERPENT [1] produces a result file (i.e. _res.m), containing general results (e.g. k-eff), metadata (e.g. title) and homogenized cross-sections. The homogenized cross-section sets are printed in the results file for all the requested universes. The ResultsReader is capable of reading this file, and storing the data inside univ objects. Each such object has methods and attributes that should ease the analyses.
End of explanation
print(res.metadata['version'])  # Serpent version used for the execution
print(res.metadata['decayDataFilePath'])  # Directory path for data libraries
print(res.metadata['inputFileName'])  # Directory path for data libraries
res.metadata.keys()
res.metadata['startDate']
res.metadata['pop'], res.metadata['skip']  , res.metadata['cycles']
Explanation: Metadata
metadata is a collective data that describes the problem. These are values that do not change over burnup and across homogenized universes. The following data is included: titles, data paths, and other descriptive data exist on the reader.
End of explanation
sorted(res.resdata.keys())[0:5]
Explanation: Results Data
Results are stored as a function of time/burnup/index and include integral parameters of the system.
Results, such as k-eff, total flux, and execution times are included in .resdata. Some results include values and uncertainities (e.g. criticality) and some just the values (e.g. CPU resources).
End of explanation
res.resdata['absKeff']
res.resdata['absKeff'][:,0]
res.resdata['burnup']
res.resdata['burnDays']
res.resdata['totCpuTime']
Explanation: Values are presented in similar fashion as if they were read in to Matlab, with one exception. Serpent currently appends a new row for each burnup step, but also for each homogenized universe. This results in repetition of many quantities as Serpent loops over group constant data. The ResultsReader understands Serpent outputs and knows when to append "new" result data to avoid repetition. 
The structure of the data is otherwise identical to Matlab. For many quantities, the first column indicates expected value, while the second column contains relative uncertainties. For a better reference, please consult the Serpent wiki on structure of the main output file.
End of explanation
res["burnup"]
res.get("absKeff")
Explanation: Data in the resdata dictionary can be obtained by indexing directly into the reader with
End of explanation
res.plot('absKeff')
res.plot('burnup', ['absKeff', 'colKeff'])
Explanation: Plotting Results Data
The ResultsReader has a versatile plot method, used to plot primary time-dependent data from the result file. With it, one can plot
data from one or more quanties against various metrics of time. Control over formatting axis, legend placement, and label formatting is easily yielded to the user.
End of explanation
# plot multiple values with better labels and formatting
res.plot(
    'burnup', {'absKeff': '$k_{eff}^{abs}$', 'colKeff': '$k_{eff}^{col}$'},
    ylabel=r'Criticality $\pm 3\sigma$',
    legend='above', ncol=2)
Explanation: Pass a dictionary of {variable: label} pairs to set plot labels
End of explanation
res.plot(
    'burnStep', {'actinideIngTox': 'Actinide Ingestion Tox'},
    right={'totCpuTime': "CPU Time [right]"}, sigma=0, rightlabel='CPU Time', 
    logy=[False, True])
Explanation: Using the right argument, quantities can be plotted on the left and right y-axis. Similar formatting options are available
End of explanation
for key in sorted(res.universes):
    break
key
key[0]
assert key.burnup == key[1]
Explanation: Homogenized Universes
Universe data is stored for each state point in the universes dictionary. Keys are UnivTuple representing ('univ',burnup, step, time)
'univ': universe ID (e.g., '0')
burnup: in MWd/kg
step: step index, 
time: in days.
and can be indexes by attribute or by position.
End of explanation
sorted(res.universes)[:10]
Explanation: Results, such as infinite cross-sections, b1-leakage corrected cross-sections, kinetic parameters, are included in .universes. All the results include values and uncertainties.
End of explanation
print(res.universes['0', 0, 0, 0])
Explanation: One can directly index into the universes dictionary to obtain data for a specific universe.
End of explanation
univ0 = res.getUniv('0', index=0)  
print(univ0)
univ3101 = res.getUniv('3101', index=3)
print(univ3101)
univ3102 = res.getUniv('3102', burnup=0.1)
print(univ3102)
print(res.getUniv('0', timeDays=24.0096))
Explanation: However this requires knowledge of all four parameters which may be difficult. The getUniv method retrieves a specific universe that matches universe id and time of interest. 
While all four identifers, (universe id, burnup, step, and time) can be provided, the latter three are usually redundant.
End of explanation
sorted(univ0.infExp)[:10]
univ0.infExp['infAbs']
univ0["infAbs"]
univ0.infExp['infFlx']
Explanation: Working with homogenized universe data
Each state contains the same data fields, which can be obatined by using the following attributes on the HomogUniv objects: 
infExp: infinite values, e.g. INF_ABS, 
infUnc: infinite uncertainties, 
b1Exp:  b1 (leakage corrected) values, e.g. B1_ABS,  
b1Exp:  b1 (leakage corrected) uncertainties, 
gc: variables that are not included in 'inf' or 'b1', e.g. BETA
gcUnc: group uncertainties
groups: macro energy group structure, MeV
microGroups: micro energy group structure, MeV
The parser reads all variables by default, and the HomogUniv objects stores data in various dictionaries. Data are energy dependent, exactly as they would appear in Serpent outputs.
End of explanation
univ0.infUnc['infFlx']
Explanation: Uncertainties can be obtained by using the infUnc, b1Unc, and gcUnc dictionaries. Uncertainties are relative, as they appear in the output files.
End of explanation
sorted(univ0.b1Exp)[:10]
univ0.b1Exp['b1Flx']
univ0["b1Flx"]
univ0.b1Exp['b1Abs']
Explanation: Serpent also outputs the B1 cross-sections. However, the user must enable the B1 option by setting the fum card. If this card is not enabled by the user, the B1_ variables will all be zeros.
End of explanation
sorted(univ0.gc)[:5]
univ3101.gc['betaEff']
univ3101["betaEff"]
Explanation: Data that does not contain the prefix INF_ or B1_ is stored under the gc and gcUnc fields. Criticality, kinetic, and other variables are stored under this field.
End of explanation
univ3101.groups
univ3101.microGroups[:5:]
Explanation: Macro- and micro-group structures are stored directly in the universe in MeV as they appear in the Serpent output files. This means that the macro-group structure is in order of descending energy, while micro-group are in order of increasing energy.
End of explanation
univ0.plot(['infAbs', 'b1Abs']);
Explanation: Plotting universes
HomogUniv objects can plot group constants using their plot method. This method has a range of formatting options, with defaults corresponding to plotting macroscopic cross sections. This is manifested in the default y axis label, but can be easily adjusted.
End of explanation
univ0.plot(['infTot', 'infFlx', 'infMicroFlx'], legend='right');
Explanation: Macroscopic and microscopic quantities, such as micro-group flux, can be plotted on the same figure.
Note The units and presentation of the micro- and macro-group fluxes are dissimilar, and the units do not agree with that of the assumed group constants. This will adjust the default y-label, as demonstrated below.
End of explanation
fmt = r"Universe {u} - $\Sigma_{abs}^\infty$"
ax = univ3101.plot('infFiss', labelFmt=fmt)
univ3102.plot('infFiss', ax=ax, labelFmt=fmt, legend='above', ncol=2);
Explanation: For plotting data from multiple universes, pass the returned matplotlib.axes.Axes object, on which the plot was drawn, into the plot method for the next universe. The labelFmt argument can be used to differentiate between plotted data. The following strings are replaced when creating the labels:
|String|Replaced value|
|-|-|
|{k}|Name of variable plotted|
|{u}| Name of this universe|
|{b}| Value of burnup in MWd/kgU|
|{d}| Value of burnup in days|
|{i}| Burnup index
These can be used in conjunction with the matplotlib $\LaTeX$ rendering system.
End of explanation
rc.keys()
Explanation: User Defined Settings
The user is able to filter the required information by using the settings option.
A detailed description on how to use the settings can be found on:
http://serpent-tools.readthedocs.io/en/latest/settingsTop.html
End of explanation
rc['xs.variableGroups'] = ['versions', 'xs', 'eig', 'burnup-coeff']
Explanation: The rc object and various xs.* settings can be used to control the ResultsReader. Specifically, these settings can be used to store only specific bits of information. Here, we will store the version of Serpent, various cross sections, eigenvalues, and burnup data.
End of explanation
rc['xs.getB1XS'] = False
resFilt = serpentTools.read(resFile)
resFilt.metadata.keys()
resFilt.resdata.keys()
univ0Filt = resFilt.getUniv('0', index=1)  
univ0Filt.infExp.keys() 
univ0Filt.b1Exp
Explanation: Further, instruct the reader to only read infinite medium cross sections, not critical spectrum B1 cross sections.
End of explanation
<END_TASK>