Chaste  Release::2017.1
FibreReader.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 
36 #include "FibreReader.hpp"
37 
38 #include <sstream>
39 #include "Exception.hpp"
40 
41 template<unsigned DIM>
42 FibreReader<DIM>::FibreReader(const FileFinder& rFileFinder, FibreFileType fibreFileType)
43  : mFileIsBinary(false), // overwritten by ReadNumLinesOfDataFromFile() if applicable.
44  mNextIndex(0u)
45 {
46  if (fibreFileType == AXISYM)
47  {
48  mNumItemsPerLine = DIM;
49  }
50  else //(fibreFileType == ORTHO)
51  {
52  mNumItemsPerLine = DIM*DIM;
53  }
54  mTokens.resize(mNumItemsPerLine);
55 
56  mFilePath = rFileFinder.GetAbsolutePath();
57  mDataFile.open(mFilePath.c_str());
58  if (!mDataFile.is_open())
59  {
60  EXCEPTION("Failed to open fibre file " + rFileFinder.GetAbsolutePath());
61  }
62 
63  // Note: this method will close the file on error
65 }
66 
67 template<unsigned DIM>
69 {
70  mDataFile.close();
71 }
72 
73 template<unsigned DIM>
74 void FibreReader<DIM>::GetAllAxi(std::vector< c_vector<double, DIM> >& direction)
75 {
76  assert(direction.empty());
77  if (mNumItemsPerLine != DIM)
78  {
79  EXCEPTION("Use GetAllOrtho when reading orthotropic fibres");
80  }
81  direction.reserve(mNumLinesOfData);
82  for (unsigned i=0; i<mNumLinesOfData; i++)
83  {
84  c_vector<double, DIM> temp_vector;
85  GetFibreVector(i, temp_vector, false);
86  direction.push_back(temp_vector);
87  }
88 }
89 
90 template<unsigned DIM>
91 void FibreReader<DIM>::GetAllOrtho(std::vector< c_vector<double, DIM> >& first_direction,
92  std::vector< c_vector<double, DIM> >& second_direction,
93  std::vector< c_vector<double, DIM> >& third_direction)
94 {
95  assert(first_direction.empty());
96  assert(second_direction.empty());
97  assert(third_direction.empty());
98  if (mNumItemsPerLine != DIM*DIM)
99  {
100  EXCEPTION("Use GetAllAxi when reading axisymmetric fibres");
101  }
102  for (unsigned i=0; i<mNumLinesOfData; i++)
103  {
104  c_matrix<double, DIM, DIM> temp_matrix;
105  GetFibreSheetAndNormalMatrix(i, temp_matrix, true);
106 
107  //Note that although the matrix appears row-wise in the ascii .ortho file,
108  //for convenience it is stored column-wise.
109  matrix_column<c_matrix<double, DIM, DIM> > col0(temp_matrix, 0);
110  first_direction.push_back(col0);
111  if (DIM>=2)
112  {
113  matrix_column<c_matrix<double, DIM, DIM> > col1(temp_matrix, 1);
114  second_direction.push_back(col1);
115  }
116  if (DIM==3)
117  {
118  matrix_column<c_matrix<double, DIM, DIM> > col2(temp_matrix, 2);
119  third_direction.push_back(col2);
120  }
121  }
122 }
123 
124 template<unsigned DIM>
126  c_matrix<double,DIM,DIM>& rFibreMatrix,
127  bool checkOrthogonality)
128 {
129  if (mNumItemsPerLine != DIM*DIM)
130  {
131  EXCEPTION("Use GetFibreVector when reading axisymmetric fibres");
132  }
133  if (fibreIndex < mNextIndex)
134  {
135  EXCEPTION("Fibre reads must be monotonically increasing; " << fibreIndex
136  << " is before expected next index " << mNextIndex);
137  }
138  if (mFileIsBinary)
139  {
140 
141  // Skip to the desired index
142  mDataFile.seekg((fibreIndex-mNextIndex)*mNumItemsPerLine*sizeof(double), std::ios::cur);
143  // Take mNumItemsPerLine from the ifstream
144  mDataFile.read((char*)&(rFibreMatrix(0,0)), mNumItemsPerLine*sizeof(double));
145  mNextIndex = fibreIndex+1;
146  }
147  else
148  {
149  unsigned num_entries = 0u;
150  while (fibreIndex >= mNextIndex)
151  {
152  num_entries = GetTokensAtNextLine();
153  mNextIndex++;
154  }
155  if (num_entries < mNumItemsPerLine)
156  {
157  EXCEPTION("A line is incomplete in " << mFilePath
158  << " - each line should contain " << DIM*DIM << " entries");
159  }
160  for (unsigned i=0; i<DIM; i++)
161  {
162  for (unsigned j=0; j<DIM; j++)
163  {
164  rFibreMatrix(i,j) = mTokens[DIM*i + j];
165  }
166  }
167  }
168 
169  // The binary file and ascii file are row-major. However, we store column major matrices.
170  rFibreMatrix = trans(rFibreMatrix);
171 
172  if (checkOrthogonality)
173  {
174  // Note that we define this matrix before setting it as otherwise the profiling build will break (see #2367)
175  c_matrix<double,DIM,DIM> temp;
176  temp = prod(trans(rFibreMatrix), rFibreMatrix);
177 
178  // Check temp is equal to the identity
179  for (unsigned i=0; i<DIM; i++)
180  {
181  for (unsigned j=0; j<DIM; j++)
182  {
183  double val = (i==j ? 1.0 : 0.0);
184 
185  if (fabs(temp(i,j)-val) > 1e-4)
186  {
187  EXCEPTION("Read fibre-sheet matrix, " << rFibreMatrix << " from file "
188  << " which is not orthogonal (tolerance 1e-4)");
189  }
190  }
191  }
192  }
193 }
194 
195 template<unsigned DIM>
196 void FibreReader<DIM>::GetFibreVector(unsigned fibreIndex,
197  c_vector<double,DIM>& rFibreVector,
198  bool checkNormalised)
199 {
200  if (mNumItemsPerLine != DIM)
201  {
202  EXCEPTION("Use GetFibreSheetAndNormalMatrix when reading orthotropic fibres");
203  }
204  if (fibreIndex < mNextIndex)
205  {
206  EXCEPTION("Fibre reads must be monotonically increasing; " << fibreIndex
207  << " is before expected next index " << mNextIndex);
208  }
209 
210  if (mFileIsBinary)
211  {
212  // Skip to the desired index
213  mDataFile.seekg((fibreIndex-mNextIndex)*mNumItemsPerLine*sizeof(double), std::ios::cur);
214  // Take mNumItemsPerLine from the ifstream
215  mDataFile.read((char*)&rFibreVector[0], mNumItemsPerLine*sizeof(double));
216  mNextIndex = fibreIndex+1;
217  }
218  else
219  {
220  unsigned num_entries = 0u;
221  while (fibreIndex >= mNextIndex)
222  {
223  num_entries = GetTokensAtNextLine();
224  mNextIndex++;
225  }
226  if (num_entries < mNumItemsPerLine)
227  {
228  EXCEPTION("A line is incomplete in " << mFilePath
229  << " - each line should contain " << DIM << " entries");
230  }
231  for (unsigned i=0; i<DIM; i++)
232  {
233  rFibreVector(i) = mTokens[i];
234  }
235  }
236 
237 
238  if (checkNormalised && fabs(norm_2(rFibreVector)-1)>1e-4)
239  {
240  EXCEPTION("Read vector " << rFibreVector << " from file "
241  << mFilePath << " which is not normalised (tolerance 1e-4)");
242  }
243 }
244 
245 template<unsigned DIM>
247 {
248  assert(mTokens.size() == mNumItemsPerLine);
249 
250  std::string line;
251  bool blank_line;
252 
253  do
254  {
255  getline(mDataFile, line);
256 
257  if (line.empty() && mDataFile.eof())
258  {
259  mDataFile.close();
260  std::string error = "End of file " + mFilePath + " reached. Either file contains fewer "
261  + "definitions than defined in header, or one of the GetNext[..] methods "
262  + "has been called too often";
263  EXCEPTION(error);
264  }
265 
266  // Get rid of any comments
267  line = line.substr(0, line.find('#'));
268 
269  blank_line = (line.find_first_not_of(" \t",0) == std::string::npos);
270  }
271  while (blank_line);
272 
273  // Get rid of any trailing whitespace
274  std::string::iterator iter = line.end();
275  iter--;
276  unsigned nchars2delete = 0;
277  while (*iter == ' ' || *iter == '\t')
278  {
279  nchars2delete++;
280  iter--;
281  }
282  line.erase(line.length()-nchars2delete);
283 
284  std::stringstream line_stream(line);
285 
286  unsigned index = 0;
287  while (!line_stream.eof())
288  {
289  double item;
290  line_stream >> item;
291  if (index >= mNumItemsPerLine)
292  {
293  EXCEPTION("Too many entries in a line in " + mFilePath);
294  }
295  mTokens[index++] = item;
296  }
297 
298  return index; // the number of entries put into mTokens
299 }
300 
301 template<unsigned DIM>
303 {
304  std::string raw_line;
305  bool blank_line = false;
306  do
307  {
308  getline(mDataFile, raw_line);
309  //Strip comments following a hash
310  raw_line = raw_line.substr(0, raw_line.find('#'));
311  //Check for blank line
312  blank_line = (raw_line.find_first_not_of(" \t",0) == std::string::npos);
313  }
314  while (blank_line);
315 
316  std::stringstream header_line(raw_line);
317 
318  header_line >> mNumLinesOfData;
319 
320  std::string extras;
321  header_line >> extras;
322 
323  if (extras == "BIN")
324  {
325  mFileIsBinary = true;
326  }
327  else if (extras!="")
328  {
329  mDataFile.close();
330  EXCEPTION("First (non comment) line of the fibre orientation file should contain the number of lines of data in the file (and possibly a BIN tag) at most");
331  }
332 }
333 
334 template class FibreReader<1>;
335 template class FibreReader<2>;
336 template class FibreReader<3>;
FibreReader(const FileFinder &rFileFinder, FibreFileType fibreFileType)
Definition: FibreReader.cpp:42
std::ifstream mDataFile
Definition: FibreReader.hpp:65
unsigned mNumLinesOfData
Definition: FibreReader.hpp:71
std::string GetAbsolutePath() const
Definition: FileFinder.cpp:221
#define EXCEPTION(message)
Definition: Exception.hpp:143
void ReadNumLinesOfDataFromFile()
bool mFileIsBinary
Definition: FibreReader.hpp:73
unsigned GetTokensAtNextLine()
std::string mFilePath
Definition: FibreReader.hpp:68
std::vector< double > mTokens
Definition: FibreReader.hpp:82
unsigned mNumItemsPerLine
Definition: FibreReader.hpp:76
void GetFibreVector(unsigned fibreIndex, c_vector< double, DIM > &rFibreVector, bool checkNormalised=true)
void GetAllAxi(std::vector< c_vector< double, DIM > > &direction)
Definition: FibreReader.cpp:74
unsigned mNextIndex
Definition: FibreReader.hpp:79
void GetAllOrtho(std::vector< c_vector< double, DIM > > &first_direction, std::vector< c_vector< double, DIM > > &second_direction, std::vector< c_vector< double, DIM > > &third_direction)
Definition: FibreReader.cpp:91
void GetFibreSheetAndNormalMatrix(unsigned fibreIndex, c_matrix< double, DIM, DIM > &rFibreMatrix, bool checkOrthogonality=true)