Chaste Commit::fa89f2b838c1edb21a1eaec92ee3a2eacc9255dd
CmguiMeshWriter.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 "CmguiMeshWriter.hpp"
37
38#include <string>
39
40#include <boost/shared_ptr.hpp>
41
42#include "AbstractTetrahedralMesh.hpp"
43#include "DistributedTetrahedralMesh.hpp"
44#include "Exception.hpp"
45#include "FilesystemPermissions.hpp"
46#include "Version.hpp"
47
48template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
50 const std::string& rBaseName,
51 bool cleanDirectory)
52 : AbstractTetrahedralMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, cleanDirectory)
53{
54 this->mIndexFromZero = false;
55 mGroupName = this->mBaseName;
56
57 switch (ELEMENT_DIM)
58 {
59 case 1:
60 {
61 mElementFileHeader = CmguiElementFileHeader1D;
62 mCoordinatesFileHeader = CmguiCoordinatesFileHeader1D;
63 mAdditionalFieldHeader = CmguiAdditionalFieldHeader1D;
64 break;
65 }
66 case 2:
67 {
68 mElementFileHeader = CmguiElementFileHeader2D;
69 mCoordinatesFileHeader = CmguiCoordinatesFileHeader2D;
70 mAdditionalFieldHeader = CmguiAdditionalFieldHeader2D;
71 break;
72 }
73 case 3:
74 {
75 mElementFileHeader = CmguiElementFileHeader3D;
76 mCoordinatesFileHeader = CmguiCoordinatesFileHeader3D;
77 mAdditionalFieldHeader = CmguiAdditionalFieldHeader3D;
78 break;
79 }
80 default:
81 {
83 }
84 }
85
86
87 mNumNodesPerElement = ELEMENT_DIM+1;
89 for (unsigned i=0; i<mNumNodesPerElement; i++)
90 {
91 mReordering[i] = i;
92 }
93}
94
95template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
97{
99 // Write the exnode file
101 out_stream p_node_file = OpenNodeFile();
102 WriteNodeFileHeader(p_node_file);
103
104 // Write each node's data
105 for (unsigned item_num=0; item_num<this->GetNumNodes(); item_num++)
106 {
107 std::vector<double> current_item = this->GetNextNode();
108
109 *p_node_file << "Node:\t" << item_num+1 << "\t";
110 for (unsigned i=0; i<SPACE_DIM; i++)
111 {
112 *p_node_file << current_item[i] << "\t";
113 }
114
115 *p_node_file << "\n";
116 }
117 p_node_file->close();
118
120 // Write the exlem file
122
123 std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
124 WriteElementsFileHeader(elem_files);
125
126 // Write each elements's data
127 for (unsigned item_num=0; item_num<this->GetNumElements(); item_num++)
128 {
129 ElementData elem =this->GetNextElement();
130 std::vector<unsigned> current_element = elem.NodeIndices;
131
133 assert(elem.AttributeValue < mRegionNames.size());
134
135 *elem_files[elem.AttributeValue] << "Element:\t" << item_num+1 << " 0 0 Nodes:\t";
136 for (unsigned i=0; i<mNumNodesPerElement; i++)
137 {
138 *elem_files[elem.AttributeValue] << current_element[mReordering[i]]+1 << "\t";
139 }
140
141 *elem_files[elem.AttributeValue] << "\n";
142
143 }
144
145 for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
146 {
147 elem_files[region_index]->close();
148 }
149}
150
151template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
153{
154 mAdditionalFieldNames = rFieldNames;
155}
156
157template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
158void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetRegionNames(std::vector<std::string>& rRegionNames)
159{
160 mRegionNames = rRegionNames;
161}
162
163template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
165{
166 std::string node_file_name = this->mBaseName + ".exnode";
167 return this->mpOutputFileHandler->OpenOutputFile(node_file_name, GetOpenMode(append));
168}
169
170template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
171std::vector<boost::shared_ptr<std::ofstream> > CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::OpenElementFiles(bool append)
172{
173
174 std::vector<boost::shared_ptr<std::ofstream> > elem_files;
175 // If nobody defined region names we default to the same name as the file name.
176 if (mRegionNames.size() == 0)
177 {
178 mRegionNames.push_back(this->mBaseName);
179 }
180 elem_files.resize(mRegionNames.size());
181
182 std::string directory = this->mpOutputFileHandler->GetOutputDirectoryFullPath();
183 for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
184 {
185 std::string elem_file_name = mRegionNames[region_index] + ".exelem";
186 fs::path elem_file_path(directory);
187 elem_file_path /= elem_file_name;
188
189 boost::shared_ptr<std::ofstream> p_output_file(new std::ofstream(elem_file_path, GetOpenMode(append)));
190// LCOV_EXCL_START
191 if (!p_output_file->is_open())
192 {
193 EXCEPTION("Could not open file \"" + elem_file_name + "\" in " + directory);
194 }
195// LCOV_EXCL_STOP
197
198 // NOTE THAT one could simply do:
199 //
200 // elem_files[region_index] = this->mpOutputFileHandler->OpenOutputFile(elem_file_name, GetOpenMode(append));
201 //
202 // but that implies automatic conversion between std::shared_ptr to boost::shared_ptr.
203 // That is OK with most compilers, but the combination of gcc 4.1 and boost 1.33 complains about that
204 elem_files[region_index] = p_output_file;
205 }
206 return elem_files;
207}
208
209template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
211{
212 // Write provenance info
213 std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
214 *rpNodeFile << comment;
215
216 // Write the node header
217 *rpNodeFile << "Group name: " << this->mGroupName << "\n";
218 switch (SPACE_DIM)
219 {
220 case 1:
221 {
222 *rpNodeFile << CmguiNodeFileHeader1D;
223 break;
224 }
225 case 2:
226 {
227 *rpNodeFile << CmguiNodeFileHeader2D;
228 break;
229 }
230 case 3:
231 {
232 *rpNodeFile << CmguiNodeFileHeader3D;
233 break;
234 }
235 default:
236 {
238 }
239 }
240}
241
242template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
243void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteElementsFileHeader(std::vector<boost::shared_ptr<std::ofstream> >& rElemFiles)
244{
245
246 for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
247 {
248 // Write the elem header
249
250 //write provenance info
251 std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
252 *rElemFiles[region_index] << comment;
253
254 *rElemFiles[region_index] << "Group name: " << mGroupName << "\n";
255 *rElemFiles[region_index] << mElementFileHeader;
256
257 // Now we need to figure out how many additional fields we have
258 unsigned number_of_fields = mAdditionalFieldNames.size();
259 std::stringstream string_of_number_of_fields;
260
261 // We write the number of additional fields + 1 because the coordinates field gets written anyway...
262 string_of_number_of_fields << number_of_fields+1;
263
264 // ...and write accordingly the total number of fields
265 *rElemFiles[region_index] << " #Fields="<<string_of_number_of_fields.str()<<"\n";
266
267 // First field (the coordinates field is fixed and alwys there)
268 *rElemFiles[region_index] << mCoordinatesFileHeader;
269
270 // Now write the specification for each additional field
271 for (unsigned i = 0; i < number_of_fields; i++)
272 {
273 //unsigned to string
274 std::stringstream i_string;
275 i_string << i+2;
276 *rElemFiles[region_index]<<i_string.str()<<") "<<mAdditionalFieldNames[i]<<" ,";
277 *rElemFiles[region_index] << mAdditionalFieldHeader;
278 }
279 }
280}
281
282template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
284{
285 /*
286 * Node file
287 */
288 out_stream p_node_file = OpenNodeFile();
289 WriteNodeFileHeader(p_node_file);
290 p_node_file->close();
291
292 /*
293 * Element files
294 */
295 // Array with file descriptors for each of regions
296 std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
297 WriteElementsFileHeader(elem_files);
298 for (unsigned i = 0; i < elem_files.size(); i++)
299 {
300 elem_files[i]->close();
301 }
302}
303
304template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
306{
307 //Nodes first
308 out_stream p_node_file = OpenNodeFile(true);
309
310 typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
311
312 for (NodeIterType iter = this->mpDistributedMesh->GetNodeIteratorBegin();
313 iter != this->mpDistributedMesh->GetNodeIteratorEnd();
314 ++iter)
315 {
316 const c_vector<double, SPACE_DIM>& r_current_item = iter->rGetLocation();
317 *p_node_file << "Node:\t" << iter->GetIndex()+1 << "\t";
318
319 for (unsigned i=0; i<SPACE_DIM; i++)
320 {
321 *p_node_file << r_current_item[i] << "\t";
322 }
323
324 *p_node_file << "\n";
325 }
326 p_node_file->close();
327
328 //Now Element files
329
330 std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles(true);
332
333 for (ElemIterType iter = this->mpDistributedMesh->GetElementIteratorBegin();
334 iter != this->mpDistributedMesh->GetElementIteratorEnd();
335 ++iter)
336 {
337 if (this->mpDistributedMesh->CalculateDesignatedOwnershipOfElement(iter->GetIndex()))
338 {
339 assert(iter->GetUnsignedAttribute() < mRegionNames.size());//segfault guard
340
341 *elem_files[iter->GetUnsignedAttribute()] << "Element:\t" << iter->GetIndex()+1 << " 0 0 Nodes:\t";
342 for (unsigned i=0; i<this->mNodesPerElement; i++)
343 {
344 *elem_files[iter->GetUnsignedAttribute()] << iter->GetNodeGlobalIndex(i)+1 << "\t";
345 }
346
347 *elem_files[iter->GetUnsignedAttribute()] << "\n";
348 }
349 }
350
351 for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
352 {
353 elem_files[region_index]->close();
354 }
355
356}
357
358template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
360{
361 //No need of footers here, but void implementation is needed
362}
363
364template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
366{
367 std::ios_base::openmode mode = std::ios::out;
368 if (append)
369 {
370 mode |= std::ios::app; // Note: bitwise OR operation
371 }
372 else
373 {
374 mode |= std::ios::trunc;
375 }
376 return mode;
377}
378
379// Explicit instantiation
380template class CmguiMeshWriter<1,1>;
381template class CmguiMeshWriter<1,2>;
382template class CmguiMeshWriter<1,3>;
383template class CmguiMeshWriter<2,2>;
384template class CmguiMeshWriter<2,3>;
385template class CmguiMeshWriter<3,3>;
#define EXCEPTION(message)
#define NEVER_REACHED
static std::string GetProvenanceString()
std::string mElementFileHeader
void WriteElementsFileHeader(std::vector< boost::shared_ptr< std::ofstream > > &rElemFiles)
std::vector< boost::shared_ptr< std::ofstream > > OpenElementFiles(bool append=false)
std::ios_base::openmode GetOpenMode(bool append)
CmguiMeshWriter(const std::string &rDirectory, const std::string &rBaseName, bool cleanDirectory=true)
std::vector< unsigned > mReordering
void SetAdditionalFieldNames(std::vector< std::string > &rFieldNames)
std::string mAdditionalFieldHeader
void WriteNodeFileHeader(out_stream &rpNodeFile)
out_stream OpenNodeFile(bool append=false)
void SetRegionNames(std::vector< std::string > &rRegionNames)
std::string mCoordinatesFileHeader
static void SetFilePermissions(const fs::path &rPath)
std::vector< unsigned > NodeIndices