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

[WIP] ND Sampled Variables #2391

Open
wants to merge 20 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
4 changes: 2 additions & 2 deletions doc/workshop/ExternalModels/projectile.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ def current_angle(v0, ang, vel):
return np.arccos(v0 * np.cos(ang) / vel)

def run(raven, inputs):
vars = {'x0': get_from_raven('x0', raven, 0),
inps = {'x0': get_from_raven('x0', raven, 0),
'y0': get_from_raven('y0', raven, 0),
'v0': get_from_raven('v0', raven, 1),
'angle': get_from_raven('angle', raven, 45),
'timeOption': get_from_raven('timeOption', raven, 0)}
res = main(vars)
res = main(inps)
raven.x = res['x']
raven.y = res['y']
raven.t = res['t']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
</variable>
<constant name="x0">0</constant>
<constant name="y0">0</constant>
<constant name="v0">1</constant>
</MonteCarlo>
</Samplers>

Expand Down
2 changes: 1 addition & 1 deletion plugins/HERON
Submodule HERON updated 105 files
4 changes: 3 additions & 1 deletion ravenframework/BaseClasses/BaseEntity.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,16 @@ def provideExpectedMetaKeys(self):
"""
return self.metadataKeys, self.metadataParams

def addMetaKeys(self,args, params={}):
def addMetaKeys(self,args, params=None):
"""
Adds keywords to a list of expected metadata keys.
@ In, args, list(str), keywords to register
@ In, params, dict, optional, {key:[indexes]}, keys of the dictionary are the variable names,
values of the dictionary are lists of the corresponding indexes/coordinates of given variable
@ Out, None
"""
if params is None:
params = {}
if any(not mathUtils.isAString(a) for a in args):
self.raiseAnError('Arguments to addMetaKeys were not all strings:',args)
self.metadataKeys = self.metadataKeys.union(set(args))
Expand Down
18 changes: 18 additions & 0 deletions ravenframework/BaseClasses/MessageUser.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

@author: talbpaul
"""

from pprint import pp

from .. import MessageHandler

class MessageUser(object):
Expand Down Expand Up @@ -121,3 +124,18 @@ def raiseADebug(self, *args, **kwargs):
color = kwargs.get('color', None)
msg = ' '.join(str(a) for a in args)
self.messageHandler.message(self, msg, str(tag), verbosity, color)

def raiseWhatsThis(self, member, obj=None, tag="DEBUGG"):
"""
Shortcut for a commonly-used print command for developers.
@ In, member, str, name of member to interrogate
@ In, obj, object, optional, if provided then this is the thing to print; otherwise it's self.member
@ In, tag, str, optional, identifying message to include with print
"""
print('/'+'*'*80)
print(f'{tag}:')
if obj is None:
pp(getattr(self, member))
else:
pp(obj)
print('\\'+'*'*80)
6 changes: 2 additions & 4 deletions ravenframework/CodeInterfaceBaseClass.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,17 +181,15 @@ def generateCommand(self, inputFiles, executable, clargs=None, fargs=None, preEx
return

@abc.abstractmethod
def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs):
def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, rlz):
"""
This method is used to generate an input based on the information passed in.
@ 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})
@ In, rlz, Realization, sampled input that should be entered into code run
@ Out, newInputFiles, list, list of newer input files, list of the new input files (modified and not)
"""
pass

