예제 #1
0
class DLLM_param(DLLM_Geom):

    ERROR_MSG = 'ERROR in DLLM_param.'

    def __init__(self, tag, n_sect=20, grad_active=True):
        """
        Constructor: set main attributes
        """
        DLLM_Geom.__init__(self, tag, n_sect=n_sect, grad_active=grad_active)
        self.BC_manager = BCManager()
        
        self.__AoA_id    = 'AoA'
        
        self.__common_OC = None
        
    #-- Accessors
    def get_dv_array(self):
        return self.BC_manager.get_dv_array()

    def get_dv_id_list(self):
        return self.BC_manager.get_dv_id_list()

    def get_dv_info_list(self):
        return self.BC_manager.get_dv_info_list()

    def get_bounds_array(self):
        return self.BC_manager.get_bounds_array()
    
    #-- Setters
    def set_AoA_id(self, AoA_id):
        self.__AoA_id = AoA_id
    
    def set_value(self, Id, val):
        pt = self.__BC_manager.get_pt(Id)
        pt.set_value(val)
        
    def set_common_OC(self, OC):
        self.__common_OC = OC
    
    #-- Methods
    def import_BC_from_file(self, filename):
        self.BC_manager.import_from_file(filename)
        self.BC_manager.update()
        
    def config_from_dict(self, config_dict):
        config_dict_keys = config_dict.keys()
        #-- Import BCManager from filename defined in config_dict
        BC_filename_key=self.get_tag()+'.BCfilename'
        if BC_filename_key in config_dict_keys:
            BC_filename = config_dict[BC_filename_key]
            self.import_BC_from_file(BC_filename)
            
        #TBC: to be update with new way of working
        #-- Config airfoils
        airfoil_type_key = self.get_tag() + '.airfoil.type'
        if airfoil_type_key in config_dict_keys:
            airfoil_type = config_dict[airfoil_type_key]
        else:
            airfoil_type = 'simple'
             
        self.set_airfoil_type(airfoil_type)
         
        if airfoil_type == 'simple':
            AoA0_key = self.get_tag() + '.airfoil.AoA0'
            if AoA0_key in config_dict_keys:
                AoA0 = config_dict[AoA0_key]
            else:
                AoA0 = 0.
 
            self.build_linear_airfoil(self.__common_OC, AoA0=AoA0, set_as_ref=True)
 
        elif airfoil_type == 'meta':
            surrogate_model_key = self.__tag + '.airfoil.surrogate_model'
            if surrogate_model_key in config_dict_keys:
                surrogate_model = config_dict[surrogate_model_key]
            else:
                surrogate_model = None
 
            self.build_meta_airfoil(self.__common_OC, surrogate_model, set_as_ref=True)
 
        self.build_airfoils_from_ref()
        self.update()
    
    def update_from_x_list(self, x):
        # print 'update wing_param with x=',x
        self.BC_manager.update_dv_from_x_list(x)
        self.update()
        
    def update(self):
        #-- Design variables update
        self.BC_manager.update()
        ndv = self.BC_manager.get_ndv()
        self.set_ndv(ndv)
        self.__update_AoA()
    
        #-- Update necessary information
        self.build_r_lists()
        
        #-- Build discretization
        self.build_discretization()
        
        DLLM_Geom.update(self)
        
    def build_discretization(self):
        print 'WARNING: build_discretization method has to be overloaded in child classes...'

    #-- Private methods
    def __update_AoA(self):
        Id = self.__AoA_id
        if Id in self.get_dv_id_list():
            pt = self.BC_manager.get_pt(Id)
            deg_to_rad = np.pi / 180.
            AoA = pt.get_value() * deg_to_rad
            AoA_grad = pt.get_gradient() * deg_to_rad
        else:
            AoA = None
            AoA_grad = None
        self.set_AoA(AoA)
        self.set_AoA_grad(AoA_grad)
        
    def __repr__(self):
        DLLM_Geom.__repr__(self)
        info_string = '\n*** Wing param information ***'
        info_string += '\n  n_sect       : ' + str(self.get_n_sect())
        info_string += '\n  ndv          : ' + str(self.get_ndv())
        info_string += '\n  airfoil_type : ' + str(self.get_airfoil_type())
        info_string += '\n  --    parameters information section    --\n'
        for Id in self.BC_manager.get_list_id():
            pt = self.BC_manager.get_pt(Id)
            BC_Type = pt.get_BCType()
            if BC_Type == 'Variable':
                value = pt.get_value()
                info_string += "%30s" % Id + \
                    "%20s" % BC_Type + " %24.16e" % value + "\n"
            if BC_Type == 'DesignVariable':
                value = pt.get_value()
                bounds = pt.get_bounds()
                info_string += "%30s" % Id + "%20s" % BC_Type + \
                    " %24.16e" % value + " %24s" % str(bounds) + "\n"
            if BC_Type == 'Parameter':
                expr = pt.get_expr()
                info_string += "%30s" % Id + \
                    "%20s" % BC_Type + " %24s" % expr + "\n"
        info_string += '  -- end of parameters information section --\n'
        return info_string
