WSL/SLF GitLab Repository

IOUtils.h 14.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/***********************************************************************************/
/*  Copyright 2009 WSL Institute for Snow and Avalanche Research    SLF-DAVOS      */
/***********************************************************************************/
/* This file is part of MeteoIO.
    MeteoIO is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MeteoIO is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with MeteoIO.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IOUTILS_H__
#define __IOUTILS_H__

#include <meteoio/Coords.h>
#include <meteoio/Date.h>
#include <meteoio/IOExceptions.h>
24
#include <meteoio/meteolaws/Meteoconst.h>
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

#include <sstream>
#include <string>
#include <map>
#include <vector>
#include <list>
#include <cstdlib>
#include <iostream>
#include <cstdio>
#include <fstream>
#include <cctype>
#include <limits>

#ifndef MAX
#define MAX(x,y)    (((x) < (y)) ? (y) : (x))
#endif
#ifndef MIN
#define MIN(x,y)    (((x) < (y)) ? (x) : (y))
#endif

#ifndef C_TO_K
Fierz's avatar
Fierz committed
46
#define C_TO_K( T ) ( T + Cst::t_water_freezing_pt )	  // degree Celsius to kelvin
47
48
#endif
#ifndef K_TO_C
Fierz's avatar
Fierz committed
49
#define K_TO_C( T ) ( T - Cst::t_water_freezing_pt )	  // kelvin to degree Celsius
50
51
52
53
#endif

namespace mio {

54
55
56
57
#ifdef _MSC_VER
double round(const double& x);
#endif

58
59
class MeteoData;
class Coords;
60
class Config;
61

62
63
64
65
66
67
/**
* @brief Return the library version
* @return library version string
*/
std::string getLibVersion();

68
namespace IOUtils {
69
70
	const unsigned int nothrow = 0;
	const unsigned int dothrow = 1;
71
72
73
74
	const double nodata = -999.0; ///<This is the internal nodata value
	//const double not_set = std::numeric_limits<double>::max()-2.;
	const unsigned int unodata = (unsigned int)-1;
	const int inodata = -999;
75
	const short int snodata = -999;
76
	const size_t npos    = (size_t)-1;  ///<npos is the out-of-range value
77
78

	const double grid_epsilon = 5.; ///<What is an acceptable small distance on a grid, in meters
79
	const double lon_epsilon = grid_epsilon / Cst::earth_R0; ///<in degrees. Small angle for longitudes, so sin(x)=x
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
	const double lat_epsilon = lon_epsilon/2.; ///<in degrees. Small angle for latitudes. Since for longitudes it is for 360deg, it has to be 180deg for latitudes

	/**
	* @brief Check whether two values are equal regarding a certain epsilon environment (within certain radius of each other)
	* @param val1
	* @param val2
	* @param epsilon is a radius around val1
	* @return true if val2 is within the radius around val1, false otherwise.
	*/
	bool checkEpsilonEquality(const double& val1, const double& val2, const double& epsilon);

	double pow2(const double& val);
	double pow3(const double& val);
	double pow4(const double& val);

95
	size_t seek(const Date& soughtdate, const std::vector<MeteoData>& vecM, const bool& exactmatch=true);
96

97
98
99
100
101
102
103
104
	/**
	 * @brief Copies a files from one location to another
	 * @author Thomas Egger
	 * @param src  The filename of the file to be copied
	 * @param dest The filename of the file to copy to (will be created or overwritten)
	 */
	void copy_file(const std::string& src, const std::string& dest);

105
106
107
108
109
110
111
112
113
114
115
116
	/**
	* @brief Converts a compass bearing to a trigonometric angle
	* @param bearing compass bearing (0° on top, clockwise, in [0°, 360°[)
	* @return trigonometric angle (0° on the right, counterclockwise, in [0, 2PI[)
	*/
	double bearing_to_angle(const double& bearing);
	/**
	* @brief Converts a trigonometric angle to a compass bearing
	* @param angle trigonometric angle (0° on the right, counterclockwise, in [0, 2PI[)
	* @return bearing (0° on top, clockwise, in [0°, 360°[)
	*/
	double angle_to_bearing(const double& angle);
117
118
119
120
121
	/**
	* @brief Converts a string bearing to a compass bearing
	* @param bearing_str as N, NE, SSW, etc
	* @return bearing (0° on top, clockwise, in [0°, 360°[)
	*/
122
	double bearing(std::string bearing_str);
123

124
125
126
127
128
129
130
131
	/**
	* @brief Build a list of file in a given directory.
	* The matching is very primitive: it only looks for the substring "pattern" in the file names.
	* If this substrings exists, the file matches.
	* @param path directory containing the files
	* @param dirlist list of mathcing file names
	* @param pattern optional pattern that must be part of the file names
	*/
132
133
134
135
136
137
	void readDirectory(const std::string& path, std::list<std::string>& dirlist, const std::string& pattern = "");

