/*============================================================================
*
* 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
*
*============================================================================*/
/*============================================================================
* Communications en série avec le module Enveloppe ou d'autres codes
*============================================================================*/
/* includes système */
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_CS_HAVE_MPI)
#include <mpi.h>
#endif
#if defined(_CS_HAVE_MPI) && defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
#include <mpe.h>
#endif
#if defined(_CS_HAVE_SOCKET)
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
/* Includes librairie BFT et FVM */
#include <bft_error.h>
#include <bft_file.h>
#include <bft_mem.h>
#include <bft_printf.h>
/* Includes librairie */
#include "cs_base.h"
/*----------------------------------------------------------------------------
* Fichiers `include' associés au fichier courant
*----------------------------------------------------------------------------*/
#include "cs_comm.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*============================================================================
* Structures locales
*============================================================================*/
struct _cs_comm_t {
char *nom; /* Nom du communicateur */
bft_file_t *fic; /* Pointeur sur fichier associé */
cs_int_t rang_proc; /* Rang processus en communication (MPI) */
int sock; /* Numéro de socket */
cs_comm_mode_t mode; /* Mode de communication */
cs_comm_type_t type; /* Type de codage des donnees */
cs_bool_t swap_endian; /* Permutation des octets ? */
cs_int_t echo; /* Niveau d'impression des donnees */
};
/*============================================================================
* Constantes et Macros
*============================================================================*/
#define CS_COMM_LNG_NOM_TYPE_ELT 2 /* Longueur du nom de type */
/* Format des messages en mode texte */
#define CS_COMM_FMT_ASCII_NBR_COLONNE 3
#define CS_COMM_SOCKET_ENTETE "CS_comm_socket"
#define CS_COMM_SOCKET_NBR_MAX 65
#define CS_LOC_COMM_LNG_HOSTNAME 256
#define CS_LOC_COMM_LNG_NOM_MAX 256
/*
Si SSIZE_MAX non définie via les "includes" système, on prend la valeur
minimale requise par POSIX (pour read/write de bas niveau utilisés
avec les sockets).
*/
#if !defined(SSIZE_MAX)
#define SSIZE_MAX 32767
#endif
/*============================================================================
* Variables globales statiques
*============================================================================*/
static char cs_comm_nom_typ_elt_char[] = "c "; /* Type "chaîne" */
static char cs_comm_nom_typ_elt_int[] = "i "; /* Type "entier" */
static char cs_comm_nom_typ_elt_real[] = "r8"; /* Type "réel" */
static char cs_comm_fmt_ascii_tab_int[] = "%10d";
static char cs_comm_fmt_ascii_tab_real[] = "%23.15E";
/* Pointeurs globaux sur communicateurs avec le module Enveloppe */
cs_comm_t *cs_glob_comm_ecs_vers_cs = NULL;
#if defined(_CS_HAVE_SOCKET)
static cs_bool_t cs_glob_comm_little_endian = CS_FALSE;
static char cs_glob_comm_sock_nom_hote[CS_LOC_COMM_LNG_HOSTNAME + 1];
static int cs_glob_comm_sock_num_port = -1;
static int cs_glob_comm_socket = 0;
struct sockaddr_in cs_glob_comm_addr_sock;
static char cs_glob_comm_err_socket[]
= N_("Erreur pour la communication par socket : "
" %s (noeud %4d)\n");
#endif /* _CS_HAVE_SOCKET */
/* Instrumentation MPE */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
static int cs_glob_mpe_comm_ouvre;
static int cs_glob_mpe_comm_entete;
static int cs_glob_mpe_comm_corps;
#endif
/*============================================================================
* Prototypes de fonctions privées
*============================================================================*/
/*----------------------------------------------------------------------------
* Fonction qui construit le descripteur du fichier d'interface et initialise
* ce fichier par l'envoi ou la lecture d'une éventuelle "chaîne magique"
* servant a vérifier le bon format des fichiers
*----------------------------------------------------------------------------*/
static void cs_loc_comm_fic_ouvre
(
cs_comm_t *const comm,
const char *const nom,
const char *const chaine_magique
);
/*----------------------------------------------------------------------------
* Fonction qui ferme le fichier d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_fic_ferme
(
cs_comm_t *comm
);
#if defined(_CS_HAVE_MPI)
/*----------------------------------------------------------------------------
* Fonction qui initialise une communication MPI par l'envoi ou la lecture
* d'une éventuelle "chaîne magique" servant a vérifier le bon format des
* données
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_ouvre
(
cs_comm_t *comm,
const char *const chaine_magique
);
/*----------------------------------------------------------------------------
* Fonction qui échange une entête de rubrique via MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_entete
(
cs_int_t *const num_rub,
char *const nom_rub,
cs_int_t *const nbr_elt_rub,
char *const nom_typ_elt,
const cs_comm_t *const comm
);
/*----------------------------------------------------------------------------
* Fonction qui échange le corps d'une rubrique via MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_corps
(
void *const elt_rub,
const cs_int_t nbr_elt_rub,
cs_type_t typ_elt,
const cs_comm_t *const comm
);
/*----------------------------------------------------------------------------
* Fonction qui imprime un message d'erreur en cas de problème de
* communication MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_msg_err
(
const cs_comm_t *const comm,
const int error
);
#endif /* (_CS_HAVE_MPI) */
#if defined(_CS_HAVE_SOCKET)
/*----------------------------------------------------------------------------
* Fonction qui initialise une connection par "socket"
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_connect
(
cs_comm_t *const comm
);
/*----------------------------------------------------------------------------
* Fonction qui assure l'échange de la "chaine magique" via les sockets
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_ouvre
(
cs_comm_t *const comm ,
const char *const nom_fic ,
const char *const chaine_magique
);
/*----------------------------------------------------------------------------
* Fonction qui ferme la connextion avec le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_ferme
(
cs_comm_t *comm
);
/*----------------------------------------------------------------------------
* Fonction qui écrit un enregistrement dans le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_ecrit_sock
(
const cs_comm_t *const comm,
const cs_byte_t * rec,
const size_t nbr,
cs_type_t typ_e
);
/*----------------------------------------------------------------------------
* Fonction qui lit un enregistrement dans le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_lit_sock
(
const cs_comm_t *const comm,
cs_byte_t * rec,
const size_t nbr,
cs_type_t typ_e
);
#endif /* (_CS_HAVE_SOCKET) */
/*----------------------------------------------------------------------------
* Affichage de l'attente d'échange d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_pre
(
const cs_comm_t *const comm
);
/*----------------------------------------------------------------------------
* Affichage de l'entete d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_entete
(
const cs_int_t num_rub,
const char *const nom_rub,
const cs_int_t nbr_elt,
const cs_type_t typ_elt
);
/*----------------------------------------------------------------------------
* Affichage (partiel) du contenu d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_donnees
(
const cs_int_t echo,
const cs_int_t nbr_elt,
const cs_type_t typ_elt,
const void *const elt_rub
);
/*----------------------------------------------------------------------------
* Fonction qui écrit un enregistrement dans le fichier d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_ecrit_rec
(
const cs_comm_t *const comm,
const void *const rec,
const size_t nbr,
cs_type_t typ
);
/*----------------------------------------------------------------------------
* Fonction qui lit un enregistrement dans le fichier d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_lit_rec
(
const cs_comm_t *const comm,
void *const rec ,
const size_t nbr,
cs_type_t typ
);
/*----------------------------------------------------------------------------
* Fonction d'impression d'un tableau en ASCII
*
* Si les valeurs sont de type "caractère", les valeurs non séparées
* par un caractère nul sont écrites sur une seule ligne
*----------------------------------------------------------------------------*/
void cs_loc_comm_ecrit_ascii
(
const bft_file_t *const fic,
const void *const tab_val,
const cs_int_t tab_nbr,
const cs_type_t typ_val
);
/*----------------------------------------------------------------------------
* Fonction de lecture formatée (stricte) d'un tableau en ASCII
*
* Si les valeurs sont de type "caractère", les valeurs sont lues
* par lignes ; entre les valeurs de chaque ligne, on insère un caractère
* nul (symétrique écriture)
*----------------------------------------------------------------------------*/
void cs_loc_comm_lit_ascii
(
const bft_file_t *const fic,
void *const tab_val,
const cs_int_t tab_nbr,
const cs_type_t typ_val
);
/*============================================================================
* Définitions de fonctions publiques
*============================================================================*/
/*----------------------------------------------------------------------------
* Fonction qui initialise une communication
*----------------------------------------------------------------------------*/
cs_comm_t * cs_comm_initialise
(
const char *const nom_emetteur, /* --> partie "émetteur" du nom */
const char *const nom_recepteur, /* --> partie "recepteur du nom */
const char *const chaine_magique, /* --> Chaîne de vérif. de type */
const cs_int_t numero, /* --> Complète le nom si non nul */
#if defined(_CS_HAVE_MPI)
const cs_int_t rang_proc, /* --> Rang processus en comm
(< 0 si comm par fichier) */
#endif
const cs_comm_mode_t mode, /* --> Émission ou réception */
const cs_comm_type_t type, /* --> Type de communication */
const cs_int_t echo /* --> Écho sur sortie principale
(< 0 si aucun, entête si 0,
n premiers et derniers
éléments si n) */
)
{
unsigned int_endian;
char *nom_fic = NULL;
cs_comm_t *comm = NULL;
BFT_MALLOC(comm, 1, cs_comm_t);
/* Construction du nom du communicateur */
BFT_MALLOC(comm->nom,
strlen(nom_emetteur) + strlen("_vers_") + strlen(nom_recepteur) + 1
+ (numero == 0 ? 0 : 4 + 1),
char);
sprintf(comm->nom, "%s_vers_%s", nom_emetteur, nom_recepteur);
if (numero > 0)
sprintf(comm->nom + strlen(comm->nom), ".%04d", numero);
/* Initialisation des autres champs */
comm->mode = mode;
comm->type = type;
comm->echo = echo;
comm->fic = NULL;
#if defined(_CS_HAVE_MPI)
comm->rang_proc = rang_proc;
#else
comm->rang_proc = -1;
#endif
/* Test si système "big-endian" ou "little-endian" */
comm->swap_endian = CS_FALSE;
int_endian = 0;
*((char *)(&int_endian)) = '\1';
if (int_endian == 1)
comm->swap_endian = CS_TRUE;
#if defined(DEBUG) && !defined(NDEBUG)
else {
int_endian = 0;
*((char *)(&int_endian) + sizeof(unsigned) - 1) = '\1';
assert(int_endian == 1);
}
#endif
/* Info sur la création de l'interface */
bft_printf(_("\n Ouverture de la communication : %s ..."), comm->nom);
bft_printf_flush();
#if defined(_CS_HAVE_SOCKET)
if (comm->type == CS_COMM_TYPE_SOCKET)
cs_loc_comm_sock_connect(comm);
#endif /* (_CS_HAVE_SOCKET) */
/* Création du descripteur de fichier d'interface */
/*------------------------------------------------*/
if (comm->type == CS_COMM_TYPE_MPI) {
#if defined(_CS_HAVE_MPI)
cs_loc_comm_mpi_ouvre(comm, chaine_magique);
#else
assert(comm->rang_proc < 0);
#endif
}
else {
if (cs_glob_base_nbr == 1) {
nom_fic = comm->nom;
}
else if (cs_glob_base_nbr > 1) {
BFT_MALLOC(nom_fic,
strlen(nom_emetteur) + strlen("_vers_") + strlen(nom_recepteur)
+ 1 + (cs_glob_base_nbr == 1 ? 0 : 4 + 2) + (numero == 0 ? 0 : 4 + 1),
char);
if (mode == CS_COMM_MODE_EMISSION)
sprintf(nom_fic, "%s_n%04d_vers_%s",
nom_emetteur, cs_glob_base_rang + 1, nom_recepteur);
else if (mode == CS_COMM_MODE_RECEPTION)
sprintf(nom_fic, "%s_vers_%s_n%04d",
nom_emetteur, nom_recepteur, cs_glob_base_rang + 1);
else
assert( mode == CS_COMM_MODE_EMISSION
|| mode == CS_COMM_MODE_RECEPTION);
if (numero > 0)
sprintf(nom_fic + strlen(nom_fic), ".%04d", numero);
}
if ( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN)
cs_loc_comm_fic_ouvre(comm, nom_fic, chaine_magique);
#if defined(_CS_HAVE_SOCKET)
else if (comm->type == CS_COMM_TYPE_SOCKET)
cs_loc_comm_sock_ouvre(comm, nom_fic, chaine_magique);
#endif /* (_CS_HAVE_SOCKET) */
if (cs_glob_base_nbr > 1)
BFT_FREE(nom_fic);
}
/* Info sur le succès de la création de l'interface */
bft_printf(_(" [ok]\n"));
bft_printf_flush();
return comm;
}
/*----------------------------------------------------------------------------
* Fonction qui termine une communication
*----------------------------------------------------------------------------*/
cs_comm_t * cs_comm_termine
(
cs_comm_t *comm
)
{
/* Info sur la fermeture du fichier d'interface */
bft_printf(_("\n Fermeture de la communication : %s\n"), comm->nom);
bft_printf_flush();
if ( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN)
cs_loc_comm_fic_ferme(comm);
#if defined(_CS_HAVE_SOCKET)
else if (comm->type == CS_COMM_TYPE_SOCKET)
cs_loc_comm_sock_ferme(comm);
#endif /* (_CS_HAVE_SOCKET) */
BFT_FREE(comm->nom);
BFT_FREE(comm);
return NULL;
}
/*----------------------------------------------------------------------------
* Fonction qui renvoie un pointeur sur le nom d'une communication
*----------------------------------------------------------------------------*/
const char * cs_comm_ret_nom
(
const cs_comm_t *const comm
)
{
assert(comm != NULL);
return(comm->nom);
}
/*----------------------------------------------------------------------------
* Envoi d'un message
*----------------------------------------------------------------------------*/
void cs_comm_envoie_message
(
const cs_int_t num_rub, /* --> Num. rubrique associée */
const char nom_rub[CS_COMM_LNG_NOM_RUB], /* --> Si num_rub = 0 */
const cs_int_t nbr_elt, /* --> Nombre d'éléments */
const cs_type_t typ_elt, /* --> Type si nbr_elt > 0 */
void *const elt, /* --> Éléments si nbr_elt > 0 */
const cs_comm_t *const comm
)
{
char nom_rub_ecr[CS_COMM_LNG_NOM_RUB + 1];
char *nom_typ_elt;
char nom_typ_elt_ecr[CS_COMM_LNG_NOM_TYPE_ELT + 1];
assert(comm != NULL);
assert(nbr_elt >= 0);
/* nom de la rubrique */
sprintf(nom_rub_ecr,
"%-*.*s",
CS_COMM_LNG_NOM_RUB,
CS_COMM_LNG_NOM_RUB,
nom_rub);
/* nom du type d'elements */
if (nbr_elt != 0) {
switch(typ_elt) {
case CS_TYPE_cs_int_t:
nom_typ_elt = cs_comm_nom_typ_elt_int;
break;
case CS_TYPE_cs_real_t:
nom_typ_elt = cs_comm_nom_typ_elt_real;
break;
case CS_TYPE_char:
nom_typ_elt = cs_comm_nom_typ_elt_char;
break;
default:
assert( typ_elt == CS_TYPE_cs_int_t
|| typ_elt == CS_TYPE_cs_real_t
|| typ_elt == CS_TYPE_char);
} /* Fin `swich(typ_elt_e)' */
sprintf(nom_typ_elt_ecr,
"%-*.*s",
CS_COMM_LNG_NOM_TYPE_ELT,
CS_COMM_LNG_NOM_TYPE_ELT,
nom_typ_elt);
}
if (comm->echo >= 0)
cs_loc_comm_echo_pre(comm);
/* Communication par fichier */
/*---------------------------*/
if ( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN) {
/* numéro de type de la rubrique */
cs_loc_comm_ecrit_rec(comm,
(const void *)(&num_rub),
1,
CS_TYPE_cs_int_t);
/* nom de type de la rubrique */
if (num_rub == 0)
cs_loc_comm_ecrit_rec(comm,
(const void *) nom_rub_ecr,
CS_COMM_LNG_NOM_RUB,
CS_TYPE_char);
/* nombre d'éléments */
cs_loc_comm_ecrit_rec(comm,
(const void *)(&nbr_elt),
1,
CS_TYPE_cs_int_t);
if (nbr_elt != 0) {
/* nom du type d'éléments */
cs_loc_comm_ecrit_rec(comm,
(const void *) nom_typ_elt_ecr,
CS_COMM_LNG_NOM_TYPE_ELT,
CS_TYPE_char);
/* valeurs des éléments */
cs_loc_comm_ecrit_rec(comm,
(const void *) elt,
(size_t) nbr_elt,
typ_elt);
} /* Fin : s'il y a des éléments a écrire */
bft_file_flush(comm->fic);
}
#if defined(_CS_HAVE_MPI)
/* Communication par MPI */
/*-----------------------*/
else if (comm->type == CS_COMM_TYPE_MPI) {
cs_int_t num_rub_ecr = num_rub;
cs_int_t nbr_elt_rub_ecr = nbr_elt;
cs_loc_comm_mpi_entete(&num_rub_ecr,
nom_rub_ecr,
&nbr_elt_rub_ecr,
nom_typ_elt_ecr,
comm);
if (nbr_elt > 0)
cs_loc_comm_mpi_corps((void *) elt,
nbr_elt,
typ_elt,
comm);
}
#endif /* (_CS_HAVE_MPI) */
#if defined(_CS_HAVE_SOCKET)
/* Communication par socket */
/*--------------------------*/
else if (comm->type == CS_COMM_TYPE_SOCKET) {
/* numéro de type de la rubrique */
cs_loc_comm_ecrit_sock(comm,
(const void *)(&num_rub),
1,
CS_TYPE_cs_int_t);
/* nom de type de la rubrique */
if (num_rub == 0)
cs_loc_comm_ecrit_sock(comm,
(const void *) nom_rub_ecr,
CS_COMM_LNG_NOM_RUB,
CS_TYPE_char);
/* nombre d'éléments */
cs_loc_comm_ecrit_sock(comm,
(const void *)(&nbr_elt),
1,
CS_TYPE_cs_int_t);
if (nbr_elt != 0) {
/* nom du type d'éléments */
cs_loc_comm_ecrit_sock(comm,
(const void *) nom_typ_elt_ecr,
CS_COMM_LNG_NOM_TYPE_ELT,
CS_TYPE_char);
/* valeurs des éléments */
cs_loc_comm_ecrit_sock(comm,
(const void *) elt,
(size_t) nbr_elt,
typ_elt);
} /* Fin : s'il y a des éléments à écrire */
}
#endif /* (_CS_HAVE_SOCKET) */
/* Affichage éventuel */
if (comm->echo >= 0)
cs_loc_comm_echo_entete(num_rub,
nom_rub,
nbr_elt,
typ_elt);
if (comm->echo > 0)
cs_loc_comm_echo_donnees(comm->echo,
nbr_elt,
typ_elt,
elt);
}
/*----------------------------------------------------------------------------
* Réception de l'entete d'un message ; renvoie le nombre d'éléments du
* corps du message.
*----------------------------------------------------------------------------*/
cs_int_t cs_comm_recoit_entete
(
cs_comm_msg_entete_t *const entete, /* <-- entête du message */
const cs_comm_t *const comm
)
{
char nom_typ_elt[CS_COMM_LNG_NOM_TYPE_ELT + 1];
assert(comm != NULL);
entete->nbr_elt = 0;
if (comm->echo >= 0)
cs_loc_comm_echo_pre(comm);
/* Communication par fichier */
/*---------------------------*/
if ( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN) {
/* numéro de type de la rubrique */
cs_loc_comm_lit_rec(comm,
(void *) &(entete->num_rub),
1,
CS_TYPE_cs_int_t);
/* nom de type de la rubrique */
if (entete->num_rub == 0)
cs_loc_comm_lit_rec(comm,
(void *) &(entete->nom_rub),
CS_COMM_LNG_NOM_RUB,
CS_TYPE_char);
/* nombre d'éléments */
cs_loc_comm_lit_rec(comm,
(void *) &(entete->nbr_elt),
1,
CS_TYPE_cs_int_t);
if (entete->nbr_elt != 0) {
/* nom du type d'éléments */
cs_loc_comm_lit_rec(comm,
(void *) nom_typ_elt,
CS_COMM_LNG_NOM_TYPE_ELT,
CS_TYPE_char);
} /* Fin : s'il y a des elements à lire */
}
#if defined(_CS_HAVE_MPI)
/* Communication par MPI */
/*-----------------------*/
else if (comm->type == CS_COMM_TYPE_MPI) {
cs_loc_comm_mpi_entete(&(entete->num_rub),
entete->nom_rub,
&(entete->nbr_elt),
nom_typ_elt,
comm);
}
#endif /* (_CS_HAVE_MPI) */
#if defined(_CS_HAVE_SOCKET)
/* Communication par socket */
/*--------------------------*/
else if (comm->type == CS_COMM_TYPE_SOCKET) {
/* numéro de type de la rubrique */
cs_loc_comm_lit_sock(comm,
(void *) &(entete->num_rub),
1,
CS_TYPE_cs_int_t);
/* nom de type de la rubrique */
if (entete->num_rub == 0)
cs_loc_comm_lit_sock(comm,
(void *) &(entete->nom_rub),
CS_COMM_LNG_NOM_RUB,
CS_TYPE_char);
/* nombre d'éléments */
cs_loc_comm_lit_sock(comm,
(void *) &(entete->nbr_elt),
1,
CS_TYPE_cs_int_t);
if (entete->nbr_elt != 0) {
/* nom du type d'éléments */
cs_loc_comm_lit_sock(comm,
(void *) nom_typ_elt,
CS_COMM_LNG_NOM_TYPE_ELT,
CS_TYPE_char);
} /* Fin : s'il y a des elements à lire */
}
#endif /* (_CS_HAVE_SOCKET) */
entete->nom_rub[CS_COMM_LNG_NOM_RUB] = '\0';
if (entete->nbr_elt != 0) {
nom_typ_elt[CS_COMM_LNG_NOM_TYPE_ELT] = '\0';
if (strcmp(nom_typ_elt, cs_comm_nom_typ_elt_int) == 0)
entete->typ_elt = CS_TYPE_cs_int_t;
else if (strcmp(nom_typ_elt, cs_comm_nom_typ_elt_real) == 0)
entete->typ_elt = CS_TYPE_cs_real_t;
else if (strcmp(nom_typ_elt, cs_comm_nom_typ_elt_char) == 0)
entete->typ_elt = CS_TYPE_char;
else
assert( strcmp(nom_typ_elt, cs_comm_nom_typ_elt_int) == 0
|| strcmp(nom_typ_elt, cs_comm_nom_typ_elt_real) == 0
|| strcmp(nom_typ_elt, cs_comm_nom_typ_elt_char) == 0);
}
/* Affichage eventuel */
if (comm->echo >= 0)
cs_loc_comm_echo_entete(entete->num_rub,
entete->nom_rub,
entete->nbr_elt,
entete->typ_elt);
/* Transmission du nombre d'elements à lire */
return entete->nbr_elt;
}
/*----------------------------------------------------------------------------
* Réception du corps d'un message.
*
* Si la zone mémoire destinée à recevoir les données existe deja, on
* fournit un pointeur "elt" sur cette zone ; la fonction renvoie alors
* ce même pointeur. Sinon (si "elt" est à NULL), la mémoire est allouée
* ici, et la fonction renvoie un pointeur sur cette zone.
*----------------------------------------------------------------------------*/
void * cs_comm_recoit_corps
(
const cs_comm_msg_entete_t *const entete, /* --> entête du message */
void *const elt, /* --> Pointeur sur les éléments */
const cs_comm_t *const comm
)
{
cs_int_t ind;
void *_elt_rub;
assert(comm != NULL);
assert(entete->nbr_elt >= 0);
_elt_rub = elt;
if (_elt_rub == NULL && entete->nbr_elt != 0) {
switch(entete->typ_elt) {
case CS_TYPE_cs_int_t:
{
cs_int_t *elt_rub_int;
BFT_MALLOC(elt_rub_int, entete->nbr_elt, cs_int_t);
_elt_rub = (void *) elt_rub_int;
}
break;
case CS_TYPE_cs_real_t:
{
cs_real_t *elt_rub_rea;
BFT_MALLOC(elt_rub_rea, entete->nbr_elt, cs_real_t);
_elt_rub = (void *)elt_rub_rea;
}
break;
case CS_TYPE_char:
{
char *elt_rub_cha;
BFT_MALLOC(elt_rub_cha, entete->nbr_elt + 1, char);
_elt_rub = (void *)elt_rub_cha;
}
break;
default:
assert( entete->typ_elt == CS_TYPE_cs_int_t
|| entete->typ_elt == CS_TYPE_cs_real_t
|| entete->typ_elt == CS_TYPE_char);
}
}
/* valeurs des éléments */
if (entete->nbr_elt != 0) {
/* Communication par fichier */
if ( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN)
cs_loc_comm_lit_rec(comm,
(void *)_elt_rub,
(size_t) entete->nbr_elt,
entete->typ_elt);
#if defined(_CS_HAVE_MPI)
/* Communication par MPI */
else if (comm->type == CS_COMM_TYPE_MPI)
cs_loc_comm_mpi_corps((void *)_elt_rub,
entete->nbr_elt,
entete->typ_elt,
comm);
#endif /* (_CS_HAVE_MPI) */
#if defined(_CS_HAVE_SOCKET)
/* Communication par socket */
else if (comm->type == CS_COMM_TYPE_SOCKET)
cs_loc_comm_lit_sock(comm,
(void *)_elt_rub,
(size_t) entete->nbr_elt,
entete->typ_elt);
#endif /* (_CS_HAVE_SOCKET) */
/* Vérifications */
if (entete->typ_elt == CS_TYPE_char) {
for (ind = 0 ;
ind < entete->nbr_elt && ((char *)_elt_rub)[ind] != '\0' ;
ind++);
((char *)_elt_rub)[ind] = '\0';
}
/* Affichage éventuel */
if (comm->echo > 0)
cs_loc_comm_echo_donnees(comm->echo,
entete->nbr_elt,
entete->typ_elt,
_elt_rub);
} /* Fin : s'il y a des éléments a lire */
/* Transmission des valeurs lues */
return _elt_rub;
}
#if defined(_CS_HAVE_SOCKET)
/*----------------------------------------------------------------------------
* Fonction qui ouvre un "socket" IP pour préparer ce mode de communication
*----------------------------------------------------------------------------*/
void cs_comm_init_socket
(
void
)
{
char chaine[CS_LOC_COMM_LNG_HOSTNAME + 1];
int nbr_connect_max;
int num_port;
#if defined(_CS_ARCH_Linux)
socklen_t long_sock;
#else
int long_sock; /* size_t d'apres standard SUS-v2, mais d'apres
man gethostbyname sous Linux, le standard est
mauvais, on doit avoir un int (ou socklen_t) */
#endif
unsigned int_endian;
struct sockaddr_in addr_sock;
struct hostent *ent_hote;
int rang = (cs_glob_base_rang == -1 ? 0 : cs_glob_base_rang);
/* Initialisations */
nbr_connect_max = 0;
if (getenv("CS_COMM_SOCKET_NBR_MAX") != NULL)
nbr_connect_max = atoi(getenv("CS_COMM_SOCKET_NBR_MAX"));
if (nbr_connect_max == 0)
nbr_connect_max = CS_COMM_SOCKET_NBR_MAX;
/* Test si système "big-endian" (référence réseau) ou "little-endian" */
cs_glob_comm_little_endian = CS_FALSE;
int_endian = 0;
*((char *) (&int_endian)) = '\1';
if (int_endian == 1)
cs_glob_comm_little_endian = CS_TRUE;
#if defined(DEBUG) && !defined(NDEBUG)
else {
int_endian = 0;
*((char *) (&int_endian) + sizeof(unsigned) - 1) = '\1';
assert (int_endian == 1);
}
#endif
/* Création du socket serveur */
cs_glob_comm_socket = socket(AF_INET, SOCK_STREAM, 0);
if (cs_glob_comm_socket == -1)
bft_error(__FILE__, __LINE__, errno,
_("Erreur d'initialisation du support de communication "
"par socket.\n"));
/* Préparation à l'utilisation */
long_sock = sizeof(addr_sock);
memset((char *) &addr_sock, 0, long_sock);
addr_sock.sin_family = AF_INET;
addr_sock.sin_addr.s_addr = INADDR_ANY;
addr_sock.sin_port = 0;
if (cs_glob_comm_little_endian == CS_TRUE) {
bft_file_swap_endian(&(addr_sock.sin_addr.s_addr),
&(addr_sock.sin_addr.s_addr),
sizeof(addr_sock.sin_addr.s_addr),
1);
bft_file_swap_endian(&(addr_sock.sin_port),
&(addr_sock.sin_port),
sizeof(addr_sock.sin_port),
1);
}
if (gethostname(chaine, CS_LOC_COMM_LNG_HOSTNAME) < 0)
bft_error(__FILE__, __LINE__, errno,
_("Erreur de récupération du nom de la machine"));
chaine[CS_LOC_COMM_LNG_HOSTNAME] = '\0';
ent_hote = gethostbyname(chaine);
memcpy(ent_hote->h_addr, &addr_sock.sin_addr, ent_hote->h_length);
if (bind(cs_glob_comm_socket,
(struct sockaddr *)&addr_sock,
long_sock) != 0)
bft_error(__FILE__, __LINE__, errno,
_("Erreur d'initialisation du support de communication "
"par socket.\n"));
if (listen(cs_glob_comm_socket, nbr_connect_max) < 0)
bft_error(__FILE__, __LINE__, errno,
_("Erreur d'initialisation du support de communication "
"par socket.\n"));
/* Récupération du numéro de service affecté */
if (getsockname(cs_glob_comm_socket,
(struct sockaddr *)&addr_sock,
&long_sock) != 0)
bft_error(__FILE__, __LINE__, errno,
_("Erreur d'initialisation du support de communication "
"par socket.\n"));
num_port = addr_sock.sin_port;
if (cs_glob_comm_little_endian == CS_TRUE) {
bft_file_swap_endian(&(addr_sock.sin_port),
&(addr_sock.sin_port),
sizeof(addr_sock.sin_port), 1);
num_port = addr_sock.sin_port;
bft_file_swap_endian(&(addr_sock.sin_port),
&(addr_sock.sin_port),
sizeof(addr_sock.sin_port), 1);
}
/* Sauvegarde de la structure dans la variable globale associée */
cs_glob_comm_addr_sock = addr_sock;
/* Ecriture dans l'ordre des processus du nom de l'hôte et du port */
if (rang == 0) {
/* Impression du message de transfert des caractéristiques
sur le listing pour le rang "0" */
bft_printf(_("\n Communication possible sur %s, port %d\n\n"),
chaine, num_port);
bft_printf_flush();
}
memcpy(cs_glob_comm_sock_nom_hote, chaine, CS_LOC_COMM_LNG_HOSTNAME);
cs_glob_comm_sock_nom_hote[CS_LOC_COMM_LNG_HOSTNAME] = '\0';
cs_glob_comm_sock_num_port = num_port;
}
/*----------------------------------------------------------------------------
* Fonction qui ferme le "socket" IP avec ce mode de communication
*----------------------------------------------------------------------------*/
void cs_comm_termine_socket
(
void
)
{
if (cs_glob_comm_socket == 0)
return;
close(cs_glob_comm_socket);
bft_printf(_("\nFermeture du socket ...\t [ok]\n"));
bft_printf_flush();
}
#endif /* _CS_HAVE_SOCKET */
/*============================================================================
* Définitions de fonctions privées
*============================================================================*/
/*----------------------------------------------------------------------------
* Fonction qui construit le descripteur du fichier d'interface et initialise
* ce fichier par l'envoi ou la lecture d'une eventuelle "chaîne magique"
* servant a vérifier le bon format des fichiers
*----------------------------------------------------------------------------*/
static void cs_loc_comm_fic_ouvre
(
cs_comm_t *const comm,
const char *const nom,
const char *const chaine_magique
)
{
bft_file_type_t fic_typ_comm;
bft_file_mode_t fic_mod_comm;
/* Préparation de l'ouverture du fichier */
switch(comm->type) {
case CS_COMM_TYPE_ASCII:
fic_typ_comm = BFT_FILE_TYPE_TEXT;
break;
case CS_COMM_TYPE_BINAIRE:
fic_typ_comm = BFT_FILE_TYPE_BINARY;
break;
case CS_COMM_TYPE_BINAIRE_FORTRAN:
fic_typ_comm = BFT_FILE_TYPE_FORTRAN_BINARY;
break;
default:
assert( comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_ASCII);
}
switch(comm->mode) {
case CS_COMM_MODE_RECEPTION:
fic_mod_comm = BFT_FILE_MODE_READ;
break;
case CS_COMM_MODE_EMISSION:
fic_mod_comm = BFT_FILE_MODE_WRITE;
break;
default:
assert( comm->mode == CS_COMM_MODE_RECEPTION
|| comm->mode == CS_COMM_MODE_EMISSION);
}
/* Création du descripteur du fichier d'interface */
comm->fic = bft_file_open(nom,
fic_mod_comm,
fic_typ_comm);
bft_file_set_big_endian(comm->fic);
/*-----------------------------------------------------*/
/* Écriture ou lecture éventuelle d'une chaine magique */
/*-----------------------------------------------------*/
if (comm->mode == CS_COMM_MODE_RECEPTION) {
char *chaine_magique_lue;
cs_int_t lng_chaine_magique = strlen(chaine_magique);
BFT_MALLOC(chaine_magique_lue, lng_chaine_magique + 1, char);
cs_loc_comm_lit_rec(comm,
(void *)(chaine_magique_lue),
strlen(chaine_magique),
CS_TYPE_char);
chaine_magique_lue[lng_chaine_magique] = '\0';
/* Si la chaine magique ne correspond pas, on a une erreur */
if (strcmp(chaine_magique_lue, chaine_magique) != 0) {
bft_error(__FILE__, __LINE__, 0,
_("Erreur à la lecture du fichier de communication : "
"\"%s\".\n"
"Le format de l'interface n'est pas à la bonne version.\n"
"La chaîne magique repère la version du format "
"d'interface :\n"
"chaîne magique lue : \"%s\"\n"
"chaîne magique actuelle : \"%s\"\n"),
comm->nom, chaine_magique_lue, chaine_magique);
}
BFT_FREE(chaine_magique_lue);
}
else if (comm->mode == CS_COMM_MODE_EMISSION) {
cs_loc_comm_ecrit_rec(comm,
(const void *)(chaine_magique),
strlen(chaine_magique),
CS_TYPE_char);
bft_file_flush(comm->fic);
}
}
/*----------------------------------------------------------------------------
* Fonction qui ferme le fichier d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_fic_ferme
(
cs_comm_t *comm
)
{
comm->fic = bft_file_free(comm->fic);
}
#if defined(_CS_HAVE_MPI)
/*----------------------------------------------------------------------------
* Fonction qui initialise une communication MPI par l'envoi ou la lecture
* d'une éventuelle "chaîne magique" servant a vérifier le bon format des
* données
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_ouvre
(
cs_comm_t *const comm,
const char *const chaine_magique
)
{
int ierror, comm_size;
MPI_Status status;
char * chaine_magique_comm;
cs_int_t lng_chaine_magique = strlen(chaine_magique);
/*-------------------------------------*/
/* Initialisation de l'instrumentation */
/*-------------------------------------*/
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
{
int rang;
bft_printf("Instrumentation de la communication MPI via MPE\n");
bft_printf_flush();
cs_glob_mpe_comm_ouvre = MPE_Log_get_event_number();
cs_glob_mpe_comm_entete = MPE_Log_get_event_number();
cs_glob_mpe_comm_corps = MPE_Log_get_event_number();
if (cs_glob_base_mpi_comm != MPI_COMM_NULL)
MPI_Comm_rank(cs_glob_base_mpi_comm, &rang);
else
MPI_Comm_rank(MPI_COMM_WORLD, &rang);
if (rang == 0) {
MPE_Describe_event(cs_glob_mpe_comm_ouvre,
"cs_loc_comm_mpi_ouvre", "white");
MPE_Describe_event(cs_glob_mpe_comm_entete,
"cs_loc_com_mpi_entete", "blue");
MPE_Describe_event(cs_glob_mpe_comm_corps,
"cs_loc_comm_mpi_corps", "orange");
}
}
#endif
/*------------------------------------*/
/* Initialisation de la communication */
/*------------------------------------*/
/* Instructions */
assert( comm->mode == CS_COMM_MODE_RECEPTION
|| comm->mode == CS_COMM_MODE_EMISSION);
MPI_Comm_size(MPI_COMM_WORLD, &comm_size);
if (comm->rang_proc >= comm_size)
bft_error(__FILE__, __LINE__, 0,
_("Impossible d'établir la communication : %s\n"
"car le rang du processus recherché (%d)\n"
"est supérieur ou égal au nombre de processus MPI (%d)."),
comm->nom, comm->rang_proc, comm_size);
BFT_MALLOC(chaine_magique_comm, lng_chaine_magique + 1, char);
/*-----------------------------------------------------*/
/* Écriture ou lecture eventuelle d'une chaine magique */
/*-----------------------------------------------------*/
if (comm->mode == CS_COMM_MODE_RECEPTION) {
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_rcv_a, 0, NULL);
#endif
ierror = MPI_Recv(chaine_magique_comm, lng_chaine_magique, MPI_CHAR,
comm->rang_proc,
MPI_ANY_TAG, MPI_COMM_WORLD, &status);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_rcv_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_ouvre, 0, NULL);
#endif
if (ierror != MPI_SUCCESS)
cs_loc_comm_mpi_msg_err(comm, ierror);
chaine_magique_comm[lng_chaine_magique] = '\0';
/* Si la chaine magique ne correspond pas, on a une erreur */
if (strcmp(chaine_magique_comm, chaine_magique) != 0) {
bft_error(__FILE__, __LINE__, 0,
_("Erreur pour la communication : \"%s\".\n"
"La chaîne magique indique une mauvaise version du "
"format de l'interface.\n"
"chaîne magique lue : \"%s\"\n"
"chaîne magique attendue : \"%s\""),
comm->nom, chaine_magique_comm, chaine_magique);
}
}
else if (comm->mode == CS_COMM_MODE_EMISSION) {
strncpy(chaine_magique_comm, chaine_magique, lng_chaine_magique);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_send_a, 0, NULL);
#endif
ierror = MPI_Send(chaine_magique_comm, lng_chaine_magique, MPI_CHAR,
comm->rang_proc,
0, MPI_COMM_WORLD);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_send_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_ouvre, 0, NULL);
#endif
if (ierror != MPI_SUCCESS)
cs_loc_comm_mpi_msg_err(comm, ierror);
}
BFT_FREE(chaine_magique_comm);
}
/*----------------------------------------------------------------------------
* Fonction qui échange une entête de rubrique via MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_entete
(
cs_int_t *const num_rub,
char *const nom_rub,
cs_int_t *const nbr_elt_rub,
char *const nom_typ_elt,
const cs_comm_t *const comm
)
{
#undef CS_COMM_MPI_PACK_SIZE
#define CS_COMM_MPI_PACK_SIZE CS_COMM_LNG_NOM_RUB \
+ CS_COMM_LNG_NOM_TYPE_ELT \
+ (sizeof(int) * 2)
char buffer[CS_COMM_MPI_PACK_SIZE];
int position, ierror;
MPI_Status status;
/* Instructions */
assert(comm != NULL);
assert(*nbr_elt_rub >= 0);
assert(sizeof(int) == sizeof(cs_int_t));
/* Communication en réception */
/*----------------------------*/
if (comm->mode == CS_COMM_MODE_RECEPTION) {
/* Réception du message */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_rcv_a, 0, NULL);
#endif
ierror = MPI_Recv(buffer, CS_COMM_MPI_PACK_SIZE, MPI_PACKED,
comm->rang_proc,
MPI_ANY_TAG, MPI_COMM_WORLD, &status);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_rcv_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_entete, 0, NULL);
#endif
if (ierror != MPI_SUCCESS)
cs_loc_comm_mpi_msg_err(comm, ierror);
/* Extraction des éléments du tampon */
position = 0;
MPI_Unpack(buffer, CS_COMM_MPI_PACK_SIZE, &position, num_rub,
1, CS_MPI_INT, MPI_COMM_WORLD);
if (*num_rub == 0)
MPI_Unpack(buffer, CS_COMM_MPI_PACK_SIZE, &position, nom_rub,
CS_COMM_LNG_NOM_RUB, MPI_CHAR, MPI_COMM_WORLD);
MPI_Unpack(buffer, CS_COMM_MPI_PACK_SIZE, &position, nbr_elt_rub,
1, CS_MPI_INT, MPI_COMM_WORLD);
if (*nbr_elt_rub > 0)
MPI_Unpack(buffer, CS_COMM_MPI_PACK_SIZE, &position, nom_typ_elt,
CS_COMM_LNG_NOM_TYPE_ELT, MPI_CHAR, MPI_COMM_WORLD);
}
/* Communication en émission */
/*---------------------------*/
else if (comm->mode == CS_COMM_MODE_EMISSION) {
/* Assemblage du tampon */
position = 0;
MPI_Pack(num_rub, 1, CS_MPI_INT, buffer, CS_COMM_MPI_PACK_SIZE,
&position, MPI_COMM_WORLD);
if (*num_rub == 0)
MPI_Pack(nom_rub, CS_COMM_LNG_NOM_RUB, MPI_CHAR, buffer,
CS_COMM_MPI_PACK_SIZE, &position, MPI_COMM_WORLD);
MPI_Pack(nbr_elt_rub, 1, CS_MPI_INT, buffer, CS_COMM_MPI_PACK_SIZE,
&position, MPI_COMM_WORLD);
if (*nbr_elt_rub > 0)
MPI_Pack(nom_typ_elt, CS_COMM_LNG_NOM_TYPE_ELT, MPI_CHAR, buffer,
CS_COMM_MPI_PACK_SIZE, &position, MPI_COMM_WORLD);
/* Envoi du message */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_send_a, 0, NULL);
#endif
ierror = MPI_Send(buffer, position, MPI_PACKED, comm->rang_proc,
0, MPI_COMM_WORLD);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_send_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_entete, 0, NULL);
#endif
if (ierror != MPI_SUCCESS)
cs_loc_comm_mpi_msg_err(comm, ierror);
}
else
assert( comm->mode == CS_COMM_MODE_RECEPTION
|| comm->mode == CS_COMM_MODE_EMISSION);
}
/*----------------------------------------------------------------------------
* Fonction qui échange le corps d'une rubrique via MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_corps
(
void *const elt_rub,
const cs_int_t nbr_elt_rub,
cs_type_t typ_elt,
const cs_comm_t *const comm
)
{
int ierror;
int nbr_elt = nbr_elt_rub;
MPI_Status status;
/* Instructions */
assert(comm != NULL);
assert(nbr_elt_rub >= 0);
/* Communication en réception */
/*----------------------------*/
if (comm->mode == CS_COMM_MODE_RECEPTION) {
switch (typ_elt) {
case CS_TYPE_cs_int_t: /* Tableau d'entiers */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_rcv_a, 0, NULL);
#endif
ierror = MPI_Recv(elt_rub, nbr_elt, CS_MPI_INT,
comm->rang_proc,
MPI_ANY_TAG, MPI_COMM_WORLD, &status);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_rcv_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
case CS_TYPE_cs_real_t: /* Tableau de réels double précision */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_rcv_a, 0, NULL);
#endif
ierror = MPI_Recv(elt_rub, nbr_elt, CS_MPI_REAL,
comm->rang_proc,
MPI_ANY_TAG, MPI_COMM_WORLD, &status);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_rcv_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
case CS_TYPE_char: /* Tableau de caractères */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_rcv_a, 0, NULL);
#endif
ierror = MPI_Recv(elt_rub, nbr_elt, MPI_CHAR,
comm->rang_proc,
MPI_ANY_TAG, MPI_COMM_WORLD, &status);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_rcv_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
default:
assert ( typ_elt == CS_TYPE_char
|| typ_elt == CS_TYPE_cs_int_t
|| typ_elt == CS_TYPE_cs_real_t);
}
}
/* Communication en émission */
/*---------------------------*/
else if (comm->mode == CS_COMM_MODE_EMISSION) {
switch (typ_elt) {
case CS_TYPE_cs_int_t: /* Tableau d'entiers */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_send_a, 0, NULL);
#endif
ierror = MPI_Send(elt_rub, nbr_elt, CS_MPI_INT,
comm->rang_proc,
0, MPI_COMM_WORLD);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_send_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
case CS_TYPE_cs_real_t: /* Tableau de réels double précision */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_send_a, 0, NULL);
#endif
ierror = MPI_Send(elt_rub, nbr_elt, CS_MPI_REAL,
comm->rang_proc,
0, MPI_COMM_WORLD);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_send_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
case CS_TYPE_char: /* Tableau de caractères */
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_compute_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_send_a, 0, NULL);
#endif
ierror = MPI_Send(elt_rub, nbr_elt, MPI_CHAR,
comm->rang_proc,
0, MPI_COMM_WORLD);
#if defined(_CS_HAVE_MPE) && defined(_CS_COMM_PROFILING)
MPE_Log_event(cs_glob_mpe_send_b, 0, NULL);
MPE_Log_event(cs_glob_mpe_compute_a, 0, NULL);
MPE_Log_event(cs_glob_mpe_comm_corps, 0, NULL);
#endif
break;
default:
assert( typ_elt == CS_TYPE_char
|| typ_elt == CS_TYPE_cs_int_t
|| typ_elt == CS_TYPE_cs_real_t);
}
}
else
assert( comm->mode == CS_COMM_MODE_RECEPTION
|| comm->mode == CS_COMM_MODE_EMISSION);
if (ierror != MPI_SUCCESS)
cs_loc_comm_mpi_msg_err(comm, ierror);
}
/*----------------------------------------------------------------------------
* Fonction qui imprime un message d'erreur en cas de problème de
* communication MPI
*----------------------------------------------------------------------------*/
static void cs_loc_comm_mpi_msg_err
(
const cs_comm_t *const comm,
const int error
)
{
char buffer[MPI_MAX_ERROR_STRING];
int buffer_len;
MPI_Error_string(error, buffer, &buffer_len);
bft_error(__FILE__, __LINE__, 0,
_("Erreur MPI pour la communication : %s\n"
"Type d'erreur : %s"), comm->nom, buffer);
}
#endif /* (_CS_HAVE_MPI) */
#if defined(_CS_HAVE_SOCKET)
/*----------------------------------------------------------------------------
* Fonction qui initialise une connection par "socket"
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_connect
(
cs_comm_t *comm
)
{
int ind;
#if defined(_CS_ARCH_Linux)
socklen_t long_sock;
#else
int long_sock; /* size_t d'apres standard SUS-v2, mais d'apres
man gethostbyname sous Linux, le standard est
mauvais, on doit avoir un int (ou socklen_t) */
#endif
char str_taille[6] = " ";
char *host_names = NULL;
int *tab_num_port = NULL;
#if defined (_CS_HAVE_MPI)
int ierror = MPI_SUCCESS;
#endif
int rang = (cs_glob_base_rang == -1 ? 0 : cs_glob_base_rang);
const int lng_hostname = CS_LOC_COMM_LNG_HOSTNAME + 1;
/* Connexion au socket "serveur" */
long_sock = sizeof(cs_glob_comm_addr_sock);
if (rang == 0)
comm->sock = accept(cs_glob_comm_socket,
(struct sockaddr *)&cs_glob_comm_addr_sock,
&long_sock);
/* Récupère le nom de la machine hôte et de son numéro de port sur
le rang 0 */
if (cs_glob_base_nbr > 1) {
BFT_MALLOC(host_names,
lng_hostname * cs_glob_base_nbr,
char);
BFT_MALLOC(tab_num_port, cs_glob_base_nbr, int);
#if defined(_CS_HAVE_MPI)
ierror = MPI_Gather(cs_glob_comm_sock_nom_hote, lng_hostname, MPI_CHAR,
host_names, lng_hostname, MPI_CHAR, 0,
cs_glob_base_mpi_comm);
if (ierror < 0)
bft_error(__FILE__, __LINE__, 0,
_("Erreur lors de l'envoi via MPI du nom de l'hôte "
"en initialisant les sockets.\n"));
/* Envoie du numéro de port */
ierror = MPI_Gather(&cs_glob_comm_sock_num_port, 1, MPI_INT,
tab_num_port, 1, MPI_INT, 0, cs_glob_base_mpi_comm);
if (ierror < 0)
bft_error(__FILE__, __LINE__, 0,
_("Erreur lors de l'envoi via MPI du numéro du port "
"en initialisant les sockets.\n"));
if (rang != 0)
comm->sock = accept(cs_glob_comm_socket,
(struct sockaddr *)&cs_glob_comm_addr_sock,
&long_sock);
#else
bft_error(__FILE__, __LINE__, 0,
_("Besoin de MPI lors de l'initialisation des sockets.\n"));
#endif
/* envoie depuis le rang 0 par les sockets des noms des machines
hôte et des numéros de port */
if (rang == 0) {
/* Envoi de la taille max. du nom de l'hôte */
sprintf(str_taille, "%3d", lng_hostname);
if (write(comm->sock, str_taille, 4) < 4)
bft_error(__FILE__, __LINE__, errno,
_("Erreur de communication par socket\n"));
for (ind = 1; ind < cs_glob_base_nbr; ind++) {
/* Envoi du nom de la machine hôte */
if (write(comm->sock, &(host_names[lng_hostname*ind]), lng_hostname)
< lng_hostname)
bft_error(__FILE__, __LINE__, errno,
_("Erreur de communication par socket\n"));
/* Envoi du numéro de port */
sprintf(str_taille, "%5d", tab_num_port[ind]);
if (write(comm->sock, str_taille, 6) < 6)
bft_error(__FILE__, __LINE__, errno,
_("Erreur de communication par socket\n"));
}
} /* Fin de si rang == 0 */
BFT_FREE(host_names);
BFT_FREE(tab_num_port);
} /* Fin de si cs_glob_base_nbr > 1 */
}
/*----------------------------------------------------------------------------
* Fonction qui assure l'échange de la "chaine magique" via les sockets
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_ouvre
(
cs_comm_t *const comm,
const char *const nom_fic,
const char *const chaine_magique
)
{
char nom_tmp[CS_LOC_COMM_LNG_NOM_MAX + 1];
int taille;
int rang = (cs_glob_base_rang == -1 ? 0 : cs_glob_base_rang);
taille = strlen(CS_COMM_SOCKET_ENTETE);
if (read(comm->sock, nom_tmp, taille) < taille)
bft_error(__FILE__, __LINE__, errno,
_(cs_glob_comm_err_socket), comm->nom,
rang + 1);
/* Vérification que la connexion provient du bon type d'application */
if (strncmp(nom_tmp, CS_COMM_SOCKET_ENTETE, taille != 0))
bft_error(__FILE__, __LINE__, 0,
_("Tentative de connexion au port de communication avec\n"
"un format de message non reconnu\n"));
/* Taille du nom du fichier en communication */
if (read(comm->sock, nom_tmp, 4) < 4)
bft_error(__FILE__, __LINE__, errno,
_(cs_glob_comm_err_socket), comm->nom, rang + 1);
nom_tmp[4] = '\0';
taille = atoi(nom_tmp);
if (taille <= CS_LOC_COMM_LNG_NOM_MAX) {
/* Nom du fichier en communication */
if (read(comm->sock, nom_tmp, taille) < taille)
bft_error(__FILE__, __LINE__, errno,
_(cs_glob_comm_err_socket), comm->nom, rang + 1);
nom_tmp[taille] = '\0';
/* Le nom correspond-il à celui attendu ? */
if (strcmp(nom_tmp, nom_fic) != 0)
bft_error(__FILE__, __LINE__, 0,
_("Nom du fichier de communication incohérent.\n"
"Nom reçu: \"%s\"\n"
"Nom attendu: \"%s\"\n"),
nom_tmp, nom_fic);
}
else
bft_error(__FILE__, __LINE__, 0,
_("La longueur du nom du fichier de communication est "
"trop importante\n"));
/*-----------------------------------------------------*/
/* Écriture ou lecture éventuelle d'une chaine magique */
/*-----------------------------------------------------*/
if (comm->mode == CS_COMM_MODE_RECEPTION) {
char *chaine_magique_lue;
cs_int_t lng_chaine_magique = strlen(chaine_magique);
BFT_MALLOC(chaine_magique_lue, lng_chaine_magique + 1, char);
cs_loc_comm_lit_sock(comm,
(void *)(chaine_magique_lue),
strlen(chaine_magique),
CS_TYPE_char);
chaine_magique_lue[lng_chaine_magique] = '\0';
/* Si la chaine magique ne correspond pas, on a une erreur */
if (strcmp(chaine_magique_lue, chaine_magique) != 0) {
bft_error(__FILE__, __LINE__, 0,
_("Erreur à l'initialisation de la communication : "
"\"%s\".\n"
"Le format de l'interface n'est pas à la bonne version.\n"
"La chaîne magique repère la version du format "
"d'interface :\n"
"chaîne magique lue : \"%s\"\n"
"chaîne magique actuelle : \"%s\"\n"),
comm->nom, chaine_magique_lue, chaine_magique);
}
BFT_FREE(chaine_magique_lue);
}
else if (comm->mode == CS_COMM_MODE_EMISSION) {
cs_loc_comm_ecrit_sock(comm,
(const void *)(chaine_magique),
strlen(chaine_magique),
CS_TYPE_char);
}
}
/*----------------------------------------------------------------------------
* Fonction qui ferme la connextion avec le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_sock_ferme
(
cs_comm_t *comm
)
{
if (close(comm->sock) != 0)
bft_error(__FILE__, __LINE__, errno,
_("Communication %s) :\n"
"Erreur à la fermeture du socket.\n"),
comm->nom);
comm->sock = -1;
}
/*----------------------------------------------------------------------------
* Fonction qui écrit un enregistrement dans le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_ecrit_sock
(
const cs_comm_t *const comm,
const cs_byte_t * rec,
const size_t nbr,
cs_type_t type
)
{
size_t ind_deb;
size_t ind_fin;
size_t nbr_loc;
size_t nbr_octet;
size_t taille;
ssize_t ret;
cs_byte_t * rec_tmp;
assert(rec != NULL);
assert(comm != NULL);
/* Détermination du nombre d'octets à envoyer */
switch(type) {
case CS_TYPE_cs_int_t:
taille = sizeof(cs_int_t);
break;
case CS_TYPE_cs_real_t:
taille = sizeof(cs_real_t);
break;
case CS_TYPE_char:
taille = sizeof(char);
break;
default:
assert(type == CS_TYPE_cs_int_t ||
type == CS_TYPE_cs_real_t ||
type == CS_TYPE_char);
} /* Fin `switch (type)' */
nbr_octet = taille * nbr;
/* Conversion si "little-endian" */
if (comm->swap_endian == CS_TRUE && taille != 1) {
BFT_MALLOC(rec_tmp, nbr_octet, cs_byte_t);
bft_file_swap_endian(rec_tmp, rec, taille, nbr);
}
else
rec_tmp = NULL;
/* écriture de l'enregistrement dans le socket */
/*---------------------------------------------*/
ind_deb = 0;
while (ind_deb < nbr_octet) {
ind_fin = CS_MIN(ind_deb + SSIZE_MAX, nbr_octet);
nbr_loc = ind_fin - ind_deb;
if (rec_tmp == NULL)
ret = write(comm->sock, (const void *)(rec + ind_deb), nbr_loc);
else
ret = write(comm->sock, (const void *)(rec_tmp + ind_deb), nbr_loc);
if (ret < 1)
bft_error(__FILE__, __LINE__, errno,
_("Communication %s :\n"
"Erreur d'envoi de données par socket.\n"),
comm->nom);
ind_deb += ret;
}
if (rec_tmp != NULL)
BFT_FREE(rec_tmp);
}
/*----------------------------------------------------------------------------
* Fonction qui lit un enregistrement dans le socket d'interface
*----------------------------------------------------------------------------*/
static void cs_loc_comm_lit_sock
(
const cs_comm_t *const comm,
cs_byte_t * rec,
const size_t nbr,
cs_type_t type
)
{
size_t ind_deb;
size_t ind_fin;
size_t nbr_loc;
size_t nbr_octet;
size_t taille;
ssize_t ret;
assert(rec != NULL);
assert(comm != NULL);
/* Détermination du nombre d'octets à recevoir */
switch(type) {
case CS_TYPE_cs_int_t:
taille = sizeof(cs_int_t);
break;
case CS_TYPE_cs_real_t:
taille = sizeof(cs_real_t);
break;
case CS_TYPE_char:
taille = sizeof(char);
break;
default:
assert(type == CS_TYPE_cs_int_t ||
type == CS_TYPE_cs_real_t ||
type == CS_TYPE_char);
} /* Fin `switch (type)' */
nbr_octet = taille * nbr;
/* Lecture de l'enregistrement dans le socket */
/*--------------------------------------------*/
ind_deb = 0;
while (ind_deb < nbr_octet) {
ind_fin = CS_MIN(ind_deb + SSIZE_MAX, nbr_octet);
nbr_loc = ind_fin - ind_deb;
ret = read(comm->sock, (void *)(rec + ind_deb), nbr_loc);
if (ret < 1)
bft_error(__FILE__, __LINE__, errno,
_("Communication %s :\n"
"Erreur de réception de données par socket.\n"),
comm->nom);
ind_deb += ret;
}
if (comm->swap_endian == CS_TRUE)
bft_file_swap_endian(rec, rec, taille, nbr);
}
#endif /* (_CS_HAVE_SOCKET) */
/*----------------------------------------------------------------------------
* Affichage de l'attente d'échange d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_pre
(
const cs_comm_t *const comm
)
{
assert(comm != NULL);
switch(comm->mode) {
case CS_COMM_MODE_RECEPTION:
bft_printf(_("\nMessage reçu sur \"%s\" :\n"), comm->nom);
break;
case CS_COMM_MODE_EMISSION:
bft_printf(_("\nMessage envoyé sur \"%s\" :\n"), comm->nom);
break;
default:
assert( comm->mode == CS_COMM_MODE_RECEPTION
|| comm->mode == CS_COMM_MODE_EMISSION);
}
bft_printf_flush();
}
/*----------------------------------------------------------------------------
* Affichage de l'entete d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_entete
(
const cs_int_t num_rub,
const char *const nom_rub,
const cs_int_t nbr_elt,
const cs_type_t typ_elt
)
{
char nom_rub_ecr[CS_COMM_LNG_NOM_RUB + 1];
/* instructions */
strncpy(nom_rub_ecr, nom_rub, CS_COMM_LNG_NOM_RUB);
nom_rub_ecr[CS_COMM_LNG_NOM_RUB] = '\0';
bft_printf(_(" numéro de rubrique : %d\n"
" nom de la rubrique : \"%s\"\n"
" nombre d'éléments : %d\n"),
num_rub, nom_rub_ecr, nbr_elt);
if (nbr_elt > 0) {
char *nom_typ;
switch(typ_elt) {
case CS_TYPE_char:
nom_typ = cs_comm_nom_typ_elt_char;
break;
case CS_TYPE_cs_int_t:
nom_typ = cs_comm_nom_typ_elt_int;
break;
case CS_TYPE_cs_real_t:
nom_typ = cs_comm_nom_typ_elt_real;
break;
default:
assert( typ_elt == CS_TYPE_char
|| typ_elt == CS_TYPE_cs_int_t
|| typ_elt == CS_TYPE_cs_real_t);
}
bft_printf(_(" nom du type d'élément : \"%s\"\n"), nom_typ);
}
bft_printf_flush();
}
/*----------------------------------------------------------------------------
* Affichage (partiel) du contenu d'un message
*----------------------------------------------------------------------------*/
static void cs_loc_comm_echo_donnees
(
const cs_int_t echo,
const cs_int_t nbr_elt,
const cs_type_t typ_elt,
const void *const elt_rub
)
{
cs_int_t echo_deb = 0;
cs_int_t echo_fin;
cs_int_t ind;
/* Instructions */
if (nbr_elt == 0) return;
if (echo * 2 < nbr_elt) {
echo_fin = echo;
bft_printf(_(" %d premiers et derniers éléments :\n"), echo);
}
else {
echo_fin = nbr_elt;
bft_printf(_(" éléments :\n"));
}
do {
switch (typ_elt) {
case CS_TYPE_cs_int_t:
{
const cs_int_t *elt_rub_int = (const cs_int_t *) elt_rub;
for (ind = echo_deb ; ind < echo_fin ; ind++)
bft_printf(" %10d : %12d\n", ind + 1, *(elt_rub_int + ind));
}
break;
case CS_TYPE_cs_real_t:
{
const cs_real_t *elt_rub_real = (const cs_real_t *) elt_rub;
for (ind = echo_deb ; ind < echo_fin ; ind++)
bft_printf(" %10d : %12.5e\n", ind + 1, *(elt_rub_real + ind));
}
break;
case CS_TYPE_char:
{
const char *elt_rub_char = (const char *) elt_rub;
for (ind = echo_deb ; ind < echo_fin ; ind++) {
if (*(elt_rub_char + ind) != '\0')
bft_printf(" %10d : '%c'\n", ind + 1, *(elt_rub_char + ind));
else
bft_printf(" %10d : '\\0'\n", ind + 1);
}
}
break;
default:
assert( typ_elt == CS_TYPE_cs_int_t
|| typ_elt == CS_TYPE_cs_real_t
|| typ_elt == CS_TYPE_char);
}
if (echo_fin < nbr_elt) {
bft_printf(" .......... ............\n");
echo_deb = nbr_elt - echo;
echo_fin = nbr_elt;
}
else {
assert(echo_fin == nbr_elt);
echo_fin = nbr_elt + 1;
}
} while (echo_fin <= nbr_elt);
bft_printf_flush();
}
/*----------------------------------------------------------------------------
* Fonction qui écrit un enregistrement dans le fichier d'interface
*
* Cette fonction selectionne le mode d'écriture de l'enregistrement
* (ASCII, BINAIRE ou BINAIRE FORTRAN) suivant le type du fichier
* (ASCII, BINAIRE ou BINAIRE FORTRAN)
*----------------------------------------------------------------------------*/
static void cs_loc_comm_ecrit_rec
(
const cs_comm_t *const comm,
const void *const rec,
const size_t nbr,
cs_type_t typ
)
{
size_t taille = 0;
assert(comm != NULL);
assert(rec != NULL);
switch(comm->type) {
case CS_COMM_TYPE_ASCII:
/* écriture de l'enregistrement dans le fichier ASCII */
cs_loc_comm_ecrit_ascii(comm->fic,
(const void *) rec,
(cs_int_t) nbr,
typ);
break;
case CS_COMM_TYPE_BINAIRE:
case CS_COMM_TYPE_BINAIRE_FORTRAN:
/* écriture de l'enregistrement dans le fichier */
switch(typ) {
case CS_TYPE_char:
taille = sizeof(char);
break;
case CS_TYPE_cs_int_t:
taille = sizeof(cs_int_t);
break;
case CS_TYPE_cs_real_t:
taille = sizeof(cs_real_t);
break;
default:
assert( typ == CS_TYPE_char
|| typ == CS_TYPE_cs_int_t
|| typ == CS_TYPE_cs_real_t);
}
bft_file_write(rec, taille, nbr, comm->fic);
break;
default:
assert( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN);
}
}
/*----------------------------------------------------------------------------
* Fonction qui lit un enregistrement dans le fichier d'interface
*
* Cette fonction selectionne le mode d'écriture de l'enregistrement
* (ASCII ou BINAIRE FORTRAN) suivant le type du fichier
* (ASCII ou BINAIRE FORTRAN)
*----------------------------------------------------------------------------*/
static void cs_loc_comm_lit_rec
(
const cs_comm_t *const comm,
void *const rec,
const size_t nbr,
cs_type_t typ
)
{
size_t taille = 0;
assert(comm != NULL);
assert(rec != NULL);
switch(comm->type) {
case CS_COMM_TYPE_ASCII:
cs_loc_comm_lit_ascii(comm->fic,
(void *) rec,
(cs_int_t)nbr,
typ);
break;
case CS_COMM_TYPE_BINAIRE:
case CS_COMM_TYPE_BINAIRE_FORTRAN:
/* Lecture de l'enregistrement dans le fichier */
switch (typ) {
case CS_TYPE_char:
taille = sizeof(char);
break;
case CS_TYPE_cs_int_t:
taille = sizeof(cs_int_t);
break;
case CS_TYPE_cs_real_t:
taille = sizeof(cs_real_t);
break;
default:
assert( typ == CS_TYPE_char
|| typ == CS_TYPE_cs_int_t
|| typ == CS_TYPE_cs_real_t);
}
bft_file_read(rec, taille, nbr, comm->fic);
break;
default:
assert( comm->type == CS_COMM_TYPE_ASCII
|| comm->type == CS_COMM_TYPE_BINAIRE
|| comm->type == CS_COMM_TYPE_BINAIRE_FORTRAN);
}
}
/*----------------------------------------------------------------------------
* Fonction d'impression d'un tableau en ASCII
*
* Si les valeurs sont de type "caractère", les valeurs non séparées
* par un caractère nul sont écrites sur une seule ligne
*----------------------------------------------------------------------------*/
void cs_loc_comm_ecrit_ascii
(
const bft_file_t *const fic,
const void *const tab_val,
const cs_int_t tab_nbr,
const cs_type_t typ_val
)
{
cs_int_t nbr_ligne;
cs_int_t reste_col;
cs_int_t cpt_val;
cs_int_t icol;
cs_int_t ilig;
/* Instructions */
assert(tab_val != NULL);
cpt_val = 0;
nbr_ligne = tab_nbr / CS_COMM_FMT_ASCII_NBR_COLONNE; /* Division entière */
reste_col = tab_nbr - nbr_ligne * CS_COMM_FMT_ASCII_NBR_COLONNE;
/* Impression des valeurs */
/*========================*/
switch (typ_val) {
case CS_TYPE_char:
{
const char *const tab_val_char = (const char *)tab_val;
cpt_val = 0;
while (cpt_val < tab_nbr) {
bft_file_printf(fic, "%s\n", tab_val_char + cpt_val);
cpt_val += strlen(tab_val_char + cpt_val) + 1;
}
}
break;
case CS_TYPE_cs_int_t:
{
const cs_int_t *const tab_val_int = (const cs_int_t *) tab_val;
for (ilig = 0 ; ilig < nbr_ligne ; ilig++) {
for (icol = 0 ;
icol < CS_COMM_FMT_ASCII_NBR_COLONNE ;
icol++ , cpt_val++)
bft_file_printf(fic, cs_comm_fmt_ascii_tab_int,
tab_val_int[cpt_val]);
bft_file_printf(fic, "\n");
}
if (reste_col != 0) {
for (icol = 0 ;
icol < reste_col ;
icol++ , cpt_val++)
bft_file_printf(fic, cs_comm_fmt_ascii_tab_int,
tab_val_int[cpt_val]);
bft_file_printf(fic, "\n");
}
}
break;
case CS_TYPE_cs_real_t:
{
const cs_real_t *const tab_val_real = (const cs_real_t *)tab_val;
for (ilig = 0 ; ilig < nbr_ligne ; ilig++) {
for (icol = 0 ;
icol < CS_COMM_FMT_ASCII_NBR_COLONNE ;
icol++ , cpt_val++)
bft_file_printf(fic, cs_comm_fmt_ascii_tab_real,
tab_val_real[cpt_val]);
bft_file_printf(fic, "\n");
}
if (reste_col != 0) {
for (icol = 0 ;
icol < reste_col ;
icol++ , cpt_val++)
bft_file_printf(fic, cs_comm_fmt_ascii_tab_real,
tab_val_real[cpt_val]);
bft_file_printf(fic, "\n");
}
}
break;
default:
assert ( typ_val != CS_TYPE_cs_int_t
|| typ_val != CS_TYPE_cs_real_t
|| typ_val != CS_TYPE_char);
} /* Fin : switch (typ_val_e) */
}
/*----------------------------------------------------------------------------
* Fonction de lecture formatée (stricte) d'un tableau en ASCII
*
* Si les valeurs sont de type "caractère", les valeurs sont lues
* par lignes ; entre les valeurs de chaque ligne, on insère un caractère
* nul (symétrique écriture)
*----------------------------------------------------------------------------*/
void cs_loc_comm_lit_ascii
(
const bft_file_t *const fic,
void *const tab_val,
const cs_int_t tab_nbr,
const cs_type_t typ_val
)
{
char fmt_lec[4];
char buf_loc[81];
char *res;
cs_int_t ind, len;
cs_int_t nbr_lus = 0;
cs_int_t num_ligne = 0; /* Numéro de ligne non pris en compte ici */
/* Instructions */
assert(tab_val != NULL);
/* Lecture des valeurs */
/*=====================*/
switch (typ_val) {
case CS_TYPE_char:
{
char * buf;
cs_bool_t reste_fin_ligne = CS_FALSE;
char *const tab_val_char = (char *) tab_val;
if (tab_nbr > (cs_int_t)sizeof(buf_loc) -1)
BFT_MALLOC(buf, tab_nbr + 1, char);
else
buf = buf_loc;
do {
res = bft_file_gets_try(buf,
tab_nbr - nbr_lus + 1,
fic,
&num_ligne);
len = strlen(buf);
/* On a lu une ligne entière */
if (buf[len - 1] == '\n') {
buf[len - 1] = '\0';
strcpy(tab_val_char + nbr_lus, buf);
reste_fin_ligne = CS_FALSE;
}
/* On n'a pas lu une ligne entière */
else {
strcpy(tab_val_char + nbr_lus, buf);
reste_fin_ligne = CS_TRUE;
}
nbr_lus += len;
}
while (nbr_lus < tab_nbr && res != NULL);
while (reste_fin_ligne == CS_TRUE && res != NULL) {
res = bft_file_gets_try(buf,
tab_nbr,
fic,
&num_ligne);
if (buf[strlen(buf) - 1] == '\n')
reste_fin_ligne = CS_FALSE;
}
if (buf != buf_loc)
BFT_FREE(buf);
}
break;
case CS_TYPE_cs_int_t:
{
const cs_int_t *const tab_val_int = (const cs_int_t *)tab_val;
/* Attention au format de lecture (longueur des types) ! */
fmt_lec[0] = '%';
if (sizeof(cs_int_t) == sizeof(int))
fmt_lec[1] = 'd', fmt_lec[2] = '\0';
else if (sizeof(cs_int_t) == sizeof(long))
fmt_lec[1] = 'l', fmt_lec[2] = 'd', fmt_lec[3] = '\0';
else
fmt_lec[1] = 'L', fmt_lec[2] = 'd', fmt_lec[3] = '\0';
/* Lecture effective */
while (nbr_lus < tab_nbr) {
res = bft_file_gets_try(buf_loc,
sizeof(buf_loc),
fic,
&num_ligne);
if (res == NULL)
break;
len = strlen(buf_loc);
ind = 0;
do {
for ( ; ind < len && buf_loc[ind] == ' ' ; ind++);
if (sscanf(buf_loc + ind, fmt_lec, tab_val_int + nbr_lus) < 1)
break;
nbr_lus += 1;
for ( ; ind < len && buf_loc[ind] != ' ' ; ind++);
}
while (ind < len);
}
}
break;
case CS_TYPE_cs_real_t:
{
const cs_real_t *const tab_val_real = (const cs_real_t *)tab_val;
/* Attention au format de lecture (longueur des types) ! */
fmt_lec[0] = '%';
if (sizeof(cs_real_t) == sizeof(float))
fmt_lec[1] = 'g', fmt_lec[2] = '\0';
else if (sizeof(cs_real_t) == sizeof(double))
fmt_lec[1] = 'l', fmt_lec[2] = 'g', fmt_lec[3] = '\0';
else
fmt_lec[1] = 'L', fmt_lec[2] = 'g', fmt_lec[3] = '\0';
/* Lecture effective */
while (nbr_lus < tab_nbr) {
res = bft_file_gets_try(buf_loc,
sizeof(buf_loc),
fic,
&num_ligne);
if (res == NULL)
break;
len = strlen(buf_loc);
ind = 0 ;
do {
for ( ; ind < len && buf_loc[ind] == ' ' ; ind++);
if (sscanf(buf_loc + ind, fmt_lec, tab_val_real + nbr_lus) < 1)
break;
nbr_lus += 1;
for ( ; ind < len && buf_loc[ind] != ' ' ; ind++);
}
while (ind < len);
}
}
break;
default:
assert( typ_val != CS_TYPE_char
|| typ_val != CS_TYPE_cs_int_t
|| typ_val != CS_TYPE_cs_real_t);
} /* Fin : switch (typ_val) */
if (res == NULL) {
if (bft_file_eof(fic) != 0)
bft_error(__FILE__, __LINE__, 0,
_("Fin prématurée du fichier texte %s\n"),
bft_file_get_name(fic));
else
bft_error(__FILE__, __LINE__, 0,
_("Erreur de lecture du fichier texte %s\n"),
bft_file_get_name(fic));
}
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
syntax highlighted by Code2HTML, v. 0.9.1