~ubuntu-branches/ubuntu/precise/code-saturne/precise

« back to all changes in this revision

Viewing changes to src/mesh/cs_join_merge.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2011-11-01 17:43:32 UTC
  • mto: (6.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20111101174332-tl4vk45no0x3emc3
Tags: upstream-2.1.0
ImportĀ upstreamĀ versionĀ 2.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================
 
2
 * Set of subroutines for:
 
3
 *  - merging equivalent vertices,
 
4
 *  - managing tolerance reduction
 
5
 *===========================================================================*/
 
6
 
 
7
/*
 
8
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
9
 
 
10
  Copyright (C) 1998-2011 EDF S.A.
 
11
 
 
12
  This program is free software; you can redistribute it and/or modify it under
 
13
  the terms of the GNU General Public License as published by the Free Software
 
14
  Foundation; either version 2 of the License, or (at your option) any later
 
15
  version.
 
16
 
 
17
  This program is distributed in the hope that it will be useful, but WITHOUT
 
18
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
19
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
20
  details.
 
21
 
 
22
  You should have received a copy of the GNU General Public License along with
 
23
  this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
24
  Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
25
*/
 
26
 
 
27
/*----------------------------------------------------------------------------*/
 
28
 
 
29
#if defined(HAVE_CONFIG_H)
 
30
#include "cs_config.h"
 
31
#endif
 
32
 
 
33
/*----------------------------------------------------------------------------
 
34
 * Standard C library headers
 
35
 *---------------------------------------------------------------------------*/
 
36
 
 
37
#include <stdlib.h>
 
38
#include <stdio.h>
 
39
#include <string.h>
 
40
#include <math.h>
 
41
#include <float.h>
 
42
#include <assert.h>
 
43
 
 
44
/*----------------------------------------------------------------------------
 
45
 * BFT library headers
 
46
 *---------------------------------------------------------------------------*/
 
47
 
 
48
#include <bft_mem.h>
 
49
#include <bft_timer.h>
 
50
#include <bft_printf.h>
 
51
 
 
52
/*----------------------------------------------------------------------------
 
53
 * FVM headers
 
54
 *---------------------------------------------------------------------------*/
 
55
 
 
56
#include <fvm_io_num.h>
 
57
#include <fvm_order.h>
 
58
#include <fvm_parall.h>
 
59
 
 
60
/*----------------------------------------------------------------------------
 
61
 * Local headers
 
62
 *---------------------------------------------------------------------------*/
 
63
 
 
64
#include "cs_search.h"
 
65
#include "cs_join_post.h"
 
66
 
 
67
/*----------------------------------------------------------------------------
 
68
 * Header for the current file
 
69
 *---------------------------------------------------------------------------*/
 
70
 
 
71
#include "cs_join_merge.h"
 
72
 
 
73
/*---------------------------------------------------------------------------*/
 
74
 
 
75
BEGIN_C_DECLS
 
76
 
 
77
/*============================================================================
 
78
 * Structure and type definitions
 
79
 *===========================================================================*/
 
80
 
 
81
/*============================================================================
 
82
 * Macro definitions
 
83
 *===========================================================================*/
 
84
 
 
85
/* Turn on (1) or off (0) the tolerance reduc. */
 
86
#define  CS_JOIN_MERGE_TOL_REDUC  1
 
87
#define  CS_JOIN_MERGE_INV_TOL  1
 
88
 
 
89
/*============================================================================
 
90
 * Global variable definitions
 
91
 *===========================================================================*/
 
92
 
 
93
/* Parameters to control the vertex merge */
 
94
 
 
95
enum {
 
96
 
 
97
  CS_JOIN_MERGE_MAX_GLOB_ITERS = 50,  /* Max. number of glob. iter. for finding
 
98
                                         equivalent vertices */
 
99
  CS_JOIN_MERGE_MAX_LOC_ITERS = 100   /* Max. number of loc. iter. for finding
 
100
                                         equivalent vertices */
 
101
};
 
102
 
 
103
/* Coefficient to deal with rounding approximations */
 
104
 
 
105
static const double  cs_join_tol_eps_coef2 = 1.0001*1.001;
 
106
 
 
107
/* Counter on the number of loops useful to converge for the merge operation */
 
108
 
 
109
static int  _glob_merge_counter = 0, _loc_merge_counter = 0;
 
110
 
 
111
/*============================================================================
 
112
 * Private function definitions
 
113
 *===========================================================================*/
 
114
 
 
115
/*----------------------------------------------------------------------------
 
116
 * Initialize counter for the merge operation
 
117
 *---------------------------------------------------------------------------*/
 
118
 
 
119
static void
 
120
_initialize_merge_counter(void)
 
121
{
 
122
  _glob_merge_counter = 0;
 
123
  _loc_merge_counter = 0;
 
124
}
 
125
 
 
126
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
127
 
 
128
/*----------------------------------------------------------------------------
 
129
 * Dump an cs_join_eset_t structure on vertices.
 
130
 *
 
131
 * parameters:
 
132
 *   e_set   <-- cs_join_eset_t structure to dump
 
133
 *   mesh    <-- cs_join_mesh_t structure associated
 
134
 *   logfile <-- handle to log file
 
135
 *---------------------------------------------------------------------------*/
 
136
 
 
137
static void
 
138
_dump_vtx_eset(const cs_join_eset_t  *e_set,
 
139
               const cs_join_mesh_t  *mesh,
 
140
               FILE                  *logfile)
 
141
{
 
142
  int  i;
 
143
 
 
144
  fprintf(logfile, "\n  Dump an cs_join_eset_t structure (%p)\n",
 
145
          (const void *)e_set);
 
146
  fprintf(logfile, "  n_max_equiv: %10d\n", e_set->n_max_equiv);
 
147
  fprintf(logfile, "  n_equiv    : %10d\n\n", e_set->n_equiv);
 
148
 
 
149
  for (i = 0; i < e_set->n_equiv; i++) {
 
150
 
 
151
    cs_int_t  v1_num = e_set->equiv_couple[2*i];
 
152
    cs_int_t  v2_num = e_set->equiv_couple[2*i+1];
 
153
 
 
154
    fprintf(logfile,
 
155
            " %10d - local: (%9d, %9d) - global: (%10llu, %10llu)\n",
 
156
            i, v1_num, v2_num,
 
157
            (unsigned long long)(mesh->vertices[v1_num-1]).gnum,
 
158
            (unsigned long long)(mesh->vertices[v2_num-1]).gnum);
 
159
 
 
160
  }
 
161
  fflush(logfile);
 
162
}
 
163
 
 
164
#endif /* Only in debug mode */
 
165
 
 
166
/*----------------------------------------------------------------------------
 
167
 * Compute the length of a segment between two vertices.
 
168
 *
 
169
 * parameters:
 
170
 *   v1 <-- cs_join_vertex_t structure for the first vertex of the segment
 
171
 *   v2 <-- cs_join_vertex_t structure for the second vertex of the segment
 
172
 *
 
173
 * returns:
 
174
 *    length of the segment
 
175
 *---------------------------------------------------------------------------*/
 
176
 
 
177
inline static cs_real_t
 
178
_compute_length(cs_join_vertex_t  v1,
 
179
                cs_join_vertex_t  v2)
 
180
{
 
181
  cs_int_t  k;
 
182
  cs_real_t  len = 0.0, d2 = 0.0;
 
183
 
 
184
  for (k = 0; k < 3; k++) {
 
185
    cs_real_t  d = v1.coord[k] - v2.coord[k];
 
186
    d2 += d * d;
 
187
  }
 
188
  len = sqrt(d2);
 
189
 
 
190
  return len;
 
191
}
 
192
 
 
193
/*----------------------------------------------------------------------------
 
194
 * Compute a new cs_join_vertex_t structure.
 
195
 *
 
196
 * parameters:
 
197
 *   curv_abs   <-- curvilinear abscissa of the intersection
 
198
 *   gnum       <-- global number associated to the new
 
199
 *                  cs_join_vertex_t structure
 
200
 *   vtx_couple <-- couple of vertex numbers defining the current edge
 
201
 *   work       <-- local cs_join_mesh_t structure
 
202
 *
 
203
 * returns:
 
204
 *   a new cs_join_vertex_t structure
 
205
 *---------------------------------------------------------------------------*/
 
206
 
 
207
static cs_join_vertex_t
 
208
_get_new_vertex(float                  curv_abs,
 
209
                fvm_gnum_t             gnum,
 
210
                const cs_int_t         vtx_couple[],
 
211
                const cs_join_mesh_t  *work)
 
212
{
 
213
  cs_int_t  k;
 
214
  cs_join_vertex_t  new_vtx_data;
 
215
 
 
216
  cs_join_vertex_t  v1 = work->vertices[vtx_couple[0]-1];
 
217
  cs_join_vertex_t  v2 = work->vertices[vtx_couple[1]-1];
 
218
 
 
219
  assert(curv_abs >= 0.0);
 
220
  assert(curv_abs <= 1.0);
 
221
 
 
222
  /* New vertex features */
 
223
 
 
224
  new_vtx_data.state = CS_JOIN_STATE_NEW;
 
225
  new_vtx_data.gnum = gnum;
 
226
  new_vtx_data.tolerance = (1-curv_abs)*v1.tolerance + curv_abs*v2.tolerance;
 
227
 
 
228
  for (k = 0; k < 3; k++)
 
229
    new_vtx_data.coord[k] = (1-curv_abs)*v1.coord[k] + curv_abs*v2.coord[k];
 
230
 
 
231
  return new_vtx_data;
 
232
}
 
233
 
 
234
/*----------------------------------------------------------------------------
 
235
 * Define a tag (3 values) to globally order intersections.
 
236
 *
 
237
 * parameters:
 
238
 *   tag           <-> tag to fill
 
239
 *   e1_gnum       <-- global number for the first edge
 
240
 *   e2_gnum       <-- global number for the second edge
 
241
 *   link_vtx_gnum <-- global number of the vertex associated to the current
 
242
 *                      intersection
 
243
 *---------------------------------------------------------------------------*/
 
244
 
 
245
static void
 
246
_define_inter_tag(fvm_gnum_t  tag[],
 
247
                  fvm_gnum_t  e1_gnum,
 
248
                  fvm_gnum_t  e2_gnum,
 
249
                  fvm_gnum_t  link_vtx_gnum)
 
250
{
 
251
  if (e1_gnum < e2_gnum) {
 
252
    tag[0] = e1_gnum;
 
253
    tag[1] = e2_gnum;
 
254
  }
 
255
  else {
 
256
    tag[0] = e2_gnum;
 
257
    tag[1] = e1_gnum;
 
258
  }
 
259
 
 
260
  tag[2] = link_vtx_gnum;
 
261
}
 
262
 
 
263
/*----------------------------------------------------------------------------
 
264
 * Creation of new vertices.
 
265
 *
 
266
 * Update list of equivalent vertices.
 
267
 *
 
268
 * parameters:
 
269
 *   work               <-- pointer to a cs_join_mesh_t structure
 
270
 *   edges              <-- list of edges
 
271
 *   inter_set          <-- structure including data on edge intersections
 
272
 *   init_max_vtx_gnum  <-- initial max. global numbering for vertices
 
273
 *   n_iwm_vertices     <-- initial local number of vertices (work struct)
 
274
 *   n_new_vertices     <-- local number of new vertices to define
 
275
 *   p_n_g_new_vertices <-> pointer to the global number of new vertices
 
276
 *   p_new_vtx_gnum     <-> pointer to the global numbering array for the
 
277
 *                          new vertices
 
278
 *---------------------------------------------------------------------------*/
 
279
 
 
280
static void
 
281
_compute_new_vertex_gnum(const cs_join_mesh_t       *work,
 
282
                         const cs_join_edges_t      *edges,
 
283
                         const cs_join_inter_set_t  *inter_set,
 
284
                         fvm_gnum_t                  init_max_vtx_gnum,
 
285
                         cs_int_t                    n_iwm_vertices,
 
286
                         cs_int_t                    n_new_vertices,
 
287
                         fvm_gnum_t                 *p_n_g_new_vertices,
 
288
                         fvm_gnum_t                 *p_new_vtx_gnum[])
 
289
{
 
290
  cs_int_t  i;
 
291
 
 
292
  fvm_gnum_t  n_g_new_vertices = 0;
 
293
  cs_int_t  n_new_vertices_save = n_new_vertices;
 
294
  fvm_lnum_t  *order = NULL;
 
295
  fvm_gnum_t  *inter_tag = NULL, *adjacency = NULL, *new_vtx_gnum = NULL;
 
296
  fvm_io_num_t  *new_vtx_io_num = NULL;
 
297
 
 
298
  /* Define a fvm_io_num_t structure to get the global numbering
 
299
     for the new vertices.
 
300
     First, build a tag associated to each intersection */
 
301
 
 
302
  BFT_MALLOC(new_vtx_gnum, n_new_vertices, fvm_gnum_t);
 
303
  BFT_MALLOC(inter_tag, 3*n_new_vertices, fvm_gnum_t);
 
304
 
 
305
  n_new_vertices = 0;
 
306
 
 
307
  for (i = 0; i < inter_set->n_inter; i++) {
 
308
 
 
309
    cs_join_inter_t  inter1 = inter_set->inter_lst[2*i];
 
310
    cs_join_inter_t  inter2 = inter_set->inter_lst[2*i+1];
 
311
    fvm_gnum_t  e1_gnum = edges->gnum[inter1.edge_id];
 
312
    fvm_gnum_t  e2_gnum = edges->gnum[inter2.edge_id];
 
313
 
 
314
    if (inter1.vtx_id + 1 > n_iwm_vertices) {
 
315
 
 
316
      if (inter2.vtx_id + 1 > n_iwm_vertices)
 
317
        _define_inter_tag(&(inter_tag[3*n_new_vertices]),
 
318
                          e1_gnum, e2_gnum,
 
319
                          0);
 
320
      else
 
321
        _define_inter_tag(&(inter_tag[3*n_new_vertices]),
 
322
                          e1_gnum, e2_gnum,
 
323
                          (work->vertices[inter2.vtx_id]).gnum);
 
324
 
 
325
      n_new_vertices++;
 
326
 
 
327
    } /* New vertices for this intersection */
 
328
 
 
329
    if (inter2.vtx_id + 1 > n_iwm_vertices) {
 
330
 
 
331
      if (inter1.vtx_id + 1 > n_iwm_vertices)
 
332
        _define_inter_tag(&(inter_tag[3*n_new_vertices]),
 
333
                          e1_gnum, e2_gnum,
 
334
                          init_max_vtx_gnum + 1);
 
335
      else
 
336
        _define_inter_tag(&(inter_tag[3*n_new_vertices]),
 
337
                          e1_gnum, e2_gnum,
 
338
                          (work->vertices[inter1.vtx_id]).gnum);
 
339
 
 
340
      n_new_vertices++;
 
341
 
 
342
    } /* New vertices for this intersection */
 
343
 
 
344
  } /* End of loop on intersections */
 
345
 
 
346
  if (n_new_vertices != n_new_vertices_save)
 
347
    bft_error(__FILE__, __LINE__, 0,
 
348
              _("  The number of new vertices to create is not consistent.\n"
 
349
                "     Previous number: %10d\n"
 
350
                "     Current number:  %10d\n\n"),
 
351
              n_new_vertices_save, n_new_vertices);
 
352
 
 
353
  /* Create a new fvm_io_num_t structure */
 
354
 
 
355
  BFT_MALLOC(order, n_new_vertices, fvm_lnum_t);
 
356
 
 
357
  fvm_order_local_allocated_s(NULL, inter_tag, 3, order, n_new_vertices);
 
358
 
 
359
  BFT_MALLOC(adjacency, 3*n_new_vertices, fvm_gnum_t);
 
360
 
 
361
  for (i = 0; i < n_new_vertices; i++) {
 
362
 
 
363
    cs_int_t  o_id = order[i];
 
364
 
 
365
    adjacency[3*i] = inter_tag[3*o_id];
 
366
    adjacency[3*i+1] = inter_tag[3*o_id+1];
 
367
    adjacency[3*i+2] = inter_tag[3*o_id+2];
 
368
 
 
369
  }
 
370
 
 
371
  BFT_FREE(inter_tag);
 
372
 
 
373
  if (cs_glob_n_ranks > 1) {
 
374
 
 
375
    const fvm_gnum_t  *global_num = NULL;
 
376
 
 
377
    new_vtx_io_num =
 
378
      fvm_io_num_create_from_adj_s(NULL, adjacency, n_new_vertices, 3);
 
379
 
 
380
    n_g_new_vertices = fvm_io_num_get_global_count(new_vtx_io_num);
 
381
    global_num = fvm_io_num_get_global_num(new_vtx_io_num);
 
382
 
 
383
    for (i = 0; i < n_new_vertices; i++)
 
384
      new_vtx_gnum[order[i]] = global_num[i] + init_max_vtx_gnum;
 
385
 
 
386
    fvm_io_num_destroy(new_vtx_io_num);
 
387
 
 
388
  } /* End of parallel treatment */
 
389
 
 
390
  else {
 
391
 
 
392
    if (n_new_vertices > 0) {
 
393
 
 
394
      fvm_gnum_t  new_gnum = init_max_vtx_gnum + 1;
 
395
 
 
396
      new_vtx_gnum[order[0]] = new_gnum;
 
397
 
 
398
      for (i = 1; i < n_new_vertices; i++) {
 
399
 
 
400
        if (adjacency[3*i] != adjacency[3*(i-1)])
 
401
          new_gnum += 1;
 
402
        else {
 
403
          if (adjacency[3*i+1] != adjacency[3*(i-1)+1])
 
404
            new_gnum += 1;
 
405
          else
 
406
            if (adjacency[3*i+2] != adjacency[3*(i-1)+2])
 
407
              new_gnum += 1;
 
408
        }
 
409
 
 
410
        new_vtx_gnum[order[i]] = new_gnum;
 
411
 
 
412
      }
 
413
 
 
414
    } /* End if n_new_vertices > 0 */
 
415
 
 
416
    n_g_new_vertices = n_new_vertices;
 
417
 
 
418
  } /* End of serial treatment */
 
419
 
 
420
  /* Free memory */
 
421
 
 
422
  BFT_FREE(order);
 
423
  BFT_FREE(adjacency);
 
424
 
 
425
  /* Return pointer */
 
426
 
 
427
  *p_n_g_new_vertices = n_g_new_vertices;
 
428
  *p_new_vtx_gnum = new_vtx_gnum;
 
429
 
 
430
}
 
431
 
 
432
/*----------------------------------------------------------------------------
 
433
 * Get vertex id associated to the current intersection.
 
434
 *
 
435
 * Create a new vertex id if needed. Update n_new_vertices in this case.
 
436
 *
 
437
 * parameters:
 
438
 *   inter           <-- a inter_t structure
 
439
 *   vtx_couple      <-- couple of vertex numbers defining the current edge
 
440
 *   n_init_vertices <-- initial number of vertices
 
441
 *   n_new_vertices  <-- number of new vertices created
 
442
 *
 
443
 * returns:
 
444
 *   vertex id associated to the current intersection.
 
445
 *---------------------------------------------------------------------------*/
 
446
 
 
447
static cs_int_t
 
448
_get_vtx_id(cs_join_inter_t  inter,
 
449
            const cs_int_t   vtx_couple[],
 
450
            cs_int_t         n_init_vertices,
 
451
            cs_int_t        *p_n_new_vertices)
 
452
{
 
453
  cs_int_t  vtx_id = -1;
 
454
  cs_int_t  n_new_vertices = *p_n_new_vertices;
 
455
 
 
456
  assert(inter.curv_abs >= 0.0);
 
457
  assert(inter.curv_abs <= 1.0);
 
458
 
 
459
  if (inter.curv_abs <= 0.0)
 
460
    vtx_id = vtx_couple[0] - 1;
 
461
 
 
462
  else if (inter.curv_abs >= 1.0)
 
463
    vtx_id = vtx_couple[1] - 1;
 
464
 
 
465
  else {
 
466
 
 
467
    assert(inter.curv_abs > 0 && inter.curv_abs < 1.0);
 
468
    vtx_id = n_init_vertices + n_new_vertices;
 
469
    n_new_vertices++;
 
470
 
 
471
  }
 
472
 
 
473
  assert(vtx_id != -1);
 
474
 
 
475
  *p_n_new_vertices = n_new_vertices;
 
476
 
 
477
  return vtx_id;
 
478
}
 
479
 
 
480
 
 
481
/*----------------------------------------------------------------------------
 
482
 * Test if we have to continue to spread the tag associate to each vertex
 
483
 *
 
484
 * parameters:
 
485
 *   n_vertices   <-- local number of vertices
 
486
 *   prev_vtx_tag <-- previous tag for each vertex
 
487
 *   vtx_tag      <-- tag for each vertex
 
488
 *
 
489
 * returns:
 
490
 *   true or false
 
491
 *---------------------------------------------------------------------------*/
 
492
 
 
493
static cs_bool_t
 
494
_is_spread_not_converged(cs_int_t          n_vertices,
 
495
                         const fvm_gnum_t  prev_vtx_tag[],
 
496
                         const fvm_gnum_t  vtx_tag[])
 
497
{
 
498
  cs_int_t  i;
 
499
 
 
500
  cs_bool_t  have_to_continue = true;
 
501
 
 
502
  for (i = 0; i < n_vertices; i++)
 
503
    if (vtx_tag[i] != prev_vtx_tag[i])
 
504
      break;
 
505
 
 
506
  if (i == n_vertices)
 
507
    have_to_continue = false;
 
508
 
 
509
  return have_to_continue;
 
510
}
 
511
 
 
512
/*----------------------------------------------------------------------------
 
513
 * Spread the tag associated to each vertex according the rule:
 
514
 *  Between two equivalent vertices, the tag associated to each considered
 
515
 *  vertex is equal to the minimal global number.
 
516
 *
 
517
 * parameters:
 
518
 *  n_vertices <-- local number of vertices
 
519
 *  vtx_eset   <-- structure dealing with vertices equivalences
 
520
 *  vtx_tag    <-> tag for each vertex
 
521
 *---------------------------------------------------------------------------*/
 
522
 
 
523
static void
 
524
_spread_tag(cs_int_t               n_vertices,
 
525
            const cs_join_eset_t  *vtx_eset,
 
526
            fvm_gnum_t             vtx_tag[])
 
527
{
 
528
  cs_int_t  i, v1_id, v2_id;
 
529
  fvm_gnum_t  v1_gnum, v2_gnum;
 
530
  cs_int_t  *equiv_lst = vtx_eset->equiv_couple;
 
531
 
 
532
  for (i = 0; i < vtx_eset->n_equiv; i++) {
 
533
 
 
534
    v1_id = equiv_lst[2*i] - 1, v2_id = equiv_lst[2*i+1] - 1;
 
535
    assert(v1_id < n_vertices);
 
536
    assert(v1_id < n_vertices);
 
537
    v1_gnum = vtx_tag[v1_id], v2_gnum = vtx_tag[v2_id];
 
538
 
 
539
    if (v1_gnum != v2_gnum) {
 
540
 
 
541
      fvm_gnum_t  min_gnum = CS_MIN(v1_gnum, v2_gnum);
 
542
 
 
543
      vtx_tag[v1_id] = min_gnum;
 
544
      vtx_tag[v2_id] = min_gnum;
 
545
    }
 
546
 
 
547
  } /* End of loop on vertex equivalences */
 
548
}
 
549
 
 
550
/*----------------------------------------------------------------------------
 
551
 * Define an array wich keeps the new vertex id of each vertex.
 
552
 *
 
553
 * If two vertices have the same vertex id, they should merge.
 
554
 *
 
555
 * parameters:
 
556
 *   vtx_eset     <-- structure dealing with vertex equivalences
 
557
 *   n_vertices   <-- local number of vertices
 
558
 *   prev_vtx_tag <-> previous tag for each vertex
 
559
 *   vtx_tag      <-> tag for each vertex
 
560
 *---------------------------------------------------------------------------*/
 
561
 
 
562
static void
 
563
_local_spread(const cs_join_eset_t  *vtx_eset,
 
564
              cs_int_t               n_vertices,
 
565
              fvm_gnum_t             prev_vtx_tag[],
 
566
              fvm_gnum_t             vtx_tag[])
 
567
{
 
568
  cs_int_t  i;
 
569
 
 
570
  _loc_merge_counter++;
 
571
 
 
572
  _spread_tag(n_vertices, vtx_eset, vtx_tag);
 
573
 
 
574
  while (_is_spread_not_converged(n_vertices, prev_vtx_tag, vtx_tag)) {
 
575
 
 
576
    _loc_merge_counter++;
 
577
 
 
578
    if (_loc_merge_counter > CS_JOIN_MERGE_MAX_LOC_ITERS)
 
579
      bft_error(__FILE__, __LINE__, 0,
 
580
                _("\n  The authorized maximum number of iterations "
 
581
                  " for the merge of vertices has been reached.\n"
 
582
                  "  Local counter on iteration : %d (MAX =%d)\n"
 
583
                  "  Check the fraction parameter.\n"),
 
584
                _loc_merge_counter, CS_JOIN_MERGE_MAX_LOC_ITERS);
 
585
 
 
586
    for (i = 0; i < n_vertices; i++)
 
587
      prev_vtx_tag[i] = vtx_tag[i];
 
588
 
 
589
    _spread_tag(n_vertices, vtx_eset, vtx_tag);
 
590
  }
 
591
}
 
592
 
 
593
#if defined(HAVE_MPI)
 
594
 
 
595
/*----------------------------------------------------------------------------
 
596
 * Exchange local vtx_tag buffer over the ranks and update global vtx_tag
 
597
 * buffers. Apply modifications observed on the global vtx_tag to the local
 
598
 * vtx_tag.
 
599
 *
 
600
 * parameters:
 
601
 *   block_size        <-- size of block for the current rank
 
602
 *   work              <-- local cs_join_mesh_t structure which has initial
 
603
 *                         vertex data
 
604
 *   vtx_tag           <-> local vtx_tag for the local vertices
 
605
 *   glob_vtx_tag      <-> global vtx_tag affected to the local rank
 
606
 *                         (size: block_size)
 
607
 *   prev_glob_vtx_tag <-> same but for the previous iteration
 
608
 *   recv2glob         <-> buffer used to place correctly receive elements
 
609
 *   send_count        <-> buffer used to count the number of elts to send
 
610
 *   send_shift        <-> index on ranks of the elements to send
 
611
 *   send_glob_buffer  <-> buffer used to save elements to send
 
612
 *   recv_count        <-> buffer used to count the number of elts to receive
 
613
 *   recv_shift        <-> index on ranks of the elements to receive
 
614
 *   recv_glob_buffer  <-> buffer used to save elements to receive
 
615
 *
 
616
 * returns:
 
617
 *   true if we have to continue the spread, false otherwise.
 
618
 *---------------------------------------------------------------------------*/
 
619
 
 
620
static cs_bool_t
 
621
_global_spread(cs_int_t               block_size,
 
622
               const cs_join_mesh_t  *work,
 
623
               fvm_gnum_t             vtx_tag[],
 
624
               fvm_gnum_t             glob_vtx_tag[],
 
625
               fvm_gnum_t             prev_glob_vtx_tag[],
 
626
               fvm_gnum_t             recv2glob[],
 
627
               cs_int_t               send_count[],
 
628
               cs_int_t               send_shift[],
 
629
               fvm_gnum_t             send_glob_buffer[],
 
630
               cs_int_t               recv_count[],
 
631
               cs_int_t               recv_shift[],
 
632
               fvm_gnum_t             recv_glob_buffer[])
 
633
{
 
634
  cs_bool_t  ret_value;
 
635
  cs_int_t  i, local_value, global_value;
 
636
 
 
637
  cs_int_t  n_vertices = work->n_vertices;
 
638
  int  n_ranks = cs_glob_n_ranks;
 
639
  MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
640
 
 
641
  _glob_merge_counter++;
 
642
 
 
643
  /* Push modifications in local vtx_tag to the global vtx_tag */
 
644
 
 
645
  for (i = 0; i < n_ranks; i++)
 
646
    send_count[i] = 0;
 
647
 
 
648
  for (i = 0; i < n_vertices; i++) {
 
649
 
 
650
    int  rank = (work->vertices[i].gnum - 1) % n_ranks;
 
651
    cs_int_t  shift = send_shift[rank] + send_count[rank];
 
652
 
 
653
    send_glob_buffer[shift] = vtx_tag[i];
 
654
    send_count[rank] += 1;
 
655
 
 
656
  }
 
657
 
 
658
  MPI_Alltoallv(send_glob_buffer, send_count, send_shift, FVM_MPI_GNUM,
 
659
                recv_glob_buffer, recv_count, recv_shift, FVM_MPI_GNUM,
 
660
                mpi_comm);
 
661
 
 
662
  /* Apply update to glob_vtx_tag */
 
663
 
 
664
  for (i = 0; i < recv_shift[n_ranks]; i++) {
 
665
    cs_int_t  cur_id = recv2glob[i];
 
666
    glob_vtx_tag[cur_id] = CS_MIN(glob_vtx_tag[cur_id], recv_glob_buffer[i]);
 
667
  }
 
668
 
 
669
  ret_value = _is_spread_not_converged(block_size,
 
670
                                       prev_glob_vtx_tag,
 
671
                                       glob_vtx_tag);
 
672
 
 
673
  if (ret_value == false)
 
674
    local_value = 0;
 
675
  else
 
676
    local_value = 1;
 
677
 
 
678
  MPI_Allreduce(&local_value, &global_value, 1, MPI_INT, MPI_SUM, mpi_comm);
 
679
 
 
680
  if (global_value > 0) { /* Store the current state as the previous one
 
681
                             Update local vtx_tag */
 
682
 
 
683
    if (_glob_merge_counter > CS_JOIN_MERGE_MAX_GLOB_ITERS)
 
684
      bft_error(__FILE__, __LINE__, 0,
 
685
                _("\n  The authorized maximum number of iterations "
 
686
                  " for the merge of vertices has been reached.\n"
 
687
                  "  Global counter on iteration : %d (MAX =%d)\n"
 
688
                  "  Check the fraction parameter.\n"),
 
689
                _glob_merge_counter, CS_JOIN_MERGE_MAX_GLOB_ITERS);
 
690
 
 
691
    for (i = 0; i < block_size; i++)
 
692
      prev_glob_vtx_tag[i] = glob_vtx_tag[i];
 
693
 
 
694
    for (i = 0; i < recv_shift[n_ranks]; i++)
 
695
      recv_glob_buffer[i] = glob_vtx_tag[recv2glob[i]];
 
696
 
 
697
    MPI_Alltoallv(recv_glob_buffer, recv_count, recv_shift, FVM_MPI_GNUM,
 
698
                  send_glob_buffer, send_count, send_shift, FVM_MPI_GNUM,
 
699
                  mpi_comm);
 
700
 
 
701
    /* Update vtx_tag */
 
702
 
 
703
    for (i = 0; i < n_ranks; i++)
 
704
      send_count[i] = 0;
 
705
 
 
706
    assert(send_shift[n_ranks] == n_vertices);
 
707
 
 
708
    for (i = 0; i < n_vertices; i++) {
 
709
 
 
710
      int  rank = (work->vertices[i].gnum - 1) % n_ranks;
 
711
      cs_int_t  shift = send_shift[rank] + send_count[rank];
 
712
 
 
713
      vtx_tag[i] = CS_MIN(send_glob_buffer[shift], vtx_tag[i]);
 
714
      send_count[rank] += 1;
 
715
 
 
716
    }
 
717
 
 
718
    return true;
 
719
 
 
720
  } /* End if prev_glob_vtx_tag != glob_vtx_tag */
 
721
 
 
722
  else
 
723
    return false; /* No need to continue */
 
724
}
 
725
 
 
726
/*----------------------------------------------------------------------------
 
727
 * Initialize and allocate buffers for the tag operation in parallel mode.
 
728
 *
 
729
 * parameters:
 
730
 *   n_g_vertices_to_treat <-- global number of vertices to consider for the
 
731
 *                             merge operation (existing + created vertices)
 
732
 *   work                  <-- local cs_join_mesh_t structure which has
 
733
 *                             initial vertex data
 
734
 *   p_block_size          <-> size of block for the current rank
 
735
 *   p_send_count          <-> buf. for counting the number of elts to send
 
736
 *   p_send_shift          <-> index on ranks of the elements to send
 
737
 *   p_send_glob_buf       <-> buf. for saving elements to send
 
738
 *   p_recv_count          <-> buf. for counting the number of elts to receive
 
739
 *   p_recv_shift          <-> index on ranks of the elements to receive
 
740
 *   p_recv_glob_buf       <-> buf. for storing elements to receive
 
741
 *   p_recv2glob           <-> buf. for putting correctly received elements
 
742
 *   p_glob_vtx_tag        <-> vtx_tag locally treated (size = block_size)
 
743
 *   p_prev_glob_vtx_tag   <-> idem but for the previous iteration
 
744
 *---------------------------------------------------------------------------*/
 
745
 
 
746
static void
 
747
_parall_tag_init(fvm_gnum_t             n_g_vertices_to_treat,
 
748
                 const cs_join_mesh_t  *work,
 
749
                 cs_int_t              *p_block_size,
 
750
                 cs_int_t              *p_send_count[],
 
751
                 cs_int_t              *p_send_shift[],
 
752
                 fvm_gnum_t            *p_send_glob_buf[],
 
753
                 cs_int_t              *p_recv_count[],
 
754
                 cs_int_t              *p_recv_shift[],
 
755
                 fvm_gnum_t            *p_recv_glob_buf[],
 
756
                 fvm_gnum_t            *p_recv2glob[],
 
757
                 fvm_gnum_t            *p_glob_vtx_tag[],
 
758
                 fvm_gnum_t            *p_prev_glob_vtx_tag[])
 
759
{
 
760
  cs_int_t  i;
 
761
 
 
762
  cs_int_t  n_vertices = work->n_vertices;
 
763
  cs_int_t  block_size = 0, left_over = 0;
 
764
  cs_int_t  *send_count = NULL, *recv_count = NULL;
 
765
  cs_int_t  *send_shift = NULL, *recv_shift = NULL;
 
766
  fvm_gnum_t  *recv2glob = NULL;
 
767
  fvm_gnum_t  *recv_glob_buffer = NULL, *send_glob_buffer = NULL;
 
768
  fvm_gnum_t  *glob_vtx_tag = NULL, *prev_glob_vtx_tag = NULL;
 
769
  MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
770
 
 
771
  const int  n_ranks = cs_glob_n_ranks;
 
772
  const int  local_rank = CS_MAX(cs_glob_rank_id, 0);
 
773
 
 
774
  /* Allocate and intialize vtx_tag associated to the local rank */
 
775
 
 
776
  block_size = n_g_vertices_to_treat / n_ranks;
 
777
  left_over = n_g_vertices_to_treat % n_ranks;
 
778
  if (local_rank < left_over)
 
779
    block_size += 1;
 
780
 
 
781
  BFT_MALLOC(glob_vtx_tag, block_size, fvm_gnum_t);
 
782
  BFT_MALLOC(prev_glob_vtx_tag, block_size, fvm_gnum_t);
 
783
 
 
784
  for (i = 0; i < block_size; i++) {
 
785
    prev_glob_vtx_tag[i] = i*n_ranks + local_rank + 1;
 
786
    glob_vtx_tag[i] = i*n_ranks + local_rank + 1;
 
787
  }
 
788
 
 
789
  /* Allocate and define send/recv_count/shift */
 
790
 
 
791
  BFT_MALLOC(send_count, n_ranks, cs_int_t);
 
792
  BFT_MALLOC(recv_count, n_ranks, cs_int_t);
 
793
  BFT_MALLOC(send_shift, n_ranks + 1, cs_int_t);
 
794
  BFT_MALLOC(recv_shift, n_ranks + 1, cs_int_t);
 
795
 
 
796
  send_shift[0] = 0;
 
797
  recv_shift[0] = 0;
 
798
 
 
799
  for (i = 0; i < n_ranks; i++)
 
800
    send_count[i] = 0;
 
801
 
 
802
  for (i = 0; i < n_vertices; i++) {
 
803
    int  rank = (work->vertices[i].gnum - 1) % n_ranks;
 
804
    send_count[rank] += 1;
 
805
  }
 
806
 
 
807
  MPI_Alltoall(&(send_count[0]), 1, FVM_MPI_LNUM,
 
808
               &(recv_count[0]), 1, FVM_MPI_LNUM, mpi_comm);
 
809
 
 
810
  /* Build index */
 
811
 
 
812
  for (i = 0; i < n_ranks; i++) {
 
813
    send_shift[i+1] = send_shift[i] + send_count[i];
 
814
    recv_shift[i+1] = recv_shift[i] + recv_count[i];
 
815
  }
 
816
 
 
817
  assert(send_shift[n_ranks] == n_vertices);
 
818
 
 
819
  /* Allocate and define recv2glob */
 
820
 
 
821
  BFT_MALLOC(send_glob_buffer, send_shift[n_ranks], fvm_gnum_t);
 
822
  BFT_MALLOC(recv2glob, recv_shift[n_ranks], fvm_gnum_t);
 
823
  BFT_MALLOC(recv_glob_buffer, recv_shift[n_ranks], fvm_gnum_t);
 
824
 
 
825
  for (i = 0; i < n_ranks; i++)
 
826
    send_count[i] = 0;
 
827
 
 
828
  for (i = 0; i < n_vertices; i++) {
 
829
 
 
830
    int  rank = (work->vertices[i].gnum - 1) % n_ranks;
 
831
    cs_int_t  shift = send_shift[rank] + send_count[rank];
 
832
 
 
833
    send_glob_buffer[shift] = (work->vertices[i].gnum - 1) / n_ranks;
 
834
    send_count[rank] += 1;
 
835
 
 
836
  }
 
837
 
 
838
  MPI_Alltoallv(send_glob_buffer, send_count, send_shift, FVM_MPI_GNUM,
 
839
                recv2glob, recv_count, recv_shift, FVM_MPI_GNUM,
 
840
                mpi_comm);
 
841
 
 
842
  /* Return pointers */
 
843
 
 
844
  *p_block_size = block_size;
 
845
  *p_send_count = send_count;
 
846
  *p_recv_count = recv_count;
 
847
  *p_send_shift = send_shift;
 
848
  *p_recv_shift = recv_shift;
 
849
  *p_send_glob_buf = send_glob_buffer;
 
850
  *p_recv_glob_buf = recv_glob_buffer;
 
851
  *p_recv2glob = recv2glob;
 
852
  *p_glob_vtx_tag = glob_vtx_tag;
 
853
  *p_prev_glob_vtx_tag = prev_glob_vtx_tag;
 
854
 
 
855
}
 
856
 
 
857
#endif /* HAVE_MPI */
 
858
 
 
859
/*----------------------------------------------------------------------------
 
860
 * Tag with the same number all the vertices which might be merged together
 
861
 *
 
862
 * parameters:
 
863
 *   n_g_vertices_tot <-- global number of vertices to consider for the
 
864
 *                        merge operation (existing + created vertices)
 
865
 *   vtx_eset         <-- structure dealing with vertex equivalences
 
866
 *   work             <-- local cs_join_mesh_t structure which has initial
 
867
 *                        vertex data
 
868
 *   verbosity        <-- level of detail in information display
 
869
 *   p_vtx_tag        --> pointer to the vtx_tag for the local vertices
 
870
 *---------------------------------------------------------------------------*/
 
871
 
 
872
static void
 
873
_tag_equiv_vertices(fvm_gnum_t             n_g_vertices_tot,
 
874
                    const cs_join_eset_t  *vtx_eset,
 
875
                    const cs_join_mesh_t  *work,
 
876
                    int                    verbosity,
 
877
                    fvm_gnum_t            *p_vtx_tag[])
 
878
{
 
879
  cs_int_t  i;
 
880
 
 
881
  fvm_gnum_t  *vtx_tag = NULL;
 
882
  fvm_gnum_t  *prev_vtx_tag = NULL;
 
883
  FILE  *logfile = cs_glob_join_log;
 
884
 
 
885
  const cs_int_t  n_vertices = work->n_vertices;
 
886
  const int  n_ranks = cs_glob_n_ranks;
 
887
 
 
888
  /* Local initialization : we tag each vertex by its global number */
 
889
 
 
890
  BFT_MALLOC(prev_vtx_tag, n_vertices, fvm_gnum_t);
 
891
  BFT_MALLOC(vtx_tag, n_vertices, fvm_gnum_t);
 
892
 
 
893
  for (i = 0; i < work->n_vertices; i++) {
 
894
 
 
895
    fvm_gnum_t  v_gnum = work->vertices[i].gnum;
 
896
 
 
897
    vtx_tag[i] = v_gnum;
 
898
    prev_vtx_tag[i] = v_gnum;
 
899
 
 
900
  }
 
901
 
 
902
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
903
  for (i = 0; i < n_vertices; i++)
 
904
    fprintf(logfile, " Initial vtx_tag[%6d] = %9llu\n",
 
905
            i, (unsigned long long)vtx_tag[i]);
 
906
  fflush(logfile);
 
907
#endif
 
908
 
 
909
  /* Compute vtx_tag */
 
910
 
 
911
  _local_spread(vtx_eset, n_vertices, prev_vtx_tag, vtx_tag);
 
912
 
 
913
  if (n_ranks > 1) { /* Parallel treatment */
 
914
 
 
915
    cs_bool_t  go_on;
 
916
 
 
917
    cs_int_t  block_size = 0;
 
918
    cs_int_t  *send_count = NULL, *recv_count = NULL;
 
919
    cs_int_t  *send_shift = NULL, *recv_shift = NULL;
 
920
    fvm_gnum_t  *recv2glob = NULL;
 
921
    fvm_gnum_t  *recv_glob_buffer = NULL, *send_glob_buffer = NULL;
 
922
    fvm_gnum_t  *glob_vtx_tag = NULL, *prev_glob_vtx_tag = NULL;
 
923
 
 
924
#if defined(HAVE_MPI)
 
925
    _parall_tag_init(n_g_vertices_tot,
 
926
                     work,
 
927
                     &block_size,
 
928
                     &send_count, &send_shift, &send_glob_buffer,
 
929
                     &recv_count, &recv_shift, &recv_glob_buffer,
 
930
                     &recv2glob,
 
931
                     &glob_vtx_tag,
 
932
                     &prev_glob_vtx_tag);
 
933
 
 
934
    go_on = _global_spread(block_size,
 
935
                           work,
 
936
                           vtx_tag,
 
937
                           glob_vtx_tag,
 
938
                           prev_glob_vtx_tag,
 
939
                           recv2glob,
 
940
                           send_count, send_shift, send_glob_buffer,
 
941
                           recv_count, recv_shift, recv_glob_buffer);
 
942
 
 
943
    while (go_on == true) {
 
944
 
 
945
      /* Local convergence of vtx_tag */
 
946
 
 
947
      _local_spread(vtx_eset, n_vertices, prev_vtx_tag, vtx_tag);
 
948
 
 
949
      /* Global update and test to continue */
 
950
 
 
951
      go_on = _global_spread(block_size,
 
952
                             work,
 
953
                             vtx_tag,
 
954
                             glob_vtx_tag,
 
955
                             prev_glob_vtx_tag,
 
956
                             recv2glob,
 
957
                             send_count, send_shift, send_glob_buffer,
 
958
                             recv_count, recv_shift, recv_glob_buffer);
 
959
 
 
960
    }
 
961
 
 
962
    /* Partial free */
 
963
 
 
964
    BFT_FREE(glob_vtx_tag);
 
965
    BFT_FREE(prev_glob_vtx_tag);
 
966
    BFT_FREE(send_count);
 
967
    BFT_FREE(send_shift);
 
968
    BFT_FREE(send_glob_buffer);
 
969
    BFT_FREE(recv_count);
 
970
    BFT_FREE(recv_shift);
 
971
    BFT_FREE(recv2glob);
 
972
    BFT_FREE(recv_glob_buffer);
 
973
 
 
974
#endif
 
975
  } /* End of parallel treatment */
 
976
 
 
977
  BFT_FREE(prev_vtx_tag);
 
978
 
 
979
  if (verbosity > 3) {
 
980
    fprintf(logfile,
 
981
            "\n  Number of local iterations to converge on vertex"
 
982
            " equivalences: %3d\n", _loc_merge_counter);
 
983
    if (n_ranks > 1)
 
984
      fprintf(logfile,
 
985
              "  Number of global iterations to converge on vertex"
 
986
              " equivalences: %3d\n\n", _glob_merge_counter);
 
987
    fflush(logfile);
 
988
  }
 
989
 
 
990
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
991
  if (logfile != NULL) {
 
992
    for (i = 0; i < n_vertices; i++)
 
993
      fprintf(logfile, " Final vtx_tag[%6d] = %9llu\n",
 
994
              i, (unsigned long long)vtx_tag[i]);
 
995
    fflush(logfile);
 
996
  }
 
997
#endif
 
998
 
 
999
  /* Returns pointer */
 
1000
 
 
1001
  *p_vtx_tag = vtx_tag;
 
1002
}
 
1003
 
 
1004
#if defined(HAVE_MPI)
 
1005
 
 
1006
/*----------------------------------------------------------------------------
 
1007
 * Build in parallel a cs_join_gset_t structure to store all the potential
 
1008
 * merges between vertices and its associated cs_join_vertex_t structure.
 
1009
 *
 
1010
 * parameters:
 
1011
 *   work             <-- local cs_join_mesh_t structure which
 
1012
 *                        has initial vertex data
 
1013
 *   vtx_tag          <-- local vtx_tag for the local vertices
 
1014
 *   send_count       <-> buffer used to count the number of elts to send
 
1015
 *   send_shift       <-> index on ranks of the elements to send
 
1016
 *   recv_count       <-> buffer used to count the number of elts to receive
 
1017
 *   recv_shift       <-> index on ranks of the elements to receive
 
1018
 *   p_vtx_merge_data <-> a pointer to a cs_join_vertex_t structure which
 
1019
 *                        stores data about merged vertices
 
1020
 *   p_merge_set      <-> pointer to a cs_join_gset_t struct. storing the
 
1021
 *                        evolution of each global vtx number
 
1022
 *---------------------------------------------------------------------------*/
 
1023
 
 
1024
static void
 
1025
_build_parall_merge_structures(const cs_join_mesh_t    *work,
 
1026
                               const fvm_gnum_t         vtx_tag[],
 
1027
                               cs_int_t                 send_count[],
 
1028
                               cs_int_t                 send_shift[],
 
1029
                               cs_int_t                 recv_count[],
 
1030
                               cs_int_t                 recv_shift[],
 
1031
                               cs_join_vertex_t        *p_vtx_merge_data[],
 
1032
                               cs_join_gset_t         **p_merge_set)
 
1033
{
 
1034
  cs_int_t  i;
 
1035
 
 
1036
  cs_int_t  n_vertices = work->n_vertices;
 
1037
  fvm_gnum_t  *recv_gbuf = NULL, *send_gbuf = NULL;
 
1038
  cs_join_vertex_t  *send_vtx_data = NULL, *recv_vtx_data = NULL;
 
1039
  cs_join_gset_t  *merge_set = NULL;
 
1040
 
 
1041
  MPI_Datatype  CS_MPI_JOIN_VERTEX = cs_join_mesh_create_vtx_datatype();
 
1042
  MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
1043
 
 
1044
  const int  n_ranks = cs_glob_n_ranks;
 
1045
 
 
1046
  for (i = 0; i < n_ranks; i++)
 
1047
    send_count[i] = 0;
 
1048
 
 
1049
  for (i = 0; i < n_vertices; i++) {
 
1050
    int  rank = (vtx_tag[i] - 1) % n_ranks;
 
1051
    send_count[rank] += 1;
 
1052
  }
 
1053
 
 
1054
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, mpi_comm);
 
1055
 
 
1056
  /* Build index */
 
1057
 
 
1058
  send_shift[0] = 0;
 
1059
  recv_shift[0] = 0;
 
1060
 
 
1061
  for (i = 0; i < n_ranks; i++) {
 
1062
    send_shift[i+1] = send_shift[i] + send_count[i];
 
1063
    recv_shift[i+1] = recv_shift[i] + recv_count[i];
 
1064
  }
 
1065
 
 
1066
  assert(send_shift[n_ranks] == n_vertices);
 
1067
 
 
1068
  /* Allocate and define recv_gbuf and send_gbuf */
 
1069
 
 
1070
  BFT_MALLOC(send_gbuf, send_shift[n_ranks], fvm_gnum_t);
 
1071
  BFT_MALLOC(recv_gbuf, recv_shift[n_ranks], fvm_gnum_t);
 
1072
 
 
1073
  for (i = 0; i < n_ranks; i++)
 
1074
    send_count[i] = 0;
 
1075
 
 
1076
  for (i = 0; i < n_vertices; i++) {
 
1077
 
 
1078
    int  rank = (vtx_tag[i] - 1) % n_ranks;
 
1079
    cs_int_t  shift = send_shift[rank] + send_count[rank];
 
1080
 
 
1081
    send_gbuf[shift] = vtx_tag[i];
 
1082
    send_count[rank] += 1;
 
1083
 
 
1084
  }
 
1085
 
 
1086
  MPI_Alltoallv(send_gbuf, send_count, send_shift, FVM_MPI_GNUM,
 
1087
                recv_gbuf, recv_count, recv_shift, FVM_MPI_GNUM,
 
1088
                mpi_comm);
 
1089
 
 
1090
  /* Allocate and build send_vtx_data, receive recv_vtx_data. */
 
1091
 
 
1092
  BFT_MALLOC(recv_vtx_data, recv_shift[n_ranks], cs_join_vertex_t);
 
1093
  BFT_MALLOC(send_vtx_data, send_shift[n_ranks], cs_join_vertex_t);
 
1094
 
 
1095
  for (i = 0; i < n_ranks; i++)
 
1096
    send_count[i] = 0;
 
1097
 
 
1098
  for (i = 0; i < n_vertices; i++) {
 
1099
 
 
1100
    int  rank = (vtx_tag[i] - 1) % n_ranks;
 
1101
    cs_int_t  shift = send_shift[rank] + send_count[rank];
 
1102
 
 
1103
    send_vtx_data[shift] = work->vertices[i];
 
1104
    send_count[rank] += 1;
 
1105
 
 
1106
  }
 
1107
 
 
1108
  MPI_Alltoallv(send_vtx_data, send_count, send_shift, CS_MPI_JOIN_VERTEX,
 
1109
                recv_vtx_data, recv_count, recv_shift, CS_MPI_JOIN_VERTEX,
 
1110
                mpi_comm);
 
1111
 
 
1112
  /* Partial free memory */
 
1113
 
 
1114
  BFT_FREE(send_vtx_data);
 
1115
  BFT_FREE(send_gbuf);
 
1116
  MPI_Type_free(&CS_MPI_JOIN_VERTEX);
 
1117
 
 
1118
  /* Build merge set */
 
1119
 
 
1120
  merge_set = cs_join_gset_create_from_tag(recv_shift[n_ranks], recv_gbuf);
 
1121
 
 
1122
  cs_join_gset_sort_sublist(merge_set);
 
1123
 
 
1124
  /* Free memory */
 
1125
 
 
1126
  BFT_FREE(recv_gbuf);
 
1127
 
 
1128
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
1129
  if (cs_glob_join_log != NULL) {
 
1130
    FILE *logfile = cs_glob_join_log;
 
1131
    fprintf(logfile,
 
1132
            "\n  Number of vertices to treat for the merge step: %d\n",
 
1133
            recv_shift[n_ranks]);
 
1134
    fprintf(logfile,
 
1135
            "  List of vertices to treat:\n");
 
1136
    for (i = 0; i < recv_shift[n_ranks]; i++) {
 
1137
      fprintf(logfile, " %9d - ", i);
 
1138
      cs_join_mesh_dump_vertex(logfile, recv_vtx_data[i]);
 
1139
    }
 
1140
    fflush(logfile);
 
1141
  }
 
1142
#endif
 
1143
 
 
1144
  /* Set return pointers */
 
1145
 
 
1146
  *p_merge_set = merge_set;
 
1147
  *p_vtx_merge_data = recv_vtx_data;
 
1148
}
 
