Пример #1
0
    def __init__(self, CurrentConstitutiveLaw, Section, Jx, Iyy, Izz, k=0, ID = ""):
        #k: shear shape factor
        
        if isinstance(CurrentConstitutiveLaw, str):
            CurrentConstitutiveLaw = ConstitutiveLaw.GetAll()[CurrentConstitutiveLaw]

        if ID == "":
            ID = CurrentConstitutiveLaw.GetID()
            
        WeakForm.__init__(self,ID)

        Variable("DispX") 
        Variable("DispY")            
        if ProblemDimension.Get() == '3D':
            Variable("DispZ")   
            Variable("RotX") #torsion rotation 
            Variable("RotY")   
            Variable("RotZ")
            Variable.SetVector('Disp' , ('DispX', 'DispY', 'DispZ') , 'global')
            Variable.SetVector('Rot' , ('RotX', 'RotY', 'RotZ') , 'global')            
        elif ProblemDimension.Get() == '2Dplane':
            Variable("RotZ")
            Variable.SetVector('Disp' , ['DispX', 'DispY'], 'global' )            
            Variable.SetVector('Rot' , ['RotZ'] ) 
        elif ProblemDimension.Get() == '2Dstress':
            assert 0, "No 2Dstress model for a beam kinematic. Choose '2Dplane' instead."
                          
        self.__ConstitutiveLaw = CurrentConstitutiveLaw
        self.__parameters = {'Section': Section, 'Jx': Jx, 'Iyy':Iyy, 'Izz':Izz, 'k':k}        
Пример #2
0
    def __init__(self, E=None, nu = None, S=None, Jx=None, Iyy=None, Izz = None, R = None, k=0, ID = ""):
        """
        Weak formulation dedicated to treat parametric problems using Bernoulli beams for isotropic materials
        
        Arugments
        ----------
        ID: str
            ID of the weak formulation
        List of other optional parameters
            E: Young Modulus
            nu: Poisson Ratio
            S: Section area
            Jx: Torsion constant
            Iyy, Izz: Second moment of area, if Izz is not specified, Iyy = Izz is assumed
            k is a scalar. k=0 for no shear effect. For other values, k is the shear area coefficient            
        When the differntial operator is generated (using PGD.Assembly) the parameters are searched among the CoordinateID defining the associated mesh.
        If a parameter is not found , a Numeric value should be specified in argument.
        
        In the particular case of cylindrical beam, the radius R can be specified instead of S, Jx, Iyy and Izz.
            S = pi * R**2
            Jx = pi * R**4/2
            Iyy = Izz = pi * R**4/4         
        """
    
        WeakForm.__init__(self,ID)

        Variable("DispX") 
        Variable("DispY")     
        if ProblemDimension.Get() == '3D':
            Variable("DispZ")   
            Variable("RotX") #torsion rotation    
            Variable('RotY')
            Variable('RotZ')
            # Variable.SetDerivative('DispZ', 'RotY', sign = -1) #only valid with Bernoulli model
            # Variable.SetDerivative('DispY', 'RotZ') #only valid with Bernoulli model       
            Variable.SetVector('Disp' , ('DispX', 'DispY', 'DispZ') , 'global')
            Variable.SetVector('Rot' , ('RotX', 'RotY', 'RotZ') , 'global')
        elif ProblemDimension.Get() == '2Dplane':
            Variable('RotZ')
            Variable.SetVector('Disp' , ('DispX', 'DispY'), 'global' )
            Variable.SetVector('Rot' , ('RotZ'))
        elif ProblemDimension.Get() == '2Dstress':
            assert 0, "No 2Dstress model for a beam kinematic. Choose '2Dplane' instead."
        
        if R is not None:
            S = np.pi * R**2
            Jx = np.pi * R**4/2
            Iyy = Izz = np.pi * R**4/4 
        
        self.__parameters = {'E':E, 'nu':nu, 'S':S, 'Jx':Jx, 'Iyy':Iyy, 'Izz':Izz, 'k':k}
