Example #1
0
 def getLineCoords(self, Time):    # formerly UpdateLine
     '''Gets the updated line coordinates for drawing and plotting purposes.'''
 
     # if a quasi-static analysis, just call the catenary function to return the line coordinates
     if self.qs==1:
     
         depth = self.sys.depth
     
         dr =  self.rB - self.rA                 
         LH = np.hypot(dr[0], dr[1])     # horizontal spacing of line ends
         LV = dr[2]                      # vertical offset from end A to end B
         
         if np.min([self.rA[2],self.rB[2]]) > -depth:
             self.cb = -depth - np.min([self.rA[2],self.rB[2]])   # if this line's lower end is off the seabed, set cb negative and to the distance off the seabed
         elif self.cb < 0:   # if a line end is at the seabed, but the cb is still set negative to indicate off the seabed
             self.cb = 0.0     # set to zero so that the line includes seabed interaction.
     
         try:
             (fAH, fAV, fBH, fBV, info) = catenary(LH, LV, self.L, self.sys.lineTypes[self.type].EA, 
                                               self.sys.lineTypes[self.type].w, self.cb, HF0=self.HF, VF0=self.VF, nNodes=self.nNodes, plots=1) 
         except CatenaryError as error:
             raise LineError(self.number, error.message)
         
         Xs = self.rA[0] + info["X"]*dr[0]/LH
         Ys = self.rA[1] + info["X"]*dr[1]/LH
         Zs = self.rA[2] + info["Z"]
         
         return Xs, Ys, Zs
         
     # otherwise, count on read-in time-series data
     else:
         # figure out what time step to use
         ts = self.getTimestep(Time)
         
         # drawing rods
         if self.isRod > 0:
         
             k1 = np.array([ self.xp[ts,-1]-self.xp[ts,0], self.yp[ts,-1]-self.yp[ts,0], self.zp[ts,-1]-self.zp[ts,0] ]) / self.length # unit vector
             
             k = np.array(k1) # make copy
         
             Rmat = np.array(rotationMatrix(0, np.arctan2(np.hypot(k[0],k[1]), k[2]), np.arctan2(k[1],k[0])))  # <<< should fix this up at some point, MattLib func may be wrong
             
             # make points for appropriately sized cylinder
             d = self.sys.lineTypes[self.type].d
             Xs, Ys, Zs = makeTower(self.length, np.array([d, d]))
             
             # translate and rotate into proper position for Rod
             coords = np.vstack([Xs, Ys, Zs])
             newcoords = np.matmul(Rmat,coords)
             Xs = newcoords[0,:] + self.xp[ts,0]
             Ys = newcoords[1,:] + self.yp[ts,0]
             Zs = newcoords[2,:] + self.zp[ts,0]
             
             return Xs, Ys, Zs
             
         # drawing lines
         else:
             
             return self.xp[ts,:], self.yp[ts,:], self.zp[ts,:]
