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

« back to all changes in this revision

Viewing changes to src/fvm/fvm_box.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
 * Handle boxes aligned with Cartesian axes.
 
3
 *===========================================================================*/
 
4
 
 
5
/*
 
6
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
7
 
 
8
  Copyright (C) 1998-2011 EDF S.A.
 
9
 
 
10
  This program is free software; you can redistribute it and/or modify it under
 
11
  the terms of the GNU General Public License as published by the Free Software
 
12
  Foundation; either version 2 of the License, or (at your option) any later
 
13
  version.
 
14
 
 
15
  This program is distributed in the hope that it will be useful, but WITHOUT
 
16
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
17
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
18
  details.
 
19
 
 
20
  You should have received a copy of the GNU General Public License along with
 
21
  this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
22
  Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
23
*/
 
24
 
 
25
/*----------------------------------------------------------------------------*/
 
26
 
 
27
#if defined(HAVE_CONFIG_H)
 
28
#include "cs_config.h"
 
29
#endif
 
30
 
 
31
/*----------------------------------------------------------------------------
 
32
 * Standard C library headers
 
33
 *---------------------------------------------------------------------------*/
 
34
 
 
35
#include <assert.h>
 
36
#include <float.h>
 
37
#include <limits.h>
 
38
#include <math.h>
 
39
#include <stdlib.h>
 
40
#include <string.h>
 
41
 
 
42
/*----------------------------------------------------------------------------
 
43
 * BFT library headers
 
44
 *---------------------------------------------------------------------------*/
 
45
 
 
46
#include <bft_mem.h>
 
47
#include <bft_timer.h>
 
48
#include <bft_printf.h>
 
49
 
 
50
/*----------------------------------------------------------------------------
 
51
 *  Local headers
 
52
 *---------------------------------------------------------------------------*/
 
53
 
 
54
#include "fvm_config_defs.h"
 
55
#include "fvm_parall.h"
 
56
 
 
57
/*----------------------------------------------------------------------------
 
58
 *  Header for the current file
 
59
 *---------------------------------------------------------------------------*/
 
60
 
 
61
#include "fvm_box.h"
 
62
#include "fvm_box_priv.h"
 
63
 
 
64
/*---------------------------------------------------------------------------*/
 
65
 
 
66
#ifdef __cplusplus
 
67
extern "C" {
 
68
#if 0
 
69
} /* Fake brace to force Emacs auto-indentation back to column 0 */
 
70
#endif
 
71
#endif /* __cplusplus */
 
72
 
 
73
/*=============================================================================
 
74
 * Local Macro definitions
 
75
 *===========================================================================*/
 
76
 
 
77
/*============================================================================
 
78
 * Type and structure definitions
 
79
 *===========================================================================*/
 
80
 
 
81
/*============================================================================
 
82
 * Private function definitions
 
83
 *===========================================================================*/
 
84
 
 
85
#if defined(HAVE_MPI)
 
86
 
 
87
/*----------------------------------------------------------------------------
 
88
 * Display a histogram on leaves associated to the boxes and several
 
89
 * other pieces of information (min, max, ...)
 
90
 *
 
91
 * parameters:
 
92
 *   distrib          <-- pointer to the fvm_box_distrib_t structure
 
93
 *   n_quantiles      <-> number of quantiles requested (or NULL);
 
94
 *                        may be lower upon return
 
95
 *   quantile_start   --> start of quantile (size: n_quantiles + 1)
 
96
 *   n_quantile_boxes --> number of boxes per quantile (size: n_quantiles)
 
97
 *   imbalance        --> distribution imbalance measure (or NULL)
 
98
 *   n_ranks          --> number of ranks with boxes (or NULL)
 
99
 *   comm             <-- associated MPI communicator
 
100
 *---------------------------------------------------------------------------*/
 
101
 
 
102
static void
 
103
_get_distrib_statistics(const fvm_box_distrib_t  *distrib,
 
104
                        fvm_lnum_t               *n_quantiles,
 
105
                        fvm_lnum_t                quantile_start[],
 
106
                        fvm_lnum_t                n_quantile_boxes[],
 
107
                        double                   *imbalance,
 
108
                        int                      *n_ranks,
 
109
                        MPI_Comm                  comm)
 