1149
 
 
1150
/*----------------------------------------------------------------------------
 
1151
 * Exchange the updated cs_join_vertex_t array over the ranks.
 
1152
 *
 
1153
 * parameters:
 
1154
 *   work           <-- local cs_join_mesh_t structure which
 
1155
 *                      has initial vertex data
 
1156
 *   vtx_tag        <-- local vtx_tag for the local vertices
 
1157
 *   send_count     <-- buffer used to count the number of elts to send
 
1158
 *   send_shift     <-- index on ranks of the elements to send
 
1159
 *   recv_count     <-- buffer used to count the number of elts to receive
 
1160
 *   recv_shift     <-- index on ranks of the elements to receive
 
1161
 *   vtx_merge_data <-- pointer to a cs_join_vertex_t structure
 
1162
 *---------------------------------------------------------------------------*/
 
1163
 
 
1164
static void
 
1165
_exchange_merged_vertices(const cs_join_mesh_t  *work,
 
1166
                          const fvm_gnum_t       vtx_tag[],
 
1167
                          cs_int_t               send_count[],
 
1168
                          cs_int_t               send_shift[],
 
1169
                          cs_int_t               recv_count[],
 
1170
                          cs_int_t               recv_shift[],
 
1171
                          cs_join_vertex_t       vtx_merge_data[])
 
