/*============================================================================
*
*                    Code_Saturne version 1.3
*                    ------------------------
*
*
*     This file is part of the Code_Saturne Kernel, element of the
*     Code_Saturne CFD tool.
*
*     Copyright (C) 1998-2007 EDF S.A., France
*
*     contact: saturne-support@edf.fr
*
*     The Code_Saturne Kernel is free software; you can redistribute it
*     and/or modify it under the terms of the GNU General Public License
*     as published by the Free Software Foundation; either version 2 of
*     the License, or (at your option) any later version.
*
*     The Code_Saturne Kernel is distributed in the hope that it will be
*     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
*     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*     GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with the Code_Saturne Kernel; if not, write to the
*     Free Software Foundation, Inc.,
*     51 Franklin St, Fifth Floor,
*     Boston, MA  02110-1301  USA
*
*============================================================================*/

/*============================================================================
 * Structure principale associée à un maillage
 *============================================================================*/

/* includes système */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>


/*----------------------------------------------------------------------------
 *  Fichiers `include' librairie standard C, BFT, ou FVM
 *----------------------------------------------------------------------------*/

#include <bft_mem.h>
#include <bft_error.h>
#include <bft_printf.h>

#include <fvm_parall.h>
#include <fvm_order.h>


/*----------------------------------------------------------------------------
 *  Fichiers `include' locaux
 *----------------------------------------------------------------------------*/

#include "cs_base.h"
#include "cs_perio.h"


/*----------------------------------------------------------------------------
 *  Fichiers `include' associés au fichier courant
 *----------------------------------------------------------------------------*/

#include "cs_maillage.h"


#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */


/*============================================================================
 *  Variables globales statiques
 *============================================================================*/

/* Pointeur sur le maillage principal */
cs_maillage_t  *cs_glob_maillage = NULL;

#if defined(_CS_HAVE_MPI)
/* Pointeur sur la structure de tampons associée au maillage principal */
cs_maillage_tmp_t  *cs_glob_maillage_tmp = NULL;
#endif


/*============================================================================
 * Prototypes de fonctions privées
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Recherche des coordonnées minimales et maximales
 *----------------------------------------------------------------------------*/

static void _cs_maillage_extents
(
 const cs_maillage_t  *maillage
);


#if defined(_CS_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Mise à jour d'un tableau des familles de cellules en cas de parallélisme
 *
 * Le rôle de cette fonction consiste à recopier les valeurs sur les
 * cellules principales en frontière parallèle d'autres domaines
 * (indices entre 1 et ncel) vers les cellules halo du domaine en
 * cours (indices ncel+1 à ncelet)
 *----------------------------------------------------------------------------*/

static void _cs_maillage_sync_fam_cel
(
 cs_maillage_t      *const maillage,     /* <-> Structure maillage associée   */
 cs_maillage_tmp_t  *const maillage_tmp  /* <-> Structure tampon maillage     */
);

#endif /* _CS_HAVE_MPI */


/*============================================================================
 *  Fonctions publiques pour API Fortran
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Recherche du numéro de groupe correspondant à un nom donné. Si le groupe
 * existe, le numéro renvoyé correspond au rang du groupe (commençant à 1)
 * dans la liste des groupes du maillage, et multiplié par -1. Cette
 * numérotation est celle utilisée dans le tableau IPRFML(NFML, NPRFML)
 * de description des familles.
 *
 * Si le groupe de nom indiqué n'existe pas, on renvoie 9999.
 *
 * Interface Fortran :
 *
 * FUNCTION NUMGRP (NOMGRP, LNGNOM)
 * ***************
 *
 * CHARACTER*       NOMGRP      : --> : Nom du groupe recherché
 * INTEGER          LNGNOM      : --> : Longueur du nom du groupe
 *----------------------------------------------------------------------------*/

cs_int_t CS_PROCF (numgrp, NUMGRP)
(
 const char       *const nomgrp,  /* --> Nom du groupe                        */
 const cs_int_t   *const lngnom   /* --> Longueur du nom                      */
 CS_ARGF_SUPP_CHAINE              /*     (arguments 'longueur' éventuels F77, */
                                  /*     inutilisés lors de l'appel mais      */
                                  /*     placés par de nombreux compilateurs) */
)
{
  int   ind, lngcmp ;
  char *nomcmp ;

  cs_maillage_t *maillage = cs_glob_maillage;

  for (ind = 0 ; ind < maillage->nbr_grp ; ind++) {

    nomcmp = maillage->nom_grp + (maillage->pos_grp[ind] - 1) ;

    lngcmp = strlen(nomcmp) ;

    if (lngcmp == *lngnom && strncmp(nomcmp, nomgrp, lngcmp) == 0)
      return (-(ind + 1)) ;

  }

  return -9999 ;

}


