def calculate_gradients_cfd(samples, data, normalize=True): """ Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map. THIS METHOD IS DEPENDENT ON USING :meth:~bet.sensitivity.pick_cfd_points TO CHOOSE SAMPLES FOR THE CFD STENCIL AROUND EACH CENTER. THE ORDERING MATTERS. :param samples: Samples for which the model has been solved. :type samples: :class:`np.ndarray` of shape (2*Lambda_dim*num_centers, Lambda_dim) :param data: QoI values corresponding to each sample. :type data: :class:`np.ndarray` of shape (num_samples, Data_dim) :rtype: :class:`np.ndarray` of shape (num_samples, Data_dim, Lambda_dim) :returns: Tensor representation of the gradient vectors of each QoI map at each point in centers """ num_model_samples = samples.shape[0] Lambda_dim = samples.shape[1] num_centers = num_model_samples / (2*Lambda_dim + 1) # Find rvec from the first cluster of samples rvec = samples[num_centers:num_centers + Lambda_dim, :] - samples[0, :] rvec = util.fix_dimensions_vector_2darray(rvec.diagonal()) # Clean the data data = util.fix_dimensions_vector_2darray(util.clean_data( data[num_centers:])) num_qois = data.shape[1] gradient_tensor = np.zeros([num_centers, num_qois, Lambda_dim]) rvec = np.tile(np.repeat(rvec, num_qois, axis=1), [num_centers, 1]) # Construct indices for CFD gradient approxiation inds = np.repeat(range(0, 2 * Lambda_dim * num_centers, 2 * Lambda_dim), Lambda_dim) + np.tile(range(0, Lambda_dim), num_centers) inds = np.array([inds, inds+Lambda_dim]).transpose() gradient_mat = (data[inds[:, 0]] - data[inds[:, 1]]) * (0.5 / rvec) # Reshape and organize gradient_tensor = np.reshape(gradient_mat.transpose(), [num_qois, Lambda_dim, num_centers], order='F').transpose(2, 0, 1) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor/np.tile(norm_gradient_tensor, (Lambda_dim, 1, 1)).transpose(1, 2, 0) return gradient_tensor
def calculate_gradients_cfd(samples, data, normalize=True): """ Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map. THIS METHOD IS DEPENDENT ON USING :meth:~bet.sensitivity.pick_cfd_points TO CHOOSE SAMPLES FOR THE CFD STENCIL AROUND EACH CENTER. THE ORDERING MATTERS. :param samples: Samples for which the model has been solved. :type samples: :class:`np.ndarray` of shape (2*Lambda_dim*num_centers, Lambda_dim) :param data: QoI values corresponding to each sample. :type data: :class:`np.ndarray` of shape (num_samples, Data_dim) :param boolean normalize: If normalize is True, normalize each gradient vector :rtype: :class:`np.ndarray` of shape (num_samples, Data_dim, Lambda_dim) :returns: Tensor representation of the gradient vectors of each QoI map at each point in centers """ num_model_samples = samples.shape[0] Lambda_dim = samples.shape[1] num_centers = num_model_samples / (2*Lambda_dim + 1) # Find rvec from the first cluster of samples rvec = samples[num_centers:num_centers + Lambda_dim, :] - samples[0, :] rvec = util.fix_dimensions_vector_2darray(rvec.diagonal()) # Clean the data data = util.fix_dimensions_vector_2darray(util.clean_data( data[num_centers:])) num_qois = data.shape[1] gradient_tensor = np.zeros([num_centers, num_qois, Lambda_dim]) rvec = np.tile(np.repeat(rvec, num_qois, axis=1), [num_centers, 1]) # Construct indices for CFD gradient approxiation inds = np.repeat(range(0, 2 * Lambda_dim * num_centers, 2 * Lambda_dim), Lambda_dim) + np.tile(range(0, Lambda_dim), num_centers) inds = np.array([inds, inds+Lambda_dim]).transpose() gradient_mat = (data[inds[:, 0]] - data[inds[:, 1]]) * (0.5 / rvec) # Reshape and organize gradient_tensor = np.reshape(gradient_mat.transpose(), [num_qois, Lambda_dim, num_centers], order='F').transpose(2, 0, 1) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, ord=1, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor/np.tile(norm_gradient_tensor, (Lambda_dim, 1, 1)).transpose(1, 2, 0) return gradient_tensor
def test_hypersphere(self): """ Test :meth:`bet.calculateP.indicatorFunctions.hypersphere` """ indicator = ifun.hypersphere(self.center, self.radius) assert np.all(indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_sphere))
def test_hyperrectangle_size(self): """ Test :meth:`bet.calculateP.indicatorFunctions.hyperrectangle_size` """ indicator = ifun.hyperrectangle_size(self.center, self.width) assert np.all(indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_rect))
def test_hypersphere(self): """ Test :meth:`bet.calculateP.indicatorFunctions.hypersphere` """ indicator = ifun.hypersphere(self.center, self.radius) assert np.all( indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_sphere))
def test_hyperrectangle(self): """ Test :meth:`bet.calculateP.indicatorFunctions.hyperrectangle` """ indicator = ifun.hyperrectangle(self.left, self.right) assert np.all( indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_rect))
def test_fix_dimensions_vector_2darray(): """ Tests :meth:`bet.util.fix_dimensions_vector_2darray` """ values = [1, [1], np.empty((1, 1)), range(5), np.array(range(5)), np.empty((5, 1))] shapes = [(1, 1), (1, 1), (1, 1), (5, 1), (5, 1), (5, 1)] for value, shape in zip(values, shapes): vector = util.fix_dimensions_vector_2darray(value) assert vector.shape == shape
def test_boundary_hyperrectangle(self): """ Test :meth:`bet.calculateP.indicatorFunctions.boundary_hyperrectangle` """ indicator = ifun.boundary_hyperrectangle(self.left, self.right, self.boundary_width) assert False == np.all(indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_rect)) assert np.all(indicator(self.oncoords_rect))
def test_boundary_hyperrectangle_size_ratio(self): """ Test :meth:`bet.calculateP.indicatorFunctions.boundary_hyperrectangle_size_ratio` """ indicator = ifun.boundary_hyperrectangle_size_ratio(self.center, self.width, self.boundary_ratio) assert False == np.all( indicator(util.fix_dimensions_vector_2darray(self.center))) assert False == np.all(indicator(self.outcoords_rect)) assert np.all(indicator(self.oncoords_rect))
def test_fix_dimensions_vector_2darray(): """ Tests :meth:`bet.util.fix_dimensions_vector_2darray` """ values = [ 1, [1], np.empty((1, 1)), range(5), np.array(range(5)), np.empty((5, 1)) ] shapes = [(1, 1), (1, 1), (1, 1), (5, 1), (5, 1), (5, 1)] for value, shape in zip(values, shapes): vector = util.fix_dimensions_vector_2darray(value) assert vector.shape == shape
def find_good_sets(grad_tensor, good_sets_prev, unique_indices, num_optsets_return, cond_tol, volume): r""" #TODO: Use the idea we only know vectors are with 10% accuracy to guide inner_prod tol and condnum_tol. Given gradient vectors at each center in the parameter space and given good sets of size n - 1, return good sets of size n. That is, return sets of size n that have average condition number less than some tolerance. :param grad_tensor: Gradient vectors at each centers in the parameter space :math:'\Lambda' for each QoI map. :type grad_tensor: :class:`np.ndarray` of shape (num_centers,num_qois,Ldim) where num_centers is the number of points in :math:'\Lambda' we have approximated the gradient vectors, num_qois is the total number of possible QoIs to choose from, Ldim is the dimension of :math:`\Lambda`. :param good_sets_prev: Good sets of QoIs of size n - 1. :type good_sets_prev: :class:`np.ndarray` of size (num_good_sets_prev, n - 1) :param unique_indices: Unique QoIs to consider. :type unique_indices: :class:'np.ndarray' of size (num_unique_qois, 1) :param int num_optsets_return: Number of best sets to return :param float cond_tol: Throw out all sets of QoIs with average condition number greater than this. :param boolean volume: If volume is True, use ``calculate_avg_volume`` to determine optimal QoIs :rtype: tuple :returns: (good_sets, best_sets, optsingvals_tensor) where good sets has size (num_good_sets, n), best sets has size (num_optsets_return, n + 1) and optsingvals_tensor has size (num_centers, n, Lambda_dim) """ num_centers = grad_tensor.shape[0] Lambda_dim = grad_tensor.shape[2] num_qois_return = good_sets_prev.shape[1] + 1 comm.Barrier() # Initialize best sets and set all condition numbers large best_sets = np.zeros([num_optsets_return, num_qois_return + 1]) best_sets[:, 0] = 1E99 good_sets = np.zeros([1, num_qois_return]) count_qois = 0 optsingvals_tensor = np.zeros([num_centers, num_qois_return, num_optsets_return]) # For each good set of size n - 1, find the possible sets of size n and # compute the average condition number of each count_qois = 0 for i in range(good_sets_prev.shape[0]): min_ind = np.max(good_sets_prev[i, :]) # Find all possible combinations of QoIs that include this set of n - 1 if comm.rank == 0: inds_notin_set = util.fix_dimensions_vector_2darray(list(set(\ unique_indices) - set(good_sets_prev[i, :]))) # Choose only the QoI indices > min_ind so we do not repeat sets inds_notin_set = util.fix_dimensions_vector_2darray(inds_notin_set[\ inds_notin_set > min_ind]) qoi_combs = util.fix_dimensions_vector_2darray(np.append(np.tile(\ good_sets_prev[i, :], [inds_notin_set.shape[0], 1]), inds_notin_set, axis=1)) qoi_combs = np.array_split(qoi_combs, comm.size) else: qoi_combs = None # Scatter them throughout the processors qoi_combs = comm.scatter(qoi_combs, root=0) # For each combination, compute the average condition number and add the # set to good_sets if it is less than cond_tol for qoi_set in range(len(qoi_combs)): count_qois += 1 curr_set = util.fix_dimensions_vector_2darray(qoi_combs[qoi_set])\ .transpose() if volume == False: (current_condnum, singvals) = calculate_avg_condnum(grad_tensor, qoi_combs[qoi_set]) else: (current_condnum, singvals) = calculate_avg_volume(grad_tensor, qoi_combs[qoi_set]) # If its a good set, add it to good_sets if current_condnum < cond_tol: good_sets = np.append(good_sets, curr_set, axis=0) # If the average condition number is less than the max condition # number in our best_sets, add it to best_sets if current_condnum < best_sets[-1, 0]: best_sets[-1, :] = np.append(np.array([current_condnum]), qoi_combs[qoi_set]) order = best_sets[:, 0].argsort() best_sets = best_sets[order] # Store the corresponding singular values optsingvals_tensor[:, :, -1] = singvals optsingvals_tensor = optsingvals_tensor[:, :, order] # Wait for all processes to get to this point comm.Barrier() # Gather the best sets and condition numbers from each processor good_sets = comm.gather(good_sets, root=0) best_sets = np.array(comm.gather(best_sets, root=0)) count_qois = np.array(comm.gather(count_qois, root=0)) # Find the num_optsets_return smallest condition numbers from all processors if comm.rank == 0: # Organize the best sets best_sets = best_sets.reshape(num_optsets_return * \ comm.size, num_qois_return + 1) [temp, uniq_inds_best] = np.unique(best_sets[:, 0], return_index=True) best_sets = best_sets[uniq_inds_best, :] best_sets = best_sets[best_sets[:, 0].argsort()] best_sets = best_sets[:num_optsets_return, :] # Organize the good sets good_sets_new = np.zeros([1, num_qois_return]) for each in good_sets: good_sets_new = np.append(good_sets_new, each[1:], axis=0) good_sets = good_sets_new print 'Possible sets of QoIs of size %i : '%good_sets.shape[1],\ np.sum(count_qois) print 'Good sets of QoIs of size %i : '%good_sets.shape[1],\ good_sets.shape[0] - 1 comm.Barrier() best_sets = comm.bcast(best_sets, root=0) good_sets = comm.bcast(good_sets, root=0) return (good_sets[1:].astype(int), best_sets, optsingvals_tensor)
def find_good_sets(input_set, good_sets_prev, unique_indices, num_optsets_return, measskew_tol, measure): r""" .. todo:: Use the idea we only know vectors are with 10% accuracy to guide inner_prod tol and skewness_tol. Given gradient vectors at each center in the parameter space and given good sets of size (n - 1), return good sets of size n. That is, return sets of size n that have average measure(skewness) less than some tolerance. :param input_set: The input sample set. Make sure the attribute _jacobians is not None. :type input_set: :class:`~bet.sample.sample_set` :param good_sets_prev: Good sets of QoIs of size n - 1. :type good_sets_prev: :class:`np.ndarray` of size (num_good_sets_prev, n - 1) :param unique_indices: Unique QoIs to consider. :type unique_indices: :class:`np.ndarray` of size (num_unique_qois, 1) :param int num_optsets_return: Number of best sets to return :param float measskew_tol: Throw out all sets of QoIs with average measure(skewness) number greater than this. :param boolean measure: If measure is True, use ``calculate_avg_measure`` to determine optimal QoIs, else use ``calculate_avg_skewness`` :rtype: tuple :returns: (good_sets, best_sets, optsingvals_tensor) where good sets has size (num_good_sets, n), best sets has size (num_optsets_return, n + 1) and optsingvals_tensor has size (num_centers, n, input_dim) """ if input_set._jacobians is None: raise ValueError("You must have jacobians to use this method.") num_centers = input_set._jacobians.shape[0] num_qois_return = good_sets_prev.shape[1] + 1 comm.Barrier() # Initialize best sets and set all skewness values large best_sets = np.zeros([num_optsets_return, num_qois_return + 1]) best_sets[:, 0] = np.inf good_sets = np.zeros([1, num_qois_return]) count_qois = 0 optsingvals_tensor = np.zeros([num_centers, num_qois_return, num_optsets_return]) # For each good set of size (n - 1), find the possible sets of size n and # compute the average skewness of each count_qois = 0 for i in range(good_sets_prev.shape[0]): min_ind = np.max(good_sets_prev[i, :]) # Find all possible combinations of QoIs that include this set of # (n - 1) if comm.rank == 0: inds_notin_set = util.fix_dimensions_vector_2darray(list(set( unique_indices) - set(good_sets_prev[i, :]))) # Choose only the QoI indices > min_ind so we do not repeat sets inds_notin_set = util.fix_dimensions_vector_2darray(inds_notin_set[ inds_notin_set > min_ind]) qoi_combs = util.fix_dimensions_vector_2darray(np.append(np.tile( good_sets_prev[i, :], [inds_notin_set.shape[0], 1]), inds_notin_set, axis=1)) qoi_combs = np.array_split(qoi_combs, comm.size) else: qoi_combs = None # Scatter them throughout the processors qoi_combs = comm.scatter(qoi_combs, root=0) # For each combination, compute the average measure(skewness) and add # the set to good_sets if it is less than measskew_tol for qoi_set in range(len(qoi_combs)): count_qois += 1 curr_set = util.fix_dimensions_vector_2darray(qoi_combs[qoi_set])\ .transpose() if measure is False: (current_measskew, singvals) = calculate_avg_skewness(input_set, qoi_combs[qoi_set]) else: (current_measskew, singvals) = calculate_avg_measure(input_set, qoi_combs[qoi_set]) # If its a good set, add it to good_sets if current_measskew < measskew_tol: good_sets = np.append(good_sets, curr_set, axis=0) # If the average skewness is less than the maxskewness # in our best_sets, add it to best_sets if current_measskew < best_sets[-1, 0]: best_sets[-1, :] = np.append(np.array([current_measskew]), qoi_combs[qoi_set]) order = best_sets[:, 0].argsort() best_sets = best_sets[order] # Store the corresponding singular values optsingvals_tensor[:, :, -1] = singvals optsingvals_tensor = optsingvals_tensor[:, :, order] # Wait for all processes to get to this point comm.Barrier() # Gather the best sets and skewness values from each processor good_sets = comm.gather(good_sets, root=0) best_sets = np.array(comm.gather(best_sets, root=0)) count_qois = np.array(comm.gather(count_qois, root=0)) # Find the num_optsets_return smallest skewness from all processors if comm.rank == 0: # Organize the best sets best_sets = best_sets.reshape(num_optsets_return * comm.size, num_qois_return + 1) [_, uniq_inds_best] = np.unique(best_sets[:, 0], return_index=True) best_sets = best_sets[uniq_inds_best, :] best_sets = best_sets[best_sets[:, 0].argsort()] best_sets = best_sets[:num_optsets_return, :] # Organize the good sets good_sets_new = np.zeros([1, num_qois_return]) for each in good_sets: good_sets_new = np.append(good_sets_new, each[1:], axis=0) good_sets = good_sets_new logging.info('Possible sets of QoIs of size {} : {}'.format( good_sets.shape[1], np.sum(count_qois))) logging.info('Good sets of QoIs of size {} : {}'.format( good_sets.shape[1], good_sets.shape[0] - 1)) comm.Barrier() best_sets = comm.bcast(best_sets, root=0) good_sets = comm.bcast(good_sets, root=0) return (good_sets[1:].astype(int), best_sets, optsingvals_tensor)
def chooseOptQoIs_large_verbose(input_set, qoiIndices=None, max_qois_return=None, num_optsets_return=None, inner_prod_tol=None, measskew_tol=None, measure=False, remove_zeros=True): r""" Given gradient vectors at some points (centers) in the parameter space, a large set of QoIs to choose from, and the number of desired QoIs to return, this method return the set of optimal QoIs of size 1, 2, ... max_qois_return to use in the inverse problem by choosing the set with smallext average skewness. Also a tensor that represents the singular values of the matrices formed by the gradient vectors of the optimal QoIs at each center is returned. :param input_set: The input sample set. Make sure the attribute _jacobians is not None. :type input_set: :class:`~bet.sample.sample_set` :param qoiIndices: Set of QoIs to consider from G. Default is xrange(0, G.shape[1]). :type qoiIndices: :class:`np.ndarray` of size (1, num QoIs to consider) :param int max_qois_return: Maximum number of desired QoIs to use in the inverse problem. Default is input_dim. :param int num_optsets_return: Number of best sets to return. Default is 10. :param float inner_prod_tol: Throw out one vectors from each pair of QoIs that has average inner product greater than this. Default is 0.9. :param float measskew_tol: Throw out all sets of QoIs with average measure(skewness) number greater than this. Default is max_float. :param boolean measure: If measure is True, use ``calculate_avg_measure`` to determine optimal QoIs, else use ``calculate_avg_skewness`` :param boolean remove_zeros: If True, ``find_unique_vecs`` will remove any QoIs that have a zero gradient vector at atleast one point in :math:`\Lambda`. :rtype: tuple :returns: (measure_skewness_indices_mat, optsingvals) where measure_skewness_indices_mat has shape (num_optsets_return, num_qois_return+1) and optsingvals is a list where each element has shape (num_centers, num_qois_return, num_optsets_return). num_qois_return will change for each element of the list. """ input_dim = input_set._dim if input_set._jacobians is None: raise ValueError("You must have jacobians to use this method.") if qoiIndices is None: qoiIndices = range(0, input_set._jacobians.shape[1]) if max_qois_return is None: max_qois_return = input_dim if num_optsets_return is None: num_optsets_return = 10 if inner_prod_tol is None: inner_prod_tol = 1.0 if measskew_tol is None: measskew_tol = np.inf # Find the unique QoIs to consider unique_indices = find_unique_vecs(input_set, inner_prod_tol, qoiIndices, remove_zeros) if comm.rank == 0: logging.info('Unique Indices are : {}'.format(unique_indices)) good_sets_curr = util.fix_dimensions_vector_2darray(unique_indices) best_sets = [] optsingvals_list = [] # Given good sets of QoIs of size (n - 1), find the good sets of size n for qois_return in range(2, max_qois_return + 1): (good_sets_curr, best_sets_curr, optsingvals_tensor_curr) = \ find_good_sets(input_set, good_sets_curr, unique_indices, num_optsets_return, measskew_tol, measure) best_sets.append(best_sets_curr) optsingvals_list.append(optsingvals_tensor_curr) if comm.rank == 0: logging.info(best_sets_curr) return (best_sets, optsingvals_list)
def chooseOptQoIs_large_verbose(grad_tensor, qoiIndices=None, max_qois_return=None, num_optsets_return=None, inner_prod_tol=None, cond_tol=None, volume=False, remove_zeros=True): r""" Given gradient vectors at some points (centers) in the parameter space, a large set of QoIs to choose from, and the number of desired QoIs to return, this method return the set of optimal QoIs of size 1, 2, ... max_qois_return to use in the inverse problem by choosing the set with smallext average condition number. Also a tensor that represents the singular values of the matrices formed by the gradient vectors of the optimal QoIs at each center is returned. :param grad_tensor: Gradient vectors at each point of interest in the parameter space :math:`\Lambda` for each QoI map. :type grad_tensor: :class:`np.ndarray` of shape (num_centers, num_qois, Lambda_dim) where num_centers is the number of points in :math:`\Lambda` we have approximated the gradient vectors and num_qois is the total number of possible QoIs to choose from. :param qoiIndices: Set of QoIs to consider from grad_tensor. Default is range(0, grad_tensor.shape[1]). :type qoiIndices: :class:`np.ndarray` of size (1, num QoIs to consider) :param int max_qois_return: Maximum number of desired QoIs to use in the inverse problem. Default is Lambda_dim. :param int num_optsets_return: Number of best sets to return. Default is 10. :param float inner_prod_tol: Throw out one vectors from each pair of QoIs that has average inner product greater than this. Default is 0.9. :param float cond_tol: Throw out all sets of QoIs with average condition number greater than this. Default is max_float. :param boolean volume: If volume is True, use ``calculate_avg_volume`` to determine optimal QoIs :param boolean remove_zeros: If True, ``find_unique_vecs`` will remove any QoIs that have a zero gradient vector at atleast one point in :math:`\Lambda`. :rtype: tuple :returns: (condnum_indices_mat, optsingvals) where condnum_indices_mat has shape (num_optsets_return, num_qois_return+1) and optsingvals is a list where each element has shape (num_centers, num_qois_return, num_optsets_return). num_qois_return will change for each element of the list. """ num_centers = grad_tensor.shape[0] Lambda_dim = grad_tensor.shape[2] if qoiIndices is None: qoiIndices = range(0, grad_tensor.shape[1]) if max_qois_return is None: max_qois_return = Lambda_dim if num_optsets_return is None: num_optsets_return = 10 if inner_prod_tol is None: inner_prod_tol = 1.0 if cond_tol is None: cond_tol = np.inf # Find the unique QoIs to consider unique_indices = find_unique_vecs(grad_tensor, inner_prod_tol, qoiIndices, remove_zeros) if comm.rank == 0: print 'Unique Indices are : ', unique_indices good_sets_curr = util.fix_dimensions_vector_2darray(unique_indices) best_sets = [] optsingvals_list = [] # Given good sets of QoIs of size n - 1, find the good sets of size n for qois_return in range(2, max_qois_return + 1): (good_sets_curr, best_sets_curr, optsingvals_tensor_curr) = \ find_good_sets(grad_tensor, good_sets_curr, unique_indices, num_optsets_return, cond_tol, volume) best_sets.append(best_sets_curr) optsingvals_list.append(optsingvals_tensor_curr) if comm.rank == 0: print best_sets_curr return (best_sets, optsingvals_list)
def find_good_sets(grad_tensor, good_sets_prev, unique_indices, num_optsets_return, cond_tol, volume): r""" #TODO: Use the idea we only know vectors are with 10% accuracy to guide inner_prod tol and condnum_tol. Given gradient vectors at each center in the parameter space and given good sets of size n - 1, return good sets of size n. That is, return sets of size n that have average condition number less than some tolerance. :param grad_tensor: Gradient vectors at each centers in the parameter space :math:'\Lambda' for each QoI map. :type grad_tensor: :class:`np.ndarray` of shape (num_centers,num_qois,Ldim) where num_centers is the number of points in :math:'\Lambda' we have approximated the gradient vectors, num_qois is the total number of possible QoIs to choose from, Ldim is the dimension of :math:`\Lambda`. :param good_sets_prev: Good sets of QoIs of size n - 1. :type good_sets_prev: :class:`np.ndarray` of size (num_good_sets_prev, n - 1) :param unique_indices: Unique QoIs to consider. :type unique_indices: :class:'np.ndarray' of size (num_unique_qois, 1) :param int num_optsets_return: Number of best sets to return :param float cond_tol: Throw out all sets of QoIs with average condition number greater than this. :param boolean volume: If volume is True, use ``calculate_avg_volume`` to determine optimal QoIs :rtype: tuple :returns: (good_sets, best_sets, optsingvals_tensor) where good sets has size (num_good_sets, n), best sets has size (num_optsets_return, n + 1) and optsingvals_tensor has size (num_centers, n, Lambda_dim) """ num_centers = grad_tensor.shape[0] Lambda_dim = grad_tensor.shape[2] num_qois_return = good_sets_prev.shape[1] + 1 comm.Barrier() # Initialize best sets and set all condition numbers large best_sets = np.zeros([num_optsets_return, num_qois_return + 1]) best_sets[:, 0] = np.inf good_sets = np.zeros([1, num_qois_return]) count_qois = 0 optsingvals_tensor = np.zeros( [num_centers, num_qois_return, num_optsets_return]) # For each good set of size n - 1, find the possible sets of size n and # compute the average condition number of each count_qois = 0 for i in range(good_sets_prev.shape[0]): min_ind = np.max(good_sets_prev[i, :]) # Find all possible combinations of QoIs that include this set of n - 1 if comm.rank == 0: inds_notin_set = util.fix_dimensions_vector_2darray(list(set(\ unique_indices) - set(good_sets_prev[i, :]))) # Choose only the QoI indices > min_ind so we do not repeat sets inds_notin_set = util.fix_dimensions_vector_2darray(inds_notin_set[\ inds_notin_set > min_ind]) qoi_combs = util.fix_dimensions_vector_2darray(np.append(np.tile(\ good_sets_prev[i, :], [inds_notin_set.shape[0], 1]), inds_notin_set, axis=1)) qoi_combs = np.array_split(qoi_combs, comm.size) else: qoi_combs = None # Scatter them throughout the processors qoi_combs = comm.scatter(qoi_combs, root=0) # For each combination, compute the average condition number and add the # set to good_sets if it is less than cond_tol for qoi_set in range(len(qoi_combs)): count_qois += 1 curr_set = util.fix_dimensions_vector_2darray(qoi_combs[qoi_set])\ .transpose() if volume == False: (current_condnum, singvals) = calculate_avg_condnum(grad_tensor, qoi_combs[qoi_set]) else: (current_condnum, singvals) = calculate_avg_volume(grad_tensor, qoi_combs[qoi_set]) # If its a good set, add it to good_sets if current_condnum < cond_tol: good_sets = np.append(good_sets, curr_set, axis=0) # If the average condition number is less than the max condition # number in our best_sets, add it to best_sets if current_condnum < best_sets[-1, 0]: best_sets[-1, :] = np.append(np.array([current_condnum]), qoi_combs[qoi_set]) order = best_sets[:, 0].argsort() best_sets = best_sets[order] # Store the corresponding singular values optsingvals_tensor[:, :, -1] = singvals optsingvals_tensor = optsingvals_tensor[:, :, order] # Wait for all processes to get to this point comm.Barrier() # Gather the best sets and condition numbers from each processor good_sets = comm.gather(good_sets, root=0) best_sets = np.array(comm.gather(best_sets, root=0)) count_qois = np.array(comm.gather(count_qois, root=0)) # Find the num_optsets_return smallest condition numbers from all processors if comm.rank == 0: # Organize the best sets best_sets = best_sets.reshape(num_optsets_return * \ comm.size, num_qois_return + 1) [temp, uniq_inds_best] = np.unique(best_sets[:, 0], return_index=True) best_sets = best_sets[uniq_inds_best, :] best_sets = best_sets[best_sets[:, 0].argsort()] best_sets = best_sets[:num_optsets_return, :] # Organize the good sets good_sets_new = np.zeros([1, num_qois_return]) for each in good_sets: good_sets_new = np.append(good_sets_new, each[1:], axis=0) good_sets = good_sets_new print 'Possible sets of QoIs of size %i : '%good_sets.shape[1],\ np.sum(count_qois) print 'Good sets of QoIs of size %i : '%good_sets.shape[1],\ good_sets.shape[0] - 1 comm.Barrier() best_sets = comm.bcast(best_sets, root=0) good_sets = comm.bcast(good_sets, root=0) return (good_sets[1:].astype(int), best_sets, optsingvals_tensor)
def chooseOptQoIs_large_verbose(input_set, qoiIndices=None, max_qois_return=None, num_optsets_return=None, inner_prod_tol=None, measskew_tol=None, measure=False, remove_zeros=True): r""" Given gradient vectors at some points (centers) in the parameter space, a large set of QoIs to choose from, and the number of desired QoIs to return, this method return the set of optimal QoIs of size 1, 2, ... max_qois_return to use in the inverse problem by choosing the set with smallext average skewness. Also a tensor that represents the singular values of the matrices formed by the gradient vectors of the optimal QoIs at each center is returned. :param input_set: The input sample set. Make sure the attribute _jacobians is not None. :type input_set: :class:`~bet.sample.sample_set` :param qoiIndices: Set of QoIs to consider from G. Default is xrange(0, G.shape[1]). :type qoiIndices: :class:`np.ndarray` of size (1, num QoIs to consider) :param int max_qois_return: Maximum number of desired QoIs to use in the inverse problem. Default is input_dim. :param int num_optsets_return: Number of best sets to return. Default is 10. :param float inner_prod_tol: Throw out one vectors from each pair of QoIs that has average inner product greater than this. Default is 0.9. :param float measskew_tol: Throw out all sets of QoIs with average measure(skewness) number greater than this. Default is max_float. :param boolean measure: If measure is True, use ``calculate_avg_measure`` to determine optimal QoIs, else use ``calculate_avg_skewness`` :param boolean remove_zeros: If True, ``find_unique_vecs`` will remove any QoIs that have a zero gradient vector at atleast one point in :math:`\Lambda`. :rtype: tuple :returns: (measure_skewness_indices_mat, optsingvals) where measure_skewness_indices_mat has shape (num_optsets_return, num_qois_return+1) and optsingvals is a list where each element has shape (num_centers, num_qois_return, num_optsets_return). num_qois_return will change for each element of the list. """ input_dim = input_set._dim if input_set._jacobians is None: raise ValueError("You must have jacobians to use this method.") if qoiIndices is None: qoiIndices = xrange(0, input_set._jacobians.shape[1]) if max_qois_return is None: max_qois_return = input_dim if num_optsets_return is None: num_optsets_return = 10 if inner_prod_tol is None: inner_prod_tol = 1.0 if measskew_tol is None: measskew_tol = np.inf # Find the unique QoIs to consider unique_indices = find_unique_vecs(input_set, inner_prod_tol, qoiIndices, remove_zeros) if comm.rank == 0: logging.info('Unique Indices are : {}'.format(unique_indices)) good_sets_curr = util.fix_dimensions_vector_2darray(unique_indices) best_sets = [] optsingvals_list = [] # Given good sets of QoIs of size (n - 1), find the good sets of size n for qois_return in xrange(2, max_qois_return + 1): (good_sets_curr, best_sets_curr, optsingvals_tensor_curr) = \ find_good_sets(input_set, good_sets_curr, unique_indices, num_optsets_return, measskew_tol, measure) best_sets.append(best_sets_curr) optsingvals_list.append(optsingvals_tensor_curr) if comm.rank == 0: logging.info(best_sets_curr) return (best_sets, optsingvals_list)
def find_good_sets(input_set, good_sets_prev, unique_indices, num_optsets_return, measskew_tol, measure): r""" .. todo:: Use the idea we only know vectors are with 10% accuracy to guide inner_prod tol and skewness_tol. Given gradient vectors at each center in the parameter space and given good sets of size (n - 1), return good sets of size n. That is, return sets of size n that have average measure(skewness) less than some tolerance. :param input_set: The input sample set. Make sure the attribute _jacobians is not None. :type input_set: :class:`~bet.sample.sample_set` :param good_sets_prev: Good sets of QoIs of size n - 1. :type good_sets_prev: :class:`np.ndarray` of size (num_good_sets_prev, n - 1) :param unique_indices: Unique QoIs to consider. :type unique_indices: :class:`np.ndarray` of size (num_unique_qois, 1) :param int num_optsets_return: Number of best sets to return :param float measskew_tol: Throw out all sets of QoIs with average measure(skewness) number greater than this. :param boolean measure: If measure is True, use ``calculate_avg_measure`` to determine optimal QoIs, else use ``calculate_avg_skewness`` :rtype: tuple :returns: (good_sets, best_sets, optsingvals_tensor) where good sets has size (num_good_sets, n), best sets has size (num_optsets_return, n + 1) and optsingvals_tensor has size (num_centers, n, input_dim) """ if input_set._jacobians is None: raise ValueError("You must have jacobians to use this method.") num_centers = input_set._jacobians.shape[0] num_qois_return = good_sets_prev.shape[1] + 1 comm.Barrier() # Initialize best sets and set all skewness values large best_sets = np.zeros([num_optsets_return, num_qois_return + 1]) best_sets[:, 0] = np.inf good_sets = np.zeros([1, num_qois_return]) count_qois = 0 optsingvals_tensor = np.zeros( [num_centers, num_qois_return, num_optsets_return]) # For each good set of size (n - 1), find the possible sets of size n and # compute the average skewness of each count_qois = 0 for i in xrange(good_sets_prev.shape[0]): min_ind = np.max(good_sets_prev[i, :]) # Find all possible combinations of QoIs that include this set of # (n - 1) if comm.rank == 0: inds_notin_set = util.fix_dimensions_vector_2darray(list(set(\ unique_indices) - set(good_sets_prev[i, :]))) # Choose only the QoI indices > min_ind so we do not repeat sets inds_notin_set = util.fix_dimensions_vector_2darray(inds_notin_set[\ inds_notin_set > min_ind]) qoi_combs = util.fix_dimensions_vector_2darray(np.append(np.tile(\ good_sets_prev[i, :], [inds_notin_set.shape[0], 1]), inds_notin_set, axis=1)) qoi_combs = np.array_split(qoi_combs, comm.size) else: qoi_combs = None # Scatter them throughout the processors qoi_combs = comm.scatter(qoi_combs, root=0) # For each combination, compute the average measure(skewness) and add # the set to good_sets if it is less than measskew_tol for qoi_set in xrange(len(qoi_combs)): count_qois += 1 curr_set = util.fix_dimensions_vector_2darray(qoi_combs[qoi_set])\ .transpose() if measure is False: (current_measskew, singvals) = calculate_avg_skewness(input_set, qoi_combs[qoi_set]) else: (current_measskew, singvals) = calculate_avg_measure(input_set, qoi_combs[qoi_set]) # If its a good set, add it to good_sets if current_measskew < measskew_tol: good_sets = np.append(good_sets, curr_set, axis=0) # If the average skewness is less than the maxskewness # in our best_sets, add it to best_sets if current_measskew < best_sets[-1, 0]: best_sets[-1, :] = np.append(np.array([current_measskew]), qoi_combs[qoi_set]) order = best_sets[:, 0].argsort() best_sets = best_sets[order] # Store the corresponding singular values optsingvals_tensor[:, :, -1] = singvals optsingvals_tensor = optsingvals_tensor[:, :, order] # Wait for all processes to get to this point comm.Barrier() # Gather the best sets and skewness values from each processor good_sets = comm.gather(good_sets, root=0) best_sets = np.array(comm.gather(best_sets, root=0)) count_qois = np.array(comm.gather(count_qois, root=0)) # Find the num_optsets_return smallest skewness from all processors if comm.rank == 0: # Organize the best sets best_sets = best_sets.reshape(num_optsets_return * \ comm.size, num_qois_return + 1) [_, uniq_inds_best] = np.unique(best_sets[:, 0], return_index=True) best_sets = best_sets[uniq_inds_best, :] best_sets = best_sets[best_sets[:, 0].argsort()] best_sets = best_sets[:num_optsets_return, :] # Organize the good sets good_sets_new = np.zeros([1, num_qois_return]) for each in good_sets: good_sets_new = np.append(good_sets_new, each[1:], axis=0) good_sets = good_sets_new logging.info('Possible sets of QoIs of size {} : {}'.format(\ good_sets.shape[1], np.sum(count_qois))) logging.info('Good sets of QoIs of size {} : {}'.format(\ good_sets.shape[1], good_sets.shape[0] - 1)) comm.Barrier() best_sets = comm.bcast(best_sets, root=0) good_sets = comm.bcast(good_sets, root=0) return (good_sets[1:].astype(int), best_sets, optsingvals_tensor)
def calculate_gradients_cfd(cluster_discretization, normalize=True): """ Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map. THIS METHOD IS DEPENDENT ON USING :meth:~bet.sensitivity.pick_cfd_points TO CHOOSE SAMPLES FOR THE CFD STENCIL AROUND EACH CENTER. THE ORDERING MATTERS. :param cluster_discretization: Must contain input and output values for the sample clusters. :type cluster_discretization: :class:`~bet.sample.discretization` :param boolean normalize: If normalize is True, normalize each gradient vector :rtype: :class:`~bet.sample.discretization` :returns: A new :class:`~bet.sample.discretization` that contains only the centers of the clusters and their associated ``_jacobians`` which are tensor representation of the gradient vectors of each QoI map at each point in centers :class:`numpy.ndarray` of shape (num_samples, output_dim, input_dim) """ if cluster_discretization._input_sample_set.get_values() is None \ or cluster_discretization._output_sample_set.get_values() is None: raise ValueError("You must have values to use this method.") samples = cluster_discretization._input_sample_set.get_values() data = cluster_discretization._output_sample_set.get_values() input_dim = cluster_discretization._input_sample_set.get_dim() num_model_samples = cluster_discretization.check_nums() output_dim = cluster_discretization._output_sample_set.get_dim() num_model_samples = cluster_discretization.check_nums() input_dim = cluster_discretization._input_sample_set.get_dim() num_centers = num_model_samples / (2 * input_dim + 1) # Find radii_vec from the first cluster of samples radii_vec = samples[num_centers:num_centers + input_dim, :] - samples[0, :] radii_vec = util.fix_dimensions_vector_2darray(radii_vec.diagonal()) # Clean the data data = util.clean_data(data[num_centers:]) gradient_tensor = np.zeros([num_centers, output_dim, input_dim]) radii_vec = np.tile(np.repeat(radii_vec, output_dim, axis=1), [num_centers, 1]) # Construct indices for CFD gradient approxiation inds = np.repeat(range(0, 2 * input_dim * num_centers, 2 * input_dim), input_dim) + np.tile(range(0, input_dim), num_centers) inds = np.array([inds, inds + input_dim]).transpose() gradient_mat = (data[inds[:, 0]] - data[inds[:, 1]]) * (0.5 / radii_vec) # Reshape and organize gradient_tensor = np.reshape(gradient_mat.transpose(), [output_dim, input_dim, num_centers], order='F').transpose(2, 0, 1) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, ord=1, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor / np.tile( norm_gradient_tensor, (input_dim, 1, 1)).transpose(1, 2, 0) center_input_sample_set = sample.sample_set(input_dim) center_input_sample_set.set_values(samples[:num_centers, :]) if cluster_discretization._input_sample_set.get_domain() is not None: center_input_sample_set.set_domain(cluster_discretization.\ _input_sample_set.get_domain()) center_input_sample_set.set_jacobians(gradient_tensor) center_output_sample_set = sample.sample_set(output_dim) center_output_sample_set.set_values(data[:num_centers, :]) if cluster_discretization._output_sample_set.get_domain() is not None: center_output_sample_set.set_domain(cluster_discretization.\ _output_sample_set.get_domain()) #center_output_sample_set.set_jacobians(gradient_tensor.transpose()) center_discretization = sample.discretization(center_input_sample_set, center_output_sample_set) return center_discretization
def calculate_gradients_rbf(samples, data, centers=None, num_neighbors=None, RBF=None, ep=None, normalize=True): r""" Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map using a radial basis function interpolation method. :param samples: Samples for which the model has been solved. :type samples: :class:`np.ndarray` of shape (num_samples, Lambda_dim) :param data: QoI values corresponding to each sample. :type data: :class:`np.ndarray` of shape (num_samples, Data_dim) :param centers: Points in :math:`\Lambda` at which to approximate gradient information. :type centers: :class:`np.ndarray` of shape (num_exval, Lambda_dim) :param int num_neighbors: Number of nearest neighbors to use in gradient approximation. Default value is Lambda_dim + 2. :param string RBF: Choice of radial basis function. Default is Gaussian :param float ep: Choice of shape parameter for radial basis function. Default value is 1.0 :param boolean normalize: If normailze is True, normalize each gradient vector :rtype: :class:`np.ndarray` of shape (num_samples, Data_dim, Lambda_dim) :returns: Tensor representation of the gradient vectors of each QoI map at each point in centers """ data = util.fix_dimensions_vector_2darray(util.clean_data(data)) Lambda_dim = samples.shape[1] num_model_samples = samples.shape[0] Data_dim = data.shape[1] if num_neighbors is None: num_neighbors = Lambda_dim + 2 if ep is None: ep = 1.0 if RBF is None: RBF = 'Gaussian' # If centers is None we assume the user chose clusters of size # Lambda_dim + 2 if centers is None: num_centers = num_model_samples / (Lambda_dim + 2) centers = samples[:num_centers] else: num_centers = centers.shape[0] rbf_tensor = np.zeros([num_centers, num_model_samples, Lambda_dim]) gradient_tensor = np.zeros([num_centers, Data_dim, Lambda_dim]) tree = spatial.KDTree(samples) # For each centers, interpolate the data using the rbf chosen and # then evaluate the partial derivative of that rbf at the desired point. for c in range(num_centers): # Find the k nearest neighbors and their distances to centers[c,:] [r, nearest] = tree.query(centers[c, :], k=num_neighbors) r = np.tile(r, (Lambda_dim, 1)) # Compute the linf distances to each of the nearest neighbors diffVec = (centers[c, :] - samples[nearest, :]).transpose() # Compute the l2 distances between pairs of nearest neighbors distMat = spatial.distance_matrix( samples[nearest, :], samples[nearest, :]) # Solve for the rbf weights using interpolation conditions and # evaluate the partial derivatives rbf_mat_values = \ np.linalg.solve(radial_basis_function(distMat, RBF), radial_basis_function_dxi(r, diffVec, RBF, ep) \ .transpose()).transpose() # Construct the finite difference matrices rbf_tensor[c, nearest, :] = rbf_mat_values.transpose() gradient_tensor = rbf_tensor.transpose(2, 0, 1).dot(data).transpose(1, 2, 0) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, ord=1, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor/np.tile(norm_gradient_tensor, (Lambda_dim, 1, 1)).transpose(1, 2, 0) return gradient_tensor
def calculate_gradients_cfd(cluster_discretization, normalize=True): """ Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map. THIS METHOD IS DEPENDENT ON USING :meth:~bet.sensitivity.pick_cfd_points TO CHOOSE SAMPLES FOR THE CFD STENCIL AROUND EACH CENTER. THE ORDERING MATTERS. :param cluster_discretization: Must contain input and output values for the sample clusters. :type cluster_discretization: :class:`~bet.sample.discretization` :param boolean normalize: If normalize is True, normalize each gradient vector :rtype: :class:`~bet.sample.discretization` :returns: A new :class:`~bet.sample.discretization` that contains only the centers of the clusters and their associated ``_jacobians`` which are tensor representation of the gradient vectors of each QoI map at each point in centers :class:`numpy.ndarray` of shape (num_samples, output_dim, input_dim) """ if cluster_discretization._input_sample_set.get_values() is None \ or cluster_discretization._output_sample_set.get_values() is None: raise ValueError("You must have values to use this method.") samples = cluster_discretization._input_sample_set.get_values() data = cluster_discretization._output_sample_set.get_values() input_dim = cluster_discretization._input_sample_set.get_dim() num_model_samples = cluster_discretization.check_nums() output_dim = cluster_discretization._output_sample_set.get_dim() num_model_samples = cluster_discretization.check_nums() input_dim = cluster_discretization._input_sample_set.get_dim() num_centers = num_model_samples / (2*input_dim + 1) # Find radii_vec from the first cluster of samples radii_vec = samples[num_centers:num_centers + input_dim, :] - samples[0, :] radii_vec = util.fix_dimensions_vector_2darray(radii_vec.diagonal()) # Clean the data data = util.clean_data(data[num_centers:]) gradient_tensor = np.zeros([num_centers, output_dim, input_dim]) radii_vec = np.tile(np.repeat(radii_vec, output_dim, axis=1), [num_centers, 1]) # Construct indices for CFD gradient approxiation inds = np.repeat(range(0, 2 * input_dim * num_centers, 2 * input_dim), input_dim) + np.tile(range(0, input_dim), num_centers) inds = np.array([inds, inds+input_dim]).transpose() gradient_mat = (data[inds[:, 0]] - data[inds[:, 1]]) * (0.5 / radii_vec) # Reshape and organize gradient_tensor = np.reshape(gradient_mat.transpose(), [output_dim, input_dim, num_centers], order='F').transpose(2, 0, 1) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, ord=1, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor/np.tile(norm_gradient_tensor, (input_dim, 1, 1)).transpose(1, 2, 0) center_input_sample_set = sample.sample_set(input_dim) center_input_sample_set.set_values(samples[:num_centers, :]) if cluster_discretization._input_sample_set.get_domain() is not None: center_input_sample_set.set_domain(cluster_discretization.\ _input_sample_set.get_domain()) center_input_sample_set.set_jacobians(gradient_tensor) center_output_sample_set = sample.sample_set(output_dim) center_output_sample_set.set_values(data[:num_centers, :]) if cluster_discretization._output_sample_set.get_domain() is not None: center_output_sample_set.set_domain(cluster_discretization.\ _output_sample_set.get_domain()) #center_output_sample_set.set_jacobians(gradient_tensor.transpose()) center_discretization = sample.discretization(center_input_sample_set, center_output_sample_set) return center_discretization
def chooseOptQoIs_large_verbose(grad_tensor, qoiIndices=None, max_qois_return=None, num_optsets_return=None, inner_prod_tol=None, cond_tol=None, volume=False, remove_zeros=True): r""" Given gradient vectors at some points (centers) in the parameter space, a large set of QoIs to choose from, and the number of desired QoIs to return, this method return the set of optimal QoIs of size 1, 2, ... max_qois_return to use in the inverse problem by choosing the set with smallext average condition number. Also a tensor that represents the singular values of the matrices formed by the gradient vectors of the optimal QoIs at each center is returned. :param grad_tensor: Gradient vectors at each point of interest in the parameter space :math:`\Lambda` for each QoI map. :type grad_tensor: :class:`np.ndarray` of shape (num_centers, num_qois, Lambda_dim) where num_centers is the number of points in :math:`\Lambda` we have approximated the gradient vectors and num_qois is the total number of possible QoIs to choose from. :param qoiIndices: Set of QoIs to consider from grad_tensor. Default is range(0, grad_tensor.shape[1]). :type qoiIndices: :class:`np.ndarray` of size (1, num QoIs to consider) :param int max_qois_return: Maximum number of desired QoIs to use in the inverse problem. Default is Lambda_dim. :param int num_optsets_return: Number of best sets to return. Default is 10. :param float inner_prod_tol: Throw out one vectors from each pair of QoIs that has average inner product greater than this. Default is 0.9. :param float cond_tol: Throw out all sets of QoIs with average condition number greater than this. Default is max_float. :param boolean volume: If volume is True, use ``calculate_avg_volume`` to determine optimal QoIs :param boolean remove_zeros: If True, ``find_unique_vecs`` will remove any QoIs that have a zero gradient vector at atleast one point in :math:`\Lambda`. :rtype: tuple :returns: (condnum_indices_mat, optsingvals) where condnum_indices_mat has shape (num_optsets_return, num_qois_return+1) and optsingvals is a list where each element has shape (num_centers, num_qois_return, num_optsets_return). num_qois_return will change for each element of the list. """ num_centers = grad_tensor.shape[0] Lambda_dim = grad_tensor.shape[2] if qoiIndices is None: qoiIndices = range(0, grad_tensor.shape[1]) if max_qois_return is None: max_qois_return = Lambda_dim if num_optsets_return is None: num_optsets_return = 10 if inner_prod_tol is None: inner_prod_tol = 0.9 if cond_tol is None: cond_tol = sys.float_info[0] # Find the unique QoIs to consider unique_indices = find_unique_vecs(grad_tensor, inner_prod_tol, qoiIndices, remove_zeros) if comm.rank == 0: print 'Unique Indices are : ', unique_indices good_sets_curr = util.fix_dimensions_vector_2darray(unique_indices) best_sets = [] optsingvals_list = [] # Given good sets of QoIs of size n - 1, find the good sets of size n for qois_return in range(2, max_qois_return + 1): (good_sets_curr, best_sets_curr, optsingvals_tensor_curr) = \ find_good_sets(grad_tensor, good_sets_curr, unique_indices, num_optsets_return, cond_tol, volume) best_sets.append(best_sets_curr) optsingvals_list.append(optsingvals_tensor_curr) if comm.rank == 0: print best_sets_curr return (best_sets, optsingvals_list)
def calculate_gradients_rbf(samples, data, centers=None, num_neighbors=None, RBF=None, ep=None, normalize=True): r""" Approximate gradient vectors at ``num_centers, centers.shape[0]`` points in the parameter space for each QoI map using a radial basis function interpolation method. :param samples: Samples for which the model has been solved. :type samples: :class:`np.ndarray` of shape (num_samples, Lambda_dim) :param data: QoI values corresponding to each sample. :type data: :class:`np.ndarray` of shape (num_samples, Data_dim) :param centers: Points in :math:`\Lambda` at which to approximate gradient information. :type centers: :class:`np.ndarray` of shape (num_exval, Lambda_dim) :param int num_neighbors: Number of nearest neighbors to use in gradient approximation. Default value is Lambda_dim + 2. :param string RBF: Choice of radial basis function. Default is Gaussian :param float ep: Choice of shape parameter for radial basis function. Default value is 1.0 :param boolean normalize: If normalize is True, normalize each gradient vector :rtype: :class:`np.ndarray` of shape (num_samples, Data_dim, Lambda_dim) :returns: Tensor representation of the gradient vectors of each QoI map at each point in centers """ data = util.fix_dimensions_vector_2darray(util.clean_data(data)) Lambda_dim = samples.shape[1] num_model_samples = samples.shape[0] Data_dim = data.shape[1] if num_neighbors is None: num_neighbors = Lambda_dim + 2 if ep is None: ep = 1.0 if RBF is None: RBF = 'Gaussian' # If centers is None we assume the user chose clusters of size # Lambda_dim + 2 if centers is None: num_centers = num_model_samples / (Lambda_dim + 2) centers = samples[:num_centers] else: num_centers = centers.shape[0] rbf_tensor = np.zeros([num_centers, num_model_samples, Lambda_dim]) gradient_tensor = np.zeros([num_centers, Data_dim, Lambda_dim]) tree = spatial.KDTree(samples) # For each centers, interpolate the data using the rbf chosen and # then evaluate the partial derivative of that rbf at the desired point. for c in range(num_centers): # Find the k nearest neighbors and their distances to centers[c,:] [r, nearest] = tree.query(centers[c, :], k=num_neighbors) r = np.tile(r, (Lambda_dim, 1)) # Compute the linf distances to each of the nearest neighbors diffVec = (centers[c, :] - samples[nearest, :]).transpose() # Compute the l2 distances between pairs of nearest neighbors distMat = spatial.distance_matrix( samples[nearest, :], samples[nearest, :]) # Solve for the rbf weights using interpolation conditions and # evaluate the partial derivatives rbf_mat_values = \ np.linalg.solve(radial_basis_function(distMat, RBF), radial_basis_function_dxi(r, diffVec, RBF, ep) \ .transpose()).transpose() # Construct the finite difference matrices rbf_tensor[c, nearest, :] = rbf_mat_values.transpose() gradient_tensor = rbf_tensor.transpose(2, 0, 1).dot(data).transpose(1, 2, 0) if normalize: # Compute the norm of each vector norm_gradient_tensor = np.linalg.norm(gradient_tensor, ord=1, axis=2) # If it is a zero vector (has 0 norm), set norm=1, avoid divide by zero norm_gradient_tensor[norm_gradient_tensor == 0] = 1.0 # Normalize each gradient vector gradient_tensor = gradient_tensor/np.tile(norm_gradient_tensor, (Lambda_dim, 1, 1)).transpose(1, 2, 0) return gradient_tensor