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

« back to all changes in this revision

Viewing changes to src/fvm/fvm_io_num.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2011-11-24 00:00:08 UTC
  • mfrom: (6.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20111124000008-2vo99e38267942q5
Tags: 2.1.0-3
Install a missing file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================
 
2
 * Main structure for an I/O numbering scheme associated with mesh entities
 
3
 * (such as cells, faces, and vertices);
 
4
 *
 
5
 * In parallel mode, such a scheme is important so as to redistribute
 
6
 * locally numbered entities on n processes to files written by p
 
7
 * processes, with p <= n.
 
8
 *
 
9
 * Only the case where p = 1 is presently implemented, so the numbering
 
10
 * scheme is simply based on entity's global labels.
 
11
 *
 
12
 * For p > 1, it would probably be necessary to extend the numbering
 
13
 * schemes so as to account for the fact that a given entity may have
 
14
 * a main index on its main associated domain, but may be present
 
15
 * as a ghost entity with another index on neighboring domains.
 
16
 *============================================================================*/
 
17
 
 
18
/*
 
19
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
20
 
 
21
  Copyright (C) 1998-2011 EDF S.A.
 
22
 
 
23
  This program is free software; you can redistribute it and/or modify it under
 
24
  the terms of the GNU General Public License as published by the Free Software
 
25
  Foundation; either version 2 of the License, or (at your option) any later
 
26
  version.
 
27
 
 
28
  This program is distributed in the hope that it will be useful, but WITHOUT
 
29
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
30
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
31
  details.
 
32
 
 
33
  You should have received a copy of the GNU General Public License along with
 
34
  this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
35
  Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
36
*/
 
37
 
 
38
/*----------------------------------------------------------------------------*/
 
39
 
 
40
#if defined(HAVE_CONFIG_H)
 
41
#include "cs_config.h"
 
42
#endif
 
43
 
 
44
/*----------------------------------------------------------------------------
 
45
 * Standard C library headers
 
46
 *----------------------------------------------------------------------------*/
 
47
 
 
48
#include <assert.h>
 
49
#include <math.h>
 
50
#include <stdio.h>
 
51
#include <string.h>
 
52
 
 
53
/*----------------------------------------------------------------------------
 
54
 * BFT library headers
 
55
 *----------------------------------------------------------------------------*/
 
56
 
 
57
#include <bft_mem.h>
 
58
#include <bft_printf.h>
 
59
 
 
60
/*----------------------------------------------------------------------------
 
61
 *  Local headers
 
62
 *----------------------------------------------------------------------------*/
 
63
 
 
64
#include "fvm_defs.h"
 
65
#include "fvm_config_defs.h"
 
66
#include "fvm_hilbert.h"
 
67
#include "fvm_morton.h"
 
68
#include "fvm_order.h"
 
69
#include "fvm_parall.h"
 
70
 
 
71
/*----------------------------------------------------------------------------
 
72
 *  Header for the current file
 
73
 *----------------------------------------------------------------------------*/
 
74
 
 
75
#include "fvm_io_num.h"
 
76
 
 
77
/*----------------------------------------------------------------------------*/
 
78
 
 
79
#ifdef __cplusplus
 
80
extern "C" {
 
81
#if 0
 
82
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
 
83
#endif
 
84
#endif /* __cplusplus */
 
85
 
 
86
/*============================================================================
 
87
 * Local structure definitions
 
88
 *============================================================================*/
 
89
 
 
90
/*----------------------------------------------------------------------------
 
91
 * Structure defining an I/O numbering scheme
 
92
 *----------------------------------------------------------------------------*/
 
93
 
 
94
/*
 
95
 * Notes:
 
96
 *
 
97
 * This structure currently only contains a global numbering array containing
 
98
 * each entity's global number (a 1 to n index). In the future, it may
 
99
 * also contain information relative to ghost zones, for I/O to file formats
 
100
 * enabling domain splitting with (with multiple groups of processes writing
 
101
 * different subsets, using ghost zones for entities on boundaries between
 
102
 * mesh parts assigned to different process groups). In such a case, the
 
103
 * main numbering would only be global as regards a process group, at least
 
104
 * for use with formats such as that of EnSight Gold.
 
105
 *
 
106
 * In some cases, a global number may appear on multiple processes (for a face
 
107
 * or vertex on a processor boundary). This means that multiple processes may
 
108
 * update the corresponding value in a gather-type operation preceding or
 
109
 * associated with I/O, in an undefined order. If the associated data is up to
 
110
 * date on each process, it should be identical, so this should not be a
 
111
 * problem. MPI-IO file writes or MPI-2 one-sided communication PUT operations
 
112
 * also authorize this, though for the latter, the MPI-2 standard indicates
 
113
 * that this is authorized if processes overlapping PUT operations should use
 
114
 * the same predefined datatype, which seems to exclude similar indexed
 
115
 * datatypes with different indexes. To avoid problems if we wish to use
 
116
 * MPI-2 one-sided communication, one relatively simple solution would be to
 
117
 * consider that for processes other than that of lowest rank in which an
 
118
 * entity appears, it appears after all entities not occuring in processes
 
119
 * of lower rank. In that case, we would have two array sizes:
 
120
 * global_num_size_tot defining the array's full size, and global_num_size
 
121
 * defining the size of the portion to use in gather type operations.
 
122
 */
 
123
 
 
124
struct _fvm_io_num_t {
 
125
 
 
126
  fvm_gnum_t         global_count;    /* Global number of entities */
 
127
  fvm_lnum_t         global_num_size; /* Local size of global numbering array */
 
128
  const fvm_gnum_t  *global_num;      /* Global (possibly shared) entity
 
129
                                         numbers (1 to n) */
 
130
  fvm_gnum_t        *_global_num;     /* Global entity numbers if owner,
 
131
                                         NULL otherwise */
 
132
 
 
133
};
 
134
 
 
135
/*=============================================================================
 
136
 * Static global variables
 
137
 *============================================================================*/
 
138
 
 
139
/* Names of space-filling curve types */
 
140
 
 
141
const char  *fvm_io_num_sfc_type_name[] = {N_("Morton (in bounding box)"),
 
142
                                           N_("Morton (in bounding cube)"),
 
143
                                           N_("Hilbert (in bounding box)"),
 
144
                                           N_("Hilbert (in bounding cube)")};
 
145
 
 
146
/*=============================================================================
 
147
 * Private function definitions
 
148
 *============================================================================*/
 
149
 
 
150
/*----------------------------------------------------------------------------
 
151
 * Use bubble sort on an expectedly short sequence of coordinates
 
152
 * to ensure lexicographical ordering.
 
153
 *
 
154
 * parameters:
 
155
 *   dim        <-- spatial dimension
 
156
 *   start_id   <-- start id in array
 
157
 *   end_id     <-- past-the-end id in array
 
158
 *   coords     <-- pointer to entity coordinates (interlaced)
 
159
 *   order      <-> ordering array base on Morton encoding, or
 
160
 *                  lexicographical coordinate ordering for ties
 
161
 *----------------------------------------------------------------------------*/
 
162
 
 
163
inline static void
 
164
_reorder_coords_lexicographic(int                dim,
 
165
                              size_t             start_id,
 
166
                              size_t             end_id,
 
167
                              const fvm_coord_t  coords[],
 
168
                              fvm_lnum_t         order[])
 
169
{
 
170
  size_t  i;
 
171
  _Bool g_swap;
 
172
 
 
173
  do {
 
174
 
 
175
    g_swap = false;
 
176
 
 
177
    for (i = start_id + 1; i < end_id; i++) {
 
178
 
 
179
      size_t j_prev = order[i-1], j = order[i];
 
180
      _Bool l_swap = false;
 
181
 
 
182
      if (dim == 3) {
 
183
        if (coords[j_prev*3] < coords[j*3])
 
184
          continue;
 
185
        else if (coords[j_prev*3] > coords[j*3])
 
186
          l_swap = true;
 
187
        else if (coords[j_prev*3 + 1] < coords[j*3 + 1])
 
188
          continue;
 
189
        else if (   coords[j_prev*3 + 1] > coords[j*3 + 1]
 
190
                 || coords[j_prev*3 + 2] > coords[j*3 + 2])
 
191
          l_swap = true;
 
192
      }
 
193
      else if (dim == 2) {
 
194
        if (coords[j_prev*2] < coords[j*2 + 1])
 
195
          continue;
 
196
        else if (   coords[j_prev*2]     > coords[j*2]
 
197
                 || coords[j_prev*2 + 1] > coords[j*2 + 1])
 
198
          l_swap = true;
 
199
      }
 
200
      else { /* if (dim == 1) */
 
201
        if (coords[j_prev] > coords[j])
 
202
          l_swap = true;
 
203
      }
 
204
 
 
205
      if (l_swap) {
 
206
        fvm_lnum_t o_save = order[i-1];
 
207
        order[i-1] = order[i];
 
208
        order[i] = o_save;
 
209
        g_swap = true;
 
210
      }
 
211
    }
 
212
 
 
213
  } while (g_swap);
 
214
}
 
215
 
 
216
/*----------------------------------------------------------------------------
 
217
 * Creation of an I/O numbering structure based on coordinates.
 
218
 *
 
219
 * The ordering is based on a Morton code, and it is expected that
 
220
 * entities are unique (i.e. not duplicated on 2 or more ranks).
 
221
 * In the case that 2 entities have a same Morton code, their global
 
222
 * number will be different, but their order is undetermined.
 
223
 *
 
224
 * parameters:
 
225
 *   dim        <-- spatial dimension
 
226
 *   n_entities <-- number of entities considered
 
227
 *   coords     <-- pointer to entity coordinates (interlaced)
 
228
 *   m_code     <-- Morton code associated with each entity
 
229
 *   order      <-> ordering array base on Morton encoding, or
 
230
 *                  lexicographical coordinate ordering for ties
 
231
 *
 
232
 * returns:
 
233
 *  pointer to I/O numbering structure
 
234
 *----------------------------------------------------------------------------*/
 
235
 
 
236
static void
 
237
_check_morton_ordering(int                      dim,
 
238
                       size_t                   n_entities,
 
239
                       const fvm_coord_t        coords[],
 
240
                       const fvm_morton_code_t  m_code[],
 
241
                       fvm_lnum_t               order[])
 
242
{
 
243
  size_t  i_prev = 0, i = 1;
 
244
 
 
245
  if (n_entities == 0)
 
246
    return;
 
247
 
 
248
  /* Check ordering; if two entities have the same Morton codes,
 
249
     use lexicographical coordinates ordering to ensure the
 
250
     final order is deterministic. */
 
251
 
 
252
  for (i = 1; i < n_entities; i++) {
 
253
 
 
254
    size_t j_prev = order[i_prev], j = order[i];
 
255
 
 
256
    if (   m_code[j_prev].X[0] != m_code[j].X[0]
 
257
        || m_code[j_prev].X[1] != m_code[j].X[1]
 
258
        || m_code[j_prev].X[2] != m_code[j].X[2]) {
 
259
 
 
260
      /* If successive values have the same Morton code,
 
261
         order them lexicographically */
 
262
      if (i_prev < i - 1)
 
263
        _reorder_coords_lexicographic(dim, i_prev, i-1, coords, order);
 
264
 
 
265
      i_prev = i;
 
266
    }
 
267
  }
 
268
 
 
269
  if (i_prev < n_entities - 1)
 
270
    _reorder_coords_lexicographic(dim, i_prev, n_entities - 1, coords, order);
 
271
}
 
272
 
 
273
#if defined(HAVE_MPI)
 
274
 
 
275
/*----------------------------------------------------------------------------
 
276
 * Copy selected shared global ordering information to private ordering
 
277
 * information for an I/O numbering structure.
 
278
 *
 
279
 * parameters:
 
280
 *   this_io_num <-- pointer to numbering structure
 
281
 *----------------------------------------------------------------------------*/
 
282
 
 
283
static void
 
284
_fvm_io_num_copy_on_write(fvm_io_num_t  *const this_io_num)
 
285
{
 
286
  if (this_io_num->_global_num == NULL) {
 
287
    fvm_lnum_t i;
 
288
    BFT_MALLOC(this_io_num->_global_num,
 
289
               this_io_num->global_num_size,
 
290
               fvm_gnum_t);
 
291
    for (i = 0; i < this_io_num->global_num_size; i++)
 
292
      this_io_num->_global_num[i] = this_io_num->global_num[i];
 
293
    this_io_num->global_num = this_io_num->_global_num;
 
294
  }
 
295
  assert(this_io_num->global_num == this_io_num->_global_num);
 
296
}
 
297
 
 
298
/*----------------------------------------------------------------------------
 
299
 * Copy selected shared global ordering information to private ordering
 
300
 * information for an I/O numbering structure.
 
301
 *
 
302
 * parameters:
 
303
 *   this_io_num          <-> pointer to numbering structure
 
304
 *   parent_global_number <-- pointer to shared list of global parent
 
305
 *                            entity numbers
 
306
 *----------------------------------------------------------------------------*/
 
307
 
 
308
static void
 
309
_fvm_io_num_try_to_set_shared(fvm_io_num_t      *const this_io_num,
 
310
                              const fvm_gnum_t         parent_global_number[])
 
311
{
 
312
  if (this_io_num->_global_num != NULL && parent_global_number != NULL) {
 
313
    fvm_lnum_t i;
 
314
    for (i = 0; i < this_io_num->global_num_size; i++)
 
315
      if (this_io_num->_global_num[i] != parent_global_number[i])
 
316
        break;
 
317
    if (i < this_io_num->global_num_size)
 
318
      this_io_num->global_num = this_io_num->_global_num;
 
319
    else {
 
320
      this_io_num->global_num = parent_global_number;
 
321
      BFT_FREE(this_io_num->_global_num);
 
322
    }
 
323
  }
 
324
}
 
325
 
 
326
/*----------------------------------------------------------------------------
 
327
 * Maximum global number associated with an I/O numbering structure
 
328
 *
 
329
 * parameters:
 
330
 *   this_io_num <-- pointer to partially initialized I/O numbering structure.
 
331
 *   comm        <-- associated MPI communicator
 
332
 *
 
333
 * returns:
 
334
 *   maximum global number associated with the I/O numbering
 
335
 *----------------------------------------------------------------------------*/
 
336
 
 
337
static fvm_gnum_t
 
338
_fvm_io_num_global_max(const fvm_io_num_t  *const this_io_num,
 
339
                       const MPI_Comm             comm)
 
340
{
 
341
  fvm_gnum_t  local_max, global_max;
 
342
  size_t      n_ent;
 
343
 
 
344
  /* Get maximum global number value */
 
345
 
 
346
  n_ent = this_io_num->global_num_size;
 
347
  if (n_ent > 0)
 
348
    local_max = this_io_num->global_num[n_ent - 1];
 
349
  else
 
350
    local_max = 0;
 
351
 
 
352
  MPI_Allreduce(&local_max, &global_max, 1, FVM_MPI_GNUM, MPI_MAX, comm);
 
353
 
 
354
  return global_max;
 
355
}
 
356
 
 
357
/*----------------------------------------------------------------------------
 
358
 * Global ordering associated with an I/O numbering structure.
 
359
 *
 
360
 * The structure should contain an initial ordering, which should
 
361
 * be sorted, but need not be contiguous. On output, the numbering
 
362
 * will be contiguous.
 
363
 *
 
364
 * As an option, a number of sub-entities per initial entity may be
 
365
 * given, in which case sub-entities of a same entity will have contiguous
 
366
 * numbers in the final ordering.
 
367
 *
 
368
 * parameters:
 
369
 *   this_io_num    <-> pointer to structure that should be ordered
 
370
 *   n_sub_entities <-- optional number of sub-entities per initial entity,
 
371
 *                      or NULL if unused
 
372
 *   comm           <-- associated MPI communicator
 
373
 *----------------------------------------------------------------------------*/
 
374
 
 
375
static void
 
376
_fvm_io_num_global_order(fvm_io_num_t       *this_io_num,
 
377
                         const fvm_lnum_t    n_sub_entities[],
 
378
                         MPI_Comm            comm)
 
379
{
 
380
 
 
381
  fvm_gnum_t  n_ent_recv, num_prev, num_cur;
 
382
  size_t      i, j, slice_size;
 
383
  fvm_lnum_t  k;
 
384
  int         rank;
 
385
 
 
386
  _Bool       may_be_shared = false;
 
387
 
 
388
  fvm_gnum_t  *recv_global_num = NULL;
 
389
  fvm_lnum_t  *recv_n_sub = NULL, *recv_order = NULL;
 
390
  int         *send_count = NULL, *recv_count = NULL;
 
391
  int         *send_shift = NULL, *recv_shift = NULL;
 
392
  int         have_sub_loc = 0, have_sub_glob = 0;
 
393
 
 
394
  int         local_rank, size;
 
395
 
 
396
  fvm_gnum_t  current_global_num = 0, global_num_shift = 0;
 
397
 
 
398
  /* Initialization */
 
399
 
 
400
  MPI_Comm_rank(comm, &local_rank);
 
401
  MPI_Comm_size(comm, &size);
 
402
 
 
403
  num_prev = 0;    /* true initialization later for slice 0, */
 
404
 
 
405
  /* If numbering is shared, we will check later it was changed or if
 
406
     it can remain shared (in which case the copy may be discarded) */
 
407
 
 
408
  if (this_io_num->global_num != this_io_num->_global_num)
 
409
    may_be_shared = true;
 
410
  else
 
411
    may_be_shared = false;
 
412
 
 
413
  /* Get temporary maximum global number value */
 
414
 
 
415
  this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
416
 
 
417
  /* slice_size = ceil(this_io_num->global_count/size) */
 
418
 
 
419
  slice_size = this_io_num->global_count / size;
 
420
  if (this_io_num->global_count % size > 0)
 
421
    slice_size += 1;
 
422
 
 
423
  assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
 
424
 
 
425
  BFT_MALLOC(send_count, size, int);
 
426
  BFT_MALLOC(recv_count, size, int);
 
427
 
 
428
  BFT_MALLOC(send_shift, size, int);
 
429
  BFT_MALLOC(recv_shift, size, int);
 
430
 
 
431
  /* Count number of values to send to each process */
 
432
 
 
433
  for (rank = 0; rank < size; rank++)
 
434
    send_count[rank] = 0;
 
435
 
 
436
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
437
    send_count[(this_io_num->global_num[i] - 1) / slice_size] += 1;
 
438
 
 
439
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
440
 
 
441
  send_shift[0] = 0;
 
442
  recv_shift[0] = 0;
 
443
 
 
444
  for (rank = 1; rank < size; rank++) {
 
445
    send_shift[rank] = send_shift[rank - 1] + send_count[rank -1];
 
446
    recv_shift[rank] = recv_shift[rank - 1] + recv_count[rank -1];
 
447
  }
 
448
 
 
449
  /* As data is sorted by increasing base global numbering, we do not
 
450
     need to build an extra array, but only to send the correct parts
 
451
     of the n_sub_entities[] array to the correct processors */
 
452
 
 
453
  n_ent_recv = recv_shift[size - 1] + recv_count[size - 1];
 
454
 
 
455
  BFT_MALLOC(recv_global_num, n_ent_recv, fvm_gnum_t);
 
456
  BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
 
457
 
 
458
  MPI_Alltoallv(this_io_num->_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
459
                recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
 
460
 
 
461
  /* Do we have sub-entities ? */
 
462
 
 
463
  if (n_sub_entities != NULL)
 
464
    have_sub_loc = 1;
 
465
 
 
466
  MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX, comm);
 
467
 
 
468
  if (have_sub_glob > 0) {
 
469
 
 
470
    fvm_lnum_t  *send_n_sub;
 
471
 
 
472
    BFT_MALLOC(send_n_sub, this_io_num->global_num_size, fvm_lnum_t);
 
473
    BFT_MALLOC(recv_n_sub, n_ent_recv, fvm_lnum_t);
 
474
 
 
475
    if (n_sub_entities != NULL) {
 
476
      for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
477
        send_n_sub[i] = n_sub_entities[i];
 
478
    }
 
479
    else {
 
480
      for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
481
        send_n_sub[i] = 1;
 
482
    }
 
483
 
 
484
    MPI_Alltoallv(send_n_sub, send_count, send_shift, FVM_MPI_LNUM,
 
485
                  recv_n_sub, recv_count, recv_shift, FVM_MPI_LNUM, comm);
 
486
 
 
487
    BFT_FREE(send_n_sub);
 
488
  }
 
489
 
 
490
  if (n_ent_recv > 0) {
 
491
 
 
492
    fvm_order_local_allocated(NULL,
 
493
                              recv_global_num,
 
494
                              recv_order,
 
495
                              n_ent_recv);
 
496
 
 
497
    /* Determine global order; requires ordering to loop through buffer by
 
498
       increasing number (slice blocks associated with each process are
 
499
       already sorted, but the whole "gathered" slice is not).
 
500
       We build an initial global order based on the initial global numbering,
 
501
       such that for each slice, the global number of an entity is equal to
 
502
       the cumulative number of sub-entities */
 
503
 
 
504
    if (have_sub_glob > 0) {
 
505
 
 
506
      current_global_num = recv_n_sub[recv_order[0]];
 
507
      num_prev = recv_global_num[recv_order[0]];
 
508
      recv_global_num[recv_order[0]] = current_global_num;
 
509
 
 
510
      for (i = 1; i < n_ent_recv; i++) {
 
511
        num_cur = recv_global_num[recv_order[i]];
 
512
        if (num_cur > num_prev)
 
513
          current_global_num += recv_n_sub[recv_order[i]];
 
514
        recv_global_num[recv_order[i]] = current_global_num;
 
515
        num_prev = num_cur;
 
516
      }
 
517
 
 
518
    }
 
519
    else { /* if (have_sub_glob == 0) */
 
520
 
 
521
      current_global_num = 1;
 
522
      num_prev = recv_global_num[recv_order[0]];
 
523
      recv_global_num[recv_order[0]] = current_global_num;
 
524
 
 
525
      for (i = 1; i < n_ent_recv; i++) {
 
526
        num_cur = recv_global_num[recv_order[i]];
 
527
        if (num_cur > num_prev)
 
528
          current_global_num += 1;
 
529
        recv_global_num[recv_order[i]] = current_global_num;
 
530
        num_prev = num_cur;
 
531
      }
 
532
 
 
533
    }
 
534
 
 
535
  }
 
536
 
 
537
  /* Partial clean-up */
 
538
 
 
539
  BFT_FREE(recv_n_sub);
 
540
  BFT_FREE(recv_order);
 
541
 
 
542
  /* At this stage, recv_global_num[] is valid for this process, and
 
543
     current_global_num indicates the total number of entities handled
 
544
     by this process; we must now shift global numberings on different
 
545
     processes by the cumulative total number of entities handled by
 
546
     each process */
 
547
 
 
548
  MPI_Scan(&current_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
 
549
           MPI_SUM, comm);
 
550
  global_num_shift -= current_global_num;
 
551
 
 
552
  for (i = 0; i < n_ent_recv; i++)
 
553
    recv_global_num[i] += global_num_shift;
 
554
 
 
555
  /* Return global order to all processors */
 
556
 
 
557
  MPI_Alltoallv(recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
558
                this_io_num->_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
559
                comm);
 
560
 
 
561
  /* Free memory */
 
562
 
 
563
  BFT_FREE(recv_global_num);
 
564
 
 
565
  BFT_FREE(send_count);
 
566
  BFT_FREE(recv_count);
 
567
  BFT_FREE(send_shift);
 
568
  BFT_FREE(recv_shift);
 
569
 
 
570
  /* Get final maximum global number value */
 
571
 
 
572
  this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
573
 
 
574
  /* When sub-entities have been added, now switch from a numbering on
 
575
     the initial entities (shifted by number of sub-entities) to
 
576
     a numbering on the final sub-entities */
 
577
 
 
578
  if (n_sub_entities != NULL) {
 
579
 
 
580
    fvm_gnum_t *_global_num;
 
581
 
 
582
    for (i = 0, j = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
583
      j += n_sub_entities[i];
 
584
 
 
585
    BFT_MALLOC(_global_num, j, fvm_gnum_t);
 
586
 
 
587
    for (i = 0, j = 0; i < (size_t)(this_io_num->global_num_size); i++) {
 
588
      for (k = 0; k < n_sub_entities[i]; j++, k++)
 
589
        _global_num[j] = this_io_num->_global_num[i] - n_sub_entities[i] + k + 1;
 
590
    }
 
591
 
 
592
    BFT_FREE(this_io_num->_global_num);
 
593
    this_io_num->_global_num = _global_num;
 
594
 
 
595
    if (this_io_num->global_num_size != (fvm_lnum_t)j) {
 
596
      this_io_num->global_num_size = j;
 
597
      may_be_shared = false;
 
598
    }
 
599
 
 
600
    if (may_be_shared == false)
 
601
      this_io_num->global_num = this_io_num->_global_num;
 
602
  }
 
603
 
 
604
  /* If numbering was initially shared, check if it was changed or if it
 
605
     may remain shared (in which case the copy may be discarded) */
 
606
 
 
607
  if (may_be_shared == true) {
 
608
    for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
609
      if (this_io_num->_global_num[i] != this_io_num->global_num[i])
 
610
        break;
 
611
    if (i < (size_t)(this_io_num->global_num_size))
 
612
      this_io_num->global_num = this_io_num->_global_num;
 
613
    else
 
614
      BFT_FREE(this_io_num->_global_num);
 
615
  }
 
616
}
 
617
 
 
618
/*----------------------------------------------------------------------------
 
619
 * Global ordering associated with an I/O numbering structure.
 
620
 *
 
621
 * The structure should contain an initial ordering, which should
 
622
 * be sorted, but need not be contiguous. On output, the numbering
 
623
 * will be contiguous.
 
624
 *
 
625
 * parameters:
 
626
 *   this_io_num    <-> pointer to structure that should be ordered
 
627
 *   stride         <-- values per entity
 
628
 *   global_num     <-- global numbering array
 
629
 *   comm           <-- associated MPI communicator
 
630
 *----------------------------------------------------------------------------*/
 
631
 
 
632
static void
 
633
_fvm_io_num_global_order_s(fvm_io_num_t       *this_io_num,
 
634
                           size_t              stride,
 
635
                           fvm_gnum_t          global_num[],
 
636
                           MPI_Comm            comm)
 
637
{
 
638
  fvm_gnum_t  n_ent_recv;
 
639
  size_t      i, j, slice_size;
 
640
  int         rank;
 
641
 
 
642
  fvm_gnum_t  *block_global_num = NULL, *recv_global_num = NULL;
 
643
  fvm_lnum_t  *recv_order = NULL;
 
644
  int         *send_count = NULL, *recv_count = NULL;
 
645
  int         *send_shift = NULL, *recv_shift = NULL;
 
646
 
 
647
  int         local_rank, size;
 
648
 
 
649
  fvm_gnum_t  current_global_num = 0, global_num_shift = 0;
 
650
 
 
651
  /* Initialization */
 
652
 
 
653
  MPI_Comm_rank(comm, &local_rank);
 
654
  MPI_Comm_size(comm, &size);
 
655
 
 
656
  /* Get maximum global number value for first value of each series
 
657
     (does not need to be exact, simply used to define blocks) */
 
658
 
 
659
  {
 
660
    fvm_gnum_t  local_max = 0, global_max = 0;
 
661
    size_t      n_ent = this_io_num->global_num_size;
 
662
 
 
663
    if (n_ent > 0)
 
664
      local_max = global_num[(n_ent-1)*stride];
 
665
    MPI_Allreduce(&local_max, &global_max, 1, FVM_MPI_GNUM, MPI_MAX, comm);
 
666
    this_io_num->global_count = global_max;
 
667
  }
 
668
 
 
669
  /* slice_size = ceil(this_io_num->global_count/size) */
 
670
 
 
671
  slice_size = this_io_num->global_count / size;
 
672
  if (this_io_num->global_count % size > 0)
 
673
    slice_size += 1;
 
674
 
 
675
  assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
 
676
 
 
677
  BFT_MALLOC(send_count, size, int);
 
678
  BFT_MALLOC(recv_count, size, int);
 
679
 
 
680
  BFT_MALLOC(send_shift, size, int);
 
681
  BFT_MALLOC(recv_shift, size, int);
 
682
 
 
683
  /* Count number of values to send to each process */
 
684
 
 
685
  for (rank = 0; rank < size; rank++)
 
686
    send_count[rank] = 0;
 
687
 
 
688
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
689
    send_count[(global_num[stride*i] - 1) / slice_size] += stride;
 
690
 
 
691
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
692
 
 
693
  send_shift[0] = 0;
 
694
  recv_shift[0] = 0;
 
695
 
 
696
  for (rank = 1; rank < size; rank++) {
 
697
    send_shift[rank] = send_shift[rank - 1] + send_count[rank -1];
 
698
    recv_shift[rank] = recv_shift[rank - 1] + recv_count[rank -1];
 
699
  }
 
700
 
 
701
  /* As data is sorted by increasing base global numbering, we do not
 
702
     need to build an extra array, but only to send the correct parts
 
703
     of the n_sub_entities[] array to the correct processors */
 
704
 
 
705
  n_ent_recv = (recv_shift[size - 1] + recv_count[size - 1]) / stride;
 
706
 
 
707
  BFT_MALLOC(recv_global_num, stride*n_ent_recv, fvm_gnum_t);
 
708
  BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
 
709
 
 
710
  MPI_Alltoallv(global_num, send_count, send_shift, FVM_MPI_GNUM,
 
711
                recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
 
712
 
 
713
  if (n_ent_recv > 0) {
 
714
 
 
715
    size_t prev_id, cur_id;
 
716
 
 
717
    fvm_order_local_allocated_s(NULL,
 
718
                                recv_global_num,
 
719
                                stride,
 
720
                                recv_order,
 
721
                                n_ent_recv);
 
722
 
 
723
    /* Determine global order; requires ordering to loop through buffer by
 
724
       increasing number (slice blocks associated with each process are
 
725
       already sorted, but the whole "gathered" slice is not).
 
726
       We build an initial global order based on the initial global numbering,
 
727
       such that for each slice, the global number of an entity is equal to
 
728
       the cumulative number of sub-entities */
 
729
 
 
730
    BFT_MALLOC(block_global_num, n_ent_recv, fvm_gnum_t);
 
731
 
 
732
    current_global_num = 1;
 
733
    prev_id = recv_order[0];
 
734
    block_global_num[recv_order[0]] = current_global_num;
 
735
 
 
736
    for (i = 1; i < n_ent_recv; i++) {
 
737
      bool greater_than_prev = false;
 
738
      cur_id = recv_order[i];
 
739
      for (j = 0; j < stride; j++) {
 
740
        if (  recv_global_num[cur_id*stride + j]
 
741
            > recv_global_num[prev_id*stride + j])
 
742
          greater_than_prev = true;
 
743
      }
 
744
      if (greater_than_prev)
 
745
        current_global_num += 1;
 
746
      block_global_num[recv_order[i]] = current_global_num;
 
747
      prev_id = cur_id;
 
748
    }
 
749
 
 
750
  }
 
751
 
 
752
  /* Partial clean-up */
 
753
 
 
754
  BFT_FREE(recv_order);
 
755
  BFT_FREE(recv_global_num);
 
756
 
 
757
  /* At this stage, recv_global_num[] is valid for this process, and
 
758
     current_global_num indicates the total number of entities handled
 
759
     by this process; we must now shift global numberings on different
 
760
     processes by the cumulative total number of entities handled by
 
761
     each process */
 
762
 
 
763
  MPI_Scan(&current_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
 
764
           MPI_SUM, comm);
 
765
  global_num_shift -= current_global_num;
 
766
 
 
767
  for (i = 0; i < n_ent_recv; i++)
 
768
    block_global_num[i] += global_num_shift;
 
769
 
 
770
  /* Return global order to all processors */
 
771
 
 
772
  for (rank = 0; rank < size; rank++) {
 
773
    send_count[rank] /= stride;
 
774
    recv_count[rank] /= stride;
 
775
  }
 
776
 
 
777
  for (rank = 1; rank < size; rank++) {
 
778
    send_shift[rank] = send_shift[rank - 1] + send_count[rank -1];
 
779
    recv_shift[rank] = recv_shift[rank - 1] + recv_count[rank -1];
 
780
  }
 
781
 
 
782
  MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
783
                this_io_num->_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
784
                comm);
 
785
 
 
786
  /* Free memory */
 
787
 
 
788
  BFT_FREE(block_global_num);
 
789
  BFT_FREE(send_count);
 
790
  BFT_FREE(recv_count);
 
791
  BFT_FREE(send_shift);
 
792
  BFT_FREE(recv_shift);
 
793
 
 
794
  /* Get final maximum global number value */
 
795
 
 
796
  this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
797
}
 
798
 
 
799
/*----------------------------------------------------------------------------
 
800
 * Compare two elements in an indexed list and returns true if element in
 
801
 * position i1 is strictly greater than element in position i2.
 
802
 *
 
803
 * parameters:
 
804
 *   i1        <-- position in index for the first element
 
805
 *   i2        <-- position in index for the second element
 
806
 *   index     <-- number of values to compare for each entity
 
807
 *   number    <-- pointer to numbers of entities that should be ordered.
 
808
 *                 (if NULL, a default 1 to n numbering is considered)
 
809
 *
 
810
 * returns:
 
811
 *  true or false
 
812
 *----------------------------------------------------------------------------*/
 
813
 
 
814
inline static _Bool
 
815
_indexed_is_greater(size_t            i1,
 
816
                    size_t            i2,
 
817
                    const fvm_lnum_t  index[],
 
818
                    const fvm_gnum_t  number[])
 
819
{
 
820
  int  i;
 
821
 
 
822
  fvm_lnum_t  i1_s = index[i1], i1_e = index[i1+1], s1 = i1_e - i1_s;
 
823
  fvm_lnum_t  i2_s = index[i2], i2_e = index[i2+1], s2 = i2_e - i2_s;
 
824
 
 
825
  if (s1 > s2) {
 
826
 
 
827
    for (i = 0; i < s2; i++) {
 
828
      if (number[i1_s + i] > number[i2_s + i])
 
829
        return true;
 
830
      else if (number[i1_s + i] < number[i2_s + i])
 
831
        return false;
 
832
    }
 
833
 
 
834
    return true;
 
835
  }
 
836
  else { /* s1 <= s2 */
 
837
 
 
838
    for (i = 0; i < s1; i++) {
 
839
      if (number[i1_s + i] > number[i2_s + i])
 
840
        return true;
 
841
      else if (number[i1_s + i] < number[i2_s + i])
 
842
        return false;
 
843
    }
 
844
 
 
845
    return false;
 
846
  }
 
847
 
 
848
}
 
849
 
 
850
/*----------------------------------------------------------------------------
 
851
 * Global indexed ordering associated with an I/O numbering structure.
 
852
 *
 
853
 * The structure should contain an initial ordering, which should
 
854
 * be sorted, but need not be contiguous. On output, the numbering
 
855
 * will be contiguous.
 
856
 *
 
857
 * parameters:
 
858
 *   this_io_num    <-> pointer to structure that should be ordered
 
859
 *   index          <-- index on entities for global_num[]
 
860
 *   global_num     <--
 
861
 *   comm           <-- associated MPI communicator
 
862
 *----------------------------------------------------------------------------*/
 
863
 
 
864
static void
 
865
_fvm_io_num_global_order_index(fvm_io_num_t       *this_io_num,
 
866
                               fvm_lnum_t          index[],
 
867
                               fvm_gnum_t          global_num[],
 
868
                               MPI_Comm            comm)
 
869
{
 
870
  int  rank, local_rank, size;
 
871
  size_t  i, shift, slice_size;
 
872
 
 
873
  fvm_gnum_t  n_ent_recv = 0, n_ent_send = 0;
 
874
  fvm_gnum_t  current_global_num = 0, global_num_shift = 0;
 
875
  int  *send_count = NULL, *recv_count = NULL;
 
876
  int  *send_shift = NULL, *recv_shift = NULL;
 
877
  fvm_lnum_t  *recv_order = NULL, *recv_sub_index = NULL;
 
878
  fvm_lnum_t  *recv_sub_count = NULL, *send_sub_count = NULL;
 
879
  fvm_gnum_t  *block_global_num = NULL, *recv_global_num = NULL;
 
880
 
 
881
  /* Initialization */
 
882
 
 
883
  MPI_Comm_rank(comm, &local_rank);
 
884
  MPI_Comm_size(comm, &size);
 
885
 
 
886
  /* Get maximum global number value for first value of each series
 
887
     (does not need to be exact, simply used to define blocks) */
 
888
 
 
889
  {
 
890
    fvm_gnum_t  local_max = 0, global_max = 0;
 
891
    size_t      n_ent = this_io_num->global_num_size;
 
892
 
 
893
    if (n_ent > 0)
 
894
      local_max = global_num[index[n_ent-1]];
 
895
    MPI_Allreduce(&local_max, &global_max, 1, FVM_MPI_GNUM, MPI_MAX, comm);
 
896
    this_io_num->global_count = global_max;
 
897
  }
 
898
 
 
899
  /* slice_size = ceil(this_io_num->global_count/size) */
 
900
 
 
901
  slice_size = this_io_num->global_count / size;
 
902
  if (this_io_num->global_count % size > 0)
 
903
    slice_size += 1;
 
904
 
 
905
  /* Build for each slice, a new ordered indexed list from the received
 
906
     elements */
 
907
 
 
908
  assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
 
909
 
 
910
  BFT_MALLOC(send_count, size, int);
 
911
  BFT_MALLOC(recv_count, size, int);
 
912
  BFT_MALLOC(send_shift, size + 1, int);
 
913
  BFT_MALLOC(recv_shift, size + 1, int);
 
914
 
 
915
  /* Count number of values to send to each process */
 
916
 
 
917
  for (rank = 0; rank < size; rank++)
 
918
    send_count[rank] = 0;
 
919
 
 
920
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++) {
 
921
    rank = (global_num[index[i]] - 1) / slice_size;
 
922
    send_count[rank] += 1;
 
923
  }
 
924
 
 
925
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
926
 
 
927
  send_shift[0] = 0;
 
928
  recv_shift[0] = 0;
 
929
 
 
930
  for (rank = 0; rank < size; rank++) {
 
931
    send_shift[rank+1] = send_shift[rank] + send_count[rank];
 
932
    recv_shift[rank+1] = recv_shift[rank] + recv_count[rank];
 
933
  }
 
934
 
 
935
  /* Get recv_index */
 
936
 
 
937
  n_ent_recv = recv_shift[size];
 
938
  n_ent_send = send_shift[size];
 
939
 
 
940
  BFT_MALLOC(recv_sub_count, n_ent_recv, fvm_lnum_t);
 
941
  BFT_MALLOC(send_sub_count, n_ent_send, fvm_lnum_t);
 
942
 
 
943
  assert(n_ent_send == (fvm_gnum_t)this_io_num->global_num_size);
 
944
 
 
945
  for (rank = 0; rank < size; rank++)
 
946
    send_count[rank] = 0;
 
947
 
 
948
  for (i = 0; i < (size_t)this_io_num->global_num_size; i++) {
 
949
    rank = (global_num[index[i]] - 1) / slice_size;
 
950
    shift = send_shift[rank] + send_count[rank];
 
951
    send_sub_count[shift] = index[i+1] - index[i];
 
952
    send_count[rank] +=  1;
 
953
  }
 
954
 
 
955
  MPI_Alltoallv(send_sub_count, send_count, send_shift, FVM_MPI_LNUM,
 
956
                recv_sub_count, recv_count, recv_shift, FVM_MPI_LNUM, comm);
 
957
 
 
958
  BFT_MALLOC(recv_sub_index, n_ent_recv + 1, fvm_lnum_t);
 
959
 
 
960
  recv_sub_index[0] = 0;
 
961
  for (i = 0; i < n_ent_recv; i++)
 
962
      recv_sub_index[i+1] = recv_sub_index[i] + recv_sub_count[i];
 
963
 
 
964
  BFT_FREE(send_sub_count);
 
965
  BFT_FREE(recv_sub_count);
 
966
 
 
967
  /* Get recv_global_num */
 
968
 
 
969
  /* Count number of values to send to each process */
 
970
 
 
971
  for (rank = 0; rank < size; rank++)
 
972
    send_count[rank] = 0;
 
973
 
 
974
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++) {
 
975
    rank = (global_num[index[i]] - 1) / slice_size;
 
976
    send_count[rank] += index[i+1] - index[i];
 
977
  }
 
978
 
 
979
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
980
 
 
981
  send_shift[0] = 0;
 
982
  recv_shift[0] = 0;
 
983
 
 
984
  for (rank = 0; rank < size; rank++) {
 
985
    send_shift[rank+1] = send_shift[rank] + send_count[rank];
 
986
    recv_shift[rank+1] = recv_shift[rank] + recv_count[rank];
 
987
  }
 
988
 
 
989
  BFT_MALLOC(recv_global_num, recv_sub_index[n_ent_recv], fvm_gnum_t);
 
990
 
 
991
  /* As data is sorted by increasing base global numbering, we do not
 
992
     need to build an extra array, but only to send the correct parts
 
993
     of the indexed list to the correct processors */
 
994
 
 
995
  MPI_Alltoallv(global_num, send_count, send_shift, FVM_MPI_GNUM,
 
996
                recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
 
997
 
 
998
  if (n_ent_recv > 0) { /* Order received elements of the indexed list */
 
999
 
 
1000
    size_t prev_id, cur_id;
 
1001
 
 
1002
    BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
 
1003
 
 
1004
    fvm_order_local_allocated_i(NULL,
 
1005
                                recv_global_num,
 
1006
                                recv_sub_index,
 
1007
                                recv_order,
 
1008
                                n_ent_recv);
 
1009
 
 
1010
    /* Determine global order; requires ordering to loop through buffer by
 
1011
       increasing number (slice blocks associated with each process are
 
1012
       already sorted, but the whole "gathered" slice is not).
 
1013
       We build an initial global order based on the initial global numbering,
 
1014
       such that for each slice, the global number of an entity is equal to
 
1015
       the cumulative number of elements */
 
1016
 
 
1017
    BFT_MALLOC(block_global_num, n_ent_recv, fvm_gnum_t);
 
1018
 
 
1019
    current_global_num = 1;
 
1020
    prev_id = recv_order[0];
 
1021
    block_global_num[recv_order[0]] = current_global_num;
 
1022
 
 
1023
    for (i = 1; i < n_ent_recv; i++) {
 
1024
 
 
1025
      cur_id = recv_order[i];
 
1026
 
 
1027
      if (_indexed_is_greater(cur_id, prev_id, recv_sub_index, recv_global_num))
 
1028
        current_global_num += 1;
 
1029
 
 
1030
      block_global_num[recv_order[i]] = current_global_num;
 
1031
      prev_id = cur_id;
 
1032
 
 
1033
    }
 
1034
 
 
1035
  } /* End if n_ent_recv > 0 */
 
1036
 
 
1037
  /* Partial clean-up */
 
1038
 
 
1039
  BFT_FREE(recv_order);
 
1040
  BFT_FREE(recv_sub_index);
 
1041
  BFT_FREE(recv_global_num);
 
1042
 
 
1043
  /* At this stage, block_global_num[] is valid for this process, and
 
1044
     current_global_num indicates the total number of entities handled
 
1045
     by this process; we must now shift global numberings on different
 
1046
     processes by the cumulative total number of entities handled by
 
1047
     each process */
 
1048
 
 
1049
  MPI_Scan(&current_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
 
1050
           MPI_SUM, comm);
 
1051
  global_num_shift -= current_global_num;
 
1052
 
 
1053
  for (i = 0; i < n_ent_recv; i++)
 
1054
    block_global_num[i] += global_num_shift;
 
1055
 
 
1056
  /* Return global order to all processors */
 
1057
 
 
1058
  /* Count number of values to send to each process */
 
1059
 
 
1060
  for (rank = 0; rank < size; rank++)
 
1061
    send_count[rank] = 0;
 
1062
 
 
1063
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++) {
 
1064
    rank = (global_num[index[i]] - 1) / slice_size;
 
1065
    send_count[rank] += 1;
 
1066
  }
 
1067
 
 
1068
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
1069
 
 
1070
  send_shift[0] = 0;
 
1071
  recv_shift[0] = 0;
 
1072
 
 
1073
  for (rank = 0; rank < size; rank++) {
 
1074
    send_shift[rank+1] = send_shift[rank] + send_count[rank];
 
1075
    recv_shift[rank+1] = recv_shift[rank] + recv_count[rank];
 
1076
  }
 
1077
 
 
1078
  MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
1079
                this_io_num->_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
1080
                comm);
 
1081
 
 
1082
  /* Free memory */
 
1083
 
 
1084
  BFT_FREE(block_global_num);
 
1085
  BFT_FREE(send_count);
 
1086
  BFT_FREE(recv_count);
 
1087
  BFT_FREE(send_shift);
 
1088
  BFT_FREE(recv_shift);
 
1089
 
 
1090
  /* Get final maximum global number value */
 
1091
 
 
1092
  this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
1093
}
 
