Salome HOME
Update copyrights
[tools/medcoupling.git] / src / MEDPartitioner / MEDPARTITIONER_MeshCollectionMedXmlDriver.cxx
1 // Copyright (C) 2007-2019  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, or (at your option) any later version.
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
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"
26
27 #include "MEDCouplingUMesh.hxx"
28 #include "MEDLoader.hxx"
29 #include "MEDFileMesh.hxx"
30
31 #include <map>
32 #include <set>
33 #include <vector>
34 #include <string>
35 #include <cstring>
36 #include <fstream>
37 #include <sstream>
38 #include <iostream>
39 #ifdef WIN32
40 #include <time.h>
41 #include <windows.h>
42 #endif
43
44
45 #include <libxml/tree.h>
46 #include <libxml/parser.h>
47 #include <libxml/xpath.h>
48 #include <libxml/xpathInternals.h>
49
50 using namespace MEDPARTITIONER;
51
52 /*!\class MeshCollectionMedXmlDriver
53  *
54  *\brief Driver for MED 3.2 files having Xml master files
55  *
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.
64  */
65
66 MeshCollectionMedXmlDriver::MeshCollectionMedXmlDriver(MeshCollection* collection):MeshCollectionDriver(collection)
67 {
68 }
69
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
73  * 
74  *\param filename Xml file containing the list of MED v2.3 files
75  * */
76
77 int MeshCollectionMedXmlDriver::read(const char* filename, ParaDomainSelector* domainSelector)
78 {
79   //distributed meshes
80   int nbdomain;
81   _master_filename=filename;
82
83   //reading ascii master file
84   try
85     {
86       //Setting up the Xml tree corresponding to filename
87       xmlDocPtr master_doc=xmlParseFile(filename);
88
89       if (!master_doc)
90         throw INTERP_KERNEL::Exception("Xml Master File does not exist or is not compliant with Xml scheme");
91
92       //number of domains
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");
97
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);
102
103       //mesh name
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);
109
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);
117
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;
125     
126       for (int i=0; i<nbfiles;i++)
127         {
128           //reading information about the domain
129           std::string host;
130           //reading file names 
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;
138
139           //reading the local mesh names
140           std::ostringstream mesh_search_string;
141           mesh_search_string<<"//mapping/mesh/chunk[@subdomain=\""<<i+1<<"\"]/name";
142
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;
147
148           if ( !domainSelector || domainSelector->isMyDomain(i))
149             readSubdomain(i);
150           xmlXPathFreeObject(xpathObjfilename);
151           xmlXPathFreeObject(xpathMeshObj);
152         } //loop on domains
153
154       //LIBXML cleanup
155       xmlXPathFreeObject(xpathObj); 
156       xmlXPathFreeContext(xpathCtx); 
157       xmlFreeDoc(master_doc); 
158
159     } //of try
160   catch(...)
161     {
162       throw INTERP_KERNEL::Exception("I/O error reading parallel MED file");
163     }
164
165   ParallelTopology* aPT = new ParallelTopology(_collection->getMesh());
166   //creation of topology from mesh and connect zones
167   if ( _collection->isParallelMode() )
168     {
169       //to know nb of cells on each proc to compute global cell ids from locally global
170       domainSelector->gatherNbOf(_collection->getMesh());
171     }
172   _collection->setTopology(aPT, true);
173   _collection->setDomainNames(_collection->getName());
174   return 0;
175 }
176
177
178 /*! writes the collection of meshes in a 
179  * MED v2.3 Xml file
180  * with the connect zones being written as joints
181  * \param filename name of the Xml file containing the meshes description
182  */
183 void MeshCollectionMedXmlDriver::write(const char* filename, ParaDomainSelector* domainSelector) const
184 {
185   xmlDocPtr master_doc = 0;
186   xmlNodePtr root_node = 0, node, node2;
187   char buff[256];
188
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);
193
194   //Creating child nodes
195   // Version tag
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");
200
201   //Description tag
202   time_t present; 
203   char date[20];
204 #ifndef WIN32
205   time( &present);
206   struct tm *time_asc = localtime(&present);
207   sprintf(date,"%02d%02d%02d",time_asc->tm_year
208           ,time_asc->tm_mon+1
209           ,time_asc->tm_mday);
210 #else
211   SYSTEMTIME    st;
212   GetLocalTime ( &st );
213   sprintf(date,"%02d%02d%02d",
214           st.wYear
215           ,st.wMonth
216           ,st.wDay);
217 #endif
218
219   node = xmlNewChild(root_node,0, BAD_CAST "description",0);
220
221   xmlNewProp(node, BAD_CAST "what", BAD_CAST _collection->getDescription().c_str());
222   xmlNewProp(node, BAD_CAST "when", BAD_CAST date);
223
224   //Content tag
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());
228
229   //Splitting tag
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");
236
237   //Files tag
238   xmlNodePtr file_node=xmlNewChild(root_node,0,BAD_CAST "files",0);
239
240   //Mapping tag
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());
244
245   int nbdomains= _collection->getMesh().size();
246
247   //loop on the domains
248   std::string finalMeshName="";
249   if (MyGlobals::_General_Informations.size()!=0)
250     {
251       std::size_t found=MyGlobals::_General_Informations[0].find("finalMeshName=");
252      if ((found!=std::string::npos) && (found>0))
253        {
254          finalMeshName=ExtractFromDescription(MyGlobals::_General_Informations[0], "finalMeshName=");
255        }
256     }
257   if (finalMeshName.empty())
258     {
259       finalMeshName=_collection->getName();
260     }
261   for (int idomain=nbdomains-1; idomain>=0;idomain--)
262     {
263       std::string distfilename;
264       std::ostringstream suffix;
265       suffix<<filename<<idomain+1<<".med";
266       distfilename=suffix.str();
267
268       if ( !domainSelector || domainSelector->isMyDomain( idomain ) )
269         {
270           if ( (_collection->getMesh())[idomain]->getNumberOfCells()==0 )
271             continue; //empty domain
272           if (MyGlobals::_Verbose>1)
273             std::cout << "proc "<< domainSelector->rank() << " : writeMedFile " << distfilename
274                       << " "<< (_collection->getMesh())[idomain]->getNumberOfCells() << " cells"
275                       << " " << (_collection->getFaceMesh())[idomain]->getNumberOfCells() << " faces"
276                       << " " << (_collection->getMesh())[idomain]->getNumberOfNodes()<<" nodes" << std::endl;
277           writeMedFile(idomain,distfilename);
278         }
279
280       if (domainSelector->rank()==0)
281         {
282           //updating the ascii description file
283           node = xmlNewChild(file_node, 0, BAD_CAST "subfile",0);
284           sprintf (buff,"%d",idomain+1);
285           xmlNewProp(node, BAD_CAST "id", BAD_CAST buff);
286           xmlNewChild(node,0,BAD_CAST "name",BAD_CAST distfilename.c_str());
287           xmlNewChild(node,0,BAD_CAST "machine",BAD_CAST "localhost");
288
289           node = xmlNewChild(mesh_node,0, BAD_CAST "chunk",0);
290           xmlNewProp(node, BAD_CAST "subdomain", BAD_CAST buff);
291           xmlNewChild(node,0,BAD_CAST "name", BAD_CAST finalMeshName.c_str());
292           //xmlNewChild(node,0,BAD_CAST "name", BAD_CAST ((_collection->getMesh())[idomain]->getName()).c_str());
293         }
294     }
295   
296   //create the ascii description file
297   if (domainSelector->rank()==0)
298     {
299       std::string myfile(filename);
300       myfile.append(".xml");
301       if ( !domainSelector || domainSelector->rank() == 0 )
302         xmlSaveFormatFileEnc(myfile.c_str(), master_doc, "UTF-8", 1);
303     }
304   xmlFreeDoc(master_doc);
305   xmlCleanupParser();
306 }