1 /*============================================================================
2  * Convection-diffusion operators.
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 #include "cs_defs.h"
27 
28 /*----------------------------------------------------------------------------
29  * Standard C library headers
30  *----------------------------------------------------------------------------*/
31 
32 #include <assert.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <math.h>
38 #include <float.h>
39 
40 #if defined(HAVE_MPI)
41 #include <mpi.h>
42 #endif
43 
44 /*----------------------------------------------------------------------------
45  *  Local headers
46  *----------------------------------------------------------------------------*/
47 
48 #include "bft_error.h"
49 #include "bft_mem.h"
50 #include "bft_printf.h"
51 
52 #include "cs_blas.h"
53 #include "cs_bad_cells_regularisation.h"
54 #include "cs_boundary_conditions.h"
55 #include "cs_halo.h"
56 #include "cs_halo_perio.h"
57 #include "cs_log.h"
58 #include "cs_internal_coupling.h"
59 #include "cs_math.h"
60 #include "cs_mesh.h"
61 #include "cs_field.h"
62 #include "cs_field_operator.h"
63 #include "cs_field_pointer.h"
64 #include "cs_gradient.h"
65 #include "cs_ext_neighborhood.h"
66 #include "cs_mesh_quantities.h"
67 #include "cs_parall.h"
68 #include "cs_parameters.h"
69 #include "cs_porous_model.h"
70 #include "cs_prototypes.h"
71 #include "cs_timer.h"
72 #include "cs_velocity_pressure.h"
73 
74 /*----------------------------------------------------------------------------
75  *  Header for the current file
76  *----------------------------------------------------------------------------*/
77 
78 #include "cs_convection_diffusion.h"
79 
80 /*----------------------------------------------------------------------------*/
81 
82 BEGIN_C_DECLS
83 
84 /*=============================================================================
85  * Additional Doxygen documentation
86  *============================================================================*/
87 
88 /*! \file  cs_convection_diffusion.c
89  *
90  * \brief Convection-diffusion operators.
91  *
92  * Please refer to the
93  * <a href="../../theory.pdf#conv-diff"><b>convection-diffusion</b></a> section
94  *  of the theory guide for more informations.
95  */
96 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
97 
98 /*=============================================================================
99  * Local Macro Definitions
100  *============================================================================*/
101 
102 /*=============================================================================
103  * Local type definitions
104  *============================================================================*/
105 
106 /*============================================================================
107  * Private function definitions
108  *============================================================================*/
109 
110 /*----------------------------------------------------------------------------
111  * Return the equivalent heat transfer coefficient. If both terms are
112  * below a given tolerance, 0. is returned.
113  *
114  * parameters:
115  *   h1     <-- first exchange coefficient
116  *   h2     <-- second exchange coefficient
117  *
118  * return:
119  *   value of equivalent exchange coefficient
120  *----------------------------------------------------------------------------*/
121 
122 static inline cs_real_t
_calc_heq(cs_real_t h1,cs_real_t h2)123 _calc_heq(cs_real_t h1,
124           cs_real_t h2)
125 {
126   const cs_real_t h_eps = 1.e-12;
127 
128   cs_real_t heq = 0.;
129   if (h1 + h2 > h_eps)
130     heq = h1 * h2 / (h1 + h2);
131 
132   return heq;
133 }
134 
135 /*----------------------------------------------------------------------------
136  * Return the denominator to build the beta blending coefficient of the
137  * beta limiter (ensuring preservation of a given min/max pair of values).
138  *
139  * parameters:
140  *   f_id        <-- field id (or -1)
141  *   inc         <-- 0 if an increment, 1 otherwise
142  *   denom_inf   --> computed denominator for the inferior bound
143  *   denom_sup   --> computed denominator for the superior bound
144  *
145  * return:
146  *   pointer to local values array, or NULL;
147  *----------------------------------------------------------------------------*/
148 
149 static void
_beta_limiter_denom(const int f_id,const int inc,cs_real_t * restrict denom_inf,cs_real_t * restrict denom_sup)150 _beta_limiter_denom(const int              f_id,
151                     const int              inc,
152                     cs_real_t    *restrict denom_inf,
153                     cs_real_t    *restrict denom_sup)
154 {
155   const cs_mesh_t  *m = cs_glob_mesh;
156   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
157 
158   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
159   const int n_i_groups = m->i_face_numbering->n_groups;
160   const int n_i_threads = m->i_face_numbering->n_threads;
161   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
162 
163   const cs_lnum_2_t *restrict i_face_cells
164     = (const cs_lnum_2_t *restrict)m->i_face_cells;
165   const cs_real_t *restrict weight = fvq->weight;
166   const cs_real_3_t *restrict cell_cen
167     = (const cs_real_3_t *restrict)fvq->cell_cen;
168   const cs_real_3_t *restrict i_face_normal
169     = (const cs_real_3_t *restrict)fvq->i_face_normal;
170   const cs_real_3_t *restrict i_face_cog
171     = (const cs_real_3_t *restrict)fvq->i_face_cog;
172   const cs_real_3_t *restrict diipf
173     = (const cs_real_3_t *restrict)fvq->diipf;
174   const cs_real_3_t *restrict djjpf
175     = (const cs_real_3_t *restrict)fvq->djjpf;
176 
177   /* Get option from the field */
178   cs_field_t *f = cs_field_by_id(f_id);
179 
180   const cs_real_t *restrict pvar  = f->val;
181   const cs_real_t *restrict pvara = f->val_pre;
182 
183   const cs_real_t *restrict coefap = f->bc_coeffs->a;
184   const cs_real_t *restrict coefbp = f->bc_coeffs->b;
185 
186   int key_cal_opt_id = cs_field_key_id("var_cal_opt");
187   cs_var_cal_opt_t var_cal_opt;
188 
189   cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
190 
191   const int ischcp = var_cal_opt.ischcv;
192   const int ircflp = var_cal_opt.ircflu;
193   const int imrgra = var_cal_opt.imrgra;
194   const cs_real_t thetap = var_cal_opt.thetav;
195   const cs_real_t blencp = var_cal_opt.blencv;
196 
197   const int kimasf = cs_field_key_id("inner_mass_flux_id");
198   const int kbmasf = cs_field_key_id("boundary_mass_flux_id");
199   const cs_real_t *restrict i_massflux =
200     cs_field_by_id(cs_field_get_key_int(f, kimasf))->val;
201   const cs_real_t *restrict b_massflux =
202     cs_field_by_id(cs_field_get_key_int(f, kbmasf))->val;
203 
204   /* select halo type according to field gradient method */
205 
206   cs_halo_type_t halo_type = CS_HALO_STANDARD;
207   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
208 
209   cs_gradient_type_by_imrgra(imrgra,
210                              &gradient_type,
211                              &halo_type);
212 
213   /* for NVD / TVD schemes (including VoF schemes) */
214 
215   const int key_lim_choice = cs_field_key_id("limiter_choice");
216   int limiter_choice = -1;
217 
218   cs_real_t *local_min = NULL;
219   cs_real_t *local_max = NULL;
220   cs_real_t *courant = NULL;
221 
222   if (ischcp == 4) {
223     /* get limiter choice */
224     limiter_choice = cs_field_get_key_int(f, key_lim_choice);
225 
226     /* local extrema computation */
227     BFT_MALLOC(local_max, n_cells_ext, cs_real_t);
228     BFT_MALLOC(local_min, n_cells_ext, cs_real_t);
229     cs_field_local_extrema_scalar(f_id,
230                                   halo_type,
231                                   local_max,
232                                   local_min);
233 
234     /* cell Courant number computation */
235     if (limiter_choice >= CS_NVD_VOF_HRIC) {
236       BFT_MALLOC(courant, n_cells_ext, cs_real_t);
237       cs_cell_courant_number(f_id, courant);
238     }
239   }
240 
241   cs_real_t *df_limiter = NULL;
242   int df_limiter_id =
243     cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
244   if (df_limiter_id > -1)
245     df_limiter = cs_field_by_id(df_limiter_id)->val;
246 
247   /* step 1: gradient computation */
248   cs_real_3_t *grdpa;  /* for the implicit part */
249   cs_real_3_t *grdpaa; /* for the explicit part */
250 
251   BFT_MALLOC(grdpa, n_cells_ext, cs_real_3_t);
252   BFT_MALLOC(grdpaa, n_cells_ext, cs_real_3_t);
253 
254 # pragma omp parallel for
255   for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
256     grdpa[cell_id][0] = 0.;
257     grdpa[cell_id][1] = 0.;
258     grdpa[cell_id][2] = 0.;
259 
260     grdpaa[cell_id][0] = 0.;
261     grdpaa[cell_id][1] = 0.;
262     grdpaa[cell_id][2] = 0.;
263   }
264 
265   /* legacy SOLU Scheme or centered scheme */
266   if (ischcp == 0 || ischcp == 1 || ischcp == 3) {
267 
268     cs_field_gradient_scalar(f,
269                              false, /* use_previous_t */
270                              inc,
271                              true, /* _recompute_cocg */
272                              grdpa);
273 
274     cs_field_gradient_scalar(f,
275                              true, /* use_previous_t */
276                              inc,
277                              true, /* _recompute_cocg */
278                              grdpaa);
279 
280   }
281   /* pure SOLU scheme (upwind gradient reconstruction) */
282   else if (ischcp == 2) {
283 
284     cs_upwind_gradient(f_id,
285                        inc,
286                        halo_type,
287                        coefap,
288                        coefbp,
289                        i_massflux,
290                        b_massflux,
291                        pvar,
292                        grdpa);
293 
294     cs_upwind_gradient(f_id,
295                        inc,
296                        halo_type,
297                        coefap,
298                        coefbp,
299                        i_massflux,
300                        b_massflux,
301                        pvara,
302                        grdpaa);
303 
304   }
305 
306   /* Step 2: Building of denominator */
307 
308 # pragma omp parallel for
309   for (cs_lnum_t ii = 0; ii < n_cells_ext; ii++) {
310     denom_inf[ii] = 0.;
311     denom_sup[ii] = 0.;
312   }
313 
314   /* ---> Contribution from interior faces */
315 
316   for (int g_id = 0; g_id < n_i_groups; g_id++) {
317 #   pragma omp parallel for
318     for (int t_id = 0; t_id < n_i_threads; t_id++) {
319       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
320           face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
321           face_id++) {
322 
323         cs_lnum_t ii = i_face_cells[face_id][0];
324         cs_lnum_t jj = i_face_cells[face_id][1];
325 
326         cs_real_t pi = pvar[ii];
327         cs_real_t pj = pvar[jj];
328         cs_real_t pia = pvara[ii];
329         cs_real_t pja = pvara[jj];
330         cs_real_t pif, pjf, pip, pjp;
331         cs_real_t pifa, pjfa, pipa, pjpa;
332 
333         cs_real_t hybrid_coef_ii, hybrid_coef_jj;
334         if (ischcp == 3) {
335           hybrid_coef_ii = CS_F_(hybrid_blend)->val[ii];
336           hybrid_coef_jj = CS_F_(hybrid_blend)->val[jj];
337         } else {
338           hybrid_coef_ii = 0.;
339           hybrid_coef_jj = 0.;
340         }
341 
342         cs_real_t bldfrp = (cs_real_t) ircflp;
343         /* Local limitation of the reconstruction */
344         if (df_limiter != NULL && ircflp > 0)
345           bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
346 
347         if (ischcp == 4) {
348           /* NVD/TVD family of high accuracy schemes */
349 
350           cs_lnum_t ic, id;
351 
352           /* Determine central and downwind sides w.r.t. current face */
353           cs_central_downwind_cells(ii,
354                                     jj,
355                                     i_massflux[face_id],
356                                     &ic,  /* central cell id */
357                                     &id); /* downwind cell id */
358 
359           cs_real_t courant_c = -1.;
360           if (courant != NULL)
361             courant_c = courant[ic];
362 
363           cs_i_cd_unsteady_nvd(limiter_choice,
364                                blencp,
365                                cell_cen[ic],
366                                cell_cen[id],
367                                i_face_normal[face_id],
368                                i_face_cog[face_id],
369                                grdpa[ic],
370                                pvar[ic],
371                                pvar[id],
372                                local_max[ic],
373                                local_min[ic],
374                                courant_c,
375                                &pif,
376                                &pjf);
377 
378           cs_i_cd_unsteady_nvd(limiter_choice,
379                                blencp,
380                                cell_cen[ic],
381                                cell_cen[id],
382                                i_face_normal[face_id],
383                                i_face_cog[face_id],
384                                grdpaa[ic],
385                                pvara[ic],
386                                pvara[id],
387                                local_max[ic],
388                                local_min[ic],
389                                courant_c,
390                                &pifa,
391                                &pjfa);
392         } else {
393           /* Value at time n */
394           cs_i_cd_unsteady(bldfrp,
395                            ischcp,
396                            blencp,
397                            weight[face_id],
398                            cell_cen[ii],
399                            cell_cen[jj],
400                            i_face_cog[face_id],
401                            hybrid_coef_ii,
402                            hybrid_coef_jj,
403                            diipf[face_id],
404                            djjpf[face_id],
405                            grdpa[ii], /* Std gradient when needed */
406                            grdpa[jj], /* Std gradient when needed */
407                            grdpa[ii], /* Upwind gradient when needed */
408                            grdpa[jj], /* Upwind gradient when needed */
409                            pi,
410                            pj,
411                            &pif,
412                            &pjf,
413                            &pip,
414                            &pjp);
415 
416           /* Value at time n-1 */
417           cs_i_cd_unsteady(bldfrp,
418                            ischcp,
419                            blencp,
420                            weight[face_id],
421                            cell_cen[ii],
422                            cell_cen[jj],
423                            i_face_cog[face_id],
424                            hybrid_coef_ii, /* FIXME use previous values
425                                               of blending function */
426                            hybrid_coef_jj, /* FIXME use previous values
427                                               of blending function */
428                            diipf[face_id],
429                            djjpf[face_id],
430                            grdpaa[ii], /* Std gradient when needed */
431                            grdpaa[jj], /* Std gradient when needed */
432                            grdpaa[ii], /* Upwind gradient when needed */
433                            grdpaa[jj], /* Upwind gradient when needed */
434                            pia,
435                            pja,
436                            &pifa,
437                            &pjfa,
438                            &pipa,
439                            &pjpa);
440         }
441 
442         cs_real_t flui = 0.5*(i_massflux[face_id] +fabs(i_massflux[face_id]));
443         cs_real_t fluj = 0.5*(i_massflux[face_id] -fabs(i_massflux[face_id]));
444 
445         cs_real_t flux =     thetap  * ( (pif  - pi )*flui
446                                        + (pjf  - pj )*fluj)
447                        + (1.-thetap) * ( (pifa - pia)*flui
448                                        + (pjfa - pja)*fluj);
449 
450         /* blending to prevent INFERIOR bound violation
451           We need to take the positive part*/
452         cs_real_t partii = 0.5*(flux + CS_ABS(flux));
453         cs_real_t partjj = 0.5*(flux - CS_ABS(flux));
454 
455         denom_inf[ii] = denom_inf[ii] + partii;
456         denom_inf[jj] = denom_inf[jj] - partjj;
457 
458         /* blending to prevent SUPERIOR bound violation
459           We need to take the negative part
460           Note: the swap between ii and jj is due to the fact
461           that an upwind value on (Y-bound) is equivalent to a
462           downwind value on (bound-Y) */
463         denom_sup[ii] = denom_sup[ii] - partjj;
464         denom_sup[jj] = denom_sup[jj] + partii;
465       }
466     }
467   }
468 
469   //Free Gradient arrays
470   BFT_FREE(local_min);
471   BFT_FREE(local_max);
472   BFT_FREE(courant);
473   BFT_FREE(grdpa);
474   BFT_FREE(grdpaa);
475 
476 }
477 
478 /*----------------------------------------------------------------------------
479  * Return the diagonal part of the numerator to build the Min/max limiter.
480  *
481  * parameters:
482  *   f_id        <-- field id (or -1)
483  *   rovsdt      <-- rho * volume / dt
484  *   num_inf     --> computed numerator for the inferior bound
485  *   num_sup     --> computed numerator for the superior bound
486  *
487  *----------------------------------------------------------------------------*/
488 
489 static void
_beta_limiter_num(const int f_id,const int inc,const cs_real_t rovsdt[],cs_real_t * num_inf,cs_real_t * num_sup)490 _beta_limiter_num(const int           f_id,
491                   const int           inc,
492                   const cs_real_t     rovsdt[],
493                   cs_real_t          *num_inf,
494                   cs_real_t          *num_sup)
495 {
496   const cs_mesh_t  *m = cs_glob_mesh;
497 
498   const cs_lnum_t n_cells = m->n_cells;
499   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
500   const int n_i_groups = m->i_face_numbering->n_groups;
501   const int n_i_threads = m->i_face_numbering->n_threads;
502   const int n_b_groups = m->b_face_numbering->n_groups;
503   const int n_b_threads = m->b_face_numbering->n_threads;
504   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
505   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
506 
507   const cs_lnum_2_t *restrict i_face_cells
508     = (const cs_lnum_2_t *restrict)m->i_face_cells;
509   const cs_lnum_t *restrict b_face_cells
510     = (const cs_lnum_t *restrict)m->b_face_cells;
511 
512   /* Get option from the field */
513   cs_field_t *f = cs_field_by_id(f_id);
514 
515   const cs_real_t *restrict pvara = f->val_pre;
516 
517   const cs_real_t *restrict coefap = f->bc_coeffs->a;
518   const cs_real_t *restrict coefbp = f->bc_coeffs->b;
519 
520   int key_scamax_id = cs_field_key_id("max_scalar");
521   int key_scamin_id = cs_field_key_id("min_scalar");
522 
523   cs_real_t scalar_max = cs_field_get_key_double(f, key_scamax_id);
524   cs_real_t scalar_min = cs_field_get_key_double(f, key_scamin_id);
525 
526   int key_cal_opt_id = cs_field_key_id("var_cal_opt");
527   cs_var_cal_opt_t var_cal_opt;
528 
529   cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
530 
531   const cs_real_t thetex =  1.-var_cal_opt.thetav;
532 
533   const int kimasf = cs_field_key_id("inner_mass_flux_id");
534   const int kbmasf = cs_field_key_id("boundary_mass_flux_id");
535   const cs_real_t *restrict i_massflux =
536     cs_field_by_id( cs_field_get_key_int(f, kimasf) )->val;
537   const cs_real_t *restrict b_massflux =
538     cs_field_by_id( cs_field_get_key_int(f, kbmasf) )->val;
539 
540   for (cs_lnum_t ii = n_cells; ii < n_cells_ext; ii++) {
541     num_inf[ii] = 0.;
542     num_sup[ii] = 0.;
543   }
544 
545 # pragma omp parallel for
546   for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
547     num_inf[ii] = rovsdt[ii] * (pvara[ii] -scalar_min);
548     num_sup[ii] = rovsdt[ii] * (scalar_max-pvara[ii]);
549   }
550 
551   /* ---> Contribution from interior faces */
552 
553   for (int g_id = 0; g_id < n_i_groups; g_id++) {
554 #   pragma omp parallel for
555     for (int t_id = 0; t_id < n_i_threads; t_id++) {
556       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
557           face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
558           face_id++) {
559 
560         cs_lnum_t ii = i_face_cells[face_id][0];
561         cs_lnum_t jj = i_face_cells[face_id][1];
562 
563         cs_real_t flui = 0.5*(i_massflux[face_id] + fabs(i_massflux[face_id]));
564         cs_real_t fluj = 0.5*(i_massflux[face_id] - fabs(i_massflux[face_id]));
565 
566         cs_real_t pi = pvara[ii]-scalar_min;
567         cs_real_t pj = pvara[jj]-scalar_min;
568 
569         num_inf[ii] -= thetex *(pi * flui + pj * fluj);
570         num_inf[jj] += thetex *(pj * fluj + pi * flui);
571 
572         pi = scalar_max-pvara[ii];
573         pj = scalar_max-pvara[jj];
574 
575         num_sup[ii] -= thetex *(pi * flui + pj * fluj);
576         num_sup[jj] += thetex *(pj * fluj + pi * flui);
577       }
578     }
579   }
580 
581   /* ---> Contribution from boundary faces */
582 
583   for (int g_id = 0; g_id < n_b_groups; g_id++) {
584 #   pragma omp parallel for
585     for (int t_id = 0; t_id < n_b_threads; t_id++) {
586       for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
587           face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
588           face_id++) {
589 
590         cs_lnum_t ii = b_face_cells[face_id];
591 
592         cs_real_t flui = 0.5*(b_massflux[face_id]+fabs(b_massflux[face_id]));
593         cs_real_t fluf = 0.5*(b_massflux[face_id]-fabs(b_massflux[face_id]));
594         cs_real_t pfabor = inc*coefap[face_id]+coefbp[face_id]*pvara[ii];
595 
596         num_inf[ii] -= thetex *( (pvara[ii]-scalar_min) * flui
597                                + (pfabor   -scalar_min) * fluf);
598         num_sup[ii] -= thetex *( (scalar_max-pvara[ii]) * flui
599                                + (scalar_max-pfabor   ) * fluf);
600       }
601     }
602   }
603 }
604 
605 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
606 
607 /*============================================================================
608  * Public function definitions for Fortran API
609  *============================================================================*/
610 
611 /*----------------------------------------------------------------------------
612  * Wrapper to cs_face_diffusion_potential
613  *----------------------------------------------------------------------------*/
614 
CS_PROCF(itrmas,ITRMAS)615 void CS_PROCF (itrmas, ITRMAS)
616 (
617  const int       *const   f_id,
618  const int       *const   init,
619  const int       *const   inc,
620  const int       *const   imrgra,
621  const int       *const   iccocg,
622  const int       *const   nswrgp,
623  const int       *const   imligp,
624  const int       *const   iphydp,
625  const int       *const   iwgrp,
626  const int       *const   iwarnp,
627  const cs_real_t *const   epsrgp,
628  const cs_real_t *const   climgp,
629  const cs_real_t *const   extrap,
630  cs_real_3_t              frcxt[],
631  cs_real_t                pvar[],
632  const cs_real_t          coefap[],
633  const cs_real_t          coefbp[],
634  const cs_real_t          cofafp[],
635  const cs_real_t          cofbfp[],
636  const cs_real_t          i_visc[],
637  const cs_real_t          b_visc[],
638  cs_real_t                visel[],
639  cs_real_t                i_massflux[],
640  cs_real_t                b_massflux[]
641 )
642 {
643   CS_UNUSED(extrap);
644 
645   const cs_mesh_t  *m = cs_glob_mesh;
646   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
647 
648   cs_face_diffusion_potential(*f_id,
649                               m,
650                               fvq,
651                               *init,
652                               *inc,
653                               *imrgra,
654                               *iccocg,
655                               *nswrgp,
656                               *imligp,
657                               *iphydp,
658                               *iwgrp,
659                               *iwarnp,
660                               *epsrgp,
661                               *climgp,
662                               frcxt,
663                               pvar,
664                               coefap,
665                               coefbp,
666                               cofafp,
667                               cofbfp,
668                               i_visc,
669                               b_visc,
670                               visel,
671                               i_massflux,
672                               b_massflux);
673 }
674 
675 /*----------------------------------------------------------------------------
676  * Wrapper to cs_face_anisotropic_diffusion_potential
677  *----------------------------------------------------------------------------*/
678 
CS_PROCF(itrmav,ITRMAV)679 void CS_PROCF (itrmav, ITRMAV)
680 (
681  const int       *const   f_id,
682  const int       *const   init,
683  const int       *const   inc,
684  const int       *const   imrgra,
685  const int       *const   iccocg,
686  const int       *const   nswrgp,
687  const int       *const   imligp,
688  const int       *const   ircflp,
689  const int       *const   iphydp,
690  const int       *const   iwgrp,
691  const int       *const   iwarnp,
692  const cs_real_t *const   epsrgp,
693  const cs_real_t *const   climgp,
694  const cs_real_t *const   extrap,
695  cs_real_3_t              frcxt[],
696  cs_real_t                pvar[],
697  const cs_real_t          coefap[],
698  const cs_real_t          coefbp[],
699  const cs_real_t          cofafp[],
700  const cs_real_t          cofbfp[],
701  const cs_real_t          i_visc[],
702  const cs_real_t          b_visc[],
703  cs_real_6_t              viscel[],
704  const cs_real_2_t        weighf[],
705  const cs_real_t          weighb[],
706  cs_real_t                i_massflux[],
707  cs_real_t                b_massflux[]
708 )
709 {
710   CS_UNUSED(extrap);
711 
712   const cs_mesh_t  *m = cs_glob_mesh;
713   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
714 
715   cs_face_anisotropic_diffusion_potential(*f_id,
716                                           m,
717                                           fvq,
718                                           *init,
719                                           *inc,
720                                           *imrgra,
721                                           *iccocg,
722                                           *nswrgp,
723                                           *imligp,
724                                           *ircflp,
725                                           *iphydp,
726                                           *iwgrp,
727                                           *iwarnp,
728                                           *epsrgp,
729                                           *climgp,
730                                           frcxt,
731                                           pvar,
732                                           coefap,
733                                           coefbp,
734                                           cofafp,
735                                           cofbfp,
736                                           i_visc,
737                                           b_visc,
738                                           viscel,
739                                           weighf,
740                                           weighb,
741                                           i_massflux,
742                                           b_massflux);
743 }
744 
745 /*----------------------------------------------------------------------------
746  * Wrapper to cs_diffusion_potential
747  *----------------------------------------------------------------------------*/
748 
CS_PROCF(itrgrp,ITRGRP)749 void CS_PROCF (itrgrp, ITRGRP)
750 (
751  const int       *const   f_id,
752  const int       *const   init,
753  const int       *const   inc,
754  const int       *const   imrgra,
755  const int       *const   iccocg,
756  const int       *const   nswrgp,
757  const int       *const   imligp,
758  const int       *const   iphydp,
759  const int       *const   iwgrp,
760  const int       *const   iwarnp,
761  const cs_real_t *const   epsrgp,
762  const cs_real_t *const   climgp,
763  const cs_real_t *const   extrap,
764  cs_real_3_t              frcxt[],
765  cs_real_t                pvar[],
766  const cs_real_t          coefap[],
767  const cs_real_t          coefbp[],
768  const cs_real_t          cofafp[],
769  const cs_real_t          cofbfp[],
770  const cs_real_t          i_visc[],
771  const cs_real_t          b_visc[],
772  cs_real_t                visel[],
773  cs_real_t                diverg[]
774 )
775 {
776   CS_UNUSED(extrap);
777 
778   const cs_mesh_t  *m = cs_glob_mesh;
779   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
780 
781   cs_diffusion_potential(*f_id,
782                          m,
783                          fvq,
784                          *init,
785                          *inc,
786                          *imrgra,
787                          *iccocg,
788                          *nswrgp,
789                          *imligp,
790                          *iphydp,
791                          *iwgrp,
792                          *iwarnp,
793                          *epsrgp,
794                          *climgp,
795                          frcxt,
796                          pvar,
797                          coefap,
798                          coefbp,
799                          cofafp,
800                          cofbfp,
801                          i_visc,
802                          b_visc,
803                          visel,
804                          diverg);
805 }
806 
807 /*----------------------------------------------------------------------------
808  * Wrapper to cs_anisotropic_diffusion_potential
809  *----------------------------------------------------------------------------*/
810 
CS_PROCF(itrgrv,ITRGRV)811 void CS_PROCF (itrgrv, ITRGRV)
812 (
813  const int       *const   f_id,
814  const int       *const   init,
815  const int       *const   inc,
816  const int       *const   imrgra,
817  const int       *const   iccocg,
818  const int       *const   nswrgp,
819  const int       *const   imligp,
820  const int       *const   ircflp,
821  const int       *const   iphydp,
822  const int       *const   iwgrp,
823  const int       *const   iwarnp,
824  const cs_real_t *const   epsrgp,
825  const cs_real_t *const   climgp,
826  const cs_real_t *const   extrap,
827  cs_real_3_t              frcxt[],
828  cs_real_t                pvar[],
829  const cs_real_t          coefap[],
830  const cs_real_t          coefbp[],
831  const cs_real_t          cofafp[],
832  const cs_real_t          cofbfp[],
833  const cs_real_t          i_visc[],
834  const cs_real_t          b_visc[],
835  cs_real_6_t              viscel[],
836  const cs_real_2_t        weighf[],
837  const cs_real_t          weighb[],
838  cs_real_t                diverg[]
839 )
840 {
841   CS_UNUSED(extrap);
842 
843   const cs_mesh_t  *m = cs_glob_mesh;
844   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
845 
846   cs_anisotropic_diffusion_potential(*f_id,
847                                      m,
848                                      fvq,
849                                      *init,
850                                      *inc,
851                                      *imrgra,
852                                      *iccocg,
853                                      *nswrgp,
854                                      *imligp,
855                                      *ircflp,
856                                      *iphydp,
857                                      *iwgrp,
858                                      *iwarnp,
859                                      *epsrgp,
860                                      *climgp,
861                                      frcxt,
862                                      pvar,
863                                      coefap,
864                                      coefbp,
865                                      cofafp,
866                                      cofbfp,
867                                      i_visc,
868                                      b_visc,
869                                      viscel,
870                                      weighf,
871                                      weighb,
872                                      diverg);
873 }
874 
875 /*============================================================================
876  * Public function definitions
877  *============================================================================*/
878 
879 /*----------------------------------------------------------------------------*/
880 /*!
881  * \brief Compute the upwind gradient used in the slope tests.
882  *
883  * This function assumes the input gradient and pvar values have already
884  * been synchronized.
885  *
886  * \param[in]     f_id         field id
887  * \param[in]     inc          Not an increment flag
888  * \param[in]     halo_type    halo type
889  * \param[in]     grad         standard gradient
890  * \param[out]    grdpa        upwind gradient
891  * \param[in]     pvar         values
892  * \param[in]     coefap       boundary condition array for the variable
893  *                             (explicit part)
894  * \param[in]     coefbp       boundary condition array for the variable
895  *                             (implicit part)
896  * \param[in]     i_massflux   mass flux at interior faces
897  */
898 /*----------------------------------------------------------------------------*/
899 
900 void
cs_slope_test_gradient(int f_id,int inc,cs_halo_type_t halo_type,const cs_real_3_t * grad,cs_real_3_t * grdpa,const cs_real_t * pvar,const cs_real_t * coefap,const cs_real_t * coefbp,const cs_real_t * i_massflux)901 cs_slope_test_gradient(int                     f_id,
902                        int                     inc,
903                        cs_halo_type_t          halo_type,
904                        const cs_real_3_t      *grad,
905                        cs_real_3_t            *grdpa,
906                        const cs_real_t        *pvar,
907                        const cs_real_t        *coefap,
908                        const cs_real_t        *coefbp,
909                        const cs_real_t        *i_massflux)
910 {
911   CS_UNUSED(f_id);
912 
913   const cs_mesh_t  *m = cs_glob_mesh;
914   const cs_halo_t  *halo = m->halo;
915   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
916 
917   const cs_lnum_t n_cells = m->n_cells;
918 
919   const cs_lnum_2_t *restrict i_face_cells
920     = (const cs_lnum_2_t *restrict)m->i_face_cells;
921   const cs_lnum_t *restrict b_face_cells
922     = (const cs_lnum_t *restrict)m->b_face_cells;
923   const cs_real_t *restrict cell_vol = fvq->cell_vol;
924   const cs_real_3_t *restrict cell_cen
925     = (const cs_real_3_t *restrict)fvq->cell_cen;
926   const cs_real_3_t *restrict i_face_normal
927     = (const cs_real_3_t *restrict)fvq->i_face_normal;
928   const cs_real_3_t *restrict b_face_normal
929     = (const cs_real_3_t *restrict)fvq->b_face_normal;
930   const cs_real_3_t *restrict i_face_cog
931     = (const cs_real_3_t *restrict)fvq->i_face_cog;
932   const cs_real_3_t *restrict diipb
933     = (const cs_real_3_t *restrict)fvq->diipb;
934 
935   const int n_i_groups = m->i_face_numbering->n_groups;
936   const int n_i_threads = m->i_face_numbering->n_threads;
937   const int n_b_groups = m->b_face_numbering->n_groups;
938   const int n_b_threads = m->b_face_numbering->n_threads;
939   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
940   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
941 
942   for (int g_id = 0; g_id < n_i_groups; g_id++) {
943 #   pragma omp parallel for
944     for (int t_id = 0; t_id < n_i_threads; t_id++) {
945       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
946            face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
947            face_id++) {
948 
949         cs_lnum_t ii = i_face_cells[face_id][0];
950         cs_lnum_t jj = i_face_cells[face_id][1];
951 
952         cs_real_t difx = i_face_cog[face_id][0] - cell_cen[ii][0];
953         cs_real_t dify = i_face_cog[face_id][1] - cell_cen[ii][1];
954         cs_real_t difz = i_face_cog[face_id][2] - cell_cen[ii][2];
955         cs_real_t djfx = i_face_cog[face_id][0] - cell_cen[jj][0];
956         cs_real_t djfy = i_face_cog[face_id][1] - cell_cen[jj][1];
957         cs_real_t djfz = i_face_cog[face_id][2] - cell_cen[jj][2];
958 
959         cs_real_t pif =   pvar[ii]
960                         + difx*grad[ii][0]+dify*grad[ii][1]+difz*grad[ii][2];
961         cs_real_t pjf =   pvar[jj]
962                         + djfx*grad[jj][0]+djfy*grad[jj][1]+djfz*grad[jj][2];
963 
964         cs_real_t pfac = pjf;
965         if (i_massflux[face_id] > 0.) pfac = pif;
966 
967         cs_real_t pfac1 = pfac*i_face_normal[face_id][0];
968         cs_real_t pfac2 = pfac*i_face_normal[face_id][1];
969         cs_real_t pfac3 = pfac*i_face_normal[face_id][2];
970 
971         grdpa[ii][0] = grdpa[ii][0] + pfac1;
972         grdpa[ii][1] = grdpa[ii][1] + pfac2;
973         grdpa[ii][2] = grdpa[ii][2] + pfac3;
974 
975         grdpa[jj][0] = grdpa[jj][0] - pfac1;
976         grdpa[jj][1] = grdpa[jj][1] - pfac2;
977         grdpa[jj][2] = grdpa[jj][2] - pfac3;
978 
979       }
980     }
981   }
982 
983   for (int g_id = 0; g_id < n_b_groups; g_id++) {
984 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
985     for (int t_id = 0; t_id < n_b_threads; t_id++) {
986       for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
987            face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
988            face_id++) {
989 
990         cs_lnum_t ii = b_face_cells[face_id];
991 
992         cs_real_t pfac = inc*coefap[face_id] + coefbp[face_id]
993           * (pvar[ii] + cs_math_3_dot_product(grad[ii], diipb[face_id]));
994         grdpa[ii][0] = grdpa[ii][0] + pfac*b_face_normal[face_id][0];
995         grdpa[ii][1] = grdpa[ii][1] + pfac*b_face_normal[face_id][1];
996         grdpa[ii][2] = grdpa[ii][2] + pfac*b_face_normal[face_id][2];
997 
998       }
999     }
1000   }
1001 
1002 # pragma omp parallel for
1003   for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
1004 
1005     cs_real_t unsvol = 1./cell_vol[cell_id];
1006 
1007     grdpa[cell_id][0] = grdpa[cell_id][0]*unsvol;
1008     grdpa[cell_id][1] = grdpa[cell_id][1]*unsvol;
1009     grdpa[cell_id][2] = grdpa[cell_id][2]*unsvol;
1010 
1011   }
1012 
1013   /* Synchronization for parallelism or periodicity */
1014 
1015   if (halo != NULL) {
1016     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)grdpa, 3);
1017     if (cs_glob_mesh->n_init_perio > 0)
1018       cs_halo_perio_sync_var_vect(halo, CS_HALO_STANDARD, (cs_real_t *)grdpa, 3);
1019   }
1020 
1021 }
1022 
1023 /*----------------------------------------------------------------------------*/
1024 /*!
1025  * \brief Compute the upwind gradient used in the pure SOLU schemes
1026  *        (observed in the litterature).
1027  *
1028  * \param[in]     f_id         field index
1029  * \param[in]     inc          Not an increment flag
1030  * \param[in]     halo_type    halo type
1031  * \param[in]     coefap       boundary condition array for the variable
1032  *                             (explicit part)
1033  * \param[in]     coefbp       boundary condition array for the variable
1034  *                             (implicit part)
1035  * \param[in]     i_massflux   mass flux at interior faces
1036  * \param[in]     b_massflux   mass flux at boundary faces
1037  * \param[in]     pvar         values
1038  * \param[out]    grdpa        upwind gradient
1039  */
1040 /*----------------------------------------------------------------------------*/
1041 
1042 void
cs_upwind_gradient(const int f_id,const int inc,const cs_halo_type_t halo_type,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],const cs_real_t * restrict pvar,cs_real_3_t * restrict grdpa)1043 cs_upwind_gradient(const int                     f_id,
1044                    const int                     inc,
1045                    const cs_halo_type_t          halo_type,
1046                    const cs_real_t               coefap[],
1047                    const cs_real_t               coefbp[],
1048                    const cs_real_t               i_massflux[],
1049                    const cs_real_t               b_massflux[],
1050                    const cs_real_t     *restrict pvar,
1051                    cs_real_3_t         *restrict grdpa)
1052 {
1053   CS_UNUSED(f_id);
1054 
1055   const cs_mesh_t  *m = cs_glob_mesh;
1056   const cs_halo_t  *halo = m->halo;
1057   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
1058 
1059   const cs_lnum_t n_cells = m->n_cells;
1060 
1061   const cs_lnum_2_t *restrict i_face_cells
1062     = (const cs_lnum_2_t *restrict)m->i_face_cells;
1063   const cs_lnum_t *restrict b_face_cells
1064     = (const cs_lnum_t *restrict)m->b_face_cells;
1065   const cs_real_t *restrict cell_vol = fvq->cell_vol;
1066   const cs_real_3_t *restrict i_face_normal
1067     = (const cs_real_3_t *restrict)fvq->i_face_normal;
1068   const cs_real_3_t *restrict b_face_normal
1069     = (const cs_real_3_t *restrict)fvq->b_face_normal;
1070 
1071   const int n_i_groups = m->i_face_numbering->n_groups;
1072   const int n_i_threads = m->i_face_numbering->n_threads;
1073   const int n_b_groups = m->b_face_numbering->n_groups;
1074   const int n_b_threads = m->b_face_numbering->n_threads;
1075   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1076   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1077 
1078   for (int g_id = 0; g_id < n_i_groups; g_id++) {
1079 #   pragma omp parallel for
1080     for (int t_id = 0; t_id < n_i_threads; t_id++) {
1081       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1082            face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1083            face_id++) {
1084 
1085         cs_lnum_t ii = i_face_cells[face_id][0];
1086         cs_lnum_t jj = i_face_cells[face_id][1];
1087 
1088         cs_real_t pif = pvar[ii];
1089         cs_real_t pjf = pvar[jj];
1090 
1091         cs_real_t pfac = pjf;
1092         if (i_massflux[face_id] > 0.) pfac = pif;
1093 
1094         cs_real_t pfac1 = pfac*i_face_normal[face_id][0];
1095         cs_real_t pfac2 = pfac*i_face_normal[face_id][1];
1096         cs_real_t pfac3 = pfac*i_face_normal[face_id][2];
1097 
1098         grdpa[ii][0] = grdpa[ii][0] + pfac1;
1099         grdpa[ii][1] = grdpa[ii][1] + pfac2;
1100         grdpa[ii][2] = grdpa[ii][2] + pfac3;
1101 
1102         grdpa[jj][0] = grdpa[jj][0] - pfac1;
1103         grdpa[jj][1] = grdpa[jj][1] - pfac2;
1104         grdpa[jj][2] = grdpa[jj][2] - pfac3;
1105 
1106       }
1107     }
1108   }
1109 
1110   for (int g_id = 0; g_id < n_b_groups; g_id++) {
1111 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
1112     for (int t_id = 0; t_id < n_b_threads; t_id++) {
1113       for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1114            face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1115            face_id++) {
1116 
1117         cs_lnum_t ii = b_face_cells[face_id];
1118 
1119         cs_real_t pfac = pvar[ii];
1120 
1121         if (b_massflux[face_id] < 0)
1122           pfac = inc*coefap[face_id] + coefbp[face_id] * pvar[ii];
1123 
1124         grdpa[ii][0] = grdpa[ii][0] + pfac*b_face_normal[face_id][0];
1125         grdpa[ii][1] = grdpa[ii][1] + pfac*b_face_normal[face_id][1];
1126         grdpa[ii][2] = grdpa[ii][2] + pfac*b_face_normal[face_id][2];
1127 
1128       }
1129     }
1130   }
1131 
1132 # pragma omp parallel for
1133   for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
1134 
1135     cs_real_t unsvol = 1./cell_vol[cell_id];
1136 
1137     grdpa[cell_id][0] = grdpa[cell_id][0]*unsvol;
1138     grdpa[cell_id][1] = grdpa[cell_id][1]*unsvol;
1139     grdpa[cell_id][2] = grdpa[cell_id][2]*unsvol;
1140 
1141   }
1142 
1143   /* Synchronization for parallelism or periodicity */
1144 
1145   if (halo != NULL) {
1146     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)grdpa, 3);
1147     if (cs_glob_mesh->n_init_perio > 0)
1148       cs_halo_perio_sync_var_vect(halo, halo_type, (cs_real_t *)grdpa, 3);
1149   }
1150 }
1151 
1152 /*----------------------------------------------------------------------------*/
1153 /*!
1154  * \brief Compute the upwind gradient used in the slope tests.
1155  *
1156  * This function assumes the input gradient and pvar values have already
1157  * been synchronized.
1158  *
1159  * \param[in]     inc          Not an increment flag
1160  * \param[in]     halo_type    halo type
1161  * \param[in]     grad         standard gradient
1162  * \param[out]    grdpa        upwind gradient
1163  * \param[in]     pvar         values
1164  * \param[in]     coefa        boundary condition array for the variable
1165                                (Explicit part)
1166  * \param[in]     coefb        boundary condition array for the variable
1167                               (Implicit part)
1168  * \param[in]     i_massflux   mass flux at interior faces
1169  */
1170 /*----------------------------------------------------------------------------*/
1171 
1172 void
cs_slope_test_gradient_vector(const int inc,const cs_halo_type_t halo_type,const cs_real_33_t * grad,cs_real_33_t * grdpa,const cs_real_3_t * pvar,const cs_real_3_t * coefa,const cs_real_33_t * coefb,const cs_real_t * i_massflux)1173 cs_slope_test_gradient_vector(const int              inc,
1174                               const cs_halo_type_t   halo_type,
1175                               const cs_real_33_t    *grad,
1176                               cs_real_33_t          *grdpa,
1177                               const cs_real_3_t     *pvar,
1178                               const cs_real_3_t     *coefa,
1179                               const cs_real_33_t    *coefb,
1180                               const cs_real_t       *i_massflux)
1181 {
1182   const cs_mesh_t  *m = cs_glob_mesh;
1183   const cs_halo_t  *halo = m->halo;
1184   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
1185 
1186   const cs_lnum_t n_cells = m->n_cells;
1187 
1188   const cs_lnum_2_t *restrict i_face_cells
1189     = (const cs_lnum_2_t *restrict)m->i_face_cells;
1190   const cs_lnum_t *restrict b_face_cells
1191     = (const cs_lnum_t *restrict)m->b_face_cells;
1192   const cs_real_t *restrict cell_vol = fvq->cell_vol;
1193   const cs_real_3_t *restrict cell_cen
1194     = (const cs_real_3_t *restrict)fvq->cell_cen;
1195   const cs_real_3_t *restrict i_f_face_normal
1196     = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
1197   const cs_real_3_t *restrict b_f_face_normal
1198     = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
1199   const cs_real_3_t *restrict i_face_cog
1200     = (const cs_real_3_t *restrict)fvq->i_face_cog;
1201   const cs_real_3_t *restrict diipb
1202     = (const cs_real_3_t *restrict)fvq->diipb;
1203 
1204   const int n_i_groups = m->i_face_numbering->n_groups;
1205   const int n_i_threads = m->i_face_numbering->n_threads;
1206   const int n_b_groups = m->b_face_numbering->n_groups;
1207   const int n_b_threads = m->b_face_numbering->n_threads;
1208   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1209   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1210 
1211   for (int g_id = 0; g_id < n_i_groups; g_id++) {
1212 #   pragma omp parallel for
1213     for (int t_id = 0; t_id < n_i_threads; t_id++) {
1214       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1215            face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1216            face_id++) {
1217 
1218         cs_real_t difv[3], djfv[3];
1219 
1220         cs_lnum_t ii = i_face_cells[face_id][0];
1221         cs_lnum_t jj = i_face_cells[face_id][1];
1222 
1223         for (int jsou = 0; jsou < 3; jsou++) {
1224           difv[jsou] = i_face_cog[face_id][jsou] - cell_cen[ii][jsou];
1225           djfv[jsou] = i_face_cog[face_id][jsou] - cell_cen[jj][jsou];
1226         }
1227 
1228         /* x-y-z component, p = u, v, w */
1229 
1230         for (int isou = 0; isou < 3; isou++) {
1231           cs_real_t pif = pvar[ii][isou];
1232           cs_real_t pjf = pvar[jj][isou];
1233           for (int jsou = 0; jsou < 3; jsou++) {
1234             pif = pif + grad[ii][isou][jsou]*difv[jsou];
1235             pjf = pjf + grad[jj][isou][jsou]*djfv[jsou];
1236           }
1237 
1238           cs_real_t pfac = pjf;
1239           if (i_massflux[face_id] > 0.) pfac = pif;
1240 
1241           /* U gradient */
1242 
1243           cs_real_t vfac[3];
1244 
1245           for (int jsou = 0; jsou < 3; jsou++) {
1246             vfac[jsou] = pfac*i_f_face_normal[face_id][jsou];
1247 
1248             grdpa[ii][isou][jsou] = grdpa[ii][isou][jsou] + vfac[jsou];
1249             grdpa[jj][isou][jsou] = grdpa[jj][isou][jsou] - vfac[jsou];
1250           }
1251         }
1252 
1253       }
1254     }
1255   }
1256 
1257   for (int g_id = 0; g_id < n_b_groups; g_id++) {
1258 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
1259     for (int t_id = 0; t_id < n_b_threads; t_id++) {
1260       for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1261            face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1262            face_id++) {
1263 
1264         cs_real_t diipbv[3];
1265         cs_lnum_t ii = b_face_cells[face_id];
1266 
1267         for (int jsou = 0; jsou < 3; jsou++)
1268           diipbv[jsou] = diipb[face_id][jsou];
1269 
1270         /* x-y-z components, p = u, v, w */
1271 
1272         for (int isou = 0; isou < 3; isou++) {
1273           cs_real_t pfac = inc*coefa[face_id][isou];
1274           /*coefu is a matrix */
1275           for (int jsou =  0; jsou < 3; jsou++)
1276             pfac += coefb[face_id][jsou][isou]*(  pvar[ii][jsou]
1277                                                 + grad[ii][jsou][0]*diipbv[0]
1278                                                 + grad[ii][jsou][1]*diipbv[1]
1279                                                 + grad[ii][jsou][2]*diipbv[2]);
1280 
1281           for (int jsou = 0; jsou < 3; jsou++)
1282             grdpa[ii][isou][jsou] += pfac*b_f_face_normal[face_id][jsou];
1283         }
1284 
1285       }
1286     }
1287   }
1288 
1289 # pragma omp parallel for
1290   for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
1291     cs_real_t unsvol = 1./cell_vol[cell_id];
1292     for (int isou = 0; isou < 3; isou++) {
1293       for (int jsou = 0; jsou < 3; jsou++)
1294         grdpa[cell_id][isou][jsou] = grdpa[cell_id][isou][jsou]*unsvol;
1295     }
1296   }
1297 
1298   /* Handle parallelism and periodicity */
1299 
1300   if (halo != NULL) {
1301     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)grdpa, 9);
1302     if (m->n_init_perio > 0)
1303       cs_halo_perio_sync_var_sym_tens(halo, halo_type, (cs_real_t *)grdpa);
1304   }
1305 }
1306 
1307 /*----------------------------------------------------------------------------*/
1308 /*!
1309  * \brief Compute the upwind gradient used in the slope tests.
1310  *
1311  * This function assumes the input gradient and pvar values have already
1312  * been synchronized.
1313  *
1314  * \param[in]     inc          Not an increment flag
1315  * \param[in]     halo_type    halo type
1316  * \param[in]     grad         standard gradient
1317  * \param[out]    grdpa        upwind gradient
1318  * \param[in]     pvar         values
1319  * \param[in]     coefa        boundary condition array for the variable
1320                                (Explicit part)
1321  * \param[in]     coefb        boundary condition array for the variable
1322                               (Implicit part)
1323  * \param[in]     i_massflux   mass flux at interior faces
1324  */
1325 /*----------------------------------------------------------------------------*/
1326 
1327 void
cs_slope_test_gradient_tensor(const int inc,const cs_halo_type_t halo_type,const cs_real_63_t * grad,cs_real_63_t * grdpa,const cs_real_6_t * pvar,const cs_real_6_t * coefa,const cs_real_66_t * coefb,const cs_real_t * i_massflux)1328 cs_slope_test_gradient_tensor(const int              inc,
1329                               const cs_halo_type_t   halo_type,
1330                               const cs_real_63_t    *grad,
1331                               cs_real_63_t          *grdpa,
1332                               const cs_real_6_t     *pvar,
1333                               const cs_real_6_t     *coefa,
1334                               const cs_real_66_t    *coefb,
1335                               const cs_real_t       *i_massflux)
1336 {
1337   const cs_mesh_t  *m = cs_glob_mesh;
1338   const cs_halo_t  *halo = m->halo;
1339   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
1340 
1341   const cs_lnum_t n_cells = m->n_cells;
1342 
1343   const cs_lnum_2_t *restrict i_face_cells
1344     = (const cs_lnum_2_t *restrict)m->i_face_cells;
1345   const cs_lnum_t *restrict b_face_cells
1346     = (const cs_lnum_t *restrict)m->b_face_cells;
1347   const cs_real_t *restrict cell_vol = fvq->cell_vol;
1348   const cs_real_3_t *restrict cell_cen
1349     = (const cs_real_3_t *restrict)fvq->cell_cen;
1350   const cs_real_3_t *restrict i_f_face_normal
1351     = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
1352   const cs_real_3_t *restrict b_f_face_normal
1353     = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
1354   const cs_real_3_t *restrict i_face_cog
1355     = (const cs_real_3_t *restrict)fvq->i_face_cog;
1356   const cs_real_3_t *restrict diipb
1357     = (const cs_real_3_t *restrict)fvq->diipb;
1358 
1359   const int n_i_groups = m->i_face_numbering->n_groups;
1360   const int n_i_threads = m->i_face_numbering->n_threads;
1361   const int n_b_groups = m->b_face_numbering->n_groups;
1362   const int n_b_threads = m->b_face_numbering->n_threads;
1363   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1364   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1365 
1366   for (int g_id = 0; g_id < n_i_groups; g_id++) {
1367 #   pragma omp parallel for
1368     for (int t_id = 0; t_id < n_i_threads; t_id++) {
1369       for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1370            face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1371            face_id++) {
1372 
1373         cs_real_t difv[3], djfv[3];
1374 
1375         cs_lnum_t ii = i_face_cells[face_id][0];
1376         cs_lnum_t jj = i_face_cells[face_id][1];
1377 
1378         for (int jsou = 0; jsou < 3; jsou++) {
1379           difv[jsou] = i_face_cog[face_id][jsou] - cell_cen[ii][jsou];
1380           djfv[jsou] = i_face_cog[face_id][jsou] - cell_cen[jj][jsou];
1381         }
1382 
1383         /* x-y-z component, p = u, v, w */
1384 
1385         for (int isou = 0; isou < 6; isou++) {
1386           cs_real_t pif = pvar[ii][isou];
1387           cs_real_t pjf = pvar[jj][isou];
1388           for (int jsou = 0; jsou < 3; jsou++) {
1389             pif = pif + grad[ii][isou][jsou]*difv[jsou];
1390             pjf = pjf + grad[jj][isou][jsou]*djfv[jsou];
1391           }
1392 
1393           cs_real_t pfac = pjf;
1394           if (i_massflux[face_id] > 0.) pfac = pif;
1395 
1396           /* U gradient */
1397 
1398           cs_real_t vfac[3];
1399 
1400           for (int jsou = 0; jsou < 3; jsou++) {
1401             vfac[jsou] = pfac*i_f_face_normal[face_id][jsou];
1402 
1403             grdpa[ii][isou][jsou] = grdpa[ii][isou][jsou] + vfac[jsou];
1404             grdpa[jj][isou][jsou] = grdpa[jj][isou][jsou] - vfac[jsou];
1405           }
1406         }
1407 
1408       }
1409     }
1410   }
1411 
1412   for (int g_id = 0; g_id < n_b_groups; g_id++) {
1413 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
1414     for (int t_id = 0; t_id < n_b_threads; t_id++) {
1415       for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1416            face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1417            face_id++) {
1418 
1419         cs_real_t diipbv[3];
1420         cs_lnum_t ii = b_face_cells[face_id];
1421 
1422         for (int jsou = 0; jsou < 3; jsou++)
1423           diipbv[jsou] = diipb[face_id][jsou];
1424 
1425         /* x-y-z components, p = u, v, w */
1426 
1427         for (int isou = 0; isou < 6; isou++) {
1428           cs_real_t pfac = inc*coefa[face_id][isou];
1429           /*coefu is a matrix */
1430           for (int jsou =  0; jsou < 6; jsou++)
1431             pfac += coefb[face_id][jsou][isou]*(  pvar[ii][jsou]
1432                                                 + grad[ii][jsou][0]*diipbv[0]
1433                                                 + grad[ii][jsou][1]*diipbv[1]
1434                                                 + grad[ii][jsou][2]*diipbv[2]);
1435 
1436           for (int jsou = 0; jsou < 3; jsou++)
1437             grdpa[ii][isou][jsou] += pfac*b_f_face_normal[face_id][jsou];
1438         }
1439 
1440       }
1441     }
1442   }
1443 
1444 # pragma omp parallel for
1445   for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
1446     cs_real_t unsvol = 1./cell_vol[cell_id];
1447     for (int isou = 0; isou < 6; isou++) {
1448       for (int jsou = 0; jsou < 3; jsou++)
1449         grdpa[cell_id][isou][jsou] = grdpa[cell_id][isou][jsou]*unsvol;
1450     }
1451   }
1452 
1453   /* Handle parallelism and periodicity */
1454 
1455   if (halo != NULL) {
1456     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)grdpa, 18);
1457     if (m->n_init_perio > 0)
1458       cs_halo_perio_sync_var_sym_tens(halo, halo_type, (cs_real_t *)grdpa);
1459   }
1460 }
1461 
1462 /*----------------------------------------------------------------------------*/
1463 /*!
1464  * \brief Compute the beta blending coefficient of the
1465  * beta limiter (ensuring preservation of a given min/max pair of values).
1466  *
1467  * \param[in]     f_id         field id
1468  * \param[in]     inc          "not an increment" flag
1469  * \param[in]     rovsdt       rho * volume / dt
1470  */
1471 /*----------------------------------------------------------------------------*/
1472 
1473 void
cs_beta_limiter_building(int f_id,int inc,const cs_real_t rovsdt[])1474 cs_beta_limiter_building(int              f_id,
1475                          int              inc,
1476                          const cs_real_t  rovsdt[])
1477 {
1478   const cs_mesh_t *m = cs_glob_mesh;
1479   const cs_halo_t *halo = m->halo;
1480   const cs_lnum_t n_cells = m->n_cells;
1481   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
1482 
1483   /* Get options from the field */
1484 
1485   cs_field_t *f = cs_field_by_id(f_id);
1486   int key_cal_opt_id = cs_field_key_id("var_cal_opt");
1487   cs_var_cal_opt_t var_cal_opt;
1488 
1489   cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
1490 
1491   if (var_cal_opt.isstpc != 2)
1492     return;
1493 
1494   cs_real_t* cpro_beta = cs_field_by_id(
1495       cs_field_get_key_int(f, cs_field_key_id("convection_limiter_id")))->val;
1496 
1497   cs_real_t* denom_inf;
1498   cs_real_t* num_inf;
1499   cs_real_t* denom_sup;
1500   cs_real_t* num_sup;
1501 
1502   BFT_MALLOC(denom_inf, n_cells_ext, cs_real_t);
1503   BFT_MALLOC(denom_sup, n_cells_ext, cs_real_t);
1504   BFT_MALLOC(num_inf, n_cells_ext, cs_real_t);
1505   BFT_MALLOC(num_sup, n_cells_ext, cs_real_t);
1506 
1507   /* computation of the denominator for the inferior and superior bound */
1508 
1509   _beta_limiter_denom(f_id,
1510                       inc,
1511                       denom_inf,
1512                       denom_sup);
1513 
1514   /* computation of the numerator for the inferior and superior bound */
1515 
1516   _beta_limiter_num(f_id,
1517                     inc,
1518                     rovsdt,
1519                     num_inf,
1520                     num_sup);
1521 
1522 # pragma omp parallel for
1523   for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
1524 
1525     /* Treatment of the inferior bound */
1526     cs_real_t beta_inf;
1527     if (denom_inf[ii] <= num_inf[ii]) {
1528       beta_inf = 1.;
1529     }
1530     else if (denom_inf[ii] <= CS_ABS(num_inf[ii])) {
1531       beta_inf = -1.;
1532     }
1533     else {
1534       beta_inf = num_inf[ii]/denom_inf[ii]; //FIXME division by 0
1535       beta_inf = CS_MIN(beta_inf, 1.);
1536     }
1537 
1538     /* Treatment of the superior bound */
1539     cs_real_t beta_sup;
1540     if (denom_sup[ii] <= num_sup[ii]) {
1541       beta_sup = 1.;
1542     }
1543     else if (denom_sup[ii] <= CS_ABS(num_sup[ii])) {
1544       beta_sup = -1.;
1545     }
1546     else {
1547       beta_sup = num_sup[ii]/denom_sup[ii]; //FIXME division by 0
1548       beta_sup = CS_MIN(beta_sup, 1.);
1549     }
1550 
1551     cpro_beta[ii] = CS_MIN(beta_inf, beta_sup);
1552   }
1553 
1554   /* Synchronize variable */
1555   if (halo != NULL)
1556     cs_halo_sync_var(halo, CS_HALO_STANDARD, cpro_beta);
1557 
1558   BFT_FREE(denom_inf);
1559   BFT_FREE(num_inf);
1560   BFT_FREE(denom_sup);
1561   BFT_FREE(num_sup);
1562 }
1563 
1564 /*----------------------------------------------------------------------------*/
1565 /*!
1566  * <a name="cs_convection_diffusion_scalar"></a>
1567  *
1568  * \brief Add the explicit part of the convection/diffusion terms of a
1569  * standard transport equation of a scalar field \f$ \varia \f$.
1570  *
1571  * More precisely, the right hand side \f$ Rhs \f$ is updated as
1572  * follows:
1573  * \f[
1574  * Rhs = Rhs - \sum_{\fij \in \Facei{\celli}}      \left(
1575  *        \dot{m}_\ij \left( \varia_\fij - \varia_\celli \right)
1576  *      - \mu_\fij \gradv_\fij \varia \cdot \vect{S}_\ij  \right)
1577  * \f]
1578  *
1579  * Warning:
1580  * - \f$ Rhs \f$ has already been initialized before calling bilsc2!
1581  * - mind the sign minus
1582  *
1583  * Please refer to the
1584  * <a href="../../theory.pdf#bilsc2"><b>bilsc2</b></a> section of the
1585  * theory guide for more informations.
1586  *
1587  * \param[in]     idtvar        indicator of the temporal scheme
1588  * \param[in]     f_id          field id (or -1)
1589  * \param[in]     var_cal_opt   variable calculation options
1590  * \param[in]     icvflb        global indicator of boundary convection flux
1591  *                               - 0 upwind scheme at all boundary faces
1592  *                               - 1 imposed flux at some boundary faces
1593  * \param[in]     inc           indicator
1594  *                               - 0 when solving an increment
1595  *                               - 1 otherwise
1596  * \param[in]     iccocg        indicator
1597  *                               - 1 re-compute cocg matrix
1598  *                                   (for iterative gradients)
1599  *                               - 0 otherwise
1600  * \param[in]     imasac        take mass accumulation into account?
1601  * \param[in]     pvar          solved variable (current time step)
1602  * \param[in]     pvara         solved variable (previous time step)
1603  * \param[in]     icvfli        boundary face indicator array of convection flux
1604  *                               - 0 upwind scheme
1605  *                               - 1 imposed flux
1606  * \param[in]     coefap        boundary condition array for the variable
1607  *                               (explicit part)
1608  * \param[in]     coefbp        boundary condition array for the variable
1609  *                               (implicit part)
1610  * \param[in]     cofafp        boundary condition array for the diffusion
1611  *                               of the variable (explicit part)
1612  * \param[in]     cofbfp        boundary condition array for the diffusion
1613  *                               of the variable (implicit part)
1614  * \param[in]     i_massflux    mass flux at interior faces
1615  * \param[in]     b_massflux    mass flux at boundary faces
1616  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
1617  *                               at interior faces for the r.h.s.
1618  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
1619  *                               at border faces for the r.h.s.
1620  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
1621  */
1622 /*----------------------------------------------------------------------------*/
1623 
1624 void
cs_convection_diffusion_scalar(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int icvflb,int inc,int iccocg,int imasac,cs_real_t * restrict pvar,const cs_real_t * restrict pvara,const int icvfli[],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_t * restrict rhs)1625 cs_convection_diffusion_scalar(int                       idtvar,
1626                                int                       f_id,
1627                                const cs_var_cal_opt_t    var_cal_opt,
1628                                int                       icvflb,
1629                                int                       inc,
1630                                int                       iccocg,
1631                                int                       imasac,
1632                                cs_real_t       *restrict pvar,
1633                                const cs_real_t *restrict pvara,
1634                                const int                 icvfli[],
1635                                const cs_real_t           coefap[],
1636                                const cs_real_t           coefbp[],
1637                                const cs_real_t           cofafp[],
1638                                const cs_real_t           cofbfp[],
1639                                const cs_real_t           i_massflux[],
1640                                const cs_real_t           b_massflux[],
1641                                const cs_real_t           i_visc[],
1642                                const cs_real_t           b_visc[],
1643                                cs_real_t       *restrict rhs)
1644 {
1645   const int iconvp = var_cal_opt.iconv;
1646   const int idiffp = var_cal_opt.idiff;
1647   const int nswrgp = var_cal_opt.nswrgr;
1648   const int imrgra = var_cal_opt.imrgra;
1649   const int imligp = var_cal_opt.imligr;
1650   const int ircflp = var_cal_opt.ircflu;
1651   const int ischcp = var_cal_opt.ischcv;
1652   const int isstpp = var_cal_opt.isstpc;
1653   const int iwarnp = var_cal_opt.verbosity;
1654   const int icoupl = var_cal_opt.icoupl;
1655   int limiter_choice = -1;
1656   const double blencp = var_cal_opt.blencv;
1657   const double blend_st = var_cal_opt.blend_st;
1658   const double epsrgp = var_cal_opt.epsrgr;
1659   const double climgp = var_cal_opt.climgr;
1660   const double relaxp = var_cal_opt.relaxv;
1661   const double thetap = var_cal_opt.thetav;
1662 
1663   const cs_mesh_t  *m = cs_glob_mesh;
1664   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
1665 
1666   const cs_lnum_t n_cells = m->n_cells;
1667   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
1668   const int n_i_groups = m->i_face_numbering->n_groups;
1669   const int n_i_threads = m->i_face_numbering->n_threads;
1670   const int n_b_groups = m->b_face_numbering->n_groups;
1671   const int n_b_threads = m->b_face_numbering->n_threads;
1672   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1673   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1674 
1675   const cs_lnum_2_t *restrict i_face_cells
1676     = (const cs_lnum_2_t *restrict)m->i_face_cells;
1677   const cs_lnum_t *restrict b_face_cells
1678     = (const cs_lnum_t *restrict)m->b_face_cells;
1679   const cs_real_t *restrict weight = fvq->weight;
1680   const cs_real_t *restrict i_dist = fvq->i_dist;
1681   const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
1682   const cs_real_t *restrict cell_vol = fvq->cell_vol;
1683   const cs_real_3_t *restrict cell_cen
1684     = (const cs_real_3_t *restrict)fvq->cell_cen;
1685   const cs_real_3_t *restrict i_face_normal
1686     = (const cs_real_3_t *restrict)fvq->i_face_normal;
1687   const cs_real_3_t *restrict i_face_cog
1688     = (const cs_real_3_t *restrict)fvq->i_face_cog;
1689   const cs_real_3_t *restrict diipf
1690     = (const cs_real_3_t *restrict)fvq->diipf;
1691   const cs_real_3_t *restrict djjpf
1692     = (const cs_real_3_t *restrict)fvq->djjpf;
1693   const cs_real_3_t *restrict diipb
1694     = (const cs_real_3_t *restrict)fvq->diipb;
1695 
1696   const int *bc_type = cs_glob_bc_type;
1697 
1698   /* Local variables */
1699 
1700   char var_name[64];
1701 
1702   int iupwin = 0;
1703   int w_stride = 1;
1704 
1705   bool recompute_cocg = (iccocg) ? true : false;
1706 
1707   cs_real_t *coface = NULL, *cofbce = NULL;
1708 
1709   cs_real_3_t *grad;
1710   cs_real_3_t *gradup = NULL;
1711   cs_real_3_t *gradst = NULL;
1712   cs_field_t *f = NULL;
1713 
1714   cs_real_t *local_min = NULL;
1715   cs_real_t *local_max = NULL;
1716   cs_real_t *courant = NULL;
1717 
1718   cs_real_t *cv_limiter = NULL;
1719   cs_real_t *df_limiter = NULL;
1720 
1721   cs_real_t *gweight = NULL;
1722 
1723   const int key_lim_choice = cs_field_key_id("limiter_choice");
1724 
1725   cs_real_t  *v_slope_test = cs_get_v_slope_test(f_id,  var_cal_opt);
1726 
1727   /* Internal coupling variables */
1728   cs_real_t *pvar_local = NULL;
1729   cs_real_t *pvar_distant = NULL;
1730   cs_real_t *df_limiter_local = NULL;
1731   int coupling_id = -1;
1732   cs_lnum_t n_local = 0, n_distant = 0;
1733   const cs_lnum_t *faces_local = NULL, *faces_distant = NULL;
1734   cs_internal_coupling_t *cpl = NULL;
1735 
1736   /* Initialization */
1737 
1738   /* Allocate work arrays */
1739 
1740   BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
1741 
1742   /* Choose gradient type */
1743 
1744   cs_halo_type_t halo_type = CS_HALO_STANDARD;
1745   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
1746 
1747   cs_gradient_type_by_imrgra(imrgra,
1748                              &gradient_type,
1749                              &halo_type);
1750 
1751   /* Handle cases where only the previous values (already synchronized)
1752      or current values are provided */
1753 
1754   if (pvar != NULL)
1755     cs_sync_scalar_halo(m, pvar);
1756   if (pvara == NULL)
1757     pvara = (const cs_real_t *restrict)pvar;
1758 
1759   const cs_real_t  *restrict _pvar = (pvar != NULL) ? pvar : pvara;
1760 
1761   /* Limiters */
1762 
1763   if (f_id != -1) {
1764     f = cs_field_by_id(f_id);
1765 
1766     /* NVD/TVD limiters */
1767     if (ischcp == 4) {
1768       limiter_choice = cs_field_get_key_int(f, key_lim_choice);
1769       BFT_MALLOC(local_max, n_cells_ext, cs_real_t);
1770       BFT_MALLOC(local_min, n_cells_ext, cs_real_t);
1771       cs_field_local_extrema_scalar(f_id,
1772                                     halo_type,
1773                                     local_max,
1774                                     local_min);
1775       if (limiter_choice >= CS_NVD_VOF_HRIC) {
1776         BFT_MALLOC(courant, n_cells_ext, cs_real_t);
1777         cs_cell_courant_number(f_id, courant);
1778       }
1779     }
1780 
1781     int cv_limiter_id =
1782       cs_field_get_key_int(f, cs_field_key_id("convection_limiter_id"));
1783     if (cv_limiter_id > -1)
1784       cv_limiter = cs_field_by_id(cv_limiter_id)->val;
1785 
1786     int df_limiter_id =
1787       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
1788     if (df_limiter_id > -1)
1789       df_limiter = cs_field_by_id(df_limiter_id)->val;
1790 
1791     snprintf(var_name, 63, "%s", f->name);
1792   }
1793   else if (isstpp > 1) {
1794     bft_error(__FILE__, __LINE__, 0,
1795               _("invalid value of isstpp for a work array"));
1796   } else {
1797     strncpy(var_name, "[scalar convection-diffusion]", 63);
1798   }
1799   var_name[63] = '\0';
1800 
1801   if (iwarnp >= 2) {
1802     if (ischcp == 1) {
1803       bft_printf(
1804         _(" %s: Convection in centered blending with %f percent of upwind\n"),
1805         var_name, (1.-blencp)*100.);
1806     } else {
1807       bft_printf(
1808         _(" %s: Convection in 2nd order blending with %f percent of upwind\n"),
1809         var_name, (1.-blencp)*100.);
1810     }
1811   }
1812 
1813   iupwin = (blencp > 0.) ? 0 : 1;
1814 
1815   if (icoupl > 0) {
1816     assert(f_id != -1);
1817     const int coupling_key_id = cs_field_key_id("coupling_entity");
1818     coupling_id = cs_field_get_key_int(f, coupling_key_id);
1819     cpl = cs_internal_coupling_by_id(coupling_id);
1820     cs_internal_coupling_coupled_faces(cpl,
1821                                        &n_local,
1822                                        &faces_local,
1823                                        &n_distant,
1824                                        &faces_distant);
1825   }
1826 
1827   /* Compute the balance with reconstruction */
1828 
1829   /* Compute the gradient of the variable */
1830 
1831   /* The gradient (grad) is used in the flux reconstruction and the slope test.
1832      Thus we must compute it:
1833          - when we have diffusion and we reconstruct the fluxes,
1834          - when the convection scheme is the legacy SOLU,
1835          - when we have convection, we are not in pure upwind
1836            and we reconstruct the fluxes,
1837          - when we have convection, we are not in pure upwind
1838            and we have not shunted the slope test,
1839          - when we use NVD / TVD schemes.
1840   */
1841 
1842   if (  (idiffp != 0 && ircflp == 1)
1843      || (  iconvp != 0 && iupwin == 0
1844         && (ischcp == 0 || ircflp == 1 || isstpp == 0 || ischcp == 3 || ischcp == 4))) {
1845 
1846     if (f_id != -1) {
1847       /* Get the calculation option from the field */
1848       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
1849         if (var_cal_opt.idiff > 0) {
1850           int key_id = cs_field_key_id("gradient_weighting_id");
1851           int diff_id = cs_field_get_key_int(f, key_id);
1852           if (diff_id > -1) {
1853             cs_field_t *weight_f = cs_field_by_id(diff_id);
1854             gweight = weight_f->val;
1855             w_stride = weight_f->dim;
1856             cs_field_synchronize(weight_f, halo_type);
1857           }
1858         }
1859       }
1860     }
1861 
1862     cs_gradient_scalar_synced_input(var_name,
1863                                     gradient_type,
1864                                     halo_type,
1865                                     inc,
1866                                     recompute_cocg,
1867                                     nswrgp,
1868                                     0, /* hyd_p_flag */
1869                                     w_stride,
1870                                     iwarnp,
1871                                     imligp,
1872                                     epsrgp,
1873                                     climgp,
1874                                     NULL, /* f_ext exterior force */
1875                                     coefap,
1876                                     coefbp,
1877                                     _pvar,
1878                                     gweight, /* Weighted gradient */
1879                                     cpl,
1880                                     grad);
1881 
1882   } else {
1883 
1884 #   pragma omp parallel for
1885     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
1886       grad[cell_id][0] = 0.;
1887       grad[cell_id][1] = 0.;
1888       grad[cell_id][2] = 0.;
1889     }
1890   }
1891 
1892   /* Compute gradients used in convection schemes */
1893 
1894   if (iconvp > 0 && iupwin == 0) {
1895 
1896     /* Compute cell gradient used in slope test */
1897     if (isstpp == 0) {
1898 
1899       BFT_MALLOC(gradst, n_cells_ext, cs_real_3_t);
1900 
1901 #     pragma omp parallel for
1902       for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
1903         gradst[cell_id][0] = 0.;
1904         gradst[cell_id][1] = 0.;
1905         gradst[cell_id][2] = 0.;
1906       }
1907 
1908       cs_slope_test_gradient(f_id,
1909                              inc,
1910                              halo_type,
1911                              (const cs_real_3_t *)grad,
1912                              gradst,
1913                              _pvar,
1914                              coefap,
1915                              coefbp,
1916                              i_massflux);
1917 
1918     }
1919 
1920     /* Pure SOLU scheme */
1921     if (ischcp == 2) {
1922 
1923       BFT_MALLOC(gradup, n_cells_ext, cs_real_3_t);
1924 
1925 #     pragma omp parallel for
1926       for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
1927         gradup[cell_id][0] = 0.;
1928         gradup[cell_id][1] = 0.;
1929         gradup[cell_id][2] = 0.;
1930       }
1931 
1932       cs_upwind_gradient(f_id,
1933                          inc,
1934                          halo_type,
1935                          coefap,
1936                          coefbp,
1937                          i_massflux,
1938                          b_massflux,
1939                          _pvar,
1940                          gradup);
1941 
1942     }
1943 
1944   }
1945 
1946   /* ======================================================================
1947     ---> Contribution from interior faces
1948     ======================================================================*/
1949 
1950   cs_gnum_t n_upwind = 0;
1951 
1952   if (n_cells_ext>n_cells) {
1953 #   pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
1954     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
1955       rhs[cell_id] = 0.;
1956     }
1957   }
1958 
1959   /* --> Pure upwind flux
1960     =====================*/
1961 
1962   if (iupwin == 1) {
1963 
1964     /* Steady */
1965     if (idtvar < 0) {
1966 
1967       for (int g_id = 0; g_id < n_i_groups; g_id++) {
1968 #       pragma omp parallel for reduction(+:n_upwind)
1969         for (int t_id = 0; t_id < n_i_threads; t_id++) {
1970           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1971                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1972                face_id++) {
1973 
1974             cs_lnum_t ii = i_face_cells[face_id][0];
1975             cs_lnum_t jj = i_face_cells[face_id][1];
1976 
1977             /* in parallel, face will be counted by one and only one rank */
1978             if (ii < n_cells) {
1979               n_upwind++;
1980             }
1981 
1982             cs_real_2_t fluxij = {0.,0.};
1983 
1984             cs_real_t pifri, pjfri, pifrj, pjfrj;
1985             cs_real_t pip, pjp, pipr, pjpr;
1986 
1987             cs_real_t bldfrp = (cs_real_t) ircflp;
1988             /* Local limitation of the reconstruction */
1989             if (df_limiter != NULL && ircflp > 0)
1990               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
1991 
1992             cs_i_cd_steady_upwind(bldfrp,
1993                                   relaxp,
1994                                   diipf[face_id],
1995                                   djjpf[face_id],
1996                                   grad[ii],
1997                                   grad[jj],
1998                                   _pvar[ii],
1999                                   _pvar[jj],
2000                                   pvara[ii],
2001                                   pvara[jj],
2002                                   &pifri,
2003                                   &pifrj,
2004                                   &pjfri,
2005                                   &pjfrj,
2006                                   &pip,
2007                                   &pjp,
2008                                   &pipr,
2009                                   &pjpr);
2010 
2011             cs_i_conv_flux(iconvp,
2012                            1.,
2013                            1,
2014                            _pvar[ii],
2015                            _pvar[jj],
2016                            pifri,
2017                            pifrj,
2018                            pjfri,
2019                            pjfrj,
2020                            i_massflux[face_id],
2021                            1., /* xcpp */
2022                            1., /* xcpp */
2023                            fluxij);
2024 
2025             cs_i_diff_flux(idiffp,
2026                            1.,
2027                            pip,
2028                            pjp,
2029                            pipr,
2030                            pjpr,
2031                            i_visc[face_id],
2032                            fluxij);
2033 
2034             rhs[ii] -= fluxij[0];
2035             rhs[jj] += fluxij[1];
2036 
2037           }
2038         }
2039       }
2040 
2041     /* Unsteady */
2042     } else {
2043 
2044       for (int g_id = 0; g_id < n_i_groups; g_id++) {
2045 #       pragma omp parallel for reduction(+:n_upwind)
2046         for (int t_id = 0; t_id < n_i_threads; t_id++) {
2047           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2048                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2049                face_id++) {
2050 
2051             cs_lnum_t ii = i_face_cells[face_id][0];
2052             cs_lnum_t jj = i_face_cells[face_id][1];
2053 
2054             /* in parallel, face will be counted by one and only one rank */
2055             if (ii < n_cells) {
2056               n_upwind++;
2057             }
2058 
2059             cs_real_2_t fluxij = {0.,0.};
2060 
2061             cs_real_t pif, pjf;
2062             cs_real_t pip, pjp;
2063 
2064             cs_real_t bldfrp = (cs_real_t) ircflp;
2065             /* Local limitation of the reconstruction */
2066             if (df_limiter != NULL && ircflp > 0)
2067               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
2068 
2069             cs_i_cd_unsteady_upwind(bldfrp,
2070                                     diipf[face_id],
2071                                     djjpf[face_id],
2072                                     grad[ii],
2073                                     grad[jj],
2074                                     _pvar[ii],
2075                                     _pvar[jj],
2076                                     &pif,
2077                                     &pjf,
2078                                     &pip,
2079                                     &pjp);
2080 
2081             cs_i_conv_flux(iconvp,
2082                            thetap,
2083                            imasac,
2084                            _pvar[ii],
2085                            _pvar[jj],
2086                            pif,
2087                            pif, /* no relaxation */
2088                            pjf,
2089                            pjf, /* no relaxation */
2090                            i_massflux[face_id],
2091                            1., /* xcpp */
2092                            1., /* xcpp */
2093                            fluxij);
2094 
2095             cs_i_diff_flux(idiffp,
2096                            thetap,
2097                            pip,
2098                            pjp,
2099                            pip,/* no relaxation */
2100                            pjp,/* no relaxation */
2101                            i_visc[face_id],
2102                            fluxij);
2103 
2104             rhs[ii] -= fluxij[0];
2105             rhs[jj] += fluxij[1];
2106 
2107           }
2108         }
2109       }
2110 
2111     }
2112 
2113   /* --> Flux with no slope test or Min/Max Beta limiter
2114     ====================================================*/
2115 
2116   } else if (isstpp == 1 || isstpp == 2) {
2117 
2118     if (ischcp < 0 || ischcp > 4) {
2119       bft_error(__FILE__, __LINE__, 0,
2120                 _("invalid value of ischcv"));
2121     }
2122 
2123     /* Steady */
2124     if (idtvar < 0) {
2125 
2126       for (int g_id = 0; g_id < n_i_groups; g_id++) {
2127 #       pragma omp parallel for
2128         for (int t_id = 0; t_id < n_i_threads; t_id++) {
2129           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2130                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2131                face_id++) {
2132 
2133             cs_lnum_t ii = i_face_cells[face_id][0];
2134             cs_lnum_t jj = i_face_cells[face_id][1];
2135 
2136             cs_real_2_t fluxij = {0.,0.};
2137 
2138             cs_real_t pifri, pjfri, pifrj, pjfrj;
2139             cs_real_t pip, pjp, pipr, pjpr;
2140 
2141             cs_real_t bldfrp = (cs_real_t) ircflp;
2142             /* Local limitation of the reconstruction */
2143             if (df_limiter != NULL && ircflp > 0)
2144               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
2145 
2146             cs_i_cd_steady(bldfrp,
2147                            ischcp,
2148                            relaxp,
2149                            blencp,
2150                            weight[face_id],
2151                            cell_cen[ii],
2152                            cell_cen[jj],
2153                            i_face_cog[face_id],
2154                            diipf[face_id],
2155                            djjpf[face_id],
2156                            grad[ii],
2157                            grad[jj],
2158                            gradup[ii],
2159                            gradup[jj],
2160                            _pvar[ii],
2161                            _pvar[jj],
2162                            pvara[ii],
2163                            pvara[jj],
2164                            &pifri,
2165                            &pifrj,
2166                            &pjfri,
2167                            &pjfrj,
2168                            &pip,
2169                            &pjp,
2170                            &pipr,
2171                            &pjpr);
2172 
2173             cs_i_conv_flux(iconvp,
2174                            1.,
2175                            1,
2176                            _pvar[ii],
2177                            _pvar[jj],
2178                            pifri,
2179                            pifrj,
2180                            pjfri,
2181                            pjfrj,
2182                            i_massflux[face_id],
2183                            1., /* xcpp */
2184                            1., /* xcpp */
2185                            fluxij);
2186 
2187             cs_i_diff_flux(idiffp,
2188                            1.,
2189                            pip,
2190                            pjp,
2191                            pipr,
2192                            pjpr,
2193                            i_visc[face_id],
2194                            fluxij);
2195 
2196             rhs[ii] -= fluxij[0];
2197             rhs[jj] += fluxij[1];
2198 
2199           }
2200         }
2201       }
2202 
2203     /* Unsteady */
2204     } else {
2205 
2206       for (int g_id = 0; g_id < n_i_groups; g_id++) {
2207 #       pragma omp parallel for
2208         for (int t_id = 0; t_id < n_i_threads; t_id++) {
2209           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2210                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2211                face_id++) {
2212 
2213             cs_lnum_t ii = i_face_cells[face_id][0];
2214             cs_lnum_t jj = i_face_cells[face_id][1];
2215 
2216             cs_real_t beta = blencp;
2217 
2218             cs_real_t pif, pjf;
2219             cs_real_t pip, pjp;
2220 
2221             /* Beta blending coefficient ensuring positivity of the scalar */
2222             if (isstpp == 2) {
2223               beta = CS_MAX(CS_MIN(cv_limiter[ii], cv_limiter[jj]), 0.);
2224             }
2225 
2226             cs_real_2_t fluxij = {0.,0.};
2227 
2228             cs_real_t bldfrp = (cs_real_t) ircflp;
2229             /* Local limitation of the reconstruction */
2230             if (df_limiter != NULL && ircflp > 0)
2231               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
2232 
2233             if (ischcp != 4) {
2234               cs_real_t hybrid_coef_ii, hybrid_coef_jj;
2235               if (ischcp == 3) {
2236                 hybrid_coef_ii = CS_F_(hybrid_blend)->val[ii];
2237                 hybrid_coef_jj = CS_F_(hybrid_blend)->val[jj];
2238               } else {
2239                 hybrid_coef_ii = 0.;
2240                 hybrid_coef_jj = 0.;
2241               }
2242               cs_i_cd_unsteady(bldfrp,
2243                               ischcp,
2244                               beta,
2245                               weight[face_id],
2246                               cell_cen[ii],
2247                               cell_cen[jj],
2248                               i_face_cog[face_id],
2249                               hybrid_coef_ii,
2250                               hybrid_coef_jj,
2251                               diipf[face_id],
2252                               djjpf[face_id],
2253                               grad[ii],
2254                               grad[jj],
2255                               gradup[ii],
2256                               gradup[jj],
2257                               _pvar[ii],
2258                               _pvar[jj],
2259                               &pif,
2260                               &pjf,
2261                               &pip,
2262                               &pjp);
2263 
2264               cs_i_conv_flux(iconvp,
2265                              thetap,
2266                              imasac,
2267                              _pvar[ii],
2268                              _pvar[jj],
2269                              pif,
2270                              pif, /* no relaxation */
2271                              pjf,
2272                              pjf, /* no relaxation */
2273                              i_massflux[face_id],
2274                              1., /* xcpp */
2275                              1., /* xcpp */
2276                              fluxij);
2277 
2278             } else {
2279               /* NVD/TVD family of high accuracy schemes */
2280 
2281               cs_lnum_t ic, id;
2282 
2283               /* Determine central and downwind sides w.r.t. current face */
2284               cs_central_downwind_cells(ii,
2285                                         jj,
2286                                         i_massflux[face_id],
2287                                         &ic,  /* central cell id */
2288                                         &id); /* downwind cell id */
2289 
2290               cs_real_t courant_c = -1.;
2291               if (courant != NULL)
2292                 courant_c = courant[ic];
2293 
2294               cs_i_cd_unsteady_nvd(limiter_choice,
2295                                    beta,
2296                                    cell_cen[ic],
2297                                    cell_cen[id],
2298                                    i_face_normal[face_id],
2299                                    i_face_cog[face_id],
2300                                    grad[ic],
2301                                    _pvar[ic],
2302                                    _pvar[id],
2303                                    local_max[ic],
2304                                    local_min[ic],
2305                                    courant_c,
2306                                    &pif,
2307                                    &pjf);
2308 
2309               cs_i_conv_flux(iconvp,
2310                              thetap,
2311                              imasac,
2312                              _pvar[ii],
2313                              _pvar[jj],
2314                              pif,
2315                              pif, /* no relaxation */
2316                              pjf,
2317                              pjf, /* no relaxation */
2318                              i_massflux[face_id],
2319                              1., /* xcpp */
2320                              1., /* xcpp */
2321                              fluxij);
2322 
2323               /* Compute required quantities for diffusive flux */
2324               cs_real_t recoi, recoj;
2325 
2326               cs_i_compute_quantities(bldfrp,
2327                                       diipf[face_id],
2328                                       djjpf[face_id],
2329                                       grad[ii],
2330                                       grad[jj],
2331                                       _pvar[ii],
2332                                       _pvar[jj],
2333                                       &recoi,
2334                                       &recoj,
2335                                       &pip,
2336                                       &pjp);
2337             }
2338 
2339             cs_i_diff_flux(idiffp,
2340                            thetap,
2341                            pip,
2342                            pjp,
2343                            pip, /* no relaxation */
2344                            pjp, /* no relaxation */
2345                            i_visc[face_id],
2346                            fluxij);
2347 
2348             rhs[ii] -= fluxij[0];
2349             rhs[jj] += fluxij[1];
2350 
2351           }
2352         }
2353       }
2354 
2355     }
2356 
2357   /* --> Flux with slope test
2358     ============================================*/
2359 
2360   } else { /* isstpp = 0 */
2361 
2362     if (ischcp < 0 || ischcp > 2) {
2363       bft_error(__FILE__, __LINE__, 0,
2364                 _("invalid value of ischcv"));
2365     }
2366 
2367     /* Steady */
2368     if (idtvar < 0) {
2369 
2370       for (int g_id = 0; g_id < n_i_groups; g_id++) {
2371 #       pragma omp parallel for reduction(+:n_upwind)
2372         for (int t_id = 0; t_id < n_i_threads; t_id++) {
2373           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2374                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2375                face_id++) {
2376 
2377             cs_lnum_t ii = i_face_cells[face_id][0];
2378             cs_lnum_t jj = i_face_cells[face_id][1];
2379 
2380             cs_real_2_t fluxij = {0., 0.};
2381 
2382             bool upwind_switch = false;
2383             cs_real_t pifri, pjfri, pifrj, pjfrj;
2384             cs_real_t pip, pjp, pipr, pjpr;
2385 
2386             cs_real_t bldfrp = (cs_real_t) ircflp;
2387             /* Local limitation of the reconstruction */
2388             if (df_limiter != NULL && ircflp > 0)
2389               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
2390 
2391             cs_i_cd_steady_slope_test(&upwind_switch,
2392                                       iconvp,
2393                                       bldfrp,
2394                                       ischcp,
2395                                       relaxp,
2396                                       blencp,
2397                                       blend_st,
2398                                       weight[face_id],
2399                                       i_dist[face_id],
2400                                       i_face_surf[face_id],
2401                                       cell_cen[ii],
2402                                       cell_cen[jj],
2403                                       i_face_normal[face_id],
2404                                       i_face_cog[face_id],
2405                                       diipf[face_id],
2406                                       djjpf[face_id],
2407                                       i_massflux[face_id],
2408                                       grad[ii],
2409                                       grad[jj],
2410                                       gradup[ii],
2411                                       gradup[jj],
2412                                       gradst[ii],
2413                                       gradst[jj],
2414                                       _pvar[ii],
2415                                       _pvar[jj],
2416                                       pvara[ii],
2417                                       pvara[jj],
2418                                       &pifri,
2419                                       &pifrj,
2420                                       &pjfri,
2421                                       &pjfrj,
2422                                       &pip,
2423                                       &pjp,
2424                                       &pipr,
2425                                       &pjpr);
2426 
2427             cs_i_conv_flux(iconvp,
2428                            1.,
2429                            1,
2430                            _pvar[ii],
2431                            _pvar[jj],
2432                            pifri,
2433                            pifrj,
2434                            pjfri,
2435                            pjfrj,
2436                            i_massflux[face_id],
2437                            1., /* xcpp */
2438                            1., /* xcpp */
2439                            fluxij);
2440 
2441             cs_i_diff_flux(idiffp,
2442                            1.,
2443                            pip,
2444                            pjp,
2445                            pipr,
2446                            pjpr,
2447                            i_visc[face_id],
2448                            fluxij);
2449 
2450             if (upwind_switch) {
2451 
2452               /* in parallel, face will be counted by one and only one rank */
2453               if (ii < n_cells)
2454                 n_upwind++;
2455               if (v_slope_test != NULL) {
2456                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
2457                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
2458               }
2459 
2460             }
2461 
2462             rhs[ii] -= fluxij[0];
2463             rhs[jj] += fluxij[1];
2464 
2465           }
2466         }
2467       }
2468 
2469     /* Unsteady */
2470     } else {
2471 
2472       for (int g_id = 0; g_id < n_i_groups; g_id++) {
2473 #       pragma omp parallel for reduction(+:n_upwind)
2474         for (int t_id = 0; t_id < n_i_threads; t_id++) {
2475           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2476                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2477                face_id++) {
2478 
2479             cs_lnum_t ii = i_face_cells[face_id][0];
2480             cs_lnum_t jj = i_face_cells[face_id][1];
2481 
2482             bool upwind_switch = false;
2483 
2484             cs_real_2_t fluxij = {0.,0.};
2485 
2486             cs_real_t pif, pjf;
2487             cs_real_t pip, pjp;
2488 
2489             cs_real_t bldfrp = (cs_real_t) ircflp;
2490             /* Local limitation of the reconstruction */
2491             if (df_limiter != NULL && ircflp > 0)
2492               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
2493 
2494             cs_i_cd_unsteady_slope_test(&upwind_switch,
2495                                         iconvp,
2496                                         bldfrp,
2497                                         ischcp,
2498                                         blencp,
2499                                         blend_st,
2500                                         weight[face_id],
2501                                         i_dist[face_id],
2502                                         i_face_surf[face_id],
2503                                         cell_cen[ii],
2504                                         cell_cen[jj],
2505                                         i_face_normal[face_id],
2506                                         i_face_cog[face_id],
2507                                         diipf[face_id],
2508                                         djjpf[face_id],
2509                                         i_massflux[face_id],
2510                                         grad[ii],
2511                                         grad[jj],
2512                                         gradup[ii],
2513                                         gradup[jj],
2514                                         gradst[ii],
2515                                         gradst[jj],
2516                                         _pvar[ii],
2517                                         _pvar[jj],
2518                                         &pif,
2519                                         &pjf,
2520                                         &pip,
2521                                         &pjp);
2522 
2523             cs_i_conv_flux(iconvp,
2524                            thetap,
2525                            imasac,
2526                            _pvar[ii],
2527                            _pvar[jj],
2528                            pif,
2529                            pif, /* no relaxation */
2530                            pjf,
2531                            pjf, /* no relaxation */
2532                            i_massflux[face_id],
2533                            1., /* xcpp */
2534                            1., /* xcpp */
2535                            fluxij);
2536 
2537             cs_i_diff_flux(idiffp,
2538                            thetap,
2539                            pip,
2540                            pjp,
2541                            pip, /* no relaxation */
2542                            pjp, /* no relaxation */
2543                            i_visc[face_id],
2544                            fluxij);
2545 
2546             if (upwind_switch) {
2547               /* in parallel, face will be counted by one and only one rank */
2548               if (ii < n_cells)
2549                 n_upwind++;
2550 
2551               if (v_slope_test != NULL) {
2552                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
2553                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
2554               }
2555             }
2556 
2557             rhs[ii] -= fluxij[0];
2558             rhs[jj] += fluxij[1];
2559 
2560           }
2561         }
2562       }
2563 
2564     } /* idtvar */
2565 
2566   } /* iupwin */
2567 
2568 
2569   if (iwarnp >= 2 && iconvp == 1) {
2570 
2571     /* Sum number of clippings */
2572     cs_parall_counter(&n_upwind, 1);
2573 
2574     bft_printf(_(" %s: %llu Faces with upwind on %llu interior faces\n"),
2575                var_name, (unsigned long long)n_upwind,
2576                (unsigned long long)m->n_g_i_c_faces);
2577   }
2578 
2579   /* ======================================================================
2580     ---> Contribution from boundary faces
2581     ======================================================================*/
2582 
2583   /* Boundary convective flux are all computed with an upwind scheme */
2584   if (icvflb == 0) {
2585 
2586     /* Steady */
2587     if (idtvar < 0) {
2588 
2589       for (int g_id = 0; g_id < n_b_groups; g_id++) {
2590 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
2591         for (int t_id = 0; t_id < n_b_threads; t_id++) {
2592           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2593                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2594                face_id++) {
2595 
2596             cs_lnum_t ii = b_face_cells[face_id];
2597 
2598             cs_real_t fluxi = 0.;
2599             cs_real_t pir, pipr;
2600 
2601             cs_real_t bldfrp = (cs_real_t) ircflp;
2602             /* Local limitation of the reconstruction */
2603             if (df_limiter != NULL && ircflp > 0)
2604               bldfrp = CS_MAX(df_limiter[ii], 0.);
2605 
2606             cs_b_cd_steady(bldfrp,
2607                            relaxp,
2608                            diipb[face_id],
2609                            grad[ii],
2610                            _pvar[ii],
2611                            pvara[ii],
2612                            &pir,
2613                            &pipr);
2614 
2615             cs_b_upwind_flux(iconvp,
2616                              1.,
2617                              1,
2618                              inc,
2619                              bc_type[face_id],
2620                              _pvar[ii],
2621                              pir,
2622                              pipr,
2623                              coefap[face_id],
2624                              coefbp[face_id],
2625                              b_massflux[face_id],
2626                              1., /* xcpp */
2627                              &fluxi);
2628 
2629             cs_b_diff_flux(idiffp,
2630                            1., /* thetap */
2631                            inc,
2632                            pipr,
2633                            cofafp[face_id],
2634                            cofbfp[face_id],
2635                            b_visc[face_id],
2636                            &fluxi);
2637 
2638             rhs[ii] -= fluxi;
2639 
2640           }
2641         }
2642       }
2643 
2644       /* The scalar is internal_coupled and an implicit contribution
2645        * is required */
2646       if (icoupl > 0) {
2647         /* Prepare data for sending */
2648         BFT_MALLOC(pvar_distant, n_distant, cs_real_t);
2649 
2650         for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
2651           cs_lnum_t face_id = faces_distant[ii];
2652           cs_lnum_t jj = b_face_cells[face_id];
2653           cs_real_t pip, pipr;
2654 
2655           cs_real_t bldfrp = (cs_real_t) ircflp;
2656           /* Local limitation of the reconstruction */
2657           if (df_limiter != NULL && ircflp > 0)
2658             bldfrp = CS_MAX(df_limiter[jj], 0.);
2659 
2660           cs_b_cd_steady(bldfrp,
2661                          relaxp,
2662                          diipb[face_id],
2663                          grad[jj],
2664                          _pvar[jj],
2665                          pvara[jj],
2666                          &pip,
2667                          &pipr);
2668           pvar_distant[ii] = pipr;
2669         }
2670 
2671         /* Receive data */
2672         BFT_MALLOC(pvar_local, n_local, cs_real_t);
2673         cs_internal_coupling_exchange_var(cpl,
2674                                           1, /* Dimension */
2675                                           pvar_distant,
2676                                           pvar_local);
2677 
2678         /* Exchange diffusion limiter */
2679         if (df_limiter != NULL) {
2680           BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
2681           cs_internal_coupling_exchange_var(cpl,
2682                                             1, /* Dimension */
2683                                             df_limiter,
2684                                             df_limiter_local);
2685         }
2686 
2687         /* Flux contribution */
2688         assert(f != NULL);
2689         cs_real_t *hintp = f->bc_coeffs->hint;
2690         cs_real_t *hextp = f->bc_coeffs->hext;
2691         for (cs_lnum_t ii = 0; ii < n_local; ii++) {
2692           cs_lnum_t face_id = faces_local[ii];
2693           cs_lnum_t jj = b_face_cells[face_id];
2694           cs_real_t pip, pipr, pjpr;
2695           cs_real_t fluxi = 0.;
2696 
2697           cs_real_t bldfrp = (cs_real_t) ircflp;
2698           /* Local limitation of the reconstruction */
2699           if (df_limiter != NULL && ircflp > 0)
2700             bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
2701 
2702           cs_b_cd_steady(bldfrp,
2703                          relaxp,
2704                          diipb[face_id],
2705                          grad[jj],
2706                          _pvar[jj],
2707                          pvara[jj],
2708                          &pip,
2709                          &pipr);
2710 
2711           pjpr = pvar_local[ii];
2712 
2713           cs_real_t hint = hintp[face_id];
2714           cs_real_t hext = hextp[face_id];
2715           cs_real_t heq = _calc_heq(hint, hext);
2716 
2717           cs_b_diff_flux_coupling(idiffp,
2718                                   pipr,
2719                                   pjpr,
2720                                   heq,
2721                                   &fluxi);
2722 
2723           rhs[jj] -= thetap * fluxi;
2724         }
2725 
2726         BFT_FREE(pvar_local);
2727         /* Sending structures are no longer needed */
2728         BFT_FREE(pvar_distant);
2729         if (df_limiter != NULL)
2730           BFT_FREE(df_limiter_local);
2731       }
2732 
2733     /* Unsteady */
2734     } else {
2735 
2736       for (int g_id = 0; g_id < n_b_groups; g_id++) {
2737 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
2738         for (int t_id = 0; t_id < n_b_threads; t_id++) {
2739           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2740                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2741                face_id++) {
2742 
2743             cs_lnum_t ii = b_face_cells[face_id];
2744 
2745             cs_real_t fluxi = 0.;
2746             cs_real_t pip;
2747 
2748             cs_real_t bldfrp = (cs_real_t) ircflp;
2749             /* Local limitation of the reconstruction */
2750             if (df_limiter != NULL && ircflp > 0)
2751               bldfrp = CS_MAX(df_limiter[ii], 0.);
2752 
2753             cs_b_cd_unsteady(bldfrp,
2754                              diipb[face_id],
2755                              grad[ii],
2756                              _pvar[ii],
2757                              &pip);
2758 
2759             cs_b_upwind_flux(iconvp,
2760                              thetap,
2761                              imasac,
2762                              inc,
2763                              bc_type[face_id],
2764                              _pvar[ii],
2765                              _pvar[ii], /* no relaxation */
2766                              pip,
2767                              coefap[face_id],
2768                              coefbp[face_id],
2769                              b_massflux[face_id],
2770                              1., /* xcpp */
2771                              &fluxi);
2772 
2773             cs_b_diff_flux(idiffp,
2774                            thetap,
2775                            inc,
2776                            pip,
2777                            cofafp[face_id],
2778                            cofbfp[face_id],
2779                            b_visc[face_id],
2780                            &fluxi);
2781 
2782             rhs[ii] -= fluxi;
2783 
2784           }
2785         }
2786       }
2787 
2788       /* The scalar is internally coupled and an implicit contribution
2789        * is required */
2790       if (icoupl > 0) {
2791         /* Prepare data for sending */
2792         BFT_MALLOC(pvar_distant, n_distant, cs_real_t);
2793 
2794         for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
2795           cs_lnum_t face_id = faces_distant[ii];
2796           cs_lnum_t jj = b_face_cells[face_id];
2797           cs_real_t pip;
2798 
2799           cs_real_t bldfrp = (cs_real_t) ircflp;
2800           /* Local limitation of the reconstruction */
2801           if (df_limiter != NULL && ircflp > 0)
2802             bldfrp = CS_MAX(df_limiter[jj], 0.);
2803 
2804           cs_b_cd_unsteady(bldfrp,
2805                            diipb[face_id],
2806                            grad[jj],
2807                            _pvar[jj],
2808                            &pip);
2809           pvar_distant[ii] = pip;
2810         }
2811 
2812         /* Receive data */
2813         BFT_MALLOC(pvar_local, n_local, cs_real_t);
2814         cs_internal_coupling_exchange_var(cpl,
2815                                           1, /* Dimension */
2816                                           pvar_distant,
2817                                           pvar_local);
2818 
2819         /* Exchange diffusion limiter */
2820         if (df_limiter != NULL) {
2821           BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
2822           cs_internal_coupling_exchange_var(cpl,
2823                                             1, /* Dimension */
2824                                             df_limiter,
2825                                             df_limiter_local);
2826         }
2827 
2828         /* Flux contribution */
2829         assert(f != NULL);
2830         cs_real_t *hintp = f->bc_coeffs->hint;
2831         cs_real_t *hextp = f->bc_coeffs->hext;
2832         for (cs_lnum_t ii = 0; ii < n_local; ii++) {
2833           cs_lnum_t face_id = faces_local[ii];
2834           cs_lnum_t jj = b_face_cells[face_id];
2835           cs_real_t pip, pjp;
2836           cs_real_t fluxi = 0.;
2837 
2838           cs_real_t bldfrp = (cs_real_t) ircflp;
2839           /* Local limitation of the reconstruction */
2840           if (df_limiter != NULL && ircflp > 0)
2841             bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
2842 
2843           cs_b_cd_unsteady(bldfrp,
2844                            diipb[face_id],
2845                            grad[jj],
2846                            _pvar[jj],
2847                            &pip);
2848 
2849           pjp = pvar_local[ii];
2850 
2851           cs_real_t hint = hintp[face_id];
2852           cs_real_t hext = hextp[face_id];
2853           cs_real_t heq = _calc_heq(hint, hext);
2854 
2855           cs_b_diff_flux_coupling(idiffp,
2856                                   pip,
2857                                   pjp,
2858                                   heq,
2859                                   &fluxi);
2860 
2861           rhs[jj] -= thetap * fluxi;
2862         }
2863 
2864         BFT_FREE(pvar_local);
2865         /* Sending structures are no longer needed */
2866         BFT_FREE(pvar_distant);
2867         if (df_limiter != NULL)
2868           BFT_FREE(df_limiter_local);
2869       }
2870     }
2871 
2872   /* Boundary convective flux is imposed at some faces
2873      (tagged in icvfli array) */
2874   } else if (icvflb == 1) {
2875 
2876     /* Retrieve the value of the convective flux to be imposed */
2877     if (f_id != -1) {
2878       coface = f->bc_coeffs->ac;
2879       cofbce = f->bc_coeffs->bc;
2880     } else {
2881       bft_error(__FILE__, __LINE__, 0,
2882                 _("invalid value of icvflb and f_id"));
2883     }
2884 
2885     /* Steady */
2886     if (idtvar < 0) {
2887 
2888       for (int g_id = 0; g_id < n_b_groups; g_id++) {
2889 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
2890         for (int t_id = 0; t_id < n_b_threads; t_id++) {
2891           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2892                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2893                face_id++) {
2894 
2895             cs_lnum_t ii = b_face_cells[face_id];
2896 
2897             cs_real_t fluxi = 0.;
2898             cs_real_t pir, pipr;
2899 
2900             cs_real_t bldfrp = (cs_real_t) ircflp;
2901             /* Local limitation of the reconstruction */
2902             if (df_limiter != NULL && ircflp > 0)
2903               bldfrp = CS_MAX(df_limiter[ii], 0.);
2904 
2905             cs_b_cd_steady(bldfrp,
2906                            relaxp,
2907                            diipb[face_id],
2908                            grad[ii],
2909                            _pvar[ii],
2910                            pvara[ii],
2911                            &pir,
2912                            &pipr);
2913 
2914             cs_b_imposed_conv_flux(iconvp,
2915                                    1.,
2916                                    1,
2917                                    inc,
2918                                    bc_type[face_id],
2919                                    icvfli[face_id],
2920                                    _pvar[ii],
2921                                    pir,
2922                                    pipr,
2923                                    coefap[face_id],
2924                                    coefbp[face_id],
2925                                    coface[face_id],
2926                                    cofbce[face_id],
2927                                    b_massflux[face_id],
2928                                    1., /* xcpp */
2929                                    &fluxi);
2930 
2931             cs_b_diff_flux(idiffp,
2932                            1., /* thetap */
2933                            inc,
2934                            pipr,
2935                            cofafp[face_id],
2936                            cofbfp[face_id],
2937                            b_visc[face_id],
2938                            &fluxi);
2939 
2940             rhs[ii] -= fluxi;
2941 
2942           }
2943         }
2944       }
2945 
2946     /* Unsteady */
2947     } else {
2948 
2949       for (int g_id = 0; g_id < n_b_groups; g_id++) {
2950 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
2951         for (int t_id = 0; t_id < n_b_threads; t_id++) {
2952           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2953                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2954                face_id++) {
2955 
2956             cs_lnum_t ii = b_face_cells[face_id];
2957 
2958             cs_real_t fluxi = 0.;
2959             cs_real_t pip;
2960 
2961             cs_real_t bldfrp = (cs_real_t) ircflp;
2962             /* Local limitation of the reconstruction */
2963             if (df_limiter != NULL && ircflp > 0)
2964               bldfrp = CS_MAX(df_limiter[ii], 0.);
2965 
2966             cs_b_cd_unsteady(bldfrp,
2967                              diipb[face_id],
2968                              grad[ii],
2969                              _pvar[ii],
2970                              &pip);
2971 
2972             cs_b_imposed_conv_flux(iconvp,
2973                                    thetap,
2974                                    imasac,
2975                                    inc,
2976                                    bc_type[face_id],
2977                                    icvfli[face_id],
2978                                    _pvar[ii],
2979                                    _pvar[ii], /* no relaxation */
2980                                    pip,
2981                                    coefap[face_id],
2982                                    coefbp[face_id],
2983                                    coface[face_id],
2984                                    cofbce[face_id],
2985                                    b_massflux[face_id],
2986                                    1., /* xcpp */
2987                                    &fluxi);
2988 
2989             cs_b_diff_flux(idiffp,
2990                            thetap,
2991                            inc,
2992                            pip,
2993                            cofafp[face_id],
2994                            cofbfp[face_id],
2995                            b_visc[face_id],
2996                            &fluxi);
2997 
2998             rhs[ii] -= fluxi;
2999 
3000           }
3001         }
3002       }
3003 
3004     }
3005   }
3006 
3007   /* Free memory */
3008   BFT_FREE(grad);
3009   BFT_FREE(gradup);
3010   BFT_FREE(gradst);
3011   BFT_FREE(local_max);
3012   BFT_FREE(local_min);
3013   BFT_FREE(courant);
3014 }
3015 
3016 /*----------------------------------------------------------------------------*/
3017 /*!
3018  * <a name="cs_face_convection_scalar"></a>
3019  *
3020  * \brief Update face flux with convection contribution of a standard transport
3021  * equation of a scalar field \f$ \varia \f$.
3022  *
3023  * \f[
3024  * C_\ij = \dot{m}_\ij \left( \varia_\fij - \varia_\celli \right)
3025  * \f]
3026  *
3027  * \param[in]     idtvar        indicator of the temporal scheme
3028  * \param[in]     f_id          field id (or -1)
3029  * \param[in]     var_cal_opt   variable calculation options
3030  * \param[in]     icvflb        global indicator of boundary convection flux
3031  *                               - 0 upwind scheme at all boundary faces
3032  *                               - 1 imposed flux at some boundary faces
3033  * \param[in]     inc           indicator
3034  *                               - 0 when solving an increment
3035  *                               - 1 otherwise
3036  * \param[in]     iccocg        indicator
3037  *                               - 1 re-compute cocg matrix
3038  *                                   (for iterative gradients)
3039  *                               - 0 otherwise
3040  * \param[in]     imasac        take mass accumulation into account?
3041  * \param[in]     pvar          solved variable (current time step)
3042  * \param[in]     pvara         solved variable (previous time step)
3043  * \param[in]     icvfli        boundary face indicator array of convection flux
3044  *                               - 0 upwind scheme
3045  *                               - 1 imposed flux
3046  * \param[in]     coefap        boundary condition array for the variable
3047  *                               (explicit part)
3048  * \param[in]     coefbp        boundary condition array for the variable
3049  *                               (implicit part)
3050  * \param[in]     i_massflux    mass flux at interior faces
3051  * \param[in]     b_massflux    mass flux at boundary faces
3052  * \param[in,out] i_conv_flux   scalar convection flux at interior faces
3053  * \param[in,out] b_conv_flux   scalar convection flux at boundary faces
3054  */
3055 /*----------------------------------------------------------------------------*/
3056 
3057 void
cs_face_convection_scalar(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int icvflb,int inc,int iccocg,int imasac,cs_real_t * restrict pvar,const cs_real_t * restrict pvara,const int icvfli[],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],cs_real_2_t i_conv_flux[],cs_real_t b_conv_flux[])3058 cs_face_convection_scalar(int                       idtvar,
3059                           int                       f_id,
3060                           const cs_var_cal_opt_t    var_cal_opt,
3061                           int                       icvflb,
3062                           int                       inc,
3063                           int                       iccocg,
3064                           int                       imasac,
3065                           cs_real_t       *restrict pvar,
3066                           const cs_real_t *restrict pvara,
3067                           const int                 icvfli[],
3068                           const cs_real_t           coefap[],
3069                           const cs_real_t           coefbp[],
3070                           const cs_real_t           i_massflux[],
3071                           const cs_real_t           b_massflux[],
3072                           cs_real_2_t               i_conv_flux[],
3073                           cs_real_t                 b_conv_flux[])
3074 {
3075   const int iconvp = var_cal_opt.iconv;
3076   const int nswrgp = var_cal_opt.nswrgr;
3077   const int imrgra = var_cal_opt.imrgra;
3078   const int imligp = var_cal_opt.imligr;
3079   const int ircflp = var_cal_opt.ircflu;
3080   const int ischcp = var_cal_opt.ischcv;
3081   const int isstpp = var_cal_opt.isstpc;
3082   const int iwarnp = var_cal_opt.verbosity;
3083   const int icoupl = var_cal_opt.icoupl;
3084   int limiter_choice = -1;
3085   const double blencp = var_cal_opt.blencv;
3086   const double blend_st = var_cal_opt.blend_st;
3087   const double epsrgp = var_cal_opt.epsrgr;
3088   const double climgp = var_cal_opt.climgr;
3089   const double relaxp = var_cal_opt.relaxv;
3090   const double thetap = var_cal_opt.thetav;
3091 
3092   const cs_mesh_t  *m = cs_glob_mesh;
3093   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
3094 
3095   const cs_lnum_t n_cells = m->n_cells;
3096   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
3097   const int n_i_groups = m->i_face_numbering->n_groups;
3098   const int n_i_threads = m->i_face_numbering->n_threads;
3099   const int n_b_groups = m->b_face_numbering->n_groups;
3100   const int n_b_threads = m->b_face_numbering->n_threads;
3101   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
3102   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
3103 
3104   const cs_lnum_2_t *restrict i_face_cells
3105     = (const cs_lnum_2_t *restrict)m->i_face_cells;
3106   const cs_lnum_t *restrict b_face_cells
3107     = (const cs_lnum_t *restrict)m->b_face_cells;
3108   const cs_real_t *restrict weight = fvq->weight;
3109   const cs_real_t *restrict i_dist = fvq->i_dist;
3110   const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
3111   const cs_real_t *restrict cell_vol = fvq->cell_vol;
3112   const cs_real_3_t *restrict cell_cen
3113     = (const cs_real_3_t *restrict)fvq->cell_cen;
3114   const cs_real_3_t *restrict i_face_normal
3115     = (const cs_real_3_t *restrict)fvq->i_face_normal;
3116   const cs_real_3_t *restrict i_face_cog
3117     = (const cs_real_3_t *restrict)fvq->i_face_cog;
3118   const cs_real_3_t *restrict diipf
3119     = (const cs_real_3_t *restrict)fvq->diipf;
3120   const cs_real_3_t *restrict djjpf
3121     = (const cs_real_3_t *restrict)fvq->djjpf;
3122   const cs_real_3_t *restrict diipb
3123     = (const cs_real_3_t *restrict)fvq->diipb;
3124 
3125   const int *bc_type = cs_glob_bc_type;
3126 
3127   /* Local variables */
3128 
3129   char var_name[64];
3130 
3131   int iupwin = 0;
3132   int w_stride = 1;
3133 
3134   bool recompute_cocg = (iccocg) ? true : false;
3135 
3136   cs_real_t *coface = NULL, *cofbce = NULL;
3137 
3138   cs_real_3_t *grad;
3139   cs_real_3_t *gradup = NULL;
3140   cs_real_3_t *gradst = NULL;
3141   cs_field_t *f = NULL;
3142 
3143   cs_real_t *local_min = NULL;
3144   cs_real_t *local_max = NULL;
3145   cs_real_t *courant = NULL;
3146 
3147   cs_real_t *cv_limiter = NULL;
3148   cs_real_t *df_limiter = NULL;
3149 
3150   cs_real_t *gweight = NULL;
3151 
3152   const int key_lim_choice = cs_field_key_id("limiter_choice");
3153 
3154   cs_real_t  *v_slope_test = cs_get_v_slope_test(f_id,  var_cal_opt);
3155 
3156   /* Internal coupling variables */
3157   int coupling_id;
3158   cs_internal_coupling_t *cpl = NULL;
3159 
3160   /* Initialization */
3161 
3162   /* Allocate work arrays */
3163 
3164   BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
3165 
3166   /* Choose gradient type */
3167 
3168   cs_halo_type_t halo_type = CS_HALO_STANDARD;
3169   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
3170 
3171   cs_gradient_type_by_imrgra(imrgra,
3172                              &gradient_type,
3173                              &halo_type);
3174 
3175   /* Handle cases where only the previous values (already synchronized)
3176      or current values are provided */
3177 
3178   if (pvar != NULL)
3179     cs_sync_scalar_halo(m, pvar);
3180   if (pvara == NULL)
3181     pvara = (const cs_real_t *restrict)pvar;
3182 
3183   const cs_real_t  *restrict _pvar = (pvar != NULL) ? pvar : pvara;
3184 
3185   /* Slope limiters */
3186 
3187   if (f_id != -1) {
3188     f = cs_field_by_id(f_id);
3189 
3190     /* NVD/TVD limiters */
3191     if (ischcp == 4) {
3192       limiter_choice = cs_field_get_key_int(f, key_lim_choice);
3193       BFT_MALLOC(local_max, n_cells_ext, cs_real_t);
3194       BFT_MALLOC(local_min, n_cells_ext, cs_real_t);
3195       cs_field_local_extrema_scalar(f_id,
3196                                     halo_type,
3197                                     local_max,
3198                                     local_min);
3199       if (limiter_choice >= CS_NVD_VOF_HRIC) {
3200         BFT_MALLOC(courant, n_cells_ext, cs_real_t);
3201         cs_cell_courant_number(f_id, courant);
3202       }
3203     }
3204 
3205     int cv_limiter_id =
3206       cs_field_get_key_int(f, cs_field_key_id("convection_limiter_id"));
3207     if (cv_limiter_id > -1)
3208       cv_limiter = cs_field_by_id(cv_limiter_id)->val;
3209 
3210     int df_limiter_id =
3211       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
3212     if (df_limiter_id > -1)
3213       df_limiter = cs_field_by_id(df_limiter_id)->val;
3214 
3215     snprintf(var_name, 63, "%s", f->name);
3216   }
3217   else if (isstpp > 1) {
3218     bft_error(__FILE__, __LINE__, 0,
3219               _("invalid value of isstpp for a work array"));
3220   } else {
3221     strncpy(var_name, "[scalar face flux from convection]", 63);
3222   }
3223   var_name[63] = '\0';
3224 
3225   if (iwarnp >= 2) {
3226     if (ischcp == 1) {
3227       bft_printf(
3228         _(" %s: Convection in centered blending with %f percent of upwind\n"),
3229         var_name, (1.-blencp)*100.);
3230     } else {
3231       bft_printf(
3232         _(" %s: Convection in 2nd order blending with %f percent of upwind\n"),
3233         var_name, (1.-blencp)*100.);
3234     }
3235   }
3236 
3237   iupwin = (blencp > 0.) ? 0 : 1;
3238 
3239   if (icoupl > 0) {
3240     assert(f_id != -1);
3241     const int coupling_key_id = cs_field_key_id("coupling_entity");
3242     coupling_id = cs_field_get_key_int(f, coupling_key_id);
3243     cpl = cs_internal_coupling_by_id(coupling_id);
3244   }
3245 
3246   /* Compute the balance with reconstruction */
3247 
3248   /* Compute the gradient of the variable */
3249 
3250   /* The gradient (grad) is used in the flux reconstruction and the slope test.
3251      Thus we must compute it:
3252          - when the convection scheme is the legacy SOLU,
3253          - when we have convection, we are not in pure upwind
3254            and we reconstruct the fluxes,
3255          - when we have convection, we are not in pure upwind
3256            and we have not shunted the slope test,
3257          - when we use NVD / TVD schemes.
3258   */
3259 
3260   if (   iconvp != 0 && iupwin == 0
3261       && (ischcp == 0 || ircflp == 1 || isstpp == 0 || ischcp == 4)) {
3262 
3263     if (f_id != -1) {
3264       /* Get the calculation option from the field */
3265       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
3266         if (var_cal_opt.idiff > 0) {
3267           int key_id = cs_field_key_id("gradient_weighting_id");
3268           int diff_id = cs_field_get_key_int(f, key_id);
3269           if (diff_id > -1) {
3270             cs_field_t *weight_f = cs_field_by_id(diff_id);
3271             gweight = weight_f->val;
3272             w_stride = weight_f->dim;
3273             cs_field_synchronize(weight_f, halo_type);
3274           }
3275         }
3276       }
3277     }
3278 
3279     cs_gradient_scalar_synced_input(var_name,
3280                                     gradient_type,
3281                                     halo_type,
3282                                     inc,
3283                                     recompute_cocg,
3284                                     nswrgp,
3285                                     0, /* hyd_p_flag */
3286                                     w_stride,
3287                                     iwarnp,
3288                                     imligp,
3289                                     epsrgp,
3290                                     climgp,
3291                                     NULL, /* f_ext exterior force */
3292                                     coefap,
3293                                     coefbp,
3294                                     _pvar,
3295                                     gweight, /* Weighted gradient */
3296                                     cpl,
3297                                     grad);
3298 
3299   } else {
3300 
3301 #   pragma omp parallel for
3302     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
3303       grad[cell_id][0] = 0.;
3304       grad[cell_id][1] = 0.;
3305       grad[cell_id][2] = 0.;
3306     }
3307   }
3308 
3309   /* Compute gradients used in convection schemes */
3310 
3311   if (iconvp > 0 && iupwin == 0) {
3312 
3313     /* Compute cell gradient used in slope test */
3314     if (isstpp == 0) {
3315 
3316       BFT_MALLOC(gradst, n_cells_ext, cs_real_3_t);
3317 
3318 #     pragma omp parallel for
3319       for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
3320         gradst[cell_id][0] = 0.;
3321         gradst[cell_id][1] = 0.;
3322         gradst[cell_id][2] = 0.;
3323       }
3324 
3325       cs_slope_test_gradient(f_id,
3326                              inc,
3327                              halo_type,
3328                              (const cs_real_3_t *)grad,
3329                              gradst,
3330                              _pvar,
3331                              coefap,
3332                              coefbp,
3333                              i_massflux);
3334 
3335     }
3336 
3337     /* Pure SOLU scheme */
3338     if (ischcp == 2) {
3339 
3340       BFT_MALLOC(gradup, n_cells_ext, cs_real_3_t);
3341 
3342 #     pragma omp parallel for
3343       for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
3344         gradup[cell_id][0] = 0.;
3345         gradup[cell_id][1] = 0.;
3346         gradup[cell_id][2] = 0.;
3347       }
3348 
3349       cs_upwind_gradient(f_id,
3350                          inc,
3351                          halo_type,
3352                          coefap,
3353                          coefbp,
3354                          i_massflux,
3355                          b_massflux,
3356                          _pvar,
3357                          gradup);
3358 
3359     }
3360 
3361   }
3362 
3363   /* ======================================================================
3364     ---> Contribution from interior faces
3365     ======================================================================*/
3366 
3367   cs_gnum_t n_upwind = 0;
3368 
3369   /* --> Pure upwind flux
3370     =====================*/
3371 
3372   if (iupwin == 1) {
3373 
3374     /* Steady */
3375     if (idtvar < 0) {
3376 
3377       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3378 #       pragma omp parallel for reduction(+:n_upwind)
3379         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3380           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3381                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3382                face_id++) {
3383 
3384             cs_lnum_t ii = i_face_cells[face_id][0];
3385             cs_lnum_t jj = i_face_cells[face_id][1];
3386 
3387             /* in parallel, face will be counted by one and only one rank */
3388             if (ii < n_cells) {
3389               n_upwind++;
3390             }
3391 
3392             cs_real_t pifri, pjfri, pifrj, pjfrj;
3393             cs_real_t pip, pjp, pipr, pjpr;
3394 
3395             cs_real_t bldfrp = (cs_real_t) ircflp;
3396             /* Local limitation of the reconstruction */
3397             if (df_limiter != NULL && ircflp > 0)
3398               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3399 
3400             cs_i_cd_steady_upwind(bldfrp,
3401                                   relaxp,
3402                                   diipf[face_id],
3403                                   djjpf[face_id],
3404                                   grad[ii],
3405                                   grad[jj],
3406                                   _pvar[ii],
3407                                   _pvar[jj],
3408                                   pvara[ii],
3409                                   pvara[jj],
3410                                   &pifri,
3411                                   &pifrj,
3412                                   &pjfri,
3413                                   &pjfrj,
3414                                   &pip,
3415                                   &pjp,
3416                                   &pipr,
3417                                   &pjpr);
3418 
3419             cs_i_conv_flux(iconvp,
3420                            1.,
3421                            1,
3422                            _pvar[ii],
3423                            _pvar[jj],
3424                            pifri,
3425                            pifrj,
3426                            pjfri,
3427                            pjfrj,
3428                            i_massflux[face_id],
3429                            1., /* xcpp */
3430                            1., /* xcpp */
3431                            i_conv_flux[face_id]);
3432 
3433           }
3434         }
3435       }
3436 
3437     /* Unsteady */
3438     } else {
3439 
3440       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3441 #       pragma omp parallel for reduction(+:n_upwind)
3442         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3443           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3444                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3445                face_id++) {
3446 
3447             cs_lnum_t ii = i_face_cells[face_id][0];
3448             cs_lnum_t jj = i_face_cells[face_id][1];
3449 
3450             /* in parallel, face will be counted by one and only one rank */
3451             if (ii < n_cells) {
3452               n_upwind++;
3453             }
3454 
3455             cs_real_t pif, pjf;
3456             cs_real_t pip, pjp;
3457 
3458             cs_real_t bldfrp = (cs_real_t) ircflp;
3459             /* Local limitation of the reconstruction */
3460             if (df_limiter != NULL && ircflp > 0)
3461               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3462 
3463             cs_i_cd_unsteady_upwind(bldfrp,
3464                                     diipf[face_id],
3465                                     djjpf[face_id],
3466                                     grad[ii],
3467                                     grad[jj],
3468                                     _pvar[ii],
3469                                     _pvar[jj],
3470                                     &pif,
3471                                     &pjf,
3472                                     &pip,
3473                                     &pjp);
3474 
3475             cs_i_conv_flux(iconvp,
3476                            thetap,
3477                            imasac,
3478                            _pvar[ii],
3479                            _pvar[jj],
3480                            pif,
3481                            pif, /* no relaxation */
3482                            pjf,
3483                            pjf, /* no relaxation */
3484                            i_massflux[face_id],
3485                            1., /* xcpp */
3486                            1., /* xcpp */
3487                            i_conv_flux[face_id]);
3488 
3489           }
3490         }
3491       }
3492 
3493     }
3494 
3495   /* --> Flux with no slope test or Min/Max Beta limiter
3496     ====================================================*/
3497 
3498   } else if (isstpp == 1 || isstpp == 2) {
3499 
3500     if (ischcp < 0 || ischcp > 4) {
3501       bft_error(__FILE__, __LINE__, 0,
3502                 _("invalid value of ischcv"));
3503     }
3504 
3505     /* Steady */
3506     if (idtvar < 0) {
3507 
3508       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3509 #       pragma omp parallel for
3510         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3511           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3512                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3513                face_id++) {
3514 
3515             cs_lnum_t ii = i_face_cells[face_id][0];
3516             cs_lnum_t jj = i_face_cells[face_id][1];
3517 
3518             cs_real_t pifri, pjfri, pifrj, pjfrj;
3519             cs_real_t pip, pjp, pipr, pjpr;
3520 
3521             cs_real_t bldfrp = (cs_real_t) ircflp;
3522             /* Local limitation of the reconstruction */
3523             if (df_limiter != NULL && ircflp > 0)
3524               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3525 
3526             cs_i_cd_steady(bldfrp,
3527                            ischcp,
3528                            relaxp,
3529                            blencp,
3530                            weight[face_id],
3531                            cell_cen[ii],
3532                            cell_cen[jj],
3533                            i_face_cog[face_id],
3534                            diipf[face_id],
3535                            djjpf[face_id],
3536                            grad[ii],
3537                            grad[jj],
3538                            gradup[ii],
3539                            gradup[jj],
3540                            _pvar[ii],
3541                            _pvar[jj],
3542                            pvara[ii],
3543                            pvara[jj],
3544                            &pifri,
3545                            &pifrj,
3546                            &pjfri,
3547                            &pjfrj,
3548                            &pip,
3549                            &pjp,
3550                            &pipr,
3551                            &pjpr);
3552 
3553             cs_i_conv_flux(iconvp,
3554                            1.,
3555                            1,
3556                            _pvar[ii],
3557                            _pvar[jj],
3558                            pifri,
3559                            pifrj,
3560                            pjfri,
3561                            pjfrj,
3562                            i_massflux[face_id],
3563                            1., /* xcpp */
3564                            1., /* xcpp */
3565                            i_conv_flux[face_id]);
3566 
3567           }
3568         }
3569       }
3570 
3571     /* Unsteady */
3572     } else {
3573 
3574       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3575 #       pragma omp parallel for
3576         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3577           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3578                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3579                face_id++) {
3580 
3581             cs_lnum_t ii = i_face_cells[face_id][0];
3582             cs_lnum_t jj = i_face_cells[face_id][1];
3583 
3584             cs_real_t beta = blencp;
3585 
3586             cs_real_t pif, pjf;
3587             cs_real_t pip, pjp;
3588 
3589             /* Beta blending coefficient ensuring positivity of the scalar */
3590             if (isstpp == 2) {
3591               beta = CS_MAX(CS_MIN(cv_limiter[ii], cv_limiter[jj]), 0.);
3592             }
3593 
3594             cs_real_t bldfrp = (cs_real_t) ircflp;
3595             /* Local limitation of the reconstruction */
3596             if (df_limiter != NULL && ircflp > 0)
3597               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3598 
3599             if (ischcp != 4) {
3600               cs_real_t hybrid_coef_ii, hybrid_coef_jj;
3601               if (ischcp == 3) {
3602                 hybrid_coef_ii = CS_F_(hybrid_blend)->val[ii];
3603                 hybrid_coef_jj = CS_F_(hybrid_blend)->val[jj];
3604               } else {
3605                 hybrid_coef_ii = 0.;
3606                 hybrid_coef_jj = 0.;
3607               }
3608               cs_i_cd_unsteady(bldfrp,
3609                                ischcp,
3610                                beta,
3611                                weight[face_id],
3612                                cell_cen[ii],
3613                                cell_cen[jj],
3614                                i_face_cog[face_id],
3615                                hybrid_coef_ii,
3616                                hybrid_coef_jj,
3617                                diipf[face_id],
3618                                djjpf[face_id],
3619                                grad[ii],
3620                                grad[jj],
3621                                gradup[ii],
3622                                gradup[jj],
3623                                _pvar[ii],
3624                                _pvar[jj],
3625                                &pif,
3626                                &pjf,
3627                                &pip,
3628                                &pjp);
3629 
3630               cs_i_conv_flux(iconvp,
3631                              thetap,
3632                              imasac,
3633                              _pvar[ii],
3634                              _pvar[jj],
3635                              pif,
3636                              pif, /* no relaxation */
3637                              pjf,
3638                              pjf, /* no relaxation */
3639                              i_massflux[face_id],
3640                              1., /* xcpp */
3641                              1., /* xcpp */
3642                              i_conv_flux[face_id]);
3643             } else {
3644               /* NVD/TVD family of high accuracy schemes */
3645 
3646               cs_lnum_t ic, id;
3647 
3648               /* Determine central and downwind sides w.r.t. current face */
3649               cs_central_downwind_cells(ii,
3650                                         jj,
3651                                         i_massflux[face_id],
3652                                         &ic,  /* central cell id */
3653                                         &id); /* downwind cell id */
3654 
3655               cs_real_t courant_c = -1.;
3656               if (courant != NULL)
3657                 courant_c = courant[ic];
3658 
3659               cs_i_cd_unsteady_nvd(limiter_choice,
3660                                    beta,
3661                                    cell_cen[ic],
3662                                    cell_cen[id],
3663                                    i_face_normal[face_id],
3664                                    i_face_cog[face_id],
3665                                    grad[ic],
3666                                    _pvar[ic],
3667                                    _pvar[id],
3668                                    local_max[ic],
3669                                    local_min[ic],
3670                                    courant_c,
3671                                    &pif,
3672                                    &pjf);
3673 
3674               cs_i_conv_flux(iconvp,
3675                              thetap,
3676                              imasac,
3677                              _pvar[ii],
3678                              _pvar[jj],
3679                              pif,
3680                              pif, /* no relaxation */
3681                              pjf,
3682                              pjf, /* no relaxation */
3683                              i_massflux[face_id],
3684                              1., /* xcpp */
3685                              1., /* xcpp */
3686                              i_conv_flux[face_id]);
3687             }
3688 
3689           }
3690         }
3691       }
3692 
3693     }
3694 
3695   /* --> Flux with slope test or NVD/TVD limiter
3696     ============================================*/
3697 
3698   } else { /* isstpp = 0 */
3699 
3700     if (ischcp < 0 || ischcp > 2) {
3701       bft_error(__FILE__, __LINE__, 0,
3702                 _("invalid value of ischcv"));
3703     }
3704 
3705     /* Steady */
3706     if (idtvar < 0) {
3707 
3708       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3709 #       pragma omp parallel for reduction(+:n_upwind)
3710         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3711           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3712                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3713                face_id++) {
3714 
3715             cs_lnum_t ii = i_face_cells[face_id][0];
3716             cs_lnum_t jj = i_face_cells[face_id][1];
3717 
3718             bool upwind_switch = false;
3719             cs_real_t pifri, pjfri, pifrj, pjfrj;
3720             cs_real_t pip, pjp, pipr, pjpr;
3721 
3722             cs_real_t bldfrp = (cs_real_t) ircflp;
3723             /* Local limitation of the reconstruction */
3724             if (df_limiter != NULL && ircflp > 0)
3725               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3726 
3727             cs_i_cd_steady_slope_test(&upwind_switch,
3728                                       iconvp,
3729                                       bldfrp,
3730                                       ischcp,
3731                                       relaxp,
3732                                       blencp,
3733                                       blend_st,
3734                                       weight[face_id],
3735                                       i_dist[face_id],
3736                                       i_face_surf[face_id],
3737                                       cell_cen[ii],
3738                                       cell_cen[jj],
3739                                       i_face_normal[face_id],
3740                                       i_face_cog[face_id],
3741                                       diipf[face_id],
3742                                       djjpf[face_id],
3743                                       i_massflux[face_id],
3744                                       grad[ii],
3745                                       grad[jj],
3746                                       gradup[ii],
3747                                       gradup[jj],
3748                                       gradst[ii],
3749                                       gradst[jj],
3750                                       _pvar[ii],
3751                                       _pvar[jj],
3752                                       pvara[ii],
3753                                       pvara[jj],
3754                                       &pifri,
3755                                       &pifrj,
3756                                       &pjfri,
3757                                       &pjfrj,
3758                                       &pip,
3759                                       &pjp,
3760                                       &pipr,
3761                                       &pjpr);
3762 
3763             cs_i_conv_flux(iconvp,
3764                            1.,
3765                            1,
3766                            _pvar[ii],
3767                            _pvar[jj],
3768                            pifri,
3769                            pifrj,
3770                            pjfri,
3771                            pjfrj,
3772                            i_massflux[face_id],
3773                            1., /* xcpp */
3774                            1., /* xcpp */
3775                            i_conv_flux[face_id]);
3776 
3777             if (upwind_switch) {
3778 
3779               /* in parallel, face will be counted by one and only one rank */
3780               if (ii < n_cells)
3781                 n_upwind++;
3782               if (v_slope_test != NULL) {
3783                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
3784                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
3785               }
3786 
3787             }
3788 
3789           }
3790         }
3791       }
3792 
3793     /* Unsteady */
3794     } else {
3795 
3796       for (int g_id = 0; g_id < n_i_groups; g_id++) {
3797 #       pragma omp parallel for reduction(+:n_upwind)
3798         for (int t_id = 0; t_id < n_i_threads; t_id++) {
3799           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3800                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3801                face_id++) {
3802 
3803             cs_lnum_t ii = i_face_cells[face_id][0];
3804             cs_lnum_t jj = i_face_cells[face_id][1];
3805 
3806             bool upwind_switch = false;
3807 
3808             cs_real_t pif, pjf;
3809             cs_real_t pip, pjp;
3810 
3811             cs_real_t bldfrp = (cs_real_t) ircflp;
3812             /* Local limitation of the reconstruction */
3813             if (df_limiter != NULL && ircflp > 0)
3814               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
3815 
3816             cs_i_cd_unsteady_slope_test(&upwind_switch,
3817                                         iconvp,
3818                                         bldfrp,
3819                                         ischcp,
3820                                         blencp,
3821                                         blend_st,
3822                                         weight[face_id],
3823                                         i_dist[face_id],
3824                                         i_face_surf[face_id],
3825                                         cell_cen[ii],
3826                                         cell_cen[jj],
3827                                         i_face_normal[face_id],
3828                                         i_face_cog[face_id],
3829                                         diipf[face_id],
3830                                         djjpf[face_id],
3831                                         i_massflux[face_id],
3832                                         grad[ii],
3833                                         grad[jj],
3834                                         gradup[ii],
3835                                         gradup[jj],
3836                                         gradst[ii],
3837                                         gradst[jj],
3838                                         _pvar[ii],
3839                                         _pvar[jj],
3840                                         &pif,
3841                                         &pjf,
3842                                         &pip,
3843                                         &pjp);
3844 
3845             cs_i_conv_flux(iconvp,
3846                            thetap,
3847                            imasac,
3848                            _pvar[ii],
3849                            _pvar[jj],
3850                            pif,
3851                            pif, /* no relaxation */
3852                            pjf,
3853                            pjf, /* no relaxation */
3854                            i_massflux[face_id],
3855                            1., /* xcpp */
3856                            1., /* xcpp */
3857                            i_conv_flux[face_id]);
3858 
3859             if (upwind_switch) {
3860               /* in parallel, face will be counted by one and only one rank */
3861               if (ii < n_cells)
3862                 n_upwind++;
3863 
3864               if (v_slope_test != NULL) {
3865                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
3866                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
3867               }
3868             }
3869 
3870           }
3871         }
3872       }
3873 
3874     } /* idtvar */
3875 
3876   } /* iupwin */
3877 
3878 
3879   if (iwarnp >= 2 && iconvp == 1) {
3880 
3881     /* Sum number of clippings */
3882     cs_parall_counter(&n_upwind, 1);
3883 
3884     bft_printf(_(" %s: %llu Faces with upwind on %llu interior faces\n"),
3885                var_name, (unsigned long long)n_upwind,
3886                (unsigned long long)m->n_g_i_c_faces);
3887   }
3888 
3889   /* ======================================================================
3890     ---> Contribution from boundary faces
3891     ======================================================================*/
3892 
3893   /* Boundary convective flux are all computed with an upwind scheme */
3894   if (icvflb == 0) {
3895 
3896     /* Steady */
3897     if (idtvar < 0) {
3898 
3899       for (int g_id = 0; g_id < n_b_groups; g_id++) {
3900 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
3901         for (int t_id = 0; t_id < n_b_threads; t_id++) {
3902           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
3903                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
3904                face_id++) {
3905 
3906             cs_lnum_t ii = b_face_cells[face_id];
3907 
3908             cs_real_t pir, pipr;
3909 
3910             cs_real_t bldfrp = (cs_real_t) ircflp;
3911             /* Local limitation of the reconstruction */
3912             if (df_limiter != NULL && ircflp > 0)
3913               bldfrp = CS_MAX(df_limiter[ii], 0.);
3914 
3915             cs_b_cd_steady(bldfrp,
3916                            relaxp,
3917                            diipb[face_id],
3918                            grad[ii],
3919                            _pvar[ii],
3920                            pvara[ii],
3921                            &pir,
3922                            &pipr);
3923 
3924             cs_b_upwind_flux(iconvp,
3925                              1.,
3926                              1,
3927                              inc,
3928                              bc_type[face_id],
3929                              _pvar[ii],
3930                              pir,
3931                              pipr,
3932                              coefap[face_id],
3933                              coefbp[face_id],
3934                              b_massflux[face_id],
3935                              1., /* xcpp */
3936                              &(b_conv_flux[face_id]));
3937 
3938           }
3939         }
3940       }
3941 
3942     /* Unsteady */
3943     } else {
3944 
3945       for (int g_id = 0; g_id < n_b_groups; g_id++) {
3946 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
3947         for (int t_id = 0; t_id < n_b_threads; t_id++) {
3948           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
3949                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
3950                face_id++) {
3951 
3952             cs_lnum_t ii = b_face_cells[face_id];
3953 
3954             cs_real_t pip;
3955 
3956             cs_real_t bldfrp = (cs_real_t) ircflp;
3957             /* Local limitation of the reconstruction */
3958             if (df_limiter != NULL && ircflp > 0)
3959               bldfrp = CS_MAX(df_limiter[ii], 0.);
3960 
3961             cs_b_cd_unsteady(bldfrp,
3962                              diipb[face_id],
3963                              grad[ii],
3964                              _pvar[ii],
3965                              &pip);
3966 
3967             cs_b_upwind_flux(iconvp,
3968                              thetap,
3969                              imasac,
3970                              inc,
3971                              bc_type[face_id],
3972                              _pvar[ii],
3973                              _pvar[ii], /* no relaxation */
3974                              pip,
3975                              coefap[face_id],
3976                              coefbp[face_id],
3977                              b_massflux[face_id],
3978                              1., /* xcpp */
3979                              &(b_conv_flux[face_id]));
3980 
3981           }
3982         }
3983       }
3984     }
3985 
3986   /* Boundary convective flux is imposed at some faces
3987      (tagged in icvfli array) */
3988   } else if (icvflb == 1) {
3989 
3990     /* Retrieve the value of the convective flux to be imposed */
3991     if (f_id != -1) {
3992       coface = f->bc_coeffs->ac;
3993       cofbce = f->bc_coeffs->bc;
3994     } else {
3995       bft_error(__FILE__, __LINE__, 0,
3996                 _("invalid value of icvflb and f_id"));
3997     }
3998 
3999     /* Steady */
4000     if (idtvar < 0) {
4001 
4002       for (int g_id = 0; g_id < n_b_groups; g_id++) {
4003 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
4004         for (int t_id = 0; t_id < n_b_threads; t_id++) {
4005           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
4006                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
4007                face_id++) {
4008 
4009             cs_lnum_t ii = b_face_cells[face_id];
4010 
4011             cs_real_t pir, pipr;
4012 
4013             cs_real_t bldfrp = (cs_real_t) ircflp;
4014             /* Local limitation of the reconstruction */
4015             if (df_limiter != NULL && ircflp > 0)
4016               bldfrp = CS_MAX(df_limiter[ii], 0.);
4017 
4018             cs_b_cd_steady(bldfrp,
4019                            relaxp,
4020                            diipb[face_id],
4021                            grad[ii],
4022                            _pvar[ii],
4023                            pvara[ii],
4024                            &pir,
4025                            &pipr);
4026 
4027             cs_b_imposed_conv_flux(iconvp,
4028                                    1.,
4029                                    1,
4030                                    inc,
4031                                    bc_type[face_id],
4032                                    icvfli[face_id],
4033                                    _pvar[ii],
4034                                    pir,
4035                                    pipr,
4036                                    coefap[face_id],
4037                                    coefbp[face_id],
4038                                    coface[face_id],
4039                                    cofbce[face_id],
4040                                    b_massflux[face_id],
4041                                    1., /* xcpp */
4042                                    &(b_conv_flux[face_id]));
4043 
4044           }
4045         }
4046       }
4047 
4048     /* Unsteady */
4049     } else {
4050 
4051       for (int g_id = 0; g_id < n_b_groups; g_id++) {
4052 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
4053         for (int t_id = 0; t_id < n_b_threads; t_id++) {
4054           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
4055                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
4056                face_id++) {
4057 
4058             cs_lnum_t ii = b_face_cells[face_id];
4059 
4060             cs_real_t pip;
4061 
4062             cs_real_t bldfrp = (cs_real_t) ircflp;
4063             /* Local limitation of the reconstruction */
4064             if (df_limiter != NULL && ircflp > 0)
4065               bldfrp = CS_MAX(df_limiter[ii], 0.);
4066 
4067             cs_b_cd_unsteady(bldfrp,
4068                              diipb[face_id],
4069                              grad[ii],
4070                              _pvar[ii],
4071                              &pip);
4072 
4073             cs_b_imposed_conv_flux(iconvp,
4074                                    thetap,
4075                                    imasac,
4076                                    inc,
4077                                    bc_type[face_id],
4078                                    icvfli[face_id],
4079                                    _pvar[ii],
4080                                    _pvar[ii], /* no relaxation */
4081                                    pip,
4082                                    coefap[face_id],
4083                                    coefbp[face_id],
4084                                    coface[face_id],
4085                                    cofbce[face_id],
4086                                    b_massflux[face_id],
4087                                    1., /* xcpp */
4088                                    &(b_conv_flux[face_id]));
4089 
4090           }
4091         }
4092       }
4093 
4094     }
4095   }
4096 
4097   /* Free memory */
4098   BFT_FREE(grad);
4099   BFT_FREE(gradup);
4100   BFT_FREE(gradst);
4101   BFT_FREE(local_max);
4102   BFT_FREE(local_min);
4103   BFT_FREE(courant);
4104 }
4105 
4106 /*----------------------------------------------------------------------------*/
4107 /*!
4108  * \brief Add the explicit part of the convection/diffusion terms of a transport
4109  *  equation of a vector field \f$ \vect{\varia} \f$.
4110  *
4111  * More precisely, the right hand side \f$ \vect{Rhs} \f$ is updated as
4112  * follows:
4113  * \f[
4114  *  \vect{Rhs} = \vect{Rhs} - \sum_{\fij \in \Facei{\celli}}      \left(
4115  *         \dot{m}_\ij \left( \vect{\varia}_\fij - \vect{\varia}_\celli \right)
4116  *       - \mu_\fij \gradt_\fij \vect{\varia} \cdot \vect{S}_\ij  \right)
4117  * \f]
4118  *
4119  * Remark:
4120  * if ivisep = 1, then we also take \f$ \mu \transpose{\gradt\vect{\varia}}
4121  * + \lambda \trace{\gradt\vect{\varia}} \f$, where \f$ \lambda \f$ is
4122  * the secondary viscosity, i.e. usually \f$ -\frac{2}{3} \mu \f$.
4123  *
4124  * Warning:
4125  * - \f$ \vect{Rhs} \f$ has already been initialized before calling bilsc!
4126  * - mind the sign minus
4127  *
4128  * \param[in]     idtvar        indicator of the temporal scheme
4129  * \param[in]     f_id          index of the current variable
4130  * \param[in]     var_cal_opt   variable calculation options
4131  * \param[in]     icvflb        global indicator of boundary convection flux
4132  *                               - 0 upwind scheme at all boundary faces
4133  *                               - 1 imposed flux at some boundary faces
4134  * \param[in]     inc           indicator
4135  *                               - 0 when solving an increment
4136  *                               - 1 otherwise
4137  * \param[in]     ivisep        indicator to take \f$ \divv
4138  *                               \left(\mu \gradt \transpose{\vect{a}} \right)
4139  *                               -2/3 \grad\left( \mu \dive \vect{a} \right)\f$
4140  *                               - 1 take into account,
4141  *                               - 0 otherwise
4142  * \param[in]     imasac        take mass accumulation into account?
4143  * \param[in]     pvar          solved velocity (current time step)
4144  * \param[in]     pvara         solved velocity (previous time step)
4145  * \param[in]     icvfli        boundary face indicator array of convection flux
4146  *                               - 0 upwind scheme
4147  *                               - 1 imposed flux
4148  * \param[in]     coefav        boundary condition array for the variable
4149  *                               (explicit part)
4150  * \param[in]     coefbv        boundary condition array for the variable
4151  *                               (implicit part)
4152  * \param[in]     cofafv        boundary condition array for the diffusion
4153  *                               of the variable (explicit part)
4154  * \param[in]     cofbfv        boundary condition array for the diffusion
4155  *                               of the variable (implicit part)
4156  * \param[in]     i_massflux    mass flux at interior faces
4157  * \param[in]     b_massflux    mass flux at boundary faces
4158  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
4159  *                               at interior faces for the r.h.s.
4160  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
4161  *                               at border faces for the r.h.s.
4162  * \param[in]     i_secvis      secondary viscosity at interior faces
4163  * \param[in]     b_secvis      secondary viscosity at boundary faces
4164  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
4165  */
4166 /*----------------------------------------------------------------------------*/
4167 
4168 void
cs_convection_diffusion_vector(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int icvflb,int inc,int ivisep,int imasac,cs_real_3_t * restrict pvar,const cs_real_3_t * restrict pvara,const int icvfli[],const cs_real_3_t coefav[],const cs_real_33_t coefbv[],const cs_real_3_t cofafv[],const cs_real_33_t cofbfv[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],const cs_real_t i_visc[],const cs_real_t b_visc[],const cs_real_t i_secvis[],const cs_real_t b_secvis[],cs_real_3_t * restrict rhs)4169 cs_convection_diffusion_vector(int                         idtvar,
4170                                int                         f_id,
4171                                const cs_var_cal_opt_t      var_cal_opt,
4172                                int                         icvflb,
4173                                int                         inc,
4174                                int                         ivisep,
4175                                int                         imasac,
4176                                cs_real_3_t       *restrict pvar,
4177                                const cs_real_3_t *restrict pvara,
4178                                const int                   icvfli[],
4179                                const cs_real_3_t           coefav[],
4180                                const cs_real_33_t          coefbv[],
4181                                const cs_real_3_t           cofafv[],
4182                                const cs_real_33_t          cofbfv[],
4183                                const cs_real_t             i_massflux[],
4184                                const cs_real_t             b_massflux[],
4185                                const cs_real_t             i_visc[],
4186                                const cs_real_t             b_visc[],
4187                                const cs_real_t             i_secvis[],
4188                                const cs_real_t             b_secvis[],
4189                                cs_real_3_t       *restrict rhs)
4190 {
4191   const int iconvp = var_cal_opt.iconv;
4192   const int idiffp = var_cal_opt.idiff;
4193   const int nswrgp = var_cal_opt.nswrgr;
4194   const int imrgra = var_cal_opt.imrgra;
4195   const int imligp = var_cal_opt.imligr;
4196   const int ircflp = var_cal_opt.ircflu;
4197   const int ischcp = var_cal_opt.ischcv;
4198   const int isstpp = var_cal_opt.isstpc;
4199   const int iwarnp = var_cal_opt.verbosity;
4200   const int icoupl = var_cal_opt.icoupl;
4201   const double blencp = var_cal_opt.blencv;
4202   const double blend_st = var_cal_opt.blend_st;
4203   const double epsrgp = var_cal_opt.epsrgr;
4204   const double climgp = var_cal_opt.climgr;
4205   const double relaxp = var_cal_opt.relaxv;
4206   const double thetap = var_cal_opt.thetav;
4207 
4208   const cs_mesh_t  *m = cs_glob_mesh;
4209   const cs_halo_t  *halo = m->halo;
4210   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
4211 
4212   const cs_lnum_t n_cells = m->n_cells;
4213   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
4214   const int n_i_groups = m->i_face_numbering->n_groups;
4215   const int n_i_threads = m->i_face_numbering->n_threads;
4216   const int n_b_groups = m->b_face_numbering->n_groups;
4217   const int n_b_threads = m->b_face_numbering->n_threads;
4218   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
4219   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
4220 
4221   const cs_lnum_2_t *restrict i_face_cells
4222     = (const cs_lnum_2_t *restrict)m->i_face_cells;
4223   const cs_lnum_t *restrict b_face_cells
4224     = (const cs_lnum_t *restrict)m->b_face_cells;
4225   const cs_real_t *restrict weight = fvq->weight;
4226   const cs_real_t *restrict i_dist = fvq->i_dist;
4227   const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
4228   const cs_real_t *restrict cell_vol = fvq->cell_vol;
4229   const cs_real_3_t *restrict cell_cen
4230     = (const cs_real_3_t *restrict)fvq->cell_cen;
4231   const cs_real_3_t *restrict i_face_normal
4232     = (const cs_real_3_t *restrict)fvq->i_face_normal;
4233   const cs_real_3_t *restrict i_f_face_normal
4234     = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
4235   const cs_real_3_t *restrict b_face_normal
4236     = (const cs_real_3_t *restrict)fvq->b_face_normal;
4237   const cs_real_3_t *restrict b_f_face_normal
4238     = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
4239   const cs_real_3_t *restrict i_face_cog
4240     = (const cs_real_3_t *restrict)fvq->i_face_cog;
4241   const cs_real_3_t *restrict diipf
4242     = (const cs_real_3_t *restrict)fvq->diipf;
4243   const cs_real_3_t *restrict djjpf
4244     = (const cs_real_3_t *restrict)fvq->djjpf;
4245   const cs_real_3_t *restrict diipb
4246     = (const cs_real_3_t *restrict)fvq->diipb;
4247 
4248   const int *bc_type = cs_glob_bc_type;
4249   cs_real_2_t *i_f_face_factor = NULL;
4250   cs_real_t *b_f_face_factor = NULL;
4251 
4252   /* Local variables */
4253 
4254   cs_real_t *df_limiter = NULL;
4255 
4256   cs_field_t *f = NULL;
4257   char var_name[64];
4258 
4259   if (f_id != -1) {
4260     f = cs_field_by_id(f_id);
4261 
4262     int df_limiter_id =
4263       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
4264     if (df_limiter_id > -1)
4265       df_limiter = cs_field_by_id(df_limiter_id)->val;
4266 
4267     snprintf(var_name, 63, "%s", f->name);
4268   }
4269   else
4270     strncpy(var_name, "[convection-diffusion, vector]", 63);
4271   var_name[63] = '\0';
4272 
4273   /* Discontinuous porous treatment */
4274   if (cs_glob_porous_model == 3 && f == CS_F_(vel)) {
4275     i_f_face_factor = fvq->i_f_face_factor;
4276     b_f_face_factor = fvq->b_f_face_factor;
4277   }
4278 
4279   cs_gnum_t n_upwind;
4280   int iupwin = 0;
4281 
4282   cs_real_33_t *grad, *grdpa;
4283   cs_real_t *bndcel;
4284 
4285   const cs_real_3_t *coface = NULL;
4286   const cs_real_33_t *cofbce = NULL;
4287 
4288   cs_real_t *gweight = NULL;
4289 
4290   cs_real_t  *v_slope_test = cs_get_v_slope_test(f_id,  var_cal_opt);
4291 
4292   /* Internal coupling variables */
4293   cs_real_3_t *pvar_local = NULL;
4294   cs_real_3_t *pvar_distant = NULL;
4295   cs_real_t *df_limiter_local = NULL;
4296   const cs_lnum_t *faces_local = NULL, *faces_distant = NULL;
4297   cs_lnum_t n_local = 0, n_distant = 0;
4298   int coupling_id = -1;
4299   cs_internal_coupling_t *cpl = NULL;
4300 
4301   /*==========================================================================*/
4302 
4303   /* 1. Initialization */
4304 
4305   /* Allocate work arrays */
4306 
4307   BFT_MALLOC(grad, n_cells_ext, cs_real_33_t);
4308   BFT_MALLOC(grdpa, n_cells_ext, cs_real_33_t);
4309 
4310   /* Choose gradient type */
4311 
4312   cs_halo_type_t halo_type = CS_HALO_STANDARD;
4313   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
4314 
4315   cs_gradient_type_by_imrgra(imrgra,
4316                              &gradient_type,
4317                              &halo_type);
4318 
4319   /* Handle cases where only the previous values (already synchronized)
4320      or current values are provided */
4321 
4322   if (pvar != NULL && halo != NULL) {
4323     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)pvar, 3);
4324     if (cs_glob_mesh->n_init_perio > 0)
4325       cs_halo_perio_sync_var_vect(halo, halo_type, (cs_real_t *)pvar, 3);
4326   }
4327   if (pvara == NULL)
4328     pvara = (const cs_real_3_t *restrict)pvar;
4329 
4330   const cs_real_3_t  *restrict _pvar
4331     = (pvar != NULL) ? (const cs_real_3_t  *restrict)pvar : pvara;
4332 
4333   /* Slope limiters */
4334 
4335   if (iwarnp >= 2 && iconvp == 1) {
4336     if (ischcp == 1) {
4337       bft_printf
4338         (
4339          _(" %s: Convection in centered blending with %f percent of upwind\n"),
4340          var_name, (1.-blencp)*100.);
4341     } else {
4342       bft_printf
4343         (
4344          _(" %s: Convection in 2nd order blending with %f percent of upwind\n"),
4345          var_name, (1.-blencp)*100.);
4346     }
4347   }
4348 
4349   iupwin = (blencp > 0.) ? 0 : 1;
4350 
4351   if (icoupl > 0) {
4352     assert(f_id != -1);
4353     const int coupling_key_id = cs_field_key_id("coupling_entity");
4354     coupling_id = cs_field_get_key_int(f, coupling_key_id);
4355     cpl = cs_internal_coupling_by_id(coupling_id);
4356     cs_internal_coupling_coupled_faces(cpl,
4357                                        &n_local,
4358                                        &faces_local,
4359                                        &n_distant,
4360                                        &faces_distant);
4361   }
4362 
4363   /* 2. Compute the balance with reconstruction */
4364 
4365   /* Compute the gradient of the velocity
4366 
4367      The gradient (grad) is used in the flux reconstruction and the slope test.
4368      Thus we must compute it:
4369          - when we have diffusion and we reconstruct the fluxes,
4370          - when the convection scheme is SOLU,
4371          - when we have convection, we are not in pure upwind
4372            and we reconstruct the fluxes,
4373          - when we have convection, we are not in pure upwind
4374            and we have not shunted the slope test. */
4375 
4376   if (  (idiffp != 0 && ircflp == 1) || ivisep == 1
4377      || (   iconvp != 0 && iupwin == 0
4378          && (ischcp == 0 || ircflp == 1 || isstpp == 0))) {
4379 
4380     if (f_id != -1) {
4381       /* Get the calculation option from the field */
4382       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
4383         if (var_cal_opt.idiff > 0) {
4384           int key_id = cs_field_key_id("gradient_weighting_id");
4385           int diff_id = cs_field_get_key_int(f, key_id);
4386           if (diff_id > -1) {
4387             cs_field_t *weight_f = cs_field_by_id(diff_id);
4388             gweight = weight_f->val;
4389             cs_field_synchronize(weight_f, halo_type);
4390           }
4391         }
4392       }
4393     }
4394 
4395     cs_gradient_vector_synced_input(var_name,
4396                                     gradient_type,
4397                                     halo_type,
4398                                     inc,
4399                                     nswrgp,
4400                                     iwarnp,
4401                                     imligp,
4402                                     epsrgp,
4403                                     climgp,
4404                                     coefav,
4405                                     coefbv,
4406                                     _pvar,
4407                                     gweight, /* weighted gradient */
4408                                     cpl,
4409                                     grad);
4410 
4411   } else {
4412 #   pragma omp parallel for
4413     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
4414       for (int isou = 0; isou < 3; isou++) {
4415         for (int jsou = 0; jsou < 3; jsou++)
4416           grad[cell_id][isou][jsou] = 0.;
4417       }
4418     }
4419   }
4420 
4421   /* ======================================================================
4422      ---> Compute uncentered gradient grdpa for the slope test
4423      ======================================================================*/
4424 
4425 # pragma omp parallel for
4426   for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
4427     for (int jsou = 0; jsou < 3; jsou++) {
4428       for (int isou = 0; isou < 3; isou++)
4429         grdpa[cell_id][isou][jsou] = 0.;
4430     }
4431   }
4432 
4433   if (iconvp > 0 && iupwin == 0 && isstpp == 0) {
4434 
4435     cs_slope_test_gradient_vector(inc,
4436                                   halo_type,
4437                                   (const cs_real_33_t *)grad,
4438                                   grdpa,
4439                                   _pvar,
4440                                   coefav,
4441                                   coefbv,
4442                                   i_massflux);
4443 
4444   }
4445 
4446   /* ======================================================================
4447      ---> Contribution from interior faces
4448      ======================================================================*/
4449 
4450   n_upwind = 0;
4451 
4452   if (n_cells_ext > n_cells) {
4453 #   pragma omp parallel for if(n_cells_ext -n_cells > CS_THR_MIN)
4454     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
4455       for (int isou = 0; isou < 3; isou++)
4456         rhs[cell_id][isou] = 0.;
4457     }
4458   }
4459 
4460   /* --> Pure upwind flux
4461      =====================*/
4462 
4463   if (iupwin == 1) {
4464 
4465     /* Steady */
4466     if (idtvar < 0) {
4467 
4468       for (int g_id = 0; g_id < n_i_groups; g_id++) {
4469 #       pragma omp parallel for reduction(+:n_upwind)
4470         for (int t_id = 0; t_id < n_i_threads; t_id++) {
4471           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4472                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4473                face_id++) {
4474 
4475             cs_lnum_t ii = i_face_cells[face_id][0];
4476             cs_lnum_t jj = i_face_cells[face_id][1];
4477 
4478             /* in parallel, face will be counted by one and only one rank */
4479             if (ii < n_cells) {
4480               n_upwind++;
4481             }
4482 
4483             cs_real_t fluxi[3], fluxj[3] ;
4484             for (int isou =  0; isou < 3; isou++) {
4485               fluxi[isou] = 0;
4486               fluxj[isou] = 0;
4487             }
4488 
4489             cs_real_3_t pip, pjp, pipr, pjpr;
4490             cs_real_3_t pifri, pifrj, pjfri, pjfrj;
4491             cs_real_3_t _pi, _pj, _pia, _pja;
4492 
4493             for (int i = 0; i < 3; i++) {
4494               _pi[i]  = _pvar[ii][i];
4495               _pj[i]  = _pvar[jj][i];
4496               _pia[i] = pvara[ii][i];
4497               _pja[i] = pvara[jj][i];
4498             }
4499 
4500             /* Scaling due to mass balance in porous modelling */
4501             if (i_f_face_factor != NULL) {
4502               cs_real_3_t n;
4503               cs_math_3_normalise(i_face_normal[face_id], n);
4504 
4505               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
4506               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pia);
4507               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
4508               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pja);
4509             }
4510 
4511             cs_real_t bldfrp = (cs_real_t) ircflp;
4512             /* Local limitation of the reconstruction */
4513             if (df_limiter != NULL && ircflp > 0)
4514               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
4515 
4516             cs_i_cd_steady_upwind_vector(bldfrp,
4517                                          relaxp,
4518                                          diipf[face_id],
4519                                          djjpf[face_id],
4520                                          (const cs_real_3_t *)grad[ii],
4521                                          (const cs_real_3_t *)grad[jj],
4522                                          _pi,
4523                                          _pj,
4524                                          _pia,
4525                                          _pja,
4526                                          pifri,
4527                                          pifrj,
4528                                          pjfri,
4529                                          pjfrj,
4530                                          pip,
4531                                          pjp,
4532                                          pipr,
4533                                          pjpr);
4534 
4535 
4536             cs_i_conv_flux_vector(iconvp,
4537                                   1.,
4538                                   1,
4539                                   _pvar[ii],
4540                                   _pvar[jj],
4541                                   pifri,
4542                                   pifrj,
4543                                   pjfri,
4544                                   pjfrj,
4545                                   i_massflux[face_id],
4546                                   fluxi,
4547                                   fluxj);
4548 
4549 
4550             cs_i_diff_flux_vector(idiffp,
4551                                   1.,
4552                                   pip,
4553                                   pjp,
4554                                   pipr,
4555                                   pjpr,
4556                                   i_visc[face_id],
4557                                   fluxi,
4558                                   fluxj);
4559 
4560            for (int isou = 0; isou < 3; isou++) {
4561               rhs[ii][isou] -= fluxi[isou];
4562               rhs[jj][isou] += fluxj[isou];
4563             }
4564 
4565           }
4566         }
4567       }
4568 
4569     /* Unsteady */
4570     } else {
4571 
4572       for (int g_id = 0; g_id < n_i_groups; g_id++) {
4573 #       pragma omp parallel for reduction(+:n_upwind)
4574         for (int t_id = 0; t_id < n_i_threads; t_id++) {
4575           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4576                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4577                face_id++) {
4578 
4579             cs_lnum_t ii = i_face_cells[face_id][0];
4580             cs_lnum_t jj = i_face_cells[face_id][1];
4581 
4582             /* in parallel, face will be counted by one and only one rank */
4583             if (ii < n_cells) {
4584               n_upwind++;
4585             }
4586 
4587             cs_real_t fluxi[3], fluxj[3] ;
4588             for (int i = 0; i < 3; i++) {
4589               fluxi[i] = 0;
4590               fluxj[i] = 0;
4591             }
4592             cs_real_3_t pip, pjp;
4593             cs_real_3_t pif, pjf;
4594             cs_real_3_t _pi, _pj;
4595 
4596             for (int i = 0; i < 3; i++) {
4597               _pi[i]  = _pvar[ii][i];
4598               _pj[i]  = _pvar[jj][i];
4599             }
4600 
4601             /* Scaling due to mass balance in porous modelling */
4602             if (i_f_face_factor != NULL) {
4603               cs_real_3_t n;
4604               cs_math_3_normalise(i_face_normal[face_id], n);
4605 
4606               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
4607               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
4608             }
4609 
4610             cs_real_t bldfrp = (cs_real_t) ircflp;
4611             /* Local limitation of the reconstruction */
4612             if (df_limiter != NULL && ircflp > 0)
4613               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
4614 
4615             cs_i_cd_unsteady_upwind_vector(bldfrp,
4616                                            diipf[face_id],
4617                                            djjpf[face_id],
4618                                            (const cs_real_3_t *)grad[ii],
4619                                            (const cs_real_3_t *)grad[jj],
4620                                            _pi,
4621                                            _pj,
4622                                            pif,
4623                                            pjf,
4624                                            pip,
4625                                            pjp);
4626 
4627             cs_i_conv_flux_vector(iconvp,
4628                                   thetap,
4629                                   imasac,
4630                                   _pvar[ii],
4631                                   _pvar[jj],
4632                                   pif,
4633                                   pif, /* no relaxation */
4634                                   pjf,
4635                                   pjf, /* no relaxation */
4636                                   i_massflux[face_id],
4637                                   fluxi,
4638                                   fluxj);
4639 
4640 
4641             cs_i_diff_flux_vector(idiffp,
4642                                   thetap,
4643                                   pip,
4644                                   pjp,
4645                                   pip, /* no relaxation */
4646                                   pjp, /* no relaxation */
4647                                   i_visc[face_id],
4648                                   fluxi,
4649                                   fluxj);
4650 
4651             for (int isou = 0; isou < 3; isou++) {
4652               rhs[ii][isou] -= fluxi[isou];
4653               rhs[jj][isou] += fluxj[isou];
4654             }
4655 
4656           }
4657         }
4658       }
4659 
4660     }
4661 
4662     /* --> Flux with no slope test
4663        ============================*/
4664 
4665   } else if (isstpp == 1) {
4666 
4667     if (ischcp < 0 || ischcp == 2 || ischcp > 3) {
4668       bft_error(__FILE__, __LINE__, 0,
4669                 _("invalid value of ischcv"));
4670     }
4671 
4672     /* Steady */
4673     if (idtvar < 0) {
4674 
4675       for (int g_id = 0; g_id < n_i_groups; g_id++) {
4676 #       pragma omp parallel for
4677         for (int t_id = 0; t_id < n_i_threads; t_id++) {
4678           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4679                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4680                face_id++) {
4681 
4682             cs_lnum_t ii = i_face_cells[face_id][0];
4683             cs_lnum_t jj = i_face_cells[face_id][1];
4684 
4685             cs_real_t fluxi[3], fluxj[3] ;
4686             for (int isou =  0; isou < 3; isou++) {
4687               fluxi[isou] = 0;
4688               fluxj[isou] = 0;
4689             }
4690             cs_real_3_t pip, pjp, pipr, pjpr;
4691             cs_real_3_t pifri, pifrj, pjfri, pjfrj;
4692             cs_real_3_t _pi, _pj, _pia, _pja;
4693 
4694             for (int i = 0; i < 3; i++) {
4695               _pi[i]  = _pvar[ii][i];
4696               _pj[i]  = _pvar[jj][i];
4697               _pia[i] = pvara[ii][i];
4698               _pja[i] = pvara[jj][i];
4699             }
4700 
4701             /* Scaling due to mass balance in porous modelling */
4702             if (i_f_face_factor != NULL) {
4703               cs_real_3_t n;
4704               cs_math_3_normalise(i_face_normal[face_id], n);
4705 
4706               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
4707               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pia);
4708               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
4709               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pja);
4710             }
4711 
4712             cs_real_t bldfrp = (cs_real_t) ircflp;
4713             /* Local limitation of the reconstruction */
4714             if (df_limiter != NULL && ircflp > 0)
4715               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
4716 
4717             cs_i_cd_steady_vector(bldfrp,
4718                                   ischcp,
4719                                   relaxp,
4720                                   blencp,
4721                                   weight[face_id],
4722                                   cell_cen[ii],
4723                                   cell_cen[jj],
4724                                   i_face_cog[face_id],
4725                                   diipf[face_id],
4726                                   djjpf[face_id],
4727                                   (const cs_real_3_t *)grad[ii],
4728                                   (const cs_real_3_t *)grad[jj],
4729                                   _pi,
4730                                   _pj,
4731                                   _pia,
4732                                   _pja,
4733                                   pifri,
4734                                   pifrj,
4735                                   pjfri,
4736                                   pjfrj,
4737                                   pip,
4738                                   pjp,
4739                                   pipr,
4740                                   pjpr);
4741 
4742             cs_i_conv_flux_vector(iconvp,
4743                                   1.,
4744                                   1,
4745                                   _pvar[ii],
4746                                   _pvar[jj],
4747                                   pifri,
4748                                   pifrj,
4749                                   pjfri,
4750                                   pjfrj,
4751                                   i_massflux[face_id],
4752                                   fluxi,
4753                                   fluxj);
4754 
4755 
4756             cs_i_diff_flux_vector(idiffp,
4757                                   1.,
4758                                   pip,
4759                                   pjp,
4760                                   pipr,
4761                                   pjpr,
4762                                   i_visc[face_id],
4763                                   fluxi,
4764                                   fluxj);
4765 
4766             for (int isou = 0; isou < 3; isou++) {
4767               rhs[ii][isou] -= fluxi[isou];
4768               rhs[jj][isou] += fluxj[isou];
4769             }
4770 
4771           }
4772         }
4773       }
4774 
4775       /* Unsteady */
4776     } else {
4777 
4778       for (int g_id = 0; g_id < n_i_groups; g_id++) {
4779 #       pragma omp parallel for
4780         for (int t_id = 0; t_id < n_i_threads; t_id++) {
4781           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4782                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4783                face_id++) {
4784 
4785             cs_lnum_t ii = i_face_cells[face_id][0];
4786             cs_lnum_t jj = i_face_cells[face_id][1];
4787 
4788             cs_real_t fluxi[3], fluxj[3] ;
4789             for (int isou =  0; isou < 3; isou++) {
4790               fluxi[isou] = 0;
4791               fluxj[isou] = 0;
4792             }
4793 
4794             cs_real_3_t pip, pjp;
4795             cs_real_3_t pif, pjf;
4796             cs_real_3_t _pi, _pj;
4797 
4798             for (int i = 0; i < 3; i++) {
4799               _pi[i]  = _pvar[ii][i];
4800               _pj[i]  = _pvar[jj][i];
4801             }
4802 
4803             /* Scaling due to mass balance in porous modelling */
4804             if (i_f_face_factor != NULL) {
4805               cs_real_3_t n;
4806               cs_math_3_normalise(i_face_normal[face_id], n);
4807 
4808               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
4809               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
4810             }
4811 
4812             cs_real_t hybrid_coef_ii, hybrid_coef_jj;
4813             if (ischcp == 3) {
4814               hybrid_coef_ii = CS_F_(hybrid_blend)->val[ii];
4815               hybrid_coef_jj = CS_F_(hybrid_blend)->val[jj];
4816             } else {
4817               hybrid_coef_ii = 0.;
4818               hybrid_coef_jj = 0.;
4819             }
4820 
4821             cs_real_t bldfrp = (cs_real_t) ircflp;
4822             /* Local limitation of the reconstruction */
4823             if (df_limiter != NULL && ircflp > 0)
4824               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
4825 
4826             cs_i_cd_unsteady_vector(bldfrp,
4827                                     ischcp,
4828                                     blencp,
4829                                     weight[face_id],
4830                                     cell_cen[ii],
4831                                     cell_cen[jj],
4832                                     i_face_cog[face_id],
4833                                     hybrid_coef_ii,
4834                                     hybrid_coef_jj,
4835                                     diipf[face_id],
4836                                     djjpf[face_id],
4837                                     (const cs_real_3_t *)grad[ii],
4838                                     (const cs_real_3_t *)grad[jj],
4839                                     _pi,
4840                                     _pj,
4841                                     pif,
4842                                     pjf,
4843                                     pip,
4844                                     pjp);
4845 
4846             cs_i_conv_flux_vector(iconvp,
4847                                   thetap,
4848                                   imasac,
4849                                   _pvar[ii],
4850                                   _pvar[jj],
4851                                   pif,
4852                                   pif, /* no relaxation */
4853                                   pjf,
4854                                   pjf, /* no relaxation */
4855                                   i_massflux[face_id],
4856                                   fluxi,
4857                                   fluxj);
4858 
4859 
4860             cs_i_diff_flux_vector(idiffp,
4861                                   thetap,
4862                                   pip,
4863                                   pjp,
4864                                   pip, /* no relaxation */
4865                                   pjp, /* no relaxation */
4866                                   i_visc[face_id],
4867                                   fluxi,
4868                                   fluxj);
4869 
4870             for (int isou = 0; isou < 3; isou++) {
4871               rhs[ii][isou] -= fluxi[isou];
4872               rhs[jj][isou] += fluxj[isou];
4873             }
4874 
4875           }
4876         }
4877       }
4878 
4879     }
4880 
4881     /* --> Flux with slope test
4882        =========================*/
4883 
4884   } else {
4885 
4886     if (ischcp < 0 || ischcp > 1) {
4887       bft_error(__FILE__, __LINE__, 0,
4888                 _("invalid value of ischcv"));
4889     }
4890 
4891     /* Steady */
4892     if (idtvar < 0) {
4893 
4894       for (int g_id = 0; g_id < n_i_groups; g_id++) {
4895 #       pragma omp parallel for reduction(+:n_upwind)
4896         for (int t_id = 0; t_id < n_i_threads; t_id++) {
4897           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4898                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4899                face_id++) {
4900 
4901             cs_lnum_t ii = i_face_cells[face_id][0];
4902             cs_lnum_t jj = i_face_cells[face_id][1];
4903 
4904             cs_real_t fluxi[3], fluxj[3] ;
4905             for (int isou =  0; isou < 3; isou++) {
4906               fluxi[isou] = 0;
4907               fluxj[isou] = 0;
4908             }
4909             cs_real_3_t pip, pjp, pipr, pjpr;
4910             cs_real_3_t pifri, pifrj, pjfri, pjfrj;
4911             bool upwind_switch = false;
4912             cs_real_3_t _pi, _pj, _pia, _pja;
4913 
4914             for (int i = 0; i < 3; i++) {
4915               _pi[i]  = _pvar[ii][i];
4916               _pj[i]  = _pvar[jj][i];
4917               _pia[i] = pvara[ii][i];
4918               _pja[i] = pvara[jj][i];
4919             }
4920 
4921             /* Scaling due to mass balance in porous modelling */
4922             if (i_f_face_factor != NULL) {
4923               cs_real_3_t n;
4924               cs_math_3_normalise(i_face_normal[face_id], n);
4925 
4926               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
4927               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pia);
4928               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
4929               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pja);
4930             }
4931 
4932             cs_real_t bldfrp = (cs_real_t) ircflp;
4933             /* Local limitation of the reconstruction */
4934             if (df_limiter != NULL && ircflp > 0)
4935               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
4936 
4937             cs_i_cd_steady_slope_test_vector(&upwind_switch,
4938                                              iconvp,
4939                                              bldfrp,
4940                                              ischcp,
4941                                              relaxp,
4942                                              blencp,
4943                                              blend_st,
4944                                              weight[face_id],
4945                                              i_dist[face_id],
4946                                              i_face_surf[face_id],
4947                                              cell_cen[ii],
4948                                              cell_cen[jj],
4949                                              i_face_normal[face_id],
4950                                              i_face_cog[face_id],
4951                                              diipf[face_id],
4952                                              djjpf[face_id],
4953                                              i_massflux[face_id],
4954                                              (const cs_real_3_t *)grad[ii],
4955                                              (const cs_real_3_t *)grad[jj],
4956                                              (const cs_real_3_t *)grdpa[ii],
4957                                              (const cs_real_3_t *)grdpa[jj],
4958                                              _pi,
4959                                              _pj,
4960                                              _pia,
4961                                              _pja,
4962                                              pifri,
4963                                              pifrj,
4964                                              pjfri,
4965                                              pjfrj,
4966                                              pip,
4967                                              pjp,
4968                                              pipr,
4969                                              pjpr);
4970 
4971             cs_i_conv_flux_vector(iconvp,
4972                                   1.,
4973                                   1,
4974                                   _pvar[ii],
4975                                   _pvar[jj],
4976                                   pifri,
4977                                   pifrj,
4978                                   pjfri,
4979                                   pjfrj,
4980                                   i_massflux[face_id],
4981                                   fluxi,
4982                                   fluxj);
4983 
4984 
4985             cs_i_diff_flux_vector(idiffp,
4986                                   1.,
4987                                   pip,
4988                                   pjp,
4989                                   pipr,
4990                                   pjpr,
4991                                   i_visc[face_id],
4992                                   fluxi,
4993                                   fluxj);
4994 
4995             for (int isou = 0; isou < 3; isou++) {
4996               rhs[ii][isou] -= fluxi[isou];
4997               rhs[jj][isou] += fluxj[isou];
4998             }
4999 
5000           }
5001         }
5002       }
5003 
5004       /* Unsteady */
5005     } else {
5006 
5007       for (int g_id = 0; g_id < n_i_groups; g_id++) {
5008 #       pragma omp parallel for reduction(+:n_upwind)
5009         for (int t_id = 0; t_id < n_i_threads; t_id++) {
5010           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
5011                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
5012                face_id++) {
5013 
5014             cs_lnum_t ii = i_face_cells[face_id][0];
5015             cs_lnum_t jj = i_face_cells[face_id][1];
5016 
5017             cs_real_t fluxi[3], fluxj[3] ;
5018             for (int isou =  0; isou < 3; isou++) {
5019               fluxi[isou] = 0;
5020               fluxj[isou] = 0;
5021             }
5022             cs_real_3_t pip, pjp;
5023             cs_real_3_t pif, pjf;
5024             bool upwind_switch = false;
5025             cs_real_3_t _pi, _pj;
5026 
5027             for (int i = 0; i < 3; i++) {
5028               _pi[i]  = _pvar[ii][i];
5029               _pj[i]  = _pvar[jj][i];
5030             }
5031 
5032             /* Scaling due to mass balance in porous modelling */
5033             if (i_f_face_factor != NULL) {
5034               cs_real_3_t n;
5035               cs_math_3_normalise(i_face_normal[face_id], n);
5036 
5037               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][0], _pi);
5038               cs_math_3_normal_scaling(n, i_f_face_factor[face_id][1], _pj);
5039             }
5040 
5041             cs_real_t bldfrp = (cs_real_t) ircflp;
5042             /* Local limitation of the reconstruction */
5043             if (df_limiter != NULL && ircflp > 0)
5044               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
5045 
5046             cs_i_cd_unsteady_slope_test_vector(&upwind_switch,
5047                                                iconvp,
5048                                                bldfrp,
5049                                                ischcp,
5050                                                blencp,
5051                                                blend_st,
5052                                                weight[face_id],
5053                                                i_dist[face_id],
5054                                                i_face_surf[face_id],
5055                                                cell_cen[ii],
5056                                                cell_cen[jj],
5057                                                i_face_normal[face_id],
5058                                                i_face_cog[face_id],
5059                                                diipf[face_id],
5060                                                djjpf[face_id],
5061                                                i_massflux[face_id],
5062                                                (const cs_real_3_t *)grad[ii],
5063                                                (const cs_real_3_t *)grad[jj],
5064                                                (const cs_real_3_t *)grdpa[ii],
5065                                                (const cs_real_3_t *)grdpa[jj],
5066                                                _pi,
5067                                                _pj,
5068                                                pif,
5069                                                pjf,
5070                                                pip,
5071                                                pjp);
5072 
5073             cs_i_conv_flux_vector(iconvp,
5074                                   thetap,
5075                                   imasac,
5076                                   _pvar[ii],
5077                                   _pvar[jj],
5078                                   pif,
5079                                   pif, /* no relaxation */
5080                                   pjf,
5081                                   pjf, /* no relaxation */
5082                                   i_massflux[face_id],
5083                                   fluxi,
5084                                   fluxj);
5085 
5086 
5087             cs_i_diff_flux_vector(idiffp,
5088                                   thetap,
5089                                   pip,
5090                                   pjp,
5091                                   pip, /* no relaxation */
5092                                   pjp, /* no relaxation */
5093                                   i_visc[face_id],
5094                                   fluxi,
5095                                   fluxj);
5096 
5097             if (upwind_switch) {
5098 
5099               /* in parallel, face will be counted by one and only one rank */
5100               if (ii < n_cells)
5101                 n_upwind++;
5102 
5103               if (v_slope_test != NULL) {
5104                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
5105                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
5106               }
5107             }
5108 
5109             for (int isou = 0; isou < 3; isou++) {
5110 
5111               rhs[ii][isou] -= fluxi[isou];
5112               rhs[jj][isou] += fluxj[isou];
5113 
5114             } /* isou */
5115 
5116           }
5117         }
5118       }
5119 
5120     } /* idtvar */
5121 
5122   } /* iupwin */
5123 
5124   if (iwarnp >= 2 && iconvp == 1) {
5125 
5126     /* Sum number of clippings */
5127     cs_parall_counter(&n_upwind, 1);
5128 
5129     bft_printf(_(" %s: %llu Faces with upwind on %llu interior faces\n"),
5130                var_name, (unsigned long long)n_upwind,
5131                (unsigned long long)m->n_g_i_c_faces);
5132   }
5133 
5134   /* ======================================================================
5135      ---> Contribution from boundary faces
5136      ======================================================================*/
5137 
5138   /* Boundary convective flux are all computed with an upwind scheme */
5139   if (icvflb == 0) {
5140 
5141     /* Steady */
5142     if (idtvar < 0) {
5143 
5144       for (int g_id = 0; g_id < n_b_groups; g_id++) {
5145 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5146         for (int t_id = 0; t_id < n_b_threads; t_id++) {
5147           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5148                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5149                face_id++) {
5150 
5151             cs_lnum_t ii = b_face_cells[face_id];
5152 
5153             cs_real_t fluxi[3] ;
5154             for (int isou =  0; isou < 3; isou++) {
5155               fluxi[isou] = 0;
5156             }
5157             cs_real_3_t pir, pipr;
5158             cs_real_3_t _pi, _pia;
5159 
5160             for (int i = 0; i < 3; i++) {
5161               _pi[i]  = _pvar[ii][i];
5162               _pia[i] = pvara[ii][i];
5163             }
5164 
5165             /* Scaling due to mass balance in porous modelling */
5166             if (b_f_face_factor != NULL) {
5167               cs_real_3_t n;
5168               cs_math_3_normalise(b_face_normal[face_id], n);
5169 
5170               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pi);
5171               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pia);
5172             }
5173 
5174             cs_real_t bldfrp = (cs_real_t) ircflp;
5175             /* Local limitation of the reconstruction */
5176             if (df_limiter != NULL && ircflp > 0)
5177               bldfrp = CS_MAX(df_limiter[ii], 0.);
5178 
5179             cs_b_cd_steady_vector(bldfrp,
5180                                   relaxp,
5181                                   diipb[face_id],
5182                                   (const cs_real_3_t *)grad[ii],
5183                                   _pi,
5184                                   _pia,
5185                                   pir,
5186                                   pipr);
5187 
5188             cs_b_upwind_flux_vector(iconvp,
5189                                     1., /* thetap */
5190                                     1, /* imasac */
5191                                     inc,
5192                                     bc_type[face_id],
5193                                     _pi,
5194                                     pir,
5195                                     pipr,
5196                                     coefav[face_id],
5197                                     coefbv[face_id],
5198                                     b_massflux[face_id],
5199                                     fluxi);
5200 
5201             cs_b_diff_flux_vector(idiffp,
5202                                   1., /* thetap */
5203                                   inc,
5204                                   pipr,
5205                                   cofafv[face_id],
5206                                   cofbfv[face_id],
5207                                   b_visc[face_id],
5208                                   fluxi);
5209 
5210             for (int isou = 0; isou < 3; isou++) {
5211               rhs[ii][isou] -= fluxi[isou];
5212             } /* isou */
5213 
5214           }
5215         }
5216       }
5217 
5218       if (icoupl > 0) {
5219         /* Prepare data for sending */
5220         BFT_MALLOC(pvar_distant, n_distant, cs_real_3_t);
5221 
5222         for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
5223           cs_lnum_t face_id = faces_distant[ii];
5224           cs_lnum_t jj = b_face_cells[face_id];
5225 
5226           cs_real_3_t pip, pipr;
5227           cs_real_3_t _pj, _pja;
5228 
5229           for (int i = 0; i < 3; i++) {
5230             _pj[i]  = _pvar[jj][i];
5231             _pja[i]  = pvara[jj][i];
5232           }
5233 
5234           cs_real_t bldfrp = (cs_real_t) ircflp;
5235           /* Local limitation of the reconstruction */
5236           /* Note: to be treated exactly as a internal face, should be a bending
5237            * between the two cells... */
5238           if (df_limiter != NULL && ircflp > 0)
5239             bldfrp = CS_MAX(df_limiter[jj], 0.);
5240 
5241           /* Scaling due to mass balance in porous modelling */
5242           if (b_f_face_factor != NULL) {
5243             cs_real_3_t n;
5244             cs_math_3_normalise(b_face_normal[face_id], n);
5245 
5246             cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pj);
5247           }
5248 
5249           cs_b_cd_steady_vector(bldfrp,
5250                                 relaxp,
5251                                 diipb[face_id],
5252                                 (const cs_real_3_t *)grad[jj],
5253                                 _pj,
5254                                 _pja,
5255                                 pip,
5256                                 pipr);
5257 
5258           for (int k = 0; k < 3; k++)
5259             pvar_distant[ii][k] = pipr[k];
5260         }
5261 
5262         /* Receive data */
5263         BFT_MALLOC(pvar_local, n_local, cs_real_3_t);
5264         cs_internal_coupling_exchange_var(cpl,
5265                                           3, /* Dimension */
5266                                           (cs_real_t *)pvar_distant,
5267                                           (cs_real_t *)pvar_local);
5268 
5269         if (df_limiter != NULL) {
5270           BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
5271           cs_internal_coupling_exchange_var(cpl,
5272                                             1, /* Dimension */
5273                                             df_limiter,
5274                                             df_limiter_local);
5275         }
5276 
5277         /* Flux contribution */
5278         assert(f != NULL);
5279         cs_real_t *hintp = f->bc_coeffs->hint;
5280         cs_real_t *hextp = f->bc_coeffs->hext;
5281         for (cs_lnum_t ii = 0; ii < n_local; ii++) {
5282           cs_lnum_t face_id = faces_local[ii];
5283           cs_lnum_t jj = b_face_cells[face_id];
5284           cs_real_t pip[3], pipr[3], pjpr[3];
5285           cs_real_t fluxi[3] = {0., 0., 0.};
5286           cs_real_3_t _pj, _pja;
5287 
5288           for (cs_lnum_t i = 0; i < 3; i++) {
5289             _pj[i]  = _pvar[jj][i];
5290             _pja[i]  = pvara[jj][i];
5291           }
5292 
5293           /* Scaling due to mass balance in porous modelling */
5294           if (b_f_face_factor != NULL) {
5295             cs_real_3_t n;
5296             cs_math_3_normalise(b_face_normal[face_id], n);
5297 
5298             cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pj);
5299           }
5300 
5301           cs_real_t bldfrp = (cs_real_t) ircflp;
5302           /* Local limitation of the reconstruction */
5303           if (df_limiter != NULL && ircflp > 0)
5304             bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
5305 
5306           cs_b_cd_steady_vector(bldfrp,
5307                                 relaxp,
5308                                 diipb[face_id],
5309                                 (const cs_real_3_t *)grad[jj],
5310                                 _pj,
5311                                 _pja,
5312                                 pip,
5313                                 pipr);
5314 
5315           for (cs_lnum_t k = 0; k < 3; k++)
5316             pjpr[k] = pvar_local[ii][k];
5317 
5318           cs_real_t hint = hintp[face_id];
5319           cs_real_t hext = hextp[face_id];
5320           cs_real_t heq = _calc_heq(hint, hext);
5321 
5322           cs_b_diff_flux_coupling_vector(idiffp,
5323                                          pipr,
5324                                          pjpr,
5325                                          heq,
5326                                          fluxi);
5327 
5328           for (int k = 0; k < 3; k++)
5329             rhs[jj][k] -= thetap * fluxi[k];
5330         }
5331 
5332         BFT_FREE(pvar_local);
5333         /* Sending structures are no longer needed */
5334         BFT_FREE(pvar_distant);
5335         if (df_limiter != NULL) {
5336           BFT_FREE(df_limiter_local);
5337         }
5338       }
5339 
5340       /* Unsteady */
5341     } else {
5342 
5343       for (int g_id = 0; g_id < n_b_groups; g_id++) {
5344 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5345         for (int t_id = 0; t_id < n_b_threads; t_id++) {
5346           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5347                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5348                face_id++) {
5349 
5350             cs_lnum_t ii = b_face_cells[face_id];
5351 
5352             cs_real_t fluxi[3] ;
5353             for (int isou =  0; isou < 3; isou++) {
5354               fluxi[isou] = 0;
5355             }
5356             cs_real_3_t pip;
5357             cs_real_3_t _pi;
5358 
5359             for (int i = 0; i < 3; i++) {
5360               _pi[i]  = _pvar[ii][i];
5361             }
5362 
5363             /* Scaling due to mass balance in porous modelling */
5364             if (b_f_face_factor != NULL) {
5365               cs_real_3_t n;
5366               cs_math_3_normalise(b_face_normal[face_id], n);
5367 
5368               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pi);
5369             }
5370 
5371             cs_real_t bldfrp = (cs_real_t) ircflp;
5372             /* Local limitation of the reconstruction */
5373             if (df_limiter != NULL && ircflp > 0)
5374               bldfrp = CS_MAX(df_limiter[ii], 0.);
5375 
5376             cs_b_cd_unsteady_vector(bldfrp,
5377                                     diipb[face_id],
5378                                     (const cs_real_3_t *)grad[ii],
5379                                     _pi,
5380                                     pip);
5381 
5382             cs_b_upwind_flux_vector(iconvp,
5383                                     thetap,
5384                                     imasac,
5385                                     inc,
5386                                     bc_type[face_id],
5387                                     _pi,
5388                                     _pi, /* no relaxation */
5389                                     pip,
5390                                     coefav[face_id],
5391                                     coefbv[face_id],
5392                                     b_massflux[face_id],
5393                                     fluxi);
5394 
5395             cs_b_diff_flux_vector(idiffp,
5396                                   thetap,
5397                                   inc,
5398                                   pip,
5399                                   cofafv[face_id],
5400                                   cofbfv[face_id],
5401                                   b_visc[face_id],
5402                                   fluxi);
5403 
5404             for(int isou = 0; isou < 3; isou++) {
5405               rhs[ii][isou] -= fluxi[isou];
5406             }
5407 
5408           }
5409         }
5410       }
5411 
5412       /* The variable is internally coupled and an implicit contribution
5413        * is required */
5414       if (icoupl > 0) {
5415         /* Prepare data for sending */
5416         BFT_MALLOC(pvar_distant, n_distant, cs_real_3_t);
5417 
5418         for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
5419           cs_lnum_t face_id = faces_distant[ii];
5420           cs_lnum_t jj = b_face_cells[face_id];
5421 
5422           cs_real_3_t pip;
5423           cs_real_3_t _pj;
5424 
5425           for (int i = 0; i < 3; i++) {
5426             _pj[i]  = _pvar[jj][i];
5427           }
5428 
5429           cs_real_t bldfrp = (cs_real_t) ircflp;
5430           /* Local limitation of the reconstruction */
5431           /* Note: to be treated exactly as a internal face, should be a bending
5432            * between the two cells... */
5433           if (df_limiter != NULL && ircflp > 0)
5434             bldfrp = CS_MAX(df_limiter[jj], 0.);
5435 
5436           /* Scaling due to mass balance in porous modelling */
5437           if (b_f_face_factor != NULL) {
5438             cs_real_3_t n;
5439             cs_math_3_normalise(b_face_normal[face_id], n);
5440 
5441             cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pj);
5442           }
5443 
5444           cs_b_cd_unsteady_vector(bldfrp,
5445                                   diipb[face_id],
5446                                   (const cs_real_3_t *)grad[jj],
5447                                   _pj,
5448                                   pip);
5449 
5450           for (int k = 0; k < 3; k++)
5451             pvar_distant[ii][k] = pip[k];
5452         }
5453 
5454         /* Receive data */
5455         BFT_MALLOC(pvar_local, n_local, cs_real_3_t);
5456         cs_internal_coupling_exchange_var(cpl,
5457                                           3, /* Dimension */
5458                                           (cs_real_t *)pvar_distant,
5459                                           (cs_real_t *)pvar_local);
5460 
5461         if (df_limiter != NULL) {
5462           BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
5463           cs_internal_coupling_exchange_var(cpl,
5464                                             1, /* Dimension */
5465                                             df_limiter,
5466                                             df_limiter_local);
5467         }
5468 
5469         /* Flux contribution */
5470         assert(f != NULL);
5471         cs_real_t *hintp = f->bc_coeffs->hint;
5472         cs_real_t *hextp = f->bc_coeffs->hext;
5473         for (cs_lnum_t ii = 0; ii < n_local; ii++) {
5474           cs_lnum_t face_id = faces_local[ii];
5475           cs_lnum_t jj = b_face_cells[face_id];
5476           cs_real_t pip[3], pjp[3];
5477           cs_real_t fluxi[3] = {0., 0., 0.};
5478           cs_real_3_t _pj;
5479 
5480           for (int i = 0; i < 3; i++) {
5481             _pj[i]  = _pvar[jj][i];
5482           }
5483 
5484           /* Scaling due to mass balance in porous modelling */
5485           if (b_f_face_factor != NULL) {
5486             cs_real_3_t n;
5487             cs_math_3_normalise(b_face_normal[face_id], n);
5488 
5489             cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pj);
5490           }
5491 
5492           cs_real_t bldfrp = (cs_real_t) ircflp;
5493           /* Local limitation of the reconstruction */
5494           if (df_limiter != NULL && ircflp > 0)
5495             bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
5496 
5497           cs_b_cd_unsteady_vector(bldfrp,
5498                                   diipb[face_id],
5499                                   (const cs_real_3_t *)grad[jj],
5500                                   _pj,
5501                                   pip);
5502 
5503           for (int k = 0; k < 3; k++)
5504             pjp[k] = pvar_local[ii][k];
5505 
5506           cs_real_t hint = hintp[face_id];
5507           cs_real_t hext = hextp[face_id];
5508           cs_real_t heq = _calc_heq(hint, hext);
5509 
5510           cs_b_diff_flux_coupling_vector(idiffp,
5511                                          pip,
5512                                          pjp,
5513                                          heq,
5514                                          fluxi);
5515 
5516           for (int k = 0; k < 3; k++)
5517             rhs[jj][k] -= thetap * fluxi[k];
5518         }
5519 
5520         BFT_FREE(pvar_local);
5521         /* Sending structures are no longer needed */
5522         BFT_FREE(pvar_distant);
5523         if (df_limiter != NULL) {
5524           BFT_FREE(df_limiter_local);
5525         }
5526       }
5527     } /* idtvar */
5528 
5529     /* Boundary convective flux imposed at some faces (tags in icvfli array) */
5530   } else if (icvflb == 1) {
5531 
5532     /* Retrieve the value of the convective flux to be imposed */
5533     if (f_id != -1) {
5534       coface = (const cs_real_3_t *)(f->bc_coeffs->ac);
5535       cofbce = (const cs_real_33_t *)(f->bc_coeffs->bc);
5536     } else {
5537       bft_error(__FILE__, __LINE__, 0,
5538                 _("invalid value of icvflb and f_id"));
5539     }
5540 
5541     /* Steady */
5542     if (idtvar < 0) {
5543 
5544       for (int g_id = 0; g_id < n_b_groups; g_id++) {
5545 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5546         for (int t_id = 0; t_id < n_b_threads; t_id++) {
5547           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5548                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5549                face_id++) {
5550 
5551             cs_lnum_t ii = b_face_cells[face_id];
5552 
5553             cs_real_t fluxi[3], pir[3], pipr[3];
5554 
5555             for (int isou =  0; isou < 3; isou++) {
5556               fluxi[isou] = 0;
5557             }
5558             cs_real_3_t _pi, _pia;
5559 
5560             for (int i = 0; i < 3; i++) {
5561               _pi[i]  = _pvar[ii][i];
5562               _pia[i] = pvara[ii][i];
5563             }
5564 
5565             /* Scaling due to mass balance in porous modelling */
5566             if (b_f_face_factor != NULL) {
5567               cs_real_3_t n;
5568               cs_math_3_normalise(b_face_normal[face_id], n);
5569 
5570               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pi);
5571               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pia);
5572             }
5573 
5574             cs_real_t bldfrp = (cs_real_t) ircflp;
5575             /* Local limitation of the reconstruction */
5576             if (df_limiter != NULL && ircflp > 0)
5577               bldfrp = CS_MAX(df_limiter[ii], 0.);
5578 
5579             cs_b_cd_steady_vector(bldfrp,
5580                                   relaxp,
5581                                   diipb[face_id],
5582                                   (const cs_real_3_t *)grad[ii],
5583                                   _pi,
5584                                   _pia,
5585                                   pir,
5586                                   pipr);
5587 
5588             cs_b_imposed_conv_flux_vector(iconvp,
5589                                           1., /* thetap */
5590                                           1., /* imasac */
5591                                           inc,
5592                                           bc_type[face_id],
5593                                           icvfli[face_id],
5594                                           _pvar[ii],
5595                                           pir,
5596                                           pipr,
5597                                           coefav[face_id],
5598                                           coefbv[face_id],
5599                                           coface[face_id],
5600                                           cofbce[face_id],
5601                                           b_massflux[face_id],
5602                                           fluxi);
5603 
5604             cs_b_diff_flux_vector(idiffp,
5605                                   1., /* thetap */
5606                                   inc,
5607                                   pipr,
5608                                   cofafv[face_id],
5609                                   cofbfv[face_id],
5610                                   b_visc[face_id],
5611                                   fluxi);
5612 
5613             for (int isou = 0; isou < 3; isou++) {
5614               rhs[ii][isou] -= fluxi[isou];
5615             }
5616 
5617           }
5618         }
5619       }
5620 
5621       /* Unsteady */
5622     } else {
5623 
5624       for (int g_id = 0; g_id < n_b_groups; g_id++) {
5625 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5626         for (int t_id = 0; t_id < n_b_threads; t_id++) {
5627           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5628                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5629                face_id++) {
5630 
5631             cs_lnum_t ii = b_face_cells[face_id];
5632 
5633             cs_real_t fluxi[3] ;
5634             for (int isou =  0; isou < 3; isou++) {
5635               fluxi[isou] = 0;
5636             }
5637             cs_real_3_t pip;
5638             cs_real_3_t _pi;
5639 
5640             for (int i = 0; i < 3; i++) {
5641               _pi[i]  = _pvar[ii][i];
5642             }
5643 
5644             /* Scaling due to mass balance in porous modelling */
5645             if (b_f_face_factor != NULL) {
5646               cs_real_3_t n;
5647               cs_math_3_normalise(b_face_normal[face_id], n);
5648 
5649               cs_math_3_normal_scaling(n, b_f_face_factor[face_id], _pi);
5650             }
5651 
5652             cs_real_t bldfrp = (cs_real_t) ircflp;
5653             /* Local limitation of the reconstruction */
5654             if (df_limiter != NULL && ircflp > 0)
5655               bldfrp = CS_MAX(df_limiter[ii], 0.);
5656 
5657             cs_b_cd_unsteady_vector(bldfrp,
5658                                     diipb[face_id],
5659                                     (const cs_real_3_t *)grad[ii],
5660                                     _pi,
5661                                     pip);
5662 
5663             cs_b_imposed_conv_flux_vector(iconvp,
5664                                           thetap,
5665                                           imasac,
5666                                           inc,
5667                                           bc_type[face_id],
5668                                           icvfli[face_id],
5669                                           _pvar[ii],
5670                                           _pvar[ii], /* no relaxation */
5671                                           pip,
5672                                           coefav[face_id],
5673                                           coefbv[face_id],
5674                                           coface[face_id],
5675                                           cofbce[face_id],
5676                                           b_massflux[face_id],
5677                                           fluxi);
5678 
5679             cs_b_diff_flux_vector(idiffp,
5680                                   thetap,
5681                                   inc,
5682                                   pip,
5683                                   cofafv[face_id],
5684                                   cofbfv[face_id],
5685                                   b_visc[face_id],
5686                                   fluxi);
5687 
5688             for (int isou = 0; isou < 3; isou++) {
5689               rhs[ii][isou] -= fluxi[isou];
5690             }
5691 
5692           }
5693         }
5694       }
5695 
5696     } /* idtvar */
5697 
5698   }
5699 
5700   /* 3. Computation of the transpose grad(vel) term and grad(-2/3 div(vel)) */
5701 
5702   if (ivisep == 1 && idiffp == 1) {
5703 
5704     /* We do not know what condition to put in the inlets and the outlets, so we
5705        assume that there is an equilibrium. Moreover, cells containing a coupled
5706        are removed. */
5707 
5708     /* Allocate a temporary array */
5709     BFT_MALLOC(bndcel, n_cells_ext, cs_real_t);
5710 
5711 #   pragma omp parallel for
5712     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++)
5713       bndcel[cell_id] = 1.;
5714 
5715 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5716     for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id++) {
5717       int ityp = bc_type[face_id];
5718       if (   ityp == CS_OUTLET
5719           || ityp == CS_INLET
5720           || ityp == CS_FREE_INLET
5721           || ityp == CS_CONVECTIVE_INLET
5722           || ityp == CS_COUPLED_FD)
5723         bndcel[b_face_cells[face_id]] = 0.;
5724     }
5725 
5726     if (halo != NULL)
5727       cs_halo_sync_var(halo, halo_type, bndcel);
5728 
5729     /* ---> Interior faces */
5730 
5731     for (int g_id = 0; g_id < n_i_groups; g_id++) {
5732 #     pragma omp parallel for
5733       for (int t_id = 0; t_id < n_i_threads; t_id++) {
5734         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
5735              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
5736              face_id++) {
5737 
5738           cs_lnum_t ii = i_face_cells[face_id][0];
5739           cs_lnum_t jj = i_face_cells[face_id][1];
5740 
5741           double pnd = weight[face_id];
5742           double secvis = i_secvis[face_id]; /* - 2/3 * mu */
5743           double visco = i_visc[face_id]; /* mu S_ij / d_ij */
5744 
5745           double grdtrv =      pnd*(grad[ii][0][0]+grad[ii][1][1]+grad[ii][2][2])
5746                  + (1.-pnd)*(grad[jj][0][0]+grad[jj][1][1]+grad[jj][2][2]);
5747 
5748           cs_real_3_t n, ipjp;
5749           cs_math_3_normalise(i_face_normal[face_id], n);
5750 
5751           /* I'J' */
5752           for (int i = 0; i < 3; i++)
5753             ipjp[i] = n[i] * i_dist[face_id];
5754 
5755           /* We need to compute trans_grad(u).I'J' which is equal to I'J'.grad(u) */
5756           for (int isou = 0; isou < 3; isou++) {
5757 
5758             double tgrdfl = ipjp[0] * (      pnd*grad[ii][0][isou]
5759                                       + (1.-pnd)*grad[jj][0][isou])
5760                           + ipjp[1] * (      pnd*grad[ii][1][isou]
5761                                       + (1.-pnd)*grad[jj][1][isou])
5762                           + ipjp[2] * (      pnd*grad[ii][2][isou]
5763                                       + (1.-pnd)*grad[jj][2][isou]);
5764 
5765             double flux = visco*tgrdfl + secvis*grdtrv*i_f_face_normal[face_id][isou];
5766 
5767             rhs[ii][isou] += thetap * flux*bndcel[ii];
5768             rhs[jj][isou] -= thetap * flux*bndcel[jj];
5769 
5770           }
5771 
5772         }
5773       }
5774     }
5775 
5776     /* ---> Boundary FACES
5777        the whole flux term of the stress tensor is already taken into account
5778        (so, no corresponding term in forbr)
5779        TODO in theory we should take the normal component into account (the
5780        tangential one is modeled by the wall law) */
5781 
5782 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
5783     for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id++) {
5784       cs_lnum_t ii = b_face_cells[face_id];
5785 
5786       /* Trace of velocity gradient */
5787       double grdtrv = (grad[ii][0][0]+grad[ii][1][1]+grad[ii][2][2]);
5788       double secvis = b_secvis[face_id]; /* - 2/3 * mu */
5789 
5790       for (int isou = 0; isou < 3; isou++) {
5791 
5792         double flux = secvis*grdtrv*b_f_face_normal[face_id][isou];
5793         rhs[ii][isou] += thetap * flux * bndcel[ii];
5794 
5795       }
5796 
5797     }
5798 
5799     /*Free memory */
5800     BFT_FREE(bndcel);
5801 
5802   }
5803 
5804   /* Free memory */
5805   BFT_FREE(grdpa);
5806   BFT_FREE(grad);
5807 }
5808 
5809 /*----------------------------------------------------------------------------*/
5810 /*!
5811  * \brief Add the explicit part of the convection/diffusion terms of a transport
5812  *  equation of a vector field \f$ \vect{\varia} \f$.
5813  *
5814  * More precisely, the right hand side \f$ \vect{Rhs} \f$ is updated as
5815  * follows:
5816  * \f[
5817  *  \vect{Rhs} = \vect{Rhs} - \sum_{\fij \in \Facei{\celli}}      \left(
5818  *         \dot{m}_\ij \left( \vect{\varia}_\fij - \vect{\varia}_\celli \right)
5819  *       - \mu_\fij \gradt_\fij \vect{\varia} \cdot \vect{S}_\ij  \right)
5820  * \f]
5821  *
5822  * Warning:
5823  * - \f$ \vect{Rhs} \f$ has already been initialized before calling bilsc!
5824  * - mind the sign minus
5825  *
5826  * \param[in]     idtvar        indicator of the temporal scheme
5827  * \param[in]     f_id          index of the current variable
5828  * \param[in]     var_cal_opt   variable calculation options
5829  * \param[in]     icvflb        global indicator of boundary convection flux
5830  *                               - 0 upwind scheme at all boundary faces
5831  *                               - 1 imposed flux at some boundary faces
5832  * \param[in]     inc           indicator
5833  *                               - 0 when solving an increment
5834  *                               - 1 otherwise
5835  * \param[in]     imasac        take mass accumulation into account?
5836  * \param[in]     pvar          solved velocity (current time step)
5837  * \param[in]     pvara         solved velocity (previous time step)
5838  * \param[in]     coefa         boundary condition array for the variable
5839  *                               (Explicit part)
5840  * \param[in]     coefb         boundary condition array for the variable
5841  *                               (Implicit part)
5842  * \param[in]     cofaf         boundary condition array for the diffusion
5843  *                               of the variable (Explicit part)
5844  * \param[in]     cofbf         boundary condition array for the diffusion
5845  *                               of the variable (Implicit part)
5846  * \param[in]     i_massflux    mass flux at interior faces
5847  * \param[in]     b_massflux    mass flux at boundary faces
5848  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
5849  *                               at interior faces for the r.h.s.
5850  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
5851  *                               at border faces for the r.h.s.
5852  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
5853  */
5854 /*----------------------------------------------------------------------------*/
5855 
5856 void
cs_convection_diffusion_tensor(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int icvflb,int inc,int imasac,cs_real_6_t * restrict pvar,const cs_real_6_t * restrict pvara,const cs_real_6_t coefa[],const cs_real_66_t coefb[],const cs_real_6_t cofaf[],const cs_real_66_t cofbf[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict rhs)5857 cs_convection_diffusion_tensor(int                         idtvar,
5858                                int                         f_id,
5859                                const cs_var_cal_opt_t      var_cal_opt,
5860                                int                         icvflb,
5861                                int                         inc,
5862                                int                         imasac,
5863                                cs_real_6_t       *restrict pvar,
5864                                const cs_real_6_t *restrict pvara,
5865                                const cs_real_6_t           coefa[],
5866                                const cs_real_66_t          coefb[],
5867                                const cs_real_6_t           cofaf[],
5868                                const cs_real_66_t          cofbf[],
5869                                const cs_real_t             i_massflux[],
5870                                const cs_real_t             b_massflux[],
5871                                const cs_real_t             i_visc[],
5872                                const cs_real_t             b_visc[],
5873                                cs_real_6_t       *restrict rhs)
5874 {
5875   const int iconvp = var_cal_opt.iconv;
5876   const int idiffp = var_cal_opt.idiff;
5877   const int nswrgp = var_cal_opt.nswrgr;
5878   const int imrgra = var_cal_opt.imrgra;
5879   const int imligp = var_cal_opt.imligr;
5880   const int ircflp = var_cal_opt.ircflu;
5881   const int ischcp = var_cal_opt.ischcv;
5882   const int isstpp = var_cal_opt.isstpc;
5883   const int iwarnp = var_cal_opt.verbosity;
5884   const double blencp = var_cal_opt.blencv;
5885   const double blend_st = var_cal_opt.blend_st;
5886   const double epsrgp = var_cal_opt.epsrgr;
5887   const double climgp = var_cal_opt.climgr;
5888   const double relaxp = var_cal_opt.relaxv;
5889   const double thetap = var_cal_opt.thetav;
5890 
5891   const cs_mesh_t  *m = cs_glob_mesh;
5892   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
5893 
5894   const cs_lnum_t n_cells = m->n_cells;
5895   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
5896   const int n_i_groups = m->i_face_numbering->n_groups;
5897   const int n_i_threads = m->i_face_numbering->n_threads;
5898   const int n_b_groups = m->b_face_numbering->n_groups;
5899   const int n_b_threads = m->b_face_numbering->n_threads;
5900   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
5901   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
5902 
5903   const cs_lnum_2_t *restrict i_face_cells
5904     = (const cs_lnum_2_t *restrict)m->i_face_cells;
5905   const cs_lnum_t *restrict b_face_cells
5906     = (const cs_lnum_t *restrict)m->b_face_cells;
5907   const cs_real_t *restrict weight = fvq->weight;
5908   const cs_real_t *restrict i_dist = fvq->i_dist;
5909   const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
5910   const cs_real_t *restrict cell_vol = fvq->cell_vol;
5911   const cs_real_3_t *restrict cell_cen
5912     = (const cs_real_3_t *restrict)fvq->cell_cen;
5913   const cs_real_3_t *restrict i_face_normal
5914     = (const cs_real_3_t *restrict)fvq->i_face_normal;
5915   const cs_real_3_t *restrict i_face_cog
5916     = (const cs_real_3_t *restrict)fvq->i_face_cog;
5917   const cs_real_3_t *restrict diipf
5918     = (const cs_real_3_t *restrict)fvq->diipf;
5919   const cs_real_3_t *restrict djjpf
5920     = (const cs_real_3_t *restrict)fvq->djjpf;
5921   const cs_real_3_t *restrict diipb
5922     = (const cs_real_3_t *restrict)fvq->diipb;
5923 
5924   cs_real_t *df_limiter = NULL;
5925 
5926   const int *bc_type = cs_glob_bc_type;
5927 
5928   /* Local variables */
5929 
5930   char var_name[64];
5931 
5932   cs_gnum_t n_upwind;
5933   int iupwin;
5934 
5935   cs_real_63_t *grad, *grdpa;
5936 
5937   cs_field_t *f;
5938 
5939   cs_real_t  *v_slope_test = cs_get_v_slope_test(f_id, var_cal_opt);
5940 
5941   /*==========================================================================*/
5942 
5943   /* 1. Initialization */
5944 
5945   /* Allocate work arrays */
5946 
5947   BFT_MALLOC(grad, n_cells_ext, cs_real_63_t);
5948   BFT_MALLOC(grdpa, n_cells_ext, cs_real_63_t);
5949 
5950   /* Choose gradient type */
5951 
5952   cs_halo_type_t halo_type = CS_HALO_STANDARD;
5953   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
5954 
5955   cs_gradient_type_by_imrgra(imrgra,
5956                              &gradient_type,
5957                              &halo_type);
5958 
5959   /* Handle cases where only the previous values (already synchronized)
5960      or current values are provided */
5961 
5962   if (pvar != NULL && m->halo != NULL) {
5963     cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)pvar, 6);
5964     if (cs_glob_mesh->n_init_perio > 0)
5965       cs_halo_perio_sync_var_sym_tens(m->halo, halo_type, (cs_real_t *)pvar);
5966   }
5967   if (pvara == NULL)
5968     pvara = (const cs_real_6_t *restrict)pvar;
5969 
5970   const cs_real_6_t  *restrict _pvar
5971     = (pvar != NULL) ? (const cs_real_6_t  *restrict)pvar : pvara;
5972 
5973   /* Logging info */
5974 
5975   if (f_id != -1) {
5976     f = cs_field_by_id(f_id);
5977 
5978     int df_limiter_id =
5979       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
5980     if (df_limiter_id > -1)
5981       df_limiter = cs_field_by_id(df_limiter_id)->val;
5982 
5983     snprintf(var_name, 63, "%s", f->name);
5984   }
5985   else
5986     strncpy(var_name, "[convection-diffusion, tensor]", 63);
5987   var_name[63] = '\0';
5988 
5989   if (iwarnp >= 2 && iconvp == 1) {
5990     if (ischcp == 1) {
5991       bft_printf
5992         (
5993          _(" %s: Convection in centered blending with %f percent of upwind\n"),
5994          var_name, (1.-blencp)*100.);
5995     } else {
5996       bft_printf
5997         (
5998          _(" %s: Convection in 2nd order blending with %f percent of upwind\n"),
5999          var_name, (1.-blencp)*100.);
6000     }
6001   }
6002 
6003   iupwin = (blencp > 0.) ? 0 : 1;
6004 
6005   /* 2. Compute the balance with reconstruction */
6006 
6007   /* Compute the gradient of the velocity
6008 
6009      The gradient (grad) is used in the flux reconstruction and the slope test.
6010      Thus we must compute it:
6011          - when we have diffusion and we reconstruct the fluxes,
6012          - when the convection scheme is SOLU,
6013          - when we have convection, we are not in pure upwind
6014            and we reconstruct the fluxes,
6015          - when we have convection, we are not in pure upwind
6016            and we have not shunted the slope test. */
6017 
6018   if (  (idiffp != 0 && ircflp == 1)
6019      || (   iconvp != 0 && iupwin == 0
6020          && (ischcp == 0 || ircflp == 1 || isstpp == 0))) {
6021 
6022     cs_gradient_tensor_synced_input(var_name,
6023                                     gradient_type,
6024                                     halo_type,
6025                                     inc,
6026                                     nswrgp,
6027                                     iwarnp,
6028                                     imligp,
6029                                     epsrgp,
6030                                     climgp,
6031                                     coefa,
6032                                     coefb,
6033                                     _pvar,
6034                                     grad);
6035 
6036   } else {
6037 #   pragma omp parallel for
6038     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
6039       for (int isou = 0; isou < 6; isou++) {
6040         for (int jsou = 0; jsou < 3; jsou++)
6041           grad[cell_id][isou][jsou] = 0.;
6042       }
6043     }
6044   }
6045 
6046   /* ======================================================================
6047      ---> Compute uncentered gradient grdpa for the slope test
6048      ======================================================================*/
6049 
6050 # pragma omp parallel for
6051   for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
6052     for (int jsou = 0; jsou < 3; jsou++) {
6053       for (int isou = 0; isou < 6; isou++)
6054         grdpa[cell_id][isou][jsou] = 0.;
6055     }
6056   }
6057 
6058   if (iconvp > 0 && iupwin == 0 && isstpp == 0) {
6059 
6060     cs_slope_test_gradient_tensor(inc,
6061                                   halo_type,
6062                                   (const cs_real_63_t *)grad,
6063                                   grdpa,
6064                                   _pvar,
6065                                   coefa,
6066                                   coefb,
6067                                   i_massflux);
6068 
6069   }
6070 
6071   /* ======================================================================
6072      ---> Contribution from interior faces
6073      ======================================================================*/
6074 
6075   n_upwind = 0;
6076 
6077   if (n_cells_ext > n_cells) {
6078 #   pragma omp parallel for
6079     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
6080       for (int isou = 0; isou < 6; isou++)
6081         rhs[cell_id][isou] = 0.;
6082     }
6083   }
6084 
6085   /* --> Pure upwind flux
6086      =====================*/
6087 
6088   if (iupwin == 1) {
6089 
6090     /* Steady */
6091     if (idtvar < 0) {
6092 
6093       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6094 #       pragma omp parallel for reduction(+:n_upwind)
6095         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6096           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6097                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6098                face_id++) {
6099 
6100             cs_lnum_t ii = i_face_cells[face_id][0];
6101             cs_lnum_t jj = i_face_cells[face_id][1];
6102 
6103             /* in parallel, face will be counted by one and only one rank */
6104             if (ii < n_cells) {
6105               n_upwind++;
6106             }
6107             double fluxi[6], fluxj[6] ;
6108             for (int isou =  0; isou < 6; isou++) {
6109               fluxi[isou] = 0;
6110               fluxj[isou] = 0;
6111             }
6112             cs_real_6_t pip, pjp, pipr, pjpr;
6113             cs_real_6_t pifri, pifrj, pjfri, pjfrj;
6114 
6115             cs_real_t bldfrp = (cs_real_t) ircflp;
6116             /* Local limitation of the reconstruction */
6117             if (df_limiter != NULL && ircflp > 0)
6118               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6119 
6120             cs_i_cd_steady_upwind_tensor(bldfrp,
6121                                          relaxp,
6122                                          diipf[face_id],
6123                                          djjpf[face_id],
6124                                          (const cs_real_3_t *)grad[ii],
6125                                          (const cs_real_3_t *)grad[jj],
6126                                          _pvar[ii],
6127                                          _pvar[jj],
6128                                          pvara[ii],
6129                                          pvara[jj],
6130                                          pifri,
6131                                          pifrj,
6132                                          pjfri,
6133                                          pjfrj,
6134                                          pip,
6135                                          pjp,
6136                                          pipr,
6137                                          pjpr);
6138 
6139 
6140             cs_i_conv_flux_tensor(iconvp,
6141                                   1.,
6142                                   1,
6143                                   _pvar[ii],
6144                                   _pvar[jj],
6145                                   pifri,
6146                                   pifrj,
6147                                   pjfri,
6148                                   pjfrj,
6149                                   i_massflux[face_id],
6150                                   fluxi,
6151                                   fluxj);
6152 
6153 
6154             cs_i_diff_flux_tensor(idiffp,
6155                                   1.,
6156                                   pip,
6157                                   pjp,
6158                                   pipr,
6159                                   pjpr,
6160                                   i_visc[face_id],
6161                                   fluxi,
6162                                   fluxj);
6163 
6164            for (int isou = 0; isou < 6; isou++) {
6165               rhs[ii][isou] -= fluxi[isou];
6166               rhs[jj][isou] += fluxj[isou];
6167             }
6168 
6169           }
6170         }
6171       }
6172 
6173     /* Unsteady */
6174     } else {
6175 
6176       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6177 #       pragma omp parallel for reduction(+:n_upwind)
6178         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6179           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6180                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6181                face_id++) {
6182 
6183             cs_lnum_t ii = i_face_cells[face_id][0];
6184             cs_lnum_t jj = i_face_cells[face_id][1];
6185 
6186             /* in parallel, face will be counted by one and only one rank */
6187             if (ii < n_cells) {
6188               n_upwind++;
6189             }
6190             double fluxi[6], fluxj[6] ;
6191             for (int isou =  0; isou < 6; isou++) {
6192               fluxi[isou] = 0;
6193               fluxj[isou] = 0;
6194             }
6195             cs_real_6_t pip, pjp;
6196             cs_real_6_t pif, pjf;
6197 
6198             cs_real_t bldfrp = (cs_real_t) ircflp;
6199             /* Local limitation of the reconstruction */
6200             if (df_limiter != NULL && ircflp > 0)
6201               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6202 
6203             cs_i_cd_unsteady_upwind_tensor(bldfrp,
6204                                            diipf[face_id],
6205                                            djjpf[face_id],
6206                                            (const cs_real_3_t *)grad[ii],
6207                                            (const cs_real_3_t *)grad[jj],
6208                                            _pvar[ii],
6209                                            _pvar[jj],
6210                                            pif,
6211                                            pjf,
6212                                            pip,
6213                                            pjp);
6214 
6215             cs_i_conv_flux_tensor(iconvp,
6216                                   thetap,
6217                                   imasac,
6218                                   _pvar[ii],
6219                                   _pvar[jj],
6220                                   pif,
6221                                   pif, /* no relaxation */
6222                                   pjf,
6223                                   pjf, /* no relaxation */
6224                                   i_massflux[face_id],
6225                                   fluxi,
6226                                   fluxj);
6227 
6228 
6229             cs_i_diff_flux_tensor(idiffp,
6230                                   thetap,
6231                                   pip,
6232                                   pjp,
6233                                   pip, /* no relaxation */
6234                                   pjp, /* no relaxation */
6235                                   i_visc[face_id],
6236                                   fluxi,
6237                                   fluxj);
6238 
6239             for (int isou = 0; isou < 6; isou++) {
6240 
6241               rhs[ii][isou] -= fluxi[isou];
6242               rhs[jj][isou] += fluxj[isou];
6243             }
6244 
6245           }
6246         }
6247       }
6248 
6249     }
6250 
6251     /* --> Flux with no slope test
6252        ============================*/
6253 
6254   } else if (isstpp == 1) {
6255 
6256     if (ischcp < 0 || ischcp > 1) {
6257       bft_error(__FILE__, __LINE__, 0,
6258                 _("invalid value of ischcp"));
6259     }
6260 
6261     /* Steady */
6262     if (idtvar < 0) {
6263 
6264       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6265 #       pragma omp parallel for
6266 
6267         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6268           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6269                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6270                face_id++) {
6271 
6272             cs_lnum_t ii = i_face_cells[face_id][0];
6273             cs_lnum_t jj = i_face_cells[face_id][1];
6274 
6275             double fluxi[6], fluxj[6] ;
6276             for (int isou =  0; isou < 6; isou++) {
6277               fluxi[isou] = 0;
6278               fluxj[isou] = 0;
6279             }
6280             cs_real_6_t pip, pjp, pipr, pjpr;
6281             cs_real_6_t pifri, pifrj, pjfri, pjfrj;
6282 
6283             cs_real_t bldfrp = (cs_real_t) ircflp;
6284             /* Local limitation of the reconstruction */
6285             if (df_limiter != NULL && ircflp > 0)
6286               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6287 
6288             cs_i_cd_steady_tensor(bldfrp,
6289                                   ischcp,
6290                                   relaxp,
6291                                   blencp,
6292                                   weight[face_id],
6293                                   cell_cen[ii],
6294                                   cell_cen[jj],
6295                                   i_face_cog[face_id],
6296                                   diipf[face_id],
6297                                   djjpf[face_id],
6298                                   (const cs_real_3_t *)grad[ii],
6299                                   (const cs_real_3_t *)grad[jj],
6300                                   _pvar[ii],
6301                                   _pvar[jj],
6302                                   pvara[ii],
6303                                   pvara[jj],
6304                                   pifri,
6305                                   pifrj,
6306                                   pjfri,
6307                                   pjfrj,
6308                                   pip,
6309                                   pjp,
6310                                   pipr,
6311                                   pjpr);
6312 
6313             cs_i_conv_flux_tensor(iconvp,
6314                                   1.,
6315                                   1,
6316                                   _pvar[ii],
6317                                   _pvar[jj],
6318                                   pifri,
6319                                   pifrj,
6320                                   pjfri,
6321                                   pjfrj,
6322                                   i_massflux[face_id],
6323                                   fluxi,
6324                                   fluxj);
6325 
6326 
6327             cs_i_diff_flux_tensor(idiffp,
6328                                   1.,
6329                                   pip,
6330                                   pjp,
6331                                   pipr,
6332                                   pjpr,
6333                                   i_visc[face_id],
6334                                   fluxi,
6335                                   fluxj);
6336 
6337             for (int isou = 0; isou < 6; isou++) {
6338               rhs[ii][isou] -= fluxi[isou];
6339               rhs[jj][isou] += fluxj[isou];
6340             }
6341 
6342           }
6343         }
6344       }
6345 
6346       /* Unsteady */
6347     } else {
6348 
6349       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6350 #       pragma omp parallel for
6351         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6352           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6353                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6354                face_id++) {
6355 
6356             cs_lnum_t ii = i_face_cells[face_id][0];
6357             cs_lnum_t jj = i_face_cells[face_id][1];
6358 
6359             double fluxi[6], fluxj[6] ;
6360             for (int isou =  0; isou < 6; isou++) {
6361               fluxi[isou] = 0;
6362               fluxj[isou] = 0;
6363             }
6364             cs_real_6_t pip, pjp;
6365             cs_real_6_t pif, pjf;
6366 
6367             cs_real_t bldfrp = (cs_real_t) ircflp;
6368             /* Local limitation of the reconstruction */
6369             if (df_limiter != NULL && ircflp > 0)
6370               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6371 
6372             cs_i_cd_unsteady_tensor(bldfrp,
6373                                     ischcp,
6374                                     blencp,
6375                                     weight[face_id],
6376                                     cell_cen[ii],
6377                                     cell_cen[jj],
6378                                     i_face_cog[face_id],
6379                                     diipf[face_id],
6380                                     djjpf[face_id],
6381                                     (const cs_real_3_t *)grad[ii],
6382                                     (const cs_real_3_t *)grad[jj],
6383                                     _pvar[ii],
6384                                     _pvar[jj],
6385                                     pif,
6386                                     pjf,
6387                                     pip,
6388                                     pjp);
6389 
6390             cs_i_conv_flux_tensor(iconvp,
6391                                   thetap,
6392                                   imasac,
6393                                   _pvar[ii],
6394                                   _pvar[jj],
6395                                   pif,
6396                                   pif, /* no relaxation */
6397                                   pjf,
6398                                   pjf, /* no relaxation */
6399                                   i_massflux[face_id],
6400                                   fluxi,
6401                                   fluxj);
6402 
6403 
6404             cs_i_diff_flux_tensor(idiffp,
6405                                   thetap,
6406                                   pip,
6407                                   pjp,
6408                                   pip, /* no relaxation */
6409                                   pjp, /* no relaxation */
6410                                   i_visc[face_id],
6411                                   fluxi,
6412                                   fluxj);
6413 
6414             for (int isou = 0; isou < 6; isou++) {
6415               rhs[ii][isou] -= fluxi[isou];
6416               rhs[jj][isou] += fluxj[isou];
6417             }
6418           }
6419         }
6420       }
6421     }
6422 
6423     /* --> Flux with slope test
6424        =========================*/
6425 
6426   } else {
6427 
6428     if (ischcp < 0 || ischcp > 1) {
6429       bft_error(__FILE__, __LINE__, 0,
6430                 _("invalid value of ischcp"));
6431     }
6432 
6433     /* Steady */
6434     if (idtvar < 0) {
6435 
6436       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6437 #       pragma omp parallel for reduction(+:n_upwind)
6438         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6439           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6440                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6441                face_id++) {
6442 
6443             cs_lnum_t ii = i_face_cells[face_id][0];
6444             cs_lnum_t jj = i_face_cells[face_id][1];
6445 
6446             double fluxi[6], fluxj[6] ;
6447             for (int isou =  0; isou < 6; isou++) {
6448               fluxi[isou] = 0;
6449               fluxj[isou] = 0;
6450             }
6451             cs_real_6_t pip, pjp, pipr, pjpr;
6452             cs_real_6_t pifri, pifrj, pjfri, pjfrj;
6453             bool upwind_switch = false;
6454 
6455             cs_real_t bldfrp = (cs_real_t) ircflp;
6456             /* Local limitation of the reconstruction */
6457             if (df_limiter != NULL && ircflp > 0)
6458               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6459 
6460             cs_i_cd_steady_slope_test_tensor(&upwind_switch,
6461                                              iconvp,
6462                                              bldfrp,
6463                                              ischcp,
6464                                              relaxp,
6465                                              blencp,
6466                                              blend_st,
6467                                              weight[face_id],
6468                                              i_dist[face_id],
6469                                              i_face_surf[face_id],
6470                                              cell_cen[ii],
6471                                              cell_cen[jj],
6472                                              i_face_normal[face_id],
6473                                              i_face_cog[face_id],
6474                                              diipf[face_id],
6475                                              djjpf[face_id],
6476                                              i_massflux[face_id],
6477                                              (const cs_real_3_t *)grad[ii],
6478                                              (const cs_real_3_t *)grad[jj],
6479                                              (const cs_real_3_t *)grdpa[ii],
6480                                              (const cs_real_3_t *)grdpa[jj],
6481                                              _pvar[ii],
6482                                              _pvar[jj],
6483                                              pvara[ii],
6484                                              pvara[jj],
6485                                              pifri,
6486                                              pifrj,
6487                                              pjfri,
6488                                              pjfrj,
6489                                              pip,
6490                                              pjp,
6491                                              pipr,
6492                                              pjpr);
6493 
6494             cs_i_conv_flux_tensor(iconvp,
6495                                   1.,
6496                                   1,
6497                                   _pvar[ii],
6498                                   _pvar[jj],
6499                                   pifri,
6500                                   pifrj,
6501                                   pjfri,
6502                                   pjfrj,
6503                                   i_massflux[face_id],
6504                                   fluxi,
6505                                   fluxj);
6506 
6507 
6508             cs_i_diff_flux_tensor(idiffp,
6509                                   1.,
6510                                   pip,
6511                                   pjp,
6512                                   pipr,
6513                                   pjpr,
6514                                   i_visc[face_id],
6515                                   fluxi,
6516                                   fluxj);
6517 
6518             for (int isou = 0; isou < 6; isou++) {
6519               rhs[ii][isou] -= fluxi[isou];
6520               rhs[jj][isou] += fluxj[isou];
6521             }
6522 
6523           }
6524         }
6525       }
6526 
6527       /* Unsteady */
6528     } else {
6529 
6530       for (int g_id = 0; g_id < n_i_groups; g_id++) {
6531 #       pragma omp parallel for reduction(+:n_upwind)
6532         for (int t_id = 0; t_id < n_i_threads; t_id++) {
6533           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6534                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6535                face_id++) {
6536 
6537             cs_lnum_t ii = i_face_cells[face_id][0];
6538             cs_lnum_t jj = i_face_cells[face_id][1];
6539 
6540             double fluxi[6], fluxj[6] ;
6541             for (int isou =  0; isou < 6; isou++) {
6542               fluxi[isou] = 0;
6543               fluxj[isou] = 0;
6544             }
6545             cs_real_6_t pip, pjp;
6546             cs_real_6_t pif, pjf;
6547             bool upwind_switch = false;
6548 
6549             cs_real_t bldfrp = (cs_real_t) ircflp;
6550             /* Local limitation of the reconstruction */
6551             if (df_limiter != NULL && ircflp > 0)
6552               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
6553 
6554             cs_i_cd_unsteady_slope_test_tensor(&upwind_switch,
6555                                                iconvp,
6556                                                bldfrp,
6557                                                ischcp,
6558                                                blencp,
6559                                                blend_st,
6560                                                weight[face_id],
6561                                                i_dist[face_id],
6562                                                i_face_surf[face_id],
6563                                                cell_cen[ii],
6564                                                cell_cen[jj],
6565                                                i_face_normal[face_id],
6566                                                i_face_cog[face_id],
6567                                                diipf[face_id],
6568                                                djjpf[face_id],
6569                                                i_massflux[face_id],
6570                                                (const cs_real_3_t *)grad[ii],
6571                                                (const cs_real_3_t *)grad[jj],
6572                                                (const cs_real_3_t *)grdpa[ii],
6573                                                (const cs_real_3_t *)grdpa[jj],
6574                                                _pvar[ii],
6575                                                _pvar[jj],
6576                                                pif,
6577                                                pjf,
6578                                                pip,
6579                                                pjp);
6580 
6581             cs_i_conv_flux_tensor(iconvp,
6582                                   thetap,
6583                                   imasac,
6584                                   _pvar[ii],
6585                                   _pvar[jj],
6586                                   pif,
6587                                   pif, /* no relaxation */
6588                                   pjf,
6589                                   pjf, /* no relaxation */
6590                                   i_massflux[face_id],
6591                                   fluxi,
6592                                   fluxj);
6593 
6594 
6595             cs_i_diff_flux_tensor(idiffp,
6596                                   thetap,
6597                                   pip,
6598                                   pjp,
6599                                   pip, /* no relaxation */
6600                                   pjp, /* no relaxation */
6601                                   i_visc[face_id],
6602                                   fluxi,
6603                                   fluxj);
6604 
6605             if (upwind_switch) {
6606               /* in parallel, face will be counted by one and only one rank */
6607               if (ii < n_cells)
6608                 n_upwind++;
6609 
6610               if (v_slope_test != NULL) {
6611                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
6612                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
6613               }
6614             }
6615 
6616             for (int isou = 0; isou < 6; isou++) {
6617               rhs[ii][isou] -= fluxi[isou];
6618               rhs[jj][isou] += fluxj[isou];
6619             } /* isou */
6620           }
6621         }
6622       }
6623     } /* idtvar */
6624   } /* iupwin */
6625 
6626   if (iwarnp >= 2 && iconvp == 1) {
6627 
6628     /* Sum number of clippings */
6629     cs_parall_counter(&n_upwind, 1);
6630 
6631     bft_printf(_(" %s: %llu Faces with upwind on %llu interior faces\n"),
6632                var_name, (unsigned long long)n_upwind,
6633                (unsigned long long)m->n_g_i_c_faces);
6634   }
6635 
6636   /* ======================================================================
6637      ---> Contribution from boundary faces
6638      ======================================================================*/
6639 
6640   /* Boundary convective flux are all computed with an upwind scheme */
6641   if (icvflb == 0) {
6642 
6643     /* Steady */
6644     if (idtvar < 0) {
6645 
6646       for (int g_id = 0; g_id < n_b_groups; g_id++) {
6647 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
6648         for (int t_id = 0; t_id < n_b_threads; t_id++) {
6649           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
6650                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
6651                face_id++) {
6652 
6653             cs_lnum_t ii = b_face_cells[face_id];
6654 
6655             double fluxi[6] ;
6656             for (int isou =  0; isou < 6; isou++) {
6657               fluxi[isou] = 0;
6658             }
6659             cs_real_6_t pir, pipr;
6660 
6661             cs_real_t bldfrp = (cs_real_t) ircflp;
6662             /* Local limitation of the reconstruction */
6663             if (df_limiter != NULL && ircflp > 0)
6664               bldfrp = CS_MAX(df_limiter[ii], 0.);
6665 
6666             cs_b_cd_steady_tensor(bldfrp,
6667                                   relaxp,
6668                                   diipb[face_id],
6669                                   (const cs_real_3_t *)grad[ii],
6670                                   _pvar[ii],
6671                                   pvara[ii],
6672                                   pir,
6673                                   pipr);
6674 
6675             cs_b_upwind_flux_tensor(iconvp,
6676                                     1., /* thetap */
6677                                     1, /* imasac */
6678                                     inc,
6679                                     bc_type[face_id],
6680                                     _pvar[ii],
6681                                     pir,
6682                                     pipr,
6683                                     coefa[face_id],
6684                                     coefb[face_id],
6685                                     b_massflux[face_id],
6686                                     fluxi);
6687 
6688             cs_b_diff_flux_tensor(idiffp,
6689                                   1., /* thetap */
6690                                   inc,
6691                                   pipr,
6692                                   cofaf[face_id],
6693                                   cofbf[face_id],
6694                                   b_visc[face_id],
6695                                   fluxi);
6696 
6697             for (int isou = 0; isou < 6; isou++) {
6698               rhs[ii][isou] -= fluxi[isou];
6699             }
6700           }
6701         }
6702       }
6703 
6704       /* Unsteady */
6705     } else {
6706 
6707       for (int g_id = 0; g_id < n_b_groups; g_id++) {
6708 #       pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
6709         for (int t_id = 0; t_id < n_b_threads; t_id++) {
6710           for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
6711                face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
6712                face_id++) {
6713 
6714             cs_lnum_t ii = b_face_cells[face_id];
6715 
6716             double fluxi[6] ;
6717             for (int isou =  0; isou < 6; isou++) {
6718               fluxi[isou] = 0;
6719             }
6720             cs_real_6_t pip;
6721 
6722             cs_real_t bldfrp = (cs_real_t) ircflp;
6723             /* Local limitation of the reconstruction */
6724             if (df_limiter != NULL && ircflp > 0)
6725               bldfrp = CS_MAX(df_limiter[ii], 0.);
6726 
6727             cs_b_cd_unsteady_tensor(bldfrp,
6728                                     diipb[face_id],
6729                                     (const cs_real_3_t *)grad[ii],
6730                                     _pvar[ii],
6731                                     pip);
6732 
6733             cs_b_upwind_flux_tensor(iconvp,
6734                                     thetap,
6735                                     imasac,
6736                                     inc,
6737                                     bc_type[face_id],
6738                                     _pvar[ii],
6739                                     _pvar[ii], /* no relaxation */
6740                                     pip,
6741                                     coefa[face_id],
6742                                     coefb[face_id],
6743                                     b_massflux[face_id],
6744                                     fluxi);
6745 
6746             cs_b_diff_flux_tensor(idiffp,
6747                                   thetap,
6748                                   inc,
6749                                   pip,
6750                                   cofaf[face_id],
6751                                   cofbf[face_id],
6752                                   b_visc[face_id],
6753                                   fluxi);
6754 
6755             for(int isou = 0; isou < 6; isou++) {
6756               rhs[ii][isou] -= fluxi[isou];
6757             } /* isou */
6758           }
6759         }
6760       }
6761 
6762     } /* idtvar */
6763 
6764   }
6765 
6766   /* Free memory */
6767   BFT_FREE(grdpa);
6768   BFT_FREE(grad);
6769 }
6770 
6771 /*----------------------------------------------------------------------------*/
6772 /*!
6773  * \brief Add the explicit part of the convection/diffusion terms of a transport
6774  * equation of a scalar field \f$ \varia \f$ such as the temperature.
6775  *
6776  * More precisely, the right hand side \f$ Rhs \f$ is updated as
6777  * follows:
6778  * \f[
6779  * Rhs = Rhs + \sum_{\fij \in \Facei{\celli}}      \left(
6780  *        C_p\dot{m}_\ij \varia_\fij
6781  *      - \lambda_\fij \gradv_\fij \varia \cdot \vect{S}_\ij  \right)
6782  * \f]
6783  *
6784  * Warning:
6785  * \f$ Rhs \f$ has already been initialized before calling bilsct!
6786  *
6787  * \param[in]     idtvar        indicator of the temporal scheme
6788  * \param[in]     f_id          index of the current variable
6789  * \param[in]     var_cal_opt   variable calculation options
6790  * \param[in]     inc           indicator
6791  *                               - 0 when solving an increment
6792  *                               - 1 otherwise
6793  * \param[in]     iccocg        indicator
6794  *                               - 1 re-compute cocg matrix
6795  *                                 (for iterative gradients)
6796  *                               - 0 otherwise
6797  * \param[in]     imasac        take mass accumulation into account?
6798  * \param[in]     pvar          solved variable (current time step)
6799  * \param[in]     pvara         solved variable (previous time step)
6800  * \param[in]     coefap        boundary condition array for the variable
6801  *                               (explicit part)
6802  * \param[in]     coefbp        boundary condition array for the variable
6803  *                               (implicit part)
6804  * \param[in]     cofafp        boundary condition array for the diffusion
6805  *                               of the variable (explicit part)
6806  * \param[in]     cofbfp        boundary condition array for the diffusion
6807  *                               of the variable (implicit part)
6808  * \param[in]     i_massflux    mass flux at interior faces
6809  * \param[in]     b_massflux    mass flux at boundary faces
6810  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
6811  *                               at interior faces for the r.h.s.
6812  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
6813  *                               at border faces for the r.h.s.
6814  * \param[in]     xcpp          array of specific heat (\f$ C_p \f$)
6815  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
6816  */
6817 /*----------------------------------------------------------------------------*/
6818 
6819 void
cs_convection_diffusion_thermal(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int inc,int iccocg,int imasac,cs_real_t * restrict pvar,const cs_real_t * restrict pvara,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_massflux[],const cs_real_t b_massflux[],const cs_real_t i_visc[],const cs_real_t b_visc[],const cs_real_t xcpp[],cs_real_t * restrict rhs)6820 cs_convection_diffusion_thermal(int                       idtvar,
6821                                 int                       f_id,
6822                                 const cs_var_cal_opt_t    var_cal_opt,
6823                                 int                       inc,
6824                                 int                       iccocg,
6825                                 int                       imasac,
6826                                 cs_real_t       *restrict pvar,
6827                                 const cs_real_t *restrict pvara,
6828                                 const cs_real_t           coefap[],
6829                                 const cs_real_t           coefbp[],
6830                                 const cs_real_t           cofafp[],
6831                                 const cs_real_t           cofbfp[],
6832                                 const cs_real_t           i_massflux[],
6833                                 const cs_real_t           b_massflux[],
6834                                 const cs_real_t           i_visc[],
6835                                 const cs_real_t           b_visc[],
6836                                 const cs_real_t           xcpp[],
6837                                 cs_real_t       *restrict rhs)
6838 {
6839   const int iconvp = var_cal_opt.iconv ;
6840   const int idiffp = var_cal_opt.idiff ;
6841   const int nswrgp = var_cal_opt.nswrgr;
6842   const int imrgra = var_cal_opt.imrgra;
6843   const int imligp = var_cal_opt.imligr;
6844   const int ircflp = var_cal_opt.ircflu;
6845   const int ischcp = var_cal_opt.ischcv;
6846   const int isstpp = var_cal_opt.isstpc;
6847   const int iwarnp = var_cal_opt.verbosity;
6848   const int icoupl = var_cal_opt.icoupl;
6849   int limiter_choice = -1;
6850   const double blencp = var_cal_opt.blencv;
6851   const double blend_st = var_cal_opt.blend_st;
6852   const double epsrgp = var_cal_opt.epsrgr;
6853   const double climgp = var_cal_opt.climgr;
6854   const double relaxp = var_cal_opt.relaxv;
6855   const double thetap = var_cal_opt.thetav;
6856 
6857   const cs_mesh_t  *m = cs_glob_mesh;
6858   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
6859 
6860   const cs_lnum_t n_cells = m->n_cells;
6861   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
6862   const int n_i_groups = m->i_face_numbering->n_groups;
6863   const int n_i_threads = m->i_face_numbering->n_threads;
6864   const int n_b_groups = m->b_face_numbering->n_groups;
6865   const int n_b_threads = m->b_face_numbering->n_threads;
6866   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
6867   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
6868 
6869   const cs_lnum_2_t *restrict i_face_cells
6870     = (const cs_lnum_2_t *restrict)m->i_face_cells;
6871   const cs_lnum_t *restrict b_face_cells
6872     = (const cs_lnum_t *restrict)m->b_face_cells;
6873   const cs_real_t *restrict weight = fvq->weight;
6874   const cs_real_t *restrict i_dist = fvq->i_dist;
6875   const cs_real_t *restrict i_face_surf = fvq->i_face_surf;
6876   const cs_real_t *restrict cell_vol = fvq->cell_vol;
6877   const cs_real_3_t *restrict cell_cen
6878     = (const cs_real_3_t *restrict)fvq->cell_cen;
6879   const cs_real_3_t *restrict i_face_normal
6880     = (const cs_real_3_t *restrict)fvq->i_face_normal;
6881   const cs_real_3_t *restrict i_face_cog
6882     = (const cs_real_3_t *restrict)fvq->i_face_cog;
6883   const cs_real_3_t *restrict diipf
6884     = (const cs_real_3_t *restrict)fvq->diipf;
6885   const cs_real_3_t *restrict djjpf
6886     = (const cs_real_3_t *restrict)fvq->djjpf;
6887   const cs_real_3_t *restrict diipb
6888     = (const cs_real_3_t *restrict)fvq->diipb;
6889 
6890   const int *bc_type = cs_glob_bc_type;
6891 
6892   /* Local variables */
6893 
6894   char var_name[64];
6895 
6896   cs_gnum_t n_upwind;
6897   int iupwin;
6898   int w_stride = 1;
6899 
6900   bool recompute_cocg = (iccocg) ? true : false;
6901 
6902   cs_real_3_t *grad;
6903   cs_real_3_t *gradup = NULL;
6904   cs_real_3_t *gradst = NULL;
6905   cs_field_t *f = NULL;
6906 
6907   cs_real_t *local_min = NULL;
6908   cs_real_t *local_max = NULL;
6909 
6910   cs_real_t *cv_limiter = NULL;
6911   cs_real_t *df_limiter = NULL;
6912 
6913   cs_real_t *gweight = NULL;
6914 
6915   cs_real_t  *v_slope_test = cs_get_v_slope_test(f_id,  var_cal_opt);
6916 
6917   /* Internal coupling variables */
6918   cs_real_t *pvar_local = NULL;
6919   cs_real_t *pvar_distant = NULL;
6920   cs_real_t *df_limiter_local = NULL;
6921   const cs_lnum_t *faces_local = NULL, *faces_distant = NULL;
6922   cs_lnum_t n_local = 0, n_distant = 0;
6923   int coupling_id = -1;
6924   cs_internal_coupling_t *cpl = NULL;
6925 
6926   /*==========================================================================*/
6927 
6928   /* 1. Initialization */
6929 
6930   /* Allocate work arrays */
6931   BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
6932 
6933   /* Choose gradient type */
6934 
6935   cs_halo_type_t halo_type = CS_HALO_STANDARD;
6936   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
6937 
6938   cs_gradient_type_by_imrgra(imrgra,
6939                              &gradient_type,
6940                              &halo_type);
6941 
6942   /* Handle cases where only the previous values (already synchronized)
6943      or current values are provided */
6944 
6945   if (pvar != NULL)
6946     cs_sync_scalar_halo(m, pvar);
6947   if (pvara == NULL)
6948     pvara = (const cs_real_t *restrict)pvar;
6949 
6950   const cs_real_t  *restrict _pvar = (pvar != NULL) ? pvar : pvara;
6951 
6952   /* Slope limiters */
6953 
6954   if (f_id != -1) {
6955     f = cs_field_by_id(f_id);
6956     /* Get option from the field */
6957     if (ischcp == 4) {
6958       const int key_limiter = cs_field_key_id("limiter_choice");
6959       limiter_choice = cs_field_get_key_int(f, key_limiter);
6960       BFT_MALLOC(local_max, n_cells_ext, cs_real_t);
6961       BFT_MALLOC(local_min, n_cells_ext, cs_real_t);
6962       cs_field_local_extrema_scalar(f_id,
6963                                     halo_type,
6964                                     local_max,
6965                                     local_min);
6966 
6967       assert(limiter_choice < CS_NVD_VOF_HRIC); /* VOF scheme forbidden here */
6968     }
6969 
6970     int cv_limiter_id =
6971       cs_field_get_key_int(f, cs_field_key_id("convection_limiter_id"));
6972     if (cv_limiter_id > -1)
6973       cv_limiter = cs_field_by_id(cv_limiter_id)->val;
6974 
6975     int df_limiter_id =
6976       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
6977     if (df_limiter_id > -1)
6978       df_limiter = cs_field_by_id(df_limiter_id)->val;
6979 
6980     snprintf(var_name, 63, "%s", f->name);
6981   }
6982   else
6983     strncpy(var_name, "[convection-diffusion, thermal]", 63);
6984   var_name[63] = '\0';
6985 
6986   if (iwarnp >= 2) {
6987     if (ischcp == 1) {
6988       bft_printf
6989         (
6990          _(" %s: Convection in centered blending with %f percent of upwind\n"),
6991          var_name, (1.-blencp)*100.);
6992     } else {
6993       bft_printf
6994         (
6995          _(" %s: Convection in 2nd order blending with %f percent of upwind\n"),
6996          var_name, (1.-blencp)*100.);
6997     }
6998   }
6999 
7000   iupwin = (blencp > 0.) ? 0 : 1;
7001 
7002   if (icoupl > 0) {
7003     assert(f_id != -1);
7004     const int coupling_key_id = cs_field_key_id("coupling_entity");
7005     coupling_id = cs_field_get_key_int(f, coupling_key_id);
7006     cpl = cs_internal_coupling_by_id(coupling_id);
7007     cs_internal_coupling_coupled_faces(cpl,
7008                                        &n_local,
7009                                        &faces_local,
7010                                        &n_distant,
7011                                        &faces_distant);
7012   }
7013 
7014   /* 2. Compute the balance with reconstruction technics */
7015 
7016   /* Compute the gradient of the variable
7017 
7018      The gradient (grad) is used in the flux reconstruction and the slope test.
7019      Thus we must compute it:
7020          - when we have diffusion and we reconstruct the fluxes,
7021          - when the convection scheme is SOLU,
7022          - when we have convection, we are not in pure upwind
7023            and we reconstruct the fluxes,
7024          - when we have convection, we are not in pure upwind
7025            and we have not shunted the slope test. */
7026 
7027   if (   (idiffp != 0 && ircflp == 1)
7028       || (   iconvp != 0 && iupwin == 0
7029           && (ischcp == 0 || ircflp == 1 || isstpp == 0))) {
7030 
7031     if (f_id != -1) {
7032       /* Get the calculation option from the field */
7033       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
7034         if (var_cal_opt.idiff > 0) {
7035           int key_id = cs_field_key_id("gradient_weighting_id");
7036           int diff_id = cs_field_get_key_int(f, key_id);
7037           if (diff_id > -1) {
7038             cs_field_t *weight_f = cs_field_by_id(diff_id);
7039             gweight = weight_f->val;
7040             w_stride = weight_f->dim;
7041             cs_field_synchronize(weight_f, halo_type);
7042           }
7043         }
7044       }
7045     }
7046 
7047     cs_gradient_scalar_synced_input(var_name,
7048                                     gradient_type,
7049                                     halo_type,
7050                                     inc,
7051                                     recompute_cocg,
7052                                     nswrgp,
7053                                     0, /* hyd_p_flag */
7054                                     w_stride,
7055                                     iwarnp,
7056                                     imligp,
7057                                     epsrgp,
7058                                     climgp,
7059                                     NULL, /* f_ext exterior force */
7060                                     coefap,
7061                                     coefbp,
7062                                     _pvar,
7063                                     gweight, /* Weighted gradient */
7064                                     cpl, /* internal coupling */
7065                                     grad);
7066 
7067   } else {
7068 #   pragma omp parallel for
7069     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
7070       grad[cell_id][0] = 0.;
7071       grad[cell_id][1] = 0.;
7072       grad[cell_id][2] = 0.;
7073     }
7074   }
7075 
7076   /* ======================================================================
7077      ---> Compute uncentered gradient gradpa for the slope test
7078      ======================================================================*/
7079 
7080   /* 2.1 Compute the gradient for convective scheme (the slope test, limiter, SOLU, etc) */
7081 
7082   /* Slope test gradient */
7083   if (iconvp > 0 && iupwin == 0 && isstpp == 0) {
7084 
7085     BFT_MALLOC(gradst, n_cells_ext, cs_real_3_t);
7086 
7087 # pragma omp parallel for
7088     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
7089       gradst[cell_id][0] = 0.;
7090       gradst[cell_id][1] = 0.;
7091       gradst[cell_id][2] = 0.;
7092     }
7093 
7094     cs_slope_test_gradient(f_id,
7095                            inc,
7096                            halo_type,
7097                            (const cs_real_3_t *)grad,
7098                            gradst,
7099                            _pvar,
7100                            coefap,
7101                            coefbp,
7102                            i_massflux);
7103 
7104   }
7105 
7106   /* Pure SOLU scheme without using gradient_slope_test function
7107      or NVD/TVD limiters */
7108   if (iconvp > 0 && iupwin == 0 && (ischcp == 2 || ischcp == 4)) {
7109 
7110     BFT_MALLOC(gradup, n_cells_ext, cs_real_3_t);
7111 
7112 # pragma omp parallel for
7113     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
7114       gradup[cell_id][0] = 0.;
7115       gradup[cell_id][1] = 0.;
7116       gradup[cell_id][2] = 0.;
7117     }
7118 
7119     cs_upwind_gradient(f_id,
7120                        inc,
7121                        halo_type,
7122                        coefap,
7123                        coefbp,
7124                        i_massflux,
7125                        b_massflux,
7126                        _pvar,
7127                        gradup);
7128 
7129   }
7130 
7131   /* ======================================================================
7132      ---> Contribution from interior faces
7133      ======================================================================*/
7134 
7135   n_upwind = 0;
7136 
7137   if (n_cells_ext > n_cells) {
7138 #   pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
7139     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++)
7140       rhs[cell_id] = 0.;
7141   }
7142 
7143   /* --> Pure upwind flux
7144      =====================*/
7145 
7146   if (iupwin == 1) {
7147 
7148     /* Steady */
7149     if (idtvar < 0) {
7150 
7151       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7152 #       pragma omp parallel for reduction(+:n_upwind)
7153         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7154           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7155                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7156                face_id++) {
7157 
7158             cs_lnum_t ii = i_face_cells[face_id][0];
7159             cs_lnum_t jj = i_face_cells[face_id][1];
7160 
7161             /* in parallel, face will be counted by one and only one rank */
7162             if (ii < n_cells) {
7163               n_upwind++;
7164             }
7165 
7166             cs_real_2_t fluxij = {0.,0.};
7167 
7168             cs_real_t pifri, pjfri, pifrj, pjfrj;
7169             cs_real_t pip, pjp, pipr, pjpr;
7170 
7171             cs_real_t bldfrp = (cs_real_t) ircflp;
7172             /* Local limitation of the reconstruction */
7173             if (df_limiter != NULL && ircflp > 0)
7174               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7175 
7176             cs_i_cd_steady_upwind(bldfrp,
7177                                   relaxp,
7178                                   diipf[face_id],
7179                                   djjpf[face_id],
7180                                   grad[ii],
7181                                   grad[jj],
7182                                   _pvar[ii],
7183                                   _pvar[jj],
7184                                   pvara[ii],
7185                                   pvara[jj],
7186                                   &pifri,
7187                                   &pifrj,
7188                                   &pjfri,
7189                                   &pjfrj,
7190                                   &pip,
7191                                   &pjp,
7192                                   &pipr,
7193                                   &pjpr);
7194 
7195             cs_i_conv_flux(iconvp,
7196                            1.,
7197                            1,
7198                            _pvar[ii],
7199                            _pvar[jj],
7200                            pifri,
7201                            pifrj,
7202                            pjfri,
7203                            pjfrj,
7204                            i_massflux[face_id],
7205                            xcpp[ii],
7206                            xcpp[jj],
7207                            fluxij);
7208 
7209             cs_i_diff_flux(idiffp,
7210                            1.,
7211                            pip,
7212                            pjp,
7213                            pipr,
7214                            pjpr,
7215                            i_visc[face_id],
7216                            fluxij);
7217 
7218             rhs[ii] -= fluxij[0];
7219             rhs[jj] += fluxij[1];
7220 
7221           }
7222         }
7223       }
7224 
7225       /* Unsteady */
7226     } else {
7227 
7228       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7229 #       pragma omp parallel for reduction(+:n_upwind)
7230         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7231           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7232                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7233                face_id++) {
7234 
7235             cs_lnum_t ii = i_face_cells[face_id][0];
7236             cs_lnum_t jj = i_face_cells[face_id][1];
7237 
7238             /* in parallel, face will be counted by one and only one rank */
7239             if (ii < n_cells) {
7240               n_upwind++;
7241             }
7242 
7243             cs_real_2_t fluxij = {0.,0.};
7244 
7245             cs_real_t pif, pjf;
7246             cs_real_t pip, pjp;
7247 
7248             cs_real_t bldfrp = (cs_real_t) ircflp;
7249             /* Local limitation of the reconstruction */
7250             if (df_limiter != NULL && ircflp > 0)
7251               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7252 
7253             cs_i_cd_unsteady_upwind(bldfrp,
7254                                     diipf[face_id],
7255                                     djjpf[face_id],
7256                                     grad[ii],
7257                                     grad[jj],
7258                                     _pvar[ii],
7259                                     _pvar[jj],
7260                                     &pif,
7261                                     &pjf,
7262                                     &pip,
7263                                     &pjp);
7264 
7265             cs_i_conv_flux(iconvp,
7266                            thetap,
7267                            imasac,
7268                            _pvar[ii],
7269                            _pvar[jj],
7270                            pif,
7271                            pif, /* no relaxation */
7272                            pjf,
7273                            pjf, /* no relaxation */
7274                            i_massflux[face_id],
7275                            xcpp[ii],
7276                            xcpp[jj],
7277                            fluxij);
7278 
7279             cs_i_diff_flux(idiffp,
7280                            thetap,
7281                            pip,
7282                            pjp,
7283                            pip,/* no relaxation */
7284                            pjp,/* no relaxation */
7285                            i_visc[face_id],
7286                            fluxij);
7287 
7288             rhs[ii] -= fluxij[0];
7289             rhs[jj] += fluxij[1];
7290 
7291           }
7292         }
7293       }
7294 
7295     }
7296 
7297   /* --> Flux with no slope test or Min/Max Beta limiter
7298     ====================================================*/
7299 
7300   } else if (isstpp == 1 || isstpp == 2) {
7301 
7302     if (ischcp < 0 || ischcp > 2) {
7303       bft_error(__FILE__, __LINE__, 0,
7304                 _("invalid value of ischcv"));
7305     }
7306 
7307     /* Steady */
7308     if (idtvar < 0) {
7309 
7310       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7311 #       pragma omp parallel for
7312         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7313           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7314                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7315                face_id++) {
7316 
7317             cs_lnum_t ii = i_face_cells[face_id][0];
7318             cs_lnum_t jj = i_face_cells[face_id][1];
7319 
7320             cs_real_2_t fluxij = {0.,0.};
7321 
7322             cs_real_t pifri, pjfri, pifrj, pjfrj;
7323             cs_real_t pip, pjp, pipr, pjpr;
7324 
7325             cs_real_t bldfrp = (cs_real_t) ircflp;
7326             /* Local limitation of the reconstruction */
7327             if (df_limiter != NULL && ircflp > 0)
7328               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7329 
7330             cs_i_cd_steady(bldfrp,
7331                            ischcp,
7332                            relaxp,
7333                            blencp,
7334                            weight[face_id],
7335                            cell_cen[ii],
7336                            cell_cen[jj],
7337                            i_face_cog[face_id],
7338                            diipf[face_id],
7339                            djjpf[face_id],
7340                            grad[ii],
7341                            grad[jj],
7342                            gradup[ii],
7343                            gradup[jj],
7344                            _pvar[ii],
7345                            _pvar[jj],
7346                            pvara[ii],
7347                            pvara[jj],
7348                            &pifri,
7349                            &pifrj,
7350                            &pjfri,
7351                            &pjfrj,
7352                            &pip,
7353                            &pjp,
7354                            &pipr,
7355                            &pjpr);
7356 
7357             cs_i_conv_flux(iconvp,
7358                            1.,
7359                            1,
7360                            _pvar[ii],
7361                            _pvar[jj],
7362                            pifri,
7363                            pifrj,
7364                            pjfri,
7365                            pjfrj,
7366                            i_massflux[face_id],
7367                            xcpp[ii],
7368                            xcpp[jj],
7369                            fluxij);
7370 
7371             cs_i_diff_flux(idiffp,
7372                            1.,
7373                            pip,
7374                            pjp,
7375                            pipr,
7376                            pjpr,
7377                            i_visc[face_id],
7378                            fluxij);
7379 
7380             rhs[ii] -= fluxij[0];
7381             rhs[jj] += fluxij[1];
7382 
7383           }
7384         }
7385       }
7386 
7387       /* Unsteady */
7388     } else {
7389 
7390       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7391 #       pragma omp parallel for
7392         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7393           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7394                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7395                face_id++) {
7396 
7397             cs_lnum_t ii = i_face_cells[face_id][0];
7398             cs_lnum_t jj = i_face_cells[face_id][1];
7399 
7400             cs_real_t beta = blencp;
7401 
7402             cs_real_t pif, pjf;
7403             cs_real_t pip, pjp;
7404 
7405             /* Beta blending coefficient ensuring the positivity of the scalar */
7406             if (isstpp == 2) {
7407               beta = CS_MAX(CS_MIN(cv_limiter[ii], cv_limiter[jj]), 0.);
7408             }
7409 
7410             cs_real_2_t fluxij = {0.,0.};
7411 
7412             cs_real_t bldfrp = (cs_real_t) ircflp;
7413             /* Local limitation of the reconstruction */
7414             if (df_limiter != NULL && ircflp > 0)
7415               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7416 
7417             cs_real_t hybrid_coef_ii, hybrid_coef_jj;
7418             if (ischcp == 3) {
7419               hybrid_coef_ii = CS_F_(hybrid_blend)->val[ii];
7420               hybrid_coef_jj = CS_F_(hybrid_blend)->val[jj];
7421 
7422               cs_i_cd_unsteady(bldfrp,
7423                                ischcp,
7424                                beta,
7425                                weight[face_id],
7426                                cell_cen[ii],
7427                                cell_cen[jj],
7428                                i_face_cog[face_id],
7429                                hybrid_coef_ii,
7430                                hybrid_coef_jj,
7431                                diipf[face_id],
7432                                djjpf[face_id],
7433                                grad[ii],
7434                                grad[jj],
7435                                gradup[ii],
7436                                gradup[jj],
7437                                _pvar[ii],
7438                                _pvar[jj],
7439                                &pif,
7440                                &pjf,
7441                                &pip,
7442                                &pjp);
7443 
7444               cs_i_conv_flux(iconvp,
7445                              thetap,
7446                              imasac,
7447                              _pvar[ii],
7448                              _pvar[jj],
7449                              pif,
7450                              pif, /* no relaxation */
7451                              pjf,
7452                              pjf, /* no relaxation */
7453                              i_massflux[face_id],
7454                              xcpp[ii],
7455                              xcpp[jj],
7456                              fluxij);
7457             } else if (ischcp == 4) {
7458               /* NVD/TVD family of high accuracy schemes */
7459 
7460               cs_lnum_t ic, id;
7461 
7462               /* Determine central and downwind sides w.r.t. current face */
7463               cs_central_downwind_cells(ii,
7464                                         jj,
7465                                         i_massflux[face_id],
7466                                         &ic,  /* central cell id */
7467                                         &id); /* downwind cell id */
7468 
7469               cs_i_cd_unsteady_nvd(limiter_choice,
7470                                    beta,
7471                                    cell_cen[ic],
7472                                    cell_cen[id],
7473                                    i_face_normal[face_id],
7474                                    i_face_cog[face_id],
7475                                    grad[ic],
7476                                    _pvar[ic],
7477                                    _pvar[id],
7478                                    local_max[ic],
7479                                    local_min[ic],
7480                                    -1., /* courant */
7481                                    &pif,
7482                                    &pjf);
7483 
7484               cs_i_conv_flux(iconvp,
7485                              thetap,
7486                              imasac,
7487                              _pvar[ii],
7488                              _pvar[jj],
7489                              pif,
7490                              pif, /* no relaxation */
7491                              pjf,
7492                              pjf, /* no relaxation */
7493                              i_massflux[face_id],
7494                              xcpp[ii],
7495                              xcpp[jj],
7496                              fluxij);
7497 
7498 
7499               /* Compute required quantities for diffusive flux */
7500               cs_real_t recoi, recoj;
7501 
7502               cs_i_compute_quantities(bldfrp,
7503                                       diipf[face_id],
7504                                       djjpf[face_id],
7505                                       grad[ii],
7506                                       grad[jj],
7507                                       _pvar[ii],
7508                                       _pvar[jj],
7509                                       &recoi,
7510                                       &recoj,
7511                                       &pip,
7512                                       &pjp);
7513 
7514             } else {
7515               hybrid_coef_ii = 0.;
7516               hybrid_coef_jj = 0.;
7517 
7518               cs_i_cd_unsteady(bldfrp,
7519                                ischcp,
7520                                beta,
7521                                weight[face_id],
7522                                cell_cen[ii],
7523                                cell_cen[jj],
7524                                i_face_cog[face_id],
7525                                hybrid_coef_ii,
7526                                hybrid_coef_jj,
7527                                diipf[face_id],
7528                                djjpf[face_id],
7529                                grad[ii],
7530                                grad[jj],
7531                                gradup[ii],
7532                                gradup[jj],
7533                                _pvar[ii],
7534                                _pvar[jj],
7535                                &pif,
7536                                &pjf,
7537                                &pip,
7538                                &pjp);
7539 
7540               cs_i_conv_flux(iconvp,
7541                              thetap,
7542                              imasac,
7543                              _pvar[ii],
7544                              _pvar[jj],
7545                              pif,
7546                              pif, /* no relaxation */
7547                              pjf,
7548                              pjf, /* no relaxation */
7549                              i_massflux[face_id],
7550                              xcpp[ii],
7551                              xcpp[jj],
7552                              fluxij);
7553 
7554             }
7555 
7556             cs_i_diff_flux(idiffp,
7557                            thetap,
7558                            pip,
7559                            pjp,
7560                            pip, /* no relaxation */
7561                            pjp, /* no relaxation */
7562                            i_visc[face_id],
7563                            fluxij);
7564 
7565             rhs[ii] -= fluxij[0];
7566             rhs[jj] += fluxij[1];
7567 
7568           }
7569         }
7570       }
7571 
7572     }
7573 
7574   /* --> Flux with slope test
7575     ============================================*/
7576 
7577   } else {
7578 
7579     if (ischcp < 0 || ischcp > 2) {
7580       bft_error(__FILE__, __LINE__, 0,
7581                 _("invalid value of ischcv"));
7582     }
7583     if (isstpp != 0) {
7584       bft_error(__FILE__, __LINE__, 0,
7585                 _("invalid value of isstpc"));
7586     }
7587 
7588     /* Steady */
7589     if (idtvar < 0) {
7590 
7591       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7592 #       pragma omp parallel for reduction(+:n_upwind)
7593         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7594           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7595                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7596                face_id++) {
7597 
7598             cs_lnum_t ii = i_face_cells[face_id][0];
7599             cs_lnum_t jj = i_face_cells[face_id][1];
7600 
7601             cs_real_2_t fluxij = {0.,0.};
7602 
7603             cs_real_t pifri, pjfri, pifrj, pjfrj;
7604             cs_real_t pip, pjp, pipr, pjpr;
7605 
7606             bool upwind_switch = false;
7607 
7608             cs_real_t bldfrp = (cs_real_t) ircflp;
7609             /* Local limitation of the reconstruction */
7610             if (df_limiter != NULL && ircflp > 0)
7611               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7612 
7613             cs_i_cd_steady_slope_test(&upwind_switch,
7614                                       iconvp,
7615                                       bldfrp,
7616                                       ischcp,
7617                                       relaxp,
7618                                       blencp,
7619                                       blend_st,
7620                                       weight[face_id],
7621                                       i_dist[face_id],
7622                                       i_face_surf[face_id],
7623                                       cell_cen[ii],
7624                                       cell_cen[jj],
7625                                       i_face_normal[face_id],
7626                                       i_face_cog[face_id],
7627                                       diipf[face_id],
7628                                       djjpf[face_id],
7629                                       i_massflux[face_id],
7630                                       grad[ii],
7631                                       grad[jj],
7632                                       gradup[ii],
7633                                       gradup[jj],
7634                                       gradst[ii],
7635                                       gradst[jj],
7636                                       _pvar[ii],
7637                                       _pvar[jj],
7638                                       pvara[ii],
7639                                       pvara[jj],
7640                                       &pifri,
7641                                       &pifrj,
7642                                       &pjfri,
7643                                       &pjfrj,
7644                                       &pip,
7645                                       &pjp,
7646                                       &pipr,
7647                                       &pjpr);
7648 
7649             cs_i_conv_flux(iconvp,
7650                            1.,
7651                            1,
7652                            _pvar[ii],
7653                            _pvar[jj],
7654                            pifri,
7655                            pifrj,
7656                            pjfri,
7657                            pjfrj,
7658                            i_massflux[face_id],
7659                            xcpp[ii],
7660                            xcpp[jj],
7661                            fluxij);
7662 
7663             cs_i_diff_flux(idiffp,
7664                            1.,
7665                            pip,
7666                            pjp,
7667                            pipr,
7668                            pjpr,
7669                            i_visc[face_id],
7670                            fluxij);
7671 
7672             if (upwind_switch) {
7673 
7674               /* in parallel, face will be counted by one and only one rank */
7675               if (ii < n_cells)
7676                 n_upwind++;
7677               if (v_slope_test != NULL) {
7678                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
7679                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
7680               }
7681 
7682             }
7683 
7684             rhs[ii] -= fluxij[0];
7685             rhs[jj] += fluxij[1];
7686 
7687           }
7688         }
7689       }
7690 
7691       /* Unsteady */
7692     } else {
7693 
7694       for (int g_id = 0; g_id < n_i_groups; g_id++) {
7695 #       pragma omp parallel for reduction(+:n_upwind)
7696         for (int t_id = 0; t_id < n_i_threads; t_id++) {
7697           for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7698                face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7699                face_id++) {
7700 
7701             cs_lnum_t ii = i_face_cells[face_id][0];
7702             cs_lnum_t jj = i_face_cells[face_id][1];
7703 
7704             cs_real_2_t fluxij = {0.,0.};
7705 
7706             bool upwind_switch = false;
7707 
7708             cs_real_t pif, pjf;
7709             cs_real_t pip, pjp;
7710 
7711             cs_real_t bldfrp = (cs_real_t) ircflp;
7712             /* Local limitation of the reconstruction */
7713             if (df_limiter != NULL && ircflp > 0)
7714               bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
7715 
7716             cs_i_cd_unsteady_slope_test(&upwind_switch,
7717                                         iconvp,
7718                                         bldfrp,
7719                                         ischcp,
7720                                         blencp,
7721                                         blend_st,
7722                                         weight[face_id],
7723                                         i_dist[face_id],
7724                                         i_face_surf[face_id],
7725                                         cell_cen[ii],
7726                                         cell_cen[jj],
7727                                         i_face_normal[face_id],
7728                                         i_face_cog[face_id],
7729                                         diipf[face_id],
7730                                         djjpf[face_id],
7731                                         i_massflux[face_id],
7732                                         grad[ii],
7733                                         grad[jj],
7734                                         gradup[ii],
7735                                         gradup[jj],
7736                                         gradst[ii],
7737                                         gradst[jj],
7738                                         _pvar[ii],
7739                                         _pvar[jj],
7740                                         &pif,
7741                                         &pjf,
7742                                         &pip,
7743                                         &pjp);
7744 
7745             cs_i_conv_flux(iconvp,
7746                            thetap,
7747                            imasac,
7748                            _pvar[ii],
7749                            _pvar[jj],
7750                            pif,
7751                            pif, /* no relaxation */
7752                            pjf,
7753                            pjf, /* no relaxation */
7754                            i_massflux[face_id],
7755                            xcpp[ii],
7756                            xcpp[jj],
7757                            fluxij);
7758 
7759             cs_i_diff_flux(idiffp,
7760                            thetap,
7761                            pip,
7762                            pjp,
7763                            pip, /* no relaxation */
7764                            pjp, /* no relaxation */
7765                            i_visc[face_id],
7766                            fluxij);
7767 
7768             if (upwind_switch) {
7769 
7770               /* in parallel, face will be counted by one and only one rank */
7771               if (ii < n_cells)
7772                 n_upwind++;
7773               if (v_slope_test != NULL) {
7774                 v_slope_test[ii] += fabs(i_massflux[face_id]) / cell_vol[ii];
7775                 v_slope_test[jj] += fabs(i_massflux[face_id]) / cell_vol[jj];
7776               }
7777 
7778             }
7779 
7780             rhs[ii] -= fluxij[0];
7781             rhs[jj] += fluxij[1];
7782 
7783           }
7784         }
7785       }
7786 
7787     } /* idtvar */
7788 
7789   } /* iupwin */
7790 
7791 
7792   if (iwarnp >= 2 && iconvp == 1) {
7793 
7794     /* Sum number of clippings */
7795     cs_parall_counter(&n_upwind, 1);
7796 
7797     bft_printf(_(" %s: %llu Faces with upwind on %llu interior faces\n"),
7798                var_name, (unsigned long long)n_upwind,
7799                (unsigned long long)m->n_g_i_c_faces);
7800   }
7801 
7802   /* ======================================================================
7803      ---> Contribution from boundary faces
7804      ======================================================================*/
7805 
7806   /* Steady */
7807   if (idtvar < 0) {
7808 
7809     for (int g_id = 0; g_id < n_b_groups; g_id++) {
7810 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
7811       for (int t_id = 0; t_id < n_b_threads; t_id++) {
7812         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
7813              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
7814              face_id++) {
7815 
7816           cs_lnum_t ii = b_face_cells[face_id];
7817 
7818           cs_real_t fluxi = 0.;
7819           cs_real_t pir, pipr;
7820 
7821           cs_real_t bldfrp = (cs_real_t) ircflp;
7822           /* Local limitation of the reconstruction */
7823           if (df_limiter != NULL && ircflp > 0)
7824             bldfrp = CS_MAX(df_limiter[ii], 0.);
7825 
7826           cs_b_cd_steady(bldfrp,
7827                          relaxp,
7828                          diipb[face_id],
7829                          grad[ii],
7830                          _pvar[ii],
7831                          pvara[ii],
7832                          &pir,
7833                          &pipr);
7834 
7835           cs_b_upwind_flux(iconvp,
7836                            1.,
7837                            1,
7838                            inc,
7839                            bc_type[face_id],
7840                            _pvar[ii],
7841                            pir,
7842                            pipr,
7843                            coefap[face_id],
7844                            coefbp[face_id],
7845                            b_massflux[face_id],
7846                            xcpp[ii],
7847                            &fluxi);
7848 
7849           cs_b_diff_flux(idiffp,
7850                          1., /* thetap */
7851                          inc,
7852                          pipr,
7853                          cofafp[face_id],
7854                          cofbfp[face_id],
7855                          b_visc[face_id],
7856                          &fluxi);
7857 
7858           rhs[ii] -= fluxi;
7859 
7860         }
7861       }
7862     }
7863 
7864     /* The thermal is internal_coupled and an implicit contribution
7865      * is required */
7866     if (icoupl > 0) {
7867       /* Prepare data for sending */
7868       BFT_MALLOC(pvar_distant, n_distant, cs_real_t);
7869 
7870       for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
7871         cs_lnum_t face_id = faces_distant[ii];
7872         cs_lnum_t jj = b_face_cells[face_id];
7873         cs_real_t pip, pipr;
7874 
7875         cs_real_t bldfrp = (cs_real_t) ircflp;
7876         /* Local limitation of the reconstruction */
7877         /* Note: to be treated exactly as a internal face, should be a bending
7878          * between the two cells... */
7879         if (df_limiter != NULL && ircflp > 0)
7880           bldfrp = CS_MAX(df_limiter[jj], 0.);
7881 
7882         cs_b_cd_steady(bldfrp,
7883                        relaxp,
7884                        diipb[face_id],
7885                        grad[jj],
7886                        _pvar[jj],
7887                        pvara[jj],
7888                        &pip,
7889                        &pipr);
7890         pvar_distant[ii] = pipr;
7891       }
7892 
7893       /* Receive data */
7894       BFT_MALLOC(pvar_local, n_local, cs_real_t);
7895       cs_internal_coupling_exchange_var(cpl,
7896                                         1, /* Dimension */
7897                                         pvar_distant,
7898                                         pvar_local);
7899       if (df_limiter != NULL) {
7900         BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
7901         cs_internal_coupling_exchange_var(cpl,
7902                                           1, /* Dimension */
7903                                           df_limiter,
7904                                           df_limiter_local);
7905       }
7906 
7907       /* Flux contribution */
7908       assert(f_id!=-1); // Otherwise the "f" can't be used
7909       cs_real_t *hintp = f->bc_coeffs->hint;
7910       cs_real_t *hextp = f->bc_coeffs->hext;
7911       for (cs_lnum_t ii = 0; ii < n_local; ii++) {
7912         cs_lnum_t face_id = faces_local[ii];
7913         cs_lnum_t jj = b_face_cells[face_id];
7914         cs_real_t pip, pipr, pjpr;
7915         cs_real_t fluxi = 0.;
7916 
7917         cs_real_t bldfrp = (cs_real_t) ircflp;
7918         /* Local limitation of the reconstruction */
7919         if (df_limiter != NULL && ircflp > 0)
7920           bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
7921 
7922         cs_b_cd_steady(bldfrp,
7923                        relaxp,
7924                        diipb[face_id],
7925                        grad[jj],
7926                        _pvar[jj],
7927                        pvara[jj],
7928                        &pip,
7929                        &pipr);
7930 
7931         pjpr = pvar_local[ii];
7932 
7933         cs_real_t hint = hintp[face_id];
7934         cs_real_t hext = hextp[face_id];
7935         cs_real_t heq = _calc_heq(hint, hext);
7936 
7937         cs_b_diff_flux_coupling(idiffp,
7938                                 pipr,
7939                                 pjpr,
7940                                 heq,
7941                                 &fluxi);
7942 
7943         rhs[jj] -= thetap * fluxi;
7944       }
7945 
7946       BFT_FREE(pvar_local);
7947       /* Sending structures are no longer needed */
7948       BFT_FREE(pvar_distant);
7949       if (df_limiter != NULL)
7950         BFT_FREE(df_limiter_local);
7951 
7952     }
7953 
7954     /* Unsteady */
7955   } else {
7956 
7957     for (int g_id = 0; g_id < n_b_groups; g_id++) {
7958 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
7959       for (int t_id = 0; t_id < n_b_threads; t_id++) {
7960         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
7961              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
7962              face_id++) {
7963 
7964           cs_lnum_t ii = b_face_cells[face_id];
7965 
7966           cs_real_t fluxi = 0.;
7967           cs_real_t pip;
7968 
7969           cs_real_t bldfrp = (cs_real_t) ircflp;
7970           /* Local limitation of the reconstruction */
7971           if (df_limiter != NULL && ircflp > 0)
7972             bldfrp = CS_MAX(df_limiter[ii], 0.);
7973 
7974           cs_b_cd_unsteady(bldfrp,
7975                            diipb[face_id],
7976                            grad[ii],
7977                            _pvar[ii],
7978                            &pip);
7979 
7980           cs_b_upwind_flux(iconvp,
7981                            thetap,
7982                            imasac,
7983                            inc,
7984                            bc_type[face_id],
7985                            _pvar[ii],
7986                            _pvar[ii], /* no relaxation */
7987                            pip,
7988                            coefap[face_id],
7989                            coefbp[face_id],
7990                            b_massflux[face_id],
7991                            xcpp[ii],
7992                            &fluxi);
7993 
7994           cs_b_diff_flux(idiffp,
7995                          thetap,
7996                          inc,
7997                          pip,
7998                          cofafp[face_id],
7999                          cofbfp[face_id],
8000                          b_visc[face_id],
8001                          &fluxi);
8002 
8003           rhs[ii] -= fluxi;
8004 
8005         }
8006       }
8007     }
8008 
8009     /* The thermal is internal_coupled and an implicit contribution
8010      * is required */
8011     if (icoupl > 0) {
8012       /* Prepare data for sending */
8013       BFT_MALLOC(pvar_distant, n_distant, cs_real_t);
8014 
8015       for (cs_lnum_t ii = 0; ii < n_distant; ii++) {
8016         cs_lnum_t face_id = faces_distant[ii];
8017         cs_lnum_t jj = b_face_cells[face_id];
8018         cs_real_t pip;
8019 
8020         cs_real_t bldfrp = (cs_real_t) ircflp;
8021         /* Local limitation of the reconstruction */
8022         /* Note: to be treated exactly as a internal face, should be a bending
8023          * between the two cells... */
8024         if (df_limiter != NULL && ircflp > 0)
8025           bldfrp = CS_MAX(df_limiter[jj], 0.);
8026 
8027         cs_b_cd_unsteady(bldfrp,
8028                          diipb[face_id],
8029                          grad[jj],
8030                          _pvar[jj],
8031                          &pip);
8032         pvar_distant[ii] = pip;
8033       }
8034 
8035       /* Receive data */
8036       BFT_MALLOC(pvar_local, n_local, cs_real_t);
8037       cs_internal_coupling_exchange_var(cpl,
8038                                         1, /* Dimension */
8039                                         pvar_distant,
8040                                         pvar_local);
8041       if (df_limiter != NULL) {
8042         BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
8043         cs_internal_coupling_exchange_var(cpl,
8044                                           1, /* Dimension */
8045                                           df_limiter,
8046                                           df_limiter_local);
8047       }
8048 
8049       /* Flux contribution */
8050       assert(f_id!=-1); // Otherwise the "f" can't be used
8051       cs_real_t *hintp = f->bc_coeffs->hint;
8052       cs_real_t *hextp = f->bc_coeffs->hext;
8053       for (cs_lnum_t ii = 0; ii < n_local; ii++) {
8054         cs_lnum_t face_id = faces_local[ii];
8055         cs_lnum_t jj = b_face_cells[face_id];
8056         cs_real_t pip, pjp;
8057         cs_real_t fluxi = 0.;
8058 
8059         cs_real_t bldfrp = (cs_real_t) ircflp;
8060         /* Local limitation of the reconstruction */
8061         if (df_limiter != NULL && ircflp > 0)
8062           bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
8063 
8064         cs_b_cd_unsteady(bldfrp,
8065                          diipb[face_id],
8066                          grad[jj],
8067                          _pvar[jj],
8068                          &pip);
8069 
8070         pjp = pvar_local[ii];
8071 
8072         cs_real_t hint = hintp[face_id];
8073         cs_real_t hext = hextp[face_id];
8074         cs_real_t heq = _calc_heq(hint, hext);
8075 
8076         cs_b_diff_flux_coupling(idiffp,
8077                                 pip,
8078                                 pjp,
8079                                 heq,
8080                                 &fluxi);
8081 
8082         rhs[jj] -= thetap * fluxi;
8083       }
8084 
8085       BFT_FREE(pvar_local);
8086       /* Sending structures are no longer needed */
8087       BFT_FREE(pvar_distant);
8088       if (df_limiter != NULL)
8089         BFT_FREE(df_limiter_local);
8090 
8091     }
8092 
8093   }
8094 
8095   /* Free memory */
8096   BFT_FREE(grad);
8097   BFT_FREE(gradup);
8098   BFT_FREE(gradst);
8099   BFT_FREE(local_max);
8100   BFT_FREE(local_min);
8101 }
8102 
8103 /*----------------------------------------------------------------------------*/
8104 /*!
8105  * \brief Add the explicit part of the diffusion terms with a symmetric tensor
8106  * diffusivity for a transport equation of a scalar field \f$ \varia \f$.
8107  *
8108  * More precisely, the right hand side \f$ Rhs \f$ is updated as
8109  * follows:
8110  * \f[
8111  * Rhs = Rhs - \sum_{\fij \in \Facei{\celli}}      \left(
8112  *      - \tens{\mu}_\fij \gradv_\fij \varia \cdot \vect{S}_\ij  \right)
8113  * \f]
8114  *
8115  * Warning:
8116  * - \f$ Rhs \f$ has already been initialized before
8117  *   calling cs_anisotropic_diffusion_scalar!
8118  * - mind the sign minus
8119  *
8120  * \param[in]     idtvar        indicator of the temporal scheme
8121  * \param[in]     f_id          index of the current variable
8122  * \param[in]     var_cal_opt   variable calculation options
8123  * \param[in]     inc           indicator
8124  *                               - 0 when solving an increment
8125  *                               - 1 otherwise
8126  * \param[in]     iccocg        indicator
8127  *                               - 1 re-compute cocg matrix
8128                                 (for iterativ gradients)
8129  *                               - 0 otherwise
8130  * \param[in]     pvar          solved variable (current time step)
8131  * \param[in]     pvara         solved variable (previous time step)
8132  * \param[in]     coefap        boundary condition array for the variable
8133  *                               (explicit part)
8134  * \param[in]     coefbp        boundary condition array for the variable
8135  *                               (implicit part)
8136  * \param[in]     cofafp        boundary condition array for the diffusion
8137  *                               of the variable (explicit part)
8138  * \param[in]     cofbfp        boundary condition array for the diffusion
8139  *                               of the variable (implicit part)
8140  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
8141  *                               at interior faces for the r.h.s.
8142  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
8143  *                               at border faces for the r.h.s.
8144  * \param[in]     viscel        symmetric cell tensor \f$ \tens{\mu}_\celli \f$
8145  * \param[in]     weighf        internal face weight between cells i j in case
8146  *                               of tensor diffusion
8147  * \param[in]     weighb        boundary face weight for cells i in case
8148  *                               of tensor diffusion
8149  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
8150  */
8151 /*----------------------------------------------------------------------------*/
8152 
8153 void
cs_anisotropic_diffusion_scalar(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int inc,int iccocg,cs_real_t * restrict pvar,const cs_real_t * restrict pvara,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict viscel,const cs_real_2_t weighf[],const cs_real_t weighb[],cs_real_t * restrict rhs)8154 cs_anisotropic_diffusion_scalar(int                       idtvar,
8155                                 int                       f_id,
8156                                 const cs_var_cal_opt_t    var_cal_opt,
8157                                 int                       inc,
8158                                 int                       iccocg,
8159                                 cs_real_t       *restrict pvar,
8160                                 const cs_real_t *restrict pvara,
8161                                 const cs_real_t           coefap[],
8162                                 const cs_real_t           coefbp[],
8163                                 const cs_real_t           cofafp[],
8164                                 const cs_real_t           cofbfp[],
8165                                 const cs_real_t           i_visc[],
8166                                 const cs_real_t           b_visc[],
8167                                 cs_real_6_t     *restrict viscel,
8168                                 const cs_real_2_t         weighf[],
8169                                 const cs_real_t           weighb[],
8170                                 cs_real_t       *restrict rhs)
8171 {
8172   const int nswrgp = var_cal_opt.nswrgr;
8173   const int imrgra = var_cal_opt.imrgra;
8174   const int imligp = var_cal_opt.imligr;
8175   const int ircflp = var_cal_opt.ircflu;
8176   const int iwarnp = var_cal_opt.verbosity;
8177   const int icoupl = var_cal_opt.icoupl;
8178   const double epsrgp = var_cal_opt.epsrgr;
8179   const double climgp = var_cal_opt.climgr;
8180   const double relaxp = var_cal_opt.relaxv;
8181   const double thetap = var_cal_opt.thetav;
8182 
8183   const cs_mesh_t  *m = cs_glob_mesh;
8184   const cs_halo_t  *halo = m->halo;
8185   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
8186 
8187   const cs_lnum_t n_cells = m->n_cells;
8188   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
8189   const int n_i_groups = m->i_face_numbering->n_groups;
8190   const int n_i_threads = m->i_face_numbering->n_threads;
8191   const int n_b_groups = m->b_face_numbering->n_groups;
8192   const int n_b_threads = m->b_face_numbering->n_threads;
8193   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
8194   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
8195 
8196   const cs_lnum_2_t *restrict i_face_cells
8197     = (const cs_lnum_2_t *restrict)m->i_face_cells;
8198   const cs_lnum_t *restrict b_face_cells
8199     = (const cs_lnum_t *restrict)m->b_face_cells;
8200   const cs_real_3_t *restrict cell_cen
8201     = (const cs_real_3_t *restrict)fvq->cell_cen;
8202   const cs_real_3_t *restrict i_face_normal
8203     = (const cs_real_3_t *restrict)fvq->i_face_normal;
8204   const cs_real_3_t *restrict b_face_normal
8205     = (const cs_real_3_t *restrict)fvq->b_face_normal;
8206   const cs_real_3_t *restrict i_face_cog
8207     = (const cs_real_3_t *restrict)fvq->i_face_cog;
8208   const cs_real_3_t *restrict b_face_cog
8209     = (const cs_real_3_t *restrict)fvq->b_face_cog;
8210 
8211   /* Local variables */
8212 
8213   cs_real_t *df_limiter = NULL;
8214 
8215   char var_name[64];
8216 
8217   int w_stride = 1;
8218 
8219   bool recompute_cocg = (iccocg) ? true : false;
8220 
8221   cs_real_6_t *viscce;
8222   cs_real_6_t *w2;
8223   cs_real_3_t *grad;
8224 
8225   cs_field_t *f = NULL;
8226 
8227   cs_real_t *gweight = NULL;
8228 
8229   /* Internal coupling variables */
8230   cs_real_t *pvar_local = NULL;
8231   cs_real_3_t *grad_local = NULL;
8232   cs_real_t *df_limiter_local = NULL;
8233   cs_real_6_t *viscce_local = NULL;
8234   cs_real_t *weighb_local = NULL;
8235   const cs_lnum_t *faces_local = NULL;
8236   cs_lnum_t n_local = 0;
8237   int coupling_id = -1;
8238   cs_internal_coupling_t *cpl = NULL;
8239 
8240   /* 1. Initialization */
8241 
8242   viscce = NULL;
8243   w2 = NULL;
8244 
8245   /* Allocate work arrays */
8246   BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
8247 
8248   /* Choose gradient type */
8249   cs_halo_type_t halo_type = CS_HALO_STANDARD;
8250   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8251 
8252   cs_gradient_type_by_imrgra(imrgra,
8253                              &gradient_type,
8254                              &halo_type);
8255 
8256   /* Handle cases where only the previous values (already synchronized)
8257      or current values are provided */
8258 
8259   if (pvar != NULL)
8260     cs_sync_scalar_halo(m, pvar);
8261   if (pvara == NULL)
8262     pvara = (const cs_real_t *restrict)pvar;
8263 
8264   const cs_real_t  *restrict _pvar = (pvar != NULL) ? pvar : pvara;
8265 
8266   /* Logging */
8267 
8268   if (f_id != -1) {
8269     f = cs_field_by_id(f_id);
8270 
8271     int df_limiter_id =
8272       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
8273     if (df_limiter_id > -1)
8274       df_limiter = cs_field_by_id(df_limiter_id)->val;
8275 
8276     snprintf(var_name, 63, "%s", f->name);
8277   }
8278   else
8279     strncpy(var_name, "[anisotropic diffusion, scalar]", 63);
8280   var_name[63] = '\0';
8281 
8282   /* Porosity fields */
8283   cs_field_t *fporo = cs_field_by_name_try("porosity");
8284   cs_field_t *ftporo = cs_field_by_name_try("tensorial_porosity");
8285 
8286   cs_real_t *porosi = NULL;
8287   cs_real_6_t *porosf = NULL;
8288 
8289   if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2) {
8290     porosi = fporo->val;
8291     if (ftporo != NULL) {
8292       porosf = (cs_real_6_t *)ftporo->val;
8293     }
8294   }
8295 
8296   /* Without porosity */
8297   if (porosi == NULL) {
8298     viscce = viscel;
8299 
8300     /* With porosity */
8301   } else if (porosi != NULL && porosf == NULL) {
8302     BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
8303     for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
8304       for (int isou = 0; isou < 6; isou++) {
8305         w2[cell_id][isou] = porosi[cell_id]*viscel[cell_id][isou];
8306       }
8307     }
8308     viscce = w2;
8309 
8310     /* With tensorial porosity */
8311   } else if (porosi != NULL && porosf != NULL) {
8312     BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
8313     for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
8314       cs_math_sym_33_product(porosf[cell_id],
8315                              viscel[cell_id],
8316                              w2[cell_id]);
8317     }
8318     viscce = w2;
8319   }
8320 
8321   /* ---> Periodicity and parallelism treatment of symmetric tensors */
8322   if (halo != NULL) {
8323     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)viscce, 6);
8324     if (m->n_init_perio > 0)
8325       cs_halo_perio_sync_var_sym_tens(halo, halo_type, (cs_real_t *)viscce);
8326   }
8327 
8328   if (icoupl > 0) {
8329     assert(f_id != -1);
8330     const int coupling_key_id = cs_field_key_id("coupling_entity");
8331     coupling_id = cs_field_get_key_int(f, coupling_key_id);
8332     cpl = cs_internal_coupling_by_id(coupling_id);
8333     cs_internal_coupling_coupled_faces(cpl,
8334                                        &n_local,
8335                                        &faces_local,
8336                                        NULL,
8337                                        NULL);
8338   }
8339 
8340   /* 2. Compute the diffusive part with reconstruction technics */
8341 
8342   /* ======================================================================
8343      ---> Compute the gradient of the current variable if needed
8344      ======================================================================*/
8345 
8346   if (ircflp == 1) {
8347 
8348     if (f_id != -1) {
8349       /* Get the calculation option from the field */
8350       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
8351         if (var_cal_opt.idifft > 0) {
8352           int key_id = cs_field_key_id("gradient_weighting_id");
8353           int diff_id = cs_field_get_key_int(f, key_id);
8354           if (diff_id > -1) {
8355             cs_field_t *weight_f = cs_field_by_id(diff_id);
8356             gweight = weight_f->val;
8357             w_stride = weight_f->dim;
8358             cs_field_synchronize(weight_f, halo_type);
8359           }
8360         }
8361       }
8362     }
8363 
8364     cs_gradient_scalar_synced_input(var_name,
8365                                     gradient_type,
8366                                     halo_type,
8367                                     inc,
8368                                     recompute_cocg,
8369                                     nswrgp,
8370                                     0, /* hyd_p_flag */
8371                                     w_stride,
8372                                     iwarnp,
8373                                     imligp,
8374                                     epsrgp,
8375                                     climgp,
8376                                     NULL, /* f_ext exterior force */
8377                                     coefap,
8378                                     coefbp,
8379                                     _pvar,
8380                                     gweight, /* Weighted gradient */
8381                                     cpl, /* internal coupling */
8382                                     grad);
8383 
8384   } else {
8385 #   pragma omp parallel for
8386     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
8387       grad[cell_id][0] = 0.;
8388       grad[cell_id][1] = 0.;
8389       grad[cell_id][2] = 0.;
8390     }
8391   }
8392 
8393   /* ======================================================================
8394      ---> Contribution from interior faces
8395      ======================================================================*/
8396 
8397   if (n_cells_ext > n_cells) {
8398 #   pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
8399     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
8400       rhs[cell_id] = 0.;
8401     }
8402   }
8403 
8404   /* Steady */
8405   if (idtvar < 0) {
8406 
8407     for (int g_id = 0; g_id < n_i_groups; g_id++) {
8408 #     pragma omp parallel for
8409       for (int t_id = 0; t_id < n_i_threads; t_id++) {
8410         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
8411              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
8412              face_id++) {
8413 
8414           cs_lnum_t ii = i_face_cells[face_id][0];
8415           cs_lnum_t jj = i_face_cells[face_id][1];
8416 
8417           cs_real_t pi = _pvar[ii];
8418           cs_real_t pj = _pvar[jj];
8419           cs_real_t pia = pvara[ii];
8420           cs_real_t pja = pvara[jj];
8421 
8422           cs_real_t bldfrp = (cs_real_t) ircflp;
8423           /* Local limitation of the reconstruction */
8424           if (df_limiter != NULL && ircflp > 0)
8425             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
8426 
8427           /* Recompute II" and JJ"
8428              ----------------------*/
8429 
8430           cs_real_t visci[3][3], viscj[3][3];
8431 
8432           visci[0][0] = viscce[ii][0];
8433           visci[1][1] = viscce[ii][1];
8434           visci[2][2] = viscce[ii][2];
8435           visci[1][0] = viscce[ii][3];
8436           visci[0][1] = viscce[ii][3];
8437           visci[2][1] = viscce[ii][4];
8438           visci[1][2] = viscce[ii][4];
8439           visci[2][0] = viscce[ii][5];
8440           visci[0][2] = viscce[ii][5];
8441 
8442           /* IF.Ki.S / ||Ki.S||^2 */
8443           cs_real_t fikdvi = weighf[face_id][0];
8444 
8445           cs_real_t diippf[3], djjppf[3];
8446 
8447           /* II" = IF + FI" */
8448           for (int i = 0; i < 3; i++) {
8449             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
8450                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
8451                                + visci[1][i]*i_face_normal[face_id][1]
8452                                + visci[2][i]*i_face_normal[face_id][2] );
8453           }
8454 
8455           viscj[0][0] = viscce[jj][0];
8456           viscj[1][1] = viscce[jj][1];
8457           viscj[2][2] = viscce[jj][2];
8458           viscj[1][0] = viscce[jj][3];
8459           viscj[0][1] = viscce[jj][3];
8460           viscj[2][1] = viscce[jj][4];
8461           viscj[1][2] = viscce[jj][4];
8462           viscj[2][0] = viscce[jj][5];
8463           viscj[0][2] = viscce[jj][5];
8464 
8465           /* FJ.Kj.S / ||Kj.S||^2 */
8466           cs_real_t fjkdvi = weighf[face_id][1];
8467 
8468           /* JJ" = JF + FJ" */
8469           for (int i = 0; i < 3; i++) {
8470             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
8471                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
8472                                + viscj[1][i]*i_face_normal[face_id][1]
8473                                + viscj[2][i]*i_face_normal[face_id][2] );
8474           }
8475 
8476           /* p in I" and J" */
8477           cs_real_t pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
8478                                         + grad[ii][1]*diippf[1]
8479                                         + grad[ii][2]*diippf[2]);
8480           cs_real_t pjpp = pj + bldfrp*(  grad[jj][0]*djjppf[0]
8481                                         + grad[jj][1]*djjppf[1]
8482                                         + grad[jj][2]*djjppf[2]);
8483 
8484           cs_real_t pir = pi/relaxp - (1.-relaxp)/relaxp * pia;
8485           cs_real_t pjr = pj/relaxp - (1.-relaxp)/relaxp * pja;
8486 
8487           /* pr in I" and J" */
8488           cs_real_t pippr = pir + bldfrp*(  grad[ii][0]*diippf[0]
8489                                           + grad[ii][1]*diippf[1]
8490                                           + grad[ii][2]*diippf[2]);
8491           cs_real_t pjppr = pjr + bldfrp*(  grad[jj][0]*djjppf[0]
8492                                           + grad[jj][1]*djjppf[1]
8493                                           + grad[jj][2]*djjppf[2]);
8494 
8495 
8496           cs_real_t fluxi = i_visc[face_id]*(pippr - pjpp);
8497           cs_real_t fluxj = i_visc[face_id]*(pipp - pjppr);
8498 
8499           rhs[ii] -= fluxi;
8500           rhs[jj] += fluxj;
8501 
8502         }
8503       }
8504     }
8505 
8506     /* Unsteady */
8507   } else {
8508 
8509     for (int g_id = 0; g_id < n_i_groups; g_id++) {
8510 #     pragma omp parallel for
8511       for (int t_id = 0; t_id < n_i_threads; t_id++) {
8512         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
8513              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
8514              face_id++) {
8515 
8516           cs_lnum_t ii = i_face_cells[face_id][0];
8517           cs_lnum_t jj = i_face_cells[face_id][1];
8518 
8519           cs_real_t pi = _pvar[ii];
8520           cs_real_t pj = _pvar[jj];
8521 
8522           cs_real_t bldfrp = (cs_real_t) ircflp;
8523           /* Local limitation of the reconstruction */
8524           if (df_limiter != NULL && ircflp > 0)
8525             bldfrp = CS_MAX(df_limiter[jj], 0.);
8526 
8527           /* Recompute II" and JJ"
8528              ----------------------*/
8529 
8530           cs_real_t visci[3][3], viscj[3][3];
8531 
8532           visci[0][0] = viscce[ii][0];
8533           visci[1][1] = viscce[ii][1];
8534           visci[2][2] = viscce[ii][2];
8535           visci[1][0] = viscce[ii][3];
8536           visci[0][1] = viscce[ii][3];
8537           visci[2][1] = viscce[ii][4];
8538           visci[1][2] = viscce[ii][4];
8539           visci[2][0] = viscce[ii][5];
8540           visci[0][2] = viscce[ii][5];
8541 
8542           /* IF.Ki.S / ||Ki.S||^2 */
8543           cs_real_t fikdvi = weighf[face_id][0];
8544 
8545           cs_real_t diippf[3], djjppf[3];
8546 
8547           /* II" = IF + FI" */
8548           for (int i = 0; i < 3; i++) {
8549             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
8550                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
8551                                + visci[1][i]*i_face_normal[face_id][1]
8552                                + visci[2][i]*i_face_normal[face_id][2] );
8553           }
8554 
8555           viscj[0][0] = viscce[jj][0];
8556           viscj[1][1] = viscce[jj][1];
8557           viscj[2][2] = viscce[jj][2];
8558           viscj[1][0] = viscce[jj][3];
8559           viscj[0][1] = viscce[jj][3];
8560           viscj[2][1] = viscce[jj][4];
8561           viscj[1][2] = viscce[jj][4];
8562           viscj[2][0] = viscce[jj][5];
8563           viscj[0][2] = viscce[jj][5];
8564 
8565           /* FJ.Kj.S / ||Kj.S||^2 */
8566           cs_real_t fjkdvi = weighf[face_id][1];
8567 
8568           /* JJ" = JF + FJ" */
8569           for (int i = 0; i < 3; i++) {
8570             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
8571                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
8572                                + viscj[1][i]*i_face_normal[face_id][1]
8573                                + viscj[2][i]*i_face_normal[face_id][2] );
8574           }
8575 
8576           /* p in I" and J" */
8577           cs_real_t pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
8578                                         + grad[ii][1]*diippf[1]
8579                                         + grad[ii][2]*diippf[2]);
8580           cs_real_t pjpp = pj + bldfrp*(  grad[jj][0]*djjppf[0]
8581                                         + grad[jj][1]*djjppf[1]
8582                                         + grad[jj][2]*djjppf[2]);
8583 
8584           cs_real_t flux = i_visc[face_id]*(pipp -pjpp);
8585 
8586           rhs[ii] -= thetap*flux;
8587           rhs[jj] += thetap*flux;
8588 
8589         }
8590       }
8591     }
8592   }
8593 
8594   /* ======================================================================
8595      ---> Contribution from boundary faces
8596      ======================================================================*/
8597 
8598   /* Steady */
8599   if (idtvar < 0) {
8600 
8601     for (int g_id = 0; g_id < n_b_groups; g_id++) {
8602 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
8603       for (int t_id = 0; t_id < n_b_threads; t_id++) {
8604         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
8605              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
8606              face_id++) {
8607 
8608           cs_lnum_t ii = b_face_cells[face_id];
8609 
8610           cs_real_t pi = _pvar[ii];
8611           cs_real_t pia = pvara[ii];
8612 
8613           cs_real_t pir = pi/relaxp - (1.-relaxp)/relaxp*pia;
8614 
8615           cs_real_t bldfrp = (cs_real_t) ircflp;
8616           /* Local limitation of the reconstruction */
8617           if (df_limiter != NULL && ircflp > 0)
8618             bldfrp = CS_MAX(df_limiter[ii], 0.);
8619 
8620           /* Recompute II"
8621              --------------*/
8622 
8623           cs_real_t visci[3][3];
8624 
8625           visci[0][0] = viscce[ii][0];
8626           visci[1][1] = viscce[ii][1];
8627           visci[2][2] = viscce[ii][2];
8628           visci[1][0] = viscce[ii][3];
8629           visci[0][1] = viscce[ii][3];
8630           visci[2][1] = viscce[ii][4];
8631           visci[1][2] = viscce[ii][4];
8632           visci[2][0] = viscce[ii][5];
8633           visci[0][2] = viscce[ii][5];
8634 
8635           /* IF.Ki.S / ||Ki.S||^2 */
8636           cs_real_t fikdvi = weighb[face_id];
8637 
8638           cs_real_t diippf[3];
8639 
8640           /* II" = IF + FI" */
8641           for (int i = 0; i < 3; i++) {
8642             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
8643                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
8644                                + visci[1][i]*b_face_normal[face_id][1]
8645                                + visci[2][i]*b_face_normal[face_id][2] );
8646           }
8647 
8648           cs_real_t pippr = pir + bldfrp*(  grad[ii][0]*diippf[0]
8649                                           + grad[ii][1]*diippf[1]
8650                                           + grad[ii][2]*diippf[2]);
8651 
8652           cs_real_t pfacd = inc*cofafp[face_id] + cofbfp[face_id]*pippr;
8653 
8654           cs_real_t flux = b_visc[face_id]*pfacd;
8655           rhs[ii] -= flux;
8656 
8657         }
8658       }
8659     }
8660 
8661     /* Unsteady */
8662   } else {
8663 
8664     for (int g_id = 0; g_id < n_b_groups; g_id++) {
8665 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
8666       for (int t_id = 0; t_id < n_b_threads; t_id++) {
8667         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
8668              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
8669              face_id++) {
8670 
8671           cs_lnum_t ii = b_face_cells[face_id];
8672 
8673           cs_real_t pi = _pvar[ii];
8674 
8675           cs_real_t bldfrp = (cs_real_t) ircflp;
8676           /* Local limitation of the reconstruction */
8677           if (df_limiter != NULL && ircflp > 0)
8678             bldfrp = CS_MAX(df_limiter[ii], 0.);
8679 
8680           /* Recompute II"
8681              --------------*/
8682 
8683           cs_real_t visci[3][3];
8684 
8685           visci[0][0] = viscce[ii][0];
8686           visci[1][1] = viscce[ii][1];
8687           visci[2][2] = viscce[ii][2];
8688           visci[1][0] = viscce[ii][3];
8689           visci[0][1] = viscce[ii][3];
8690           visci[2][1] = viscce[ii][4];
8691           visci[1][2] = viscce[ii][4];
8692           visci[2][0] = viscce[ii][5];
8693           visci[0][2] = viscce[ii][5];
8694 
8695           /* IF.Ki.S / ||Ki.S||^2 */
8696           cs_real_t fikdvi = weighb[face_id];
8697 
8698           cs_real_t diippf[3];
8699 
8700           /* II" = IF + FI" */
8701           for (int i = 0; i < 3; i++) {
8702             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
8703                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
8704                                + visci[1][i]*b_face_normal[face_id][1]
8705                                + visci[2][i]*b_face_normal[face_id][2]);
8706           }
8707 
8708           cs_real_t pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
8709                                         + grad[ii][1]*diippf[1]
8710                                         + grad[ii][2]*diippf[2]);
8711 
8712           cs_real_t pfacd = inc*cofafp[face_id] + cofbfp[face_id]*pipp;
8713 
8714           cs_real_t flux = b_visc[face_id]*pfacd;
8715           rhs[ii] -= thetap*flux;
8716 
8717         }
8718       }
8719     }
8720 
8721     /* The scalar is internal_coupled and an implicit contribution
8722      * is required */
8723     if (icoupl > 0) {
8724 
8725       /* Exchange pvar */
8726       BFT_MALLOC(pvar_local, n_local, cs_real_t);
8727       cs_internal_coupling_exchange_by_cell_id(cpl,
8728                                                1, /* Dimension */
8729                                                _pvar,
8730                                                pvar_local);
8731 
8732       /* Exchange grad */
8733       BFT_MALLOC(grad_local, n_local, cs_real_3_t);
8734       cs_internal_coupling_exchange_by_cell_id(cpl,
8735                                                3, /* Dimension */
8736                                                (const cs_real_t*)grad,
8737                                                (cs_real_t *)grad_local);
8738 
8739       /* Exchange viscce */
8740       BFT_MALLOC(viscce_local, n_local, cs_real_6_t);
8741       cs_internal_coupling_exchange_by_cell_id(cpl,
8742                                                6, /* Dimension */
8743                                                (const cs_real_t*)viscce,
8744                                                (cs_real_t *)viscce_local);
8745 
8746       /* Exchange weighb */
8747       BFT_MALLOC(weighb_local, n_local, cs_real_t);
8748       cs_internal_coupling_exchange_by_face_id(cpl,
8749                                                1, /* Dimension */
8750                                                (const cs_real_t*)weighb,
8751                                                (cs_real_t *)weighb_local);
8752 
8753       /* Exchange diffusion limiter */
8754       if (df_limiter != NULL) {
8755         BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
8756         cs_internal_coupling_exchange_var(cpl,
8757                                           1, /* Dimension */
8758                                           df_limiter,
8759                                           df_limiter_local);
8760       }
8761 
8762       /* Flux contribution */
8763       for (cs_lnum_t jj = 0; jj < n_local; jj++) {
8764         cs_lnum_t face_id = faces_local[jj];
8765         cs_lnum_t ii = b_face_cells[face_id];
8766 
8767         cs_real_t pi = _pvar[ii];
8768         cs_real_t pj = pvar_local[jj];
8769 
8770         cs_real_t bldfrp = (cs_real_t) ircflp;
8771         /* Local limitation of the reconstruction */
8772         if (df_limiter != NULL && ircflp > 0)
8773           bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
8774 
8775         /* Recompute II" and JJ" */
8776         cs_real_t visci[3][3], viscj[3][3];
8777         cs_real_t diippf[3], djjppf[3];
8778 
8779         visci[0][0] = viscce[ii][0];
8780         visci[1][1] = viscce[ii][1];
8781         visci[2][2] = viscce[ii][2];
8782         visci[1][0] = viscce[ii][3];
8783         visci[0][1] = viscce[ii][3];
8784         visci[2][1] = viscce[ii][4];
8785         visci[1][2] = viscce[ii][4];
8786         visci[2][0] = viscce[ii][5];
8787         visci[0][2] = viscce[ii][5];
8788 
8789         /* IF.Ki.S / ||Ki.S||^2 */
8790         cs_real_t fikdvi = weighb[face_id];
8791 
8792         /* II" = IF + FI" */
8793         for (int i = 0; i < 3; i++) {
8794           diippf[i] = b_face_cog[face_id][i]-cell_cen[ii][i]
8795                     - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
8796                              + visci[1][i]*b_face_normal[face_id][1]
8797                              + visci[2][i]*b_face_normal[face_id][2] );
8798         }
8799 
8800         viscj[0][0] = viscce_local[jj][0];
8801         viscj[1][1] = viscce_local[jj][1];
8802         viscj[2][2] = viscce_local[jj][2];
8803         viscj[1][0] = viscce_local[jj][3];
8804         viscj[0][1] = viscce_local[jj][3];
8805         viscj[2][1] = viscce_local[jj][4];
8806         viscj[1][2] = viscce_local[jj][4];
8807         viscj[2][0] = viscce_local[jj][5];
8808         viscj[0][2] = viscce_local[jj][5];
8809 
8810         /* FJ.Kj.S / ||Kj.S||^2
8811          * weighb_local defined with vector JF and surface -S */
8812         cs_real_t fjkdvi = weighb_local[jj];
8813 
8814         /* JJ" = JF + FJ"
8815          *   */
8816         for (int i = 0; i < 3; i++) {
8817           djjppf[i] = b_face_cog[face_id][i]-cell_cen[ii][i]-cpl->ci_cj_vect[jj][i]
8818                     + fjkdvi*( viscj[0][i]*b_face_normal[face_id][0]
8819                              + viscj[1][i]*b_face_normal[face_id][1]
8820                              + viscj[2][i]*b_face_normal[face_id][2] );
8821         }
8822 
8823         /* p in I" and J" */
8824         cs_real_t pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
8825                                       + grad[ii][1]*diippf[1]
8826                                       + grad[ii][2]*diippf[2]);
8827         cs_real_t pjpp = pj + bldfrp*(  grad_local[jj][0]*djjppf[0]
8828                                       + grad_local[jj][1]*djjppf[1]
8829                                       + grad_local[jj][2]*djjppf[2]);
8830 
8831         /* Reproduce multiplication by i_visc[face_id] */
8832         cs_real_t flux = (pipp - pjpp) / (weighb[face_id] + weighb_local[jj]);
8833 
8834         rhs[ii] -= thetap*flux;
8835 
8836       }
8837 
8838       /* Remote data no longer needed */
8839       BFT_FREE(pvar_local);
8840       if (df_limiter != NULL)
8841         BFT_FREE(df_limiter_local);
8842       BFT_FREE(grad_local);
8843       BFT_FREE(viscce_local);
8844       BFT_FREE(weighb_local);
8845     }
8846 
8847   }
8848 
8849   /* Free memory */
8850   BFT_FREE(grad);
8851   BFT_FREE(w2);
8852 }
8853 
8854 /*-----------------------------------------------------------------------------*/
8855 /*!
8856  * \brief Add explicit part of the terms of diffusion by a left-multiplying
8857  * symmetric tensorial diffusivity for a transport equation of a vector field
8858  * \f$ \vect{\varia} \f$.
8859  *
8860  * More precisely, the right hand side \f$ \vect{Rhs} \f$ is updated as
8861  * follows:
8862  * \f[
8863  * \vect{Rhs} = \vect{Rhs} - \sum_{\fij \in \Facei{\celli}}      \left(
8864  *      - \gradt_\fij \vect{\varia} \tens{\mu}_\fij  \cdot \vect{S}_\ij  \right)
8865  * \f]
8866  *
8867  * Remark:
8868  * if ivisep = 1, then we also take \f$ \mu \transpose{\gradt\vect{\varia}}
8869  * + \lambda \trace{\gradt\vect{\varia}} \f$, where \f$ \lambda \f$ is
8870  * the secondary viscosity, i.e. usually \f$ -\frac{2}{3} \mu \f$.
8871  *
8872  * Warning:
8873  * - \f$ \vect{Rhs} \f$ has already been initialized before calling the present
8874  *   function
8875  * - mind the sign minus
8876  *
8877  * \param[in]     idtvar        indicator of the temporal scheme
8878  * \param[in]     f_id          index of the current variable
8879  * \param[in]     var_cal_opt   variable calculation options
8880  * \param[in]     inc           indicator
8881  *                               - 0 when solving an increment
8882  *                               - 1 otherwise
8883  * \param[in]     ivisep        indicator to take \f$ \divv
8884  *                               \left(\mu \gradt \transpose{\vect{a}} \right)
8885  *                               -2/3 \grad\left( \mu \dive \vect{a} \right)\f$
8886  *                               - 1 take into account,
8887  * \param[in]     pvar          solved variable (current time step)
8888  * \param[in]     pvara         solved variable (previous time step)
8889  * \param[in]     coefav        boundary condition array for the variable
8890  *                               (explicit part)
8891  * \param[in]     coefbv        boundary condition array for the variable
8892  *                               (implicit part)
8893  * \param[in]     cofafv        boundary condition array for the diffusion
8894  *                               of the variable (explicit part)
8895  * \param[in]     cofbfv        boundary condition array for the diffusion
8896  *                               of the variable (implicit part)
8897  * \param[in]     i_visc        \f$ \tens{\mu}_\fij \dfrac{S_\fij}{\ipf\jpf} \f$
8898  *                               at interior faces for the r.h.s.
8899  * \param[in]     b_visc        \f$ \dfrac{S_\fib}{\ipf \centf} \f$
8900  *                               at border faces for the r.h.s.
8901  * \param[in]     i_secvis      secondary viscosity at interior faces
8902  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
8903  */
8904 /*----------------------------------------------------------------------------*/
8905 
8906 void
cs_anisotropic_left_diffusion_vector(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int inc,int ivisep,cs_real_3_t * restrict pvar,const cs_real_3_t * restrict pvara,const cs_real_3_t coefav[],const cs_real_33_t coefbv[],const cs_real_3_t cofafv[],const cs_real_33_t cofbfv[],const cs_real_33_t i_visc[],const cs_real_t b_visc[],const cs_real_t i_secvis[],cs_real_3_t * restrict rhs)8907 cs_anisotropic_left_diffusion_vector(int                         idtvar,
8908                                      int                         f_id,
8909                                      const cs_var_cal_opt_t      var_cal_opt,
8910                                      int                         inc,
8911                                      int                         ivisep,
8912                                      cs_real_3_t       *restrict pvar,
8913                                      const cs_real_3_t *restrict pvara,
8914                                      const cs_real_3_t           coefav[],
8915                                      const cs_real_33_t          coefbv[],
8916                                      const cs_real_3_t           cofafv[],
8917                                      const cs_real_33_t          cofbfv[],
8918                                      const cs_real_33_t          i_visc[],
8919                                      const cs_real_t             b_visc[],
8920                                      const cs_real_t             i_secvis[],
8921                                      cs_real_3_t       *restrict rhs)
8922 {
8923   const int nswrgp = var_cal_opt.nswrgr;
8924   const int idiffp = var_cal_opt.idiff;
8925   const int imrgra = var_cal_opt.imrgra;
8926   const int imligp = var_cal_opt.imligr;
8927   const int ircflp = var_cal_opt.ircflu;
8928   const int iwarnp = var_cal_opt.verbosity;
8929   const int icoupl = var_cal_opt.icoupl;
8930   const double epsrgp = var_cal_opt.epsrgr;
8931   const double climgp = var_cal_opt.climgr;
8932   const double relaxp = var_cal_opt.relaxv;
8933   const double thetap = var_cal_opt.thetav;
8934 
8935   const cs_mesh_t  *m = cs_glob_mesh;
8936   const cs_halo_t  *halo = m->halo;
8937   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
8938 
8939   const cs_lnum_t n_cells = m->n_cells;
8940   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
8941   const int n_i_groups = m->i_face_numbering->n_groups;
8942   const int n_i_threads = m->i_face_numbering->n_threads;
8943   const int n_b_groups = m->b_face_numbering->n_groups;
8944   const int n_b_threads = m->b_face_numbering->n_threads;
8945   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
8946   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
8947 
8948   const cs_lnum_2_t *restrict i_face_cells
8949     = (const cs_lnum_2_t *restrict)m->i_face_cells;
8950   const cs_lnum_t *restrict b_face_cells
8951     = (const cs_lnum_t *restrict)m->b_face_cells;
8952   const cs_real_t *restrict weight = fvq->weight;
8953   const cs_real_3_t *restrict i_f_face_normal
8954     = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
8955   const cs_real_3_t *restrict i_face_normal
8956     = (const cs_real_3_t *restrict)fvq->i_face_normal;
8957   const cs_real_t *restrict i_dist = fvq->i_dist;
8958   const cs_real_3_t *restrict diipf
8959     = (const cs_real_3_t *restrict)fvq->diipf;
8960   const cs_real_3_t *restrict djjpf
8961     = (const cs_real_3_t *restrict)fvq->djjpf;
8962   const cs_real_3_t *restrict diipb
8963     = (const cs_real_3_t *restrict)fvq->diipb;
8964 
8965   const int *bc_type = cs_glob_bc_type;
8966 
8967   /* Internal coupling variables */
8968   const cs_lnum_t *faces_local = NULL, *faces_distant = NULL;
8969   cs_lnum_t n_local = 0, n_distant = 0;
8970   int coupling_id = -1;
8971   cs_internal_coupling_t *cpl = NULL;
8972 
8973   /* Local variables */
8974 
8975   cs_real_t *df_limiter = NULL;
8976 
8977   char var_name[64];
8978 
8979   cs_real_33_t *gradv;
8980   cs_real_t *bndcel;
8981 
8982   cs_field_t *f = NULL;
8983 
8984   /* 1. Initialization */
8985 
8986   /* Allocate work arrays */
8987   BFT_MALLOC(gradv, n_cells_ext, cs_real_33_t);
8988 
8989   /* Choose gradient type */
8990 
8991   cs_halo_type_t halo_type = CS_HALO_STANDARD;
8992   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8993 
8994   cs_gradient_type_by_imrgra(imrgra,
8995                              &gradient_type,
8996                              &halo_type);
8997 
8998   /* Handle cases where only the previous values (already synchronized)
8999      or current values are provided */
9000 
9001   if (pvar != NULL && halo != NULL) {
9002     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)pvar, 3);
9003     if (cs_glob_mesh->n_init_perio > 0)
9004       cs_halo_perio_sync_var_vect(halo, halo_type, (cs_real_t *)pvar, 3);
9005   }
9006   if (pvara == NULL)
9007     pvara = (const cs_real_3_t *restrict)pvar;
9008 
9009   const cs_real_3_t  *restrict _pvar
9010     = (pvar != NULL) ? (const cs_real_3_t  *restrict)pvar : pvara;
9011 
9012   /* logging info */
9013 
9014   if (f_id != -1) {
9015     f = cs_field_by_id(f_id);
9016 
9017     int df_limiter_id =
9018       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
9019     if (df_limiter_id > -1)
9020       df_limiter = cs_field_by_id(df_limiter_id)->val;
9021 
9022     snprintf(var_name, 63, "%s", f->name);
9023   }
9024   else
9025     strncpy(var_name, "[anisotropic left diffusion, vector]", 63);
9026   var_name[63] = '\0';
9027 
9028   if (icoupl > 0) {
9029     assert(f_id != -1);
9030     const int coupling_key_id = cs_field_key_id("coupling_entity");
9031     coupling_id = cs_field_get_key_int(f, coupling_key_id);
9032     cpl = cs_internal_coupling_by_id(coupling_id);
9033     cs_internal_coupling_coupled_faces(cpl,
9034                                        &n_local,
9035                                        &faces_local,
9036                                        &n_distant,
9037                                        &faces_distant);
9038   }
9039 
9040 
9041   /* 2. Compute the diffusive part with reconstruction technics */
9042 
9043   /* Compute the gradient of the current variable if needed */
9044 
9045   if (ircflp == 1 || ivisep == 1) {
9046 
9047     cs_gradient_vector_synced_input(var_name,
9048                                     gradient_type,
9049                                     halo_type,
9050                                     inc,
9051                                     nswrgp,
9052                                     iwarnp,
9053                                     imligp,
9054                                     epsrgp,
9055                                     climgp,
9056                                     coefav,
9057                                     coefbv,
9058                                     _pvar,
9059                                     NULL, /* weighted gradient */
9060                                     cpl,
9061                                     gradv);
9062 
9063   } else {
9064 #   pragma omp parallel for
9065     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
9066       for (int isou = 0; isou < 3; isou++) {
9067         for (int jsou = 0; jsou < 3; jsou++)
9068           gradv[cell_id][isou][jsou] = 0.;
9069       }
9070     }
9071   }
9072 
9073   /* ======================================================================
9074      ---> Contribution from interior faces
9075      ======================================================================*/
9076 
9077   if (n_cells_ext > n_cells) {
9078 #   pragma omp parallel for if(n_cells_ext -n_cells > CS_THR_MIN)
9079     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
9080       for (int isou = 0; isou < 3; isou++) {
9081         rhs[cell_id][isou] = 0.;
9082       }
9083     }
9084   }
9085 
9086   /* Steady */
9087   if (idtvar < 0) {
9088 
9089     for (int g_id = 0; g_id < n_i_groups; g_id++) {
9090 #     pragma omp parallel for
9091       for (int t_id = 0; t_id < n_i_threads; t_id++) {
9092         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
9093              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
9094              face_id++) {
9095 
9096           cs_lnum_t ii = i_face_cells[face_id][0];
9097           cs_lnum_t jj = i_face_cells[face_id][1];
9098 
9099           cs_real_t pip[3], pjp[3], pipr[3], pjpr[3];
9100 
9101           cs_real_t bldfrp = (cs_real_t) ircflp;
9102           /* Local limitation of the reconstruction */
9103           if (df_limiter != NULL && ircflp > 0)
9104             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
9105 
9106           /*-----------------
9107             X-Y-Z components, p = u, v, w */
9108           for (int isou = 0; isou < 3; isou++) {
9109 
9110             cs_real_t dpvf[3];
9111 
9112             for (int jsou = 0; jsou < 3; jsou++) {
9113               dpvf[jsou] = 0.5*(gradv[ii][isou][jsou] + gradv[jj][isou][jsou]);
9114             }
9115 
9116             cs_real_t pi  = _pvar[ii][isou];
9117             cs_real_t pj  = _pvar[jj][isou];
9118 
9119             cs_real_t pia = pvara[ii][isou];
9120             cs_real_t pja = pvara[jj][isou];
9121 
9122             /* reconstruction only if IRCFLP = 1 */
9123             pip[isou] = pi + bldfrp * (cs_math_3_dot_product(dpvf, diipf[face_id]));
9124             pjp[isou] = pj + bldfrp * (cs_math_3_dot_product(dpvf, djjpf[face_id]));
9125 
9126             pipr[isou] = pi /relaxp - (1.-relaxp)/relaxp * pia
9127                          + bldfrp * (cs_math_3_dot_product(dpvf, diipf[face_id]));
9128             pjpr[isou] = pj /relaxp - (1.-relaxp)/relaxp * pja
9129                          + bldfrp * (cs_math_3_dot_product(dpvf, djjpf[face_id]));
9130 
9131           }
9132 
9133           for (int isou = 0; isou < 3; isou++) {
9134 
9135             cs_real_t fluxi =   i_visc[face_id][0][isou]*(pipr[0] - pjp[0])
9136                               + i_visc[face_id][1][isou]*(pipr[1] - pjp[1])
9137                               + i_visc[face_id][2][isou]*(pipr[2] - pjp[2]);
9138             cs_real_t fluxj =   i_visc[face_id][0][isou]*(pip[0] - pjpr[0])
9139                               + i_visc[face_id][1][isou]*(pip[1] - pjpr[1])
9140                               + i_visc[face_id][2][isou]*(pip[2] - pjpr[2]);
9141 
9142             rhs[ii][isou] = rhs[ii][isou] - fluxi;
9143             rhs[jj][isou] = rhs[jj][isou] + fluxj;
9144 
9145           }
9146 
9147         }
9148       }
9149     }
9150 
9151     /* Unsteady */
9152   } else {
9153 
9154     for (int g_id = 0; g_id < n_i_groups; g_id++) {
9155 #     pragma omp parallel for
9156       for (int t_id = 0; t_id < n_i_threads; t_id++) {
9157         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
9158              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
9159              face_id++) {
9160 
9161           cs_lnum_t ii = i_face_cells[face_id][0];
9162           cs_lnum_t jj = i_face_cells[face_id][1];
9163 
9164           cs_real_t pip[3], pjp[3];
9165 
9166           cs_real_t bldfrp = (cs_real_t) ircflp;
9167           /* Local limitation of the reconstruction */
9168           if (df_limiter != NULL && ircflp > 0)
9169             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
9170 
9171           /*-----------------
9172             X-Y-Z components, p = u, v, w */
9173           for (int isou = 0; isou < 3; isou++) {
9174 
9175             cs_real_t dpvf[3];
9176 
9177             for (int jsou = 0; jsou < 3; jsou++) {
9178               dpvf[jsou] = 0.5*(gradv[ii][isou][jsou] + gradv[jj][isou][jsou]);
9179             }
9180 
9181             cs_real_t pi = _pvar[ii][isou];
9182             cs_real_t pj = _pvar[jj][isou];
9183 
9184             pip[isou] = pi + bldfrp * (cs_math_3_dot_product(dpvf, diipf[face_id]));
9185             pjp[isou] = pj + bldfrp * (cs_math_3_dot_product(dpvf, djjpf[face_id]));
9186 
9187           }
9188 
9189           for (int isou = 0; isou < 3; isou++) {
9190 
9191             cs_real_t flux =   i_visc[face_id][0][isou]*(pip[0] - pjp[0])
9192                              + i_visc[face_id][1][isou]*(pip[1] - pjp[1])
9193                              + i_visc[face_id][2][isou]*(pip[2] - pjp[2]);
9194 
9195             rhs[ii][isou] -= thetap*flux;
9196             rhs[jj][isou] += thetap*flux;
9197 
9198           }
9199 
9200         }
9201       }
9202     }
9203 
9204   }
9205 
9206   /* ======================================================================
9207      ---> Contribution from boundary faces
9208      ======================================================================*/
9209 
9210   /* Steady */
9211   if (idtvar < 0) {
9212 
9213     for (int g_id = 0; g_id < n_b_groups; g_id++) {
9214 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
9215       for (int t_id = 0; t_id < n_b_threads; t_id++) {
9216         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
9217              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
9218              face_id++) {
9219 
9220           cs_lnum_t cell_id = b_face_cells[face_id];
9221 
9222           cs_real_t bldfrp = (cs_real_t) ircflp;
9223           /* Local limitation of the reconstruction */
9224           if (df_limiter != NULL && ircflp > 0)
9225             bldfrp = CS_MAX(df_limiter[cell_id], 0.);
9226 
9227           const cs_real_t *diipbv = diipb[face_id];
9228           cs_real_t pipr[3];
9229 
9230           for (int k = 0; k < 3; k++) {
9231             cs_real_t pir  =   _pvar[cell_id][k]/relaxp
9232                              - (1.-relaxp)/relaxp*pvara[cell_id][k];
9233 
9234             pipr[k] = pir +bldfrp*(  gradv[cell_id][k][0]*diipbv[0]
9235                                    + gradv[cell_id][k][1]*diipbv[1]
9236                                    + gradv[cell_id][k][2]*diipbv[2]);
9237 
9238           }
9239 
9240           /*-----------------
9241             X-Y-Z components, p = u, v, w */
9242           for (int i = 0; i < 3; i++) {
9243 
9244             cs_real_t pfacd = inc*cofafv[face_id][i];
9245 
9246             /*coefu and cofuf and b_visc are matrices */
9247             for (int j = 0; j < 3; j++) {
9248 
9249               pfacd += cofbfv[face_id][i][j]*pipr[j];
9250             }
9251 
9252             rhs[cell_id][i] -= b_visc[face_id] * pfacd;
9253 
9254           } /* i */
9255 
9256         }
9257       }
9258     }
9259 
9260     /* Unsteady */
9261   } else {
9262 
9263     for (int g_id = 0; g_id < n_b_groups; g_id++) {
9264 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
9265       for (int t_id = 0; t_id < n_b_threads; t_id++) {
9266         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
9267              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
9268              face_id++) {
9269 
9270           cs_lnum_t cell_id = b_face_cells[face_id];
9271 
9272           cs_real_t bldfrp = (cs_real_t) ircflp;
9273           /* Local limitation of the reconstruction */
9274           if (df_limiter != NULL && ircflp > 0)
9275             bldfrp = CS_MAX(df_limiter[cell_id], 0.);
9276 
9277           cs_real_t diipbv[3];
9278 
9279           for (int k = 0; k < 3; k++)
9280             diipbv[k] = diipb[face_id][k];
9281 
9282           /*-----------------
9283             X-Y-Z components, p = u, v, w */
9284           for (int i = 0; i < 3; i++) {
9285 
9286             cs_real_t pfacd = inc*cofafv[face_id][i];
9287 
9288             /*coefu and cofuf are matrices */
9289             for (int j = 0; j < 3; j++) {
9290               cs_real_t pir =   _pvar[cell_id][j]
9291                               + bldfrp*(  gradv[cell_id][j][0]*diipbv[0]
9292                                         + gradv[cell_id][j][1]*diipbv[1]
9293                                         + gradv[cell_id][j][2]*diipbv[2]);
9294               pfacd += cofbfv[face_id][j][i]*pir;
9295             }
9296 
9297             rhs[cell_id][i] -= thetap * b_visc[face_id] * pfacd;
9298 
9299           } /* i */
9300 
9301         }
9302       }
9303     }
9304 
9305   } /* idtvar */
9306 
9307   /* 3. Computation of the transpose grad(vel) term and grad(-2/3 div(vel)) */
9308 
9309   if (ivisep == 1 && idiffp == 1) {
9310 
9311     /* We do not know what condition to put in the inlets and the outlets, so we
9312        assume that there is an equilibrium. Moreover, cells containing a coupled
9313        are removed. */
9314 
9315     /* Allocate a temporary array */
9316     BFT_MALLOC(bndcel, n_cells_ext, cs_real_t);
9317 
9318 #   pragma omp parallel for
9319     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
9320       bndcel[cell_id] = 1.;
9321     }
9322 
9323 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
9324     for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id++) {
9325       int ityp = bc_type[face_id];
9326       if (   ityp == CS_OUTLET
9327           || ityp == CS_INLET
9328           || ityp == CS_FREE_INLET
9329           || ityp == CS_CONVECTIVE_INLET
9330           || ityp == CS_COUPLED_FD) {
9331         bndcel[b_face_cells[face_id]] = 0.;
9332       }
9333     }
9334 
9335     if (halo != NULL)
9336       cs_halo_sync_var(halo, halo_type, bndcel);
9337 
9338     /* ---> Interior faces */
9339 
9340     for (int g_id = 0; g_id < n_i_groups; g_id++) {
9341 #     pragma omp parallel for
9342       for (int t_id = 0; t_id < n_i_threads; t_id++) {
9343         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
9344              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
9345              face_id++) {
9346 
9347           cs_lnum_t ii = i_face_cells[face_id][0];
9348           cs_lnum_t jj = i_face_cells[face_id][1];
9349 
9350           cs_real_t pnd = weight[face_id];
9351           cs_real_t secvis = i_secvis[face_id];
9352 
9353           cs_real_t grdtrv
9354             =        pnd*(gradv[ii][0][0]+gradv[ii][1][1]+gradv[ii][2][2])
9355               + (1.-pnd)*(gradv[jj][0][0]+gradv[jj][1][1]+gradv[jj][2][2]);
9356 
9357           cs_real_3_t n, ipjp;
9358           cs_math_3_normalise(i_face_normal[face_id], n);
9359 
9360           /* I'J' */
9361           for (int i = 0; i < 3; i++)
9362             ipjp[i] = n[i] * i_dist[face_id];
9363 
9364           for (int i = 0; i < 3; i++) {
9365 
9366             cs_real_t flux = secvis*grdtrv*i_f_face_normal[face_id][i];
9367 
9368             /* We need to compute (K grad(u)^T) .I'J'
9369                which is equal to I'J' . (grad(u) . K^T)
9370                But: (I'J' . (grad(u) . K^T))_i = I'J'_k grad(u)_kj K_ij
9371             */
9372 
9373             for (int j = 0; j < 3; j++) {
9374               for (int k = 0; k < 3; k++) {
9375                 flux += ipjp[k]
9376                             *(pnd*gradv[ii][k][j]+(1-pnd)*gradv[jj][k][j])
9377                             *i_visc[face_id][i][j];
9378               }
9379             }
9380 
9381             rhs[ii][i] += flux*bndcel[ii];
9382             rhs[jj][i] -= flux*bndcel[jj];
9383 
9384           }
9385 
9386         }
9387       }
9388     }
9389 
9390     /* ---> Boundary FACES
9391        the whole flux term of the stress tensor is already taken into account
9392        (so, no corresponding term in forbr)
9393        TODO in theory we should take the normal component into account (the
9394        tangential one is modeled by the wall law) */
9395 
9396     /*Free memory */
9397     BFT_FREE(bndcel);
9398 
9399   }
9400 
9401   /* Free memory */
9402   BFT_FREE(gradv);
9403 }
9404 
9405 /*-----------------------------------------------------------------------------*/
9406 /*!
9407  * \brief Add explicit part of the terms of diffusion by a right-multiplying
9408  * symmetric tensorial diffusivity for a transport equation of a vector field
9409  * \f$ \vect{\varia} \f$.
9410  *
9411  * More precisely, the right hand side \f$ \vect{Rhs} \f$ is updated as
9412  * follows:
9413  * \f[
9414  * \vect{Rhs} = \vect{Rhs} - \sum_{\fij \in \Facei{\celli}}      \left(
9415  *      - \gradt_\fij \vect{\varia} \tens{\mu}_\fij  \cdot \vect{S}_\ij  \right)
9416  * \f]
9417  *
9418  * Warning:
9419  * - \f$ \vect{Rhs} \f$ has already been initialized before calling the present
9420  *   function
9421  * - mind the sign minus
9422  *
9423  * \param[in]     idtvar        indicator of the temporal scheme
9424  * \param[in]     f_id          index of the current variable
9425  * \param[in]     var_cal_opt   variable calculation options
9426  * \param[in]     inc           indicator
9427  *                               - 0 when solving an increment
9428  *                               - 1 otherwise
9429  * \param[in]     pvar          solved variable (current time step)
9430  * \param[in]     pvara         solved variable (previous time step)
9431  * \param[in]     coefav        boundary condition array for the variable
9432  *                               (explicit part)
9433  * \param[in]     coefbv        boundary condition array for the variable
9434  *                               (implicit part)
9435  * \param[in]     cofafv        boundary condition array for the diffusion
9436  *                               of the variable (explicit part)
9437  * \param[in]     cofbfv        boundary condition array for the diffusion
9438  *                               of the variable (implicit part)
9439  * \param[in]     i_visc        \f$ \tens{\mu}_\fij \dfrac{S_\fij}{\ipf\jpf} \f$
9440  *                               at interior faces for the r.h.s.
9441  * \param[in]     b_visc        \f$ \dfrac{S_\fib}{\ipf \centf} \f$
9442  *                               at border faces for the r.h.s.
9443  * \param[in]     viscel        symmetric cell tensor \f$ \tens{\mu}_\celli \f$
9444  * \param[in]     weighf        internal face weight between cells i j in case
9445  *                               of tensor diffusion
9446  * \param[in]     weighb        boundary face weight for cells i in case
9447  *                               of tensor diffusion
9448  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
9449  */
9450 /*----------------------------------------------------------------------------*/
9451 
9452 void
cs_anisotropic_right_diffusion_vector(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int inc,cs_real_3_t * restrict pvar,const cs_real_3_t * restrict pvara,const cs_real_3_t coefav[],const cs_real_33_t coefbv[],const cs_real_3_t cofafv[],const cs_real_33_t cofbfv[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict viscel,const cs_real_2_t weighf[],const cs_real_t weighb[],cs_real_3_t * restrict rhs)9453 cs_anisotropic_right_diffusion_vector(int                         idtvar,
9454                                       int                         f_id,
9455                                       const cs_var_cal_opt_t      var_cal_opt,
9456                                       int                         inc,
9457                                       cs_real_3_t       *restrict pvar,
9458                                       const cs_real_3_t *restrict pvara,
9459                                       const cs_real_3_t           coefav[],
9460                                       const cs_real_33_t          coefbv[],
9461                                       const cs_real_3_t           cofafv[],
9462                                       const cs_real_33_t          cofbfv[],
9463                                       const cs_real_t             i_visc[],
9464                                       const cs_real_t             b_visc[],
9465                                       cs_real_6_t     *restrict   viscel,
9466                                       const cs_real_2_t           weighf[],
9467                                       const cs_real_t             weighb[],
9468                                       cs_real_3_t       *restrict rhs)
9469 {
9470   const int nswrgp = var_cal_opt.nswrgr;
9471   const int imrgra = var_cal_opt.imrgra;
9472   const int imligp = var_cal_opt.imligr;
9473   const int ircflp = var_cal_opt.ircflu;
9474   const int iwarnp = var_cal_opt.verbosity;
9475   const int icoupl = var_cal_opt.icoupl;
9476   const double epsrgp = var_cal_opt.epsrgr;
9477   const double climgp = var_cal_opt.climgr;
9478   const double relaxp = var_cal_opt.relaxv;
9479   const double thetap = var_cal_opt.thetav;
9480 
9481   const cs_mesh_t  *m = cs_glob_mesh;
9482   const cs_halo_t  *halo = m->halo;
9483   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
9484 
9485   const cs_lnum_t n_cells = m->n_cells;
9486   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
9487   const int n_i_groups = m->i_face_numbering->n_groups;
9488   const int n_i_threads = m->i_face_numbering->n_threads;
9489   const int n_b_groups = m->b_face_numbering->n_groups;
9490   const int n_b_threads = m->b_face_numbering->n_threads;
9491   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
9492   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
9493 
9494   const cs_lnum_2_t *restrict i_face_cells
9495     = (const cs_lnum_2_t *restrict)m->i_face_cells;
9496   const cs_lnum_t *restrict b_face_cells
9497     = (const cs_lnum_t *restrict)m->b_face_cells;
9498   const cs_real_3_t *restrict cell_cen
9499     = (const cs_real_3_t *restrict)fvq->cell_cen;
9500   const cs_real_3_t *restrict i_face_normal
9501     = (const cs_real_3_t *restrict)fvq->i_face_normal;
9502   const cs_real_3_t *restrict b_face_normal
9503     = (const cs_real_3_t *restrict)fvq->b_face_normal;
9504   const cs_real_3_t *restrict i_face_cog
9505     = (const cs_real_3_t *restrict)fvq->i_face_cog;
9506   const cs_real_3_t *restrict b_face_cog
9507     = (const cs_real_3_t *restrict)fvq->b_face_cog;
9508 
9509   /* Internal coupling variables */
9510   cs_real_3_t *pvar_local = NULL;
9511   cs_real_33_t *grad_local = NULL;
9512   cs_real_t *df_limiter_local = NULL;
9513   cs_real_6_t *viscce_local = NULL;
9514   cs_real_t *weighb_local = NULL;
9515   const cs_lnum_t *faces_local = NULL, *faces_distant = NULL;
9516   cs_lnum_t n_local = 0, n_distant = 0;
9517   int coupling_id = -1;
9518   cs_internal_coupling_t *cpl = NULL;
9519 
9520   /* Local variables */
9521 
9522   cs_real_t *df_limiter = NULL;
9523 
9524   char var_name[64];
9525 
9526   cs_real_6_t *viscce;
9527   cs_real_33_t *grad;
9528 
9529   cs_field_t *f = NULL;
9530 
9531   /* 1. Initialization */
9532 
9533   viscce = NULL;
9534 
9535   /* Allocate work arrays */
9536   BFT_MALLOC(grad, n_cells_ext, cs_real_33_t);
9537 
9538   /* Choose gradient type */
9539 
9540   cs_halo_type_t halo_type = CS_HALO_STANDARD;
9541   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
9542 
9543   cs_gradient_type_by_imrgra(imrgra,
9544                              &gradient_type,
9545                              &halo_type);
9546 
9547   /* Handle cases where only the previous values (already synchronized)
9548      or current values are provided */
9549 
9550   if (pvar != NULL && halo != NULL) {
9551     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)pvar, 3);
9552     if (cs_glob_mesh->n_init_perio > 0)
9553       cs_halo_perio_sync_var_vect(halo, halo_type, (cs_real_t *)pvar, 3);
9554   }
9555   if (pvara == NULL)
9556     pvara = (const cs_real_3_t *restrict)pvar;
9557 
9558   const cs_real_3_t  *restrict _pvar
9559     = (pvar != NULL) ? (const cs_real_3_t  *restrict)pvar : pvara;
9560 
9561   /* logging info */
9562 
9563   if (f_id != -1) {
9564     f = cs_field_by_id(f_id);
9565 
9566     int df_limiter_id =
9567       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
9568     if (df_limiter_id > -1)
9569       df_limiter = cs_field_by_id(df_limiter_id)->val;
9570 
9571     snprintf(var_name, 63, "%s", f->name);
9572   }
9573   else
9574     strncpy(var_name, "[anisotropic right diffusion, vector]", 63);
9575   var_name[63] = '\0';
9576 
9577   viscce = viscel;
9578 
9579   if (icoupl > 0) {
9580     assert(f_id != -1);
9581     const int coupling_key_id = cs_field_key_id("coupling_entity");
9582     coupling_id = cs_field_get_key_int(f, coupling_key_id);
9583     cpl = cs_internal_coupling_by_id(coupling_id);
9584     cs_internal_coupling_coupled_faces(cpl,
9585                                        &n_local,
9586                                        &faces_local,
9587                                        &n_distant,
9588                                        &faces_distant);
9589   }
9590 
9591   /* 2. Compute the diffusive part with reconstruction technics */
9592 
9593   /* Compute the gradient of the current variable if needed */
9594 
9595   if (ircflp == 1) {
9596 
9597     cs_gradient_vector_synced_input(var_name,
9598                                     gradient_type,
9599                                     halo_type,
9600                                     inc,
9601                                     nswrgp,
9602                                     iwarnp,
9603                                     imligp,
9604                                     epsrgp,
9605                                     climgp,
9606                                     coefav,
9607                                     coefbv,
9608                                     _pvar,
9609                                     NULL, /* weighted gradient */
9610                                     cpl,
9611                                     grad);
9612 
9613   } else {
9614 #   pragma omp parallel for
9615     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
9616       for (int isou = 0; isou < 3; isou++) {
9617         for (int jsou = 0; jsou < 3; jsou++)
9618           grad[cell_id][isou][jsou] = 0.;
9619       }
9620     }
9621   }
9622 
9623   /* ======================================================================
9624      ---> Contribution from interior faces
9625      ======================================================================*/
9626 
9627   if (n_cells_ext > n_cells) {
9628 #   pragma omp parallel for if(n_cells_ext -n_cells > CS_THR_MIN)
9629     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
9630       for (int isou = 0; isou < 3; isou++) {
9631         rhs[cell_id][isou] = 0.;
9632       }
9633     }
9634   }
9635 
9636   /* Steady */
9637   if (idtvar < 0) {
9638 
9639     for (int g_id = 0; g_id < n_i_groups; g_id++) {
9640 #     pragma omp parallel for
9641       for (int t_id = 0; t_id < n_i_threads; t_id++) {
9642         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
9643              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
9644              face_id++) {
9645 
9646           cs_lnum_t ii = i_face_cells[face_id][0];
9647           cs_lnum_t jj = i_face_cells[face_id][1];
9648 
9649           cs_real_t visci[3][3], viscj[3][3];
9650           cs_real_t diippf[3], djjppf[3], pipp[3], pjpp[3];
9651           cs_real_t  pir[3], pjr[3], pippr[3], pjppr[3];
9652           cs_real_t  pi[3], pj[3], pia[3], pja[3];
9653 
9654           for (int isou = 0; isou < 3; isou++) {
9655             pi[isou] = _pvar[ii][isou];
9656             pj[isou] = _pvar[jj][isou];
9657             pia[isou] = pvara[ii][isou];
9658             pja[isou] = pvara[jj][isou];
9659           }
9660 
9661           cs_real_t bldfrp = (cs_real_t) ircflp;
9662           /* Local limitation of the reconstruction */
9663           if (df_limiter != NULL && ircflp > 0)
9664             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
9665 
9666           /* Recompute II' and JJ' at this level */
9667 
9668           visci[0][0] = viscce[ii][0];
9669           visci[1][1] = viscce[ii][1];
9670           visci[2][2] = viscce[ii][2];
9671           visci[1][0] = viscce[ii][3];
9672           visci[0][1] = viscce[ii][3];
9673           visci[2][1] = viscce[ii][4];
9674           visci[1][2] = viscce[ii][4];
9675           visci[2][0] = viscce[ii][5];
9676           visci[0][2] = viscce[ii][5];
9677 
9678           /* IF.Ki.S / ||Ki.S||^2 */
9679           cs_real_t fikdvi = weighf[face_id][0];
9680 
9681           /* II" = IF + FI" */
9682           for (int i = 0; i < 3; i++) {
9683             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
9684                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
9685                                + visci[1][i]*i_face_normal[face_id][1]
9686                                + visci[2][i]*i_face_normal[face_id][2] );
9687           }
9688 
9689           viscj[0][0] = viscce[jj][0];
9690           viscj[1][1] = viscce[jj][1];
9691           viscj[2][2] = viscce[jj][2];
9692           viscj[1][0] = viscce[jj][3];
9693           viscj[0][1] = viscce[jj][3];
9694           viscj[2][1] = viscce[jj][4];
9695           viscj[1][2] = viscce[jj][4];
9696           viscj[2][0] = viscce[jj][5];
9697           viscj[0][2] = viscce[jj][5];
9698 
9699           /* FJ.Kj.S / ||Kj.S||^2 */
9700           cs_real_t fjkdvi = weighf[face_id][1];
9701 
9702           /* JJ" = JF + FJ" */
9703           for (int i = 0; i < 3; i++) {
9704             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
9705                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
9706                                + viscj[1][i]*i_face_normal[face_id][1]
9707                                + viscj[2][i]*i_face_normal[face_id][2] );
9708           }
9709 
9710           for (int isou = 0; isou < 3; isou++) {
9711             /* p in I" and J" */
9712             pipp[isou] = pi[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
9713                                            + grad[ii][isou][1]*diippf[1]
9714                                            + grad[ii][isou][2]*diippf[2]);
9715             pjpp[isou] = pj[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
9716                                            + grad[jj][isou][1]*djjppf[1]
9717                                            + grad[jj][isou][2]*djjppf[2]);
9718 
9719             pir[isou] = pi[isou]/relaxp - (1.-relaxp)/relaxp * pia[isou];
9720             pjr[isou] = pj[isou]/relaxp - (1.-relaxp)/relaxp * pja[isou];
9721 
9722 
9723             /* pr in I" and J" */
9724             pippr[isou] = pir[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
9725                                              + grad[ii][isou][1]*diippf[1]
9726                                              + grad[ii][isou][2]*diippf[2]);
9727             pjppr[isou] = pjr[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
9728                                              + grad[jj][isou][1]*djjppf[1]
9729                                              + grad[jj][isou][2]*djjppf[2]);
9730 
9731             cs_real_t fluxi = i_visc[face_id]*(pippr[isou] - pjpp[isou]);
9732             cs_real_t fluxj = i_visc[face_id]*(pipp[isou] - pjppr[isou]);
9733 
9734             rhs[ii][isou] -= fluxi;
9735             rhs[jj][isou] += fluxj;
9736           }
9737         }
9738       }
9739     }
9740 
9741     /* Unsteady */
9742   } else {
9743 
9744     for (int g_id = 0; g_id < n_i_groups; g_id++) {
9745 #     pragma omp parallel for
9746       for (int t_id = 0; t_id < n_i_threads; t_id++) {
9747         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
9748              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
9749              face_id++) {
9750 
9751           cs_lnum_t ii = i_face_cells[face_id][0];
9752           cs_lnum_t jj = i_face_cells[face_id][1];
9753 
9754           cs_real_t visci[3][3], viscj[3][3];
9755           cs_real_t diippf[3], djjppf[3], pipp[3], pjpp[3];
9756           cs_real_t pi[3], pj[3];
9757 
9758           for (int isou = 0; isou < 3; isou++) {
9759             pi[isou] = _pvar[ii][isou];
9760             pj[isou] = _pvar[jj][isou];
9761           }
9762 
9763           cs_real_t bldfrp = (cs_real_t) ircflp;
9764           /* Local limitation of the reconstruction */
9765           if (df_limiter != NULL && ircflp > 0)
9766             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
9767 
9768           /* Recompute II' and JJ' at this level */
9769 
9770           visci[0][0] = viscce[ii][0];
9771           visci[1][1] = viscce[ii][1];
9772           visci[2][2] = viscce[ii][2];
9773           visci[1][0] = viscce[ii][3];
9774           visci[0][1] = viscce[ii][3];
9775           visci[2][1] = viscce[ii][4];
9776           visci[1][2] = viscce[ii][4];
9777           visci[2][0] = viscce[ii][5];
9778           visci[0][2] = viscce[ii][5];
9779 
9780           /* IF.Ki.S / ||Ki.S||^2 */
9781           cs_real_t fikdvi = weighf[face_id][0];
9782 
9783           /* II" = IF + FI" */
9784           for (int i = 0; i < 3; i++) {
9785             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
9786                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
9787                                + visci[1][i]*i_face_normal[face_id][1]
9788                                + visci[2][i]*i_face_normal[face_id][2] );
9789           }
9790 
9791           viscj[0][0] = viscce[jj][0];
9792           viscj[1][1] = viscce[jj][1];
9793           viscj[2][2] = viscce[jj][2];
9794           viscj[1][0] = viscce[jj][3];
9795           viscj[0][1] = viscce[jj][3];
9796           viscj[2][1] = viscce[jj][4];
9797           viscj[1][2] = viscce[jj][4];
9798           viscj[2][0] = viscce[jj][5];
9799           viscj[0][2] = viscce[jj][5];
9800 
9801           /* FJ.Kj.S / ||Kj.S||^2 */
9802           cs_real_t fjkdvi = weighf[face_id][1];
9803 
9804           /* JJ" = JF + FJ" */
9805           for (int i = 0; i < 3; i++) {
9806             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
9807                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
9808                                + viscj[1][i]*i_face_normal[face_id][1]
9809                                + viscj[2][i]*i_face_normal[face_id][2] );
9810           }
9811 
9812           for (int isou = 0; isou < 3; isou++) {
9813             /* p in I" and J" */
9814             pipp[isou] = pi[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
9815                                            + grad[ii][isou][1]*diippf[1]
9816                                            + grad[ii][isou][2]*diippf[2]);
9817             pjpp[isou] = pj[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
9818                                            + grad[jj][isou][1]*djjppf[1]
9819                                            + grad[jj][isou][2]*djjppf[2]);
9820 
9821             cs_real_t flux = i_visc[face_id]*(pipp[isou] -pjpp[isou]);
9822 
9823             rhs[ii][isou] -= thetap*flux;
9824             rhs[jj][isou] += thetap*flux;
9825 
9826           }
9827 
9828         }
9829       }
9830     }
9831 
9832   }
9833 
9834   /* ======================================================================
9835      ---> Contribution from boundary faces
9836      ======================================================================*/
9837 
9838   /* Steady */
9839   if (idtvar < 0) {
9840 
9841     for (int g_id = 0; g_id < n_b_groups; g_id++) {
9842 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
9843       for (int t_id = 0; t_id < n_b_threads; t_id++) {
9844         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
9845              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
9846              face_id++) {
9847 
9848           cs_lnum_t ii = b_face_cells[face_id];
9849 
9850           cs_real_t pi[3], pia[3], pir[3], pippr[3];
9851           cs_real_t visci[3][3];
9852           cs_real_t diippf[3];
9853 
9854           for (int isou = 0; isou < 3; isou++) {
9855             pi[isou] = pvar[ii][isou];
9856             pia[isou] = pvara[ii][isou];
9857             pir[isou] = pi[isou]/relaxp - (1.-relaxp)/relaxp*pia[isou];
9858           }
9859 
9860           cs_real_t bldfrp = (cs_real_t) ircflp;
9861           /* Local limitation of the reconstruction */
9862           if (df_limiter != NULL && ircflp > 0)
9863             bldfrp = CS_MAX(df_limiter[ii], 0.);
9864 
9865           /* Recompute II"
9866              --------------*/
9867 
9868           visci[0][0] = viscce[ii][0];
9869           visci[1][1] = viscce[ii][1];
9870           visci[2][2] = viscce[ii][2];
9871           visci[1][0] = viscce[ii][3];
9872           visci[0][1] = viscce[ii][3];
9873           visci[2][1] = viscce[ii][4];
9874           visci[1][2] = viscce[ii][4];
9875           visci[2][0] = viscce[ii][5];
9876           visci[0][2] = viscce[ii][5];
9877 
9878           /* IF.Ki.S / ||Ki.S||^2 */
9879           cs_real_t fikdvi = weighb[face_id];
9880 
9881           /* II" = IF + FI" */
9882           for (int i = 0; i < 3; i++) {
9883             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
9884                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
9885                                + visci[1][i]*b_face_normal[face_id][1]
9886                                + visci[2][i]*b_face_normal[face_id][2] );
9887           }
9888           for (int isou = 0; isou < 3; isou++) {
9889             pippr[isou] = pir[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
9890                                              + grad[ii][isou][1]*diippf[1]
9891                                              + grad[ii][isou][2]*diippf[2]);
9892           }
9893           for (int isou = 0; isou < 3; isou++) {
9894             cs_real_t pfacd = inc*cofafv[face_id][isou];
9895             for (int jsou = 0; jsou < 3; jsou++) {
9896               pfacd += cofbfv[face_id][isou][jsou]*pippr[jsou];
9897             }
9898 
9899             cs_real_t flux = b_visc[face_id]*pfacd;
9900             rhs[ii][isou] -= flux;
9901 
9902           } /* isou */
9903 
9904         }
9905       }
9906     }
9907 
9908     /* Unsteady */
9909   } else {
9910 
9911     for (int g_id = 0; g_id < n_b_groups; g_id++) {
9912 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
9913       for (int t_id = 0; t_id < n_b_threads; t_id++) {
9914         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
9915              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
9916              face_id++) {
9917 
9918           cs_lnum_t ii = b_face_cells[face_id];
9919 
9920           cs_real_t visci[3][3];
9921           cs_real_t diippf[3], pi[3], pipp[3];
9922 
9923           for (int isou = 0; isou < 3; isou++) {
9924             pi[isou] = pvar[ii][isou];
9925           }
9926 
9927           cs_real_t bldfrp = (cs_real_t) ircflp;
9928           /* Local limitation of the reconstruction */
9929           if (df_limiter != NULL && ircflp > 0)
9930             bldfrp = CS_MAX(df_limiter[ii], 0.);
9931 
9932           /* Recompute II"
9933              --------------*/
9934 
9935           visci[0][0] = viscce[ii][0];
9936           visci[1][1] = viscce[ii][1];
9937           visci[2][2] = viscce[ii][2];
9938           visci[1][0] = viscce[ii][3];
9939           visci[0][1] = viscce[ii][3];
9940           visci[2][1] = viscce[ii][4];
9941           visci[1][2] = viscce[ii][4];
9942           visci[2][0] = viscce[ii][5];
9943           visci[0][2] = viscce[ii][5];
9944 
9945           /* IF.Ki.S / ||Ki.S||^2 */
9946           cs_real_t fikdvi = weighb[face_id];
9947 
9948           /* II" = IF + FI" */
9949           for (int i = 0; i < 3; i++) {
9950             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
9951                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
9952                                + visci[1][i]*b_face_normal[face_id][1]
9953                                + visci[2][i]*b_face_normal[face_id][2]);
9954           }
9955           for (int isou = 0; isou < 3; isou++) {
9956             pipp[isou] = pi[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
9957                                            + grad[ii][isou][1]*diippf[1]
9958                                            + grad[ii][isou][2]*diippf[2]);
9959           }
9960           for (int isou = 0; isou < 3; isou++) {
9961             cs_real_t pfacd = inc*cofafv[face_id][isou];
9962             for (int jsou = 0; jsou < 3; jsou++) {
9963               pfacd += cofbfv[face_id][isou][jsou]*pipp[jsou];
9964             }
9965 
9966             cs_real_t flux = b_visc[face_id]*pfacd;
9967             rhs[ii][isou] -= thetap * flux;
9968 
9969           } /* isou */
9970 
9971         }
9972       }
9973     }
9974 
9975     /* The vector is internal_coupled and an implicit contribution
9976      * is required */
9977     if (icoupl > 0) {
9978 
9979       /* Exchange pvar */
9980       BFT_MALLOC(pvar_local, n_local, cs_real_3_t);
9981       cs_internal_coupling_exchange_by_cell_id(cpl,
9982                                                3, /* Dimension */
9983                                                (const cs_real_t*)_pvar,
9984                                                (cs_real_t *)pvar_local);
9985 
9986       /* Exchange grad */
9987       BFT_MALLOC(grad_local, n_local, cs_real_33_t);
9988       cs_internal_coupling_exchange_by_cell_id(cpl,
9989                                                9, /* Dimension */
9990                                                (const cs_real_t*)grad,
9991                                                (cs_real_t *)grad_local);
9992 
9993       /* Exchange viscce */
9994       BFT_MALLOC(viscce_local, n_local, cs_real_6_t);
9995       cs_internal_coupling_exchange_by_cell_id(cpl,
9996                                                6, /* Dimension */
9997                                                (const cs_real_t*)viscce,
9998                                                (cs_real_t *)viscce_local);
9999 
10000       /* Exchange weighb */
10001       BFT_MALLOC(weighb_local, n_local, cs_real_t);
10002       cs_internal_coupling_exchange_by_face_id(cpl,
10003                                                1, /* Dimension */
10004                                                (const cs_real_t*)weighb,
10005                                                (cs_real_t *)weighb_local);
10006 
10007       /* Exchange diffusion limiter */
10008       if (df_limiter != NULL) {
10009         BFT_MALLOC(df_limiter_local, n_local, cs_real_t);
10010         cs_internal_coupling_exchange_var(cpl,
10011                                           1, /* Dimension */
10012                                           df_limiter,
10013                                           df_limiter_local);
10014       }
10015 
10016       /* Flux contribution */
10017       for (cs_lnum_t jj = 0; jj < n_local; jj++) {
10018         cs_lnum_t face_id = faces_local[jj];
10019         cs_lnum_t ii = b_face_cells[face_id];
10020 
10021         cs_real_t pipp[3], pjpp[3];
10022         cs_real_t pi[3], pj[3];
10023 
10024         for (int isou = 0; isou < 3; isou++) {
10025           pi[isou] = _pvar[ii][isou];
10026           pj[isou] = pvar_local[jj][isou];
10027         }
10028 
10029         cs_real_t bldfrp = (cs_real_t) ircflp;
10030         /* Local limitation of the reconstruction */
10031         if (df_limiter != NULL && ircflp > 0)
10032           bldfrp = CS_MAX(CS_MIN(df_limiter_local[ii], df_limiter[jj]), 0.);
10033 
10034         /* Recompute II" and JJ" */
10035         cs_real_t visci[3][3], viscj[3][3];
10036         cs_real_t diippf[3], djjppf[3];
10037 
10038         visci[0][0] = viscce[ii][0];
10039         visci[1][1] = viscce[ii][1];
10040         visci[2][2] = viscce[ii][2];
10041         visci[1][0] = viscce[ii][3];
10042         visci[0][1] = viscce[ii][3];
10043         visci[2][1] = viscce[ii][4];
10044         visci[1][2] = viscce[ii][4];
10045         visci[2][0] = viscce[ii][5];
10046         visci[0][2] = viscce[ii][5];
10047 
10048         /* IF.Ki.S / ||Ki.S||^2 */
10049         cs_real_t fikdvi = weighb[face_id];
10050 
10051         /* II" = IF + FI" */
10052         for (int i = 0; i < 3; i++) {
10053           diippf[i] = b_face_cog[face_id][i]-cell_cen[ii][i]
10054                     - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
10055                              + visci[1][i]*b_face_normal[face_id][1]
10056                              + visci[2][i]*b_face_normal[face_id][2] );
10057         }
10058 
10059         viscj[0][0] = viscce_local[jj][0];
10060         viscj[1][1] = viscce_local[jj][1];
10061         viscj[2][2] = viscce_local[jj][2];
10062         viscj[1][0] = viscce_local[jj][3];
10063         viscj[0][1] = viscce_local[jj][3];
10064         viscj[2][1] = viscce_local[jj][4];
10065         viscj[1][2] = viscce_local[jj][4];
10066         viscj[2][0] = viscce_local[jj][5];
10067         viscj[0][2] = viscce_local[jj][5];
10068 
10069         /* FJ.Kj.S / ||Kj.S||^2
10070          * weighb_local defined with vector JF and surface -S */
10071         cs_real_t fjkdvi = weighb_local[jj];
10072 
10073         /* JJ" = JF + FJ"
10074          *   */
10075         for (int i = 0; i < 3; i++) {
10076           djjppf[i] = b_face_cog[face_id][i]-cell_cen[ii][i]-cpl->ci_cj_vect[jj][i]
10077                     + fjkdvi*( viscj[0][i]*b_face_normal[face_id][0]
10078                              + viscj[1][i]*b_face_normal[face_id][1]
10079                              + viscj[2][i]*b_face_normal[face_id][2] );
10080         }
10081 
10082         for (int isou = 0; isou < 3; isou++) {
10083           /* p in I" and J" */
10084           pipp[isou] = pi[isou] + bldfrp*(  grad[ii][isou][0]*diippf[0]
10085                                           + grad[ii][isou][1]*diippf[1]
10086                                           + grad[ii][isou][2]*diippf[2]);
10087           pjpp[isou] = pj[isou] + bldfrp*(  grad_local[jj][isou][0]*djjppf[0]
10088                                           + grad_local[jj][isou][1]*djjppf[1]
10089                                           + grad_local[jj][isou][2]*djjppf[2]);
10090 
10091           /* Reproduce multiplication by i_visc[face_id] */
10092           cs_real_t flux = (pipp[isou] - pjpp[isou])
10093             / (weighb[face_id] + weighb_local[jj]);
10094 
10095           rhs[ii][isou] -= thetap*flux;
10096         }
10097 
10098       }
10099 
10100       /* Remote data no longer needed */
10101       BFT_FREE(pvar_local);
10102       if (df_limiter != NULL)
10103         BFT_FREE(df_limiter_local);
10104       BFT_FREE(grad_local);
10105       BFT_FREE(viscce_local);
10106       BFT_FREE(weighb_local);
10107 
10108     }
10109 
10110 
10111   } /* idtvar */
10112 
10113   /* Free memory */
10114   BFT_FREE(grad);
10115 }
10116 
10117 /*----------------------------------------------------------------------------*/
10118 /*!
10119  * \brief Add the explicit part of the diffusion terms with a symmetric tensor
10120  * diffusivity for a transport equation of a scalar field \f$ \varia \f$.
10121  *
10122  * More precisely, the right hand side \f$ Rhs \f$ is updated as
10123  * follows:
10124  * \f[
10125  * Rhs = Rhs - \sum_{\fij \in \Facei{\celli}}      \left(
10126  *      - \tens{\mu}_\fij \gradv_\fij \varia \cdot \vect{S}_\ij  \right)
10127  * \f]
10128  *
10129  * Warning:
10130  * - \f$ Rhs \f$ has already been initialized before
10131  *   calling cs_anisotropic_diffusion_scalar!
10132  * - mind the sign minus
10133  *
10134  * \param[in]     idtvar        indicator of the temporal scheme
10135  * \param[in]     f_id          index of the current variable
10136  * \param[in]     var_cal_opt   variable calculation options
10137  * \param[in]     inc           indicator
10138  *                               - 0 when solving an increment
10139  *                               - 1 otherwise
10140  * \param[in]     pvar          solved variable (current time step)
10141  * \param[in]     pvara         solved variable (previous time step)
10142  * \param[in]     coefa         boundary condition array for the variable
10143  *                               (explicit part)
10144  * \param[in]     coefb         boundary condition array for the variable
10145  *                               (implicit part)
10146  * \param[in]     cofaf         boundary condition array for the diffusion
10147  *                               of the variable (explicit part)
10148  * \param[in]     cofbf         boundary condition array for the diffusion
10149  *                               of the variable (implicit part)
10150  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
10151  *                               at interior faces for the r.h.s.
10152  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
10153  *                               at border faces for the r.h.s.
10154  * \param[in]     viscel        symmetric cell tensor \f$ \tens{\mu}_\celli \f$
10155  * \param[in]     weighf        internal face weight between cells i j in case
10156  *                               of tensor diffusion
10157  * \param[in]     weighb        boundary face weight for cells i in case
10158  *                               of tensor diffusion
10159  * \param[in,out] rhs           right hand side \f$ \vect{Rhs} \f$
10160  */
10161 /*----------------------------------------------------------------------------*/
10162 
10163 void
cs_anisotropic_diffusion_tensor(int idtvar,int f_id,const cs_var_cal_opt_t var_cal_opt,int inc,cs_real_6_t * restrict pvar,const cs_real_6_t * restrict pvara,const cs_real_6_t coefa[],const cs_real_66_t coefb[],const cs_real_6_t cofaf[],const cs_real_66_t cofbf[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict viscel,const cs_real_2_t weighf[],const cs_real_t weighb[],cs_real_6_t * restrict rhs)10164 cs_anisotropic_diffusion_tensor(int                         idtvar,
10165                                 int                         f_id,
10166                                 const cs_var_cal_opt_t      var_cal_opt,
10167                                 int                         inc,
10168                                 cs_real_6_t       *restrict pvar,
10169                                 const cs_real_6_t *restrict pvara,
10170                                 const cs_real_6_t           coefa[],
10171                                 const cs_real_66_t          coefb[],
10172                                 const cs_real_6_t           cofaf[],
10173                                 const cs_real_66_t          cofbf[],
10174                                 const cs_real_t             i_visc[],
10175                                 const cs_real_t             b_visc[],
10176                                 cs_real_6_t     *restrict   viscel,
10177                                 const cs_real_2_t           weighf[],
10178                                 const cs_real_t             weighb[],
10179                                 cs_real_6_t     *restrict   rhs)
10180 {
10181   const int nswrgp = var_cal_opt.nswrgr;
10182   const int imrgra = var_cal_opt.imrgra;
10183   const int imligp = var_cal_opt.imligr;
10184   const int ircflp = var_cal_opt.ircflu;
10185   const int iwarnp = var_cal_opt.verbosity;
10186   const double epsrgp = var_cal_opt.epsrgr;
10187   const double climgp = var_cal_opt.climgr;
10188   const double relaxp = var_cal_opt.relaxv;
10189   const double thetap = var_cal_opt.thetav;
10190 
10191   const cs_mesh_t  *m = cs_glob_mesh;
10192   const cs_halo_t  *halo = m->halo;
10193   cs_mesh_quantities_t  *fvq = cs_glob_mesh_quantities;
10194 
10195   const cs_lnum_t n_cells = m->n_cells;
10196   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
10197   const int n_i_groups = m->i_face_numbering->n_groups;
10198   const int n_i_threads = m->i_face_numbering->n_threads;
10199   const int n_b_groups = m->b_face_numbering->n_groups;
10200   const int n_b_threads = m->b_face_numbering->n_threads;
10201   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
10202   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
10203 
10204   const cs_lnum_2_t *restrict i_face_cells
10205     = (const cs_lnum_2_t *restrict)m->i_face_cells;
10206   const cs_lnum_t *restrict b_face_cells
10207     = (const cs_lnum_t *restrict)m->b_face_cells;
10208   const cs_real_3_t *restrict cell_cen
10209     = (const cs_real_3_t *restrict)fvq->cell_cen;
10210   const cs_real_3_t *restrict i_face_normal
10211     = (const cs_real_3_t *restrict)fvq->i_face_normal;
10212   const cs_real_3_t *restrict b_face_normal
10213     = (const cs_real_3_t *restrict)fvq->b_face_normal;
10214   const cs_real_3_t *restrict i_face_cog
10215     = (const cs_real_3_t *restrict)fvq->i_face_cog;
10216   const cs_real_3_t *restrict b_face_cog
10217     = (const cs_real_3_t *restrict)fvq->b_face_cog;
10218 
10219   /* Local variables */
10220 
10221   cs_real_t *df_limiter = NULL;
10222 
10223   char var_name[64];
10224 
10225   cs_real_6_t *viscce;
10226   cs_real_6_t *w2;
10227   cs_real_63_t *grad;
10228 
10229   cs_field_t *f;
10230 
10231   /* 1. Initialization */
10232 
10233   viscce = NULL;
10234   w2 = NULL;
10235 
10236   /* Allocate work arrays */
10237   BFT_MALLOC(grad, n_cells_ext, cs_real_63_t);
10238 
10239   /* Choose gradient type */
10240   cs_halo_type_t halo_type = CS_HALO_STANDARD;
10241   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
10242 
10243   cs_gradient_type_by_imrgra(imrgra,
10244                              &gradient_type,
10245                              &halo_type);
10246 
10247   /* Handle cases where only the previous values (already synchronized)
10248      or current values are provided */
10249 
10250   if (pvar != NULL && m->halo != NULL) {
10251     cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)pvar, 6);
10252     if (cs_glob_mesh->n_init_perio > 0)
10253       cs_halo_perio_sync_var_sym_tens(m->halo, halo_type, (cs_real_t *)pvar);
10254   }
10255   if (pvara == NULL)
10256     pvara = (const cs_real_6_t *restrict)pvar;
10257 
10258   const cs_real_6_t  *restrict _pvar
10259     = (pvar != NULL) ? (const cs_real_6_t  *restrict)pvar : pvara;
10260 
10261   /* Logging info */
10262 
10263   if (f_id != -1) {
10264     f = cs_field_by_id(f_id);
10265 
10266     int df_limiter_id
10267       = cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
10268     if (df_limiter_id > -1)
10269       df_limiter = cs_field_by_id(df_limiter_id)->val;
10270 
10271     snprintf(var_name, 63, "%s", f->name);
10272   }
10273   else
10274     strncpy(var_name, "[anisotropic diffusion, tensor]", 63);
10275   var_name[63] = '\0';
10276 
10277   /* Porosity fields */
10278   cs_field_t *fporo = cs_field_by_name_try("porosity");
10279   cs_field_t *ftporo = cs_field_by_name_try("tensorial_porosity");
10280 
10281   cs_real_t *porosi = NULL;
10282   cs_real_6_t *porosf = NULL;
10283 
10284   if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2) {
10285     porosi = fporo->val;
10286     if (ftporo != NULL) {
10287       porosf = (cs_real_6_t *)ftporo->val;
10288     }
10289   }
10290 
10291   /* Without porosity */
10292   if (porosi == NULL) {
10293     viscce = viscel;
10294 
10295     /* With porosity */
10296   } else if (porosi != NULL && porosf == NULL) {
10297     BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
10298     for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
10299       for (int isou = 0; isou < 6; isou++) {
10300         w2[cell_id][isou] = porosi[cell_id]*viscel[cell_id][isou];
10301       }
10302     }
10303     viscce = w2;
10304 
10305     /* With tensorial porosity */
10306   } else if (porosi != NULL && porosf != NULL) {
10307     BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
10308     for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
10309       cs_math_sym_33_product(porosf[cell_id],
10310                              viscel[cell_id],
10311                              w2[cell_id]);
10312     }
10313     viscce = w2;
10314   }
10315 
10316   /* ---> Periodicity and parallelism treatment of symmetric tensors */
10317   if (halo != NULL) {
10318     cs_halo_sync_var_strided(halo, halo_type, (cs_real_t *)viscce, 6);
10319     if (m->n_init_perio > 0)
10320       cs_halo_perio_sync_var_sym_tens(halo, halo_type, (cs_real_t *)viscce);
10321   }
10322 
10323   /* 2. Compute the diffusive part with reconstruction technics */
10324 
10325   /* ======================================================================
10326      ---> Compute the gradient of the current variable if needed
10327      ======================================================================*/
10328 
10329   if (ircflp == 1) {
10330 
10331     cs_gradient_tensor_synced_input(var_name,
10332                                     gradient_type,
10333                                     halo_type,
10334                                     inc,
10335                                     nswrgp,
10336                                     iwarnp,
10337                                     imligp,
10338                                     epsrgp,
10339                                     climgp,
10340                                     coefa,
10341                                     coefb,
10342                                     _pvar,
10343                                     grad);
10344 
10345   } else {
10346 #   pragma omp parallel for
10347     for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
10348       for (int isou = 0; isou < 6; isou++) {
10349         for (int jsou = 0; jsou < 3; jsou++)
10350           grad[cell_id][isou][jsou] = 0.;
10351       }
10352     }
10353   }
10354 
10355   /* ======================================================================
10356      ---> Contribution from interior faces
10357      ======================================================================*/
10358 
10359   if (n_cells_ext > n_cells) {
10360 #   pragma omp parallel for if(n_cells_ext -n_cells > CS_THR_MIN)
10361     for (cs_lnum_t cell_id = n_cells; cell_id < n_cells_ext; cell_id++) {
10362       for (int isou = 0; isou < 6; isou++) {
10363         rhs[cell_id][isou] = 0.;
10364       }
10365     }
10366   }
10367 
10368   /* Steady */
10369   if (idtvar < 0) {
10370 
10371     for (int g_id = 0; g_id < n_i_groups; g_id++) {
10372 #     pragma omp parallel for
10373       for (int t_id = 0; t_id < n_i_threads; t_id++) {
10374         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
10375              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
10376              face_id++) {
10377 
10378           cs_lnum_t ii = i_face_cells[face_id][0];
10379           cs_lnum_t jj = i_face_cells[face_id][1];
10380 
10381           cs_real_t visci[3][3], viscj[3][3];
10382           cs_real_t diippf[3], djjppf[3], pipp[6], pjpp[6];
10383           cs_real_t  pir[6], pjr[6], pippr[6], pjppr[6];
10384           cs_real_t  pi[6], pj[6], pia[6], pja[6];
10385 
10386           for (int isou = 0; isou < 6; isou++) {
10387             pi[isou] = _pvar[ii][isou];
10388             pj[isou] = _pvar[jj][isou];
10389             pia[isou] = pvara[ii][isou];
10390             pja[isou] = pvara[jj][isou];
10391           }
10392 
10393           cs_real_t bldfrp = (cs_real_t) ircflp;
10394           /* Local limitation of the reconstruction */
10395           if (df_limiter != NULL && ircflp > 0)
10396             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
10397 
10398 
10399           /* Recompute II" and JJ"
10400              ----------------------*/
10401 
10402           visci[0][0] = viscce[ii][0];
10403           visci[1][1] = viscce[ii][1];
10404           visci[2][2] = viscce[ii][2];
10405           visci[1][0] = viscce[ii][3];
10406           visci[0][1] = viscce[ii][3];
10407           visci[2][1] = viscce[ii][4];
10408           visci[1][2] = viscce[ii][4];
10409           visci[2][0] = viscce[ii][5];
10410           visci[0][2] = viscce[ii][5];
10411 
10412           /* IF.Ki.S / ||Ki.S||^2 */
10413           cs_real_t fikdvi = weighf[face_id][0];
10414 
10415           /* II" = IF + FI" */
10416           for (int i = 0; i < 3; i++) {
10417             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
10418                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
10419                                + visci[1][i]*i_face_normal[face_id][1]
10420                                + visci[2][i]*i_face_normal[face_id][2] );
10421           }
10422 
10423           viscj[0][0] = viscce[jj][0];
10424           viscj[1][1] = viscce[jj][1];
10425           viscj[2][2] = viscce[jj][2];
10426           viscj[1][0] = viscce[jj][3];
10427           viscj[0][1] = viscce[jj][3];
10428           viscj[2][1] = viscce[jj][4];
10429           viscj[1][2] = viscce[jj][4];
10430           viscj[2][0] = viscce[jj][5];
10431           viscj[0][2] = viscce[jj][5];
10432 
10433           /* FJ.Kj.S / ||Kj.S||^2 */
10434           cs_real_t fjkdvi = weighf[face_id][1];
10435 
10436           /* JJ" = JF + FJ" */
10437           for (int i = 0; i < 3; i++) {
10438             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
10439                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
10440                                + viscj[1][i]*i_face_normal[face_id][1]
10441                                + viscj[2][i]*i_face_normal[face_id][2] );
10442           }
10443 
10444           for (int isou = 0; isou < 6; isou++) {
10445             /* p in I" and J" */
10446             pipp[isou] = pi[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
10447                                            + grad[ii][isou][1]*diippf[1]
10448                                            + grad[ii][isou][2]*diippf[2]);
10449             pjpp[isou] = pj[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
10450                                            + grad[jj][isou][1]*djjppf[1]
10451                                            + grad[jj][isou][2]*djjppf[2]);
10452 
10453             pir[isou] = pi[isou]/relaxp - (1.-relaxp)/relaxp * pia[isou];
10454             pjr[isou] = pj[isou]/relaxp - (1.-relaxp)/relaxp * pja[isou];
10455 
10456 
10457             /* pr in I" and J" */
10458             pippr[isou] = pir[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
10459                                              + grad[ii][isou][1]*diippf[1]
10460                                              + grad[ii][isou][2]*diippf[2]);
10461             pjppr[isou] = pjr[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
10462                                              + grad[jj][isou][1]*djjppf[1]
10463                                              + grad[jj][isou][2]*djjppf[2]);
10464 
10465 
10466             cs_real_t fluxi = i_visc[face_id]*(pippr[isou] - pjpp[isou]);
10467             cs_real_t fluxj = i_visc[face_id]*(pipp[isou] - pjppr[isou]);
10468 
10469             rhs[ii][isou] -= fluxi;
10470             rhs[jj][isou] += fluxj;
10471           } // loop on isou
10472         }
10473       }
10474     }
10475 
10476     /* Unsteady */
10477   } else {
10478 
10479     for (int g_id = 0; g_id < n_i_groups; g_id++) {
10480 #     pragma omp parallel for
10481       for (int t_id = 0; t_id < n_i_threads; t_id++) {
10482         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
10483              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
10484              face_id++) {
10485 
10486           cs_lnum_t ii = i_face_cells[face_id][0];
10487           cs_lnum_t jj = i_face_cells[face_id][1];
10488 
10489           cs_real_t visci[3][3], viscj[3][3];
10490           cs_real_t diippf[3], djjppf[3], pipp[6], pjpp[6];
10491           cs_real_t pi[6], pj[6];
10492 
10493           for (int isou = 0; isou < 6; isou++) {
10494             pi[isou] = _pvar[ii][isou];
10495             pj[isou] = _pvar[jj][isou];
10496           }
10497 
10498           cs_real_t bldfrp = (cs_real_t) ircflp;
10499           /* Local limitation of the reconstruction */
10500           if (df_limiter != NULL && ircflp > 0)
10501             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
10502 
10503           /* Recompute II" and JJ"
10504              ----------------------*/
10505 
10506           visci[0][0] = viscce[ii][0];
10507           visci[1][1] = viscce[ii][1];
10508           visci[2][2] = viscce[ii][2];
10509           visci[1][0] = viscce[ii][3];
10510           visci[0][1] = viscce[ii][3];
10511           visci[2][1] = viscce[ii][4];
10512           visci[1][2] = viscce[ii][4];
10513           visci[2][0] = viscce[ii][5];
10514           visci[0][2] = viscce[ii][5];
10515 
10516           /* IF.Ki.S / ||Ki.S||^2 */
10517           cs_real_t fikdvi = weighf[face_id][0];
10518 
10519           /* II" = IF + FI" */
10520           for (int i = 0; i < 3; i++) {
10521             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
10522                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
10523                                + visci[1][i]*i_face_normal[face_id][1]
10524                                + visci[2][i]*i_face_normal[face_id][2] );
10525           }
10526 
10527           viscj[0][0] = viscce[jj][0];
10528           viscj[1][1] = viscce[jj][1];
10529           viscj[2][2] = viscce[jj][2];
10530           viscj[1][0] = viscce[jj][3];
10531           viscj[0][1] = viscce[jj][3];
10532           viscj[2][1] = viscce[jj][4];
10533           viscj[1][2] = viscce[jj][4];
10534           viscj[2][0] = viscce[jj][5];
10535           viscj[0][2] = viscce[jj][5];
10536 
10537           /* FJ.Kj.S / ||Kj.S||^2 */
10538           cs_real_t fjkdvi = weighf[face_id][1];
10539 
10540           /* JJ" = JF + FJ" */
10541           for (int i = 0; i < 3; i++) {
10542             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
10543                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
10544                                + viscj[1][i]*i_face_normal[face_id][1]
10545                                + viscj[2][i]*i_face_normal[face_id][2] );
10546           }
10547 
10548           for (int isou = 0; isou < 6; isou++) {
10549             /* p in I" and J" */
10550             pipp[isou] = pi[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
10551                                            + grad[ii][isou][1]*diippf[1]
10552                                            + grad[ii][isou][2]*diippf[2]);
10553             pjpp[isou] = pj[isou] + bldfrp*( grad[jj][isou][0]*djjppf[0]
10554                                            + grad[jj][isou][1]*djjppf[1]
10555                                            + grad[jj][isou][2]*djjppf[2]);
10556 
10557             cs_real_t flux = i_visc[face_id]*(pipp[isou] -pjpp[isou]);
10558 
10559             rhs[ii][isou] -= thetap*flux;
10560             rhs[jj][isou] += thetap*flux;
10561           }
10562         }
10563       }
10564     }
10565   }
10566 
10567   /* ======================================================================
10568      ---> Contribution from boundary faces
10569      ======================================================================*/
10570 
10571   /* Steady */
10572   if (idtvar < 0) {
10573 
10574     for (int g_id = 0; g_id < n_b_groups; g_id++) {
10575 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
10576       for (int t_id = 0; t_id < n_b_threads; t_id++) {
10577         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
10578              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
10579              face_id++) {
10580 
10581           cs_lnum_t ii = b_face_cells[face_id];
10582 
10583           cs_real_t pi[6], pia[6], pir[6], pippr[6];
10584           cs_real_t visci[3][3];
10585           cs_real_t diippf[3];
10586 
10587           for (int isou = 0; isou < 6; isou++) {
10588             pi[isou] = _pvar[ii][isou];
10589             pia[isou] = pvara[ii][isou];
10590             pir[isou] = pi[isou]/relaxp - (1.-relaxp)/relaxp*pia[isou];
10591           }
10592 
10593           cs_real_t bldfrp = (cs_real_t) ircflp;
10594           /* Local limitation of the reconstruction */
10595           if (df_limiter != NULL && ircflp > 0)
10596             bldfrp = CS_MAX(df_limiter[ii], 0.);
10597 
10598           /* Recompute II"
10599              --------------*/
10600 
10601           visci[0][0] = viscce[ii][0];
10602           visci[1][1] = viscce[ii][1];
10603           visci[2][2] = viscce[ii][2];
10604           visci[1][0] = viscce[ii][3];
10605           visci[0][1] = viscce[ii][3];
10606           visci[2][1] = viscce[ii][4];
10607           visci[1][2] = viscce[ii][4];
10608           visci[2][0] = viscce[ii][5];
10609           visci[0][2] = viscce[ii][5];
10610 
10611           /* IF.Ki.S / ||Ki.S||^2 */
10612           cs_real_t fikdvi = weighb[face_id];
10613 
10614           /* II" = IF + FI" */
10615           for (int i = 0; i < 3; i++) {
10616             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
10617                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
10618                                + visci[1][i]*b_face_normal[face_id][1]
10619                                + visci[2][i]*b_face_normal[face_id][2] );
10620           }
10621           for (int isou = 0; isou < 6; isou++) {
10622             pippr[isou] = pir[isou] + bldfrp*( grad[ii][isou][0]*diippf[0]
10623                                              + grad[ii][isou][1]*diippf[1]
10624                                              + grad[ii][isou][2]*diippf[2]);
10625           }
10626           for (int isou = 0; isou < 6; isou++) {
10627             cs_real_t pfacd = inc*cofaf[face_id][isou];
10628             for (int jsou = 0; jsou < 6; jsou++) {
10629               pfacd += cofbf[face_id][isou][jsou]*pippr[jsou];
10630             }
10631 
10632             cs_real_t flux = b_visc[face_id]*pfacd;
10633             rhs[ii][isou] -= flux;
10634           }
10635         }
10636       }
10637     }
10638 
10639     /* Unsteady */
10640   } else {
10641 
10642     for (int g_id = 0; g_id < n_b_groups; g_id++) {
10643 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
10644       for (int t_id = 0; t_id < n_b_threads; t_id++) {
10645         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
10646              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
10647              face_id++) {
10648 
10649           cs_lnum_t ii = b_face_cells[face_id];
10650 
10651           cs_real_t visci[3][3];
10652           cs_real_t diippf[3], pi[6], pipp[6];
10653 
10654           for (int isou = 0; isou < 6; isou++) {
10655             pi[isou] = _pvar[ii][isou];
10656           }
10657 
10658           cs_real_t bldfrp = (cs_real_t) ircflp;
10659           /* Local limitation of the reconstruction */
10660           if (df_limiter != NULL && ircflp > 0)
10661             bldfrp = CS_MAX(df_limiter[ii], 0.);
10662 
10663 
10664           /* Recompute II"
10665              --------------*/
10666 
10667           visci[0][0] = viscce[ii][0];
10668           visci[1][1] = viscce[ii][1];
10669           visci[2][2] = viscce[ii][2];
10670           visci[1][0] = viscce[ii][3];
10671           visci[0][1] = viscce[ii][3];
10672           visci[2][1] = viscce[ii][4];
10673           visci[1][2] = viscce[ii][4];
10674           visci[2][0] = viscce[ii][5];
10675           visci[0][2] = viscce[ii][5];
10676 
10677           /* IF.Ki.S / ||Ki.S||^2 */
10678           cs_real_t fikdvi = weighb[face_id];
10679 
10680           /* II" = IF + FI" */
10681           for (int i = 0; i < 3; i++) {
10682             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
10683                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
10684                                + visci[1][i]*b_face_normal[face_id][1]
10685                                + visci[2][i]*b_face_normal[face_id][2]);
10686           }
10687           for (int isou = 0; isou < 6; isou++) {
10688             pipp[isou] = pi[isou] + bldfrp * ( grad[ii][isou][0]*diippf[0]
10689                                                + grad[ii][isou][1]*diippf[1]
10690                                                + grad[ii][isou][2]*diippf[2]);
10691           }
10692           for (int isou = 0; isou < 6; isou++) {
10693             cs_real_t pfacd = inc*cofaf[face_id][isou];
10694             for (int jsou = 0; jsou < 6; jsou++) {
10695               pfacd += cofbf[face_id][isou][jsou]*pipp[jsou];
10696             }
10697 
10698             cs_real_t flux = b_visc[face_id]*pfacd;
10699             rhs[ii][isou] -= thetap*flux;
10700           }
10701 
10702         }
10703       }
10704     }
10705 
10706   }
10707 
10708   /* Free memory */
10709   BFT_FREE(grad);
10710   BFT_FREE(w2);
10711 }
10712 
10713 /*----------------------------------------------------------------------------*/
10714 /*!
10715  * \brief Update the face mass flux with the face pressure (or pressure
10716  * increment, or pressure double increment) gradient.
10717  *
10718  * <a name="itrmas"></a>
10719  *
10720  * \f[
10721  * \dot{m}_\ij = \dot{m}_\ij
10722  *             - \Delta t \grad_\fij \delta p \cdot \vect{S}_\ij
10723  * \f]
10724  *
10725  * Please refer to the
10726  * <a href="../../theory.pdf#itrmas"><b>itrmas/itrgrp</b></a> section of the
10727  * theory guide for more information.
10728  *
10729  * \param[in]     f_id          field id (or -1)
10730  * \param[in]     m             pointer to mesh
10731  * \param[in]     fvq           pointer to finite volume quantities
10732  * \param[in]     init          indicator
10733  *                               - 1 initialize the mass flux to 0
10734  *                               - 0 otherwise
10735  * \param[in]     inc           indicator
10736  *                               - 0 when solving an increment
10737  *                               - 1 otherwise
10738  * \param[in]     imrgra        indicator
10739  *                               - 0 iterative gradient
10740  *                               - 1 least squares gradient
10741  * \param[in]     iccocg        indicator
10742  *                               - 1 re-compute cocg matrix
10743  *                                 (for iterative gradients)
10744  *                               - 0 otherwise
10745  * \param[in]     nswrgp        number of reconstruction sweeps for the
10746  *                               gradients
10747  * \param[in]     imligp        clipping gradient method
10748  *                               - < 0 no clipping
10749  *                               - = 0 thank to neighbooring gradients
10750  *                               - = 1 thank to the mean gradient
10751  * \param[in]     iphydp        hydrostatic pressure indicator
10752  * \param[in]     iwgrp         indicator
10753  *                               - 1 weight gradient by vicosity*porosity
10754  *                               - weighting determined by field options
10755  * \param[in]     iwarnp        verbosity
10756  * \param[in]     epsrgp        relative precision for the gradient
10757  *                               reconstruction
10758  * \param[in]     climgp        clipping coeffecient for the computation of
10759  *                               the gradient
10760  * \param[in]     frcxt         body force creating the hydrostatic pressure
10761  * \param[in]     pvar          solved variable (current time step)
10762  * \param[in]     coefap        boundary condition array for the variable
10763  *                               (explicit part)
10764  * \param[in]     coefbp        boundary condition array for the variable
10765  *                               (implicit part)
10766  * \param[in]     cofafp        boundary condition array for the diffusion
10767  *                               of the variable (explicit part)
10768  * \param[in]     cofbfp        boundary condition array for the diffusion
10769  *                               of the variable (implicit part)
10770  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
10771  *                               at interior faces for the r.h.s.
10772  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
10773  *                               at border faces for the r.h.s.
10774  * \param[in]     visel         viscosity by cell
10775  * \param[in,out] i_massflux    mass flux at interior faces
10776  * \param[in,out] b_massflux    mass flux at boundary faces
10777  */
10778 /*----------------------------------------------------------------------------*/
10779 
10780 void
cs_face_diffusion_potential(const int f_id,const cs_mesh_t * m,cs_mesh_quantities_t * fvq,int init,int inc,int imrgra,int iccocg,int nswrgp,int imligp,int iphydp,int iwgrp,int iwarnp,double epsrgp,double climgp,cs_real_3_t * restrict frcxt,cs_real_t * restrict pvar,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_t * restrict visel,cs_real_t * restrict i_massflux,cs_real_t * restrict b_massflux)10781 cs_face_diffusion_potential(const int                 f_id,
10782                             const cs_mesh_t          *m,
10783                             cs_mesh_quantities_t     *fvq,
10784                             int                       init,
10785                             int                       inc,
10786                             int                       imrgra,
10787                             int                       iccocg,
10788                             int                       nswrgp,
10789                             int                       imligp,
10790                             int                       iphydp,
10791                             int                       iwgrp,
10792                             int                       iwarnp,
10793                             double                    epsrgp,
10794                             double                    climgp,
10795                             cs_real_3_t     *restrict frcxt,
10796                             cs_real_t       *restrict pvar,
10797                             const cs_real_t           coefap[],
10798                             const cs_real_t           coefbp[],
10799                             const cs_real_t           cofafp[],
10800                             const cs_real_t           cofbfp[],
10801                             const cs_real_t           i_visc[],
10802                             const cs_real_t           b_visc[],
10803                             cs_real_t       *restrict visel,
10804                             cs_real_t       *restrict i_massflux,
10805                             cs_real_t       *restrict b_massflux)
10806 {
10807   const cs_halo_t  *halo = m->halo;
10808 
10809   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
10810   const int n_i_groups = m->i_face_numbering->n_groups;
10811   const int n_i_threads = m->i_face_numbering->n_threads;
10812   const int n_b_groups = m->b_face_numbering->n_groups;
10813   const int n_b_threads = m->b_face_numbering->n_threads;
10814   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
10815   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
10816   const cs_lnum_2_t *restrict i_face_cells
10817     = (const cs_lnum_2_t *restrict)m->i_face_cells;
10818   const cs_lnum_t *restrict b_face_cells
10819     = (const cs_lnum_t *restrict)m->b_face_cells;
10820   const cs_real_t *restrict i_dist = fvq->i_dist;
10821   const cs_real_t *restrict i_f_face_surf = fvq->i_f_face_surf;
10822   const cs_real_3_t *restrict diipf
10823     = (const cs_real_3_t *restrict)fvq->diipf;
10824   const cs_real_3_t *restrict djjpf
10825     = (const cs_real_3_t *restrict)fvq->djjpf;
10826   const cs_real_3_t *restrict diipb
10827     = (const cs_real_3_t *restrict)fvq->diipb;
10828 
10829   /* Local variables */
10830 
10831   char var_name[64];
10832   int w_stride = 1;
10833 
10834   bool recompute_cocg = (iccocg) ? true : false;
10835 
10836   cs_real_3_t *grad;
10837   cs_field_t *f;
10838 
10839   cs_real_t *gweight = NULL;
10840 
10841   /*==========================================================================*/
10842 
10843   /* i_visc and carry similar information */
10844 
10845   /*============================================================================
10846     1. Initialization
10847     ==========================================================================*/
10848 
10849   if (init >= 1) {
10850 #   pragma omp parallel for
10851     for (cs_lnum_t face_id = 0; face_id < m->n_i_faces; face_id++) {
10852       i_massflux[face_id] = 0.;
10853     }
10854 #   pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
10855     for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id++) {
10856       b_massflux[face_id] = 0.;
10857     }
10858   } else if (init != 0) {
10859     bft_error(__FILE__, __LINE__, 0,
10860               _("invalid value of init"));
10861   }
10862 
10863   /* Use iterative gradient */
10864 
10865   cs_halo_type_t halo_type = CS_HALO_STANDARD;
10866   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
10867 
10868   if (imrgra < 0)
10869     imrgra = 0;
10870 
10871   cs_gradient_type_by_imrgra(imrgra,
10872                              &gradient_type,
10873                              &halo_type);
10874 
10875   if (f_id > -1) {
10876     f = cs_field_by_id(f_id);
10877     snprintf(var_name, 63, "%s", f->name);
10878   }
10879   else
10880     strncpy(var_name, "[face mass flux update]", 63);
10881   var_name[63] = '\0';
10882 
10883   /* Handle parallelism and periodicity */
10884 
10885   if (halo != NULL)
10886     cs_halo_sync_var(halo, halo_type, pvar);
10887 
10888   /*==========================================================================
10889     2. Update mass flux without reconstruction technics
10890     ==========================================================================*/
10891 
10892   if (nswrgp <= 1) {
10893 
10894     /* Mass flow through interior faces */
10895 
10896     for (int g_id = 0; g_id < n_i_groups; g_id++) {
10897 #     pragma omp parallel for
10898       for (int t_id = 0; t_id < n_i_threads; t_id++) {
10899         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
10900              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
10901              face_id++) {
10902 
10903           cs_lnum_t ii = i_face_cells[face_id][0];
10904           cs_lnum_t jj = i_face_cells[face_id][1];
10905 
10906           i_massflux[face_id] += i_visc[face_id]*(pvar[ii] - pvar[jj]);
10907 
10908         }
10909       }
10910     }
10911 
10912     /* Mass flow through boundary faces */
10913 
10914     for (int g_id = 0; g_id < n_b_groups; g_id++) {
10915 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
10916       for (int t_id = 0; t_id < n_b_threads; t_id++) {
10917         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
10918              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
10919              face_id++) {
10920 
10921           cs_lnum_t ii = b_face_cells[face_id];
10922           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pvar[ii];
10923 
10924           b_massflux[face_id] += b_visc[face_id]*pfac;
10925 
10926         }
10927       }
10928     }
10929 
10930   }
10931 
10932   /*==========================================================================
10933     3. Update mass flux with reconstruction technique if the mesh is non
10934        orthogonal
10935     ==========================================================================*/
10936 
10937   if (nswrgp > 1) {
10938 
10939     /* Allocate a work array for the gradient calculation */
10940     BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
10941 
10942     /* Compute gradient */
10943     if (iwgrp > 0) {
10944       gweight = visel;
10945       if (halo != NULL)
10946         cs_halo_sync_var(halo, halo_type, gweight);
10947     }
10948 
10949     else if (f_id > -1) {
10950       /* Get the calculation option from the field */
10951       int key_cal_opt_id = cs_field_key_id("var_cal_opt");
10952       cs_var_cal_opt_t var_cal_opt;
10953       cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
10954       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
10955         if (var_cal_opt.idiff > 0) {
10956           int key_id = cs_field_key_id("gradient_weighting_id");
10957           int diff_id = cs_field_get_key_int(f, key_id);
10958           if (diff_id > -1) {
10959             cs_field_t *weight_f = cs_field_by_id(diff_id);
10960             gweight = weight_f->val;
10961             w_stride = weight_f->dim;
10962             cs_field_synchronize(weight_f, halo_type);
10963           }
10964         }
10965       }
10966     }
10967 
10968     cs_gradient_scalar_synced_input(var_name,
10969                                     gradient_type,
10970                                     halo_type,
10971                                     inc,
10972                                     recompute_cocg,
10973                                     nswrgp,
10974                                     iphydp,
10975                                     w_stride,
10976                                     iwarnp,
10977                                     imligp,
10978                                     epsrgp,
10979                                     climgp,
10980                                     frcxt,
10981                                     coefap,
10982                                     coefbp,
10983                                     (const cs_real_t *)pvar,
10984                                     gweight, /* Weighted gradient */
10985                                     NULL, /* internal coupling */
10986                                     grad);
10987 
10988     /* Handle parallelism and periodicity */
10989 
10990     if (halo != NULL)
10991       cs_halo_sync_var(halo, halo_type, visel);
10992 
10993     /* Mass flow through interior faces */
10994 
10995     for (int g_id = 0; g_id < n_i_groups; g_id++) {
10996 #     pragma omp parallel for
10997       for (int t_id = 0; t_id < n_i_threads; t_id++) {
10998         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
10999              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
11000              face_id++) {
11001 
11002           cs_lnum_t ii = i_face_cells[face_id][0];
11003           cs_lnum_t jj = i_face_cells[face_id][1];
11004 
11005           double dpxf = 0.5*(  visel[ii]*grad[ii][0]
11006                              + visel[jj]*grad[jj][0]);
11007           double dpyf = 0.5*(  visel[ii]*grad[ii][1]
11008                              + visel[jj]*grad[jj][1]);
11009           double dpzf = 0.5*(  visel[ii]*grad[ii][2]
11010                              + visel[jj]*grad[jj][2]);
11011 
11012           /*---> Dij = IJ - (IJ.N) N = II' - JJ' */
11013           double dijx = diipf[face_id][0] - djjpf[face_id][0];
11014           double dijy = diipf[face_id][1] - djjpf[face_id][1];
11015           double dijz = diipf[face_id][2] - djjpf[face_id][2];
11016 
11017           i_massflux[face_id] =  i_massflux[face_id]
11018                                + i_visc[face_id]*(pvar[ii] - pvar[jj])
11019                                +  (dpxf *dijx + dpyf*dijy + dpzf*dijz)
11020                                  * i_f_face_surf[face_id]/i_dist[face_id];
11021 
11022         }
11023       }
11024     }
11025 
11026     /* Mass flow through boundary faces */
11027 
11028     for (int g_id = 0; g_id < n_b_groups; g_id++) {
11029 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
11030       for (int t_id = 0; t_id < n_b_threads; t_id++) {
11031         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
11032              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
11033              face_id++) {
11034 
11035           cs_lnum_t ii = b_face_cells[face_id];
11036 
11037           double diipbx = diipb[face_id][0];
11038           double diipby = diipb[face_id][1];
11039           double diipbz = diipb[face_id][2];
11040 
11041           double pip = pvar[ii] + grad[ii][0]*diipbx
11042                                  + grad[ii][1]*diipby
11043                                  + grad[ii][2]*diipbz;
11044           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pip;
11045 
11046           b_massflux[face_id] += b_visc[face_id]*pfac;
11047 
11048         }
11049       }
11050     }
11051 
11052     /* Free memory */
11053     BFT_FREE(grad);
11054   }
11055 }
11056 
11057 /*----------------------------------------------------------------------------*/
11058 /*!
11059  * \brief Add the explicit part of the pressure gradient term to the mass flux
11060  * in case of anisotropic diffusion of the pressure field \f$ P \f$.
11061  *
11062  * More precisely, the mass flux side \f$ \dot{m}_\fij \f$ is updated as
11063  * follows:
11064  * \f[
11065  * \dot{m}_\fij = \dot{m}_\fij -
11066  *              \left( \tens{\mu}_\fij \gradv_\fij P \cdot \vect{S}_\ij  \right)
11067  * \f]
11068  *
11069  * \param[in]     f_id          field id (or -1)
11070  * \param[in]     m             pointer to mesh
11071  * \param[in]     fvq           pointer to finite volume quantities
11072  * \param[in]     init           indicator
11073  *                               - 1 initialize the mass flux to 0
11074  *                               - 0 otherwise
11075  * \param[in]     inc           indicator
11076  *                               - 0 when solving an increment
11077  *                               - 1 otherwise
11078  * \param[in]     imrgra        indicator
11079  *                               - 0 iterative gradient
11080  *                               - 1 least squares gradient
11081  * \param[in]     iccocg        indicator
11082  *                               - 1 re-compute cocg matrix
11083                                     (for iterativ gradients)
11084  *                               - 0 otherwise
11085  * \param[in]     nswrgp        number of reconstruction sweeps for the
11086  *                               gradients
11087  * \param[in]     imligp        clipping gradient method
11088  *                               - < 0 no clipping
11089  *                               - = 0 thank to neighbooring gradients
11090  *                               - = 1 thank to the mean gradient
11091  * \param[in]     ircflp        indicator
11092  *                               - 1 flux reconstruction,
11093  *                               - 0 otherwise
11094  * \param[in]     iphydp        indicator
11095  *                               - 1 hydrostatic pressure taken into account
11096  *                               - 0 otherwise
11097  * \param[in]     iwgrp         indicator
11098  *                               - 1 weight gradient by vicosity*porosity
11099  *                               - weighting determined by field options
11100  * \param[in]     iwarnp        verbosity
11101  * \param[in]     epsrgp        relative precision for the gradient
11102  *                               reconstruction
11103  * \param[in]     climgp        clipping coeffecient for the computation of
11104  *                               the gradient
11105  * \param[in]     frcxt         body force creating the hydrostatic pressure
11106  * \param[in]     pvar          solved variable (pressure)
11107  * \param[in]     coefap        boundary condition array for the variable
11108  *                               (explicit part)
11109  * \param[in]     coefbp        boundary condition array for the variable
11110  *                               (implicit part)
11111  * \param[in]     cofafp        boundary condition array for the diffusion
11112  *                               of the variable (explicit part)
11113  * \param[in]     cofbfp        boundary condition array for the diffusion
11114  *                               of the variable (implicit part)
11115  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
11116  *                               at interior faces for the r.h.s.
11117  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
11118  *                               at border faces for the r.h.s.
11119  * \param[in]     viscel        symmetric cell tensor \f$ \tens{\mu}_\celli \f$
11120  * \param[in]     weighf        internal face weight between cells i j in case
11121  *                               of tensor diffusion
11122  * \param[in]     weighb        boundary face weight for cells i in case
11123  *                               of tensor diffusion
11124  * \param[in,out] i_massflux    mass flux at interior faces
11125  * \param[in,out] b_massflux    mass flux at boundary faces
11126  */
11127 /*----------------------------------------------------------------------------*/
11128 
11129 void
cs_face_anisotropic_diffusion_potential(const int f_id,const cs_mesh_t * m,cs_mesh_quantities_t * fvq,int init,int inc,int imrgra,int iccocg,int nswrgp,int imligp,int ircflp,int iphydp,int iwgrp,int iwarnp,double epsrgp,double climgp,cs_real_3_t * restrict frcxt,cs_real_t * restrict pvar,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict viscel,const cs_real_2_t weighf[],const cs_real_t weighb[],cs_real_t * restrict i_massflux,cs_real_t * restrict b_massflux)11130 cs_face_anisotropic_diffusion_potential(const int                 f_id,
11131                                         const cs_mesh_t          *m,
11132                                         cs_mesh_quantities_t     *fvq,
11133                                         int                       init,
11134                                         int                       inc,
11135                                         int                       imrgra,
11136                                         int                       iccocg,
11137                                         int                       nswrgp,
11138                                         int                       imligp,
11139                                         int                       ircflp,
11140                                         int                       iphydp,
11141                                         int                       iwgrp,
11142                                         int                       iwarnp,
11143                                         double                    epsrgp,
11144                                         double                    climgp,
11145                                         cs_real_3_t     *restrict frcxt,
11146                                         cs_real_t       *restrict pvar,
11147                                         const cs_real_t           coefap[],
11148                                         const cs_real_t           coefbp[],
11149                                         const cs_real_t           cofafp[],
11150                                         const cs_real_t           cofbfp[],
11151                                         const cs_real_t           i_visc[],
11152                                         const cs_real_t           b_visc[],
11153                                         cs_real_6_t     *restrict viscel,
11154                                         const cs_real_2_t         weighf[],
11155                                         const cs_real_t           weighb[],
11156                                         cs_real_t       *restrict i_massflux,
11157                                         cs_real_t       *restrict b_massflux)
11158 {
11159   const cs_halo_t  *halo = m->halo;
11160 
11161   const cs_lnum_t n_cells = m->n_cells;
11162   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
11163 
11164   const int n_i_groups = m->i_face_numbering->n_groups;
11165   const int n_i_threads = m->i_face_numbering->n_threads;
11166   const int n_b_groups = m->b_face_numbering->n_groups;
11167   const int n_b_threads = m->b_face_numbering->n_threads;
11168   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
11169   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
11170 
11171   const cs_lnum_2_t *restrict i_face_cells
11172     = (const cs_lnum_2_t *restrict)m->i_face_cells;
11173   const cs_lnum_t *restrict b_face_cells
11174     = (const cs_lnum_t *restrict)m->b_face_cells;
11175   const cs_real_3_t *restrict cell_cen
11176     = (const cs_real_3_t *restrict)fvq->cell_cen;
11177   const cs_real_3_t *restrict i_face_normal
11178     = (const cs_real_3_t *restrict)fvq->i_face_normal;
11179   const cs_real_3_t *restrict b_face_normal
11180     = (const cs_real_3_t *restrict)fvq->b_face_normal;
11181   const cs_real_3_t *restrict i_face_cog
11182     = (const cs_real_3_t *restrict)fvq->i_face_cog;
11183   const cs_real_3_t *restrict b_face_cog
11184     = (const cs_real_3_t *restrict)fvq->b_face_cog;
11185 
11186   /* Local variables */
11187 
11188   cs_real_t *df_limiter = NULL;
11189 
11190   char var_name[64];
11191   int w_stride = 6;
11192 
11193   bool recompute_cocg = (iccocg) ? true : false;
11194 
11195   cs_real_6_t *viscce;
11196   cs_real_6_t *w2;
11197   cs_real_3_t *grad;
11198   cs_field_t *f = NULL;
11199 
11200   cs_real_t *gweight = NULL;
11201 
11202   /*==========================================================================
11203     1. Initialization
11204     ==========================================================================*/
11205 
11206   if (init >= 1) {
11207     #pragma omp parallel for
11208     for (cs_lnum_t face_id = 0; face_id < m->n_i_faces; face_id++) {
11209       i_massflux[face_id] = 0.;
11210     }
11211     for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id++) {
11212       b_massflux[face_id] = 0.;
11213     }
11214   } else if (init != 0) {
11215       bft_error(__FILE__, __LINE__, 0,
11216                 _("invalid value of init"));
11217   }
11218 
11219   /* Use iterative gradient */
11220 
11221   cs_halo_type_t halo_type = CS_HALO_STANDARD;
11222   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
11223 
11224   if (imrgra < 0)
11225     imrgra = 0;
11226 
11227   cs_gradient_type_by_imrgra(imrgra,
11228                              &gradient_type,
11229                              &halo_type);
11230 
11231   if (f_id > -1) {
11232     f = cs_field_by_id(f_id);
11233 
11234     int df_limiter_id =
11235       cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
11236     if (df_limiter_id > -1)
11237       df_limiter = cs_field_by_id(df_limiter_id)->val;
11238 
11239     snprintf(var_name, 63, "%s", f->name);
11240   }
11241   else
11242     strncpy(var_name, "[face mass flux update]", 63);
11243   var_name[63] = '\0';
11244 
11245   /* Porosity fields */
11246   cs_field_t *fporo = cs_field_by_name_try("porosity");
11247   cs_field_t *ftporo = cs_field_by_name_try("tensorial_porosity");
11248 
11249   cs_real_t *porosi = NULL;
11250   cs_real_6_t *porosf = NULL;
11251 
11252   if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2) {
11253     porosi = fporo->val;
11254     if (ftporo != NULL) {
11255       porosf = (cs_real_6_t *)ftporo->val;
11256     }
11257   }
11258 
11259   /* Handle parallelism and periodicity */
11260 
11261   if (halo != NULL)
11262     cs_halo_sync_var(halo, halo_type, pvar);
11263 
11264   /*==========================================================================
11265     2. Update mass flux without reconstruction technique
11266     ==========================================================================*/
11267 
11268   if (nswrgp <= 1) {
11269 
11270     /* ---> Contribution from interior faces */
11271 
11272     for (int g_id = 0; g_id < n_i_groups; g_id++) {
11273 #     pragma omp parallel for
11274       for (int t_id = 0; t_id < n_i_threads; t_id++) {
11275         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
11276              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
11277              face_id++) {
11278 
11279           cs_lnum_t ii = i_face_cells[face_id][0];
11280           cs_lnum_t jj = i_face_cells[face_id][1];
11281 
11282           i_massflux[face_id] += i_visc[face_id]*(pvar[ii] - pvar[jj]);
11283 
11284         }
11285       }
11286     }
11287 
11288     /* ---> Contribution from boundary faces */
11289 
11290     for (int g_id = 0; g_id < n_b_groups; g_id++) {
11291 #     pragma omp parallel for
11292       for (int t_id = 0; t_id < n_b_threads; t_id++) {
11293         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
11294              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
11295              face_id++) {
11296 
11297           cs_lnum_t ii = b_face_cells[face_id];
11298           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pvar[ii];
11299 
11300           b_massflux[face_id] += b_visc[face_id]*pfac;
11301 
11302         }
11303       }
11304     }
11305 
11306   }
11307 
11308   /*==========================================================================
11309     3. Update mass flux with reconstruction technique
11310     ==========================================================================*/
11311 
11312   if (nswrgp > 1) {
11313 
11314     viscce = NULL;
11315     w2 = NULL;
11316 
11317     /* Without porosity */
11318     if (porosi == NULL) {
11319       viscce = viscel;
11320 
11321       /* With porosity */
11322     } else if (porosi != NULL && porosf == NULL) {
11323       BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
11324       for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
11325         for (int isou = 0; isou < 6; isou++) {
11326           w2[cell_id][isou] = porosi[cell_id]*viscel[cell_id][isou];
11327         }
11328       }
11329       viscce = w2;
11330 
11331       /* With tensorial porosity */
11332     } else if (porosi != NULL && porosf != NULL) {
11333       BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
11334       for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
11335         cs_math_sym_33_product(porosf[cell_id],
11336                                viscel[cell_id],
11337                                w2[cell_id]);
11338       }
11339       viscce = w2;
11340     }
11341 
11342     /* ---> Periodicity and parallelism treatment of symmetric tensors */
11343 
11344     if (halo != NULL) {
11345       cs_halo_sync_var_strided(halo, CS_HALO_STANDARD, (cs_real_t *)viscce, 6);
11346 
11347       if (m->n_init_perio > 0)
11348         cs_halo_perio_sync_var_sym_tens(halo,
11349                                         CS_HALO_STANDARD,
11350                                         (cs_real_t *)viscce);
11351     }
11352 
11353     /* Allocate a work array for the gradient calculation */
11354     BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
11355 
11356     /* Compute gradient */
11357     if (iwgrp > 0) {
11358       gweight = (cs_real_t *)viscce;
11359       if (halo != NULL) {
11360         cs_halo_sync_var_strided(halo, halo_type, gweight, 6);
11361         if (cs_glob_mesh->n_init_perio > 0)
11362           cs_halo_perio_sync_var_sym_tens(halo, halo_type, gweight);
11363       }
11364     }
11365 
11366     else if (f_id > -1) {
11367       /* Get the calculation option from the field */
11368       int key_cal_opt_id = cs_field_key_id("var_cal_opt");
11369       cs_var_cal_opt_t var_cal_opt;
11370       cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
11371       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
11372         if (var_cal_opt.idifft > 0) {
11373           int key_id = cs_field_key_id("gradient_weighting_id");
11374           int diff_id = cs_field_get_key_int(f, key_id);
11375           if (diff_id > -1) {
11376             cs_field_t *weight_f = cs_field_by_id(diff_id);
11377             gweight = weight_f->val;
11378             w_stride = weight_f->dim;
11379             cs_field_synchronize(weight_f, halo_type);
11380           }
11381         }
11382       }
11383     }
11384 
11385     /* Compute gradient */
11386     cs_gradient_scalar_synced_input(var_name,
11387                                     gradient_type,
11388                                     halo_type,
11389                                     inc,
11390                                     recompute_cocg,
11391                                     nswrgp,
11392                                     iphydp,
11393                                     w_stride,
11394                                     iwarnp,
11395                                     imligp,
11396                                     epsrgp,
11397                                     climgp,
11398                                     frcxt,
11399                                     coefap,
11400                                     coefbp,
11401                                     pvar,
11402                                     gweight, /* Weighted gradient */
11403                                     NULL, /* internal coupling */
11404                                     grad);
11405 
11406     /* Mass flow through interior faces */
11407 
11408     for (int g_id = 0; g_id < n_i_groups; g_id++) {
11409 #     pragma omp parallel for
11410       for (int t_id = 0; t_id < n_i_threads; t_id++) {
11411         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
11412              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
11413              face_id++) {
11414 
11415           cs_lnum_t ii = i_face_cells[face_id][0];
11416           cs_lnum_t jj = i_face_cells[face_id][1];
11417 
11418           double pi = pvar[ii];
11419           double pj = pvar[jj];
11420 
11421           /* Recompute II" and JJ"
11422              ----------------------*/
11423 
11424           cs_real_t visci[3][3], viscj[3][3];
11425           cs_real_t diippf[3], djjppf[3];
11426 
11427           visci[0][0] = viscce[ii][0];
11428           visci[1][1] = viscce[ii][1];
11429           visci[2][2] = viscce[ii][2];
11430           visci[1][0] = viscce[ii][3];
11431           visci[0][1] = viscce[ii][3];
11432           visci[2][1] = viscce[ii][4];
11433           visci[1][2] = viscce[ii][4];
11434           visci[2][0] = viscce[ii][5];
11435           visci[0][2] = viscce[ii][5];
11436 
11437           cs_real_t bldfrp = (cs_real_t) ircflp;
11438           /* Local limitation of the reconstruction */
11439           if (df_limiter != NULL && ircflp > 0)
11440             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
11441 
11442 
11443           /* IF.Ki.S / ||Ki.S||^2 */
11444           cs_real_t fikdvi = weighf[face_id][0];
11445 
11446           /* II" = IF + FI" */
11447           for (int i = 0; i < 3; i++) {
11448             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
11449                       - fikdvi*(  visci[0][i]*i_face_normal[face_id][0]
11450                                 + visci[1][i]*i_face_normal[face_id][1]
11451                                 + visci[2][i]*i_face_normal[face_id][2] );
11452           }
11453 
11454           viscj[0][0] = viscce[jj][0];
11455           viscj[1][1] = viscce[jj][1];
11456           viscj[2][2] = viscce[jj][2];
11457           viscj[1][0] = viscce[jj][3];
11458           viscj[0][1] = viscce[jj][3];
11459           viscj[2][1] = viscce[jj][4];
11460           viscj[1][2] = viscce[jj][4];
11461           viscj[2][0] = viscce[jj][5];
11462           viscj[0][2] = viscce[jj][5];
11463 
11464           /* FJ.Kj.S / ||Kj.S||^2 */
11465           double fjkdvi = weighf[face_id][1];
11466 
11467           /* JJ" = JF + FJ" */
11468           for (int i = 0; i < 3; i++) {
11469             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
11470                       + fjkdvi*(  viscj[0][i]*i_face_normal[face_id][0]
11471                                 + viscj[1][i]*i_face_normal[face_id][1]
11472                                 + viscj[2][i]*i_face_normal[face_id][2] );
11473           }
11474 
11475           /* p in I" and J" */
11476           double pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
11477                                      + grad[ii][1]*diippf[1]
11478                                      + grad[ii][2]*diippf[2]);
11479           double pjpp = pj + bldfrp*(  grad[jj][0]*djjppf[0]
11480                                      + grad[jj][1]*djjppf[1]
11481                                      + grad[jj][2]*djjppf[2]);
11482 
11483           i_massflux[face_id] += i_visc[face_id]*(pipp - pjpp);
11484 
11485         }
11486       }
11487     }
11488 
11489     /* ---> Contribution from boundary faces */
11490 
11491     for (int g_id = 0; g_id < n_b_groups; g_id++) {
11492 #     pragma omp parallel for
11493       for (int t_id = 0; t_id < n_b_threads; t_id++) {
11494         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
11495              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
11496              face_id++) {
11497 
11498           cs_lnum_t ii = b_face_cells[face_id];
11499 
11500           double pi = pvar[ii];
11501 
11502           cs_real_t bldfrp = (cs_real_t) ircflp;
11503           /* Local limitation of the reconstruction */
11504           if (df_limiter != NULL && ircflp > 0)
11505             bldfrp = CS_MAX(df_limiter[ii], 0.);
11506 
11507           /* Recompute II"
11508              --------------*/
11509 
11510           cs_real_t visci[3][3];
11511           cs_real_t diippf[3];
11512 
11513           visci[0][0] = viscce[ii][0];
11514           visci[1][1] = viscce[ii][1];
11515           visci[2][2] = viscce[ii][2];
11516           visci[1][0] = viscce[ii][3];
11517           visci[0][1] = viscce[ii][3];
11518           visci[2][1] = viscce[ii][4];
11519           visci[1][2] = viscce[ii][4];
11520           visci[2][0] = viscce[ii][5];
11521           visci[0][2] = viscce[ii][5];
11522 
11523           /* IF.Ki.S / ||Ki.S||^2 */
11524           cs_real_t fikdvi = weighb[face_id];
11525 
11526           /* II" = IF + FI" */
11527           for (int i = 0; i < 3; i++) {
11528             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
11529                       - fikdvi*(  visci[0][i]*b_face_normal[face_id][0]
11530                                 + visci[1][i]*b_face_normal[face_id][1]
11531                                 + visci[2][i]*b_face_normal[face_id][2] );
11532           }
11533 
11534           double pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
11535                                      + grad[ii][1]*diippf[1]
11536                                      + grad[ii][2]*diippf[2]);
11537 
11538 
11539           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pipp;
11540 
11541           b_massflux[face_id] += b_visc[face_id]*pfac;
11542 
11543         }
11544       }
11545     }
11546 
11547     /* Free memory */
11548     BFT_FREE(grad);
11549     BFT_FREE(w2);
11550 
11551   }
11552 }
11553 
11554 /*----------------------------------------------------------------------------*/
11555 /*!
11556  * \brief Update the cell mass flux divergence with the face pressure (or
11557  * pressure increment, or pressure double increment) gradient.
11558  *
11559  * \f[
11560  * \dot{m}_\ij = \dot{m}_\ij
11561  *             - \sum_j \Delta t \grad_\fij p \cdot \vect{S}_\ij
11562  * \f]
11563  *
11564  * \param[in]     f_id          field id (or -1)
11565  * \param[in]     m             pointer to mesh
11566  * \param[in]     fvq           pointer to finite volume quantities
11567  * \param[in]     init          indicator
11568  *                               - 1 initialize the mass flux to 0
11569  *                               - 0 otherwise
11570  * \param[in]     inc           indicator
11571  *                               - 0 when solving an increment
11572  *                               - 1 otherwise
11573  * \param[in]     imrgra        indicator
11574  *                               - 0 iterative gradient
11575  *                               - 1 least squares gradient
11576  * \param[in]     iccocg        indicator
11577  *                               - 1 re-compute cocg matrix
11578  *                                 (for iterative gradients)
11579  *                               - 0 otherwise
11580  * \param[in]     nswrgp        number of reconstruction sweeps for the
11581  *                               gradients
11582  * \param[in]     imligp        clipping gradient method
11583  *                               - < 0 no clipping
11584  *                               - = 0 thank to neighbooring gradients
11585  *                               - = 1 thank to the mean gradient
11586  * \param[in]     iphydp        hydrostatic pressure indicator
11587  * \param[in]     iwarnp        verbosity
11588  * \param[in]     iwgrp         indicator
11589  *                               - 1 weight gradient by vicosity*porosity
11590  *                               - weighting determined by field options
11591  * \param[in]     epsrgp        relative precision for the gradient
11592  *                               reconstruction
11593  * \param[in]     climgp        clipping coeffecient for the computation of
11594  *                               the gradient
11595  * \param[in]     frcxt         body force creating the hydrostatic pressure
11596  * \param[in]     pvar          solved variable (current time step)
11597  * \param[in]     coefap        boundary condition array for the variable
11598  *                               (explicit part)
11599  * \param[in]     coefbp        boundary condition array for the variable
11600  *                               (implicit part)
11601  * \param[in]     cofafp        boundary condition array for the diffusion
11602  *                               of the variable (explicit part)
11603  * \param[in]     cofbfp        boundary condition array for the diffusion
11604  *                               of the variable (implicit part)
11605  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
11606  *                               at interior faces for the r.h.s.
11607  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
11608  *                               at border faces for the r.h.s.
11609  * \param[in]     visel         viscosity by cell
11610  * \param[in,out] diverg        mass flux divergence
11611  */
11612 /*----------------------------------------------------------------------------*/
11613 
11614 void
cs_diffusion_potential(const int f_id,const cs_mesh_t * m,cs_mesh_quantities_t * fvq,int init,int inc,int imrgra,int iccocg,int nswrgp,int imligp,int iphydp,int iwgrp,int iwarnp,double epsrgp,double climgp,cs_real_3_t * restrict frcxt,cs_real_t * restrict pvar,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_t visel[],cs_real_t * restrict diverg)11615 cs_diffusion_potential(const int                 f_id,
11616                        const cs_mesh_t          *m,
11617                        cs_mesh_quantities_t     *fvq,
11618                        int                       init,
11619                        int                       inc,
11620                        int                       imrgra,
11621                        int                       iccocg,
11622                        int                       nswrgp,
11623                        int                       imligp,
11624                        int                       iphydp,
11625                        int                       iwgrp,
11626                        int                       iwarnp,
11627                        double                    epsrgp,
11628                        double                    climgp,
11629                        cs_real_3_t     *restrict frcxt,
11630                        cs_real_t       *restrict pvar,
11631                        const cs_real_t           coefap[],
11632                        const cs_real_t           coefbp[],
11633                        const cs_real_t           cofafp[],
11634                        const cs_real_t           cofbfp[],
11635                        const cs_real_t           i_visc[],
11636                        const cs_real_t           b_visc[],
11637                        cs_real_t                 visel[],
11638                        cs_real_t       *restrict diverg)
11639 {
11640   const cs_halo_t  *halo = m->halo;
11641 
11642   const cs_lnum_t n_cells = m->n_cells;
11643   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
11644   const int n_i_groups = m->i_face_numbering->n_groups;
11645   const int n_i_threads = m->i_face_numbering->n_threads;
11646   const int n_b_groups = m->b_face_numbering->n_groups;
11647   const int n_b_threads = m->b_face_numbering->n_threads;
11648   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
11649   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
11650 
11651   const cs_lnum_2_t *restrict i_face_cells
11652     = (const cs_lnum_2_t *restrict)m->i_face_cells;
11653   const cs_lnum_t *restrict b_face_cells
11654     = (const cs_lnum_t *restrict)m->b_face_cells;
11655   const cs_real_t *restrict i_dist = fvq->i_dist;
11656   const cs_real_t *restrict i_f_face_surf = fvq->i_f_face_surf;
11657   const cs_real_3_t *restrict diipf
11658     = (const cs_real_3_t *restrict)fvq->diipf;
11659   const cs_real_3_t *restrict djjpf
11660     = (const cs_real_3_t *restrict)fvq->djjpf;
11661   const cs_real_3_t *restrict diipb
11662     = (const cs_real_3_t *restrict)fvq->diipb;
11663 
11664   /* Local variables */
11665 
11666   char var_name[64];
11667   int mass_flux_rec_type = cs_glob_velocity_pressure_param->irecmf;
11668   int w_stride = 1;
11669 
11670   bool recompute_cocg = (iccocg) ? true : false;
11671 
11672   cs_real_3_t *grad;
11673   cs_field_t *f;
11674 
11675   cs_real_t *gweight = NULL;
11676 
11677   /*==========================================================================*/
11678 
11679   /*==========================================================================
11680     1. Initialization
11681     ==========================================================================*/
11682 
11683   if (init >= 1) {
11684 #   pragma omp parallel for
11685     for (cs_lnum_t ii = 0; ii < n_cells_ext; ii++) {
11686       diverg[ii] = 0.;
11687     }
11688   } else if (init == 0 && n_cells_ext > n_cells) {
11689 #   pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
11690     for (cs_lnum_t ii = n_cells; ii < n_cells_ext; ii++) {
11691       diverg[ii] = 0.;
11692     }
11693   } else if (init != 0) {
11694     bft_error(__FILE__, __LINE__, 0,
11695               _("invalid value of init"));
11696   }
11697 
11698   /* Use iterative gradient */
11699 
11700   cs_halo_type_t halo_type = CS_HALO_STANDARD;
11701   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
11702 
11703   if (imrgra < 0)
11704     imrgra = 0;
11705 
11706   cs_gradient_type_by_imrgra(imrgra,
11707                              &gradient_type,
11708                              &halo_type);
11709   if (f_id != -1) {
11710     f = cs_field_by_id(f_id);
11711     snprintf(var_name, 63, "%s", f->name);
11712   }
11713   else
11714     strncpy(var_name, "[cell mass flux divergence update]", 63);
11715   var_name[63] = '\0';
11716 
11717   /* Handle parallelism and periodicity */
11718 
11719   if (halo != NULL)
11720     cs_halo_sync_var(halo, halo_type, pvar);
11721 
11722   /*==========================================================================
11723     2. Update mass flux without reconstruction technics
11724     ==========================================================================*/
11725 
11726   if (nswrgp <= 1) {
11727 
11728     /* Mass flow through interior faces */
11729 
11730     for (int g_id = 0; g_id < n_i_groups; g_id++) {
11731 #     pragma omp parallel for
11732       for (int t_id = 0; t_id < n_i_threads; t_id++) {
11733         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
11734              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
11735              face_id++) {
11736 
11737           cs_lnum_t ii = i_face_cells[face_id][0];
11738           cs_lnum_t jj = i_face_cells[face_id][1];
11739 
11740           double i_massflux = i_visc[face_id]*(pvar[ii] - pvar[jj]);
11741           diverg[ii] += i_massflux;
11742           diverg[jj] -= i_massflux;
11743 
11744         }
11745       }
11746     }
11747 
11748     /* Mass flow through boundary faces */
11749 
11750     for (int g_id = 0; g_id < n_b_groups; g_id++) {
11751 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
11752       for (int t_id = 0; t_id < n_b_threads; t_id++) {
11753         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
11754              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
11755              face_id++) {
11756 
11757           cs_lnum_t ii = b_face_cells[face_id];
11758           double pfac = inc*cofafp[face_id] +cofbfp[face_id]*pvar[ii];
11759 
11760           double b_massflux = b_visc[face_id]*pfac;
11761           diverg[ii] += b_massflux;
11762 
11763         }
11764       }
11765     }
11766 
11767   }
11768 
11769   /*==========================================================================
11770     3. Update mass flux with reconstruction if the mesh is non-orthogonal
11771     ==========================================================================*/
11772 
11773   if (nswrgp > 1) {
11774 
11775     /* Allocate a work array for the gradient calculation */
11776     BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
11777 
11778     /* Compute gradient */
11779     if (iwgrp > 0) {
11780       gweight = visel;
11781       if (halo != NULL)
11782         cs_halo_sync_var(halo, halo_type, gweight);
11783     }
11784 
11785     else if (f_id > -1) {
11786       /* Get the calculation option from the field */
11787       int key_cal_opt_id = cs_field_key_id("var_cal_opt");
11788       cs_var_cal_opt_t var_cal_opt;
11789       cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
11790       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
11791         if (var_cal_opt.idiff > 0) {
11792           int key_id = cs_field_key_id("gradient_weighting_id");
11793           int diff_id = cs_field_get_key_int(f, key_id);
11794           if (diff_id > -1) {
11795             cs_field_t *weight_f = cs_field_by_id(diff_id);
11796             gweight = weight_f->val;
11797             w_stride = weight_f->dim;
11798             cs_field_synchronize(weight_f, halo_type);
11799           }
11800         }
11801       }
11802     }
11803 
11804     cs_real_t *_pvar = pvar;
11805 
11806     if (cs_glob_mesh_quantities_flag & CS_BAD_CELLS_REGULARISATION) {
11807       BFT_MALLOC(_pvar, n_cells_ext, cs_real_t);
11808 
11809       for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++)
11810         _pvar[cell_id] = pvar[cell_id];
11811 
11812       cs_bad_cells_regularisation_scalar(_pvar);
11813     }
11814 
11815     cs_gradient_scalar_synced_input(var_name,
11816                                     gradient_type,
11817                                     halo_type,
11818                                     inc,
11819                                     recompute_cocg,
11820                                     nswrgp,
11821                                     iphydp,
11822                                     w_stride,
11823                                     iwarnp,
11824                                     imligp,
11825                                     epsrgp,
11826                                     climgp,
11827                                     frcxt,
11828                                     coefap,
11829                                     coefbp,
11830                                     _pvar,
11831                                     gweight, /* Weighted gradient */
11832                                     NULL, /* internal coupling */
11833                                     grad);
11834 
11835     if (_pvar != pvar)
11836       BFT_FREE(_pvar);
11837 
11838     /* Handle parallelism and periodicity */
11839 
11840     if (halo != NULL)
11841       cs_halo_sync_var(halo, halo_type, visel);
11842 
11843     /* Mass flow through interior faces */
11844 
11845     for (int g_id = 0; g_id < n_i_groups; g_id++) {
11846 #     pragma omp parallel for
11847       for (int t_id = 0; t_id < n_i_threads; t_id++) {
11848         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
11849              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
11850              face_id++) {
11851 
11852           cs_lnum_t ii = i_face_cells[face_id][0];
11853           cs_lnum_t jj = i_face_cells[face_id][1];
11854 
11855           double i_massflux = i_visc[face_id]*(pvar[ii] - pvar[jj]);
11856 
11857           if (mass_flux_rec_type == 0) {
11858 
11859             /*---> Dij = IJ - (IJ.N) N = II' - JJ' */
11860             double dijx = diipf[face_id][0] - djjpf[face_id][0];
11861             double dijy = diipf[face_id][1] - djjpf[face_id][1];
11862             double dijz = diipf[face_id][2] - djjpf[face_id][2];
11863 
11864             double dpxf = 0.5*(  visel[ii]*grad[ii][0]
11865                                + visel[jj]*grad[jj][0]);
11866             double dpyf = 0.5*(  visel[ii]*grad[ii][1]
11867                                + visel[jj]*grad[jj][1]);
11868             double dpzf = 0.5*(  visel[ii]*grad[ii][2]
11869                                + visel[jj]*grad[jj][2]);
11870 
11871             i_massflux += (dpxf*dijx + dpyf*dijy + dpzf*dijz)
11872                           *i_f_face_surf[face_id]/i_dist[face_id];
11873           }
11874           else {
11875             i_massflux += i_visc[face_id]*
11876                           ( cs_math_3_dot_product(grad[ii], diipf[face_id])
11877                           - cs_math_3_dot_product(grad[jj], djjpf[face_id]));
11878           }
11879 
11880           diverg[ii] += i_massflux;
11881           diverg[jj] -= i_massflux;
11882 
11883         }
11884       }
11885     }
11886 
11887     /* Mass flow through boundary faces */
11888 
11889     for (int g_id = 0; g_id < n_b_groups; g_id++) {
11890 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
11891       for (int t_id = 0; t_id < n_b_threads; t_id++) {
11892         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
11893              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
11894              face_id++) {
11895 
11896           cs_lnum_t ii = b_face_cells[face_id];
11897 
11898           double diipbx = diipb[face_id][0];
11899           double diipby = diipb[face_id][1];
11900           double diipbz = diipb[face_id][2];
11901 
11902           double pip = pvar[ii] + grad[ii][0]*diipbx
11903                                 + grad[ii][1]*diipby
11904                                 + grad[ii][2]*diipbz;
11905           double pfac = inc*cofafp[face_id] +cofbfp[face_id]*pip;
11906 
11907           double b_massflux = b_visc[face_id]*pfac;
11908           diverg[ii] += b_massflux;
11909 
11910         }
11911       }
11912     }
11913 
11914     /* Free memory */
11915     BFT_FREE(grad);
11916   }
11917 }
11918 
11919 /*----------------------------------------------------------------------------*/
11920 /*!
11921  * \brief Add the explicit part of the divergence of the mass flux due to the
11922  * pressure gradient (routine analog to diften).
11923  *
11924  * More precisely, the divergence of the mass flux side
11925  * \f$ \sum_{\fij \in \Facei{\celli}} \dot{m}_\fij \f$ is updated as follows:
11926  * \f[
11927  * \sum_{\fij \in \Facei{\celli}} \dot{m}_\fij
11928  *  = \sum_{\fij \in \Facei{\celli}} \dot{m}_\fij
11929  *  - \sum_{\fij \in \Facei{\celli}}
11930  *    \left( \tens{\mu}_\fij \gradv_\fij P \cdot \vect{S}_\ij  \right)
11931  * \f]
11932  *
11933  * \param[in]     f_id          field id (or -1)
11934  * \param[in]     m             pointer to mesh
11935  * \param[in]     fvq           pointer to finite volume quantities
11936  * \param[in]     init           indicator
11937  *                               - 1 initialize the mass flux to 0
11938  *                               - 0 otherwise
11939  * \param[in]     inc           indicator
11940  *                               - 0 when solving an increment
11941  *                               - 1 otherwise
11942  * \param[in]     imrgra        indicator
11943  *                               - 0 iterative gradient
11944  *                               - 1 least squares gradient
11945  * \param[in]     iccocg        indicator
11946  *                               - 1 re-compute cocg matrix
11947                                      (for iterative gradients)
11948  *                               - 0 otherwise
11949  * \param[in]     nswrgp        number of reconstruction sweeps for the
11950  *                               gradients
11951  * \param[in]     imligp        clipping gradient method
11952  *                               - < 0 no clipping
11953  *                               - = 0 thank to neighbooring gradients
11954  *                               - = 1 thank to the mean gradient
11955  * \param[in]     ircflp        indicator
11956  *                               - 1 flux reconstruction,
11957  *                               - 0 otherwise
11958  * \param[in]     iphydp        indicator
11959  *                               - 1 hydrostatic pressure taken into account
11960  *                               - 0 otherwise
11961  * \param[in]     iwgrp         indicator
11962  *                               - 1 weight gradient by vicosity*porosity
11963  *                               - weighting determined by field options
11964  * \param[in]     iwarnp        verbosity
11965  * \param[in]     epsrgp        relative precision for the gradient
11966  *                               reconstruction
11967  * \param[in]     climgp        clipping coeffecient for the computation of
11968  *                               the gradient
11969  * \param[in]     frcxt         body force creating the hydrostatic pressure
11970  * \param[in]     pvar          solved variable (pressure)
11971  * \param[in]     coefap        boundary condition array for the variable
11972  *                               (explicit part)
11973  * \param[in]     coefbp        boundary condition array for the variable
11974  *                               (implicit part)
11975  * \param[in]     cofafp        boundary condition array for the diffusion
11976  *                               of the variable (explicit part)
11977  * \param[in]     cofbfp        boundary condition array for the diffusion
11978  *                               of the variable (implicit part)
11979  * \param[in]     i_visc        \f$ \mu_\fij \dfrac{S_\fij}{\ipf \jpf} \f$
11980  *                               at interior faces for the r.h.s.
11981  * \param[in]     b_visc        \f$ \mu_\fib \dfrac{S_\fib}{\ipf \centf} \f$
11982  *                               at border faces for the r.h.s.
11983  * \param[in]     viscel        symmetric cell tensor \f$ \tens{\mu}_\celli \f$
11984  * \param[in]     weighf        internal face weight between cells i j in case
11985  *                               of tensor diffusion
11986  * \param[in]     weighb        boundary face weight for cells i in case
11987  *                               of tensor diffusion
11988  * \param[in,out] diverg        divergence of the mass flux
11989  */
11990 /*----------------------------------------------------------------------------*/
11991 
11992 void
cs_anisotropic_diffusion_potential(const int f_id,const cs_mesh_t * m,cs_mesh_quantities_t * fvq,int init,int inc,int imrgra,int iccocg,int nswrgp,int imligp,int ircflp,int iphydp,int iwgrp,int iwarnp,double epsrgp,double climgp,cs_real_3_t * restrict frcxt,cs_real_t * restrict pvar,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t cofafp[],const cs_real_t cofbfp[],const cs_real_t i_visc[],const cs_real_t b_visc[],cs_real_6_t * restrict viscel,const cs_real_2_t weighf[],const cs_real_t weighb[],cs_real_t * restrict diverg)11993 cs_anisotropic_diffusion_potential(const int                 f_id,
11994                                    const cs_mesh_t          *m,
11995                                    cs_mesh_quantities_t     *fvq,
11996                                    int                       init,
11997                                    int                       inc,
11998                                    int                       imrgra,
11999                                    int                       iccocg,
12000                                    int                       nswrgp,
12001                                    int                       imligp,
12002                                    int                       ircflp,
12003                                    int                       iphydp,
12004                                    int                       iwgrp,
12005                                    int                       iwarnp,
12006                                    double                    epsrgp,
12007                                    double                    climgp,
12008                                    cs_real_3_t     *restrict frcxt,
12009                                    cs_real_t       *restrict pvar,
12010                                    const cs_real_t           coefap[],
12011                                    const cs_real_t           coefbp[],
12012                                    const cs_real_t           cofafp[],
12013                                    const cs_real_t           cofbfp[],
12014                                    const cs_real_t           i_visc[],
12015                                    const cs_real_t           b_visc[],
12016                                    cs_real_6_t     *restrict viscel,
12017                                    const cs_real_2_t         weighf[],
12018                                    const cs_real_t           weighb[],
12019                                    cs_real_t       *restrict diverg)
12020 {
12021   const cs_halo_t  *halo = m->halo;
12022 
12023   const cs_lnum_t n_cells = m->n_cells;
12024   const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
12025   const int n_i_groups = m->i_face_numbering->n_groups;
12026   const int n_i_threads = m->i_face_numbering->n_threads;
12027   const int n_b_groups = m->b_face_numbering->n_groups;
12028   const int n_b_threads = m->b_face_numbering->n_threads;
12029   const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
12030   const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
12031 
12032   const cs_lnum_2_t *restrict i_face_cells
12033     = (const cs_lnum_2_t *restrict)m->i_face_cells;
12034   const cs_lnum_t *restrict b_face_cells
12035     = (const cs_lnum_t *restrict)m->b_face_cells;
12036   const cs_real_3_t *restrict cell_cen
12037     = (const cs_real_3_t *restrict)fvq->cell_cen;
12038   const cs_real_3_t *restrict i_face_normal
12039     = (const cs_real_3_t *restrict)fvq->i_face_normal;
12040   const cs_real_3_t *restrict b_face_normal
12041     = (const cs_real_3_t *restrict)fvq->b_face_normal;
12042   const cs_real_3_t *restrict i_face_cog
12043     = (const cs_real_3_t *restrict)fvq->i_face_cog;
12044   const cs_real_3_t *restrict b_face_cog
12045     = (const cs_real_3_t *restrict)fvq->b_face_cog;
12046 
12047   /* Local variables */
12048 
12049   cs_real_t *df_limiter = NULL;
12050 
12051   char var_name[64];
12052   int w_stride = 6;
12053 
12054   bool recompute_cocg = (iccocg) ? true : false;
12055 
12056   cs_real_6_t *viscce = NULL;
12057   cs_real_6_t *w2 = NULL;
12058   cs_real_3_t *grad = NULL;
12059   cs_field_t *f = NULL;
12060 
12061   cs_real_t *gweight = NULL;
12062 
12063   /*==========================================================================
12064     1. Initialization
12065     ==========================================================================*/
12066 
12067   if (init >= 1) {
12068 #   pragma omp parallel for
12069     for (cs_lnum_t ii = 0; ii < n_cells_ext; ii++) {
12070       diverg[ii] = 0.;
12071     }
12072   } else if (init == 0 && n_cells_ext > n_cells) {
12073 #   pragma omp parallel for if(n_cells_ext - n_cells > CS_THR_MIN)
12074     for (cs_lnum_t ii = n_cells+0; ii < n_cells_ext; ii++) {
12075       diverg[ii] = 0.;
12076     }
12077   } else if (init != 0) {
12078     bft_error(__FILE__, __LINE__, 0,
12079               _("invalid value of init"));
12080   }
12081 
12082   /* Use iterative gradient */
12083 
12084   cs_halo_type_t halo_type = CS_HALO_STANDARD;
12085   cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
12086 
12087   if (imrgra < 0)
12088     imrgra = 0;
12089 
12090   cs_gradient_type_by_imrgra(imrgra,
12091                              &gradient_type,
12092                              &halo_type);
12093 
12094   if (f_id != -1) {
12095     f = cs_field_by_id(f_id);
12096 
12097     int df_limiter_id
12098       = cs_field_get_key_int(f, cs_field_key_id("diffusion_limiter_id"));
12099     if (df_limiter_id > -1)
12100       df_limiter = cs_field_by_id(df_limiter_id)->val;
12101 
12102 
12103     snprintf(var_name, 63, "%s", f->name);
12104   }
12105   else
12106     strncpy(var_name, "[cell mass flux divergence update]", 63);
12107   var_name[63] = '\0';
12108 
12109   /* Porosity fields */
12110   cs_field_t *fporo = cs_field_by_name_try("porosity");
12111   cs_field_t *ftporo = cs_field_by_name_try("tensorial_porosity");
12112 
12113   cs_real_t *porosi = NULL;
12114   cs_real_6_t *porosf = NULL;
12115 
12116   if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2) {
12117     porosi = fporo->val;
12118     if (ftporo != NULL) {
12119       porosf = (cs_real_6_t *)ftporo->val;
12120     }
12121   }
12122 
12123   /* Handle parallelism and periodicity */
12124 
12125   if (halo != NULL)
12126     cs_halo_sync_var(halo, halo_type, pvar);
12127 
12128   /*==========================================================================
12129     2. Update mass flux without reconstruction technics
12130     ==========================================================================*/
12131 
12132   if (nswrgp <= 1) {
12133 
12134     /* Mass flow through interior faces */
12135 
12136     for (int g_id = 0; g_id < n_i_groups; g_id++) {
12137 #     pragma omp parallel for
12138       for (int t_id = 0; t_id < n_i_threads; t_id++) {
12139         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
12140              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
12141              face_id++) {
12142 
12143           cs_lnum_t ii = i_face_cells[face_id][0];
12144           cs_lnum_t jj = i_face_cells[face_id][1];
12145 
12146           double flux = i_visc[face_id]*(pvar[ii] - pvar[jj]);
12147           diverg[ii] += flux;
12148           diverg[jj] -= flux;
12149 
12150         }
12151       }
12152     }
12153 
12154     /* Mass flow though boundary faces */
12155 
12156     for (int g_id = 0; g_id < n_b_groups; g_id++) {
12157 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
12158       for (int t_id = 0; t_id < n_b_threads; t_id++) {
12159         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
12160              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
12161              face_id++) {
12162 
12163           cs_lnum_t ii = b_face_cells[face_id];
12164           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pvar[ii];
12165 
12166           double flux = b_visc[face_id]*pfac;
12167           diverg[ii] += flux;
12168 
12169         }
12170       }
12171     }
12172 
12173   }
12174 
12175   /*==========================================================================
12176     3. Update mass flux with reconstruction technics
12177     ==========================================================================*/
12178 
12179   if (nswrgp > 1) {
12180 
12181     viscce = NULL;
12182     w2 = NULL;
12183 
12184     /* Without porosity */
12185     if (porosi == NULL) {
12186       viscce = viscel;
12187 
12188       /* With porosity */
12189     } else if (porosi != NULL && porosf == NULL) {
12190       BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
12191       for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
12192         for (int isou = 0; isou < 6; isou++) {
12193           w2[cell_id][isou] = porosi[cell_id]*viscel[cell_id][isou];
12194         }
12195       }
12196       viscce = w2;
12197 
12198       /* With tensorial porosity */
12199     } else if (porosi != NULL && porosf != NULL) {
12200       BFT_MALLOC(w2, n_cells_ext, cs_real_6_t);
12201       for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
12202         cs_math_sym_33_product(porosf[cell_id],
12203                                viscel[cell_id],
12204                                w2[cell_id]);
12205       }
12206       viscce = w2;
12207     }
12208 
12209     /* ---> Periodicity and parallelism treatment of symmetric tensors */
12210 
12211     if (halo != NULL) {
12212       cs_halo_sync_var_strided(halo, CS_HALO_STANDARD, (cs_real_t *)viscce, 6);
12213 
12214       if (m->n_init_perio > 0)
12215         cs_halo_perio_sync_var_sym_tens(halo,
12216                                         CS_HALO_STANDARD,
12217                                         (cs_real_t *)viscce);
12218     }
12219 
12220     /* Allocate a work array for the gradient calculation */
12221     BFT_MALLOC(grad, n_cells_ext, cs_real_3_t);
12222 
12223     /* Compute gradient */
12224     if (iwgrp > 0) {
12225       gweight = (cs_real_t *)viscce;
12226       if (halo != NULL) {
12227         cs_halo_sync_var_strided(halo, halo_type, gweight, 6);
12228         if (cs_glob_mesh->n_init_perio > 0)
12229           cs_halo_perio_sync_var_sym_tens(halo, halo_type, gweight);
12230       }
12231     }
12232 
12233     else if (f_id > -1) {
12234       /* Get the calculation option from the field */
12235       int key_cal_opt_id = cs_field_key_id("var_cal_opt");
12236       cs_var_cal_opt_t var_cal_opt;
12237       cs_field_get_key_struct(f, key_cal_opt_id, &var_cal_opt);
12238       if (f->type & CS_FIELD_VARIABLE && var_cal_opt.iwgrec == 1) {
12239         if (var_cal_opt.idifft > 0) {
12240           int key_id = cs_field_key_id("gradient_weighting_id");
12241           int diff_id = cs_field_get_key_int(f, key_id);
12242           if (diff_id > -1) {
12243             cs_field_t *weight_f = cs_field_by_id(diff_id);
12244             gweight = weight_f->val;
12245             w_stride = weight_f->dim;
12246             cs_field_synchronize(weight_f, halo_type);
12247           }
12248         }
12249       }
12250     }
12251 
12252     /* Compute gradient */
12253     cs_gradient_scalar_synced_input(var_name,
12254                                     gradient_type,
12255                                     halo_type,
12256                                     inc,
12257                                     recompute_cocg,
12258                                     nswrgp,
12259                                     iphydp,
12260                                     w_stride,
12261                                     iwarnp,
12262                                     imligp,
12263                                     epsrgp,
12264                                     climgp,
12265                                     frcxt,
12266                                     coefap,
12267                                     coefbp,
12268                                     pvar,
12269                                     gweight, /* Weighted gradient */
12270                                     NULL, /* internal coupling */
12271                                     grad);
12272 
12273     /* Mass flow through interior faces */
12274 
12275     for (int g_id = 0; g_id < n_i_groups; g_id++) {
12276 #     pragma omp parallel for
12277       for (int t_id = 0; t_id < n_i_threads; t_id++) {
12278         for (cs_lnum_t face_id = i_group_index[(t_id*n_i_groups + g_id)*2];
12279              face_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
12280              face_id++) {
12281 
12282           cs_lnum_t ii = i_face_cells[face_id][0];
12283           cs_lnum_t jj = i_face_cells[face_id][1];
12284 
12285           double pi = pvar[ii];
12286           double pj = pvar[jj];
12287 
12288           cs_real_t bldfrp = (cs_real_t) ircflp;
12289           /* Local limitation of the reconstruction */
12290           if (df_limiter != NULL && ircflp > 0)
12291             bldfrp = CS_MAX(CS_MIN(df_limiter[ii], df_limiter[jj]), 0.);
12292 
12293 
12294           /* Recompute II" and JJ"
12295              ----------------------*/
12296 
12297           cs_real_t visci[3][3], viscj[3][3];
12298 
12299           visci[0][0] = viscce[ii][0];
12300           visci[1][1] = viscce[ii][1];
12301           visci[2][2] = viscce[ii][2];
12302           visci[1][0] = viscce[ii][3];
12303           visci[0][1] = viscce[ii][3];
12304           visci[2][1] = viscce[ii][4];
12305           visci[1][2] = viscce[ii][4];
12306           visci[2][0] = viscce[ii][5];
12307           visci[0][2] = viscce[ii][5];
12308 
12309           /* IF.Ki.S / ||Ki.S||^2 */
12310           cs_real_t fikdvi = weighf[face_id][0];
12311 
12312           /* II" = IF + FI" */
12313 
12314           double diippf[3], djjppf[3];
12315 
12316           for (int i = 0; i < 3; i++) {
12317             diippf[i] = i_face_cog[face_id][i]-cell_cen[ii][i]
12318                       - fikdvi*( visci[0][i]*i_face_normal[face_id][0]
12319                                + visci[1][i]*i_face_normal[face_id][1]
12320                                + visci[2][i]*i_face_normal[face_id][2] );
12321           }
12322 
12323           viscj[0][0] = viscce[jj][0];
12324           viscj[1][1] = viscce[jj][1];
12325           viscj[2][2] = viscce[jj][2];
12326           viscj[1][0] = viscce[jj][3];
12327           viscj[0][1] = viscce[jj][3];
12328           viscj[2][1] = viscce[jj][4];
12329           viscj[1][2] = viscce[jj][4];
12330           viscj[2][0] = viscce[jj][5];
12331           viscj[0][2] = viscce[jj][5];
12332 
12333           /* FJ.Kj.S / ||Kj.S||^2 */
12334           double fjkdvi = weighf[face_id][1];
12335 
12336           /* JJ" = JF + FJ" */
12337           for (int i = 0; i < 3; i++) {
12338             djjppf[i] = i_face_cog[face_id][i]-cell_cen[jj][i]
12339                       + fjkdvi*( viscj[0][i]*i_face_normal[face_id][0]
12340                                + viscj[1][i]*i_face_normal[face_id][1]
12341                                + viscj[2][i]*i_face_normal[face_id][2] );
12342           }
12343 
12344           /* p in I" and J" */
12345           double pipp = pi + bldfrp*( grad[ii][0]*diippf[0]
12346                                     + grad[ii][1]*diippf[1]
12347                                     + grad[ii][2]*diippf[2]);
12348           double pjpp = pj + bldfrp*( grad[jj][0]*djjppf[0]
12349                                     + grad[jj][1]*djjppf[1]
12350                                     + grad[jj][2]*djjppf[2]);
12351 
12352           double flux = i_visc[face_id]*(pipp - pjpp);
12353 
12354           diverg[ii] += flux;
12355           diverg[jj] -= flux;
12356 
12357         }
12358       }
12359     }
12360 
12361     /* Mass flow though boundary faces */
12362 
12363     for (int g_id = 0; g_id < n_b_groups; g_id++) {
12364 #     pragma omp parallel for if(m->n_b_faces > CS_THR_MIN)
12365       for (int t_id = 0; t_id < n_b_threads; t_id++) {
12366         for (cs_lnum_t face_id = b_group_index[(t_id*n_b_groups + g_id)*2];
12367              face_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
12368              face_id++) {
12369 
12370           cs_lnum_t ii = b_face_cells[face_id];
12371 
12372           double pi = pvar[ii];
12373 
12374           cs_real_t bldfrp = (cs_real_t) ircflp;
12375           /* Local limitation of the reconstruction */
12376           if (df_limiter != NULL && ircflp > 0)
12377             bldfrp = CS_MAX(df_limiter[ii], 0.);
12378 
12379           /* Recompute II"
12380              --------------*/
12381 
12382           cs_real_t visci[3][3];
12383 
12384           visci[0][0] = viscce[ii][0];
12385           visci[1][1] = viscce[ii][1];
12386           visci[2][2] = viscce[ii][2];
12387           visci[1][0] = viscce[ii][3];
12388           visci[0][1] = viscce[ii][3];
12389           visci[2][1] = viscce[ii][4];
12390           visci[1][2] = viscce[ii][4];
12391           visci[2][0] = viscce[ii][5];
12392           visci[0][2] = viscce[ii][5];
12393 
12394           /* IF.Ki.S / ||Ki.S||^2 */
12395           double fikdvi = weighb[face_id];
12396 
12397           double diippf[3];
12398 
12399           /* II" = IF + FI" */
12400           for (int i = 0; i < 3; i++) {
12401             diippf[i] = b_face_cog[face_id][i] - cell_cen[ii][i]
12402                       - fikdvi*( visci[0][i]*b_face_normal[face_id][0]
12403                                + visci[1][i]*b_face_normal[face_id][1]
12404                                + visci[2][i]*b_face_normal[face_id][2] );
12405           }
12406 
12407           double pipp = pi + bldfrp*(  grad[ii][0]*diippf[0]
12408                                      + grad[ii][1]*diippf[1]
12409                                      + grad[ii][2]*diippf[2]);
12410 
12411 
12412           double pfac = inc*cofafp[face_id] + cofbfp[face_id]*pipp;
12413 
12414           double flux = b_visc[face_id]*pfac;
12415           diverg[ii] += flux;
12416 
12417         }
12418       }
12419     }
12420 
12421     /* Free memory */
12422     BFT_FREE(grad);
12423     BFT_FREE(w2);
12424 
12425   }
12426 
12427 }
12428 
12429 /*----------------------------------------------------------------------------*/
12430 
12431 END_C_DECLS
12432