110
{
 
111
  fvm_lnum_t  i, j, k, step, delta, _n_rank_boxes;
 
112
 
 
113
  int  _n_ranks = 0;
 
114
  fvm_lnum_t  _min = INT_MAX, _max = 0, gmin = 0, gmax = 0;
 
115
 
 
116
  /* Sanity checks */
 
117
 
 
118
  assert(distrib != NULL);
 
119
  assert(distrib->index != NULL);
 
120
 
 
121
  if (n_quantiles != NULL) {
 
122
 
 
123
    fvm_lnum_t _n_quantiles = 0;
 
124
 
 
125
    /* Get global min and max number of boxes */
 
126
 
 
127
    for (i = 0; i < distrib->n_ranks; i++) {
 
128
 
 
129
      _n_rank_boxes = distrib->index[i+1] - distrib->index[i];
 
130
      _min = FVM_MIN(_min, _n_rank_boxes);
 
131
      _max = FVM_MAX(_max, _n_rank_boxes);
 
132
 
 
133
      if (_n_rank_boxes > 0)
 
134
        _n_ranks += 1;
 
135
 
 
136
    }
 
137
 
 
138
    gmin = _min;
 
139
    gmax = _max;
 
140
 
 
141
    MPI_Allreduce(&_min, &gmin, 1, FVM_MPI_LNUM, MPI_MIN, comm);
 
142
    MPI_Allreduce(&_max, &gmax, 1, FVM_MPI_LNUM, MPI_MAX, comm);
 
143
 
 
144
    /* Build a histogram for the distribution of boxes */
 
145
 
 
146
    delta = gmax - gmin;
 
147
    if (delta < _n_quantiles)
 
148
      _n_quantiles = delta;
 
149
 
 
150
    /* Define quantiles */
 
151
 
 
152
    step = delta / _n_quantiles;
 
153
    if (delta % _n_quantiles > 0)
 
154
      step++;
 
155
 
 
156
    for (i = 0; i < _n_quantiles; i++)
 
157
      quantile_start[i] = gmin + i*step;
 
158
 
 
159
    quantile_start[_n_quantiles] = gmax + 1;
 
160
 
 
161
    /* Count for quantiles */
 
162
 
 
163
    for (j = 0; j < _n_quantiles; j++)
 
164
      n_quantile_boxes[j] = 0;
 
165
 
 
166
    if (delta > 0) {  /* Loop on boxes */
 
167
 
 
168
      for (i = 0; i < distrib->n_ranks; i++) {
 
169
 
 
170
        _n_rank_boxes = distrib->index[i+1] - distrib->index[i];
 
171
 
 
172
        for (k = 1; k < _n_quantiles; k++) {
 
173
          if (_n_rank_boxes < gmin + k*step)
 
174
            break;
 
175
        }
 
176
        n_quantile_boxes[k-1] += 1;
 
177
 
 
178
      } /* End of loop on boxes */
 
179
 
 
180
    }
 
181
 
 
182
    *n_quantiles = _n_quantiles;
 
183
  }
 
184
 
 
185
  /* Set other return values */
 
186
 
 
187
  if (imbalance != NULL)
 
188
    *imbalance = distrib->fit;
 
189
 
 
190
  if (n_ranks != NULL)
 
191
    *n_ranks = _n_ranks;
 
192
}
 
193
 
 
194
#endif /* defined(HAVE_MPI) */
 
195
 
 
196
/*============================================================================
 
197
 * Public function definitions
 
198
 *===========================================================================*/
 
199
 
 
200
/*----------------------------------------------------------------------------
 
201
 * Create a set of boxes and initialize it.
 
202
 *
 
203
 * parameters:
 
204
 *   dim              <-- spatial dimension
 
205
 *   normalize        <-- 1 if boxes are to be normalized, 0 otherwize
 
206
 *   allow_projection <-- if 1, project to lower dimension if all boxes
 
207
 *                        are cut by the median plane of the set.
 
208
 *   n_boxes          <-- number of elements to create
 
209
 *   box_gnum         <-- global numbering of boxes
 
210
 *   extents          <-- coordinate extents (size: n_boxes*dim*2, as
 
211
 *                        xmin1, ymin1, .. xmax1, ymax1, ..., xmin2, ...)
 
212
 *   comm             <-- associated MPI communicator
 
213
 *
 
214
 * returns:
 
215
 *   a new allocated pointer to a fvm_box_set_t structure.
 
216
 *---------------------------------------------------------------------------*/
 
217
 
 
218
#if defined(HAVE_MPI)
 
219
fvm_box_set_t *
 
220
fvm_box_set_create(int                 dim,
 
221
                   int                 normalize,
 
222
                   int                 allow_projection,
 
223
                   fvm_lnum_t          n_boxes,
 
224
                   const fvm_gnum_t   *box_gnum,
 
225
                   const fvm_coord_t  *box_extents,
 
226
                   MPI_Comm            comm)
 
227
#else
 
228
fvm_box_set_t *
 
229
fvm_box_set_create(int                 dim,
 
230
                   int                 normalize,
 
231
                   int                 allow_projection,
 
232
                   fvm_lnum_t          n_boxes,
 
233
                   const fvm_gnum_t   *box_gnum,
 
234
                   const fvm_coord_t  *box_extents)
 
235
#endif
 