예제 #2
0
class Wing_param():

    ERROR_MSG = 'ERROR in Wing_param.'
    POSSIBLE_GEOM_TYPES = ["Rectangular", "Elliptic", "Broken"]
    POS_DISTRIB = ['linear', 'cos_law']
    DISCRETE_ATTRIBUTES_LIST = [
        'span',
        'sweep',
        'break_percent',
        'root_chord',
        'break_chord',
        'tip_chord',
        'root_height',
        'break_height',
        'tip_height']

    def __init__(self, tag, geom_type='Broken', n_sect=20):
        """
        Constructor: set main attributes
        """
        self.__tag = tag
        self.__geom_type = None
        self.__n_sect = None
        self.__PCADModel = None
        self.__BC_manager = None

        self.__distrib_type = 'cos_law'

        self.set_geom_type(geom_type)
        self.set_n_sect(n_sect)

        self.__BC_manager = BCManager()

        self.__ndv = 0

        self.__thetaY = None

        self.__AoA_id = 'AoA'

        self.__init_discrete_attributes()
        self.__init_airfoils_attributes()

    def __init_discrete_attributes(self):
        # -- OC design variable
        self.__AoA = None
        self.__AoA_grad = None

        # -- discrete attributes
        self.__span = None
        self.__span_grad = None

        self.__r_list_y = None
        self.__r_list_eta = None

        self.__sweep = None
        self.__sweep_grad = None

        self.__break_percent = None
        self.__break_percent_grad = None

        self.__root_chord = None
        self.__root_chord_grad = None

        self.__break_chord = None
        self.__break_chord_grad = None

        self.__tip_chord = None
        self.__tip_chord_grad = None

        self.__root_height = None
        self.__root_height_grad = None

        self.__break_height = None
        self.__break_height_grad = None

        self.__tip_height = None
        self.__tip_height_grad = None

        self.__twist = None
        self.__twist_grad = None

        self.__chords = None
        self.__chords_grad = None

        self.__heights = None
        self.__heights_grad = None

        self.__rel_thicks = None
        self.__rel_thicks_grad = None

        self.__XYZ = None
        self.__XYZ_grad = None

        self.__eta = None
        self.__eta_grad = None

        self.__Lref = None
        self.__Lref_grad = None

        self.__Sref = None
        self.__Sref_grad = None

        self.__root_ToC = None
        self.__root_ToC_grad = None

        self.__break_ToC = None
        self.__break_ToC_grad = None

        self.__tip_ToC = None
        self.__tip_ToC_grad = None

        self.__AR = None
        self.__AR_grad = None

        self.__fuel = None
        self.__fuel_grad = None

    def __init_airfoils_attributes(self):
        self.__airfoil_type = None
        # reference airfoil, only used if the same airfoil is put for all
        # sections
        self.__ref_airfoil = None
        self.__airfoils = None   # Airfoil list for each section
        self.__linked_airfoils = None   # Airfoil scaled to the the planform

    # -- Accessors
    def get_n_sect(self):
        return self.__n_sect

    def get_ndv(self):
        return self.__ndv

    def get_eta(self):
        return self.__eta

    def get_eta_grad(self):
        return self.__eta_grad

    def get_XYZ(self):
        return self.__XYZ

    def get_XYZ_grad(self):
        return self.__XYZ_grad

    def get_twist(self):
        return self.__twist

    def get_twist_grad(self):
        return self.__twist_grad

    def get_chords(self):
        return self.__chords

    def get_chords_grad(self):
        return self.__chords_grad

    def get_rel_thicks(self):
        return self.__rel_thicks

    def get_rel_thicks_grad(self):
        return self.__rel_thicks_grad

    def get_thetaY(self):
        return self.__thetaY

    def get_BC_manager(self):
        return self.__BC_manager

    def get_AoA(self):
        return self.__AoA

    def get_AoA_grad(self):
        return self.__AoA_grad

    def get_span(self):
        return self.__span

    def get_span_grad(self):
        return self.__span_grad

    def get_sweep(self):
        return self.__sweep

    def get_sweep_grad(self):
        return self.__sweep_grad

    def get_Lref(self):
        return self.__Lref

    def get_Lref_grad(self):
        return self.__Lref_grad

    def get_Sref(self):
        return self.__Sref

    def get_Sref_grad(self):
        return self.__Sref_grad

    def get_root_ToC(self):
        return self.__root_ToC

    def get_root_ToC_grad(self):
        return self.__root_ToC_grad

    def get_break_ToC(self):
        return self.__break_ToC

    def get_break_ToC_grad(self):
        return self.__break_ToC_grad

    def get_tip_ToC(self):
        return self.__tip_ToC

    def get_tip_ToC_grad(self):
        return self.__tip_ToC_grad

    def get_AR(self):
        return self.__AR

    def get_AR_grad(self):
        return self.__AR_grad

    def get_fuel(self):
        return self.__fuel

    def get_fuel_grad(self):
        return self.__fuel_grad

    # -- Setters
    def set_AoA_id(self, AoA_id):
        self.__AoA_id = AoA_id

    def set_geom_type(self, geom_type):
        """
        @param wing_geometry_type : Rectangular or Elliptic planforms
        @param type wing_geometry_type : String
        """
        if not geom_type in self.POSSIBLE_GEOM_TYPES:
            raise Exception("geom_type :" +
                            str(geom_type) +
                            " not in possible types : " +
                            str(self.POSSIBLE_GEOM_TYPES))
        self.__geom_type = geom_type

    def set_n_sect(self, n_sect):
        ERROR_MSG = self.ERROR_MSG + '.set_n_sect: ' + str(self.__tag) + ': '
        if n_sect % 2 != 0:
            raise Exception(
                ERROR_MSG +
                'The total number of elements in the wing must be even.')
        self.__n_sect = n_sect

    def set_distrib_type(self, distrib_type):
        if not distrib_type in self.POS_DISTRIB:
            raise Exception("distrib_type :" +
                            str(distrib_type) +
                            " not in possible types : " +
                            str(self.POS_DISTRIB))
        self.__distrib_type = distrib_type

    def set_value(self, Id, val):
        pt = self.__BC_manager.get_pt(Id)
        pt.set_value(val)

    def set_thetaY(self, thetaY):
        self.__thetaY = thetaY

    # -- controller management
    def convert_to_variable(self, Id):
        self.__BC_manager.convert_to_variable(Id)

    def convert_to_design_variable(self, Id, bounds):
        self.__BC_manager.convert_to_design_variable(Id, bounds)

    def convert_to_parameter(self, Id, fexpr):
        self.__BC_manager.convert_to_parameter(Id, fexpr)

    def add_AoA_design_variable(self, val, bounds):
        self.__BC_manager.create_design_variable(self.__AoA_id, val, bounds)

    def __update_AoA(self):
        Id = self.__AoA_id
        if Id in self.get_dv_id_list():
            pt = self.__BC_manager.get_pt(Id)
            deg_to_rad = pi / 180.
            self.__AoA = pt.get_value() * deg_to_rad
            self.__AoA_grad = pt.get_gradient() * deg_to_rad

    def get_dv_array(self):
        return self.__BC_manager.get_dv_array()

    def get_dv_id_list(self):
        return self.__BC_manager.get_dv_id_list()

    def get_dv_info_list(self):
        return self.__BC_manager.get_dv_info_list()

    def get_bounds_array(self):
        return self.__BC_manager.get_bounds_array()

    def build_wing(self):
        self.__BC_manager.clean()
        self.__BC_manager.create_variable('span', 0.)
        if self.__geom_type not in ['Elliptic']:
            self.__BC_manager.create_variable('sweep', 0.)
        if self.__geom_type in ['Rectangular', 'Elliptic']:
            self.__BC_manager.create_variable('root_chord', 0.)
            self.__BC_manager.create_variable('root_height', 0.)
            self.__BC_manager.create_variable('tip_height', 0.)
        elif self.__geom_type == 'Broken':
            self.__BC_manager.create_variable('break_percent', 0.33)
            self.__BC_manager.create_variable('root_chord', 0.)
            self.__BC_manager.create_variable('break_chord', 0.)
            self.__BC_manager.create_variable('tip_chord', 0.)
            self.__BC_manager.create_variable('root_height', 0.)
            self.__BC_manager.create_variable('break_height', 0.)
            self.__BC_manager.create_variable('tip_height', 0.)

        for i in xrange(self.__n_sect / 2):
            self.__BC_manager.create_design_variable(
                'rtwist' + str(i), 0., (-10., 10.))
        for i in xrange(self.__n_sect / 2):
            # print
            # self.__tag+'.twist'+str(i),self.__tag+'.twist'+str(self.__n_sect/2+i),self.__tag+'.rtwist'+str(self.__n_sect/2-1-i),self.__tag+'.rtwist'+str(i)
            self.__BC_manager.create_parameter(
                'twist' + str(i), 'rtwist' + str(self.__n_sect / 2 - 1 - i))
            self.__BC_manager.create_parameter(
                'twist' + str(self.__n_sect / 2 + i), 'rtwist' + str(i))