1094
 
 
1095
/*----------------------------------------------------------------------------
 
1096
 * Return the global number of sub-entities associated with an initial
 
1097
 * entity whose global numbering is known, given the number of
 
1098
 * sub-entities per initial entity.
 
1099
 *
 
1100
 * parameters:
 
1101
 *   this_io_num    <-- pointer to base io numbering
 
1102
 *   n_sub_entities <-- number of sub-entities per initial entity
 
1103
 *   comm           <-- associated MPI communicator
 
1104
 *
 
1105
 * returns:
 
1106
 *   global number of sub-entities
 
1107
 *----------------------------------------------------------------------------*/
 
1108
 
 
1109
static fvm_gnum_t
 
1110
_fvm_io_num_global_sub_size(const fvm_io_num_t  *this_io_num,
 
1111
                            const fvm_lnum_t     n_sub_entities[],
 
1112
                            MPI_Comm             comm)
 
1113
{
 
1114
 
 
1115
  fvm_gnum_t  global_count, n_ent_recv, num_prev, num_cur;
 
1116
  size_t      i, slice_size;
 
1117
  int         rank;
 
1118
 
 
1119
  fvm_gnum_t  *recv_global_num = NULL;
 
1120
  fvm_gnum_t  *send_global_num = NULL;
 
1121
  fvm_lnum_t  *recv_n_sub = NULL, *recv_order = NULL;
 
1122
  int         *send_count = NULL, *recv_count = NULL;
 
1123
  int         *send_shift = NULL, *recv_shift = NULL;
 
1124
  int         have_sub_loc = 0, have_sub_glob = 0;
 
1125
 
 
1126
  int         size;
 
1127
 
 
1128
  fvm_gnum_t  current_global_num = 0;
 
1129
  fvm_gnum_t  retval = 0;
 
1130
 
 
1131
  /* Initialization */
 
1132
 
 
1133
  MPI_Comm_size(comm, &size);
 
1134
 
 
1135
  num_prev = 0;    /* true initialization later for slice 0, */
 
1136
 
 
1137
  /* Get temporary maximum global number value */
 
1138
 
 
1139
  global_count = _fvm_io_num_global_max(this_io_num, comm);
 
1140
 
 
1141
  /* slice_size = ceil(this_io_num->global_count/size) */
 
1142
 
 
1143
  slice_size = global_count / size;
 
1144
  if (global_count % size > 0)
 
1145
    slice_size += 1;
 
1146
 
 
1147
  assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
 
1148
 
 
1149
  BFT_MALLOC(send_count, size, int);
 
1150
  BFT_MALLOC(recv_count, size, int);
 
1151
 
 
1152
  BFT_MALLOC(send_shift, size, int);
 
1153
  BFT_MALLOC(recv_shift, size, int);
 
1154
 
 
1155
  /* Count number of values to send to each process */
 
1156
 
 
1157
  for (rank = 0; rank < size; rank++)
 
1158
    send_count[rank] = 0;
 
1159
 
 
1160
  for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
1161
    send_count[(this_io_num->global_num[i] - 1) / slice_size] += 1;
 
1162
 
 
1163
  MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
1164
 
 
1165
  send_shift[0] = 0;
 
1166
  recv_shift[0] = 0;
 
1167
 
 
1168
  for (rank = 1; rank < size; rank++) {
 
1169
    send_shift[rank] = send_shift[rank - 1] + send_count[rank -1];
 
1170
    recv_shift[rank] = recv_shift[rank - 1] + recv_count[rank -1];
 
1171
  }
 
1172
 
 
1173
  /* As data is sorted by increasing base global numbering, we do not
 
1174
     need to build an extra array, but only to send the correct parts
 
1175
     of the n_sub_entities[] array to the correct processors */
 
1176
 
 
1177
  n_ent_recv = recv_shift[size - 1] + recv_count[size - 1];
 
1178
 
 
1179
  BFT_MALLOC(recv_global_num, n_ent_recv, fvm_gnum_t);
 
1180
  BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
 
1181
 
 
1182
  if (this_io_num->_global_num != NULL)
 
1183
    send_global_num = this_io_num->_global_num;
 
1184
  else {
 
1185
    BFT_MALLOC(send_global_num,
 
1186
               this_io_num->global_num_size,
 
1187
               fvm_gnum_t);
 
1188
    memcpy(send_global_num,
 
1189
           this_io_num->global_num,
 
1190
           this_io_num->global_num_size * sizeof(fvm_gnum_t));
 
1191
  }
 
1192
 
 
1193
  MPI_Alltoallv(send_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
1194
                recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
 
1195
 
 
1196
  if (send_global_num != this_io_num->_global_num)
 
1197
    BFT_FREE(send_global_num);
 
1198
 
 
1199
  /* Do we have sub-entities ? */
 
1200
 
 
1201
  if (n_sub_entities != NULL)
 
1202
    have_sub_loc = 1;
 
1203
 
 
1204
  MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX, comm);
 
1205
 
 
1206
  if (have_sub_glob > 0) {
 
1207
 
 
1208
    fvm_lnum_t  *send_n_sub;
 
1209
 
 
1210
    BFT_MALLOC(send_n_sub, this_io_num->global_num_size, fvm_lnum_t);
 
1211
    BFT_MALLOC(recv_n_sub, n_ent_recv, fvm_lnum_t);
 
1212
 
 
1213
    if (n_sub_entities != NULL) {
 
1214
      for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
1215
        send_n_sub[i] = n_sub_entities[i];
 
1216
    }
 
1217
    else {
 
1218
      for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
 
1219
        send_n_sub[i] = 1;
 
1220
    }
 
1221
 
 
1222
    MPI_Alltoallv(send_n_sub, send_count, send_shift, FVM_MPI_LNUM,
 
1223
                  recv_n_sub, recv_count, recv_shift, FVM_MPI_LNUM, comm);
 
1224
 
 
1225
    BFT_FREE(send_n_sub);
 
1226
  }
 
1227
 
 
1228
  if (n_ent_recv > 0) {
 
1229
 
 
1230
    fvm_order_local_allocated(NULL,
 
1231
                              recv_global_num,
 
1232
                              recv_order,
 
1233
                              n_ent_recv);
 
1234
 
 
1235
    /* Determine global order; requires ordering to loop through buffer by
 
1236
       increasing number (slice blocks associated with each process are
 
1237
       already sorted, but the whole "gathered" slice is not).
 
1238
       We build an initial global order based on the initial global numbering,
 
1239
       such that for each slice, the global number of an entity is equal to
 
1240
       the cumulative number of sub-entities */
 
1241
 
 
1242
    current_global_num = recv_n_sub[recv_order[0]];
 
1243
    num_prev = recv_global_num[recv_order[0]];
 
1244
    recv_global_num[recv_order[0]] = current_global_num;
 
1245
 
 
1246
    for (i = 1; i < n_ent_recv; i++) {
 
1247
      num_cur = recv_global_num[recv_order[i]];
 
1248
      if (num_cur > num_prev)
 
1249
        current_global_num += recv_n_sub[recv_order[i]];
 
1250
      num_prev = num_cur;
 
1251
    }
 
1252
 
 
1253
  }
 
1254
 
 
1255
  /* Partial clean-up */
 
1256
 
 
1257
  BFT_FREE(recv_n_sub);
 
1258
  BFT_FREE(recv_order);
 
1259
  BFT_FREE(recv_global_num);
 
1260
 
 
1261
  BFT_FREE(send_count);
 
1262
  BFT_FREE(recv_count);
 
1263
  BFT_FREE(send_shift);
 
1264
  BFT_FREE(recv_shift);
 
1265
 
 
1266
  /* At this stage, current_global_num indicates the total number of
 
1267
     entities handled by this process; we must now shift global
 
1268
     numberings on different processes by the cumulative total
 
1269
     number of entities handled by each process */
 
1270
 
 
1271
  MPI_Allreduce(&current_global_num, &retval, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
1272
 
 
1273
  return retval;
 
1274
}
 
1275
 
 
1276
#endif /* defined(HAVE_MPI) */
 
1277
 
 
1278
/*----------------------------------------------------------------------------
 
1279
 * Stretch extents in some directions.
 
1280
 *
 
1281
 * If the multiplication factor for a given axis direction is less than 1,
 
1282
 * the extents in that direction will be defined so that the extent box's
 
1283
 * size in that direction is its maximum size.
 
1284
 *
 
1285
 * parameters:
 
1286
 *   extents     <-> box extents
 
1287
 *   box_to_cube <-- if 1, transform bounding box to boundign cube
 
1288
 *----------------------------------------------------------------------------*/
 
1289
 
 
1290
static void
 
1291
_adjust_extents(fvm_coord_t  extents[6],
 
1292
                int          box_to_cube)
 
1293
{
 
1294
  size_t  i;
 
1295
  fvm_coord_t max_width = 0.;
 
1296
  const double epsilon = 1e-12;
 
1297
 
 
1298
  for (i = 0; i < 3; i++) {
 
1299
    double  w = fabs(extents[i+3] - extents[i]);
 
1300
    max_width = FVM_MAX(max_width, w);
 
1301
  }
 
1302
 
 
1303
  for (i = 0; i < 3; i++) {
 
1304
    double  mult = 1.0;
 
1305
    double  m = (extents[i] + extents[i+3])*0.5;
 
1306
    double  w = fabs(extents[i+3] - extents[i]);
 
1307
    if (box_to_cube > 0) {
 
1308
      if (w > epsilon)
 
1309
        mult = max_width / w;
 
1310
    }
 
1311
    if (mult < 1.0 + epsilon)
 
1312
      mult= 1.0 + epsilon;
 
1313
    extents[i] = m - (w*0.5*mult);
 
1314
    extents[i+3] = m + (w*0.5*mult);
 
1315
  }
 
1316
}
 
1317
 
 
1318
/*----------------------------------------------------------------------------
 
1319
 * Creation of an I/O numbering structure based on coordinates.
 
1320
 *
 
1321
 * The ordering is based on a Morton code, and it is expected that
 
1322
 * entities are unique (i.e. not duplicated on 2 or more ranks).
 
1323
 * In the case that 2 entities have a same Morton code, their global
 
1324
 * number will be determined by lexicographical ordering of coordinates.
 
1325
 *
 
1326
 * parameters:
 
1327
 *   coords      <-- pointer to entity coordinates (interlaced)
 
1328
 *   dim         <-- spatial dimension
 
1329
 *   n_entities  <-- number of entities considered
 
1330
 *   box_to_cube <-- if 1, use bounding cube instead of bounding box
 
1331
 *
 
1332
 * returns:
 
1333
 *  pointer to I/O numbering structure
 
1334
 *----------------------------------------------------------------------------*/
 
1335
 
 
1336
static fvm_io_num_t *
 
1337
_create_from_coords_morton(const fvm_coord_t  coords[],
 
1338
                           int                dim,
 
1339
                           size_t             n_entities,
 
1340
                           int                box_to_cube)
 
1341
{
 
1342
  size_t i;
 
1343
  fvm_coord_t extents[6];
 
1344
  fvm_lnum_t *order = NULL;
 
1345
  fvm_morton_code_t *m_code = NULL;
 
1346
 
 
1347
#if defined(HAVE_MPI)
 
1348
  MPI_Comm comm = fvm_parall_get_mpi_comm();
 
1349
#endif
 
1350
 
 
1351
  const int level = sizeof(fvm_morton_int_t)*8 - 1;
 
1352
  const int n_ranks = fvm_parall_get_size();
 
1353
 
 
1354
  fvm_io_num_t  *this_io_num = NULL;
 
1355
 
 
1356
  /* Create structure */
 
1357
 
 
1358
  BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
1359
 
 
1360
  this_io_num->global_num_size = n_entities;
 
1361
 
 
1362
  BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
1363
  this_io_num->global_num = this_io_num->_global_num;
 
1364
 
 
1365
  /* Build Morton encoding and order it */
 
1366
 
 
1367
#if defined(HAVE_MPI)
 
1368
  fvm_morton_get_coord_extents(dim, n_entities, coords, extents, comm);
 
1369
#else
 
1370
  fvm_morton_get_coord_extents(dim, n_entities, coords, extents);
 
1371
#endif
 
1372
 
 
1373
  _adjust_extents(extents, box_to_cube);
 
1374
 
 
1375
  BFT_MALLOC(m_code, n_entities, fvm_morton_code_t);
 
1376
  BFT_MALLOC(order, n_entities, fvm_lnum_t);
 
1377
 
 
1378
  fvm_morton_encode_coords(dim, level, extents, n_entities, coords, m_code);
 
1379
 
 
1380
  fvm_morton_local_order(n_entities, m_code, order);
 
1381
 
 
1382
#if defined(HAVE_MPI)
 
1383
 
 
1384
  if (n_ranks > 1) {
 
1385
 
 
1386
    int rank_id;
 
1387
    fvm_lnum_t j, shift;
 
1388
 
 
1389
    size_t n_block_ents = 0;
 
1390
    fvm_gnum_t current_global_num = 0, global_num_shift = 0;
 
1391
    double fit = 0.;
 
1392
 
 
1393
    int *c_rank = NULL;
 
1394
    int *send_count = NULL, *send_shift = NULL;
 
1395
    int *recv_count = NULL, *recv_shift = NULL;
 
1396
    fvm_coord_t *send_coords = NULL, *recv_coords = NULL;
 
1397
    fvm_lnum_t *weight = NULL;
 
1398
    fvm_gnum_t *block_global_num = NULL, *part_global_num = NULL;
 
1399
    fvm_morton_code_t *morton_index = NULL;
 
1400
 
 
1401
    BFT_MALLOC(weight, n_entities, fvm_lnum_t);
 
1402
    BFT_MALLOC(morton_index, n_ranks + 1, fvm_morton_code_t);
 
1403
 
 
1404
    for (i = 0; i < n_entities; i++)
 
1405
      weight[i] = 1;
 
1406
 
 
1407
    fit = fvm_morton_build_rank_index(dim,
 
1408
                                      level,
 
1409
                                      n_entities,
 
1410
                                      m_code,
 
1411
                                      weight,
 
1412
                                      order,
 
1413
                                      morton_index,
 
1414
                                      comm);
 
1415
 
 
1416
    BFT_FREE(order);
 
1417
    BFT_FREE(weight);
 
1418
    BFT_MALLOC(c_rank, n_entities, int);
 
1419
 
 
1420
    for (i = 0; i < n_entities; i++)
 
1421
      c_rank[i] = fvm_morton_quantile_search(n_ranks,
 
1422
                                             m_code[i],
 
1423
                                             morton_index);
 
1424
 
 
1425
    BFT_FREE(morton_index);
 
1426
    BFT_FREE(m_code);
 
1427
 
 
1428
    /* Build send_buf, send_count and send_shift
 
1429
       to build a rank to coords indexed list */
 
1430
 
 
1431
    BFT_MALLOC(send_count, n_ranks, int);
 
1432
    BFT_MALLOC(recv_count, n_ranks, int);
 
1433
    BFT_MALLOC(send_shift, n_ranks + 1, int);
 
1434
    BFT_MALLOC(recv_shift, n_ranks + 1, int);
 
1435
 
 
1436
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1437
      send_count[rank_id] = 0;
 
1438
 
 
1439
    for (i = 0; i < n_entities; i++)
 
1440
      send_count[c_rank[i]] += dim;
 
1441
 
 
1442
    /* Exchange number of coords to send to each process */
 
1443
 
 
1444
    MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
1445
 
 
1446
    send_shift[0] = 0;
 
1447
    recv_shift[0] = 0;
 
1448
    for (rank_id = 0; rank_id < n_ranks; rank_id++) {
 
1449
      send_shift[rank_id + 1] = send_shift[rank_id] + send_count[rank_id];
 
1450
      recv_shift[rank_id + 1] = recv_shift[rank_id] + recv_count[rank_id];
 
1451
    }
 
1452
 
 
1453
    /* Build send and receive buffers */
 
1454
 
 
1455
    BFT_MALLOC(send_coords, send_shift[n_ranks], fvm_coord_t);
 
1456
 
 
1457
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1458
      send_count[rank_id] = 0;
 
1459
 
 
1460
    for (i = 0; i < n_entities; i++) {
 
1461
      rank_id = c_rank[i];
 
1462
      shift = send_shift[rank_id] + send_count[rank_id];
 
1463
      for (j = 0; j < dim; j++)
 
1464
        send_coords[shift + j] = coords[i*dim + j];
 
1465
      send_count[rank_id] += dim;
 
1466
    }
 
1467
 
 
1468
    BFT_MALLOC(recv_coords, recv_shift[n_ranks], fvm_coord_t);
 
1469
 
 
1470
    /* Exchange coords between processes */
 
1471
 
 
1472
    MPI_Alltoallv(send_coords, send_count, send_shift, FVM_MPI_COORD,
 
1473
                  recv_coords, recv_count, recv_shift, FVM_MPI_COORD,
 
1474
                  comm);
 
1475
 
 
1476
    BFT_FREE(send_coords);
 
1477
 
 
1478
    /* Now re-build Morton codes on block distribution */
 
1479
 
 
1480
    n_block_ents = recv_shift[n_ranks] / dim;
 
1481
 
 
1482
    BFT_MALLOC(m_code, n_block_ents, fvm_morton_code_t);
 
1483
    BFT_MALLOC(order, n_block_ents, fvm_lnum_t);
 
1484
 
 
1485
    fvm_morton_encode_coords(dim,
 
1486
                             level,
 
1487
                             extents,
 
1488
                             n_block_ents,
 
1489
                             recv_coords,
 
1490
                             m_code);
 
1491
 
 
1492
    fvm_morton_local_order(n_block_ents, m_code, order);
 
1493
 
 
1494
    /* Check ordering; if two entities have the same Morton codes,
 
1495
       use lexicographical coordinates ordering to ensure the
 
1496
       final order is deterministic. */
 
1497
 
 
1498
    _check_morton_ordering(dim, n_block_ents, recv_coords, m_code, order);
 
1499
 
 
1500
    /* Determine global order; requires ordering to loop through buffer by
 
1501
       increasing number (slice blocks associated with each process are
 
1502
       already sorted, but the whole "gathered" slice is not).
 
1503
       We build an initial global order based on the initial global numbering,
 
1504
       such that for each slice, the global number of an entity is equal to
 
1505
       the cumulative number of sub-entities */
 
1506
 
 
1507
    BFT_FREE(m_code);
 
1508
    BFT_FREE(recv_coords);
 
1509
    BFT_MALLOC(block_global_num, n_block_ents, fvm_gnum_t);
 
1510
 
 
1511
    for (i = 0; i < n_block_ents; i++)
 
1512
      block_global_num[order[i]] = i+1;
 
1513
 
 
1514
    BFT_FREE(order);
 
1515
 
 
1516
    current_global_num = n_block_ents;
 
1517
 
 
1518
    /* At this stage, block_global_num[] is valid for this process, and
 
1519
       current_global_num indicates the total number of entities handled
 
1520
       by this process; we must now shift global numberings on different
 
1521
       processes by the cumulative total number of entities handled by
 
1522
       each process */
 
1523
 
 
1524
    MPI_Scan(&current_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
 
1525
             MPI_SUM, comm);
 
1526
    global_num_shift -= current_global_num;
 
1527
 
 
1528
    for (i = 0; i < n_block_ents; i++)
 
1529
      block_global_num[i] += global_num_shift;
 
1530
 
 
1531
    /* Return global order to all processors */
 
1532
 
 
1533
    for (rank_id = 0; rank_id < n_ranks; rank_id++) {
 
1534
      send_count[rank_id] /= dim;
 
1535
      recv_count[rank_id] /= dim;
 
1536
      send_shift[rank_id] /= dim;
 
1537
      recv_shift[rank_id] /= dim;
 
1538
    }
 
1539
 
 
1540
    send_shift[n_ranks] /= dim;
 
1541
 
 
1542
    BFT_MALLOC(part_global_num, send_shift[n_ranks], fvm_gnum_t);
 
1543
 
 
1544
    MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
1545
                  part_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
1546
                  comm);
 
1547
 
 
1548
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1549
      send_count[rank_id] = 0;
 
1550
 
 
1551
    for (i = 0; i < n_entities; i++) {
 
1552
      rank_id = c_rank[i];
 
1553
      shift = send_shift[rank_id] + send_count[rank_id];
 
1554
      this_io_num->_global_num[i] = part_global_num[shift];
 
1555
      send_count[rank_id] += 1;
 
1556
    }
 
1557
 
 
1558
    /* Free memory */
 
1559
 
 
1560
    BFT_FREE(c_rank);
 
1561
 
 
1562
    BFT_FREE(block_global_num);
 
1563
    BFT_FREE(part_global_num);
 
1564
 
 
1565
    BFT_FREE(send_count);
 
1566
    BFT_FREE(recv_count);
 
1567
    BFT_FREE(send_shift);
 
1568
    BFT_FREE(recv_shift);
 
1569
 
 
1570
    /* Get final maximum global number value */
 
1571
 
 
1572
    this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
1573
 
 
1574
  }
 
1575
 
 
1576
#endif /* HAVE_MPI */
 
1577
 
 
1578
  if (n_ranks == 1) {
 
1579
 
 
1580
    _check_morton_ordering(dim, n_entities, coords, m_code, order);
 
1581
 
 
1582
    BFT_FREE(m_code);
 
1583
 
 
1584
    for (i = 0; i < n_entities; i++)
 
1585
      this_io_num->_global_num[order[i]] = i+1;
 
1586
 
 
1587
    BFT_FREE(order);
 
1588
 
 
1589
    this_io_num->global_count = n_entities;
 
1590
 
 
1591
  }
 
1592
 
 
1593
  return this_io_num;
 
1594
}
 