236
{
 
237
  int j, k;
 
238
  fvm_lnum_t  i;
 
239
  fvm_gnum_t  n_g_boxes = n_boxes;
 
240
  fvm_coord_t  g_min[3], g_max[3], g_extents[6];
 
241
 
 
242
  fvm_box_set_t  *boxes = NULL;
 
243
 
 
244
  /* Get global min/max coordinates */
 
245
 
 
246
#if defined(HAVE_MPI)
 
247
  fvm_morton_get_global_extents(dim, n_boxes, box_extents, g_extents, comm);
 
248
#else
 
249
  fvm_morton_get_global_extents(dim, n_boxes, box_extents, g_extents);
 
250
#endif
 
251
 
 
252
  for (j = 0; j < 3; j++) {
 
253
    g_min[j] = g_extents[j];
 
254
    g_max[j] = g_extents[j+dim];
 
255
  }
 
256
 
 
257
#if defined(HAVE_MPI)
 
258
 
 
259
  if (comm != MPI_COMM_NULL) {
 
260
 
 
261
    fvm_gnum_t  box_max = 0;
 
262
 
 
263
    for (i = 0; i < n_boxes; i++)
 
264
      box_max = FVM_MAX(box_max, box_gnum[i]);
 
265
 
 
266
    MPI_Allreduce(&box_max, &n_g_boxes, 1, FVM_MPI_GNUM, MPI_MAX, comm);
 
267
 
 
268
  }
 
269
 
 
270
#endif
 
271
 
 
272
  /* Allocate box set structure and initialize it */
 
273
 
 
274
  BFT_MALLOC(boxes, 1, fvm_box_set_t);
 
275
 
 
276
  boxes->dim = dim;
 
277
  boxes->n_boxes = n_boxes;
 
278
  boxes->n_g_boxes = n_g_boxes;
 
279
 
 
280
  for (j = 0; j < 3; j++) {
 
281
    boxes->dimensions[j] = j;
 
282
    boxes->gmin[j] = g_min[j];
 
283
    boxes->gmax[j] = g_max[j];
 
284
  }
 
285
 
 
286
  boxes->g_num = NULL;
 
287
  boxes->extents = NULL;
 
288
 
 
289
#if defined(HAVE_MPI)
 
290
  boxes->comm = comm;
 
291
#endif
 
292
 
 
293
  /* Optionally allow and detect a layout of lower
 
294
     dimension than the spatial dimension */
 
295
 
 
296
  if (allow_projection) {
 
297
 
 
298
    double g_mid[3];
 
299
    int proj[] = {1, 1, 1};
 
300
 
 
301
    for (j = 0; j < dim; j++)
 
302
      g_mid[j] = (g_min[j] + g_max[j]) * 0.5;
 
303
 
 
304
    for (i = 0; i < n_boxes; i++) {
 
305
      for (j = 0; j < dim; j++) {
 
306
        if (   box_extents[i*dim*2 + j]     > g_mid[j]
 
307
            || box_extents[i*dim*2 + j+dim] < g_mid[j])
 
308
          proj[j] = 0;
 
309
      }
 
310
    }
 
311
 
 
312
#if defined(HAVE_MPI)
 
313
    if (comm != MPI_COMM_NULL) {
 
314
      int l_proj[3];
 
315
      for (j = 0; j < dim; j++)
 
316
        l_proj[j] = proj[j];
 
317
      MPI_Allreduce(l_proj, proj, dim, MPI_INT, MPI_MIN, comm);
 
318
    }
 
319
#endif
 
320
 
 
321
    boxes->dim = 0;
 
322
    for (j = 0; j < dim; j++) {
 
323
      if (proj[j] == 0) {
 
324
        boxes->dimensions[boxes->dim] = j;
 
325
        boxes->dim += 1;
 
326
      }
 
327
    }
 
328
 
 
329
 
 
330
  }
 
331
 
 
332
  for (j = boxes->dim; j < 3; j++) /* ensure all is initialized */
 
333
    boxes->dimensions[j] = -1;
 
334
 
 
335
  /* Now assign values */
 
336
 
 
337
  BFT_MALLOC(boxes->g_num, n_boxes, fvm_gnum_t);
 
338
  BFT_MALLOC(boxes->extents, n_boxes*boxes->dim*2, fvm_coord_t);
 
339
 
 
340
  for (i = 0; i < n_boxes; i++) {
 
341
 
 
342
    fvm_coord_t *_min = boxes->extents + (boxes->dim*2*i);
 
343
    fvm_coord_t *_max = _min + boxes->dim;
 
344
 
 
345
    boxes->g_num[i] = box_gnum[i];
 
346
 
 
347
    for (j = 0; j < boxes->dim; j++) {
 
348
      k = boxes->dimensions[j];
 
349
      _min[j] = box_extents[i*dim*2 + k];
 
350
      _max[j] = box_extents[i*dim*2 + k+dim];
 
351
      assert(_min[j] <= _max[j]);
 
352
    }
 
353
  }
 
354
 
 
355
  /* Define the normalized min/max coordinates of the box */
 
356
 
 
357
  if (normalize) {
 
358
 
 
359
    fvm_coord_t  d[3], s[3];
 
360
 
 
361
    for (j = 0; j < boxes->dim; j++) {
 
362
      k = boxes->dimensions[j];
 
363
      s[j] = g_min[k];
 
364
      d[j] = g_max[k] - g_min[k];
 
365
    }
 
366
 
 
367
    for (i = 0; i < n_boxes; i++) {
 
368
 
 
369
      fvm_coord_t *_min = boxes->extents + (boxes->dim*2*i);
 
370
      fvm_coord_t *_max = _min + boxes->dim;
 
371
 
 
372
      for (j = 0; j < boxes->dim; j++) {
 
373
        _min[j] = (_min[j] - s[j]) / d[j];
 
374
        _max[j] = (_max[j] - s[j]) / d[j];
 
375
      }
 
376
    }
 
377
 
 
378
  }
 
379
 
 
380
  /* Return pointer to structure */
 
381
 
 
382
  return boxes;
 
383
}
 
384
 
 
385
/*----------------------------------------------------------------------------
 
386
 * Delete a fvm_box_set_t structure.
 
387
 *
 
388
 * parameters:
 
389
 *   boxes <-> pointer to the fvm_box_set_t structure to delete
 
390
 *---------------------------------------------------------------------------*/
 
