Source code for turbodesign.lossinterp

from typing import List, Tuple, Union
import pandas as pd 
import numpy as np 
import numpy.typing as npt
from scipy.interpolate import bisplrep, bisplev, interp1d, LSQBivariateSpline
import matplotlib.pyplot as plt 


[docs] class LossInterp: """Interpret the loss of an XY Graph with an additional 3rd variable """ df: pd.DataFrame x:np.ndarray y:np.ndarray c:np.ndarray x_max_c:np.ndarray x_min_c:np.ndarray c_max:float c_min:float fxc_max: interp1d fxc_min: interp1d weights: np.ndarray xlabel:str ylabel:str clabel:str _name:str is_xy:bool func: interp1d xlogscale:bool @property def name(self): return self._name @name.setter def name(self,val:str): self._name = val def __init__(self,csv_filename:str,xlabel:str="",ylabel:str="",clabel:str="",logx10:bool=False): """Initialize the loss interpolation with data Note: The data contains x,y, and c. Y is predicted from x and c Args: csv_filename (str): csv data with 3 columns, x,y,c. xlabel (str, optional): xlabel. Defaults to "". ylabel (str, optional): ylabel. Defaults to "". clabel (str, optional): clabel. Defaults to "". logx10 (bool, optional): apply log base 10 to x axis. Defaults to False """ self.df = pd.read_csv(csv_filename) self.df = self.df.sort_values(self.df.columns[0],ascending=True) self.name = csv_filename data = self.df.to_numpy() self.xlabel = xlabel self.ylabel = ylabel self.logX10 = logx10 if data.shape[1] == 3: self.x = data[:,0] self.y = data[:,1] self.c = data[:,2] self.clabel = clabel # Find the minimum x value for every item in row self.x_max_c = np.zeros(shape=(len(self.df.iloc[:,2].unique()),2)) self.x_min_c = np.zeros(shape=(len(self.df.iloc[:,2].unique()),2)) i = 0 for inlet_flow in self.df.iloc[:,2].unique(): df_slice = self.df[self.df.iloc[:,2] == inlet_flow] df_slice = df_slice.sort_values(df_slice.columns[0],ascending=True) self.x_max_c[i,0] = inlet_flow self.x_max_c[i,1] = df_slice.iloc[:,0].max() self.x_min_c[i,0] = inlet_flow self.x_min_c[i,1] = df_slice.iloc[:,0].min() i+=1 self.fxc_max = interp1d(self.x_max_c[:,0],self.x_max_c[:,1]) # xmax as a function of c self.fxc_min = interp1d(self.x_min_c[:,0],self.x_min_c[:,1]) # xmin as a function of c # self.weights = bisplrep(self.x,self.c,self.y,kx=5, ky=5) if self.logX10: self.func = LSQBivariateSpline(np.log10(self.x),self.c,self.y,np.log10(np.unique(self.x[:4])),np.unique(self.c[:4])) else: self.func = LSQBivariateSpline(self.x,self.c,self.y,np.unique(self.x[:3]),np.unique(self.c[:3])) self.is_xy = False # 3 columns self.c_max = self.df.to_numpy()[:,-1].max() self.c_min = self.df.to_numpy()[:,-1].min() else: self.is_xy = True self.x = data[:,0] self.y = data[:,1] if self.logX10: self.func = interp1d(np.log10(self.x),self.y) else: self.func = interp1d(self.x,self.y)
[docs] def __call__(self,x:Union[npt.NDArray,float],c:Union[npt.NDArray,float,None]=None) -> float: """Pass in an array of x and c values Args: x (Union[npt.NDArray,float]): value on x axis c (Union[npt.NDArray,float,None]): Third axis value Returns: float: y """ if self.is_xy or c==None: if self.logX10: x = np.log10(x) if isinstance(x, np.ndarray): return self.func(x) elif isinstance(x, float): return float(self.func(x)) else: if isinstance(x, np.ndarray): xmax = self.fxc_max(c) xmin = self.fxc_min(c) x[x>xmax] = xmax x[x<xmin] = xmin if self.logX10: y = self.func(np.log10(x),c) else: y = self.func(x,c) elif isinstance(x, float): if (c>self.c_max): c = self.c_max elif c<self.c_min: c = self.c_min xmax = float(self.fxc_max(c)) xmin = float(self.fxc_min(c)) x = xmin if x<xmin else x x = xmax if x>xmax else x # y[j] = bisplev(x[j],cc,self.weights) if self.logX10: y = self.func(np.log10(x),c)[0][0] # type: ignore else: y = self.func(x,c)[0][0] # type: ignore return y
[docs] def plot(self): """Plot the data with predicted values """ plt.figure(num=1,figsize=(10,6)) if not self.is_xy: c_unique = np.unique(self.c) graycolors = plt.cm.gray(np.linspace(0,1,len(c_unique))) coolcolors = plt.cm.cool(np.linspace(0,1,len(c_unique))) # Plot the actual data i = 0 for c in c_unique: df2 = self.df[self.df.iloc[:,2] == c] x = df2.iloc[:,0].to_numpy() plt.plot(x,df2.iloc[:,1],'.-',label=f'{c}',color=graycolors[i]) y = self(x,c) plt.plot(x,y,'o-',label=f'predicted-{c}',color=coolcolors[i]) i+=1 else: x = self.df.iloc[:,0].to_numpy() plt.plot(x,self.df.iloc[:,1],'ro',linewidth=2,label='actual') y = self(x) plt.plot(x,y,'b-',label='predicted') plt.ylabel(self.ylabel) plt.xlabel(self.xlabel) plt.title(self.name) plt.legend() plt.show()