Пример #3
0
    def __init__(self,
                 NodeCoordinates,
                 ElementTable=None,
                 ElementShape=None,
                 LocalFrame=None,
                 ID=""):
        MeshBase.__init__(self, ID)
        self.__NodeCoordinates = NodeCoordinates  #node coordinates
        self.__ElementTable = ElementTable  #element
        self.__ElementShape = ElementShape
        self.__SetOfNodes = {}  #node on the boundary for instance
        self.__SetOfElements = {}
        self.__LocalFrame = LocalFrame  #contient le repere locale (3 vecteurs unitaires) en chaque noeud. Vaut 0 si pas de rep locaux definis

        n = ProblemDimension.Get()
        N = self.__NodeCoordinates.shape[0]

        if self.__NodeCoordinates.shape[1] == 1: self.__CoordinateID = ('X')
        elif self.__NodeCoordinates.shape[1] == 2:
            self.__CoordinateID = ('X', 'Y')
        elif n == '2Dplane' or n == '2Dstress':
            self.__CoordinateID = ('X', 'Y')
        else:
            self.__CoordinateID = ('X', 'Y', 'Z')

        if n == '3D' and self.__NodeCoordinates.shape[1] == 2:
            self.__NodeCoordinates = np.c_[self.__NodeCoordinates, np.zeros(N)]
            if LocalFrame != None:
                LocalFrameTemp = np.zeros((N, 3, 3))
                LocalFrameTemp[:, :2, :2] = self.__LocalFrame
                LocalFrameTemp[:, 2, 2] = 1
                self.__LocalFrame = LocalFrameTemp
Пример #4
0
def GetGradOperator():
    if ProblemDimension.Get() == "3D":        
        GradOperator = [[OpDiff(IDvar, IDcoord,1) for IDcoord in ['X','Y','Z']] for IDvar in ['DispX','DispY','DispZ']]    
    else:
        GradOperator = [[OpDiff(IDvar, IDcoord,1) for IDcoord in ['X','Y']] + [0] for IDvar in ['DispX','DispY']]       
        GradOperator += [[0,0,0]]
            
    return GradOperator
Пример #5
0
    def __init__(self, Density, ID = ""):
           
        if ID == "":
            ID = "Inertia"
            
        WeakForm.__init__(self,ID)

        Variable("DispX") 
        Variable("DispY")                
        if ProblemDimension.Get() == "3D": Variable("DispZ")        
        
        self.__Density = Density        
Пример #6
0
    def __init__(self, CurrentConstitutiveLaw, ID=""):
        if isinstance(CurrentConstitutiveLaw, str):
            CurrentConstitutiveLaw = ConstitutiveLaw.GetAll(
            )[CurrentConstitutiveLaw]

        if ID == "":
            ID = CurrentConstitutiveLaw.GetID()

        WeakForm.__init__(self, ID)

        Variable("DispX")
        Variable("DispY")
        if ProblemDimension.Get() == "3D": Variable("DispZ")

        self.__ConstitutiveLaw = CurrentConstitutiveLaw
        self.__InitialStressVector = 0
Пример #7
0
    def __init__(self, Density, ID=""):

        if ID == "":
            ID = "Inertia"

        WeakForm.__init__(self, ID)

        Variable("DispX")
        Variable("DispY")
        if ProblemDimension.Get() == "3D":
            Variable("DispZ")
            Variable.SetVector('Disp', ('DispX', 'DispY', 'DispZ'))
        else:
            Variable.SetVector('Disp', ('DispX', 'DispY'))

        self.__Density = Density
Пример #8
0
def LineMesh(N=11, x_min=0, x_max=1, ElementShape='lin2', ID=""):
    """
    Define the mesh of a line  

    Parameters
    ----------
    N : int
        Numbers of nodes (default = 11).
    x_min, x_max : int,float,list
        The boundary of the line as scalar (1D) or list (default : 0, 1).
    ElementShape : {'lin2', 'lin3', 'lin4'}
        The shape of the elements (default='lin2')
        * 'lin2' -- 2 node line
        * 'lin3' -- 3 node line
        * 'lin4' -- 4 node line  

    Returns
    -------
    Mesh
        The generated geometry in Mesh format. See the Mesh class for more details.
        
    See Also
    --------     
    RectangleMesh : Surface mesh of a rectangle
    BoxMesh : Volume mesh of a box 
    GridMeshCylindric : Surface mesh of a grid in cylindrical coodrinate 
    LineMeshCylindric : Line mesh in cylindrical coordinate
    """
    if np.isscalar(x_min):
        m = LineMesh1D(N, x_min, x_max, ElementShape, ID)
        if ProblemDimension.Get() in ['2Dplane', '2Dstress']: dim = 2
        else: dim = 3
        crd = np.c_[m.GetNodeCoordinates(), np.zeros((N, dim - 1))]
        elm = m.GetElementTable()
        ReturnedMesh = Mesh(crd, elm, ElementShape, None, ID)
        ReturnedMesh.AddSetOfNodes(m.GetSetOfNodes("left"), "left")
        ReturnedMesh.AddSetOfNodes(m.GetSetOfNodes("right"), "right")
    else:
        m = LineMesh1D(N, 0., 1., ElementShape, ID)
        crd = m.GetNodeCoordinates()
        crd = (np.array(x_max) - np.array(x_min)) * crd + np.array(x_min)
        elm = m.GetElementTable()
        ReturnedMesh = Mesh(crd, elm, ElementShape, None, ID)
        ReturnedMesh.AddSetOfNodes(m.GetSetOfNodes("left"), "left")
        ReturnedMesh.AddSetOfNodes(m.GetSetOfNodes("right"), "right")

    return ReturnedMesh
