1 /*============================================================================
2  * STL reader and writer.
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 <math.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
40 
41 /*----------------------------------------------------------------------------
42  * Local headers
43  *----------------------------------------------------------------------------*/
44 
45 #include "bft_mem.h"
46 #include "bft_error.h"
47 #include "bft_printf.h"
48 
49 #include "fvm_nodal.h"
50 #include "fvm_writer.h"
51 #include "cs_post.h"
52 
53 #include "fvm_nodal_append.h"
54 #include "fvm_neighborhood.h"
55 
56 #include "cs_math.h"
57 #include "cs_mesh_headers.h"
58 #include "cs_order.h"
59 #include "cs_parall.h"
60 #include "cs_rotation.h"
61 
62 /*----------------------------------------------------------------------------
63  * Header of the current file
64  *----------------------------------------------------------------------------*/
65 
66 #include "cs_stl.h"
67 
68 /*----------------------------------------------------------------------------*/
69 
70 BEGIN_C_DECLS
71 
72 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
73 
74 /*=============================================================================
75  * Static global variables
76  *============================================================================*/
77 
78 static cs_stl_mesh_info_t _stl_meshes = {NULL, 0, 0};
79 
80 cs_stl_mesh_info_t *cs_glob_stl_meshes = &_stl_meshes;
81 
82 /*=============================================================================
83  * Private function definitions
84  *============================================================================*/
85 
86 /*----------------------------------------------------------------------------
87  * Function to cast 4 uint8_t value into one single uint32_t value
88  *
89  * parameters:
90  *   val <-- array of 4 uint8_t
91  *
92  * returns :
93  *   the uint32_t corresponding value
94   ----------------------------------------------------------------------------*/
95 
96 static uint32_t
_cast32(uint8_t * val)97 _cast32(uint8_t *val)
98 {
99   uint32_t retval;
100 
101   /* We have here 4 8bits unsigned int
102    * and we cast then in a single 32bit
103    * unsigned int by progessive shifts */
104 
105   retval =   (uint32_t)val[0]
106          + ( (uint32_t)val[1]<<8  )
107          + ( (uint32_t)val[2]<<16 )
108          + ( (uint32_t)val[3]<<24 );
109 
110   return retval;
111 }
112 
113 /*----------------------------------------------------------------------------
114  * Function to cut one uint32_t value into an array of 4 uint8_t value
115  *
116  * parameters:
117  *   out --> cut array of 4 uint8_t
118  *   val <-- input uint32_t value
119   ----------------------------------------------------------------------------*/
120 
121 static void
_cut32(uint8_t * out,int val)122 _cut32(uint8_t *out, int val)
123 {
124   out[0] = (val       ) & 0xff;
125   out[1] = (val >> 8  ) & 0xff;
126   out[2] = (val >> 16 ) & 0xff;
127   out[3] = (val >> 24 ) & 0xff;
128 }
129 
130 /*----------------------------------------------------------------------------
131  * Function to compute the normal of a triangle defined by 3 points
132  *
133  * parameters:
134  *   coords <-- triangle coordinates
135  *   normal --> triangle normal
136   ----------------------------------------------------------------------------*/
137 
138 static void
_compute_normal(cs_real_t coords[3][3],cs_real_t normal[3])139 _compute_normal(cs_real_t  coords[3][3],
140                 cs_real_t  normal[3])
141 {
142   /* Compute and Write the face normal coordinates */
143   const cs_real_t *a = coords[0], *b = coords[1], *c = coords[2];
144 
145   // ab vect ac
146   normal[0] = (b[1]-a[1])*(c[2]-a[2]) - (b[2]-a[2])*(c[1]-a[1]);
147   normal[1] = (b[2]-a[2])*(c[0]-a[0]) - (b[0]-a[0])*(c[2]-a[2]);
148   normal[2] = (b[0]-a[0])*(c[1]-a[1]) - (b[1]-a[1])*(c[0]-a[0]);
149 
150   cs_real_t norm = cs_math_3_norm(normal);
151 
152   for (int dir = 0; dir < 3; dir ++)
153     normal[dir] /= norm;
154 }
155 
156 /*----------------------------------------------------------------------------
157  * Function to check if an AABB (Axis Aligned Bounding Box) is overlaped
158  * by a triangle. It is based on the SAT (Separating Axis Theorem).
159  *
160  * Warning : the user must first be sure that the bounding boxes of
161  * the AABB and the triangle intersects, otherwise, this functions might
162  * give wrong results.
163  *
164  * parameters:
165  *   box_extents <-- coordinates of the bounding box (xmin,...,xmax,...)
166  *   tria_coords <-- coordinates of the triangle vertices
167  *
168  * returns:
169  *   a boolean
170   ----------------------------------------------------------------------------*/
171 
172 static bool
_triangle_box_intersect(const cs_real_t box_extents[6],const cs_real_t tria_coords[3][3])173 _triangle_box_intersect(const cs_real_t  box_extents[6],
174                         const cs_real_t  tria_coords[3][3])
175 {
176 
177   // Origin axis
178   cs_real_t e[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
179 
180   // Width of the box, center of the box
181   cs_real_t h[3], c[3];
182   h[0] = 0.5*(box_extents[3]-box_extents[0]);
183   h[1] = 0.5*(box_extents[4]-box_extents[1]);
184   h[2] = 0.5*(box_extents[5]-box_extents[2]);
185 
186   c[0] = box_extents[0] + h[0];
187   c[1] = box_extents[1] + h[1];
188   c[2] = box_extents[2] + h[2];
189 
190   // Move triangle so that the box is virtually centered on 0
191   cs_real_t v[3][3];
192   for (int vi = 0; vi < 3; vi++) {
193     for (int dir = 0; dir < 3; dir++)
194       v[vi][dir] = tria_coords[vi][dir] - c[dir];
195   }
196 
197   // Compute triangle edges
198   cs_real_t f[3][3];
199   for (int dir = 0; dir < 3; dir++) {
200     f[0][dir] = v[1][dir] - v[0][dir];
201     f[1][dir] = v[2][dir] - v[1][dir];
202     f[2][dir] = v[0][dir] - v[2][dir];
203   }
204 
205   // Construction of the 9 testing axis resulting from
206   // cross product combinations of the edges of the
207   // triangle and the edges of the AABB on which vertices
208   // will be projected.
209 
210   for (int i = 0; i < 3; i++) {
211     for (int j = 0; j < 3; j++) {
212 
213       cs_real_t axis[3];
214       cs_math_3_cross_product(f[i], e[j], axis);
215 
216       // Projection of the triangle's vertices on the
217       // seperated axis
218       cs_real_t p[3];
219       for (int dir = 0; dir < 3; dir ++)
220         p[dir] = cs_math_3_dot_product(axis, v[dir]);
221 
222       // Projection of the box on the seperated axis
223       // computation of the "radius" r
224       cs_real_t r = h[0] * CS_ABS(axis[0])
225                   + h[1] * CS_ABS(axis[1])
226                   + h[2] * CS_ABS(axis[2]);
227 
228       cs_real_t pmin = fmin(p[0], fmin(p[1], p[2]));
229       cs_real_t pmax = fmax(p[0], fmax(p[1], p[2]));
230 
231       // Finally, we test if most extreme
232       // of the triangle points intersects r
233       if (pmin > r || pmax < -r)
234         return false;
235     }
236   }
237 
238   // Construction of the last testing axis resulting from
239   // the triangle normal, repeat the process
240   cs_real_t n[3];
241   cs_math_3_cross_product(f[0], f[1], n);
242 
243   cs_real_t p[3];
244   for (int dir = 0; dir < 3; dir ++)
245     p[dir] = cs_math_3_dot_product(n, v[dir]);
246 
247   cs_real_t r = h[0] * CS_ABS(n[0])
248               + h[1] * CS_ABS(n[1])
249               + h[2] * CS_ABS(n[2]);
250 
251   cs_real_t pmin = fmin(p[0], fmin(p[1],p[2]));
252   cs_real_t pmax = fmax(p[0], fmax(p[1],p[2]));
253 
254   if ( pmin > r || pmax < -r )
255     return false;
256 
257 
258   return true;
259 }
260 
261 /*----------------------------------------------------------------------------
262  * Function to check if a point is "inside" or "outside" a plane, according
263  * to its normal. Basically, performs the dot product between the point and
264  * the normal and check its sign.
265  *
266  * parameters:
267  *   plane  <-- plane definition (x,y,z, Nx,Ny,Nz)
268  *   x      <-- the point considered
269  *
270  * returns:
271  *   true if the point is "inside", false otherwise
272   ----------------------------------------------------------------------------*/
273 
274 static bool
_is_point_inside_plane(cs_real_t plane[6],cs_real_t x[3])275 _is_point_inside_plane(cs_real_t plane[6],
276                        cs_real_t x[3])
277 {
278   bool val = false;
279 
280   cs_real_t *p = &plane[0];
281   cs_real_t *n = &plane[3];
282 
283   cs_real_t psca = cs_math_3_distance_dot_product(p,x,n);
284 
285   if (psca <= 0.0)
286     val = true;
287 
288   return val;
289 }
290 
291 /*----------------------------------------------------------------------------
292  * Function that performs the intersection between a plane and a polygon.
293  * It returns the resulting polygon at the "inner" side of the plane
294  * according to its normal.
295  *
296  * parameters:
297  *   nb_vertex     <--> number of vertices of the polygon
298  *   vertex_coords <--> coordinates of the vertices (size : 3*nb_vertex)
299  *   plane         <-- plane definition (point + normal)
300  *
301   ----------------------------------------------------------------------------*/
302 
303 static void
_polygon_plane_intersection(int * nb_vertex,cs_real_3_t ** vertex_coord,cs_real_t plane[6])304 _polygon_plane_intersection(int         *nb_vertex,
305                             cs_real_3_t **vertex_coord,
306                             cs_real_t   plane[6])
307 {
308   /* Initial number of vertices in the polygon */
309   int n_vtx = *nb_vertex;
310   cs_real_3_t *vtx = *vertex_coord;
311 
312   cs_real_3_t *new_vtx = NULL;
313   BFT_MALLOC(new_vtx, n_vtx + 1, cs_real_3_t);
314   int j = 0;
315 
316   /* Now we check which edge is intersected by the plane */
317   for (int i = 0; i < n_vtx; i++) {
318     int v1 = i;
319     int v2 = (i+1) % n_vtx;
320 
321     cs_real_t xn = cs_math_3_distance_dot_product(vtx[v1], &plane[0], &plane[3]);
322     cs_real_t xd = cs_math_3_distance_dot_product(vtx[v1],   vtx[v2], &plane[3]);
323 
324     // if the edge is //, we keep the vertex
325     if ( CS_ABS(xd) < 1.0e-12 ) {
326 
327       if(_is_point_inside_plane(plane, vtx[v2])){
328         for (int dir = 0; dir < 3; dir ++)
329           new_vtx[j][dir] = vtx[v2][dir];
330         j++;
331       }
332 
333     // if the edge is not // to the plane
334     } else {
335       cs_real_t t = xn/xd;
336 
337       // If intersection, new vertex
338       if (t > 0 && t < 1.0){
339         for (int dir = 0; dir < 3; dir ++)
340           new_vtx[j][dir] = vtx[v1][dir] + t * (vtx[v2][dir] - vtx[v1][dir]);
341         j++;
342       }
343 
344       // We check if the second point is "inside" inside the plane
345       // if yes, add the vertex to the new vertex list
346       if(_is_point_inside_plane(plane, vtx[v2])){
347         for (int dir = 0; dir < 3; dir ++)
348           new_vtx[j][dir] = vtx[v2][dir];
349         j++;
350       }
351     }
352   }
353 
354   BFT_REALLOC(new_vtx, j, cs_real_3_t);
355   BFT_REALLOC(vtx, j, cs_real_3_t);
356 
357   for (int i = 0; i < j; i++) {
358     for (int dir = 0; dir < 3; dir ++)
359       vtx[i][dir] = new_vtx[i][dir];
360   }
361 
362   *nb_vertex = j;
363   *vertex_coord = vtx;
364 
365   BFT_FREE(new_vtx);
366 }
367 
368 /*----------------------------------------------------------------------------
369  * Function to compute the approximate surface of a triangle overlapping
370  * an AABB (Axis Aligned Bounding Box). It is based on a Monte-Carlo like
371  * method that randomly draw points in the triangle.
372  *
373  * parameters:
374  *   box_extents <-- coordinates of the bounding box (xmin,...,xmax,...)
375  *   tria_coords <-- coordinates of the triangle vertices
376  *
377  * returns:
378  *   the surface of the triangle inside the bounding box
379   ----------------------------------------------------------------------------*/
380 
381 static cs_real_t
_triangle_box_surface_intersection(const cs_real_t box_extents[6],const cs_real_t tria_coords[3][3])382 _triangle_box_surface_intersection(const cs_real_t  box_extents[6],
383                                    const cs_real_t  tria_coords[3][3])
384 {
385   cs_real_t surf = 0.;
386 
387   const cs_real_t *a = tria_coords[0];
388   const cs_real_t *b = tria_coords[1];
389   const cs_real_t *c = tria_coords[2];
390 
391   /* Computation of the total triangle surface */
392   cs_real_t ab[3], ac[3], vec[3];
393 
394   for (int i = 0; i < 3; i++) {
395     ab[i] = b[i]-a[i];
396     ac[i] = c[i]-a[i];
397   }
398 
399   cs_math_3_cross_product(ab,ac,vec);
400   surf = 0.5 * cs_math_3_norm(vec);
401 
402   /* Particular case if the triangle is totally included in the box */
403   cs_real_t bbox[6];
404   bbox[0] =  HUGE_VAL; bbox[1] =  HUGE_VAL; bbox[2] =  HUGE_VAL;
405   bbox[3] = -HUGE_VAL; bbox[4] = -HUGE_VAL; bbox[5] = -HUGE_VAL;
406 
407   for (int vtx_id = 0; vtx_id < 3; vtx_id ++) {
408     bbox[0] = CS_MIN(bbox[0], tria_coords[vtx_id][0]);
409     bbox[3] = CS_MAX(bbox[3], tria_coords[vtx_id][0]);
410     bbox[1] = CS_MIN(bbox[1], tria_coords[vtx_id][1]);
411     bbox[4] = CS_MAX(bbox[4], tria_coords[vtx_id][1]);
412     bbox[2] = CS_MIN(bbox[2], tria_coords[vtx_id][2]);
413     bbox[5] = CS_MAX(bbox[5], tria_coords[vtx_id][2]);
414   }
415 
416   if (   bbox[0] >= box_extents[0]
417       && bbox[1] >= box_extents[1]
418       && bbox[2] >= box_extents[2]
419       && bbox[3] <= box_extents[3]
420       && bbox[4] <= box_extents[4]
421       && bbox[5] <= box_extents[5])
422     return surf;
423 
424   /* Approximation of the surface enclosed in the AABB */
425 
426   int max_draw = 5000;
427   int nb_point_in = 0;
428   cs_real_t px[3];
429 
430   for (int nb_draw = 0; nb_draw < max_draw; nb_draw ++) {
431     /* Random draw in [[0:1]] */
432     cs_real_t ra = (cs_real_t)rand() / (cs_real_t)RAND_MAX;
433     cs_real_t rb = (cs_real_t)rand() / (cs_real_t)RAND_MAX;
434 
435     if (ra+rb >= 1.0){
436       ra = 1.0-ra;
437       rb = 1.0-rb;
438     }
439 
440     /* Contruction of the random point */
441     for (int i = 0; i < 3; i++)
442       px[i] = a[i] + ra*(b[i]-a[i]) + rb*(c[i]-a[i]);
443 
444     if (   px[0] >= box_extents[0]
445         && px[1] >= box_extents[1]
446         && px[2] >= box_extents[2]
447         && px[0] <= box_extents[3]
448         && px[1] <= box_extents[4]
449         && px[2] <= box_extents[5])
450       nb_point_in ++;
451   }
452 
453   surf *= (cs_real_t)nb_point_in / (cs_real_t)max_draw;
454 
455   return surf;
456 }
457 
458 /*----------------------------------------------------------------------------
459  * Function to compute the exact surface of a triangle overlapping
460  * an AABB (Axis Aligned Bounding Box). It is based on recursive cut
461  * of the triangle by the planes defined by the AABB faces.
462  *
463  * parameters:
464  *   box_extents <-- coordinates of the bounding box (xmin,...,xmax,...)
465  *   tria_coords <-- coordinates of the triangle vertices
466  *
467  * returns:
468  *   the surface of the triangle inside the bounding box
469   ----------------------------------------------------------------------------*/
470 
471 static cs_real_t
_exact_triangle_box_surface_intersection(const cs_real_t box_extents[6],const cs_real_t tria_coords[3][3])472 _exact_triangle_box_surface_intersection(const cs_real_t  box_extents[6],
473                                          const cs_real_t  tria_coords[3][3])
474 {
475   cs_real_t surf = 0.;
476 
477   const cs_real_t *a = tria_coords[0];
478   const cs_real_t *b = tria_coords[1];
479   const cs_real_t *c = tria_coords[2];
480 
481   /* Computation of the total triangle surface */
482   cs_real_t ab[3], ac[3], vec[3];
483 
484   for (int i = 0; i < 3; i++) {
485     ab[i] = b[i]-a[i];
486     ac[i] = c[i]-a[i];
487   }
488 
489   cs_math_3_cross_product(ab,ac,vec);
490   surf = 0.5 * cs_math_3_norm(vec);
491 
492   /* Particular case if the triangle is totally included in the box */
493   cs_real_t bbox[6];
494   bbox[0] =  HUGE_VAL; bbox[1] =  HUGE_VAL; bbox[2] =  HUGE_VAL;
495   bbox[3] = -HUGE_VAL; bbox[4] = -HUGE_VAL; bbox[5] = -HUGE_VAL;
496 
497   for (int vtx_id = 0; vtx_id < 3; vtx_id ++) {
498     bbox[0] = CS_MIN(bbox[0], tria_coords[vtx_id][0]);
499     bbox[3] = CS_MAX(bbox[3], tria_coords[vtx_id][0]);
500     bbox[1] = CS_MIN(bbox[1], tria_coords[vtx_id][1]);
501     bbox[4] = CS_MAX(bbox[4], tria_coords[vtx_id][1]);
502     bbox[2] = CS_MIN(bbox[2], tria_coords[vtx_id][2]);
503     bbox[5] = CS_MAX(bbox[5], tria_coords[vtx_id][2]);
504   }
505 
506   if (   bbox[0] >= box_extents[0]
507       && bbox[1] >= box_extents[1]
508       && bbox[2] >= box_extents[2]
509       && bbox[3] <= box_extents[3]
510       && bbox[4] <= box_extents[4]
511       && bbox[5] <= box_extents[5])
512     return surf;
513 
514   /* Successively cut the triangle by the planes
515    * defined byt the box faces */
516   int nv = 3;
517   cs_real_3_t *coords = NULL ;
518   BFT_MALLOC(coords, nv, cs_real_3_t);
519 
520   /* Polygon init */
521   for (int i = 0; i < nv; i ++){
522     for (int dir = 0; dir < 3; dir ++)
523       coords[i][dir] = tria_coords[i][dir];
524   }
525 
526   /* Plane definition */
527   cs_real_t plane[6][6];
528   cs_real_t e[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
529 
530   for (int i = 0; i < 3; i++){
531     for (int j = 0; j < 3; j++){
532       plane[i][j]   = box_extents[j];
533       plane[i][j+3] = -e[i][j];
534     }
535   }
536 
537   for (int i = 3; i < 6; i++){
538     for (int j = 0; j < 3; j++){
539       plane[i][j]   = box_extents[j+3];
540       plane[i][j+3] = e[i-3][j];
541     }
542   }
543 
544   /* Recursively cut the tiangle by the planes */
545   for (int f = 0; f < 6; f++)
546     _polygon_plane_intersection(&nv, &coords, plane[f]);
547 
548   /* If no intersection, surface is 0*/
549   if (nv ==0) {
550     surf = 0;
551     return surf;
552   }
553 
554   /* Compute approximate face center coordinates for the polygon */
555   cs_real_t a_center[3] = {0, 0, 0};
556   cs_real_t f_norm[3] = {0, 0, 0};
557 
558   for (int i = 0; i < nv; i++) {
559     for (int dir = 0; dir < 3; dir++)
560       a_center[dir] += coords[i][dir];
561   }
562 
563   for (cs_lnum_t i = 0; i < 3; i++)
564     a_center[i] /= nv;
565 
566   /* Surface computation */
567   cs_real_t vc0[3], vc1[3], vn[3];
568 
569   for (cs_lnum_t i = 0; i < nv; i++) {
570 
571     const int v0 = i;
572     const int v1 = (i+1) % nv;
573 
574     for (cs_lnum_t dir = 0; dir < 3; dir++) {
575       vc0[dir] = coords[v0][dir] - a_center[dir];
576       vc1[dir] = coords[v1][dir] - a_center[dir];
577     }
578 
579     cs_math_3_cross_product(vc0, vc1, vn);
580 
581     for (cs_lnum_t dir = 0; dir < 3; dir++)
582       f_norm[dir] += 0.5*vn[dir];
583   }
584 
585   surf = cs_math_3_norm(f_norm);
586 
587   BFT_FREE(coords);
588 
589   return surf;
590 }
591 
592 /*----------------------------------------------------------------------------
593  * Function to compute the volume of a tetrahedron
594  *
595  * parameters:
596  *   x1      <-- coordinates of the tetrahedra (x1,y1,z1)
597  *   x2      <-- coordinates of the tetrahedra (x2,y2,z2)
598  *   x3      <-- coordinates of the tetrahedra (x3,y3,z3)
599  *   x4      <-- coordinates of the tetrahedra (x4,y4,z4)
600  *
601  * returns:
602  *   the volume of the tetrahedron
603   ----------------------------------------------------------------------------*/
604 
605 static cs_real_t
_tetra_vol(cs_real_t x1[3],cs_real_t x2[3],cs_real_t x3[3],cs_real_t x4[3])606 _tetra_vol(cs_real_t x1[3],
607            cs_real_t x2[3],
608            cs_real_t x3[3],
609            cs_real_t x4[3])
610 {
611   cs_real_t tetra_vol;
612 
613   tetra_vol =  cs_math_fabs((  (x1[0]-x4[0])*(x2[1]-x4[1])
614                              - (x1[1]-x4[1])*(x2[0]-x4[0])) * (x3[2]-x4[2])
615                          + (   (x1[1]-x4[1])*(x2[2]-x4[2])
616                              - (x1[2]-x4[2])*(x2[1]-x4[1])) * (x3[0]-x4[0])
617                          + (   (x1[2]-x4[2])*(x2[0]-x4[0])
618                              - (x1[0]-x4[0])*(x2[2]-x4[2])) * (x3[1]-x4[1]));
619 
620   tetra_vol *= cs_math_1ov6;
621 
622   return tetra_vol;
623 }
624 
625 /*----------------------------------------------------------------------------
626  * Function to compute the volume of a pyramid, whose base is defined by
627  * x1, x2, x3 and x4.
628  *
629  * parameters:
630  *   x1      <-- coordinates of the pyramid (x1,y1,z1)
631  *   x2      <-- coordinates of the pyramid (x2,y2,z2)
632  *   x3      <-- coordinates of the pyramid (x3,y3,z3)
633  *   x4      <-- coordinates of the pyramid (x4,y4,z4)
634  *   x5      <-- coordinates of the pyramid (x5,y5,z5)
635  *
636  * returns:
637  *   the volume of the pyramid
638   ----------------------------------------------------------------------------*/
639 
640 static cs_real_t
_pyramid_vol(cs_real_t x1[3],cs_real_t x2[3],cs_real_t x3[3],cs_real_t x4[3],cs_real_t x5[3])641 _pyramid_vol(cs_real_t x1[3],
642              cs_real_t x2[3],
643              cs_real_t x3[3],
644              cs_real_t x4[3],
645              cs_real_t x5[3])
646 {
647   cs_real_t xc[3];
648 
649   for (int i = 0; i < 3; i++)
650     xc[i] = 0.25 * (x1[i]+x2[i]+x3[i]+x4[i]);
651 
652   cs_real_t vol12 = _tetra_vol(x1, x2, xc, x5);
653   cs_real_t vol23 = _tetra_vol(x2, x3, xc, x5);
654   cs_real_t vol34 = _tetra_vol(x3, x4, xc, x5);
655   cs_real_t vol41 = _tetra_vol(x4, x1, xc, x5);
656 
657   cs_real_t pyram_vol = vol12 + vol23 + vol34 + vol41;
658 
659   return pyram_vol;
660 }
661 
662 /*----------------------------------------------------------------------------
663  * Function to compute the volume of a prism, whose base is defined by
664  * x1, x2, x3 and x4.
665  *
666  * parameters:
667  *   x1      <-- coordinates of the prism (x1,y1,z1)
668  *   x2      <-- coordinates of the prism (x2,y2,z2)
669  *   x3      <-- coordinates of the prism (x3,y3,z3)
670  *   x4      <-- coordinates of the prism (x4,y4,z4)
671  *   x5      <-- coordinates of the prism (x5,y5,z5)
672  *   x6      <-- coordinates of the prism (x5,y5,z5)
673  *
674  * returns:
675  *   the volume of the prism
676   ----------------------------------------------------------------------------*/
677 
678 static cs_real_t
_prism_vol(cs_real_t x1[3],cs_real_t x2[3],cs_real_t x3[3],cs_real_t x4[3],cs_real_t x5[3],cs_real_t x6[3])679 _prism_vol(cs_real_t x1[3],
680            cs_real_t x2[3],
681            cs_real_t x3[3],
682            cs_real_t x4[3],
683            cs_real_t x5[3],
684            cs_real_t x6[3])
685 {
686   cs_real_t xc[3];
687 
688   for (int i = 0; i < 3; i++)
689     xc[i] = (x1[i]+x2[i]+x3[i]+x4[i]+x5[i]+x6[i]) * cs_math_1ov6;
690 
691   cs_real_t vol136c  = _tetra_vol(x1, x3, x6, xc);
692   cs_real_t vol245c  = _tetra_vol(x2, x4, x5, xc);
693   cs_real_t vol1256c = _pyramid_vol(x1, x2, x5, x6, xc);
694   cs_real_t vol1243c = _pyramid_vol(x1, x2, x4, x3, xc);
695   cs_real_t vol3456c = _pyramid_vol(x3, x4, x5, x6, xc);
696 
697   cs_real_t prisme_vol = vol136c + vol245c + vol1256c +  vol1243c + vol3456c;
698 
699   return prisme_vol;
700 }
701 
702 /*----------------------------------------------------------------------------
703  * Function to compute the "outside" length of a segment cut by a plan,
704  * according to its normal
705  *
706  * parameters:
707  *   x1      <-- coordinates of the tetrahedra (x1,y1,z1)
708  *   x2      <-- coordinates of the tetrahedra (x2,y2,z2)
709  *   plane   <-- coordinates of the triangle vertices and normals
710  *               (x1,y1,z1,nx,ny,nz)
711  *
712  * returns:
713  *   the volume of the tetrahedra under the plane (according to its normal)
714   ----------------------------------------------------------------------------*/
715 
716 static cs_real_t
_plane_segment_intersection(cs_real_t x1[3],cs_real_t x2[3],cs_real_t plane[6])717 _plane_segment_intersection(cs_real_t x1[3],
718                             cs_real_t x2[3],
719                             cs_real_t plane[6])
720 {
721   cs_real_t length = cs_math_3_distance(x1, x2);
722   cs_real_t *a = &plane[0];
723   cs_real_t *n = &plane[3];
724 
725   int v1_is_inside = 0; int v2_is_inside = 0;
726 
727   if (_is_point_inside_plane(plane, x1))
728     v1_is_inside = 1;
729 
730   if (_is_point_inside_plane(plane, x2))
731     v2_is_inside = 1;
732 
733 
734   if (v1_is_inside == 0 && v2_is_inside == 0)
735     length = 0.0;
736 
737   if (v1_is_inside == 1 && v2_is_inside == 0) {
738 
739     cs_real_t den = cs_math_3_distance_dot_product(x2, x1, n);
740     cs_real_t num = cs_math_3_distance_dot_product(x2, a, n);
741 
742     cs_real_t lambda = 1.0;
743     if (cs_math_fabs(den) > 1.e-20)
744       lambda = num / den;
745 
746     length *= lambda;
747   }
748 
749   if (v1_is_inside == 0 && v2_is_inside == 1) {
750 
751     cs_real_t den = cs_math_3_distance_dot_product(x1, x2, n);
752     cs_real_t num = cs_math_3_distance_dot_product(x1, a, n);
753 
754     cs_real_t lambda = 1.0;
755     if (cs_math_fabs(den) > 1.e-20)
756       lambda = num / den;
757 
758     length *= lambda;
759   }
760 
761   return length;
762 }
763 
764 /*----------------------------------------------------------------------------
765  * Function to compute the volume of a tetrahedra cut by a plane surface
766  *
767  * parameters:
768  *   x1      <-- coordinates of the tetrahedra (x1,y1,z1)
769  *   x2      <-- coordinates of the tetrahedra (x2,y2,z2)
770  *   x3      <-- coordinates of the tetrahedra (x3,y3,z3)
771  *   x4      <-- coordinates of the tetrahedra (x4,y4,z4)
772  *   plane   <-- coordinates of the triangle vertices and normals
773  *               (x1,y1,z1,nx,ny,nz)
774  *
775  * returns:
776  *   the volume of the tetrahedra under the plane (according to its normal)
777   ----------------------------------------------------------------------------*/
778 
779 static cs_real_t
_tetrahedron_plane_volume_intersection(cs_real_t x1[3],cs_real_t x2[3],cs_real_t x3[3],cs_real_t x4[3],cs_real_t plane[6])780 _tetrahedron_plane_volume_intersection(cs_real_t x1[3],
781                                        cs_real_t x2[3],
782                                        cs_real_t x3[3],
783                                        cs_real_t x4[3],
784                                        cs_real_t plane[6])
785 {
786   cs_real_t vol = 0.0;
787 
788   int v1_is_inside = 0; int v2_is_inside = 0;
789   int v3_is_inside = 0; int v4_is_inside = 0;
790 
791   /* Test if the tetra vertices are "inside" or "outside" the plane,
792    * according to its normal */
793 
794   if (_is_point_inside_plane(plane, x1))
795     v1_is_inside = 1;
796 
797   if (_is_point_inside_plane(plane, x2))
798     v2_is_inside = 1;
799 
800   if (_is_point_inside_plane(plane, x3))
801     v3_is_inside = 1;
802 
803   if (_is_point_inside_plane(plane, x4))
804     v4_is_inside = 1;
805 
806   int nb_point_inside_plane = v1_is_inside + v2_is_inside + v3_is_inside + v4_is_inside;
807 
808   switch(nb_point_inside_plane) {
809 
810     case 0: /* entire tetra "outside" the plane */
811 
812       vol = _tetra_vol(x1, x2, x3, x4);
813 
814       break;
815 
816     case 1: /* 3 intersection points with one point inside */
817     {
818       vol = _tetra_vol(x1, x2, x3, x4);
819 
820       /* Looking for the point located inside */
821       cs_real_t *a, *b, *c, *d;
822 
823       if (v1_is_inside == 1) {
824         a = &x1[0];
825         b = &x2[0];
826         c = &x3[0];
827         d = &x4[0];
828       } else if (v2_is_inside == 1) {
829         a = &x2[0];
830         b = &x1[0];
831         c = &x3[0];
832         d = &x4[0];
833       } else if (v3_is_inside == 1) {
834         a = &x3[0];
835         b = &x1[0];
836         c = &x2[0];
837         d = &x4[0];
838       } else if (v4_is_inside == 1) {
839         a = &x4[0];
840         b = &x1[0];
841         c = &x2[0];
842         d = &x3[0];
843       }
844 
845 
846       cs_real_t ab[3], ac[3], ad[3];
847       for (int i = 0; i < 3; i++) {
848         ab[i] = a[i] - b[i];
849         ac[i] = a[i] - c[i];
850         ad[i] = a[i] - d[i];
851       }
852 
853       cs_real_t lab = cs_math_3_norm(ab);
854       cs_real_t lac = cs_math_3_norm(ac);
855       cs_real_t lad = cs_math_3_norm(ad);
856 
857       cs_real_t lab_inside =  lab - _plane_segment_intersection(a, b, plane);
858       cs_real_t lac_inside =  lac - _plane_segment_intersection(a, c, plane);
859       cs_real_t lad_inside =  lad - _plane_segment_intersection(a, d, plane);
860 
861       cs_real_t lab_frac = lab_inside / lab;
862       cs_real_t lac_frac = lac_inside / lac;
863       cs_real_t lad_frac = lad_inside / lad;
864 
865       vol *= (1.0 - lab_frac * lac_frac * lad_frac);
866 
867       break;
868     }
869 
870     case 3: /* 3 intersection points with 3 points inside*/
871     {
872       vol = _tetra_vol(x1, x2, x3, x4);
873 
874       /* Lookink for the point located outside */
875       cs_real_t *a, *b, *c, *d;
876 
877       if (v1_is_inside == 0){
878         a = &x1[0];
879         b = &x2[0];
880         c = &x3[0];
881         d = &x4[0];
882       } else if (v2_is_inside == 0) {
883         a = &x2[0];
884         b = &x1[0];
885         c = &x3[0];
886         d = &x4[0];
887       } else if (v3_is_inside == 0) {
888         a = &x3[0];
889         b = &x1[0];
890         c = &x2[0];
891         d = &x4[0];
892       } else if (v4_is_inside == 0) {
893         a = &x4[0];
894         b = &x1[0];
895         c = &x2[0];
896         d = &x3[0];
897       }
898 
899       cs_real_t ab[3], ac[3], ad[3];
900       for (int i = 0; i < 3; i++) {
901         ab[i] = a[i] - b[i];
902         ac[i] = a[i] - c[i];
903         ad[i] = a[i] - d[i];
904       }
905 
906       cs_real_t lab = cs_math_3_norm(ab);
907       cs_real_t lac = cs_math_3_norm(ac);
908       cs_real_t lad = cs_math_3_norm(ad);
909 
910       cs_real_t lab_inside =  _plane_segment_intersection(a, b, plane);
911       cs_real_t lac_inside =  _plane_segment_intersection(a, c, plane);
912       cs_real_t lad_inside =  _plane_segment_intersection(a, d, plane);
913 
914       cs_real_t lab_frac = lab_inside / lab;
915       cs_real_t lac_frac = lac_inside / lac;
916       cs_real_t lad_frac = lad_inside / lad;
917 
918       vol *= lab_frac * lac_frac * lad_frac;
919 
920       break;
921     }
922 
923     case 2: /* 4 intersection points */
924     {
925       /* Looking for the 2 inside and 2 outside points */
926       cs_real_t *a, *b, *c, *d;
927 
928       if (v1_is_inside && v2_is_inside) {
929         a = &x1[0];
930         b = &x2[0];
931         c = &x3[0];
932         d = &x4[0];
933       } else if (v1_is_inside && v3_is_inside) {
934         a = &x1[0];
935         b = &x3[0];
936         c = &x2[0];
937         d = &x4[0];
938       } else if (v1_is_inside && v4_is_inside) {
939         a = &x1[0];
940         b = &x4[0];
941         c = &x2[0];
942         d = &x3[0];
943       } else if (v2_is_inside && v3_is_inside) {
944         a = &x2[0];
945         b = &x3[0];
946         c = &x1[0];
947         d = &x4[0];
948       } else if (v2_is_inside && v4_is_inside) {
949         a = &x2[0];
950         b = &x4[0];
951         c = &x1[0];
952         d = &x3[0];
953       } else if (v3_is_inside && v4_is_inside) {
954         a = &x3[0];
955         b = &x4[0];
956         c = &x1[0];
957         d = &x2[0];
958       }
959 
960       cs_real_t ac[3], ad[3], bc[3], bd[3];
961       for (int i = 0; i < 3; i++) {
962         ac[i] = c[i] - a[i];
963         ad[i] = d[i] - a[i];
964         bc[i] = c[i] - b[i];
965         bd[i] = d[i] - b[i];
966       }
967 
968       cs_real_t lac = cs_math_3_norm(ac);
969       cs_real_t lad = cs_math_3_norm(ad);
970       cs_real_t lbc = cs_math_3_norm(bc);
971       cs_real_t lbd = cs_math_3_norm(bd);
972 
973       cs_real_t lac_inside = _plane_segment_intersection(a, c, plane);
974       cs_real_t lad_inside = _plane_segment_intersection(a, d, plane);
975       cs_real_t lbc_inside = _plane_segment_intersection(b, c, plane);
976       cs_real_t lbd_inside = _plane_segment_intersection(b, d, plane);
977 
978       cs_real_t lac_frac = lac_inside / lac;
979       cs_real_t lad_frac = lad_inside / lad;
980       cs_real_t lbc_frac = lbc_inside / lbc;
981       cs_real_t lbd_frac = lbd_inside / lbd;
982 
983       cs_real_t ac_inter[3], ad_inter[3], bc_inter[3], bd_inter[3];
984       /* Coordinates of the intersection point between the tetra and the plane */
985       for (int i = 0; i < 3; i++) {
986         ac_inter[i] = a[i] + lac_frac * ac[i];
987         ad_inter[i] = a[i] + lad_frac * ad[i];
988         bc_inter[i] = b[i] + lbc_frac * bc[i];
989         bd_inter[i] = b[i] + lbd_frac * bd[i];
990       }
991 
992       vol = _prism_vol(a, b, ac_inter, bc_inter, bd_inter, ad_inter);
993 
994       break;
995     }
996 
997     case 4:
998       vol = 0.0;
999       break;
1000 
1001     default:
1002       bft_error(__FILE__, __LINE__, 0,
1003                 "Error in function _tetrahedra_plane_volume_intersection\n");
1004       break;
1005   }
1006 
1007   return vol;
1008 
1009 }
1010 /*----------------------------------------------------------------------------
1011  * Function to update the copy of the mesh at initialization
1012  * (necessary is the STL mesh needs to move with time)
1013  *
1014  * parameters:
1015  *   stl_mesh      <-- a STL mesh structure
1016   ----------------------------------------------------------------------------*/
1017 
1018 static void
_update_init_mesh(cs_stl_mesh_t * stl_mesh)1019 _update_init_mesh(cs_stl_mesh_t *stl_mesh)
1020 {
1021   cs_lnum_t n_tria = stl_mesh->n_faces;
1022   cs_lnum_t n_points = n_tria*3;
1023 
1024   for (cs_lnum_t i = 0; i < n_points; i++) {
1025     for (int j = 0; j < 3; j++) {
1026       stl_mesh->coords_ini[i][j] = stl_mesh->coords[i][j];
1027     }
1028   }
1029 
1030 }
1031 
1032 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
1033 
1034 /*=============================================================================
1035  * Public function definitions
1036  *============================================================================*/
1037 
1038 /*----------------------------------------------------------------------------*/
1039 /*!
1040  * \brief Add a new STL mesh structure.
1041  *
1042  * \param[in] name name of the STL mesh
1043  *
1044  * \return pointer to the new STL mesh structure
1045  */
1046 /*----------------------------------------------------------------------------*/
1047 
1048 cs_stl_mesh_t *
cs_stl_mesh_add(const char * name)1049 cs_stl_mesh_add(const char  *name)
1050 {
1051   /* First check if it already exists */
1052   cs_stl_mesh_t  *stl_mesh = cs_stl_mesh_get_by_name(name);
1053 
1054   if (stl_mesh != NULL) {
1055     // The STL mesh already exists
1056     bft_error(__FILE__, __LINE__, 0,
1057               _("Error creating stl mesh: mesh %s already exists."), name);
1058 
1059   }
1060   else {
1061     // If it does not exists create it
1062     _stl_meshes.n_meshes++;
1063     BFT_REALLOC(_stl_meshes.mesh_list, _stl_meshes.n_meshes, cs_stl_mesh_t *);
1064 
1065     BFT_MALLOC(stl_mesh, 1, cs_stl_mesh_t);
1066 
1067     if (name != NULL) {
1068       strncpy(stl_mesh->name, name, 19);
1069       stl_mesh->name[19] = '\0';
1070     }
1071     else
1072       bft_error(__FILE__, __LINE__, 0,
1073                 _("Error creating stl mesh: no name given."));
1074 
1075     memset(stl_mesh->header, 0, 80);
1076     stl_mesh->n_faces = 0;
1077     stl_mesh->coords = NULL;
1078     stl_mesh->n_seeds = 0;
1079     stl_mesh->seed_coords = NULL;
1080     stl_mesh->is_porous = false;
1081     stl_mesh->ext_mesh = NULL;
1082 
1083     _stl_meshes.mesh_list[_stl_meshes.n_meshes - 1] = stl_mesh;
1084   }
1085 
1086   return stl_mesh;
1087 }
1088 
1089 /*----------------------------------------------------------------------------*/
1090 /*!
1091  * \brief Return a pointer to a STL mesh based on its name if present.
1092  *
1093  * \param[in] name name of the STL mesh
1094  *
1095  * If no STL mesh of the given name is defined, NULL is returned.
1096  *
1097  * \return pointer to the STL mesh structure, or NULL
1098  */
1099 /*----------------------------------------------------------------------------*/
1100 
1101 cs_stl_mesh_t *
cs_stl_mesh_get_by_name(const char * name)1102 cs_stl_mesh_get_by_name(const char  *name)
1103 {
1104   cs_stl_mesh_t *ptr = NULL;
1105 
1106   for (int s_id = 0; s_id < _stl_meshes.n_meshes; s_id ++) {
1107     cs_stl_mesh_t *stl_mesh = _stl_meshes.mesh_list[s_id];
1108     int test = strcmp(stl_mesh->name, name);
1109     if (test == 0)
1110       ptr = stl_mesh;
1111   }
1112 
1113   return ptr;
1114 }
1115 
1116 /*----------------------------------------------------------------------------*/
1117 /*!
1118  * \brief  Free all allocated STL mesh structures
1119  */
1120 /*----------------------------------------------------------------------------*/
1121 
1122 void
cs_stl_mesh_destroy_all(void)1123 cs_stl_mesh_destroy_all(void)
1124 {
1125   for (int s_id = 0; s_id < _stl_meshes.n_meshes; s_id ++) {
1126     cs_stl_mesh_t *ptr = _stl_meshes.mesh_list[s_id];
1127     BFT_FREE(ptr->coords);
1128     BFT_FREE(ptr->coords_ini);
1129     BFT_FREE(ptr->seed_coords);
1130   }
1131 
1132   BFT_FREE(_stl_meshes.mesh_list);
1133 }
1134 
1135 /*----------------------------------------------------------------------------*/
1136 /*!
1137  * \brief Read a binary STL file and store its content in a STL mesh structure
1138  *
1139  * Each STL file composed of the following header:
1140  *
1141  * uint8[80] – Header
1142  * uint32 – Number of triangles
1143  *
1144  * followed by 50 byte blocks for each triangle:
1145  *
1146  * - real32[3] – Normal vector
1147  * - real32[3] – Vertex 1 coordinates
1148  * - real32[3] – Vertex 2 coordinates
1149  * - real32[3] – Vertex 3 coordiantes
1150  * - uint16    – Attribute (any other information, usually void)
1151  *
1152  * \param[in] path     path to the STL file
1153  * \param[in] stl_mesh pointer to the associated STL mesh structure
1154  */
1155 /*----------------------------------------------------------------------------*/
1156 
1157 void
cs_stl_file_read(cs_stl_mesh_t * stl_mesh,const char * path)1158 cs_stl_file_read(cs_stl_mesh_t  *stl_mesh,
1159                  const char     *path)
1160 {
1161   uint8_t buf[128];
1162   FILE *fp;
1163   float *loc_coords = NULL;
1164 
1165   cs_lnum_t n_tria = 0;
1166   cs_lnum_t n_tria_new = 0;
1167 
1168   if (cs_glob_rank_id < 1) {
1169 
1170     /* Open STL file */
1171     fp = fopen(path, "rb");
1172     if (fp == NULL) {
1173       bft_error(__FILE__, __LINE__, 0,
1174                 _("Error opening file \"%s\":\n\n"
1175                   "  %s"), path, strerror(errno));
1176     }
1177 
1178     /* Check if the file is ASCII or Binary */
1179     char temp[6] ;
1180     fread(temp, 5, 1, fp);
1181     temp[5] = '\0';
1182     int test = strcmp(temp, "solid");
1183 
1184     if (test == 0)
1185       bft_error(__FILE__, __LINE__, 0,
1186                 _("Error opening file \"%s\":\n"
1187                   "You are probably tyring to open an ASCII STL file\n"
1188                   "Please convert your file to binary :-)"), path);
1189 
1190 
1191     /* Read and copy header */
1192     rewind(fp);
1193     fread(buf, 84, 1, fp);
1194     memcpy(stl_mesh->header, buf, 80);
1195 
1196     /* Read number of triangles */
1197     uint32_t ntri;
1198     ntri = _cast32(buf+80);
1199     n_tria = (int)ntri;
1200 
1201     stl_mesh->n_faces = n_tria;
1202 
1203     /* Allocation*/
1204     BFT_MALLOC(stl_mesh->coords     , 3*n_tria, cs_real_3_t);
1205     BFT_MALLOC(loc_coords , 9, float);
1206 
1207     /* Loop on triangle faces
1208        ---------------------- */
1209     for (uint32_t i = 0; i < ntri; i++) {
1210 
1211       // Each triangle data are contained in 50bytes blocks
1212       fread(buf, 50, 1, fp);
1213       uint8_t *start = buf + 12;
1214 
1215       // Read the 3 vertices for the current triangle
1216       for (uint32_t vi = 0; vi < 3; vi ++) {
1217 
1218         // Read the 3 coordinates for each vertex
1219         for (cs_lnum_t dir = 0; dir < 3; dir ++) {
1220 
1221           uint32_t v_temp = _cast32(start + 3*4*vi + 4*dir);
1222           float *dir_coo = (float *)(&v_temp);
1223           loc_coords[3*vi + dir] = *dir_coo;
1224         }
1225       }
1226 
1227       // Check if the current triangle has a null area
1228 
1229       cs_real_t a[3], b[3], c[3], n[3];
1230 
1231       for (int dir = 0; dir < 3; dir ++) {
1232         a[dir] = (cs_real_t)loc_coords[3*0 + dir];
1233         b[dir] = (cs_real_t)loc_coords[3*1 + dir];
1234         c[dir] = (cs_real_t)loc_coords[3*2 + dir];
1235       }
1236 
1237       n[0] = (b[1]-a[1])*(c[2]-a[2]) - (b[2]-a[2])*(c[1]-a[1]);
1238       n[1] = (b[2]-a[2])*(c[0]-a[0]) - (b[0]-a[0])*(c[2]-a[2]);
1239       n[2] = (b[0]-a[0])*(c[1]-a[1]) - (b[1]-a[1])*(c[0]-a[0]);
1240 
1241       cs_real_t nn = cs_math_3_norm(n);
1242 
1243       if (nn > 1.e-20) {
1244         for (cs_lnum_t dir = 0; dir < 3; dir ++) {
1245           for (cs_lnum_t vi = 0; vi < 3; vi ++) {
1246             stl_mesh->coords[3*n_tria_new + vi][dir]
1247               = (cs_real_t)loc_coords[3*vi + dir];
1248           }
1249         }
1250         n_tria_new ++;
1251       }
1252 
1253     }
1254 
1255     /* Some log information */
1256     bft_printf(_("\n"
1257                  " ** Reading of STL mesh \"%s\"\n"
1258                  "    Number of triangles: %d\n"
1259                  "    Number of removed triangles: %d\n\n"),
1260                stl_mesh->name, (int)n_tria_new, (int)n_tria-n_tria_new);
1261 
1262     n_tria = n_tria_new;
1263     stl_mesh->n_faces = n_tria;
1264 
1265     /* Re-allocation*/
1266     BFT_REALLOC(stl_mesh->coords    , 3*n_tria, cs_real_3_t);
1267 
1268     /* Copy coordinates to a work aray that
1269      * will contain all the init coordinates */
1270     BFT_MALLOC(stl_mesh->coords_ini , 3*n_tria, cs_real_3_t);
1271     for (int i = 0; i < 3*n_tria; i++)
1272       for (int j = 0; j < 3; j++)
1273         stl_mesh->coords_ini[i][j] = stl_mesh->coords[i][j];
1274 
1275     BFT_FREE(loc_coords);
1276     fclose(fp);
1277 
1278   }
1279 
1280   /* Broadcast to other ranks */
1281 
1282   cs_parall_bcast(0, /* root_rank */
1283                   1,
1284                   CS_LNUM_TYPE,
1285                   &(stl_mesh->n_faces));
1286 
1287   if (cs_glob_rank_id > 0) {
1288     BFT_MALLOC(stl_mesh->coords    , stl_mesh->n_faces*3, cs_real_3_t);
1289     BFT_MALLOC(stl_mesh->coords_ini, stl_mesh->n_faces*3, cs_real_3_t);
1290   }
1291 
1292   cs_parall_bcast(0, /* root_rank */
1293                   stl_mesh->n_faces*9,
1294                   CS_REAL_TYPE,
1295                   stl_mesh->coords);
1296 
1297   cs_parall_bcast(0, /* root_rank */
1298                   stl_mesh->n_faces*9,
1299                   CS_REAL_TYPE,
1300                   stl_mesh->coords_ini);
1301 
1302 
1303   /* Merge identical vertices
1304      ------------------------ */
1305 
1306 #if 0
1307   cs_lnum_t n_coo_ini = n_tria*3;
1308 
1309   cs_coord_t *_face_vtx_coord = NULL;
1310   BFT_MALLOC(_face_vtx_coord, n_coo_ini*3, cs_coord_t);
1311   for (cs_lnum_t i = 0; i < n_coo_ini*3; i++)
1312     _face_vtx_coord[i] = stl_mesh->coords[i];
1313 
1314   fvm_io_num_t *v_io_num = fvm_io_num_create_from_sfc(_face_vtx_coord,
1315                                                       3,
1316                                                       n_coo_ini,
1317                                                       FVM_IO_NUM_SFC_MORTON_BOX);
1318 
1319   BFT_FREE(_face_vtx_coord);
1320 
1321   cs_gnum_t *vtx_gnum = fvm_io_num_transfer_global_num(v_io_num);
1322 
1323   cs_lnum_t *order = cs_order_gnum(NULL, vtx_gnum, n_coo_ini);
1324 
1325   v_io_num = fvm_io_num_destroy(v_io_num);
1326 
1327   cs_coord_t  *vertex_coord = NULL;
1328   cs_lnum_t  *vertex_num = NULL;
1329 
1330   if (cs_glob_rank_id < 1) {
1331 
1332     BFT_MALLOC(vertex_coord, n_coo_ini*3, cs_coord_t);
1333     BFT_MALLOC(vertex_num, n_tria*3, cs_lnum_t);
1334 
1335     for (cs_lnum_t i = 0; i < n_coo_ini; i++)
1336       vertex_num[i] = -1;
1337 
1338     cs_lnum_t n_coo_new = 0;
1339     for (cs_lnum_t i = 0; i < n_coo_ini; i++) {
1340       cs_lnum_t j = order[i];
1341       vertex_num[j] = n_coo_new + 1;
1342       bool identical = false;
1343       if (! identical) {
1344         for (cs_lnum_t k = 0; k < 3; k++)
1345           vertex_coord[n_coo_new*3 + k] = stl_mesh->coords[j*3 + k];
1346         n_coo_new++;
1347       }
1348     }
1349 
1350     BFT_REALLOC(vertex_coord, n_coo_new*3, cs_coord_t);
1351 
1352   }
1353 #endif
1354 
1355   cs_coord_3_t *vertex_coord = NULL;
1356   cs_lnum_t  *vertex_num   = NULL;
1357   cs_gnum_t  *vertex_gnum  = NULL;
1358   cs_gnum_t  *faces_gnum   = NULL;
1359 
1360   if (cs_glob_rank_id < 1) {
1361     BFT_MALLOC(vertex_coord, n_tria*3, cs_coord_3_t);
1362     BFT_MALLOC(vertex_num  , n_tria*3, cs_lnum_t);
1363     BFT_MALLOC(vertex_gnum , n_tria*3, cs_gnum_t);
1364     BFT_MALLOC(faces_gnum  , n_tria,   cs_gnum_t);
1365 
1366     for (cs_lnum_t j = 0; j < n_tria*3; j++) {
1367       vertex_num[j] = j+1;
1368       vertex_gnum[j] = j+1;
1369       for (cs_lnum_t k = 0; k < 3; k++)
1370         vertex_coord[j][k] = stl_mesh->coords[j][k];
1371     }
1372     for (cs_lnum_t j = 0; j < n_tria; j++)
1373       faces_gnum[j] = j+1;
1374 
1375   }
1376 
1377   fvm_nodal_t *ext_mesh = fvm_nodal_create(stl_mesh->name, 3);
1378 
1379   /* Generate FVM structure */
1380 
1381   fvm_nodal_append_by_transfer(ext_mesh,
1382                                n_tria,
1383                                FVM_FACE_TRIA,
1384                                NULL,
1385                                NULL,
1386                                NULL,
1387                                vertex_num,
1388                                NULL);
1389 
1390   if (cs_glob_rank_id < 1) {
1391     fvm_nodal_set_shared_vertices(ext_mesh, (const cs_coord_t *)stl_mesh->coords);
1392   } else {
1393     fvm_nodal_set_shared_vertices(ext_mesh, NULL);
1394   }
1395 
1396   fvm_nodal_init_io_num(ext_mesh, faces_gnum , 2);
1397   fvm_nodal_init_io_num(ext_mesh, vertex_gnum, 0);
1398 
1399   stl_mesh->ext_mesh = ext_mesh;
1400 
1401   if (cs_glob_rank_id < 1) {
1402     BFT_FREE(vertex_gnum);
1403     BFT_FREE(faces_gnum);
1404   }
1405 }
1406 
1407 /*----------------------------------------------------------------------------*/
1408 /*!
1409  * \brief Apply a transformation matrix to a STL mesh structure.
1410  *
1411  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1412  * \param[in]  matrix          transformation matrix
1413  */
1414 /*----------------------------------------------------------------------------*/
1415 
1416 void
cs_stl_mesh_transform(cs_stl_mesh_t * stl_mesh,double matrix[3][4])1417 cs_stl_mesh_transform(cs_stl_mesh_t  *stl_mesh,
1418                       double          matrix[3][4])
1419 {
1420   cs_lnum_t n_tria = stl_mesh->n_faces;
1421   cs_lnum_t n_points = n_tria*3;
1422 
1423   for (cs_lnum_t i = 0; i < n_points; i++) {
1424 
1425     cs_real_t *c = stl_mesh->coords[i];
1426 
1427     double  c_a[4] = {c[0], c[1], c[2], 1.}; /* homogeneous coords */
1428     double  c_b[3] = {0, 0, 0};
1429 
1430     for (cs_lnum_t j = 0; j < 3; j++)
1431       for (int k = 0; k < 4; k++)
1432         c_b[j] += matrix[j][k]*c_a[k];
1433 
1434     for (cs_lnum_t j = 0; j < 3; j++)
1435       c[j] = c_b[j];
1436 
1437   }
1438 
1439   _update_init_mesh(stl_mesh);
1440 
1441 }
1442 
1443 /*----------------------------------------------------------------------------*/
1444 /*!
1445  * \brief Apply a transformation matrix to a STL mesh structure, but use
1446  * \brief the initial coordinates as inputs
1447  *
1448  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1449  * \param[in]  matrix          transformation matrix
1450  */
1451 /*----------------------------------------------------------------------------*/
1452 
1453 void
cs_stl_mesh_transform_from_init(cs_stl_mesh_t * stl_mesh,double matrix[3][4])1454 cs_stl_mesh_transform_from_init(cs_stl_mesh_t  *stl_mesh,
1455                                 double          matrix[3][4])
1456 {
1457   cs_lnum_t n_tria = stl_mesh->n_faces;
1458   cs_lnum_t n_points = n_tria*3;
1459 
1460   for (cs_lnum_t i = 0; i < n_points; i++) {
1461 
1462     cs_real_t *c = stl_mesh->coords[i];
1463     cs_real_t *ci = stl_mesh->coords_ini[i];
1464 
1465     double  c_a[4] = {ci[0], ci[1], ci[2], 1.}; /* homogeneous coords */
1466     double  c_b[3] = {0, 0, 0};
1467 
1468     for (cs_lnum_t j = 0; j < 3; j++)
1469       for (int k = 0; k < 4; k++)
1470         c_b[j] += matrix[j][k]*c_a[k];
1471 
1472     for (cs_lnum_t j = 0; j < 3; j++)
1473       c[j] = c_b[j];
1474 
1475   }
1476 }
1477 
1478 /*----------------------------------------------------------------------------*/
1479 /*!
1480  * \brief Apply a translation to a STL mesh structure.
1481  *
1482  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1483  * \param[in]  vector          translation vector
1484  */
1485 /*----------------------------------------------------------------------------*/
1486 
1487 void
cs_stl_mesh_translate(cs_stl_mesh_t * stl_mesh,cs_real_t vector[3])1488 cs_stl_mesh_translate(cs_stl_mesh_t  *stl_mesh,
1489                       cs_real_t      vector[3])
1490 {
1491   cs_lnum_t n_tria = stl_mesh->n_faces;
1492   cs_lnum_t n_points = n_tria*3;
1493 
1494   for (cs_lnum_t i = 0; i < n_points; i++) {
1495     for (cs_lnum_t j = 0; j < 3; j++) {
1496       stl_mesh->coords[i][j] += vector[j];
1497     }
1498   }
1499 
1500   _update_init_mesh(stl_mesh);
1501 
1502 }
1503 
1504 /*----------------------------------------------------------------------------*/
1505 /*!
1506  * \brief Apply a rotation to a STL mesh structure.
1507  *
1508  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1509  * \param[in]  theta           rotation angle
1510  * \param[in]  axis            rotation axis
1511  * \param[in]  center          rotation center
1512  */
1513 /*----------------------------------------------------------------------------*/
1514 
1515 void
cs_stl_mesh_rotate(cs_stl_mesh_t * stl_mesh,double theta,double axis[3],double center[3])1516 cs_stl_mesh_rotate(cs_stl_mesh_t  *stl_mesh,
1517                    double          theta,
1518                    double          axis[3],
1519                    double          center[3])
1520 {
1521   double matrix[3][4];
1522 
1523   cs_rotation_matrix(theta, axis, center, matrix);
1524 
1525   cs_stl_mesh_transform(stl_mesh, matrix);
1526 }
1527 
1528 /*----------------------------------------------------------------------------*/
1529 /*!
1530  * \brief Apply a scaling to a STL mesh structure.
1531  *
1532  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1533  * \param[in]  vector          translation vector
1534  */
1535 /*----------------------------------------------------------------------------*/
1536 
1537 void
cs_stl_mesh_scale(cs_stl_mesh_t * stl_mesh,double scale)1538 cs_stl_mesh_scale(cs_stl_mesh_t  *stl_mesh,
1539                   double          scale)
1540 {
1541   cs_lnum_t n_tria = stl_mesh->n_faces;
1542   cs_lnum_t n_points = n_tria*3;
1543 
1544   for (cs_lnum_t i = 0; i < n_points; i++) {
1545     for (cs_lnum_t j = 0; j < 3; j++) {
1546       stl_mesh->coords[i][j] *= scale;
1547     }
1548   }
1549 }
1550 
1551 /*----------------------------------------------------------------------------*/
1552 /*!
1553  * \brief Set the points outside he STL geometry. Those points will be used as
1554  * \brief seeds to propagate porosity values outside the STL geometry.
1555  *
1556  * \param[in]  stl_mesh  pointer to the associated STL mesh structure
1557  * \param[in]  n_points  number of points
1558  * \param[in]  coords    coordinates (x1,y1,z1,...,xn,yn,zn) (size : 3*n_point)
1559  */
1560 /*----------------------------------------------------------------------------*/
1561 
1562 void
cs_stl_set_porosity_seed(cs_stl_mesh_t * stl_mesh,int n_points,cs_real_t * coords)1563 cs_stl_set_porosity_seed(cs_stl_mesh_t  *stl_mesh,
1564                          int            n_points,
1565                          cs_real_t      *coords)
1566 {
1567   stl_mesh->n_seeds = n_points;
1568   BFT_REALLOC(stl_mesh->seed_coords, n_points*3, cs_real_t);
1569 
1570   for (int i = 0; i < 3*n_points; i++)
1571     stl_mesh->seed_coords[i] = coords[i];
1572 }
1573 
1574 /*----------------------------------------------------------------------------*/
1575 /*!
1576  * \brief Return writer_id used for stl meshes. 0 means unused.
1577  */
1578 /*----------------------------------------------------------------------------*/
1579 
1580 int
cs_stl_post_get_writer_id(void)1581 cs_stl_post_get_writer_id(void)
1582 {
1583 
1584   return _stl_meshes.writer_id;
1585 
1586 }
1587 
1588 /*----------------------------------------------------------------------------*/
1589 /*!
1590  * \brief Create a new writer that will contains the STL mesh added by the user
1591  * \brief The writer_id is stored in the cs_glob_stl_meshes structure.
1592  *
1593  * \param[in]  time_dep > 1 if the writer is transient, else writer is fixed
1594  */
1595 /*----------------------------------------------------------------------------*/
1596 
1597 void
cs_stl_post_init_writer(const char * case_name,const char * dir_name,const char * fmt_name,const char * fmt_opts,fvm_writer_time_dep_t time_dep,bool output_at_start,bool output_at_end,int frequency_n,double frequency_t)1598 cs_stl_post_init_writer(const char             *case_name,
1599                         const char             *dir_name,
1600                         const char             *fmt_name,
1601                         const char             *fmt_opts,
1602                         fvm_writer_time_dep_t   time_dep,
1603                         bool                    output_at_start,
1604                         bool                    output_at_end,
1605                         int                     frequency_n,
1606                         double                  frequency_t)
1607 {
1608   /* We check if a writer_id has already been defined.*/
1609   bool writer_exists = false;
1610   if ( _stl_meshes.writer_id != 0)
1611     writer_exists = true;
1612 
1613   /* If a writer do no already exist, create it */
1614   if (!writer_exists) {
1615     int writer_id = cs_post_get_free_writer_id();
1616     _stl_meshes.writer_id = writer_id;
1617 
1618     /* Add writer  */
1619     cs_post_define_writer(writer_id,       /* writer_id */
1620                           case_name,       /* writer name */
1621                           dir_name,        /* directory name */
1622                           fmt_name,        /* format_name */
1623                           fmt_opts,        /* format_options */
1624                           time_dep,
1625                           output_at_start, /* output_at_start */
1626                           output_at_end,   /* output_at_end */
1627                           frequency_n,     /* frequency_n */
1628                           frequency_t);    /* frequency_t */
1629   }
1630 }
1631 
1632 /*----------------------------------------------------------------------------*/
1633 /*!
1634  * \brief Associate a STL mesh to the default writer
1635  *
1636  * \param[in]  stl_mesh  pointer to the associated STL mesh structure
1637  */
1638 /*----------------------------------------------------------------------------*/
1639 
1640 void
cs_stl_post_add_mesh(cs_stl_mesh_t * stl_mesh)1641 cs_stl_post_add_mesh(cs_stl_mesh_t  *stl_mesh)
1642 {
1643   if (_stl_meshes.writer_id == 0)
1644     bft_error(__FILE__, __LINE__, 0,
1645               _("No writer was defined for STL mesh output\n"
1646                 "cs_stl_post_init_writer should be called first.\n"));
1647 
1648   int writer_ids[] = {_stl_meshes.writer_id};
1649   int stl_mesh_id = cs_post_get_free_mesh_id();
1650   cs_post_define_existing_mesh(stl_mesh_id,
1651                                stl_mesh->ext_mesh,
1652                                0,
1653                                true,
1654                                false,
1655                                1,
1656                                writer_ids);
1657 
1658   cs_post_write_meshes(NULL);
1659 }
1660 
1661 /*----------------------------------------------------------------------------*/
1662 /*!
1663  * \brief Write a binary STL file according to a given STL mesh structure
1664  *
1665  * \param[in]  stl_mesh  pointer to the associated STL mesh structure
1666  * \param[in]  path      path to the STL file
1667  */
1668 /*----------------------------------------------------------------------------*/
1669 
1670 void
cs_stl_file_write(cs_stl_mesh_t * stl_mesh,const char * path)1671 cs_stl_file_write(cs_stl_mesh_t  *stl_mesh,
1672                   const char     *path)
1673 {
1674   /* Output only on rank 0 for now */
1675   if (cs_glob_rank_id > 0)
1676     return;
1677 
1678   uint8_t buf[128];
1679   FILE *fp;
1680 
1681   /* Open STL file */
1682   fp = fopen(path,"wb");
1683   if (fp == NULL) {
1684       bft_error(__FILE__, __LINE__, 0,
1685                 _("Error opening file \"%s\":\n\n"
1686                   "  %s"), path, strerror(errno));
1687   }
1688 
1689   /* Write header */
1690   char header[80] = "Exported from code_saturne";
1691   memcpy(buf, header, 80);
1692 
1693   /* Cut number of triangles in 4 8bytes unsigned int */
1694   uint32_t ntri = (uint32_t)stl_mesh->n_faces;
1695   _cut32(buf+80,ntri);
1696 
1697   fwrite(buf, 84, 1, fp);
1698 
1699   /* Loop on each triangle */
1700   for (int i = 0; i < stl_mesh->n_faces; i++) {
1701 
1702     uint8_t *start = buf + 12;
1703 
1704     /* Compute and Write the face normal coordinates */
1705     float normals[3];
1706     float a[3], b[3], c[3];
1707 
1708     for (int dir = 0; dir < 3; dir ++) {
1709       a[dir] = (float)stl_mesh->coords[3*i + 0][dir];
1710       b[dir] = (float)stl_mesh->coords[3*i + 1][dir];
1711       c[dir] = (float)stl_mesh->coords[3*i + 2][dir];
1712     }
1713 
1714     // ab vect ac
1715     normals[0] = (b[1]-a[1])*(c[2]-a[2]) - (b[2]-a[2])*(c[1]-a[1]);
1716     normals[1] = (b[2]-a[2])*(c[0]-a[0]) - (b[0]-a[0])*(c[2]-a[2]);
1717     normals[2] = (b[0]-a[0])*(c[1]-a[1]) - (b[1]-a[1])*(c[0]-a[0]);
1718 
1719     float norm = sqrt(  normals[0]*normals[0]
1720                       + normals[1]*normals[1]
1721                       + normals[2]*normals[2]);
1722 
1723     for (int dir = 0; dir < 3; dir ++)
1724       normals[dir] /= norm;
1725 
1726     uint32_t n_temp[3];
1727     for (int dir = 0; dir < 3; dir ++) {
1728       memcpy(&n_temp[dir],
1729              &normals[dir],
1730              sizeof n_temp[dir]);
1731 
1732       _cut32(buf + 4*dir, n_temp[dir]);
1733     }
1734 
1735     /* Write the 3 vertices for the current triangle */
1736     for (int vi = 0; vi < 3; vi ++) {
1737 
1738       uint32_t v_temp[3];
1739       for (int dir = 0; dir < 3; dir ++) {
1740         float loc_coord = (float)stl_mesh->coords[3*i + vi][dir];
1741         memcpy(&v_temp[dir],
1742                &loc_coord,
1743                sizeof v_temp[dir]);
1744         _cut32(start + 3*4*vi + 4*dir, v_temp[dir]);
1745       }
1746     }
1747 
1748     fwrite(buf, 50, 1, fp);
1749   }
1750 
1751   fclose(fp);
1752 }
1753 
1754 /*----------------------------------------------------------------------------*/
1755 /*!
1756  * \brief Compute intersection between a STL mesh and the main mesh.
1757  *
1758  * \param[in]     stl_mesh         pointer to the associated STL mesh structure
1759  * \param[in]     n_input          number of cells on which intersection is done
1760  * \param[in]     input_idx        index of input cells (size: input_idx)
1761  * \param[out]    n_selected_cells number of output intersecting cells
1762  * \param[out]    selected_cells   index of output cells (size: output_idx)
1763  * \param[out]    tria_in_cell_idx start index of triangle intersecting each cell
1764  *                                  (size: n_output)
1765  * \param[out]    tria_in_cell_lst list of triangles in intersecting cells
1766  * \param[in,out] max_size         maximum size of tria_in_cell_lst array
1767  */
1768 /*----------------------------------------------------------------------------*/
1769 
1770 void
cs_stl_intersection(cs_stl_mesh_t * stl_mesh,cs_lnum_t n_input,cs_lnum_t * input_idx,cs_lnum_t * n_selected_cells,cs_lnum_t * selected_cells,cs_lnum_t * tria_in_cell_idx,cs_lnum_t ** tria_in_cell_lst,cs_lnum_t * max_size)1771 cs_stl_intersection(cs_stl_mesh_t *stl_mesh,
1772                     cs_lnum_t     n_input,
1773                     cs_lnum_t     *input_idx,
1774                     cs_lnum_t     *n_selected_cells,
1775                     cs_lnum_t     *selected_cells,
1776                     cs_lnum_t     *tria_in_cell_idx,
1777                     cs_lnum_t     **tria_in_cell_lst,
1778                     cs_lnum_t     *max_size)
1779 {
1780   cs_mesh_t *m = cs_glob_mesh;
1781 
1782   cs_lnum_t  n_cells = n_input;// Local number of cells of the main mesh
1783   cs_lnum_t  n_tria_stl = stl_mesh->n_faces; // Local number of triangles of the STL
1784   cs_lnum_t  n_boxes = n_cells + n_tria_stl;
1785   int dim = 3;
1786 
1787   cs_lnum_t *_tria_in_cell_lst = NULL;
1788   if (tria_in_cell_lst != NULL)
1789     _tria_in_cell_lst = *tria_in_cell_lst;
1790 
1791   cs_gnum_t *box_gnum = NULL;
1792   cs_coord_t *extents = NULL;
1793 
1794   BFT_MALLOC(box_gnum, n_boxes, cs_gnum_t);
1795   BFT_MALLOC(extents , 2*dim*n_boxes, cs_coord_t);
1796 
1797   /* Global numbering construction */
1798   for (cs_lnum_t i = 0; i < n_cells; i++)
1799     box_gnum[i] = i + 1;
1800 
1801   for (cs_lnum_t i = 0; i < n_tria_stl; i++)
1802     box_gnum[i + n_cells] = n_cells + i + 1;
1803 
1804 
1805   /* Compute extents */
1806 
1807   // For the main mesh
1808   cs_real_6_t *bbox = NULL;
1809   bbox = cs_mesh_quantities_cell_extents(m, 0.0);
1810 
1811   for (cs_lnum_t i = 0; i < n_cells; i++)
1812     for (int id = 0; id < 6; id ++)
1813       extents[6*i + id] = bbox[input_idx[i]][id];
1814 
1815   BFT_FREE(bbox);
1816 
1817   // For the STL mesh
1818   BFT_MALLOC(bbox, n_tria_stl, cs_real_6_t);
1819 
1820   for (cs_lnum_t i = 0; i < n_tria_stl; i++) {
1821     bbox[i][0] = HUGE_VAL;
1822     bbox[i][1] = HUGE_VAL;
1823     bbox[i][2] = HUGE_VAL;
1824     bbox[i][3] = -HUGE_VAL;
1825     bbox[i][4] = -HUGE_VAL;
1826     bbox[i][5] = -HUGE_VAL;
1827   }
1828 
1829   for (cs_lnum_t i = 0; i < n_tria_stl; i++) {
1830     for (int vtx_id = 0; vtx_id < 3; vtx_id ++) {
1831       bbox[i][0] = CS_MIN(bbox[i][0], stl_mesh->coords[3*i + vtx_id][0]);
1832       bbox[i][3] = CS_MAX(bbox[i][3], stl_mesh->coords[3*i + vtx_id][0]);
1833       bbox[i][1] = CS_MIN(bbox[i][1], stl_mesh->coords[3*i + vtx_id][1]);
1834       bbox[i][4] = CS_MAX(bbox[i][4], stl_mesh->coords[3*i + vtx_id][1]);
1835       bbox[i][2] = CS_MIN(bbox[i][2], stl_mesh->coords[3*i + vtx_id][2]);
1836       bbox[i][5] = CS_MAX(bbox[i][5], stl_mesh->coords[3*i + vtx_id][2]);
1837     }
1838   }
1839 
1840   for (cs_lnum_t i = 0; i < n_tria_stl; i++) {
1841     for (cs_lnum_t id = 0; id < 6; id ++)
1842       extents[6*(i+n_cells) + id] = bbox[i][id];
1843   }
1844 
1845   BFT_FREE(bbox);
1846 
1847   fvm_neighborhood_t  *cell_neighborhood = NULL;
1848 
1849 #if defined HAVE_MPI
1850   cell_neighborhood = fvm_neighborhood_create(MPI_COMM_NULL);
1851 #else
1852   cell_neighborhood = fvm_neighborhood_create();
1853 #endif
1854 
1855   // Compute intersections by boxes (transfer ownership)
1856   fvm_neighborhood_by_boxes( cell_neighborhood,
1857                              dim,
1858                              n_boxes,
1859                              box_gnum,
1860                              extents,
1861                              NULL,
1862                              NULL );
1863 
1864   cs_lnum_t  n_elts = 0;
1865   cs_gnum_t *elt_num = NULL;
1866   cs_lnum_t *neighbor_index = NULL;
1867   cs_gnum_t *neighbor_num = NULL;
1868 
1869   // Get the data back
1870   fvm_neighborhood_transfer_data( cell_neighborhood,
1871                                   &n_elts,
1872                                   &elt_num,
1873                                   &neighbor_index,
1874                                   &neighbor_num );
1875 
1876   cs_gnum_t _n_cells = n_cells;
1877   cs_lnum_t _n_selected_cells = 0;
1878   cs_lnum_t idx_num = 0;
1879 
1880   /* Init of list if needed */
1881   if (tria_in_cell_idx != NULL)
1882     tria_in_cell_idx[_n_selected_cells] = 0;
1883 
1884   /* Loop on the elements that have neighbors */
1885   for (cs_lnum_t i = 0; i < n_elts; i++) {
1886 
1887     // Check if the element is a box from the main mesh
1888     if (elt_num[i] <= _n_cells) {
1889 
1890       cs_lnum_t cell_id = elt_num[i] - 1;
1891       cs_lnum_t nb_tri_in_cell = 0;
1892 
1893       // Loop on the neighbors
1894       for (cs_lnum_t j = neighbor_index[i]; j < neighbor_index[i+1]; j++) {
1895 
1896         // If the current neighbor is a box from the STL,
1897         // -> the BB from the cell intersects the BB from
1898         // the STL
1899         if (neighbor_num[j] > _n_cells) {
1900 
1901           // Local number of the triangle
1902           cs_lnum_t ntria_id = neighbor_num[j] - n_cells - 1;
1903 
1904           cs_real_t tri_coords[3][3];
1905           for (cs_lnum_t k = 0; k < 3; k++) {
1906             for (cs_lnum_t l = 0; l < 3; l++)
1907               tri_coords[k][l] = stl_mesh->coords[3*ntria_id + k][l];
1908           }
1909 
1910           // Additional tests to know weather the triangle
1911           // overlap the cell bounding box
1912           bool triangle_box_intersect
1913             = _triangle_box_intersect(&extents[6*cell_id],
1914                                       tri_coords);
1915 
1916 
1917           if (triangle_box_intersect) {
1918             nb_tri_in_cell++;
1919             if (tria_in_cell_lst != NULL) {
1920               if (idx_num >= *max_size) {
1921                 *max_size *= 2;
1922                 BFT_REALLOC(_tria_in_cell_lst, *max_size, cs_lnum_t);
1923               }
1924               _tria_in_cell_lst[idx_num] = ntria_id;
1925               idx_num ++;
1926             }
1927 
1928           }
1929 
1930         }
1931 
1932       } // End loop on neighbors
1933 
1934       // If at least one time a triangle neigbor was found in the
1935       // previous loop, tag the cell.
1936       if (nb_tri_in_cell > 0) {
1937         selected_cells[_n_selected_cells] = input_idx[cell_id];
1938         if (tria_in_cell_idx != NULL)
1939           tria_in_cell_idx[_n_selected_cells + 1] = idx_num;
1940         _n_selected_cells ++;
1941       }
1942 
1943     }
1944   }
1945 
1946   *n_selected_cells  = _n_selected_cells;
1947   if (tria_in_cell_lst != NULL)
1948     *tria_in_cell_lst = _tria_in_cell_lst;
1949 
1950   fvm_neighborhood_destroy(&cell_neighborhood);
1951 
1952   BFT_FREE(elt_num);
1953   BFT_FREE(neighbor_index);
1954   BFT_FREE(neighbor_num);
1955   BFT_FREE(box_gnum);
1956   BFT_FREE(extents);
1957 }
1958 
1959 /*----------------------------------------------------------------------------*/
1960 /*!
1961  * \brief Refine the mesh following a given STL mesh
1962  *
1963  * \param[in]  stl_mesh        pointer to the associated STL mesh structure
1964  * \param[in]  n_ref           level of refinement
1965  * \param[in]  n_add_layer     additional layers between two refinement stage
1966  */
1967 /*----------------------------------------------------------------------------*/
1968 
1969 void
cs_stl_refine(cs_stl_mesh_t * stl_mesh,int n_ref,int n_add_layer)1970 cs_stl_refine(cs_stl_mesh_t *stl_mesh,
1971               int           n_ref,
1972               int           n_add_layer)
1973 {
1974   cs_mesh_t *m = cs_glob_mesh;
1975 
1976   /* Initialisation of the selection criteria (first level) */
1977   cs_lnum_t n_input_cells = m->n_cells;
1978   cs_lnum_t *input_cells = NULL;
1979   BFT_MALLOC(input_cells, m->n_cells, cs_lnum_t);
1980   for (cs_lnum_t i = 0; i < m->n_cells; i++)
1981     input_cells[i] = i;
1982 
1983    /* Begining of the refinement loop */
1984   for (int n_level = 0; n_level < n_ref+1; n_level ++) {
1985 
1986     if (cs_glob_rank_id < 1)
1987       bft_printf("Refinement %d\n",n_level);
1988 
1989     cs_lnum_t n_selected_cells = 0;
1990     cs_lnum_t *selected_cells = NULL;
1991     BFT_MALLOC(selected_cells, m->n_cells, cs_lnum_t);
1992 
1993     /* Select previous refined cells */
1994     if (n_level > 0) {
1995        BFT_REALLOC(input_cells, m->n_cells, cs_lnum_t);
1996 
1997       char criteria[100];
1998       sprintf(criteria,"STL_refined_region_%d",n_level-1);
1999       cs_selector_get_cell_list(criteria,
2000                                 &n_input_cells,
2001                                 input_cells  );
2002     }
2003 
2004     /* Compute mesh/STL intersection  */
2005     cs_stl_intersection( stl_mesh,
2006                          n_input_cells,
2007                          input_cells,
2008                          &n_selected_cells,
2009                          selected_cells,
2010                          NULL,
2011                          NULL,
2012                          NULL);
2013 
2014     /* If no intersected cells, do not perform refinement */
2015     cs_lnum_t n_intersected_cells = n_selected_cells;
2016     cs_parall_sum(1, CS_LNUM_TYPE, &n_intersected_cells);
2017     if (n_intersected_cells == 0)
2018       bft_error(__FILE__, __LINE__, 0,
2019                 "Error in function cs_stl_refine: no intersection\n"
2020                 "detected between the given STL file and the main mesh \n");
2021 
2022     /* Add incremented group */
2023     char group_name[100];
2024     sprintf(group_name,"STL_refined_region_%d",n_level);
2025     cs_mesh_group_cells_add(m,
2026                             group_name,
2027                             n_selected_cells,
2028                             selected_cells);
2029 
2030     /* Perform refinement */
2031     if (n_level < n_ref) {
2032 
2033       int *cell_tag;
2034       BFT_MALLOC(cell_tag, m->n_cells_with_ghosts, int);
2035 
2036       for (cs_lnum_t c_id = 0; c_id < m->n_cells; c_id ++) {
2037         cell_tag[c_id] = 0;
2038         for (cs_lnum_t i = 0; i < n_selected_cells; i++) {
2039           if (c_id == selected_cells[i]) cell_tag[c_id] = 1;
2040         }
2041       }
2042 
2043       if (m->halo!=NULL) {
2044         cs_halo_set_use_barrier(1);
2045         cs_halo_sync_num(m->halo, CS_HALO_STANDARD, cell_tag);
2046       }
2047 
2048       /* Here we add additionnal layers of refined cells
2049        * around the original STL selected cells */
2050       int nn = 1;
2051 
2052       for (int k = 0; k < n_add_layer ; k++){
2053         for (cs_lnum_t face_id = 0; face_id < m->n_i_faces; face_id++){
2054           cs_lnum_t c1 = m->i_face_cells[face_id][0];
2055           cs_lnum_t c2 = m->i_face_cells[face_id][1];
2056           if (cell_tag[c1] == 0 && cell_tag[c2] == nn)
2057             cell_tag[c1] = nn+1;
2058           if (cell_tag[c2] == 0 && cell_tag[c1] == nn)
2059             cell_tag[c2] = nn+1;
2060         }
2061 
2062         if (m->halo!=NULL)
2063           cs_halo_sync_num(m->halo, CS_HALO_STANDARD, cell_tag);
2064         nn ++;
2065       }
2066 
2067       n_selected_cells = 0;
2068       for (cs_lnum_t c_id = 0; c_id < m->n_cells; c_id ++) {
2069         if (cell_tag[c_id] > 0) {
2070           selected_cells[n_selected_cells] = c_id;
2071           n_selected_cells ++;
2072         }
2073       }
2074 
2075       BFT_FREE(cell_tag);
2076 
2077       cs_mesh_refine_simple_selected(m,
2078                                      false,
2079                                      n_selected_cells,
2080                                      selected_cells);
2081     }
2082 
2083     BFT_FREE(selected_cells);
2084 
2085     /* Every 2 refinemet stages and at the end, re-partition
2086      * the mesh to limit imbalance in the processors load */
2087 
2088     if ((n_level%2 == 0 || n_level == n_ref -1)
2089         && cs_glob_rank_id > -1) {
2090 
2091       cs_mesh_builder_destroy(&cs_glob_mesh_builder);
2092       cs_glob_mesh_builder = cs_mesh_builder_create();
2093       cs_mesh_to_builder(m, cs_glob_mesh_builder, true, NULL);
2094 
2095       cs_partition(m, cs_glob_mesh_builder, CS_PARTITION_MAIN);
2096 
2097       cs_mesh_from_builder(m, cs_glob_mesh_builder);
2098       cs_mesh_init_halo(m, cs_glob_mesh_builder, m->halo_type, -1, true);
2099     }
2100 
2101     cs_mesh_update_auxiliary(m);
2102   }
2103 
2104   BFT_FREE(input_cells);
2105 }
2106 
2107 /*----------------------------------------------------------------------------*/
2108 /*!
2109  * \brief Compute porosity field according to a given STL mesh
2110  *
2111  * \param[in]  stl_mesh      pointer to the associated STL mesh structure
2112  * \param[out] porosity      interpolated porosity field
2113  * \param[out] indic         indicator of the STL location
2114  */
2115 /*----------------------------------------------------------------------------*/
2116 
2117 void
cs_stl_compute_porosity(cs_stl_mesh_t * stl_mesh,cs_real_t * porosity,int * indic)2118 cs_stl_compute_porosity(cs_stl_mesh_t *stl_mesh,
2119                         cs_real_t     *porosity,
2120                         int           *indic)
2121 {
2122   cs_mesh_t *m = cs_glob_mesh;
2123   cs_mesh_quantities_t *mq = cs_glob_mesh_quantities;
2124 
2125   cs_stl_mesh_t *stl = stl_mesh;
2126 
2127   const cs_real_t *volume   = (const cs_real_t *)mq->cell_vol;
2128   const cs_real_3_t *xyzcen = (const cs_real_3_t *)mq->cell_cen;
2129   const cs_real_3_t *cdgfac = (const cs_real_3_t *)mq->i_face_cog;
2130   const cs_real_3_t *cdgfbo = (const cs_real_3_t *)mq->b_face_cog;
2131   const cs_lnum_2_t *ifacel = (const cs_lnum_2_t *)m->i_face_cells;
2132   const cs_lnum_t *ifabor   = (const cs_lnum_t *)m->b_face_cells;
2133 
2134   /* If no reference point outside the STL file is given
2135    * by the user, the porosity computation will fail */
2136   if (stl_mesh->seed_coords == NULL || stl_mesh->n_seeds == 0)
2137     bft_error(__FILE__, __LINE__, 0,
2138               _("Error in STL porosity computation: no seed points"
2139                 "for STL mesh %s is given."), stl_mesh->name);
2140 
2141   /* Initialisation */
2142   cs_lnum_t n_input_cells      = m->n_cells;
2143   cs_lnum_t n_selected_cells   = 0;
2144   cs_lnum_t *input_cells       = NULL;
2145   cs_lnum_t *selected_cells    = NULL;
2146   cs_lnum_t *tria_in_cell_lst  = NULL;
2147   cs_lnum_t *tria_in_cell_idx  = NULL;
2148   cs_lnum_t *cell_selected_idx = NULL;
2149   cs_real_t *mean_plane_def    = NULL;
2150   cs_real_t *stl_normals       = NULL;
2151 
2152   cs_lnum_t max_size = stl->n_faces;
2153 
2154   BFT_MALLOC(input_cells      , m->n_cells      , cs_lnum_t);
2155   BFT_MALLOC(selected_cells   , m->n_cells      , cs_lnum_t);
2156   BFT_MALLOC(tria_in_cell_idx , m->n_cells      , cs_lnum_t);
2157   BFT_MALLOC(tria_in_cell_lst , max_size        , cs_lnum_t);
2158   BFT_MALLOC(cell_selected_idx, m->n_cells      , cs_lnum_t);
2159   BFT_MALLOC(stl_normals      , stl->n_faces*3  , cs_real_t);
2160   BFT_MALLOC(mean_plane_def   , m->n_cells*6    , cs_real_t);
2161 
2162   /* Input cells are all[] cells and initialisation */
2163   for (cs_lnum_t i = 0; i < m->n_cells; i++) {
2164     input_cells[i] = i;
2165     cell_selected_idx[i] = -1;
2166     porosity[i] = 0.0;
2167   }
2168 
2169   /* Compute normals */
2170   for (cs_lnum_t i = 0; i < stl->n_faces; i++)
2171     _compute_normal(stl_mesh->coords + (3*i), stl_normals + (3*i));
2172 
2173   /* Get the intersection
2174    * ==================== */
2175   cs_stl_intersection(stl_mesh,
2176                       n_input_cells,
2177                       input_cells,
2178                       &n_selected_cells,
2179                       selected_cells,
2180                       tria_in_cell_idx,
2181                       &tria_in_cell_lst,
2182                       &max_size);
2183 
2184   /* Compute the bounding boxes of the main mesh */
2185   cs_real_6_t *bbox = NULL;
2186   bbox = cs_mesh_quantities_cell_extents(m, 0.0);
2187 
2188   /* If a cell is overlaped by more than 1 triangle,
2189    * replace those triangles by a mean plane
2190    * ============================================== */
2191   for (cs_lnum_t i = 0; i < n_selected_cells; i ++) {
2192 
2193     cs_lnum_t start_id = tria_in_cell_idx[i];
2194     cs_lnum_t end_id   = tria_in_cell_idx[i+1];
2195     cs_lnum_t n_tria_in_cell = end_id - start_id;
2196 
2197     cs_lnum_t cell_id   = selected_cells[i];
2198 
2199     if (n_tria_in_cell > 1) {
2200 
2201       cs_real_t surftot  = 0;
2202 
2203       // Mean plane defined by normal and point
2204       cs_real_t n_plan[3], p_plan[3];
2205       for (int k = 0; k < 3; k++) {
2206         n_plan[k] = 0.;
2207         p_plan[k] = 0.;
2208       }
2209 
2210       /* Loop on triangles intersecting the current cell */
2211       for (cs_lnum_t tri = start_id; tri < end_id; tri ++) {
2212 
2213         cs_lnum_t f_tria_id = tria_in_cell_lst[tri];
2214 
2215         cs_real_3_t *coords  = stl_mesh->coords + (3*f_tria_id);
2216         cs_real_t *n         = stl_normals + (3*f_tria_id);
2217         cs_real_t *aabb      = &bbox[cell_id][0];
2218         const cs_real_t *cog = xyzcen[cell_id];
2219 
2220         /* Compute the surface of the triangle in the box */
2221         cs_real_t surf = _exact_triangle_box_surface_intersection(aabb, coords);
2222         surftot += surf;
2223 
2224         /* Center of gravity of triangle */
2225         cs_real_t cog_tri[3];
2226         for (int k = 0; k < 3; k++)
2227           cog_tri[k] = (coords[0][k] + coords[1][k] + coords[2][k]) / 3.0;
2228 
2229         double psca = cs_math_3_distance_dot_product(cog, cog_tri, n);
2230         psca *= surf;
2231 
2232         /* Weigh triangle normal and point by the
2233          * surface included in the box  */
2234         for (int k = 0; k < 3; k++) {
2235           n_plan[k] += surf * n[k];
2236           p_plan[k] += psca * n[k];
2237 
2238         }
2239 
2240       } // End loop on tri intersecting the cell
2241 
2242       /* Normalisation */
2243       cs_real_t nn = cs_math_3_norm(n_plan);
2244 
2245       for (int k = 0; k < 3; k++) {
2246         n_plan[k] /= cs_math_fmax(nn, 1.e-20);
2247         p_plan[k] /= cs_math_fmax(surftot, 1.e-20);
2248       }
2249 
2250       /* Mean plane definition storage */
2251       for (int k = 0; k < 3; k++) {
2252         mean_plane_def[6*i + k] = p_plan[k] + xyzcen[cell_id][k];
2253         mean_plane_def[6*i + 3 + k] = n_plan[k];
2254       }
2255 
2256 
2257     /* else if only one triangle in cell */
2258     } else {
2259       cs_lnum_t f_tria_id = tria_in_cell_lst[start_id];
2260 
2261       for (int k = 0; k < 3; k++) {
2262         mean_plane_def[6*i + k] = stl_mesh->coords[3*f_tria_id][k];
2263         mean_plane_def[6*i + 3 + k] = stl_normals[3*f_tria_id + k];
2264       }
2265 
2266     }// End test on n_tria_in_cell
2267 
2268   // Building indirection
2269   cell_selected_idx[cell_id] = i;
2270   } // End loop on selected_cells
2271 
2272   /* Porosity computation on intersecting cells
2273    * ========================================== */
2274 
2275   cs_real_t vol;
2276 
2277   /* Loop on internal faces */
2278   for (cs_lnum_t face_id = 0; face_id < m->n_i_faces; face_id ++) {
2279 
2280     /* Loop on adjacent cells */
2281     for (int k = 0; k < 2; k++) {
2282       cs_lnum_t cell_id = ifacel[face_id][k];
2283       cs_lnum_t idx;
2284 
2285       /* Test if the cell is ghost cell */
2286       if (cell_id < m->n_cells) {
2287         idx = cell_selected_idx[cell_id];
2288 
2289         /* Test if the cell was a previously selected
2290          * intersecting cell*/
2291         if (idx > -1) {
2292           cs_real_t xf[3], xc[3];
2293 
2294           for (int i = 0; i < 3; i++) {
2295             xf[i] = cdgfac[face_id][i];
2296             xc[i] = xyzcen[cell_id][i];
2297           }
2298 
2299           cs_real_t *tria_mean_plane = &mean_plane_def[6*idx];
2300 
2301           /* For each face, tetrahedra based one edge, the cog of
2302            * the face and the cog of the cell, are built*/
2303           cs_lnum_t vtx_start = m->i_face_vtx_idx[face_id];
2304           cs_lnum_t vtx_end   = m->i_face_vtx_idx[face_id + 1];
2305           cs_lnum_t nb_vtx    = vtx_end - vtx_start;
2306 
2307           for (cs_lnum_t vtx = vtx_start; vtx < vtx_end; vtx++) {
2308 
2309             // When vtx = vtx_end-1, vtx+1 has to point towards vtx_start
2310             cs_lnum_t vtx1 = vtx;
2311             cs_lnum_t vtx2 = vtx_start + (vtx+1-vtx_start) % nb_vtx;
2312 
2313             cs_lnum_t vtx1_id = m->i_face_vtx_lst[vtx1];
2314             cs_lnum_t vtx2_id = m->i_face_vtx_lst[vtx2];
2315 
2316             cs_real_t *x1 = &(m->vtx_coord[3*vtx1_id]);
2317             cs_real_t *x2 = &(m->vtx_coord[3*vtx2_id]);
2318 
2319             vol = _tetrahedron_plane_volume_intersection(x1, x2, xf, xc, tria_mean_plane);
2320 
2321             porosity[cell_id] += vol;
2322           }
2323 
2324         } // End test if it is an intersecting cell
2325 
2326       } // End test if cell in not a ghost
2327 
2328     } // End loop on adjacent cells
2329 
2330   } // End loop on internal faces
2331 
2332   /* Loop on boundary faces */
2333   for (cs_lnum_t face_id = 0; face_id < m->n_b_faces; face_id ++) {
2334 
2335     cs_lnum_t cell_id = ifabor[face_id];
2336     cs_lnum_t idx;
2337 
2338     /* Test if the cell is ghost cell */
2339     if (cell_id < m->n_cells) {
2340       idx = cell_selected_idx[cell_id];
2341 
2342       /* Test if the cell was a previously selected
2343        * intersecting cell*/
2344       if (idx > -1) {
2345         cs_real_t xf[3], xc[3];
2346 
2347         for (int i = 0; i < 3; i++) {
2348           xf[i] = cdgfbo[face_id][i];
2349           xc[i] = xyzcen[cell_id][i];
2350         }
2351 
2352         cs_real_t *tria_mean_plane = &mean_plane_def[6*idx];
2353 
2354         /* For each face, tetrahedra based one edge, the cog of
2355          * the face and the cog of the cell, are built*/
2356         cs_lnum_t vtx_start = m->b_face_vtx_idx[face_id];
2357         cs_lnum_t vtx_end   = m->b_face_vtx_idx[face_id + 1];
2358         cs_lnum_t nb_vtx    = vtx_end - vtx_start;
2359 
2360         for (cs_lnum_t vtx = vtx_start; vtx < vtx_end; vtx++) {
2361 
2362           // When vtx = vtx_end-1, vtx+1 has to point towards vtx_start
2363           cs_lnum_t vtx1 = vtx;
2364           cs_lnum_t vtx2 = vtx_start + (vtx+1-vtx_start) % nb_vtx;
2365 
2366           cs_lnum_t vtx1_id = m->b_face_vtx_lst[vtx1];
2367           cs_lnum_t vtx2_id = m->b_face_vtx_lst[vtx2];
2368 
2369           cs_real_t *x1 = &(m->vtx_coord[3*vtx1_id]);
2370           cs_real_t *x2 = &(m->vtx_coord[3*vtx2_id]);
2371 
2372           vol = _tetrahedron_plane_volume_intersection(x1, x2, xf, xc, tria_mean_plane);
2373 
2374           porosity[cell_id] += vol;
2375 
2376         }
2377 
2378       } // End test if it is an intersecting cell
2379 
2380     } // End test if cell in not a ghost
2381 
2382   } // End loop on boundary faces
2383 
2384   /* Normalisation and clipping of the porosity field */
2385   for (cs_lnum_t i = 0; i < n_selected_cells; i++) {
2386     cs_lnum_t cell_id = selected_cells[i];
2387     porosity[cell_id] /= volume[cell_id];
2388     porosity[cell_id] = CS_MAX(porosity[cell_id],0.0);
2389     porosity[cell_id] = CS_MIN(porosity[cell_id],1.0);
2390 
2391     if (porosity[cell_id] < 1.e-5)
2392       porosity[cell_id] = 0.0;
2393   }
2394 
2395   if (m->halo!=NULL)
2396     cs_halo_sync_var(m->halo, CS_HALO_STANDARD, porosity);
2397 
2398   /* Porosity : filling the entire domain
2399    * ==================================== */
2400 
2401   int *cell_tag = NULL;
2402   BFT_MALLOC(cell_tag, m->n_cells_with_ghosts, int);
2403 
2404   /*-------------------------
2405    * cell_tag is :
2406    *  - 1 inside solid
2407    *  -  0 on the solid border
2408    *  - -1 outside the solid
2409    *  ------------------------*/
2410 
2411   for (cs_lnum_t cell_id = 0; cell_id < m->n_cells_with_ghosts; cell_id ++) {
2412     cell_tag[cell_id] = 1;
2413     if (cell_id < m->n_cells)
2414       /* If the cell in a border of the STL mesh */
2415       if (cell_selected_idx[cell_id] > -1)
2416         cell_tag[cell_id] = 0;
2417   }
2418 
2419 
2420   /* Tag outside cells according to user presribed points */
2421   for (int p = 0; p < stl_mesh->n_seeds; p++) {
2422 
2423     cs_real_t *xyz_ref = &(stl_mesh->seed_coords[3*p]);
2424     cs_lnum_t ref_id;
2425     int ref_rank;
2426 
2427     cs_geom_closest_point(m->n_cells,
2428                           (const cs_real_3_t *)(mq->cell_cen),
2429                           xyz_ref,
2430                           &ref_id,
2431                           &ref_rank);
2432 
2433     if (ref_rank == cs_glob_rank_id)
2434       cell_tag[ref_id] = -1;
2435   }
2436 
2437   /* Sychronize */
2438   if (m->halo!=NULL)
2439     cs_halo_sync_num(m->halo, CS_HALO_STANDARD, cell_tag);
2440 
2441   /* Loop on internal faces "Algo glouton" */
2442 
2443   bool new_cells_found = true;
2444 
2445   while (new_cells_found) {
2446 
2447     cs_gnum_t cpt = 0;
2448 
2449     for (cs_lnum_t face_id = 0; face_id < m->n_i_faces; face_id ++) {
2450 
2451       cs_lnum_t ii = ifacel[face_id][0];
2452       cs_lnum_t jj = ifacel[face_id][1];
2453 
2454       int ti = cell_tag[ii];
2455       int tj = cell_tag[jj];
2456 
2457       if (ti == 1 && tj == -1) {
2458         cell_tag[ii] = -1;
2459         cpt ++;
2460       }
2461 
2462       if (ti == -1 && tj == 1) {
2463         cell_tag[jj] = -1;
2464         cpt ++;
2465       }
2466     }
2467 
2468     if (cs_glob_rank_id >= 0)
2469       cs_parall_counter(&cpt, 1);
2470 
2471     if (cpt == 0)
2472       new_cells_found = false;
2473 
2474     if (m->halo!=NULL)
2475       cs_halo_sync_num(m->halo, CS_HALO_STANDARD, cell_tag);
2476   }
2477 
2478   for (cs_lnum_t cell_id = 0; cell_id < m->n_cells; cell_id ++) {
2479     if (indic != NULL)
2480       indic[cell_id] = cell_tag[cell_id];
2481     if (cell_tag[cell_id] == -1)
2482       porosity[cell_id] = 1.0;
2483   }
2484 
2485   BFT_FREE(cell_tag);
2486   BFT_FREE(cell_selected_idx);
2487   BFT_FREE(mean_plane_def);
2488   BFT_FREE(stl_normals);
2489   BFT_FREE(bbox);
2490   BFT_FREE(input_cells);
2491   BFT_FREE(selected_cells);
2492   BFT_FREE(tria_in_cell_lst);
2493   BFT_FREE(tria_in_cell_idx);
2494 }
2495 
2496 /*----------------------------------------------------------------------------*/
2497 
2498 END_C_DECLS
2499