# RCAIDE/Methods/Aerodynamics/Common/Drag/parasite_drag_wing.py
# 
# 
# Created:  Jul 2023, M. Clarke 

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------   
from RCAIDE.Framework.Core import Data  
from RCAIDE.Library.Methods.Aerodynamics.Common.Drag.compressible_mixed_flat_plate import compressible_mixed_flat_plate
from RCAIDE.Library.Methods.Utilities         import Cubic_Spline_Blender  
 
# package imports
import numpy as np  

# ----------------------------------------------------------------------------------------------------------------------  
#   Parasite Drag Wing 
# ----------------------------------------------------------------------------------------------------------------------   
def parasite_drag_wing(state,settings,geometry):
    """Computes the parasite drag due to wings

    Assumptions:
    Basic fit

    Source:
    http://aerodesign.stanford.edu/aircraftdesign/aircraftdesign.html (Stanford AA241 A/B Course Notes)

    Args:
    settings.wing_parasite_drag_form_factor      [Unitless]
    state.conditions.freestream.
      mach_number                                [Unitless]
      temperature                                [K]
      reynolds_number                            [Unitless]
    geometry.
      areas.reference                            [m^2]
      chords.mean_aerodynamic                    [m]
      thickness_to_chord                         [Unitless]
      sweeps.quarter_chord                       [radians]
      aspect_ratio                               [Unitless]
      spans.projected                            [m]
      areas.affected                             [m^2]
      areas.wetted                               [m^2]
      transition_x_upper                         [Unitless]
      transition_x_lower                         [Unitless]
      
      
    Returns:
    wing_parasite_drag                           [Unitless] 
    """
    
    # unpack inputs
    C                             = settings.wing_parasite_drag_form_factor 
    recalculate_total_wetted_area = settings.recalculate_total_wetted_area
    freestream                    = state.conditions.freestream
    
    # conditions
    Mc  = freestream.mach_number
    Tc  = freestream.temperature    
    re  = freestream.reynolds_number     
    
    wing = geometry
    wing_parasite_drag = 0.0
    
    # Unpack wing
    exposed_root_chord_offset = wing.exposed_root_chord_offset
    t_c_w                     = wing.thickness_to_chord
    Sref                      = wing.areas.reference
    num_segments              = len(wing.segments.keys())     
    
    # if wing has segments, compute and sum parasite drag of each segment

    xtu       = wing.transition_x_upper
    xtl       = wing.transition_x_lower     
    
    if num_segments>0:        
        total_segment_parasite_drag  = 0 
        total_segment_k_w            = 0 
        total_segment_cf_w_u         = 0
        total_segment_cf_w_l         = 0 
        total_segment_k_comp_u       = 0
        total_segment_k_comp_l       = 0
        total_k_reyn_u               = 0          
        total_k_reyn_l               = 0
        
        for i,segment in enumerate (wing.segments): 
            if i == num_segments-1:
                continue  
            mac_seg       = segment.chords.mean_aerodynamic
            Sref_seg      = segment.areas.reference 
            Swet_seg      = segment.areas.wetted
            sweep_seg     = segment.sweeps.quarter_chord
    
            # compute parasite drag coef., form factor, skin friction coef., compressibility factor and reynolds number for segments
            segment_parasite_drag , segment_k_w, segment_cf_w_u, segment_cf_w_l, segment_k_comp_u, segment_k_comp_l, k_reyn_u ,k_reyn_l = compute_parasite_drag(re,mac_seg,Mc,Tc,xtu,xtl,sweep_seg,t_c_w,Sref_seg,Swet_seg,C)    
            
            total_segment_parasite_drag  += segment_parasite_drag*Sref_seg   
            total_segment_k_w            += segment_k_w*Sref_seg 
            total_segment_cf_w_u         += segment_cf_w_u*Sref_seg 
            total_segment_cf_w_l         += segment_cf_w_l*Sref_seg 
            total_segment_k_comp_u       += segment_k_comp_u*Sref_seg 
            total_segment_k_comp_l       += segment_k_comp_l*Sref_seg 
            total_k_reyn_u               += k_reyn_u*Sref_seg                 
            total_k_reyn_l               += k_reyn_l*Sref_seg  
                
        wing_parasite_drag = total_segment_parasite_drag  / Sref
        k_w                = total_segment_k_w / Sref
        cf_w_u             = total_segment_cf_w_u  / Sref
        cf_w_l             = total_segment_cf_w_l / Sref
        k_comp_u           = total_segment_k_comp_u  / Sref
        k_comp_l           = total_segment_k_comp_l  / Sref
        k_reyn_u           = total_k_reyn_u  / Sref
        k_reyn_l           = total_k_reyn_l  / Sref

    # if wing has no segments      
    else:              
        # wing
        mac_w        = wing.chords.mean_aerodynamic
        sweep_w      = wing.sweeps.quarter_chord 
        span_w       = wing.spans.projected
        Sref         = wing.areas.reference
        
        chord_root = wing.chords.root
        chord_tip  = wing.chords.tip
        wing_root     = chord_root + exposed_root_chord_offset*((chord_tip - chord_root)/span_w)
        
        if recalculate_total_wetted_area or wing.areas.wetted==0.:  
            
            # calculate exposed area
            if wing.symmetric:
                S_exposed_w = wing.areas.reference - (chord_root + wing_root)*exposed_root_chord_offset         
            else: 
                S_exposed_w = wing.areas.reference - 0.5*(chord_root + wing_root)*exposed_root_chord_offset
                
            if t_c_w < 0.05:
                Swet = 2.003* S_exposed_w
            else:
                Swet = (1.977 + 0.52*t_c_w) * S_exposed_w   
                
            wing.areas.wetted = Swet 
        else:
            Swet              = wing.areas.wetted                         

        # compute parasite drag coef., form factor, skin friction coef., compressibility factor and reynolds number for wing
        wing_parasite_drag , k_w, cf_w_u, cf_w_l, k_comp_u, k_comp_l, k_reyn_u, k_reyn_l = compute_parasite_drag(re,mac_w,Mc,Tc,xtu,xtl,sweep_w,t_c_w,Sref,Swet,C)             

    # dump data to conditions
    wing_result = Data(
        wetted_area               = wing.areas.wetted,
        reference_area            = Sref   , 
        total                     = wing_parasite_drag ,
        skin_friction             = (cf_w_u+cf_w_l)/2.   ,
        compressibility_factor    = (k_comp_u+k_comp_l)/2 ,
        reynolds_factor           = (k_reyn_u+k_reyn_l)/2 , 
        form_factor               = k_w    ,
    )
    
    state.conditions.aerodynamics.coefficients.drag.parasite[wing.tag] = wing_result

    return  
 
