def compute(self, inputs, outputs):
        dtype = float
        if self.under_complex_step:
            dtype = complex

        self.T = np.zeros((3, 3),dtype=dtype)
        self.x_gl = np.array([1, 0, 0],dtype=dtype)
        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            P0 = nodes[ielem, :]
            P1 = nodes[ielem+1, :]
            L = norm(P1 - P0)

            x_loc = unit(P1 - P0)
            y_loc = unit(np.cross(x_loc, x_gl))
            z_loc = unit(np.cross(x_loc, y_loc))

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem+1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem+1, 3:])

            tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2)
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L

            outputs['vonmises'][ielem, 0] = np.sqrt(sxx0**2 + 3 * sxt**2)
            outputs['vonmises'][ielem, 1] = np.sqrt(sxx1**2 + 3 * sxt**2)
Beispiel #2
0
    def compute(self, inputs, outputs):
        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        if fortran_flag:
            vm = OAS_API.oas_api.calc_vonmises(nodes, radius, disp, E, G, x_gl)
            outputs['vonmises'] = vm

        else:

            num_elems = self.ny - 1
            for ielem in range(self.ny - 1):

                P0 = nodes[ielem, :]
                P1 = nodes[ielem + 1, :]
                L = norm(P1 - P0)

                x_loc = unit(P1 - P0)
                y_loc = unit(np.cross(x_loc, x_gl))
                z_loc = unit(np.cross(x_loc, y_loc))

                T[0, :] = x_loc
                T[1, :] = y_loc
                T[2, :] = z_loc

                u0x, u0y, u0z = T.dot(disp[ielem, :3])
                r0x, r0y, r0z = T.dot(disp[ielem, 3:])
                u1x, u1y, u1z = T.dot(disp[ielem + 1, :3])
                r1x, r1y, r1z = T.dot(disp[ielem + 1, 3:])

                tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2)
                sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
                sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
                sxt = G * radius[ielem] * (r1x - r0x) / L

                outputs['vonmises'][ielem, 0] = np.sqrt(sxx0**2 + 3 * sxt**2)
                outputs['vonmises'][ielem, 1] = np.sqrt(sxx1**2 + 3 * sxt**2)
    def compute(self, inputs, outputs):
        dtype = float
        if self.under_complex_step:
            dtype = complex

        self.T = np.zeros((3, 3), dtype=dtype)
        self.x_gl = np.array([1, 0, 0], dtype=dtype)
        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            P0 = nodes[ielem, :]
            P1 = nodes[ielem + 1, :]
            L = norm(P1 - P0)

            x_loc = unit(P1 - P0)
            y_loc = unit(np.cross(x_loc, x_gl))
            z_loc = unit(np.cross(x_loc, y_loc))

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem + 1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem + 1, 3:])

            tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2)
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L

            outputs['vonmises'][ielem, 0] = np.sqrt(sxx0**2 + 3 * sxt**2)
            outputs['vonmises'][ielem, 1] = np.sqrt(sxx1**2 + 3 * sxt**2)
    def compute(self, inputs, outputs):
        disp = inputs['disp']
        nodes = inputs['nodes']
        A_enc = inputs['A_enc']
        Qy = inputs['Qz']
        J = inputs['J']
        htop = inputs['htop']
        hbottom = inputs['hbottom']
        hfront = inputs['hfront']
        hrear = inputs['hrear']
        spar_thickness = inputs['spar_thickness']
        vonmises = outputs['vonmises']

        # Only use complex type for these arrays if we're using cs to check derivs
        dtype = type(disp[0, 0])
        T = np.zeros((3, 3), dtype=dtype)
        x_gl = np.array([1, 0, 0], dtype=dtype)

        E = self.E
        G = self.G

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            P0 = nodes[ielem, :]
            P1 = nodes[ielem + 1, :]
            L = norm(P1 - P0)

            x_loc = unit(P1 - P0)
            y_loc = unit(np.cross(x_loc, x_gl))
            z_loc = unit(np.cross(x_loc, y_loc))

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem + 1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem + 1, 3:])

            # this is stress = modulus * strain; positive is tensile
            axial_stress = E * (u1x - u0x) / L

            # this is Torque / (2 * thickness_min * Area_enclosed)
            torsion_stress = G * J[ielem] / L * (
                r1x - r0x) / 2 / spar_thickness[ielem] / A_enc[ielem]

            # this is moment * h / I
            top_bending_stress = E / (L**2) * (
                6 * u0y + 2 * r0z * L - 6 * u1y + 4 * r1z * L) * htop[ielem]

            # this is moment * h / I
            bottom_bending_stress = -E / (L**2) * (
                6 * u0y + 2 * r0z * L - 6 * u1y + 4 * r1z * L) * hbottom[ielem]

            # this is moment * h / I
            front_bending_stress = -E / (L**2) * (
                -6 * u0z + 2 * r0y * L + 6 * u1z + 4 * r1y * L) * hfront[ielem]

            # this is moment * h / I
            rear_bending_stress = E / (L**2) * (
                -6 * u0z + 2 * r0y * L + 6 * u1z + 4 * r1y * L) * hrear[ielem]

            # shear due to bending (VQ/It) note: the I used to get V cancels the other I
            vertical_shear = E / (L**3) * (-12 * u0y - 6 * r0z * L + 12 * u1y -
                                           6 * r1z * L) * Qy[ielem] / (
                                               2 * spar_thickness[ielem])

            # print("==========",ielem,"================")
            # print("vertical_shear", vertical_shear)
            # print("top",top_bending_stress)
            # print("bottom",bottom_bending_stress)
            # print("front",front_bending_stress)
            # print("rear",rear_bending_stress)
            # print("axial", axial_stress)
            # print("torsion", torsion_stress)

            # The 4 stress combinations:
            vonmises[ielem, 0] = np.sqrt(
                (top_bending_stress + rear_bending_stress + axial_stress)**2 +
                3 * torsion_stress**2) / self.tssf
            vonmises[ielem,
                     1] = np.sqrt((bottom_bending_stress +
                                   front_bending_stress + axial_stress)**2 +
                                  3 * torsion_stress**2)
            vonmises[ielem,
                     2] = np.sqrt((front_bending_stress + axial_stress)**2 +
                                  3 * (torsion_stress - vertical_shear)**2)
            vonmises[ielem, 3] = np.sqrt(
                (rear_bending_stress + axial_stress)**2 + 3 *
                (torsion_stress + vertical_shear)**2) / self.tssf
    def compute_partials(self, inputs, partials):

        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            # Compute the coordinate delta between the two element end points
            P0 = nodes[ielem, :]
            P1 = nodes[ielem+1, :]
            dP = P1 - P0

            # Compute the derivative of element length
            L = norm(dP)
            dLddP = norm_d(dP)

            # unit function converts a vector to a unit vector
            # calculate the transormation to the local element frame.
            # We use x_gl to provide a reference axis to reference
            x_loc = unit(dP)
            dxdP = unit_d(dP)

            y_loc = unit(np.cross(x_loc, x_gl))
            dtmpdx, _ = cross_d(x_loc, x_gl)
            dydtmp = unit_d(np.cross(x_loc, x_gl))
            dydP = dydtmp.dot(dtmpdx).dot(dxdP)

            z_loc = unit(np.cross(x_loc, y_loc))
            dtmpdx, dtmpdy = cross_d(x_loc,y_loc)
            dzdtmp = unit_d(np.cross(x_loc, y_loc))
            dzdP = dzdtmp.dot(dtmpdx).dot(dxdP) + dzdtmp.dot(dtmpdy).dot(dydP)

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x = x_loc.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x = x_loc.dot(disp[ielem+1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem+1, 3:])

            # #$$$$$$$$$$$$$$$$$$$$$$$$$$

            # The derivatives of the above code wrt displacement all boil down to sections of the T matrix
            dxddisp = T[0,:]
            dyddisp = T[1,:]
            dzddisp = T[2,:]

            #The derivatives of the above code wrt T all boil down to sections of the #displacement vector
            du0dloc = disp[ielem, :3]
            dr0dloc = disp[ielem, 3:]
            du1dloc = disp[ielem+1, :3]
            dr1dloc = disp[ielem+1, 3:]

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2) + 1e-50 #added eps to avoid 0 disp singularity
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L
            # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

            dtmpdr0y = 1/tmp * (r1y - r0y)*-1
            dtmpdr1y = 1/tmp * (r1y - r0y)
            dtmpdr0z = 1/tmp * (r1z - r0z)*-1
            dtmpdr1z = 1/tmp * (r1z - r0z)

            # Combine all of the derivtives for tmp
            dtmpdDisp = np.zeros(12)
            dr0xdDisp = np.zeros(12)
            dr1xdDisp = np.zeros(12)

            #r0 term
            dr0xdDisp[3:6] = dxddisp
            dr1xdDisp[9:12] = dxddisp

            dtmpdDisp[3:6] = dtmpdr0y*dyddisp
            dtmpdDisp[3:6] += dtmpdr0z*dzddisp
            dtmpdDisp[9:12] = dtmpdr1y*dyddisp
            dtmpdDisp[9:12] += dtmpdr1z*dzddisp

            # x_loc, y_loc and z_loc terms
            # (dttmpx_loc is zeros, so don't compute with it)
            dtmpdy_loc = dtmpdr0y*dr0dloc + dtmpdr1y*dr1dloc
            dtmpdz_loc = dtmpdr0z*dr0dloc + dtmpdr1z*dr1dloc

            dtmpdP = dtmpdy_loc.dot(dydP) + dtmpdz_loc.dot(dzdP)

            dsxx0dtmp = E * radius[ielem] / L
            dsxx0du0x = -E / L
            dsxx0du1x = E / L
            dsxx0dL =  -E * (u1x - u0x) / (L*L) - E * radius[ielem] / (L*L) * tmp

            dsxx1dtmp = E * radius[ielem] / L
            dsxx1du0x = E / L
            dsxx1du1x = -E / L
            dsxx1dL = -E * (u0x - u1x) / (L*L) - E * radius[ielem] / (L*L) * tmp

            dsxx0dP = dsxx0dtmp * dtmpdP + \
                      dsxx0du0x*du0dloc.dot(dxdP) + dsxx0du1x*du1dloc.dot(dxdP)+\
                      dsxx0dL*dLddP

            dsxx1dP = dsxx1dtmp * dtmpdP + \
                      dsxx1du0x*du0dloc.dot(dxdP)+dsxx1du1x*du1dloc.dot(dxdP)+\
                      dsxx1dL*dLddP

            # Combine sxx0 and sxx1 terms

            # Start with the tmp term
            dsxx0dDisp = dsxx0dtmp * dtmpdDisp
            dsxx1dDisp = dsxx1dtmp * dtmpdDisp

            # Now add the direct u dep
            dsxx0dDisp[0:3] = dsxx0du0x * dxddisp
            dsxx0dDisp[6:9] = dsxx0du1x * dxddisp

            dsxx1dDisp[0:3] = dsxx1du0x * dxddisp
            dsxx1dDisp[6:9] = dsxx1du1x * dxddisp

            # Combine sxt term
            dsxtdr0x = -G * radius[ielem] / L
            dsxtdr1x = G * radius[ielem] / L
            dsxtdL =  - G * radius[ielem] * (r1x - r0x) / (L*L)

            dsxtdP = dsxtdr0x*(dr0dloc.dot(dxdP)) + dsxtdr1x*(dr1dloc.dot(dxdP)) + \
                     dsxtdL*dLddP
            #disp
            dsxtdDisp = dsxtdr0x * dr0xdDisp + dsxtdr1x * dr1xdDisp

            #radius derivatives
            dsxxdrad = E / L * tmp
            dsxtdrad = G * (r1x - r0x)/L

            fact = 1.0 / (np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm0dsxx0 = sxx0 * fact
            dVm0dsxt = 3 * sxt * fact

            fact = 1.0 / (np.sqrt(sxx1**2 + 3 * sxt**2))
            dVm1dsxx1 = sxx1 * fact
            dVm1dsxt = 3 * sxt * fact

            ii = 2 * ielem
            partials['vonmises', 'radius'][ii] = dVm0dsxx0*dsxxdrad + dVm0dsxt*dsxtdrad
            partials['vonmises', 'radius'][ii+1] = dVm1dsxx1*dsxxdrad + dVm1dsxt*dsxtdrad

            ii = 24 * ielem
            partials['vonmises', 'disp'][ii:ii+12] = dVm0dsxx0*dsxx0dDisp + dVm0dsxt*dsxtdDisp
            partials['vonmises', 'disp'][ii+12:ii+24] = dVm1dsxx1*dsxx1dDisp + dVm1dsxt*dsxtdDisp

            # Compute terms for the nodes
            ii = 12 * ielem

            dVm0_dnode = dVm0dsxx0*dsxx0dP + dVm0dsxt*dsxtdP
            partials['vonmises', 'nodes'][ii:ii+3] = -dVm0_dnode
            partials['vonmises', 'nodes'][ii+3:ii+6] = dVm0_dnode

            dVM1_dnode = dVm1dsxx1*dsxx1dP + dVm1dsxt*dsxtdP
            partials['vonmises', 'nodes'][ii+6:ii+9] = -dVM1_dnode
            partials['vonmises', 'nodes'][ii+9:ii+12] = dVM1_dnode
Beispiel #6
0
    def compute_partials(self, inputs, partials):

        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            # Compute the coordinate delta between the two element end points
            P0 = nodes[ielem, :]
            P1 = nodes[ielem + 1, :]
            dP = P1 - P0

            # and its derivatives
            ddPdP0 = -1.0 * np.eye(3)
            ddPdP1 = 1.0 * np.eye(3)

            # Compute the element length and its derivative
            L = norm(dP)
            dLddP = norm_d(dP)

            # unit function converts a vector to a unit vector
            # calculate the transormation to the local element frame.
            # We use x_gl to provide a reference axis to reference
            x_loc = unit(dP)
            dxdP = unit_d(dP)

            y_loc = unit(np.cross(x_loc, x_gl))
            dtmpdx, dummy = cross_d(x_loc, x_gl)
            dydtmp = unit_d(np.cross(x_loc, x_gl))
            dydP = dydtmp.dot(dtmpdx).dot(dxdP)

            z_loc = unit(np.cross(x_loc, y_loc))
            dtmpdx, dtmpdy = cross_d(x_loc, y_loc)
            dzdtmp = unit_d(np.cross(x_loc, y_loc))
            dzdP = dzdtmp.dot(dtmpdx).dot(dxdP) + dzdtmp.dot(dtmpdy).dot(dydP)

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem + 1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem + 1, 3:])

            # #$$$$$$$$$$$$$$$$$$$$$$$$$$

            # The derivatives of the above code wrt displacement all boil down to sections of the T matrix
            dxddisp = T[0, :]
            dyddisp = T[1, :]
            dzddisp = T[2, :]

            #The derivatives of the above code wrt T all boil down to sections of the #displacement vector
            # du0dT = disp[ielem, :3]
            # dr0dT = disp[ielem, 3:]
            # du1dT = disp[ielem+1, :3]
            # dr1dT = disp[ielem+1, 3:]

            du0dloc = disp[ielem, :3]
            dr0dloc = disp[ielem, 3:]
            du1dloc = disp[ielem + 1, :3]
            dr1dloc = disp[ielem + 1, 3:]

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2)
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L
            # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

            dtmpdr0y = 1 / tmp * (r1y - r0y) * -1
            dtmpdr1y = 1 / tmp * (r1y - r0y)
            dtmpdr0z = 1 / tmp * (r1z - r0z) * -1
            dtmpdr1z = 1 / tmp * (r1z - r0z)

            # Combine all of the derivtives for tmp
            dtmpdDisp = np.zeros(2 * 6)
            dr0xdDisp = np.zeros(2 * 6)
            dr0ydDisp = np.zeros(2 * 6)
            dr0zdDisp = np.zeros(2 * 6)
            dr1xdDisp = np.zeros(2 * 6)
            dr1ydDisp = np.zeros(2 * 6)
            dr1zdDisp = np.zeros(2 * 6)

            idx1 = 3
            idx2 = 6 + 3
            #r0 term
            dr0xdDisp[idx1:idx1 + 3] = dxddisp
            dr0ydDisp[idx1:idx1 + 3] = dyddisp
            dr0zdDisp[idx1:idx1 + 3] = dzddisp
            dr1xdDisp[idx2:idx2 + 3] = dxddisp
            dr1ydDisp[idx2:idx2 + 3] = dyddisp
            dr1zdDisp[idx2:idx2 + 3] = dzddisp
            dtmpdDisp = (dtmpdr0y*dr0ydDisp+dtmpdr1y*dr1ydDisp+\
                        dtmpdr0z*dr0zdDisp+dtmpdr1z*dr1zdDisp)

            # x_loc, y_loc and z_loc terms
            dtmpdx_loc = np.array([0, 0, 0])
            dtmpdy_loc = dtmpdr0y * dr0dloc + dtmpdr1y * dr1dloc
            dtmpdz_loc = dtmpdr0z * dr0dloc + dtmpdr1z * dr1dloc

            dtmpdP = dtmpdx_loc.dot(dxdP) + dtmpdy_loc.dot(
                dydP) + dtmpdz_loc.dot(dzdP)

            dsxx0dtmp = E * radius[ielem] / L
            dsxx0du0x = -E / L
            dsxx0du1x = E / L
            dsxx0dL = -E * (u1x -
                            u0x) / (L * L) - E * radius[ielem] / (L * L) * tmp

            dsxx1dtmp = E * radius[ielem] / L
            dsxx1du0x = E / L
            dsxx1du1x = -E / L
            dsxx1dL = -E * (u0x -
                            u1x) / (L * L) - E * radius[ielem] / (L * L) * tmp

            dsxx0dP = dsxx0dtmp * dtmpdP + \
                      dsxx0du0x*du0dloc.dot(dxdP) + dsxx0du1x*du1dloc.dot(dxdP)+\
                      dsxx0dL*dLddP

            dsxx1dP = dsxx1dtmp * dtmpdP + \
                      dsxx1du0x*du0dloc.dot(dxdP)+dsxx1du1x*du1dloc.dot(dxdP)+\
                      dsxx1dL*dLddP

            # Combine sxx0 and sxx1 terms
            idx1 = 0
            idx2 = 6
            # Start with the tmp term
            dsxx0dDisp = dsxx0dtmp * dtmpdDisp
            dsxx1dDisp = dsxx1dtmp * dtmpdDisp

            # Now add the direct u dep
            dsxx0dDisp[idx1:idx1 + 3] = dsxx0du0x * dxddisp
            dsxx0dDisp[idx2:idx2 + 3] = dsxx0du1x * dxddisp

            dsxx1dDisp[idx1:idx1 + 3] = dsxx1du0x * dxddisp
            dsxx1dDisp[idx2:idx2 + 3] = dsxx1du1x * dxddisp

            # Combine sxt term
            dsxtdDisp = np.zeros(2 * 6)
            idx1 = 3
            idx2 = 6 + 3

            dsxtdr0x = -G * radius[ielem] / L
            dsxtdr1x = G * radius[ielem] / L
            dsxtdL = -G * radius[ielem] * (r1x - r0x) / (L * L)

            dsxtdP = dsxtdr0x*(dr0dloc.dot(dxdP))+ dsxtdr1x*(dr1dloc.dot(dxdP))+\
                     dsxtdL*dLddP
            #disp
            dsxtdDisp = dsxtdr0x * dr0xdDisp + dsxtdr1x * dr1xdDisp

            #radius derivatives
            dsxx0drad = E / L * tmp
            dsxx1drad = E / L * tmp
            dsxtdrad = G * (r1x - r0x) / L

            dVm0dsxx0 = (sxx0) / (np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm0dsxt = (3 * sxt) / (np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm1dsxx1 = (sxx1) / (np.sqrt(sxx1**2 + 3 * sxt**2))
            dVm1dsxt = (3 * sxt) / (np.sqrt(sxx1**2 + 3 * sxt**2))

            idx = ielem * 2
            partials['vonmises', 'radius'][
                idx, ielem] = dVm0dsxx0 * dsxx0drad + dVm0dsxt * dsxtdrad
            partials['vonmises', 'radius'][
                idx + 1, ielem] = dVm1dsxx1 * dsxx1drad + dVm1dsxt * dsxtdrad

            idx2 = ielem * 6
            partials['vonmises','disp'][idx,idx2:idx2+12] = partials['vonmises','disp'][idx,idx2:idx2+12]+\
                                                            (dVm0dsxx0*dsxx0dDisp+dVm0dsxt*dsxtdDisp )
            partials['vonmises','disp'][idx+1,idx2:idx2+12] = partials['vonmises','disp'][idx+1,idx2:idx2+12]+\
                                                              (dVm1dsxx1*dsxx1dDisp+dVm1dsxt*dsxtdDisp )

            # Compute terms for the nodes
            idx3 = ielem * 3

            partials['vonmises', 'nodes'][idx, idx3:idx3 + 3] = partials[
                'vonmises',
                'nodes'][idx, idx3:idx3 + 3] + dVm0dsxx0 * dsxx0dP.dot(
                    ddPdP0) + dVm0dsxt * dsxtdP.dot(ddPdP0)
            partials['vonmises', 'nodes'][idx, idx3 + 3:idx3 + 6] = partials[
                'vonmises',
                'nodes'][idx, idx3 + 3:idx3 + 6] + dVm0dsxx0 * dsxx0dP.dot(
                    ddPdP1) + dVm0dsxt * dsxtdP.dot(ddPdP1)

            partials['vonmises', 'nodes'][idx + 1, idx3:idx3 + 3] = partials[
                'vonmises',
                'nodes'][idx + 1, idx3:idx3 + 3] + dVm1dsxx1 * dsxx1dP.dot(
                    ddPdP0) + dVm1dsxt * dsxtdP.dot(ddPdP0)
            partials['vonmises',
                     'nodes'][idx + 1, idx3 + 3:idx3 +
                              6] = partials['vonmises', 'nodes'][
                                  idx + 1,
                                  idx3 + 3:idx3 + 6] + dVm1dsxx1 * dsxx1dP.dot(
                                      ddPdP1) + dVm1dsxt * dsxtdP.dot(ddPdP1)
    def compute_partials(self, inputs, partials):

        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            # Compute the coordinate delta between the two element end points
            P0 = nodes[ielem, :]
            P1 = nodes[ielem + 1, :]
            dP = P1 - P0

            # Compute the derivative of element length
            L = norm(dP)
            dLddP = norm_d(dP)

            # unit function converts a vector to a unit vector
            # calculate the transormation to the local element frame.
            # We use x_gl to provide a reference axis to reference
            x_loc = unit(dP)
            dxdP = unit_d(dP)

            y_loc = unit(np.cross(x_loc, x_gl))
            dtmpdx, _ = cross_d(x_loc, x_gl)
            dydtmp = unit_d(np.cross(x_loc, x_gl))
            dydP = dydtmp.dot(dtmpdx).dot(dxdP)

            z_loc = unit(np.cross(x_loc, y_loc))
            dtmpdx, dtmpdy = cross_d(x_loc, y_loc)
            dzdtmp = unit_d(np.cross(x_loc, y_loc))
            dzdP = dzdtmp.dot(dtmpdx).dot(dxdP) + dzdtmp.dot(dtmpdy).dot(dydP)

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x = x_loc.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x = x_loc.dot(disp[ielem + 1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem + 1, 3:])

            # #$$$$$$$$$$$$$$$$$$$$$$$$$$

            # The derivatives of the above code wrt displacement all boil down to sections of the T matrix
            dxddisp = T[0, :]
            dyddisp = T[1, :]
            dzddisp = T[2, :]

            #The derivatives of the above code wrt T all boil down to sections of the #displacement vector
            du0dloc = disp[ielem, :3]
            dr0dloc = disp[ielem, 3:]
            du1dloc = disp[ielem + 1, :3]
            dr1dloc = disp[ielem + 1, 3:]

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            tmp = np.sqrt(
                (r1y - r0y)**2 +
                (r1z - r0z)**2) + 1e-50  #added eps to avoid 0 disp singularity
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L
            # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

            dtmpdr0y = 1 / tmp * (r1y - r0y) * -1
            dtmpdr1y = 1 / tmp * (r1y - r0y)
            dtmpdr0z = 1 / tmp * (r1z - r0z) * -1
            dtmpdr1z = 1 / tmp * (r1z - r0z)

            # Combine all of the derivtives for tmp
            dtmpdDisp = np.zeros(12)
            dr0xdDisp = np.zeros(12)
            dr1xdDisp = np.zeros(12)

            #r0 term
            dr0xdDisp[3:6] = dxddisp
            dr1xdDisp[9:12] = dxddisp

            dtmpdDisp[3:6] = dtmpdr0y * dyddisp
            dtmpdDisp[3:6] += dtmpdr0z * dzddisp
            dtmpdDisp[9:12] = dtmpdr1y * dyddisp
            dtmpdDisp[9:12] += dtmpdr1z * dzddisp

            # x_loc, y_loc and z_loc terms
            # (dttmpx_loc is zeros, so don't compute with it)
            dtmpdy_loc = dtmpdr0y * dr0dloc + dtmpdr1y * dr1dloc
            dtmpdz_loc = dtmpdr0z * dr0dloc + dtmpdr1z * dr1dloc

            dtmpdP = dtmpdy_loc.dot(dydP) + dtmpdz_loc.dot(dzdP)

            dsxx0dtmp = E * radius[ielem] / L
            dsxx0du0x = -E / L
            dsxx0du1x = E / L
            dsxx0dL = -E * (u1x -
                            u0x) / (L * L) - E * radius[ielem] / (L * L) * tmp

            dsxx1dtmp = E * radius[ielem] / L
            dsxx1du0x = E / L
            dsxx1du1x = -E / L
            dsxx1dL = -E * (u0x -
                            u1x) / (L * L) - E * radius[ielem] / (L * L) * tmp

            dsxx0dP = dsxx0dtmp * dtmpdP + \
                      dsxx0du0x*du0dloc.dot(dxdP) + dsxx0du1x*du1dloc.dot(dxdP)+\
                      dsxx0dL*dLddP

            dsxx1dP = dsxx1dtmp * dtmpdP + \
                      dsxx1du0x*du0dloc.dot(dxdP)+dsxx1du1x*du1dloc.dot(dxdP)+\
                      dsxx1dL*dLddP

            # Combine sxx0 and sxx1 terms

            # Start with the tmp term
            dsxx0dDisp = dsxx0dtmp * dtmpdDisp
            dsxx1dDisp = dsxx1dtmp * dtmpdDisp

            # Now add the direct u dep
            dsxx0dDisp[0:3] = dsxx0du0x * dxddisp
            dsxx0dDisp[6:9] = dsxx0du1x * dxddisp

            dsxx1dDisp[0:3] = dsxx1du0x * dxddisp
            dsxx1dDisp[6:9] = dsxx1du1x * dxddisp

            # Combine sxt term
            dsxtdr0x = -G * radius[ielem] / L
            dsxtdr1x = G * radius[ielem] / L
            dsxtdL = -G * radius[ielem] * (r1x - r0x) / (L * L)

            dsxtdP = dsxtdr0x*(dr0dloc.dot(dxdP)) + dsxtdr1x*(dr1dloc.dot(dxdP)) + \
                     dsxtdL*dLddP
            #disp
            dsxtdDisp = dsxtdr0x * dr0xdDisp + dsxtdr1x * dr1xdDisp

            #radius derivatives
            dsxxdrad = E / L * tmp
            dsxtdrad = G * (r1x - r0x) / L

            fact = 1.0 / (np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm0dsxx0 = sxx0 * fact
            dVm0dsxt = 3 * sxt * fact

            fact = 1.0 / (np.sqrt(sxx1**2 + 3 * sxt**2))
            dVm1dsxx1 = sxx1 * fact
            dVm1dsxt = 3 * sxt * fact

            ii = 2 * ielem
            partials['vonmises',
                     'radius'][ii] = dVm0dsxx0 * dsxxdrad + dVm0dsxt * dsxtdrad
            partials['vonmises',
                     'radius'][ii +
                               1] = dVm1dsxx1 * dsxxdrad + dVm1dsxt * dsxtdrad

            ii = 24 * ielem
            partials[
                'vonmises',
                'disp'][ii:ii +
                        12] = dVm0dsxx0 * dsxx0dDisp + dVm0dsxt * dsxtdDisp
            partials[
                'vonmises',
                'disp'][ii + 12:ii +
                        24] = dVm1dsxx1 * dsxx1dDisp + dVm1dsxt * dsxtdDisp

            # Compute terms for the nodes
            ii = 12 * ielem

            dVm0_dnode = dVm0dsxx0 * dsxx0dP + dVm0dsxt * dsxtdP
            partials['vonmises', 'nodes'][ii:ii + 3] = -dVm0_dnode
            partials['vonmises', 'nodes'][ii + 3:ii + 6] = dVm0_dnode

            dVM1_dnode = dVm1dsxx1 * dsxx1dP + dVm1dsxt * dsxtdP
            partials['vonmises', 'nodes'][ii + 6:ii + 9] = -dVM1_dnode
            partials['vonmises', 'nodes'][ii + 9:ii + 12] = dVM1_dnode
    def compute(self, inputs, outputs):
        disp = inputs['disp']
        nodes = inputs['nodes']
        A_enc = inputs['A_enc']
        Qy = inputs['Qz']
        Iz = inputs['Iz']
        J = inputs['J']
        htop = inputs['htop']
        hbottom = inputs['hbottom']
        hfront = inputs['hfront']
        hrear = inputs['hrear']
        spar_thickness = inputs['spar_thickness']
        skin_thickness = inputs['skin_thickness']
        vonmises = outputs['vonmises']

        # Only use complex type for these arrays if we're using cs to check derivs
        dtype = type(disp[0, 0])
        T = np.zeros((3, 3), dtype=dtype)
        x_gl = np.array([1, 0, 0], dtype=dtype)

        E = self.E
        G = self.G

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            P0 = nodes[ielem, :]
            P1 = nodes[ielem+1, :]
            L = norm(P1 - P0)

            x_loc = unit(P1 - P0)
            y_loc = unit(np.cross(x_loc, x_gl))
            z_loc = unit(np.cross(x_loc, y_loc))

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem+1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem+1, 3:])

            axial_stress = E * (u1x - u0x) / L      # this is stress = modulus * strain; positive is tensile
            torsion_stress = G * J[ielem] / L * (r1x - r0x) / 2 / spar_thickness[ielem] / A_enc[ielem]   # this is Torque / (2 * thickness_min * Area_enclosed)
            top_bending_stress = E / (L**2) * (6 * u0y + 2 * r0z * L - 6 * u1y + 4 * r1z * L ) * htop[ielem] # this is moment * htop / I
            bottom_bending_stress = - E / (L**2) * (6 * u0y + 2 * r0z * L - 6 * u1y + 4 * r1z * L ) * hbottom[ielem] # this is moment * htop / I
            front_bending_stress = - E / (L**2) * (-6 * u0z + 2 * r0y * L + 6 * u1z + 4 * r1y * L ) * hfront[ielem] # this is moment * htop / I
            rear_bending_stress = E / (L**2) * (-6 * u0z + 2 * r0y * L + 6 * u1z + 4 * r1y * L ) * hrear[ielem] # this is moment * htop / I

            vertical_shear =  E / (L**3) *(-12 * u0y - 6 * r0z * L + 12 * u1y - 6 * r1z * L ) * Qy[ielem] / (2 * spar_thickness[ielem]) # shear due to bending (VQ/It) note: the I used to get V cancels the other I

            # print("==========",ielem,"================")
            # print("vertical_shear", vertical_shear)
            # print("top",top_bending_stress)
            # print("bottom",bottom_bending_stress)
            # print("front",front_bending_stress)
            # print("rear",rear_bending_stress)
            # print("axial", axial_stress)
            # print("torsion", torsion_stress)

            vonmises[ielem, 0] = np.sqrt((top_bending_stress + rear_bending_stress + axial_stress)**2 + 3*torsion_stress**2) / self.tssf
            vonmises[ielem, 1] = np.sqrt((bottom_bending_stress + front_bending_stress + axial_stress)**2 + 3*torsion_stress**2)
            vonmises[ielem, 2] = np.sqrt((front_bending_stress + axial_stress)**2 + 3*(torsion_stress-vertical_shear)**2)
            vonmises[ielem, 3] = np.sqrt((rear_bending_stress + axial_stress)**2 + 3*(torsion_stress+vertical_shear)**2) / self.tssf
    def compute_partials(self, inputs, partials):

        radius = inputs['radius']
        disp = inputs['disp']
        nodes = inputs['nodes']
        T = self.T
        E = self.E
        G = self.G
        x_gl = self.x_gl

        num_elems = self.ny - 1
        for ielem in range(num_elems):

            # Compute the coordinate delta between the two element end points
            P0 = nodes[ielem, :]
            P1 = nodes[ielem+1, :]
            dP = P1 - P0

            # and its derivatives
            ddPdP0 = -1.0*np.eye(3)
            ddPdP1 = 1.0*np.eye(3)

            # Compute the element length and its derivative
            L = norm(dP)
            dLddP = norm_d(dP)

            # unit function converts a vector to a unit vector
            # calculate the transormation to the local element frame.
            # We use x_gl to provide a reference axis to reference
            x_loc = unit(dP)
            dxdP = unit_d(dP)

            y_loc = unit(np.cross(x_loc, x_gl))
            dtmpdx,dummy = cross_d(x_loc,x_gl)
            dydtmp = unit_d(np.cross(x_loc, x_gl))
            dydP = dydtmp.dot(dtmpdx).dot(dxdP)

            z_loc = unit(np.cross(x_loc, y_loc))
            dtmpdx,dtmpdy = cross_d(x_loc,y_loc)
            dzdtmp = unit_d(np.cross(x_loc, y_loc))
            dzdP = dzdtmp.dot(dtmpdx).dot(dxdP)+dzdtmp.dot(dtmpdy).dot(dydP)

            T[0, :] = x_loc
            T[1, :] = y_loc
            T[2, :] = z_loc

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            u0x, u0y, u0z = T.dot(disp[ielem, :3])
            r0x, r0y, r0z = T.dot(disp[ielem, 3:])
            u1x, u1y, u1z = T.dot(disp[ielem+1, :3])
            r1x, r1y, r1z = T.dot(disp[ielem+1, 3:])

            # #$$$$$$$$$$$$$$$$$$$$$$$$$$

            # The derivatives of the above code wrt displacement all boil down to sections of the T matrix
            dxddisp = T[0,:]
            dyddisp = T[1,:]
            dzddisp = T[2,:]

            #The derivatives of the above code wrt T all boil down to sections of the #displacement vector
            # du0dT = disp[ielem, :3]
            # dr0dT = disp[ielem, 3:]
            # du1dT = disp[ielem+1, :3]
            # dr1dT = disp[ielem+1, 3:]

            du0dloc = disp[ielem, :3]
            dr0dloc = disp[ielem, 3:]
            du1dloc = disp[ielem+1, :3]
            dr1dloc = disp[ielem+1, 3:]

            #$$$$$$$$$$$$$$$$$$$$$$$$$$
            # Original code
            # $$$$$$$$$$$$
            tmp = np.sqrt((r1y - r0y)**2 + (r1z - r0z)**2) + 1e-50 #added eps to avoid 0 disp singularity
            sxx0 = E * (u1x - u0x) / L + E * radius[ielem] / L * tmp
            sxx1 = E * (u0x - u1x) / L + E * radius[ielem] / L * tmp
            sxt = G * radius[ielem] * (r1x - r0x) / L
            # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

            dtmpdr0y = 1/tmp * (r1y - r0y)*-1
            dtmpdr1y = 1/tmp * (r1y - r0y)
            dtmpdr0z = 1/tmp * (r1z - r0z)*-1
            dtmpdr1z = 1/tmp * (r1z - r0z)

            # Combine all of the derivtives for tmp
            dtmpdDisp = np.zeros(2 * 6)
            dr0xdDisp = np.zeros(2*6)
            dr0ydDisp = np.zeros(2*6)
            dr0zdDisp = np.zeros(2*6)
            dr1xdDisp = np.zeros(2*6)
            dr1ydDisp = np.zeros(2*6)
            dr1zdDisp = np.zeros(2*6)

            idx1 = 3
            idx2 = 6 + 3
            #r0 term
            dr0xdDisp[idx1:idx1+3] = dxddisp
            dr0ydDisp[idx1:idx1+3] = dyddisp
            dr0zdDisp[idx1:idx1+3] = dzddisp
            dr1xdDisp[idx2:idx2+3] = dxddisp
            dr1ydDisp[idx2:idx2+3] = dyddisp
            dr1zdDisp[idx2:idx2+3] = dzddisp
            dtmpdDisp = (dtmpdr0y*dr0ydDisp+dtmpdr1y*dr1ydDisp+\
                        dtmpdr0z*dr0zdDisp+dtmpdr1z*dr1zdDisp)

            # x_loc, y_loc and z_loc terms
            dtmpdx_loc = np.array([0,0,0])
            dtmpdy_loc = dtmpdr0y*dr0dloc + dtmpdr1y*dr1dloc
            dtmpdz_loc = dtmpdr0z*dr0dloc + dtmpdr1z*dr1dloc

            dtmpdP = dtmpdx_loc.dot(dxdP) + dtmpdy_loc.dot(dydP) + dtmpdz_loc.dot(dzdP)

            dsxx0dtmp = E * radius[ielem] / L
            dsxx0du0x = -E / L
            dsxx0du1x = E / L
            dsxx0dL =  -E * (u1x - u0x) / (L*L) - E * radius[ielem] / (L*L) * tmp

            dsxx1dtmp = E * radius[ielem] / L
            dsxx1du0x = E / L
            dsxx1du1x = -E / L
            dsxx1dL = -E * (u0x - u1x) / (L*L) - E * radius[ielem] / (L*L) * tmp

            dsxx0dP = dsxx0dtmp * dtmpdP + \
                      dsxx0du0x*du0dloc.dot(dxdP) + dsxx0du1x*du1dloc.dot(dxdP)+\
                      dsxx0dL*dLddP

            dsxx1dP = dsxx1dtmp * dtmpdP + \
                      dsxx1du0x*du0dloc.dot(dxdP)+dsxx1du1x*du1dloc.dot(dxdP)+\
                      dsxx1dL*dLddP

            # Combine sxx0 and sxx1 terms
            idx1 = 0
            idx2 = 6
            # Start with the tmp term
            dsxx0dDisp = dsxx0dtmp * dtmpdDisp
            dsxx1dDisp = dsxx1dtmp * dtmpdDisp

            # Now add the direct u dep
            dsxx0dDisp[idx1:idx1+3] = dsxx0du0x * dxddisp
            dsxx0dDisp[idx2:idx2+3] = dsxx0du1x * dxddisp

            dsxx1dDisp[idx1:idx1+3] = dsxx1du0x * dxddisp
            dsxx1dDisp[idx2:idx2+3] = dsxx1du1x * dxddisp

            # Combine sxt term
            dsxtdDisp = np.zeros(2 * 6)
            idx1 = 3
            idx2 = 6 + 3

            dsxtdr0x = -G * radius[ielem] / L
            dsxtdr1x = G * radius[ielem] / L
            dsxtdL =  - G * radius[ielem] * (r1x - r0x) / (L*L)

            dsxtdP = dsxtdr0x*(dr0dloc.dot(dxdP))+ dsxtdr1x*(dr1dloc.dot(dxdP))+\
                     dsxtdL*dLddP
            #disp
            dsxtdDisp= dsxtdr0x * dr0xdDisp + dsxtdr1x * dr1xdDisp

            #radius derivatives
            dsxx0drad = E / L * tmp
            dsxx1drad = E / L * tmp
            dsxtdrad = G * (r1x - r0x)/L

            dVm0dsxx0 = (sxx0)/(np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm0dsxt = (3*sxt)/(np.sqrt(sxx0**2 + 3 * sxt**2))
            dVm1dsxx1 = (sxx1)/(np.sqrt(sxx1**2 + 3 * sxt**2))
            dVm1dsxt = (3*sxt)/(np.sqrt(sxx1**2 + 3 * sxt**2))

            idx = ielem*2
            partials['vonmises','radius'][idx,ielem] = dVm0dsxx0*dsxx0drad+dVm0dsxt*dsxtdrad
            partials['vonmises','radius'][idx+1,ielem] = dVm1dsxx1*dsxx1drad+dVm1dsxt*dsxtdrad

            idx2 = ielem*6
            partials['vonmises','disp'][idx,idx2:idx2+12] = (dVm0dsxx0*dsxx0dDisp+dVm0dsxt*dsxtdDisp )
            partials['vonmises','disp'][idx+1,idx2:idx2+12] = (dVm1dsxx1*dsxx1dDisp+dVm1dsxt*dsxtdDisp )

            # Compute terms for the nodes
            idx3 = ielem*3

            partials['vonmises','nodes'][idx,idx3:idx3+3] = dVm0dsxx0*dsxx0dP.dot(ddPdP0)+dVm0dsxt*dsxtdP.dot(ddPdP0)
            partials['vonmises','nodes'][idx,idx3+3:idx3+6] = dVm0dsxx0*dsxx0dP.dot(ddPdP1)+dVm0dsxt*dsxtdP.dot(ddPdP1)

            partials['vonmises','nodes'][idx+1,idx3:idx3+3] = dVm1dsxx1*dsxx1dP.dot(ddPdP0)+dVm1dsxt*dsxtdP.dot(ddPdP0)
            partials['vonmises','nodes'][idx+1,idx3+3:idx3+6] = dVm1dsxx1*dsxx1dP.dot(ddPdP1)+dVm1dsxt*dsxtdP.dot(ddPdP1)