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