Chaste Commit::1fd4e48e3990e67db148bc1bc4cf6991a0049d0c
FibreReader.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 "FibreReader.hpp"
37
38#include <sstream>
39#include "Exception.hpp"
40
41template<unsigned DIM>
42FibreReader<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 }
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
67template<unsigned DIM>
69{
70 mDataFile.close();
71}
72
73template<unsigned DIM>
74void 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}
90template<unsigned DIM>
91void 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
124template<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 }
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 = zero_matrix<double>(DIM, DIM);
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
195template<unsigned DIM>
196void 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
245template<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
301template<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
334template class FibreReader<1>;
335template class FibreReader<2>;
336template class FibreReader<3>;
#define EXCEPTION(message)
std::vector< double > mTokens
void GetFibreVector(unsigned fibreIndex, c_vector< double, DIM > &rFibreVector, bool checkNormalised=true)
unsigned GetTokensAtNextLine()
void GetAllAxi(std::vector< c_vector< double, DIM > > &direction)
std::string mFilePath
unsigned mNumItemsPerLine
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)
FibreReader(const FileFinder &rFileFinder, FibreFileType fibreFileType)
void GetFibreSheetAndNormalMatrix(unsigned fibreIndex, c_matrix< double, DIM, DIM > &rFibreMatrix, bool checkOrthogonality=true)
void ReadNumLinesOfDataFromFile()
std::ifstream mDataFile
std::string GetAbsolutePath() const