/*----------------------------------------------------------------------------
 * Sauvegarde des numérotations initiales des faces
 *
 * Remarque : lorsque des faces sont renumérotées, les connectivités et
 *            variables basées sur les faces sont toutes mises à jour, sauf
 *            les numéros globaux associés à ces faces (en cas de parallélisme)
 *            et conservés dans la structure maillage ('num_fac'et num_fbr') ;
 *            en effet, cette numérotation est destinée à se ramener à la
 *            numérotation initiale, notamment pour l'écriture et la lecture de
 *            fichiers suite indépendants du nombre de domaines en parallélisme
 *            ou d'une renumérotation vectorielle, et il est plus aisé de la
 *            manipuler si elle n'est pas modifiée.
 *
 * Interface Fortran :
 *
 * SUBROUTINE SAVNUM (IVECTV, IVECTB, INUMFI, INUMFB)
 * *****************
 *
 * INTEGER          IVECTV      : --> : Indicateur renum. faces internes
 * INTEGER          IVECTB      : --> : Indicateur renum. faces de bord
 * INTEGER          INUMFI      : --> : Table de renum. des faces internes
 * INTEGER          INUMFB      : --> : Table de renum. des faces de bord
 *----------------------------------------------------------------------------*/

void CS_PROCF (savnum, SAVNUM)
(
 const cs_int_t   *const ivectv,  /* --> Indicateur renum. faces internes     */
 const cs_int_t   *const ivectb,  /* --> Indicateur renum. faces de bord      */
 const cs_int_t   *const inumfi,  /* --> Table de renum. des faces internes   */
 const cs_int_t   *const inumfb   /* --> Table de renum. des faces de bord    */
)
{
  cs_int_t ind;

  cs_maillage_t *maillage = cs_glob_maillage;

  /* Sauvegarde correspondance des faces internes -> faces internes initiales */

  if (*ivectv != 0) {

    BFT_MALLOC (maillage->num_fac_ini, maillage->nbr_fac, cs_int_t);

    for (ind = 0 ; ind < maillage->nbr_fac ; ind++)
      maillage->num_fac_ini[ind] = inumfi[ind];

  }

  /* Sauvegarde correspondance des faces de bord -> faces de bord initiales */

  if (*ivectb != 0) {

    BFT_MALLOC (maillage->num_fbr_ini, maillage->nbr_fbr, cs_int_t);

    for (ind = 0 ; ind < maillage->nbr_fbr ; ind++)
      maillage->num_fbr_ini[ind] = inumfb[ind];

  }

}


/*============================================================================
 * Fonctions publiques
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Création d'une structure maillage
 *----------------------------------------------------------------------------*/

cs_maillage_t * cs_maillage_cree
(
  void
)
{
  cs_maillage_t * maillage;

  BFT_MALLOC (maillage, 1, cs_maillage_t);

  maillage->dim     = 3;
  maillage->num_dom = cs_glob_base_rang + 1;
  maillage->nbr_dom = 0;
  maillage->nbr_per = 0;
  maillage->ind_type_voiset = CS_MAILLAGE_TYPE_VOISET_SANS ;

  maillage->nbr_cel = 0;
  maillage->nbr_fac = 0;
  maillage->nbr_fbr = 0;
  maillage->nbr_som = 0;
  maillage->lng_fac_som = 0;
  maillage->lng_fbr_som = 0;
  maillage->nbr_cel_fac_par = 0;
  maillage->nbr_dom_fac_par = 0;
  maillage->nbr_cel_etendu = 0;
  maillage->nbr_cel_fac_par_voiset = 0;
  maillage->nbr_dom_fac_par_voiset = 0;
  maillage->nbr_val_connect_voiset_cel_cel_dom = 0;

  maillage->nbr_cel_glob = 0;
  maillage->nbr_fac_glob = 0;
  maillage->nbr_fbr_glob = 0;
  maillage->nbr_som_glob = 0;

  maillage->coo_som = NULL;
  maillage->fac_cel = NULL;
  maillage->fbr_cel = NULL;
  maillage->pos_fac_som = NULL;
  maillage->pos_fbr_som = NULL;
  maillage->val_fac_som = NULL;
  maillage->val_fbr_som = NULL;

  maillage->num_cel = NULL;
  maillage->num_fac = NULL;
  maillage->num_fbr = NULL;
  maillage->num_som = NULL;

  maillage->pos_dom_fac_par = NULL;
  maillage->pos_per_fac_par = NULL;
  maillage->num_cel_fac_par = NULL;
  maillage->num_dom_fac_par = NULL;

  maillage->liste_param_per = NULL;

  maillage->pos_dom_fac_par_voiset = NULL;
  maillage->pos_per_fac_par_voiset = NULL;
  maillage->num_cel_fac_par_voiset = NULL;
  maillage->num_dom_fac_par_voiset = NULL;
  maillage->coord_cel_avec_voiset = NULL;

  maillage->pos_connect_voiset_cel_cel_dom = NULL;
  maillage->val_connect_voiset_cel_cel_dom = NULL;

  maillage->num_fac_ini = NULL;
  maillage->num_fbr_ini = NULL;

  maillage->nbr_grp = 0;
  maillage->pos_grp = NULL;
  maillage->nom_grp = NULL;

  maillage->nbr_prop_fam_max = 0;
  maillage->nbr_fam = 0;

  maillage->prop_fam = NULL;
  maillage->fam_cel  = NULL;
  maillage->fam_fbr  = NULL;

  return (maillage);
}