1172
{
 
1173
  cs_int_t  i;
 
1174
 
 
1175
  cs_join_vertex_t  *updated_vtx_data = NULL;
 
1176
  int  n_ranks = cs_glob_n_ranks;
 
1177
  MPI_Datatype  cs_mpi_join_vertex = cs_join_mesh_create_vtx_datatype();
 
1178
  MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
1179
 
 
1180
  /* Allocate send_vtx_data and exchange vtx_merge_data */
 
1181
 
 
1182
  BFT_MALLOC(updated_vtx_data, send_shift[n_ranks], cs_join_vertex_t);
 
1183
 
 
1184
  MPI_Alltoallv(vtx_merge_data, recv_count, recv_shift, cs_mpi_join_vertex,
 
1185
                updated_vtx_data, send_count, send_shift, cs_mpi_join_vertex,
 
1186
                mpi_comm);
 
1187
 
 
1188
  /* Replace work->vertices by the updated structure after merge
 
1189
     of vertices */
 
1190
 
 
1191
  assert(send_shift[n_ranks] == work->n_vertices);
 
1192
 
 
1193
  for (i = 0; i < n_ranks; i++)
 
1194
    send_count[i] = 0;
 
1195
 
 
1196
  for (i = 0; i < work->n_vertices; i++) {
 
1197
 
 
1198
    int  rank = (vtx_tag[i] - 1) % n_ranks;
 
1199
    cs_int_t  shift = send_shift[rank] + send_count[rank];
 
1200
 
 
1201
    work->vertices[i] = updated_vtx_data[shift];
 
1202
    send_count[rank] += 1;
 
1203
 
 
1204
  }
 
1205
 
 
1206
  /* Free memory */
 
1207
 
 
1208
  MPI_Type_free(&cs_mpi_join_vertex);
 
1209
  BFT_FREE(updated_vtx_data);
 
1210
}
 
1211
 
 
1212
#endif /* HAVE_MPI */
 
1213
 
 
1214
/*----------------------------------------------------------------------------
 
1215
 * Get the resulting cs_join_vertex_t structure after the merge of a set
 
1216
 * of vertices.
 
1217
 *
 
1218
 * parameters:
 
1219
 *   n_elts    <-- size of the set
 
1220
 *   set       <-- set of vertices
 
1221
 *
 
1222
 * returns:
 
1223
 *   a cs_join_vertex_t structure for the resulting vertex
 
1224
 *---------------------------------------------------------------------------*/
 
1225
 
 
1226
static cs_join_vertex_t
 
1227
_compute_merged_vertex(cs_int_t                n_elts,
 
1228
                       const cs_join_vertex_t  set[])
 
1229
{
 
1230
  cs_int_t  i, k;
 
1231
  cs_real_t  w;
 
1232
  cs_join_vertex_t  mvtx;
 
1233
 
 
1234
  cs_real_t  denum = 0.0;
 
1235
 
 
1236
  assert(n_elts > 0);
 
1237
 
 
1238
  /* Initialize cs_join_vertex_t structure */
 
1239
 
 
1240
  mvtx.state = CS_JOIN_STATE_UNDEF;
 
1241
  mvtx.gnum = set[0].gnum;
 
1242
  mvtx.tolerance = set[0].tolerance;
 
1243
 
 
1244
  for (k = 0; k < 3; k++)
 
1245
    mvtx.coord[k] = 0.0;
 
1246
 
 
1247
  /* Compute the resulting vertex */
 
1248
 
 
1249
  for (i = 0; i < n_elts; i++) {
 
1250
 
 
1251
    mvtx.tolerance = CS_MIN(set[i].tolerance, mvtx.tolerance);
 
1252
    mvtx.gnum = CS_MIN(set[i].gnum, mvtx.gnum);
 
1253
    mvtx.state = CS_MAX(set[i].state, mvtx.state);
 
1254
 
 
1255
    /* Compute the resulting coordinates of the merged vertices */
 
1256
 
 
1257
#if CS_JOIN_MERGE_INV_TOL
 
1258
    w = 1.0/set[i].tolerance;
 
1259
#else
 
1260
    w = 1.0;
 
1261
#endif
 
1262
    denum += w;
 
1263
 
 
1264
    for (k = 0; k < 3; k++)
 
1265
      mvtx.coord[k] += w * set[i].coord[k];
 
1266
 
 
1267
  }
 
1268
 
 
1269
  for (k = 0; k < 3; k++)
 
1270
    mvtx.coord[k] /= denum;
 
1271
 
 
1272
  if (mvtx.state == CS_JOIN_STATE_ORIGIN)
 
1273
    mvtx.state = CS_JOIN_STATE_MERGE;
 
1274
  else if (mvtx.state == CS_JOIN_STATE_PERIO)
 
1275
    mvtx.state = CS_JOIN_STATE_PERIO_MERGE;
 
1276
 
 
1277
  return mvtx;
 
1278
}
 
1279
 
 
1280
/*----------------------------------------------------------------------------
 
1281
 * Merge between identical vertices.
 
1282
 *
 
1283
 * Only the vertex numbering and the related tolerance may be different.
 
1284
 * Store new data associated to the merged vertices in vertices array.
 
1285
 *
 
1286
 * parameters:
 
1287
 *   param      <-- set of user-defined parameters
 
1288
 *   merge_set  <-> a pointer to a cs_join_vertex_t structure which
 
1289
 *                  stores data about merged vertices
 
1290
 *   n_vertices <-- number of vertices in vertices array
 
1291
 *   vertices   <-> array of cs_join_vertex_t structures
 
1292
 *   equiv_gnum --> equivalence between id in vertices (same global number
 
1293
 *                  initially or identical vertices: same coordinates)
 
1294
 *---------------------------------------------------------------------------*/
 
1295
 
 
1296
static void
 
1297
_pre_merge(cs_join_param_t     param,
 
1298
           cs_join_gset_t     *merge_set,
 
1299
           cs_join_vertex_t    vertices[],
 
1300
           cs_join_gset_t    **p_equiv_gnum)
 
