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:
- Ghost layer = f(patch) V box
= f( f_inv(f(patch) V box) ) = f( patch V f_inv(box) ),
where V denotes a ghost layer intersection.
21 import matplotlib.pyplot as plt
22 import numpy as np
23
24 import shamrock
Set box size
30 box_size_x = 2.0
31 box_size_y = 2.0
Particle set
36 color_set = [
37 "blue",
38 "red",
39 "green",
40 "black",
41 "orange",
42 "purple",
43 "brown",
44 "pink",
45 "gray",
46 "olive",
47 "cyan",
48 "magenta",
49 "yellow",
50 "teal",
51 "navy",
52 "gold",
53 "lime",
54 "indigo",
55 "maroon",
56 "turquoise",
57 ]
58
59 x_set = np.linspace(0.2, box_size_x - 0.2, 4)
60 y_set = np.linspace(0.2, box_size_y - 0.2, 4)
61
62 parts = []
63 i = 0
64 for x in x_set:
65 for y in y_set:
66 parts.append({"x": x, "y": y, "color": color_set[i % len(color_set)]})
67 i += 1
Utility to plot the paving function
73 margin = 0.1
74
75
76 def add_rect(x, y, w, h):
77 plt.gca().add_patch(
78 plt.Rectangle(
79 (x + margin, y + margin),
80 w - 2 * margin,
81 h - 2 * margin,
82 alpha=0.5,
83 fill=True,
84 facecolor="grey",
85 linewidth=2,
86 )
87 )
88
89
90 def add_rect_aabb(aabb):
91 add_rect(
92 aabb.lower[0], aabb.lower[1], aabb.upper[0] - aabb.lower[0], aabb.upper[1] - aabb.lower[1]
93 )
94
95
96 def ghost_intersect(part, box_to_intersect):
97 """
98 dummy ghost layer intersection to showcase how it works
99 """
100 x, y, z = part["x"], part["y"], 0.0
101
102 part_aabb = shamrock.math.AABB_f64_3((x - 0.3, y - 0.3, 0.0), (x + 0.3, y + 0.3, 0.0))
103
104 intersect = box_to_intersect.get_intersect(part_aabb)
105
106 _x, _y, _z = intersect.upper
107 _z = 1.0 # we want to be sure that the volume is not null but the z is not used
108 intersect.upper = (_x, _y, _z)
109
110 return intersect.is_volume_not_null()
111
112
113 def plot_paving_function(pav_func, pav_func_name):
114
115 box_to_intersect = shamrock.math.AABB_f64_3((0.0, 0.0, 0.0), (box_size_x, box_size_y, 0.0))
116
117 def get_indices():
118 for i in range(-2, 3):
119 for j in range(-3, 4):
120 if i == 0 and j == 0:
121 continue
122 yield i, j
123
124 plt.figure()
125
126 for i, j in get_indices():
127
128 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
129
130 add_rect_aabb(box_to_intersect_inv_mapped)
131
132 for part in parts:
133 x, y, z = (part["x"], part["y"], 0.0)
134 plt.scatter(x, y, color=part["color"])
135
136 plt.title(f"Paving function: {pav_func_name}\n1. Inverse map current sim box")
137 plt.xlabel("x")
138 plt.ylabel("y")
139
140 plt.figure()
141
142 for i, j in get_indices():
143
144 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
145
146 add_rect_aabb(box_to_intersect_inv_mapped)
147
148 for part in parts:
149 x, y, z = (part["x"], part["y"], 0.0)
150 if ghost_intersect(part, box_to_intersect_inv_mapped):
151 plt.scatter(x, y, color=part["color"])
152
153 plt.title(f"Paving function: {pav_func_name}\n2. Inverse ghost layer with inverse map")
154 plt.xlabel("x")
155 plt.ylabel("y")
156
157 plt.figure()
158
159 for i, j in get_indices():
160
161 box_to_intersect_inv_mapped = pav_func.f_aabb_inv(box_to_intersect, i, j, 0)
162 box_to_intersect_mapped = pav_func.f_aabb(box_to_intersect, i, j, 0)
163
164 add_rect_aabb(box_to_intersect_mapped)
165
166 for part in parts:
167 x, y, z = (part["x"], part["y"], 0.0)
168
169 if ghost_intersect(part, box_to_intersect_inv_mapped):
170 x, y, z = pav_func.f((x, y, 0.0), i, j, 0)
171 plt.scatter(x, y, color=part["color"])
172
173 for part in parts:
174 x, y, z = (part["x"], part["y"], 0.0)
175 plt.scatter(x, y, color=part["color"])
176
177 plt.title(f"Paving function: {pav_func_name}\n3. Map back the resulting ghost layer")
178 plt.xlabel("x")
179 plt.ylabel("y")
Testing the paving functions#
Periodic paving function
189 plot_paving_function(
190 shamrock.math.paving_function_general_3d(
191 (box_size_x, box_size_y, 0.0), (box_size_x / 2.0, box_size_y / 2.0, 0.0), True, True, True
192 ),
193 "Periodic box",
194 )
Periodic & reflective paving function
200 plot_paving_function(
201 shamrock.math.paving_function_general_3d(
202 (box_size_x, box_size_y, 0.0), (box_size_x / 2.0, box_size_y / 2.0, 0.0), False, True, True
203 ),
204 "reflective in x periodic in y",
205 )
Fully reflective paving function
211 plot_paving_function(
212 shamrock.math.paving_function_general_3d(
213 (box_size_x, box_size_y, 0.0), (box_size_x / 2.0, box_size_y / 2.0, 0.0), False, False, True
214 ),
215 "Fully reflective",
216 )
Periodic & reflective paving function with shear
222 plot_paving_function(
223 shamrock.math.paving_function_general_3d_shear_x(
224 (box_size_x, box_size_y, 0.0),
225 (box_size_x / 2.0, box_size_y / 2.0, 0.0),
226 False,
227 True,
228 True,
229 0.3,
230 ),
231 "reflective in x periodic in y with shear",
232 )
233
234 plt.show()
Total running time of the script: (0 minutes 3.269 seconds)
Estimated memory usage: 108 MB