TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
IJK_Bubble_tools.cpp
1/****************************************************************************
2* Copyright (c) 2023, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <IJK_Bubble_tools.h>
17
18
19static int decoder_numero_bulle(const int code)
20{
21 const int num_bulle = code >> 6;
22 return num_bulle;
23}
24
25std::vector<int> arg_sort_array(const ArrOfDouble& array_to_sort)
26{
27 const int n = array_to_sort.size_array();
28 // IntVect indices(n);
29 std::vector<int> indices(n);
30 for (int j=0; j<n; j++)
31 indices[j]=j;
32 std::sort(indices.begin(), indices.end(), [&array_to_sort](int i, int j) {return array_to_sort[i] < array_to_sort[j];});
33 return indices;
34}
35
36std::vector<int> arg_sort_array_phi(const ArrOfDouble& angle_incr, const ArrOfDouble& first_angle, const ArrOfDouble& array_to_sort)
37{
38 const int n = array_to_sort.size_array();
39 const double constant_angle_incr = abs(angle_incr[1] - angle_incr[0]);
40 std::vector<int> indices;
41 std::vector<int> indices_subarray;
42 ArrOfDouble sub_array;
43 for (int i=0; i<angle_incr.size_array(); i++)
44 {
45 const double angle_min = angle_incr(i) - constant_angle_incr / 2;
46 const double angle_max = angle_incr(i) + constant_angle_incr / 2;
47 for (int j=0; j<first_angle.size_array(); j++)
48 if (first_angle(j) >= angle_min && first_angle(j) < angle_max)
49 {
50 indices_subarray.push_back(j);
51 sub_array.append_array(array_to_sort(j));
52 }
53 std::vector<int> indices_subarray_sorted = arg_sort_array(sub_array);
54 const int size_subarray_sorted = (int) indices_subarray_sorted.size();
55 for (int k=0; k<size_subarray_sorted; k++)
56 {
57 const int index = indices_subarray_sorted[k];
58 indices.push_back((int) indices_subarray[index]);
59 }
60 indices_subarray.clear();
61 sub_array.reset();
62 }
63
64 assert((int) indices.size() == n);
65 if (!((int) indices.size() == n))
67
68 return indices;
69}
70
71/* FROM void IJK_Interfaces::calculer_volume_bulles
72 * L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
73 * const int idx_ghost = get_ghost_number_from_compo(compo);
74 * // On la place en fin de tableau :
75 * compo = nbulles_reelles - 1 - idx_ghost;
76 */
77
78void compute_bounding_box_fill_compo(const IJK_Interfaces& interfaces,
79 DoubleTab& bounding_box,
80 DoubleTab& min_max_larger_box,
81 IJK_Field_double& eulerian_compo_connex,
82 IJK_Field_double& eulerian_compo_connex_ghost,
83 DoubleTab& bubbles_barycentre)
84{
85 /*
86 * bounding_box(b, dir, m) :
87 * b -> Numero de la composante connexe de la bulle.
88 * dir -> Direction i,j ou k.
89 * m -> min (0) ou max (1)
90 */
91 interfaces.calculer_bounding_box_bulles(bounding_box);
92 int nb_bubbles = interfaces.get_nb_bulles_reelles();
93 int nb_ghost_bubbles = interfaces.get_nb_bulles_ghost();
94 eulerian_compo_connex.data() = -1;
95 eulerian_compo_connex.echange_espace_virtuel(eulerian_compo_connex.ghost());
96 eulerian_compo_connex_ghost.data() = -1;
97 eulerian_compo_connex_ghost.echange_espace_virtuel(eulerian_compo_connex_ghost.ghost());
98 IntTab ghost_to_real_bubble(nb_ghost_bubbles);
99 for (int l = 0; l < nb_ghost_bubbles; l++)
100 {
101 const int ighost = interfaces.ghost_compo_converter(l);
102 const int ibulle_reelle = decoder_numero_bulle(-ighost);
103 ghost_to_real_bubble(l) = ibulle_reelle;
104 }
105
106 ArrOfDouble bubbles_volume;
107 interfaces.calculer_volume_bulles(bubbles_volume, bubbles_barycentre);
108
109 /*
110 * Considered a constant grid spacing
111 */
112 const Domaine_IJK& geometry =eulerian_compo_connex.get_domaine();
113 double dx = geometry.get_constant_delta(DIRECTION_I);
114 double dy = geometry.get_constant_delta(DIRECTION_J);
115 double dz = geometry.get_constant_delta(DIRECTION_K);
116 double delta_xyz[3] = {dx, dy, dz};
117
118 /*
119 * Look for a larger bounding box (3D)
120 */
121 double geom_origin_x = geometry.get_origin(DIRECTION_I);
122 double geom_origin_y = geometry.get_origin(DIRECTION_J);
123 double geom_origin_z = geometry.get_origin(DIRECTION_K);
124 double origin_x = geom_origin_x + geometry.get_offset_local(DIRECTION_I) * dx;
125 double origin_y = geom_origin_y + geometry.get_offset_local(DIRECTION_J) * dy;
126 double origin_z = geom_origin_z + geometry.get_offset_local(DIRECTION_K) * dz;
127 double geom_origin[3] = {geom_origin_x, geom_origin_y, geom_origin_z};
128 double origin[3] = {origin_x, origin_y, origin_z};
129 //
130 // DoubleTab min_max_larger_box(nb_bubbles, 3, 2);
131 min_max_larger_box.resize(nb_bubbles, 3, 2);
132 DoubleTab min_max_larger_box_absolute(nb_bubbles, 3, 2);
133 for (int ibubble = 0; ibubble < nb_bubbles; ibubble++)
134 {
135 for (int dir = 0; dir < 3; dir++)
136 {
137 min_max_larger_box(ibubble, dir, 0) = origin[dir] + trunc((bounding_box(ibubble, dir, 0) - geom_origin[dir]) / delta_xyz[dir])
138 * delta_xyz[dir];
139 min_max_larger_box_absolute(ibubble, dir, 0) = min_max_larger_box(ibubble, dir, 0) - bubbles_barycentre(ibubble, dir);
140 }
141 for (int dir = 0; dir < 3; dir++)
142 {
143 min_max_larger_box(ibubble, dir, 1) = origin[dir] + trunc((bounding_box(ibubble, dir, 1) - geom_origin[dir] + delta_xyz[dir]) / delta_xyz[dir]) * delta_xyz[dir];
144 min_max_larger_box_absolute(ibubble, dir, 1) = min_max_larger_box(ibubble, dir, 1) - bubbles_barycentre(ibubble, dir);
145 }
146 }
147 /*
148 * FT fields
149 */
150 const int nk = eulerian_compo_connex.nk();
151 const int nj = eulerian_compo_connex.nj();
152 const int ni = eulerian_compo_connex.ni();
153 // const IJK_Field_double& indic = interfaces.I_ft();
154 const IJK_Field_double& indic = interfaces.In_ft();
155 for (int k = 0; k < nk; k++)
156 for (int j = 0; j < nj; j++)
157 for (int i = 0; i < ni; i++)
158 for (int ibubble = 0; ibubble < (nb_bubbles + nb_ghost_bubbles); ibubble++)
159 {
160 const double cell_pos_x = origin_x + (i + 0.5) * delta_xyz[0];
161 const double cell_pos_y = origin_y + (j + 0.5) * delta_xyz[1];
162 const double cell_pos_z = origin_z + (k + 0.5) * delta_xyz[2];
163 double cell_pos[3] = {cell_pos_x, cell_pos_y, cell_pos_z};
164 const double chi_l = indic(i,j,k);
165 int cell_pos_bool = true;
166 int bubble_index;
167 for (int dir = 0; dir < 3; dir++)
168 {
169 double min_box;
170 double max_box;
171 if (ibubble < nb_bubbles)
172 {
173 bubble_index = ibubble;
174 min_box = min_max_larger_box(bubble_index, dir, 0);
175 max_box = min_max_larger_box(bubble_index, dir, 1);
176 }
177 else
178 {
179 bubble_index = ghost_to_real_bubble(ibubble - nb_bubbles);
180 min_box = min_max_larger_box_absolute(bubble_index, dir, 0) + bubbles_barycentre(ibubble, dir);
181 max_box = min_max_larger_box_absolute(bubble_index, dir, 1) + bubbles_barycentre(ibubble, dir);
182 }
183 cell_pos_bool = (cell_pos_bool && cell_pos[dir] > min_box && cell_pos[dir] < max_box);
184 }
185 if (fabs(chi_l) < LIQUID_INDICATOR_TEST)
186 {
187 if (cell_pos_bool)
188 {
189 eulerian_compo_connex(i,j,k) = bubble_index;
190 eulerian_compo_connex_ghost(i,j,k) = ibubble;
191 }
192 }
193 }
194}
195
196void compute_interfacial_compo_fill_compo(const IJK_Interfaces& interfaces, IJK_Field_double& eulerian_compo_connex)
197{
198
199}
200
201void compute_rising_velocity_overall(const IJK_Interfaces& interfaces,
202 const DoubleTab& rising_vectors,
203 const ArrOfDouble& rising_velocities,
204 const ArrOfDouble& bubbles_volume,
205 Vecteur3& rising_velocities_overall,
206 const DoubleTab& bubbles_velocities_from_interface,
207 const int& use_bubbles_velocities_from_interface,
208 const DoubleTab& bubbles_velocities_from_barycentres,
209 const int& use_bubbles_velocities_from_barycentres)
210{
211 rising_velocities_overall = {0.,0.,0.};
212 double total_volume = 0;
213 int nb_bubbles = interfaces.get_nb_bulles_reelles();
214 for (int ibubble = 0; ibubble < nb_bubbles; ibubble++)
215 {
216 for (int l=0; l<3; l++)
217 {
218 if (use_bubbles_velocities_from_interface)
219 rising_velocities_overall[l] = bubbles_velocities_from_interface(ibubble, l) * bubbles_volume[ibubble];
220 else if (use_bubbles_velocities_from_barycentres)
221 rising_velocities_overall[l] = bubbles_velocities_from_barycentres(ibubble, l) * bubbles_volume[ibubble];
222 else
223 rising_velocities_overall[l] = (rising_velocities[ibubble] * rising_vectors(ibubble, l))
224 * bubbles_volume[ibubble];
225 }
226 total_volume += bubbles_volume[ibubble];
227 }
228 for (int l=0; l<3; l++)
229 {
230 const double rising_velocity_compo = rising_velocities_overall[l];
231 rising_velocities_overall[l] = rising_velocity_compo / total_volume;
232 }
233}
234
235void compute_rising_velocity(const IJK_Field_vector3_double& velocity,
236 const IJK_Interfaces& interfaces,
237 const IJK_Field_int& eulerian_compo_connex_ns,
238 const int& gravity_dir,
239 ArrOfDouble& rising_velocities,
240 DoubleTab& rising_vectors,
241 Vecteur3& liquid_velocity,
242 const DoubleTab& bubbles_velocities_from_interface,
243 const int& use_bubbles_velocities_from_interface,
244 const DoubleTab& bubbles_velocities_from_barycentres,
245 const int& use_bubbles_velocities_from_barycentres)
246{
247 const DoubleTab * bubbles_velocities_interf_bary = nullptr;
248 if (use_bubbles_velocities_from_barycentres)
249 bubbles_velocities_interf_bary = &bubbles_velocities_from_barycentres;
250 else
251 bubbles_velocities_interf_bary = &bubbles_velocities_from_interface;
252 /*
253 * Constant cell volume
254 */
255 const int nk = eulerian_compo_connex_ns.nk();
256 const int nj = eulerian_compo_connex_ns.nj();
257 const int ni = eulerian_compo_connex_ns.ni();
258
259 const IJK_Field_double& indic = interfaces.I();
260
261 int nb_bubbles = interfaces.get_nb_bulles_reelles();
262
263 DoubleVect sum_indicator(nb_bubbles);
264 DoubleVect sum_velocity_x_indicator(nb_bubbles);
265 DoubleVect sum_velocity_y_indicator(nb_bubbles);
266 DoubleVect sum_velocity_z_indicator(nb_bubbles);
267
268 liquid_velocity = 0.;
269 double sum_indicator_liquid = 0.;
270
271 for (int k = 0; k < nk; k++)
272 for (int j = 0; j < nj; j++)
273 for (int i = 0; i < ni; i++)
274 {
275 const double chi_l = indic(i,j,k);
276 const double vel_x = 0.5 * (velocity[0](i,j,k) + velocity[0](i+1,j,k));
277 const double vel_y = 0.5 * (velocity[1](i,j,k) + velocity[1](i,j+1,k));
278 const double vel_z = 0.5 * (velocity[2](i,j,k) + velocity[2](i,j,k+1));
279 if (!(use_bubbles_velocities_from_interface || use_bubbles_velocities_from_barycentres))
280 {
281 const double chi_v = (1. - indic(i,j,k));
282 int compo_connex = eulerian_compo_connex_ns(i,j,k);
283 // USE PURE VAPOUR ONLY ?
284
285 if (compo_connex >= 0)
286 // if (compo_connex >= 0 && chi_l < VAPOUR_INDICATOR_TEST)
287 {
288 sum_indicator(compo_connex) += chi_v;
289 sum_velocity_x_indicator(compo_connex) += chi_v * vel_x;
290 sum_velocity_y_indicator(compo_connex) += chi_v * vel_y;
291 sum_velocity_z_indicator(compo_connex) += chi_v * vel_z;
292 }
293 }
294 // USE PURE LIQUID ONLY ?
295 if (chi_l > VAPOUR_INDICATOR_TEST)
296 // if (chi_l > LIQUID_INDICATOR_TEST)
297 {
298 Vecteur3 liquid_velocity_local = {vel_x, vel_y, vel_z};
299 liquid_velocity_local *= chi_l;
300 sum_indicator_liquid += chi_l;
301 liquid_velocity += liquid_velocity_local;
302 }
303 }
304
305 if (!(use_bubbles_velocities_from_interface || use_bubbles_velocities_from_barycentres))
306 {
307 Process::mp_sum_for_each_item(sum_indicator);
308 Process::mp_sum_for_each_item(sum_velocity_x_indicator);
309 Process::mp_sum_for_each_item(sum_velocity_y_indicator);
310 Process::mp_sum_for_each_item(sum_velocity_z_indicator);
311
312 for (int ibubble = 0; ibubble < nb_bubbles; ibubble++)
313 {
314 sum_velocity_x_indicator(ibubble) /= sum_indicator(ibubble);
315 sum_velocity_y_indicator(ibubble) /= sum_indicator(ibubble);
316 sum_velocity_z_indicator(ibubble) /= sum_indicator(ibubble);
317 rising_velocities(ibubble) = sqrt( sum_velocity_x_indicator(ibubble) * sum_velocity_x_indicator(ibubble)
318 + sum_velocity_y_indicator(ibubble) * sum_velocity_y_indicator(ibubble)
319 + sum_velocity_z_indicator(ibubble) * sum_velocity_z_indicator(ibubble));
320 if (rising_velocities(ibubble) > DMINFLOAT)
321 {
322 rising_vectors(ibubble, 0) = sum_velocity_x_indicator(ibubble) / rising_velocities(ibubble);
323 rising_vectors(ibubble, 1) = sum_velocity_y_indicator(ibubble) / rising_velocities(ibubble);
324 rising_vectors(ibubble, 2) = sum_velocity_z_indicator(ibubble) / rising_velocities(ibubble);
325 }
326 else
327 {
328 assert(gravity_dir >=0);
329 for (int l=0; l<3; l++)
330 if (l != gravity_dir)
331 rising_vectors(ibubble, gravity_dir) = 0.;
332 rising_vectors(ibubble, gravity_dir) = 1.;
333 }
334 }
335 }
336 else
337 {
338 for (int ibubble = 0; ibubble < nb_bubbles; ibubble++)
339 {
340 const double vel_x = (*bubbles_velocities_interf_bary)(ibubble, 0);
341 const double vel_y = (*bubbles_velocities_interf_bary)(ibubble, 1);
342 const double vel_z = (*bubbles_velocities_interf_bary)(ibubble, 2);
343 rising_velocities(ibubble) = sqrt( vel_x * vel_x + vel_y * vel_y + vel_z * vel_z);
344 if (rising_velocities(ibubble) > DMINFLOAT)
345 {
346 rising_vectors(ibubble, 0) = vel_x / rising_velocities(ibubble);
347 rising_vectors(ibubble, 1) = vel_y / rising_velocities(ibubble);
348 rising_vectors(ibubble, 2) = vel_z / rising_velocities(ibubble);
349 }
350 else
351 {
352 assert(gravity_dir >=0);
353 for (int l=0; l<3; l++)
354 if (l != gravity_dir)
355 rising_vectors(ibubble, gravity_dir) = 0.;
356 rising_vectors(ibubble, gravity_dir) = 1.;
357 }
358 }
359 }
360
361 // Reduce 4 mp_sum calls to 1 by using mp_sum_for_each
362 double liquid_velocity_x = liquid_velocity[0];
363 double liquid_velocity_y = liquid_velocity[1];
364 double liquid_velocity_z = liquid_velocity[2];
365 Process::mp_sum_for_each(sum_indicator_liquid, liquid_velocity_x, liquid_velocity_y, liquid_velocity_z);
366 liquid_velocity = {liquid_velocity_x, liquid_velocity_y, liquid_velocity_z};
367 liquid_velocity *= (1 / (1e-30 + sum_indicator_liquid));
368}
369
370void fill_rising_velocity_double(const IJK_Field_double * eulerian_compo_connex_ns,
371 const ArrOfDouble& rising_velocities,
372 IJK_Field_double& eulerian_rising_velocity)
373{
374 const int nk = (*eulerian_compo_connex_ns).nk();
375 const int nj = (*eulerian_compo_connex_ns).nj();
376 const int ni = (*eulerian_compo_connex_ns).ni();
377 for (int k = 0; k < nk; k++)
378 for (int j = 0; j < nj; j++)
379 for (int i = 0; i < ni; i++)
380 {
381 double compo_connex = (*eulerian_compo_connex_ns)(i,j,k);
382 int int_compo_connex = (int) compo_connex;
383 if (int_compo_connex >= 0)
384 {
385 eulerian_rising_velocity(i,j,k) = rising_velocities(int_compo_connex);
386 }
387 }
388}
389
390void fill_rising_velocity_int(const IJK_Field_int& eulerian_compo_connex_ns,
391 const ArrOfDouble& rising_velocities,
392 IJK_Field_double& eulerian_rising_velocity)
393{
394 const int nk = eulerian_compo_connex_ns.nk();
395 const int nj = eulerian_compo_connex_ns.nj();
396 const int ni = eulerian_compo_connex_ns.ni();
397 for (int k = 0; k < nk; k++)
398 for (int j = 0; j < nj; j++)
399 for (int i = 0; i < ni; i++)
400 {
401 int int_compo_connex = eulerian_compo_connex_ns(i,j,k);
402 if (int_compo_connex >= 0)
403 {
404 eulerian_rising_velocity(i,j,k) = rising_velocities(int_compo_connex);
405 }
406 }
407}
This class encapsulates all the information related to the eulerian mesh for TrioIJK.
Definition Domaine_IJK.h:47
int get_offset_local(int direction) const
Returns the local offset in requested direction.
double get_constant_delta(int direction) const
Returns the size of cells in a direction.
double get_origin(int direction) const
Returns the coordinate of the first node (global) of the mesh in the requested direction.
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
const Domaine_IJK & get_domaine() const
: class IJK_Interfaces
int get_nb_bulles_ghost(const int print=0) const
const IJK_Field_double & I() const
int get_nb_bulles_reelles() const
int ghost_compo_converter(const int i) const
void calculer_bounding_box_bulles(DoubleTab &bounding_box, int option_shear=0) const
void calculer_volume_bulles(ArrOfDouble &volumes, DoubleTab &centre_gravite) const
const IJK_Field_double & In_ft() const
static void mp_sum_for_each(T &arg1, T &arg2)
C++14 compatible mp_sum_for_each: combine multiple mp_sum calls into one collective operation Usage: ...
Definition Process.cpp:207
static void mp_sum_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:193
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
virtual void reset()
Definition TRUSTArray.h:240
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469