From b15f4942932dd4040364c986127f6b46d83e51dc Mon Sep 17 00:00:00 2001 From: kohlhaasrebecca <rebecca.kohlhaas@outlook.com> Date: Mon, 29 Jan 2024 11:12:16 +0100 Subject: [PATCH] Finalized UMBridge example UMBridge examples cleaned and pylink 'single-valued' removed --- .../example_umbridge.py | 183 ------------------ .../example_umbridge_testmodel.py | 24 +-- .../example_umbridge_tsunamitutorial.py | 183 ++++++++++++++++++ .../umbridge_tsunamitutorial/testmodel.pk1 | Bin 12063 -> 0 bytes .../umbridge_tsunamitutorial/testmodel.py | 20 -- .../umbridge_tsunamitutorial/tsunami_model.py | 4 +- .../tsunami_model1.py | 4 +- src/bayesvalidrox/pylink/pylink.py | 45 +++-- 8 files changed, 221 insertions(+), 242 deletions(-) delete mode 100644 examples/umbridge_tsunamitutorial/example_umbridge.py create mode 100644 examples/umbridge_tsunamitutorial/example_umbridge_tsunamitutorial.py delete mode 100644 examples/umbridge_tsunamitutorial/testmodel.pk1 delete mode 100644 examples/umbridge_tsunamitutorial/testmodel.py diff --git a/examples/umbridge_tsunamitutorial/example_umbridge.py b/examples/umbridge_tsunamitutorial/example_umbridge.py deleted file mode 100644 index b83175cf7..000000000 --- a/examples/umbridge_tsunamitutorial/example_umbridge.py +++ /dev/null @@ -1,183 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Dec 11 14:03:23 2023 - -Example and test for using umbridge with bayesvalidrox. -Example model is the tsunami model by -docker run -it -p 4242:4242 -v ~/tsunami_output:/output linusseelinger/model-exahype-tsunami - -@author: rkohlhaas -""" - -import joblib -import numpy as np -import umbridge - -import bayesvalidrox as bv - - -if __name__ == '__main__': - - # This model has 2 inputs and four outputs - n_prior_sample = 1000 - priors = bv.Input() - priors.add_marginals() - priors.Marginals[0].name = 'x' - priors.Marginals[0].input_data = np.random.uniform(50,150,n_prior_sample) - priors.add_marginals() - priors.Marginals[1].name = 'y' - priors.Marginals[1].input_data = np.random.uniform(50,150,n_prior_sample) - - # Define the model - level 0 - model0 = bv.PyLinkForwardModel() - #model.link_type = 'Function' - model0.link_type = 'umbridge' - model0.py_file = 'tsunami_model' - model0.name = 'tsunami_model' - model0.Output.names = ['T1', 'T2', 'H1', 'H2'] - #model.observations = data_dict1_times - - # Define the model - level 1 - model1 = bv.PyLinkForwardModel() - #model.link_type = 'Function' - model1.link_type = 'umbridge' - model1.py_file = 'tsunami_model1' - model1.name = 'tsunami_model1' - model1.Output.names = ['T1', 'T2', 'H1', 'H2'] - #model.observations = data_dict1_times - - # Create the surrogate - surrogate_opts0 = bv.MetaModel(priors, model0) - - # Select your metamodel method - surrogate_opts0.meta_model_type = 'aPCE' - surrogate_opts0.pce_reg_method = 'FastARD' - surrogate_opts0.pce_deg = np.arange(1, 5) - surrogate_opts0.pce_q_norm = 0.4#1.0 - - # Select your metamodel method - surrogate_opts0.add_ExpDesign() - surrogate_opts0.ExpDesign.method = 'normal' - surrogate_opts0.ExpDesign.n_init_samples = 50 - surrogate_opts0.ExpDesign.sampling_method = 'latin-hypercube' - surrogate0 = surrogate_opts0.create_metamodel() - print('Surrogate 0 completed') - print('') - - # Create the surrogate - surrogate_opts1 = bv.MetaModel(priors, model1) - - # Select your metamodel method - surrogate_opts1.meta_model_type = 'aPCE' - surrogate_opts1.pce_reg_method = 'FastARD' - surrogate_opts1.pce_deg = np.arange(1, 5) - surrogate_opts1.pce_q_norm = 0.4#1.0 - - # Select your metamodel method - surrogate_opts1.add_ExpDesign() - surrogate_opts1.ExpDesign.method = 'normal' - surrogate_opts1.ExpDesign.n_init_samples = 50 - surrogate_opts1.ExpDesign.sampling_method = 'latin-hypercube' - surrogate1 = surrogate_opts1.create_metamodel() - print('Surrogate 1 completed') - print('') - - # Save surrogate - with open('tsunami0.pk1', 'wb') as output: - joblib.dump(surrogate0, output, 2) - - # Save surrogate - with open('tsunami1.pk1', 'wb') as output: - joblib.dump(surrogate1, output, 2) - - if 0: - # Post processing - L2_PostPCE = bv.PostProcessing(surrogate1) - L2_PostPCE.plot_moments(plot_type='line') - # Plot to check validation visually. - L2_PostPCE.valid_metamodel(n_samples=1) - # Compute and print RMSE error - L2_PostPCE.check_accuracy(n_samples=300) - total_sobol = L2_PostPCE.sobol_indices() - - # Test BayesInference - import copy - from tsunami_model import tsunami_model - true_data = tsunami_model(np.array([[90.0,60.0]])) - model0.observations = true_data - model1.observations = true_data - true_data_nox = copy.deepcopy(true_data) - true_data_nox.pop('x_values') - - # Test surrogate output shape - mean, std = surrogate1.eval_metamodel(np.array([[90.0,60.0]])) - - # Bayesian Inference - if 0: - # Set uncertainty - import pandas as pd - obsData = pd.DataFrame(true_data_nox, columns=model0.Output.names) - DiscrepancyOpts = bv.Discrepancy('') - DiscrepancyOpts.type = 'Gaussian' - DiscrepancyOpts.parameters = (obsData*0.15)**2 - - # Parameter estimation / single model validation via TOM - BayesOpts = bv.BayesInference(surrogate1) - BayesOpts.emulator= True - BayesOpts.plot_post_pred = True - #BayesOpts.inference_method = 'rejection' - BayesOpts.Discrepancy = DiscrepancyOpts - BayesOpts.bootstrap = True - BayesOpts.n_bootstrap_itrs = 10 - BayesOpts.bootstrap_noise = 0.05 - BayesOpts.out_dir = '' - - # Set the MCMC parameters - import emcee - BayesOpts.inference_method = "MCMC" - BayesOpts.mcmc_params = { - 'n_steps': 1e3, - 'n_walkers': 30, - 'moves': emcee.moves.KDEMove(), - 'multiprocessing': False, - 'verbose': False - } - - Bayes = BayesOpts.create_inference() - # Pkl the inference results - with open(f'Bayes_{model0.name}.pkl', 'wb') as output: - joblib.dump(Bayes, output, 2) - - # Model Comparison - if 1: - # Set the models - meta_models = { - "M0": surrogate0, - "M1": surrogate1, - } - - # BME Bootstrap options - opts_bootstrap = { - "bootstrap": True, - "n_samples": 1000, - "Discrepancy": DiscrepancyOpts, - "emulator": True, - "plot_post_pred": False - } - - # Run model comparison - BayesOpts = bv.BayesModelComparison( - justifiability=True, - n_bootstarp=10, - just_n_meas=2 - ) - output_dict = BayesOpts.create_model_comparison( - meta_models, - opts_bootstrap - ) - - import pickle as pkl - # save model comparison results - with open('ModelComparison.pkl', 'wb') as f: - pkl.dump(output_dict, f) - \ No newline at end of file diff --git a/examples/umbridge_tsunamitutorial/example_umbridge_testmodel.py b/examples/umbridge_tsunamitutorial/example_umbridge_testmodel.py index 95ec964fa..22a0f750e 100644 --- a/examples/umbridge_tsunamitutorial/example_umbridge_testmodel.py +++ b/examples/umbridge_tsunamitutorial/example_umbridge_testmodel.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- """ -Created on Mon Dec 11 14:03:23 2023 +Example and test for using UM-Bridge with bayesvalidrox. +This example uses the `testmodel` and sets the model type explicitly as +UM-Bridge for the pylink model. -Example and test for using umbridge with bayesvalidrox. -Example model is the tsunami model by -docker run -it -p 4242:4242 -v ~/tsunami_output:/output linusseelinger/model-exahype-tsunami +An example for using UM-Bridge with an explicitly defined model can be found in +`example_umbridge_tsunamimodel.py` -@author: rkohlhaas """ import joblib @@ -31,32 +31,30 @@ if __name__ == '__main__': priors.Marginals[0].name = 'x' priors.Marginals[0].input_data = np.random.uniform(50,150,n_prior_sample) - # Define the model - level 0 + # Define the model directly via Pylink model = PyLinkForwardModel() - #model.link_type = 'Function' - #model.py_file = 'testmodel' - #model.name = 'testmodel' model.link_type = 'umbridge' model.host = 'http://testmodel.linusseelinger.de' model.modelparams = {} model.name = 'testmodel' model.Output.names = ['y'] - model.output_type = 'single-valued' + model.x_values = np.array([0]) # Create the surrogate surrogate_opts = MetaModel(priors) - # Select your metamodel method + # Select the surrogate type and properties surrogate_opts.meta_model_type = 'aPCE' surrogate_opts.pce_reg_method = 'FastARD' surrogate_opts.pce_deg = np.arange(1, 5) surrogate_opts.pce_q_norm = 0.4 - # Select your metamodel method + # Define the experimental design and sampling methods ExpDesign = ExpDesigns(priors) ExpDesign.n_init_samples = 50 ExpDesign.sampling_method = 'latin-hypercube' + # Start and run the engine engine = Engine(surrogate_opts, model, ExpDesign) engine.start_engine() engine.train_normal(parallel = False) @@ -70,8 +68,10 @@ if __name__ == '__main__': # Post processing L2_PostPCE = PostProcessing(engine) L2_PostPCE.plot_moments(plot_type='line') + # Plot to check validation visually. L2_PostPCE.valid_metamodel(n_samples=1) + # Compute and print RMSE error L2_PostPCE.check_accuracy(n_samples=300) total_sobol = L2_PostPCE.sobol_indices() diff --git a/examples/umbridge_tsunamitutorial/example_umbridge_tsunamitutorial.py b/examples/umbridge_tsunamitutorial/example_umbridge_tsunamitutorial.py new file mode 100644 index 000000000..c456787d0 --- /dev/null +++ b/examples/umbridge_tsunamitutorial/example_umbridge_tsunamitutorial.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- +""" +Example and test for using UM-Bridge with bayesvalidrox. +Example model is the tsunami model described here: + https://um-bridge-benchmarks.readthedocs.io/en/docs/inverse-benchmarks/exahype-tsunami.html +It needs to run separately while starting this example. + docker run -it -p 4242:4242 -v ~/tsunami_output:/output linusseelinger/model-exahype-tsunami + +This example uses models that are exmplicitly defined as functions outside of +PyLink. An example for the link_type 'umbdridge' can be found in +`example_umbridge_testmodel.py`. + +""" + +import copy +import joblib +import numpy as np +import pandas as pd +import umbridge + +import bayesvalidrox as bv +from tsunami_model import tsunami_model + +if __name__ == '__main__': + # This model has 2 inputs and four outputs + n_prior_sample = 1000 + priors = bv.Input() + priors.add_marginals() + priors.Marginals[0].name = 'x' + priors.Marginals[0].input_data = np.random.uniform(50,150,n_prior_sample) + priors.add_marginals() + priors.Marginals[1].name = 'y' + priors.Marginals[1].input_data = np.random.uniform(50,150,n_prior_sample) + + # Define the model - level 0 + model0 = bv.PyLinkForwardModel() + model0.link_type = 'function' + model0.py_file = 'tsunami_model' + model0.name = 'tsunami_model' + model0.Output.names = ['T1', 'T2', 'H1', 'H2'] + #model.observations = data_dict1_times + + # Define the model - level 1 + model1 = bv.PyLinkForwardModel() + model1.link_type = 'function' + model1.py_file = 'tsunami_model1' + model1.name = 'tsunami_model1' + model1.Output.names = ['T1', 'T2', 'H1', 'H2'] + #model.observations = data_dict1_times + + # Create the surrogate + surrogate_opts0 = bv.MetaModel(priors, model0) + + # Select your metamodel method + surrogate_opts0.meta_model_type = 'aPCE' + surrogate_opts0.pce_reg_method = 'FastARD' + surrogate_opts0.pce_deg = np.arange(1, 5) + surrogate_opts0.pce_q_norm = 0.4#1.0 + + # Define ExpDesign - this is the same for both models + ExpDesign0 = bv.ExpDesigns(priors) + ExpDesign0.method = 'normal' + ExpDesign0.n_init_samples = 50 + ExpDesign0.sampling_method = 'latin-hypercube' + ExpDesign1 = copy.deepcopy(ExpDesign0) + + # Start and run the engine + engine0 = bv.Engine(surrogate_opts0, model0, ExpDesign0) + engine0.start_engine() + engine0.train_normal(parallel = False) + print('Surrogate 0 completed') + print('') + + # Create the surrogate + surrogate_opts1 = bv.MetaModel(priors, model1) + + # Select your metamodel method + surrogate_opts1.meta_model_type = 'aPCE' + surrogate_opts1.pce_reg_method = 'FastARD' + surrogate_opts1.pce_deg = np.arange(1, 5) + surrogate_opts1.pce_q_norm = 0.4#1.0 + + # Start and run the engine + engine1 = bv.Engine(surrogate_opts1, model1, ExpDesign1) + engine1.start_engine() + engine1.train_normal(parallel = False) + print('Surrogate 1 completed') + print('') + + # Save surrogate + with open('tsunami0.pk1', 'wb') as output: + joblib.dump(engine0.MetaModel, output, 2) + + # Save surrogate + with open('tsunami1.pk1', 'wb') as output: + joblib.dump(engine1.MetaModel, output, 2) + + # Post processing on model 1 + L2_PostPCE = bv.PostProcessing(engine1) + L2_PostPCE.plot_moments(plot_type='line') + # Plot to check validation visually. + L2_PostPCE.valid_metamodel(n_samples=1) + + # Compute and print RMSE error + L2_PostPCE.check_accuracy(n_samples=300) + total_sobol = L2_PostPCE.sobol_indices() + + # Get reference evaluation as 'true data' + true_data = tsunami_model(np.array([[90.0,60.0]])) + model0.observations = true_data + model1.observations = true_data + true_data_nox = copy.deepcopy(true_data) + true_data_nox.pop('x_values') + + # Direct surrogate evaluation + mean, std = engine1.MetaModel.eval_metamodel(np.array([[90.0,60.0]])) + + # Bayesian Inference + # Set uncertainty + obsData = pd.DataFrame(true_data_nox, columns=model0.Output.names) + DiscrepancyOpts = bv.Discrepancy('') + DiscrepancyOpts.type = 'Gaussian' + DiscrepancyOpts.parameters = (obsData*0.15)**2 + + # Parameter estimation / single model validation via TOM for model 1 + BayesOpts = bv.BayesInference(engine1) + BayesOpts.emulator= True + BayesOpts.plot_post_pred = True + #BayesOpts.inference_method = 'rejection' + BayesOpts.Discrepancy = DiscrepancyOpts + BayesOpts.bootstrap = True + BayesOpts.n_bootstrap_itrs = 10 + BayesOpts.bootstrap_noise = 0.05 + BayesOpts.out_dir = '' + + # Set the MCMC parameters + import emcee + BayesOpts.inference_method = "MCMC" + BayesOpts.mcmc_params = { + 'n_steps': 1e3, + 'n_walkers': 30, + 'moves': emcee.moves.KDEMove(), + 'multiprocessing': False, + 'verbose': False + } + + Bayes = BayesOpts.create_inference() + + # Pkl the inference results + with open(f'Bayes_{model0.name}.pkl', 'wb') as output: + joblib.dump(Bayes, output, 2) + + # Model Comparison + # Set the models + meta_models = { + "M0": engine0, + "M1": engine1, + } + + # BME Bootstrap options + opts_bootstrap = { + "bootstrap": True, + "n_samples": 1000, + "Discrepancy": DiscrepancyOpts, + "emulator": True, + "plot_post_pred": False + } + + # Run model comparison + BayesOpts = bv.BayesModelComparison( + justifiability=True, + n_bootstarp=10, + just_n_meas=2 + ) + output_dict = BayesOpts.create_model_comparison( + meta_models, + opts_bootstrap + ) + + # save model comparison results + with open('ModelComparison.pkl', 'wb') as f: + joblib.dump(output_dict, f) + \ No newline at end of file diff --git a/examples/umbridge_tsunamitutorial/testmodel.pk1 b/examples/umbridge_tsunamitutorial/testmodel.pk1 deleted file mode 100644 index 700c643fc23e631a23cb23dd0972954904268377..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12063 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 ULH8_6w`rJ;EflFKay{w)03D*=fdBvi diff --git a/examples/umbridge_tsunamitutorial/testmodel.py b/examples/umbridge_tsunamitutorial/testmodel.py deleted file mode 100644 index b213d2a3a..000000000 --- a/examples/umbridge_tsunamitutorial/testmodel.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Runs the umbridge command for the tsunami model - -@author: Rebecca Kohlhaas -""" -import umbridge -import numpy as np - -def testmodel(params): - # Get the model - model = umbridge.HTTPModel('http://testmodel.linusseelinger.de', 'forward') - # Run the model - params = np.ndarray.tolist(params) - out = np.array(model(params)) - #print(out) - return {'y':out[:,0],'x_values':[0]} - - - \ No newline at end of file diff --git a/examples/umbridge_tsunamitutorial/tsunami_model.py b/examples/umbridge_tsunamitutorial/tsunami_model.py index 7f8e54170..2d837a9ae 100644 --- a/examples/umbridge_tsunamitutorial/tsunami_model.py +++ b/examples/umbridge_tsunamitutorial/tsunami_model.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- """ -Runs the umbridge command for the tsunami model - -@author: Rebecca Kohlhaas +Runs the umbridge command for the tsunami model. """ import umbridge import numpy as np diff --git a/examples/umbridge_tsunamitutorial/tsunami_model1.py b/examples/umbridge_tsunamitutorial/tsunami_model1.py index 3e56801e5..239670773 100644 --- a/examples/umbridge_tsunamitutorial/tsunami_model1.py +++ b/examples/umbridge_tsunamitutorial/tsunami_model1.py @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- """ -Runs the umbridge command for the tsunami model - -@author: Rebecca Kohlhaas +Runs the umbridge command for the tsunami model on level 1. """ import umbridge import numpy as np diff --git a/src/bayesvalidrox/pylink/pylink.py b/src/bayesvalidrox/pylink/pylink.py index 5084f1cf1..8899447c5 100644 --- a/src/bayesvalidrox/pylink/pylink.py +++ b/src/bayesvalidrox/pylink/pylink.py @@ -473,6 +473,8 @@ class PyLinkForwardModel(object): # TODO: if umbridge, just run, no parallel from here # If the link type is UM-Bridge, then no parallel needs to be started from here if self.link_type.lower() == 'umbridge': + if not hasattr(self, 'x_values'): + raise AttributeError('For model type `umbridge` the attribute `x_values` needs to be set for the model!') # Init model #model = umbridge.HTTPModel('http://localhost:4242', 'forward') self.model = umbridge.HTTPModel(self.host, 'forward') # TODO: is this always forward? @@ -608,30 +610,31 @@ class PyLinkForwardModel(object): out_dict = {} cnt = 0 for key in self.Output.names: - # If needed resort into single-value outputs - if self.output_type == 'single-valued': - if out.shape[1]>1: # TODO: this doesn't fully seem correct?? - for i in range(out[:,key]): # TODO: this doesn't fully seem correct?? - new_key = key+str(i) - if new_key not in self.Output.names: - self.Output.names.append(new_key) - if i == 0: - self.Ouptut.names.remove(key) - out_dict[new_key] = out[:,cnt,i] # TODO: not sure about this, need to test - else: - out_dict[key] = out[:,cnt] - - - else: - out_dict[key] = out[:,cnt] + # # If needed resort into single-value outputs + # if self.output_type == 'single-valued': + # if out.shape[1]>1: # TODO: this doesn't fully seem correct?? + # for i in range(out[:,key]): # TODO: this doesn't fully seem correct?? + # new_key = key+str(i) + # if new_key not in self.Output.names: + # self.Output.names.append(new_key) + # if i == 0: + # self.Ouptut.names.remove(key) + # out_dict[new_key] = out[:,cnt,i] # TODO: not sure about this, need to test + # else: + # out_dict[key] = out[:,cnt] + # + # + # else: + out_dict[key] = out[:,cnt] cnt += 1 - # TODO: how to deal with the x-values? - if self.output_type == 'single-valued': - out_dict['x_values'] = [0] - else: - out_dict['x_values'] = np.arange(0,out[:,0].shape[0],1) + ## TODO: how to deal with the x-values? + #if self.output_type == 'single-valued': + # out_dict['x_values'] = [0] + #else: + # out_dict['x_values'] = np.arange(0,out[:,0].shape[0],1) + out_dict['x_values'] = self.x_values #return {'T1':out[:,0], 'T2':out[:,1], 'H1':out[:,2], 'H2':out[:,3], # 'x_values':[0]} -- GitLab