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
Set box size
33 box_size_x = 2.0
34 box_size_y = 2.0
35 box_size_z = 2.0
Particle set
40 color_set = [
41 "blue",
42 "red",
43 "green",
44 "black",
45 "orange",
46 "purple",
47 "brown",
48 "pink",
49 "gray",
50 "olive",
51 "cyan",
52 "magenta",
53 "yellow",
54 "teal",
55 "navy",
56 "gold",
57 "lime",
58 "indigo",
59 "maroon",
60 "turquoise",
61 ]
62
63 x_set = np.linspace(0.2, box_size_x - 0.2, 4)
64 y_set = np.linspace(0.2, box_size_y - 0.2, 4)
65
66 parts = []
67 i = 0
68 for x in x_set:
69 for y in y_set:
70 parts.append({"x": x, "y": y, "color": color_set[i % len(color_set)]})
71 i += 1
Utility to plot the paving function
77 margin = 0.0
78
79
80 def add_rect(x, y, w, h, facecolor="grey", alpha=0.5):
81 plt.gca().add_patch(
82 plt.Rectangle(
83 (x + margin, y + margin),
84 w - 2 * margin,
85 h - 2 * margin,
86 alpha=alpha,
87 fill=True,
88 facecolor=facecolor,
89 edgecolor="black",
90 linewidth=4,
91 )
92 )
93
94
95 def add_rect_aabb(aabb, facecolor="grey", alpha=0.5):
96 add_rect(
97 aabb.lower[0],
98 aabb.lower[1],
99 aabb.upper[0] - aabb.lower[0],
100 aabb.upper[1] - aabb.lower[1],
101 facecolor=facecolor,
102 alpha=alpha,
103 )
104
105
106 def ghost_intersect(part, box_to_intersect):
107 """
108 dummy ghost layer intersection to showcase how it works
109 """
110 x, y, z = part["x"], part["y"], 0.0
111
112 part_aabb = shamrock.math.AABB_f64_3((x - 0.3, y - 0.3, 0.0), (x + 0.3, y + 0.3, 0.0))
113
114 intersect = box_to_intersect.get_intersect(part_aabb)
115
116 _x, _y, _z = intersect.upper
117 _z = 1.0 # we want to be sure that the volume is not null but the z is not used
118 intersect.upper = (_x, _y, _z)
119
120 return intersect.is_volume_not_null()
121
122
123 def plot_paving_function(pav_func, pav_func_name):
124
125 box_to_intersect = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, 0.0))
126
127 def get_indices():
128 for i in range(-3, 4):
129 for j in range(-2, 3):
130 if i == 0 and j == 0:
131 continue
132 yield i, j
133
134 plt.figure()
135
136 for i, j in get_indices():
137
138 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
139
140 add_rect_aabb(box_to_intersect_inv_mapped)
141
142 for part in parts:
143 x, y, z = (part["x"], part["y"], 0.0)
144 plt.scatter(x, y, color=part["color"])
145
146 plt.title(f"Paving function: {pav_func_name}\n1. Inverse map current sim box")
147 plt.xlabel("x")
148 plt.ylabel("y")
149 plt.axis("equal")
150
151 plt.figure()
152
153 for i, j in get_indices():
154
155 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
156
157 add_rect_aabb(box_to_intersect_inv_mapped)
158
159 for part in parts:
160 x, y, z = (part["x"], part["y"], 0.0)
161 if ghost_intersect(part, box_to_intersect_inv_mapped):
162 plt.scatter(x, y, color=part["color"])
163
164 plt.title(f"Paving function: {pav_func_name}\n2. Inverse ghost layer with inverse map")
165 plt.xlabel("x")
166 plt.ylabel("y")
167 plt.axis("equal")
168
169 plt.figure()
170
171 for i, j in get_indices():
172
173 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
174 box_to_intersect_mapped = pav_func.f_aabb(box_to_intersect, i, j, 0)
175
176 add_rect_aabb(box_to_intersect_mapped)
177
178 for part in parts:
179 x, y, z = (part["x"], part["y"], 0.0)
180
181 if ghost_intersect(part, box_to_intersect_inv_mapped):
182 x, y, z = pav_func.f((x, y, 0.0), i, j, 0)
183 plt.scatter(x, y, color=part["color"])
184
185 for part in parts:
186 x, y, z = (part["x"], part["y"], 0.0)
187 plt.scatter(x, y, color=part["color"])
188
189 plt.title(f"Paving function: {pav_func_name}\n3. Map back the resulting ghost layer")
190 plt.xlabel("x")
191 plt.ylabel("y")
192 plt.axis("equal")
Testing the paving functions#
Periodic paving function
202 plot_paving_function(
203 shamrock.math.paving_function_general_3d(
204 (box_size_x, box_size_y, box_size_z),
205 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
206 True,
207 True,
208 True,
209 ),
210 "Periodic box",
211 )
Periodic & reflective paving function
217 plot_paving_function(
218 shamrock.math.paving_function_general_3d(
219 (box_size_x, box_size_y, box_size_z),
220 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
221 False,
222 True,
223 True,
224 ),
225 "reflective in x periodic in y",
226 )
Fully reflective paving function
232 plot_paving_function(
233 shamrock.math.paving_function_general_3d(
234 (box_size_x, box_size_y, box_size_z),
235 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
236 False,
237 False,
238 True,
239 ),
240 "Fully reflective",
241 )
Periodic & reflective paving function with shear
247 plot_paving_function(
248 shamrock.math.paving_function_general_3d_shear_x(
249 (box_size_x, box_size_y, box_size_z),
250 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
251 False,
252 True,
253 True,
254 0.3,
255 ),
256 "reflective in x periodic in y with shear",
257 )
Testing the list of indices with the paving function#
265 def test_paving_index_intersecting(pav_func, pav_func_name):
266
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
288 domain_mapped = pav_func.f_aabb(domain, i, j, 0)
289
290 if [i, j, 0] in indices:
291 add_rect_aabb(domain_mapped, facecolor="green")
292 else:
293 add_rect_aabb(domain_mapped, facecolor="grey")
294
295 add_rect_aabb(box_to_intersect, facecolor="lightblue", alpha=0.5)
296
297 plt.title(f"Paving function: {pav_func_name}\n")
298 plt.xlabel("x")
299 plt.ylabel("y")
300 plt.axis("equal")
Periodic paving function
306 test_paving_index_intersecting(
307 shamrock.math.paving_function_general_3d(
308 (box_size_x, box_size_y, box_size_z),
309 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
310 True,
311 True,
312 True,
313 ),
314 "Periodic box",
315 )

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

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

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

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

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