/*----------------------------------------------------------------------------
 * Destruction d'une structure maillage
 *----------------------------------------------------------------------------*/

cs_maillage_t * cs_maillage_detruit
(
  cs_maillage_t * maillage
)
{

  BFT_FREE(maillage->coo_som);
  BFT_FREE(maillage->fac_cel);
  BFT_FREE(maillage->fbr_cel);
  BFT_FREE(maillage->pos_fac_som);
  BFT_FREE(maillage->pos_fbr_som);
  BFT_FREE(maillage->val_fac_som);
  BFT_FREE(maillage->val_fbr_som);

  BFT_FREE (maillage->num_cel);
  BFT_FREE (maillage->num_fac);
  BFT_FREE (maillage->num_fbr);
  BFT_FREE (maillage->num_som);

  BFT_FREE (maillage->num_cel_fac_par);
  BFT_FREE (maillage->pos_dom_fac_par);
  BFT_FREE (maillage->pos_per_fac_par);
  BFT_FREE (maillage->num_dom_fac_par);

  BFT_FREE (maillage->liste_param_per);

  BFT_FREE (maillage->num_cel_fac_par_voiset);
  BFT_FREE (maillage->pos_dom_fac_par_voiset);
  BFT_FREE (maillage->pos_per_fac_par_voiset);
  BFT_FREE (maillage->num_dom_fac_par_voiset);
  BFT_FREE (maillage->coord_cel_avec_voiset);

  BFT_FREE (maillage->pos_connect_voiset_cel_cel_dom);
  BFT_FREE (maillage->val_connect_voiset_cel_cel_dom);

  BFT_FREE (maillage->num_fac_ini);
  BFT_FREE (maillage->num_fbr_ini);

  BFT_FREE(maillage->pos_grp);
  BFT_FREE(maillage->nom_grp);

  BFT_FREE(maillage->prop_fam);
  BFT_FREE(maillage->fam_cel);
  BFT_FREE(maillage->fam_fbr);

  BFT_FREE (maillage);

  return (maillage);
}


/*----------------------------------------------------------------------------
 * Renumérotation des sommets de manière à assurer que :
 * si i < j, maillage->num_som[i] < maillage->num_som[j]
 * (ce qui n'est pas assuré par la numérotation initialement
 * fournie par l'Enveloppe).
 *----------------------------------------------------------------------------*/

void cs_maillage_ordonne_sommets
(
 cs_maillage_t      *const maillage      /* <-> Structure maillage associée   */
)
{
  /* Variables locales */

  cs_int_t    ind, ind_dim;
  cs_int_t    taille;

  cs_int_t    dim = 3;
  cs_int_t    nbr_som = 0;
  cs_int_t   *num_tmp = NULL;
  cs_real_t  *coord_tmp = NULL;
  fvm_lnum_t *ordre_som = NULL;
  fvm_lnum_t *renum_som = NULL;
  fvm_gnum_t *num_g_som = NULL;

  assert(maillage != NULL);


  /* Aucun traitement en mode séquentiel */

  if (maillage->num_som == NULL)
    return;

  dim     = maillage->dim;
  nbr_som = maillage->nbr_som;


  /* Calcul de la renumérotation des sommets */

  BFT_MALLOC(num_g_som, nbr_som, fvm_gnum_t);

  for (ind = 0 ; ind < nbr_som ; ind++)
    num_g_som[ind] = maillage->num_som[ind];

  ordre_som = fvm_order_local(NULL, num_g_som, (size_t)nbr_som);

  BFT_FREE(num_g_som);

  renum_som = fvm_order_local_renumbering(ordre_som, (size_t)nbr_som);

  BFT_FREE(ordre_som);


  /* Application de la renumérotation des sommets à la connectivité
     faces -> sommets */

  if (maillage->nbr_fac > 0) {
    for (ind = 0, taille = maillage->pos_fac_som[maillage->nbr_fac] - 1 ;
         ind < taille ;
         ind++)
      maillage->val_fac_som[ind] = renum_som[maillage->val_fac_som[ind] - 1] + 1;
  }

  if (maillage->nbr_fbr > 0) {
    for (ind = 0, taille = maillage->pos_fbr_som[maillage->nbr_fbr] - 1 ;
         ind < taille ;
         ind++)
      maillage->val_fbr_som[ind] = renum_som[maillage->val_fbr_som[ind] - 1] + 1;
  }


  /* Mise à jour des coordonnées */

  BFT_MALLOC(coord_tmp, nbr_som * dim, cs_real_t);

  for (ind = 0 ; ind < nbr_som ; ind++) {
    for (ind_dim = 0 ; ind_dim < dim ; ind_dim++) {
      coord_tmp[renum_som[ind]*dim + ind_dim]
        = maillage->coo_som[ind*dim + ind_dim];
    }
  }
  memcpy(maillage->coo_som, coord_tmp, (nbr_som * dim * sizeof(cs_real_t)));

  BFT_FREE(coord_tmp);


  /* Mise à jour de la numérotation globale */

  BFT_MALLOC(num_tmp, nbr_som, cs_int_t);

  for (ind = 0 ; ind < nbr_som ; ind++) {
    num_tmp[renum_som[ind]] = maillage->num_som[ind];
  }
  memcpy(maillage->num_som, num_tmp, (nbr_som * sizeof(cs_int_t)));

  BFT_FREE(num_tmp);


  /* Libération mémoire */

  BFT_FREE(renum_som);
}