1595
 
 
1596
/*----------------------------------------------------------------------------
 
1597
 * Creation of an I/O numbering structure based on coordinates.
 
1598
 *
 
1599
 * The ordering is based on a Hilbert curve, and it is expected that
 
1600
 * entities are unique (i.e. not duplicated on 2 or more ranks).
 
1601
 * In the case that 2 entities have a same Hilbert code, their global
 
1602
 * number will be determined by lexicographical ordering of coordinates.
 
1603
 *
 
1604
 * parameters:
 
1605
 *   coords      <-- pointer to entity coordinates (interlaced)
 
1606
 *   dim         <-- spatial dimension
 
1607
 *   n_entities  <-- number of entities considered
 
1608
 *   box_to_cube <-- if 1, use bounding cube instead of bounding box
 
1609
 *
 
1610
 * returns:
 
1611
 *  pointer to I/O numbering structure
 
1612
 *----------------------------------------------------------------------------*/
 
1613
 
 
1614
static fvm_io_num_t *
 
1615
_create_from_coords_hilbert(const fvm_coord_t  coords[],
 
1616
                            int                dim,
 
1617
                            size_t             n_entities,
 
1618
                            int                box_to_cube)
 
1619
{
 
1620
  size_t i;
 
1621
  fvm_coord_t extents[6];
 
1622
  fvm_lnum_t *order = NULL;
 
1623
 
 
1624
#if defined(HAVE_MPI)
 
1625
  MPI_Comm comm = fvm_parall_get_mpi_comm();
 
1626
#endif
 
1627
 
 
1628
  const int n_ranks = fvm_parall_get_size();
 
1629
 
 
1630
  fvm_io_num_t  *this_io_num = NULL;
 
1631
 
 
1632
  /* Create structure */
 
1633
 
 
1634
  BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
1635
 
 
1636
  this_io_num->global_num_size = n_entities;
 
1637
 
 
1638
  BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
1639
  this_io_num->global_num = this_io_num->_global_num;
 
1640
 
 
1641
  /* Build Hilbert encoding and order it */
 
1642
 
 
1643
#if defined(HAVE_MPI)
 
1644
  fvm_hilbert_get_coord_extents(dim, n_entities, coords, extents, comm);
 
1645
#else
 
1646
  fvm_hilbert_get_coord_extents(dim, n_entities, coords, extents);
 
1647
#endif
 
1648
 
 
1649
  _adjust_extents(extents, box_to_cube);
 
1650
 
 
1651
  BFT_MALLOC(order, n_entities, fvm_lnum_t);
 
1652
 
 
1653
#if defined(HAVE_MPI)
 
1654
 
 
1655
  if (n_ranks > 1) {
 
1656
 
 
1657
    int rank_id;
 
1658
    fvm_lnum_t j, shift;
 
1659
 
 
1660
    size_t n_block_ents = 0;
 
1661
    fvm_gnum_t current_global_num = 0, global_num_shift = 0;
 
1662
    double fit = 0.;
 
1663
 
 
1664
    int *c_rank = NULL;
 
1665
    int *send_count = NULL, *send_shift = NULL;
 
1666
    int *recv_count = NULL, *recv_shift = NULL;
 
1667
    fvm_coord_t *send_coords = NULL, *recv_coords = NULL;
 
1668
    fvm_lnum_t *weight = NULL;
 
1669
    fvm_gnum_t *block_global_num = NULL, *part_global_num = NULL;
 
1670
    fvm_hilbert_code_t *h_code = NULL;
 
1671
    fvm_hilbert_code_t *hilbert_index = NULL;
 
1672
 
 
1673
    BFT_MALLOC(h_code, n_entities, fvm_hilbert_code_t);
 
1674
 
 
1675
    fvm_hilbert_encode_coords(dim, extents, n_entities, coords, h_code);
 
1676
 
 
1677
    fvm_hilbert_local_order(n_entities, h_code, order);
 
1678
 
 
1679
    BFT_MALLOC(weight, n_entities, fvm_lnum_t);
 
1680
    BFT_MALLOC(hilbert_index, (n_ranks + 1)*3, fvm_hilbert_code_t);
 
1681
 
 
1682
    for (i = 0; i < n_entities; i++)
 
1683
      weight[i] = 1;
 
1684
 
 
1685
    fit = fvm_hilbert_build_rank_index(dim,
 
1686
                                       n_entities,
 
1687
                                       h_code,
 
1688
                                       weight,
 
1689
                                       order,
 
1690
                                       hilbert_index,
 
1691
                                       comm);
 
1692
 
 
1693
    BFT_FREE(order);
 
1694
    BFT_FREE(weight);
 
1695
    BFT_MALLOC(c_rank, n_entities, int);
 
1696
 
 
1697
    for (i = 0; i < n_entities; i++)
 
1698
      c_rank[i] = fvm_hilbert_quantile_search(n_ranks,
 
1699
                                              h_code[i],
 
1700
                                              hilbert_index);
 
1701
 
 
1702
    BFT_FREE(hilbert_index);
 
1703
    BFT_FREE(h_code);
 
1704
 
 
1705
    /* Build send_buf, send_count and send_shift
 
1706
       to build a rank to coords indexed list */
 
1707
 
 
1708
    BFT_MALLOC(send_count, n_ranks, int);
 
1709
    BFT_MALLOC(recv_count, n_ranks, int);
 
1710
    BFT_MALLOC(send_shift, n_ranks + 1, int);
 
1711
    BFT_MALLOC(recv_shift, n_ranks + 1, int);
 
1712
 
 
1713
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1714
      send_count[rank_id] = 0;
 
1715
 
 
1716
    for (i = 0; i < n_entities; i++)
 
1717
      send_count[c_rank[i]] += dim;
 
1718
 
 
1719
    /* Exchange number of coords to send to each process */
 
1720
 
 
1721
    MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
 
1722
 
 
1723
    send_shift[0] = 0;
 
1724
    recv_shift[0] = 0;
 
1725
    for (rank_id = 0; rank_id < n_ranks; rank_id++) {
 
1726
      send_shift[rank_id + 1] = send_shift[rank_id] + send_count[rank_id];
 
1727
      recv_shift[rank_id + 1] = recv_shift[rank_id] + recv_count[rank_id];
 
1728
    }
 
1729
 
 
1730
    /* Build send and receive buffers */
 
1731
 
 
1732
    BFT_MALLOC(send_coords, send_shift[n_ranks], fvm_coord_t);
 
1733
 
 
1734
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1735
      send_count[rank_id] = 0;
 
1736
 
 
1737
    for (i = 0; i < n_entities; i++) {
 
1738
      rank_id = c_rank[i];
 
1739
      shift = send_shift[rank_id] + send_count[rank_id];
 
1740
      for (j = 0; j < dim; j++)
 
1741
        send_coords[shift + j] = coords[i*dim + j];
 
1742
      send_count[rank_id] += dim;
 
1743
    }
 
1744
 
 
1745
    BFT_MALLOC(recv_coords, recv_shift[n_ranks], fvm_coord_t);
 
1746
 
 
1747
    /* Exchange coords between processes */
 
1748
 
 
1749
    MPI_Alltoallv(send_coords, send_count, send_shift, FVM_MPI_COORD,
 
1750
                  recv_coords, recv_count, recv_shift, FVM_MPI_COORD,
 
1751
                  comm);
 
1752
 
 
1753
    BFT_FREE(send_coords);
 
1754
 
 
1755
    /* Now re-order coords on block distribution */
 
1756
 
 
1757
    n_block_ents = recv_shift[n_ranks] / dim;
 
1758
 
 
1759
    BFT_MALLOC(order, n_block_ents, fvm_lnum_t);
 
1760
 
 
1761
    fvm_hilbert_local_order_coords(dim,
 
1762
                                   extents,
 
1763
                                   n_block_ents,
 
1764
                                   recv_coords,
 
1765
                                   order);
 
1766
 
 
1767
    /* Determine global order; requires ordering to loop through buffer by
 
1768
       increasing number (slice blocks associated with each process are
 
1769
       already sorted, but the whole "gathered" slice is not).
 
1770
       We build an initial global order based on the initial global numbering,
 
1771
       such that for each slice, the global number of an entity is equal to
 
1772
       the cumulative number of sub-entities */
 
1773
 
 
1774
    BFT_FREE(recv_coords);
 
1775
    BFT_MALLOC(block_global_num, n_block_ents, fvm_gnum_t);
 
1776
 
 
1777
    for (i = 0; i < n_block_ents; i++)
 
1778
      block_global_num[order[i]] = i+1;
 
1779
 
 
1780
    BFT_FREE(order);
 
1781
 
 
1782
    current_global_num = n_block_ents;
 
1783
 
 
1784
    /* At this stage, block_global_num[] is valid for this process, and
 
1785
       current_global_num indicates the total number of entities handled
 
1786
       by this process; we must now shift global numberings on different
 
1787
       processes by the cumulative total number of entities handled by
 
1788
       each process */
 
1789
 
 
1790
    MPI_Scan(&current_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
 
1791
             MPI_SUM, comm);
 
1792
    global_num_shift -= current_global_num;
 
1793
 
 
1794
    for (i = 0; i < n_block_ents; i++)
 
1795
      block_global_num[i] += global_num_shift;
 
1796
 
 
1797
    /* Return global order to all processors */
 
1798
 
 
1799
    for (rank_id = 0; rank_id < n_ranks; rank_id++) {
 
1800
      send_count[rank_id] /= dim;
 
1801
      recv_count[rank_id] /= dim;
 
1802
      send_shift[rank_id] /= dim;
 
1803
      recv_shift[rank_id] /= dim;
 
1804
    }
 
1805
 
 
1806
    send_shift[n_ranks] /= dim;
 
1807
 
 
1808
    BFT_MALLOC(part_global_num, send_shift[n_ranks], fvm_gnum_t);
 
1809
 
 
1810
    MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
1811
                  part_global_num, send_count, send_shift, FVM_MPI_GNUM,
 
1812
                  comm);
 
1813
 
 
1814
    for (rank_id = 0; rank_id < n_ranks; rank_id++)
 
1815
      send_count[rank_id] = 0;
 
1816
 
 
1817
    for (i = 0; i < n_entities; i++) {
 
1818
      rank_id = c_rank[i];
 
1819
      shift = send_shift[rank_id] + send_count[rank_id];
 
1820
      this_io_num->_global_num[i] = part_global_num[shift];
 
1821
      send_count[rank_id] += 1;
 
1822
    }
 
1823
 
 
1824
    /* Free memory */
 
1825
 
 
1826
    BFT_FREE(c_rank);
 
1827
 
 
1828
    BFT_FREE(block_global_num);
 
1829
    BFT_FREE(part_global_num);
 
1830
 
 
1831
    BFT_FREE(send_count);
 
1832
    BFT_FREE(recv_count);
 
1833
    BFT_FREE(send_shift);
 
1834
    BFT_FREE(recv_shift);
 
1835
 
 
1836
    /* Get final maximum global number value */
 
1837
 
 
1838
    this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
 
1839
 
 
1840
  }
 