1301
{
 
1302
  cs_int_t  i, j, j1, j2, k, k1, k2, n_sub_elts;
 
1303
  cs_real_t  deltad, deltat, limit, min_tol;
 
1304
  cs_join_vertex_t  mvtx, coupled_vertices[2];
 
1305
 
 
1306
  cs_int_t  max_n_sub_elts = 0, n_local_pre_merge = 0;
 
1307
  cs_int_t  *merge_index = merge_set->index;
 
1308
  fvm_gnum_t  *merge_list = merge_set->g_list;
 
1309
  fvm_gnum_t  *sub_list = NULL, *init_list = NULL;
 
1310
  cs_join_gset_t  *equiv_gnum = NULL;
 
1311
 
 
1312
  const cs_real_t  pmf = param.pre_merge_factor;
 
1313
 
 
1314
  cs_join_gset_sort_sublist(merge_set);
 
1315
 
 
1316
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
1317
  {
 
1318
    int  len;
 
1319
    FILE  *dbg_file = NULL;
 
1320
    char  *filename = NULL;
 
1321
 
 
1322
    len = strlen("JoinDBG_InitMergeSet.dat")+1+2+4;
 
1323
    BFT_MALLOC(filename, len, char);
 
1324
    sprintf(filename, "Join%02dDBG_InitMergeSet%04d.dat",
 
1325
            param.num, CS_MAX(cs_glob_rank_id, 0));
 
1326
    dbg_file = fopen(filename, "w");
 
1327
 
 
1328
    cs_join_gset_dump(dbg_file, merge_set);
 
1329
 
 
1330
    fflush(dbg_file);
 
1331
    BFT_FREE(filename);
 
1332
    fclose(dbg_file);
 
1333
  }
 
1334
#endif
 
1335
 
 
1336
  /* Compute the max. size of a sub list */
 
1337
 
 
1338
  for (i = 0; i < merge_set->n_elts; i++)
 
1339
    max_n_sub_elts = CS_MAX(max_n_sub_elts,
 
1340
                            merge_index[i+1] - merge_index[i]);
 
1341
 
 
1342
  BFT_MALLOC(sub_list, max_n_sub_elts, fvm_gnum_t);
 
1343
 
 
1344
  /* Store initial merge list */
 
1345
 
 
1346
  BFT_MALLOC(init_list, merge_index[merge_set->n_elts], fvm_gnum_t);
 
1347
 
 
1348
  for (i = 0; i < merge_index[merge_set->n_elts]; i++)
 
1349
    init_list[i] = merge_list[i];
 
1350
 
 
1351
  /* Apply merge */
 
1352
 
 
1353
  for (i = 0; i < merge_set->n_elts; i++) {
 
1354
 
 
1355
    cs_int_t  f_s = merge_index[i];
 
1356
    cs_int_t  f_e = merge_index[i+1];
 
1357
 
 
1358
    n_sub_elts = f_e - f_s;
 
1359
 
 
1360
    for (j = f_s, k = 0; j < f_e; j++, k++)
 
1361
      sub_list[k] = merge_list[j];
 
1362
 
 
1363
    for (j1 = 0; j1 < n_sub_elts - 1; j1++) {
 
1364
 
 
1365
      cs_int_t  v1_id = sub_list[j1];
 
1366
      cs_join_vertex_t  v1 = vertices[v1_id];
 
1367
 
 
1368
      for (j2 = j1 + 1; j2 < n_sub_elts; j2++) {
 
1369
 
 
1370
        cs_int_t  v2_id = sub_list[j2];
 
1371
        cs_join_vertex_t  v2 = vertices[v2_id];
 
1372
 
 
1373
        if (v1.gnum == v2.gnum) { /* Possible if n_ranks > 1 */
 
1374
 
 
1375
          if (sub_list[j1] < sub_list[j2])
 
1376
            k1 = j1, k2 = j2;
 
1377
          else
 
1378
            k1 = j2, k2 = j1;
 
1379
 
 
1380
          for (k = 0; k < n_sub_elts; k++)
 
1381
            if (sub_list[k] == sub_list[k2])
 
1382
              sub_list[k] = sub_list[k1];
 
1383
 
 
1384
        }
 
1385
        else {
 
1386
 
 
1387
          min_tol = CS_MIN(v1.tolerance, v2.tolerance);
 
1388
          limit = min_tol * pmf;
 
1389
          deltat = CS_ABS(v1.tolerance - v2.tolerance);
 
1390
 
 
1391
          if (deltat < limit) {
 
1392
 
 
1393
            deltad = _compute_length(v1, v2);
 
1394
 
 
1395
            if (deltad < limit) { /* Do a pre-merge */
 
1396
 
 
1397
              n_local_pre_merge++;
 
1398
 
 
1399
              if (v1.gnum < v2.gnum)
 
1400
                k1 = j1, k2 = j2;
 
1401
              else
 
1402
                k1 = j2, k2 = j1;
 
1403
 
 
1404
              for (k = 0; k < n_sub_elts; k++)
 
1405
                if (sub_list[k] == sub_list[k2])
 
1406
                  sub_list[k] = sub_list[k1];
 
1407
 
 
1408
              coupled_vertices[0] = v1, coupled_vertices[1] = v2;
 
1409
              mvtx = _compute_merged_vertex(2, coupled_vertices);
 
1410
              vertices[v1_id] = mvtx;
 
1411
              vertices[v2_id] = mvtx;
 
1412
 
 
1413
            } /* deltad < limit */
 
1414
 
 
1415
          } /* deltat < limit */
 
1416
 
 
1417
        } /* v1.gnum != v2.gnum */
 
1418
 
 
1419
      } /* End of loop on j2 */
 
1420
    } /* End of loop on j1 */
 
1421
 
 
1422
    /* Update vertices */
 
1423
 
 
1424
    for (j = f_s, k = 0; j < f_e; j++, k++)
 
1425
      vertices[merge_list[j]] = vertices[sub_list[k]];
 
1426
 
 
1427
    /* Update merge list */
 
1428
 
 
1429
    for (j = f_s, k = 0; j < f_e; j++, k++)
 
1430
      merge_list[j] = sub_list[k];
 
1431
 
 
1432
  } /* End of loop on merge_set elements */
 
1433
 
 
1434
  /* Keep equivalences between identical vertices in equiv_gnum */
 
1435
 
 
1436
  equiv_gnum = cs_join_gset_create_by_equiv(merge_set, init_list);
 
1437
 
 
1438
  /* Clean merge set */
 
1439
 
 
1440
  cs_join_gset_clean(merge_set);
 
1441
 
 
1442
  /* Display information about the joining */
 
1443
 
 
1444
  if (param.verbosity > 0) {
 
1445
 
 
1446
    fvm_gnum_t n_g_counter = n_local_pre_merge;
 
1447
    fvm_parall_counter(&n_g_counter, 1);
 
1448
 
 
1449
    bft_printf(_("\n  Pre-merge for %llu global element couples.\n"),
 
1450
               (unsigned long long)n_g_counter);
 
1451
 
 
1452
    if (param.verbosity > 2) {
 
1453
      fprintf(cs_glob_join_log, "\n  Local number of pre-merges: %d\n",
 
1454
              n_local_pre_merge);
 
1455
    }
 
1456
  }
 
1457
 
 
1458
  /* Free memory */
 
1459
 
 
1460
  BFT_FREE(sub_list);
 
1461
  BFT_FREE(init_list);
 
1462
 
 
1463
  /* Return pointer */
 
1464
 
 
1465
  *p_equiv_gnum = equiv_gnum;
 
1466
}
 
1467
 
 
1468
/*----------------------------------------------------------------------------
 
1469
 * Check if all vertices in the set include the ref_vertex in their tolerance.
 
1470
 *
 
1471
 * parameters:
 
1472
 *   set_size   <-- size of set of vertices
 
1473
 *   vertices   <-- set of vertices to check
 
1474
 *   ref_vertex <-- ref. vertex
 
1475
 *
 
1476
 * returns:
 
1477
 *   true if all vertices have ref_vertex in their tolerance, false otherwise
 
1478
 *---------------------------------------------------------------------------*/
 
1479
 
 
1480
static cs_bool_t
 
1481
_is_in_tolerance(cs_int_t                set_size,
 
1482
                 const cs_join_vertex_t  set[],
 
1483
                 cs_join_vertex_t        ref_vertex)
 
1484
{
 
1485
  cs_int_t  i;
 
1486
 
 
1487
  for (i = 0; i < set_size; i++) {
 
1488
 
 
1489
    cs_real_t  d2ref = _compute_length(set[i], ref_vertex);
 
1490
    cs_real_t  tolerance =  set[i].tolerance * cs_join_tol_eps_coef2;
 
1491
 
 
1492
    if (d2ref > tolerance)
 
1493
      return false;
 
1494
 
 
1495
  }
 
1496
 
 
1497
  return true;
 
1498
}
 
1499
 
 
1500
/*----------------------------------------------------------------------------
 
1501
 * Test if we have to continue to the subset building
 
1502
 *
 
1503
 * parameters:
 
1504
 *   set_size  <-- size of set
 
1505
 *   prev_num  <-> array used to store previous subset_num
 
1506
 *   new_num   <-> number associated to each vertices of the set
 
1507
 *
 
1508
 * returns:
 
1509
 *   true or false
 
1510
 *---------------------------------------------------------------------------*/
 
1511
 
 
1512
static cs_bool_t
 
1513
_continue_subset_building(int              set_size,
 
1514
                          const cs_int_t   prev_num[],
 
1515
                          const cs_int_t   new_num[])
 
1516
{
 
1517
  int  i;
 
1518
 
 
1519
  for (i = 0; i < set_size; i++)
 
1520
    if (new_num[i] != prev_num[i])
 
1521
      return true;
 
1522
 
 
1523
  return false;
 
1524
}
 
1525
 
 
1526
/*----------------------------------------------------------------------------
 
1527
 * Define subsets of vertices.
 
1528
 *
 
1529
 * parameters:
 
1530
 *   set_size    <-- size of set
 
1531
 *   state       <-- array keeping the state of the link
 
1532
 *   subset_num  <-> number associated to each vertices of the set
 
1533
 *---------------------------------------------------------------------------*/
 
1534
 
 
1535
static void
 
1536
_iter_subset_building(cs_int_t                set_size,
 
1537
                      const cs_int_t          state[],
 
1538
                      cs_int_t                subset_num[])
 
1539
{
 
1540
  cs_int_t  i1, i2, k;
 
1541
 
 
1542
  for (k = 0, i1 = 0; i1 < set_size-1; i1++) {
 
1543
    for (i2 = i1 + 1; i2 < set_size; i2++, k++) {
 
1544
 
 
1545
      if (state[k] == 1) { /* v1 - v2 are in tolerance each other */
 
1546
 
 
1547
        int _min = CS_MIN(subset_num[i1], subset_num[i2]);
 
1548
 
 
1549
        subset_num[i1] = _min;
 
1550
        subset_num[i2] = _min;
 
1551
 
 
1552
      }
 
1553
 
 
1554
    }
 
1555
  }
 
1556
 
 
1557
}
 
1558
 
 
1559
/*----------------------------------------------------------------------------
 
1560
 * Define subsets of vertices.
 
1561
 *
 
1562
 * parameters:
 
1563
 *   set_size    <-- size of set
 
1564
 *   state       <-- array keeping the state of the link
 
1565
 *   prev_num    <-> array used to store previous subset_num
 
1566
 *   subset_num  <-> number associated to each vertices of the set
 
1567
 *---------------------------------------------------------------------------*/
 
1568
 
 
1569
static void
 
1570
_build_subsets(cs_int_t          set_size,
 
1571
               const cs_int_t    state[],
 
1572
               cs_int_t          prev_num[],
 
1573
               cs_int_t          subset_num[])
 
1574
{
 
1575
  int  i;
 
1576
  cs_int_t  n_loops = 0;
 
1577
 
 
1578
  /* Initialize */
 
1579
 
 
1580
  for (i = 0; i < set_size; i++) {
 
1581
    subset_num[i] = i+1;
 
1582
    prev_num[i] = subset_num[i];
 
1583
  }
 
1584
 
 
1585
  _iter_subset_building(set_size, state, subset_num);
 
1586
 
 
1587
  while (   _continue_subset_building(set_size, prev_num, subset_num)
 
1588
         && n_loops < CS_JOIN_MERGE_MAX_LOC_ITERS ) {
 
1589
 
 
1590
    n_loops++;
 
1591
 
 
1592
    for (i = 0; i < set_size; i++)
 
1593
      prev_num[i] = subset_num[i];
 
1594
 
 
1595
    _iter_subset_building(set_size, state, subset_num);
 
1596
 
 
1597
  }
 
1598
 
 
1599
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
1600
  if (cs_glob_join_log != NULL && n_loops >= CS_JOIN_MERGE_MAX_LOC_ITERS)
 
1601
    fprintf(cs_glob_join_log,
 
1602
            "WARNING max sub_loops to build subset reached\n");
 
1603
#endif
 
1604
 
 
1605
}
 
1606
 
 
1607
/*----------------------------------------------------------------------------
 
1608
 * Check if each subset is consistent with tolerance of vertices
 
1609
 * If a transitivity is found, modify the state of the link
 
1610
 * state = 1 (each other in their tolerance)
 
1611
 *       = 0 (not each other in their tolerance)
 
1612
 *
 
1613
 * parameters:
 
1614
 *   set_size    <-- size of set
 
1615
 *   set         <-- pointer to a set of vertices
 
1616
 *   state       <-> array keeping the state of the link
 
1617
 *   subset_num  <-> number associated to each vertices of the set
 
1618
 *   issues      <-> numbering of inconsistent subsets
 
1619
 *   verbosity   <-- level of verbosity
 
1620
 *
 
1621
 * returns:
 
1622
 *  number of subsets not consistent
 
1623
 *---------------------------------------------------------------------------*/
 
1624
 
 
1625
static cs_int_t
 
1626
_check_tol_consistency(cs_int_t                set_size,
 
1627
                       const cs_join_vertex_t  set[],
 
1628
                       cs_int_t                state[],
 
1629
                       cs_int_t                subset_num[],
 
1630
                       cs_int_t                issues[],
 
1631
                       cs_int_t                verbosity)
 
1632
{
 
1633
  cs_int_t  i1, i2, j, k;
 
1634
 
 
1635
  cs_int_t  n_issues = 0;
 
1636
  FILE  *logfile = cs_glob_join_log;
 
1637
 
 
1638
  for (k = 0, i1 = 0; i1 < set_size-1; i1++) {
 
1639
    for (i2 = i1 + 1; i2 < set_size; i2++, k++) {
 
1640
 
 
1641
      if (state[k] == 0) {
 
1642
 
 
1643
        if (subset_num[i1] == subset_num[i2]) {
 
1644
 
 
1645
          if (verbosity > 4)
 
1646
            fprintf(logfile,
 
1647
                    " Transitivity detected between (%llu, %llu)\n",
 
1648
                    (unsigned long long)set[i1].gnum,
 
1649
                    (unsigned long long)set[i2].gnum);
 
1650
 
 
1651
          for (j = 0; j < n_issues; j++)
 
1652
            if (issues[j] == subset_num[i1])
 
1653
              break;
 
1654
          if (j == n_issues)
 
1655
            issues[n_issues++] = subset_num[i1];
 
1656
 
 
1657
        }
 
1658
      }
 
1659
 
 
1660
    } /* End of loop on i2 */
 
1661
  } /* ENd of loop on i1 */
 
1662
 
 
1663
  return  n_issues; /* Not a subset number */
 
1664
}
 
1665
 
 
1666
/*----------------------------------------------------------------------------
 
1667
 * Check if the merged vertex related to a subset is consistent with tolerance
 
1668
 * of each vertex of the subset.
 
1669
 *
 
1670
 * parameters:
 
1671
 *   set_size    <-- size of set
 
1672
 *   subset_num  <-- number associated to each vertices of the set
 
1673
 *   set         <-- pointer to a set of vertices
 
1674
 *   merge_set   <-> merged vertex related to each subset
 
1675
 *   work_set    <-> work array of vertices
 
1676
 *
 
1677
 * returns:
 
1678
 *  true if all subsets are consistent otherwise false
 
1679
 *---------------------------------------------------------------------------*/
 
1680
 
 
1681
static cs_bool_t
 
1682
_check_subset_consistency(cs_int_t                set_size,
 
1683
                          const cs_int_t          subset_num[],
 
1684
                          const cs_join_vertex_t  set[],
 
1685
                          cs_join_vertex_t        merge_set[],
 
1686
                          cs_join_vertex_t        work_set[])
 
1687
{
 
1688
  cs_int_t  i, set_id, subset_size;
 
1689
 
 
1690
  cs_bool_t  is_consistent = true;
 
1691
 
 
1692
  /* Apply merged to each subset */
 
1693
 
 
1694
  for (set_id = 0; set_id < set_size; set_id++) {
 
1695
 
 
1696
    subset_size = 0;
 
1697
    for (i = 0; i < set_size; i++)
 
1698
      if (subset_num[i] == set_id+1)
 
1699
        work_set[subset_size++] = set[i];
 
1700
 
 
1701
    if (subset_size > 0) {
 
1702
 
 
1703
      merge_set[set_id] = _compute_merged_vertex(subset_size, work_set);
 
1704
 
 
1705
      if (!_is_in_tolerance(subset_size, work_set, merge_set[set_id]))
 
1706
        is_consistent = false;
 
1707
 
 
1708
    }
 
1709
 
 
1710
  } /* End of loop on subsets */
 
1711
 
 
1712
  return is_consistent;
 
1713
}
 
1714
 
 
1715
/*----------------------------------------------------------------------------
 
1716
 * Get position of the link between vertices i1 and i2.
 
1717
 *
 
1718
 * parameters:
 
1719
 *   i1     <-- id in set for vertex 1
 
1720
 *   i2     <-- id in set for vertex 2
 
1721
 *   idx    <-- array of positions
 
1722
 *
 
1723
 * returns:
 
1724
 *   position in an array like distances or state
 
1725
 *---------------------------------------------------------------------------*/
 
1726
 
 
1727
inline static cs_int_t
 
1728
_get_pos(cs_int_t        i1,
 
1729
         cs_int_t        i2,
 
1730
         const cs_int_t  idx[])
 
1731
{
 
1732
  cs_int_t  pos = -1;
 
1733
 
 
1734
  if (i1 < i2)
 
1735
    pos = idx[i1] + i2-i1-1;
 
1736
  else {
 
1737
    assert(i1 != i2);
 
1738
    pos = idx[i2] + i1-i2-1;
 
1739
  }
 
1740
 
 
1741
  return pos;
 
1742
}
 
1743
 
 
1744
/*----------------------------------------------------------------------------
 
1745
 * Break equivalences for vertices implied in transitivity issue
 
1746
 *
 
1747
 * parameters:
 
1748
 *   param       <-- parameters used to manage the joining algorithm
 
1749
 *   set_size    <-- size of set
 
1750
 *   set         <-- pointer to a set of vertices
 
1751
 *   state       <-> array keeping the state of the link
 
1752
 *   n_issues    <-- number of detected transitivity issues
 
1753
 *   issues      <-- subset numbers of subset with a transitivity issue
 
1754
 *   idx         <-- position of vertices couple in array like distances
 
1755
 *   subset_num  <-- array of subset numbers
 
1756
 *   distances   <-- array keeping the distances between vertices
 
1757
 *---------------------------------------------------------------------------*/
 
1758
 
 
1759
static void
 
1760
_break_equivalence(cs_join_param_t         param,
 
1761
                   cs_int_t                set_size,
 
1762
                   const cs_join_vertex_t  set[],
 
1763
                   int                     state[],
 
1764
                   cs_int_t                n_issues,
 
1765
                   const int               issues[],
 
1766
                   const int               idx[],
 
1767
                   const int               subset_num[],
 
1768
                   const double            distances[])
 
