Salome HOME
Merge from BR_V5_DEV 16Feb09
[modules/med.git] / src / MULTIPR / MULTIPR_MeshDis.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D
2 //
3 //  This library is free software; you can redistribute it and/or
4 //  modify it under the terms of the GNU Lesser General Public
5 //  License as published by the Free Software Foundation; either
6 //  version 2.1 of the License.
7 //
8 //  This library is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 //  Lesser General Public License for more details.
12 //
13 //  You should have received a copy of the GNU Lesser General Public
14 //  License along with this library; if not, write to the Free Software
15 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Partitioning/decimation module for the SALOME v3.2 platform
20 //
21 /**
22  * \file    MULTIPR_MeshDis.cxx
23  *
24  * \brief   see MULTIPR_MeshDis.hxx
25  *
26  * \author  Olivier LE ROUX - CS, Virtual Reality Dpt
27  * 
28  * \date    01/2007
29  */
30
31 //*****************************************************************************
32 // Includes section
33 //*****************************************************************************
34
35 #include "MULTIPR_MeshDis.hxx"
36 #include "MULTIPR_Mesh.hxx"
37 #include "MULTIPR_DecimationFilter.hxx"
38 #include "MULTIPR_Utils.hxx"
39 #include "MULTIPR_Globals.hxx"
40 #include "MULTIPR_API.hxx"
41 #include "MULTIPR_Exceptions.hxx"
42 #include "MULTIPR_ProgressCallback.hxx"
43 #include "MULTIPR_Field.hxx"
44 #include "MULTIPR_Profil.hxx"
45
46 #include "MEDSPLITTER_API.hxx"
47 #include "MED_Factory.hxx"
48
49 #include <iostream>
50 #include <fstream>
51 #include <string>
52 #include <map>
53
54 // Standard includes for decimation statistics.
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <unistd.h>
58 #include <stdio.h>
59
60
61 using namespace std;
62
63
64 namespace multipr
65 {
66
67 //*****************************************************************************
68 // Global variables (exported)
69 //*****************************************************************************
70
71 // callback used to report progress about a long task (e.g. save to disk)
72 MULTIPR_ProgressCallback* gProgressCallback = NULL;
73
74 // callback used to report empty meshes
75 MULTIPR_EmptyMeshCallback* gEmptyMeshCallback = NULL;
76
77
78 //*****************************************************************************
79 // Class MeshDisEntry implementation
80 //*****************************************************************************
81
82 MeshDisPart::MeshDisPart()
83 {
84     mMesh             = NULL;
85     mCollection       = NULL;
86     mOldCollection    = NULL;
87     
88     reset();
89 }
90
91
92 MeshDisPart::~MeshDisPart()
93 {
94     reset();
95 }
96
97
98 void MeshDisPart::reset()
99 {
100     mToDoOnNextWrite = MULTIPR_UNDEFINED;
101     
102     mMeshName[0]     = '\0';
103     mId              = 0;
104     mPartName[0]     = '\0';
105     mPath[0]         = '\0';
106     mMEDFileName[0]  = '\0';
107     
108     if (mMesh != NULL)
109     {
110         delete mMesh;
111         mMesh = NULL;
112     }
113     
114     mSplit           = 0;
115     
116     if (mCollection != NULL)
117     {
118         delete mCollection;
119         mCollection = NULL;
120     }
121     
122     if (mOldCollection != NULL)
123     {
124         delete mOldCollection;
125         mOldCollection = NULL;
126     }
127 }
128
129
130 const char* MeshDisPart::getMEDFileNameSuffix() const
131 {    
132     // Examples:
133     //    "agregat100grains_12pas_groupe97.med"                      -> "groupe97"
134     //    "agregat100grains_12pas_groupe100_part2.med"               -> "groupe100_part2"
135     //    "agregat100grains_12pas_groupe98_gradmoy-low-25.0-0.3.med" -> "groupe98_gradmoy-low-25-0.3"
136     
137     string prefix = removeExtension(mMEDFileName, ".med");
138     prefix.erase(0, prefix.rfind("groupe"));
139     return prefix.c_str();
140 }
141
142
143 void MeshDisPart::create(
144         OnNextWrite pToDoOnNextWrite,
145         const char* pMeshName, 
146         int         pId,
147         const char* pPartName,
148         const char* pPath,
149         const char* pMEDFileName,
150         Mesh*       pMesh)
151 {
152     if (pToDoOnNextWrite == MULTIPR_UNDEFINED) throw IllegalArgumentException("", __FILE__, __LINE__);
153     if (pMeshName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
154     if (pId < 1) throw IllegalArgumentException("", __FILE__, __LINE__);
155     if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
156     if (pPath == NULL) throw NullArgumentException("", __FILE__, __LINE__);
157     if (pMEDFileName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
158     
159     reset();
160     
161     mToDoOnNextWrite = pToDoOnNextWrite;
162     strcpy(mMeshName, pMeshName);
163     mId = pId;
164     strcpy(mPartName, pPartName);
165     strcpy(mPath, pPath);
166     strcpy(mMEDFileName, pMEDFileName);
167     mMesh = pMesh;
168 }
169
170
171 void MeshDisPart::readMED()
172 {
173     if (mMesh != NULL) throw IllegalStateException("", __FILE__, __LINE__);
174     if (mCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
175     if (mOldCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
176     
177     mMesh = new Mesh();
178     mMesh->readSequentialMED(mMEDFileName, mMeshName);
179 }
180
181
182 ostream& operator<<(ostream& pOs, MeshDisPart& pM)
183 {
184     switch (pM.mToDoOnNextWrite)
185     {
186         case MeshDisPart::MULTIPR_UNDEFINED: 
187             pOs << "undefined"; 
188             break;
189             
190         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
191             pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
192             break;
193             
194         case MeshDisPart::MULTIPR_WRITE_MESH:
195             pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
196             break;
197             
198         case MeshDisPart::MULTIPR_WRITE_PARTS:
199             pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName << " SPLIT " << pM.mSplit;
200             break;
201         
202         default: throw IllegalStateException("", __FILE__, __LINE__);
203     }
204     
205     return pOs;
206 }
207
208 //*****************************************************************************
209 // Class TLockProxy implementation
210 //*****************************************************************************
211 /*
212 TLockProxy::TLockProxy (MeshDis* theMeshDis, boost::shared_ptr<boost::mutex> theMutex)
213   : myMeshDis(theMeshDis),
214     myMutex(theMutex)
215 {
216   //boost::detail::thread::lock_ops<MeshDis::TMutex>::lock(myMeshDis->myMutex);
217   boost::detail::thread::lock_ops<boost::mutex>::lock(*myMutex);
218 }
219
220 TLockProxy::~TLockProxy()
221 {
222   //boost::detail::thread::lock_ops<MeshDis::TMutex>::unlock(myMeshDis->myMutex);
223   boost::detail::thread::lock_ops<boost::mutex>::unlock(*myMutex);
224 }
225
226 MeshDis* TLockProxy::operator-> () const // never throws
227 {
228   return myMeshDis;
229 }
230 */
231 //*****************************************************************************
232 // Class MeshDis implementation
233 //*****************************************************************************
234
235 MeshDis::MeshDis()
236 {
237     reset();
238 }
239
240
241 MeshDis::~MeshDis()
242 {
243     reset();
244 }
245
246
247 void MeshDis::reset()
248 {
249     mSequentialMEDFilename[0]  = '\0';
250     mDistributedMEDFilename[0] = '\0';
251     
252     for (unsigned itPart = 0 ; itPart != mParts.size() ; itPart++)
253     {
254         MeshDisPart* part = mParts[itPart];
255         delete part;
256     }
257     mParts.clear();
258
259     boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
260     mWriteProgress = 100;
261 }
262
263
264 void MeshDis::setSequentialMEDFilename(const char* pFilename) 
265
266     strcpy(mSequentialMEDFilename, pFilename); 
267 }
268
269
270 void MeshDis::addMesh(
271     MeshDisPart::OnNextWrite pToDoOnNextWrite,
272     const char* pMeshName, 
273     int         pId,
274     const char* pPartName,
275     const char* pPath,
276     const char* pMEDFileName,
277     Mesh*       pMesh)
278 {
279     MeshDisPart* part = new MeshDisPart();
280     
281     part->create(
282         pToDoOnNextWrite,
283         pMeshName,
284         pId,
285         pPartName,
286         pPath,
287         pMEDFileName,
288         pMesh);
289     
290     mParts.push_back(part);
291 }
292
293
294 void MeshDis::insertMesh(
295     MeshDisPart::OnNextWrite pToDoOnNextWrite,
296     const char* pMeshName, 
297     int         pId,
298     const char* pPartName,
299     const char* pPath,
300     const char* pMEDFileName,
301     Mesh*       pMesh,
302     int         pPosition)
303 {
304     MeshDisPart* part = new MeshDisPart();
305     
306     part->create(
307         pToDoOnNextWrite,
308         pMeshName,
309         pId,
310         pPartName,
311         pPath,
312         pMEDFileName,
313         pMesh);
314     
315     mParts.insert(mParts.begin() + pPosition, part);
316     
317     // rename id of following parts
318     for (unsigned i = pPosition + 1 ; i < mParts.size() ; i++)
319     {
320         mParts[i]->mId++;
321     }
322 }
323
324
325 void MeshDis::removeParts(const char* pPrefixPartName)
326 {
327     if (pPrefixPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
328     
329     char strPrefix[256];
330     sprintf(strPrefix, "%s_", pPrefixPartName);
331     
332     for (vector<MeshDisPart*>::iterator itPart = mParts.begin() ; itPart != mParts.end() ; itPart++)
333     {
334         MeshDisPart* currentPart = (*itPart);
335         
336         // remove part which have the same name and all sub_parts
337         // e.g. if pPrefixPartName="PART_4" => remove "PART_4" and "PART_4_*", but not "PART41"        
338         if ((strcmp(currentPart->getPartName(), pPrefixPartName) == 0) || 
339             startsWith(currentPart->getPartName(), strPrefix))
340         {
341             mParts.erase(itPart);
342         
343             // decrement id of following parts
344             for (vector<MeshDisPart*>::iterator itPart2 = itPart ; itPart2 != mParts.end() ; itPart2++)
345             {
346                 (*itPart2)->mId--;
347             }
348             
349             itPart--;
350             if (currentPart->mMEDFileName != NULL)
351             {
352                 remove(currentPart->mMEDFileName);
353             }
354             
355             delete currentPart;
356         }
357     }
358 }
359
360
361 MeshDisPart* MeshDis::findPart(const char* pPartName)
362 {
363     if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
364     
365     MeshDisPart* part = NULL;
366
367     for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
368     {
369         MeshDisPart* currentPart = mParts[itPart];
370         if (strcmp(currentPart->getPartName(), pPartName) == 0)
371         {
372              part = currentPart;
373             break;
374         }
375     }
376     
377     return part;
378     
379 }
380
381
382 vector<string> MeshDis::getMeshes() const
383 {
384     vector<string> res;
385     
386     if (mParts.size() > 0)
387     {
388         MeshDisPart* part = mParts[0];
389         const char* meshName = part->getMeshName();
390         res.push_back(meshName);
391     }
392     
393     return res;
394 }
395
396
397 vector<string> MeshDis::getFields(const char* pPartList,  bool pAddNbGaussPoint) const
398 {
399     vector<string>      res;
400     MeshDisPart*        curPart = NULL;
401     unsigned            i, pos, len;
402
403     if (mParts.size() == 0)
404     {
405         return res;
406     }
407
408     // get the right part.
409     pos = 0;
410     len = 0;
411     // Get the next separator.
412     for (; pPartList[pos+len] && pPartList[pos+len] != '|'; ++len);
413     // Find the corresponding part.
414     for (i = 0; i < mParts.size(); ++i)
415     {
416         // Avoid a match between MAIL_9 and MAIL_99
417         if (len != strlen(mParts[i]->getPartName()))
418         {
419             continue;
420         }
421         if (strncmp(mParts[i]->getPartName(), &pPartList[pos], len) == 0)
422         {
423             curPart = mParts[i];
424         }
425     }
426     if (curPart == NULL)
427     {
428         return res;
429     }
430
431     // all the parts of the distributed MED file should have the same fields
432     // => just return the name of fields of the first part
433     switch (curPart->mToDoOnNextWrite)
434     {
435         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
436         case MeshDisPart::MULTIPR_WRITE_PARTS:
437         {
438             vector<pair<string, int> > tmp;
439             multipr::getListScalarFields(curPart->getMEDFileName(), tmp,
440                                          pAddNbGaussPoint, curPart->getMeshName());
441
442             for (unsigned i = 0 ; i < tmp.size() ; i++)
443             {
444                 res.push_back(tmp[i].first);
445             }
446             return res;
447         }
448             
449         case MeshDisPart::MULTIPR_WRITE_MESH:
450             return curPart->mMesh->getNameScalarFields();
451         
452         default: 
453             throw IllegalStateException("Don't know what to do now.", __FILE__, __LINE__);
454     }
455 }
456
457
458 int MeshDis::getTimeStamps(const char* pPartList, const char* pFieldName) const
459 {
460     MeshDisPart*        curPart = NULL;
461     unsigned            i, pos, len;
462
463     if (mParts.size() == 0)
464     {
465         // no parts in this distributed MED file => no fields => #iteration = 0
466         return 0;
467     }
468
469     // get the right part.
470     pos = 0;
471     len = 0;
472     // Get the next separator.
473     for (; pPartList[pos+len] && pPartList[pos+len] != '|'; ++len);
474     // Find the corresponding part.
475     for (i = 0; i < mParts.size(); ++i)
476     {
477       // Avoid a match between MAIL_9 and MAIL_99
478       if (len != strlen(mParts[i]->getPartName()))
479       {
480         continue;
481       }
482       if (strncmp(mParts[i]->getPartName(), &pPartList[pos], len) == 0)
483       {
484         curPart = mParts[i];
485       }
486     }
487
488     // all the parts of the distributed MED file should have the same fields
489     // => just return the number of iteration found in the field of the first part
490     switch (mParts[0]->mToDoOnNextWrite)
491     {
492         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
493         case MeshDisPart::MULTIPR_WRITE_PARTS:
494         {
495             vector<pair<string, int> > tmp;
496             multipr::getListScalarFields(curPart->getMEDFileName(), tmp);
497
498             for (unsigned i = 0 ; i < tmp.size() ; i++)
499             {
500                 if (strcmp(tmp[i].first.c_str(), pFieldName) == 0)
501                 {
502                     return tmp[i].second;
503                 }
504             }
505
506             // pFieldName not found in the list of fields
507             return 0;
508         }
509             
510         case MeshDisPart::MULTIPR_WRITE_MESH:
511             return mParts[0]->mMesh->getTimeStamps(pFieldName);
512         
513         default: 
514             throw IllegalStateException("", __FILE__, __LINE__);
515     }
516 }
517
518
519 string MeshDis::getPartInfo(const char* pPartName)
520 {
521     MeshDisPart* part = findPart(pPartName);
522     
523     if (part != NULL)
524     {
525         char num[16];
526         sprintf(num, "%d", part->mId);
527         
528         string res = 
529             string(part->mMeshName) + 
530             string(" ") +
531             string(num) +
532             string(" ") +
533             string(part->mPartName) +
534             string(" ") +
535             string(part->mPath) +
536             string(" ") +
537             string(part->mMEDFileName);
538
539         return res;
540     }
541     else
542     {
543         // part not found => return empty string
544         return "";
545     }
546 }
547
548
549 void MeshDis::splitPart(const char* pPartName, int pNbParts, int pPartitionner)
550 {
551     if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
552     if (pNbParts < 2) throw IllegalArgumentException("", __FILE__, __LINE__);
553     if ((pPartitionner != MULTIPR_METIS) && (pPartitionner != MULTIPR_SCOTCH))
554       throw IllegalArgumentException("should be 0=METIS or 1=SCOTCH", __FILE__, __LINE__);
555
556     //---------------------------------------------------------------------
557     // Find the MED file corresponding to the given part
558     //---------------------------------------------------------------------
559     MeshDisPart* part = findPart(pPartName);
560     
561     if (part == NULL)
562     {
563         throw IllegalArgumentException("part not found in this distributed MED file", __FILE__, __LINE__);
564     }
565     
566     //---------------------------------------------------------------------
567     // Load the sequential MED file
568     //---------------------------------------------------------------------
569     MEDSPLITTER::MESHCollection* collection =
570       new MEDSPLITTER::MESHCollection(part->getMEDFileName(), part->getMeshName());
571     collection->setDriverType(MEDSPLITTER::MedAscii);
572     
573     //---------------------------------------------------------------------
574     // Partition the group
575     //---------------------------------------------------------------------
576     MEDSPLITTER::Topology* topology;
577     if (pPartitionner == MULTIPR_METIS)
578     {
579         try
580         {
581             topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::METIS);
582         }
583         catch (...)
584         {
585             throw RuntimeException("MEDSPLITTER error: createPartition(), using METIS", __FILE__, __LINE__);
586         }
587     }
588     else if (pPartitionner == MULTIPR_SCOTCH)
589     {
590         try
591         {
592             topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::SCOTCH);
593         }
594         catch (...)
595         {
596             throw RuntimeException("MEDSPLITTER error: createPartition(), using SCOTCH", __FILE__, __LINE__);
597         }
598     }
599     else
600     {
601         throw IllegalStateException("unknown partitionner", __FILE__, __LINE__);
602     }
603     
604     try
605     {
606         MEDSPLITTER::MESHCollection* newCollection = new MEDSPLITTER::MESHCollection(*collection, topology);
607         newCollection->setDriverType(MEDSPLITTER::MedAscii);
608
609         part->mToDoOnNextWrite = MeshDisPart::MULTIPR_WRITE_PARTS; 
610         part->mSplit           = pNbParts;
611         part->mOldCollection   = collection;
612         part->mCollection      = newCollection;
613     }
614     catch (...)
615     {
616         throw RuntimeException("MEDSPLITTER error: new MESHCollection()", __FILE__, __LINE__);
617     }
618 }
619
620
621 std::list<std::string> MeshDis::decimatePart (const char* pPartName, 
622                                               const char* pFieldName,
623                                               med_int     pFieldIt,
624                                               const char* pFilterName,
625                                               const char* pFilterParams)
626 {
627     char                stats[512];
628     float               lowResStat = 0.0f;
629     float               medResStat = 0.0f;
630     unsigned    lowResSize = 0;
631     unsigned    medResSize = 0;
632     struct stat fileStat;
633
634     fileStat.st_size = 0;
635
636     //---------------------------------------------------------------------
637     // Check arguments
638     //---------------------------------------------------------------------
639     if (pPartName == NULL)
640       throw NullArgumentException("partname should not be NULL", __FILE__, __LINE__);
641     if (pFieldName == NULL)
642       throw NullArgumentException("fieldname should not be NULL", __FILE__, __LINE__);
643     if (pFieldIt < med_int(1))
644       throw IllegalArgumentException("invalid field iteration; should be >= 1", __FILE__, __LINE__);
645     if (pFilterParams == NULL)
646       throw IllegalArgumentException("filterparams should not be NULL", __FILE__, __LINE__);
647
648     //---------------------------------------------------------------------
649     // Find the MED file corresponding to the given part
650     //---------------------------------------------------------------------
651     MeshDisPart* part = findPart(pPartName);
652     if (part == NULL)
653     {
654         throw IllegalArgumentException("part not found in the given distributed MED file",
655                                        __FILE__, __LINE__);
656     }
657
658     //---------------------------------------------------------------------
659     // Load the associated sequential MED file
660     //---------------------------------------------------------------------
661     if (part->mMesh == NULL)
662     {
663         part->readMED();
664     }
665
666     Mesh* meshFull = part->mMesh;
667     cout << (*meshFull) << endl;
668
669     std::list<std::string> ret;
670     
671     const char* originalFilename = part->getMEDFileName();
672     string strPrefix = removeExtension(originalFilename, ".med");
673
674     // debug
675     //cout << (*this) << endl;
676
677     //---------------------------------------------------------------------
678     // Decimates the given mesh
679     //---------------------------------------------------------------------
680     // arguments for decimation are passed as a string for genericity
681     char argv[256];
682     char newPartName[MED_TAILLE_NOM + 1];
683     char newMEDFileNameLow[256];
684     char newMEDFileNameMed[256];
685     float lTMed;
686     float lTLow;
687     float lRadius = 0.0f;
688     int lBoxing = 0;
689
690     // *** create a new mesh = MEDIUM resolution ***
691     if (strcmp(pFilterName, "Filtre_GradientMoyen") == 0)
692     {
693       sscanf(pFilterParams, "%f %f %f %d", &lTMed, &lTLow, &lRadius, &lBoxing);
694       sprintf(newMEDFileNameMed, "%s_%s-med-%s-%s.med", 
695               strPrefix.c_str(), 
696               "gradmoy",
697               realToString(lTMed).c_str(), 
698               realToString(lRadius).c_str());
699       sprintf(newMEDFileNameLow, "%s_%s-low-%s-%s.med", 
700               strPrefix.c_str(), 
701               "gradmoy",
702               realToString(lTLow).c_str(), 
703               realToString(lRadius).c_str());
704     }
705     else if (strcmp(pFilterName, "Filtre_Direct") == 0)
706     {
707       sscanf(pFilterParams, "%f %f", &lTMed, &lTLow);
708       sprintf(newMEDFileNameMed, "%s_%s-med-%s.med", 
709               strPrefix.c_str(), 
710               "direct",
711               realToString(lTMed).c_str());
712       sprintf(newMEDFileNameLow, "%s_%s-low-%s.med", 
713               strPrefix.c_str(), 
714               "direct",
715               realToString(lTLow).c_str());
716     }
717     else
718     {
719       throw IllegalArgumentException("Filter not found !", __FILE__, __LINE__);
720     }
721
722     sprintf(argv, "%s %d %f %f %d", pFieldName, pFieldIt, lTMed, lRadius, lBoxing);
723     sprintf(newPartName, "%s_MED", pPartName);
724     {
725       Mesh* meshMedium = meshFull->decimate(pFilterName, argv, part->getMeshName());
726       cout << (*meshMedium) << endl;
727       if (meshMedium->getNumberOfElements())
728       {
729         medResStat = 1.0f - (float)meshMedium->getNumberOfElements() / (float)meshFull->getNumberOfElements();
730
731         // We write the file in /tmp to get it's size.
732         try {
733           meshMedium->writeMED("/tmp/delete-me.med");
734           stat("/tmp/delete-me.med", &fileStat);
735           medResSize = fileStat.st_size;
736           remove("/tmp/delete-me.med");
737         }
738         catch (...)
739         {
740           medResSize = 0;
741         }
742
743         insertMesh(
744                    MeshDisPart::MULTIPR_WRITE_MESH,
745                    part->getMeshName(),
746                    part->mId + 1,
747                    newPartName,
748                    "localhost",
749                    newMEDFileNameMed,
750                    meshMedium,
751                    part->mId + 0);
752       }
753       else
754       {
755         ret.push_back(newPartName);
756         delete meshMedium;
757       }
758     }
759
760     // *** create a new mesh = LOW resolution ***
761     sprintf(argv, "%s %d %lf %lf %d", pFieldName, pFieldIt, lTLow, lRadius, lBoxing);
762     sprintf(newPartName, "%s_LOW", pPartName);
763     {
764       Mesh* meshLow = meshFull->decimate(pFilterName, argv, part->getMeshName());
765       cout << (*meshLow) << endl;
766       if (meshLow->getNumberOfElements())
767       {         
768         lowResStat = 1.0f - (float)meshLow->getNumberOfElements() / (float)meshFull->getNumberOfElements();
769
770         // We write the file in /tmp to get it's size.
771         try {
772           meshLow->writeMED("/tmp/delete-me.med");
773           stat("/tmp/delete-me.med", &fileStat);
774           lowResSize = fileStat.st_size;
775           remove("/tmp/delete-me.med");
776         }
777         catch (...)
778         {
779           lowResSize = 0;
780         }
781
782         insertMesh(MeshDisPart::MULTIPR_WRITE_MESH,
783                    part->getMeshName(),
784                    part->mId + 2,
785                    newPartName,
786                    "localhost",
787                    newMEDFileNameLow,
788                    meshLow,
789                    part->mId + 1);
790       }
791       else
792       {
793         ret.push_back(newPartName);
794         delete meshLow;
795       }
796     }
797     // We get the original file size.
798     std::string filename = part->getMEDFileName();
799     stat(filename.c_str(), &fileStat);
800
801     snprintf(stats, 512, "Mesh compression : Low resolution=%.1f\%%. Medium resolution=%.1f%%.\nFile compression :   Low resolution=%.1f%%. Medium resolution=%.1f%%.", 
802              lowResStat * 100.0f, medResStat * 100.0f, 
803              (1.0f - (float)lowResSize / (float)fileStat.st_size) * 100.0f,
804              (1.0f - (float)medResSize / (float)fileStat.st_size) * 100.0f);
805     this->mStats = stats;
806
807     return ret;
808 }
809
810
811 string MeshDis::evalDecimationParams(
812     const char* pPartName, 
813     const char* pFieldName, 
814     int         pFieldIt, 
815     const char* pFilterName,
816     const char* pFilterParams)
817 {
818     MeshDisPart* part = findPart(pPartName);
819     if (part == NULL) 
820     {
821         return "";
822     }
823     
824     try
825     {
826         if (part->mMesh == NULL)
827         {
828             part->readMED();
829         }
830     
831         multipr::DecimationFilter* filter = multipr::DecimationFilter::create(pFilterName);
832         if (filter == NULL) 
833         {
834             return "";
835         }
836         
837         multipr::DecimationFilterGradAvg* filterGrad = dynamic_cast<multipr::DecimationFilterGradAvg*>(filter);
838         
839         if (filterGrad != NULL)
840         {
841             int mode;
842             
843             int ret = sscanf(pFilterParams, "%d", &mode);
844             
845             // mode 2 = GET RADIUS
846             if ((ret == 1) && (mode == 2))
847             {
848                 double radius = part->mMesh->evalDefaultRadius(8);
849                 char res[256];
850                 sprintf(res, "%f", radius);
851                 return res;
852             }
853             
854             float radius;
855             int boxing;
856             
857             ret = sscanf(pFilterParams, "%d %f %d", &mode, &radius, &boxing);
858             
859             // mode 1 = GET GRADIENT MIN, MAX and AVG
860             if ((ret == 3) && (mode == 1))
861             {
862                 double gradMin = 0.1, gradAvg = 0.15, gradMax = 0.2;
863                 
864                 filterGrad->getGradientInfo(
865                     part->mMesh,
866                     pFieldName,
867                     pFieldIt,
868                     radius,
869                     boxing,
870                     &gradMin,
871                     &gradAvg,
872                     &gradMax);
873                 
874                 char res[2048];
875                 sprintf(res, "%f %f %f", gradMin, gradAvg, gradMax);
876                 return res;
877             }
878         }
879         
880         delete filter;
881     }
882     catch(...)
883     {
884     }
885     
886     return "";
887 }
888
889
890 int MeshDis::computeNumParts()
891 {
892     int numParts = 0;
893     
894     for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
895     {
896         switch (mParts[itPart]->mToDoOnNextWrite)
897         {
898         case MeshDisPart::MULTIPR_KEEP_AS_IT: 
899         case MeshDisPart::MULTIPR_WRITE_MESH:
900             numParts++;
901             break;
902         
903         case MeshDisPart::MULTIPR_WRITE_PARTS:
904             numParts += mParts[itPart]->mSplit + 1;
905             break;
906         
907         default: throw IllegalStateException("", __FILE__, __LINE__);
908         }
909     }
910     
911     return numParts;
912 }
913
914
915 void MeshDis::readDistributedMED(const char* pMEDfilename)
916 {
917     if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
918     
919     const int MAX_SIZEOF_LINE = 1024;
920     
921     reset();
922     strcpy(mDistributedMEDFilename, pMEDfilename);
923     
924     //---------------------------------------------------------------------
925     // Open master file (ASCII file)
926     //---------------------------------------------------------------------
927     ifstream fileMaster(mDistributedMEDFilename);
928     if (fileMaster.fail()) throw IOException("i/o error while opening MED master file", __FILE__, __LINE__);
929
930     //---------------------------------------------------------------------
931     // Read header
932     //---------------------------------------------------------------------
933     char charbuffer[MAX_SIZEOF_LINE];
934     fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
935     if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
936     
937     // check format
938     if ((charbuffer[0] != '#') ||
939         (charbuffer[1] != ' ') ||
940         (charbuffer[2] != 'M') ||
941         (charbuffer[3] != 'E') ||
942         (charbuffer[4] != 'D'))
943         throw IOException("not a valid distributed MED file", __FILE__, __LINE__);
944         
945     while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
946     {
947         char* strTag = NULL;
948         if ((charbuffer[0] == '#') && ((strTag = strstr(charbuffer, "[SOURCE]=")) != NULL))
949         {
950             char strSequentialMEDFilename[256];
951             int ret = sscanf(strTag, "[SOURCE]=%s", strSequentialMEDFilename);
952             if (ret == 1)
953             {
954                 MED::EVersion aVersion = MED::GetVersionId(strSequentialMEDFilename, true);
955                 if ( aVersion == MED::eVUnknown ) {
956                     std::string aMessage = std::string("source file - '") + strSequentialMEDFilename + "' is not a valid MED file";       
957                     throw IOException( aMessage.c_str(), __FILE__, __LINE__ );
958                 }
959
960                 setSequentialMEDFilename(strSequentialMEDFilename);
961             }
962         }
963         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
964         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
965     }
966     
967     // read number of parts
968     int nbParts = atoi(charbuffer);
969     
970     //---------------------------------------------------------------------
971     // Read infos about sub-parts
972     //---------------------------------------------------------------------
973     char   lMeshName[MED_TAILLE_NOM + 1];
974     int    lId;
975     char   lPartName[MED_TAILLE_NOM + 1];
976     char   lPath[256];
977     char   lMEDFileName[256];    
978     
979     for (int i = 0 ; i < nbParts ; i++)
980     {
981         fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
982         if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
983         
984         while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
985         {
986             fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
987             if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
988         }
989         
990         lMeshName[0]    = '\0';
991         lId             = 0;
992         lPartName[0]    = '\0';
993         lPath[0]        = '\0';
994         lMEDFileName[0] = '\0';
995         
996         int ret = sscanf(charbuffer, "%s %d %s %s %s", 
997             lMeshName,
998             &lId,
999             lPartName,
1000             lPath,
1001             lMEDFileName);
1002     
1003         if (ret != 5) throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
1004
1005         MED::EVersion aVersion = MED::GetVersionId(lMEDFileName, true);
1006         if ( aVersion == MED::eVUnknown ) {
1007             std::string aMessage = std::string("partition file - '") + lMEDFileName + "' is not a valid MED file" ;       
1008             throw IOException( aMessage.c_str(), __FILE__, __LINE__ );
1009         }
1010
1011         //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
1012         addMesh(
1013             MeshDisPart::MULTIPR_KEEP_AS_IT,
1014             lMeshName,
1015             lId,
1016             lPartName,
1017             lPath,
1018             lMEDFileName,
1019             NULL);
1020     }
1021     
1022     //---------------------------------------------------------------------
1023     // Close master file
1024     //---------------------------------------------------------------------
1025     fileMaster.close();
1026     if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1027 }
1028
1029 void MeshDis::readPersistentDistributedMED(const char* pMEDfilename)
1030 {
1031   if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
1032
1033   const int MAX_SIZEOF_LINE = 1024;
1034
1035   reset();
1036   strcpy(mDistributedMEDFilename, pMEDfilename);
1037
1038   //---------------------------------------------------------------------
1039   // Open master file (ASCII file)
1040   //---------------------------------------------------------------------
1041   ifstream fileMaster(mDistributedMEDFilename);
1042   if (fileMaster.fail()) throw IOException("i/o error while opening MED master file", __FILE__, __LINE__);
1043
1044   //---------------------------------------------------------------------
1045   // Read header
1046   //---------------------------------------------------------------------
1047   char charbuffer[MAX_SIZEOF_LINE];
1048   fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1049   if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1050
1051   // check format
1052   if ((charbuffer[0] != '#') ||
1053       (charbuffer[1] != ' ') ||
1054       (charbuffer[2] != 'M') ||
1055       (charbuffer[3] != 'E') ||
1056       (charbuffer[4] != 'D'))
1057     throw IOException("not a valid distributed MED file", __FILE__, __LINE__);
1058
1059   while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1060   {
1061     char* strTag = NULL;
1062     if ((charbuffer[0] == '#') && ((strTag = strstr(charbuffer, "[SOURCE]=")) != NULL))
1063     {
1064       char strSequentialMEDFilename[256];
1065       int ret = sscanf(strTag, "[SOURCE]=%s", strSequentialMEDFilename);
1066       if (ret == 1)
1067       {
1068         setSequentialMEDFilename(strSequentialMEDFilename);
1069       }
1070     }
1071     fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1072     if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1073   }
1074
1075   // read number of parts
1076   int nbParts = atoi(charbuffer);
1077
1078   //---------------------------------------------------------------------
1079   // Read infos about sub-parts
1080   //---------------------------------------------------------------------
1081   char   lMeshName[MED_TAILLE_NOM + 1];
1082   int    lId;
1083   char   lPartName[MED_TAILLE_NOM + 1];
1084   char   lPath[256];
1085   char   lMEDFileName[256];    
1086
1087   for (int i = 0 ; i < nbParts ; i++)
1088   {
1089     fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1090     if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1091
1092     while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1093     {
1094       fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1095       if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1096     }
1097
1098     lMeshName[0]    = '\0';
1099     lId             = 0;
1100     lPartName[0]    = '\0';
1101     lPath[0]        = '\0';
1102     lMEDFileName[0] = '\0';
1103
1104     int ret = sscanf(charbuffer, "%s %d %s %s %s", 
1105                      lMeshName,
1106                      &lId,
1107                      lPartName,
1108                      lPath,
1109                      lMEDFileName);
1110
1111     if (ret != 5)
1112       throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
1113
1114     // For Persistent (most probably moved) set of files:
1115     // - replace path to the part in <lMEDFileName> by path to the master file.
1116     string masterFilePath = multipr::getPath(pMEDfilename);
1117     string partFileName   = multipr::getFilenameWithoutPath(lMEDFileName);
1118     string newMEDFileName = masterFilePath + partFileName;
1119
1120     //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
1121     addMesh(MeshDisPart::MULTIPR_KEEP_AS_IT,
1122             lMeshName,
1123             lId,
1124             lPartName,
1125             lPath,
1126             newMEDFileName.c_str(), // lMEDFileName
1127             NULL);
1128   }
1129
1130   //---------------------------------------------------------------------
1131   // Close master file
1132   //---------------------------------------------------------------------
1133   fileMaster.close();
1134   if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1135 }
1136
1137 /**
1138  * Retrieves the output of MEDSPLITTER and convert it for MULTIPR.
1139  */
1140 int convertMedsplitterToMultipr(
1141     ofstream&    pFileMaster, 
1142     const char*  pTmpFilename, 
1143     int          pId, 
1144     MeshDisPart* pPart, 
1145     string       pDestPath)
1146 {
1147     MULTIPR_LOG("convert" << endl);
1148
1149     const int MAX_SIZEOF_LINE = 1024;
1150     char charbuffer[MAX_SIZEOF_LINE];
1151
1152     // Open medsplitter master file (ASCII file)
1153     ifstream fileMasterMedsplitter(pTmpFilename);
1154     if (fileMasterMedsplitter.fail())
1155       throw IOException("i/o error while opening MEDSPLITTER master file", __FILE__, __LINE__);
1156
1157     fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1158     if (fileMasterMedsplitter.fail())
1159       throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);    
1160
1161     while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1162     {
1163       fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1164       if (fileMasterMedsplitter.fail())
1165         throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);
1166     }
1167
1168     // read number of parts
1169     int nbParts = atoi(charbuffer);
1170     //cout << "nb parts=" << nbParts << endl;
1171
1172     char   lMeshName[MED_TAILLE_NOM + 1];
1173     int    lId;
1174     char   lPartName[MED_TAILLE_NOM + 1];
1175     char   lPath[256];
1176     char   lMEDFileName[256];
1177
1178     for (int i = 0 ; i < nbParts ; i++)
1179     {
1180       fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1181       if (fileMasterMedsplitter.fail()) throw IOException("", __FILE__, __LINE__);
1182
1183       // parses the current line
1184       lMeshName[0]    = '\0';
1185       lId             = 0;
1186       lPartName[0]    = '\0';
1187       lPath[0]        = '\0';
1188       lMEDFileName[0] = '\0';
1189
1190       int ret = sscanf(charbuffer, "%s %d %s %s %s",
1191                        lMeshName,
1192                        &lId,
1193                        lPartName,
1194                        lPath,
1195                        lMEDFileName);
1196
1197       if (ret != 5)
1198         throw IOException("i/o error while reading MEDSPLITTER master file; bad format", __FILE__, __LINE__);
1199
1200       string strDestFilename = pDestPath + multipr::getFilenameWithoutPath(lMEDFileName);
1201       if (strcmp(lMEDFileName, strDestFilename.c_str()) != 0)
1202       {
1203         multipr::copyFile(lMEDFileName, pDestPath.c_str());
1204         strcpy(lMEDFileName, strDestFilename.c_str());
1205       }
1206
1207       pFileMaster << lMeshName << "_" << (i + 1) << " " << (pId + i + 1)
1208                   << " " << pPart->getPartName() << "_" << (i + 1)
1209                   << " " << lPath << " " << lMEDFileName << endl;
1210     }
1211
1212     fileMasterMedsplitter.close();
1213     if (fileMasterMedsplitter.fail())
1214       throw IOException("i/o error while closing MEDSPLITTER master file", __FILE__, __LINE__);
1215
1216     // remove master file generated by MEDSPLITTER
1217     remove(pTmpFilename);
1218
1219     return nbParts + 1;
1220 }
1221
1222
1223 void MeshDis::writeDistributedMED (const char* pMEDfilenamePrefix,
1224                                    bool        pIsPersistence)
1225 {
1226     if (pMEDfilenamePrefix == NULL) throw NullArgumentException("", __FILE__, __LINE__);
1227     
1228     //---------------------------------------------------------------------
1229     // Build master filename
1230     //---------------------------------------------------------------------
1231     string strPrefix = string(pMEDfilenamePrefix);
1232     const char* strExtension = ".med";
1233     string strMasterFilename;
1234     
1235     // add suffix "_groupes_maitre" iff it is not yet in the filename
1236     if (strstr(pMEDfilenamePrefix, "_groupes_maitre") == 0)
1237     {
1238         strMasterFilename= strPrefix + "_groupes_maitre" + strExtension;
1239     }
1240     else
1241     {
1242         strMasterFilename = strPrefix + strExtension;
1243     }
1244     
1245     string strDestPath = multipr::getPath(strMasterFilename.c_str());
1246     
1247     MULTIPR_LOG("Create master: " << strMasterFilename << endl);
1248     strcpy(mDistributedMEDFilename, strMasterFilename.c_str());
1249     
1250     //---------------------------------------------------------------------
1251     // Create an ASCII master file for the resulting distributed mesh and write header
1252     //---------------------------------------------------------------------
1253     remove(strMasterFilename.c_str());
1254     ofstream fileMaster(strMasterFilename.c_str());
1255     
1256     if (fileMaster == 0) throw IOException("i/o error while creating MED master file", __FILE__, __LINE__);
1257     
1258     fileMaster << "# MED file v2.3 - Master file created by MULTIPR v" << getVersion() << endl;
1259     fileMaster << "#" << " " << endl;
1260     fileMaster << "# [SOURCE]=" << mSequentialMEDFilename << endl;
1261     fileMaster << "#" << " " << endl;
1262     
1263     fileMaster << computeNumParts() << endl;
1264     if (fileMaster.fail()) throw IOException("i/o error while writing MED master file", __FILE__, __LINE__);
1265     
1266     //---------------------------------------------------------------------
1267     // Create a new MED file (v2.3)
1268     //---------------------------------------------------------------------
1269     int id = 1;
1270
1271     if (gProgressCallback != NULL) gProgressCallback->start("Save mesh", mParts.size());
1272     setProgress(0);
1273
1274     try
1275     {
1276       // for each sub-meshes
1277       for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
1278       {
1279         switch (mParts[itPart]->mToDoOnNextWrite)
1280         {
1281             case MeshDisPart::MULTIPR_KEEP_AS_IT: 
1282             {
1283                 string curFilename = mParts[itPart]->getMEDFileName();
1284                 int curId = mParts[itPart]->mId;
1285
1286                 mParts[itPart]->mId = id;
1287                 id++;
1288                 
1289                 // copy file in another directory?
1290                 string strSrcPath = multipr::getPath(curFilename.c_str());
1291                 if (strSrcPath != strDestPath)
1292                 {
1293                   string strDestFilename = strDestPath +
1294                     multipr::getFilenameWithoutPath(curFilename.c_str());
1295                   multipr::copyFile(mParts[itPart]->getMEDFileName(), strDestPath.c_str());
1296                   strcpy(mParts[itPart]->mMEDFileName, strDestFilename.c_str());
1297                 }
1298                 
1299                 fileMaster << (*mParts[itPart]) << endl;
1300                 cout << (*mParts[itPart]) << endl;
1301
1302                 // restore old filename and id in case of persistence
1303                 if (pIsPersistence)
1304                 {
1305                   strcpy(mParts[itPart]->mMEDFileName, curFilename.c_str());
1306                   mParts[itPart]->mId = curId;
1307                 }
1308                 break;
1309             }
1310             
1311             case MeshDisPart::MULTIPR_WRITE_MESH:
1312             {
1313                 if (strlen(mParts[itPart]->getMEDFileName()) == 0)
1314                   throw IOException("MED filename should not be empty", __FILE__, __LINE__);
1315                 if (mParts[itPart]->mMesh == NULL)
1316                   throw IllegalStateException("invalid mesh (shoult not be NULL)", __FILE__, __LINE__);
1317                 
1318                 string curFilename = mParts[itPart]->getMEDFileName();
1319                 int curId = mParts[itPart]->mId;
1320
1321                 string strDestFilename = strDestPath +
1322                   multipr::getFilenameWithoutPath(curFilename.c_str());
1323                 strcpy(mParts[itPart]->mMEDFileName, strDestFilename.c_str());
1324                 
1325                 mParts[itPart]->mMesh->writeMED(mParts[itPart]->getMEDFileName());
1326                 mParts[itPart]->mId = id;
1327                 id++;
1328                 fileMaster << (*mParts[itPart]) << endl;
1329                 cout << (*mParts[itPart]) << endl;
1330
1331                 // restore old filename and id in case of persistence
1332                 if (pIsPersistence)
1333                 {
1334                   strcpy(mParts[itPart]->mMEDFileName, curFilename.c_str());
1335                   mParts[itPart]->mId = curId;
1336                 }
1337                 break;
1338             }
1339             
1340             case MeshDisPart::MULTIPR_WRITE_PARTS:
1341             {
1342                 // We need to keep the original file.
1343                 fileMaster << (*mParts[itPart]) << endl;
1344                 // split this part using medsplitter
1345                 if (mParts[itPart]->mOldCollection == NULL)
1346                   throw IllegalStateException("collection should not be NULL", __FILE__, __LINE__);
1347                 string strPrefix = removeExtension(mParts[itPart]->getMEDFileName(), ".med"); 
1348                 char tmpFilename[256];
1349                 sprintf(tmpFilename, "%s_part", strPrefix.c_str());
1350                 
1351                 // remove previous file
1352                 remove(tmpFilename);
1353                 for (int i = 1 ; i <= mParts[itPart]->mSplit ; i++)
1354                 {
1355                     char filename[256];
1356                     sprintf(filename, "%s%d.med", tmpFilename, i);
1357                     remove(filename);
1358                 }
1359                 
1360                 mParts[itPart]->mCollection->write(tmpFilename);
1361                 mParts[itPart]->mCollection->castAllFields(*(mParts[itPart]->mOldCollection));
1362                 int ret = convertMedsplitterToMultipr(fileMaster, tmpFilename, id,
1363                                                       mParts[itPart], strDestPath);
1364                 id += ret;
1365                 //remove(mParts[itPart]->getMEDFileName());
1366                 break;
1367             }
1368         
1369             default: throw IllegalStateException("should not be there", __FILE__, __LINE__);
1370         }
1371
1372         if (gProgressCallback != NULL) gProgressCallback->moveOn();
1373         setProgress((itPart + 1) * 100 / mParts.size());
1374       }
1375     }
1376     catch (RuntimeException& e)
1377     {
1378         if (gProgressCallback != NULL) gProgressCallback->done();
1379         setProgress(100);
1380         throw e;
1381     }
1382
1383     if (gProgressCallback != NULL) gProgressCallback->done();
1384     setProgress(90);
1385
1386     //---------------------------------------------------------------------
1387     // Close master file
1388     //---------------------------------------------------------------------
1389     fileMaster.close();
1390
1391     if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1392 }
1393
1394 void MeshDis::setProgress (int pPercents)
1395 {
1396   boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
1397   mWriteProgress = pPercents;
1398 }
1399
1400 int MeshDis::getProgress()
1401 {
1402   boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
1403   int ret = mWriteProgress;
1404   return ret;
1405 }
1406
1407
1408 void MeshDis::readAndWriteFields (const char* pMeshName, std::vector<Group*>* pGroups,
1409                                   GaussIndexList* pGaussList, std::vector<Profil*>& pProfils)
1410 {
1411     med_int                 lMEDfile, lCurMEDfile;
1412     std::vector<med_int>    lFiles;
1413     std::map<std::string, Profil*>  lProfilByName;
1414
1415     // Open the original MED file.
1416     lMEDfile = MEDouvrir(mSequentialMEDFilename, MED_LECTURE);
1417     //---------------------------------------------------------------------
1418     // Read number of fields
1419     //---------------------------------------------------------------------
1420     MULTIPR_LOG("Read fields: ");
1421     med_int numFields = MEDnChamp(lMEDfile, 0);
1422     if (numFields <= 0)
1423       throw IOException("error while reading number of fields in the MED file", __FILE__, __LINE__);
1424     MULTIPR_LOG(numFields << ": OK\n");
1425
1426     // For each part open the corresponding MED file.
1427     for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
1428     {
1429         lCurMEDfile = MEDouvrir(const_cast<char*>(mParts[itPart]->getMEDFileName()), MED_LECTURE_ECRITURE);
1430         // Keep the files descriptors. 
1431         lFiles.push_back(lCurMEDfile);
1432         if (lCurMEDfile == -1)
1433         {
1434             throw IOException("Can't open part med file.", __FILE__, __LINE__);
1435         }
1436     }
1437
1438     // For easy acces we create an associative container to find the profil by its name.
1439     for (std::vector<Profil*>::iterator it = pProfils.begin(); it != pProfils.end(); ++it)
1440     {
1441         std::string lName = (*it)->getName();
1442         lProfilByName[lName] = (*it);
1443     }
1444     
1445     //---------------------------------------------------------------------
1446     // Iterate over fields
1447     //---------------------------------------------------------------------
1448     // for each field, read and write number of components and others infos
1449     for (int itField = 1 ; itField <= numFields ; ++itField)
1450     {
1451         for (int i = 0; i < eMaxMedMesh; ++i)
1452         {
1453             // Create and read the field.
1454             Field* field = new Field();
1455             field->readMED(lMEDfile, itField, const_cast<char*>(pMeshName), CELL_TYPES[i]);
1456             // if the nth field does not apply on our mesh => skip it
1457             if (!field->isEmpty()) 
1458             {
1459                 // Split and write this field in the MED files of the parts.
1460                 field->writeMEDOptimized(&mParts, pMeshName, pGaussList, i, lFiles, lProfilByName);
1461                 // If this field is on nodes, we dont need to iterate over the geometry types.
1462                 if (field->isFieldOnNodes())
1463                 {
1464                     delete field;
1465                     break;
1466                 }
1467             }
1468             delete field;
1469         }
1470     }
1471     // Close all MED files.
1472     for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
1473     {
1474         MEDfermer(lFiles[itPart]);
1475     }
1476 }
1477
1478 ostream& operator<<(ostream& pOs, MeshDis& pM)
1479 {
1480     pOs << "Mesh Dis.:" << endl;
1481     pOs << "    Sequential filename (source) =|" << pM.mSequentialMEDFilename << "|" << endl;
1482     pOs << "    Distributed filename (master)=|" << pM.mDistributedMEDFilename << "|" << endl;
1483     pOs << "    #Sub-meshes =" << pM.mParts.size() << endl;
1484     
1485     for (unsigned itPart = 0 ; itPart < pM.mParts.size() ; itPart++)
1486     {
1487         cout << "        " << (itPart + 1) << ": " << (*(pM.mParts[itPart])) << endl; 
1488     }
1489     
1490     return pOs;
1491 }
1492
1493
1494 } // namespace multipr
1495
1496 // EOF