Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of SCALE CSAS sequence in scale interface #2155

Merged
merged 16 commits into from
Aug 9, 2023
Merged
11 changes: 9 additions & 2 deletions doc/user_manual/ProbabilityDistributions.tex
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ \subsubsection{1-Dimensional Discrete Distributions.}
\label{Categorical}
The \distname{Categorical} distribution is a discrete distribution that describes the result of a random variable that can have $K$ possible outcomes.
The probability of each outcome is separately specified.
The possible outcomes must be only numerical values (either integer or float numbers). No string can be assigned to any outcome.
The possible outcomes can be numerical values (either integer or float numbers) or strings.
%
There is not necessarily an underlying ordering of these outcomes, but labels are assigned in describing the distribution (in the range $1$ to $K$).
%
Expand Down Expand Up @@ -892,13 +892,20 @@ \subsubsection{1-Dimensional Discrete Distributions.}
\begin{lstlisting}[style=XML]
<Distributions>
...
<Categorical name='testCategorical'>
<Categorical name='testCategoricalFloat'>
<state outcome="10">0.1</state>
<state outcome="20">0.2</state>
<state outcome="50">0.15</state>
<state outcome="60">0.4</state>
<state outcome="90">0.15</state>
</Categorical>
<Categorical name='testCategoricalString'>
<state outcome="A">0.1</state>
<state outcome="B">0.2</state>
<state outcome="C">0.15</state>
<state outcome="D">0.4</state>
<state outcome="E">0.15</state>
</Categorical>
...
</Distributions>
\end{lstlisting}
Expand Down
64 changes: 59 additions & 5 deletions doc/user_manual/code_interfaces/scale.tex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ \subsection{SCALE Interface}
\begin{itemize}
\item \textbf{\textit{ORIGEN}}
\item \textbf{\textit{TRITON (using NEWT as transport solver)}}
\item \textbf{\textit{CSAS (any CSAS sequence)}}
\end{itemize}
}

Expand Down Expand Up @@ -61,8 +62,9 @@ \subsubsection{Models}
\item ``\textit{triton}''
\item ``\textit{origen}''
\item ``\textit{triton,origen}''
\item ``\textit{csas}''
\end{itemize}
\item \xmlNode{timeUOM}, optional, string. In this node the user can specify the \textit{units} for the independent variable ``time''.
\item \xmlNode{timeUOM}, optional, string. In this node the user can specify the \textit{units} for the independent variable ``time'' (this does not have any effect for \textit{csas} since it is a static sequence).
If the outputs are exported by SCALE in a different unit (e.g days, years, etc.), the SCALE interface will convert all the different
time scales into the unit here specified (in order to have a consistent (and unique) time scale). Available are:
\begin{itemize}
Expand All @@ -78,11 +80,15 @@ \subsubsection{Models}
An example is shown below:
\begin{lstlisting}[style=XML]
<Models>
<Code name="MyScale" subType="Scale">
<Code name="MyScale1" subType="Scale">
<executable>path/to/scalerte</executable>
<sequence>triton,origen</sequence>
<timeUOM>d</timeUOM>
</Code>
<Code name="MyScale2" subType="Scale">
<executable>path/to/scalerte</executable>
<sequence>csas</sequence>
</Code>
</Models>
\end{lstlisting}

Expand All @@ -92,15 +98,18 @@ \subsubsection{Files}
The \xmlNode{Files} XML node has to contain all the files required by the particular
sequence (s) of the external code (SCALE) to be run.
This involves not only the input file(s) (.inp) but also the auxiliary files that might be needed (e.g. binary initial compositions, etc.).
As mentioned, the current SCALE interface only supports TRITON and ORIGEN sequences. For this reason, depending on the
As mentioned, the current SCALE interface only supports TRITON, ORIGEN and CSAS sequences.
For this reason, depending on the
type of sequence (see previous section) to be run, the relative input files need to be marked with the sequence they are associated
with. This means that the type of the input file must be either ``triton'' or ``origen''. The auxiliary files that might be needed by
with. This means that the type of the input file must be either ``triton'', ``origen'' or ``csas''.
The auxiliary files that might be needed by
a particular sequence (e.g. binary initial compositions, etc.) should not be marked with any specific type (i.e. \textit{type=``''}).
Example:
\begin{lstlisting}[style=XML]
<Files>
<Input name="triton_input" type="triton">pwr_depletion.inp</Input>
<Input name="origen_input" type="origen">decay_calc.inp</Input>
<Input name="csas_input" type="csas">csas_expample.inp</Input>
<Input name="binary_comp" type="">pwr_depletion.f71</Input>
</Files>
\end{lstlisting}
Expand All @@ -111,7 +120,7 @@ \subsubsection{Files}
\paragraph{Output Files conversion}
Since RAVEN expects to receive a CSV file containing the outputs of the simulation, the results in the SCALE output
files need to be converted by the code interface.
\\As mentioned, the current interface \textcolor{red}{ is able to collect data from TRITON and ORIGEN sequences only}.
\\As mentioned, the current interface \textcolor{red}{ is able to collect data from TRITON, ORIGEN and CSAS sequences only}.
%% TRITON
\\The following information is collected from TRITON output:
\begin{itemize}
Expand Down Expand Up @@ -265,6 +274,51 @@ \subsubsection{Files}
\end{table}
\end{itemize}