	bool validFileName(const std::string& filename);

	bool fileExists(const std::string& filename);

138
139
140
141
142
143
144
	/**
	* @brief Retrieve the user name
	* This checks various environment variables (USERNAME, USER, LOGNAME).
	* @return user name
	*/
	std::string getLogName();

145
146
147
148
149
150
	/**
	* @brief Replace "\" by "/" in a string so that a path string is cross plateform
	* @param in_path the path string to cleanup
	*/
	std::string cleanPath(const std::string& in_path);

151
152
153
154
155
156
157
158
159
	/**
	* @brief returns the extension part of a given filename.
	* The extension is defined as all the non-whitespace characters after the last '.'
	* in the filename.
	* @param filename filename to extract the extension from
	* @return extension
	*/
	std::string getExtension(const std::string& filename);

160
161
162
163
164
165
166
167
168
	/**
	* @brief remove the extension part of a given filename.
	* The extension is defined as all the non-whitespace characters after the last '.'
	* in the filename.
	* @param filename filename to remove the extension from
	* @return filename without extension (the '.' is also removed)
	*/
	std::string removeExtension(const std::string& filename);

169
	/**
170
	* @brief Removes trailing and leading whitespaces, tabs and newlines from a string.
171
172
173
174
	* @param s The reference of the string to trim (in/out parameter)
	*/
	void trim(std::string &s);

175
176
	void stripComments(std::string& str);

177
178
	char getEoln(std::istream& fin);

179
	void skipLines(std::istream& fin, const size_t& nbLines, const char& eoln='\n');
180
181
182
183
184
185
186

	/**
	* @brief read a string line, parse it and save it into a map object, that is passed by reference
	* @param in_line (const string&) string to parse
	* @param delimiter (const string&) delimiter to use for the parsing
	* @param out_map (map\<string,string\>&) map after parsing
	* @param keyprefix this string is prefixed before the key, defaults to no prefix: ""
187
	* @param setToUpperCase If set to true the key will be put into upper case (for case insensitivity)
188
189
	* @return (bool) true when line is empty
	*/
190
191
192
193
	bool readKeyValuePair(const std::string& in_line,
	                      const std::string& delimiter,
	                      std::map<std::string,std::string>& out_map,
	                      const std::string& keyprefix="", const bool& setToUpperCase=false);
194
195

	void toUpper(std::string& str);
196
	void toLower(std::string& str);
197
	bool isNumeric(std::string input, const unsigned int& nBase=10);
198
	size_t readLineToVec(const std::string& line_in, std::vector<double>& vec_data);
199
200
	size_t readLineToVec(const std::string& line_in, std::vector<std::string>& vecString);
	size_t readLineToVec(const std::string& line_in, std::vector<std::string>& vecString, const char& delim);
201
202
	void readKeyValueHeader(std::map<std::string, std::string>& headermap,
	                        std::istream& bs,
203
	                        const size_t& linecount=1,
204
205
206
207
208
209
210
211
212
	                        const std::string& delimiter="=");


