1
/*============================================================================
2
* Main structure for an I/O numbering scheme associated with mesh entities
3
* (such as cells, faces, and vertices);
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.
9
* Only the case where p = 1 is presently implemented, so the numbering
10
* scheme is simply based on entity's global labels.
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
*============================================================================*/
19
This file is part of Code_Saturne, a general-purpose CFD tool.
21
Copyright (C) 1998-2011 EDF S.A.
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
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
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.
38
/*----------------------------------------------------------------------------*/
40
#if defined(HAVE_CONFIG_H)
41
#include "cs_config.h"
44
/*----------------------------------------------------------------------------
45
* Standard C library headers
46
*----------------------------------------------------------------------------*/
53
/*----------------------------------------------------------------------------
55
*----------------------------------------------------------------------------*/
58
#include <bft_printf.h>
60
/*----------------------------------------------------------------------------
62
*----------------------------------------------------------------------------*/
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"
71
/*----------------------------------------------------------------------------
72
* Header for the current file
73
*----------------------------------------------------------------------------*/
75
#include "fvm_io_num.h"
77
/*----------------------------------------------------------------------------*/
82
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
84
#endif /* __cplusplus */
86
/*============================================================================
87
* Local structure definitions
88
*============================================================================*/
90
/*----------------------------------------------------------------------------
91
* Structure defining an I/O numbering scheme
92
*----------------------------------------------------------------------------*/
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.
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.
124
struct _fvm_io_num_t {
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
130
fvm_gnum_t *_global_num; /* Global entity numbers if owner,
135
/*=============================================================================
136
* Static global variables
137
*============================================================================*/
139
/* Names of space-filling curve types */
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)")};
146
/*=============================================================================
147
* Private function definitions
148
*============================================================================*/
150
/*----------------------------------------------------------------------------
151
* Use bubble sort on an expectedly short sequence of coordinates
152
* to ensure lexicographical ordering.
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
*----------------------------------------------------------------------------*/
164
_reorder_coords_lexicographic(int dim,
167
const fvm_coord_t coords[],
177
for (i = start_id + 1; i < end_id; i++) {
179
size_t j_prev = order[i-1], j = order[i];
180
_Bool l_swap = false;
183
if (coords[j_prev*3] < coords[j*3])
185
else if (coords[j_prev*3] > coords[j*3])
187
else if (coords[j_prev*3 + 1] < coords[j*3 + 1])
189
else if ( coords[j_prev*3 + 1] > coords[j*3 + 1]
190
|| coords[j_prev*3 + 2] > coords[j*3 + 2])
194
if (coords[j_prev*2] < coords[j*2 + 1])
196
else if ( coords[j_prev*2] > coords[j*2]
197
|| coords[j_prev*2 + 1] > coords[j*2 + 1])
200
else { /* if (dim == 1) */
201
if (coords[j_prev] > coords[j])
206
fvm_lnum_t o_save = order[i-1];
207
order[i-1] = order[i];
216
/*----------------------------------------------------------------------------
217
* Creation of an I/O numbering structure based on coordinates.
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.
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
233
* pointer to I/O numbering structure
234
*----------------------------------------------------------------------------*/
237
_check_morton_ordering(int dim,
239
const fvm_coord_t coords[],
240
const fvm_morton_code_t m_code[],
243
size_t i_prev = 0, i = 1;
248
/* Check ordering; if two entities have the same Morton codes,
249
use lexicographical coordinates ordering to ensure the
250
final order is deterministic. */
252
for (i = 1; i < n_entities; i++) {
254
size_t j_prev = order[i_prev], j = order[i];
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]) {
260
/* If successive values have the same Morton code,
261
order them lexicographically */
263
_reorder_coords_lexicographic(dim, i_prev, i-1, coords, order);
269
if (i_prev < n_entities - 1)
270
_reorder_coords_lexicographic(dim, i_prev, n_entities - 1, coords, order);
273
#if defined(HAVE_MPI)
275
/*----------------------------------------------------------------------------
276
* Copy selected shared global ordering information to private ordering
277
* information for an I/O numbering structure.
280
* this_io_num <-- pointer to numbering structure
281
*----------------------------------------------------------------------------*/
284
_fvm_io_num_copy_on_write(fvm_io_num_t *const this_io_num)
286
if (this_io_num->_global_num == NULL) {
288
BFT_MALLOC(this_io_num->_global_num,
289
this_io_num->global_num_size,
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;
295
assert(this_io_num->global_num == this_io_num->_global_num);
298
/*----------------------------------------------------------------------------
299
* Copy selected shared global ordering information to private ordering
300
* information for an I/O numbering structure.
303
* this_io_num <-> pointer to numbering structure
304
* parent_global_number <-- pointer to shared list of global parent
306
*----------------------------------------------------------------------------*/
309
_fvm_io_num_try_to_set_shared(fvm_io_num_t *const this_io_num,
310
const fvm_gnum_t parent_global_number[])
312
if (this_io_num->_global_num != NULL && parent_global_number != NULL) {
314
for (i = 0; i < this_io_num->global_num_size; i++)
315
if (this_io_num->_global_num[i] != parent_global_number[i])
317
if (i < this_io_num->global_num_size)
318
this_io_num->global_num = this_io_num->_global_num;
320
this_io_num->global_num = parent_global_number;
321
BFT_FREE(this_io_num->_global_num);
326
/*----------------------------------------------------------------------------
327
* Maximum global number associated with an I/O numbering structure
330
* this_io_num <-- pointer to partially initialized I/O numbering structure.
331
* comm <-- associated MPI communicator
334
* maximum global number associated with the I/O numbering
335
*----------------------------------------------------------------------------*/
338
_fvm_io_num_global_max(const fvm_io_num_t *const this_io_num,
341
fvm_gnum_t local_max, global_max;
344
/* Get maximum global number value */
346
n_ent = this_io_num->global_num_size;
348
local_max = this_io_num->global_num[n_ent - 1];
352
MPI_Allreduce(&local_max, &global_max, 1, FVM_MPI_GNUM, MPI_MAX, comm);
357
/*----------------------------------------------------------------------------
358
* Global ordering associated with an I/O numbering structure.
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.
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.
369
* this_io_num <-> pointer to structure that should be ordered
370
* n_sub_entities <-- optional number of sub-entities per initial entity,
372
* comm <-- associated MPI communicator
373
*----------------------------------------------------------------------------*/
376
_fvm_io_num_global_order(fvm_io_num_t *this_io_num,
377
const fvm_lnum_t n_sub_entities[],
381
fvm_gnum_t n_ent_recv, num_prev, num_cur;
382
size_t i, j, slice_size;
386
_Bool may_be_shared = false;
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;
394
int local_rank, size;
396
fvm_gnum_t current_global_num = 0, global_num_shift = 0;
400
MPI_Comm_rank(comm, &local_rank);
401
MPI_Comm_size(comm, &size);
403
num_prev = 0; /* true initialization later for slice 0, */
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) */
408
if (this_io_num->global_num != this_io_num->_global_num)
409
may_be_shared = true;
411
may_be_shared = false;
413
/* Get temporary maximum global number value */
415
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
417
/* slice_size = ceil(this_io_num->global_count/size) */
419
slice_size = this_io_num->global_count / size;
420
if (this_io_num->global_count % size > 0)
423
assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
425
BFT_MALLOC(send_count, size, int);
426
BFT_MALLOC(recv_count, size, int);
428
BFT_MALLOC(send_shift, size, int);
429
BFT_MALLOC(recv_shift, size, int);
431
/* Count number of values to send to each process */
433
for (rank = 0; rank < size; rank++)
434
send_count[rank] = 0;
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;
439
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
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 */
453
n_ent_recv = recv_shift[size - 1] + recv_count[size - 1];
455
BFT_MALLOC(recv_global_num, n_ent_recv, fvm_gnum_t);
456
BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
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);
461
/* Do we have sub-entities ? */
463
if (n_sub_entities != NULL)
466
MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX, comm);
468
if (have_sub_glob > 0) {
470
fvm_lnum_t *send_n_sub;
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);
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];
480
for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
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);
487
BFT_FREE(send_n_sub);
490
if (n_ent_recv > 0) {
492
fvm_order_local_allocated(NULL,
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 */
504
if (have_sub_glob > 0) {
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;
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;
519
else { /* if (have_sub_glob == 0) */
521
current_global_num = 1;
522
num_prev = recv_global_num[recv_order[0]];
523
recv_global_num[recv_order[0]] = current_global_num;
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;
537
/* Partial clean-up */
539
BFT_FREE(recv_n_sub);
540
BFT_FREE(recv_order);
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
548
MPI_Scan(¤t_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
550
global_num_shift -= current_global_num;
552
for (i = 0; i < n_ent_recv; i++)
553
recv_global_num[i] += global_num_shift;
555
/* Return global order to all processors */
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,
563
BFT_FREE(recv_global_num);
565
BFT_FREE(send_count);
566
BFT_FREE(recv_count);
567
BFT_FREE(send_shift);
568
BFT_FREE(recv_shift);
570
/* Get final maximum global number value */
572
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
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 */
578
if (n_sub_entities != NULL) {
580
fvm_gnum_t *_global_num;
582
for (i = 0, j = 0; i < (size_t)(this_io_num->global_num_size); i++)
583
j += n_sub_entities[i];
585
BFT_MALLOC(_global_num, j, fvm_gnum_t);
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;
592
BFT_FREE(this_io_num->_global_num);
593
this_io_num->_global_num = _global_num;
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;
600
if (may_be_shared == false)
601
this_io_num->global_num = this_io_num->_global_num;
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) */
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])
611
if (i < (size_t)(this_io_num->global_num_size))
612
this_io_num->global_num = this_io_num->_global_num;
614
BFT_FREE(this_io_num->_global_num);
618
/*----------------------------------------------------------------------------
619
* Global ordering associated with an I/O numbering structure.
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.
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
*----------------------------------------------------------------------------*/
633
_fvm_io_num_global_order_s(fvm_io_num_t *this_io_num,
635
fvm_gnum_t global_num[],
638
fvm_gnum_t n_ent_recv;
639
size_t i, j, slice_size;
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;
647
int local_rank, size;
649
fvm_gnum_t current_global_num = 0, global_num_shift = 0;
653
MPI_Comm_rank(comm, &local_rank);
654
MPI_Comm_size(comm, &size);
656
/* Get maximum global number value for first value of each series
657
(does not need to be exact, simply used to define blocks) */
660
fvm_gnum_t local_max = 0, global_max = 0;
661
size_t n_ent = this_io_num->global_num_size;
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;
669
/* slice_size = ceil(this_io_num->global_count/size) */
671
slice_size = this_io_num->global_count / size;
672
if (this_io_num->global_count % size > 0)
675
assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
677
BFT_MALLOC(send_count, size, int);
678
BFT_MALLOC(recv_count, size, int);
680
BFT_MALLOC(send_shift, size, int);
681
BFT_MALLOC(recv_shift, size, int);
683
/* Count number of values to send to each process */
685
for (rank = 0; rank < size; rank++)
686
send_count[rank] = 0;
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;
691
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
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 */
705
n_ent_recv = (recv_shift[size - 1] + recv_count[size - 1]) / stride;
707
BFT_MALLOC(recv_global_num, stride*n_ent_recv, fvm_gnum_t);
708
BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
710
MPI_Alltoallv(global_num, send_count, send_shift, FVM_MPI_GNUM,
711
recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
713
if (n_ent_recv > 0) {
715
size_t prev_id, cur_id;
717
fvm_order_local_allocated_s(NULL,
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 */
730
BFT_MALLOC(block_global_num, n_ent_recv, fvm_gnum_t);
732
current_global_num = 1;
733
prev_id = recv_order[0];
734
block_global_num[recv_order[0]] = current_global_num;
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;
744
if (greater_than_prev)
745
current_global_num += 1;
746
block_global_num[recv_order[i]] = current_global_num;
752
/* Partial clean-up */
754
BFT_FREE(recv_order);
755
BFT_FREE(recv_global_num);
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
763
MPI_Scan(¤t_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
765
global_num_shift -= current_global_num;
767
for (i = 0; i < n_ent_recv; i++)
768
block_global_num[i] += global_num_shift;
770
/* Return global order to all processors */
772
for (rank = 0; rank < size; rank++) {
773
send_count[rank] /= stride;
774
recv_count[rank] /= stride;
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];
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,
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);
794
/* Get final maximum global number value */
796
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
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.
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)
812
*----------------------------------------------------------------------------*/
815
_indexed_is_greater(size_t i1,
817
const fvm_lnum_t index[],
818
const fvm_gnum_t number[])
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;
827
for (i = 0; i < s2; i++) {
828
if (number[i1_s + i] > number[i2_s + i])
830
else if (number[i1_s + i] < number[i2_s + i])
836
else { /* s1 <= s2 */
838
for (i = 0; i < s1; i++) {
839
if (number[i1_s + i] > number[i2_s + i])
841
else if (number[i1_s + i] < number[i2_s + i])
850
/*----------------------------------------------------------------------------
851
* Global indexed ordering associated with an I/O numbering structure.
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.
858
* this_io_num <-> pointer to structure that should be ordered
859
* index <-- index on entities for global_num[]
861
* comm <-- associated MPI communicator
862
*----------------------------------------------------------------------------*/
865
_fvm_io_num_global_order_index(fvm_io_num_t *this_io_num,
867
fvm_gnum_t global_num[],
870
int rank, local_rank, size;
871
size_t i, shift, slice_size;
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;
883
MPI_Comm_rank(comm, &local_rank);
884
MPI_Comm_size(comm, &size);
886
/* Get maximum global number value for first value of each series
887
(does not need to be exact, simply used to define blocks) */
890
fvm_gnum_t local_max = 0, global_max = 0;
891
size_t n_ent = this_io_num->global_num_size;
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;
899
/* slice_size = ceil(this_io_num->global_count/size) */
901
slice_size = this_io_num->global_count / size;
902
if (this_io_num->global_count % size > 0)
905
/* Build for each slice, a new ordered indexed list from the received
908
assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
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);
915
/* Count number of values to send to each process */
917
for (rank = 0; rank < size; rank++)
918
send_count[rank] = 0;
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;
925
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
937
n_ent_recv = recv_shift[size];
938
n_ent_send = send_shift[size];
940
BFT_MALLOC(recv_sub_count, n_ent_recv, fvm_lnum_t);
941
BFT_MALLOC(send_sub_count, n_ent_send, fvm_lnum_t);
943
assert(n_ent_send == (fvm_gnum_t)this_io_num->global_num_size);
945
for (rank = 0; rank < size; rank++)
946
send_count[rank] = 0;
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;
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);
958
BFT_MALLOC(recv_sub_index, n_ent_recv + 1, fvm_lnum_t);
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];
964
BFT_FREE(send_sub_count);
965
BFT_FREE(recv_sub_count);
967
/* Get recv_global_num */
969
/* Count number of values to send to each process */
971
for (rank = 0; rank < size; rank++)
972
send_count[rank] = 0;
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];
979
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
989
BFT_MALLOC(recv_global_num, recv_sub_index[n_ent_recv], fvm_gnum_t);
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 */
995
MPI_Alltoallv(global_num, send_count, send_shift, FVM_MPI_GNUM,
996
recv_global_num, recv_count, recv_shift, FVM_MPI_GNUM, comm);
998
if (n_ent_recv > 0) { /* Order received elements of the indexed list */
1000
size_t prev_id, cur_id;
1002
BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
1004
fvm_order_local_allocated_i(NULL,
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 */
1017
BFT_MALLOC(block_global_num, n_ent_recv, fvm_gnum_t);
1019
current_global_num = 1;
1020
prev_id = recv_order[0];
1021
block_global_num[recv_order[0]] = current_global_num;
1023
for (i = 1; i < n_ent_recv; i++) {
1025
cur_id = recv_order[i];
1027
if (_indexed_is_greater(cur_id, prev_id, recv_sub_index, recv_global_num))
1028
current_global_num += 1;
1030
block_global_num[recv_order[i]] = current_global_num;
1035
} /* End if n_ent_recv > 0 */
1037
/* Partial clean-up */
1039
BFT_FREE(recv_order);
1040
BFT_FREE(recv_sub_index);
1041
BFT_FREE(recv_global_num);
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
1049
MPI_Scan(¤t_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
1051
global_num_shift -= current_global_num;
1053
for (i = 0; i < n_ent_recv; i++)
1054
block_global_num[i] += global_num_shift;
1056
/* Return global order to all processors */
1058
/* Count number of values to send to each process */
1060
for (rank = 0; rank < size; rank++)
1061
send_count[rank] = 0;
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;
1068
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
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,
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);
1090
/* Get final maximum global number value */
1092
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
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.
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
1106
* global number of sub-entities
1107
*----------------------------------------------------------------------------*/
1110
_fvm_io_num_global_sub_size(const fvm_io_num_t *this_io_num,
1111
const fvm_lnum_t n_sub_entities[],
1115
fvm_gnum_t global_count, n_ent_recv, num_prev, num_cur;
1116
size_t i, slice_size;
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;
1128
fvm_gnum_t current_global_num = 0;
1129
fvm_gnum_t retval = 0;
1131
/* Initialization */
1133
MPI_Comm_size(comm, &size);
1135
num_prev = 0; /* true initialization later for slice 0, */
1137
/* Get temporary maximum global number value */
1139
global_count = _fvm_io_num_global_max(this_io_num, comm);
1141
/* slice_size = ceil(this_io_num->global_count/size) */
1143
slice_size = global_count / size;
1144
if (global_count % size > 0)
1147
assert(sizeof(fvm_gnum_t) >= sizeof(fvm_lnum_t));
1149
BFT_MALLOC(send_count, size, int);
1150
BFT_MALLOC(recv_count, size, int);
1152
BFT_MALLOC(send_shift, size, int);
1153
BFT_MALLOC(recv_shift, size, int);
1155
/* Count number of values to send to each process */
1157
for (rank = 0; rank < size; rank++)
1158
send_count[rank] = 0;
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;
1163
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
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 */
1177
n_ent_recv = recv_shift[size - 1] + recv_count[size - 1];
1179
BFT_MALLOC(recv_global_num, n_ent_recv, fvm_gnum_t);
1180
BFT_MALLOC(recv_order, n_ent_recv, fvm_lnum_t);
1182
if (this_io_num->_global_num != NULL)
1183
send_global_num = this_io_num->_global_num;
1185
BFT_MALLOC(send_global_num,
1186
this_io_num->global_num_size,
1188
memcpy(send_global_num,
1189
this_io_num->global_num,
1190
this_io_num->global_num_size * sizeof(fvm_gnum_t));
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);
1196
if (send_global_num != this_io_num->_global_num)
1197
BFT_FREE(send_global_num);
1199
/* Do we have sub-entities ? */
1201
if (n_sub_entities != NULL)
1204
MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX, comm);
1206
if (have_sub_glob > 0) {
1208
fvm_lnum_t *send_n_sub;
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);
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];
1218
for (i = 0; i < (size_t)(this_io_num->global_num_size); i++)
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);
1225
BFT_FREE(send_n_sub);
1228
if (n_ent_recv > 0) {
1230
fvm_order_local_allocated(NULL,
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 */
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;
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]];
1255
/* Partial clean-up */
1257
BFT_FREE(recv_n_sub);
1258
BFT_FREE(recv_order);
1259
BFT_FREE(recv_global_num);
1261
BFT_FREE(send_count);
1262
BFT_FREE(recv_count);
1263
BFT_FREE(send_shift);
1264
BFT_FREE(recv_shift);
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 */
1271
MPI_Allreduce(¤t_global_num, &retval, 1, FVM_MPI_GNUM, MPI_SUM, comm);
1276
#endif /* defined(HAVE_MPI) */
1278
/*----------------------------------------------------------------------------
1279
* Stretch extents in some directions.
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.
1286
* extents <-> box extents
1287
* box_to_cube <-- if 1, transform bounding box to boundign cube
1288
*----------------------------------------------------------------------------*/
1291
_adjust_extents(fvm_coord_t extents[6],
1295
fvm_coord_t max_width = 0.;
1296
const double epsilon = 1e-12;
1298
for (i = 0; i < 3; i++) {
1299
double w = fabs(extents[i+3] - extents[i]);
1300
max_width = FVM_MAX(max_width, w);
1303
for (i = 0; i < 3; i++) {
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) {
1309
mult = max_width / w;
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);
1318
/*----------------------------------------------------------------------------
1319
* Creation of an I/O numbering structure based on coordinates.
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.
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
1333
* pointer to I/O numbering structure
1334
*----------------------------------------------------------------------------*/
1336
static fvm_io_num_t *
1337
_create_from_coords_morton(const fvm_coord_t coords[],
1343
fvm_coord_t extents[6];
1344
fvm_lnum_t *order = NULL;
1345
fvm_morton_code_t *m_code = NULL;
1347
#if defined(HAVE_MPI)
1348
MPI_Comm comm = fvm_parall_get_mpi_comm();
1351
const int level = sizeof(fvm_morton_int_t)*8 - 1;
1352
const int n_ranks = fvm_parall_get_size();
1354
fvm_io_num_t *this_io_num = NULL;
1356
/* Create structure */
1358
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
1360
this_io_num->global_num_size = n_entities;
1362
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
1363
this_io_num->global_num = this_io_num->_global_num;
1365
/* Build Morton encoding and order it */
1367
#if defined(HAVE_MPI)
1368
fvm_morton_get_coord_extents(dim, n_entities, coords, extents, comm);
1370
fvm_morton_get_coord_extents(dim, n_entities, coords, extents);
1373
_adjust_extents(extents, box_to_cube);
1375
BFT_MALLOC(m_code, n_entities, fvm_morton_code_t);
1376
BFT_MALLOC(order, n_entities, fvm_lnum_t);
1378
fvm_morton_encode_coords(dim, level, extents, n_entities, coords, m_code);
1380
fvm_morton_local_order(n_entities, m_code, order);
1382
#if defined(HAVE_MPI)
1387
fvm_lnum_t j, shift;
1389
size_t n_block_ents = 0;
1390
fvm_gnum_t current_global_num = 0, global_num_shift = 0;
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;
1401
BFT_MALLOC(weight, n_entities, fvm_lnum_t);
1402
BFT_MALLOC(morton_index, n_ranks + 1, fvm_morton_code_t);
1404
for (i = 0; i < n_entities; i++)
1407
fit = fvm_morton_build_rank_index(dim,
1418
BFT_MALLOC(c_rank, n_entities, int);
1420
for (i = 0; i < n_entities; i++)
1421
c_rank[i] = fvm_morton_quantile_search(n_ranks,
1425
BFT_FREE(morton_index);
1428
/* Build send_buf, send_count and send_shift
1429
to build a rank to coords indexed list */
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);
1436
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1437
send_count[rank_id] = 0;
1439
for (i = 0; i < n_entities; i++)
1440
send_count[c_rank[i]] += dim;
1442
/* Exchange number of coords to send to each process */
1444
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
1453
/* Build send and receive buffers */
1455
BFT_MALLOC(send_coords, send_shift[n_ranks], fvm_coord_t);
1457
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1458
send_count[rank_id] = 0;
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;
1468
BFT_MALLOC(recv_coords, recv_shift[n_ranks], fvm_coord_t);
1470
/* Exchange coords between processes */
1472
MPI_Alltoallv(send_coords, send_count, send_shift, FVM_MPI_COORD,
1473
recv_coords, recv_count, recv_shift, FVM_MPI_COORD,
1476
BFT_FREE(send_coords);
1478
/* Now re-build Morton codes on block distribution */
1480
n_block_ents = recv_shift[n_ranks] / dim;
1482
BFT_MALLOC(m_code, n_block_ents, fvm_morton_code_t);
1483
BFT_MALLOC(order, n_block_ents, fvm_lnum_t);
1485
fvm_morton_encode_coords(dim,
1492
fvm_morton_local_order(n_block_ents, m_code, order);
1494
/* Check ordering; if two entities have the same Morton codes,
1495
use lexicographical coordinates ordering to ensure the
1496
final order is deterministic. */
1498
_check_morton_ordering(dim, n_block_ents, recv_coords, m_code, order);
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 */
1508
BFT_FREE(recv_coords);
1509
BFT_MALLOC(block_global_num, n_block_ents, fvm_gnum_t);
1511
for (i = 0; i < n_block_ents; i++)
1512
block_global_num[order[i]] = i+1;
1516
current_global_num = n_block_ents;
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
1524
MPI_Scan(¤t_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
1526
global_num_shift -= current_global_num;
1528
for (i = 0; i < n_block_ents; i++)
1529
block_global_num[i] += global_num_shift;
1531
/* Return global order to all processors */
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;
1540
send_shift[n_ranks] /= dim;
1542
BFT_MALLOC(part_global_num, send_shift[n_ranks], fvm_gnum_t);
1544
MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
1545
part_global_num, send_count, send_shift, FVM_MPI_GNUM,
1548
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1549
send_count[rank_id] = 0;
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;
1562
BFT_FREE(block_global_num);
1563
BFT_FREE(part_global_num);
1565
BFT_FREE(send_count);
1566
BFT_FREE(recv_count);
1567
BFT_FREE(send_shift);
1568
BFT_FREE(recv_shift);
1570
/* Get final maximum global number value */
1572
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
1576
#endif /* HAVE_MPI */
1580
_check_morton_ordering(dim, n_entities, coords, m_code, order);
1584
for (i = 0; i < n_entities; i++)
1585
this_io_num->_global_num[order[i]] = i+1;
1589
this_io_num->global_count = n_entities;
1596
/*----------------------------------------------------------------------------
1597
* Creation of an I/O numbering structure based on coordinates.
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.
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
1611
* pointer to I/O numbering structure
1612
*----------------------------------------------------------------------------*/
1614
static fvm_io_num_t *
1615
_create_from_coords_hilbert(const fvm_coord_t coords[],
1621
fvm_coord_t extents[6];
1622
fvm_lnum_t *order = NULL;
1624
#if defined(HAVE_MPI)
1625
MPI_Comm comm = fvm_parall_get_mpi_comm();
1628
const int n_ranks = fvm_parall_get_size();
1630
fvm_io_num_t *this_io_num = NULL;
1632
/* Create structure */
1634
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
1636
this_io_num->global_num_size = n_entities;
1638
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
1639
this_io_num->global_num = this_io_num->_global_num;
1641
/* Build Hilbert encoding and order it */
1643
#if defined(HAVE_MPI)
1644
fvm_hilbert_get_coord_extents(dim, n_entities, coords, extents, comm);
1646
fvm_hilbert_get_coord_extents(dim, n_entities, coords, extents);
1649
_adjust_extents(extents, box_to_cube);
1651
BFT_MALLOC(order, n_entities, fvm_lnum_t);
1653
#if defined(HAVE_MPI)
1658
fvm_lnum_t j, shift;
1660
size_t n_block_ents = 0;
1661
fvm_gnum_t current_global_num = 0, global_num_shift = 0;
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;
1673
BFT_MALLOC(h_code, n_entities, fvm_hilbert_code_t);
1675
fvm_hilbert_encode_coords(dim, extents, n_entities, coords, h_code);
1677
fvm_hilbert_local_order(n_entities, h_code, order);
1679
BFT_MALLOC(weight, n_entities, fvm_lnum_t);
1680
BFT_MALLOC(hilbert_index, (n_ranks + 1)*3, fvm_hilbert_code_t);
1682
for (i = 0; i < n_entities; i++)
1685
fit = fvm_hilbert_build_rank_index(dim,
1695
BFT_MALLOC(c_rank, n_entities, int);
1697
for (i = 0; i < n_entities; i++)
1698
c_rank[i] = fvm_hilbert_quantile_search(n_ranks,
1702
BFT_FREE(hilbert_index);
1705
/* Build send_buf, send_count and send_shift
1706
to build a rank to coords indexed list */
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);
1713
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1714
send_count[rank_id] = 0;
1716
for (i = 0; i < n_entities; i++)
1717
send_count[c_rank[i]] += dim;
1719
/* Exchange number of coords to send to each process */
1721
MPI_Alltoall(send_count, 1, MPI_INT, recv_count, 1, MPI_INT, comm);
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];
1730
/* Build send and receive buffers */
1732
BFT_MALLOC(send_coords, send_shift[n_ranks], fvm_coord_t);
1734
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1735
send_count[rank_id] = 0;
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;
1745
BFT_MALLOC(recv_coords, recv_shift[n_ranks], fvm_coord_t);
1747
/* Exchange coords between processes */
1749
MPI_Alltoallv(send_coords, send_count, send_shift, FVM_MPI_COORD,
1750
recv_coords, recv_count, recv_shift, FVM_MPI_COORD,
1753
BFT_FREE(send_coords);
1755
/* Now re-order coords on block distribution */
1757
n_block_ents = recv_shift[n_ranks] / dim;
1759
BFT_MALLOC(order, n_block_ents, fvm_lnum_t);
1761
fvm_hilbert_local_order_coords(dim,
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 */
1774
BFT_FREE(recv_coords);
1775
BFT_MALLOC(block_global_num, n_block_ents, fvm_gnum_t);
1777
for (i = 0; i < n_block_ents; i++)
1778
block_global_num[order[i]] = i+1;
1782
current_global_num = n_block_ents;
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
1790
MPI_Scan(¤t_global_num, &global_num_shift, 1, FVM_MPI_GNUM,
1792
global_num_shift -= current_global_num;
1794
for (i = 0; i < n_block_ents; i++)
1795
block_global_num[i] += global_num_shift;
1797
/* Return global order to all processors */
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;
1806
send_shift[n_ranks] /= dim;
1808
BFT_MALLOC(part_global_num, send_shift[n_ranks], fvm_gnum_t);
1810
MPI_Alltoallv(block_global_num, recv_count, recv_shift, FVM_MPI_GNUM,
1811
part_global_num, send_count, send_shift, FVM_MPI_GNUM,
1814
for (rank_id = 0; rank_id < n_ranks; rank_id++)
1815
send_count[rank_id] = 0;
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;
1828
BFT_FREE(block_global_num);
1829
BFT_FREE(part_global_num);
1831
BFT_FREE(send_count);
1832
BFT_FREE(recv_count);
1833
BFT_FREE(send_shift);
1834
BFT_FREE(recv_shift);
1836
/* Get final maximum global number value */
1838
this_io_num->global_count = _fvm_io_num_global_max(this_io_num, comm);
1842
#endif /* HAVE_MPI */
1846
fvm_hilbert_local_order_coords(dim,
1852
for (i = 0; i < n_entities; i++)
1853
this_io_num->_global_num[order[i]] = i+1;
1857
this_io_num->global_count = n_entities;
1864
/*=============================================================================
1865
* Public function definitions
1866
*============================================================================*/
1868
/*----------------------------------------------------------------------------
1869
* Creation of an I/O numbering structure.
1871
* The corresponding entities must be locally ordered.
1874
* parent_entity_number <-- pointer to list of selected entitie's parent's
1875
* numbers, or NULL if all first n_ent entities
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
1884
* pointer to I/O numbering structure
1885
*----------------------------------------------------------------------------*/
1888
fvm_io_num_create(const fvm_lnum_t parent_entity_number[],
1889
const fvm_gnum_t parent_global_number[],
1891
int share_parent_global)
1893
fvm_io_num_t *this_io_num = NULL;
1895
/* Initial checks */
1897
if (fvm_parall_get_size() < 2)
1900
assert(fvm_order_local_test(parent_entity_number,
1901
parent_global_number,
1902
n_entities) == true);
1904
#if defined(HAVE_MPI)
1906
/* Create structure */
1908
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
1910
this_io_num->global_num_size = n_entities;
1912
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
1913
this_io_num->global_num = this_io_num->_global_num;
1915
if (n_entities > 0) {
1919
/* Assign initial global numbers */
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];
1927
for (i = 0 ; i < n_entities ; i++)
1928
this_io_num->_global_num[i] = parent_global_number[i];
1933
/* Order globally */
1935
this_io_num->global_count = n_entities;
1937
_fvm_io_num_copy_on_write(this_io_num);
1938
_fvm_io_num_global_order(this_io_num,
1940
fvm_parall_get_mpi_comm());
1942
if (share_parent_global != 0)
1943
_fvm_io_num_try_to_set_shared(this_io_num,
1944
parent_global_number);
1951
/*----------------------------------------------------------------------------
1952
* Creation of an I/O numbering structure,
1953
* sharing a given global numbering array.
1955
* The corresponding entities must be locally ordered.
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
1964
* pointer to I/O numbering structure
1965
*----------------------------------------------------------------------------*/
1968
fvm_io_num_create_shared(const fvm_gnum_t global_number[],
1969
fvm_gnum_t global_count,
1972
fvm_io_num_t *this_io_num;
1974
/* Create structure */
1976
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
1978
this_io_num->global_count = global_count;
1979
this_io_num->global_num_size = n_entities;
1981
this_io_num->global_num = global_number;
1982
this_io_num->_global_num = NULL;
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.
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.
1995
* base_io_num <-- pointer to base I/O numbering structure
1996
* n_sub_entities <-- number of new entities per base entity
1999
* pointer to I/O numbering structure
2000
*----------------------------------------------------------------------------*/
2003
fvm_io_num_create_from_sub(const fvm_io_num_t *base_io_num,
2004
const fvm_lnum_t n_sub_entities[])
2006
fvm_io_num_t *this_io_num = NULL;
2008
/* Initial checks */
2010
if (base_io_num == NULL)
2013
assert(fvm_parall_get_size() > 1); /* Otherwise, base_io_num should be NULL */
2015
#if defined(HAVE_MPI)
2017
fvm_lnum_t i, n_ent;
2019
/* Create structure */
2021
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
2023
n_ent = base_io_num->global_num_size;
2025
BFT_MALLOC(this_io_num->_global_num, n_ent, fvm_gnum_t);
2026
this_io_num->global_num = this_io_num->_global_num;
2028
this_io_num->global_num_size = n_ent;
2030
/* Assign initial global numbers */
2032
for (i = 0 ; i < n_ent ; i++)
2033
this_io_num->_global_num[i] = base_io_num->global_num[i];
2035
/* Order globally */
2037
this_io_num->global_count = n_ent;
2039
_fvm_io_num_copy_on_write(this_io_num);
2040
_fvm_io_num_global_order(this_io_num,
2042
fvm_parall_get_mpi_comm());
2049
/*----------------------------------------------------------------------------
2050
* Creation of an I/O numbering structure based on a strided adjacency.
2052
* The corresponding entities must be locally ordered.
2055
* parent_entity_number <-- pointer to list of selected entitie's parent's
2056
* numbers, or NULL if all first n_ent entities
2058
* adjacency <-- entity adjacency (1 to n global numbering)
2059
* n_entities <-- number of entities considered
2060
* stride <-- values per entity
2063
* pointer to I/O numbering structure
2064
*----------------------------------------------------------------------------*/
2067
fvm_io_num_create_from_adj_s(const fvm_lnum_t parent_entity_number[],
2068
const fvm_gnum_t adjacency[],
2072
fvm_io_num_t *this_io_num = NULL;
2074
/* Initial checks */
2076
if (fvm_parall_get_size() < 2)
2079
assert(fvm_order_local_test_s(parent_entity_number,
2082
n_entities) == true);
2084
#if defined(HAVE_MPI)
2086
fvm_gnum_t *_adjacency = NULL;
2088
/* Create structure */
2090
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
2092
this_io_num->global_num_size = n_entities;
2094
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
2095
this_io_num->global_num = this_io_num->_global_num;
2097
if (n_entities > 0) {
2101
/* Assign initial global numbers */
2103
BFT_MALLOC(_adjacency, n_entities*stride, fvm_gnum_t);
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];
2113
memcpy(_adjacency, adjacency, n_entities*stride*sizeof(fvm_gnum_t));
2117
/* Order globally */
2119
this_io_num->global_count = n_entities;
2121
_fvm_io_num_global_order_s(this_io_num,
2124
fvm_parall_get_mpi_comm());
2126
BFT_FREE(_adjacency);
2133
/*----------------------------------------------------------------------------
2134
* Creation of an I/O numbering structure based on an indexed adjacency.
2136
* The corresponding entities do not need to be locally ordered.
2139
* parent_entity_number <-- pointer to list of selected entitie's parent's
2140
* numbers, or NULL if all first n_ent entities
2142
* index <-- index on entities for adjacency
2143
* adjacency <-- entity adjacency (1 to n global numbering)
2144
* n_entities <-- number of entities considered
2147
* pointer to I/O numbering structure
2148
*----------------------------------------------------------------------------*/
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)
2156
fvm_io_num_t *this_io_num = NULL;
2158
/* Initial checks */
2160
if (fvm_parall_get_size() < 2)
2163
#if defined(HAVE_MPI)
2165
fvm_lnum_t *_index = NULL;
2166
fvm_gnum_t *_adjacency = NULL;
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.";
2177
/* Create structure */
2179
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
2181
this_io_num->global_num_size = n_entities;
2183
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
2184
this_io_num->global_num = this_io_num->_global_num;
2186
if (n_entities > 0) {
2188
fvm_lnum_t i, j, k, ent_id, _shift;
2190
/* Assign initial global numbers */
2192
BFT_MALLOC(_index, n_entities + 1, fvm_lnum_t);
2195
if (parent_entity_number != NULL) {
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);
2205
/* Count reduced size */
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];
2212
for (i = 0 ; i < n_entities ; i++)
2213
_index[i+1] += _index[i];
2215
BFT_MALLOC(_adjacency, _index[n_entities], fvm_gnum_t);
2217
/* Define reduced index and adjacency */
2219
for (i = 0 ; i < n_entities ; i++) {
2221
ent_id = parent_entity_number[i]-1;
2224
for (j = index[ent_id], k = 0; j < index[ent_id+1]; j++, k++)
2225
_adjacency[_shift + k] = adjacency[j];
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);
2239
BFT_MALLOC(_adjacency, index[n_entities], fvm_gnum_t);
2241
memcpy(_index, index, (n_entities+1)*sizeof(fvm_lnum_t));
2242
memcpy(_adjacency, adjacency, index[n_entities]*sizeof(fvm_gnum_t));
2248
/* Order globally */
2250
this_io_num->global_count = n_entities;
2252
_fvm_io_num_global_order_index(this_io_num,
2255
fvm_parall_get_mpi_comm());
2257
if (_adjacency != NULL)
2258
BFT_FREE(_adjacency);
2267
/*----------------------------------------------------------------------------
2268
* Creation of an I/O numbering structure based on a space-filling curve.
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.
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)
2281
* pointer to I/O numbering structure
2282
*----------------------------------------------------------------------------*/
2285
fvm_io_num_create_from_sfc(const fvm_coord_t coords[],
2288
fvm_io_num_sfc_t sfc_type)
2290
fvm_io_num_t *this_io_num = NULL;
2293
case FVM_IO_NUM_SFC_MORTON_BOX:
2294
this_io_num = _create_from_coords_morton(coords, dim, n_entities, 0);
2296
case FVM_IO_NUM_SFC_MORTON_CUBE:
2297
this_io_num = _create_from_coords_morton(coords, dim, n_entities, 1);
2299
case FVM_IO_NUM_SFC_HILBERT_BOX:
2300
this_io_num = _create_from_coords_hilbert(coords, dim, n_entities, 0);
2302
case FVM_IO_NUM_SFC_HILBERT_CUBE:
2303
this_io_num = _create_from_coords_hilbert(coords, dim, n_entities, 1);
2312
/*----------------------------------------------------------------------------
2313
* Creation of an I/O numbering structure based on a simple accumulation
2314
* (i.e. scan) of counts on successive ranks.
2317
* n_entities <-- number of entities considered
2320
* pointer to I/O numbering structure
2321
*----------------------------------------------------------------------------*/
2324
fvm_io_num_create_from_scan(size_t n_entities)
2326
fvm_io_num_t *this_io_num = NULL;
2328
/* Initial checks */
2330
if (fvm_parall_get_size() < 2)
2333
#if defined(HAVE_MPI)
2336
fvm_gnum_t gnum_base = n_entities;
2337
fvm_gnum_t gnum_sum = n_entities;
2338
fvm_gnum_t gnum_shift = 0;
2340
MPI_Comm comm = fvm_parall_get_mpi_comm();
2342
/* Create structure */
2344
BFT_MALLOC(this_io_num, 1, fvm_io_num_t);
2346
BFT_MALLOC(this_io_num->_global_num, n_entities, fvm_gnum_t);
2347
this_io_num->global_num = this_io_num->_global_num;
2349
this_io_num->global_num_size = n_entities;
2351
MPI_Scan(&gnum_base, &gnum_shift, 1, FVM_MPI_GNUM, MPI_SUM, comm);
2353
gnum_base = gnum_shift - gnum_base + 1;
2355
for (i = 0; i < n_entities; i++)
2356
this_io_num->_global_num[i] = gnum_base + i;
2358
gnum_base = n_entities;
2360
MPI_Allreduce(&gnum_base, &gnum_sum, 1, FVM_MPI_GNUM, MPI_SUM, comm);
2362
this_io_num->global_count = gnum_sum;
2369
/*----------------------------------------------------------------------------
2370
* Destruction of a I/O numbering structure.
2373
* this_io_num <-- pointer to structure that should be destroyed
2377
*----------------------------------------------------------------------------*/
2380
fvm_io_num_destroy(fvm_io_num_t * this_io_num)
2382
if (this_io_num != NULL) {
2383
BFT_FREE(this_io_num->_global_num);
2384
BFT_FREE(this_io_num);
2390
/*----------------------------------------------------------------------------
2391
* Return local number of entities associated with an I/O numbering
2395
* this_io_num <-- pointer to I/O/ numbering structure
2398
* local number of associated entities
2399
*----------------------------------------------------------------------------*/
2402
fvm_io_num_get_local_count(const fvm_io_num_t *const this_io_num)
2404
assert(this_io_num != NULL);
2406
return this_io_num->global_num_size;
2409
/*----------------------------------------------------------------------------
2410
* Return global number of entities associated with an I/O numbering
2414
* this_io_num <-- pointer to I/O/ numbering structure
2417
* global number of associated entities
2418
*----------------------------------------------------------------------------*/
2421
fvm_io_num_get_global_count(const fvm_io_num_t *const this_io_num)
2423
assert(this_io_num != NULL);
2425
return this_io_num->global_count;
2428
/*----------------------------------------------------------------------------
2429
* Return global numbering associated with an I/O numbering structure.
2432
* this_io_num <-- pointer to I/O/ numbering structure
2435
* pointer to array of global numbers associated with local entities
2436
* (1 to n numbering)
2437
*----------------------------------------------------------------------------*/
2440
fvm_io_num_get_global_num(const fvm_io_num_t *const this_io_num)
2442
assert(this_io_num != NULL);
2444
return this_io_num->global_num;
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.
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
2458
* global number of sub-entities
2459
*----------------------------------------------------------------------------*/
2462
fvm_io_num_global_sub_size(const fvm_io_num_t *this_io_num,
2463
const fvm_lnum_t n_sub_entities[])
2465
fvm_gnum_t retval = 0;
2467
/* Initial checks */
2469
if (this_io_num == NULL)
2472
assert(fvm_parall_get_size() > 1); /* Otherwise, base_io_num should be NULL */
2474
#if defined(HAVE_MPI)
2476
int have_sub_loc = 0, have_sub_glob = 0;
2478
/* Caution: we may have sub-entities on some ranks and not on others */
2480
if (n_sub_entities != NULL)
2483
MPI_Allreduce(&have_sub_loc, &have_sub_glob, 1, MPI_INT, MPI_MAX,
2484
fvm_parall_get_mpi_comm());
2486
if (have_sub_glob > 0)
2487
retval = _fvm_io_num_global_sub_size(this_io_num,
2489
fvm_parall_get_mpi_comm());
2496
/*----------------------------------------------------------------------------
2497
* Dump printout of a I/O numbering structure.
2500
* this_io_num <-- pointer to structure that should be dumped
2501
*----------------------------------------------------------------------------*/
2504
fvm_io_num_dump(const fvm_io_num_t *const this_io_num)
2508
if (this_io_num == NULL) {
2509
bft_printf(" global numbering: nil\n");
2513
bft_printf(" global numbering size: %u\n",
2514
(unsigned)this_io_num->global_num_size);
2517
" pointer to shareable array:\n"
2518
" global_num: %p\n",
2519
this_io_num->global_num);
2522
" pointer to local array:\n"
2523
" _global_num: %p\n",
2524
this_io_num->global_num);
2526
if (this_io_num->global_num_size > 0) {
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",
2532
(unsigned long long)this_io_num->global_num[i]);
2536
/*----------------------------------------------------------------------------*/
2540
#endif /* __cplusplus */