/*============================================================================
*
*                    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
*
*============================================================================*/

/*============================================================================
 * Interfaces Fortran pour la lecture des données au format "SolCom"
 *============================================================================*/

/* includes système */

#include <assert.h>
#include <stdarg.h>
#include <string.h>


/* Includes BFT */

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

/* Includes FVM */

#include <fvm_nodal.h>
#include <fvm_nodal_append.h>

/* Includes librairie */

#include "cs_base.h"

#include "cs_maillage.h"
#include "cs_post.h"

#include "cs_maillage_solcom.h"

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


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

/* Nombre de sommets, tétraèdres, pyramides, prismes, et hexaèdres */

static cs_int_t  cs_glob_nsom = 0;
static cs_int_t  cs_glob_ntetra = 0;
static cs_int_t  cs_glob_npyram = 0;
static cs_int_t  cs_glob_nprism = 0;
static cs_int_t  cs_glob_nhexae = 0;


/*============================================================================
 * Prototypes de fonctions externes publiques
 *============================================================================*/


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

/*----------------------------------------------------------------------------
 * Allocation de mémoire pour la lecture d'un fichier au format "SolCom" ;
 *----------------------------------------------------------------------------*/

static void cs_loc_maillage_solcom_alloc_mem
(
 cs_maillage_t      *const maillage,      /* <-> maillage associé             */
 cs_maillage_grd_t  *const maillage_grd   /* <-> grandeurs associés           */
);


/*----------------------------------------------------------------------------
 * Transfert d'une partie de la connectivité nodale à une structure FVM ;
 *----------------------------------------------------------------------------*/

static void cs_loc_maillage_solcom_ajoute
(
 fvm_nodal_t    *maillage_ext,            /* <-> maillage à compléter         */
 cs_int_t        nbr_elt,                 /* --> nombre d'élements à ajouter  */
 fvm_element_t   type,                    /* --> type de section à ajouter    */
 cs_int_t       *connect,                 /* --> connectivité à transférer    */
 cs_int_t       *cpt_elt_tot              /* <-> compteur total d'éléments    */
);


/*============================================================================
 * Prototypes de fonctions Fortran appellées
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Lecture des tableaux entités géométriques
 *----------------------------------------------------------------------------*/

void CS_PROCF (letgeo, LETGEO)
(
 const cs_int_t  *ndim,      /* --> dimension de l'espace                     */
 const cs_int_t  *ncelet,    /* --> nombre de cellules étendu                 */
 const cs_int_t  *ncel,      /* --> nombre de cellules                        */
 const cs_int_t  *nfac,      /* --> nombre de faces internes                  */
 const cs_int_t  *nfabor,    /* --> nombre de faces de bord                   */
 const cs_int_t  *nfml,      /* --> nombre de familles                        */
 const cs_int_t  *nprfml,    /* --> nombre de proprietes des familles         */
 const cs_int_t  *nnod,      /* --> nombre de sommets                         */
 const cs_int_t  *lndfac,    /* --> longueur de nodfac                        */
 const cs_int_t  *lndfbr,    /* --> longueur de nodfbr                        */
 const cs_int_t  *ntetra,    /* --> nombre de tetraèdres du maillage          */
 const cs_int_t  *npyram,    /* --> nombre de pyramides du maillage           */
 const cs_int_t  *nprism,    /* --> nombre de prismes du maillage             */
 const cs_int_t  *nhexae,    /* --> nombre d'hexaèdres du maillage            */
       cs_int_t  *inodal,    /* <-- indique si l'on doit lire la connectivite */
                             /*     nodale pour le post traitement            */
       cs_int_t   ifacel[],  /* <-- connect. faces internes / cellules        */
       cs_int_t   ifabor[],  /* <-- connect. faces de bord / cellules         */
       cs_int_t   ifmfbr[],  /* <-- liste des familles des faces bord         */
       cs_int_t   ifmcel[],  /* <-- liste des familles des cellules           */
       cs_int_t   iprfml[],  /* <-- liste des propriétés des familles         */
       cs_int_t   icotet[],  /* <-- connectivité nodale des tétraèdres        */
       cs_int_t   icopyr[],  /* <-- connectivité nodale des pyramides         */
       cs_int_t   icopri[],  /* <-- connectivité nodale des prismes           */
       cs_int_t   icohex[],  /* <-- connectivité nodale des hexaèdres         */
       cs_int_t   ipnfac[],  /* <-- rang ds nodfac 1er sommet faces int       */
       cs_int_t   nodfac[],  /* <-- numéro des sommets des faces int          */
       cs_int_t   ipnfbr[],  /* <-- rang ds nodfbr 1er sommt faces brd        */
       cs_int_t   nodfbr[],  /* <-- numéro des sommets des faces bord         */
       cs_real_t  xyzcen[],  /* <-- c.d.g. des cellules                       */
       cs_real_t  surfac[],  /* <-- surfaces des faces internes               */
       cs_real_t  surfbo[],  /* <-- surfaces des faces de bord                */
       cs_real_t  cdgfac[],  /* <-- c.d.g. des faces internes                 */
       cs_real_t  cdgfbo[],  /* <-- c.d.g. des faces de bord                  */
       cs_real_t  xyznod[]   /* <-- coordonnées des sommets                   */
);


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

