pygeo/parameterization/DVGeo.py
def sectionFrame(self, sectionIndex, sectionTransform, sectionLink, ivol=0, orient0=None, orient2="svd"):
        """
        This function computes a unique reference coordinate frame for each
        section of an FFD volume. You can choose which axis of the FFD you would
        like these sections to be defined by. For example, if we have a wing
        with a winglet, the airfoil sections which make up the wing will not all
        lie in parallel planes. We want to find a reference frame for each of
        these airfoil sections so that we can constrain local control points to
        deform within the sectional plane. Let's say the wing FFD is oriented
        with indices:

        `i`
            along chord
        `j`
            normal to wing surface
        `k`
            along span

        If we choose `sectionIndex='k'`, this function will compute a frame which
        has two axes aligned with the k-planes of the FFD volume. This is useful
        because in some cases (as with a winglet), we want to perturb sectional
        control points within the section plane instead of in the global
        coordinate directions.

        Assumptions:

        * the normal direction is computed along the block index with size 2
        * all point for a given sectionIndex lie within a plane

        Parameters
        ----------
        sectionIndex : `i`, `j`, or `k`
            This the index of the FFD which defines a section plane.

        orient0 : None, `i`, `j`, `k`, or numpy vector. Default is None.
            Although secIndex defines the '2' axis, the '0' and '1' axes are still
            free to rotate within the section plane. We will choose the orientation
            of the '0' axis and let '1' be orthogonal. See `addLocalSectionDV`
            for a more detailed description.

        ivol : integer
            Volume ID for the volume in which section normals will be computed.

        alignStreamwise : `x`, `y`, or `z` (optional)
            If given, section frames are rotated about the k-plane normal
            so that the longitudinal axis is parallel with the given streamwise
            direction.

        rootGlobal : list
            List of sections along specified axis that will be fixed to the
            global coordinate frame.

        Returns
        -------
        sectionTransform : list of 3x3 arrays
            List of transformation matrices for the sections of a given volume.
            Transformations are set up from local section frame to global frame.
        """
        # xyz_2_idx = {"x": 0, "y": 1, "z": 2}
        ijk_2_idx = {"i": 0, "j": 1, "k": 2}
        lIndex = self.FFD.topo.lIndex[ivol]

        # Get normal index
        orient0idx = False
        orient0vec = False
        if orient0 is not None:
            if isinstance(orient0, str):
                orient0 = ijk_2_idx[orient0.lower()]
                orient0idx = True
            elif isinstance(orient0, np.ndarray):
                orient0vec = True
            else:
                raise Error("orient0 must be an index (i, j, or k) or a " "vector.")
        # Get section index and number of sections
        sectionIndex = ijk_2_idx[sectionIndex.lower()]
        nSections = lIndex.shape[sectionIndex]

        # Roll lIndex so that 0th index is sectionIndex and 1st index is orient0
        rolledlIndex = np.rollaxis(lIndex, sectionIndex, 0)
        if orient0idx:
            if orient0 != 2:
                orient0 += 1
            rolledlIndex = np.rollaxis(rolledlIndex, orient0, 1)

        # Length of sectionTransform
        Tcount = len(sectionTransform)

        for i in range(nSections):
            # Compute singular value decomposition of points in section (the
            # U matrix should provide us with a pretty good approximation
            # of the transformation matrix)
            pts = self.FFD.coef[rolledlIndex[i, :, :]]
            nJ, nI = pts.shape[:-1]
            X = np.reshape(pts, (nI * nJ, 3))
            c = np.mean(X, 0)
            A = X - c
            U, S, V = np.linalg.svd(A.T)

            # Choose section plane normal axis
            if orient2 == "svd":
                ax2 = U[:, 2]
            elif orient2 == "ffd":
                # Use a centered FD approximation (first order at the boundaries)
                if i == 0:
                    pt = np.mean(self.FFD.coef[rolledlIndex[i, :, :]].reshape(nI * nJ, 3), 0)
                    ptp = np.mean(self.FFD.coef[rolledlIndex[i + 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = ptp - pt
                elif i == nSections - 1:
                    pt = np.mean(self.FFD.coef[rolledlIndex[i, :, :]].reshape(nI * nJ, 3), 0)
                    ptm = np.mean(self.FFD.coef[rolledlIndex[i - 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = pt - ptm
                else:
                    ptp = np.mean(self.FFD.coef[rolledlIndex[i + 1, :, :]].reshape(nI * nJ, 3), 0)
                    ptm = np.mean(self.FFD.coef[rolledlIndex[i - 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = ptp - ptm
                ax2 /= np.linalg.norm(ax2)
            else:
                raise Error("orient2 must be 'svd' or 'ffd'")

            # Options for choosing in-plane axes
            # 1. Align axis '0' with projection of the given vector on section
            #       plane.
            # 2. Align axis '0' with the projection of an average
            #       difference vector between opposing edges of FFD block
            #       section plane
            # 3. Use the default SVD decomposition (in general this will work).
            #       It will choose the chordwise direction as the best fit line
            #       through the section points.
            if orient0vec or orient0idx:
                if orient0vec:
                    u = orient0 / np.linalg.norm(orient0)
                else:
                    u = np.mean((pts[-1, :] - pts[0, :]), axis=0)
                    u = u / np.linalg.norm(u)
                ax0 = u - u.dot(ax2) * ax2
                ax1 = np.cross(ax2, ax0)
            else:
                ax0 = U[:, 0]
                ax1 = U[:, 1]

            T = np.vstack((ax0, ax1, ax2)).T
            sectionTransform.append(T)
            # Designate section transformation matrix for each control point in
            # section
            sectionLink[rolledlIndex[i, :, :]] = Tcount
            Tcount += 1

            # Need to initialize coefRotM to identity matrix for case with no
            # global design variables
            for j in rolledlIndex[i, :, :]:
                for coef in j:
                    self.coefRotM[coef] = np.eye(3)

        return nSections

        This function computes a unique reference coordinate frame for each
        section of an FFD volume. You can choose which axis of the FFD you would
        like these sections to be defined by. For example, if we have a wing
        with a winglet, the airfoil sections which make up the wing will not all
        lie in parallel planes. We want to find a reference frame for each of
        these airfoil sections so that we can constrain local control points to
        deform within the sectional plane. Let's say the wing FFD is oriented
        with indices:

        `i`
            along chord
        `j`
            normal to wing surface
        `k`
            along span

        If we choose `sectionIndex='k'`, this function will compute a frame which
        has two axes aligned with the k-planes of the FFD volume. This is useful
        because in some cases (as with a winglet), we want to perturb sectional
        control points within the section plane instead of in the global
        coordinate directions.

        Assumptions:

        * the normal direction is computed along the block index with size 2
        * all point for a given sectionIndex lie within a plane

        Parameters
        ----------
        sectionIndex : `i`, `j`, or `k`
            This the index of the FFD which defines a section plane.

        orient0 : None, `i`, `j`, `k`, or numpy vector. Default is None.
            Although secIndex defines the '2' axis, the '0' and '1' axes are still
            free to rotate within the section plane. We will choose the orientation
            of the '0' axis and let '1' be orthogonal. See `addLocalSectionDV`
            for a more detailed description.

        ivol : integer
            Volume ID for the volume in which section normals will be computed.

        alignStreamwise : `x`, `y`, or `z` (optional)
            If given, section frames are rotated about the k-plane normal
            so that the longitudinal axis is parallel with the given streamwise
            direction.

        rootGlobal : list
            List of sections along specified axis that will be fixed to the
            global coordinate frame.

        Returns
        -------
        sectionTransform : list of 3x3 arrays
            List of transformation matrices for the sections of a given volume.
            Transformations are set up from local section frame to global frame.
        
This function computes a unique reference coordinate frame for each
section of an FFD volume. You can choose which axis of the FFD you would
like these sections to be defined by. For example, if we have a wing
with a winglet, the airfoil sections which make up the wing will not all
lie in parallel planes. We want to find a reference frame for each of
these airfoil sections so that we can constrain local control points to
deform within the sectional plane. Let's say the wing FFD is oriented
with indices.



If we choose `sectionIndex='k'`, this function will compute a frame which
has two axes aligned with the k-planes of the FFD volume. This is useful
because in some cases (as with a winglet), we want to perturb sectional
control points within the section plane instead of in the global
coordinate directions.



the normal direction is computed along the block index with size 2
all point for a given sectionIndex lie within a plane

Parameters





ivol : integer
Volume ID for the volume in which section normals will be computed.



rootGlobal : list
List of sections along specified axis that will be fixed to the
global coordinate frame.

Returns

sectionTransform : list of 3x3 arrays
List of transformation matrices for the sections of a given volume.
Transformations are set up from local section frame to global frame.
This function computes a unique reference coordinate frame for each section of an FFD volume . You can choose which axis of the FFD you would like these sections to be defined by . For example if we have a wing with a winglet the airfoil sections which make up the wing will not all lie in parallel planes . We want to find a reference frame for each of these airfoil sections so that we can constrain local control points to deform within the sectional plane . Let ' s say the wing FFD is oriented with indices . If we choose ` sectionIndex = ' k ' ` this function will compute a frame which has two axes aligned with the k - planes of the FFD volume . This is useful because in some cases ( as with a winglet ) we want to perturb sectional control points within the section plane instead of in the global coordinate directions . the normal direction is computed along the block index with size 2 all point for a given sectionIndex lie within a plane Parameters ivol : integer Volume ID for the volume in which section normals will be computed . rootGlobal : list List of sections along specified axis that will be fixed to the global coordinate frame . Returns sectionTransform : list of 3x3 arrays List of transformation matrices for the sections of a given volume . Transformations are set up from local section frame to global frame .
def sectionFrame(self, sectionIndex, sectionTransform, sectionLink, ivol=0, orient0=None, orient2="svd"):
        ijk_2_idx = {"i": 0, "j": 1, "k": 2}
        lIndex = self.FFD.topo.lIndex[ivol]
        orient0idx = False
        orient0vec = False
        if orient0 is not None:
            if isinstance(orient0, str):
                orient0 = ijk_2_idx[orient0.lower()]
                orient0idx = True
            elif isinstance(orient0, np.ndarray):
                orient0vec = True
            else:
                raise Error("orient0 must be an index (i, j, or k) or a " "vector.")
        sectionIndex = ijk_2_idx[sectionIndex.lower()]
        nSections = lIndex.shape[sectionIndex]
        rolledlIndex = np.rollaxis(lIndex, sectionIndex, 0)
        if orient0idx:
            if orient0 != 2:
                orient0 += 1
            rolledlIndex = np.rollaxis(rolledlIndex, orient0, 1)
        Tcount = len(sectionTransform)
        for i in range(nSections):
            pts = self.FFD.coef[rolledlIndex[i, :, :]]
            nJ, nI = pts.shape[:-1]
            X = np.reshape(pts, (nI * nJ, 3))
            c = np.mean(X, 0)
            A = X - c
            U, S, V = np.linalg.svd(A.T)
            if orient2 == "svd":
                ax2 = U[:, 2]
            elif orient2 == "ffd":
                if i == 0:
                    pt = np.mean(self.FFD.coef[rolledlIndex[i, :, :]].reshape(nI * nJ, 3), 0)
                    ptp = np.mean(self.FFD.coef[rolledlIndex[i + 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = ptp - pt
                elif i == nSections - 1:
                    pt = np.mean(self.FFD.coef[rolledlIndex[i, :, :]].reshape(nI * nJ, 3), 0)
                    ptm = np.mean(self.FFD.coef[rolledlIndex[i - 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = pt - ptm
                else:
                    ptp = np.mean(self.FFD.coef[rolledlIndex[i + 1, :, :]].reshape(nI * nJ, 3), 0)
                    ptm = np.mean(self.FFD.coef[rolledlIndex[i - 1, :, :]].reshape(nI * nJ, 3), 0)
                    ax2 = ptp - ptm
                ax2 /= np.linalg.norm(ax2)
            else:
                raise Error("orient2 must be 'svd' or 'ffd'")
            if orient0vec or orient0idx:
                if orient0vec:
                    u = orient0 / np.linalg.norm(orient0)
                else:
                    u = np.mean((pts[-1, :] - pts[0, :]), axis=0)
                    u = u / np.linalg.norm(u)
                ax0 = u - u.dot(ax2) * ax2
                ax1 = np.cross(ax2, ax0)
            else:
                ax0 = U[:, 0]
                ax1 = U[:, 1]
            T = np.vstack((ax0, ax1, ax2)).T
            sectionTransform.append(T)
            sectionLink[rolledlIndex[i, :, :]] = Tcount
            Tcount += 1
            for j in rolledlIndex[i, :, :]:
                for coef in j:
                    self.coefRotM[coef] = np.eye(3)
        return nSections
def sectionFrame ( self , sectionIndex , sectionTransform , sectionLink , ivol = 0 , orient0 = None , orient2 = "svd" ) : ijk_2_idx = { "i" : 0 , "j" : 1 , "k" : 2 } lIndex = self . FFD . topo . lIndex [ ivol ] orient0idx = False orient0vec = False if orient0 is not None : if isinstance ( orient0 , str ) : orient0 = ijk_2_idx [ orient0 . lower ( ) ] orient0idx = True elif isinstance ( orient0 , np . ndarray ) : orient0vec = True else : raise Error ( "orient0 must be an index (i, j, or k) or a " "vector." ) sectionIndex = ijk_2_idx [ sectionIndex . lower ( ) ] nSections = lIndex . shape [ sectionIndex ] rolledlIndex = np . rollaxis ( lIndex , sectionIndex , 0 ) if orient0idx : if orient0 != 2 : orient0 += 1 rolledlIndex = np . rollaxis ( rolledlIndex , orient0 , 1 ) Tcount = len ( sectionTransform ) for i in range ( nSections ) : pts = self . FFD . coef [ rolledlIndex [ i , : , : ] ] nJ , nI = pts . shape [ : - 1 ] X = np . reshape ( pts , ( nI * nJ , 3 ) ) c = np . mean ( X , 0 ) A = X - c U , S , V = np . linalg . svd ( A . T ) if orient2 == "svd" : ax2 = U [ : , 2 ] elif orient2 == "ffd" : if i == 0 : pt = np . mean ( self . FFD . coef [ rolledlIndex [ i , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ptp = np . mean ( self . FFD . coef [ rolledlIndex [ i + 1 , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ax2 = ptp - pt elif i == nSections - 1 : pt = np . mean ( self . FFD . coef [ rolledlIndex [ i , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ptm = np . mean ( self . FFD . coef [ rolledlIndex [ i - 1 , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ax2 = pt - ptm else : ptp = np . mean ( self . FFD . coef [ rolledlIndex [ i + 1 , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ptm = np . mean ( self . FFD . coef [ rolledlIndex [ i - 1 , : , : ] ] . reshape ( nI * nJ , 3 ) , 0 ) ax2 = ptp - ptm ax2 /= np . linalg . norm ( ax2 ) else : raise Error ( "orient2 must be 'svd' or 'ffd'" ) if orient0vec or orient0idx : if orient0vec : u = orient0 / np . linalg . norm ( orient0 ) else : u = np . mean ( ( pts [ - 1 , : ] - pts [ 0 , : ] ) , axis = 0 ) u = u / np . linalg . norm ( u ) ax0 = u - u . dot ( ax2 ) * ax2 ax1 = np . cross ( ax2 , ax0 ) else : ax0 = U [ : , 0 ] ax1 = U [ : , 1 ] T = np . vstack ( ( ax0 , ax1 , ax2 ) ) . T sectionTransform . append ( T ) sectionLink [ rolledlIndex [ i , : , : ] ] = Tcount Tcount += 1 for j in rolledlIndex [ i , : , : ] : for coef in j : self . coefRotM [ coef ] = np . eye ( 3 ) return nSections
This function computes a unique reference coordinate frame for each
section of an FFD volume.
This function computes a unique reference coordinate frame for each section of an FFD volume .
"""
        This function computes a unique reference coordinate frame for each
        section of an FFD volume. You can choose which axis of the FFD you would
        like these sections to be defined by. For example, if we have a wing
        with a winglet, the airfoil sections which make up the wing will not all
        lie in parallel planes. We want to find a reference frame for each of
        these airfoil sections so that we can constrain local control points to
        deform within the sectional plane. Let's say the wing FFD is oriented
        with indices:

        `i`
            along chord
        `j`
            normal to wing surface
        `k`
            along span

        If we choose `sectionIndex='k'`, this function will compute a frame which
        has two axes aligned with the k-planes of the FFD volume. This is useful
        because in some cases (as with a winglet), we want to perturb sectional
        control points within the section plane instead of in the global
        coordinate directions.

        Assumptions:

        * the normal direction is computed along the block index with size 2
        * all point for a given sectionIndex lie within a plane

        Parameters
        ----------
        sectionIndex : `i`, `j`, or `k`
            This the index of the FFD which defines a section plane.

        orient0 : None, `i`, `j`, `k`, or numpy vector. Default is None.
            Although secIndex defines the '2' axis, the '0' and '1' axes are still
            free to rotate within the section plane. We will choose the orientation
            of the '0' axis and let '1' be orthogonal. See `addLocalSectionDV`
            for a more detailed description.

        ivol : integer
            Volume ID for the volume in which section normals will be computed.

        alignStreamwise : `x`, `y`, or `z` (optional)
            If given, section frames are rotated about the k-plane normal
            so that the longitudinal axis is parallel with the given streamwise
            direction.

        rootGlobal : list
            List of sections along specified axis that will be fixed to the
            global coordinate frame.

        Returns
        -------
        sectionTransform : list of 3x3 arrays
            List of transformation matrices for the sections of a given volume.
            Transformations are set up from local section frame to global frame.
        """ # xyz_2_idx = {"x": 0, "y": 1, "z": 2} # Get normal index # Get section index and number of sections # Roll lIndex so that 0th index is sectionIndex and 1st index is orient0 # Length of sectionTransform # Compute singular value decomposition of points in section (the # U matrix should provide us with a pretty good approximation # of the transformation matrix) # Choose section plane normal axis # Use a centered FD approximation (first order at the boundaries) # Options for choosing in-plane axes # 1. Align axis '0' with projection of the given vector on section #       plane. # 2. Align axis '0' with the projection of an average #       difference vector between opposing edges of FFD block #       section plane # 3. Use the default SVD decomposition (in general this will work). #       It will choose the chordwise direction as the best fit line #       through the section points. # Designate section transformation matrix for each control point in # section # Need to initialize coefRotM to identity matrix for case with no # global design variables
self
sectionIndex
sectionTransform
sectionLink
ivol
orient0
orient2