예제 #1
0
    def compute(self, inputs, outputs):

        frame3dd_opt = self.options["frame3dd_opt"]

        # ------- node data ----------------
        z = inputs["z"]
        n = len(z)
        node = np.arange(1, n + 1)
        x = np.zeros(n)
        y = np.zeros(n)
        r = np.zeros(n)

        nodes = pyframe3dd.NodeData(node, x, y, z, r)
        # -----------------------------------

        # ------ reaction data ------------

        # rigid base
        node = inputs["kidx"] + np.ones(len(inputs["kidx"]))  # add one because 0-based index but 1-based node numbering
        rigid = RIGID

        reactions = pyframe3dd.ReactionData(
            node, inputs["kx"], inputs["ky"], inputs["kz"], inputs["ktx"], inputs["kty"], inputs["ktz"], rigid
        )
        # -----------------------------------

        # ------ frame element data ------------
        element = np.arange(1, n)
        N1 = np.arange(1, n)
        N2 = np.arange(2, n + 1)

        roll = np.zeros(n - 1)

        # average across element b.c. frame3dd uses constant section elements
        # TODO: Use nodal2sectional
        Az = inputs["Az"]
        Asx = inputs["Asx"]
        Asy = inputs["Asy"]
        Jz = inputs["Jz"]
        Ixx = inputs["Ixx"]
        Iyy = inputs["Iyy"]
        E = inputs["E"]
        G = inputs["G"]
        rho = inputs["rho"]

        elements = pyframe3dd.ElementData(element, N1, N2, Az, Asx, Asy, Jz, Ixx, Iyy, E, G, roll, rho)
        # -----------------------------------

        # ------ options ------------
        dx = -1.0
        options = pyframe3dd.Options(frame3dd_opt["shear"], frame3dd_opt["geom"], dx)
        # -----------------------------------

        # initialize frame3dd object
        cylinder = pyframe3dd.Frame(nodes, reactions, elements, options)

        # ------ add extra mass ------------

        # extra node inertia data
        N = inputs["midx"] + np.ones(len(inputs["midx"]))

        add_gravity = True
        cylinder.changeExtraNodeMass(
            N,
            inputs["m"],
            inputs["mIxx"],
            inputs["mIyy"],
            inputs["mIzz"],
            inputs["mIxy"],
            inputs["mIxz"],
            inputs["mIyz"],
            inputs["mrhox"],
            inputs["mrhoy"],
            inputs["mrhoz"],
            add_gravity,
        )

        # ------------------------------------

        # ------- enable dynamic analysis ----------
        Mmethod = 1
        lump = 0
        shift = 0.0
        # Run twice the number of modes to ensure that we can ignore the torsional modes and still get the desired number of fore-aft, side-side modes
        cylinder.enableDynamics(2 * NFREQ, Mmethod, lump, frame3dd_opt["tol"], shift)
        # ----------------------------

        # ------ static load case 1 ------------

        # gravity in the X, Y, Z, directions (global)
        gx = 0.0
        gy = 0.0
        gz = -gravity

        load = pyframe3dd.StaticLoadCase(gx, gy, gz)

        # point loads
        nF = inputs["plidx"] + np.ones(len(inputs["plidx"]))
        load.changePointLoads(nF, inputs["Fx"], inputs["Fy"], inputs["Fz"], inputs["Mxx"], inputs["Myy"], inputs["Mzz"])

        # distributed loads
        Px, Py, Pz = inputs["Pz"], inputs["Py"], -inputs["Px"]  # switch to local c.s.
        z = inputs["z"]

        # trapezoidally distributed loads
        EL = np.arange(1, n)
        xx1 = xy1 = xz1 = np.zeros(n - 1)
        xx2 = xy2 = xz2 = np.diff(z) - 1e-6  # subtract small number b.c. of precision
        wx1 = Px[:-1]
        wx2 = Px[1:]
        wy1 = Py[:-1]
        wy2 = Py[1:]
        wz1 = Pz[:-1]
        wz2 = Pz[1:]

        load.changeTrapezoidalLoads(EL, xx1, xx2, wx1, wx2, xy1, xy2, wy1, wy2, xz1, xz2, wz1, wz2)

        cylinder.addLoadCase(load)
        # Debugging
        # cylinder.write('temp.3dd')
        # -----------------------------------
        # run the analysis
        displacements, forces, reactions, internalForces, mass, modal = cylinder.run()
        iCase = 0

        # mass
        outputs["mass"] = mass.struct_mass

        # natural frequncies
        outputs["f1"] = modal.freq[0]
        outputs["f2"] = modal.freq[1]
        outputs["freqs"] = modal.freq[:NFREQ]

        # Get all mode shapes in batch
        NFREQ2 = int(NFREQ / 2)
        freq_x, freq_y, mshapes_x, mshapes_y = util.get_xy_mode_shapes(
            z, modal.freq, modal.xdsp, modal.ydsp, modal.zdsp, modal.xmpf, modal.ympf, modal.zmpf
        )
        outputs["x_mode_freqs"] = freq_x[:NFREQ2]
        outputs["y_mode_freqs"] = freq_y[:NFREQ2]
        outputs["x_mode_shapes"] = mshapes_x[:NFREQ2, :]
        outputs["y_mode_shapes"] = mshapes_y[:NFREQ2, :]

        # deflections due to loading (from cylinder top and wind/wave loads)
        outputs["top_deflection"] = displacements.dx[iCase, n - 1]  # in yaw-aligned direction

        # shear and bending, one per element (convert from local to global c.s.)
        Fz = forces.Nx[iCase, 1::2]
        Vy = forces.Vy[iCase, 1::2]
        Vx = -forces.Vz[iCase, 1::2]

        Mzz = forces.Txx[iCase, 1::2]
        Myy = forces.Myy[iCase, 1::2]
        Mxx = -forces.Mzz[iCase, 1::2]

        # Record total forces and moments
        outputs["base_F"] = -1.0 * np.array([reactions.Fx.sum(), reactions.Fy.sum(), reactions.Fz.sum()])
        outputs["base_M"] = -1.0 * np.array([reactions.Mxx.sum(), reactions.Myy.sum(), reactions.Mzz.sum()])

        outputs["Fz_out"] = Fz
        outputs["Vx_out"] = Vx
        outputs["Vy_out"] = Vy
        outputs["Mxx_out"] = Mxx
        outputs["Myy_out"] = Myy
        outputs["Mzz_out"] = Mzz

        # axial and shear stress
        d, _ = util.nodal2sectional(inputs["d"])
        qdyn, _ = util.nodal2sectional(inputs["qdyn"])

        ##R = self.d/2.0
        ##x_stress = R*np.cos(self.theta_stress)
        ##y_stress = R*np.sin(self.theta_stress)
        ##axial_stress = Fz/self.Az + Mxx/self.Ixx*y_stress - Myy/self.Iyy*x_stress
        #        V = Vy*x_stress/R - Vx*y_stress/R  # shear stress orthogonal to direction x,y
        #        shear_stress = 2. * V / self.Az  # coefficient of 2 for a hollow circular section, but should be conservative for other shapes
        outputs["axial_stress"] = (
            Fz / inputs["Az"] - np.sqrt(Mxx ** 2 + Myy ** 2) / inputs["Iyy"] * d / 2.0
        )  # More conservative, just use the tilted bending and add total max shear as well at the same point, if you do not like it go back to the previous lines

        outputs["shear_stress"] = (
            2.0 * np.sqrt(Vx ** 2 + Vy ** 2) / inputs["Az"]
        )  # coefficient of 2 for a hollow circular section, but should be conservative for other shapes

        # hoop_stress (Eurocode method)
        L_reinforced = self.options["buckling_length"] * np.ones(Fz.shape)
        outputs["hoop_stress_euro"] = hoopStressEurocode(inputs["z"], d, inputs["t"], L_reinforced, qdyn)

        # Simpler hoop stress used in API calculations
        outputs["hoop_stress"] = hoopStress(d, inputs["t"], qdyn)
