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

Mattdon/new melcor interface #2017

Open
wants to merge 37 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
12d25ce
Update melcorCombinedInterface.py
mattdon Oct 18, 2022
e74717b
Delete MELCORdata.py
mattdon Oct 18, 2022
0fa7df7
Delete melcorInterface.py
mattdon Oct 18, 2022
33bc4ce
Delete melgenInterface.py
mattdon Oct 18, 2022
e0ead47
Update melcorCombinedInterface.py
mattdon Oct 18, 2022
9e98ecb
Update melcorCombinedInterface.py
mattdon Oct 28, 2022
446f280
Merge branch 'idaholab:devel' into New_MELCOR_Interface
mattdon Oct 28, 2022
9f398e0
Update test_melcor_interface.xml
mattdon Nov 2, 2022
49913b9
merge
mattdon Nov 11, 2022
6deb3ab
merge
mattdon Nov 11, 2022
216cb92
Merge branch 'devel' into mattdon/New_MELCOR_Interface
mandd Nov 17, 2022
081f5f6
Revert "merge"
wangcj05 Nov 17, 2022
5b1c43a
first cleaning of PR
mandd Nov 18, 2022
99e71a0
Merge branch 'devel' into mattdon/New_MELCOR_Interface
mandd Dec 15, 2022
8bcc76f
edits
mandd Jan 12, 2023
2c71868
Merge branch 'devel' into mattdon/New_MELCOR_Interface
mandd Jan 12, 2023
508d1a0
Merge remote-tracking branch 'origin/mattdon/New_MELCOR_Interface' in…
mandd Jan 16, 2023
d0b5a91
edit test files
mandd Jan 17, 2023
a569931
edit combinedInterface file
mandd Jan 17, 2023
4954399
added test files
mandd Jan 17, 2023
ad60e3a
missing test file
mandd Jan 17, 2023
9fdb226
fix for diego
Jan 18, 2023
5f2c16c
small edits
mandd Feb 15, 2023
879acc3
Merge remote-tracking branch 'origin/devel' into mattdon/New_MELCOR_I…
mandd Feb 17, 2023
3eb7f67
added edits from rome
mandd Feb 22, 2023
ab83307
edit file
mandd Feb 24, 2023
b065ddb
final files
mandd May 26, 2023
d8c1ae7
removed last file
mandd May 26, 2023
3108b58
Merge branch 'devel' into mattdon/New_MELCOR_Interface
aalfonsi May 27, 2023
e1ec0f5
removed whitespaces
aalfonsi May 27, 2023
65d3231
Update ravenframework/Models/PostProcessors/SubdomainBasicStatistics.py
aalfonsi May 27, 2023
e81ace2
fixed dictionary format
aalfonsi Jun 1, 2023
303b225
fixed dictionary format
aalfonsi Jun 1, 2023
d52231b
updated test
aalfonsi Jun 1, 2023
851e8df
final edits
mandd Jun 2, 2023
a5c4085
addressing comments
mandd Jun 23, 2023
d0d345c
addressing comments
mandd Sep 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ravenframework/CodeInterfaceClasses/Factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from .MAAP5.MAAP5Interface import MAAP5
from .MAMMOTH.MAMMOTHInterface import MAMMOTH
from .MELCOR.melcorCombinedInterface import Melcor
from .MELCOR.melcorInterface import MelcorApp
from .MooseBasedApp.BisonAndMeshInterface import BisonAndMesh
from .MooseBasedApp.CubitInterface import Cubit
from .MooseBasedApp.CubitMooseInterface import CubitMoose
Expand Down
152 changes: 0 additions & 152 deletions ravenframework/CodeInterfaceClasses/MELCOR/MELCORdata.py

This file was deleted.

157 changes: 115 additions & 42 deletions ravenframework/CodeInterfaceClasses/MELCOR/melcorCombinedInterface.py
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.
Expand All @@ -13,104 +13,177 @@
# limitations under the License.
"""
Created on April 18, 2017
@author: Matteo Donorio (University of Rome La Sapienza),
Fabio Gianneti (University of Rome La Sapienza),
@author: Matteo D'Onorio (Sapienza University of Rome)
Copy link
Collaborator

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?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

Andrea Alfonsi (INL)
"""

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
Copy link
Collaborator

Choose a reason for hiding this comment

The 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("$,")]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split using '$,' need also be documented in the user manual.

self.melcorPlotFile = [var.strip() for var in plotNode.text.split(",")][0]
self.melcorOutFile = [var.strip() for var in melNode.text.split(",")][0]
Comment on lines +55 to +56
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also document the output files types and explain the use of these files. For example, self.melcorPlotFile is used to retrieve outputs, and self.melcorOutFile is used to detect failures.


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
@ Out, (melgIn,melcIn), tuple, tuple containing Melgin and Melcor input files
@ In, currentInputFiles, list, list of Files objects
@ 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():
if foundMelcorInp:
raise IOError(f"Multiple Melcor input files are found {inputFile} and {melgIn}, please check your inputs, only one of input is accepted")
foundMelcorInp = True
melgIn = inputFiles[index]
melcIn = inputFiles[index]
melgIn = currentInputFiles[index]
melcIn = currentInputFiles[index]

if not foundMelcorInp:
raise IOError('None of the input files has one of the following extensions: ' + ' '.join(self.getInputExtension()))

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

melcOut = 'OUTPUT_MELCOR'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest move this to init method using self.melcOut.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you address this issue also?

Copy link
Collaborator

Choose a reason for hiding this comment

The 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= []
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

def writeDict(self,workDir):
"""
Output the parsed results into a CSV file
@ In, workDir, str, current working directory
@ Out, dictionary, dict, dictioanry containing the data generated by MELCOR
"""
fileDir = os.path.join(workDir,self.melcorPlotFile)
time,data,varUdm = melcorTools.MCRBin(fileDir,self.varList)
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
response = self.writeDict(workingDir)
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")
Copy link
Collaborator

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The 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
outputToRead.close()
return failure
Loading