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

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

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

Gallery generated by Sphinx-Gallery