Пример #9
0
def GetBernoulliBeamStrainOperator():
    n = ProblemDimension.Get()

    epsX = OpDiff('DispX', 'X', 1)  # dérivée en repère locale
    xsiZ = OpDiff('RotZ', 'X', 1)  # flexion autour de Z

    if n == "2Dplane":
        eps = [epsX, 0, 0, 0, 0, xsiZ]

    elif n == "2Dstress":
        assert 0, "no 2Dstress for a beam kinematic, use '2Dplane' instead"

    elif n == "3D":
        xsiX = OpDiff('RotX', 'X', 1)  # torsion autour de X
        xsiY = OpDiff('RotY', 'X', 1)  # flexion autour de Y
        eps = [epsX, 0, 0, xsiX, xsiY, xsiZ]

    eps_vir = [e.virtual() if e != 0 else 0 for e in eps]

    return eps, eps_vir
Пример #10
0
def GetBeamStrainOperator():
    n = ProblemDimension.Get()

    epsX = OpDiff('DispX', 'X', 1)  # dérivée en repère locale
    xsiZ = OpDiff('RotZ', 'X', 1)  # flexion autour de Z
    gammaY = OpDiff('DispY', 'X', 1) - OpDiff('RotZ')  #shear/Y

    if n == "2Dplane":
        eps = [epsX, gammaY, 0, 0, 0, xsiZ]

    elif n == "2Dstress":
        assert 0, "no 2Dstress for a beam kinematic"

    elif n == "3D":
        xsiX = OpDiff('RotX', 'X', 1)  # torsion autour de X
        xsiY = OpDiff('RotY', 'X', 1)  # flexion autour de Y
        gammaZ = OpDiff('DispZ', 'X', 1) + OpDiff('RotY')  #shear/Z

        eps = [epsX, gammaY, gammaZ, xsiX, xsiY, xsiZ]

    eps_vir = [e.virtual() if e != 0 else 0 for e in eps]

    return eps, eps_vir
Пример #11
0
    def __init__(self, CurrentConstitutiveLaw, ID="", nlgeom=False):
        if isinstance(CurrentConstitutiveLaw, str):
            CurrentConstitutiveLaw = ConstitutiveLaw.GetAll(
            )[CurrentConstitutiveLaw]

        if ID == "":
            ID = CurrentConstitutiveLaw.GetID()

        WeakForm.__init__(self, ID)

        Variable("DispX")
        Variable("DispY")
        if ProblemDimension.Get() == "3D":
            Variable("DispZ")
            Variable.SetVector('Disp', ('DispX', 'DispY', 'DispZ'))
        else:  #2D assumed
            Variable.SetVector('Disp', ('DispX', 'DispY'))

        self.__ConstitutiveLaw = CurrentConstitutiveLaw
        self.__InitialStressTensor = 0
        self.__InitialGradDispTensor = None

        self.__nlgeom = nlgeom  #geometric non linearities

        if nlgeom:
            if ProblemDimension.Get() == "3D":
                GradOperator = [[
                    OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y', 'Z']
                ] for IDvar in ['DispX', 'DispY', 'DispZ']]
                #NonLinearStrainOperatorVirtual = 0.5*(vir(duk/dxi) * duk/dxj + duk/dxi * vir(duk/dxj)) using voigt notation and with a 2 factor on non diagonal terms
                NonLinearStrainOperatorVirtual = [
                    sum([
                        GradOperator[k][i].virtual() * GradOperator[k][i]
                        for k in range(3)
                    ]) for i in range(3)
                ]
                NonLinearStrainOperatorVirtual += [
                    sum([
                        GradOperator[k][0].virtual() * GradOperator[k][1] +
                        GradOperator[k][1].virtual() * GradOperator[k][0]
                        for k in range(3)
                    ])
                ]
                NonLinearStrainOperatorVirtual += [
                    sum([
                        GradOperator[k][0].virtual() * GradOperator[k][2] +
                        GradOperator[k][2].virtual() * GradOperator[k][0]
                        for k in range(3)
                    ])
                ]
                NonLinearStrainOperatorVirtual += [
                    sum([
                        GradOperator[k][1].virtual() * GradOperator[k][2] +
                        GradOperator[k][2].virtual() * GradOperator[k][1]
                        for k in range(3)
                    ])
                ]
            else:
                GradOperator = [[
                    OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y']
                ] for IDvar in ['DispX', 'DispY']]
                NonLinearStrainOperatorVirtual = [
                    sum([
                        GradOperator[k][i].virtual() * GradOperator[k][i]
                        for k in range(2)
                    ]) for i in range(2)
                ] + [0]
                NonLinearStrainOperatorVirtual += [
                    sum([
                        GradOperator[k][0].virtual() * GradOperator[k][1] +
                        GradOperator[k][1].virtual() * GradOperator[k][0]
                        for k in range(2)
                    ])
                ] + [0, 0]

            self.__NonLinearStrainOperatorVirtual = NonLinearStrainOperatorVirtual

        else:
            self.__NonLinearStrainOperatorVirtual = 0
