Note
Go to the end to download the full example code.
Ghost layer generation using paving functions#
This example showcase how to use the paving functions to generate ghost layers.
The complex thing is that we want to intersect the current data with the ghost layer, but we do not want to modify the original buffer. As a result we perform the intersection in a space transformed by the paving function, and then map the result back to the original space.
Formally speaking for a paving function f:
where \(\vee\) denotes a ghost layer intersection.
24 import matplotlib.pyplot as plt
25 import numpy as np
26
27 import shamrock
Use shamrock documentation style for matplotlib
32 shamrock.matplotlib.set_shamrock_mpl_style()
Set box size
38 box_size_x = 2.0
39 box_size_y = 2.0
40 box_size_z = 2.0
Particle set
45 color_set = [
46 "blue",
47 "red",
48 "green",
49 "black",
50 "orange",
51 "purple",
52 "brown",
53 "pink",
54 "gray",
55 "olive",
56 "cyan",
57 "magenta",
58 "yellow",
59 "teal",
60 "navy",
61 "gold",
62 "lime",
63 "indigo",
64 "maroon",
65 "turquoise",
66 ]
67
68 x_set = np.linspace(0.2, box_size_x - 0.2, 4)
69 y_set = np.linspace(0.2, box_size_y - 0.2, 4)
70
71 parts = []
72 i = 0
73 for x in x_set:
74 for y in y_set:
75 parts.append({"x": x, "y": y, "color": color_set[i % len(color_set)]})
76 i += 1
Utility to plot the paving function
82 margin = 0.0
83
84
85 def add_rect(x, y, w, h, facecolor="grey", alpha=0.5):
86 plt.gca().add_patch(
87 plt.Rectangle(
88 (x + margin, y + margin),
89 w - 2 * margin,
90 h - 2 * margin,
91 alpha=alpha,
92 fill=True,
93 facecolor=facecolor,
94 edgecolor="black",
95 linewidth=4,
96 )
97 )
98
99
100 def add_rect_aabb(aabb, facecolor="grey", alpha=0.5):
101 add_rect(
102 aabb.lower[0],
103 aabb.lower[1],
104 aabb.upper[0] - aabb.lower[0],
105 aabb.upper[1] - aabb.lower[1],
106 facecolor=facecolor,
107 alpha=alpha,
108 )
109
110
111 def ghost_intersect(part, box_to_intersect):
112 """
113 dummy ghost layer intersection to showcase how it works
114 """
115 x, y, z = part["x"], part["y"], 0.0
116
117 part_aabb = shamrock.math.AABB_f64_3((x - 0.3, y - 0.3, 0.0), (x + 0.3, y + 0.3, 0.0))
118
119 intersect = box_to_intersect.get_intersect(part_aabb)
120
121 _x, _y, _z = intersect.upper
122 _z = 1.0 # we want to be sure that the volume is not null but the z is not used
123 intersect.upper = (_x, _y, _z)
124
125 return intersect.is_volume_not_null()
126
127
128 def plot_paving_function(pav_func, pav_func_name):
129 box_to_intersect = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, 0.0))
130
131 def get_indices():
132 for i in range(-3, 4):
133 for j in range(-2, 3):
134 if i == 0 and j == 0:
135 continue
136 yield i, j
137
138 plt.figure()
139
140 for i, j in get_indices():
141 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
142
143 add_rect_aabb(box_to_intersect_inv_mapped)
144
145 for part in parts:
146 x, y, z = (part["x"], part["y"], 0.0)
147 plt.scatter(x, y, color=part["color"])
148
149 plt.title(f"Paving function: {pav_func_name}\n1. Inverse map current sim box")
150 plt.xlabel("x")
151 plt.ylabel("y")
152 plt.axis("equal")
153
154 plt.figure()
155
156 for i, j in get_indices():
157 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
158
159 add_rect_aabb(box_to_intersect_inv_mapped)
160
161 for part in parts:
162 x, y, z = (part["x"], part["y"], 0.0)
163 if ghost_intersect(part, box_to_intersect_inv_mapped):
164 plt.scatter(x, y, color=part["color"])
165
166 plt.title(f"Paving function: {pav_func_name}\n2. Inverse ghost layer with inverse map")
167 plt.xlabel("x")
168 plt.ylabel("y")
169 plt.axis("equal")
170
171 plt.figure()
172
173 for i, j in get_indices():
174 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
175 box_to_intersect_mapped = pav_func.f_aabb(box_to_intersect, i, j, 0)
176
177 add_rect_aabb(box_to_intersect_mapped)
178
179 for part in parts:
180 x, y, z = (part["x"], part["y"], 0.0)
181
182 if ghost_intersect(part, box_to_intersect_inv_mapped):
183 x, y, z = pav_func.f((x, y, 0.0), i, j, 0)
184 plt.scatter(x, y, color=part["color"])
185
186 for part in parts:
187 x, y, z = (part["x"], part["y"], 0.0)
188 plt.scatter(x, y, color=part["color"])
189
190 plt.title(f"Paving function: {pav_func_name}\n3. Map back the resulting ghost layer")
191 plt.xlabel("x")
192 plt.ylabel("y")
193 plt.axis("equal")
Testing the paving functions#
Periodic paving function
203 plot_paving_function(
204 shamrock.math.paving_function_general_3d(
205 (box_size_x, box_size_y, box_size_z),
206 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
207 True,
208 True,
209 True,
210 ),
211 "Periodic box",
212 )
Periodic & reflective paving function
218 plot_paving_function(
219 shamrock.math.paving_function_general_3d(
220 (box_size_x, box_size_y, box_size_z),
221 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
222 False,
223 True,
224 True,
225 ),
226 "reflective in x periodic in y",
227 )
Fully reflective paving function
233 plot_paving_function(
234 shamrock.math.paving_function_general_3d(
235 (box_size_x, box_size_y, box_size_z),
236 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
237 False,
238 False,
239 True,
240 ),
241 "Fully reflective",
242 )
Periodic & reflective paving function with shear
248 plot_paving_function(
249 shamrock.math.paving_function_general_3d_shear_x(
250 (box_size_x, box_size_y, box_size_z),
251 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
252 False,
253 True,
254 True,
255 0.3,
256 ),
257 "reflective in x periodic in y with shear",
258 )
Testing the list of indices with the paving function#
266 def test_paving_index_intersecting(pav_func, pav_func_name):
267 radius_int = 3.5
268 box_to_intersect = shamrock.math.AABB_f64_3(
269 (box_size_x / 2 - radius_int, box_size_y / 2 - radius_int, box_size_z / 2 - radius_int),
270 (box_size_x / 2 + radius_int, box_size_y / 2 + radius_int, box_size_z / 2 + radius_int),
271 )
272
273 indices = pav_func.get_paving_index_intersecting(box_to_intersect)
274
275 def get_indices():
276 x_r = 6
277 y_r = 4
278 for i in range(-x_r, x_r + 1):
279 for j in range(-y_r, y_r + 1):
280 yield i, j
281
282 domain = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, box_size_z))
283
284 plt.figure()
285
286 for i, j in get_indices():
287 domain_mapped = pav_func.f_aabb(domain, i, j, 0)
288
289 if [i, j, 0] in indices:
290 add_rect_aabb(domain_mapped, facecolor="green")
291 else:
292 add_rect_aabb(domain_mapped, facecolor="grey")
293
294 add_rect_aabb(box_to_intersect, facecolor="lightblue", alpha=0.5)
295
296 plt.title(f"Paving function: {pav_func_name}\n")
297 plt.xlabel("x")
298 plt.ylabel("y")
299 plt.axis("equal")
Periodic paving function
305 test_paving_index_intersecting(
306 shamrock.math.paving_function_general_3d(
307 (box_size_x, box_size_y, box_size_z),
308 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
309 True,
310 True,
311 True,
312 ),
313 "Periodic box",
314 )