def compute_parasite_drag(re,mac_w,Mc,Tc,xtu,xtl,sweep_w,t_c_w,Sref,Swet,C):
    """Computes the parasite drag due to wings

    Assumptions:
    Basic fit

    Source:
    adg.stanford.edu (Stanford AA241 A/B Course Notes)

    Args:
    re (Reynolds Number)    [Unitless]
    mac_w (Wing MAC)        [m]
    Mc (Mach Number)        [Unitless]
    Tc (Temperature)        [K]
    xtu (Upper Transition)  [Unitless] (percent of chord)
    xtl (Lower Transition)  [Unitless] (percent of chord)
    sweep_w (Wing Sweep)    [rad]
    t_c_w (Wing t/c)        [Unitless]
    Sref (Wing Ref Area)    [m^2]
    Swet (Wing Wetted Area) [m^2]
    C (Form Factor)         [Unitless]
      
    Returns:
    (u is upper, l is lower)
    wing_parasite_drag                 [Unitless]
    k_w    (Form Factor)               [Unitless]
    cf_w_u (Skin Friction Coefficient) [Unitless]
    cf_w_l                             [Unitless]
    k_comp_u (Compressibility Factor)  [Unitless]
    k_comp_l                           [Unitless]
    k_reyn_u (Reynolds Factor)         [Unitless]
    k_reyn_l                           [Unitless] 
    """    
   
    # reynolds number
    Re_w = re*mac_w  
    
    # skin friction  coefficient, upper
    cf_w_u, k_comp_u, k_reyn_u = compressible_mixed_flat_plate(Re_w,Mc,Tc,xtu)
    
    # skin friction  coefficient, lower
    cf_w_l, k_comp_l, k_reyn_l = compressible_mixed_flat_plate(Re_w,Mc,Tc,xtl) 
    
    # correction for airfoils
    cos_sweep = np.cos(sweep_w)
    cos2      = cos_sweep*cos_sweep
    
    ind = Mc <= 1.
    
    k_w = np.ones_like(Mc)
    k_w[ind] = 1. + ( 2.* C * (t_c_w * cos2) ) / ( np.sqrt(1.- Mc[ind]*Mc[ind] * cos2) )  \
            + ( C*C * cos2 * t_c_w*t_c_w * (1. + 5.*(cos2)) ) \
            / (2.*(1.-(Mc[ind]*cos_sweep)**2.))             
    
    spline = Cubic_Spline_Blender(.95,1.0)
    h00 = lambda M:spline.compute(M)
    
    k_w = k_w*(h00(Mc)) + 1*(1-h00(Mc))   

    # find the final result
    wing_parasite_drag = k_w * cf_w_u * Swet / Sref /2. + k_w * cf_w_l * Swet / Sref /2.


    return wing_parasite_drag , k_w, cf_w_u, cf_w_l, k_comp_u, k_comp_l, k_reyn_u, k_reyn_l