TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
IJK_Navier_Stokes_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_Navier_Stokes_tools.h>
17#include <Parser.h>
18#include <IJK_ptr.h>
19#include <EChaine.h>
20#include <SChaine.h>
21#include <Interprete_bloc.h>
22#include <Perf_counters.h>
23#include <Option_IJK.h>
24#include <Multigrille_Adrien.h>
25#include <Boundary_Conditions_Thermique.h>
26
27double compute_fractionnal_timestep_rk3(const double dt_tot, int step)
28{
29 assert(step >= 0 && step < 3);
30 const double intermediate_tstep[3] = { 1. / 3., 5. / 12., 1. / 4. };
31 return intermediate_tstep[step] * dt_tot;
32}
33
34// Imposer une condition limite de vitesse nulle aux parois (en zmin et zmax)
35void force_zero_on_walls(IJK_Field_double& vz)
36{
37 const int nj = vz.nj();
38 const int ni = vz.ni();
39 const int kmin = vz.get_domaine().get_offset_local(DIRECTION_K);
40 const int nktot = vz.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
41 if (kmin == 0)
42 {
43 for (int j = 0; j < nj; j++)
44 for (int i = 0; i < ni; i++)
45 vz(i, j, 0) = 0.;
46 }
47 if (kmin + vz.nk() == nktot)
48 {
49 const int k = vz.nk() - 1;
50 for (int j = 0; j < nj; j++)
51 for (int i = 0; i < ni; i++)
52 vz(i, j, k) = 0.;
53 }
54}
55
56// Compute, for each cell, the integral on the cell of dt times the divergence of the velocity field.
57// Computed as the sum on each face of ("velocity" scalar "normal vector" times "surface of the face")
58void compute_divergence_times_constant(const IJK_Field_double& vx, const IJK_Field_double& vy, const IJK_Field_double& vz, const double constant, IJK_Field_double& resu)
59{
60 const Domaine_IJK& geom = vx.get_domaine();
61 const double delta_x = geom.get_constant_delta(0);
62 const double delta_y = geom.get_constant_delta(1);
63 const int kmax = resu.nk();
64 const int imax = resu.ni();
65 const int jmax = resu.nj();
66 const int offset = vx.get_domaine().get_offset_local(DIRECTION_K);
67 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
68 for (int k = 0; k < kmax; k++)
69 {
70 const double delta_z = delta_z_all[k + offset];
71 const double fx = delta_y * delta_z * constant;
72 const double fy = delta_x * delta_z * constant;
73 const double fz = delta_x * delta_y * constant;
74 for (int j = 0; j < jmax; j++)
75 {
76 for (int i = 0; i < imax; i++)
77 {
78 double x = (vx(i + 1, j, k) - vx(i, j, k)) * fx + (vy(i, j + 1, k) - vy(i, j, k)) * fy + (vz(i, j, k + 1) - vz(i, j, k)) * fz;
79 resu(i, j, k) = x;
80 }
81 }
82 }
83}
84
85// Compute, for each cell, the divergence of the velocity field
86// without the product with volume or a constant.
87void compute_divergence(const IJK_Field_double& vx, const IJK_Field_double& vy, const IJK_Field_double& vz, IJK_Field_double& resu)
88{
89 const Domaine_IJK& geom = vx.get_domaine();
90 const double delta_x = geom.get_constant_delta(0);
91 const double delta_y = geom.get_constant_delta(1);
92 const int kmax = resu.nk();
93 const int imax = resu.ni();
94 const int jmax = resu.nj();
95 const int offset = vx.get_domaine().get_offset_local(DIRECTION_K);
96 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
97 for (int k = 0; k < kmax; k++)
98 {
99 const double delta_z = delta_z_all[k + offset];
100 const double fx = 1. / delta_x;
101 const double fy = 1. / delta_y;
102 const double fz = 1. / delta_z;
103 for (int j = 0; j < jmax; j++)
104 {
105 for (int i = 0; i < imax; i++)
106 {
107 double x = (vx(i + 1, j, k) - vx(i, j, k)) * fx + (vy(i, j + 1, k) - vy(i, j, k)) * fy + (vz(i, j, k + 1) - vz(i, j, k)) * fz;
108 resu(i, j, k) = x;
109 }
110 }
111 }
112}
113
114// Add to vx, vy and vz the gradient of the pressure gradient multiplied by the constant.
115// Input and output velocity is in m/s (not the integral of the momentum on the cell).
116// On the walls, don't touch velocity
117void add_gradient_times_constant(const IJK_Field_double& pressure, const double constant, IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz)
118{
119 const Domaine_IJK& geom = vx.get_domaine();
120 const int kmax = std::max(std::max(vx.nk(), vy.nk()), vz.nk());
121 for (int k = 0; k < kmax; k++)
122 {
123 // i component of velocity
124 if (k < vx.nk())
125 {
126 const int jmax = vx.nj();
127 const int imax = vx.ni();
128 const double f = constant / geom.get_constant_delta(0);
129 for (int j = 0; j < jmax; j++)
130 for (int i = 0; i < imax; i++)
131 vx(i, j, k) += (pressure(i, j, k) - pressure(i - 1, j, k)) * f;
132 }
133 // j component:
134 if (k < vy.nk())
135 {
136 const int jmax = vy.nj();
137 const int imax = vy.ni();
138 const double f = constant / geom.get_constant_delta(1);
139 for (int j = 0; j < jmax; j++)
140 for (int i = 0; i < imax; i++)
141 vy(i, j, k) += (pressure(i, j, k) - pressure(i, j - 1, k)) * f;
142 }
143 // k component:
144 bool on_the_wall = false;
145 const int k_min = vz.get_domaine().get_offset_local(DIRECTION_K);
146 const int nk_tot = vz.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
147 const int offset = vz.get_domaine().get_offset_local(DIRECTION_K);
148 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
149 bool perio_k = vz.get_domaine().get_periodic_flag(DIRECTION_K);
150 if ((k + k_min == 0 || k + k_min == nk_tot - 1) && (!perio_k))
151 on_the_wall = true;
152 if (k < vz.nk() && (!on_the_wall))
153 {
154 const int jmax = vz.nj();
155 const int imax = vz.ni();
156 double f;
157 if (!perio_k)
158 {
159 f = constant * 2. / (delta_z_all[k - 1 + k_min] + delta_z_all[k + k_min]);
160 }
161 else
162 {
163 f = (constant / delta_z_all[k + offset]);
164 }
165 for (int j = 0; j < jmax; j++)
166 for (int i = 0; i < imax; i++)
167 vz(i, j, k) += (pressure(i, j, k) - pressure(i, j, k - 1)) * f;
168 }
169 }
170}
171
172// Add to vx, vy and vz the gradient of the pressure gradient multiplied by the constant.
173// Input and output velocity is in m/s (not the integral of the momentum on the cell).
174// On the walls, don't touch velocity
175void add_gradient_times_constant_over_rho(const IJK_Field_double& pressure, const IJK_Field_double& rho, const double constant, IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz)
176{
177 const Domaine_IJK& geom = vx.get_domaine();
178 const int kmax = std::max(std::max(vx.nk(), vy.nk()), vz.nk());
179 for (int k = 0; k < kmax; k++)
180 {
181 // i component of velocity
182 if (k < vx.nk())
183 {
184 const int jmax = vx.nj();
185 const int imax = vx.ni();
186 const double f = constant / geom.get_constant_delta(0) * 2.;
187 for (int j = 0; j < jmax; j++)
188 for (int i = 0; i < imax; i++)
189 vx(i, j, k) += (pressure(i, j, k) - pressure(i - 1, j, k)) / (rho(i, j, k) + rho(i - 1, j, k)) * f;
190 }
191 // j component:
192 if (k < vy.nk())
193 {
194 const int jmax = vy.nj();
195 const int imax = vy.ni();
196 const double f = constant / geom.get_constant_delta(1) * 2.;
197 for (int j = 0; j < jmax; j++)
198 for (int i = 0; i < imax; i++)
199 vy(i, j, k) += (pressure(i, j, k) - pressure(i, j - 1, k)) / (rho(i, j, k) + rho(i, j - 1, k)) * f;
200 }
201 // k component:
202 bool on_the_wall = false;
203 const int k_min = vz.get_domaine().get_offset_local(DIRECTION_K);
204 const int nk_tot = vz.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
205 const int offset = vz.get_domaine().get_offset_local(DIRECTION_K);
206 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
207 bool perio_k = vz.get_domaine().get_periodic_flag(DIRECTION_K);
208
209 if ((k + k_min == 0 || k + k_min == nk_tot - 1) && (!perio_k))
210 on_the_wall = true;
211 if (k < vz.nk() && (!on_the_wall))
212 {
213 const int jmax = vz.nj();
214 const int imax = vz.ni();
215 double f;
216 if (!perio_k)
217 {
218 f = constant * 2. / (delta_z_all[k - 1 + k_min] + delta_z_all[k + k_min]) * 2.;
219 }
220 else
221 {
222 f = (constant / delta_z_all[k + offset]) * 2.;
223 }
224 for (int j = 0; j < jmax; j++)
225 for (int i = 0; i < imax; i++)
226 vz(i, j, k) += (pressure(i, j, k) - pressure(i, j, k - 1)) / (rho(i, j, k) + rho(i, j, k - 1)) * f;
227 }
228 }
229}
230void add_gradient_times_constant_times_inv_rho(const IJK_Field_double& pressure, const IJK_Field_double& inv_rho, const double constant, IJK_Field_double& vx, IJK_Field_double& vy,
231 IJK_Field_double& vz)
232{
233 const Domaine_IJK& geom = vx.get_domaine();
234 const int kmax = std::max(std::max(vx.nk(), vy.nk()), vz.nk());
235 for (int k = 0; k < kmax; k++)
236 {
237 // i component of velocity
238 if (k < vx.nk())
239 {
240 const int jmax = vx.nj();
241 const int imax = vx.ni();
242 const double f = constant / geom.get_constant_delta(0) * 0.5;
243 for (int j = 0; j < jmax; j++)
244 for (int i = 0; i < imax; i++)
245 vx(i, j, k) += (pressure(i, j, k) - pressure(i - 1, j, k)) * (inv_rho(i, j, k) + inv_rho(i - 1, j, k)) * f;
246 }
247 // j component:
248 if (k < vy.nk())
249 {
250 const int jmax = vy.nj();
251 const int imax = vy.ni();
252 const double f = constant / geom.get_constant_delta(1) * 0.5;
253 for (int j = 0; j < jmax; j++)
254 for (int i = 0; i < imax; i++)
255 vy(i, j, k) += (pressure(i, j, k) - pressure(i, j - 1, k)) * (inv_rho(i, j, k) + inv_rho(i, j - 1, k)) * f;
256 }
257 // k component:
258 bool on_the_wall = false;
259 const int k_min = vz.get_domaine().get_offset_local(DIRECTION_K);
260 const int nk_tot = vz.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
261 const int offset = vz.get_domaine().get_offset_local(DIRECTION_K);
262 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
263 bool perio_k = vz.get_domaine().get_periodic_flag(DIRECTION_K);
264
265 if ((k + k_min == 0 || k + k_min == nk_tot - 1) && (!perio_k))
266 on_the_wall = true;
267 if (k < vz.nk() && (!on_the_wall))
268 {
269 const int jmax = vz.nj();
270 const int imax = vz.ni();
271 double f;
272 if (!perio_k)
273 {
274 f = constant * 2. / (delta_z_all[k - 1 + k_min] + delta_z_all[k + k_min]) * 0.5;
275 }
276 else
277 {
278 f = (constant / delta_z_all[k + offset]) * 0.5;
279 }
280 for (int j = 0; j < jmax; j++)
281 for (int i = 0; i < imax; i++)
282 vz(i, j, k) += (pressure(i, j, k) - pressure(i, j, k - 1)) * (inv_rho(i, j, k) + inv_rho(i, j, k - 1)) * f;
283 }
284 }
285}
286
287// Projects the input velocity field on the zero divergence subspace by solving the Poisson equation:
288// v_output = v_input - dt * gradient(pressure)
289// pressure is such that div(v_output) = 0, that is, solve for pressure_ satisfying:
290// div(v_input) + div(-dt * gradient(pressure)),
291// that is:
292// div(gradient(pressure_)) = 1/dt * div(v_input)
293//
294// input value of pressure_ is used as an initial guess by the solver
295
296void pressure_projection(IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz,
297 IJK_Field_double& pressure, double dt,
298 IJK_Field_double& pressure_rhs,
299 Multigrille_Adrien& poisson_solver)
300{
301 statistics().create_custom_counter("Velocity update: projection",2,"IJK");
302 statistics().begin_count("Velocity update: projection",statistics().get_last_opened_counter_level()+1);
303 // We need the velocity on the face at right to compute the divergence:
304 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
305 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
306 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
307
308 compute_divergence_times_constant(vx, vy, vz, -1./dt, pressure_rhs);
310 {
311 pressure.ajouter_second_membre_shear_perio(pressure_rhs);
312 }
313 double divergence_before = 0.;
315 divergence_before = norme_ijk(pressure_rhs);
316
317 poisson_solver.resoudre_systeme_IJK(pressure_rhs, pressure);
318 // pressure gradient requires the "left" value in all directions:
319 pressure.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_LEFT_IJK*/);
320 add_gradient_times_constant(pressure, -dt, vx, vy, vz);
322 {
323 IJK_Field rhs_after(pressure_rhs);
324
325 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
326 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
327 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
328
329 compute_divergence_times_constant(vx, vy, vz, 1. / dt, rhs_after);
330 double divergence_after = norme_ijk(rhs_after);
331 Cout << "Divergence of velocity field: before solver: " << divergence_before << " after solver: " << divergence_after << finl;
332 }
333 statistics().end_count("Velocity update: projection");
334}
335
336// Projects the input velocity field on the zero divergence subspace by solving the Poisson equation:
337// v_output = v_input - dt * gradient(pressure)
338// pressure is such that div(v_output) = 0, that is, solve for pressure_ satisfying:
339// div(v_input) + div(-dt * gradient(pressure)),
340// that is:
341// div(gradient(pressure_)) = 1/dt * div(v_input)
342//
343// input value of pressure_ is used as an initial guess by the solver
344
345void pressure_projection_with_rho(const IJK_Field_double& rho,
346 IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz,
347 IJK_Field_double& pressure, double dt,
348 IJK_Field_double& pressure_rhs,
349 Multigrille_Adrien& poisson_solver, int NoSym)
350{
351 statistics().create_custom_counter("Velocity update: projection",2,"IJK");
352 statistics().begin_count("Velocity update: projection",statistics().get_last_opened_counter_level()+1);
353 // We need the velocity on the face at right to compute the divergence:
354 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
355 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
356 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
357
358 compute_divergence_times_constant(vx, vy, vz, -1./dt, pressure_rhs);
360 {
361 pressure.ajouter_second_membre_shear_perio(pressure_rhs);
362 }
363 double divergence_before = 0.;
365 divergence_before = norme_ijk(pressure_rhs);
366
367 if (NoSym)
368 {
369 poisson_solver.set_rho_NoSym(rho);
370 }
371 else
372 {
373 poisson_solver.set_rho(rho);
374 }
375
376 poisson_solver.resoudre_systeme_IJK(pressure_rhs, pressure);
377 // pressure gradient requires the "left" value in all directions:
378 pressure.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_LEFT_IJK*/);
379 add_gradient_times_constant_over_rho(pressure, rho, -dt, vx, vy, vz);
381 {
382 IJK_Field rhs_after(pressure_rhs);
383
384 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
385 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
386 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
387
388 compute_divergence_times_constant(vx, vy, vz, 1. / dt, rhs_after);
389 double divergence_after = norme_ijk(rhs_after);
390 Cout << "Divergence of velocity field: before solver: " << divergence_before << " after solver: " << divergence_after << finl;
391 }
392 statistics().end_count("Velocity update: projection");
393}
394
395// Methode basee sur 1/rho au lieu de rho :
396
397void pressure_projection_with_inv_rho(const IJK_Field_double& inv_rho,
398 IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz,
399 IJK_Field_double& pressure, double dt,
400 IJK_Field_double& pressure_rhs,
401 Multigrille_Adrien& poisson_solver, int NoSym)
402{
403 statistics().create_custom_counter("Velocity update: projection",2,"IJK");
404 statistics().begin_count("Velocity update: projection",statistics().get_last_opened_counter_level()+1);
405 // We need the velocity on the face at right to compute the divergence:
406 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
407 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
408 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
409 compute_divergence_times_constant(vx, vy, vz, -1./dt, pressure_rhs);
411 {
412 pressure.ajouter_second_membre_shear_perio(pressure_rhs);
413 }
414 double divergence_before = 0.;
416 divergence_before = norme_ijk(pressure_rhs);
417
418 if (NoSym)
419 {
420 poisson_solver.set_inv_rho_NoSym(inv_rho);
421 }
422 else
423 {
424 poisson_solver.set_inv_rho(inv_rho);
425 }
426
427 // Fait aussi : compute_faces_coefficients_from_inv_rho
428 poisson_solver.resoudre_systeme_IJK(pressure_rhs, pressure);
429 // pressure gradient requires the "left" value in all directions:
430 pressure.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_LEFT_IJK*/);
431 add_gradient_times_constant_times_inv_rho(pressure, inv_rho, -dt, vx, vy, vz);
433 {
434 IJK_Field rhs_after(pressure_rhs);
435
436 vx.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_I*/);
437 vy.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_J*/);
438 vz.echange_espace_virtuel(1 /*, IJK_Field_double::EXCHANGE_GET_AT_RIGHT_K*/);
439
440 compute_divergence_times_constant(vx, vy, vz, 1. / dt, rhs_after);
441 double divergence_after = norme_ijk(rhs_after);
442 Cout << "Divergence of velocity field: before solver: " << divergence_before << " after solver: " << divergence_after << finl;
443 }
444 statistics().end_count("Velocity update: projection");
445}
446
447void forward_euler_update(const IJK_Field_double& dv, IJK_Field_double& v, const int k_layer, double dt_tot)
448{
449 const int imax = v.ni();
450 const int jmax = v.nj();
451 for (int j = 0; j < jmax; j++)
452 {
453 for (int i = 0; i < imax; i++)
454 {
455 double x = dv(i, j, k_layer);
456 v(i, j, k_layer) += x * dt_tot;
457 }
458 }
459}
460
461// Take the provided derivative dv and update F and the unknown v for the Runge Kutta "rk_step"
462// (0<=rk_step<=2).
463// F is an intermediate result, from the previous rk step (overwritten at step==0), used by
464// the RungeKutta algorithm
465// dv is the derivative evaluated at the current step
466// v is the unknown, the derivative for the next step must be computed with the output v of the
467// this step, after the last step, v is the final value at the end of the timestep_
468// dt_tot: total timestep
469void runge_kutta3_update(const IJK_Field_double& dv, IJK_Field_double& F, IJK_Field_double& v, const int step, const int k_layer, double dt_tot)
470{
471 const double coeff_a[3] = { 0., -5. / 9., -153. / 128. };
472 // Fk[0] = 1; Fk[i+1] = Fk[i] * a[i+1] + 1
473 const double coeff_Fk[3] = { 1., 4. / 9., 15. / 32. };
474
475 const double facteurF = coeff_a[step];
476 const double intermediate_dt = compute_fractionnal_timestep_rk3(dt_tot, step);
477 const double delta_t_divided_by_Fk = intermediate_dt / coeff_Fk[step];
478 const int imax = v.ni();
479 const int jmax = v.nj();
480 switch(step)
481 {
482 case 0:
483 // don't read initial value of F (no performance benefit because write to F causes the
484 // processor to fetch the cache line, but we don't wand to use a potentially uninitialized value
485 for (int j = 0; j < jmax; j++)
486 {
487 for (int i = 0; i < imax; i++)
488 {
489 double x = dv(i, j, k_layer);
490 F(i, j, k_layer) = x;
491 v(i, j, k_layer) += x * delta_t_divided_by_Fk;
492 }
493 }
494 break;
495 case 1:
496 // general case, read and write F
497 for (int j = 0; j < jmax; j++)
498 {
499 for (int i = 0; i < imax; i++)
500 {
501 double x = F(i, j, k_layer) * facteurF + dv(i, j, k_layer);
502 F(i, j, k_layer) = x;
503 v(i, j, k_layer) += x * delta_t_divided_by_Fk;
504 }
505 }
506 break;
507 case 2:
508 // do not write F
509 for (int j = 0; j < jmax; j++)
510 {
511 for (int i = 0; i < imax; i++)
512 {
513 double x = F(i, j, k_layer) * facteurF + dv(i, j, k_layer);
514 v(i, j, k_layer) += x * delta_t_divided_by_Fk;
515 }
516 }
517 break;
518 default:
519 Cerr << "Error in runge_kutta_update: wrong step" << finl;
521 };
522}
523#if 0
524// Copie de la methode precedente mais pour les DoubleTab aux sommets :
525void runge_kutta3_update(const DoubleTab& dvi, DoubleTab& G, DoubleTab& l,
526 const int step, const double dt_tot,
527 const Maillage_FT_IJK& maillage)
528{
529 const double coeff_a[3] = { 0., -5./9., -153./128. };
530 // Gk[0] = 1; Gk[i+1] = Gk[i] * a[i+1] + 1
531 const double coeff_Gk[3] = { 1., 4./9., 15./32. };
532
533 const double facteurG = coeff_a[step];
534 const double intermediate_dt = compute_fractionnal_timestep_rk3(dt_tot, step);
535 const double delta_t_divided_by_Gk = intermediate_dt / coeff_Gk[step];
536 const int nbsom = maillage.nb_sommets();
537
538 // Resize du tableau
539
540 G.resize(nbsom, 3);
541
542 switch(step)
543 {
544 case 0:
545 // don't read initial value of G (no performance benefit because write to G causes the
546 // processor to fetch the cache line, but we don't wand to use a potentially uninitialized value
547 for (int isom = 0; isom < nbsom; isom++)
548 {
549 for (int dir = 0; dir < 3; dir++)
550 {
551 if (maillage.sommet_virtuel(isom))
552 {
553 G(isom,dir) = 111./intermediate_dt;
554 l(isom,dir) = 111./intermediate_dt;
555 }
556 double x = dvi(isom,dir);
557 G(isom,dir) = x;
558 l(isom,dir) += x * delta_t_divided_by_Gk;
559 }
560 }
561 break;
562 case 1:
563 // general case, read and write G
564 for (int isom = 0; isom < nbsom; isom++)
565 {
566 for (int dir = 0; dir < 3; dir++)
567 {
568 if (maillage.sommet_virtuel(isom))
569 {
570 G(isom,dir) = 111./intermediate_dt;
571 l(isom,dir) = 111./intermediate_dt;
572 }
573 double x = G(isom,dir) * facteurG + dvi(isom,dir);
574 G(isom,dir) = x;
575 l(isom,dir) += x * delta_t_divided_by_Gk;
576 }
577 }
578 break;
579 case 2:
580 // do not write G
581 for (int isom = 0; isom < nbsom; isom++)
582 {
583 for (int dir = 0; dir < 3; dir++)
584 {
585 if (maillage.sommet_virtuel(isom))
586 {
587 G(isom,dir) = 111./intermediate_dt;
588 l(isom,dir) = 111./intermediate_dt;
589 }
590 double x = G(isom,dir) * facteurG + dvi(isom,dir);
591 l(isom,dir) += x * delta_t_divided_by_Gk;
592 }
593 }
594 break;
595 default:
596 Cerr << "Error in runge_kutta_update: wrong step" << finl;
598 };
599}
600#endif
601
602void runge_kutta3_update_surfacic_fluxes(IJK_Field_double& dv, IJK_Field_double& F, const int step, const int k_layer, double dt_tot)
603{
604 const double coeff_a[3] = { 0., -5. / 9., -153. / 128. };
605 // Fk[0] = 1; Fk[i+1] = Fk[i] * a[i+1] + 1
606 const double coeff_Fk[3] = { 1., 4. / 9., 15. / 32. };
607
608 const double facteurF = coeff_a[step];
609 const double one_divided_by_Fk = 1. / coeff_Fk[step];
610 const int imax = dv.ni();
611 const int jmax = dv.nj();
612 const int ghost = dv.ghost();
613 switch(step)
614 {
615 case 0:
616 // don't read initial value of F (no performance benefit because write to F causes the
617 // processor to fetch the cache line, but we don't wand to use a potentially uninitialized value
618 for (int j = -ghost; j < jmax+ghost; j++)
619 {
620 for (int i = -ghost; i < imax+ghost; i++)
621 {
622
623 double x = dv(i, j, k_layer);
624 dv(i, j, k_layer) = x * one_divided_by_Fk;
625 F(i, j, k_layer) = x;
626 }
627 }
628 break;
629 case 1:
630 // general case, read and write F
631 for (int j = -ghost; j < jmax+ghost; j++)
632 {
633 for (int i = -ghost; i < imax+ghost; i++)
634 {
635 double x = F(i, j, k_layer) * facteurF + dv(i, j, k_layer);
636 dv(i, j, k_layer) = x * one_divided_by_Fk;
637 F(i, j, k_layer) = x;
638 }
639 }
640 break;
641 case 2:
642 // do not write F
643 for (int j = -ghost; j < jmax+ghost; j++)
644 {
645 for (int i = -ghost; i < imax+ghost; i++)
646 {
647 double x = F(i, j, k_layer) * facteurF + dv(i, j, k_layer);
648 dv(i, j, k_layer) = x * one_divided_by_Fk;
649 }
650 }
651 break;
652 default:
653 Cerr << "Error in runge_kutta_update: wrong step" << finl;
655 };
656}
657
658// Calculer rho*v sur la couche k de faces dans la direction DIR
659// a partir de rho aux elements et v aux faces
660static void calculer_rho_v_DIR(DIRECTION _DIR_, const IJK_Field_double& input_rho, const IJK_Field_double& input_v, IJK_Field_double& rho_v, const int k)
661{
662 const int ni = rho_v.ni();
663 const int nj = rho_v.nj();
664 ConstIJK_double_ptr rho(input_rho, 0, 0, k);
665 ConstIJK_double_ptr v(input_v, 0, 0, k); // pointeur sur le plan k de la vitesse
666 IJK_double_ptr resu(rho_v, 0, 0, k);
667
668 for (int j = 0; j < nj; j++)
669 {
670 for (int i = 0; i < ni; i++)
671 {
672 double a, b, c;
673 rho.get_left_center(_DIR_, i, a, b); // a et b sont les masses volumiques a gauche et a droite de la face
674 v.get_center(i, c);
675 resu.put_val(i, (a + b) * c * 0.5);
676 }
677 if (j < nj - 1)
678 {
679 rho.next_j();
680 v.next_j();
681 resu.next_j();
682 }
683 }
684}
685
686// Remplace la moyenne arithmetique par une moyenne des inverses :
687// rho_face = 2 rho1 rho2 / (rho1+rho2) => 1/rho_face = (1/rho1 + 1/rho2) /2
688static void calculer_rho_harmonic_v_DIR(DIRECTION _DIR_, const IJK_Field_double& input_rho, const IJK_Field_double& input_v, IJK_Field_double& rho_v, const int k)
689{
690 const int ni = rho_v.ni();
691 const int nj = rho_v.nj();
692 ConstIJK_double_ptr rho(input_rho, 0, 0, k);
693 ConstIJK_double_ptr v(input_v, 0, 0, k); // pointeur sur le plan k de la vitesse
694 IJK_double_ptr resu(rho_v, 0, 0, k);
695
696 for (int j = 0; j < nj; j++)
697 {
698 for (int i = 0; i < ni; i++)
699 {
700 double a, b, c;
701 rho.get_left_center(_DIR_, i, a, b); // a et b sont les masses volumiques a gauche et a droite de la face
702 v.get_center(i, c);
703 resu.put_val(i, 2. * a * b / (a + b) * c);
704 }
705 if (j < nj - 1)
706 {
707 rho.next_j();
708 v.next_j();
709 resu.next_j();
710 }
711 }
712}
713
714void calculer_rho_v(const IJK_Field_double& rho, const IJK_Field_vector3_double& v, IJK_Field_vector3_double& rho_v)
715{
716 // Conditions aux limites plans: on suppose que v = 0 sur le plan, alors rho_v sera = 0,
717 // donc il n'y a rien a faire.
718 const int nk = std::max(rho_v[0].nk(), std::max(rho_v[1].nk(), rho_v[2].nk()));
719 // Boucle sur les plans de maillage pour reutiliser les valeurs de rho mises en cache
720 for (int k = 0; k < nk; k++)
721 {
722 // Calcul des trois composantes de vitesse pour ce plan de maillage
723 if (k < rho_v[0].nk())
724 calculer_rho_v_DIR(DIRECTION::X, rho, v[0], rho_v[0], k);
725 if (k < rho_v[1].nk())
726 calculer_rho_v_DIR(DIRECTION::Y, rho, v[1], rho_v[1], k);
727 if (k < rho_v[2].nk())
728 calculer_rho_v_DIR(DIRECTION::Z, rho, v[2], rho_v[2], k);
729 }
730}
731
732// On utilise la moyenne harmonique au lieu de la moyenne arithmetique.
733void calculer_rho_harmonic_v(const IJK_Field_double& rho, const IJK_Field_vector3_double& v, IJK_Field_vector3_double& rho_v)
734{
735 // Conditions aux limites plans: on suppose que v = 0 sur le plan, alors rho_v sera = 0,
736 // donc il n'y a rien a faire.
737 const int nk = std::max(rho_v[0].nk(), std::max(rho_v[1].nk(), rho_v[2].nk()));
738 // Boucle sur les plans de maillage pour reutiliser les valeurs de rho mises en cache
739 for (int k = 0; k < nk; k++)
740 {
741 // Calcul des trois composantes de vitesse pour ce plan de maillage
742 if (k < rho_v[0].nk())
743 calculer_rho_harmonic_v_DIR(DIRECTION::X, rho, v[0], rho_v[0], k);
744 if (k < rho_v[1].nk())
745 calculer_rho_harmonic_v_DIR(DIRECTION::Y, rho, v[1], rho_v[1], k);
746 if (k < rho_v[2].nk())
747 calculer_rho_harmonic_v_DIR(DIRECTION::Z, rho, v[2], rho_v[2], k);
748 }
749}
750
751// Calculer rho*v sur la couche k de faces dans la direction DIR
752// a partir de rho aux elements et v aux faces
753static void mass_solver_with_rho_DIR(DIRECTION _DIR_, const IJK_Field_double& input_rho, IJK_Field_double& velocity, const double volume, const int k)
754{
755 const int ni = velocity.ni();
756 const int nj = velocity.nj();
757 ConstIJK_double_ptr rho(input_rho, 0, 0, k);
758 IJK_double_ptr v(velocity, 0, 0, k);
759
760 const double facteur = volume * 0.5;
761
762 for (int j = 0; j < nj; j++)
763 {
764 for (int i = 0; i < ni; i++)
765 {
766 double a = 0., b = 0., c, resu;
767 rho.get_left_center(_DIR_, i, a, b); // a et b sont les masses volumiques a gauche et a droite de la face
768 v.get_center(i, c); // v
769 resu = c / ((a + b) * facteur); // division par le produit (volume * rho_face)
770 v.put_val(i, resu);
771 }
772 if (j < nj - 1)
773 {
774 rho.next_j();
775 v.next_j();
776 }
777 }
778}
779// Remplace la moyenne arithmetique par une moyenne des inverses :
780// rho_face = 2 rho1 rho2 / (rho1+rho2) => 1/rho_face = (1/rho1 + 1/rho2) /2
781static void mass_solver_with_inv_rho_DIR(DIRECTION _DIR_, const IJK_Field_double& input_inv_rho, IJK_Field_double& velocity, const double volume, const int k)
782{
783 const int ni = velocity.ni();
784 const int nj = velocity.nj();
785 ConstIJK_double_ptr inv_rho(input_inv_rho, 0, 0, k);
786 IJK_double_ptr v(velocity, 0, 0, k);
787
788 const double facteur = 0.5 / volume;
789
790 for (int j = 0; j < nj; j++)
791 {
792 for (int i = 0; i < ni; i++)
793 {
794 double a = 0., b = 0., c, resu;
795 inv_rho.get_left_center(_DIR_, i, a, b); // a et b sont les masses volumiques a gauche et a droite de la face
796 v.get_center(i, c); // v
797 resu = c * (a + b) * facteur; // v * inv_rho_face * volume
798 v.put_val(i, resu);
799 }
800 if (j < nj - 1)
801 {
802 inv_rho.next_j();
803 v.next_j();
804 }
805 }
806}
807
808// Calcule le volume d'un volume de controle situe a l'indice local k
809// en fonction de la localisation du champ
810// (suppose que le maillage est uniforme en i et j)
811// Si maillage non periodique, renvoie le demi-volume pour les faces paroi
812double get_channel_control_volume(IJK_Field_double& field, int local_k_layer, const ArrOfDouble_with_ghost& delta_z_local)
813{
814 double delta_z;
815 const double delta_x = field.get_domaine().get_constant_delta(0);
816 const double delta_y = field.get_domaine().get_constant_delta(1);
817 switch(field.get_localisation())
818 {
822 delta_z = delta_z_local[local_k_layer];
823 break;
825 if (!field.get_domaine().get_periodic_flag(DIRECTION_K))
826 {
827 const int global_k_index = local_k_layer + field.get_domaine().get_offset_local(DIRECTION_K);
828 const int last_global_k = field.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K) - 1;
829 // We have walls, are we on a wall ?
830 if (global_k_index == 0)
831 {
832 delta_z = delta_z_local[local_k_layer] * 0.5; // size of unique neighboug cell
833 }
834 else if (global_k_index == last_global_k)
835 {
836 delta_z = delta_z_local[local_k_layer - 1] * 0.5; // size of unique neighboug cell
837 }
838 else
839 {
840 delta_z = (delta_z_local[local_k_layer - 1] + delta_z_local[local_k_layer]) * 0.5;
841 }
842 }
843 else
844 {
845 // Periodic mesh: always the same formula:
846 delta_z = (delta_z_local[local_k_layer - 1] + delta_z_local[local_k_layer]) * 0.5;
847 }
848 break;
849 default:
850 delta_z = 0.;
851 Cerr << "Error in get_channel_control_volume: invalid field localisation" << finl;
853 }
854 return delta_x * delta_y * delta_z;
855}
856
857// Division de toutes les valeurs stockees dans velocity par le volume du "volume de controle"
858// et par la mase volumique moyenne au noeud de vitesse.
859// (meme moyenne que pour calculer_rho_v)
860void mass_solver_with_rho(IJK_Field_double& velocity, const IJK_Field_double& rho, const ArrOfDouble_with_ghost& delta_z_local, const int k)
861{
862 const double volume = get_channel_control_volume(velocity, k, delta_z_local);
863 switch(velocity.get_localisation())
864 {
866 mass_solver_with_rho_DIR(DIRECTION::X, rho, velocity, volume, k);
867 break;
869 mass_solver_with_rho_DIR(DIRECTION::Y, rho, velocity, volume, k);
870 break;
872 mass_solver_with_rho_DIR(DIRECTION::Z, rho, velocity, volume, k);
873 break;
874 default:
876 }
877}
878
879// Au lieu de diviser par rho, on multiplie par inv_rho
880// C'est mieux car en discret : inv_rho = 1/rho_l * chi_l + 1/rho_v * (1-chi_l)
881void mass_solver_with_inv_rho(IJK_Field_double& velocity, const IJK_Field_double& inv_rho, const ArrOfDouble_with_ghost& delta_z_local, const int k)
882{
883 const double volume = get_channel_control_volume(velocity, k, delta_z_local);
884 switch(velocity.get_localisation())
885 {
887 mass_solver_with_inv_rho_DIR(DIRECTION::X, inv_rho, velocity, volume, k);
888 break;
890 mass_solver_with_inv_rho_DIR(DIRECTION::Y, inv_rho, velocity, volume, k);
891 break;
893 mass_solver_with_inv_rho_DIR(DIRECTION::Z, inv_rho, velocity, volume, k);
894 break;
895 default:
897 }
898}
899
900void mass_solver_scalar(IJK_Field_double& dv, const ArrOfDouble_with_ghost& delta_z_local, int k_index)
901{
902 const double volume = get_channel_control_volume(dv, k_index, delta_z_local);
903 const double constant = 1. / volume;
904 const int imax = dv.ni();
905 const int jmax = dv.nj();
906 for (int j = 0; j < jmax; j++)
907 {
908 for (int i = 0; i < imax; i++)
909 {
910 dv(i, j, k_index) *= constant;
911 }
912 }
913}
914
915// Division de toutes les valeurs stockees dans velocity par
916// la mase volumique moyenne au noeud de vitesse.
917// (meme moyenne que pour calculer_rho_v)
918void density_solver_with_rho(IJK_Field_double& velocity, const IJK_Field_double& rho, const ArrOfDouble_with_ghost& delta_z_local, const int k)
919{
920 switch(velocity.get_localisation())
921 {
923 mass_solver_with_rho_DIR(DIRECTION::X, rho, velocity, 1., k);
924 break;
926 mass_solver_with_rho_DIR(DIRECTION::Y, rho, velocity, 1., k);
927 break;
929 mass_solver_with_rho_DIR(DIRECTION::Z, rho, velocity, 1., k);
930 break;
931 default:
933 }
934}
935
936// fonction moyenne en temps du champs de vitesse utilise dans le cas de bulles fixes
937void update_integral_velocity(const IJK_Field_vector3_double& v_instant, IJK_Field_vector3_double& v_tmp, const IJK_Field_double& indic, const IJK_Field_double& indic_tmp)
938{
939 const int ni = indic_tmp.ni();
940 const int nj = indic_tmp.nj();
941 const int nk = indic_tmp.nk();
942 for (int k = 0; k < nk; k++)
943 {
944 for (int j = 0; j < nj; j++)
945 {
946 for (int i = 0; i < ni; i++)
947 {
948 double u, v, w;
949 u = (v_instant[0](i, j, k) + v_instant[0](i + 1, j, k)) * 0.5;
950 v = (v_instant[1](i, j, k) + v_instant[1](i, j + 1, k)) * 0.5;
951 w = (v_instant[2](i, j, k) + v_instant[2](i, j, k + 1)) * 0.5;
952 if (indic_tmp(i, j, k) + indic(i, j, k) != 0.0)
953 {
954 v_tmp[0](i, j, k) = (v_tmp[0](i, j, k) * indic_tmp(i, j, k) + u * indic(i, j, k)) / (indic_tmp(i, j, k) + indic(i, j, k));
955 v_tmp[1](i, j, k) = (v_tmp[1](i, j, k) * indic_tmp(i, j, k) + v * indic(i, j, k)) / (indic_tmp(i, j, k) + indic(i, j, k));
956 v_tmp[2](i, j, k) = (v_tmp[2](i, j, k) * indic_tmp(i, j, k) + w * indic(i, j, k)) / (indic_tmp(i, j, k) + indic(i, j, k));
957 }
958 }
959 }
960 }
961 v_tmp[0].echange_espace_virtuel(v_tmp[0].ghost());
962 v_tmp[1].echange_espace_virtuel(v_tmp[1].ghost());
963 v_tmp[2].echange_espace_virtuel(v_tmp[2].ghost());
964 return;
965}
966
967/*
968 * Calcul le gradient de U aux cellules a partir de la vitesse aux faces
969 * all components or not.
970 */
971void compute_and_store_gradU_cell(const IJK_Field_double& vitesse_i, const IJK_Field_double& vitesse_j, const IJK_Field_double& vitesse_k,
972 /* Et les champs en sortie */
973 IJK_Field_double& dudx,
974 IJK_Field_double& dvdy, IJK_Field_double& dwdx, IJK_Field_double& dudz, IJK_Field_double& dvdz, IJK_Field_double& dwdz, const int compute_all,
975 /* Following will be untouched if compute_all is 0 */
976 IJK_Field_double& dudy,
977 IJK_Field_double& dvdx, IJK_Field_double& dwdy, IJK_Field_double& lambda2)
978{
979 const Domaine_IJK& geom = vitesse_i.get_domaine();
980
981 // Pour detacher de toute classe :
982 const double dx = geom.get_constant_delta(0);
983 const double dy = geom.get_constant_delta(1);
984 const ArrOfDouble& tab_dz = geom.get_delta(2);
985
986 // Nombre total de mailles en K
987 const int nktot = geom.get_nb_items_global(Domaine_IJK::ELEM, DIRECTION_K);
988 // Nombre local de mailles :
989 const int imax = geom.get_nb_items_local(Domaine_IJK::ELEM, 0);
990 const int jmax = geom.get_nb_items_local(Domaine_IJK::ELEM, 1);
991 const int kmax = geom.get_nb_items_local(Domaine_IJK::ELEM, 2);
992 const int offset = geom.get_offset_local(DIRECTION_K);
993 double residue = 0.;
994 for (int k = 0; k < kmax; k++)
995 {
996 const double dz = tab_dz[k + offset];
997 bool on_the_first_cell = false;
998 bool on_the_last_cell = false;
999 if (k + offset == 0)
1000 on_the_first_cell = true;
1001 if (k + offset == nktot - 1)
1002 on_the_last_cell = true;
1003 for (int j = 0; j < jmax; j++)
1004 {
1005 for (int i = 0; i < imax; i++)
1006 {
1007 // ******************************** //
1008 // derivation direction x
1009 // de Ux
1010 dudx(i, j, k) = (vitesse_i(i + 1, j, k) - vitesse_i(i, j, k)) / dx;
1011
1012 // de Uz !!!!!! ATTENTION on veux calculer la moyenne entre (i,j,k) et (i,j,k+1) aux mailles i-1 et i+1
1013 double We_mi = (vitesse_k(i - 1, j, k) + vitesse_k(i - 1, j, k + 1)) * 0.5;
1014 double We_pi = (vitesse_k(i + 1, j, k) + vitesse_k(i + 1, j, k + 1)) * 0.5;
1015 dwdx(i, j, k) = (We_pi - We_mi) / (2 * dx);
1016
1017 // ******************************** //
1018 // derivation direction y
1019 // de Uy
1020 dvdy(i, j, k) = (vitesse_j(i, j + 1, k) - vitesse_j(i, j, k)) / dy;
1021
1022 if (compute_all)
1023 {
1024 double Ue_mj = (vitesse_i(i, j - 1, k) + vitesse_i(i + 1, j - 1, k)) * 0.5;
1025 double Ue_pj = (vitesse_i(i, j + 1, k) + vitesse_i(i + 1, j + 1, k)) * 0.5;
1026 dudy(i, j, k) = (Ue_pj - Ue_mj) / (2 * dy);
1027 double Ve_mi = (vitesse_j(i - 1, j, k) + vitesse_j(i - 1, j + 1, k)) * 0.5;
1028 double Ve_pi = (vitesse_j(i + 1, j, k) + vitesse_j(i + 1, j + 1, k)) * 0.5;
1029 dvdx(i, j, k) = (Ve_pi - Ve_mi) / (2 * dx);
1030 double We_mj = (vitesse_k(i, j - 1, k) + vitesse_k(i, j - 1, k + 1)) * 0.5;
1031 double We_pj = (vitesse_k(i, j + 1, k) + vitesse_k(i, j + 1, k + 1)) * 0.5;
1032 dwdy(i, j, k) = (We_pj - We_mj) / (2 * dy);
1033 }
1034
1035 // ******************************** //
1036 // derivation direction z
1037 // Si on est sur un bord, on utilise l'info que la vitesse y est nulle.
1038 // Cette info est a dz/2 donc on utilise la formule centree d'ordre 2 pour pas variable :
1039 // Formule centree (ordre 2) pour pas variable dans le domaine :
1040 // grad[1:-1] = (h1/h2*u_pl - h2/h1*u_m + (h2**2-h1**2)/(h1*h2)*u_c) / (h1+h2)
1041 //
1042 if (on_the_first_cell && !(geom.get_periodic_flag(DIRECTION_K)))
1043 {
1044 // de Ux
1045 double Ue_mk = 0.;
1046 double Ue_ck = (vitesse_i(i, j, k) + vitesse_i(i + 1, j, k)) * 0.5;
1047 double Ue_pk = (vitesse_i(i, j, k + 1) + vitesse_i(i + 1, j, k + 1)) * 0.5;
1048 // Formule decentree (ordre 2) pour pas variable sur le bord gauche :
1049 dudz(i, j, k) = (-4 * Ue_mk + 3 * Ue_ck + Ue_pk) / (3 * dz);
1050
1051 // de Uy
1052 double Ve_mk = 0.;
1053 double Ve_ck = (vitesse_j(i, j, k) + vitesse_j(i, j + 1, k)) * 0.5;
1054 double Ve_pk = (vitesse_j(i, j, k + 1) + vitesse_j(i, j + 1, k + 1)) * 0.5;
1055 dvdz(i, j, k) = (-4 * Ve_mk + 3 * Ve_ck + Ve_pk) / (3 * dz);
1056 }
1057 else if (on_the_last_cell && !(geom.get_periodic_flag(DIRECTION_K)))
1058 {
1059 // de Ux
1060 double Ue_mk = (vitesse_i(i, j, k - 1) + vitesse_i(i + 1, j, k - 1)) * 0.5;
1061 double Ue_ck = (vitesse_i(i, j, k) + vitesse_i(i + 1, j, k)) * 0.5;
1062 double Ue_pk = 0.;
1063 // Formule decentree (ordre 2) pour pas variable sur le bord droit :
1064 dudz(i, j, k) = (-Ue_mk - 3 * Ue_ck + 4 * Ue_pk) / (3 * dz);
1065
1066 // de Uy
1067 double Ve_mk = (vitesse_j(i, j, k - 1) + vitesse_j(i, j + 1, k - 1)) * 0.5;
1068 double Ve_ck = (vitesse_j(i, j, k) + vitesse_j(i, j + 1, k)) * 0.5;
1069 double Ve_pk = 0.;
1070 dvdz(i, j, k) = (-Ve_mk - 3 * Ve_ck + 4 * Ve_pk) / (3 * dz);
1071 }
1072 else
1073 {
1074 // For any interior cell... Formule centree pour pas cste
1075
1076 // de Ux !!!!!! ATTENTION on veux calculer la moyenne entre (i,j,k) et (i+1,j,k) aux mailles k-1 et k+1
1077 double Ue_mk = (vitesse_i(i, j, k - 1) + vitesse_i(i + 1, j, k - 1)) * 0.5;
1078 double Ue_pk = (vitesse_i(i, j, k + 1) + vitesse_i(i + 1, j, k + 1)) * 0.5;
1079 dudz(i, j, k) = (Ue_pk - Ue_mk) / (2 * dz);
1080
1081 // de Uy !!!!!! ATTENTION on veux calculer la moyenne entre (i,j,k) et (i,j+1,k) aux mailles k-1 et k+1
1082 double Ve_mk = (vitesse_j(i, j, k - 1) + vitesse_j(i, j + 1, k - 1)) * 0.5;
1083 double Ve_pk = (vitesse_j(i, j, k + 1) + vitesse_j(i, j + 1, k + 1)) * 0.5;
1084 dvdz(i, j, k) = (Ve_pk - Ve_mk) / (2 * dz);
1085 }
1086
1087 // de Uz
1088 dwdz(i, j, k) = (vitesse_k(i, j, k + 1) - vitesse_k(i, j, k)) / dz;
1089
1090 // Calcul de lambda2 :
1091 if (compute_all)
1092 {
1093 // Sij = 1/2*(aij+aji)
1094 double s11 = dudx(i, j, k);
1095 double s12 = (dudy(i, j, k) + dvdx(i, j, k)) * 0.5;
1096 double s13 = (dudz(i, j, k) + dwdx(i, j, k)) * 0.5;
1097 double s21 = s12;
1098 double s22 = dvdy(i, j, k);
1099 double s23 = (dvdz(i, j, k) + dwdy(i, j, k)) * 0.5;
1100 double s31 = s13;
1101 double s32 = s23;
1102 double s33 = dwdz(i, j, k);
1103 squared_3x3(s11, s12, s13, s21, s22, s23, s31, s32, s33);
1104
1105 // Omega_ij = 1/2*(aij-aji)
1106 double o11 = 0.;
1107 double o12 = (dudy(i, j, k) - dvdx(i, j, k)) * 0.5;
1108 double o13 = (dudz(i, j, k) - dwdx(i, j, k)) * 0.5;
1109 double o21 = -o12;
1110 double o22 = 0.;
1111 double o23 = (dvdz(i, j, k) - dwdy(i, j, k)) * 0.5;
1112 double o31 = -o13;
1113 double o32 = -o23;
1114 double o33 = 0.;
1115 squared_3x3(o11, o12, o13, o21, o22, o23, o31, o32, o33);
1116
1117 //
1118 const double a11 = s11 + o11;
1119 const double a12 = s12 + o12;
1120 const double a13 = s13 + o13;
1121 const double a21 = s21 + o21;
1122 const double a22 = s22 + o22;
1123 const double a23 = s23 + o23;
1124 const double a31 = s31 + o31;
1125 const double a32 = s32 + o32;
1126 const double a33 = s33 + o33;
1127
1128 //double a11=1,a22=2,a33=3,a12=0,a21=0,a13=0,a31=0,a23=0,a32=0;
1129 // Changement de tous les signes :
1130 const double a = 1.;
1131 const double b = -(a11 + a22 + a33);
1132 const double c = -(a12 * a21 + a23 * a32 + a13 * a31 - a11 * a22 - a11 * a33 - a22 * a33);
1133 const double d = -(a11 * a22 * a33 + a12 * a23 * a31 + a13 * a32 * a21 - a11 * a23 * a32 - a22 * a13 * a31 - a33 * a12 * a21);
1134
1135 const double delta = 18 * a * b * c * d - 4 * b * b * b * d + b * b * c * c - 4 * a * c * c * c - 27 * a * a * d * d;
1136 const double Q = (3. * c - b * b) / 9.;
1137 const double R = (9. * b * c - 27. * d - 2. * b * b * b) / 54.;
1138 const double D = Q * Q * Q + R * R;
1139 if ((delta < 0) || (Q > 0))
1140 {
1141 double Re_sqrtD, Im_sqrtD;
1142 double mod = 0, arg = 0;
1143 if (D > 0)
1144 {
1145 Cerr << "Singularity for lambda2 at " << i << " " << j << " " << k << " D=" << D << finl;
1146 // only one real value :
1147 Re_sqrtD = sqrt(D);
1148 Im_sqrtD = 0.;
1149 complex_to_trig(R + Re_sqrtD, Im_sqrtD, mod, arg);
1150 // Puissance 1/3 :
1151 const double modS = pow(mod, 1. / 3.);
1152 const double argS = arg / 3.;
1153 const double Re_S = modS * cos(argS);
1154 const double Im_S = modS * sin(argS);
1155 //
1156 complex_to_trig(R - Re_sqrtD, -Im_sqrtD, mod, arg);
1157 // Puissance 1/3 :
1158 const double modT = pow(mod, 1. / 3.);
1159 const double argT = arg / 3.;
1160 const double Re_T = modT * cos(argT);
1161 const double Im_T = modT * sin(argT);
1162
1163 const double Re_B = Re_S + Re_T;
1164 const double Im_B = Im_S + Im_T;
1165 const double Re_A = Re_S - Re_T;
1166 const double Im_A = Im_S - Im_T;
1167 Cerr << "Im_B : " << Im_B << " Re_A : " << Re_A << finl;
1168 const double z1 = -1. / 3. * b + Re_B;
1169 const double z2 = -1. / 3. * b - 0.5 * Re_B + 1. / 2. * sqrt(3.) * Im_A;
1170 const double z3 = -1. / 3. * b - 0.5 * Re_B - 1. / 2. * sqrt(3.) * Im_A;
1171 Cerr << " z1,2,3 = " << z1 << " " << z2 << " " << z3 << finl;
1172 Cerr << "Im_z1,2,3 = " << Im_B << " " << -0.5 * Re_B + sqrt(3) / 2. * Re_A << " " << -0.5 * Re_B - sqrt(3) / 2. * Re_A << finl;
1173 double x = z1 + z2 + z3 - std::min(z1, std::min(z2, z3)) - std::max(z1, std::max(z2, z3));
1174 lambda2(i, j, k) = x;
1175 // Check that lambda2 is root :
1176 x = z1;
1177 Cerr << "x= " << x << " results in: " << a * x * x * x + b * x * x + c * x + d << finl;
1178 x = z2;
1179 Cerr << "x= " << x << " results in: " << a * x * x * x + b * x * x + c * x + d << finl;
1180 x = z3;
1181 Cerr << "x= " << x << " results in: " << a * x * x * x + b * x * x + c * x + d << finl;
1182
1183 }
1184 else
1185 {
1186 lambda2(i, j, k) = -1000.;
1187 Cerr << "Singularity for lambda2 at " << i << " " << j << " " << k << " value prescribed : -1000. ";
1188 Cerr << "delta = " << delta << " ; Q = " << Q << finl;
1189 Cerr << "(R*sqrt(pow(fabs(Q),-3)))= " << (R * sqrt(pow(fabs(Q), -3))) << finl;
1190 }
1191 }
1192 else
1193 {
1194 // Cerr << "D : " << D << finl;
1195 // If computation from scratch, Q=0 at t=0
1196 const double theta = acos(R * sqrt(-pow(Q - DMINFLOAT, -3)));
1197 //Cerr << "theta : " << theta << finl;
1198 const double z1 = 2 * sqrt(-Q) * cos(theta / 3.) - 1. / 3. * b;
1199 const double z2 = 2 * sqrt(-Q) * cos((theta + 2 * M_PI) / 3.) - 1. / 3. * b;
1200 const double z3 = 2 * sqrt(-Q) * cos((theta + 4 * M_PI) / 3.) - 1. / 3. * b;
1201 //Cerr << " z1,2,3 = " << z1 << " " << z2 << " " << z3 << finl;
1202 /*
1203 double Re_sqrtD, Im_sqrtD;
1204 if (D<0)
1205 {
1206 Re_sqrtD = 0.;
1207 Im_sqrtD = sqrt(-D);
1208 }
1209 else
1210 {
1211 Re_sqrtD = sqrt(D);
1212 Im_sqrtD = 0.;
1213 }
1214 double mod=0, arg=0;
1215 complex_to_trig(R+Re_sqrtD, Im_sqrtD, mod, arg);
1216 // Puissance 1/3 :
1217 const double modS = pow(mod, 1./3.);
1218 const double argS = arg /3.;
1219 const double Re_S = modS*cos(argS);
1220 const double Im_S = modS*sin(argS);
1221 //
1222 complex_to_trig(R-Re_sqrtD, -Im_sqrtD, mod, arg);
1223 // Puissance 1/3 :
1224 const double modT = pow(mod, 1./3.);
1225 const double argT = arg /3.;
1226 const double Re_T = modT*cos(argT);
1227 const double Im_T = modT*sin(argT);
1228
1229 const double Re_B = Re_S+Re_T;
1230 const double Im_B = Im_S+Im_T;
1231 const double Re_A = Re_S-Re_T;
1232 const double Im_A = Im_S-Im_T;
1233 Cerr << "Im_B : " << Im_B << " Re_A : " << Re_A << finl;
1234 const double zz1 = -1./3.*b+Re_B;
1235 const double zz2 = -1./3.*b-0.5*Re_B+1./2.*sqrt(3.)*Im_A;
1236 const double zz3 = -1./3.*b-0.5*Re_B-1./2.*sqrt(3.)*Im_A;
1237 Cerr << " zz1,2,3 = " << zz1 << " " << zz2 << " " << zz3 << finl;
1238
1239 //const double delta0 = b*b-3*a*c;
1240 //const double delta1 = 2*b*b*b-9*a*b*c+27*a*a*d;
1241 // Cerr << delta1*delta1-4*delta0*delta0*delta0 << " " << -27.*a*a*delta << finl;
1242 // Apres le premier delta1, WIKI dit +- choix libre ?!
1243 // WIKI : const double C = std::cbrt((delta1+sqrt(delta1*delta1-4*delta0*delta0*delta0))/2.);
1244 // const double C = std::cbrt((delta1+sqrt(-delta1*delta1+4*delta0*delta0*delta0))/2.);
1245 //const double C = cbrt((delta1+sqrt(-delta1*delta1+4*delta0*delta0*delta0))/2.);
1246 //const double r = -1./(3.*a)*(b+C+delta0/C);
1247 //
1248 // Other roots :
1249 //const double dprime = b*b-4*a*c-2*a*b*r-3*a*a*r*r;
1250 // WIKI : const double r1 = (-b-r*a+sqrt(dprime))/(2.*a);
1251 // WIKI : const double r2 = (-b-r*a-sqrt(dprime))/(2.*a);
1252 //const double r1 = (-b-r*a+sqrt(-dprime))/(2.*a);
1253 //const double r2 = (-b-r*a-sqrt(-dprime))/(2.*a);
1254 // Cerr << r << " " << r1 << " " << r2 << finl;
1255 // Sort it out :
1256 */
1257 //DoubleVect roots(3);
1258 //roots[0] = z1;
1259 //roots[1] = z2;
1260 //roots[2] = z3;
1261 //ArrOfInt cc(3);
1262 //trier(roots,cc); // du + grand au plus petit...
1263 //Cerr << roots;
1264 //Cerr << "Sorted roots : " << roots[0] << " " << roots[1] << " " << roots[2] << finl;
1265 const double x = z1 + z2 + z3 - std::min(z1, std::min(z2, z3)) - std::max(z1, std::max(z2, z3));
1266 lambda2(i, j, k) = x;
1267 // Check that lambda2 is root :
1268 const double rr = a * x * x * x + b * x * x + c * x + d;
1269 //const double tol = 0.01;
1270 //if ((rr>tol)||(rr<-tol))
1271 // {
1272 // Cerr << "theta : " << theta << finl;
1273 // Cerr << " z1,2,3 = " << z1 << " " << z2 << " " << z3 << finl;
1274 // //Cerr << "Sorted roots : " << roots[0] << " " << roots[1] << " " << roots[2] << finl;
1275 // Cerr << "x= " << x << " results in: " << rr << finl;
1276 // }
1277 residue = std::max(residue, fabs(rr));
1278 }
1279 }
1280 }
1281 }
1282 }
1283
1284 Cerr << "Maximal residue encountered with lambda2 : " << residue << finl;
1285 // Mise a jour des espaces virtuels :
1286 dudx.echange_espace_virtuel(dudx.ghost());
1287 dvdy.echange_espace_virtuel(dvdy.ghost());
1288 dwdx.echange_espace_virtuel(dwdx.ghost());
1289 dudz.echange_espace_virtuel(dudz.ghost());
1290 dvdz.echange_espace_virtuel(dvdz.ghost());
1291 dwdz.echange_espace_virtuel(dwdz.ghost());
1292
1293 return;
1294}
1295
1296void supprimer_chevauchement(IJK_Field_double& ind)
1297{
1298
1299 const int ni = ind.ni();
1300 const int nj = ind.nj();
1301 const int nk = ind.nk();
1302 for (int k = 0; k < nk; k++)
1303 {
1304 for (int j = 0; j < nj; j++)
1305 {
1306 for (int i = 0; i < ni; i++)
1307 {
1308 if (ind(i, j, k) != 0.0)
1309 {
1310 ind(i, j, k) = 1.0;
1311
1312 }
1313 }
1314 }
1315 }
1316
1317 return;
1318
1319}
1320
1321void update_integral_pressure(const IJK_Field_double& p_instant, IJK_Field_double& p_tmp, const IJK_Field_double& indic, const IJK_Field_double& indic_tmp)
1322{
1323 const int ni = p_instant.ni();
1324 const int nj = p_instant.nj();
1325 const int nk = p_instant.nk();
1326 for (int k = 0; k < nk; k++)
1327 {
1328 for (int j = 0; j < nj; j++)
1329 {
1330 for (int i = 0; i < ni; i++)
1331 {
1332 if (indic_tmp(i, j, k) + indic(i, j, k) != 0.0 and indic(i, j, k) == 1.0)
1333 {
1334 p_tmp(i, j, k) = (p_tmp(i, j, k) * indic_tmp(i, j, k) + p_instant(i, j, k) * indic(i, j, k)) / (indic_tmp(i, j, k) + indic(i, j, k));
1335
1336 }
1337 }
1338 }
1339 }
1340 p_tmp.echange_espace_virtuel(p_tmp.ghost());
1341 return;
1342}
1343
1344// out : the cumulative integral
1345void update_integral_indicatrice(const IJK_Field_double& indic, const double deltat, IJK_Field_double& out)
1346{
1347 const int ni = out.ni();
1348 const int nj = out.nj();
1349 const int nk = out.nk();
1350 for (int k = 0; k < nk; k++)
1351 for (int j = 0; j < nj; j++)
1352 for (int i = 0; i < ni; i++)
1353 out(i, j, k) += indic(i, j, k) * deltat;
1354 return;
1355}
1356
1357double calculer_v_moyen(const IJK_Field_double& vx)
1358{
1359 const Domaine_IJK& geom = vx.get_domaine();
1360 const int ni = vx.ni();
1361 const int nj = vx.nj();
1362 const int nk = vx.nk();
1363 double v_moy = 0.;
1364#ifndef VARIABLE_DZ
1365 for (int k = 0; k < nk; k++)
1366 {
1367 for (int j = 0; j < nj; j++)
1368 {
1369 for (int i = 0; i < ni; i++)
1370 {
1371 v_moy += vx(i, j, k);
1372 }
1373 }
1374 }
1375 // somme sur tous les processeurs.
1376 v_moy = Process::mp_sum(v_moy);
1377 // Maillage uniforme, il suffit donc de diviser par le nombre total de mailles:
1378 // cast en double au cas ou on voudrait faire un maillage >2 milliards
1379 const double n_mailles_tot = ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1) * geom.get_nb_elem_tot(2);
1380 v_moy /= n_mailles_tot;
1381#else
1382 const int offset = splitting.get_offset_local(DIRECTION_K);
1383 const ArrOfDouble& tab_dz=geom.get_delta(DIRECTION_K);
1384 for (int k = 0; k < nk; k++)
1385 {
1386 const double dz = tab_dz[k+offset];
1387 for (int j = 0; j < nj; j++)
1388 {
1389 for (int i = 0; i < ni; i++)
1390 {
1391 v_moy += vx(i,j,k)*dz;
1392 }
1393 }
1394 }
1395 // somme sur tous les processeurs.
1396 v_moy = Process::mp_sum(v_moy);
1397 // Maillage uniforme, il suffit donc de diviser par le nombre total de mailles:
1398 // cast en double au cas ou on voudrait faire un maillage >2 milliards
1399 const double n_mailles_xy = ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1);
1400 v_moy /= (n_mailles_xy * geom.get_domain_length(DIRECTION_K) );
1401#endif
1402 return v_moy;
1403}
1404
1405double calculer_vl_moyen(const IJK_Field_double& vx, const IJK_Field_double& indic)
1406{
1407 const Domaine_IJK& geom = vx.get_domaine();
1408 const int ni = vx.ni();
1409 const int nj = vx.nj();
1410 const int nk = vx.nk();
1411 double v_moy = 0.;
1412 double indic_moy = 0.;
1413 for (int k = 0; k < nk; k++)
1414 {
1415 for (int j = 0; j < nj; j++)
1416 {
1417 for (int i = 0; i < ni; i++)
1418 {
1419 v_moy += vx(i,j,k)*(1.-indic(i,j,k));
1420 indic_moy+=1.-indic(i,j,k);
1421 }
1422 }
1423 }
1424 // somme sur tous les processeurs.
1425 v_moy = Process::mp_sum(v_moy);
1426 indic_moy = Process::mp_sum(indic_moy);
1427 // Maillage uniforme, il suffit donc de diviser par le nombre total de mailles:
1428 // cast en double au cas ou on voudrait faire un maillage >2 milliards
1429 const double n_mailles_tot = ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1) * geom.get_nb_elem_tot(2);
1430 v_moy /= n_mailles_tot;
1431 indic_moy /= n_mailles_tot;
1432
1433 return v_moy/indic_moy;
1434}
1435
1436double calculer_rho_cp_u_moyen(const IJK_Field_double& vx, const IJK_Field_double& cp_rhocp_rhocpinv, const IJK_Field_double& rho_field, const double& rho_cp, const int rho_cp_case)
1437{
1438 const int ni = vx.ni();
1439 const int nj = vx.nj();
1440 const int nk = vx.nk();
1441 double rho_cp_u_moy = 0.;
1442 double rho = 1.;
1443 double cp = 1.;
1444 for (int k = 0; k < nk; k++)
1445 for (int j = 0; j < nj; j++)
1446 for (int i = 0; i < ni; i++)
1447 {
1448 switch(rho_cp_case)
1449 {
1450 case 0:
1451 rho = rho_field(i, j, k);
1452 cp = cp_rhocp_rhocpinv(i, j, k);
1453 break;
1454 case 1:
1455 rho = cp_rhocp_rhocpinv(i, j, k);
1456 break;
1457 case 2:
1458 rho = rho_cp;
1459 break;
1460 case 3:
1461 rho = (1 / cp_rhocp_rhocpinv(i, j, k));
1462 break;
1463 default:
1464 rho = rho_field(i, j, k);
1465 cp = cp_rhocp_rhocpinv(i, j, k);
1466 break;
1467 }
1468 const double u = (vx(i, j, k) + vx(i + 1, j, k)) / 2;
1469 const double rho_cp_u = rho * cp * u;
1470 rho_cp_u_moy += rho_cp_u;
1471 }
1472 // somme sur tous les processeurs.
1473 rho_cp_u_moy = Process::mp_sum(rho_cp_u_moy);
1474 // Maillage uniforme, il suffit donc de diviser par le nombre total de mailles:
1475 // cast en double au cas ou on voudrait faire un maillage >2 milliards
1476 const Domaine_IJK& geom = vx.get_domaine();
1477 const double n_mailles_tot = ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1) * geom.get_nb_elem_tot(2);
1478 rho_cp_u_moy /= n_mailles_tot;
1479 return rho_cp_u_moy;
1480}
1481
1482double calculer_temperature_adimensionnelle_theta_moy(const IJK_Field_double& vx, const IJK_Field_double& temperature_adimensionnelle_theta, const IJK_Field_double& cp_rhocp_rhocpinv,
1483 const IJK_Field_double& rho_field, const double& rho_cp, const int rho_cp_case)
1484{
1485 const Domaine_IJK& geom = temperature_adimensionnelle_theta.get_domaine();
1486 double theta_adim_moy = 0;
1487 double rho_cp_u_moy = 0;
1488 double rho = 1.;
1489 double cp = 1.;
1490
1491 const int nk = temperature_adimensionnelle_theta.nk();
1492 const int ni = temperature_adimensionnelle_theta.ni();
1493 const int nj = temperature_adimensionnelle_theta.nj();
1494 for (int k = 0; k < nk; k++)
1495 for (int j = 0; j < nj; j++)
1496 for (int i = 0; i < ni; i++)
1497 {
1498 switch(rho_cp_case)
1499 {
1500 case 0:
1501 rho = rho_field(i, j, k);
1502 cp = cp_rhocp_rhocpinv(i, j, k);
1503 break;
1504 case 1:
1505 rho = cp_rhocp_rhocpinv(i, j, k);
1506 break;
1507 case 2:
1508 rho = rho_cp;
1509 break;
1510 case 3:
1511 rho = (1 / cp_rhocp_rhocpinv(i, j, k));
1512 break;
1513 default:
1514 rho = rho_field(i, j, k);
1515 cp = cp_rhocp_rhocpinv(i, j, k);
1516 break;
1517 }
1518 const double theta_adim = temperature_adimensionnelle_theta(i, j, k);
1519 const double u = (vx(i, j, k) + vx(i + 1, j, k)) / 2.;
1520 rho_cp_u_moy += rho * cp * u;
1521 theta_adim_moy += rho * cp * u * theta_adim;
1522 }
1523 //somme sur les proc
1524 rho_cp_u_moy = Process::mp_sum(rho_cp_u_moy);
1525 theta_adim_moy = Process::mp_sum(theta_adim_moy);
1526 //Division par le nombre de mailles
1527 const double n_mailles_tot = ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1) * geom.get_nb_elem_tot(2);
1528 rho_cp_u_moy /= n_mailles_tot;
1529 theta_adim_moy /= n_mailles_tot;
1530 //valeur adimensionnelle moyenne
1531 theta_adim_moy /= rho_cp_u_moy;
1532 return theta_adim_moy;
1533}
1534
1535double calculer_variable_wall(const IJK_Field_double& variable, const IJK_Field_double& cp_rhocp_rhocpinv, const IJK_Field_double& rho_field, const double& rho_cp, const int kmin, const int kmax,
1536 const int rho_cp_case)
1537{
1538 const Domaine_IJK& geom = variable.get_domaine();
1539 double variable_moy = 0;
1540 double rho_cp_moy = 0.;
1541 const int nk = variable.nk();
1542 if (kmin == 0)
1543 calculer_rho_cp_var(variable, cp_rhocp_rhocpinv, rho_field, rho_cp, rho_cp_moy, variable_moy, kmin, rho_cp_case);
1544 if (kmin + variable.nk() == kmax)
1545 {
1546 int k = nk - 1;
1547 calculer_rho_cp_var(variable, cp_rhocp_rhocpinv, rho_field, rho_cp, rho_cp_moy, variable_moy, k, rho_cp_case);
1548 }
1549 //somme sur les proc
1550 rho_cp_moy = Process::mp_sum(rho_cp_moy);
1551 variable_moy = Process::mp_sum(variable_moy);
1552 //Division par le nombre de mailles sur les 2 plans de bords
1553 const double n_mailles_plan_xy_tot = 2. * ((double) geom.get_nb_elem_tot(0)) * geom.get_nb_elem_tot(1);
1554 rho_cp_moy /= n_mailles_plan_xy_tot;
1555 variable_moy /= n_mailles_plan_xy_tot;
1556 //valeur adimensionnelle moyenne
1557 variable_moy /= rho_cp_moy;
1558 return variable_moy;
1559}
1560
1561void calculer_rho_cp_var(const IJK_Field_double& variable, const IJK_Field_double& cp_rhocp_rhocpinv, const IJK_Field_double& rho, const double& rho_cp, double& rho_cp_moy, double& variable_moy,
1562 int k, const int rho_cp_case)
1563{
1564 const int ni = variable.ni();
1565 const int nj = variable.nj();
1566 double rho_ijk = 1.;
1567 double cp_ijk = 1.;
1568 for (int j = 0; j < nj; j++)
1569 for (int i = 0; i < ni; i++)
1570 {
1571 switch(rho_cp_case)
1572 {
1573 case 0:
1574 rho_ijk = rho(i, j, k);
1575 cp_ijk = cp_rhocp_rhocpinv(i, j, k);
1576 break;
1577 case 1:
1578 rho_ijk = cp_rhocp_rhocpinv(i, j, k);
1579 break;
1580 case 2:
1581 rho_ijk = rho_cp;
1582 break;
1583 case 3:
1584 rho_ijk = (1 / cp_rhocp_rhocpinv(i, j, k));
1585 break;
1586 default:
1587 rho_ijk = rho(i, j, k);
1588 cp_ijk = cp_rhocp_rhocpinv(i, j, k);
1589 break;
1590 }
1591 const double var = variable(i, j, k);
1592 rho_cp_moy += rho_ijk * cp_ijk;
1593 variable_moy += rho_ijk * cp_ijk * var;
1594 }
1595}
1596
1597/*
1598 * Temperature gradient calculation
1599 */
1600void add_gradient_temperature(const IJK_Field_double& temperature, const double constant, IJK_Field_double& grad_T_x, IJK_Field_double& grad_T_y, IJK_Field_double& grad_T_z,
1601 const Boundary_Conditions_Thermique& boundary, const IJK_Field_double& lambda)
1602{
1603 const Domaine_IJK& geom = grad_T_x.get_domaine();
1604 const int kmax = std::max(std::max(grad_T_x.nk(), grad_T_y.nk()), grad_T_z.nk());
1605 for (int k = 0; k < kmax; k++)
1606 {
1607 // i component of the temperature gradient:
1608 if (k < grad_T_x.nk())
1609 {
1610 const int jmax = grad_T_x.nj();
1611 const int imax = grad_T_x.ni();
1612 const double f = constant / geom.get_constant_delta(0);
1613 for (int j = 0; j < jmax; j++)
1614 for (int i = 0; i < imax; i++)
1615 grad_T_x(i, j, k) += (temperature(i, j, k) - temperature(i - 1, j, k)) * f;
1616 }
1617 // j component of the temperature gradient:
1618 if (k < grad_T_y.nk())
1619 {
1620 const int jmax = grad_T_y.nj();
1621 const int imax = grad_T_y.ni();
1622 const double f = constant / geom.get_constant_delta(1);
1623 for (int j = 0; j < jmax; j++)
1624 for (int i = 0; i < imax; i++)
1625 grad_T_y(i, j, k) += (temperature(i, j, k) - temperature(i, j - 1, k)) * f;
1626 }
1627 // k component of the temperature gradient:
1628 bool on_the_wall = false;
1629 bool on_the_first_cell = false;
1630 bool on_the_last_cell = false;
1631 int bctype_kmin = boundary.get_bctype_k_min();
1632 int bctype_kmax = boundary.get_bctype_k_max();
1633
1634 const int k_min = grad_T_z.get_domaine().get_offset_local(DIRECTION_K);
1635 const int nk_tot = grad_T_z.get_domaine().get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
1636 const int offset = grad_T_z.get_domaine().get_offset_local(DIRECTION_K);
1637 const ArrOfDouble& delta_z_all = geom.get_delta(DIRECTION_K);
1638 bool perio_k = grad_T_z.get_domaine().get_periodic_flag(DIRECTION_K);
1639 if ((k + k_min == 0 || k + k_min == nk_tot - 1) && (!perio_k))
1640 on_the_wall = true;
1641
1642 if (k < grad_T_z.nk() && (!on_the_wall))
1643 {
1644 const int jmax = grad_T_z.nj();
1645 const int imax = grad_T_z.ni();
1646 double f;
1647 if (!perio_k)
1648 {
1649 f = constant * 2. / (delta_z_all[k - 1 + k_min] + delta_z_all[k + k_min]);
1650 }
1651 else
1652 {
1653 f = (constant / delta_z_all[k + offset]);
1654 }
1655 for (int j = 0; j < jmax; j++)
1656 for (int i = 0; i < imax; i++)
1657 grad_T_z(i, j, k) += (temperature(i, j, k) - temperature(i, j, k - 1)) * f;
1658 }
1659 else if (k < grad_T_z.nk() && (on_the_wall))
1660 {
1661 if (k + k_min == 0)
1662 on_the_first_cell = true;
1663 if (k + k_min == nk_tot - 1)
1664 on_the_last_cell = true;
1665
1666 if (on_the_first_cell)
1667 {
1668 const int jmax = grad_T_z.nj();
1669 const int imax = grad_T_z.ni();
1670 double f;
1671 if (bctype_kmin == 0)
1672 {
1673 f = constant * 2. / delta_z_all[k + offset];
1674 // schema decentre prenant en compte le bord et les trois centres de cellules suivants
1675 // pour calculer le gradient a la demi-longueur
1676 //const double coef = 1./48.;
1677
1678 const double temperature_kmin = boundary.get_temperature_kmin();
1679 for (int j = 0; j < jmax; j++)
1680 for (int i = 0; i < imax; i++)
1681 grad_T_z(i, j, 0) += (temperature(i, j, 0) - temperature_kmin) * f;
1682 // grad_T_z(i,j,0) += (- (23.* temperature_kmin) + (21. * temperature(i,j,k)) + (3.* temperature(i,j,k+1)) - (1. * temperature(i,j,k+2)) ) * f * coef;
1683 // grad_T_z(i,j,0) += ( 23.*temperature_kmin - 21.*temperature(i,j,k) - 3.*temperature(i,j,k+1) + 1.*temperature(i,j,k+2)) * f *coef;
1684
1685 }
1686
1687 if (bctype_kmin == 1)
1688 {
1689 const double flux_kmin = boundary.get_flux_kmin();
1690 for (int j = 0; j < jmax; j++)
1691 for (int i = 0; i < imax; i++)
1692 {
1693 double l = lambda(i, j, 0);
1694 grad_T_z(i, j, 0) += -flux_kmin / l;
1695 }
1696
1697 }
1698 }
1699
1700 if (on_the_last_cell)
1701 {
1702 const int jmax = grad_T_z.nj();
1703 const int imax = grad_T_z.ni();
1704 double f;
1705
1706 if (bctype_kmax == 0)
1707 {
1708 f = constant * 2. / delta_z_all[k - 1 + offset];
1709
1710 Cerr << "IJK_Naviers_Stokes" << " " << "erreur_dans_le_calcul_du_gradient_de_T" << finl;
1711
1712 const double temperature_kmax = boundary.get_temperature_kmax();
1713 //const double coef = 1./48.;
1714 for (int j = 0; j < jmax; j++)
1715 for (int i = 0; i < imax; i++)
1716 grad_T_z(i, j, k) += (temperature_kmax - temperature(i, j, k - 1)) * f;
1717 //grad_T_z(i,j,k) += ( 23.*temperature_kmax - 21.*temperature(i,j,k-1) - 3.*temperature(i,j,k-2) + 1.*temperature(i,j,k-3)) * f *coef;
1718 // grad_T_z(i,j,k) += (-23.*temperature_kmax + 21.*temperature(i,j,k-1) + 3.*temperature(i,j,k-2)-1.*temperature(i,j,k+2) ) * f * coef;
1719 }
1720
1721 if (bctype_kmax == 1)
1722 {
1723 const double flux_kmax = boundary.get_flux_kmax();
1724 for (int j = 0; j < jmax; j++)
1725 for (int i = 0; i < imax; i++)
1726 {
1727 double l = lambda(i, j, k - 1);
1728 grad_T_z(i, j, k) += flux_kmax / l;
1729 }
1730 }
1731 }
1732 }
1733
1734 }
1735}
1736
1737void force_entry_velocity(IJK_Field_double& vx, IJK_Field_double& vy, IJK_Field_double& vz, double v_imposed, const int& dir, const int& compo, const int& stencil)
1738{
1739 const Domaine_IJK& splitting = select_dir(dir, vx.get_domaine(), vy.get_domaine(), vz.get_domaine());
1740 const int offset_ijk = splitting.get_offset_local(dir);
1741
1742 if (offset_ijk > 0)
1743 return;
1744
1745 double imposed[3] = { v_imposed, v_imposed, v_imposed };
1746 const int direction_min = (compo == -1) ? 0 : dir;
1747 const int direction_max = (compo == -1) ? 3 : dir + 1;
1748 for (int direction = direction_min; direction < direction_max; direction++)
1749 {
1750 IJK_Field_double& velocity = select_dir(direction, vx, vy, vz);
1751 const int imin = select_dir(direction, 0, 0, 0);
1752 const int jmin = select_dir(direction, 0, 0, 0);
1753 const int kmin = select_dir(direction, 0, 0, 0);
1754 const int imax = select_dir(direction, stencil, velocity.ni(), velocity.ni());
1755 const int jmax = select_dir(direction, velocity.nj(), stencil, velocity.nj());
1756 const int kmax = select_dir(direction, velocity.nk(), velocity.nk(), stencil);
1757 for (int k = kmin; k < kmax; k++)
1758 for (int j = jmin; j < jmax; j++)
1759 for (int i = imin; i < imax; i++)
1760 velocity(i, j, k) = imposed[direction];
1761 }
1762}
: class Boundary_Conditions_Thermique
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.
int get_nb_items_local(Localisation loc, int direction) const
Returns the number of local items (on this processor) for the given localisation in the requested dir...
double get_constant_delta(int direction) const
Returns the size of cells in a direction.
const ArrOfDouble & get_delta(int direction) const
Returns the array of mesh cell sizes in requested direction.
int get_nb_items_global(Localisation loc, int direction) const
Returns the number of local items (on this processor) for the given localisation in the requested dir...
int get_nb_elem_tot(int direction) const
Returns the total (global) number of mesh cells in requested direction.
void ajouter_second_membre_shear_perio(IJK_Field_double &resu)
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
Domaine_IJK::Localisation get_localisation() const
const Domaine_IJK & get_domaine() const
int nb_sommets() const
renvoie le nombre de sommets (reels et virtuels) (egal a sommets().
int sommet_virtuel(int i) const
: class Maillage_FT_IJK
void set_inv_rho(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &inv_rho)
void set_rho(const DoubleVect &rho)
void set_rho_NoSym(const DoubleVect &rho)
void set_inv_rho_NoSym(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &inv_rho)
void resoudre_systeme_IJK(const IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &rhs, IJK_Field_template< _TYPE_, _TYPE_ARRAY_ > &x)
static bool CHECK_DIVERGENCE
Definition Option_IJK.h:26
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469