From 0584e705bff5f8a68c601081e589e18b1353e75a Mon Sep 17 00:00:00 2001 From: Lalit Rajendran Date: Mon, 3 May 2021 15:29:13 -0400 Subject: [PATCH] moved common functions to module helper_functions --- __pycache__/helper_functions.cpython-38.pyc | Bin 14057 -> 10317 bytes helper_functions.py | 446 ++++++++++++++++++++ sample_script.py | 395 +---------------- 3 files changed, 453 insertions(+), 388 deletions(-) create mode 100755 helper_functions.py diff --git a/__pycache__/helper_functions.cpython-38.pyc b/__pycache__/helper_functions.cpython-38.pyc index 24413b3dc8c67738effaa72b616d9ae006432c08..221662d9f3849a243cc88cf880af9024e88ac27e 100755 GIT binary patch literal 10317 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 diff --git a/helper_functions.py b/helper_functions.py new file mode 100755 index 0000000..87ad450 --- /dev/null +++ b/helper_functions.py @@ -0,0 +1,446 @@ +#!/usr/bin/env python2 +# -*- coding: utf-8 -*- + +import numpy as np +import matplotlib +# matplotlib.use('Agg') +import matplotlib.pyplot as plt +from scipy.io import savemat +from scipy.io import loadmat +import timeit + +from DensityIntegrationUncertaintyQuantification import Density_integration_Poisson_uncertainty +from DensityIntegrationUncertaintyQuantification import Density_integration_WLS_uncertainty + + +def plot_figures(X, Y, rho_x, rho_y, rho, sigma_rho): + + # -------------------------- + # Plot the results + # -------------------------- + fig = plt.figure(1, figsize=(12,8)) + plt.figure(1) + ax1 = fig.add_subplot(2,2,1) + ax2 = fig.add_subplot(2,2,2) + ax3 = fig.add_subplot(2,2,3) + ax4 = fig.add_subplot(2,2,4) + + # plot x gradient + plt.axes(ax1) + plt.pcolormesh(X, Y, rho_x) + plt.colorbar() + ax1.set_aspect('equal') + plt.title('rho_x') + + # plot y gradient + plt.axes(ax2) + plt.pcolormesh(X, Y, rho_y) + plt.colorbar() + ax2.set_aspect('equal') + plt.title('rho_y') + + # plot density + plt.axes(ax3) + plt.pcolormesh(X, Y, rho) + plt.colorbar() + ax3.set_aspect('equal') + plt.title('rho') + + # plot density uncertainty7 + plt.axes(ax4) + plt.pcolormesh(X, Y, sigma_rho) + plt.colorbar() + ax4.set_aspect('equal') + plt.title('sigma rho') + + # plt.tight_layout() + + return fig + + +def create_border_array(nr, nc, fill_val=1): + """ + Function to create a binary array with non-zero elements along the four boundaries + + Args: + nr, nc (int): number of rows and columns of the binary array to be created + fill_val (int, optional): non-zero value to be assigned to the border elements. Defaults to 1. + + Returns: + border_array: the 2d array with non-zero elements along the borders + """ + + # create array with fill val + border_array = np.ones((nr, nc)) * fill_val + border_array[1:-1, 1:-1] = 0 + + return border_array + + +def set_bc(nr, nc, rho_0, sigma_rho_0): + """ + Function to set matrices to enforce dirichlet boundary conditions + + Args: + nr, nc (int): number of rows and columns + rho_0 (float, scalar): reference density (kg/m^3) + sigma_rho_0 (float, scalar): uncertainty in reference density (kg/m^3) + + Returns: + dirichlet_label: binary array specifying regions where reference density will be imposed + rho_dirichlet (float 2D): array containing reference density values at the non-zero dirichlet label points + sigma_rho_dirichlet (float 2D): array containing reference density UNCERTAINTY values at the non-zero dirichlet label points + """ + + # define dirichlet boundary points (minimum one point) - here defined to be all boundaries + # THIS NEEDS TO BE MODIFIED FOR EACH EXPERIMENT + dirichlet_label = create_border_array(nr, nc, fill_val=1) + + # # sample to set left boundary to be 1s + # dirichlet_label = np.zeros((nr, nc)) + # dirichlet_label[:, 0] = 1 + # dirichlet_label[10, 0] = 1 + + # set density and density uncertainty at these boundary points + # HERE SET TO BE THE SAME VALUE FOR ALL BOUNDARY POINTS + rho_dirichlet = rho_0 * dirichlet_label + sigma_rho_dirichlet = sigma_rho_0 * dirichlet_label + + # convert to boolean array + dirichlet_label = dirichlet_label.astype('bool') + + return dirichlet_label, rho_dirichlet, sigma_rho_dirichlet + + +def calculate_gradients_from_displacements(U, experimental_parameters): + """ + Function to calculate density gradients from displacements using the BOS equation + + Inputs: + U: pixel displacements + experimental_parameters: dictionary of optical layout and other parameters + + Returns: + rho_x: density gradient (kg/m^4) + """ + # extract experimental parameters + M, Z_D, l_p, delta_z, gladstone_dale, n_0 = experimental_parameters['magnification'], experimental_parameters['Z_D'], experimental_parameters['pixel_pitch'], experimental_parameters['delta_z'], experimental_parameters['gladstone_dale'], experimental_parameters['n_0'] + + # gradient calculation from BOS equation + rho_x = U * l_p * 1 / (Z_D * M * delta_z) * 1 / gladstone_dale * n_0 + + return rho_x + + +def convert_displacements_to_physical_units(X_pix, Y_pix, U, V, sigma_U, sigma_V, experimental_parameters, mask): + """ + Function to convert displacements to density gradients and co-ordinates to physical units. + + Args: + X_pix, Y_pix (float): co-ordinate grid in pixels + U, V (float): X, Y displacements in pixels + sigma_U, sigma_V (float): X, Y displacements uncertainty in pixels + experimental_parameters (dict): structure of all the experimental parameters + mask (float): binary array of the integration mask + + Returns: + X, Y: co-ordinate grid in meters + rho_x, rho_y (float): X, Y density gradients (kg/m^4) + sigma_rho_x, sigma)rho_y (float): X, Y density gradient uncertainties (kg/m^4) + """ + + # calculate co-ordinates in the density gradient plane (m) + X = (X_pix - experimental_parameters['x0']) * experimental_parameters['pixel_pitch'] * 1 / experimental_parameters['magnification_grad'] + Y = (Y_pix - experimental_parameters['y0']) * experimental_parameters['pixel_pitch'] * 1 / experimental_parameters['magnification_grad'] + + # calculate density gradients from displacements (kg/m^4) + rho_x = calculate_gradients_from_displacements(U, experimental_parameters) + rho_y = calculate_gradients_from_displacements(V, experimental_parameters) + + # calculate density gradient uncertainty from displacement uncertainty (kg/m^4) + # sigma_rho_x = calculate_gradients_from_displacements(sigma_U, experimental_parameters) + # sigma_rho_y = calculate_gradients_from_displacements(sigma_V, experimental_parameters) + + # calculate density gradient uncertainty from displacement uncertainty (kg/m^4) + factor_1 = experimental_parameters['pixel_pitch'] * \ + 1 / (experimental_parameters['magnification'] * experimental_parameters['gladstone_dale'] * + experimental_parameters['n_0'] * experimental_parameters['Z_D']) + + factor_2 = experimental_parameters['pixel_pitch'] * \ + 1 / (experimental_parameters['gladstone_dale'] * + experimental_parameters['n_0'] * experimental_parameters['Z_D']) * \ + 1/experimental_parameters['magnification']**2 * experimental_parameters['sigma_M'] + + factor_3 = experimental_parameters['pixel_pitch'] * \ + 1 / (experimental_parameters['magnification'] * experimental_parameters['gladstone_dale'] * + experimental_parameters['n_0']) * \ + 1/experimental_parameters['Z_D']**2 * experimental_parameters['sigma_Z_D'] + + sigma_rho_x = np.sqrt((sigma_U * factor_1)**2 + (U * factor_2)**2 + (U * factor_3)**2) + sigma_rho_y = np.sqrt((sigma_V * factor_1)**2 + (V * factor_2)**2 + (V * factor_3)**2) + + # -------------------------- + # enforce mask and ensure valid values for uncertainties + # -------------------------- + # set uncertainties in masked regions to be zero (e.g. for image matching) + sigma_rho_x[mask == False] = 0.0 + sigma_rho_y[mask == False] = 0.0 + + # set nan values to be zero + sigma_rho_x[~np.isfinite(sigma_rho_x)] = 0.0 + sigma_rho_y[~np.isfinite(sigma_rho_y)] = 0.0 + + # set zero values to a small non-zero number (OR WLS will blow up) + sigma_rho_x[sigma_rho_x == 0] = 1e-8 + sigma_rho_y[sigma_rho_y == 0] = 1e-8 + + return X, Y, rho_x, rho_y, sigma_rho_x, sigma_rho_y + + +def create_mask(nr, nc, Eval): + """ + Function to create the integration mask + + Args: + nr (int): number of rows + nc (int): number of columns + Eval (float): binary array of the mask + + Returns: + mask (bool): integration mask as a boolean array (True for integration, False otherwise) + """ + + # -------------------------- + # set mask + # -------------------------- + # create binary mask. True for flow, False for blocked region. + if len(Eval.shape) == 1: + # mask = np.reshape(a=Eval, newshape=(X.shape[1], X.shape[0])) + mask = np.reshape(a=Eval, newshape=(nc, nr)) + mask = np.transpose(mask) + else: + mask = Eval + + return mask + + +def load_displacements_correlation(filename, displacement_uncertainty_method): + """ + Function to load the displacements from Prana processing + + Args: + filename (str): file name + displacement_uncertainty_method (str): name of the displacement uncertainty method + + Returns: + X_pix, Y_pix: pixel co-ordinate grid + U, V: X, Y displacements + sigma_U, sigma_V: X, Y, displacement uncertainties + Eval: Processing mask (binary array) + """ + + # load the data: + data = loadmat_functions.loadmat(filename=filename) + + # extract co-ordinates + X_pix = data['X'].astype('float') + Y_pix = data['Y'].astype('float') + + # extract displacements (sign conversion for the SAMPLE DATASET ONLY) + U = data['U'] + V = data['V'] + + # extract displacement uncertainties + sigma_U = data['uncertainty2D'][displacement_uncertainty_method + 'x'] + sigma_V = data['uncertainty2D'][displacement_uncertainty_method + 'y'] + + # bias correction for MC + if displacement_uncertainty_method == 'MC': + sigma_U = np.sqrt(sigma_U ** 2 - data['uncertainty2D']['biasx'] ** 2) + sigma_V = np.sqrt(sigma_V ** 2 - data['uncertainty2D']['biasy'] ** 2) + + # extract mask + Eval = data['Eval'] + 1 + + return X_pix, Y_pix, U, V, sigma_U, sigma_V, Eval + + +def grid_PTV_velocity_uncertainty_2D(Xn, Yn, fluid_mask, xp, yp, up, vp, up_unc, vp_unc, N_avg=3, dist_epsilon=1e-6): + # This function maps the velocity and its uncertainty from PTV data (on unstructured particle locations) to + # a predefined Cartesian grid using inverse-distance based weighted average. + # Inputs: + # Xn, Yn: 2d array specifying the Cartesian grid. + # fluid_mask: 2d array of a binary mask specifying the flow region. The particle data will be interpolated only onto the grid points with fluid_mask==True + # xp, yp: 1d array of particle locations. + # up, vp: 1d array of particle velocity values. + # up_unc, vp_unc: 1d array of paticle velocity uncertainty (std). + # N_avg: the number of particle data points used to determine the velocity for each grid point. + # dist_epsilon: the minimum distance allowed for setting up the weights (to avoid signularity). + # Outputs: + # Un, Vn: the 3d arrays of velocity on grid. + # Un_unc, Vn_unc: 3d arrays of velocity uncertainty on grid. + # Cov_u, Cov_v: the sparse matrices of covariance matrices of interpolated velocity. + + Ny,Nx = np.shape(Xn) + + j,i = np.where(fluid_mask==True) + Npts = len(j) + Np = len(xp) + + # Setup the linear operator to map the p velocity to grid using inverse distance based average + Map_M = scysparse.csr_matrix((Npts,Np),dtype=np.float) + for ct_pt in range(Npts): + x_grid = Xn[j[ct_pt],i[ct_pt]] + y_grid = Yn[j[ct_pt],i[ct_pt]] + # find closest particles for linear interpolation. + dist = ((xp - x_grid)**2 + (yp - y_grid)**2)**0.5 + dist[dist