Example #1
0
class BladeStructureBuilderBase(Component):
    """
    base class for components that can interpret the BladeStructure3DVT
    vartree and generate input for specific types of codes.
    """

    surface = VarTree(BladeSurfaceVT(),
                      iotype='in',
                      desc='Stacked blade surface object')
    st3d = VarTree(BladeStructureVT3D(),
                   iotype='in',
                   desc='Blade structure definition')

    def execute(self):

        raise NotImplementedError(
            '%s.execute needs to be overwritten by derived classes' %
            self.get_pathname())

    def get_material(self, name):
        """
        retrieve a material by its name
        
        parameters
        ----------
        name: string
            name of material

        returns
        -------
        mat: object
            MaterialProps VariableTree object
        """

        # strip integers from name to be safe
        st = ''.join(i for i in name if i.isalpha())
        try:
            return self.st3d.materials[st]
        except:
            return None
Example #2
0
class LoftedBladeSurface(Component):

    pf = VarTree(BladePlanformVT(), iotype='in')
    base_airfoils = List(iotype='in')
    blend_var = Array(iotype='in')
    chord_ni = Int(300, iotype='in')
    span_ni = Int(300, iotype='in')

    interp_type = Enum('rthick', ('rthick', 's'), iotype='in')
    surface_spline = Str('akima', iotype='in', desc='Spline')

    rot_order = Array(np.array([2, 1, 0]),
                      iotype='in',
                      desc='rotation order of airfoil sections'
                      'default z,y,x (twist,sweep,dihedral)')

    surfout = VarTree(BladeSurfaceVT(), iotype='out')
    surfnorot = VarTree(BladeSurfaceVT(), iotype='out')

    def execute(self):

        self.interpolator = BlendAirfoilShapes()
        self.interpolator.ni = self.chord_ni
        self.interpolator.spline = self.surface_spline
        self.interpolator.blend_var = self.blend_var
        self.interpolator.airfoil_list = self.base_airfoils
        self.interpolator.initialize()

        self.span_ni = self.pf.s.shape[0]
        x = np.zeros((self.chord_ni, self.span_ni, 3))

        for i in range(self.span_ni):

            s = self.pf.s[i]
            pos_x = self.pf.x[i]
            pos_y = self.pf.y[i]
            pos_z = self.pf.z[i]
            chord = self.pf.chord[i]
            p_le = self.pf.p_le[i]

            # generate the blended airfoil shape
            if self.interp_type == 'rthick':
                rthick = self.pf.rthick[i]
                points = self.interpolator(rthick)
            else:
                points = self.interpolator(s)

            points *= chord
            points[:, 0] += pos_x - chord * p_le

            # x-coordinate needs to be inverted for clockwise rotating blades
            x[:, i, :] = (np.array(
                [-points[:, 0], points[:, 1], x.shape[0] * [pos_z]]).T)

        # save non-rotated blade (only really applicable for straight blades)
        x_norm = x.copy()
        x[:, :, 1] += self.pf.y
        x = self.rotate(x)

        self.surfnorot.surface = x_norm
        self.surfout.surface = x

    def rotate(self, x):
        """
        rotate blade sections accounting for twist and main axis orientation
        
        the blade will be built with a "sheared" layout, ie no rotation around y
        in the case of sweep.
        if the main axis includes a winglet, the blade sections will be
        rotated accordingly. ensure that an adequate point distribution is
        used in this case to avoid sections colliding in the winglet junction!
        """

        main_axis = Curve(points=np.array([self.pf.x, self.pf.y, self.pf.z]).T)

        rot_normals = np.zeros((3, 3))
        x_rot = np.zeros(x.shape)

        for i in range(x.shape[1]):
            points = x[:, i, :]
            rot_center = main_axis.points[i]
            # rotation angles read from file
            angles = np.array([
                self.pf.rot_x[i], self.pf.rot_y[i], self.pf.rot_z[i]
            ]) * np.pi / 180.

            # compute rotation angles of main_axis
            t = main_axis.dp[i]
            rot = np.zeros(3)
            rot[0] = -np.arctan(t[1] / (t[2] + 1.e-20))
            v = np.array([t[2], t[1]])
            vt = np.dot(v, v)**0.5
            rot[1] = (np.arcsin(t[0] / vt))
            angles[0] += rot[0]
            angles[1] += rot[1]

            # compute x-y-z normal vectors of rotation
            n_y = np.cross(t, [1, 0, 0])
            n_y = n_y / norm(n_y)
            rot_normals[0, :] = np.array([1, 0, 0])
            rot_normals[1, :] = n_y
            rot_normals[2, :] = t

            # compute final rotation matrix
            rotation_matrix = np.matrix([[1., 0., 0.], [0., 1., 0.],
                                         [0., 0., 1.]])
            for n, ii in enumerate(self.rot_order):
                mat = np.matrix(RotMat(rot_normals[ii], angles[ii]))
                rotation_matrix = mat * rotation_matrix

            # apply rotation
            x_rot[:, i, :] = dotXC(rotation_matrix, points, rot_center)

        return x_rot