예제 #2
0
    def compute(self, inputs, outputs):

        frame3dd_opt = self.options["frame3dd_opt"]

        # ------- node data ----------------
        z = inputs["z"]
        n = len(z)
        node = np.arange(1, n + 1)
        x = np.zeros(n)
        y = np.zeros(n)
        r = np.zeros(n)

        nodes = pyframe3dd.NodeData(node, x, y, z, r)
        # -----------------------------------

        # ------ reaction data ------------

        # rigid base
        node = inputs["kidx"] + np.ones(len(inputs["kidx"]))  # add one because 0-based index but 1-based node numbering
        rigid = RIGID

        reactions = pyframe3dd.ReactionData(
            node, inputs["kx"], inputs["ky"], inputs["kz"], inputs["ktx"], inputs["kty"], inputs["ktz"], rigid
        )
        # -----------------------------------

        # ------ frame element data ------------
        element = np.arange(1, n)
        N1 = np.arange(1, n)
        N2 = np.arange(2, n + 1)

        roll = np.zeros(n - 1)

        # Element properties
        Az = inputs["Az"]
        Asx = inputs["Asx"]
        Asy = inputs["Asy"]
        Jz = inputs["Jz"]
        Ixx = inputs["Ixx"]
        Iyy = inputs["Iyy"]
        E = inputs["E"]
        G = inputs["G"]
        rho = inputs["rho"]

        elements = pyframe3dd.ElementData(element, N1, N2, Az, Asx, Asy, Jz, Ixx, Iyy, E, G, roll, rho)
        # -----------------------------------

        # ------ options ------------
        dx = -1.0
        options = pyframe3dd.Options(frame3dd_opt["shear"], frame3dd_opt["geom"], dx)
        # -----------------------------------

        # initialize frame3dd object
        cylinder = pyframe3dd.Frame(nodes, reactions, elements, options)

        # ------ add extra mass ------------

        # extra node inertia data
        N = inputs["midx"] + np.ones(len(inputs["midx"]))

        add_gravity = True
        cylinder.changeExtraNodeMass(
            N,
            inputs["m"],
            inputs["mIxx"],
            inputs["mIyy"],
            inputs["mIzz"],
            inputs["mIxy"],
            inputs["mIxz"],
            inputs["mIyz"],
            inputs["mrhox"],
            inputs["mrhoy"],
            inputs["mrhoz"],
            add_gravity,
        )

        # ------------------------------------

        # ------- enable dynamic analysis ----------
        Mmethod = 1
        lump = 0
        shift = 0.0
        # Run twice the number of modes to ensure that we can ignore the torsional modes and still get the desired number of fore-aft, side-side modes
        cylinder.enableDynamics(2 * NFREQ, Mmethod, lump, frame3dd_opt["tol"], shift)
        # ----------------------------

        # ------ static load case 1 ------------

        # gravity in the X, Y, Z, directions (global)
        gx = 0.0
        gy = 0.0
        gz = -gravity

        load = pyframe3dd.StaticLoadCase(gx, gy, gz)

        # point loads
        nF = inputs["plidx"] + np.ones(len(inputs["plidx"]))
        load.changePointLoads(nF, inputs["Fx"], inputs["Fy"], inputs["Fz"], inputs["Mxx"], inputs["Myy"], inputs["Mzz"])

        # distributed loads
        Px, Py, Pz = inputs["Pz"], inputs["Py"], -inputs["Px"]  # switch to local c.s.
        z = inputs["z"]

        # trapezoidally distributed loads
        EL = np.arange(1, n)
        xx1 = xy1 = xz1 = np.zeros(n - 1)
        xx2 = xy2 = xz2 = np.diff(z) - 1e-6  # subtract small number b.c. of precision
        wx1 = Px[:-1]
        wx2 = Px[1:]
        wy1 = Py[:-1]
        wy2 = Py[1:]
        wz1 = Pz[:-1]
        wz2 = Pz[1:]

        load.changeTrapezoidalLoads(EL, xx1, xx2, wx1, wx2, xy1, xy2, wy1, wy2, xz1, xz2, wz1, wz2)

        cylinder.addLoadCase(load)
        # Debugging
        # cylinder.write('temp.3dd')
        # -----------------------------------
        # run the analysis
        displacements, forces, reactions, internalForces, mass, modal = cylinder.run()
        ic = 0

        # mass
        outputs["mass"] = mass.struct_mass

        # natural frequncies
        outputs["f1"] = modal.freq[0]
        outputs["f2"] = modal.freq[1]
        outputs["structural_frequencies"] = modal.freq[:NFREQ]

        # Get all mode shapes in batch
        NFREQ2 = int(NFREQ / 2)
        freq_x, freq_y, freq_z, mshapes_x, mshapes_y, mshapes_z = util.get_xyz_mode_shapes(
            z, modal.freq, modal.xdsp, modal.ydsp, modal.zdsp, modal.xmpf, modal.ympf, modal.zmpf
        )
        outputs["fore_aft_freqs"] = freq_x[:NFREQ2]
        outputs["side_side_freqs"] = freq_y[:NFREQ2]
        outputs["torsion_freqs"] = freq_z[:NFREQ2]
        outputs["fore_aft_modes"] = mshapes_x[:NFREQ2, :]
        outputs["side_side_modes"] = mshapes_y[:NFREQ2, :]
        outputs["torsion_modes"] = mshapes_z[:NFREQ2, :]

        # deflections due to loading (from cylinder top and wind/wave loads)
        outputs["tower_deflection"] = np.sqrt(
            displacements.dx[ic, :] ** 2 + displacements.dy[ic, :] ** 2
        )  # in yaw-aligned direction
        outputs["top_deflection"] = outputs["tower_deflection"][-1]

        # Record total forces and moments
        ibase = 2 * int(inputs["kidx"].max())
        outputs["base_F"] = -np.r_[-forces.Vz[ic, ibase], forces.Vy[ic, ibase], forces.Nx[ic, ibase]]
        outputs["base_M"] = -np.r_[-forces.Mzz[ic, ibase], forces.Myy[ic, ibase], forces.Txx[ic, ibase]]

        # Forces and moments along the structure
        outputs["tower_Fz"] = forces.Nx[ic, 1::2]
        outputs["tower_Vx"] = -forces.Vz[ic, 1::2]
        outputs["tower_Vy"] = forces.Vy[ic, 1::2]
        outputs["tower_Mxx"] = -forces.Mzz[ic, 1::2]
        outputs["tower_Myy"] = forces.Myy[ic, 1::2]
        outputs["tower_Mzz"] = forces.Txx[ic, 1::2]
