TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Navier_Stokes_FTD_IJK_tools.cpp
1/****************************************************************************
2* Copyright (c) 2025, 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 <Navier_Stokes_FTD_IJK_tools.h>
17#include <IJK_Shear_Periodic_helpler.h>
18#include <IJK_Navier_Stokes_tools.h>
19#include <Boundary_Conditions.h>
20#include <IJK_Interfaces.h>
21
22void force_upstream_velocity(IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz, double v_imposed, const IJK_Interfaces& interfaces,
23 double nb_diam, int upstream_dir, int gravity_dir, int upstream_stencil)
24{
25 int dir = 0;
26 if (upstream_dir == -1)
27 {
28 dir = gravity_dir;
29 if (dir == -1)
30 dir = 0;
31 }
32
33 const Domaine_IJK& geom = vx.get_domaine();
34
35 bool perio = geom.get_periodic_flag(dir);
36
37 assert(interfaces.get_nb_bulles_reelles() == 1);
38 DoubleTab bounding_box;
39 Cerr << "Upstream Velocity - Compute Bounding box" << finl;
40 interfaces.calculer_bounding_box_bulles(bounding_box);
41 // Calcule la hauteur en x de la permiere bulle et la position de son cdg :
42 const double Dbdir = bounding_box(0, dir, 1) - bounding_box(0, dir, 0);
43 const double dirb = (bounding_box(0, dir, 1) + bounding_box(0, dir, 0)) / 2.;
44 const double ldir = geom.get_domain_length(dir);
45 if (nb_diam == 0.)
46 nb_diam = (ldir / Dbdir) / 2;
47 double dirobj = dirb + nb_diam * Dbdir;
48
49 // L'origine est sur un noeud. Donc que la premiere face en I est sur get_origin(DIRECTION_I)
50 const double ddir = geom.get_constant_delta(dir);
51 const double origin_dir = geom.get_origin(dir);
52 const int offset_dir = geom.get_offset_local(dir);
53
54 // FIXME: If nb_diam is too large it will iterate a lot
55 if (perio)
56 {
57 while (dirobj < origin_dir)
58 dirobj += ldir;
59 while (dirobj > origin_dir + ldir)
60 dirobj -= ldir;
61 }
62
63 // On devrait avoir xobj dans le domaine, sinon, on a choisi nb_diam trop grand :
64 assert(((dirobj >= origin_dir) && (dirobj <= origin_dir + ldir)));
65
66 const double x2 = (dirobj - origin_dir) / ddir;
67 int index_dir = (int) (floor(x2)) - offset_dir; // C'est l'index local, donc potentiellement negatif...
68 int ndir;
69 switch(dir)
70 {
71 case 0:
72 ndir = vx.ni();
73 break;
74 case 1:
75 ndir = vx.nj();
76 break;
77 case 2:
78 ndir = vx.nk();
79 break;
80 default:
81 ndir = vx.ni();
82 break;
83 }
84 // Cerr << "index_dir " << index_dir << finl;
85 if ((index_dir >= 0) && (index_dir < ndir))
86 {
87 // On est sur le bon proc...
88 if (index_dir + upstream_stencil >= ndir)
89 {
90 // On ne veut pas s'embeter sur 2 procs...
91 index_dir = ndir - upstream_stencil;
92 }
93 }
94 else
95 return;
96
97 double imposed[3] = { 0., 0., 0. };
98 imposed[dir] = v_imposed;
99 for (int direction = 0; direction < 3; direction++)
100 {
101 IJK_Field_double& velocity = select_dir(direction, vx, vy, vz);
102 int imin, jmin, kmin;
103 int imax, jmax, kmax;
104 switch(dir)
105 {
106 case 0:
107 imin = index_dir;
108 jmin = 0;
109 kmin = 0;
110 imax = imin + upstream_stencil;
111 jmax = velocity.nj();
112 kmax = velocity.nk();
113 break;
114 case 1:
115 imin = 0;
116 jmin = index_dir;
117 kmin = 0;
118 imax = velocity.ni();
119 jmax = jmin + upstream_stencil;
120 kmax = velocity.nk();
121 break;
122 case 2:
123 imin = 0;
124 jmin = 0;
125 kmin = index_dir;
126 imax = velocity.ni();
127 jmax = velocity.nj();
128 kmax = kmin + upstream_stencil;
129 break;
130 default:
131 imin = index_dir;
132 jmin = 0;
133 kmin = 0;
134 imax = imin + upstream_stencil;
135 jmax = velocity.nj();
136 kmax = velocity.nk();
137 break;
138 }
139 for (int k = kmin; k < kmax; k++)
140 for (int j = jmin; j < jmax; j++)
141 for (int i = imin; i < imax; i++)
142 velocity(i, j, k) = imposed[direction];
143 }
144
145 Cerr << "Upstream Velocity has been forced" << finl;
146}
147
148void force_upstream_velocity_shear_perio(IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz, double v_imposed, const IJK_Interfaces& interfaces, double nb_diam, Boundary_Conditions& bc,
149 double nb_diam_ortho_shear_perio, double Ux0, double Uy0, double Uz0, int epaisseur_maille)
150{
151 assert(interfaces.get_nb_bulles_reelles() == 1);
152 DoubleTab bounding_box;
153 Cerr << "Upstream Velocity - Compute Bounding box" << finl;
154 interfaces.calculer_bounding_box_bulles(bounding_box);
155
156 // Calcule la hauteur en x et z de la bulle et la position de son cdg :
157 const double Dbx = bounding_box(0, 0, 1) - bounding_box(0, 0, 0);
158 const double Dbz = bounding_box(0, 2, 1) - bounding_box(0, 2, 0);
159 const double xb = (bounding_box(0, 0, 1) + bounding_box(0, 0, 0)) / 2.;
160 const double zb = (bounding_box(0, 2, 1) + bounding_box(0, 2, 0)) / 2.;
161
162 const Domaine_IJK& geom = vx.get_domaine();
163 double origin_x = geom.get_origin(DIRECTION_I);
164 double lx = geom.get_domain_length(DIRECTION_I);
165 double origin_z = geom.get_origin(DIRECTION_K);
166 double lz = geom.get_domain_length(DIRECTION_K);
167 double z_min = zb - (Dbz * nb_diam_ortho_shear_perio) / 2.;
168 double z_max = zb + (Dbz * nb_diam_ortho_shear_perio) / 2.;
169 double z_min_modulo = z_min;
170 double z_max_modulo = z_max;
171
172 bool perio = geom.get_periodic_flag(DIRECTION_K);
173 if (perio)
174 {
175 z_min_modulo = std::fmod(std::fmod(z_min - origin_z, lz) + lz, lz) + origin_z;
176 z_max_modulo = std::fmod(std::fmod(z_max - origin_z, lz) + lz, lz) + origin_z;
177 }
178 // Calcule la hauteur du plan ou sera impose la vitesse par rapport a la bulle reelle
179 double xobj = xb + nb_diam * Dbx;
180 // Calcule la hauteur du plan ou sera impose la vitesse par rapport a la bulle shear periodique par le shear positif
181 double xb_offsetp = xb + std::fmod(std::fmod(IJK_Shear_Periodic_helpler::shear_x_time_, lx) + lx, lx);
182 double xobj_offsetp = xb_offsetp + nb_diam * Dbx;
183 // Calcule la hauteur du plan ou sera impose la vitesse par rapport a la bulle shear periodique par le shear negatif
184 double xb_offsetm = xb - std::fmod(std::fmod(IJK_Shear_Periodic_helpler::shear_x_time_, lx) + lx, lx);
185 double xobj_offsetm = xb_offsetm + nb_diam * Dbx;
186
187 perio = geom.get_periodic_flag(DIRECTION_I);
188 // on s'assure que la position des plans en x reste dans le domaine physique
189 if (perio)
190 {
191 xobj = std::fmod(std::fmod(xobj - origin_x, lx) + lx, lx) + origin_x;
192 xobj_offsetp = std::fmod(std::fmod(xobj_offsetp - origin_x, lx) + lx, lx) + origin_x;
193 xobj_offsetm = std::fmod(std::fmod(xobj_offsetm - origin_x, lx) + lx, lx) + origin_x;
194 }
195
196 double dx = geom.get_constant_delta(DIRECTION_I);
197 double dz = geom.get_constant_delta(DIRECTION_K);
198 int offset_i = geom.get_offset_local(DIRECTION_I);
199 int offset_k = geom.get_offset_local(DIRECTION_K);
200
201 // position des plans : conversion en indice du tableau NS
202 // en shear perio, pas de decoupage sur x. les index_i sont compris entre 0 et ni_tot
203 int ni = vy.ni();
204 int index_i_offsetp = (int) (round((xobj_offsetp - origin_x) / dx)) - offset_i;
205 int index_i_offsetm = (int) (round((xobj_offsetm - origin_x) / dx)) - offset_i;
206 int index_i = (int) (round((xobj - origin_x) / dx)) - offset_i;
207 // decoupage en z autorise. ATTENTION, indices locaux potentiellement negatifs
208 int index_k_min = (int) (round((z_min_modulo - origin_z) / dz)) - offset_k;
209 int index_k_max = (int) (((z_max_modulo - origin_z) / dz)) - offset_k;
210
211 for (int direction = 0; direction < 3; direction++)
212 {
213 IJK_Field_double& velocity = select_dir(direction, vx, vy, vz);
214 for (int k = 0; k < velocity.nk(); k++)
215 {
216 for (int j = 0; j < velocity.nj(); j++)
217 {
218 for (int i = 0; i < velocity.ni(); i++)
219 {
220 bool go_i = false;
221 bool go_k = false;
222 int index_i_real = index_i;
223
224 // coord Z
225 if (z_min_modulo > z_max_modulo)
226 {
227 // la plan est a cheval sur la frontiere z
228 // Il y donc deux plans distincts ou imposer la vitesse
229 // un pour la bulle "de droite" (k=nk), un pour la bulle "de gauche" (k=0).
230 if (z_min < origin_z)
231 {
232 // la bulle reelle est en 0
233 // la bulle fantome est soumise a un shear positif
234 if (k > index_k_min and index_k_min < velocity.nk())
235 {
236 // indice i du plan pour la bulle fantome
237 index_i_real = index_i_offsetp;
238 go_k = true;
239
240 }
241 else if (k < index_k_max and index_k_max >= 0)
242 {
243 // indice i du plan pour la bulle reelle
244 index_i_real = index_i;
245 go_k = true;
246
247 }
248 }
249 else if (z_max > lz + origin_z)
250 {
251 // la bulle reelle est en nk
252 // la bulle fantome est soumise a un shear negatif
253 if (k > index_k_min and index_k_min < velocity.nk())
254 {
255 // indice i du plan pour la bulle reelle
256 index_i_real = index_i;
257 go_k = true;
258 }
259 else if (k < index_k_max and index_k_max >= 0)
260 {
261 // indice i du plan pour la bulle fantome
262 index_i_real = index_i_offsetm;
263 go_k = true;
264 }
265 }
266 }
267 else
268 {
269 // le plan ne traverse pas la frontiere z
270 // un seul plan defini pour la bulle entiere
271 if (z_max_modulo != z_max and z_min_modulo != z_min)
272 {
273 // le plan est entierement contenu dans le domaine etendu
274 // pas a cheval sur la frontiere dz
275 // lechange de compo n a pas encore ete fait
276 if (z_min < origin_z)
277 {
278 if ((index_k_min < velocity.nk() and k > index_k_min) and (k < index_k_max and index_k_max >= 0))
279 {
280 index_i_real = index_i_offsetp;
281 go_k = true;
282 }
283 }
284 else if (z_max > lz + origin_z)
285 {
286 if ((index_k_min < velocity.nk() and k > index_k_min) and (k < index_k_max and index_k_max >= 0))
287 {
288 index_i_real = index_i_offsetm;
289 go_k = true;
290 }
291 }
292
293 }
294 else
295 {
296 // la bulle reelle est entierement dans le domaine NS
297 if ((index_k_min < velocity.nk() and k > index_k_min) and (k < index_k_max and index_k_max >= 0))
298 {
299 index_i_real = index_i;
300 go_k = true;
301 }
302 }
303
304 }
305
306 // coord X
307 if (i == index_i_real % ni)
308 {
309 // On est sur la ligne du plan ou imposer la vitesse
310 go_i = true;
311 }
312
313 if (go_i && go_k)
314 {
315 // on impose la vitesse sur une couche de 3 mailles
316 // U(z) = DU_perio * z / Lz
317 // V = W = 0
318 // ATTENTION : doit etre utilisee avec corrections_qdm pour eviter toute deviation
319 // ATTENTION : s assurer que la condition de corrections_qdm est compatible avec ce profil de vitesse
320 if (direction == 0)
321 {
322 double z = dz / 2. + (k + offset_k) * dz;
323 for (int m = 0; m < epaisseur_maille; m++)
324 velocity((i + m) % ni, j, k) = Ux0 + bc.get_dU_perio(bc.get_resolution_u_prime_()) * z / lz;
325 }
326 else if (direction == 2)
327 {
328 for (int m = 0; m < epaisseur_maille; m++)
329 velocity((i + m) % ni, j, k) = Uz0;
330 }
331 else
332 {
333 for (int m = 0; m < epaisseur_maille; m++)
334 velocity((i + m) % ni, j, k) = Uy0;
335
336 }
337 }
338
339 }
340 }
341 }
342 }
343
344 Cerr << "Upstream Velocity has been forced" << finl;
345}
double get_dU_perio(int fluctuations=0) const
int get_resolution_u_prime_() const
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.
bool get_periodic_flag(int direction) const
Method returns true if periodic in this direction.
double get_domain_length(int direction) const
Returns the length of the entire domain 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.
const Domaine_IJK & get_domaine() const
: class IJK_Interfaces
int get_nb_bulles_reelles() const
void calculer_bounding_box_bulles(DoubleTab &bounding_box, int option_shear=0) const