/*----------------------------------------------------------------------------
 * Mise à jour des informations de dimensionnement maillage après la lecture
 * de l'entête du fichier de maillage en mode IFOENV = 0
 *
 * Interface Fortran :
 *
 * SUBROUTINE DIMGEO (NDIM  , NCELET, NCEL  , NFAC  , NFABOR, NSOM  ,
 * *****************
 *                    LNDFAC, LNDFBR, NFML  , NPRFML,
 *                    NTETRA, NPYRAM, NPRISM, NHEXAE )
 *
 * INTEGER          NDIM        : <-- : Dimension de l'espace (3)
 * INTEGER          NCELET      : <-- : Nombre d'éléments halo compris
 * INTEGER          NCEL        : <-- : Nombre d'éléments actifs
 * INTEGER          NFAC        : <-- : Nombre de faces internes
 * INTEGER          NFABOR      : <-- : Nombre de faces de bord
 * INTEGER          NSOM        : <-- : Nombre de sommets (optionnel)
 * INTEGER          LNDFAC      : <-- : Longueur de SOMFAC (optionnel)
 * INTEGER          LNDFBR      : <-- : Longueur de SOMFBR (optionnel)
 * INTEGER          NFML        : <-- : Nombre de familles des faces de bord
 * INTEGER          NPRFML      : <-- : Nombre de propriétés max par famille
 * INTEGER          NTETRA      : <-- : Nombre de tétraèdres
 * INTEGER          NPYRAM      : <-- : Nombre de pyramides
 * INTEGER          NPRISM      : <-- : Nombre de prismes
 * INTEGER          NHEXAE      : <-- : Nombre d'hexaèdres
 *----------------------------------------------------------------------------*/

void CS_PROCF (dimgeo, DIMGEO)
(
 const cs_int_t   *const ndim,    /* <-- dimension de l'espace                */
 const cs_int_t   *const ncelet,  /* <-- nombre d'éléments halo compris       */
 const cs_int_t   *const ncel,    /* <-- nombre d'éléments actifs             */
 const cs_int_t   *const nfac,    /* <-- nombre de faces internes             */
 const cs_int_t   *const nfabor,  /* <-- nombre de faces de bord              */
 const cs_int_t   *const nsom,    /* <-- nombre de sommets (optionnel)        */
 const cs_int_t   *const lndfac,  /* <-- longueur de somfac (optionnel)       */
 const cs_int_t   *const lndfbr,  /* <-- longueur de somfbr (optionnel)       */
 const cs_int_t   *const nfml,    /* <-- nombre de familles des faces de bord */
 const cs_int_t   *const nprfml,  /* <-- nombre de propriétés max par famille */
 const cs_int_t   *const ntetra,  /* <-- nombre de tétraèdres                 */
 const cs_int_t   *const npyram,  /* <-- nombre de pyramides                  */
 const cs_int_t   *const nprism,  /* <-- nombre de prismes                    */
 const cs_int_t   *const nhexae   /* <-- nombre d'hexaèdres                   */
)
{
  cs_maillage_t *maillage = cs_glob_maillage;

  maillage->dim = *ndim;

  maillage->nbr_cel = *ncel;
  maillage->nbr_fac = *nfac;
  maillage->nbr_fbr = *nfabor;

  cs_glob_nsom = *nsom;

  if (*lndfac + *lndfbr > 0)
    maillage->nbr_som = *nsom;
  else
    maillage->nbr_som = 0;

  maillage->lng_fac_som = *lndfac;
  maillage->lng_fbr_som = *lndfbr;

  maillage->nbr_cel_etendu = *ncelet;

  assert (*ncelet == *ncel);

  maillage->nbr_cel_glob = maillage->nbr_cel;
  maillage->nbr_fac_glob = maillage->nbr_fac;
  maillage->nbr_fbr_glob = maillage->nbr_fbr;
  maillage->nbr_som_glob = maillage->nbr_som;

  maillage->nbr_prop_fam_max = *nprfml;
  maillage->nbr_fam          = *nfml;

  cs_glob_ntetra = *ntetra;
  cs_glob_npyram = *npyram;
  cs_glob_nprism = *nprism;
  cs_glob_nhexae = *nhexae;

}


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

