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