Two inclusions mechanical analysis

Here we present a study case of a thick plate with 2 inclusions. One softer and the other stiffer than the base material. Then we compute the energy deformation on one inclusion.

Includes

[1]:
from Muscat.FE.UnstructuredFeaSym import UnstructuredFeaSym
from Muscat.FE.KR.KRBlock import KRBlockVector
from Muscat.IO.GmshReader import ReadGmsh
from Muscat.FE.Fields.FieldTools import GetPointRepresentation
from Muscat.FE.Fields.FEField import FEField
from Muscat.FE.SymPhysics import MecaPhysics
import Muscat.FE.SymWeakForm as SWF
from Muscat.FE.MaterialHelp import HookeIso
from Muscat.Containers.Filters.FilterObjects import ElementFilter
from Muscat.FE.DofNumbering import  ComputeDofNumbering
from Muscat.FE.Spaces.FESpaces import LagrangeSpaceP0
from Muscat.FE.Integration import IntegrateGeneral
from Muscat.IO.XdmfWriter import XdmfWriter
from Muscat.Containers.MeshInspectionTools import ExtractElementsByElementFilter
from Muscat.FE.Fields.FieldTools import VectorToFEFieldsData
from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory

import numpy as np
import pyvista
pyvista.global_theme._jupyter_backend = 'panel' # remove this line to get interactive 3D plots

import pathlib

Unstructured FEA with mechanical

[2]:
problem = UnstructuredFeaSym()

# the mecanical problem
mecaPhysics = MecaPhysics()

# Definition of the degree of the spaces [1 or 2]
mecaPhysics.SetSpaceToLagrange(P=1)

# add weak form terms to the tanget matrix
youngModulusInclusionBase = 1.0
mecaPhysics.AddBFormulation( "Bulk",mecaPhysics.GetBulkFormulation(youngModulusInclusionBase,0.3)  )
mecaPhysics.AddBFormulation( "Inclusion1",mecaPhysics.GetBulkFormulation(5*youngModulusInclusionBase,0.3)  )
youngModulusInclusionII = youngModulusInclusionBase/2
mecaPhysics.AddBFormulation( "Inclusion2",mecaPhysics.GetBulkFormulation(youngModulusInclusionII,0.3)  )

# add weak form term to the rhs
mecaPhysics.AddLFormulation( "Right", mecaPhysics.GetForceFormulation([1,0,0],1)  )
problem.physics.append(mecaPhysics)

Boundary conditions

[3]:
# the boundary conditions
dirichlet = KRBlockVector()
dirichlet.AddArg("u").On('Left').Fix0().Fix1().Fix2().To()

problem.solver.constraints.AddConstraint(dirichlet)

Numerical part (mesh)

[4]:
# Read The mesh

mesh = ReadGmsh(pathlib.Path("").resolve() / pathlib.Path("TwoInclusions.msh"))
problem.SetMesh(mesh)

print(mesh)
Mesh
  Number Of Nodes    : 6750
    Tags :
  Number Of Elements : 29129
    ElementsContainer,   Type : (ElementType.Tetrahedron_4,28889),   Tags : (Bulk:17170) (GeoTag1:17170) (Inclusion1:4348) (GeoTag2:4348) (Inclusion2:7371) (GeoTag3:7371)
    ElementsContainer,   Type : (ElementType.Triangle_3,240),   Tags : (Right:120) (GeoTag33:120) (Left:120) (GeoTag41:120)

Resolution

[5]:
# we compute the numbering (maping from the mesh to the linear system)
problem.ComputeDofNumbering()

from Muscat.Helpers.Timer import Timer
with Timer("Assembly "):
    k,f = problem.GetLinearProblem()

#compute the constraints to add to the system
problem.ComputeConstraintsEquations()


with Timer("Solve"):
    problem.Solve(k,f)

problem.PushSolutionVectorToUnknownFields()

# Recover a point representation of the displacement
mesh.nodeFields["sol"] = GetPointRepresentation(problem.unknownFields)
print(mesh)
Mesh
  Number Of Nodes    : 6750
    Tags :
  Number Of Elements : 29129
    ElementsContainer,   Type : (ElementType.Tetrahedron_4,28889),   Tags : (Bulk:17170) (GeoTag1:17170) (Inclusion1:4348) (GeoTag2:4348) (Inclusion2:7371) (GeoTag3:7371)
    ElementsContainer,   Type : (ElementType.Triangle_3,240),   Tags : (Right:120) (GeoTag33:120) (Left:120) (GeoTag41:120)
  nodeFields         : ['sol']

Post Processing

[6]:
#Creation of a fake fields to export the rhs member
rhsFields = [ FEField(mesh=mesh,space=None,numbering=problem.numberings[i]) for i in range(3) ]
VectorToFEFieldsData(f,rhsFields)
problem.mesh.nodeFields["RHS"] = GetPointRepresentation(rhsFields)

Compute of the strain energy only on the second inclusion (integral in each element)

[7]:
symdep = SWF.GetField("u",3)
K = HookeIso(youngModulusInclusionII,0.3,dim=3)
symCellData = SWF.GetField("cellData",1)
symCellDataT = SWF.GetTestField("cellData",1)

print("Post process")

