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 box_to_intersect = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, 0.0))
125
126 def get_indices():
127 for i in range(-3, 4):
128 for j in range(-2, 3):
129 if i == 0 and j == 0:
130 continue
131 yield i, j
132
133 plt.figure()
134
135 for i, j in get_indices():
136 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
137
138 add_rect_aabb(box_to_intersect_inv_mapped)
139
140 for part in parts:
141 x, y, z = (part["x"], part["y"], 0.0)
142 plt.scatter(x, y, color=part["color"])
143
144 plt.title(f"Paving function: {pav_func_name}\n1. Inverse map current sim box")
145 plt.xlabel("x")
146 plt.ylabel("y")
147 plt.axis("equal")
148
149 plt.figure()
150
151 for i, j in get_indices():
152 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
153
154 add_rect_aabb(box_to_intersect_inv_mapped)
155
156 for part in parts:
157 x, y, z = (part["x"], part["y"], 0.0)
158 if ghost_intersect(part, box_to_intersect_inv_mapped):
159 plt.scatter(x, y, color=part["color"])
160
161 plt.title(f"Paving function: {pav_func_name}\n2. Inverse ghost layer with inverse map")
162 plt.xlabel("x")
163 plt.ylabel("y")
164 plt.axis("equal")
165
166 plt.figure()
167
168 for i, j in get_indices():
169 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
170 box_to_intersect_mapped = pav_func.f_aabb(box_to_intersect, i, j, 0)
171
172 add_rect_aabb(box_to_intersect_mapped)
173
174 for part in parts:
175 x, y, z = (part["x"], part["y"], 0.0)
176
177 if ghost_intersect(part, box_to_intersect_inv_mapped):
178 x, y, z = pav_func.f((x, y, 0.0), i, j, 0)
179 plt.scatter(x, y, color=part["color"])
180
181 for part in parts:
182 x, y, z = (part["x"], part["y"], 0.0)
183 plt.scatter(x, y, color=part["color"])
184
185 plt.title(f"Paving function: {pav_func_name}\n3. Map back the resulting ghost layer")
186 plt.xlabel("x")
187 plt.ylabel("y")
188 plt.axis("equal")
Testing the paving functions#
Periodic paving function
198 plot_paving_function(
199 shamrock.math.paving_function_general_3d(
200 (box_size_x, box_size_y, box_size_z),
201 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
202 True,
203 True,
204 True,
205 ),
206 "Periodic box",
207 )
Periodic & reflective paving function
213 plot_paving_function(
214 shamrock.math.paving_function_general_3d(
215 (box_size_x, box_size_y, box_size_z),
216 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
217 False,
218 True,
219 True,
220 ),
221 "reflective in x periodic in y",
222 )
Fully reflective paving function
228 plot_paving_function(
229 shamrock.math.paving_function_general_3d(
230 (box_size_x, box_size_y, box_size_z),
231 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
232 False,
233 False,
234 True,
235 ),
236 "Fully reflective",
237 )
Periodic & reflective paving function with shear
243 plot_paving_function(
244 shamrock.math.paving_function_general_3d_shear_x(
245 (box_size_x, box_size_y, box_size_z),
246 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
247 False,
248 True,
249 True,
250 0.3,
251 ),
252 "reflective in x periodic in y with shear",
253 )
Testing the list of indices with the paving function#
261 def test_paving_index_intersecting(pav_func, pav_func_name):
262 radius_int = 3.5
263 box_to_intersect = shamrock.math.AABB_f64_3(
264 (box_size_x / 2 - radius_int, box_size_y / 2 - radius_int, box_size_z / 2 - radius_int),
265 (box_size_x / 2 + radius_int, box_size_y / 2 + radius_int, box_size_z / 2 + radius_int),
266 )
267
268 indices = pav_func.get_paving_index_intersecting(box_to_intersect)
269
270 def get_indices():
271 x_r = 6
272 y_r = 4
273 for i in range(-x_r, x_r + 1):
274 for j in range(-y_r, y_r + 1):
275 yield i, j
276
277 domain = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, box_size_z))
278
279 plt.figure()
280
281 for i, j in get_indices():
282 domain_mapped = pav_func.f_aabb(domain, i, j, 0)
283
284 if [i, j, 0] in indices:
285 add_rect_aabb(domain_mapped, facecolor="green")
286 else:
287 add_rect_aabb(domain_mapped, facecolor="grey")
288
289 add_rect_aabb(box_to_intersect, facecolor="lightblue", alpha=0.5)
290
291 plt.title(f"Paving function: {pav_func_name}\n")
292 plt.xlabel("x")
293 plt.ylabel("y")
294 plt.axis("equal")
Periodic paving function
300 test_paving_index_intersecting(
301 shamrock.math.paving_function_general_3d(
302 (box_size_x, box_size_y, box_size_z),
303 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
304 True,
305 True,
306 True,
307 ),
308 "Periodic box",
309 )

Periodic & reflective paving function
315 test_paving_index_intersecting(
316 shamrock.math.paving_function_general_3d(
317 (box_size_x, box_size_y, box_size_z),
318 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
319 False,
320 True,
321 True,
322 ),
323 "reflective in x periodic in y",
324 )

Fully reflective paving function
330 test_paving_index_intersecting(
331 shamrock.math.paving_function_general_3d(
332 (box_size_x, box_size_y, box_size_z),
333 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
334 False,
335 False,
336 True,
337 ),
338 "Fully reflective",
339 )

Periodic & reflective paving function with shear
345 test_paving_index_intersecting(
346 shamrock.math.paving_function_general_3d_shear_x(
347 (box_size_x, box_size_y, box_size_z),
348 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
349 False,
350 True,
351 True,
352 0.3,
353 ),
354 "reflective in x periodic in y with shear",
355 )

Periodic & reflective paving function with strong shear
360 test_paving_index_intersecting(
361 shamrock.math.paving_function_general_3d_shear_x(
362 (box_size_x, box_size_y, box_size_z),
363 (box_size_x / 2.0, box_size_y / 2.0, box_size_z / 2.0),
364 False,
365 True,
366 True,
367 1.8,
368 ),
369 "reflective in x periodic in y with shear",
370 )
371
372 plt.show()

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











