]> SALOME platform Git repositories - modules/multipr.git/blob - src/MULTIPR/MULTIPR_MeshDis.cxx
Salome HOME
*** empty log message ***
[modules/multipr.git] / src / MULTIPR / MULTIPR_MeshDis.cxx
1 // Project MULTIPR, IOLS WP1.2.1 - EDF/CS
2 // Partitioning/decimation module for the SALOME v3.2 platform
3
4 /**
5  * \file    MULTIPR_MeshDis.cxx
6  *
7  * \brief   see MULTIPR_MeshDis.hxx
8  *
9  * \author  Olivier LE ROUX - CS, Virtual Reality Dpt
10  * 
11  * \date    01/2007
12  */
13
14 //*****************************************************************************
15 // Includes section
16 //*****************************************************************************
17
18 #include "MULTIPR_MeshDis.hxx"
19 #include "MULTIPR_Mesh.hxx"
20 #include "MULTIPR_DecimationFilter.hxx"
21 #include "MULTIPR_Utils.hxx"
22 #include "MULTIPR_Globals.hxx"
23 #include "MULTIPR_API.hxx"
24 #include "MULTIPR_Exceptions.hxx"
25 #include "MULTIPR_ProgressCallback.hxx"
26
27 #include "MEDSPLITTER_API.hxx"
28
29 #include <iostream>
30 #include <fstream>
31
32 using namespace std;
33
34
35 namespace multipr
36 {
37
38
39 //*****************************************************************************
40 // Global variables (exported)
41 //*****************************************************************************
42
43 MULTIPR_ProgressCallback* gProgressCallback = NULL;
44
45
46 //*****************************************************************************
47 // Class MeshDisEntry implementation
48 //*****************************************************************************
49
50 MeshDisPart::MeshDisPart()
51 {
52         mMesh             = NULL;
53         mCollection       = NULL;
54         mOldCollection    = NULL;
55         
56         reset();
57 }
58
59
60 MeshDisPart::~MeshDisPart()
61 {
62         reset();
63 }
64
65
66 void MeshDisPart::reset()
67 {
68         mToDoOnNextWrite = MULTIPR_UNDEFINED;
69         
70         mMeshName[0]     = '\0';
71         mId              = 0;
72         mPartName[0]     = '\0';
73         mPath[0]         = '\0';
74         mMEDFileName[0]  = '\0';
75         
76         if (mMesh != NULL)
77         {
78                 delete mMesh;
79                 mMesh = NULL;
80         }
81         
82         mSplit           = 0;
83         
84         if (mCollection != NULL)
85         {
86                 delete mCollection;
87                 mCollection = NULL;
88         }
89         
90         if (mOldCollection != NULL)
91         {
92                 delete mOldCollection;
93                 mOldCollection = NULL;
94         }
95 }
96
97
98 const char* MeshDisPart::getMEDFileNameSuffix() const
99 {       
100         // "agregat100grains_12pas_grain97.med"                       -> "grain97"
101         // "agregat100grains_12pas_grain100_part2.med"                -> "grain100_part2"
102         // "aagregat100grains_12pas_grain98_gradmoy-low-25.0-0.3.med" -> "grain98_gradmoy-low-25-0.3"
103         
104         string prefix = removeExtension(mMEDFileName, ".med");
105         prefix.erase(0, prefix.rfind("grain"));
106         return prefix.c_str();
107 }
108
109
110 void MeshDisPart::create(
111                 OnNextWrite pToDoOnNextWrite,
112                 const char* pMeshName, 
113                 int         pId,
114                 const char* pPartName,
115                 const char* pPath,
116                 const char* pMEDFileName,
117                 Mesh*       pMesh)
118 {
119         if (pToDoOnNextWrite == MULTIPR_UNDEFINED) throw IllegalArgumentException("", __FILE__, __LINE__);
120         if (pMeshName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
121         if (pId < 1) throw IllegalArgumentException("", __FILE__, __LINE__);
122         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
123         if (pPath == NULL) throw NullArgumentException("", __FILE__, __LINE__);
124         if (pMEDFileName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
125         
126         reset();
127         
128         mToDoOnNextWrite = pToDoOnNextWrite;
129         strcpy(mMeshName, pMeshName);
130         mId = pId;
131         strcpy(mPartName, pPartName);
132         strcpy(mPath, pPath);
133         strcpy(mMEDFileName, pMEDFileName);
134         mMesh = pMesh;
135         
136 }
137
138
139 void MeshDisPart::readMED()
140 {
141         if (mMesh != NULL) throw IllegalStateException("", __FILE__, __LINE__);
142         if (mCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
143         if (mOldCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
144         
145         //cout << "read MED : mesh=" << mMEDfilename << endl;
146         
147         mMesh = new Mesh();
148         mMesh->readSequentialMED(mMEDFileName, mMeshName);
149 }
150
151
152 ostream& operator<<(ostream& pOs, MeshDisPart& pM)
153 {
154         switch (pM.mToDoOnNextWrite)
155         {
156                 case MeshDisPart::MULTIPR_UNDEFINED: 
157                         pOs << "undefined"; 
158                         break;
159                         
160                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
161                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
162                         break;
163                         
164                 case MeshDisPart::MULTIPR_WRITE_MESH:
165                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
166                         break;
167                         
168                 case MeshDisPart::MULTIPR_WRITE_PARTS:
169                         pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName << " SPLIT " << pM.mSplit;
170                         break;
171                 
172                 default: throw IllegalStateException("", __FILE__, __LINE__);
173         }
174         
175         return pOs;
176 }
177
178
179 //*****************************************************************************
180 // Class MeshDis implementation
181 //*****************************************************************************
182
183 MeshDis::MeshDis()
184 {
185         reset();
186 }
187
188
189 MeshDis::~MeshDis()
190 {
191         reset();
192 }
193
194
195 void MeshDis::reset()
196 {
197         mMEDfilename[0] = '\0';
198         
199         for (unsigned itPart = 0 ; itPart != mParts.size() ; itPart++)
200         {
201                 MeshDisPart* part = mParts[itPart];
202                 delete part;
203         }
204         mParts.clear();
205         
206         //mProgressCallback = NULL;
207 }
208
209
210 void MeshDis::addMesh(
211         MeshDisPart::OnNextWrite pToDoOnNextWrite,
212         const char* pMeshName, 
213         int         pId,
214         const char* pPartName,
215         const char* pPath,
216         const char* pMEDFileName,
217         Mesh*       pMesh)
218 {
219         MeshDisPart* part = new MeshDisPart();
220         
221         part->create(
222                 pToDoOnNextWrite,
223                 pMeshName,
224                 pId,
225                 pPartName,
226                 pPath,
227                 pMEDFileName,
228                 pMesh);
229         
230         mParts.push_back(part);
231 }
232
233
234 void MeshDis::insertMesh(
235         MeshDisPart::OnNextWrite pToDoOnNextWrite,
236         const char* pMeshName, 
237         int         pId,
238         const char* pPartName,
239         const char* pPath,
240         const char* pMEDFileName,
241         Mesh*       pMesh,
242         int         pPosition)
243 {
244         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         cout << "MULTIPR: MeshDis::splitPart()" << endl;
443         if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
444         if (pNbParts < 2) throw IllegalArgumentException("", __FILE__, __LINE__);
445         if ((pPartitionner != MULTIPR_METIS) && (pPartitionner != MULTIPR_SCOTCH)) throw IllegalArgumentException("should be 0=METIS or 1=SCOTCH", __FILE__, __LINE__);
446         
447         cout << "MULTIPR: MeshDis::splitPart(): args OK" << endl;
448         //---------------------------------------------------------------------
449         // Find the MED file corresponding to the given part
450         //---------------------------------------------------------------------
451         MeshDisPart* part = findPart(pPartName);
452         
453         if (part == NULL)
454         {
455                 throw IllegalArgumentException("part not found in this distributed MED file", __FILE__, __LINE__);
456         }
457
458         cout << "MULTIPR: MeshDis::splitPart(): find part OK" << endl;
459         
460         //---------------------------------------------------------------------
461         // Load the sequential MED file
462         //---------------------------------------------------------------------
463         MEDSPLITTER::MESHCollection* collection;
464         collection = new MEDSPLITTER::MESHCollection(part->getMEDFileName(), part->getMeshName());
465         
466         cout << "MULTIPR: MeshDis::splitPart(): MEDSPLITTER collection OK" << endl;
467         //---------------------------------------------------------------------
468         // Partition the group
469         //---------------------------------------------------------------------
470         MEDSPLITTER::Topology* topology;
471         if (pPartitionner == MULTIPR_METIS)
472         {
473                 try
474                 {
475                         topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::METIS);
476                 }
477                 catch (...)
478                 {
479                         throw RuntimeException("MEDSPLITTER error: createPartition(), using METIS", __FILE__, __LINE__);
480                 }
481         }
482         else if (pPartitionner == MULTIPR_SCOTCH)
483         {
484                 try
485                 {
486                         cout << "MULTIPR: try to create partition using SCOTCH: #parts=" << pNbParts << endl;
487                         topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::SCOTCH);
488                         cout << "MULTIPR: assigned SCOTCH" << endl;
489                 }
490                 catch (...)
491                 {
492                         throw RuntimeException("MEDSPLITTER error: createPartition(), using SCOTCH", __FILE__, __LINE__);
493                 }
494         }
495         else
496         {
497                 throw IllegalStateException("unknown partitionner", __FILE__, __LINE__);
498         }
499         
500         try
501         {
502                 MEDSPLITTER::MESHCollection* newCollection = new MEDSPLITTER::MESHCollection(*collection, topology);
503                 
504                 part->mToDoOnNextWrite = MeshDisPart::MULTIPR_WRITE_PARTS; 
505                 part->mSplit           = pNbParts;
506                 part->mOldCollection   = collection;
507                 part->mCollection      = newCollection;
508         }
509         catch (...)
510         {
511                 cout << "MEDSPLITTER error: new MESHCollection()" << endl;
512                 throw RuntimeException("MEDSPLITTER error: new MESHCollection()", __FILE__, __LINE__);
513         }
514 }
515
516
517 void MeshDis::decimatePart(
518         const char* pPartName, 
519         const char* pFieldName,
520         med_int     pFieldIt,
521         const char* pFilterName,
522         med_float   pTMed, 
523         med_float   pTLow,
524         med_float   pRadius,
525         int         pBoxing)
526 {
527         //---------------------------------------------------------------------
528         // Check arguments
529         //---------------------------------------------------------------------
530         if (pPartName == NULL) throw NullArgumentException("partname should not be NULL", __FILE__, __LINE__);
531         if (pFieldName == NULL) throw NullArgumentException("fieldname should not be NULL", __FILE__, __LINE__);
532         if (pFieldIt < med_int(1)) throw IllegalArgumentException("invalid field iteration; should be >= 1", __FILE__, __LINE__);
533         if (pTMed < 0.0) throw IllegalArgumentException("med res.: threshold must be > 0", __FILE__, __LINE__);
534         if (pTMed >= pTLow) throw IllegalArgumentException("threshold for med res. must be < threshold for low res.", __FILE__, __LINE__);      
535         if (pRadius <= med_float(0.0)) throw IllegalArgumentException("radius should be > 0", __FILE__, __LINE__);
536         if ((pBoxing < 1) || (pBoxing > 200)) throw IllegalArgumentException("boxing should be in [1..200]", __FILE__, __LINE__);
537         
538         //---------------------------------------------------------------------
539         // Find the MED file corresponding to the given part
540         //---------------------------------------------------------------------
541         MeshDisPart* part = findPart(pPartName);
542         if (part == NULL)
543         {
544                 throw IllegalArgumentException("part not found in the given distributed MED file", __FILE__, __LINE__);
545         }
546         
547         //---------------------------------------------------------------------
548         // Load the associated sequential MED file
549         //---------------------------------------------------------------------
550         if (part->mMesh == NULL)
551         {
552                 part->readMED();
553         }
554         
555         Mesh* meshFull = part->mMesh;
556         cout << (*meshFull) << endl;
557         
558         const char* originalFilename = part->getMEDFileName();
559         string strPrefix = removeExtension(originalFilename, ".med");
560         
561         // debug
562         //cout << (*this) << endl;
563         
564         //---------------------------------------------------------------------
565         // Decimates the given mesh
566         //---------------------------------------------------------------------
567         // arguments for decimation are passed as a string for genericity
568         char argv[256];
569         char newPartName[MED_TAILLE_NOM + 1];
570         char newMEDFileName[256];
571         
572         // *** create a new mesh = MEDIUM resolution ***
573         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTMed, pRadius, pBoxing);
574         sprintf(newPartName, "%s_MED", pPartName);
575         sprintf(newMEDFileName, "%s_gradmoy-med-%s-%s.med", 
576                 strPrefix.c_str(), 
577                 realToString(pTMed).c_str(), 
578                 realToString(pRadius).c_str());
579         
580         {
581                 Mesh* meshMedium = meshFull->decimate(pFilterName, argv, part->getMeshName());
582                 cout << (*meshMedium) << endl;
583                 
584                 insertMesh(
585                         MeshDisPart::MULTIPR_WRITE_MESH,
586                         part->getMeshName(),
587                         part->mId + 1,
588                         newPartName,
589                         "localhost",
590                         newMEDFileName,
591                         meshMedium,
592                         part->mId + 0);
593         }
594         
595         // *** create a new mesh = LOW resolution ***
596         sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, pTLow, pRadius, pBoxing);
597         sprintf(newPartName, "%s_LOW", pPartName);
598         sprintf(newMEDFileName, "%s_gradmoy-low-%s-%s.med", 
599                 strPrefix.c_str(), 
600                 realToString(pTLow).c_str(), 
601                 realToString(pRadius).c_str());
602         
603         {
604                 Mesh* meshLow = meshFull->decimate(pFilterName, argv, part->getMeshName());
605                 cout << (*meshLow) << endl;
606                 
607                 insertMesh(
608                         MeshDisPart::MULTIPR_WRITE_MESH,
609                         part->getMeshName(),
610                         part->mId + 2,
611                         newPartName,
612                         "localhost",
613                         newMEDFileName,
614                         meshLow,
615                         part->mId + 1);
616         }
617         
618         // debug
619         //cout << (*this) << endl;
620 }
621
622
623 string MeshDis::evalDecimationParams(
624         const char* pPartName, 
625         const char* pFieldName, 
626         int         pFieldIt, 
627         const char* pFilterName,
628         const char* pFilterParams)
629 {
630         MeshDisPart* part = findPart(pPartName);
631         if (part == NULL) 
632         {
633                 return "";
634         }
635         
636         try
637         {
638                 if (part->mMesh == NULL)
639                 {
640                         part->readMED();
641                 }
642         
643                 multipr::DecimationFilter* filter = multipr::DecimationFilter::create(pFilterName);
644                 if (filter == NULL) 
645                 {
646                         return "";
647                 }
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         }
697         
698         return "";
699 }
700
701
702 int MeshDis::computeNumParts()
703 {
704         int numParts = 0;
705         
706         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
707         {
708                 switch (mParts[itPart]->mToDoOnNextWrite)
709                 {
710                 case MeshDisPart::MULTIPR_KEEP_AS_IT: 
711                 case MeshDisPart::MULTIPR_WRITE_MESH:
712                         numParts++;
713                         break;
714                 
715                 case MeshDisPart::MULTIPR_WRITE_PARTS:
716                         numParts += mParts[itPart]->mSplit;
717                         break;
718                 
719                 default: throw IllegalStateException("", __FILE__, __LINE__);
720                 }
721         }
722         
723         return numParts;
724 }
725
726
727 void MeshDis::readDistributedMED(const char* pMEDfilename)
728 {
729         //cout << "DBG: readDistributedMED" << endl;
730         if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
731         
732         const int MAX_SIZEOF_LINE = 1024;
733         
734         reset();
735         strcpy(mMEDfilename, pMEDfilename);
736         
737         //---------------------------------------------------------------------
738         // Open master file (ASCII file)
739         //---------------------------------------------------------------------
740         ifstream fileMaster(mMEDfilename);
741         if (fileMaster.fail()) throw IOException("i/o error while opening MED master file", __FILE__, __LINE__);
742
743         //cout << "DBG: readDistributedMED: open" << endl;
744
745         //---------------------------------------------------------------------
746         // Read header
747         //---------------------------------------------------------------------
748         char charbuffer[MAX_SIZEOF_LINE];
749         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
750         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
751         
752         // check format
753         if ((charbuffer[0] != '#') ||
754             (charbuffer[1] != ' ') ||
755                 (charbuffer[2] != 'M') ||
756                 (charbuffer[3] != 'E') ||
757                 (charbuffer[4] != 'D'))
758                 throw IOException("not a valid distributed MED file", __FILE__, __LINE__);
759                 
760         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
761         {
762                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
763                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
764         }
765         
766         // read number of parts
767         int nbParts = atoi(charbuffer);
768         //cout << "readDistributedMED: #parts=" << nbParts << endl;
769         
770         //---------------------------------------------------------------------
771         // Read infos about sub-parts
772         //---------------------------------------------------------------------
773         char   lMeshName[MED_TAILLE_NOM + 1];
774         int    lId;
775         char   lPartName[MED_TAILLE_NOM + 1];
776         char   lPath[256];
777         char   lMEDFileName[256];       
778         
779         for (int i = 0 ; i < nbParts ; i++)
780         {
781                 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
782                 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
783                 
784                 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
785                 {
786                         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
787                         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
788                 }
789                 
790                 lMeshName[0]    = '\0';
791                 lId             = 0;
792                 lPartName[0]    = '\0';
793                 lPath[0]        = '\0';
794                 lMEDFileName[0] = '\0';
795                 
796                 int ret = sscanf(charbuffer, "%s %d %s %s %s", 
797                         lMeshName,
798                         &lId,
799                         lPartName,
800                         lPath,
801                         lMEDFileName);
802         
803                 if (ret != 5) throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
804
805                 //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
806                 addMesh(
807                         MeshDisPart::MULTIPR_KEEP_AS_IT,
808                         lMeshName,
809                         lId,
810                         lPartName,
811                         lPath,
812                         lMEDFileName,
813                         NULL);
814         }
815         
816         //---------------------------------------------------------------------
817         // Close master file
818         //---------------------------------------------------------------------
819         fileMaster.close();
820         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
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, string pDestPath)
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                 string strDestFilename = pDestPath + multipr::getFilenameWithoutPath(lMEDFileName);
881                 if (strcmp(lMEDFileName, strDestFilename.c_str()) != 0)
882                 {
883                         multipr::copyFile(lMEDFileName, pDestPath.c_str());
884                         strcpy(lMEDFileName, strDestFilename.c_str());
885                 }
886                                 
887                 pFileMaster << lMeshName << " " << (pId + i) << " " << pPart->getPartName() << "_" << (i + 1) << " " << lPath << " " << lMEDFileName << endl;
888         }
889         
890         fileMasterMedsplitter.close();
891         if (fileMasterMedsplitter.fail()) throw IOException("i/o error while closing MEDSPLITTER master file", __FILE__, __LINE__);
892         
893         // remove master file generated by MEDSPLITTER
894         remove(pTmpFilename);
895         
896         return nbParts;
897 }
898
899
900 void MeshDis::writeDistributedMED(const char* pMEDfilenamePrefix)
901 {
902         if (pMEDfilenamePrefix == NULL) throw NullArgumentException("", __FILE__, __LINE__);
903         
904         //---------------------------------------------------------------------
905         // Build master filename
906         //---------------------------------------------------------------------
907         string strPrefix = string(pMEDfilenamePrefix);
908         const char* strExtension = ".med";
909         string strMasterFilename;
910         
911         // add suffix "_grains_maitre" iff it is not yet in the filename
912         if (strstr(pMEDfilenamePrefix, "_grains_maitre") == 0)
913         {
914                 strMasterFilename= strPrefix + "_grains_maitre" + strExtension;
915         }
916         else
917         {
918                 strMasterFilename = strPrefix + strExtension;
919         }
920         
921         string strDestPath = multipr::getPath(strMasterFilename.c_str());
922         
923         MULTIPR_LOG("Create master: " << strMasterFilename << endl);
924         strcpy(mMEDfilename, strMasterFilename.c_str());
925         
926         //---------------------------------------------------------------------
927         // Create an ASCII master file for the resulting distributed mesh and write header
928         //---------------------------------------------------------------------
929         remove(strMasterFilename.c_str());
930         ofstream fileMaster(strMasterFilename.c_str());
931         
932         if (fileMaster == 0) throw IOException("i/o error while creating MED master file", __FILE__, __LINE__);
933         
934         fileMaster << "# MED file v2.3 - Master file created by MULTIPR v" << getVersion() << endl;
935         fileMaster << "#" << " " << endl;
936         
937         fileMaster << computeNumParts() << endl;
938         if (fileMaster.fail()) throw IOException("i/o error while writing MED master file", __FILE__, __LINE__);
939         
940         //---------------------------------------------------------------------
941         // Create a new MED file (v2.3)
942         //---------------------------------------------------------------------
943         int id = 1;
944         
945         if (gProgressCallback != NULL) gProgressCallback->start("Save mesh", mParts.size());
946         
947         try
948         {
949         
950         // for each sub-meshes
951         for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
952         {
953                 switch (mParts[itPart]->mToDoOnNextWrite)
954                 {
955                         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
956                         {
957                                 mParts[itPart]->mId = id;
958                                 id++;
959                                 
960                                 // copy file in another directory?
961                                 string strSrcPath = multipr::getPath(mParts[itPart]->getMEDFileName());
962                                 if (strSrcPath != strDestPath)
963                                 {
964                                         cout << "Write: KEEP_AS_IT: copy file" << endl;
965                                         string strDestFilename = strDestPath + multipr::getFilenameWithoutPath(mParts[itPart]->getMEDFileName());
966                                         multipr::copyFile(mParts[itPart]->getMEDFileName(), strDestPath.c_str());
967                                         strcpy(mParts[itPart]->mMEDFileName, strDestFilename.c_str());
968                                 }
969                                 
970                                 fileMaster << (*mParts[itPart]) << endl;
971                                 cout << (*mParts[itPart]) << endl;
972                                 break;
973                         }
974                         
975                         case MeshDisPart::MULTIPR_WRITE_MESH:
976                         {
977                                 if (strlen(mParts[itPart]->getMEDFileName()) == 0) throw IOException("MED filename is empty", __FILE__, __LINE__);
978                                 if (mParts[itPart]->mMesh == NULL) throw IllegalStateException("invalid mesh (shoult not be NULL)", __FILE__, __LINE__);
979                                 
980                                 string strDestFilename = strDestPath + multipr::getFilenameWithoutPath(mParts[itPart]->getMEDFileName());
981                                 strcpy(mParts[itPart]->mMEDFileName, strDestFilename.c_str());
982                                 
983                                 mParts[itPart]->mMesh->writeMED(mParts[itPart]->getMEDFileName());
984                                 mParts[itPart]->mId = id;
985                                 id++;
986                                 fileMaster << (*mParts[itPart]) << endl;
987                                 cout << (*mParts[itPart]) << endl;
988                                 break;
989                         }
990                         
991                         case MeshDisPart::MULTIPR_WRITE_PARTS:
992                         {
993                                 // split this part using medsplitter
994                                 if (mParts[itPart]->mOldCollection == NULL) throw IllegalStateException("", __FILE__, __LINE__);
995                                 string strPrefix = removeExtension(mParts[itPart]->getMEDFileName(), ".med"); 
996                                 char tmpFilename[256];
997                                 sprintf(tmpFilename, "%s_part", strPrefix.c_str());
998                                 mParts[itPart]->mCollection->write(tmpFilename);
999                                 mParts[itPart]->mCollection->castAllFields(*(mParts[itPart]->mOldCollection));
1000                                 int ret = convertMedsplitterToMultipr(fileMaster, tmpFilename, id, mParts[itPart], strDestPath);
1001                                 id += ret;
1002                                 remove(mParts[itPart]->getMEDFileName());
1003                                 break;
1004                         }
1005                 
1006                         default: throw IllegalStateException("should not be there", __FILE__, __LINE__);
1007                 }
1008                 
1009                 if (gProgressCallback != NULL) gProgressCallback->moveOn();
1010         }
1011         
1012         }
1013         catch (RuntimeException& e)
1014         {
1015                 if (gProgressCallback != NULL) gProgressCallback->done();
1016                 throw e;
1017         }
1018         
1019         if (gProgressCallback != NULL) gProgressCallback->done();
1020         
1021         //---------------------------------------------------------------------
1022         // Close master file
1023         //---------------------------------------------------------------------
1024         fileMaster.close();
1025         if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1026 }
1027
1028
1029 ostream& operator<<(ostream& pOs, MeshDis& pM)
1030 {
1031         pOs << "Mesh Dis.:" << endl;
1032         pOs << "    Filename   =|" << pM.mMEDfilename << "|" << endl;
1033         pOs << "    #Sub-meshes=" << pM.mParts.size() << endl;
1034         
1035         for (unsigned itPart = 0 ; itPart < pM.mParts.size() ; itPart++)
1036         {
1037                 cout << "        " << (itPart + 1) << ": " << (*(pM.mParts[itPart])) << endl; 
1038         }
1039         
1040         return pOs;
1041 }
1042
1043
1044 } // namespace multipr
1045
1046 // EOF