Salome HOME
4f2a301699d4fedc56240923f22baba92e5162d5
[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 cout << (*this) << endl;
570         //---------------------------------------------------------------------
571         // Decimates the given mesh
572         //---------------------------------------------------------------------
573         // arguments for decimation are passed as a string for genericity
574         char argv[256];
575         char newPartName[MED_TAILLE_NOM + 1];
576         char newMEDFileName[256];
577         
578         // *** create a new mesh = MEDIUM resolution ***
579         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTMed, pRadius, pBoxing);
580         sprintf(newPartName, "%s_MED", pPartName);
581         sprintf(newMEDFileName, "%s_gradmoy-med-%s-%s.med", 
582                 strPrefix.c_str(), 
583                 realToString(pTMed).c_str(), 
584                 realToString(pRadius).c_str());
585         
586         {
587                 Mesh* meshMedium = meshFull->decimate(pFilterName, argv, part->getMeshName());
588                 cout << (*meshMedium) << endl;
589                 
590                 insertMesh(
591                         MeshDisPart::MULTIPR_WRITE_MESH,
592                         part->getMeshName(),
593                         part->mId + 1,
594                         newPartName,
595                         "localhost",
596                         newMEDFileName,
597                         meshMedium,
598                         part->mId + 0);
599         }
600         
601         // *** create a new mesh = LOW resolution ***
602         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTLow, pRadius, pBoxing);
603         sprintf(newPartName, "%s_LOW", pPartName);
604         sprintf(newMEDFileName, "%s_gradmoy-low-%s-%s.med", 
605                 strPrefix.c_str(), 
606                 realToString(pTLow).c_str(), 
607                 realToString(pRadius).c_str());
608         
609         {
610                 Mesh* meshLow = meshFull->decimate(pFilterName, argv, part->getMeshName());
611                 cout << (*meshLow) << endl;
612                 
613                 insertMesh(
614                         MeshDisPart::MULTIPR_WRITE_MESH,
615                         part->getMeshName(),
616                         part->mId + 2,
617                         newPartName,
618                         "localhost",
619                         newMEDFileName,
620                         meshLow,
621                         part->mId + 1);
622         }
623         
624         // debug
625         //cout << (*this) << endl;
626 }
627
628
629 string MeshDis::evalDecimationParams(
630         const char* pPartName, 
631         const char* pFieldName, 
632         int         pFieldIt, 
633         const char* pFilterName,
634         const char* pFilterParams)
635 {
636         MeshDisPart* part = findPart(pPartName);
637         if (part == NULL) return "";
638         
639         try
640         {
641                 if (part->mMesh == NULL)
642                 {
643                         part->readMED();
644                 }
645         
646                 multipr::DecimationFilter* filter = multipr::DecimationFilter::create(pFilterName);
647                 if (filter == NULL) return "";
648                 
649                 multipr::DecimationFilterGradAvg* filterGrad = dynamic_cast<multipr::DecimationFilterGradAvg*>(filter);
650                 
651                 if (filterGrad != NULL)
652                 {
653                         int mode;
654                         
655                         int ret = sscanf(pFilterParams, "%d", &mode);
656                         
657                         // mode 2 = GET RADIUS
658                         if ((ret == 1) && (mode == 2))
659                         {
660                                 double radius = part->mMesh->evalDefaultRadius(8);
661                                 char res[256];
662                                 sprintf(res, "%f", radius);
663                                 return res;
664                         }
665                         
666                         float radius;
667                         int boxing;
668                         
669                         ret = sscanf(pFilterParams, "%d %f %d", &mode, &radius, &boxing);
670                         
671                         // mode 1 = GET GRADIENT MIN, MAX and AVG
672                         if ((ret == 3) && (mode == 1))
673                         {
674                                 double gradMin = 0.1, gradAvg = 0.15, gradMax = 0.2;
675                                 
676                                 filterGrad->getGradientInfo(
677                                         part->mMesh,
678                                         pFieldName,
679                                         pFieldIt,
680                                         radius,
681                                         boxing,
682                                         &gradMin,
683                                         &gradAvg,
684                                         &gradMax);
685                                 
686                                 char res[2048];
687                                 sprintf(res, "%f %f %f", gradMin, gradAvg, gradMax);
688                                 return res;
689                         }
690                 }
691                 
692                 delete filter;
693         }
694         catch(...)
695         {
696                 return "";
697         }
698 }
699
700
701 int MeshDis::computeNumParts()
702 {
703         int numParts = 0;
704         
705         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
706         {
707                 switch (mParts[itPart]->mToDoOnNextWrite)
708                 {
709                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
710                 case MeshDisPart::MULTIPR_WRITE_MESH:
711                         numParts++;
712                         break;
713                 
714                 case MeshDisPart::MULTIPR_WRITE_PARTS:
715                         numParts += mParts[itPart]->mSplit;
716                         break;
717                 
718                 default: throw IllegalStateException("", __FILE__, __LINE__);
719                 }
720         }
721         
722         return numParts;
723 }
724
725
726 void MeshDis::readDistributedMED(const char* pMEDfilename)
727 {
728         //cout << "DBG: readDistributedMED" << endl;
729         if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
730         
731         const int MAX_SIZEOF_LINE = 1024;
732         
733         reset();
734         strcpy(mMEDfilename, pMEDfilename);
735         
736         //---------------------------------------------------------------------
737         // Open master file (ASCII file)
738         //---------------------------------------------------------------------
739         ifstream fileMaster(mMEDfilename);
740         if (fileMaster.fail()) throw IOException("i/o error while opening MED master file", __FILE__, __LINE__);
741
742         //cout << "DBG: readDistributedMED: open" << endl;
743
744         //---------------------------------------------------------------------
745         // Read header
746         //---------------------------------------------------------------------
747         char charbuffer[MAX_SIZEOF_LINE];
748         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
749         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
750         
751         // check format
752         if ((charbuffer[0] != '#') ||
753             (charbuffer[1] != ' ') ||
754                 (charbuffer[2] != 'M') ||
755                 (charbuffer[3] != 'E') ||
756                 (charbuffer[4] != 'D'))
757                 throw IOException("not a valid distributed MED file", __FILE__, __LINE__);
758                 
759         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
760         {
761                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
762                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
763         }
764         
765         // read number of parts
766         int nbParts = atoi(charbuffer);
767         //cout << "DBG: readDistributedMED: #parts=" << nbParts << endl;
768         
769         //---------------------------------------------------------------------
770         // Read infos about sub-parts
771         //---------------------------------------------------------------------
772         char   lMeshName[MED_TAILLE_NOM + 1];
773         int    lId;
774         char   lPartName[MED_TAILLE_NOM + 1];
775         char   lPath[256];
776         char   lMEDFileName[256];       
777         
778         for (int i = 0 ; i < nbParts ; i++)
779         {
780                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
781                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
782                 
783                 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
784                 {
785                         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
786                         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
787                 }
788                 
789                 lMeshName[0]    = '\0';
790                 lId             = 0;
791                 lPartName[0]    = '\0';
792                 lPath[0]        = '\0';
793                 lMEDFileName[0] = '\0';
794                 
795                 int ret = sscanf(charbuffer, "%s %d %s %s %s", 
796                         lMeshName,
797                         &lId,
798                         lPartName,
799                         lPath,
800                         lMEDFileName);
801         
802                 if (ret != 5) throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
803
804                 //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
805                 addMesh(
806                         MeshDisPart::MULTIPR_KEEP_AS_IT,
807                         lMeshName,
808                         lId,
809                         lPartName,
810                         lPath,
811                         lMEDFileName,
812                         NULL);
813         }
814         
815         //---------------------------------------------------------------------
816         // Close master file
817         //---------------------------------------------------------------------
818         fileMaster.close();
819         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
820         //cout << "DBG: readDistributedMED: close" << endl;
821 }
822
823
824 /**
825  * Retrieves the output of MEDSPLITTER and convert it for MULTIPR.
826  */
827 int convertMedsplitterToMultipr(ofstream& pFileMaster, const char* pTmpFilename, int pId, MeshDisPart* pPart)
828 {
829         MULTIPR_LOG("convert" << endl);
830         
831         const int MAX_SIZEOF_LINE = 1024;
832         char charbuffer[MAX_SIZEOF_LINE];
833         
834         // Open medsplitter master file (ASCII file)
835         ifstream fileMasterMedsplitter(pTmpFilename);
836         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while opening MEDSPLITTER master file", __FILE__, __LINE__);
837         
838         fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
839         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);     
840
841         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
842         {
843                 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
844                 if (fileMasterMedsplitter.fail()) throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);
845         }
846
847         // read number of parts
848         int nbParts = atoi(charbuffer);
849         cout << "nb parts=" << nbParts << endl;
850
851         char   lMeshName[MED_TAILLE_NOM + 1];
852         int    lId;
853         char   lPartName[MED_TAILLE_NOM + 1];
854         char   lPath[256];
855         char   lMEDFileName[256];
856         
857         for (int i = 0 ; i < nbParts ; i++)
858         {
859                 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
860                 if (fileMasterMedsplitter.fail()) throw IOException("", __FILE__, __LINE__);
861                 
862                 // parses the current line
863                 lMeshName[0]    = '\0';
864                 lId             = 0;
865                 lPartName[0]    = '\0';
866                 lPath[0]        = '\0';
867                 lMEDFileName[0] = '\0';
868                 
869                 int ret = sscanf(charbuffer, "%s %d %s %s %s", 
870                         lMeshName,
871                         &lId,
872                         lPartName,
873                         lPath,
874                         lMEDFileName);
875                         
876                 if (ret != 5) throw IOException("i/o error while reading MEDSPLITTER master file; bad format", __FILE__, __LINE__);
877                 
878                 //cout << lMeshName << " " << (pId + i) << " " << pPart->getPartName() << "_" << (i + 1) << " " << lPath << " " << lMEDFileName << endl;
879                 
880                 pFileMaster << lMeshName << " " << (pId + i) << " " << pPart->getPartName() << "_" << (i + 1) << " " << lPath << " " << lMEDFileName << endl;
881         }
882         
883         fileMasterMedsplitter.close();
884         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while closing MEDSPLITTER master file", __FILE__, __LINE__);
885         
886         // remove master file generated by MEDSPLITTER
887         remove(pTmpFilename);
888         
889         return nbParts;
890 }
891
892
893 void MeshDis::writeDistributedMED(const char* pMEDfilenamePrefix)
894 {
895         if (pMEDfilenamePrefix == NULL) throw NullArgumentException("", __FILE__, __LINE__);
896         
897         //---------------------------------------------------------------------
898         // Build master filename
899         //---------------------------------------------------------------------
900         string strPrefix = string(pMEDfilenamePrefix);
901         const char* strExtension = ".med";
902         string strMasterFilename;
903         
904         // add suffix "_grains_maitre" iff it is not yet in the filename
905         if (strstr(pMEDfilenamePrefix, "_grains_maitre") == 0)
906         {
907                 strMasterFilename= strPrefix + "_grains_maitre" + strExtension;
908         }
909         else
910         {
911                 strMasterFilename = strPrefix + strExtension;
912         }
913         
914         MULTIPR_LOG("Create master: " << strMasterFilename << endl);
915         strcpy(mMEDfilename, strMasterFilename.c_str());
916         
917         //---------------------------------------------------------------------
918         // Create an ASCII master file for the resulting distributed mesh and write header
919         //---------------------------------------------------------------------
920         remove(strMasterFilename.c_str());
921         ofstream fileMaster(strMasterFilename.c_str());
922         
923         if (fileMaster == 0) throw IOException("i/o error while creating MED master file", __FILE__, __LINE__);
924         
925         fileMaster << "# MED file v2.3 - Master file created by MULTIPR v" << getVersion() << endl;
926         fileMaster << "#" << " " << endl;
927         
928         fileMaster << computeNumParts() << endl;
929         if (fileMaster.fail()) throw IOException("i/o error while writing MED master file", __FILE__, __LINE__);
930         
931         //---------------------------------------------------------------------
932         // Create a new MED file (v2.3)
933         //---------------------------------------------------------------------
934         int id = 1;
935         
936         if (gProgressCallback != NULL) gProgressCallback->start("Save mesh", mParts.size());
937         
938         try
939         {
940         
941         // for each sub-meshes
942         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
943         {
944                 switch (mParts[itPart]->mToDoOnNextWrite)
945                 {
946                         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
947                         {
948                                 mParts[itPart]->mId = id;
949                                 id++;
950                                 fileMaster << (*mParts[itPart]) << endl;
951                                 cout << (*mParts[itPart]) << endl;
952                                 break;
953                         }
954                         
955                         case MeshDisPart::MULTIPR_WRITE_MESH:
956                         {
957                                 if (strlen(mParts[itPart]->getMEDFileName()) == 0) throw IOException("MED filename is empty", __FILE__, __LINE__);
958                                 if (mParts[itPart]->mMesh == NULL) throw IllegalStateException("invalid mesh (shoult not be NULL)", __FILE__, __LINE__);
959                                 mParts[itPart]->mMesh->writeMED(mParts[itPart]->getMEDFileName());
960                                 mParts[itPart]->mId = id;
961                                 id++;
962                                 fileMaster << (*mParts[itPart]) << endl;
963                                 cout << (*mParts[itPart]) << endl;
964                                 break;
965                         }
966                         
967                         case MeshDisPart::MULTIPR_WRITE_PARTS:
968                         {
969                                 // split this part using medsplitter
970                                 if (mParts[itPart]->mOldCollection == NULL) throw IllegalStateException("", __FILE__, __LINE__);
971                                 string strPrefix = removeExtension(mParts[itPart]->getMEDFileName(), ".med"); 
972                                 char tmpFilename[256];
973                                 sprintf(tmpFilename, "%s_part", strPrefix.c_str());
974                                 mParts[itPart]->mCollection->write(tmpFilename);
975                                 mParts[itPart]->mCollection->castAllFields(*(mParts[itPart]->mOldCollection));
976                                 int ret = convertMedsplitterToMultipr(fileMaster, tmpFilename, id, mParts[itPart]);
977                                 id += ret;
978                                 remove(mParts[itPart]->getMEDFileName());
979                                 break;
980                         }
981                 
982                         default: throw IllegalStateException("should not be there", __FILE__, __LINE__);
983                 }
984                 
985                 if (gProgressCallback != NULL) gProgressCallback->moveOn();
986         }
987         
988         }
989         catch (RuntimeException& e)
990         {
991                 if (gProgressCallback != NULL) gProgressCallback->done();
992                 throw e;
993         }
994         
995         if (gProgressCallback != NULL) gProgressCallback->done();
996         
997         //---------------------------------------------------------------------
998         // Close master file
999         //---------------------------------------------------------------------
1000         fileMaster.close();
1001         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1002 }
1003
1004
1005 ostream& operator<<(ostream& pOs, MeshDis& pM)
1006 {
1007         pOs << "Mesh Dis.:" << endl;
1008         pOs << "    Filename   =|" << pM.mMEDfilename << "|" << endl;
1009         pOs << "    #Sub-meshes=" << pM.mParts.size() << endl;
1010         
1011         for (unsigned itPart = 0 ; itPart < pM.mParts.size() ; itPart++)
1012         {
1013                 cout << "        " << (itPart + 1) << ": " << (*(pM.mParts[itPart])) << endl; 
1014         }
1015         
1016         return pOs;
1017 }
1018
1019
1020 } // namespace multipr
1021
1022 // EOF