Пример #12
0
    def Get(InitialGradDisp=None):
        n = ProblemDimension.Get()
        # InitialGradDisp = StrainOperator.__InitialGradDisp

        if (InitialGradDisp is None) or (InitialGradDisp is 0):
            du_dx = OpDiff('DispX', 'X', 1)
            dv_dy = OpDiff('DispY', 'Y', 1)
            du_dy = OpDiff('DispX', 'Y', 1)
            dv_dx = OpDiff('DispY', 'X', 1)

            if n == "2Dplane" or n == "2Dstress":
                eps = [du_dx, dv_dy, 0, du_dy + dv_dx, 0, 0]

        #    elif n == "2Dstress":
        #        dw_dx = OpDiff('DispZ', 'X', 1)
        #        dw_dy = OpDiff('DispZ', 'Y', 1)
        #        eps = [du_dx, dv_dy, 0, dw_dy, dw_dx, du_dy+dv_dx]

            elif n == "3D":
                dw_dz = OpDiff('DispZ', 'Z', 1)
                du_dz = OpDiff('DispX', 'Z', 1)
                dv_dz = OpDiff('DispY', 'Z', 1)
                dw_dx = OpDiff('DispZ', 'X', 1)
                dw_dy = OpDiff('DispZ', 'Y', 1)
                eps = [
                    du_dx, dv_dy, dw_dz, du_dy + dv_dx, du_dz + dw_dx,
                    dv_dz + dw_dy
                ]

        else:

            if n == "2Dplane" or n == "2Dstress":
                GradOperator = [[
                    OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y']
                ] for IDvar in ['DispX', 'DispY']]
                eps = [
                    GradOperator[i][i] + sum([
                        GradOperator[k][i] * InitialGradDisp[k][i]
                        for k in range(2)
                    ]) for i in range(2)
                ]
                eps += [0]
                eps += [
                    GradOperator[0][1] + GradOperator[1][0] + sum([
                        GradOperator[k][0] * InitialGradDisp[k][1] +
                        GradOperator[k][1] * InitialGradDisp[k][0]
                        for k in range(2)
                    ])
                ]
                eps += [0, 0]

            elif n == "3D":
                GradOperator = [[
                    OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y', 'Z']
                ] for IDvar in ['DispX', 'DispY', 'DispZ']]
                eps = [
                    GradOperator[i][i] + sum([
                        GradOperator[k][i] * InitialGradDisp[k][i]
                        for k in range(3)
                    ]) for i in range(3)
                ]
                eps += [
                    GradOperator[0][1] + GradOperator[1][0] + sum([
                        GradOperator[k][0] * InitialGradDisp[k][1] +
                        GradOperator[k][1] * InitialGradDisp[k][0]
                        for k in range(3)
                    ])
                ]
                eps += [
                    GradOperator[0][2] + GradOperator[2][0] + sum([
                        GradOperator[k][0] * InitialGradDisp[k][2] +
                        GradOperator[k][2] * InitialGradDisp[k][0]
                        for k in range(3)
                    ])
                ]
                eps += [
                    GradOperator[1][2] + GradOperator[2][1] + sum([
                        GradOperator[k][1] * InitialGradDisp[k][2] +
                        GradOperator[k][2] * InitialGradDisp[k][1]
                        for k in range(3)
                    ])
                ]

        eps_vir = [e.virtual() if e != 0 else 0 for e in eps]

        return eps, eps_vir