예제 #3
0
파일: exB.py 프로젝트: ptrbortolotti/WEIS
dx = 20.0  # x-axis increment for internal forces
other = pyframe3dd.Options(shear, geom, dx)
# 3 -----------------------------------


# 4 ------ initialize frame3dd object
frame = pyframe3dd.Frame(nodes, reactions, elements, other)
# 4 -----------------------------------


# 5 ------ static load case 1 ------------
# gravity in the X, Y, Z, directions (global)
gx = 0.0
gy = 0.0
gz = -9806.33
load = pyframe3dd.StaticLoadCase(gx, gy, gz)

# point load
nF = np.array([1])
Fx = np.array([100.0])
Fy = np.array([-200.0])
Fz = np.array([-100.0])
Mxx = np.array([0.0])
Myy = np.array([0.0])
Mzz = np.array([0.0])
load.changePointLoads(nF, Fx, Fy, Fz, Mxx, Myy, Mzz)

frame.addLoadCase(load)
# 5 -----------------------------------

예제 #4
0
    def compute(self, inputs, outputs):

        # Unpack variables
        opt = self.options["options"]
        n_attach = opt["mooring"]["n_attach"]
        m_rna = float(inputs["rna_mass"])
        cg_rna = inputs["rna_cg"]
        I_rna = inputs["rna_I"]
        I_trans = inputs["transition_piece_I"]

        fairlead_joints = inputs["mooring_fairlead_joints"]
        mooringF = inputs["mooring_neutral_load"]

        # Create frame3dd instance: nodes, elements, reactions, and options
        for frame in ["tower", "system"]:
            nodes = inputs[frame + "_nodes"]
            nnode = np.where(nodes[:, 0] == NULL)[0][0]
            nodes = nodes[:nnode, :]
            rnode = np.zeros(nnode)  # inputs[frame + "_Rnode"][:nnode]
            Fnode = inputs[frame + "_Fnode"][:nnode, :]
            Mnode = np.zeros((nnode, 3))
            ihub = np.argmax(nodes[:, 2]) - 1
            itrans = util.closest_node(nodes, inputs["transition_node"])

            N1 = np.int_(inputs[frame + "_elem_n1"])
            nelem = np.where(N1 == NULL)[0][0]
            N1 = N1[:nelem]
            N2 = np.int_(inputs[frame + "_elem_n2"][:nelem])
            A = inputs[frame + "_elem_A"][:nelem]
            Asx = inputs[frame + "_elem_Asx"][:nelem]
            Asy = inputs[frame + "_elem_Asy"][:nelem]
            Ixx = inputs[frame + "_elem_Ixx"][:nelem]
            Iyy = inputs[frame + "_elem_Iyy"][:nelem]
            Izz = inputs[frame + "_elem_Izz"][:nelem]
            rho = inputs[frame + "_elem_rho"][:nelem]
            E = inputs[frame + "_elem_E"][:nelem]
            G = inputs[frame + "_elem_G"][:nelem]
            roll = np.zeros(nelem)

            inodes = np.arange(nnode) + 1
            node_obj = pyframe3dd.NodeData(inodes, nodes[:, 0], nodes[:, 1],
                                           nodes[:, 2], rnode)

            ielem = np.arange(nelem) + 1
            elem_obj = pyframe3dd.ElementData(ielem, N1 + 1, N2 + 1, A, Asx,
                                              Asy, Izz, Ixx, Iyy, E, G, roll,
                                              rho)

            # TODO: Hydro_K + Mooring_K for tower (system too?)
            rid = np.array([itrans])  # np.array([np.argmin(nodes[:, 2])])
            Rx = Ry = Rz = Rxx = Ryy = Rzz = np.array([RIGID])
            react_obj = pyframe3dd.ReactionData(rid + 1,
                                                Rx,
                                                Ry,
                                                Rz,
                                                Rxx,
                                                Ryy,
                                                Rzz,
                                                rigid=RIGID)

            frame3dd_opt = opt["WISDEM"]["FloatingSE"]["frame3dd"]
            opt_obj = pyframe3dd.Options(frame3dd_opt["shear"],
                                         frame3dd_opt["geom"], -1.0)

            myframe = pyframe3dd.Frame(node_obj, react_obj, elem_obj, opt_obj)

            # Added mass
            m_trans = float(inputs["transition_piece_mass"])
            if frame == "tower":
                # TODO: Added mass and stiffness
                m_trans += float(inputs["platform_mass"])
                cg_trans = inputs["transition_node"] - inputs[
                    "platform_center_of_mass"]
            else:
                cg_trans = np.zeros(3)
            add_gravity = True
            mID = np.array([itrans, ihub], dtype=np.int_).flatten()
            m_add = np.array([m_trans, m_rna]).flatten()
            I_add = np.c_[I_trans, I_rna]
            cg_add = np.c_[cg_trans, cg_rna]
            myframe.changeExtraNodeMass(
                mID + 1,
                m_add,
                I_add[0, :],
                I_add[1, :],
                I_add[2, :],
                I_add[3, :],
                I_add[4, :],
                I_add[5, :],
                cg_add[0, :],
                cg_add[1, :],
                cg_add[2, :],
                add_gravity,
            )

            # Dynamics
            if frame == "tower" and frame3dd_opt["modal"]:
                Mmethod = 1
                lump = 0
                shift = 0.0
                myframe.enableDynamics(2 * NFREQ, Mmethod, lump,
                                       frame3dd_opt["tol"], shift)

            # Initialize loading with gravity, mooring line forces, and buoyancy (already in nodal forces)
            gx = gy = 0.0
            gz = -gravity
            load_obj = pyframe3dd.StaticLoadCase(gx, gy, gz)

            if frame == "system":
                for k in range(n_attach):
                    ind = util.closest_node(nodes, fairlead_joints[k, :])
                    Fnode[ind, :] += mooringF[k, :]
            Fnode[ihub, :] += inputs["rna_F"]
            Mnode[ihub, :] += inputs["rna_M"]
            nF = np.where(np.abs(Fnode).sum(axis=1) > 0.0)[0]
            load_obj.changePointLoads(nF + 1, Fnode[nF, 0], Fnode[nF, 1],
                                      Fnode[nF, 2], Mnode[nF, 0], Mnode[nF, 1],
                                      Mnode[nF, 2])

            # Add the load case and run
            myframe.addLoadCase(load_obj)
            # myframe.write(frame + ".3dd")
            displacements, forces, reactions, internalForces, mass, modal = myframe.run(
            )

            # natural frequncies
            if frame == "tower" and frame3dd_opt["modal"]:
                outputs[frame + "_freqs"] = modal.freq[:NFREQ]

                # Get all mode shapes in batch
                NFREQ2 = int(NFREQ / 2)
                freq_x, freq_y, mshapes_x, mshapes_y = util.get_xy_mode_shapes(
                    nodes[:, 2], modal.freq, modal.xdsp, modal.ydsp,
                    modal.zdsp, modal.xmpf, modal.ympf, modal.zmpf)
                outputs[frame + "_fore_aft_freqs"] = freq_x[:NFREQ2]
                outputs[frame + "_side_side_freqs"] = freq_y[:NFREQ2]
                outputs[frame + "_fore_aft_modes"] = mshapes_x[:NFREQ2, :]
                outputs[frame + "_side_side_modes"] = mshapes_y[:NFREQ2, :]

            # Determine forces
            F_sum = -1.0 * np.array(
                [reactions.Fx.sum(),
                 reactions.Fy.sum(),
                 reactions.Fz.sum()])
            M_sum = -1.0 * np.array([
                reactions.Mxx.sum(),
                reactions.Myy.sum(),
                reactions.Mzz.sum()
            ])
            L = np.sqrt(np.sum((nodes[N2, :] - nodes[N1, :])**2, axis=1))