#         for i in xrange(self.__n_sect):
#             self.__BC_manager.create_design_variable(self.__tag+'.twist'+str(i),-25.,0.,25.)

    def config_from_dict(self, OC, config_dict):
        self.build_wing()
        self.__config_airfoils(OC, config_dict)
        self.__config_desc(config_dict)
        self.update()

    def __config_airfoils(self, OC, config_dict):
        in_keys_list = config_dict.keys()

        airfoil_type_key = self.__tag + '.airfoil.type'
        if airfoil_type_key in in_keys_list:
            airfoil_type = config_dict[airfoil_type_key]
        else:
            airfoil_type = 'simple'

        if airfoil_type == 'simple':
            AoA0_key = self.__tag + '.airfoil.AoA0'
            if AoA0_key in in_keys_list:
                AoA0 = config_dict[AoA0_key]
            else:
                AoA0 = 0.

            Cm0_key = self.__tag + '.airfoil.Cm0'
            if Cm0_key in in_keys_list:
                Cm0 = config_dict[Cm0_key]
            else:
                Cm0 = 0.

            self.build_linear_airfoil(OC, AoA0=AoA0, Cm0=Cm0, set_as_ref=True)

        elif airfoil_type == 'meta':
            surrogate_model_key = self.__tag + '.airfoil.surrogate_model'
            if surrogate_model_key in in_keys_list:
                surrogate_model = config_dict[surrogate_model_key]
            else:
                surrogate_model = None

            self.build_meta_airfoil(OC, surrogate_model, set_as_ref=True)

        self.build_airfoils_from_ref()

    def __config_desc(self, config_dict):
        in_keys_list=sorted(config_dict.keys())
        existing_keys=deepcopy(self.__BC_manager.get_list_id())
        
        # Add user defined DesignVariable, Variable and Parameter
        added_list=[]        
        for in_key in in_keys_list:
            words=in_key.split('.')
            if len(words) >=4:
                test=string.join(words[:-2],'.')
                if test==self.__tag+'.desc':
                    name=words[-2]
                    Id=name
                    Id_in=self.__tag+'.desc.'+name
                    type=config_dict[Id_in+'.type']
                    if Id not in existing_keys and Id not in added_list:
                        if   type == 'DesignVariable':
                            bounds = config_dict[Id_in+'.bounds']
                            value  = config_dict[Id_in+'.value']
                            self.__BC_manager.create_design_variable(Id,value,(bounds[0],bounds[1]))
                        elif type == 'Variable':
                            value  = config_dict[Id_in+'.value']
                            self.__BC_manager.create_variable(Id,value)
                        elif type == 'Parameter':
                            fexpr = config_dict[Id_in+'.fexpr']
                            self.__BC_manager.create_parameter(Id,fexpr)
                        added_list.append(Id)
        
        # Convert pre-defined parameters
        for existing_id in existing_keys:
            ex_words=existing_id.split('.')
            name=ex_words[-1]
            Id_in=self.__tag+'.desc.'+name
            Id=name
            if Id_in+'.type' in in_keys_list:
                type=config_dict[Id_in+'.type']
                if   type == 'DesignVariable':
                    bounds = config_dict[Id_in+'.bounds']
                    value  = config_dict[Id_in+'.value']
                    self.set_value(Id,value)
                    self.convert_to_design_variable(Id,bounds)
                elif type == 'Variable':
                    value  = config_dict[Id_in+'.value']
                    self.set_value(Id,value)
                    self.convert_to_variable(Id)
                elif type == 'Parameter':
                    fexpr = config_dict[Id_in+'.fexpr']
                    self.convert_to_parameter(Id,fexpr)

    def update(self):
        self.__BC_manager.update()
        self.__ndv = self.__BC_manager.get_ndv()
        self.__update_AoA()
        self.__check_thetaY()
        self.__build_discretization()
        self.__check_airfoils_inputs()
        self.__link_airfoils_to_geom()
        self.__compute_Sref_Lref_ToC_AR_fuel()

    def update_from_x_list(self, x):
        # print 'update wing_param with x=',x
        self.__BC_manager.update_dv_from_x_list(x)
        self.update()

    def __repr__(self):
        info_string = '\n*** Wing param information ***'
        info_string += '\n  geom_type    : ' + str(self.__geom_type)
        info_string += '\n  n_sect       : ' + str(self.__n_sect)
        info_string += '\n  ndv          : ' + str(self.__ndv)
        info_string += '\n  airfoil_type : ' + str(self.__airfoil_type)
        info_string += '\n  --    parameters information section    --\n'
        for Id in self.__BC_manager.get_list_id():
            pt = self.__BC_manager.get_pt(Id)
            BC_Type = pt.get_BCType()
            if BC_Type == 'Variable':
                value = pt.get_value()
                info_string += "%30s" % Id + \
                    "%20s" % BC_Type + " %24.16e" % value + "\n"
            if BC_Type == 'DesignVariable':
                value = pt.get_value()
                bounds = pt.get_bounds()
                info_string += "%30s" % Id + "%20s" % BC_Type + \
                    " %24.16e" % value + " %24s" % str(bounds) + "\n"
            if BC_Type == 'Parameter':
                expr = pt.get_expr()
                info_string += "%30s" % Id + \
                    "%20s" % BC_Type + " %24s" % expr + "\n"
        info_string += '  -- end of parameters information section --\n'
        return info_string

    # -- Structural displacement methods
    def __check_thetaY(self):
        # 6 dimensions for structural displacement:
        # dx,dy,dz,dthetax,dthetay,dthetaz at each section
        if self.__thetaY is None:
            self.__thetaY = zeros(self.__n_sect)

    # -- discretization methods
    def __build_discretization(self):
        self.__build_planform()
        self.__build_r_lists()
        self.__build_chords()
        self.__build_heights_rel_thicks()
        self.__build_XYZ_eta()

    def __build_planform(self):
        deg_to_rad = pi / 180.

        # -- span
        Id = 'span'
        pt = self.__BC_manager.get_pt(Id)
        val = pt.get_value()
        grad = pt.get_gradient()
        self.__span = val
        self.__span_grad = grad

        if self.__geom_type not in ['Elliptic']:
            # -- sweep
            Id = 'sweep'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__sweep = val * deg_to_rad
            self.__sweep_grad = grad * deg_to_rad
        else:
            self.__sweep = 0.
            self.__sweep_grad = zeros(self.get_ndv())

        if self.__geom_type in ['Rectangular', 'Elliptic']:
            Id = 'root_chord'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__root_chord = val
            self.__root_chord_grad = grad

            Id = 'root_height'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__root_height = val
            self.__root_height_grad = grad

            Id = 'tip_height'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__tip_height = val
            self.__tip_height_grad = grad

        elif self.__geom_type == 'Broken':
            Id = 'break_percent'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__break_percent = val
            self.__break_percent_grad = grad

            Id = 'root_chord'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__root_chord = val
            self.__root_chord_grad = grad

            Id = 'break_chord'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__break_chord = val
            self.__break_chord_grad = grad

            Id = 'tip_chord'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__tip_chord = val
            self.__tip_chord_grad = grad

            Id = 'root_height'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__root_height = val
            self.__root_height_grad = grad

            Id = 'break_height'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__break_height = val
            self.__break_height_grad = grad

            Id = 'tip_height'
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__tip_height = val
            self.__tip_height_grad = grad

        self.__twist = zeros((self.__n_sect))
        self.__twist_grad = zeros((self.__n_sect, self.__ndv))
        for i in xrange(self.__n_sect):
            Id = 'twist' + str(i)
            pt = self.__BC_manager.get_pt(Id)
            val = pt.get_value()
            grad = pt.get_gradient()
            self.__twist[i] = val * deg_to_rad
            self.__twist_grad[i, :] = grad * deg_to_rad

    def __build_r_lists(self):
        N = self.__n_sect

        if self.__distrib_type == 'linear':
            self.__r_list_eta = numpy.linspace(-0.5, 0.5, N + 1)
        else:
            theta_list = numpy.linspace(0., numpy.pi, N + 1)
            self.__r_list_eta = -0.5 + 0.5 * (1. - numpy.cos(theta_list))

        self.__r_list_y = 0.5 * \
            (self.__r_list_eta[:-1] + self.__r_list_eta[1:])

    def __build_chords(self):
        self.__chords = zeros((self.__n_sect))
        self.__chords_grad = zeros((self.__n_sect, self.__ndv))

        self.__chords_eta = zeros((self.__n_sect + 1))
        self.__chords_grad_eta = zeros((self.__n_sect + 1, self.__ndv))

        if self.__geom_type == 'Elliptic':
            for i, r in enumerate(self.__r_list_y):
                self.__chords[i] = self.__root_chord * sqrt(1. - (2. * r)**2)
                self.__chords_grad[i, :] = self.__root_chord_grad[
                    :] * sqrt(1. - (2. * r)**2)
            for i, r in enumerate(self.__r_list_eta):
                self.__chords_eta[i] = self.__root_chord * \
                    sqrt(1. - (2. * r)**2)
                self.__chords_grad_eta[i, :] = self.__root_chord_grad[:] \
                * sqrt(1. - (2. * r)**2)

        elif self.__geom_type == 'Rectangular':
            for i in xrange(self.__n_sect):
                self.__chords[i] = self.__root_chord
                self.__chords_grad[i, :] = self.__root_chord_grad[:]
            for i in xrange(self.__n_sect + 1):
                self.__chords_eta[i] = self.__root_chord
                self.__chords_grad_eta[i, :] = self.__root_chord_grad[:]

        elif self.__geom_type == 'Broken':
            p = self.__break_percent / 100.
            p_grad = self.__break_percent_grad / 100.

            for i, r in enumerate(self.__r_list_y):
                r = abs(2. * r)
                if r <= p:
                    coeff = r / p
                    dcoeff = -r * p_grad[:] / p**2
                    self.__chords[i] = (self.__break_chord - self.__root_chord) * coeff + self.__root_chord
                    self.__chords_grad[i, :] = (self.__break_chord_grad[:] - self.__root_chord_grad[:]) * coeff  \
                        + (self.__break_chord - self.__root_chord) * dcoeff + self.__root_chord_grad[:]

                else:
                    coeff = (r - p) / (1. - p)
                    dcoeff = (r - 1) * p_grad[:] / (1. - p)**2
                    self.__chords[i] = ( self.__tip_chord - self.__break_chord) * coeff + self.__break_chord
                    self.__chords_grad[i, :] = (self.__tip_chord_grad[:] - self.__break_chord_grad[:]) * coeff  \
                        + (self.__tip_chord - self.__break_chord) * dcoeff + self.__break_chord_grad[:]

            for i, r in enumerate(self.__r_list_eta):
                r = abs(2. * r)
                if r <= p:
                    coeff = r / p
                    dcoeff = -r * p_grad[:] / p**2
                    self.__chords_eta[i] = (
                        self.__break_chord - self.__root_chord) * coeff + self.__root_chord
                    self.__chords_grad_eta[i, :] = (self.__break_chord_grad[:] - self.__root_chord_grad[:]) * coeff  \
                        + (self.__break_chord - self.__root_chord) * dcoeff \
                        + self.__root_chord_grad[:]

                else:
                    coeff = (r - p) / (1. - p)
                    dcoeff = (r - 1) * p_grad[:] / (1. - p)**2
                    self.__chords_eta[i] = (
                        self.__tip_chord - self.__break_chord) * coeff + self.__break_chord
                    self.__chords_grad_eta[i, :] = (self.__tip_chord_grad[:] - self.__break_chord_grad[:]) * coeff  \
                        + (self.__tip_chord - self.__break_chord) * dcoeff \
                        + self.__break_chord_grad[:]

    def __build_heights_rel_thicks(self):
        self.__heights = zeros((self.__n_sect))
        self.__heights_grad = zeros((self.__n_sect, self.__ndv))

        self.__rel_thicks = zeros((self.__n_sect))
        self.__rel_thicks_grad = zeros((self.__n_sect, self.__ndv))

        if self.__geom_type == 'Broken':
            p = self.__break_percent / 100.
            p_grad = self.__break_percent_grad / 100.

            for i, r in enumerate(self.__r_list_y):
                r = abs(2. * r)
                if r <= p:
                    coeff = r / p
                    dcoeff = -r * p_grad[:] / p**2
                    self.__heights[i] = (
                        (self.__break_height -
                         self.__root_height) *
                        coeff +
                        self.__root_height)
                    self.__heights_grad[i, :] = (self.__break_height_grad[:] - self.__root_height_grad[:]) * coeff \
                        + (self.__break_height - self.__root_height) * dcoeff \
                        + self.__root_height_grad[:]

                else:
                    coeff = (r - p) / (1. - p)
                    dcoeff = (r - 1) * p_grad[:] / (1. - p)**2
                    self.__heights[i] = (
                        (self.__tip_height -
                         self.__break_height) *
                        coeff +
                        self.__break_height)
                    self.__heights_grad[i, :] = (self.__tip_height_grad[:] - self.__break_height_grad[:]) * coeff \
                        + (self.__tip_height - self.__break_height) * dcoeff \
                        + self.__break_height_grad[:]
        else:
            for i, r in enumerate(self.__r_list_y):
                r = abs(2. * r)
                self.__heights[i] = (
                    (self.__tip_height -
                     self.__root_height) *
                    r +
                    self.__root_height)
                self.__heights_grad[
                    i,
                    :] = (
                    (self.__tip_height_grad[:] -
                     self.__root_height_grad[:]) *
                    r +
                    self.__root_height_grad[:])

        #-- build rel_thiks
        for i in xrange(self.__n_sect):
            self.__rel_thicks[i] = self.__heights[i] / self.__chords[i]
            self.__rel_thicks_grad[i,
                                   :] = (self.__heights_grad[i,
                                                             :] * self.__chords[i] - self.__heights[i] * self.__chords_grad[i,
                                                                                                                            :]) / (self.__chords[i])**2

    def __build_XYZ_eta(self):
        self.__XYZ = zeros((3, self.__n_sect))
        self.__XYZ_grad = zeros((3, self.__n_sect, self.__ndv))

        self.__eta = zeros((3, self.__n_sect + 1))
        self.__eta_grad = zeros((3, self.__n_sect + 1, self.__ndv))

        # print 'sweep=',self.__sweep,'sin sweep',sin(self.__sweep)

        for i, r in enumerate(self.__r_list_y):
            abs_r = abs(r)
            #self.__XYZ[0,i]        = 0.25*self.__chords[i] + abs_r*self.__span*sin(self.__sweep)
            self.__XYZ[0, i] = abs_r * self.__span * sin(self.__sweep)
            #self.__XYZ_grad[0,i,:] = 0.25*self.__chords_grad[i] + abs_r*self.__span_grad[:]*sin(self.__sweep)+abs_r*self.__span*cos(self.__sweep)*self.__sweep_grad[:]
            self.__XYZ_grad[0, i, :] = abs_r * self.__span_grad[:] * sin(
                self.__sweep) + abs_r * self.__span * cos(self.__sweep) * self.__sweep_grad[:]

            self.__XYZ[1, i] = r * self.__span
            self.__XYZ_grad[1, i, :] = r * self.__span_grad[:]

        for i, r in enumerate(self.__r_list_eta):
            abs_r = abs(r)
            #self.__eta[0,i]        = 0.25*self.__chords_eta[i] + abs_r*self.__span*sin(self.__sweep)
            self.__eta[0, i] = abs_r * self.__span * sin(self.__sweep)
            #self.__eta_grad[0,i,:] = 0.25*self.__chords_grad_eta[i] + abs_r*self.__span_grad[:]*sin(self.__sweep)+abs_r*self.__span*cos(self.__sweep)*self.__sweep_grad[:]
            self.__eta_grad[0, i, :] = abs_r * self.__span_grad[:] * sin(
                self.__sweep) + abs_r * self.__span * cos(self.__sweep) * self.__sweep_grad[:]

            self.__eta[1, i] = r * self.__span
            self.__eta_grad[1, i, :] = r * self.__span_grad[:]

    # -- Airfoils methods
    def get_linked_airfoils(self):
        return self.__linked_airfoils

    def set_ref_aifoil(self, ref_airfoil):
        self.__ref_airfoil = ref_airfoil

    def set_airfoils(self, airfoils):
        ERROR_MSG = self.ERROR_MSG + 'set_airfoils: '
        if len(airfoils) != self.__n_sect:
            print ERROR_MSG + 'number of airfoils is different than the number of sections. attribute not set'
            self.__airfoils = None
        else:
            self.__airfoils = airfoils

    def build_linear_airfoil(self, OC, AoA0=0., Cm0=0., Sref=1.,
                             Lref=1., rel_thick=0., sweep=0., Ka=0.95, set_as_ref=True):
        self.__airfoil_type = 'simple'
        degToRad = pi / 180.
        airfoil = AnalyticAirfoil(
            OC,
            AoA0=degToRad *
            AoA0,
            Cm0=Cm0,
            Sref=Sref,
            Lref=Lref,
            rel_thick=rel_thick,
            sweep=sweep,
            Ka=Ka)
        if set_as_ref:
            self.set_ref_aifoil(airfoil)
        return airfoil

