def GetLocalTraction(self, function_space, material, LagrangeElemCoords, EulerElemCoords, fem_solver, elem=0): """Get traction vector of the system""" nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss # ALLOCATE tractionforce = np.zeros((nodeperelem*nvar,1),dtype=np.float64) B = np.zeros((nodeperelem*nvar,material.H_VoigtSize),dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerElemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil',Jm, EulerElemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj',inv(ParentGradientx),Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX)),np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj',MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX))) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # COMPUTE CAUCHY STRESS TENSOR CauchyStressTensor = [] if fem_solver.requires_geometry_update: CauchyStressTensor = material.CauchyStress(StrainTensors,None,elem,counter) # COMPUTE THE TANGENT STIFFNESS MATRIX t = self.TractionIntegrand(B, SpatialGradient[counter,:,:], CauchyStressTensor, requires_geometry_update=fem_solver.requires_geometry_update) if fem_solver.requires_geometry_update: # INTEGRATE TRACTION FORCE tractionforce += t*detJ[counter] return tractionforce
def GetLinearMomentum(self, function_space, material, LagrangeElemCoords, EulerELemCoords, VelocityElem, fem_solver, elem=0): """Get linear momentum or virtual power of the system. For dynamic analysis this is handy for computing conservation of linear momentum. The routine computes the global form of virtual power i.e. integral of "P:Grad_0(V)"" where P is first Piola-Kirchhoff stress tensor and Grad_0(V) is the material gradient of velocity. Alternatively in update Lagrangian format this could be computed using "Sigma: Grad(V) J" where Sigma is the Cauchy stress tensor and Grad(V) is the spatial gradient of velocity. The latter approach is followed here """ nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss internal_power = 0. # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # TIME DERIVATIVE OF F Fdot = np.einsum('ij,kli->kjl', VelocityElem, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil', Jm, EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj', inv(ParentGradientx), Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX)), np.abs(StrainTensors['J'])) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): GradV = np.dot(Fdot[counter, :, :], np.linalg.inv(F[counter, :, :])) # COMPUTE CAUCHY CauchyStressTensor = material.CauchyStress(StrainTensors, None, elem, counter) # INTEGRATE INTERNAL VIRTUAL POWER internal_power += np.einsum('ij,ij', CauchyStressTensor, GradV) * detJ[counter] return internal_power
def GetEnergy(self, function_space, material, LagrangeElemCoords, EulerELemCoords, ElectricPotentialElem, fem_solver, elem=0): """Get virtual energy of the system. For dynamic analysis this is handy for computing conservation of energy. The routine computes the global form of virtual internal energy i.e. integral of "W(C,G,C)"". This can be computed purely in a Lagrangian configuration. """ nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss internal_energy = 0. # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj',MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX))) # GET ELECTRIC FIELD ElectricFieldx = - np.einsum('ijk,j',SpatialGradient,ElectricPotentialElem) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): if material.energy_type == "enthalpy": # COMPUTE THE INTERNAL ENERGY AT THIS GAUSS POINT energy = material.InternalEnergy(StrainTensors,ElectricFieldx[counter,:],0,elem,counter) elif material.energy_type == "internal_energy": # COMPUTE ELECTRIC DISPLACEMENT IMPLICITLY ElectricDisplacementx = material.ElectricDisplacementx(StrainTensors, ElectricFieldx[counter,:], elem, counter) # COMPUTE THE INTERNAL ENERGY AT THIS GAUSS POINT energy = material.InternalEnergy(StrainTensors,ElectricDisplacementx[counter,:],elem,counter) # INTEGRATE INTERNAL ENERGY internal_energy += energy*detJ[counter] return internal_energy
def GetEnergy(self, function_space, material, LagrangeElemCoords, EulerELemCoords, fem_solver, elem=0): """Get virtual energy of the system. For dynamic analysis this is handy for computing conservation of energy. The routine computes the global form of virtual internal energy i.e. integral of "W(C,G,C)"". This can be computed purely in a Lagrangian configuration. """ nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss internal_energy = 0. # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil', Jm, EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj', inv(ParentGradientx), Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX)), np.abs(StrainTensors['J'])) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # COMPUTE THE INTERNAL ENERGY AT THIS GAUSS POINT energy = material.InternalEnergy(StrainTensors, elem, counter) # INTEGRATE INTERNAL ENERGY internal_energy += energy * detJ[counter] return internal_energy
def K_ww(self, material, fem_solver, Eulerw, Eulerp=None, elem=0): """Get stiffness matrix of the system""" meshes = self.meshes mesh = self.meshes[1] function_spaces = self.function_spaces function_space = self.function_spaces[1] ndim = self.ndim nvar = ndim nodeperelem = meshes[1].elements.shape[1] # GET THE FIELDS AT THE ELEMENT LEVEL LagrangeElemCoords = mesh.points[mesh.elements[elem,:],:] EulerELemCoords = Eulerw[mesh.elements[elem,:],:] Jm = function_spaces[1].Jm AllGauss = function_space.AllGauss # # GET LOCAL KINEMATICS # SpatialGradient, F, detJ = _KinematicMeasures_(Jm, AllGauss[:,0], # LagrangeElemCoords, EulerELemCoords, fem_solver.requires_geometry_update) # # COMPUTE WORK-CONJUGATES AND HESSIAN AT THIS GAUSS POINT # CauchyStressTensor, _, H_Voigt = material.KineticMeasures(F,elem=elem) # ALLOCATE stiffness = np.zeros((nodeperelem*nvar,nodeperelem*nvar),dtype=np.float64) tractionforce = np.zeros((nodeperelem*nvar,1),dtype=np.float64) B = np.zeros((nodeperelem*nvar,material.gradient_elasticity_tensor_size),dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil',Jm,EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj',inv(ParentGradientx),Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX)),np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj',MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX))) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # COMPUTE THE HESSIAN AT THIS GAUSS POINT material.Hessian(StrainTensors,None, elem, counter) H_Voigt = material.gradient_elasticity_tensor # COMPUTE CAUCHY STRESS TENSOR CoupleStressVector = [] if fem_solver.requires_geometry_update: CoupleStressVector = material.CoupleStress(StrainTensors,None,elem,counter).reshape(self.ndim,1) # COMPUTE THE TANGENT STIFFNESS MATRIX BDB_1, t = self.K_ww_Integrand(B, SpatialGradient[counter,:,:], None, CoupleStressVector, H_Voigt, analysis_nature=fem_solver.analysis_nature, has_prestress=fem_solver.has_prestress) # COMPUTE GEOMETRIC STIFFNESS MATRIX if fem_solver.requires_geometry_update: # INTEGRATE TRACTION FORCE tractionforce += t*detJ[counter] # INTEGRATE STIFFNESS stiffness += BDB_1*detJ[counter] # # SAVE AT THIS GAUSS POINT # self.SpatialGradient = SpatialGradient # self.detJ = detJ return stiffness, tractionforce
def GetLocalStiffness(self, function_space, material, VolumesX, Volumesx, LagrangeElemCoords, EulerELemCoords, fem_solver, elem=0): """Compute stiffness matrix of an element""" nvar = self.nvar ndim = self.ndim Domain = function_space det = np.linalg.det inv = np.linalg.inv Jm = Domain.Jm AllGauss = Domain.AllGauss material.kappa = material.lamb + 2.0 * material.mu / 3.0 material.pressure = (Volumesx - VolumesX) / VolumesX # ALLOCATE stiffness = np.zeros( (Domain.Bases.shape[0] * nvar, Domain.Bases.shape[0] * nvar), dtype=np.float64) stiffness_XP = np.zeros(Domain.Bases.shape[0] * nvar, dtype=np.float64) stiffness_JJ = 0 tractionforce = np.zeros((Domain.Bases.shape[0] * nvar, 1), dtype=np.float64) B = np.zeros((Domain.Bases.shape[0] * nvar, material.H_VoigtSize), dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # COFACTOR OF DEFORMATION GRADIENT TENSOR H = np.einsum('ijk,k->ijk', np.linalg.inv(F).T, StrainTensors['J']) # COMPUTE H:\nabla_{\delta\vec{v}} - TRANSPOSE IS NECESSARY TO FORCE F-CONTIGUOUS B_XP = np.einsum('ijk,kjl->il', H, MaterialGradient).T.ravel() # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil', Domain.Jm, EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj', inv(ParentGradientx), Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX)), np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj', MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX))) # print(MaterialGradient.shape) # exit() stiffness_x = np.zeros((12, 12)) dN = np.zeros((6, 2)) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # for a in range(6): # for b in range(6): # dNa = SpatialGradient[counter,a,:] # dNb = SpatialGradient[counter,b,:] # stiffness_x[2*a:2*(a+1),2*b:2*(b+1)] += dNa[:,None].dot(dNb[None,:])*detJ[counter] dN[:] += 1. / Volumesx[elem] * SpatialGradient[ counter, :, :] * detJ[counter] # COMPUTE THE HESSIAN AT THIS GAUSS POINT H_Voigt = material.Hessian(StrainTensors, None, elem, counter) # COMPUTE CAUCHY STRESS TENSOR CauchyStressTensor = [] if fem_solver.requires_geometry_update: CauchyStressTensor = material.CauchyStress( StrainTensors, None, elem, counter) # COMPUTE THE TANGENT STIFFNESS MATRIX BDB_1, t = self.ConstitutiveStiffnessIntegrand( B, SpatialGradient[counter, :, :], CauchyStressTensor, H_Voigt, analysis_nature=fem_solver.analysis_nature, has_prestress=fem_solver.has_prestress) # COMPUTE GEOMETRIC STIFFNESS MATRIX if fem_solver.requires_geometry_update: BDB_1 += self.GeometricStiffnessIntegrand( SpatialGradient[counter, :, :], CauchyStressTensor) # INTEGRATE TRACTION FORCE tractionforce += t * detJ[counter] # INTEGRATE STIFFNESS stiffness += BDB_1 * detJ[counter] # K_JP, K_PJ # detJ_XP = np.einsum('i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX))) # stiffness_XP[:] = B_XP*detJ_XP[counter] # K_JJ # stiffness_JJ += detJ_XP[counter] # stiffness_JP = np.copy(stiffness_JJ) # stiffness_JJ *= material.kappa # b1 = np.concatenate((stiffness,np.zeros((12,1)),stiffness_XP[:,None]),axis=1) # b2 = np.concatenate((np.zeros((1,12)),stiffness_XP[:,None].T),axis=0) # b3 = np.array([[stiffness_JJ, - stiffness_JP], [-stiffness_JP, 0]]) # b4 = np.concatenate((b2,b3),axis=1) # bf = np.concatenate((b1,b4),axis=0) # stiffness = bf # stiffness = stiffness+stiffness_x*material.kappa/VolumesX[elem] # print dN[0,:,None].dot(dN[0,:,None].T) # exit() for a in range(6): for b in range(6): stiffness_x[2 * a:2 * (a + 1), 2 * b:2 * (b + 1)] += dN[a, :, None].dot(dN[b, :, None].T) kappa_bar = material.kappa * Volumesx[elem] / VolumesX[elem] stiffness_x *= (kappa_bar * Volumesx[elem]) stiffness = stiffness + stiffness_x return stiffness, tractionforce
def GetLocalStiffness(self, function_space, material, LagrangeElemCoords, EulerElemCoords, fem_solver, elem=0): """Get stiffness matrix of the system""" nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss # ALLOCATE stiffness = np.zeros((nodeperelem * nvar, nodeperelem * nvar), dtype=np.float64) tractionforce = np.zeros((nodeperelem * nvar, 1), dtype=np.float64) B = np.zeros((nodeperelem * nvar, material.H_VoigtSize), dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # ParentGradientX = [np.eye(3,3)] # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerElemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj', MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i', AllGauss[:, 0], det(ParentGradientX)) # detJ = np.einsum('i,i,i->i', AllGauss[:,0], det(ParentGradientX), StrainTensors['J']) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # COMPUTE THE HESSIAN AT THIS GAUSS POINT H_Voigt = material.Hessian(StrainTensors, None, elem, counter) # COMPUTE CAUCHY STRESS TENSOR CauchyStressTensor = [] if fem_solver.requires_geometry_update: CauchyStressTensor = material.CauchyStress( StrainTensors, None, elem, counter) # COMPUTE THE TANGENT STIFFNESS MATRIX BDB_1, t = self.ConstitutiveStiffnessIntegrand( B, SpatialGradient[counter, :, :], StrainTensors['F'][counter], CauchyStressTensor, H_Voigt, requires_geometry_update=fem_solver.requires_geometry_update) # INTEGRATE TRACTION FORCE if fem_solver.requires_geometry_update: tractionforce += t * detJ[counter] # INTEGRATE STIFFNESS stiffness += BDB_1 * detJ[counter] makezero(stiffness, 1e-12) # print(stiffness) # print(tractionforce) # exit() return stiffness, tractionforce
def GetLocalTraction(self, function_space, material, LagrangeElemCoords, EulerELemCoords, ElectricPotentialElem, fem_solver, elem=0): """Get traction vector of the system""" nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss # ALLOCATE tractionforce = np.zeros((nodeperelem * nvar, 1), dtype=np.float64) B = np.zeros((nodeperelem * nvar, material.H_VoigtSize), dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil', Jm, EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj', inv(ParentGradientx), Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX)), np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj', MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX))) # GET ELECTRIC FIELD ElectricFieldx = -np.einsum('ijk,j', SpatialGradient, ElectricPotentialElem) # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): if material.energy_type == "enthalpy": # COMPUTE ELECTRIC DISPLACEMENT ElectricDisplacementx = material.ElectricDisplacementx( StrainTensors, ElectricFieldx[counter, :], elem, counter) elif material.energy_type == "internal_energy": # THIS REQUIRES LEGENDRE TRANSFORM # COMPUTE ELECTRIC DISPLACEMENT IMPLICITLY ElectricDisplacementx = material.ElectricDisplacementx( StrainTensors, ElectricFieldx[counter, :], elem, counter) # COMPUTE THE TANGENT STIFFNESS MATRIX t = self.TractionIntegrand( B, SpatialGradient[counter, :, :], ElectricDisplacementx, analysis_nature=fem_solver.analysis_nature, has_prestress=fem_solver.has_prestress) # INTEGRATE TRACTION FORCE tractionforce += t * detJ[counter] return tractionforce
def ComputeErrorNorms(MainData,mesh,nmesh,AnalyticalSolution,Domain,Quadrature,MaterialArgs): # AT THE MOMENT THE ERROR NORMS ARE COMPUTED FOR LINEAR PROBLEMS ONLY if MainData.GeometryUpdate: raise ValueError('The error norms are computed for linear problems only.') # INITIATE/ALLOCATE C = MainData.C ndim = MainData.ndim nvar = MainData.nvar elements = nmesh.elements points = nmesh.points nelem = elements.shape[0] nodeperelem = elements.shape[1] w = Quadrature.weights # TotalDisp & TotalPot ARE BOTH THIRD ORDER TENSOR (3RD DIMENSION FOR INCREMENTS) - TRANCATE THEM UNLESS REQUIRED TotalDisp = MainData.TotalDisp[:,:,-1] TotalPot = MainData.TotalPot[:,:,-1] # # print TotalDisp # TotalDispa = np.zeros(TotalDisp.shape) # uxa = (points[:,1]*np.cos(points[:,0])); uxa=np.zeros(uxa.shape) # uya = (points[:,0]*np.sin(points[:,1])) # TotalDispa[:,0]=uxa # TotalDispa[:,1]=uya # # print TotalDispa # # print TotalDisp # print np.concatenate((TotalDispa,TotalDisp),axis=1) # # print points # ALLOCATE B = np.zeros((Domain.Bases.shape[0]*nvar,MaterialArgs.H_VoigtSize)) E_nom = 0; E_denom = 0; L2_nom = 0; L2_denom = 0 # LOOP OVER ELEMENTS for elem in range(0,nelem): xycoord = points[elements[elem,:],:] # GET THE NUMERICAL SOLUTION WITHIN THE ELEMENT (AT NODES) ElementalSol = np.zeros((nodeperelem,nvar)) ElementalSol[:,:ndim] = TotalDisp[elements[elem,:],:] ElementalSol[:,ndim] = TotalPot[elements[elem,:],:].reshape(nodeperelem) # GET THE ANALYTICAL SOLUTION WITHIN THE ELEMENT (AT NODES) AnalyticalSolution.Args.node = xycoord AnalyticalSol = AnalyticalSolution().Get(AnalyticalSolution.Args) # AnalyticalSol[:,0] = ElementalSol[:,0] # print np.concatenate((AnalyticalSol[:,:2], ElementalSol[:,:2]),axis=1) # print # print points # print points[elements[elem,:],:] # print AnalyticalSol # ALLOCATE nvarBasis = np.zeros((Domain.Bases.shape[0],nvar)) ElementalSolGauss = np.zeros((Domain.AllGauss.shape[0],nvar)); AnalyticalSolGauss = np.copy(ElementalSolGauss) dElementalSolGauss = np.zeros((Domain.AllGauss.shape[0],nvar)); dAnalyticalSolGauss = np.copy(ElementalSolGauss) # LOOP OVER GAUSS POINTS for counter in range(0,Domain.AllGauss.shape[0]): # GET THE NUMERICAL SOLUTION WITHIN THE ELEMENT (AT QUADRATURE POINTS) ElementalSolGauss[counter,:] = np.dot(Domain.Bases[:,counter].reshape(1,nodeperelem),ElementalSol) # GET THE ANALYTICAL SOLUTION WITHIN THE ELEMENT (AT QUADRATURE POINTS) AnalyticalSolution.Args.node = np.dot(Domain.Bases[:,counter],xycoord) AnalyticalSolGauss[counter,:] = AnalyticalSolution().Get(AnalyticalSolution.Args) # print AnalyticalSolGauss, ElementalSolGauss[:,0] # AnalyticalSolGauss[:,0] = ElementalSolGauss[:,0] # REMOVE # AnalyticalSolGauss[:,1] = ElementalSolGauss[:,1] # REMOVE # print np.concatenate((AnalyticalSolGauss[:,:2], ElementalSolGauss[:,:2]),axis=1)#, AnalyticalSolution.Args.node # print # GRADIENT TENSOR IN PARENT ELEMENT [\nabla_\varepsilon (N)] Jm = Domain.Jm[:,:,counter] # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX=np.dot(Jm,xycoord) # # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.dot(la.inv(ParentGradientX),Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] # F = np.dot(EulerELemCoords.T,MaterialGradient.T) F = np.eye(ndim,ndim) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F).Compute() # UPDATE/NO-UPDATE GEOMETRY if MainData.GeometryUpdate: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx=np.dot(Jm,EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.dot(la.inv(ParentGradientx),Jm).T else: SpatialGradient = MaterialGradient.T # SPATIAL ELECTRIC FIELD ElectricFieldx = - np.dot(SpatialGradient.T,ElementalSol[:,ndim]) # COMPUTE SPATIAL ELECTRIC DISPLACEMENT ElectricDisplacementx = MainData.ElectricDisplacementx(MaterialArgs,StrainTensors,ElectricFieldx) # COMPUTE CAUCHY STRESS TENSOR CauchyStressTensor = MainData.CauchyStress(MaterialArgs,StrainTensors,ElectricFieldx) # COMPUTE THE HESSIAN AT THIS GAUSS POINT H_Voigt = MainData.Hessian(MaterialArgs,ndim,StrainTensors,ElectricFieldx) # COMPUTE THE TANGENT STIFFNESS MATRIX BDB_1, t = MainData().ConstitutiveStiffnessIntegrand(Domain,B,MaterialGradient,nvar,SpatialGradient, ndim,CauchyStressTensor,ElectricDisplacementx,MaterialArgs,H_Voigt) # L2 NORM L2_nom += np.linalg.norm((AnalyticalSolGauss - ElementalSolGauss)**2)*Domain.AllGauss[counter,0] L2_denom += np.linalg.norm((AnalyticalSolGauss)**2)*Domain.AllGauss[counter,0] # ENERGY NORM DiffSol = (AnalyticalSol - ElementalSol).reshape(ElementalSol.shape[0]*ElementalSol.shape[1],1) E_nom += np.linalg.norm(DiffSol**2)*Domain.AllGauss[counter,0] E_denom += np.linalg.norm(AnalyticalSol.reshape(AnalyticalSol.shape[0]*AnalyticalSol.shape[1],1)**2)*Domain.AllGauss[counter,0] L2Norm = np.sqrt(L2_nom)/np.sqrt(L2_denom) EnergyNorm = np.sqrt(E_nom)/np.sqrt(E_denom) print(L2Norm, EnergyNorm) return L2Norm, EnergyNorm
def GetLocalStiffness(self, function_space, material, LagrangeElemCoords, EulerELemCoords, fem_solver, elem=0): """Get stiffness matrix of the system""" nvar = self.nvar ndim = self.ndim nodeperelem = function_space.Bases.shape[0] det = np.linalg.det inv = np.linalg.inv Jm = function_space.Jm AllGauss = function_space.AllGauss # ALLOCATE stiffness = np.zeros((nodeperelem * nvar, nodeperelem * nvar), dtype=np.float64) tractionforce = np.zeros((nodeperelem * nvar, 1), dtype=np.float64) B = np.zeros((nodeperelem * nvar, material.H_VoigtSize), dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil', Jm, EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj', inv(ParentGradientx), Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX)), np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj', MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX))) # COMPUTE PARAMETERS FOR MEAN DILATATION METHOD, IT NEEDS TO BE BEFORE COMPUTE HESSIAN AND STRESS if material.is_nearly_incompressible: dV = np.einsum('i,i->i', AllGauss[:, 0], np.abs(det(ParentGradientX))) stiffness_k = self.VolumetricStiffnessIntegrand( material, SpatialGradient, detJ, dV) stiffness += stiffness_k # LOOP OVER GAUSS POINTS for counter in range(AllGauss.shape[0]): # COMPUTE THE HESSIAN AT THIS GAUSS POINT H_Voigt = material.Hessian(StrainTensors, None, elem, counter) # COMPUTE CAUCHY STRESS TENSOR CauchyStressTensor = [] if fem_solver.requires_geometry_update: CauchyStressTensor = material.CauchyStress( StrainTensors, None, elem, counter) # COMPUTE THE TANGENT STIFFNESS MATRIX BDB_1, t = self.ConstitutiveStiffnessIntegrand( B, SpatialGradient[counter, :, :], CauchyStressTensor, H_Voigt, requires_geometry_update=fem_solver.requires_geometry_update) # COMPUTE GEOMETRIC STIFFNESS MATRIX if material.nature != "linear": BDB_1 += self.GeometricStiffnessIntegrand( SpatialGradient[counter, :, :], CauchyStressTensor) # INTEGRATE TRACTION FORCE if fem_solver.requires_geometry_update: tractionforce += t * detJ[counter] # INTEGRATE STIFFNESS stiffness += BDB_1 * detJ[counter] return stiffness, tractionforce
AllGauss = function_space.AllGauss # ALLOCATE tractionforce = np.zeros((nodeperelem*nvar,1),dtype=np.float64) B = np.zeros((nodeperelem*nvar,material.H_VoigtSize),dtype=np.float64) # COMPUTE KINEMATIC MEASURES AT ALL INTEGRATION POINTS USING EINSUM (AVOIDING THE FOR LOOP) # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientX = np.einsum('ijk,jl->kil', Jm, LagrangeElemCoords) # MATERIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla_0 (N)] MaterialGradient = np.einsum('ijk,kli->ijl', inv(ParentGradientX), Jm) # DEFORMATION GRADIENT TENSOR [\vec{x} \otimes \nabla_0 (N)] F = np.einsum('ij,kli->kjl', EulerELemCoords, MaterialGradient) # COMPUTE REMAINING KINEMATIC MEASURES StrainTensors = KinematicMeasures(F, fem_solver.analysis_nature) # UPDATE/NO-UPDATE GEOMETRY if fem_solver.requires_geometry_update: # MAPPING TENSOR [\partial\vec{X}/ \partial\vec{\varepsilon} (ndim x ndim)] ParentGradientx = np.einsum('ijk,jl->kil',Jm,EulerELemCoords) # SPATIAL GRADIENT TENSOR IN PHYSICAL ELEMENT [\nabla (N)] SpatialGradient = np.einsum('ijk,kli->ilj',inv(ParentGradientx),Jm) # COMPUTE ONCE detJ (GOOD SPEEDUP COMPARED TO COMPUTING TWICE) detJ = np.einsum('i,i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX)),np.abs(StrainTensors['J'])) else: # SPATIAL GRADIENT AND MATERIAL GRADIENT TENSORS ARE EQUAL SpatialGradient = np.einsum('ikj',MaterialGradient) # COMPUTE ONCE detJ detJ = np.einsum('i,i->i',AllGauss[:,0],np.abs(det(ParentGradientX)))