Example #2
0
File: line.py Project: NREL/MoorPy
    def getStiffnessMatrix(self):
        '''Returns the stiffness matrix of a line derived from analytic terms in the jacobian of catenary

        Raises
        ------
        LineError
            If a singluar matrix error occurs while taking the inverse of the Line's Jacobian matrix.

        Returns
        -------
        K2_rot : matrix
            the analytic stiffness matrix of the line in the rotated frame.

        '''

        # take the inverse of the Jacobian to get the starting analytic stiffness matrix
        '''
        if np.isnan(self.jacobian[0,0]): #if self.LBot >= self.L and self.HF==0. and self.VF==0.  << handle tricky cases here?
            K = np.array([[0., 0.], [0., 1.0/self.jacobian[1,1] ]])
        else:
            try:
                K = np.linalg.inv(self.jacobian)
            except:
                raise LineError(self.number, f"Check Line Length ({self.L}), it might be too long, or check catenary ProfileType")
        '''
        
        # solve for required variables to set up the perpendicular stiffness. Keep it horizontal
        L_xy = np.linalg.norm(self.rB[:2] - self.rA[:2])
        T_xy = np.linalg.norm(self.fB[:2])
        Kt = T_xy/L_xy
        
        # initialize the line's analytic stiffness matrix in the "in-line" plane
        KA = np.array([[self.KA2[0,0], 0 , self.KA2[0,1]],
                       [     0      , Kt,      0      ],
                       [self.KA2[1,0], 0 , self.KA2[1,1]]])
                       
        KB = np.array([[self.KB2[0,0], 0 , self.KB2[0,1]],
                       [     0      , Kt,      0      ],
                       [self.KB2[1,0], 0 , self.KB2[1,1]]])
        
        # create the rotation matrix based on the heading angle that the line is from the horizontal
        R = rotationMatrix(0,0,self.th)
        
        # rotate the matrix to be about the global frame [K'] = [R][K][R]^T
        KA_rot = np.matmul(np.matmul(R, KA), R.T)
        KB_rot = np.matmul(np.matmul(R, KB), R.T)
        
        return KA_rot, KB_rot
Example #3
0
    def getStiffnessMatrix(self):
        '''Returns the stiffness matrix of a line derived from analytic terms in the jacobian of catenary

        Raises
        ------
        LineError
            If a singluar matrix error occurs while taking the inverse of the Line's Jacobian matrix.

        Returns
        -------
        K2_rot : matrix
            the analytic stiffness matrix of the line in the rotated frame.

        '''
        
        # take the inverse of the Jacobian to get the starting analytic stiffness matrix
        try:
            K = np.linalg.inv(self.jacobian)
        except:
            raise LineError(self.number, f"Check Line Length ({self.L}), it might be too long, or check catenary ProfileType")
        
        # solve for required variables to set up the perpendicular stiffness. Keep it horizontal
        L_xy = np.linalg.norm(self.rB[:2] - self.rA[:2])
        T_xy = np.linalg.norm(self.fB[:2])
        Kt = T_xy/L_xy
        
        # initialize the line's analytic stiffness matrix in the "in-line" plane
        K2 = np.array([[K[0,0], 0 , K[0,1]],
                       [0     , Kt, 0     ],
                       [K[1,0], 0 , K[1,1]]])
        
        # create the rotation matrix based on the heading angle that the line is from the horizontal
        R = rotationMatrix(0,0,self.th)
        
        # rotate the matrix to be about the global frame [K'] = [R][K][R]^T
        K2_rot = np.matmul(np.matmul(R, K2), R.T)
        
        # need to make sign changes if the end fairlead (B) of the line is lower than the starting point (A)
        if self.rB[2] < self.rA[2]:
            K2_rot[2,0] *= -1
            K2_rot[0,2] *= -1
            K2_rot[2,1] *= -1
            K2_rot[1,2] *= -1
        
        return K2_rot
Example #4
0
    def setPosition(self, r6):
        '''Sets the position of the Body, along with that of any dependent objects.

        Parameters
        ----------
        r6 : array
            6DOF position and orientation vector of the body [m, rad]

        Raises
        ------
        ValueError
            If the length of the input r6 array is not of length 6

        Returns
        -------
        None.

        '''

        if len(r6) == 6:
            self.r6 = np.array(
                r6, dtype=np.float_)  # update the position of the Body itself
        else:
            raise ValueError(
                f"Body setPosition method requires an argument of size 6, but size {len(r6):d} was provided"
            )

        self.R = rotationMatrix(self.r6[3], self.r6[4],
                                self.r6[5])  # update body rotation matrix

        # update the position of any attached Points
        for PointID, rPointRel in zip(self.attachedP, self.rPointRel):
            rPoint = np.matmul(
                self.R, rPointRel
            ) + self.r6[:3]  # rPoint = transformPosition(rPointRel, r6)
            self.sys.pointList[PointID - 1].setPosition(rPoint)

        if self.sys.display > 3:
            printVec(rPoint)
            breakpoint()
