-
Notifications
You must be signed in to change notification settings - Fork 135
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
Mattdon/new melcor interface #2017
base: devel
Are you sure you want to change the base?
Changes from 35 commits
12d25ce
e74717b
0fa7df7
33bc4ce
e0ead47
9e98ecb
446f280
9f398e0
49913b9
6deb3ab
216cb92
081f5f6
5b1c43a
99e71a0
8bcc76f
2c71868
508d1a0
d0b5a91
a569931
4954399
ad60e3a
9fdb226
5f2c16c
879acc3
3eb7f67
ab83307
b065ddb
d8c1ae7
3108b58
e1ec0f5
65d3231
e81ace2
303b225
d52231b
851e8df
a5c4085
d0d345c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# Copyright 2017 University of Rome La Sapienza and Battelle Energy Alliance, LLC | ||
# 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. | ||
|
@@ -13,104 +13,189 @@ | |
# limitations under the License. | ||
""" | ||
Created on April 18, 2017 | ||
@author: Matteo Donorio (University of Rome La Sapienza), | ||
Fabio Gianneti (University of Rome La Sapienza), | ||
Andrea Alfonsi (INL) | ||
@author: Matteo D'Onorio (Sapienza University of Rome) | ||
""" | ||
|
||
import os | ||
from ...contrib.melcorTools import melcorTools | ||
from ravenframework.CodeInterfaceBaseClass import CodeInterfaceBase | ||
from .melcorInterface import MelcorApp | ||
from .melgenInterface import MelgenApp | ||
from ..Generic import GenericParser | ||
import pandas as pd | ||
|
||
|
||
class Melcor(CodeInterfaceBase): | ||
""" | ||
this class is used a part of a code dictionary to specialize Model.Code for MELCOR 2. Version | ||
This class is used a part of a code dictionary to specialize Model. Code for different MELCOR versions | ||
like MELCOR 2.2x, MELCOR 1.86, MELCOR for fusion applications | ||
""" | ||
|
||
def __init__(self): | ||
def _readMoreXML(self,xmlNode): | ||
""" | ||
Constructor. | ||
@ In, None | ||
@ Out, None | ||
Function to read the portion of the xml input that belongs to this specialized class and initialize | ||
some members based on inputs. This can be overloaded in specialize code interface in order to | ||
read specific flags. | ||
Only one option is possible. You can choose here, if multi-deck mode is activated, from which deck you want to load the results | ||
@ In, xmlNode, xml.etree.ElementTree.Element, Xml element node | ||
@ Out, None. | ||
""" | ||
CodeInterfaceBase.__init__(self) | ||
self.melcorInterface = MelcorApp() | ||
self.melgenInterface = MelgenApp() | ||
|
||
def findInps(self,inputFiles): | ||
melNode = xmlNode.find('MelcorOutput') | ||
varNode = xmlNode.find('variables') | ||
plotNode = xmlNode.find('CodePlotFile') | ||
Comment on lines
+43
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These nodes need to be documented in the user manual |
||
|
||
if varNode is None: | ||
raise IOError("Melcor variables not found, define variables to print") | ||
if plotNode is None: | ||
raise IOError("Please define the name of the MELCOR plot file in the CodePlotFile xml node") | ||
if melNode is None: | ||
raise IOError("Please enter MELCOR message file name") | ||
|
||
self.VarList = [var.strip() for var in varNode.text.split("$,")] | ||
self.MelcorPlotFile = [var.strip() for var in plotNode.text.split(",")][0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use camelBack style for variables. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
self.melcorOutFile = [var.strip() for var in melNode.text.split(",")][0] | ||
|
||
return self.VarList, self.MelcorPlotFile, self.melcorOutFile | ||
|
||
def findInps(self,currentInputFiles): | ||
""" | ||
Locates the input files for Melgen, Melcor | ||
@ In, inputFiles, list, list of Files objects | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please change 'inputFiles' to 'currentInputFiles' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
@ Out, (melgIn,melcIn), tuple, tuple containing Melgin and Melcor input files | ||
@ Out, (melgIn,melcIn), tuple, tuple containing Melgen and Melcor input files | ||
""" | ||
foundMelcorInp = False | ||
for index, inputFile in enumerate(inputFiles): | ||
for index, inputFile in enumerate(currentInputFiles): | ||
if inputFile.getExt() in self.getInputExtension(): | ||
foundMelcorInp = True | ||
melgIn = inputFiles[index] | ||
melcIn = inputFiles[index] | ||
melgIn = currentInputFiles[index] | ||
melcIn = currentInputFiles[index] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not clear to me about the 'for loop' here. For example, if there are multiple files provided in raven input, how can this for loop check which files to pick? I guess only one file is accepted for melgIn and melcIn. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure here TBH There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest to add a check inside the if statement, for example: if foundMelcorInp:
raise IOError(f"Multiple Melcor input files are founded {inputFile} and {melgIn}, please check your inputs, only one of input is accepted") |
||
if not foundMelcorInp: | ||
raise IOError("Unknown input extensions. Expected input file extensions are "+ ",".join(self.getInputExtension())+" No input file has been found!") | ||
return melgIn,melcIn | ||
return melgIn, melcIn | ||
|
||
|
||
def generateCommand(self, inputFiles, executable, clargs=None, fargs=None, preExec=None): | ||
""" | ||
Generate a command to run MELCOR (combined MELGEN AND MELCOR) | ||
Collects all the clargs and the executable to produce the command-line call. | ||
This method is used to retrieve the command (in tuple format) needed to launch the Code. | ||
See base class. Collects all the clargs and the executable to produce the command-line call. | ||
Returns tuple of commands and base file name for run. | ||
Commands are a list of tuples, indicating parallel/serial and the execution command to use. | ||
This method is used to retrieve the command (in tuple format) needed to launch the Code. | ||
@ In, inputFiles, list, List of input files (length of the list depends on the number of inputs that have been added in the Step is running this code) | ||
@ In, inputFiles, list, List of input files (length of the list depends on the number of inputs have been added in the Step is running this code) | ||
@ In, executable, string, executable name with absolute path (e.g. /home/path_to_executable/code.exe) | ||
@ In, clargs, dict, optional, dictionary containing the command-line flags the user can specify in the input (e.g. under the node < Code >< clargstype =0 input0arg =0 i0extension =0 .inp0/ >< /Code >) | ||
@ In, fargs, dict, optional, a dictionary containing the axuiliary input file variables the user can specify in the input (e.g. under the node < Code >< clargstype =0 input0arg =0 aux0extension =0 .aux0/ >< /Code >) | ||
@ In, fargs, dict, optional, a dictionary containing the auxiliary input file variables the user can specify in the input (e.g. under the node < Code >< fileargstype =0 input0arg =0 aux0extension =0 .aux0/ >< /Code >) | ||
@ In, preExec, string, optional, a string the command that needs to be pre-executed before the actual command here defined | ||
@ Out, returnCommand, tuple, tuple containing the generated command. returnCommand[0] is the command to run the code (string), returnCommand[1] is the name of the output root | ||
""" | ||
if preExec is None: | ||
raise IOError('No preExec listed in input! Exiting...') | ||
found = False | ||
|
||
for index, inputFile in enumerate(inputFiles): | ||
if inputFile.getExt() in self.getInputExtension(): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not see a function to add the input extension for this interface. I think you need to update the self.inputExtensions using setInputExtension method or using addDefaultExtension method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems this issue has not been addressed yet. |
||
found = True | ||
break | ||
if not found: | ||
raise IOError('None of the input files has one of the following extensions: ' + ' '.join(self.getInputExtension())) | ||
melcOut = 'OUTPUT_MELCOR' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest move this to init method using self.melcOut. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you address this issue also? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you address this? |
||
melcin,melgin = self.findInps(inputFiles) | ||
#get the melgen part | ||
melgCommand,melgOut = self.melcorInterface.generateCommand([melgin],preExec,clargs,fargs) | ||
#get the melcor part | ||
melcCommand,melcOut = self.melgenInterface.generateCommand([melcin],executable,clargs,fargs) | ||
#combine them | ||
returnCommand = melgCommand + melcCommand, melcOut | ||
if clargs: | ||
precommand = executable + clargs['text'] | ||
else: | ||
precommand = executable | ||
melgCommand = str(preExec)+ ' '+melcin.getFilename() | ||
melcCommand = precommand+ ' '+melcin.getFilename() | ||
returnCommand = [('serial',melgCommand + ' && ' + melcCommand +' ow=o ')],melcOut | ||
|
||
return returnCommand | ||
|
||
def createNewInput(self,currentInputFiles,origInputFiles,samplerType,**Kwargs): | ||
""" | ||
This generates a new input file depending on which sampler has been chosen | ||
This generates a new input file depending on which sampler is chosen | ||
@ In, currentInputFiles, list, list of current input files (input files from last this method call) | ||
@ In, oriInputFiles, list, list of the original input files | ||
@ In, samplerType, string, Sampler type (e.g. MonteCarlo, Adaptive, etc. see manual Samplers section) | ||
@ In, Kwargs, dictionary, kwarded dictionary of parameters. In this dictionary there is another dictionary called "SampledVars" | ||
where RAVEN stores the variables that got sampled (e.g. Kwargs['SampledVars'] => {'var1':10,'var2':40}) | ||
@ Out, newInputFiles, list, list of newer input files, list of the new input files (modified and not) | ||
""" | ||
return self.melcorInterface.createNewInput(currentInputFiles,origInputFiles,samplerType,**Kwargs) | ||
|
||
def finalizeCodeOutput(self, command, output, workingDir): | ||
if "dynamicevent" in samplerType.lower(): | ||
raise IOError("Dynamic Event Tree-based samplers not implemented for MELCOR yet! But we are working on that.") | ||
indexes = [] | ||
inFiles = [] | ||
origFiles= [] | ||
#FIXME possible danger here from reading binary files | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this comment is for line 133 "parser = GenericParser.GenericParser(inFiles)" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
for index,inputFile in enumerate(currentInputFiles): | ||
if inputFile.getExt() in self.getInputExtension(): | ||
indexes.append(index) | ||
inFiles.append(inputFile) | ||
for index,inputFile in enumerate(origInputFiles): | ||
if inputFile.getExt() in self.getInputExtension(): | ||
origFiles.append(inputFile) | ||
parser = GenericParser.GenericParser(inFiles) | ||
parser.modifyInternalDictionary(**Kwargs) | ||
parser.writeNewInput(currentInputFiles,origFiles) | ||
|
||
return currentInputFiles #, origInputFiles, samplerType | ||
#return self.createNewInput(currentInputFiles,origInputFiles,samplerType,**Kwargs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove the commented lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cleaned |
||
|
||
def writeDict(self,filen,workDir): | ||
""" | ||
Output the parsed results into a CSV file | ||
@ In, filen, str, the file name of the CSV file | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems 'filen' is not used, if true, please update this function by removing filen keyword. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
@ In, workDir, str, current working directory | ||
@ Out, None | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please update the Out, 'dictionary' will be returned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
""" | ||
fileDir = os.path.join(workDir,self.MelcorPlotFile) | ||
time,data,VarUdm = melcorTools.MCRBin(fileDir,self.VarList) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. camelBack for VarUdm? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
dfTime = pd.DataFrame(time, columns= ["Time"]) | ||
dfData = pd.DataFrame(data, columns = self.VarList) | ||
df = pd.concat([dfTime, dfData], axis=1, join='inner') | ||
df.drop_duplicates(subset="Time",keep='first',inplace=True) | ||
dictionary = df.to_dict(orient='list') | ||
return dictionary | ||
|
||
def finalizeCodeOutput(self,command,output,workingDir): | ||
""" | ||
This method is called by the RAVEN code at the end of each run (if the method is present, since it is optional). | ||
In this method the MELCOR outputfile is parsed and a CSV is created | ||
It can be used for those codes, that do not create CSV files to convert the whatever output format into a csv | ||
@ In, command, string, the command used to run the just ended job | ||
@ In, output, string, the Output name root | ||
@ In, workingDir, string, current working dir | ||
@ Out, output, string, optional, present in case the root of the output file gets changed in this method. | ||
@ Out, response, dict, dictionary containing the data | ||
""" | ||
output = self.melcorInterface.finalizeCodeOutput(command,output, workingDir) | ||
return output | ||
self.det = False | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused by next few lines here. In previous check, an error will be raised if "dynamicevent" present in samplerType, why there are dynamic event tree related code provided in the following lines? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cleared |
||
response = self.writeDict(os.path.join(workingDir,output),workingDir) | ||
if self.det: | ||
stopDET = self.stopDET ( workingDir ) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The space before and after workingDir looks strange to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
if stopDET == True: | ||
print("RUN ended successfully!!!!!") | ||
else: | ||
tripVariable = self.messageReader(workingDir)[0] | ||
endTime = self.messageReader(workingDir)[1][0] | ||
endTimeStep = self.messageReader(workingDir)[1][1] | ||
filename = os.path.join(workingDir,output+"_actual_branch_info.xml") | ||
self._writeBranchInfo(filename, endTime, endTimeStep, tripVariable) | ||
return response | ||
|
||
|
||
def checkForOutputFailure(self,output,workingDir): | ||
""" | ||
This method is called by the RAVEN code at the end of each run if the return code is == 0. | ||
This method needs to be implemented by the codes that, if the run fails, return a return code that is 0 | ||
This can happen in those codes that record the failure of the job (e.g. not converged, etc.) as normal termination (returncode == 0) | ||
This method can be used, for example, to parse the outputfile looking for a special keyword that testifies that a particular job got failed | ||
(e.g. in MELCOR would be the expression "Normal termination") | ||
(e.g. in RELAP5 would be the keyword "********") | ||
@ In, output, string, the Output name root | ||
@ In, workingDir, string, current working dir | ||
@ Out, failure, bool, True if the job is failed, False otherwise | ||
""" | ||
failure = self.melcorInterface.checkForOutputFailure(output, workingDir) | ||
failure = True | ||
goodWord = "Normal termination" # This is for MELCOR 2.2 (todo: list for other MELCOR versions) | ||
try: | ||
outputToRead = open(os.path.join(workingDir,self.melcorOutFile),"r") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. file is not closed, I guess you need to close the file before you return. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
except FileNotFoundError: | ||
return failure | ||
readLines = outputToRead.readlines() | ||
lastRow = readLines[-1] | ||
if goodWord in lastRow: | ||
failure = False | ||
return failure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to add your name and Andrea name here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added