Homog4#

Conduct 3d homogenization on a simple RVE.

Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
C_hom =
 6.776e+00  4.564e+00  4.385e+00  1.272e-16  1.533e-17  1.990e-06
 4.564e+00  6.776e+00  4.385e+00  1.749e-15  8.502e-16 -6.731e-06
 4.385e+00  4.385e+00  2.400e+01  3.387e-16 -1.336e-16 -1.367e-06
 1.799e-17  8.317e-17  2.500e-14  1.569e+00 -8.944e-08  1.886e-17
-2.614e-16 -2.488e-17  1.151e-15 -8.944e-08  1.569e+00  5.839e-17
 1.990e-06 -6.731e-06 -1.367e-06 -7.757e-16 -6.912e-15  1.262e+00

 13 import matplotlib.pyplot as plt
 14 import numpy as np
 15
 16 from EasyFEA import Display, Models, Mesh, ElemType, Simulations, PyVista
 17 from EasyFEA.Geoms import Points, Circle
 18 from EasyFEA.FEM import LagrangeCondition, FeArray
 19 from typing import Optional
 20
 21
 22 def Compute_ukl(
 23     simu: Simulations.Elastic,
 24     Ekl: np.ndarray,
 25     nodesKUBC: Optional[np.ndarray] = None,
 26     pairedNodes: Optional[np.ndarray] = None,
 27     pltSol=False,
 28 ):
 29     simu.Bc_Init()
 30     mesh = simu.mesh
 31     coord = mesh.coord
 32
 33     directions = ["x", "y", "z"]
 34
 35     if nodesKUBC is not None:
 36
 37         def func_ux(x, y, z):
 38             return Ekl.dot([x, y, z])[0]
 39
 40         def func_uy(x, y, z):
 41             return Ekl.dot([x, y, z])[1]
 42
 43         def func_uz(x, y, z):
 44             return Ekl.dot([x, y, z])[2]
 45
 46         simu.add_dirichlet(nodesKUBC, [func_ux, func_uy, func_uz], directions)
 47
 48     if pairedNodes is not None:
 49         for n0, n1 in pairedNodes:
 50             nodes = np.array([n0, n1])
 51
 52             delta = coord[n0] - coord[n1]
 53             values = Ekl @ delta
 54
 55             for d, direction in enumerate(directions):
 56                 dofs = simu.Bc_dofs_nodes(nodes, [direction])
 57
 58                 condition = LagrangeCondition(
 59                     "elastic", nodes, dofs, [direction], [values[d]], [1, -1]
 60                 )
 61                 simu._Bc_Add_Lagrange(condition)
 62
 63         # remove rigid body motion
 64         nodes = mesh.nodes
 65         vect = np.ones(mesh.Nn) * 1 / mesh.Nn
 66         for direction in directions:
 67             # sum d_i / Nn = 0
 68             dofs = simu.Bc_dofs_nodes(nodes, [direction])
 69             condition = LagrangeCondition(
 70                 "elastic", nodes, dofs, [direction], [0], [vect]
 71             )
 72             simu._Bc_Add_Lagrange(condition)
 73
 74     ukl = simu.Solve()
 75
 76     simu.Save_Iter()
 77
 78     if pltSol:
 79         PyVista.Plot(simu, "ux", deformFactor=0.3).show()
 80         PyVista.Plot(simu, "uy", deformFactor=0.3).show()
 81
 82         PyVista.Plot(simu, "Sxx", deformFactor=0.3).show()
 83         PyVista.Plot(simu, "Syy", deformFactor=0.3).show()
 84         PyVista.Plot(simu, "Sxy", deformFactor=0.3).show()
 85
 86     return ukl
 87
 88
 89 def Get_nodes(mesh: Mesh, tol=1e-6, plotSurfaces=False):
 90     """Returns nodesXm, nodesXp, nodesYm, nodesYp, nodesZm, nodesZp"""
 91
 92     # PyVista.Plot_Tags(mesh).show()
 93     coord = mesh.coord
 94     nodesXm = mesh.Nodes_Conditions(lambda x, y, z: x <= coord[:, 0].min() + tol)
 95     nodesXp = mesh.Nodes_Conditions(lambda x, y, z: x >= coord[:, 0].max() - tol)
 96     nodesYm = mesh.Nodes_Conditions(lambda x, y, z: y <= coord[:, 1].min() + tol)
 97     nodesYp = mesh.Nodes_Conditions(lambda x, y, z: y >= coord[:, 1].max() - tol)
 98     nodesZm = mesh.Nodes_Conditions(lambda x, y, z: z <= coord[:, 2].min() + tol)
 99     nodesZp = mesh.Nodes_Conditions(lambda x, y, z: z >= coord[:, 2].max() - tol)