/*----------------------------------------------------------------------------
 * Affichage d'informations relatives à un maillage
 *----------------------------------------------------------------------------*/

void cs_maillage_info
(
 const cs_maillage_t  *maillage
)
{
  _cs_maillage_extents(maillage);
}


#if defined(_CS_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Création d'une structure de tampons associée à un maillage
 *----------------------------------------------------------------------------*/

cs_maillage_tmp_t * cs_maillage_tmp_cree
(
 cs_maillage_t  * maillage
)
{
  cs_int_t             nbr_val_var_assembl ;
  cs_int_t             nbr_val_var_assembl_voiset ;
  cs_int_t             ind_dom ;
  cs_int_t             ind_dom_fac_par ;
  cs_int_t             icpt ;

  cs_int_t            *nbr_cel_attendu;
  cs_int_t            *nbr_cel_a_envoyer;

  cs_maillage_tmp_t  * maillage_tmp = NULL;

  if (cs_glob_base_nbr <= 1)
    return NULL;

  BFT_MALLOC (maillage_tmp, 1, cs_maillage_tmp_t);

  /* Requetes et status surdimensionnés, mais pas grave  */

  BFT_MALLOC (maillage_tmp->mpi_request, maillage->nbr_dom * 2,
              MPI_Request);
  BFT_MALLOC (maillage_tmp->mpi_status,  maillage->nbr_dom * 2,
              MPI_Status);

  /*
                               ATTENTION

    Les halos entrant et sortant n'ont pas forcément la meme taille :
    pour un voisinage étendu basé sur les sommets (dans le halo standard
    ou séparé), il est nécessaire de prévoir des tableaux distincts
    pour les données entrantes et sortantes du processeur courant.

    La modification pourrait être limitée à ce cas, mais elle conduirait
    en pratique à dupliquer les fonctions de communication, ce qui rendrait
    les tests moins faciles.

    La principale difficulté consiste à dimensionner les tableaux relatifs
    aux données sortantes (pour les données entrantes, les informations
    sont lues dans le fichier de communication avec l'enveloppe).


    On alloue ci-dessous :
      pos_dom_var_assembl
        num_dom_var_assembl
        var_assembl
        num_cel_loc_par
    On calcule
      nbr_dom_var_assembl
        pos_dom_var_assembl
        num_dom_var_assembl

    On procède de même pour le voisinage étendu, s'il est traité séparément.
      En outre, on réserve une variable maillage_tmp->var_cel_avec_voiset
        qui permettra de stocker une variable ncelet+voinage étendu séparé

  */

  BFT_MALLOC(nbr_cel_attendu, maillage->nbr_dom, cs_int_t);
  BFT_MALLOC(nbr_cel_a_envoyer, maillage->nbr_dom, cs_int_t);

  /*
    Pour allouer var_assembl, on calcule sa taille en demandant
    aux processeurs voisins la quantité de données qu'ils attendent
    du processeur courant.
  */

  for (ind_dom = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++)
    nbr_cel_attendu[ind_dom] = 0 ;

  for (ind_dom_fac_par = 0 ;
       ind_dom_fac_par < maillage->nbr_dom_fac_par ;
       ind_dom_fac_par++) {
    ind_dom = maillage->num_dom_fac_par[ind_dom_fac_par] - 1;
    nbr_cel_attendu[ind_dom]
      =   maillage->pos_dom_fac_par[ind_dom_fac_par + 1]
        - maillage->pos_dom_fac_par[ind_dom_fac_par];
  }

  /* Envoi au processeur j de nbr_cel_attendu[j], et
     réception en nbr_cel_a_envoyer[i] la valeur correspondante
     fournie par le processeur i */

  MPI_Alltoall(nbr_cel_attendu, 1, CS_MPI_INT,
               nbr_cel_a_envoyer, 1, CS_MPI_INT,
               cs_glob_base_mpi_comm);

  /*
  MPI_Alltoall(nbr_cel_attendu, maillage->nbr_dom, CS_MPI_INT,
               nbr_cel_a_envoyer, maillage->nbr_dom, CS_MPI_INT,
               cs_glob_base_mpi_comm);
  */

  /* Calcul du nombre de domaines auxquels on envoie effectivement
     des voisins */

  for (ind_dom = 0, icpt = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++) {
    if (nbr_cel_a_envoyer[ind_dom] > 0)
      icpt++;
  }
  maillage_tmp->nbr_dom_var_assembl = icpt;

  /* Tableau des numéro des voisins
     auquel le processeur courant envoie des informations. */

  BFT_MALLOC (maillage_tmp->num_dom_var_assembl,
              maillage_tmp->nbr_dom_var_assembl, cs_int_t);

  /* Tableau de position des cases de var_assembl associées à un voisin
     donné auquel le processeur courant envoie des informations. */

  BFT_MALLOC (maillage_tmp->pos_dom_var_assembl,
              maillage_tmp->nbr_dom_var_assembl + 1, cs_int_t);

  /* Construction de num_dom_var_assembl et de pos_dom_var_assembl */

  maillage_tmp->pos_dom_var_assembl[0] = 1;

  for (ind_dom = 0, icpt = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++) {
    if (nbr_cel_a_envoyer[ind_dom] > 0) {
      maillage_tmp->num_dom_var_assembl[icpt] = ind_dom + 1;
      maillage_tmp->pos_dom_var_assembl[icpt+1]
        =   maillage_tmp->pos_dom_var_assembl[icpt]
          + nbr_cel_a_envoyer[ind_dom];
      icpt++;
    }
  }

  assert(icpt == maillage_tmp->nbr_dom_var_assembl);

  /* Allocation du halo sortant (variable d'assemblage et tableau
     destiné à contenir le numéro local des cellules à y verser) */

  nbr_val_var_assembl =
    maillage_tmp->pos_dom_var_assembl[maillage_tmp->nbr_dom_var_assembl] - 1;

  BFT_MALLOC (maillage_tmp->var_assembl,     nbr_val_var_assembl, cs_real_t);
  BFT_MALLOC (maillage_tmp->num_cel_loc_par, nbr_val_var_assembl, cs_int_t);


  /* Même chose pour le voisinage étendu s'il est traité séparément du
     halo classique */

  if(maillage->ind_type_voiset == CS_MAILLAGE_TYPE_VOISET_SEPARE) {

    /*
      Pour allouer var_assembl_voiset, on calcule sa taille en demandant
      aux processeurs voisins la quantité de données qu'ils attendent
      du processeur courant.
    */

    for (ind_dom = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++)
      nbr_cel_attendu[ind_dom] = 0 ;

    for (ind_dom_fac_par = 0 ;
         ind_dom_fac_par < maillage->nbr_dom_fac_par_voiset ;
         ind_dom_fac_par++) {
      ind_dom = maillage->num_dom_fac_par_voiset[ind_dom_fac_par] - 1;
      nbr_cel_attendu[ind_dom]
        =   maillage->pos_dom_fac_par_voiset[ind_dom_fac_par + 1]
          - maillage->pos_dom_fac_par_voiset[ind_dom_fac_par];
    }

    /* Envoi au processeur j de nbr_cel_attendu[j], et
       réception en nbr_cel_a_envoyer[i] la valeur correspondante
       fournie par le processeur i */

    MPI_Alltoall(nbr_cel_attendu, 1, CS_MPI_INT,
                 nbr_cel_a_envoyer, 1, CS_MPI_INT,
                 cs_glob_base_mpi_comm);

    /* Calcul du nombre de domaines auxquels on envoie effectivement
     des voisins */

    for (ind_dom = 0, icpt = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++) {
      if (nbr_cel_a_envoyer[ind_dom] > 0)
        icpt++;
    }
    maillage_tmp->nbr_dom_var_assembl_voiset = icpt ;

    /* Tableau des numéro des voisins étendus
       auquel le processeur courant envoie des informations. */

    BFT_MALLOC (maillage_tmp->num_dom_var_assembl_voiset,
                maillage_tmp->nbr_dom_var_assembl_voiset, cs_int_t);

    /* Tableau de position des cases de var_assembl_voiset associées à un
       voisin donné auquel le processeur courant envoie des informations. */

    BFT_MALLOC (maillage_tmp->pos_dom_var_assembl_voiset,
                maillage_tmp->nbr_dom_var_assembl_voiset + 1, cs_int_t);

    /* Construction de num_dom_var_assembl_voiset et
       de pos_dom_var_assembl_voiset */

    maillage_tmp->pos_dom_var_assembl_voiset[0] = 1;

    for (ind_dom = 0, icpt = 0 ; ind_dom < maillage->nbr_dom ; ind_dom++) {
      if (nbr_cel_a_envoyer[ind_dom] > 0) {
        maillage_tmp->num_dom_var_assembl_voiset[icpt] = ind_dom + 1;
        maillage_tmp->pos_dom_var_assembl_voiset[icpt+1]
          =   maillage_tmp->pos_dom_var_assembl_voiset[icpt]
            + nbr_cel_a_envoyer[ind_dom];
        icpt++;
      }
    }

    assert(icpt == maillage_tmp->nbr_dom_var_assembl_voiset);

    /* Allocation du halo sortant (variable d'assemblage et tableau
       destiné à contenir le numéro local des cellules à y verser) */

    nbr_val_var_assembl_voiset
      = maillage_tmp->pos_dom_var_assembl_voiset
          [maillage_tmp->nbr_dom_var_assembl_voiset] - 1;

    BFT_MALLOC (maillage_tmp->var_assembl_voiset,
                nbr_val_var_assembl_voiset, cs_real_t);
    BFT_MALLOC (maillage_tmp->num_cel_loc_par_voiset,
                nbr_val_var_assembl_voiset, cs_int_t);


    /* Allocation d'une variable allongée pour le halo entrant
       (voisinage étendu séparé)  */
    if(maillage->nbr_cel_fac_par_voiset > 0)
      BFT_MALLOC (maillage_tmp->var_cel_avec_voiset,
                  maillage->nbr_cel +
                  maillage->nbr_cel_fac_par +
                  maillage->nbr_cel_fac_par_voiset, cs_real_t);
    else
      maillage_tmp->var_cel_avec_voiset = NULL ;

  }

  /* Si voisinage étendu n'est pas traité séparément du halo classique
     (ou s'il n'existe pas) : tout nul */

  else {
    maillage_tmp->nbr_dom_var_assembl_voiset = 0 ;
    maillage_tmp->pos_dom_var_assembl_voiset = NULL ;
    maillage_tmp->num_dom_var_assembl_voiset = NULL ;
    maillage_tmp->num_cel_loc_par_voiset     = NULL ;
    maillage_tmp->var_assembl_voiset         = NULL ;
    maillage_tmp->var_cel_avec_voiset        = NULL ;
  }

  BFT_FREE (nbr_cel_attendu);
  BFT_FREE (nbr_cel_a_envoyer);

  return (maillage_tmp);

}