1769
{
 
1770
  cs_int_t  i, i1, i2, k;
 
1771
 
 
1772
  for (i = 0; i < n_issues; i++) {
 
1773
 
 
1774
    /* Find the weakest equivalence and break it.
 
1775
       Purpose: Have the minimal number of equivalences to break
 
1776
       for each subset where an inconsistency has been detected */
 
1777
 
 
1778
    int  i_save = 0;
 
1779
    double rtf = -1.0, dist_save = 0.0;
 
1780
 
 
1781
    for (k = 0, i1 = 0; i1 < set_size-1; i1++) {
 
1782
      for (i2 = i1 + 1; i2 < set_size; i2++, k++) {
 
1783
 
 
1784
        if (state[k] == 1) { /* v1, v2 are equivalent */
 
1785
 
 
1786
          if (   subset_num[i1] == issues[i]
 
1787
              && subset_num[i2] == issues[i]) {
 
1788
 
 
1789
            /* Vertices belongs to a subset where an inconsistency
 
1790
               has been found */
 
1791
 
 
1792
            double  rtf12 = distances[k]/set[i1].tolerance;
 
1793
            double  rtf21 = distances[k]/set[i2].tolerance;
 
1794
 
 
1795
            assert(rtf12 < 1.0); /* Because they are equivalent */
 
1796
            assert(rtf21 < 1.0);
 
1797
 
 
1798
            if (rtf12 >= rtf21) {
 
1799
              if (rtf12 > rtf) {
 
1800
                rtf = rtf12;
 
1801
                i_save = i1;
 
1802
                dist_save = distances[k];
 
1803
              }
 
1804
            }
 
1805
            else {
 
1806
              if (rtf21 > rtf) {
 
1807
                rtf = rtf21;
 
1808
                i_save = i2;
 
1809
                dist_save = distances[k];
 
1810
              }
 
1811
            }
 
1812
 
 
1813
          }
 
1814
        }
 
1815
 
 
1816
      } /* End of loop on i1 */
 
1817
    } /* End of loop on i2 */
 
1818
 
 
1819
    if (rtf > 0.0) {
 
1820
 
 
1821
      /* Break equivalence between i_save and all vertices linked to
 
1822
         i_save with a distance to i_save >= dist_save */
 
1823
 
 
1824
      for (i2 = 0; i2 < set_size; i2++) {
 
1825
 
 
1826
        if (i2 != i_save) {
 
1827
 
 
1828
          k = _get_pos(i_save, i2, idx);
 
1829
          if (distances[k] >= dist_save && state[k] == 1) {
 
1830
 
 
1831
            state[k] = 0; /* Break equivalence */
 
1832
 
 
1833
            if (param.verbosity > 3)
 
1834
              fprintf(cs_glob_join_log,
 
1835
                      " %2d - Break equivalence between [%llu, %llu]"
 
1836
                      " (dist_ref: %6.4e)\n",
 
1837
                      issues[i],
 
1838
                      (unsigned long long)set[i_save].gnum,
 
1839
                      (unsigned long long)set[i2].gnum, dist_save);
 
1840
 
 
1841
          }
 
1842
        }
 
1843
 
 
1844
      } /* End of loop on vertices */
 
1845
 
 
1846
    } /* rtf > 0.0 */
 
1847
 
 
1848
  } /* End of loop on issues */
 
1849
 
 
1850
}
 
1851
 
 
1852
/*----------------------------------------------------------------------------
 
1853
 * Break equivalences between vertices until each vertex of the list has
 
1854
 * the resulting vertex of the merge under its tolerance.
 
1855
 *
 
1856
 * parameters:
 
1857
 *   param         <-- set of user-defined parameters
 
1858
 *   set_size      <-- size of the set of vertices
 
1859
 *   set           <-> set of vertices
 
1860
 *   vbuf          <-> tmp buffer
 
1861
 *   rbuf          <-> tmp buffer
 
1862
 *   ibuf          <-> tmp buffer
 
1863
 *
 
1864
 * returns:
 
1865
 *   number of loops necessary to build consistent subsets
 
1866
 *---------------------------------------------------------------------------*/
 
1867
 
 
1868
static cs_int_t
 
1869
_solve_transitivity(cs_join_param_t    param,
 
1870
                    cs_int_t           set_size,
 
1871
                    cs_join_vertex_t   set[],
 
1872
                    cs_join_vertex_t   vbuf[],
 
1873
                    cs_real_t          rbuf[],
 
1874
                    cs_int_t           ibuf[])
 
1875
{
 
1876
  cs_int_t  i1, i2, k, n_issues;
 
1877
 
 
1878
  cs_int_t  n_loops = 0;
 
1879
  cs_bool_t  is_end = false;
 
1880
  cs_int_t  *subset_num = NULL, *state = NULL, *prev_num = NULL;
 
1881
  cs_int_t  *subset_issues = NULL, *idx = NULL;
 
1882
  cs_real_t  *distances = NULL;
 
1883
  cs_join_vertex_t  *merge_set = NULL, *work_set = NULL;
 
1884
 
 
1885
  /* Sanity checks */
 
1886
 
 
1887
  assert(set_size > 0);
 
1888
 
 
1889
  /* Define temporary buffers */
 
1890
 
 
1891
  subset_num = &(ibuf[0]);
 
1892
  prev_num = &(ibuf[set_size]);
 
1893
  subset_issues = &(ibuf[2*set_size]);
 
1894
  idx = &(ibuf[3*set_size]);
 
1895
  state = &(ibuf[4*set_size]);
 
1896
  distances = &(rbuf[0]);
 
1897
  merge_set = &(vbuf[0]);
 
1898
  work_set = &(vbuf[set_size]);
 
1899
 
 
1900
  /* Compute distances between each couple of vertices among the set */
 
1901
 
 
1902
  for (k = 0, i1 = 0; i1 < set_size-1; i1++)
 
1903
    for (i2 = i1 + 1; i2 < set_size; i2++, k++)
 
1904
      distances[k] = _compute_length(set[i1], set[i2]);
 
1905
 
 
1906
  /* Compute initial state of equivalences between vertices */
 
1907
 
 
1908
  for (k = 0, i1 = 0; i1 < set_size-1; i1++) {
 
1909
    for (i2 = i1 + 1; i2 < set_size; i2++, k++) {
 
1910
      if (   set[i1].tolerance < distances[k]
 
1911
          || set[i2].tolerance < distances[k])
 
1912
        state[k] = 0;
 
1913
      else
 
1914
        state[k] = 1;
 
1915
    }
 
1916
  }
 
1917
 
 
1918
  idx[0] = 0;
 
1919
  for (k = 1; k < set_size - 1; k++)
 
1920
    idx[k] = set_size - k + idx[k-1];
 
1921
 
 
1922
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
1923
  if (cs_glob_join_log != NULL) {
 
1924
    cs_join_dump_array(cs_glob_join_log, "double", "\nDist",
 
1925
                       set_size*(set_size-1)/2, distances);
 
1926
    cs_join_dump_array(cs_glob_join_log, "int", "\nInit. State",
 
1927
                       set_size*(set_size-1)/2, state);
 
1928
  }
 
1929
#endif
 
1930
 
 
1931
  _build_subsets(set_size, state, prev_num, subset_num);
 
1932
 
 
1933
  while (is_end == false && n_loops < param.n_max_equiv_breaks) {
 
1934
 
 
1935
    n_loops++;
 
1936
 
 
1937
    n_issues = _check_tol_consistency(set_size,
 
1938
                                      set,
 
1939
                                      state,
 
1940
                                      subset_num,
 
1941
                                      subset_issues,
 
1942
                                      param.verbosity);
 
1943
 
 
1944
    if (n_issues > 0)
 
1945
      _break_equivalence(param,
 
1946
                         set_size,
 
1947
                         set,
 
1948
                         state,
 
1949
                         n_issues,
 
1950
                         subset_issues,
 
1951
                         idx,
 
1952
                         subset_num,
 
1953
                         distances);
 
1954
 
 
1955
    _build_subsets(set_size, state, prev_num, subset_num);
 
1956
 
 
1957
    is_end = _check_subset_consistency(set_size,
 
1958
                                       subset_num,
 
1959
                                       set,
 
1960
                                       merge_set,
 
1961
                                       work_set);
 
1962
 
 
1963
  } /* End of while */
 
1964
 
 
1965
  if (param.verbosity > 3) {
 
1966
 
 
1967
    fprintf(cs_glob_join_log,
 
1968
            " Number of tolerance reductions:  %4d\n", n_loops);
 
1969
 
 
1970
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
1971
    cs_join_dump_array(cs_glob_join_log, "int", "\nFinal Subset",
 
1972
                       set_size, subset_num);
 
1973
#endif
 
1974
 
 
1975
  }
 
1976
 
 
1977
  /* Apply merged to each subset */
 
1978
 
 
1979
  for (k = 0; k < set_size; k++)
 
1980
    set[k] = merge_set[subset_num[k]-1];
 
1981
 
 
1982
  return n_loops;
 
1983
}
 
1984
 
 
1985
/*----------------------------------------------------------------------------
 
1986
 * Merge between vertices. Store new data associated to the merged vertices
 
1987
 * in vertices.
 
1988
 *
 
1989
 * parameters:
 
1990
 *   param      <-- set of user-defined parameters
 
1991
 *   merge_set  <-> a pointer to a cs_join_vertex_t structure which
 
1992
 *                  stores data about merged vertices
 
1993
 *   n_vertices <-- number of vertices in vertices array
 
1994
 *   vertices   <-> array of cs_join_vertex_t structures
 
1995
 *---------------------------------------------------------------------------*/
 
1996
 
 
1997
static void
 
1998
_merge_vertices(cs_join_param_t    param,
 
1999
                cs_join_gset_t    *merge_set,
 
2000
                cs_int_t           n_vertices,
 
2001
                cs_join_vertex_t   vertices[])
 
2002
{
 
2003
  cs_int_t  i, j, k, list_size;
 
2004
  cs_join_vertex_t  merged_vertex;
 
2005
  cs_bool_t  ok;
 
2006
 
 
2007
  cs_int_t  max_list_size = 0, vv_max_list_size = 0;
 
2008
  cs_int_t  n_loops = 0, n_max_loops = 0, n_transitivity = 0;
 
2009
 
 
2010
  cs_join_gset_t  *equiv_gnum = NULL;
 
2011
  cs_real_t  *rbuf = NULL;
 
2012
  cs_int_t  *merge_index = NULL, *ibuf = NULL;
 
2013
  fvm_gnum_t  *merge_list = NULL, *merge_ref_elts = NULL;
 
2014
  fvm_gnum_t  *list = NULL;
 
2015
  cs_join_vertex_t  *set = NULL, *vbuf = NULL;
 
2016
  FILE  *logfile = cs_glob_join_log;
 
2017
 
 
2018
  const int  verbosity = param.verbosity;
 
2019
 
 
2020
  /* Sanity check */
 
2021
 
 
2022
  assert(param.merge_tol_coef >= 0.0);
 
2023
 
 
2024
  /* Pre-merge of identical vertices */
 
2025
 
 
2026
  _pre_merge(param, merge_set, vertices, &equiv_gnum);
 
2027
 
 
2028
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
2029
  {
 
2030
    int  len;
 
2031
    FILE  *dbg_file = NULL;
 
2032
    char  *filename = NULL;
 
2033
 
 
2034
    len = strlen("JoinDBG_MergeSet.dat")+1+2+4;
 
2035
    BFT_MALLOC(filename, len, char);
 
2036
    sprintf(filename, "Join%02dDBG_MergeSet%04d.dat",
 
2037
            param.num, CS_MAX(cs_glob_rank_id, 0));
 
2038
    dbg_file = fopen(filename, "w");
 
2039
 
 
2040
    cs_join_gset_dump(dbg_file, merge_set);
 
2041
 
 
2042
    fflush(dbg_file);
 
2043
    BFT_FREE(filename);
 
2044
    fclose(dbg_file);
 
2045
  }
 
2046
#endif /* defined(DEBUG) && !defined(NDEBUG) */
 
2047
 
 
2048
  /* Modify the tolerance for the merge operation if needed */
 
2049
 
 
2050
  if (fabs(param.merge_tol_coef - 1.0) > 1e-30) {
 
2051
    for (i = 0; i < n_vertices; i++)
 
2052
      vertices[i].tolerance *= param.merge_tol_coef;
 
2053
  }
 
2054
 
 
2055
  /* Compute the max. size of a sub list */
 
2056
 
 
2057
  merge_index = merge_set->index;
 
2058
  merge_list = merge_set->g_list;
 
2059
  merge_ref_elts = merge_set->g_elts;
 
2060
 
 
2061
  for (i = 0; i < merge_set->n_elts; i++) {
 
2062
    list_size = merge_index[i+1] - merge_index[i];
 
2063
    max_list_size = CS_MAX(max_list_size, list_size);
 
2064
  }
 
2065
  vv_max_list_size = ((max_list_size-1)*max_list_size)/2;
 
2066
 
 
2067
  if (verbosity > 0) {   /* Display information */
 
2068
 
 
2069
    fvm_lnum_t g_max_list_size = max_list_size;
 
2070
    fvm_parall_counter_max(&g_max_list_size, 1);
 
2071
 
 
2072
    if (g_max_list_size < 2) {
 
2073
      cs_join_gset_destroy(&equiv_gnum);
 
2074
      bft_printf(_("\n  No need to merge vertices.\n"));
 
2075
      return;
 
2076
    }
 
2077
    else
 
2078
      bft_printf(_("\n  Max size of a merge set of vertices: %llu\n"),
 
2079
                 (unsigned long long)g_max_list_size);
 
2080
  }
 
2081
 
 
2082
  /* Temporary buffers allocation */
 
2083
 
 
2084
  BFT_MALLOC(ibuf, 4*max_list_size + vv_max_list_size, cs_int_t);
 
2085
  BFT_MALLOC(rbuf, vv_max_list_size, cs_real_t);
 
2086
  BFT_MALLOC(vbuf, 2*max_list_size, cs_join_vertex_t);
 
2087
  BFT_MALLOC(list, max_list_size, fvm_gnum_t);
 
2088
  BFT_MALLOC(set, max_list_size, cs_join_vertex_t);
 
2089
 
 
2090
  /* Merge set of vertices */
 
2091
 
 
2092
  for (i = 0; i < merge_set->n_elts; i++) {
 
2093
 
 
2094
    list_size = merge_index[i+1] - merge_index[i];
 
2095
 
 
2096
    if (list_size > 1) {
 
2097
 
 
2098
      for (j = 0, k = merge_index[i]; k < merge_index[i+1]; k++, j++) {
 
2099
        list[j] = merge_list[k];
 
2100
        set[j] = vertices[list[j]];
 
2101
      }
 
2102
 
 
2103
      /* Define the resulting cs_join_vertex_t structure of the merge */
 
2104
 
 
2105
      merged_vertex = _compute_merged_vertex(list_size, set);
 
2106
 
 
2107
      /* Check if the vertex resulting of the merge is in the tolerance
 
2108
         for each vertex of the list */
 
2109
 
 
2110
      ok = _is_in_tolerance(list_size, set, merged_vertex);
 
2111
 
 
2112
#if CS_JOIN_MERGE_TOL_REDUC
 
2113
      if (ok == false) { /*
 
2114
                            The merged vertex is not in the tolerance of
 
2115
                            each vertex. This is a transitivity problem.
 
2116
                            We have to split the initial set into several
 
2117
                            subsets.
 
2118
                         */
 
2119
 
 
2120
        n_transitivity++;
 
2121
 
 
2122
        /* Display information on vertices to merge */
 
2123
        if (verbosity > 3) {
 
2124
          fprintf(logfile,
 
2125
                  "\n Begin merge for ref. elt: %llu - list_size: %d\n",
 
2126
                  (unsigned long long)merge_ref_elts[i],
 
2127
                  merge_index[i+1] - merge_index[i]);
 
2128
          for (j = 0; j < list_size; j++) {
 
2129
            fprintf(logfile, "%9llu -", (unsigned long long)list[j]);
 
2130
            cs_join_mesh_dump_vertex(logfile, set[j]);
 
2131
          }
 
2132
          fprintf(logfile, "\nMerged vertex rejected:\n");
 
2133
          cs_join_mesh_dump_vertex(logfile, merged_vertex);
 
2134
        }
 
2135
 
 
2136
        n_loops = _solve_transitivity(param,
 
2137
                                      list_size,
 
2138
                                      set,
 
2139
                                      vbuf,
 
2140
                                      rbuf,
 
2141
                                      ibuf);
 
2142
 
 
2143
        for (j = 0; j < list_size; j++)
 
2144
          vertices[list[j]] = set[j];
 
2145
 
 
2146
        n_max_loops = CS_MAX(n_max_loops, n_loops);
 
2147
 
 
2148
        if (verbosity > 3) { /* Display information */
 
2149
          fprintf(logfile, "\n  %3d loop(s) to get consistent subsets\n",
 
2150
                  n_loops);
 
2151
          fprintf(logfile, "\n End merge for ref. elt: %llu - list_size: %d\n",
 
2152
                  (unsigned long long)merge_ref_elts[i],
 
2153
                  merge_index[i+1] - merge_index[i]);
 
2154
          for (j = 0; j < list_size; j++) {
 
2155
            fprintf(logfile, "%7llu -", (unsigned long long)list[j]);
 
2156
            cs_join_mesh_dump_vertex(logfile, vertices[list[j]]);
 
2157
          }
 
2158
          fprintf(logfile, "\n");
 
2159
        }
 
2160
 
 
2161
      }
 
2162
      else /* New vertex data for the sub-elements */
 
2163
 
 
2164
#endif /* CS_JOIN_MERGE_TOL_REDUC */
 
2165
 
 
2166
        for (j = 0; j < list_size; j++)
 
2167
          vertices[list[j]] = merged_vertex;
 
2168
 
 
2169
    } /* list_size > 1 */
 
2170
 
 
2171
  } /* End of loop on potential merges */
 
2172
 
 
2173
  /* Apply merge to vertex initially identical */
 
2174
 
 
2175
  if (equiv_gnum != NULL) {
 
2176
 
 
2177
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
2178
    {
 
2179
      int  len;
 
2180
      FILE  *dbg_file = NULL;
 
2181
      char  *filename = NULL;
 
2182
 
 
2183
      len = strlen("JoinDBG_EquivMerge.dat")+1+2+4;
 
2184
      BFT_MALLOC(filename, len, char);
 
2185
      sprintf(filename, "Join%02dDBG_EquivMerge%04d.dat",
 
2186
              param.num, CS_MAX(cs_glob_rank_id, 0));
 
2187
      dbg_file = fopen(filename, "w");
 
2188
 
 
2189
      cs_join_gset_dump(dbg_file, equiv_gnum);
 
2190
 
 
2191
      fflush(dbg_file);
 
2192
      BFT_FREE(filename);
 
2193
      fclose(dbg_file);
 
2194
    }
 
2195
#endif /* defined(DEBUG) && !defined(NDEBUG) */
 
2196
 
 
2197
    for (i = 0; i < equiv_gnum->n_elts; i++) {
 
2198
 
 
2199
      cs_int_t  start = equiv_gnum->index[i];
 
2200
      cs_int_t  end = equiv_gnum->index[i+1];
 
2201
      cs_int_t  ref_id = equiv_gnum->g_elts[i];
 
2202
 
 
2203
      for (j = start; j < end; j++)
 
2204
        vertices[equiv_gnum->g_list[j]] = vertices[ref_id];
 
2205
 
 
2206
    }
 
2207
  }
 
2208
 
 
2209
  if (verbosity > 0) {
 
2210
 
 
2211
    fvm_gnum_t n_g_counter = n_transitivity;
 
2212
    fvm_parall_counter(&n_g_counter, 1);
 
2213
 
 
2214
    bft_printf(_("\n  Excessive transitivity for %llu set(s) of vertices.\n"),
 
2215
               (unsigned long long)n_g_counter);
 
2216
 
 
2217
    if (verbosity > 1) {
 
2218
      fvm_lnum_t g_n_max_loops = n_max_loops;
 
2219
      fvm_parall_counter_max(&g_n_max_loops, 1);
 
2220
      bft_printf(_("\n  Max. number of iterations to solve transitivity"
 
2221
                   " excess: %llu\n"), (unsigned long long)g_n_max_loops);
 
2222
    }
 
2223
  }
 
2224
 
 
2225
  /* Free memory */
 
2226
 
 
2227
  BFT_FREE(ibuf);
 
2228
  BFT_FREE(vbuf);
 
2229
  BFT_FREE(rbuf);
 
2230
  BFT_FREE(set);
 
2231
  BFT_FREE(list);
 
2232
 
 
2233
  cs_join_gset_destroy(&equiv_gnum);
 
2234
}
 