%% CSAS
The following information is collected from CSAS output:
\begin{itemize}
\item \textit{\textbf{history overview}}
\begin{lstlisting}[basicstyle=\tiny]
*****************************************************************************************************
*** ***
*** title ***
*** ***
*****************************************************************************************************
*** ***
*** ****** final results table ****** ***
*** ***
*** best estimate system k-eff 0.1111 + or - 0.11111 ***
*** ***
*** Energy of average lethargy of Fission (eV) 1.11111E-01 + or - 1.11111E-03 ***
*** ***
*** system nu bar 1.11111E+00 + or - 1.11111E-04 ***
*** ***
*** system mean free path (cm) 1.11111E+00 + or - 1.11111E-03 ***
*** ***
*** number of warning messages xx ***
*** ***
*** number of error messages x ***
*** ***
*** k-effective satisfies the chi**2 test for normality at the 95 % level ***
*** ***
*** ***
*****************************************************************************************************
\end{lstlisting}
that will be converted in the following way (CSV):
\begin{table}[h]
\centering
\caption{CSAS Results}
\label{CSASresults}
\tabcolsep=0.11cm
\tiny
\begin{tabular}{|c|c|c|c|c|c|c|c|}
\hline
time & keff & AverageLethargyFission & nubar & meanFreePath \\
0.0 & 0.1111 & 1.11111E-01 & 1.11111E+00 & 1.11111E+00
\end{tabular}
\end{table}
\end{itemize}

\textbf{Remember also that a SCALE simulation run is considered successful (i.e., the simulation did not crash) if it does not contain, in
the last 20 lines, the following message:}

Expand Down
29 changes: 25 additions & 4 deletions ravenframework/CodeInterfaceClasses/SCALE/ScaleInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from ..Generic import GenericParser
from ravenframework.CodeInterfaceBaseClass import CodeInterfaceBase
from .tritonAndOrigenData import origenAndTritonData
from .csasData import csasData

class Scale(CodeInterfaceBase):
"""
Expand All @@ -39,7 +40,7 @@ def __init__(self):
@ Out, None
"""
CodeInterfaceBase.__init__(self)
self.sequence = [] # this contains the sequence that needs to be run. For example, ['triton'] or ['origen'] or ['triton','origen']
self.sequence = [] # this contains the sequence that needs to be run. For example, ['triton'] or ['origen'] or ['triton','origen','csas']
self.timeUOM = 's' # uom of time (i.e. s, h, m, d, y )
self.outputRoot = {} # the root of the output sequences

Expand All @@ -59,6 +60,11 @@ def _readMoreXML(self,xmlNode):
self.sequence = [elm.strip() for elm in sequence.text.split(",")]
if self.sequence.count('triton') > 1 or self.sequence.count('origen') > 1:
raise IOError("Multiple triton or origen sequences are not supported yet!")
if self.sequence.count('csas') == 1:
if self.sequence.count('triton') > 0 or self.sequence.count('origen') > 0:
raise IOError("If csas sequence is activated, nor triton/origen special sequence can be activated!")


timeUOM = xmlNode.find("timeUOM")
if timeUOM is not None:
self.timeUOM = timeUOM.text.strip()
Expand All @@ -74,26 +80,38 @@ def findInps(self,inputFiles):
inputDict = {}
origen = []
triton = []
csas = []

for inputFile in inputFiles:
if inputFile.getType().strip().lower() == "triton":
triton.append(inputFile)
elif inputFile.getType().strip().lower() == "origen":
origen.append(inputFile)
elif inputFile.getType().strip().lower() == "csas":
csas.append(inputFile)
if len(triton) > 1:
raise IOError('multiple triton input files have been found. Only one is allowed!')
if len(origen) > 1:
raise IOError('multiple origen input files have been found. Only one is allowed!')
if len(csas) > 1:
raise IOError('multiple SCALE csas input files have been found. Only one is allowed!')
if len(csas) > 0 and len(triton) > 0 and len(origen) > 0:
raise IOError('multiple SCALE csas, origen and triton input files have been found. Only one is allowed!')

