1 /*============================================================================
2 * Functions associated to VOF model
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #include "cs_defs.h"
28
29 /*----------------------------------------------------------------------------
30 * Standard C library headers
31 *----------------------------------------------------------------------------*/
32
33 /*----------------------------------------------------------------------------
34 * Local headers
35 *----------------------------------------------------------------------------*/
36
37 #include "bft_mem.h"
38 #include "bft_printf.h"
39
40 #include "cs_base.h"
41 #include "cs_boundary_conditions.h"
42 #include "cs_boundary_zone.h"
43 #include "cs_cdo_quantities.h"
44 #include "cs_cdo_connect.h"
45 #include "cs_cdo_main.h"
46 #include "cs_convection_diffusion.h"
47 #include "cs_domain.h"
48 #include "cs_domain_setup.h"
49 #include "cs_equation.h"
50 #include "cs_equation_iterative_solve.h"
51 #include "cs_face_viscosity.h"
52 #include "cs_divergence.h"
53 #include "cs_field.h"
54 #include "cs_field_pointer.h"
55 #include "cs_field_operator.h"
56 #include "cs_gui_mobile_mesh.h"
57 #include "cs_interface.h"
58 #include "cs_log.h"
59 #include "cs_physical_constants.h"
60 #include "cs_math.h"
61 #include "cs_mesh.h"
62 #include "cs_mesh_quantities.h"
63 #include "cs_mesh_bad_cells.h"
64 #include "cs_parall.h"
65 #include "cs_time_step.h"
66 #include "cs_rotation.h"
67 #include "cs_turbomachinery.h"
68
69 /*----------------------------------------------------------------------------
70 * Header for the current file
71 *----------------------------------------------------------------------------*/
72
73 #include "cs_vof.h"
74
75 /*----------------------------------------------------------------------------*/
76
77 BEGIN_C_DECLS
78
79 /*=============================================================================
80 * Additional doxygen documentation
81 *============================================================================*/
82
83 /*!
84 \file cs_vof.c
85 VOF model data.
86 */
87
88 /*----------------------------------------------------------------------------*/
89
90 /*!
91
92 \defgroup homogeneous_mixture Homogeneous mixture modelling
93
94 @addtogroup homogeneous_mixture
95 @{
96
97 \defgroup vof VOF model for free surface flow or dispersed flow
98
99 @addtogroup vof
100 @{
101
102 \defgroup vof_mixture_properties Mixture properties
103
104 @addtogroup vof_mixture_properties
105 @{
106
107 \struct cs_vof_parameters_t
108
109 \brief VOF model parameters. Void fraction variable tracks fluid 2.
110
111 Members of this structure are publicly accessible to allow for concise
112 syntax, as it is expected to be used in many places.
113
114 \var cs_vof_parameters_t::vof_model
115 Volume of Fluid model - sum of masks defining VoF model and submodels.
116 See defined masks in \ref vof_masks.
117
118 \var cs_vof_parameters_t::rho1
119 reference density of fluid 1 (kg/m3).
120 By convention, liquid phase for cavitation model.
121
122 \var cs_vof_parameters_t::rho2
123 reference density of fluid 2 (kg/m3).
124 By convention, gas phase for cavitation model.
125
126 \var cs_vof_parameters_t::mu1
127 reference molecular viscosity of fluid 1 (kg/(m s))
128
129 \var cs_vof_parameters_t::mu2
130 reference molecular viscosity of fluid 2 (kg/(m s))
131
132 \var cs_vof_parameters_t::idrift
133 drift velocity model
134 - 0: drift model disable
135 - 1: field inner_drift_velocity_flux is used
136 Deshpande's model
137 - 2: field drift_velocity is used
138 User-defined drift velocity field
139
140 \var cs_vof_parameters_t::cdrift
141 Flux factor parameter.
142 In case of drift flux, factor of the local flux compared to the
143 global max flux.
144
145 \var cs_vof_parameters_t::kdrift
146 Turbulent like diffusion effect (m2/s).
147 In case of drift velocity, factor of a volume fraction gradient
148
149 @}
150
151 \defgroup cavitation Cavitation model
152
153 @addtogroup cavitation
154 @{
155
156 \struct cs_cavitation_parameters_t
157
158 \brief Cavitation model parameters.
159
160 Members of this structure are publicly accessible to allow for concise
161 syntax, as it is expected to be used in many places.
162
163 \defgroup cav_source_term Vaporization/condensation model
164
165 @addtogroup cav_source_term
166 @{
167
168 \var cs_cavitation_parameters_t::presat
169 Reference saturation pressure (kg/(m s2)).
170
171 \var cs_cavitation_parameters_t::uinf
172 Reference velocity of the flow (m/s).
173
174 \var cs_cavitation_parameters_t::linf
175 Reference length scale of the flow (m).
176
177 \var cs_cavitation_parameters_t::cdest
178 Constant Cdest of the condensation source term (Merkle model).
179
180 \var cs_cavitation_parameters_t::cprod
181 Constant Cprod of the vaporization source term (Merkle model).
182
183 @}
184
185 \defgroup cav_turbulence Interaction with turbulence
186
187 @addtogroup cav_turbulence
188 @{
189
190 \var cs_cavitation_parameters_t::icvevm
191 Activation of the eddy-viscosity correction (Reboud correction).
192 - 1: activated
193 - 0: desactivated
194
195 \var cs_cavitation_parameters_t::mcav
196 Constant mcav of the eddy-viscosity correction (Reboud correction).
197
198 @}
199
200 \defgroup cav_numerics Numerical parameters
201
202 @addtogroup cav_numerics
203 @{
204
205 \var cs_cavitation_parameters_t::itscvi
206 Implicitation in pressure of the vaporization/condensation model
207 - 1: activated
208 - 0: desactivated
209
210 @}
211
212 @}
213
214 @}
215
216 @}
217
218 */
219 /*----------------------------------------------------------------------------*/
220
221 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
222
223 /*============================================================================
224 * Static variables
225 *============================================================================*/
226
227 static cs_vof_parameters_t _vof_parameters =
228 {
229 .vof_model = 0,
230 .rho1 = 1.e3,
231 .rho2 = 1.,
232 .mu1 = 1.e-3,
233 .mu2 = 1.e-5,
234 .idrift = 0,
235 .cdrift = 1.,
236 .kdrift = 0.
237 };
238
239 static cs_cavitation_parameters_t _cavit_parameters =
240 {
241 .presat = 2.e3,
242 .uinf = -1e13,
243 .linf = 1.e-1,
244 .cdest = 5.e1,
245 .cprod = 1.e4,
246 .icvevm = 1,
247 .mcav = 1.e1,
248 .itscvi = 1
249 };
250
251 /*============================================================================
252 * Global variables
253 *============================================================================*/
254
255 const cs_vof_parameters_t *cs_glob_vof_parameters = &_vof_parameters;
256
257 /*============================================================================
258 * Prototypes for functions intended for use only by Fortran wrappers.
259 * (descriptions follow, with function bodies).
260 *============================================================================*/
261
262 void
263 cs_f_vof_get_pointers(unsigned **ivofmt,
264 double **rho1,
265 double **rho2,
266 double **mu1,
267 double **mu2,
268 int **idrift,
269 double **cdrift,
270 double **kdrift);
271
272 void
273 cs_f_vof_compute_linear_rho_mu(void);
274
275 void
276 cs_f_vof_update_phys_prop(void);
277
278 void
279 cs_f_vof_log_mass_budget(void);
280
281 void
282 cs_f_vof_deshpande_drift_flux(void);
283
284 void
285 cs_f_vof_update_drift_flux(void);
286
287 void
288 cs_f_cavitation_get_pointers(double **presat,
289 double **uinf,
290 double **linf,
291 double **cdest,
292 double **cprod,
293 int **icvevm,
294 double **mcav,
295 int **itscvi);
296
297 /*============================================================================
298 * Fortran wrapper function definitions
299 *============================================================================*/
300
301 /*----------------------------------------------------------------------------
302 * Get pointer to VOF model indicator and parameters
303 *
304 * This function is intended for use by Fortran wrappers, and
305 * enables mapping to Fortran global pointers.
306 *
307 * parameters:
308 * ivofmt --> pointer to cs_glob_vof_parameters->vof_model
309 * rho1 --> pointer to cs_glob_vof_parameters->rho1
310 * rho2 --> pointer to cs_glob_vof_parameters->rho2
311 * mu1 --> pointer to cs_glob_vof_parameters->mu1
312 * mu2 --> pointer to cs_glob_vof_parameters->mu2
313 * idrift --> pointer to cs_glob_vof_parameters->idrift
314 * cdrift --> pointer to cs_glob_vof_parameters->cdrift
315 * kdrift --> pointer to cs_glob_vof_parameters->kdrift
316 *----------------------------------------------------------------------------*/
317
318 void
cs_f_vof_get_pointers(unsigned ** ivofmt,double ** rho1,double ** rho2,double ** mu1,double ** mu2,int ** idrift,double ** cdrift,double ** kdrift)319 cs_f_vof_get_pointers(unsigned **ivofmt,
320 double **rho1,
321 double **rho2,
322 double **mu1,
323 double **mu2,
324 int **idrift,
325 double **cdrift,
326 double **kdrift)
327 {
328 *ivofmt = &(_vof_parameters.vof_model);
329 *rho1 = &(_vof_parameters.rho1);
330 *rho2 = &(_vof_parameters.rho2);
331 *mu1 = &(_vof_parameters.mu1);
332 *mu2 = &(_vof_parameters.mu2);
333 *idrift = &(_vof_parameters.idrift);
334 *cdrift = &(_vof_parameters.cdrift);
335 *kdrift = &(_vof_parameters.kdrift);
336 }
337
338 /*----------------------------------------------------------------------------
339 * wrapper vof functions, intended for use by Fortran wrapper only.
340 *----------------------------------------------------------------------------*/
341
342 void
cs_f_vof_compute_linear_rho_mu(void)343 cs_f_vof_compute_linear_rho_mu(void)
344 {
345 cs_vof_compute_linear_rho_mu(cs_glob_domain);
346 }
347
348 void
cs_f_vof_update_phys_prop(void)349 cs_f_vof_update_phys_prop(void)
350 {
351 cs_vof_update_phys_prop(cs_glob_domain);
352 }
353
354 void
cs_f_vof_log_mass_budget(void)355 cs_f_vof_log_mass_budget(void)
356 {
357 cs_vof_log_mass_budget(cs_glob_domain);
358 }
359
360 void
cs_f_vof_deshpande_drift_flux(void)361 cs_f_vof_deshpande_drift_flux(void)
362 {
363 cs_vof_deshpande_drift_flux(cs_glob_domain);
364 }
365
366 /*----------------------------------------------------------------------------
367 * Get pointer to cavitation model indicator and parameters
368 *
369 * This function is intended for use by Fortran wrappers, and
370 * enables mapping to Fortran global pointers.
371 *
372 * parameters:
373 * presat --> pointer to cs_glob_cavitation_parameters->presat
374 * uinf --> pointer to cs_glob_cavitation_parameters->uinf
375 * linf --> pointer to cs_glob_cavitation_parameters->linf
376 * cdest --> pointer to cs_glob_cavitation_parameters->cdest
377 * cprod --> pointer to cs_glob_cavitation_parameters->cprod
378 * icvevm --> pointer to cs_glob_cavitation_parameters->icvevm
379 * mcav --> pointer to cs_glob_cavitation_parameters->mcav
380 * itscvi --> pointer to cs_glob_cavitation_parameters->itscvi
381 *----------------------------------------------------------------------------*/
382
383 void
cs_f_cavitation_get_pointers(double ** presat,double ** uinf,double ** linf,double ** cdest,double ** cprod,int ** icvevm,double ** mcav,int ** itscvi)384 cs_f_cavitation_get_pointers(double **presat,
385 double **uinf,
386 double **linf,
387 double **cdest,
388 double **cprod,
389 int **icvevm,
390 double **mcav,
391 int **itscvi)
392 {
393 *presat = &(_cavit_parameters.presat);
394 *uinf = &(_cavit_parameters.uinf);
395 *linf = &(_cavit_parameters.linf);
396 *cdest = &(_cavit_parameters.cdest);
397 *cprod = &(_cavit_parameters.cprod);
398 *icvevm = &(_cavit_parameters.icvevm);
399 *mcav = &(_cavit_parameters.mcav);
400 *itscvi = &(_cavit_parameters.itscvi);
401 }
402
403 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
404
405 /*============================================================================
406 * Public function definitions
407 *============================================================================*/
408
409 /*----------------------------------------------------------------------------
410 *!
411 * \brief Provide access to VOF structure.
412 */
413 /*----------------------------------------------------------------------------*/
414
415 cs_vof_parameters_t *
cs_get_glob_vof_parameters(void)416 cs_get_glob_vof_parameters(void)
417 {
418 return &_vof_parameters;
419 }
420
421 /*----------------------------------------------------------------------------*/
422 /*!
423 * \brief Compute the mixture density, mixture dynamic viscosity given fluid
424 * volume fractions and the reference density and dynamic viscosity
425 * \f$ \rho_l, \mu_l \f$ (liquid), \f$ \rho_v, \mu_v \f$ (gas).
426 *
427 * Computation is done as follows on cells:
428 * \f[
429 * \rho_\celli = \alpha_\celli \rho_v + (1-\alpha_\celli) \rho_l,
430 * \f]
431 * \f[
432 * \mu_\celli = \alpha_\celli \mu_v + (1-\alpha_\celli) \mu_l,
433 * \f]
434 *
435 * A similar linear formula is followed on boundary using fluid volume fraction
436 * value on the boundary.
437 */
438 /*----------------------------------------------------------------------------*/
439
440 void
cs_vof_compute_linear_rho_mu(const cs_domain_t * domain)441 cs_vof_compute_linear_rho_mu(const cs_domain_t *domain)
442 {
443 const cs_mesh_t *m = domain->mesh;
444 const cs_lnum_t n_cells = m->n_cells;
445 const cs_lnum_t n_b_faces = m->n_b_faces;
446
447 const cs_lnum_t *b_face_cells = m->b_face_cells;
448
449 cs_real_t *cvar_voidf = CS_F_(void_f)->val;
450 cs_real_t *a_voidf = CS_F_(void_f)->bc_coeffs->a;
451 cs_real_t *b_voidf = CS_F_(void_f)->bc_coeffs->b;
452
453 cs_real_t *cpro_rom = CS_F_(rho)->val;
454 cs_real_t *bpro_rom = CS_F_(rho_b)->val;
455
456 cs_real_t *cpro_viscl = CS_F_(mu)->val;
457
458 const cs_real_t rho1 = _vof_parameters.rho1;
459 const cs_real_t rho2 = _vof_parameters.rho2;
460 const cs_real_t mu1 = _vof_parameters.mu1;
461 const cs_real_t mu2 = _vof_parameters.mu2;
462
463 /* Update mixture density and viscosity on cells */
464
465 # pragma omp parallel for
466 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
467 cs_real_t vf = cvar_voidf[c_id];
468 cpro_rom[c_id] = rho2*vf + rho1*(1. - vf);
469 cpro_viscl[c_id] = mu2*vf + mu1*(1. - vf);
470 }
471
472 cs_halo_type_t halo_type = m->halo_type;
473 cs_field_synchronize(CS_F_(rho), halo_type);
474 cs_field_synchronize(CS_F_(mu), halo_type);
475
476 /* Update mixture density on boundary faces */
477
478 for (cs_lnum_t f_id = 0; f_id < n_b_faces; f_id++) {
479 cs_lnum_t c_id = b_face_cells[f_id];
480 cs_real_t vf = a_voidf[f_id] + b_voidf[f_id]*cvar_voidf[c_id];
481
482 bpro_rom[f_id] = rho2*vf + rho1*(1. - vf);
483 }
484 }
485
486 /*----------------------------------------------------------------------------*/
487 /*!
488 * \brief Compute the mixture density, mixture dynamic viscosity and mixture
489 * mass flux given the volumetric flux, the volume fraction and the
490 * reference density and dynamic viscosity \f$ \rho_l, \mu_l \f$
491 * (liquid), \f$ \rho_v, \mu_v \f$ (gas).
492 *
493 * For the computation of mixture density, mixture dynamic viscosity, see
494 * \ref cs_vof_compute_linear_rho_mu.
495 *
496 * Computation of mass flux is as follows:
497 * \f[
498 * \left( \rho\vect{u}\cdot\vect{S} \right)_\ij = \\ \left\lbrace
499 * \begin{array}{ll}
500 * \rho_\celli (\vect{u}\cdot\vect{S})_\ij
501 * &\text{ if } (\vect{u}\cdot\vect{S})_\ij>0, \\
502 * \rho_\cellj (\vect{u}\cdot\vect{S})_\ij
503 * &\text{ otherwise },
504 * \end{array} \right.
505 * \f]
506 * \f[
507 * \left( \rho\vect{u}\cdot\vect{S} \right)_\ib = \\ \left\lbrace
508 * \begin{array}{ll}
509 * \rho_\celli (\vect{u}\cdot\vect{S})_\ib
510 * &\text{ if } (\vect{u}\cdot\vect{S})_\ib>0, \\
511 * \rho_b (\vect{u}\cdot\vect{S})_\ib
512 * &\text{ otherwise }.
513 * \end{array} \right.
514 * \f]
515 */
516 /*----------------------------------------------------------------------------*/
517
518 void
cs_vof_update_phys_prop(const cs_domain_t * domain)519 cs_vof_update_phys_prop(const cs_domain_t *domain)
520 {
521 /* update rho and mu with linear laws */
522 cs_vof_compute_linear_rho_mu(domain);
523
524 const cs_mesh_t *m = domain->mesh;
525 const cs_lnum_t n_i_faces = m->n_i_faces;
526 const cs_lnum_t n_b_faces = m->n_b_faces;
527
528 const cs_real_t rho1 = _vof_parameters.rho1;
529 const cs_real_t rho2 = _vof_parameters.rho2;
530
531 const int kimasf = cs_field_key_id("inner_mass_flux_id");
532 const int kbmasf = cs_field_key_id("boundary_mass_flux_id");
533 const int kiflux = cs_field_key_id("inner_flux_id");
534 const int kbflux = cs_field_key_id("boundary_flux_id");
535
536 const cs_real_t *restrict i_voidflux =
537 cs_field_by_id(cs_field_get_key_int(CS_F_(void_f), kiflux))->val;
538 const cs_real_t *restrict b_voidflux =
539 cs_field_by_id(cs_field_get_key_int(CS_F_(void_f), kbflux))->val;
540
541 const cs_real_t *restrict i_volflux =
542 cs_field_by_id(cs_field_get_key_int(CS_F_(void_f), kimasf))->val;
543 const cs_real_t *restrict b_volflux =
544 cs_field_by_id(cs_field_get_key_int(CS_F_(void_f), kbmasf))->val;
545
546 cs_real_t *restrict i_massflux =
547 cs_field_by_id(cs_field_get_key_int(CS_F_(vel), kimasf))->val;
548 cs_real_t *restrict b_massflux =
549 cs_field_by_id(cs_field_get_key_int(CS_F_(vel), kbmasf))->val;
550
551 cs_real_t drho = rho2 - rho1;
552
553 for (cs_lnum_t f_id = 0; f_id < n_i_faces; f_id++) {
554 i_massflux[f_id] += drho * i_voidflux[f_id] + rho1*i_volflux[f_id];
555 }
556
557 for (cs_lnum_t f_id = 0; f_id < n_b_faces; f_id++) {
558 b_massflux[f_id] += drho * b_voidflux[f_id] + rho1*b_volflux[f_id];
559 }
560 }
561
562 /*----------------------------------------------------------------------------*/
563 /*!
564 * \brief Write in main log the global mixture mass budget:
565 * \f[
566 * \sum_\celli\left(
567 * |\Omega_\celli|\dfrac{\alpha_\celli^n - \alpha_\celli^{n-1}}{\Delta t} +
568 * \sum_{\cellj\in\Face{\celli}}\left(\rho\vect{u}\vect{S}\right)_{\ij}^n
569 * \right).
570 * \f]
571 */
572 /*----------------------------------------------------------------------------*/
573
574 void
cs_vof_log_mass_budget(const cs_domain_t * domain)575 cs_vof_log_mass_budget(const cs_domain_t *domain)
576 {
577 const cs_mesh_t *m = domain->mesh;
578 const cs_lnum_t n_cells = m->n_cells;
579 const cs_lnum_t n_cells_with_ghosts = m->n_cells_with_ghosts;
580 const cs_lnum_t n_i_faces = m->n_i_faces;
581 const cs_lnum_t n_b_faces = m->n_b_faces;
582
583 const cs_lnum_2_t *i_face_cells = (const cs_lnum_2_t *)m->i_face_cells;
584 const cs_lnum_t *b_face_cells = m->b_face_cells;
585
586 const cs_mesh_quantities_t *mq = domain->mesh_quantities;
587 const cs_real_t *restrict cell_f_vol = mq->cell_f_vol;
588 const cs_real_3_t *restrict i_face_cog
589 = (const cs_real_3_t *restrict)mq->i_face_cog;
590 const cs_real_3_t *restrict b_face_cog
591 = (const cs_real_3_t *restrict)mq->b_face_cog;
592
593 const cs_real_3_t *restrict i_f_face_normal
594 = (const cs_real_3_t *restrict)mq->i_f_face_normal;
595 const cs_real_3_t *restrict b_f_face_normal
596 = (const cs_real_3_t *restrict)mq->b_f_face_normal;
597
598 const int kimasf = cs_field_key_id("inner_mass_flux_id");
599 const int kbmasf = cs_field_key_id("boundary_mass_flux_id");
600
601 cs_real_t *restrict i_massflux =
602 cs_field_by_id(cs_field_get_key_int(CS_F_(vel), kimasf))->val;
603 cs_real_t *restrict b_massflux =
604 cs_field_by_id(cs_field_get_key_int(CS_F_(vel), kbmasf))->val;
605
606 cs_real_t *cpro_rom = CS_F_(rho)->val;
607 cs_real_t *cproa_rom = CS_F_(rho)->val_pre;
608 cs_real_t *bpro_rom = CS_F_(rho_b)->val;
609
610 int icorio = cs_glob_physical_constants->icorio;
611 cs_turbomachinery_model_t iturbo = cs_turbomachinery_get_model();
612
613 cs_real_t *i_massflux_abs = NULL, *b_massflux_abs = NULL;
614
615 if (icorio == 1 || iturbo > CS_TURBOMACHINERY_NONE) {
616
617 cs_lnum_t cr_step = 0;
618 const int *cell_rotor_num = NULL;
619
620 const int _corio_rotor_num[] = {1};
621
622 if (iturbo > CS_TURBOMACHINERY_NONE) {
623 cr_step = 1;
624 cell_rotor_num = cs_turbomachinery_get_cell_rotor_num();
625 }
626 else
627 cell_rotor_num = _corio_rotor_num;
628
629 BFT_MALLOC(i_massflux_abs, n_i_faces, cs_real_t);
630 BFT_MALLOC(b_massflux_abs, n_b_faces, cs_real_t);
631
632 for (cs_lnum_t f_id = 0; f_id < n_i_faces; f_id++) {
633 i_massflux_abs[f_id] = i_massflux[f_id];
634
635 cs_lnum_t c_id_i = i_face_cells[f_id][0];
636 cs_lnum_t c_id_j = i_face_cells[f_id][1];
637 int rot_ce_i = cell_rotor_num[cr_step*c_id_i];
638 int rot_ce_j = cell_rotor_num[cr_step*c_id_j];
639
640 if (rot_ce_i != 0 || rot_ce_j != 0) {
641 cs_real_t rhofac = 0.5*(cpro_rom[c_id_i] + cpro_rom[c_id_j]);
642
643 cs_real_t vr1[3], vr2[3];
644 cs_rotation_velocity(cs_glob_rotation + rot_ce_i,
645 i_face_cog[f_id],
646 vr1);
647 cs_rotation_velocity(cs_glob_rotation + rot_ce_i,
648 i_face_cog[f_id],
649 vr2);
650 cs_real_t vr[] = {0.5*(vr1[0]+vr2[0]),
651 0.5*(vr1[1]+vr2[1]),
652 0.5*(vr1[2]+vr2[2])};
653
654 i_massflux_abs[f_id] +=
655 rhofac * cs_math_3_dot_product(i_f_face_normal[f_id], vr);
656 }
657 }
658
659 for (cs_lnum_t f_id = 0; f_id < n_b_faces; f_id++) {
660 b_massflux_abs[f_id] = b_massflux[f_id];
661
662 cs_lnum_t c_id = b_face_cells[f_id];
663 int rot_ce_i = cell_rotor_num[cr_step*c_id];
664
665 if (rot_ce_i != 0) {
666 cs_real_t vr[3];
667 cs_rotation_velocity(cs_glob_rotation + rot_ce_i, b_face_cog[f_id], vr);
668
669 b_massflux[f_id] +=
670 bpro_rom[f_id] * cs_math_3_dot_product(b_f_face_normal[f_id], vr);
671 }
672 }
673
674 /* massflux point to absolute ones now */
675 i_massflux = i_massflux_abs;
676 b_massflux = b_massflux_abs;
677 }
678
679 /* (Absolute) Mass flux divergence */
680
681 cs_real_t *divro;
682 BFT_MALLOC(divro, n_cells_with_ghosts, cs_real_t);
683 cs_divergence(m,
684 1, /* initialize to 0 */
685 i_massflux,
686 b_massflux,
687 divro);
688
689 if (icorio == 1 || iturbo > CS_TURBOMACHINERY_NONE) {
690 BFT_FREE(i_massflux_abs);
691 BFT_FREE(b_massflux_abs);
692 }
693 i_massflux = NULL, b_massflux = NULL;
694
695 /* Unsteady term and mass budget */
696
697 cs_real_t glob_m_budget = 0.;
698 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
699 cs_real_t tinsro = cell_f_vol[c_id]
700 * (cpro_rom[c_id]-cproa_rom[c_id]) / CS_F_(dt)->val[c_id];
701
702 glob_m_budget += tinsro + divro[c_id];
703 }
704
705 cs_parall_sum(1, CS_DOUBLE, &glob_m_budget);
706
707 bft_printf(_(" ** VOF MODEL, MASS BALANCE at iteration %6i: %12.4e\n\n"),
708 cs_glob_time_step->nt_cur, glob_m_budget);
709
710 BFT_FREE(divro);
711 }
712
713 /*----------------------------------------------------------------------------*/
714 /*!
715 * \brief Compute a relative velocity \f$ \vect u _d \f$ directly at internal
716 * faces (drift flux), following the approach described by
717 * Suraj S. Deshpande et al 2012 Comput. Sci. Disc. 5 014016.
718 * It is activated with the option idrift = 1
719 *
720 * Using the notation:
721 * \f[
722 * \begin{cases}
723 * \left ( \vect u ^{n+1} . \vect S \right ) _{\face} = \Dot{m}_{\face}\\
724 * \left ( \vect u _d^{n+1} . \vect S \right ) _{\face} = \Dot{m^d}_{\face}
725 * \end{cases}
726 * \f]
727 * The drift flux is computed as:
728 * \f[
729 * \Dot{m^d}_{\face} = min \left ( C_{\gamma} \dfrac{\Dot{m}_{\face}}
730 * {\vect S_{\face}}, \underset{\face'}{max} \left [ \dfrac{\Dot{m}_{\face'}}
731 * {\vect S_{\face'}} \right ] \right ) \left ( \vect n \cdot \vect S \right )
732 * _{\face}
733 * \f]
734 * Where \f$ C_{\gamma} \f$ is the drift flux factor defined with the variable
735 * \ref cdrift, \f$ \vect n _{\face} \f$ the normal vector to the interface.
736 * The gradient is computed using a centered scheme:
737 * \f[
738 * \vect {n} _{\face} = \dfrac{\left ( \grad \alpha \right ) _{\face}}
739 * {\norm {\left ( \grad \alpha \right ) _{\face} + \delta}},
740 * \text{ with: }
741 * \left ( \grad \alpha \right ) _{\face _{\celli \cellj}} = \dfrac{\left (
742 * \grad \alpha \right ) _\celli + \left ( \grad \alpha \right ) _\cellj}{2},
743 * \text{ and: }
744 * \delta = 10^{-8} / \overline{\vol \celli} ^{1/3}
745 * \f]
746 */
747 /*----------------------------------------------------------------------------*/
748
749 void
cs_vof_deshpande_drift_flux(const cs_domain_t * domain)750 cs_vof_deshpande_drift_flux(const cs_domain_t *domain)
751 {
752 const cs_mesh_t *m = domain->mesh;
753 const cs_mesh_quantities_t *mq = domain->mesh_quantities;
754
755 const cs_lnum_t n_i_faces = m->n_i_faces;
756 const cs_gnum_t n_g_cells = m->n_g_cells;
757 const cs_lnum_t n_cells_with_ghosts = m->n_cells_with_ghosts;
758
759 const cs_real_t tot_vol = mq->tot_vol;
760 const cs_real_t *i_face_surf = (const cs_real_t *)mq->i_face_surf;
761 const cs_real_3_t *i_face_normal = (const cs_real_3_t *)mq->i_face_normal;
762 const cs_lnum_2_t *i_face_cells = (const cs_lnum_2_t *)m->i_face_cells;
763
764 /* Constant parameter */
765 const cs_real_t cdrift = _vof_parameters.cdrift;
766
767 const int kimasf = cs_field_key_id("inner_mass_flux_id");
768 const cs_real_t *restrict i_volflux =
769 cs_field_by_id(cs_field_get_key_int(CS_F_(void_f), kimasf))->val;
770
771 cs_field_t *idriftflux = NULL;
772 idriftflux = cs_field_by_name_try("inner_drift_velocity_flux");
773
774 /* Check if field exists */
775 if (idriftflux == NULL)
776 bft_error(__FILE__, __LINE__, 0,_("error drift velocity not defined\n"));
777 cs_real_t *cpro_idriftf = idriftflux->val;
778
779 cs_real_3_t *voidf_grad;
780 BFT_MALLOC(voidf_grad, n_cells_with_ghosts, cs_real_3_t);
781 /* Compute the gradient of the void fraction */
782 cs_field_gradient_scalar(CS_F_(void_f),
783 true, // use_previous_t
784 1, // inc
785 true, // _recompute_cocg
786 voidf_grad);
787
788 /* Stabilization factor */
789 cs_real_t delta = pow(10,-8)/pow(tot_vol/n_g_cells,(1./3.));
790
791 /* Compute the max of flux/Surf over the entire domain*/
792 cs_real_t maxfluxsurf = 0.;
793 for (cs_lnum_t f_id = 0; f_id < n_i_faces; f_id++) {
794 if (maxfluxsurf < CS_ABS(i_volflux[f_id])/i_face_surf[f_id])
795 maxfluxsurf = CS_ABS(i_volflux[f_id])/i_face_surf[f_id];
796 }
797 cs_parall_max(1, CS_DOUBLE, &maxfluxsurf);
798
799 /* Compute the relative velocity at internal faces */
800 cs_real_3_t gradface, normalface;
801 for (cs_lnum_t f_id = 0; f_id < n_i_faces; f_id++) {
802 cs_lnum_t cell_id1 = i_face_cells[f_id][0];
803 cs_lnum_t cell_id2 = i_face_cells[f_id][1];
804 cs_real_t fluxfactor =
805 CS_MIN(cdrift*CS_ABS(i_volflux[f_id])/i_face_surf[f_id], maxfluxsurf);
806
807 for (int idim = 0; idim < 3; idim++)
808 gradface[idim] = ( voidf_grad[cell_id1][idim]
809 + voidf_grad[cell_id2][idim])/2.;
810
811 cs_real_t normgrad = sqrt(pow(gradface[0],2)+
812 pow(gradface[1],2)+
813 pow(gradface[2],2));
814
815 for (int idim = 0; idim < 3; idim++)
816 normalface[idim] = gradface[idim] / (normgrad+delta);
817
818 cpro_idriftf[f_id] = fluxfactor*(normalface[0]*i_face_normal[f_id][0]+
819 normalface[1]*i_face_normal[f_id][1]+
820 normalface[2]*i_face_normal[f_id][2]);
821 }
822
823 BFT_FREE(voidf_grad);
824 }
825
826 /*----------------------------------------------------------------------------*/
827 /*!
828 * \brief Add the divergence of the drift velocity term in the volume
829 * fraction equation.
830 *
831 * More precisely, the right hand side \f$ Rhs \f$ is updated as follows:
832 * \f[
833 * Rhs = Rhs - \sum_{\fij \in \Facei{\celli}} \left(
834 * \alpha_\celli^{n+1} \left( 1 - \alpha_\cellj^{n+1} \right) \left(
835 * \dot{m}_\fij^{d} \right)^{+} + \alpha_\cellj^{n+1} \left( 1 -
836 * \alpha_\celli^{n+1} \right) \left( \dot{m}_\fij^{d} \right)^{-}
837 * \right)
838 * \f]
839 * \param[in] imrgra indicator
840 * - 0 iterative gradient
841 * - 1 least squares gradient
842 * \param[in] nswrgp number of reconstruction sweeps for the
843 * gradients
844 * \param[in] imligp clipping gradient method
845 * - < 0 no clipping
846 * - = 0 by neighboring gradients
847 * - = 1 by the mean gradient
848 * \param[in] iwarnp verbosity
849 * \param[in] epsrgp relative precision for the gradient
850 * reconstruction
851 * \param[in] climgp clipping coefficient for the computation of
852 * the gradient
853 * \param[in] pvar solved variable (current time step)
854 * \param[in] pvara solved variable (previous time step)
855 * \param[in,out] rhs right hand side \f$ \vect{Rhs} \f$
856 */
857 /*----------------------------------------------------------------------------*/
858
859 void
cs_vof_drift_term(int imrgra,int nswrgp,int imligp,int iwarnp,cs_real_t epsrgp,cs_real_t climgp,cs_real_t * restrict pvar,const cs_real_t * restrict pvara,cs_real_t * restrict rhs)860 cs_vof_drift_term(int imrgra,
861 int nswrgp,
862 int imligp,
863 int iwarnp,
864 cs_real_t epsrgp,
865 cs_real_t climgp,
866 cs_real_t *restrict pvar,
867 const cs_real_t *restrict pvara,
868 cs_real_t *restrict rhs)
869 {
870 const cs_mesh_t *m = cs_glob_mesh;
871 cs_mesh_quantities_t *fvq = cs_glob_mesh_quantities;
872
873 const cs_lnum_t n_cells = m->n_cells;
874 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
875 const int n_i_groups = m->i_face_numbering->n_groups;
876 const int n_i_threads = m->i_face_numbering->n_threads;
877 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
878
879 const cs_lnum_2_t *restrict i_face_cells
880 = (const cs_lnum_2_t *restrict)m->i_face_cells;
881 const cs_real_t *restrict i_dist = fvq->i_dist;
882 const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
883
884 /* Handle cases where only the previous values (already synchronized)
885 or current values are provided */
886
887 if (pvar != NULL)
888 cs_sync_scalar_halo(m, pvar);
889 else if (pvara == NULL)
890 pvara = (const cs_real_t *restrict)pvar;
891
892 const cs_real_t *restrict _pvar = (pvar != NULL) ? pvar : pvara;
893
894 /*======================================================================
895 Computation of the drift flux
896 ======================================================================*/
897
898 cs_field_t *vr = cs_field_by_name_try("drift_velocity");
899 cs_field_t *idriftflux = cs_field_by_name_try("inner_drift_velocity_flux");
900 cs_field_t *bdriftflux = cs_field_by_name_try("boundary_drift_velocity_flux");
901
902 if (_vof_parameters.idrift == 1) {
903
904 // FIXME Handle boundary terms bdriftflux
905 cs_vof_deshpande_drift_flux(cs_glob_domain);
906
907 } else {
908
909 const cs_lnum_t n_b_faces = cs_glob_mesh->n_b_faces;
910 int f_id, itypfl, iflmb0, init, inc;
911
912 cs_real_3_t *coefav;
913 cs_real_33_t *coefbv;
914
915 /* Check if field exist */
916 if (idriftflux == NULL)
917 bft_error(__FILE__, __LINE__, 0,_("error drift velocity not defined\n"));
918
919 cs_real_3_t *cpro_vr = (cs_real_3_t *)vr->val;
920 cs_real_t *cpro_idriftf = idriftflux->val;
921 cs_real_t *cpro_bdriftf = bdriftflux->val;
922
923 BFT_MALLOC(coefav, n_b_faces, cs_real_3_t);
924 BFT_MALLOC(coefbv, n_b_faces, cs_real_33_t);
925
926 f_id = -1;
927 itypfl = 0;
928 iflmb0 = 1;
929 init = 1;
930 inc = 1;
931
932 /* Boundary coefficients */
933 for (cs_lnum_t ifac = 0 ; ifac < n_b_faces ; ifac++) {
934 for (int ii = 0 ; ii < 3 ; ii++) {
935 coefav[ifac][ii] = 0.;
936 for (int jj = 0 ; jj < 3 ; jj++) {
937 coefbv[ifac][ii][jj] = 0.;
938 }
939 coefbv[ifac][ii][ii] = 1.;
940 }
941 }
942
943 cs_mass_flux(m,
944 fvq,
945 f_id,
946 itypfl,
947 iflmb0,
948 init,
949 inc,
950 imrgra,
951 nswrgp,
952 imligp,
953 iwarnp,
954 epsrgp,
955 climgp,
956 NULL, /* rom */
957 NULL, /* romb */
958 (const cs_real_3_t *)cpro_vr,
959 (const cs_real_3_t *)coefav,
960 (const cs_real_33_t *)coefbv,
961 cpro_idriftf,
962 cpro_bdriftf);
963
964 BFT_FREE(coefav);
965 BFT_FREE(coefbv);
966
967 }
968
969 /*======================================================================
970 Contribution from interior faces
971 ======================================================================*/
972
973 const int kiflux = cs_field_key_id("inner_flux_id");
974 int i_flux_id = cs_field_get_key_int(CS_F_(void_f), kiflux);
975 cs_field_t *i_flux = cs_field_by_id(i_flux_id);
976
977 if (n_cells_ext>n_cells) {
978 # pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
979 for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
980 rhs[cell_id] = 0.;
981 }
982 }
983
984 for (int g_id = 0; g_id < n_i_groups; g_id++) {
985 # pragma omp parallel for
986 for (int t_id = 0; t_id < n_i_threads; t_id++) {
987 for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
988 face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
989 face_id++) {
990
991 cs_lnum_t ii = i_face_cells[face_id][0];
992 cs_lnum_t jj = i_face_cells[face_id][1];
993
994 cs_real_t irvf = 0.;
995 if (idriftflux != NULL)
996 irvf = idriftflux->val[face_id];
997
998 cs_real_2_t fluxij = {0.,0.};
999
1000 cs_i_conv_flux(1,
1001 1.,
1002 0,
1003 _pvar[ii],
1004 _pvar[jj],
1005 _pvar[ii]*(1.-_pvar[jj]),
1006 _pvar[ii]*(1.-_pvar[jj]),
1007 _pvar[jj]*(1.-_pvar[ii]),
1008 _pvar[jj]*(1.-_pvar[ii]),
1009 irvf,
1010 1.,
1011 1.,
1012 fluxij);
1013
1014 const cs_real_t kdrift = _vof_parameters.kdrift;
1015 cs_i_diff_flux(1,
1016 1.,
1017 _pvar[ii],
1018 _pvar[jj],
1019 _pvar[ii],
1020 _pvar[jj],
1021 kdrift*(2.-_pvar[ii]-_pvar[jj])
1022 / 2.*i_face_surf[face_id]/i_dist[face_id],
1023 fluxij);
1024
1025 rhs[ii] -= fluxij[0];
1026 rhs[jj] += fluxij[1];
1027 /* store void fraction convection flux contribution */
1028 i_flux->val[face_id] += fluxij[0];
1029 }
1030 }
1031 }
1032 }
1033
1034 /*----------------------------------------------------------------------------
1035 *!
1036 * \brief Provide access to cavitation parameters structure.
1037 */
1038 /*----------------------------------------------------------------------------*/
1039
1040 cs_cavitation_parameters_t *
cs_get_glob_cavitation_parameters(void)1041 cs_get_glob_cavitation_parameters(void)
1042 {
1043 return &_cavit_parameters;
1044 }
1045
1046 /*----------------------------------------------------------------------------*/
1047
1048 END_C_DECLS
1049