Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/med.git] / src / MEDMEM / MEDMEM_PorflowMeshDriver.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 // 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either 
7 // version 2.1 of the License.
8 // 
9 // This library is distributed in the hope that it will be useful 
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public  
15 // License along with this library; if not, write to the Free Software 
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 #include "MEDMEM_PorflowMeshDriver.hxx"
21 #include "MEDMEM_DriversDef.hxx"
22 #include "MEDMEM_DriverTools.hxx"
23
24 #include "MEDMEM_Family.hxx"
25 #include "MEDMEM_Group.hxx"
26 #include "MEDMEM_Coordinate.hxx"
27 #include "MEDMEM_Connectivity.hxx"
28 #include "MEDMEM_Mesh.hxx"
29 #include "MEDMEM_CellModel.hxx"
30 #include "MEDMEM_define.hxx"
31 #include <string.h>
32 #include <ctype.h>
33 #include <iostream>
34 #include <sstream>
35 #include <iomanip>
36
37 using namespace std;
38 using namespace MED_EN;
39 using namespace MEDMEM;
40
41 // geometric types conversion from PORFLOW -> MED
42 //const size_t PORFLOW_MESH_DRIVER::nb_geometrie_porflow;
43 const medGeometryElement PORFLOW_MESH_DRIVER::geomPORFLOWtoMED[nb_geometrie_porflow] =
44   {   /*  1  */ MED_TRIA3   ,/*  2  */ MED_QUAD4  ,/*  3  */ MED_TETRA4  ,/*  4  */ MED_PYRA5  ,
45       /*  5  */ MED_PENTA6  ,/*  6  */ MED_HEXA8   };
46 // indirection table from PORFLOW order to MED one for nodes numerotation in all PORFLOW geometries
47 //const size_t PORFLOW_MESH_DRIVER::nb_nodes_max;
48
49 // conversion from porflow connectivity to MED connectivity
50 const int PORFLOW_MESH_DRIVER::numPORFLOWtoMED[nb_geometrie_porflow] [nb_nodes_max] = {
51       /*  TRI3   */ { /*1*/ 1, /*2*/ 3, /*3*/ 2 },
52       /*  QUA4   */ { /*1*/ 1, /*2*/ 4, /*3*/ 3, /*4*/ 2 },
53       /*  TETRA4 */ { /*1*/ 1, /*2*/ 4, /*3*/ 3, /*4*/ 2 },
54       /*  PYRA5  */ { /*1*/ 1, /*2*/ 4, /*3*/ 3, /*4*/ 2, /*5*/ 5 },
55       /*  PENTA6 */ { /*1*/ 1, /*2*/ 3, /*3*/ 2, /*4*/ 4, /*5*/ 6, /*6*/ 5 },
56       /*  HEXA8  */ { /*1*/ 1, /*2*/ 4, /*3*/ 3, /*4*/ 2, /*5*/ 5, /*6*/ 8, /*7*/ 7, /*8*/ 6 } };
57
58 // Porflox nodal connectivity of faces - documented in Porflow user's manual
59 //const size_t PORFLOW_MESH_DRIVER::nb_faces_max;
60 //const size_t PORFLOW_MESH_DRIVER::nb_nodes2_max;
61 const int PORFLOW_MESH_DRIVER::connectivityPORFLOW[nb_geometrie_porflow][nb_faces_max][nb_nodes2_max]={
62   //{/* TRI3   */ {3,1,0,0}, {1,2,0,0}, {2,3,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} },
63   //{/* QUA4   */ {1,4,0,0}, {2,3,0,0}, {1,2,0,0}, {3,4,0,0}, {0,0,0,0}, {0,0,0,0} },
64     {/* TRI3   */ {1,3,0,0}, {2,1,0,0}, {3,2,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} },
65     {/* QUA4   */ {1,4,0,0}, {3,2,0,0}, {2,1,0,0}, {4,3,0,0}, {0,0,0,0}, {0,0,0,0} },
66     {/* TETRA4 */ {1,3,4,0}, {1,4,2,0}, {4,3,2,0}, {1,2,3,0}, {0,0,0,0}, {0,0,0,0} },
67     {/* PYRA5  */ {1,4,5,0}, {1,5,2,0}, {3,2,5,0}, {4,3,5,0}, {1,2,3,4}, {0,0,0,0} },
68     {/* PENTA6 */ {1,3,6,4}, {2,1,4,5}, {3,2,5,6}, {1,2,3,0}, {4,6,5,0}, {0,0,0,0} },
69     {/* HEXA8  */ {1,4,8,5}, {3,2,6,7}, {2,1,5,6}, {4,3,7,8}, {1,2,3,4}, {5,8,7,6} },
70 };
71
72 // helper function
73 inline static bool isKeyWord(const string & line, const char * key);
74 inline static void locateFileName(const string& line, string::size_type& pos1, string::size_type& pos2);
75 inline static string getPorflowFileName(const string& line, const char * context);
76 inline static medGeometryElement get2DMedGeomType(int nbSommets);
77
78
79 // Every memory allocation made in the MedDriver members function are desallocated in the Mesh destructor 
80
81 PORFLOW_MESH_DRIVER::PORFLOW_MESH_DRIVER():
82   GENDRIVER(),
83   _ptrMesh(( MESH *) NULL),
84   // A VOIR _medIdt(MED_INVALID),
85   _meshName("")
86 {
87 }
88
89 PORFLOW_MESH_DRIVER::PORFLOW_MESH_DRIVER(const string & fileName,
90                                    MESH * ptrMesh,
91                                    MED_EN::med_mode_acces accessMode): 
92   GENDRIVER(fileName,accessMode),
93   _ptrMesh(ptrMesh)
94 {
95     // mesh name construction from fileName
96     const string ext=".inp"; // expected extension
97     string::size_type pos=fileName.find(ext,0);
98     string::size_type pos1=fileName.rfind('/');
99     _meshName = string(fileName,pos1+1,pos-pos1-1); //get rid of directory & extension
100     SCRUTE(_meshName);
101 }
102   
103 PORFLOW_MESH_DRIVER::PORFLOW_MESH_DRIVER(const PORFLOW_MESH_DRIVER & driver): 
104   GENDRIVER(driver),
105   _ptrMesh(driver._ptrMesh),
106   // A VOIR _medIdt(MED_INVALID), 
107   _meshName(driver._meshName)
108 {
109 }
110
111 PORFLOW_MESH_DRIVER::~PORFLOW_MESH_DRIVER()
112 {
113 }
114
115 void PORFLOW_MESH_DRIVER::open()
116   throw (MEDEXCEPTION)
117 {
118     const char * LOC = "PORFLOW_MESH_DRIVER::open()" ;
119     BEGIN_OF(LOC);
120     _porflow.open(_fileName.c_str(), ios::in);
121     if(_porflow)
122         _status = MED_OPENED;
123     else
124     {
125         _status = MED_CLOSED;
126         throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<<" Could not open file "<<_fileName<<" in mode ios::in"));
127     }
128     END_OF(LOC);
129 }
130   
131 void PORFLOW_MESH_DRIVER::close()
132   throw (MEDEXCEPTION)
133 {
134     const char * LOC = "PORFLOW_MESH_DRIVER::close() " ;
135     BEGIN_OF(LOC);
136     if ( _status == MED_OPENED) 
137     {
138         _porflow.close();
139         _status = MED_CLOSED;
140     }
141     END_OF(LOC);
142 }
143
144 void    PORFLOW_MESH_DRIVER::setMeshName(const string & meshName) { _meshName = meshName; };
145 string  PORFLOW_MESH_DRIVER::getMeshName() const { return _meshName; };
146
147
148 //---------------------------------- RDONLY PART -------------------------------------------------------------
149
150 PORFLOW_MESH_RDONLY_DRIVER::PORFLOW_MESH_RDONLY_DRIVER(): PORFLOW_MESH_DRIVER()
151 {
152 }
153   
154 PORFLOW_MESH_RDONLY_DRIVER::PORFLOW_MESH_RDONLY_DRIVER(const string & fileName,
155                                                  MESH * ptrMesh):
156   PORFLOW_MESH_DRIVER(fileName,ptrMesh,MED_RDONLY)
157
158   MESSAGE("PORFLOW_MESH_RDONLY_DRIVER::PORFLOW_MESH_RDONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
159 }
160   
161 PORFLOW_MESH_RDONLY_DRIVER::PORFLOW_MESH_RDONLY_DRIVER(const PORFLOW_MESH_RDONLY_DRIVER & driver): 
162   PORFLOW_MESH_DRIVER(driver)
163 {
164 }
165
166 PORFLOW_MESH_RDONLY_DRIVER::~PORFLOW_MESH_RDONLY_DRIVER()
167 {
168   //MESSAGE("PORFLOW_MESH_RDONLY_DRIVER::~PORFLOW_MESH_RDONLY_DRIVER() has been destroyed");
169 }
170   
171 GENDRIVER * PORFLOW_MESH_RDONLY_DRIVER::copy(void) const
172 {
173   return new PORFLOW_MESH_RDONLY_DRIVER(*this);
174 }
175
176 // helper function to check if line starts with key
177 inline static bool isKeyWord(const string & line, const char * key)
178 {
179     const int SIZE_KEY=4;
180     const char * pt=line.c_str();
181     while( isspace(*pt) ) // get rid of leading blanks
182         ++pt;
183     return !strncmp(pt,key,SIZE_KEY);
184 }
185
186 inline static void locateFileName(const string& line, string::size_type& pos1, string::size_type& pos2)
187 {
188     pos1 = line.find('"',0);
189     if ( pos1 != string::npos ) // if we found "
190         pos2=line.find('"',pos1+1); // search a second "
191     else // we didn't succeed with double quotes, so we try single quotes
192     {
193         pos1 = line.find('\'',0);
194         if ( pos1 != string::npos ) // if we found '
195             pos2=line.find('\'',pos1+1); // search a second '
196     }
197 }
198
199
200 // helper fonction : inversion of PORFLOW_MESH_DRIVER::geomPORFLOWtoMED
201 // return the Porflow geometric type, -1 if not found
202 inline int PORFLOW_MESH_DRIVER::geomMEDtoPorflow(medGeometryElement medGeo)
203 {
204     for (int g=0; g!=nb_geometrie_porflow; ++g)
205         if( medGeo == geomPORFLOWtoMED[g] )
206             return g;
207     return -1;
208 }
209
210
211 // Correspondance between the number of nodes and the Med face geometric type
212 inline static medGeometryElement get2DMedGeomType(int nbSommets)
213 {
214     switch (nbSommets)
215     {
216         case 2:
217             return MED_SEG2;
218             break;
219         case 3:
220             return MED_TRIA3;
221             break;
222         case 4:
223             return MED_QUAD4;
224             break;
225     }
226     return MED_NONE;
227 }
228
229 // helper function to read a porflow file name (enclosed in single or double quotes) in line
230 inline static string getPorflowFileName(const string& line, const char * context)
231 {
232     string::size_type pos1=string::npos;
233     string::size_type pos2=string::npos;
234
235     locateFileName(line, pos1, pos2);
236
237     // if we found a not empty filename
238     if (pos1 != string::npos && pos2 != string::npos && pos2>pos1+1)
239         return string(line,pos1+1,pos2-pos1-1);
240
241     // else, we throw an exception
242     string diagnosis("PORFLOW_MESH_RDONLY_DRIVER::read() : Error after reading keyword ");
243     diagnosis+=context;
244     diagnosis+="\nNo filename was found enclosed in single or double quotes\n";
245     throw MEDEXCEPTION(diagnosis.c_str());
246 }
247
248
249 // helper function to read a porflow coordinate file ( .xyz )
250 void PORFLOW_MESH_RDONLY_DRIVER::readPorflowCoordinateFile(const string & coorFileName,_intermediateMED & medi,const int space_dimension)
251 {
252
253     ifstream coorFile(coorFileName.c_str(), ios::in);
254     if(!coorFile)
255     {
256         string diagnosis("PORFLOW_MESH_RDONLY_DRIVER::read()\nError, can't open coordinates file :");
257         diagnosis+=coorFileName;
258         throw MEDEXCEPTION(diagnosis.c_str());
259     }
260     
261     // scan of the coord file
262     _noeud node;
263     node.coord.resize(space_dimension);
264     string buf_ligne; // to read a line
265     while ( getline(coorFile, buf_ligne) ) // we can't use input stream directly because some 2D files have "0.0" in third coordinate
266       {
267         istringstream buf(buf_ligne.c_str());
268         buf >> node.number;
269         if (!buf) // for spaces at the end of the file
270           break;
271         for (unsigned i=0; i!=space_dimension; ++i)
272           buf >> node.coord[i];
273         medi.points.insert(make_pair(node.number,node));
274       }
275     coorFile.close();
276 }
277
278 // helper function to read a porflow connectivity file ( .cnc )
279 void PORFLOW_MESH_RDONLY_DRIVER::readPorflowConnectivityFile(bool hybride,const string & connecFileName,_intermediateMED & medi,std::vector<std::set<_maille>::iterator>& p_ma_table,int mesh_dimension)
280 {
281
282     ifstream connFile(connecFileName.c_str(), ios::in);
283     if(!connFile)
284     {
285         string diagnosis("PORFLOW_MESH_RDONLY_DRIVER::read()\nError, can't open connectivity file :");
286         diagnosis+=connecFileName;
287         throw MEDEXCEPTION(diagnosis.c_str());
288     }
289
290     _maille maille;
291     unsigned int code, nodes_number, node;
292     pair<set<_maille>::iterator,bool> p_ma;
293
294     if (hybride) // "HYBR" key-word
295       while (connFile)
296         {
297           connFile >> maille.ordre;
298           if (!connFile) // for spaces at the end of the file
299             break;
300           connFile >> code;
301           connFile >> nodes_number;
302           maille.geometricType = geomPORFLOWtoMED[code-1];
303           if(maille.geometricType%100!=nodes_number) // following incohenrences founded in some porflow files!
304           {
305               MESSAGE("WARNING : the read node number don't seem to be compatible with geometric type!");
306               SCRUTE(maille.geometricType);
307               SCRUTE(nodes_number);
308           }
309           maille.sommets.resize(nodes_number);
310           for (unsigned i=0; i!=nodes_number; ++i)
311             {
312               connFile >> node;
313               maille.sommets[numPORFLOWtoMED[code-1][i]-1] = medi.points.find(node);
314             }
315           p_ma = medi.maillage.insert(maille);
316           if (maille.ordre > p_ma_table.size()-1) // construction of a vector of iterators on _maille structures
317             p_ma_table.resize(2*maille.ordre);
318           p_ma_table[maille.ordre] = p_ma.first;
319         }
320     else // default case (or "VERT" key-word)
321       {
322         if (mesh_dimension == 2) // we have QUA4
323           {
324             code = 2;
325             maille.geometricType = geomPORFLOWtoMED[code-1];
326             nodes_number = 4;
327             maille.sommets.resize(nodes_number);
328           }
329         else if (mesh_dimension == 3) // we have HEXA8
330           {
331             code = 6;
332             maille.geometricType = geomPORFLOWtoMED[code-1];
333             nodes_number = 8;
334             maille.sommets.resize(nodes_number);
335           }
336         else
337           throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::read()\nError, can't determine geometric type for this VERT mesh");
338         while (connFile)
339           {
340             connFile >> maille.ordre;
341             if (!connFile) // for spaces at the end of the file
342               break;
343             for (unsigned i=0; i!=nodes_number; ++i)
344               {
345                 connFile >> node;
346                 maille.sommets[numPORFLOWtoMED[code-1][i]-1] = medi.points.find(node);
347               }
348             p_ma = medi.maillage.insert(maille);
349             if (maille.ordre > p_ma_table.size()-1) // construction of a vector of iterators on _maille structures
350               p_ma_table.resize(2*maille.ordre);
351             p_ma_table[maille.ordre] = p_ma.first;
352           }
353       }
354     connFile.close();
355 }
356
357 void PORFLOW_MESH_RDONLY_DRIVER::read(void)
358   throw (MEDEXCEPTION)
359 {
360     const char * LOC = "PORFLOW_MESH_RDONLY_DRIVER::read() : " ;
361     BEGIN_OF(LOC);
362
363     if (_status!=MED_OPENED)
364         throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << "The _idt of file " << _fileName 
365                     << " is : "  <<  " (the file is not opened)." )) ;
366
367     // if _fileName contains a directory, extract the directory name
368     // the directory name will be used to locate the files included in _fileName.
369     string dirName;
370     string::size_type pos=_fileName.rfind('/');
371     if (pos != string::npos )
372         dirName=string(_fileName, 0, pos+1);
373
374     _intermediateMED medi; // structure de données intermédiaire pour conversion porflow->med
375     string buf_ligne; // pour lire une ligne
376     unsigned numberOfGridElement=0; // number of grid elements
377     unsigned space_dimension=2;  // by default, the problem is assumed to be 2D
378     string coordinateSystem="CARTESIAN";
379     bool hybride=false;
380     _groupe currentGroup;
381     vector<bool> isGroupAList; // vector to store the type of a group (ie PAIR or LIST)
382     bool processLoca=false;
383     string connFileName;
384     string coorFileName;
385     std::vector<std::set<_maille>::iterator> p_ma_table(10000); // store iterators for direct access by index
386     string small("abcdefghijklmnopqrstuvwxyz");
387
388     while ( getline(_porflow, buf_ligne) ) // scan .inp file and look for main keywords (LOCA, GRID, COOR & CONN)
389     {
390
391         // Skip comments
392         if(buf_ligne[0]=='/')
393             continue; 
394         
395         // look if there is a filename
396         string::size_type pos1=string::npos;
397         string::size_type pos2=string::npos;
398         locateFileName(buf_ligne, pos1, pos2);
399         
400         pos=0;
401         if (pos1!=string::npos && pos2!=string::npos) // if there is a file name in buf_line
402             // convert every char to upper, except those between pos1-pos2 (which correspond to a file name)
403             while ( (pos=buf_ligne.find_first_of(small,pos)) != string::npos )
404                 if (pos<pos1 || pos>pos2 )
405                     buf_ligne[pos]=toupper(buf_ligne[pos]);
406                 else
407                     ++pos;
408         else
409             // convert every char to upper
410             while ( (pos=buf_ligne.find_first_of(small,pos)) != string::npos )
411                 buf_ligne[pos]=toupper(buf_ligne[pos]);
412
413         
414         // LOCA KEYWORD :
415         //   expected syntax : 
416         //      - LOCA {PAIR} [ID=id] {N1,N2, ... ,Nn} : group specification by paired element & surface numbers
417         //      - LOCA {LIST} [ID=id] {N1, ... ,Nn}    : group specification by a list of elements
418         //   the syntax corresponding to the use of input file is not implemented
419         if ( isKeyWord(buf_ligne,"LOCA") )
420         {
421             MESSAGE("Mot clé LOCA détecté");
422             processLoca=true;
423             // if currentGroup is not empty, a group has been precessed 
424             //  -> we store it, clear currentGroup, and start the precessing of a new group
425             if ( !currentGroup.groupes.empty() )
426                 medi.groupes.push_back(currentGroup);
427             currentGroup.groupes.clear();
428             currentGroup.nom.erase();
429             if ( buf_ligne.find("PAIR",0) != string::npos )
430             {
431                 isGroupAList.push_back(false);
432             }
433             else if ( buf_ligne.find("LIST",0) != string::npos )
434             {
435                 isGroupAList.push_back(true);
436             }
437             else
438                 throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::read() : Error, after keyword LOCA, LIST or PAIR is expected\n");
439                 
440             pos=buf_ligne.find("ID=",0);
441             if ( pos != string::npos )
442             {
443                 istringstream buf(buf_ligne.c_str()+pos+3);
444                 buf >> currentGroup.nom;
445
446                 // avoid problem in the following processing of elements if the group's name contains a digit
447                 // -> we replace group's name with blanks
448                 while( pos<buf_ligne.size() && !isspace( buf_ligne[pos] ) )
449                     buf_ligne[pos++]=' ';
450             }
451         }
452
453
454         // GRID KEYWORD :
455         //   expected syntax : GRID {UNST} [THREE] {N1} [NODE] [N2]
456         //   the syntax corresponding to structured grids is not implemented
457         else if ( isKeyWord(buf_ligne,"GRID") )
458         {
459             MESSAGE("Mot clé GRID détecté");
460             processLoca=false;
461             pos=buf_ligne.find("UNST",0);
462             if ( pos != string::npos ) // unstructured grid
463             {
464                 // we find the number of grid elements
465                 string::size_type len=buf_ligne.size();
466                 while ( pos<len && !isdigit(buf_ligne[pos]) )
467                         ++pos;
468                 if ( pos==len )
469                     throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::read() : Error, number of grid elements unspecified!\n");
470                 istringstream buf(buf_ligne.c_str()+pos);
471                 buf >> numberOfGridElement;
472
473                 pos=buf_ligne.find("THREE",0);
474                 if ( pos != string::npos ) // if we find THREE, the problem is 3D
475                     space_dimension=3;
476             }
477             else
478             {
479                 throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::read() : Error, structured grids are not yet supported!\n");
480             }
481         }
482         
483
484         // CONN KEYWORD :
485         //   expected syntax : 
486         //      - CONN {HYBR} {filename} : vertex connectivity for mixed hybrid elements
487         //      - CONN {VERT} {filename} : vertex connectivity for quad or hex elements
488         //   the default option is HYBR
489         else if ( isKeyWord(buf_ligne,"CONN") )
490         {
491             MESSAGE("Mot clé CONN détecté");
492             processLoca=false;
493             string fileCONN=getPorflowFileName(buf_ligne,"CONN");
494             
495             if ( buf_ligne.find("HYBR",0) != string::npos )
496                 hybride=true;
497
498
499             if(fileCONN.rfind('/') == string::npos)
500                 // no directory was specified -> we add dirName, which may be empty
501
502                 connFileName=dirName+fileCONN;
503             else
504                 connFileName=fileCONN;
505         }
506
507         
508         // COOR KEYWORD :
509         //   expected syntax : COOR {VERT} {filename}
510         else if ( isKeyWord(buf_ligne,"COOR") )
511         {
512             MESSAGE("Mot clé COOR");
513             processLoca=false;
514             string fileCOOR=getPorflowFileName(buf_ligne,"COOR");
515
516             pos=buf_ligne.find("VERT",0);
517             if ( pos == string::npos ) 
518                 throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::read() : Error, after keyword COOR, we require VERT\n");
519
520             pos=buf_ligne.find("CYLI",0);
521             if ( pos != string::npos )
522                 coordinateSystem="CYLINDRICAL";
523
524             if(fileCOOR.rfind('/') == string::npos)
525                 // no directory was specified -> we add dirName, which may be empty
526                 coorFileName=dirName+fileCOOR;
527             else
528                 coorFileName=fileCOOR;
529         }
530
531
532         if (processLoca) 
533         {
534             // read group specification
535
536
537             // replace non digit caracters with blanks
538             string::iterator last_non_blank=buf_ligne.end();
539             for (string::iterator it=buf_ligne.begin(); it!=buf_ligne.end(); ++it)
540                 if ( !isdigit(*it) )
541                     *it=' ';
542                 else
543                     last_non_blank=it;
544
545             if (last_non_blank != buf_ligne.end() ) // if the line is not blank
546             {
547                 buf_ligne=string(buf_ligne.begin(),++last_non_blank); // suppress trailing blanks
548
549                 istringstream buf(buf_ligne.c_str());
550                 int i1;
551                 buf >> i1; // we know the line is not blank
552                 do
553                 {
554                     currentGroup.groupes.push_back(i1);
555                     buf >> i1;
556                 }
557                 while ( buf );
558
559             }
560         }
561         
562     }
563     if ( !currentGroup.groupes.empty() ) // if necessary, add the last group to medi.groupes
564         medi.groupes.push_back(currentGroup);
565
566     readPorflowCoordinateFile(coorFileName,medi,space_dimension);
567     readPorflowConnectivityFile(hybride,connFileName,medi,p_ma_table,space_dimension);
568
569
570     // Group processing :
571     //   In the scan loop, we have store in medi.groupes.groupes either :
572     //     - paired list of element and surface number (keyword PAIR)
573     //     - an explicit list of element numbers (keyword LIST)
574     //   What we stored (pairs or list) is remembered through vector isGroupAList.
575     //   For both cases, we must convert these numbers to iterators to cells inside the set medi.maillage
576     //     - in the LIST case, these cells already exist.
577     //     - in the PAIR case, we have to create the corresponding 2D/1D faces
578     // scan groups
579     //for( std::vector<_groupe>::iterator i=medi.groupes.begin(); i!=medi.groupes.end(); ++i)
580     for( int i=0; i!=medi.groupes.size(); ++i)
581     {
582         if ( isGroupAList[i] ) 
583         {
584             // medi.groupes[i].groupes is a vector of element numbers; it points to it
585             medi.groupes[i].mailles.resize( medi.groupes[i].groupes.size() );
586             std::vector<int>::const_iterator it=medi.groupes[i].groupes.begin();
587             for(int j = 0 ; it!=medi.groupes[i].groupes.end(); ++it, ++j)
588             {
589                 // insert the iterator to the corresponding cell we stored in p_ma_table
590                 medi.groupes[i].mailles[j] = p_ma_table[*it];
591             }
592             
593         }
594         else
595         {
596             int nelem=0;
597             int nface=0;
598             int ngeom=0;
599             int ielem=0;
600             std::set<_maille>::iterator p_ma;
601             _maille maille2D;
602             
603             // medi.groupes[i].groupes is a vector of paired element and surface numbers
604             // *it points to the element number,  *(it+1) points to the surface number
605             std::vector<int>::const_iterator it=medi.groupes[i].groupes.begin();
606             medi.groupes[i].mailles.resize( medi.groupes[i].groupes.size() / 2 );
607             for(  ; it!=medi.groupes[i].groupes.end(); ++it)
608             {
609                 nelem=*it;
610                 nface=*(++it);
611                 p_ma=p_ma_table[nelem]; // points to the cell
612                 ngeom=geomMEDtoPorflow(p_ma->geometricType);
613
614                 // create the face corresponding to nface
615                 int l=0;
616                 while( l<nb_nodes2_max && connectivityPORFLOW[ngeom][nface-1][l] )
617                 {
618                     maille2D.sommets.push_back(p_ma->sommets[ numPORFLOWtoMED[ngeom][ connectivityPORFLOW[ngeom][nface-1][l++]-1 ]-1 ]);
619                 }
620
621                 // the corresponding 2D MED geometric type depends upon the number of nodes
622                 maille2D.sommets.resize(l);
623                 maille2D.geometricType = get2DMedGeomType(l);
624                 p_ma = medi.maillage.insert(maille2D).first; // we insert the face in our mesh
625                 medi.groupes[i].mailles[ielem++]=p_ma; // and insert an iterator on it in our group
626                 maille2D.sommets.clear();
627             }
628
629         }
630         medi.groupes[i].groupes.clear(); // we don't need element numbers anymore
631         
632     }
633
634     p_ma_table.clear(); // we don't need it anymore
635     MESSAGE(LOC << "PORFLOW_MESH_RDONLY_DRIVER::read : RESULTATS STRUCTURE INTERMEDIAIRES : ");
636     MESSAGE(LOC <<  medi );
637             // TRANSFORMATION EN STRUCTURES MED
638     if ( ! _ptrMesh->isEmpty() )
639     {
640         throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<<"Mesh object not empty : can't fill it!"));
641     }
642     else if ( medi.maillage.size()==0 || medi.groupes.size()==0 || medi.points.size()==0)
643     {
644         throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Error while reading file " << _fileName 
645                     << " The data read are not completed " ) ) ;
646     }
647     else
648     {
649         _ptrMesh->_name = _meshName;
650         _ptrMesh->_spaceDimension = medi.points.begin()->second.coord.size();
651         _ptrMesh->_meshDimension = medi.maillage.rbegin()->dimension();
652         _ptrMesh->_numberOfNodes = medi.points.size();
653         _ptrMesh->_isAGrid = 0;
654         _ptrMesh->_coordinate = medi.getCoordinate();
655
656         //Construction des groupes
657         vector<GROUP *> groupCell, groupFace, groupEdge, groupNode;
658         medi.getGroups(groupCell, groupFace, groupEdge, groupNode, _ptrMesh);
659         _ptrMesh->_groupCell = groupCell;
660         _ptrMesh->_groupFace = groupFace;
661         _ptrMesh->_groupEdge = groupEdge;
662         _ptrMesh->_groupNode = groupNode;
663
664         // appele en dernier car cette fonction detruit le maillage intermediaire!
665         _ptrMesh->_connectivity = medi.getConnectivity(); 
666         MESSAGE(LOC << "PORFLOW_MESH_RDONLY_DRIVER::read : FIN ");
667
668         // calcul de la connectivite d-1 complete, avec renumerotation des groupes
669         // if (_ptrMesh->_spaceDimension==3)
670         //     _ptrMesh->_connectivity->updateGroup(_ptrMesh->_groupFace) ;
671         // else if (_ptrMesh->_spaceDimension==2)
672         //     _ptrMesh->_connectivity->updateGroup(_ptrMesh->_groupEdge) ;
673         
674         // Creation des familles ?artir des groupes
675         // NC : Cet appel pourra ?e diff鲩 quand la gestion de la coh鲥nce famille/groupes sera assur饊      _ptrMesh->createFamilies();
676     }
677
678
679     END_OF(LOC);
680 }
681
682 void PORFLOW_MESH_RDONLY_DRIVER::write( void ) const
683   throw (MEDEXCEPTION)
684 {
685   throw MEDEXCEPTION("PORFLOW_MESH_RDONLY_DRIVER::write : Can't write with a RDONLY driver !");
686 }
687
688
689 /*--------------------- WRONLY PART -------------------------------*/
690
691 PORFLOW_MESH_WRONLY_DRIVER::PORFLOW_MESH_WRONLY_DRIVER():PORFLOW_MESH_DRIVER()
692 {
693 }
694   
695 PORFLOW_MESH_WRONLY_DRIVER::PORFLOW_MESH_WRONLY_DRIVER(const string & fileName,
696                                                  MESH * ptrMesh):
697   PORFLOW_MESH_DRIVER(fileName,ptrMesh,MED_WRONLY)
698 {
699   MESSAGE("PORFLOW_MESH_WRONLY_DRIVER::PORFLOW_MESH_WRONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
700 }
701
702 PORFLOW_MESH_WRONLY_DRIVER::PORFLOW_MESH_WRONLY_DRIVER(const PORFLOW_MESH_WRONLY_DRIVER & driver): 
703   PORFLOW_MESH_DRIVER(driver)
704 {
705 }
706
707 PORFLOW_MESH_WRONLY_DRIVER::~PORFLOW_MESH_WRONLY_DRIVER()
708 {
709   //MESSAGE("PORFLOW_MESH_WRONLY_DRIVER::PORFLOW_MESH_WRONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been destroyed");
710 }
711
712 GENDRIVER * PORFLOW_MESH_WRONLY_DRIVER::copy(void) const
713 {
714   return new PORFLOW_MESH_WRONLY_DRIVER(*this);
715 }
716
717 void PORFLOW_MESH_WRONLY_DRIVER::read (void)
718   throw (MEDEXCEPTION)
719 {
720   throw MEDEXCEPTION("PORFLOW_MESH_WRONLY_DRIVER::read : Can't read with a WRONLY driver !");
721 }
722
723 void PORFLOW_MESH_WRONLY_DRIVER::write(void) const
724   throw (MEDEXCEPTION)
725
726   const char * LOC = "void PORFLOW_MESH_WRONLY_DRIVER::write(void) const : ";
727   BEGIN_OF(LOC);
728
729   throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<< "Write Driver isn\'t implemented"));
730
731   END_OF(LOC);
732
733
734
735
736 /*--------------------- RDWR PART -------------------------------*/
737
738 PORFLOW_MESH_RDWR_DRIVER::PORFLOW_MESH_RDWR_DRIVER():PORFLOW_MESH_DRIVER()
739 {
740 }
741
742 PORFLOW_MESH_RDWR_DRIVER::PORFLOW_MESH_RDWR_DRIVER(const string & fileName,
743                                            MESH * ptrMesh):
744   PORFLOW_MESH_DRIVER(fileName,ptrMesh,MED_RDWR)
745 {
746   MESSAGE("PORFLOW_MESH_RDWR_DRIVER::PORFLOW_MESH_RDWR_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
747 }
748
749 PORFLOW_MESH_RDWR_DRIVER::PORFLOW_MESH_RDWR_DRIVER(const PORFLOW_MESH_RDWR_DRIVER & driver): 
750   PORFLOW_MESH_RDONLY_DRIVER::PORFLOW_MESH_DRIVER(driver)
751 {
752 }
753
754 PORFLOW_MESH_RDWR_DRIVER::~PORFLOW_MESH_RDWR_DRIVER() {
755   //MESSAGE("PORFLOW_MESH_RDWR_DRIVER::PORFLOW_MESH_RDWR_DRIVER(const string & fileName, MESH * ptrMesh) has been destroyed");
756
757   
758 GENDRIVER * PORFLOW_MESH_RDWR_DRIVER::copy(void) const
759 {
760   return new PORFLOW_MESH_RDWR_DRIVER(*this);
761 }
762
763 void PORFLOW_MESH_RDWR_DRIVER::write(void) const
764   throw (MEDEXCEPTION)
765 {
766   PORFLOW_MESH_WRONLY_DRIVER::write();
767 }
768 void PORFLOW_MESH_RDWR_DRIVER::read (void)
769   throw (MEDEXCEPTION)
770 {
771   PORFLOW_MESH_RDONLY_DRIVER::read();
772 }