Periodic & reflective paving function
320 test_paving_index_intersecting(
321 shamrock.math.paving_function_general_3d(
322 (box_size_x, box_size_y, box_size_z),
323 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
324 False,
325 True,
326 True,
327 ),
328 "reflective in x periodic in y",
329 )

Fully reflective paving function
335 test_paving_index_intersecting(
336 shamrock.math.paving_function_general_3d(
337 (box_size_x, box_size_y, box_size_z),
338 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
339 False,
340 False,
341 True,
342 ),
343 "Fully reflective",
344 )

Periodic & reflective paving function with shear
350 test_paving_index_intersecting(
351 shamrock.math.paving_function_general_3d_shear_x(
352 (box_size_x, box_size_y, box_size_z),
353 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
354 False,
355 True,
356 True,
357 0.3,
358 ),
359 "reflective in x periodic in y with shear",
360 )

Periodic & reflective paving function with strong shear
365 test_paving_index_intersecting(
366 shamrock.math.paving_function_general_3d_shear_x(
367 (box_size_x, box_size_y, box_size_z),
368 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
369 False,
370 True,
371 True,
372 1.8,
373 ),
374 "reflective in x periodic in y with shear",
375 )
376
377 plt.show()

Total running time of the script: (0 minutes 5.175 seconds)
Estimated memory usage: 159 MB