Example #3
0
class LoftedBladeSurfaceBase(Component):

    surfout = VarTree(BladeSurfaceVT(), iotype='out')
    surfnorot = VarTree(BladeSurfaceVT(), iotype='out')
Example #4
0
class BladeStructureCSBuilder(BladeStructureBuilderBase):
    """
    Class that generates a series of 2D cross-sectional property
    vartrees (CrossSectionStructureVT) used by structural codes like BECAS
    """

    blade_length = Float(1., iotype='in')
    surface = VarTree(BladeSurfaceVT(),
                      iotype='in',
                      desc='Stacked blade surface object')
    st3d = VarTree(BladeStructureVT3D(),
                   iotype='in',
                   desc='Blade structure definition')

    cs2d = List(iotype='out',
                desc='List of cross-sectional properties'
                'vartrees')

    def execute(self):
        """
        generate cross sections at every spanwise node of the st3d vartree
        """

        # clear list of outputs!
        self.cs2d = []

        ni = self.st3d.x.shape[0]
        for i in range(ni):
            x = self.st3d.x[i]
            # print 'adding section at r/R = %2.2f' % x
            st2d = CrossSectionStructureVT()
            st2d.s = x * self.blade_length
            st2d.DPs = []
            try:
                airfoil = self.surface.interpolate_profile(
                    x)[:, [0, 1]] * self.blade_length
                st2d.airfoil.initialize(airfoil)
            except:
                pass
            for ir, rname in enumerate(self.st3d.regions):
                reg = getattr(self.st3d, rname)
                if reg.thickness[i] == 0.:
                    print 'zero thickness region!', rname
                    # continue
                DP0 = getattr(self.st3d, 'DP%02d' % ir)
                DP1 = getattr(self.st3d, 'DP%02d' % (ir + 1))
                r = st2d.add_region(rname.upper())
                st2d.DPs.append(DP0[i])
                r.s0 = DP0[i]
                r.s1 = DP1[i]
                for lname in reg.layers:
                    lay = getattr(reg, lname)
                    if lay.thickness[i] > 1.e-5:
                        l = r.add_layer(lname)
                        # try:
                        lnamebase = lname.translate(None, digits)
                        st2d.add_material(lnamebase,
                                          self.get_material(lname).copy())
                        # except:
                        # raise RuntimeError('Material %s not in materials list' % lname)
                        l.materialname = lnamebase
                        l.thickness = max(0., lay.thickness[i])
                        try:
                            l.angle = lay.angle[i]
                        except:
                            l.angle = 0.

            st2d.DPs.append(DP1[i])
            for ir, rname in enumerate(self.st3d.webs):
                reg = getattr(self.st3d, rname)
                if reg.thickness[i] == 0.:
                    continue
                r = st2d.add_web(rname.upper())
                try:
                    DP0 = getattr(self.st3d, 'DP%02d' % self.st3d.iwebs[ir][0])
                except:
                    DP0 = getattr(
                        self.st3d, 'DP%02d' %
                        (len(self.st3d.regions) + self.st3d.iwebs[ir][0] + 1))
                try:
                    DP1 = getattr(self.st3d, 'DP%02d' % self.st3d.iwebs[ir][1])
                except:
                    DP1 = getattr(
                        self.st3d, 'DP%02d' %
                        (len(self.st3d.regions) + self.st3d.iwebs[ir][1] + 1))
                r.s0 = DP0[i]
                r.s1 = DP1[i]
                for lname in reg.layers:
                    lay = getattr(reg, lname)
                    if lay.thickness[i] > 1.e-5:
                        l = r.add_layer(lname)
                        try:
                            lnamebase = lname.translate(None, digits)
                            st2d.add_material(lnamebase,
                                              self.get_material(lname).copy())
                        except:
                            raise RuntimeError(
                                'Material %s not in materials list' % lname)
                        l.materialname = lnamebase
                        l.thickness = max(0., lay.thickness[i])
                        try:
                            l.angle = lay.angle[i]
                        except:
                            l.angle = 0.

            self.cs2d.append(st2d)