391
 
 
392
void
 
393
fvm_box_set_destroy(fvm_box_set_t  **boxes)
 
394
{
 
395
  if (boxes != NULL) {
 
396
 
 
397
    fvm_box_set_t  *_boxes = *boxes;
 
398
 
 
399
    if (_boxes == NULL)
 
400
      return;
 
401
 
 
402
    BFT_FREE(_boxes->g_num);
 
403
    BFT_FREE(_boxes->extents);
 
404
    BFT_FREE(_boxes);
 
405
  }
 
406
}
 
407
 
 
408
/*----------------------------------------------------------------------------
 
409
 * Return the dimension associated with a set of boxes.
 
410
 *
 
411
 * parameters:
 
412
 *   boxes <-- pointer to set of boxes
 
413
 *
 
414
 * returns:
 
415
 *   associated spatial dimension
 
416
 *---------------------------------------------------------------------------*/
 
417
 
 
418
int
 
419
fvm_box_set_get_dim(const fvm_box_set_t  *boxes)
 
420
{
 
421
  int retval = 0;
 
422
 
 
423
  if (boxes != NULL)
 
424
    retval = boxes->dim;
 
425
 
 
426
  return retval;
 
427
}
 
428
 
 
429
/*----------------------------------------------------------------------------
 
430
 * Return the local number of boxes in a set.
 
431
 *
 
432
 * parameters:
 
433
 *   boxes <-- pointer to set of boxes
 
434
 *
 
435
 * returns:
 
436
 *   local number of boxes
 
437
 *---------------------------------------------------------------------------*/
 
438
 
 
439
fvm_lnum_t
 
440
fvm_box_set_get_size(const fvm_box_set_t  *boxes)
 
441
{
 
442
  fvm_lnum_t retval = 0;
 
443
 
 
444
  if (boxes != NULL)
 
445
    retval = boxes->n_boxes;
 
446
 
 
447
  return retval;
 
448
}
 
449
 
 
450
/*----------------------------------------------------------------------------
 
451
 * Return the global number of boxes in a set.
 
452
 *
 
453
 * parameters:
 
454
 *   boxes <-- pointer to set of boxes
 
455
 *
 
456
 * returns:
 
457
 *   global number of boxes
 
458
 *---------------------------------------------------------------------------*/
 
459
 
 
460
fvm_gnum_t
 
461
fvm_box_set_get_global_size(const fvm_box_set_t  *boxes)
 
462
{
 
463
  fvm_gnum_t retval = 0;
 
464
 
 
465
  if (boxes != NULL)
 
466
    retval = boxes->n_g_boxes;
 
467
 
 
468
  return retval;
 
469
}
 
470
 
 
471
/*----------------------------------------------------------------------------
 
472
 * Return extents associated with a set of boxes.
 
473
 *
 
474
 * The extents array is organized in the following fashion:
 
475
 * {x_min_0, y_min_0, ..., x_max_0, y_max_0, ...
 
476
 *  x_min_n, y_min_n, ..., x_max_n, y_max_n, ...}
 
477
 *
 
478
 * Its size is thus: n_boxes * dim * 2.
 
479
 *
 
480
 * parameters:
 
481
 *   boxes <-- pointer to set of boxes
 
482
 *
 
483
 * returns:
 
484
 *   pointer to extents array
 
485
 *---------------------------------------------------------------------------*/
 
486
 
 
487
const fvm_coord_t *
 
488
fvm_box_set_get_extents(fvm_box_set_t  *boxes)
 
489
{
 
490
  assert(boxes != NULL);
 
491
 
 
492
  return boxes->extents;
 
493
}
 
494
 
 
495
/*----------------------------------------------------------------------------
 
496
 * Return global numbers associated with a set of boxes.
 
497
 *
 
498
 * parameters:
 
499
 *   boxes <-- pointer to set of boxes
 
500
 *
 
501
 * returns:
 
502
 *   pointer to global box numbers array
 
503
 *---------------------------------------------------------------------------*/
 
504
 
 
505
const fvm_gnum_t *
 
506
fvm_box_set_get_g_num(fvm_box_set_t  *boxes)
 
507
{
 
508
  assert(boxes != NULL);
 
509
 
 
510
  return boxes->g_num;
 
511
}
 
512
 
 
513
/*----------------------------------------------------------------------------
 
514
 * Build a Morton_index to get a well-balanced distribution of the boxes.
 
515
 *
 
516
 * parameters:
 
517
 *  boxes      <-- pointer to associated fvm_box_set_t structure
 
518
 *  distrib    <-> pointer to a fvm_box_distrib_t structure
 
519
 *  n_leaves   <-- number of leaves with weight > 0
 
520
 *  leaf_codes <-- Morton code for each leaf
 
521
 *  weight     <-- number of boxes related to each leaf
 
522
 *---------------------------------------------------------------------------*/
 
523
 
 
524
void
 
525
fvm_box_set_build_morton_index(const fvm_box_set_t  *boxes,
 
526
                               fvm_box_distrib_t    *distrib,
 
527
                               fvm_lnum_t            n_leaves,
 
528
                               fvm_morton_code_t    *leaf_codes,
 
529
                               fvm_lnum_t           *weight)
 