1841
 
 
1842
#endif /* HAVE_MPI */
 
1843
 
 
1844
  if (n_ranks == 1) {
 
1845
 
 
1846
    fvm_hilbert_local_order_coords(dim,
 
1847
                                   extents,
 
1848
                                   n_entities,
 
1849
                                   coords,
 
1850
                                   order);
 
1851
 
 
1852
    for (i = 0; i < n_entities; i++)
 
1853
      this_io_num->_global_num[order[i]] = i+1;
 
1854
 
 
1855
    BFT_FREE(order);
 
1856
 
 
1857
    this_io_num->global_count = n_entities;
 
1858
 
 
1859
  }
 
1860
 
 
1861
  return this_io_num;
 
1862
}
 
1863
 
 
1864
/*=============================================================================
 
1865
 * Public function definitions
 
1866
 *============================================================================*/
 
1867
 
 
1868
/*----------------------------------------------------------------------------
 
1869
 * Creation of an I/O numbering structure.
 
1870
 *
 
1871
 * The corresponding entities must be locally ordered.
 
1872
 *
 
1873
 * parameters:
 
1874
 *   parent_entity_number <-- pointer to list of selected entitie's parent's
 
1875
 *                            numbers, or NULL if all first n_ent entities
 
1876
 *                            are used
 
1877
 *   parent_global_number <-- pointer to list of global (i.e. domain splitting
 
1878
 *                            independent) parent entity numbers
 
1879
 *   n_entities           <-- number of entities considered
 
1880
 *   share_parent_global  <-- if non zero, try to share parent_global_number
 
1881
 *                            instead of using a local copy
 
1882
 *
 
1883
 * returns:
 
1884
 *  pointer to I/O numbering structure
 
1885
 *----------------------------------------------------------------------------*/
 
