Example #1
0
    def staticSolve(self, reset=False):
        '''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.

        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, HF0=self.HF, VF0=self.VF)   # 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.jacobian = info["jacobian"]
        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
Example #2
0
File: line.py Project: NREL/MoorPy
    def getEndForce(self, endB):
        '''Returns the force of the line at the specified end based on the endB value

        Parameters
        ----------
        endB : boolean
            An indicator of which end of the line is the force wanted

        Raises
        ------
        LineError
            If the given endB value is not a 1 or 0

        Returns
        -------
        fA or fB: array
            The force vector at the end of the line

        '''
        
        if endB == 1:
            return self.fB
        elif endB == 0:
            return self.fA
        else:
            raise LineError("getEndForce: endB value has to be either 1 or 0")
Example #3
0
File: line.py Project: NREL/MoorPy
    def setEndPosition(self, r, endB):
        '''Sets the end position of the line based on the input endB value.

        Parameters
        ----------
        r : array
            x,y,z coorindate position vector of the line end [m].
        endB : boolean
            An indicator of whether the r array is at the end or beginning of the line

        Raises
        ------
        LineError
            If the given endB value is not a 1 or 0

        Returns
        -------
        None.

        '''
        
        if endB == 1:
            self.rB = np.array(r, dtype=np.float_)
        elif endB == 0:
            self.rA = np.array(r, dtype=np.float_)
        else:
            raise LineError("setEndPosition: endB value has to be either 1 or 0")
Example #4
0
    def loadData(self, dirname):
        '''Loads line-specific time series data from a MoorDyn output file'''
    
        self.qs = 0 # signals time series data
    
        # load time series data
        if self.isRod > 0:
            data, ch, channels, units = read_mooring_file(dirname, "Rod"+str(self.number)+".out") # remember number starts on 1 rather than 0
        else:
            data, ch, channels, units = read_mooring_file(dirname, "Line"+str(self.number)+".out") # remember number starts on 1 rather than 0
                
        # get time info
        if ("Time" in ch):
            self.Tdata = data[:,ch["Time"]]
            self.dt = self.Tdata[1]-self.Tdata[0]
        else:
            raise LineError("loadData: could not find Time channel for mooring line "+str(self.number))
    
        
        nT = len(self.Tdata)  # number of time steps
        
        # check for position data <<<<<<
        
        self.xp = np.zeros([nT,self.nNodes])
        self.yp = np.zeros([nT,self.nNodes])
        self.zp = np.zeros([nT,self.nNodes])
        
        
        for i in range(self.nNodes):
            self.xp[:,i] = data[:, ch['Node'+str(i)+'px']]
            self.yp[:,i] = data[:, ch['Node'+str(i)+'py']]
            self.zp[:,i] = data[:, ch['Node'+str(i)+'pz']]
            
        if self.isRod==0:
            self.Te = np.zeros([nT,self.nNodes-1])   # read in tension data if available
            if "Seg1Te" in ch:
                for i in range(self.nNodes-1):
                    self.Te[:,i] = data[:, ch['Seg'+str(i+1)+'Te']]
                    
            self.Ku = np.zeros([nT,self.nNodes])   # read in curvature data if available
            if "Node0Ku" in ch:
                for i in range(self.nNodes):
                    self.Ku[:,i] = data[:, ch['Node'+str(i)+'Ku']]

        self.Ux = np.zeros([nT,self.nNodes])   # read in fluid velocity data if available
        self.Uy = np.zeros([nT,self.nNodes])
        self.Uz = np.zeros([nT,self.nNodes])
        if "Node0Ux" in ch:
            for i in range(self.nNodes):
                self.Ux[:,i] = data[:, ch['Node'+str(i)+'Ux']]
                self.Uy[:,i] = data[:, ch['Node'+str(i)+'Uy']]
                self.Uz[:,i] = data[:, ch['Node'+str(i)+'Uz']]


        self.xpi= self.xp[0,:]
        self.ypi= self.yp[0,:]
        self.zpi= self.zp[0,:]
        
        # get length (constant)
        self.L = np.sqrt( (self.xpi[-1]-self.xpi[0])**2 + (self.ypi[-1]-self.ypi[0])**2 + (self.zpi[-1]-self.zpi[0])**2 )
Example #5
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 #6
0
File: line.py Project: NREL/MoorPy
    def getTimestep(self, Time):
        '''Get the time step to use for showing time series data'''
        
        if Time < 0: 
            ts = np.int(-Time)  # negative value indicates passing a time step index
        else:           # otherwise it's a time in s, so find closest time step
            for index, item in enumerate(self.Tdata):
                #print "index is "+str(index)+" and item is "+str(item)
                ts = -1
                if item > Time:
                    ts = index
                    break
            if ts==-1:
                raise LineError("getTimestep: requested time likely out of range")

                
        return ts
Example #7
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 #8
0
File: line.py Project: NREL/MoorPy
    def getLineTens(self):
        '''Calls the catenary function to return the tensions of the Line for a quasi-static analysis'''

        # >>> this can probably be done using data already generated by static Solve <<<

        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)

        Ts = info["Te"]
        return Ts
Example #9
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()