/*----------------------------------------------------------------------------
 * Destruction d'une structure de tampons associée à un maillage
 *----------------------------------------------------------------------------*/

cs_maillage_tmp_t * cs_maillage_tmp_detruit
(
  cs_maillage_tmp_t * maillage_tmp
)
{
  if (maillage_tmp == NULL)
    return NULL;

  /* Libération posant problème avec lam-mpi */
  BFT_FREE (maillage_tmp->mpi_request);
  BFT_FREE (maillage_tmp->mpi_status);

  BFT_FREE (maillage_tmp->num_cel_loc_par);
  BFT_FREE (maillage_tmp->pos_dom_var_assembl);
  BFT_FREE (maillage_tmp->num_dom_var_assembl);
  BFT_FREE (maillage_tmp->var_assembl);

  BFT_FREE (maillage_tmp->num_cel_loc_par_voiset);
  BFT_FREE (maillage_tmp->pos_dom_var_assembl_voiset);
  BFT_FREE (maillage_tmp->num_dom_var_assembl_voiset);
  BFT_FREE (maillage_tmp->var_assembl_voiset);

  BFT_FREE (maillage_tmp->var_cel_avec_voiset);

  BFT_FREE (maillage_tmp);

  return (maillage_tmp);
}


/*----------------------------------------------------------------------------
 * Tableaux supplémentaires d'un maillage pour le parallélisme
 *----------------------------------------------------------------------------*/

