From dec9c70d7c1333035a4598d97a387b3f31ce7561 Mon Sep 17 00:00:00 2001 From: Andrea Alfonsi - NuCube Date: Fri, 7 Jun 2024 08:37:30 -0600 Subject: [PATCH] Add capability to handle interdependent functions in samplers/optimizers (#2319) * moved samplers-optimizers function tests in their own folder for clarity * renamed * modified test names and revisions * moved subfolders * Closes #2302 * usage base class function evaluation method in ensembleForward * added error msg for detection of loop in function system * added test for ensemble model passing strings (restart file paths) around * removed trailing spaces * Update ravenframework/Samplers/EnsembleForward.py * Update ravenframework/Samplers/Sampler.py * Update ravenframework/Samplers/Sampler.py * Update ravenframework/Samplers/Sampler.py * fixed comment * we always check for isolated functions * updated model.tex * changed order to reflect order of appearance in the introduction of the Model sections * modified test description to make them latex compatible * specialization for EnsembleForward and CustomSampler * Apply suggestions from code review addressed Congjian's comments * Apply suggestions from code review * Apply suggestions from code review * Update ravenframework/Samplers/Sampler.py * updated setuptools dep * updated to simply ver 69 * added utility function as Congjian's request * plot entity * model order * added starting models * Apply suggestions from code review * Update ravenframework/utils/graphStructure.py --------- Co-authored-by: Congjian Wang - INL --- doc/user_manual/model.tex | 19 ++- ravenframework/Models/EnsembleModel.py | 8 +- ravenframework/OutStreams/PlotEntity.py | 1 - ravenframework/Samplers/CustomSampler.py | 3 +- ravenframework/Samplers/EnsembleForward.py | 9 +- ravenframework/Samplers/Sampler.py | 41 ++++- ravenframework/utils/graphStructure.py | 37 ++++- .../interdependent_functions.py | 34 ++++ .../RedundantInputs/d_calc.py | 0 .../RedundantInputs/e_calc.py | 0 .../RedundantInputs/input.py | 0 .../RedundantInputs/simp_imp.py | 0 .../two_functions_module_calc.py | 0 .../mc_out.csv | 3 + .../gold/RedundantInputs/grid_out.csv | 0 .../gold/RedundantInputs/grid_out.xml | 0 .../gold/RedundantInputs/hdmr_out.csv | 0 .../gold/RedundantInputs/hdmr_out.xml | 0 .../gold/RedundantInputs/mc_out.csv | 0 .../gold/RedundantInputs/mc_out.xml | 0 .../gold/RedundantInputs/sc_out.csv | 0 .../gold/RedundantInputs/sc_out.xml | 0 .../mc_out.csv | 0 ...nterdependent_variables_from_functions.xml | 125 ++++++++++++++ .../test_redundant_inputs.xml | 3 +- ...dant_inputs_functions_same_python_file.xml | 3 +- .../test_redundant_scgpc.xml | 3 +- .../test_redundant_sobol.xml | 3 +- .../tests | 41 +++++ .../finalResponsesNoPath.csv | 3 + .../createRestart.py | 61 +++++++ .../input_code_1.xml | 6 + .../input_code_2.xml | 5 + .../useRestart.py | 57 +++++++ ...e_model_2_codes_passing_string_outputs.xml | 154 ++++++++++++++++++ tests/framework/ensembleModelTests/tests | 8 + .../hybridModel/test_logical_code.xml | 6 +- .../hybridModel/test_logical_model.xml | 2 +- .../hybridModel/test_logical_rom.xml | 4 +- tests/framework/tests | 29 ---- 40 files changed, 609 insertions(+), 59 deletions(-) create mode 100644 tests/framework/VariablesFunctionsSamplersOptimizers/InterdependentVariableFunctions/interdependent_functions.py rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/RedundantInputs/d_calc.py (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/RedundantInputs/e_calc.py (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/RedundantInputs/input.py (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/RedundantInputs/simp_imp.py (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/RedundantInputsFunctionsSameModule/two_functions_module_calc.py (100%) create mode 100644 tests/framework/VariablesFunctionsSamplersOptimizers/gold/InterdependentVariableFunctions/mc_out.csv rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/grid_out.csv (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/grid_out.xml (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/hdmr_out.csv (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/hdmr_out.xml (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/mc_out.csv (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/mc_out.xml (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/sc_out.csv (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputs/sc_out.xml (100%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/gold/RedundantInputsFunctionsSameModule/mc_out.csv (100%) create mode 100644 tests/framework/VariablesFunctionsSamplersOptimizers/test_interdependent_variables_from_functions.xml rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/test_redundant_inputs.xml (96%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/test_redundant_inputs_functions_same_python_file.xml (94%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/test_redundant_scgpc.xml (94%) rename tests/framework/{ => VariablesFunctionsSamplersOptimizers}/test_redundant_sobol.xml (95%) create mode 100644 tests/framework/VariablesFunctionsSamplersOptimizers/tests create mode 100644 tests/framework/ensembleModelTests/gold/metaModelWith2CodesOnePassingStringToOther/finalResponsesNoPath.csv create mode 100755 tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/createRestart.py create mode 100644 tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_1.xml create mode 100644 tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_2.xml create mode 100755 tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/useRestart.py create mode 100644 tests/framework/ensembleModelTests/test_ensemble_model_2_codes_passing_string_outputs.xml diff --git a/doc/user_manual/model.tex b/doc/user_manual/model.tex index 0f4c0aa252..700bfb6849 100644 --- a/doc/user_manual/model.tex +++ b/doc/user_manual/model.tex @@ -911,6 +911,14 @@ \section{Models} of Models (whose execution order is determined by the Input/Output relationships among them). If the relationships among the models evolve in a non-linear system, a Picard's Iteration scheme is employed. + \item \xmlNode{HybridModel} is a model aimed to combine reduced order models (ROMs) and + any other high-fidelity Model (i.e., Code, ExternalModel). + The ROMs will be trained based on the results from the high-fidelity model. + The accuracy of the ROMs will be evaluated based on the cross validation scores, + and the validity of the ROMs will be determined via some local validation metrics. + \item \xmlNode{LogicalModel} is a model aimed to execute ROMs, Codes and ExternalModels via a user + provided control function. The control function utilizes the inputs generated by RAVEN and the control logic + provided by the user to determine which model to execute. \item \xmlNode{PostProcessor} is a container of all the actions that can manipulate and process a data object in order to extract key information, such as statistical quantities, clustering, etc. @@ -1528,12 +1536,6 @@ \subsubsection{pickledModel} \end{lstlisting} } - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%% PostProcessor %%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\input{postprocessor.tex} - % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%% EnsembleModel Model %%%%%% @@ -1996,3 +1998,8 @@ \subsection{HybridModel} %%%%% Logical Model %%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \input{logical_model.tex} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%% PostProcessor %%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\input{postprocessor.tex} diff --git a/ravenframework/Models/EnsembleModel.py b/ravenframework/Models/EnsembleModel.py index ef295b2fe6..ebb7035596 100644 --- a/ravenframework/Models/EnsembleModel.py +++ b/ravenframework/Models/EnsembleModel.py @@ -33,7 +33,7 @@ #Internal Modules------------------------------------------------------------------------------------ from .Dummy import Dummy from ..utils import utils, InputData -from ..utils import graphStructure +from ..utils.graphStructure import evaluateModelsOrder from ..Runners import Error as rerror #Internal Modules End-------------------------------------------------------------------------------- @@ -318,17 +318,17 @@ def initialize(self,runInfo,inputs,initDict=None): outputMatch.extend(match if match is not None else []) outputMatch = list(set(outputMatch)) modelsToOutputModels[modelIn] = outputMatch + executionList, modelsGraph, _ = evaluateModelsOrder(modelsToOutputModels, acceptLoop=True, reverse=False, initialStartingModels=self.initialStartModels) # construct the ensemble model directed graph - self.ensembleModelGraph = graphStructure.graphObject(modelsToOutputModels) + self.ensembleModelGraph = modelsGraph #graphStructure.graphObject(modelsToOutputModels) # make some checks if not self.ensembleModelGraph.isConnectedNet(): isolatedModels = self.ensembleModelGraph.findIsolatedVertices() self.raiseAnError(IOError, "Some models are not connected. Possible candidates are: "+' '.join(isolatedModels)) # get all paths - allPath = self.ensembleModelGraph.findAllUniquePaths(self.initialStartModels) ################################################### # to be removed once executionList can be handled # - self.orderList = self.ensembleModelGraph.createSingleListOfVertices(allPath) + self.orderList = executionList self.raiseAMessage("Model Execution list: "+' -> '.join(self.orderList)) ################################################### ########################################################################################### diff --git a/ravenframework/OutStreams/PlotEntity.py b/ravenframework/OutStreams/PlotEntity.py index b24372fe24..179b71934a 100644 --- a/ravenframework/OutStreams/PlotEntity.py +++ b/ravenframework/OutStreams/PlotEntity.py @@ -29,7 +29,6 @@ matplotlib.use('Agg') - class Plot(OutStreamEntity): """ Handler for Plot implementations diff --git a/ravenframework/Samplers/CustomSampler.py b/ravenframework/Samplers/CustomSampler.py index 4c6834e9b2..15b6f1f05c 100644 --- a/ravenframework/Samplers/CustomSampler.py +++ b/ravenframework/Samplers/CustomSampler.py @@ -164,7 +164,8 @@ def _localGenerateAssembler(self,initDict): else: mName = val self.funcDict[key] = fPointer(mName, initDict['Functions'][val]) - + # evaluate function order in custom sampler + self._evaluateFunctionsOrder() if 'Source' not in self.assemblerDict: self.raiseAnError(IOError, "No Source object has been found!") diff --git a/ravenframework/Samplers/EnsembleForward.py b/ravenframework/Samplers/EnsembleForward.py index 56edfcab07..ced8046ee0 100644 --- a/ravenframework/Samplers/EnsembleForward.py +++ b/ravenframework/Samplers/EnsembleForward.py @@ -179,6 +179,9 @@ def _localGenerateAssembler(self, initDict): mName = val self.funcDict[key] = fPointer(mName, availableFunc[val]) + # evaluate function order in custom sampler + self._evaluateFunctionsOrder() + def localInitialize(self): """ Initialize the EnsembleForward sampler. It calls the localInitialize method of all the Samplers defined in this input @@ -247,11 +250,7 @@ def localGenerateInput(self, model, myInput): self.inputInfo['SamplerType'] = 'EnsembleForward' # Update dependent variables - for var in self.dependentSample: - test = self.funcDict[var].instance.evaluate(self.funcDict[var].methodName, self.inputInfo['SampledVars']) - for corrVar in var.split(","): - self.values[corrVar.strip()] = test - self.inputInfo['SampledVars'][corrVar.strip()] = test + self._functionalVariables() def flush(self): """ diff --git a/ravenframework/Samplers/Sampler.py b/ravenframework/Samplers/Sampler.py index 19d2b74c63..0d28fbd9c9 100644 --- a/ravenframework/Samplers/Sampler.py +++ b/ravenframework/Samplers/Sampler.py @@ -27,6 +27,7 @@ from ..BaseClasses.InputDataUser import InputDataUser from ..utils import utils,randomUtils,InputData, InputTypes +from ..utils.graphStructure import evaluateModelsOrder from ..BaseClasses import BaseEntity, Assembler class Sampler(utils.metaclass_insert(abc.ABCMeta, BaseEntity), Assembler, InputDataUser): @@ -204,11 +205,16 @@ def __init__(self): self.distDict = {} # Contains the instance of the distribution to be used, it is created every time the sampler is initialized. keys are the variable names self.funcDict = {} # Mapping between variable name and the a 2-element namedtuple namedtuple('func', ['methodName', 'instance']) containing: # element 0 (methodName): name of the method in the function to be be invoked. Either the default "evaluate", or the function name + self.variableFunctionExecutionList = [] # This is an ordered sequence of functional variable + # (linked to functions) that need to be performed (in case of + # interdependency). This list is always created. If no interdependence + # is detected, the order is just random, otherwise the order is + # determined through graph theory. # element 1 (instance): instance of the function to be used, it is created every time the sampler is initialized. self.values = {} # for each variable the current value {'var name':value} self.variableShapes = {} # stores the dimensionality of each variable by name, as tuple e.g. (2,3) for [[#,#,#],[#,#,#]] self.inputInfo = {} # depending on the sampler several different type of keywarded information could be present only one is mandatory, see below - self.initSeed = None # if not provided the seed is randomly generated at the istanciation of the sampler, the step can override the seed by sending in another seed + self.initSeed = None # if not provided the seed is randomly generated at the initialization of the sampler, the step can override the seed by sending in another one self.inputInfo['SampledVars' ] = self.values # this is the location where to get the values of the sampled variables self.inputInfo['SampledVarsPb' ] = {} # this is the location where to get the probability of the sampled variables self.inputInfo['crowDist'] = {} # Stores a dictionary that contains the information to create a crow distribution. Stored as a json object @@ -277,6 +283,9 @@ def _generateDistributions(self, availableDist, availableFunc): mName = val self.funcDict[key] = fPointer(mName, availableFunc[val]) + # evaluate function execution order + self._evaluateFunctionsOrder() + def _localGenerateAssembler(self, initDict): """ It is used for sending to the instanciated class, which is implementing the method, the objects that have been requested through "whatDoINeed" method @@ -844,6 +853,33 @@ def _expandVectorVariables(self): baseVal = self.inputInfo['SampledVars'][var] self.inputInfo['SampledVars'][var] = np.ones(shape)*baseVal + def _evaluateFunctionsOrder(self): + """ + Method to evaluate the function execution order using graph theory + The order is stored in self.variableFunctionExecutionList + @ In, None + @ Out, None + """ + functionsToVariables = {} + for var in self.funcDict: + outputMatch = [] + functionInputs = self.funcDict[var].instance.parameterNames() + for inpVar in functionInputs: + # find functions that are linked to this inpVar + if inpVar in self.funcDict: + outputMatch.append(inpVar) + outputMatch = list(set(outputMatch)) + functionsToVariables[var] = outputMatch + executionList, variableFunctionsGraph, errMsg = evaluateModelsOrder(functionsToVariables, acceptLoop=False, reverse=True) + if errMsg is not None: + self.raiseAnError(*errMsg) + if executionList: + self.variableFunctionExecutionList = executionList + self.raiseAMessage("Function Variables are interdependent") + self.raiseAMessage("Variable Evaluation and Function Execution list: "+ + ' -> '.join([f"variable:{var} | function: {self.funcDict[var].instance.name}" + for var in self.variableFunctionExecutionList])) + def _functionalVariables(self): """ Evaluates variables that are functions of other input variables. @@ -851,7 +887,7 @@ def _functionalVariables(self): @ Out, None """ # generate the function variable values - for var in self.dependentSample: + for var in self.variableFunctionExecutionList: if self.inputInfo.get('batchMode',False): for b in range(self.inputInfo['batchInfo']['nRuns']): values = self.inputInfo['batchInfo']['batchRealizations'][b]['SampledVars'] @@ -1164,3 +1200,4 @@ def flush(self): self.auxcnt = 0 self.distDict = {} self.funcDict = {} + self.variableFunctionExecutionList = [] diff --git a/ravenframework/utils/graphStructure.py b/ravenframework/utils/graphStructure.py index 0fbe63365b..6b4d22d83c 100644 --- a/ravenframework/utils/graphStructure.py +++ b/ravenframework/utils/graphStructure.py @@ -20,15 +20,50 @@ from __future__ import division, print_function, absolute_import #----- end python 2 - 3 compatibility #External Modules------------------------------------------------------------------------------------ -import sys import itertools import copy +from typing import Optional #External Modules End-------------------------------------------------------------------------------- #Internal Modules------------------------------------------------------------------------------------ from . import utils #Internal Modules End-------------------------------------------------------------------------------- +def evaluateModelsOrder(modelDict: dict, acceptLoop: Optional[bool] = True, reverse: Optional[bool] = False,initialStartingModels: Optional[list] = []): + """ + Utility method to evaluate the model/node execution order (From First(s) nodes till to the last + node(s) in the dictionary). The method uses graph theory for such evaluation. + The order, the graph object and (eventually) the error messages are returned in a tuple. + @ In, modelDict, dict, dictionary of models to outputs (e.g. {modelName1:[modelName2,modelName3],modelName2:[modelName4],..}) + @ In, acceptLoop, bool, optional, should loops be accepted? Default: True + @ In, reverse, bool, optional, should the execution list be reversed? (Ie. First to Last or Last to First) + @ In, initialStartingModels, list, optional, initial starting models in case of "non-linear" connections + @ Out, executionList, list, model execution (ordered) list + @ Out, modelsGraph, graphObject, graph object + @ Out, errMsg, tuple or None, if tuple: el[0] -> Exception, el[1] -> error msg + """ + errMsg = None # element 1 is Exception, element 2 is the error msg + if not len(modelDict): + return None, None, errMsg + modelsGraph = graphObject(modelDict) + # check for isolated models: + # isolated models are models that are not connected to other models + # consequentially thse models can be executed first (since no interdependency exists) + isolatedModels = modelsGraph.findIsolatedVertices() + executionList = isolatedModels + if len(isolatedModels) != len(modelDict): + if not acceptLoop and modelsGraph.isALoop(): + errMsg = (IOError, "Models are interdependent but connections determined a loop of dependencies that " + "is not supported in the system. Use EnsembleModel to solve such dependencies.") + return + allPath = modelsGraph.findAllUniquePaths(initialStartingModels) + executionList = modelsGraph.createSingleListOfVertices(allPath) + if reverse: + # the execution list is reversed becuase the created a graph above in reversed order (output to input) + executionList.reverse() + executionList = isolatedModels + executionList + return executionList, modelsGraph, errMsg + class graphObject(object): """ This is a class that crates a graph object. diff --git a/tests/framework/VariablesFunctionsSamplersOptimizers/InterdependentVariableFunctions/interdependent_functions.py b/tests/framework/VariablesFunctionsSamplersOptimizers/InterdependentVariableFunctions/interdependent_functions.py new file mode 100644 index 0000000000..a7997b7e22 --- /dev/null +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/InterdependentVariableFunctions/interdependent_functions.py @@ -0,0 +1,34 @@ +# 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. +import imp +import os +# the functions below are imported from the respective files +# this is aimed to show how multiple functions can be coded in the same file +d_calc = imp.load_source('d_calc', os.path.join(os.path.dirname(os.path.abspath(__file__)),'../RedundantInputs/d_calc.py')) + +def raven_d_calc_f_a_c(ravenContainer): + return d_calc.evaluate(ravenContainer) + +def raven_e_calc_f_a_c(ravenContainer): + return ravenContainer.a + ravenContainer.c + +def raven_b_calc_f_a(ravenContainer): + return ravenContainer.a*1.2 + +def raven_c_calc_f_b(ravenContainer): + return ravenContainer.b*1.2 + +def raven_z_l_calc_f_a(ravenContainer): + return ravenContainer.a*1.2 + diff --git a/tests/framework/RedundantInputs/d_calc.py b/tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/d_calc.py similarity index 100% rename from tests/framework/RedundantInputs/d_calc.py rename to tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/d_calc.py diff --git a/tests/framework/RedundantInputs/e_calc.py b/tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/e_calc.py similarity index 100% rename from tests/framework/RedundantInputs/e_calc.py rename to tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/e_calc.py diff --git a/tests/framework/RedundantInputs/input.py b/tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/input.py similarity index 100% rename from tests/framework/RedundantInputs/input.py rename to tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/input.py diff --git a/tests/framework/RedundantInputs/simp_imp.py b/tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/simp_imp.py similarity index 100% rename from tests/framework/RedundantInputs/simp_imp.py rename to tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputs/simp_imp.py diff --git a/tests/framework/RedundantInputsFunctionsSameModule/two_functions_module_calc.py b/tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputsFunctionsSameModule/two_functions_module_calc.py similarity index 100% rename from tests/framework/RedundantInputsFunctionsSameModule/two_functions_module_calc.py rename to tests/framework/VariablesFunctionsSamplersOptimizers/RedundantInputsFunctionsSameModule/two_functions_module_calc.py diff --git a/tests/framework/VariablesFunctionsSamplersOptimizers/gold/InterdependentVariableFunctions/mc_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/InterdependentVariableFunctions/mc_out.csv new file mode 100644 index 0000000000..f4942c00af --- /dev/null +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/InterdependentVariableFunctions/mc_out.csv @@ -0,0 +1,3 @@ +a,b,c,d,e,z,l,f,g,h +2.37409342951,2.84891211541,3.41869453849,8.11630024131,5.79278796799,2.84891211541,2.84891211541,6.76358203682,3.38917233333,17.1417897746 +4.35373093545,5.22447712254,6.26937254705,27.295161204,10.6231034825,5.22447712254,5.22447712254,22.7459674737,10.3522616,56.6023944473 diff --git a/tests/framework/gold/RedundantInputs/grid_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/grid_out.csv similarity index 100% rename from tests/framework/gold/RedundantInputs/grid_out.csv rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/grid_out.csv diff --git a/tests/framework/gold/RedundantInputs/grid_out.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/grid_out.xml similarity index 100% rename from tests/framework/gold/RedundantInputs/grid_out.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/grid_out.xml diff --git a/tests/framework/gold/RedundantInputs/hdmr_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/hdmr_out.csv similarity index 100% rename from tests/framework/gold/RedundantInputs/hdmr_out.csv rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/hdmr_out.csv diff --git a/tests/framework/gold/RedundantInputs/hdmr_out.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/hdmr_out.xml similarity index 100% rename from tests/framework/gold/RedundantInputs/hdmr_out.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/hdmr_out.xml diff --git a/tests/framework/gold/RedundantInputs/mc_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/mc_out.csv similarity index 100% rename from tests/framework/gold/RedundantInputs/mc_out.csv rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/mc_out.csv diff --git a/tests/framework/gold/RedundantInputs/mc_out.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/mc_out.xml similarity index 100% rename from tests/framework/gold/RedundantInputs/mc_out.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/mc_out.xml diff --git a/tests/framework/gold/RedundantInputs/sc_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/sc_out.csv similarity index 100% rename from tests/framework/gold/RedundantInputs/sc_out.csv rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/sc_out.csv diff --git a/tests/framework/gold/RedundantInputs/sc_out.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/sc_out.xml similarity index 100% rename from tests/framework/gold/RedundantInputs/sc_out.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputs/sc_out.xml diff --git a/tests/framework/gold/RedundantInputsFunctionsSameModule/mc_out.csv b/tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputsFunctionsSameModule/mc_out.csv similarity index 100% rename from tests/framework/gold/RedundantInputsFunctionsSameModule/mc_out.csv rename to tests/framework/VariablesFunctionsSamplersOptimizers/gold/RedundantInputsFunctionsSameModule/mc_out.csv diff --git a/tests/framework/VariablesFunctionsSamplersOptimizers/test_interdependent_variables_from_functions.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/test_interdependent_variables_from_functions.xml new file mode 100644 index 0000000000..f33beda7cc --- /dev/null +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/test_interdependent_variables_from_functions.xml @@ -0,0 +1,125 @@ + + + + framework.VariablesFunctionsSamplersOptimizers.interdependentVariablesFromFunctions + alfoa + 2024-05-14 + Samplers.Sampler, Functions.External + + This test is aimed to check the capability of RAVEN to treat variables that are + defined through function relations of the sampled variables that are interdependent: variables that depends + on the value of other variables that are defined through functions as well. + In this test the variables ``b'' and ``z,l'' solely depend on sampled variable a. Variable ``c'' depends + on the variable ``b'' and the variable ``e'' on variable ``c'' and sampled variable ``a''. + The order of execution that RAVEN needs to identify is consequentially: + First evaluate ``b'' and ``z,l'', then variable ``c'' and finally variable ``e''. + + + Implemented variable function interdependency (Closes #2302) + + + + + InterdependentVariableFunctions + sim_py_MC + 1 + + + + ../RedundantInputs/input.py + ../RedundantInputs/simp_imp.py + + + + + + input.py + py_script + 5factMC + mcset + mc_out + + + + + + -3 + 6 + + + + + + + 2 + 452508 + false + + + + a_dist + + + raven_b_calc_f_a + + + raven_c_calc_f_b + + + raven_d_calc_f_a_c + + + raven_e_calc_f_a_c + + + raven_z_l_calc_f_a + + + + + + + RedundantInputs/simp_imp.py + python + .py + + + + + + + + + a,c + + + a,c + + + a + + + b + + + a + + + + + + a,b,c,d,e,z,l + f,g,h + + + + + + csv + mcset + input, output + + + + + diff --git a/tests/framework/test_redundant_inputs.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs.xml similarity index 96% rename from tests/framework/test_redundant_inputs.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs.xml index 1d18ae58ac..d803f3c552 100644 --- a/tests/framework/test_redundant_inputs.xml +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs.xml @@ -1,7 +1,7 @@ - framework.redundantInputs + framework.VariablesFunctionsSamplersOptimizers.redundantInputs talbpaul 2015-06-25 Samplers.Sampler, Functions.External @@ -15,6 +15,7 @@ Updating test cases to reflect the changes to the user input. Adding this test description. Modified syntax in Functions as for issue #934 + Moved test to dedicated subfolder for test reorganization diff --git a/tests/framework/test_redundant_inputs_functions_same_python_file.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs_functions_same_python_file.xml similarity index 94% rename from tests/framework/test_redundant_inputs_functions_same_python_file.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs_functions_same_python_file.xml index 77fa4e1eb6..0c62686eb3 100644 --- a/tests/framework/test_redundant_inputs_functions_same_python_file.xml +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_inputs_functions_same_python_file.xml @@ -1,7 +1,7 @@ - framework.redundantInputsWithFunctionsInSameFile + framework.VariablesFunctionsSamplersOptimizers.redundantInputsWithFunctionsInSameFile alfoa 2024-04-15 Samplers.Sampler, Functions.External @@ -14,6 +14,7 @@ Added test and added description of the test. + Moved test to dedicated subfolder for test reorganization diff --git a/tests/framework/test_redundant_scgpc.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_scgpc.xml similarity index 94% rename from tests/framework/test_redundant_scgpc.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_scgpc.xml index 19410bbf5a..e5be0a2c10 100644 --- a/tests/framework/test_redundant_scgpc.xml +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_scgpc.xml @@ -1,7 +1,7 @@ - framework.redundantInputsSCgPC + framework.VariablesFunctionsSamplersOptimizers.redundantInputsSCgPC talbpaul 2016-01-07 Samplers.SparseGridCollocation, Functions.External @@ -16,6 +16,7 @@ Updating test cases to reflect the changes to the user input. Adding this test description. Modified syntax in Functions as for issue #934 + Moved test to dedicated subfolder for test reorganization diff --git a/tests/framework/test_redundant_sobol.xml b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_sobol.xml similarity index 95% rename from tests/framework/test_redundant_sobol.xml rename to tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_sobol.xml index b4d0386103..ee889fb4d3 100644 --- a/tests/framework/test_redundant_sobol.xml +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/test_redundant_sobol.xml @@ -1,7 +1,7 @@ - framework.redundantInputsSobol + framework.VariablesFunctionsSamplersOptimizers.redundantInputsSobol talbpaul 2016-01-07 Samplers.Sobol, Functions.External @@ -16,6 +16,7 @@ Updating test cases to reflect the changes to the user input. Adding this test description. Modified syntax in Functions as for issue #934 + Moved test to dedicated subfolder for test reorganization diff --git a/tests/framework/VariablesFunctionsSamplersOptimizers/tests b/tests/framework/VariablesFunctionsSamplersOptimizers/tests new file mode 100644 index 0000000000..9cc2f02c85 --- /dev/null +++ b/tests/framework/VariablesFunctionsSamplersOptimizers/tests @@ -0,0 +1,41 @@ +[Tests] + + [./redundantInputs] + type = 'RavenFramework' + input = 'test_redundant_inputs.xml' + output = 'RedundantInputs/mc_out.xml RedundantInputs/grid_out.xml' + csv = 'RedundantInputs/mc_out.csv RedundantInputs/grid_out.csv' + rel_err = 2.0e-3 + [../] + [./redundantInputsWithFunctionsInSameFile] + type = 'RavenFramework' + input = 'test_redundant_inputs_functions_same_python_file.xml' + output = 'RedundantInputsFunctionsSameModule/mc_out.xml' + csv = 'RedundantInputsFunctionsSameModule/mc_out.csv' + rel_err = 2.0e-3 + [../] + [./redundantInputsSCgPC] + type = 'RavenFramework' + input = 'test_redundant_scgpc.xml' + output = 'RedundantInputs/sc_out.xml' + UnorderedCsv = 'RedundantInputs/sc_out.csv' + rel_err = 1.0E-6 + [../] + [./redundantInputsSobol] + type = 'RavenFramework' + input = 'test_redundant_sobol.xml' + output = 'RedundantInputs/hdmr_out.xml' + UnorderedCsv = 'RedundantInputs/hdmr_out.csv' + rel_err = 1.0E-6 + [../] + [./interdependentVariablesFromFunctions] + type = 'RavenFramework' + input = 'test_interdependent_variables_from_functions.xml' + output = 'InterdependentVariableFunctions/mc_out.xml' + csv = 'InterdependentVariableFunctions/mc_out.csv' + rel_err = 1.0e-4 + [../] + +[] + + diff --git a/tests/framework/ensembleModelTests/gold/metaModelWith2CodesOnePassingStringToOther/finalResponsesNoPath.csv b/tests/framework/ensembleModelTests/gold/metaModelWith2CodesOnePassingStringToOther/finalResponsesNoPath.csv new file mode 100644 index 0000000000..44ada7bdc2 --- /dev/null +++ b/tests/framework/ensembleModelTests/gold/metaModelWith2CodesOnePassingStringToOther/finalResponsesNoPath.csv @@ -0,0 +1,3 @@ +multiplicationFactor,seed,Amodel1,Bmodel1,Cmodel1,Amodel2,Bmodel2,Cmodel2 +5.0,34.0,0.0138908483202,0.414824632937,0.807992818882,0.0694542416011,2.07412316468,4.03996409441 +4.0,52.0,0.0982844653369,0.521127650271,0.768805306324,0.393137861348,2.08451060108,3.07522122529 diff --git a/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/createRestart.py b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/createRestart.py new file mode 100755 index 0000000000..ec8541cf98 --- /dev/null +++ b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/createRestart.py @@ -0,0 +1,61 @@ +# 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 May 14 2024 + +@author: alfoa + +This python script/module mimics a code that creates a solution vector (CSV in this case) that +can be used by another code to restart a calculation. The solution vector is contained +in a filename that is dumped as well. +The 'restart' file name can be retrieved by RAVEN and stored in a RAVEN variable. +""" +import xml.etree.ElementTree as ET +import sys +import os +import numpy as np + +def readInput(filename): + tree = ET.parse(filename) + root = tree.getroot() + input = {} + for element in root: + input[element.tag] = element.text + return input + +if __name__ == '__main__': + if len(sys.argv) < 2: + raise Exception("No input file") + inputFileName = sys.argv[1] + initializationDict = readInput(inputFileName) + rseed = int(float(initializationDict['randomSeed'])) + ts = int(float(initializationDict['time_steps'])) + outputfile = initializationDict['outputFileName'] + variables = [var.strip() for var in initializationDict['randomVariableNames'].split(",")] + # seed + np.random.seed(rseed) + values = {} + for var in variables: + values[var] = np.random.random(size=ts) + with open(outputfile,"w") as fo: + fo.write(",".join(variables+['restartFileName'])+'\n') + for tts in range(ts): + vv = [] + for var in variables: + vv.append(str(values[var][tts])) + vv.append(os.path.abspath(outputfile)) + fo.write(",".join(vv)+'\n') + + + diff --git a/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_1.xml b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_1.xml new file mode 100644 index 0000000000..f5059fc2f7 --- /dev/null +++ b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_1.xml @@ -0,0 +1,6 @@ + + 5 + $RAVEN-seed$ + A,B,C + code_1_results.csv + diff --git a/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_2.xml b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_2.xml new file mode 100644 index 0000000000..df5ef27be5 --- /dev/null +++ b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/input_code_2.xml @@ -0,0 +1,5 @@ + + $RAVEN-multiplicationFactor$ + $RAVEN-restartInModel2$ + code_2_results.csv + diff --git a/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/useRestart.py b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/useRestart.py new file mode 100755 index 0000000000..ee85b8d67d --- /dev/null +++ b/tests/framework/ensembleModelTests/metaModelWith2CodesOnePassingStringToOther/useRestart.py @@ -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 May 14 2024 + +@author: alfoa + +This python script/module mimics a code that can retrieve a restart file containing a solution vector +(CSV in this case) and simply moltiply the content by a factor 'multiplication_factor' retrieved from +the input file. +The 'restart' file name can be inputted by RAVEN as a Sampled Variable +""" +import xml.etree.ElementTree as ET +import sys +import numpy as np +import pandas as pd + +def readInput(filename): + tree = ET.parse(filename) + root = tree.getroot() + input = {} + for element in root: + input[element.tag] = element.text + return input + +if __name__ == '__main__': + if len(sys.argv) < 2: + raise Exception("No input file") + inputFileName = sys.argv[1] + initializationDict = readInput(inputFileName) + restartFileName = initializationDict['restartFileName'] + mult = int(float(initializationDict['multiplication_factor'])) + outputfile = initializationDict['outputFileName'] + df = pd.read_csv(restartFileName) + df = df.mul(mult) + variables = df.keys() + with open(outputfile,"w") as fo: + fo.write(",".join(variables)+'\n') + for tts in range(len(df)): + vv = [] + for var in variables: + vv.append(str(df[var][tts])) + fo.write(",".join(vv)+'\n') + + + diff --git a/tests/framework/ensembleModelTests/test_ensemble_model_2_codes_passing_string_outputs.xml b/tests/framework/ensembleModelTests/test_ensemble_model_2_codes_passing_string_outputs.xml new file mode 100644 index 0000000000..831e9b9126 --- /dev/null +++ b/tests/framework/ensembleModelTests/test_ensemble_model_2_codes_passing_string_outputs.xml @@ -0,0 +1,154 @@ + + + + framework/ensembleModelTests.testEnsembleModelWith2CodesUsingVariablesToTransferStrings + alfoa + 2024-05-14 + Models.EnsembleModel, JobHandler.Thread + + The main goal of this test is to show how to the ensemble model can be used to transfer string info + from a model to the other using a RAVEN variable. In this test for example, the variable ``restart'' + is a string, containing a absolute path of a filename, that is generated by the code ``createRestart'' and + then transferred by the EnsembleModel to the second code ``useRestart''. + + + + Example on how to use current (May 2024) capabilities to transfer + string variables from a model to the other + + + + + + testEnsembleModelWith2CodesUsingVariablesToTransferStrings + sample,write + metaModelWith2CodesOnePassingStringToOther + + + + input_code_1.xml + input_code_2.xml + + + + + ../../createRestart.py + + + code_1_results.csv + python + A + B + C + restartFileName + + + ../../useRestart.py + + + python + code_2_results.csv + restartInModel2 + A + B + C + restartInModel2 + + + + createRestart + input_code_1.xml + Code1Data + + + useRestart + input_code_2.xml + Code2Data + responseModel2 + + + + + + + 0 + 100 + withReplacement + + + 1 + 5 + withReplacement + + + + + + + 2 + + + seed + + + multiplicationFactor + + + + + + + input_code_1.xml + input_code_2.xml + restartAndUse + mc + finalResponsesNoPath + responseModel2 + + + finalResponsesNoPath + responseModel2 + finalResponsesNoPath + printResponseModel2 + + + + + + csv + finalResponsesNoPath + input,output + + + csv + responseModel2 + input,output + + + + + + multiplicationFactor,seed + Amodel1,Bmodel1,Cmodel1,Amodel2,Bmodel2,Cmodel2 + + + restart,multiplicationFactor + Amodel2,Bmodel2,Cmodel2 + + + + multiplicationFactor,seed + Amodel1,Bmodel1,Cmodel1,restart + + + restart,multiplicationFactor + Amodel2,Bmodel2,Cmodel2 + + + + diff --git a/tests/framework/ensembleModelTests/tests b/tests/framework/ensembleModelTests/tests index ad245de8a9..3fa3940544 100644 --- a/tests/framework/ensembleModelTests/tests +++ b/tests/framework/ensembleModelTests/tests @@ -112,4 +112,12 @@ input = 'nd_ensemble_2outs.xml' csv = 'NDEnsemble2Outs/nd1.csv NDEnsemble2Outs/nd2.csv NDEnsemble2Outs/ps.csv' [../] + + [./testEnsembleModelWith2CodesUsingVariablesToTransferStrings] + type = 'RavenFramework' + input = 'test_ensemble_model_2_codes_passing_string_outputs.xml' + csv = 'metaModelWith2CodesOnePassingStringToOther/finalResponsesNoPath.csv' + output = 'metaModelWith2CodesOnePassingStringToOther/printResponseModel2.csv' + [../] + [] diff --git a/tests/framework/hybridModel/test_logical_code.xml b/tests/framework/hybridModel/test_logical_code.xml index 0d25c9d02c..df3645690b 100644 --- a/tests/framework/hybridModel/test_logical_code.xml +++ b/tests/framework/hybridModel/test_logical_code.xml @@ -10,10 +10,10 @@ This test is intended to check the functionality of Logical Model with the generic code system. Two simple python codes are used in this test. One is an exponential function of input variables x and y, the other one is - a polynomial function of input variables x and y. A control function "control" + a polynomial function of input variables x and y. A control function ``control'' utilizes the input values of x and y to determine which code to run. If - x > 0.5 and y > 1.5, the polynomial model 'poly' will be executed, otherwise - the exponential model 'exp' will be executed. + x > 0.5 and y > 1.5, the polynomial model ``poly'' will be executed, otherwise + the exponential model ``exp'' will be executed. diff --git a/tests/framework/hybridModel/test_logical_model.xml b/tests/framework/hybridModel/test_logical_model.xml index 5be647cf82..ee78c234dc 100644 --- a/tests/framework/hybridModel/test_logical_model.xml +++ b/tests/framework/hybridModel/test_logical_model.xml @@ -8,7 +8,7 @@ Example of usage of the Logical Model capability in RAVEN This test is intended to check the functionality of Logical Model - with three external models "sum", "minus" and "multiply". + with three external models ``sum'', ``minus'' and ``multiply''. A control function "control" is required to select the external model to run based on the values of input variables x and y. If x > 0 and y > 1, the model "sum" will be selected. if x > 0 diff --git a/tests/framework/hybridModel/test_logical_rom.xml b/tests/framework/hybridModel/test_logical_rom.xml index 599b6f8c15..8c8d70ee93 100644 --- a/tests/framework/hybridModel/test_logical_rom.xml +++ b/tests/framework/hybridModel/test_logical_rom.xml @@ -8,11 +8,11 @@ Example of usage of the Logical Model capability in RAVEN This test is intended to check the functionality of Logical Model - with ROMs. A control function "control" is required to select the right + with ROMs. A control function ``control'' is required to select the right model to run based on the values of input variables leftTemperature and rightTemperatureDist. If leftTemperature in (860,1340) and rightTemperatureDist in (740, 1460), - the ROM "svr" will be selected, else the model "thermalConductivityComputation" + the ROM ``svr'' will be selected, else the model ``thermalConductivityComputation'' will be selected. diff --git a/tests/framework/tests b/tests/framework/tests index b4df09f177..e9e86d7d96 100644 --- a/tests/framework/tests +++ b/tests/framework/tests @@ -223,35 +223,6 @@ csv = 'dists_vars/PrintPointSet_dump.csv' [../] - [./redundantInputs] - type = 'RavenFramework' - input = 'test_redundant_inputs.xml' - output = 'RedundantInputs/mc_out.xml RedundantInputs/grid_out.xml' - csv = 'RedundantInputs/mc_out.csv RedundantInputs/grid_out.csv' - rel_err = 2.0e-3 - [../] - [./redundantInputsWithFunctionsInSameFile] - type = 'RavenFramework' - input = 'test_redundant_inputs_functions_same_python_file.xml' - output = 'RedundantInputsFunctionsSameModule/mc_out.xml' - csv = 'RedundantInputsFunctionsSameModule/mc_out.csv' - rel_err = 2.0e-3 - [../] - [./redundantInputsSCgPC] - type = 'RavenFramework' - input = 'test_redundant_scgpc.xml' - output = 'RedundantInputs/sc_out.xml' - UnorderedCsv = 'RedundantInputs/sc_out.csv' - rel_err = 1.0E-6 - [../] - [./redundantInputsSobol] - type = 'RavenFramework' - input = 'test_redundant_sobol.xml' - output = 'RedundantInputs/hdmr_out.xml' - UnorderedCsv = 'RedundantInputs/hdmr_out.csv' - rel_err = 1.0E-6 - [../] - [./failrunsMC] type = 'RavenFramework' input = 'test_failruns_MC.xml'