# Check if the input requested by the sequence has been found
if self.sequence.count('triton') != len(triton):
raise IOError('triton input file has not been found. Files type must be set to "triton"!')
if self.sequence.count('origen') != len(origen):
raise IOError('origen input file has not been found. Files type must be set to "origen"!')
if self.sequence.count('csas') != len(csas):
raise IOError('csas input file has not been found. Files type must be set to "csas"!')
# add inputs
if len(origen) > 0:
inputDict['origen'] = origen
if len(triton) > 0:
inputDict['triton'] = triton
if len(csas) > 0:
inputDict['csas'] = csas
return inputDict

def generateCommand(self, inputFiles, executable, clargs=None, fargs=None, preExec=None):
Expand Down Expand Up @@ -171,10 +189,13 @@ def finalizeCodeOutput(self, command, output, workingDir):
@ In, workingDir, string, current working dir
@ Out, output, string, output csv file containing the variables of interest specified in the input
"""
outputType = 'combined' if len(self.sequence) > 1 else self.sequence[0]
outputType = 'combined' if len(self.sequence) > 1 else self.sequence[0]
filesIn = {}
for key in self.outputRoot.keys():
if self.outputRoot[key] is not None:
filesIn[key] = os.path.join(workingDir,self.outputRoot[key]+'.out')
outputParser = origenAndTritonData(filesIn, self.timeUOM, outputType)
outputParser.writeCSV(os.path.join(workingDir,output+".csv"))
if outputType == 'csas':
outputParser = csasData(os.path.join(workingDir,self.outputRoot[outputType]+".out"))
else:
outputParser = origenAndTritonData(filesIn, self.timeUOM, outputType)
return outputParser.returnData()
57 changes: 57 additions & 0 deletions ravenframework/CodeInterfaceClasses/SCALE/csasData.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Copyright 2017 Battelle Energy Alliance, 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.
"""
Created on March 25, 2022

@author: aalfonsi
"""

class csasData:
"""
Class that parses output of scale output (csas sequences) and collect a RAVEN compatible dict
"""
def __init__(self,filen):
"""
Constructor
@ In, filen, str, file name to be parsed
@ Out, None
"""
self._data = {}
self.filename = filen
self.loadData()

def loadData(self):
"""
Method to load data from csas sqeuences
@ In, None
@ Out, None
"""
with open(self.filename,"r+") as fobj:
for line in fobj.readlines():
if line.strip().startswith("***") and "best estimate system k-eff" in line:
self._data['keff'] = [float(line.split("best estimate system k-eff")[1].strip().split()[0])]
if line.strip().startswith("***") and "Energy of average lethargy of Fission (eV)" in line:
self._data['AverageLethargyFission'] = [float(line.split("Energy of average lethargy of Fission (eV)")[1].strip().split()[0])]
if line.strip().startswith("***") and "system nu bar" in line:
self._data['nubar'] = [float(line.split("system nu bar")[1].strip().split()[0])]
if line.strip().startswith("***") and "system mean free path (cm)" in line:
self._data['meanFreePath'] = [float(line.split("system mean free path (cm)")[1].strip().split()[0])]

def returnData(self):
"""
Return Data into dict format
@ In, None
@ Out, self._data, dict, dictionary with data
"""
return self._data
17 changes: 7 additions & 10 deletions ravenframework/CodeInterfaceClasses/SCALE/tritonAndOrigenData.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def _scalingFactorBetweenTimeUOM(targetUOM, inputUOM):

class origenAndTritonData:
"""
Class that parses output of scale output (now Triton and/or Orgin only) and write a RAVEN compatible CSV
Class that parses output of scale output (now Triton and/or Orgin only) and collect a RAVEN compatible dict
"""
def __init__(self,filen, timeUOM='s', outputType="triton"):
"""
Expand Down Expand Up @@ -350,13 +350,12 @@ def retrieveNuclideConcentrations(self):
outputDict['values'] = np.atleast_2d(values)
return outputDict

def writeCSV(self, fileout):
def returnData(self):
"""
Print Data into CSV format
@ In, fileout, str, the output file name
@ Out, None
Return Data into dict format
@ In, None
@ Out, data, dict, {'key':[...]}
"""
fileObject = open(fileout.strip()+".csv", mode='wb+') if not fileout.endswith('csv') else open(fileout.strip(), mode='wb+')
headers = ['time']
timeGrid = None
nParams = np.sum([len(data['info_ids']) for data in self.data.values() if data is not None])+1
Expand All @@ -372,7 +371,5 @@ def writeCSV(self, fileout):
outputMatrix = np.zeros( (nParams, len(timeGrid)) )
outputMatrix[0,:] = timeGrid[:]
outputMatrix[startIndex:endIndex,:] = data['values'][:,:]
# print the csv
np.savetxt(fileObject, outputMatrix.T, delimiter=',', header=','.join(headers), comments='')
fileObject.close()

data = {k:outputMatrix[c][:] for c,k in enumerate(headers)}
return data
Loading