void cs_maillage_init_parallel
(
 cs_maillage_t      *maillage,
 cs_maillage_tmp_t  *maillage_tmp
)
{

  cs_int_t     lbloc, ind, ind_dom;
  cs_int_t    *buf;
  fvm_gnum_t   nbr_ent_glob[4], num_ent_max[4];
  int          cpt_request ;

  if (cs_glob_base_nbr <= 1)
    return;

  /* Dimensions globales du maillage */

  num_ent_max[0] = maillage->nbr_cel;
  MPI_Allreduce (num_ent_max, nbr_ent_glob, 1, FVM_MPI_GNUM, MPI_SUM,
                 cs_glob_base_mpi_comm);

  num_ent_max[1] = 0;
  for (ind = 0 ; ind < maillage->nbr_fac ; ind++) {
    if (maillage->num_fac[ind] > num_ent_max[1])
      num_ent_max[1] = maillage->num_fac[ind];
  }

  num_ent_max[2] = 0;
  for (ind = 0 ; ind < maillage->nbr_fbr ; ind++) {
    if (maillage->num_fbr[ind] > num_ent_max[2])
      num_ent_max[2] = maillage->num_fbr[ind];
  }

  num_ent_max[3] = 0;
  for (ind = 0 ; ind < maillage->nbr_som ; ind++) {
    if (maillage->num_som[ind] > num_ent_max[3])
      num_ent_max[3] = maillage->num_som[ind];
  }

  MPI_Allreduce (num_ent_max + 1, nbr_ent_glob + 1, 3, FVM_MPI_GNUM, MPI_MAX,
                 cs_glob_base_mpi_comm);

  maillage->nbr_cel_glob = nbr_ent_glob[0];
  maillage->nbr_fac_glob = nbr_ent_glob[1];
  maillage->nbr_fbr_glob = nbr_ent_glob[2];
  maillage->nbr_som_glob = nbr_ent_glob[3];


  /*
    On souhaite disposer du numéro local des cellules à envoyer aux voisins
  */


  /*
    Émission et réception de messages des autres domaines
    (avec des communications non bloquantes)
  */

  cpt_request = 0 ;

  /* On envoie aux voisins le numéro (dans leur numérotation locale) des
     cellules que l'on souhaite recevoir de leur part */

  for (ind_dom = 0 ; ind_dom < maillage->nbr_dom_fac_par ; ind_dom++) {

    lbloc =   maillage->pos_dom_fac_par[ind_dom + 1]
            - maillage->pos_dom_fac_par[ind_dom] ;

    buf = maillage->num_cel_fac_par + maillage->pos_dom_fac_par[ind_dom] - 1;

    MPI_Isend (buf,
               lbloc,
               CS_MPI_INT,
               maillage->num_dom_fac_par[ind_dom] - 1,
               maillage->num_dom - 1,
               cs_glob_base_mpi_comm,
               &(maillage_tmp->mpi_request[cpt_request++]));

  }

  /* On recoit des voisins le numéro (dans la numérotation locale courante)
     des cellules qu'il faudra leur envoyer, dans l'ordre */

  for (ind_dom = 0 ; ind_dom < maillage_tmp->nbr_dom_var_assembl ; ind_dom++) {

    lbloc =   maillage_tmp->pos_dom_var_assembl[ind_dom + 1]
            - maillage_tmp->pos_dom_var_assembl[ind_dom] ;

    buf = maillage_tmp->num_cel_loc_par
      + maillage_tmp->pos_dom_var_assembl[ind_dom] - 1;

    MPI_Irecv (buf,
               lbloc,
               CS_MPI_INT,
               maillage_tmp->num_dom_var_assembl[ind_dom] - 1,
               maillage_tmp->num_dom_var_assembl[ind_dom] - 1,
               cs_glob_base_mpi_comm,
               &(maillage_tmp->mpi_request[cpt_request++]));

  }

  MPI_Waitall (cpt_request,
               maillage_tmp->mpi_request,
               maillage_tmp->mpi_status);

  /* Synchronisation du tableau des familles des cellules */

  _cs_maillage_sync_fam_cel (maillage,
                             maillage_tmp) ;


  /*
    Pour le voisinage étendu, s'il est traité séparément : de même.
  */

  if(maillage->ind_type_voiset == CS_MAILLAGE_TYPE_VOISET_SEPARE) {

    /*
      Émission et réception de messages des autres domaines pour disposer
      du numéro local des cellules à envoyer
      (avec des communications non bloquantes)
    */

    cpt_request = 0 ;


    /* On envoie aux voisins le numéro (dans leur numérotation locale) des
       cellules que l'on souhaite recevoir de leur part */

    for (ind_dom = 0 ; ind_dom < maillage->nbr_dom_fac_par_voiset ; ind_dom++) {

      lbloc =   maillage->pos_dom_fac_par_voiset[ind_dom + 1]
              - maillage->pos_dom_fac_par_voiset[ind_dom] ;

      buf = maillage->num_cel_fac_par_voiset +
        maillage->pos_dom_fac_par_voiset[ind_dom] - 1;

      MPI_Isend (buf,
                 lbloc,
                 CS_MPI_INT,
                 maillage->num_dom_fac_par_voiset[ind_dom] - 1,
                 maillage->num_dom - 1,
                 cs_glob_base_mpi_comm,
                 &(maillage_tmp->mpi_request[cpt_request++]));
    }

    /* On recoit des voisins le numéro (dans la numérotation locale courante)
       des cellules qu'il faudra leur envoyer, dans l'ordre */

    for (ind_dom = 0 ;
         ind_dom < maillage_tmp->nbr_dom_var_assembl_voiset ; ind_dom++) {

      lbloc =   maillage_tmp->pos_dom_var_assembl_voiset[ind_dom + 1]
              - maillage_tmp->pos_dom_var_assembl_voiset[ind_dom] ;

      buf = maillage_tmp->num_cel_loc_par_voiset
          + maillage_tmp->pos_dom_var_assembl_voiset[ind_dom] - 1;

      MPI_Irecv (buf,
                 lbloc,
                 CS_MPI_INT,
                 maillage_tmp->num_dom_var_assembl_voiset[ind_dom] - 1,
                 maillage_tmp->num_dom_var_assembl_voiset[ind_dom] - 1,
                 cs_glob_base_mpi_comm,
                 &(maillage_tmp->mpi_request[cpt_request++]));

    }

    MPI_Waitall (cpt_request,
                 maillage_tmp->mpi_request,
                 maillage_tmp->mpi_status);

  }

}
#endif /* _CS_HAVE_MPI */