2235
 
 
2236
/*----------------------------------------------------------------------------
 
2237
 * Keep an history of the evolution of each vertex id before/after the merge
 
2238
 * operation.
 
2239
 *
 
2240
 * parameters:
 
2241
 *   n_iwm_vertices    <-- number of vertices before intersection for the
 
2242
 *                          work cs_join_mesh_t structure
 
2243
 *   iwm_vtx_gnum      <-- initial global vertex num. (work mesh struct.)
 
2244
 *   init_max_vtx_gnum <-- initial max. global numbering for vertices
 
2245
 *   n_vertices        <-- number of vertices before merge/after intersection
 
2246
 *   vertices          <-- array of cs_join_vertex_t structures
 
2247
 *   p_o2n_vtx_gnum    --> distributed array by block on the new global vertex
 
2248
 *                         numbering for the initial vertices (before inter.)
 
2249
 *---------------------------------------------------------------------------*/
 
2250
 
 
2251
static void
 
2252
_keep_global_vtx_evolution(cs_int_t                n_iwm_vertices,
 
2253
                           const fvm_gnum_t        iwm_vtx_gnum[],
 
2254
                           fvm_gnum_t              init_max_vtx_gnum,
 
2255
                           cs_int_t                n_vertices,
 
2256
                           const cs_join_vertex_t  vertices[],
 
2257
                           fvm_gnum_t             *p_o2n_vtx_gnum[])
 
2258
{
 
2259
  cs_int_t  i;
 
2260
 
 
2261
  fvm_gnum_t  *o2n_vtx_gnum = NULL;
 
2262
 
 
2263
  const int  n_ranks = cs_glob_n_ranks;
 
2264
  const int  local_rank = CS_MAX(cs_glob_rank_id, 0);
 
2265
 
 
2266
  assert(n_iwm_vertices <= n_vertices); /* after inter. >= init */
 
2267
 
 
2268
  if (n_ranks == 1) {
 
2269
 
 
2270
    BFT_MALLOC(o2n_vtx_gnum, n_iwm_vertices, fvm_gnum_t);
 
2271
 
 
2272
    for (i = 0; i < n_iwm_vertices; i++)
 
2273
      o2n_vtx_gnum[i] = vertices[i].gnum;
 
2274
 
 
2275
  }
 
2276
 
 
2277
#if defined(HAVE_MPI) /* Parallel treatment */
 
2278
  if (n_ranks > 1) {
 
2279
 
 
2280
    fvm_gnum_t  ii;
 
2281
    cs_int_t  shift, rank, n_recv_elts;
 
2282
 
 
2283
    cs_int_t  *send_shift = NULL, *recv_shift = NULL;
 
2284
    cs_int_t  *send_count = NULL, *recv_count = NULL;
 
2285
    fvm_gnum_t  *send_glist = NULL, *recv_glist = NULL;
 
2286
 
 
2287
    cs_join_block_info_t  block_info = cs_join_get_block_info(init_max_vtx_gnum,
 
2288
                                                              n_ranks,
 
2289
                                                              local_rank);
 
2290
 
 
2291
    MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
2292
 
 
2293
    /* Initialize o2n_vtx_gnum */
 
2294
 
 
2295
    BFT_MALLOC(o2n_vtx_gnum, block_info.local_size, fvm_gnum_t);
 
2296
 
 
2297
    for (ii = 0; ii < block_info.local_size; ii++)
 
2298
      o2n_vtx_gnum[ii] = block_info.first_gnum + ii;
 
2299
 
 
2300
    /* Send new vtx global number to the related rank = the good block */
 
2301
 
 
2302
    BFT_MALLOC(send_count, n_ranks, cs_int_t);
 
2303
    BFT_MALLOC(recv_count, n_ranks, cs_int_t);
 
2304
 
 
2305
    for (i = 0; i < n_ranks; i++)
 
2306
      send_count[i] = 0;
 
2307
 
 
2308
    for (i = 0; i < n_iwm_vertices; i++) {
 
2309
      rank = (iwm_vtx_gnum[i] - 1)/block_info.size;
 
2310
      send_count[rank] += 2;
 
2311
    }
 
2312
 
 
2313
    MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, mpi_comm);
 
2314
 
 
2315
    BFT_MALLOC(send_shift, n_ranks + 1, cs_int_t);
 
2316
    BFT_MALLOC(recv_shift, n_ranks + 1, cs_int_t);
 
2317
 
 
2318
    send_shift[0] = 0;
 
2319
    recv_shift[0] = 0;
 
2320
 
 
2321
    for (rank = 0; rank < n_ranks; rank++) {
 
2322
      send_shift[rank + 1] = send_shift[rank] + send_count[rank];
 
2323
      recv_shift[rank + 1] = recv_shift[rank] + recv_count[rank];
 
2324
    }
 
2325
 
 
2326
    assert(send_shift[n_ranks] == 2*n_iwm_vertices);
 
2327
 
 
2328
    /* Build send_list */
 
2329
 
 
2330
    BFT_MALLOC(send_glist, send_shift[n_ranks], fvm_gnum_t);
 
2331
    BFT_MALLOC(recv_glist, recv_shift[n_ranks], fvm_gnum_t);
 
2332
 
 
2333
    for (i = 0; i < n_ranks; i++)
 
2334
      send_count[i] = 0;
 
2335
 
 
2336
    for (i = 0; i < n_iwm_vertices; i++) {
 
2337
 
 
2338
      rank = (iwm_vtx_gnum[i] - 1)/block_info.size;
 
2339
      shift = send_shift[rank] + send_count[rank];
 
2340
 
 
2341
      send_glist[shift] = iwm_vtx_gnum[i];  /* Old global number */
 
2342
      send_glist[shift+1] = vertices[i].gnum;   /* New global number */
 
2343
      send_count[rank] += 2;
 
2344
 
 
2345
    }
 
2346
 
 
2347
    MPI_Alltoallv(send_glist, send_count, send_shift, FVM_MPI_GNUM,
 
2348
                  recv_glist, recv_count, recv_shift, FVM_MPI_GNUM,
 
2349
                  mpi_comm);
 
2350
 
 
2351
    n_recv_elts = recv_shift[n_ranks]/2;
 
2352
 
 
2353
    BFT_FREE(send_count);
 
2354
    BFT_FREE(send_shift);
 
2355
    BFT_FREE(send_glist);
 
2356
    BFT_FREE(recv_count);
 
2357
 
 
2358
    /* Update o2n_vtx_gnum */
 
2359
 
 
2360
    for (rank = 0; rank < n_ranks; rank++) {
 
2361
 
 
2362
      for (i = recv_shift[rank]; i < recv_shift[rank+1]; i+=2) {
 
2363
 
 
2364
        fvm_gnum_t  o_gnum = recv_glist[i];
 
2365
        fvm_gnum_t  n_gnum = recv_glist[i+1];
 
2366
        cs_int_t  id = o_gnum - block_info.first_gnum;
 
2367
 
 
2368
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
2369
        if (o2n_vtx_gnum[id] != block_info.first_gnum + id)
 
2370
          assert(o2n_vtx_gnum[id] == n_gnum);
 
2371
#endif
 
2372
 
 
2373
        o2n_vtx_gnum[id] = n_gnum;
 
2374
 
 
2375
      }
 
2376
 
 
2377
    } /* End of loop on ranks */
 
2378
 
 
2379
    BFT_FREE(recv_shift);
 
2380
    BFT_FREE(recv_glist);
 
2381
 
 
2382
  }
 
2383
#endif /* HAVE_MPI */
 
2384
 
 
2385
  /* Set return pointer */
 
2386
 
 
2387
  *p_o2n_vtx_gnum = o2n_vtx_gnum;
 
2388
}
 
2389
 
 
2390
/*----------------------------------------------------------------------------
 
2391
 * Keep a history of the evolution of each vertex id before/after the merge
 
2392
 * operation for the current mesh (local point of view).
 
2393
 *
 
2394
 * parameters:
 
2395
 *   n_vertices      <-- number of vertices before merge/after intersection
 
2396
 *   vertices        <-- array of cs_join_vertex_t structures
 
2397
 *   p_n_am_vertices --> number of vertices after the merge step
 
2398
 *   p_o2n_vtx_id    --> array keeping the evolution of the vertex ids
 
2399
 *---------------------------------------------------------------------------*/
 
2400
 
 
2401
static void
 
2402
_keep_local_vtx_evolution(cs_int_t                 n_vertices,
 
2403
                          const cs_join_vertex_t   vertices[],
 
2404
                          cs_int_t                *p_n_am_vertices,
 
2405
                          cs_int_t                *p_o2n_vtx_id[])
 
2406
{
 
2407
  cs_int_t  i;
 
2408
  fvm_gnum_t  prev;
 
2409
 
 
2410
  cs_int_t  n_am_vertices = 0;
 
2411
  cs_int_t  *o2n_vtx_id = NULL;
 
2412
  fvm_lnum_t  *order = NULL;
 
2413
  fvm_gnum_t  *vtx_gnum = NULL;
 
2414
 
 
2415
  if (n_vertices == 0)
 
2416
    return;
 
2417
 
 
2418
  BFT_MALLOC(vtx_gnum, n_vertices, fvm_gnum_t);
 
2419
 
 
2420
  for (i = 0; i < n_vertices; i++)
 
2421
    vtx_gnum[i] = vertices[i].gnum;
 
2422
 
 
2423
  /* Order vertices according to their global numbering */
 
2424
 
 
2425
  BFT_MALLOC(order, n_vertices, fvm_lnum_t);
 
2426
 
 
2427
  fvm_order_local_allocated(NULL, vtx_gnum, order, n_vertices);
 
2428
 
 
2429
  /* Delete vertices sharing the same global number. Keep only one */
 
2430
 
 
2431
  BFT_MALLOC(o2n_vtx_id, n_vertices, cs_int_t);
 
2432
 
 
2433
  prev = vtx_gnum[order[0]];
 
2434
  o2n_vtx_id[order[0]] = n_am_vertices;
 
2435
 
 
2436
  for (i = 1; i < n_vertices; i++) {
 
2437
 
 
2438
    cs_int_t  o_id = order[i];
 
2439
    fvm_gnum_t  cur = vtx_gnum[o_id];
 
2440
 
 
2441
    if (cur != prev) {
 
2442
      prev = cur;
 
2443
      n_am_vertices++;
 
2444
      o2n_vtx_id[o_id] = n_am_vertices;
 
2445
    }
 
2446
    else
 
2447
      o2n_vtx_id[o_id] = n_am_vertices;
 
2448
 
 
2449
  } /* End of loop on vertices */
 
2450
 
 
2451
  /* n_am_vertices is an id */
 
2452
  n_am_vertices += 1;
 
2453
 
 
2454
  assert(n_am_vertices <= n_vertices); /* after merge <= after inter. */
 
2455
 
 
2456
  /* Free memory */
 
2457
 
 
2458
  BFT_FREE(order);
 
2459
  BFT_FREE(vtx_gnum);
 
2460
 
 
2461
  /* Set return pointers */
 
2462
 
 
2463
  *p_n_am_vertices = n_am_vertices;
 
2464
  *p_o2n_vtx_id = o2n_vtx_id;
 
2465
}
 
2466
 
 
2467
/*----------------------------------------------------------------------------
 
2468
 * Search for new elements to add to the definition of the current edge
 
2469
 * These new sub-elements come from initial edges which are now (after the
 
2470
 * merge step) sub-edge of the current edge
 
2471
 * Count step
 
2472
 *
 
2473
 * parameters:
 
2474
 *   edge_id        <-- id of the edge to deal with
 
2475
 *   inter_edges    <-- structure keeping data on edge intersections
 
2476
 *   edges          <-- edges definition
 
2477
 *   n_iwm_vertices <-- initial number of vertices in work_mesh
 
2478
 *   n_new_sub_elts --> number of new elements to add in the edge definition
 
2479
 *
 
2480
 * returns:
 
2481
 *  number of new sub-elements related to this edge
 
2482
 *---------------------------------------------------------------------------*/
 
2483
 
 
2484
static cs_int_t
 
2485
_count_new_sub_edge_elts(cs_int_t                      edge_id,
 
2486
                         const cs_join_inter_edges_t  *inter_edges,
 
2487
                         const cs_join_edges_t        *edges,
 
2488
                         cs_int_t                      n_iwm_vertices)
 
2489
{
 
2490
  cs_int_t  j, k, j1, j2, sub_edge_id;
 
2491
  cs_int_t  start, end, _start, _end, v1_num, v2_num;
 
2492
  cs_bool_t  found;
 
2493
 
 
2494
  cs_int_t  n_new_sub_elts = 0;
 
2495
 
 
2496
  start = inter_edges->index[edge_id];
 
2497
  end = inter_edges->index[edge_id+1];
 
2498
 
 
2499
  for (j1 = start; j1 < end-1; j1++) {
 
2500
 
 
2501
    v1_num = inter_edges->vtx_lst[j1];
 
2502
 
 
2503
    if (v1_num <= n_iwm_vertices) { /* v1 is an initial vertex */
 
2504
      for (j2 = j1+1; j2 < end; j2++) {
 
2505
 
 
2506
        v2_num = inter_edges->vtx_lst[j2];
 
2507
 
 
2508
        if (v2_num <= n_iwm_vertices) { /* (v1,v2) is an initial edge */
 
2509
 
 
2510
          sub_edge_id = CS_ABS(cs_join_mesh_get_edge(v1_num,
 
2511
                                                     v2_num,
 
2512
                                                     edges))-1;
 
2513
          assert(sub_edge_id != -1);
 
2514
          _start = inter_edges->index[sub_edge_id];
 
2515
          _end = inter_edges->index[sub_edge_id+1];
 
2516
 
 
2517
          for (j = _start; j < _end; j++) {
 
2518
 
 
2519
            found = false;
 
2520
            for (k = j1+1; k < j2; k++)
 
2521
              if (inter_edges->vtx_glst[k] == inter_edges->vtx_glst[j])
 
2522
                found = true;
 
2523
 
 
2524
            if (found == false)
 
2525
              n_new_sub_elts += 1;
 
2526
 
 
2527
          } /* End of loop on sub_edge_id definition */
 
2528
 
 
2529
        }
 
2530
 
 
2531
      } /* End of loop on j2 */
 
2532
    }
 
2533
 
 
2534
  } /* End of loop on j1 */
 
2535
 
 
2536
  return n_new_sub_elts;
 
2537
}
 
2538
 
 
2539
/*----------------------------------------------------------------------------
 
2540
 * Update a cs_join_inter_edges_t structure after the merge operation.
 
2541
 * cs_join_inter_edges_t structure should be not NULL.
 
2542
 *
 
2543
 * parameters:
 
2544
 *   param          <-- user-defined parameters for the joining algorithm
 
2545
 *   n_iwm_vertices <-- initial number of vertices in work_mesh
 
2546
 *   o2n_vtx_id     <-- array keeping the evolution of the vertex ids
 
2547
 *   edges          <-- edges definition
 
2548
 *   p_inter_edges  <-> pointer to the structure keeping data on
 
2549
 *                      edge intersections
 
2550
 *---------------------------------------------------------------------------*/
 
2551
 
 
2552
static void
 
2553
_update_inter_edges_after_merge(cs_join_param_t          param,
 
2554
                                cs_int_t                 n_iwm_vertices,
 
2555
                                const cs_int_t           o2n_vtx_id[],
 
2556
                                const cs_join_edges_t   *edges,
 
2557
                                const cs_join_mesh_t    *mesh,
 
2558
                                cs_join_inter_edges_t  **p_inter_edges)
 