Example #5
0
File: line.py Project: NREL/MoorPy
    def staticSolve(self, reset=False, tol=0.0001, profiles=0):
        '''Solves static equilibrium of line. Sets the end forces of the line based on the end points' positions.

        Parameters
        ----------
        reset : boolean, optional
            Determines if the previous fairlead force values will be used for the catenary iteration. The default is False.

        tol : float
            Convergence tolerance for catenary solver measured as absolute error of x and z values in m.
            
        profiles : int
            Values greater than 0 signal for line profile data to be saved (used for plotting, getting distributed tensions, etc).

        Raises
        ------
        LineError
            If the horizontal force at the fairlead (HF) is less than 0

        Returns
        -------
        None.

        '''

        depth = self.sys.depth
        
        dr =  self.rB - self.rA                 
        LH = np.hypot(dr[0], dr[1])     # horizontal spacing of line ends
        LV = dr[2]                # vertical offset from end A to end B

        if self.rA[2] < -depth:
            raise LineError("Line {} end A is lower than the seabed.".format(self.number))
        elif self.rB[2] < -depth:
            raise LineError("Line {} end B is lower than the seabed.".format(self.number))
        elif np.min([self.rA[2],self.rB[2]]) > -depth:
            self.cb = -depth - np.min([self.rA[2],self.rB[2]])   # if this line's lower end is off the seabed, set cb negative and to the distance off the seabed
        elif self.cb < 0:   # if a line end is at the seabed, but the cb is still set negative to indicate off the seabed
            self.cb = 0.0     # set to zero so that the line includes seabed interaction.
        
        
        if self.HF < 0:  # or self.VF < 0:  <<<<<<<<<<< it shouldn't matter if VF is negative - this could happen for buoyant lines, etc.
            raise LineError("Line HF cannot be negative") # this could be a ValueError too...
            
        if reset==True:   # Indicates not to use previous fairlead force values to start catenary 
            self.HF = 0   # iteration with, and insteady use the default values.
            
        try:
            (fAH, fAV, fBH, fBV, info) = catenary(LH, LV, self.L, self.sys.lineTypes[self.type].EA, self.sys.lineTypes[self.type].w, 
                                                  CB=self.cb, Tol=tol, HF0=self.HF, VF0=self.VF, plots=profiles)   # call line model
        except CatenaryError as error:
            raise LineError(self.number, error.message)
            
        self.th = np.arctan2(dr[1],dr[0])  # probably a more efficient way to handle this <<<
        self.HF = info["HF"]
        self.VF = info["VF"]
        self.KA2 = info["stiffnessA"]
        self.KB2 = info["stiffnessB"]
        self.LBot = info["LBot"]
        self.info = info
            
        self.fA[0] = fAH*dr[0]/LH
        self.fA[1] = fAH*dr[1]/LH
        self.fA[2] = fAV
        self.fB[0] = fBH*dr[0]/LH
        self.fB[1] = fBH*dr[1]/LH
        self.fB[2] = fBV
        self.TA = np.sqrt(fAH*fAH + fAV*fAV) # end tensions
        self.TB = np.sqrt(fBH*fBH + fBV*fBV)
        
        # ----- compute 3d stiffness matrix for both line ends (3 DOF + 3 DOF) -----
        
        # solve for required variables to set up the perpendicular stiffness. Keep it horizontal
        #L_xy = np.linalg.norm(self.rB[:2] - self.rA[:2])
        #T_xy = np.linalg.norm(self.fB[:2])
        
        # create the rotation matrix based on the heading angle that the line is from the horizontal
        R = rotationMatrix(0,0,self.th)
        
        # initialize the line's analytic stiffness matrix in the "in-line" plane then rotate the matrix to be about the global frame [K'] = [R][K][R]^T
        def from2Dto3Drotated(K2D, Kt):
            K2 = np.array([[K2D[0,0], 0 , K2D[0,1]],
                           [  0     , Kt,   0     ],
                           [K2D[1,0], 0 , K2D[1,1]]])
            return np.matmul(np.matmul(R, K2), R.T)
        
        self.KA  = from2Dto3Drotated(info['stiffnessA'], -fBH/LH)   # stiffness matrix describing reaction force on end A due to motion of end A
        self.KB  = from2Dto3Drotated(info['stiffnessB'], -fBH/LH)   # stiffness matrix describing reaction force on end B due to motion of end B
        self.KAB = from2Dto3Drotated(info['stiffnessAB'], fBH/LH)  # stiffness matrix describing reaction force on end B due to motion of end A
                
        #self.K6 = np.block([[ from2Dto3Drotated(self.KA),  from2Dto3Drotated(self.KAB.T)],
        #                    [ from2Dto3Drotated(self.KAB), from2Dto3Drotated(self.KB)  ]])
        
        
        
        if profiles > 1:
            import matplotlib.pyplot as plt
            plt.plot(info['X'], info['Z'])
            plt.show()