/*----------------------------------------------------------------------------
 * Lecture d'un maillage au format "SolCom"
 *----------------------------------------------------------------------------*/

void cs_maillage_solcom_lit
(
 cs_maillage_t      *const maillage,      /* <-> maillage associé             */
 cs_maillage_grd_t  *const maillage_grd   /* <-> grandeurs associés           */
)
{

  cs_int_t   indic_nodal = 0;
  cs_int_t   cpt_elt_tot = 0;

  cs_real_t  *coo_som = NULL;
  cs_int_t   *connect_tetra = NULL;
  cs_int_t   *connect_pyram = NULL;
  cs_int_t   *connect_prism = NULL;
  cs_int_t   *connect_hexae = NULL;

  fvm_nodal_t  *maillage_ext = NULL;


  /* Allocations pour maillage principal */

  cs_loc_maillage_solcom_alloc_mem(maillage,
                                   maillage_grd);


  /* Allocations pour maillage de post traitement
     quand on n'a pas de connectivité faces -> sommets */

  if (maillage->coo_som != NULL)
    coo_som = maillage->coo_som;

  else {

    BFT_MALLOC(coo_som, cs_glob_nsom * 3, cs_real_t);
    BFT_MALLOC(connect_tetra, cs_glob_ntetra * 4, cs_int_t);
    BFT_MALLOC(connect_pyram, cs_glob_npyram * 5, cs_int_t);
    BFT_MALLOC(connect_prism, cs_glob_nprism * 6, cs_int_t);
    BFT_MALLOC(connect_hexae, cs_glob_nhexae * 8, cs_int_t);

  }

  /* Lecture effective du corps du maillage */

  CS_PROCF (letgeo, LETGEO) (&(maillage->dim),
                             &(maillage->nbr_cel_etendu),
                             &(maillage->nbr_cel),
                             &(maillage->nbr_fac),
                             &(maillage->nbr_fbr),
                             &(maillage->nbr_fam),
                             &(maillage->nbr_prop_fam_max),
                             &(cs_glob_nsom),
                             &(maillage->lng_fac_som),
                             &(maillage->lng_fbr_som),
                             &cs_glob_ntetra,
                             &cs_glob_npyram,
                             &cs_glob_nprism,
                             &cs_glob_nhexae,
                             &indic_nodal,
                             maillage->fac_cel,
                             maillage->fbr_cel,
                             maillage->fam_fbr,
                             maillage->fam_cel,
                             maillage->prop_fam,
                             connect_tetra,
                             connect_pyram,
                             connect_prism,
                             connect_hexae,
                             maillage->pos_fac_som,
                             maillage->val_fac_som,
                             maillage->pos_fbr_som,
                             maillage->val_fbr_som,
                             maillage_grd->cen_cel,
                             maillage_grd->surf_fac,
                             maillage_grd->surf_fbr,
                             maillage_grd->cdg_fac,
                             maillage_grd->cdg_fbr,
                             coo_som);


  if (indic_nodal > 0) {

    /* Création directe du maillage de post-traitement
       lorsque l'on n'a pas de connectivité faces->sommets */

    maillage_ext = fvm_nodal_create(_("Volume fluide"));

    if (cs_glob_ntetra > 0)
      cs_loc_maillage_solcom_ajoute(maillage_ext,
                                    cs_glob_ntetra,
                                    FVM_CELL_TETRA,
                                    connect_tetra,
                                    &cpt_elt_tot);

    if (cs_glob_npyram > 0)
      cs_loc_maillage_solcom_ajoute(maillage_ext,
                                    cs_glob_npyram,
                                    FVM_CELL_PYRAM,
                                    connect_pyram,
                                    &cpt_elt_tot);

    if (cs_glob_nprism > 0)
      cs_loc_maillage_solcom_ajoute(maillage_ext,
                                    cs_glob_nprism,
                                    FVM_CELL_PRISM,
                                    connect_prism,
                                    &cpt_elt_tot);

    if (cs_glob_nhexae > 0)
      cs_loc_maillage_solcom_ajoute(maillage_ext,
                                    cs_glob_nhexae,
                                    FVM_CELL_HEXA,
                                    connect_hexae,
                                    &cpt_elt_tot);

    fvm_nodal_transfer_vertices(maillage_ext,
                                coo_som);

    /* Transfert de la structure au post-traitement */

    cs_post_ajoute_maillage_existant(-1,
                                     maillage_ext,
                                     CS_TRUE);

  }
  else if (maillage->coo_som == NULL) {

    BFT_FREE(coo_som);
    BFT_FREE(connect_tetra);
    BFT_FREE(connect_pyram);
    BFT_FREE(connect_prism);
    BFT_FREE(connect_hexae);

  }

}


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

