Salome HOME
MEDMEM suppression
[modules/med.git] / src / MEDSPLITTER / MEDSPLITTER_MeshSendReceive.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // File      : MEDSPLITTER_MeshSendReceive.cxx
20 // Created   : Tue Jun 30 20:39:33 2009
21 // Author    : Edward AGAPOV (eap)
22
23
24 #include "MEDSPLITTER_MeshSendReceive.hxx"
25
26 #include "MEDMEM_Meshing.hxx"
27 #include "MEDMEM_Group.hxx"
28
29 using namespace MEDSPLITTER;
30
31
32
33 #ifdef HAVE_MPI2
34
35 //=======================================================================
36 //function : MeshSendReceive
37 //purpose  : 
38 //=======================================================================
39
40 MeshSendReceive::MeshSendReceive():_mesh(0)
41 {
42   _int_request = _coord_request = _char_request = MPI_REQUEST_NULL;
43   _node_nums_request = _cell_nums_request = _face_nums_request = MPI_REQUEST_NULL;
44 }
45
46 //================================================================================
47 /*!
48  * \brief Do not die until everything is sent
49  */
50 //================================================================================
51
52 MeshSendReceive::~MeshSendReceive()
53 {
54   clear();
55 }
56
57 //================================================================================
58 /*!
59  * \brief Wait for ending send() before freeing buffers
60  */
61 //================================================================================
62
63 void MeshSendReceive::clear()
64 {
65   MPI_Request* request[6] = { &_int_request, &_coord_request, &_char_request,
66                               &_node_nums_request, &_cell_nums_request, &_face_nums_request };
67
68   for ( int i = 0; i < 6; ++i )
69   {
70     if ( *request[i] != MPI_REQUEST_NULL ) {
71       MPI_Status status;
72       MPI_Wait( request[i], &status);
73     }
74     switch ( i ) {
75     case 0: _int_buf.clear(); break;
76     case 1: /*_coord_buf.clear()*/; break;
77     case 2: _char_buf.clear(); break;
78     case 3: _node_glob_numbers.clear(); break;
79     case 4: _cell_glob_numbers.clear(); break;
80     case 5: _face_glob_numbers.clear(); break;
81     }
82   }
83 }
84
85 //================================================================================
86 /*!
87  * \brief Return true if mesh is already sent
88  */
89 //================================================================================
90
91 bool MeshSendReceive::isSent()
92 {
93   MPI_Request* request[6] = { &_int_request, &_coord_request, &_char_request,
94                               &_node_nums_request, &_cell_nums_request, &_face_nums_request };
95
96   for ( int i = 0; i < 6; ++i )
97     if ( *request[i] != MPI_REQUEST_NULL )
98     {
99       int complete;
100       MPI_Status status;
101       MPI_Request_get_status(*request[i], &complete, &status);
102       if ( !complete )
103         return false;
104     }
105   return true;
106 }
107
108 //================================================================================
109 namespace { // local utils
110 //================================================================================
111
112   using namespace MED_EN;
113   /*!
114    * \brief Pointer to data and size of data
115    */
116   template< typename T > struct TSlice
117   {
118     typedef MEDMEM::PointerOf<T> TPtr;
119     TPtr _pointer;
120     int  _size;
121
122     TSlice(): _size(0) {}
123     TSlice& operator=(const TSlice& s){_size = s._size; _pointer.set(_size,s._pointer); return *this;}
124     TSlice(const TSlice& other): _size(other._size),_pointer(other._size, other._pointer){} // copy
125     void resize(int nb) { _size=nb; _pointer.set(nb); }
126     void setPtr(int nb, const T* ptr) { _size=nb; _pointer.set(ptr); } // shallowcopy
127     void copy  (int nb, const T* ptr) { _size=nb; _pointer.set(nb,ptr); } // deep copy
128     void clear() { _size=0; _pointer.set(0); }
129     T& operator[](const int i) { return _pointer[i]; }
130     string dumpPtr() const; // debug
131   };
132   template<> string TSlice<char>::dumpPtr() const
133   {
134     return _size > 0 ? string(_pointer) : string("");
135   }
136   template<typename T> string TSlice<T>::dumpPtr() const
137   {
138     MEDMEM::STRING res("");
139     for ( int i = 0; i < _size && res.size() < 200; ++i )
140       res << _pointer[i] << " ";
141     return res;
142   }
143   typedef TSlice<int>    TIntSlice;
144   typedef TSlice<char>   TCharSlice;
145   typedef TSlice<double> TDoubleSlice;
146
147   //================================================================================
148   /*!
149    * \brief Make TCharSlice from string 
150    */
151   //================================================================================
152
153   TCharSlice toCharSlice( const string& str )
154   {
155     TCharSlice slice;
156     if ( !str.empty() )
157       slice.setPtr( str.size() + 1, str.c_str());
158     return slice;
159   }
160
161   //================================================================================
162   /*!
163    * \brief Make string from TCharSlice
164    */
165   //================================================================================
166
167   string fromCharSlice( TCharSlice& slice  )
168   {
169     return slice._size < 1 ? string() : string( slice._pointer );
170   }
171
172 #define DEB_OUT(txt) \
173 //cout << txt << endl;
174   //================================================================================
175   /*!
176    * \brief Put list of slices into one array
177    *  \param data - slices of data
178    *  \param buffer - output array
179    */
180   //================================================================================
181   template< typename T >
182   void serialize( vector< TSlice< T > >& data, vector< T >& buffer)
183   {
184     // mesure data
185     int shift = max( 1, int(sizeof(int)/sizeof(T))); // nb of T to store int
186     int size = shift; // to store nb of slices in data
187     typename vector< TSlice< T > >::iterator slice = data.begin();
188     for ( ; slice != data.end(); ++slice )
189       size += slice->_size + shift; // +shift - to store each slice size in the buffer
190
191     // fill in the buffer
192
193     buffer.resize( size );
194     T* ptr = & buffer[0];
195     // store nb of slices as the first number
196     *((int*) ptr) = (int) data.size();
197     ptr += shift;
198
199     DEB_OUT( "\n *** Nb slices: " << data.size());
200     for ( slice = data.begin(); slice != data.end(); ++slice )
201     {
202       *((int*) ptr) = (int) slice->_size;
203       ptr += shift;
204       if ( slice->_size )
205         memcpy( ptr, slice->_pointer, slice->_size * sizeof(T));
206       ptr += slice->_size;
207       DEB_OUT("#"<< slice - data.begin() << ": \tsize " << slice->_size << " \t" << slice->dumpPtr());
208       slice->clear();
209     }
210     data.clear();
211   }
212   //================================================================================
213   /*!
214    * \brief Retrieve data slices from array
215    *  \param data - output slices of data
216    *  \param buffer - data array
217    *  \retval int - zero or slice index (counting from 1) where deserialization failed
218    */
219   //================================================================================
220
221   template< typename T >
222   int deserialize( vector< T >& buffer, vector< TSlice< T > >& data )
223   {
224     T* ptr = & buffer[0];
225     T* end = ptr + buffer.size();
226
227     int nb_slices = *((int*) ptr);
228     data.resize( nb_slices );
229     int shift = max( 1, int(sizeof(int)/sizeof(T))); // nb of T to store int
230     ptr += shift;
231
232     DEB_OUT( "Nb slices: " << data.size());
233     for ( int i = 0; i < nb_slices; ++i )
234     {
235       data[i]._size = *((int*) ptr);
236       ptr += shift;
237       data[i]._pointer.set( ptr );
238       DEB_OUT("#"<< i << ": \tsize " << data[i]._size << " \t" << data[i].dumpPtr());
239       if ( data[i]._size < 0 || data[i]._size > end - ptr )
240         return i + 1; // error
241       ptr += data[i]._size;
242     }
243     DEB_OUT(" *** END" << endl )
244     return 0;
245   }
246
247   //================================================================================
248   /*!
249    * \brief Return all groups and families of mesh
250    */
251   //================================================================================
252
253   void getGroupsAndFamilies( MEDMEM::MESH*              mesh,
254                              vector< MEDMEM::GROUP*>&   groups,
255                              vector< MEDMEM::FAMILY*> & families)
256   {
257     medEntityMesh face_entity = mesh->getMeshDimension()==3 ? MED_FACE : MED_EDGE;
258
259     // get all groups
260     groups = mesh->getGroups( MED_CELL );
261     vector< MEDMEM::GROUP* > face_groups = mesh->getGroups( face_entity );
262     vector< MEDMEM::GROUP* > node_groups = mesh->getGroups( MED_NODE );
263     groups.insert( groups.end(), face_groups.begin(), face_groups.end());
264     groups.insert( groups.end(), node_groups.begin(), node_groups.end());
265
266     // get all families
267     families = mesh->getFamilies( MED_CELL );
268     vector< MEDMEM::FAMILY* > face_families = mesh->getFamilies( face_entity );
269     vector< MEDMEM::FAMILY* > node_families = mesh->getFamilies( MED_NODE );
270     families.insert( families.end(), face_families.begin(), face_families.end() );
271     families.insert( families.end(), node_families.begin(), node_families.end() );
272   }
273
274   enum SliceEnum // indices of fixed slices and sub-indices within slices
275     {
276       // INT slices
277       SLC_GENERAL_INFO = 0,
278       SLC_GEOM_TYPES,
279       SLC_FAMILY_GEN_DATA,
280       SLC_FAMILY_GROUP_IDS,
281       SLC_POLYGON_INDEX,
282       SLC_POLYHED_INDEX,
283       SLC_FIRST_STD_CONN, // index of the first of non-fixed int slices:
284       // - connectivities of std types and
285       // - elements of families
286
287       // sub-indices of SLC_GENERAL_INFO:
288       I_SPACEDIM = 0, I_MESHDIM,
289       I_NB_CELL_TYPES,  I_NB_FACE_TYPES,  I_NB_NODES, I_NB_GROUPS,
290       I_NB_CELL_FAMILY, I_NB_FACE_FAMILY, I_NB_NODES_FAMILY,
291       I_HAD_FAMILIES,
292       I_MIN_SIZE, // size of SLC_GENERAL_INFO
293
294       // sub-indices repeated within SLC_FAMILY_DATA for each group:
295       I_FAM_ID = 0, I_NB_FAM_TYPES, I_NB_FAM_GROUPS,
296       I_FAM_DATA_SIZE,
297
298       // CHAR slices
299       SLC_MESH_NAME = 0,
300       SLC_MESH_DESC,
301       SLC_COORD_SYS,
302       SLC_FIRST_COORD_NAME // index of the first of non-fixed char slices:
303       // - coord names
304       // - coord unites
305       // - family names
306       // - group names
307     };
308   enum TagEnum
309     {
310       // MPI message tags
311       TAG_INT = 1032, TAG_COORD = 2064, TAG_CHAR = 3008,
312       TAG_NODE_NUMS = 4032, TAG_CELL_NUMS = 5032, TAG_FACE_NUMS = 6032,
313
314       // miscellaneous
315       IS_ON_ALL_FLAG = -1
316     };
317
318   //================================================================================
319   /*!
320    * \brief Enrich MEDMEM::MESHING with addFamily() etc
321    */
322   //================================================================================
323
324   struct TMESHING : public MEDMEM::MESHING
325   {
326     MEDMEM::FAMILY* addFamily(MEDMEM::FAMILY* family, const medEntityMesh& entity)
327     {
328       switch ( entity ) {
329       case MED_CELL: _familyCell.push_back(family); break;
330       case MED_FACE: _familyFace.push_back(family); break;
331       case MED_EDGE: _familyEdge.push_back(family); break;
332       case MED_NODE: _familyNode.push_back(family); break;
333       default :
334         throw MED_EXCEPTION(LOCALIZED("Bad Entity !"));
335       }
336       family->setMesh( this );
337       family->setEntity( entity );
338       return family;
339     }
340     //================================================================================
341     /*!
342      * \brief Remove all families that prevent correct writting groups that not pass through
343      * send/recieve as no families exist for them
344      */
345     //================================================================================
346
347     void clearFamilies()
348     {
349       vector< MEDMEM::GROUP*> groups;
350       vector< MEDMEM::FAMILY*> families;
351       getGroupsAndFamilies(this, groups, families);
352
353       for ( int i = 0; i < families.size(); ++i )
354       {
355         addReference();
356         families[i]->removeReference();
357       }
358       _familyCell.clear();
359       _familyFace.clear();
360       _familyEdge.clear();
361       _familyNode.clear();
362
363       families.clear();
364       for ( int i = 0; i < groups.size(); ++i )
365         groups[i]->setNumberOfFamilies(0), groups[i]->setFamilies(families);
366     }
367
368     //================================================================================
369     /*!
370      * \brief Sets type of coordinate system
371      */
372     //================================================================================
373
374     void setCoordinatesSystem(const std::string& system)
375     {
376       _coordinate->setCoordinatesSystem(system);
377     }
378
379     //================================================================================
380     /*!
381      * \brief Sets space dimension
382      */
383     //================================================================================
384
385     void setSpaceDimension( int dim )
386     {
387       _spaceDimension = dim;
388     }
389
390     //================================================================================
391     /*!
392      * \brief Sets the number of nodes in the mesh
393      */
394     //================================================================================
395
396     void setNumberOfNodes(const int NumberOfNodes)
397     {
398       _numberOfNodes = NumberOfNodes ;
399     }
400   };
401
402   //================================================================================
403   /*!
404    * \brief Set string data to mesh
405    */
406   //================================================================================
407
408   void setNames( vector< TCharSlice> & char_data, MEDMEM::MESH* mesh )
409   {
410     if ( char_data.size() < SLC_FIRST_COORD_NAME + 2 * mesh->getSpaceDimension() )
411       throw MED_EXCEPTION(LOCALIZED("Internal error in MeshSendReceive::recv()"));
412
413     TMESHING* meshing = (TMESHING*) mesh;
414
415     meshing->setName             ( fromCharSlice( char_data[ SLC_MESH_NAME ]));
416     meshing->setDescription      ( fromCharSlice( char_data[ SLC_MESH_DESC ]));
417     meshing->setCoordinatesSystem( fromCharSlice( char_data[ SLC_COORD_SYS ]));
418
419     int char_slice = SLC_FIRST_COORD_NAME;
420     for ( int ax = 0; ax < meshing->getSpaceDimension(); ++ax )
421     {
422       meshing->setCoordinateName( fromCharSlice( char_data[ char_slice++ ]), ax );
423       meshing->setCoordinateUnit( fromCharSlice( char_data[ char_slice++ ]), ax );
424     }
425
426     // names of groups and families
427
428     vector< MEDMEM::GROUP* > groups;
429     vector< MEDMEM::FAMILY*> families;
430     getGroupsAndFamilies( mesh, groups, families );
431
432     int group_slice_0 = char_slice + families.size();
433     for ( int f = 0; char_slice < char_data.size() && f < families.size(); ++char_slice, ++f )
434     {
435       families[f]->setName ( fromCharSlice( char_data[ char_slice ]));
436       // group names in families
437       const string* group_ids = families[f]->getGroupsNames();
438       vector< string > group_names( families[f]->getNumberOfGroups() );
439       for ( int i = 0; i < families[f]->getNumberOfGroups(); ++i )
440       {
441         int group_id = atoi( group_ids[i].c_str() );
442         group_names[i] = fromCharSlice( char_data[ group_slice_0 + group_id ]);
443       }
444       families[f]->setGroupsNames( & group_names[0] );
445     }
446     // group names
447     for ( int g = 0; char_slice < char_data.size() && g < groups.size(); ++char_slice, ++g )
448       groups[g]->setName( fromCharSlice( char_data[ char_slice ]));
449   }
450
451
452   //================================================================================
453   /*!
454    * \brief Creates families and groups in the mesh
455    */
456   //================================================================================
457
458   void makeGroupsAndFamilies ( TMESHING* mesh, vector< TIntSlice >& int_data, int first_elem_slice )
459   {
460     int nb_cell_fams = int_data [ SLC_GENERAL_INFO ][ I_NB_CELL_FAMILY  ];
461     int nb_face_fams = int_data [ SLC_GENERAL_INFO ][ I_NB_FACE_FAMILY  ];
462     int nb_node_fams = int_data [ SLC_GENERAL_INFO ][ I_NB_NODES_FAMILY ];
463
464     medEntityMesh face_entity = mesh->getMeshDimension()==3 ? MED_FACE : MED_EDGE;
465
466     // make families
467     vector< MEDMEM::FAMILY*> families;
468     for ( int g = 0; g < nb_cell_fams; ++g )
469       families.push_back( mesh->addFamily( new MEDMEM::FAMILY, MED_CELL ));
470     for ( int g = 0; g < nb_face_fams; ++g ) 
471       families.push_back( mesh->addFamily( new MEDMEM::FAMILY, face_entity ));
472     for ( int g = 0; g < nb_node_fams; ++g )
473       families.push_back( mesh->addFamily( new MEDMEM::FAMILY, MED_NODE ));
474
475     vector< list< MEDMEM::FAMILY* > > fams_of_group( int_data[ SLC_GENERAL_INFO ][ I_NB_GROUPS ]);
476
477     const int* fam_data   = int_data [ SLC_FAMILY_GEN_DATA  ]._pointer;
478     const int* fam_groups = int_data [ SLC_FAMILY_GROUP_IDS ]._pointer;
479     int i_group = 0, fam_elem_slice = first_elem_slice;
480
481     // set family data
482     for ( int f = 0; f < families.size(); ++f, fam_data += I_FAM_DATA_SIZE )
483     {
484       families[f]->setIdentifier( fam_data[ I_FAM_ID ] );
485       // set types and elements
486       int nb_geom_types = fam_data[ I_NB_FAM_TYPES ];
487       families[f]->setNumberOfGeometricType( nb_geom_types );
488       if ( nb_geom_types < 1 || int_data[ fam_elem_slice ]._size < 1 )
489       {
490       }
491       else if ( int_data[ fam_elem_slice ][0] == IS_ON_ALL_FLAG )
492       {
493         families[f]->setAll(true);
494         families[f]->update();
495       }
496       else
497       {
498         vector< medGeometryElement > geom_types( nb_geom_types );
499         vector< int >               nb_elements( nb_geom_types );
500         vector< int >                     index( nb_geom_types + 1);
501         index[0] = 1;
502         for ( int t = 0; t < nb_geom_types; ++t )
503         {
504           if ( families[f]->getEntity() != MED_NODE )
505             geom_types[t] = mesh->getElementType( families[f]->getEntity(),
506                                                   int_data[ fam_elem_slice + t ][0] );
507           else
508             geom_types[t] = MED_NONE;
509           nb_elements[t] = int_data[ fam_elem_slice ]._size;
510           index[t+1] = index[t] + nb_elements[t];
511         }
512         families[f]->setGeometricType( &geom_types[0] );
513         families[f]->setNumberOfElements( &nb_elements[0] );
514         families[f]->setNumber(new MEDMEM::MEDSKYLINEARRAY(nb_geom_types, index[nb_geom_types]-1));
515         families[f]->getnumber()->setIndex( & index[0] );
516         for ( int t = 0; t < nb_geom_types; ++t )
517           families[f]->getnumber()->setI( t+1, int_data[ fam_elem_slice + t ]._pointer );
518       }
519       fam_elem_slice += nb_geom_types;
520
521       // set groups of a family
522       vector< string > group_names( fam_data[ I_NB_FAM_GROUPS] );
523       for ( int g = 0; g < group_names.size(); ++g )
524       {
525         int group_id = fam_groups[ i_group++ ];
526         fams_of_group[ group_id ].push_back( families[f] );
527         // store group id as string until real names are read
528         group_names[g] = MEDMEM::STRING( group_id );
529       }
530       families[f]->setNumberOfGroups( group_names.size() );
531       families[f]->setGroupsNames( &group_names[0] );
532     }
533     // create groups
534
535     for ( int g = 0; g < fams_of_group.size(); ++g )
536     {
537       MEDMEM::GROUP* group = new MEDMEM::GROUP( "", fams_of_group[ g ]);
538       mesh->addGroup( *group );
539       group->removeReference();
540     }
541   }
542
543   //================================================================================
544   /*!
545    * \brief Restore mesh from received data
546    */
547   //================================================================================
548
549   MEDMEM::MESH* makeMesh( vector< TIntSlice >& int_data, bool& toClearFamilies )
550   {
551     if ( int_data.empty() || int_data[ SLC_GENERAL_INFO ]._size < I_MIN_SIZE ||
552          int_data[ SLC_GENERAL_INFO ][ I_NB_NODES ] < 1 )
553       return 0;
554
555     TMESHING* mesh = new TMESHING();
556     // general info
557     mesh->setSpaceDimension( int_data[ SLC_GENERAL_INFO ][ I_SPACEDIM ]);
558     mesh->setNumberOfNodes ( int_data[ SLC_GENERAL_INFO ][ I_NB_NODES ]);
559     int meshDimension = int_data[ SLC_GENERAL_INFO ][ I_MESHDIM ];
560
561     // nb of types
562     medEntityMesh face_entity = meshDimension==3 ? MED_FACE : MED_EDGE;
563     int nb_cell_types = int_data[ SLC_GENERAL_INFO ][ I_NB_CELL_TYPES ];
564     int nb_face_types = int_data[ SLC_GENERAL_INFO ][ I_NB_FACE_TYPES ];
565     mesh->setNumberOfTypes ( nb_cell_types, MED_CELL );
566     mesh->setNumberOfTypes ( nb_face_types, face_entity );
567
568     // types and nb of elems
569     vector< medGeometryElement > types( nb_cell_types + nb_face_types );
570     vector< int >                nbElementsByType( types.size() ) ;
571     int t = 0, conn_slice = SLC_FIRST_STD_CONN;
572     for ( ; t < types.size(); ++t )
573     {
574       types[t] = medGeometryElement( int_data[ SLC_GEOM_TYPES ][t] );
575       if ( types[t] == MED_POLYGON )
576       {
577         nbElementsByType[t] = int_data[ SLC_POLYGON_INDEX ]._size - 1;
578       }
579       else if ( types[t] == MED_POLYHEDRA )
580       {
581         nbElementsByType[t] = int_data[ SLC_POLYHED_INDEX ]._size - 1;
582       }
583       else
584       {
585         int nn = types[t] % 100;
586         nbElementsByType[t] = int_data[ conn_slice++ ]._size / nn;
587       }
588     }
589     mesh->setTypes( &types[0], MED_CELL );
590     mesh->setTypes( &types[0] + nb_cell_types, face_entity );
591     mesh->setNumberOfElements( &nbElementsByType[0], MED_CELL );
592     mesh->setNumberOfElements( &nbElementsByType[0] + nb_cell_types, face_entity );
593
594     // connectivity
595     const int * index = 0;
596     for ( t = 0, conn_slice = SLC_FIRST_STD_CONN; t < types.size(); ++t )
597     {
598       if ( types[t] == MED_POLYGON )
599       {
600         index = int_data[ SLC_POLYGON_INDEX ]._pointer;
601       }
602       else if ( types[t] == MED_POLYHEDRA )
603       {
604         index = int_data[ SLC_POLYHED_INDEX ]._pointer;
605       }
606
607       mesh->setConnectivity( t < nb_cell_types ? MED_CELL : face_entity,
608                              types[ t ],
609                              int_data[ conn_slice++ ]._pointer,
610                              index);
611     }
612
613     // make families and groups
614
615     makeGroupsAndFamilies( mesh, int_data, SLC_FIRST_STD_CONN + types.size() );
616
617     toClearFamilies = ! int_data[ SLC_GENERAL_INFO ][ I_HAD_FAMILIES ];
618
619     return mesh;
620   }
621
622   //================================================================================
623   /*!
624    * \brief Retrieve data of groups and families
625    *  \retval int - number of geom types in all families
626    */
627   //================================================================================
628
629   int getFamilyData( MEDMEM::MESH*             mesh,
630                      vector<MEDMEM::FAMILY*> & families,
631                      vector<MEDMEM::GROUP *> & groups,
632                      vector<int> &             family_gen_data,
633                      vector<int> &             family_group_ids )
634   {
635     // get all groups and families of mesh
636     getGroupsAndFamilies( mesh, groups, families );
637     if ( families.empty() ) return 0;
638
639     // assign ids to groups
640     map < string, int > group_ids;
641     map < string, int >::iterator name_id;
642     for ( int id = 0; id < groups.size(); ++id )
643       if ( !group_ids.insert( make_pair( groups[id]->getName(), id)).second )
644         throw MED_EXCEPTION(LOCALIZED("Equal group names"));
645
646
647     family_gen_data.resize( families.size() * I_FAM_DATA_SIZE );
648     family_group_ids.clear();
649     int nb_fam_types = 0, *fam_data = &family_gen_data[0];
650
651     for ( int f = 0; f < families.size(); ++f, fam_data += I_FAM_DATA_SIZE )
652     {
653       // sum up number of geom types of families
654       int nb_types =
655         families[f]->getEntity() == MED_NODE || families[f]->isOnAllElements() ?
656         1 :
657         families[f]->getNumberOfTypes();
658       nb_fam_types += nb_types;
659
660       // fill in family_group_ids
661       for ( int g = 0; g < families[f]->getNumberOfGroups(); ++g )
662       {
663         name_id = group_ids.find( families[f]->getGroupName( g+1 ));
664         if ( name_id == group_ids.end() )
665           throw  MED_EXCEPTION (LOCALIZED(MEDMEM::STRING("Non-exiting group name:>")<<
666                                           families[f]->getGroupName( g )<<"<"));
667         family_group_ids.push_back( name_id->second );
668       }
669       // fill in family_gen_data
670       fam_data[ I_FAM_ID ]        = families[f]->getIdentifier();
671       fam_data[ I_NB_FAM_TYPES ]  = nb_types;
672       fam_data[ I_NB_FAM_GROUPS ] = families[f]->getNumberOfGroups();
673     }
674     return nb_fam_types;
675   }
676
677   //================================================================================
678   /*!
679    * \brief Store mesh as arrayrs of ints, doubles and chars
680    */
681   //================================================================================
682
683   bool getMeshData(MEDMEM::MESH*         mesh,
684                    vector< TIntSlice >&  int_data,
685                    vector< TCharSlice >& char_data,
686                    TDoubleSlice&         coords)
687   {
688     if ( !mesh || mesh->getNumberOfNodes() < 1 )
689       return false;
690     medEntityMesh face_entity = mesh->getMeshDimension()==3 ? MED_FACE : MED_EDGE;
691     medConnectivity conn = MED_NODAL;
692     bool have_faces = mesh->existConnectivity( conn, face_entity );
693     bool have_families = ( mesh->getNumberOfFamilies( MED_CELL ) +
694                            mesh->getNumberOfFamilies( face_entity ) +
695                            mesh->getNumberOfFamilies( MED_NODE ));
696
697     // create missing families
698     if ( !have_families && ( mesh->getNumberOfGroups( MED_CELL ) > 0 ||
699                              mesh->getNumberOfGroups(face_entity) > 0 ||
700                              mesh->getNumberOfGroups( MED_NODE) > 0 ))
701       mesh->createFamilies();
702
703     // general info
704
705     int general_info[ I_MIN_SIZE ] = { // SLC_GENERAL_INFO
706       mesh->getSpaceDimension(),
707       mesh->getMeshDimension(),
708       mesh->getNumberOfTypes( MED_CELL ),
709       have_faces ? mesh->getNumberOfTypes( face_entity ) : 0,
710       mesh->getNumberOfNodes(),
711       mesh->getNumberOfGroups( MED_CELL )
712       + mesh->getNumberOfGroups( face_entity )
713       + mesh->getNumberOfGroups( MED_NODE ),
714       mesh->getNumberOfFamilies( MED_CELL ),
715       mesh->getNumberOfFamilies( face_entity ),
716       mesh->getNumberOfFamilies( MED_NODE ),
717       int( have_families )
718     };
719     vector<MEDMEM::FAMILY*> families;
720     vector<MEDMEM::GROUP *> groups;
721     vector<int> family_gen_data, family_group_ids;
722     int nb_fam_types = getFamilyData( mesh, families, groups, family_gen_data, family_group_ids );
723
724     // count nb of int data slices taking into account non-fixed slices:
725     // 1) connectivities of std types and 2) elements per type of family
726     int nb_int_slices =
727       SLC_FIRST_STD_CONN +
728       general_info[ I_NB_CELL_TYPES ] +
729       general_info[ I_NB_FACE_TYPES ] +
730       nb_fam_types;
731
732     // nb of char slices (names)
733     int nb_char_slices =
734       SLC_FIRST_COORD_NAME +
735       2 * general_info[ I_SPACEDIM ] + // coord names + coord unites
736       families.size() +                // family names
737       groups.size();                   // group names
738
739     int_data. resize( nb_int_slices );
740     char_data.resize( nb_char_slices );
741
742     // general info and strings of mesh
743
744     int_data[ SLC_GENERAL_INFO ].copy( I_MIN_SIZE, general_info );
745     char_data[ SLC_MESH_NAME ] = toCharSlice( mesh->getName() );
746     char_data[ SLC_MESH_DESC ] = toCharSlice( mesh->getDescription() );
747     char_data[ SLC_COORD_SYS ] = toCharSlice( mesh->getCoordinatesSystem() );
748     int char_slice = SLC_FIRST_COORD_NAME; // next non-filled char slice
749     for ( int ax = 0; ax < general_info[ I_SPACEDIM ]; ++ax )
750     {
751       char_data[ char_slice++ ] = toCharSlice( mesh->getCoordinatesNames()[ax] );
752       char_data[ char_slice++ ] = toCharSlice( mesh->getCoordinatesUnits()[ax] );
753     }
754     int_data[ SLC_FAMILY_GEN_DATA  ].copy( family_gen_data.size(),  &family_gen_data[0] );
755     int_data[ SLC_FAMILY_GROUP_IDS ].copy( family_group_ids.size(), &family_group_ids[0] );
756     family_gen_data.clear(); family_group_ids.clear();
757
758     // geom types and their connectvity
759
760     int_data[ SLC_GEOM_TYPES ].resize( general_info[I_NB_CELL_TYPES] +
761                                        general_info[I_NB_FACE_TYPES] );
762     int* type_ptr = int_data[ SLC_GEOM_TYPES]._pointer;
763     int i_slice = SLC_FIRST_STD_CONN;
764
765     const medGeometryElement * cell_types = mesh->getTypes(MED_CELL);
766     for ( int t = 0; t < general_info[I_NB_CELL_TYPES]; ++t )
767     {
768       *type_ptr++ = cell_types[t];
769       int_data[ i_slice++ ].setPtr( mesh->getConnectivityLength( conn, MED_CELL, cell_types[t]),
770                                     mesh->getConnectivity      ( conn, MED_CELL, cell_types[t]));
771     }
772     if ( have_faces )
773     {
774       const medGeometryElement * face_types = mesh->getTypes( face_entity );
775       for ( int t = 0; t < general_info[I_NB_FACE_TYPES]; ++t )
776       {
777         *type_ptr++ = face_types[t];
778         int_data[ i_slice++ ].setPtr(mesh->getConnectivityLength( conn, face_entity, face_types[t]),
779                                      mesh->getConnectivity( conn, face_entity, face_types[t]));
780       }
781     }
782     // polygon connectivity index
783
784     medEntityMesh polygon_entity = mesh->getMeshDimension()==2 ? MED_CELL : MED_FACE;
785     if ( int nb_polygon = mesh->getNumberOfElements( polygon_entity, MED_POLYGON ))
786     {
787       const int nbTypes = mesh->getNumberOfTypes( polygon_entity );
788       const int * index = mesh->getConnectivityIndex( conn, polygon_entity );
789       index += mesh->getGlobalNumberingIndex( polygon_entity )[ nbTypes-1 ] - 1;
790       int_data[SLC_POLYGON_INDEX].setPtr( nb_polygon + 1, index );
791     }
792     // polyherdra connectivity index
793
794     if ( int nb_polyhedra = mesh->getNumberOfElements( MED_CELL, MED_POLYHEDRA ))
795     {
796       const int nbTypes = mesh->getNumberOfTypes( MED_CELL );
797       const int * index = mesh->getConnectivityIndex( conn, MED_CELL );
798       index += mesh->getGlobalNumberingIndex( MED_CELL )[ nbTypes-1 ] - 1;
799       int_data[SLC_POLYHED_INDEX].setPtr( nb_polyhedra + 1, index );
800     }
801     // coordinates
802
803     coords.setPtr( general_info[I_NB_NODES] * general_info[I_SPACEDIM],
804                    mesh->getCoordinates( MED_FULL_INTERLACE ));
805
806     // elements and names of families
807
808     int is_on_all_elements[] = { IS_ON_ALL_FLAG };
809     for ( int f = 0; f < families.size(); ++f )
810     {
811       char_data[ char_slice++ ] = toCharSlice( families[f]->getName() );
812
813       if ( families[f]->isOnAllElements() )
814       {
815         int_data[ i_slice++ ].copy( 1, is_on_all_elements);
816       }
817       else
818       {
819         bool is_nodal = ( families[f]->getEntity() == MED_NODE );
820         int nb_types = is_nodal ? 1 : families[f]->getNumberOfTypes();
821         for ( int t = 0; t < nb_types; ++t )
822         {
823           medGeometryElement type = is_nodal ? MED_ALL_ELEMENTS : families[f]->getTypes()[t];
824           int_data[ i_slice++ ].setPtr( families[f]->getNumberOfElements( type ),
825                                         families[f]->getNumber( type ));
826         }
827       }
828     }
829     // names of groups
830
831     for ( int g = 0; g < groups.size(); ++g )
832       char_data[ char_slice++ ] = toCharSlice( groups[g]->getName() );
833
834     return true;
835   }
836
837 }
838
839 //================================================================================
840 /*!
841  * \brief Send mesh to processor irank
842  *
843  * WARNING: do NOT delete the mesh until this->isSent()!
844  */
845 //================================================================================
846
847 void MeshSendReceive::send(int                irank,
848                            int                idomain,
849                            MEDMEM::MESH*      mesh,
850                            const vector<int>& cell_glob_numbers,
851                            const vector<int>& face_glob_numbers,
852                            const vector<int>& node_glob_numbers)
853 {
854   _mesh = mesh;
855   vector< TIntSlice  > int_data;
856   vector< TCharSlice > char_data;
857   TDoubleSlice         coords;
858   if ( _mesh && getMeshData( _mesh, int_data, char_data, coords ))
859   {
860     serialize( int_data, _int_buf );
861     serialize( char_data, _char_buf );
862     _node_glob_numbers = node_glob_numbers;
863     _cell_glob_numbers = cell_glob_numbers;
864     _face_glob_numbers = face_glob_numbers;
865
866     // sending
867     MPI_Isend((void*)&_int_buf[0], _int_buf.size(), MPI_INT, irank,
868               idomain + TAG_INT, MPI_COMM_WORLD, &_int_request);
869
870     MPI_Isend((void*)coords._pointer, coords._size, MPI_DOUBLE, irank,
871               idomain + TAG_COORD, MPI_COMM_WORLD, &_coord_request);
872
873     MPI_Isend((void*)&_char_buf[0], _char_buf.size(), MPI_CHAR, irank,
874               idomain + TAG_CHAR, MPI_COMM_WORLD, &_char_request);
875
876     MPI_Isend((void*)&_cell_glob_numbers[0], _cell_glob_numbers.size(), MPI_INT, irank,
877               idomain + TAG_CELL_NUMS, MPI_COMM_WORLD, &_cell_nums_request);
878
879     MPI_Isend((void*)&_face_glob_numbers[0], _face_glob_numbers.size(), MPI_INT, irank,
880               idomain + TAG_FACE_NUMS, MPI_COMM_WORLD, &_face_nums_request);
881
882     MPI_Isend((void*)&_node_glob_numbers[0], _node_glob_numbers.size(), MPI_INT, irank,
883               idomain + TAG_NODE_NUMS, MPI_COMM_WORLD, &_node_nums_request);
884   }
885   else
886   {
887     // send anything not to block recv()
888     MPI_Isend((void*)&irank, 1, MPI_INT, irank,
889               idomain + TAG_INT, MPI_COMM_WORLD, &_int_request);
890   }
891 }
892
893 //================================================================================
894 /*!
895  * \brief Receive mesh from irank processor synchronously
896  */
897 //================================================================================
898
899 MEDMEM::MESH* MeshSendReceive::recv(int irank, int idomain,
900                                     vector<int>& cell_glob_numbers,
901                                     vector<int>& face_glob_numbers,
902                                     vector<int>& node_glob_numbers)
903 {
904   _mesh = 0;
905
906   // receive INT data
907
908   MPI_Status status;
909   MPI_Probe(irank, idomain + TAG_INT, MPI_COMM_WORLD, &status); // wait for the message
910   int msg_size = 0;
911   MPI_Get_count( &status, MPI_INT, &msg_size ); // size of arrived message
912   _int_buf.resize( msg_size );
913   MPI_Recv((void*)&_int_buf[0], _int_buf.size(), MPI_INT, irank,
914            idomain + TAG_INT, MPI_COMM_WORLD, &status);
915   if ( msg_size <= I_MIN_SIZE )
916     return 0; // mesh not sent
917
918   // receive coordinates
919
920   MPI_Probe(irank, idomain + TAG_COORD, MPI_COMM_WORLD, &status); // wait for the message
921   MPI_Get_count( &status, MPI_DOUBLE, &msg_size ); // size of arrived message
922   vector< double > coord_buf( msg_size );
923   MPI_Recv((void*)&coord_buf[0], msg_size, MPI_DOUBLE, irank,
924            idomain + TAG_COORD, MPI_COMM_WORLD, &status);
925
926   // receive chars
927
928   MPI_Probe(irank, idomain + TAG_CHAR, MPI_COMM_WORLD, &status); // wait for the message
929   MPI_Get_count( &status, MPI_CHAR, &msg_size ); // size of arrived message
930   _char_buf.resize( msg_size );
931   MPI_Recv((void*)&_char_buf[0], _char_buf.size(), MPI_CHAR, irank,
932            idomain + TAG_CHAR, MPI_COMM_WORLD, &status);
933
934   // receive global cell numbers
935
936   MPI_Probe(irank, idomain + TAG_CELL_NUMS, MPI_COMM_WORLD, &status); // wait for the message
937   MPI_Get_count( &status, MPI_INT, &msg_size ); // size of arrived message
938   cell_glob_numbers.resize( msg_size );
939   MPI_Recv((void*)&cell_glob_numbers[0], cell_glob_numbers.size(), MPI_INT, irank,
940            idomain + TAG_CELL_NUMS, MPI_COMM_WORLD, &status);
941
942   // receive global face numbers
943
944   MPI_Probe(irank, idomain + TAG_FACE_NUMS, MPI_COMM_WORLD, &status); // wait for the message
945   MPI_Get_count( &status, MPI_INT, &msg_size ); // size of arrived message
946   face_glob_numbers.resize( msg_size );
947   MPI_Recv((void*)&face_glob_numbers[0], face_glob_numbers.size(), MPI_INT, irank,
948            idomain + TAG_FACE_NUMS, MPI_COMM_WORLD, &status);
949
950   // receive global node numbers
951
952   MPI_Probe(irank, idomain + TAG_NODE_NUMS, MPI_COMM_WORLD, &status); // wait for the message
953   MPI_Get_count( &status, MPI_INT, &msg_size ); // size of arrived message
954   node_glob_numbers.resize( msg_size );
955   MPI_Recv((void*)&node_glob_numbers[0], node_glob_numbers.size(), MPI_INT, irank,
956            idomain + TAG_NODE_NUMS, MPI_COMM_WORLD, &status);
957
958   // make mesh
959
960   vector< TIntSlice > int_data;
961   if ( int badSlice = deserialize( _int_buf, int_data ))
962     throw MED_EXCEPTION(MEDMEM::STRING("MeshSendReceive::recv(")<<irank<<"): "
963                                   << "int deserialization error on slice "<< badSlice);
964
965   bool toClearFamilies;
966   _mesh = makeMesh( int_data, toClearFamilies );
967   _int_buf.clear();
968   if ( !_mesh )
969     return 0;
970
971   // set coordinates
972
973   ((MEDMEM::MESHING*)_mesh)->setCoordinates( _mesh->getSpaceDimension(),
974                                              _mesh->getNumberOfNodes(),
975                                              &coord_buf[0], "",
976                                              MED_EN::MED_FULL_INTERLACE);
977   coord_buf.clear();
978
979   // set names
980
981   vector< TCharSlice > char_data;
982   if ( int badSlice = deserialize( _char_buf, char_data ))
983     throw MED_EXCEPTION(MEDMEM::STRING("MeshSendReceive::recv(")<<irank<<"): "
984                         << "char deserialization error on slice "<< badSlice);
985   setNames( char_data, _mesh );
986   _char_buf.clear();
987
988   if ( toClearFamilies )
989     ((TMESHING*) _mesh)->clearFamilies();
990
991   return _mesh;
992 }
993
994 //=======================================================================
995 #else // #ifdef HAVE_MPI2
996
997 MeshSendReceive::MeshSendReceive() {}
998 MeshSendReceive::~MeshSendReceive() {}
999 void MeshSendReceive::send(int irank, int idomain, MEDMEM::MESH* mesh, const vector<int>& cell_glob_nums, const vector<int>& face_glob_nums, const vector<int>& node_glob_numbers) {}
1000 MEDMEM::MESH* MeshSendReceive::recv(int irank,int idomain, vector<int>& cell_glob_nums, vector<int>& face_glob_nums, vector<int>& node_glob_numbers) { return 0; }
1001 bool MeshSendReceive::isSent() { return 0; }
1002 void MeshSendReceive::clear() {}
1003
1004 #endif
1005 //=======================================================================