TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
IJK_Ghost_Fluid_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_Ghost_Fluid_tools.h>
17#include <IJK_Field_vector.h>
18#include <Probleme_base.h>
19#include <DebogIJK.h>
20
21#include <Operateur_IJK_elem_diff.h>
22
23static int decoder_numero_bulle(const int code)
24{
25 const int num_bulle = code >> 6;
26 return num_bulle;
27}
28
29static void extrapolate_with_elem_faces_connectivity(const Domaine_VF& domaine_vf,
30 const IJK_Field_double& distance,
31 IJK_Field_double& field,
32 const int stencil_width)
33{
34 const double invalid_test = INVALID_TEST;
35 const IntTab& elem_faces = domaine_vf.elem_faces();
36 const IntTab& faces_elem = domaine_vf.face_voisins();
37 const int nb_faces_elem = elem_faces.dimension(1);
38 const int nb_elem = elem_faces.dimension(0);
39 IJK_Field_double field_old;
40 // Use to locate the initial non-zero values
41 IJK_Field_double field_ini(field);
42 const Domaine_IJK& splitting_distance = distance.get_domaine();
43 /*
44 * n_iterations = stencil_width is the minimum to get a propagation of information from the interface to the border
45 * of the extrapolation. But doing more will lead to smoother values... And it probably costs close to nothing
46 */
47 const double n_iterations = 5 * stencil_width;
48 for (int iteration = 0; iteration < n_iterations; iteration++)
49 {
50 // Necessary !!!
51 // Copy the old field value as we do not want to use the current iteration values.
52 field_old = field;
53 // La valeur sur un element est la moyenne des valeurs sur les elements voisins
54 for (int i_elem = 0; i_elem < nb_elem; i_elem++)
55 {
56 // Do not touch field in interfacial cells.
57 // Iterate on other values.
58 const Int3 num_elem_ijk = splitting_distance.convert_packed_to_ijk_cell(i_elem);
59 const double d = distance(num_elem_ijk[DIRECTION_I],
60 num_elem_ijk[DIRECTION_J],
61 num_elem_ijk[DIRECTION_K]);
62 // const double interfacial_area_elem = interfacial_area(num_elem_ijk[DIRECTION_I],
63 // num_elem_ijk[DIRECTION_J],
64 // num_elem_ijk[DIRECTION_K]);
65 // Need a value of distance but don't overwrite the first calculated value
66 // if ((d > invalid_test) && (interfacial_area_elem < invalid_test))
67 const double field_ini_val = field_ini(num_elem_ijk[DIRECTION_I],
68 num_elem_ijk[DIRECTION_J],
69 num_elem_ijk[DIRECTION_K]);
70 if ((d > invalid_test) && (field_ini_val == 0))
71 {
72 double sum_field = 0.;
73 double coeff = 0.;
74 for (int i_face = 0; i_face < nb_faces_elem; i_face++)
75 {
76 const int face = elem_faces(i_elem, i_face);
77 const int neighbour = faces_elem(face, 0) + faces_elem(face, 1) - i_elem;
78 if (neighbour >= 0)
79 {
80 // Not a boundary...
81 const Int3 num_elem_neighbour_ijk = splitting_distance.convert_packed_to_ijk_cell(neighbour);
82 double field_neighbour = field_old(num_elem_neighbour_ijk[DIRECTION_I],
83 num_elem_neighbour_ijk[DIRECTION_J],
84 num_elem_neighbour_ijk[DIRECTION_K]);
85 const double distance_neighbour = distance(num_elem_neighbour_ijk[DIRECTION_I],
86 num_elem_neighbour_ijk[DIRECTION_J],
87 num_elem_neighbour_ijk[DIRECTION_K]);
88 // Don't use zero values
89 // if ((distance_neighbour > invalid_test) && (field_neighbour != 0))
90 // Use zero_values grad_T_ decreasing with distance
91 if (distance_neighbour > invalid_test)
92 {
93 // Give more weight in the smoothing to values closer to the interface:
94 if (fabs(distance_neighbour) < INVALID_TEST)
95 {
96 Cerr << "Distance is very much at zero whereas interfacial_area is zero too... Pathological case to be looked into closely. " << finl;
97 Cerr << "Contact TRUST support." << finl;
99 }
100 /*
101 * TODO: Check the difference between extrapoler_champ_elem
102 * and extrapolate from Convection_Diffusion_Temperature_FT_Disc.cpp
103 */
104// const double inv_distance_squared = 1./ (distance_neighbour * distance_neighbour);
105// sum_field += field_neighbour * inv_distance_squared;
106// coeff += inv_distance_squared;
107 sum_field += field_neighbour;
108 coeff++;
109 }
110 }
111 }
112 if (coeff > 0.)
113 {
114 field(num_elem_ijk[DIRECTION_I],
115 num_elem_ijk[DIRECTION_J],
116 num_elem_ijk[DIRECTION_K]) = sum_field / coeff;
117 }
118 }
119 }
120 field.echange_espace_virtuel(field.ghost());
121 }
122}
123
124static void extrapolate_with_ijk_indices(const IJK_Field_double& distance,
125 const IJK_Field_double& indicator,
126 IJK_Field_double& field,
127 const int& stencil_width,
128 const int& recompute_field_ini,
129 const int& zero_neighbour_value_mean,
130 const int& vapour_mixed_only,
131 const int& smooth_factor)
132{
133 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(3, "GFM - Extrapolate gfm temperature values");
134 // statistiques().begin_count(stat_counter);
135
136 const double invalid_test = INVALID_TEST;
137 const double n_iterations = zero_neighbour_value_mean ? smooth_factor * stencil_width : stencil_width;
138 const int ni = field.ni();
139 const int nj = field.nj();
140 const int nk = field.nk();
141 IJK_Field_double field_old;
142 IJK_Field_double field_ini = field;
143 for (int iteration = 0; iteration < n_iterations; iteration++)
144 {
145 field_old = field;
146 for (int k = 0; k < nk; k++)
147 for (int j = 0; j < nj; j++)
148 for (int i = 0; i < ni; i++)
149 {
150 const double indic = indicator(i,j,k);
151 const int vapour_mixed = !vapour_mixed_only ? 1 : (indic < LIQUID_INDICATOR_TEST);
152 if (vapour_mixed)
153 {
154 const double d = distance(i,j,k);
155 // const double field_ini_val = field_ini(i,j,k);
156 const double field_ini_val = (!zero_neighbour_value_mean && !recompute_field_ini) ? field_old(i,j,k) : field_ini(i,j,k);
157 if ((d > invalid_test) && (field_ini_val == 0))
158 {
159 double sum_field = 0.;
160 double coeff = 0.;
161 for (int l=0; l<6; l++)
162 {
163 const int ii = NEIGHBOURS_I[l];
164 const int jj = NEIGHBOURS_J[l];
165 const int kk = NEIGHBOURS_K[l];
166 const double distance_neighbour = distance(i+ii,j+jj,k+kk);
167 const double field_neighbour = field_old(i+ii,j+jj,k+kk);
168 const int neighbour_condition = zero_neighbour_value_mean ? 1 : (field_neighbour != 0);
169 // if (distance_neighbour > invalid_test)
170 // Don't use zero values
171 // if ((distance_neighbour > invalid_test) && field_neighbour != 0))
172 // Use zero_values grad_T_ decreasing with distance
173 if (distance_neighbour > invalid_test && neighbour_condition)
174 {
175 sum_field += field_neighbour;
176 coeff++;
177 }
178 }
179 if (coeff > 0.)
180 field(i,j,k) = sum_field / coeff;
181 }
182 }
183 }
184 field.echange_espace_virtuel(field.ghost());
185 }
186 // statistiques().end_count(stat_counter);
187}
188
189/*
190 * TODO: Store the facets' barycentres
191 */
192void compute_eulerian_normal_distance_facet_barycentre_field(const IJK_Interfaces& interfaces, // ref_problem_ft_disc,
193 IJK_Field_double& distance_field,
194 IJK_Field_vector3_double& normal_vect,
195 IJK_Field_vector3_double& facets_barycentre,
196 IJK_Field_vector3_double& tmp_old_vector_val,
197 IJK_Field_vector3_double& tmp_new_vector_val,
198 IJK_Field_double& tmp_old_val,
199 IJK_Field_double& tmp_new_val,
200 IJK_Field_int& tmp_interf_cells,
201 IJK_Field_int& tmp_propagated_cells,
202 FixedVector<ArrOfInt,3>& interf_cells_indices,
203 FixedVector<ArrOfInt,3>& gfm_first_cells_indices_,
204 FixedVector<ArrOfInt,3>& propagated_cells_indices,
205 const int& n_iter,
206 const int& avoid_gfm_parallel_calls)
207{
208 /*
209 * Compute the normal distance to the interface
210 */
211 const bool use_ijk = true;
212 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(2, "GFM - Compute Eulerian normal distance field");
213 // statistiques().begin_count(stat_counter);
214
215 static const double invalid_distance_value = INVALID_TEST;
216 const int dim = 3; // in IJK
217
218 // Vertex coordinates of the eulerian domain
219 const Domaine_dis_base& mon_dom_dis = interfaces.get_domaine_dis();
220 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, mon_dom_dis);
221 const DoubleTab& centre_element = domaine_vf.xp();
222
223 // Approximation of the normal distance
224 distance_field.data() = invalid_distance_value * 1.1;
225 for (int dir = 0; dir < dim; dir++)
226 normal_vect[dir].data() = 0.;
227
228 const int nb_elem = mon_dom_dis.domaine().nb_elem();
229
230 const Maillage_FT_IJK& maillage = interfaces.maillage_ft_ijk();
231
232 // Same splitting for the normal vector field
233 const Domaine_IJK& geom = distance_field.get_domaine();
234
235 for (int l=0; l<dim; l++)
236 {
237 interf_cells_indices[l].reset();
238 gfm_first_cells_indices_[l].reset();
239 propagated_cells_indices[l].reset();
240 }
241 tmp_interf_cells.data() = 0;
242 tmp_propagated_cells.data() = 0;
243
244 /*
245 * M.G: Copy of B.M from Transport_Interfaces_FT_Disc::calculer_distance_interface
246 * Distance calculation for the thickness 0 (vertices of the elements crossed by
247 * the interface). For each element, we calculate the plane intersecting the
248 * barycentre of the facets portions. The normal vector to the plane corresponds to
249 * the average normal vector weighting by the surface portions. The distance
250 * interface/element is the distance between this plane and the centre of the element.
251 */
252 {
253 const Intersections_Elem_Facettes& intersections = maillage.intersections_elem_facettes();
254 const ArrOfInt& index_elem = intersections.index_elem();
255 const DoubleTab& normale_facettes = maillage.get_update_normale_facettes();
256 const ArrOfDouble& surface_facettes = maillage.get_update_surface_facettes();
257 const IntTab& facettes = maillage.facettes();
258 const DoubleTab& sommets = maillage.sommets();
259 // Loop on the elements
260
261 for (int elem = 0; elem < nb_elem; elem++)
262 {
263 int index = index_elem[elem];
264 // Moyenne ponderee des normales aux facettes qui traversent l'element
265 double normale[3] = {0., 0., 0.};
266 // Barycentre of the facets/element intersections
267 double centre[3] = {0., 0., 0.};
268 // Sum of the weights
269 double surface_tot = 0.;
270 // Loop on the facets which cross the element
271 while (index >= 0)
272 {
274 intersections.data_intersection(index);
275
276 const int num_facette = data.numero_facette_;
277#ifdef AVEC_BUG_SURFACES
278 const double surface = data.surface_intersection_;
279#else
280 const double surface = data.fraction_surface_intersection_ * surface_facettes[num_facette];
281#endif
282 surface_tot += surface;
283 for (int i = 0; i < dim; i++)
284 {
285 normale[i] += surface * normale_facettes(num_facette, i);
286 // Barycentre calculation of the facets/element intersections
287 double g_i = 0.; // i-component of the barycentre coordinate
288 for (int j = 0; j < dim; j++)
289 {
290 const int som = facettes(num_facette, j);
291 const double coord = sommets(som, i);
292 const double coeff = data.barycentre_[j];
293 g_i += coord * coeff;
294 }
295 centre[i] += surface * g_i;
296 }
297 index = data.index_facette_suivante_;
298 }
299 const Int3 num_elem_ijk = geom.convert_packed_to_ijk_cell(elem);
300 if (surface_tot > 0.)
301 {
302 /*
303 * The stored vector is not normed : norm ~ surface portion
304 * centre = sum(centre[facet] * surface) / sum(surface)
305 */
306 const double inverse_surface_tot = 1. / surface_tot;
307 double norme = 0.;
308 int j;
309 for (j = 0; j < dim; j++)
310 {
311 norme += normale[j] * normale[j];
312 normal_vect[j](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = normale[j];
313 centre[j] *= inverse_surface_tot;
314 }
315
316 if (norme > 0)
317 {
318 double i_norme = 1./sqrt(norme);
319 double distance = 0.;
320 for (j = 0; j < dim; j++)
321 {
322 double n_j = normale[j] * i_norme; // normal vector normed
323 distance += (centre_element(elem, j) - centre[j]) * n_j;
324 }
325 distance_field(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = distance;
326 }
327
328 if (avoid_gfm_parallel_calls)
329 tmp_interf_cells(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = 1;
330
331 }
332 for (int j = 0; j < dim; j++)
333 facets_barycentre[j](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = centre[j];
334 }
335 distance_field.echange_espace_virtuel(distance_field.ghost());
336 normal_vect.echange_espace_virtuel();
337 tmp_interf_cells.echange_espace_virtuel(tmp_interf_cells.ghost());
338 for (int dir = 0; dir < dim; dir++)
339 DebogIJK::verifier("IJK_Ghost_Fluid_tools::compute_eulerian_normal_distance_field", normal_vect[dir]);
340 DebogIJK::verifier("IJK_Ghost_Fluid_tools::compute_eulerian_normal_distance_field", distance_field);
341 }
342
343 if (avoid_gfm_parallel_calls)
344 {
345 const int ni = tmp_interf_cells.ni();
346 const int nj = tmp_interf_cells.nj();
347 const int nk = tmp_interf_cells.nk();
348 const int nb_ghost = tmp_interf_cells.ghost();
349 for (int k = - nb_ghost; k < nk + nb_ghost; k++)
350 for (int j = - nb_ghost; j < nj + nb_ghost; j++)
351 for (int i = - nb_ghost; i < ni + nb_ghost; i++)
352 if (tmp_interf_cells(i,j,k))
353 for (int l=0; l<dim; l++)
354 {
355 const int index = select_dir(l, i, j, k);
356 interf_cells_indices[l].append_array(index);
357 }
358 }
359
360 // IJK_Field_vector3_double terme_src(normal_vect);
361 // IJK_Field_vector3_double tmp(normal_vect);
362 IJK_Field_vector3_double& terme_src = tmp_old_vector_val;
363 IJK_Field_vector3_double& tmp = tmp_new_vector_val;
364 for (int l=0; l<dim; l++)
365 {
366 terme_src[l].data() = normal_vect[l].data();
367 tmp[l].data() = normal_vect[l].data();
368 }
369
370 const IntTab& face_voisins = domaine_vf.face_voisins();
371 const IntTab& elem_faces = domaine_vf.elem_faces();
372 const int nb_elem_voisins = elem_faces.line_size();
373
374 // Normal vector calculation at the element location:
375 /*
376 * TODO: Check the how fast it is compared to using elem_faces matrix
377 */
378 tmp_propagated_cells.data() = tmp_interf_cells.data();
379 propagated_cells_indices = interf_cells_indices;
380 FixedVector<ArrOfInt,3> propagated_cells_indices_tmp;
381 for (int l=0; l<dim; l++)
382 propagated_cells_indices_tmp[l].resize_array(1);
383
384 int iteration;
385 const int n_iter_tmp = avoid_gfm_parallel_calls ? n_iter + 1: n_iter;
386
387 if (use_ijk)
388 {
389 const int ni = normal_vect[0].ni();
390 const int nj = normal_vect[0].nj();
391 const int nk = normal_vect[0].nk();
392 const int nghost = normal_vect[0].ghost();
393 int m;
394 for (iteration = 0; iteration < n_iter_tmp; iteration++)
395 {
396 /*
397 * Smoothing iterator, in theory:
398 * normal = normal + (source_term - laplacian(normal)) * factor
399 * converge towards laplacian(normal) = source_term
400 * in practice:
401 * normal = average(normal on neighbours) + source_term
402 */
403
404 const double un_sur_ncontrib = 1. / (1. + nb_elem_voisins);
405 if (avoid_gfm_parallel_calls)
406 {
407 propagated_cells_indices_tmp = propagated_cells_indices;
408
409 for (int ielem = 0; ielem < propagated_cells_indices_tmp[0].size_array(); ielem++)
410 {
411 const int i = propagated_cells_indices_tmp[DIRECTION_I](ielem);
412 const int j = propagated_cells_indices_tmp[DIRECTION_J](ielem);
413 const int k = propagated_cells_indices_tmp[DIRECTION_K](ielem);
414
415 // Averaging the normal vector on the neighbours
416 double n[3] = {0., 0., 0.};
417 for (m = 0; m < dim; m++)
418 n[m] = normal_vect[m](i,j,k);
419 for (int l=0; l<6; l++)
420 {
421 const int ii = NEIGHBOURS_I[l];
422 const int jj = NEIGHBOURS_J[l];
423 const int kk = NEIGHBOURS_K[l];
424
425 const int is_outside_proc = (i + ii < -nghost || j + jj < -nghost || k + kk < -nghost)
426 || (i + ii >= ni + nghost || j + jj >= nj + nghost || k + kk >= nk + nghost);
427 if (!is_outside_proc)
428 {
429 for (m = 0; m < dim; m++)
430 n[m] += normal_vect[m](i+ii,j+jj,k+kk);
431
432 if (!tmp_propagated_cells(i+ii,j+jj,k+kk))
433 {
434 const Int3 ijk_index(i+ii, j+jj, k+kk);
435 for (m=0; m<dim; m++)
436 propagated_cells_indices[m].append_array(ijk_index[m]);
437 tmp_propagated_cells(i+ii,j+jj,k+kk) = 1;
438 if (!iteration)
439 for (m=0; m<dim; m++)
440 gfm_first_cells_indices_[m].append_array(ijk_index[m]);
441 }
442 }
443 }
444 for (m = 0; m < dim; m++)
445 tmp[m](i,j,k) = terme_src[m](i,j,k) + n[m] * un_sur_ncontrib;
446 }
447 for (int l=0; l<dim; l++)
448 normal_vect[l].data() = tmp[l].data();
449 }
450 else
451 {
452 for (int k = 0; k < nk; k++)
453 for (int j = 0; j < nj; j++)
454 for (int i = 0; i < ni; i++)
455 {
456 // Averaging the normal vector on the neighbours
457 double n[3] = {0., 0., 0.};
458 for (m = 0; m < dim; m++)
459 n[m] = normal_vect[m](i,j,k);
460 for (int l=0; l<6; l++)
461 {
462 const int ii = NEIGHBOURS_I[l];
463 const int jj = NEIGHBOURS_J[l];
464 const int kk = NEIGHBOURS_K[l];
465 for (m = 0; m < dim; m++)
466 n[m] += normal_vect[m](i+ii,j+jj,k+kk);
467 }
468 for (m = 0; m < dim; m++)
469 tmp[m](i,j,k) = terme_src[m](i,j,k) + n[m] * un_sur_ncontrib;
470 }
471 for (int l=0; l<dim; l++)
472 normal_vect[l].data() = tmp[l].data();
473 normal_vect.echange_espace_virtuel();
474 }
475 }
476 }
477 else
478 {
479 for (iteration = 0; iteration < n_iter; iteration++)
480 {
481 /*
482 * Smoothing iterator, in theory:
483 * normal = normal + (source_term - laplacian(normal)) * factor
484 * converge towards laplacian(normal) = source_term
485 * in practice:
486 * normal = average(normal on neighbours) + source_term
487 */
488 const double un_sur_ncontrib = 1. / (1. + nb_elem_voisins);
489 int elem, i, k;
490 for (elem = 0; elem < nb_elem; elem++)
491 {
492 // Averaging the normal vector on the neighbours
493 double n[3] = {0., 0., 0.};
494 const Int3 num_elem_ijk = geom.convert_packed_to_ijk_cell(elem);
495 for (i = 0; i < dim; i++)
496 {
497 n[i] = normal_vect[i](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
498 }
499 for (k = 0; k < nb_elem_voisins; k++)
500 {
501 // We look for the neighbour by face k
502 const int face = elem_faces(elem, k);
503 const int e_voisin = face_voisins(face, 0) + face_voisins(face, 1) - elem;
504 const Int3 num_elem_voisin_ijk = geom.convert_packed_to_ijk_cell(e_voisin);
505 if (e_voisin >= 0) // Not on a boundary
506 for (i = 0; i < dim; i++)
507 n[i] += normal_vect[i](num_elem_voisin_ijk[DIRECTION_I],num_elem_voisin_ijk[DIRECTION_J],num_elem_voisin_ijk[DIRECTION_K]);
508 }
509 for (i = 0; i < dim; i++)
510 {
511 tmp[i](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) =
512 terme_src[i](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) + n[i] * un_sur_ncontrib;
513 }
514 }
515 normal_vect = tmp;
516 normal_vect.echange_espace_virtuel();
517 }
518 }
519 /*
520 * We normalise the normal vector and we create a list of elements
521 * for whom the normal is known
522 */
523 ArrOfIntFT liste_elements;
524 if (!use_ijk)
525 {
526 int elem;
527 for (elem = 0; elem < nb_elem; elem++)
528 {
529 const Int3 num_elem_ijk = geom.convert_packed_to_ijk_cell(elem);
530 double nx = normal_vect[0](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
531 double ny = normal_vect[1](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
532 double nz = normal_vect[2](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
533 double norme2 = nx*nx + ny*ny + nz*nz;
534 if (norme2 > 0.)
535 {
536 double i_norme = 1. / sqrt(norme2);
537 normal_vect[0](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = nx * i_norme;
538 normal_vect[1](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = ny * i_norme;
539 normal_vect[2](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = nz * i_norme;
540 liste_elements.append_array(elem);
541 }
542 }
543 normal_vect.echange_espace_virtuel(); // This swap is essential ?
544 }
545 else
546 {
547 if (!avoid_gfm_parallel_calls)
548 normal_vect.echange_espace_virtuel(); // This swap is essential ?
549 }
550 // Distance calculation at the interface
551 /*
552 * TODO: Check the how fast it is compared to using elem_faces matrix
553 */
554 // IJK_Field_double terme_src_dist(distance_field);
555 // IJK_Field_double tmp_dist(distance_field);
556 IJK_Field_double& terme_src_dist = tmp_old_val;
557 IJK_Field_double& tmp_dist = tmp_new_val;
558 terme_src_dist.data() = distance_field.data();
559 tmp_dist.data() = distance_field.data();
560
561 tmp_propagated_cells.data() = tmp_interf_cells.data();
562 propagated_cells_indices = gfm_first_cells_indices_;
563 for (int l=0; l<dim; l++)
564 propagated_cells_indices_tmp[l].reset();
565
566 if (use_ijk)
567 {
568 const int ni = normal_vect[0].ni();
569 const int nj = normal_vect[0].nj();
570 const int nk = normal_vect[0].nk();
571 const int nghost = normal_vect[0].ghost();
572 int m;
573 for (iteration = 0; iteration < n_iter; iteration++)
574 {
575 if (avoid_gfm_parallel_calls)
576 {
577 propagated_cells_indices_tmp = propagated_cells_indices;
578 for (int l=0; l<dim; l++)
579 propagated_cells_indices[l].reset();
580 for (int ielem = 0; ielem < propagated_cells_indices_tmp[0].size_array(); ielem++)
581 {
582 const int i = propagated_cells_indices_tmp[DIRECTION_I](ielem);
583 const int j = propagated_cells_indices_tmp[DIRECTION_J](ielem);
584 const int k = propagated_cells_indices_tmp[DIRECTION_K](ielem);
585
586 // For all the element already crossed by the interface, the value is not computed again
587 if (terme_src_dist(i,j,k) > invalid_distance_value)
588 tmp_dist(i,j,k) = distance_field(i,j,k);
589 else
590 {
591 if (!tmp_propagated_cells(i,j,k))
592 tmp_propagated_cells(i,j,k) = 1;
593 // For the others, we compute a distance value per neighbour
594 double ncontrib = 0.;
595 double somme_distances = 0.;
596 for (int l = 0; l < 6; l++)
597 {
598 // Look for a neighbour
599 const int ii = NEIGHBOURS_I[l];
600 const int jj = NEIGHBOURS_J[l];
601 const int kk = NEIGHBOURS_K[l];
602
603 const int is_outside_proc = (i + ii < -nghost || j + jj < -nghost || k + kk < -nghost)
604 || (i + ii >= ni + nghost || j + jj >= nj + nghost || k + kk >= nk + nghost);
605 if (!is_outside_proc)
606 {
607 const Int3 ijk_index(i+ii, j+jj, k+kk);
608 if (!tmp_propagated_cells(i+ii,j+jj,k+kk))
609 {
610 for (m=0; m<dim; m++)
611 propagated_cells_indices[m].append_array(ijk_index[m]);
612 tmp_propagated_cells(i+ii,j+jj,k+kk) = 1;
613 }
614
615 const double distance_voisin = distance_field(i+ii, j+jj, k+kk);
616 if (distance_voisin > invalid_distance_value)
617 {
618 // Average normal distance between an element and its neighbours
619 double nx = normal_vect[0](i,j,k) + normal_vect[0](i+ii, j+jj, k+kk);
620 double ny = normal_vect[1](i,j,k) + normal_vect[1](i+ii, j+jj, k+kk);
621 double nz = normal_vect[2](i,j,k) + normal_vect[2](i+ii, j+jj, k+kk);
622 double norm2 = nx*nx + ny*ny + nz*nz;
623 if (norm2 > 0.)
624 {
625 double i_norm = 1./sqrt(norm2);
626 nx *= i_norm;
627 ny *= i_norm;
628 nz *= i_norm;
629 }
630 // Element to neighbour vector calculation
631 double dx = - geom.get_constant_delta(DIRECTION_I) * ii;
632 double dy = - geom.get_constant_delta(DIRECTION_J) * jj;
633 double dz = - geom.get_constant_delta(DIRECTION_K) * kk;
634 double d = nx * dx + ny * dy + nz * dz + distance_voisin;
635 somme_distances += d;
636 ncontrib++;
637 }
638 }
639 }
640 // Averaging the distances obtained from neighbours
641 if (ncontrib > 0.)
642 {
643 double d = somme_distances / ncontrib;
644 tmp_dist(i,j,k) = d;
645 }
646 }
647 }
648 distance_field.data() = tmp_dist.data();
649 }
650 else
651 {
652 for (int k = 0; k < nk; k++)
653 for (int j = 0; j < nj; j++)
654 for (int i = 0; i < ni; i++)
655 {
656 // For all the element already crossed by the interface, the value is not computed again
657 if (terme_src_dist(i,j,k) > invalid_distance_value)
658 tmp_dist(i,j,k) = distance_field(i,j,k);
659 else
660 {
661 // For the others, we compute a distance value per neighbour
662 double ncontrib = 0.;
663 double somme_distances = 0.;
664 for (int l = 0; l < 6; l++)
665 {
666 // Look for a neighbour
667 const int ii = NEIGHBOURS_I[l];
668 const int jj = NEIGHBOURS_J[l];
669 const int kk = NEIGHBOURS_K[l];
670 const double distance_voisin = distance_field(i+ii, j+jj, k+kk);
671 if (distance_voisin > invalid_distance_value)
672 {
673 // Average normal distance between an element and its neighbours
674 double nx = normal_vect[0](i,j,k) + normal_vect[0](i+ii, j+jj, k+kk);
675 double ny = normal_vect[1](i,j,k) + normal_vect[1](i+ii, j+jj, k+kk);
676 double nz = normal_vect[2](i,j,k) + normal_vect[2](i+ii, j+jj, k+kk);
677 double norm2 = nx*nx + ny*ny + nz*nz;
678 if (norm2 > 0.)
679 {
680 double i_norm = 1./sqrt(norm2);
681 nx *= i_norm;
682 ny *= i_norm;
683 nz *= i_norm;
684 }
685 // Element to neighbour vector calculation
686 double dx = - geom.get_constant_delta(DIRECTION_I) * ii;
687 double dy = - geom.get_constant_delta(DIRECTION_J) * jj;
688 double dz = - geom.get_constant_delta(DIRECTION_K) * kk;
689 double d = nx * dx + ny * dy + nz * dz + distance_voisin;
690 somme_distances += d;
691 ncontrib++;
692 }
693 }
694 // Averaging the distances obtained from neighbours
695 if (ncontrib > 0.)
696 {
697 double d = somme_distances / ncontrib;
698 tmp_dist(i,j,k) = d;
699 }
700 }
701 }
702 distance_field.data() = tmp_dist.data();
703 distance_field.echange_espace_virtuel(distance_field.ghost());
704 }
705 }
706 }
707 else
708 {
709 for (iteration = 0; iteration < n_iter; iteration++)
710 {
711 int i_elem, elem;
712 const int liste_elem_size = liste_elements.size_array();
713 for (i_elem = 0; i_elem < liste_elem_size; i_elem++)
714 {
715 elem = liste_elements[i_elem];
716 const Int3 num_elem_ijk = geom.convert_packed_to_ijk_cell(elem);
717 if (terme_src_dist(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) > invalid_distance_value)
718 {
719 // For all the element already crossed by the interface, the value is not computed again
720 tmp_dist(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = distance_field(num_elem_ijk[DIRECTION_I],
721 num_elem_ijk[DIRECTION_J],
722 num_elem_ijk[DIRECTION_K]);
723 }
724 else
725 {
726 // For the others, we compute a distance value per neighbour
727 double ncontrib = 0.;
728 double somme_distances = 0.;
729 int k;
730 for (k = 0; k < nb_elem_voisins; k++)
731 {
732 // Look for a neighbour by the face k
733 const int face = elem_faces(elem, k);
734 const int e_voisin = face_voisins(face, 0) + face_voisins(face, 1) - elem;
735 const Int3 num_elem_voisin_ijk = geom.convert_packed_to_ijk_cell(e_voisin);
736 if (e_voisin >= 0) // Not on a boundary
737 {
738 const double distance_voisin = distance_field(num_elem_voisin_ijk[DIRECTION_I],
739 num_elem_voisin_ijk[DIRECTION_J],
740 num_elem_voisin_ijk[DIRECTION_K]);
741 if (distance_voisin > invalid_distance_value)
742 {
743 // Average normal distance between an element and its neighbours
744 double nx = normal_vect[0](num_elem_ijk[DIRECTION_I],
745 num_elem_ijk[DIRECTION_J],
746 num_elem_ijk[DIRECTION_K]) +
747 normal_vect[0](num_elem_voisin_ijk[DIRECTION_I],
748 num_elem_voisin_ijk[DIRECTION_J],
749 num_elem_voisin_ijk[DIRECTION_K]);
750 double ny = normal_vect[1](num_elem_ijk[DIRECTION_I],
751 num_elem_ijk[DIRECTION_J],
752 num_elem_ijk[DIRECTION_K]) +
753 normal_vect[1](num_elem_voisin_ijk[DIRECTION_I],
754 num_elem_voisin_ijk[DIRECTION_J],
755 num_elem_voisin_ijk[DIRECTION_K]);
756 double nz = normal_vect[2](num_elem_ijk[DIRECTION_I],
757 num_elem_ijk[DIRECTION_J],
758 num_elem_ijk[DIRECTION_K]) +
759 normal_vect[2](num_elem_voisin_ijk[DIRECTION_I],
760 num_elem_voisin_ijk[DIRECTION_J],
761 num_elem_voisin_ijk[DIRECTION_K]);
762 double norm2 = nx*nx + ny*ny + nz*nz;
763 if (norm2 > 0.)
764 {
765 double i_norm = 1./sqrt(norm2);
766 nx *= i_norm;
767 ny *= i_norm;
768 nz *= i_norm;
769 }
770 // Element to neighbour vector calculation
771 double dx = centre_element(elem, 0) - centre_element(e_voisin, 0);
772 double dy = centre_element(elem, 1) - centre_element(e_voisin, 1);
773 double dz = centre_element(elem, 2) - centre_element(e_voisin, 2);
774 double d = nx * dx + ny * dy + nz * dz + distance_voisin;
775 somme_distances += d;
776 ncontrib++;
777 }
778 }
779 }
780 // Averaging the distances obtained from neighbours
781 if (ncontrib > 0.)
782 {
783 double d = somme_distances / ncontrib;
784 tmp_dist(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = d;
785 }
786 }
787 }
788 distance_field = tmp_dist;
789 distance_field.echange_espace_virtuel(distance_field.ghost());
790 }
791 }
792 if (avoid_gfm_parallel_calls)
793 {
794 normal_vect.echange_espace_virtuel();
795 distance_field.echange_espace_virtuel(distance_field.ghost());
796 }
797
798 // statistiques().end_count(stat_counter);
799}
800
801void compute_eulerian_curvature_field_from_distance_field(const IJK_Field_double& distance,
802 IJK_Field_double& curvature,
803 const IJK_Field_local_double& boundary_flux_kmin,
804 const IJK_Field_local_double& boundary_flux_kmax)
805{
806 /*
807 * Compute the divergence of the normal vector field or the laplacian of the eulerian distance field
808 */
809 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(2, "GFM - Compute Eulerian curvature dield from distance field");
810 // statistiques().begin_count(stat_counter);
811
812 // Laplacian operator
813 Operateur_IJK_elem_diff laplacian_distance;
814 laplacian_distance.typer_diffusion_op("uniform");
815 // Initialise with unit lambda
816 laplacian_distance.initialize(distance.get_domaine());
817 const double lambda = 1.;
818 laplacian_distance->set_uniform_lambda(lambda);
819 // Calculate Laplacian(dist)
820 laplacian_distance->calculer(distance, curvature, boundary_flux_kmin, boundary_flux_kmax);
821 const Domaine_IJK& geom = curvature.get_domaine();
822 const double dx = geom.get_constant_delta(DIRECTION_I);
823 const double dy = geom.get_constant_delta(DIRECTION_J);
824 const double dz = geom.get_constant_delta(DIRECTION_K);
825 const double vol = dx * dy * dz;
826 const int nx = curvature.ni();
827 const int ny = curvature.nj();
828 const int nz = curvature.nk();
829 for (int k=0; k < nz ; k++)
830 for (int j=0; j< ny; j++)
831 for (int i=0; i < nx; i++)
832 curvature(i,j,k) /= vol;
833 curvature.echange_espace_virtuel(curvature.ghost());
834
835 // statistiques().end_count(stat_counter);
836}
837
838void compute_eulerian_curvature_field_from_normal_vector_field(const IJK_Field_vector3_double& normal_vect,
839 IJK_Field_double& curvature)
840{
841
842}
843
844void compute_eulerian_curvature_field_from_interface(const IJK_Field_vector3_double& normal_vect,
845 const IJK_Interfaces& interfaces,
846 IJK_Field_double& interfacial_area,
847 IJK_Field_double& curvature,
848 IJK_Field_double& tmp_old_val,
849 IJK_Field_double& tmp_new_val,
850 const int& n_iter,
851 const int igroup)
852{
853 /*
854 * From IJK_Interfaces::calculer_normales_et_aires_interfaciales
855 * Called in update_stat_ft IJK_FT through an instance of IJK_FT_Post !!!!!
856 */
857 const bool use_ijk = true;
858 // Vertex coordinates of the eulerian domain
859 interfacial_area.echange_espace_virtuel(interfacial_area.ghost());
860 curvature.echange_espace_virtuel(curvature.ghost());
861
862 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(2, "GFM - Compute Eulerian Curvature field from interface");
863 // statistiques().begin_count(stat_counter);
864
865 static const double invalid_curvature_value = INVALID_TEST;
866
867 interfacial_area.data() = invalid_curvature_value * 1.1;
868 curvature.data() = invalid_curvature_value * 1.1;
869
870 // Vertex coordinates of the eulerian domain
871 const Domaine_dis_base& mon_dom_dis = interfaces.get_domaine_dis();
872 const int nb_elem = mon_dom_dis.domaine().nb_elem();
873 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, mon_dom_dis);
874 const Domaine_IJK& splitting_curvature = normal_vect.get_domaine();
875
876 const Maillage_FT_IJK& maillage = interfaces.maillage_ft_ijk();
877 const Intersections_Elem_Facettes& intersections = maillage.intersections_elem_facettes();
878 const ArrOfDouble& surface_facettes = maillage.get_update_surface_facettes();
879 const IntTab& facettes = maillage.facettes();
880 const ArrOfDouble& courbure = maillage.get_update_courbure_sommets();
881
882 const int n_fa7 = maillage.nb_facettes();
883 // Calculate the curvature in the cells crossed by the interface
884 const ArrOfInt& compo_facette = maillage.compo_connexe_facettes();
885 const ArrOfInt& compo_to_group = interfaces.get_compo_to_group();
886 for (int fa7 = 0; fa7 < n_fa7; fa7++)
887 {
888 int icompo = compo_facette[fa7];
889 if (icompo<0)
890 {
891 // Portion d'interface ghost. On recherche le vrai numero
892 icompo = decoder_numero_bulle(-icompo);
893 }
894 if ((compo_to_group[icompo] != igroup) && (igroup != -1))
895 continue;
896 const double sf = surface_facettes[fa7];
897 int index = intersections.index_facette()[fa7];
898 while (index >= 0)
899 {
900 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
901 const int num_elem = data.numero_element_;
902 const Int3 ijk = splitting_curvature.convert_packed_to_ijk_cell(num_elem);
903 const double surf = data.fraction_surface_intersection_ * sf;
904 for (int isom = 0; isom < 3; isom++)
905 {
906 const int num_som = facettes(fa7, isom);
907 const double kappa = courbure[num_som];
908 // No volume consideration
909 if (curvature(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) < invalid_curvature_value)
910 curvature(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) = kappa * surf / 3.;
911 else
912 curvature(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) += kappa * surf / 3.;
913 }
914 if (interfacial_area(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) < invalid_curvature_value)
915 interfacial_area(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) = surf;
916 else
917 interfacial_area(ijk[DIRECTION_I], ijk[DIRECTION_J], ijk[DIRECTION_K]) += surf;
918 index = data.index_element_suivant_;
919 }
920 }
921 interfacial_area.echange_espace_virtuel(interfacial_area.ghost());
922 curvature.echange_espace_virtuel(curvature.ghost());
923
924 {
925 const int nx = curvature.ni();
926 const int ny = curvature.nj();
927 const int nz = curvature.nk();
928 for (int k=0; k < nz ; k++)
929 for (int j=0; j< ny; j++)
930 for (int i=0; i < nx; i++)
931 {
932 const double kappa = curvature(i,j,k);
933 const double ai = interfacial_area(i,j,k);
934 // TODO: Why do I get a floating point exception ? Interface portion too small ?
935 if ((kappa > invalid_curvature_value) && (ai > invalid_curvature_value))
936 {
937 if (fabs(ai) < DMINFLOAT)
938 {
939 Cerr << "Interfacial_area is very much at zero... Pathological case to be looked into closely. " << finl;
940 Cerr << "Curvature is set to invalid value to be overwritten by its neighbours" << finl;
941 // Be careful if the distance is not calculated well the spreading algorithm will not work
942 curvature(i,j,k) = invalid_curvature_value * 1.1;
943 // Process::exit();
944 }
945 else
946 {
947 curvature(i,j,k) = kappa / ai;
948 }
949 }
950 }
951 }
952 interfacial_area.echange_espace_virtuel(interfacial_area.ghost());
953 curvature.echange_espace_virtuel(curvature.ghost());
954
955 // Get back the cells filled with non-zero normal vectors
956 ArrOfIntFT liste_elements;
957 if (!use_ijk)
958 {
959 for (int elem = 0; elem < nb_elem; elem++)
960 {
961 const Int3 num_elem_ijk = splitting_curvature.convert_packed_to_ijk_cell(elem);
962 double nx = normal_vect[0](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
963 double ny = normal_vect[1](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
964 double nz = normal_vect[2](num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]);
965 double norme2 = nx*nx + ny*ny + nz*nz;
966 if (norme2 > 0.)
967 liste_elements.append_array(elem);
968 }
969 }
970
971 // Curvature calculation at the interface
972 // IJK_Field_double terme_src_curv(curvature);
973 // IJK_Field_double tmp_curv(curvature);
974
975 IJK_Field_double& terme_src_curv = tmp_old_val;
976 IJK_Field_double& tmp_curv = tmp_new_val;
977 terme_src_curv.data() = curvature.data();
978 tmp_curv.data() = curvature.data();
979
980 /*
981 * TODO: Check the how fast it is compared to using elem_faces matrix
982 */
983 if (use_ijk)
984 {
985 const int ni = normal_vect[0].ni();
986 const int nj = normal_vect[0].nj();
987 const int nk = normal_vect[0].nk();
988 for (int iteration = 0; iteration < n_iter; iteration++)
989 {
990 for (int k = 0; k < nk; k++)
991 for (int j = 0; j < nj; j++)
992 for (int i = 0; i < ni; i++)
993 {
994 // For all the element already crossed by the interface, the value is not computed again
995 if (terme_src_curv(i,j,k) > invalid_curvature_value)
996 tmp_curv(i,j,k) = curvature(i,j,k);
997 else
998 {
999 // For the others, we compute a distance value per neighbour
1000 double ncontrib = 0.;
1001 double sum_kappa = 0.;
1002 for (int l = 0; l < 6; l++)
1003 {
1004 // Look for a neighbour
1005 const int ii = NEIGHBOURS_I[l];
1006 const int jj = NEIGHBOURS_J[l];
1007 const int kk = NEIGHBOURS_K[l];
1008 const double curvature_voisin = curvature(i+ii,j+jj,k+kk);
1009 if (curvature_voisin > invalid_curvature_value)
1010 {
1011 // Average normal distance between an element and its neighbours
1012 sum_kappa += curvature_voisin;
1013 ncontrib++;
1014 }
1015 }
1016 // Averaging the distances obtained from neighbours
1017 if (ncontrib > 0.)
1018 {
1019 double kappa = sum_kappa / ncontrib;
1020 tmp_curv(i,j,k) = kappa;
1021 }
1022 }
1023 }
1024 curvature.data() = tmp_curv.data();
1025 curvature.echange_espace_virtuel(curvature.ghost());
1026 }
1027 }
1028 else
1029 {
1030 const IntTab& face_voisins = domaine_vf.face_voisins();
1031 const IntTab& elem_faces = domaine_vf.elem_faces();
1032 const int nb_elem_voisins = elem_faces.line_size();
1033 for (int iteration = 0; iteration < n_iter; iteration++)
1034 {
1035 int i_elem, elem;
1036 const int liste_elem_size = liste_elements.size_array();
1037 for (i_elem = 0; i_elem < liste_elem_size; i_elem++)
1038 {
1039 elem = liste_elements[i_elem];
1040 const Int3 num_elem_ijk = splitting_curvature.convert_packed_to_ijk_cell(elem);
1041 if (terme_src_curv(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) > invalid_curvature_value)
1042 {
1043 // For all the element already crossed by the interface, the value is not computed again
1044 tmp_curv(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = curvature(num_elem_ijk[DIRECTION_I],
1045 num_elem_ijk[DIRECTION_J],
1046 num_elem_ijk[DIRECTION_K]);
1047 }
1048 else
1049 {
1050 // For the others, we compute a distance value per neighbour
1051 double ncontrib = 0.;
1052 double sum_kappa = 0.;
1053 int k;
1054 for (k = 0; k < nb_elem_voisins; k++)
1055 {
1056 // Look for a neighbour by the face k
1057 const int face = elem_faces(elem, k);
1058 const int e_voisin = face_voisins(face, 0) + face_voisins(face, 1) - elem;
1059 const Int3 num_elem_voisin_ijk = splitting_curvature.convert_packed_to_ijk_cell(e_voisin);
1060 if (e_voisin >= 0) // Not on a boundary
1061 {
1062 const double curvature_voisin = curvature(num_elem_voisin_ijk[DIRECTION_I],
1063 num_elem_voisin_ijk[DIRECTION_J],
1064 num_elem_voisin_ijk[DIRECTION_K]);
1065 if (curvature_voisin > invalid_curvature_value)
1066 {
1067 // Average normal distance between an element and its neighbours
1068 sum_kappa += curvature_voisin;
1069 ncontrib++;
1070 }
1071 }
1072 }
1073 // Averaging the distances obtained from neighbours
1074 if (ncontrib > 0.)
1075 {
1076 double kappa = sum_kappa / ncontrib;
1077 tmp_curv(num_elem_ijk[DIRECTION_I], num_elem_ijk[DIRECTION_J], num_elem_ijk[DIRECTION_K]) = kappa;
1078 }
1079 }
1080 }
1081 curvature = tmp_curv;
1082 curvature.echange_espace_virtuel(curvature.ghost());
1083 }
1084 }
1085 // statistiques().end_count(stat_counter);
1086}
1087
1088void compute_eulerian_normal_temperature_gradient_interface(const IJK_Field_double& distance,
1089 const IJK_Field_double& indicator,
1090 const IJK_Field_double& interfacial_area,
1091 const IJK_Field_double& curvature,
1092 const IJK_Field_double& temperature,
1093 IJK_Field_double& grad_T_interface,
1094 const int& spherical_approx,
1095 const double& temperature_interf)
1096{
1097 /*
1098 * Compute the normal temperature gradient at the bubble interface
1099 * Write in the ijk manner !
1100 */
1101 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(3, "GFM - Compute Eulerian normal temperature gradient interface");
1102 // statistiques().begin_count(stat_counter);
1103
1104
1105 static const double invalid_value = INVALID_TEST;
1106 static const double liquid_indicator = LIQUID_INDICATOR_TEST;
1107 const int ni = temperature.ni();
1108 const int nj = temperature.nj();
1109 const int nk = temperature.nk();
1110
1111 // grad_T_interface.data() = 1.1 * invalid_value;
1112 grad_T_interface.data() = 0.;
1113 grad_T_interface.echange_espace_virtuel(grad_T_interface.ghost());
1114
1115 for (int k = 0; k < nk; k++)
1116 for (int j = 0; j < nj; j++)
1117 for (int i = 0; i < ni; i++)
1118 {
1119 const double ai = interfacial_area(i,j,k);
1120 if (ai > invalid_value)
1121 {
1122 for (int l=0; l < 6; l++)
1123 {
1124 const int ii = NEIGHBOURS_I[l];
1125 const int jj = NEIGHBOURS_J[l];
1126 const int kk = NEIGHBOURS_K[l];
1127 const double d = distance(i+ii,j+jj,k+kk);
1128 const double indic = indicator(i+ii,j+jj,k+kk);
1129 // if ((indic > liquid_indicator) && (d > invalid_value) && grad_T_interface(i+ii,j+jj,k+kk) < invalid_value)
1130 if ((indic > liquid_indicator) && (d > invalid_value) && grad_T_interface(i+ii,j+jj,k+kk) == 0)
1131 {
1132 const double temperature_liquid = temperature(i+ii,j+jj,k+kk);
1133 const double second_order_gradient = (temperature_liquid - temperature_interf) / d;
1134 const double kappa = curvature(i+ii,j+jj,k+kk);
1135 double grad_T_modified = 0.;
1136 // TODO: Check sign kappa
1137 if (spherical_approx)
1138 grad_T_modified = second_order_gradient * (1. - 0.5 * kappa * d);
1139 else
1140 {
1141 const double kappa_non_zero = kappa + 1.e-16;
1142 grad_T_modified = pow((d / 2. - 2. / kappa_non_zero),2) * second_order_gradient / (pow((0. - 2. / kappa_non_zero),2) + 1e-16);
1143 }
1144 grad_T_interface(i+ii,j+jj,k+kk) = grad_T_modified;
1145 }
1146 }
1147 }
1148 }
1149 grad_T_interface.echange_espace_virtuel(grad_T_interface.ghost());
1150 // statistiques().end_count(stat_counter);
1151 /*
1152 * Check if indicatrice of the neighbours is zero + interfacial_area to locate the mixed cells
1153 */
1154}
1155
1156void propagate_eulerian_normal_temperature_gradient_interface(const IJK_Interfaces& interfaces,
1157 const IJK_Field_double& distance,
1158 IJK_Field_double& grad_T_interface,
1159 const int& stencil_width,
1160 const int& recompute_field_ini,
1161 const int& zero_neighbour_value_mean,
1162 const int& vapour_mixed_only,
1163 const int& smooth_factor)
1164{
1165 /*
1166 * Propagate value of grad_T_int stored in pure liquid phase towards the vapour phase and mixed cells
1167 */
1168 const bool use_ijk = true;
1169 if (use_ijk)
1170 {
1171 // Using the ijk indices
1172 extrapolate_with_ijk_indices(distance,
1173 interfaces.I_ft(),
1174 grad_T_interface,
1175 stencil_width,
1176 recompute_field_ini,
1177 zero_neighbour_value_mean,
1178 vapour_mixed_only,
1179 smooth_factor);
1180 }
1181 else
1182 {
1183 // Using the elem_faces connectivity matrix of TrioCFD
1184 const Domaine_dis_base& mon_dom_dis = interfaces.get_domaine_dis();
1185 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, mon_dom_dis);
1186 extrapolate_with_elem_faces_connectivity(domaine_vf, distance, grad_T_interface, stencil_width);
1187 }
1188}
1189
1190void compute_eulerian_extended_temperature(const IJK_Field_double& indicator,
1191 const IJK_Field_double& distance,
1192 const IJK_Field_double& curvature,
1193 IJK_Field_double& grad_T_interface,
1194 IJK_Field_double& temperature,
1195 const int& spherical_approx,
1196 const double& temperature_interf)
1197{
1198 /*
1199 * Compute the extended temperature field using propagated values of the temperature gradient
1200 */
1201 // static const Stat_Counter_Id stat_counter = statistiques().new_counter(3, "GFM - Compute Eulerian ghost fluid temperature extension");
1202 // statistiques().begin_count(stat_counter);
1203
1204 const double invalid_test = INVALID_TEST;
1205 const int ni = temperature.ni();
1206 const int nj = temperature.nj();
1207 const int nk = temperature.nk();
1208 for (int k = 0; k < nk; k++)
1209 for (int j = 0; j < nj; j++)
1210 for (int i = 0; i < ni; i++)
1211 {
1212 const double indicator_vapour = fabs(1 - indicator(i,j,k));
1213 const double d = distance(i,j,k);
1214 const double grad_T = grad_T_interface(i,j,k);
1215 const double temperature_val = temperature(i,j,k);
1216 if ((d > invalid_test) && (indicator_vapour > VAPOUR_INDICATOR_TEST) && (grad_T != 0) && (temperature_val == 0))
1217 {
1218 const double kappa = curvature(i,j,k);
1219 double temperature_ghost = 0.;
1220 if (spherical_approx)
1221 temperature_ghost = temperature_interf + d * grad_T * (1. + 0.5 * kappa * d + kappa * kappa * d * d / 6.);
1222 else
1223 {
1224 const double kappa_non_zero = kappa + 1.e-16;
1225 temperature_ghost = temperature_interf + grad_T * (- 2 / kappa_non_zero) * (1 - (- 2 / kappa_non_zero) / ((d - (2 / kappa_non_zero)) + 1e-16));
1226 }
1227 temperature(i,j,k) = temperature_ghost;
1228 }
1229 }
1230 temperature.echange_espace_virtuel(temperature.ghost());
1231
1232 // statistiques().end_count(stat_counter);
1233}
1234
1235void smooth_vector_field(IJK_Field_vector3_double& vector_field,
1236 IJK_Field_vector3_double& vector_field_init,
1237 const IJK_Field_vector3_double * eulerian_normal_vectors_ns_normed,
1238 const IJK_Interfaces& interfaces,
1239 const double (&direct_smoothing_factors) [7],
1240 const double (&gaussian_smoothing_factors) [3][3][3],
1241 const int& smooth_numbers,
1242 const int& remove_normal_compo,
1243 const int& direct_neighbours,
1244 const int& use_field_init,
1245 const int& use_unique_phase)
1246{
1247 for (int c=0; c<3; c++)
1248 {
1249 IJK_Field_double& field = vector_field[c];
1250 IJK_Field_double& field_init = vector_field_init[c];
1251 smooth_eulerian_field(field,
1252 field_init,
1253 c,
1254 vector_field_init,
1255 eulerian_normal_vectors_ns_normed,
1256 interfaces,
1257 direct_smoothing_factors,
1258 gaussian_smoothing_factors,
1259 smooth_numbers,
1260 remove_normal_compo,
1261 direct_neighbours,
1262 use_field_init,
1263 use_unique_phase);
1264 }
1265}
1266
1267void smooth_eulerian_field(IJK_Field_double& field,
1268 IJK_Field_double& field_init,
1269 const int& dir,
1270 IJK_Field_vector3_double& vector_field_init,
1271 const IJK_Field_vector3_double * eulerian_normal_vectors_ns_normed,
1272 const IJK_Interfaces& interfaces,
1273 const double (&direct_smoothing_factors) [7],
1274 const double (&gaussian_smoothing_factors) [3][3][3],
1275 const int& smooth_numbers,
1276 const int& remove_normal_compo,
1277 const int& direct_neighbours,
1278 const int& use_field_init,
1279 const int& use_unique_phase)
1280{
1281 const IJK_Field_double& indicator = interfaces.I();
1282 const int smooth_numbers_end = (smooth_numbers < 1) ? 1: smooth_numbers;
1283 const int use_field_init_usr = use_field_init && (smooth_numbers_end == 1);
1284 IJK_Field_double field_copy;
1285 for (int m=0; m<smooth_numbers_end; m++)
1286 {
1287 const int ni = field.ni();
1288 const int nj = field.nj();
1289 const int nk = field.nk();
1290 IJK_Field_double& field_raw = use_field_init_usr ? field_init : field_copy;
1291 if (!use_field_init_usr)
1292 {
1293 if (m == 0)
1294 field_copy = field_init;
1295 else
1296 field_copy.data() = field.data();
1297 field_copy.echange_espace_virtuel(field_copy.ghost());
1298 }
1299
1300 double sum_factors = 0;
1301 double sum_factors_phase = 0;
1302 double sum_direct_smoothing_factors = 0.;
1303 double sum_gaussian_smoothing_factors = 0.;
1304
1305 for (int c=0; c<7; c++)
1306 sum_direct_smoothing_factors += direct_smoothing_factors[c];
1307 for (int c=0; c<3; c++)
1308 for (int l=0; l<3; l++)
1309 for (int n=0; n<3; n++)
1310 sum_gaussian_smoothing_factors += gaussian_smoothing_factors[n][l][c];
1311
1312 sum_factors = (direct_neighbours) ? sum_direct_smoothing_factors : sum_gaussian_smoothing_factors;
1313 sum_factors_phase = sum_factors;
1314 Cerr << "Sum of smoothing factors: " << sum_factors << finl;
1315 for (int k = 0; k < nk; k++)
1316 for (int j = 0; j < nj; j++)
1317 for (int i = 0; i < ni; i++)
1318 {
1319 if (direct_neighbours)
1320 {
1321 field(i,j,k) = direct_smoothing_factors[6] * field_raw(i,j,k);
1322 for (int l=0; l<6; l++)
1323 {
1324 const int ii = NEIGHBOURS_I[l];
1325 const int jj = NEIGHBOURS_J[l];
1326 const int kk = NEIGHBOURS_K[l];
1327 if (!remove_normal_compo)
1328 field(i,j,k) += direct_smoothing_factors[l] * field_raw(i+ii,j+jj,k+kk);
1329 else
1330 {
1331 const double normal_vect = (*eulerian_normal_vectors_ns_normed)[dir](i,j,k);
1332 const double normal_compo = (field_raw(i+ii,j+jj,k+kk) *
1333 direct_smoothing_factors[l] *
1334 normal_vect);
1335 // const double normal_vect = (*eulerian_normal_vectors_ns_normed)[dir](i+ii,j+jj,k+kk);
1336 // const double normal_compo = (field_raw(i+ii,j+jj,k+kk) *
1337 // direct_smoothing_factors[l] *
1338 // (*eulerian_normal_vectors_ns_normed)[dir](i+ii,j+jj,k+kk));
1339 field(i,j,k) += (direct_smoothing_factors[l] * field_raw(i+ii,j+jj,k+kk) - normal_compo);
1340 }
1341 }
1342 }
1343 else
1344 {
1345 sum_factors_phase = use_unique_phase ? 0 : sum_factors;
1346 bool test_indicator;
1347 field(i,j,k) = 0.;
1348 // for (int c=0; c<3; c++)
1349 for (int c=-1; c<=1; c++)
1350 for (int l=-1; l<=1; l++)
1351 for (int n=-1; n<=1; n++)
1352 {
1353 test_indicator=true;
1354 // const int ii = select_dir(c, l, 0, 0);
1355 // const int jj = select_dir(c, 0, l, 0);
1356 // const int kk = select_dir(c, 0, 0, l);
1357 const int ii = n;
1358 const int jj = l;
1359 const int kk = c;
1360 const double indic = indicator(i+ii,j+jj,k+kk);
1361 if (use_unique_phase && indic < VAPOUR_INDICATOR_TEST)
1362 test_indicator = false;
1363 if (test_indicator)
1364 {
1365 const double smoothing_factor_index = gaussian_smoothing_factors[n+1][l+1][c+1];
1366 if (!remove_normal_compo)
1367 field(i,j,k) += smoothing_factor_index * field_raw(i+ii,j+jj,k+kk);
1368 else
1369 {
1370 const double normal_vect = (*eulerian_normal_vectors_ns_normed)[dir](i,j,k);
1371// const double normal_compo = (smoothing_factor_index *
1372// field_raw(i+ii,j+jj,k+kk) *
1373// normal_vect * normal_vect);
1374 double normal_compo_tot = 0;
1375 for (int cc=0; cc<3; cc++)
1376 {
1377 const double normal_vect_dir = (*eulerian_normal_vectors_ns_normed)[cc](i,j,k);
1378 normal_compo_tot += (smoothing_factor_index *
1379 vector_field_init[cc](i+ii,j+jj,k+kk) *
1380 normal_vect_dir * normal_vect);
1381 }
1382 // normal_compo_tot = normal_compo;
1383 // const double sign_projection = signbit(normal_vect) ? -1.: 1.;
1384 // const double normal_compo = (smoothing_factor_index *
1385 // field_raw(i+ii,j+jj,k+kk) *
1386 // (*eulerian_normal_vectors_ns_normed)[dir](i+ii,j+jj,k+kk));
1387 field(i,j,k) += (smoothing_factor_index * field_raw(i+ii,j+jj,k+kk) - normal_compo_tot);
1388 if (use_unique_phase)
1389 sum_factors_phase += smoothing_factor_index;
1390 }
1391 }
1392 }
1393 }
1394 if (sum_factors_phase != 0)
1395 {
1396 field(i,j,k) /= sum_factors_phase;
1397
1398 if (remove_normal_compo)
1399 {
1400 const double normal_vect = (*eulerian_normal_vectors_ns_normed)[dir](i,j,k);
1401 double normal_compo_tot = 0;
1402 for (int cc=0; cc<3; cc++)
1403 {
1404 const double normal_vect_dir = (*eulerian_normal_vectors_ns_normed)[cc](i,j,k);
1405 normal_compo_tot += vector_field_init[cc](i,j,k) * normal_vect_dir;
1406 }
1407 // normal_compo_tot = field_raw(i,j,k) * normal_vect;
1408 const double normal_compo = normal_compo_tot * normal_vect;
1409 field(i,j,k) += normal_compo;
1410 }
1411 }
1412 }
1413 }
1414}
1415
1416void fill_tangential_gradient(const IJK_Field_vector3_double& vector_field,
1417 const IJK_Field_vector3_double * eulerian_normal_vectors_ns_normed,
1418 IJK_Field_vector3_double& tangential_vector_field)
1419{
1420 for (int c=0; c<3; c++)
1421 {
1422 IJK_Field_double& field = tangential_vector_field[c];
1423 fill_tangential_gradient_compo(vector_field,
1424 eulerian_normal_vectors_ns_normed,
1425 field, c);
1426 }
1427}
1428
1429void fill_tangential_gradient_compo(const IJK_Field_vector3_double& vector_field,
1430 const IJK_Field_vector3_double * eulerian_normal_vectors_ns_normed,
1431 IJK_Field_double& tangential_field,
1432 const int& dir)
1433{
1434 const int ni = tangential_field.ni();
1435 const int nj = tangential_field.nj();
1436 const int nk = tangential_field.nk();
1437 for (int k = 0; k < nk; k++)
1438 for (int j = 0; j < nj; j++)
1439 for (int i = 0; i < ni; i++)
1440 {
1441 const double normal_vect = (*eulerian_normal_vectors_ns_normed)[dir](i,j,k);
1442 double normal_compo_tot = 0;
1443 for (int cc=0; cc<3; cc++)
1444 {
1445 const double normal_vect_dir = (*eulerian_normal_vectors_ns_normed)[cc](i,j,k);
1446 normal_compo_tot += vector_field[cc](i,j,k) * normal_vect_dir * normal_vect;
1447 }
1448 tangential_field(i,j,k) = vector_field[dir](i,j,k) - normal_compo_tot;
1449 }
1450}
static void verifier(const char *msg, const IJK_Field_float &)
Definition DebogIJK.cpp:117
int_t nb_elem() const
Definition Domaine.h:131
This class encapsulates all the information related to the eulerian mesh for TrioIJK.
Definition Domaine_IJK.h:47
double get_constant_delta(int direction) const
Returns the size of cells in a direction.
FixedVector< int, 3 > convert_packed_to_ijk_cell(int index) const
Convert the local index of an element to a vector with IJK indices.
class Domaine_VF
Definition Domaine_VF.h:44
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
const Domaine_IJK & get_domaine() const
const Domaine_IJK & get_domaine() const
: class IJK_Interfaces
const IJK_Field_double & I_ft() const
const Domaine_dis_base & get_domaine_dis() const
const IJK_Field_double & I() const
const ArrOfInt & get_compo_to_group() const
const Maillage_FT_IJK & maillage_ft_ijk() const
: class Intersections_Elem_Facettes
const ArrOfInt & index_elem() const
Renvoie un tableau de taille domaine.
const ArrOfInt & index_facette() const
Renvoie un tableau de taille "nombre de facettes de l'interface" pour un element 0 <= facette < nb_fa...
const Intersections_Elem_Facettes_Data & data_intersection(int index) const
Renvoie les donnees de l'intersection stockee a l'indice "index" dans le tableau "data" ( 0 <= index ...
const DoubleTab & sommets() const
renvoie le tableau des sommets (reels et virtuels) dimension(0) = nombre de sommets,
int nb_facettes() const
renvoie le nombre de facettes (reelles et virtuelles) (egal a facettes().
virtual const DoubleTab & get_update_normale_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
const Intersections_Elem_Facettes & intersections_elem_facettes() const
virtual const ArrOfDouble & get_update_surface_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
virtual const ArrOfDouble & get_update_courbure_sommets() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
const IntTab & facettes() const
renvoie le tableau des facettes (reelles et virtuelles) dimension(0) = nombre de facettes,
: class Maillage_FT_IJK
const ArrOfInt & compo_connexe_facettes() const
void typer_diffusion_op(const char *diffusion_op)
void initialize(const Domaine_IJK &splitting)
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67