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

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 )
  • 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

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 )
  • 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

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 )
  • 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

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 )
  • 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#

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

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

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

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

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

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

Estimated memory usage: 159 MB

Gallery generated by Sphinx-Gallery