530
{
 
531
#if defined(HAVE_MPI)
 
532
 
 
533
  fvm_lnum_t  *order = NULL;
 
534
 
 
535
  assert(distrib != NULL);
 
536
  assert(distrib->morton_index != NULL);
 
537
 
 
538
  BFT_MALLOC(order, n_leaves, fvm_lnum_t);
 
539
 
 
540
  /* Locally order Morton encoding */
 
541
 
 
542
  fvm_morton_local_order(n_leaves,
 
543
                         leaf_codes,
 
544
                         order);
 
545
 
 
546
  /* Compute a Morton index on ranks and return the associated fit */
 
547
 
 
548
  if (boxes->comm != MPI_COMM_NULL)
 
549
    distrib->fit = fvm_morton_build_rank_index(boxes->dim,
 
550
                                               distrib->max_level,
 
551
                                               n_leaves,
 
552
                                               leaf_codes,
 
553
                                               weight,
 
554
                                               order,
 
555
                                               distrib->morton_index,
 
556
                                               boxes->comm);
 
557
  /* Free memory */
 
558
 
 
559
  BFT_FREE(order);
 
560
 
 
561
#endif
 
562
}
 
563
 
 
564
/*----------------------------------------------------------------------------
 
565
 * Redistribute boxes over the ranks according to the Morton index to
 
566
 * assume a better balanced distribution of the boxes.
 
567
 *
 
568
 * parameters:
 
569
 *  distrib <--  data structure on box distribution
 
570
 *  boxes   <->  pointer to the structure to redistribute
 
571
 *---------------------------------------------------------------------------*/
 
572
 
 
573
void
 
574
fvm_box_set_redistribute(const fvm_box_distrib_t  *distrib,
 
575
                         fvm_box_set_t            *boxes)
 
576
{
 
577
#if defined(HAVE_MPI)
 
578
 
 
579
  int  rank_id;
 
580
 
 
581
  fvm_lnum_t  i, j;
 
582
  int  *send_count = NULL, *send_shift = NULL;
 
583
  int  *recv_count = NULL, *recv_shift = NULL;
 
584
  fvm_gnum_t  *send_g_num = NULL;
 
585
  fvm_coord_t  *send_extents = NULL;
 
586
 
 
587
  const int stride = boxes->dim * 2;
 
588
 
 
589
  /* Sanity checks */
 
590
 
 
591
  assert(distrib != NULL);
 
592
  assert(boxes != NULL);
 
593
  assert(distrib->n_ranks > 1);
 
594
 
 
595
  /* Build send_buf, send_count and send_shift
 
596
     to build a rank to boxes indexed list */
 
597
 
 
598
  BFT_MALLOC(send_count, distrib->n_ranks, int);
 
599
  BFT_MALLOC(recv_count, distrib->n_ranks, int);
 
600
  BFT_MALLOC(send_shift, distrib->n_ranks + 1, int);
 
601
  BFT_MALLOC(recv_shift, distrib->n_ranks + 1, int);
 
602
 
 
603
  for (rank_id = 0; rank_id < distrib->n_ranks; rank_id++)
 
604
    send_count[rank_id]
 
605
      = distrib->index[rank_id+1] - distrib->index[rank_id];
 
606
 
 
607
  /* Exchange number of boxes to send to each process */
 
608
 
 
609
  MPI_Alltoall(send_count, 1, MPI_INT,
 
610
               recv_count, 1, MPI_INT, boxes->comm);
 
611
 
 
612
  for (i = 0; i < distrib->n_ranks; i++)
 
613
    send_shift[i] = distrib->index[i];
 
614
 
 
615
  recv_shift[0] = 0;
 
616
  for (rank_id = 0; rank_id < distrib->n_ranks; rank_id++)
 
617
    recv_shift[rank_id + 1] = recv_shift[rank_id] + recv_count[rank_id];
 
618
 
 
619
  /* Build send_buffers */
 
620
 
 
621
  BFT_MALLOC(send_g_num, distrib->index[distrib->n_ranks], fvm_gnum_t);
 
622
  BFT_MALLOC(send_extents,
 
623
             distrib->index[distrib->n_ranks] * boxes->dim * 2,
 
624
             fvm_coord_t);
 
625
 
 
626
  for (rank_id = 0; rank_id < distrib->n_ranks; rank_id++)
 
627
    send_count[rank_id] = 0;
 
628
 
 
629
  for (rank_id = 0; rank_id < distrib->n_ranks; rank_id++) {
 
630
 
 
631
    for (i = distrib->index[rank_id];
 
632
         i < distrib->index[rank_id+1];
 
633
         i++) {
 
634
 
 
635
      fvm_lnum_t  box_id = distrib->list[i];
 
636
      fvm_lnum_t  shift = distrib->index[rank_id] + send_count[rank_id];
 
637
 
 
638
      send_g_num[shift] = boxes->g_num[box_id];
 
639
 
 
640
      for (j = 0; j < stride; j++)
 
641
        send_extents[shift*stride + j] = boxes->extents[box_id*stride + j];
 
642
 
 
643
      send_count[rank_id] += 1;
 
644
 
 
645
    }
 
646
 
 
647
  } /* End of loop on ranks */
 
648
 
 
649
  /* Prepare to replace the local arrays */
 
650
 
 
651
  boxes->n_boxes = recv_shift[distrib->n_ranks];
 
652
  BFT_FREE(boxes->g_num);
 
653
  BFT_FREE(boxes->extents);
 
654
 
 
655
  BFT_MALLOC(boxes->g_num, boxes->n_boxes, fvm_gnum_t);
 
656
  BFT_MALLOC(boxes->extents, boxes->n_boxes*stride, fvm_coord_t);
 
657
 
 
658
  /* Exchange boxes between processes */
 
659
 
 
660
  MPI_Alltoallv(send_g_num, send_count, send_shift, FVM_MPI_GNUM,
 
661
                boxes->g_num, recv_count, recv_shift, FVM_MPI_GNUM,
 
662
                boxes->comm);
 
663
 
 
664
  for (rank_id = 0; rank_id < distrib->n_ranks; rank_id++) {
 
665
    send_count[rank_id] *= stride;
 
666
    send_shift[rank_id] *= stride;
 
667
    recv_count[rank_id] *= stride;
 
668
    recv_shift[rank_id] *= stride;
 
669
  }
 
670
 
 
671
  MPI_Alltoallv(send_extents, send_count, send_shift, FVM_MPI_COORD,
 
672
                boxes->extents, recv_count, recv_shift, FVM_MPI_COORD,
 
673
                boxes->comm);
 
674
 
 
675
  /* Free buffers */
 
676
 
 
677
  BFT_FREE(send_g_num);
 
678
  BFT_FREE(send_extents);
 
679
  BFT_FREE(send_count);
 
680
  BFT_FREE(send_shift);
 
681
  BFT_FREE(recv_count);
 
682
  BFT_FREE(recv_shift);
 
683
 
 
684
#endif /* HAVE_MPI */
 
685
}
 