1886
 
 
1887
fvm_io_num_t *
 
1888
fvm_io_num_create(const fvm_lnum_t  parent_entity_number[],
 
1889
                  const fvm_gnum_t  parent_global_number[],
 
1890
                  size_t            n_entities,
 
1891
                  int               share_parent_global)
 
1892
{
 
1893
  fvm_io_num_t  *this_io_num = NULL;
 
1894
 
 
1895
  /* Initial checks */
 
1896
 
 
1897
  if (fvm_parall_get_size() < 2)
 
1898
    return NULL;
 
1899
 
 
1900
  assert(fvm_order_local_test(parent_entity_number,
 
1901
                              parent_global_number,
 
1902
                              n_entities) == true);
 
1903
 
 
1904
#if defined(HAVE_MPI)
 
1905
 
 
1906
  /* Create structure */
 
1907
 
 
1908
  BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
1909
 
 
1910
  this_io_num->global_num_size = n_entities;
 
1911
 
 
1912
  BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
1913
  this_io_num->global_num = this_io_num->_global_num;
 
1914
 
 
1915
  if (n_entities > 0) {
 
1916
 
 
1917
    size_t  i;
 
1918
 
 
1919
    /* Assign initial global numbers */
 
1920
 
 
1921
    if (parent_entity_number != NULL) {
 
1922
      for (i = 0 ; i < n_entities ; i++)
 
1923
        this_io_num->_global_num[i]
 
1924
          = parent_global_number[parent_entity_number[i]-1];
 
1925
    }
 
1926
    else {
 
1927
      for (i = 0 ; i < n_entities ; i++)
 
1928
        this_io_num->_global_num[i] = parent_global_number[i];
 
1929
    }
 
1930
 
 
1931
  }
 
1932
 
 
1933
  /* Order globally */
 
1934
 
 
1935
  this_io_num->global_count = n_entities;
 
1936
 
 
1937
  _fvm_io_num_copy_on_write(this_io_num);
 
1938
  _fvm_io_num_global_order(this_io_num,
 
1939
                           NULL,
 
1940
                           fvm_parall_get_mpi_comm());
 
1941
 
 
1942
  if (share_parent_global != 0)
 
1943
    _fvm_io_num_try_to_set_shared(this_io_num,
 
1944
                                  parent_global_number);
 
1945
 
 
1946
#endif
 
1947
 
 
1948
  return this_io_num;
 
1949
}
 
