1 /*============================================================================
2  * Manage the enforcement of values at interior degrees of freedom (DoFs) and
3  * associated helper functions
4  *============================================================================*/
5 
6 /*
7   This file is part of Code_Saturne, a general-purpose CFD tool.
8 
9   Copyright (C) 1998-2021 EDF S.A.
10 
11   This program is free software; you can redistribute it and/or modify it under
12   the terms of the GNU General Public License as published by the Free Software
13   Foundation; either version 2 of the License, or (at your option) any later
14   version.
15 
16   This program is distributed in the hope that it will be useful, but WITHOUT
17   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19   details.
20 
21   You should have received a copy of the GNU General Public License along with
22   this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
23   Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 */
25 
26 /*----------------------------------------------------------------------------*/
27 
28 #include "cs_defs.h"
29 
30 /*----------------------------------------------------------------------------
31  * Standard C library headers
32  *----------------------------------------------------------------------------*/
33 
34 #include <assert.h>
35 #include <string.h>
36 #include <float.h>
37 
38 /*----------------------------------------------------------------------------
39  *  Local headers
40  *----------------------------------------------------------------------------*/
41 
42 #include <bft_mem.h>
43 
44 #include "cs_cdo_bc.h"
45 #include "cs_parall.h"
46 
47 /*----------------------------------------------------------------------------
48  * Header for the current file
49  *----------------------------------------------------------------------------*/
50 
51 #include "cs_enforcement.h"
52 
53 /*----------------------------------------------------------------------------*/
54 
55 BEGIN_C_DECLS
56 
57 /*=============================================================================
58  * Additional doxygen documentation
59  *============================================================================*/
60 
61 /*!
62   \file cs_enforcement.c
63 
64   \brief Structure and functions handling the way to enforce interior degrees
65          of freedom.
66 */
67 
68 /*=============================================================================
69  * Local macro definitions
70  *============================================================================*/
71 
72 #define CS_ENFORCEMENT_DBG       0
73 
74 /*============================================================================
75  * Type definitions
76  *============================================================================*/
77 
78 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
79 
80 /*============================================================================
81  * Static variables
82  *============================================================================*/
83 
84 /*============================================================================
85  * Private function prototypes
86  *============================================================================*/
87 
88 /*============================================================================
89  * Public function prototypes
90  *============================================================================*/
91 
92 /*----------------------------------------------------------------------------*/
93 /*!
94  * \brief  Create and define a cs_enforcement_param_t structure
95  *
96  * \param[in] sel_type   type of elements which have been selected
97  * \param[in] type       way to set values for the selected elements
98  * \param[in] stride     number of values to enforce by element
99  * \param[in] n_elts     number of selected elements locally
100  * \param[in] elt_ids    list of element ids
101  * \param[in] values     array of values to enforce
102  *
103  * \return a pointer to a cs_enforcement_param_t structure
104  */
105 /*----------------------------------------------------------------------------*/
106 
107 cs_enforcement_param_t *
cs_enforcement_param_create(cs_enforcement_selection_t sel_type,cs_enforcement_type_t type,int stride,cs_lnum_t n_elts,const cs_lnum_t * elt_ids,const cs_real_t * values)108 cs_enforcement_param_create(cs_enforcement_selection_t    sel_type,
109                             cs_enforcement_type_t         type,
110                             int                           stride,
111                             cs_lnum_t                     n_elts,
112                             const cs_lnum_t              *elt_ids,
113                             const cs_real_t              *values)
114 {
115   cs_enforcement_param_t  *efp = NULL;
116 
117   BFT_MALLOC(efp, 1, cs_enforcement_param_t);
118 
119   efp->selection_type = sel_type;
120   efp->type = type;
121   efp->stride = stride;
122   efp->n_elts = n_elts;
123 
124   if (n_elts > 0 && values == NULL)
125     bft_error(__FILE__, __LINE__, 0,
126               "%s: No value for the enforcement\n", __func__);
127 
128   BFT_MALLOC(efp->elt_ids, n_elts, cs_lnum_t);
129   memcpy(efp->elt_ids, elt_ids, n_elts*sizeof(cs_lnum_t));
130 
131   switch (type) {
132 
133   case CS_ENFORCEMENT_BY_CONSTANT:
134     BFT_MALLOC(efp->values, efp->stride, cs_real_t);
135     for (int k = 0; k < stride; k++)
136       efp->values[k] = values[k];
137     break;
138 
139   case CS_ENFORCEMENT_BY_DOF_VALUES:
140     BFT_MALLOC(efp->values, stride*n_elts, cs_real_t);
141     memcpy(efp->values, values, stride*n_elts*sizeof(cs_real_t));
142     break;
143 
144   default:
145     bft_error(__FILE__, __LINE__, 0,
146               "%s: Undefined way to enforce values for interior DoFs\n",
147               __func__);
148 
149   }
150 
151   return efp;
152 }
153 
154 /*----------------------------------------------------------------------------*/
155 /*!
156  * \brief  Copy a cs_enforcement_param_t structure
157  *
158  * \param[in] ref    reference structure to copy
159  *
160  * \return a pointer to a cs_enforcement_param_t structure
161  */
162 /*----------------------------------------------------------------------------*/
163 
164 cs_enforcement_param_t *
cs_enforcement_param_copy(const cs_enforcement_param_t * ref)165 cs_enforcement_param_copy(const cs_enforcement_param_t   *ref)
166 {
167   cs_enforcement_param_t  *dst = NULL;
168 
169   if (ref == NULL)
170     return dst;
171 
172   dst =  cs_enforcement_param_create(ref->selection_type,
173                                      ref->type,
174                                      ref->stride,
175                                      ref->n_elts,
176                                      ref->elt_ids,
177                                      ref->values);
178 
179   return dst;
180 }
181 
182 /*----------------------------------------------------------------------------*/
183 /*!
184  * \brief  Free a cs_enforcement_param_t structure
185  *
186  * \param[in, out] p_efp    double pointer to the structure to free
187  */
188 /*----------------------------------------------------------------------------*/
189 
190 void
cs_enforcement_param_free(cs_enforcement_param_t ** p_efp)191 cs_enforcement_param_free(cs_enforcement_param_t   **p_efp)
192 {
193   if (p_efp == NULL)
194     return;
195 
196   cs_enforcement_param_t  *efp = *p_efp;
197 
198   if (efp == NULL)
199     return;
200 
201   BFT_FREE(efp->elt_ids);
202   BFT_FREE(efp->values);
203 
204   BFT_FREE(efp);
205   *p_efp = NULL;
206 }
207 
208 /*----------------------------------------------------------------------------*/
209 /*!
210  * \brief  Log a cs_enforcement_param_t structure
211  *
212  * \param[in] eqname  name of the related equation
213  * \param[in] efp     pointer to a  cs_enforcement_param_t structure
214  */
215 /*----------------------------------------------------------------------------*/
216 
217 void
cs_enforcement_param_log(const char * eqname,const cs_enforcement_param_t * efp)218 cs_enforcement_param_log(const char                     *eqname,
219                          const cs_enforcement_param_t   *efp)
220 {
221   if (efp == NULL)
222     return;
223 
224   if (efp->type == CS_ENFORCEMENT_BY_CONSTANT) {
225 
226     switch (efp->selection_type) {
227 
228     case CS_ENFORCEMENT_SELECTION_CELLS:
229       cs_log_printf(CS_LOG_SETUP, "  * %s |   Cell selection | Constant value:",
230                     eqname);
231       break;
232 
233     case CS_ENFORCEMENT_SELECTION_FACES:
234       cs_log_printf(CS_LOG_SETUP, "  * %s |   Face selection | Constant value:",
235                     eqname);
236       break;
237 
238     case CS_ENFORCEMENT_SELECTION_EDGES:
239       cs_log_printf(CS_LOG_SETUP, "  * %s |   Edge selection | Constant value:",
240                     eqname);
241       break;
242 
243     case CS_ENFORCEMENT_SELECTION_VERTICES:
244       cs_log_printf(CS_LOG_SETUP, "  * %s | Vertex selection | Constant value:",
245                     eqname);
246       break;
247 
248     default:
249       bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of selection.",
250                 __func__);
251 
252     } /* Switch on selection type */
253 
254     for (int i = 0; i < efp->stride; i++)
255       cs_log_printf(CS_LOG_SETUP, " % -6.3e", efp->values[i]);
256     cs_log_printf(CS_LOG_SETUP, "\n");
257 
258   }
259   else if (efp->type == CS_ENFORCEMENT_BY_DOF_VALUES) {
260 
261     switch (efp->selection_type) {
262 
263     case CS_ENFORCEMENT_SELECTION_CELLS:
264       cs_log_printf(CS_LOG_SETUP, "  * %s |   Cell selection | By DoF values\n",
265                     eqname);
266       break;
267 
268     case CS_ENFORCEMENT_SELECTION_FACES:
269       cs_log_printf(CS_LOG_SETUP, "  * %s |   Face selection | By DoF values\n",
270                     eqname);
271       break;
272 
273     case CS_ENFORCEMENT_SELECTION_EDGES:
274       cs_log_printf(CS_LOG_SETUP, "  * %s |   Edge selection | By DoF values\n",
275                     eqname);
276       break;
277 
278     case CS_ENFORCEMENT_SELECTION_VERTICES:
279       cs_log_printf(CS_LOG_SETUP, "  * %s | Vertex selection | By DoF values\n",
280                     eqname);
281       break;
282 
283     default:
284       bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of selection.",
285                 __func__);
286 
287     } /* Switch on selection type */
288 
289   }
290   else
291     bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition",
292               __func__);
293 }
294 
295 /*----------------------------------------------------------------------------*/
296 /*!
297  * \brief  Build a cs_enforcement_t structure for vertex-based scheme
298  *
299  * \param[in] connect    pointer to a cs_cdo_connect_t
300  * \param[in] n_params   number of enforcement parameters
301  * \param[in] efp_array  array of parameter structures defining the enforcement
302  *
303  * \return an array with the values to enforce
304  */
305 /*----------------------------------------------------------------------------*/
306 
307 cs_real_t *
cs_enforcement_define_at_vertices(const cs_cdo_connect_t * connect,int n_params,cs_enforcement_param_t ** efp_array)308 cs_enforcement_define_at_vertices(const cs_cdo_connect_t     *connect,
309                                   int                         n_params,
310                                   cs_enforcement_param_t    **efp_array)
311 {
312   if (n_params == 0)
313     return NULL;
314 
315   cs_lnum_t  n_vertices = connect->n_vertices;
316   cs_real_t  *values = NULL;
317   int  stride = (efp_array[0])->stride;
318 
319   BFT_MALLOC(values, stride*n_vertices, cs_real_t);
320   for (cs_lnum_t i = 0; i < stride*n_vertices; i++)
321     values[i] = FLT_MAX; /* By default, max value */
322 
323   /* Define the enforcement value for each vertex related to an enforcement */
324 
325   for (int param_id = 0; param_id < n_params; param_id++) {
326 
327     cs_enforcement_param_t  *efp = efp_array[param_id];
328     assert(stride == efp->stride);
329 
330     switch (efp->selection_type) {
331 
332     case CS_ENFORCEMENT_SELECTION_VERTICES:
333 
334       switch (efp->type) {
335 
336       case CS_ENFORCEMENT_BY_CONSTANT:
337         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
338 
339           cs_lnum_t  vtx_id = efp->elt_ids[i];
340           for (int k = 0; k < stride; k++)
341             values[stride*vtx_id + k] = efp->values[k];
342 
343         }
344         break;
345 
346       case CS_ENFORCEMENT_BY_DOF_VALUES:
347         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
348 
349           cs_lnum_t  vtx_id = efp->elt_ids[i];
350           for (int k = 0; k < stride; k++)
351             values[stride*vtx_id + k] = efp->values[stride*i+k];
352 
353         }
354         break;
355 
356       default:
357         bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
358                   __func__);
359 
360       } /* End of switch on type */
361       break;
362 
363     case CS_ENFORCEMENT_SELECTION_CELLS:
364       {
365         const cs_adjacency_t  *c2v = connect->c2v;
366 
367         switch (efp->type) {
368 
369         case CS_ENFORCEMENT_BY_CONSTANT:
370           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
371 
372             const cs_lnum_t  c_id = efp->elt_ids[i];
373             for (cs_lnum_t j = c2v->idx[c_id]; j < c2v->idx[c_id+1]; j++)
374               for (int k = 0; k < stride; k++)
375                 values[stride*c2v->ids[j] + k] = efp->values[k];
376 
377           }
378           break;
379 
380         case CS_ENFORCEMENT_BY_DOF_VALUES:
381           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
382 
383             const cs_lnum_t  c_id = efp->elt_ids[i];
384             for (cs_lnum_t j = c2v->idx[c_id]; j < c2v->idx[c_id+1]; j++)
385               for (int k = 0; k < stride; k++)
386                 values[stride*c2v->ids[j] + k] = efp->values[stride*c_id + k];
387 
388           }
389           break;
390 
391         default:
392           bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
393                     __func__);
394 
395         } /* End of switch on type */
396 
397       }
398       break;
399 
400     default:
401       bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of selection",
402                 __func__);
403 
404     } /* End of switch on selection */
405 
406   } /* Loop on parameters */
407 
408   /* Parallel synchronization: If there is a conflict between two definitions
409      or if a DoF at the parallel interface is defined and its corresponding one
410      is not defined, one takes the min. values (since one initializes with
411      FLT_MAX). */
412 
413   cs_interface_set_t  *ifs = connect->interfaces[CS_CDO_CONNECT_VTX_SCAL];
414 
415   if (ifs != NULL)
416     cs_interface_set_min(ifs,
417                          n_vertices,  /* array size */
418                          stride,      /* array stride */
419                          true,        /* interlace */
420                          CS_REAL_TYPE,
421                          values);
422 
423   return values;
424 }
425 
426 /*----------------------------------------------------------------------------*/
427 /*!
428  * \brief  Build a cs_enforcement_t structure for face-based scheme
429  *
430  * \param[in] connect    pointer to a cs_cdo_connect_t
431  * \param[in] n_params   number of enforcement parameters
432  * \param[in] efp_array  array of parameter structures defining the enforcement
433  *
434  * \return an array with the values to enforce
435  */
436 /*----------------------------------------------------------------------------*/
437 
438 cs_real_t *
cs_enforcement_define_at_faces(const cs_cdo_connect_t * connect,int n_params,cs_enforcement_param_t ** efp_array)439 cs_enforcement_define_at_faces(const cs_cdo_connect_t     *connect,
440                                int                         n_params,
441                                cs_enforcement_param_t    **efp_array)
442 {
443   if (n_params == 0)
444     return NULL;
445 
446   cs_lnum_t  n_faces = connect->n_faces[0];
447   cs_real_t  *values = NULL;
448   int  stride = (efp_array[0])->stride;
449 
450   BFT_MALLOC(values, stride*n_faces, cs_real_t);
451   for (cs_lnum_t i = 0; i < stride*n_faces; i++)
452     values[i] = FLT_MAX; /* By default, max value */
453 
454   /* Define the enforcement value for each vertex related to an enforcement */
455 
456   for (int param_id = 0; param_id < n_params; param_id++) {
457 
458     cs_enforcement_param_t  *efp = efp_array[param_id];
459     assert(stride == efp->stride);
460 
461     switch (efp->selection_type) {
462 
463     case CS_ENFORCEMENT_SELECTION_FACES:
464 
465       switch (efp->type) {
466 
467       case CS_ENFORCEMENT_BY_CONSTANT:
468         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
469 
470           cs_lnum_t  f_id = efp->elt_ids[i];
471           for (int k = 0; k < stride; k++)
472             values[stride*f_id + k] = efp->values[k];
473 
474         }
475         break;
476 
477       case CS_ENFORCEMENT_BY_DOF_VALUES:
478         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
479 
480           cs_lnum_t  f_id = efp->elt_ids[i];
481           for (int k = 0; k < stride; k++)
482             values[stride*f_id + k] = efp->values[stride*i+k];
483 
484         }
485         break;
486 
487       default:
488         bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
489                   __func__);
490 
491       } /* End of switch on type */
492       break;
493 
494     case CS_ENFORCEMENT_SELECTION_CELLS:
495       {
496         const cs_adjacency_t  *c2f = connect->c2f;
497 
498         switch (efp->type) {
499 
500         case CS_ENFORCEMENT_BY_CONSTANT:
501           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
502 
503             const cs_lnum_t  c_id = efp->elt_ids[i];
504             for (cs_lnum_t j = c2f->idx[c_id]; j < c2f->idx[c_id+1]; j++)
505               for (int k = 0; k < stride; k++)
506                 values[stride*c2f->ids[j] + k] = efp->values[k];
507 
508           }
509           break;
510 
511         case CS_ENFORCEMENT_BY_DOF_VALUES:
512           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
513 
514             const cs_lnum_t  c_id = efp->elt_ids[i];
515             for (cs_lnum_t j = c2f->idx[c_id]; j < c2f->idx[c_id+1]; j++)
516               for (int k = 0; k < stride; k++)
517                 values[stride*c2f->ids[j] + k] = efp->values[stride*c_id + k];
518 
519           }
520           break;
521 
522         default:
523           bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
524                     __func__);
525 
526         } /* End of switch on type */
527 
528       }
529       break;
530 
531     default:
532       bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of selection",
533                 __func__);
534 
535     } /* End of switch on selection */
536 
537   } /* Loop on parameters */
538 
539   /* Parallel synchronization: If there is a conflict between two definitions
540      or if a DoF at the parallel interface is defined and its corresponding one
541      is not defined, one takes the min. values (since one initializes with
542      FLT_MAX). */
543 
544   cs_interface_set_t  *ifs = connect->interfaces[CS_CDO_CONNECT_FACE_SP0];
545 
546   if (ifs != NULL)
547     cs_interface_set_min(ifs,
548                          n_faces,     /* array size */
549                          stride,      /* array stride */
550                          true,        /* interlace */
551                          CS_REAL_TYPE,
552                          values);
553 
554   return values;
555 }
556 
557 /*----------------------------------------------------------------------------*/
558 /*!
559  * \brief  Build a cs_enforcement_t structure for edge-based scheme
560  *
561  * \param[in] connect    pointer to a cs_cdo_connect_t
562  * \param[in] n_params   number of enforcement parameters
563  * \param[in] efp_array  array of parameter structures defining the enforcement
564  *
565  * \return an array with the values to enforce
566  */
567 /*----------------------------------------------------------------------------*/
568 
569 cs_real_t *
cs_enforcement_define_at_edges(const cs_cdo_connect_t * connect,int n_params,cs_enforcement_param_t ** efp_array)570 cs_enforcement_define_at_edges(const cs_cdo_connect_t     *connect,
571                                int                         n_params,
572                                cs_enforcement_param_t    **efp_array)
573 {
574   if (n_params == 0)
575     return NULL;
576 
577   cs_lnum_t  n_edges = connect->n_edges;
578   cs_real_t  *values = NULL;
579   int  stride = (efp_array[0])->stride;
580 
581   BFT_MALLOC(values, stride*n_edges, cs_real_t);
582   for (cs_lnum_t i = 0; i < stride*n_edges; i++)
583     values[i] = FLT_MAX; /* By default, max value */
584 
585   /* Define the enforcement value for each vertex related to an enforcement */
586 
587   for (int param_id = 0; param_id < n_params; param_id++) {
588 
589     cs_enforcement_param_t  *efp = efp_array[param_id];
590     assert(stride == efp->stride);
591 
592     switch (efp->selection_type) {
593 
594     case CS_ENFORCEMENT_SELECTION_EDGES:
595 
596       switch (efp->type) {
597 
598       case CS_ENFORCEMENT_BY_CONSTANT:
599         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
600 
601           cs_lnum_t  f_id = efp->elt_ids[i];
602           for (int k = 0; k < stride; k++)
603             values[stride*f_id + k] = efp->values[k];
604 
605         }
606         break;
607 
608       case CS_ENFORCEMENT_BY_DOF_VALUES:
609         for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
610 
611           cs_lnum_t  f_id = efp->elt_ids[i];
612           for (int k = 0; k < stride; k++)
613             values[stride*f_id + k] = efp->values[stride*i+k];
614 
615         }
616         break;
617 
618       default:
619         bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
620                   __func__);
621 
622       } /* End of switch on type */
623       break;
624 
625     case CS_ENFORCEMENT_SELECTION_CELLS:
626       {
627         const cs_adjacency_t  *c2e = connect->c2e;
628 
629         switch (efp->type) {
630 
631         case CS_ENFORCEMENT_BY_CONSTANT:
632           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
633 
634             const cs_lnum_t  c_id = efp->elt_ids[i];
635             for (cs_lnum_t j = c2e->idx[c_id]; j < c2e->idx[c_id+1]; j++)
636               for (int k = 0; k < stride; k++)
637                 values[stride*c2e->ids[j] + k] = efp->values[k];
638 
639           }
640           break;
641 
642         case CS_ENFORCEMENT_BY_DOF_VALUES:
643           for (cs_lnum_t i = 0; i < efp->n_elts; i++) {
644 
645             const cs_lnum_t  c_id = efp->elt_ids[i];
646             for (cs_lnum_t j = c2e->idx[c_id]; j < c2e->idx[c_id+1]; j++)
647               for (int k = 0; k < stride; k++)
648                 values[stride*c2e->ids[j] + k] = efp->values[stride*c_id + k];
649 
650           }
651           break;
652 
653         default:
654           bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of definition.\n",
655                     __func__);
656 
657         } /* End of switch on type */
658 
659       }
660       break;
661 
662     default:
663       bft_error(__FILE__, __LINE__, 0, "%s: Invalid type of selection",
664                 __func__);
665 
666     } /* End of switch on selection */
667 
668   } /* Loop on parameters */
669 
670   /* Parallel synchronization: If there is a conflict between two definitions
671      or if a DoF at the parallel interface is defined and its corresponding one
672      is not defined, one takes the min. values (since one initializes with
673      FLT_MAX). */
674 
675   cs_interface_set_t  *ifs = connect->interfaces[CS_CDO_CONNECT_EDGE_SCAL];
676 
677   if (ifs != NULL)
678     cs_interface_set_min(ifs,
679                          n_edges,     /* array size */
680                          stride,      /* array stride */
681                          true,        /* interlace */
682                          CS_REAL_TYPE,
683                          values);
684 
685   return values;
686 }
687 
688 /*----------------------------------------------------------------------------*/
689 /*!
690  * \brief  Build the cell-wise value to enforce
691  *
692  * \param[in]      forced_values     values to enforce or FLT_MAX
693  * \param[in, out] csys              pointer to a cs_cell_sys_t structure
694  * \param[in, out] cw_forced_values  local values to enforce
695  *
696  * \return true if at least one DoF has to be enforced
697  */
698 /*----------------------------------------------------------------------------*/
699 
700 bool
cs_enforcement_dofs_cw(const cs_real_t * forced_values,cs_cell_sys_t * csys,cs_real_t * cw_forced_values)701 cs_enforcement_dofs_cw(const cs_real_t      *forced_values,
702                        cs_cell_sys_t        *csys,
703                        cs_real_t            *cw_forced_values)
704 {
705   assert(forced_values != NULL && cw_forced_values != NULL);
706 
707   /* cw_forced_values is initialized by the calling function */
708 
709   /* Initialization */
710 
711   bool  has_enforcement = false;
712 
713   for (int i = 0; i < csys->n_dofs; i++) {
714 
715     csys->dof_is_forced[i] = false;    /* Not enforced by default */
716 
717     /* In case of a Dirichlet BC or a circulation BC, this BC is applied and
718        the enforcement is ignored. A dirichlet BC is included inside the
719        circulation condition */
720 
721     if (!cs_cdo_bc_is_circulation(csys->dof_flag[i])) {
722 
723       cs_real_t  _val = forced_values[csys->dof_ids[i]];
724       if (_val < FLT_MAX) {
725 
726         cw_forced_values[i] = _val;
727         has_enforcement = true;
728         csys->dof_is_forced[i] = true;
729 
730       }
731 
732     } /* DoF is not associated to a Dirichlet BCs */
733 
734   } /* Loop on cell-wise DoFs */
735 
736   return has_enforcement;
737 }
738 
739 /*----------------------------------------------------------------------------*/
740 
741 END_C_DECLS
742