686
 
 
687
/*----------------------------------------------------------------------------
 
688
 * Dump a fvm_box_set_t structure.
 
689
 *
 
690
 * parameters:
 
691
 *   boxes     <-- pointer to the fvm_box_t structure
 
692
 *   verbosity <-- verbosity level (0 or 1)
 
693
 *----------------------------------------------------------------------------*/
 
694
 
 
695
void
 
696
fvm_box_set_dump(const fvm_box_set_t  *boxes,
 
697
                 int                   verbosity)
 
698
{
 
699
  fvm_lnum_t  i;
 
700
 
 
701
  const char  XYZ[3] = "XYZ";
 
702
 
 
703
  if (boxes == NULL)
 
704
    return;
 
705
 
 
706
  /* Print basic information */
 
707
 
 
708
  if (boxes->dim == 3)
 
709
    bft_printf("\nBox set (3D layout):\n\n"
 
710
               "global min/max on selected faces:\n"
 
711
               "  [%7.5e %7.5e %7.5e] --> [%7.5e %7.5e %7.5e]\n",
 
712
               boxes->gmin[0], boxes->gmin[1], boxes->gmin[2],
 
713
               boxes->gmax[0], boxes->gmax[1], boxes->gmax[2]);
 
714
 
 
715
  else if (boxes->dim == 2) {
 
716
    bft_printf("\nBox set (2D layout, selected axes [%c, %c]\n\n",
 
717
               XYZ[boxes->dimensions[0]],
 
718
               XYZ[boxes->dimensions[1]]);
 
719
    bft_printf("global min/max on selected faces:\n"
 
720
               "  [%7.5e %7.5e] --> [%7.5e %7.5e]\n",
 
721
               boxes->gmin[boxes->dimensions[0]],
 
722
               boxes->gmin[boxes->dimensions[1]],
 
723
               boxes->gmax[boxes->dimensions[0]],
 
724
               boxes->gmax[boxes->dimensions[1]]);
 
725
  }
 
726
 
 
727
  else if (boxes->dim == 1) {
 
728
    bft_printf("\nBox set (1D layout, selected axis [%c]\n\n",
 
729
               XYZ[boxes->dimensions[0]]);
 
730
    bft_printf("global min/max on selected faces:\n"
 
731
               "  [%7.5e %7.5e] --> [%7.5e %7.5e]\n",
 
732
               boxes->gmin[boxes->dimensions[0]],
 
733
               boxes->gmin[boxes->dimensions[1]],
 
734
               boxes->gmax[boxes->dimensions[0]],
 
735
               boxes->gmax[boxes->dimensions[1]]);
 
736
  }
 
737
  bft_printf_flush();
 
738
 
 
739
  /* Print detailed box information */
 
740
 
 
741
  if (verbosity < 1)
 
742
    return;
 
743
 
 
744
  if (boxes->dim == 3) {
 
745
    for (i = 0; i < boxes->n_boxes; i++) {
 
746
      const fvm_coord_t *bmin = boxes->extents + i*6;
 
747
      const fvm_coord_t *bmax = boxes->extents + i*6 + 3;
 
748
      bft_printf("  id %8d, num %9llu: "
 
749
                 "[%7.5e %7.5e %7.5e] --> [%7.5e %7.5e %7.5e]\n",
 
750
                 i, (unsigned long long)(boxes->g_num[i]),
 
751
                 bmin[0], bmin[1], bmin[2],
 
752
                 bmax[0], bmax[1], bmax[2]);
 
753
    }
 
754
  }
 
755
 
 
756
  else if (boxes->dim == 2) {
 
757
    for (i = 0; i < boxes->n_boxes; i++) {
 
758
      const fvm_coord_t *bmin = boxes->extents + i*4;
 
759
      const fvm_coord_t *bmax = boxes->extents + i*4 + 2;
 
760
      bft_printf("  id %8d, num %9llu: "
 
761
                 "[%7.5e %7.5e] --> [%7.5e %7.5e]\n",
 
762
                 i, (unsigned long long)(boxes->g_num[i]),
 
763
                 bmin[0], bmin[1], bmax[0], bmax[1]);
 
764
    }
 
765
  }
 
766
 
 
767
  else if (boxes->dim == 1) {
 
768
    for (i = 0; i < boxes->n_boxes; i++) {
 
769
      const fvm_coord_t *bmin = boxes->extents + i*2;
 
770
      const fvm_coord_t *bmax = boxes->extents + i*2 + 1;
 
771
      bft_printf("  id %8d, num %9llu: "
 
772
                 "[%7.5e] --> [%7.5e]\n",
 
773
                 i, (unsigned long long)(boxes->g_num[i]),
 
774
                 bmin[0], bmax[0]);
 
775
    }
 
776
  }
 
777
 
 
778
  /* Sanity check */
 
779
 
 
780
  for (i = 0; i < boxes->n_boxes; i++) {
 
781
    int j;
 
782
    const fvm_coord_t *bmin = boxes->extents + boxes->dim*2*i;
 
783
    const fvm_coord_t *bmax = boxes->extents + boxes->dim*(2*i + 1);
 
784
    for (j = 0; j < boxes->dim; j++) {
 
785
      if (bmin[j] > bmax[j])
 
786
        bft_error(__FILE__, __LINE__, 0,
 
787
                  _("Inconsistent box found (min > max):\n"
 
788
                    "  global number:  %u\n"
 
789
                    "  min       :  %10.4g\n"
 
790
                    "  max       :  %10.4g\n"),
 
791
                  boxes->g_num[i], bmin[j], bmax[j]);
 
792
    }
 
793
  }
 
794
 
 
795
}
 
