Salome HOME
*** empty log message ***
[modules/multipr.git] / src / MULTIPR / MULTIPR_MeshDis.cxx
1 // Project MULTIPR, IOLS WP1.2.1 - EDF/CS
2 // Partitioning/decimation module for the SALOME v3.2 platform
3
4 /**
5  * \file    MULTIPR_MeshDis.cxx
6  *
7  * \brief   see MULTIPR_MeshDis.hxx
8  *
9  * \author  Olivier LE ROUX - CS, Virtual Reality Dpt
10  * 
11  * \date    01/2007
12  */
13
14 //*****************************************************************************
15 // Includes section
16 //*****************************************************************************
17
18 #include "MULTIPR_MeshDis.hxx"
19 #include "MULTIPR_Mesh.hxx"
20 #include "MULTIPR_Utils.hxx"
21 #include "MULTIPR_Globals.hxx"
22 #include "MULTIPR_API.hxx"
23 #include "MULTIPR_Exceptions.hxx"
24 #include "MULTIPR_ProgressCallback.hxx"
25
26 #include "MEDSPLITTER_API.hxx"
27
28 #include <iostream>
29 #include <fstream>
30
31 using namespace std;
32
33
34 namespace multipr
35 {
36
37
38 //*****************************************************************************
39 // Global variables (exported)
40 //*****************************************************************************
41
42 MULTIPR_ProgressCallback* gProgressCallback = NULL;
43
44
45 //*****************************************************************************
46 // Class MeshDisEntry implementation
47 //*****************************************************************************
48
49 MeshDisPart::MeshDisPart()
50 {
51         mMesh             = NULL;
52         mCollection       = NULL;
53         mOldCollection    = NULL;
54         
55         reset();
56 }
57
58
59 MeshDisPart::~MeshDisPart()
60 {
61         reset();
62 }
63
64
65 void MeshDisPart::reset()
66 {
67         mToDoOnNextWrite = MULTIPR_UNDEFINED;
68         
69         mMeshName[0]     = '\0';
70         mId              = 0;
71         mPartName[0]     = '\0';
72         mPath[0]         = '\0';
73         mMEDFileName[0]  = '\0';
74         
75         if (mMesh != NULL)
76         {
77                 delete mMesh;
78                 mMesh = NULL;
79         }
80         
81         mSplit           = 0;
82         
83         if (mCollection != NULL)
84         {
85                 delete mCollection;
86                 mCollection = NULL;
87         }
88         
89         if (mOldCollection != NULL)
90         {
91                 delete mOldCollection;
92                 mOldCollection = NULL;
93         }
94 }
95
96
97 const char* MeshDisPart::getMEDFileNameSuffix() const
98 {       
99         // "agregat100grains_12pas_grain97.med"                       -> "grain97"
100         // "agregat100grains_12pas_grain100_part2.med"                -> "grain100_part2"
101         // "aagregat100grains_12pas_grain98_gradmoy-low-25.0-0.3.med" -> "grain98_gradmoy-low-25-0.3"
102         
103         string prefix = removeExtension(mMEDFileName, ".med");
104         prefix.erase(0, prefix.rfind("grain"));
105         return prefix.c_str();
106 }
107
108
109 void MeshDisPart::create(
110                 OnNextWrite pToDoOnNextWrite,
111                 const char* pMeshName, 
112                 int         pId,
113                 const char* pPartName,
114                 const char* pPath,
115                 const char* pMEDFileName,
116                 Mesh*       pMesh)
117 {
118         if (pToDoOnNextWrite == MULTIPR_UNDEFINED) throw IllegalArgumentException("", __FILE__, __LINE__);
119         if (pMeshName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
120         if (pId < 1) throw IllegalArgumentException("", __FILE__, __LINE__);
121         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
122         if (pPath == NULL) throw NullArgumentException("", __FILE__, __LINE__);
123         if (pMEDFileName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
124         
125         reset();
126         
127         mToDoOnNextWrite = pToDoOnNextWrite;
128         strcpy(mMeshName, pMeshName);
129         mId = pId;
130         strcpy(mPartName, pPartName);
131         strcpy(mPath, pPath);
132         strcpy(mMEDFileName, pMEDFileName);
133         mMesh = pMesh;
134         
135 }
136
137
138 void MeshDisPart::readMED()
139 {
140         if (mMesh != NULL) throw IllegalStateException("", __FILE__, __LINE__);
141         if (mCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
142         if (mOldCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
143         
144         //cout << "read MED : mesh=" << mMEDfilename << endl;
145         
146         mMesh = new Mesh();
147         mMesh->readSequentialMED(mMEDFileName, mMeshName);
148 }
149
150
151 ostream& operator<<(ostream& pOs, MeshDisPart& pM)
152 {
153         switch (pM.mToDoOnNextWrite)
154         {
155                 case MeshDisPart::MULTIPR_UNDEFINED: 
156                         pOs << "undefined"; 
157                         break;
158                         
159                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
160                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
161                         break;
162                         
163                 case MeshDisPart::MULTIPR_WRITE_MESH:
164                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
165                         break;
166                         
167                 case MeshDisPart::MULTIPR_WRITE_PARTS:
168                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName << " SPLIT " << pM.mSplit;
169                         break;
170                 
171                 default: throw IllegalStateException("", __FILE__, __LINE__);
172         }
173         
174         return pOs;
175 }
176
177
178 //*****************************************************************************
179 // Class MeshDis implementation
180 //*****************************************************************************
181
182 MeshDis::MeshDis()
183 {
184         reset();
185 }
186
187
188 MeshDis::~MeshDis()
189 {
190         reset();
191 }
192
193
194 void MeshDis::reset()
195 {
196         mMEDfilename[0] = '\0';
197         
198         for (unsigned itPart = 0 ; itPart != mParts.size() ; itPart++)
199         {
200                 MeshDisPart* part = mParts[itPart];
201                 delete part;
202         }
203         mParts.clear();
204         
205         //mProgressCallback = NULL;
206 }
207
208
209 void MeshDis::addMesh(
210         MeshDisPart::OnNextWrite pToDoOnNextWrite,
211         const char* pMeshName, 
212         int         pId,
213         const char* pPartName,
214         const char* pPath,
215         const char* pMEDFileName,
216         Mesh*       pMesh)
217 {
218         MeshDisPart* part = new MeshDisPart();
219         
220         part->create(
221                 pToDoOnNextWrite,
222                 pMeshName,
223                 pId,
224                 pPartName,
225                 pPath,
226                 pMEDFileName,
227                 pMesh);
228         
229         mParts.push_back(part);
230 }
231
232
233 void MeshDis::insertMesh(
234         MeshDisPart::OnNextWrite pToDoOnNextWrite,
235         const char* pMeshName, 
236         int         pId,
237         const char* pPartName,
238         const char* pPath,
239         const char* pMEDFileName,
240         Mesh*       pMesh,
241         int         pPosition)
242 {
243         // debug
244         //cout << "INSERT PARTS BEFORE: " << endl;
245         //cout << (*this) << endl;
246         
247         MeshDisPart* part = new MeshDisPart();
248         
249         part->create(
250                 pToDoOnNextWrite,
251                 pMeshName,
252                 pId,
253                 pPartName,
254                 pPath,
255                 pMEDFileName,
256                 pMesh);
257         
258         mParts.insert(mParts.begin() + pPosition, part);
259         
260         // rename id of following parts
261         for (unsigned i = pPosition + 1 ; i < mParts.size() ; i++)
262         {
263                 mParts[i]->mId++;
264         }
265         
266         // debug
267         //cout << "INSERT PARTS AFTER: " << endl;
268         //cout << (*this) << endl;
269 }
270
271
272 void MeshDis::removeParts(const char* pPrefixPartName)
273 {
274         // debug
275         //cout << "REMOVE PARTS BEFORE: " << endl;
276         //cout << (*this) << endl;
277         
278         if (pPrefixPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
279         
280         for (vector<MeshDisPart*>::iterator itPart = mParts.begin() ; itPart != mParts.end() ; itPart++)
281         {
282                 MeshDisPart* currentPart = (*itPart);
283                 
284                 if (startWith(currentPart->getPartName(), pPrefixPartName))
285                 {
286                         mParts.erase(itPart);
287                 
288                         // decrement id of following parts
289                         for (vector<MeshDisPart*>::iterator itPart2 = itPart ; itPart2 != mParts.end() ; itPart2++)
290                         {
291                                 (*itPart2)->mId--;
292                         }
293                         
294                         itPart--;
295                         if (currentPart->mMEDFileName != NULL)
296                         {
297                                 remove(currentPart->mMEDFileName);
298                         }
299                         
300                         delete currentPart;
301                 }
302         }
303         
304         // debug
305         //cout << "REMOVE PARTS AFTER: " << endl;
306         //cout << (*this) << endl;
307 }
308
309
310 MeshDisPart* MeshDis::findPart(const char* pPartName)
311 {
312         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
313         
314         MeshDisPart* part = NULL;
315         
316         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
317         {
318                 MeshDisPart* currentPart = mParts[itPart];
319                 
320                 if (strcmp(currentPart->getPartName(), pPartName) == 0)
321                 {
322                         part = currentPart;
323                         break;
324                 }
325         }
326         
327         return part;
328         
329 }
330
331
332 vector<string> MeshDis::getMeshes() const
333 {
334         vector<string> res;
335         
336         if (mParts.size() > 0)
337         {
338                 MeshDisPart* part = mParts[0];
339                 const char* meshName = part->getMeshName();
340                 res.push_back(meshName);
341         }
342         
343         return res;
344 }
345
346
347 vector<string> MeshDis::getFields() const
348 {
349         vector<string> res;
350         
351         if (mParts.size() == 0)
352         {
353                 return res;
354         }
355         
356         // all the parts of the distributed MED file should have the same fields
357         // => just return the name of fields of the first part
358         switch (mParts[0]->mToDoOnNextWrite)
359         {
360                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
361                 case MeshDisPart::MULTIPR_WRITE_PARTS:
362                 {
363                         vector<pair<string, int> > tmp = multipr::getListFields(mParts[0]->getMEDFileName());
364         
365                         for (int i = 0 ; i < tmp.size() ; i++)
366                         {
367                                 res.push_back(tmp[i].first);
368                         }
369                         return res;
370                 }
371                         
372                 case MeshDisPart::MULTIPR_WRITE_MESH:
373                         return mParts[0]->mMesh->getNameFields();
374                 
375                 default: 
376                         throw IllegalStateException("", __FILE__, __LINE__);
377         }
378 }
379
380
381 int MeshDis::getTimeStamps(const char* pFieldName) const
382 {
383         if (mParts.size() == 0)
384         {
385                 // no parts in this distributed MED file => no fields => #iteration = 0
386                 return 0;
387         }
388         
389         // all the parts of the distributed MED file should have the same fields
390         // => just return the number of iteration found in the field of the first part
391         switch (mParts[0]->mToDoOnNextWrite)
392         {
393                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
394                 case MeshDisPart::MULTIPR_WRITE_PARTS:
395                 {
396                         vector<pair<string, int> > tmp = multipr::getListFields(mParts[0]->getMEDFileName());
397                 
398                         for (int i = 0 ; i < tmp.size() ; i++)
399                         {
400                                 if (strcmp(tmp[i].first.c_str(), pFieldName) == 0)
401                                 {
402                                         return tmp[i].second;
403                                 }
404                         }
405                         
406                         // pFieldName not found in the list of fields
407                         return 0;
408                 }
409                         
410                 case MeshDisPart::MULTIPR_WRITE_MESH:
411                         return mParts[0]->mMesh->getTimeStamps(pFieldName);
412                 
413                 default: 
414                         throw IllegalStateException("", __FILE__, __LINE__);
415         }
416 }
417
418
419 string MeshDis::getPartInfo(const char* pPartName)
420 {
421         MeshDisPart* part = findPart(pPartName);
422         
423         if (part != NULL)
424         {
425                 char num[16];
426                 sprintf(num, "%d", part->mId);
427                 
428                 string res = 
429                         string(part->mMeshName) + 
430                         string(" ") +
431                         string(num) +
432                         string(" ") +
433                         string(part->mPartName) +
434                         string(" ") +
435                         string(part->mPath) +
436                         string(" ") +
437                         string(part->mMEDFileName);
438
439                 return res;
440         }
441         else
442         {
443                 // part not found => return empty string
444                 return "";
445         }
446 }
447
448
449 void MeshDis::splitPart(const char* pPartName, int pNbParts, int pPartitionner)
450 {
451         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
452         if (pNbParts < 2) throw IllegalArgumentException("", __FILE__, __LINE__);
453         if ((pPartitionner != MULTIPR_METIS) && (pPartitionner != MULTIPR_SCOTCH)) throw IllegalArgumentException("should be 0=METIS or 1=SCOTCH", __FILE__, __LINE__);
454         
455         //---------------------------------------------------------------------
456         // Find the MED file corresponding to the given part
457         //---------------------------------------------------------------------
458         MeshDisPart* part = findPart(pPartName);
459         
460         if (part == NULL)
461         {
462                 throw IllegalArgumentException("part not found in this distributed MED file", __FILE__, __LINE__);
463         }
464         
465         //---------------------------------------------------------------------
466         // Load the sequential MED file
467         //---------------------------------------------------------------------
468         MEDSPLITTER::MESHCollection* collection;
469         collection = new MEDSPLITTER::MESHCollection(part->getMEDFileName(), part->getMeshName());
470         
471         //---------------------------------------------------------------------
472         // Partition the group
473         //---------------------------------------------------------------------
474         MEDSPLITTER::Topology* topology;
475         if (pPartitionner == MULTIPR_METIS)
476         {
477                 try
478                 {
479                         topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::METIS);
480                 }
481                 catch (...)
482                 {
483                         throw RuntimeException("MEDSPLITTER error: createPartition(), using METIS", __FILE__, __LINE__);
484                 }
485         }
486         else if (pPartitionner == MULTIPR_SCOTCH)
487         {
488                 try
489                 {
490                         topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::SCOTCH);
491                 }
492                 catch (...)
493                 {
494                         throw RuntimeException("MEDSPLITTER error: createPartition(), using SCOTCH", __FILE__, __LINE__);
495                 }
496         }
497         else
498         {
499                 throw IllegalStateException("unknown partitionner", __FILE__, __LINE__);
500         }
501         
502         try
503         {
504                 MEDSPLITTER::MESHCollection* newCollection = new MEDSPLITTER::MESHCollection(*collection, topology);
505                 
506                 part->mToDoOnNextWrite = MeshDisPart::MULTIPR_WRITE_PARTS; 
507                 part->mSplit           = pNbParts;
508                 part->mOldCollection   = collection;
509                 part->mCollection      = newCollection;
510         }
511         catch (...)
512         {
513                 throw RuntimeException("MEDSPLITTER error: new MESHCollection()", __FILE__, __LINE__);
514         }
515 }
516
517
518 void MeshDis::decimatePart(
519         const char* pPartName, 
520         const char* pFieldName,
521         med_int     pFieldIt,
522         const char* pFilterName,
523         med_float   pTMed, 
524         med_float   pTLow,
525         med_float   pRadius,
526         int         pBoxing)
527 {
528         //---------------------------------------------------------------------
529         // Check arguments
530         //---------------------------------------------------------------------
531         if (pPartName == NULL) throw NullArgumentException("partname should not be NULL", __FILE__, __LINE__);
532         if (pFieldName == NULL) throw NullArgumentException("fieldname should not be NULL", __FILE__, __LINE__);
533         if (pFieldIt < med_int(1)) throw IllegalArgumentException("invalid field iteration; should be >= 1", __FILE__, __LINE__);
534         if (pTMed < 0.0) throw IllegalArgumentException("med res.: threshold must be > 0", __FILE__, __LINE__);
535         if (pTMed >= pTLow) throw IllegalArgumentException("threshold for med res. must be < threshold for low res.", __FILE__, __LINE__);      
536         if (pRadius <= med_float(0.0)) throw IllegalArgumentException("radius should be > 0", __FILE__, __LINE__);
537         if ((pBoxing < 1) || (pBoxing > 200)) throw IllegalArgumentException("boxing should be in [1..200]", __FILE__, __LINE__);
538         
539         //---------------------------------------------------------------------
540         // Find the MED file corresponding to the given part
541         //---------------------------------------------------------------------
542         MeshDisPart* part = findPart(pPartName);
543         if (part == NULL)
544         {
545                 throw IllegalArgumentException("part not found in the given distributed MED file", __FILE__, __LINE__);
546         }
547         
548         //---------------------------------------------------------------------
549         // Load the associated sequential MED file
550         //---------------------------------------------------------------------
551         if (part->mMesh == NULL)
552         {
553                 part->readMED();
554         }
555         
556         Mesh* meshFull = part->mMesh;
557         cout << (*meshFull) << endl;
558         
559         const char* originalFilename = part->getMEDFileName();
560         string strPrefix = removeExtension(originalFilename, ".med");
561         
562 cout << (*this) << endl;
563         //---------------------------------------------------------------------
564         // Decimates the given mesh
565         //---------------------------------------------------------------------
566         // arguments for decimation are passed as a string for genericity
567         char argv[256];
568         char newPartName[MED_TAILLE_NOM + 1];
569         char newMEDFileName[256];
570         
571         // *** create a new mesh = MEDIUM resolution ***
572         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTMed, pRadius, pBoxing);
573         sprintf(newPartName, "%s_MED", pPartName);
574         sprintf(newMEDFileName, "%s_gradmoy-med-%s-%s.med", 
575                 strPrefix.c_str(), 
576                 realToString(pTMed).c_str(), 
577                 realToString(pRadius).c_str());
578         
579         {
580                 Mesh* meshMedium = meshFull->decimate(pFilterName, argv, part->getMeshName());
581                 cout << (*meshMedium) << endl;
582                 
583                 insertMesh(
584                         MeshDisPart::MULTIPR_WRITE_MESH,
585                         part->getMeshName(),
586                         part->mId + 1,
587                         newPartName,
588                         "localhost",
589                         newMEDFileName,
590                         meshMedium,
591                         part->mId + 0);
592         }
593         
594         // *** create a new mesh = LOW resolution ***
595         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTLow, pRadius, pBoxing);
596         sprintf(newPartName, "%s_LOW", pPartName);
597         sprintf(newMEDFileName, "%s_gradmoy-low-%s-%s.med", 
598                 strPrefix.c_str(), 
599                 realToString(pTLow).c_str(), 
600                 realToString(pRadius).c_str());
601         
602         {
603                 Mesh* meshLow = meshFull->decimate(pFilterName, argv, part->getMeshName());
604                 cout << (*meshLow) << endl;
605                 
606                 insertMesh(
607                         MeshDisPart::MULTIPR_WRITE_MESH,
608                         part->getMeshName(),
609                         part->mId + 2,
610                         newPartName,
611                         "localhost",
612                         newMEDFileName,
613                         meshLow,
614                         part->mId + 1);
615         }
616         
617 cout << (*this) << endl;
618 }
619
620
621 int MeshDis::computeNumParts()
622 {
623         int numParts = 0;
624         
625         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
626         {
627                 switch (mParts[itPart]->mToDoOnNextWrite)
628                 {
629                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
630                 case MeshDisPart::MULTIPR_WRITE_MESH:
631                         numParts++;
632                         break;
633                 
634                 case MeshDisPart::MULTIPR_WRITE_PARTS:
635                         numParts += mParts[itPart]->mSplit;
636                         break;
637                 
638                 default: throw IllegalStateException("", __FILE__, __LINE__);
639                 }
640         }
641         
642         return numParts;
643 }
644
645
646 void MeshDis::readDistributedMED(const char* pMEDfilename)
647 {
648         //cout << "DBG: readDistributedMED" << endl;
649         if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
650         
651         const int MAX_SIZEOF_LINE = 1024;
652         
653         reset();
654         strcpy(mMEDfilename, pMEDfilename);
655         
656         //---------------------------------------------------------------------
657         // Open master file (ASCII file)
658         //---------------------------------------------------------------------
659         ifstream fileMaster(mMEDfilename);
660         if (fileMaster.fail()) throw IOException("i/o error while opening MED master file", __FILE__, __LINE__);
661
662         //cout << "DBG: readDistributedMED: open" << endl;
663
664         //---------------------------------------------------------------------
665         // Read header
666         //---------------------------------------------------------------------
667         char charbuffer[MAX_SIZEOF_LINE];
668         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
669         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
670         
671         // check format
672         if ((charbuffer[0] != '#') ||
673             (charbuffer[1] != ' ') ||
674                 (charbuffer[2] != 'M') ||
675                 (charbuffer[3] != 'E') ||
676                 (charbuffer[4] != 'D'))
677                 throw IOException("not a valid distributed MED file", __FILE__, __LINE__);
678                 
679         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
680         {
681                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
682                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
683         }
684         
685         // read number of parts
686         int nbParts = atoi(charbuffer);
687         //cout << "DBG: readDistributedMED: #parts=" << nbParts << endl;
688         
689         //---------------------------------------------------------------------
690         // Read infos about sub-parts
691         //---------------------------------------------------------------------
692         char   lMeshName[MED_TAILLE_NOM + 1];
693         int    lId;
694         char   lPartName[MED_TAILLE_NOM + 1];
695         char   lPath[256];
696         char   lMEDFileName[256];       
697         
698         for (int i = 0 ; i < nbParts ; i++)
699         {
700                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
701                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
702                 
703                 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
704                 {
705                         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
706                         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
707                 }
708                 
709                 lMeshName[0]    = '\0';
710                 lId             = 0;
711                 lPartName[0]    = '\0';
712                 lPath[0]        = '\0';
713                 lMEDFileName[0] = '\0';
714                 
715                 int ret = sscanf(charbuffer, "%s %d %s %s %s", 
716                         lMeshName,
717                         &lId,
718                         lPartName,
719                         lPath,
720                         lMEDFileName);
721         
722                 if (ret != 5) throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
723
724                 //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
725                 addMesh(
726                         MeshDisPart::MULTIPR_KEEP_AS_IT,
727                         lMeshName,
728                         lId,
729                         lPartName,
730                         lPath,
731                         lMEDFileName,
732                         NULL);
733         }
734         
735         //---------------------------------------------------------------------
736         // Close master file
737         //---------------------------------------------------------------------
738         fileMaster.close();
739         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
740         //cout << "DBG: readDistributedMED: close" << endl;
741 }
742
743
744 /**
745  * Retrieves the output of MEDSPLITTER and convert it for MULTIPR.
746  */
747 int convertMedsplitterToMultipr(ofstream& pFileMaster, const char* pTmpFilename, int pId, MeshDisPart* pPart)
748 {
749         MULTIPR_LOG("convert" << endl);
750         
751         const int MAX_SIZEOF_LINE = 1024;
752         char charbuffer[MAX_SIZEOF_LINE];
753         
754         // Open medsplitter master file (ASCII file)
755         ifstream fileMasterMedsplitter(pTmpFilename);
756         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while opening MEDSPLITTER master file", __FILE__, __LINE__);
757         
758         fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
759         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);     
760
761         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
762         {
763                 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
764                 if (fileMasterMedsplitter.fail()) throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);
765         }
766
767         // read number of parts
768         int nbParts = atoi(charbuffer);
769         cout << "nb parts=" << nbParts << endl;
770
771         char   lMeshName[MED_TAILLE_NOM + 1];
772         int    lId;
773         char   lPartName[MED_TAILLE_NOM + 1];
774         char   lPath[256];
775         char   lMEDFileName[256];
776         
777         for (int i = 0 ; i < nbParts ; i++)
778         {
779                 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
780                 if (fileMasterMedsplitter.fail()) throw IOException("", __FILE__, __LINE__);
781                 
782                 // parses the current line
783                 lMeshName[0]    = '\0';
784                 lId             = 0;
785                 lPartName[0]    = '\0';
786                 lPath[0]        = '\0';
787                 lMEDFileName[0] = '\0';
788                 
789                 int ret = sscanf(charbuffer, "%s %d %s %s %s", 
790                         lMeshName,
791                         &lId,
792                         lPartName,
793                         lPath,
794                         lMEDFileName);
795                         
796                 if (ret != 5) throw IOException("i/o error while reading MEDSPLITTER master file; bad format", __FILE__, __LINE__);
797                 
798                 //cout << lMeshName << " " << (pId + i) << " " << pPart->getPartName() << "_" << (i + 1) << " " << lPath << " " << lMEDFileName << endl;
799                 
800                 pFileMaster << lMeshName << " " << (pId + i) << " " << pPart->getPartName() << "_" << (i + 1) << " " << lPath << " " << lMEDFileName << endl;
801         }
802         
803         fileMasterMedsplitter.close();
804         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while closing MEDSPLITTER master file", __FILE__, __LINE__);
805         
806         // remove master file generated by MEDSPLITTER
807         remove(pTmpFilename);
808         
809         return nbParts;
810 }
811
812
813 void MeshDis::writeDistributedMED(const char* pMEDfilenamePrefix)
814 {
815         if (pMEDfilenamePrefix == NULL) throw NullArgumentException("", __FILE__, __LINE__);
816         
817         //---------------------------------------------------------------------
818         // Build master filename
819         //---------------------------------------------------------------------
820         string strPrefix = string(pMEDfilenamePrefix);
821         const char* strExtension = ".med";
822         string strMasterFilename;
823         
824         // add suffix "_grains_maitre" iff it is not yet in the filename
825         if (strstr(pMEDfilenamePrefix, "_grains_maitre") == 0)
826         {
827                 strMasterFilename= strPrefix + "_grains_maitre" + strExtension;
828         }
829         else
830         {
831                 strMasterFilename = strPrefix + strExtension;
832         }
833         
834         MULTIPR_LOG("Create master: " << strMasterFilename << endl);
835         strcpy(mMEDfilename, strMasterFilename.c_str());
836         
837         //---------------------------------------------------------------------
838         // Create an ASCII master file for the resulting distributed mesh and write header
839         //---------------------------------------------------------------------
840         remove(strMasterFilename.c_str());
841         ofstream fileMaster(strMasterFilename.c_str());
842         
843         if (fileMaster == 0) throw IOException("i/o error while creating MED master file", __FILE__, __LINE__);
844         
845         fileMaster << "# MED file v2.3 - Master file created by MULTIPR v" << getVersion() << endl;
846         fileMaster << "#" << " " << endl;
847         
848         fileMaster << computeNumParts() << endl;
849         if (fileMaster.fail()) throw IOException("i/o error while writing MED master file", __FILE__, __LINE__);
850         
851         //---------------------------------------------------------------------
852         // Create a new MED file (v2.3)
853         //---------------------------------------------------------------------
854         int id = 1;
855         
856         if (gProgressCallback != NULL) gProgressCallback->start("Save mesh", mParts.size());
857         
858         try
859         {
860         
861         // for each sub-meshes
862         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
863         {
864                 switch (mParts[itPart]->mToDoOnNextWrite)
865                 {
866                         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
867                         {
868                                 mParts[itPart]->mId = id;
869                                 id++;
870                                 fileMaster << (*mParts[itPart]) << endl;
871                                 cout << (*mParts[itPart]) << endl;
872                                 break;
873                         }
874                         
875                         case MeshDisPart::MULTIPR_WRITE_MESH:
876                         {
877                                 if (strlen(mParts[itPart]->getMEDFileName()) == 0) throw IOException("MED filename is empty", __FILE__, __LINE__);
878                                 if (mParts[itPart]->mMesh == NULL) throw IllegalStateException("invalid mesh (shoult not be NULL)", __FILE__, __LINE__);
879                                 mParts[itPart]->mMesh->writeMED(mParts[itPart]->getMEDFileName());
880                                 mParts[itPart]->mId = id;
881                                 id++;
882                                 fileMaster << (*mParts[itPart]) << endl;
883                                 cout << (*mParts[itPart]) << endl;
884                                 break;
885                         }
886                         
887                         case MeshDisPart::MULTIPR_WRITE_PARTS:
888                         {
889                                 // split this part using medsplitter
890                                 if (mParts[itPart]->mOldCollection == NULL) throw IllegalStateException("", __FILE__, __LINE__);
891                                 string strPrefix = removeExtension(mParts[itPart]->getMEDFileName(), ".med"); 
892                                 char tmpFilename[256];
893                                 sprintf(tmpFilename, "%s_part", strPrefix.c_str());
894                                 mParts[itPart]->mCollection->write(tmpFilename);
895                                 mParts[itPart]->mCollection->castAllFields(*(mParts[itPart]->mOldCollection));
896                                 int ret = convertMedsplitterToMultipr(fileMaster, tmpFilename, id, mParts[itPart]);
897                                 id += ret;
898                                 remove(mParts[itPart]->getMEDFileName());
899                                 break;
900                         }
901                 
902                         default: throw IllegalStateException("should not be there", __FILE__, __LINE__);
903                 }
904                 
905                 if (gProgressCallback != NULL) gProgressCallback->moveOn();
906         }
907         
908         }
909         catch (RuntimeException& e)
910         {
911                 if (gProgressCallback != NULL) gProgressCallback->done();
912                 throw e;
913         }
914         
915         if (gProgressCallback != NULL) gProgressCallback->done();
916         
917         //---------------------------------------------------------------------
918         // Close master file
919         //---------------------------------------------------------------------
920         fileMaster.close();
921         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
922 }
923
924
925 ostream& operator<<(ostream& pOs, MeshDis& pM)
926 {
927         pOs << "Mesh Dis.:" << endl;
928         pOs << "    Filename   =|" << pM.mMEDfilename << "|" << endl;
929         pOs << "    #Sub-meshes=" << pM.mParts.size() << endl;
930         
931         for (unsigned itPart = 0 ; itPart < pM.mParts.size() ; itPart++)
932         {
933                 cout << "        " << (itPart + 1) << ": " << (*(pM.mParts[itPart])) << endl; 
934         }
935         
936         return pOs;
937 }
938
939
940 } // namespace multipr
941
942 // EOF