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

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

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

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

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

Estimated memory usage: 108 MB

Gallery generated by Sphinx-Gallery