def test_scalarQoI(self): systemsize = 3 mu = np.random.rand(systemsize) std_dev = np.diag(np.random.rand(systemsize)) jdist = cp.MvNormal(mu, std_dev) # Create QoI Object QoI = Paraboloid3D(systemsize) # Create the Monte Carlo object QoI_dict = { 'paraboloid': { 'QoI_func': QoI.eval_QoI, 'output_dimensions': 1, } } nsample = 1000000 mc_obj = MonteCarlo(nsample, jdist, QoI_dict) mc_obj.getSamples(jdist) # Get the mean and variance using Monte Carlo mu_js = mc_obj.mean(jdist, of=['paraboloid']) var_js = mc_obj.variance(jdist, of=['paraboloid']) # Analytical mean mu_j_analytical = QoI.eval_QoI_analyticalmean(mu, cp.Cov(jdist)) err = abs((mu_js['paraboloid'] - mu_j_analytical) / mu_j_analytical) self.assertTrue(err < 1e-3) # Analytical variance var_j_analytical = QoI.eval_QoI_analyticalvariance(mu, cp.Cov(jdist)) err = abs((var_js['paraboloid'] - var_j_analytical) / var_j_analytical) # print('var_js paraboloid = ', var_js['paraboloid'], '\n') self.assertTrue(err < 1e-2)
def test_hadamard_accuracy(self): systemsize = 4 eigen_decayrate = 2.0 # Create Hadmard Quadratic object QoI = examples.HadamardQuadratic(systemsize, eigen_decayrate) mu = np.zeros(systemsize) std_dev = np.eye(systemsize) jdist = cp.MvNormal(mu, std_dev) active_subspace = ActiveSubspace(QoI, n_dominant_dimensions=4, n_monte_carlo_samples=10000, use_svd=True, read_rv_samples=False, write_rv_samples=False) active_subspace.getDominantDirections(QoI, jdist) mu_j_analytical = QoI.eval_analytical_QoI_mean(mu, cp.Cov(jdist)) var_j_analytical = QoI.eval_analytical_QoI_variance(mu, cp.Cov(jdist)) # Create reduced collocation object QoI_dict = {'Hadamard' : {'QoI_func' : QoI.eval_QoI, 'output_dimensions' : 1, }, } sc_obj_active = StochasticCollocation2(jdist, 4, 'MvNormal', QoI_dict, include_derivs=False, reduced_collocation=True, dominant_dir=active_subspace.dominant_dir) sc_obj_active.evaluateQoIs(jdist) mu_j_active = sc_obj_active.mean(of=['Hadamard']) var_j_active = sc_obj_active.variance(of=['Hadamard'])
def calcMarginals(self, jdist): """ Compute the marginal density object for the dominant space. The current implementation is only for Gaussian distribution. """ marginal_size = len(self.dominant_indices) orig_mean = cp.E(jdist) orig_covariance = cp.Cov(jdist) # Step 1: Rotate the mean & covariance matrix of the the original joint # distribution along the eigenve dominant_vecs = self.iso_eigenvecs[:, self.dominant_indices] marginal_mean = np.dot(dominant_vecs.T, orig_mean) marginal_covariance = np.matmul( dominant_vecs.T, np.matmul(orig_covariance, dominant_vecs)) # Step 2: Create the new marginal distribution if marginal_size == 1: # Univariate distributions have to be treated separately marginal_std_dev = np.sqrt(np.asscalar(marginal_covariance)) self.marginal_distribution = cp.Normal(np.asscalar(marginal_mean), marginal_std_dev) else: self.marginal_distribution = cp.MvNormal(marginal_mean, marginal_covariance)
def reduced_dVariance(self, QoI_func, jdist, dominant_space, mu_j, dQoI_func, dmu_j): """ same as dVariance but in the reduced stochastic space. """ x = cp.E(jdist) rv_covariance = cp.Cov(jdist) n_quadrature_loops = len(dominant_space.dominant_indices) dominant_dir = dominant_space.iso_eigenvecs[:, dominant_space. dominant_indices] ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(n_quadrature_loops) colloc_w_arr = np.zeros(n_quadrature_loops) dvariance_j = np.zeros([self.QoI_dimensions, self.QoI_dimensions]) idx = self.doReduced_dVariance(x, rv_covariance, dominant_dir, mu_j, dmu_j, dvariance_j, ref_collocation_pts, ref_collocation_w, QoI_func, dQoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 dvariance_j[:] = dvariance_j[:] / (np.sqrt(np.pi)**n_quadrature_loops) # TODO: figure out a better way of handling arrays and matrices for this routine return dvariance_j.diagonal()
def dVariance(self, QoI_func, jdist, mu_j, dQoI_func, dmu_j): """ Computes the partial derivative of the variance This implementation is CURRENTLY ONLY for QoI's that return scalar values. """ x = cp.E(jdist) rv_covariance = cp.Cov(jdist) systemsize = x.size ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(systemsize) colloc_w_arr = np.zeros(systemsize) dvariance_j = np.zeros([self.QoI_dimensions, self.QoI_dimensions]) # dvariance_j = np.zeros(self.QoI_dimensions) idx = self.do_dVariance(x, rv_covariance, mu_j, dmu_j, dvariance_j, ref_collocation_pts, ref_collocation_w, QoI_func, dQoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 dvariance_j[:] = dvariance_j[:] / (np.sqrt(np.pi)**systemsize) # TODO: figure out a better way of handling arrays and matrices for this routine return dvariance_j.diagonal()
def test_multipleQoI(self): # This tests for multiple QoIs. We only compute the mean in this test, # because it is only checking if it can do multiple loops systemsize = 2 theta = 0 mu = mean_2dim # np.random.randn(systemsize) std_dev = std_dev_2dim # np.diag(np.random.rand(systemsize)) jdist = cp.MvNormal(mu, std_dev) QoI1 = examples.Paraboloid2D(systemsize, (theta, )) QoI2 = examples.PolyRVDV() QoI_dict = { 'paraboloid2': { 'QoI_func': QoI1.eval_QoI, 'output_dimensions': 1, }, 'PolyRVDV': { 'QoI_func': QoI2.eval_QoI, 'output_dimensions': 1, } } sc_obj = StochasticCollocation2(jdist, 3, 'MvNormal', QoI_dict) sc_obj.evaluateQoIs(jdist) mu_js = sc_obj.mean(of=['paraboloid2', 'PolyRVDV']) # Compare against known values # 1. Paraboloid2D, we use nested loops mu_j1_analytical = QoI1.eval_QoI_analyticalmean(mu, cp.Cov(jdist)) err = abs( (mu_js['paraboloid2'][0] - mu_j1_analytical) / mu_j1_analytical) self.assertTrue(err < 1.e-15)
def __init__(self, uq_systemsize): mean_v = 248.136 # Mean value of input random variable mean_alpha = 5 # mean_Ma = 0.84 mean_re = 1.e6 mean_rho = 0.38 mean_cg = np.zeros((3)) std_dev = np.diag([0.2, 0.01]) # np.diag([1.0, 0.2, 0.01, 1.e2, 0.01]) rv_dict = { # 'v' : mean_v, 'alpha': mean_alpha, 'Mach_number': mean_Ma, # 're' : mean_re, # 'rho' : mean_rho, } self.QoI = examples.OASAerodynamicWrapper(uq_systemsize, rv_dict) self.jdist = cp.Normal(self.QoI.rv_array, std_dev) self.dominant_space = DimensionReduction( n_arnoldi_sample=uq_systemsize + 1, exact_Hessian=False) self.dominant_space.getDominantDirections(self.QoI, self.jdist, max_eigenmodes=1) # print 'iso_eigenvals = ', self.dominant_space.iso_eigenvals # print 'iso_eigenvecs = ', '\n', self.dominant_space.iso_eigenvecs # print 'dominant_indices = ', self.dominant_space.dominant_indices # print 'ratio = ', abs(self.dominant_space.iso_eigenvals[0] / self.dominant_space.iso_eigenvals[1]) print 'std_dev = ', cp.Std(self.jdist), '\n' print 'cov = ', cp.Cov(self.jdist), '\n'
def getDominantDirections(self, QoI, jdist): systemsize = QoI.systemsize if self.read_file == True: rv_arr = np.loadtxt('rv_arr.txt') np.testing.assert_equal(self.n_monte_carlo_samples, rv_arr.shape[1]) else: if self.use_truncated_samples: rv_arr = self.get_truncated_samples(jdist) else: rv_arr = jdist.sample( self.n_monte_carlo_samples ) # points for computing the uncentered covariance matrix if self.write_file == True: np.savetxt('rv_arr.txt', rv_arr) pert = np.zeros(systemsize) if self.use_truncated_samples: new_samples = self.check_3sigma_violation(rv_arr, jdist) if self.use_svd == False: # Get C_tilde using Monte Carlo grad = np.zeros(systemsize) self.C_tilde = np.zeros([systemsize, systemsize]) for i in range(0, self.n_monte_carlo_samples): grad[:] = QoI.eval_QoIGradient(rv_arr[:, i], pert) self.C_tilde[:, :] += np.outer(grad, grad) self.C_tilde[:, :] = self.C_tilde[:, :] / self.n_monte_carlo_samples # Factorize C_tilde that self.iso_eigenvals, self.iso_eigenvecs = np.linalg.eig( self.C_tilde) else: # Grad matrix grad = np.zeros([systemsize, self.n_monte_carlo_samples]) for i in range(0, self.n_monte_carlo_samples): grad[:, i] = QoI.eval_QoIGradient(rv_arr[:, i], pert) grad[:, :] = grad / np.sqrt(self.n_monte_carlo_samples) # Perform SVD W, s, _ = np.linalg.svd(grad) if self.use_iso_transformation: # Do the isoprobabilistic transformation covariance = cp.Cov(jdist) sqrt_Sigma = np.sqrt(covariance) iso_grad = np.dot(grad.T, sqrt_Sigma).T # Perform SVD W, s, _ = np.linalg.svd(iso_grad) self.iso_eigenvals = s**2 self.iso_eigenvecs = W # get the indices of dominant eigenvalues in descending order sort_ind = self.iso_eigenvals.argsort()[::-1] self.iso_eigenvecs[:, :] = self.iso_eigenvecs[:, sort_ind] self.iso_eigenvals[:] = self.iso_eigenvals[sort_ind] self.dominant_indices = np.arange(0, self.n_dominant_dimensions) self.dominant_dir = self.iso_eigenvecs[:, self.dominant_indices]
def reduced_mean(self, QoI_func, jdist, dominant_space): x = cp.E(jdist) covariance = cp.Cov(jdist) n_quadrature_loops = len(dominant_space.dominant_indices) dominant_dir = dominant_space.iso_eigen_vectors[:, dominant_space. dominant_indices] ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(n_quadrature_loops) colloc_w_arr = np.zeros(n_quadrature_loops) mu_j = np.zeros(self.QoI_dimensions) idx = self.doReducedUniformMean(x, covariance, dominant_dir, mu_j, ref_collocation_pts, ref_collocation_w, QoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 # TODO: The following scaling doesnt look right, INVESTIGATE mu_j[:] = mu_j[:] * (0.5**n_quadrature_loops) if len(mu_j) == 1: return mu_j[0] else: return mu_j
def test_reduced_normalStochasticCollocation3D(self): # This is not a very good test because we are comparing the reduced collocation # against the analytical expected value. The only hting it tells us is that # the solution is within the ball park of actual value. We still need to # come up with a better test. systemsize = 3 mu = mean_3dim # np.random.randn(systemsize) std_dev = std_dev_3dim # abs(np.diag(np.random.randn(systemsize))) jdist = cp.MvNormal(mu, std_dev) # Create QoI Object QoI = examples.Paraboloid3D(systemsize) dominant_dir = np.array([[1.0, 0.0], [0.0, 1.0], [0.0, 0.0]], dtype=np.float) # Create the Stochastic Collocation object deriv_dict = { 'xi': { 'dQoI_func': QoI.eval_QoIGradient, 'output_dimensions': systemsize } } QoI_dict = { 'paraboloid': { 'QoI_func': QoI.eval_QoI, 'output_dimensions': 1, 'deriv_dict': deriv_dict } } sc_obj = StochasticCollocation2(jdist, 3, 'MvNormal', QoI_dict, reduced_collocation=True, dominant_dir=dominant_dir) sc_obj.evaluateQoIs(jdist) mu_js = sc_obj.mean(of=['paraboloid']) var_js = sc_obj.variance(of=['paraboloid']) # Analytical mean mu_j_analytical = QoI.eval_QoI_analyticalmean(mu, cp.Cov(jdist)) err = abs((mu_js['paraboloid'][0] - mu_j_analytical) / mu_j_analytical) self.assertTrue(err < 1e-1) # Analytical variance var_j_analytical = QoI.eval_QoI_analyticalvariance(mu, cp.Cov(jdist)) err = abs( (var_js['paraboloid'][0, 0] - var_j_analytical) / var_j_analytical) self.assertTrue(err < 0.01)
def run_hadamard(systemsize, eigen_decayrate, std_dev, n_eigenmodes): n_collocation_pts = 2 # Create Hadmard Quadratic object QoI = examples.HadamardQuadratic(systemsize, eigen_decayrate) # # Create stochastic collocation object # collocation = StochasticCollocation(n_collocation_pts, "Normal") # Initialize chaospy distribution x = np.random.rand(QoI.systemsize) jdist = cp.MvNormal(x, np.diag(std_dev)) threshold_factor = 0.5 dominant_space = DimensionReduction(threshold_factor=threshold_factor, exact_Hessian=False, n_arnoldi_sample=71, min_eigen_accuracy=1.e-2) dominant_space.getDominantDirections(QoI, jdist, max_eigenmodes=n_eigenmodes) # if systemsize == 64: # print('x = \n', repr(x)) # print('std_dev = \n', repr(std_dev)) # print('iso_eigenvals = ', dominant_space.iso_eigenvals) # print("dominant_indices = ", dominant_space.dominant_indices) # Collocate # collocation = StochasticCollocation(n_collocation_pts, "Normal") # mu_j = collocation.normal.reduced_mean(QoI.eval_QoI, jdist, dominant_space) # print "mu_j = ", mu_j QoI_dict = { 'Hadamard': { 'QoI_func': QoI.eval_QoI, 'output_dimensions': 1, }, } sc_obj = StochasticCollocation2(jdist, n_collocation_pts, 'MvNormal', QoI_dict, include_derivs=False, reduced_collocation=True, dominant_dir=dominant_space.dominant_dir) sc_obj.evaluateQoIs(jdist) mu_j_dict = sc_obj.mean(of=['Hadamard']) mu_j = mu_j_dict['Hadamard'] # Evaluate the analytical value of the Hadamard Quadratic covariance = cp.Cov(jdist) mu_analytic = QoI.eval_analytical_QoI_mean(x, covariance) # print "mu_analytic = ", mu_analytic relative_error = np.linalg.norm((mu_j - mu_analytic) / mu_analytic) # print "relative_error = ", relative_error return relative_error
def test_orth_ttr(): dist = cp.Normal(0, 1) orth = cp.orth_ttr(5, dist) outer = cp.outer(orth, orth) Cov1 = cp.E(outer, dist) Diatoric = Cov1 - np.diag(np.diag(Cov1)) assert np.allclose(Diatoric, 0) Cov2 = cp.Cov(orth[1:], dist) assert np.allclose(Cov1[1:,1:], Cov2)
def test_normalStochasticCollocation3D(self): systemsize = 3 mu = mean_3dim # np.random.randn(systemsize) std_dev = std_dev_3dim # np.diag(np.random.rand(systemsize)) jdist = cp.MvNormal(mu, std_dev) # Create QoI Object QoI = examples.Paraboloid3D(systemsize) # Create the Stochastic Collocation object deriv_dict = { 'xi': { 'dQoI_func': QoI.eval_QoIGradient, 'output_dimensions': systemsize } } QoI_dict = { 'paraboloid': { 'quadrature_degree': 3, 'reduced_collocation': False, 'QoI_func': QoI.eval_QoI, 'output_dimensions': 1, 'include_derivs': False, 'deriv_dict': deriv_dict } } sc_obj = StochasticCollocation3(jdist, 'MvNormal', QoI_dict) sc_obj.evaluateQoIs(jdist) mu_js = sc_obj.mean(of=['paraboloid']) var_js = sc_obj.variance(of=['paraboloid']) # Analytical mean mu_j_analytical = QoI.eval_QoI_analyticalmean(mu, cp.Cov(jdist)) err = abs((mu_js['paraboloid'][0] - mu_j_analytical) / mu_j_analytical) self.assertTrue(err < 1.e-15) # Analytical variance var_j_analytical = QoI.eval_QoI_analyticalvariance(mu, cp.Cov(jdist)) err = abs( (var_js['paraboloid'][0, 0] - var_j_analytical) / var_j_analytical) self.assertTrue(err < 1.e-15)
def reduced_variance(self, QoI_func, jdist, dominant_space, mu_j): """ Public member that is used to perform stochastic collocation only along certain directions to compute the variance of a QoI. **Inputs** * `QoI_func` : Quantity of Interest function to be evaluated * `jdist` : joint distribution object of the random variables * `dominant_space` : Array of vectors along which the stochastic collocation is performed. **Outputs** * `mu_j` : Mean value of the Quantity of Interest for a given mean value of random variabes """ x = cp.E(jdist) rv_covariance = cp.Cov(jdist) n_quadrature_loops = len(dominant_space.dominant_indices) dominant_dir = dominant_space.iso_eigenvecs[:, dominant_space. dominant_indices] ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(n_quadrature_loops) colloc_w_arr = np.zeros(n_quadrature_loops) variance_j = np.zeros([self.QoI_dimensions, self.QoI_dimensions]) idx = self.doReducedNormalVariance(x, rv_covariance, dominant_dir, mu_j, variance_j, ref_collocation_pts, ref_collocation_w, QoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 variance_j[:] = variance_j[:] / (np.sqrt(np.pi)**n_quadrature_loops) if len(variance_j) == 1: return variance_j[0] else: return variance_j
def Corr(poly, dist=None, **kws): """ Correlation matrix of a distribution or polynomial. Args: poly (numpoly.ndpoly, Distribution): Input to take correlation on. Must have ``len(poly)>=2``. dist (Distribution): Defines the space the correlation is taken on. It is ignored if ``poly`` is a distribution. Returns: (numpy.ndarray): Correlation matrix with ``correlation.shape == poly.shape+poly.shape``. Examples: >>> distribution = chaospy.MvNormal( ... [3, 4], [[2, .5], [.5, 1]]) >>> chaospy.Corr(distribution).round(4) array([[1. , 0.3536], [0.3536, 1. ]]) >>> q0 = chaospy.variable() >>> poly = chaospy.polynomial([q0, q0**2]) >>> distribution = chaospy.Normal() >>> chaospy.Corr(poly, distribution).round(4) array([[1., 0.], [0., 1.]]) """ if isinstance(poly, chaospy.Distribution): poly, dist = numpoly.variable(len(poly)), poly else: poly = numpoly.polynomial(poly) if not poly.shape: return numpy.ones((1, 1)) cov = chaospy.Cov(poly, dist, **kws) var = numpy.diag(cov) vvar = numpy.sqrt(numpy.outer(var, var)) return numpy.where(vvar > 0, cov / vvar, 0)
def get_iso_gradients(dv_dict): """ Computes the gradient of the scaneagle problem in the isoprobabilistic space w.r.t the random variables. """ UQObj.QoI.p['oas_scaneagle.wing.twist_cp'] = dv_dict['twist_cp'] UQObj.QoI.p['oas_scaneagle.wing.thickness_cp'] = dv_dict['thickness_cp'] UQObj.QoI.p['oas_scaneagle.wing.sweep'] = dv_dict['sweep'] UQObj.QoI.p['oas_scaneagle.alpha'] = dv_dict['alpha'] mu_val = cp.E(UQObj.jdist) covariance = cp.Cov(UQObj.jdist) sqrt_Sigma = np.sqrt(covariance) # !!!! ONLY FOR INDEPENDENT RVs !!!! print('mu_val = ', mu_val) print('covariance = ', covariance) # print('sqrt_Sigma = \n', sqrt_Sigma) grad = UQObj.QoI.eval_QoIGradient(mu_val, np.zeros(len(mu_val))) iso_grad = np.dot(grad, sqrt_Sigma) return iso_grad, grad
def mean(self, QoI_func, jdist): x = cp.E(jdist) covariance = cp.Cov(jdist) systemsize = x.size ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(systemsize) colloc_w_arr = np.zeros(systemsize) mu_j = np.zeros(self.QoI_dimensions) idx = self.doUniformMean(x, covariance, mu_j, ref_collocation_pts, ref_collocation_w, QoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 mu_j[:] = mu_j[:] * (0.5**systemsize) if len(mu_j) == 1: return mu_j[0] else: return mu_j
def __init__(self, nsamples, jdist, QoI_dict, include_derivs=False, reduced_collocation=False, dominant_dir=None, data_type=np.float): assert nsamples > 0, "Number of MonteCarlo samples must be greater than 0" self.num_samples = nsamples self.data_type = data_type # To enable complex variables self.QoI_dict = utils.copy_qoi_dict(QoI_dict) if reduced_collocation == False: self.samples = jdist.sample(self.num_samples) else: # !!! This implementation is only for normal distribution !!! # Get the number of dominant directions ndims = dominant_dir.shape[1] mu = cp.E(jdist) covariance = cp.Cov(jdist) sqrt_Sigma = np.sqrt(covariance) # This assumes the random variables are independent if ndims > 1: self.iso_jdist = cp.MvNormal(np.zeros(ndims), np.eye(ndims)) self.iso_samples = self.iso_jdist.sample(self.num_samples) int_mat = np.matmul(sqrt_Sigma, dominant_dir) self.samples = np.add(np.einsum('ij,jk', int_mat, self.iso_samples).T, mu).T else: self.iso_jdist = cp.Normal() self.iso_samples = self.iso_jdist.sample(self.num_samples) int_mat = np.matmul(sqrt_Sigma, dominant_dir) # print(np.outer(int_mat, self.iso_samples)) self.samples = np.add(np.outer(int_mat, self.iso_samples).T, mu).T for i in self.QoI_dict: self.QoI_dict[i]['fvals'] = np.zeros([self.num_samples, self.QoI_dict[i]['output_dimensions']], dtype=self.data_type) if include_derivs == True: for i in self.QoI_dict: for j in self.QoI_dict[i]['deriv_dict']: self.QoI_dict[i]['deriv_dict'][j]['fvals'] = np.zeros([self.num_samples, self.QoI_dict[i]['output_dimensions'], self.QoI_dict[i]['deriv_dict'][j]['output_dimensions']], dtype=self.data_type)
def variance(self, QoI_func, jdist, mu_j): """ Public member that is used to perform stochastic collocation only along certain directions to compute the variance of a QoI. **Inputs** * `QoI` : Quantity of Interest Object * `jdist` : joint distribution object of the random variables * `mu_j` : Mean value of the quantity of interest **Outputs** * `variance_j` : variance of the Quantity of Interest for a given mean value of random variabes """ # np.testing.assert_equal(len(mu_j), self.QoI_dimensions) # sanity check x = cp.E(jdist) rv_covariance = cp.Cov(jdist) systemsize = x.size ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(systemsize) colloc_w_arr = np.zeros(systemsize) variance_j = np.zeros([self.QoI_dimensions, self.QoI_dimensions]) idx = self.doVariance(x, rv_covariance, mu_j, variance_j, ref_collocation_pts, ref_collocation_w, QoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 variance_j[:] = variance_j[:] / (np.sqrt(np.pi)**systemsize) if len(variance_j) == 0: return variance_j[0] else: return variance_j
def variance(self, QoI_func, jdist, mu_j): x = cp.E(jdist) rv_covariance = cp.Cov(jdist) systemsize = x.size ref_collocation_pts = self.q ref_collocation_w = self.w idx = 0 colloc_xi_arr = np.zeros(systemsize) colloc_w_arr = np.zeros(systemsize) variance_j = np.zeros(1) idx = self.doVariance(x, rv_covariance, mu_j, variance_j, ref_collocation_pts, ref_collocation_w, QoI_func, colloc_xi_arr, colloc_w_arr, idx) assert idx == -1 variance_j[:] = variance_j[:] * (0.5**systemsize) if len(variance_j) == 1: return variance_j[0] else: return variance_j
def test_reducedCollocation(self): systemsize = 4 eigen_decayrate = 2.0 # Create Hadmard Quadratic object QoI = examples.HadamardQuadratic(systemsize, eigen_decayrate) # Create stochastic collocation object collocation = StochasticCollocation(3, "Normal") # Create dimension reduction object threshold_factor = 0.9 dominant_space = DimensionReduction(threshold_factor=threshold_factor, exact_Hessian=True) # Initialize chaospy distribution std_dev = 0.2 * np.ones(QoI.systemsize) x = np.ones(QoI.systemsize) jdist = cp.MvNormal(x, np.diag(std_dev)) # Get the eigenmodes of the Hessian product and the dominant indices dominant_space.getDominantDirections(QoI, jdist) QoI_func = QoI.eval_QoI # Check the mean mu_j = collocation.normal.reduced_mean(QoI_func, jdist, dominant_space) true_value_mu_j = 4.05 err = abs(mu_j - true_value_mu_j) self.assertTrue(err < 1.e-13) # Check the variance red_var_j = collocation.normal.reduced_variance( QoI_func, jdist, dominant_space, mu_j) # var_j = collocation.normal.variance(QoI_func, jdist, mu_j) analytical_var_j = QoI.eval_analytical_QoI_variance(x, cp.Cov(jdist)) err = abs(analytical_var_j - red_var_j) self.assertTrue(err < 1.e-4)
def getQuadratureInfo(self, jdist, quadrature_degree, ref_collocation_pts, ref_collocation_w): """ Generates the integration points at which the deterministic QoI needs to be evaluated, and also the corresponding quadrature weights. """ self.n_quadrature_loops = self.n_rv self.n_points = quadrature_degree**self.n_quadrature_loops covariance = cp.Cov(jdist) idx = 0 ctr = 0 colloc_xi_arr = np.zeros(self.n_rv) colloc_w_arr = np.zeros(self.n_rv) self.points = np.zeros([self.n_points, self.n_rv], dtype=self.data_type) self.quadrature_weights = np.zeros(self.n_points, dtype=self.data_type) sqrt_Sigma = np.sqrt(covariance) idx, ctr = self.__compute_quad(sqrt_Sigma, ref_collocation_pts, ref_collocation_w, colloc_xi_arr, colloc_w_arr, self.points, self.quadrature_weights, idx, ctr) assert idx == -1 self.points += cp.E(jdist)
def getReducedQuadratureInfo(self, jdist, dominant_dir, quadrature_degree, ref_collocation_pts, ref_collocation_w): """ Generates the integration points at which the deterministic QoI needs to be evaluated for the reduced stochastic space, and also the corresponding quadrature weights. """ n_quadrature_loops = dominant_dir.shape[1] n_points = quadrature_degree**n_quadrature_loops covariance = cp.Cov(jdist) idx = 0 ctr = 0 colloc_xi_arr = np.zeros(n_quadrature_loops) colloc_w_arr = np.zeros(n_quadrature_loops) points = np.zeros([n_points, self.n_rv], dtype=self.data_type) quadrature_weights = np.zeros(n_points, dtype=self.data_type) sqrt_Sigma = np.sqrt(covariance) idx, ctr = self.__compute_reduced_quad( sqrt_Sigma, dominant_dir, ref_collocation_pts, ref_collocation_w, colloc_xi_arr, colloc_w_arr, points, quadrature_weights, idx, ctr) assert idx == -1 points += cp.E(jdist) return points, quadrature_weights
def test_descriptives(): dist = cp.Iid(cp.Normal(), dim) orth = cp.orth_ttr(order, dist) cp.E(orth, dist) cp.Var(orth, dist) cp.Cov(orth, dist)
from dimension_reduction import DimensionReduction from stochastic_arnoldi.arnoldi_sample import ArnoldiSampling import examples # V_orig = np.array([[-np.sqrt(3)/2, -0.5],[-0.5, np.sqrt(3)/2]]) # V2 = np.array([-0.5, np.sqrt(3)/2]) mu = np.zeros(2) theta = np.pi / 3 tuple = (theta, ) QoI = examples.Paraboloid2D(2, tuple) sigma = np.ones(2) jdist = cp.MvNormal(mu, np.diag(sigma)) Hessian = QoI.eval_QoIHessian(mu, np.zeros(2)) covariance = cp.Cov(jdist) sqrt_Sigma = np.sqrt(covariance) Hessian_Product = np.matmul(sqrt_Sigma, np.matmul(Hessian, sqrt_Sigma)) eigenvalues, V_orig = np.linalg.eig(Hessian_Product) sort_ind = eigenvalues.argsort() eigenvalues[:] = eigenvalues[sort_ind] V_orig[:, :] = V_orig[:, sort_ind] V2 = V_orig[:, 1] theta_bar = np.arctan(V2[1] / V2[0]) # contour plot n_xi = 100 xi_min = [-3.0, -3.0] xi_max = [3.0, 3.0] xi_1 = np.linspace(xi_min[0], xi_max[0], n_xi) xi_2 = np.linspace(xi_min[1], xi_max[1], n_xi)
from oas_aerodynamic_group import OASAerodynamic p = Problem() dvs = p.model.add_subsystem('des_vars', IndepVarComp(), promotes_outputs=['*']) N_RANDOM = 2 DEGREE = 3 N_SAMPLES = DEGREE**N_RANDOM SCLOC_Q, SCLOC_W = np.polynomial.hermite.hermgauss(DEGREE) x_init = np.zeros(N_RANDOM) dvs.add_output('mu', val=x_init) J_dist = cp.MvNormal(x_init, np.eye(N_RANDOM)) co_mat = cp.Cov(J_dist) class Rosenbrock_OMDAO(ExplicitComponent): """ Base class that computes the deterministic Rosenbrock function. """ def initialize(self): self.options.declare('size', types=int) def setup(self): self.add_input('rv', val = np.zeros(N_RANDOM)) # rv = random variable self.add_output('fval', val=0.0) self.declare_partials('fval', 'rv') def compute(self, inputs, outputs):
def getDominantDirections(self, QoI, jdist, **kwargs): """ Given a Quantity of Interest and a jpint distribution of the random variables, this function computes the directions along which the function is most nonlinear. We call these nonlinear directions as dominant directions. **Arguments** * `QoI` : QuantityOfInterest object * `jdist` : Joint distribution object """ mu = cp.E(jdist) covariance = cp.Cov(jdist) # Check if variance covariance matrix is diagonal if np.count_nonzero(covariance - np.diag(np.diagonal(covariance))) == 0: sqrt_Sigma = np.sqrt(covariance) else: raise NotImplementedError # TODO: Break the long if blocks into functions if self.use_exact_Hessian == True: # Get the Hessian of the QoI xi = np.zeros(QoI.systemsize) Hessian = QoI.eval_QoIHessian(mu, xi) # Compute the eigen modes of the Hessian of the Hadamard Quadratic Hessian_Product = np.matmul(sqrt_Sigma, np.matmul(Hessian, sqrt_Sigma)) self.iso_eigenvals, self.iso_eigenvecs = np.linalg.eig( Hessian_Product) self.num_sample = QoI.systemsize # Next, # Get the system energy of Hessian_Product system_energy = np.sum(self.iso_eigenvals) ind = [] # get the indices of dominant eigenvalues in descending order sort_ind = self.iso_eigenvals.argsort()[::-1] # Check the threshold for i in range(0, self.num_sample): dominant_eigen_val_ind = sort_ind[0:i + 1] reduced_energy = np.sum( self.iso_eigenvals[dominant_eigen_val_ind]) if reduced_energy <= self.threshold_factor * system_energy: ind.append(dominant_eigen_val_ind[i]) else: break if len(ind) == 0: ind.append(np.argmax(self.iso_eigenvals)) self.dominant_indices = ind else: # approximate the hessian of the QoI in the isoprobabilistic space # 1. Initialize ArnoldiSampling object # Check if the system size is smaller than the number of arnoldi sample - 1 if QoI.systemsize < self.num_sample - 1: self.num_sample = QoI.systemsize + 1 arnoldi = ArnoldiSampling(self.sample_radius, self.num_sample) # 2. Declare arrays # 2.1 iso-eigenmodes self.iso_eigenvals = np.zeros(self.num_sample - 1) self.iso_eigenvecs = np.zeros( [QoI.systemsize, self.num_sample - 1]) # 2.2 solution and function history array mu_iso = np.zeros(QoI.systemsize) gdata0 = np.zeros([QoI.systemsize, self.num_sample]) # 3. Approximate eigenvalues using ArnoldiSampling # 3.1 Convert x into a standard normal distribution mu_iso[:] = 0.0 gdata0[:, 0] = np.dot( QoI.eval_QoIGradient(mu, np.zeros(QoI.systemsize)), sqrt_Sigma) dim, error_estimate = arnoldi.arnoldiSample( QoI, jdist, mu_iso, gdata0, self.iso_eigenvals, self.iso_eigenvecs) # Check how many eigen pairs are good. We will exploit the fact that # the eigen pairs are already sorted in a descending order. We will # only use "good" eigen pairs to estimate the dominant directions. ctr = 0 for i in range(0, dim): if error_estimate[i] < self.min_eigen_accuracy: ctr += 1 else: break # print('error_estimate = ', error_estimate) # Compute the accumulated energy # acc_energy = np.sum(np.square(self.iso_eigenvals[0:ctr])) # Compute the magnitude of the eigenvalues w.r.t the largest eigenvalues relative_ratio = self.iso_eigenvals[0:ctr] / self.iso_eigenvals[0] # We will only use eigenpairs which whose relative size > discard_ratio # Since we are considering the size we consider the absolute magnitude usable_pairs = np.where( np.abs(relative_ratio) > self.discard_ratio) if 'max_eigenmodes' in kwargs: max_eigenmodes = kwargs['max_eigenmodes'] if usable_pairs[0].size < max_eigenmodes: self.dominant_indices = usable_pairs[0] else: self.dominant_indices = usable_pairs[0][0:max_eigenmodes] else: self.dominant_indices = usable_pairs[0] # For either of the two cases of Exact hessian or inexact Hessian, we # specify the dominant indices self.dominant_dir = self.iso_eigenvecs[:, self.dominant_indices]
def run_hadamard(systemsize, eigen_decayrate, std_dev, n_eigenmodes): n_collocation_pts = 3 # Create Hadmard Quadratic object QoI = examples.HadamardQuadratic(systemsize, eigen_decayrate) # Initialize chaospy distribution x = np.random.rand(QoI.systemsize) jdist = cp.MvNormal(x, np.diag(std_dev)) threshold_factor = 1.0 use_exact_Hessian = False if use_exact_Hessian: dominant_space = DimensionReduction(threshold_factor=threshold_factor, exact_Hessian=True) dominant_space.getDominantDirections(QoI, jdist) dominant_dir = dominant_space.iso_eigenvecs[:, 0:n_eigenmodes] else: dominant_space = DimensionReduction(threshold_factor=threshold_factor, exact_Hessian=False, n_arnoldi_sample=71, min_eigen_accuracy=1.e-2) dominant_space.getDominantDirections(QoI, jdist, max_eigenmodes=n_eigenmodes) dominant_dir = dominant_space.dominant_dir # print "dominant_indices = ", dominant_space.dominant_indices # Create stochastic collocation object # collocation = StochasticCollocation(n_collocation_pts, "Normal") QoI_dict = { 'Hadamard': { 'QoI_func': QoI.eval_QoI, 'output_dimensions': 1, }, } sc_obj = StochasticCollocation2(jdist, n_collocation_pts, 'MvNormal', QoI_dict, include_derivs=False, reduced_collocation=True, dominant_dir=dominant_dir) sc_obj.evaluateQoIs(jdist) # Collocate # mu_j = collocation.normal.reduced_mean(QoI, jdist, dominant_space) mu_j = sc_obj.mean(of=['Hadamard']) var_j = sc_obj.variance(of=['Hadamard']) std_dev_j = np.sqrt(var_j['Hadamard']) # print "mu_j = ", mu_j # Evaluate the analytical value of the Hadamard Quadratic covariance = cp.Cov(jdist) mu_analytic = QoI.eval_analytical_QoI_mean(x, covariance) var_analytic = QoI.eval_analytical_QoI_variance(x, covariance) std_dev_analytic = np.sqrt(var_analytic) # print "mu_analytic = ", mu_analytic relative_error_mu = np.linalg.norm( (mu_j['Hadamard'] - mu_analytic) / mu_analytic) relative_err_var = np.linalg.norm( (var_j['Hadamard'] - var_analytic) / var_analytic) relative_err_std_dev = np.linalg.norm( (std_dev_j - std_dev_analytic) / std_dev_analytic) # print "relative_error = ", relative_error return relative_error_mu, relative_err_var, relative_err_std_dev
mu, std_dev = utils.get_scaneagle_input_rv_statistics(rv_dict) jdist = cp.MvNormal(mu, std_dev) # Step 1: Instantiate all objects needed for test QoI.p['oas_scaneagle.wing.thickness_cp'] = optimal_dv_dict[dv_dict_key]['thickness_cp'] QoI.p['oas_scaneagle.wing.twist_cp'] = optimal_dv_dict[dv_dict_key]['twist_cp'] QoI.p['oas_scaneagle.wing.sweep'] = optimal_dv_dict[dv_dict_key]['sweep'] QoI.p['oas_scaneagle.alpha'] = optimal_dv_dict[dv_dict_key]['alpha'] QoI.p.final_setup() # Get the direction number dir_no = int(sys.argv[3]) npts = 11 rdo_range = 9.0 # 3.0 sqrt_Sigma = np.sqrt(cp.Cov(jdist)) v_samples = np.linspace(-rdo_range, rdo_range, num=npts) # Create vector for plucking out points in the isoprobabilistic space e_i = np.zeros(uq_systemsize) e_i[dir_no] = 1.0 fval_arr = np.zeros(npts) for pts in range(0, npts): rvs = mu + np.dot(sqrt_Sigma, np.dot(iso_eigenvecs, v_samples[pts] * e_i)) # Update the random variables QoI.update_rv(rvs) QoI.p.run_model() fval_arr[pts] = QoI.p['oas_scaneagle.AS_point_0.fuelburn'] # Write to file combined_arr = np.array([v_samples, fval_arr]) fname = './V' + str(dir_no) + '/fburn_vs_V' + str(dir_no) + '_' + dv_dict_key + '.txt'
def test_descriptives(): dist = cp.Iid(cp.Normal(), dim) orth = cp.expansion.stieltjes(order, dist) cp.E(orth, dist) cp.Var(orth, dist) cp.Cov(orth, dist)