Chaste Commit::baa90ac2819b962188b7562f2326be23c47859a7
TrianglesMeshWriter.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 "TrianglesMeshWriter.hpp"
37
38#include "AbstractTetrahedralMesh.hpp"
39#include "Version.hpp"
40
41#include <cassert>
42
44// Implementation
46template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
48 const std::string& rDirectory,
49 const std::string& rBaseName,
50 const bool clearOutputDir)
51 : AbstractTetrahedralMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, clearOutputDir)
52{
53}
54
55template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
59
60template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
62{
63 this->mFilesAreBinary=true;
64}
65
66template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
68{
69 std::string comment = "#\n# " + ChasteBuildInfo::GetProvenanceString();
70// PetscTools::Barrier("DodgyBarrierBeforeNODE");
71 MeshEventHandler::BeginEvent(MeshEventHandler::NODE);
72 // Write node file
73 std::string node_file_name = this->mBaseName + ".node";
74 out_stream p_node_file = this->mpOutputFileHandler->OpenOutputFile(node_file_name, std::ios::binary | std::ios::trunc);
75
76 // Write the node header
77 unsigned num_attr = 0;
78
79 if (this->mpMesh && !this->mFilesAreBinary)
80 {
81 // Assumes that all nodes have the same number of attributes as the first node in the mesh.
82 num_attr = this->mpMesh->GetNumNodeAttributes();
83 }
85 unsigned max_bdy_marker = 0;
86 unsigned num_nodes = this->GetNumNodes();
87
88 *p_node_file << num_nodes << "\t";
89 *p_node_file << SPACE_DIM << "\t";
90 *p_node_file << num_attr << "\t";
91 *p_node_file << max_bdy_marker;
92 if (this->mFilesAreBinary)
93 {
94 *p_node_file << "\tBIN\n";
95 }
96 else
97 {
98 *p_node_file << "\n";
99 }
100
101 *p_node_file << std::setprecision(20);
102
103 // Write each node's data
104 for (unsigned item_num=0; item_num<num_nodes; item_num++)
105 {
106 if (this->mpMesh && !this->mFilesAreBinary && num_attr!=0)
107 {
108
110 WriteItem(p_node_file, item_num, this->GetNextNode(), this->mpMesh->GetNode(item_num)->rGetNodeAttributes());
111 }
112 else
113 {
114 WriteItem(p_node_file, item_num, this->GetNextNode());
115 }
116 }
117 *p_node_file << comment << "\n";
118 p_node_file->close();
119// PetscTools::Barrier("DodgyBarrierAfterNODE");
120 MeshEventHandler::EndEvent(MeshEventHandler::NODE);
121 MeshEventHandler::BeginEvent(MeshEventHandler::ELE);
122 if (ELEMENT_DIM < SPACE_DIM)
123 {
124 WriteElementsAsFaces();
125 WriteFacesAsEdges();
126 return;
127 }
128
129 // Write element file
130 std::string element_file_name = this->mBaseName + ".ele";
131 out_stream p_element_file = this->mpOutputFileHandler->OpenOutputFile(element_file_name, std::ios::binary | std::ios::trunc);
132
133 // Write the element header
134 unsigned num_elements = this->GetNumElements();
135 num_attr = 1u; // We have a single region code
136
137 // The condition below allows the writer to cope with a NodesOnlyMesh
138 if (num_elements == 0)
139 {
140 *p_element_file << 0 << "\t";
141 *p_element_file << 0 << "\t";
142 *p_element_file << 0;
143 if (this->mFilesAreBinary)
144 {
145 *p_element_file << "\tBIN\n";
146 }
147 else
148 {
149 *p_element_file << "\n";
150 }
151 p_element_file->close();
152 }
153 else
154 {
155 ElementData element_data = this->GetNextElement();
156
157 unsigned nodes_per_element = element_data.NodeIndices.size();
158 if (nodes_per_element != ELEMENT_DIM+1)
159 {
160 // Check that this is a quadratic mesh
161 assert(ELEMENT_DIM == SPACE_DIM);
162 assert(nodes_per_element == (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2);
163 }
164
165 *p_element_file << num_elements << "\t";
166 *p_element_file << nodes_per_element << "\t";
167 *p_element_file << num_attr;
168 if (this->mFilesAreBinary)
169 {
170 *p_element_file << "\tBIN\n";
171 }
172 else
173 {
174 *p_element_file << "\n";
175 }
176
177 // Write each element's data
178 std::vector<double> attribute_values(1);
179 for (unsigned item_num=0; item_num<num_elements; item_num++)
180 {
181 /*
182 * If item_num==0 we will already have got the element above (in order to
183 * get the number of nodes per element).
184 */
185 if (item_num > 0)
186 {
187 element_data = this->GetNextElement();
188 }
189 attribute_values[0] = element_data.AttributeValue;
190 WriteItem(p_element_file, item_num, element_data.NodeIndices, attribute_values);
191 }
192 *p_element_file << comment << "\n";
193 p_element_file->close();
194 }
195// PetscTools::Barrier("DodgyBarrierAfterELE");
196 MeshEventHandler::EndEvent(MeshEventHandler::ELE);
197 MeshEventHandler::BeginEvent(MeshEventHandler::FACE);
198 // Write boundary face file
199 std::string face_file_name = this->mBaseName;
200
201 if (ELEMENT_DIM == 1)
202 {
203 // In 1-D there is no boundary file: it's trivial to calculate
204 return;
205 }
206 else if (ELEMENT_DIM == 2)
207 {
208 face_file_name = face_file_name + ".edge";
209 }
210 else
211 {
212 face_file_name = face_file_name + ".face";
213 }
214 out_stream p_face_file = this->mpOutputFileHandler->OpenOutputFile(face_file_name, std::ios::binary | std::ios::trunc);
215
216 // Write the boundary face header
217 if (num_elements != 0)
218 {
219 unsigned num_faces = this->GetNumBoundaryFaces();
220
221 *p_face_file << num_faces << "\t";
223 *p_face_file << max_bdy_marker;
224 if (this->mFilesAreBinary)
225 {
226 *p_face_file << "\tBIN\n";
227 }
228 else
229 {
230 *p_face_file << "\n";
231 }
232
233 // Write each face's data
234 std::vector<double> default_marker(0);
235 for (unsigned item_num=0; item_num<num_faces; item_num++)
236 {
237 ElementData face_data = this->GetNextBoundaryElement();
238 WriteItem(p_face_file, item_num, face_data.NodeIndices, default_marker);
239 }
240 *p_face_file << comment << "\n";
241 p_face_file->close();
242
243 if (this->GetNumCableElements() > 0)
244 {
245 // Write cable element file
246 std::string cable_element_file_name = this->mBaseName + ".cable";
247 out_stream p_cable_element_file = this->mpOutputFileHandler->OpenOutputFile(cable_element_file_name, std::ios::binary | std::ios::trunc);
248
249 // Write the cable element header
250 unsigned num_cable_elements = this->GetNumCableElements();
252 num_attr = 1u; // We have a single region code - which is actually a radius
253
254 *p_cable_element_file << num_cable_elements << "\t";
255 *p_cable_element_file << 2 << "\t";
256 *p_cable_element_file << num_attr;
257 if (this->mFilesAreBinary)
258 {
259 *p_cable_element_file << "\tBIN\n";
260 }
261 else
262 {
263 *p_cable_element_file << "\n";
264 }
265
266 // Write each element's data
267 std::vector<double> attribute_values(1);
268 for (unsigned item_num=0; item_num<num_cable_elements; item_num++)
269 {
270 ElementData cable_element_data = this->GetNextCableElement();
271 attribute_values[0] = cable_element_data.AttributeValue;
272 WriteItem(p_cable_element_file, item_num, cable_element_data.NodeIndices, attribute_values);
273 }
274 *p_cable_element_file << comment;
275 p_cable_element_file->close();
276 }
277 }
278// PetscTools::Barrier("DodgyBarrierAfterFACE");
279 MeshEventHandler::EndEvent(MeshEventHandler::FACE);
280}
281
282template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
284{
285 std::string comment = "#\n# " + ChasteBuildInfo::GetProvenanceString();
286
287 std::string element_file_name = this->mBaseName;
288 if (ELEMENT_DIM == 1 && (SPACE_DIM == 2 || SPACE_DIM == 3))
289 {
290 element_file_name = element_file_name + ".edge";
291 }
292 else if (ELEMENT_DIM == 2 && SPACE_DIM == 3)
293 {
294 element_file_name = element_file_name + ".face";
295 }
296
297 out_stream p_element_file = this->mpOutputFileHandler->OpenOutputFile(element_file_name, std::ios::binary | std::ios::trunc);
298
299 // Write the element header
300 unsigned num_elements = this->GetNumElements();
301 assert(SPACE_DIM != ELEMENT_DIM); // LCOV_EXCL_LINE
302 unsigned num_attr = 1;
303
304 *p_element_file << num_elements << "\t";
305 //*p_element_file << nodes_per_element << "\t";
306 *p_element_file << num_attr;
307 if (this->mFilesAreBinary)
308 {
309 *p_element_file << "\tBIN\n";
310 }
311 else
312 {
313 *p_element_file << "\n";
314 }
315
316 // Write each element's data
317 std::vector<double> attribute_values(1);
318 for (unsigned item_num=0; item_num<num_elements; item_num++)
319 {
320 ElementData element_data = this->GetNextElement();
321 attribute_values[0] = element_data.AttributeValue;
322 WriteItem(p_element_file, item_num, element_data.NodeIndices, attribute_values);
323 }
324
325 *p_element_file << comment << "\n";
326 p_element_file->close();
327}
328
329template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
331{
332 std::string comment = "#\n# " + ChasteBuildInfo::GetProvenanceString();
333
334 if (ELEMENT_DIM == 1 && (SPACE_DIM == 2 || SPACE_DIM == 3))
335 {
336 return;
337 }
338
339 assert(SPACE_DIM == 3 && ELEMENT_DIM == 2); // LCOV_EXCL_LINE
340
341 std::string face_file_name = this->mBaseName;
342 face_file_name = face_file_name + ".edge";
343
344 out_stream p_face_file = this->mpOutputFileHandler->OpenOutputFile(face_file_name, std::ios::binary | std::ios::trunc);
345
346 // Write the boundary face header
347 unsigned num_faces = this->GetNumBoundaryFaces();
348
349 unsigned max_bdy_marker = 0;
350 std::vector<double> default_marker(0);
351
352 *p_face_file << num_faces << "\t";
353 *p_face_file << max_bdy_marker;
354 if (this->mFilesAreBinary)
355 {
356 *p_face_file << "\tBIN\n";
357 }
358 else
359 {
360 *p_face_file << "\n";
361 }
362
363 // Write each face's data
364 for (unsigned item_num=0; item_num<num_faces; item_num++)
365 {
366 ElementData face_data = this->GetNextBoundaryElement();
367 WriteItem(p_face_file, item_num, face_data.NodeIndices, default_marker);
368 }
369 *p_face_file << comment << "\n";
370 p_face_file->close();
371}
372
373template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
374template<class T_DATA>
375void TrianglesMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteItem(out_stream &pFile, unsigned itemNumber,
376 const std::vector<T_DATA> &dataPacket)
377{
378 //Writing with no attribute
379 //Instantiates the attribute variety with the attributes empty
380 WriteItem(pFile, itemNumber, dataPacket, std::vector<double>());
381}
382
383template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
384template<class T_DATA>
385void TrianglesMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteItem(out_stream &pFile, unsigned itemNumber,
386 const std::vector<T_DATA> &dataPacket,
387 const std::vector<double> &rAttributes)
388{
389 if (this->mFilesAreBinary)
390 {
391 // No item numbers
392 // Write raw data out of std::vector into the file
393 pFile->write((char*)&dataPacket[0], dataPacket.size()*sizeof(T_DATA));
394
395 // Write raw attribute(s)
396 // MSVC 10 will trip an assertion on accessing the 0th element if the vector is empty.
397 // Note that C++11 gives vectors a .data() method which would be a better way of doing this!
398 if (!rAttributes.empty())
399 {
400 pFile->write((char*)&rAttributes[0], rAttributes.size()*sizeof(double));
401 }
402 }
403 else
404 {
405 *pFile << itemNumber;
406 for (unsigned i=0; i<dataPacket.size(); i++)
407 {
408 *pFile << "\t" << dataPacket[i];
409 }
410 for (unsigned i=0; i<rAttributes.size(); i++)
411 {
412 *pFile << "\t" << rAttributes[i];
413 }
414 *pFile << "\n";
415 }
416}
417
418// Explicit instantiation
419template class TrianglesMeshWriter<1,1>;
420template class TrianglesMeshWriter<1,2>;
421template class TrianglesMeshWriter<1,3>;
422template class TrianglesMeshWriter<2,2>;
423template class TrianglesMeshWriter<2,3>;
424template class TrianglesMeshWriter<3,3>;
425
430template void TrianglesMeshWriter<1, 1>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
431template void TrianglesMeshWriter<1, 1>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
432template void TrianglesMeshWriter<1, 2>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
433template void TrianglesMeshWriter<1, 2>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
434template void TrianglesMeshWriter<1, 3>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
435template void TrianglesMeshWriter<1, 3>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
436template void TrianglesMeshWriter<2, 2>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
437template void TrianglesMeshWriter<2, 2>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
438template void TrianglesMeshWriter<2, 3>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
439template void TrianglesMeshWriter<2, 3>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
440template void TrianglesMeshWriter<3, 3>::WriteItem(out_stream &, unsigned, const std::vector<unsigned> &, const std::vector<double> & );
441template void TrianglesMeshWriter<3, 3>::WriteItem(out_stream &, unsigned, const std::vector<double> &, const std::vector<double> & );
static std::string GetProvenanceString()
TrianglesMeshWriter(const std::string &rDirectory, const std::string &rBaseName, const bool clearOutputDir=true)
void WriteItem(out_stream &pFile, unsigned itemNumber, const std::vector< T_DATA > &dataPacket, const std::vector< double > &rAttributes)
std::vector< unsigned > NodeIndices