/*============================================================================
 * Fonctions privées
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Recherche des coordonnées minimales et maximales
 *----------------------------------------------------------------------------*/

static void _cs_maillage_extents
(
 const cs_maillage_t  *maillage
)
{
  cs_int_t  isom, iloc;

  cs_int_t  dim = maillage->dim;

  /* Allocation des structures s'il ne s'agit pas d'une mise à jour */

  if (maillage->nbr_som_glob > 0) {

    cs_real_t xyz_min[3] = { 1.e127,  1.e127,  1.e127};
    cs_real_t xyz_max[3] = {-1.e127, -1.e127, -1.e127};

    for (isom = 0 ; isom < maillage->nbr_som ; isom++) {

      for (iloc = 0 ; iloc < dim ; iloc++) {
        if (maillage->coo_som[isom*dim + iloc] < xyz_min[iloc])
          xyz_min[iloc] = maillage->coo_som[isom*dim + iloc];
        if (maillage->coo_som[isom*dim + iloc] > xyz_max[iloc])
          xyz_max[iloc] = maillage->coo_som[isom*dim + iloc];
      }

    }

#if defined(_CS_HAVE_MPI)

    if (cs_glob_base_nbr > 1) {

      cs_real_t xyz_min_g[3];
      cs_real_t xyz_max_g[3];

      MPI_Allreduce (xyz_min, xyz_min_g, dim, CS_MPI_REAL, MPI_MIN,
                     cs_glob_base_mpi_comm);
      MPI_Allreduce (xyz_max, xyz_max_g, dim, CS_MPI_REAL, MPI_MAX,
                     cs_glob_base_mpi_comm);

      for (iloc = 0 ; iloc < dim ; iloc++) {
        xyz_min[iloc] = xyz_min_g[iloc];
        xyz_max[iloc] = xyz_max_g[iloc];
      }

    }
#endif /* _CS_HAVE_MPI */

    bft_printf(_("\n"
                 " ** COORDONNEES DU MAILLAGE      MINIMALE    ET MAXIMALE\n"
                 "                       X : %14.7e %14.7e\n"
                 "                       Y : %14.7e %14.7e\n"
                 "                       Z : %14.7e %14.7e\n"),
               xyz_min[0], xyz_max[0], xyz_min[1], xyz_max[1],
               xyz_min[2], xyz_max[2]);

  }

}