Example #6
0
    def getForces(self, lines_only=False):
        '''Sums the forces and moments on the Body, including its own plus those from any attached objects.

        Parameters
        ----------
        lines_only : boolean, optional
            An option for calculating forces from just the mooring lines or not. The default is False.

        Returns
        -------
        f6 : array
            The 6DOF forces and moments applied to the body in its current position [N, Nm]

        '''

        f6 = np.zeros(6)

        # TODO: could save time in below by storing the body's rotation matrix when it's position is set rather than
        #       recalculating it in each of the following function calls.

        if lines_only == False:

            # add weight, which may result in moments as well as a force
            rCG_rotated = rotatePosition(
                self.rCG, self.r6[3:]
            )  # relative position of CG about body ref point in unrotated reference frame
            f6 += translateForce3to6DOF(rCG_rotated,
                                        np.array([
                                            0, 0, -self.m * self.sys.g
                                        ]))  # add to net forces/moments

            # add buoyancy force and moments if applicable (this can include hydrostatic restoring moments
            # if rM is considered the metacenter location rather than the center of buoyancy)
            rM_rotated = rotatePosition(
                self.rM, self.r6[3:]
            )  # relative position of metacenter about body ref point in unrotated reference frame
            f6 += translateForce3to6DOF(rM_rotated,
                                        np.array([
                                            0, 0,
                                            self.sys.rho * self.sys.g * self.v
                                        ]))  # add to net forces/moments

            # add hydrostatic heave stiffness (if AWP is nonzero)
            f6[2] -= self.sys.rho * self.sys.g * self.AWP * self.r6[2]

            # add any externally applied forces/moments (in global orientation)
            f6 += self.f6Ext

        # add forces from any attached Points (and their attached lines)
        for PointID, rPointRel in zip(self.attachedP, self.rPointRel):

            fPoint = self.sys.pointList[PointID - 1].getForces(
                lines_only=lines_only)  # get net force on attached Point
            rPoint_rotated = rotatePosition(
                rPointRel, self.r6[3:]
            )  # relative position of Point about body ref point in unrotated reference frame
            f6 += translateForce3to6DOF(
                rPoint_rotated, fPoint
            )  # add net force and moment resulting from its position to the Body

        # All forces and moments on the body should now be summed, and are in global/unrotated orientations.

        # For application to the body DOFs, convert the moments to be about the body's local/rotated x/y/z axes <<< do we want this in all cases?
        rotMat = rotationMatrix(*self.r6[3:])  # get rotation matrix for body
        moment_about_body_ref = np.matmul(
            rotMat.T, f6[3:]
        )  # transform moments so that they are about the body's local/rotated axes
        f6[3:] = moment_about_body_ref  # use these moments

        return f6