1950
 
 
1951
/*----------------------------------------------------------------------------
 
1952
 * Creation of an I/O numbering structure,
 
1953
 * sharing a given global numbering array.
 
1954
 *
 
1955
 * The corresponding entities must be locally ordered.
 
1956
 *
 
1957
 * parameters:
 
1958
 *   global_number <-- pointer to list of global (i.e. domain splitting
 
1959
 *                     independent) entity numbers
 
1960
 *   global_count  <-- global number of entities
 
1961
 *   n_entities    <-- number of local entities considered
 
1962
 *
 
1963
 * returns:
 
1964
 *  pointer to I/O numbering structure
 
1965
 *----------------------------------------------------------------------------*/
 
1966
 
 
1967
fvm_io_num_t *
 
1968
fvm_io_num_create_shared(const fvm_gnum_t  global_number[],
 
1969
                         fvm_gnum_t        global_count,
 
1970
                         size_t            n_entities)
 
1971
{
 
1972
  fvm_io_num_t  *this_io_num;
 
1973
 
 
1974
  /* Create structure */
 
1975
 
 
1976
  BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
1977
 
 
1978
  this_io_num->global_count = global_count;
 
1979
  this_io_num->global_num_size = n_entities;
 
1980
 
 
1981
  this_io_num->global_num = global_number;
 
1982
  this_io_num->_global_num = NULL;
 
1983
 
 
1984
  return this_io_num;
 
1985
}
 