/*----------------------------------------------------------------------------
 * Allocation de mémoire pour la lecture d'un fichier au format "SolCom" ;
 *----------------------------------------------------------------------------*/

static void cs_loc_maillage_solcom_alloc_mem
(
 cs_maillage_t      *const maillage,      /* <-> maillage associé             */
 cs_maillage_grd_t  *const maillage_grd   /* <-> grandeurs associés           */
)
{

  cs_int_t               nbr_elt;

  /* Allocation */
  /*------------*/

  /* Connectivités faces / cellules*/
  BFT_MALLOC(maillage->fac_cel, maillage->nbr_fac * 2, cs_int_t);
  BFT_MALLOC(maillage->fbr_cel, maillage->nbr_fbr, cs_int_t);

  /* CDG cellules (surdimensionnement usuel pour cellules fantômes,
     normalement inexistantes ici) */
  nbr_elt = maillage->dim * maillage->nbr_cel_etendu;
  BFT_MALLOC(maillage_grd->cen_cel, nbr_elt, cs_real_t);

  /* Surfaces faces */
  BFT_MALLOC(maillage_grd->surf_fac, maillage->dim * maillage->nbr_fac,
            cs_real_t);
  BFT_MALLOC(maillage_grd->surf_fbr, maillage->dim * maillage->nbr_fbr,
            cs_real_t);

  /* CDG faces */
  BFT_MALLOC(maillage_grd->cdg_fac, maillage->dim * maillage->nbr_fac,
            cs_real_t);
  BFT_MALLOC(maillage_grd->cdg_fbr, maillage->dim * maillage->nbr_fbr,
            cs_real_t);

  /* Familles faces de bord et cellules */
  BFT_MALLOC(maillage->fam_fbr, maillage->nbr_fbr, cs_int_t);
  BFT_MALLOC(maillage->fam_cel, maillage->nbr_cel_etendu, cs_int_t);

  /* Propriétés des familles */
  nbr_elt = maillage->nbr_fam * maillage->nbr_prop_fam_max;
  BFT_MALLOC(maillage->prop_fam, nbr_elt, cs_int_t);


  if (maillage->nbr_som > 0) {

    /* Coordonnées des sommets */
    nbr_elt = maillage->dim * maillage->nbr_som;
    BFT_MALLOC(maillage->coo_som, nbr_elt, cs_real_t);

    /* Connectivités faces / sommets */
    BFT_MALLOC(maillage->pos_fac_som, maillage->nbr_fac + 1, cs_int_t);
    BFT_MALLOC(maillage->val_fac_som, maillage->lng_fac_som, cs_int_t);
    BFT_MALLOC(maillage->pos_fbr_som, maillage->nbr_fbr + 1, cs_int_t);
    BFT_MALLOC(maillage->val_fbr_som, maillage->lng_fbr_som, cs_int_t);

  }

}


/*----------------------------------------------------------------------------
 * Transfert d'une partie de la connectivité nodale à une structure FVM ;
 *----------------------------------------------------------------------------*/

static void cs_loc_maillage_solcom_ajoute
(
 fvm_nodal_t    *maillage_ext,            /* <-> maillage à compléter         */
 cs_int_t        nbr_elt,                 /* --> nombre d'élements à ajouter  */
 fvm_element_t   type,                    /* --> type de section à ajouter    */
 cs_int_t       *connect,                 /* --> connectivité à transférer    */
 cs_int_t       *cpt_elt_tot              /* <-> compteur total d'éléments    */
)
{

  cs_int_t   ind_elt = 0;
  cs_int_t   cpt_elt = 0;

  fvm_lnum_t   *parent_element_num = NULL;

  if (nbr_elt == 0)
    return;

  /* Numéros d'éléments parents à si nécessaire */

  if (cpt_elt > 0) {
    BFT_MALLOC(parent_element_num, nbr_elt, fvm_lnum_t);
    for (ind_elt = 0 ; ind_elt < nbr_elt ; ind_elt++)
      parent_element_num[ind_elt] = ind_elt + (*cpt_elt_tot + 1);
  }


  /* Transfert de la connectivité et des numéros de parents */

  fvm_nodal_append_by_transfer(maillage_ext,
                               nbr_elt,
                               type,
                               NULL,
                               NULL,
                               NULL,
                               connect,
                               parent_element_num);

  *cpt_elt_tot = *cpt_elt_tot + nbr_elt;

}


#ifdef __cplusplus
}
#endif /* __cplusplus */