예제 #5
0
        def run_hcurve(FrIn, optFlag=True):
            Fr = FrIn.reshape((self.n_span-1, 2))
            
            # Will only worry about radial loads
            Fy = Mx = My = Mz = np.zeros(self.n_span-1)

            # Output containers
            RF_derailH = np.zeros(2) # Derailment reaction force
            r_check    = np.zeros((self.n_span, 2)) # Envelope constraint
            strainPS   = np.zeros((self.n_span, 2)) 
            strainSS   = np.zeros((self.n_span, 2))

            # Look over bend to PS/SS cases
            for k in range(2):
                if k == 0:
                    blade, r_outer, angs = blade1, r_envelopeH_outer1, arcsH[1:]
                else:
                    blade, r_outer, angs = blade2, r_envelopeH_outer2, np.pi-arcsH[1:]
                    
                # Load case: gravity + blade bending to conform to outer boundary
                load = pyframe3dd.StaticLoadCase(gx, gy, gz)

                # Put radial loads in x,z plane   
                Fx = -1e4*Fr[:,k]*np.cos(angs)
                Fz = -1e4*Fr[:,k]*np.sin(angs)
                load.changePointLoads(inode[1:], Fx, Fy, Fz, Mx, My, Mz)

                # Add load case to Frame3DD objects and run
                blade.clearLoadCases()
                blade.addLoadCase(load)

                # Run the case
                displacements, forces, forces_rxn, internalForces, mass, modal = blade.run()

                # Check solved blade shape against envelope
                r_check[:,k]  = np.sqrt( (blade.nx+displacements.dx[0,:])**2 + (blade.nz+displacements.dz[0,:])**2) - r_outer

                # Derailing reaction force on root node
                #  - Lateral force on wheels (multiply by 0.5 for 2 wheel sets)
                #  - Moment around axis perpendicular to ground
                RF_derailH[k] = 0.5*np.sqrt(forces_rxn.Fx**2 + forces_rxn.Fz**2) + np.abs(forces_rxn.Myy)/flatcar_tc_length

                # Element shear and bending, one per element, which are already in principle directions in Hansen's notation
                # Zero-ing out axial stress as there shouldn't be any for pure beam bending
                Fz = np.r_[-forces.Nx[ 0,0],  forces.Nx[ 0, 1::2]]
                M1 = np.r_[-forces.Myy[0,0],  forces.Myy[0, 1::2]]
                M2 = np.r_[ forces.Mzz[0,0], -forces.Mzz[0, 1::2]]
                if PBEAM: M1,M2 = rotate(M1,M2)
                
                # Compute strain at the two points: pressure/suction side extremes
                strainPS[:,k] = -(M1/EI11*ps2 - M2/EI22*ps1 + Fz/EA)  # negative sign because Hansen c3 is opposite of Precomp z
                strainSS[:,k] = -(M1/EI11*ss2 - M2/EI22*ss1 + Fz/EA)

            if optFlag:
                # First constraint is compliance with outer boundary
                cboundary = np.maximum(r_check, 0)

                # Second constraint is reaction forces for derailment:
                crxn = np.maximum(RF_derailH - (0.5 * mass_car_8axle * gravity)/max_LV, 0.0)

                # Third constraint is keeping the strains reasonable
                cstrainPS = np.maximum(np.abs(strainPS) - max_strains, 0.0)
                cstrainSS = np.maximum(np.abs(strainSS) - max_strains, 0.0)

                # Accumulate constraints
                cons = np.array([np.sum(cboundary) , np.sum(crxn) , np.sum(cstrainPS) , np.sum(cstrainSS)])
            
                return -cons
            else:
                return RF_derailH, strainPS, strainSS
