Source code for UQpy.surrogates.polynomial_chaos.physics_informed.ReducedPCE

import numpy as np
import copy
import UQpy.surrogates.polynomial_chaos.physics_informed.Utilities as utils
from beartype import beartype
from UQpy.surrogates.polynomial_chaos.PolynomialChaosExpansion import PolynomialChaosExpansion
from UQpy.surrogates.polynomial_chaos.polynomials.baseclass.PolynomialBasis import PolynomialBasis
from UQpy.surrogates.polynomial_chaos.polynomials.baseclass.Polynomials import Polynomials

[docs]class ReducedPCE: @beartype def __init__(self, pce: PolynomialChaosExpansion, n_deterministic: int, deterministic_positions: list = None): """ Class to create a reduced PCE filtering out deterministic input variables (e.g. geometry) :param pce: an object of the :py:meth:`UQpy` :class:`PolynomialChaosExpansion` class :param n_deterministic: number of deterministic input variables :param deterministic_positions: list of positions of deterministic random variables in input vector. If None, positions are assumed to be the first n_det variables. """ if deterministic_positions is None: deterministic_positions = list(np.arange(n_deterministic)) self.original_multindex = pce.multi_index_set self.original_beta = pce.coefficients self.original_P, self.nvar = self.original_multindex.shape self.original_pce = pce self.determ_pos = deterministic_positions # select basis containing only deterministic variables determ_multi_index = np.zeros(self.original_multindex.shape) determ_selection_mask = [False] * self.nvar for i in deterministic_positions: determ_selection_mask[i] = True determ_multi_index[:, determ_selection_mask] = self.original_multindex[:, determ_selection_mask] self.determ_multi_index = determ_multi_index.astype(int) self.determ_basis = PolynomialBasis.construct_arbitrary_basis(self.nvar, self.original_pce.polynomial_basis.distributions, self.determ_multi_index) reduced_multi_mask = self.original_multindex > 0 reduced_var_mask = [True] * self.nvar for i in deterministic_positions: reduced_var_mask[i] = False reduced_multi_mask = reduced_multi_mask * reduced_var_mask reduced_multi_index = np.zeros(self.original_multindex.shape) + (self.original_multindex * reduced_multi_mask) reduced_multi_index = reduced_multi_index[:, reduced_var_mask] self.reduced_positions = reduced_multi_mask.sum(axis=1) > 0 reduced_multi_index = reduced_multi_index[self.reduced_positions, :] unique_basis, unique_positions, self.unique_indices = np.unique(reduced_multi_index, axis=0, return_index=True, return_inverse=True) P_unique, nrand = unique_basis.shape self.unique_basis = np.concatenate((np.zeros((1, nrand)), unique_basis), axis=0)
[docs] @beartype def evaluate_coordinate(self, coordinates: np.ndarray, return_coefficients: bool = False): """ Evaluate reduced PCE coefficients for given deterministic coordinates. :param coordinates: deterministic coordinates for evaluation of reduced PCE :param return_coefficients: if True, return a vector of deterministic coefficients, else return Mean and Variance :return: mean and variance, or a vector of deterministic coefficients if return_coeff """ coord_x = np.zeros((1, self.nvar)) coord_x[0, self.determ_pos] = coordinates determ_basis_eval = PolynomialBasis(self.nvar, len(self.determ_multi_index), self.determ_multi_index, self.determ_basis, self.original_pce.polynomial_basis.distributions).evaluate_basis( coord_x) return self._unique_coefficients(determ_basis_eval, return_coefficients)
[docs] @beartype def derive_coordinate(self, coordinates: np.ndarray, derivative_order: int, leading_variable: int, derivative_multiplier: float = 1, return_coefficients: bool = False): """ Evaluate derivative of reduced PCE coefficients for given deterministic coordinates. :param coordinates: deterministic coordinates for evaluation of reduced PCE :param derivative_order: derivation order of reduced PCE :param leading_variable: leading variable for derivation :param derivative_multiplier: multiplier reflecting different sizes of the original physical and transformed spaces :param return_coefficients: if True, return a vector of deterministic coefficients, else return Mean and Variance :return: mean and variance, or a vector of deterministic coefficients if return_coeff """ coord_x = np.zeros((1, self.nvar)) coord_x[0, self.determ_pos] = coordinates coord_s = Polynomials.standardize_sample(coord_x, self.original_pce.polynomial_basis.distributions) determ_multi_index = np.zeros(self.original_multindex.shape) determ_selection_mask = np.arange(self.nvar) == self.determ_pos determ_multi_index[:, determ_selection_mask] = self.original_multindex[:, determ_selection_mask] determ_multi_index = determ_multi_index.astype(int) pce_deriv = copy.deepcopy(self.original_pce) pce_deriv.multi_index_set = determ_multi_index determ_basis_eval = utils.derivative_basis(coord_s, pce_deriv, derivative_order=derivative_order, leading_variable=leading_variable) * ( derivative_multiplier) return self._unique_coefficients(determ_basis_eval, return_coefficients)
[docs] @beartype def variance_contributions(self, unique_beta: np.ndarray): """ Get first order conditional variances from coefficients of reduced PCE evaluated in the specified deterministic physical coordinates :param unique_beta: vector of reduced PCE coefficients :return: first order conditional variances associated to each input random variable """ variance = np.sum(unique_beta[1:] ** 2) multi_index_set = self.unique_basis terms, inputs_number = multi_index_set.shape variances = np.zeros(inputs_number) # take all multi-indices except 0-index idx_no_0 = np.delete(multi_index_set, 0, axis=0) for nn in range(inputs_number): # remove nn-th column idx_no_0_nn = np.delete(idx_no_0, nn, axis=1) # we want the rows with all indices (except nn) equal to zero sum_idx_rows = np.sum(idx_no_0_nn, axis=1) zero_rows = np.asarray(np.where(sum_idx_rows == 0)).flatten() + 1 variance_contribution = np.sum(unique_beta[zero_rows] ** 2, axis=0) variances[nn] = variance_contribution return variances
def _unique_coefficients(self, determ_basis_eval, return_coefficients): determ_beta = np.transpose(determ_basis_eval * self.original_beta) reduced_beta = determ_beta[self.reduced_positions] complement_beta = determ_beta[~self.reduced_positions] unique_beta = [] for ind in np.unique(self.unique_indices): sum_beta = np.sum(reduced_beta[self.unique_indices == ind, 0]) unique_beta.append(sum_beta) unique_beta = np.array([0] + unique_beta) unique_beta[0] = unique_beta[0] + np.sum(complement_beta) if not return_coefficients: mean = unique_beta[0] var = np.sum(unique_beta[1:] ** 2) return mean, var else: return unique_beta