100
101     if plotSurfaces:
102         plotter = PyVista.Plot(mesh, alpha=0.1)
103         colors = plt.get_cmap("tab10").colors
104
105         dict_nodes = {
106             f"{nodesXm=}".split("=")[0]: nodesXm,
107             f"{nodesXp=}".split("=")[0]: nodesXp,
108             f"{nodesYm=}".split("=")[0]: nodesYm,
109             f"{nodesYp=}".split("=")[0]: nodesYp,
110             f"{nodesZm=}".split("=")[0]: nodesZm,
111             f"{nodesZp=}".split("=")[0]: nodesZp,
112         }
113
114         for i, (name, nodes) in enumerate(dict_nodes.items()):
115             PyVista.Plot_Elements(
116                 mesh, nodes, 2, color=colors[i], label=name, plotter=plotter
117             )
118         plotter.add_legend()
119         plotter.show()
120
121     return nodesXm, nodesXp, nodesYm, nodesYp, nodesZm, nodesZp
122
123
124 def Get_pairedNodes(
125     mesh: Mesh,
126     nodesXm: np.ndarray,
127     nodesXp: np.ndarray,
128     nodesYm: np.ndarray,
129     nodesYp: np.ndarray,
130     nodesZm: np.ndarray,
131     nodesZp: np.ndarray,
132     plotPBC=False,
133 ):
134
135     # remove Xp nodes on Y nodes
136     nodesYp = np.array(list(set(nodesYp) - set(nodesXp)))
137     nodesYm = np.array(list(set(nodesYm) - set(nodesXp)))
138
139     # remove Xp and Yp nodes on Z nodes
140     nodesZp = np.array(list(set(nodesZp) - set(nodesXp) - set(nodesYp)))
141     nodesZm = np.array(list(set(nodesZm) - set(nodesXp) - set(nodesYp)))
142
143     list_tuple_nodes = [
144         (nodesXm, nodesXp),
145         (nodesYm, nodesYp),
146         (nodesZm, nodesZp),
147     ]
148
149     # get paired nodes
150     for i, (nodes1, nodes2) in enumerate(list_tuple_nodes):
151
152         # sort nodes
153         sorted_nodes2 = np.zeros_like(nodes1)
154         coord = mesh.coord
155         for n, node in enumerate(nodes1):
156             dist = np.linalg.norm(coord[nodes2] - coord[node], axis=1)
157             sorted_nodes2[n] = nodes2[dist.argmin()]
158         nodes2 = sorted_nodes2
159
160         if plotPBC:
161             plotter = PyVista.Plot_Mesh(mesh, alpha=0.1)
162             PyVista.Plot_Nodes(mesh, nodes1, plotter=plotter)
163             PyVista.Plot_Nodes(mesh, nodes2, plotter=plotter)
164             plotter.add_lines(
165                 np.concatenate(
166                     (mesh.coord[nodes1], mesh.coord[nodes2]), axis=1
167                 ).reshape(-1, 3),
168                 color="k",
169             )
170             plotter.add_title(f"paired nodes along {['x','y','z'][i]} axis.")
171             plotter.show()
172
173         # set new paired nodes
174         newPairedNodes = np.array([nodes1, nodes2], dtype=int).T
175         if i == 0:
176             pairedNodes = newPairedNodes
177         else:
178             pairedNodes = np.concatenate((pairedNodes, newPairedNodes))
179
180     return pairedNodes
181
182
183 if __name__ == "__main__":
184     Display.Clear()
185
186     # ----------------------------------------------
187     # Configuration
188     # ----------------------------------------------
189
190     # use Periodic boundary conditions ?
191     usePBC = True
192     plotPBC = False
193     plotSurfaces = False
194
195     # ----------------------------------------------
196     # Mesh
197     # ----------------------------------------------
198     meshSize = 1 / 5
199
200     p0 = (-1 / 2, -1 / 2)
201     p1 = (1 / 2, -1 / 2)
202     p2 = (1 / 2, 1 / 2)
203     p3 = (-1 / 2, 1 / 2)
204     pts = [p0, p1, p2, p3]
205     contour = Points(pts, meshSize)
206
207     # inclusion
208     f = 0.4
209     r = 1 * np.sqrt(f / np.pi)
210     inclusion = Circle((0, 0), 2 * r, meshSize, isFilled=True)
211     # contour.Plot_Geoms([contour, inclusion])
212
213     elemType = ElemType.PRISM15
214     mesh = contour.Mesh_Extrude([inclusion], [0, 0, 1], [1 / meshSize], elemType)
215     mesh.Translate(*-mesh.center)  # center mesh on 0,0,0
216
217     plotter = PyVista.Plot_Mesh(mesh)
218     plotter.show_grid()
219     plotter.add_title("RVE")
220     plotter.show()
221
222     # ----------------------------------------------
223     # Get paired nodes
224     # ----------------------------------------------
225
226     tuple_nodes = Get_nodes(mesh, plotSurfaces=plotSurfaces)
227     if usePBC:
228         nodesKUBC = None
229         pairedNodes = Get_pairedNodes(mesh, *tuple_nodes, plotPBC=plotPBC)
230     else:
231         nodesKUBC = set(np.concatenate(tuple_nodes))
232         nodesKUBC = list(nodesKUBC)
233         pairedNodes = None
234
235     # ----------------------------------------------
236     # Material and Simulation
237     # ----------------------------------------------
238     elements_inclusion = (
239         np.array([]) if not inclusion.isFilled else mesh.Elements_Tags(["V1"])
240     )
241     elements_matrix = mesh.Elements_Tags(["V0"])
242
243     E = np.zeros_like(mesh.groupElem.elements, dtype=float)
244     v = np.zeros_like(mesh.groupElem.elements, dtype=float)
245
246     E[elements_matrix] = 1  # MPa
247     v[elements_matrix] = 0.45
248
249     if elements_inclusion.size > 0:
250         E[elements_inclusion] = 50
251         v[elements_inclusion] = 0.3
252
253     material = Models.Elastic.Isotropic(3, E, v)
254
255     simu = Simulations.Elastic(mesh, material)
256
257     PyVista.Plot(simu, E, nodeValues=False, colorbarTitle="E [MPa]").show()
258     PyVista.Plot(simu, v, nodeValues=False, colorbarTitle="v").show()
259
260     # ----------------------------------------------
261     # Homogenization
262     # ----------------------------------------------
263     r2 = np.sqrt(2)
264     E1 = np.array(
265         [
266             [1, 0, 0],
267             [0, 0, 0],
268             [0, 0, 0],
269         ]
270     )
271     E2 = np.array(
272         [
273             [0, 0, 0],
274             [0, 1, 0],
275             [0, 0, 0],
276         ]
277     )
278     E3 = np.array(
279         [
280             [0, 0, 0],
281             [0, 0, 0],
282             [0, 0, 1],
283         ]
284     )
285     E12 = np.array(
286         [
287             [0, 1 / r2, 0],
288             [1 / r2, 0, 0],
289             [0, 0, 0],
290         ]
291     )
292     E13 = np.array(
293         [
294             [0, 0, 1 / r2],
295             [0, 0, 0],
296             [1 / r2, 0, 0],
297         ]
298     )
299     E23 = np.array(
300         [
301             [0, 0, 0],
302             [0, 0, 1 / r2],
303             [0, 1 / r2, 0],
304         ]
305     )
306
307     u11 = Compute_ukl(simu, E1, nodesKUBC, pairedNodes, True)
308     u22 = Compute_ukl(simu, E2, nodesKUBC, pairedNodes)
309     u33 = Compute_ukl(simu, E3, nodesKUBC, pairedNodes)
310     u12 = Compute_ukl(simu, E12, nodesKUBC, pairedNodes, True)
311     u13 = Compute_ukl(simu, E13, nodesKUBC, pairedNodes)
312     u23 = Compute_ukl(simu, E23, nodesKUBC, pairedNodes)
313
314     u11_e = mesh.Locates_sol_e(u11, asFeArray=True)
315     u22_e = mesh.Locates_sol_e(u22, asFeArray=True)
316     u33_e = mesh.Locates_sol_e(u33, asFeArray=True)
317     u12_e = mesh.Locates_sol_e(u12, asFeArray=True)
318     u13_e = mesh.Locates_sol_e(u13, asFeArray=True)
319     u23_e = mesh.Locates_sol_e(u23, asFeArray=True)
320
321     # ----------------------------------------------
322     # Effective elasticity tensor (C_hom)
323     # ----------------------------------------------
324     U_e = FeArray.zeros(*u11_e.shape, 6)
325
326     U_e[..., 0] = u11_e
327     U_e[..., 1] = u22_e
328     U_e[..., 2] = u33_e
329     U_e[..., 3] = u23_e
330     U_e[..., 4] = u13_e
331     U_e[..., 5] = u12_e
332
333     matrixType = "mass"
334     wJ_e_pg = mesh.Get_weightedJacobian_e_pg(matrixType)
335     B_e_pg = mesh.Get_B_e_pg(matrixType)
336
337     C_Mat = Models.Reshape_variable(material.C, *B_e_pg.shape[:2])
338
339     xMin, yMin, zMin = mesh.coord.min(axis=0)
340     xMax, yMax, zMax = mesh.coord.max(axis=0)
341     volume = (xMax - xMin) * (yMax - yMin) * (zMax - zMin)
342
343     C_hom = (wJ_e_pg * C_Mat @ B_e_pg @ U_e).sum((0, 1)) / volume
344
345     formatted_array = ""
346     for i in range(6):
347         formatted_array += "\n"
348         for j in range(6):
349             formatted_array += f"{C_hom[i,j]:10.3e} "
350
351     print("C_hom =", formatted_array)
352
353     plt.show()

Total running time of the script: (0 minutes 6.660 seconds)

Gallery generated by Sphinx-Gallery