def __init__(self, inputsrom, outputsamples, outputgradients=None): ''' Initialize SROM surrogate using the input SROM used to generate the output samples. Output gradients are also supplied for the case of the piecewise linear surrogate. output samples have the following convention: m = SROM size (superscript), do = dimension (subscript); outputsamples = | y^(1)_1, ..., y^(1)_do | | ... , ..., ... | | y^(m)_1, ..., y^(m)_do | output samples must match the order of inputsrom samples/probs! (m x d_i array) gradients = | dy(x^{(1)})/dx_1, ..., dy(x^{(1)})/dx_di | | ... , ..., ... | | dy(x^{(m)})/dx_1, ..., dy(x^{(m)})/dx_di | do - dimension of output samples (doesn't need to equal di of input) ''' if inputsrom._samples is None or inputsrom._probs is None: raise ValueError("Input SROM must be properly initialized") self._inputsrom = inputsrom #Handle 1 dimension case, adjust shape: if len(outputsamples.shape) == 1: outputsamples.shape = (len(outputsamples), 1) #Verify dimensions of samples/probs (size, dim) = outputsamples.shape if size != self._inputsrom._size: raise ValueError("Number of output samples must match input " + " srom size!") self._outsamples = outputsamples self._dim = dim self._size = size #TODO - checks on outputgradients: if outputgradients is not None: (size__, dim__) = outputgradients.shape if size__ != self._inputsrom._size: raise ValueError("Incorrect # samples in gradient array!") if dim__ != self._inputsrom._dim: raise ValueError("Incorrect dimension in gradient array!") self._gradients = outputgradients #Make SROM for output? self._outputsrom = SROM(size, dim) self._outputsrom.set_params(outputsamples, inputsrom._probs)
import numpy as np from postprocess import Postprocessor from srom import SROM from target import SampleRandomVector ''' Generate SROM to model input distribution (samples) ''' #Specify input/output files and SROM optimization parameters dim = 3 srom_size = 20 samplesfile = "mc_data/input_samples_MC.txt" outfile = "srom_data_tmp/srom_m" + str(srom_size) + ".txt" #Define target random variable from samples MCsamples = np.genfromtxt(samplesfile) target = SampleRandomVector(MCsamples) #Define SROM, determine optimal parameters, store parameters srom = SROM(srom_size, dim) srom.optimize(target, weights=[1, 1, 1], error="SSE") #NOTE - commented out to not overwrite paper data files: #srom.save_params(outfile) #Check out the CDFs pp = Postprocessor(srom, target) pp.compare_CDFs(variablenames=[r'log$C$', r'$y_{0}$', r'$n$'])
disp_samples[i] = model.get_max_disp(k_samples[i], m_samples[i]) #Get Monte carlo solution as a sample-based random variable: mc_solution = SampleRandomVector(disp_samples) #-------------SROM----------------------- #generate SROM for random vector of stiffness & mass sromsize = 25 dim = 2 #Assume we only have access to samples in this example and want SROM from them: km_samples = np.array([k_samples, m_samples]).T km_random_vector = SampleRandomVector(km_samples) srom = SROM(sromsize, dim) srom.optimize(km_random_vector) (samples, probs) = srom.get_params() #Run model to get max disp for each SROM stiffness sample srom_disps = np.zeros(sromsize) for i in range(sromsize): k = samples[i,0] m = samples[i,1] srom_disps[i] = model.get_max_disp(k, m) #Form new SROM for the max displacement solution using samples from the model srom_solution = SROM(sromsize, 1) srom_solution.set_params(srom_disps, probs) #----------------------------------------
import numpy as np from model import Model from srom import SROM ''' Run computational model for each input SROM sample - step 2 NOTE - this script will not run, "Model" class is not provided. But this script is representative of a common SROM workflow. ''' dim = 3 srom_size = 20 sromfile = "srom_data/srom_m" + str(srom_size) + ".txt" sromeolfile = "srom_data/srom_eol_m" + str(srom_size) + ".txt" srom = SROM(srom_size, dim) srom.load_params(sromfile) srom_outputs = np.zeros(srom_size) (srom_samples, srom_probs) = srom.get_params() for i, input in enumerate(srom_samples): srom_outputs[i] = model.evaluate(input) np.savetxt(sromeolfile, srom_outputs)
dim = 3 sromsize = 10 #Data files for EOL samples, EOL finite difference samples, and SROM inputs srom_eol_file = "srom_data/srom_eol_m" + str(sromsize) + ".txt" srom_fd_eol_file = "srom_data/srom_fd_eol_m" + str(sromsize) + ".txt" srom_input_file = "srom_data/srom_m" + str(sromsize) + ".txt" #Get MC input/EOL samples MC_inputs = np.genfromtxt(mc_input_file) MC_eols = np.genfromtxt(mc_eol_file) #Get SROM EOL samples, FD samples and input SROM from file srom_eols = np.genfromtxt(srom_eol_file) srom_fd_eols = np.genfromtxt(srom_fd_eol_file) input_srom = SROM(sromsize, dim) input_srom.load_params(srom_input_file) #Get FD step sizes from file (the same for all samples, just pull the first) #Step sizes chosen as approximately 2% of the median sample value of inputs stepsizes = [0.083, 0.0065, 0.025] #Calculate gradient from FiniteDifference class: gradient = FD.compute_gradient(srom_eols, srom_fd_eols, stepsizes) #Create SROM surrogate, sample, and create random variable solution surrogate_PWL = SROMSurrogate(input_srom, srom_eols, gradient) srom_eol_samples = surrogate_PWL.sample(MC_inputs) solution_PWL = SampleRandomVector(srom_eol_samples) #Store EOL samples for plotting later:
import numpy from os import path from postprocess import Postprocessor from srom import SROM, SROMSurrogate from target import SampleRandomVector #Define target random vector from samples monte_carlo_input_samples_filename = path.join("mc_data", "input_samples_MC.txt") monte_carlo_input_samples = numpy.genfromtxt( monte_carlo_input_samples_filename) target_vector = SampleRandomVector(monte_carlo_input_samples) #Define SROM and determine optimal parameters srom_size = 20 input_srom = SROM(size=srom_size, dim=3) input_srom.optimize(target_vector) #Compare the input CDFs (produces Figure 6) post_processor = Postprocessor(input_srom, target_vector) post_processor.compare_CDFs(variablenames=[r'log$C$', r'$y_{0}$', r'$n$']) #Run the model for each input SROM sample: srom_results = numpy.zeros(srom_size) (srom_samples, srom_probs) = input_srom.get_params() # TODO: define model here. model = None if model is None: raise ValueError("model has not been defined.")
from target import SampleRandomVector ''' Ex3 - unimodal 3D Script to generate PW constant SROM approximation to EOL and compare it with the monte carlo solution (w/ surrogate model) ''' mc_eol_file = "mc_data/eol_samples_MC.txt" sromsize = 20 srom_eol_file = "srom_data/srom_eol_m" + str(sromsize) + ".txt" srom_input_file = "srom_data/srom_m" + str(sromsize) + ".txt" #Get MC EOL samples MC_eols = np.genfromtxt(mc_eol_file) #Get SROM EOL samples & probabilities from input srom srom_eols = np.genfromtxt(srom_eol_file) srom_probs = np.genfromtxt(srom_input_file)[:,-1] #probs in last column #Make MC random variable & SROM to compare eol_srom = SROM(sromsize, dim=1) eol_srom.set_params(srom_eols, srom_probs) eol_mc = SampleRandomVector(MC_eols) pp = Postprocessor(eol_srom, eol_mc) pp.compare_CDFs(variablenames=["EOL"])
''' Generate SROM to model input distribution (samples) ''' #Specify input/output files and SROM optimization parameters dim = 3 srom_size = 20 mc_input_file = "mc_data/input_samples_MC.txt" mc_eol_file = "mc_data/eol_samples_MC.txt" #Define target random variable from samples MCsamples = np.genfromtxt(samplesfile) target = SampleRandomVector(MCsamples) #Define SROM, determine optimal parameters, store parameters input_srom = SROM(srom_size, dim) input_srom.optimize(target, weights=[1,1,1], error="SSE") #Compare the CDFs pp = Postprocessor(srom, target) pp.compare_CDFs(saveFig=False) #Run the model for each input SROM sample: srom_eols = np.zeros(srom_size) (srom_samples, srom_probs) = input_srom.get_params() for i, sample in enumerate(srom_samples): srom_eols[i] = model.evaluate(sample) #Generate SROM surrogate for the output eol_srom = SROMSurrogate(input_srom, srom_eols)
#Load / initialize target random variable from samples: samples = np.genfromtxt(targetsamples) target = SampleRandomVector(samples) #Set x limits for each variable based on target: xlimits = [] for i in range(target._dim): lims = [np.min(samples[:, i]), np.max(samples[:, i])] xlimits.append(lims) #Build up sromsize-to-SROM object map for plotting routine sroms = OrderedDict() for sromsize in sromsizes: #Generate SROM from file: srom = SROM(sromsize, target._dim) sromfile = "srom_m" + str(sromsize) + ".txt" sromfile = os.path.join(srom_dir, sromfile) srom.load_params(sromfile) sroms[sromsize] = srom Postprocessor.compare_srom_CDFs(sroms, target, plotdir="plots", plotsuffix=plot_suffix, variablenames=varz, xlimits=xlimits, xticks=xticks, cdfylabel=cdfylabel)
from postprocess import Postprocessor from srom import SROM from target import NormalRandomVariable #Initialize Normal random variable object to be modeled by SROM: normal = NormalRandomVariable(mean=3., std_dev=1.5) #Initialize SROM & optimize to model the normal random variable: srom = SROM(size=10, dim=1) srom.optimize(normal) #Compare the CDF of the SROM & target normal variable: pp = Postprocessor(srom, normal) pp.compare_CDFs()
class SROMSurrogate: """ SROMPy class that provides a closed-form surrogate model for a model output that can be sampled as a means of efficiently propagating uncertainty. Enables both a piecewise-constant model and a piecewise-linear model, if gradient information is provided. :param inputsrom: The input SROM that was used to generate the outputs. :type inputsrom: SROMPy SROM object. :param outputsamples: Output samples corresponding to each input SROM sample :type outputsamples: 2d Numpy Array :param outputgradients: Gradient of output with respect to input samples :type outputgradients: 2d Numpy Array Conventions: * m denotes the SROM size (superscripts). di denotes the dimension of the SROM input (subscripts). do denotes dimension of SROM output (subscripts). * The output samples array has the following layout (m x d0): | [[ y^(1)_1, y_2^(1), ..., y_do^(1)], | [y_1^(2), y_2^(2), ..., y_d0^(2)], | ... ... ... .... | [y_1^(m), y_2^(m), ... y_d0^(m)]] * The gradients array has the following layout (m x di): | [[dy(x^{(1)})/dx_1, ..., dy(x^{(1)})/dx_di ], | ... , ..., ... | [dy(x^{(m)})/dx_1, ..., dy(x^{(m)})/dx_di ]] Note * the order of the output samples array must match the order of the samples array from the input SROM! * If gradients array is provided, the piecewise-linear surrogate model is implemented. Otherwise, the piecewise-constant surrogate is used. """ def __init__(self, inputsrom, outputsamples, outputgradients=None): ''' Initialize SROM surrogate using the input SROM used to generate the output samples. Output gradients are also supplied for the case of the piecewise linear surrogate. output samples have the following convention: m = SROM size (superscript), do = dimension (subscript); outputsamples = | y^(1)_1, ..., y^(1)_do | | ... , ..., ... | | y^(m)_1, ..., y^(m)_do | output samples must match the order of inputsrom samples/probs! (m x d_i array) gradients = | dy(x^{(1)})/dx_1, ..., dy(x^{(1)})/dx_di | | ... , ..., ... | | dy(x^{(m)})/dx_1, ..., dy(x^{(m)})/dx_di | do - dimension of output samples (doesn't need to equal di of input) ''' if inputsrom._samples is None or inputsrom._probs is None: raise ValueError("Input SROM must be properly initialized") self._inputsrom = inputsrom #Handle 1 dimension case, adjust shape: if len(outputsamples.shape) == 1: outputsamples.shape = (len(outputsamples), 1) #Verify dimensions of samples/probs (size, dim) = outputsamples.shape if size != self._inputsrom._size: raise ValueError("Number of output samples must match input " + " srom size!") self._outsamples = outputsamples self._dim = dim self._size = size #TODO - checks on outputgradients: if outputgradients is not None: (size__, dim__) = outputgradients.shape if size__ != self._inputsrom._size: raise ValueError("Incorrect # samples in gradient array!") if dim__ != self._inputsrom._dim: raise ValueError("Incorrect dimension in gradient array!") self._gradients = outputgradients #Make SROM for output? self._outputsrom = SROM(size, dim) self._outputsrom.set_params(outputsamples, inputsrom._probs) #Do these change for linear surrogate? def compute_moments(self, max_order): """ Calculates and returns SROM moments. :param max_order: Maximum order of moments to return :type max_order: int Returns (max_order x dim) size Numpy array with SROM moments for each dimension. """ return self._outputsrom.compute_moments(max_order) def compute_CDF(self, x_grid): """ Computes the SROM marginal CDF values in each dimension. :param x_grid: Grid of points to compute CDF values on. If 1d array is provided, the same points are used to evaluate CDF in each dimension. If 2d array is provided, calculates CDF values on different points, but must have same # points for each dimension. Size is (# grid pts) x (dim) or (# grid pts) x (1). :type x_grid: Numpy array. Returns: Numpy array of CDF values at x_grid points. Size is (# grid pts) x (dim). Note: * Increasing the number of grid points can significantly slow down the SROM optimization problem. * Providing a 2d array for x_grid can specify a different range of values for each dimension, but must use the same number of pts. """ return self._outputsrom.compute_CDF(x_grid) def sample(self, inputsamples): ''' Generates output samples from the SROM surrogate corresponding to the provided input samples. :param inputsamples: samples of inputs to draw output samples for :type inputsamples: 2d Numpy array. Returns: 2d Numpy array of output samples corresponding to input samples Convention: * N - number of samples. di - dimension of the input. do - dimension of the output. * input samples array has following layout (N x di): | [[x^(1)_1, ..., x^(1)_di ], | ... , ..., ... | [x^(N)_1, ..., x^(N)_di ]] * surrogate output samples has following layout (N x do): | [[y^(1)_1, ..., y^(1)_do ], | ... , ..., ... | [y^(N)_1, ..., y^(N)_do ]] Note that the samples are drawn from a piecewise-linear SROM surrogate when gradients are provided to the constructor of this class, and drawn from a piecewise-constant SROM surrogate if not. ''' #Handle 1 dimension case, adjust shape: if len(inputsamples.shape) == 1: inputsamples.shape = (len(inputsamples), 1) #Verify dimensions of samples/probs (numsamples, dim) = inputsamples.shape if dim != self._inputsrom._dim: raise ValueError("Incorrect input sample dimension") #Evaluate piecewise constant or linear surrogate model to get samples: if self._gradients is None: surr_samples = self._sample_pwconstant_surrogate(inputsamples) else: surr_samples = self._sample_pwlinear_surrogate(inputsamples) return surr_samples def _sample_pwconstant_surrogate(self, inputsamples): ''' Evaluate standard piecewise constant output surrogate model ''' inputsamples_srom = self._inputsrom._samples #Generate surrogate samples: (numsamples, _) = inputsamples.shape #Generate surrogate samples: surr_samples = np.zeros((numsamples, self._dim)) for i in range(numsamples): #Find which input SROM sample is closest to current sample sample_i = inputsamples[i, :] diff_norms = np.linalg.norm(sample_i - inputsamples_srom, axis=1) sromindex = np.argmin(diff_norms) surr_samples[i, :] = self._outsamples[sromindex, :] return surr_samples def _sample_pwlinear_surrogate(self, inputsamples): ''' Evaluate the linear output surrogate model using input SROM samples and gradients input: inputsamples = | x^(1)_1, ..., x^(1)_di | | ... , ..., ... | | x^(N)_1, ..., x^(N)_di | (mxd array) gradients = | dy(x^{(1)})/dx_1, ..., dy(x^{(1)})/dx_d | | ... , ..., ... | | dy(x^{(m)})/dx_1, ..., dy(x^{(m)})/dx_d | ''' inputsamples_srom = self._inputsrom._samples #Generate surrogate samples: (numsamples, _) = inputsamples.shape #Generate surrogate samples: surr_samples = np.zeros((numsamples, self._dim)) for i in range(numsamples): #Find which input SROM sample is closest to current sample sample_i = inputsamples[i, :] diffs = sample_i - inputsamples_srom diff_norms = np.linalg.norm(diffs, axis=1) sromindex = np.argmin(diff_norms) #Calculate ouput sample value (eq 11b from emery paper) output_k = self._outsamples[sromindex, :] diffs_k = diffs[sromindex, :] grad_k = self._gradients[sromindex, :] out = output_k + np.dot(grad_k, diffs_k) surr_samples[i, :] = out return surr_samples
stiffness_samples = stiffness_rv.draw_random_sample(num_samples) #Calculate maximum displacement samples using MC simulation disp_samples = np.zeros(num_samples) for i, stiff in enumerate(stiffness_samples): disp_samples[i] = model.get_max_disp(stiff) #Get Monte carlo solution as a sample-based random variable: mc_solution = SampleRandomVector(disp_samples) #-------------SROM----------------------- #generate SROM for random stiffness sromsize = 10 dim = 1 input_srom = SROM(sromsize, dim) input_srom.optimize(stiffness_rv) #Compare SROM vs target stiffness distribution: pp_input = Postprocessor(input_srom, stiffness_rv) pp_input.compare_CDFs() #Run model to get max disp for each SROM stiffness sample srom_disps = np.zeros(sromsize) (samples, probs) = input_srom.get_params() for i, stiff in enumerate(samples): srom_disps[i] = model.get_max_disp(stiff) #Form new SROM for the max disp. solution using samples from the model output_srom = SROM(sromsize, dim) output_srom.set_params(srom_disps, probs)