diff --git a/Analysis.py b/Analysis.py deleted file mode 100644 index f03d660..0000000 --- a/Analysis.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Jan 24 18:02:05 2023 - -@author: marcu -""" - -import matplotlib.pyplot as plt -import numpy as np -import h5py -import pickle -import seaborn as sns - -class CoefficientAnalysis(object): - - def __init__(self, visualizer): - """ - Nothing as yet... - - Returns - ------- - Also nothing... - - """ - self.visualizer = visualizer # need to re-structure this... or do I - - def JointPlot(self, model, y_var_str, x_var_str, t, x_range, y_range,\ - interp_dims, method, y_component_indices, x_component_indices): - y_data_to_plot, points = \ - self.visualizer.get_var_data(model, y_var_str, t, x_range, y_range, interp_dims, method, y_component_indices) - x_data_to_plot, points = \ - self.visualizer.get_var_data(model, x_var_str, t, x_range, y_range, interp_dims, method, x_component_indices) - fig = plt.figure(figsize=(16,16)) - sns.jointplot(x=x_data_to_plot.flatten(), y=y_data_to_plot.flatten(), kind="hex", color="#4CB391") - plt.title(y_var_str+'('+x_var_str+')') - fig.tight_layout() - plt.show() - - def DistributionPlot(self, model, var_str, t, x_range, y_range, interp_dims, method, component_indices): - - data_to_plot, points = \ - self.visualizer.get_var_data(model, var_str, t, x_range, y_range, interp_dims, method, component_indices) - - # print(data_to_plot) - - fig = plt.figure(figsize=(16,16)) - sns.displot(data_to_plot) - plt.title(var_str) - fig.tight_layout() - plt.show() - - - - - - - - - - - - - - - - - - - diff --git a/FileReaders.py b/FileReaders.py deleted file mode 100644 index 4b38791..0000000 --- a/FileReaders.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Mar 31 10:00:00 2023 -@author: Thomas -""" - -import h5py -import glob -import numpy as np - -class METHOD_HDF5(object): - - def __init__(self, directory): - """ - Set up the list of files (from hdf5) and dictionary with dataset names - in the hdf5 file. - Parameters - ---------- - directory: string - the filenames in the directory have to be incremental (sorted is used) - """ - - hdf5_filenames = sorted( glob.glob(directory+str('*.hdf5'))) - self.hdf5_files = [] - for filename in hdf5_filenames: - self.hdf5_files.append(h5py.File(filename,'r')) - self.num_files = len(self.hdf5_files) - - self.hdf5_keys = dict.fromkeys(list(self.hdf5_files[0].keys())) - for key in self.hdf5_keys: - self.hdf5_keys[key] = list(self.hdf5_files[0][key].keys()) - - def get_hdf5_keys(self): - return self.hdf5_keys - - def read_in_data(self, micro_model): - """ - Store data from files into micro_model - Parameters - ---------- - micro_model: class MicroModel - strs in micromodel have to be the same as hdf5 files output from METHOD. - """ - for prim_var_str in micro_model.prim_vars: - try: - for counter in range(self.num_files): - micro_model.prim_vars[prim_var_str].append( self.hdf5_files[counter]["Primitive/"+prim_var_str][:] ) - # The [:] is for returning the arrays not the dataset - micro_model.prim_vars[prim_var_str] = np.array(micro_model.prim_vars[prim_var_str]) - except KeyError: - print(f'{prim_var_str} is not in the hdf5 dataset: check Primitive/') - - - for aux_var_str in micro_model.aux_vars: - try: - for counter in range(self.num_files): - micro_model.aux_vars[aux_var_str].append( self.hdf5_files[counter]["Auxiliary/"+aux_var_str][:] ) - micro_model.aux_vars[aux_var_str] = np.array(micro_model.aux_vars[aux_var_str]) - except KeyError: - print(f'{aux_var_str} is not in the hdf5 dataset: check Auxiliary/') - - # As METHOD saves endTime, the time variables (and points) need to be dealt with separately - for dom_var_str in micro_model.domain_int_strs: - try: - if dom_var_str == 'nt': - pass - else: - micro_model.domain_vars[dom_var_str] = int( self.hdf5_files[0]['Domain/' + dom_var_str][:]) - except KeyError: - print(f'{dom_var_str} is not in the hdf5 dataset: check Domain/') - - for dom_var_str in micro_model.domain_float_strs: - try: - if dom_var_str in ['tmin', 'tmax']: - pass - else: - micro_model.domain_vars[dom_var_str] = float( self.hdf5_files[0]['Domain/' + dom_var_str][:]) - except KeyError: - print(f'{dom_var_str} is not in the hdf5 dataset: check Domain/') - - for dom_var_str in micro_model.domain_array_strs: - try: - if dom_var_str in ['t','points']: - pass - else: - micro_model.domain_vars[dom_var_str] = self.hdf5_files[0]['Domain/' + dom_var_str][:] - except KeyError: - print(f'{dom_var_str} is not in the hdf5 dataset: check Domain/') - - # for dom_var_str in micro_model.domain_vars: - # try: - # if dom_var_str in ['t','nt','tmin','tmax','points']: - # pass - # if dom_var_str in ['x', 'y']: - # micro_model.domain_vars[dom_var_str] = self.hdf5_files[0]['Domain/' + dom_var_str][:] - # if dom_var_str in ['nx', 'ny']: - # micro_model.domain_vars[dom_var_str] = int(self.hdf5_files[0]['Domain/' + dom_var_str][:] - # else: - # micro_model.domain_vars[dom_var_str] = self.hdf5_files[0]['Domain/' + dom_var_str][:] - # except KeyError: - # print(f'{dom_var_str} is not in the hdf5 dataset: check Domain/') - - micro_model.domain_vars['nt'] = self.num_files - for counter in range(self.num_files): - micro_model.domain_vars['t'].append( float(self.hdf5_files[counter]['Domain/endTime'][:])) - micro_model.domain_vars['t'] = np.array(micro_model.domain_vars['t']) - micro_model.domain_vars['tmin'] = np.amin(micro_model.domain_vars['t']) - micro_model.domain_vars['tmax'] = np.amax(micro_model.domain_vars['t']) - micro_model.domain_vars['points'] = [micro_model.domain_vars['t'], micro_model.domain_vars['x'], \ - micro_model.domain_vars['y']] - - -if __name__ == '__main__': - - from MicroModels import * - - FileReader = METHOD_HDF5('./Data/test_res100/') - MicroModel = IdealMHD_2D() - - # print(FileReader.get_hdf5_keys()) - # FileReader.micro_model_compatibility(MicroModel) - FileReader.read_in_data(MicroModel) - for str in MicroModel.domain_vars: - print(str + ' ',type(MicroModel.domain_vars[str]),' ', MicroModel.domain_vars[str], '\n') - \ No newline at end of file diff --git a/Filters.py b/Filters.py deleted file mode 100644 index 1177f75..0000000 --- a/Filters.py +++ /dev/null @@ -1,392 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Tue Mar 28 15:36:01 2023 - -@author: Marcus -""" - -import numpy as np -import scipy.integrate as integrate -from scipy.optimize import minimize -from itertools import product - -from MicroModels import * -from FileReaders import * -from system.BaseFunctionality import * - -class Favre_observers(object): - - def __init__(self, micro_model, box_len): - """ - Parameters: - ----------- - micro_model: instance of class containing the microdata - - Note: - ----- - To-do: think about checking compatibility (dimension + baryon currrent) - """ - self.micro_model = micro_model - self.spatial_dims = micro_model.spatial_dims - self.L = box_len - - def set_box_length(self, bl): - self.L = bl - - def get_tetrad_from_U(self, U): - """ - Build tetrad orthogonal to unit velocity with from complete velocity vector - - Parameters: - ----------- - U: list of d+1 floats, with d the number of spatial dimensions - - Return: - ------- - list of arrays: U + d unit vectors that complete it to a orthonormal basis - """ - es =[] - for _ in range(self.spatial_dims): - es.append(np.zeros(self.spatial_dims+1)) - for i in range(len(es)): - es[i][i+1] = 1 - tetrad = [U] - for i, vec in enumerate(es): #enumerate returns a tuple: so acts by value not reference! - vec = vec + np.multiply(Base.Mink_dot(vec, U), U) - for j in range(i-1,-1,-1): - vec = vec - np.multiply(Base.Mink_dot(vec, es[j]), es[j]) - es[i] = np.multiply(vec, 1 / np.sqrt(Base.Mink_dot(vec, vec))) - tetrad += [es[i]] - return tetrad - - def get_tetrad_from_vels(self, spatial_vels): - """ - Build tetrad orthogonal to unit velocity with spatial velocities spatial_vels - - Parameters: - ----------- - spatial_vels: list of d floats, with d the number of spatial dimensions - - Return: - ------- - list of arrays: U + d unit vectors that complete it to a orthonormal basis - """ - - U = np.array(Base.get_rel_vel(spatial_vels)) - return self.get_tetrad_from_U(U) - - - def Favre_residual(self, spatial_vels, point, lin_spacing): - """ - Compute the drift of baryons through the box built from vx_vy. - First get the center of the 2*(d+1) faces of the (d+1)-box, then build coords - for points to sample the flux through each face. - Next, approximate the flux integral as a sum - - Parameters: - ----------- - spatial_vels: list of d (spatial dimension) floats, spatial coord of vel - - point: list of d+1 floats (t,x,y) for the box center - - lin_spacing: integer, lin_spacing**spatial_dim is the # of points used to - sample the flux through each face. - - Returns: - -------- - float: absolute flux - - Notes: - ------ - Much faster than method based on inbuilt dblquad: 100 points (per face) gives decent - results, and is 250 times faster. - """ - - tetrad = self.get_tetrad_from_vels(spatial_vels) - flux = 0 - - for vec in tetrad: - rem_vecs = [x for x in tetrad if not (x==vec).all()] - for i in range(2): - center = point + np.multiply( (-1)**i * self.L / 2, vec) - - xs = [] - for i in range(self.spatial_dims): - xs.append(np.linspace(-self.L /2 , self.L /2, lin_spacing)) - coords = [] - for element in product(*xs): - coords.append(np.array(element)) - - surf_coords = [] - for coord in coords: - temp = center - for i in range(self.spatial_dims): - temp += np.multiply(coord[i], rem_vecs[i]) - surf_coords.append(temp) - - for coord in surf_coords: - U = self.micro_model.get_interpol_var(['bar_vel'], coord)[0] - rho = self.micro_model.get_interpol_var(['rho'], coord) - Na = np.multiply(rho, U) - flux += Base.Mink_dot(Na, vec) - - flux *= (self.L / lin_spacing) ** self.spatial_dims - return abs(flux) - - - def point_flux(self, x, y , point, Vx, Vy, normal): - """ - Compute the baryon flux at a point given two coordinates that param the surface - Identified by normal. - - Parameters: - ----------- - coords: d floats, adapted coordinates of the box face - - point: list of floats (t,x,y) - - Vx, Vy: (2+1)-arrays, tangent vectors to the box face - - normal: (2+1)-array, normal to the box face - - Returns: - -------- - Float: flux at the point - - Notes: - ------ - As this is used in Favre_residual_ib - which uses dblquad - this method has been - developed for the 2+1 dimensional case only. - """ - coords = point + np.multiply(x, Vx) + np.multiply(y, Vy) - U = self.micro_model.get_interpol_struct('bar_vel', coords) - rho = self.micro_model.get_interpol_prim(['rho'], coords) - Na = np.multiply(rho, U) - flux = Base.Mink_dot(Na, normal) - return flux - - def Favre_residual_ib(self, vx_vy, point): - """ - Compute the residual using inbuilt method dblquad - Based on function point_flux - - Parameters: - ----------- - Vs: list of d floats, spatial components of the velocity vec - - point: float, center of the box - - Returns: - -------- - tuple: absolute flux and error estimate - - Notes: - ------ - Vastly slower than method above. - As this is based on dblquad, this method works fine only if it's 2+1 dim - - """ - if self.spatial_dim != 2: - print('This method uses a 2-dim integrator, so works fine only for 2 spatial dimensions ') - return [] - - xy_range = [- self.L / 2, + self.L / 2] - tetrad = self.get_tetrad_from_vels(vx_vy) - flux = 0 - partial_flux = 0 - error = 0 - partial_error = 0 - - for vec in tetrad: - rem_vecs = [x for x in tetrad if not (x==vec).all()] - for i in range(2): - partial_flux, partial_error = integrate.dblquad(self.point_flux, xy_range[0], xy_range[1], xy_range[0], xy_range[1], \ - args = (point, rem_vecs[0],rem_vecs[1],vec), epsabs = 1e-6 )[:] - flux += partial_flux - error += partial_error - return abs(flux) , error - - - def find_observers(self, num_points, ranges, spacing): - """ - Main function: minimize the Favre_residual and find the Favre observers for points - in linearly spaced (with spacing num_points) in the ranges. - Spacing is the param passed to Favre_residual to sample the box faces. - - Parameters: - ----------- - num_points: list of floats (t,x,y,(z)) - number of points to find observers at - - ranges: list of lists of two floats [[t_min,t_max], ...] - Define the coord ranges to find observers at - - spacing: integer - param to be passed to Favre_residual - - Returns: - -------- - list of: - 1) coordinates at which minimization is successful - 2) corresponding observers - 3) corresponding residual - - list of coordinates at which the minimization failed - - Notes: - ------ - This uses the faster residual, not the one based on the inbuilt dblquad - """ - - list_of_coords = [] - for i in range(len(num_points)): - list_of_coords.append( np.linspace( ranges[i][0], ranges[i][-1] , num_points[i]) ) - - coords = [] - for element in product(*list_of_coords): - coords.append(np.array(element)) - - observers = [] - funs = [] - success_coords = [] - failed_coords = [] - - for coord in coords: - U = self.micro_model.get_interpol_var(['bar_vel'], coord)[0] - guess = [] - for i in range(1, len(U)): - guess.append(U[i] / U[0]) - guess = np.array(guess) - sol = minimize(self.Favre_residual, x0 = guess, args = (coord, spacing), bounds=((-0.8,0.8),(-0.8,0.8)),tol=1e-6) - # This rearrangement shouldn't be necessary!?!? - try: - if sol.success: - observers.append(Base.get_rel_vel(sol.x)) - funs.append(sol.fun) - success_coords.append(coord) - - if (sol.fun > 1e-5): - print(f"Warning, residual is large at {coord}: ", sol.fun) - except: - print(f'Failed for coordinates: {coord}, due to', sol.message) - failed_coords.append(coord) - - return [success_coords, observers, funs] , failed_coords - - def filter_prim_var(self, centre_coord, U, var_str, shape='box'): - """ - Filter a variable over the volume of a box with centre given by 'point'. - Originally done by scipy integration over the volume, but again incredibly - slow so now a manual sum over all the cells within the box and then a - division by total number of cells. - """ - tetrad = self.get_tetrad_from_U(U) - start_coord, end_coord = centre_coord, centre_coord - for coord, vec in zip(centre_coord, tetrad): - start_coord -= np.array(vec)*self.L/2 - end_coord += np.array(vec)*self.L/2 - integrand = 0 - counter = 0 - start_cell, end_cell = Base.find_nearest_cell(start_coord, self.micro_model.domain_vars['points']),\ - Base.find_nearest_cell(end_coord, self.micro_model.domain_vars['points']) - for i in range(start_cell[0],end_cell[0]+1): - for j in range(start_cell[1],end_cell[1]+1): - for k in range(start_cell[2],end_cell[2]+1): - integrand += self.micro_model.prim_vars[var_str][i,j,k] - counter += 1 - return integrand/counter - - def filter_struc(self, centre_coord, U, var_str, shape='box'): - """ - Filter a variable over the volume of a box with centre given by 'point'. - Originally done by scipy integration over the volume, but again incredibly - slow so now a manual sum over all the cells within the box and then a - division by total number of cells. - """ - # contruct tetrad... - tetrad = self.get_tetrad_from_U(U) - start_coord, end_coord = centre_coord, centre_coord - for coord, vec in zip(centre_coord, tetrad): - start_coord -= np.array(vec)*self.L/2 - end_coord += np.array(vec)*self.L/2 - integrand = 0 - counter = 0 - start_cell, end_cell = Base.find_nearest_cell(start_coord, self.micro_model.domain_vars['points']),\ - Base.find_nearest_cell(end_coord, self.micro_model.domain_vars['points']) - for i in range(start_cell[0],end_cell[0]+1): - for j in range(start_cell[1],end_cell[1]+1): - for k in range(start_cell[2],end_cell[2]+1): - integrand += self.micro_model.structures[var_str][i,j,k] - counter += 1 - return integrand/counter - - def get_interpol_var(self, t, x, y, var_str): - return self.micro_model.get_interpol_var(var_str, [t,x,y]) - - def filter_var_ib(self, point, spatial_vels, var_str, shape='box'): - """ - Filter a variable over the volume of a box with centre given by 'point'. - Originally done by scipy integration over the volume, but again incredibly - slow so now a manual sum over all the cells within the box and then a - division by total number of cells. - """ - # contruct tetrad... - tetrad = self.get_tetrad_from_vels(spatial_vels) - # t_range = - # corners = self.find_boundary_pts(E_x,E_y,point,self.L) - # start, end = corners[0], corners[2] - integrand = 0 - integrand, error = integrate.tplquad(self.get_interpol_var, t_range[0], t_range[1],\ - x_range[0], x_range[1], y_range[0], y_range[1],\ - args = var_str, epsabs = 1e-6 )[:] - - return vol_integrand/(self.L)**3, error - -# if __name__ == '__main__': -# CPU_start_time = time.process_time() - -# FileReader = METHOD_HDF5('./Data/Testing/') -# # micro_model = IdealMHD_2D() -# micro_model = IdealHydro_2D() -# FileReader.read_in_data(micro_model) -# micro_model.setup_structures() - -# filter = Favre_observers(micro_model,box_len=0.001) - -# # tetrad = filter.get_tetrad_from_vxvy([0.5,0.73]) -# # print(type(tetrad[0]),' ',type(tetrad[1]),' ',type(tetrad[2]),'\n', tetrad[0],' ',tetrad[1],' ',tetrad[2],'\n') -# # print(filter.Mink_dot(tetrad[0],tetrad[1]), filter.Mink_dot(tetrad[0],tetrad[2]), filter.Mink_dot(tetrad[1],tetrad[2])) -# # print(type(tetrad)) - -# # smart_guess = micro_model.get_interpol_prim(['vx','vy'],[0.5,0.5,0.5]) - -# # CPU_start_time = time.process_time() -# # res = filter.Favre_residual(smart_guess,[0.5,0.5,0.5], 10) -# # print('Residual: ',res,f'\nElapsed CPU time is {time.process_time() - CPU_start_time} with {10**filter.spatial_dim} points per face\n') - -# # CPU_start_time = time.process_time() -# # res, error = filter.Favre_residual_ib(smart_guess,[0.5,0.5,0.5])[:] -# # print('Residual: ',res,"\nError estimate: ",error,f'\nElapsed CPU time is {time.process_time() - CPU_start_time} with the inbuilt method') - -# CPU_start_time = time.process_time() -# coord_range = [[9.995,10.005],[-0.2,-0.3],[0.5,0.7]] -# num_points = [1,1,1] - -# min_res, failed_coord = filter.find_observers(num_points, coord_range, 10) -# for i in range(len(min_res[0])): -# for j in range(len(min_res)): -# print(min_res[j][i]) -# print('\n') - -# num_minim = 1 -# for x in num_points: -# num_minim *= x -# print(f'Elapsed CPU time for finding {num_minim} observer(s) is {time.process_time() - CPU_start_time}.') -# print('Failed coordinates:', failed_coord) - - - - - - - \ No newline at end of file diff --git a/MesoModels.py b/MesoModels.py deleted file mode 100644 index 912db1e..0000000 --- a/MesoModels.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Mar 27 18:53:53 2023 - -@author: Marcus -""" - -import numpy as np -from scipy.integrate import quad -from multiprocessing import Process, Pool -from system.BaseFunctionality import * -import pickle - -class NonIdealHydro2D(object): - - def __init__(self, MicroModel, ObsFinder, Filter, interp_method = "linear"): - self.MicroModel = MicroModel - self.ObsFinder = ObsFinder - self.Filter = Filter - self.spatial_dims = 2 - self.n_dims = self.spatial_dims + 1 - self.interp_method = interp_method - - self.domain_var_strs = ('Nt','Nx','Ny','dT','dX','dY','points') - self.domain_vars = dict.fromkeys(self.domain_var_strs) - - #Dictionary for 'local' variables, - #obtained from filtering the appropriate MicroModel variables - self.filter_var_strs = ("BC","SET") - self.filter_vars = dict.fromkeys(self.filter_var_strs) - - #Dictionary for MesoModel variables - self.meso_var_strs = ("U","U_coords","U_errors","T~","N") - self.meso_vars = dict.fromkeys(self.meso_var_strs) - - #Strings for 'non-local' variables - ones we need to take derivatives of - self.nonlocal_var_strs = ("U","T~") - - #Dictionary for derivative variables - calculated by finite differencing - self.deriv_var_strs = ("dtU","dxU","dyU","dtT~","dxT~","dyT~") - self.deriv_vars = dict.fromkeys(self.deriv_var_strs) - - #Dictionary for dissipative residuals - from the NonId-SET that we take - #projections of - self.diss_residual_strs = ("Pi","q","pi") - self.diss_residuals = dict.fromkeys(self.diss_residual_strs) - - self.diss_var_strs = ("Theta","Omega","Sigma") - self.diss_vars = dict.fromkeys(self.diss_residual_strs) - - self.diss_coeff_strs = ("Zeta", "Kappa", "Eta") - self.diss_coeffs = dict.fromkeys(self.diss_coeff_strs) - - self.coefficient_strs = ("Gamma") - self.coefficients = dict.fromkeys(self.diss_coeff_strs) - self.coefficients['Gamma'] = 4.0/3.0 - - #Dictionary for all vars - useful for e.g. plotting - self.all_var_strs = self.filter_var_strs + self.meso_var_strs + self.deriv_var_strs\ - + self.diss_residual_strs + self.diss_var_strs + self.diss_coeff_strs - - # Stencils for finite-differencing - self.cen_SO_stencil = [1/12, -2/3, 0, 2/3, -1/12] - self.cen_FO_stencil = [-1/2, 0, 1/2] - self.fw_FO_stencil = [-1, 1] - self.bw_FO_stencil = [-1, 1] - - self.metric = np.zeros((3,3)) - self.metric[0,0] = -1 - self.metric[1,1] = self.metric[2,2] = +1 - - # Run some compatability test... - compatible = True - if self.spatial_dims != self.MicroModel.spatial_dims: - compatible = False - for filter_var_str in self.filter_var_strs: - if not (filter_var_str in MicroModel.vars.keys()): - compatible = False - - if compatible: - print("Meso and Micro models are compatible!") - else: - print("Meso and Micro models are incompatible!") - - def get_all_var_strs(self): - return self.all_var_strs - - def get_model_name(self): - return 'NonIdealHydro2D' - - def find_observers(self, num_points, ranges):#, spacing): - # self.meso_vars['U_coords'], self.meso_vars['U'], self.meso_vars['U_errors'] = \ - # self.ObsFinder.find_observers(num_points, ranges, spacing)[0] - self.meso_vars['U_coords'], self.meso_vars['U'], self.meso_vars['U_errors'] = \ - self.ObsFinder.find_observers_ranges(num_points, ranges)[0] - self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny'] = num_points[:] - self.domain_vars['dT'] = (ranges[0][-1] - ranges[0][0]) / self.domain_vars['Nt'] - self.domain_vars['dX'] = (ranges[1][-1] - ranges[1][0]) / self.domain_vars['Nx'] - self.domain_vars['dY'] = (ranges[2][-1] - ranges[2][0]) / self.domain_vars['Ny'] - self.domain_vars['points'] = [np.linspace(ranges[0][0], ranges[0][-1], num_points[0]),\ - np.linspace(ranges[1][0], ranges[1][-1], num_points[1]),\ - np.linspace(ranges[2][0], ranges[2][-1], num_points[2])] - - def setup_variables(self): - Nt, Nx, Ny = self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny'] - n_dims = self.spatial_dims+1 - self.meso_vars['U_coords'] = np.array(self.meso_vars['U_coords']).reshape([Nt, Nx, Ny, n_dims]) - self.meso_vars['U'] = np.array(self.meso_vars['U']).reshape([Nt, Nx, Ny, n_dims]) - self.meso_vars['U_errors'] = np.array(self.meso_vars['U_errors']).reshape([Nt, Nx, Ny, 2]) - self.meso_vars['T~'] = np.zeros((Nt, Nx, Ny)) - self.meso_vars['N'] = np.zeros((Nt, Nx, Ny)) - - self.filter_vars['BC'] = np.zeros((Nt, Nx, Ny, n_dims)) - self.filter_vars['SET'] = np.zeros((Nt, Nx, Ny, n_dims,n_dims)) - - for nonlocal_var_str in self.nonlocal_var_strs: - self.deriv_vars['dt'+nonlocal_var_str] = np.zeros_like(self.meso_vars[nonlocal_var_str]) - self.deriv_vars['dx'+nonlocal_var_str] = np.zeros_like(self.meso_vars[nonlocal_var_str]) - self.deriv_vars['dy'+nonlocal_var_str] = np.zeros_like(self.meso_vars[nonlocal_var_str]) - - self.diss_residuals['Pi'] = np.zeros((Nt, Nx, Ny)) - self.diss_vars['Theta'] = np.zeros((Nt, Nx, Ny)) - self.diss_residuals['q'] = np.zeros((Nt, Nx, Ny, n_dims)) - self.diss_vars['Omega'] = np.zeros((Nt, Nx, Ny, n_dims)) - self.diss_residuals['pi'] = np.zeros((Nt, Nx, Ny, n_dims, n_dims)) - self.diss_vars['Sigma'] = np.zeros((Nt, Nx, Ny, n_dims, n_dims)) - - # Single value for each coefficient (per data point) for now... - self.diss_coeffs['Zeta'] = np.zeros((Nt, Nx, Ny)) - self.diss_coeffs['Kappa'] = np.zeros((Nt, Nx, Ny, n_dims)) - self.diss_coeffs['Eta'] = np.zeros((Nt, Nx, Ny, n_dims, n_dims)) - - self.vars = self.filter_vars - self.vars.update(self.meso_vars) - self.vars.update(self.deriv_vars) - self.vars.update(self.diss_residuals) - self.vars.update(self.diss_vars) - self.vars.update(self.diss_coeffs) - - def p_from_EoS(self, rho, n): - """ - Calculate pressure from EoS using rho (energy density) and n (number density) - """ - p = (self.coefficients['Gamma']-1)*(rho-n) - return p - - - def filter_micro_variables(self): - """ - 'Spatially' average required variables from the micromodel w.r.t. - the observers that have been found. - """ - for h in range(self.domain_vars['Nt']): - for i in range(self.domain_vars['Nx']): - for j in range(self.domain_vars['Ny']): - self.filter_vars['BC'][h,i,j] = self.Filter.filter_var_point('BC', self.meso_vars['U_coords'][h,i,j], - self.meso_vars['U'][h,i,j]) - self.filter_vars['SET'][h,i,j] = self.Filter.filter_var_point('SET', self.meso_vars['U_coords'][h,i,j], - self.meso_vars['U'][h,i,j]) - - # self.filter_vars['n'][h,i,j] =\ - # self.Filter.filter_prim_var(self.meso_vars['U_coords'][h,i,j], self.meso_vars['U'][h,i,j], 'n') - # self.filter_vars['SET'][h,i,j] =\ - # self.Filter.filter_struc(self.meso_vars['U_coords'][h,i,j], self.meso_vars['U'][h,i,j], 'SET') - - # Should be able to convert here to only 1 filter function... (not prim/struct) - # for filter_var_str in self.filter_var_strs: - # filter_args = [(coord, U, filter_var_str) for coord, U in zip(self.U_coords, self.Us)] - # with Pool(2) as p: - # self.micro_vars[micro_var_str] = p.starmap(self.Filter.filter_var, filter_args) - # self.micro_vars[micro_var_str] = p.starmap(self.Filter.filter_prim_var, filter_args) - - - def calculate_derivatives(self): - """ - Calculate the required derivatives of MesoModel variables for - constructing the non-ideal terms. - """ - for nonlocal_var_str in self.nonlocal_var_strs: - self.calculate_time_derivatives(nonlocal_var_str) - self.calculate_x_derivatives(nonlocal_var_str) - self.calculate_y_derivatives(nonlocal_var_str) - - def calculate_time_derivatives(self, nonlocal_var_str): - deriv_var_str = 'dt'+nonlocal_var_str - stencil = self.cen_FO_stencil - samples = [-1,0,1] - for h in range(self.domain_vars['Nt']): - if h == 0: - stencil = self.fw_FO_stencil - samples = [0,1] - if h == (self.domain_vars['Nt']-1): - stencil = self.fw_FO_stencil - samples = [-1,0] - for i in range(self.domain_vars['Nx']): - for j in range(self.domain_vars['Ny']): - for s in range(len(samples)): - self.deriv_vars[deriv_var_str][h,i,j] \ - += (stencil[s]*self.meso_vars[nonlocal_var_str][h+samples[s],i,j]) / self.domain_vars['dT'] - - def calculate_x_derivatives(self, nonlocal_var_str): - deriv_var_str = 'dx'+nonlocal_var_str - stencil = self.cen_FO_stencil - samples = [-1,0,1] - for h in range(self.domain_vars['Nt']): - for i in range(self.domain_vars['Nx']): - if i == 0: - stencil = self.fw_FO_stencil - samples = [0,1] - if i == (self.domain_vars['Nx']-1): - stencil = self.fw_FO_stencil - samples = [-1,0] - for j in range(self.domain_vars['Ny']): - for s in range(len(samples)): - # print((stencil[s]*self.meso_vars[nonlocal_var_str][h,i+samples[s],j]) / self.domain_vars['dX']) - self.deriv_vars[deriv_var_str][h,i,j] \ - += (stencil[s]*self.meso_vars[nonlocal_var_str][h,i+samples[s],j]) / self.domain_vars['dX'] - - def calculate_y_derivatives(self, nonlocal_var_str): - deriv_var_str = 'dy'+nonlocal_var_str - stencil = self.cen_FO_stencil - samples = [-1,0,1] - for h in range(self.domain_vars['Nt']): - for i in range(self.domain_vars['Nx']): - for j in range(self.domain_vars['Ny']): - if j == 0: - stencil = self.fw_FO_stencil - samples = [0,1] - if j == (self.domain_vars['Ny']-1): - stencil = self.fw_FO_stencil - samples = [-1,0] - for s in range(len(samples)): - self.deriv_vars[deriv_var_str][h,i,j] \ - += (stencil[s]*self.meso_vars[nonlocal_var_str][h,i,j+samples[s]]) / self.domain_vars['dY'] - - def calculate_dissipative_residuals(self, h, i, j): - """ - Returns the inferred (residual) values of the - dissipative terms from the filtered MicroModel SET. - - Parameters - ---------- - indices : TYPE - DESCRIPTION. - - Returns - ------- - Pi_res : scalar float - Bulk viscosity - q_res : (d+1) vector of floats - Heat flux. - pi_res : (d+1)x(d+1) tensor of floats - Shear viscosity. - - """ - # Move this - # h, i, j = indices - # Filter the scalar fields - BC = self.filter_vars['BC'][h,i,j] - N = np.sqrt(-Base.Mink_dot(BC, BC)) - self.meso_vars['N'][h,i,j] = N - Id_SET = self.filter_vars['SET'][h,i,j] - U = self.meso_vars['U'][h,i,j] - - # Do required projections of SET - h_mu_nu = Base.orthogonal_projector(U, self.metric) - rho_res = Base.project_tensor(U,U,Id_SET) - - # Set Meso temperature from filtered quantities using EoS - p_tilde = self.p_from_EoS(rho_res, N) - T_tilde = p_tilde/N - self.meso_vars['T~'][h,i,j] = T_tilde - - # Calculate dissipative residual with tensor manipulation - q_res = np.einsum('ij,i,jk',Id_SET,U,h_mu_nu) - tau_res = np.einsum('ij,ik,jl',Id_SET,h_mu_nu,h_mu_nu) - tau_trace = np.trace(tau_res) - Pi_res = tau_trace - p_tilde - pi_res = tau_res - np.dot((p_tilde + Pi_res),h_mu_nu) - - # print(Pi_res, q_res, pi_res) - - self.diss_residuals['Pi'][h,i,j] = Pi_res - self.diss_residuals['q'][h,i,j] = q_res - self.diss_residuals['pi'][h,i,j] = pi_res - - def calculate_dissipative_variables(self, h, i, j): - """ - Calculates the non-ideal, dissipation terms (without coefficeints) - for the non-ideal MesoModel SET. - - Parameters - ---------- - indices : list of ints - Indices of data-point. - coord : list of floats - Coordinates in (t,x,y). - - Returns - ------- - Decomposition of the observer velocity: - - Theta : float (scalar) - Divergence (isotropic). - omega : vector of floats - Transverse momentum. - sigma : (d+1)x(d+1) tensor of floats - Symmetric, trace-free. - - """ - # h, i, j = indices - - T = self.meso_vars['T~'][h, i, j] - dtT = self.deriv_vars['dtT~'][h, i, j] - dxT = self.deriv_vars['dxT~'][h, i, j] - dyT = self.deriv_vars['dyT~'][h, i, j] - - # U = self.meso_vars['U'][h,i,j][:] - Ut, Ux, Uy = self.meso_vars['U'][h,i,j][:] - - # print(Ut, Ux, Uy) - - # dtU = self.deriv_vars['dtU'][h,i,j] - dtUt, dtUx, dtUy = self.deriv_vars['dtU'][h,i,j][:] - dxUt, dxUx, dxUy = self.deriv_vars['dxU'][h,i,j][:] - dyUt, dyUx, dyUy = self.deriv_vars['dyU'][h,i,j][:] - - # Need to do this with Einsum... - Theta = dtUt + dxUx + dyUy - a = np.array([Ut*dtUt + Ux*dxUt + Uy*dyUt, Ut*dtUx + Ux*dxUx + Uy*dyUx, Ut*dtUy + Ux*dxUy + Uy*dyUy]) - - Omega = np.array([dtT, dxT, dyT]) + np.multiply(T,a) - Sigma = np.array([[2*dtUt - (2/3)*Theta, dtUx + dxUt, dtUy + dyUt],\ - [dxUt + dtUx, 2*dxUx - (2/3)*Theta, dxUy + dyUx], - [dyUt + dtUy, dyUx + dxUy, 2*dyUy - (2/3)*Theta]]) - - self.diss_vars['Theta'][h,i,j] = Theta - self.diss_vars['Omega'][h,i,j] = Omega - self.diss_vars['Sigma'][h,i,j] = Sigma - - def calculate_dissipative_coefficients(self): - Nt, Nx, Ny = self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny'] - # parallel_args = [(h, i, j) for h in range(Nt) for i in range(Nx) for j in range(Ny)] - # # print(parallel_args) - # with Pool(2) as p: - # p.starmap(self.calculate_dissipative_residuals, parallel_args) - # p.starmap(self.calculate_dissipative_variables, parallel_args) - - # self.diss_coeffs['Zeta'] = -self.diss_residuals['Pi'] / self.diss_vars['Theta'] - for h in range(self.domain_vars['Nt']): - for i in range(self.domain_vars['Nx']): - for j in range(self.domain_vars['Ny']): - self.calculate_dissipative_residuals(h,i,j) - - # Derivative calculations need to be done after all residuals - self.calculate_derivatives() - for h in range(self.domain_vars['Nt']): - for i in range(self.domain_vars['Nx']): - for j in range(self.domain_vars['Ny']): - self.calculate_dissipative_variables(h,i,j) - self.diss_coeffs['Zeta'][h,i,j] = -self.diss_residuals['Pi'][h,i,j] / self.diss_vars['Theta'][h,i,j] - for k in range(self.n_dims): - self.diss_coeffs['Kappa'][h,i,j,k] = -self.diss_residuals['q'][h,i,j,k] / self.diss_vars['Omega'][h,i,j,k] - for l in range(self.n_dims): - self.diss_coeffs['Eta'][h,i,j,k,l] = -self.diss_residuals['pi'][h,i,j,k,l] / self.diss_vars['Sigma'][h,i,j,k,l] - - for diss_coeff_str in self.diss_coeff_strs: - coeffs_handle = open(diss_coeff_str+'.pickle', 'wb') - pickle.dump(self.diss_coeffs[diss_coeff_str], coeffs_handle, protocol=pickle.HIGHEST_PROTOCOL) - - - - - - - - - - - - - - \ No newline at end of file diff --git a/MicroModels.py b/MicroModels.py deleted file mode 100644 index bb407f3..0000000 --- a/MicroModels.py +++ /dev/null @@ -1,555 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Mar 31 10:00:02 2023 - -@author: Thomas -""" - -from FileReaders import * -from scipy.interpolate import interpn -from system.BaseFunctionality import * -import numpy as np -import math -import time - -# These are the symbols, so be careful when using these to construct vectors! -# levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \ -# for k in range(3)]for j in range(3) ] for i in range(3) ]) - -# levi4D = np.array([[[[ np.sign(i - j) * np.sign(j - k) * np.sign(k - l) * np.sign(i - l) \ -# for l in range(4)] for k in range(4) ] for j in range(4)] for i in range(4)]) - - -class IdealMHD_2D(object): - - def __init__(self, interp_method = "linear"): - """ - Sets up the variables and dictionaries, strings correspond to - those used in METHOD - - Parameters - ---------- - interp_method: str - optional method to be used by interpn - """ - self.spatial_dims = 2 - self.interp_method = interp_method - - self.metric = np.zeros((3,3)) - self.metric[0,0] = -1 - self.metric[1,1] = self.metric[2,2] = +1 - - # This is the Levi-Civita symbol, not tensor, so be careful when using it - self.Levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \ - for k in range(3)]for j in range(3) ] for i in range(3) ]) - - #Dictionary for grid: info and points - self.domain_int_strs = ('nt','nx','ny') - self.domain_float_strs = ("tmin","tmax","xmin","xmax","ymin","ymax","dt","dx","dy") - self.domain_array_strs = ("t","x","y","points") - self.domain_vars = dict.fromkeys(self.domain_int_strs+self.domain_float_strs+self.domain_array_strs) - for str in self.domain_vars: - self.domain_vars[str] = [] - - #Dictionary for primitive var - self.prim_strs = ("vx","vy","n","p","Bx","By") - self.prim_vars = dict.fromkeys(self.prim_strs) - for str in self.prim_strs: - self.prim_vars[str] = [] - - #Dictionary for auxiliary var - self.aux_strs = ("W","h","b0","bx","by","bsq") - self.aux_vars = dict.fromkeys(self.aux_strs) - for str in self.aux_strs: - self.aux_vars[str] = [] - - #Dictionary for structures - self.structures_strs = ("BC","SET","Faraday") - self.structures = dict.fromkeys(self.structures_strs) - for str in self.structures_strs: - self.structures[str] = [] - - #Dictionary for all vars - self.all_var_strs = self.prim_strs + self.aux_strs + self.structures_strs - self.all_vars = self.prim_vars.copy() - self.all_vars.update(self.aux_vars) - self.all_vars.update(self.structures) - - def get_model_name(self): - return 'IdealMHD_2D' - - def get_spatial_dims(self): - return self.spatial_dims - - def get_domain_strs(self): - return self.domain_int_strs + self.domain_float_strs + self.domain_array_strs - - def get_prim_strs(self): - return self.prim_strs - - def get_aux_strs(self): - return self.aux_strs - - def get_structures_strs(self): - return self.structures_strs - - def get_all_var_strs(self): - return self.all_var_strs - - def setup_structures(self): - """ - Set up the structures (i.e baryon current, SET and Faraday) - - Structures are built as multi-dim np.arrays, with the first three indices referring - to the grid, while the last one or two refer to space-time components. - """ - self.structures["BC"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3)) - self.structures["SET"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3)) - self.structures["Faraday"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3)) - - for h in range(self.domain_vars['nt']): - for i in range(self.domain_vars['nx']): - for j in range(self.domain_vars['ny']): - vel = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['vx'][h,i,j] ,\ - self.aux_vars['W'][h,i,j] * self.prim_vars['vy'][h,i,j]]) - self.structures['BC'][h,i,j,:] = np.multiply(self.prim_vars['n'][h,i,j], vel ) - - - fibr_b = np.array([self.aux_vars['b0'][h,i,j],self.aux_vars['bx'][h,i,j],self.aux_vars['by'][h,i,j]]) - - - self.structures["SET"][h,i,j,:,:] = (self.prim_vars["n"][h,i,j] + self.prim_vars["p"][h,i,j] + self.aux_vars["bsq"][h,i,j]) * \ - np.outer( vel,vel) + (self.prim_vars["p"][h,i,j] + self.aux_vars["bsq"][h,i,j]/2) * self.metric \ - - np.outer(fibr_b, fibr_b) - - fol_vel_vec = np.zeros(3) - fol_vel_vec[0]=+1 - fol_b_vec = np.array([self.aux_vars["b0"][h,i,j],self.aux_vars["bx"][h,i,j],self.aux_vars["by"][h,i,j]]) - fol_e_vec = np.tensordot( self.Levi3D, np.outer(vel,fol_b_vec), axes = ([1,2],[0,1])) - - self.structures['Faraday'][h,i,j,:,:] = np.outer( fol_vel_vec,fol_e_vec) - np.outer(fol_e_vec,fol_vel_vec) -\ - np.tensordot(self.Levi3D,fol_b_vec,axes=([2],[0])) - - self.vars = self.prim_vars - self.vars.update(self.aux_vars) - self.vars.update(self.structures) - - def get_var_gridpoint(self, var, point): - """ - Returns variable corresponding to input 'var' at gridpoint - closest to input 'point'. - - Parameters: - ----------- - vars: string corresponding to primitive, auxiliary or structure variable - - point: list of 2+1 floats - - Returns: - -------- - Values or arrays corresponding to variable evaluated at the closest grid-point to input 'point'. - - Notes: - ------ - This method should be used in case using interpolated values - becomes too expensive. - """ - indices = Base.find_nearest_cell(point, self.domain_vars['points']) - if var in self.get_prim_strs(): - return self.prim_vars[var][tuple(indices)] - - elif var in self.get_aux_strs(): - return self.aux_vars[var][tuple(indices)] - - elif var in self.get_structures_strs(): - if var == "BC": - tmp = np.zeros(self.structures[var][0,0,0,:].shape) - for a in range(len(self.structures[var][0,0,0,:])): - tmp[a] = self.structures[var][tuple(indices+[a])] - return tmp - else: - tmp = np.zeros(self.structures[var][0,0,0,:,:].shape) - for a in range(len(tmp[:,0])): - for b in range(len(tmp[0,:])): - tmp[a,b] = self.structures[var][tuple(indices+[a,b])] - return tmp - else: - print(f"{var} is not a variable of IdealMHD_2D!") - return None - - def get_interpol_var(self, var, point): - """ - Returns the interpolated variables at the point. - - Parameters - ---------- - vars : str corresponding to primitive, auxiliary or structre variable - - point : list of floats - ordered coordinates: t,x,y - - Return - ------ - Interpolated values/arrays corresponding to variable. - Empty list if none of the variables is a primitive, auxiliary o structure of the micro_model - - Notes - ----- - Interpolation gives errors when applied to boundary - """ - - if var in self.get_prim_strs(): - return interpn(self.domain_vars['points'], self.prim_vars[var], point, method = self.interp_method)[0] - elif var in self.get_aux_strs(): - return interpn(self.domain_vars['points'], self.aux_vars[var], point, method = self.interp_method)[0] - elif var in self.get_structures_strs(): - return interpn(self.domain_vars['points'], self.structures[var], point, method = self.interp_method)[0] - else: - print(f'{var} is not a primitive, auxiliary variable or structure of the micro_model!!') - - - - """ - Returns the interpolated structure at the point - Parameters - ---------- - var : str corresponding to one of the structures - - point : list of floats - ordered coordinates: t,x,y - Return - ------ - Array with the interpolated values of any var - Empty list if var is not a structure in the micro_model - Notes - ----- - Interpolation gives errors when applied to boundary - """ - res = [] - for var_name in var_names: - try: - res.append( interpn(self.domain_vars["points"], self.vars[var_name], point, method = self.interp_method)[0]) - except KeyError: - print(f"{var_name} does not belong to the auxiliary variables of the micro_model!") - return res - -class IdealHydro_2D(object): - - def __init__(self, interp_method = "linear"): - """ - Sets up the variables and dictionaries, strings correspond to - those used in METHOD - - Parameters - ---------- - interp_method: str - optional method to be used by interpn - """ - self.spatial_dims = 2 - self.interp_method = interp_method - - self.metric = np.zeros((3,3)) - self.metric[0,0] = -1 - self.metric[1,1] = self.metric[2,2] = +1 - - # This is the Levi-Civita symbol, not tensor, so be careful when using it - self.Levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \ - for k in range(3)]for j in range(3) ] for i in range(3) ]) - - #Dictionary for grid: info and points - self.domain_int_strs = ('nt','nx','ny') - self.domain_float_strs = ("tmin","tmax","xmin","xmax","ymin","ymax","dt","dx","dy") - self.domain_array_strs = ("t","x","y","points") - self.domain_vars = dict.fromkeys(self.domain_int_strs+self.domain_float_strs + self.domain_array_strs) - for str in self.domain_vars: - self.domain_vars[str] = [] - - #Dictionary for primitive var - self.prim_strs = ("v1","v2","rho","p","n") - self.prim_vars = dict.fromkeys(self.prim_strs) - for str in self.prim_strs: - self.prim_vars[str] = [] - - #Dictionary for auxiliary var - self.aux_strs = ("W","h","T") - self.aux_vars = dict.fromkeys(self.aux_strs) - for str in self.aux_strs: - self.aux_vars[str] = [] - - #Dictionary for structures - self.structures_strs = ("BC","SET") - self.structures = dict.fromkeys(self.structures_strs) - for str in self.structures_strs: - self.structures[str] = [] - - #Dictionary for all vars - self.all_var_strs = self.prim_strs + self.aux_strs + self.structures_strs - - def get_model_name(self): - return 'IdealHydro_2D' - - def get_spatial_dims(self): - return self.spatial_dims - - def get_domain_strs(self): - return self.domain_info_strs + self.domain_points_strs - - def get_prim_strs(self): - return self.prim_strs - - def get_aux_strs(self): - return self.aux_strs - - def get_structures_strs(self): - return self.structures_strs - - def get_all_var_strs(self): - return self.all_var_strs - - def setup_structures(self): - """ - Set up the structures (i.e baryon current, SET) - - Structures are built as multi-dim np.arrays, with the first three indices referring - to the grid, while the last one or two refer to space-time components. - """ - self.structures["BC"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3)) - self.structures["SET"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3)) - - for h in range(self.domain_vars['nt']): - for i in range(self.domain_vars['nx']): - for j in range(self.domain_vars['ny']): - vel = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['v1'][h,i,j] ,\ - self.aux_vars['W'][h,i,j] * self.prim_vars['v2'][h,i,j]]) - self.structures['BC'][h,i,j,:] = np.multiply(self.prim_vars['n'][h,i,j], vel ) - - - self.structures["SET"][h,i,j,:,:] = (self.prim_vars["rho"][h,i,j] + self.prim_vars["p"][h,i,j]) * \ - np.outer(vel,vel) + self.prim_vars["p"][h,i,j] * self.metric - - self.vars = self.prim_vars - self.vars.update(self.aux_vars) - self.vars.update(self.structures) - - - def get_interpol_prim(self, var_names, point): - """ - Returns the interpolated variable at the point - - Parameters - ---------- - vars : list of strings - strings have to be in to prim_vars keys - point : list of floats - ordered coordinates: t,x,y - Return - ------ - list of floats corresponding to string of vars - - Notes - ----- - Interpolation raises a ValueError when out of grid boundaries. - """ - res = [] - - for var_name in var_names: - try: - res.append( interpn(self.domain_vars["points"], self.prim_vars[var_name], point, method = self.interp_method)[0]) #, bounds_error = False) - except KeyError: - print(f"{var_name} does not belong to the primitive variables of the micro_model!") - return res - - def get_interpol_aux(self, var_names, point): - """ - Returns the interpolated variable at the point - - Parameters - ---------- - vars : list of strings - strings have to be in to aux_vars keys - point : list of floats - ordered coordinates: t,x,y - Return - ------ - list of floats corresponding to string of vars - - Notes - ----- - Interpolation gives errors when applied to boundary - """ - - res = [] - for var_name in var_names: - try: - res.append( interpn(self.domain_vars["points"], self.aux_vars[var_name], point, method = self.interp_method)[0]) - except KeyError: - print(f"{var_name} does not belong to the auxiliary variables of the micro_model!") - return res - - def get_interpol_struct(self, var_name, point): - """ - Returns the interpolated structure at the point - - Parameters - ---------- - var : str corresponding to one of the structures - - point : list of floats - ordered coordinates: t,x,y - - Return - ------ - Array with the interpolated values of the var structure - Empty list if var is not a structure in the micro_model - - Notes - ----- - Interpolation gives errors when applied to boundary - """ - res = [] - if var_name == "BC": - res = np.zeros(len(self.structures[var_name][:,0,0,0])) - for a in range(len(self.structures[var_name][:,0,0,0])): - res[a] = interpn(self.domain_vars["points"], self.structures[var_name][a,:,:,:], point, method = self.interp_method)[0] - elif var_name == "SET": - res = np.zeros((len(self.structures[var_name][:,0,0,0,0]),len(self.structures[var][0,:,0,0,0]))) - for a in range(len(self.structures[var_name][:,0,0,0,0])): - for b in range(len(self.structures[var_name][0,:,0,0,0])): - res[a,b] = interpn(self.domain_vars["points"],self.structures[var_name][a,b,:,:,:], point, method = self.interp_method)[0] - else: - print(f"{var} does not belong to the structures in the micro_model") - return res - - # def get_interpol_var(self, var_names, point): - # """ - # Returns the interpolated structure at the point - - # Parameters - # ---------- - # var : str corresponding to one of the structures - - # point : list of floats - # ordered coordinates: t,x,y - - # Return - # ------ - # Array with the interpolated values of any var - # Empty list if var is not a structure in the micro_model - - # Notes - # ----- - # Interpolation gives errors when applied to boundary - # """ - # res = [] - # for var_name in var_names: - # try: - # res.append( interpn(self.domain_vars["points"], self.vars[var_name], point, method = self.interp_method)[0]) - # except KeyError: - # print(f"{var_name} does not belong to the variables of the micro_model!") - # return res - - - def get_interpol_var(self, var, point): - """ - Returns the interpolated variables at the point. - - Parameters - ---------- - vars : str corresponding to primitive, auxiliary or structre variable - - point : list of floats - ordered coordinates: t,x,y - - Return - ------ - Interpolated values/arrays corresponding to variable. - Empty list if none of the variables is a primitive, auxiliary o structure of the micro_model - - Notes - ----- - Interpolation gives errors when applied to boundary - """ - - if var in self.get_prim_strs(): - return interpn(self.domain_vars['points'], self.prim_vars[var], point, method = self.interp_method)[0] - elif var in self.get_aux_strs(): - return interpn(self.domain_vars['points'], self.aux_vars[var], point, method = self.interp_method)[0] - elif var in self.get_structures_strs(): - return interpn(self.domain_vars['points'], self.structures[var], point, method = self.interp_method)[0] - else: - print(f'{var} is not a primitive, auxiliary variable or structure of the micro_model!!') - - - - """ - Returns the interpolated structure at the point - Parameters - ---------- - var : str corresponding to one of the structures - - point : list of floats - ordered coordinates: t,x,y - Return - ------ - Array with the interpolated values of any var - Empty list if var is not a structure in the micro_model - Notes - ----- - Interpolation gives errors when applied to boundary - """ - res = [] - for var_name in var_names: - try: - res.append( interpn(self.domain_vars["points"], self.vars[var_name], point, method = self.interp_method)[0]) - except KeyError: - print(f"{var_name} does not belong to the auxiliary variables of the micro_model!") - return res - -# TC -if __name__ == '__main__': - - CPU_start_time = time.process_time() - - FileReader = METHOD_HDF5('./Data/test_res100/') - micro_model = IdealMHD_2D() - FileReader.read_in_data(micro_model) - micro_model.setup_structures() - - point = [1.502,0.4,0.2] - vars = ['SET', 'BC'] - for var in vars: - res = micro_model.get_interpol_var(var, point) - res2 = micro_model.get_var_gridpoint(var, point) - print(f'{var}: \n {res} \n {res2} \n ********** \n ') - -# MH -if __name__ == '__main__': - - CPU_start_time = time.process_time() - - FileReader = METHOD_HDF5('./Data/Testing/') - # micro_model = IdealMHD_2D() - micro_model = IdealHydro_2D() - FileReader.read_in_data(micro_model) - micro_model.setup_structures() - - res = micro_model.get_interpol_var(['v1','rho'],[10.0,0.3,0.2]) - print(type(res),"\n", res) - - res = micro_model.get_interpol_var(['T','W'],[10.0,0.3,0.2]) - print(type(res),"\n", res) - - # res = micro_model.get_interpol_var(['bar_vel','SET'],[10.0,0.3,0.2]) - # print(type(res),"\n", res) - # res = micro_model.get_interpol_aux(["b0","bx"],[0.5, 0.3,0.2]) - # print(type(res),"\n", res) - - # res = micro_model.get_interpol_struct("SET",[2.5, 0.3, 0.2]) - # print(res.shape, res[0],'\n') - - # print( micro_model.get_domain_strs() ) - - CPU_end_time = time.process_time() - CPU_time = CPU_end_time - CPU_start_time - print(f'The CPU time is {CPU_time} seconds') - diff --git a/Proof_of_principle/calibration_scripts/.DS_Store b/Proof_of_principle/calibration_scripts/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/Proof_of_principle/calibration_scripts/.DS_Store differ diff --git a/Proof_of_principle/calibration_scripts/compare_eta_cw.py b/Proof_of_principle/calibration_scripts/compare_eta_cw.py new file mode 100644 index 0000000..b16e129 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/compare_eta_cw.py @@ -0,0 +1,236 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats +from itertools import product +import multiprocessing as mp +from sklearn.metrics import mean_absolute_error + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + + print('================================================') + print(f'Starting job on data from {pickle_directory}') + print('================================================\n\n') + + meso_filename = config['Filenames']['meso_pickled_filename'] + + MesoModelLoadFile = pickle_directory + meso_filename + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + n_cpus = int(config['compare_eta_cw']['n_cpus']) + cw_dict = meso_model.EL_componentwise_parallel(n_cpus, store=False) + print('Finished computing the coefficients componentwise\n') + print(f'Keys in the dictionary: {cw_dict.keys()}') + + # meso_model.EL_style_closure_parallel(n_cpus) + # print('Finished recomputing the coefficients covariantly, now saving\n') + # pickle_directory = config['Directories']['pickled_files_dir'] + # filename = config['Filenames']['meso_pickled_filename'] + # MesoModelPickleDumpFile = pickle_directory + filename + # with open(MesoModelPickleDumpFile, 'wb') as filehandle: + # pickle.dump(meso_model, filehandle) + + eta_cw = cw_dict['eta_cw'] + print(f'eta_cw.shape: {eta_cw.shape}\n') + + eta_cw_shape = eta_cw[0,0,0].shape + Nt = meso_model.domain_vars['Nt'] + Nx = meso_model.domain_vars['Nx'] + Ny = meso_model.domain_vars['Ny'] + new_shape = tuple(list(eta_cw_shape) + [Nt, Nx, Ny]) + print(f'new_shape: {new_shape}\n') + eta_cw = eta_cw.reshape(new_shape) + + components = json.loads(config['compare_eta_cw']['components']) + components = [tuple(comp) for comp in components] + preprocess_data = json.loads(config['compare_eta_cw']['preprocess_data']) + statistical_tool = CoefficientsAnalysis() + + eta_comps = [eta_cw[comp] for comp in components] + eta_comps = statistical_tool.preprocess_data(eta_comps, preprocess_data) + + eta_quadratic = meso_model.meso_vars['eta'] + eta_quadratic = np.log10(np.abs(eta_quadratic)) + + print('Finished preparing data for plottting distributions\n') + + # # #################################################### + # # PLOTTING THE COMPONENTS DISTRIBUTIONS ALL AT ONCE + # # #################################################### + # plt.rc("font",family="serif") + # plt.rc("mathtext",fontset="cm") + # fig, ax = plt.subplots(1,1, figsize=[6,4]) + + # with warnings.catch_warnings(): + # warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + # warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + # for i in range(len(eta_comps)): + # label = 'comp = ' + str(components[i]) + # sns.histplot(eta_comps[i].flatten(), ax=ax, stat='density', kde=True, label=label) + + # label = 'squaring' + # sns.histplot(eta_quadratic.flatten(), ax=ax, stat='density', color='black', kde=True, label=label) + + # ax.set_ylabel('pdf', fontsize=10) + # xlabel = r'$\log(|\eta|)$' + # ax.set_xlabel(xlabel, fontsize=10) + # ax.legend(loc = 'best', prop={'size': 10}) + + + # fig.tight_layout() + + # fig_directory = config['Directories']['figures_dir'] + # filename = 'eta_cw_distrib' + # format = 'png' + # dpi = 400 + # filename += "." + format + # plt.savefig(fig_directory + filename, format=format, dpi=dpi) + # plt.close() + + # # ################################################################################## + # SINGLE PLOT WITH 6 PANELS AND HISTOGRAMS OF POSITIVE AND NEGATIVE VALUES SEPARATELY + # # ################################################################################## + components = [(0,0), (0,1), (0,2), (1,1), (1,2)] + eta_comps = [np.array(eta_cw[comp]) for comp in components] + + eta_quadratic = meso_model.meso_vars['eta'] + eta_quad_pos = ma.masked_where(eta_quadratic<0, eta_quadratic, copy=True).compressed() + eta_quad_neg = ma.masked_where(eta_quadratic>0, eta_quadratic, copy=True).compressed() + eta_quad_pos = np.log10(np.abs(eta_quad_pos)) + eta_quad_neg = np.log10(np.abs(eta_quad_neg)) + eta_quad_counts = [len(eta_quad_pos), len(eta_quad_neg)] + + tot_counts = [] + for i in range(len(eta_comps)): + eta_pos = ma.masked_where(eta_comps[i]<0, eta_comps[i], copy=True) + eta_neg = ma.masked_where(eta_comps[i]>0, eta_comps[i], copy=True) + eta_pos = eta_pos.compressed() + eta_neg = eta_neg.compressed() + eta_pos = np.log10(eta_pos) + eta_neg = np.log10(np.abs(eta_neg)) + eta_comps[i] = [eta_pos, eta_neg] + + counts = [len(eta_pos), len(eta_neg)] + tot_counts.append(counts) + tot_number = len((eta_cw[components[i]]).flatten()) + print(f'len(eta_comps[i].flatten()): {tot_number}') + + + # Computing the min and max to set a common range in the plot + min, max = np.amin(eta_quad_pos), np.amax(eta_quad_pos) + if np.amin(eta_quad_neg) < np.amin(eta_quad_pos): + min = np.amin(eta_quad_neg) + if np.amax(eta_quad_neg) > np.amax(eta_quad_pos): + max = np.amax(eta_quad_neg) + + for i in range(len(eta_comps)): + m1, M1 = np.amin(eta_comps[i][0]), np.amax(eta_comps[i][0]) + m2, M2 = np.amin(eta_comps[i][1]), np.amax(eta_comps[i][1]) + m, M = np.amin([m1,m2]), np.amax([M1,M2]) + if m < min: + min = m + if M > max: + max = M + if max >0: + max = 0 + + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + fig, axes = plt.subplots(2,3, figsize=[12,8]) + axes = axes.flatten() + + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + + for i in range(5): + # sns.histplot(eta_comps[i][0], ax=axes[i], stat='density', kde=True, label=r'$\eta_{+}$') + # sns.histplot(eta_comps[i][1], ax=axes[i], stat='density', kde=True, label=r'$\eta_{-}$') + label = r'$\eta_{+}$' + ', #=' + str(tot_counts[i][0]) + sns.histplot(eta_comps[i][0], ax=axes[i], label=label) + label = r'$\eta_{-}$' + ', #=' + str(tot_counts[i][1]) + sns.histplot(eta_comps[i][1], ax=axes[i], label=label) + + xlabel = r'$\log(|\eta|)$, comp=' + str(components[i]) + axes[i].set_xlabel(xlabel, fontsize=10) + axes[i].set_ylabel('counts', fontsize=10) + axes[i].set_xlim([min, max]) + + axes[i].legend(loc = 'best', prop={'size': 10}) + + label = r'$\eta_{+}$' + ', #=' + str(eta_quad_counts[0]) + sns.histplot(eta_quad_pos, ax=axes[5], label=label) + label = r'$\eta_{-}$' + ', #=' + str(eta_quad_counts[1]) + sns.histplot(eta_quad_neg, ax=axes[5], label=label) + + xlabel = r'$\log(|\eta|)$' + ', squaring' + axes[5].set_xlabel(xlabel, fontsize=10) + axes[5].set_ylabel('counts', fontsize=10) + axes[5].legend(loc = 'best', prop={'size': 10}) + axes[5].set_xlim([min, max]) + + + fig.tight_layout() + + fig_directory = config['Directories']['figures_dir'] + filename = 'pos_neg_histos' + format = 'png' + dpi = 400 + filename += "." + format + plt.savefig(fig_directory + filename, format=format, dpi=dpi) + plt.close() + + # ################################################# + # # PLOTTING THE SIGNS + # ################################################# + # for i in range(len(axes)): + # quantity = eta_cw[components[i]] + # quantity = np.sign(quantity) + # im = axes[i].imshow(quantity, origin='lower', cmap='Spectral_r') + # divider = make_axes_locatable(axes[i]) + # cax = divider.append_axes('right', size='5%', pad=0.05) + # fig.colorbar(im, cax=cax, orientation='vertical') + + # xlabel = r'$|\eta|/\eta$, comp=' + str(components[i]) + # axes[i].set_xlabel(xlabel, fontsize=12) + + # fig.tight_layout() + + # fig_directory = config['Directories']['figures_dir'] + # filename = 'eta_cw_signs' + # format = 'png' + # dpi = 400 + # filename += "." + format + # plt.savefig(fig_directory + filename, format=format, dpi=dpi) + # plt.close() + + + + + + + + diff --git a/Proof_of_principle/calibration_scripts/config_calibration.txt b/Proof_of_principle/calibration_scripts/config_calibration.txt new file mode 100644 index 0000000..aaffb85 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/config_calibration.txt @@ -0,0 +1,148 @@ +# CONFIGURATION FILE FOR SCRIPTS: +########################################################## + +[Directories] + +pickled_files_dir = /scratch/tc2m23/KHIRandom/hydro/new_data/800X800/ET10/pickled/50dx_data + +figures_dir = ./ + +[Filenames] + +meso_pickled_filename = /rHD2d_cg=fw=bl=8dx.pickle + + +[Visualize_correlations] + +vars = ["eta", "shear_sq", "vort_sq", "det_shear", "T_tilde", "n_tilde", "Q1", "Q2"] +ranges = {"x_range": [0.03, 0.97], "y_range": [0.03, 0.97]} +num_T_slices = 3 + +# Set values to null if you do not want to restrict the data +preprocess_data = {"value_ranges": [[null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null]], + "log_abs": [1, 1, 1, 1, 1, 1, 1, 1]} + +#set extractions 0 if you don't want to extract randomly from sample +extractions = 0 + +#Options for building weights: 'Q2' 'Q1_skew' 'Q1_non_neg' 'residual_weights' 'denominator_weights'. Any other choice correspond to no weights + +weighing_func = nope + +# this is only relevant when weights are built using 'residual_weights': specify a positive residual you want to consider for the weights +residual_str = pi_res_sq + +# this is only relevant when weights are built using 'denominator_weights': specify the positive quantity at the denominator of extracted coefficient +denominator_str = shear_sq + +# Set format_fig to either pdf or png +format_fig = png + +[Fs_residual_dependence] + +coeff = zeta +residual = Pi_res +EL_force = exp_tilde + +[compare_eta_cw] + +n_cpus = 30 +components = [[0,0], [0,1], [0,2], [1,1], [1,2]] +preprocess_data = {"value_ranges": [[null, null], [null, null], [null, null], [null, null], [null, null]], + "log_abs": [1, 1, 1, 1, 1]} + + +[Regression_settings] + +dependent_var = eta +regressors = ["vort_sq", "det_shear", "n_tilde", "T_tilde"] +ranges = {"x_range": [0.03, 0.97], "y_range": [0.03, 0.97]} +num_T_slices = 3 + +add_intercept = 0 +centralize = 1 +test_percentage = 0.2 + +# Set values to null if you do not want to restrict the data +preprocess_data = {"value_ranges": [[null, 0], [null, null], [null, null], [null, null], [null, null]], + "log_abs": [1, 1, 1, 1, 1]} + +#set extractions 0 if you don't want to extract randomly from sample: extraction only in the scatter plot? Not in regression? +extractions = 0 + +#Options for building weights: 'Q2' 'Q1_skew' 'Q1_non_neg' 'residual_weights' 'denominator_weights'. Any other choice correspond to no weights + +weighing_func = no_weights + +# only relevant when weights are built using 'residual_weights': specify a positive residual you want to consider for the weights +residual_str = pi_res_sq + +# this is only relevant when weights are built using 'denominator_weights': specify the positive quantity at the denominator of extracted coefficient +denominator_str = shear_sq + +# Set format_fig to either pdf or png +format_fig = png + +[Find_best_fit_settings] + +var_to_model = eta +regressors_strs = ["vort_sq", "det_shear", "shear_sq", "T_tilde", "n_tilde", "Q1", "Q2", "acc_mag", + "Theta_sq", "n_tilde_dot", "T_tilde_dot", "sD_n_tilde_sq", "dot_Dn_Theta", "exp_tilde"] + +ranges = {"x_range": [0.03, 0.97], "y_range": [0.03, 0.97]} +num_T_slices = 3 + +add_intercept = 0 +centralize = 1 +test_percentage = 0.2 + +# Set values to null if you do not want to restrict the data + +preprocess_data = {"log_abs": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} + +n_cpus = 40 + +# Set format_fig to either pdf or png +format_fig = png + +[Regress+residual_check_settings] + +coeff_str = kappa +coeff_regressors_strs = ["shear_sq", "n_tilde", "Q1", "sD_n_tilde_sq", "dot_Dn_Theta"] +residual_str = q_res_sq +closure_ingr_str = Theta_sq + +regression_ranges = {"x_range": [0.04, 0.96], "y_range": [0.04, 0.96]} +idxs_time_slices = [1] + +add_intercept = 1 +centralize = 0 + +#set the following 0 if you don't want to split into train and test +test_percentage = 0. +preprocess_data = { "log_abs": [1, 1, 1, 1, 1, 1, 1, 1], + "sqrt": [0, 0, 0, 0, 0, 0, 1, 1]} + +[PCA_settings] + +dependent_var = eta +explanatory_vars = ["n_tilde", "T_tilde", "det_shear", "shear_sq", "vort_sq", "Q1", "Q2"] +ranges = {"x_range": [0.03, 0.97], "y_range": [0.03, 0.97]} +num_T_slices = 3 + +pcs_num = 1 +regressors_2_reduce = ["det_shear", "shear_sq", "vort_sq", "Q1", "Q2"] +variance_wanted = 0.9 + +# Careful, only one dictionary here +#preprocess_data = {"pos_or_neg": [1,1,1], "log_or_not": [1,1,1]} + +# Set values to null if you do not want to restrict the data +preprocess_data = {"value_ranges": [[null, null], [null, null], [null, null], [null, null], [null, null]], + "log_abs": [1, 1, 1, 1, 1]} + +#set extractions 0 if you don't want to extract randomly from sample +extractions = 0 + +# Set format_fig to either pdf or png +format_fig = png \ No newline at end of file diff --git a/Proof_of_principle/calibration_scripts/find_best_fit.py b/Proof_of_principle/calibration_scripts/find_best_fit.py new file mode 100644 index 0000000..cec5a40 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/find_best_fit.py @@ -0,0 +1,344 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats +from itertools import product +import multiprocessing as mp +from sklearn.metrics import mean_absolute_error + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################## + # # GIVEN A VAR TO MODEL AND A LIST OF REGRESSORS, PERFORM THE REGRESSION + # # WITH ANY POSSIBLE COMBINATION OF REGRESSORS TAKEN FROM THE INPUT LIST + # # FIND THE ONE THAT BEST DESCRIBE THE QUANITY TO BE MODELLED, AND PRODUCE + # # A SCATTER PLOT FOR IT + # ################################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + # # RE-COMPUTING DERIVATIVES AND STUFF FOR MODELLING COEFFICIENTS + # # adding labels to dictionary for better figures + # entry_dic = {'D_n_tilde' : r'$\nabla_{a}\tilde{n}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'D_eps_tilde' : r'$\nabla_{a}\tilde{\varepsilon}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'n_tilde_dot' : r'$\dot{\tilde{n}}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'T_tilde_dot' : r'$\dot{\tilde{T}}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'sD_T_tilde': r'$D_{a}\tilde{T}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'sD_n_tilde': r'$D_{a}\tilde{n}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'sD_n_tilde_sq' : r'$D_{a}\tilde{n}D^{a}\tilde{n}$'} + # meso_model.update_labels_dict(entry_dic) + # entry_dic = {'dot_Dn_Theta' : r'$D_{a}\tilde{n}\Theta^{a}$'} + # meso_model.update_labels_dict(entry_dic) + + # Nt = meso_model.domain_vars['Nt'] + # Nx = meso_model.domain_vars['Nx'] + # Ny = meso_model.domain_vars['Ny'] + + # meso_model.nonlocal_vars_strs = ['u_tilde', 'T_tilde', 'n_tilde', 'eps_tilde'] + # meso_model.deriv_vars.update({'D_n_tilde' : np.zeros((Nt,Nx,Ny,3))}) + # meso_model.deriv_vars.update({'D_eps_tilde' : np.zeros((Nt,Nx,Ny,3))}) + + # n_cpus = int(config['Find_best_fit_settings']['n_cpus']) + # start_time = time.perf_counter() + # meso_model.calculate_derivatives() + # time_taken = time.perf_counter() - start_time + # print('Finished computing derivatives (serial), time taken: {}\n'.format(time_taken), flush=True) + + # start_time = time.perf_counter() + # meso_model.closure_ingredients_parallel(n_cpus) + # time_taken = time.perf_counter() - start_time + # print('Finished computing the closure ingredients in parallel, time taken: {}\n'.format(time_taken), flush=True) + + # start_time = time.perf_counter() + # meso_model.EL_style_closure_parallel(n_cpus) + # time_taken = time.perf_counter() - start_time + # print('Finished computing the EL_style closure in parallel, time taken: {}\n'.format(time_taken), flush=True) + + # start_time = time.perf_counter() + # meso_model.modelling_coefficients_parallel(n_cpus) + # time_taken = time.perf_counter() - start_time + # print('Finished computing quantities to model extracted coefficients, time taken: {}\n'.format(time_taken), flush=True) + + # pickle_directory = config['Directories']['pickled_files_dir'] + # filename = config['Filenames']['meso_pickled_filename'] + # MesoModelPickleDumpFile = pickle_directory + filename + # with open(MesoModelPickleDumpFile, 'wb') as filehandle: + # pickle.dump(meso_model, filehandle) + + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON? + dep_var_str = config['Find_best_fit_settings']['var_to_model'] + dep_var = meso_model.meso_vars[dep_var_str] + regressors_strs = json.loads(config['Find_best_fit_settings']['regressors_strs']) + regressors = [] + for i in range(len(regressors_strs)): + temp = meso_model.meso_vars[regressors_strs[i]] + regressors.append(temp) + print(f'Dependent var: {dep_var_str},\n Explanatory vars: {regressors_strs}\n') + + + # WHICH GRID-RANGES SHOULD WE CONSIDER? + regression_ranges = json.loads(config['Find_best_fit_settings']['ranges']) + x_range = regression_ranges['x_range'] + y_range = regression_ranges['y_range'] + num_slices_meso = int(config['Find_best_fit_settings']['num_T_slices']) + time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range] + + # READING PREPROCESSING INFO FROM CONFIG FILE + preprocess_data = json.loads(config['Find_best_fit_settings']['preprocess_data']) + add_intercept = not not int(config['Find_best_fit_settings']['add_intercept']) + centralize = int(config['Find_best_fit_settings']['centralize']) + test_percentage = float(config['Find_best_fit_settings']['test_percentage']) + + data = [dep_var] + for i in range(len(regressors)): + data.append(regressors[i]) + + # PRE-PROCESSING: Trimming, pre-processing and splitting intro train + test set + statistical_tool = CoefficientsAnalysis() + model_points = meso_model.domain_vars['Points'] + new_data = statistical_tool.trim_dataset(data, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + + if centralize: + new_data, means = statistical_tool.centralize_dataset(new_data) + dep_var_mean = means[0] + regressors_means = means[1:] + + training_data, test_data = statistical_tool.split_train_test(new_data, test_percentage=test_percentage) + + dep_var_train = training_data[0] + dep_var_test = test_data[0] + regressors_train = training_data[1:] + regressors_test = test_data[1:] + + + # REGRESSING IN PARALLEL: consider all possible combination of input regressors' list + # ALSO: EVALUATE GOODNESS OF FIT + num_regressors = len(regressors_train) + bool_regressors_combs = [seq for seq in product((True, False), repeat=num_regressors)][0:-1] + print(f'Number of tested combinations of regressors: {len(bool_regressors_combs)}\n') + + def parall_regress_task(comb_regressors): + """ + """ + # DOING THE REGRESSION GIVEN SOME COMBINATION OF INPUT REGRESSORS + actual_regressors = [] + actual_regressors_strs = [] + for i in range(num_regressors): + if comb_regressors[i] == True: + actual_regressors.append(regressors_train[i]) + actual_regressors_strs.append(regressors_strs[i]) + + coeffs, _ = statistical_tool.scalar_regression(dep_var_train, actual_regressors, add_intercept=add_intercept) + + # BUILDING TEST-DATA PREDICTIONs GIVEN THE REGRESSED MODEL + actual_regressors = [] + for i in range(num_regressors): + if comb_regressors[i] == True: + actual_regressors.append(regressors_test[i]) + + dep_var_model = np.zeros(dep_var_test.shape) + if centralize: + for i in range(len(actual_regressors)): + dep_var_model += np.multiply(coeffs[i], actual_regressors[i]) + + else: + if add_intercept: + dep_var_model += coeffs[0] + for i in range(len(actual_regressors)): + dep_var_model += np.multiply(coeffs[i+1], actual_regressors[i]) + elif not add_intercept: + for i in range(len(actual_regressors)): + dep_var_model += np.multiply(coeffs[i], actual_regressors[i]) + + # r, _ = stats.pearsonr(dep_var_test, dep_var_model) + # return r, coeffs , comb_regressors + + # mean_error = mean_absolute_error(dep_var_test, dep_var_model) + # return mean_error, coeffs , comb_regressors + + w = statistical_tool.wasserstein_distance(dep_var_test, dep_var_model, sample_points=300) + return w, coeffs, comb_regressors + + + n_cpus = int(config['Find_best_fit_settings']['n_cpus']) + # pearsons = [] + # mean_errors = [] + wassersteins = [] + fitted_coeffs = [] + regressors_combinations = [] + with mp.Pool(processes=n_cpus) as pool: + print('Performing all possible regression of {} in parallel with {} processes\n'.format(dep_var_str, pool._processes), flush=True) + for result in pool.map(parall_regress_task, bool_regressors_combs): + # pearsons.append(result[0]) + # mean_errors.append(result[0]) + wassersteins.append(result[0]) + fitted_coeffs.append(result[1]) + regressors_combinations.append(result[2]) + + + # FINDING BEST MODEL, RE-BUILDING DATA PREDICITON FOR TEST SET + # rs_squared = np.power(pearsons, 2) + # max_r_index = np.argmax(rs_squared) + # best_coeffs = fitted_coeffs[max_r_index] + # best_regressors_combination = regressors_combinations[max_r_index] + # ordering_idx = np.argsort(rs_squared) + # print('Printing max r-squared and the corresponding regression combination:') + + min_w_index = np.argmin(wassersteins) + best_coeffs = fitted_coeffs[min_w_index] + ordering_idx = np.argsort(wassersteins) + + + # for i in range(-1,-6,-1): + for i in range(0,6,1): + index = ordering_idx[i] + which_regressors = [] + for j in range(len(regressors_combinations[index])): + if regressors_combinations[index][j] == True: + which_regressors.append(regressors_strs[j]) + # print(f'r^2: {rs_squared[index]}, regressors: {which_regressors}') + print(f'wasserstein: {wassersteins[index]}, regressors: {which_regressors}') + + print(f'\nBest coefficients: {best_coeffs}') + + # # RECONSTRUCTING THE BEST MODEL FOR TEST DATA + # actual_regressors = [] + # actual_regressors_strs = [] + # if centralize: + # actual_regressors_means = [] + # for i in range(len(regressors_strs)): + # if best_regressors_combination[i] == True: + # actual_regressors.append(regressors_test[i]) + # actual_regressors_strs.append(regressors_strs[i]) + # if centralize: + # actual_regressors_means.append(regressors_means[i]) + + # dep_var_model = np.zeros(dep_var_test.shape) + # if centralize: + # for i in range(len(actual_regressors)): + # dep_var_model += np.multiply(best_coeffs[i], actual_regressors[i]) + + # else: + # if add_intercept: + # dep_var_model += best_coeffs[0] + # for i in range(len(actual_regressors)): + # dep_var_model += np.multiply(best_coeffs[i+1], actual_regressors[i]) + # elif not add_intercept: + # for i in range(len(actual_regressors)): + # dep_var_model += np.multiply(best_coeffs[i], actual_regressors[i]) + + + # # FINALLY, PLOTTING THE BEST MODEL PREDICTIONS VS TEST DATA + # ylabel = dep_var_str + # if hasattr(meso_model, 'labels_var_dict') and dep_var_str in meso_model.labels_var_dict.keys(): + # ylabel = meso_model.labels_var_dict[dep_var_str] + # if preprocess_data['log_abs'][0] == 1: + # ylabel = r"$\log($" + ylabel + r"$)$" + # statistical_tool.visualize_correlation(dep_var_model, dep_var_test, xlabel=r"$regression$ $model$", ylabel=ylabel) + + # # Building the annotation box with the specifics of the model + # if centralize: + # text_for_box = r"$Model$ $coeff.s$, $means:$" + "\n" + # add_text = dep_var_str + " : , " + # if hasattr(meso_model, 'labels_var_dict') and dep_var_str in meso_model.labels_var_dict.keys(): + # add_text = meso_model.labels_var_dict[dep_var_str] + " : , " + # sign, val = int(np.sign(dep_var_mean)), '%.3f' %np.abs(dep_var_mean) + # coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + # add_text += coeff_for_text_box + # text_for_box += add_text + + # for i in range(len(actual_regressors_strs)): + # add_text = "\n" + actual_regressors_strs[i] + " : " + # if hasattr(meso_model, 'labels_var_dict') and actual_regressors_strs[i] in meso_model.labels_var_dict.keys(): + # add_text = "\n" + meso_model.labels_var_dict[actual_regressors_strs[i]] + " : " + + # sign, val = int(np.sign(best_coeffs[i])), '%.3f' %np.abs(best_coeffs[i]) + # coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + # add_text += coeff_for_text_box + + # sign, val = int(np.sign(actual_regressors_means[i])), '%.3f' %np.abs(actual_regressors_means[i]) + # coeff_for_text_box = r", $+{}$".format(val) if sign == 1 else r", $-{}$".format(val) + # add_text += coeff_for_text_box + + # text_for_box += add_text + + + # else: + # text_for_box = r"$Model$ $coeff.s:$" + "\n" + # if add_intercept: + # sign, val = int(np.sign(best_coeffs[0])), '%.3f' %np.abs(best_coeffs[0]) + # text_for_box += r'$offset$' +' : ' + # coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + # text_for_box += coeff_for_text_box + # else: + # best_coeffs = [0] + best_coeffs + + # for i in range(len(actual_regressors_strs)): + # sign, val = int(np.sign(best_coeffs[i+1])), '%.3f' %np.abs(best_coeffs[i+1]) + # coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + + # add_text = "\n" + actual_regressors_strs[i] + " : " + # if hasattr(meso_model, 'labels_var_dict') and actual_regressors_strs[i] in meso_model.labels_var_dict.keys(): + # add_text = "\n" + meso_model.labels_var_dict[actual_regressors_strs[i]] + " : " + + # add_text += coeff_for_text_box + # text_for_box += add_text + + # bbox_args = dict(boxstyle="round", fc="0.95") + # plt.annotate(text=text_for_box, xy = (0.99,0.1), xycoords='figure fraction', bbox=bbox_args, ha="right", va="bottom", fontsize = 8) + + + # # Saving the figure + # saving_directory = config['Directories']['figures_dir'] + # if centralize: + # filename = f'/CentredBestFit_{dep_var_str}_vs' + # else: + # filename = f'/BestFit_{dep_var_str}_vs' + + # for i in range(0,len(regressors_strs)): + # filename += f'_{regressors_strs[i]}' + # format = str(config['Regression_settings']['format_fig']) + # filename += "." + format + # dpi = None + # if format == 'png': + # dpi = 400 + # plt.savefig(saving_directory + filename, format=format, dpi=dpi) + # print(f'Finished regression and scatter plot for {dep_var_str}, saved as {filename}\n\n') \ No newline at end of file diff --git a/Proof_of_principle/calibration_scripts/fs_residual_dependence.py b/Proof_of_principle/calibration_scripts/fs_residual_dependence.py new file mode 100644 index 0000000..e294b7c --- /dev/null +++ b/Proof_of_principle/calibration_scripts/fs_residual_dependence.py @@ -0,0 +1,213 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats +from itertools import product +import multiprocessing as mp +from sklearn.metrics import mean_absolute_error + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + + print('================================================') + print(f'Starting job on data from {pickle_directory}') + print('================================================\n\n') + + meso_filename_8 = '/rHD2d_cg=fw=bl=8dx.pickle' + meso_filename_4 = '/rHD2d_cg=fw=bl=4dx.pickle' + meso_filename_2 = '/rHD2d_cg=fw=bl=2dx.pickle' + + MesoModelLoadFile = pickle_directory + meso_filename_2 + with open(MesoModelLoadFile, 'rb') as filehandle: + meso2 = pickle.load(filehandle) + + MesoModelLoadFile = pickle_directory + meso_filename_4 + with open(MesoModelLoadFile, 'rb') as filehandle: + meso4 = pickle.load(filehandle) + + MesoModelLoadFile = pickle_directory + meso_filename_8 + with open(MesoModelLoadFile, 'rb') as filehandle: + meso8 = pickle.load(filehandle) + + # # READING INFO ON RESIDUALS FROM CONFIG FILE + # coeff_str = config['Fs_residual_dependence']['coeff'] + # residual_str = config['Fs_residual_dependence']['residual'] + # EL_force_str = config['Fs_residual_dependence']['EL_force'] + + # print(f'coeff_str: {coeff_str}\nresidual_str: {residual_str}\nEL_force_str: {EL_force_str}\n') + + # coeff2 = np.abs(meso2.meso_vars[coeff_str]) + # coeff4 = np.abs(meso4.meso_vars[coeff_str]) + # coeff8 = np.abs(meso8.meso_vars[coeff_str]) + + # coeffs = [coeff2, coeff4, coeff8] + # filter_sizes = [2,4,8] + + # log_coeffs = [np.log10(elem) for elem in coeffs] + # means = [np.mean(elem) for elem in log_coeffs] + # print(f'The log-mean values of {coeff_str} are: {means[0]}, {means[1]}, {means[2]}') + + # coeffs_rescaled = [coeffs[i]/(filter_sizes[i]**2) for i in range(len(coeffs))] + # log_coeffs_rescaled = [np.log10(elem) for elem in coeffs_rescaled] + + # EL_force2 = np.abs(meso2.meso_vars[EL_force_str]) + # EL_force4 = np.abs(meso4.meso_vars[EL_force_str]) + # EL_force8 = np.abs(meso8.meso_vars[EL_force_str]) + + # residual2 = meso2.meso_vars[residual_str] + # residual4 = meso4.meso_vars[residual_str] + # residual8 = meso8.meso_vars[residual_str] + + # log_residuals = [np.log10(elem) for elem in [residual2, residual4, residual8]] + # log_EL_forces = [np.log10(elem) for elem in [EL_force2, EL_force4, EL_force8]] + + # means = [np.mean(elem) for elem in log_residuals] + # print(f'The log-mean value of pi_res_sq are: {means[0]}, {means[1]}, {means[2]}') + + + # plt.rc("font",family="serif") + # plt.rc("mathtext",fontset="cm") + # fig, axes = plt.subplots(1,3, figsize=[12,4]) + # axes = axes.flatten() + + # stat = 'density' + # with warnings.catch_warnings(): + # warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + # warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + + # sns.histplot(log_EL_forces[0].flatten(), stat=stat, kde=True, color='firebrick', ax=axes[0], label=r'$L=2dx$') + # sns.histplot(log_EL_forces[1].flatten(), stat=stat, kde=True, color='steelblue', ax=axes[0], label=r'$L=4dx$') + # sns.histplot(log_EL_forces[2].flatten(), stat=stat, kde=True, color='olive', ax=axes[0], label=r'$L=8dx$') + + # sns.histplot(log_residuals[0].flatten(), stat=stat, kde=True, color='firebrick', ax=axes[1], label=r'$L=2dx$') + # sns.histplot(log_residuals[1].flatten(), stat=stat, kde=True, color='steelblue', ax=axes[1], label=r'$L=4dx$') + # sns.histplot(log_residuals[2].flatten(), stat=stat, kde=True, color='olive', ax=axes[1], label=r'$L=8dx$') + + # sns.histplot(log_coeffs_rescaled[0].flatten(), stat=stat, kde=True, color='firebrick', ax=axes[2], label=r'$L=2dx$') + # sns.histplot(log_coeffs_rescaled[1].flatten(), stat=stat, kde=True, color='steelblue', ax=axes[2], label=r'$L=4dx$') + # sns.histplot(log_coeffs_rescaled[2].flatten(), stat=stat, kde=True, color='olive', ax=axes[2], label=r'$L=8dx$') + + + # axes[0].legend(loc = 'best', prop={'size': 10}) + # axes[1].legend(loc = 'best', prop={'size': 10}) + # axes[2].legend(loc = 'best', prop={'size': 10}) + + # axes[0].set_ylabel('pdf', fontsize=12) + # axes[1].set_ylabel('pdf', fontsize=12) + # axes[2].set_ylabel('pdf', fontsize=12) + + # xlabel = meso2.labels_var_dict[EL_force_str] + # xlabel = r'$\log(|$' + xlabel + r'$|)$' + # axes[0].set_xlabel(xlabel, fontsize=12) + + # xlabel = meso2.labels_var_dict[residual_str] + # xlabel = r'$\log($' + xlabel + r'$)$' + # axes[1].set_xlabel(xlabel, fontsize=12) + + # xlabel = meso2.labels_var_dict[coeff_str] + # xlabel = xlabel + r'$/\tilde{L}^2,\qquad \tilde{L} = L/dx$' + # axes[2].set_xlabel(xlabel, fontsize=12) + + # fig.tight_layout() + + # fig_directory = config['Directories']['figures_dir'] + # filename = 'fs_residual_dependence' + # format = 'png' + # dpi = 400 + # filename += "." + format + # plt.savefig(fig_directory + filename, format=format, dpi=dpi) + + # READING INFO ON RESIDUALS FROM CONFIG FILE + coeff_str = config['Fs_residual_dependence']['coeff'] + residual_str = config['Fs_residual_dependence']['residual'] + EL_force_str = config['Fs_residual_dependence']['EL_force'] + + print(f'coeff_str: {coeff_str}\nresidual_str: {residual_str}\nEL_force_str: {EL_force_str}\n') + + zeta2 = np.abs(meso2.meso_vars['zeta']) + zeta4 = np.abs(meso4.meso_vars['zeta']) + zeta8 = np.abs(meso8.meso_vars['zeta']) + zetas = [zeta2, zeta4, zeta8] + + kappa2 = np.abs(meso2.meso_vars['kappa']) + kappa4 = np.abs(meso4.meso_vars['kappa']) + kappa8 = np.abs(meso8.meso_vars['kappa']) + kappas = [kappa2, kappa4, kappa8] + + filter_sizes = [2,4,8] + + zetas_rescaled = [zetas[i]/(filter_sizes[i]**2) for i in range(len(zetas))] + kappas_rescaled = [kappas[i]/(filter_sizes[i]**2) for i in range(len(kappas))] + + log_zetas_rescaled = [np.log10(elem) for elem in zetas_rescaled] + log_kappas_rescaled = [np.log10(elem) for elem in kappas_rescaled] + + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + fig, axes = plt.subplots(1,2, figsize=[8,4]) + axes = axes.flatten() + + stat = 'density' + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + + sns.histplot(log_zetas_rescaled[0].flatten(), stat=stat, kde=True, color='firebrick', ax=axes[0], label=r'$L=2dx$') + sns.histplot(log_zetas_rescaled[1].flatten(), stat=stat, kde=True, color='steelblue', ax=axes[0], label=r'$L=4dx$') + sns.histplot(log_zetas_rescaled[2].flatten(), stat=stat, kde=True, color='olive', ax=axes[0], label=r'$L=8dx$') + + sns.histplot(log_kappas_rescaled[0].flatten(), stat=stat, kde=True, color='firebrick', ax=axes[1], label=r'$L=2dx$') + sns.histplot(log_kappas_rescaled[1].flatten(), stat=stat, kde=True, color='steelblue', ax=axes[1], label=r'$L=4dx$') + sns.histplot(log_kappas_rescaled[2].flatten(), stat=stat, kde=True, color='olive', ax=axes[1], label=r'$L=8dx$') + + + axes[0].legend(loc = 'best', prop={'size': 10}) + axes[1].legend(loc = 'best', prop={'size': 10}) + + axes[0].set_ylabel('pdf', fontsize=12) + axes[1].set_ylabel('pdf', fontsize=12) + + xlabel = meso2.labels_var_dict['zeta'] + xlabel = xlabel + r'$/\tilde{L}^2,\qquad \tilde{L} = L/dx$' + axes[0].set_xlabel(xlabel, fontsize=12) + + xlabel = meso2.labels_var_dict['kappa'] + xlabel = xlabel + r'$/\tilde{L}^2,\qquad \tilde{L} = L/dx$' + axes[1].set_xlabel(xlabel, fontsize=12) + + fig.tight_layout() + + fig_directory = config['Directories']['figures_dir'] + filename = 'fs_residual_dependence' + format = 'png' + dpi = 400 + filename += "." + format + plt.savefig(fig_directory + filename, format=format, dpi=dpi) + + + + + + + diff --git a/Proof_of_principle/calibration_scripts/hunting_correlations.py b/Proof_of_principle/calibration_scripts/hunting_correlations.py new file mode 100644 index 0000000..cf65cec --- /dev/null +++ b/Proof_of_principle/calibration_scripts/hunting_correlations.py @@ -0,0 +1,148 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################## + # # USING PCA TO LOOK FOR CORRELATIONS: FIND THE FIRST FEW PRINCIPAL + # # COMPONENTS IN A DATASET, AND PRINT THEIR CORRELATION PLOT WITH + # #Â A RESIDUAL/DISSIPATIVE COEFFICIENT + # ################################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO AND MICRO MODELS + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON? + dep_var_str = config['PCA_settings']['dependent_var'] + explanatory_vars_strs = json.loads(config['PCA_settings']['explanatory_vars']) + explanatory_vars = [] + for i in range(len(explanatory_vars_strs)): + temp = meso_model.meso_vars[explanatory_vars_strs[i]] + explanatory_vars.append(temp) + dep_var = meso_model.meso_vars[dep_var_str] + print(f'Dependent var: {dep_var_str}, Explanatory vars: {explanatory_vars_strs}\n') + + + # WHICH GRID-RANGES SHOULD WE CONSIDER? + PCA_ranges = json.loads(config['PCA_settings']['ranges']) + x_range = PCA_ranges['x_range'] + y_range = PCA_ranges['y_range'] + num_slices_meso = int(config['PCA_settings']['num_T_slices']) + time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range] + + # READING PREPROCESSING INFO FROM CONFIG FILE + preprocess_data = json.loads(config['PCA_settings']['preprocess_data']) + extractions = int(config['PCA_settings']['extractions']) #This is only used for plotting, like in regression routines + + # PRE-PROCESSING + data = [dep_var] + for i in range(len(explanatory_vars)): + data.append(explanatory_vars[i]) + statistical_tool = CoefficientsAnalysis() + model_points = meso_model.domain_vars['Points'] + new_data = statistical_tool.trim_dataset(data, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + # if extractions != 0: + # new_data = statistical_tool.extract_randomly(new_data, extractions) + + dep_var = new_data[0] + explanatory_vars = [] + for i in range(1,len(new_data)): + explanatory_vars.append(new_data[i]) + + # NOW DO THE PCA ANALYSIS + pcs_num = int(config['PCA_settings']['pcs_num']) + highest_pcs_decomp, scores = statistical_tool.PCA_find_regressors(dep_var, explanatory_vars, pcs_num=pcs_num) + + for i in range(len(highest_pcs_decomp)): + print(f'{i}-th highest PCs decomposition: \n{highest_pcs_decomp[i]}\nCorresponding score: {scores[i]}\n') + + # NOW, USE THE PCs DECOMPOSITION TO BUILD A LINEAR MODEL FOR DEP_VAR + # THIS IS USED FOR PRODUCING A CORRELATION PLOT TO VISUALLY GRASP HOW GOOD THE MODEL IS + # ONLY THE PC WITH HIGHEST SCORE ON DEP_VAR IS USED, THE OTHERS PROVIDE AUXILIARY INFO? + + + # BUILD THE LINEAR MODEL FROM PCA + best_pc_decomp = highest_pcs_decomp[0] + coeffs = [] + temp = 0 + for j in range(0, len(explanatory_vars)): + coeff = -best_pc_decomp[j+1] / best_pc_decomp[0] + print(f'{explanatory_vars_strs[j]}-rescaled coefficient: {coeff}\n') + coeffs.append(coeff) + temp += np.multiply(coeff, explanatory_vars[j]) + dep_var_model = temp + + # FINALLY, PLOTTING + print('\nProducing correlation plot using info from PCA') + x = dep_var_model + y = dep_var + if extractions != 0: + new_data = statistical_tool.extract_randomly([x,y], extractions) + x, y = new_data[0], new_data[1] + + ylabel = dep_var_str + if hasattr(meso_model, 'labels_var_dict') and dep_var_str in meso_model.labels_var_dict.keys(): + ylabel = meso_model.labels_var_dict[dep_var_str] + if preprocess_data['log_abs'][0] ==1: + ylabel = r"$\log($" + ylabel + r"$)$" + g=statistical_tool.visualize_correlation(x, y, xlabel=r"$Highest$ $PC$ $model$", ylabel=ylabel) + + # Building the text for the annotation box + text_for_box = r"$Coefficients$ $(\log)$:" + "\n" + legend_entries = [] + for i in range(len(explanatory_vars_strs)): + label = explanatory_vars_strs[i] + " : " + if hasattr(meso_model, 'labels_var_dict') and explanatory_vars_strs[i] in meso_model.labels_var_dict.keys(): + label = meso_model.labels_var_dict[explanatory_vars_strs[i]] + " : " + sign, val = int(np.sign(coeffs[i])), '%.3f' %np.abs(coeffs[i]) + coeff_for_label = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + label += coeff_for_label + "\n" + legend_entries.append(label) + for i in range(len(legend_entries)): + text_for_box += legend_entries[i] + bbox_args = dict(boxstyle="round", fc="0.95") + plt.annotate(text=text_for_box, xy = (0.99,0.1), xycoords='figure fraction', bbox=bbox_args, ha="right", va="bottom", fontsize = 9) + + # Saving the figure + saving_directory = config['Directories']['figures_dir'] + filename = f'/PCA_hunt_{dep_var_str}' + format = str(config['Regression_settings']['format_fig']) + filename += "." + format + dpi = None + if format == 'png': + dpi = 400 + plt.savefig(saving_directory + filename, format=format, dpi=dpi) + print(f'Finished correlation plot for {dep_var_str}, saved as {filename}\n\n') + + \ No newline at end of file diff --git a/Proof_of_principle/calibration_scripts/py_parallel.slurm b/Proof_of_principle/calibration_scripts/py_parallel.slurm new file mode 100644 index 0000000..351d7be --- /dev/null +++ b/Proof_of_principle/calibration_scripts/py_parallel.slurm @@ -0,0 +1,34 @@ +#!/bin/bash +#################################### +# JOB INFO: parallel, single node +#################################### + +#SBATCH --output=outputs/parallel_%A.out +#SBATCH --nodes=1 +#SBATCH --ntasks=30 +#SBATCH --time=00:10:00 + +#SBATCH --mail-type=begin +#SBATCH --mail-type=fail +#SBATCH --mail-type=end +#SBATCH --mail-user=celora@ice.csic.es + + +#################################### +# LOADING THE CONDA ENVIRONMENT +#################################### + +module load conda/py3-latest +# I get warnings to use 'conda deactivate' instead but that doesn't work +source deactivate +conda activate myenv + +#################################### +# LAUNCHING THE JOBS +#################################### + +python3 -u find_best_fit.py config_calibration.txt + + + + diff --git a/Proof_of_principle/calibration_scripts/py_serial.slurm b/Proof_of_principle/calibration_scripts/py_serial.slurm new file mode 100644 index 0000000..3cf5524 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/py_serial.slurm @@ -0,0 +1,42 @@ +#!/bin/bash +#################################### +# JOB INFO: serial +#################################### + + +#SBATCH --nodes=1 +#SBATCH --ntasks=1 +#SBATCH --time=00:10:00 +#SBATCH --output=outputs/serial_%A.out + + +#SBATCH --mail-type=begin # send email when job begins +#SBATCH --mail-type=fail +#SBATCH --mail-type=end # send email when job ends +#SBATCH --mail-user=celora@ice.csic.es + + +#################################### +# LOADING THE CONDA ENVIRONMENT +#################################### + +module load conda/py3-latest +# I get warnings to use 'conda deactivate' instead but that doesn't work +source deactivate +conda activate myenv + + +#################################### +# LAUNCHING THE JOBS +##################################### +# python3 -u regress+residual_check.py config_calibration.txt +# python3 -u visualizing_correlations.py config_calibration.txt +# python3 -u reducing_regressors.py config_calibration.txt +# python3 -u hunting_correlations.py config_calibration.txt +# python3 -u regressing_residual.py config_calibration.txt + +python3 -u L_dep_eta.py config_calibration.txt + + + + diff --git a/Proof_of_principle/calibration_scripts/reducing_regressors.py b/Proof_of_principle/calibration_scripts/reducing_regressors.py new file mode 100644 index 0000000..da4a84c --- /dev/null +++ b/Proof_of_principle/calibration_scripts/reducing_regressors.py @@ -0,0 +1,83 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################### + # # USING PCA TO REDUCE A LARGE LIST OF REGRESSOR TO A SMALLER SUBSET + # ################################################################### + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO AND MICRO MODELS + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON + regressors_strs = json.loads(config['PCA_settings']['regressors_2_reduce']) + regressors = [] + for i in range(len(regressors_strs)): + temp = meso_model.meso_vars[regressors_strs[i]] + regressors.append(temp) + print('Trying to reduce the following list to a smaller subset: {}\n'.format(regressors_strs)) + + # WHICH GRID-RANGES SHOULD WE CONSIDER? + ranges = json.loads(config['PCA_settings']['ranges']) + x_range = ranges['x_range'] + y_range = ranges['y_range'] + num_slices_meso = int(config['PCA_settings']['num_T_slices']) + time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range] + + # READING PREPROCESSING INFO FROM CONFIG FILE + preprocess_data = json.loads(config['PCA_settings']['preprocess_data']) + extractions = int(config['PCA_settings']['extractions']) + + # PRE-PROCESSING and REGRESSING + statistical_tool = CoefficientsAnalysis() + model_points = meso_model.domain_vars['Points'] + new_data = statistical_tool.trim_dataset(regressors, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + # if extractions != 0: + # new_data = statistical_tool.extract_randomly(new_data, extractions) + + # PERFORMING PCA TO EXTRACT PRINCIPAL COMPONENTS + var_wanted = float(config['PCA_settings']['variance_wanted']) + comp_decomp = statistical_tool.PCA_find_regressors_subset(new_data, var_wanted=var_wanted) + + saving_directory = config['Directories']['figures_dir'] + with open(saving_directory + '/Reducing_regressors.txt', 'w') as filehandle: + filehandle.write("===================================\nFeatures in the dataset:\n") + filehandle.write(regressors_strs[0]) + for i in range(1, len(regressors_strs)): + filehandle.write(", " + regressors_strs[i]) + filehandle.write("\n===================================\n") + for i in range(len(comp_decomp)): + filehandle.write(f'The {i}-th component decomposition in terms of original vars is\n\n{comp_decomp[i]}\n\n') diff --git a/Proof_of_principle/calibration_scripts/regress+residual_check.py b/Proof_of_principle/calibration_scripts/regress+residual_check.py new file mode 100644 index 0000000..95bd4b1 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/regress+residual_check.py @@ -0,0 +1,298 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + ################################################ + # # REGRESSING THE COEFFICIENT + ################################################ + statistical_tool = CoefficientsAnalysis() + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON? + coeff_str = config['Regress+residual_check_settings']['coeff_str'] + coeff = meso_model.meso_vars[coeff_str] + coeff_regressors_strs = json.loads(config['Regress+residual_check_settings']['coeff_regressors_strs']) + regressors = [] + for i in range(len(coeff_regressors_strs)): + temp = meso_model.meso_vars[coeff_regressors_strs[i]] + regressors.append(temp) + print(f'Dependent var: {coeff_str}, Explanatory vars: {coeff_regressors_strs}\n') + + residual_str = config['Regress+residual_check_settings']['residual_str'] + closure_ingr_str = config['Regress+residual_check_settings']['closure_ingr_str'] + residual = meso_model.meso_vars[residual_str] + closure_ingr = meso_model.meso_vars[closure_ingr_str] + print(f'Residuals and closure ingredient for model check: {residual_str}, {closure_ingr_str}\n') + + # PREPARING THE DATA + preprocess_data = json.loads(config['Regress+residual_check_settings']['preprocess_data']) + add_intercept = not not int(config['Regress+residual_check_settings']['add_intercept']) + centralize = int(config['Regress+residual_check_settings']['centralize']) + test_percentage = float(config['Regress+residual_check_settings']['test_percentage']) + + # first step: trimming and pre-processing + regression_ranges = json.loads(config['Regress+residual_check_settings']['regression_ranges']) + x_range = regression_ranges['x_range'] + y_range = regression_ranges['y_range'] + idxs_time_slices = json.loads(config['Regress+residual_check_settings']['idxs_time_slices']) + times = [meso_model.domain_vars['T'][i] for i in idxs_time_slices] + t_range = [np.amin(times), np.amax(times)] + ranges = [t_range, x_range, y_range] + + data = [coeff] + for i in range(len(regressors)): + data.append(regressors[i]) + data.append(residual) + data.append(closure_ingr) + model_points = meso_model.domain_vars['Points'] + new_data = statistical_tool.trim_dataset(data, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + + # next step: centralizing the coefficients data + if centralize: + new_data, means = statistical_tool.centralize_dataset(new_data) + coeff_mean = means[0] + del means[0] + closure_ingr_mean = means[-1] + del means[-1] + residual_means = means[-1] + del means[-1] + regressors_means = means + + # second step: splitting into train and test + if test_percentage==0.: + coeff_train = new_data[0] + coeff_test = np.copy(new_data[0]) + del new_data[0] + closure_ingr_train = new_data[-1] + closure_ingr_test = np.copy(new_data[-1]) + del new_data[-1] + residual_train = new_data[-1] + residual_test = np.copy(new_data[-1]) + del new_data[-1] + regressors_train = new_data + regressors_test = [] + for elem in regressors_train: + regressors_test.append(np.copy(elem)) + else: + training_data, test_data = statistical_tool.split_train_test(new_data, test_percentage=test_percentage) + coeff_train = training_data[0] + coeff_test = test_data[0] + del training_data[0] + del test_data[0] + closure_ingr_train = training_data[-1] + closure_ingr_test = test_data[-1] + del training_data[-1] + del test_data[-1] + residual_train = training_data[-1] + residual_test = test_data[-1] + del training_data[-1] + del test_data[-1] + regressors_train = training_data + regressors_test = test_data + + # # fourth step: centralizing the coefficients data + # if centralize: + # tot_coeff = [np.stack((coeff_train, coeff_test))] + # tot_regress = [np.stack((regressors_test[i], regressors_train[i])) for i in range(len(regressors))] + + # _, means = statistical_tool.centralize_dataset(tot_coeff + tot_regress) + # coeff_mean = means[0] + # regressors_means = means[1:] + + # coeff_train -= coeff_mean + # for i in range(len(regressors_means)): + # regressors_train[i] -= regressors_means[i] + + coeffs, std_errors = statistical_tool.scalar_regression(coeff_train, regressors_train, add_intercept=add_intercept) + print('regression coeffs: {}\n'.format(coeffs)) + # print('Corresponding std errors: {}\n'.format(std_errors)) + + ###################################################### + # # RECONSTRUCTING PREDICTIONS FOR COEFF AND RESIDUAL + ###################################################### + # Note: the reconstruction depends on the order with which you pre-process above + + # building predictions for the coefficient + coeff_model = np.zeros(coeff_test.shape) + if centralize: + coeff_model += coeff_mean + coeff_test += coeff_mean + for i in range(len(regressors_test)): + # regressors_test[i] += regressors_means[i] + coeff_model += np.multiply(coeffs[i], regressors_test[i]) + else: + if add_intercept: + coeff_model += coeffs[0] + for i in range(len(regressors)): + coeff_model += np.multiply(coeffs[i+1], regressors_test[i]) + elif not add_intercept: + for i in range(len(regressors)): + coeff_model += np.multiply(coeffs[i], regressors_test[i]) + + # preprocessing and building model predictions for the residual + residual_model = np.zeros(residual_test.shape) + residual_model = coeff_model + closure_ingr_test + if centralize: + residual_model += closure_ingr_mean + residual_test += residual_means + + # FINALLY: PLOTTING + plt.rc("font", family="serif") + plt.rc("mathtext",fontset="cm") + plt.rc('font', size=10) + + fig, axes = plt.subplots(1,3, figsize=[13,4]) + axes = axes.flatten() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + + coeff_model = coeff_model.flatten() + coeff_test = coeff_test.flatten() + residual_model = residual_model.flatten() + residual_test = residual_test.flatten() + + sns.set_theme(style="dark") + sns.scatterplot(x=coeff_model, y=coeff_test, s=4, color=".15", ax=axes[0]) + sns.histplot(x=coeff_model, y=coeff_test, bins=50, ax=axes[0], pthresh=.1, cmap="mako") + sns.kdeplot(x=coeff_model, y=coeff_test, levels=5, ax=axes[0], color="w", linewidths=1) + + sns.histplot(coeff_model, stat='density', kde=True, color='steelblue', ax=axes[1], label='model') + sns.histplot(coeff_test, stat='density', kde=True, color='firebrick', ax=axes[1], label='sim. data') + + sns.histplot(residual_model, stat='density', kde=True, color='steelblue', ax=axes[2], label='model') + sns.histplot(residual_test, stat='density', kde=True, color='firebrick', ax=axes[2], label='sim. data') + + print('finished plot, now making it nice\n') + + # adding labels + coeff_label = coeff_str + if hasattr(meso_model, 'labels_var_dict') and coeff_str in meso_model.labels_var_dict.keys(): + coeff_label = meso_model.labels_var_dict[coeff_str] + if preprocess_data['log_abs'][0] == 1: + coeff_label = r"$\log($" + coeff_label + r"$)$" + + residual_label = residual_str + if hasattr(meso_model, 'labels_var_dict') and residual_str in meso_model.labels_var_dict.keys(): + residual_label = meso_model.labels_var_dict[residual_str] + # comment the following line if you don't take the log of the residual + residual_label = r"$\frac{1}{2}\log($" + residual_label + r"$)$" + # residual_label = r"$\log($" + residual_label + r"$)$" + + axes[0].set_xlabel('Regression model', fontsize=12) + axes[0].set_ylabel(coeff_label, fontsize=12) + axes[1].set_xlabel(coeff_label, fontsize=12) + axes[1].set_ylabel('pdf', fontsize=12) + axes[2].set_xlabel(residual_label, fontsize=12) + axes[2].set_ylabel('pdf', fontsize=12) + + fig.tight_layout() + + # Building the annotation box with the specifics of the model + if centralize: + text_for_box = r'$Means,$ $model$ $coeffs$:' + '\n' + add_text = coeff_str + " : " + if hasattr(meso_model, 'labels_var_dict') and coeff_str in meso_model.labels_var_dict.keys(): + add_text = meso_model.labels_var_dict[coeff_str] + " : " + sign, val = int(np.sign(coeff_mean)), '%.3f' %np.abs(coeff_mean) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + add_text += coeff_for_text_box + text_for_box += add_text + + for i in range(len(coeff_regressors_strs)): + add_text = "\n" + coeff_regressors_strs[i] + " : " + if hasattr(meso_model, 'labels_var_dict') and coeff_regressors_strs[i] in meso_model.labels_var_dict.keys(): + add_text = "\n" + meso_model.labels_var_dict[coeff_regressors_strs[i]] + " : " + + sign, val = int(np.sign(regressors_means[i])), '%.3f' %np.abs(regressors_means[i]) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r", $-{}$".format(val) + add_text += coeff_for_text_box + + sign, val = int(np.sign(coeffs[i])), '%.3f' %np.abs(coeffs[i]) + coeff_for_text_box = r", $+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + add_text += coeff_for_text_box + + text_for_box += add_text + + else: + text_for_box = r"$Model$ $coeff.s:$" + "\n" + if add_intercept: + sign, val = int(np.sign(coeffs[0])), '%.3f' %np.abs(coeffs[0]) + text_for_box += r'$offset$' +' : ' + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + text_for_box += coeff_for_text_box + else: + coeffs = [0] + coeffs + + for i in range(len(coeff_regressors_strs)): + sign, val = int(np.sign(coeffs[i+1])), '%.3f' %np.abs(coeffs[i+1]) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + + add_text = "\n" + coeff_regressors_strs[i] + " : " + if hasattr(meso_model, 'labels_var_dict') and coeff_regressors_strs[i] in meso_model.labels_var_dict.keys(): + add_text = "\n" + meso_model.labels_var_dict[coeff_regressors_strs[i]] + " : " + + add_text += coeff_for_text_box + text_for_box += add_text + + + bbox_args = dict(boxstyle="round", fc="0.95") + plt.annotate(text=text_for_box, xy = (0.34,0.2), xycoords='figure fraction', bbox=bbox_args, ha="right", va="bottom", fontsize = 9) + + + # Adding legend to the distribution comparison panel + axes[1].legend(loc = 'best', prop={'size': 10}) + h, _ = axes[1].get_legend_handles_labels() + labels = ['Regression model', 'sim. data'] + axes[1].legend(h, labels, loc = 'best', prop={'size': 10, 'family' : 'serif'}) + + axes[2].legend(loc = 'best', prop={'size': 10}) + h, _ = axes[2].get_legend_handles_labels() + labels = ['Regression model', 'sim. data'] + axes[2].legend(h, labels, loc = 'best', prop={'size': 10, 'family' : 'serif'}) + + # Saving the figure + print(f'Finished plot, now saving...\n\n') + saving_directory = config['Directories']['figures_dir'] + filename = '/Regress_and_check' + format = 'png' + filename += "." + format + dpi = 300 + plt.savefig(saving_directory + filename, format=format, dpi=dpi) + + + diff --git a/Proof_of_principle/calibration_scripts/regressing_residual.py b/Proof_of_principle/calibration_scripts/regressing_residual.py new file mode 100644 index 0000000..0e43ac4 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/regressing_residual.py @@ -0,0 +1,260 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################## + # # RUN THE REGRESSION ROUTINE GIVEN DEPENDENT DATA AND EXPLANATORY + # # VARS. DATA IS PRE-PROCESSED + # ################################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON? + dep_var_str = config['Regression_settings']['dependent_var'] + dep_var = meso_model.meso_vars[dep_var_str] + regressors_strs = json.loads(config['Regression_settings']['regressors']) + regressors = [] + for i in range(len(regressors_strs)): + temp = meso_model.meso_vars[regressors_strs[i]] + regressors.append(temp) + print(f'Dependent var: {dep_var_str}, Explanatory vars: {regressors_strs}\n') + + + # WHICH GRID-RANGES SHOULD WE CONSIDER? + regression_ranges = json.loads(config['Regression_settings']['ranges']) + x_range = regression_ranges['x_range'] + y_range = regression_ranges['y_range'] + num_slices_meso = int(config['Regression_settings']['num_T_slices']) + time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range] + + # READING PREPROCESSING INFO FROM CONFIG FILE + preprocess_data = json.loads(config['Regression_settings']['preprocess_data']) + add_intercept = not not int(config['Regression_settings']['add_intercept']) + extractions = int(config['Regression_settings']['extractions']) + centralize = int(config['Regression_settings']['centralize']) + test_percentage = float(config['Regression_settings']['test_percentage']) + + # BUILDING THE WEIGHTS + weighing_func_str = config['Regression_settings']['weighing_func'] + if weighing_func_str == 'Q2': + meso_model.weights_Q2() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q2.__name__}\n') + + elif weighing_func_str == 'Q1_skew': + meso_model.weights_Q1_skew() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q1_skew.__name__}\n') + + elif weighing_func_str == 'Q1_non_neg': + meso_model.weights_Q1_non_neg() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q1_non_neg.__name__}\n') + + elif weighing_func_str == "residual_weights": + residual_str = config['Regression_settings']['residual_str'] + meso_model.residual_weights(residual_str) + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.residual_weights.__name__}\n') + + elif weighing_func_str == "denominator_weights": + residual_str = config['Regression_settings']['denominator_str'] + meso_model.denominator_weights(residual_str) + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.denominator_weights.__name__}\n') + + else: + print(f'The string for building weights {weighing_func_str} does not match any of the implemented routines.\n') + weights = None + + # PRE-PROCESSING: Trimming, pre-processing and splitting intro train + test set + data = [dep_var] + for i in range(len(regressors)): + data.append(regressors[i]) + statistical_tool = CoefficientsAnalysis() + model_points = meso_model.domain_vars['Points'] + + if weights is not None: + new_data = statistical_tool.trim_dataset(data + [weights], ranges, model_points) + weights = new_data[-1] + del new_data[-1] + new_data, weights = statistical_tool.preprocess_data(new_data, preprocess_data, weights=weights) + + if centralize: + new_data, means = statistical_tool.centralize_dataset(new_data) + dep_var_mean = means[0] + regressors_means = means[1:] + + training_data, test_data = statistical_tool.split_train_test(new_data + [weights], test_percentage=test_percentage) + dep_var_train = training_data[0] + dep_var_test = test_data[0] + del training_data[0] + del test_data[0] + weights_train = training_data[-1] + weights_test = test_data[-1] + del training_data[-1] + del test_data[-1] + regressors_train = training_data + regressors_test = test_data + + + else: + new_data = statistical_tool.trim_dataset(data, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + + if centralize: + new_data, means = statistical_tool.centralize_dataset(new_data) + dep_var_mean = means[0] + regressors_means = means[1:] + + training_data, test_data = statistical_tool.split_train_test(new_data, test_percentage=test_percentage) + dep_var_train = training_data[0] + dep_var_test = test_data[0] + del training_data[0] + del test_data[0] + regressors_train = training_data + regressors_test = test_data + + weights_train = weights_test = None + + + coeffs, std_errors = statistical_tool.scalar_regression(dep_var_train, regressors_train, add_intercept=add_intercept, weights=weights_train) + print('regression coeffs: {}\n'.format(coeffs)) + print('Corresponding std errors: {}\n'.format(std_errors)) + + + # BUILDING TEST-DATA PREDICTIONs GIVEN THE REGRESSED MODEL + dep_var_model = np.zeros(dep_var_test.shape) + if centralize: + for i in range(len(regressors_test)): + dep_var_model += np.multiply(coeffs[i], regressors_test[i]) + + else: + if add_intercept: + dep_var_model += coeffs[0] + for i in range(len(regressors)): + dep_var_model += np.multiply(coeffs[i+1], regressors_test[i]) + elif not add_intercept: + for i in range(len(regressors)): + dep_var_model += np.multiply(coeffs[i], regressors_test[i]) + + # EXTRACTIONS ARE NOT NEEDED IF YOU SAVE THE FIG AS PNG + if extractions != 0: + data_for_scatter = [dep_var_test, dep_var_model] + new_data = statistical_tool.extract_randomly(data_for_scatter + [weights_test], extractions) + if weights is not None: + weights_test = new_data[-1] + del new_data[-1] + + dep_var_test, dep_var_model = new_data[0], new_data[1] + + + # FINALLY: PLOTTING + ylabel = dep_var_str + if hasattr(meso_model, 'labels_var_dict') and dep_var_str in meso_model.labels_var_dict.keys(): + ylabel = meso_model.labels_var_dict[dep_var_str] + if preprocess_data['log_abs'][0] == 1: + ylabel = r"$\log($" + ylabel + r"$)$" + # statistical_tool.visualize_correlation(dep_var_model, dep_var_test , xlabel=r"$regression$ $model$", ylabel=ylabel, weights = weights) + fig = statistical_tool.compare_distributions(dep_var_model, dep_var_test, xlabel=r'$regression$ $model$', ylabel=ylabel) + + # Building the annotation box with the specifics of the model + if centralize: + text_for_box = r"$Model$ $coeff.s$, $means:$" + "\n" + add_text = dep_var_str + " : , " + if hasattr(meso_model, 'labels_var_dict') and dep_var_str in meso_model.labels_var_dict.keys(): + add_text = meso_model.labels_var_dict[dep_var_str] + " : , " + sign, val = int(np.sign(dep_var_mean)), '%.3f' %np.abs(dep_var_mean) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + add_text += coeff_for_text_box + text_for_box += add_text + + for i in range(len(regressors_strs)): + add_text = "\n" + regressors_strs[i] + " : " + if hasattr(meso_model, 'labels_var_dict') and regressors_strs[i] in meso_model.labels_var_dict.keys(): + add_text = "\n" + meso_model.labels_var_dict[regressors_strs[i]] + " : " + + sign, val = int(np.sign(coeffs[i])), '%.3f' %np.abs(coeffs[i]) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + add_text += coeff_for_text_box + + sign, val = int(np.sign(regressors_means[i])), '%.3f' %np.abs(regressors_means[i]) + coeff_for_text_box = r", $+{}$".format(val) if sign == 1 else r", $-{}$".format(val) + add_text += coeff_for_text_box + + text_for_box += add_text + + + else: + text_for_box = r"$Model$ $coeff.s:$" + "\n" + if add_intercept: + sign, val = int(np.sign(coeffs[0])), '%.3f' %np.abs(coeffs[0]) + text_for_box += r'$offset$' +' : ' + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + text_for_box += coeff_for_text_box + else: + coeffs = [0] + coeffs + + for i in range(len(regressors_strs)): + sign, val = int(np.sign(coeffs[i+1])), '%.3f' %np.abs(coeffs[i+1]) + coeff_for_text_box = r"$+{}$".format(val) if sign == 1 else r"$-{}$".format(val) + + add_text = "\n" + regressors_strs[i] + " : " + if hasattr(meso_model, 'labels_var_dict') and regressors_strs[i] in meso_model.labels_var_dict.keys(): + add_text = "\n" + meso_model.labels_var_dict[regressors_strs[i]] + " : " + + add_text += coeff_for_text_box + text_for_box += add_text + + bbox_args = dict(boxstyle="round", fc="0.95") + plt.annotate(text=text_for_box, xy = (0.99,0.1), xycoords='figure fraction', bbox=bbox_args, ha="right", va="bottom", fontsize = 8) + + + # Saving the figure + saving_directory = config['Directories']['figures_dir'] + filename = f'/Regress_{dep_var_str}_vs' + for i in range(1,len(regressors_strs)): + filename += f'_{regressors_strs[i]}' + format = str(config['Regression_settings']['format_fig']) + filename += "." + format + dpi = None + if format == 'png': + dpi = 400 + plt.savefig(saving_directory + filename, format=format, dpi=dpi) + print(f'Finished regression and scatter plot for {dep_var_str}, saved as {filename}\n\n') + + diff --git a/Proof_of_principle/calibration_scripts/visualizing_correlations.py b/Proof_of_principle/calibration_scripts/visualizing_correlations.py new file mode 100644 index 0000000..8a4ec26 --- /dev/null +++ b/Proof_of_principle/calibration_scripts/visualizing_correlations.py @@ -0,0 +1,146 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################## + # #CORRELATION PLOTS: RESIDUALS VS CORRESPONDING CLOSURE INGREDIENTS + # ################################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + + # WHICH DATA YOU WANT TO RUN THE ROUTINE ON? + var_strs = json.loads(config['Visualize_correlations']['vars']) + vars = [] + for i in range(len(var_strs)): + vars.append(meso_model.meso_vars[var_strs[i]]) + print(f'Producing scatter plot for the vars: {var_strs}\n') + + # WHICH GRID-RANGES SHOULD WE CONSIDER? + regression_ranges = json.loads(config['Visualize_correlations']['ranges']) + x_range = regression_ranges['x_range'] + y_range = regression_ranges['y_range'] + num_slices_meso = int(config['Visualize_correlations']['num_T_slices']) + time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range] + + # READING PREPROCESSING INFO FROM CONFIG FILE, AND PREPROCESSING + preprocess_data = json.loads(config['Visualize_correlations']['preprocess_data']) + extractions = int(config['Visualize_correlations']['extractions']) + + # BUILDING THE WEIGHTS + weighing_func_str = config['Visualize_correlations']['weighing_func'] + if weighing_func_str == 'Q2': + meso_model.weights_Q2() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q2.__name__}\n') + + elif weighing_func_str == 'Q1_skew': + meso_model.weights_Q1_skew() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q1_skew.__name__}\n') + + elif weighing_func_str == 'Q1_non_neg': + meso_model.weights_Q1_non_neg() + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.weights_Q1_non_neg.__name__}\n') + + elif weighing_func_str == "residual_weights": + residual_str = config['Visualize_correlations']['residual_str'] + meso_model.residual_weights(residual_str) + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.residual_weights.__name__}\n') + + elif weighing_func_str == "denominator_weights": + residual_str = config['Visualize_correlations']['denominator_str'] + meso_model.denominator_weights(residual_str) + weights = meso_model.meso_vars['weights'] + print(f'Finished building weights using {meso_model.denominator_weights.__name__}\n') + + else: + print(f'The string for building weights {weighing_func_str} does not match any of the implemented routines.\n') + weights = None + + + # PRE-PROCESSING DATA + statistical_tool = CoefficientsAnalysis() + model_points = meso_model.domain_vars['Points'] + if weights is not None: + new_data = statistical_tool.trim_dataset(vars + [weights], ranges, model_points) + weights = new_data[-1] + del new_data[-1] + new_data, weights = statistical_tool.preprocess_data(new_data, preprocess_data, weights=weights) + if extractions != 0: + new_data = statistical_tool.extract_randomly(new_data + [weights], extractions) + weights = new_data[-1] + del new_data[-1] + vars = new_data + + else: + new_data = statistical_tool.trim_dataset(vars, ranges, model_points) + new_data = statistical_tool.preprocess_data(new_data, preprocess_data) + if extractions != 0: + new_data = statistical_tool.extract_randomly(new_data, extractions) + vars = new_data + + # FINALLY, THE CORRELATION PLOT + labels = [] + for var_str in var_strs: + label = var_str + if hasattr(meso_model, 'labels_var_dict') and var_str in meso_model.labels_var_dict.keys(): + label = meso_model.labels_var_dict[var_str] + if preprocess_data['log_abs'][0] == 1: + label = r"$\log($" + label + r"$)$" + labels.append(label) + + if len(var_strs) ==2: + statistical_tool.visualize_correlation(vars[0], vars[1], xlabel=labels[0], ylabel=labels[1], weights = weights) + else: + statistical_tool.visualize_many_correlations(vars, labels, weights = weights) + + saving_directory = config['Directories']['figures_dir'] + filename = '/Correlation' + if weights is not None: + filename = '/Correlation' + for i in range(len(var_strs)): + filename += "_" + var_strs[i] + + format = str(config['Regression_settings']['format_fig']) + filename += "." + format + dpi = None + if format == 'png': + dpi = 400 + plt.savefig(saving_directory + filename, format=format, dpi=dpi) + print(f'Finished producing correlation plot for {var_strs}, saved as {filename}\n') + diff --git a/Proof_of_principle/draft_scripts/.DS_Store b/Proof_of_principle/draft_scripts/.DS_Store new file mode 100644 index 0000000..87ed1dd Binary files /dev/null and b/Proof_of_principle/draft_scripts/.DS_Store differ diff --git a/Proof_of_principle/draft_scripts/comparison_zoom.py b/Proof_of_principle/draft_scripts/comparison_zoom.py new file mode 100644 index 0000000..fe8292c --- /dev/null +++ b/Proof_of_principle/draft_scripts/comparison_zoom.py @@ -0,0 +1,162 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ############################################################## + # # SCRIPT TO COMPARE MICRO AND FILTERED DATA + # # one figure shows the relative difference over the full grid, + # # other two are produced to compare the data in a zoomed-in patch + # ############################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO AND MICRO MODELS + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + + print('=========================================================================') + print(f'Starting job on data from {pickle_directory+ meso_pickled_filename}') + print('=========================================================================\n\n') + + MesoModelLoadFile = pickle_directory + meso_pickled_filename + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + micro_model = meso_model.micro_model + + print('Finished reading pickled data\n') + + # CHECKING WE ARE COMPARING DATA FROM THE SAME TIME-SLICE + num_snaps = micro_model.domain_vars['nt'] + central_slice_num = int(num_snaps/2.) + time_micro = micro_model.domain_vars['t'][central_slice_num] + num_slices_meso = int(config['Models_settings']['num_T_slices']) + time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)] + if time_meso != time_micro: + print("Slices of meso and micro model do not coincide. Careful!\n") + else: + print("Comparing data at same time-slice, hurray!\n") + + # # PLOT SETTINGS + saving_directory = config['Directories']['figures_dir'] + visualizer = Plotter_2D() + + inset_ranges = json.loads(config['Plot_settings']['inset_ranges']) + inset_x_range = inset_ranges['x_range'] + inset_y_range = inset_ranges['y_range'] + + rel_diff_ranges = json.loads(config['Plot_settings']['plot_ranges']) + rel_diff_x_range = rel_diff_ranges['x_range'] + rel_diff_y_range = rel_diff_ranges['y_range'] + + + # Building the data for showing the relative difference between the various plots + var_str = 'BC' + comp = (0,) + + micro_data_zoom, extent_micro_zoom = visualizer.get_var_data(micro_model, var_str, time_meso, inset_x_range, inset_y_range, comp) + meso_data_zoom, extent_meso_zoom = visualizer.get_var_data(meso_model, var_str, time_meso, inset_x_range, inset_y_range, comp) + + micro_data, extent_micro = visualizer.get_var_data(micro_model, var_str, time_meso, rel_diff_x_range, rel_diff_y_range, comp) + meso_data, extent_meso = visualizer.get_var_data(meso_model, var_str, time_meso, rel_diff_x_range, rel_diff_y_range, comp) + ar_mean = (np.abs(micro_data) + np.abs(meso_data))/2 + rel_diff = np.abs(meso_data - micro_data)/ar_mean + + # now plotting + fig = plt.figure(figsize=[13,4]) + ax1 = fig.add_subplot(1, 3, 1) + ax2 = fig.add_subplot(1, 3, 2) + ax3 = fig.add_subplot(1, 3, 3, sharey=ax2) + plt.setp(ax3.get_yticklabels(), visible=False) + axes = [ax1, ax2, ax3] + axesRight = [ax2, ax3] + + + im = ax1.imshow(rel_diff, extent=extent_meso, origin='lower', cmap = 'plasma', norm='log') + divider = make_axes_locatable(ax1) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + images = [] + im = ax2.imshow(micro_data_zoom, extent=extent_micro_zoom, origin='lower', cmap='plasma') #, norm='log') + images.append(im) + im = ax3.imshow(meso_data_zoom, extent=extent_meso_zoom, origin='lower', cmap='plasma') #, norm='log') + images.append(im) + + + for i in range(len(axes)): + axes[i].set_xlabel(r'$x$') + axes[i].set_ylabel(r'$y$') + + title = r'$Rel.$ $difference$' + ax1.set_title(title, fontsize=10) + + title = micro_model.labels_var_dict[var_str] + title += r'$,$ $a=0$' + ax2.set_title(title, fontsize=10) + + title = meso_model.labels_var_dict[var_str] + title += r'$,$ $a=0$' + ax3.set_title(title, fontsize=10) + + # fig.tight_layout() + divider = make_axes_locatable(ax2) + cax = divider.append_axes('right', size='5%', pad=0.05) + cax.set_axis_off() + + divider = make_axes_locatable(ax3) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + # fig.colorbar(images[0], ax=axesRight, orientation='vertical', location='right', shrink=.8, pad=0.025 ) + # Make images respond to changes in the norm of other images (e.g. via the + # "edit axis, curves and images parameters" GUI on Qt), but be careful not to + # recurse infinitely! + def update(changed_image): + for im in images: + if (changed_image.get_cmap() != im.get_cmap() + or changed_image.get_clim() != im.get_clim()): + im.set_cmap(changed_image.get_cmap()) + im.set_clim(changed_image.get_clim()) + + for im in images: + im.callbacks.connect('changed', update) + + + # Adding boundaries of zoomed in regions + A = np.array([inset_x_range[0], inset_y_range[0]]) + B = np.array([inset_x_range[1], inset_y_range[0]]) + C = np.array([inset_x_range[1], inset_y_range[1]]) + D = np.array([inset_x_range[0], inset_y_range[1]]) + arrows_starts = [A, B, C, D] + arrows_increments = [arrows_starts[i] - arrows_starts[i-1] for i in range(1, len(arrows_starts))] + arrows_increments.append(A-D) + for i in range(len(arrows_starts)): + ax1.arrow(arrows_starts[i][0], arrows_starts[i][1], arrows_increments[i][0], arrows_increments[i][1], \ + width=0.005,color='white',head_length=0.0,head_width=0.0) + + fig.tight_layout() + + format='png' + dpi=400 + filename = f"/Compairing_zoom_{var_str}_{comp}." + format + plt.savefig(saving_directory + filename, format = format, dpi=dpi) + + diff --git a/Proof_of_principle/draft_scripts/config_draft.txt b/Proof_of_principle/draft_scripts/config_draft.txt new file mode 100644 index 0000000..4be187e --- /dev/null +++ b/Proof_of_principle/draft_scripts/config_draft.txt @@ -0,0 +1,34 @@ +# CONFIGURATION FILE FOR SCRIPTS VISUALIZING_*.PY +################################################# + +[Directories] + +pickled_files_dir = /scratch/tc2m23/KHIRandom/hydro/new_data/800X800/ET10/pickled/50dx_data + +figures_dir = ./ + + +[Filenames] + +meso_pickled_filename = /rHD2d_cg=fw=bl=8dx.pickle + + +[Models_settings] +#snapshots_opts are useful in case not all snapshots from METHOD in the folder are required. +#relevant only for visualizing_micro.py + +snapshots_opts = {"fewer_snaps_required": false, "smaller_list": [9,10,11]} + +num_T_slices = 3 + +[Plot_settings] +# method sets that used for producing difference plots: set it to 'interpolate' when plotting models with different grids +# interp_dims is relevant when 'interpolate' method is used: should be set to the dims of the coarser grid +# Else, set method to "raw_data" to use gridded data directly + +plot_ranges = {"x_range": [0.04, 0.96], "y_range": [0.04, 0.96]} + +inset_ranges = {"x_range": [0.15, 0.35], "y_range": [0.5, 0.7]} + +diff_plot_settings = {"method": "raw_data", "interp_dims": [300, 300]} + diff --git a/Proof_of_principle/draft_scripts/const_coeff_all.py b/Proof_of_principle/draft_scripts/const_coeff_all.py new file mode 100644 index 0000000..347a75f --- /dev/null +++ b/Proof_of_principle/draft_scripts/const_coeff_all.py @@ -0,0 +1,154 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ############################################################## + # # SCRIPT TO COMPARE THE COMPUTED RESIDUALS WITH THEIR CONSTANT + # # COEFFICIENTS MODELLING + # ############################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO AND MICRO MODELS + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('=========================================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('=========================================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + micro_model = meso_model.micro_model + + print('Finished reading pickled data\n') + + + num_slices_meso = int(config['Models_settings']['num_T_slices']) + central_slice_num = int((num_slices_meso-1)/2) + + + # BUILDING THE VARIOUS MODELS WITH CONSTANT COEFF + eta = meso_model.meso_vars['eta'] + pi_res = meso_model.meso_vars['pi_res'] + shear_tilde = meso_model.meso_vars['shear_tilde'] + eta_const = np.mean(np.abs(eta)) + pi_res_model = np.multiply(eta_const, shear_tilde) + # print(f'data shape: {pi_res.shape} model shape: {pi_res_model.shape}') + + zeta = meso_model.meso_vars['zeta'] + Pi_res = meso_model.meso_vars['Pi_res'] + exp_tilde = meso_model.meso_vars['exp_tilde'] + zeta_const = np.mean(np.abs(zeta)) + Pi_res_model = np.multiply(zeta_const, np.abs(exp_tilde)) + # print(f'data shape: {Pi_res.shape} model shape: {Pi_res_model.shape}') + + # # Adding EOS residual to Pi_res + EOS_res = meso_model.meso_vars['eos_res'] + Pi_res = Pi_res + EOS_res + + kappa = meso_model.meso_vars['kappa'] + q_res = meso_model.meso_vars['q_res'] + Theta_tilde = meso_model.meso_vars['Theta_tilde'] + kappa_const = np.mean(np.abs(kappa)) + q_res_model = np.multiply(kappa_const, Theta_tilde) + # print(f'data shape: {q_res.shape} model shape: {q_res_model.shape}') + + # SQUARING THE TENSORS + metric = np.zeros((3,3)) + metric[0,0] = -1 + metric[1,1] = metric[2,2] = +1 + + Nx, Ny = meso_model.domain_vars['Nx'], meso_model.domain_vars['Ny'] + pi_res_sq = np.zeros((Nx, Ny)) + pi_res_sq_mod = np.zeros((Nx, Ny)) + q_res_sq = np.zeros((Nx, Ny)) + q_res_sq_mod = np.zeros((Nx, Ny)) + + h = central_slice_num + Pi_res = np.log10(Pi_res[h,:,:]) + Pi_res_model = np.log10(Pi_res_model[h,:,:]) + + for i in range(Nx): + for j in range(Ny): + temp = np.einsum('ij,kl,kj,li->', pi_res[h,i,j], pi_res[h,i,j], metric, metric) + temp = np.log10(np.sqrt(temp)) + pi_res_sq[i,j] = temp + + temp = np.einsum('ij,kl,kj,li->',pi_res_model[h,i,j], pi_res_model[h,i,j], metric, metric) + temp = np.log10(np.sqrt(temp)) + pi_res_sq_mod[i,j] = temp + + temp = np.einsum('i,ij,j->', q_res[h,i,j], metric, q_res[h,i,j]) + temp = np.log10(np.sqrt(temp)) + q_res_sq[i,j] = temp + + temp = np.einsum('i,ij,j->', q_res_model[h,i,j], metric, q_res_model[h,i,j]) + temp = np.log10(np.sqrt(temp)) + q_res_sq_mod[i,j] = temp + + # CREATING SUBPLOTS WITH CORRESPONDING DISTRIBUTIONS + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + fig, axes = plt.subplots(1,3, figsize=[13,4]) + axes = axes.flatten() + + data = [[Pi_res, Pi_res_model], [pi_res_sq, pi_res_sq_mod], [q_res_sq, q_res_sq_mod],] + + x_axis_labels = [] + x_axis_labels.append(r'$\log(\tilde\Pi)$') + x_axis_labels.append(r'$\log(\sqrt{\tilde\pi_{ab}\tilde\pi^{ab}})$') + x_axis_labels.append(r'$\log(\sqrt{\tilde q_{a}\tilde q^{a}})$') + + + + for i in range(len(axes)): + X = data[i][0] + Y = data[i][1] + if X.shape != Y.shape: + print(f'Careful: shapes not compatible. i={i}') + + X = X.flatten() + Y = Y.flatten() + + stat = 'probability' + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", message='is_categorical_dtype is deprecated') + warnings.filterwarnings('ignore', message='use_inf_as_na option is deprecated') + sns.histplot(X, stat=stat, kde=True, color='firebrick', ax=axes[i], label='sim. data') + sns.histplot(Y, stat=stat, kde=True, color='steelblue', ax=axes[i], label='model') + + axes[i].legend(loc = 'best', prop={'size': 10}) + axes[i].set_xlabel(x_axis_labels[i], fontsize=10) + axes[i].set_ylabel(stat, fontsize=10) + + + fig.tight_layout() + + fig_directory = config['Directories']['figures_dir'] + filename = f'/Const_coeff_models_' + f'{stat}' + 'EOS' + format = 'png' + dpi = 300 + filename += "." + format + plt.savefig(fig_directory + filename, format=format, dpi=dpi) + + diff --git a/Proof_of_principle/draft_scripts/filter_scaling.py b/Proof_of_principle/draft_scripts/filter_scaling.py new file mode 100644 index 0000000..f33c22c --- /dev/null +++ b/Proof_of_principle/draft_scripts/filter_scaling.py @@ -0,0 +1,390 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +from matplotlib import colors +from mpl_toolkits.axes_grid1.inset_locator import InsetPosition + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ############################################################################################### + # # SCRIPT TO SHOW HOW THE IMPACT OF FILTERING SCALES WITH THE FILTER-SIZE: REL DIFFERENCES + # ############################################################################################### + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO AND MICRO MODELS + pickle_directory = config['Directories']['pickled_files_dir'] + + + print('=========================================================================') + print(f'Starting job on data from {pickle_directory}') + print('=========================================================================\n\n') + + meso_pickled_filename = '/rHD2d_nocg_fw=2_bl=8dx.pickle' + MesoModelLoadFile = pickle_directory + meso_pickled_filename + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_2 = pickle.load(filehandle) + micro_model = meso_2.micro_model + + meso_pickled_filename = '/rHD2d_nocg_fw=4_bl=8dx.pickle' + MesoModelLoadFile = pickle_directory + meso_pickled_filename + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_4 = pickle.load(filehandle) + + meso_pickled_filename = '/rHD2d_nocg_fw=bl=8dx.pickle' + MesoModelLoadFile = pickle_directory + meso_pickled_filename + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_8 = pickle.load(filehandle) + + + print('Finished reading pickled data\n') + + # CHECKING WE ARE COMPARING DATA FROM THE SAME TIME-SLICE + num_snaps = micro_model.domain_vars['nt'] + central_slice_num = int(num_snaps/2.) + time_micro = micro_model.domain_vars['t'][central_slice_num] + num_slices_meso = int(config['Models_settings']['num_T_slices']) + time_meso2 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + time_meso4 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + time_meso8 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + + compatible = True + if time_micro != time_meso2 or time_meso2 != time_meso4 or time_meso4 != time_meso8: + compatible = False + + if not compatible: + print("Slices of meso and micro models do not coincide. Careful!\n") + else: + print("Comparing data at same time-slice, hurray!\n") + + # # PLOT SETTINGS + plot_ranges = json.loads(config['Plot_settings']['plot_ranges']) + x_range = plot_ranges['x_range'] + y_range = plot_ranges['y_range'] + saving_directory = config['Directories']['figures_dir'] + visualizer = Plotter_2D() + # diff_plot_settings =json.loads(config['Plot_settings']['diff_plot_settings']) + + # Building the data for showing the relative difference between the various plots + models = [micro_model, meso_2, meso_4, meso_8] + var_str = 'BC' + comp = (0,) + + # full_range = [0.04,0.96] + datamicro, extentmicro = visualizer.get_var_data(micro_model, var_str, time_micro, x_range, y_range, comp) + data2, extent2 = visualizer.get_var_data(meso_2, var_str, time_meso2, x_range, y_range, comp) + data4, extent4 = visualizer.get_var_data(meso_4, var_str, time_meso4, x_range, y_range, comp) + data8, extent8 = visualizer.get_var_data(meso_8, var_str, time_meso8, x_range, y_range, comp) + + + abs_diff2 = data2 - datamicro + abs_diff4 = data4 - datamicro + abs_diff8 = data8 - datamicro + + ar_mean = (np.abs(data2) + np.abs(datamicro))/2 + rel_diff2 = np.abs(datamicro -data2)/ar_mean + rel_diff2 = rel_diff2 / 2. + + ar_mean = (np.abs(data4) + np.abs(datamicro))/2 + rel_diff4 = np.abs(data4 -datamicro)/ar_mean + rel_diff4 = rel_diff4 / 4 + + ar_mean = (np.abs(data8) + np.abs(datamicro))/2 + rel_diff8 = np.abs(data8 - datamicro)/ar_mean + rel_diff8 = rel_diff8 /8 + + + # PLOTTING + fig = plt.figure(figsize=[13,4]) + ax1 = fig.add_subplot(1, 4, 1) + ax2 = fig.add_subplot(1, 4, 2, sharey=ax1) + ax3 = fig.add_subplot(1, 4, 3, sharey=ax1) + ax4 = fig.add_subplot(1, 4, 4, sharey=ax1) + axes = [ax1, ax2, ax3, ax4] + plt.setp(ax2.get_yticklabels(), visible=False) + plt.setp(ax3.get_yticklabels(), visible=False) + plt.setp(ax4.get_yticklabels(), visible=False) + + + + images =[] + + im = ax1.imshow(datamicro, extent=extentmicro, origin='lower', cmap='plasma') #, norm='log') + divider = make_axes_locatable(ax1) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = ax2.imshow(rel_diff2, extent=extent2, origin='lower', cmap='plasma') #, norm='log') + divider = make_axes_locatable(ax2) + cax = divider.append_axes('right', size='5%', pad=0.05) + cax.set_axis_off() + images.append(im) + + im = ax3.imshow(rel_diff4, extent=extent4, origin='lower', cmap='plasma') #, norm='log') + divider = make_axes_locatable(ax3) + cax = divider.append_axes('right', size='5%', pad=0.05) + cax.set_axis_off() + images.append(im) + + im = ax4.imshow(rel_diff8, extent=extent8, origin='lower', cmap='plasma') #, norm='log') + divider = make_axes_locatable(ax4) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + images.append(im) + + for i in range(len(axes)): + axes[i].set_xlabel(r'$x$') + axes[i].set_ylabel(r'$y$') + + title = micro_model.labels_var_dict[var_str] + title += r'$,$ $a=0$' + axes[0].set_title(title, fontsize=10) + + title = r'$Scaled$ $rel.$ $diff.,$ $L=2dx$' + # title = meso_2.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=2dx$' + axes[1].set_title(title, fontsize=10) + + title = r'$Scaled$ $rel.$ $diff.,$ $L=4dx$' + # title = meso_4.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=4dx$' + axes[2].set_title(title, fontsize=10) + + title = r'$Scaled$ $rel.$ $diff.,$ $L=8dx$' + # title = meso_8.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=8dx$' + axes[3].set_title(title, fontsize=10) + + fig.tight_layout() + + # COMMON COLORMAP + # Finding the global min and max and setting the shared colormap based on these. + vmin = min(image.get_array().min() for image in images) + vmax = max(image.get_array().max() for image in images) + norm = colors.Normalize(vmin=vmin, vmax=vmax) + for im in images: + im.set_norm(norm) + + # fig.colorbar(images[0], ax=axes, orientation='vertical', location='right', shrink=0.52, pad=0.025 ) + + # Make images respond to changes in the norm of other images (e.g. via the + # "edit axis, curves and images parameters" GUI on Qt), but be careful not to + # recurse infinitely! + def update(changed_image): + for im in images: + if (changed_image.get_cmap() != im.get_cmap() + or changed_image.get_clim() != im.get_clim()): + im.set_cmap(changed_image.get_cmap()) + im.set_clim(changed_image.get_clim()) + + for im in images: + im.callbacks.connect('changed', update) + + + format='png' + dpi=400 + filename = f"/Lin_scale_filt_{var_str}_{comp[0]}." + format + plt.savefig(saving_directory + filename, format = format, dpi=dpi) + + + + # # ################################################################################################## + # # # SCRIPT TO SHOW HOW THE IMPACT OF FILTERING SCALES WITH THE FILTER-SIZE: COARSE-GRAINING + # # ################################################################################################## + + # # READING SIMULATION SETTINGS FROM CONFIG FILE + # if len(sys.argv) == 1: + # print(f"You must pass the configuration file for the simulations.") + # raise Exception() + + # config = configparser.ConfigParser() + # config.read(sys.argv[1]) + + # # LOADING MESO AND MICRO MODELS + # pickle_directory = config['Directories']['pickled_files_dir'] + + + # print('=========================================================================') + # print(f'Starting job on data from {pickle_directory}') + # print('=========================================================================\n\n') + + # meso_pickled_filename = '/rHD2d_cg=fw=bl=2dx.pickle' + # MesoModelLoadFile = pickle_directory + meso_pickled_filename + # with open(MesoModelLoadFile, 'rb') as filehandle: + # meso_2 = pickle.load(filehandle) + # micro_model = meso_2.micro_model + + # meso_pickled_filename = '/rHD2d_cg=fw=bl=4dx.pickle' + # MesoModelLoadFile = pickle_directory + meso_pickled_filename + # with open(MesoModelLoadFile, 'rb') as filehandle: + # meso_4 = pickle.load(filehandle) + + # meso_pickled_filename = '/rHD2d_cg=fw=bl=8dx.pickle' + # MesoModelLoadFile = pickle_directory + meso_pickled_filename + # with open(MesoModelLoadFile, 'rb') as filehandle: + # meso_8 = pickle.load(filehandle) + + + # print('Finished reading pickled data\n') + + # # CHECKING WE ARE COMPARING DATA FROM THE SAME TIME-SLICE + # num_snaps = micro_model.domain_vars['nt'] + # central_slice_num = int(num_snaps/2.) + # time_micro = micro_model.domain_vars['t'][central_slice_num] + # num_slices_meso = int(config['Models_settings']['num_T_slices']) + # time_meso2 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + # time_meso4 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + # time_meso8 = meso_2.domain_vars['T'][int((num_slices_meso-1)/2)] + + # compatible = True + # if time_micro != time_meso2 or time_meso2 != time_meso4 or time_meso4 != time_meso8: + # compatible = False + + # if not compatible: + # print("Slices of meso and micro models do not coincide. Careful!\n") + # else: + # print("Comparing data at same time-slice, hurray!\n") + + # # # PLOT SETTINGS + # plot_ranges = json.loads(config['Plot_settings']['plot_ranges']) + # x_range = plot_ranges['x_range'] + # y_range = plot_ranges['y_range'] + # saving_directory = config['Directories']['figures_dir'] + # visualizer = Plotter_2D() + # # diff_plot_settings =json.loads(config['Plot_settings']['diff_plot_settings']) + + # # Building the data for showing the relative difference between the various plots + # models = [micro_model, meso_2, meso_4, meso_8] + # var_str = 'BC' + # comp = (0,) + + # inset_ranges = json.loads(config['Plot_settings']['inset_ranges']) + # inset_x_range = inset_ranges['x_range'] + # inset_y_range = inset_ranges['y_range'] + + # # full_range = [0.04,0.96] + # datamicro, extentmicro = visualizer.get_var_data(micro_model, var_str, time_micro, x_range, y_range, comp) + # data2, extent2 = visualizer.get_var_data(meso_2, var_str, time_meso2, inset_x_range, inset_y_range, comp) + # data4, extent4 = visualizer.get_var_data(meso_4, var_str, time_meso4, inset_x_range, inset_y_range, comp) + # data8, extent8 = visualizer.get_var_data(meso_8, var_str, time_meso8, inset_x_range, inset_y_range, comp) + + + # # PLOTTING + # fig = plt.figure(figsize=[13,4]) + # ax1 = fig.add_subplot(1, 4, 1) + # ax2 = fig.add_subplot(1, 4, 2, sharey=ax1) + # ax3 = fig.add_subplot(1, 4, 3, sharey=ax1) + # ax4 = fig.add_subplot(1, 4, 4, sharey=ax1) + # axes = [ax1, ax2, ax3, ax4] + # plt.setp(ax3.get_yticklabels(), visible=False) + # plt.setp(ax4.get_yticklabels(), visible=False) + + + # images =[] + + # im = ax1.imshow(datamicro, extent=extentmicro, origin='lower', cmap='plasma') #, norm='log') + # divider = make_axes_locatable(ax1) + # cax = divider.append_axes('right', size='5%', pad=0.05) + # images.append(im) + + # im = ax2.imshow(rel_diff2, extent=extent2, origin='lower', cmap='plasma') #, norm='log') + # divider = make_axes_locatable(ax2) + # cax = divider.append_axes('right', size='5%', pad=0.05) + # cax.set_axis_off() + # images.append(im) + + # im = ax3.imshow(rel_diff4, extent=extent4, origin='lower', cmap='plasma') #, norm='log') + # divider = make_axes_locatable(ax3) + # cax = divider.append_axes('right', size='5%', pad=0.05) + # cax.set_axis_off() + # images.append(im) + + # im = ax4.imshow(rel_diff8, extent=extent8, origin='lower', cmap='plasma') #, norm='log') + # divider = make_axes_locatable(ax4) + # cax = divider.append_axes('right', size='5%', pad=0.05) + # fig.colorbar(im, cax=cax, orientation='vertical') + # images.append(im) + + # for i in range(len(axes)): + # axes[i].set_xlabel(r'$x$') + # axes[i].set_ylabel(r'$y$') + + # title = micro_model.labels_var_dict[var_str] + # title += r'$,$ $a=0$' + # axes[0].set_title(title) + + # # title = r'$Scaled$ $rel.$ $diff.,$ $L=2dx$' + # title = meso_2.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=2dx$' + # axes[1].set_title(title) + + # # title = r'$Scaled$ $rel.$ $diff.,$ $L=4dx$' + # title = meso_4.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=4dx$' + # axes[2].set_title(title) + + # # title = r'$Scaled$ $rel.$ $diff.,$ $L=8dx$' + # title = meso_8.labels_var_dict[var_str] + # title += r'$,$ $a=0,$ $L=8dx$' + # axes[3].set_title(title) + + # fig.tight_layout() + + # # COMMON COLORMAP + # # Finding the global min and max and setting the shared colormap based on these. + # vmin = min(image.get_array().min() for image in images) + # vmax = max(image.get_array().max() for image in images) + # norm = colors.Normalize(vmin=vmin, vmax=vmax) + # for im in images: + # im.set_norm(norm) + + # # fig.colorbar(images[0], ax=axes, orientation='vertical', location='right', shrink=0.52, pad=0.025 ) + + # # Make images respond to changes in the norm of other images (e.g. via the + # # "edit axis, curves and images parameters" GUI on Qt), but be careful not to + # # recurse infinitely! + # def update(changed_image): + # for im in images: + # if (changed_image.get_cmap() != im.get_cmap() + # or changed_image.get_clim() != im.get_clim()): + # im.set_cmap(changed_image.get_cmap()) + # im.set_clim(changed_image.get_clim()) + + # for im in images: + # im.callbacks.connect('changed', update) + + + # # Adding boundaries of zoomed in regions + # A = np.array([inset_x_range[0], inset_y_range[0]]) + # B = np.array([inset_x_range[1], inset_y_range[0]]) + # C = np.array([inset_x_range[1], inset_y_range[1]]) + # D = np.array([inset_x_range[0], inset_y_range[1]]) + # arrows_starts = [A, B, C, D] + # arrows_increments = [arrows_starts[i] - arrows_starts[i-1] for i in range(1, len(arrows_starts))] + # arrows_increments.append(A-D) + # for i in range(len(arrows_starts)): + # ax1.arrow(arrows_starts[i][0], arrows_starts[i][1], arrows_increments[i][0], arrows_increments[i][1], \ + # width=0.005,color='white',head_length=0.0,head_width=0.0) + + # fig.tight_layout() + + # format='png' + # dpi=400 + # filename = f"/Filter_scale_BC_bl=fw." + format + # plt.savefig(saving_directory + filename, format = format, dpi=dpi) \ No newline at end of file diff --git a/Proof_of_principle/draft_scripts/gamma_interp.py b/Proof_of_principle/draft_scripts/gamma_interp.py new file mode 100644 index 0000000..992738b --- /dev/null +++ b/Proof_of_principle/draft_scripts/gamma_interp.py @@ -0,0 +1,272 @@ +import sys +# import os +sys.path.append('../../master_files/') +import pickle +import configparser +import json +import time +import math +from scipy import stats +from scipy.interpolate import SmoothBivariateSpline + +from matplotlib.ticker import FuncFormatter + +from FileReaders import * +from MicroModels import * +from MesoModels import * +from Visualization import * +from Analysis import * + +if __name__ == '__main__': + + # ################################################################## + # EXTRACTING THE 1ST ADIABATIC COEFFICIENT LOCALLY + # ################################################################## + + # READING SIMULATION SETTINGS FROM CONFIG FILE + if len(sys.argv) == 1: + print(f"You must pass the configuration file for the simulations.") + raise Exception() + + config = configparser.ConfigParser() + config.read(sys.argv[1]) + + # LOADING MESO MODEL + pickle_directory = config['Directories']['pickled_files_dir'] + meso_pickled_filename = config['Filenames']['meso_pickled_filename'] + MesoModelLoadFile = pickle_directory + meso_pickled_filename + + print('================================================') + print(f'Starting job on data from {MesoModelLoadFile}') + print('================================================\n\n') + + with open(MesoModelLoadFile, 'rb') as filehandle: + meso_model = pickle.load(filehandle) + + micro_model = meso_model.micro_model + + nx, ny = micro_model.domain_vars['nx'], micro_model.domain_vars['ny'] + central_slice_idx = int((micro_model.domain_vars['nt']-1)/2) + time_micro = micro_model.domain_vars['t'][central_slice_idx] + x_range = micro_model.domain_vars['xmin'], micro_model.domain_vars['xmax'] + y_range = micro_model.domain_vars['ymin'], micro_model.domain_vars['ymax'] + + visualizer = Plotter_2D() + + p_micro, micro_extent = visualizer.get_var_data(micro_model, 'p', time_micro, x_range, y_range) + n_micro, _ = visualizer.get_var_data(micro_model, 'n', time_micro, x_range, y_range) + int_en_micro, _ = visualizer.get_var_data(micro_model, 'e', time_micro, x_range, y_range) + + eps_micro = n_micro + np.multiply(n_micro, int_en_micro) + + p_micro_flat = p_micro.flatten() + n_micro_flat = n_micro.flatten() + eps_micro_flat = eps_micro.flatten() + + micro_SBS_p = SmoothBivariateSpline(n_micro_flat, eps_micro_flat, p_micro_flat) + micro_SBS_p_n = micro_SBS_p.partial_derivative(1, 0) + micro_SBS_p_eps = micro_SBS_p.partial_derivative(0, 1) + + def compute_Gamma(p, n,eps, partial_n_p, partial_eps_p): + """ + Given some values for the number density, the energy density and the pressure + Compute the corresponding adiabatic index (1st) using the cubic spline interpolations above + """ + Gamma = partial_n_p + (p+eps)/n * partial_eps_p + Gamma *= n/p + + return Gamma + + gamma_micro = np.zeros_like(p_micro) + rel_diff_gamma_micro = np.zeros_like(p_micro) + for i in range(len(p_micro[:,0])): + for j in range(len(p_micro[0,:])): + p = p_micro[i, j] + n = n_micro[i, j] + eps = eps_micro[i, j] + + partial_n_p = micro_SBS_p_n(n, eps) + partial_eps_p = micro_SBS_p_eps(n, eps) + gamma_micro[i,j] = compute_Gamma(p, n , eps, partial_n_p, partial_eps_p) -4./3. + rel_diff_gamma_micro[i,j] = np.abs(gamma_micro[i,j]) / (4/3) + + + Nt, Nx, Ny = meso_model.domain_vars['Nt'], meso_model.domain_vars['Nx'], meso_model.domain_vars['Ny'] + central_slice_idx = int((Nt-1)/2) + + time_meso = meso_model.domain_vars['T'][central_slice_idx] + x_range = meso_model.domain_vars['Xmin'], meso_model.domain_vars['Xmax'] + y_range = meso_model.domain_vars['Ymin'], meso_model.domain_vars['Ymax'] + + p_filt, meso_extent = visualizer.get_var_data(meso_model, 'p_filt', time_meso, x_range, y_range) + n_tilde, _ = visualizer.get_var_data(meso_model, 'n_tilde', time_meso, x_range, y_range) + eps_tilde, _ = visualizer.get_var_data(meso_model, 'eps_tilde', time_meso, x_range, y_range) + + p_filt_flat = p_filt.flatten() + n_tilde_flat = n_tilde.flatten() + eps_tilde_flat = eps_tilde.flatten() + + meso_SBS_p = SmoothBivariateSpline(n_tilde_flat, eps_tilde_flat, p_filt_flat) + meso_SBS_p_n = meso_SBS_p.partial_derivative(1, 0) + meso_SBS_p_eps = meso_SBS_p.partial_derivative(0, 1) + + gamma_meso = np.zeros_like(p_filt) + rel_diff_gamma_meso = np.zeros_like(p_filt) + for i in range(len(p_filt[:,0])): + for j in range(len(p_filt[0,:])): + p = p_filt[i, j] + n = n_tilde[i, j] + eps = eps_tilde[i, j] + + partial_n_p = meso_SBS_p_n(n, eps) + partial_eps_p = meso_SBS_p_eps(n, eps) + + gamma_meso[i,j] = compute_Gamma(p, n , eps, partial_n_p, partial_eps_p) -4./3. + rel_diff_gamma_meso[i,j] = np.abs(gamma_meso[i,j]) / (4/3.) + + + ############################################################################################### + # PLOTTING THE DIFFERENCE BETWEEN THE EXTRACTED ADIABATIC INDEX AND THE EXPECTED VALUE OF 4/3 + ############################################################################################### + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[9,4]) + axes = axes.flatten() + + im = axes[0].imshow(gamma_micro, extent=micro_extent, origin='lower', cmap='Spectral_r', norm='symlog') + divider = make_axes_locatable(axes[0]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[1].imshow(gamma_meso, extent=meso_extent, origin='lower', cmap='Spectral_r', norm='symlog') + divider = make_axes_locatable(axes[1]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + axes[0].set_title(r"$\Gamma_{micro} - 4/3$", fontsize =10) + axes[1].set_title(r"$\Gamma_{meso} - 4/3$", fontsize =10) + + for ax in axes: + ax.set_xlabel(r'$x$') + ax.set_ylabel(r'$y$') + + fig.tight_layout() + + fig_directory = config['Directories']['figures_dir'] + filename = 'Interp_Gamma' + format = 'png' + dpi = 300 + filename += "." + format + plt.savefig(fig_directory + filename, format=format, dpi=dpi) + plt.close() + + + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + fig, axes = plt.subplots(nrows=1, ncols=2, figsize=[9,4]) + axes = axes.flatten() + + im = axes[0].imshow(rel_diff_gamma_micro, extent=micro_extent, origin='lower', cmap='plasma', norm='log') + divider = make_axes_locatable(axes[0]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[1].imshow(rel_diff_gamma_meso, extent=meso_extent, origin='lower', cmap='plasma', norm='log') + divider = make_axes_locatable(axes[1]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + axes[0].set_title(r"$\frac{|\Gamma_{micro} - 4/3|}{4/3}$", fontsize =12) + axes[1].set_title(r"$\frac{|\Gamma_{meso} - 4/3|}{4/3}$", fontsize =12) + + for ax in axes: + ax.set_xlabel(r'$x$') + ax.set_ylabel(r'$y$') + + fig.tight_layout() + + fig_directory = config['Directories']['figures_dir'] + filename = 'Interp_Gamma_reldiff' + format = 'png' + dpi = 300 + filename += "." + format + plt.savefig(fig_directory + filename, format=format, dpi=dpi) + plt.close() + + + ################################################################################## + # PLOTTING THE INTERPOLATED P AND ITS DERIVATIVES: CHECK ON IMPACT OF ARTIFACTS + ################################################################################## + + p_filt_interp = np.zeros_like(p_filt) + d_n_p = np.zeros_like(p_filt) + d_eps_p = np.zeros_like(p_filt) + for i in range(len(p_filt[:,0])): + for j in range(len(p_filt[0,:])): + n = n_tilde[i, j] + eps = eps_tilde[i, j] + + p_filt_interp[i,j] = meso_SBS_p(n, eps) + d_n_p[i,j] = meso_SBS_p_n(n, eps) + d_eps_p[i,j] = meso_SBS_p_eps(n, eps) + + plt.rc("font",family="serif") + plt.rc("mathtext",fontset="cm") + + + fig, axes = plt.subplots(nrows=2, ncols=3, figsize=[13,8], sharex = True, sharey = True) + axes = axes.flatten() + + im = axes[0].imshow(p_filt, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[0]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[1].imshow(n_tilde, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[1]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[2].imshow(eps_tilde, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[2]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[3].imshow(p_filt_interp, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[3]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[4].imshow(d_n_p, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[4]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + im = axes[5].imshow(d_eps_p, extent=meso_extent, origin='lower', cmap='plasma') + divider = make_axes_locatable(axes[5]) + cax = divider.append_axes('right', size='5%', pad=0.05) + fig.colorbar(im, cax=cax, orientation='vertical') + + + for ax in axes: + ax.set_xlabel(r'$x$') + ax.set_ylabel(r'$y$') + + + axes[0].set_title(r"$
$", fontsize=12) + axes[1].set_title(r"$\tilde n$", fontsize=12) + axes[2].set_title(r"$\tilde \varepsilon$", fontsize=12) + axes[3].set_title(r"$
_{interpolated}$", fontsize=12) + axes[4].set_title(r"$\partial_{\tilde{n}}
$", fontsize=14) + axes[5].set_title(r"$\partial_{\tilde{\varepsilon}}
$", fontsize=14)
+
+
+ fig.tight_layout()
+
+ fig_directory = config['Directories']['figures_dir']
+ filename = 'Interpolation_test'
+ format = 'png'
+ dpi = 300
+ filename += "." + format
+ plt.savefig(fig_directory + filename, format=format, dpi=dpi)
+ plt.close()
\ No newline at end of file
diff --git a/Proof_of_principle/draft_scripts/outputs/.DS_Store b/Proof_of_principle/draft_scripts/outputs/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/Proof_of_principle/draft_scripts/outputs/.DS_Store differ
diff --git a/Proof_of_principle/draft_scripts/py_serial.slurm b/Proof_of_principle/draft_scripts/py_serial.slurm
new file mode 100644
index 0000000..e4ec88f
--- /dev/null
+++ b/Proof_of_principle/draft_scripts/py_serial.slurm
@@ -0,0 +1,37 @@
+#!/bin/bash
+####################################
+# JOB INFO:
+####################################
+
+
+#SBATCH --nodes=1
+#SBATCH --ntasks=1
+#SBATCH --time=00:10:00
+#SBATCH --output=outputs/serial_%A.out
+
+
+#SBATCH --mail-type=begin # send email when job begins
+#SBATCH --mail-type=fail
+#SBATCH --mail-type=end # send email when job ends
+#SBATCH --mail-user=celora@ice.csic.es
+
+
+####################################
+# LOADING THE CONDA ENVIRONMENT
+####################################
+
+module load conda/py3-latest
+# I get warnings to use 'conda deactivate' instead but that doesn't work
+source deactivate
+conda activate myenv
+
+
+####################################
+# LAUNCHING THE JOBS
+#####################################
+python3 -u filter_scaling.py config_draft.txt
+python3 -u comparison_zoom.py config_draft.txt
+python3 -u const_coeff_all.py config_draft.txt
+
+
+
diff --git a/Proof_of_principle/filter_scripts/.DS_Store b/Proof_of_principle/filter_scripts/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/Proof_of_principle/filter_scripts/.DS_Store differ
diff --git a/Proof_of_principle/filter_scripts/config_filter.txt b/Proof_of_principle/filter_scripts/config_filter.txt
new file mode 100644
index 0000000..3026fa3
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/config_filter.txt
@@ -0,0 +1,48 @@
+# CONFIGURATION FILE FOR SCRIPT PICKLING_MESO.PY
+#################################################
+
+[Directories]
+
+hdf5_dir = /scratch/tc2m23/KHIRandom/hydro/new_data/800X800/ET10/METHOD_output/50dx/
+
+pickled_files_dir = /scratch/tc2m23/KHIRandom/hydro/new_data/800X800/ET10/pickled/50dx_data
+
+figures_dir = .
+
+
+[Filenames]
+
+meso_pickled_filename = /rHD2d_nocg_fw=bl=8dx.pickle
+
+micro_pickled_filename = /
+
+
+[Micro_model_settings]
+#snapshots_opts are useful in case not all snapshots from METHOD in the folder are required.
+#the options is activated using the first key, while the list refers to the index of the elements of
+#ordered filenames' list to be retained (list ordered with glob in FileReaders.METHOD_HDF5 )
+
+snapshots_opts = {"fewer_snaps_required": true,
+ "smaller_list": [15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]}
+
+[Meso_model_settings]
+
+meso_grid = {"x_range": [0.03, 0.97], "y_range": [0.03, 0.97], "num_T_slices": 3,
+ "coarse_grain_factor": 1, "coarse_grain_time": false}
+
+filtering_options = {"box_len_ratio": 8.0, "filter_width_ratio": 2.0}
+
+n_cpus = 40
+
+
+[Plot_settings]
+# method sets that used for producing difference plots: set it to 'interpolate' when plotting models with different grids
+# interp_dims is relevant when 'interpolate' method is used: should be set to the dims of the coarser grid
+# Else, set method to "raw_data" to use gridded data directly
+
+plot_ranges = {"x_range": [0.04, 0.96], "y_range": [0.04, 0.96]}
+
+diff_plot_settings = {"method": "raw_data", "interp_dims": [300, 300]}
+
+
+
diff --git a/Proof_of_principle/filter_scripts/pickling_meso.py b/Proof_of_principle/filter_scripts/pickling_meso.py
new file mode 100644
index 0000000..dcff019
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/pickling_meso.py
@@ -0,0 +1,161 @@
+import sys
+import os
+sys.path.append('../../master_files/')
+import pickle
+import time
+import configparser
+import json
+
+from FileReaders import *
+from MicroModels import *
+from Filters import *
+from MesoModels import *
+
+if __name__ == '__main__':
+
+ ####################################################################################################
+ # # MAIN SCRIPT OF PIPELINE: SET UP THE MESO MODEL FROM SIM DATA (MESO-GRID + OBSERVERS + FILTER)
+ # # AND DECOMPOSE THE RESIDUALS AS WELL AS COMPUTE DERIVATIVES AND QUANTITIES FOR MODELLING THEM
+ ####################################################################################################
+
+ # READING SIMULATION SETTINGS FROM CONFIG FILE
+ if len(sys.argv) == 1:
+ print(f"You must pass the configuration file for the simulations.", flush=True)
+ raise Exception()
+
+ config = configparser.ConfigParser()
+ config.read(sys.argv[1])
+
+ # SETTING UP THE MICROMODEL
+ start_time = time.perf_counter()
+ hdf5_directory = config['Directories']['hdf5_dir']
+ print(f'Starting job with data from {hdf5_directory}', flush=True)
+ print('==============================================\n')
+ filenames = hdf5_directory
+ snapshots_opts = json.loads(config['Micro_model_settings']['snapshots_opts'])
+ fewer_snaps_required = snapshots_opts['fewer_snaps_required']
+ smaller_list = snapshots_opts['smaller_list']
+ FileReader = METHOD_HDF5(filenames,fewer_snaps_required, smaller_list)
+ num_snaps = FileReader.num_files
+ micro_model = IdealHD_2D()
+ FileReader.read_in_data_HDF5_missing_xy(micro_model)
+ micro_model.setup_structures()
+ time_taken = time.perf_counter() - start_time
+ print(f'Finished reading micro data from hdf5, structures also set up. Time taken: {time_taken}', flush=True)
+
+ # SETTING UP THE MESO MODEL
+ start_time = time.perf_counter()
+ meso_grid = json.loads(config['Meso_model_settings']['meso_grid'])
+ filtering_options = json.loads(config['Meso_model_settings']['filtering_options'])
+
+ coarse_factor = meso_grid['coarse_grain_factor']
+ coarse_time = meso_grid['coarse_grain_time']
+ central_slice_num = int(num_snaps/2)
+ num_T_slices = meso_grid['num_T_slices']
+ furthest_slice_number = int((num_T_slices-1)/2)
+ if coarse_time:
+ furthest_slice_number = int(coarse_factor * furthest_slice_number)
+
+ t_range = [micro_model.domain_vars['t'][central_slice_num-furthest_slice_number], micro_model.domain_vars['t'][central_slice_num+furthest_slice_number]]
+ x_range = meso_grid['x_range']
+ y_range = meso_grid['y_range']
+
+ ts = micro_model.domain_vars['t'][:]
+ print(f'ts: {ts}\n')
+
+ box_len_ratio = float(filtering_options['box_len_ratio'])
+ filter_width_ratio = float(filtering_options['filter_width_ratio'])
+
+ box_len = box_len_ratio * micro_model.domain_vars['dx']
+ width = filter_width_ratio * micro_model.domain_vars['dx']
+ find_obs = FindObs_root_parallel(micro_model, box_len)
+ filter = box_filter_parallel(micro_model, width)
+ meso_model = resHD2D(micro_model, find_obs, filter)
+ meso_model.setup_meso_grid([t_range, x_range, y_range], coarse_factor = coarse_factor, coarse_time = coarse_time)
+
+ time_taken = time.perf_counter() - start_time
+ print('Grid is set up, time taken: {}\n'.format(time_taken), flush=True)
+ num_points = meso_model.domain_vars['Nx'] * meso_model.domain_vars['Ny'] * meso_model.domain_vars['Nt']
+ print('Number of points: {}\n'.format(num_points), flush=True)
+
+ # FINDING THE OBSERVERS
+ n_cpus = int(config['Meso_model_settings']['n_cpus'])
+
+ start_time = time.perf_counter()
+ meso_model.find_observers_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Observers found in parallel: time taken= {}\n'.format(time_taken), flush=True)
+
+
+ # # UNCOMMENT IF MESO_MODEL EXISTS PICKLED EXIST ALREADY AND YOU WANT TO RE-RUN SOME OF THE LATER ROUTINES:
+ # # LOADING MESO MODEL
+ # pickle_directory = config['Directories']['pickled_files_dir']
+ # meso_pickled_filename = config['Filenames']['meso_pickled_filename']
+ # MesoModelLoadFile = pickle_directory + meso_pickled_filename
+ # n_cpus = int(config['Meso_model_settings']['n_cpus'])
+
+ # print('=========================================================================')
+ # print(f'Starting job on data from {MesoModelLoadFile}')
+ # print('=========================================================================\n\n')
+ # with open(MesoModelLoadFile, 'rb') as filehandle:
+ # meso_model = pickle.load(filehandle)
+
+
+ # # This is to adjust the filter-size by retaining the observers computed above
+ # filtering_options = json.loads(config['Meso_model_settings']['filtering_options'])
+ # filter_width_ratio = filtering_options['filter_width_ratio']
+ # micro_model = meso_model.micro_model
+ # width = filter_width_ratio * micro_model.domain_vars['dx']
+ # filter = box_filter_parallel(micro_model, width)
+ # meso_model.set_filter(filter)
+
+
+ # FILTERING
+ start_time = time.perf_counter()
+ meso_model.filter_micro_vars_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Parallel filtering stage ended (fw= {}): time taken= {}\n'.format(int(filter_width_ratio), time_taken), flush=True)
+
+
+ # DECOMPOSING AND CALCULATING THE CLOSURE INGREDIENTS
+ start_time = time.perf_counter()
+ meso_model.decompose_structures_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Finished decomposing meso structures in parallel, time taken: {}\n'.format(time_taken), flush=True)
+
+
+ start_time = time.perf_counter()
+ meso_model.calculate_derivatives()
+ time_taken = time.perf_counter() - start_time
+ print('Finished computing derivatives (serial), time taken: {}\n'.format(time_taken), flush=True)
+
+ start_time = time.perf_counter()
+ meso_model.closure_ingredients_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Finished computing the closure ingredients in parallel, time taken: {}\n'.format(time_taken), flush=True)
+
+ start_time = time.perf_counter()
+ meso_model.EL_style_closure_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Finished computing the EL_style closure in parallel, time taken: {}\n'.format(time_taken), flush=True)
+
+ start_time = time.perf_counter()
+ meso_model.modelling_coefficients_parallel(n_cpus)
+ time_taken = time.perf_counter() - start_time
+ print('Finished computing quantities to model extracted coefficients, time taken: {}\n'.format(time_taken), flush=True)
+
+ # start_time = time.perf_counter()
+ # meso_model.build_weights_Q1()
+ # time_taken = time.perf_counter() - start_time
+ # print('Finished computing weights in serial, time taken: {}\n'.format(time_taken), flush=True)
+
+ # PICKLING THE CLASS INSTANCE FOR FUTURE USE
+ pickle_directory = config['Directories']['pickled_files_dir']
+ filename = config['Filenames']['meso_pickled_filename']
+ MesoModelPickleDumpFile = pickle_directory + filename
+ with open(MesoModelPickleDumpFile, 'wb') as filehandle:
+ pickle.dump(meso_model, filehandle)
+
+
+
+
diff --git a/Proof_of_principle/filter_scripts/py_parallel.slurm b/Proof_of_principle/filter_scripts/py_parallel.slurm
new file mode 100644
index 0000000..1189a96
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/py_parallel.slurm
@@ -0,0 +1,37 @@
+#!/bin/bash
+####################################
+# JOB INFO: parallel, single node
+####################################
+
+#SBATCH --output=outputs/parallel_%A.out
+#SBATCH --nodes=1
+#SBATCH --ntasks=40
+#SBATCH --time=01:00:00
+
+#SBATCH --mail-type=begin
+#SBATCH --mail-type=fail
+#SBATCH --mail-type=end
+#SBATCH --mail-user=celora@ice.csic.es
+
+
+####################################
+# LOADING THE CONDA ENVIRONMENT
+####################################
+
+module load conda/py3-latest
+# I get warnings to use 'conda deactivate' instead but that doesn't work
+source deactivate
+conda activate myenv
+
+
+
+####################################
+# LAUNCHING THE JOBS
+####################################
+
+python3 -u pickling_meso.py config_filter.txt
+
+
+
+
+
diff --git a/Proof_of_principle/filter_scripts/py_serial.slurm b/Proof_of_principle/filter_scripts/py_serial.slurm
new file mode 100644
index 0000000..c00fa73
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/py_serial.slurm
@@ -0,0 +1,42 @@
+#!/bin/bash
+####################################
+# JOB INFO: serial
+####################################
+
+
+#SBATCH --nodes=1
+#SBATCH --ntasks=1
+#SBATCH --time=00:10:00
+#SBATCH --output=outputs/serial_%A.out
+
+
+
+#SBATCH --mail-type=begin # send email when job begins
+#SBATCH --mail-type=fail
+#SBATCH --mail-type=end # send email when job ends
+#SBATCH --mail-user=celora@ice.csic.es
+
+
+####################################
+# LOADING THE CONDA ENVIRONMENT
+####################################
+
+module load conda/py3-latest
+# I get warnings to use 'conda deactivate' instead but that doesn't work
+source deactivate
+conda activate myenv
+
+
+####################################
+# LAUNCHING THE JOBS
+#####################################
+
+# python3 -u visualizing_micro.py config_filter.txt
+# python3 -u visualizing_obs.py config_filter.txt
+python3 -u visualizing_meso.py config_filter.txt
+# python3 -u visualizing_residuals.py config_filter.txt
+
+
+
+
+
diff --git a/Proof_of_principle/filter_scripts/visualizing_meso.py b/Proof_of_principle/filter_scripts/visualizing_meso.py
new file mode 100644
index 0000000..7ffc655
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/visualizing_meso.py
@@ -0,0 +1,338 @@
+import sys
+# import os
+sys.path.append('../../master_files/')
+import pickle
+import configparser
+import json
+import time
+
+from FileReaders import *
+from MicroModels import *
+from MesoModels import *
+from Visualization import *
+from Analysis import *
+
+if __name__ == '__main__':
+
+ # ###################################################################
+ # SCRIPT TO VISUALIZE VARIOUS MESO QUANTITIES AND COMPARE WITH MICRO
+ # ###################################################################
+
+ # READING SIMULATION SETTINGS FROM CONFIG FILE
+ if len(sys.argv) == 1:
+ print(f"You must pass the configuration file for the simulations.")
+ raise Exception()
+
+ config = configparser.ConfigParser()
+ config.read(sys.argv[1])
+
+ # LOADING MESO AND MICRO MODELS
+ pickle_directory = config['Directories']['pickled_files_dir']
+ meso_pickled_filename = config['Filenames']['meso_pickled_filename']
+ MesoModelLoadFile = pickle_directory + meso_pickled_filename
+
+ print('=========================================================================')
+ print(f'Starting job on data from {MesoModelLoadFile}')
+ print('=========================================================================\n\n')
+
+ with open(MesoModelLoadFile, 'rb') as filehandle:
+ meso_model = pickle.load(filehandle)
+ micro_model = meso_model.micro_model
+
+ print('Finished reading pickled data\n')
+
+ # CHECKING WE ARE COMPARING DATA FROM THE SAME TIME-SLICE
+ num_snaps = micro_model.domain_vars['nt']
+ central_slice_num = int(num_snaps/2.)
+ time_micro = micro_model.domain_vars['t'][central_slice_num]
+ meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ num_slices_meso = meso_grid_info['num_T_slices']
+ time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ if time_meso != time_micro:
+ print("Slices of meso and micro model do not coincide. Careful!\n")
+ else:
+ print("Comparing data at same time-slice, hurray!\n")
+
+ # # PLOT SETTINGS
+ plot_ranges = json.loads(config['Plot_settings']['plot_ranges'])
+ x_range = plot_ranges['x_range']
+ y_range = plot_ranges['y_range']
+ saving_directory = config['Directories']['figures_dir']
+ visualizer = Plotter_2D([12, 8])
+ diff_plot_settings =json.loads(config['Plot_settings']['diff_plot_settings'])
+ diff_method = diff_plot_settings['method']
+ interp_dims = diff_plot_settings['interp_dims']
+
+ # # PLOTTING MICRO VS FILTERED BC AND SET
+ # # #####################################
+ # start_time = time.perf_counter()
+ # vars = [['BC'],['BC']]
+ # models = [micro_model, meso_model]
+ # comp = 1
+ # components= [[(comp,)],[(comp,)]]
+ # # norms = [['log'], ['log'], ['log']]
+ # norms = [['symlog'], ['symlog'], ['log']]
+ # # cmaps = [['plasma'],['plasma'],['plasma']]
+ # cmaps = [['coolwarm'],['coolwarm'],['plasma']]
+ # fig=visualizer.plot_vars_models_comparison(models, vars, time_meso, x_range, y_range, components_indices = components,
+ # interp_dims = interp_dims, method = diff_method, diff_plot=False, rel_diff=True, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # format='png'
+ # dpi=400
+ # filename = "/Comparing_BC" +f"_{comp}." + format
+ # plt.savefig(saving_directory + filename, format = format, dpi=dpi)
+
+ # vars = [['SET'], ['SET']]
+ # models = [micro_model, meso_model]
+ # comp = 1
+ # components = [[(comp,comp)], [(comp,comp)]]
+ # norms = [['log'], ['log'], ['log']]
+ # # norms = [['symlog'], ['symlog'], ['log']]
+ # cmaps = [['plasma'],['plasma'],['plasma']]
+ # # cmaps = [['coolwarm'],['coolwarm'],['plasma']]
+ # fig=visualizer.plot_vars_models_comparison(models, vars, time_meso, x_range, y_range, components_indices = components,
+ # interp_dims = interp_dims, method = diff_method, diff_plot=False, rel_diff=True, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # format='png'
+ # dpi=400
+ # filename = "/Comparing_SET" +f"_({comp},{comp})."+format
+ # plt.savefig(saving_directory + filename, format = format, dpi=dpi)
+ # time_taken = time.perf_counter() - start_time
+ # print(f'Finished plotting model comparison: time taken (X2) ={time_taken}\n')
+
+ # # # PLOTTING THE DECOMPOSED SET
+ # # #############################
+ vars_strs = ['pi_res', 'pi_res', 'pi_res', 'pi_res', 'pi_res', 'pi_res']
+ norms = ['mysymlog', 'mysymlog', 'mysymlog', 'mysymlog', 'mysymlog', 'mysymlog']
+ cmaps = ['Spectral_r','Spectral_r','Spectral_r','Spectral_r','Spectral_r','Spectral_r']
+ components = [(0,0), (0,1), (0,2), (1,1), (1,2), (2,2)]
+ fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(time_meso,2))
+ filename = "/DecomposedSET_1.pdf"
+ plt.savefig(saving_directory + filename, format = 'pdf')
+
+ vars_strs = ['q_res', 'q_res', 'q_res', 'Pi_res', 'p_tilde', 'p_filt']
+ norms = ['mysymlog', 'mysymlog', 'mysymlog', 'log', 'log', 'log']
+ cmaps = ['Spectral_r','Spectral_r','Spectral_r', 'plasma', 'plasma', 'plasma']
+ components = [(0,), (1,), (2,), (), (), ()]
+ fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(time_meso,2))
+ filename = "/DecomposedSET_2.pdf"
+ plt.savefig(saving_directory + filename, format = 'pdf')
+ print('Finished plotting decomposition of SET\n')
+
+ # # # # PLOTTING THE DERIVATIVES OF FAVRE VEL AND TEMPERATURE
+ # # #########################################################
+ # favre_vel_components = [0,1,2]
+ # for i in range(len(favre_vel_components)):
+ # components = [tuple([favre_vel_components[i]])]
+ # for j in range(3):
+ # components.append(tuple([j,favre_vel_components[i]]))
+ # if i==0:
+ # norms = ['log', 'mysymlog', 'mysymlog', 'mysymlog']
+ # cmaps = ['plasma', 'seismic', 'seismic', 'seismic']
+ # else:
+ # norms = ['mysymlog', 'mysymlog', 'mysymlog', 'mysymlog']
+ # cmaps = ['seismic', 'seismic', 'seismic', 'seismic']
+
+ # vars_strs = ['u_tilde', 'D_u_tilde', 'D_u_tilde', 'D_u_tilde']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/D_favre_{}.pdf".format(favre_vel_components[i])
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished plotting derivatives of favre velocity\n', flush=True)
+
+ # vars_strs = ['T_tilde', 'D_T_tilde', 'D_T_tilde', 'D_T_tilde']
+ # components = [(), (0,), (1,), (2,)]
+ # norms = ['log', 'mysymlog', 'mysymlog', 'mysymlog']
+ # cmaps = ['plasma', 'seismic', 'seismic', 'seismic']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/D_T.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished plotting temperature derivatives\n', flush=True)
+
+ # # # PLOTTING SHEAR, ACCELERATION, EXPANSION AND TEMPERATURE DERIVATIVES
+ # ########################################################################
+ # vars_strs = ['shear_tilde', 'shear_tilde', 'shear_tilde', 'shear_tilde', 'shear_tilde', 'shear_tilde']
+ # components = [(0,0), (0,1), (0,2), (1,1), (1,2), (2,2)]
+ # norms = ['mysymlog','mysymlog','mysymlog','mysymlog','mysymlog','mysymlog']
+ # cmaps = ['seismic','seismic','seismic','seismic','seismic','seismic']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/Shear_comps.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished plotting shear\n', flush=True)
+
+ # vars_strs = ['acc_tilde', 'acc_tilde', 'acc_tilde', 'Theta_tilde', 'Theta_tilde', 'Theta_tilde']
+ # components = [(0,), (1,), (2,), (0,), (1,), (2,)]
+ # norms = ['mysymlog','mysymlog','mysymlog','mysymlog','mysymlog','mysymlog']
+ # cmaps = ['seismic','seismic','seismic','seismic','seismic','seismic']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/Acc+Tderivs.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished plotting DaT\n', flush=True)
+
+ # vars_strs = ['vort_tilde', 'vort_tilde', 'vort_tilde']
+ # components = [(0,1), (0,2), (1,2)]
+ # norms = [None, None, None] #['mysymlog','mysymlog','mysymlog']
+ # cmaps = ['plasma','plasma','plasma']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, components_indices=components, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/Vorticity_comps.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished plotting vorticity\n', flush=True)
+
+ # # SUMMARY PLOT OF THE RESIDUALS
+ vars_strs = ['Pi_res', 'pi_res_sq', 'q_res_sq']
+ vars = []
+ extents = []
+ for var_str in vars_strs:
+ temp_var, temp_extent = visualizer.get_var_data(meso_model, var_str, time_meso, x_range, y_range)
+ if var_str != 'Pi_res':
+ temp_var = np.sqrt(temp_var)
+ vars.append(temp_var)
+ extents.append(temp_extent)
+
+
+
+ norms = ['log', 'log', 'log']
+ cmaps = ['plasma', 'plasma', 'plasma']
+
+
+ plt.rc("font",family="serif")
+ plt.rc("mathtext",fontset="cm")
+ fig, axes = plt.subplots(1,3, squeeze=False, figsize=[12,4], sharey=True)
+ axes = axes.flatten()
+
+ images = []
+
+ for i in range(len(axes)):
+
+ if norms[i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(vars[i])
+ data_to_plot = MySymLogPlotting.symlog_var(vars[i])
+ mynorm = MyThreeNodesNorm(nodes)
+ im = axes[i].imshow(data_to_plot, extent=extents[i], origin='lower', norm=mynorm, cmap=cmaps[i])
+ divider = make_axes_locatable(axes[i])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ else:
+ im = axes[i].imshow(vars[i], extent=extents[i], origin='lower', cmap=cmaps[i], norm=norms[i])
+ # divider = make_axes_locatable(axes[i])
+ # cax = divider.append_axes('right', size='5%', pad=0.05)
+ # fig.colorbar(im, cax=cax, orientation='vertical')
+ images.append(im)
+
+ axes[i].set_xlabel(r'$x$', fontsize=10)
+ axes[i].set_ylabel(r'$y$', fontsize=10)
+
+ axes[0].set_title(r'$\tilde{\Pi}$', fontsize=14)
+ axes[1].set_title(r'$\sqrt{\tilde{\pi}_{ab}\tilde{\pi}^{ab}}$', fontsize=14)
+ axes[2].set_title(r'$\sqrt{\tilde{q}_{a}\tilde{q}^{a}}$', fontsize=14)
+
+ fig.tight_layout()
+
+
+ ###########################################################
+ # Adapt the following if you want to have a single colormap
+ ###########################################################
+ # SETTING UP A COMMON COLORMAP
+ # Finding the global min and max and setting the colormap to be based on these.
+ vmin = min(image.get_array().min() for image in images)
+ vmax = max(image.get_array().max() for image in images)
+ norm = colors.LogNorm(vmin=vmin, vmax=vmax)
+ for im in images:
+ im.set_norm(norm)
+
+ fig.colorbar(images[0], ax=axes.ravel().tolist(), orientation='vertical', location='right', shrink=0.9)
+
+ # Make images respond to changes in the norm of other images (e.g. via the
+ # "edit axis, curves and images parameters" GUI on Qt), but be careful not to
+ # recurse infinitely!
+ def update(changed_image):
+ for im in images:
+ if (changed_image.get_cmap() != im.get_cmap()
+ or changed_image.get_clim() != im.get_clim()):
+ im.set_cmap(changed_image.get_cmap())
+ im.set_clim(changed_image.get_clim())
+
+ for im in images:
+ im.callbacks.connect('changed', update)
+
+ format='png'
+ dpi=400
+ filename = f"/Residuals." + format
+ plt.savefig(saving_directory + filename, format = format, dpi=dpi)
+
+
+ # # NOW SUMMARY PLOT FOR THE CLOSURE INGREDIENTS
+
+ vars_strs = ['exp_tilde', 'shear_sq', 'Theta_sq']
+ vars = []
+ extents = []
+ for var_str in vars_strs:
+ temp_var, temp_extent = visualizer.get_var_data(meso_model, var_str, time_meso, x_range, y_range)
+ if var_str != 'exp_tilde':
+ temp_var = np.sqrt(temp_var)
+ vars.append(temp_var)
+ extents.append(temp_extent)
+
+
+
+ norms = ['symlog', 'log', 'log']
+ cmaps = ['Spectral_r', 'plasma', 'plasma']
+
+
+ plt.rc("font",family="serif")
+ plt.rc("mathtext",fontset="cm")
+ fig, axes = plt.subplots(1,3, squeeze=False, figsize=[12,4], sharey=True)
+ axes = axes.flatten()
+
+ images = []
+
+ for i in range(len(axes)):
+
+ if norms[i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(vars[i])
+ data_to_plot = MySymLogPlotting.symlog_var(vars[i])
+ mynorm = MyThreeNodesNorm(nodes)
+ im = axes[i].imshow(data_to_plot, extent=extents[i], origin='lower', norm=mynorm, cmap=cmaps[i])
+ divider = make_axes_locatable(axes[i])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ else:
+ im = axes[i].imshow(vars[i], extent=extents[i], origin='lower', cmap=cmaps[i], norm=norms[i])
+ divider = make_axes_locatable(axes[i])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+ images.append(im)
+
+ axes[i].set_xlabel(r'$x$', fontsize=10)
+ axes[i].set_ylabel(r'$y$', fontsize=10)
+
+ axes[0].set_title(r'$\tilde{\theta}$', fontsize=14)
+ axes[1].set_title(r'$\sqrt{\tilde{\sigma}_{ab}\tilde{\sigma}^{ab}}$', fontsize=14)
+ axes[2].set_title(r'$\sqrt{\tilde{\Theta}_{a}\tilde{\Theta}^{a}}$', fontsize=14)
+
+ fig.tight_layout()
+
+ format='png'
+ dpi=400
+ filename = f"/Gradients." + format
+ plt.savefig(saving_directory + filename, format = format, dpi=dpi)
+
diff --git a/Proof_of_principle/filter_scripts/visualizing_micro.py b/Proof_of_principle/filter_scripts/visualizing_micro.py
new file mode 100644
index 0000000..78dc253
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/visualizing_micro.py
@@ -0,0 +1,102 @@
+import sys
+# import os
+sys.path.append('../../master_files/')
+import configparser
+import json
+import pickle
+
+from FileReaders import *
+from MicroModels import *
+from Visualization import *
+
+if __name__ == '__main__':
+
+ ####################################################################################################
+ # SCRIPT TO PLOT MICRO-MODEL QUANTITIES: THIS IS THE DATA DIRECTLY FROM SIMULATIONS
+ ####################################################################################################
+
+ # READING SIMULATION SETTINGS FROM CONFIG FILE
+ if len(sys.argv) == 1:
+ print(f"You must pass the configuration file for the simulations.")
+ raise Exception()
+
+ config = configparser.ConfigParser()
+ config.read(sys.argv[1])
+
+ # LOADING MICRO DATA FROM HDF5 OR PICKLE
+ micro_from_hdf5 = False
+
+ if micro_from_hdf5:
+ hdf5_directory = config['Directories']['hdf5_dir']
+ print('=========================================================================')
+ print(f'Starting job on data from {hdf5_directory}')
+ print('=========================================================================\n\n')
+ filenames = hdf5_directory + '/'
+ snapshots_opts = json.loads(config['Micro_model_settings']['snapshots_opts'])
+ fewer_snaps_required = snapshots_opts['fewer_snaps_required']
+ smaller_list = snapshots_opts['smaller_list']
+ FileReader = METHOD_HDF5(filenames, fewer_snaps_required, smaller_list)
+ num_snaps = FileReader.num_files
+ micro_model = IdealHD_2D()
+ FileReader.read_in_data_HDF5_missing_xy(micro_model)
+ micro_model.setup_structures()
+ print('Finished reading micro data from hdf5, structures also set up.')
+
+ else:
+ pickle_directory = config['Directories']['pickled_files_dir']
+ micro_pickled_filename = config['Filenames']['micro_pickled_filename']
+ MicroModelLoadFile = pickle_directory + micro_pickled_filename
+ print('=========================================================================')
+ print(f'Starting job on data from {MicroModelLoadFile}')
+ print('=========================================================================\n\n')
+ with open(MicroModelLoadFile, 'rb') as filehandle:
+ meso_model = pickle.load(filehandle)
+ micro_model = meso_model.micro_model
+ # micro_model = pickle.load(filehandle)
+
+
+ # PLOT SETTINGS
+ plot_ranges = json.loads(config['Plot_settings']['plot_ranges'])
+ x_range = plot_ranges['x_range']
+ y_range = plot_ranges['y_range']
+
+ num_snaps = micro_model.domain_vars['nt']
+ central_slice_num = int(num_snaps/2.)
+ plot_time = micro_model.domain_vars['t'][central_slice_num]
+
+ saving_directory = config['Directories']['figures_dir']
+ visualizer = Plotter_2D([11.97, 8.36])
+
+ # FINALLY, PLOTTING
+ # Plotting the baryon current
+ vars = ['BC', 'BC', 'BC', 'W', 'vx', 'vy']
+ norms= ['log', 'symlog', 'symlog', 'log', 'symlog', 'symlog']
+ cmaps = [None, 'Spectral_r', 'Spectral_r', None, 'Spectral_r', 'Spectral_r']
+ components = [(0,), (1,), (2,), (), (), ()]
+ fig=visualizer.plot_vars(micro_model, vars, plot_time, x_range, y_range, components_indices = components, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(plot_time,2))
+ filename = "/micro_T_" + time_for_filename + "_BC.pdf"
+ plt.savefig(saving_directory + filename, format = "pdf")
+
+ # Plotting the stress energy tensor
+ vars = ['SET', 'SET', 'SET', 'SET', 'SET', 'SET']
+ components = [(0,0), (0,1), (0,2), (1,1), (1,2), (2,2)]
+ norms= ['log', 'symlog', 'symlog', 'log', 'symlog', 'log']
+ cmaps = [None, 'Spectral_r', 'Spectral_r', None, 'Spectral_r', None]
+ fig=visualizer.plot_vars(micro_model, vars, plot_time, x_range, y_range, components_indices = components, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(plot_time,2))
+ filename = "/micro_T_" + time_for_filename + "_SET.pdf"
+ plt.savefig(saving_directory + filename, format = "pdf")
+
+ # plotting primitive quantities
+ vars = ['W', 'vx', 'vy', 'n', 'p', 'e']
+ norms= ['log', 'symlog', 'symlog', 'log', 'log', 'log']
+ cmaps = [None, 'Spectral_r', 'Spectral_r', None, None, None]
+ fig=visualizer.plot_vars(micro_model, vars, plot_time, x_range, y_range, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(plot_time,2))
+ filename = "/micro_T_" + time_for_filename + "_prims.pdf"
+ plt.savefig(saving_directory + filename, format = "pdf")
+
diff --git a/Proof_of_principle/filter_scripts/visualizing_obs.py b/Proof_of_principle/filter_scripts/visualizing_obs.py
new file mode 100644
index 0000000..1da6c46
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/visualizing_obs.py
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+import sys
+# import os
+sys.path.append('../../master_files/')
+import pickle
+import configparser
+import json
+from matplotlib.ticker import LogLocator
+
+from FileReaders import *
+from MicroModels import *
+from MesoModels import *
+from Visualization import *
+
+if __name__ == '__main__':
+
+ ####################################################################################################
+ # SCRIPT TO VISUALIZE THE FILTERING OBSERVERS: COMPARE WITH EITHER MICRO OR FAVRE VEL
+ ####################################################################################################
+
+ # READING SIMULATION SETTINGS FROM CONFIG FILE
+ if len(sys.argv) == 1:
+ print(f"You must pass the configuration file for the simulations.")
+ raise Exception()
+
+ config = configparser.ConfigParser()
+ config.read(sys.argv[1])
+
+ # LOADING MESO AND MICRO MODELS
+ pickle_directory = config['Directories']['pickled_files_dir']
+ meso_pickled_filename = config['Filenames']['meso_pickled_filename']
+ MesoModelLoadFile = pickle_directory + meso_pickled_filename
+
+ print('=========================================================================')
+ print(f'Starting job on data from {MesoModelLoadFile}')
+ print('=========================================================================\n\n')
+
+ with open(MesoModelLoadFile, 'rb') as filehandle:
+ meso_model = pickle.load(filehandle)
+ micro_model = meso_model.micro_model
+
+ print(f'Finished reading data from {MesoModelLoadFile}')
+
+ # CHECKING WE ARE COMPARING DATA FROM THE SAME TIME-SLICE
+ num_snaps = micro_model.domain_vars['nt']
+ central_slice_num = int(num_snaps/2.)
+ time_micro = micro_model.domain_vars['t'][central_slice_num]
+ meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ num_slices_meso = meso_grid_info['num_T_slices']
+ time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ if time_meso != time_micro:
+ print("Slices of meso and micro model do not coincide. Careful!")
+ else:
+ print("Comparing data at same time-slice, hurray!")
+
+
+ # PLOT SETTINGS
+ saving_directory = config['Directories']['figures_dir']
+ plot_ranges = json.loads(config['Plot_settings']['plot_ranges'])
+ x_range = plot_ranges['x_range']
+ y_range = plot_ranges['y_range']
+ diff_plot_settings = json.loads(config['Plot_settings']['diff_plot_settings'])
+ diff_method = diff_plot_settings['method']
+ interp_dims = diff_plot_settings['interp_dims']
+ visualizer = Plotter_2D([10, 3])
+
+ # label_2_update = {'U' : r'$U^a$'}
+ # meso_model.upgrade_labels_dict(label_2_update)
+
+ # FINALLY, PLOTTING
+ # models = [micro_model, meso_model]
+ # vars = [['bar_vel', 'bar_vel', 'bar_vel'],['u_tilde', 'u_tilde', 'u_tilde']]
+ # components_indices= [[(0,),(1,),(2,)], [(0,), (1,), (2,)]]
+ # norms = [['log','mysymlog','mysymlog'],['log','mysymlog','mysymlog'],['log','log','log']]
+ # cmaps = [['plasma','seismic','seismic'],['plasma','seismic','seismic'], ['plasma','plasma','plasma']]
+ # fig = visualizer.plot_vars_models_comparison(models, vars, time_meso, x_range, y_range, components_indices=components_indices, method=diff_method,
+ # interp_dims=interp_dims, diff_plot=False, rel_diff=True, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename="/favreVSmicro.pdf"
+ # plt.savefig(saving_directory + filename, format="pdf")
+ # print('Finished plotting the favre velocities')
+
+
+ models = [micro_model, meso_model]
+ # vars = [['bar_vel', 'bar_vel', 'bar_vel'],['U', 'U', 'U']]
+ # norms = [['log','mysymlog','mysymlog'],['log','mysymlog','mysymlog'],['log','log','log']]
+ # cmaps = [['plasma','seismic','seismic'], ['plasma','seismic','seismic'], ['plasma','plasma','plasma']]
+
+ # vars = [['bar_vel'], ['U']]
+ # norms = [['log'], ['log'], ['log']]
+ # cmaps = [['plasma'],['plasma'], ['plasma']]
+ # components_indices= [[(0,)], [(0,)]]
+ # fig = visualizer.plot_vars_models_comparison(models, vars, time_meso, x_range, y_range, components_indices=components_indices, method=diff_method,
+ # interp_dims=interp_dims, diff_plot=False, rel_diff=True, norms=norms, cmaps=cmaps)
+
+ # axes = np.array(fig.axes)
+ # axes = axes.flatten()
+ # axes[0].set_title(micro_model.labels_var_dict['bar_vel'] + r"$,$ $a=0$")
+ # axes[1].set_title(meso_model.labels_var_dict['U'] + r"$,$ $a=0$")
+ # axes[2].set_title(r"$Relative$ $difference$")
+
+ comp = (1,)
+ bar_vel_data, extent_micro = visualizer.get_var_data(micro_model, 'bar_vel', time_meso, x_range, y_range, comp)
+ obs_data, extent_meso = visualizer.get_var_data(meso_model, 'U', time_meso, x_range, y_range, comp)
+ ar_mean = (np.abs(bar_vel_data) + np.abs(obs_data))/2
+ rel_diff = np.abs(bar_vel_data - obs_data)/ar_mean
+
+
+ fig = plt.figure(figsize=[13,4])
+ ax1 = fig.add_subplot(1, 3, 1)
+ ax2 = fig.add_subplot(1, 3, 2)
+ ax3 = fig.add_subplot(1, 3, 3, sharey=ax2)
+ plt.setp(ax3.get_yticklabels(), visible=False)
+ axes = [ax1, ax2, ax3]
+ axesRight = [ax2, ax3]
+
+
+ im = ax1.imshow(rel_diff, extent=extent_meso, origin='lower', cmap = 'plasma', norm='log')
+ divider = make_axes_locatable(ax1)
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.ax.minorticks_on()
+
+ images = []
+ im = ax2.imshow(bar_vel_data, extent=extent_micro, origin='lower', cmap='plasma') #, norm='log')
+ images.append(im)
+ im = ax3.imshow(obs_data, extent=extent_meso, origin='lower', cmap='plasma') #, norm='log')
+ images.append(im)
+
+
+ for i in range(len(axes)):
+ axes[i].set_xlabel(r'$x$')
+ axes[i].set_ylabel(r'$y$')
+
+ title = r'$Rel.$ $difference$'
+ ax1.set_title(title)
+
+ title = micro_model.labels_var_dict['bar_vel']
+ title += r'$,$ $a=0$'
+ ax2.set_title(title)
+
+ title = meso_model.labels_var_dict['U']
+ title += r'$,$ $a=0$'
+ ax3.set_title(title)
+
+ # fig.tight_layout()
+ divider = make_axes_locatable(ax2)
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cax.set_axis_off()
+
+ divider = make_axes_locatable(ax3)
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+
+ # fig.colorbar(images[0], ax=axesRight, orientation='vertical', location='right', shrink=.8, pad=0.025 )
+ # Make images respond to changes in the norm of other images (e.g. via the
+ # "edit axis, curves and images parameters" GUI on Qt), but be careful not to
+ # recurse infinitely!
+ def update(changed_image):
+ for im in images:
+ if (changed_image.get_cmap() != im.get_cmap()
+ or changed_image.get_clim() != im.get_clim()):
+ im.set_cmap(changed_image.get_cmap())
+ im.set_clim(changed_image.get_clim())
+
+ for im in images:
+ im.callbacks.connect('changed', update)
+
+
+ fig.tight_layout()
+ filename=f"/ObsVSmicro_{comp[0]}."
+ format = 'png'
+ dpi=400
+ plt.savefig(saving_directory + filename + format, format=format, dpi=dpi)
+ print('Finished plotting the observers')
+
diff --git a/Proof_of_principle/filter_scripts/visualizing_residuals.py b/Proof_of_principle/filter_scripts/visualizing_residuals.py
new file mode 100644
index 0000000..c0a66bd
--- /dev/null
+++ b/Proof_of_principle/filter_scripts/visualizing_residuals.py
@@ -0,0 +1,253 @@
+import sys
+# import os
+sys.path.append('../../master_files/')
+import pickle
+import configparser
+import json
+import time
+import math
+
+from FileReaders import *
+from MicroModels import *
+from MesoModels import *
+from Visualization import *
+from Analysis import *
+
+if __name__ == '__main__':
+
+ # # ##########################################################################################
+ # # SCRIPT TO VISUALIZE THE RESIDUALS: PLOT THEM AGAINST THE CLOSURE INGREDIENTS AND THE
+ # # WEIGHING FUNCTIONS THAT CAN BE CONSIDERED FOR CALIBRATING THE MODEL
+ # ############################################################################################
+
+
+ # READING SIMULATION SETTINGS FROM CONFIG FILE
+ if len(sys.argv) == 1:
+ print(f"You must pass the configuration file for the simulations.")
+ raise Exception()
+
+ config = configparser.ConfigParser()
+ config.read(sys.argv[1])
+
+ # LOADING MESO AND MICRO MODELS
+ pickle_directory = config['Directories']['pickled_files_dir']
+ meso_pickled_filename = config['Filenames']['meso_pickled_filename']
+ MesoModelLoadFile = pickle_directory + meso_pickled_filename
+
+ print('================================================')
+ print(f'Starting job on data from {MesoModelLoadFile}')
+ print('================================================\n\n')
+
+ with open(MesoModelLoadFile, 'rb') as filehandle:
+ meso_model = pickle.load(filehandle)
+
+ statistical_tool = CoefficientsAnalysis()
+ correlation_ranges = json.loads(config['Plot_settings']['plot_ranges'])
+ x_range = correlation_ranges['x_range']
+ y_range = correlation_ranges['y_range']
+ meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ num_slices_meso = meso_grid_info['num_T_slices']
+ time_of_central_slice = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ ranges = [[time_of_central_slice, time_of_central_slice], x_range, y_range]
+ model_points = meso_model.domain_vars['Points']
+ saving_directory = config['Directories']['figures_dir']
+
+ # print('Producing correlation plot for pi_res')
+ # x = meso_model.meso_vars['shear_sq']
+ # y = meso_model.meso_vars['pi_res_sq']
+ # data = [x,y]
+ # data = statistical_tool.trim_dataset(data, ranges, model_points)
+ # preprocess_data = {"value_ranges": [[None, None], [None, None]], "log_abs": [1, 1]}
+ # data = statistical_tool.preprocess_data(data, preprocess_data)
+ # data = statistical_tool.extract_randomly(data, 30000)
+ # x, y = data[0], data[1]
+ # xlabel = r'$\log(\tilde{\sigma}_{ab}\tilde{\sigma}^{ab})$'
+ # ylabel = r'$\log(\tilde{\pi}_{ab}\tilde{\pi}^{ab})$'
+ # g2=statistical_tool.visualize_correlation(x, y, xlabel=xlabel, ylabel=ylabel)
+ # saving_directory = config['Directories']['figures_dir']
+ # filename = '/pi_aniso_correlation.pdf'
+ # plt.savefig(saving_directory + filename, format='pdf')
+ # print(f'Finished correlation plot for pi_res, saved as {filename}\n\n')
+
+
+ # print('Producing correlation plot for q_res')
+ # x = meso_model.meso_vars['q_res_sq']
+ # y = meso_model.meso_vars['Theta_sq']
+ # data = [x,y]
+ # data = statistical_tool.trim_dataset(data, ranges, model_points)
+ # preprocess_data = {"value_ranges": [[None, None], [None, None]], "log_abs": [1, 1]}
+ # data = statistical_tool.preprocess_data(data, preprocess_data)
+ # data = statistical_tool.extract_randomly(data, 30000)
+ # x, y = data[0], data[1]
+ # xlabel = r'$\log(\tilde{q}_a\tilde{q}^a)$'
+ # ylabel = r'$\log(\tilde{\Theta}_a \tilde{\Theta}^a)$'
+ # model_points = meso_model.domain_vars['Points']
+ # g2=statistical_tool.visualize_correlation(x, y, xlabel=xlabel, ylabel=ylabel)
+ # saving_directory = config['Directories']['figures_dir']
+ # filename = '/q_res_correlation.pdf'
+ # plt.savefig(saving_directory + filename, format='pdf')
+ # print(f'Finished correlation plot for q_res, saved as {filename}\n\n')
+
+
+ # print('Producing correlation plot for Pi_res')
+ # x = np.power(meso_model.meso_vars['Pi_res'], 2)
+ # y = np.power(meso_model.meso_vars['exp_tilde'], 2)
+ # data = [x,y]
+ # data = statistical_tool.trim_dataset(data, ranges, model_points)
+ # preprocess_data = {"value_ranges": [[None, None], [None, None]], "log_abs": [1, 1]}
+ # data = statistical_tool.preprocess_data(data, preprocess_data)
+ # data = statistical_tool.extract_randomly(data, 30000)
+ # x, y = data[0], data[1]
+ # xlabel = r'$\log(\tilde{\Pi}^2)$'
+ # ylabel = r'$\log(\tilde{\theta}^2)$'
+ # model_points = meso_model.domain_vars['Points']
+ # g2=statistical_tool.visualize_correlation(x, y, xlabel=xlabel, ylabel=ylabel)
+ # saving_directory = config['Directories']['figures_dir']
+ # filename = '/Pi_res_correlation.pdf'
+ # plt.savefig(saving_directory + filename, format='pdf')
+ # print(f'Finished correlation plot for Pi_res, saved as {filename}\n\n')
+
+
+ # #############################################################
+ # PLOTTING RESIDUALS VS CORRESPONDING CLOSURE INGREDIENTS
+ # #############################################################
+
+ meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ num_slices_meso = meso_grid_info['num_T_slices']
+ time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ visualizer = Plotter_2D()
+
+ vars_strs = ['zeta', 'exp_tilde', 'Pi_res']
+ norms = ['mysymlog', 'symlog', 'log']
+ cmaps = ['Spectral', 'Spectral', 'plasma']
+ fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(time_meso,2))
+ filename = "/Bulk_viscosity.png"
+ plt.savefig(saving_directory + filename, format = 'png', dpi=300)
+ print('Finished bulk viscosity')
+
+ vars_strs = ['eta', 'shear_sq', 'pi_res_sq']
+ norms = ['mysymlog', 'log', 'log']
+ cmaps = ['Spectral', 'plasma', 'plasma']
+ fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(time_meso,2))
+ filename = "/Shear_viscosity.png"
+ plt.savefig(saving_directory + filename, format = 'png', dpi=300)
+ print('Finished shear viscosity')
+
+ vars_strs = ['kappa', 'Theta_sq', 'q_res_sq']
+ norms = ['mysymlog', 'log', 'log']
+ cmaps = ['Spectral', 'plasma', 'plasma']
+ fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ fig.tight_layout()
+ time_for_filename = str(round(time_meso,2))
+ filename = "/Heat_conductivity.png"
+ plt.savefig(saving_directory + filename, format = 'png', dpi=300)
+ print('Finished heat conductivity')
+
+
+ # det_s = meso_model.meso_vars['det_shear']
+ # vars_strs = ['eta', 'det_shear']
+ # norms = ['mysymlog', 'mysymlog']
+ # cmaps = ['seismic', 'seismic']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # time_for_filename = str(round(time_meso,2))
+ # filename = "/eta_vs_newdet.png"
+ # plt.savefig(saving_directory + filename, format = 'png', dpi = 400)
+ # print(f'Finished figure {filename}')
+
+
+ # ############################################################
+ # # PLOTTING Q1 AND Q2 AGAINST THE RESIDUALS SQUARED
+ # ############################################################
+
+ # meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ # num_slices_meso = meso_grid_info['num_T_slices']
+ # time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ # visualizer = Plotter_2D()
+
+ # vars_strs = ['Pi_res_sq', 'Q1', 'Q2']
+ # norms = ['log', 'mysymlog', 'log']
+ # cmaps = ['plasma', 'coolwarm', 'plasma']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/Pi_res_Q.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished Pi_res')
+
+ # vars_strs = ['pi_res_sq', 'Q1', 'Q2']
+ # norms = ['log', 'mysymlog', 'log']
+ # cmaps = ['plasma', 'coolwarm', 'plasma']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/an_pi_res_Q.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished pi_res')
+
+ # vars_strs = ['q_res_sq', 'Q1', 'Q2']
+ # norms = ['log', 'mysymlog', 'log']
+ # cmaps = ['plasma', 'coolwarm', 'plasma']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/q_res_Q.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished q_res')
+
+ # ############################################################
+ # # PLOTTING WEIGHING FUNCTIONS
+ # ############################################################
+
+ # meso_grid_info = json.loads(config['Meso_model_settings']['meso_grid'])
+ # num_slices_meso = meso_grid_info['num_T_slices']
+ # time_meso = meso_model.domain_vars['T'][int((num_slices_meso-1)/2)]
+ # visualizer = Plotter_2D()
+
+ # d = {'Q1' : r'$\tilde{\sigma}_{ab}\tilde{\sigma}^{ab} - \tilde{\omega}_{ab}\tilde{\omega}^{ab}$'}
+ # meso_model.update_labels_dict(d)
+ # d = {'Q2' : r'$\tilde{\sigma}_{ab}\tilde{\sigma}^{ab}/\tilde{\omega}_{ab}\tilde{\omega}^{ab}$'}
+ # meso_model.update_labels_dict(d)
+ # d = {'weights' : r'$w$'}
+ # meso_model.update_labels_dict(d)
+
+ # print('Building skew weights based on Q1')
+ # meso_model.weights_Q1_skew()
+ # print('Finished re-building the weights\n')
+
+ # vars_strs = ['weights', 'Q1']
+ # norms = [None, 'mysymlog']
+ # cmaps = ['plasma', 'coolwarm']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/Q1_skew.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished Q1weights_plot\n')
+
+ # print('Building non-negative weights based on Q1')
+ # meso_model.weights_Q1_non_neg()
+ # print('Finished re-building the weights\n')
+
+ # vars_strs = ['weights', 'Q1']
+ # norms = [None, 'mysymlog']
+ # cmaps = ['plasma', 'coolwarm']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/Q1_non_neg.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished Q1weights_plot')
+
+
+ # print('Building weights based on Q2')
+ # meso_model.weights_Q2()
+ # print('Finished re-building the weights\n')
+
+ # vars_strs = ['weights', 'Q2']
+ # norms = [None, 'log']
+ # cmaps = ['plasma', 'plasma']
+ # fig = visualizer.plot_vars(meso_model, vars_strs, time_meso, x_range, y_range, norms=norms, cmaps=cmaps)
+ # fig.tight_layout()
+ # filename = "/Q2_weights.pdf"
+ # plt.savefig(saving_directory + filename, format = 'pdf')
+ # print('Finished Q1weights_plot\n')
\ No newline at end of file
diff --git a/Visualization.py b/Visualization.py
deleted file mode 100644
index e0f8583..0000000
--- a/Visualization.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Mon Jun 5 03:14:43 2023
-
-@author: marcu
-"""
-
-
-import matplotlib.pyplot as plt
-import numpy as np
-import h5py
-from mpl_toolkits.axes_grid1 import make_axes_locatable
-from scipy.interpolate import interpn
-from system.BaseFunctionality import *
-
-class Plotter_2D(object):
-
- def __init__(self):
- """
- Blank as yet.
- """
- self.subplots_dims = {1 : (1,1),
- 2 : (1,2),
- 3 : (1,3),
- 4 : (2,2),
- 5 : (2,3),
- 6 : (2,3)}
-
-
- def get_var_data(self, model, var_str, t, x_range, y_range, interp_dims, method, component_indices):
- """
- Retrieves the required data from model to plot a variable defined by
- var_str over coordinates t, x_range, y_range, either from the model's
- raw data or by interpolating between the model's raw data over the coords.
-
- Parameters
- ----------
- model : Micro or Meso Model
- var_str : str
- Must match a variable of the model.
- t : float
- time coordinate (defines the foliation).
- x_range : list of 2 floats: x_start and x_end
- defines range of x coordinates within foliation.
- y_range : list of 2 floats: y_start and y_end
- defines range of y coordinates within foliation.
- interp_dims : tuple of integers
- defines the number of points to interpolate at in x and y directions.
- method : str
- currently either raw_data or interpolate.
- component_indices : tuple
- the indices of the component to pick out if the variable is a vector/tensor.
-
- Returns
- -------
- data_to_plot : numpy array of floats
- the (2D) data to be plotted by plt.imshow().
- points : numpy array of floats
- the coordinates of the data-points.
-
- """
- if var_str in model.get_all_var_strs():
-
- if method == 'interpolate':
-
- nx, ny = interp_dims[:]
- xs, ys = np.linspace(x_range[0],x_range[1],nx), np.linspace(y_range[0],y_range[1],ny)
- points = [t,xs,ys]
- data_to_plot = np.zeros((nx,ny))
-
- for i in range(nx):
- for j in range(ny):
- point = [t,xs[i],ys[j]]
- data_to_plot[i,j] = interpn(model.domain_vars['points'],\
- model.vars[var_str], point,\
- method = model.interp_method)[0][component_indices]
- elif method == 'raw_data':
-
- start_indices = Base.find_nearest_cell([t, x_range[0], y_range[0]], model.domain_vars['points'])
- end_indices = Base.find_nearest_cell([t, x_range[1], y_range[1]], model.domain_vars['points'])
-
- h = start_indices[0]
- i_s, i_f = start_indices[1], end_indices[1]
- j_s, j_f = start_indices[2], end_indices[2]
-
- points = [model.domain_vars['points'][0][h],\
- model.domain_vars['points'][1][i_s:i_f+1],\
- model.domain_vars['points'][2][j_s:j_f+1]]
-
- data_to_plot = model.vars[var_str][h:h+1, i_s:i_f+1, j_s:j_f+1][0]#[:, :, component_indices]
- # print(data_to_plot)
- if component_indices:
- for component_index in component_indices:
- data_to_plot = data_to_plot[:, :, component_index]
-
-
-
- else:
- print('Data method is not a valid choice! Must be interpolate or raw_data.')
-
- else:
- print(f'{var_str} is not a plottable variable of the model!')
-
- return data_to_plot, points
-
-
- def plot_vars(self, model, var_strs, t, x_range, y_range, interp_dims=(), \
- method='interpolate', components_indices=None):
- """
- Plot variable(s) from model, defined by var_strs, over coordinates
- t, x_range, y_range. Either from the model's raw data or by interpolating
- between the model's raw data over the coords.
-
- Parameters
- ----------
- model : Micro or Meso Model
- var_strs : list of str
- Must match entries in the models' 'vars' dictionary.
- t : float
- time coordinate (defines the foliation).
- x_range : list of 2 floats: x_start and x_end
- defines range of x coordinates within foliation.
- y_range : list of 2 floats: y_start and y_end
- defines range of y coordinates within foliation.
- interp_dims : tuple of integers
- defines the number of points to interpolate at in x and y directions.
- method : str
- currently either raw_data or interpolate.
- components_indices : list of tuple(s)
- the indices of the components to pick out if the variables are vectors/tensors.
- Can be omitted is all variables are scalars, otherwise must be a list
- of tuples matching the length of var_strs that corresponds with each
- variable in the list.
-
- Output
- -------
- Plots the (2D) data using imshow. Note that the plotting data's coordinates
- may not perfectly match the input coordinates if method=raw_data as
- nearest-cell data is used where the input coordinates do not coincide
- with the model's raw data coordinates.
-
- """
- n_plots = len(var_strs)
- n_rows, n_cols = self.subplots_dims[n_plots]
- fig, axes = plt.subplots(n_rows,n_cols, figsize=(16,16)) # figsize should be adaptive..
- if n_plots == 1:
- axes = [axes]
- else:
- axes = axes.flatten()
-
- for var_str, component_indices, ax in zip(var_strs, components_indices, axes):
- data_to_plot, points = self.get_var_data(model, var_str, t, x_range, y_range, interp_dims, method, component_indices)
- extent = [points[2][0],points[2][-1],points[1][0],points[1][-1]]
- im = ax.imshow(data_to_plot, extent=extent)
- divider = make_axes_locatable(ax)
- cax = divider.append_axes('right', size='5%', pad=0.05)
- fig.colorbar(im, cax=cax, orientation='vertical')
- ax.set_title(model.get_model_name())
- # fig.suptitle(model.get_model_name(), fontsize=16)
- ax.set_title(var_str)
- ax.set_xlabel(r'$y$')
- ax.set_ylabel(r'$x$')
-
- fig.tight_layout()
- plt.show()
-
-
- def plot_var_model_comparison(self, models, var_str, t, x_range, y_range, \
- interp_dims=(), method='interpolate', component_indices=(), diff_plot=True):
- """
- Plot a variable from a number of models. If 2 models are given, a third
- plot of the difference will be automatically plotted, too. If 'raw_data'
- is chosen as the method, will check to see if the data points in the model
- lie at the same coordinates, which they must.
-
- Parameters
- ----------
- models : Micro or Meso Models
- var_sts : str
- Must match entries in the models' 'vars' dictionary.
- t : float
- time coordinate (defines the foliation).
- x_range : list of 2 floats: x_start and x_end
- defines range of x coordinates within foliation.
- y_range : list of 2 floats: y_start and y_end
- defines range of y coordinates within foliation.
- interp_dims : tuple of integers
- defines the number of points to interpolate at in x and y directions.
- method : str
- currently either raw_data or interpolate.
- component_indices : tuple
- the indices of the component to pick out if the variable is a vector/tensor.
-
- Output
- -------
- Plots the (2D) data using imshow. Note that the plotting data's coordinates
- may not perfectly match the input coordinates if method=raw_data as
- nearest-cell data is used where the input coordinates do not coincide
- with the model's raw data coordinates.
-
- """
- n_cols = len(models)
- if not n_cols == 2:
- diff_plot = False # Only plot difference of 2 models...
- n_rows = 1
- if diff_plot:
- n_cols+=1
- fig, axes = plt.subplots(n_rows,n_cols,sharex='row',sharey='col',figsize=(16,16))
-
- for model, ax in zip(models, axes.flatten()):
- data_to_plot, points = self.get_var_data(model, var_str, t, x_range, y_range, interp_dims, method, component_indices)
- extent = [points[2][0],points[2][-1],points[1][0],points[1][-1]]
- im = ax.imshow(data_to_plot, extent=extent)
- divider = make_axes_locatable(ax)
- cax = divider.append_axes('right', size='5%', pad=0.05)
- fig.colorbar(im, cax=cax, orientation='vertical')
- ax.set_title(model.get_model_name())
- ax.set_xlabel(r'$y$')
- ax.set_ylabel(r'$x$')
-
- if diff_plot:
- ax = axes.flatten()[-1]
- data_to_plot1, points1 = self.get_var_data(models[0], var_str, t, x_range, y_range, interp_dims, method, component_indices)
- data_to_plot2, points2 = self.get_var_data(models[1], var_str, t, x_range, y_range, interp_dims, method, component_indices)
- # if len(points1) != len(points2):
- # diff_plot = False
- # pass
- # for t_points1, t_points2 in zip(points1, points2):
- # print(t_points1, t_points2)
- # if len(t_points1) != t_points2.shape:
- # diff_plot = False
- # continue
- # if not np.allclose(t_points1, t_points2):
- # diff_plot = False
- # if diff_plot:
- try:
- extent = [points1[2][0],points1[2][-1],points1[1][0],points1[1][-1]]
- im = ax.imshow(data_to_plot1 - data_to_plot2, extent=extent)
- divider = make_axes_locatable(ax)
- cax = divider.append_axes('right', size='5%', pad=0.05)
- fig.colorbar(im, cax=cax, orientation='vertical')
- ax.set_title(model.get_model_name())
- ax.set_title('Model Difference')
- ax.set_xlabel(r'$y$')
- ax.set_ylabel(r'$x$')
- except(ValueError):
- print(f"Cannot plot the difference between {var_str} in the two "
- "models. Likely due to the data coordinates not coinciding.")
- fig.tight_layout()
- plt.show()
-
-
-
-
-
-
-
-
-
-
diff --git a/master_files/Analysis.py b/master_files/Analysis.py
new file mode 100644
index 0000000..30d67cf
--- /dev/null
+++ b/master_files/Analysis.py
@@ -0,0 +1,1251 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Jan 24 18:02:05 2023
+
+@author: marcu
+"""
+
+# USE !SCIKIT LEARN INSTEAD? IT'S THE PACKAGE FOR MACHINE LEARNING SO!
+
+import matplotlib.pyplot as plt
+import numpy as np
+import numpy.ma as ma
+import pandas as pd
+import h5py
+import pickle
+import seaborn as sns
+import warnings
+import random
+from sklearn.linear_model import LinearRegression
+from sklearn.decomposition import PCA
+from sklearn.model_selection import train_test_split
+# from scipy import stats
+from scipy.stats import gaussian_kde, wasserstein_distance, pearsonr
+# import statsmodels.api as sm
+
+from system.BaseFunctionality import *
+from MicroModels import *
+from FileReaders import *
+from Filters import *
+from Visualization import *
+from MesoModels import *
+
+
+
+class CoefficientsAnalysis(object):
+ """
+ Class containing a number of methods for performing statistical analysis on gridded data.
+ Methods include: regression, visualizing correlations, PCA routines
+ """
+ def __init__(self): #, visualizer, spatial_dims):
+ """
+ Nothing as yet...
+
+ Returns
+ -------
+ Also nothing...
+
+ """
+ # Change to latex font
+ plt.rc("font",family="serif")
+ plt.rc("mathtext",fontset="cm")
+
+ def trim_data(self, data, ranges, model_points):
+ """
+ Takes input gridded data 'data' (grid points given by input 'model_points')
+ and trim this to lie within ranges.
+
+ Parameters:
+ -----------
+ data: ndarray
+ gridded data, shape must be compatible with model_points
+
+ ranges: list of lists of 2 floats
+ the min and max in each direction
+
+ model_points: list of list of floats
+
+ Returns:
+ --------
+ data trimmed to within ranges
+ """
+ if not (len(ranges)==len(model_points) and len(ranges) == len(data.shape)):
+ print('Check: i) data incompatible with ranges or ii) ranges incompatible with model_points. Skipping!')
+ return data
+ else:
+ mins = [i[0] for i in ranges]
+ maxs = [i[1] for i in ranges]
+ start_indices = Base.find_nearest_cell(mins, model_points)
+ end_indices = Base.find_nearest_cell(maxs, model_points)
+
+ IdxsToRemove = []
+ num_points = [len(model_points[i]) for i in range(len(model_points))]
+ for i in range(len(ranges)):
+ IdxsToRemove.append([ j for j in range(num_points[i]) if j < start_indices[i] or j > end_indices[i]])
+
+ newdata = np.delete(data, IdxsToRemove[0], axis=0)
+ for i in range(1, len(ranges)):
+ newdata = np.delete(newdata, IdxsToRemove[i], axis=i)
+
+ return newdata
+
+ def trim_dataset(self, list_of_data, ranges, model_points):
+ """
+ wrapper of trim data: check the shapes of the various arrays are compatible
+ Then trim each of them individually.
+
+ Parameters:
+ -----------
+ list_of_data: list of np.arrays (gridded data)
+ the dataset you want to trim
+
+ ranges: list of lists
+ the min and max in each direction
+
+ model_points: list of lists
+ the gridpoints, len of this must be compatible with the ranges
+
+ Returns:
+ --------
+ list of arrays trimmed within ranges
+ """
+ print('Trimming the dataset')
+
+ if len(ranges) != len(model_points):
+ print('Ranges incompatible with model_points. Exiting')
+ return None
+
+ ref_shape = list_of_data[0].shape
+ new_data = [list_of_data[0]]
+
+ for i in range(1, len(list_of_data)):
+ if list_of_data[i].shape == ref_shape:
+ new_data.append(list_of_data[i])
+ else:
+ print(f'The {i}th array in the dataset is not compatible with the first: ignoring it.')
+
+ if len(new_data) <=1:
+ print('No two variables in the dataset are compatible. Exiting.')
+ return None
+ else:
+ for i in range(len(new_data)):
+ new_data[i] = self.trim_data(new_data[i], ranges, model_points)
+ return new_data
+
+ def get_pos_or_neg_mask(self, pos_or_neg, array):
+ """
+ NOT USED ANYMORE!!!!!!
+
+ Function that return the mask that would be applied to an array in order to select
+ positive or negative values
+
+ Parameters:
+ -----------
+ pos_or_neg: can be int (0 or 1) or bool True or False
+
+ array: np.array
+
+ Return:
+ -------
+ mask: is True where values are masked!
+
+ Notes:
+ ------
+ To be combined with others before applying all together
+ """
+ if pos_or_neg:
+ mask = ma.masked_where(array<0, array, copy=True).mask
+ else:
+ mask = ma.masked_where(array>0, array, copy=True).mask
+
+ return mask
+
+ def restrict_data_range_mask(self, var, min=None, max=None):
+ """
+ Takes input var and make a copy of array masking those entries that are outside the (min, max) range
+ Return compressed masked array.
+ """
+ if min is None:
+ min = np.amin(var)
+ if max is None:
+ max = np.amax(var)
+
+ restricted_var = ma.masked_where(var < min, var, copy = True)
+ restricted_var = ma.masked_where(restricted_var > max, restricted_var, copy=True)
+ restricted_var = restricted_var.compressed()
+
+ return restricted_var
+
+ def get_mask_min_max(self, array, min=None, max=None):
+ """
+ Given an input 'array' and a list of 'value_ranges' to be considered, return
+ mask that would have to be applied to array to mask the entries outside the given
+ range
+
+ Parameters:
+ -----------
+ min, max: floats
+ the ranges to be considered
+
+ array: nd.array
+
+ Returns:
+ --------
+ Mask
+ """
+ if min is None:
+ min = -np.inf
+ if max is None:
+ max = np.inf
+
+ masked_array = ma.masked_where(array $',
+ 'T_tilde' : r'$\tilde{T}$',
+ 'u_tilde' : r'$\tilde{u}^a$',
+ 'D_u_tilde' : r'$\nabla_{a}\tilde{u}^b$',
+ 'D_T_tilde' : r'$\nabla_{a}\tilde{T}$',
+ 'D_n_tilde' : r'$\nabla_{a}\tilde{n}$',
+ 'D_eps_tilde' : r'$\nabla_{a}\tilde{\varepsilon}$',
+ 'n_tilde_dot' : r'$\dot{\tilde{n}}$',
+ 'T_tilde_dot' : r'$\dot{\tilde{T}}$',
+ 'sD_T_tilde': r'$D_{a}\tilde{T}$',
+ 'sD_n_tilde': r'$D_{a}\tilde{n}$',
+ 'shear_tilde' : r'$\tilde{\sigma}^{ab}$',
+ 'acc_tilde' : r'$\tilde{a}^a$',
+ 'exp_tilde' : r'$\tilde{\theta}$',
+ 'Theta_tilde' : r'$\tilde{\Theta}^a$',
+ 'eta' : r'$\eta$',
+ 'zeta' : r'$\zeta$',
+ 'kappa' : r'$\kappa$',
+ 'Pi_res_sq' : r'$\tilde{\Pi}^2$',
+ 'pi_res_sq' : r'$\tilde{\pi}_{ab}\tilde{\pi}^{ab}$',
+ 'shear_sq' : r'$\tilde{\sigma}_{ab}\tilde{\sigma}^{ab}$',
+ 'Theta_sq': r'$\tilde{\Theta}_a\tilde{\Theta}^a$',
+ 'q_res_sq': r'$\tilde{q}_a \tilde{q}^a$',
+ 'det_shear': r'$det(\sigma)$',
+ 'vort_sq' : r'$\omega_{ab}\omega^{ab}$',
+ 'acc_mag': r'$|a|$',
+ 'sD_n_tilde_sq' : r'$D_{a}\tilde{n}D^{a}\tilde{n}$',
+ 'dot_Dn_Theta' : r'$D_{a}\tilde{n}\Theta^{a}$',
+ 'Q1' : r'$\tilde{\sigma}_{ab}\tilde{\sigma}^{ab} - \tilde{\omega}_{ab}\tilde{\omega}^{ab}$',
+ 'Q2' : r'$\tilde{\sigma}_{ab}\tilde{\sigma}^{ab}/\tilde{\omega}_{ab}\tilde{\omega}^{ab}$',
+ 'weights' : r'$w$'}
+
+ def update_labels_dict(self, entry_dict):
+ """
+ pretty self-explanatory
+ """
+ self.labels_var_dict.update(entry_dict)
+
+ def set_find_obs(self, find_obs):
+ self.find_obs = find_obs
+
+ def set_filter(self, filter):
+ self.filter = filter
+
+ def get_all_var_strs(self):
+ return list(self.meso_vars.keys()) + list(self.deriv_vars.keys()) + list(self.meso_structures.keys()) + \
+ list(self.filter_vars.keys())
+
+ def get_gridpoints(self):
+ """
+ Pretty self-explanatory
+ """
+ return self.domain_vars['Points']
+
+ def get_interpol_var(self, var, point):
+ """
+ Returns the interpolated variables at the point.
+
+ Parameters
+ ----------
+ var: str corresponding to meso_structure, meso_vars or deriv_vars
+
+ point : list of floats
+ ordered coordinates: t,x,y
+
+ Return
+ ------
+ Interpolated values/arrays corresponding to variable.
+ Empty list if none of the variables is not meso_structures/meso_vars or deriv_vars of the model.
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+ if var in self.meso_structures:
+ return interpn(self.domain_vars['Points'], self.meso_structures[var], point, method = self.interp_method)[0]
+ elif var in self.meso_vars:
+ return interpn(self.domain_vars['Points'], self.meso_vars[var], point, method = self.interp_method)[0]
+ elif var in self.deriv_vars:
+ return interpn(self.domain_vars['Points'], self.deriv_vars[var], point, method = self.interp_method)[0]
+ elif var in self.filter_vars:
+ return interpn(self.domain_vars['Points'], self.filter_vars[var], point, method=self.interp_method)[0]
+ else:
+ print('Cannot interpolate value of {} using data fromfilter_vars meso_structures/meso_varsderiv_vars/filter_vars. Check!'.format(var))
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, h: object, i: object, j: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint
+ identified by h,i,j
+
+ Parameters:
+ -----------
+ var: string corresponding to structure, meso_vars or deriv_vars
+
+ h,i,j: int
+ integers corresponding to position on the grid.
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest
+ grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method is useful e.g. for plotting the raw data.
+ """
+ if var in self.meso_structures:
+ return self.meso_structures[var][h,i,j]
+ elif var in self.meso_vars:
+ return self.meso_vars[var][h,i,j]
+ elif var in self.deriv_vars:
+ return self.deriv_vars[var][h,i,j]
+ elif var in self.filter_vars:
+ return self.filter_vars[var][h,i,j]
+ else:
+ print(f'Cannot get value of {var} at h,i,j from data in meso_vars/meso_structures/deriv_vars/filter_vars')
+ return None
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, point: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint
+ closest to input 'point'.
+
+ Parameters:
+ -----------
+ vars: string corresponding to structure, meso_vars or deriv_vars
+
+ point: list of 2+1 floats
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest
+ grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method should be used in case using interpolated values becomes
+ too expensive.
+ """
+ indices = Base.find_nearest_cell(point, self.domain_vars['Points'])
+ if var in self.meso_structures:
+ return self.meso_structures[var][tuple(indices)]
+ elif var in self.meso_vars:
+ return self.meso_vars[var][tuple(indices)]
+ elif var in self.deriv_vars:
+ return self.deriv_vars[var][tuple(indices)]
+ elif var in self.filter_vars:
+ return self.filter_vars[var][tuple(indices)]
+ else:
+ print(f'Cannot get value of {var} at h,i,j from data in meso_vars/meso_structures/deriv_vars/filter_vars')
+ return None
+
+ def get_model_name(self):
+ return 'resHD2D'
+
+ def set_find_obs_method(self, find_obs):
+ self.find_obs = find_obs
+
+ def setup_meso_grid(self, patch_bdrs, coarse_factor = 1, coarse_time = False):
+ """
+ Builds the meso_model grid using the micro_model grid points contained in
+ the input patch (defined via 'patch_bdrs'). The method allows for coarse graining
+ the grid (both in space dirs only or also in time)
+ Then store the info about the meso grid and set up arrays of definite rank and size
+ for the quantities needed later.
+
+ Parameters:
+ -----------
+ patch_bdrs: list of lists of two floats,
+ [[tmin, tmax],[xmin,xmax],[ymin,ymax]]
+
+ coarse_factor: integer
+
+ coarse_time: boolean
+ If true, coarsening is also applied to the time direction.
+ Notes:
+ ------
+ If the patch_bdrs are larger than micro_grid, the method will not set-up the meso_grid,
+ and an error message is printed. This is extra safety measure!
+ """
+
+ # Is the patch within the micro_model domain?
+ conditions = patch_bdrs[0][0] < self.micro_model.domain_vars['tmin'] or \
+ patch_bdrs[0][1] > self.micro_model.domain_vars['tmax'] or \
+ patch_bdrs[1][0] < self.micro_model.domain_vars['xmin'] or \
+ patch_bdrs[1][1] > self.micro_model.domain_vars['xmax'] or \
+ patch_bdrs[2][0] < self.micro_model.domain_vars['ymin'] or \
+ patch_bdrs[2][1] > self.micro_model.domain_vars['ymax']
+
+ if conditions:
+ print('Error: the input region for filtering is larger than micro_model domain!')
+ return None
+
+ #Find the nearest cell to input patch bdrs
+ patch_min = [patch_bdrs[0][0], patch_bdrs[1][0], patch_bdrs[2][0]]
+ patch_max = [patch_bdrs[0][1], patch_bdrs[1][1], patch_bdrs[2][1]]
+ idx_mins = Base.find_nearest_cell(patch_min, self.micro_model.domain_vars['points'])
+ idx_maxs = Base.find_nearest_cell(patch_max, self.micro_model.domain_vars['points'])
+
+ # Set meso_grid spacings
+ self.domain_vars['Dt'] = self.micro_model.domain_vars['dt']
+ if coarse_time:
+ self.domain_vars['Dt'] = self.micro_model.domain_vars['dt'] * coarse_factor
+ else:
+ self.domain_vars['Dt'] = self.micro_model.domain_vars['dt']
+ self.domain_vars['Dx'] = self.micro_model.domain_vars['dx'] * coarse_factor
+ self.domain_vars['Dy'] = self.micro_model.domain_vars['dy'] * coarse_factor
+
+ # Building the meso_grid
+ h, i, j = idx_mins[0], idx_mins[1], idx_mins[2]
+ while h <= idx_maxs[0]:
+ t = self.micro_model.domain_vars['t'][h]
+ self.domain_vars['T'].append(t)
+ if coarse_time:
+ h += coarse_factor
+ else:
+ h += 1
+ while i <= idx_maxs[1]:
+ x = self.micro_model.domain_vars['x'][i]
+ self.domain_vars['X'].append(x)
+ i += coarse_factor
+ while j <= idx_maxs[2]:
+ y = self.micro_model.domain_vars['y'][j]
+ self.domain_vars['Y'].append(y)
+ j += coarse_factor
+
+ # Saving the info about the meso_grid
+ self.domain_vars['Points'] = [self.domain_vars['T'], self.domain_vars['X'], self.domain_vars['Y']]
+ self.domain_vars['Tmin'] = np.amin(self.domain_vars['T'])
+ self.domain_vars['Xmin'] = np.amin(self.domain_vars['X'])
+ self.domain_vars['Ymin'] = np.amin(self.domain_vars['Y'])
+ self.domain_vars['Tmax'] = np.amax(self.domain_vars['T'])
+ self.domain_vars['Xmax'] = np.amax(self.domain_vars['X'])
+ self.domain_vars['Ymax'] = np.amax(self.domain_vars['Y'])
+ self.domain_vars['Nt'] = len(self.domain_vars['T'])
+ self.domain_vars['Nx'] = len(self.domain_vars['X'])
+ self.domain_vars['Ny'] = len(self.domain_vars['Y'])
+
+ # Setup arrays for structures
+ Nt, Nx, Ny = self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny']
+ self.meso_structures['BC'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+ self.meso_structures['SET'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1, self.spatial_dims+1))
+
+ # Setup arrays for meso_vars
+ for str in self.meso_scalars_strs:
+ self.meso_vars[str] = np.zeros((Nt, Nx, Ny))
+ for str in self.meso_vectors_strs:
+ self.meso_vars[str] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+ for str in self.meso_r2tensors_strs:
+ self.meso_vars[str] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1, self.spatial_dims+1))
+
+ # Setup arrays for filter_vars
+ self.filter_vars['U'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+ self.filter_vars['U_errors'] = np.zeros((Nt, Nx, Ny))
+ self.filter_vars['U_success'] = dict()
+
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ self.filter_vars['U_success'].update({(h,i,j): False})
+
+ # Setup arrays for derivatives of the model.
+ self.deriv_vars['D_u_tilde'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1, self.spatial_dims+1))
+ self.deriv_vars['D_T_tilde'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+ self.deriv_vars['D_eps_tilde'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+ self.deriv_vars['D_n_tilde'] = np.zeros((Nt, Nx, Ny, self.spatial_dims+1))
+
+ def find_observers(self):
+ """
+ Method to compute filtering observers at grid points built with setup_meso_grid.
+ The observers found (and relative errors) are saved in the dictionary self.filter_vars.
+ Set up the entry self.filter_vars['U_success'] as a dictionary with (tuples of) indices
+ on the meso_grid as keys, and bool as values (true if the observer has been found, false otherwise)
+
+ Notes:
+ ------
+ Requires setup_meso_grid() to be called first.
+ """
+ for h, t in enumerate(self.domain_vars['T']):
+ for i, x in enumerate(self.domain_vars['X']):
+ for j, y in enumerate(self.domain_vars['Y']):
+ point = [t,x,y]
+ sol = self.find_obs.find_observer(point)
+ if sol[0]:
+ self.filter_vars['U'][h,i,j] = sol[1]
+ self.filter_vars['U_errors'][h,i,j] = sol[2]
+ self.filter_vars['U_success'].update({(h,i,j) : True})
+
+ if not sol[0]:
+ # self.filter_vars['U_success'].update({(h,i,j) : False})
+ # No need to update the dictionary as this has been initialized to False everywhere.
+ print('Careful: obs could not be found at: ', self.domain_vars['Points'][h][i][j])
+
+ def find_observers_parallel(self, n_cpus):
+ """
+ Method to find observers at all points on meso-grid, parallelized version.
+ The observers found (and relative errors) are saved in the dictionary self.filter_vars.
+ Set up the entry self.filter_vars['U_success'] as a dictionary with (tuples of) indices
+ on the meso_grid as keys, and bool as values (true if the observer has been found, false otherwise)
+
+ Parameters:
+ -----------
+
+ n_cpus: int
+ number of processes to run in parallel
+
+ Notes:
+ ------
+ This method relies on the routine find_obs.find_observers_parallel().
+ So meso_class must be constructed passing parallelized class for finding observers.
+ """
+ ts = self.domain_vars['T']
+ xs = self.domain_vars['X']
+ ys = self.domain_vars['Y']
+
+ t_idxs = np.arange(len(ts))
+ x_idxs = np.arange(len(xs))
+ y_idxs = np.arange(len(ys))
+
+ points = []
+ for elem in product(ts,xs,ys):
+ points.append(list(elem))
+
+ indices_meso_grid = []
+ for elem in product(t_idxs, x_idxs, y_idxs):
+ indices_meso_grid.append(elem)
+
+ successes, failures = self.find_obs.find_observers_parallel(points, n_cpus)
+
+ for i in range(len(successes[0])):
+ point_indxs_meso_grid = indices_meso_grid[successes[0][i]]
+ self.filter_vars['U'][point_indxs_meso_grid] = successes[1][i]
+ self.filter_vars['U_errors'][point_indxs_meso_grid] = successes[2][i]
+ self.filter_vars['U_success'].update({(point_indxs_meso_grid): True})
+
+ if len(failures)!=0:
+ print('Observers could not be found at the following points:\n')
+ for i in range(len(failures)):
+ failed_idxs_meso_grid = indices_meso_grid[failures[i]]
+ print('{}\n'.format(failed_idxs_meso_grid))
+
+ def filter_micro_variables(self):
+ """
+ Filter all meso_model structures AND micro pressure within the input ranges.
+ If no range is provided in one direction, routine will try and filter at all points
+ on the meso-grid. Note this would require the grid to be set up wisely so to avoid
+ problems at the boundaries.
+
+ This method relies on filter_var_point implemented separately for the filter, e.g. spatial_box_filter
+
+ Notes:
+ ------
+ Requires setup_meso_grid() to be called first.
+ Also find_observers() should be called first, although not doing so won't crash it.
+ """
+ for h, t in enumerate(self.domain_vars['T']):
+ for i, x in enumerate(self.domain_vars['X']):
+ for j, y in enumerate(self.domain_vars['Y']):
+ point = [t,x,y]
+ if self.filter_vars['U_success'][h,i,j]:
+ obs = self.filter_vars['U'][h,i,j]
+ for struct in self.meso_structures:
+ self.meso_structures[struct][h,i,j] = self.filter.filter_var_point(struct, point, obs)
+ self.meso_vars['p_filt'][h,i,j] = self.filter.filter_var_point('p', point, obs)
+ else:
+ print('Could not filter at {}: observer not found.'.format(point))
+
+ def filter_micro_vars_parallel(self, n_cpus):
+ """
+ Filter all meso_model structures AND micro pressure.
+ Routine will try and filter at all points on the meso-grid.
+ Note this would require the grid to be set up wisely so to avoid
+ problems at the boundaries.
+
+ This method relies on filter_vars_parallel implemented separately for the
+ filter class, e.g. as in box_filter_parallel
+
+ Parameters:
+ -----------
+
+ n_cpus: int
+ number of processes for parallelization
+
+ Notes:
+ ------
+ Requires setup_meso_grid() to be called first.
+ Also find_observers() should be called first, although not doing so won't crash it.
+ """
+ ts = self.domain_vars['T']
+ xs = self.domain_vars['X']
+ ys = self.domain_vars['Y']
+
+ t_idxs = np.arange(len(ts))
+ x_idxs = np.arange(len(xs))
+ y_idxs = np.arange(len(ys))
+
+ points = []
+ for elem in product(ts,xs,ys):
+ points.append(list(elem))
+
+ indices_meso_grid = []
+ for elem in product(t_idxs, x_idxs, y_idxs):
+ indices_meso_grid.append(elem)
+
+ observers = []
+ for elem in product(t_idxs, x_idxs, y_idxs):
+ if self.filter_vars['U_success'][elem]:
+ observers.append(self.filter_vars['U'][elem])
+ else:
+ print('Observers are not computed on (parts of) the grid!')
+ return None
+
+ vars = ['BC', 'SET', 'p']
+ points_observers = []
+ for i in range(len(points)):
+ # args_for_filtering_parallel.append([points[i], observers[i], vars])
+ points_observers.append([points[i], observers[i]])
+
+ # positions, filtered_vars = self.filter.filter_vars_parallel(args_for_filtering_parallel, n_cpus)
+ filtered_vars = dict.fromkeys(vars)
+ for var in vars:
+ positions, filtered_vars[var] = self.filter.filter_var_parallel(points_observers, var, n_cpus)
+
+ for i in range(len(positions)):
+ point_indxs_meso_grid = indices_meso_grid[positions[i]]
+ self.meso_structures['BC'][point_indxs_meso_grid] = filtered_vars['BC'][i]
+ self.meso_structures['SET'][point_indxs_meso_grid] = filtered_vars['SET'][i]
+ self.meso_vars['p_filt'][point_indxs_meso_grid] = filtered_vars['p'][i]
+ # self.meso_structures['BC'][point_indxs_meso_grid] = filtered_vars[i][0]
+ # self.meso_structures['SET'][point_indxs_meso_grid] = filtered_vars[i][1]
+ # self.meso_vars['p_filt'][point_indxs_meso_grid] = filtered_vars[i][2]
+
+ def p_from_EOS(self, eps, n):
+ """
+ Compute pressure from Gamma-law EoS
+ """
+ return (self.coefficients['Gamma']-1)*(eps-n)
+
+ def decompose_structures_gridpoint(self, h, i, j):
+ """
+ Decompose the fluid part of SET as well as Fab at grid point (h,i,j)
+
+ Parameters:
+ -----------
+ h, i, j: integers
+ the indices on the grid where the decomposition is performed.
+
+ Returns:
+ --------
+ None
+
+ Notes:
+ ------
+ Decomposition of BC, fluid SET and Faraday tensor. The EM part of SET is decomposed later
+ via non local operations (same story for the charge current).
+
+ """
+ # Computing the Favre density and velocity
+ n_t = np.sqrt(-Base.Mink_dot(self.meso_structures['BC'][h,i,j], self.meso_structures['BC'][h,i,j]))
+ u_t = np.multiply(1. / n_t, self.meso_structures['BC'][h,i,j])
+ T_ab = self.meso_structures['SET'][h,i,j,:,:] # Remember this is rank (2,0)
+
+ # Computing the decomposition at each point
+ eps_t = np.einsum('i,j,ik,jl,kl', u_t, u_t, self.metric, self.metric, T_ab)
+ h_ab = np.einsum('ij,jk->ik', self.metric + np.einsum('i,j->ij', u_t, u_t), self.metric) # This is a rank (1,1) tensor, i.e. a real projector.
+ q_a = np.einsum('ij,jk,kl,l->i',h_ab, T_ab, self.metric, u_t) # There might be missing a minus sign here?
+ s_ab = np.einsum('ij,kl,jl->ik',h_ab, h_ab, T_ab)
+ s = np.einsum('ii',s_ab)
+ p_t = self.p_from_EOS(eps_t, n_t)
+
+
+ # Storing the decomposition with appropriate names.
+ self.meso_vars['n_tilde'][h,i,j] = n_t
+ self.meso_vars['u_tilde'][h,i,j,:] = u_t
+ self.meso_vars['eps_tilde'][h,i,j] = eps_t
+ self.meso_vars['q_res'][h,i,j,:] = q_a
+ self.meso_vars['pi_res'][h,i,j,:,:] = s_ab - np.multiply(s / self.spatial_dims , self.metric +np.outer(u_t,u_t))
+ self.meso_vars['p_tilde'][h,i,j] = p_t
+ self.meso_vars['Pi_res'][h,i,j] = s - p_t
+ self.meso_vars['eos_res'][h,i,j] = self.meso_vars['p_filt'][h,i,j] - p_t
+ self.meso_vars['T_tilde'][h,i,j] = p_t / n_t
+
+ def decompose_structures(self):
+ """
+ Decompose structures at all points on the meso_grid where observers could be found.
+
+ Parameters:
+ -----------
+ t_range: list of two floats
+ ranges in the t-direction, used for selecting the sublist of points
+
+ x_range, y_range: similar to above.
+ """
+ for h, t in enumerate(self.domain_vars['T']):
+ for i, x in enumerate(self.domain_vars['X']):
+ for j, y in enumerate(self.domain_vars['Y']):
+ point = [t,y,x]
+ if self.filter_vars['U_success'][h,i,j]:
+ self.decompose_structures_gridpoint(h,i,j)
+ else:
+ print('Structures not decomposed at {}: observer could not be found.'.format(point))
+
+ @staticmethod
+ def p_Gamma_law(eps, n, Gamma):
+ """
+ staticmethod used by decompose_structures_task, that is the
+ parallel version decompose_structures_gridpoint
+
+ Parameters:
+ -----------
+ eps: float
+ the energy density of the fluid at a point
+
+ n: float
+ the baryon number density of the fluid at a point
+
+ Gamma: float
+ Gamma factor of the Gamma law
+ """
+ return (Gamma-1)* (eps-n)
+
+ @staticmethod
+ def decompose_structures_task(BC, SET , p_filt, h, i, j):
+ """
+ Task to be executed in parallel: decomposing the structures at a point
+
+ Parameters:
+ -----------
+
+ BC: np.array (3,)
+ the baryon current, rank: (1,0)
+
+ SET: np.array (3,3)
+ the Stress-Energy tensor, rank (2,0)
+
+ p_filt: float
+ the filtered pressure, scalar
+
+ h,i,j: integers
+ indices of the corresponding gridpoint on meso-grid
+
+ Returns:
+ --------
+ (list, list):
+ first list contains the decomposition of structures at point
+ second list contains indices of point on mesogrid
+ """
+ # As this is staticmethod, no access to self.metric
+ metric = np.zeros((3,3))
+ metric[0,0] = -1.
+ metric[1,1] = metric[2,2] = 1.
+ spatial_dims = 2.
+
+ # Computing the Favre density and velocity
+ n_t = np.sqrt(-Base.Mink_dot(BC, BC))
+ u_t = np.multiply(1./ n_t, BC)
+
+ # remember SET is a rank (2,0) tensor
+ # Computing the SET decomposition at each point
+ eps_t = np.einsum('i,j,ik,jl,kl', u_t, u_t, metric, metric, SET)
+ h_ab = np.einsum('ij,jk->ik', metric + np.einsum('i,j->ij', u_t, u_t), metric) # This is a rank (1,1) tensor, i.e. a real projector.
+ q_a = - np.einsum('ij,jk,kl,l->i', h_ab, SET, metric, u_t)
+ s_ab = np.einsum('ij,kl,jl->ik', h_ab, h_ab, SET)
+ s = np.einsum('ij,ji->', s_ab, metric)
+ # s = np.multiply(1/spatial_dims, s)
+ s_ab_tracefree = s_ab - np.multiply(s/3, metric + np.einsum('i,j->ij', u_t, u_t))
+
+ p_t = resHD2D.p_Gamma_law(eps_t, n_t, 4.0/3.0)
+ # rechange this: this was just to test the impact of EOS residuals onto the modelling of zeta
+ # Pi_res = s - p_t
+ Pi_res = s - p_filt
+ EOS_res = p_filt - p_t
+ T_t = p_t/n_t
+
+ return [n_t, u_t, eps_t, q_a, s_ab_tracefree, p_t, Pi_res, EOS_res, T_t], [h,i,j] #Uncomment if EoS residual is modelled
+ # return [n_t, u_t, eps_t, q_a, s_ab_tracefree, p_t, Pi_res, T_t], [h,i,j]
+
+ def decompose_structures_parallel(self, n_cpus):
+ """
+ Routine to decompose structures on the entire grid in
+ parallel.
+
+ Parameters:
+ -----------
+ n_cpus: int
+ numbers of processes for parallelization
+ """
+ # Preparing arguments for pool
+ args_for_pool=[]
+ for h in range(len(self.domain_vars['T'])):
+ for i in range(len(self.domain_vars['X'])):
+ for j in range(len(self.domain_vars['Y'])):
+ BC = self.meso_structures['BC'][h,i,j]
+ SET = self.meso_structures['SET'][h,i,j]
+ p_filt = self.meso_vars['p_filt'][h,i,j]
+ args_for_pool.append((BC, SET, p_filt, h,i,j))
+
+ with mp.Pool(processes=n_cpus) as pool:
+ print('Decomposing structures in parallel with {} processes'.format(pool._processes), flush=True)
+ for result in pool.starmap(resHD2D.decompose_structures_task, args_for_pool):
+ h,i,j = result[1]
+ self.meso_vars['n_tilde'][h,i,j] = result[0][0]
+ self.meso_vars['u_tilde'][h,i,j,:] = result[0][1]
+ self.meso_vars['eps_tilde'][h,i,j] = result[0][2]
+ self.meso_vars['q_res'][h,i,j,:] = result[0][3]
+ self.meso_vars['pi_res'][h,i,j,:,:] = result[0][4]
+ self.meso_vars['p_tilde'][h,i,j] = result[0][5]
+ self.meso_vars['Pi_res'][h,i,j] = result[0][6]
+ self.meso_vars['eos_res'][h,i,j] = result[0][7] #If EoS is not modelled you should adjust this!
+ self.meso_vars['T_tilde'][h,i,j] = result[0][8]
+
+ def calculate_derivatives_gridpoint(self, nonlocal_var_str, h, i, j, direction, order = 1):
+ """
+ Calculate partial derivative in the input 'direction' of the variable corresponding to 'nonlocal_var_str'
+ at the position on the grid identified by indices h,i,j. The order of the differencing scheme
+ can also be specified, default to 1.
+
+ Parameters:
+ -----------
+ nonlocal_var_str: string
+ quantity to be taken derivate of, must be in self.nonlocal_vars_strs()
+
+ h, i ,j: integers
+ indices for point on the meso_grid
+
+ direction: integer < self.spatial_dim + 1
+
+ order: integer, defatult to 1
+ order of the differencing scheme
+
+ Returns:
+ --------
+ Finite-differenced quantity at (h,i,j)
+
+ Notes:
+ ------
+ The method returns the value instead of storing it, so that these can be
+ rearranged as preferred later, that is in calculate_derivatives()
+ """
+
+ if direction > self.spatial_dims:
+ print('Directions are numbered from 0 up to {}'.format(self.spatial_dims))
+ return None
+
+ if order > len(self.differencing):
+ print('Maximum order implemented is {}: continuing with it.'.format(len(self.differencing)))
+ order = len(self.differencing)
+
+ # Forward, backward or centered differencing?
+ k = [h,i,j][direction]
+ N = len(self.domain_vars['Points'][direction])
+
+ if k in [l for l in range(order)]:
+ coefficients = self.differencing[order]['fw']['coefficients']
+ stencil = self.differencing[order]['fw']['stencil']
+ elif k in [N-1-l for l in range(order)]:
+ coefficients = self.differencing[order]['bw']['coefficients']
+ stencil = self.differencing[order]['bw']['stencil']
+ else:
+ coefficients = self.differencing[order]['cen']['coefficients']
+ stencil = self.differencing[order]['cen']['stencil']
+
+ temp = 0
+ for s, sample in enumerate(stencil):
+ idxs = [h,i,j]
+ idxs[direction] += sample
+ temp += np.multiply( coefficients[s] / self.domain_vars['Dx'], self.get_var_gridpoint(nonlocal_var_str, *idxs))
+ return temp
+
+ def calculate_derivatives(self):
+ """
+ Compute all the derivatives of the quantities corresponding to nonlocal_vars_strs, for all
+ gridpoints on the meso-grid.
+
+ Notes:
+ ------
+ The derived quantities are stored as 'tensors' as follows:
+ 1st three indices refer to the position on the grid
+
+ 4th index refers to the directionality of the derivative
+
+ last indices (1 or 2) correspond to the components of the quantity to be derived
+
+ The index corresponding to the derivative is covariant, i.e. down.
+
+ Example:
+
+ Fab [h,i,j,a,b] : h,i,j grid; a,b, spacetime components
+
+ D_Fab[h,i,j,c,a,b]: h,i,j grid; c direction of derivative; a,b as for Fab
+
+ """
+ for h, t in enumerate(self.domain_vars['T']):
+ for i, x in enumerate(self.domain_vars['X']):
+ for j, y in enumerate(self.domain_vars['Y']):
+ point = [t,y,x]
+ if self.filter_vars['U_success'][h,i,j]:
+ for dir in range(self.spatial_dims+1):
+ for str in self.nonlocal_vars_strs:
+ dstr = 'D_' + str
+ self.deriv_vars[dstr][h,i,j,dir] = self.calculate_derivatives_gridpoint(str, h, i, j, dir)
+ else:
+ print('Derivatives not calculated at {}: observer could not be found.'.format(point))
+
+ def closure_ingredients_gridpoint(self, h, i, j):
+ """
+ Decompose quantities obatined via non_local operations (i.e. derivatives) as needed
+ for the closure scheme. This is done at gridpoint (h,i,j) and then relevant values are
+ returned
+
+ Parameters:
+ -----------
+ h, i, j: integers
+ the indices of the gridpoint
+
+ Returns:
+ --------
+ list of strings: names of the quantities computed
+
+ list of nd.arrays with quantities computed
+
+ Notes:
+ ------
+ The ingredients for the closure scheme are model specific: it makes sense that the relevant
+ dictionary is set up not on construction.
+
+ UNDER CONSTRUCTION: THE EM PART NEEDS MORE THINKING
+
+ Rename: closure_ingredients_gridpoint() ??
+ Coefficients can be computed here directly, but more general models will require more work.
+ Do not split this, at least for now
+ """
+ # FAVRE_OBS
+ u_t = self.meso_vars['u_tilde'][h,i,j]
+ u_t_cov = np.einsum('ij,j->i', self.metric, u_t)
+
+ # CLOSURE INGREDIENTS: FAVRE OBS DERIVATIVE DECOMPOSITION - WORKING WITH (2,0)
+ nabla_u = self.deriv_vars['D_u_tilde'][h,i,j] # This is a rank (1,1) tensor
+ nabla_u = np.einsum('ij,jk->ik', self.metric, nabla_u) #this is a rank (2,0) tensor
+ acc_t = np.einsum('i,ij', u_t_cov, nabla_u) # vector
+
+ # The following two quantities should be identically zero, but they won't be due to numerical errors.
+ # Computing them and removing to project velocity gradients
+ unit_norm_violation = np.einsum('ij,j', nabla_u, u_t_cov) #vector
+ acc_orthogonality_violation = np.einsum('i,i->', u_t_cov, acc_t)
+ Daub = nabla_u + np.einsum('i,j->ij', u_t, acc_t) + np.einsum('i,j->ij', unit_norm_violation, u_t) +\
+ np.multiply(acc_orthogonality_violation, np.einsum('i,j->ij', u_t, u_t)) #Should be a (2,0) tensor
+ h_ab = self.metric + np.einsum('i,j->ij', u_t, u_t)
+ exp_t = np.einsum('ii->',Daub)
+ shear_t = np.multiply(1/2., Daub + np.einsum('ij->ji', Daub)) - np.multiply( 1/self.spatial_dims * exp_t, h_ab)
+ vort_t = np.multiply(1/2., Daub - np.einsum('ij->ji', Daub))
+
+
+ # CLOSURE INGREDIENTS: HEAT FLUX
+ nabla_T = self.deriv_vars['D_T_tilde'][h,i,j]
+ projector = np.zeros((3,3))
+ np.fill_diagonal(projector, 1)
+ projector += np.einsum('i,j->ij',u_t_cov, u_t)
+ DaT = np.einsum('ij,j->i', projector, nabla_T)
+ Theta_tilde = DaT + np.multiply(self.meso_vars['T_tilde'][h,i,j], np.einsum('ij,j->i', self.metric, acc_t))
+
+ closure_vars_strs = ['shear_tilde', 'exp_tilde', 'acc_tilde', 'Theta_tilde']
+ closure_vars = [shear_t, exp_t, acc_t, Theta_tilde]
+ return closure_vars_strs, closure_vars
+
+ def closure_ingredients(self):
+ """
+ Wrapper of the corresponding gridpoint method.
+ Set up the dictionary for the closure variables not yet defined.
+ Loop over the grid and store the decomposed variables.
+ """
+ Nt, Nx, Ny = self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny']
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ if self.filter_vars['U_success'][h,i,j]:
+ keys, values = self.closure_ingredients_gridpoint(h,i,j)
+ # try-except block to extend the meso_vars dictionary
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key))
+ shape = values[idx].shape
+ self.meso_vars.update({key: np.zeros(([Nt, Nx, Ny] + list(shape)))})
+ finally:
+ self.meso_vars[key][h,i,j] = values[idx]
+
+ @staticmethod
+ def closure_ingredients_task(u_t, nabla_u, T_t, nabla_T, nabla_n, h, i, j):
+ """
+ Task to decompose Favre obs + Temperature derivatives
+ These will be used in EL_style_closure to extract the
+ turbulent effective dissipative coefficients
+
+ Parameters:
+ -----------
+ u_t: np.array (3,)
+ the Favre-observer, rank: (1,0)
+
+ nabla_u: np.array(3,3)
+ derivatives of Favre observer, rank: (1,1)
+
+ T_t: float
+ The temperature from filtered EoS
+
+ nabla_T: np.array (3,0)
+ Temperature derivatives, rank: (0,1)
+
+ h,i,j: integers
+ the indices of point on meso-grid
+
+ Returns:
+ --------
+ (list, list, list):
+ first list contains the strings of the returned quantities
+ (needed as the meso-vars dictionary is extended appropriately)
+
+ second list contains the corresponding np.arrays
+
+ third list contains the indices on meso-grid
+ """
+ # building blocks: this task is static so no access to self
+ spatial_dims = 2.
+ metric = np.zeros((3,3))
+ metric[0,0] = -1
+ metric[1,1] = metric[2,2] = 1
+
+ # CLOSURE INGREDIENTS: FAVRE OBS DERIVATIVE DECOMPOSITION - WORKING WITH (2,0)
+ # The decomposition below is exact if certain algebraic constraints are satisfied, which they won't be
+ # due to numerical errors.
+ # However, it appears the only quantity to be corrected is the acceleration
+ u_t_cov = np.einsum('ij,j->i', metric, u_t)
+ nabla_u = np.einsum('ij,jk->ik', metric, nabla_u) #this is a rank (2,0) tensor
+ acc_t = np.einsum('i,ij', u_t_cov, nabla_u) # vector
+
+ acc_orthogonality_violation = np.einsum('i,i->', u_t_cov, acc_t)
+ acc_t = acc_t + acc_orthogonality_violation * u_t
+
+ projector = np.zeros((3,3))
+ np.fill_diagonal(projector, 1)
+ projector += np.einsum('i,j->ij',u_t, u_t_cov)
+ h_ab = metric + np.einsum('i,j->ij', u_t, u_t) #Rank (2,0) tensor
+
+ Daub = np.einsum('ij,kl,jl->ik', projector, projector, nabla_u)
+ exp_t = np.einsum('ij,ji->', Daub, metric)
+ shear_t = np.multiply(1/2., Daub + np.einsum('ij->ji', Daub)) - np.multiply( exp_t/ spatial_dims, h_ab)
+ vort_t = np.multiply(1/2., Daub - np.einsum('ij->ji', Daub))
+
+ # #The following should be used if the violation of the algebraic constraints become too large
+ # Daub = np.einsum('ij,kl,jl->ik', projector, projector, nabla_u)
+ # orthogonality_violation_1 = np.einsum('i,ij->j', u_t_cov, Daub)
+ # orthogonality_violation_2 = np.einsum('ij,j->i', Daub, u_t_cov)
+ # orthogonality_violation_3 = np.einsum('i,j,ij->', u_t_cov, u_t_cov, Daub)
+ # Daub = Daub + np.einsum('i,j->ij', u_t, orthogonality_violation_1) + np.einsum('i,j->ij', orthogonality_violation_2, u_t) + \
+ # np.multiply(orthogonality_violation_3, np.einsum('i,j->ij', u_t, u_t) )
+ # exp_t = np.einsum('ij,ji->', Daub, metric)
+ # shear_t = np.multiply(1/2., Daub + np.einsum('ij->ji', Daub)) - np.multiply( exp_t/ spatial_dims, h_ab)
+ # vort_t = np.multiply(1/2., Daub - np.einsum('ij->ji', Daub))
+
+
+ # CLOSURE INGREDIENTS: DERIVATIVES OF N_TILDE AND T_TILDE
+ projector = np.zeros((3,3))
+ np.fill_diagonal(projector, 1)
+ projector += np.einsum('i,j->ij',u_t_cov, u_t) #This is different from the projector above: look at indices!
+
+ sD_n_tilde = np.einsum('ij,j->i', projector, nabla_n)
+ sD_T_tilde = np.einsum('ij,j->i', projector, nabla_T)
+
+ n_tilde_dot = np.einsum('i,i->', u_t, nabla_n)
+ T_tilde_dot = np.einsum('i,i->', u_t, nabla_T)
+
+ Theta_t = sD_T_tilde + np.multiply(T_t, np.einsum('ij,j->i', metric, acc_t))
+
+ closure_vars_strs = ['shear_tilde', 'exp_tilde', 'acc_tilde', 'vort_tilde','Theta_tilde', 'n_tilde_dot', \
+ 'T_tilde_dot', 'sD_n_tilde', 'sD_T_tilde' ]
+ closure_vars = [shear_t, exp_t, acc_t, vort_t, Theta_t, n_tilde_dot, T_tilde_dot, sD_n_tilde, sD_T_tilde]
+ return closure_vars_strs, closure_vars, [h,i,j]
+
+ def closure_ingredients_parallel(self, n_cpus):
+ """
+ Routine to compute and store the closure ingredients at all gridpoints in parallel
+
+ Parameters:
+ -----------
+ n_cpus: int
+ number of processes for parallelization
+
+ Notes:
+ ------
+ worth thinking about merging this with decompose structures?
+ """
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ args_for_pool = []
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ u_t = self.meso_vars['u_tilde'][h,i,j]
+ nabla_u = self.deriv_vars['D_u_tilde'][h,i,j]
+ T_t = self.meso_vars['T_tilde'][h,i,j]
+ nabla_T = self.deriv_vars['D_T_tilde'][h,i,j]
+ nabla_n = self.deriv_vars['D_n_tilde'][h,i,j]
+ args_for_pool.append((u_t, nabla_u, T_t, nabla_T, nabla_n, h, i, j))
+
+ with mp.Pool(processes=n_cpus) as pool:
+ print('Computing closure ingredients with {} processes'.format(pool._processes), flush=True)
+ for result in pool.starmap(resHD2D.closure_ingredients_task, args_for_pool):
+ keys, values, grid_idxs = result
+ # if self.filter_vars['U_success'][tuple(grid_idxs)]: #this check is in practice always True
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key), flush=True)
+ shape = values[idx].shape
+ self.meso_vars.update({key : np.zeros(([Nt,Nx,Ny]+ list(shape)))})
+ finally:
+ self.meso_vars[key][tuple(grid_idxs)] = values[idx]
+
+ def EL_style_closure_gridpoint(self, h, i, j):
+ """
+ Compute bulk, shear via scalarization + PA trick, thermal conductivity later.
+ At a point.
+ Returns: coefficient(s) at a point.
+ """
+ coefficients_names=[]
+ coefficients=[]
+
+ # CALCULATING BULK VISCOUS COEFF
+ zeta = self.meso_vars['Pi_res'][h,i,j] / self.meso_vars['exp_tilde'][h,i,j]
+ coefficients_names.append('zeta')
+ coefficients.append(zeta)
+
+ # CALCULATING SHEAR VISCOUS COEFF
+ pi_res_sq = np.einsum('ij,kl,ik,jl->', self.meso_vars['pi_res'][h,i,j], self.meso_vars['pi_res'][h,i,j], self.metric, self.metric)
+ shear_sq = np.einsum('ij,kl,ik,jl->', self.meso_vars['shear_tilde'][h,i,j], self.meso_vars['shear_tilde'][h,i,j], self.metric, self.metric)
+ eta = pi_res_sq/shear_sq
+ # Compute sign of eta by looking at the PA of pi_res with higher eigenvalue.
+ # Change shear to the eigenbasis of pi_res (using that the matrix is unitary as pi_res is sym)
+ pi_eig, pi_eigv = np.linalg.eigh(self.meso_vars['pi_res'][h,i,j])
+ transformed_shear = np.einsum('ji,jk,kl', pi_eigv, self.meso_vars['shear_tilde'][h,i,j], pi_eigv)
+ abs_pi_eig = np.abs(pi_eig)
+ pos = list(abs_pi_eig).index(np.max(abs_pi_eig))
+ eta = eta * np.sign(pi_eig[pos] / transformed_shear[pos,pos])
+ coefficients_names.append('eta')
+ coefficients.append(eta)
+
+ # CALCULATING THE HEAT CONDUCTIVITIY
+ q_res = self.meso_vars['q_res'][h,i,j]
+ Theta_t = self.meso_vars['Theta_tilde'][h,i,j]
+ q_res_sq = np.einsum('i,ij,j', q_res, self.metric, q_res)
+ Theta_t_sq = np.einsum('i,ij,j', Theta_t, self.metric, Theta_t)
+ cos_angle = np.einsum('i,ij,j', q_res, self.metric, Theta_t) / (q_res_sq * Theta_t_sq)
+ sign = np.sign(cos_angle)
+ kappa = sign * np.sqrt(q_res_sq / Theta_t_sq)
+ coefficients_names.append('kappa')
+ coefficients.append(kappa)
+
+ return coefficients_names, coefficients
+
+ def EL_style_closure(self):
+ """
+ Wrapper of EL_style_closure_gridpoint()
+ """
+ Nt, Nx, Ny = self.domain_vars['Nt'], self.domain_vars['Nx'], self.domain_vars['Ny']
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ if self.filter_vars['U_success'][h,i,j]:
+ keys, values = self.EL_style_closure_gridpoint(h,i,j)
+ # try-except block to extend the meso_vars dictionary with the dissipative coefficients
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key))
+ shape = values[idx].shape
+ self.meso_vars.update({key: np.zeros(([Nt, Nx, Ny] + list(shape)))})
+ finally:
+ self.meso_vars[key][h,i,j] = values[idx]
+
+ @staticmethod
+ def EL_style_closure_task(Pi_res, exp, pi_res, shear, q_res, Theta, h, i, j):
+ """
+ Task for computing the effective dissipative coefficients at all gridpoint
+ in parallel
+
+ Parameters:
+ -----------
+ Pi_res: float
+ Pressure residual using meso EoS
+
+ exp: float
+ the Favre expansion rate
+
+ pi_res: np.array (3,3)
+ the residual anisotropic stresses (should be trace-free)
+
+ shear: np.array (3,3)
+ the shear matrix computed from Favre obs derivatives
+
+ q_res: np.array (3,)
+ the residual heat-flux
+
+ Theta: np.array (3,)
+ the temperature spatial gradients with acceleration term
+
+ h,i,j: integers
+ grid indixes corresponding to point on grid
+
+ Return:
+ -------
+ (coeff names, coeff, [h,i,j])
+
+ """
+ coefficients_names=[]
+ coefficients=[]
+
+ metric = np.zeros((3,3))
+ metric[0,0] = -1
+ metric[1,1] = metric[2,2] = +1
+
+ # CALCULATING BULK VISCOUS COEFF
+ zeta = - Pi_res / exp
+ coefficients_names.append('zeta')
+ coefficients.append(zeta)
+
+ # CALCULATING SHEAR VISCOUS COEFF
+ pi_res_sq = np.einsum('ij,kl,ik,jl->', pi_res, pi_res, metric, metric)
+ shear_sq = np.einsum('ij,kl,ik,jl->', shear, shear, metric, metric)
+ eta = np.sqrt(pi_res_sq/shear_sq)
+ # Compute sign of eta by looking at the PA of pi_res with higher eigenvalue.
+ # Change shear to the eigenbasis of pi_res (using that the matrix is unitary as pi_res is sym)
+ pi_eig, pi_eigv = np.linalg.eigh(pi_res)
+ transformed_shear = np.einsum('ji,jk,kl', pi_eigv, shear, pi_eigv)
+ abs_pi_eig = np.abs(pi_eig)
+ pos = list(abs_pi_eig).index(np.max(abs_pi_eig))
+ eta = eta * np.sign( - pi_eig[pos] / transformed_shear[pos,pos])
+ coefficients_names.append('eta')
+ coefficients.append(eta)
+
+ # CALCULATING THE HEAT CONDUCTIVITIY
+ q_res_sq = np.einsum('i,ij,j', q_res, metric, q_res)
+ Theta_sq = np.einsum('i,ij,j', Theta, metric, Theta)
+ cos_angle = np.einsum('i,ij,j', q_res, metric, Theta) / (q_res_sq * Theta_sq)
+ sign = - np.sign(cos_angle)
+ kappa = sign * np.sqrt(q_res_sq / Theta_sq)
+ coefficients_names.append('kappa')
+ coefficients.append(kappa)
+
+
+ return coefficients_names, coefficients, [h,i,j]
+
+ def EL_style_closure_parallel(self, n_cpus):
+ """
+ Routine to launch EL_style_closure_task in parallel across multiple gridpoints
+
+ Parameters:
+ -----------
+ n_cpus: int
+ number of processes for parallelization
+
+ Notes:
+ ------
+ worth thinking about merging this with decompose_structures_task and closure_ingredients_task?
+ could compute just u_t at all points, so to be able to take derivatives of it
+ Then since you're accesing a single point, you could decompose, compute ingredients and extract coeff
+ in one go. Might give you a speed up: the loop for preparning arguments for pool is done once
+ and not twice/thrice, and the processes are opened/closed half the times.
+ """
+ args_for_pool=[]
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ Pi_res = self.meso_vars['Pi_res'][h,i,j]
+ pi_res = self.meso_vars['pi_res'][h,i,j]
+ q_res = self.meso_vars['q_res'][h,i,j]
+ exp_t = self.meso_vars['exp_tilde'][h,i,j]
+ shear_t = self.meso_vars['shear_tilde'][h,i,j]
+ Theta_t = self.meso_vars['Theta_tilde'][h,i,j]
+
+ args_for_pool.append((Pi_res, exp_t, pi_res, shear_t, q_res, Theta_t, h,i,j))
+
+
+ with mp.Pool(processes=n_cpus) as pool:
+ print('Computing dissipative coefficients with {} processes'.format(pool._processes), flush=True)
+ for result in pool.starmap(resHD2D.EL_style_closure_task, args_for_pool):
+ keys, values, grid_idxs = result
+ # if self.filter_vars['U_success'][tuple(grid_idxs)]: #this check is in practice always True
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key), flush=True)
+ shape = values[idx].shape
+ self.meso_vars.update({key : np.zeros(([Nt,Nx,Ny]+ list(shape)))})
+ finally:
+ self.meso_vars[key][tuple(grid_idxs)] = values[idx]
+
+ @staticmethod
+ def EL_componentwise_task(pi_res, shear, h, i, j):
+ """
+ Task for computing the shear coefficients componentwise
+
+ Parameters:
+ -----------
+ pi_res: nd.array
+ the anisotropic stress residual at gridpoint h,i,j
+
+ shear: nd.array
+ the (Favre-observer) shear tensor at gridpoint h,i,j
+
+ Returns:
+ --------
+ list of strs:
+ the names by which you want to store data in the class instance
+
+ nd.array:
+ the componentwise values of the coefficient, for now eta only
+
+ list:
+ the gridpoint indices on the meso-grid
+
+ Notes:
+ ------
+ """
+ eta_componentwise = np.zeros(pi_res.shape)
+ eta_componentwise = - np.divide(pi_res, shear)
+ coeff_name = 'eta_cw'
+
+ return [coeff_name], [eta_componentwise], [h, i, j]
+
+ def EL_componentwise_parallel(self, n_cpus, store=False):
+ """
+ Wrapper of EL_componentwise_task: launch the task in parallel with n_cpus
+
+ Parameters:
+ -----------
+ n_cpus: int
+ number of processes for parallelization
+
+ store: bool
+ If true, the meso_vars dictionary is extended to include these
+ Otherwise, the dictionary is created and returned
+ """
+ args_for_pool=[]
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ printshit = self.meso_vars['shear_tilde'].shape
+ print(f'shear_tilde.shape: {printshit}')
+ printshit = self.meso_vars['pi_res'].shape
+ print(f'pi_res.shape: {printshit}')
+
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ shear_t = self.meso_vars['shear_tilde'][h,i,j]
+ pi_res = self.meso_vars['pi_res'][h,i,j]
+
+ args_for_pool.append((pi_res, shear_t, h, i, j))
+
+ with mp.Pool(processes=n_cpus) as pool:
+ print('Computing vars for modelling coefficients with {} processes'.format(pool._processes), flush=True)
+
+ for result in pool.starmap(resHD2D.EL_componentwise_task, args_for_pool):
+ keys, values, grid_idxs = result
+
+ if store:
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key), flush=True)
+ try:
+ shape = values[idx].shape
+ except AttributeError:
+ shape = []
+ self.meso_vars.update({key : np.zeros(([Nt,Nx,Ny]+ list(shape)))})
+ finally:
+ self.meso_vars[key][tuple(grid_idxs)] = values[idx]
+
+ else:
+ for i, key in enumerate(keys):
+ try:
+ results_dictionary[key]
+ except UnboundLocalError:
+ results_dictionary = dict.fromkeys([key])
+ shape = values[i].shape
+ results_dictionary[key] = np.zeros(([Nt, Nx, Ny] + list(shape)))
+ except KeyError:
+ shape = values[i].shape
+ results_dictionary.update( {key : np.zeros(([Nt, Nx, Ny] + list(shape)))} )
+
+ finally:
+ results_dictionary[key][tuple(grid_idxs)] = values[i]
+
+ if not store:
+ return results_dictionary
+
+ @staticmethod
+ def modelling_coefficients_task(shear, vort, acc, Theta, sD_n_tilde, Pi_res, pi_res, q_res, h, i, j):
+ """
+ Task (to be used in parallel) to compute various quantities that will be used later
+ for modelling the extracted closure coefficients.
+ """
+ var_names = []
+ vars = []
+
+ metric = np.zeros((3,3))
+ metric[0,0] = -1
+ metric[1,1] = metric[2,2] = +1
+
+ # Computing various invariants of the velocity gradients
+
+ # This is required as the determinant is an invariant (does not change under coordinates changes)
+ # only when the tensor is written as a rank (1,1)
+ shear_rank11 = np.einsum('ij,jk->ik', shear, metric)
+ det_shear = det(shear_rank11)
+ var_names.append('det_shear')
+ vars.append(det_shear)
+
+ shear_sq = np.einsum('ij,kl,ik,jl->', shear, shear, metric, metric)
+ var_names.append('shear_sq')
+ vars.append(shear_sq)
+
+ vort_sq = np.einsum('ij,kl,ik,jl->', vort, vort, metric, metric)
+ var_names.append('vort_sq')
+ vars.append(vort_sq)
+
+ acc_mag = np.sqrt(np.einsum('i,ij,j->', acc, metric, acc))
+ var_names.append('acc_mag')
+ vars.append(acc_mag)
+
+ # Computing quantities related to the Q-criterion
+ Q1 = shear_sq - vort_sq
+ var_names.append('Q1')
+ vars.append(Q1)
+
+ Q2 = shear_sq/vort_sq
+ var_names.append('Q2')
+ vars.append(Q2)
+
+ # Computing scalars out of thermo gradients
+ Theta_sq = np.einsum('i,ij,j', Theta, metric, Theta)
+ var_names.append('Theta_sq')
+ vars.append(Theta_sq)
+
+ sD_n_tilde_sq = np.einsum('i,ij,j->', sD_n_tilde, metric, sD_n_tilde)
+ var_names.append('sD_n_tilde_sq')
+ vars.append(sD_n_tilde_sq)
+
+ dot_Dn_Theta = np.einsum('i,ij,j->', sD_n_tilde, metric, Theta )
+ var_names.append('dot_Dn_Theta')
+ vars.append(dot_Dn_Theta)
+
+ # Computing squares of residuals and also of Theta_tilde
+ Pi_res_sq = Pi_res * Pi_res
+ var_names.append('Pi_res_sq')
+ vars.append(Pi_res_sq)
+
+ pi_res_sq = np.einsum('ij,kl,ik,jl->', pi_res, pi_res, metric, metric)
+ var_names.append('pi_res_sq')
+ vars.append(pi_res_sq)
+
+ q_res_sq = np.einsum('i,ij,j', q_res, metric, q_res)
+ var_names.append('q_res_sq')
+ vars.append(q_res_sq)
+
+ return var_names, vars, [h,i,j]
+
+ def modelling_coefficients_parallel(self, n_cpus):
+ """
+ Routine to parallelize the task 'Computing_calibration_vars_task'
+ """
+ args_for_pool=[]
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ shear_t = self.meso_vars['shear_tilde'][h,i,j]
+ vort_t = self.meso_vars['vort_tilde'][h,i,j]
+ acc_t = self.meso_vars['acc_tilde'][h,i,j]
+ Theta_t = self.meso_vars['Theta_tilde'][h,i,j]
+ sD_n_tilde = self.meso_vars['sD_n_tilde'][h,i,j]
+ Pi_res = self.meso_vars['Pi_res'][h,i,j]
+ pi_res = self.meso_vars['pi_res'][h,i,j]
+ q_res = self.meso_vars['q_res'][h,i,j]
+
+ args_for_pool.append((shear_t, vort_t, acc_t, Theta_t, sD_n_tilde, Pi_res, pi_res, q_res, h, i, j))
+
+ with mp.Pool(processes=n_cpus) as pool:
+ print('Computing vars for modelling coefficients with {} processes'.format(pool._processes), flush=True)
+
+ for result in pool.starmap(resHD2D.modelling_coefficients_task, args_for_pool):
+ keys, values, grid_idxs = result
+
+ for idx, key in enumerate(keys):
+ try:
+ self.meso_vars[key]
+ except KeyError:
+ print('The key {} does not belong to meso_vars yet, adding it!'.format(key), flush=True)
+ try:
+ shape = values[idx].shape
+ except AttributeError:
+ shape = []
+ self.meso_vars.update({key : np.zeros(([Nt,Nx,Ny]+ list(shape)))})
+ finally:
+ self.meso_vars[key][tuple(grid_idxs)] = values[idx]
+
+ def weights_Q1_skew(self):
+ """
+ Build weights for gridpoints: downplay points where shear is small, but take into
+ account both positive and negative values of Q1
+ """
+ # def symlog(array):
+ # return np.sign(array) * np.log10(np.abs(array)+1)
+
+ Q1 = self.meso_vars['Q1']
+ symlog_Q1 = MySymLogPlotting.symlog_var(Q1)
+
+ M_pos = np.amax(symlog_Q1)
+ m_neg = np.amin(symlog_Q1)
+
+ symlog_Q1_pos = np.ma.masked_where(symlog_Q1 < 0, symlog_Q1, copy=True).compressed()
+ symlog_Q1_neg = np.ma.masked_where(symlog_Q1 > 0, symlog_Q1, copy=True).compressed()
+ M_neg = np.amax(symlog_Q1_neg)
+ m_pos = np.amin(symlog_Q1_pos)
+
+ c_pos = (M_pos + m_pos)/2.
+ c_neg = (M_neg + m_neg)/2.
+
+ def get_weights(x, c_pos, c_neg):
+ if x >= 0:
+ result = (np.tanh(x-c_pos)+1)/2
+ else:
+ result = (-np.tanh(x-c_neg)+1)/2
+ return (result+1.)/2.
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ weights = np.zeros((Nt, Nx, Ny))
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ weights[h,i,j] = get_weights(symlog_Q1[h,i,j], c_pos, c_neg)
+
+ self.meso_vars.update({'weights' : weights})
+
+ def weights_Q1_non_neg(self):
+ """
+ Build weights for gridpoints: downplay points where Q1 is negative
+ """
+ # def symlog(array):
+ # return np.sign(array) * np.log10(np.abs(array)+1)
+
+ Q1 = self.meso_vars['Q1']
+ symlog_Q1 = MySymLogPlotting.symlog_var(Q1)
+ symlog_Q1_pos = np.ma.masked_where(symlog_Q1 < 0, symlog_Q1, copy=True).compressed()
+ symlog_Q1_neg = np.ma.masked_where(symlog_Q1 > 0, symlog_Q1, copy=True).compressed()
+
+ M_pos = np.amax(symlog_Q1_pos)
+ m_pos = np.amin(symlog_Q1_pos)
+ M_neg = np.amax(symlog_Q1_neg)
+ m_neg = np.amin(symlog_Q1_neg)
+
+ c = (M_pos + m_neg)/2.
+ a_pos = (M_pos + m_pos)/2.
+ a_neg = np.abs(M_neg + m_neg)/2.
+ a = (a_pos + a_neg)/2.
+
+ def get_weights(x, c, a):
+ result = np.tanh((x-c)/a)
+ return (result+1.)/2.
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ weights = np.zeros((Nt, Nx, Ny))
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ weights[h,i,j] = get_weights(symlog_Q1[h,i,j], c, a)
+
+ self.meso_vars.update({'weights' : weights})
+
+ def weights_Q2(self):
+ """
+ Build weights for gridpoints based on Q2
+ """
+ Q2 = np.log10(self.meso_vars['Q2'])
+
+ M = np.amax(Q2)
+ m = np.amin(Q2)
+ scale = (M+m)/2
+
+ def get_weights(x, scale):
+ result = np.tanh(x/scale)
+ result = (result +1)/2
+ return result
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ weights = np.zeros((Nt, Nx, Ny))
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ weights[h,i,j] = get_weights(Q2[h,i,j], scale)
+
+ self.meso_vars.update({'weights' : weights})
+
+ def residual_weights(self, residual_str):
+ """
+ Build weights based on residual corresponding to input 'residual_str'.
+ Downplay points where this is small, that is those points where a closure is less required!
+ """
+
+ residual = np.log10(self.meso_vars[residual_str])
+
+ M = np.amax(residual)
+ m = np.amin(residual)
+ scale = (M+m)/2
+
+ def get_weights(x, scale):
+ result = np.tanh(x/scale)
+ result = (result +1)/2
+ return result
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ weights = np.zeros((Nt, Nx, Ny))
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ weights[h,i,j] = get_weights(residual[h,i,j], scale)
+
+ self.meso_vars.update({'weights' : weights})
+
+ def denominator_weights(self, coeff_denominator_str):
+ """
+ Build weights based on quantity corresponding to 'coeff_denominator_str'.
+ Downplay points where this is small, that is points where the extracted coefficient are less
+ trustworthy
+ """
+
+ denominator = np.log10(self.meso_vars[coeff_denominator_str])
+
+ M = np.amax(denominator)
+ m = np.amin(denominator)
+ scale = (M+m)/2
+
+ def get_weights(x, scale):
+ result = np.tanh(x/scale)
+ result = (result +1)/2
+ return result
+
+ Nt = self.domain_vars['Nt']
+ Nx = self.domain_vars['Nx']
+ Ny = self.domain_vars['Ny']
+
+ weights = np.zeros((Nt, Nx, Ny))
+ for h in range(Nt):
+ for i in range(Nx):
+ for j in range(Ny):
+ weights[h,i,j] = get_weights(denominator[h,i,j], scale)
+
+ self.meso_vars.update({'weights' : weights})
+
+ def EL_style_closure_regression(self, CoefficientAnalysis):
+ """
+ Takes in a list of correlation quantities (strings? The regressors needed are computed
+ previously via closure ingredients)
+ Pass the dataset to a CoefficientAnalysis instance.
+ Plot the correlations with the regressors and perform the regression using methods from a Coefficient
+ Analysis instance.
+ """
+ # FICTITIOUS RANGES AND POINTS TO TEST TRIM_DATA ROUTINE
+ ranges = [[self.domain_vars['Tmin'], self.domain_vars['Tmax']],\
+ [self.domain_vars['Xmin'], self.domain_vars['Xmax']],\
+ [self.domain_vars['Ymin'], self.domain_vars['Ymax']]]
+ points = self.domain_vars['Points']
+
+ # TESTING SCALAR REGRESSION ROUTINE
+ # y = self.meso_vars['zeta']
+ # X = [self.meso_vars['eps_tilde'], self.meso_vars['n_tilde']]
+ # stats_result = CoefficientAnalysis.scalar_regression(y, X, ranges, points)
+ # print(*stats_result)
+
+ # TESTING TENSOR REGRESSION ROUTINE
+ # y=self.meso_vars['q_res']
+ # X=[self.meso_vars['e_tilde'], self.meso_vars['u_tilde']]
+ # # stats_result = CoefficientAnalysis.tensor_components_regression(y, X, 2,ranges, points, components=[(0,),(2,)])
+ # stats_result = CoefficientAnalysis.tensor_components_regression(y, X, 2,ranges, points, add_intercept=False)
+ # for i in range(len(stats_result)):
+ # print('{}-th component: \n {} \n\n'.format(i, stats_result[i]))
+
+ # TESTING CORRELATION VISUALIZATION ROUTINES
+ # x = self.meso_vars['n_tilde']
+ # y = self.meso_vars['eps_tilde']
+ # labels = ['n_tilde','eps_tilde']
+ # g1=CoefficientAnalysis.visualize_correlation(x, y, xlabel=labels[0], ylabel=labels[1])
+ # fig=g1.figure
+ # fig.savefig('Single_correlation_plot.pdf', format='pdf')
+
+ # data=[self.meso_vars['eta'], self.meso_vars['b_tilde'], self.meso_vars['eps_tilde'], self.meso_vars['n_tilde']]
+ # labels=['eta', 'b_tilde', 'eps_tilde', 'n_tilde']
+ # g2=CoefficientAnalysis.visualize_many_correlations(data, labels)
+
+ # data=[self.meso_vars['zeta'], self.meso_vars['b_tilde'], self.meso_vars['eps_tilde'], self.meso_vars['n_tilde']]
+ # labels=['zeta', 'b_tilde', 'eps_tilde', 'n_tilde']
+ # gbis= CoefficientAnalysis.visualize_many_correlations(data, labels)
+ # # plt.savefig('Many_correlations_plot.pdf', format='pdf')
+ # plt.show()
+
+ # TESTING THE CHECK REGRESSORS ROUTINE:
+ # data=[self.meso_vars['b_tilde'], self.meso_vars['eps_tilde'], self.meso_vars['n_tilde']]
+ # labels=['b_tilde', 'eps_tilde', 'n_tilde']
+ # g1=CoefficientAnalysis.visualize_many_correlations(data, labels)
+ # comps, g2 = CoefficientAnalysis.PCA_find_regressors_subset(data, ranges = ranges, model_points = points)
+ # g2.fig.suptitle("Correlation between PC (standardized data)")
+ # g2.fig.subplots_adjust(top=0.94)
+ # print(comps)
+ # plt.show()
+
+if __name__ == '__main__':
+
+
+
+ ########################################################
+ # TESTING SERIAL IMPLEMENTATION
+ ########################################################
+ # FileReader = METHOD_HDF5('/Users/thomas/Dropbox/Work/projects/Filtering/Data/test_res100/')
+ # micro_model = IdealHD_2D()
+ # FileReader.read_in_data(micro_model)
+ # micro_model.setup_structures()
+ # find_obs = FindObs_drift_root(micro_model, 0.001)
+ # filter = spatial_box_filter(micro_model, 0.003)
+
+
+ # CPU_start_time = time.process_time()
+ # meso_model = resHD2D(micro_model, find_obs, filter)
+
+ # # print(micro_model.domain_vars['tmin'], micro_model.domain_vars['tmax'])
+
+ # t_range = [1.502, 1.505]
+ # x_range = [0.29, 0.36]
+ # y_range = [0.39, 0.46]
+
+ # meso_model.setup_meso_grid([t_range, x_range, y_range])
+ # meso_model.find_observers()
+ # meso_model.filter_micro_variables()
+
+
+ # print('Filter stage ended')
+ # # # meso_model.decompose_structures_gridpoint(1,1,1)
+ # meso_model.decompose_structures()
+
+ # print('Decomposition stage ended')
+ # # print(meso_model.calculate_derivative_gridpoint('u_tilde', 0,1,1,0))
+ # meso_model.calculate_derivatives()
+
+ # # meso_model.closure_ingredients_gridpoint(1,1,0)
+ # # meso_model.closure_ingredients()
+ # # print('Derivatives and Decomposition stage ended')
+
+ # # meso_model.EL_style_closure_gridpoint(1,2,3)
+ # # meso_model.EL_style_closure()
+ # # regressor = CoefficientsAnalysis()
+ # # meso_model.EL_style_closure_regression(regressor)
+
+ # # print('Total time is {}'.format(time.process_time() - CPU_start_time))
+
+
+ # ########################################################
+ # # TESTING PARALLEL IMPLEMENTATION: find obs + filter
+ # ########################################################
+ # FileReader = METHOD_HDF5('../Data/test_res100/')
+ # micro_model = IdealHD_2D()
+ # FileReader.read_in_data(micro_model)
+ # micro_model.setup_structures()
+
+ # t_range = [1.502, 1.504]
+ # x_range = [0.05, 0.95]
+ # y_range = [0.05, 0.95]
+
+
+ # # find obs - serial
+ # start_time = time.perf_counter()
+ # find_obs = FindObs_drift_root(micro_model, 0.001)
+ # filter = spatial_box_filter(micro_model, 0.003)
+ # meso_model = resHD2D(micro_model, find_obs, filter)
+ # meso_model.setup_meso_grid([t_range, x_range, y_range])
+
+ # num_points = meso_model.domain_vars['Nt'] * meso_model.domain_vars['Nx'] * meso_model.domain_vars['Ny']
+ # print(f'Testing parallelization with {num_points} points\n')
+
+ # meso_model.find_observers()
+ # serial_time = time.perf_counter() - start_time
+ # print('Serial execution time: {}\n'.format(serial_time))
+
+
+ # # fin obs - parallel
+ # start_time = time.perf_counter()
+ # find_obs = FindObs_root_parallel(micro_model, 0.001)
+ # filter = spatial_box_filter(micro_model, 0.003)
+ # meso_model = resHD2D(micro_model, find_obs, filter)
+ # meso_model.setup_meso_grid([t_range, x_range, y_range])
+ # meso_model.find_observers_parallel()
+ # parallel_time = time.perf_counter() - start_time
+ # print('Finished finding observers in parallel, execution time: {}\n'.format(parallel_time))
+ # print('Speed-up factor: {}'.format(serial_time/parallel_time))
+
+
+ # # now filtering serial
+ # start_time = time.perf_counter()
+ # meso_model.filter_micro_variables()
+ # serial_time = time.perf_counter() - start_time
+ # print('Finished filtering in serial, time taken {}\n'.format(serial_time))
+
+ # # now filtering in parallel
+ # parallel_filter = box_filter_parallel(micro_model, 0.003)
+ # meso_model.set_filter(parallel_filter)
+ # start_time = time.perf_counter()
+ # meso_model.filter_micro_vars_parallel()
+ # parallel_time = time.perf_counter() - start_time
+ # print('Finished filtering in parallel, time taken {}\n'.format(parallel_time))
+ # print('Speed-up factor: {}'.format(serial_time/parallel_time))
+
+
+ ########################################################
+ # TESTING PARALLEL IMPLEMENTATION: meso routines
+ ########################################################
+ directory = '../Data/test_res100/'
+ FileReader = METHOD_HDF5(directory)
+ micro_model = IdealHD_2D()
+ FileReader.read_in_data(micro_model)
+ micro_model.setup_structures()
+
+ t_range = [1.502, 1.504]
+ x_range = [0.05, 0.06]
+ y_range = [0.05, 0.06]
+
+ # set up meso model and grid
+ find_obs = FindObs_root_parallel(micro_model, 0.001)
+ filter = box_filter_parallel(micro_model, 0.003)
+ meso_model = resHD2D(micro_model, find_obs, filter)
+ meso_model.setup_meso_grid([t_range, x_range, y_range])
+
+ num_points = meso_model.domain_vars['Nt'] * meso_model.domain_vars['Nx'] * meso_model.domain_vars['Ny']
+ print(f'Testing parallelization with {num_points} points\n')
+
+ # fin obs - parallel
+ start_time = time.perf_counter()
+ meso_model.find_observers_parallel(os.cpu_count())
+ parallel_time = time.perf_counter() - start_time
+ print('Finished finding observers in parallel, execution time: {}\n'.format(parallel_time))
+
+ # now filtering in parallel
+ start_time = time.perf_counter()
+ meso_model.filter_micro_vars_parallel(os.cpu_count())
+ parallel_time = time.perf_counter() - start_time
+ print('Finished filtering in parallel, time taken {}\n'.format(parallel_time))
+
+ # # now testing serial vs parallel decomposition
+ # start_time = time.perf_counter()
+ # meso_model.decompose_structures()
+ # serial_time = time.perf_counter() - start_time
+ # print('Finished decomposing in serial, time taken {}\n'.format(serial_time))
+
+ start_time = time.perf_counter()
+ meso_model.decompose_structures_parallel(os.cpu_count())
+ parallel_time = time.perf_counter() - start_time
+ print('Finished decomposing in parallel, time taken {}\n'.format(parallel_time))
+ # print('Speed-up factor: {}'.format(serial_time/parallel_time))
+
+
\ No newline at end of file
diff --git a/master_files/MicroModels.py b/master_files/MicroModels.py
new file mode 100644
index 0000000..a8555ac
--- /dev/null
+++ b/master_files/MicroModels.py
@@ -0,0 +1,802 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Mar 31 10:00:02 2023
+
+@author: Thomas
+"""
+
+import numpy as np
+import math
+import time
+import os
+import multiprocessing as mp
+from itertools import product
+
+from scipy.interpolate import interpn
+from multimethod import multimethod
+
+from FileReaders import *
+from system.BaseFunctionality import *
+
+
+# These are the symbols, so be careful when using these to construct vectors!
+# levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \
+# for k in range(3)]for j in range(3) ] for i in range(3) ])
+
+# levi4D = np.array([[[[ np.sign(i - j) * np.sign(j - k) * np.sign(k - l) * np.sign(i - l) \
+# for l in range(4)] for k in range(4) ] for j in range(4)] for i in range(4)])
+
+
+class IdealMHD_2D(object):
+ """
+ ADD SHORT DESCRIPTION OF THE CLASS AND ITS METHODS
+ """
+ def __init__(self, interp_method = "linear"):
+ """
+ Sets up the variables and dictionaries, strings correspond to
+ those used in METHOD
+
+ Parameters
+ ----------
+ interp_method: str
+ optional method to be used by interpn
+ """
+ self.spatial_dims = 2
+ self.interp_method = interp_method
+
+ self.metric = np.zeros((3,3))
+ self.metric[0,0] = -1
+ self.metric[1,1] = self.metric[2,2] = +1
+
+ # This is the Levi-Civita symbol, not tensor, so be careful when using it
+ self.Levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \
+ for k in range(3)]for j in range(3) ] for i in range(3) ])
+
+ #Dictionary for grid: info and points
+ self.domain_int_strs = ('nt','nx','ny')
+ self.domain_float_strs = ("tmin","tmax","xmin","xmax","ymin","ymax","dt","dx","dy")
+ self.domain_array_strs = ("t","x","y","points")
+ self.domain_vars = dict.fromkeys(self.domain_int_strs+self.domain_float_strs+self.domain_array_strs)
+ for str in self.domain_vars:
+ self.domain_vars[str] = []
+
+ #Dictionary for primitive var
+ self.prim_strs = ("vx","vy","n","p", "Bz")
+ self.prim_vars = dict.fromkeys(self.prim_strs)
+ for str in self.prim_strs:
+ self.prim_vars[str] = []
+
+ #Dictionary for auxiliary var
+ self.aux_strs = ("W","h","bz","bsq", "e")
+ self.aux_vars = dict.fromkeys(self.aux_strs)
+ for str in self.aux_strs:
+ self.aux_vars[str] = []
+
+ #Dictionary for structures
+ self.structures_strs = ("BC", "SETfl", "SETem", "Fab")
+ self.structures = dict.fromkeys(self.structures_strs)
+ for str in self.structures_strs:
+ self.structures[str] = []
+
+ def get_spatial_dims(self):
+ return self.spatial_dims
+
+ def get_model_name(self):
+ return 'IdealMHD_2D'
+
+ def get_domain_strs(self):
+ return self.domain_int_strs + self.domain_float_strs + self.domain_array_strs
+
+ def get_prim_strs(self):
+ return self.prim_strs
+
+ def get_aux_strs(self):
+ return self.aux_strs
+
+ def get_structures_strs(self):
+ return self.structures_strs
+
+ def get_all_var_strs(self):
+ return self.get_prim_strs() + self.get_aux_strs() + self.get_structures_strs()
+
+ def get_gridpoints(self):
+ """
+ Pretty self-explanatory
+ """
+ return self.domain_vars['points']
+
+ def get_interpol_var(self, var, point):
+ """
+ Returns the interpolated variables at the point.
+
+ Parameters
+ ----------
+ var: str corresponding to primitive, auxiliary or structre variable
+
+ point : list of floats
+ ordered coordinates: t,x,y
+
+ Return
+ ------
+ Interpolated values/arrays corresponding to variable.
+ Empty list if none of the variables is a primitive, auxiliary o structure of the micro_model
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+
+ if var in self.get_prim_strs():
+ return interpn(self.domain_vars['points'], self.prim_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_aux_strs():
+ return interpn(self.domain_vars['points'], self.aux_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_structures_strs():
+ return interpn(self.domain_vars['points'], self.structures[var], point, method = self.interp_method)[0]
+ else:
+ print(f'{var} is not a primitive, auxiliary variable or structure of the micro_model!!')
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, h: object, i: object, j: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint identified by h,i,j
+
+ Parameters:
+ -----------
+ var: str
+ String corresponding to primitive, auxiliary or structure variable
+
+ h,i,j: int
+ integers corresponding to position on the grid.
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method is useful e.g. for plotting the raw data.
+ """
+ if var in self.get_prim_strs():
+ return self.prim_vars[var][h,i,j]
+ elif var in self.get_aux_strs():
+ return self.aux_vars[var][h,i,j]
+ elif var in self.get_structures_strs():
+ return self.structures[var][h,i,j]
+ else:
+ print('{} is not a variable of model {}'.format(var, self.get_model_name()))
+ return None
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, point: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint
+ closest to input 'point'.
+
+ Parameters:
+ -----------
+ vars: string corresponding to primitive, auxiliary or structure variable
+
+ point: list of 2+1 floats
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method should be used in case using interpolated values
+ becomes too expensive.
+ """
+ indices = Base.find_nearest_cell(point, self.domain_vars['points'])
+ if var in self.get_prim_strs():
+ return self.prim_vars[var][tuple(indices)]
+ elif var in self.get_aux_strs():
+ return self.aux_vars[var][tuple(indices)]
+ elif var in self.get_structures_strs():
+ return self.structures[var][tuple(indices)]
+ else:
+ print(f"{var} is not a variable of IdealMHD_2D!")
+ return None
+
+ def setup_structures(self):
+ """
+ Set up the structures (i.e baryon (mass) current BC, Stress-Energy and Faraday tensors
+
+ Notes:
+ ------
+ Structures are built as multi-dim np.arrays, with the first three indices referring
+ to the grid, while the last one or two refer to space-time components.
+
+ The Faraday tensor is stored as a fully co-variant tensor (both indices down)
+ The stress-energy tensor is stored as a fully contra-variant tensor (both indices up)
+ """
+ self.structures["BC"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3))
+ self.structures["SETfl"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3))
+ self.structures["SETem"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3))
+ self.structures["Fab"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3))
+
+ for h in range(self.domain_vars['nt']):
+ for i in range(self.domain_vars['nx']):
+ for j in range(self.domain_vars['ny']):
+ vel_vec = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['vx'][h,i,j] ,\
+ self.aux_vars['W'][h,i,j] * self.prim_vars['vy'][h,i,j]])
+
+ fibr_b = self.aux_vars['bz'][h,i,j]
+
+ self.structures['BC'][h,i,j,:] = np.multiply(self.prim_vars['n'][h,i,j], vel_vec )
+
+ self.structures['SETfl'][h,i,j,:,:] = (self.prim_vars["n"][h,i,j] * self.aux_vars['h'][h,i,j]) * np.outer(vel_vec, vel_vec) \
+ + self.prim_vars['p'][h,i,j] * self.metric
+
+ self.structures['SETem'][h,i,j:,:] = (fibr_b**2) * np.outer(vel_vec, vel_vec) + (fibr_b/2) * self.metric
+
+ self.structures['Fab'][h,i,j,:,:] = np.tensordot(self.Levi3D, vel_vec, axes = ([2,0])) * fibr_b
+
+
+ ################################
+ # CORRESPONDING 3+1-d FORMULAE
+ ################################
+
+ # vel_vec = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['vx'][h,i,j] ,\
+ # self.aux_vars['W'][h,i,j] * self.prim_vars['vy'][h,i,j], self.aux_vars['W'][h,i,j] * self.prim_vars['vz'][h,i,j]])
+
+ # fibr_b = [0, self.aux_vars['bx'][h,i,j], self.aux_vars['by'][h,i,j], self.aux_vars['bz'][h,i,j]]
+
+ # self.structures['Fab'][h,i,j,:,:] = np.tensordot(np.tensordot(self.Levi4D, vel_vec, axes = ([2,0])), fibr_b, axes= ([2,0]))
+
+ # self.structures['SETem'][h,i,j,:,:] = Base.Mink_dot(fibr_b, fibr_b) * np.outer(vel_vec, vel_vec) +\
+ # (Base.Mink_dot(fibr_b, fibr_b)/2) * self.metric -\
+ # np.multiply(1/2., np.outer(fibr_b, fibr_b) )
+
+
+ # This might be useful/needed
+ # self.all_vars = self.prim_vars
+ # self.all_vars.update(self.aux_vars)
+ # self.all_vars.update(self.structures)
+
+ self.vars = self.prim_vars
+ self.vars.update(self.aux_vars)
+ self.vars.update(self.structures)
+
+
+class IdealHydro_2D(object):
+
+ def __init__(self, interp_method = "linear"):
+ """
+ Sets up the variables and dictionaries, strings correspond to
+ those used in METHOD
+
+ Parameters
+ ----------
+ interp_method: str
+ optional method to be used by interpn
+ """
+ self.spatial_dims = 2
+ self.interp_method = interp_method
+
+ self.metric = np.zeros((3,3))
+ self.metric[0,0] = -1
+ self.metric[1,1] = self.metric[2,2] = +1
+
+ # This is the Levi-Civita symbol, not tensor, so be careful when using it
+ self.Levi3D = np.array([[[ np.sign(i-j) * np.sign(j- k) * np.sign(k-i) \
+ for k in range(3)]for j in range(3) ] for i in range(3) ])
+
+ #Dictionary for grid: info and points
+ self.domain_int_strs = ('nt','nx','ny')
+ self.domain_float_strs = ("tmin","tmax","xmin","xmax","ymin","ymax","dt","dx","dy")
+ self.domain_array_strs = ("t","x","y","points")
+ self.domain_vars = dict.fromkeys(self.domain_int_strs+self.domain_float_strs + self.domain_array_strs)
+ for str in self.domain_vars:
+ self.domain_vars[str] = []
+
+ #Dictionary for primitive var
+ self.prim_strs = ("v1","v2","rho","p","n")
+ self.prim_vars = dict.fromkeys(self.prim_strs)
+ for str in self.prim_strs:
+ self.prim_vars[str] = []
+
+ #Dictionary for auxiliary var
+ self.aux_strs = ("W","h","T")
+ self.aux_vars = dict.fromkeys(self.aux_strs)
+ for str in self.aux_strs:
+ self.aux_vars[str] = []
+
+ #Dictionary for structures
+ self.structures_strs = ("BC","SET")
+ self.structures = dict.fromkeys(self.structures_strs)
+ for str in self.structures_strs:
+ self.structures[str] = []
+
+ #Dictionary for all vars
+ self.var_strs = self.prim_strs + self.aux_strs + self.structures_strs
+ # self.vars = self.prim_vars
+ # self.vars.update(self.aux_vars)
+ # self.vars.update(self.structures)
+
+ self.all_var_strs = self.prim_strs + self.aux_strs + self.structures_strs
+
+ def get_model_name(self):
+ return 'IdealHydro_2D'
+
+ def get_spatial_dims(self):
+ return self.spatial_dims
+
+ def get_domain_strs(self):
+ return self.domain_info_strs + self.domain_points_strs
+
+ def get_prim_strs(self):
+ return list(self.prim_vars.keys())
+
+ def get_aux_strs(self):
+ return list(self.aux_vars.keys())
+
+ def get_structures_strs(self):
+ return list(self.structures.keys())
+
+ def get_all_var_strs(self):
+ return list(self.prim_vars.keys()) + list(self.aux_vars_vars.keys()) + list(self.structures.keys())
+
+ def setup_structures(self):
+ """
+ Set up the structures (i.e baryon current, SET)
+
+ Structures are built as multi-dim np.arrays, with the first three indices referring
+ to the grid, while the last one or two refer to space-time components.
+ """
+ self.structures["BC"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3))
+ self.structures["SET"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3))
+
+ for h in range(self.domain_vars['nt']):
+ for i in range(self.domain_vars['nx']):
+ for j in range(self.domain_vars['ny']):
+ vel = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['v1'][h,i,j] ,\
+ self.aux_vars['W'][h,i,j] * self.prim_vars['v2'][h,i,j]])
+ self.structures['BC'][h,i,j,:] = np.multiply(self.prim_vars['n'][h,i,j], vel )
+
+
+ self.structures["SET"][h,i,j,:,:] = (self.prim_vars["rho"][h,i,j] + self.prim_vars["p"][h,i,j]) * \
+ np.outer(vel,vel) + self.prim_vars["p"][h,i,j] * self.metric
+
+ self.vars = self.prim_vars
+ self.vars.update(self.aux_vars)
+ self.vars.update(self.structures)
+
+ def get_interpol_prim(self, var_names, point):
+ """
+ Returns the interpolated variable at the point
+
+ Parameters
+ ----------
+ vars : list of strings
+ strings have to be in to prim_vars keys
+ point : list of floats
+ ordered coordinates: t,x,y
+ Return
+ ------
+ list of floats corresponding to string of vars
+
+ Notes
+ -----
+ Interpolation raises a ValueError when out of grid boundaries.
+ """
+ res = []
+
+ for var_name in var_names:
+ try:
+ res.append( interpn(self.domain_vars["points"], self.prim_vars[var_name], point, method = self.interp_method)[0]) #, bounds_error = False)
+ except KeyError:
+ print(f"{var_name} does not belong to the primitive variables of the micro_model!")
+ return res
+
+ def get_interpol_aux(self, var_names, point):
+ """
+ Returns the interpolated variable at the point
+
+ Parameters
+ ----------
+ vars : list of strings
+ strings have to be in to aux_vars keys
+ point : list of floats
+ ordered coordinates: t,x,y
+ Return
+ ------
+ list of floats corresponding to string of vars
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+
+ res = []
+ for var_name in var_names:
+ try:
+ res.append( interpn(self.domain_vars["points"], self.aux_vars[var_name], point, method = self.interp_method)[0])
+ except KeyError:
+ print(f"{var_name} does not belong to the auxiliary variables of the micro_model!")
+ return res
+
+ def get_interpol_struct(self, var_name, point):
+ """
+ Returns the interpolated structure at the point
+
+ Parameters
+ ----------
+ var : str corresponding to one of the structures
+
+ point : list of floats
+ ordered coordinates: t,x,y
+
+ Return
+ ------
+ Array with the interpolated values of the var structure
+ Empty list if var is not a structure in the micro_model
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+ res = []
+ if var_name == "BC":
+ res = np.zeros(len(self.structures[var_name][:,0,0,0]))
+ for a in range(len(self.structures[var_name][:,0,0,0])):
+ res[a] = interpn(self.domain_vars["points"], self.structures[var_name][a,:,:,:], point, method = self.interp_method)[0]
+ elif var_name == "SET":
+ res = np.zeros((len(self.structures[var_name][:,0,0,0,0]),len(self.structures[var][0,:,0,0,0])))
+ for a in range(len(self.structures[var_name][:,0,0,0,0])):
+ for b in range(len(self.structures[var_name][0,:,0,0,0])):
+ res[a,b] = interpn(self.domain_vars["points"],self.structures[var_name][a,b,:,:,:], point, method = self.interp_method)[0]
+ else:
+ print(f"{var} does not belong to the structures in the micro_model")
+ return res
+
+ def get_interpol_var(self, var, point):
+ """
+ Returns the interpolated variables at the point.
+
+ Parameters
+ ----------
+ vars : str corresponding to primitive, auxiliary or structre variable
+
+ point : list of floats
+ ordered coordinates: t,x,y
+
+ Return
+ ------
+ Interpolated values/arrays corresponding to variable.
+ Empty list if none of the variables is a primitive, auxiliary o structure of the micro_model
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+
+ if var in self.get_prim_strs():
+ return interpn(self.domain_vars['points'], self.prim_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_aux_strs():
+ return interpn(self.domain_vars['points'], self.aux_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_structures_strs():
+ return interpn(self.domain_vars['points'], self.structures[var], point, method = self.interp_method)[0]
+ else:
+ print(f'{var} is not a primitive, auxiliary variable or structure of the micro_model!!')
+
+
+
+ """
+ Returns the interpolated structure at the point
+ Parameters
+ ----------
+ var : str corresponding to one of the structures
+
+ point : list of floats
+ ordered coordinates: t,x,y
+ Return
+ ------
+ Array with the interpolated values of any var
+ Empty list if var is not a structure in the micro_model
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+ res = []
+ for var_name in var_names:
+ try:
+ res.append( interpn(self.domain_vars["points"], self.vars[var_name], point, method = self.interp_method)[0])
+ except KeyError:
+ print(f"{var_name} does not belong to the auxiliary variables of the micro_model!")
+ return res
+
+
+class IdealHD_2D(object):
+ """
+ CUT AND PAST OF IdealMHD_2D --> removing the magnetic bits
+ """
+ def __init__(self, interp_method = "linear"):
+ """
+ Sets up the variables and dictionaries, strings correspond to
+ those used in METHOD
+
+ Parameters
+ ----------
+ interp_method: str
+ optional method to be used by interpn
+ """
+ self.spatial_dims = 2
+ self.interp_method = interp_method
+
+ self.metric = np.zeros((3,3))
+ self.metric[0,0] = -1
+ self.metric[1,1] = self.metric[2,2] = +1
+
+ #Dictionary for grid: info and points
+ self.domain_int_strs = ('nt','nx','ny')
+ self.domain_float_strs = ("tmin","tmax","xmin","xmax","ymin","ymax","dt","dx","dy")
+ self.domain_array_strs = ("t","x","y","points")
+ self.domain_vars = dict.fromkeys(self.domain_int_strs+self.domain_float_strs+self.domain_array_strs)
+ for str in self.domain_vars:
+ self.domain_vars[str] = []
+
+ #Dictionary for primitive var
+ self.prim_strs = ("vx","vy","n","p")
+ self.prim_vars = dict.fromkeys(self.prim_strs)
+ for str in self.prim_strs:
+ self.prim_vars[str] = []
+
+ #Dictionary for auxiliary var
+ self.aux_strs = ("W", "h", "e")
+ self.aux_vars = dict.fromkeys(self.aux_strs)
+ for str in self.aux_strs:
+ self.aux_vars[str] = []
+
+ #Dictionary for structures
+ self.structures_strs = ("BC", "SET", "bar_vel")
+ self.structures = dict.fromkeys(self.structures_strs)
+ for str in self.structures_strs:
+ self.structures[str] = []
+
+ self.labels_var_dict = {'BC' : r'$n^{a}$',
+ 'SET' : r'$T^{ab}$',
+ 'bar_vel' : r'$u^a$',
+ 'vx' : r'$v_x$',
+ 'vy' : r'$v_y$',
+ 'n' : r'$n$',
+ 'W' : r'$W$',
+ 'e' : r'$e$',
+ 'h' : r'$h$',
+ 'p' : r'$p$'}
+
+ def upgrade_labels_dict(self, entry_dict):
+ """
+ pretty self-explanatory
+ """
+ self.labels_var_dict.update(entry_dict)
+
+ def get_spatial_dims(self):
+ return self.spatial_dims
+
+ def get_model_name(self):
+ return 'Ideal Hydro (2+1d)'
+
+ def get_domain_strs(self):
+ return self.domain_int_strs + self.domain_float_strs + self.domain_array_strs
+
+ def get_prim_strs(self):
+ return self.prim_strs
+
+ def get_aux_strs(self):
+ return self.aux_strs
+
+ def get_structures_strs(self):
+ return self.structures_strs
+
+ def get_all_var_strs(self):
+ return self.get_prim_strs() + self.get_aux_strs() + self.get_structures_strs()
+
+ def get_gridpoints(self):
+ """
+ Pretty self-explanatory
+ """
+ return self.domain_vars['points']
+
+ def get_interpol_var(self, var, point):
+ """
+ Returns the interpolated variables at the point.
+
+ Parameters
+ ----------
+ var: str corresponding to primitive, auxiliary or structre variable
+
+ point : list of floats
+ ordered coordinates: t,x,y
+
+ Return
+ ------
+ Interpolated values/arrays corresponding to variable.
+ Empty list if none of the variables is a primitive, auxiliary o structure of the micro_model
+
+ Notes
+ -----
+ Interpolation gives errors when applied to boundary
+ """
+
+ if var in self.get_prim_strs():
+ return interpn(self.domain_vars['points'], self.prim_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_aux_strs():
+ return interpn(self.domain_vars['points'], self.aux_vars[var], point, method = self.interp_method)[0]
+ elif var in self.get_structures_strs():
+ return interpn(self.domain_vars['points'], self.structures[var], point, method = self.interp_method)[0]
+ else:
+ print(f'{var} is not a primitive, auxiliary variable or structure of the micro_model!!')
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, h: object, i: object, j: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint identified by h,i,j
+
+ Parameters:
+ -----------
+ var: str
+ String corresponding to primitive, auxiliary or structure variable
+
+ h,i,j: int
+ integers corresponding to position on the grid.
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method is useful e.g. for plotting the raw data.
+ """
+ if var in self.get_prim_strs():
+ return self.prim_vars[var][h,i,j]
+ elif var in self.get_aux_strs():
+ return self.aux_vars[var][h,i,j]
+ elif var in self.get_structures_strs():
+ return self.structures[var][h,i,j]
+ else:
+ print('{} is not a variable of model {}'.format(var, self.get_model_name()))
+ return None
+
+ @multimethod
+ def get_var_gridpoint(self, var: str, point: object):
+ """
+ Returns variable corresponding to input 'var' at gridpoint
+ closest to input 'point'.
+
+ Parameters:
+ -----------
+ vars: string corresponding to primitive, auxiliary or structure variable
+
+ point: list of 2+1 floats
+
+ Returns:
+ --------
+ Values or arrays corresponding to variable evaluated at the closest grid-point to input 'point'.
+
+ Notes:
+ ------
+ This method should be used in case using interpolated values
+ becomes too expensive.
+ """
+ indices = Base.find_nearest_cell(point, self.domain_vars['points'])
+ if var in self.get_prim_strs():
+ return self.prim_vars[var][tuple(indices)]
+ elif var in self.get_aux_strs():
+ return self.aux_vars[var][tuple(indices)]
+ elif var in self.get_structures_strs():
+ return self.structures[var][tuple(indices)]
+ else:
+ print(f"{var} is not a variable of IdealMHD_2D!")
+ return None
+
+ def setup_structures(self):
+ """
+ Set up the structures (i.e baryon (mass) current BC, Stress-Energy and Faraday tensors
+
+ Notes:
+ ------
+ Structures are built as multi-dim np.arrays, with the first three indices referring
+ to the grid, while the last one or two refer to space-time components.
+
+ The Faraday tensor is stored as a fully co-variant tensor (both indices down)
+ The stress-energy tensor is stored as a fully contra-variant tensor (both indices up)
+ """
+ self.structures["BC"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3))
+ self.structures["bar_vel"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3))
+ self.structures["SET"] = np.zeros((self.domain_vars['nt'],self.domain_vars['nx'],self.domain_vars['ny'],3,3))
+
+ for h in range(self.domain_vars['nt']):
+ for i in range(self.domain_vars['nx']):
+ for j in range(self.domain_vars['ny']):
+ vel_vec = np.array([self.aux_vars['W'][h,i,j],self.aux_vars['W'][h,i,j] * self.prim_vars['vx'][h,i,j] ,\
+ self.aux_vars['W'][h,i,j] * self.prim_vars['vy'][h,i,j]])
+
+ self.structures['bar_vel'][h,i,j,:] = vel_vec
+
+ self.structures['BC'][h,i,j,:] = np.multiply(self.prim_vars['n'][h,i,j], vel_vec )
+
+ self.structures['SET'][h,i,j,:,:] = (self.prim_vars['n'][h,i,j] * self.aux_vars['h'][h,i,j]) * np.outer(vel_vec, vel_vec) \
+ + self.prim_vars['p'][h,i,j] * self.metric
+
+
+
+
+ self.vars = self.prim_vars
+ self.vars.update(self.aux_vars)
+ self.vars.update(self.structures)
+
+ ####################################################
+ # ATTEMPT TO PARALLELIZE SETUP STRUCTURES: NOT WORTHY
+ # FOR SETUP_STRUCTURES ROUTINE
+ ####################################################
+ # # defining it statically means no self is passed on construction, but guarantees
+ # # the method is the specific for this class!
+ # @staticmethod
+ # def setting_up(W, vx, vy, n, h, p, idxs):
+ # bar_vel = [W, W * vx, W * vy]
+ # BC = np.multiply(n, bar_vel)
+ # metric = np.zeros((3,3))
+ # metric[0,0] = -1
+ # metric[1,1] = metric[2,2] = +1
+ # SET = n * h * np.outer(bar_vel, bar_vel) + p * metric
+ # return bar_vel, BC, SET, idxs
+
+
+ # def setup_structures_parallel(self):
+ # args_to_pass = []
+ # for h in range(self.domain_vars['nt']):
+ # for i in range(self.domain_vars['nx']):
+ # for j in range(self.domain_vars['ny']):
+ # args = (self.aux_vars['W'][h,i,j], self.prim_vars['vx'][h,i,j], self.prim_vars['vy'][h,i,j], \
+ # self.prim_vars['n'][h,i,j], self.aux_vars['h'][h,i,j], self.prim_vars['p'][h,i,j], (h,i,j))
+ # args_to_pass.append(args)
+
+ # # chunksize = [None, 1, len(args_to_pass)/ os.cpu_count()]
+ # with mp.Manager() as manager:
+ # print('Running with {} processes\n'.format(os.cpu_count()))
+ # with manager.Pool(os.cpu_count()) as pool:
+ # for result in pool.starmap(self.setting_up, args_to_pass):
+ # bar_vel, BC, SET, grid_idxs = result[0], result[1], result[2], tuple(result[3])
+ # self.structures['bar_vel'][tuple(grid_idxs)] = bar_vel
+ # self.structures['BC'][tuple(grid_idxs)] = BC
+ # self.structures['SET'][tuple(grid_idxs)] = SET
+
+# TC
+if __name__ == '__main__':
+
+ CPU_start_time = time.process_time()
+
+ FileReader = METHOD_HDF5('../Data/test_res100/')
+ # FileReader = METHOD_HDF5('../Data/res800/res800_t3')
+ micro_model = IdealHD_2D()
+ FileReader.read_in_data(micro_model)
+ micro_model.setup_structures()
+
+ ####################################################
+ # Comparing speed of gridpoint vs interpol routines
+ ####################################################
+ print('Structure strs: {}'.format(micro_model.get_structures_strs()))
+ point = [1.502,0.4,0.2]
+ # vars = ['SETfl', 'BC', 'Fab', 'SETem']
+ vars = ['BC', 'bar_vel', 'n']
+ for var in vars:
+ res = micro_model.get_interpol_var(var, point)
+ res2 = micro_model.get_var_gridpoint(var, point)
+ print(f'{var}: \n {res} \n\n\n {res2} \n ********** \n ')
+
+
+ ####################################################
+ # TESTING PARALLELIZED SETUP STRUCTURE
+ ####################################################
+ # CPU_start_time = time.perf_counter()
+ # micro_model.setup_structures()
+ # serial_time= time.perf_counter() - CPU_start_time
+ # print('Time taken serial: {}\n'.format(serial_time))
+
+ # CPU_start_time = time.perf_counter()
+ # micro_model.setup_structures_parallel()
+ # parallel_time = time.perf_counter() - CPU_start_time
+ # print('Time taken parallel: {}\n'.format(parallel_time))
+ # print('Speed up factor: {}\n'.format(serial_time/parallel_time))
\ No newline at end of file
diff --git a/master_files/Visualization.py b/master_files/Visualization.py
new file mode 100644
index 0000000..e7ed228
--- /dev/null
+++ b/master_files/Visualization.py
@@ -0,0 +1,567 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Mon Jun 5 03:14:43 2023
+
+@author: marcu
+"""
+
+
+import matplotlib.pyplot as plt
+from matplotlib import colors
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+from matplotlib.ticker import LogLocator
+import numpy as np
+import h5py
+from scipy.interpolate import interpn
+from system.BaseFunctionality import *
+
+from MicroModels import *
+from MesoModels import *
+from Filters import *
+
+class Plotter_2D(object):
+
+ def __init__(self, screen_size = [11.97, 8.36]):
+ """
+ Parameters:
+ -----------
+ screen_size = list of 2 floats
+ width and height of the screen: used to rescale plots' size.
+ """
+ self.plot_vars_subplots_dims = {1 : (1,1),
+ 2 : (1,2),
+ 3 : (1,3),
+ 4 : (2,2),
+ 5 : (2,3),
+ 6 : (2,3)}
+
+
+ self.screen_size = np.array(screen_size)
+
+ # Change to latex font
+ plt.rc("font",family="serif")
+ plt.rc("mathtext",fontset="cm")
+
+ def get_var_data(self, model, var_str, t, x_range, y_range, component_indices=(), method= 'raw_data', interp_dims=None):
+ """
+ Retrieves the required data from model to plot a variable defined by
+ var_str over coordinates t, x_range, y_range, either from the model's
+ raw data or by interpolating between the model's raw data over the coords.
+
+ Parameters
+ ----------
+ model : Micro or Meso Model
+ var_str : str
+ Must match a variable of the model.
+ t : float
+ time coordinate (defines the foliation).
+ x_range : list of 2 floats: x_start and x_end
+ defines range of x coordinates within foliation.
+ y_range : list of 2 floats: y_start and y_end
+ defines range of y coordinates within foliation.
+ component_indices : tuple
+ the indices of the component to pick out if the variable is a vector/tensor.
+ method : str
+ currently either raw_data or interpolate.
+ interp_dims : tuple of integers
+ defines the number of points to interpolate at in x and y directions.
+
+ Returns
+ -------
+ data_to_plot : numpy array of floats
+ the 2D data to be plotted by plt.imshow()
+ extent: list of floats
+
+
+
+ Notes:
+ ------
+ Logic: if method is raw_data, then no interp_dims are needed.
+ Better to have 'raw_data' and interp_dims = None as default
+
+ data_to_plot is transposed and extent is built to be used with:
+ origin=lower, extent=L,R,B,T by imshow
+
+ """
+ if var_str in model.get_all_var_strs():
+
+ # Block to check component_indices passed are compatible with shape of var to be plotted.
+ st1 = len(component_indices)
+ st2 = len(model.get_var_gridpoint(var_str, 0, 0, 0).shape)
+ compatible = st1==st2
+ if not compatible:
+ if st2 == 0 :
+ print('WARNING: {} is a scalar but you passed some indices, ignoring this and moving on.'.format(var_str))
+ component_indices = ()
+ elif st2 != 0:
+ print('WARNING: {} is a tensor but you passed more/fewer indices than required. Retrieving the "first component"!'.format(var_str))
+ component_indices = tuple([0 for _ in range(st2)])
+
+ # extent = [*x_range, *y_range]
+
+ if method == 'interpolate':
+ compatible = interp_dims != None and len(interp_dims) ==2
+ if not compatible:
+ print('Error: when using (linearly spaced) interpolated data, you must' +\
+ 'specify # points in each spatial direction! Exiting.')
+ return None
+
+ nx, ny = interp_dims[:]
+ xs, ys = np.linspace(x_range[0], x_range[1], nx), np.linspace(y_range[0], y_range[1], ny)
+ data_to_plot = np.zeros((nx, ny))
+
+ points = [t, xs, ys]
+ # extent = [points[2][0],points[2][-1],points[1][0],points[1][-1]]
+ extent = [points[1][0],points[1][-1],points[2][0],points[2][-1]]
+
+ for i in range(nx):
+ for j in range(ny):
+ point = [t, xs[i], ys[j]]
+ data_to_plot[i, j] = model.get_interpol_var(var_str, point)[component_indices]
+
+ elif method == 'raw_data':
+ start_indices = Base.find_nearest_cell([t, x_range[0], y_range[0]], model.get_gridpoints())
+ end_indices = Base.find_nearest_cell([t, x_range[1], y_range[1]], model.get_gridpoints())
+
+ h = start_indices[0]
+ i_s, i_f = start_indices[1], end_indices[1]
+ j_s, j_f = start_indices[2], end_indices[2]
+
+ gridpoints = model.get_gridpoints()
+ points = [gridpoints[0][h], gridpoints[1][i_s:i_f+1], gridpoints[2][j_s:j_f+1]]
+ # extent = [points[2][0],points[2][-1],points[1][0],points[1][-1]]
+ extent = [points[1][0],points[1][-1],points[2][0],points[2][-1]]
+
+ data_shape = (i_f - i_s + 1, j_f - j_s + 1)
+ data_to_plot = np.zeros(data_shape)
+
+ for i in range(i_f - i_s + 1):
+ for j in range(j_f - j_s + 1):
+ data_to_plot[i,j] = model.get_var_gridpoint(var_str, h, i + i_s, j + j_s)[component_indices]
+
+ else:
+ print('Data method is not a valid choice! Must be interpolate or raw_data.')
+ return None
+ # return data_to_plot, points
+ data_to_plot = np.transpose(data_to_plot)
+ return data_to_plot, extent
+
+ else:
+ print(f'{var_str} is not a plottable variable of the model!')
+ return None
+
+ def plot_vars(self, model, var_strs, t, x_range, y_range, components_indices=None, method='raw_data', interp_dims=None,
+ norms=None, cmaps=None):
+ """
+ Plot variable(s) from model, defined by var_strs, over coordinates
+ t, x_range, y_range. Either from the model's raw data or by interpolating
+ between the model's raw data over the coords.
+
+ Parameters
+ ----------
+ model : Micro or Meso Model
+ var_strs : list of str
+ Must match entries in the models' 'vars' dictionary.
+ t : float
+ time coordinate (defines the foliation).
+ x_range : list of 2 floats: x_start and x_end
+ defines range of x coordinates within foliation.
+ y_range : list of 2 floats: y_start and y_end
+ defines range of y coordinates within foliation.
+ components_indices : list of tuple(s)
+ the indices of the components to pick out if the variables are vectors/tensors.
+ Can be omitted if all variables are scalars, otherwise must be a list
+ of tuples matching the length of var_strs that corresponds with each
+ variable in the list.
+ method : str
+ currently either raw_data or interpolate
+ interp_dims : tuple of integers
+ defines the number of points to interpolate at in x and y directions.
+ norms = list of strs
+ each entry of the list is passed as option to imshow as norm=str
+ when plotting the corresponding var
+
+ valid choices include all the standard norms like log or symlog,
+ and 'mysymlog' which is implemented in BaseFunctionality
+
+ cmaps = list of strs
+ each entry of the list is passed to imshow as cmap=cmaps[i]
+ when plotting the corresponding var
+
+ valid choices are all the std ones
+
+ Output
+ -------
+ Plots the (2D) data using imshow. Note that the plotting data's coordinates
+ may not perfectly match the input coordinates if method=raw_data as
+ nearest-cell data is used where the input coordinates do not coincide
+ with the model's raw data coordinates.
+
+ """
+ n_plots = len(var_strs)
+
+ if norms == None:
+ norms = [None for _ in range(len(var_strs))]
+ elif len(var_strs)!= len(norms):
+ print('The norms provided are not the same number as the variables: setting these to auto')
+ norms = [None for _ in range(len(var_strs))]
+
+ if cmaps == None:
+ cmaps = [None for _ in range(len(var_strs))]
+ elif len(var_strs)!= len(cmaps):
+ print('The norms provided are not the same number as the variables: setting these to auto')
+ cmaps = [None for _ in range(len(var_strs))]
+
+ n_rows, n_cols = self.plot_vars_subplots_dims[n_plots]
+
+ # Block to determine adaptively the figsize.
+ figsizes = {1 : (1/3.,1/3.),
+ 2 : (2/3.,1/3.),
+ 3 : (1,1/3.),
+ 4 : (2/3.,2/3.),
+ 5 : (1,2/3.),
+ 6 : (1,2/3.)}
+ for item in figsizes:
+ figsizes[item] = tuple(figsizes[item] * self.screen_size)
+ figsize = figsizes[n_plots]
+
+
+ fig, axes = plt.subplots(n_rows,n_cols, figsize=figsize)
+ if n_plots == 1:
+ axes = [axes]
+ else:
+ axes = axes.flatten()
+
+ if not components_indices:
+ print('No list of components indices passed: setting this to an empty list.')
+ components_indices = [ () for _ in range(len(var_strs))]
+
+ for i, (var_str, component_indices, ax) in enumerate(zip(var_strs, components_indices, axes)):
+ # data_to_plot, points = self.get_var_data(model, var_str, t, x_range, y_range, interp_dims, method, component_indices)
+ # extent = [points[2][0],points[2][-1],points[1][0],points[1][-1]]
+ data_to_plot, extent = self.get_var_data(model, var_str, t, x_range, y_range, component_indices, method, interp_dims)
+
+ if norms[i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(data_to_plot)
+ data_to_plot = MySymLogPlotting.symlog_var(data_to_plot)
+ mynorm = MyThreeNodesNorm(nodes)
+ im = ax.imshow(data_to_plot, extent=extent, origin='lower', norm=mynorm, cmap=cmaps[i])
+ divider = make_axes_locatable(ax)
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ elif norms[i] != 'mysymlog':
+ im = ax.imshow(data_to_plot, extent=extent, origin='lower', norm=norms[i], cmap=cmaps[i])
+ divider = make_axes_locatable(ax)
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+
+ title = var_str
+ if hasattr(model, 'labels_var_dict'):
+ if title in model.labels_var_dict.keys():
+ title = model.labels_var_dict[title]
+ if component_indices != ():
+ title = title + ", {}-component".format(component_indices)
+ ax.set_title(title)
+ ax.set_xlabel(r'$x$')
+ ax.set_ylabel(r'$y$')
+
+ time_for_filename = str(round(t,2))
+ fig.suptitle('Snapshot from model {} at time {}'.format(model.get_model_name(), time_for_filename), fontsize = 12)
+ fig.tight_layout()
+ # plt.show()
+ return fig
+
+ def plot_vars_models_comparison(self, models, var_strs, t, x_range, y_range, components_indices=None, method='raw_data',\
+ interp_dims=None, diff_plot=False, rel_diff=False, norms=None, cmaps=None):
+ """
+ Plot variables from a number of models. If 2 models are given, a third
+ plot of the difference (relative or absolute) can be added too.
+ The method refers to the difference plot(s): for models with different grid spacings, data must
+ be extracted via interpolation, so setting method = 'interpolate'.
+ In any other case, should set method = 'raw_data'.
+
+ Parameters
+ ----------
+ models : list of Micro or Meso Models
+ var_strs : list of lists of strings
+ each sublist must match entries in the models' 'vars' dictionary.
+ t : float
+ time coordinate (defines the foliation).
+ x_range : list of 2 floats: x_start and x_end
+ defines range of x coordinates within foliation.
+ y_range : list of 2 floats: y_start and y_end
+ defines range of y coordinates within foliation.
+ component_indices : list of list of tuples
+ each tuple identifies the indices of the component to pick out if the variable
+ is a vector/tensor.
+ method : str
+ currently either raw_data or interpolate.
+ interp_dims : tuple of integers
+ defines the number of points to interpolate at in x and y directions.
+ diff_plot: bool
+ Whether to add a column to show difference between models
+ rel_diff: bool
+ Whether to plot the absolute or relative difference between models
+ norms/maps = list of list of strs
+ these have to be compatible with the final number of rows and columns
+ in the plot. First index in the list runs over the columns (models and their difference),
+ second index runs over the rows (vars).
+
+ Output
+ -------
+ Plots the (2D) data using imshow. Note that the plotting data's coordinates
+ may not perfectly match the input coordinates if method=raw_data as
+ nearest-cell data is used where the input coordinates do not coincide
+ with the model's raw data coordinates.
+
+ """
+ if len(var_strs) != len(models):
+ print("I need a list of vars to plot per model. Check!")
+ return None
+ num_vars_1st_model = len(var_strs[0])
+ for i in range(1, len(var_strs)):
+ if len(var_strs[i]) != num_vars_1st_model:
+ print("The number of variables per model must be the same. Exiting.")
+ return None
+
+
+ n_cols = len(models)
+ if diff_plot:
+ if len(models)!=2:
+ print("Can plot the difference between TWO models, not more.")
+ else:
+ n_cols+=1
+ if rel_diff:
+ if len(models)!=2:
+ print("Can plot the difference between TWO models, not more.")
+ else:
+ n_cols+=1
+
+ n_rows = len(var_strs[0])
+ if len(var_strs[0])>3:
+ print("This function is meant to compare up to 3 vars. Plotting the first three.")
+ n_rows = 3
+
+ if not components_indices:
+ print('No list of components indices passed: setting this to an empty list.')
+ empty_tuple_components = [ () for _ in range(len(var_strs[0]))]
+ components_indices = []
+ for i in range(len(models)):
+ components_indices.append(empty_tuple_components)
+
+ inv_fig_shape = (n_cols, n_rows)
+ if not norms or np.array(norms).shape != inv_fig_shape:
+ print('Norms provided are not compatible with figure, setting these to auto')
+ norms = [None for _ in range(n_rows)]
+ norms = [norms for _ in range(n_cols)]
+
+ if not cmaps or np.array(cmaps).shape != inv_fig_shape:
+ print('Colormaps not compatible with figure, setting these to auto')
+ cmaps = [None for _ in range(n_rows)]
+ cmaps = [cmaps for _ in range(n_cols)]
+
+
+ figsize = self.screen_size
+ fig, axes = plt.subplots(n_rows, n_cols, squeeze=False, figsize=figsize)
+
+ for j in range(len(models)):
+ for i in range(n_rows):
+
+ data_to_plot, extent = self.get_var_data(models[j], var_strs[j][i], t, x_range, y_range, components_indices[j][i], 'raw_data', None)
+
+ if norms[j][i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(data_to_plot)
+ data_to_plot = MySymLogPlotting.symlog_var(data_to_plot)
+ mynorm = MyThreeNodesNorm(nodes)
+ im = axes[i,j].imshow(data_to_plot, extent=extent, origin='lower', norm=mynorm, cmap=cmaps[j][i])
+ divider = make_axes_locatable(axes[i,j])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ elif norms[j][i] != 'mysymlog':
+ im = axes[i,j].imshow(data_to_plot, extent=extent, origin='lower', norm=norms[j][i], cmap=cmaps[j][i])
+ divider = make_axes_locatable(axes[i,j])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+
+ # im=axes[i,j].imshow(data_to_plot, extent=extent, norm=norms[j][i], cmap=cmaps[j][i])
+ # divider = make_axes_locatable(axes[i,j])
+ # cax = divider.append_axes('right', size='5%', pad=0.05)
+ # fig.colorbar(im, cax=cax, orientation='vertical')
+ # title = models[j].get_model_name() + "\n"+var_strs[j][i]
+
+ # title = models[j].get_model_name() + '\n'
+ title = ''
+ if hasattr(models[j], 'labels_var_dict'):
+ if var_strs[j][i] in models[j].labels_var_dict.keys():
+ title += models[j].labels_var_dict[var_strs[j][i]]
+ else:
+ title += var_strs[j][i]
+ else:
+ title += var_strs[j][i]
+
+ if components_indices[j][i] != ():
+ title += " {}-component".format(components_indices[j][i])
+ axes[i,j].set_title(title)
+ axes[i,j].set_xlabel(r'$x$')
+ axes[i,j].set_ylabel(r'$y$')
+
+
+
+ if diff_plot and len(models)==2:
+ try:
+ for i in range(len(var_strs[0])):
+ data1, extent1 = self.get_var_data(models[0], var_strs[0][i], t, x_range, y_range, components_indices[0][i], method, interp_dims)
+ data2, extent2 = self.get_var_data(models[1], var_strs[1][i], t, x_range, y_range, components_indices[1][i], method, interp_dims)
+ if extent1 != extent2:
+ print("Cannot plot the difference between the vars: data not aligned.")
+ continue
+ data_to_plot = data1 - data2
+
+ if norms[2][i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(data_to_plot)
+ data_to_plot = MySymLogPlotting.symlog_var(data_to_plot)
+ mynorm = MyThreeNodesNorm(nodes)
+ im = axes[i,2].imshow(data_to_plot, extent=extent, origin='lower', norm=mynorm, cmap=cmaps[2][i])
+ divider = make_axes_locatable(axes[i,2])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ elif norms[2][i] != 'mysymlog':
+ im = axes[i,2].imshow(data_to_plot, extent=extent, origin='lower', norm=norms[2][i], cmap=cmaps[2][i])
+ divider = make_axes_locatable(axes[i,2])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+
+
+ # im = axes[i,2].imshow(data_to_plot, extent=extent1, norm=norms[2][i], cmap=cmaps[2][i])
+ # divider = make_axes_locatable(axes[i,2])
+ # cax = divider.append_axes('right', size='5%', pad=0.05)
+ # fig.colorbar(im, cax=cax, orientation='vertical')
+
+
+ axes[i,2].set_title('Models difference')
+ axes[i,2].set_xlabel(r'$y$')
+ axes[i,2].set_ylabel(r'$x$')
+ except ValueError as v:
+ print(f"Cannot plot the difference between {var_strs} in the two "+\
+ f"models. Caught a value error: {v}")
+
+
+ if rel_diff and len(models)==2:
+ try:
+ for i in range(len(var_strs[0])):
+ data1, extent1 = self.get_var_data(models[0], var_strs[0][i], t, x_range, y_range, components_indices[0][i], method, interp_dims)
+ data2, extent2 = self.get_var_data(models[1], var_strs[1][i], t, x_range, y_range, components_indices[1][i], method, interp_dims)
+ if extent1 != extent2:
+ print("Cannot plot the difference between the vars: data not aligned.")
+ continue
+ ar_mean = (np.abs(data1) + np.abs(data2))/2
+ data_to_plot = np.abs(data1 -data2)/ar_mean
+ if diff_plot:
+ column = 3
+ else:
+ column = 2
+
+
+ if norms[column][i] == 'mysymlog':
+ ticks, labels, nodes = MySymLogPlotting.get_mysymlog_var_ticks(data_to_plot)
+ data_to_plot = MySymLogPlotting.symlog_var(data_to_plot)
+ mynorm = MyThreeNodesNorm(nodes)
+ im = axes[i,column].imshow(data_to_plot, extent=extent, origin='lower', norm=mynorm, cmap=cmaps[column][i])
+ divider = make_axes_locatable(axes[i,column])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ cbar = fig.colorbar(im, cax=cax, orientation='vertical')
+ cbar.set_ticks(ticks)
+ cbar.ax.set_yticklabels(labels)
+
+ elif norms[column][i] != 'mysymlog':
+ im = axes[i,column].imshow(data_to_plot, extent=extent, origin='lower', norm=norms[column][i], cmap=cmaps[column][i])
+ divider = make_axes_locatable(axes[i,column])
+ cax = divider.append_axes('right', size='5%', pad=0.05)
+ fig.colorbar(im, cax=cax, orientation='vertical')
+
+ # im = axes[i,column].imshow(data_to_plot, extent=extent1, norm=norms[column][i], cmap=cmaps[column][i])
+ # divider = make_axes_locatable(axes[i,column])
+ # cax = divider.append_axes('right', size='5%', pad=0.05)
+ # fig.colorbar(im, cax=cax, orientation='vertical')
+
+ axes[i,column].set_title('Relative difference')
+ axes[i,column].set_xlabel(r'$y$')
+ axes[i,column].set_ylabel(r'$x$')
+ except ValueError as v:
+ print(f"Cannot plot the difference between {var_strs} in the two "+\
+ f"models. Caught a value error: {v}")
+
+
+ models_names = [model.get_model_name() for model in models]
+ suptitle = "Comparing "
+ for i in range(len(models_names)):
+ suptitle += models_names[i] + ", "
+ suptitle += "models."
+ # fig.suptitle(suptitle)
+ fig.tight_layout()
+ # plt.subplot_tool()
+ return fig
+
+
+
+if __name__ == '__main__':
+
+ FileReader = METHOD_HDF5('../Data/test_res100/')
+ micro_model = IdealMHD_2D()
+ FileReader.read_in_data(micro_model)
+ micro_model.setup_structures()
+
+
+ visualizer = Plotter_2D([11.97, 8.36])
+ print('Finished initializing')
+
+ # TESTING GET_VAR_DATA
+ ######################
+ # var = 'BC'
+ # components = (0,2)
+ # data1= visualizer.get_var_data(micro_model, var, 1.502, [0.3, 0.4], [0.3,0.4], component_indices=components)[0]
+ # data, extent= visualizer.get_var_data(micro_model, var, 1.502, [0.3, 0.4], [0.3,0.4], component_indices=components, method='interpolate', interp_dims=(20,20))
+ # print(extent)
+
+ # TESTING PLOT_VARS
+ ###################
+ # vars = ['BC', 'vx', 'vy', 'Bz', 'p', 'W']
+ # components = [(0,), (), (), (), (), ()]
+ # model = micro_model
+ # visualizer.plot_vars(model, vars, 1.502, [0.01, 0.98], [0.01, 0.98], components_indices=components)
+ # visualizer.plot_vars(model, vars, 1.502, [0.01, 0.98], [0.01, 0.98], method = 'interpolate', interp_dims=(100,100), components_indices=components)
+
+
+ # TESTING PLOT_VAR_MODEL_COMPARISON
+ ###################################
+ find_obs = FindObs_drift_root(micro_model, 0.001)
+ filter = spatial_box_filter(micro_model, 0.003)
+ meso_model = resMHD2D(micro_model, find_obs, filter)
+ ranges = [0.2, 0.25]
+ meso_model.setup_meso_grid([[1.501, 1.503],ranges, ranges], coarse_factor=1)
+ meso_model.find_observers()
+ meso_model.filter_micro_variables()
+
+ print("Finished filtering")
+
+ vars = [['BC'], ['BC']]
+ models = [micro_model, meso_model]
+ components = [[(0,)],[(0,)]]
+ norms = [['log'], ['log'], ['symlog']]
+ cmaps=None
+ # cmaps = [['seismic'], ['seismic'], ['seismic']]
+ # smaller_ranges = [ranges[0]+0.01, ranges[1]- 0.01] # Needed to avoid interpolation errors at boundaries
+ # visualizer.plot_var_model_comparison(models, var, 1.502, smaller_ranges, smaller_ranges, \
+ # method='interpolate', interp_dims=(30,30), component_indices=component)
+ visualizer.plot_vars_models_comparison(models, vars, 1.502, ranges, ranges, components_indices=components, diff_plot=True, rel_diff = False,
+ norms=norms, cmaps=cmaps)
+ plt.show()
diff --git a/master_files/system/BaseFunctionality.py b/master_files/system/BaseFunctionality.py
new file mode 100644
index 0000000..58771b6
--- /dev/null
+++ b/master_files/system/BaseFunctionality.py
@@ -0,0 +1,398 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Nov 2 17:21:02 2022
+
+@author: mjh1n20
+"""
+
+# from multiprocessing import Process, Pool
+import numpy as np
+# from timeit import default_timer as timer
+import cProfile, pstats, io
+import math
+import matplotlib as mpl
+import matplotlib.pyplot as plt
+from mpl_toolkits.axes_grid1 import make_axes_locatable
+import random
+
+class Base(object):
+ @staticmethod
+ def Mink_dot(vec1, vec2):
+ """
+ Parameters:
+ -----------
+ vec1, vec2 : list of floats (or np.arrays)
+
+ Return:
+ -------
+ mink-dot (cartesian) in 1+n dim
+ """
+ if len(vec1) != len(vec2):
+ print("The two vectors passed to Mink_dot are not of same dimension!")
+
+ dot = -vec1[0]*vec2[0]
+ for i in range(1,len(vec1)):
+ dot += vec1[i] * vec2[i]
+ return dot
+
+ @staticmethod
+ def get_rel_vel(spatial_vels):
+ """
+ Build unit vectors starting from spatial components
+ Needed as this will enter the minimization procedure
+
+ Parameters:
+ ----------
+ spatial_vels: list of floats
+
+ Returns:
+ --------
+ list of floats: the d+1 vector, normalized wrt Mink metric
+ """
+ W = 1 / np.sqrt(1-np.sum(spatial_vels**2))
+ return W * np.insert(spatial_vels,0,1.0)
+
+ @staticmethod
+ def project_tensor(vector1_wrt, vector2_wrt, to_project):
+ """
+ """
+ return np.inner(vector1_wrt,np.inner(vector2_wrt,to_project))
+
+
+ @staticmethod
+ def orthogonal_projector(u, metric):
+ """
+ Returns:
+ --------
+ Orthogonal projector wrt vector u
+
+ Notes:
+ ------
+ The vector u must be time-like
+ """
+ return metric + np.outer(u,u)
+
+
+ """
+ A pair of functions that work in conjuction (thank you stack overflow).
+ find_nearest returns the closest value to 'value' in 'array',
+ find_nearest_cell then takes this closest value and returns its indices.
+ Should now work for any dimensional data.
+ """
+ @staticmethod
+ def find_nearest(array, value):
+ """
+ Returns closest value to input 'value' in 'array'
+
+ Parameters:
+ -----------
+ array: np.array of shape (n,)
+
+ value: float
+
+ Returns:
+ --------
+ float
+
+ Note:
+ -----
+ To be used together with find_nearest_cell.
+ """
+ idx = np.searchsorted(array, value, side="left")
+ if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
+ return array[idx-1]
+ else:
+ return array[idx]
+
+ @staticmethod
+ def find_nearest_cell(point, points):
+ """
+ Use find nearest to find closest value in a list of input 'points' to
+ input 'point'.
+
+ Parameters:
+ -----------
+ point: list of d+1 float
+
+ points: list of lists of d+1 floats
+
+ Returns:
+ --------
+ List of d+1 indices corresponding to closest value to point in points
+ """
+ if len(points) != len(point):
+ print("find_nearest_cell: The length of the coordinate vector\
+ does not match the length of the coordinates.")
+ positions = []
+ for dim in range(len(point)):
+ positions.append(Base.find_nearest(points[dim], point[dim]))
+ return [np.where(points[i] == positions[i])[0][0] for i in range(len(positions))]
+
+ def profile(self, fnc):
+ """A decorator that uses cProfile to profile a function"""
+ def inner(*args, **kwargs):
+ pr = cProfile.Profile()
+ pr.enable()
+ retval = fnc(*args, **kwargs)
+ pr.disable()
+ s = io.StringIO()
+ sortby = 'cumulative'
+ ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
+ ps.print_stats()
+ print(s.getvalue())
+ return retval
+ return inner
+
+class MySymLogPlotting(object):
+
+ @staticmethod
+ def symlog_num(num):
+ """
+ Return the symlog of a number
+
+ Parameters:
+ -----------
+ num: float
+
+ Returns:
+ --------
+ The symlog of the input num (separate copy)
+ """
+ if np.abs(num) +1. == 1.0:
+ result = num
+ else:
+ result = np.sign(num) * np.log10(np.abs(num)+1.)
+ return result
+
+ @staticmethod
+ def inverse_symlog_num(num):
+ if num > 0:
+ return 1 + 10 ** num
+ elif num < 0:
+ return 1- 10 ** (- num)
+ else:
+ return 0
+
+ @staticmethod
+ def symlog_var(var):
+ """
+ Return the symlog of an array.
+
+ Parameters:
+ -----------
+ var: np.array of any shape
+
+ Returns:
+ --------
+ The symlog of the input var (separate copy)
+ """
+ count_zeros=0
+ temp = np.empty_like(var)
+ for index in np.ndindex(var.shape):
+ value = var[index]
+ if value == 0:
+ count_zeros +=1
+ else:
+ temp[index] = MySymLogPlotting.symlog_num(value)
+ if count_zeros >= 1:
+ print('Careful: there are {} zeros in the data'.format(count_zeros))
+ return temp
+
+ @staticmethod
+ def get_mysymlog_var_ticks(var):
+ """
+ Method to automatize the computation of the ticks and nodes for a variable.
+ Nodes are then to be used within the class MyThreeNodesNorm.
+ Ticks and labels are for the colorbar of the plot of input 'var'.
+
+ Parameters:
+ -----------
+ var: np.array
+ This HAS TO take both positive and negative values
+
+ Returns:
+ --------
+ ticks: list
+ list of tick points to be used by the colorbar
+
+ ticks_labels: list
+ list of corresponding labels for the colorbar
+
+ nodes: list of len=5
+ the extrame and the three central nodes to be used by MyThreeNodesNorm
+
+ Notes:
+ ------
+ The ticks/nodes and labels are computed like this: start from negative values, identify min
+ and max values of the negative part of input 'var' to identify relevant ticks and nodes.
+ Then add a zero (tick and node) and proceed to the positive values.
+ """
+ ticks = []
+ ticks_labels = []
+ nodes = []
+
+
+ pos_var = np.ma.masked_where(var <0., var, copy=True).compressed()
+ pos_var_small = np.ma.masked_where(pos_var >=1., pos_var, copy=True).compressed()
+ pos_var_large = np.ma.masked_where(pos_var <1., pos_var, copy=True).compressed()
+
+ neg_var = np.ma.masked_where(var >0., var, copy=True).compressed()
+ neg_var_small = np.ma.masked_where(neg_var <=-1., neg_var, copy=True).compressed()
+ neg_var_large = np.ma.masked_where(neg_var >-1., neg_var, copy=True).compressed()
+
+ # Working out nodes, ticks and ticks_labels for the negative range
+ if len(neg_var_large) >0:
+ # print('There are negative large values', flush=True)
+ vmin = np.amin(neg_var_large)
+ new_nodes = [MySymLogPlotting.symlog_num(vmin)]
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$-10^{%d}$'%(int(np.log10(-vmin)))]
+
+ nodes += new_nodes
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+
+
+ if len(neg_var_small) == 0:
+ # print('Actually: only negative large values', flush=True)
+ vmax = np.amax(neg_var_large)
+ new_nodes = [MySymLogPlotting.symlog_num(vmax)]
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$-10^{%d}$'%(int(np.log10(-vmax)))]
+
+ nodes += new_nodes
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+
+ else:
+ # print('And also negative small values', flush=True)
+ vmin = np.amin(neg_var_small)
+ vmax = np.amax(neg_var_small)
+
+ new_nodes = [MySymLogPlotting.symlog_num(vmax)]
+ # new_ticks = [symlog_num(vmin), symlog_num(vmax)]
+ new_ticks = [MySymLogPlotting.symlog_num(vmax)]
+ # new_ticks_labels = [r'$-10^{%d}$'%(int(d)) for d in np.log10([-vmin,-vmax])]
+ new_ticks_labels = [r'$-10^{%d}$'%(int(d)) for d in np.log10([-vmax])]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+ else: # len(neg_var_large)==0:
+ # print('Only negative small values', flush=True)
+ vmin = np.amin(neg_var_small)
+ vmax = np.amax(neg_var_small)
+
+ # print(vmin, vmax, "\n")
+ new_nodes = [MySymLogPlotting.symlog_num(vmin), MySymLogPlotting.symlog_num(vmax)]
+ # print(new_nodes)
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$-10^{%d}$'%(int(d)) for d in np.log10([-vmin,-vmax])]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+
+ nodes += [0.]
+ ticks += [0.]
+ ticks_labels += ['0']
+
+ # Working out the remaining nodes, ticks and ticks_labels for the positive range
+
+ if len(pos_var_large)==0:
+ # print('Only positive small values', flush=True)
+ vmin = np.amin(pos_var_small)
+ vmax = np.amax(pos_var_small)
+
+ # print(vmin, vmax)
+ new_nodes = [MySymLogPlotting.symlog_num(vmin), MySymLogPlotting.symlog_num(vmax)]
+ # print(new_nodes)
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$10^{%d}$'%(int(d)) for d in np.log10([vmin,vmax])]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+ else: # len(pos_var_large) > 0:
+ # print('There are positive large values', flush=True)
+
+ if len(pos_var_small) >0:
+ # print('And also positive small values', flush=True)
+ vmin = np.amin(pos_var_small)
+ vmax = np.amax(pos_var_small)
+
+ # new_nodes = [symlog_num(vmax)]
+ new_nodes = [MySymLogPlotting.symlog_num(vmin)]
+ # new_ticks = [symlog_num(vmin), symlog_num(vmax)]
+ new_ticks = [MySymLogPlotting.symlog_num(vmin)]
+ # new_ticks_labels = [r'$10^{%d}$'%(int(d)) for d in np.log10([vmin,vmax])]
+ new_ticks_labels = [r'$10^{%d}$'%(int(d)) for d in np.log10([vmin])]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+ vmax = np.amax(pos_var_large)
+ new_nodes = [MySymLogPlotting.symlog_num(vmax)]
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$10^{%d}$'%(int(np.log10(vmax)))]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+
+ else: # len(pos_var_small) ==0:
+ vmin = np.amin(pos_var_large)
+ vmax = np.amax(pos_var_large)
+
+ new_nodes = [MySymLogPlotting.symlog_num(vmin), MySymLogPlotting.symlog_num(vmax)]
+ new_ticks = new_nodes
+ new_ticks_labels = [r'$10^{%d}$'%(int(d)) for d in np.log10([vmin,vmax])]
+
+ ticks += new_ticks
+ ticks_labels += new_ticks_labels
+ nodes += new_nodes
+
+ return ticks, ticks_labels, nodes
+
+class MyThreeNodesNorm(mpl.colors.Normalize):
+ """
+ Sub-classing colors.Normalize: the norm has three inner nodes plus the extrema.
+ Within each segment (delimited by a node or extrema) you have linear interpolation.
+
+ Should be used when plotting quantities that are both positive and negative, and you
+ want to highlight 1) where a critical value (middle_node) is 2) the closest values some
+ variable takes to its left and right
+ """
+ def __init__(self, nodes, clip=False):
+ """
+ Parameters:
+
+ nodes: array of five numbers in strictly ascending order (the nodes)
+ """
+ if len(nodes)!=5:
+ raise ValueError('The class MyThreeNodesNorm requires 5 nodes: the extrema and the three central')
+
+ for i in range(len(nodes)-1):
+ if nodes[i+1] <=nodes[i]:
+ raise ValueError('nodes must be in monotonically ascending order!')
+
+ super().__init__(nodes[0], nodes[4], clip)
+ self.first_node = nodes[1]
+ self.central_node = nodes[2]
+ self.third_node = nodes[3]
+
+ def __call__(self, value, clip=None):
+ x = [self.vmin, self.first_node, self.central_node, self.third_node, self.vmax]
+ y = [0, 0.4, 0.5, 0.6, 1.]
+ return np.ma.masked_array(np.interp(value, x, y,
+ left=-np.inf, right=np.inf))
+
+ def inverse(self, value):
+ y = [self.vmin, self.first_node, self.central_node, self.third_node, self.vmax]
+ x = [0, 0.4, 0.5, 0.6, 1.]
+ return np.interp(value, x, y, left=-np.inf, right=np.inf)
diff --git a/system/BaseFunctionality.py b/system/BaseFunctionality.py
deleted file mode 100644
index c48f439..0000000
--- a/system/BaseFunctionality.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Created on Wed Nov 2 17:21:02 2022
-
-@author: mjh1n20
-"""
-
-from multiprocessing import Process, Pool
-import os
-import numpy as np
-#import matplotlib.pyplot as plt
-import pickle
-from timeit import default_timer as timer
-import h5py
-from scipy.interpolate import interpn
-from scipy.optimize import root, minimize
-#from mpl_toolkits.mplot3d import Axes3D
-from scipy.integrate import solve_ivp, quad
-import cProfile, pstats, io
-import math
-
-class Base(object):
-
- @staticmethod
- def Mink_dot(vec1,vec2):
- """
- Parameters:
- -----------
- vec1, vec2 : list of floats (or np.arrays)
-
- Return:
- -------
- mink-dot (cartesian) in 1+n dim
- """
- if len(vec1) != len(vec2):
- print("The two vectors passed to Mink_dot are not of same dimension!")
-
- dot = -vec1[0]*vec2[0]
- for i in range(1,len(vec1)):
- dot += vec1[i] * vec2[i]
- return dot
-
- @staticmethod
- def get_rel_vel(spatial_vels):
- """
- Build unit vectors starting from spatial components
- Needed as this will enter the minimization procedure
-
- Parameters:
- ----------
- spatial_vels: list of floats
-
- Returns:
- --------
- list of floats: the d+1 vector, normalized wrt Mink metric
- """
- W = 1 / np.sqrt(1-np.sum(spatial_vels**2))
- return W * np.insert(spatial_vels,0,1.0)
-
- @staticmethod
- def project_tensor(vector1_wrt, vector2_wrt, to_project):
- return np.inner(vector1_wrt,np.inner(vector2_wrt,to_project))
-
- @staticmethod
- def orthogonal_projector(u, metric):
- return metric + np.outer(u,u)
-
-
- """
- A pair of functions that work in conjuction (thank you stack overflow).
- find_nearest returns the closest value to 'value' in 'array',
- find_nearest_cell then takes this closest value and returns its indices.
- Should now work for any dimensional data.
- """
- @staticmethod
- def find_nearest(array, value):
- idx = np.searchsorted(array, value, side="left")
- if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
- return array[idx-1]
- else:
- return array[idx]
-
- @staticmethod
- def find_nearest_cell(point, points):
- if len(points) != len(point):
- print("find_nearest_cell: The length of the coordinate vector\
- does not match the length of the coordinates.")
- positions = []
- for dim in range(len(point)):
- positions.append(Base.find_nearest(points[dim], point[dim]))
- return [np.where(points[i] == positions[i])[0][0] for i in range(len(positions))]
-
- def profile(self, fnc):
- """A decorator that uses cProfile to profile a function"""
- def inner(*args, **kwargs):
- pr = cProfile.Profile()
- pr.enable()
- retval = fnc(*args, **kwargs)
- pr.disable()
- s = io.StringIO()
- sortby = 'cumulative'
- ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
- ps.print_stats()
- print(s.getvalue())
- return retval
- return inner
diff --git a/system/__pycache__/BaseFunctionality.cpython-36.pyc b/system/__pycache__/BaseFunctionality.cpython-36.pyc
deleted file mode 100644
index f323591..0000000
Binary files a/system/__pycache__/BaseFunctionality.cpython-36.pyc and /dev/null differ