#     def build_polar_airoil(self, OC, database, Sref=1., Lref=1., interpolator='2DSpline', set_as_ref=True):
#         # Why relative thickness usage ? The extraction from a polar should give us more freedom.
#         airfoil = AirfoilPolar(OC, database,rel_thick=0.15, interpolator=interpolator, Sref=Sref, Lref=Lref)
#         if set_as_ref:
#             self.set_ref_aifoil(airfoil)
#         return airfoil

    def build_meta_airfoil(self, OC, surrogate_model, relative_thickness=.12,
                           camber=0., Sref=1., Lref=1., sweep=.0, set_as_ref=True):
        self.__airfoil_type = 'meta'
        airfoil = MetaAirfoil(OC, surrogate_model, relative_thickness=relative_thickness,
                              camber=camber, Sref=Sref, Lref=Lref, sweep=sweep)
        if set_as_ref:
            self.set_ref_aifoil(airfoil)
        return airfoil

    def build_airfoils_from_ref(self):
        ERROR_MSG = self.ERROR_MSG + 'build_airfoils_from_ref: '
        if self.__ref_airfoil is None:
            print ERROR_MSG + 'cannot build airfoils if reference airfoil is not defined.'
        else:
            airfoils = []
            for n in xrange(self.__n_sect):
                airfoils.append(self.__ref_airfoil.get_scaled_copy())

            self.set_airfoils(airfoils)

    def __link_airfoils_to_geom(self):
        self.__linked_airfoils = []
        for i in range(self.__n_sect):
            LLoc, LLoc_grad, SLoc, SLoc_grad = self.__compute_local_info(i)
            linked_af = self.__airfoils[i].get_scaled_copy(
                Sref=SLoc,
                Lref=LLoc)
            linked_af.set_Sref_grad(SLoc_grad)
            linked_af.set_Lref_grad(LLoc_grad)
            linked_af.set_rel_thick_grad(self.__rel_thicks_grad[i])
            linked_af.set_rel_thick(self.__rel_thicks[i])
            linked_af.set_sweep(self.__sweep)
            linked_af.set_sweep_grad(self.__sweep_grad)
            self.__linked_airfoils.append(linked_af)

    def __compute_local_info(self, i):
        LLoc = self.__chords[i]
        LLoc_grad = self.__chords_grad[i]
        SLoc = LLoc * (self.__eta[1, i + 1] - self.__eta[1, i])
        SLoc_grad = LLoc_grad * (self.__eta[1, i + 1] - self.__eta[1, i]) + \
            LLoc * (self.__eta_grad[1, i + 1, :] - self.__eta_grad[1, i, :])