796
 
 
797
#if defined(HAVE_MPI)
 
798
 
 
799
/*----------------------------------------------------------------------------
 
800
 * Create a fvm_box_distrib_t structure.
 
801
 *
 
802
 * parameters:
 
803
 *   n_boxes   <-- number of boxes
 
804
 *   n_g_boxes <-- global number of boxes
 
805
 *   max_level <-- max level reached locally in the related tree
 
806
 *   comm      <-- MPI communicator. on which the distribution takes place
 
807
 *
 
808
 * returns:
 
809
 *   a pointer to a new allocated fvm_box_distrib_t structure.
 
810
 *---------------------------------------------------------------------------*/
 
811
 
 
812
fvm_box_distrib_t *
 
813
fvm_box_distrib_create(fvm_lnum_t  n_boxes,
 
814
                       fvm_gnum_t  n_g_boxes,
 
815
                       int         max_level,
 
816
                       MPI_Comm    comm)
 
817
{
 
818
  int  i, n_ranks, gmax_level;
 
819
 
 
820
  fvm_box_distrib_t  *new_distrib = NULL;
 
821
 
 
822
  if (n_g_boxes == 0)
 
823
    return NULL;
 
824
 
 
825
  BFT_MALLOC(new_distrib, 1, fvm_box_distrib_t);
 
826
 
 
827
  /* Parallel parameters */
 
828
 
 
829
  MPI_Comm_size(comm, &n_ranks);
 
830
 
 
831
  new_distrib->n_ranks = n_ranks;
 
832
 
 
833
  new_distrib->n_boxes = n_boxes;
 
834
 
 
835
  assert(n_ranks > 1);
 
836
 
 
837
  BFT_MALLOC(new_distrib->morton_index, n_ranks + 1, fvm_morton_code_t);
 
838
 
 
839
  MPI_Allreduce(&max_level, &gmax_level, 1, MPI_INT, MPI_MAX, comm);
 
840
 
 
841
  new_distrib->max_level = gmax_level;
 
842
  new_distrib->fit = 999.0;
 
843
 
 
844
  BFT_MALLOC(new_distrib->index, n_ranks + 1, fvm_lnum_t);
 
845
 
 
846
  for (i = 0; i < n_ranks + 1; i++)
 
847
    new_distrib->index[i] = 0;
 
848
 
 
849
  new_distrib->list = NULL;
 
850
 
 
851
  return  new_distrib;
 
852
}
 
853
 
 
854
/*----------------------------------------------------------------------------
 
855
 * Destroy a fvm_box_distrib_t structure.
 
856
 *
 
857
 * parameters:
 
858
 *   distrib <-> pointer to pointer to the structure to destroy
 
859
 *---------------------------------------------------------------------------*/
 
860
 
 
861
void
 
862
fvm_box_distrib_destroy(fvm_box_distrib_t  **distrib)
 