1986
 
 
1987
/*----------------------------------------------------------------------------
 
1988
 * Creation of an I/O numbering structure based on an an initial
 
1989
 * I/O numbering and a number of new entities per base entity.
 
1990
 *
 
1991
 * This is useful for example to create an I/O numbering for
 
1992
 * triangles based on split polygons, whose I/O numbering is defined.
 
1993
 *
 
1994
 * parameters:
 
1995
 *   base_io_num    <-- pointer to base I/O numbering structure
 
1996
 *   n_sub_entities <-- number of new entities per base entity
 
1997
 *
 
1998
 * returns:
 
1999
 *  pointer to I/O numbering structure
 
2000
 *----------------------------------------------------------------------------*/
 
2001
 
 
2002
fvm_io_num_t *
 
2003
fvm_io_num_create_from_sub(const fvm_io_num_t  *base_io_num,
 
2004
                           const fvm_lnum_t     n_sub_entities[])
 
2005
{
 
2006
  fvm_io_num_t  *this_io_num = NULL;
 
2007
 
 
2008
  /* Initial checks */
 
2009
 
 
2010
  if (base_io_num == NULL)
 
2011
    return NULL;
 
2012
 
 
2013
  assert(fvm_parall_get_size() > 1); /* Otherwise, base_io_num should be NULL */
 
2014
 
 
2015
#if defined(HAVE_MPI)
 
2016
  {
 
2017
    fvm_lnum_t  i, n_ent;
 
2018
 
 
2019
    /* Create structure */
 
2020
 
 
2021
    BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
2022
 
 
2023
    n_ent = base_io_num->global_num_size;
 
2024
 
 
2025
    BFT_MALLOC(this_io_num->_global_num, n_ent, fvm_gnum_t);
 
2026
    this_io_num->global_num = this_io_num->_global_num;
 
2027
 
 
2028
    this_io_num->global_num_size = n_ent;
 
2029
 
 
2030
    /* Assign initial global numbers */
 
2031
 
 
2032
    for (i = 0 ; i < n_ent ; i++)
 
2033
      this_io_num->_global_num[i] = base_io_num->global_num[i];
 
2034
 
 
2035
    /* Order globally */
 
2036
 
 
2037
    this_io_num->global_count = n_ent;
 
2038
 
 
2039
    _fvm_io_num_copy_on_write(this_io_num);
 
2040
    _fvm_io_num_global_order(this_io_num,
 
2041
                             n_sub_entities,
 
2042
                             fvm_parall_get_mpi_comm());
 
2043
  }
 
2044
#endif
 
2045
 
 
2046
  return this_io_num;
 
2047
}
 
2048
 
 
2049
/*----------------------------------------------------------------------------
 
2050
 * Creation of an I/O numbering structure based on a strided adjacency.
 
2051
 *
 
2052
 * The corresponding entities must be locally ordered.
 
2053
 *
 
2054
 * parameters:
 
2055
 *   parent_entity_number <-- pointer to list of selected entitie's parent's
 
2056
 *                            numbers, or NULL if all first n_ent entities
 
2057
 *                            are used
 
2058
 *   adjacency            <-- entity adjacency (1 to n global numbering)
 
2059
 *   n_entities           <-- number of entities considered
 
2060
 *   stride               <-- values per entity
 
2061
 *
 
2062
 * returns:
 
2063
 *  pointer to I/O numbering structure
 
2064
 *----------------------------------------------------------------------------*/
 
2065
 
 
2066
fvm_io_num_t *
 
2067
fvm_io_num_create_from_adj_s(const fvm_lnum_t  parent_entity_number[],
 
2068
                             const fvm_gnum_t  adjacency[],
 
2069
                             size_t            n_entities,
 
2070
                             size_t            stride)
 
2071
{
 
2072
  fvm_io_num_t  *this_io_num = NULL;
 
2073
 
 
2074
  /* Initial checks */
 
2075
 
 
2076
  if (fvm_parall_get_size() < 2)
 
2077
    return NULL;
 
2078
 
 
2079
  assert(fvm_order_local_test_s(parent_entity_number,
 
2080
                                adjacency,
 
2081
                                stride,
 
2082
                                n_entities) == true);
 
2083
 
 
2084
#if defined(HAVE_MPI)
 
2085
  {
 
2086
    fvm_gnum_t *_adjacency = NULL;
 
2087
 
 
2088
    /* Create structure */
 
2089
 
 
2090
    BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
2091
 
 
2092
    this_io_num->global_num_size = n_entities;
 
2093
 
 
2094
    BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
2095
    this_io_num->global_num = this_io_num->_global_num;
 
2096
 
 
2097
    if (n_entities > 0) {
 
2098
 
 
2099
      size_t  i, j;
 
2100
 
 
2101
      /* Assign initial global numbers */
 
2102
 
 
2103
      BFT_MALLOC(_adjacency, n_entities*stride, fvm_gnum_t);
 
2104
 
 
2105
      if (parent_entity_number != NULL) {
 
2106
        for (i = 0 ; i < n_entities ; i++) {
 
2107
          for (j = 0; j < stride; j++)
 
2108
            _adjacency[i*stride + j]
 
2109
              = adjacency[(parent_entity_number[i]-1)*stride + j];
 
2110
        }
 
2111
      }
 
2112
      else
 
2113
        memcpy(_adjacency, adjacency, n_entities*stride*sizeof(fvm_gnum_t));
 
2114
 
 
2115
    }
 
2116
 
 
2117
    /* Order globally */
 
2118
 
 
2119
    this_io_num->global_count = n_entities;
 
2120
 
 
2121
    _fvm_io_num_global_order_s(this_io_num,
 
2122
                               stride,
 
2123
                               _adjacency,
 
2124
                               fvm_parall_get_mpi_comm());
 
2125
 
 
2126
    BFT_FREE(_adjacency);
 
2127
  }
 
2128
#endif
 
2129
 
 
2130
  return this_io_num;
 
2131
}
 
2132
 
 
2133
/*----------------------------------------------------------------------------
 
2134
 * Creation of an I/O numbering structure based on an indexed adjacency.
 
2135
 *
 
2136
 * The corresponding entities do not need to be locally ordered.
 
2137
 *
 
2138
 * parameters:
 
2139
 *  parent_entity_number <-- pointer to list of selected entitie's parent's
 
2140
 *                           numbers, or NULL if all first n_ent entities
 
2141
 *                           are used
 
2142
 *  index                <-- index on entities for adjacency
 
2143
 *  adjacency            <-- entity adjacency (1 to n global numbering)
 
2144
 *  n_entities           <-- number of entities considered
 
2145
 *
 
2146
 * returns:
 
2147
 *  pointer to I/O numbering structure
 
2148
 *----------------------------------------------------------------------------*/
 
2149
 
 
2150
fvm_io_num_t *
 
2151
fvm_io_num_create_from_adj_i(const fvm_lnum_t  parent_entity_number[],
 
2152
                             const fvm_lnum_t  index[],
 
2153
                             const fvm_gnum_t  adjacency[],
 
2154
                             fvm_lnum_t        n_entities)
 
2155
{
 
2156
  fvm_io_num_t  *this_io_num = NULL;
 
2157
 
 
2158
  /* Initial checks */
 
2159
 
 
2160
  if (fvm_parall_get_size() < 2)
 
2161
    return NULL;
 
2162
 
 
2163
#if defined(HAVE_MPI)
 
2164
  {
 
2165
    fvm_lnum_t  *_index = NULL;
 
2166
    fvm_gnum_t *_adjacency = NULL;
 
2167
 
 
2168
#if defined(DEBUG) && !defined(NDEBUG)
 
2169
    const char no_adjacent_elt_msg[]
 
2170
      = " Error during the creation of a fvm_io_num_t structure\n"
 
2171
        " for an indexed adjacency.\n\n"
 
2172
        " At least one entity has no adjacent element, and\n"
 
2173
        " this case is not currently handled.\n\n"
 
2174
        " Check if this definition is correct.";
 
2175
#endif
 
2176
 
 
2177
    /* Create structure */
 
2178
 
 
2179
    BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
2180
 
 
2181
    this_io_num->global_num_size = n_entities;
 
2182
 
 
2183
    BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
2184
    this_io_num->global_num = this_io_num->_global_num;
 
2185
 
 
2186
    if (n_entities > 0) {
 
2187
 
 
2188
      fvm_lnum_t  i, j, k, ent_id, _shift;
 
2189
 
 
2190
      /* Assign initial global numbers */
 
2191
 
 
2192
      BFT_MALLOC(_index, n_entities + 1, fvm_lnum_t);
 
2193
      _index[0] = 0;
 
2194
 
 
2195
      if (parent_entity_number != NULL) {
 
2196
 
 
2197
#if defined(DEBUG) && !defined(NDEBUG)
 
2198
        for (i = 0 ; i < n_entities ; i++) {
 
2199
          ent_id = parent_entity_number[i]-1;
 
2200
          if ((index[ent_id+1] - index[ent_id]) == 0)
 
2201
            bft_error(__FILE__, __LINE__, 0, no_adjacent_elt_msg);
 
2202
        }
 
2203
#endif
 
2204
 
 
2205
        /* Count reduced size */
 
2206
 
 
2207
        for (i = 0 ; i < n_entities ; i++) {
 
2208
          ent_id = parent_entity_number[i]-1;
 
2209
          _index[i+1] = index[ent_id+1] - index[ent_id];
 
2210
        }
 
2211
 
 
2212
        for (i = 0 ; i < n_entities ; i++)
 
2213
          _index[i+1] += _index[i];
 
2214
 
 
2215
        BFT_MALLOC(_adjacency, _index[n_entities], fvm_gnum_t);
 
2216
 
 
2217
        /* Define reduced index and adjacency */
 
2218
 
 
2219
        for (i = 0 ; i < n_entities ; i++) {
 
2220
 
 
2221
          ent_id = parent_entity_number[i]-1;
 
2222
          _shift = _index[i];
 
2223
 
 
2224
          for (j = index[ent_id], k = 0; j < index[ent_id+1]; j++, k++)
 
2225
            _adjacency[_shift + k] = adjacency[j];
 
2226
 
 
2227
        }
 
2228
 
 
2229
      }
 
2230
      else {
 
2231
 
 
2232
#if defined(DEBUG) && !defined(NDEBUG)
 
2233
        for (i = 0 ; i < n_entities ; i++) {
 
2234
          if ((index[i+1] - index[i]) == 0)
 
2235
            bft_error(__FILE__, __LINE__, 0, no_adjacent_elt_msg);
 
2236
        }
 
2237
#endif
 
2238
 
 
2239
        BFT_MALLOC(_adjacency, index[n_entities], fvm_gnum_t);
 
2240
 
 
2241
        memcpy(_index, index, (n_entities+1)*sizeof(fvm_lnum_t));
 
2242
        memcpy(_adjacency, adjacency, index[n_entities]*sizeof(fvm_gnum_t));
 
2243
 
 
2244
      }
 
2245
 
 
2246
    }
 
2247
 
 
2248
    /* Order globally */
 
2249
 
 
2250
    this_io_num->global_count = n_entities;
 
2251
 
 
2252
    _fvm_io_num_global_order_index(this_io_num,
 
2253
                                   _index,
 
2254
                                   _adjacency,
 
2255
                                   fvm_parall_get_mpi_comm());
 
2256
 
 
2257
    if (_adjacency != NULL)
 
2258
      BFT_FREE(_adjacency);
 
2259
    if (_index != NULL)
 
2260
      BFT_FREE(_index);
 
2261
  }
 
2262
#endif
 
2263
 
 
2264
  return this_io_num;
 
2265
}
 