####################
####### OPTIONAL METHODS #######
Expand Down
24 changes: 10 additions & 14 deletions ravenframework/CodeInterfaceClasses/Dymola/DymolaInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,11 @@
<executable> -s <dsin file text> <outputfile>
"""

from __future__ import division, print_function, unicode_literals, absolute_import

import os
import math
import scipy.io
import csv
import re
import copy

import scipy.io
import numpy
import pandas as pd

Expand Down Expand Up @@ -182,16 +179,15 @@ def getInputExtension(self):
validExtensions = ('txt', 'TXT')
return validExtensions

def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs):
def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, rlz):
"""
Generate a new Dymola input file (txt format) from the original, changing parameters
as specified in Kwargs['SampledVars']. In addition, it creaes an additional input file including the vector data to be
passed to Dymola.
@ 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})
@ In, rlz, Realization, Realization from which to build input
@ Out, newInputFiles, list, list of newer input files, list of the new input files (modified and not)
"""
# Start with the original input file, which we have to find first.
Expand All @@ -206,7 +202,7 @@ def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs
foundVect = True
indexVect = index
if not foundInit:
raise Exception('Dymola INTERFACE ERROR -> None of the input files has the type "DymolaInitialisation"!')
raise IOError('Dymola INTERFACE ERROR -> None of the input files has the type "DymolaInitialisation"!')
if not foundVect:
print('Dymola INTERFACE WARNING -> None of the input files has the type "DymolaVectors"! ')
# Figure out the new file name and put it into the proper place in the return list
Expand All @@ -221,7 +217,7 @@ def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs
# numbers (integer or floating point). *True* and *False* (not 'true' and 'false') are
# automatically mapped to 1 and 0. Enumerations must be given explicitly as the unsigned integer
# equivalent. Strings, functions, redeclarations, etc. are not supported.
varDict = Kwargs['SampledVars']
varDict = rlz

vectorsToPass= {}
for key, value in list(varDict.items()):
Expand All @@ -234,15 +230,15 @@ def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs
print(" 'DymolaInitialisation' the array must be split into scalars.")
print(" => It is assumed that the array goes into the input file with type 'DymolaVectors'")
if not foundVect:
raise Exception('Dymola INTERFACE ERROR -> None of the input files has the type "DymolaVectors"! ')
raise IOError('Dymola INTERFACE ERROR -> None of the input files has the type "DymolaVectors"! ')
# extract dict entry
vectorsToPass[key] = varDict.pop(key)
assert not type(value).__name__ in ['str','bytes','unicode'], ("Strings cannot be "
"used as values in the simulation initialization file.")

# create aditional input file for vectors if needed
if bool(vectorsToPass):
with open(currentInputFiles[indexVect].getAbsFile(), 'w') as Fvect:
with open(currentInputFiles[indexVect].getAbsFile(), 'w', encoding='utf-8') as Fvect:
Fvect.write("#1\n")
for key, value in sorted(vectorsToPass.items()) :
inc = 0
Expand Down Expand Up @@ -299,7 +295,7 @@ def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs
# contains the text after it (minus one space on both sides for clarity).

# Read the file.
with open(originalPath, 'r') as src:
with open(originalPath, 'r', enoding='utf-8') as src:
text = src.read()

# Set the parameters.
Expand All @@ -319,7 +315,7 @@ def createNewInput(self, currentInputFiles, oriInputFiles, samplerType, **Kwargs
"in %s." % (name, originalPath))

# Re-write the file.
with open(currentInputFiles[indexInit].getAbsFile(), 'w') as src:
with open(currentInputFiles[indexInit].getAbsFile(), 'w', encoding='utf-8') as src:
src.write(text)

return currentInputFiles
Expand Down
4 changes: 2 additions & 2 deletions ravenframework/CodeInterfaceClasses/Factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .CobraTF.CTFinterface import CTF
from .Dymola.DymolaInterface import Dymola
from .MAAP5.MAAP5Interface import MAAP5
from .MAMMOTH.MAMMOTHInterface import MAMMOTH
#from .MAMMOTH.MAMMOTHInterface import MAMMOTH
from .MELCOR.melcorCombinedInterface import Melcor
from .MELCOR.melcorInterface import MelcorApp
from .MooseBasedApp.BisonAndMeshInterface import BisonAndMesh
Expand All @@ -41,7 +41,7 @@
from .RELAP5.Relap5Interface import Relap5
from .RELAP5inssJp.Relap5inssJpInterface import Relap5inssJp
from .RELAP7.RELAP7Interface import RELAP7
from .Rattlesnake.RattlesnakeInterface import Rattlesnake
#from .Rattlesnake.RattlesnakeInterface import Rattlesnake
from .SCALE.ScaleInterface import Scale
from .PARCS.PARCSInterface import PARCS
from .SERPENT.SerpentInterface import SERPENT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,13 @@ def getFileWithExtension(fileList,ext):
print('Execution Command: '+str(returnCommand[0]))
return returnCommand

def createNewInput(self,currentInputFiles,origInputFiles,samplerType,**Kwargs):
def createNewInput(self, currentInputFiles, origInputFiles, samplerType, rlz):
"""
This method is used to generate an input based on the information passed in.
@ 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})
@ In, rlz, Realization, Realization from whiech to build input
@ Out, newInputFiles, list, list of newer input files, list of the new input files (modified and not)
"""
infiles=[]
Expand All @@ -175,6 +174,6 @@ def createNewInput(self,currentInputFiles,origInputFiles,samplerType,**Kwargs):
if inputFile.getExt() in self.getInputExtension():
origfiles.append(inputFile)
parser = GenericParser.GenericParser(infiles)
parser.modifyInternalDictionary(**Kwargs)
parser.modifyInternalDictionary(rlz)
parser.writeNewInput(infiles,origfiles)
return currentInputFiles
74 changes: 38 additions & 36 deletions ravenframework/CodeInterfaceClasses/Generic/GenericParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def __init__(self,inputFiles,prefix='$RAVEN-',postfix='$',defaultDelim=':', form
self.varPlaces = {} # varPlaces[var][inputFile]
self.defaults = {} # defaults[var][inputFile]
self.formats = {} # formats[var][inputFile]
self.adlDict = None # additional edits to make
self.acceptFormats = {"d":int,"e":float,"E":float,"f":float,"F":float,"g":float,"G":float}
self.segments = {} # segments[inputFile]
self.printTag = 'GENERIC_PARSER'
Expand Down Expand Up @@ -93,87 +94,88 @@ def __init__(self,inputFiles,prefix='$RAVEN-',postfix='$',defaultDelim=':', form
defval = var[optionalPos[0]+1:min(optionalPos[1],len(var))] if optionalPos[0] < optionalPos[1] else var[min(optionalPos[0]+1,len(var)):len(var)]
varformat = var[min(optionalPos[1]+1,len(var)):len(var)] if optionalPos[0] < optionalPos[1] else var[optionalPos[1]+1:min(optionalPos[0],len(var))]
var = var[0:min(optionalPos)]
if var in self.defaults.keys() and optionalPos[0] != sys.maxsize:
if var in self.defaults and optionalPos[0] != sys.maxsize:
print('multiple default values given for variable',var)
if var in self.formats.keys() and optionalPos[1] != sys.maxsize:
if var in self.formats and optionalPos[1] != sys.maxsize:
print('multiple format values given for variable',var)
#TODO allow the user to specify take-last or take-first?
if var not in self.defaults.keys() and optionalPos[0] != sys.maxsize:
if var not in self.defaults and optionalPos[0] != sys.maxsize:
self.defaults[var] = {}
if var not in self.formats.keys() and optionalPos[1] != sys.maxsize:
if var not in self.formats and optionalPos[1] != sys.maxsize:
self.formats[var ] = {}
if optionalPos[0] != sys.maxsize:
self.defaults[var][infileName]=defval
if optionalPos[1] != sys.maxsize:
# check if the format is valid
if not any(formVal in varformat for formVal in self.acceptFormats.keys()):
if not any(formVal in varformat for formVal in self.acceptFormats):
try:
int(varformat)
except ValueError:
raise ValueError("the format specified for wildcard "+ line[start+len(self.prefixKey):end] +
" is unknown. Available are either a plain integer or the following "+" ".join(self.acceptFormats.keys()))
except ValueError as ve:
raise ValueError("the format specified for wildcard "+ line[start+len(self.prefixKey):end] +\
" is unknown. Available are either a plain integer or the following " +\
" ".join(self.acceptFormats.keys())) from ve
self.formats[var][infileName ]=varformat,int
else:
for formVal in self.acceptFormats.keys():
for formVal, entry in self.acceptFormats.items():
if formVal in varformat:
self.formats[var][infileName ]=varformat,self.acceptFormats[formVal]
self.formats[var][infileName] = varformat, entry
break
self.segments[infileName].append(line[:start])
self.segments[infileName].append(var)
if var not in self.varPlaces.keys():
if var not in self.varPlaces:
self.varPlaces[var] = {infileName:[len(self.segments[infileName])-1]}
elif infileName not in self.varPlaces[var].keys():
elif infileName not in self.varPlaces[var]:
self.varPlaces[var][infileName]=[len(self.segments[infileName])-1]
else:
self.varPlaces[var][infileName].append(len(self.segments[infileName])-1)
#self.segments.append(line[end+1:])
line=line[end+1:]
seg = ''
else:
seg+=line
seg += line
self.segments[infileName].append(seg)

def modifyInternalDictionary(self,**Kwargs):
def modifyInternalDictionary(self, rlz):
"""
Edits the parsed file stored in self.segments to enter new variable values preparatory to a new run.
@ In, **Kwargs, dict, dict including moddit (the dictionary of variable:value to replace) and additionalEdits.
@ In, rlz, Realization, Realization from whiech to build input
@ Out, None
"""
modDict = Kwargs['SampledVars']
self.adlDict = Kwargs.get('additionalEdits',{})
modDict = rlz
self.adlDict = rlz.inputInfo.get('additionalEdits',{})
ioVars = []
for value in self.adlDict.values():
if type(value)==dict:
if isinstance(value, dict):
for k in value.keys():
ioVars.append(k)
elif type(value)==list:
elif isinstance(value, list):
for v in value:
ioVars.append(v)
else:
ioVars.append(value)
for var in self.varPlaces.keys():
for inputFile in self.segments.keys():
for place in self.varPlaces[var][inputFile] if inputFile in self.varPlaces[var].keys() else []:
if var in modDict.keys():
if var in self.formats.keys():
if inputFile in self.formats[var].keys():
if any(formVal in self.formats[var][inputFile][0] for formVal in self.acceptFormats.keys()):
for var, dat in self.varPlaces.items():
for inputFile, seg in self.segments.items():
for place in dat[inputFile] if inputFile in dat else []:
if var in modDict:
if var in self.formats:
if inputFile in self.formats:
if any(formVal in self.formats[var][inputFile][0] for formVal in self.acceptFormats):
formatstringc = "{:"+self.formats[var][inputFile][0].strip()+"}"
self.segments[inputFile][place] = formatstringc.format(self.formats[var][inputFile][1](modDict[var]))
seg[place] = formatstringc.format(self.formats[var][inputFile][1](modDict[var]))
else:
self.segments[inputFile][place] = _reprIfFloat(modDict[var]).strip().rjust(self.formats[var][inputFile][1](self.formats[var][inputFile][0]))
seg[place] = _reprIfFloat(modDict[var]).strip().rjust(self.formats[var][inputFile][1](self.formats[var][inputFile][0]))
else:
self.segments[inputFile][place] = _reprIfFloat(modDict[var])
elif var in self.defaults.keys():
if var in self.formats.keys():
if inputFile in self.formats[var].keys():
if any(formVal in self.formats[var][inputFile][0] for formVal in self.acceptFormats.keys()):
seg[place] = _reprIfFloat(modDict[var])
elif var in self.defaults:
if var in self.formats:
if inputFile in self.formats[var]:
if any(formVal in self.formats[var][inputFile][0] for formVal in self.acceptFormats):
formatstringc = "{:"+self.formats[var][inputFile][0].strip()+"}"
self.segments[inputFile][place] = formatstringc.format(self.formats[var][inputFile][1](self.defaults[var][inputFile]))
seg[place] = formatstringc.format(self.formats[var][inputFile][1](self.defaults[var][inputFile]))
else:
self.segments[inputFile][place] = _reprIfFloat(self.defaults[var][inputFile]).strip().rjust(self.formats[var][inputFile][1](self.formats[var][inputFile][0]))
seg[place] = _reprIfFloat(self.defaults[var][inputFile]).strip().rjust(self.formats[var][inputFile][1](self.formats[var][inputFile][0]))
else:
self.segments[inputFile][place] = self.defaults[var][inputFile]
seg[place] = self.defaults[var][inputFile]
elif var in ioVars:
continue #this gets handled in writeNewInput
else:
Expand Down
Loading