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