1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Partitioning/decimation module for the SALOME v3.2 platform
22 * \file MULTIPR_MeshDis.cxx
24 * \brief see MULTIPR_MeshDis.hxx
26 * \author Olivier LE ROUX - CS, Virtual Reality Dpt
31 //*****************************************************************************
33 //*****************************************************************************
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"
46 #include "MEDSPLITTER_API.hxx"
47 #include "MED_Factory.hxx"
54 // Standard includes for decimation statistics.
55 #include <sys/types.h>
67 //*****************************************************************************
68 // Global variables (exported)
69 //*****************************************************************************
71 // callback used to report progress about a long task (e.g. save to disk)
72 MULTIPR_ProgressCallback* gProgressCallback = NULL;
74 // callback used to report empty meshes
75 MULTIPR_EmptyMeshCallback* gEmptyMeshCallback = NULL;
78 //*****************************************************************************
79 // Class MeshDisEntry implementation
80 //*****************************************************************************
82 MeshDisPart::MeshDisPart()
86 mOldCollection = NULL;
92 MeshDisPart::~MeshDisPart()
98 void MeshDisPart::reset()
100 mToDoOnNextWrite = MULTIPR_UNDEFINED;
106 mMEDFileName[0] = '\0';
116 if (mCollection != NULL)
122 if (mOldCollection != NULL)
124 delete mOldCollection;
125 mOldCollection = NULL;
130 const char* MeshDisPart::getMEDFileNameSuffix() const
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"
137 string prefix = removeExtension(mMEDFileName, ".med");
138 prefix.erase(0, prefix.rfind("groupe"));
139 return prefix.c_str();
143 void MeshDisPart::create(
144 OnNextWrite pToDoOnNextWrite,
145 const char* pMeshName,
147 const char* pPartName,
149 const char* pMEDFileName,
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__);
161 mToDoOnNextWrite = pToDoOnNextWrite;
162 strcpy(mMeshName, pMeshName);
164 strcpy(mPartName, pPartName);
165 strcpy(mPath, pPath);
166 strcpy(mMEDFileName, pMEDFileName);
171 void MeshDisPart::readMED()
173 if (mMesh != NULL) throw IllegalStateException("", __FILE__, __LINE__);
174 if (mCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
175 if (mOldCollection != NULL) throw IllegalStateException("", __FILE__, __LINE__);
178 mMesh->readSequentialMED(mMEDFileName, mMeshName);
182 ostream& operator<<(ostream& pOs, MeshDisPart& pM)
184 switch (pM.mToDoOnNextWrite)
186 case MeshDisPart::MULTIPR_UNDEFINED:
190 case MeshDisPart::MULTIPR_KEEP_AS_IT:
191 pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
194 case MeshDisPart::MULTIPR_WRITE_MESH:
195 pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName;
198 case MeshDisPart::MULTIPR_WRITE_PARTS:
199 pOs << pM.mMeshName << " " << pM.mId << " " << pM.mPartName << " " << pM.mPath << " " << pM.mMEDFileName << " SPLIT " << pM.mSplit;
202 default: throw IllegalStateException("", __FILE__, __LINE__);
208 //*****************************************************************************
209 // Class TLockProxy implementation
210 //*****************************************************************************
212 TLockProxy::TLockProxy (MeshDis* theMeshDis, boost::shared_ptr<boost::mutex> theMutex)
213 : myMeshDis(theMeshDis),
216 //boost::detail::thread::lock_ops<MeshDis::TMutex>::lock(myMeshDis->myMutex);
217 boost::detail::thread::lock_ops<boost::mutex>::lock(*myMutex);
220 TLockProxy::~TLockProxy()
222 //boost::detail::thread::lock_ops<MeshDis::TMutex>::unlock(myMeshDis->myMutex);
223 boost::detail::thread::lock_ops<boost::mutex>::unlock(*myMutex);
226 MeshDis* TLockProxy::operator-> () const // never throws
231 //*****************************************************************************
232 // Class MeshDis implementation
233 //*****************************************************************************
247 void MeshDis::reset()
249 mSequentialMEDFilename[0] = '\0';
250 mDistributedMEDFilename[0] = '\0';
252 for (unsigned itPart = 0 ; itPart != mParts.size() ; itPart++)
254 MeshDisPart* part = mParts[itPart];
259 boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
260 mWriteProgress = 100;
264 void MeshDis::setSequentialMEDFilename(const char* pFilename)
266 strcpy(mSequentialMEDFilename, pFilename);
270 void MeshDis::addMesh(
271 MeshDisPart::OnNextWrite pToDoOnNextWrite,
272 const char* pMeshName,
274 const char* pPartName,
276 const char* pMEDFileName,
279 MeshDisPart* part = new MeshDisPart();
290 mParts.push_back(part);
294 void MeshDis::insertMesh(
295 MeshDisPart::OnNextWrite pToDoOnNextWrite,
296 const char* pMeshName,
298 const char* pPartName,
300 const char* pMEDFileName,
304 MeshDisPart* part = new MeshDisPart();
315 mParts.insert(mParts.begin() + pPosition, part);
317 // rename id of following parts
318 for (unsigned i = pPosition + 1 ; i < mParts.size() ; i++)
325 void MeshDis::removeParts(const char* pPrefixPartName)
327 if (pPrefixPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
330 sprintf(strPrefix, "%s_", pPrefixPartName);
332 for (vector<MeshDisPart*>::iterator itPart = mParts.begin() ; itPart != mParts.end() ; itPart++)
334 MeshDisPart* currentPart = (*itPart);
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))
341 mParts.erase(itPart);
343 // decrement id of following parts
344 for (vector<MeshDisPart*>::iterator itPart2 = itPart ; itPart2 != mParts.end() ; itPart2++)
350 if (currentPart->mMEDFileName != NULL)
352 remove(currentPart->mMEDFileName);
361 MeshDisPart* MeshDis::findPart(const char* pPartName)
363 if (pPartName == NULL) throw NullArgumentException("", __FILE__, __LINE__);
365 MeshDisPart* part = NULL;
367 for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
369 MeshDisPart* currentPart = mParts[itPart];
370 if (strcmp(currentPart->getPartName(), pPartName) == 0)
382 vector<string> MeshDis::getMeshes() const
386 if (mParts.size() > 0)
388 MeshDisPart* part = mParts[0];
389 const char* meshName = part->getMeshName();
390 res.push_back(meshName);
397 vector<string> MeshDis::getFields(const char* pPartList, bool pAddNbGaussPoint) const
400 MeshDisPart* curPart = NULL;
401 unsigned i, pos, len;
403 if (mParts.size() == 0)
408 // get the right part.
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)
416 // Avoid a match between MAIL_9 and MAIL_99
417 if (len != strlen(mParts[i]->getPartName()))
421 if (strncmp(mParts[i]->getPartName(), &pPartList[pos], len) == 0)
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)
435 case MeshDisPart::MULTIPR_KEEP_AS_IT:
436 case MeshDisPart::MULTIPR_WRITE_PARTS:
438 vector<pair<string, int> > tmp;
439 multipr::getListScalarFields(curPart->getMEDFileName(), tmp,
440 pAddNbGaussPoint, curPart->getMeshName());
442 for (unsigned i = 0 ; i < tmp.size() ; i++)
444 res.push_back(tmp[i].first);
449 case MeshDisPart::MULTIPR_WRITE_MESH:
450 return curPart->mMesh->getNameScalarFields();
453 throw IllegalStateException("Don't know what to do now.", __FILE__, __LINE__);
458 int MeshDis::getTimeStamps(const char* pPartList, const char* pFieldName) const
460 MeshDisPart* curPart = NULL;
461 unsigned i, pos, len;
463 if (mParts.size() == 0)
465 // no parts in this distributed MED file => no fields => #iteration = 0
469 // get the right part.
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)
477 // Avoid a match between MAIL_9 and MAIL_99
478 if (len != strlen(mParts[i]->getPartName()))
482 if (strncmp(mParts[i]->getPartName(), &pPartList[pos], len) == 0)
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)
492 case MeshDisPart::MULTIPR_KEEP_AS_IT:
493 case MeshDisPart::MULTIPR_WRITE_PARTS:
495 vector<pair<string, int> > tmp;
496 multipr::getListScalarFields(curPart->getMEDFileName(), tmp);
498 for (unsigned i = 0 ; i < tmp.size() ; i++)
500 if (strcmp(tmp[i].first.c_str(), pFieldName) == 0)
502 return tmp[i].second;
506 // pFieldName not found in the list of fields
510 case MeshDisPart::MULTIPR_WRITE_MESH:
511 return mParts[0]->mMesh->getTimeStamps(pFieldName);
514 throw IllegalStateException("", __FILE__, __LINE__);
519 string MeshDis::getPartInfo(const char* pPartName)
521 MeshDisPart* part = findPart(pPartName);
526 sprintf(num, "%d", part->mId);
529 string(part->mMeshName) +
533 string(part->mPartName) +
535 string(part->mPath) +
537 string(part->mMEDFileName);
543 // part not found => return empty string
549 void MeshDis::splitPart(const char* pPartName, int pNbParts, int pPartitionner)
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__);
556 //---------------------------------------------------------------------
557 // Find the MED file corresponding to the given part
558 //---------------------------------------------------------------------
559 MeshDisPart* part = findPart(pPartName);
563 throw IllegalArgumentException("part not found in this distributed MED file", __FILE__, __LINE__);
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);
573 //---------------------------------------------------------------------
574 // Partition the group
575 //---------------------------------------------------------------------
576 MEDSPLITTER::Topology* topology;
577 if (pPartitionner == MULTIPR_METIS)
581 topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::METIS);
585 throw RuntimeException("MEDSPLITTER error: createPartition(), using METIS", __FILE__, __LINE__);
588 else if (pPartitionner == MULTIPR_SCOTCH)
592 topology = collection->createPartition(pNbParts, MEDSPLITTER::Graph::SCOTCH);
596 throw RuntimeException("MEDSPLITTER error: createPartition(), using SCOTCH", __FILE__, __LINE__);
601 throw IllegalStateException("unknown partitionner", __FILE__, __LINE__);
606 MEDSPLITTER::MESHCollection* newCollection = new MEDSPLITTER::MESHCollection(*collection, topology);
607 newCollection->setDriverType(MEDSPLITTER::MedAscii);
609 part->mToDoOnNextWrite = MeshDisPart::MULTIPR_WRITE_PARTS;
610 part->mSplit = pNbParts;
611 part->mOldCollection = collection;
612 part->mCollection = newCollection;
616 throw RuntimeException("MEDSPLITTER error: new MESHCollection()", __FILE__, __LINE__);
621 std::list<std::string> MeshDis::decimatePart (const char* pPartName,
622 const char* pFieldName,
624 const char* pFilterName,
625 const char* pFilterParams)
628 float lowResStat = 0.0f;
629 float medResStat = 0.0f;
630 unsigned lowResSize = 0;
631 unsigned medResSize = 0;
632 struct stat fileStat;
634 fileStat.st_size = 0;
636 //---------------------------------------------------------------------
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__);
648 //---------------------------------------------------------------------
649 // Find the MED file corresponding to the given part
650 //---------------------------------------------------------------------
651 MeshDisPart* part = findPart(pPartName);
654 throw IllegalArgumentException("part not found in the given distributed MED file",
658 //---------------------------------------------------------------------
659 // Load the associated sequential MED file
660 //---------------------------------------------------------------------
661 if (part->mMesh == NULL)
666 Mesh* meshFull = part->mMesh;
667 cout << (*meshFull) << endl;
669 std::list<std::string> ret;
671 const char* originalFilename = part->getMEDFileName();
672 string strPrefix = removeExtension(originalFilename, ".med");
675 //cout << (*this) << endl;
677 //---------------------------------------------------------------------
678 // Decimates the given mesh
679 //---------------------------------------------------------------------
680 // arguments for decimation are passed as a string for genericity
682 char newPartName[MED_TAILLE_NOM + 1];
683 char newMEDFileNameLow[256];
684 char newMEDFileNameMed[256];
687 float lRadius = 0.0f;
690 // *** create a new mesh = MEDIUM resolution ***
691 if (strcmp(pFilterName, "Filtre_GradientMoyen") == 0)
693 sscanf(pFilterParams, "%f %f %f %d", &lTMed, &lTLow, &lRadius, &lBoxing);
694 sprintf(newMEDFileNameMed, "%s_%s-med-%s-%s.med",
697 realToString(lTMed).c_str(),
698 realToString(lRadius).c_str());
699 sprintf(newMEDFileNameLow, "%s_%s-low-%s-%s.med",
702 realToString(lTLow).c_str(),
703 realToString(lRadius).c_str());
705 else if (strcmp(pFilterName, "Filtre_Direct") == 0)
707 sscanf(pFilterParams, "%f %f", &lTMed, &lTLow);
708 sprintf(newMEDFileNameMed, "%s_%s-med-%s.med",
711 realToString(lTMed).c_str());
712 sprintf(newMEDFileNameLow, "%s_%s-low-%s.med",
715 realToString(lTLow).c_str());
719 throw IllegalArgumentException("Filter not found !", __FILE__, __LINE__);
722 sprintf(argv, "%s %d %f %f %d", pFieldName, pFieldIt, lTMed, lRadius, lBoxing);
723 sprintf(newPartName, "%s_MED", pPartName);
725 Mesh* meshMedium = meshFull->decimate(pFilterName, argv, part->getMeshName());
726 cout << (*meshMedium) << endl;
727 if (meshMedium->getNumberOfElements())
729 medResStat = 1.0f - (float)meshMedium->getNumberOfElements() / (float)meshFull->getNumberOfElements();
731 // We write the file in /tmp to get it's size.
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");
744 MeshDisPart::MULTIPR_WRITE_MESH,
755 ret.push_back(newPartName);
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);
764 Mesh* meshLow = meshFull->decimate(pFilterName, argv, part->getMeshName());
765 cout << (*meshLow) << endl;
766 if (meshLow->getNumberOfElements())
768 lowResStat = 1.0f - (float)meshLow->getNumberOfElements() / (float)meshFull->getNumberOfElements();
770 // We write the file in /tmp to get it's size.
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");
782 insertMesh(MeshDisPart::MULTIPR_WRITE_MESH,
793 ret.push_back(newPartName);
797 // We get the original file size.
798 std::string filename = part->getMEDFileName();
799 stat(filename.c_str(), &fileStat);
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;
811 string MeshDis::evalDecimationParams(
812 const char* pPartName,
813 const char* pFieldName,
815 const char* pFilterName,
816 const char* pFilterParams)
818 MeshDisPart* part = findPart(pPartName);
826 if (part->mMesh == NULL)
831 multipr::DecimationFilter* filter = multipr::DecimationFilter::create(pFilterName);
837 multipr::DecimationFilterGradAvg* filterGrad = dynamic_cast<multipr::DecimationFilterGradAvg*>(filter);
839 if (filterGrad != NULL)
843 int ret = sscanf(pFilterParams, "%d", &mode);
845 // mode 2 = GET RADIUS
846 if ((ret == 1) && (mode == 2))
848 double radius = part->mMesh->evalDefaultRadius(8);
850 sprintf(res, "%f", radius);
857 ret = sscanf(pFilterParams, "%d %f %d", &mode, &radius, &boxing);
859 // mode 1 = GET GRADIENT MIN, MAX and AVG
860 if ((ret == 3) && (mode == 1))
862 double gradMin = 0.1, gradAvg = 0.15, gradMax = 0.2;
864 filterGrad->getGradientInfo(
875 sprintf(res, "%f %f %f", gradMin, gradAvg, gradMax);
890 int MeshDis::computeNumParts()
894 for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
896 switch (mParts[itPart]->mToDoOnNextWrite)
898 case MeshDisPart::MULTIPR_KEEP_AS_IT:
899 case MeshDisPart::MULTIPR_WRITE_MESH:
903 case MeshDisPart::MULTIPR_WRITE_PARTS:
904 numParts += mParts[itPart]->mSplit + 1;
907 default: throw IllegalStateException("", __FILE__, __LINE__);
915 void MeshDis::readDistributedMED(const char* pMEDfilename)
917 if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
919 const int MAX_SIZEOF_LINE = 1024;
922 strcpy(mDistributedMEDFilename, pMEDfilename);
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__);
930 //---------------------------------------------------------------------
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__);
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__);
945 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
948 if ((charbuffer[0] == '#') && ((strTag = strstr(charbuffer, "[SOURCE]=")) != NULL))
950 char strSequentialMEDFilename[256];
951 int ret = sscanf(strTag, "[SOURCE]=%s", strSequentialMEDFilename);
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__ );
960 setSequentialMEDFilename(strSequentialMEDFilename);
963 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
964 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
967 // read number of parts
968 int nbParts = atoi(charbuffer);
970 //---------------------------------------------------------------------
971 // Read infos about sub-parts
972 //---------------------------------------------------------------------
973 char lMeshName[MED_TAILLE_NOM + 1];
975 char lPartName[MED_TAILLE_NOM + 1];
977 char lMEDFileName[256];
979 for (int i = 0 ; i < nbParts ; i++)
981 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
982 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
984 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
986 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
987 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
994 lMEDFileName[0] = '\0';
996 int ret = sscanf(charbuffer, "%s %d %s %s %s",
1003 if (ret != 5) throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
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__ );
1011 //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
1013 MeshDisPart::MULTIPR_KEEP_AS_IT,
1022 //---------------------------------------------------------------------
1023 // Close master file
1024 //---------------------------------------------------------------------
1026 if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1029 void MeshDis::readPersistentDistributedMED(const char* pMEDfilename)
1031 if (pMEDfilename == NULL) throw NullArgumentException("filename should not be NULL", __FILE__, __LINE__);
1033 const int MAX_SIZEOF_LINE = 1024;
1036 strcpy(mDistributedMEDFilename, pMEDfilename);
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__);
1044 //---------------------------------------------------------------------
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__);
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__);
1059 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1061 char* strTag = NULL;
1062 if ((charbuffer[0] == '#') && ((strTag = strstr(charbuffer, "[SOURCE]=")) != NULL))
1064 char strSequentialMEDFilename[256];
1065 int ret = sscanf(strTag, "[SOURCE]=%s", strSequentialMEDFilename);
1068 setSequentialMEDFilename(strSequentialMEDFilename);
1071 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1072 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1075 // read number of parts
1076 int nbParts = atoi(charbuffer);
1078 //---------------------------------------------------------------------
1079 // Read infos about sub-parts
1080 //---------------------------------------------------------------------
1081 char lMeshName[MED_TAILLE_NOM + 1];
1083 char lPartName[MED_TAILLE_NOM + 1];
1085 char lMEDFileName[256];
1087 for (int i = 0 ; i < nbParts ; i++)
1089 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1090 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1092 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1094 fileMaster.getline(charbuffer, MAX_SIZEOF_LINE);
1095 if (fileMaster.fail()) throw IOException("i/o error while reading MED master file", __FILE__, __LINE__);
1098 lMeshName[0] = '\0';
1100 lPartName[0] = '\0';
1102 lMEDFileName[0] = '\0';
1104 int ret = sscanf(charbuffer, "%s %d %s %s %s",
1112 throw IOException("i/o error while reading MED master file; bad format", __FILE__, __LINE__);
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;
1120 //cout << "DBG: read: " << lMeshName << " " << lId << " " << lPartName << endl;
1121 addMesh(MeshDisPart::MULTIPR_KEEP_AS_IT,
1126 newMEDFileName.c_str(), // lMEDFileName
1130 //---------------------------------------------------------------------
1131 // Close master file
1132 //---------------------------------------------------------------------
1134 if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1138 * Retrieves the output of MEDSPLITTER and convert it for MULTIPR.
1140 int convertMedsplitterToMultipr(
1141 ofstream& pFileMaster,
1142 const char* pTmpFilename,
1147 MULTIPR_LOG("convert" << endl);
1149 const int MAX_SIZEOF_LINE = 1024;
1150 char charbuffer[MAX_SIZEOF_LINE];
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__);
1157 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1158 if (fileMasterMedsplitter.fail())
1159 throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);
1161 while ((charbuffer[0] == '#') || (strlen(charbuffer) == 0))
1163 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1164 if (fileMasterMedsplitter.fail())
1165 throw IOException("i/o error while reading MEDSPLITTER master file", __FILE__, __LINE__);
1168 // read number of parts
1169 int nbParts = atoi(charbuffer);
1170 //cout << "nb parts=" << nbParts << endl;
1172 char lMeshName[MED_TAILLE_NOM + 1];
1174 char lPartName[MED_TAILLE_NOM + 1];
1176 char lMEDFileName[256];
1178 for (int i = 0 ; i < nbParts ; i++)
1180 fileMasterMedsplitter.getline(charbuffer, MAX_SIZEOF_LINE);
1181 if (fileMasterMedsplitter.fail()) throw IOException("", __FILE__, __LINE__);
1183 // parses the current line
1184 lMeshName[0] = '\0';
1186 lPartName[0] = '\0';
1188 lMEDFileName[0] = '\0';
1190 int ret = sscanf(charbuffer, "%s %d %s %s %s",
1198 throw IOException("i/o error while reading MEDSPLITTER master file; bad format", __FILE__, __LINE__);
1200 string strDestFilename = pDestPath + multipr::getFilenameWithoutPath(lMEDFileName);
1201 if (strcmp(lMEDFileName, strDestFilename.c_str()) != 0)
1203 multipr::copyFile(lMEDFileName, pDestPath.c_str());
1204 strcpy(lMEDFileName, strDestFilename.c_str());
1207 pFileMaster << lMeshName << "_" << (i + 1) << " " << (pId + i + 1)
1208 << " " << pPart->getPartName() << "_" << (i + 1)
1209 << " " << lPath << " " << lMEDFileName << endl;
1212 fileMasterMedsplitter.close();
1213 if (fileMasterMedsplitter.fail())
1214 throw IOException("i/o error while closing MEDSPLITTER master file", __FILE__, __LINE__);
1216 // remove master file generated by MEDSPLITTER
1217 remove(pTmpFilename);
1223 void MeshDis::writeDistributedMED (const char* pMEDfilenamePrefix,
1224 bool pIsPersistence)
1226 if (pMEDfilenamePrefix == NULL) throw NullArgumentException("", __FILE__, __LINE__);
1228 //---------------------------------------------------------------------
1229 // Build master filename
1230 //---------------------------------------------------------------------
1231 string strPrefix = string(pMEDfilenamePrefix);
1232 const char* strExtension = ".med";
1233 string strMasterFilename;
1235 // add suffix "_groupes_maitre" iff it is not yet in the filename
1236 if (strstr(pMEDfilenamePrefix, "_groupes_maitre") == 0)
1238 strMasterFilename= strPrefix + "_groupes_maitre" + strExtension;
1242 strMasterFilename = strPrefix + strExtension;
1245 string strDestPath = multipr::getPath(strMasterFilename.c_str());
1247 MULTIPR_LOG("Create master: " << strMasterFilename << endl);
1248 strcpy(mDistributedMEDFilename, strMasterFilename.c_str());
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());
1256 if (fileMaster == 0) throw IOException("i/o error while creating MED master file", __FILE__, __LINE__);
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;
1263 fileMaster << computeNumParts() << endl;
1264 if (fileMaster.fail()) throw IOException("i/o error while writing MED master file", __FILE__, __LINE__);
1266 //---------------------------------------------------------------------
1267 // Create a new MED file (v2.3)
1268 //---------------------------------------------------------------------
1271 if (gProgressCallback != NULL) gProgressCallback->start("Save mesh", mParts.size());
1276 // for each sub-meshes
1277 for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
1279 switch (mParts[itPart]->mToDoOnNextWrite)
1281 case MeshDisPart::MULTIPR_KEEP_AS_IT:
1283 string curFilename = mParts[itPart]->getMEDFileName();
1284 int curId = mParts[itPart]->mId;
1286 mParts[itPart]->mId = id;
1289 // copy file in another directory?
1290 string strSrcPath = multipr::getPath(curFilename.c_str());
1291 if (strSrcPath != strDestPath)
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());
1299 fileMaster << (*mParts[itPart]) << endl;
1300 cout << (*mParts[itPart]) << endl;
1302 // restore old filename and id in case of persistence
1305 strcpy(mParts[itPart]->mMEDFileName, curFilename.c_str());
1306 mParts[itPart]->mId = curId;
1311 case MeshDisPart::MULTIPR_WRITE_MESH:
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__);
1318 string curFilename = mParts[itPart]->getMEDFileName();
1319 int curId = mParts[itPart]->mId;
1321 string strDestFilename = strDestPath +
1322 multipr::getFilenameWithoutPath(curFilename.c_str());
1323 strcpy(mParts[itPart]->mMEDFileName, strDestFilename.c_str());
1325 mParts[itPart]->mMesh->writeMED(mParts[itPart]->getMEDFileName());
1326 mParts[itPart]->mId = id;
1328 fileMaster << (*mParts[itPart]) << endl;
1329 cout << (*mParts[itPart]) << endl;
1331 // restore old filename and id in case of persistence
1334 strcpy(mParts[itPart]->mMEDFileName, curFilename.c_str());
1335 mParts[itPart]->mId = curId;
1340 case MeshDisPart::MULTIPR_WRITE_PARTS:
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());
1351 // remove previous file
1352 remove(tmpFilename);
1353 for (int i = 1 ; i <= mParts[itPart]->mSplit ; i++)
1356 sprintf(filename, "%s%d.med", tmpFilename, i);
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);
1365 //remove(mParts[itPart]->getMEDFileName());
1369 default: throw IllegalStateException("should not be there", __FILE__, __LINE__);
1372 if (gProgressCallback != NULL) gProgressCallback->moveOn();
1373 setProgress((itPart + 1) * 100 / mParts.size());
1376 catch (RuntimeException& e)
1378 if (gProgressCallback != NULL) gProgressCallback->done();
1383 if (gProgressCallback != NULL) gProgressCallback->done();
1386 //---------------------------------------------------------------------
1387 // Close master file
1388 //---------------------------------------------------------------------
1391 if (fileMaster.fail()) throw IOException("i/o error while closing MED master file", __FILE__, __LINE__);
1394 void MeshDis::setProgress (int pPercents)
1396 boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
1397 mWriteProgress = pPercents;
1400 int MeshDis::getProgress()
1402 boost::recursive_mutex::scoped_lock aLock (mWriteMutex);
1403 int ret = mWriteProgress;
1408 void MeshDis::readAndWriteFields (const char* pMeshName, std::vector<Group*>* pGroups,
1409 GaussIndexList* pGaussList, std::vector<Profil*>& pProfils)
1411 med_int lMEDfile, lCurMEDfile;
1412 std::vector<med_int> lFiles;
1413 std::map<std::string, Profil*> lProfilByName;
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);
1423 throw IOException("error while reading number of fields in the MED file", __FILE__, __LINE__);
1424 MULTIPR_LOG(numFields << ": OK\n");
1426 // For each part open the corresponding MED file.
1427 for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
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)
1434 throw IOException("Can't open part med file.", __FILE__, __LINE__);
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)
1441 std::string lName = (*it)->getName();
1442 lProfilByName[lName] = (*it);
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)
1451 for (int i = 0; i < eMaxMedMesh; ++i)
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())
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())
1471 // Close all MED files.
1472 for (unsigned itPart = 0 ; itPart < mParts.size() ; itPart++)
1474 MEDfermer(lFiles[itPart]);
1478 ostream& operator<<(ostream& pOs, MeshDis& pM)
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;
1485 for (unsigned itPart = 0 ; itPart < pM.mParts.size() ; itPart++)
1487 cout << " " << (itPart + 1) << ": " << (*(pM.mParts[itPart])) << endl;
1494 } // namespace multipr