diff --git a/developer_tools/XSDSchemas/Optimizers.xsd b/developer_tools/XSDSchemas/Optimizers.xsd index cd120ea283..3539b07805 100644 --- a/developer_tools/XSDSchemas/Optimizers.xsd +++ b/developer_tools/XSDSchemas/Optimizers.xsd @@ -28,6 +28,7 @@ + @@ -65,6 +66,7 @@ + diff --git a/developer_tools/XSDSchemas/Samplers.xsd b/developer_tools/XSDSchemas/Samplers.xsd index b33d644d3f..c9f1dbad22 100644 --- a/developer_tools/XSDSchemas/Samplers.xsd +++ b/developer_tools/XSDSchemas/Samplers.xsd @@ -88,9 +88,9 @@ - + @@ -117,6 +117,7 @@ + @@ -139,6 +140,7 @@ + @@ -155,6 +157,7 @@ + @@ -187,6 +190,7 @@ + @@ -232,6 +236,7 @@ + @@ -255,6 +260,7 @@ + @@ -268,6 +274,7 @@ + @@ -335,6 +342,7 @@ + @@ -367,6 +375,7 @@ + @@ -391,6 +400,7 @@ + @@ -430,6 +440,7 @@ + @@ -448,6 +459,7 @@ + @@ -461,6 +473,7 @@ + @@ -488,6 +501,7 @@ + diff --git a/doc/user_manual/sampler.tex b/doc/user_manual/sampler.tex index 2815404ebd..b90621fe91 100644 --- a/doc/user_manual/sampler.tex +++ b/doc/user_manual/sampler.tex @@ -13,6 +13,29 @@ \section{Samplers} \nb As with other objects, this identifier can be used to reference this specific entity from other input blocks in the XML. } +\newcommand{\shapeVariableDescription} +{ + \xmlAttr{shape}, + \xmlDesc{comma-separated integers, optional field}, + determines the number of samples and shape of samples + to be taken. For example, \xmlAttr{shape}=``2,3'' will provide a 2 by 3 + matrix of values, while \xmlAttr{shape}=``10'' will produce a vector of 10 values. + Omitting this optional attribute will result in a single scalar value instead. + Each of the values in the matrix or vector will be the same as the single sampled value. + \nb A model interface must be prepared to handle non-scalar inputs to use this option. +} +\newcommand{\shapeConstantDescription} +{ + \xmlAttr{shape}, + \xmlDesc{comma-separated integers, optional field}, + determines the shape of samples of the constant value. + For example, \xmlAttr{shape}=``2,3'' will shape the values into a 2 by 3 + matrix, while \xmlAttr{shape}=``10'' will shape into a vector of 10 values. + Unlike the \xmlNode{variable}, the constant requires each value be entered; the number + of required values is equal to the product of the \xmlAttr{shape}. + \nb A model interface must be prepared to handle non-scalar inputs to use this option. +} + \renewcommand{\specBlock}[2] { The specifications of this sampler must be defined within #1 \xmlNode{#2} XML @@ -98,10 +121,11 @@ \section{Samplers} \newcommand{\variableDescription} { \xmlNode{variable}, \xmlDesc{XML node, - required parameter} will specify one attribute: + required parameter} can specify the following attribute: \begin{itemize} \item \xmlAttr{name}, \xmlDesc{required string attribute}, user-defined name of this variable. + \item \shapeVariableDescription \end{itemize} } @@ -112,7 +136,12 @@ \section{Samplers} kept constant. For doing this, as many \xmlNode{constant} nodes as needed can be input, where the body of the node contains the constant value that is - going to be injected as an additional variable + going to be injected as an additional variable. The constant has the following attributes: + \begin{itemize} + \item \xmlAttr{name}, \xmlDesc{required string attribute}, user-defined name + of this constant. + \item \shapeConstantDescription + \end{itemize} } \newcommand{\distributionDescription} @@ -133,16 +162,6 @@ \section{Samplers} \nb{Alternatively, this node must be ommitted if the \xmlNode{distribution} node is supplied.} } -\newcommand{\shapeDescription} -{ - \xmlNode{shape}, \xmlDesc{comma-separated integers, - optional field}, determines the number of samples and shape of samples - to be taken. For example, \xmlNode{shape}2,3\xmlNode{/shape} will provide - a 2 x 3 matrix of values. In general, samplers will simply replicate - the single sampled value into each point of the matrix. Omitting this optional - node will result in a single scalar value instead. \nb A model interface - must be prepared to handle non-scalar inputs to use this option. -} @@ -577,7 +596,6 @@ \subsubsection{Monte Carlo} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -667,7 +685,6 @@ \subsubsection{Grid} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -764,7 +781,6 @@ \subsubsection{Sparse Grid Collocation} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -904,7 +920,6 @@ \subsubsection{Sobol} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -981,7 +996,6 @@ \subsubsection{Stratified} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -1196,7 +1210,6 @@ \subsubsection{Response Surface Design} \item \functionDescription \item \gridDescriptionOnlyCustom \nb{Only the construction ``custom'' is available. In the \xmlNode{grid} body only the lower and upper bounds can be inputted (2 numbers only).} - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \item \xmlNode{ResponseSurfaceDesignSettings}, \xmlDesc{required}, @@ -1384,7 +1397,6 @@ \subsubsection{Factorial Design} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -1799,7 +1811,6 @@ \subsubsection{Dynamic Event Tree} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -1910,7 +1921,6 @@ \subsubsection{Hybrid Dynamic Event Tree} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -1948,7 +1958,6 @@ \subsubsection{Hybrid Dynamic Event Tree} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -2095,7 +2104,6 @@ \subsubsection{Limit Surface Search} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \end{itemize} @@ -2332,7 +2340,6 @@ \subsubsection{Adaptive Dynamic Event Tree} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -2487,7 +2494,6 @@ \subsubsection{Adaptive Hybrid Dynamic Event Tree} \item \distributionDescription \item \functionDescription \item \gridDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -2560,7 +2566,6 @@ \subsubsection{Adaptive Hybrid Dynamic Event Tree} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -2658,7 +2663,6 @@ \subsubsection{Adaptive Sparse Grid} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} @@ -2839,7 +2843,6 @@ \subsubsection{Adaptive Sobol Decomposition} \begin{itemize} \item \distributionDescription \item \functionDescription - \item \shapeDescription \end{itemize} \item \constantVariablesDescription \end{itemize} diff --git a/framework/CodeInterfaces/RAVEN/RAVENInterface.py b/framework/CodeInterfaces/RAVEN/RAVENInterface.py index 517d175445..1d2d276094 100644 --- a/framework/CodeInterfaces/RAVEN/RAVENInterface.py +++ b/framework/CodeInterfaces/RAVEN/RAVENInterface.py @@ -80,26 +80,40 @@ def _readMoreXML(self,xmlNode): if len(self.linkedDataObjectOutStreamsNames) > 2: raise IOError(self.printTag+' ERROR: outputExportOutStreams node. The maximum number of linked OutStreams are 2 (1 for PointSet and 1 for HistorySet)!') - child = xmlNode.find("conversionModule") + self.conversionDict = {} # {modulePath : {'variables': [], 'noScalar': 0, 'scalar': 0}, etc } + child = xmlNode.find("conversion") if child is not None: - self.extModForVarsManipulationPath = os.path.expanduser(child.text.strip()) - if not os.path.isabs(self.extModForVarsManipulationPath): - self.extModForVarsManipulationPath = os.path.abspath(self.extModForVarsManipulationPath) - # check if it exist - if not os.path.exists(self.extModForVarsManipulationPath): - raise IOError(self.printTag+' ERROR: the conversionModule "'+self.extModForVarsManipulationPath+'" has not been found!') - extModForVarsManipulation = utils.importFromPath(self.extModForVarsManipulationPath) - if extModForVarsManipulation is None: - raise IOError(self.printTag+' ERROR: the conversionModule "'+self.extModForVarsManipulationPath+'" failed to be imported!') - # check if the methods are there - if 'convertNotScalarSampledVariables' in extModForVarsManipulation.__dict__.keys(): - self.hasMethods['noscalar'] = True - if 'manipulateScalarSampledVariables' in extModForVarsManipulation.__dict__.keys(): - self.hasMethods['scalar' ] = True - if not self.hasMethods['scalar'] and not self.hasMethods['noscalar']: - raise IOError(self.printTag +' ERROR: the conversionModule "'+self.extModForVarsManipulationPath - +'" does not contain any of the usable methods! Expected at least ' - +'one of: "manipulateScalarSampledVariables" and/or "manipulateScalarSampledVariables"!') + for moduleNode in child: + # get the module to be used for conversion + source = moduleNode.attrib.get('source',None) + if source is None: + raise IOError(self.printTag+' ERROR: no module "source" listed in "conversion" subnode attributes!') + # fix up the path + source = os.path.expanduser(source) + if not os.path.isabs(source): + source = os.path.abspath(source) + # check for existence + if not os.path.exists(source): + raise IOError(self.printTag+' ERROR: the conversionModule "{}" was not found!' + .format(self.extModForVarsManipulationPath)) + # check module is imported + checkImport = utils.importFromPath(source) + if checkImport is None: + raise IOError(self.printTag+' ERROR: the conversionModule "{}" failed on import!' + .format(self.extModForVarsManipulationPath)) + # check methods are in place + noScalar = 'convertNotScalarSampledVariables' in checkImport.__dict__ + scalar = 'manipulateScalarSampledVariables' in checkImport.__dict__ + if not (noScalar or scalar): + raise IOError(self.printTag +' ERROR: the conversionModule "'+source + +'" does not contain any of the usable methods! Expected at least ' + +'one of: "manipulateScalarSampledVariables" and/or "manipulateScalarSampledVariables"!') + # acquire the variables to be modified + varNode = moduleNode.find('variables') + if varNode is None: + raise IOError(self.printTag+' ERROR: no node "variables" listed in "conversion|module" subnode!') + variables = [x.strip() for x in varNode.text.split(',')] + self.conversionDict[source] = {'variables':variables, 'noScalar':noScalar, 'scalar':scalar} def __findInputFile(self,inputFiles): """ @@ -185,42 +199,24 @@ def createNewInput(self,currentInputFiles,oriInputFiles,samplerType,**Kwargs): self.innerWorkingDir = parser.workingDir # get sampled variables modifDict = Kwargs['SampledVars'] - # check if there are noscalar variables - vectorVars = {} - totSizeExpected = 0 - for var, value in modifDict.items(): - if np.asarray(value).size > 1: - vectorVars[var] = np.asarray(value) - totSizeExpected += vectorVars[var].size - if len(vectorVars) > 0 and not self.hasMethods['noscalar']: - raise IOError(self.printTag+' ERROR: No scalar variables ('+','.join(vectorVars.keys()) - + ') have been detected but no convertNotScalarSampledVariables has been inputted!') - # check if ext module has been inputted - if self.hasMethods['noscalar'] or self.hasMethods['scalar']: - extModForVarsManipulation = utils.importFromPath(self.extModForVarsManipulationPath) - if self.hasMethods['noscalar']: - if len(vectorVars) > 0: - toPopOut = vectorVars.keys() - try: - newVars = extModForVarsManipulation.convertNotScalarSampledVariables(vectorVars) - if type(newVars).__name__ != 'dict': - raise IOError(self.printTag+' ERROR: convertNotScalarSampledVariables must return a dictionary!') - # DEBUGG this is failing b/c Index and Variable both being counted! - #if len(newVars) != totSizeExpected: - # raise IOError(self.printTag+' ERROR: The total number of variables expected from method convertNotScalarSampledVariables is "'+str(totSizeExpected)+'". Got:"'+str(len(newVars))+'"!') - modifDict.update(newVars) - for noscalarVar in toPopOut: - modifDict.pop(noscalarVar) - except TypeError: - raise IOError(self.printTag+' ERROR: convertNotScalarSampledVariables accept only one argument convertNotScalarSampledVariables(variableDict)') - else: - print(self.printTag+' Warning: method "convertNotScalarSampledVariables" has been inputted but no "no scalar" variables have been found!') - # check if ext module has the method to manipulate the variables - if self.hasMethods['scalar']: - try: - extModForVarsManipulation.manipulateScalarSampledVariables(modifDict) - except TypeError: - raise IOError(self.printTag+' ERROR: manipulateScalarSampledVariables accept only one argument manipulateScalarSampledVariables(variableDict)') + + # apply conversion scripts + for source,convDict in self.conversionDict.items(): + module = utils.importFromPath(source) + varVals = dict((var,np.asarray(modifDict[var])) for var in convDict['variables']) + # modify vector+ variables that need to be flattened + if convDict['noScalar']: + # call conversion + newVars = module.convertNotScalarSampledVariables(varVals) + # check type + if type(newVars).__name__ != 'dict': + raise IOError(self.printTag+' ERROR: convertNotScalarSampledVariables in "{}" must return a dictionary!'.format(source)) + # apply new and/or updated values + modifDict.update(newVars) + # modify scalar variables + if convDict['scalar']: + # call conversion, value changes happen in-place + module.manipulateScalarSampledVariables(modifDict) # we work on batchSizes here newBatchSize = Kwargs['NumMPI'] diff --git a/framework/CodeInterfaces/RAVEN/RAVENparser.py b/framework/CodeInterfaces/RAVEN/RAVENparser.py index 518aaba73f..fd6adc9920 100644 --- a/framework/CodeInterfaces/RAVEN/RAVENparser.py +++ b/framework/CodeInterfaces/RAVEN/RAVENparser.py @@ -30,7 +30,7 @@ import numpy as np from collections import OrderedDict -from utils import xmlUtils +from utils import xmlUtils, mathUtils class RAVENparser(): """ @@ -293,16 +293,30 @@ def modifyOrAdd(self,modiDictionary={},save=True, allowAdd = False): subElement = ET.Element(nodeWithAttributeName, attrib=allowAddNodesPath[nodeWithAttributeName]) getFirstElement.append(subElement) getFirstElement = subElement + # in the event of vector entries, handle those here + if mathUtils.isSingleValued(val): + val = str(val).strip() + else: + if len(val.shape) > 1: + raise IOError(self.printTag+'ERROR: RAVEN interface is not prepared to handle matrix value passing yet!') + val = ','.join(str(i) for i in val) if changeTheNode: - subElement.text = str(val).strip() + subElement.text = val else: - subElement.attrib[attribConstruct.keys()[-1]] = str(val).strip() + subElement.attrib[attribConstruct.keys()[-1]] = val else: nodeToChange = foundNodes[0] pathNode = './/' + # in the event of vector entries, handle those here + if mathUtils.isSingleValued(val): + val = str(val).strip() + else: + if len(val.shape) > 1: + raise IOError(self.printTag+'ERROR: RAVEN interface is not prepared to handle matrix value passing yet!') + val = ','.join(str(i) for i in val) if changeTheNode: - nodeToChange.text = str(val).strip() + nodeToChange.text = val else: - nodeToChange.attrib[attribName] = str(val).strip() + nodeToChange.attrib[attribName] = val return returnElement diff --git a/framework/Optimizers/GradientBasedOptimizer.py b/framework/Optimizers/GradientBasedOptimizer.py index 957596675a..43b16840e2 100644 --- a/framework/Optimizers/GradientBasedOptimizer.py +++ b/framework/Optimizers/GradientBasedOptimizer.py @@ -398,6 +398,10 @@ def printProgress(name,boolCheck,test,gold): #same coordinate check sameCoordinateCheck = True for var,values in self.optVarsHist[traj][varsUpdate].items(): + # don't check constants, of course they're the same + if var in self.constants: + continue + # differentiate vectors and scalars for checking if hasattr(values,'__len__'): if any(values != self.counter['recentOptHist'][traj][0][var]): sameCoordinateCheck = False diff --git a/framework/Optimizers/Optimizer.py b/framework/Optimizers/Optimizer.py index b608f83a69..9744199c52 100644 --- a/framework/Optimizers/Optimizer.py +++ b/framework/Optimizers/Optimizer.py @@ -80,14 +80,13 @@ def getInputSpecification(cls): inputSpecification.removeSub('variable') variable = InputData.parameterInputFactory('variable', strictMode=True) variable.addParam("name", InputData.StringType, True) + variable.addParam("shape", InputData.IntegerListType, required=False) upperBound = InputData.parameterInputFactory('upperBound', contentType=InputData.FloatType, strictMode=True) lowerBound = InputData.parameterInputFactory('lowerBound', contentType=InputData.FloatType, strictMode=True) initial = InputData.parameterInputFactory('initial',contentType=InputData.StringListType) - shape = InputData.parameterInputFactory('shape',contentType=InputData.StringListType) variable.addSub(upperBound) variable.addSub(lowerBound) variable.addSub(initial) - variable.addSub(shape) inputSpecification.addSub(variable) # constant -> use the Sampler's specs. @@ -138,10 +137,10 @@ def getInputSpecification(cls): stoch = InputData.parameterInputFactory('stochasticDistribution' , contentType=stochEnum ) bisect = InputData.parameterInputFactory('innerBisectionThreshold', contentType=InputData.FloatType ) loop = InputData.parameterInputFactory('innerLoopLimit' , contentType=InputData.IntegerType) - param.addSub(num ) - param.addSub(stoch ) + param.addSub(num) + param.addSub(stoch) param.addSub(bisect) - param.addSub(loop ) + param.addSub(loop) inputSpecification.addSub(param) # multilevel @@ -321,11 +320,12 @@ def _readMoreXMLbase(self,xmlNode): if child.getName() == "variable": if self.fullOptVars is None: self.fullOptVars = [] - try: - varName = child.parameterValues['name'] - self.optVarsInitialized[varName] = False - except KeyError: - self.raiseAnError(IOError, '"{}" node does not have the "name" attribute'.format(child.getName())) + # store variable name + varName = child.parameterValues['name'] + self.optVarsInitialized[varName] = False + # store varible requested shape, if any + if 'shape' in child.parameterValues: + self.variableShapes[varName] = child.parameterValues['shape'] self.fullOptVars.append(varName) self.optVarsInit['initial'][varName] = {} for childChild in child.subparts: @@ -341,24 +341,15 @@ def _readMoreXMLbase(self,xmlNode): try: self.optVarsInit['initial'][varName][trajInd] = float(initVal) except ValueError: - self.raiseAnError(ValueError, 'Unable to convert to float the intial value for variable "{}" in trajectory "{}": {}'.format(varName,trajInd,initVal)) + self.raiseAnError(ValueError, + 'Unable to convert to float the intial value for variable "{}" in trajectory "{}": {}' + .format(varName,trajInd,initVal)) if self.optTraj == None: self.optTraj = range(len(self.optVarsInit['initial'][varName].keys())) - elif childChild.getName() == 'shape': - try: - variableShape = tuple(int(i) for i in childChild.value) - except ValueError as e: - self.raiseAnError(IOError,'Failed to interpret "shape" for variable "{}"! Should be comma-separated list of integers.'.format(varName)) - self.variableShapes[varName] = variableShape elif child.getName() == "constant": - value = utils.partialEval(child.value) - if value is None: - self.raiseAnError(IOError,'The body of "constant" XML block should be a number. Got: ' +child.value) - try: - self.constants[child.parameterValues['name']] = value - except KeyError: - self.raiseAnError(KeyError,child.getName()+'"constant" nodes must have the attribute "name" (missing in "{}").'.format(self.name)) + name,value = self._readInConstant(child) + self.constants[child.parameterValues['name']] = value elif child.getName() == "objectVar": self.objVar = child.value.strip() diff --git a/framework/Samplers/Sampler.py b/framework/Samplers/Sampler.py index 017d3bb6de..ad7efbb30f 100644 --- a/framework/Samplers/Sampler.py +++ b/framework/Samplers/Sampler.py @@ -55,6 +55,8 @@ class cls. specifying input of cls. """ inputSpecification = super(Sampler, cls).getInputSpecification() + # FIXME the DET HybridSampler doesn't use the "name" param for the samples it creates, + # so we can't require the name yet inputSpecification.addParam("name", InputData.StringType) outerDistributionInput = InputData.parameterInputFactory("Distribution") @@ -64,12 +66,11 @@ class cls. variableInput = InputData.parameterInputFactory("variable") variableInput.addParam("name", InputData.StringType) + variableInput.addParam("shape", InputData.IntegerListType, required=False) distributionInput = InputData.parameterInputFactory("distribution", contentType=InputData.StringType) distributionInput.addParam("dim", InputData.IntegerType) - shapeInput = InputData.parameterInputFactory("shape", contentType=InputData.StringType) variableInput.addSub(distributionInput) - variableInput.addSub(shapeInput) functionInput = InputData.parameterInputFactory("function", contentType=InputData.StringType) @@ -87,8 +88,9 @@ class cls. inputSpecification.addSub(variablesTransformationInput) - constantInput = InputData.parameterInputFactory("constant", contentType=InputData.StringType) + constantInput = InputData.parameterInputFactory("constant", contentType=InputData.InterpretedListType) constantInput.addParam("name", InputData.StringType, True) + constantInput.addParam("shape", InputData.IntegerListType, required=False) inputSpecification.addSub(constantInput) @@ -239,6 +241,10 @@ def _readMoreXMLbase(self,xmlNode): foundDistOrFunc = False # store variable name for re-use varName = child.parameterValues['name'] + # set shape if present + if 'shape' in child.parameterValues: + self.variableShapes[varName] = child.parameterValues['shape'] + # read subnodes for childChild in child.subparts: if childChild.getName() =='distribution': # can only have a distribution if doesn't already have a distribution or function @@ -270,13 +276,6 @@ def _readMoreXMLbase(self,xmlNode): toBeSampled = childChild.value # track variable as a functional sample self.dependentSample[prefix+varName] = toBeSampled - elif childChild.getName() == 'shape': - try: - variableShape = tuple(int(i) for i in childChild.value.split(',')) - except ValueError as e: - self.raiseAnError(IOError,'Failed to interpret "shape" for variable "{}"! Should be comma-separated list of integers.'.format(varName)) - self.variableShapes[varName] = variableShape - # TODO error check variable shape: all positive integers unless just 0? if not foundDistOrFunc: self.raiseAnError(IOError,'Sampled variable',varName,'has neither a nor node specified!') @@ -301,13 +300,9 @@ def _readMoreXMLbase(self,xmlNode): self.variablesTransformationDict[child.parameterValues['distribution']] = transformationDict elif child.getName() == "constant": - value = utils.partialEval(child.value) - if value is None: - self.raiseAnError(IOError,'The body of "constant" XML block should be a number. Got: ' +child.value) - try: - self.constants[child.parameterValues['name']] = value - except KeyError: - self.raiseAnError(KeyError,child.getName()+' must have the attribute "name"!!!') + name,value = self._readInConstant(child) + self.constants[name] = value + elif child.getName() == "restartTolerance": self.restartTolerance = child.value @@ -387,6 +382,32 @@ def _readMoreXMLbase(self,xmlNode): self.variablesTransformationDict[dist]['latentVariablesIndex'] = listIndex return paramInput + def _readInConstant(self,inp): + """ + Reads in a "constant" input parameter node. + @ In, inp, utils.InputParameter.ParameterInput, input parameter node to read from + @ Out, name, string, name of constant + @ Out, value, float or np.array, + """ + value = inp.value + name = inp.parameterValues['name'] + shape = inp.parameterValues.get('shape',None) + # if single entry, remove array structure; if multiple entries, cast them as numpy array + if len(value) == 1: + value = value[0] + else: + value = np.asarray(value) + # if specific shape requested, then reshape it + if shape is not None: + try: + value = value.reshape(shape) + except ValueError: + self.raiseAnError(IOError, + ('Requested shape "{}" ({} entries) for constant "{}"' +\ + ' is not consistent with the provided values ({} entries)!') + .format(shape,np.prod(shape),name,len(value))) + return name, value + def getInitParams(self): """ This function is called from the base class to print some of the information inside the class. diff --git a/framework/utils/InputData.py b/framework/utils/InputData.py index 14de6a9778..08fe2e73d9 100644 --- a/framework/utils/InputData.py +++ b/framework/utils/InputData.py @@ -20,7 +20,7 @@ """ from __future__ import division, print_function, unicode_literals, absolute_import import xml.etree.ElementTree as ET -from utils import utils +from utils import utils,mathUtils class InputType(object): """ @@ -133,6 +133,37 @@ def convert(cls, value): FloatType.createClass("float","xsd:double") +# +# +# +# +class InterpretedListType(InputType): + """ + A type for lists with unknown (but consistent) type; could be string, float, etc + """ + + @classmethod + def convert(cls, value): + """ + Converts value from string to a listi with string, integer, or float type. + @ In, value, string, the value to convert + @ Out, convert, list, the converted value + """ + values = value.split(",") + base = utils.partialEval(values[0].strip()) + # three possibilities: string, integer, or float + if mathUtils.isAString(base): + conv = str + elif mathUtils.isAnInteger(base): + conv = int + else: #float + conv = float + return [conv(x.strip()) for x in values] + +#Note, XSD's list type is split by spaces, not commas, so using xsd:string +InterpretedListType.createClass("stringtype","xsd:string") + + # # # @@ -155,6 +186,50 @@ def convert(cls, value): StringListType.createClass("stringtype","xsd:string") +# +# +# +# +class FloatListType(InputType): + """ + A type for float lists "1.1, 2.0, 3.4" -> [1.1, 2.0, 3.4] + """ + + @classmethod + def convert(cls, value): + """ + Converts value from string to a float list. + @ In, value, string, the value to convert + @ Out, convert, list, the converted value + """ + return [float(x.strip()) for x in value.split(",")] + +#Note, XSD's list type is split by spaces, not commas, so using xsd:string +FloatListType.createClass("stringtype","xsd:string") + + +# +# +# +# +class IntegerListType(InputType): + """ + A type for integer lists "1, 2, 3" -> [1,2,3] + """ + + @classmethod + def convert(cls, value): + """ + Converts value from string to an integer list. + @ In, value, string, the value to convert + @ Out, convert, list, the converted value + """ + return [int(x.strip()) for x in value.split(",")] + +#Note, XSD's list type is split by spaces, not commas, so using xsd:string +IntegerListType.createClass("stringtype","xsd:string") + + # # # @@ -425,7 +500,7 @@ def handleError(s): if node.tag != self.name: #should this be an error or a warning? Or even that? #handleError('XML node "{}" != param spec name "{}"'.format(node.tag,self.name)) - print('Note: XML node "{}" != param spec name "{}". This should not usually be an issue.'.format(node.tag,self.name)) + print('Using param spec "{}" to read XML node "{}.'.format(self.name,node.tag)) if self.contentType: self.value = self.contentType.convert(node.text) else: diff --git a/tests/framework/CodeInterfaceTests/test_raven_running_raven_int_models.xml b/tests/framework/CodeInterfaceTests/test_raven_running_raven_int_models.xml index a0b893d91b..2a8b50deae 100644 --- a/tests/framework/CodeInterfaceTests/test_raven_running_raven_int_models.xml +++ b/tests/framework/CodeInterfaceTests/test_raven_running_raven_int_models.xml @@ -46,7 +46,11 @@ %FRAMEWORK_DIR%/../raven_framework outputMontecarloRom_dump,outputMontecarloRomHS_dump - raven_running_raven_internal_models/testConversionModule.py + + + Models|ROM@subType:SciKitLearn@name:ROM1|C + + Models|ROM@subType:SciKitLearn@name:ROM1|C Models|ROM@subType:SciKitLearn@name:ROM1|tol Samplers|Grid@name:gridRom|constant@name:DG1recoveryTime diff --git a/tests/framework/DataObjects/load_csv_dataset.xml b/tests/framework/DataObjects/load_csv_dataset.xml index b091b08e00..9499212615 100644 --- a/tests/framework/DataObjects/load_csv_dataset.xml +++ b/tests/framework/DataObjects/load_csv_dataset.xml @@ -59,9 +59,8 @@ 3 42 - + uni - 11 0.0 diff --git a/tests/framework/Optimizers/RavenRunningRaven/inner_opt.xml b/tests/framework/Optimizers/RavenRunningRaven/inner_opt.xml index 75a994de31..828dc92443 100644 --- a/tests/framework/Optimizers/RavenRunningRaven/inner_opt.xml +++ b/tests/framework/Optimizers/RavenRunningRaven/inner_opt.xml @@ -39,6 +39,8 @@ -0.75 1 + 1 + 1 reg diff --git a/tests/framework/Optimizers/custom_vector_init.xml b/tests/framework/Optimizers/custom_vector_init.xml index 6eca404d9f..07ba4ad520 100644 --- a/tests/framework/Optimizers/custom_vector_init.xml +++ b/tests/framework/Optimizers/custom_vector_init.xml @@ -68,10 +68,9 @@ 6 -6 - + 6 -6 - 11 ans -2 - + 6 -6 0 - 11 ans diff --git a/tests/framework/Samplers/VectorSamples/gold/MC/solns.csv b/tests/framework/Samplers/VectorSamples/gold/MC/solns.csv index 6e5d57ff22..5b66cb6afc 100644 --- a/tests/framework/Samplers/VectorSamples/gold/MC/solns.csv +++ b/tests/framework/Samplers/VectorSamples/gold/MC/solns.csv @@ -1,31 +1,31 @@ -t,scalarIn,vectorIn,scalarOut,vectorOut -0,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -1,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -2,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -3,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -4,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -5,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -6,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -7,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -8,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -9,1.3745401144,2.79654298439,1.88936052609,7.82065266352 -0,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -1,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -2,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -3,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -4,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -5,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -6,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -7,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -8,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -9,1.95071431178,2.18343478771,3.8052863262,4.7673874722 -0,1.7319939385,2.77969099762,2.999803003,7.72668204227 -1,1.7319939385,2.77969099762,2.999803003,7.72668204227 -2,1.7319939385,2.77969099762,2.999803003,7.72668204227 -3,1.7319939385,2.77969099762,2.999803003,7.72668204227 -4,1.7319939385,2.77969099762,2.999803003,7.72668204227 -5,1.7319939385,2.77969099762,2.999803003,7.72668204227 -6,1.7319939385,2.77969099762,2.999803003,7.72668204227 -7,1.7319939385,2.77969099762,2.999803003,7.72668204227 -8,1.7319939385,2.77969099762,2.999803003,7.72668204227 -9,1.7319939385,2.77969099762,2.999803003,7.72668204227 +t,scalarIn,vectorIn,scalarOut,vectorOut,vectorConst1,vectorConst2 +0,1.3745401144,2.79654298439,1.88936052609,7.82065266352,1,a +1,1.3745401144,2.79654298439,1.88936052609,7.82065266352,2,b +2,1.3745401144,2.79654298439,1.88936052609,7.82065266352,3,c +3,1.3745401144,2.79654298439,1.88936052609,7.82065266352,4,d +4,1.3745401144,2.79654298439,1.88936052609,7.82065266352,5,e +5,1.3745401144,2.79654298439,1.88936052609,7.82065266352,6,f +6,1.3745401144,2.79654298439,1.88936052609,7.82065266352,7,g +7,1.3745401144,2.79654298439,1.88936052609,7.82065266352,8,h +8,1.3745401144,2.79654298439,1.88936052609,7.82065266352,9,i +9,1.3745401144,2.79654298439,1.88936052609,7.82065266352,10,j +0,1.95071431178,2.18343478771,3.8052863262,4.7673874722,1,a +1,1.95071431178,2.18343478771,3.8052863262,4.7673874722,2,b +2,1.95071431178,2.18343478771,3.8052863262,4.7673874722,3,c +3,1.95071431178,2.18343478771,3.8052863262,4.7673874722,4,d +4,1.95071431178,2.18343478771,3.8052863262,4.7673874722,5,e +5,1.95071431178,2.18343478771,3.8052863262,4.7673874722,6,f +6,1.95071431178,2.18343478771,3.8052863262,4.7673874722,7,g +7,1.95071431178,2.18343478771,3.8052863262,4.7673874722,8,h +8,1.95071431178,2.18343478771,3.8052863262,4.7673874722,9,i +9,1.95071431178,2.18343478771,3.8052863262,4.7673874722,10,j +0,1.7319939385,2.77969099762,2.999803003,7.72668204227,1,a +1,1.7319939385,2.77969099762,2.999803003,7.72668204227,2,b +2,1.7319939385,2.77969099762,2.999803003,7.72668204227,3,c +3,1.7319939385,2.77969099762,2.999803003,7.72668204227,4,d +4,1.7319939385,2.77969099762,2.999803003,7.72668204227,5,e +5,1.7319939385,2.77969099762,2.999803003,7.72668204227,6,f +6,1.7319939385,2.77969099762,2.999803003,7.72668204227,7,g +7,1.7319939385,2.77969099762,2.999803003,7.72668204227,8,h +8,1.7319939385,2.77969099762,2.999803003,7.72668204227,9,i +9,1.7319939385,2.77969099762,2.999803003,7.72668204227,10,j diff --git a/tests/framework/Samplers/VectorSamples/mc.xml b/tests/framework/Samplers/VectorSamples/mc.xml index 24deca70f4..4d49900ae7 100644 --- a/tests/framework/Samplers/VectorSamples/mc.xml +++ b/tests/framework/Samplers/VectorSamples/mc.xml @@ -48,10 +48,11 @@ u1 - + u2 - 10 + 1,2,3,4,5,6,7,8,9,10 + a,b,c,d,e,f,g,h,i,j @@ -68,8 +69,8 @@ scalarIn,vectorIn - scalarOut,vectorOut - vectorIn,vectorOut + scalarOut,vectorOut,vectorConst1,vectorConst2 + vectorIn,vectorOut,vectorConst1,vectorConst2