2559
{
 
2560
  cs_int_t  i, j,k, j1, j2,  start_shift, idx_shift;
 
2561
  cs_int_t  save, _start, _end, start, end;
 
2562
  cs_int_t  v1_num, v2_num, v1_id, v2_id, sub_edge_id;
 
2563
  fvm_gnum_t  v1_gnum, v2_gnum, new_gnum, prev_gnum;
 
2564
  cs_bool_t  found;
 
2565
 
 
2566
  cs_int_t  n_adds = 0;
 
2567
 
 
2568
  cs_join_inter_edges_t  *inter_edges = *p_inter_edges;
 
2569
  cs_join_inter_edges_t  *new_inter_edges = NULL;
 
2570
  cs_int_t  n_edges = inter_edges->n_edges;
 
2571
  cs_int_t  init_list_size = inter_edges->index[n_edges];
 
2572
  FILE  *logfile = cs_glob_join_log;
 
2573
 
 
2574
  assert(n_edges == edges->n_edges);
 
2575
 
 
2576
  /* Define vtx_glst to compare global vertex numbering */
 
2577
 
 
2578
  if (inter_edges->vtx_glst == NULL)
 
2579
    BFT_MALLOC(inter_edges->vtx_glst, inter_edges->index[n_edges], fvm_gnum_t);
 
2580
 
 
2581
  for (i = 0; i < inter_edges->index[n_edges]; i++) {
 
2582
    v1_id = inter_edges->vtx_lst[i] - 1;
 
2583
    inter_edges->vtx_glst[i] = mesh->vertices[v1_id].gnum;
 
2584
  }
 
2585
 
 
2586
  /* Delete redundancies of vertices sharing the same global numbering
 
2587
     after the merge step and define a new index */
 
2588
 
 
2589
  idx_shift = 0;
 
2590
  save = inter_edges->index[0];
 
2591
 
 
2592
  for (i = 0; i < n_edges; i++) {
 
2593
 
 
2594
    start = save;
 
2595
    end = inter_edges->index[i+1];
 
2596
 
 
2597
    if (end - start > 0) {
 
2598
 
 
2599
      start_shift = start;
 
2600
      v1_id = edges->def[2*i] - 1;
 
2601
      v2_id = edges->def[2*i+1] - 1;
 
2602
      v1_gnum = mesh->vertices[v1_id].gnum;
 
2603
      v2_gnum = mesh->vertices[v2_id].gnum;
 
2604
      prev_gnum = inter_edges->vtx_glst[start_shift];
 
2605
 
 
2606
      /* Don't take into account vertices with the same number as the
 
2607
         first edge element */
 
2608
 
 
2609
      while (prev_gnum == v1_gnum && start_shift + 1 < end)
 
2610
        prev_gnum = inter_edges->vtx_glst[++start_shift];
 
2611
 
 
2612
      if (prev_gnum != v1_gnum && start_shift < end) {
 
2613
 
 
2614
        inter_edges->vtx_lst[idx_shift] = inter_edges->vtx_lst[start_shift];
 
2615
        inter_edges->abs_lst[idx_shift] = inter_edges->abs_lst[start_shift];
 
2616
        inter_edges->vtx_glst[idx_shift] = inter_edges->vtx_glst[start_shift];
 
2617
        idx_shift += 1;
 
2618
 
 
2619
        for (j = start_shift + 1; j < end; j++) {
 
2620
 
 
2621
          new_gnum = inter_edges->vtx_glst[j];
 
2622
 
 
2623
          /* Don't take into account redundancies and vertices with the same
 
2624
             number as the second edge element */
 
2625
 
 
2626
          if (prev_gnum != new_gnum && new_gnum != v2_gnum) {
 
2627
            prev_gnum = new_gnum;
 
2628
            inter_edges->vtx_lst[idx_shift] = inter_edges->vtx_lst[j];
 
2629
            inter_edges->abs_lst[idx_shift] = inter_edges->abs_lst[j];
 
2630
            inter_edges->vtx_glst[idx_shift] = inter_edges->vtx_glst[j];
 
2631
            idx_shift += 1;
 
2632
          }
 
2633
 
 
2634
        }
 
2635
 
 
2636
      } /* If start_shift < end */
 
2637
 
 
2638
    } /* end - start > 0 */
 
2639
 
 
2640
    save = inter_edges->index[i+1];
 
2641
    inter_edges->index[i+1] = idx_shift;
 
2642
 
 
2643
  } /* End of loop on edge intersections */
 
2644
 
 
2645
  inter_edges->max_sub_size = 0;
 
2646
 
 
2647
  for (i = 0; i < n_edges; i++)
 
2648
    inter_edges->max_sub_size =
 
2649
            CS_MAX(inter_edges->max_sub_size,
 
2650
                       inter_edges->index[i+1] - inter_edges->index[i]);
 
2651
 
 
2652
  assert(inter_edges->index[n_edges] <= init_list_size);
 
2653
 
 
2654
  BFT_REALLOC(inter_edges->vtx_lst, inter_edges->index[n_edges], cs_int_t);
 
2655
  BFT_REALLOC(inter_edges->abs_lst, inter_edges->index[n_edges], float);
 
2656
 
 
2657
#if 0 && defined(DEBUG) && !defined(NDEBUG) /* Dump local structures */
 
2658
  fprintf(logfile, " AFTER REDUNDANCIES CLEAN\n");
 
2659
  cs_join_inter_edges_dump(logfile, inter_edges, edges, mesh);
 
2660
#endif
 
2661
 
 
2662
  /* Add new vertices from initial edges which are now sub-edges */
 
2663
 
 
2664
  for (i = 0; i < n_edges; i++)
 
2665
    n_adds += _count_new_sub_edge_elts(i, inter_edges, edges, n_iwm_vertices);
 
2666
 
 
2667
  if (param.verbosity > 2)
 
2668
    fprintf(logfile,
 
2669
            "  Number of sub-elements to add to edge definition: %8d\n",
 
2670
            n_adds);
 
2671
 
 
2672
  if (n_adds > 0) { /* Define a new inter_edges structure */
 
2673
 
 
2674
    new_inter_edges = cs_join_inter_edges_create(n_edges);
 
2675
 
 
2676
    BFT_MALLOC(new_inter_edges->vtx_lst,
 
2677
               inter_edges->index[n_edges] + n_adds, cs_int_t);
 
2678
    BFT_MALLOC(new_inter_edges->abs_lst,
 
2679
               inter_edges->index[n_edges] + n_adds, float);
 
2680
 
 
2681
    n_adds = 0;
 
2682
    idx_shift = 0;
 
2683
    new_inter_edges->index[0] = 0;
 
2684
 
 
2685
    for (i = 0; i < n_edges; i++) {
 
2686
 
 
2687
      new_inter_edges->edge_gnum[i] = inter_edges->edge_gnum[i];
 
2688
      start = inter_edges->index[i];
 
2689
      end = inter_edges->index[i+1];
 
2690
 
 
2691
      if (start - end > 0) {
 
2692
 
 
2693
        for (j1 = start; j1 < end-1; j1++) {
 
2694
 
 
2695
          v1_num = inter_edges->vtx_lst[j1];
 
2696
          new_inter_edges->vtx_lst[idx_shift] = v1_num;
 
2697
          new_inter_edges->abs_lst[idx_shift] = inter_edges->abs_lst[j1];
 
2698
          idx_shift++;
 
2699
 
 
2700
          if (v1_num <= n_iwm_vertices) { /* v1 is an initial vertex */
 
2701
            for (j2 = j1+1; j2 < end; j2++) {
 
2702
 
 
2703
              v2_num = inter_edges->vtx_lst[j2];
 
2704
 
 
2705
              if (v2_num <= n_iwm_vertices) { /* (v1,v2) is an initial edge */
 
2706
 
 
2707
                sub_edge_id =
 
2708
                  CS_ABS(cs_join_mesh_get_edge(v1_num, v2_num, edges))-1;
 
2709
                assert(sub_edge_id != -1);
 
2710
 
 
2711
                _start = inter_edges->index[sub_edge_id];
 
2712
                _end = inter_edges->index[sub_edge_id+1];
 
2713
 
 
2714
                for (j = _start; j < _end; j++) {
 
2715
 
 
2716
                  found = false;
 
2717
                  for (k = j1+1; k < j2; k++)
 
2718
                    if (inter_edges->vtx_glst[k] == inter_edges->vtx_glst[j])
 
2719
                      found = true;
 
2720
 
 
2721
                  if (found == false) {
 
2722
 
 
2723
                    new_inter_edges->vtx_lst[idx_shift] =
 
2724
                      inter_edges->vtx_lst[j];
 
2725
                    new_inter_edges->abs_lst[idx_shift] =
 
2726
                      inter_edges->abs_lst[j];
 
2727
                    idx_shift++;
 
2728
 
 
2729
                  }
 
2730
 
 
2731
                } /* End of loop on sub_edge_id definition */
 
2732
 
 
2733
              }
 
2734
 
 
2735
            } /* End of loop on j2 */
 
2736
          }
 
2737
 
 
2738
        } /* End of loop on j1 */
 
2739
 
 
2740
        /* Add last vertex in the previous edge definition */
 
2741
 
 
2742
        new_inter_edges->vtx_lst[idx_shift] = inter_edges->vtx_lst[end-1];
 
2743
        new_inter_edges->abs_lst[idx_shift] = inter_edges->abs_lst[end-1];
 
2744
        idx_shift++;
 
2745
 
 
2746
      } /* If end - start > 0 */
 
2747
 
 
2748
      new_inter_edges->index[i+1] = idx_shift;
 
2749
 
 
2750
    } /* End of loop on edges */
 
2751
 
 
2752
    cs_join_inter_edges_destroy(&inter_edges);
 
2753
    inter_edges = new_inter_edges;
 
2754
 
 
2755
    inter_edges->max_sub_size = 0;
 
2756
 
 
2757
    for (i = 0; i < n_edges; i++)
 
2758
      inter_edges->max_sub_size = CS_MAX(inter_edges->max_sub_size,
 
2759
                                         inter_edges->index[i+1]);
 
2760
 
 
2761
  } /* End if n_adds > 0 */
 
2762
 
 
2763
#if 0 && defined(DEBUG) && !defined(NDEBUG) /* Dump local structures */
 
2764
  if (logfile != NULL) {
 
2765
    fprintf(logfile, " AFTER SUB ELTS ADD\n");
 
2766
    cs_join_inter_edges_dump(logfile, inter_edges, edges, mesh);
 
2767
  }
 
2768
#endif
 
2769
 
 
2770
  /* Update cs_join_inter_edges_t structure */
 
2771
 
 
2772
  for (i = 0; i < n_edges; i++) {
 
2773
 
 
2774
    start = inter_edges->index[i];
 
2775
    end = inter_edges->index[i+1];
 
2776
 
 
2777
    for (j = start; j < end; j++) {
 
2778
 
 
2779
      cs_int_t old_id = inter_edges->vtx_lst[j] - 1;
 
2780
 
 
2781
      inter_edges->vtx_lst[j] = o2n_vtx_id[old_id] + 1;
 
2782
 
 
2783
    }
 
2784
 
 
2785
  }
 
2786
 
 
2787
  /* Return pointer */
 
2788
 
 
2789
  *p_inter_edges = inter_edges;
 
2790
}
 
2791
 
 
2792
#if defined(HAVE_MPI)
 
2793
 
 
2794
/*----------------------------------------------------------------------------
 
2795
 * Define send_rank_index and send_faces to prepare the exchange of new faces
 
2796
 * between mesh structures.
 
2797
 *
 
2798
 * parameters:
 
2799
 *   n_faces           <-- number of faces to send
 
2800
 *   n_g_faces         <-- global number of faces to be joined
 
2801
 *   face_gnum         <-- global face number
 
2802
 *   gnum_rank_index   <-- index on ranks for the init. global face numbering
 
2803
 *   p_send_rank_index --> index on ranks for sending face
 
2804
 *   p_send_faces      --> list of face ids to send
 
2805
 *---------------------------------------------------------------------------*/
 
2806
 
 
2807
static void
 
2808
_get_faces_to_send(cs_int_t           n_faces,
 
2809
                   fvm_gnum_t         n_g_faces,
 
2810
                   const fvm_gnum_t   face_gnum[],
 
2811
                   const fvm_gnum_t   gnum_rank_index[],
 
2812
                   cs_int_t          *p_send_rank_index[],
 
2813
                   cs_int_t          *p_send_faces[])
 
2814
{
 
2815
  cs_int_t  i, rank, shift, reduce_rank;
 
2816
  fvm_gnum_t  start_gnum, end_gnum;
 
2817
  cs_join_block_info_t  block_info;
 
2818
 
 
2819
  cs_int_t  reduce_size = 0;
 
2820
  cs_int_t  *send_rank_index = NULL, *send_faces = NULL;
 
2821
  cs_int_t  *reduce_ids = NULL, *count = NULL;
 
2822
  fvm_gnum_t  *reduce_index = NULL;
 
2823
 
 
2824
  const int  local_rank = CS_MAX(cs_glob_rank_id, 0);
 
2825
  const int  n_ranks = cs_glob_n_ranks;
 
2826
 
 
2827
  /* Sanity checks */
 
2828
 
 
2829
  assert(gnum_rank_index != NULL);
 
2830
  assert(n_ranks > 1);
 
2831
 
 
2832
  /* Compute block_size */
 
2833
 
 
2834
  block_info = cs_join_get_block_info(n_g_faces, n_ranks, local_rank);
 
2835
  start_gnum = block_info.first_gnum;
 
2836
  end_gnum = block_info.first_gnum + block_info.local_size;
 
2837
 
 
2838
  /* Compact init. global face distribution. Remove ranks without face
 
2839
     at the begining */
 
2840
 
 
2841
  for (i = 0; i < n_ranks; i++)
 
2842
    if (gnum_rank_index[i] < gnum_rank_index[i+1])
 
2843
      reduce_size++;
 
2844
 
 
2845
  BFT_MALLOC(reduce_index, reduce_size+1, fvm_gnum_t);
 
2846
  BFT_MALLOC(reduce_ids, reduce_size, cs_int_t);
 
2847
 
 
2848
  reduce_size = 0;
 
2849
  reduce_index[0] = gnum_rank_index[0] + 1;
 
2850
 
 
2851
  for (i = 0; i < n_ranks; i++) {
 
2852
 
 
2853
    /* Add +1 to gnum_rank_index because it's an id and we work on numbers */
 
2854
 
 
2855
    if (gnum_rank_index[i] < gnum_rank_index[i+1]) {
 
2856
      reduce_index[reduce_size+1] = gnum_rank_index[i+1] + 1;
 
2857
      reduce_ids[reduce_size++] = i;
 
2858
    }
 
2859
 
 
2860
  }
 
2861
 
 
2862
  BFT_MALLOC(send_rank_index, n_ranks + 1, cs_int_t);
 
2863
 
 
2864
  for (i = 0; i < n_ranks + 1; i++)
 
2865
    send_rank_index[i] = 0;
 
2866
 
 
2867
  /* Count number of ranks associated to each new face */
 
2868
 
 
2869
  for (i = 0; i < n_faces; i++) {
 
2870
 
 
2871
    if (face_gnum[i] >= start_gnum && face_gnum[i] < end_gnum) {
 
2872
 
 
2873
      /* The current face is a "main" face for the local rank */
 
2874
 
 
2875
      reduce_rank = cs_search_gindex_binary(reduce_size,
 
2876
                                            face_gnum[i],
 
2877
                                            reduce_index);
 
2878
 
 
2879
      assert(reduce_rank > -1);
 
2880
      assert(reduce_rank < reduce_size);
 
2881
 
 
2882
      rank = reduce_ids[reduce_rank];
 
2883
      send_rank_index[rank+1] += 1;
 
2884
 
 
2885
    }
 
2886
 
 
2887
  }
 
2888
 
 
2889
  for (i = 0; i < n_ranks; i++)
 
2890
    send_rank_index[i+1] += send_rank_index[i];
 
2891
 
 
2892
  BFT_MALLOC(send_faces, send_rank_index[n_ranks], cs_int_t);
 
2893
  BFT_MALLOC(count, n_ranks, cs_int_t);
 
2894
 
 
2895
  for (i = 0; i < n_ranks; i++)
 
2896
    count[i] = 0;
 
2897
 
 
2898
  /* Fill the list of ranks */
 
2899
 
 
2900
  for (i = 0; i < n_faces; i++) {
 
2901
 
 
2902
    if (face_gnum[i] >= start_gnum && face_gnum[i] < end_gnum) {
 
2903
 
 
2904
      /* The current face is a "main" face for the local rank */
 
2905
 
 
2906
      reduce_rank = cs_search_gindex_binary(reduce_size,
 
2907
                                            face_gnum[i],
 
2908
                                            reduce_index);
 
2909
 
 
2910
      assert(reduce_rank > -1);
 
2911
      assert(reduce_rank < reduce_size);
 
2912
 
 
2913
      rank = reduce_ids[reduce_rank];
 
2914
      shift = send_rank_index[rank] + count[rank];
 
2915
      send_faces[shift] = i;
 
2916
      count[rank] += 1;
 
2917
 
 
2918
    } /* End of loop on initial faces */
 
2919
 
 
2920
  }
 
2921
 
 
2922
  /* Free memory */
 
2923
 
 
2924
#if 0 && defined(DEBUG) && !defined(NDEBUG)
 
2925
  if (cs_glob_join_log != NULL) {
 
2926
    FILE *logfile = cs_glob_join_log;
 
2927
    for (rank = 0; rank < n_ranks; rank++) {
 
2928
      fprintf(logfile, " rank %d: ", rank);
 
2929
      for (i = send_rank_index[rank]; i < send_rank_index[rank+1]; i++)
 
2930
        fprintf(logfile, " %d (%llu)",
 
2931
                send_faces[i], (unsigned long long)face_gnum[send_faces[i]]);
 
2932
      fprintf(logfile, "\n");
 
2933
      fflush(logfile);
 
2934
    }
 
2935
  }
 
2936
#endif
 
2937
 
 
2938
  BFT_FREE(count);
 
2939
  BFT_FREE(reduce_ids);
 
2940
  BFT_FREE(reduce_index);
 
2941
 
 
2942
  /* Set return pointers */
 
2943
 
 
2944
  *p_send_rank_index = send_rank_index;
 
2945
  *p_send_faces = send_faces;
 
2946
}
 
2947
 
 
2948
#endif /* defined(HAVE_MPI) */
 
2949
 
 
2950
/*----------------------------------------------------------------------------
 
2951
 * Update local_mesh by redistributing mesh.
 
2952
 * Send back to the original rank the new face and vertex description.
 
2953
 *
 
2954
 * parameters:
 
2955
 *   gnum_rank_index  <--  index on ranks for the old global face numbering
 
2956
 *   send_mesh        <--  distributed mesh on faces to join
 
2957
 *   p_recv_mesh      <->  mesh on local selected faces to be joined
 
2958
 *---------------------------------------------------------------------------*/
 
2959
 
 
2960
static void
 
2961
_redistribute_mesh(const fvm_gnum_t        gnum_rank_index[],
 
2962
                   const cs_join_mesh_t   *send_mesh,
 
2963
                   cs_join_mesh_t        **p_recv_mesh)
 
2964
{
 
2965
  cs_join_mesh_t  *recv_mesh = *p_recv_mesh;
 
2966
 
 
2967
  const int  n_ranks = cs_glob_n_ranks;
 
2968
 
 
2969
  /* sanity checks */
 
2970
 
 
2971
  assert(send_mesh != NULL);
 
2972
  assert(recv_mesh != NULL);
 
2973
 
 
2974
  if (n_ranks == 1)
 
2975
    cs_join_mesh_copy(&recv_mesh, send_mesh);
 
2976
 
 
2977
#if defined(HAVE_MPI)
 
2978
  if (n_ranks > 1) { /* Parallel mode */
 
2979
 
 
2980
    cs_int_t  *send_rank_index = NULL, *send_faces = NULL;
 
2981
 
 
2982
    MPI_Comm  mpi_comm = cs_glob_mpi_comm;
 
2983
 
 
2984
    /* Free some structures of the mesh */
 
2985
 
 
2986
    cs_join_mesh_reset(recv_mesh);
 
2987
 
 
2988
    _get_faces_to_send(send_mesh->n_faces,
 
2989
                       send_mesh->n_g_faces,
 
2990
                       send_mesh->face_gnum,
 
2991
                       gnum_rank_index,
 
2992
                       &send_rank_index,
 
2993
                       &send_faces);
 
2994
 
 
2995
    assert(send_rank_index[n_ranks] <= send_mesh->n_faces);
 
2996
 
 
2997
    /* Get the new face connectivity from the distributed send_mesh */
 
2998
 
 
2999
    cs_join_mesh_exchange(n_ranks,
 
3000
                          send_rank_index,
 
3001
                          send_faces,
 
3002
                          send_mesh,
 
3003
                          recv_mesh,
 
3004
                          mpi_comm);
 
3005
 
 
3006
    BFT_FREE(send_faces);
 
3007
    BFT_FREE(send_rank_index);
 
3008
 
 
3009
  }
 
3010
#endif
 
3011
 
 
3012
  /* Return pointers */
 
3013
 
 
3014
  *p_recv_mesh = recv_mesh;
 
3015
 
 
3016
}
 
3017
 
 
3018
/*============================================================================
 
3019
 * Public function definitions
 
3020
 *===========================================================================*/
 
3021
 
 
3022
/*----------------------------------------------------------------------------
 
3023
 * Creation of new vertices.
 
3024
 *
 
3025
 * Update list of equivalent vertices, and assign a vertex (existing or
 
3026
 * newly created) to each intersection.
 
3027
 *
 
3028
 * parameters:
 
3029
 *   verbosity          <-- verbosity level
 
3030
 *   edges              <-- list of edges
 
3031
 *   work               <-> joining mesh maintaining initial vertex data
 
3032
 *   inter_set          <-> cs_join_inter_set_t structure including
 
3033
 *                          data on edge-edge  intersections
 
3034
 *   init_max_vtx_gnum  <-- initial max. global numbering for vertices
 
3035
 *   p_n_g_new_vertices <-> pointer to the global number of new vertices
 
3036
 *   p_vtx_eset         <-> pointer to a structure dealing with vertex
 
3037
 *                          equivalences
 
3038
 *---------------------------------------------------------------------------*/
 
3039
 
 
3040
void
 
3041
cs_join_create_new_vertices(int                     verbosity,
 
3042
                            const cs_join_edges_t  *edges,
 
3043
                            cs_join_mesh_t         *work,
 
3044
                            cs_join_inter_set_t    *inter_set,
 
3045
                            fvm_gnum_t              init_max_vtx_gnum,
 
3046
                            fvm_gnum_t             *p_n_g_new_vertices,
 
3047
                            cs_join_eset_t        **p_vtx_eset)
 
