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:

\[\text{Ghost layer} = f(\text{patch}) \vee \text{box} \ = f( f^{-1}(f(\text{patch}) \vee \text{box}) ) \ = f( \text{patch} \vee f^{-1}(\text{box}) ),\]

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 )
  • Paving function: Periodic box 1. Inverse map current sim box
  • Paving function: Periodic box 2. Inverse ghost layer with inverse map
  • Paving function: Periodic box 3. Map back the resulting ghost layer

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 )
  • Paving function: reflective in x periodic in y 1. Inverse map current sim box
  • Paving function: reflective in x periodic in y 2. Inverse ghost layer with inverse map
  • Paving function: reflective in x periodic in y 3. Map back the resulting ghost layer

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 )
  • Paving function: Fully reflective 1. Inverse map current sim box
  • Paving function: Fully reflective 2. Inverse ghost layer with inverse map
  • Paving function: Fully reflective 3. Map back the resulting ghost layer

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 )
  • Paving function: reflective in x periodic in y with shear 1. Inverse map current sim box
  • Paving function: reflective in x periodic in y with shear 2. Inverse ghost layer with inverse map
  • Paving function: reflective in x periodic in y with shear 3. Map back the resulting ghost layer

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 )
Paving function: Periodic box

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 )
Paving function: reflective in x periodic in y

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 )
Paving function: Fully reflective

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 )
Paving function: reflective in x periodic in y with shear

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()
Paving function: reflective in x periodic in y with shear

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

Estimated memory usage: 125 MB

Gallery generated by Sphinx-Gallery