1 // Copyright (C) 2007-2013 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
20 #include "MEDPARTITIONER_ParallelTopology.hxx"
21 #include "MEDPARTITIONER_MeshCollectionDriver.hxx"
22 #include "MEDPARTITIONER_MeshCollection.hxx"
23 #include "MEDPARTITIONER_MeshCollectionMedXmlDriver.hxx"
24 #include "MEDPARTITIONER_ParaDomainSelector.hxx"
25 #include "MEDPARTITIONER_Utils.hxx"
27 #include "MEDCouplingUMesh.hxx"
28 #include "MEDLoader.hxx"
29 #include "MEDFileMesh.hxx"
45 #include <libxml/tree.h>
46 #include <libxml/parser.h>
47 #include <libxml/xpath.h>
48 #include <libxml/xpathInternals.h>
50 using namespace MEDPARTITIONER;
52 /*!\class MeshCollectionMedXmlDriver
54 *\brief Driver for MED 3.2 files having Xml master files
56 * Driver for reading and writing distributed files
57 * for which the master file is written in an Xml format compliant with
58 * the MED 3.2 specification.
59 * The reading and writing of the meshes and fields are apart :
60 * the meshes must always be written/read before the fields. Reading/Writing fields
61 * is optional and is done field after field. API for reading/writing fields
62 * is written with a template so that FIELD<int> and FIELD<double>
63 * can be conveniently handled.
66 MeshCollectionMedXmlDriver::MeshCollectionMedXmlDriver(MeshCollection* collection):MeshCollectionDriver(collection)
70 /*!reads a MED File Xml Master File v>=2.3
71 * and mounts the corresponding meshes in memory
72 * the connect zones are created from the joints
74 *\param filename Xml file containing the list of MED v2.3 files
77 int MeshCollectionMedXmlDriver::read(const char* filename, ParaDomainSelector* domainSelector)
81 _master_filename=filename;
83 //reading ascii master file
86 //Setting up the Xml tree corresponding to filename
87 xmlDocPtr master_doc=xmlParseFile(filename);
90 throw INTERP_KERNEL::Exception("Xml Master File does not exist or is not compliant with Xml scheme");
93 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(master_doc);
94 xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(BAD_CAST "//splitting/subdomain", xpathCtx);
95 if (xpathObj==0 || xpathObj->nodesetval->nodeNr ==0)
96 throw INTERP_KERNEL::Exception("Xml Master File does not contain /MED/splitting/subdomain node");
98 //as subdomain has only one property which is "number"
99 //it suffices to take the content of its first child
100 const char* mystring = (const char*)xpathObj->nodesetval->nodeTab[0]->properties->children->content;
101 sscanf(mystring, "%d", &nbdomain);
104 xmlXPathFreeObject(xpathObj);
105 xpathObj = xmlXPathEvalExpression(BAD_CAST "//content/mesh", xpathCtx);
106 if (xpathObj==0 || xpathObj->nodesetval->nodeNr ==0)
107 throw INTERP_KERNEL::Exception("Xml Master File does not contain /MED/content/mesh node");
108 _collection->setName( (const char*)xpathObj->nodesetval->nodeTab[0]->properties->children->content);
110 //cout << "nb domain " << nbdomain << endl;
111 MyGlobals::_File_Names.resize(nbdomain);
112 MyGlobals::_Mesh_Names.resize(nbdomain);
113 (_collection->getMesh()).resize(nbdomain);
114 (_collection->getFaceMesh()).resize(nbdomain);
115 (_collection->getCellFamilyIds()).resize(nbdomain);
116 (_collection->getFaceFamilyIds()).resize(nbdomain);
118 //retrieving the node which contains the file names
119 const char filechar[]="//files/subfile";
120 xmlXPathFreeObject(xpathObj);
121 xpathObj = xmlXPathEvalExpression(BAD_CAST filechar, xpathCtx);
122 if (xpathObj==0 || xpathObj->nodesetval->nodeNr ==0)
123 throw INTERP_KERNEL::Exception("Xml Master File does not contain /MED/files/subfile nodes");
124 int nbfiles = xpathObj->nodesetval ->nodeNr;
126 for (int i=0; i<nbfiles;i++)
128 //reading information about the domain
131 std::ostringstream name_search_string;
132 name_search_string<<"//files/subfile[@id=\""<<i+1<<"\"]/name";
133 xmlXPathObjectPtr xpathObjfilename =
134 xmlXPathEvalExpression(BAD_CAST name_search_string.str().c_str(),xpathCtx);
135 if (xpathObjfilename->nodesetval ==0)
136 throw INTERP_KERNEL::Exception("Error retrieving a file name from subfile of Xml Master File");
137 MyGlobals::_File_Names[i]=(const char*)xpathObjfilename->nodesetval->nodeTab[0]->children->content;
139 //reading the local mesh names
140 std::ostringstream mesh_search_string;
141 mesh_search_string<<"//mapping/mesh/chunk[@subdomain=\""<<i+1<<"\"]/name";
143 xmlXPathObjectPtr xpathMeshObj = xmlXPathEvalExpression(BAD_CAST mesh_search_string.str().c_str(),xpathCtx);
144 if (xpathMeshObj->nodesetval ==0)
145 throw INTERP_KERNEL::Exception("Error retrieving mesh name from chunk of Xml Master File");
146 MyGlobals::_Mesh_Names[i]=(const char*)xpathMeshObj->nodesetval->nodeTab[0]->children->content;
148 if ( !domainSelector || domainSelector->isMyDomain(i))
150 xmlXPathFreeObject(xpathObjfilename);
151 xmlXPathFreeObject(xpathMeshObj);
155 xmlXPathFreeObject(xpathObj);
156 xmlXPathFreeContext(xpathCtx);
157 xmlFreeDoc(master_doc);
162 throw INTERP_KERNEL::Exception("I/O error reading parallel MED file");
165 ParallelTopology* aPT = new ParallelTopology(_collection->getMesh());
166 //creation of topology from mesh and connect zones
167 if ( _collection->isParallelMode() )
169 //to know nb of cells on each proc to compute global cell ids from locally global
170 domainSelector->gatherNbOf(_collection->getMesh());
172 _collection->setTopology(aPT);
173 _collection->setDomainNames(_collection->getName());
178 /*! writes the collection of meshes in a
180 * with the connect zones being written as joints
181 * \param filename name of the Xml file containing the meshes description
183 void MeshCollectionMedXmlDriver::write(const char* filename, ParaDomainSelector* domainSelector) const
185 xmlDocPtr master_doc = 0;
186 xmlNodePtr root_node = 0, node, node2;
189 //Creating the Xml document
190 master_doc = xmlNewDoc(BAD_CAST "1.0");
191 root_node = xmlNewNode(0, BAD_CAST "root");
192 xmlDocSetRootElement(master_doc,root_node);
194 //Creating child nodes
196 node = xmlNewChild(root_node, 0, BAD_CAST "version",0);
197 xmlNewProp(node, BAD_CAST "maj", BAD_CAST "2");
198 xmlNewProp(node, BAD_CAST "min", BAD_CAST "3");
199 xmlNewProp(node, BAD_CAST "ver", BAD_CAST "1");
206 struct tm *time_asc = localtime(&present);
207 sprintf(date,"%02d%02d%02d",time_asc->tm_year
212 GetLocalTime ( &st );
213 sprintf(date,"%02d%02d%02d",
219 node = xmlNewChild(root_node,0, BAD_CAST "description",0);
221 xmlNewProp(node, BAD_CAST "what", BAD_CAST _collection->getDescription().c_str());
222 xmlNewProp(node, BAD_CAST "when", BAD_CAST date);
225 node =xmlNewChild(root_node,0, BAD_CAST "content",0);
226 node2 = xmlNewChild(node, 0, BAD_CAST "mesh",0);
227 xmlNewProp(node2, BAD_CAST "name", BAD_CAST _collection->getName().c_str());
230 node=xmlNewChild(root_node,0,BAD_CAST "splitting",0);
231 node2=xmlNewChild(node,0,BAD_CAST "subdomain",0);
232 sprintf(buff, "%d", (int)_collection->getMesh().size());
233 xmlNewProp(node2, BAD_CAST "number", BAD_CAST buff);
234 node2=xmlNewChild(node,0,BAD_CAST "global_numbering",0);
235 xmlNewProp(node2, BAD_CAST "present", BAD_CAST "yes");
238 xmlNodePtr file_node=xmlNewChild(root_node,0,BAD_CAST "files",0);
241 node = xmlNewChild(root_node,0,BAD_CAST "mapping",0);
242 xmlNodePtr mesh_node = xmlNewChild(node, 0, BAD_CAST "mesh",0);
243 xmlNewProp(mesh_node, BAD_CAST "name", BAD_CAST _collection->getName().c_str());
245 int nbdomains= _collection->getMesh().size();
247 //loop on the domains
248 std::string finalMeshName=ExtractFromDescription(MyGlobals::_General_Informations[0], "finalMeshName=");
249 for (int idomain=nbdomains-1; idomain>=0;idomain--)
251 std::string distfilename;
252 std::ostringstream suffix;
253 suffix<<filename<<idomain+1<<".med";
254 distfilename=suffix.str();
256 if ( !domainSelector || domainSelector->isMyDomain( idomain ) )
258 if ( (_collection->getMesh())[idomain]->getNumberOfCells()==0 )
259 continue; //empty domain
260 if (MyGlobals::_Verbose>1)
261 std::cout << "proc "<< domainSelector->rank() << " : writeMedFile " << distfilename
262 << " "<< (_collection->getMesh())[idomain]->getNumberOfCells() << " cells"
263 << " " << (_collection->getFaceMesh())[idomain]->getNumberOfCells() << " faces"
264 << " " << (_collection->getMesh())[idomain]->getNumberOfNodes()<<" nodes" << std::endl;
265 writeMedFile(idomain,distfilename);
268 if (domainSelector->rank()==0)
270 //updating the ascii description file
271 node = xmlNewChild(file_node, 0, BAD_CAST "subfile",0);
272 sprintf (buff,"%d",idomain+1);
273 xmlNewProp(node, BAD_CAST "id", BAD_CAST buff);
274 xmlNewChild(node,0,BAD_CAST "name",BAD_CAST distfilename.c_str());
275 xmlNewChild(node,0,BAD_CAST "machine",BAD_CAST "localhost");
277 node = xmlNewChild(mesh_node,0, BAD_CAST "chunk",0);
278 xmlNewProp(node, BAD_CAST "subdomain", BAD_CAST buff);
279 xmlNewChild(node,0,BAD_CAST "name", BAD_CAST finalMeshName.c_str());
280 //xmlNewChild(node,0,BAD_CAST "name", BAD_CAST (_collection->getMesh())[idomain]->getName());
284 //create the ascii description file
285 if (domainSelector->rank()==0)
287 std::string myfile(filename);
288 myfile.append(".xml");
289 if ( !domainSelector || domainSelector->rank() == 0 )
290 xmlSaveFormatFileEnc(myfile.c_str(), master_doc, "UTF-8", 1);
292 xmlFreeDoc(master_doc);