1 /*============================================================================
2 * Gradient reconstruction.
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #include "cs_defs.h"
28
29 /*----------------------------------------------------------------------------
30 * Standard C library headers
31 *----------------------------------------------------------------------------*/
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <math.h>
39 #include <float.h>
40
41 #if defined(HAVE_MPI)
42 #include <mpi.h>
43 #endif
44
45 /*----------------------------------------------------------------------------
46 * Local headers
47 *----------------------------------------------------------------------------*/
48
49 #include "bft_error.h"
50 #include "bft_mem.h"
51 #include "bft_printf.h"
52
53 #include "cs_bad_cells_regularisation.h"
54 #include "cs_blas.h"
55 #include "cs_cell_to_vertex.h"
56 #include "cs_ext_neighborhood.h"
57 #include "cs_field.h"
58 #include "cs_field_pointer.h"
59 #include "cs_halo.h"
60 #include "cs_halo_perio.h"
61 #include "cs_internal_coupling.h"
62 #include "cs_log.h"
63 #include "cs_math.h"
64 #include "cs_mesh.h"
65 #include "cs_mesh_adjacencies.h"
66 #include "cs_mesh_quantities.h"
67 #include "cs_parall.h"
68 #include "cs_porous_model.h"
69 #include "cs_prototypes.h"
70 #include "cs_timer.h"
71 #include "cs_timer_stats.h"
72
73 /*----------------------------------------------------------------------------
74 * Header for the current file
75 *----------------------------------------------------------------------------*/
76
77 #include "cs_gradient.h"
78 #include "cs_gradient_priv.h"
79
80 /*----------------------------------------------------------------------------*/
81
82 BEGIN_C_DECLS
83
84 /*=============================================================================
85 * Additional Doxygen documentation
86 *============================================================================*/
87
88 /*!
89 * \file cs_gradient.c
90 * \brief Gradient reconstruction.
91 *
92 * Please refer to the
93 * <a href="../../theory.pdf#gradreco"><b>gradient reconstruction</b></a>
94 * section of the theory guide for more informations.
95 */
96
97 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
98
99 /*=============================================================================
100 * Local macros
101 *============================================================================*/
102
103 /* Cache line multiple, in cs_real_t units */
104
105 #define CS_CL (CS_CL_SIZE/8)
106
107 /*=============================================================================
108 * Local type definitions
109 *============================================================================*/
110
111 /* Structure associated to gradient quantities management */
112
113 typedef struct {
114
115 cs_real_33_t *cocg_it; /* Interleaved cocg matrix
116 for iterative gradients */
117
118 cs_cocg_6_t *cocgb_s_lsq; /* coupling of gradient components for
119 least-square reconstruction at boundary */
120 cs_cocg_6_t *cocg_lsq; /* Interleaved cocg matrix
121 for least square gradients */
122
123 cs_cocg_6_t *cocgb_s_lsq_ext; /* coupling of gradient components for
124 least-square reconstruction at boundary */
125 cs_cocg_6_t *cocg_lsq_ext; /* Interleaved cocg matrix for least
126 squares gradients with ext. neighbors */
127
128 } cs_gradient_quantities_t;
129
130 /* Basic per gradient computation options and logging */
131 /*----------------------------------------------------*/
132
133 typedef struct _cs_gradient_info_t {
134
135 char *name; /* System name */
136 cs_gradient_type_t type; /* Gradient type */
137
138 unsigned n_calls; /* Number of times system solved */
139
140 int n_iter_min; /* Minimum number of iterations */
141 int n_iter_max; /* Minimum number of iterations */
142 unsigned long n_iter_tot; /* Total number of iterations */
143
144 cs_timer_counter_t t_tot; /* Total time used */
145
146 } cs_gradient_info_t;
147
148 /*============================================================================
149 * Global variables
150 *============================================================================*/
151
152 static int cs_glob_gradient_n_systems = 0; /* Current number of systems */
153 static int cs_glob_gradient_n_max_systems = 0; /* Max. number of systems for
154 cs_glob_gradient_systems. */
155
156 /* System info array */
157 static cs_gradient_info_t **cs_glob_gradient_systems = NULL;
158
159 /* Short names for gradient computation types */
160
161 const char *cs_gradient_type_name[]
162 = {N_("Green-Gauss, iterative handling of non-orthogonalities"),
163 N_("Least-squares"),
164 N_("Green-Gauss, least-squares gradient face values"),
165 N_("Green-Gauss, vertex-based face interpolation")};
166
167 /* Timer statistics */
168
169 static cs_timer_counter_t _gradient_t_tot; /* Total time in gradients */
170 static int _gradient_stat_id = -1;
171
172 /* Gradient quantities */
173
174 static int _n_gradient_quantities = 0;
175 static cs_gradient_quantities_t *_gradient_quantities = NULL;
176
177 /*============================================================================
178 * Prototypes for functions intended for use only by Fortran wrappers.
179 * (descriptions follow, with function bodies).
180 *============================================================================*/
181
182 void
183 cs_f_gradient_s(int f_id,
184 int imrgra,
185 int inc,
186 int iccocg,
187 int n_r_sweeps,
188 int iwarnp,
189 int imligp,
190 cs_real_t epsrgp,
191 cs_real_t climgp,
192 const cs_real_t coefap[],
193 const cs_real_t coefbp[],
194 cs_real_t pvar[],
195 cs_real_3_t grad[]);
196
197 void
198 cs_f_gradient_potential(int f_id,
199 int imrgra,
200 int inc,
201 int iccocg,
202 int n_r_sweeps,
203 int iphydp,
204 int iwarnp,
205 int imligp,
206 cs_real_t epsrgp,
207 cs_real_t climgp,
208 cs_real_3_t f_ext[],
209 const cs_real_t coefap[],
210 const cs_real_t coefbp[],
211 cs_real_t pvar[],
212 cs_real_3_t grad[]);
213
214 void
215 cs_f_gradient_weighted_s(int f_id,
216 int imrgra,
217 int inc,
218 int iccocg,
219 int n_r_sweeps,
220 int iphydp,
221 int iwarnp,
222 int imligp,
223 cs_real_t epsrgp,
224 cs_real_t climgp,
225 cs_real_3_t f_ext[],
226 const cs_real_t coefap[],
227 const cs_real_t coefbp[],
228 cs_real_t pvar[],
229 cs_real_t c_weight[],
230 cs_real_3_t grad[]);
231
232 /*============================================================================
233 * Private function definitions
234 *============================================================================*/
235
236 /*----------------------------------------------------------------------------*/
237 /*!
238 * \brief Inverse a 3x3 symmetric matrix (with symmetric storage)
239 * in place, using Cramer's rule
240 *
241 * \param[in, out] a matrix to inverse
242 */
243 /*----------------------------------------------------------------------------*/
244
245 static inline void
_math_6_inv_cramer_sym_in_place(cs_cocg_t a[6])246 _math_6_inv_cramer_sym_in_place(cs_cocg_t a[6])
247 {
248 cs_real_t a00 = a[1]*a[2] - a[4]*a[4];
249 cs_real_t a01 = a[4]*a[5] - a[3]*a[2];
250 cs_real_t a02 = a[3]*a[4] - a[1]*a[5];
251 cs_real_t a11 = a[0]*a[2] - a[5]*a[5];
252 cs_real_t a12 = a[3]*a[5] - a[0]*a[4];
253 cs_real_t a22 = a[0]*a[1] - a[3]*a[3];
254
255 double det_inv = 1. / (a[0]*a00 + a[3]*a01 + a[5]*a02);
256
257 a[0] = a00 * det_inv;
258 a[1] = a11 * det_inv;
259 a[2] = a22 * det_inv;
260 a[3] = a01 * det_inv;
261 a[4] = a12 * det_inv;
262 a[5] = a02 * det_inv;
263 }
264
265 /*----------------------------------------------------------------------------*/
266 /*!
267 * \brief Return a gradient quantities structure, adding one if needed
268 *
269 * \param[in] id id of structure to return
270
271 * \return pointer to gradient quantities structure
272 */
273 /*----------------------------------------------------------------------------*/
274
275 static cs_gradient_quantities_t *
_gradient_quantities_get(int id)276 _gradient_quantities_get(int id)
277 {
278 assert(id >= 0);
279
280 if (id >= _n_gradient_quantities) {
281
282 BFT_REALLOC(_gradient_quantities, id+1, cs_gradient_quantities_t);
283
284 for (int i = _n_gradient_quantities; i < id+1; i++) {
285 cs_gradient_quantities_t *gq = _gradient_quantities + i;
286
287 gq->cocg_it = NULL;
288 gq->cocgb_s_lsq = NULL;
289 gq->cocg_lsq = NULL;
290 gq->cocgb_s_lsq_ext = NULL;
291 gq->cocg_lsq_ext = NULL;
292 }
293
294 _n_gradient_quantities = id+1;
295
296 }
297
298 return _gradient_quantities + id;
299 }
300
301 /*----------------------------------------------------------------------------*/
302 /*!
303 * \brief Destroy mesh quantities structures.
304 */
305 /*----------------------------------------------------------------------------*/
306
307 static void
_gradient_quantities_destroy(void)308 _gradient_quantities_destroy(void)
309 {
310 for (int i = 0; i < _n_gradient_quantities; i++) {
311
312 cs_gradient_quantities_t *gq = _gradient_quantities + i;
313
314 BFT_FREE(gq->cocg_it);
315 BFT_FREE(gq->cocgb_s_lsq);
316 BFT_FREE(gq->cocg_lsq);
317 BFT_FREE(gq->cocgb_s_lsq_ext);
318 BFT_FREE(gq->cocg_lsq_ext);
319
320 }
321
322 BFT_FREE(_gradient_quantities);
323 _n_gradient_quantities = 0;
324 }
325
326 /*----------------------------------------------------------------------------
327 * Factorize dense p*p symmetric matrices.
328 * Only the lower triangular part is stored and the factorization is performed
329 * in place (original coefficients are replaced).
330 * Crout Factorization is performed (A = L D t(L)).
331 *
332 * parameters:
333 * d_size <-- matrix size (p)
334 * ad <--> symmetric matrix to be factorized
335 *----------------------------------------------------------------------------*/
336
337 inline static void
_fact_crout_pp(const int d_size,cs_real_t * ad)338 _fact_crout_pp(const int d_size,
339 cs_real_t *ad)
340 {
341 cs_real_t aux[d_size];
342 for (int kk = 0; kk < d_size - 1; kk++) {
343 int kk_d_size = kk*(kk + 1)/2;
344 for (int ii = kk + 1; ii < d_size; ii++) {
345 int ii_d_size = ii*(ii + 1)/2;
346 aux[ii] = ad[ii_d_size + kk];
347 ad[ii_d_size + kk] = ad[ii_d_size + kk]
348 / ad[kk_d_size + kk];
349 for (int jj = kk + 1; jj < ii + 1; jj++) {
350 ad[ii_d_size + jj] = ad[ii_d_size + jj] - ad[ii_d_size + kk]*aux[jj];
351 }
352 }
353 }
354 }
355
356 /*----------------------------------------------------------------------------
357 * Solve forward and backward linear systems of the form L D t(L) x = b.
358 * Matrix L D t(L) should be given by a Crout factorization.
359 *
360 * parameters:
361 * mat <-- symmetric factorized (Crout) matrix
362 * d_size <-- matrix size (p)
363 * x --> linear system vector solution
364 * b <-- linear system vector right hand side
365 *----------------------------------------------------------------------------*/
366
367 inline static void
_fw_and_bw_ldtl_pp(const cs_real_t mat[],const int d_size,cs_real_t x[],const cs_real_t b[])368 _fw_and_bw_ldtl_pp(const cs_real_t mat[],
369 const int d_size,
370 cs_real_t x[],
371 const cs_real_t b[])
372 {
373 cs_real_t aux[d_size];
374
375 /* forward (stricly lower + identity) */
376 for (int ii = 0; ii < d_size; ii++) {
377 int ii_d_size = ii*(ii + 1)/2;
378 aux[ii] = b[ii];
379 for (int jj = 0; jj < ii; jj++) {
380 aux[ii] -= aux[jj]*mat[ii_d_size + jj];
381 }
382 }
383
384 /* diagonal */
385 for (int ii = 0; ii < d_size; ii++) {
386 int ii_d_size = ii*(ii + 1)/2;
387 aux[ii] /= mat[ii_d_size + ii];
388 }
389
390 /* backward (transposed of strictly lower + identity) */
391 for (int ii = d_size - 1; ii >= 0; ii--) {
392 x[ii] = aux[ii];
393 for (int jj = d_size - 1; jj > ii; jj--) {
394 int jj_d_size = jj*(jj + 1)/2;
395 x[ii] -= x[jj]*mat[jj_d_size + ii];
396 }
397 }
398 }
399
400 /*----------------------------------------------------------------------------
401 * Return pointer to new gradient computation info structure.
402 *
403 * parameters:
404 * name <-- system name
405 * type <-- resolution method
406 *
407 * returns:
408 * pointer to newly created linear system info structure
409 *----------------------------------------------------------------------------*/
410
411 static cs_gradient_info_t *
_gradient_info_create(const char * name,cs_gradient_type_t type)412 _gradient_info_create(const char *name,
413 cs_gradient_type_t type)
414 {
415 cs_gradient_info_t *new_info = NULL;
416
417 BFT_MALLOC(new_info, 1, cs_gradient_info_t);
418 BFT_MALLOC(new_info->name, strlen(name) + 1, char);
419
420 strcpy(new_info->name, name);
421 new_info->type = type;
422
423 new_info->n_calls = 0;
424 new_info->n_iter_min = 0;
425 new_info->n_iter_max = 0;
426 new_info->n_iter_tot = 0;
427
428 CS_TIMER_COUNTER_INIT(new_info->t_tot);
429
430 return new_info;
431 }
432
433 /*----------------------------------------------------------------------------
434 * Destroy gradient computation info structure.
435 *
436 * parameters:
437 * this_info <-> pointer to linear system info structure pointer
438 *----------------------------------------------------------------------------*/
439
440 static void
_gradient_info_destroy(cs_gradient_info_t ** this_info)441 _gradient_info_destroy(cs_gradient_info_t **this_info)
442 {
443 if (*this_info != NULL) {
444 BFT_FREE((*this_info)->name);
445 BFT_FREE(*this_info);
446 }
447 }
448
449 /*----------------------------------------------------------------------------
450 * Update the number of sweeps for gradient information
451 *
452 * parameters:
453 * this_info <-> pointer to linear system info structure
454 * n_iter <-- number of iterations
455 *----------------------------------------------------------------------------*/
456
457 static void
_gradient_info_update_iter(cs_gradient_info_t * this_info,int n_iter)458 _gradient_info_update_iter(cs_gradient_info_t *this_info,
459 int n_iter)
460 {
461 if (n_iter > this_info->n_iter_max) {
462 this_info->n_iter_max = n_iter;
463 /* for first pass: */
464 if (this_info->n_calls == 0)
465 this_info->n_iter_min = n_iter;
466 }
467 else if (n_iter < this_info->n_iter_min)
468 this_info->n_iter_min = n_iter;
469
470 this_info->n_iter_tot += n_iter;
471 }
472
473 /*----------------------------------------------------------------------------
474 * Output information regarding gradient computation.
475 *
476 * parameters:
477 * this_info <-> pointer to linear system info structure
478 *----------------------------------------------------------------------------*/
479
480 static void
_gradient_info_dump(cs_gradient_info_t * this_info)481 _gradient_info_dump(cs_gradient_info_t *this_info)
482 {
483 int n_calls = this_info->n_calls;
484
485 cs_log_printf(CS_LOG_PERFORMANCE,
486 _("\n"
487 "Summary of gradient computations for \"%s\":\n\n"
488 " Reconstruction type: %s\n"
489 " Number of calls: %d\n"),
490 this_info->name, cs_gradient_type_name[this_info->type],
491 n_calls);
492 if (this_info->n_iter_tot > 0)
493 cs_log_printf(CS_LOG_PERFORMANCE,
494 _(" Number of iterations: %d mean, %d min., %d max.\n"),
495 (int)(this_info->n_iter_tot / (unsigned long)n_calls),
496 this_info->n_iter_min,
497 this_info->n_iter_max);
498 cs_log_printf(CS_LOG_PERFORMANCE,
499 _(" Total elapsed time: %.3f\n"),
500 this_info->t_tot.nsec*1e-9);
501 }
502
503 /*----------------------------------------------------------------------------
504 * Return pointer to gradient computation info.
505 *
506 * If this system did not previously exist, it is added to the list of
507 * "known" systems.
508 *
509 * parameters:
510 * name --> system name
511 * type --> resolution method
512 *----------------------------------------------------------------------------*/
513
514 static cs_gradient_info_t *
_find_or_add_system(const char * name,cs_gradient_type_t type)515 _find_or_add_system(const char *name,
516 cs_gradient_type_t type)
517 {
518 int ii, start_id, end_id, mid_id;
519 int cmp_ret = 1;
520
521 /* Use binary search to find system */
522
523 start_id = 0;
524 end_id = cs_glob_gradient_n_systems - 1;
525 mid_id = start_id + ((end_id -start_id) / 2);
526
527 while (start_id <= end_id) {
528 cmp_ret = strcmp((cs_glob_gradient_systems[mid_id])->name, name);
529 if (cmp_ret == 0)
530 cmp_ret = (cs_glob_gradient_systems[mid_id])->type - type;
531 if (cmp_ret < 0)
532 start_id = mid_id + 1;
533 else if (cmp_ret > 0)
534 end_id = mid_id - 1;
535 else
536 break;
537 mid_id = start_id + ((end_id -start_id) / 2);
538 }
539
540 /* If found, return */
541
542 if (cmp_ret == 0)
543 return cs_glob_gradient_systems[mid_id];
544
545 /* Reallocate global array if necessary */
546
547 if (cs_glob_gradient_n_systems >= cs_glob_gradient_n_max_systems) {
548
549 if (cs_glob_gradient_n_max_systems == 0)
550 cs_glob_gradient_n_max_systems = 10;
551 else
552 cs_glob_gradient_n_max_systems *= 2;
553
554 BFT_REALLOC(cs_glob_gradient_systems,
555 cs_glob_gradient_n_max_systems,
556 cs_gradient_info_t *);
557
558 }
559
560 /* Insert in sorted list */
561
562 for (ii = cs_glob_gradient_n_systems; ii > mid_id; ii--)
563 cs_glob_gradient_systems[ii] = cs_glob_gradient_systems[ii - 1];
564
565 cs_glob_gradient_systems[mid_id] = _gradient_info_create(name,
566 type);
567 cs_glob_gradient_n_systems += 1;
568
569 return cs_glob_gradient_systems[mid_id];
570 }
571
572 /*----------------------------------------------------------------------------
573 * Compute L2 norm.
574 *
575 * parameters:
576 * n_elts <-- Local number of elements
577 * x <-- array of 3-vectors
578 *----------------------------------------------------------------------------*/
579
580 static double
_l2_norm_1(cs_lnum_t n_elts,cs_real_t * restrict x)581 _l2_norm_1(cs_lnum_t n_elts,
582 cs_real_t *restrict x)
583 {
584 double s = cs_dot(n_elts, x, x);
585
586 #if defined(HAVE_MPI)
587
588 if (cs_glob_n_ranks > 1) {
589 double _s;
590 MPI_Allreduce(&s, &_s, 1, MPI_DOUBLE, MPI_SUM, cs_glob_mpi_comm);
591 s = _s;
592 }
593
594 #endif /* defined(HAVE_MPI) */
595
596 return (sqrt(s));
597 }
598
599 /*----------------------------------------------------------------------------
600 * Update R.H.S. for lsq gradient taking into account the weight coefficients.
601 *
602 * parameters:
603 * wi <-- Weight coefficient of cell i
604 * wj <-- Weight coefficient of cell j
605 * p_diff <-- R.H.S.
606 * d <-- R.H.S.
607 * a <-- geometric weight J'F/I'J'
608 * resi --> Updated R.H.S. for cell i
609 * resj --> Updated R.H.S. for cell j
610 *----------------------------------------------------------------------------*/
611
612 static inline void
_compute_ani_weighting(const cs_real_t wi[],const cs_real_t wj[],const cs_real_t p_diff,const cs_real_t d[],const cs_real_t a,cs_real_t resi[],cs_real_t resj[])613 _compute_ani_weighting(const cs_real_t wi[],
614 const cs_real_t wj[],
615 const cs_real_t p_diff,
616 const cs_real_t d[],
617 const cs_real_t a,
618 cs_real_t resi[],
619 cs_real_t resj[])
620 {
621 int ii;
622 cs_real_t ki_d[3] = {0., 0., 0.};
623 cs_real_t kj_d[3] = {0., 0., 0.};
624
625 cs_real_6_t sum;
626 cs_real_6_t inv_wi;
627 cs_real_6_t inv_wj;
628 cs_real_t _d[3];
629
630 for (ii = 0; ii < 6; ii++)
631 sum[ii] = a*wi[ii] + (1. - a)*wj[ii];
632
633 cs_math_sym_33_inv_cramer(wi, inv_wi);
634
635 cs_math_sym_33_inv_cramer(wj, inv_wj);
636
637 cs_math_sym_33_3_product(inv_wj, d, _d);
638 cs_math_sym_33_3_product(sum, _d, ki_d);
639 cs_math_sym_33_3_product(inv_wi, d, _d);
640 cs_math_sym_33_3_product(sum, _d, kj_d);
641
642 /* 1 / ||Ki. K_f^-1. IJ||^2 */
643 cs_real_t normi = 1. / cs_math_3_dot_product(ki_d, ki_d);
644 /* 1 / ||Kj. K_f^-1. IJ||^2 */
645 cs_real_t normj = 1. / cs_math_3_dot_product(kj_d, kj_d);
646
647 for (ii = 0; ii < 3; ii++) {
648 resi[ii] += p_diff * ki_d[ii] * normi;
649 resj[ii] += p_diff * kj_d[ii] * normj;
650 }
651 }
652
653 /*----------------------------------------------------------------------------
654 * Compute the inverse of the face viscosity tensor and anisotropic vector
655 * taking into account the weight coefficients to update cocg for lsq gradient.
656 *
657 * parameters:
658 * wi <-- Weight coefficient of cell i
659 * wj <-- Weight coefficient of cell j
660 * d <-- IJ direction
661 * a <-- geometric weight J'F/I'J'
662 * ki_d --> Updated vector for cell i
663 * kj_d --> Updated vector for cell j
664 *----------------------------------------------------------------------------*/
665
666 static inline void
_compute_ani_weighting_cocg(const cs_real_t wi[],const cs_real_t wj[],const cs_real_t d[],const cs_real_t a,cs_real_t ki_d[],cs_real_t kj_d[])667 _compute_ani_weighting_cocg(const cs_real_t wi[],
668 const cs_real_t wj[],
669 const cs_real_t d[],
670 const cs_real_t a,
671 cs_real_t ki_d[],
672 cs_real_t kj_d[])
673 {
674 int ii;
675 cs_real_6_t sum;
676 cs_real_6_t inv_wi;
677 cs_real_6_t inv_wj;
678 cs_real_t _d[3];
679
680 for (ii = 0; ii < 6; ii++)
681 sum[ii] = a*wi[ii] + (1. - a)*wj[ii];
682
683 cs_math_sym_33_inv_cramer(wi,
684 inv_wi);
685 cs_math_sym_33_inv_cramer(wj,
686 inv_wj);
687
688 /* Note: K_i.K_f^-1 = SUM.K_j^-1
689 * K_j.K_f^-1 = SUM.K_i^-1
690 * So: K_i d = SUM.K_j^-1.IJ */
691
692 cs_math_sym_33_3_product(inv_wj,
693 d,
694 _d);
695 cs_math_sym_33_3_product(sum,
696 _d,
697 ki_d);
698 cs_math_sym_33_3_product(inv_wi,
699 d,
700 _d);
701 cs_math_sym_33_3_product(sum,
702 _d,
703 kj_d);
704 }
705
706 /*----------------------------------------------------------------------------
707 * Synchronize halos for scalar gradients.
708 *
709 * parameters:
710 * m <-- pointer to associated mesh structure
711 * halo_type <-- halo type (extended or not)
712 * grad <-> gradient of pvar (halo prepared for periodicity
713 * of rotation)
714 *----------------------------------------------------------------------------*/
715
716 static void
_sync_scalar_gradient_halo(const cs_mesh_t * m,cs_halo_type_t halo_type,cs_real_3_t grad[])717 _sync_scalar_gradient_halo(const cs_mesh_t *m,
718 cs_halo_type_t halo_type,
719 cs_real_3_t grad[])
720 {
721 if (m->halo != NULL) {
722 cs_halo_sync_var_strided
723 (m->halo, halo_type, (cs_real_t *)grad, 3);
724 if (m->have_rotation_perio)
725 cs_halo_perio_sync_var_vect
726 (m->halo, halo_type, (cs_real_t *)grad, 3);
727 }
728 }
729
730 /*----------------------------------------------------------------------------
731 * Clip the gradient of a scalar if necessary. This function deals with
732 * the standard or extended neighborhood.
733 *
734 * parameters:
735 * halo_type <-- halo type (extended or not)
736 * clip_mode <-- type of clipping for the computation of the gradient
737 * iwarnp <-- output level
738 * climgp <-- clipping coefficient for the computation of the gradient
739 * var <-- variable
740 * grad --> components of the pressure gradient
741 *----------------------------------------------------------------------------*/
742
743 static void
_scalar_gradient_clipping(cs_halo_type_t halo_type,cs_gradient_limit_t clip_mode,int verbosity,cs_real_t climgp,const char * var_name,const cs_real_t var[],cs_real_3_t * restrict grad)744 _scalar_gradient_clipping(cs_halo_type_t halo_type,
745 cs_gradient_limit_t clip_mode,
746 int verbosity,
747 cs_real_t climgp,
748 const char *var_name,
749 const cs_real_t var[],
750 cs_real_3_t *restrict grad)
751 {
752 cs_real_t global_min_factor, global_max_factor;
753
754 cs_real_t min_factor = 1, max_factor = 0;
755 cs_gnum_t n_clip = 0, n_g_clip = 0;
756 cs_real_t *buf = NULL, *restrict clip_factor = NULL;
757 cs_real_t *restrict denom = NULL, *restrict denum = NULL;
758
759 const cs_mesh_t *mesh = cs_glob_mesh;
760 const int n_i_groups = mesh->i_face_numbering->n_groups;
761 const int n_i_threads = mesh->i_face_numbering->n_threads;
762 const cs_lnum_t *restrict i_group_index = mesh->i_face_numbering->group_index;
763 const cs_lnum_t n_cells = mesh->n_cells;
764 const cs_lnum_t n_cells_ext = mesh->n_cells_with_ghosts;
765 const cs_lnum_t *cell_cells_idx = mesh->cell_cells_idx;
766 const cs_lnum_t *cell_cells_lst = mesh->cell_cells_lst;
767 const cs_real_3_t *restrict cell_cen
768 = (const cs_real_3_t *restrict)cs_glob_mesh_quantities->cell_cen;
769 const cs_lnum_2_t *restrict i_face_cells
770 = (const cs_lnum_2_t *restrict)mesh->i_face_cells;
771
772 const cs_halo_t *halo = mesh->halo;
773
774 if (clip_mode <= CS_GRADIENT_LIMIT_NONE)
775 return;
776
777 /* Synchronize variable */
778
779 if (halo != NULL) {
780
781 /* Exchange for the gradients. Not useful for working array */
782
783 if (clip_mode == CS_GRADIENT_LIMIT_FACE) {
784
785 cs_halo_sync_var_strided(halo,
786 halo_type,
787 (cs_real_t *restrict)grad,
788 3);
789 cs_halo_perio_sync_var_vect(halo,
790 halo_type,
791 (cs_real_t *restrict)grad,
792 3);
793 }
794
795 } /* End if halo */
796
797 /* Allocate and initialize working buffers */
798
799 if (clip_mode == CS_GRADIENT_LIMIT_FACE)
800 BFT_MALLOC(buf, 3*n_cells_ext, cs_real_t);
801 else
802 BFT_MALLOC(buf, 2*n_cells_ext, cs_real_t);
803
804 denum = buf;
805 denom = buf + n_cells_ext;
806
807 if (clip_mode == CS_GRADIENT_LIMIT_FACE)
808 clip_factor = buf + 2*n_cells_ext;
809
810 # pragma omp parallel for
811 for (cs_lnum_t ii = 0; ii < n_cells_ext; ii++) {
812 denum[ii] = 0;
813 denom[ii] = 0;
814 }
815
816 /* First computations:
817 denum holds the maximum variation of the gradient
818 denom holds the maximum variation of the variable */
819
820 if (clip_mode == CS_GRADIENT_LIMIT_CELL) {
821
822 for (int g_id = 0; g_id < n_i_groups; g_id++) {
823 # pragma omp parallel for
824 for (int t_id = 0; t_id < n_i_threads; t_id++) {
825 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
826 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
827 f_id++) {
828
829 cs_lnum_t ii = i_face_cells[f_id][0];
830 cs_lnum_t jj = i_face_cells[f_id][1];
831
832 cs_real_t dist[3];
833 for (cs_lnum_t ll = 0; ll < 3; ll++)
834 dist[ll] = cell_cen[ii][ll] - cell_cen[jj][ll];
835
836 cs_real_t dist1 = CS_ABS( dist[0]*grad[ii][0]
837 + dist[1]*grad[ii][1]
838 + dist[2]*grad[ii][2]);
839 cs_real_t dist2 = CS_ABS( dist[0]*grad[jj][0]
840 + dist[1]*grad[jj][1]
841 + dist[2]*grad[jj][2]);
842
843 cs_real_t dvar = CS_ABS(var[ii] - var[jj]);
844
845 denum[ii] = CS_MAX(denum[ii], dist1);
846 denum[jj] = CS_MAX(denum[jj], dist2);
847 denom[ii] = CS_MAX(denom[ii], dvar);
848 denom[jj] = CS_MAX(denom[jj], dvar);
849
850 } /* End of loop on faces */
851
852 } /* End of loop on threads */
853
854 } /* End of loop on thread groups */
855
856 /* Complement for extended neighborhood */
857
858 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
859
860 # pragma omp parallel for
861 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
862 for (cs_lnum_t cidx = cell_cells_idx[ii];
863 cidx < cell_cells_idx[ii+1];
864 cidx++) {
865
866 cs_lnum_t jj = cell_cells_lst[cidx];
867
868 cs_real_t dist[3];
869 for (cs_lnum_t ll = 0; ll < 3; ll++)
870 dist[ll] = cell_cen[ii][ll] - cell_cen[jj][ll];
871
872 cs_real_t dist1 = CS_ABS( dist[0]*grad[ii][0]
873 + dist[1]*grad[ii][1]
874 + dist[2]*grad[ii][2]);
875 cs_real_t dvar = CS_ABS(var[ii] - var[jj]);
876
877 denum[ii] = CS_MAX(denum[ii], dist1);
878 denom[ii] = CS_MAX(denom[ii], dvar);
879
880 }
881 }
882
883 } /* End for extended halo */
884
885 }
886 else if (clip_mode == CS_GRADIENT_LIMIT_FACE) {
887
888 for (int g_id = 0; g_id < n_i_groups; g_id++) {
889 # pragma omp parallel for
890 for (int t_id = 0; t_id < n_i_threads; t_id++) {
891 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
892 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
893 f_id++) {
894
895 cs_lnum_t ii = i_face_cells[f_id][0];
896 cs_lnum_t jj = i_face_cells[f_id][1];
897
898 cs_real_t dist[3];
899 for (cs_lnum_t ll = 0; ll < 3; ll++)
900 dist[ll] = cell_cen[ii][ll] - cell_cen[jj][ll];
901
902 cs_real_t dpdxf = 0.5 * (grad[ii][0] + grad[jj][0]);
903 cs_real_t dpdyf = 0.5 * (grad[ii][1] + grad[jj][1]);
904 cs_real_t dpdzf = 0.5 * (grad[ii][2] + grad[jj][2]);
905
906 cs_real_t dist1 = CS_ABS( dist[0]*dpdxf
907 + dist[1]*dpdyf
908 + dist[2]*dpdzf);
909 cs_real_t dvar = CS_ABS(var[ii] - var[jj]);
910
911 denum[ii] = CS_MAX(denum[ii], dist1);
912 denum[jj] = CS_MAX(denum[jj], dist1);
913 denom[ii] = CS_MAX(denom[ii], dvar);
914 denom[jj] = CS_MAX(denom[jj], dvar);
915
916 } /* End of loop on faces */
917
918 } /* End of loop on threads */
919
920 } /* End of loop on thread groups */
921
922 /* Complement for extended neighborhood */
923
924 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
925
926 # pragma omp parallel for
927 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
928 for (cs_lnum_t cidx = cell_cells_idx[ii];
929 cidx < cell_cells_idx[ii+1];
930 cidx++) {
931
932 cs_lnum_t jj = cell_cells_lst[cidx];
933
934 cs_real_t dist[3];
935 for (cs_lnum_t ll = 0; ll < 3; ll++)
936 dist[ll] = cell_cen[ii][ll] - cell_cen[jj][ll];
937
938 cs_real_t dpdxf = 0.5 * (grad[ii][0] + grad[jj][0]);
939 cs_real_t dpdyf = 0.5 * (grad[ii][1] + grad[jj][1]);
940 cs_real_t dpdzf = 0.5 * (grad[ii][2] + grad[jj][2]);
941
942 cs_real_t dist1 = CS_ABS( dist[0]*dpdxf
943 + dist[1]*dpdyf
944 + dist[2]*dpdzf);
945 cs_real_t dvar = CS_ABS(var[ii] - var[jj]);
946
947 denum[ii] = CS_MAX(denum[ii], dist1);
948 denom[ii] = CS_MAX(denom[ii], dvar);
949
950 }
951 }
952
953 } /* End for extended neighborhood */
954
955 } /* End if clip_mode == CS_GRADIENT_LIMIT_FACE */
956
957 /* Clipping of the gradient if denum/denom > climgp */
958
959 if (clip_mode == CS_GRADIENT_LIMIT_CELL) {
960
961 # pragma omp parallel
962 {
963 cs_gnum_t t_n_clip = 0;
964 cs_real_t t_min_factor = min_factor;
965 cs_real_t t_max_factor = max_factor;
966
967 # pragma omp for
968 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
969
970 if (denum[ii] > climgp * denom[ii]) {
971
972 cs_real_t factor1 = climgp * denom[ii]/denum[ii];
973 grad[ii][0] *= factor1;
974 grad[ii][1] *= factor1;
975 grad[ii][2] *= factor1;
976
977 t_min_factor = CS_MIN(factor1, t_min_factor);
978 t_max_factor = CS_MAX(factor1, t_max_factor);
979 t_n_clip++;
980
981 } /* If clipping */
982
983 } /* End of loop on cells */
984
985 # pragma omp critical
986 {
987 min_factor = CS_MIN(min_factor, t_min_factor);
988 max_factor = CS_MAX(max_factor, t_max_factor);
989 n_clip += t_n_clip;
990 }
991 } /* End of omp parallel construct */
992
993 }
994 else if (clip_mode == CS_GRADIENT_LIMIT_FACE) {
995
996 # pragma omp parallel for
997 for (cs_lnum_t ii = 0; ii < n_cells_ext; ii++)
998 clip_factor[ii] = (cs_real_t)DBL_MAX;
999
1000 /* Synchronize variable */
1001
1002 if (halo != NULL) {
1003 cs_halo_sync_var(halo, halo_type, denom);
1004 cs_halo_sync_var(halo, halo_type, denum);
1005 }
1006
1007 for (int g_id = 0; g_id < n_i_groups; g_id++) {
1008
1009 # pragma omp parallel for
1010 for (int t_id = 0; t_id < n_i_threads; t_id++) {
1011
1012 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1013 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1014 f_id++) {
1015
1016 cs_lnum_t ii = i_face_cells[f_id][0];
1017 cs_lnum_t jj = i_face_cells[f_id][1];
1018
1019 cs_real_t factor1 = 1.0;
1020 if (denum[ii] > climgp * denom[ii])
1021 factor1 = climgp * denom[ii]/denum[ii];
1022
1023 cs_real_t factor2 = 1.0;
1024 if (denum[jj] > climgp * denom[jj])
1025 factor2 = climgp * denom[jj]/denum[jj];
1026
1027 cs_real_t l_min_factor = CS_MIN(factor1, factor2);
1028
1029 clip_factor[ii] = CS_MIN(clip_factor[ii], l_min_factor);
1030 clip_factor[jj] = CS_MIN(clip_factor[jj], l_min_factor);
1031
1032 } /* End of loop on faces */
1033
1034 } /* End of loop on threads */
1035
1036 } /* End of loop on thread groups */
1037
1038 /* Complement for extended neighborhood */
1039
1040 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
1041
1042 # pragma omp parallel for
1043 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
1044
1045 cs_real_t factor1 = 1.0;
1046
1047 for (cs_lnum_t cidx = cell_cells_idx[ii];
1048 cidx < cell_cells_idx[ii+1];
1049 cidx++) {
1050
1051 cs_lnum_t jj = cell_cells_lst[cidx];
1052
1053 cs_real_t factor2 = 1.0;
1054
1055 if (denum[jj] > climgp * denom[jj])
1056 factor2 = climgp * denom[jj]/denum[jj];
1057
1058 factor1 = CS_MIN(factor1, factor2);
1059
1060 }
1061
1062 clip_factor[ii] = CS_MIN(clip_factor[ii], factor1);
1063
1064 } /* End of loop on cells */
1065
1066 } /* End for extended neighborhood */
1067
1068 # pragma omp parallel
1069 {
1070 cs_gnum_t t_n_clip = 0;
1071 cs_real_t t_min_factor = min_factor, t_max_factor = max_factor;
1072
1073 # pragma omp for
1074 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
1075
1076 for (cs_lnum_t ll = 0; ll < 3; ll++)
1077 grad[ii][ll] *= clip_factor[ii];
1078
1079 if (clip_factor[ii] < 0.99) {
1080 t_max_factor = CS_MAX(t_max_factor, clip_factor[ii]);
1081 t_min_factor = CS_MIN(t_min_factor, clip_factor[ii]);
1082 t_n_clip++;
1083 }
1084
1085 } /* End of loop on cells */
1086
1087 # pragma omp critical
1088 {
1089 min_factor = CS_MIN(min_factor, t_min_factor);
1090 max_factor = CS_MAX(max_factor, t_max_factor);
1091 n_clip += t_n_clip;
1092 }
1093 } /* End of omp parallel construct */
1094
1095 } /* End if clip_mode == CS_GRADIENT_LIMIT_FACE */
1096
1097 /* Update min/max and n_clip in case of parallelism */
1098
1099 #if defined(HAVE_MPI)
1100
1101 if (mesh->n_domains > 1) {
1102
1103 assert(sizeof(cs_real_t) == sizeof(double));
1104
1105 /* Global Max */
1106
1107 MPI_Allreduce(&max_factor, &global_max_factor, 1, CS_MPI_REAL,
1108 MPI_MAX, cs_glob_mpi_comm);
1109
1110 max_factor = global_max_factor;
1111
1112 /* Global min */
1113
1114 MPI_Allreduce(&min_factor, &global_min_factor, 1, CS_MPI_REAL,
1115 MPI_MIN, cs_glob_mpi_comm);
1116
1117 min_factor = global_min_factor;
1118
1119 /* Sum number of clippings */
1120
1121 MPI_Allreduce(&n_clip, &n_g_clip, 1, CS_MPI_GNUM,
1122 MPI_SUM, cs_glob_mpi_comm);
1123
1124 n_clip = n_g_clip;
1125
1126 } /* If n_domains > 1 */
1127
1128 #endif /* defined(HAVE_MPI) */
1129
1130 /* Output warning if necessary */
1131
1132 if (verbosity > 1)
1133 bft_printf(_(" Variable: %s; Gradient limitation in %llu cells\n"
1134 " minimum factor = %14.5e; maximum factor = %14.5e\n"),
1135 var_name, (unsigned long long)n_clip, min_factor, max_factor);
1136
1137 /* Synchronize grad */
1138
1139 if (halo != NULL) {
1140
1141 cs_halo_sync_var_strided(halo,
1142 halo_type,
1143 (cs_real_t *restrict)grad,
1144 3);
1145
1146 cs_halo_perio_sync_var_vect(halo,
1147 halo_type,
1148 (cs_real_t *restrict)grad,
1149 3);
1150
1151 }
1152
1153 BFT_FREE(buf);
1154 }
1155
1156 /*----------------------------------------------------------------------------
1157 * Initialize gradient and right-hand side for scalar gradient reconstruction.
1158 *
1159 * A non-reconstructed gradient is computed at this stage.
1160 *
1161 * Optionally, a volume force generating a hydrostatic pressure component
1162 * may be accounted for.
1163 *
1164 * parameters:
1165 * m <-- pointer to associated mesh structure
1166 * fvq <-- pointer to associated finite volume quantities
1167 * cpl <-- structure associated with internal coupling, or NULL
1168 * hyd_p_flag <-- flag for hydrostatic pressure
1169 * inc <-- if 0, solve on increment; 1 otherwise
1170 * f_ext <-- exterior force generating pressure
1171 * coefap <-- B.C. coefficients for boundary face normals
1172 * coefbp <-- B.C. coefficients for boundary face normals
1173 * pvar <-- variable
1174 * c_weight <-- weighted gradient coefficient variable
1175 * grad <-> gradient of pvar (halo prepared for periodicity
1176 * of rotation)
1177 *----------------------------------------------------------------------------*/
1178
1179 static void
_initialize_scalar_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,int hyd_p_flag,cs_real_t inc,const cs_real_3_t f_ext[],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t pvar[],const cs_real_t c_weight[],cs_real_3_t * restrict grad)1180 _initialize_scalar_gradient(const cs_mesh_t *m,
1181 const cs_mesh_quantities_t *fvq,
1182 const cs_internal_coupling_t *cpl,
1183 int hyd_p_flag,
1184 cs_real_t inc,
1185 const cs_real_3_t f_ext[],
1186 const cs_real_t coefap[],
1187 const cs_real_t coefbp[],
1188 const cs_real_t pvar[],
1189 const cs_real_t c_weight[],
1190 cs_real_3_t *restrict grad)
1191 {
1192 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
1193 const cs_lnum_t n_cells = m->n_cells;
1194 const int n_i_groups = m->i_face_numbering->n_groups;
1195 const int n_i_threads = m->i_face_numbering->n_threads;
1196 const int n_b_groups = m->b_face_numbering->n_groups;
1197 const int n_b_threads = m->b_face_numbering->n_threads;
1198 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1199 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1200
1201 const cs_lnum_2_t *restrict i_face_cells
1202 = (const cs_lnum_2_t *restrict)m->i_face_cells;
1203 const cs_lnum_t *restrict b_face_cells
1204 = (const cs_lnum_t *restrict)m->b_face_cells;
1205
1206 const int *restrict c_disable_flag = fvq->c_disable_flag;
1207 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
1208
1209 const cs_real_t *restrict weight = fvq->weight;
1210 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
1211 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
1212 cell_f_vol = fvq->cell_vol;
1213 const cs_real_3_t *restrict cell_cen
1214 = (const cs_real_3_t *restrict)fvq->cell_cen;
1215 const cs_real_3_t *restrict i_f_face_normal
1216 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
1217 const cs_real_3_t *restrict b_f_face_normal
1218 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
1219 const cs_real_3_t *restrict i_face_cog
1220 = (const cs_real_3_t *restrict)fvq->i_face_cog;
1221 const cs_real_3_t *restrict b_face_cog
1222 = (const cs_real_3_t *restrict)fvq->b_face_cog;
1223
1224 bool *coupled_faces = (cpl == NULL) ?
1225 NULL : (bool *)cpl->coupled_faces;
1226
1227 /*Additional terms due to porosity */
1228 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
1229
1230 cs_real_t *i_poro_duq_0;
1231 cs_real_t *i_poro_duq_1;
1232 cs_real_t *b_poro_duq;
1233 cs_real_t _f_ext = 0.;
1234
1235 cs_lnum_t is_porous = 0;
1236 if (f_i_poro_duq_0 != NULL) {
1237 is_porous = 1;
1238 i_poro_duq_0 = f_i_poro_duq_0->val;
1239 i_poro_duq_1 = cs_field_by_name("i_poro_duq_1")->val;
1240 b_poro_duq = cs_field_by_name("b_poro_duq")->val;
1241 } else {
1242 i_poro_duq_0 = &_f_ext;
1243 i_poro_duq_1 = &_f_ext;
1244 b_poro_duq = &_f_ext;
1245 }
1246
1247 /* Initialize gradient */
1248 /*---------------------*/
1249
1250 # pragma omp parallel for
1251 for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
1252 for (cs_lnum_t j = 0; j < 3; j++)
1253 grad[cell_id][j] = 0.0;
1254 }
1255
1256 /* Case with hydrostatic pressure */
1257 /*--------------------------------*/
1258
1259 if (hyd_p_flag == 1) {
1260
1261 /* Contribution from interior faces */
1262
1263 for (int g_id = 0; g_id < n_i_groups; g_id++) {
1264
1265 # pragma omp parallel for
1266 for (int t_id = 0; t_id < n_i_threads; t_id++) {
1267
1268 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1269 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1270 f_id++) {
1271
1272 cs_lnum_t ii = i_face_cells[f_id][0];
1273 cs_lnum_t jj = i_face_cells[f_id][1];
1274
1275 cs_real_t ktpond = (c_weight == NULL) ?
1276 weight[f_id] : /* no cell weighting */
1277 weight[f_id] * c_weight[ii] /* cell weighting active */
1278 / ( weight[f_id] * c_weight[ii]
1279 + (1.0-weight[f_id])* c_weight[jj]);
1280
1281 cs_real_2_t poro = {
1282 i_poro_duq_0[is_porous*f_id],
1283 i_poro_duq_1[is_porous*f_id]
1284 };
1285
1286 /*
1287 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
1288 + (1-\alpha_\ij) \varia_\cellj\f$
1289 but for the cell \f$ \celli \f$ we remove
1290 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1291 and for the cell \f$ \cellj \f$ we remove
1292 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
1293 */
1294
1295 /* Reconstruction part */
1296 cs_real_t pfaci
1297 = ktpond
1298 * ( (i_face_cog[f_id][0] - cell_cen[ii][0])*f_ext[ii][0]
1299 + (i_face_cog[f_id][1] - cell_cen[ii][1])*f_ext[ii][1]
1300 + (i_face_cog[f_id][2] - cell_cen[ii][2])*f_ext[ii][2]
1301 + poro[0])
1302 + (1.0 - ktpond)
1303 * ( (i_face_cog[f_id][0] - cell_cen[jj][0])*f_ext[jj][0]
1304 + (i_face_cog[f_id][1] - cell_cen[jj][1])*f_ext[jj][1]
1305 + (i_face_cog[f_id][2] - cell_cen[jj][2])*f_ext[jj][2]
1306 + poro[1]);
1307
1308 cs_real_t pfacj = pfaci;
1309
1310 pfaci += (1.0-ktpond) * (pvar[jj] - pvar[ii]);
1311 pfacj -= ktpond * (pvar[jj] - pvar[ii]);
1312
1313 for (cs_lnum_t j = 0; j < 3; j++) {
1314 grad[ii][j] += pfaci * i_f_face_normal[f_id][j];
1315 grad[jj][j] -= pfacj * i_f_face_normal[f_id][j];
1316 }
1317
1318 } /* loop on faces */
1319
1320 } /* loop on threads */
1321
1322 } /* loop on thread groups */
1323
1324 /* Contribution from boundary faces */
1325
1326 for (int g_id = 0; g_id < n_b_groups; g_id++) {
1327
1328 # pragma omp parallel for
1329 for (int t_id = 0; t_id < n_b_threads; t_id++) {
1330
1331 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1332 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1333 f_id++) {
1334
1335 cs_lnum_t ii = b_face_cells[f_id];
1336
1337 cs_real_t poro = b_poro_duq[is_porous*f_id];
1338
1339 /*
1340 Remark: for the cell \f$ \celli \f$ we remove
1341 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1342 */
1343
1344 /* Reconstruction part */
1345 cs_real_t pfac
1346 = coefap[f_id] * inc
1347 + coefbp[f_id]
1348 * ( (b_face_cog[f_id][0] - cell_cen[ii][0])*f_ext[ii][0]
1349 + (b_face_cog[f_id][1] - cell_cen[ii][1])*f_ext[ii][1]
1350 + (b_face_cog[f_id][2] - cell_cen[ii][2])*f_ext[ii][2]
1351 + poro);
1352
1353 pfac += (coefbp[f_id] - 1.0) * pvar[ii];
1354
1355 for (cs_lnum_t j = 0; j < 3; j++)
1356 grad[ii][j] += pfac * b_f_face_normal[f_id][j];
1357
1358 } /* loop on faces */
1359
1360 } /* loop on threads */
1361
1362 } /* loop on thread groups */
1363
1364 } /* End of test on hydrostatic pressure */
1365
1366 /* Standard case, without hydrostatic pressure */
1367 /*---------------------------------------------*/
1368
1369 else {
1370
1371 /* Contribution from interior faces */
1372
1373 for (int g_id = 0; g_id < n_i_groups; g_id++) {
1374
1375 # pragma omp parallel for
1376 for (int t_id = 0; t_id < n_i_threads; t_id++) {
1377
1378 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1379 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1380 f_id++) {
1381
1382 cs_lnum_t ii = i_face_cells[f_id][0];
1383 cs_lnum_t jj = i_face_cells[f_id][1];
1384
1385 cs_real_t ktpond = (c_weight == NULL) ?
1386 weight[f_id] : /* no cell weighting */
1387 weight[f_id] * c_weight[ii] /* cell weighting active */
1388 / ( weight[f_id] * c_weight[ii]
1389 + (1.0-weight[f_id])* c_weight[jj]);
1390
1391 /*
1392 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
1393 + (1-\alpha_\ij) \varia_\cellj\f$
1394 but for the cell \f$ \celli \f$ we remove
1395 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1396 and for the cell \f$ \cellj \f$ we remove
1397 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
1398 */
1399 cs_real_t pfaci = (1.0-ktpond) * (pvar[jj] - pvar[ii]);
1400 cs_real_t pfacj = -ktpond * (pvar[jj] - pvar[ii]);
1401
1402 for (cs_lnum_t j = 0; j < 3; j++) {
1403 grad[ii][j] += pfaci * i_f_face_normal[f_id][j];
1404 grad[jj][j] -= pfacj * i_f_face_normal[f_id][j];
1405 }
1406
1407 } /* loop on faces */
1408
1409 } /* loop on threads */
1410
1411 } /* loop on thread groups */
1412
1413 /* Contribution from coupled faces */
1414 if (cpl != NULL)
1415 cs_internal_coupling_initialize_scalar_gradient
1416 (cpl, c_weight, pvar, grad);
1417
1418 /* Contribution from boundary faces */
1419
1420 for (int g_id = 0; g_id < n_b_groups; g_id++) {
1421
1422 # pragma omp parallel for
1423 for (int t_id = 0; t_id < n_b_threads; t_id++) {
1424
1425 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1426 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1427 f_id++) {
1428
1429 if (cpl == NULL || !coupled_faces[f_id]) {
1430
1431 cs_lnum_t ii = b_face_cells[f_id];
1432
1433 /*
1434 Remark: for the cell \f$ \celli \f$ we remove
1435 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1436 */
1437
1438 cs_real_t pfac = inc*coefap[f_id]
1439 + (coefbp[f_id]-1.0)*pvar[ii];
1440
1441 for (cs_lnum_t j = 0; j < 3; j++)
1442 grad[ii][j] += pfac * b_f_face_normal[f_id][j];
1443
1444 } /* face without internal coupling */
1445
1446 } /* loop on faces */
1447
1448 } /* loop on threads */
1449
1450 } /* loop on thread groups */
1451
1452 }
1453
1454 # pragma omp parallel for
1455 for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++) {
1456 cs_real_t dvol;
1457 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
1458 if (has_dc * c_disable_flag[has_dc * cell_id] == 0)
1459 dvol = 1. / cell_f_vol[cell_id];
1460 else
1461 dvol = 0.;
1462
1463 for (cs_lnum_t j = 0; j < 3; j++)
1464 grad[cell_id][j] *= dvol;
1465 }
1466
1467 /* Synchronize halos */
1468
1469 _sync_scalar_gradient_halo(m, CS_HALO_EXTENDED, grad);
1470 }
1471
1472 /*----------------------------------------------------------------------------
1473 * Compute 3x3 matrix cocg for the iterative algorithm
1474 *
1475 * parameters:
1476 * m <-- mesh
1477 * fvq <-- mesh quantities
1478 * ce <-- coupling entity
1479 * gq <-> gradient quantities
1480 *
1481 * returns:
1482 * pointer to cocg matrix (handled in main or coupled mesh quantities)
1483 *----------------------------------------------------------------------------*/
1484
1485 static cs_real_33_t *
_compute_cell_cocg_it(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * ce,cs_gradient_quantities_t * gq)1486 _compute_cell_cocg_it(const cs_mesh_t *m,
1487 const cs_mesh_quantities_t *fvq,
1488 const cs_internal_coupling_t *ce,
1489 cs_gradient_quantities_t *gq)
1490 {
1491 /* Local variables */
1492
1493 const int n_cells = m->n_cells;
1494 const int n_cells_with_ghosts = m->n_cells_with_ghosts;
1495 const int n_i_faces = m->n_i_faces;
1496
1497 const cs_lnum_2_t *restrict i_face_cells
1498 = (const cs_lnum_2_t *restrict)m->i_face_cells;
1499
1500 const cs_real_t *restrict cell_vol = fvq->cell_vol;
1501 const cs_real_3_t *restrict i_face_normal
1502 = (const cs_real_3_t *restrict)fvq->i_face_normal;
1503 const cs_real_3_t *restrict dofij
1504 = (const cs_real_3_t *restrict)fvq->dofij;
1505
1506 cs_real_33_t *restrict cocg = gq->cocg_it;
1507
1508 cs_lnum_t cell_id, f_id, i, j;
1509 cs_real_t pfac, vecfac;
1510 cs_real_t dvol1, dvol2;
1511
1512 if (cocg == NULL) {
1513 BFT_MALLOC(cocg, n_cells_with_ghosts, cs_real_33_t);
1514 gq->cocg_it = cocg;
1515 }
1516
1517 /* compute the dimensionless matrix COCG for each cell*/
1518
1519 for (cell_id = 0; cell_id < n_cells_with_ghosts; cell_id++) {
1520 cocg[cell_id][0][0]= 1.0;
1521 cocg[cell_id][0][1]= 0.0;
1522 cocg[cell_id][0][2]= 0.0;
1523 cocg[cell_id][1][0]= 0.0;
1524 cocg[cell_id][1][1]= 1.0;
1525 cocg[cell_id][1][2]= 0.0;
1526 cocg[cell_id][2][0]= 0.0;
1527 cocg[cell_id][2][1]= 0.0;
1528 cocg[cell_id][2][2]= 1.0;
1529 }
1530
1531 /* Interior face treatment */
1532
1533 for (f_id = 0; f_id < n_i_faces; f_id++) {
1534 cs_lnum_t cell_id1 = i_face_cells[f_id][0];
1535 cs_lnum_t cell_id2 = i_face_cells[f_id][1];
1536
1537 dvol1 = 1./cell_vol[cell_id1];
1538 dvol2 = 1./cell_vol[cell_id2];
1539
1540 for (i = 0; i < 3; i++) {
1541
1542 pfac = -0.5*dofij[f_id][i];
1543
1544 for (j = 0; j < 3; j++) {
1545 vecfac = pfac*i_face_normal[f_id][j];
1546 cocg[cell_id1][i][j] += vecfac * dvol1;
1547 cocg[cell_id2][i][j] -= vecfac * dvol2;
1548 }
1549 }
1550 }
1551
1552 /* Contribution for internal coupling */
1553 if (ce != NULL) {
1554 cs_internal_coupling_it_cocg_contribution(ce, cocg);
1555 }
1556
1557 /* 3x3 Matrix inversion */
1558
1559 # pragma omp parallel for
1560 for (cell_id = 0; cell_id < n_cells; cell_id++)
1561 cs_math_33_inv_cramer_in_place(cocg[cell_id]);
1562
1563 return cocg;
1564 }
1565
1566 /*----------------------------------------------------------------------------
1567 * Compute cell gradient using iterative reconstruction for non-orthogonal
1568 * meshes (nswrgp > 1).
1569 *
1570 * Optionally, a volume force generating a hydrostatic pressure component
1571 * may be accounted for.
1572 *
1573 * parameters:
1574 * m <-- pointer to associated mesh structure
1575 * fvq <-- pointer to associated finite volume quantities
1576 * cpl <-- structure associated with internal coupling, or NULL
1577 * var_name <-- variable name
1578 * gradient_info <-- pointer to performance logging structure, or NULL
1579 * nswrgp <-- number of sweeps for gradient reconstruction
1580 * hyd_p_flag <-- flag for hydrostatic pressure
1581 * verbosity <-- verbosity level
1582 * inc <-- if 0, solve on increment; 1 otherwise
1583 * epsrgp <-- relative precision for gradient reconstruction
1584 * f_ext <-- exterior force generating pressure
1585 * bc_coeff_a <-- B.C. coefficients for boundary face normals
1586 * coefbp <-- B.C. coefficients for boundary face normals
1587 * pvar <-- variable
1588 * c_weight <-- weighted gradient coefficient variable
1589 * grad <-> gradient of pvar (halo prepared for periodicity
1590 * of rotation)
1591 *----------------------------------------------------------------------------*/
1592
1593 static void
_iterative_scalar_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,const char * var_name,cs_gradient_info_t * gradient_info,int nswrgp,int hyd_p_flag,int verbosity,cs_real_t inc,cs_real_t epsrgp,const cs_real_3_t f_ext[],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t pvar[],const cs_real_t c_weight[],cs_real_3_t * restrict grad)1594 _iterative_scalar_gradient(const cs_mesh_t *m,
1595 const cs_mesh_quantities_t *fvq,
1596 const cs_internal_coupling_t *cpl,
1597 const char *var_name,
1598 cs_gradient_info_t *gradient_info,
1599 int nswrgp,
1600 int hyd_p_flag,
1601 int verbosity,
1602 cs_real_t inc,
1603 cs_real_t epsrgp,
1604 const cs_real_3_t f_ext[],
1605 const cs_real_t coefap[],
1606 const cs_real_t coefbp[],
1607 const cs_real_t pvar[],
1608 const cs_real_t c_weight[],
1609 cs_real_3_t *restrict grad)
1610 {
1611 const cs_lnum_t n_cells = m->n_cells;
1612 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
1613 const int n_i_groups = m->i_face_numbering->n_groups;
1614 const int n_i_threads = m->i_face_numbering->n_threads;
1615 const int n_b_groups = m->b_face_numbering->n_groups;
1616 const int n_b_threads = m->b_face_numbering->n_threads;
1617 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
1618 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
1619
1620 const cs_lnum_2_t *restrict i_face_cells
1621 = (const cs_lnum_2_t *restrict)m->i_face_cells;
1622 const cs_lnum_t *restrict b_face_cells
1623 = (const cs_lnum_t *restrict)m->b_face_cells;
1624
1625 const int *restrict c_disable_flag = fvq->c_disable_flag;
1626 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
1627
1628 const cs_real_t *restrict weight = fvq->weight;
1629 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
1630 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
1631 cell_f_vol = fvq->cell_vol;
1632 const cs_real_3_t *restrict cell_cen
1633 = (const cs_real_3_t *restrict)fvq->cell_cen;
1634 const cs_real_3_t *restrict i_f_face_normal
1635 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
1636 const cs_real_3_t *restrict b_f_face_normal
1637 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
1638 const cs_real_3_t *restrict i_face_cog
1639 = (const cs_real_3_t *restrict)fvq->i_face_cog;
1640 const cs_real_3_t *restrict b_face_cog
1641 = (const cs_real_3_t *restrict)fvq->b_face_cog;
1642 const cs_real_3_t *restrict diipb
1643 = (const cs_real_3_t *restrict)fvq->diipb;
1644 const cs_real_3_t *restrict dofij
1645 = (const cs_real_3_t *restrict)fvq->dofij;
1646
1647 cs_real_3_t *rhs;
1648
1649 int n_sweeps = 0;
1650 cs_real_t l2_residual = 0.;
1651
1652 if (nswrgp < 1) {
1653 if (gradient_info != NULL)
1654 _gradient_info_update_iter(gradient_info, 0);
1655 return;
1656 }
1657
1658 int gq_id = (cpl == NULL) ? 0 : cpl->id+1;
1659 cs_gradient_quantities_t *gq = _gradient_quantities_get(gq_id);
1660
1661 cs_real_33_t *restrict cocg = gq->cocg_it;
1662 if (cocg == NULL)
1663 cocg = _compute_cell_cocg_it(m, fvq, cpl, gq);
1664
1665 bool *coupled_faces = (cpl == NULL) ?
1666 NULL : (bool *)cpl->coupled_faces;
1667
1668 /*Additional terms due to porosity */
1669 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
1670
1671 cs_real_t *i_poro_duq_0;
1672 cs_real_t *i_poro_duq_1;
1673 cs_real_t *b_poro_duq;
1674 cs_real_t _f_ext = 0.;
1675
1676 int is_porous = 0;
1677 if (f_i_poro_duq_0 != NULL) {
1678 is_porous = 1;
1679 i_poro_duq_0 = f_i_poro_duq_0->val;
1680 i_poro_duq_1 = cs_field_by_name("i_poro_duq_1")->val;
1681 b_poro_duq = cs_field_by_name("b_poro_duq")->val;
1682 } else {
1683 i_poro_duq_0 = &_f_ext;
1684 i_poro_duq_1 = &_f_ext;
1685 b_poro_duq = &_f_ext;
1686 }
1687
1688 /* Reconstruct gradients for non-orthogonal meshes */
1689 /*-------------------------------------------------*/
1690
1691 /* Semi-implicit resolution on the whole mesh */
1692
1693 /* Compute normalization residual */
1694
1695 cs_real_t rnorm = _l2_norm_1(3*n_cells, (cs_real_t *)grad);
1696
1697 if (rnorm <= cs_math_epzero) {
1698 if (gradient_info != NULL)
1699 _gradient_info_update_iter(gradient_info, 0);
1700 return;
1701 }
1702
1703 BFT_MALLOC(rhs, n_cells_ext, cs_real_3_t);
1704
1705 /* Vector OijFij is computed in CLDijP */
1706
1707 /* Start iterations */
1708 /*------------------*/
1709
1710 for (n_sweeps = 1; n_sweeps < nswrgp; n_sweeps++) {
1711
1712 /* Compute right hand side */
1713
1714 # pragma omp parallel for
1715 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
1716 rhs[c_id][0] = -grad[c_id][0] * cell_f_vol[c_id];
1717 rhs[c_id][1] = -grad[c_id][1] * cell_f_vol[c_id];
1718 rhs[c_id][2] = -grad[c_id][2] * cell_f_vol[c_id];
1719 }
1720
1721 /* Case with hydrostatic pressure */
1722 /*--------------------------------*/
1723
1724 if (hyd_p_flag == 1) {
1725
1726 /* Contribution from interior faces */
1727
1728 for (int g_id = 0; g_id < n_i_groups; g_id++) {
1729
1730 # pragma omp parallel for
1731 for (int t_id = 0; t_id < n_i_threads; t_id++) {
1732
1733 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1734 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1735 f_id++) {
1736
1737 cs_lnum_t c_id1 = i_face_cells[f_id][0];
1738 cs_lnum_t c_id2 = i_face_cells[f_id][1];
1739
1740 cs_real_t ktpond = (c_weight == NULL) ?
1741 weight[f_id] : // no cell weighting
1742 weight[f_id] * c_weight[c_id1] // cell weighting active
1743 / ( weight[f_id] * c_weight[c_id1]
1744 + (1.0-weight[f_id]) * c_weight[c_id2]);
1745
1746 cs_real_2_t poro = {
1747 i_poro_duq_0[is_porous*f_id],
1748 i_poro_duq_1[is_porous*f_id]
1749 };
1750
1751 // TODO add porous contribution
1752 cs_real_t fexd[3];
1753 fexd[0] = 0.5 * (f_ext[c_id1][0] + f_ext[c_id2][0]);
1754 fexd[1] = 0.5 * (f_ext[c_id1][1] + f_ext[c_id2][1]);
1755 fexd[2] = 0.5 * (f_ext[c_id1][2] + f_ext[c_id2][2]);
1756
1757 /*
1758 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
1759 + (1-\alpha_\ij) \varia_\cellj\f$
1760 but for the cell \f$ \celli \f$ we remove
1761 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1762 and for the cell \f$ \cellj \f$ we remove
1763 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
1764 */
1765
1766 /* Reconstruction part */
1767 cs_real_t pfaci =
1768 (i_face_cog[f_id][0]-cell_cen[c_id1][0])
1769 *(ktpond*f_ext[c_id1][0]-weight[f_id]*fexd[0])
1770 + (i_face_cog[f_id][1]-cell_cen[c_id1][1])
1771 *(ktpond*f_ext[c_id1][1]-weight[f_id]*fexd[1])
1772 + (i_face_cog[f_id][2]-cell_cen[c_id1][2])
1773 *(ktpond*f_ext[c_id1][2]-weight[f_id]*fexd[2])
1774 + ktpond*poro[0]
1775 + (i_face_cog[f_id][0]-cell_cen[c_id2][0])
1776 *((1.0 - ktpond)*f_ext[c_id2][0]-(1.-weight[f_id])*fexd[0])
1777 + (i_face_cog[f_id][1]-cell_cen[c_id2][1])
1778 *((1.0 - ktpond)*f_ext[c_id2][1]-(1.-weight[f_id])*fexd[1])
1779 + (i_face_cog[f_id][2]-cell_cen[c_id2][2])
1780 *((1.0 - ktpond)*f_ext[c_id2][2]-(1.-weight[f_id])*fexd[2])
1781 + (1.0 - ktpond)*poro[1]
1782 + ( dofij[f_id][0] * (grad[c_id1][0]+grad[c_id2][0])
1783 + dofij[f_id][1] * (grad[c_id1][1]+grad[c_id2][1])
1784 + dofij[f_id][2] * (grad[c_id1][2]+grad[c_id2][2]))*0.5;
1785
1786 cs_real_t pfacj = pfaci;
1787
1788 pfaci += (1.0-ktpond) * (pvar[c_id2] - pvar[c_id1]);
1789 pfacj -= ktpond * (pvar[c_id2] - pvar[c_id1]);
1790
1791 for (cs_lnum_t j = 0; j < 3; j++) {
1792 rhs[c_id1][j] += pfaci * i_f_face_normal[f_id][j];
1793 rhs[c_id2][j] -= pfacj * i_f_face_normal[f_id][j];
1794 }
1795
1796 } /* loop on faces */
1797
1798 } /* loop on threads */
1799
1800 } /* loop on thread groups */
1801
1802 /* Contribution from boundary faces */
1803
1804 for (int g_id = 0; g_id < n_b_groups; g_id++) {
1805
1806 # pragma omp parallel for
1807 for (int t_id = 0; t_id < n_b_threads; t_id++) {
1808
1809 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1810 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1811 f_id++) {
1812
1813 cs_lnum_t c_id = b_face_cells[f_id];
1814
1815 cs_real_t poro = b_poro_duq[is_porous*f_id];
1816
1817 /*
1818 Remark: for the cell \f$ \celli \f$ we remove
1819 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1820 */
1821
1822 /* Reconstruction part */
1823 cs_real_t pfac
1824 = coefap[f_id] * inc
1825 + coefbp[f_id]
1826 * ( diipb[f_id][0] * (grad[c_id][0] - f_ext[c_id][0])
1827 + diipb[f_id][1] * (grad[c_id][1] - f_ext[c_id][1])
1828 + diipb[f_id][2] * (grad[c_id][2] - f_ext[c_id][2])
1829 + (b_face_cog[f_id][0]-cell_cen[c_id][0]) * f_ext[c_id][0]
1830 + (b_face_cog[f_id][1]-cell_cen[c_id][1]) * f_ext[c_id][1]
1831 + (b_face_cog[f_id][2]-cell_cen[c_id][2]) * f_ext[c_id][2]
1832 + poro);
1833
1834 pfac += (coefbp[f_id] -1.0) * pvar[c_id];
1835
1836 rhs[c_id][0] += pfac * b_f_face_normal[f_id][0];
1837 rhs[c_id][1] += pfac * b_f_face_normal[f_id][1];
1838 rhs[c_id][2] += pfac * b_f_face_normal[f_id][2];
1839
1840 } /* loop on faces */
1841
1842 } /* loop on threads */
1843
1844 } /* loop on thread groups */
1845
1846 } /* End of test on hydrostatic pressure */
1847
1848 /* Standard case, without hydrostatic pressure */
1849 /*---------------------------------------------*/
1850
1851 else {
1852
1853 /* Contribution from interior faces */
1854
1855 for (int g_id = 0; g_id < n_i_groups; g_id++) {
1856
1857 # pragma omp parallel for
1858 for (int t_id = 0; t_id < n_i_threads; t_id++) {
1859
1860 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
1861 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
1862 f_id++) {
1863
1864 cs_lnum_t c_id1 = i_face_cells[f_id][0];
1865 cs_lnum_t c_id2 = i_face_cells[f_id][1];
1866
1867 /*
1868 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
1869 + (1-\alpha_\ij) \varia_\cellj\f$
1870 but for the cell \f$ \celli \f$ we remove
1871 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1872 and for the cell \f$ \cellj \f$ we remove
1873 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
1874 */
1875
1876 /* Reconstruction part */
1877 cs_real_t pfaci
1878 = 0.5 * ( dofij[f_id][0] * (grad[c_id1][0]+grad[c_id2][0])
1879 + dofij[f_id][1] * (grad[c_id1][1]+grad[c_id2][1])
1880 + dofij[f_id][2] * (grad[c_id1][2]+grad[c_id2][2]));
1881 cs_real_t pfacj = pfaci;
1882
1883 cs_real_t ktpond = (c_weight == NULL) ?
1884 weight[f_id] : // no cell weighting
1885 weight[f_id] * c_weight[c_id1] // cell weighting active
1886 / ( weight[f_id] * c_weight[c_id1]
1887 + (1.0-weight[f_id]) * c_weight[c_id2]);
1888
1889 pfaci += (1.0-ktpond) * (pvar[c_id2] - pvar[c_id1]);
1890 pfacj -= ktpond * (pvar[c_id2] - pvar[c_id1]);
1891
1892 for (cs_lnum_t j = 0; j < 3; j++) {
1893 rhs[c_id1][j] += pfaci * i_f_face_normal[f_id][j];
1894 rhs[c_id2][j] -= pfacj * i_f_face_normal[f_id][j];
1895 }
1896
1897 } /* loop on faces */
1898
1899 } /* loop on threads */
1900
1901 } /* loop on thread groups */
1902
1903 /* Contribution from coupled faces */
1904 if (cpl != NULL)
1905 cs_internal_coupling_iterative_scalar_gradient
1906 (cpl,
1907 c_weight,
1908 grad,
1909 pvar,
1910 rhs);
1911
1912 /* Contribution from boundary faces */
1913
1914 for (int g_id = 0; g_id < n_b_groups; g_id++) {
1915
1916 # pragma omp parallel for
1917 for (int t_id = 0; t_id < n_b_threads; t_id++) {
1918
1919 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
1920 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
1921 f_id++) {
1922
1923 if (cpl == NULL || !coupled_faces[f_id]) {
1924
1925 cs_lnum_t c_id = b_face_cells[f_id];
1926
1927 /*
1928 Remark: for the cell \f$ \celli \f$ we remove
1929 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
1930 */
1931
1932 /* Reconstruction part */
1933 cs_real_t pfac
1934 = coefap[f_id] * inc
1935 + coefbp[f_id]
1936 * ( diipb[f_id][0] * grad[c_id][0]
1937 + diipb[f_id][1] * grad[c_id][1]
1938 + diipb[f_id][2] * grad[c_id][2]);
1939
1940 pfac += (coefbp[f_id] -1.0) * pvar[c_id];
1941
1942 rhs[c_id][0] += pfac * b_f_face_normal[f_id][0];
1943 rhs[c_id][1] += pfac * b_f_face_normal[f_id][1];
1944 rhs[c_id][2] += pfac * b_f_face_normal[f_id][2];
1945
1946 } /* face without internal coupling */
1947
1948 } /* loop on faces */
1949
1950 } /* loop on threads */
1951
1952 } /* loop on thread groups */
1953
1954 }
1955
1956 /* Increment gradient */
1957 /*--------------------*/
1958
1959 # pragma omp parallel for
1960 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
1961 cs_real_t dvol;
1962 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
1963 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
1964 dvol = 1. / cell_f_vol[c_id];
1965 else
1966 dvol = 0.;
1967
1968 rhs[c_id][0] *= dvol;
1969 rhs[c_id][1] *= dvol;
1970 rhs[c_id][2] *= dvol;
1971
1972 grad[c_id][0] += rhs[c_id][0] * cocg[c_id][0][0]
1973 + rhs[c_id][1] * cocg[c_id][1][0]
1974 + rhs[c_id][2] * cocg[c_id][2][0];
1975 grad[c_id][1] += rhs[c_id][0] * cocg[c_id][0][1]
1976 + rhs[c_id][1] * cocg[c_id][1][1]
1977 + rhs[c_id][2] * cocg[c_id][2][1];
1978 grad[c_id][2] += rhs[c_id][0] * cocg[c_id][0][2]
1979 + rhs[c_id][1] * cocg[c_id][1][2]
1980 + rhs[c_id][2] * cocg[c_id][2][2];
1981 }
1982
1983 /* Synchronize halos */
1984
1985 _sync_scalar_gradient_halo(m, CS_HALO_STANDARD, grad);
1986
1987 /* Convergence test */
1988
1989 l2_residual = _l2_norm_1(3*n_cells, (cs_real_t *)rhs);
1990
1991 if (l2_residual < epsrgp*rnorm) {
1992 if (verbosity >= 2)
1993 bft_printf(_(" %s; variable: %s; converged in %d sweeps\n"
1994 " %*s normed residual: %11.4e; norm: %11.4e\n"),
1995 __func__, var_name, n_sweeps,
1996 (int)(strlen(__func__)), " ", l2_residual/rnorm, rnorm);
1997 break;
1998 }
1999
2000 } /* Loop on sweeps */
2001
2002 if (l2_residual >= epsrgp*rnorm && verbosity > -1) {
2003 bft_printf(_(" Warning:\n"
2004 " --------\n"
2005 " %s; variable: %s; sweeps: %d\n"
2006 " %*s normed residual: %11.4e; norm: %11.4e\n"),
2007 __func__, var_name, n_sweeps,
2008 (int)(strlen(__func__)), " ", l2_residual/rnorm, rnorm);
2009 }
2010
2011 if (gradient_info != NULL)
2012 _gradient_info_update_iter(gradient_info, n_sweeps);
2013
2014 BFT_FREE(rhs);
2015 }
2016
2017 /*----------------------------------------------------------------------------
2018 * Compute 3x3 matrix cocg for the scalar gradient least squares algorithm
2019 *
2020 * parameters:
2021 * m <-- mesh
2022 * extended <-- true if extended neighborhood used
2023 * fvq <-- mesh quantities
2024 * ce <-- coupling entity
2025 * gq <-> gradient quantities
2026 *----------------------------------------------------------------------------*/
2027
2028 static void
_compute_cell_cocg_lsq(const cs_mesh_t * m,bool extended,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * ce,cs_gradient_quantities_t * gq)2029 _compute_cell_cocg_lsq(const cs_mesh_t *m,
2030 bool extended,
2031 const cs_mesh_quantities_t *fvq,
2032 const cs_internal_coupling_t *ce,
2033 cs_gradient_quantities_t *gq)
2034
2035 {
2036 const int n_cells = m->n_cells;
2037 const int n_cells_ext = m->n_cells_with_ghosts;
2038 const int n_i_groups = m->i_face_numbering->n_groups;
2039 const int n_i_threads = m->i_face_numbering->n_threads;
2040 const int n_b_groups = m->b_face_numbering->n_groups;
2041 const int n_b_threads = m->b_face_numbering->n_threads;
2042 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
2043 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
2044
2045 const cs_lnum_2_t *restrict i_face_cells
2046 = (const cs_lnum_2_t *restrict)m->i_face_cells;
2047 const cs_lnum_t *restrict b_face_cells
2048 = (const cs_lnum_t *restrict)m->b_face_cells;
2049 const cs_lnum_t *restrict cell_cells_idx
2050 = (const cs_lnum_t *restrict)m->cell_cells_idx;
2051 const cs_lnum_t *restrict cell_cells_lst
2052 = (const cs_lnum_t *restrict)m->cell_cells_lst;
2053
2054 const cs_real_3_t *restrict cell_cen
2055 = (const cs_real_3_t *restrict)fvq->cell_cen;
2056 const cs_real_3_t *restrict b_face_normal
2057 = (const cs_real_3_t *restrict)fvq->b_face_normal;
2058
2059 cs_cocg_6_t *restrict cocgb = NULL, *restrict cocg = NULL;
2060
2061 /* Map cocg/cocgb to correct structure, reallocate if needed */
2062
2063 if (extended) {
2064 cocg = gq->cocg_lsq_ext;
2065 cocgb = gq->cocgb_s_lsq_ext;
2066 }
2067 else {
2068 cocg = gq->cocg_lsq;
2069 cocgb =gq->cocgb_s_lsq;
2070 }
2071
2072 if (cocg == NULL) {
2073
2074 assert(cocgb == NULL);
2075
2076 BFT_MALLOC(cocg, n_cells_ext, cs_cocg_6_t);
2077 BFT_MALLOC(cocgb, m->n_b_cells, cs_cocg_6_t);
2078
2079 if (extended) {
2080 gq->cocg_lsq_ext = cocg;
2081 gq->cocgb_s_lsq_ext = cocgb;
2082 }
2083 else {
2084 gq->cocg_lsq = cocg;
2085 gq->cocgb_s_lsq = cocgb;
2086 }
2087
2088 }
2089
2090 const bool *coupled_faces = NULL;
2091 if (ce != NULL)
2092 coupled_faces = ce->coupled_faces;
2093
2094 /* Initialization */
2095
2096 # pragma omp parallel
2097 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
2098 for (cs_lnum_t ll = 0; ll < 6; ll++) {
2099 cocg[c_id][ll] = 0.0;
2100 }
2101 }
2102
2103 /* Contribution from interior faces */
2104
2105 for (int g_id = 0; g_id < n_i_groups; g_id++) {
2106
2107 # pragma omp parallel for
2108 for (int t_id = 0; t_id < n_i_threads; t_id++) {
2109
2110 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2111 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2112 f_id++) {
2113
2114 cs_real_t dc[3];
2115 cs_lnum_t ii = i_face_cells[f_id][0];
2116 cs_lnum_t jj = i_face_cells[f_id][1];
2117
2118 for (cs_lnum_t ll = 0; ll < 3; ll++)
2119 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2120 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2121
2122 cocg[ii][0] += dc[0]*dc[0]*ddc;
2123 cocg[ii][1] += dc[1]*dc[1]*ddc;
2124 cocg[ii][2] += dc[2]*dc[2]*ddc;
2125 cocg[ii][3] += dc[0]*dc[1]*ddc;
2126 cocg[ii][4] += dc[1]*dc[2]*ddc;
2127 cocg[ii][5] += dc[0]*dc[2]*ddc;
2128
2129 cocg[jj][0] += dc[0]*dc[0]*ddc;
2130 cocg[jj][1] += dc[1]*dc[1]*ddc;
2131 cocg[jj][2] += dc[2]*dc[2]*ddc;
2132 cocg[jj][3] += dc[0]*dc[1]*ddc;
2133 cocg[jj][4] += dc[1]*dc[2]*ddc;
2134 cocg[jj][5] += dc[0]*dc[2]*ddc;
2135
2136 } /* loop on faces */
2137
2138 } /* loop on threads */
2139
2140 } /* loop on thread groups */
2141
2142 /* Contribution for internal coupling */
2143 if (ce != NULL) {
2144 cs_internal_coupling_lsq_cocg_contribution(ce, cocg);
2145 }
2146
2147 /* Contribution from extended neighborhood */
2148
2149 if (extended) {
2150
2151 # pragma omp parallel for
2152 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
2153 for (cs_lnum_t cidx = cell_cells_idx[ii];
2154 cidx < cell_cells_idx[ii+1];
2155 cidx++) {
2156
2157 cs_real_t dc[3];
2158 cs_lnum_t jj = cell_cells_lst[cidx];
2159
2160 for (cs_lnum_t ll = 0; ll < 3; ll++)
2161 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2162 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2163
2164 cocg[ii][0] += dc[0]*dc[0]*ddc;
2165 cocg[ii][1] += dc[1]*dc[1]*ddc;
2166 cocg[ii][2] += dc[2]*dc[2]*ddc;
2167 cocg[ii][3] += dc[0]*dc[1]*ddc;
2168 cocg[ii][4] += dc[1]*dc[2]*ddc;
2169 cocg[ii][5] += dc[0]*dc[2]*ddc;
2170
2171 }
2172 }
2173
2174 } /* End for extended neighborhood */
2175
2176 /* Save partial cocg at interior faces of boundary cells */
2177
2178 # pragma omp parallel for
2179 for (cs_lnum_t ii = 0; ii < m->n_b_cells; ii++) {
2180 cs_lnum_t c_id = m->b_cells[ii];
2181 for (cs_lnum_t ll = 0; ll < 6; ll++) {
2182 cocgb[ii][ll] = cocg[c_id][ll];
2183 }
2184 }
2185
2186 /* Contribution from boundary faces, assuming symmetry everywhere
2187 so as to avoid obtaining a non-invertible matrix in 2D cases. */
2188
2189 for (int g_id = 0; g_id < n_b_groups; g_id++) {
2190
2191 # pragma omp parallel for
2192 for (int t_id = 0; t_id < n_b_threads; t_id++) {
2193
2194 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2195 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2196 f_id++) {
2197
2198 if (ce == NULL || !coupled_faces[f_id]) {
2199
2200 cs_lnum_t ii = b_face_cells[f_id];
2201
2202 cs_real_3_t normal;
2203 /* Normal is vector 0 if the b_face_normal norm is too small */
2204 cs_math_3_normalise(b_face_normal[f_id], normal);
2205
2206 cocg[ii][0] += normal[0] * normal[0];
2207 cocg[ii][1] += normal[1] * normal[1];
2208 cocg[ii][2] += normal[2] * normal[2];
2209 cocg[ii][3] += normal[0] * normal[1];
2210 cocg[ii][4] += normal[1] * normal[2];
2211 cocg[ii][5] += normal[0] * normal[2];
2212
2213 } /* face without internal coupling */
2214
2215 } /* loop on faces */
2216
2217 } /* loop on threads */
2218
2219 } /* loop on thread groups */
2220
2221 /* Invert for all cells. */
2222 /*-----------------------*/
2223
2224 /* The cocg term for interior cells only changes if the mesh does */
2225
2226 # pragma omp parallel for
2227 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
2228 _math_6_inv_cramer_sym_in_place(cocg[c_id]);
2229 }
2230 }
2231
2232 /*----------------------------------------------------------------------------
2233 * Return current symmetric 3x3 matrix cocg for least squares algorithm
2234 *
2235 * parameters:
2236 * m <-- mesh
2237 * halo_type <-- halo type
2238 * accel <-- use accelerator device (if true, cocg and cocgb
2239 * pointers returned are device pointers)
2240 * fvq <-- mesh quantities
2241 * ce <-- coupling entity
2242 * cocg --> coupling coeffiences (covariance matrices)
2243 * cocgb --> partial boundary coupling coeffients, or NULL
2244 *----------------------------------------------------------------------------*/
2245
2246 static void
_get_cell_cocg_lsq(const cs_mesh_t * m,cs_halo_type_t halo_type,bool accel,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * ce,cs_cocg_6_t * restrict * cocg,cs_cocg_6_t * restrict * cocgb)2247 _get_cell_cocg_lsq(const cs_mesh_t *m,
2248 cs_halo_type_t halo_type,
2249 bool accel,
2250 const cs_mesh_quantities_t *fvq,
2251 const cs_internal_coupling_t *ce,
2252 cs_cocg_6_t *restrict *cocg,
2253 cs_cocg_6_t *restrict *cocgb)
2254 {
2255 int gq_id = (ce == NULL) ? 0 : ce->id+1;
2256 cs_gradient_quantities_t *gq = _gradient_quantities_get(gq_id);
2257
2258 cs_cocg_6_t *_cocg = NULL, *_cocgb = NULL;
2259
2260 bool extended = ( halo_type == CS_HALO_EXTENDED
2261 && m->cell_cells_idx) ? true : false;
2262
2263 if (extended) {
2264 _cocg = gq->cocg_lsq_ext;
2265 _cocgb = gq->cocgb_s_lsq_ext;
2266 }
2267 else {
2268 _cocg = gq->cocg_lsq;
2269 _cocgb = gq->cocgb_s_lsq;
2270 }
2271
2272 /* Compute if not present yet.
2273 *
2274 * TODO: when using accelerators, this imples a first computation will be
2275 * run on the host. This will usually be amortized, but could be
2276 * further improved. */
2277
2278 if (_cocg == NULL)
2279 _compute_cell_cocg_lsq(m, extended, fvq, ce, gq);
2280
2281 /* If used on accelerator, ensure arrays are available there */
2282
2283 if (accel) {
2284
2285 cs_alloc_mode_t alloc_mode = CS_ALLOC_HOST_DEVICE_SHARED;
2286
2287 void *_cocg_p = _cocg, *_cocgb_p = _cocgb;
2288
2289 cs_set_alloc_mode(&_cocg_p, alloc_mode);
2290 cs_set_alloc_mode(&_cocgb_p, alloc_mode);
2291
2292 if (extended) {
2293 cs_set_alloc_mode(&(gq->cocg_lsq_ext), alloc_mode);
2294 cs_set_alloc_mode(&(gq->cocgb_s_lsq_ext), alloc_mode);
2295 }
2296 else {
2297 cs_set_alloc_mode(&(gq->cocg_lsq), alloc_mode);
2298 cs_set_alloc_mode(&(gq->cocgb_s_lsq), alloc_mode);
2299 }
2300
2301 }
2302
2303 /* Set pointers */
2304
2305 if (extended)
2306 *cocg = gq->cocg_lsq_ext;
2307 else
2308 *cocg = gq->cocg_lsq;
2309
2310 if (cocgb != NULL) {
2311 if (extended)
2312 *cocgb = gq->cocgb_s_lsq_ext;
2313 else
2314 *cocgb = gq->cocgb_s_lsq;
2315 }
2316
2317 /* If used on acclelerator, copy/prefetch values and switch to
2318 device pointers */
2319
2320 if (accel) {
2321 cs_sync_h2d(*cocg);
2322 *cocg = cs_get_device_ptr(*cocg);
2323
2324 if (cocgb != NULL) {
2325 cs_sync_h2d(*cocgb);
2326 *cocgb = cs_get_device_ptr(*cocgb);
2327 }
2328 }
2329 }
2330
2331 /*----------------------------------------------------------------------------
2332 * Compute cell gradient using least-squares reconstruction for non-orthogonal
2333 * meshes (nswrgp > 1).
2334 *
2335 * Optionally, a volume force generating a hydrostatic pressure component
2336 * may be accounted for.
2337 *
2338 * cocg is computed to account for variable B.C.'s (flux).
2339 *
2340 * parameters:
2341 * m <-- pointer to associated mesh structure
2342 * fvq <-- pointer to associated finite volume quantities
2343 * cpl <-- structure associated with internal coupling, or NULL
2344 * halo_type <-- halo type (extended or not)
2345 * recompute_cocg <-- flag to recompute cocg
2346 * hyd_p_flag <-- flag for hydrostatic pressure
2347 * inc <-- if 0, solve on increment; 1 otherwise
2348 * fext <-- exterior force generating pressure
2349 * coefap <-- B.C. coefficients for boundary face normals
2350 * coefbp <-- B.C. coefficients for boundary face normals
2351 * pvar <-- variable
2352 * c_weight <-- weighted gradient coefficient variable,
2353 * or NULL
2354 * grad --> gradient of pvar (halo prepared for periodicity
2355 * of rotation)
2356 *----------------------------------------------------------------------------*/
2357
2358 static void
_lsq_scalar_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,cs_halo_type_t halo_type,bool recompute_cocg,int hyd_p_flag,cs_real_t inc,const cs_real_3_t f_ext[],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t pvar[],const cs_real_t * restrict c_weight,cs_real_3_t * restrict grad)2359 _lsq_scalar_gradient(const cs_mesh_t *m,
2360 const cs_mesh_quantities_t *fvq,
2361 const cs_internal_coupling_t *cpl,
2362 cs_halo_type_t halo_type,
2363 bool recompute_cocg,
2364 int hyd_p_flag,
2365 cs_real_t inc,
2366 const cs_real_3_t f_ext[],
2367 const cs_real_t coefap[],
2368 const cs_real_t coefbp[],
2369 const cs_real_t pvar[],
2370 const cs_real_t *restrict c_weight,
2371 cs_real_3_t *restrict grad)
2372 {
2373 const cs_lnum_t n_cells = m->n_cells;
2374 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
2375 const int n_i_groups = m->i_face_numbering->n_groups;
2376 const int n_i_threads = m->i_face_numbering->n_threads;
2377 const int n_b_groups = m->b_face_numbering->n_groups;
2378 const int n_b_threads = m->b_face_numbering->n_threads;
2379 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
2380 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
2381
2382 const cs_lnum_2_t *restrict i_face_cells
2383 = (const cs_lnum_2_t *restrict)m->i_face_cells;
2384 const cs_lnum_t *restrict b_face_cells
2385 = (const cs_lnum_t *restrict)m->b_face_cells;
2386 const cs_lnum_t *restrict cell_cells_idx
2387 = (const cs_lnum_t *restrict)m->cell_cells_idx;
2388 const cs_lnum_t *restrict cell_cells_lst
2389 = (const cs_lnum_t *restrict)m->cell_cells_lst;
2390
2391 const cs_real_3_t *restrict cell_cen
2392 = (const cs_real_3_t *restrict)fvq->cell_cen;
2393 const cs_real_3_t *restrict b_face_normal
2394 = (const cs_real_3_t *restrict)fvq->b_face_normal;
2395 const cs_real_t *restrict b_face_surf
2396 = (const cs_real_t *restrict)fvq->b_face_surf;
2397 const cs_real_t *restrict b_dist
2398 = (const cs_real_t *restrict)fvq->b_dist;
2399 const cs_real_3_t *restrict i_face_cog
2400 = (const cs_real_3_t *restrict)fvq->i_face_cog;
2401 const cs_real_3_t *restrict b_face_cog
2402 = (const cs_real_3_t *restrict)fvq->b_face_cog;
2403 const cs_real_3_t *restrict diipb
2404 = (const cs_real_3_t *restrict)fvq->diipb;
2405 const cs_real_t *restrict weight = fvq->weight;
2406
2407 cs_cocg_6_t *restrict cocgb = NULL;
2408 cs_cocg_6_t *restrict cocg = NULL;
2409
2410 /* Additional terms due to porosity */
2411 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
2412
2413 cs_real_t *i_poro_duq_0;
2414 cs_real_t *i_poro_duq_1;
2415 cs_real_t *b_poro_duq;
2416 cs_real_t _f_ext = 0.;
2417
2418 int is_porous = 0;
2419 if (f_i_poro_duq_0 != NULL) {
2420 is_porous = 1;
2421 i_poro_duq_0 = f_i_poro_duq_0->val;
2422 i_poro_duq_1 = cs_field_by_name("i_poro_duq_1")->val;
2423 b_poro_duq = cs_field_by_name("b_poro_duq")->val;
2424 } else {
2425 i_poro_duq_0 = &_f_ext;
2426 i_poro_duq_1 = &_f_ext;
2427 b_poro_duq = &_f_ext;
2428 }
2429
2430 #if defined(HAVE_CUDA)
2431 bool accel = ( cs_get_device_id() > -1
2432 && cpl == NULL
2433 && hyd_p_flag == 0
2434 && is_porous == false) ? true : false;
2435 #else
2436 bool accel = false;
2437 #endif
2438
2439 _get_cell_cocg_lsq(m,
2440 halo_type,
2441 accel,
2442 fvq,
2443 cpl,
2444 &cocg,
2445 &cocgb);
2446
2447 #if defined(HAVE_CUDA)
2448
2449 if (accel) {
2450
2451 cs_gradient_scalar_lsq_cuda(m,
2452 fvq,
2453 halo_type,
2454 recompute_cocg,
2455 hyd_p_flag,
2456 inc,
2457 f_ext,
2458 coefap,
2459 coefbp,
2460 pvar,
2461 c_weight,
2462 cocg,
2463 cocgb,
2464 grad);
2465
2466 return;
2467
2468 }
2469
2470 #endif
2471
2472 bool *coupled_faces = (cpl == NULL) ?
2473 NULL : (bool *)cpl->coupled_faces;
2474
2475 /* Reconstruct gradients using least squares for non-orthogonal meshes */
2476 /*---------------------------------------------------------------------*/
2477
2478 /* Compute cocg and save contribution at boundaries */
2479
2480 if (recompute_cocg) {
2481
2482 /* Recompute cocg at boundaries, using saved cocgb */
2483
2484 # pragma omp parallel for
2485 for (cs_lnum_t ii = 0; ii < m->n_b_cells; ii++) {
2486 cs_lnum_t c_id = m->b_cells[ii];
2487 for (cs_lnum_t ll = 0; ll < 6; ll++)
2488 cocg[c_id][ll] = cocgb[ii][ll];
2489 }
2490
2491 for (int g_id = 0; g_id < n_b_groups; g_id++) {
2492
2493 # pragma omp parallel for
2494 for (int t_id = 0; t_id < n_b_threads; t_id++) {
2495
2496 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2497 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2498 f_id++) {
2499
2500 if (cpl == NULL || !coupled_faces[f_id]) {
2501
2502 cs_lnum_t ii = b_face_cells[f_id];
2503
2504 cs_real_t umcbdd = (1. - coefbp[f_id]) / b_dist[f_id];
2505 cs_real_t udbfs = 1. / b_face_surf[f_id];
2506
2507 cs_real_t dddij[3];
2508 for (cs_lnum_t ll = 0; ll < 3; ll++)
2509 dddij[ll] = udbfs * b_face_normal[f_id][ll]
2510 + umcbdd * diipb[f_id][ll];
2511
2512 cocg[ii][0] += dddij[0]*dddij[0];
2513 cocg[ii][1] += dddij[1]*dddij[1];
2514 cocg[ii][2] += dddij[2]*dddij[2];
2515 cocg[ii][3] += dddij[0]*dddij[1];
2516 cocg[ii][4] += dddij[1]*dddij[2];
2517 cocg[ii][5] += dddij[0]*dddij[2];
2518
2519 } /* face without internal coupling */
2520
2521 } /* loop on faces */
2522
2523 } /* loop on threads */
2524
2525 } /* loop on thread groups */
2526
2527 # pragma omp parallel for
2528 for (cs_lnum_t ii = 0; ii < m->n_b_cells; ii++) {
2529 cs_lnum_t c_id = m->b_cells[ii];
2530 _math_6_inv_cramer_sym_in_place(cocg[c_id]);
2531 }
2532
2533 } /* End of recompute_cocg */
2534
2535 /* Compute Right-Hand Side */
2536 /*-------------------------*/
2537
2538 cs_real_4_t *restrict rhsv;
2539 BFT_MALLOC(rhsv, n_cells_ext, cs_real_4_t);
2540
2541 # pragma omp parallel for
2542 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
2543 rhsv[c_id][0] = 0.0;
2544 rhsv[c_id][1] = 0.0;
2545 rhsv[c_id][2] = 0.0;
2546 rhsv[c_id][3] = pvar[c_id];
2547 }
2548
2549 /* Standard case, without hydrostatic pressure */
2550 /*---------------------------------------------*/
2551
2552 if (hyd_p_flag == 0) {
2553
2554 /* Contribution from interior faces */
2555
2556 for (int g_id = 0; g_id < n_i_groups; g_id++) {
2557
2558 # pragma omp parallel for
2559 for (int t_id = 0; t_id < n_i_threads; t_id++) {
2560
2561 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2562 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2563 f_id++) {
2564
2565 cs_lnum_t ii = i_face_cells[f_id][0];
2566 cs_lnum_t jj = i_face_cells[f_id][1];
2567
2568 cs_real_t pond = weight[f_id];
2569
2570 cs_real_t pfac, dc[3], fctb[4];
2571
2572 for (cs_lnum_t ll = 0; ll < 3; ll++)
2573 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2574
2575 if (c_weight != NULL) {
2576 /* (P_j - P_i) / ||d||^2 */
2577 pfac = (rhsv[jj][3] - rhsv[ii][3])
2578 / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2579
2580 for (cs_lnum_t ll = 0; ll < 3; ll++)
2581 fctb[ll] = dc[ll] * pfac;
2582
2583 cs_real_t denom = 1. / ( pond *c_weight[ii]
2584 + (1. - pond)*c_weight[jj]);
2585
2586 for (cs_lnum_t ll = 0; ll < 3; ll++)
2587 rhsv[ii][ll] += c_weight[jj] * denom * fctb[ll];
2588
2589 for (cs_lnum_t ll = 0; ll < 3; ll++)
2590 rhsv[jj][ll] += c_weight[ii] * denom * fctb[ll];
2591 }
2592 else {
2593 /* (P_j - P_i) / ||d||^2 */
2594 pfac = (rhsv[jj][3] - rhsv[ii][3])
2595 / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2596
2597 for (cs_lnum_t ll = 0; ll < 3; ll++)
2598 fctb[ll] = dc[ll] * pfac;
2599
2600 for (cs_lnum_t ll = 0; ll < 3; ll++)
2601 rhsv[ii][ll] += fctb[ll];
2602
2603 for (cs_lnum_t ll = 0; ll < 3; ll++)
2604 rhsv[jj][ll] += fctb[ll];
2605 }
2606
2607 } /* loop on faces */
2608
2609 } /* loop on threads */
2610
2611 } /* loop on thread groups */
2612
2613 /* Contribution from extended neighborhood */
2614
2615 if (halo_type == CS_HALO_EXTENDED && cell_cells_idx != NULL) {
2616
2617 # pragma omp parallel for
2618 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
2619 for (cs_lnum_t cidx = cell_cells_idx[ii];
2620 cidx < cell_cells_idx[ii+1];
2621 cidx++) {
2622
2623 cs_lnum_t jj = cell_cells_lst[cidx];
2624
2625 cs_real_t pfac, dc[3], fctb[4];
2626
2627 for (cs_lnum_t ll = 0; ll < 3; ll++)
2628 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2629
2630 pfac = (rhsv[jj][3] - rhsv[ii][3])
2631 / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2632
2633 for (cs_lnum_t ll = 0; ll < 3; ll++)
2634 fctb[ll] = dc[ll] * pfac;
2635
2636 for (cs_lnum_t ll = 0; ll < 3; ll++)
2637 rhsv[ii][ll] += fctb[ll];
2638
2639 }
2640 }
2641
2642 } /* End for extended neighborhood */
2643
2644 /* Contribution from coupled faces */
2645
2646 if (cpl != NULL)
2647 cs_internal_coupling_lsq_scalar_gradient
2648 (cpl, c_weight, 1, rhsv);
2649
2650 /* Contribution from boundary faces */
2651
2652 for (int g_id = 0; g_id < n_b_groups; g_id++) {
2653
2654 # pragma omp parallel for
2655 for (int t_id = 0; t_id < n_b_threads; t_id++) {
2656
2657 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2658 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2659 f_id++) {
2660
2661 if (cpl == NULL || !coupled_faces[f_id]) {
2662
2663 cs_lnum_t ii = b_face_cells[f_id];
2664
2665 cs_real_t unddij = 1. / b_dist[f_id];
2666 cs_real_t udbfs = 1. / b_face_surf[f_id];
2667 cs_real_t umcbdd = (1. - coefbp[f_id]) * unddij;
2668
2669 cs_real_t dsij[3];
2670 for (cs_lnum_t ll = 0; ll < 3; ll++)
2671 dsij[ll] = udbfs * b_face_normal[f_id][ll]
2672 + umcbdd*diipb[f_id][ll];
2673
2674 cs_real_t pfac = (coefap[f_id]*inc + (coefbp[f_id] -1.)
2675 * rhsv[ii][3]) * unddij;
2676
2677 for (cs_lnum_t ll = 0; ll < 3; ll++)
2678 rhsv[ii][ll] += dsij[ll] * pfac;
2679
2680 } /* face without internal coupling */
2681
2682 } /* loop on faces */
2683
2684 } /* loop on threads */
2685
2686 } /* loop on thread groups */
2687
2688 }
2689
2690 /* Case with hydrostatic pressure */
2691 /*--------------------------------*/
2692
2693 else { /* if hyd_p_flag == 1 */
2694
2695 /* Contribution from interior faces */
2696
2697 for (int g_id = 0; g_id < n_i_groups; g_id++) {
2698
2699 # pragma omp parallel for
2700 for (int t_id = 0; t_id < n_i_threads; t_id++) {
2701
2702 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2703 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2704 f_id++) {
2705
2706 cs_lnum_t ii = i_face_cells[f_id][0];
2707 cs_lnum_t jj = i_face_cells[f_id][1];
2708
2709 cs_real_2_t poro = {
2710 i_poro_duq_0[is_porous*f_id],
2711 i_poro_duq_1[is_porous*f_id]
2712 };
2713
2714 cs_real_t pond = weight[f_id];
2715
2716 cs_real_t pfac, dc[3], fctb[4];
2717
2718 for (cs_lnum_t ll = 0; ll < 3; ll++)
2719 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2720
2721 pfac = ( rhsv[jj][3] - rhsv[ii][3]
2722 + (cell_cen[ii][0] - i_face_cog[f_id][0]) * f_ext[ii][0]
2723 + (cell_cen[ii][1] - i_face_cog[f_id][1]) * f_ext[ii][1]
2724 + (cell_cen[ii][2] - i_face_cog[f_id][2]) * f_ext[ii][2]
2725 + poro[0]
2726 - (cell_cen[jj][0] - i_face_cog[f_id][0]) * f_ext[jj][0]
2727 - (cell_cen[jj][1] - i_face_cog[f_id][1]) * f_ext[jj][1]
2728 - (cell_cen[jj][2] - i_face_cog[f_id][2]) * f_ext[jj][2]
2729 - poro[1])
2730 / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2731
2732 for (cs_lnum_t ll = 0; ll < 3; ll++)
2733 fctb[ll] = dc[ll] * pfac;
2734
2735 if (c_weight != NULL) {
2736 cs_real_t denom = 1. / ( pond *c_weight[ii]
2737 + (1. - pond)*c_weight[jj]);
2738
2739 for (cs_lnum_t ll = 0; ll < 3; ll++)
2740 rhsv[ii][ll] += c_weight[jj] * denom * fctb[ll];
2741
2742 for (cs_lnum_t ll = 0; ll < 3; ll++)
2743 rhsv[jj][ll] += c_weight[ii] * denom * fctb[ll];
2744 }
2745 else { // no cell weighting
2746 for (cs_lnum_t ll = 0; ll < 3; ll++)
2747 rhsv[ii][ll] += fctb[ll];
2748
2749 for (cs_lnum_t ll = 0; ll < 3; ll++)
2750 rhsv[jj][ll] += fctb[ll];
2751 }
2752 } /* loop on faces */
2753
2754 } /* loop on threads */
2755
2756 } /* loop on thread groups */
2757
2758 /* Contribution from extended neighborhood;
2759 We assume that the middle of the segment joining cell centers
2760 may replace the center of gravity of a fictitious face. */
2761
2762 if (halo_type == CS_HALO_EXTENDED && cell_cells_idx != NULL) {
2763
2764 # pragma omp parallel for
2765 for (cs_lnum_t ii = 0; ii < n_cells; ii++) {
2766 for (cs_lnum_t cidx = cell_cells_idx[ii];
2767 cidx < cell_cells_idx[ii+1];
2768 cidx++) {
2769
2770 cs_lnum_t jj = cell_cells_lst[cidx];
2771
2772 /* Note: replaced the expressions:
2773 * a) ptmid = 0.5 * (cell_cen[jj] - cell_cen[ii])
2774 * b) (cell_cen[ii] - ptmid) * f_ext[ii]
2775 * c) - (cell_cen[jj] - ptmid) * f_ext[jj]
2776 * with:
2777 * a) dc = cell_cen[jj] - cell_cen[ii]
2778 * b) - 0.5 * dc * f_ext[ii]
2779 * c) - 0.5 * dc * f_ext[jj]
2780 */
2781
2782 cs_real_t pfac, dc[3], fctb[4];
2783
2784 for (cs_lnum_t ll = 0; ll < 3; ll++)
2785 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
2786
2787 pfac = ( rhsv[jj][3] - rhsv[ii][3]
2788 - 0.5 * dc[0] * f_ext[ii][0]
2789 - 0.5 * dc[1] * f_ext[ii][1]
2790 - 0.5 * dc[2] * f_ext[ii][2]
2791 - 0.5 * dc[0] * f_ext[jj][0]
2792 - 0.5 * dc[1] * f_ext[jj][1]
2793 - 0.5 * dc[2] * f_ext[jj][2])
2794 / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
2795
2796 for (cs_lnum_t ll = 0; ll < 3; ll++)
2797 fctb[ll] = dc[ll] * pfac;
2798
2799 for (cs_lnum_t ll = 0; ll < 3; ll++)
2800 rhsv[ii][ll] += fctb[ll];
2801
2802 }
2803 }
2804
2805 } /* End for extended neighborhood */
2806
2807 /* Contribution from boundary faces */
2808
2809 for (int g_id = 0; g_id < n_b_groups; g_id++) {
2810
2811 # pragma omp parallel for
2812 for (int t_id = 0; t_id < n_b_threads; t_id++) {
2813
2814 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
2815 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
2816 f_id++) {
2817
2818 cs_lnum_t ii = b_face_cells[f_id];
2819
2820 cs_real_t poro = b_poro_duq[is_porous*f_id];
2821
2822 cs_real_t unddij = 1. / b_dist[f_id];
2823 cs_real_t udbfs = 1. / b_face_surf[f_id];
2824 cs_real_t umcbdd = (1. - coefbp[f_id]) * unddij;
2825
2826 cs_real_t dsij[3];
2827 for (cs_lnum_t ll = 0; ll < 3; ll++)
2828 dsij[ll] = udbfs * b_face_normal[f_id][ll]
2829 + umcbdd*diipb[f_id][ll];
2830
2831 cs_real_t pfac
2832 = (coefap[f_id]*inc
2833 + ( (coefbp[f_id] -1.)
2834 * ( rhsv[ii][3]
2835 + (b_face_cog[f_id][0] - cell_cen[ii][0]) * f_ext[ii][0]
2836 + (b_face_cog[f_id][1] - cell_cen[ii][1]) * f_ext[ii][1]
2837 + (b_face_cog[f_id][2] - cell_cen[ii][2]) * f_ext[ii][2]
2838 + poro)))
2839 * unddij;
2840
2841 for (cs_lnum_t ll = 0; ll < 3; ll++)
2842 rhsv[ii][ll] += dsij[ll] * pfac;
2843
2844 } /* loop on faces */
2845
2846 } /* loop on threads */
2847
2848 } /* loop on thread groups */
2849
2850 } /* End of test on hydrostatic pressure */
2851
2852 /* Compute gradient */
2853 /*------------------*/
2854
2855 if (hyd_p_flag == 1) {
2856
2857 # pragma omp parallel for
2858 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
2859 grad[c_id][0] = cocg[c_id][0] *rhsv[c_id][0]
2860 + cocg[c_id][3] *rhsv[c_id][1]
2861 + cocg[c_id][5] *rhsv[c_id][2]
2862 + f_ext[c_id][0];
2863 grad[c_id][1] = cocg[c_id][3] *rhsv[c_id][0]
2864 + cocg[c_id][1] *rhsv[c_id][1]
2865 + cocg[c_id][4] *rhsv[c_id][2]
2866 + f_ext[c_id][1];
2867 grad[c_id][2] = cocg[c_id][5] *rhsv[c_id][0]
2868 + cocg[c_id][4] *rhsv[c_id][1]
2869 + cocg[c_id][2] *rhsv[c_id][2]
2870 + f_ext[c_id][2];
2871 }
2872
2873 }
2874 else {
2875
2876 # pragma omp parallel for
2877 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
2878 grad[c_id][0] = cocg[c_id][0] *rhsv[c_id][0]
2879 + cocg[c_id][3] *rhsv[c_id][1]
2880 + cocg[c_id][5] *rhsv[c_id][2];
2881 grad[c_id][1] = cocg[c_id][3] *rhsv[c_id][0]
2882 + cocg[c_id][1] *rhsv[c_id][1]
2883 + cocg[c_id][4] *rhsv[c_id][2];
2884 grad[c_id][2] = cocg[c_id][5] *rhsv[c_id][0]
2885 + cocg[c_id][4] *rhsv[c_id][1]
2886 + cocg[c_id][2] *rhsv[c_id][2];
2887 }
2888
2889 }
2890
2891 /* Synchronize halos */
2892
2893 _sync_scalar_gradient_halo(m, CS_HALO_STANDARD, grad);
2894
2895 BFT_FREE(rhsv);
2896 }
2897
2898 /*----------------------------------------------------------------------------
2899 * Compute cell gradient using least-squares reconstruction for non-orthogonal
2900 * meshes (nswrgp > 1) in the anisotropic case.
2901 *
2902 * cocg is computed to account for variable B.C.'s (flux).
2903 *
2904 * parameters:
2905 * m <-- pointer to associated mesh structure
2906 * fvq <-- pointer to associated finite volume quantities
2907 * cpl <-- structure associated with internal coupling, or NULL
2908 * w_stride <-- stride for weighting coefficient
2909 * inc <-- if 0, solve on increment; 1 otherwise
2910 * coefap <-- B.C. coefficients for boundary face normals
2911 * coefbp <-- B.C. coefficients for boundary face normals
2912 * pvar <-- variable
2913 * c_weight <-- weighted gradient coefficient variable,
2914 * or NULL
2915 * grad <-> gradient of pvar (halo prepared for periodicity
2916 * of rotation)
2917 *----------------------------------------------------------------------------*/
2918
2919 static void
_lsq_scalar_gradient_ani(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,cs_real_t inc,const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t pvar[],const cs_real_t c_weight[restrict][6],cs_real_t grad[restrict][3])2920 _lsq_scalar_gradient_ani(const cs_mesh_t *m,
2921 const cs_mesh_quantities_t *fvq,
2922 const cs_internal_coupling_t *cpl,
2923 cs_real_t inc,
2924 const cs_real_t coefap[],
2925 const cs_real_t coefbp[],
2926 const cs_real_t pvar[],
2927 const cs_real_t c_weight[restrict][6],
2928 cs_real_t grad[restrict][3])
2929 {
2930 const cs_lnum_t n_cells = m->n_cells;
2931 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
2932 const int n_i_groups = m->i_face_numbering->n_groups;
2933 const int n_i_threads = m->i_face_numbering->n_threads;
2934 const int n_b_groups = m->b_face_numbering->n_groups;
2935 const int n_b_threads = m->b_face_numbering->n_threads;
2936 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
2937 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
2938
2939 const cs_lnum_2_t *restrict i_face_cells
2940 = (const cs_lnum_2_t *restrict)m->i_face_cells;
2941 const cs_lnum_t *restrict b_face_cells
2942 = (const cs_lnum_t *restrict)m->b_face_cells;
2943
2944 const cs_real_3_t *restrict cell_cen
2945 = (const cs_real_3_t *restrict)fvq->cell_cen;
2946 const cs_real_3_t *restrict b_face_normal
2947 = (const cs_real_3_t *restrict)fvq->b_face_normal;
2948 const cs_real_t *restrict b_face_surf
2949 = (const cs_real_t *restrict)fvq->b_face_surf;
2950 const cs_real_t *restrict b_dist
2951 = (const cs_real_t *restrict)fvq->b_dist;
2952 const cs_real_3_t *restrict diipb
2953 = (const cs_real_3_t *restrict)fvq->diipb;
2954 const cs_real_t *restrict weight = fvq->weight;
2955
2956 bool *coupled_faces = (cpl == NULL) ?
2957 NULL : (bool *)cpl->coupled_faces;
2958
2959 cs_real_4_t *restrict rhsv;
2960 BFT_MALLOC(rhsv, n_cells_ext, cs_real_4_t);
2961
2962 cs_cocg_6_t *restrict cocg = NULL;
2963 BFT_MALLOC(cocg, n_cells_ext, cs_cocg_6_t);
2964
2965 # pragma omp parallel for
2966 for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
2967 for (cs_lnum_t ll = 0; ll < 6; ll++)
2968 cocg[cell_id][ll] = 0.0;
2969 }
2970
2971 # pragma omp parallel for
2972 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
2973 rhsv[c_id][0] = 0.0;
2974 rhsv[c_id][1] = 0.0;
2975 rhsv[c_id][2] = 0.0;
2976 rhsv[c_id][3] = pvar[c_id];
2977 }
2978
2979 /* Reconstruct gradients using least squares for non-orthogonal meshes */
2980 /*---------------------------------------------------------------------*/
2981
2982 /* Contribution from interior faces */
2983
2984 for (int g_id = 0; g_id < n_i_groups; g_id++) {
2985
2986 # pragma omp parallel for
2987 for (int t_id = 0; t_id < n_i_threads; t_id++) {
2988
2989 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
2990 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
2991 f_id++) {
2992
2993 cs_real_t dc[3], dc_i[3], dc_j[3];
2994
2995 cs_lnum_t ii = i_face_cells[f_id][0];
2996 cs_lnum_t jj = i_face_cells[f_id][1];
2997
2998 cs_real_t pond = weight[f_id];
2999
3000 for (cs_lnum_t ll = 0; ll < 3; ll++)
3001 dc[ll] = cell_cen[jj][ll] - cell_cen[ii][ll];
3002
3003 /* cocg contribution */
3004
3005 _compute_ani_weighting_cocg(c_weight[ii],
3006 c_weight[jj],
3007 dc,
3008 pond,
3009 dc_i,
3010 dc_j);
3011
3012 cs_real_t i_dci = 1. / cs_math_3_square_norm(dc_i);
3013 cs_real_t i_dcj = 1. / cs_math_3_square_norm(dc_j);
3014
3015 cocg[ii][0] += dc_i[0] * dc_i[0] * i_dci;
3016 cocg[ii][1] += dc_i[1] * dc_i[1] * i_dci;
3017 cocg[ii][2] += dc_i[2] * dc_i[2] * i_dci;
3018 cocg[ii][3] += dc_i[0] * dc_i[1] * i_dci;
3019 cocg[ii][4] += dc_i[1] * dc_i[2] * i_dci;
3020 cocg[ii][5] += dc_i[0] * dc_i[2] * i_dci;
3021
3022 cocg[jj][0] += dc_j[0] * dc_j[0] * i_dcj;
3023 cocg[jj][1] += dc_j[1] * dc_j[1] * i_dcj;
3024 cocg[jj][2] += dc_j[2] * dc_j[2] * i_dcj;
3025 cocg[jj][3] += dc_j[0] * dc_j[1] * i_dcj;
3026 cocg[jj][4] += dc_j[1] * dc_j[2] * i_dcj;
3027 cocg[jj][5] += dc_j[0] * dc_j[2] * i_dcj;
3028
3029 /* RHS contribution */
3030
3031 /* (P_j - P_i)*/
3032 cs_real_t p_diff = (rhsv[jj][3] - rhsv[ii][3]);
3033
3034 _compute_ani_weighting(c_weight[ii],
3035 c_weight[jj],
3036 p_diff,
3037 dc,
3038 pond,
3039 rhsv[ii],
3040 rhsv[jj]);
3041 } /* loop on faces */
3042
3043 } /* loop on threads */
3044
3045 } /* loop on thread groups */
3046
3047 /* Contribution from coupled faces */
3048
3049 if (cpl != NULL) {
3050 cs_internal_coupling_lsq_cocg_weighted
3051 (cpl, (const cs_real_t *)c_weight, cocg);
3052 cs_internal_coupling_lsq_scalar_gradient
3053 (cpl, (const cs_real_t *)c_weight, 6, rhsv);
3054 }
3055
3056 /* Contribution from boundary faces */
3057
3058 for (int g_id = 0; g_id < n_b_groups; g_id++) {
3059
3060 # pragma omp parallel for
3061 for (int t_id = 0; t_id < n_b_threads; t_id++) {
3062
3063 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
3064 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
3065 f_id++) {
3066
3067 if (cpl == NULL || !coupled_faces[f_id]) {
3068
3069 cs_real_t dsij[3];
3070
3071 cs_lnum_t ii = b_face_cells[f_id];
3072
3073 cs_real_t umcbdd = (1. - coefbp[f_id]) / b_dist[f_id];
3074 cs_real_t udbfs = 1. / b_face_surf[f_id];
3075
3076 cs_real_t unddij = 1. / b_dist[f_id];
3077
3078 for (cs_lnum_t ll = 0; ll < 3; ll++)
3079 dsij[ll] = udbfs * b_face_normal[f_id][ll]
3080 + umcbdd*diipb[f_id][ll];
3081
3082 /* cocg contribution */
3083
3084 cocg[ii][0] += dsij[0]*dsij[0];
3085 cocg[ii][1] += dsij[1]*dsij[1];
3086 cocg[ii][2] += dsij[2]*dsij[2];
3087 cocg[ii][3] += dsij[0]*dsij[1];
3088 cocg[ii][4] += dsij[1]*dsij[2];
3089 cocg[ii][5] += dsij[0]*dsij[2];
3090
3091 /* RHS contribution */
3092
3093 cs_real_t pfac = (coefap[f_id]*inc + (coefbp[f_id] -1.)*rhsv[ii][3])
3094 * unddij;
3095
3096 for (cs_lnum_t ll = 0; ll < 3; ll++)
3097 rhsv[ii][ll] += dsij[ll] * pfac;
3098
3099 } /* face without internal coupling */
3100
3101 } /* loop on faces */
3102
3103 } /* loop on threads */
3104
3105 } /* loop on thread groups */
3106
3107 /* Invert cocg for all cells. */
3108 /*----------------------------*/
3109
3110 # pragma omp parallel for
3111 for (cs_lnum_t cell_id = 0; cell_id < n_cells; cell_id++)
3112 _math_6_inv_cramer_sym_in_place(cocg[cell_id]);
3113
3114 /* Compute gradient */
3115 /*------------------*/
3116
3117 # pragma omp parallel for
3118 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
3119 grad[c_id][0] = cocg[c_id][0] * rhsv[c_id][0]
3120 + cocg[c_id][3] * rhsv[c_id][1]
3121 + cocg[c_id][5] * rhsv[c_id][2];
3122 grad[c_id][1] = cocg[c_id][3] * rhsv[c_id][0]
3123 + cocg[c_id][1] * rhsv[c_id][1]
3124 + cocg[c_id][4] * rhsv[c_id][2];
3125 grad[c_id][2] = cocg[c_id][5] * rhsv[c_id][0]
3126 + cocg[c_id][4] * rhsv[c_id][1]
3127 + cocg[c_id][2] * rhsv[c_id][2];
3128 }
3129
3130 /* Synchronize halos */
3131
3132 _sync_scalar_gradient_halo(m, CS_HALO_STANDARD, grad);
3133
3134 BFT_FREE(cocg);
3135 BFT_FREE(rhsv);
3136 }
3137
3138 /*----------------------------------------------------------------------------
3139 * Reconstruct the gradient of a scalar using a given gradient of
3140 * this scalar (typically lsq).
3141 *
3142 * Optionally, a volume force generating a hydrostatic pressure component
3143 * may be accounted for.
3144 *
3145 * parameters:
3146 * m <-- pointer to associated mesh structure
3147 * fvq <-- pointer to associated finite volume quantities
3148 * cpl <-> structure associated with internal coupling, or NULL
3149 * hyd_p_flag <-- flag for hydrostatic pressure
3150 * inc <-- if 0, solve on increment; 1 otherwise
3151 * f_ext <-- exterior force generating pressure
3152 * coefap <-- B.C. coefficients for boundary face normals
3153 * coefbp <-- B.C. coefficients for boundary face normals
3154 * c_weight <-- weighted gradient coefficient variable
3155 * c_var <-- variable
3156 * r_grad <-- gradient used for reconstruction
3157 * grad <-> gradient of c_var (halo prepared for periodicity
3158 * of rotation)
3159 *----------------------------------------------------------------------------*/
3160
3161 static void
_reconstruct_scalar_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,int hyd_p_flag,cs_real_t inc,const cs_real_t f_ext[][3],const cs_real_t coefap[],const cs_real_t coefbp[],const cs_real_t c_weight[],const cs_real_t c_var[],cs_real_3_t * restrict r_grad,cs_real_3_t * restrict grad)3162 _reconstruct_scalar_gradient(const cs_mesh_t *m,
3163 const cs_mesh_quantities_t *fvq,
3164 const cs_internal_coupling_t *cpl,
3165 int hyd_p_flag,
3166 cs_real_t inc,
3167 const cs_real_t f_ext[][3],
3168 const cs_real_t coefap[],
3169 const cs_real_t coefbp[],
3170 const cs_real_t c_weight[],
3171 const cs_real_t c_var[],
3172 cs_real_3_t *restrict r_grad,
3173 cs_real_3_t *restrict grad)
3174 {
3175 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
3176 const cs_lnum_t n_cells = m->n_cells;
3177 const int n_i_groups = m->i_face_numbering->n_groups;
3178 const int n_i_threads = m->i_face_numbering->n_threads;
3179 const int n_b_groups = m->b_face_numbering->n_groups;
3180 const int n_b_threads = m->b_face_numbering->n_threads;
3181 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
3182 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
3183
3184 const cs_lnum_2_t *restrict i_face_cells
3185 = (const cs_lnum_2_t *restrict)m->i_face_cells;
3186 const cs_lnum_t *restrict b_face_cells
3187 = (const cs_lnum_t *restrict)m->b_face_cells;
3188
3189 const int *restrict c_disable_flag = fvq->c_disable_flag;
3190 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
3191
3192 const cs_real_t *restrict weight = fvq->weight;
3193 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
3194 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
3195 cell_f_vol = fvq->cell_vol;
3196 const cs_real_3_t *restrict cell_cen
3197 = (const cs_real_3_t *restrict)fvq->cell_cen;
3198 const cs_real_3_t *restrict i_f_face_normal
3199 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
3200 const cs_real_3_t *restrict b_f_face_normal
3201 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
3202 const cs_real_3_t *restrict i_face_cog
3203 = (const cs_real_3_t *restrict)fvq->i_face_cog;
3204 const cs_real_3_t *restrict b_face_cog
3205 = (const cs_real_3_t *restrict)fvq->b_face_cog;
3206
3207 const cs_real_3_t *restrict dofij
3208 = (const cs_real_3_t *restrict)fvq->dofij;
3209 const cs_real_3_t *restrict diipb
3210 = (const cs_real_3_t *restrict)fvq->diipb;
3211
3212 const cs_real_33_t *restrict corr_grad_lin
3213 = (const cs_real_33_t *restrict)fvq->corr_grad_lin;
3214
3215 bool *coupled_faces = (cpl == NULL) ?
3216 NULL : (bool *)cpl->coupled_faces;
3217
3218 /*Additional terms due to porosity */
3219 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
3220
3221 cs_real_t *i_poro_duq_0;
3222 cs_real_t *i_poro_duq_1;
3223 cs_real_t *b_poro_duq;
3224 cs_real_t _f_ext = 0.;
3225
3226 cs_lnum_t is_porous = 0;
3227 if (f_i_poro_duq_0 != NULL) {
3228 is_porous = 1;
3229 i_poro_duq_0 = f_i_poro_duq_0->val;
3230 i_poro_duq_1 = cs_field_by_name("i_poro_duq_1")->val;
3231 b_poro_duq = cs_field_by_name("b_poro_duq")->val;
3232 } else {
3233 i_poro_duq_0 = &_f_ext;
3234 i_poro_duq_1 = &_f_ext;
3235 b_poro_duq = &_f_ext;
3236 }
3237
3238 /* Initialize gradient */
3239 /*---------------------*/
3240
3241 # pragma omp parallel for
3242 for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
3243 for (cs_lnum_t j = 0; j < 3; j++)
3244 grad[cell_id][j] = 0.0;
3245 }
3246
3247 /* Case with hydrostatic pressure */
3248 /*--------------------------------*/
3249
3250 if (hyd_p_flag == 1) {
3251
3252 /* Contribution from interior faces */
3253
3254 for (int g_id = 0; g_id < n_i_groups; g_id++) {
3255
3256 # pragma omp parallel for
3257 for (int t_id = 0; t_id < n_i_threads; t_id++) {
3258
3259 cs_real_t fexd[3];
3260
3261 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3262 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3263 f_id++) {
3264
3265 cs_lnum_t c_id1 = i_face_cells[f_id][0];
3266 cs_lnum_t c_id2 = i_face_cells[f_id][1];
3267
3268 cs_real_t ktpond = (c_weight == NULL) ?
3269 weight[f_id] : /* no cell weighting */
3270 weight[f_id] * c_weight[c_id1] /* cell weighting active */
3271 / ( weight[f_id] * c_weight[c_id1]
3272 + (1.0-weight[f_id])* c_weight[c_id2]);
3273
3274 cs_real_2_t poro = {
3275 i_poro_duq_0[is_porous*f_id],
3276 i_poro_duq_1[is_porous*f_id]
3277 };
3278
3279 fexd[0] = 0.5 * (f_ext[c_id1][0] + f_ext[c_id2][0]);
3280 fexd[1] = 0.5 * (f_ext[c_id1][1] + f_ext[c_id2][1]);
3281 fexd[2] = 0.5 * (f_ext[c_id1][2] + f_ext[c_id2][2]);
3282
3283 /*
3284 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
3285 + (1-\alpha_\ij) \varia_\cellj\f$
3286 but for the cell \f$ \celli \f$ we remove
3287 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
3288 and for the cell \f$ \cellj \f$ we remove
3289 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
3290 */
3291
3292 cs_real_t pfaci
3293 = ktpond
3294 * ( (i_face_cog[f_id][0] - cell_cen[c_id1][0])*f_ext[c_id1][0]
3295 + (i_face_cog[f_id][1] - cell_cen[c_id1][1])*f_ext[c_id1][1]
3296 + (i_face_cog[f_id][2] - cell_cen[c_id1][2])*f_ext[c_id1][2]
3297 + poro[0])
3298 + (1.0 - ktpond)
3299 * ( (i_face_cog[f_id][0] - cell_cen[c_id2][0])*f_ext[c_id2][0]
3300 + (i_face_cog[f_id][1] - cell_cen[c_id2][1])*f_ext[c_id2][1]
3301 + (i_face_cog[f_id][2] - cell_cen[c_id2][2])*f_ext[c_id2][2]
3302 + poro[1]);
3303
3304 cs_real_t pfacj = pfaci;
3305
3306 pfaci += (1.0-ktpond) * (c_var[c_id2] - c_var[c_id1]);
3307 pfacj -= ktpond * (c_var[c_id2] - c_var[c_id1]);
3308
3309 /* Reconstruction part */
3310 cs_real_t rfac =
3311 weight[f_id]
3312 * ( (cell_cen[c_id1][0]-i_face_cog[f_id][0])*fexd[0]
3313 + (cell_cen[c_id1][1]-i_face_cog[f_id][1])*fexd[1]
3314 + (cell_cen[c_id1][2]-i_face_cog[f_id][2])*fexd[2])
3315 + (1.0 - weight[f_id])
3316 * ( (cell_cen[c_id2][0]-i_face_cog[f_id][0])*fexd[0]
3317 + (cell_cen[c_id2][1]-i_face_cog[f_id][1])*fexd[1]
3318 + (cell_cen[c_id2][2]-i_face_cog[f_id][2])*fexd[2])
3319 + ( dofij[f_id][0] * (r_grad[c_id1][0]+r_grad[c_id2][0])
3320 + dofij[f_id][1] * (r_grad[c_id1][1]+r_grad[c_id2][1])
3321 + dofij[f_id][2] * (r_grad[c_id1][2]+r_grad[c_id2][2])) * 0.5;
3322
3323 for (cs_lnum_t j = 0; j < 3; j++) {
3324 grad[c_id1][j] += (pfaci + rfac) * i_f_face_normal[f_id][j];
3325 grad[c_id2][j] -= (pfacj + rfac) * i_f_face_normal[f_id][j];
3326 }
3327
3328 } /* loop on faces */
3329
3330 } /* loop on threads */
3331
3332 } /* loop on thread groups */
3333
3334 /* Contribution from boundary faces */
3335
3336 for (int g_id = 0; g_id < n_b_groups; g_id++) {
3337
3338 # pragma omp parallel for
3339 for (int t_id = 0; t_id < n_b_threads; t_id++) {
3340
3341 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
3342 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
3343 f_id++) {
3344
3345 cs_lnum_t c_id = b_face_cells[f_id];
3346
3347 cs_real_t poro = b_poro_duq[is_porous*f_id];
3348
3349 /*
3350 Remark: for the cell \f$ \celli \f$ we remove
3351 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
3352 */
3353
3354 cs_real_t pfac
3355 = coefap[f_id] * inc
3356 + coefbp[f_id]
3357 * ( (b_face_cog[f_id][0] - cell_cen[c_id][0])*f_ext[c_id][0]
3358 + (b_face_cog[f_id][1] - cell_cen[c_id][1])*f_ext[c_id][1]
3359 + (b_face_cog[f_id][2] - cell_cen[c_id][2])*f_ext[c_id][2]
3360 + poro);
3361
3362 pfac += (coefbp[f_id] - 1.0) * c_var[c_id];
3363
3364 /* Reconstruction part */
3365 cs_real_t
3366 rfac = coefbp[f_id]
3367 * ( diipb[f_id][0] * (r_grad[c_id][0] - f_ext[c_id][0])
3368 + diipb[f_id][1] * (r_grad[c_id][1] - f_ext[c_id][1])
3369 + diipb[f_id][2] * (r_grad[c_id][2] - f_ext[c_id][2]));
3370
3371 for (cs_lnum_t j = 0; j < 3; j++) {
3372 grad[c_id][j] += (pfac + rfac) * b_f_face_normal[f_id][j];
3373 }
3374
3375 } /* loop on faces */
3376
3377 } /* loop on threads */
3378
3379 } /* loop on thread groups */
3380
3381 } /* End of test on hydrostatic pressure */
3382
3383
3384 /* Standard case, without hydrostatic pressure */
3385 /*---------------------------------------------*/
3386
3387 else {
3388
3389 /* Contribution from interior faces */
3390
3391 for (int g_id = 0; g_id < n_i_groups; g_id++) {
3392
3393 # pragma omp parallel for
3394 for (int t_id = 0; t_id < n_i_threads; t_id++) {
3395
3396 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
3397 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
3398 f_id++) {
3399
3400 cs_lnum_t c_id1 = i_face_cells[f_id][0];
3401 cs_lnum_t c_id2 = i_face_cells[f_id][1];
3402
3403 cs_real_t ktpond = (c_weight == NULL) ?
3404 weight[f_id] : /* no cell weighting */
3405 weight[f_id] * c_weight[c_id1] /* cell weighting active */
3406 / ( weight[f_id] * c_weight[c_id1]
3407 + (1.0-weight[f_id])* c_weight[c_id2]);
3408
3409 /*
3410 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
3411 + (1-\alpha_\ij) \varia_\cellj\f$
3412 but for the cell \f$ \celli \f$ we remove
3413 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
3414 and for the cell \f$ \cellj \f$ we remove
3415 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
3416 */
3417
3418 cs_real_t pfaci = (1.0-ktpond) * (c_var[c_id2] - c_var[c_id1]);
3419 cs_real_t pfacj = -ktpond * (c_var[c_id2] - c_var[c_id1]);
3420 /* Reconstruction part */
3421 cs_real_t rfac = 0.5 *
3422 (dofij[f_id][0]*(r_grad[c_id1][0]+r_grad[c_id2][0])
3423 +dofij[f_id][1]*(r_grad[c_id1][1]+r_grad[c_id2][1])
3424 +dofij[f_id][2]*(r_grad[c_id1][2]+r_grad[c_id2][2]));
3425
3426 for (cs_lnum_t j = 0; j < 3; j++) {
3427 grad[c_id1][j] += (pfaci + rfac) * i_f_face_normal[f_id][j];
3428 grad[c_id2][j] -= (pfacj + rfac) * i_f_face_normal[f_id][j];
3429 }
3430
3431 } /* loop on faces */
3432
3433 } /* loop on threads */
3434
3435 } /* loop on thread groups */
3436
3437 /* Contribution from coupled faces */
3438 if (cpl != NULL) {
3439 cs_internal_coupling_initialize_scalar_gradient(cpl, c_weight, c_var, grad);
3440 cs_internal_coupling_reconstruct_scalar_gradient(cpl, r_grad, grad);
3441 }
3442
3443 /* Contribution from boundary faces */
3444
3445 for (int g_id = 0; g_id < n_b_groups; g_id++) {
3446
3447 # pragma omp parallel for
3448 for (int t_id = 0; t_id < n_b_threads; t_id++) {
3449
3450 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
3451 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
3452 f_id++) {
3453
3454 if (cpl == NULL || !coupled_faces[f_id]) {
3455
3456 cs_lnum_t c_id = b_face_cells[f_id];
3457
3458 /*
3459 Remark: for the cell \f$ \celli \f$ we remove
3460 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
3461 */
3462
3463 cs_real_t pfac = inc*coefap[f_id]
3464 + (coefbp[f_id]-1.0)*c_var[c_id];
3465
3466 /* Reconstruction part */
3467 cs_real_t
3468 rfac = coefbp[f_id]
3469 * ( diipb[f_id][0] * r_grad[c_id][0]
3470 + diipb[f_id][1] * r_grad[c_id][1]
3471 + diipb[f_id][2] * r_grad[c_id][2]);
3472
3473 for (cs_lnum_t j = 0; j < 3; j++) {
3474 grad[c_id][j] += (pfac + rfac) * b_f_face_normal[f_id][j];
3475 }
3476
3477 }
3478
3479 } /* loop on faces */
3480
3481 } /* loop on threads */
3482
3483 } /* loop on thread groups */
3484
3485 }
3486
3487 # pragma omp parallel for
3488 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
3489 cs_real_t dvol;
3490 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
3491 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
3492 dvol = 1. / cell_f_vol[c_id];
3493 else
3494 dvol = 0.;
3495
3496 grad[c_id][0] *= dvol;
3497 grad[c_id][1] *= dvol;
3498 grad[c_id][2] *= dvol;
3499
3500 if (cs_glob_mesh_quantities_flag & CS_BAD_CELLS_WARPED_CORRECTION) {
3501 cs_real_3_t gradpa;
3502 for (cs_lnum_t i = 0; i < 3; i++) {
3503 gradpa[i] = grad[c_id][i];
3504 grad[c_id][i] = 0.;
3505 }
3506
3507 for (cs_lnum_t i = 0; i < 3; i++)
3508 for (cs_lnum_t j = 0; j < 3; j++)
3509 grad[c_id][i] += corr_grad_lin[c_id][i][j] * gradpa[j];
3510 }
3511 }
3512
3513 /* Synchronize halos */
3514
3515 _sync_scalar_gradient_halo(m, CS_HALO_EXTENDED, grad);
3516 }
3517
3518 /*----------------------------------------------------------------------------
3519 * Compute boundary face scalar values using least-squares reconstruction
3520 * for non-orthogonal meshes.
3521 *
3522 * parameters:
3523 * m <-- pointer to associated mesh structure
3524 * fvq <-- pointer to associated finite volume quantities
3525 * cpl <-- structure associated with internal coupling, or NULL
3526 * halo_type <-- halo type (extended or not)
3527 * recompute_cocg <-- flag to recompute cocg
3528 * nswrgp <-- number of sweeps for gradient reconstruction
3529 * inc <-- if 0, solve on increment; 1 otherwise
3530 * bc_coeff_a <-- B.C. coefficients for boundary face normals
3531 * bc_coeff_b <-- B.C. coefficients for boundary face normals
3532 * c_var <-- variable
3533 * c_weight <-- weighted gradient coefficient variable,
3534 * or NULL
3535 * b_f_var --> boundary face value.
3536 *----------------------------------------------------------------------------*/
3537
3538 static void
_lsq_scalar_b_face_val(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_halo_type_t halo_type,cs_real_t inc,const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t c_var[],const cs_real_t c_weight[],cs_real_t b_f_var[restrict])3539 _lsq_scalar_b_face_val(const cs_mesh_t *m,
3540 const cs_mesh_quantities_t *fvq,
3541 cs_halo_type_t halo_type,
3542 cs_real_t inc,
3543 const cs_real_t bc_coeff_a[],
3544 const cs_real_t bc_coeff_b[],
3545 const cs_real_t c_var[],
3546 const cs_real_t c_weight[],
3547 cs_real_t b_f_var[restrict])
3548 {
3549 const cs_lnum_t n_b_cells = m->n_b_cells;
3550
3551 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
3552 const cs_lnum_t *restrict cell_b_faces_idx
3553 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
3554 const cs_lnum_t *restrict cell_b_faces
3555 = (const cs_lnum_t *restrict) ma->cell_b_faces;
3556
3557 const cs_real_3_t *restrict diipb
3558 = (const cs_real_3_t *restrict)fvq->diipb;
3559
3560 cs_real_t *_bc_coeff_a = NULL;
3561
3562 if (inc < 1) {
3563 BFT_MALLOC(_bc_coeff_a, m->n_b_faces, cs_real_t);
3564 for (cs_lnum_t i = 0; i < m->n_b_faces; i++)
3565 _bc_coeff_a[i] = 0;
3566 bc_coeff_a = (const cs_real_t*)_bc_coeff_a;
3567 }
3568
3569 /* Reconstruct gradients using least squares for non-orthogonal meshes */
3570
3571 # pragma omp parallel for if (n_b_cells > CS_THR_MIN)
3572 for (cs_lnum_t ci = 0; ci < n_b_cells; ci++) {
3573
3574 cs_real_t grad[3];
3575 cs_lnum_t c_id = m->b_cells[ci];
3576
3577 cs_gradient_scalar_cell(m,
3578 fvq,
3579 c_id,
3580 halo_type,
3581 bc_coeff_a,
3582 bc_coeff_b,
3583 c_var,
3584 c_weight,
3585 grad);
3586
3587 /* Update boundary face value */
3588
3589 cs_lnum_t s_id = cell_b_faces_idx[c_id];
3590 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
3591
3592 for (cs_lnum_t i = s_id; i < e_id; i++) {
3593
3594 cs_lnum_t f_id = cell_b_faces[i];
3595
3596 cs_real_t pip = c_var[c_id]
3597 + cs_math_3_dot_product(diipb[f_id], grad);
3598 b_f_var[f_id] = bc_coeff_a[f_id]*inc + pip*bc_coeff_b[f_id];
3599
3600 }
3601 }
3602
3603 BFT_FREE(_bc_coeff_a);
3604 }
3605
3606 /*----------------------------------------------------------------------------
3607 * Compute boundary face scalar values using least-squares reconstruction
3608 * for non-orthogonal meshes in the presence of a volume force generating
3609 * a hydrostatic pressure component.
3610 *
3611 * parameters:
3612 * m <-- pointer to associated mesh structure
3613 * fvq <-- pointer to associated finite volume quantities
3614 * cpl <-- structure associated with internal coupling, or NULL
3615 * halo_type <-- halo type (extended or not)
3616 * recompute_cocg <-- flag to recompute cocg
3617 * nswrgp <-- number of sweeps for gradient reconstruction
3618 * inc <-- if 0, solve on increment; 1 otherwise
3619 * f_ext <-- exterior force generating pressure
3620 * bc_coeff_a <-- B.C. coefficients for boundary face normals
3621 * bc_coeff_b <-- B.C. coefficients for boundary face normals
3622 * c_var <-- cell variable
3623 * c_weight <-- weighted gradient coefficient variable,
3624 * or NULL
3625 * b_f_var --> boundary face value.
3626 *----------------------------------------------------------------------------*/
3627
3628 static void
_lsq_scalar_b_face_val_phyd(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_halo_type_t halo_type,cs_real_t inc,const cs_real_t f_ext[][3],const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t c_var[],const cs_real_t c_weight[],cs_real_t b_f_var[restrict])3629 _lsq_scalar_b_face_val_phyd(const cs_mesh_t *m,
3630 const cs_mesh_quantities_t *fvq,
3631 cs_halo_type_t halo_type,
3632 cs_real_t inc,
3633 const cs_real_t f_ext[][3],
3634 const cs_real_t bc_coeff_a[],
3635 const cs_real_t bc_coeff_b[],
3636 const cs_real_t c_var[],
3637 const cs_real_t c_weight[],
3638 cs_real_t b_f_var[restrict])
3639 {
3640 const cs_lnum_t n_b_cells = m->n_b_cells;
3641
3642 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
3643 const cs_lnum_t *restrict cell_cells_idx
3644 = (const cs_lnum_t *restrict) ma->cell_cells_idx;
3645 const cs_lnum_t *restrict cell_cells_e_idx
3646 = (const cs_lnum_t *restrict) ma->cell_cells_e_idx;
3647 const cs_lnum_t *restrict cell_b_faces_idx
3648 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
3649 const cs_lnum_t *restrict cell_cells
3650 = (const cs_lnum_t *restrict) ma->cell_cells;
3651 const cs_lnum_t *restrict cell_cells_e
3652 = (const cs_lnum_t *restrict) ma->cell_cells_e;
3653 const cs_lnum_t *restrict cell_b_faces
3654 = (const cs_lnum_t *restrict) ma->cell_b_faces;
3655
3656 const cs_real_3_t *restrict cell_cen
3657 = (const cs_real_3_t *restrict)fvq->cell_cen;
3658 const cs_real_3_t *restrict b_face_cog
3659 = (const cs_real_3_t *restrict)fvq->b_face_cog;
3660 const cs_real_3_t *restrict b_face_normal
3661 = (const cs_real_3_t *restrict)fvq->b_face_normal;
3662 const cs_real_t *restrict b_dist
3663 = (const cs_real_t *restrict)fvq->b_dist;
3664 const cs_real_3_t *restrict diipb
3665 = (const cs_real_3_t *restrict)fvq->diipb;
3666
3667 /*Additional terms due to porosity */
3668
3669 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
3670
3671 cs_real_t *b_poro_duq;
3672 cs_real_t _f_ext = 0.;
3673
3674 cs_lnum_t is_porous = false;
3675 if (f_i_poro_duq_0 != NULL) {
3676 is_porous = 1;
3677 b_poro_duq = cs_field_by_name_try("b_poro_duq")->val;
3678 }
3679 else {
3680 b_poro_duq = &_f_ext;
3681 }
3682
3683 /* Reconstruct gradients using least squares for non-orthogonal meshes */
3684
3685 # pragma omp parallel for if (n_b_cells > CS_THR_MIN)
3686 for (cs_lnum_t ci = 0; ci < n_b_cells; ci++) {
3687
3688 cs_lnum_t c_id = m->b_cells[ci];
3689
3690 cs_real_t cocg[6] = {0., 0., 0., 0., 0., 0.};
3691 cs_real_t rhsv[3] = {0., 0., 0.};
3692
3693 int n_adj = (halo_type == CS_HALO_EXTENDED) ? 2 : 1;
3694
3695 for (int adj_id = 0; adj_id < n_adj; adj_id++) {
3696
3697 const cs_lnum_t *restrict cell_cells_p;
3698 cs_lnum_t s_id, e_id;
3699
3700 if (adj_id == 0){
3701 s_id = cell_cells_idx[c_id];
3702 e_id = cell_cells_idx[c_id+1];
3703 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells);
3704 }
3705 else if (cell_cells_e_idx != NULL){
3706 s_id = cell_cells_e_idx[c_id];
3707 e_id = cell_cells_e_idx[c_id+1];
3708 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells_e);
3709 }
3710 else
3711 break;
3712
3713 if (c_weight == NULL) {
3714
3715 for (cs_lnum_t i = s_id; i < e_id; i++) {
3716
3717 cs_real_t dc[3];
3718 cs_lnum_t c_id1 = cell_cells_p[i];
3719 for (cs_lnum_t ll = 0; ll < 3; ll++)
3720 dc[ll] = cell_cen[c_id1][ll] - cell_cen[c_id][ll];
3721
3722 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
3723
3724 cs_real_t pfac = ( c_var[c_id1] - c_var[c_id]
3725 - 0.5 * dc[0] * f_ext[c_id][0]
3726 - 0.5 * dc[1] * f_ext[c_id][1]
3727 - 0.5 * dc[2] * f_ext[c_id][2]
3728 - 0.5 * dc[0] * f_ext[c_id1][0]
3729 - 0.5 * dc[1] * f_ext[c_id1][1]
3730 - 0.5 * dc[2] * f_ext[c_id1][2]) * ddc;
3731
3732 for (cs_lnum_t ll = 0; ll < 3; ll++)
3733 rhsv[ll] += dc[ll] * pfac;
3734
3735 cocg[0] += dc[0]*dc[0]*ddc;
3736 cocg[1] += dc[1]*dc[1]*ddc;
3737 cocg[2] += dc[2]*dc[2]*ddc;
3738 cocg[3] += dc[0]*dc[1]*ddc;
3739 cocg[4] += dc[1]*dc[2]*ddc;
3740 cocg[5] += dc[0]*dc[2]*ddc;
3741
3742 }
3743
3744 }
3745 else {
3746
3747 for (cs_lnum_t i = s_id; i < e_id; i++) {
3748
3749 cs_real_t dc[3];
3750 cs_lnum_t c_id1 = cell_cells_p[i];
3751 for (cs_lnum_t ll = 0; ll < 3; ll++)
3752 dc[ll] = cell_cen[c_id1][ll] - cell_cen[c_id][ll];
3753
3754 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
3755
3756 cs_real_t pfac = ( c_var[c_id1] - c_var[c_id]
3757 - 0.5 * dc[0] * f_ext[c_id][0]
3758 - 0.5 * dc[1] * f_ext[c_id][1]
3759 - 0.5 * dc[2] * f_ext[c_id][2]
3760 - 0.5 * dc[0] * f_ext[c_id1][0]
3761 - 0.5 * dc[1] * f_ext[c_id1][1]
3762 - 0.5 * dc[2] * f_ext[c_id1][2]) * ddc;
3763
3764 cs_real_t _weight = 2. * c_weight[c_id1]
3765 / (c_weight[c_id] + c_weight[c_id1]);
3766
3767 for (cs_lnum_t ll = 0; ll < 3; ll++)
3768 rhsv[ll] += dc[ll] * pfac* _weight;
3769
3770 cocg[0] += dc[0]*dc[0]*ddc;
3771 cocg[1] += dc[1]*dc[1]*ddc;
3772 cocg[2] += dc[2]*dc[2]*ddc;
3773 cocg[3] += dc[0]*dc[1]*ddc;
3774 cocg[4] += dc[1]*dc[2]*ddc;
3775 cocg[5] += dc[0]*dc[2]*ddc;
3776
3777 }
3778
3779 }
3780
3781 } /* end of contribution from interior and extended cells */
3782
3783 cs_lnum_t s_id = cell_b_faces_idx[c_id];
3784 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
3785
3786 /* Contribution from boundary faces */
3787
3788 for (cs_lnum_t i = s_id; i < e_id; i++) {
3789
3790 cs_real_t dsij[3];
3791
3792 cs_lnum_t f_id = cell_b_faces[i];
3793
3794 cs_real_t poro = b_poro_duq[is_porous*f_id];
3795
3796 cs_real_t unddij = 1. / b_dist[f_id];
3797 cs_real_t umcbdd = (1. -bc_coeff_b[f_id]) * unddij;
3798
3799 cs_real_t normal[3];
3800 /* Normal is vector 0 if the b_face_normal norm is too small */
3801 cs_math_3_normalise(b_face_normal[f_id], normal);
3802
3803 for (cs_lnum_t ll = 0; ll < 3; ll++)
3804 dsij[ll] = normal[ll] + umcbdd*diipb[f_id][ll];
3805
3806 /* (b_face_cog - cell_cen).f_ext, or IF.F_I */
3807 cs_real_t c_f_ext
3808 = cs_math_3_distance_dot_product(b_face_cog[f_id],
3809 cell_cen[c_id],
3810 f_ext[c_id]);
3811
3812 cs_real_t pfac = ( bc_coeff_a[f_id]*inc + (bc_coeff_b[f_id] -1.)
3813 * (c_var[c_id] + c_f_ext + poro))
3814 * unddij;
3815
3816 for (cs_lnum_t ll = 0; ll < 3; ll++)
3817 rhsv[ll] += dsij[ll] * pfac;
3818
3819 cocg[0] += dsij[0]*dsij[0];
3820 cocg[1] += dsij[1]*dsij[1];
3821 cocg[2] += dsij[2]*dsij[2];
3822 cocg[3] += dsij[0]*dsij[1];
3823 cocg[4] += dsij[1]*dsij[2];
3824 cocg[5] += dsij[0]*dsij[2];
3825
3826 } // end of contribution from boundary cells
3827
3828 /* Invert */
3829
3830 cs_real_t a11 = cocg[1]*cocg[2] - cocg[4]*cocg[4];
3831 cs_real_t a12 = cocg[4]*cocg[5] - cocg[3]*cocg[2];
3832 cs_real_t a13 = cocg[3]*cocg[4] - cocg[1]*cocg[5];
3833 cs_real_t a22 = cocg[0]*cocg[2] - cocg[5]*cocg[5];
3834 cs_real_t a23 = cocg[3]*cocg[5] - cocg[0]*cocg[4];
3835 cs_real_t a33 = cocg[0]*cocg[1] - cocg[3]*cocg[3];
3836
3837 cs_real_t det_inv = 1. / (cocg[0]*a11 + cocg[3]*a12 + cocg[5]*a13);
3838
3839 cs_real_t grad[3];
3840
3841 grad[0] = ( a11 * rhsv[0]
3842 + a12 * rhsv[1]
3843 + a13 * rhsv[2]) * det_inv
3844 + f_ext[c_id][0];
3845 grad[1] = ( a12 * rhsv[0]
3846 + a22 * rhsv[1]
3847 + a23 * rhsv[2]) * det_inv
3848 + f_ext[c_id][1];
3849 grad[2] = ( a13 * rhsv[0]
3850 + a23 * rhsv[1]
3851 + a33 * rhsv[2]) * det_inv
3852 + f_ext[c_id][2];
3853
3854 /* Update boundary face value */
3855
3856 for (cs_lnum_t i = s_id; i < e_id; i++) {
3857
3858 cs_lnum_t f_id = cell_b_faces[i];
3859
3860 cs_real_t pip = c_var[c_id]
3861 + cs_math_3_dot_product(diipb[f_id], grad);
3862 b_f_var[f_id] = bc_coeff_a[f_id]*inc + pip*bc_coeff_b[f_id];
3863
3864 }
3865 }
3866 }
3867
3868 /*----------------------------------------------------------------------------
3869 * Compute gradient using vertex-based face values for scalar gradient
3870 * reconstruction.
3871 *
3872 * Optionally, a volume force generating a hydrostatic pressure component
3873 * may be accounted for.
3874 *
3875 * parameters:
3876 * m <-- pointer to associated mesh structure
3877 * fvq <-- pointer to associated finite volume quantities
3878 * cpl <-- structure associated with internal coupling, or NULL
3879 * halo_type <-- halo type (extended or not)
3880 * hyd_p_flag <-- flag for hydrostatic pressure
3881 * inc <-- if 0, solve on increment; 1 otherwise
3882 * f_ext <-- exterior force generating pressure
3883 * bc_coeff_a <-- B.C. coefficients for boundary face normals
3884 * bc_coeff_b <-- B.C. coefficients for boundary face normals
3885 * c_var <-- variable
3886 * c_weight <-- weighted gradient coefficient variable
3887 * grad <-> gradient of pvar (halo prepared for periodicity
3888 * of rotation)
3889 *----------------------------------------------------------------------------*/
3890
3891 static void
_fv_vtx_based_scalar_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,int hyd_p_flag,cs_real_t inc,const cs_real_3_t f_ext[],const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t c_var[],const cs_real_t c_weight[],cs_real_3_t * restrict grad)3892 _fv_vtx_based_scalar_gradient(const cs_mesh_t *m,
3893 const cs_mesh_quantities_t *fvq,
3894 const cs_internal_coupling_t *cpl,
3895 int hyd_p_flag,
3896 cs_real_t inc,
3897 const cs_real_3_t f_ext[],
3898 const cs_real_t bc_coeff_a[],
3899 const cs_real_t bc_coeff_b[],
3900 const cs_real_t c_var[],
3901 const cs_real_t c_weight[],
3902 cs_real_3_t *restrict grad)
3903 {
3904 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
3905 const cs_lnum_t n_cells = m->n_cells;
3906 const int n_i_groups = m->i_face_numbering->n_groups;
3907 const int n_i_threads = m->i_face_numbering->n_threads;
3908 const int n_b_groups = m->b_face_numbering->n_groups;
3909 const int n_b_threads = m->b_face_numbering->n_threads;
3910 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
3911 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
3912
3913 const cs_lnum_2_t *restrict i_face_cells
3914 = (const cs_lnum_2_t *restrict)m->i_face_cells;
3915 const cs_lnum_t *restrict b_face_cells
3916 = (const cs_lnum_t *restrict)m->b_face_cells;
3917
3918 const int *restrict c_disable_flag = fvq->c_disable_flag;
3919 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
3920
3921 const cs_real_t *restrict weight = fvq->weight;
3922 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
3923 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
3924 cell_f_vol = fvq->cell_vol;
3925 const cs_real_3_t *restrict cell_cen
3926 = (const cs_real_3_t *restrict)fvq->cell_cen;
3927 const cs_real_3_t *restrict i_f_face_normal
3928 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
3929 const cs_real_3_t *restrict b_f_face_normal
3930 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
3931 const cs_real_3_t *restrict i_face_cog
3932 = (const cs_real_3_t *restrict)fvq->i_face_cog;
3933 const cs_real_3_t *restrict b_face_cog
3934 = (const cs_real_3_t *restrict)fvq->b_face_cog;
3935
3936 bool *coupled_faces = (cpl == NULL) ?
3937 NULL : (bool *)cpl->coupled_faces;
3938
3939 /*Additional terms due to porosity */
3940 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
3941
3942 cs_real_t *i_poro_duq_0;
3943 cs_real_t *i_poro_duq_1;
3944 cs_real_t *b_poro_duq;
3945 cs_real_t _f_ext = 0.;
3946
3947 cs_lnum_t is_porous = 0;
3948 if (f_i_poro_duq_0 != NULL) {
3949 is_porous = 1;
3950 i_poro_duq_0 = f_i_poro_duq_0->val;
3951 i_poro_duq_1 = cs_field_by_name_try("i_poro_duq_1")->val;
3952 b_poro_duq = cs_field_by_name_try("b_poro_duq")->val;
3953 } else {
3954 i_poro_duq_0 = &_f_ext;
3955 i_poro_duq_1 = &_f_ext;
3956 b_poro_duq = &_f_ext;
3957 }
3958
3959 /* Initialize gradient
3960 ------------------- */
3961
3962 # pragma omp parallel for
3963 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
3964 for (cs_lnum_t j = 0; j < 3; j++)
3965 grad[c_id][j] = 0.0;
3966 }
3967
3968 /* Pre-compute values at boundary using least squares */
3969
3970 cs_real_t *b_f_var;
3971 BFT_MALLOC(b_f_var, m->n_b_faces, cs_real_t);
3972
3973 if (hyd_p_flag == 1)
3974 _lsq_scalar_b_face_val_phyd(m,
3975 fvq,
3976 CS_HALO_STANDARD,
3977 inc,
3978 f_ext,
3979 bc_coeff_a,
3980 bc_coeff_b,
3981 c_var,
3982 c_weight,
3983 b_f_var);
3984 else
3985 _lsq_scalar_b_face_val(m,
3986 fvq,
3987 CS_HALO_STANDARD,
3988 inc,
3989 bc_coeff_a,
3990 bc_coeff_b,
3991 c_var,
3992 c_weight,
3993 b_f_var);
3994
3995 /* Compute vertex-based values
3996 --------------------------- */
3997
3998 cs_real_t *v_var;
3999 BFT_MALLOC(v_var, m->n_vertices, cs_real_t);
4000
4001 cs_cell_to_vertex(CS_CELL_TO_VERTEX_LR,
4002 0, /* verbosity */
4003 1, /* var_dim */
4004 0, /* tr_dim */
4005 c_weight,
4006 c_var,
4007 b_f_var,
4008 v_var);
4009
4010 /* Interpolate to face-based values
4011 -------------------------------- */
4012
4013 cs_real_t *i_f_var;
4014 BFT_MALLOC(i_f_var, m->n_i_faces, cs_real_t);
4015
4016 for (int f_t = 0; f_t < 2; f_t++) {
4017
4018 const cs_lnum_t n_faces = (f_t == 0) ? m->n_i_faces : m->n_b_faces;
4019 const cs_lnum_t *f2v_idx= NULL, *f2v_ids = NULL;
4020 cs_real_t *f_var = NULL;
4021
4022 if (f_t == 0) {
4023 f2v_idx = m->i_face_vtx_idx;
4024 f2v_ids = m->i_face_vtx_lst;
4025 f_var = i_f_var;
4026 }
4027 else {
4028 f2v_idx = m->b_face_vtx_idx;
4029 f2v_ids = m->b_face_vtx_lst;
4030 f_var = b_f_var;
4031 }
4032
4033 # pragma omp parallel for if (n_faces > CS_THR_MIN)
4034 for (cs_lnum_t f_id = 0; f_id < n_faces; f_id++) {
4035 cs_lnum_t s_id = f2v_idx[f_id];
4036 cs_lnum_t e_id = f2v_idx[f_id+1];
4037 cs_real_t s = 0;
4038 for (cs_lnum_t i = s_id; i < e_id; i++)
4039 s += v_var[f2v_ids[i]];
4040 f_var[f_id] = s / (e_id-s_id);
4041 }
4042
4043 }
4044
4045 /* Vertex values are not needed after this stage */
4046
4047 cs_real_t mean[4] = {0, 0, 0, 0};
4048 for (cs_lnum_t i = 0; i < n_cells; i++)
4049 mean[0] += c_var[i];
4050 mean[0] /= n_cells;
4051 for (cs_lnum_t i = 0; i < m->n_vertices; i++)
4052 mean[1] += v_var[i];
4053 mean[1] /= m->n_vertices;
4054 for (cs_lnum_t i = 0; i < m->n_i_faces; i++)
4055 mean[2] += i_f_var[i];
4056 mean[2] /= m->n_i_faces;
4057 for (cs_lnum_t i = 0; i < m->n_b_faces; i++)
4058 mean[3] += b_f_var[i];
4059 mean[3] /= m->n_b_faces;
4060
4061 BFT_FREE(v_var);
4062
4063 /* Case with hydrostatic pressure
4064 ------------------------------ */
4065
4066 if (hyd_p_flag == 1) {
4067
4068 /* Contribution from interior faces */
4069
4070 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4071
4072 # pragma omp parallel for
4073 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4074
4075 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4076 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4077 f_id++) {
4078
4079 cs_lnum_t ii = i_face_cells[f_id][0];
4080 cs_lnum_t jj = i_face_cells[f_id][1];
4081
4082 cs_real_t ktpond = (c_weight == NULL) ?
4083 weight[f_id] : /* no cell weighting */
4084 weight[f_id] * c_weight[ii] /* cell weighting active */
4085 / ( weight[f_id] * c_weight[ii]
4086 + (1.0-weight[f_id])* c_weight[jj]);
4087
4088 cs_real_2_t poro = {
4089 i_poro_duq_0[is_porous*f_id],
4090 i_poro_duq_1[is_porous*f_id]
4091 };
4092
4093 cs_real_t pfaci
4094 = ktpond
4095 * ( (i_face_cog[f_id][0] - cell_cen[ii][0])*f_ext[ii][0]
4096 + (i_face_cog[f_id][1] - cell_cen[ii][1])*f_ext[ii][1]
4097 + (i_face_cog[f_id][2] - cell_cen[ii][2])*f_ext[ii][2]
4098 + poro[0])
4099 + (1.0 - ktpond)
4100 * ( (i_face_cog[f_id][0] - cell_cen[jj][0])*f_ext[jj][0]
4101 + (i_face_cog[f_id][1] - cell_cen[jj][1])*f_ext[jj][1]
4102 + (i_face_cog[f_id][2] - cell_cen[jj][2])*f_ext[jj][2]
4103 + poro[1]);
4104 cs_real_t pfacj = pfaci;
4105
4106 pfaci += i_f_var[f_id] - c_var[ii];
4107 pfacj += i_f_var[f_id] - c_var[jj];
4108
4109 for (cs_lnum_t j = 0; j < 3; j++) {
4110 grad[ii][j] += pfaci * i_f_face_normal[f_id][j];
4111 grad[jj][j] -= pfacj * i_f_face_normal[f_id][j];
4112 }
4113
4114 } /* loop on faces */
4115
4116 } /* loop on threads */
4117
4118 } /* loop on thread groups */
4119
4120 /* Contribution from coupled faces */
4121 if (cpl != NULL) {
4122 assert(0); /* not handled yet */
4123 }
4124
4125 /* Contribution from boundary faces */
4126
4127 for (int g_id = 0; g_id < n_b_groups; g_id++) {
4128
4129 # pragma omp parallel for
4130 for (int t_id = 0; t_id < n_b_threads; t_id++) {
4131
4132 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
4133 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
4134 f_id++) {
4135
4136 if (cpl == NULL || !coupled_faces[f_id]) {
4137
4138 cs_lnum_t c_id = b_face_cells[f_id];
4139
4140 cs_real_t poro = b_poro_duq[is_porous*f_id];
4141 /*
4142 Remark: for the cell \f$ \celli \f$ we remove
4143 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
4144 */
4145
4146 cs_real_t pfac = b_f_var[f_id] - c_var[c_id];
4147
4148 pfac +=
4149 bc_coeff_b[f_id]
4150 * ( (b_face_cog[f_id][0] - cell_cen[c_id][0])*f_ext[c_id][0]
4151 + (b_face_cog[f_id][1] - cell_cen[c_id][1])*f_ext[c_id][1]
4152 + (b_face_cog[f_id][2] - cell_cen[c_id][2])*f_ext[c_id][2]
4153 + poro);
4154
4155 for (cs_lnum_t j = 0; j < 3; j++)
4156 grad[c_id][j] += pfac * b_f_face_normal[f_id][j];
4157
4158 } /* face without internal coupling */
4159
4160 } /* loop on faces */
4161
4162 } /* loop on threads */
4163
4164 } /* loop on thread groups */
4165
4166 } /* End of test on hydrostatic pressure */
4167
4168 /* Standard case, without hydrostatic pressure
4169 ------------------------------------------- */
4170
4171 else {
4172
4173 /* Contribution from interior faces */
4174
4175 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4176
4177 # pragma omp parallel for
4178 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4179
4180 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4181 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4182 f_id++) {
4183
4184 cs_lnum_t ii = i_face_cells[f_id][0];
4185 cs_lnum_t jj = i_face_cells[f_id][1];
4186
4187 cs_real_t pfaci = i_f_var[f_id] - c_var[ii];
4188 cs_real_t pfacj = i_f_var[f_id] - c_var[jj];
4189
4190 for (cs_lnum_t j = 0; j < 3; j++) {
4191 grad[ii][j] += pfaci * i_f_face_normal[f_id][j];
4192 grad[jj][j] -= pfacj * i_f_face_normal[f_id][j];
4193 }
4194
4195 } /* loop on faces */
4196
4197 } /* loop on threads */
4198
4199 } /* loop on thread groups */
4200
4201 /* Contribution from coupled faces */
4202 if (cpl != NULL) {
4203 assert(0); /* not handled yet */
4204 }
4205
4206 /* Contribution from boundary faces */
4207
4208 for (int g_id = 0; g_id < n_b_groups; g_id++) {
4209
4210 # pragma omp parallel for
4211 for (int t_id = 0; t_id < n_b_threads; t_id++) {
4212
4213 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
4214 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
4215 f_id++) {
4216
4217 if (cpl == NULL || !coupled_faces[f_id]) {
4218
4219 cs_lnum_t ii = b_face_cells[f_id];
4220
4221 /*
4222 Remark: for the cell \f$ \celli \f$ we remove
4223 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
4224 */
4225
4226 cs_real_t pfac = b_f_var[f_id] - c_var[ii];
4227
4228 for (cs_lnum_t j = 0; j < 3; j++)
4229 grad[ii][j] += pfac * b_f_face_normal[f_id][j];
4230
4231 } /* face without internal coupling */
4232
4233 } /* loop on faces */
4234
4235 } /* loop on threads */
4236
4237 } /* loop on thread groups */
4238
4239 }
4240
4241 BFT_FREE(i_f_var);
4242 BFT_FREE(b_f_var);
4243
4244 # pragma omp parallel for
4245 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
4246 cs_real_t dvol;
4247 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
4248 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
4249 dvol = 1. / cell_f_vol[c_id];
4250 else
4251 dvol = 0.;
4252
4253 for (cs_lnum_t j = 0; j < 3; j++)
4254 grad[c_id][j] *= dvol;
4255 }
4256
4257 /* Synchronize halos */
4258
4259 _sync_scalar_gradient_halo(m, CS_HALO_EXTENDED, grad);
4260 }
4261
4262
4263 /*----------------------------------------------------------------------------
4264 * Clip the gradient of a vector if necessary. This function deals with the
4265 * standard or extended neighborhood.
4266 *
4267 * parameters:
4268 * m <-- pointer to associated mesh structure
4269 * fvq <-- pointer to associated finite volume quantities
4270 * halo_type <-- halo type (extended or not)
4271 * clip_mode <-- type of clipping for the computation of the gradient
4272 * verbosity <-- output level
4273 * climgp <-- clipping coefficient for the computation of the gradient
4274 * pvar <-- variable
4275 * gradv <-> gradient of pvar (du_i/dx_j : gradv[][i][j])
4276 * pvar <-- variable
4277 *----------------------------------------------------------------------------*/
4278
4279 static void
_vector_gradient_clipping(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_halo_type_t halo_type,int clip_mode,int verbosity,cs_real_t climgp,const char * var_name,const cs_real_3_t * restrict pvar,cs_real_33_t * restrict gradv)4280 _vector_gradient_clipping(const cs_mesh_t *m,
4281 const cs_mesh_quantities_t *fvq,
4282 cs_halo_type_t halo_type,
4283 int clip_mode,
4284 int verbosity,
4285 cs_real_t climgp,
4286 const char *var_name,
4287 const cs_real_3_t *restrict pvar,
4288 cs_real_33_t *restrict gradv)
4289 {
4290 cs_real_t global_min_factor, global_max_factor;
4291
4292 cs_gnum_t n_clip = 0, n_g_clip =0;
4293 cs_real_t min_factor = 1;
4294 cs_real_t max_factor = 0;
4295 cs_real_t clipp_coef_sq = climgp*climgp;
4296 cs_real_t *restrict buf = NULL, *restrict clip_factor = NULL;
4297 cs_real_t *restrict denom = NULL, *restrict denum = NULL;
4298
4299 const cs_lnum_t n_cells = m->n_cells;
4300 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
4301 const int n_i_groups = m->i_face_numbering->n_groups;
4302 const int n_i_threads = m->i_face_numbering->n_threads;
4303 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
4304
4305 const cs_lnum_2_t *restrict i_face_cells
4306 = (const cs_lnum_2_t *restrict)m->i_face_cells;
4307 const cs_lnum_t *restrict cell_cells_idx
4308 = (const cs_lnum_t *restrict)m->cell_cells_idx;
4309 const cs_lnum_t *restrict cell_cells_lst
4310 = (const cs_lnum_t *restrict)m->cell_cells_lst;
4311
4312 const cs_real_3_t *restrict cell_cen
4313 = (const cs_real_3_t *restrict)fvq->cell_cen;
4314
4315 const cs_halo_t *halo = m->halo;
4316
4317 if (clip_mode < 0)
4318 return;
4319
4320 /* The gradient and the variable must be already synchronized */
4321
4322 /* Allocate and initialize working buffers */
4323
4324 if (clip_mode == 1)
4325 BFT_MALLOC(buf, 3*n_cells_ext, cs_real_t);
4326 else
4327 BFT_MALLOC(buf, 2*n_cells_ext, cs_real_t);
4328
4329 denum = buf;
4330 denom = buf + n_cells_ext;
4331
4332 if (clip_mode == 1)
4333 clip_factor = buf + 2*n_cells_ext;
4334
4335 /* Initialization */
4336
4337 # pragma omp parallel for
4338 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
4339 denum[c_id] = 0;
4340 denom[c_id] = 0;
4341 if (clip_mode == 1)
4342 clip_factor[c_id] = (cs_real_t)DBL_MAX;
4343 }
4344
4345 /* Remark:
4346 denum: holds the maximum l2 norm of the variation of the gradient squared
4347 denom: holds the maximum l2 norm of the variation of the variable squared */
4348
4349 /* First clipping Algorithm: based on the cell gradient */
4350 /*------------------------------------------------------*/
4351
4352 if (clip_mode == 0) {
4353
4354 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4355
4356 # pragma omp parallel for
4357 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4358
4359 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4360 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4361 f_id++) {
4362
4363 cs_lnum_t c_id1 = i_face_cells[f_id][0];
4364 cs_lnum_t c_id2 = i_face_cells[f_id][1];
4365
4366 cs_real_t dist[3], grad_dist1[3], grad_dist2[3];
4367
4368 for (cs_lnum_t i = 0; i < 3; i++)
4369 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
4370
4371 for (cs_lnum_t i = 0; i < 3; i++) {
4372
4373 grad_dist1[i] = gradv[c_id1][i][0] * dist[0]
4374 + gradv[c_id1][i][1] * dist[1]
4375 + gradv[c_id1][i][2] * dist[2];
4376
4377 grad_dist2[i] = gradv[c_id2][i][0] * dist[0]
4378 + gradv[c_id2][i][1] * dist[1]
4379 + gradv[c_id2][i][2] * dist[2];
4380
4381 }
4382
4383 cs_real_t dvar_sq, dist_sq1, dist_sq2;
4384
4385 dist_sq1 = grad_dist1[0]*grad_dist1[0]
4386 + grad_dist1[1]*grad_dist1[1]
4387 + grad_dist1[2]*grad_dist1[2];
4388
4389 dist_sq2 = grad_dist2[0]*grad_dist2[0]
4390 + grad_dist2[1]*grad_dist2[1]
4391 + grad_dist2[2]*grad_dist2[2];
4392
4393 dvar_sq = (pvar[c_id1][0]-pvar[c_id2][0])
4394 * (pvar[c_id1][0]-pvar[c_id2][0])
4395 + (pvar[c_id1][1]-pvar[c_id2][1])
4396 * (pvar[c_id1][1]-pvar[c_id2][1])
4397 + (pvar[c_id1][2]-pvar[c_id2][2])
4398 * (pvar[c_id1][2]-pvar[c_id2][2]);
4399
4400 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
4401 denum[c_id2] = CS_MAX(denum[c_id2], dist_sq2);
4402 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
4403 denom[c_id2] = CS_MAX(denom[c_id2], dvar_sq);
4404
4405 } /* End of loop on faces */
4406
4407 } /* End of loop on threads */
4408
4409 } /* End of loop on thread groups */
4410
4411 /* Complement for extended neighborhood */
4412
4413 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
4414
4415 # pragma omp parallel for
4416 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
4417 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
4418 cidx < cell_cells_idx[c_id1+1];
4419 cidx++) {
4420
4421 cs_lnum_t c_id2 = cell_cells_lst[cidx];
4422
4423
4424 cs_real_t dist[3], grad_dist1[3];
4425
4426 for (cs_lnum_t i = 0; i < 3; i++)
4427 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
4428
4429 for (cs_lnum_t i = 0; i < 3; i++)
4430 grad_dist1[i] = gradv[c_id1][i][0] * dist[0]
4431 + gradv[c_id1][i][1] * dist[1]
4432 + gradv[c_id1][i][2] * dist[2];
4433
4434 cs_real_t dvar_sq, dist_sq1;
4435
4436 dist_sq1 = grad_dist1[0]*grad_dist1[0]
4437 + grad_dist1[1]*grad_dist1[1]
4438 + grad_dist1[2]*grad_dist1[2];
4439
4440 dvar_sq = (pvar[c_id1][0]-pvar[c_id2][0])
4441 * (pvar[c_id1][0]-pvar[c_id2][0])
4442 + (pvar[c_id1][1]-pvar[c_id2][1])
4443 * (pvar[c_id1][1]-pvar[c_id2][1])
4444 + (pvar[c_id1][2]-pvar[c_id2][2])
4445 * (pvar[c_id1][2]-pvar[c_id2][2]);
4446
4447 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
4448 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
4449
4450 }
4451 }
4452
4453 } /* End for extended halo */
4454
4455 }
4456
4457 /* Second clipping Algorithm: based on the face gradient */
4458 /*-------------------------------------------------------*/
4459
4460 else if (clip_mode == 1) {
4461
4462 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4463
4464 # pragma omp parallel for
4465 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4466
4467 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4468 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4469 f_id++) {
4470
4471 cs_lnum_t c_id1 = i_face_cells[f_id][0];
4472 cs_lnum_t c_id2 = i_face_cells[f_id][1];
4473
4474 cs_real_t dist[3], grad_dist1[3];
4475
4476 for (cs_lnum_t i = 0; i < 3; i++)
4477 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
4478
4479 for (cs_lnum_t i = 0; i < 3; i++)
4480 grad_dist1[i]
4481 = 0.5 * ( (gradv[c_id1][i][0]+gradv[c_id2][i][0])*dist[0]
4482 + (gradv[c_id1][i][1]+gradv[c_id2][i][1])*dist[1]
4483 + (gradv[c_id1][i][2]+gradv[c_id2][i][2])*dist[2]);
4484
4485 cs_real_t dist_sq1, dvar_sq;
4486
4487 dist_sq1 = grad_dist1[0]*grad_dist1[0]
4488 + grad_dist1[1]*grad_dist1[1]
4489 + grad_dist1[2]*grad_dist1[2];
4490
4491 dvar_sq = (pvar[c_id1][0]-pvar[c_id2][0])
4492 * (pvar[c_id1][0]-pvar[c_id2][0])
4493 + (pvar[c_id1][1]-pvar[c_id2][1])
4494 * (pvar[c_id1][1]-pvar[c_id2][1])
4495 + (pvar[c_id1][2]-pvar[c_id2][2])
4496 * (pvar[c_id1][2]-pvar[c_id2][2]);
4497
4498 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
4499 denum[c_id2] = CS_MAX(denum[c_id2], dist_sq1);
4500 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
4501 denom[c_id2] = CS_MAX(denom[c_id2], dvar_sq);
4502
4503 } /* End of loop on threads */
4504
4505 } /* End of loop on thread groups */
4506
4507 } /* End of loop on faces */
4508
4509 /* Complement for extended neighborhood */
4510
4511 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
4512
4513 # pragma omp parallel for
4514 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
4515 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
4516 cidx < cell_cells_idx[c_id1+1];
4517 cidx++) {
4518
4519 cs_lnum_t c_id2 = cell_cells_lst[cidx];
4520
4521 cs_real_t dist[3], grad_dist1[3];
4522
4523 for (cs_lnum_t i = 0; i < 3; i++)
4524 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
4525
4526 for (cs_lnum_t i = 0; i < 3; i++)
4527 grad_dist1[i]
4528 = 0.5 * ( (gradv[c_id1][i][0]+gradv[c_id2][i][0])*dist[0]
4529 + (gradv[c_id1][i][1]+gradv[c_id2][i][1])*dist[1]
4530 + (gradv[c_id1][i][2]+gradv[c_id2][i][2])*dist[2]);
4531
4532 cs_real_t dist_sq1, dvar_sq;
4533
4534 dist_sq1 = grad_dist1[0]*grad_dist1[0]
4535 + grad_dist1[1]*grad_dist1[1]
4536 + grad_dist1[2]*grad_dist1[2];
4537
4538 dvar_sq = (pvar[c_id1][0]-pvar[c_id2][0])
4539 * (pvar[c_id1][0]-pvar[c_id2][0])
4540 + (pvar[c_id1][1]-pvar[c_id2][1])
4541 * (pvar[c_id1][1]-pvar[c_id2][1])
4542 + (pvar[c_id1][2]-pvar[c_id2][2])
4543 * (pvar[c_id1][2]-pvar[c_id2][2]);
4544
4545 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
4546 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
4547
4548 }
4549 }
4550
4551 } /* End for extended neighborhood */
4552
4553 /* Synchronize variable */
4554
4555 if (halo != NULL) {
4556 cs_halo_sync_var(m->halo, halo_type, denom);
4557 cs_halo_sync_var(m->halo, halo_type, denum);
4558 }
4559
4560 } /* End if clip_mode == 1 */
4561
4562 /* Clipping of the gradient if denum/denom > climgp**2 */
4563
4564 /* First clipping Algorithm: based on the cell gradient */
4565 /*------------------------------------------------------*/
4566
4567 if (clip_mode == 0) {
4568
4569 # pragma omp parallel
4570 {
4571 cs_gnum_t t_n_clip = 0;
4572 cs_real_t t_min_factor = min_factor, t_max_factor = max_factor;
4573
4574 # pragma omp for
4575 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
4576
4577 if (denum[c_id] > clipp_coef_sq * denom[c_id]) {
4578
4579 cs_real_t factor1 = sqrt(clipp_coef_sq * denom[c_id]/denum[c_id]);
4580
4581 for (cs_lnum_t i = 0; i < 3; i++) {
4582 for (cs_lnum_t j = 0; j < 3; j++)
4583 gradv[c_id][i][j] *= factor1;
4584 }
4585
4586 t_min_factor = CS_MIN(factor1, t_min_factor);
4587 t_max_factor = CS_MAX(factor1, t_max_factor);
4588 t_n_clip++;
4589
4590 } /* If clipping */
4591
4592 } /* End of loop on cells */
4593
4594 # pragma omp critical
4595 {
4596 min_factor = CS_MIN(min_factor, t_min_factor);
4597 max_factor = CS_MAX(max_factor, t_max_factor);
4598 n_clip += t_n_clip;
4599 }
4600 } /* End of omp parallel construct */
4601
4602 }
4603
4604 /* Second clipping Algorithm: based on the face gradient */
4605 /*-------------------------------------------------------*/
4606
4607 else if (clip_mode == 1) {
4608
4609 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4610
4611 # pragma omp parallel for
4612 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4613
4614 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4615 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4616 f_id++) {
4617
4618 cs_lnum_t c_id1 = i_face_cells[f_id][0];
4619 cs_lnum_t c_id2 = i_face_cells[f_id][1];
4620
4621 cs_real_t factor1 = 1.0;
4622 if (denum[c_id1] > clipp_coef_sq * denom[c_id1])
4623 factor1 = sqrt(clipp_coef_sq * denom[c_id1]/denum[c_id1]);
4624
4625 cs_real_t factor2 = 1.0;
4626 if (denum[c_id2] > clipp_coef_sq * denom[c_id2])
4627 factor2 = sqrt(clipp_coef_sq * denom[c_id2]/denum[c_id2]);
4628
4629 cs_real_t l_min_factor = CS_MIN(factor1, factor2);
4630
4631 clip_factor[c_id1] = CS_MIN(clip_factor[c_id1], l_min_factor);
4632 clip_factor[c_id2] = CS_MIN(clip_factor[c_id2], l_min_factor);
4633
4634 } /* End of loop on faces */
4635
4636 } /* End of loop on threads */
4637
4638 } /* End of loop on thread groups */
4639
4640 /* Complement for extended neighborhood */
4641
4642 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
4643
4644 # pragma omp parallel for
4645 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
4646
4647 cs_real_t l_min_factor = 1.0;
4648
4649 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
4650 cidx < cell_cells_idx[c_id1+1];
4651 cidx++) {
4652
4653 cs_lnum_t c_id2 = cell_cells_lst[cidx];
4654 cs_real_t factor2 = 1.0;
4655
4656 if (denum[c_id2] > clipp_coef_sq * denom[c_id2])
4657 factor2 = sqrt(clipp_coef_sq * denom[c_id2]/denum[c_id2]);
4658
4659 l_min_factor = CS_MIN(l_min_factor, factor2);
4660
4661 }
4662
4663 clip_factor[c_id1] = CS_MIN(clip_factor[c_id1], l_min_factor);
4664
4665 } /* End of loop on cells */
4666
4667 } /* End for extended neighborhood */
4668
4669 # pragma omp parallel
4670 {
4671 cs_gnum_t t_n_clip = 0;
4672 cs_real_t t_min_factor = min_factor, t_max_factor = max_factor;
4673
4674 # pragma omp for
4675 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
4676
4677 for (cs_lnum_t i = 0; i < 3; i++) {
4678 for (cs_lnum_t j = 0; j < 3; j++)
4679 gradv[c_id][i][j] *= clip_factor[c_id];
4680 }
4681
4682 if (clip_factor[c_id] < 0.99) {
4683 t_max_factor = CS_MAX(t_max_factor, clip_factor[c_id]);
4684 t_min_factor = CS_MIN(t_min_factor, clip_factor[c_id]);
4685 t_n_clip++;
4686 }
4687
4688 } /* End of loop on cells */
4689
4690 # pragma omp critical
4691 {
4692 min_factor = CS_MIN(min_factor, t_min_factor);
4693 max_factor = CS_MAX(max_factor, t_max_factor);
4694 n_clip += t_n_clip;
4695 }
4696 } /* End of omp parallel construct */
4697
4698 } /* End if clip_mode == 1 */
4699
4700 /* Update min/max and n_clip in case of parallelism */
4701 /*--------------------------------------------------*/
4702
4703 #if defined(HAVE_MPI)
4704
4705 if (m->n_domains > 1) {
4706
4707 assert(sizeof(cs_real_t) == sizeof(double));
4708
4709 /* Global Max */
4710
4711 MPI_Allreduce(&max_factor, &global_max_factor, 1, CS_MPI_REAL,
4712 MPI_MAX, cs_glob_mpi_comm);
4713
4714 max_factor = global_max_factor;
4715
4716 /* Global min */
4717
4718 MPI_Allreduce(&min_factor, &global_min_factor, 1, CS_MPI_REAL,
4719 MPI_MIN, cs_glob_mpi_comm);
4720
4721 min_factor = global_min_factor;
4722
4723 /* Sum number of clippings */
4724
4725 MPI_Allreduce(&n_clip, &n_g_clip, 1, CS_MPI_GNUM,
4726 MPI_SUM, cs_glob_mpi_comm);
4727
4728 n_clip = n_g_clip;
4729
4730 } /* If n_domains > 1 */
4731
4732 #endif /* defined(HAVE_MPI) */
4733
4734 /* Output warning if necessary */
4735
4736 if (verbosity > 1)
4737 bft_printf(_(" Variable: %s; Gradient of a vector limitation in %llu cells\n"
4738 " minimum factor = %14.5e; maximum factor = %14.5e\n"),
4739 var_name,
4740 (unsigned long long)n_clip, min_factor, max_factor);
4741
4742 /* Synchronize the updated Gradient */
4743
4744 if (m->halo != NULL) {
4745 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)gradv, 9);
4746 if (cs_glob_mesh->have_rotation_perio)
4747 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)gradv);
4748 }
4749
4750 BFT_FREE(buf);
4751 }
4752
4753 /*----------------------------------------------------------------------------
4754 * Initialize the gradient of a vector for gradient reconstruction.
4755 *
4756 * A non-reconstructed gradient is computed at this stage.
4757 *
4758 * parameters:
4759 * m <-- pointer to associated mesh structure
4760 * fvq <-- pointer to associated finite volume quantities
4761 * cpl <-- structure associated with internal coupling, or NULL
4762 * halo_type <-- halo type (extended or not)
4763 * inc <-- if 0, solve on increment; 1 otherwise
4764 * coefav <-- B.C. coefficients for boundary face normals
4765 * coefbv <-- B.C. coefficients for boundary face normals
4766 * pvar <-- variable
4767 * c_weight <-- weighted gradient coefficient variable
4768 * grad --> gradient of pvar (du_i/dx_j : grad[][i][j])
4769 *----------------------------------------------------------------------------*/
4770
4771 static void
_initialize_vector_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,cs_halo_type_t halo_type,int inc,const cs_real_3_t * restrict coefav,const cs_real_33_t * restrict coefbv,const cs_real_3_t * restrict pvar,const cs_real_t * restrict c_weight,cs_real_33_t * restrict grad)4772 _initialize_vector_gradient(const cs_mesh_t *m,
4773 const cs_mesh_quantities_t *fvq,
4774 const cs_internal_coupling_t *cpl,
4775 cs_halo_type_t halo_type,
4776 int inc,
4777 const cs_real_3_t *restrict coefav,
4778 const cs_real_33_t *restrict coefbv,
4779 const cs_real_3_t *restrict pvar,
4780 const cs_real_t *restrict c_weight,
4781 cs_real_33_t *restrict grad)
4782 {
4783 const cs_lnum_t n_cells = m->n_cells;
4784 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
4785 const int n_i_groups = m->i_face_numbering->n_groups;
4786 const int n_i_threads = m->i_face_numbering->n_threads;
4787 const int n_b_groups = m->b_face_numbering->n_groups;
4788 const int n_b_threads = m->b_face_numbering->n_threads;
4789 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
4790 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
4791
4792 const cs_lnum_2_t *restrict i_face_cells
4793 = (const cs_lnum_2_t *restrict)m->i_face_cells;
4794 const cs_lnum_t *restrict b_face_cells
4795 = (const cs_lnum_t *restrict)m->b_face_cells;
4796
4797 const int *restrict c_disable_flag = fvq->c_disable_flag;
4798 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
4799
4800 const cs_real_t *restrict weight = fvq->weight;
4801 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
4802 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
4803 cell_f_vol = fvq->cell_vol;
4804
4805 const cs_real_3_t *restrict i_f_face_normal
4806 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
4807 const cs_real_3_t *restrict b_f_face_normal
4808 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
4809
4810 bool *coupled_faces = (cpl == NULL) ?
4811 NULL : (bool *)cpl->coupled_faces;
4812
4813 /* Computation without reconstruction */
4814 /*------------------------------------*/
4815
4816 /* Initialization */
4817
4818 # pragma omp parallel for
4819 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
4820 for (cs_lnum_t i = 0; i < 3; i++) {
4821 for (cs_lnum_t j = 0; j < 3; j++)
4822 grad[c_id][i][j] = 0.0;
4823 }
4824 }
4825
4826 /* Interior faces contribution */
4827
4828 for (int g_id = 0; g_id < n_i_groups; g_id++) {
4829
4830 # pragma omp parallel for
4831 for (int t_id = 0; t_id < n_i_threads; t_id++) {
4832
4833 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
4834 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
4835 f_id++) {
4836
4837 cs_lnum_t c_id1 = i_face_cells[f_id][0];
4838 cs_lnum_t c_id2 = i_face_cells[f_id][1];
4839
4840 cs_real_t pond = weight[f_id];
4841
4842 cs_real_t ktpond = (c_weight == NULL) ?
4843 pond : // no cell weighting
4844 pond * c_weight[c_id1] // cell weighting active
4845 / ( pond * c_weight[c_id1]
4846 + (1.0-pond)* c_weight[c_id2]);
4847
4848 /*
4849 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
4850 + (1-\alpha_\ij) \varia_\cellj\f$
4851 but for the cell \f$ \celli \f$ we remove
4852 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
4853 and for the cell \f$ \cellj \f$ we remove
4854 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
4855 */
4856 for (cs_lnum_t i = 0; i < 3; i++) {
4857 cs_real_t pfaci = (1.0-ktpond) * (pvar[c_id2][i] - pvar[c_id1][i]);
4858 cs_real_t pfacj = - ktpond * (pvar[c_id2][i] - pvar[c_id1][i]);
4859
4860 for (cs_lnum_t j = 0; j < 3; j++) {
4861 grad[c_id1][i][j] += pfaci * i_f_face_normal[f_id][j];
4862 grad[c_id2][i][j] -= pfacj * i_f_face_normal[f_id][j];
4863 }
4864 }
4865
4866 } /* End of loop on faces */
4867
4868 } /* End of loop on threads */
4869
4870 } /* End of loop on thread groups */
4871
4872 /* Contribution from coupled faces */
4873 if (cpl != NULL)
4874 cs_internal_coupling_initialize_vector_gradient
4875 (cpl, c_weight, pvar, grad);
4876
4877 /* Boundary face treatment */
4878
4879 for (int g_id = 0; g_id < n_b_groups; g_id++) {
4880
4881 # pragma omp parallel for
4882 for (int t_id = 0; t_id < n_b_threads; t_id++) {
4883
4884 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
4885 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
4886 f_id++) {
4887
4888 if (cpl == NULL || !coupled_faces[f_id]) {
4889
4890 cs_lnum_t c_id = b_face_cells[f_id];
4891
4892 for (cs_lnum_t i = 0; i < 3; i++) {
4893 cs_real_t pfac = inc*coefav[f_id][i];
4894
4895 for (cs_lnum_t k = 0; k < 3; k++) {
4896 if (i == k)
4897 pfac += (coefbv[f_id][i][k] - 1.0) * pvar[c_id][k];
4898 else
4899 pfac += coefbv[f_id][i][k] * pvar[c_id][k];
4900 }
4901
4902 for (cs_lnum_t j = 0; j < 3; j++)
4903 grad[c_id][i][j] += pfac * b_f_face_normal[f_id][j];
4904 }
4905 }
4906
4907 } /* loop on faces */
4908
4909 } /* loop on threads */
4910
4911 } /* loop on thread groups */
4912
4913 # pragma omp parallel for
4914 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
4915 cs_real_t dvol;
4916 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
4917 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
4918 dvol = 1. / cell_f_vol[c_id];
4919 else
4920 dvol = 0.;
4921
4922 for (cs_lnum_t i = 0; i < 3; i++) {
4923 for (cs_lnum_t j = 0; j < 3; j++)
4924 grad[c_id][i][j] *= dvol;
4925 }
4926 }
4927
4928 /* Periodicity and parallelism treatment */
4929
4930 if (m->halo != NULL) {
4931 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)grad, 9);
4932 if (cs_glob_mesh->have_rotation_perio)
4933 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)grad);
4934 }
4935 }
4936
4937 /*----------------------------------------------------------------------------
4938 * Reconstruct the gradient of a vector using a given gradient of
4939 * this vector (typically lsq).
4940 *
4941 * parameters:
4942 * m <-- pointer to associated mesh structure
4943 * fvq <-- pointer to associated finite volume quantities
4944 * cpl <-- structure associated with internal coupling, or NULL
4945 * inc <-- if 0, solve on increment; 1 otherwise
4946 * coefav <-- B.C. coefficients for boundary face normals
4947 * coefbv <-- B.C. coefficients for boundary face normals
4948 * pvar <-- variable
4949 * c_weight <-- weighted gradient coefficient variable
4950 * r_grad --> gradient used for reconstruction
4951 * grad --> gradient of pvar (du_i/dx_j : grad[][i][j])
4952 *----------------------------------------------------------------------------*/
4953
4954 static void
_reconstruct_vector_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,cs_halo_type_t halo_type,int inc,const cs_real_3_t * restrict coefav,const cs_real_33_t * restrict coefbv,const cs_real_3_t * restrict pvar,const cs_real_t * restrict c_weight,cs_real_33_t * restrict r_grad,cs_real_33_t * restrict grad)4955 _reconstruct_vector_gradient(const cs_mesh_t *m,
4956 const cs_mesh_quantities_t *fvq,
4957 const cs_internal_coupling_t *cpl,
4958 cs_halo_type_t halo_type,
4959 int inc,
4960 const cs_real_3_t *restrict coefav,
4961 const cs_real_33_t *restrict coefbv,
4962 const cs_real_3_t *restrict pvar,
4963 const cs_real_t *restrict c_weight,
4964 cs_real_33_t *restrict r_grad,
4965 cs_real_33_t *restrict grad)
4966 {
4967 const cs_lnum_t n_cells = m->n_cells;
4968 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
4969 const int n_i_groups = m->i_face_numbering->n_groups;
4970 const int n_i_threads = m->i_face_numbering->n_threads;
4971 const int n_b_groups = m->b_face_numbering->n_groups;
4972 const int n_b_threads = m->b_face_numbering->n_threads;
4973 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
4974 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
4975
4976 const cs_lnum_2_t *restrict i_face_cells
4977 = (const cs_lnum_2_t *restrict)m->i_face_cells;
4978 const cs_lnum_t *restrict b_face_cells
4979 = (const cs_lnum_t *restrict)m->b_face_cells;
4980
4981 const int *restrict c_disable_flag = fvq->c_disable_flag;
4982 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
4983
4984 const cs_real_t *restrict weight = fvq->weight;
4985 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
4986 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
4987 cell_f_vol = fvq->cell_vol;
4988
4989 const cs_real_3_t *restrict i_f_face_normal
4990 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
4991 const cs_real_3_t *restrict b_f_face_normal
4992 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
4993 const cs_real_3_t *restrict diipb
4994 = (const cs_real_3_t *restrict)fvq->diipb;
4995 const cs_real_3_t *restrict dofij
4996 = (const cs_real_3_t *restrict)fvq->dofij;
4997 const cs_real_33_t *restrict corr_grad_lin
4998 = (const cs_real_33_t *restrict)fvq->corr_grad_lin;
4999
5000 bool *coupled_faces = (cpl == NULL) ?
5001 NULL : (bool *)cpl->coupled_faces;
5002
5003 /* Initialize gradient */
5004 /*---------------------*/
5005
5006 /* Initialization */
5007
5008 # pragma omp parallel for
5009 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
5010 for (cs_lnum_t i = 0; i < 3; i++) {
5011 for (cs_lnum_t j = 0; j < 3; j++)
5012 grad[c_id][i][j] = 0.0;
5013 }
5014 }
5015
5016 /* Interior faces contribution */
5017
5018 for (int g_id = 0; g_id < n_i_groups; g_id++) {
5019
5020 # pragma omp parallel for
5021 for (int t_id = 0; t_id < n_i_threads; t_id++) {
5022
5023 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
5024 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
5025 f_id++) {
5026
5027 cs_lnum_t c_id1 = i_face_cells[f_id][0];
5028 cs_lnum_t c_id2 = i_face_cells[f_id][1];
5029
5030 cs_real_t pond = weight[f_id];
5031
5032 cs_real_t ktpond = (c_weight == NULL) ?
5033 pond : // no cell weighting
5034 pond * c_weight[c_id1] // cell weighting active
5035 / ( pond * c_weight[c_id1]
5036 + (1.0-pond)* c_weight[c_id2]);
5037
5038 /*
5039 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
5040 + (1-\alpha_\ij) \varia_\cellj\f$
5041 but for the cell \f$ \celli \f$ we remove
5042 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5043 and for the cell \f$ \cellj \f$ we remove
5044 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
5045 */
5046
5047 for (cs_lnum_t i = 0; i < 3; i++) {
5048
5049 cs_real_t pfaci = (1.0-ktpond) * (pvar[c_id2][i] - pvar[c_id1][i]);
5050 cs_real_t pfacj = - ktpond * (pvar[c_id2][i] - pvar[c_id1][i]);
5051
5052 /* Reconstruction part */
5053 cs_real_t rfac = 0.5 * ( dofij[f_id][0]*( r_grad[c_id1][i][0]
5054 + r_grad[c_id2][i][0])
5055 + dofij[f_id][1]*( r_grad[c_id1][i][1]
5056 + r_grad[c_id2][i][1])
5057 + dofij[f_id][2]*( r_grad[c_id1][i][2]
5058 + r_grad[c_id2][i][2]));
5059
5060 for (cs_lnum_t j = 0; j < 3; j++) {
5061 grad[c_id1][i][j] += (pfaci + rfac) * i_f_face_normal[f_id][j];
5062 grad[c_id2][i][j] -= (pfacj + rfac) * i_f_face_normal[f_id][j];
5063 }
5064
5065 }
5066
5067 } /* End of loop on faces */
5068
5069 } /* End of loop on threads */
5070
5071 } /* End of loop on thread groups */
5072
5073 /* Contribution from coupled faces */
5074 if (cpl != NULL) {
5075 cs_internal_coupling_initialize_vector_gradient(cpl, c_weight, pvar, grad);
5076 cs_internal_coupling_reconstruct_vector_gradient(cpl, r_grad, grad);
5077 }
5078
5079 /* Boundary face treatment */
5080
5081 for (int g_id = 0; g_id < n_b_groups; g_id++) {
5082
5083 # pragma omp parallel for
5084 for (int t_id = 0; t_id < n_b_threads; t_id++) {
5085
5086 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5087 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5088 f_id++) {
5089
5090 if (cpl == NULL || !coupled_faces[f_id]) {
5091 cs_lnum_t c_id = b_face_cells[f_id];
5092
5093 /*
5094 Remark: for the cell \f$ \celli \f$ we remove
5095 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5096 */
5097
5098 for (cs_lnum_t i = 0; i < 3; i++) {
5099
5100 cs_real_t pfac = inc*coefav[f_id][i];
5101
5102 for (cs_lnum_t k = 0; k < 3; k++)
5103 pfac += coefbv[f_id][i][k] * pvar[c_id][k];
5104
5105 pfac -= pvar[c_id][i];
5106
5107 /* Reconstruction part */
5108 cs_real_t rfac = 0.;
5109 for (cs_lnum_t k = 0; k < 3; k++) {
5110 cs_real_t vecfac = r_grad[c_id][k][0] * diipb[f_id][0]
5111 + r_grad[c_id][k][1] * diipb[f_id][1]
5112 + r_grad[c_id][k][2] * diipb[f_id][2];
5113 rfac += coefbv[f_id][i][k] * vecfac;
5114 }
5115
5116 for (cs_lnum_t j = 0; j < 3; j++)
5117 grad[c_id][i][j] += (pfac + rfac) * b_f_face_normal[f_id][j];
5118 }
5119 }
5120
5121 } /* loop on faces */
5122
5123 } /* loop on threads */
5124
5125 } /* loop on thread groups */
5126
5127 # pragma omp parallel for
5128 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
5129 cs_real_t dvol;
5130 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
5131 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
5132 dvol = 1. / cell_f_vol[c_id];
5133 else
5134 dvol = 0.;
5135
5136 for (cs_lnum_t i = 0; i < 3; i++) {
5137 for (cs_lnum_t j = 0; j < 3; j++)
5138 grad[c_id][i][j] *= dvol;
5139 }
5140
5141 if (cs_glob_mesh_quantities_flag & CS_BAD_CELLS_WARPED_CORRECTION) {
5142 cs_real_t gradpa[3];
5143 for (cs_lnum_t i = 0; i < 3; i++) {
5144 for (cs_lnum_t j = 0; j < 3; j++) {
5145 gradpa[j] = grad[c_id][i][j];
5146 grad[c_id][i][j] = 0.;
5147 }
5148
5149 for (cs_lnum_t j = 0; j < 3; j++)
5150 for (cs_lnum_t k = 0; k < 3; k++)
5151 grad[c_id][i][j] += corr_grad_lin[c_id][j][k] * gradpa[k];
5152 }
5153 }
5154 }
5155
5156 /* Periodicity and parallelism treatment */
5157
5158 if (m->halo != NULL) {
5159 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)grad, 9);
5160 if (cs_glob_mesh->have_rotation_perio)
5161 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)grad);
5162 }
5163 }
5164
5165 /*----------------------------------------------------------------------------
5166 * Compute the gradient of a vector with an iterative technique in order to
5167 * handle non-orthoganalities (n_r_sweeps > 1).
5168 *
5169 * We do not take into account any volumic force here.
5170 *
5171 * parameters:
5172 * m <-- pointer to associated mesh structure
5173 * fvq <-> pointer to associated finite volume quantities
5174 * cpl <-> structure associated with internal coupling, or NULL
5175 * var_name <-- variable's name
5176 * gradient_info <-- pointer to performance logging structure, or NULL
5177 * halo_type <-- halo type (extended or not)
5178 * inc <-- if 0, solve on increment; 1 otherwise
5179 * n_r_sweeps --> >1: with reconstruction
5180 * verbosity --> verbosity level
5181 * epsrgp --> precision for iterative gradient calculation
5182 * coefav <-- B.C. coefficients for boundary face normals
5183 * coefbv <-- B.C. coefficients for boundary face normals
5184 * pvar <-- variable
5185 * c_weight <-- weighted gradient coefficient variable
5186 * grad <-> gradient of pvar (du_i/dx_j : grad[][i][j])
5187 *----------------------------------------------------------------------------*/
5188
5189 static void
_iterative_vector_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,const char * var_name,cs_gradient_info_t * gradient_info,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_real_t epsrgp,const cs_real_3_t * restrict coefav,const cs_real_33_t * restrict coefbv,const cs_real_3_t * restrict pvar,const cs_real_t * c_weight,cs_real_33_t * restrict grad)5190 _iterative_vector_gradient(const cs_mesh_t *m,
5191 const cs_mesh_quantities_t *fvq,
5192 const cs_internal_coupling_t *cpl,
5193 const char *var_name,
5194 cs_gradient_info_t *gradient_info,
5195 cs_halo_type_t halo_type,
5196 int inc,
5197 int n_r_sweeps,
5198 int verbosity,
5199 cs_real_t epsrgp,
5200 const cs_real_3_t *restrict coefav,
5201 const cs_real_33_t *restrict coefbv,
5202 const cs_real_3_t *restrict pvar,
5203 const cs_real_t *c_weight,
5204 cs_real_33_t *restrict grad)
5205 {
5206 int isweep = 0;
5207
5208 cs_real_33_t *rhs;
5209
5210 const cs_lnum_t n_cells = m->n_cells;
5211 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
5212 const int n_i_groups = m->i_face_numbering->n_groups;
5213 const int n_i_threads = m->i_face_numbering->n_threads;
5214 const int n_b_groups = m->b_face_numbering->n_groups;
5215 const int n_b_threads = m->b_face_numbering->n_threads;
5216 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
5217 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
5218
5219 const cs_lnum_2_t *restrict i_face_cells
5220 = (const cs_lnum_2_t *restrict)m->i_face_cells;
5221 const cs_lnum_t *restrict b_face_cells
5222 = (const cs_lnum_t *restrict)m->b_face_cells;
5223
5224 const int *restrict c_disable_flag = fvq->c_disable_flag;
5225 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
5226
5227 const cs_real_t *restrict weight = fvq->weight;
5228 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
5229 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
5230 cell_f_vol = fvq->cell_vol;
5231 const cs_real_3_t *restrict i_f_face_normal
5232 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
5233 const cs_real_3_t *restrict b_f_face_normal
5234 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
5235 const cs_real_3_t *restrict diipb
5236 = (const cs_real_3_t *restrict)fvq->diipb;
5237 const cs_real_3_t *restrict dofij
5238 = (const cs_real_3_t *restrict)fvq->dofij;
5239
5240 int gq_id = (cpl == NULL) ? 0 : cpl->id+1;
5241 cs_gradient_quantities_t *gq = _gradient_quantities_get(gq_id);
5242
5243 cs_real_33_t *restrict cocg = gq->cocg_it;
5244 if (cocg == NULL)
5245 cocg = _compute_cell_cocg_it(m, fvq, cpl, gq);
5246
5247 bool *coupled_faces = (cpl == NULL) ?
5248 NULL : (bool *)cpl->coupled_faces;
5249
5250 BFT_MALLOC(rhs, n_cells_ext, cs_real_33_t);
5251
5252 /* Gradient reconstruction to handle non-orthogonal meshes */
5253 /*---------------------------------------------------------*/
5254
5255 /* L2 norm */
5256
5257 cs_real_t l2_norm = _l2_norm_1(9*n_cells, (cs_real_t *)grad);
5258 cs_real_t l2_residual = l2_norm;
5259
5260 if (l2_norm > cs_math_epzero) {
5261
5262 /* Iterative process */
5263 /*-------------------*/
5264
5265 for (isweep = 1; isweep < n_r_sweeps && l2_residual > epsrgp*l2_norm; isweep++) {
5266
5267 /* Computation of the Right Hand Side*/
5268
5269 # pragma omp parallel for
5270 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
5271 for (cs_lnum_t i = 0; i < 3; i++) {
5272 for (cs_lnum_t j = 0; j < 3; j++)
5273 rhs[c_id][i][j] = -grad[c_id][i][j] * cell_f_vol[c_id];
5274 }
5275 }
5276
5277 /* Interior face treatment */
5278
5279 for (int g_id = 0; g_id < n_i_groups; g_id++) {
5280
5281 # pragma omp parallel for
5282 for (int t_id = 0; t_id < n_i_threads; t_id++) {
5283
5284 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
5285 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
5286 f_id++) {
5287
5288 cs_lnum_t c_id1 = i_face_cells[f_id][0];
5289 cs_lnum_t c_id2 = i_face_cells[f_id][1];
5290 cs_real_t pond = weight[f_id];
5291
5292 cs_real_t ktpond = (c_weight == NULL) ?
5293 pond : // no cell weighting
5294 pond * c_weight[c_id1] // cell weighting active
5295 / ( pond * c_weight[c_id1]
5296 + (1.0-pond) * c_weight[c_id2]);
5297
5298 /*
5299 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
5300 + (1-\alpha_\ij) \varia_\cellj\f$
5301 but for the cell \f$ \celli \f$ we remove
5302 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5303 and for the cell \f$ \cellj \f$ we remove
5304 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
5305 */
5306
5307 for (cs_lnum_t i = 0; i < 3; i++) {
5308
5309 /* Reconstruction part */
5310 cs_real_t
5311 pfaci = 0.5 * ( (grad[c_id1][i][0] + grad[c_id2][i][0])
5312 * dofij[f_id][0]
5313 + (grad[c_id1][i][1] + grad[c_id2][i][1])
5314 * dofij[f_id][1]
5315 + (grad[c_id1][i][2] + grad[c_id2][i][2])
5316 * dofij[f_id][2]);
5317 cs_real_t pfacj = pfaci;
5318
5319 pfaci += (1.0-ktpond) * (pvar[c_id2][i] - pvar[c_id1][i]);
5320 pfacj -= ktpond * (pvar[c_id2][i] - pvar[c_id1][i]);
5321
5322 for (cs_lnum_t j = 0; j < 3; j++) {
5323 rhs[c_id1][i][j] += pfaci * i_f_face_normal[f_id][j];
5324 rhs[c_id2][i][j] -= pfacj * i_f_face_normal[f_id][j];
5325 }
5326 }
5327
5328 } /* loop on faces */
5329
5330 } /* loop on threads */
5331
5332 } /* loop on thread groups */
5333
5334 /* Contribution from coupled faces */
5335 if (cpl != NULL)
5336 cs_internal_coupling_iterative_vector_gradient
5337 (cpl, c_weight, grad, pvar, rhs);
5338
5339 /* Boundary face treatment */
5340
5341 for (int g_id = 0; g_id < n_b_groups; g_id++) {
5342
5343 # pragma omp parallel for
5344 for (int t_id = 0; t_id < n_b_threads; t_id++) {
5345
5346 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5347 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5348 f_id++) {
5349
5350 if (cpl == NULL || !coupled_faces[f_id]) {
5351
5352 cs_lnum_t c_id = b_face_cells[f_id];
5353
5354 for (cs_lnum_t i = 0; i < 3; i++) {
5355
5356 /*
5357 Remark: for the cell \f$ \celli \f$ we remove
5358 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5359 */
5360
5361 cs_real_t pfac = inc*coefav[f_id][i];
5362
5363 for (cs_lnum_t k = 0; k < 3; k++) {
5364 /* Reconstruction part */
5365 cs_real_t vecfac = grad[c_id][k][0] * diipb[f_id][0]
5366 + grad[c_id][k][1] * diipb[f_id][1]
5367 + grad[c_id][k][2] * diipb[f_id][2];
5368 pfac += coefbv[f_id][i][k] * vecfac;
5369
5370 if (i == k)
5371 pfac += (coefbv[f_id][i][k] - 1.0) * pvar[c_id][k];
5372 else
5373 pfac += coefbv[f_id][i][k] * pvar[c_id][k];
5374 }
5375
5376 for (cs_lnum_t j = 0; j < 3; j++)
5377 rhs[c_id][i][j] += pfac * b_f_face_normal[f_id][j];
5378
5379 }
5380 }
5381
5382 } /* loop on faces */
5383
5384 } /* loop on threads */
5385
5386 } /* loop on thread groups */
5387
5388 /* Increment of the gradient */
5389
5390 # pragma omp parallel for
5391 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
5392 cs_real_t dvol;
5393 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
5394 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
5395 dvol = 1. / cell_f_vol[c_id];
5396 else
5397 dvol = 0.;
5398
5399 for (cs_lnum_t i = 0; i < 3; i++) {
5400 for (cs_lnum_t j = 0; j < 3; j++)
5401 rhs[c_id][i][j] *= dvol;
5402 }
5403
5404 for (cs_lnum_t i = 0; i < 3; i++) {
5405 for (cs_lnum_t j = 0; j < 3; j++) {
5406 for (cs_lnum_t k = 0; k < 3; k++)
5407 grad[c_id][i][j] += rhs[c_id][i][k] * cocg[c_id][k][j];
5408 }
5409 }
5410 }
5411
5412 /* Periodicity and parallelism treatment */
5413
5414 if (m->halo != NULL) {
5415 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)grad, 9);
5416 if (cs_glob_mesh->have_rotation_perio)
5417 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)grad);
5418 }
5419
5420 /* Convergence test (L2 norm) */
5421
5422 l2_residual = _l2_norm_1(9*n_cells, (cs_real_t *)rhs);
5423
5424 } /* End of the iterative process */
5425
5426 /* Printing */
5427
5428 if (l2_residual < epsrgp*l2_norm) {
5429 if (verbosity >= 2) {
5430 bft_printf
5431 (_(" %s: isweep = %d, normed residual: %e, norm: %e, var: %s\n"),
5432 __func__, isweep, l2_residual/l2_norm, l2_norm, var_name);
5433 }
5434 }
5435 else if (isweep >= n_r_sweeps) {
5436 if (verbosity >= 0) {
5437 bft_printf(_(" Warning:\n"
5438 " --------\n"
5439 " %s; variable: %s; sweeps: %d\n"
5440 " %*s normed residual: %11.4e; norm: %11.4e\n"),
5441 __func__, var_name, isweep,
5442 (int)(strlen(__func__)), " ", l2_residual/l2_norm, l2_norm);
5443 }
5444 }
5445
5446 }
5447
5448 if (gradient_info != NULL)
5449 _gradient_info_update_iter(gradient_info, isweep);
5450
5451 BFT_FREE(rhs);
5452 }
5453
5454 /*----------------------------------------------------------------------------
5455 * Compute the gradient of a vector with an iterative technique in order to
5456 * handle non-orthoganalities (n_r_sweeps > 1).
5457 *
5458 * We do not take into account any volumic force here.
5459 *
5460 * parameters:
5461 * m <-- pointer to associated mesh structure
5462 * fvq <-> pointer to associated finite volume quantities
5463 * var_name <-- variable's name
5464 * gradient_info <-- pointer to performance logging structure, or NULL
5465 * halo_type <-- halo type (extended or not)
5466 * inc <-- if 0, solve on increment; 1 otherwise
5467 * n_r_sweeps --> >1: with reconstruction
5468 * verbosity --> verbosity level
5469 * epsrgp --> precision for iterative gradient calculation
5470 * coefav <-- B.C. coefficients for boundary face normals
5471 * coefbv <-- B.C. coefficients for boundary face normals
5472 * pvar <-- variable
5473 * grad <-> gradient of pvar (du_i/dx_j : grad[][i][j])
5474 *----------------------------------------------------------------------------*/
5475
5476 static void
_iterative_tensor_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const char * var_name,cs_gradient_info_t * gradient_info,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_real_t epsrgp,const cs_real_6_t * restrict coefat,const cs_real_66_t * restrict coefbt,const cs_real_6_t * restrict pvar,cs_real_63_t * restrict grad)5477 _iterative_tensor_gradient(const cs_mesh_t *m,
5478 const cs_mesh_quantities_t *fvq,
5479 const char *var_name,
5480 cs_gradient_info_t *gradient_info,
5481 cs_halo_type_t halo_type,
5482 int inc,
5483 int n_r_sweeps,
5484 int verbosity,
5485 cs_real_t epsrgp,
5486 const cs_real_6_t *restrict coefat,
5487 const cs_real_66_t *restrict coefbt,
5488 const cs_real_6_t *restrict pvar,
5489 cs_real_63_t *restrict grad)
5490 {
5491 int isweep = 0;
5492
5493 cs_real_63_t *rhs;
5494
5495 const cs_lnum_t n_cells = m->n_cells;
5496 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
5497 const int n_i_groups = m->i_face_numbering->n_groups;
5498 const int n_i_threads = m->i_face_numbering->n_threads;
5499 const int n_b_groups = m->b_face_numbering->n_groups;
5500 const int n_b_threads = m->b_face_numbering->n_threads;
5501 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
5502 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
5503
5504 const cs_lnum_2_t *restrict i_face_cells
5505 = (const cs_lnum_2_t *restrict)m->i_face_cells;
5506 const cs_lnum_t *restrict b_face_cells
5507 = (const cs_lnum_t *restrict)m->b_face_cells;
5508
5509 const int *restrict c_disable_flag = fvq->c_disable_flag;
5510 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
5511
5512 const cs_real_t *restrict weight = fvq->weight;
5513 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
5514 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
5515 cell_f_vol = fvq->cell_vol;
5516 const cs_real_3_t *restrict i_f_face_normal
5517 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
5518 const cs_real_3_t *restrict b_f_face_normal
5519 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
5520 const cs_real_3_t *restrict diipb
5521 = (const cs_real_3_t *restrict)fvq->diipb;
5522 const cs_real_3_t *restrict dofij
5523 = (const cs_real_3_t *restrict)fvq->dofij;
5524
5525 cs_gradient_quantities_t *gq = _gradient_quantities_get(0);
5526
5527 cs_real_33_t *restrict cocg = gq->cocg_it;
5528 if (cocg == NULL)
5529 cocg = _compute_cell_cocg_it(m, fvq, NULL, gq);
5530
5531 BFT_MALLOC(rhs, n_cells_ext, cs_real_63_t);
5532
5533 /* Gradient reconstruction to handle non-orthogonal meshes */
5534 /*---------------------------------------------------------*/
5535
5536 /* L2 norm */
5537
5538 cs_real_t l2_norm = _l2_norm_1(18*n_cells, (cs_real_t *)grad);
5539 cs_real_t l2_residual = l2_norm ;
5540
5541 if (l2_norm > cs_math_epzero) {
5542
5543 /* Iterative process */
5544 /*-------------------*/
5545
5546 for (isweep = 1; isweep < n_r_sweeps && l2_residual > epsrgp*l2_norm; isweep++) {
5547
5548 /* Computation of the Right Hand Side*/
5549
5550 # pragma omp parallel for
5551 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
5552 for (cs_lnum_t i = 0; i < 6; i++) {
5553 for (cs_lnum_t j = 0; j < 3; j++)
5554 rhs[c_id][i][j] = - cell_f_vol[c_id] * grad[c_id][i][j];
5555 }
5556 }
5557
5558 /* Interior face treatment */
5559
5560 for (int g_id = 0; g_id < n_i_groups; g_id++) {
5561
5562 # pragma omp parallel for
5563 for (int t_id = 0; t_id < n_i_threads; t_id++) {
5564
5565 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
5566 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
5567 f_id++) {
5568
5569 cs_lnum_t c_id1 = i_face_cells[f_id][0];
5570 cs_lnum_t c_id2 = i_face_cells[f_id][1];
5571 cs_real_t pond = weight[f_id];
5572
5573 /*
5574 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
5575 + (1-\alpha_\ij) \varia_\cellj\f$
5576 but for the cell \f$ \celli \f$ we remove
5577 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5578 and for the cell \f$ \cellj \f$ we remove
5579 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
5580 */
5581
5582 for (cs_lnum_t i = 0; i < 6; i++) {
5583
5584 /* Reconstruction part */
5585 cs_real_t
5586 pfaci = 0.5 * ( (grad[c_id1][i][0] + grad[c_id2][i][0])
5587 * dofij[f_id][0]
5588 + (grad[c_id1][i][1] + grad[c_id2][i][1])
5589 * dofij[f_id][1]
5590 + (grad[c_id1][i][2] + grad[c_id2][i][2])
5591 * dofij[f_id][2]);
5592 cs_real_t pfacj = pfaci;
5593
5594 pfaci += (1.0-pond) * (pvar[c_id2][i] - pvar[c_id1][i]);
5595 pfacj -= pond * (pvar[c_id2][i] - pvar[c_id1][i]);
5596 for (cs_lnum_t j = 0; j < 3; j++) {
5597 rhs[c_id1][i][j] += pfaci * i_f_face_normal[f_id][j];
5598 rhs[c_id2][i][j] -= pfacj * i_f_face_normal[f_id][j];
5599 }
5600 }
5601
5602 } /* loop on faces */
5603
5604 } /* loop on threads */
5605
5606 } /* loop on thread groups */
5607
5608 /* Boundary face treatment */
5609
5610 for (int g_id = 0; g_id < n_b_groups; g_id++) {
5611
5612 # pragma omp parallel for
5613 for (int t_id = 0; t_id < n_b_threads; t_id++) {
5614
5615 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
5616 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
5617 f_id++) {
5618
5619 cs_lnum_t c_id = b_face_cells[f_id];
5620
5621 for (cs_lnum_t i = 0; i < 6; i++) {
5622
5623 /*
5624 Remark: for the cell \f$ \celli \f$ we remove
5625 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
5626 */
5627
5628 cs_real_t pfac = inc*coefat[f_id][i];
5629
5630 for (cs_lnum_t k = 0; k < 6; k++) {
5631 /* Reconstruction part */
5632 cs_real_t vecfac = grad[c_id][k][0] * diipb[f_id][0]
5633 + grad[c_id][k][1] * diipb[f_id][1]
5634 + grad[c_id][k][2] * diipb[f_id][2];
5635 pfac += coefbt[f_id][i][k] * vecfac;
5636
5637 if (i == k)
5638 pfac += (coefbt[f_id][i][k] - 1.0) * pvar[c_id][k];
5639 else
5640 pfac += coefbt[f_id][i][k] * pvar[c_id][k];
5641 }
5642
5643 for (cs_lnum_t j = 0; j < 3; j++)
5644 rhs[c_id][i][j] += pfac * b_f_face_normal[f_id][j];
5645
5646 }
5647
5648 } /* loop on faces */
5649
5650 } /* loop on threads */
5651
5652 } /* loop on thread groups */
5653
5654 /* Increment of the gradient */
5655
5656 # pragma omp parallel for
5657 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
5658 cs_real_t dvol;
5659 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
5660 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
5661 dvol = 1. / cell_f_vol[c_id];
5662 else
5663 dvol = 0.;
5664
5665 for (cs_lnum_t i = 0; i < 6; i++) {
5666 for (cs_lnum_t j = 0; j < 3; j++)
5667 rhs[c_id][i][j] *= dvol;
5668 }
5669
5670 for (cs_lnum_t i = 0; i < 6; i++) {
5671 for (cs_lnum_t j = 0; j < 3; j++) {
5672 for (cs_lnum_t k = 0; k < 3; k++)
5673 grad[c_id][i][j] += rhs[c_id][i][k] * cocg[c_id][k][j];
5674 }
5675 }
5676 }
5677
5678 /* Periodicity and parallelism treatment */
5679
5680 if (m->halo != NULL) {
5681 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)grad, 18);
5682 if (cs_glob_mesh->have_rotation_perio)
5683 cs_halo_perio_sync_var_sym_tens_grad(m->halo,
5684 halo_type,
5685 (cs_real_t *)grad);
5686 }
5687
5688 /* Convergence test (L2 norm) */
5689
5690 ///FIXME
5691 l2_residual = _l2_norm_1(18*n_cells, (cs_real_t *)rhs);
5692
5693 } /* End of the iterative process */
5694
5695 /* Printing */
5696
5697 if (l2_residual < epsrgp*l2_norm) {
5698 if (verbosity >= 2) {
5699 bft_printf
5700 (_(" %s: isweep = %d, normed residual: %e, norm: %e, var: %s\n"),
5701 __func__, isweep, l2_residual/l2_norm, l2_norm, var_name);
5702 }
5703 }
5704 else if (isweep >= n_r_sweeps) {
5705 if (verbosity >= 0) {
5706 bft_printf(_(" Warning:\n"
5707 " --------\n"
5708 " %s; variable: %s; sweeps: %d\n"
5709 " %*s normed residual: %11.4e; norm: %11.4e\n"),
5710 __func__, var_name, isweep,
5711 (int)(strlen(__func__)), " ", l2_residual/l2_norm, l2_norm);
5712 }
5713 }
5714
5715 }
5716
5717 if (gradient_info != NULL)
5718 _gradient_info_update_iter(gradient_info, isweep);
5719
5720 BFT_FREE(rhs);
5721 }
5722
5723 /*----------------------------------------------------------------------------
5724 * Complete initialization of cocg for lsq vector and tensor gradient.
5725 *
5726 * parameters:
5727 * c_id <-- cell id
5728 * halo_type <-- halo type
5729 * madj <-- pointer to mesh adjacencies structure
5730 * fvq <-- pointer to associated finite volume quantities
5731 * cocgb --> cocg
5732 *----------------------------------------------------------------------------*/
5733
5734 #if defined(__INTEL_COMPILER)
5735 #pragma optimization_level 2 /* Bug with O3 or above with icc 18.0.1 20171018
5736 at least on Xeon(R) Gold 6140 ? */
5737 #endif
5738
5739 static void
_complete_cocg_lsq(cs_lnum_t c_id,const cs_mesh_adjacencies_t * madj,const cs_mesh_quantities_t * fvq,const cs_cocg_t cocg[6],cs_real_t cocgb[restrict3][3])5740 _complete_cocg_lsq(cs_lnum_t c_id,
5741 const cs_mesh_adjacencies_t *madj,
5742 const cs_mesh_quantities_t *fvq,
5743 const cs_cocg_t cocg[6],
5744 cs_real_t cocgb[restrict 3][3])
5745 {
5746 /* Short variable accesses */
5747
5748 const cs_real_3_t *restrict b_face_normal
5749 = (const cs_real_3_t *restrict)fvq->b_face_normal;
5750
5751 cs_lnum_t s_id, e_id;
5752
5753 /* initialize cocgb */
5754
5755 cocgb[0][0] = cocg[0];
5756 cocgb[0][1] = cocg[3];
5757 cocgb[0][2] = cocg[5];
5758 cocgb[1][0] = cocg[3];
5759 cocgb[1][1] = cocg[1];
5760 cocgb[1][2] = cocg[4];
5761 cocgb[2][0] = cocg[5];
5762 cocgb[2][1] = cocg[4];
5763 cocgb[2][2] = cocg[2];
5764
5765 /* Contribution from boundary faces */
5766
5767 const cs_lnum_t *restrict cell_b_faces
5768 = (const cs_lnum_t *restrict)(madj->cell_b_faces);
5769
5770 s_id = madj->cell_b_faces_idx[c_id];
5771 e_id = madj->cell_b_faces_idx[c_id+1];
5772
5773 for (cs_lnum_t i = s_id; i < e_id; i++) {
5774
5775 cs_lnum_t f_id = cell_b_faces[i];
5776
5777 cs_real_3_t normal;
5778 /* Normal is vector 0 if the b_face_normal norm is too small */
5779 cs_math_3_normalise(b_face_normal[f_id], normal);
5780
5781 for (cs_lnum_t ii = 0; ii < 3; ii++) {
5782 for (cs_lnum_t jj = 0; jj < 3; jj++)
5783 cocgb[ii][jj] += normal[ii] * normal[jj];
5784 }
5785
5786 }
5787 }
5788
5789 /*----------------------------------------------------------------------------
5790 * Compute cocg and RHS at boundaries for lsq vector gradient.
5791 *
5792 * parameters:
5793 * c_id <-- cell id
5794 * inc <-- if 0, solve on increment; 1 otherwise
5795 * madj <-- pointer to mesh adjacencies structure
5796 * fvq <-- pointer to associated finite volume quantities
5797 * _33_9_idx <-- symmetric indexes mapping
5798 * pvar <-- variable
5799 * coefav <-- B.C. coefficients for boundary face normals
5800 * coefbv <-- B.C. coefficients for boundary face normals
5801 * cocg <-- cocg values
5802 * rhs <-- right hand side
5803 * cocgb_v --> boundary cocg vector values
5804 * rhsb_v --> boundary RHS values
5805 *----------------------------------------------------------------------------*/
5806
5807 static void
_compute_cocgb_rhsb_lsq_v(cs_lnum_t c_id,const int inc,const cs_mesh_adjacencies_t * madj,const cs_mesh_quantities_t * fvq,cs_lnum_t _33_9_idx[const restrict9][2],const cs_real_3_t * restrict pvar,const cs_real_3_t * restrict coefav,const cs_real_33_t * restrict coefbv,const cs_real_t cocg[3][3],const cs_real_t rhs[3][3],cs_real_t cocgb_v[restrict45],cs_real_t rhsb_v[restrict9])5808 _compute_cocgb_rhsb_lsq_v(cs_lnum_t c_id,
5809 const int inc,
5810 const cs_mesh_adjacencies_t *madj,
5811 const cs_mesh_quantities_t *fvq,
5812 cs_lnum_t _33_9_idx[const restrict 9][2],
5813 const cs_real_3_t *restrict pvar,
5814 const cs_real_3_t *restrict coefav,
5815 const cs_real_33_t *restrict coefbv,
5816 const cs_real_t cocg[3][3],
5817 const cs_real_t rhs[3][3],
5818 cs_real_t cocgb_v[restrict 45],
5819 cs_real_t rhsb_v[restrict 9])
5820 {
5821 /* Short variable accesses */
5822
5823 const cs_real_3_t *restrict diipb
5824 = (const cs_real_3_t *restrict)fvq->diipb;
5825
5826 const cs_real_3_t *restrict b_face_normal
5827 = (const cs_real_3_t *restrict)fvq->b_face_normal;
5828 const cs_real_t *restrict b_dist
5829 = (const cs_real_t *restrict)fvq->b_dist;
5830
5831 cs_lnum_t s_id, e_id;
5832
5833 /* initialize cocg and rhsfor lsq vector gradient */
5834
5835 for (int ll = 0; ll < 9; ll++) {
5836
5837 /* index of row first coefficient */
5838 int ll_9 = ll*(ll+1)/2;
5839
5840 for (int mm = 0; mm <= ll; mm++) {
5841 /* initialize */
5842 cocgb_v[ll_9+mm] = 0.;
5843
5844 /* contribution of t[kk][qq] */
5845 int pp = _33_9_idx[ll][0];
5846 int qq = _33_9_idx[ll][1];
5847
5848 /* derivative with respect to t[rr][ss] */
5849 int rr = _33_9_idx[mm][0];
5850 int ss = _33_9_idx[mm][1];
5851
5852 /* part from cocg_s (BCs independant) */
5853 if (pp == rr)
5854 cocgb_v[ll_9+mm] = cocg[qq][ss];
5855
5856 /* part already computed from rhs */
5857 rhsb_v[ll] = rhs[pp][qq];
5858 }
5859 }
5860
5861 s_id = madj->cell_b_faces_idx[c_id];
5862 e_id = madj->cell_b_faces_idx[c_id+1];
5863
5864 const cs_lnum_t *restrict cell_b_faces
5865 = (const cs_lnum_t *restrict)(madj->cell_b_faces);
5866
5867 for (cs_lnum_t i = s_id; i < e_id; i++) {
5868
5869 cs_lnum_t f_id = cell_b_faces[i];
5870
5871 /* build cocgb_v matrix */
5872
5873 const cs_real_t *restrict iipbf = diipb[f_id];
5874
5875 cs_real_3_t nb;
5876 /* Normal is vector 0 if the b_face_normal norm is too small */
5877 cs_math_3_normalise(b_face_normal[f_id], nb);
5878
5879 cs_real_t db = 1./b_dist[f_id];
5880 cs_real_t db2 = db*db;
5881
5882 /* A and (B - I) */
5883 cs_real_t a[3];
5884 cs_real_t bt[3][3];
5885 for (int ll = 0; ll < 3; ll++) {
5886 for (int pp = 0; pp < 3; pp++)
5887 bt[ll][pp] = coefbv[f_id][ll][pp];
5888 }
5889 for (int ll = 0; ll < 3; ll++) {
5890 a[ll] = inc*coefav[f_id][ll];
5891 bt[ll][ll] -= 1;
5892 }
5893
5894 /* cocgb */
5895
5896 for (int ll = 0; ll < 9; ll++) {
5897
5898 /* contribution of t[kk][qq] */
5899 int kk = _33_9_idx[ll][0];
5900 int qq = _33_9_idx[ll][1];
5901
5902 int ll_9 = ll*(ll+1)/2;
5903 for (int pp = 0; pp <= ll; pp++) {
5904
5905 /* derivative with respect to t[rr][ss] */
5906 int rr = _33_9_idx[pp][0];
5907 int ss = _33_9_idx[pp][1];
5908
5909 /* part from derivative of 1/2*|| B*t*II'/db ||^2 */
5910 cs_real_t cocgv = 0.;
5911 for (int mm = 0; mm < 3; mm++)
5912 cocgv += bt[mm][kk]*bt[mm][rr];
5913 cocgb_v[ll_9+pp] += cocgv*(iipbf[qq]*iipbf[ss])*db2;
5914
5915 /* part from derivative of -< t*nb , B*t*II'/db > */
5916 cocgb_v[ll_9+pp] -= ( nb[ss]*bt[rr][kk]*iipbf[qq]
5917 + nb[qq]*bt[kk][rr]*iipbf[ss])
5918 *db;
5919 }
5920 }
5921
5922 /* rhsb */
5923
5924 for (int ll = 0; ll < 9; ll++) {
5925 int pp = _33_9_idx[ll][0];
5926 int qq = _33_9_idx[ll][1];
5927
5928 /* part from derivative of < (B-1)*t*II'/db , (A+(B-1)*v)/db > */
5929 cs_real_t rhsv = 0.;
5930 for (int rr = 0; rr < 3; rr++) {
5931 rhsv += bt[rr][pp]*diipb[f_id][qq]
5932 *(a[rr]+ bt[rr][0]*pvar[c_id][0]
5933 + bt[rr][1]*pvar[c_id][1]
5934 + bt[rr][2]*pvar[c_id][2]);
5935 }
5936
5937 rhsb_v[ll] -= rhsv*db2;
5938 }
5939
5940 }
5941
5942 /* Crout factorization of 9x9 symmetric cocg at boundaries */
5943
5944 _fact_crout_pp(9, cocgb_v);
5945 }
5946
5947 /*----------------------------------------------------------------------------
5948 * Compute cocg and RHS at boundaries for lsq tensor gradient.
5949 *
5950 * parameters:
5951 * c_id <-- cell id
5952 * inc <-- if 0, solve on increment; 1 otherwise
5953 * madj <-- pointer to mesh adjacencies structure
5954 * fvq <-- pointer to associated finite volume quantities
5955 * _63_18_idx <-- symmetric indexes mapping
5956 * pvar <-- variable
5957 * coefat <-- B.C. coefficients for boundary face normals
5958 * coefbt <-- B.C. coefficients for boundary face normals
5959 * cocg <-- cocg values
5960 * rhs <-- right hand side
5961 * cocgb_t --> boundary cocg vector values
5962 * rhsb_t --> boundary RHS values
5963 *----------------------------------------------------------------------------*/
5964
5965 static void
_compute_cocgb_rhsb_lsq_t(cs_lnum_t c_id,const int inc,const cs_mesh_adjacencies_t * madj,const cs_mesh_quantities_t * fvq,cs_lnum_t _63_18_idx[const restrict18][2],const cs_real_6_t * restrict pvar,const cs_real_6_t * restrict coefat,const cs_real_66_t * restrict coefbt,const cs_real_t cocg[3][3],const cs_real_t rhs[6][3],cs_real_t cocgb_t[restrict171],cs_real_t rhsb_t[restrict18])5966 _compute_cocgb_rhsb_lsq_t(cs_lnum_t c_id,
5967 const int inc,
5968 const cs_mesh_adjacencies_t *madj,
5969 const cs_mesh_quantities_t *fvq,
5970 cs_lnum_t _63_18_idx[const restrict 18][2],
5971 const cs_real_6_t *restrict pvar,
5972 const cs_real_6_t *restrict coefat,
5973 const cs_real_66_t *restrict coefbt,
5974 const cs_real_t cocg[3][3],
5975 const cs_real_t rhs[6][3],
5976 cs_real_t cocgb_t[restrict 171],
5977 cs_real_t rhsb_t[restrict 18])
5978 {
5979 /* Short variable accesses */
5980
5981 const cs_real_3_t *restrict diipb
5982 = (const cs_real_3_t *restrict)fvq->diipb;
5983
5984 const cs_real_3_t *restrict b_face_normal
5985 = (const cs_real_3_t *restrict)fvq->b_face_normal;
5986 const cs_real_t *restrict b_face_surf
5987 = (const cs_real_t *restrict)fvq->b_face_surf;
5988 const cs_real_t *restrict b_dist
5989 = (const cs_real_t *restrict)fvq->b_dist;
5990
5991 cs_lnum_t s_id, e_id;
5992
5993 /* initialize cocg and rhs for lsq tensor gradient */
5994
5995 for (int ll = 0; ll < 18; ll++) {
5996
5997 /* index of row first coefficient */
5998 int ll_18 = ll*(ll+1)/2;
5999
6000 for (int mm = 0; mm <= ll; mm++) {
6001 /* initialize */
6002 cocgb_t[ll_18+mm] = 0.;
6003
6004 /* contribution of t[kk][qq] */
6005 int pp = _63_18_idx[ll][0];
6006 int qq = _63_18_idx[ll][1];
6007
6008 /* derivative with respect to t[rr][ss] */
6009 int rr = _63_18_idx[mm][0];
6010 int ss = _63_18_idx[mm][1];
6011
6012 /* part from cocg (BCs independant) */
6013 if (pp == rr)
6014 cocgb_t[ll_18+mm] = cocg[qq][ss];
6015
6016 /* part already computed from rhs */
6017 rhsb_t[ll] = rhs[pp][qq];
6018 }
6019 }
6020
6021 s_id = madj->cell_b_faces_idx[c_id];
6022 e_id = madj->cell_b_faces_idx[c_id+1];
6023
6024 const cs_lnum_t *restrict cell_b_faces
6025 = (const cs_lnum_t *restrict)(madj->cell_b_faces);
6026
6027 for (cs_lnum_t i = s_id; i < e_id; i++) {
6028
6029 cs_lnum_t f_id = cell_b_faces[i];
6030
6031 /* build cocgb_v matrix */
6032
6033 cs_real_t udbfs = 1. / b_face_surf[f_id];
6034 const cs_real_t *restrict iipbf = diipb[f_id];
6035
6036 /* db = I'F / ||I'F|| */
6037 cs_real_t nb[3];
6038 for (int ii = 0; ii < 3; ii++)
6039 nb[ii] = udbfs * b_face_normal[f_id][ii];
6040
6041 cs_real_t db = 1./b_dist[f_id];
6042 cs_real_t db2 = db*db;
6043
6044 /* A and (B - I) */
6045 cs_real_t a[6];
6046 cs_real_t bt[6][6];
6047 for (int ll = 0; ll < 6; ll++) {
6048 for (int pp = 0; pp < 6; pp++)
6049 bt[ll][pp] = coefbt[f_id][ll][pp];
6050 }
6051 for (int ll = 0; ll < 6; ll++) {
6052 a[ll] = inc*coefat[f_id][ll];
6053 bt[ll][ll] -= 1;
6054 }
6055
6056 /* cocgb */
6057
6058 for (int ll = 0; ll < 18; ll++) {
6059
6060 /* contribution of t[kk][qq] */
6061 int kk = _63_18_idx[ll][0];
6062 int qq = _63_18_idx[ll][1];
6063
6064 int ll_18 = ll*(ll+1)/2;
6065 for (int pp = 0; pp <= ll; pp++) {
6066
6067 /* derivative with respect to t[rr][ss] */
6068 int rr = _63_18_idx[pp][0];
6069 int ss = _63_18_idx[pp][1];
6070
6071 /* part from derivative of 1/2*|| B*t*IIp/db ||^2 */
6072 cs_real_t cocgt = 0.;
6073 for (int mm = 0; mm < 6; mm++)
6074 cocgt += bt[mm][kk]*bt[mm][rr];
6075 cocgb_t[ll_18+pp] += cocgt * (iipbf[qq]*iipbf[ss]) * db2;
6076
6077 /* part from derivative of -< t*nb , B*t*IIp/db > */
6078 cocgb_t[ll_18+pp] -= ( nb[ss]*bt[rr][kk]*iipbf[qq]
6079 + nb[qq]*bt[kk][rr]*iipbf[ss])
6080 *db;
6081 }
6082 }
6083
6084 /* rhsb */
6085
6086 for (int ll = 0; ll < 18; ll++) {
6087 int pp = _63_18_idx[ll][0];
6088 int qq = _63_18_idx[ll][1];
6089
6090 /* part from derivative of < (B-1)*t*IIp/db , (A+(B-1)*v)/db > */
6091 cs_real_t rhst = 0.;
6092 for (int rr = 0; rr < 6; rr++) {
6093 cs_real_t tfac = a[rr];
6094 for (int kk = 0; kk < 6; kk++) {
6095 tfac += bt[rr][kk]*pvar[c_id][kk];
6096 }
6097 rhst += bt[rr][pp]*diipb[f_id][qq]*tfac;
6098 }
6099
6100 rhsb_t[ll] -= rhst*db2;
6101 }
6102
6103 }
6104
6105 /* Crout factorization of 18x18 symmetric cocg at boundaries */
6106
6107 _fact_crout_pp(18, cocgb_t);
6108 }
6109
6110 /*----------------------------------------------------------------------------
6111 * Compute cell gradient of a vector using least-squares reconstruction for
6112 * non-orthogonal meshes (n_r_sweeps > 1).
6113 *
6114 * parameters:
6115 * m <-- pointer to associated mesh structure
6116 * madj <-- pointer to mesh adjacencies structure
6117 * fvq <-- pointer to associated finite volume quantities
6118 * cpl <-- structure associated with internal coupling, or NULL
6119 * halo_type <-- halo type (extended or not)
6120 * inc <-- if 0, solve on increment; 1 otherwise
6121 * coefav <-- B.C. coefficients for boundary face normals
6122 * coefbv <-- B.C. coefficients for boundary face normals
6123 * pvar <-- variable
6124 * gradv --> gradient of pvar (du_i/dx_j : gradv[][i][j])
6125 *----------------------------------------------------------------------------*/
6126
6127 static void
_lsq_vector_gradient(const cs_mesh_t * m,const cs_mesh_adjacencies_t * madj,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,const cs_halo_type_t halo_type,const int inc,const cs_real_3_t * restrict coefav,const cs_real_33_t * restrict coefbv,const cs_real_3_t * restrict pvar,const cs_real_t * restrict c_weight,cs_real_33_t * restrict gradv)6128 _lsq_vector_gradient(const cs_mesh_t *m,
6129 const cs_mesh_adjacencies_t *madj,
6130 const cs_mesh_quantities_t *fvq,
6131 const cs_internal_coupling_t *cpl,
6132 const cs_halo_type_t halo_type,
6133 const int inc,
6134 const cs_real_3_t *restrict coefav,
6135 const cs_real_33_t *restrict coefbv,
6136 const cs_real_3_t *restrict pvar,
6137 const cs_real_t *restrict c_weight,
6138 cs_real_33_t *restrict gradv)
6139 {
6140 const cs_lnum_t n_cells = m->n_cells;
6141 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
6142 const int n_i_groups = m->i_face_numbering->n_groups;
6143 const int n_i_threads = m->i_face_numbering->n_threads;
6144 const int n_b_groups = m->b_face_numbering->n_groups;
6145 const int n_b_threads = m->b_face_numbering->n_threads;
6146 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
6147 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
6148
6149 const cs_lnum_2_t *restrict i_face_cells
6150 = (const cs_lnum_2_t *restrict)m->i_face_cells;
6151 const cs_lnum_t *restrict b_face_cells
6152 = (const cs_lnum_t *restrict)m->b_face_cells;
6153 const cs_lnum_t *restrict cell_cells_idx
6154 = (const cs_lnum_t *restrict)m->cell_cells_idx;
6155 const cs_lnum_t *restrict cell_cells_lst
6156 = (const cs_lnum_t *restrict)m->cell_cells_lst;
6157
6158 const cs_real_3_t *restrict cell_cen
6159 = (const cs_real_3_t *restrict)fvq->cell_cen;
6160 const cs_real_t *restrict weight = fvq->weight;
6161 const cs_real_t *restrict b_dist = fvq->b_dist;
6162 const cs_real_3_t *restrict b_face_normal
6163 = (const cs_real_3_t *restrict)fvq->b_face_normal;
6164
6165 cs_cocg_6_t *restrict cocgb_s = NULL;
6166 cs_cocg_6_t *restrict cocg = NULL;
6167 _get_cell_cocg_lsq(m, halo_type, false, fvq, cpl, &cocg, &cocgb_s);
6168
6169 cs_real_33_t *rhs;
6170
6171 BFT_MALLOC(rhs, n_cells_ext, cs_real_33_t);
6172
6173 bool *coupled_faces = (cpl == NULL) ?
6174 NULL : (bool *)cpl->coupled_faces;
6175
6176 /* Compute Right-Hand Side */
6177 /*-------------------------*/
6178
6179 # pragma omp parallel for
6180 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
6181 for (cs_lnum_t i = 0; i < 3; i++)
6182 for (cs_lnum_t j = 0; j < 3; j++)
6183 rhs[c_id][i][j] = 0.0;
6184 }
6185
6186 /* Contribution from interior faces */
6187
6188 for (int g_id = 0; g_id < n_i_groups; g_id++) {
6189
6190 # pragma omp parallel for
6191 for (int t_id = 0; t_id < n_i_threads; t_id++) {
6192
6193 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6194 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6195 f_id++) {
6196
6197 cs_lnum_t c_id1 = i_face_cells[f_id][0];
6198 cs_lnum_t c_id2 = i_face_cells[f_id][1];
6199
6200 cs_real_t dc[3], fctb[3];
6201
6202 for (cs_lnum_t i = 0; i < 3; i++)
6203 dc[i] = cell_cen[c_id2][i] - cell_cen[c_id1][i];
6204
6205 cs_real_t ddc = 1./(dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
6206
6207 if (c_weight != NULL) {
6208 cs_real_t pond = weight[f_id];
6209 cs_real_t denom = 1. / ( pond *c_weight[c_id1]
6210 + (1. - pond)*c_weight[c_id2]);
6211
6212 for (cs_lnum_t i = 0; i < 3; i++) {
6213 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6214
6215 for (cs_lnum_t j = 0; j < 3; j++) {
6216 fctb[j] = dc[j] * pfac;
6217 rhs[c_id1][i][j] += c_weight[c_id2] * denom * fctb[j];
6218 rhs[c_id2][i][j] += c_weight[c_id1] * denom * fctb[j];
6219 }
6220 }
6221 }
6222 else {
6223 for (cs_lnum_t i = 0; i < 3; i++) {
6224 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6225
6226 for (cs_lnum_t j = 0; j < 3; j++) {
6227 fctb[j] = dc[j] * pfac;
6228 rhs[c_id1][i][j] += fctb[j];
6229 rhs[c_id2][i][j] += fctb[j];
6230 }
6231 }
6232 }
6233
6234 } /* loop on faces */
6235
6236 } /* loop on threads */
6237
6238 } /* loop on thread groups */
6239
6240 /* Contribution from extended neighborhood */
6241
6242 if (halo_type == CS_HALO_EXTENDED) {
6243
6244 # pragma omp parallel for
6245 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
6246 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
6247 cidx < cell_cells_idx[c_id1+1];
6248 cidx++) {
6249
6250 cs_lnum_t c_id2 = cell_cells_lst[cidx];
6251
6252 cs_real_t dc[3];
6253
6254 for (cs_lnum_t i = 0; i < 3; i++)
6255 dc[i] = cell_cen[c_id2][i] - cell_cen[c_id1][i];
6256
6257 cs_real_t ddc = 1./(dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
6258
6259 for (cs_lnum_t i = 0; i < 3; i++) {
6260
6261 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6262
6263 for (cs_lnum_t j = 0; j < 3; j++) {
6264 rhs[c_id1][i][j] += dc[j] * pfac;
6265 }
6266 }
6267 }
6268 }
6269
6270 } /* End for extended neighborhood */
6271
6272 /* Contribution from coupled faces */
6273
6274 if (cpl != NULL)
6275 cs_internal_coupling_lsq_vector_gradient
6276 (cpl,
6277 c_weight,
6278 1, /* w_stride */
6279 pvar,
6280 rhs);
6281
6282 /* Contribution from boundary faces */
6283
6284 for (int g_id = 0; g_id < n_b_groups; g_id++) {
6285
6286 # pragma omp parallel for
6287 for (int t_id = 0; t_id < n_b_threads; t_id++) {
6288
6289 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
6290 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
6291 f_id++) {
6292
6293 if (cpl == NULL || !coupled_faces[f_id]) {
6294
6295 cs_lnum_t c_id1 = b_face_cells[f_id];
6296
6297 cs_real_t n_d_dist[3];
6298 /* Normal is vector 0 if the b_face_normal norm is too small */
6299 cs_math_3_normalise(b_face_normal[f_id], n_d_dist);
6300
6301 cs_real_t d_b_dist = 1. / b_dist[f_id];
6302
6303 /* Normal divided by b_dist */
6304 for (cs_lnum_t i = 0; i < 3; i++)
6305 n_d_dist[i] *= d_b_dist;
6306
6307 for (cs_lnum_t i = 0; i < 3; i++) {
6308 cs_real_t pfac = (coefav[f_id][i]*inc
6309 + ( coefbv[f_id][0][i] * pvar[c_id1][0]
6310 + coefbv[f_id][1][i] * pvar[c_id1][1]
6311 + coefbv[f_id][2][i] * pvar[c_id1][2]
6312 - pvar[c_id1][i]));
6313
6314 for (cs_lnum_t j = 0; j < 3; j++)
6315 rhs[c_id1][i][j] += n_d_dist[j] * pfac;
6316 }
6317 }
6318
6319 } /* loop on faces */
6320
6321 } /* loop on threads */
6322
6323 } /* loop on thread groups */
6324
6325 /* Compute gradient */
6326 /*------------------*/
6327
6328 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
6329 for (cs_lnum_t i = 0; i < 3; i++) {
6330 gradv[c_id][i][0] = rhs[c_id][i][0] * cocg[c_id][0]
6331 + rhs[c_id][i][1] * cocg[c_id][3]
6332 + rhs[c_id][i][2] * cocg[c_id][5];
6333
6334 gradv[c_id][i][1] = rhs[c_id][i][0] * cocg[c_id][3]
6335 + rhs[c_id][i][1] * cocg[c_id][1]
6336 + rhs[c_id][i][2] * cocg[c_id][4];
6337
6338 gradv[c_id][i][2] = rhs[c_id][i][0] * cocg[c_id][5]
6339 + rhs[c_id][i][1] * cocg[c_id][4]
6340 + rhs[c_id][i][2] * cocg[c_id][2];
6341 }
6342 }
6343
6344 /* Compute gradient on boundary cells */
6345 /*------------------------------------*/
6346
6347 #pragma omp parallel
6348 {
6349 cs_lnum_t t_s_id, t_e_id;
6350 cs_parall_thread_range(m->n_b_cells, sizeof(cs_real_t), &t_s_id, &t_e_id);
6351
6352 /* Build indices bijection between [1-9] and [1-3]*[1-3] */
6353
6354 cs_lnum_t _33_9_idx[9][2];
6355 int nn = 0;
6356 for (int ll = 0; ll < 3; ll++) {
6357 for (int mm = 0; mm < 3; mm++) {
6358 _33_9_idx[nn][0] = ll;
6359 _33_9_idx[nn][1] = mm;
6360 nn++;
6361 }
6362 }
6363
6364 /* Loop on boundary cells */
6365
6366 for (cs_lnum_t b_c_id = t_s_id; b_c_id < t_e_id; b_c_id++) {
6367
6368 cs_lnum_t c_id = m->b_cells[b_c_id];
6369
6370 cs_real_t cocgb[3][3], cocgb_v[45], rhsb_v[9], x[9];
6371
6372 _complete_cocg_lsq(c_id, madj, fvq, cocgb_s[b_c_id], cocgb);
6373
6374 _compute_cocgb_rhsb_lsq_v
6375 (c_id,
6376 inc,
6377 madj,
6378 fvq,
6379 _33_9_idx,
6380 (const cs_real_3_t *)pvar,
6381 (const cs_real_3_t *)coefav,
6382 (const cs_real_33_t *)coefbv,
6383 (const cs_real_3_t *)cocgb,
6384 (const cs_real_3_t *)rhs[c_id],
6385 cocgb_v,
6386 rhsb_v);
6387
6388 _fw_and_bw_ldtl_pp(cocgb_v,
6389 9,
6390 x,
6391 rhsb_v);
6392
6393 for (int kk = 0; kk < 9; kk++) {
6394 int ii = _33_9_idx[kk][0];
6395 int jj = _33_9_idx[kk][1];
6396 gradv[c_id][ii][jj] = x[kk];
6397 }
6398
6399 }
6400
6401 }
6402
6403 /* Periodicity and parallelism treatment */
6404
6405 if (m->halo != NULL) {
6406 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)gradv, 9);
6407 if (cs_glob_mesh->have_rotation_perio)
6408 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)gradv);
6409 }
6410
6411 BFT_FREE(rhs);
6412 }
6413
6414 /*----------------------------------------------------------------------------
6415 * Compute boundary face vector values using least-squares reconstruction
6416 * for non-orthogonal meshes.
6417 *
6418 * parameters:
6419 * m <-- pointer to associated mesh structure
6420 * ma <-- pointer to mesh adjacencies structure
6421 * fvq <-- pointer to associated finite volume quantities
6422 * cpl <-- structure associated with internal coupling, or NULL
6423 * halo_type <-- halo type (extended or not)
6424 * inc <-- if 0, solve on increment; 1 otherwise
6425 * coefav <-- B.C. coefficients for boundary face normals
6426 * coefbv <-- B.C. coefficients for boundary face normals
6427 * c_var <-- cell variable
6428 * c_weight <-- weighted gradient coefficient variable,
6429 * or NULL
6430 * b_f_var --> boundary face value.
6431 *----------------------------------------------------------------------------*/
6432
6433 static void
_lsq_vector_b_face_val(const cs_mesh_t * m,const cs_mesh_adjacencies_t * ma,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,const cs_halo_type_t halo_type,const int inc,const cs_real_t bc_coeff_a[][3],const cs_real_t bc_coeff_b[][3][3],const cs_real_t c_var[][3],const cs_real_t c_weight[],cs_real_t b_f_var[restrict][3])6434 _lsq_vector_b_face_val(const cs_mesh_t *m,
6435 const cs_mesh_adjacencies_t *ma,
6436 const cs_mesh_quantities_t *fvq,
6437 const cs_internal_coupling_t *cpl,
6438 const cs_halo_type_t halo_type,
6439 const int inc,
6440 const cs_real_t bc_coeff_a[][3],
6441 const cs_real_t bc_coeff_b[][3][3],
6442 const cs_real_t c_var[][3],
6443 const cs_real_t c_weight[],
6444 cs_real_t b_f_var[restrict][3])
6445 {
6446 const cs_lnum_t n_b_cells = m->n_b_cells;
6447
6448 const cs_lnum_t *restrict cell_b_faces_idx
6449 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
6450 const cs_lnum_t *restrict cell_b_faces
6451 = (const cs_lnum_t *restrict) ma->cell_b_faces;
6452
6453 const cs_real_3_t *restrict diipb
6454 = (const cs_real_3_t *restrict)fvq->diipb;
6455
6456 bool *coupled_faces = (cpl == NULL) ?
6457 NULL : (bool *)cpl->coupled_faces;
6458
6459 cs_real_3_t *_bc_coeff_a = NULL;
6460
6461 if (inc == 0) {
6462 BFT_MALLOC(_bc_coeff_a, m->n_b_faces, cs_real_3_t);
6463 for (cs_lnum_t i = 0; i < m->n_b_faces; i++) {
6464 for (cs_lnum_t j = 0; j < 3; j++)
6465 _bc_coeff_a[i][j] = 0;
6466 }
6467 bc_coeff_a = (const cs_real_3_t*)_bc_coeff_a;
6468 }
6469
6470 /* Reconstruct gradients using least squares for non-orthogonal meshes */
6471
6472 # pragma omp parallel for if (n_b_cells > CS_THR_MIN)
6473 for (cs_lnum_t ci = 0; ci < n_b_cells; ci++) {
6474
6475 cs_real_t gradc[3][3];
6476 cs_lnum_t c_id = m->b_cells[ci];
6477
6478 cs_gradient_vector_cell(m,
6479 fvq,
6480 c_id,
6481 halo_type,
6482 bc_coeff_a,
6483 bc_coeff_b,
6484 c_var,
6485 c_weight,
6486 gradc);
6487
6488 /* Compute boundary face values */
6489
6490 cs_lnum_t s_id = cell_b_faces_idx[c_id];
6491 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
6492
6493 for (cs_lnum_t i = s_id; i < e_id; i++) {
6494
6495 cs_lnum_t f_id = cell_b_faces[i];
6496
6497 if (cpl == NULL || !coupled_faces[f_id]) {
6498
6499 const cs_real_t *_c_var = c_var[c_id];
6500 cs_real_t pip[3];
6501 for (cs_lnum_t k = 0; k < 3; k++) {
6502 pip[k] = _c_var[k]
6503 + cs_math_3_dot_product(diipb[f_id], gradc[k]);
6504 }
6505 for (cs_lnum_t k = 0; k < 3; k++) {
6506 b_f_var[f_id][k] = inc * bc_coeff_a[f_id][k]
6507 + bc_coeff_b[f_id][0][k] * pip[0]
6508 + bc_coeff_b[f_id][1][k] * pip[1]
6509 + bc_coeff_b[f_id][2][k] * pip[2];
6510 }
6511
6512 }
6513 }
6514
6515 }
6516
6517 BFT_FREE(_bc_coeff_a);
6518 }
6519
6520 /*----------------------------------------------------------------------------
6521 * Compute gradient using vertex-based face values for scalar gradient
6522 * reconstruction.
6523 *
6524 * parameters:
6525 * m <-- pointer to associated mesh structure
6526 * fvq <-- pointer to associated finite volume quantities
6527 * cpl <-- structure associated with internal coupling, or NULL
6528 * inc <-- if 0, solve on increment; 1 otherwise
6529 * bc_coeff_a <-- B.C. coefficients for boundary face normals
6530 * bc_coeff_b <-- B.C. coefficients for boundary face normals
6531 * c_var <-- variable
6532 * c_weight <-- weighted gradient coefficient variable
6533 * grad --> gradient of c_var (du_i/dx_j : grad[][i][j])
6534 *----------------------------------------------------------------------------*/
6535
6536 static void
_fv_vtx_based_vector_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,const cs_internal_coupling_t * cpl,cs_real_t inc,const cs_real_t bc_coeff_a[][3],const cs_real_t bc_coeff_b[][3][3],const cs_real_t c_var[][3],const cs_real_t c_weight[],cs_real_t grad[restrict][3][3])6537 _fv_vtx_based_vector_gradient(const cs_mesh_t *m,
6538 const cs_mesh_quantities_t *fvq,
6539 const cs_internal_coupling_t *cpl,
6540 cs_real_t inc,
6541 const cs_real_t bc_coeff_a[][3],
6542 const cs_real_t bc_coeff_b[][3][3],
6543 const cs_real_t c_var[][3],
6544 const cs_real_t c_weight[],
6545 cs_real_t grad[restrict][3][3])
6546 {
6547 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
6548 const cs_lnum_t n_cells = m->n_cells;
6549 const int n_i_groups = m->i_face_numbering->n_groups;
6550 const int n_i_threads = m->i_face_numbering->n_threads;
6551 const int n_b_groups = m->b_face_numbering->n_groups;
6552 const int n_b_threads = m->b_face_numbering->n_threads;
6553 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
6554 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
6555
6556 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
6557
6558 const cs_lnum_2_t *restrict i_face_cells
6559 = (const cs_lnum_2_t *restrict)m->i_face_cells;
6560 const cs_lnum_t *restrict b_face_cells
6561 = (const cs_lnum_t *restrict)m->b_face_cells;
6562
6563 const int *restrict c_disable_flag = fvq->c_disable_flag;
6564 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
6565
6566 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
6567 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
6568 cell_f_vol = fvq->cell_vol;
6569 const cs_real_3_t *restrict i_f_face_normal
6570 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
6571 const cs_real_3_t *restrict b_f_face_normal
6572 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
6573
6574 bool *coupled_faces = (cpl == NULL) ?
6575 NULL : (bool *)cpl->coupled_faces;
6576
6577 /* Initialize gradient
6578 ------------------- */
6579
6580 # pragma omp parallel for
6581 for (cs_lnum_t cell_id = 0; cell_id < n_cells_ext; cell_id++) {
6582 for (cs_lnum_t i = 0; i < 3; i++) {
6583 for (cs_lnum_t j = 0; j < 3; j++)
6584 grad[cell_id][i][j] = 0.0;
6585 }
6586 }
6587
6588 /* Pre-compute gradient at boundary using least squares */
6589
6590 cs_real_3_t *b_f_var;
6591 BFT_MALLOC(b_f_var, m->n_b_faces, cs_real_3_t);
6592
6593 _lsq_vector_b_face_val(m,
6594 ma,
6595 fvq,
6596 cpl,
6597 CS_HALO_STANDARD,
6598 inc,
6599 bc_coeff_a,
6600 bc_coeff_b,
6601 c_var,
6602 c_weight,
6603 b_f_var);
6604
6605 /* Compute vertex-based values
6606 --------------------------- */
6607
6608 cs_real_3_t *v_var;
6609 BFT_MALLOC(v_var, m->n_vertices, cs_real_3_t);
6610
6611 cs_cell_to_vertex(CS_CELL_TO_VERTEX_LR,
6612 0, /* verbosity */
6613 3, /* var_dim */
6614 0,
6615 c_weight,
6616 (const cs_real_t *)c_var,
6617 (const cs_real_t *)b_f_var,
6618 (cs_real_t *)v_var);
6619
6620 /* Interpolate to face-based values
6621 -------------------------------- */
6622
6623 cs_real_3_t *i_f_var;
6624 BFT_MALLOC(i_f_var, m->n_i_faces, cs_real_3_t);
6625
6626 for (int f_t = 0; f_t < 2; f_t++) {
6627
6628 const cs_lnum_t n_faces = (f_t == 0) ? m->n_i_faces : m->n_b_faces;
6629 const cs_lnum_t *f2v_idx= NULL, *f2v_ids = NULL;
6630 cs_real_3_t *f_var = NULL;
6631
6632 if (f_t == 0) {
6633 f2v_idx = m->i_face_vtx_idx;
6634 f2v_ids = m->i_face_vtx_lst;
6635 f_var = i_f_var;
6636 }
6637 else {
6638 f2v_idx = m->b_face_vtx_idx;
6639 f2v_ids = m->b_face_vtx_lst;
6640 f_var = b_f_var;
6641 }
6642
6643 # pragma omp parallel for if (n_faces > CS_THR_MIN)
6644 for (cs_lnum_t f_id = 0; f_id < n_faces; f_id++) {
6645 cs_lnum_t s_id = f2v_idx[f_id];
6646 cs_lnum_t e_id = f2v_idx[f_id+1];
6647 cs_real_t s[3] = {0, 0, 0};
6648 for (cs_lnum_t i = s_id; i < e_id; i++) {
6649 for (cs_lnum_t k = 0; k < 3; k++)
6650 s[k] += v_var[f2v_ids[i]][k];
6651 }
6652 for (cs_lnum_t k = 0; k < 3; k++)
6653 f_var[f_id][k] = s[k] / (e_id-s_id);
6654 }
6655
6656 }
6657
6658 /* Vertex values are not needed after this stage */
6659
6660 BFT_FREE(v_var);
6661
6662 /* Contribution from interior faces */
6663
6664 for (int g_id = 0; g_id < n_i_groups; g_id++) {
6665
6666 # pragma omp parallel for
6667 for (int t_id = 0; t_id < n_i_threads; t_id++) {
6668
6669 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6670 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6671 f_id++) {
6672
6673 cs_lnum_t ii = i_face_cells[f_id][0];
6674 cs_lnum_t jj = i_face_cells[f_id][1];
6675
6676 for (cs_lnum_t k = 0; k < 3; k++) {
6677
6678 cs_real_t pfaci = i_f_var[f_id][k] - c_var[ii][k];
6679 cs_real_t pfacj = i_f_var[f_id][k] - c_var[jj][k];
6680
6681 for (cs_lnum_t l = 0; l < 3; l++) {
6682 grad[ii][k][l] += pfaci * i_f_face_normal[f_id][l];
6683 grad[jj][k][l] -= pfacj * i_f_face_normal[f_id][l];
6684 }
6685
6686 }
6687
6688 } /* loop on faces */
6689
6690 } /* loop on threads */
6691
6692 } /* loop on thread groups */
6693
6694 /* Contribution from coupled faces */
6695 if (cpl != NULL) {
6696 assert(0); /* not handled yet */
6697 }
6698
6699 /* Contribution from boundary faces */
6700
6701 for (int g_id = 0; g_id < n_b_groups; g_id++) {
6702
6703 # pragma omp parallel for
6704 for (int t_id = 0; t_id < n_b_threads; t_id++) {
6705
6706 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
6707 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
6708 f_id++) {
6709
6710 if (cpl == NULL || !coupled_faces[f_id]) {
6711
6712 cs_lnum_t ii = b_face_cells[f_id];
6713
6714 /*
6715 Remark: for the cell \f$ \celli \f$ we remove
6716 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
6717 */
6718
6719 for (cs_lnum_t k = 0; k < 3; k++) {
6720
6721 cs_real_t pfac = b_f_var[f_id][k] - c_var[ii][k];
6722
6723 for (cs_lnum_t l = 0; l < 3; l++)
6724 grad[ii][k][l] += pfac * b_f_face_normal[f_id][l];
6725
6726 }
6727
6728 } /* face without internal coupling */
6729
6730 } /* loop on faces */
6731
6732 }
6733
6734 }
6735
6736 BFT_FREE(i_f_var);
6737 BFT_FREE(b_f_var);
6738
6739 # pragma omp parallel for
6740 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
6741 cs_real_t dvol;
6742 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
6743 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
6744 dvol = 1. / cell_f_vol[c_id];
6745 else
6746 dvol = 0.;
6747
6748 for (cs_lnum_t i = 0; i < 3; i++) {
6749 for (cs_lnum_t j = 0; j < 3; j++)
6750 grad[c_id][i][j] *= dvol;
6751 }
6752 }
6753
6754 /* Synchronize halos */
6755
6756 if (m->halo != NULL) {
6757 cs_halo_sync_var_strided(m->halo, CS_HALO_STANDARD, (cs_real_t *)grad, 9);
6758 if (cs_glob_mesh->have_rotation_perio)
6759 cs_halo_perio_sync_var_tens(m->halo,
6760 CS_HALO_STANDARD,
6761 (cs_real_t *)grad);
6762 }
6763 }
6764
6765 /*----------------------------------------------------------------------------
6766 * Compute cell gradient of a tensor using least-squares reconstruction for
6767 * non-orthogonal meshes (n_r_sweeps > 1).
6768 *
6769 * parameters:
6770 * m <-- pointer to associated mesh structure
6771 * madj <-- pointer to mesh adjacencies structure
6772 * fvq <-- pointer to associated finite volume quantities
6773 * halo_type <-- halo type (extended or not)
6774 * inc <-- if 0, solve on increment; 1 otherwise
6775 * coefat <-- B.C. coefficients for boundary face normals
6776 * coefbt <-- B.C. coefficients for boundary face normals
6777 * pvar <-- variable
6778 * gradt --> gradient of pvar (du_i/dx_j : gradv[][i][j])
6779 *----------------------------------------------------------------------------*/
6780
6781 static void
_lsq_tensor_gradient(const cs_mesh_t * m,const cs_mesh_adjacencies_t * madj,const cs_mesh_quantities_t * fvq,const cs_halo_type_t halo_type,const int inc,const cs_real_6_t * restrict coefat,const cs_real_66_t * restrict coefbt,const cs_real_6_t * restrict pvar,const cs_real_t * restrict c_weight,cs_real_63_t * restrict gradt)6782 _lsq_tensor_gradient(const cs_mesh_t *m,
6783 const cs_mesh_adjacencies_t *madj,
6784 const cs_mesh_quantities_t *fvq,
6785 const cs_halo_type_t halo_type,
6786 const int inc,
6787 const cs_real_6_t *restrict coefat,
6788 const cs_real_66_t *restrict coefbt,
6789 const cs_real_6_t *restrict pvar,
6790 const cs_real_t *restrict c_weight,
6791 cs_real_63_t *restrict gradt)
6792 {
6793 const cs_lnum_t n_cells = m->n_cells;
6794 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
6795 const int n_i_groups = m->i_face_numbering->n_groups;
6796 const int n_i_threads = m->i_face_numbering->n_threads;
6797 const int n_b_groups = m->b_face_numbering->n_groups;
6798 const int n_b_threads = m->b_face_numbering->n_threads;
6799 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
6800 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
6801
6802 const cs_lnum_2_t *restrict i_face_cells
6803 = (const cs_lnum_2_t *restrict)m->i_face_cells;
6804 const cs_lnum_t *restrict b_face_cells
6805 = (const cs_lnum_t *restrict)m->b_face_cells;
6806 const cs_lnum_t *restrict cell_cells_idx
6807 = (const cs_lnum_t *restrict)m->cell_cells_idx;
6808 const cs_lnum_t *restrict cell_cells_lst
6809 = (const cs_lnum_t *restrict)m->cell_cells_lst;
6810
6811 const cs_real_3_t *restrict cell_cen
6812 = (const cs_real_3_t *restrict)fvq->cell_cen;
6813 const cs_real_t *restrict weight = fvq->weight;
6814 const cs_real_t *restrict b_dist = fvq->b_dist;
6815 const cs_real_3_t *restrict b_face_normal
6816 = (const cs_real_3_t *restrict)fvq->b_face_normal;
6817
6818 cs_cocg_6_t *restrict cocgb_s = NULL;
6819 cs_cocg_6_t *restrict cocg = NULL;
6820 _get_cell_cocg_lsq(m, halo_type, false, fvq, NULL, &cocg, &cocgb_s);
6821
6822 cs_real_63_t *rhs;
6823
6824 BFT_MALLOC(rhs, n_cells_ext, cs_real_63_t);
6825
6826 /* Reinitialize cocg at boundaries, using saved cocgb */
6827
6828 # pragma omp parallel for
6829 for (cs_lnum_t ii = 0; ii < m->n_b_cells; ii++) {
6830 cs_lnum_t c_id = m->b_cells[ii];
6831 for (cs_lnum_t ll = 0; ll < 6; ll++)
6832 cocg[c_id][ll] = cocgb_s[ii][ll];
6833 }
6834
6835 /* Compute Right-Hand Side */
6836 /*-------------------------*/
6837
6838 # pragma omp parallel for
6839 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
6840 for (cs_lnum_t i = 0; i < 6; i++) {
6841 for (cs_lnum_t j = 0; j < 3; j++)
6842 rhs[c_id][i][j] = 0.0;
6843 }
6844 }
6845
6846 /* Contribution from interior faces */
6847
6848 for (int g_id = 0; g_id < n_i_groups; g_id++) {
6849
6850 # pragma omp parallel for
6851 for (int t_id = 0; t_id < n_i_threads; t_id++) {
6852
6853 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
6854 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
6855 f_id++) {
6856
6857 cs_lnum_t c_id1 = i_face_cells[f_id][0];
6858 cs_lnum_t c_id2 = i_face_cells[f_id][1];
6859
6860 cs_real_3_t dc, fctb;
6861 for (cs_lnum_t i = 0; i < 3; i++)
6862 dc[i] = cell_cen[c_id2][i] - cell_cen[c_id1][i];
6863
6864 cs_real_t ddc = 1./(dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
6865
6866 if (c_weight != NULL) {
6867 cs_real_t pond = weight[f_id];
6868 cs_real_t denom = 1. / ( pond *c_weight[c_id1]
6869 + (1. - pond)*c_weight[c_id2]);
6870
6871 for (cs_lnum_t i = 0; i < 6; i++) {
6872 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6873
6874 for (cs_lnum_t j = 0; j < 3; j++) {
6875 fctb[j] = dc[j] * pfac;
6876 rhs[c_id1][i][j] += c_weight[c_id2] * denom * fctb[j];
6877 rhs[c_id2][i][j] += c_weight[c_id1] * denom * fctb[j];
6878 }
6879 }
6880 }
6881 else {
6882 for (cs_lnum_t i = 0; i < 6; i++) {
6883 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6884
6885 for (cs_lnum_t j = 0; j < 3; j++) {
6886 fctb[j] = dc[j] * pfac;
6887 rhs[c_id1][i][j] += fctb[j];
6888 rhs[c_id2][i][j] += fctb[j];
6889 }
6890 }
6891 }
6892
6893 } /* loop on faces */
6894
6895 } /* loop on threads */
6896
6897 } /* loop on thread groups */
6898
6899 /* Contribution from extended neighborhood */
6900
6901 if (halo_type == CS_HALO_EXTENDED) {
6902
6903 # pragma omp parallel for
6904 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
6905 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
6906 cidx < cell_cells_idx[c_id1+1];
6907 cidx++) {
6908
6909 cs_lnum_t c_id2 = cell_cells_lst[cidx];
6910
6911 cs_real_3_t dc;
6912 for (cs_lnum_t i = 0; i < 3; i++)
6913 dc[i] = cell_cen[c_id2][i] - cell_cen[c_id1][i];
6914
6915 cs_real_t ddc = 1./(dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
6916
6917 for (cs_lnum_t i = 0; i < 6; i++) {
6918
6919 cs_real_t pfac = (pvar[c_id2][i] - pvar[c_id1][i]) * ddc;
6920
6921 for (cs_lnum_t j = 0; j < 3; j++) {
6922 rhs[c_id1][i][j] += dc[j] * pfac;
6923 }
6924 }
6925 }
6926 }
6927
6928 } /* End for extended neighborhood */
6929
6930 /* Contribution from boundary faces */
6931
6932 for (int g_id = 0; g_id < n_b_groups; g_id++) {
6933
6934 # pragma omp parallel for
6935 for (int t_id = 0; t_id < n_b_threads; t_id++) {
6936
6937 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
6938 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
6939 f_id++) {
6940
6941 cs_lnum_t c_id1 = b_face_cells[f_id];
6942
6943 cs_real_3_t n_d_dist;
6944 /* Normal is vector 0 if the b_face_normal norm is too small */
6945 cs_math_3_normalise(b_face_normal[f_id], n_d_dist);
6946
6947 cs_real_t d_b_dist = 1. / b_dist[f_id];
6948
6949 /* Normal divided by b_dist */
6950 for (cs_lnum_t i = 0; i < 3; i++)
6951 n_d_dist[i] *= d_b_dist;
6952
6953 for (cs_lnum_t i = 0; i < 6; i++) {
6954 cs_real_t pfac = coefat[f_id][i]*inc - pvar[c_id1][i];
6955 for (cs_lnum_t j = 0; j < 6; j++)
6956 pfac += coefbt[f_id][j][i] * pvar[c_id1][j];
6957
6958 for (cs_lnum_t j = 0; j < 3; j++)
6959 rhs[c_id1][i][j] += pfac * n_d_dist[j];
6960 }
6961
6962 } /* loop on faces */
6963
6964 } /* loop on threads */
6965
6966 } /* loop on thread groups */
6967
6968 /* Compute gradient */
6969 /*------------------*/
6970
6971 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
6972 for (cs_lnum_t i = 0; i < 6; i++) {
6973 gradt[c_id][i][0] = rhs[c_id][i][0] * cocg[c_id][0]
6974 + rhs[c_id][i][1] * cocg[c_id][3]
6975 + rhs[c_id][i][2] * cocg[c_id][5];
6976
6977 gradt[c_id][i][1] = rhs[c_id][i][0] * cocg[c_id][3]
6978 + rhs[c_id][i][1] * cocg[c_id][1]
6979 + rhs[c_id][i][2] * cocg[c_id][4];
6980
6981 gradt[c_id][i][2] = rhs[c_id][i][0] * cocg[c_id][5]
6982 + rhs[c_id][i][1] * cocg[c_id][4]
6983 + rhs[c_id][i][2] * cocg[c_id][2];
6984 }
6985 }
6986
6987 /* Compute gradient on boundary cells */
6988 /*------------------------------------*/
6989
6990 #pragma omp parallel
6991 {
6992 cs_lnum_t t_s_id, t_e_id;
6993 cs_parall_thread_range(m->n_b_cells, sizeof(cs_real_t), &t_s_id, &t_e_id);
6994
6995 /* Build indices bijection between [1-18] and [1-6]*[1-3] */
6996
6997 cs_lnum_t _63_18_idx[18][2];
6998 int nn = 0;
6999 for (int ll = 0; ll < 6; ll++) {
7000 for (int mm = 0; mm < 3; mm++) {
7001 _63_18_idx[nn][0] = ll;
7002 _63_18_idx[nn][1] = mm;
7003 nn++;
7004 }
7005 }
7006
7007 /* Loop on boundary cells */
7008
7009 for (cs_lnum_t b_c_id = t_s_id; b_c_id < t_e_id; b_c_id++) {
7010
7011 cs_lnum_t c_id = m->b_cells[b_c_id];
7012
7013 cs_real_t cocgb[3][3], cocgb_t[171], rhsb_t[18], x[18];
7014
7015 _complete_cocg_lsq(c_id, madj, fvq, cocg[c_id], cocgb);
7016
7017 _compute_cocgb_rhsb_lsq_t
7018 (c_id,
7019 inc,
7020 madj,
7021 fvq,
7022 _63_18_idx,
7023 (const cs_real_6_t *)pvar,
7024 (const cs_real_6_t *)coefat,
7025 (const cs_real_66_t *)coefbt,
7026 (const cs_real_3_t *)cocgb,
7027 (const cs_real_3_t *)rhs[c_id],
7028 cocgb_t,
7029 rhsb_t);
7030
7031 _fw_and_bw_ldtl_pp(cocgb_t,
7032 18,
7033 x,
7034 rhsb_t);
7035
7036 for (int kk = 0; kk < 18; kk++) {
7037 int ii = _63_18_idx[kk][0];
7038 int jj = _63_18_idx[kk][1];
7039 gradt[c_id][ii][jj] = x[kk];
7040 }
7041
7042 }
7043
7044 }
7045
7046 /* Periodicity and parallelism treatment */
7047
7048 if (m->halo != NULL) {
7049 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)gradt, 18);
7050 if (cs_glob_mesh->have_rotation_perio)
7051 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)gradt);
7052 }
7053
7054 BFT_FREE(rhs);
7055 }
7056
7057 /*----------------------------------------------------------------------------
7058 * Initialize the gradient of a tensor for gradient reconstruction.
7059 *
7060 * A non-reconstructed gradient is computed at this stage.
7061 *
7062 * parameters:
7063 * m <-- pointer to associated mesh structure
7064 * fvq <-- pointer to associated finite volume quantities
7065 * halo_type <-- halo type (extended or not)
7066 * inc <-- if 0, solve on increment; 1 otherwise
7067 * coefat <-- B.C. coefficients for boundary face normals
7068 * coefbt <-- B.C. coefficients for boundary face normals
7069 * pvar <-- variable
7070 * grad --> gradient of pvar (dts_i/dx_j : grad[][i][j])
7071 *----------------------------------------------------------------------------*/
7072
7073 static void
_initialize_tensor_gradient(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_halo_type_t halo_type,int inc,const cs_real_6_t * restrict coefat,const cs_real_66_t * restrict coefbt,const cs_real_6_t * restrict pvar,cs_real_63_t * restrict grad)7074 _initialize_tensor_gradient(const cs_mesh_t *m,
7075 const cs_mesh_quantities_t *fvq,
7076 cs_halo_type_t halo_type,
7077 int inc,
7078 const cs_real_6_t *restrict coefat,
7079 const cs_real_66_t *restrict coefbt,
7080 const cs_real_6_t *restrict pvar,
7081 cs_real_63_t *restrict grad)
7082 {
7083 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
7084 const cs_lnum_t n_cells = m->n_cells;
7085 const int n_i_groups = m->i_face_numbering->n_groups;
7086 const int n_i_threads = m->i_face_numbering->n_threads;
7087 const int n_b_groups = m->b_face_numbering->n_groups;
7088 const int n_b_threads = m->b_face_numbering->n_threads;
7089 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
7090 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
7091
7092 const cs_lnum_2_t *restrict i_face_cells
7093 = (const cs_lnum_2_t *restrict)m->i_face_cells;
7094 const cs_lnum_t *restrict b_face_cells
7095 = (const cs_lnum_t *restrict)m->b_face_cells;
7096
7097 const int *restrict c_disable_flag = fvq->c_disable_flag;
7098 cs_lnum_t has_dc = fvq->has_disable_flag; /* Has cells disabled? */
7099
7100 const cs_real_t *restrict weight = fvq->weight;
7101 const cs_real_t *restrict cell_f_vol = fvq->cell_f_vol;
7102 if (cs_glob_porous_model == 1 || cs_glob_porous_model == 2)
7103 cell_f_vol = fvq->cell_vol;
7104 const cs_real_3_t *restrict i_f_face_normal
7105 = (const cs_real_3_t *restrict)fvq->i_f_face_normal;
7106 const cs_real_3_t *restrict b_f_face_normal
7107 = (const cs_real_3_t *restrict)fvq->b_f_face_normal;
7108
7109 /* Computation without reconstruction */
7110 /*------------------------------------*/
7111
7112 /* Initialization */
7113
7114 # pragma omp parallel for
7115 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
7116 for (cs_lnum_t i = 0; i < 6; i++) {
7117 for (cs_lnum_t j = 0; j < 3; j++)
7118 grad[c_id][i][j] = 0.0;
7119 }
7120 }
7121
7122 /* Interior faces contribution */
7123
7124 for (int g_id = 0; g_id < n_i_groups; g_id++) {
7125
7126 # pragma omp parallel for
7127 for (int t_id = 0; t_id < n_i_threads; t_id++) {
7128
7129 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7130 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7131 f_id++) {
7132
7133 cs_lnum_t c_id1 = i_face_cells[f_id][0];
7134 cs_lnum_t c_id2 = i_face_cells[f_id][1];
7135
7136 cs_real_t pond = weight[f_id];
7137
7138 /*
7139 Remark: \f$ \varia_\face = \alpha_\ij \varia_\celli
7140 + (1-\alpha_\ij) \varia_\cellj\f$
7141 but for the cell \f$ \celli \f$ we remove
7142 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
7143 and for the cell \f$ \cellj \f$ we remove
7144 \f$ \varia_\cellj \sum_\face \vect{S}_\face = \vect{0} \f$
7145 */
7146 for (cs_lnum_t i = 0; i < 6; i++) {
7147 cs_real_t pfaci = (1.0-pond) * (pvar[c_id2][i] - pvar[c_id1][i]);
7148 cs_real_t pfacj = - pond * (pvar[c_id2][i] - pvar[c_id1][i]);
7149 for (cs_lnum_t j = 0; j < 3; j++) {
7150 grad[c_id1][i][j] += pfaci * i_f_face_normal[f_id][j];
7151 grad[c_id2][i][j] -= pfacj * i_f_face_normal[f_id][j];
7152 }
7153 }
7154
7155 } /* End of loop on faces */
7156
7157 } /* End of loop on threads */
7158
7159 } /* End of loop on thread groups */
7160
7161 /* Boundary face treatment */
7162
7163 for (int g_id = 0; g_id < n_b_groups; g_id++) {
7164
7165 # pragma omp parallel for
7166 for (int t_id = 0; t_id < n_b_threads; t_id++) {
7167
7168 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
7169 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
7170 f_id++) {
7171
7172 cs_lnum_t c_id = b_face_cells[f_id];
7173
7174 /*
7175 Remark: for the cell \f$ \celli \f$ we remove
7176 \f$ \varia_\celli \sum_\face \vect{S}_\face = \vect{0} \f$
7177 */
7178 for (cs_lnum_t i = 0; i < 6; i++) {
7179 cs_real_t pfac = inc*coefat[f_id][i];
7180
7181 for (cs_lnum_t k = 0; k < 6; k++) {
7182 if (i == k)
7183 pfac += (coefbt[f_id][i][k] - 1.0) * pvar[c_id][k];
7184 else
7185 pfac += coefbt[f_id][i][k] * pvar[c_id][k] ;
7186
7187 }
7188
7189 for (cs_lnum_t j = 0; j < 3; j++)
7190 grad[c_id][i][j] += pfac * b_f_face_normal[f_id][j];
7191 }
7192
7193 } /* loop on faces */
7194
7195 } /* loop on threads */
7196
7197 } /* loop on thread groups */
7198
7199 # pragma omp parallel for
7200 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
7201 cs_real_t dvol;
7202 /* Is the cell disabled (for solid or porous)? Not the case if coupled */
7203 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
7204 dvol = 1. / cell_f_vol[c_id];
7205 else
7206 dvol = 0.;
7207
7208 for (cs_lnum_t i = 0; i < 6; i++) {
7209 for (cs_lnum_t j = 0; j < 3; j++)
7210 grad[c_id][i][j] *= dvol;
7211 }
7212 }
7213
7214 /* Periodicity and parallelism treatment */
7215
7216 if (m->halo != NULL) {
7217 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)grad, 18);
7218 if (cs_glob_mesh->have_rotation_perio)
7219 cs_halo_perio_sync_var_sym_tens_grad(m->halo,
7220 halo_type,
7221 (cs_real_t *)grad);
7222 }
7223 }
7224
7225 /*----------------------------------------------------------------------------*/
7226 /*!
7227 * \brief Compute cell gradient of scalar field or component of vector or
7228 * tensor field.
7229 *
7230 * This variant of the \ref cs_gradient_scalar function assumes ghost cell
7231 * values for input arrays (var and optionally c_weight)
7232 * have already been synchronized.
7233 *
7234 * \param[in] var_name variable name
7235 * \param[in] gradient_info performance logging structure, or NULL
7236 * \param[in] gradient_type gradient type
7237 * \param[in] halo_type halo type
7238 * \param[in] inc if 0, solve on increment; 1 otherwise
7239 * \param[in] recompute_cocg should COCG FV quantities be recomputed ?
7240 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
7241 * \param[in] hyd_p_flag flag for hydrostatic pressure
7242 * \param[in] w_stride stride for weighting coefficient
7243 * \param[in] verbosity verbosity level
7244 * \param[in] clip_mode clipping mode
7245 * \param[in] epsilon precision for iterative gradient calculation
7246 * \param[in] clip_coeff clipping coefficient
7247 * \param[in] f_ext exterior force generating
7248 * the hydrostatic pressure
7249 * \param[in] bc_coeff_a boundary condition term a
7250 * \param[in] bc_coeff_b boundary condition term b
7251 * \param[in] var gradient's base variable
7252 * \param[in] c_weight weighted gradient coefficient variable,
7253 * or NULL
7254 * \param[in] cpl structure associated with internal coupling,
7255 * or NULL
7256 * \param[out] grad gradient
7257 */
7258 /*----------------------------------------------------------------------------*/
7259
7260 static void
_gradient_scalar(const char * var_name,cs_gradient_info_t * gradient_info,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,bool recompute_cocg,int n_r_sweeps,int hyd_p_flag,int w_stride,int verbosity,int clip_mode,double epsilon,double clip_coeff,cs_real_t f_ext[][3],const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t var[restrict],const cs_real_t c_weight[restrict],const cs_internal_coupling_t * cpl,cs_real_t grad[restrict][3])7261 _gradient_scalar(const char *var_name,
7262 cs_gradient_info_t *gradient_info,
7263 cs_gradient_type_t gradient_type,
7264 cs_halo_type_t halo_type,
7265 int inc,
7266 bool recompute_cocg,
7267 int n_r_sweeps,
7268 int hyd_p_flag,
7269 int w_stride,
7270 int verbosity,
7271 int clip_mode,
7272 double epsilon,
7273 double clip_coeff,
7274 cs_real_t f_ext[][3],
7275 const cs_real_t bc_coeff_a[],
7276 const cs_real_t bc_coeff_b[],
7277 const cs_real_t var[restrict],
7278 const cs_real_t c_weight[restrict],
7279 const cs_internal_coupling_t *cpl,
7280 cs_real_t grad[restrict][3])
7281 {
7282 const cs_mesh_t *mesh = cs_glob_mesh;
7283 cs_mesh_quantities_t *fvq = cs_glob_mesh_quantities;
7284
7285 cs_lnum_t n_b_faces = mesh->n_b_faces;
7286 cs_lnum_t n_cells_ext = mesh->n_cells_with_ghosts;
7287
7288 static int last_fvm_count = 0;
7289
7290 if (n_r_sweeps > 0) {
7291 int prev_fvq_count = last_fvm_count;
7292 last_fvm_count = cs_mesh_quantities_compute_count();
7293 if (last_fvm_count != prev_fvq_count)
7294 recompute_cocg = true;
7295 }
7296
7297 /* Use Neumann BC's as default if not provided */
7298
7299 cs_real_t *_bc_coeff_a = NULL;
7300 cs_real_t *_bc_coeff_b = NULL;
7301
7302 if (bc_coeff_a == NULL) {
7303 BFT_MALLOC(_bc_coeff_a, n_b_faces, cs_real_t);
7304 for (cs_lnum_t i = 0; i < n_b_faces; i++)
7305 _bc_coeff_a[i] = 0;
7306 bc_coeff_a = _bc_coeff_a;
7307 }
7308 if (bc_coeff_b == NULL) {
7309 BFT_MALLOC(_bc_coeff_b, n_b_faces, cs_real_t);
7310 for (cs_lnum_t i = 0; i < n_b_faces; i++)
7311 _bc_coeff_b[i] = 1;
7312 bc_coeff_b = _bc_coeff_b;
7313 }
7314
7315 /* Allocate work arrays */
7316
7317 /* Compute gradient */
7318
7319 switch (gradient_type) {
7320
7321 case CS_GRADIENT_GREEN_ITER:
7322
7323 _initialize_scalar_gradient(mesh,
7324 fvq,
7325 cpl,
7326 hyd_p_flag,
7327 inc,
7328 (const cs_real_3_t *)f_ext,
7329 bc_coeff_a,
7330 bc_coeff_b,
7331 var,
7332 c_weight,
7333 grad);
7334
7335 _iterative_scalar_gradient(mesh,
7336 fvq,
7337 cpl,
7338 var_name,
7339 gradient_info,
7340 n_r_sweeps,
7341 hyd_p_flag,
7342 verbosity,
7343 inc,
7344 epsilon,
7345 (const cs_real_3_t *)f_ext,
7346 bc_coeff_a,
7347 bc_coeff_b,
7348 var,
7349 c_weight,
7350 grad);
7351 break;
7352
7353 case CS_GRADIENT_LSQ:
7354
7355 if (w_stride == 6 && c_weight != NULL)
7356 _lsq_scalar_gradient_ani(mesh,
7357 fvq,
7358 cpl,
7359 inc,
7360 bc_coeff_a,
7361 bc_coeff_b,
7362 var,
7363 (const cs_real_6_t *)c_weight,
7364 grad);
7365 else
7366 _lsq_scalar_gradient(mesh,
7367 fvq,
7368 cpl,
7369 halo_type,
7370 recompute_cocg,
7371 hyd_p_flag,
7372 inc,
7373 (const cs_real_3_t *)f_ext,
7374 bc_coeff_a,
7375 bc_coeff_b,
7376 var,
7377 c_weight,
7378 grad);
7379
7380 _scalar_gradient_clipping(halo_type,
7381 clip_mode,
7382 verbosity,
7383 clip_coeff,
7384 var_name,
7385 var, grad);
7386 break;
7387
7388 case CS_GRADIENT_GREEN_LSQ:
7389 {
7390 cs_real_3_t *restrict r_grad;
7391 BFT_MALLOC(r_grad, n_cells_ext, cs_real_3_t);
7392
7393 if (w_stride == 6 && c_weight != NULL)
7394 _lsq_scalar_gradient_ani(mesh,
7395 fvq,
7396 cpl,
7397 inc,
7398 bc_coeff_a,
7399 bc_coeff_b,
7400 var,
7401 (const cs_real_6_t *)c_weight,
7402 grad);
7403 else
7404 _lsq_scalar_gradient(mesh,
7405 fvq,
7406 cpl,
7407 halo_type,
7408 recompute_cocg,
7409 hyd_p_flag,
7410 inc,
7411 (const cs_real_3_t *)f_ext,
7412 bc_coeff_a,
7413 bc_coeff_b,
7414 var,
7415 c_weight,
7416 r_grad);
7417
7418 _scalar_gradient_clipping(halo_type,
7419 clip_mode,
7420 verbosity,
7421 clip_coeff,
7422 var_name,
7423 var, r_grad);
7424
7425 _reconstruct_scalar_gradient(mesh,
7426 fvq,
7427 cpl,
7428 hyd_p_flag,
7429 inc,
7430 (const cs_real_3_t *)f_ext,
7431 bc_coeff_a,
7432 bc_coeff_b,
7433 c_weight,
7434 var,
7435 r_grad,
7436 grad);
7437
7438 BFT_FREE(r_grad);
7439 }
7440 break;
7441
7442 case CS_GRADIENT_GREEN_VTX:
7443 _fv_vtx_based_scalar_gradient(mesh,
7444 fvq,
7445 cpl,
7446 hyd_p_flag,
7447 inc,
7448 (const cs_real_3_t *)f_ext,
7449 bc_coeff_a,
7450 bc_coeff_b,
7451 var,
7452 c_weight,
7453 grad);
7454 break;
7455
7456 }
7457
7458 if (cs_glob_mesh_quantities_flag & CS_BAD_CELLS_REGULARISATION)
7459 cs_bad_cells_regularisation_vector(grad, 0);
7460
7461 BFT_FREE(_bc_coeff_a);
7462 BFT_FREE(_bc_coeff_b);
7463 }
7464
7465 /*----------------------------------------------------------------------------*/
7466 /*!
7467 * \brief Compute cell gradient of vector field.
7468 *
7469 * \param[in] var_name variable name
7470 * \param[in] gradient_info performance logging structure, or NULL
7471 * \param[in] gradient_type gradient type
7472 * \param[in] halo_type halo type
7473 * \param[in] inc if 0, solve on increment; 1 otherwise
7474 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
7475 * \param[in] verbosity verbosity level
7476 * \param[in] clip_mode clipping mode
7477 * \param[in] epsilon precision for iterative gradient calculation
7478 * \param[in] clip_coeff clipping coefficient
7479 * \param[in] bc_coeff_a boundary condition term a
7480 * \param[in] bc_coeff_b boundary condition term b
7481 * \param[in] var gradient's base variable
7482 * \param[in] c_weight weighted gradient coefficient variable,
7483 * or NULL
7484 * \param[in] cpl structure associated with internal coupling,
7485 * or NULL
7486 * \param[out] grad gradient
7487 (\f$ \der{u_i}{x_j} \f$ is grad[][i][j])
7488 */
7489 /*----------------------------------------------------------------------------*/
7490
7491 static void
_gradient_vector(const char * var_name,cs_gradient_info_t * gradient_info,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,int clip_mode,double epsilon,double clip_coeff,const cs_real_3_t bc_coeff_a[],const cs_real_33_t bc_coeff_b[],const cs_real_3_t * restrict var,const cs_real_t * restrict c_weight,const cs_internal_coupling_t * cpl,cs_real_33_t * restrict grad)7492 _gradient_vector(const char *var_name,
7493 cs_gradient_info_t *gradient_info,
7494 cs_gradient_type_t gradient_type,
7495 cs_halo_type_t halo_type,
7496 int inc,
7497 int n_r_sweeps,
7498 int verbosity,
7499 int clip_mode,
7500 double epsilon,
7501 double clip_coeff,
7502 const cs_real_3_t bc_coeff_a[],
7503 const cs_real_33_t bc_coeff_b[],
7504 const cs_real_3_t *restrict var,
7505 const cs_real_t *restrict c_weight,
7506 const cs_internal_coupling_t *cpl,
7507 cs_real_33_t *restrict grad)
7508 {
7509 const cs_mesh_t *mesh = cs_glob_mesh;
7510 const cs_mesh_quantities_t *fvq = cs_glob_mesh_quantities;
7511
7512 const cs_lnum_t n_cells_ext = mesh->n_cells_with_ghosts;
7513 const cs_lnum_t n_b_faces = mesh->n_b_faces;
7514
7515 /* Use Neumann BC's as default if not provided */
7516
7517 cs_real_3_t *_bc_coeff_a = NULL;
7518 cs_real_33_t *_bc_coeff_b = NULL;
7519
7520 if (bc_coeff_a == NULL) {
7521 BFT_MALLOC(_bc_coeff_a, n_b_faces, cs_real_3_t);
7522 for (cs_lnum_t i = 0; i < n_b_faces; i++) {
7523 for (cs_lnum_t j = 0; j < 3; j++)
7524 _bc_coeff_a[i][j] = 0;
7525 }
7526 bc_coeff_a = (const cs_real_3_t *)_bc_coeff_a;
7527 }
7528 if (bc_coeff_b == NULL) {
7529 BFT_MALLOC(_bc_coeff_b, n_b_faces, cs_real_33_t);
7530 for (cs_lnum_t i = 0; i < n_b_faces; i++) {
7531 for (cs_lnum_t j = 0; j < 3; j++) {
7532 for (cs_lnum_t k = 0; k < 3; k++)
7533 _bc_coeff_b[i][j][k] = 0;
7534 _bc_coeff_b[i][j][j] = 1;
7535 }
7536 }
7537 bc_coeff_b = (const cs_real_33_t *)_bc_coeff_b;
7538 }
7539
7540 /* Compute gradient */
7541
7542 switch (gradient_type) {
7543
7544 case CS_GRADIENT_GREEN_ITER:
7545
7546 _initialize_vector_gradient(mesh,
7547 fvq,
7548 cpl,
7549 halo_type,
7550 inc,
7551 bc_coeff_a,
7552 bc_coeff_b,
7553 var,
7554 c_weight,
7555 grad);
7556
7557 /* If reconstructions are required */
7558
7559 if (n_r_sweeps > 1)
7560 _iterative_vector_gradient(mesh,
7561 fvq,
7562 cpl,
7563 var_name,
7564 gradient_info,
7565 halo_type,
7566 inc,
7567 n_r_sweeps,
7568 verbosity,
7569 epsilon,
7570 bc_coeff_a,
7571 bc_coeff_b,
7572 (const cs_real_3_t *)var,
7573 c_weight,
7574 grad);
7575
7576 break;
7577
7578 case CS_GRADIENT_LSQ:
7579
7580 _lsq_vector_gradient(mesh,
7581 cs_glob_mesh_adjacencies,
7582 fvq,
7583 cpl,
7584 halo_type,
7585 inc,
7586 bc_coeff_a,
7587 bc_coeff_b,
7588 (const cs_real_3_t *)var,
7589 c_weight,
7590 grad);
7591
7592 _vector_gradient_clipping(mesh,
7593 fvq,
7594 halo_type,
7595 clip_mode,
7596 verbosity,
7597 clip_coeff,
7598 var_name,
7599 (const cs_real_3_t *)var,
7600 grad);
7601
7602 break;
7603
7604 case CS_GRADIENT_GREEN_LSQ:
7605
7606 {
7607 cs_real_33_t *restrict r_gradv;
7608 BFT_MALLOC(r_gradv, n_cells_ext, cs_real_33_t);
7609
7610 _lsq_vector_gradient(mesh,
7611 cs_glob_mesh_adjacencies,
7612 fvq,
7613 cpl,
7614 halo_type,
7615 inc,
7616 bc_coeff_a,
7617 bc_coeff_b,
7618 (const cs_real_3_t *)var,
7619 c_weight,
7620 r_gradv);
7621
7622 _vector_gradient_clipping(mesh,
7623 fvq,
7624 halo_type,
7625 clip_mode,
7626 verbosity,
7627 clip_coeff,
7628 var_name,
7629 (const cs_real_3_t *)var,
7630 r_gradv);
7631
7632 _reconstruct_vector_gradient(mesh,
7633 fvq,
7634 cpl,
7635 halo_type,
7636 inc,
7637 bc_coeff_a,
7638 bc_coeff_b,
7639 (const cs_real_3_t *)var,
7640 c_weight,
7641 r_gradv,
7642 grad);
7643
7644 BFT_FREE(r_gradv);
7645 }
7646 break;
7647
7648 case CS_GRADIENT_GREEN_VTX:
7649
7650 _fv_vtx_based_vector_gradient(mesh,
7651 fvq,
7652 cpl,
7653 inc,
7654 bc_coeff_a,
7655 bc_coeff_b,
7656 var,
7657 c_weight,
7658 grad);
7659
7660 break;
7661
7662 }
7663
7664 if (cs_glob_mesh_quantities_flag & CS_BAD_CELLS_REGULARISATION)
7665 cs_bad_cells_regularisation_tensor((cs_real_9_t *)grad, 0);
7666
7667 BFT_FREE(_bc_coeff_a);
7668 BFT_FREE(_bc_coeff_b);
7669 }
7670
7671 /*----------------------------------------------------------------------------*/
7672 /*!
7673 * \brief Compute the square of the Frobenius norm of a symmetric tensor
7674 *
7675 * \param[in] t
7676 *
7677 * \return the square of the norm
7678 */
7679 /*----------------------------------------------------------------------------*/
7680
7681 static inline cs_real_t
_tensor_norm_2(const cs_real_t t[6])7682 _tensor_norm_2(const cs_real_t t[6])
7683 {
7684 cs_real_t retval = t[0]*t[0] + t[1]*t[1] + t[2]*t[2]
7685 + 2*t[3]*t[3] + 2*t[4]*t[4] + 2*t[5]*t[5];
7686 return retval;
7687 }
7688
7689 /*----------------------------------------------------------------------------
7690 * Clip the gradient of a symmetric tensor if necessary. This function deals
7691 * with the standard or extended neighborhood.
7692 *
7693 * parameters:
7694 * m <-- pointer to associated mesh structure
7695 * fvq <-- pointer to associated finite volume quantities
7696 * halo_type <-- halo type (extended or not)
7697 * clip_mode <-- type of clipping for the computation of the gradient
7698 * verbosity <-- output level
7699 * climgp <-- clipping coefficient for the computation of the gradient
7700 * pvar <-- variable
7701 * gradt <-> gradient of pvar (du_i/dx_j : gradt[][i][j])
7702 *----------------------------------------------------------------------------*/
7703
7704 static void
_tensor_gradient_clipping(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_halo_type_t halo_type,int clip_mode,int verbosity,cs_real_t climgp,const char * var_name,const cs_real_6_t * restrict pvar,cs_real_63_t * restrict gradt)7705 _tensor_gradient_clipping(const cs_mesh_t *m,
7706 const cs_mesh_quantities_t *fvq,
7707 cs_halo_type_t halo_type,
7708 int clip_mode,
7709 int verbosity,
7710 cs_real_t climgp,
7711 const char *var_name,
7712 const cs_real_6_t *restrict pvar,
7713 cs_real_63_t *restrict gradt)
7714 {
7715 cs_real_t global_min_factor, global_max_factor;
7716
7717 cs_gnum_t n_clip = 0, n_g_clip = 0;
7718 cs_real_t min_factor = 1;
7719 cs_real_t max_factor = 0;
7720 cs_real_t clipp_coef_sq = climgp*climgp;
7721 cs_real_t *restrict buf = NULL, *restrict clip_factor = NULL;
7722 cs_real_t *restrict denom = NULL, *restrict denum = NULL;
7723
7724 const cs_lnum_t n_cells = m->n_cells;
7725 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
7726 const int n_i_groups = m->i_face_numbering->n_groups;
7727 const int n_i_threads = m->i_face_numbering->n_threads;
7728 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
7729
7730 const cs_lnum_2_t *restrict i_face_cells
7731 = (const cs_lnum_2_t *restrict)m->i_face_cells;
7732 const cs_lnum_t *restrict cell_cells_idx
7733 = (const cs_lnum_t *restrict)m->cell_cells_idx;
7734 const cs_lnum_t *restrict cell_cells_lst
7735 = (const cs_lnum_t *restrict)m->cell_cells_lst;
7736
7737 const cs_real_3_t *restrict cell_cen
7738 = (const cs_real_3_t *restrict)fvq->cell_cen;
7739
7740 const cs_halo_t *halo = m->halo;
7741
7742 if (clip_mode <= CS_GRADIENT_LIMIT_NONE)
7743 return;
7744
7745 /* The gradient and the variable must be already synchronized */
7746
7747 /* Allocate and initialize working buffers */
7748
7749 if (clip_mode == CS_GRADIENT_LIMIT_FACE)
7750 BFT_MALLOC(buf, 3*n_cells_ext, cs_real_t);
7751 else
7752 BFT_MALLOC(buf, 2*n_cells_ext, cs_real_t);
7753
7754 denum = buf;
7755 denom = buf + n_cells_ext;
7756
7757 if (clip_mode == CS_GRADIENT_LIMIT_FACE)
7758 clip_factor = buf + 2*n_cells_ext;
7759
7760 /* Initialization */
7761
7762 # pragma omp parallel for
7763 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
7764 denum[c_id] = 0;
7765 denom[c_id] = 0;
7766 if (clip_mode == CS_GRADIENT_LIMIT_FACE)
7767 clip_factor[c_id] = (cs_real_t)DBL_MAX;
7768 }
7769
7770 /* Remark:
7771 denum: holds the maximum l2 norm of the variation of the gradient squared
7772 denom: holds the maximum l2 norm of the variation of the variable squared */
7773
7774 /* First clipping Algorithm: based on the cell gradient */
7775 /*------------------------------------------------------*/
7776
7777 if (clip_mode == CS_GRADIENT_LIMIT_CELL) {
7778
7779 for (int g_id = 0; g_id < n_i_groups; g_id++) {
7780
7781 # pragma omp parallel for
7782 for (int t_id = 0; t_id < n_i_threads; t_id++) {
7783
7784 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7785 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7786 f_id++) {
7787
7788 cs_lnum_t c_id1 = i_face_cells[f_id][0];
7789 cs_lnum_t c_id2 = i_face_cells[f_id][1];
7790
7791 cs_real_t dist[3];
7792 for (cs_lnum_t i = 0; i < 3; i++)
7793 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
7794
7795 cs_real_t grad_dist1[6], grad_dist2[6], var_dist[6];
7796
7797 for (cs_lnum_t i = 0; i < 6; i++) {
7798
7799 grad_dist1[i] = gradt[c_id1][i][0] * dist[0]
7800 + gradt[c_id1][i][1] * dist[1]
7801 + gradt[c_id1][i][2] * dist[2];
7802
7803 grad_dist2[i] = gradt[c_id2][i][0] * dist[0]
7804 + gradt[c_id2][i][1] * dist[1]
7805 + gradt[c_id2][i][2] * dist[2];
7806
7807 var_dist[i] = pvar[c_id1][i] - pvar[c_id2][i];
7808
7809 }
7810
7811 cs_real_t dist_sq1 = _tensor_norm_2(grad_dist1);
7812 cs_real_t dist_sq2 = _tensor_norm_2(grad_dist2);
7813
7814 cs_real_t dvar_sq = _tensor_norm_2(var_dist);
7815
7816 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
7817 denum[c_id2] = CS_MAX(denum[c_id2], dist_sq2);
7818 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
7819 denom[c_id2] = CS_MAX(denom[c_id2], dvar_sq);
7820
7821 } /* End of loop on faces */
7822
7823 } /* End of loop on threads */
7824
7825 } /* End of loop on thread groups */
7826
7827 /* Complement for extended neighborhood */
7828
7829 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
7830
7831 # pragma omp parallel for
7832 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
7833 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
7834 cidx < cell_cells_idx[c_id1+1];
7835 cidx++) {
7836
7837 cs_lnum_t c_id2 = cell_cells_lst[cidx];
7838
7839 cs_real_t grad_dist1[6], var_dist[6];
7840
7841 cs_real_t dist[3];
7842 for (cs_lnum_t i = 0; i < 3; i++)
7843 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
7844
7845 for (cs_lnum_t i = 0; i < 6; i++) {
7846
7847 grad_dist1[i] = gradt[c_id1][i][0] * dist[0]
7848 + gradt[c_id1][i][1] * dist[1]
7849 + gradt[c_id1][i][2] * dist[2];
7850
7851 var_dist[i] = pvar[c_id1][i] - pvar[c_id2][i];
7852
7853 }
7854
7855 cs_real_t dist_sq1 = _tensor_norm_2(grad_dist1);
7856
7857 cs_real_t dvar_sq = _tensor_norm_2(var_dist);
7858
7859 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
7860 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
7861
7862 }
7863 }
7864
7865 } /* End for extended halo */
7866
7867 }
7868
7869 /* Second clipping Algorithm: based on the face gradient */
7870 /*-------------------------------------------------------*/
7871
7872 else if (clip_mode == CS_GRADIENT_LIMIT_FACE) {
7873
7874 for (int g_id = 0; g_id < n_i_groups; g_id++) {
7875
7876 # pragma omp parallel for
7877 for (int t_id = 0; t_id < n_i_threads; t_id++) {
7878
7879 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
7880 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
7881 f_id++) {
7882
7883 cs_lnum_t c_id1 = i_face_cells[f_id][0];
7884 cs_lnum_t c_id2 = i_face_cells[f_id][1];
7885
7886 cs_real_t dist[3];
7887 for (cs_lnum_t i = 0; i < 3; i++)
7888 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
7889
7890 cs_real_t grad_dist1[6], var_dist[6];
7891
7892 for (cs_lnum_t i = 0; i < 6; i++) {
7893 grad_dist1[i]
7894 = 0.5 * ( (gradt[c_id1][i][0]+gradt[c_id2][i][0])*dist[0]
7895 + (gradt[c_id1][i][1]+gradt[c_id2][i][1])*dist[1]
7896 + (gradt[c_id1][i][2]+gradt[c_id2][i][2])*dist[2]);
7897 var_dist[i] = pvar[c_id1][i] - pvar[c_id2][i];
7898 }
7899
7900 cs_real_t dist_sq1 = _tensor_norm_2(grad_dist1);
7901 cs_real_t dvar_sq = _tensor_norm_2(var_dist);
7902
7903 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
7904 denum[c_id2] = CS_MAX(denum[c_id2], dist_sq1);
7905 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
7906 denom[c_id2] = CS_MAX(denom[c_id2], dvar_sq);
7907
7908 } /* End of loop on threads */
7909
7910 } /* End of loop on thread groups */
7911
7912 } /* End of loop on faces */
7913
7914 /* Complement for extended neighborhood */
7915
7916 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
7917
7918 # pragma omp parallel for
7919 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
7920 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
7921 cidx < cell_cells_idx[c_id1+1];
7922 cidx++) {
7923
7924 cs_lnum_t c_id2 = cell_cells_lst[cidx];
7925
7926 cs_real_t dist[3];
7927 for (cs_lnum_t i = 0; i < 3; i++)
7928 dist[i] = cell_cen[c_id1][i] - cell_cen[c_id2][i];
7929
7930 cs_real_t grad_dist1[6], var_dist[6];
7931
7932 for (cs_lnum_t i = 0; i < 6; i++) {
7933 grad_dist1[i]
7934 = 0.5 * ( (gradt[c_id1][i][0]+gradt[c_id2][i][0])*dist[0]
7935 + (gradt[c_id1][i][1]+gradt[c_id2][i][1])*dist[1]
7936 + (gradt[c_id1][i][2]+gradt[c_id2][i][2])*dist[2]);
7937 var_dist[i] = pvar[c_id1][i] - pvar[c_id2][i];
7938 }
7939
7940 cs_real_t dist_sq1 = _tensor_norm_2(grad_dist1);
7941 cs_real_t dvar_sq = _tensor_norm_2(var_dist);
7942
7943 denum[c_id1] = CS_MAX(denum[c_id1], dist_sq1);
7944 denom[c_id1] = CS_MAX(denom[c_id1], dvar_sq);
7945
7946 }
7947 }
7948
7949 } /* End for extended neighborhood */
7950
7951 /* Synchronize variable */
7952
7953 if (halo != NULL) {
7954 cs_halo_sync_var(m->halo, halo_type, denom);
7955 cs_halo_sync_var(m->halo, halo_type, denum);
7956 }
7957
7958 } /* End if clip_mode == CS_GRADIENT_LIMIT_FACE */
7959
7960 /* Clipping of the gradient if denum/denom > climgp**2 */
7961
7962 /* First clipping Algorithm: based on the cell gradient */
7963 /*------------------------------------------------------*/
7964
7965 if (clip_mode == CS_GRADIENT_LIMIT_CELL) {
7966
7967 # pragma omp parallel
7968 {
7969 cs_gnum_t t_n_clip = 0;
7970 cs_real_t t_min_factor = min_factor, t_max_factor = max_factor;
7971
7972 # pragma omp for
7973 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
7974
7975 if (denum[c_id] > clipp_coef_sq * denom[c_id]) {
7976
7977 cs_real_t factor1 = sqrt(clipp_coef_sq * denom[c_id]/denum[c_id]);
7978
7979 for (cs_lnum_t i = 0; i < 3; i++) {
7980 for (cs_lnum_t j = 0; j < 3; j++)
7981 gradt[c_id][i][j] *= factor1;
7982 }
7983
7984 t_min_factor = CS_MIN(factor1, t_min_factor);
7985 t_max_factor = CS_MAX(factor1, t_max_factor);
7986 t_n_clip++;
7987
7988 } /* If clipping */
7989
7990 } /* End of loop on cells */
7991
7992 # pragma omp critical
7993 {
7994 min_factor = CS_MIN(min_factor, t_min_factor);
7995 max_factor = CS_MAX(max_factor, t_max_factor);
7996 n_clip += t_n_clip;
7997 }
7998 } /* End of omp parallel construct */
7999
8000 }
8001
8002 /* Second clipping Algorithm: based on the face gradient */
8003 /*-------------------------------------------------------*/
8004
8005 else if (clip_mode == CS_GRADIENT_LIMIT_FACE) {
8006
8007 for (int g_id = 0; g_id < n_i_groups; g_id++) {
8008
8009 # pragma omp parallel for
8010 for (int t_id = 0; t_id < n_i_threads; t_id++) {
8011
8012 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
8013 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
8014 f_id++) {
8015
8016 cs_lnum_t c_id1 = i_face_cells[f_id][0];
8017 cs_lnum_t c_id2 = i_face_cells[f_id][1];
8018
8019 cs_real_t factor1 = 1.0;
8020 if (denum[c_id1] > clipp_coef_sq * denom[c_id1])
8021 factor1 = sqrt(clipp_coef_sq * denom[c_id1]/denum[c_id1]);
8022
8023 cs_real_t factor2 = 1.0;
8024 if (denum[c_id2] > clipp_coef_sq * denom[c_id2])
8025 factor2 = sqrt(clipp_coef_sq * denom[c_id2]/denum[c_id2]);
8026
8027 cs_real_t t_min_factor = CS_MIN(factor1, factor2);
8028
8029 clip_factor[c_id1] = CS_MIN(clip_factor[c_id1], t_min_factor);
8030 clip_factor[c_id2] = CS_MIN(clip_factor[c_id2], t_min_factor);
8031
8032 } /* End of loop on faces */
8033
8034 } /* End of loop on threads */
8035
8036 } /* End of loop on thread groups */
8037
8038 /* Complement for extended neighborhood */
8039
8040 if (cell_cells_idx != NULL && halo_type == CS_HALO_EXTENDED) {
8041
8042 # pragma omp parallel for
8043 for (cs_lnum_t c_id1 = 0; c_id1 < n_cells; c_id1++) {
8044
8045 cs_real_t t_min_factor = 1;
8046
8047 for (cs_lnum_t cidx = cell_cells_idx[c_id1];
8048 cidx < cell_cells_idx[c_id1+1];
8049 cidx++) {
8050
8051 cs_lnum_t c_id2 = cell_cells_lst[cidx];
8052 cs_real_t factor2 = 1.0;
8053
8054 if (denum[c_id2] > clipp_coef_sq * denom[c_id2])
8055 factor2 = sqrt(clipp_coef_sq * denom[c_id2]/denum[c_id2]);
8056
8057 t_min_factor = CS_MIN(min_factor, factor2);
8058
8059 }
8060
8061 clip_factor[c_id1] = CS_MIN(clip_factor[c_id1], t_min_factor);
8062
8063 } /* End of loop on cells */
8064
8065 } /* End for extended neighborhood */
8066
8067 # pragma omp parallel
8068 {
8069 cs_lnum_t t_n_clip = 0;
8070 cs_real_t t_min_factor = min_factor, t_max_factor = max_factor;
8071
8072 # pragma omp for
8073 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
8074
8075 for (cs_lnum_t i = 0; i < 3; i++) {
8076 for (cs_lnum_t j = 0; j < 3; j++)
8077 gradt[c_id][i][j] *= clip_factor[c_id];
8078 }
8079
8080 if (clip_factor[c_id] < 0.99) {
8081 t_max_factor = CS_MAX(t_max_factor, clip_factor[c_id]);
8082 t_min_factor = CS_MIN(t_min_factor, clip_factor[c_id]);
8083 t_n_clip++;
8084 }
8085
8086 } /* End of loop on cells */
8087
8088 # pragma omp critical
8089 {
8090 min_factor = CS_MIN(min_factor, t_min_factor);
8091 max_factor = CS_MAX(max_factor, t_max_factor);
8092 n_clip += t_n_clip;
8093 }
8094 } /* End of omp parallel construct */
8095
8096 } /* End if clip_mode == CS_GRADIENT_LIMIT_FACE */
8097
8098 /* Update min/max and n_clip in case of parallelism */
8099 /*--------------------------------------------------*/
8100
8101 #if defined(HAVE_MPI)
8102
8103 if (m->n_domains > 1) {
8104
8105 assert(sizeof(cs_real_t) == sizeof(double));
8106
8107 /* Global Max */
8108
8109 MPI_Allreduce(&max_factor, &global_max_factor, 1, CS_MPI_REAL,
8110 MPI_MAX, cs_glob_mpi_comm);
8111
8112 max_factor = global_max_factor;
8113
8114 /* Global min */
8115
8116 MPI_Allreduce(&min_factor, &global_min_factor, 1, CS_MPI_REAL,
8117 MPI_MIN, cs_glob_mpi_comm);
8118
8119 min_factor = global_min_factor;
8120
8121 /* Sum number of clippings */
8122
8123 MPI_Allreduce(&n_clip, &n_g_clip, 1, CS_MPI_GNUM,
8124 MPI_SUM, cs_glob_mpi_comm);
8125
8126 n_clip = n_g_clip;
8127
8128 } /* If n_domains > 1 */
8129
8130 #endif /* defined(HAVE_MPI) */
8131
8132 /* Output warning if necessary */
8133
8134 if (verbosity > 1)
8135 bft_printf(_(" Variable: %s; Gradient of a vector limitation in %llu cells\n"
8136 " minimum factor = %14.5e; maximum factor = %14.5e\n"),
8137 var_name,
8138 (unsigned long long)n_clip, min_factor, max_factor);
8139
8140 /* Synchronize the updated Gradient */
8141
8142 if (m->halo != NULL) {
8143 cs_halo_sync_var_strided(m->halo, halo_type, (cs_real_t *)gradt, 9);
8144 if (cs_glob_mesh->have_rotation_perio)
8145 cs_halo_perio_sync_var_tens(m->halo, halo_type, (cs_real_t *)gradt);
8146 }
8147
8148 BFT_FREE(buf);
8149 }
8150
8151 /*----------------------------------------------------------------------------*/
8152 /*!
8153 * \brief Compute cell gradient of tensor.
8154 *
8155 * \param[in] var_name variable name
8156 * \param[in] gradient_info performance logging structure, or NULL
8157 * \param[in] gradient_type gradient type
8158 * \param[in] halo_type halo type
8159 * \param[in] inc if 0, solve on increment; 1 otherwise
8160 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
8161 * \param[in] verbosity verbosity level
8162 * \param[in] clip_mode clipping mode
8163 * \param[in] epsilon precision for iterative gradient calculation
8164 * \param[in] clip_coeff clipping coefficient
8165 * \param[in] bc_coeff_a boundary condition term a
8166 * \param[in] bc_coeff_b boundary condition term b
8167 * \param[in] var gradient's base variable
8168 * \param[out] grad gradient
8169 (\f$ \der{u_i}{x_j} \f$ is gradv[][i][j])
8170 */
8171 /*----------------------------------------------------------------------------*/
8172
8173 static void
_gradient_tensor(const char * var_name,cs_gradient_info_t * gradient_info,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,int clip_mode,double epsilon,double clip_coeff,const cs_real_6_t bc_coeff_a[],const cs_real_66_t bc_coeff_b[],const cs_real_6_t * restrict var,cs_real_63_t * restrict grad)8174 _gradient_tensor(const char *var_name,
8175 cs_gradient_info_t *gradient_info,
8176 cs_gradient_type_t gradient_type,
8177 cs_halo_type_t halo_type,
8178 int inc,
8179 int n_r_sweeps,
8180 int verbosity,
8181 int clip_mode,
8182 double epsilon,
8183 double clip_coeff,
8184 const cs_real_6_t bc_coeff_a[],
8185 const cs_real_66_t bc_coeff_b[],
8186 const cs_real_6_t *restrict var,
8187 cs_real_63_t *restrict grad)
8188 {
8189 const cs_mesh_t *mesh = cs_glob_mesh;
8190 const cs_mesh_quantities_t *fvq = cs_glob_mesh_quantities;
8191
8192 const cs_lnum_t n_b_faces = mesh->n_b_faces;
8193
8194 /* Use Neumann BC's as default if not provided */
8195
8196 cs_real_6_t *_bc_coeff_a = NULL;
8197 cs_real_66_t *_bc_coeff_b = NULL;
8198
8199 if (bc_coeff_a == NULL) {
8200 BFT_MALLOC(_bc_coeff_a, n_b_faces, cs_real_6_t);
8201 for (cs_lnum_t i = 0; i < n_b_faces; i++) {
8202 for (cs_lnum_t j = 0; j < 6; j++)
8203 _bc_coeff_a[i][j] = 0;
8204 }
8205 bc_coeff_a = (const cs_real_6_t *)_bc_coeff_a;
8206 }
8207 if (bc_coeff_b == NULL) {
8208 BFT_MALLOC(_bc_coeff_b, n_b_faces, cs_real_66_t);
8209 for (cs_lnum_t i = 0; i < n_b_faces; i++) {
8210 for (cs_lnum_t j = 0; j < 6; j++) {
8211 for (cs_lnum_t k = 0; k < 6; k++)
8212 _bc_coeff_b[i][j][k] = 0;
8213 _bc_coeff_b[i][j][j] = 1;
8214 }
8215 }
8216 bc_coeff_b = (const cs_real_66_t *)_bc_coeff_b;
8217 }
8218
8219 /* Compute gradient */
8220
8221 switch (gradient_type) {
8222
8223 case CS_GRADIENT_GREEN_ITER:
8224
8225 _initialize_tensor_gradient(mesh,
8226 fvq,
8227 halo_type,
8228 inc,
8229 bc_coeff_a,
8230 bc_coeff_b,
8231 var,
8232 grad);
8233
8234 /* If reconstructions are required */
8235
8236 if (n_r_sweeps > 1)
8237 _iterative_tensor_gradient(mesh,
8238 fvq,
8239 var_name,
8240 gradient_info,
8241 halo_type,
8242 inc,
8243 n_r_sweeps,
8244 verbosity,
8245 epsilon,
8246 bc_coeff_a,
8247 bc_coeff_b,
8248 (const cs_real_6_t *)var,
8249 grad);
8250
8251 break;
8252
8253 case CS_GRADIENT_LSQ:
8254
8255 _lsq_tensor_gradient(mesh,
8256 cs_glob_mesh_adjacencies,
8257 fvq,
8258 halo_type,
8259 inc,
8260 bc_coeff_a,
8261 bc_coeff_b,
8262 (const cs_real_6_t *)var,
8263 NULL, /* c_weight */
8264 grad);
8265
8266 _tensor_gradient_clipping(mesh,
8267 fvq,
8268 halo_type,
8269 clip_mode,
8270 verbosity,
8271 clip_coeff,
8272 var_name,
8273 (const cs_real_6_t *)var,
8274 grad);
8275
8276 break;
8277
8278 default:
8279 assert(0); /* Should be set to available options by caller */
8280 break;
8281
8282 }
8283
8284 BFT_FREE(_bc_coeff_a);
8285 BFT_FREE(_bc_coeff_b);
8286 }
8287
8288 /*============================================================================
8289 * Fortran wrapper function definitions
8290 *============================================================================*/
8291
8292 /*----------------------------------------------------------------------------
8293 * Compute cell gradient of scalar field or component of vector or
8294 * tensor field.
8295 *----------------------------------------------------------------------------*/
8296
8297 void
cs_f_gradient_s(int f_id,int imrgra,int inc,int iccocg,int n_r_sweeps,int iwarnp,int imligp,cs_real_t epsrgp,cs_real_t climgp,const cs_real_t coefap[],const cs_real_t coefbp[],cs_real_t pvar[],cs_real_3_t grad[])8298 cs_f_gradient_s(int f_id,
8299 int imrgra,
8300 int inc,
8301 int iccocg,
8302 int n_r_sweeps,
8303 int iwarnp,
8304 int imligp,
8305 cs_real_t epsrgp,
8306 cs_real_t climgp,
8307 const cs_real_t coefap[],
8308 const cs_real_t coefbp[],
8309 cs_real_t pvar[],
8310 cs_real_3_t grad[])
8311 {
8312 bool recompute_cocg = (iccocg) ? true : false;
8313
8314 cs_halo_type_t halo_type = CS_HALO_STANDARD;
8315 cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8316
8317 char var_name[32];
8318 if (f_id > -1) {
8319 cs_field_t *f = cs_field_by_id(f_id);
8320 snprintf(var_name, 31, "%s", f->name);
8321 }
8322 else
8323 strcpy(var_name, "Work array");
8324 var_name[31] = '\0';
8325
8326 /* Choose gradient type */
8327
8328 cs_gradient_type_by_imrgra(imrgra,
8329 &gradient_type,
8330 &halo_type);
8331
8332 /* Check if given field has internal coupling */
8333 cs_internal_coupling_t *cpl = NULL;
8334 if (f_id > -1) {
8335 const int key_id = cs_field_key_id_try("coupling_entity");
8336 if (key_id > -1) {
8337 const cs_field_t *f = cs_field_by_id(f_id);
8338 int coupl_id = cs_field_get_key_int(f, key_id);
8339 if (coupl_id > -1)
8340 cpl = cs_internal_coupling_by_id(coupl_id);
8341 }
8342 }
8343
8344 /* Compute gradient */
8345
8346 cs_gradient_scalar(var_name,
8347 gradient_type,
8348 halo_type,
8349 inc,
8350 recompute_cocg,
8351 n_r_sweeps,
8352 0, /* ignored */
8353 0, /* iphydp */
8354 1, /* w_stride */
8355 iwarnp,
8356 imligp,
8357 epsrgp,
8358 climgp,
8359 NULL, /* f_ext */
8360 coefap,
8361 coefbp,
8362 pvar,
8363 NULL, /* c_weight */
8364 cpl,
8365 grad);
8366 }
8367
8368 /*----------------------------------------------------------------------------
8369 * Compute cell gradient of potential-type values.
8370 *----------------------------------------------------------------------------*/
8371
8372 void
cs_f_gradient_potential(int f_id,int imrgra,int inc,int iccocg,int n_r_sweeps,int iphydp,int iwarnp,int imligp,cs_real_t epsrgp,cs_real_t climgp,cs_real_3_t f_ext[],const cs_real_t coefap[],const cs_real_t coefbp[],cs_real_t pvar[],cs_real_3_t grad[])8373 cs_f_gradient_potential(int f_id,
8374 int imrgra,
8375 int inc,
8376 int iccocg,
8377 int n_r_sweeps,
8378 int iphydp,
8379 int iwarnp,
8380 int imligp,
8381 cs_real_t epsrgp,
8382 cs_real_t climgp,
8383 cs_real_3_t f_ext[],
8384 const cs_real_t coefap[],
8385 const cs_real_t coefbp[],
8386 cs_real_t pvar[],
8387 cs_real_3_t grad[])
8388 {
8389 bool recompute_cocg = (iccocg) ? true : false;
8390
8391 cs_halo_type_t halo_type = CS_HALO_STANDARD;
8392 cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8393
8394 char var_name[32];
8395 if (f_id > -1) {
8396 cs_field_t *f = cs_field_by_id(f_id);
8397 snprintf(var_name, 31, "%s", f->name);
8398 }
8399 else
8400 strcpy(var_name, "Work array");
8401 var_name[31] = '\0';
8402
8403 /* Choose gradient type */
8404
8405 cs_gradient_type_by_imrgra(imrgra,
8406 &gradient_type,
8407 &halo_type);
8408
8409 /* Check if given field has internal coupling */
8410 cs_internal_coupling_t *cpl = NULL;
8411 if (f_id > -1) {
8412 const int key_id = cs_field_key_id_try("coupling_entity");
8413 if (key_id > -1) {
8414 const cs_field_t *f = cs_field_by_id(f_id);
8415 int coupl_id = cs_field_get_key_int(f, key_id);
8416 if (coupl_id > -1)
8417 cpl = cs_internal_coupling_by_id(coupl_id);
8418 }
8419 }
8420
8421 /* Compute gradient */
8422
8423 cs_gradient_scalar(var_name,
8424 gradient_type,
8425 halo_type,
8426 inc,
8427 recompute_cocg,
8428 n_r_sweeps,
8429 0, /* ignored */
8430 iphydp,
8431 1, /* w_stride */
8432 iwarnp,
8433 imligp,
8434 epsrgp,
8435 climgp,
8436 f_ext,
8437 coefap,
8438 coefbp,
8439 pvar,
8440 NULL, /* c_weight */
8441 cpl,
8442 grad);
8443 }
8444
8445 /*----------------------------------------------------------------------------
8446 * Compute cell gradient of potential-type values.
8447 *----------------------------------------------------------------------------*/
8448
8449 void
cs_f_gradient_weighted_s(int f_id,int imrgra,int inc,int iccocg,int n_r_sweeps,int iphydp,int iwarnp,int imligp,cs_real_t epsrgp,cs_real_t climgp,cs_real_3_t f_ext[],const cs_real_t coefap[],const cs_real_t coefbp[],cs_real_t pvar[],cs_real_t c_weight[],cs_real_3_t grad[])8450 cs_f_gradient_weighted_s(int f_id,
8451 int imrgra,
8452 int inc,
8453 int iccocg,
8454 int n_r_sweeps,
8455 int iphydp,
8456 int iwarnp,
8457 int imligp,
8458 cs_real_t epsrgp,
8459 cs_real_t climgp,
8460 cs_real_3_t f_ext[],
8461 const cs_real_t coefap[],
8462 const cs_real_t coefbp[],
8463 cs_real_t pvar[],
8464 cs_real_t c_weight[],
8465 cs_real_3_t grad[])
8466 {
8467 bool recompute_cocg = (iccocg) ? true : false;
8468
8469 cs_halo_type_t halo_type = CS_HALO_STANDARD;
8470 cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8471
8472 char var_name[32];
8473 if (f_id > -1) {
8474 cs_field_t *f = cs_field_by_id(f_id);
8475 snprintf(var_name, 31, "%s", f->name);
8476 }
8477 else
8478 strcpy(var_name, "Work array");
8479 var_name[31] = '\0';
8480
8481 /* Choose gradient type */
8482
8483 cs_gradient_type_by_imrgra(imrgra,
8484 &gradient_type,
8485 &halo_type);
8486
8487 /* Check if given field has internal coupling */
8488 cs_internal_coupling_t *cpl = NULL;
8489 if (f_id > -1) {
8490 const int key_id = cs_field_key_id_try("coupling_entity");
8491 if (key_id > -1) {
8492 const cs_field_t *f = cs_field_by_id(f_id);
8493 int coupl_id = cs_field_get_key_int(f, key_id);
8494 if (coupl_id > -1)
8495 cpl = cs_internal_coupling_by_id(coupl_id);
8496 }
8497 }
8498
8499 /* Compute gradient */
8500
8501 cs_gradient_scalar(var_name,
8502 gradient_type,
8503 halo_type,
8504 inc,
8505 recompute_cocg,
8506 n_r_sweeps,
8507 0, /* ignored */
8508 iphydp,
8509 1, /* w_stride */
8510 iwarnp,
8511 imligp,
8512 epsrgp,
8513 climgp,
8514 f_ext,
8515 coefap,
8516 coefbp,
8517 pvar,
8518 c_weight,
8519 cpl,
8520 grad);
8521 }
8522
8523 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
8524
8525 /*============================================================================
8526 * Public function definitions for Fortran API
8527 *============================================================================*/
8528
8529 /*----------------------------------------------------------------------------
8530 * Compute the steady balance due to porous modelling for the pressure
8531 * gradient
8532 *----------------------------------------------------------------------------*/
8533
CS_PROCF(grdpor,GRDPOR)8534 void CS_PROCF (grdpor, GRDPOR)
8535 (
8536 const int *const inc /* <-- 0 or 1: increment or not */
8537 )
8538 {
8539 cs_gradient_porosity_balance(*inc);
8540 }
8541
8542 /*----------------------------------------------------------------------------
8543 * Compute cell gradient of vector field.
8544 *----------------------------------------------------------------------------*/
8545
CS_PROCF(cgdvec,CGDVEC)8546 void CS_PROCF (cgdvec, CGDVEC)
8547 (
8548 const int *const f_id, /* <-- field id, or -1 */
8549 const int *const imrgra, /* <-- gradient computation mode */
8550 const int *const inc, /* <-- 0 or 1: increment or not */
8551 const int *const n_r_sweeps,/* <-- >1: with reconstruction */
8552 const int *const iwarnp, /* <-- verbosity level */
8553 const int *const imligp, /* <-- type of clipping */
8554 const cs_real_t *const epsrgp, /* <-- precision for iterative
8555 gradient calculation */
8556 const cs_real_t *const climgp, /* <-- clipping coefficient */
8557 const cs_real_3_t coefav[], /* <-- boundary condition term */
8558 const cs_real_33_t coefbv[], /* <-- boundary condition term */
8559 cs_real_3_t pvar[], /* <-- gradient's base variable */
8560 cs_real_33_t grad[] /* <-> gradient of the variable
8561 (du_i/dx_j : grad[][i][j]) */
8562 )
8563 {
8564 char var_name[32];
8565
8566 cs_halo_type_t halo_type = CS_HALO_STANDARD;
8567 cs_gradient_type_t gradient_type = CS_GRADIENT_GREEN_ITER;
8568
8569 cs_gradient_type_by_imrgra(*imrgra,
8570 &gradient_type,
8571 &halo_type);
8572
8573 if (*f_id > -1)
8574 snprintf(var_name, 31, "Field %2d", *f_id);
8575 else
8576 strcpy(var_name, "Work array");
8577 var_name[31] = '\0';
8578
8579 /* Check if given field has internal coupling */
8580 cs_internal_coupling_t *cpl = NULL;
8581 if (*f_id > -1) {
8582 const int key_id = cs_field_key_id_try("coupling_entity");
8583 if (key_id > -1) {
8584 const cs_field_t *f = cs_field_by_id(*f_id);
8585 int coupl_id = cs_field_get_key_int(f, key_id);
8586 if (coupl_id > -1)
8587 cpl = cs_internal_coupling_by_id(coupl_id);
8588 }
8589 }
8590
8591 cs_gradient_vector(var_name,
8592 gradient_type,
8593 halo_type,
8594 *inc,
8595 *n_r_sweeps,
8596 *iwarnp,
8597 *imligp,
8598 *epsrgp,
8599 *climgp,
8600 coefav,
8601 coefbv,
8602 pvar,
8603 NULL, /* weighted gradient */
8604 cpl,
8605 grad);
8606 }
8607
8608 /*============================================================================
8609 * Public function definitions
8610 *============================================================================*/
8611
8612 /*----------------------------------------------------------------------------*/
8613 /*!
8614 * \brief Initialize gradient computation API.
8615 */
8616 /*----------------------------------------------------------------------------*/
8617
8618 void
cs_gradient_initialize(void)8619 cs_gradient_initialize(void)
8620 {
8621 assert(cs_glob_mesh != NULL);
8622
8623 CS_TIMER_COUNTER_INIT(_gradient_t_tot);
8624
8625 int stats_root = cs_timer_stats_id_by_name("operations");
8626 if (stats_root > -1) {
8627 _gradient_stat_id = cs_timer_stats_create("operations",
8628 "gradients",
8629 "gradients reconstruction");
8630 }
8631 }
8632
8633 /*----------------------------------------------------------------------------*/
8634 /*!
8635 * \brief Finalize gradient computation API.
8636 */
8637 /*----------------------------------------------------------------------------*/
8638
8639 void
cs_gradient_finalize(void)8640 cs_gradient_finalize(void)
8641 {
8642 _gradient_quantities_destroy();
8643
8644 cs_log_printf(CS_LOG_PERFORMANCE,
8645 _("\n"
8646 "Total elapsed time for all gradient computations: %.3f s\n"),
8647 _gradient_t_tot.nsec*1e-9);
8648
8649 /* Free system info */
8650
8651 for (int ii = 0; ii < cs_glob_gradient_n_systems; ii++) {
8652 _gradient_info_dump(cs_glob_gradient_systems[ii]);
8653 _gradient_info_destroy(&(cs_glob_gradient_systems[ii]));
8654 }
8655
8656 cs_log_printf(CS_LOG_PERFORMANCE, "\n");
8657 cs_log_separator(CS_LOG_PERFORMANCE);
8658
8659 BFT_FREE(cs_glob_gradient_systems);
8660
8661 cs_glob_gradient_n_systems = 0;
8662 cs_glob_gradient_n_max_systems = 0;
8663 }
8664
8665 /*----------------------------------------------------------------------------*/
8666 /*!
8667 * \brief Free saved gradient quantities.
8668 *
8669 * This is required when the mesh changes, so that the on-demand computation
8670 * will be updated.
8671 */
8672 /*----------------------------------------------------------------------------*/
8673
8674 void
cs_gradient_free_quantities(void)8675 cs_gradient_free_quantities(void)
8676 {
8677 for (int i = 0; i < _n_gradient_quantities; i++) {
8678
8679 cs_gradient_quantities_t *gq = _gradient_quantities + i;
8680
8681 BFT_FREE(gq->cocg_it);
8682 BFT_FREE(gq->cocgb_s_lsq);
8683 BFT_FREE(gq->cocg_lsq);
8684 BFT_FREE(gq->cocgb_s_lsq_ext);
8685 BFT_FREE(gq->cocg_lsq_ext);
8686
8687 }
8688 }
8689
8690 /*----------------------------------------------------------------------------*/
8691 /*!
8692 * \brief Compute cell gradient of scalar field or component of vector or
8693 * tensor field.
8694 *
8695 * \param[in] var_name variable name
8696 * \param[in] gradient_type gradient type
8697 * \param[in] halo_type halo type
8698 * \param[in] inc if 0, solve on increment; 1 otherwise
8699 * \param[in] recompute_cocg should COCG FV quantities be recomputed ?
8700 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
8701 * (only used by CS_GRADIENT_GREEN_ITER)
8702 * \param[in] tr_dim ignored
8703 * \param[in] hyd_p_flag flag for hydrostatic pressure
8704 * \param[in] w_stride stride for weighting coefficient
8705 * \param[in] verbosity verbosity level
8706 * \param[in] clip_mode clipping mode
8707 * \param[in] epsilon precision for iterative gradient calculation
8708 * \param[in] clip_coeff clipping coefficient
8709 * \param[in] f_ext exterior force generating the
8710 * hydrostatic pressure
8711 * \param[in] bc_coeff_a boundary condition term a
8712 * \param[in] bc_coeff_b boundary condition term b
8713 * \param[in, out] var gradient's base variable
8714 * \param[in, out] c_weight cell variable weight, or NULL
8715 * \param[in] cpl associated internal coupling, or NULL
8716 * \param[out] grad gradient
8717 */
8718 /*----------------------------------------------------------------------------*/
8719
8720 void
cs_gradient_scalar(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,bool recompute_cocg,int n_r_sweeps,int tr_dim,int hyd_p_flag,int w_stride,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,cs_real_3_t f_ext[],const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],cs_real_t var[restrict],cs_real_t * restrict c_weight,const cs_internal_coupling_t * cpl,cs_real_t grad[restrict][3])8721 cs_gradient_scalar(const char *var_name,
8722 cs_gradient_type_t gradient_type,
8723 cs_halo_type_t halo_type,
8724 int inc,
8725 bool recompute_cocg,
8726 int n_r_sweeps,
8727 int tr_dim,
8728 int hyd_p_flag,
8729 int w_stride,
8730 int verbosity,
8731 cs_gradient_limit_t clip_mode,
8732 double epsilon,
8733 double clip_coeff,
8734 cs_real_3_t f_ext[],
8735 const cs_real_t bc_coeff_a[],
8736 const cs_real_t bc_coeff_b[],
8737 cs_real_t var[restrict],
8738 cs_real_t *restrict c_weight,
8739 const cs_internal_coupling_t *cpl,
8740 cs_real_t grad[restrict][3])
8741 {
8742 CS_UNUSED(tr_dim);
8743
8744 const cs_mesh_t *mesh = cs_glob_mesh;
8745 cs_gradient_info_t *gradient_info = NULL;
8746 cs_timer_t t0, t1;
8747
8748 bool update_stats = true;
8749
8750 t0 = cs_timer_time();
8751
8752 if (update_stats == true)
8753 gradient_info = _find_or_add_system(var_name, gradient_type);
8754
8755 /* Synchronize variable */
8756
8757 if (mesh->halo != NULL) {
8758
8759 cs_halo_sync_var(mesh->halo, halo_type, var);
8760
8761 if (c_weight != NULL) {
8762 if (w_stride == 6) {
8763 cs_halo_sync_var_strided(mesh->halo, halo_type, c_weight, 6);
8764 cs_halo_perio_sync_var_sym_tens(mesh->halo, halo_type, c_weight);
8765 }
8766 else
8767 cs_halo_sync_var(mesh->halo, halo_type, c_weight);
8768 }
8769
8770 if (hyd_p_flag == 1) {
8771 cs_halo_sync_var_strided(mesh->halo, halo_type, (cs_real_t *)f_ext, 3);
8772 cs_halo_perio_sync_var_vect(mesh->halo, halo_type, (cs_real_t *)f_ext, 3);
8773 }
8774
8775 }
8776
8777 _gradient_scalar(var_name,
8778 gradient_info,
8779 gradient_type,
8780 halo_type,
8781 inc,
8782 recompute_cocg,
8783 n_r_sweeps,
8784 hyd_p_flag,
8785 w_stride,
8786 verbosity,
8787 clip_mode,
8788 epsilon,
8789 clip_coeff,
8790 f_ext,
8791 bc_coeff_a,
8792 bc_coeff_b,
8793 var,
8794 c_weight,
8795 cpl,
8796 grad);
8797
8798 t1 = cs_timer_time();
8799
8800 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
8801
8802 if (update_stats == true) {
8803 gradient_info->n_calls += 1;
8804 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
8805 }
8806
8807 if (_gradient_stat_id > -1)
8808 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
8809 }
8810
8811 /*----------------------------------------------------------------------------*/
8812 /*!
8813 * \brief Compute cell gradient of vector field.
8814 *
8815 * \param[in] var_name variable name
8816 * \param[in] gradient_type gradient type
8817 * \param[in] halo_type halo type
8818 * \param[in] inc if 0, solve on increment; 1 otherwise
8819 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
8820 * (only used by CS_GRADIENT_GREEN_ITER)
8821 * \param[in] verbosity verbosity level
8822 * \param[in] clip_mode clipping mode
8823 * \param[in] epsilon precision for iterative gradient calculation
8824 * \param[in] clip_coeff clipping coefficient
8825 * \param[in] bc_coeff_a boundary condition term a
8826 * \param[in] bc_coeff_b boundary condition term b
8827 * \param[in, out] var gradient's base variable
8828 * \param[in, out] c_weight cell variable weight, or NULL
8829 * \param[in] cpl associated internal coupling, or NULL
8830 * \param[out] gradv gradient
8831 (\f$ \der{u_i}{x_j} \f$ is gradv[][i][j])
8832 */
8833 /*----------------------------------------------------------------------------*/
8834
8835 void
cs_gradient_vector(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,const cs_real_t bc_coeff_a[][3],const cs_real_t bc_coeff_b[][3][3],cs_real_t var[restrict][3],cs_real_t * restrict c_weight,const cs_internal_coupling_t * cpl,cs_real_t gradv[restrict][3][3])8836 cs_gradient_vector(const char *var_name,
8837 cs_gradient_type_t gradient_type,
8838 cs_halo_type_t halo_type,
8839 int inc,
8840 int n_r_sweeps,
8841 int verbosity,
8842 cs_gradient_limit_t clip_mode,
8843 double epsilon,
8844 double clip_coeff,
8845 const cs_real_t bc_coeff_a[][3],
8846 const cs_real_t bc_coeff_b[][3][3],
8847 cs_real_t var[restrict][3],
8848 cs_real_t *restrict c_weight,
8849 const cs_internal_coupling_t *cpl,
8850 cs_real_t gradv[restrict][3][3])
8851 {
8852 const cs_mesh_t *mesh = cs_glob_mesh;
8853
8854 cs_gradient_info_t *gradient_info = NULL;
8855 cs_timer_t t0, t1;
8856
8857 bool update_stats = true;
8858
8859 t0 = cs_timer_time();
8860
8861 if (update_stats == true) {
8862 gradient_info = _find_or_add_system(var_name, gradient_type);
8863 }
8864
8865 /* By default, handle the gradient as a tensor
8866 (i.e. we assume it is the gradient of a vector field) */
8867
8868 if (mesh->halo != NULL) {
8869
8870 cs_halo_sync_var_strided(mesh->halo, halo_type, (cs_real_t *)var, 3);
8871 if (cs_glob_mesh->have_rotation_perio)
8872 cs_halo_perio_sync_var_vect(mesh->halo, halo_type, (cs_real_t *)var, 3);
8873
8874 if (c_weight != NULL)
8875 cs_halo_sync_var(mesh->halo, halo_type, c_weight);
8876
8877 }
8878
8879 /* Compute gradient */
8880
8881 _gradient_vector(var_name,
8882 gradient_info,
8883 gradient_type,
8884 halo_type,
8885 inc,
8886 n_r_sweeps,
8887 verbosity,
8888 clip_mode,
8889 epsilon,
8890 clip_coeff,
8891 bc_coeff_a,
8892 bc_coeff_b,
8893 (const cs_real_3_t *)var,
8894 (const cs_real_t *)c_weight,
8895 cpl,
8896 gradv);
8897
8898 t1 = cs_timer_time();
8899
8900 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
8901
8902 if (update_stats == true) {
8903 gradient_info->n_calls += 1;
8904 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
8905 }
8906
8907 if (_gradient_stat_id > -1)
8908 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
8909 }
8910
8911 /*----------------------------------------------------------------------------*/
8912 /*!
8913 * \brief Compute cell gradient of tensor.
8914 *
8915 * \param[in] var_name variable name
8916 * \param[in] gradient_type gradient type
8917 * \param[in] halo_type halo type
8918 * \param[in] inc if 0, solve on increment; 1 otherwise
8919 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
8920 * (only used by CS_GRADIENT_GREEN_ITER)
8921 * \param[in] verbosity verbosity level
8922 * \param[in] clip_mode clipping mode
8923 * \param[in] epsilon precision for iterative gradient calculation
8924 * \param[in] clip_coeff clipping coefficient
8925 * \param[in] bc_coeff_a boundary condition term a
8926 * \param[in] bc_coeff_b boundary condition term b
8927 * \param[in, out] var gradient's base variable
8928 * \param[out] grad gradient
8929 (\f$ \der{t_ij}{x_k} \f$ is grad[][ij][k])
8930 */
8931 /*----------------------------------------------------------------------------*/
8932
8933 void
cs_gradient_tensor(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,const cs_real_6_t bc_coeff_a[],const cs_real_66_t bc_coeff_b[],cs_real_6_t * restrict var,cs_real_63_t * restrict grad)8934 cs_gradient_tensor(const char *var_name,
8935 cs_gradient_type_t gradient_type,
8936 cs_halo_type_t halo_type,
8937 int inc,
8938 int n_r_sweeps,
8939 int verbosity,
8940 cs_gradient_limit_t clip_mode,
8941 double epsilon,
8942 double clip_coeff,
8943 const cs_real_6_t bc_coeff_a[],
8944 const cs_real_66_t bc_coeff_b[],
8945 cs_real_6_t *restrict var,
8946 cs_real_63_t *restrict grad)
8947 {
8948 const cs_mesh_t *mesh = cs_glob_mesh;
8949
8950 cs_gradient_info_t *gradient_info = NULL;
8951 cs_timer_t t0, t1;
8952
8953 bool update_stats = true;
8954
8955 if ( gradient_type == CS_GRADIENT_GREEN_LSQ
8956 || gradient_type == CS_GRADIENT_GREEN_VTX)
8957 gradient_type = CS_GRADIENT_GREEN_ITER;
8958
8959 t0 = cs_timer_time();
8960
8961 if (update_stats == true) {
8962 gradient_info = _find_or_add_system(var_name, gradient_type);
8963 }
8964
8965 /* By default, handle the gradient as a tensor
8966 (i.e. we assume it is the gradient of a vector field) */
8967
8968 if (mesh->halo != NULL) {
8969 cs_halo_sync_var_strided(mesh->halo, halo_type, (cs_real_t *)var, 6);
8970 if (mesh->have_rotation_perio)
8971 cs_halo_perio_sync_var_sym_tens(mesh->halo, halo_type, (cs_real_t *)var);
8972 }
8973
8974 /* Compute gradient */
8975
8976 _gradient_tensor(var_name,
8977 gradient_info,
8978 gradient_type,
8979 halo_type,
8980 inc,
8981 n_r_sweeps,
8982 verbosity,
8983 clip_mode,
8984 epsilon,
8985 clip_coeff,
8986 bc_coeff_a,
8987 bc_coeff_b,
8988 (const cs_real_6_t *)var,
8989 grad);
8990
8991 t1 = cs_timer_time();
8992
8993 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
8994
8995 if (update_stats == true) {
8996 gradient_info->n_calls += 1;
8997 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
8998 }
8999
9000 if (_gradient_stat_id > -1)
9001 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
9002 }
9003
9004 /*----------------------------------------------------------------------------*/
9005 /*!
9006 * \brief Compute cell gradient of scalar field or component of vector or
9007 * tensor field.
9008 *
9009 * This variant of the \ref cs_gradient_scalar function assumes ghost cell
9010 * values for input arrays (var and optionally c_weight)
9011 * have already been synchronized.
9012 *
9013 * \param[in] var_name variable name
9014 * \param[in] gradient_type gradient type
9015 * \param[in] halo_type halo type
9016 * \param[in] inc if 0, solve on increment; 1 otherwise
9017 * \param[in] recompute_cocg should COCG FV quantities be recomputed ?
9018 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
9019 * (only used by CS_GRADIENT_GREEN_ITER)
9020 * \param[in] hyd_p_flag flag for hydrostatic pressure
9021 * \param[in] w_stride stride for weighting coefficient
9022 * \param[in] verbosity verbosity level
9023 * \param[in] clip_mode clipping mode
9024 * \param[in] epsilon precision for iterative gradient calculation
9025 * \param[in] clip_coeff clipping coefficient
9026 * \param[in] f_ext exterior force generating the
9027 * hydrostatic pressure
9028 * \param[in] bc_coeff_a boundary condition term a
9029 * \param[in] bc_coeff_b boundary condition term b
9030 * \param[in] var gradient's base variable
9031 * \param[in] c_weight cell variable weight, or NULL
9032 * \param[in] cpl associated internal coupling, or NULL
9033 * \param[out] grad gradient
9034 */
9035 /*----------------------------------------------------------------------------*/
9036
9037 void
cs_gradient_scalar_synced_input(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,bool recompute_cocg,int n_r_sweeps,int hyd_p_flag,int w_stride,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,cs_real_t f_ext[][3],const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t var[restrict],const cs_real_t c_weight[restrict],const cs_internal_coupling_t * cpl,cs_real_t grad[restrict][3])9038 cs_gradient_scalar_synced_input(const char *var_name,
9039 cs_gradient_type_t gradient_type,
9040 cs_halo_type_t halo_type,
9041 int inc,
9042 bool recompute_cocg,
9043 int n_r_sweeps,
9044 int hyd_p_flag,
9045 int w_stride,
9046 int verbosity,
9047 cs_gradient_limit_t clip_mode,
9048 double epsilon,
9049 double clip_coeff,
9050 cs_real_t f_ext[][3],
9051 const cs_real_t bc_coeff_a[],
9052 const cs_real_t bc_coeff_b[],
9053 const cs_real_t var[restrict],
9054 const cs_real_t c_weight[restrict],
9055 const cs_internal_coupling_t *cpl,
9056 cs_real_t grad[restrict][3])
9057 {
9058 cs_gradient_info_t *gradient_info = NULL;
9059 cs_timer_t t0, t1;
9060
9061 bool update_stats = true;
9062
9063 if (hyd_p_flag == 1) {
9064 if (cs_glob_mesh->halo != NULL) {
9065 cs_halo_sync_var_strided(cs_glob_mesh->halo, halo_type,
9066 (cs_real_t *)f_ext, 3);
9067 if (cs_glob_mesh->have_rotation_perio)
9068 cs_halo_perio_sync_var_vect(cs_glob_mesh->halo, halo_type,
9069 (cs_real_t *)f_ext, 3);
9070 }
9071 }
9072
9073 t0 = cs_timer_time();
9074
9075 if (update_stats == true)
9076 gradient_info = _find_or_add_system(var_name, gradient_type);
9077
9078 _gradient_scalar(var_name,
9079 gradient_info,
9080 gradient_type,
9081 halo_type,
9082 inc,
9083 recompute_cocg,
9084 n_r_sweeps,
9085 hyd_p_flag,
9086 w_stride,
9087 verbosity,
9088 clip_mode,
9089 epsilon,
9090 clip_coeff,
9091 f_ext,
9092 bc_coeff_a,
9093 bc_coeff_b,
9094 var,
9095 c_weight,
9096 cpl,
9097 grad);
9098
9099 t1 = cs_timer_time();
9100
9101 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
9102
9103 if (update_stats == true) {
9104 gradient_info->n_calls += 1;
9105 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
9106 }
9107
9108 if (_gradient_stat_id > -1)
9109 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
9110 }
9111
9112 /*----------------------------------------------------------------------------*/
9113 /*!
9114 * \brief Compute cell gradient of vector field.
9115 *
9116 * This variant of the \ref cs_gradient_vector function assumes ghost cell
9117 * values for input arrays (var and optionally c_weight)
9118 * have already been synchronized.
9119 *
9120 * \param[in] var_name variable name
9121 * \param[in] gradient_type gradient type
9122 * \param[in] halo_type halo type
9123 * \param[in] inc if 0, solve on increment; 1 otherwise
9124 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
9125 * (only used by CS_GRADIENT_GREEN_ITER)
9126 * \param[in] verbosity verbosity level
9127 * \param[in] clip_mode clipping mode
9128 * \param[in] epsilon precision for iterative gradient calculation
9129 * \param[in] clip_coeff clipping coefficient
9130 * \param[in] bc_coeff_a boundary condition term a
9131 * \param[in] bc_coeff_b boundary condition term b
9132 * \param[in] var gradient's base variable
9133 * \param[in] c_weight cell variable weight, or NULL
9134 * \param[in] cpl associated internal coupling, or NULL
9135 * \param[out] grad gradient
9136 (\f$ \der{u_i}{x_j} \f$ is gradv[][i][j])
9137 */
9138 /*----------------------------------------------------------------------------*/
9139
9140 void
cs_gradient_vector_synced_input(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,const cs_real_t bc_coeff_a[][3],const cs_real_t bc_coeff_b[][3][3],const cs_real_t var[restrict][3],const cs_real_t c_weight[restrict],const cs_internal_coupling_t * cpl,cs_real_t grad[restrict][3][3])9141 cs_gradient_vector_synced_input(const char *var_name,
9142 cs_gradient_type_t gradient_type,
9143 cs_halo_type_t halo_type,
9144 int inc,
9145 int n_r_sweeps,
9146 int verbosity,
9147 cs_gradient_limit_t clip_mode,
9148 double epsilon,
9149 double clip_coeff,
9150 const cs_real_t bc_coeff_a[][3],
9151 const cs_real_t bc_coeff_b[][3][3],
9152 const cs_real_t var[restrict][3],
9153 const cs_real_t c_weight[restrict],
9154 const cs_internal_coupling_t *cpl,
9155 cs_real_t grad[restrict][3][3])
9156 {
9157 cs_gradient_info_t *gradient_info = NULL;
9158 cs_timer_t t0, t1;
9159
9160 bool update_stats = true;
9161
9162 t0 = cs_timer_time();
9163
9164 if (update_stats == true)
9165 gradient_info = _find_or_add_system(var_name, gradient_type);
9166
9167 /* Compute gradient */
9168
9169 _gradient_vector(var_name,
9170 gradient_info,
9171 gradient_type,
9172 halo_type,
9173 inc,
9174 n_r_sweeps,
9175 verbosity,
9176 clip_mode,
9177 epsilon,
9178 clip_coeff,
9179 bc_coeff_a,
9180 bc_coeff_b,
9181 var,
9182 c_weight,
9183 cpl,
9184 grad);
9185
9186 t1 = cs_timer_time();
9187
9188 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
9189
9190 if (update_stats == true) {
9191 gradient_info->n_calls += 1;
9192 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
9193 }
9194
9195 if (_gradient_stat_id > -1)
9196 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
9197 }
9198
9199 /*----------------------------------------------------------------------------*/
9200 /*!
9201 * \brief Compute cell gradient of tensor.
9202 *
9203 * This variant of the \ref cs_gradient_tensor function assumes ghost cell
9204 * values for input arrays (var and optionally c_weight)
9205 * have already been synchronized.
9206 *
9207 * \param[in] var_name variable name
9208 * \param[in] gradient_type gradient type
9209 * \param[in] halo_type halo type
9210 * \param[in] inc if 0, solve on increment; 1 otherwise
9211 * \param[in] n_r_sweeps if > 1, number of reconstruction sweeps
9212 * (only used by CS_GRADIENT_GREEN_ITER)
9213 * \param[in] verbosity verbosity level
9214 * \param[in] clip_mode clipping mode
9215 * \param[in] epsilon precision for iterative gradient calculation
9216 * \param[in] clip_coeff clipping coefficient
9217 * \param[in] bc_coeff_a boundary condition term a
9218 * \param[in] bc_coeff_b boundary condition term b
9219 * \param[in, out] var gradient's base variable
9220 * \param[out] grad gradient
9221 (\f$ \der{t_ij}{x_k} \f$ is grad[][ij][k])
9222 */
9223 /*----------------------------------------------------------------------------*/
9224
9225 void
cs_gradient_tensor_synced_input(const char * var_name,cs_gradient_type_t gradient_type,cs_halo_type_t halo_type,int inc,int n_r_sweeps,int verbosity,cs_gradient_limit_t clip_mode,double epsilon,double clip_coeff,const cs_real_t bc_coeff_a[][6],const cs_real_t bc_coeff_b[][6][6],const cs_real_t var[restrict][6],cs_real_63_t * restrict grad)9226 cs_gradient_tensor_synced_input(const char *var_name,
9227 cs_gradient_type_t gradient_type,
9228 cs_halo_type_t halo_type,
9229 int inc,
9230 int n_r_sweeps,
9231 int verbosity,
9232 cs_gradient_limit_t clip_mode,
9233 double epsilon,
9234 double clip_coeff,
9235 const cs_real_t bc_coeff_a[][6],
9236 const cs_real_t bc_coeff_b[][6][6],
9237 const cs_real_t var[restrict][6],
9238 cs_real_63_t *restrict grad)
9239 {
9240 cs_gradient_info_t *gradient_info = NULL;
9241 cs_timer_t t0, t1;
9242
9243 bool update_stats = true;
9244
9245 t0 = cs_timer_time();
9246
9247 if ( gradient_type == CS_GRADIENT_GREEN_LSQ
9248 || gradient_type == CS_GRADIENT_GREEN_VTX)
9249 gradient_type = CS_GRADIENT_GREEN_ITER;
9250
9251 if (update_stats == true)
9252 gradient_info = _find_or_add_system(var_name, gradient_type);
9253
9254 /* Compute gradient */
9255
9256 _gradient_tensor(var_name,
9257 gradient_info,
9258 gradient_type,
9259 halo_type,
9260 inc,
9261 n_r_sweeps,
9262 verbosity,
9263 clip_mode,
9264 epsilon,
9265 clip_coeff,
9266 bc_coeff_a,
9267 bc_coeff_b,
9268 var,
9269 grad);
9270
9271 t1 = cs_timer_time();
9272
9273 cs_timer_counter_add_diff(&_gradient_t_tot, &t0, &t1);
9274
9275 if (update_stats == true) {
9276 gradient_info->n_calls += 1;
9277 cs_timer_counter_add_diff(&(gradient_info->t_tot), &t0, &t1);
9278 }
9279
9280 if (_gradient_stat_id > -1)
9281 cs_timer_stats_add_diff(_gradient_stat_id, &t0, &t1);
9282 }
9283
9284 /*----------------------------------------------------------------------------*/
9285 /*!
9286 * \brief Compute the gradient of a scalar field at a given cell
9287 * using least-squares reconstruction.
9288 *
9289 * This assumes ghost cell values which might be used are already
9290 * synchronized.
9291 *
9292 * When boundary conditions are provided, both the bc_coeff_a and bc_coeff_b
9293 * arrays must be given. If boundary values are known, bc_coeff_a
9294 * can point to the boundary values array, and bc_coeff_b set to NULL.
9295 * If bc_coeff_a is NULL, bc_coeff_b is ignored.
9296 *
9297 * \param[in] m pointer to associated mesh structure
9298 * \param[in] fvq pointer to associated finite volume quantities
9299 * \param[in] c_id cell id
9300 * \param[in] halo_type halo type
9301 * \param[in] bc_coeff_a boundary condition term a, or NULL
9302 * \param[in] bc_coeff_b boundary condition term b, or NULL
9303 * \param[in] var gradient's base variable
9304 * \param[in] c_weight cell variable weight, or NULL
9305 * \param[out] grad gradient
9306 */
9307 /*----------------------------------------------------------------------------*/
9308
9309 void
cs_gradient_scalar_cell(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_lnum_t c_id,cs_halo_type_t halo_type,const cs_real_t bc_coeff_a[],const cs_real_t bc_coeff_b[],const cs_real_t var[],const cs_real_t c_weight[],cs_real_t grad[3])9310 cs_gradient_scalar_cell(const cs_mesh_t *m,
9311 const cs_mesh_quantities_t *fvq,
9312 cs_lnum_t c_id,
9313 cs_halo_type_t halo_type,
9314 const cs_real_t bc_coeff_a[],
9315 const cs_real_t bc_coeff_b[],
9316 const cs_real_t var[],
9317 const cs_real_t c_weight[],
9318 cs_real_t grad[3])
9319 {
9320 CS_UNUSED(m);
9321
9322 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
9323 const cs_lnum_t *restrict cell_cells_idx
9324 = (const cs_lnum_t *restrict) ma->cell_cells_idx;
9325 const cs_lnum_t *restrict cell_cells_e_idx
9326 = (const cs_lnum_t *restrict) ma->cell_cells_e_idx;
9327 const cs_lnum_t *restrict cell_b_faces_idx
9328 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
9329 const cs_lnum_t *restrict cell_cells
9330 = (const cs_lnum_t *restrict) ma->cell_cells;
9331 const cs_lnum_t *restrict cell_cells_e
9332 = (const cs_lnum_t *restrict) ma->cell_cells_e;
9333 const cs_lnum_t *restrict cell_b_faces
9334 = (const cs_lnum_t *restrict) ma->cell_b_faces;
9335
9336 const cs_real_3_t *restrict cell_cen
9337 = (const cs_real_3_t *restrict)fvq->cell_cen;
9338
9339 /* Reconstruct gradients using least squares for non-orthogonal meshes */
9340
9341 cs_real_t cocg[6] = {0., 0., 0., 0., 0., 0.};
9342 cs_real_t rhsv[3] = {0., 0., 0.};
9343
9344 int n_adj = (halo_type == CS_HALO_EXTENDED) ? 2 : 1;
9345
9346 for (int adj_id = 0; adj_id < n_adj; adj_id++) {
9347
9348 const cs_lnum_t *restrict cell_cells_p;
9349 cs_lnum_t s_id, e_id;
9350
9351 if (adj_id == 0){
9352 s_id = cell_cells_idx[c_id];
9353 e_id = cell_cells_idx[c_id+1];
9354 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells);
9355 }
9356 else if (cell_cells_e_idx != NULL){
9357 s_id = cell_cells_e_idx[c_id];
9358 e_id = cell_cells_e_idx[c_id+1];
9359 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells_e);
9360 }
9361 else
9362 break;
9363
9364 if (c_weight == NULL) {
9365
9366 for (cs_lnum_t i = s_id; i < e_id; i++) {
9367
9368 cs_real_t dc[3];
9369 cs_lnum_t c_id1 = cell_cells_p[i];
9370 for (cs_lnum_t ii = 0; ii < 3; ii++)
9371 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9372
9373 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9374
9375 cs_real_t pfac = (var[c_id1] - var[c_id]) * ddc;
9376
9377 for (cs_lnum_t ll = 0; ll < 3; ll++)
9378 rhsv[ll] += dc[ll] * pfac;
9379
9380 cocg[0] += dc[0]*dc[0]*ddc;
9381 cocg[1] += dc[1]*dc[1]*ddc;
9382 cocg[2] += dc[2]*dc[2]*ddc;
9383 cocg[3] += dc[0]*dc[1]*ddc;
9384 cocg[4] += dc[1]*dc[2]*ddc;
9385 cocg[5] += dc[0]*dc[2]*ddc;
9386
9387 }
9388
9389 }
9390 else {
9391
9392 for (cs_lnum_t i = s_id; i < e_id; i++) {
9393
9394 cs_real_t dc[3];
9395 cs_lnum_t c_id1 = cell_cells_p[i];
9396 for (cs_lnum_t ii = 0; ii < 3; ii++)
9397 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9398
9399 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9400
9401 cs_real_t pfac = (var[c_id1] - var[c_id]) * ddc;
9402
9403 cs_real_t _weight = 2. * c_weight[c_id1]
9404 / (c_weight[c_id] + c_weight[c_id1]);
9405
9406 for (cs_lnum_t ll = 0; ll < 3; ll++)
9407 rhsv[ll] += dc[ll] * pfac * _weight;
9408
9409 cocg[0] += dc[0]*dc[0]*ddc;
9410 cocg[1] += dc[1]*dc[1]*ddc;
9411 cocg[2] += dc[2]*dc[2]*ddc;
9412 cocg[3] += dc[0]*dc[1]*ddc;
9413 cocg[4] += dc[1]*dc[2]*ddc;
9414 cocg[5] += dc[0]*dc[2]*ddc;
9415
9416 }
9417 }
9418
9419 } /* end of contribution from interior and extended cells */
9420
9421 cs_lnum_t s_id = cell_b_faces_idx[c_id];
9422 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
9423
9424 /* Contribution from boundary faces */
9425
9426 for (cs_lnum_t i = s_id; i < e_id; i++) {
9427
9428 const cs_real_3_t *restrict b_face_normal
9429 = (const cs_real_3_t *restrict)fvq->b_face_normal;
9430 const cs_real_t *restrict b_face_surf
9431 = (const cs_real_t *restrict)fvq->b_face_surf;
9432 const cs_real_t *restrict b_dist
9433 = (const cs_real_t *restrict)fvq->b_dist;
9434 const cs_real_3_t *restrict diipb
9435 = (const cs_real_3_t *restrict)fvq->diipb;
9436
9437 cs_real_t dsij[3];
9438
9439 cs_lnum_t f_id = cell_b_faces[i];
9440
9441 cs_real_t udbfs = 1. / b_face_surf[f_id];
9442
9443 for (cs_lnum_t ll = 0; ll < 3; ll++)
9444 dsij[ll] = udbfs * b_face_normal[f_id][ll];
9445
9446 if (bc_coeff_a != NULL && bc_coeff_b != NULL) { /* Known face BC's */
9447
9448 cs_real_t unddij = 1. / b_dist[f_id];
9449 cs_real_t umcbdd = (1. -bc_coeff_b[f_id]) * unddij;
9450
9451 cs_real_t pfac = ( bc_coeff_a[f_id] + (bc_coeff_b[f_id] -1.)
9452 * var[c_id]) * unddij;
9453
9454 for (cs_lnum_t ll = 0; ll < 3; ll++)
9455 dsij[ll] += umcbdd*diipb[f_id][ll];
9456
9457 for (cs_lnum_t ll = 0; ll < 3; ll++)
9458 rhsv[ll] += dsij[ll] * pfac;
9459
9460 cocg[0] += dsij[0] * dsij[0];
9461 cocg[1] += dsij[1] * dsij[1];
9462 cocg[2] += dsij[2] * dsij[2];
9463 cocg[3] += dsij[0] * dsij[1];
9464 cocg[4] += dsij[1] * dsij[2];
9465 cocg[5] += dsij[0] * dsij[2];
9466
9467 }
9468 else if (bc_coeff_a != NULL) { /* Known face values */
9469
9470 const cs_real_3_t *restrict b_face_cog
9471 = (const cs_real_3_t *restrict)fvq->b_face_cog;
9472
9473 cs_real_t dc[3];
9474 for (cs_lnum_t ii = 0; ii < 3; ii++)
9475 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
9476
9477 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9478
9479 cs_real_t pfac = (bc_coeff_a[f_id] - var[c_id]) * ddc;
9480
9481 for (cs_lnum_t ll = 0; ll < 3; ll++)
9482 rhsv[ll] += dc[ll] * pfac;
9483
9484 cocg[0] += dc[0]*dc[0]*ddc;
9485 cocg[1] += dc[1]*dc[1]*ddc;
9486 cocg[2] += dc[2]*dc[2]*ddc;
9487 cocg[3] += dc[0]*dc[1]*ddc;
9488 cocg[4] += dc[1]*dc[2]*ddc;
9489 cocg[5] += dc[0]*dc[2]*ddc;
9490
9491 }
9492
9493 else { /* Assign cell values as face values (homogeneous Neumann);
9494 as above, pfac cancels out, so does contribution to RHS */
9495
9496 const cs_real_3_t *restrict b_face_cog
9497 = (const cs_real_3_t *restrict)fvq->b_face_cog;
9498
9499 cs_real_t dc[3];
9500 for (cs_lnum_t ii = 0; ii < 3; ii++)
9501 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
9502
9503 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9504
9505 cocg[0] += dc[0]*dc[0]*ddc;
9506 cocg[1] += dc[1]*dc[1]*ddc;
9507 cocg[2] += dc[2]*dc[2]*ddc;
9508 cocg[3] += dc[0]*dc[1]*ddc;
9509 cocg[4] += dc[1]*dc[2]*ddc;
9510 cocg[5] += dc[0]*dc[2]*ddc;
9511
9512 }
9513
9514 } // end of contribution from boundary cells
9515
9516 /* Invert */
9517
9518 cs_real_t a00 = cocg[1]*cocg[2] - cocg[4]*cocg[4];
9519 cs_real_t a01 = cocg[4]*cocg[5] - cocg[3]*cocg[2];
9520 cs_real_t a02 = cocg[3]*cocg[4] - cocg[1]*cocg[5];
9521 cs_real_t a11 = cocg[0]*cocg[2] - cocg[5]*cocg[5];
9522 cs_real_t a12 = cocg[3]*cocg[5] - cocg[0]*cocg[4];
9523 cs_real_t a22 = cocg[0]*cocg[1] - cocg[3]*cocg[3];
9524
9525 cs_real_t det_inv = 1. / (cocg[0]*a00 + cocg[3]*a01 + cocg[5]*a02);
9526
9527 grad[0] = ( a00 * rhsv[0]
9528 + a01 * rhsv[1]
9529 + a02 * rhsv[2]) * det_inv;
9530 grad[1] = ( a01 * rhsv[0]
9531 + a11 * rhsv[1]
9532 + a12 * rhsv[2]) * det_inv;
9533 grad[2] = ( a02 * rhsv[0]
9534 + a12 * rhsv[1]
9535 + a22 * rhsv[2]) * det_inv;
9536 }
9537
9538 /*----------------------------------------------------------------------------*/
9539 /*!
9540 * \brief Compute the gradient of a vector field at a given cell
9541 * using least-squares reconstruction.
9542 *
9543 * This assumes ghost cell values which might be used are already
9544 * synchronized.
9545 *
9546 * When boundary conditions are provided, both the bc_coeff_a and bc_coeff_b
9547 * arrays must be given. If boundary values are known, bc_coeff_a
9548 * can point to the boundary values array, and bc_coeff_b set to NULL.
9549 * If bc_coeff_a is NULL, bc_coeff_b is ignored.
9550 *
9551 * \param[in] m pointer to associated mesh structure
9552 * \param[in] fvq pointer to associated finite volume quantities
9553 * \param[in] c_id cell id
9554 * \param[in] halo_type halo type
9555 * \param[in] bc_coeff_a boundary condition term a, or NULL
9556 * \param[in] bc_coeff_b boundary condition term b, or NULL
9557 * \param[in] var gradient's base variable
9558 * \param[in] c_weight cell variable weight, or NULL
9559 * \param[out] grad gradient
9560 */
9561 /*----------------------------------------------------------------------------*/
9562
9563 void
cs_gradient_vector_cell(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_lnum_t c_id,cs_halo_type_t halo_type,const cs_real_t bc_coeff_a[][3],const cs_real_t bc_coeff_b[][3][3],const cs_real_t var[restrict][3],const cs_real_t c_weight[],cs_real_t grad[3][3])9564 cs_gradient_vector_cell(const cs_mesh_t *m,
9565 const cs_mesh_quantities_t *fvq,
9566 cs_lnum_t c_id,
9567 cs_halo_type_t halo_type,
9568 const cs_real_t bc_coeff_a[][3],
9569 const cs_real_t bc_coeff_b[][3][3],
9570 const cs_real_t var[restrict][3],
9571 const cs_real_t c_weight[],
9572 cs_real_t grad[3][3])
9573 {
9574 CS_UNUSED(m);
9575
9576 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
9577
9578 const cs_lnum_t *restrict cell_cells_idx
9579 = (const cs_lnum_t *restrict) ma->cell_cells_idx;
9580 const cs_lnum_t *restrict cell_cells_e_idx
9581 = (const cs_lnum_t *restrict) ma->cell_cells_e_idx;
9582 const cs_lnum_t *restrict cell_b_faces_idx
9583 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
9584 const cs_lnum_t *restrict cell_cells
9585 = (const cs_lnum_t *restrict) ma->cell_cells;
9586 const cs_lnum_t *restrict cell_cells_e
9587 = (const cs_lnum_t *restrict) ma->cell_cells_e;
9588 const cs_lnum_t *restrict cell_b_faces
9589 = (const cs_lnum_t *restrict) ma->cell_b_faces;
9590
9591 const cs_real_3_t *restrict cell_cen
9592 = (const cs_real_3_t *restrict)fvq->cell_cen;
9593
9594 /* Compute covariance matrix and Right-Hand Side */
9595
9596 cs_real_t cocg[3][3] = {{0., 0., 0.},
9597 {0., 0., 0.},
9598 {0., 0., 0.}};
9599 cs_real_t rhs[3][3] = {{0., 0., 0.},
9600 {0., 0., 0.},
9601 {0., 0., 0.}};
9602
9603 /* Contribution from interior and extended cells */
9604
9605 int n_adj = (halo_type == CS_HALO_EXTENDED) ? 2 : 1;
9606
9607 for (int adj_id = 0; adj_id < n_adj; adj_id++) {
9608
9609 const cs_lnum_t *restrict cell_cells_p;
9610 cs_lnum_t s_id, e_id;
9611
9612 if (adj_id == 0){
9613 s_id = cell_cells_idx[c_id];
9614 e_id = cell_cells_idx[c_id+1];
9615 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells);
9616 }
9617 else if (cell_cells_e_idx != NULL){
9618 s_id = cell_cells_e_idx[c_id];
9619 e_id = cell_cells_e_idx[c_id+1];
9620 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells_e);
9621 }
9622 else
9623 break;
9624
9625 if (c_weight == NULL) {
9626
9627 for (cs_lnum_t i = s_id; i < e_id; i++) {
9628
9629 cs_real_t dc[3];
9630 cs_lnum_t c_id1 = cell_cells_p[i];
9631 for (cs_lnum_t ii = 0; ii < 3; ii++)
9632 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9633
9634 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9635
9636 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9637
9638 cs_real_t pfac = (var[c_id1][kk] - var[c_id][kk]) * ddc;
9639
9640 for (cs_lnum_t ll = 0; ll < 3; ll++) {
9641 rhs[kk][ll] += dc[ll] * pfac;
9642 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9643 }
9644
9645 }
9646
9647 }
9648
9649 }
9650 else {
9651
9652 for (cs_lnum_t i = s_id; i < e_id; i++) {
9653
9654 cs_real_t dc[3];
9655 cs_lnum_t c_id1 = cell_cells_p[i];
9656 for (cs_lnum_t ii = 0; ii < 3; ii++)
9657 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9658
9659 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9660
9661 cs_real_t _weight = 2. * c_weight[c_id1]
9662 / (c_weight[c_id] + c_weight[c_id1]);
9663
9664 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9665
9666 cs_real_t pfac = (var[c_id1][kk] - var[c_id][kk]) * ddc;
9667
9668 for (cs_lnum_t ll = 0; ll < 3; ll++) {
9669 rhs[kk][ll] += dc[ll] * pfac * _weight;
9670 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9671 }
9672
9673 }
9674
9675 }
9676 }
9677
9678 } /* end of contribution from interior and extended cells */
9679
9680 /* Contribution from boundary conditions */
9681
9682 cs_lnum_t s_id = cell_b_faces_idx[c_id];
9683 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
9684
9685 if (e_id > s_id && bc_coeff_a != NULL && bc_coeff_b != NULL) {
9686
9687 for (cs_lnum_t i = s_id; i < e_id; i++) {
9688
9689 const cs_real_3_t *restrict b_face_normal
9690 = (const cs_real_3_t *restrict)fvq->b_face_normal;
9691 const cs_real_t *restrict b_dist
9692 = (const cs_real_t *restrict)fvq->b_dist;
9693
9694 cs_lnum_t f_id = cell_b_faces[i];
9695
9696 cs_real_t n_d_dist[3];
9697 /* Normal is vector 0 if the b_face_normal norm is too small */
9698 cs_math_3_normalise(b_face_normal[f_id], n_d_dist);
9699
9700 for (cs_lnum_t ii = 0; ii < 3; ii++) {
9701 for (cs_lnum_t jj = 0; jj < 3; jj++)
9702 cocg[ii][jj] += n_d_dist[ii] * n_d_dist[jj];
9703 }
9704
9705 cs_real_t d_b_dist = 1. / b_dist[f_id];
9706
9707 /* Normal divided by b_dist */
9708 for (cs_lnum_t j = 0; j < 3; j++)
9709 n_d_dist[j] *= d_b_dist;
9710
9711 for (cs_lnum_t j = 0; j < 3; j++) {
9712 cs_real_t pfac = bc_coeff_a[f_id][j]
9713 + ( bc_coeff_b[f_id][0][j] * var[c_id][0]
9714 + bc_coeff_b[f_id][1][j] * var[c_id][1]
9715 + bc_coeff_b[f_id][2][j] * var[c_id][2]
9716 - var[c_id][j]);
9717
9718 for (cs_lnum_t k = 0; k < 3; k++)
9719 rhs[j][k] += n_d_dist[k] * pfac;
9720 }
9721
9722 }
9723
9724 /* Build indices bijection between [1-9] and [1-3]*[1-3] */
9725 cs_lnum_t _33_9_idx[9][2];
9726 int nn = 0;
9727 for (int ll = 0; ll < 3; ll++) {
9728 for (int mm = 0; mm < 3; mm++) {
9729 _33_9_idx[nn][0] = ll;
9730 _33_9_idx[nn][1] = mm;
9731 nn++;
9732 }
9733 }
9734
9735 cs_real_t cocgb_v[45], rhsb_v[9], x[9];
9736
9737 _compute_cocgb_rhsb_lsq_v(c_id,
9738 1,
9739 ma,
9740 fvq,
9741 _33_9_idx,
9742 (const cs_real_3_t *)var,
9743 (const cs_real_3_t *)bc_coeff_a,
9744 (const cs_real_33_t *)bc_coeff_b,
9745 (const cs_real_3_t *)cocg,
9746 (const cs_real_3_t *)rhs,
9747 cocgb_v,
9748 rhsb_v);
9749
9750 _fw_and_bw_ldtl_pp(cocgb_v,
9751 9,
9752 x,
9753 rhsb_v);
9754
9755 for (int kk = 0; kk < 9; kk++) {
9756 int ii = _33_9_idx[kk][0];
9757 int jj = _33_9_idx[kk][1];
9758 grad[ii][jj] = x[kk];
9759 }
9760 }
9761
9762 /* Case with no boundary conditions or known face values */
9763
9764 else {
9765
9766 if (bc_coeff_a != NULL) {
9767
9768 for (cs_lnum_t i = s_id; i < e_id; i++) {
9769
9770 const cs_real_3_t *restrict b_face_cog
9771 = (const cs_real_3_t *restrict)fvq->b_face_cog;
9772
9773 cs_lnum_t f_id = cell_b_faces[i];
9774
9775 cs_real_t dc[3];
9776 for (cs_lnum_t ii = 0; ii < 3; ii++)
9777 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
9778
9779 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9780
9781 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9782
9783 cs_real_t pfac = (bc_coeff_a[f_id][kk] - var[c_id][kk]) * ddc;
9784
9785 for (cs_lnum_t ll = 0; ll < 3; ll++) {
9786 rhs[kk][ll] += dc[ll] * pfac;
9787 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9788 }
9789
9790 }
9791
9792 }
9793
9794 }
9795
9796 else { /* if bc_coeff_a == NUL
9797 use homogeneous Neumann BC; as above, but
9798 pfac and RHS contribution become zero */
9799
9800 for (cs_lnum_t i = s_id; i < e_id; i++) {
9801
9802 const cs_real_3_t *restrict b_face_cog
9803 = (const cs_real_3_t *restrict)fvq->b_face_cog;
9804
9805 cs_lnum_t f_id = cell_b_faces[i];
9806
9807 cs_real_t dc[3];
9808 for (cs_lnum_t ii = 0; ii < 3; ii++)
9809 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
9810
9811 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9812
9813 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9814 for (cs_lnum_t ll = 0; ll < 3; ll++)
9815 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9816 }
9817
9818 }
9819
9820 }
9821
9822 /* Invert */
9823
9824 cs_math_33_inv_cramer_in_place(cocg);
9825
9826 for (cs_lnum_t jj = 0; jj < 3; jj++) {
9827 for (cs_lnum_t ii = 0; ii < 3; ii++) {
9828 grad[ii][jj] = 0.0;
9829 for (cs_lnum_t k = 0; k < 3; k++)
9830 grad[ii][jj] += rhs[ii][k] * cocg[k][jj];
9831
9832 }
9833 }
9834 }
9835
9836 }
9837
9838 /*----------------------------------------------------------------------------*/
9839 /*!
9840 * \brief Compute the gradient of a tensor field at a given cell
9841 * using least-squares reconstruction.
9842 *
9843 * This assumes ghost cell values which might be used are already
9844 * synchronized.
9845 *
9846 * When boundary conditions are provided, both the bc_coeff_a and bc_coeff_b
9847 * arrays must be given. If boundary values are known, bc_coeff_a
9848 * can point to the boundary values array, and bc_coeff_b set to NULL.
9849 * If bc_coeff_a is NULL, bc_coeff_b is ignored.
9850 *
9851 * \param[in] m pointer to associated mesh structure
9852 * \param[in] fvq pointer to associated finite volume quantities
9853 * \param[in] c_id cell id
9854 * \param[in] halo_type halo type
9855 * \param[in] bc_coeff_a boundary condition term a, or NULL
9856 * \param[in] bc_coeff_b boundary condition term b, or NULL
9857 * \param[in] var gradient's base variable
9858 * \param[in] c_weight cell variable weight, or NULL
9859 * \param[out] grad gradient
9860 */
9861 /*----------------------------------------------------------------------------*/
9862
9863 void
cs_gradient_tensor_cell(const cs_mesh_t * m,const cs_mesh_quantities_t * fvq,cs_lnum_t c_id,cs_halo_type_t halo_type,const cs_real_t bc_coeff_a[][6],const cs_real_t bc_coeff_b[][6][6],const cs_real_t var[restrict][6],const cs_real_t c_weight[],cs_real_t grad[6][3])9864 cs_gradient_tensor_cell(const cs_mesh_t *m,
9865 const cs_mesh_quantities_t *fvq,
9866 cs_lnum_t c_id,
9867 cs_halo_type_t halo_type,
9868 const cs_real_t bc_coeff_a[][6],
9869 const cs_real_t bc_coeff_b[][6][6],
9870 const cs_real_t var[restrict][6],
9871 const cs_real_t c_weight[],
9872 cs_real_t grad[6][3])
9873 {
9874 CS_UNUSED(m);
9875
9876 const cs_mesh_adjacencies_t *ma = cs_glob_mesh_adjacencies;
9877
9878 const cs_lnum_t *restrict cell_cells_idx
9879 = (const cs_lnum_t *restrict) ma->cell_cells_idx;
9880 const cs_lnum_t *restrict cell_cells_e_idx
9881 = (const cs_lnum_t *restrict) ma->cell_cells_e_idx;
9882 const cs_lnum_t *restrict cell_b_faces_idx
9883 = (const cs_lnum_t *restrict) ma->cell_b_faces_idx;
9884 const cs_lnum_t *restrict cell_cells
9885 = (const cs_lnum_t *restrict) ma->cell_cells;
9886 const cs_lnum_t *restrict cell_cells_e
9887 = (const cs_lnum_t *restrict) ma->cell_cells_e;
9888 const cs_lnum_t *restrict cell_b_faces
9889 = (const cs_lnum_t *restrict) ma->cell_b_faces;
9890
9891 const cs_real_3_t *restrict cell_cen
9892 = (const cs_real_3_t *restrict)fvq->cell_cen;
9893
9894 /* Compute covariance matrix and Right-Hand Side */
9895
9896 cs_real_t cocg[3][3] = {{0., 0., 0.},
9897 {0., 0., 0.},
9898 {0., 0., 0.}};
9899 cs_real_t rhs[6][3] = {{0., 0., 0.}, {0., 0., 0.},
9900 {0., 0., 0.}, {0., 0., 0.},
9901 {0., 0., 0.}, {0., 0., 0.}};
9902
9903 /* Contribution from interior and extended cells */
9904
9905 int n_adj = (halo_type == CS_HALO_EXTENDED) ? 2 : 1;
9906
9907 for (int adj_id = 0; adj_id < n_adj; adj_id++) {
9908
9909 const cs_lnum_t *restrict cell_cells_p;
9910 cs_lnum_t s_id, e_id;
9911
9912 if (adj_id == 0){
9913 s_id = cell_cells_idx[c_id];
9914 e_id = cell_cells_idx[c_id+1];
9915 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells);
9916 }
9917 else if (cell_cells_e_idx != NULL){
9918 s_id = cell_cells_e_idx[c_id];
9919 e_id = cell_cells_e_idx[c_id+1];
9920 cell_cells_p = (const cs_lnum_t *restrict)(cell_cells_e);
9921 }
9922 else
9923 break;
9924
9925 if (c_weight == NULL) {
9926
9927 for (cs_lnum_t i = s_id; i < e_id; i++) {
9928
9929 cs_real_t dc[3];
9930 cs_lnum_t c_id1 = cell_cells_p[i];
9931 for (cs_lnum_t ii = 0; ii < 3; ii++)
9932 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9933
9934 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9935
9936 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9937 for (cs_lnum_t ll = 0; ll < 3; ll++)
9938 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9939 }
9940
9941 for (cs_lnum_t kk = 0; kk < 6; kk++) {
9942 cs_real_t pfac = (var[c_id1][kk] - var[c_id][kk]) * ddc;
9943 for (cs_lnum_t ll = 0; ll < 3; ll++)
9944 rhs[kk][ll] += dc[ll] * pfac;
9945 }
9946
9947 }
9948
9949 }
9950 else {
9951
9952 for (cs_lnum_t i = s_id; i < e_id; i++) {
9953
9954 cs_real_t dc[3];
9955 cs_lnum_t c_id1 = cell_cells_p[i];
9956 for (cs_lnum_t ii = 0; ii < 3; ii++)
9957 dc[ii] = cell_cen[c_id1][ii] - cell_cen[c_id][ii];
9958
9959 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
9960
9961 cs_real_t _weight = 2. * c_weight[c_id1]
9962 / (c_weight[c_id] + c_weight[c_id1]);
9963
9964 for (cs_lnum_t kk = 0; kk < 3; kk++) {
9965 for (cs_lnum_t ll = 0; ll < 3; ll++)
9966 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
9967 }
9968
9969 for (cs_lnum_t kk = 0; kk < 6; kk++) {
9970 cs_real_t pfac = (var[c_id1][kk] - var[c_id][kk]) * ddc;
9971 for (cs_lnum_t ll = 0; ll < 3; ll++)
9972 rhs[kk][ll] += dc[ll] * pfac * _weight;
9973 }
9974
9975 }
9976 }
9977
9978 } /* end of contribution from interior and extended cells */
9979
9980 /* Contribution from boundary conditions */
9981
9982 cs_lnum_t s_id = cell_b_faces_idx[c_id];
9983 cs_lnum_t e_id = cell_b_faces_idx[c_id+1];
9984
9985 if (e_id > s_id && bc_coeff_a != NULL && bc_coeff_b != NULL) {
9986
9987 for (cs_lnum_t i = s_id; i < e_id; i++) {
9988
9989 const cs_real_3_t *restrict b_face_normal
9990 = (const cs_real_3_t *restrict)fvq->b_face_normal;
9991 const cs_real_t *restrict b_dist
9992 = (const cs_real_t *restrict)fvq->b_dist;
9993
9994 cs_lnum_t f_id = cell_b_faces[i];
9995
9996 cs_real_t n_d_dist[3];
9997 /* Normal is vector 0 if the b_face_normal norm is too small */
9998 cs_math_3_normalise(b_face_normal[f_id], n_d_dist);
9999
10000 for (cs_lnum_t ii = 0; ii < 3; ii++) {
10001 for (cs_lnum_t jj = 0; jj < 3; jj++)
10002 cocg[ii][jj] += n_d_dist[ii] * n_d_dist[jj];
10003 }
10004
10005 cs_real_t d_b_dist = 1. / b_dist[f_id];
10006
10007 /* Normal divided by b_dist */
10008 for (cs_lnum_t j = 0; j < 3; j++)
10009 n_d_dist[j] *= d_b_dist;
10010
10011 for (cs_lnum_t k = 0; k < 6; k++) {
10012 cs_real_t pfac = bc_coeff_a[f_id][k] - var[c_id][k];
10013 for (cs_lnum_t j = 0; j < 6; j++)
10014 pfac += bc_coeff_b[f_id][j][k] * var[c_id][j];
10015
10016 for (cs_lnum_t j = 0; j < 3; j++)
10017 rhs[k][j] += pfac * n_d_dist[j];
10018 }
10019
10020 }
10021
10022 /* Build indices bijection between [1-18] and [1-6]*[1-3] */
10023 cs_lnum_t _63_18_idx[18][2];
10024 cs_lnum_t nn = 0;
10025 for (cs_lnum_t ll = 0; ll < 6; ll++) {
10026 for (cs_lnum_t mm = 0; mm < 3; mm++) {
10027 _63_18_idx[nn][0] = ll;
10028 _63_18_idx[nn][1] = mm;
10029 nn++;
10030 }
10031 }
10032
10033 cs_real_t cocgb_t[171], rhsb_t[18], x[18];
10034
10035 _compute_cocgb_rhsb_lsq_t(c_id,
10036 1,
10037 ma,
10038 fvq,
10039 _63_18_idx,
10040 (const cs_real_6_t *)var,
10041 (const cs_real_6_t *)bc_coeff_a,
10042 (const cs_real_66_t *)bc_coeff_b,
10043 (const cs_real_3_t *)cocg,
10044 (const cs_real_3_t *)rhs,
10045 cocgb_t,
10046 rhsb_t);
10047
10048 _fw_and_bw_ldtl_pp(cocgb_t,
10049 18,
10050 x,
10051 rhsb_t);
10052
10053 for (int kk = 0; kk < 18; kk++) {
10054 int ii = _63_18_idx[kk][0];
10055 int jj = _63_18_idx[kk][1];
10056 grad[ii][jj] = x[kk];
10057 }
10058
10059 }
10060
10061 /* Case with no boundary conditions or known face values */
10062
10063 else {
10064
10065 if (bc_coeff_a != NULL) {
10066
10067 for (cs_lnum_t i = s_id; i < e_id; i++) {
10068
10069 const cs_real_3_t *restrict b_face_cog
10070 = (const cs_real_3_t *restrict)fvq->b_face_cog;
10071
10072 cs_lnum_t f_id = cell_b_faces[i];
10073
10074 cs_real_t dc[3];
10075 for (cs_lnum_t ii = 0; ii < 3; ii++)
10076 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
10077
10078 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
10079
10080 for (cs_lnum_t kk = 0; kk < 3; kk++) {
10081 for (cs_lnum_t ll = 0; ll < 3; ll++)
10082 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
10083 }
10084
10085 for (cs_lnum_t kk = 0; kk < 6; kk++) {
10086 cs_real_t pfac = (bc_coeff_a[f_id][kk] - var[c_id][kk]) * ddc;
10087 for (cs_lnum_t ll = 0; ll < 3; ll++)
10088 rhs[kk][ll] += dc[ll] * pfac;
10089 }
10090
10091 }
10092
10093 }
10094
10095 else { /* Use homogeneous Neumann;
10096 pfac and RHS contribution cancel out */
10097
10098 for (cs_lnum_t i = s_id; i < e_id; i++) {
10099
10100 const cs_real_3_t *restrict b_face_cog
10101 = (const cs_real_3_t *restrict)fvq->b_face_cog;
10102
10103 cs_lnum_t f_id = cell_b_faces[i];
10104
10105 cs_real_t dc[3];
10106 for (cs_lnum_t ii = 0; ii < 3; ii++)
10107 dc[ii] = b_face_cog[f_id][ii] - cell_cen[c_id][ii];
10108
10109 cs_real_t ddc = 1. / (dc[0]*dc[0] + dc[1]*dc[1] + dc[2]*dc[2]);
10110
10111 for (cs_lnum_t kk = 0; kk < 3; kk++) {
10112 for (cs_lnum_t ll = 0; ll < 3; ll++)
10113 cocg[kk][ll] += dc[kk]*dc[ll]*ddc;
10114 }
10115
10116 }
10117
10118 }
10119
10120 /* Invert */
10121
10122 cs_math_33_inv_cramer_in_place(cocg);
10123
10124 for (cs_lnum_t jj = 0; jj < 3; jj++) {
10125 for (cs_lnum_t ii = 0; ii < 6; ii++) {
10126 grad[ii][jj] = 0.0;
10127 for (cs_lnum_t k = 0; k < 3; k++)
10128 grad[ii][jj] += rhs[ii][k] * cocg[k][jj];
10129
10130 }
10131 }
10132 }
10133
10134 }
10135
10136 /*----------------------------------------------------------------------------
10137 * Determine gradient type by Fortran "imrgra" value
10138 *
10139 * parameters:
10140 * imrgra <-- Fortran gradient option
10141 * gradient_type --> gradient type
10142 * halo_type --> halo type
10143 *----------------------------------------------------------------------------*/
10144
10145 void
cs_gradient_type_by_imrgra(int imrgra,cs_gradient_type_t * gradient_type,cs_halo_type_t * halo_type)10146 cs_gradient_type_by_imrgra(int imrgra,
10147 cs_gradient_type_t *gradient_type,
10148 cs_halo_type_t *halo_type)
10149 {
10150 *halo_type = CS_HALO_STANDARD;
10151 *gradient_type = CS_GRADIENT_GREEN_ITER;
10152
10153 switch (imrgra) {
10154 case 0:
10155 *gradient_type = CS_GRADIENT_GREEN_ITER;
10156 break;
10157 case 1:
10158 *gradient_type = CS_GRADIENT_LSQ;
10159 break;
10160 case 2:
10161 case 3:
10162 *gradient_type = CS_GRADIENT_LSQ;
10163 *halo_type = CS_HALO_EXTENDED;
10164 break;
10165 case 4:
10166 *gradient_type = CS_GRADIENT_GREEN_LSQ;
10167 break;
10168 case 5:
10169 case 6:
10170 *gradient_type = CS_GRADIENT_GREEN_LSQ;
10171 *halo_type = CS_HALO_EXTENDED;
10172 break;
10173 case 7:
10174 *gradient_type = CS_GRADIENT_GREEN_VTX;
10175 break;
10176 default:
10177 *gradient_type = CS_GRADIENT_GREEN_ITER;
10178 break;
10179 }
10180 }
10181
10182 /*----------------------------------------------------------------------------*/
10183 /*!
10184 * \brief compute the steady balance due to porous modelling for the pressure
10185 * gradient.
10186 *
10187 * \param[in] inc if 0, solve on increment; 1 otherwise
10188 */
10189 /*----------------------------------------------------------------------------*/
10190
10191 void
cs_gradient_porosity_balance(int inc)10192 cs_gradient_porosity_balance(int inc)
10193 {
10194 const cs_mesh_t *m = cs_glob_mesh;
10195 cs_mesh_quantities_t *mq = cs_glob_mesh_quantities;
10196 const cs_halo_t *halo = m->halo;
10197
10198 const cs_real_t *restrict cell_f_vol = mq->cell_f_vol;
10199 cs_real_2_t *i_f_face_factor = mq->i_f_face_factor;
10200 cs_real_t *b_f_face_factor = mq->b_f_face_factor;
10201 cs_real_t *i_massflux = cs_field_by_name("inner_mass_flux")->val;
10202 cs_real_t *b_massflux = cs_field_by_name("boundary_mass_flux")->val;
10203 const cs_real_3_t *restrict i_face_normal
10204 = (const cs_real_3_t *restrict)mq->i_face_normal;
10205 const cs_real_3_t *restrict i_f_face_normal
10206 = (const cs_real_3_t *restrict)mq->i_f_face_normal;
10207 const cs_real_3_t *restrict b_face_normal
10208 = (const cs_real_3_t *restrict)mq->b_face_normal;
10209 const cs_real_3_t *restrict b_f_face_normal
10210 = (const cs_real_3_t *restrict)mq->b_f_face_normal;
10211 const cs_lnum_2_t *restrict i_face_cells
10212 = (const cs_lnum_2_t *restrict)m->i_face_cells;
10213 const cs_lnum_t *restrict b_face_cells
10214 = (const cs_lnum_t *restrict)m->b_face_cells;
10215 const cs_real_t *restrict i_f_face_surf = mq->i_f_face_surf;
10216 const cs_real_t *restrict i_face_surf = mq->i_face_surf;
10217 const cs_real_t *restrict b_f_face_surf = mq->b_f_face_surf;
10218 const cs_real_t *restrict b_face_surf = mq->b_face_surf;
10219
10220 const int *restrict c_disable_flag = mq->c_disable_flag;
10221 cs_lnum_t has_dc = mq->has_disable_flag; /* Has cells disabled? */
10222
10223 const cs_lnum_t n_cells_ext = m->n_cells_with_ghosts;
10224 const cs_lnum_t n_cells = m->n_cells;
10225
10226 const int n_i_groups = m->i_face_numbering->n_groups;
10227 const int n_i_threads = m->i_face_numbering->n_threads;
10228 const int n_b_groups = m->b_face_numbering->n_groups;
10229 const int n_b_threads = m->b_face_numbering->n_threads;
10230 const cs_lnum_t *restrict i_group_index = m->i_face_numbering->group_index;
10231 const cs_lnum_t *restrict b_group_index = m->b_face_numbering->group_index;
10232
10233 /*Additional terms due to porosity */
10234 cs_field_t *f_i_poro_duq_0 = cs_field_by_name_try("i_poro_duq_0");
10235
10236 if (f_i_poro_duq_0 == NULL)
10237 return;
10238
10239 cs_real_t *i_poro_duq_0 = f_i_poro_duq_0->val;
10240 cs_real_t *i_poro_duq_1 = cs_field_by_name("i_poro_duq_1")->val;
10241 cs_real_t *b_poro_duq = cs_field_by_name("b_poro_duq")->val;
10242 cs_real_3_t *c_poro_div_duq
10243 = (cs_real_3_t *restrict)cs_field_by_name("poro_div_duq")->val;
10244
10245 # pragma omp parallel for
10246 for (cs_lnum_t c_id = 0; c_id < n_cells_ext; c_id++) {
10247 for (cs_lnum_t i = 0; i < 3; i++)
10248 c_poro_div_duq[c_id][i] = 0.;
10249 }
10250
10251 if (inc == 1) {
10252
10253 /* Inner faces corrections */
10254 for (int g_id = 0; g_id < n_i_groups; g_id++) {
10255
10256 # pragma omp parallel for
10257 for (int t_id = 0; t_id < n_i_threads; t_id++) {
10258
10259 for (cs_lnum_t f_id = i_group_index[(t_id*n_i_groups + g_id)*2];
10260 f_id < i_group_index[(t_id*n_i_groups + g_id)*2 + 1];
10261 f_id++) {
10262
10263 cs_lnum_t ii = i_face_cells[f_id][0];
10264 cs_lnum_t jj = i_face_cells[f_id][1];
10265
10266 cs_real_3_t normal;
10267
10268 cs_math_3_normalise(i_face_normal[f_id], normal);
10269
10270 cs_real_t *vel_i = &(CS_F_(vel)->val_pre[3*ii]);
10271 cs_real_t *vel_j = &(CS_F_(vel)->val_pre[3*jj]);
10272
10273 cs_real_t veli_dot_n = (1. - i_f_face_factor[f_id][0])
10274 * cs_math_3_dot_product(vel_i, normal);
10275 cs_real_t velj_dot_n = (1. - i_f_face_factor[f_id][1])
10276 * cs_math_3_dot_product(vel_j, normal);
10277
10278 cs_real_t d_f_surf = 0.;
10279 /* Is the cell disabled (for solid or porous)?
10280 Not the case if coupled */
10281 if ( has_dc * c_disable_flag[has_dc * ii] == 0
10282 && has_dc * c_disable_flag[has_dc * jj] == 0)
10283 d_f_surf = 1. / CS_MAX(i_f_face_surf[f_id],
10284 cs_math_epzero * i_face_surf[f_id]);
10285
10286 i_poro_duq_0[f_id] = veli_dot_n * i_massflux[f_id] * d_f_surf;
10287 i_poro_duq_1[f_id] = velj_dot_n * i_massflux[f_id] * d_f_surf;
10288
10289 for (cs_lnum_t i = 0; i < 3; i++) {
10290 c_poro_div_duq[ii][i] += i_poro_duq_0[f_id]
10291 * i_f_face_normal[f_id][i];
10292 c_poro_div_duq[jj][i] -= i_poro_duq_1[f_id]
10293 * i_f_face_normal[f_id][i];
10294 }
10295 }
10296 }
10297
10298 }
10299
10300 /* Boundary faces corrections */
10301 for (int g_id = 0; g_id < n_b_groups; g_id++) {
10302
10303 # pragma omp parallel for
10304 for (int t_id = 0; t_id < n_b_threads; t_id++) {
10305
10306 for (cs_lnum_t f_id = b_group_index[(t_id*n_b_groups + g_id)*2];
10307 f_id < b_group_index[(t_id*n_b_groups + g_id)*2 + 1];
10308 f_id++) {
10309
10310 cs_lnum_t ii = b_face_cells[f_id];
10311
10312 cs_real_3_t normal;
10313
10314 cs_math_3_normalise(b_face_normal[f_id], normal);
10315
10316 cs_real_t *vel_i = &(CS_F_(vel)->val_pre[3*ii]);
10317
10318 cs_real_t veli_dot_n = (1. - b_f_face_factor[f_id])
10319 * cs_math_3_dot_product(vel_i, normal);
10320
10321 cs_real_t d_f_surf = 0.;
10322 /* Is the cell disabled (for solid or porous)?
10323 Not the case if coupled */
10324 if (has_dc * c_disable_flag[has_dc * ii] == 0)
10325 d_f_surf = 1. / CS_MAX(b_f_face_surf[f_id],
10326 cs_math_epzero * b_face_surf[f_id]);
10327
10328 b_poro_duq[f_id] = veli_dot_n * b_massflux[f_id] * d_f_surf;
10329
10330 for (cs_lnum_t i = 0; i < 3; i++)
10331 c_poro_div_duq[ii][i] += b_poro_duq[f_id]
10332 * b_f_face_normal[f_id][i];
10333 }
10334
10335 /* Finalisation of cell terms */
10336 for (cs_lnum_t c_id = 0; c_id < n_cells; c_id++) {
10337 /* Is the cell disabled (for solid or porous)?
10338 Not the case if coupled */
10339 cs_real_t dvol = 0.;
10340 if (has_dc * c_disable_flag[has_dc * c_id] == 0)
10341 dvol = 1. / cell_f_vol[c_id];
10342
10343 for (cs_lnum_t i = 0; i < 3; i++)
10344 c_poro_div_duq[c_id][i] *= dvol;
10345 }
10346 }
10347 }
10348
10349 /* Handle parallelism and periodicity */
10350 if (halo != NULL)
10351 cs_halo_sync_var_strided(halo,
10352 CS_HALO_STANDARD,
10353 (cs_real_t *)c_poro_div_duq,
10354 3);
10355
10356 }
10357 else {
10358 # pragma omp parallel for
10359 for (cs_lnum_t f_id = 0; f_id < m->n_i_faces; f_id++) {
10360 i_poro_duq_0[f_id] = 0.;
10361 i_poro_duq_1[f_id] = 0.;
10362 }
10363
10364 }
10365 }
10366
10367 /*----------------------------------------------------------------------------*/
10368
10369 END_C_DECLS
10370