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