Example #1
0
    def __init__(self, OC, surrogate_model, relative_thickness=.12, camber=0., Sref=1., Lref=1., sweep=0., surrogate_fcs=None):

        Airfoil.__init__(self, OC, Sref, Lref, relative_thickness, sweep, camber)
        if not surrogate_fcs:
            self.__coefs = SurrogateCoefs(surrogate_model)
        else:
            self.__coefs = surrogate_fcs
        self.__surrogate_model = surrogate_model
Example #2
0
    def __init__(self,
                 OC,
                 surrogate_model,
                 relative_thickness=.12,
                 camber=0.,
                 Sref=1.,
                 Lref=1.,
                 sweep=0.,
                 surrogate_fcs=None):

        Airfoil.__init__(self, OC, Sref, Lref, relative_thickness, sweep,
                         camber)
        if not surrogate_fcs:
            self.__coefs = SurrogateCoefs(surrogate_model)
        else:
            self.__coefs = surrogate_fcs
        self.__surrogate_model = surrogate_model
Example #3
0
class MetaAirfoil(Airfoil):
    """
    A meta model based on 2D CFD data
    Provide lift, drag and moment coefficients
    Provide sensitivities of aerodynamic surrogate function w.r.t. input parameters
    """
    POW_COS  = 1.0
    
    def __init__(self, OC, surrogate_model, relative_thickness=.12, camber=0., Sref=1., Lref=1., sweep=0., surrogate_fcs=None):

        Airfoil.__init__(self, OC, Sref, Lref, relative_thickness, sweep, camber)
        if not surrogate_fcs:
            self.__coefs = SurrogateCoefs(surrogate_model)
        else:
            self.__coefs = surrogate_fcs
        self.__surrogate_model = surrogate_model
        
    def Cl(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal = Mach*np.cos(sweep)**self.POW_COS
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        sweep_corr = np.cos(self.get_sweep())**(2.*self.POW_COS)
        
        return Cl*sweep_corr
    
    def ClAlpha(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)**self.POW_COS
        ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
        dCl_dAoA = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha, Mach_normal)[2]
        sweep_corr = np.cos(self.get_sweep())**(2.*self.POW_COS)
        
        return dCl_dAoA*sweep_corr
    
    def Cd(self, alpha, Mach):
        Cdf = self.__Cd_friction(alpha, Mach)
        Cdp = self.Cdp(alpha, Mach)
        
        return Cdf + Cdp
    
    def Cdp(self, alpha, Mach):
        
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)**self.POW_COS
        ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
        Cd = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha, Mach_normal)  
        
        Cds = self.Cd_spurious(alpha, Mach)
        
        Cdp = max([Cd-Cds,  0.])
        
        return Cdp
    
    def CdpAlpha(self, alpha, Mach):
        
        Cdp = self.Cdp(alpha, Mach)
        
        if Cdp == 0.:
            dCdp_dAoA = 0.
            
        else:
            Cdsalpha = self.CdsAlpha(alpha, Mach)
            
            sweep=self.get_sweep()
            Mach_normal= Mach*np.cos(sweep)**self.POW_COS
            ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
            dCdp_dAoA = self.__coefs.grad_Cd(ToC, self.get_camber(), alpha, Mach_normal)[2] - Cdsalpha
        
        return dCdp_dAoA
        
    def CdAlpha(self, alpha, Mach):
        dCdp_dAoA = self.CdpAlpha(alpha, Mach) 
        dCdf_AoA = self.__dCd_friction_dAoA(alpha, Mach)
        
        return dCdp_dAoA+dCdf_AoA
        
    def Cm(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)**self.POW_COS
        ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
        Cm = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha, Mach_normal)  
        sweep_corr = np.cos(self.get_sweep())**(2.*self.POW_COS)
        
        return Cm*sweep_corr
    
    def dCl_dchi(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal = Mach*np.cos(sweep)**self.POW_COS
        ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        
        dsweep=self.get_sweep_grad()
        sweep_corr = np.cos(self.get_sweep())**(2.*self.POW_COS)
        dsweep_corr = -2.*self.POW_COS*np.sin(sweep)*dsweep*np.cos(sweep)**(2.*self.POW_COS-1.)
        
        dCl_dToC= self.gradCl(alpha, Mach)[0]
        dToC_dchi = 100.*(self.get_rel_thick_grad()*np.cos(sweep)**self.POW_COS+self.POW_COS*self.get_rel_thick()*np.sin(sweep)*dsweep*np.cos(sweep)**(self.POW_COS-1.))/np.cos(sweep)**(2*self.POW_COS)
        
        dCl_dMach = self.gradCl(alpha, Mach)[3]
        dMach_dchi = -self.POW_COS*Mach*np.sin(sweep)*dsweep*np.cos(sweep)**(self.POW_COS-1.)
        
    
        return (dCl_dToC*dToC_dchi + dCl_dMach*dMach_dchi)*sweep_corr + Cl*dsweep_corr
        
    def dCd_dchi(self, alpha, Mach):
        dCdf_dchi = self.__dCd_friction_dchi(alpha, Mach)
        dCdp_dchi = self.dCdp_dchi(alpha, Mach)
        
        return dCdf_dchi + dCdp_dchi
        
    def dCdp_dchi(self, alpha, Mach):
        
        Cdp = self.Cdp(alpha, Mach)
        
        if Cdp != 0:
            sweep=self.get_sweep()
            Mach_normal = Mach*np.cos(sweep)**self.POW_COS
            ToC=self.get_rel_thick()/np.cos(sweep)**self.POW_COS*100.
            Cd = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha, Mach_normal)
            
            dsweep=self.get_sweep_grad()
            
            dCdp_dToC = self.gradCd(alpha, Mach)[0]
            dToC_dchi = 100.*(self.get_rel_thick_grad()*np.cos(sweep)**self.POW_COS+self.POW_COS*self.get_rel_thick()*np.sin(sweep)*dsweep*np.cos(sweep)**(self.POW_COS-1.))/np.cos(sweep)**(2*self.POW_COS)
            
            dCdp_dMach = self.gradCd(alpha, Mach)[3]
            dMach_dchi = -self.POW_COS*Mach*np.sin(sweep)*dsweep*np.cos(sweep)**(self.POW_COS-1.)
            
            dCdsdchi = self.dCds_dchi(alpha, Mach)
            
            dCdpdchi = dCdp_dToC*dToC_dchi + dCdp_dMach*dMach_dchi - dCdsdchi
        
        else:
            dCdpdchi = 0.
         
        return dCdpdchi
    
    def Cdf(self, alpha, Mach):
        return self.__Cd_friction(alpha, Mach)
        
    def __Cd_friction(self, alpha, Mach):
        # Re= V_corr*Lref_corr/nu=Mach*cos(sweep)*c*Lref/cos(sweep)/nu = Mach*c*Lref/cos(sweep)
        OC = self.get_OC()
        sweep  = self.get_sweep()
        c  = OC.get_c()
        nu = OC.get_nu()
        L  = self.get_Lref()
        Re = Mach*np.cos(sweep)*c*L/nu
        toc         = self.get_rel_thick()/np.cos(sweep)
        thick_coeff = 1.+2.1*toc # a rough guess since 1.21 for 10% relative thickness
        if Re < 1.e-12:
            # Prevent division by 0. Drag is null at zero Re number anyway
            Cdf = 0.
        elif Re < 1.e5:
            # Laminar flow
            Cdf=1.328/math.sqrt(Re)*thick_coeff
        else:
            # Turbulent flow
            Cdf=0.074*Re**(-0.2)*thick_coeff
            
        return Cdf
    
    def CdfAlpha(self, alpha, Mach):
        return self.__dCd_friction_dAoA(alpha, Mach)
    
    def __dCd_friction_dAoA(self, alpha, Mach):
        return 0.
    
    def  dCdf_dchi(self, alpha, Mach):
        return self. __dCd_friction_dchi(alpha, Mach)
    
    def __dCd_friction_dchi(self, alpha, Mach):
        OC  = self.get_OC()
        sweep  = self.get_sweep()
        dsweep = self.get_sweep_grad()
        c   = OC.get_c()
        nu  = OC.get_nu()
        L   = self.get_Lref()
        dL  = self.get_Lref_grad()
        
        Re = Mach*np.cos(sweep)*c*L/nu
        dRe = Mach*np.cos(sweep)*c*dL/nu-Mach*np.sin(sweep)*c*L/nu*dsweep
        
        toc    = self.get_rel_thick()/np.cos(sweep)
        dtoc   = (self.get_rel_thick_grad()*np.cos(sweep)+self.get_rel_thick()*np.sin(sweep)*dsweep)/np.cos(sweep)**2
        
        thick_coeff = 1.+2.1*toc
        dthick_coeff = 2.1*dtoc
        
        if Re < 1.e-6:
            # Prevent division by 0. Drag is null at zero Re number anyway
            dCdf = 0.
        elif Re < 1.e5:
            # Laminar flow
            dCdf=-0.664/(Re**1.5)*dRe*thick_coeff+1.328/math.sqrt(Re)*dthick_coeff
        else:
            # Turbulent flow
            dCdf=-0.0148*Re**(-1.2)*dRe*thick_coeff+0.074*Re**(-0.2)*dthick_coeff
        return dCdf
        
    def Cd_spurious(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal = Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        
        k, coef = self.k_coef()
        Cl0 = self.Cl0()
       
        Cds = k + coef*(Cl - Cl0)**2.
        return Cds
        
    def CdsAlpha(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal = Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        Cl_alpha = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha, Mach_normal)[2]
        
        k, coef = self.k_coef()
        Cl0 = self.Cl0()
        
        Cds_alpha = coef*2.*(Cl - Cl0)*Cl_alpha
        
        return Cds_alpha
    
    def dCds_dchi(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal = Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        #dCldchi = self.dCl_dchi(alpha, Mach)
        
        dCl_dToC = self.gradCl(alpha, Mach)[0]
        dToC_dchi = 100.*(self.get_rel_thick_grad()*np.cos(sweep)+self.get_rel_thick()*np.sin(sweep))/np.cos(sweep)**2
        
        dCl_dMach = self.gradCl(alpha, Mach)[3]
        dsweep = self.get_sweep_grad()
        dMach_dchi = -Mach*np.sin(sweep)*dsweep
        
        dCldchi = dCl_dToC*dToC_dchi + dCl_dMach*dMach_dchi
        
        k, coef = self.k_coef()
        dk_dchi, d_coef_dchi = self.d_k_coef_dchi()
        
        Cl0 = self.Cl0()
        dCl0dchi = self.dCl0_dchi()
        
        dCdsdchi = dk_dchi + d_coef_dchi*(Cl - Cl0)**2. + 2.*coef*(Cl - Cl0)*(dCldchi - dCl0dchi) 
        
        return dCdsdchi
        
    def k_coef(self):
        
        k = 0.0045235
        coef = 0.03132053
        
        return k, coef 
    
    def d_k_coef_dchi(self):
        return 0., 0.
    
    def Cl0(self):
        
        Cl0 = 0.16372357
        
        return Cl0
        
    def dCl0_dchi(self):
        return 0.
    
    def gradCl(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        gradCl = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        return gradCl
        
    def gradCd(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        gradCd = self.__coefs.grad_Cd(ToC, self.get_camber(), alpha, Mach_normal)
        return gradCd
        
    def gradCm(self, alpha, Mach):
        sweep=self.get_sweep()
        Mach_normal= Mach*np.cos(sweep)
        ToC=self.get_rel_thick()/np.cos(sweep)*100.
        gradCm = self.__coefs.grad_Cm(ToC, self.get_camber(), alpha, Mach_normal)
        return gradCm
    
#     def dCl_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dthic = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]*100.
#         
#         return dCl_dthic*sweep_corr
#         
#     def dCl_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dcamb = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCl_dcamb*sweep_corr
#         
#     def dCl_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dM = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCl_dM*sweep_corr
#         
#     def dCd_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dthic = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCd_dthic*sweep_corr
#         
#     def dCd_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dcamb = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCd_dcamb*sweep_corr
#         
#     def dCd_dalpha(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dAoA = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[2]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCd_dAoA*sweep_corr
#         
#     def dCd_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dM = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCd_dM*sweep_corr
        
#     def dCm_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dthic = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCm_dthic*sweep_corr
#         
#     def dCm_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dcamb = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCm_dcamb*sweep_corr
#         
#     def dCm_dalpha(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dAoA = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[2]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCm_dAoA*sweep_corr
#         
#     def dCm_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dM = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#         
#         return dCm_dM*sweep_corr
        
    def get_scaled_copy(self, OC=None, Sref=None,Lref=None, rel_thick=None, camber=None, sweep=None):
        if Sref is None:
            Sref=self.get_Sref()
        if Lref is None:
            Lref=self.get_Lref()
        if rel_thick is None:
            rel_thick = self.get_rel_thick()
        if camber is None:
            camber = self.get_camber()
        if sweep is None:
            sweep = self.get_sweep()
        if OC is None:
            OC = self.get_OC()
        return MetaAirfoil(OC, self.__surrogate_model, relative_thickness=rel_thick, camber=camber, Sref=Sref, Lref=Lref, sweep=sweep, surrogate_fcs=self.__coefs)
Example #4
0
class MetaAirfoil(Airfoil):
    """
    A meta model based on 2D CFD data
    Provide lift, drag and moment coefficients
    Provide sensitivities of aerodynamic surrogate function w.r.t. input parameters
    """
    POW_COS = 1.0

    def __init__(self,
                 OC,
                 surrogate_model,
                 relative_thickness=.12,
                 camber=0.,
                 Sref=1.,
                 Lref=1.,
                 sweep=0.,
                 surrogate_fcs=None):

        Airfoil.__init__(self, OC, Sref, Lref, relative_thickness, sweep,
                         camber)
        if not surrogate_fcs:
            self.__coefs = SurrogateCoefs(surrogate_model)
        else:
            self.__coefs = surrogate_fcs
        self.__surrogate_model = surrogate_model

    def Cl(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)**self.POW_COS
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        sweep_corr = np.cos(self.get_sweep())**(2. * self.POW_COS)

        return Cl * sweep_corr

    def ClAlpha(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)**self.POW_COS
        ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
        dCl_dAoA = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha,
                                        Mach_normal)[2]
        sweep_corr = np.cos(self.get_sweep())**(2. * self.POW_COS)

        return dCl_dAoA * sweep_corr

    def Cd(self, alpha, Mach):
        Cdf = self.__Cd_friction(alpha, Mach)
        Cdp = self.Cdp(alpha, Mach)

        return Cdf + Cdp

    def Cdp(self, alpha, Mach):

        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)**self.POW_COS
        ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
        Cd = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha, Mach_normal)

        Cds = self.Cd_spurious(alpha, Mach)

        Cdp = max([Cd - Cds, 0.])

        return Cdp

    def CdpAlpha(self, alpha, Mach):

        Cdp = self.Cdp(alpha, Mach)

        if Cdp == 0.:
            dCdp_dAoA = 0.

        else:
            Cdsalpha = self.CdsAlpha(alpha, Mach)

            sweep = self.get_sweep()
            Mach_normal = Mach * np.cos(sweep)**self.POW_COS
            ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
            dCdp_dAoA = self.__coefs.grad_Cd(ToC, self.get_camber(), alpha,
                                             Mach_normal)[2] - Cdsalpha

        return dCdp_dAoA

    def CdAlpha(self, alpha, Mach):
        dCdp_dAoA = self.CdpAlpha(alpha, Mach)
        dCdf_AoA = self.__dCd_friction_dAoA(alpha, Mach)

        return dCdp_dAoA + dCdf_AoA

    def Cm(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)**self.POW_COS
        ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
        Cm = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha, Mach_normal)
        sweep_corr = np.cos(self.get_sweep())**(2. * self.POW_COS)

        return Cm * sweep_corr

    def dCl_dchi(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)**self.POW_COS
        ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)

        dsweep = self.get_sweep_grad()
        sweep_corr = np.cos(self.get_sweep())**(2. * self.POW_COS)
        dsweep_corr = -2. * self.POW_COS * np.sin(sweep) * dsweep * np.cos(
            sweep)**(2. * self.POW_COS - 1.)

        dCl_dToC = self.gradCl(alpha, Mach)[0]
        dToC_dchi = 100. * (
            self.get_rel_thick_grad() * np.cos(sweep)**self.POW_COS +
            self.POW_COS * self.get_rel_thick() * np.sin(sweep) * dsweep *
            np.cos(sweep)**(self.POW_COS - 1.)) / np.cos(sweep)**(2 *
                                                                  self.POW_COS)

        dCl_dMach = self.gradCl(alpha, Mach)[3]
        dMach_dchi = -self.POW_COS * Mach * np.sin(sweep) * dsweep * np.cos(
            sweep)**(self.POW_COS - 1.)

        return (dCl_dToC * dToC_dchi +
                dCl_dMach * dMach_dchi) * sweep_corr + Cl * dsweep_corr

    def dCd_dchi(self, alpha, Mach):
        dCdf_dchi = self.__dCd_friction_dchi(alpha, Mach)
        dCdp_dchi = self.dCdp_dchi(alpha, Mach)

        return dCdf_dchi + dCdp_dchi

    def dCdp_dchi(self, alpha, Mach):

        Cdp = self.Cdp(alpha, Mach)

        if Cdp != 0:
            sweep = self.get_sweep()
            Mach_normal = Mach * np.cos(sweep)**self.POW_COS
            ToC = self.get_rel_thick() / np.cos(sweep)**self.POW_COS * 100.
            Cd = self.__coefs.meta_Cd(ToC, self.get_camber(), alpha,
                                      Mach_normal)

            dsweep = self.get_sweep_grad()

            dCdp_dToC = self.gradCd(alpha, Mach)[0]
            dToC_dchi = 100. * (
                self.get_rel_thick_grad() * np.cos(sweep)**self.POW_COS +
                self.POW_COS * self.get_rel_thick() * np.sin(sweep) * dsweep *
                np.cos(sweep)**
                (self.POW_COS - 1.)) / np.cos(sweep)**(2 * self.POW_COS)

            dCdp_dMach = self.gradCd(alpha, Mach)[3]
            dMach_dchi = -self.POW_COS * Mach * np.sin(
                sweep) * dsweep * np.cos(sweep)**(self.POW_COS - 1.)

            dCdsdchi = self.dCds_dchi(alpha, Mach)

            dCdpdchi = dCdp_dToC * dToC_dchi + dCdp_dMach * dMach_dchi - dCdsdchi

        else:
            dCdpdchi = 0.

        return dCdpdchi

    def Cdf(self, alpha, Mach):
        return self.__Cd_friction(alpha, Mach)

    def __Cd_friction(self, alpha, Mach):
        # Re= V_corr*Lref_corr/nu=Mach*cos(sweep)*c*Lref/cos(sweep)/nu = Mach*c*Lref/cos(sweep)
        OC = self.get_OC()
        sweep = self.get_sweep()
        c = OC.get_c()
        nu = OC.get_nu()
        L = self.get_Lref()
        Re = Mach * np.cos(sweep) * c * L / nu
        toc = self.get_rel_thick() / np.cos(sweep)
        thick_coeff = 1. + 2.1 * toc  # a rough guess since 1.21 for 10% relative thickness
        if Re < 1.e-12:
            # Prevent division by 0. Drag is null at zero Re number anyway
            Cdf = 0.
        elif Re < 1.e5:
            # Laminar flow
            Cdf = 1.328 / sqrt(Re) * thick_coeff
        else:
            # Turbulent flow
            Cdf = 0.074 * Re**(-0.2) * thick_coeff

        return Cdf

    def CdfAlpha(self, alpha, Mach):
        return self.__dCd_friction_dAoA(alpha, Mach)

    def __dCd_friction_dAoA(self, alpha, Mach):
        return 0.

    def dCdf_dchi(self, alpha, Mach):
        return self.__dCd_friction_dchi(alpha, Mach)

    def __dCd_friction_dchi(self, alpha, Mach):
        OC = self.get_OC()
        sweep = self.get_sweep()
        dsweep = self.get_sweep_grad()
        c = OC.get_c()
        nu = OC.get_nu()
        L = self.get_Lref()
        dL = self.get_Lref_grad()

        Re = Mach * np.cos(sweep) * c * L / nu
        dRe = Mach * np.cos(sweep) * c * dL / nu - Mach * np.sin(
            sweep) * c * L / nu * dsweep

        toc = self.get_rel_thick() / np.cos(sweep)
        dtoc = (
            self.get_rel_thick_grad() * np.cos(sweep) +
            self.get_rel_thick() * np.sin(sweep) * dsweep) / np.cos(sweep)**2

        thick_coeff = 1. + 2.1 * toc
        dthick_coeff = 2.1 * dtoc

        if Re < 1.e-6:
            # Prevent division by 0. Drag is null at zero Re number anyway
            dCdf = 0.
        elif Re < 1.e5:
            # Laminar flow
            dCdf = -0.664 / (
                Re**1.5) * dRe * thick_coeff + 1.328 / sqrt(Re) * dthick_coeff
        else:
            # Turbulent flow
            dCdf = -0.0148 * Re**(-1.2) * dRe * thick_coeff + 0.074 * Re**(
                -0.2) * dthick_coeff
        return dCdf

    def Cd_spurious(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.
        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)

        k, coef = self.k_coef()
        Cl0 = self.Cl0()

        Cds = k + coef * (Cl - Cl0)**2.
        return Cds

    def CdsAlpha(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.

        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        Cl_alpha = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha,
                                        Mach_normal)[2]

        k, coef = self.k_coef()
        Cl0 = self.Cl0()

        Cds_alpha = coef * 2. * (Cl - Cl0) * Cl_alpha

        return Cds_alpha

    def dCds_dchi(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.

        Cl = self.__coefs.meta_Cl(ToC, self.get_camber(), alpha, Mach_normal)
        #dCldchi = self.dCl_dchi(alpha, Mach)

        dCl_dToC = self.gradCl(alpha, Mach)[0]
        dToC_dchi = 100. * (
            self.get_rel_thick_grad() * np.cos(sweep) +
            self.get_rel_thick() * np.sin(sweep)) / np.cos(sweep)**2

        dCl_dMach = self.gradCl(alpha, Mach)[3]
        dsweep = self.get_sweep_grad()
        dMach_dchi = -Mach * np.sin(sweep) * dsweep

        dCldchi = dCl_dToC * dToC_dchi + dCl_dMach * dMach_dchi

        k, coef = self.k_coef()
        dk_dchi, d_coef_dchi = self.d_k_coef_dchi()

        Cl0 = self.Cl0()
        dCl0dchi = self.dCl0_dchi()

        dCdsdchi = dk_dchi + d_coef_dchi * (Cl - Cl0)**2. + 2. * coef * (
            Cl - Cl0) * (dCldchi - dCl0dchi)

        return dCdsdchi

    def k_coef(self):

        k = 0.0045235
        coef = 0.03132053

        return k, coef

    def d_k_coef_dchi(self):
        return 0., 0.

    def Cl0(self):

        Cl0 = 0.16372357

        return Cl0

    def dCl0_dchi(self):
        return 0.

    def gradCl(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.
        gradCl = self.__coefs.grad_Cl(ToC, self.get_camber(), alpha,
                                      Mach_normal)
        return gradCl

    def gradCd(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.
        gradCd = self.__coefs.grad_Cd(ToC, self.get_camber(), alpha,
                                      Mach_normal)
        return gradCd

    def gradCm(self, alpha, Mach):
        sweep = self.get_sweep()
        Mach_normal = Mach * np.cos(sweep)
        ToC = self.get_rel_thick() / np.cos(sweep) * 100.
        gradCm = self.__coefs.grad_Cm(ToC, self.get_camber(), alpha,
                                      Mach_normal)
        return gradCm

#     def dCl_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dthic = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]*100.
#
#         return dCl_dthic*sweep_corr
#
#     def dCl_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dcamb = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCl_dcamb*sweep_corr
#
#     def dCl_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCl_dM = self.__coefs.grad_Cl(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCl_dM*sweep_corr
#
#     def dCd_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dthic = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCd_dthic*sweep_corr
#
#     def dCd_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dcamb = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCd_dcamb*sweep_corr
#
#     def dCd_dalpha(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dAoA = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[2]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCd_dAoA*sweep_corr
#
#     def dCd_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCd_dM = self.__coefs.grad_Cd(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCd_dM*sweep_corr

#     def dCm_dthickness(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dthic = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[0]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCm_dthic*sweep_corr
#
#     def dCm_dcamber(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dcamb = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[1]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCm_dcamb*sweep_corr
#
#     def dCm_dalpha(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dAoA = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[2]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCm_dAoA*sweep_corr
#
#     def dCm_dMach(self):
#         sweep=self.get_sweep()
#         Mach_normal= Mach*np.cos(sweep)
#         dCm_dM = self.__coefs.grad_Cm(self.get_rel_thick()*100., self.get_camber(), alpha, Mach_normal)[3]
#         sweep_corr = np.cos(self.get_sweep())**2
#
#         return dCm_dM*sweep_corr

    def get_scaled_copy(self,
                        OC=None,
                        Sref=None,
                        Lref=None,
                        rel_thick=None,
                        camber=None,
                        sweep=None):
        if Sref is None:
            Sref = self.get_Sref()
        if Lref is None:
            Lref = self.get_Lref()
        if rel_thick is None:
            rel_thick = self.get_rel_thick()
        if camber is None:
            camber = self.get_camber()
        if sweep is None:
            sweep = self.get_sweep()
        if OC is None:
            OC = self.get_OC()
        return MetaAirfoil(OC,
                           self.__surrogate_model,
                           relative_thickness=rel_thick,
                           camber=camber,
                           Sref=Sref,
                           Lref=Lref,
                           sweep=sweep,
                           surrogate_fcs=self.__coefs)