CSV.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "CSV.H"
27 #include "DynamicList.H"
28 #include "IFstream.H"
29 
30 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
31 
32 template<>
34 (
35  const List<string>& splitted
36 )
37 {
38  if (componentColumns_[0] >= splitted.size())
39  {
41  << "No column " << componentColumns_[0] << " in "
42  << splitted << endl
43  << exit(FatalError);
44  }
45 
46  return readLabel(IStringStream(splitted[componentColumns_[0]])());
47 }
48 
49 
50 template<>
52 (
53  const List<string>& splitted
54 )
55 {
56  if (componentColumns_[0] >= splitted.size())
57  {
59  << "No column " << componentColumns_[0] << " in "
60  << splitted << endl
61  << exit(FatalError);
62  }
63 
64  return readScalar(IStringStream(splitted[componentColumns_[0]])());
65 }
66 
67 
68 template<class Type>
69 Type Foam::Function1Types::CSV<Type>::readValue(const List<string>& splitted)
70 {
71  Type result;
72 
73  for (label i = 0; i < pTraits<Type>::nComponents; i++)
74  {
75  if (componentColumns_[i] >= splitted.size())
76  {
78  << "No column " << componentColumns_[i] << " in "
79  << splitted << endl
80  << exit(FatalError);
81  }
82 
83  result[i] =
84  readScalar(IStringStream(splitted[componentColumns_[i]])());
85  }
86 
87  return result;
88 }
89 
90 
91 template<class Type>
93 {
94  fileName expandedFile(fName_);
95  IFstream is(expandedFile.expand());
96 
97  if (!is.good())
98  {
100  << "Cannot open CSV file for reading."
101  << exit(FatalIOError);
102  }
103 
104  DynamicList<Tuple2<scalar, Type>> values;
105 
106  // skip header
107  for (label i = 0; i < nHeaderLine_; i++)
108  {
109  string line;
110  is.getLine(line);
111  }
112 
113  label nEntries = max(componentColumns_);
114 
115  // read data
116  while (is.good())
117  {
118  string line;
119  is.getLine(line);
120 
121 
122  label n = 0;
123  std::size_t pos = 0;
124  DynamicList<string> splitted;
125 
126  if (mergeSeparators_)
127  {
128  std::size_t nPos = 0;
129 
130  while ((pos != std::string::npos) && (n <= nEntries))
131  {
132  bool found = false;
133  while (!found)
134  {
135  nPos = line.find(separator_, pos);
136 
137  if ((nPos != std::string::npos) && (nPos - pos == 0))
138  {
139  pos = nPos + 1;
140  }
141  else
142  {
143  found = true;
144  }
145  }
146 
147  nPos = line.find(separator_, pos);
148 
149  if (nPos == std::string::npos)
150  {
151  splitted.append(line.substr(pos));
152  pos = nPos;
153  n++;
154  }
155  else
156  {
157  splitted.append(line.substr(pos, nPos - pos));
158  pos = nPos + 1;
159  n++;
160  }
161  }
162  }
163  else
164  {
165  while ((pos != std::string::npos) && (n <= nEntries))
166  {
167  std::size_t nPos = line.find(separator_, pos);
168 
169  if (nPos == std::string::npos)
170  {
171  splitted.append(line.substr(pos));
172  pos = nPos;
173  n++;
174  }
175  else
176  {
177  splitted.append(line.substr(pos, nPos - pos));
178  pos = nPos + 1;
179  n++;
180  }
181  }
182  }
183 
184 
185  if (splitted.size() <= 1)
186  {
187  break;
188  }
189 
190  scalar x = readScalar(IStringStream(splitted[refColumn_])());
191  Type value = readValue(splitted);
192 
193  values.append(Tuple2<scalar,Type>(x, value));
194  }
195 
196  this->table_.transfer(values);
197 }
198 
199 
200 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
201 
202 template<class Type>
204 (
205  const word& entryName,
206  const dictionary& dict,
207  const word& ext
208 )
209 :
210  TableBase<Type>(entryName, dict.subDict(entryName + ext)),
211  coeffs_(dict.subDict(entryName + ext)),
212  nHeaderLine_(readLabel(coeffs_.lookup("nHeaderLine"))),
213  refColumn_(readLabel(coeffs_.lookup("refColumn"))),
214  componentColumns_(coeffs_.lookup("componentColumns")),
215  separator_(coeffs_.lookupOrDefault<string>("separator", string(","))[0]),
216  mergeSeparators_(readBool(coeffs_.lookup("mergeSeparators"))),
217  fName_(coeffs_.lookup("fileName"))
218 {
219  if (componentColumns_.size() != pTraits<Type>::nComponents)
220  {
222  << componentColumns_ << " does not have the expected length of "
224  << exit(FatalError);
225  }
226 
227  read();
228 
230 }
231 
232 
233 template<class Type>
235 :
236  TableBase<Type>(tbl),
237  nHeaderLine_(tbl.nHeaderLine_),
238  refColumn_(tbl.refColumn_),
239  componentColumns_(tbl.componentColumns_),
240  separator_(tbl.separator_),
241  mergeSeparators_(tbl.mergeSeparators_),
242  fName_(tbl.fName_)
243 {}
244 
245 
246 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
247 
248 template<class Type>
250 {}
251 
252 
253 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
254 
255 template<class Type>
257 {
258  return fName_;
259 }
260 
261 
262 template<class Type>
264 {
266  os << token::END_STATEMENT << nl;
267  os << indent << word(this->name() + "Coeffs") << nl;
268  os << indent << token::BEGIN_BLOCK << incrIndent << nl;
269 
270  // Note: for TableBase write the dictionary entries it needs but not
271  // the values themselves
273 
274  os.writeKeyword("nHeaderLine") << nHeaderLine_ << token::END_STATEMENT
275  << nl;
276  os.writeKeyword("refColumn") << refColumn_ << token::END_STATEMENT << nl;
277 
278  // Force writing labelList in ascii
279  os.writeKeyword("componentColumns");
280  if (os.format() == IOstream::BINARY)
281  {
283  os << componentColumns_;
285  }
286  else
287  {
288  os << componentColumns_;
289  }
290  os << token::END_STATEMENT << nl;
291 
292  os.writeKeyword("separator") << string(separator_)
293  << token::END_STATEMENT << nl;
294  os.writeKeyword("mergeSeparators") << mergeSeparators_
295  << token::END_STATEMENT << nl;
296  os.writeKeyword("fileName") << fName_ << token::END_STATEMENT << nl;
297  os << decrIndent << indent << token::END_BLOCK << endl;
298 }
299 
300 
301 // ************************************************************************* //
#define readScalar
Definition: doubleScalar.C:38
streamFormat format() const
Return current stream format.
Definition: IOstream.H:377
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
A class for handling file names.
Definition: fileName.H:69
const word & name() const
Return the name of the entry.
Definition: Function1.C:56
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:223
virtual void writeEntries(Ostream &os) const
Write keywords only in dictionary format. Used for non-inline.
Definition: TableBase.C:410
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
virtual const fileName & fName() const
Return const access to the file name.
Definition: CSV.C:256
Templated CSV container data entry. Reference column is always a scalar, e.g. time.
Definition: CSV.H:71
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
CSV(const word &entryName, const dictionary &dict, const word &ext="Coeffs")
Construct from entry name and dictionary.
Definition: CSV.C:204
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:633
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
Traits class for primitives.
Definition: pTraits.H:50
bool readBool(Istream &)
Definition: boolIO.C:60
virtual void writeData(Ostream &os) const
Write in dictionary format.
Definition: Function1.C:121
virtual void writeData(Ostream &os) const
Write in dictionary format.
Definition: CSV.C:263
bool read(const char *, int32_t &)
Definition: int32IO.C:85
Base class for table with bounds handling, interpolation and integration.
Definition: TableBase.H:55
A class for handling words, derived from string.
Definition: word.H:59
label readLabel(Istream &is)
Definition: label.H:64
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
static const char nl
Definition: Ostream.H:262
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:237
Ostream & writeKeyword(const keyType &)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:54
virtual ~CSV()
Destructor.
Definition: CSV.C:249
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:230
A class for handling character strings derived from std::string.
Definition: string.H:74
IOerror FatalIOError