#if defined(_CS_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Mise à jour d'un tableau des familles de cellules en cas de parallélisme
 *
 * Le rôle de cette fonction consiste à recopier les valeurs sur les
 * cellules principales en frontière parallèle d'autres domaines
 * (indices entre 1 et ncel) vers les cellules halo du domaine en
 * cours (indices ncel+1 à ncelet)
 *----------------------------------------------------------------------------*/

static void _cs_maillage_sync_fam_cel
(
 cs_maillage_t      *const maillage,     /* <-> Structure maillage associée   */
 cs_maillage_tmp_t  *const maillage_tmp  /* <-> Structure tampon maillage     */
)
{

  /* Variables locales */

  cs_int_t    dbloc, lbloc;
  cs_int_t    ind, ind_dom;
  cs_int_t   *tab_assembl = NULL;
  cs_int_t   *buf = NULL;
  int         cpt_request = 0;

  /* Aucun traitement en mode séquentiel */

  if (cs_glob_base_nbr < 2)
    return;

  /*
    On utilise ici le tampon var_assembl de maillage_tmp
    (normalement prévu pour contenir des réels) pour des entiers
  */

  assert(sizeof(cs_int_t) <= sizeof(cs_real_t));
  tab_assembl = (cs_int_t *)maillage_tmp->var_assembl;

  /* Émission vers les autres domaines (communications non bloquantes) */
  /*-------------------------------------------------------------------*/

  for (ind_dom = 0 ; ind_dom < maillage_tmp->nbr_dom_var_assembl ; ind_dom++) {

    /* Test sur le numéro de maillage utile en périodicité */

    if (maillage_tmp->num_dom_var_assembl[ind_dom] != maillage->num_dom) {

      /* On envoie aux voisins, dans une variable d'assemblage */

      dbloc = maillage_tmp->pos_dom_var_assembl[ind_dom] - 1;

      lbloc =   maillage_tmp->pos_dom_var_assembl[ind_dom + 1]
              - maillage_tmp->pos_dom_var_assembl[ind_dom] ;

      for (ind = 0 ; ind < lbloc ; ind++)
        tab_assembl[dbloc + ind]
          = maillage->fam_cel[maillage_tmp->num_cel_loc_par[dbloc + ind] - 1];

      buf = tab_assembl + dbloc ;

      MPI_Isend (buf,
                 lbloc,
                 CS_MPI_INT,
                 maillage_tmp->num_dom_var_assembl[ind_dom] - 1,
                 maillage->num_dom - 1,
                 cs_glob_base_mpi_comm,
                 &(maillage_tmp->mpi_request[cpt_request++]));

    }

  }

  /* Émission depuis les autres domaines (communications non bloquantes) */
  /*---------------------------------------------------------------------*/

  for (ind_dom = 0 ; ind_dom < maillage->nbr_dom_fac_par ; ind_dom++) {

    /* Test sur le numéro de maillage utile en périodicité */
    /* On le laisse par cohérence avec parcom, mais on pourrait
       s'en affranchir, car en périodicité, on ne fera rien de plus */

    if (maillage->num_dom_fac_par[ind_dom] != maillage->num_dom) {

      /* On réceptionne des voisins directement dans le halo */

      dbloc = maillage->pos_dom_fac_par[ind_dom] - 1;

      lbloc = maillage->pos_dom_fac_par[ind_dom + 1]
            - maillage->pos_dom_fac_par[ind_dom] ;

      buf = maillage->fam_cel + maillage->nbr_cel + dbloc ;

      MPI_Irecv (buf,
                 lbloc,
                 CS_MPI_INT,
                 maillage->num_dom_fac_par[ind_dom] - 1,
                 maillage->num_dom_fac_par[ind_dom] - 1,
                 cs_glob_base_mpi_comm,
                 &(maillage_tmp->mpi_request[cpt_request++]));

    }

  }

  /* On synchronise après que tout le monde ait recu tous les messages */

  MPI_Waitall (cpt_request,
               maillage_tmp->mpi_request,
               maillage_tmp->mpi_status);

}

#endif


#ifdef __cplusplus
}
#endif /* __cplusplus */