	/**
	* @brief Convert a string to the requested type (template function).
	* @tparam T   [in] The type wanted for the return value (template type parameter).
	* @param t   [out] The value converted to the requested type.
	* @param str   [in] The input string to convert; trailling whitespaces are ignored,
	*              comment after non-string values are allowed, but multiple values are not allowed.
213
214
215
216
	* @param f   [in] The radix for reading numbers, such as std::dec or std::oct; default is std::dec.
	* @return true if everything went fine, false otherwise
	*/
	template <class T> bool convertString(T& t, const std::string& str, std::ios_base& (*f)(std::ios_base&) = std::dec) {
217
		std::string s = str;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
		trim(s); //delete trailing and leading whitespaces and tabs
		if (s.size() == 0) {
			t = static_cast<T> (nodata);
			return true;
		} else {
			std::istringstream iss(s);
			iss.setf(std::ios::fixed);
			iss.precision(std::numeric_limits<double>::digits10); //try to read values with maximum precision
			iss >> f >> t; //Convert first part of stream with the formatter (e.g. std::dec, std::oct)
			if (iss.fail()) {
				//Conversion failed
				return false;
			}
			std::string tmp="";
			getline(iss,  tmp); //get rest of line, if any
			trim(tmp);
			if ((tmp.length() > 0) && tmp[0] != '#' && tmp[0] != ';') {
				//if line holds more than one value it's invalid
				return false;
			}
			return true;
		}
	}
	// fully specialized template functions (implementation must not be in header)
	template<> bool convertString<std::string>(std::string& t, const std::string& str, std::ios_base& (*f)(std::ios_base&));
	template<> bool convertString<bool>(bool& t, const std::string& str, std::ios_base& (*f)(std::ios_base&));
244
	template<> bool convertString<unsigned int>(unsigned int& t, const std::string& str, std::ios_base& (*f)(std::ios_base&));
245
246
	template<> bool convertString<Coords>(Coords& t, const std::string& str, std::ios_base& (*f)(std::ios_base&));

247
	bool convertString(Date& t, const std::string& str, const double& time_zone, std::ios_base& (*f)(std::ios_base&) = std::dec);
248

249
250
251
	/**
	* @brief Returns, with the requested type, the value associated to a key (template function).
	* @tparam T   [in] The type wanted for the return value (template type parameter).
252
253
254
255
	* @param[in]  properties  A map containing all the parameters.
	* @param[in]  key         The key of the parameter to retrieve.
	* @param[out] t           The value associated to the key, converted to the requested type
	* @param[in]  options     Extra options, by default IOUtils::dothrow
256
257
	*/
	template <class T> void getValueForKey(const std::map<std::string,std::string>& properties,
258
	                                       const std::string& key, T& t, const unsigned int& options=IOUtils::dothrow){
259
260
261
262
		if (key == "") {
			throw InvalidArgumentException("Empty key", AT);
		}

263
264
265
266
267
268
269
270
271
		//const std::string value = (const_cast<std::map<std::string,std::string>&>(properties))[key];
		//if (value == ""){} //The alternative way

		std::map<std::string, std::string>::const_iterator it;
		it = properties.find(key);

		if (it == properties.end()){
			if (options == IOUtils::nothrow)
				return;
272
			else
273
				throw UnknownValueException("No value for key " + key, AT);
274
		}
275
		const std::string value = it->second;
276
277

		if(!convertString<T>(t, value, std::dec)) {
Mathias Bavay's avatar
Mathias Bavay committed
278
			std::cerr << "[E] When reading \"" << key << "\" = \"" << t << "\"\n";
279
280
281
282
283
284
285
			throw ConversionFailedException(value, AT);
		}
	}