Пример #13
0
                ]
                eps += [
                    GradOperator[0][2] + GradOperator[2][0] + sum([
                        GradOperator[k][0] * InitialGradDisp[k][2] +
                        GradOperator[k][2] * InitialGradDisp[k][0]
                        for k in range(3)
                    ])
                ]
                eps += [
                    GradOperator[1][2] + GradOperator[2][1] + sum([
                        GradOperator[k][1] * InitialGradDisp[k][2] +
                        GradOperator[k][2] * InitialGradDisp[k][1]
                        for k in range(3)
                    ])
                ]

        eps_vir = [e.virtual() if e != 0 else 0 for e in eps]

        return eps, eps_vir


def GetStrainOperator(InitialGradDisp=None):
    #return linear the operator to get the strain tensor (to use in weakform)
    #InitialGradDisp is used for initial displacement effect in incremental approach
    return StrainOperator.Get(InitialGradDisp)


if __name__ == "__main__":
    ProblemDimension("3D")
    A, B = GetStrainOperator()
Пример #14
0
    def __init__(self, InitialStressTensor=0, ID=""):
        if ID == "": ID = "InitialStress"

        WeakForm.__init__(self, ID)

        if InitialStressTensor == 0:
            InitialStressTensor = [
                0, 0, 0, 0, 0, 0
            ]  #list of the six stress component (sig_xx, sig_yy, sig_zz, sig_yz, sig_xz, sigxy)

        Variable("DispX")
        Variable("DispY")
        if ProblemDimension.Get() == "3D": Variable("DispZ")

        if ProblemDimension.Get() == "3D":
            GradOperator = [[
                OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y', 'Z']
            ] for IDvar in ['DispX', 'DispY', 'DispZ']]
            #NonLinearStrainOperatorVirtual = 0.5*(vir(duk/dxi) * duk/dxj + duk/dxi * vir(duk/dxj)) using voigt notation and with a 2 factor on non diagonal terms
            NonLinearStrainOperatorVirtual = [
                sum([
                    GradOperator[k][i].virtual() * GradOperator[k][i]
                    for k in range(3)
                ]) for i in range(3)
            ]
            NonLinearStrainOperatorVirtual += [
                sum([
                    GradOperator[k][1].virtual() * GradOperator[k][2] +
                    GradOperator[k][2].virtual() * GradOperator[k][1]
                    for k in range(3)
                ])
            ]
            NonLinearStrainOperatorVirtual += [
                sum([
                    GradOperator[k][0].virtual() * GradOperator[k][2] +
                    GradOperator[k][2].virtual() * GradOperator[k][0]
                    for k in range(3)
                ])
            ]
            NonLinearStrainOperatorVirtual += [
                sum([
                    GradOperator[k][0].virtual() * GradOperator[k][1] +
                    GradOperator[k][1].virtual() * GradOperator[k][0]
                    for k in range(3)
                ])
            ]
        else:
            GradOperator = [[
                Util.OpDiff(IDvar, IDcoord, 1) for IDcoord in ['X', 'Y']
            ] for IDvar in ['DispX', 'DispY']]
            NonLinearStrainOperatorVirtual = [
                sum([
                    GradOperator[k][i].virtual() * GradOperator[k][i]
                    for k in range(2)
                ]) for i in range(2)
            ] + [0, 0, 0]
            NonLinearStrainOperatorVirtual += [
                sum([
                    GradOperator[k][0].virtual() * GradOperator[k][1] +
                    GradOperator[k][1].virtual() * GradOperator[k][0]
                    for k in range(2)
                ])
            ]

        self.__NonLinearStrainOperatorVirtual = NonLinearStrainOperatorVirtual
        self.__InitialStressTensor = InitialStressTensor
        self.__typeOperator = 'all'