863
{
 
864
  if (distrib != NULL) {
 
865
 
 
866
    fvm_box_distrib_t  *d = *distrib;
 
867
 
 
868
    if (d == NULL)
 
869
      return;
 
870
 
 
871
    BFT_FREE(d->index);
 
872
    BFT_FREE(d->list);
 
873
    BFT_FREE(d->morton_index);
 
874
 
 
875
    BFT_FREE(d);
 
876
  }
 
877
}
 
878
 
 
879
/*----------------------------------------------------------------------------
 
880
 * Delete redundancies in box distribution
 
881
 *
 
882
 * parameters:
 
883
 *   distrib <->  pointer to the fvm_box_distrib_t structure
 
884
 *---------------------------------------------------------------------------*/
 
885
 
 
886
void
 
887
fvm_box_distrib_clean(fvm_box_distrib_t  *distrib)
 
888
{
 
889
  int  i, rank;
 
890
 
 
891
  fvm_lnum_t  *counter = NULL, *new_index = NULL;
 
892
 
 
893
  BFT_MALLOC(counter, distrib->n_boxes, fvm_lnum_t);
 
894
  BFT_MALLOC(new_index, distrib->n_ranks + 1, fvm_lnum_t);
 
895
 
 
896
  for (i = 0; i < distrib->n_ranks + 1; i++)
 
897
    new_index[i] = 0;
 
898
 
 
899
  for (rank = 0; rank < distrib->n_ranks; rank++) {
 
900
 
 
901
    fvm_lnum_t  shift = new_index[rank];
 
902
    fvm_lnum_t  start = distrib->index[rank];
 
903
    fvm_lnum_t  end = distrib->index[rank + 1];
 
904
 
 
905
    if (end - start > 0) {
 
906
 
 
907
      for (i = 0; i < distrib->n_boxes; i++)
 
908
        counter[i] = 0;
 
909
 
 
910
      for (i = start; i < end; i++)
 
911
        counter[distrib->list[i]] += 1;
 
912
 
 
913
      for (i = 0; i < distrib->n_boxes; i++) {
 
914
 
 
915
        if (counter[i] > 0)
 
916
          distrib->list[shift++] = i;
 
917
 
 
918
      }
 
919
 
 
920
    } /* end if end - start > 0 */
 
921
 
 
922
    new_index[rank+1] = shift;
 
923
 
 
924
  } /* End of loop on ranks */
 
925
 
 
926
  /* Memory management */
 
927
 
 
928
  BFT_FREE(distrib->index);
 
929
  BFT_REALLOC(distrib->list, new_index[distrib->n_ranks], fvm_lnum_t);
 
930
 
 
931
  distrib->index = new_index;
 
932
 
 
933
  BFT_FREE(counter);
 
934
}
 
935
 
 
936
/*----------------------------------------------------------------------------
 
937
 * Display a histogram on leaves associated to the boxes and several
 
938
 * other pieces of information (min, max, ...)
 
939
 *
 
940
 * parameters:
 
941
 *   distrib <-- pointer to the fvm_box_distrib_t structure
 
942
 *   comm    <-- associated MPI communicator
 
943
 *---------------------------------------------------------------------------*/
 
944
 
 
945
void
 
946
fvm_box_distrib_dump_statistics(const fvm_box_distrib_t  *distrib,
 
947
                                MPI_Comm                  comm)
 
948
{
 
949
  fvm_lnum_t  i;
 
950
 
 
951
  int          n_ranks = 0;
 
952
  fvm_lnum_t   n_quantiles = 5;
 
953
  fvm_lnum_t   quantile_start[6];
 
954
  fvm_lnum_t   n_boxes[5];
 
955
 
 
956
  /* Sanity checks */
 
957
 
 
958
  assert(distrib != NULL);
 
959
  assert(distrib->index != NULL);
 
960
 
 
961
  _get_distrib_statistics(distrib,
 
962
                          &n_quantiles,
 
963
                          quantile_start,
 
964
                          n_boxes,
 
965
                          NULL,
 
966
                          &n_ranks,
 
967
                          comm);
 
968
 
 
969
  bft_printf("\n"
 
970
             "- Box distribution statistics -\n\n");
 
971
 
 
972
  bft_printf("   Distribution imbalance:              %10.4g\n",
 
973
             distrib->fit);
 
974
  bft_printf("   Number of ranks in distribution:     %8d\n\n",
 
975
             n_ranks);
 
976
 
 
977
  /* Print histogram to show the distribution of boxes */
 
978
 
 
979
  if (n_quantiles > 0) {
 
980
 
 
981
    for (i = 0; i < n_quantiles - 1; i++)
 
982
      bft_printf("    %3d : [ %10d ; %10d [ = %10d\n",
 
983
                 i+1, quantile_start[i], quantile_start[i+1], n_boxes[i]);
 
984
 
 
985
    i = n_quantiles -1;
 
986
    bft_printf("    %3d : [ %10d ; %10d ] = %10d\n",
 
987
               i+1, quantile_start[i], quantile_start[i+1] - 1, n_boxes[i]);
 
988
 
 
989
  }
 
990
  bft_printf_flush();
 
991
}
 
992
 
 
993
#endif /* defined(HAVE_MPI) */
 
994
 
 
995
/*---------------------------------------------------------------------------*/
 
996
 
 
997
#ifdef __cplusplus
 
998
}
 
999
#endif /* __cplusplus */