3048
{
 
3049
  cs_int_t  i, shift;
 
3050
  double  tol_min;
 
3051
  cs_join_vertex_t  v1, v2;
 
3052
 
 
3053
  cs_int_t  n_new_vertices = 0;
 
3054
  fvm_gnum_t  n_g_new_vertices = 0;
 
3055
  fvm_gnum_t  *new_vtx_gnum = NULL;
 
3056
  cs_int_t  n_iwm_vertices = work->n_vertices;
 
3057
  cs_join_eset_t  *vtx_equiv = *p_vtx_eset;
 
3058
 
 
3059
  /* Count the number of new vertices. Update cs_join_inter_set_t struct. */
 
3060
 
 
3061
  for (i = 0; i < inter_set->n_inter; i++) {
 
3062
 
 
3063
    cs_join_inter_t  inter1 = inter_set->inter_lst[2*i];
 
3064
    cs_join_inter_t  inter2 = inter_set->inter_lst[2*i+1];
 
3065
 
 
3066
    inter1.vtx_id = _get_vtx_id(inter1,
 
3067
                                &(edges->def[2*inter1.edge_id]),
 
3068
                                n_iwm_vertices,
 
3069
                                &n_new_vertices);
 
3070
 
 
3071
    inter2.vtx_id = _get_vtx_id(inter2,
 
3072
                                &(edges->def[2*inter2.edge_id]),
 
3073
                                n_iwm_vertices,
 
3074
                                &n_new_vertices);
 
3075
 
 
3076
    inter_set->inter_lst[2*i] = inter1;
 
3077
    inter_set->inter_lst[2*i+1] = inter2;
 
3078
 
 
3079
  } /* End of loop on intersections */
 
3080
 
 
3081
  /* Compute the global numbering for the new vertices (Take into account
 
3082
     potential redundancies) */
 
3083
 
 
3084
  _compute_new_vertex_gnum(work,
 
3085
                           edges,
 
3086
                           inter_set,
 
3087
                           init_max_vtx_gnum,
 
3088
                           n_iwm_vertices,
 
3089
                           n_new_vertices,
 
3090
                           &n_g_new_vertices,
 
3091
                           &new_vtx_gnum);
 
3092
 
 
3093
  if (verbosity > 0)
 
3094
    bft_printf(_("\n  Global number of new vertices to create: %10llu\n"),
 
3095
               (unsigned long long)n_g_new_vertices);
 
3096
 
 
3097
  /* Define new vertices */
 
3098
 
 
3099
  work->n_vertices += n_new_vertices;
 
3100
  work->n_g_vertices += n_g_new_vertices;
 
3101
 
 
3102
  BFT_REALLOC(work->vertices, work->n_vertices, cs_join_vertex_t);
 
3103
 
 
3104
#if defined(DEBUG) && !defined(NDEBUG) /* Prepare sanity checks */
 
3105
  {
 
3106
    cs_join_vertex_t  incoherency;
 
3107
 
 
3108
    /* Initialize to incoherent values new vertices structures */
 
3109
 
 
3110
    incoherency.gnum = 0;
 
3111
    incoherency.coord[0] = -9999.9999;
 
3112
    incoherency.coord[1] = -9999.9999;
 
3113
    incoherency.coord[2] = -9999.9999;
 
3114
    incoherency.tolerance = -1.0;
 
3115
    incoherency.state = CS_JOIN_STATE_UNDEF;
 
3116
 
 
3117
    for (i = 0; i < n_new_vertices; i++)
 
3118
      work->vertices[n_iwm_vertices + i] = incoherency;
 
3119
 
 
3120
  }
 
3121
#endif
 
3122
 
 
3123
  /* Fill vertices structure with new vertex definitions */
 
3124
 
 
3125
  for (i = 0; i < inter_set->n_inter; i++) {
 
3126
 
 
3127
    cs_join_inter_t  inter1 = inter_set->inter_lst[2*i];
 
3128
    cs_join_inter_t  inter2 = inter_set->inter_lst[2*i+1];
 
3129
    cs_int_t  v1_num = inter1.vtx_id + 1;
 
3130
    cs_int_t  v2_num = inter2.vtx_id + 1;
 
3131
    cs_int_t  equiv_id = vtx_equiv->n_equiv;
 
3132
 
 
3133
    assert(inter1.vtx_id < work->n_vertices);
 
3134
    assert(inter2.vtx_id < work->n_vertices);
 
3135
 
 
3136
    /* Create new vertices if needed */
 
3137
 
 
3138
    if (v1_num > n_iwm_vertices) {
 
3139
 
 
3140
      shift = inter1.vtx_id - n_iwm_vertices;
 
3141
      v1 = _get_new_vertex(inter1.curv_abs,
 
3142
                           new_vtx_gnum[shift],
 
3143
                           &(edges->def[2*inter1.edge_id]),
 
3144
                           work);
 
3145
      tol_min = v1.tolerance;
 
3146
 
 
3147
    }
 
3148
    else
 
3149
      tol_min = work->vertices[v1_num-1].tolerance;
 
3150
 
 
3151
    if (v2_num > n_iwm_vertices) {
 
3152
 
 
3153
      shift = inter2.vtx_id - n_iwm_vertices;
 
3154
      v2 = _get_new_vertex(inter2.curv_abs,
 
3155
                           new_vtx_gnum[shift],
 
3156
                           &(edges->def[2*inter2.edge_id]),
 
3157
                           work);
 
3158
      tol_min = CS_MIN(tol_min, v2.tolerance);
 
3159
 
 
3160
    }
 
3161
    else
 
3162
      tol_min = CS_MIN(tol_min, work->vertices[v2_num-1].tolerance);
 
3163
 
 
3164
    /* A new vertex has a tolerance equal to the minimal tolerance
 
3165
       between the two vertices implied in the intersection */
 
3166
 
 
3167
    if (v1_num > n_iwm_vertices) {
 
3168
      v1.tolerance = tol_min;
 
3169
      work->vertices[inter1.vtx_id] = v1;
 
3170
    }
 
3171
    if (v2_num > n_iwm_vertices) {
 
3172
      v2.tolerance = tol_min;
 
3173
      work->vertices[inter2.vtx_id] = v2;
 
3174
    }
 
3175
 
 
3176
    /* Add equivalence between the two current vertices */
 
3177
 
 
3178
    cs_join_eset_check_size(equiv_id, &vtx_equiv);
 
3179
 
 
3180
    if (v1_num < v2_num) {
 
3181
      vtx_equiv->equiv_couple[2*equiv_id] = v1_num;
 
3182
      vtx_equiv->equiv_couple[2*equiv_id+1] = v2_num;
 
3183
    }
 
3184
    else {
 
3185
      vtx_equiv->equiv_couple[2*equiv_id] = v2_num;
 
3186
      vtx_equiv->equiv_couple[2*equiv_id+1] = v1_num;
 
3187
    }
 
3188
 
 
3189
    vtx_equiv->n_equiv += 1;
 
3190
 
 
3191
  } /* End of loop on intersections */
 
3192
 
 
3193
  /* Free memory */
 
3194
 
 
3195
  BFT_FREE(new_vtx_gnum);
 
3196
 
 
3197
#if defined(DEBUG) && !defined(NDEBUG) /* Sanity checks */
 
3198
  for (i = 0; i < work->n_vertices; i++) {
 
3199
 
 
3200
    cs_join_vertex_t  vtx = work->vertices[i];
 
3201
 
 
3202
    if (vtx.gnum == 0 || vtx.tolerance < -0.99)
 
3203
      bft_error(__FILE__, __LINE__, 0,
 
3204
                _("  Inconsistent value found in cs_join_vertex_t struct.:\n"
 
3205
                  "    Vertex %d is defined by:\n"
 
3206
                  "      %u - [%7.4le, %7.4le, %7.4le] - %lg\n"),
 
3207
                i, vtx.gnum, vtx.coord[0], vtx.coord[1], vtx.coord[2],
 
3208
                vtx.tolerance);
 
3209
 
 
3210
  } /* End of loop on vertices */
 
3211
 
 
3212
#if 0
 
3213
  _dump_vtx_eset(vtx_equiv, work, cs_glob_join_log);
 
3214
#endif
 
3215
 
 
3216
#endif
 
3217
 
 
3218
  /* Set return pointers */
 
3219
 
 
3220
  *p_n_g_new_vertices = n_g_new_vertices;
 
3221
  *p_vtx_eset = vtx_equiv;
 
3222
}
 
3223
 
 
3224
/*----------------------------------------------------------------------------
 
3225
 * Merge of equivalent vertices (and tolerance reduction if necessary)
 
3226
 *
 
3227
 * Define a new cs_join_vertex_t structure (stored in "work" structure).
 
3228
 * Returns an updated cs_join_mesh_t and cs_join_edges_t structures.
 
3229
 *
 
3230
 * parameters:
 
3231
 *   param            <-- set of user-defined parameters for the joining
 
3232
 *   n_g_vertices_tot <-- global number of vertices (initial parent mesh)
 
3233
 *   work             <-> pointer to a cs_join_mesh_t structure
 
3234
 *   vtx_eset         <-- structure storing equivalences between vertices
 
3235
 *                        (two vertices are equivalent if they are within
 
3236
 *                        each other's tolerance)
 
3237
 *---------------------------------------------------------------------------*/
 
3238
 
 
3239
void
 
3240
cs_join_merge_vertices(cs_join_param_t        param,
 
3241
                       fvm_gnum_t             n_g_vertices_tot,
 
3242
                       cs_join_mesh_t        *work,
 
3243
                       const cs_join_eset_t  *vtx_eset)
 
3244
{
 
3245
  double  clock_start, clock_end, cpu_start, cpu_end;
 
3246
 
 
3247
  fvm_gnum_t  *vtx_tags = NULL;
 
3248
  cs_join_gset_t  *merge_set = NULL;
 
3249
 
 
3250
  const int  n_ranks = cs_glob_n_ranks;
 
3251
 
 
3252
  /* Initialize counters for the merge operation */
 
3253
 
 
3254
  _initialize_merge_counter();
 
3255
 
 
3256
#if 0 && defined(DEBUG) && !defined(NDEBUG) /* Dump local structures */
 
3257
  _dump_vtx_eset(vtx_eset, work, cs_glob_join_log);
 
3258
#endif
 
3259
 
 
3260
  if (param.verbosity > 2) {
 
3261
    fvm_gnum_t g_n_equiv = vtx_eset->n_equiv;
 
3262
    fvm_parall_counter(&g_n_equiv, 1);
 
3263
    fprintf(cs_glob_join_log,
 
3264
            "\n"
 
3265
            "  Final number of equiv. between vertices; local: %9d\n"
 
3266
            "                                          global: %9llu\n",
 
3267
            vtx_eset->n_equiv, (unsigned long long)g_n_equiv);
 
3268
  }
 
3269
 
 
3270
  /* Operate merge between equivalent vertices.
 
3271
     Manage reduction of tolerance if necessary */
 
3272
 
 
3273
  clock_start = bft_timer_wtime();
 
3274
  cpu_start = bft_timer_cpu_time();
 
3275
 
 
3276
  /* Tag with the same number all the vertices which might be merged together */
 
3277
 
 
3278
  _tag_equiv_vertices(n_g_vertices_tot,
 
3279
                      vtx_eset,
 
3280
                      work,
 
3281
                      param.verbosity,
 
3282
                      &vtx_tags);
 
3283
 
 
3284
  if (n_ranks == 1) { /* Serial mode */
 
3285
 
 
3286
    /* Build a merge list */
 
3287
 
 
3288
    merge_set = cs_join_gset_create_from_tag(work->n_vertices, vtx_tags);
 
3289
 
 
3290
    /* Merge of equivalent vertices */
 
3291
 
 
3292
    _merge_vertices(param,
 
3293
                    merge_set,
 
3294
                    work->n_vertices,
 
3295
                    work->vertices);
 
3296
 
 
3297
  }
 
3298
 
 
3299
#if defined(HAVE_MPI)
 
3300
  if (n_ranks > 1) { /* Parallel mode: we work by block */
 
3301
 
 
3302
    cs_int_t  *send_count = NULL, *recv_count = NULL;
 
3303
    cs_int_t  *send_shift = NULL, *recv_shift = NULL;
 
3304
    cs_join_vertex_t  *vtx_merge_data = NULL;
 
3305
 
 
3306
    BFT_MALLOC(send_count, n_ranks, cs_int_t);
 
3307
    BFT_MALLOC(recv_count, n_ranks, cs_int_t);
 
3308
    BFT_MALLOC(send_shift, n_ranks+1, cs_int_t);
 
3309
    BFT_MALLOC(recv_shift, n_ranks+1, cs_int_t);
 
3310
 
 
3311
    /* Build a merge list in parallel */
 
3312
 
 
3313
    _build_parall_merge_structures(work,
 
3314
                                   vtx_tags,
 
3315
                                   send_count, send_shift,
 
3316
                                   recv_count, recv_shift,
 
3317
                                   &vtx_merge_data,
 
3318
                                   &merge_set);
 
3319
 
 
3320
    /* Merge of equivalent vertices for the current block */
 
3321
 
 
3322
    _merge_vertices(param,
 
3323
                    merge_set,
 
3324
                    recv_shift[n_ranks],
 
3325
                    vtx_merge_data);
 
3326
 
 
3327
    _exchange_merged_vertices(work,
 
3328
                              vtx_tags,
 
3329
                              send_count, send_shift,
 
3330
                              recv_count, recv_shift,
 
3331
                              vtx_merge_data);
 
3332
 
 
3333
    BFT_FREE(send_count);
 
3334
    BFT_FREE(send_shift);
 
3335
    BFT_FREE(recv_count);
 
3336
    BFT_FREE(recv_shift);
 
3337
    BFT_FREE(vtx_merge_data);
 
3338
 
 
3339
  }
 
3340
#endif /* HAVE_MPI */
 
3341
 
 
3342
  /* Free memory */
 
3343
 
 
3344
  BFT_FREE(vtx_tags);
 
3345
 
 
3346
  clock_end = bft_timer_wtime();
 
3347
  cpu_end = bft_timer_cpu_time();
 
3348
 
 
3349
  cs_join_gset_destroy(&merge_set);
 
3350
 
 
3351
  if (param.verbosity > 1)
 
3352
    bft_printf(_("\n"
 
3353
                 "          Vertex merge (only)\n"
 
3354
                 "              wall clock time:       %10.3g\n"
 
3355
                 "              cpu time:              %10.3g\n"),
 
3356
               clock_end - clock_start, cpu_end - cpu_start);
 
3357
}
 
3358
 
 
3359
/*----------------------------------------------------------------------------
 
3360
 * Merge of equivalent vertices (and reduction of tolerance if necessary)
 
3361
 *
 
3362
 * Define a new cs_join_vertex_t structure (stored in "work" structure)
 
3363
 * Returns an updated cs_join_mesh_t and cs_join_edges_t structures.
 
3364
 *
 
3365
 * parameters:
 
3366
 *   param                <-- set of user-defined parameters for the joining
 
3367
 *   n_iwm_vertices       <-- initial number of vertices (work mesh struct.)
 
3368
 *   iwm_vtx_gnum         <-- initial global vertex num. (work mesh struct)
 
3369
 *   init_max_vtx_gnum    <-- initial max. global numbering for vertices
 
3370
 *   rank_face_gnum_index <-- index on face global numbering to determine
 
3371
 *                            the related rank
 
3372
 *   p_mesh               <-> pointer to cs_join_mesh_t structure
 
3373
 *   p_edges              <-> pointer to cs_join_edges_t structure
 
3374
 *   p_inter_edges        <-> pointer to a cs_join_inter_edges_t struct.
 
3375
 *   p_local_mesh         <-> pointer to a cs_join_mesh_t structure
 
3376
 *   p_o2n_vtx_gnum       --> array on blocks on the new global vertex
 
3377
 *                            numbering for the init. vertices (before inter.)
 
3378
 *---------------------------------------------------------------------------*/
 
3379
 
 
3380
void
 
3381
cs_join_merge_update_struct(cs_join_param_t          param,
 
3382
                            cs_int_t                 n_iwm_vertices,
 
3383
                            const fvm_gnum_t         iwm_vtx_gnum[],
 
3384
                            fvm_gnum_t               init_max_vtx_gnum,
 
3385
                            const fvm_gnum_t         rank_face_gnum_index[],
 
3386
                            cs_join_mesh_t         **p_mesh,
 
3387
                            cs_join_edges_t        **p_edges,
 
3388
                            cs_join_inter_edges_t  **p_inter_edges,
 
3389
                            cs_join_mesh_t         **p_local_mesh,
 
3390
                            fvm_gnum_t              *p_o2n_vtx_gnum[])
 
3391
{
 
3392
  cs_int_t  n_am_vertices = 0; /* new number of vertices after merge */
 
3393
  cs_int_t  *o2n_vtx_id = NULL;
 
3394
  fvm_gnum_t  *o2n_vtx_gnum = NULL;
 
3395
  cs_join_mesh_t  *mesh = *p_mesh;
 
3396
  cs_join_mesh_t  *local_mesh = *p_local_mesh;
 
3397
  cs_join_edges_t  *edges = *p_edges;
 
3398
  cs_join_inter_edges_t  *inter_edges = *p_inter_edges;
 
3399
 
 
3400
  /* Keep an history of the evolution of each vertex */
 
3401
 
 
3402
  _keep_global_vtx_evolution(n_iwm_vertices,   /* n_vertices before inter */
 
3403
                             iwm_vtx_gnum,
 
3404
                             init_max_vtx_gnum,
 
3405
                             mesh->n_vertices, /* n_vertices after inter */
 
3406
                             mesh->vertices,
 
3407
                             &o2n_vtx_gnum);   /* defined by block in // */
 
3408
 
 
3409
  _keep_local_vtx_evolution(mesh->n_vertices, /* n_vertices after inter */
 
3410
                            mesh->vertices,
 
3411
                            &n_am_vertices,   /* n_vertices after merge */
 
3412
                            &o2n_vtx_id);
 
3413
 
 
3414
  /* Update all structures which keeps data about vertices */
 
3415
 
 
3416
  if (inter_edges != NULL) { /* The join type is not conform */
 
3417
 
 
3418
    /* Update inter_edges structure */
 
3419
 
 
3420
    _update_inter_edges_after_merge(param,
 
3421
                                    n_iwm_vertices,
 
3422
                                    o2n_vtx_id,  /* size of mesh->n_vertices */
 
3423
                                    edges,
 
3424
                                    mesh,
 
3425
                                    &inter_edges);
 
3426
 
 
3427
    assert(edges->n_edges == inter_edges->n_edges);  /* Else: problem for
 
3428
                                                        future synchro. */
 
3429
 
 
3430
    /* Update cs_join_mesh_t structure after the merge of vertices
 
3431
       numbering of the old vertices + add new vertices */
 
3432
 
 
3433
    cs_join_mesh_update(mesh,
 
3434
                        edges,
 
3435
                        inter_edges->index,
 
3436
                        inter_edges->vtx_lst,
 
3437
                        n_am_vertices,
 
3438
                        o2n_vtx_id);
 
3439
 
 
3440
  } /* End if inter_edges != NULL */
 
3441
 
 
3442
  else
 
3443
    /* Update cs_join_mesh_t structure after the merge of vertices
 
3444
       numbering of the old vertices + add new vertices */
 
3445
 
 
3446
    cs_join_mesh_update(mesh,
 
3447
                        edges,
 
3448
                        NULL,
 
3449
                        NULL,
 
3450
                        n_am_vertices,
 
3451
                        o2n_vtx_id);
 
3452
 
 
3453
  BFT_FREE(o2n_vtx_id);
 
3454
 
 
3455
  /* Update local_mesh by redistributing mesh */
 
3456
 
 
3457
  _redistribute_mesh(rank_face_gnum_index,
 
3458
                     mesh,
 
3459
                     &local_mesh);
 
3460
 
 
3461
  /* Set return pointers */
 
3462
 
 
3463
  *p_mesh = mesh;
 
3464
  *p_edges = edges;
 
3465
  *p_inter_edges = inter_edges;
 
3466
  *p_o2n_vtx_gnum = o2n_vtx_gnum;
 
3467
  *p_local_mesh = local_mesh;
 
3468
}
 
3469
 
 
3470
/*---------------------------------------------------------------------------*/
 
3471
 
 
3472
END_C_DECLS