예제 #6
0
    def compute(self, inputs, outputs):

        frame3dd_opt = self.options['frame3dd_opt']

        # ------- node data ----------------
        z = inputs['z']
        n = len(z)
        node = np.arange(1, n + 1)
        x = np.zeros(n)
        y = np.zeros(n)
        r = np.zeros(n)

        nodes = pyframe3dd.NodeData(node, x, y, z, r)
        # -----------------------------------

        # ------ reaction data ------------

        # rigid base
        node = inputs['kidx'] + np.ones(
            len(inputs['kidx']
                ))  # add one because 0-based index but 1-based node numbering
        rigid = RIGID

        reactions = pyframe3dd.ReactionData(node, inputs['kx'], inputs['ky'],
                                            inputs['kz'], inputs['ktx'],
                                            inputs['kty'], inputs['ktz'],
                                            rigid)
        # -----------------------------------

        # ------ frame element data ------------
        element = np.arange(1, n)
        N1 = np.arange(1, n)
        N2 = np.arange(2, n + 1)

        roll = np.zeros(n - 1)

        # average across element b.c. frame3dd uses constant section elements
        # TODO: Use nodal2sectional
        Az = inputs['Az']
        Asx = inputs['Asx']
        Asy = inputs['Asy']
        Jz = inputs['Jz']
        Ixx = inputs['Ixx']
        Iyy = inputs['Iyy']
        E = inputs['E']
        G = inputs['G']
        rho = inputs['rho']

        elements = pyframe3dd.ElementData(element, N1, N2, Az, Asx, Asy, Jz,
                                          Ixx, Iyy, E, G, roll, rho)
        # -----------------------------------

        # ------ options ------------
        dx = -1.0
        options = pyframe3dd.Options(frame3dd_opt['shear'],
                                     frame3dd_opt['geom'], dx)
        # -----------------------------------

        # initialize frame3dd object
        cylinder = pyframe3dd.Frame(nodes, reactions, elements, options)

        # ------ add extra mass ------------

        # extra node inertia data
        N = inputs['midx'] + np.ones(len(inputs['midx']))

        add_gravity = True
        cylinder.changeExtraNodeMass(N, inputs['m'], inputs['mIxx'],
                                     inputs['mIyy'], inputs['mIzz'],
                                     inputs['mIxy'], inputs['mIxz'],
                                     inputs['mIyz'], inputs['mrhox'],
                                     inputs['mrhoy'], inputs['mrhoz'],
                                     add_gravity)

        # ------------------------------------

        # ------- enable dynamic analysis ----------
        Mmethod = 1
        lump = 0
        shift = 0.0
        cylinder.enableDynamics(NFREQ, Mmethod, lump, frame3dd_opt['tol'],
                                shift)
        # ----------------------------

        # ------ static load case 1 ------------

        # gravity in the X, Y, Z, directions (global)
        gx = 0.0
        gy = 0.0
        gz = -gravity

        load = pyframe3dd.StaticLoadCase(gx, gy, gz)

        # point loads
        nF = inputs['plidx'] + np.ones(len(inputs['plidx']))
        load.changePointLoads(nF, inputs['Fx'], inputs['Fy'], inputs['Fz'],
                              inputs['Mxx'], inputs['Myy'], inputs['Mzz'])

        # distributed loads
        Px, Py, Pz = inputs['Pz'], inputs['Py'], -inputs[
            'Px']  # switch to local c.s.
        z = inputs['z']

        # trapezoidally distributed loads
        EL = np.arange(1, n)
        xx1 = xy1 = xz1 = np.zeros(n - 1)
        xx2 = xy2 = xz2 = np.diff(
            z) - 1e-6  # subtract small number b.c. of precision
        wx1 = Px[:-1]
        wx2 = Px[1:]
        wy1 = Py[:-1]
        wy2 = Py[1:]
        wz1 = Pz[:-1]
        wz2 = Pz[1:]

        load.changeTrapezoidalLoads(EL, xx1, xx2, wx1, wx2, xy1, xy2, wy1, wy2,
                                    xz1, xz2, wz1, wz2)

        cylinder.addLoadCase(load)
        # Debugging
        #cylinder.write('temp.3dd')
        # -----------------------------------
        # run the analysis
        displacements, forces, reactions, internalForces, mass, modal = cylinder.run(
        )
        iCase = 0

        # mass
        outputs['mass'] = mass.struct_mass

        # natural frequncies
        outputs['f1'] = modal.freq[0]
        outputs['f2'] = modal.freq[1]
        outputs['freqs'] = modal.freq

        # Get all mode shapes in batch
        freq_x, freq_y, mshapes_x, mshapes_y = util.get_mode_shapes(
            z, modal.freq, modal.xdsp, modal.ydsp, modal.zdsp, modal.xmpf,
            modal.ympf, modal.zmpf)
        outputs['x_mode_freqs'] = freq_x
        outputs['y_mode_freqs'] = freq_y
        outputs['x_mode_shapes'] = mshapes_x
        outputs['y_mode_shapes'] = mshapes_y

        # deflections due to loading (from cylinder top and wind/wave loads)
        outputs['top_deflection'] = displacements.dx[
            iCase, n - 1]  # in yaw-aligned direction

        # shear and bending, one per element (convert from local to global c.s.)
        Fz = forces.Nx[iCase, 1::2]
        Vy = forces.Vy[iCase, 1::2]
        Vx = -forces.Vz[iCase, 1::2]

        Mzz = forces.Txx[iCase, 1::2]
        Myy = forces.Myy[iCase, 1::2]
        Mxx = -forces.Mzz[iCase, 1::2]

        # Record total forces and moments
        outputs['base_F'] = -1.0 * np.array(
            [reactions.Fx.sum(),
             reactions.Fy.sum(),
             reactions.Fz.sum()])
        outputs['base_M'] = -1.0 * np.array(
            [reactions.Mxx.sum(),
             reactions.Myy.sum(),
             reactions.Mzz.sum()])

        outputs['Fz_out'] = Fz
        outputs['Vx_out'] = Vx
        outputs['Vy_out'] = Vy
        outputs['Mxx_out'] = Mxx
        outputs['Myy_out'] = Myy
        outputs['Mzz_out'] = Mzz

        # axial and shear stress
        d, _ = util.nodal2sectional(inputs['d'])
        qdyn, _ = util.nodal2sectional(inputs['qdyn'])

        ##R = self.d/2.0
        ##x_stress = R*np.cos(self.theta_stress)
        ##y_stress = R*np.sin(self.theta_stress)
        ##axial_stress = Fz/self.Az + Mxx/self.Ixx*y_stress - Myy/self.Iyy*x_stress
        #        V = Vy*x_stress/R - Vx*y_stress/R  # shear stress orthogonal to direction x,y
        #        shear_stress = 2. * V / self.Az  # coefficient of 2 for a hollow circular section, but should be conservative for other shapes
        outputs['axial_stress'] = Fz / inputs['Az'] - np.sqrt(
            Mxx**2 + Myy**2
        ) / inputs[
            'Iyy'] * d / 2.0  #More conservative, just use the tilted bending and add total max shear as well at the same point, if you do not like it go back to the previous lines

        outputs['shear_stress'] = 2. * np.sqrt(Vx**2 + Vy**2) / inputs[
            'Az']  # coefficient of 2 for a hollow circular section, but should be conservative for other shapes

        # hoop_stress (Eurocode method)
        L_reinforced = self.options['buckling_length'] * np.ones(Fz.shape)
        outputs['hoop_stress_euro'] = hoopStressEurocode(
            inputs['z'], d, inputs['t'], L_reinforced, qdyn)

        # Simpler hoop stress used in API calculations
        outputs['hoop_stress'] = hoopStress(d, inputs['t'], qdyn)