Chaste Commit::fa89f2b838c1edb21a1eaec92ee3a2eacc9255dd
XdmfMeshWriter.cpp
1/*
2
3Copyright (c) 2005-2026, 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 assert(keepOriginalElementIndexing);
58 this->mpDistributedMesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* >(&rMesh);
59 bool mesh_is_distributed = (this->mpDistributedMesh != nullptr) && PetscTools::IsParallel();
60
62 {
63 // Write main test Grid collection (to be later replaced by temporal collection)
64 // Write references to geometry and topology chunk(s)
65 unsigned num_chunks = 1;
66 if (mesh_is_distributed)
67 {
68 num_chunks = PetscTools::GetNumProcs();
69 }
70 WriteXdmfMasterFile(num_chunks);
71 }
72 if (!mesh_is_distributed && !PetscTools::AmMaster())
73 {
74 //If the mesh is not distributed then the master knows everything and will write the geometry/topology as a single chunk
75 PetscTools::Barrier("XdmfMeshWriter wait for chunks to be written");
76 return;
77 }
78
79 // Geometry
80 std::stringstream local_geometry_file_name;
81 local_geometry_file_name << this->mBaseName << "_geometry_"<< PetscTools::GetMyRank() <<".xml";
82 out_stream geometry_file = this->mpOutputFileHandler->OpenOutputFile(local_geometry_file_name.str());
83 std::string geom_type = "XYZ";
84 if (SPACE_DIM == 2)
85 {
86 geom_type = "XY";
87 }
88 (*geometry_file) << "<Geometry GeometryType=\""<< geom_type <<"\">\n";
89 unsigned num_nodes = rMesh.GetNumNodes();
90 if (this->mpDistributedMesh)
91 {
92 num_nodes = this->mpDistributedMesh->GetNumLocalNodes() + this->mpDistributedMesh->GetNumHaloNodes();
93 }
94
95 (*geometry_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< num_nodes <<" "<< SPACE_DIM <<"\" DataType=\"Float\">";
96
97 // Map a global node index into a local index (into mNodes and mHaloNodes as if they were concatenated)
98 std::map<unsigned, unsigned> global_to_node_index_map;
99
100 //Node index that we are writing to the chunk (index into mNodes and mHaloNodes as if they were concatenated)
101 unsigned index = 0;
102
103 // Owned nodes come first
105 iter != rMesh.GetNodeIteratorEnd();
106 ++iter)
107 {
108 global_to_node_index_map[iter->GetIndex()] = index;
109 index++;
110 (*geometry_file) << "\n\t\t";
111 c_vector<double, SPACE_DIM> current_item = (iter)->rGetLocation();
112 for (unsigned j=0; j<SPACE_DIM; j++)
113 {
114 (*geometry_file) << current_item[j] << "\t";
115 }
116 }
117
118 // Halo nodes
119 if (this->mpDistributedMesh)
120 {
121 for (typename DistributedTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::HaloNodeIterator halo_iter=this->mpDistributedMesh->GetHaloNodeIteratorBegin();
122 halo_iter != this->mpDistributedMesh->GetHaloNodeIteratorEnd();
123 ++halo_iter)
124 {
125 global_to_node_index_map[(*halo_iter)->GetIndex()] = index;
126 index++;
127 (*geometry_file) << "\n\t\t";
128 c_vector<double, SPACE_DIM> current_item = (*halo_iter)->rGetLocation();
129 for (unsigned j=0; j<SPACE_DIM; j++)
130 {
131 (*geometry_file) << current_item[j] << "\t";
132 }
133 }
134 }
135 (*geometry_file) << "\n";
136
137 (*geometry_file) << "\t</DataItem>\n";
138 (*geometry_file) << "</Geometry>\n";
139 (*geometry_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
140 geometry_file->close();
141
142 // Topology
143 std::stringstream local_topology_file_name;
144 local_topology_file_name << this->mBaseName << "_topology_"<< PetscTools::GetMyRank() <<".xml";
145 out_stream topology_file = this->mpOutputFileHandler->OpenOutputFile(local_topology_file_name.str());
146 std::string top_type = "Tetrahedron";
147 if (SPACE_DIM == 2)
148 {
149 top_type = "Triangle";
150 }
151 unsigned num_elems = rMesh.GetNumElements();
152 if (this->mpDistributedMesh)
153 {
154 num_elems = this->mpDistributedMesh->GetNumLocalElements();
155 }
156 (*topology_file) << "<Topology TopologyType=\""<< top_type <<"\" NumberOfElements=\""<< num_elems <<"\">\n";
157 (*topology_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< num_elems <<" "<< ELEMENT_DIM+1 <<"\">";
159 elem_iter != rMesh.GetElementIteratorEnd();
160 ++elem_iter)
161 {
162 (*topology_file) << "\n\t\t";
163 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
164 {
165 unsigned local_index = global_to_node_index_map[ elem_iter->GetNodeGlobalIndex(j) ];
166 (*topology_file) << local_index <<"\t";
167 }
168 }
169 (*topology_file) << "\n";
170
171 (*topology_file) << "\t</DataItem>\n";
172 (*topology_file) << "</Topology>\n";
173 (*topology_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
174 topology_file->close();
175 PetscTools::Barrier("XdmfMeshWriter wait for chunks to be written");
176}
177
178template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
180{
181 // This method is only called when there is no mesh. We are writing from a reader.
183 {
184 WriteXdmfMasterFile();
185
186 // Geometry
187 out_stream geometry_file = this->mpOutputFileHandler->OpenOutputFile(this->mBaseName + "_geometry_0.xml");
188 std::string geom_type = "XYZ";
189 if (SPACE_DIM == 2)
190 {
191 geom_type = "XY";
192 }
193 (*geometry_file) << "<Geometry GeometryType=\""<< geom_type <<"\">\n";
194 (*geometry_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< this->GetNumNodes() <<" "<< SPACE_DIM <<"\" DataType=\"Float\">";
195 for (unsigned item_num=0; item_num<this->GetNumNodes(); item_num++)
196 {
197 (*geometry_file) << "\n\t\t";
198 std::vector<double> current_item = this->GetNextNode();
199 for (unsigned j=0; j<SPACE_DIM; j++)
200 {
201 (*geometry_file) << current_item[j]<<"\t";
202 }
203 }
204 (*geometry_file) << "\n";
205
206 (*geometry_file) << "\t</DataItem>\n";
207 (*geometry_file) << "</Geometry>\n";
208 (*geometry_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
209 geometry_file->close();
210
211 // Topology
212 out_stream topology_file = this->mpOutputFileHandler->OpenOutputFile(this->mBaseName + "_topology_0.xml");
213 std::string top_type = "Tetrahedron";
214 if (SPACE_DIM == 2)
215 {
216 top_type = "Triangle";
217 }
218 (*topology_file) << "<Topology TopologyType=\""<< top_type <<"\" NumberOfElements=\""<< this->GetNumElements() <<"\">\n";
219 (*topology_file) << "\t<DataItem Format=\"XML\" Dimensions=\""<< this->GetNumElements() <<" "<< ELEMENT_DIM+1 <<"\">";
220 for (unsigned item_num=0; item_num<this->GetNumElements(); item_num++)
221 {
222 (*topology_file) << "\n\t\t";
223 std::vector<unsigned> current_item = this->GetNextElement().NodeIndices;
224 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
225 {
226 (*topology_file) << current_item[j]<<"\t";
227 }
228 }
229 (*topology_file) << "\n";
230
231 (*topology_file) << "\t</DataItem>\n";
232 (*topology_file) << "</Topology>\n";
233 (*topology_file) << "<!-- " + ChasteBuildInfo::GetProvenanceString() + "-->\n";
234 topology_file->close();
235 }
236}
237
238template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
240{
241 assert(PetscTools::AmMaster());
242 // Define namespace symbols
243 XERCES_CPP_NAMESPACE_USE
244
245 // Initialize Xerces.
246 XMLPlatformUtils::Initialize();
247
248 DOMImplementation* p_DOM_implementation = DOMImplementationRegistry::getDOMImplementation(X("core"));
249
250 DOMDocumentType* p_DOM_document_type = p_DOM_implementation->createDocumentType(X("Xdmf"),nullptr,X("Xdmf.dtd"));
251 DOMDocument* p_DOM_document = p_DOM_implementation->createDocument(nullptr, X("Xdmf"), p_DOM_document_type);
252 DOMElement* p_root_element = p_DOM_document->getDocumentElement();
253 p_root_element->setAttribute(X("Version"), X("2.0"));
254 p_root_element->setAttribute(X("xmlns:xi"), X("http://www.w3.org/2001/XInclude"));
255
256 DOMElement* p_domain_element = p_DOM_document->createElement(X("Domain"));
257 p_root_element->appendChild(p_domain_element);
258
259 // Temporal collection
260 DOMElement* p_grid_temp_collection_element = p_DOM_document->createElement(X("Grid"));
261 p_grid_temp_collection_element->setAttribute(X("CollectionType"), X("Temporal"));
262 p_grid_temp_collection_element->setAttribute(X("GridType"), X("Collection"));
263 p_domain_element->appendChild(p_grid_temp_collection_element);
264
265 // Time values
266 DOMElement* p_time_element = p_DOM_document->createElement(X("Time"));
267 p_time_element->setAttribute(X("TimeType"), X("HyperSlab"));
268 p_grid_temp_collection_element->appendChild(p_time_element);
269
270 DOMElement* p_time_dataitem_element = p_DOM_document->createElement(X("DataItem"));
271 p_time_dataitem_element->setAttribute(X("Format"),X("XML"));
272 p_time_dataitem_element->setAttribute(X("NumberType"),X("Float"));
273 p_time_dataitem_element->setAttribute(X("Dimensions"),X("3"));
274 p_time_element->appendChild(p_time_dataitem_element);
275
276 std::stringstream time_stream;
277 time_stream << "0.0 " << mTimeStep << " " << mNumberOfTimePoints;
278 DOMText* p_time_text = p_DOM_document->createTextNode(X(time_stream.str()));
279 p_time_dataitem_element->appendChild(p_time_text);
280
281 for (unsigned t=0; t<mNumberOfTimePoints; ++t)
282 {
283 DOMElement* p_grid_collection_element = p_DOM_document->createElement(X("Grid"));
284 p_grid_collection_element->setAttribute(X("CollectionType"), X("Spatial"));
285 p_grid_collection_element->setAttribute(X("GridType"), X("Collection"));
286 //p_grid_collection_element->setAttribute(X("Name"), X("spatial_collection"));
287 p_grid_temp_collection_element->appendChild(p_grid_collection_element);
288
289 if (t==0)
290 {
291 for (unsigned chunk=0; chunk<numberOfChunks; chunk++)
292 {
293 std::stringstream chunk_stream;
294 chunk_stream << chunk;
295
296 DOMElement* p_grid_element = p_DOM_document->createElement(X("Grid"));
297 p_grid_element->setAttribute(X("GridType"), X("Uniform"));
298 p_grid_element->setAttribute(X("Name"), X("Chunk_" + chunk_stream.str()));
299 p_grid_collection_element->appendChild(p_grid_element);
300
301 //DOMElement* p_geom_element = p_DOM_document->createElement(X("Geometry"));
302 //p_geom_element->setAttribute(X("Reference"),X("/Xdmf/Domain/Geometry[1]"));
303 DOMElement* p_geom_element = p_DOM_document->createElement(X("xi:include"));
304 p_geom_element->setAttribute(X("href"), X(this->mBaseName+"_geometry_"+chunk_stream.str()+".xml"));
305 p_grid_element->appendChild(p_geom_element);
306 //DOMElement* p_topo_element = p_DOM_document->createElement(X("Topology"));
307 //p_topo_element->setAttribute(X("Reference"),X("/Xdmf/Domain/Topology[1]"));
308 DOMElement* p_topo_element = p_DOM_document->createElement(X("xi:include"));
309 p_topo_element->setAttribute(X("href"), X(this->mBaseName+"_topology_"+chunk_stream.str()+".xml"));
310 p_grid_element->appendChild(p_topo_element);
311
312 /*
313 * p_grid_element may now need an Attribute (node data). Call Annotate,
314 * which here does nothing, but in pde can be overloaded to print variables
315 */
316 AddDataOnNodes(p_grid_element, p_DOM_document, t);
317 }
318 }
319 else // t>0
320 {
321 for (unsigned chunk=0; chunk<numberOfChunks; chunk++)
322 {
323 std::stringstream chunk_stream;
324 chunk_stream << chunk;
325
326 DOMElement* p_grid_element = p_DOM_document->createElement(X("Grid"));
327 p_grid_element->setAttribute(X("GridType"), X("Subset"));
328 p_grid_element->setAttribute(X("Section"), X("All"));
329 p_grid_collection_element->appendChild(p_grid_element);
330
331 /*
332 * p_grid_element may now need an Attribute (node data). Call Annotate,
333 * which here does nothing, but in pde can be overloaded to print variables
334 */
335 AddDataOnNodes(p_grid_element, p_DOM_document, t);
336 DOMElement* p_grid_ref_element = p_DOM_document->createElement(X("Grid"));
337 p_grid_ref_element->setAttribute(X("GridType"), X("Uniform"));
338 p_grid_ref_element->setAttribute(X("Reference"), X("XML"));
339 //p_grid_ref_element->setAttribute(X("Name"), X("Chunk_" + chunk_stream.str()));
340
341 DOMText* p_ref_text = p_DOM_document->createTextNode(X("/Xdmf/Domain/Grid/Grid/Grid[@Name=\"Chunk_"+chunk_stream.str()+"\"]"));
342 p_grid_ref_element->appendChild(p_ref_text);
343 p_grid_element->appendChild(p_grid_ref_element);
344 }
345 }
346 }
347 // Create a Comment node, and then append this to the root element.
348 DOMComment* p_provenance_comment = p_DOM_document->createComment(X(" "+ChasteBuildInfo::GetProvenanceString()));
349 p_DOM_document->appendChild(p_provenance_comment);
350
351 XMLFormatTarget* p_target = new LocalFileFormatTarget(X(this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName+".xdmf"));
352
353#if _XERCES_VERSION >= 30000
354 DOMLSSerializer* p_serializer = ((DOMImplementationLS*)p_DOM_implementation)->createLSSerializer();
355 p_serializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
356 DOMLSOutput* p_output = ((DOMImplementationLS*)p_DOM_implementation)->createLSOutput(); // Calls a new somewhere!
357 p_output->setByteStream(p_target);
358 p_serializer->write(p_DOM_document, p_output);
359#else
360 DOMWriter* p_serializer = ((DOMImplementationLS*)p_DOM_implementation)->createDOMWriter();
361 p_serializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
362 p_serializer->writeNode(p_target, *p_DOM_document);
363#endif
364
365 // Cleanup
366 p_serializer->release();
367 p_DOM_document->release();
368#if _XERCES_VERSION >= 30000
369 delete p_output;
370#endif
371 delete p_target;
372 XMLPlatformUtils::Terminate();
373}
374
375// Explicit instantiation
376template class XdmfMeshWriter<1,1>;
377template class XdmfMeshWriter<1,2>;
378template class XdmfMeshWriter<1,3>;
379template class XdmfMeshWriter<2,2>; // Actually used
380template class XdmfMeshWriter<2,3>;
381template class XdmfMeshWriter<3,3>; // Actually used
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)