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