Chaste Commit::f2ff7ee04e70ac9d06c57344df8d017dbb12b97b
XdmfMeshWriter.cpp
1/*
2
3Copyright (c) 2005-2024, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include <sstream>
37#include <map>
38
39#include "XdmfMeshWriter.hpp"
40#include "DistributedTetrahedralMesh.hpp"
41#include "Version.hpp"
42
43template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
45 const std::string& rBaseName,
46 const bool clearOutputDir)
47 : AbstractTetrahedralMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, clearOutputDir),
48 mNumberOfTimePoints(1u),
49 mTimeStep(1.0)
50{
51}
52
53template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
55 bool keepOriginalElementIndexing)
56{
57#ifdef _MSC_VER
58 EXCEPTION("XDMF is not supported under Windows at present.");
59#else
60 assert(keepOriginalElementIndexing);
61 this->mpDistributedMesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* >(&rMesh);
62 bool mesh_is_distributed = (this->mpDistributedMesh != nullptr) && PetscTools::IsParallel();
63
65 {
66 // Write main test Grid collection (to be later replaced by temporal collection)
67 // Write references to geometry and topology chunk(s)
68 unsigned num_chunks = 1;
69 if (mesh_is_distributed)
70 {
71 num_chunks = PetscTools::GetNumProcs();
72 }
73 WriteXdmfMasterFile(num_chunks);
74 }
75 if (!mesh_is_distributed && !PetscTools::AmMaster())
76 {
77 //If the mesh is not distributed then the master knows everything and will write the geometry/topology as a single chunk
78 PetscTools::Barrier("XdmfMeshWriter wait for chunks to be written");
79 return;
80 }
81
82 // Geometry
83 std::stringstream local_geometry_file_name;
84 local_geometry_file_name << this->mBaseName << "_geometry_"<< PetscTools::GetMyRank() <<".xml";
85 out_stream geometry_file = this->mpOutputFileHandler->OpenOutputFile(local_geometry_file_name.str());
86 std::string geom_type = "XYZ";
87 if (SPACE_DIM == 2)
88 {
89 geom_type = "XY";
90 }
91 (*geometry_file) << "<Geometry GeometryType=\""<< geom_type <<"\">\n";
92 unsigned num_nodes = rMesh.GetNumNodes();
93 if (this->mpDistributedMesh)
94 {
95 num_nodes = this->mpDistributedMesh->GetNumLocalNodes() + this->mpDistributedMesh->GetNumHaloNodes();
96 }
97
98 (*geometry_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< num_nodes <<" "<< SPACE_DIM <<"\" DataType=\"Float\">";
99
100 // Map a global node index into a local index (into mNodes and mHaloNodes as if they were concatenated)
101 std::map<unsigned, unsigned> global_to_node_index_map;
102
103 //Node index that we are writing to the chunk (index into mNodes and mHaloNodes as if they were concatenated)
104 unsigned index = 0;
105
106 // Owned nodes come first
108 iter != rMesh.GetNodeIteratorEnd();
109 ++iter)
110 {
111 global_to_node_index_map[iter->GetIndex()] = index;
112 index++;
113 (*geometry_file) << "\n\t\t";
114 c_vector<double, SPACE_DIM> current_item = (iter)->rGetLocation();
115 for (unsigned j=0; j<SPACE_DIM; j++)
116 {
117 (*geometry_file) << current_item[j] << "\t";
118 }
119 }
120
121 // Halo nodes
122 if (this->mpDistributedMesh)
123 {
124 for (typename DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::HaloNodeIterator halo_iter=this->mpDistributedMesh->GetHaloNodeIteratorBegin();
125 halo_iter != this->mpDistributedMesh->GetHaloNodeIteratorEnd();
126 ++halo_iter)
127 {
128 global_to_node_index_map[(*halo_iter)->GetIndex()] = index;
129 index++;
130 (*geometry_file) << "\n\t\t";
131 c_vector<double, SPACE_DIM> current_item = (*halo_iter)->rGetLocation();
132 for (unsigned j=0; j<SPACE_DIM; j++)
133 {
134 (*geometry_file) << current_item[j] << "\t";
135 }
136 }
137 }
138 (*geometry_file) << "\n";
139
140 (*geometry_file) << "\t</DataItem>\n";
141 (*geometry_file) << "</Geometry>\n";
142 (*geometry_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
143 geometry_file->close();
144
145 // Topology
146 std::stringstream local_topology_file_name;
147 local_topology_file_name << this->mBaseName << "_topology_"<< PetscTools::GetMyRank() <<".xml";
148 out_stream topology_file = this->mpOutputFileHandler->OpenOutputFile(local_topology_file_name.str());
149 std::string top_type = "Tetrahedron";
150 if (SPACE_DIM == 2)
151 {
152 top_type = "Triangle";
153 }
154 unsigned num_elems = rMesh.GetNumElements();
155 if (this->mpDistributedMesh)
156 {
157 num_elems = this->mpDistributedMesh->GetNumLocalElements();
158 }
159 (*topology_file) << "<Topology TopologyType=\""<< top_type <<"\" NumberOfElements=\""<< num_elems <<"\">\n";
160 (*topology_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< num_elems <<" "<< ELEMENT_DIM+1 <<"\">";
162 elem_iter != rMesh.GetElementIteratorEnd();
163 ++elem_iter)
164 {
165 (*topology_file) << "\n\t\t";
166 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
167 {
168 unsigned local_index = global_to_node_index_map[ elem_iter->GetNodeGlobalIndex(j) ];
169 (*topology_file) << local_index <<"\t";
170 }
171 }
172 (*topology_file) << "\n";
173
174 (*topology_file) << "\t</DataItem>\n";
175 (*topology_file) << "</Topology>\n";
176 (*topology_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
177 topology_file->close();
178 PetscTools::Barrier("XdmfMeshWriter wait for chunks to be written");
179#endif
180}
181
182template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
184{
185#ifdef _MSC_VER
186 EXCEPTION("XDMF is not supported under Windows at present.");
187#else
188 // This method is only called when there is no mesh. We are writing from a reader.
190 {
191 WriteXdmfMasterFile();
192
193 // Geometry
194 out_stream geometry_file = this->mpOutputFileHandler->OpenOutputFile(this->mBaseName + "_geometry_0.xml");
195 std::string geom_type = "XYZ";
196 if (SPACE_DIM == 2)
197 {
198 geom_type = "XY";
199 }
200 (*geometry_file) << "<Geometry GeometryType=\""<< geom_type <<"\">\n";
201 (*geometry_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< this->GetNumNodes() <<" "<< SPACE_DIM <<"\" DataType=\"Float\">";
202 for (unsigned item_num=0; item_num<this->GetNumNodes(); item_num++)
203 {
204 (*geometry_file) << "\n\t\t";
205 std::vector<double> current_item = this->GetNextNode();
206 for (unsigned j=0; j<SPACE_DIM; j++)
207 {
208 (*geometry_file) << current_item[j]<<"\t";
209 }
210 }
211 (*geometry_file) << "\n";
212
213 (*geometry_file) << "\t</DataItem>\n";
214 (*geometry_file) << "</Geometry>\n";
215 (*geometry_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
216 geometry_file->close();
217
218 // Topology
219 out_stream topology_file = this->mpOutputFileHandler->OpenOutputFile(this->mBaseName + "_topology_0.xml");
220 std::string top_type = "Tetrahedron";
221 if (SPACE_DIM == 2)
222 {
223 top_type = "Triangle";
224 }
225 (*topology_file) << "<Topology TopologyType=\""<< top_type <<"\" NumberOfElements=\""<< this->GetNumElements() <<"\">\n";
226 (*topology_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< this->GetNumElements() <<" "<< ELEMENT_DIM+1 <<"\">";
227 for (unsigned item_num=0; item_num<this->GetNumElements(); item_num++)
228 {
229 (*topology_file) << "\n\t\t";
230 std::vector<unsigned> current_item = this->GetNextElement().NodeIndices;
231 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
232 {
233 (*topology_file) << current_item[j]<<"\t";
234 }
235 }
236 (*topology_file) << "\n";
237
238 (*topology_file) << "\t</DataItem>\n";
239 (*topology_file) << "</Topology>\n";
240 (*topology_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
241 topology_file->close();
242 }
243#endif
244}
245
246template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
248{
249#ifndef _MSC_VER
250 assert(PetscTools::AmMaster());
251 // Define namespace symbols
252 XERCES_CPP_NAMESPACE_USE
253
254 // Initialize Xerces.
255 XMLPlatformUtils::Initialize();
256
257 DOMImplementation* p_DOM_implementation = DOMImplementationRegistry::getDOMImplementation(X("core"));
258
259 DOMDocumentType* p_DOM_document_type = p_DOM_implementation->createDocumentType(X("Xdmf"),nullptr,X("Xdmf.dtd"));
260 DOMDocument* p_DOM_document = p_DOM_implementation->createDocument(nullptr, X("Xdmf"), p_DOM_document_type);
261 DOMElement* p_root_element = p_DOM_document->getDocumentElement();
262 p_root_element->setAttribute(X("Version"), X("2.0"));
263 p_root_element->setAttribute(X("xmlns:xi"), X("http://www.w3.org/2001/XInclude"));
264
265 DOMElement* p_domain_element = p_DOM_document->createElement(X("Domain"));
266 p_root_element->appendChild(p_domain_element);
267
268 // Temporal collection
269 DOMElement* p_grid_temp_collection_element = p_DOM_document->createElement(X("Grid"));
270 p_grid_temp_collection_element->setAttribute(X("CollectionType"), X("Temporal"));
271 p_grid_temp_collection_element->setAttribute(X("GridType"), X("Collection"));
272 p_domain_element->appendChild(p_grid_temp_collection_element);
273
274 // Time values
275 DOMElement* p_time_element = p_DOM_document->createElement(X("Time"));
276 p_time_element->setAttribute(X("TimeType"), X("HyperSlab"));
277 p_grid_temp_collection_element->appendChild(p_time_element);
278
279 DOMElement* p_time_dataitem_element = p_DOM_document->createElement(X("DataItem"));
280 p_time_dataitem_element->setAttribute(X("Format"),X("XML"));
281 p_time_dataitem_element->setAttribute(X("NumberType"),X("Float"));
282 p_time_dataitem_element->setAttribute(X("Dimensions"),X("3"));
283 p_time_element->appendChild(p_time_dataitem_element);
284
285 std::stringstream time_stream;
286 time_stream << "0.0 " << mTimeStep << " " << mNumberOfTimePoints;
287 DOMText* p_time_text = p_DOM_document->createTextNode(X(time_stream.str()));
288 p_time_dataitem_element->appendChild(p_time_text);
289
290 for (unsigned t=0; t<mNumberOfTimePoints; ++t)
291 {
292 DOMElement* p_grid_collection_element = p_DOM_document->createElement(X("Grid"));
293 p_grid_collection_element->setAttribute(X("CollectionType"), X("Spatial"));
294 p_grid_collection_element->setAttribute(X("GridType"), X("Collection"));
295 //p_grid_collection_element->setAttribute(X("Name"), X("spatial_collection"));
296 p_grid_temp_collection_element->appendChild(p_grid_collection_element);
297
298 if (t==0)
299 {
300 for (unsigned chunk=0; chunk<numberOfChunks; chunk++)
301 {
302 std::stringstream chunk_stream;
303 chunk_stream << chunk;
304
305 DOMElement* p_grid_element = p_DOM_document->createElement(X("Grid"));
306 p_grid_element->setAttribute(X("GridType"), X("Uniform"));
307 p_grid_element->setAttribute(X("Name"), X("Chunk_" + chunk_stream.str()));
308 p_grid_collection_element->appendChild(p_grid_element);
309
310 //DOMElement* p_geom_element = p_DOM_document->createElement(X("Geometry"));
311 //p_geom_element->setAttribute(X("Reference"),X("/Xdmf/Domain/Geometry[1]"));
312 DOMElement* p_geom_element = p_DOM_document->createElement(X("xi:include"));
313 p_geom_element->setAttribute(X("href"), X(this->mBaseName+"_geometry_"+chunk_stream.str()+".xml"));
314 p_grid_element->appendChild(p_geom_element);
315 //DOMElement* p_topo_element = p_DOM_document->createElement(X("Topology"));
316 //p_topo_element->setAttribute(X("Reference"),X("/Xdmf/Domain/Topology[1]"));
317 DOMElement* p_topo_element = p_DOM_document->createElement(X("xi:include"));
318 p_topo_element->setAttribute(X("href"), X(this->mBaseName+"_topology_"+chunk_stream.str()+".xml"));
319 p_grid_element->appendChild(p_topo_element);
320
321 /*
322 * p_grid_element may now need an Attribute (node data). Call Annotate,
323 * which here does nothing, but in pde can be overloaded to print variables
324 */
325 AddDataOnNodes(p_grid_element, p_DOM_document, t);
326 }
327 }
328 else // t>0
329 {
330 for (unsigned chunk=0; chunk<numberOfChunks; chunk++)
331 {
332 std::stringstream chunk_stream;
333 chunk_stream << chunk;
334
335 DOMElement* p_grid_element = p_DOM_document->createElement(X("Grid"));
336 p_grid_element->setAttribute(X("GridType"), X("Subset"));
337 p_grid_element->setAttribute(X("Section"), X("All"));
338 p_grid_collection_element->appendChild(p_grid_element);
339
340 /*
341 * p_grid_element may now need an Attribute (node data). Call Annotate,
342 * which here does nothing, but in pde can be overloaded to print variables
343 */
344 AddDataOnNodes(p_grid_element, p_DOM_document, t);
345 DOMElement* p_grid_ref_element = p_DOM_document->createElement(X("Grid"));
346 p_grid_ref_element->setAttribute(X("GridType"), X("Uniform"));
347 p_grid_ref_element->setAttribute(X("Reference"), X("XML"));
348 //p_grid_ref_element->setAttribute(X("Name"), X("Chunk_" + chunk_stream.str()));
349
350 DOMText* p_ref_text = p_DOM_document->createTextNode(X("/Xdmf/Domain/Grid/Grid/Grid[@Name=\"Chunk_"+chunk_stream.str()+"\"]"));
351 p_grid_ref_element->appendChild(p_ref_text);
352 p_grid_element->appendChild(p_grid_ref_element);
353 }
354 }
355 }
356 // Create a Comment node, and then append this to the root element.
357 DOMComment* p_provenance_comment = p_DOM_document->createComment(X(" "+ChasteBuildInfo::GetProvenanceString()));
358 p_DOM_document->appendChild(p_provenance_comment);
359
360 XMLFormatTarget* p_target = new LocalFileFormatTarget(X(this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName+".xdmf"));
361
362#if _XERCES_VERSION >= 30000
363 DOMLSSerializer* p_serializer = ((DOMImplementationLS*)p_DOM_implementation)->createLSSerializer();
364 p_serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
365 DOMLSOutput* p_output = ((DOMImplementationLS*)p_DOM_implementation)->createLSOutput(); // Calls a new somewhere!
366 p_output->setByteStream(p_target);
367 p_serializer->write(p_DOM_document, p_output);
368#else
369 DOMWriter* p_serializer = ((DOMImplementationLS*)p_DOM_implementation)->createDOMWriter();
370 p_serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
371 p_serializer->writeNode(p_target, *p_DOM_document);
372#endif
373
374 // Cleanup
375 p_serializer->release();
376 p_DOM_document->release();
377#if _XERCES_VERSION >= 30000
378 delete p_output;
379#endif
380 delete p_target;
381 XMLPlatformUtils::Terminate();
382#endif // _MSC_VER
383}
384
385// Explicit instantiation
386template class XdmfMeshWriter<1,1>;
387template class XdmfMeshWriter<1,2>;
388template class XdmfMeshWriter<1,3>;
389template class XdmfMeshWriter<2,2>; // Actually used
390template class XdmfMeshWriter<2,3>;
391template class XdmfMeshWriter<3,3>; // Actually used
#define EXCEPTION(message)
virtual unsigned GetNumNodes() const
NodeIterator GetNodeIteratorEnd()
NodeIterator GetNodeIteratorBegin(bool skipDeletedNodes=true)
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
virtual unsigned GetNumElements() const
static std::string GetProvenanceString()
std::vector< Node< SPACE_DIM > * >::const_iterator HaloNodeIterator
static bool AmMaster()
static void Barrier(const std::string callerId="")
static bool IsParallel()
static unsigned GetMyRank()
static unsigned GetNumProcs()
XdmfMeshWriter(const std::string &rDirectory, const std::string &rBaseName, const bool clearOutputDir=true)
void WriteXdmfMasterFile(unsigned numberOfChunks=1u)
void WriteFilesUsingMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, bool keepOriginalElementIndexing=true)