Homog4#

Conduct 3d homogenization.

WARNING#

Verify that the periodic boundary conditions have been correctly applied.

Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
Homog4
C_hom =
 5.793e+00  3.569e+00  3.512e+00  3.532e-16 -5.546e-15 -1.519e-04
 3.569e+00  5.857e+00  3.537e+00  3.884e-15 -7.533e-16  1.315e-04
 3.512e+00  3.537e+00  2.300e+01  1.235e-15 -1.707e-15 -7.543e-06
 5.712e-17  2.133e-16  6.665e-15  1.539e+00  3.430e-07  7.187e-18
 2.110e-16 -7.865e-17  2.774e-14  3.430e-07  1.557e+00 -4.734e-17
-1.519e-04  1.315e-04 -7.543e-06 -3.702e-15 -1.614e-15  1.282e+00

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

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

Gallery generated by Sphinx-Gallery