Chaste  Release::2017.1
CmguiMeshWriter.cpp
1 /*
2 
3 Copyright (c) 2005-2017, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, 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 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 #include "Exception.hpp"
36 #include "CmguiMeshWriter.hpp"
37 #include "Version.hpp"
38 #include <boost/shared_ptr.hpp>
39 
40 #include "AbstractTetrahedralMesh.hpp"
41 #include "DistributedTetrahedralMesh.hpp"
42 
44 // Implementation
46 
47 template<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 
94 template<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 
150 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
151 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetAdditionalFieldNames(std::vector<std::string>& rFieldNames)
152 {
153  mAdditionalFieldNames = rFieldNames;
154 }
155 
156 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
157 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetRegionNames(std::vector<std::string>& rRegionNames)
158 {
159  mRegionNames = rRegionNames;
160 }
161 
162 template<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 
169 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
170 std::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 
205 template<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 
238 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
239 void 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 
278 template<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 
300 template<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 
354 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
356 {
357  //No need of footers here, but void implementation is needed
358 }
359 
360 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
361 std::ios_base::openmode CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetOpenMode(bool append)
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
376 template class CmguiMeshWriter<1,1>;
377 template class CmguiMeshWriter<1,2>;
378 template class CmguiMeshWriter<1,3>;
379 template class CmguiMeshWriter<2,2>;
380 template class CmguiMeshWriter<2,3>;
381 template class CmguiMeshWriter<3,3>;
std::string mAdditionalFieldHeader
out_stream OpenNodeFile(bool append=false)
#define EXCEPTION(message)
Definition: Exception.hpp:143
void SetRegionNames(std::vector< std::string > &rRegionNames)
virtual unsigned GetNumNodes()
OutputFileHandler * mpOutputFileHandler
std::string mCoordinatesFileHeader
std::string GetOutputDirectoryFullPath() const
#define NEVER_REACHED
Definition: Exception.hpp:206
std::vector< boost::shared_ptr< std::ofstream > > OpenElementFiles(bool append=false)
void WriteElementsFileHeader(std::vector< boost::shared_ptr< std::ofstream > > &rElemFiles)
std::vector< unsigned > NodeIndices
std::vector< std::string > mRegionNames
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
std::ios_base::openmode GetOpenMode(bool append)
DistributedTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpDistributedMesh
std::string mElementFileHeader
unsigned mNumNodesPerElement
std::vector< unsigned > mReordering
std::string mGroupName
void SetAdditionalFieldNames(std::vector< std::string > &rFieldNames)
std::vector< std::string > mAdditionalFieldNames
static std::string GetProvenanceString()
CmguiMeshWriter(const std::string &rDirectory, const std::string &rBaseName, bool cleanDirectory=true)
void WriteNodeFileHeader(out_stream &rpNodeFile)