EnerForm = SWF.ToVoigtEpsilon(SWF.Strain(symdep)).T*K*SWF.ToVoigtEpsilon(SWF.Strain(symdep))*symCellDataT

print("Post process Eval")
ff = ElementFilter(eTag="Inclusion2")

p0Numbering = ComputeDofNumbering(mesh,LagrangeSpaceP0)

energyDensityField = FEField(name="cellData",mesh=problem.mesh,numbering=p0Numbering,space=LagrangeSpaceP0)

m,energyDensity = IntegrateGeneral(mesh=problem.mesh, wform=EnerForm,  constants={},
                        fields=problem.unknownFields, unknownFields = [ energyDensityField ], elementFilter=ff)
print("energyDensity",energyDensity)
energyDensityField.data = energyDensity

problem.mesh.elemFields["Energy"] = energyDensity
print("Strain energy on the second inclusion:", np.sum(energyDensity) )
Post process
Post process Eval
energyDensity [0. 0. 0. ... 0. 0. 0.]
Strain energy on the second inclusion: 0.0777788948445724

Graphical Output

[8]:
# generate a element field with un index per material
mesh.elemFields["inclussions"]  = np.zeros(mesh.GetNumberOfElements())
for i, name in enumerate(("Inclusion1","Inclusion2")):
    for selection in ElementFilter(eTag=name)(mesh):
        mesh.elemFields["inclussions"][selection.GetMeshSlice()]= 1 + i

import pyvista as pv
from Muscat.Bridges.PyVistaBridge import MeshToPyVista

plotter = pv.Plotter(shape=(2, 2))

camera = [(1.4464393507963245, 1.760895123462273, 2.9110300316336843),
 (-0.22723828652575934, -0.08454810909441325, 0.21480857439407788),
 (-0.25495941474725625, 0.8643967380870753, -0.43337509851877826)]

plotter.subplot(0, 0)
plotter.add_text("Two Inclusions", font_size=10)
plotter.add_mesh(MeshToPyVista(mesh), scalars="inclussions", show_edges=True, show_scalar_bar=False, edge_color="grey", cmap="rainbow_r")
plotter.camera_position = camera

plotter.subplot(0, 1)
plotter.add_text("Deformation", font_size=10)
deformedMesh = mesh.View()
deformedMesh.nodes = mesh.nodes + problem.mesh.nodeFields["sol"]*.3
deformedMesh.nodeFields["sol"] = problem.mesh.nodeFields["sol"]
plotter.add_mesh(MeshToPyVista(deformedMesh), scalars="sol", show_edges=False, show_scalar_bar=False, cmap="coolwarm_r")
plotter.camera_position = camera
rightMesh = ExtractElementsByElementFilter(deformedMesh,ElementFilter(eTag="Right"))
rightMesh.nodeFields = deformedMesh.nodeFields
glyphs = MeshToPyVista(rightMesh).glyph(orient="RHS", scale="RHS", factor=10, geom=pv.Arrow())
plotter.add_mesh(glyphs, show_scalar_bar=False)

plotter.subplot(1, 0)
plotter.add_text("Inclusion 2 energy dencity", font_size=10)
plotter.add_mesh(MeshToPyVista(ExtractElementsByElementFilter(mesh,ElementFilter(eTag="Bulk")) ).extract_feature_edges(45) )
in1Mesh = ExtractElementsByElementFilter(mesh,ElementFilter(eTag="Inclusion2"))
in1Mesh.elemFields["Energy"] = mesh.elemFields["Energy"][in1Mesh.GetElementsOriginalIDs()]
plotter.add_mesh(MeshToPyVista(in1Mesh), scalars="Energy", style="surface" , cmap="coolwarm" )
plotter.camera_position = camera

plotter.subplot(1, 1)
plotter.add_text("Inclusion deformation", font_size=10)
deformedMesh = mesh.View()
deformedMesh.nodes = mesh.nodes + problem.mesh.nodeFields["sol"]*.3
buldkDeformedMesh = ExtractElementsByElementFilter(deformedMesh,ElementFilter(eTag="Bulk"))
buldkDeformedMesh.nodeFields["sol"] = problem.mesh.nodeFields["sol"]
plotter.add_mesh(MeshToPyVista(buldkDeformedMesh).extract_feature_edges(45),scalars="sol", show_edges=False, show_scalar_bar=False)
in1Mesh.nodes = mesh.nodes + problem.mesh.nodeFields["sol"]*.3
plotter.add_mesh(MeshToPyVista(in1Mesh), scalars="Energy", style="surface" , cmap="coolwarm" )
plotter.add_mesh(glyphs)
plotter.camera_position = camera

plotter.show()
../_images/notebooks_TwoInclusions_17_0.png

Export data to file

[9]:
# To visualize this xdmf file you can use ParaView (downloadable from https://www.paraview.org/)
writer = XdmfWriter(TemporaryDirectory.GetTempPath() + 'TwoInclusions_Output.xdmf')
writer.SetHdf5(False)
writer.Open()
writer.Write(mesh,PointFields=list(mesh.nodeFields.values()), PointFieldsNames=list(mesh.nodeFields.keys()),
                CellFields=list(mesh.elemFields.values()), CellFieldsNames=list(mesh.elemFields.keys()))
writer.Close()