Пример #15
0
    def __GetChangeOfBasisMatrix(
            mesh):  # change of basis matrix for beam or plate elements
        if not (mesh.GetID()) in Assembly.__saveMatrixChangeOfBasis:
            ### change of basis treatment for beam or plate elements
            MatrixChangeOfBasis = 1
            computeMatrixChangeOfBasis = False

            Nnd = mesh.GetNumberOfNodes()
            Nel = mesh.GetNumberOfElements()
            elm = mesh.GetElementTable()
            nNd_elm = np.shape(elm)[1]
            crd = mesh.GetNodeCoordinates()
            dim = ProblemDimension.GetDoF()
            localFrame = mesh.GetLocalFrame()
            elmRefGeom = eval(mesh.GetElementShape())()
            #        xi_nd = elmRefGeom.xi_nd
            xi_nd = GetNodePositionInElementCoordinates(
                mesh.GetElementShape(), nNd_elm)  #function to define

            if 'X' in mesh.GetCoordinateID() and 'Y' in mesh.GetCoordinateID(
            ):  #if not in physical space, no change of variable
                for nameVector in Variable.ListVector():
                    if Variable.GetVectorCoordinateSystem(
                            nameVector) == 'global':
                        if computeMatrixChangeOfBasis == False:
                            range_nNd_elm = np.arange(nNd_elm)
                            computeMatrixChangeOfBasis = True
                            Nvar = Variable.GetNumberOfVariable()
                            listGlobalVector = []
                            listLocalVariable = list(range(Nvar))

    #                        MatrixChangeOfBasis = sparse.lil_matrix((Nvar*Nel*nNd_elm, Nvar*Nnd)) #lil is very slow because it change the sparcity of the structure
                        listGlobalVector.append(Variable.GetVector(nameVector))
                        listLocalVariable = [
                            i for i in listLocalVariable
                            if not (i in listGlobalVector[-1])
                        ]
                #Data to build MatrixChangeOfBasis with coo sparse format
                if computeMatrixChangeOfBasis:
                    rowMCB = np.empty(
                        (len(listGlobalVector) * Nel, nNd_elm, dim, dim))
                    colMCB = np.empty(
                        (len(listGlobalVector) * Nel, nNd_elm, dim, dim))
                    dataMCB = np.empty(
                        (len(listGlobalVector) * Nel, nNd_elm, dim, dim))
                    LocalFrameEl = elmRefGeom.GetLocalFrame(
                        crd[elm], xi_nd, localFrame
                    )  #array of shape (Nel, nb_nd, nb of vectors in basis = dim, dim)
                    for ivec, vec in enumerate(listGlobalVector):
                        dataMCB[ivec * Nel:(ivec + 1) * Nel] = LocalFrameEl
                        rowMCB[ivec * Nel:(ivec + 1) * Nel] = np.arange(
                            Nel).reshape(-1, 1, 1, 1) + range_nNd_elm.reshape(
                                1, -1, 1, 1) * Nel + np.array(vec).reshape(
                                    1, 1, -1, 1) * (Nel * nNd_elm)
                        colMCB[ivec * Nel:(ivec + 1) * Nel] = elm.reshape(
                            Nel, nNd_elm, 1,
                            1) + np.array(vec).reshape(1, 1, 1, -1) * Nnd

            if computeMatrixChangeOfBasis:
                MatrixChangeOfBasis = sparse.coo_matrix(
                    (sp.reshape(dataMCB, -1),
                     (sp.reshape(rowMCB, -1), sp.reshape(colMCB, -1))),
                    shape=(Nel * nNd_elm * Nvar, Nnd * Nvar))
                for var in listLocalVariable:
                    MatrixChangeOfBasis = MatrixChangeOfBasis.tolil()
                    MatrixChangeOfBasis[range(var * Nel * nNd_elm,
                                              (var + 1) * Nel * nNd_elm),
                                        range(var * Nel * nNd_elm,
                                              (var + 1) * Nel * nNd_elm)] = 1
                MatrixChangeOfBasis = MatrixChangeOfBasis.tocsr()

            Assembly.__saveMatrixChangeOfBasis[
                mesh.GetID()] = MatrixChangeOfBasis
            return MatrixChangeOfBasis

        return Assembly.__saveMatrixChangeOfBasis[mesh.GetID()]