2266
 
 
2267
/*----------------------------------------------------------------------------
 
2268
 * Creation of an I/O numbering structure based on a space-filling curve.
 
2269
 *
 
2270
 * It is expected that entities are unique (i.e. not duplicated on 2 or
 
2271
 * more ranks). If 2 entities have a same Morton codeor Hilbert, their global
 
2272
 * number will be determined by lexicographical ordering of coordinates.
 
2273
 *
 
2274
 * parameters:
 
2275
 *   coords     <-- pointer to entity coordinates (interlaced)
 
2276
 *   dim        <-- spatial dimension
 
2277
 *   n_entities <-- number of entities considered
 
2278
 *   sfc_type   <-- type of space-filling curve (Morton or Hilbert)
 
2279
 *
 
2280
 * returns:
 
2281
 *  pointer to I/O numbering structure
 
2282
 *----------------------------------------------------------------------------*/
 
2283
 
 
2284
fvm_io_num_t *
 
2285
fvm_io_num_create_from_sfc(const fvm_coord_t  coords[],
 
2286
                           int                dim,
 
2287
                           size_t             n_entities,
 
2288
                           fvm_io_num_sfc_t   sfc_type)
 
2289
{
 
2290
  fvm_io_num_t  *this_io_num = NULL;
 
2291
 
 
2292
  switch(sfc_type) {
 
2293
  case FVM_IO_NUM_SFC_MORTON_BOX:
 
2294
    this_io_num = _create_from_coords_morton(coords, dim, n_entities, 0);
 
2295
    break;
 
2296
  case FVM_IO_NUM_SFC_MORTON_CUBE:
 
2297
    this_io_num = _create_from_coords_morton(coords, dim, n_entities, 1);
 
2298
    break;
 
2299
  case FVM_IO_NUM_SFC_HILBERT_BOX:
 
2300
    this_io_num = _create_from_coords_hilbert(coords, dim, n_entities, 0);
 
2301
    break;
 
2302
  case FVM_IO_NUM_SFC_HILBERT_CUBE:
 
2303
    this_io_num = _create_from_coords_hilbert(coords, dim, n_entities, 1);
 
2304
    break;
 
2305
  default:
 
2306
    assert(0);
 
2307
  }
 
2308
 
 
2309
  return this_io_num;
 
2310
}
 
2311
 
 
2312
/*----------------------------------------------------------------------------
 
2313
 * Creation of an I/O numbering structure based on a simple accumulation
 
2314
 * (i.e. scan) of counts on successive ranks.
 
2315
 *
 
2316
 * parameters:
 
2317
 *   n_entities <-- number of entities considered
 
2318
 *
 
2319
 * returns:
 
2320
 *  pointer to I/O numbering structure
 
2321
 *----------------------------------------------------------------------------*/
 
2322
 
 
2323
fvm_io_num_t *
 
2324
fvm_io_num_create_from_scan(size_t  n_entities)
 
2325
{
 
2326
  fvm_io_num_t  *this_io_num = NULL;
 
2327
 
 
2328
  /* Initial checks */
 
2329
 
 
2330
  if (fvm_parall_get_size() < 2)
 
2331
    return NULL;
 
2332
 
 
2333
#if defined(HAVE_MPI)
 
2334
  {
 
2335
    size_t  i;
 
2336
    fvm_gnum_t gnum_base = n_entities;
 
2337
    fvm_gnum_t gnum_sum = n_entities;
 
2338
    fvm_gnum_t gnum_shift = 0;
 
2339
 
 
2340
    MPI_Comm comm = fvm_parall_get_mpi_comm();
 
2341
 
 
2342
    /* Create structure */
 
2343
 
 
2344
    BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
 
2345
 
 
2346
    BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
 
2347
    this_io_num->global_num = this_io_num->_global_num;
 
2348
 
 
2349
    this_io_num->global_num_size = n_entities;
 
2350
 
 
2351
    MPI_Scan(&gnum_base, &gnum_shift, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
2352
 
 
2353
    gnum_base = gnum_shift - gnum_base + 1;
 
2354
 
 
2355
    for (i = 0; i < n_entities; i++)
 
2356
      this_io_num->_global_num[i] = gnum_base + i;
 
2357
 
 
2358
    gnum_base = n_entities;
 
2359
 
 
2360
    MPI_Allreduce(&gnum_base, &gnum_sum, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
2361
 
 
2362
    this_io_num->global_count = gnum_sum;
 
2363
  }
 
2364
#endif
 
2365
 
 
2366
  return this_io_num;
 
2367
}
 
2368
 
 
2369
/*----------------------------------------------------------------------------
 
2370
 * Destruction of a I/O numbering structure.
 
2371
 *
 
2372
 * parameters:
 
2373
 *   this_io_num <-- pointer to structure that should be destroyed
 
2374
 *
 
2375
 * returns:
 
2376
 *   NULL pointer
 
2377
 *----------------------------------------------------------------------------*/
 
2378
 
 
2379
fvm_io_num_t *
 
2380
fvm_io_num_destroy(fvm_io_num_t  * this_io_num)
 
2381
{
 
2382
  if (this_io_num != NULL) {
 
2383
    BFT_FREE(this_io_num->_global_num);
 
2384
    BFT_FREE(this_io_num);
 
2385
  }
 
2386
 
 
2387
  return this_io_num;
 
2388
}
 
2389
 
 
2390
/*----------------------------------------------------------------------------
 
2391
 * Return local number of entities associated with an I/O numbering
 
2392
 * structure.
 
2393
 *
 
2394
 * parameters:
 
2395
 *   this_io_num <-- pointer to I/O/ numbering structure
 
2396
 *
 
2397
 * returns:
 
2398
 *  local number of associated entities
 
2399
 *----------------------------------------------------------------------------*/
 
2400
 
 
2401
fvm_lnum_t
 
2402
fvm_io_num_get_local_count(const fvm_io_num_t  *const this_io_num)
 
2403
{
 
2404
  assert(this_io_num != NULL);
 
2405
 
 
2406
  return this_io_num->global_num_size;
 
2407
}
 
2408
 
 
2409
/*----------------------------------------------------------------------------
 
2410
 * Return global number of entities associated with an I/O numbering
 
2411
 * structure.
 
2412
 *
 
2413
 * parameters:
 
2414
 *   this_io_num <-- pointer to I/O/ numbering structure
 
2415
 *
 
2416
 * returns:
 
2417
 *  global number of associated entities
 
2418
 *----------------------------------------------------------------------------*/
 
2419
 
 
2420
fvm_gnum_t
 
2421
fvm_io_num_get_global_count(const fvm_io_num_t  *const this_io_num)
 
2422
{
 
2423
  assert(this_io_num != NULL);
 
2424
 
 
2425
  return this_io_num->global_count;
 
2426
}
 
2427
 
 
2428
/*----------------------------------------------------------------------------
 
2429
 * Return global numbering associated with an I/O numbering structure.
 
2430
 *
 
2431
 * parameters:
 
2432
 *   this_io_num <-- pointer to I/O/ numbering structure
 
2433
 *
 
2434
 * returns:
 
2435
 *  pointer to array of global numbers associated with local entities
 
2436
 *  (1 to n numbering)
 
2437
 *----------------------------------------------------------------------------*/
 
2438
 
 
2439
const fvm_gnum_t *
 
2440
fvm_io_num_get_global_num(const fvm_io_num_t  *const this_io_num)
 
2441
{
 
2442
  assert(this_io_num != NULL);
 
2443
 
 
2444
  return this_io_num->global_num;
 
2445
}
 
2446
 
 
2447
/*----------------------------------------------------------------------------
 
2448
 * Return the global number of sub-entities associated with an initial
 
2449
 * entity whose global numbering is known, given the number of
 
2450
 * sub-entities per initial entity.
 
2451
 *
 
2452
 * parameters:
 
2453
 *   this_io_num    <-> pointer to base io numbering
 
2454
 *   n_sub_entities <-- number of sub-entities per initial entity
 
2455
 *   comm           <-- associated MPI communicator
 
2456
 *
 
2457
 * returns:
 
2458
 *   global number of sub-entities
 
2459
 *----------------------------------------------------------------------------*/
 
2460
 
 
2461
fvm_gnum_t
 
2462
fvm_io_num_global_sub_size(const fvm_io_num_t  *this_io_num,
 
2463
                           const fvm_lnum_t     n_sub_entities[])
 
2464
{
 
2465
  fvm_gnum_t  retval = 0;
 
2466
 
 
2467
  /* Initial checks */
 
2468
 
 
2469
  if (this_io_num == NULL)
 
2470
    return retval;
 
2471
 
 
2472
  assert(fvm_parall_get_size() > 1); /* Otherwise, base_io_num should be NULL */
 
2473
 
 
2474
#if defined(HAVE_MPI)
 
2475
 {
 
2476
   int  have_sub_loc = 0, have_sub_glob = 0;
 
2477
 
 
2478
   /* Caution: we may have sub-entities on some ranks and not on others */
 
2479
 
 
2480
   if (n_sub_entities != NULL)
 
2481
     have_sub_loc = 1;
 
2482
 
 
2483
   MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX,
 
2484
                 fvm_parall_get_mpi_comm());
 
2485
 
 
2486
   if (have_sub_glob > 0)
 
2487
     retval = _fvm_io_num_global_sub_size(this_io_num,
 
2488
                                          n_sub_entities,
 
2489
                                          fvm_parall_get_mpi_comm());
 
2490
 }
 
2491
#endif
 
2492
 
 
2493
  return retval;
 
2494
}
 
2495
 
 
2496
/*----------------------------------------------------------------------------
 
2497
 * Dump printout of a I/O numbering structure.
 
2498
 *
 
2499
 * parameters:
 
2500
 *   this_io_num <-- pointer to structure that should be dumped
 
2501
 *----------------------------------------------------------------------------*/
 
2502
 
 
2503
void
 
2504
fvm_io_num_dump(const fvm_io_num_t  *const this_io_num)
 
2505
{
 
2506
  fvm_lnum_t i;
 
2507
 
 
2508
  if (this_io_num == NULL) {
 
2509
    bft_printf("  global numbering: nil\n");
 
2510
    return;
 
2511
  }
 
2512
 
 
2513
  bft_printf("  global numbering size:            %u\n",
 
2514
             (unsigned)this_io_num->global_num_size);
 
2515
 
 
2516
  bft_printf("\n"
 
2517
             "  pointer to shareable array:\n"
 
2518
             "    global_num:                     %p\n",
 
2519
             this_io_num->global_num);
 
2520
 
 
2521
  bft_printf("\n"
 
2522
             "  pointer to local array:\n"
 
2523
             "    _global_num:                    %p\n",
 
2524
             this_io_num->global_num);
 
2525
 
 
2526
  if (this_io_num->global_num_size > 0) {
 
2527
 
 
2528
    bft_printf("\n  global number:\n\n");
 
2529
    for (i = 0 ; i < this_io_num->global_num_size ; i++)
 
2530
      bft_printf("  %10u : %10llu\n",
 
2531
                 (unsigned)i + 1,
 
2532
                 (unsigned long long)this_io_num->global_num[i]);
 
2533
  }
 
2534
}
 
2535
 
 
2536
/*----------------------------------------------------------------------------*/
 
2537
 
 
2538
#ifdef __cplusplus
 
2539
}
 
2540
#endif /* __cplusplus */