#         SLoc      = self.__span * LLoc / float(self.__n_sect)
#         SLoc_grad = (self.__span_grad * LLoc + self.__span * LLoc_grad) / float(self.__n_sect)
        return LLoc, LLoc_grad, SLoc, SLoc_grad

    def __compute_Sref_Lref_ToC_AR_fuel(self):
        """
        Compute Lref and Sref from airfoils information, ToC and AR
        """
        N = self.__n_sect

        self.__Sref = 0.
        self.__Lref = 0.
        self.__fuel = 0.
        self.__Sref_grad = zeros(self.__ndv)
        self.__Lref_grad = zeros(self.__ndv)
        self.__fuel_grad = zeros(self.__ndv)

        for i, af in enumerate(self.__linked_airfoils):
            self.__Sref += af.get_Sref()
            self.__Lref += af.get_Lref()
            self.__fuel += self.__rel_thicks[i] * \
                self.__chords[i] * af.get_Sref() * 0.5
            self.__Sref_grad += af.get_Sref_grad()
            self.__Lref_grad += af.get_Lref_grad()
            self.__fuel_grad += self.__rel_thicks_grad[i] * self.__chords[i] * af.get_Sref() * 0.5\
                + self.__rel_thicks[i] * self.__chords_grad[i] * af.get_Sref() * 0.5\
                + self.__rel_thicks[i] * self.__chords[i] * af.get_Sref_grad() * 0.5\

        self.__Lref /= N
        self.__Lref_grad /= N

        self.__root_ToC = self.__root_height / self.__root_chord
        self.__root_ToC_grad = (self.__root_height_grad * self.__root_chord -
                                self.__root_height * self.__root_chord_grad) / self.__root_chord**2

        if self.__break_chord is not None:
            self.__break_ToC = self.__break_height / self.__break_chord
            self.__break_ToC_grad = (self.__break_height_grad * self.__break_chord -
                                     self.__break_height * self.__break_chord_grad) / self.__break_chord**2

        if self.__tip_chord is not None:
            self.__tip_ToC = self.__tip_height / self.__tip_chord
            self.__tip_ToC_grad = (self.__tip_height_grad * self.__tip_chord -
                                   self.__tip_height * self.__tip_chord_grad) / self.__tip_chord**2

        self.__AR = self.__span**2 / self.__Sref
        self.__AR_grad = (2. * self.__span * self.__span_grad *
                          self.__Sref - self.__span**2 * self.__Sref_grad) / self.__Sref**2

    def __check_airfoils_inputs(self):
        ERROR_MSG = self.ERROR_MSG + \
            '__check_airfoils_inputs: ' + str(self.__tag) + ': '
        checked = True
        if self.__airfoils is None:
            checked = False
            print ERROR_MSG + 'airfoils attribute undefined. please set airfoils attribute.'
        elif len(self.__airfoils) != self.__n_sect:
            checked = False
            print ERROR_MSG + 'number of airfoils must equal to the number of geometrical sections.'

        if not checked:
            sys.exit(1)