Пример #16
0
    def PreComputeElementaryOperators(
        mesh,
        elementType,
        nb_pg=None,
        **kargs
    ):  #Précalcul des opérateurs dérivés suivant toutes les directions (optimise les calculs en minimisant le nombre de boucle)
        #initialisation
        if nb_pg is None:
            NumberOfGaussPoint = GetDefaultNbPG(elementType, mesh)
        else:
            NumberOfGaussPoint = nb_pg

        objElement = eval(elementType)

        if isinstance(objElement, dict):
            for val in set(objElement.values()):
                Assembly.PreComputeElementaryOperators(mesh, val, nb_pg,
                                                       **kargs)
            return

        elmRef = objElement(NumberOfGaussPoint)

        Nnd = mesh.GetNumberOfNodes()
        Nel = mesh.GetNumberOfElements()
        elm = mesh.GetElementTable()
        nNd_elm = np.shape(elm)[1]
        crd = mesh.GetNodeCoordinates()
        dim = ProblemDimension.GetDoF()

        if NumberOfGaussPoint == 0:  # in this case, it is a finite difference mesh
            # we compute the operators directly from the element library
            OP = elmRef.computeOperator(crd, elm)
            Assembly.__saveMatGaussianQuadrature[(
                mesh.GetID(), NumberOfGaussPoint)] = sparse.identity(
                    OP[0][0].shape[0], 'd', format='csr'
                )  #No gaussian quadrature in this case : nodal identity matrix
            Assembly.__savePGtoNodeMatrix[(
                mesh.GetID(), NumberOfGaussPoint
            )] = 1  #no need to translate between pg and nodes because no pg
            Assembly.__saveNodeToPGMatrix[(mesh.GetID(),
                                           NumberOfGaussPoint)] = 1
            Assembly.__saveMatrixChangeOfBasis[mesh.GetID(
            )] = 1  # No change of basis:  MatrixChangeOfBasis = 1
            Assembly.__saveOperator[(
                mesh.GetID(), elementType,
                NumberOfGaussPoint)] = OP  #elmRef.computeOperator(crd,elm)
            return

        elmRefGeom = eval(mesh.GetElementShape())(NumberOfGaussPoint)
        nNd_elm_geom = len(elmRefGeom.xi_nd)
        elm_geom = elm[:, :nNd_elm_geom]

        localFrame = mesh.GetLocalFrame()
        nb_elm_nd = np.bincount(elm_geom.reshape(-1))  #len(nb_elm_nd) = Nnd

        vec_xi = elmRef.xi_pg

        PGtoNode = np.linalg.pinv(
            elmRefGeom.ShapeFunctionPG)  #pseudo-inverse of NodeToPG
        #        PGtoNode = np.linalg.inv(np.dot(elmRef.GeometricalShapeFunctionPG.T , elmRef.GeometricalShapeFunctionPG))
        #        PGtoNode = np.dot(PGtoNode , elmRef.GeometricalShapeFunctionPG.T) #inverse of the NodeToPG matrix (built from the values of the shapeFuctions at PG) based on the least square method

        elmRefGeom.ComputeJacobianMatrix(
            crd[elm_geom], vec_xi, localFrame
        )  #elmRef.JacobianMatrix, elmRef.detJ, elmRef.inverseJacobian
        derivativePG = np.matmul(elmRefGeom.inverseJacobian,
                                 elmRef.ShapeFunctionDerivativePG)

        nb_dir_deriv = derivativePG.shape[-2]
        nop = nb_dir_deriv + 1  #nombre d'opérateur à discrétiser
        if hasattr(elmRef, 'ShapeFunctionSecondDerivativePG'):
            #TODO : only work for beam. Consider revising in the future
            #            secondDerivativePG = np.matmul(elmRefGeom.inverseJacobian , elmRef.ShapeFunctionSecondDerivativePG)
            secondDerivativePG = np.matmul(
                elmRefGeom.inverseJacobian**2,
                elmRef.ShapeFunctionSecondDerivativePG)

            nop += nb_dir_deriv
            computeSecondDerivativeOp = True
        else:
            computeSecondDerivativeOp = False

        NbDoFperNode = np.shape(elmRef.ShapeFunctionPG)[1] // nNd_elm
        if NbDoFperNode > 1:  #for bernoulli beam (of plate in the future)
            AngularDoF = True
        else:
            AngularDoF = False

        range_nbPG = np.arange(NumberOfGaussPoint)

        if Assembly.__GetChangeOfBasisMatrix(mesh) is 1: ChangeOfBasis = False
        else:
            ChangeOfBasis = True
            range_nNd_elm = np.arange(nNd_elm)

        #-------------------------------------------------------------------
        # Assemblage
        #-------------------------------------------------------------------
        gaussianQuadrature = (elmRefGeom.detJ * elmRefGeom.w_pg).T.reshape(-1)

        row = np.empty((Nel, NumberOfGaussPoint, nNd_elm))
        col = np.empty((Nel, NumberOfGaussPoint, nNd_elm))
        col2 = np.empty((Nel, NumberOfGaussPoint, nNd_elm))
        data = [[
            np.empty((Nel, NumberOfGaussPoint, nNd_elm))
            for j in range(NbDoFperNode)
        ] for i in range(nop)]
        dataNodeToPG = np.empty((Nel, NumberOfGaussPoint, nNd_elm_geom))

        row[:] = np.arange(Nel).reshape(
            (-1, 1, 1)) + range_nbPG.reshape(1, -1, 1) * Nel
        col[:] = elm.reshape((Nel, 1, nNd_elm))
        if ChangeOfBasis:
            col2[:] = np.arange(Nel).reshape(
                (-1, 1, 1)) + range_nNd_elm.reshape((1, 1, -1)) * Nel

        dataPGtoNode = PGtoNode.T.reshape(
            (1, NumberOfGaussPoint,
             nNd_elm_geom)) / nb_elm_nd[elm_geom].reshape(
                 (Nel, 1,
                  nNd_elm_geom))  #shape = (Nel, NumberOfGaussPoint, nNd_elm)
        dataNodeToPG[:] = elmRefGeom.ShapeFunctionPG.reshape(
            (1, NumberOfGaussPoint, nNd_elm_geom))
        data[0][0][:] = elmRef.ShapeFunctionPG[:, :nNd_elm].reshape(
            (1, NumberOfGaussPoint, nNd_elm))

        for dir_deriv in range(nb_dir_deriv):
            data[dir_deriv + 1][0][:] = derivativePG[..., dir_deriv, :nNd_elm]
            if computeSecondDerivativeOp:
                data[1 + nb_dir_deriv +
                     dir_deriv][0][:] = secondDerivativePG[...,
                                                           dir_deriv, :nNd_elm]

        if AngularDoF:  #angular dof for C1 elements
            for j in range(1, NbDoFperNode):
                data[0][j][:] = elmRef.ShapeFunctionPG[:, j * nNd_elm:(j + 1) *
                                                       nNd_elm].reshape(
                                                           (1,
                                                            NumberOfGaussPoint,
                                                            nNd_elm))
                for dir_deriv in range(nb_dir_deriv):
                    data[dir_deriv +
                         1][j][:] = derivativePG[..., dir_deriv,
                                                 j * nNd_elm:(j + 1) * nNd_elm]
                    if computeSecondDerivativeOp:
                        data[1 + nb_dir_deriv +
                             dir_deriv][j][:] = secondDerivativePG[
                                 ..., dir_deriv, j * nNd_elm:(j + 1) * nNd_elm]

        row_geom = np.reshape(row[..., :nNd_elm_geom], -1)
        col_geom = np.reshape(col[..., :nNd_elm_geom], -1)
        row = np.reshape(row, -1)
        col = np.reshape(col, -1)
        col2 = np.reshape(col2, -1)

        if ChangeOfBasis: Ncol = Nel * nNd_elm
        else:
            Ncol = Nnd
            col2 = col

        op_dd = [[
            sparse.coo_matrix((data[i][j].reshape(-1), (row, col2)),
                              shape=(Nel * NumberOfGaussPoint, Ncol)).tocsr()
            for j in range(NbDoFperNode)
        ] for i in range(nop)]

        #        data = [sparse.diags(gaussianQuadrature, 0, format='csr')] #matrix to get the gaussian quadrature (integration over each element)
        Assembly.__saveMatGaussianQuadrature[(mesh.GetID(
        ), NumberOfGaussPoint)] = sparse.diags(
            gaussianQuadrature, 0, format='csr'
        )  #matrix to get the gaussian quadrature (integration over each element)
        #matrix to compute the node values from pg
        #        data.extend([sparse.coo_matrix((sp.reshape(dataPGtoNode,-1),(col,row)), shape=(Nel * nNd_elm , Nel*NumberOfGaussPoint) )])
        Assembly.__savePGtoNodeMatrix[(mesh.GetID(
        ), NumberOfGaussPoint)] = sparse.coo_matrix(
            (dataPGtoNode.reshape(-1), (col_geom, row_geom)),
            shape=(Nnd, Nel * NumberOfGaussPoint)
        ).tocsr(
        )  #matrix to compute the node values from pg using the geometrical shape functions
        #matrix to compute the pg values from nodes using the geometrical shape functions (no angular dof)
        Assembly.__saveNodeToPGMatrix[(mesh.GetID(
        ), NumberOfGaussPoint)] = sparse.coo_matrix(
            (sp.reshape(dataNodeToPG, -1), (row_geom, col_geom)),
            shape=(Nel * NumberOfGaussPoint, Nnd)
        ).tocsr(
        )  #matrix to compute the pg values from nodes using the geometrical shape functions (no angular dof)

        data = {0: op_dd[0]}  #data is a dictionnary
        for i in range(nb_dir_deriv):
            data[1, i] = op_dd[i + 1]
            if computeSecondDerivativeOp:
                data[2, i] = op_dd[i + 1 + nb_dir_deriv]
        Assembly.__saveOperator[(mesh.GetID(), elementType,
                                 NumberOfGaussPoint)] = data