	/**
	* @brief Returns, with the requested type, the value associated to a key (template function).
	* @tparam T           [in] The type wanted for the return value (template type parameter).
286
287
	* @param[in]  properties  A map containing all the parameters.
	* @param[in]  key         The key of the parameter to retrieve.
288
	* @param[out] vecT        The vector of values associated to the key, each value is converted to the requested type
289
	* @param[in]  options     Extra options, by default IOUtils::dothrow
290
	*/
291
	template <class T> void getValueForKey(const std::map<std::string,std::string>& properties,
292
	                                       const std::string& key, std::vector<T>& vecT, const unsigned int& options=IOUtils::dothrow)
293
294
	{
		if (key == "") throw InvalidArgumentException("Empty key", AT);
295

296
297
298
		std::map<std::string, std::string>::const_iterator it = properties.find(key);
		if (it == properties.end()) {
			if (options == IOUtils::nothrow) {
299
				return;
300
			} else {
301
				throw UnknownValueException("No value for key " + key, AT);
302
			}
303
		}
304
		const std::string value = it->second;
305

306
		//split value string
307
		std::vector<std::string> vecUnconvertedValues;
308
309
		size_t counter = readLineToVec(value, vecUnconvertedValues);
		for (size_t ii=0; ii<counter; ii++){
310
311
			T myvar;
			if(!convertString<T>(myvar, vecUnconvertedValues.at(ii), std::dec)){
Mathias Bavay's avatar
Mathias Bavay committed
312
				std::cerr << "[E] When reading \"" << key << "\" = \"" << myvar << "\"\n";
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
				throw ConversionFailedException(vecUnconvertedValues.at(ii), AT);
			}
			vecT.push_back(myvar);
		}
	}

	/**
	* @brief Standardize a given value to use MeteoIO's internal nodata value (if applicable)
	* @tparam T           [in] The type wanted for the return value (template type parameter).
	* @param[in] value  the value to check/convert
	* @param[in] plugin_nodata plugin-specific nodata value
	* @return checked/converted value
	*/
	template <class T> T standardizeNodata(const T& value, const double& plugin_nodata) {
		if(value==plugin_nodata) return static_cast<T> (nodata);
		else return value;
	}

	/**
332
	* @brief A function that parses a Config object for COORSYS, COORDPARAM keywords in [Input] and [Output]
333
	*        section and sets the respective strings to the values of those keywords
334
	* @param[in] cfg  A Config object
335
336
337
338
339
	* @param[out] coordin The coordinate system to be used for input data
	* @param[out] coordinparam The coordinate system parameters to be used for output data
	* @param[out] coordout The coordinate system to be used for output data
	* @param[out] coordoutparam The coordinate system parameters to be used for output data
	*/
340
	void getProjectionParameters(const Config& cfg, std::string& coordin, std::string& coordinparam,
341
	                             std::string& coordout, std::string& coordoutparam);
342
343

	/**
344
	* @brief A function that parses a Config object for the time_zone keyword and returns the timezone
345
	* @param[in] cfg  A Config object
346
347
348
	* @param[out] tz_in value to be used for the input timezone
	* @param[out] tz_out value to be used for the output timezone
	*/
349
	void getTimeZoneParameters(const Config& cfg, double& tz_in, double& tz_out);
350

351
352
353
354
355
356
357
	/**
	* @brief Nicely format an hour given as fractional day into a human readable hour.
	* @param fractional fractional day (ie: fractional part of a julian date)
	* @return string containing a human readable time
	*/
	std::string printFractionalDay(const double& fractional);

358
359
360
361
362
363
	/**
	* @brief Returns the parameters for splitting an array in several, balanced sub-arrays.
	* This is mostly usefull for parallel calculations, where an array will be split and sent to different
	* workers.
	* @param[in] dimx number of cells in the desired dimension
	* @param[in] nbworkers total number of slices
364
	* @param[in] wk current slice index (starting at 1)
365
366
367
368
369
	* @param[out] startx calculated start index for the current slice
	* @param[out] nx calculated number of cells (in the desired dimension) of the current slice
	*/
	void getArraySliceParams(const unsigned int& dimx, const unsigned int& nbworkers, const unsigned int &wk, unsigned int& startx, unsigned int& nx);

370
} //end namespace IOUtils
371

372
373
374
} //end namespace mio

#endif