WSL/SLF GitLab Repository

SMETIO.cc 24.9 KB
Newer Older
1
/***********************************************************************************/
2
/*  Copyright 2010 WSL Institute for Snow and Avalanche Research    SLF-DAVOS      */
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/***********************************************************************************/
/* 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/>.
*/
18
#include "SMETIO.h"
19
20
21
22
23

using namespace std;

namespace mio {
/**
24
 * @page smetio SMET
25
 * @section template_format Format
26
 * The Station METeo data files is a station centered, ascii file format that has been designed with flexibility and ease of use in mind. Please refer to its <a href="../SMET_specifications.pdf">official format specification</a> for more information.
27
28
 *
 * @section template_units Units
29
 * All units are MKSA, the only exception being the precipitations that are in mm/h. It is however possible to use  multipliers and offsets (but they must be specified in the file header).
30
31
32
 *
 * @section template_keywords Keywords
 * This plugin uses the following keywords:
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * - METEOFILE#: input filename and path. As many meteofiles as needed may be specified
 * - METEOPATH: output directory where to write the output meteofiles
 * - METEOPARAM: output file format options (ASCII or BINARY that might be followed by GZIP)
 *
 * Example:
 * @code
 * [Input]
 * METEOFILE1 = ./input/uppper_station.smet
 * METEOFILE2 = ./input/lower_station.smet
 * METEOFILE3 = ./input/outlet_station.smet
 * [Output]
 * METEOPATH = ./output
 * METEOPARAM = ASCII GZIP
 * @endcode
47
48
 */

49
const std::string SMETIO::smet_version = "0.99";
50
51
map<string, MeteoData::Parameters> SMETIO::mapParameterByName;
const bool SMETIO::__init = SMETIO::initStaticData();
52

53
bool SMETIO::initStaticData()
54
55
56
57
58
59
60
61
{
	for (unsigned int ii=0; ii<MeteoData::nrOfParameters; ii++){
		mapParameterByName[MeteoData::getParameterName(ii)] = MeteoData::Parameters(ii);
	}

	return true;
}

62
double& SMETIO::getParameter(const std::string& columnName, MeteoData& md)
63
64
65
66
67
68
69
70
71
72
{//HACK: the whole name mapping is a big hack. Replace with proper mapping!!!
	if(columnName=="OSWR") {
		MeteoData::Parameters paramindex = mapParameterByName["RSWR"];
		return md.param(paramindex);
	}
	if(columnName=="PSUM") {
		MeteoData::Parameters paramindex = mapParameterByName["RSWR"];
		return md.param(paramindex);
	}

73
74
75
76
	MeteoData::Parameters paramindex = mapParameterByName[columnName];
	return md.param(paramindex);
}

77
void SMETIO::checkColumnNames(const std::vector<std::string>& vecColumns, const bool& locationInHeader)
78
{
79
80
81
82
	/*
	 * This function checks whether the sequence of keywords specified in the 
	 * [HEADER] section (key 'fields') is valid
	 */
83
84
85
	vector<unsigned int> paramcounter = vector<unsigned int>(MeteoData::nrOfParameters, 0);

	for (unsigned int ii=0; ii<vecColumns.size(); ii++){
86
87
88
89
90
91
92
93
		std::string column = vecColumns[ii];

		//column names mapping
		if(column=="OSWR") column="RSWR";
		if(column=="PSUM") column="HNW";

		if ((column == "timestamp") || (column == "longitude")
		    || (column == "latitude") || (column == "altitude")){
94
95
			//everything ok
		} else {
96
			map<string, MeteoData::Parameters>::iterator it = mapParameterByName.find(column);
97
98
99
			if (it == mapParameterByName.end())
				throw InvalidFormatException("Key 'fields' specified in [HEADER] section contains invalid names", AT);
			
100
			paramcounter.at(mapParameterByName[column])++;
101
102
		}
	}
103
104
	
	//Check for multiple usages of parameters
105
106
107
108
109
	for (unsigned int ii=0; ii<paramcounter.size(); ii++){
		if (paramcounter[ii] > 1)
			throw InvalidFormatException("In 'fields': Multiple use of " + MeteoData::getParameterName(ii), AT);
	}
	
110
111
	//If there is no location information in the [HEADER] section, then
	//location information must be part of fields
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
	if (!locationInHeader){
		unsigned int latcounter = 0, loncounter=0, altcounter=0;
		for (unsigned int ii=0; ii<vecColumns.size(); ii++){
			if (vecColumns[ii] == "longitude")
				loncounter++;
			else if (vecColumns[ii] == "latitude")
				latcounter++;
			else if (vecColumns[ii] == "altitude")
				altcounter++;
		}

		if ((latcounter != loncounter) && (loncounter != altcounter) && (altcounter != 1))
			throw InvalidFormatException("Key 'fields' must contain 'latitude', 'longitude' and 'altitude'", AT);
	}
}

//END STATIC SECTION


131
SMETIO::SMETIO(void (*delObj)(void*), const ConfigReader& i_cfg) : IOInterface(delObj), cfg(i_cfg)
132
133
134
135
{
	parseInputOutputSection();
}

136
SMETIO::SMETIO(const std::string& configfile) : IOInterface(NULL), cfg(configfile)
137
138
139
140
{
	parseInputOutputSection();
}

141
SMETIO::SMETIO(const ConfigReader& cfgreader) : IOInterface(NULL), cfg(cfgreader)
142
143
144
145
{
	parseInputOutputSection();
}

146
SMETIO::~SMETIO() throw()
147
148
149
150
{
	cleanup();
}

151
void SMETIO::cleanup() throw()
152
{
153
154
155
	//clear ios flags
	fout << resetiosflags(ios_base::fixed | ios_base::left);

156
157
158
159
160
161
162
163
	if (fin.is_open()) {//close fin if open
		fin.close();
	}
	if (fout.is_open()) {//close fout if open
		fout.close();
	}		
}

164
void SMETIO::read2DGrid(Grid2DObject& /*grid_out*/, const std::string& /*_name*/)
165
166
167
168
169
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

170
void SMETIO::readDEM(DEMObject& /*dem_out*/)
171
172
173
174
175
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

176
void SMETIO::readLanduse(Grid2DObject& /*landuse_out*/)
177
178
179
180
181
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

182
void SMETIO::readAssimilationData(const Date& /*date_in*/, Grid2DObject& /*da_out*/)
183
184
185
186
187
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

188
void SMETIO::readStationData(const Date&, std::vector<StationData>& /*vecStation*/)
189
190
191
192
193
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

194
void SMETIO::parseInputOutputSection()
195
{
196
197
198
199
200
	/*
	 * Parse the [Input] and [Output] sections within ConfigReader object cfg
	 */

	//Parse input section: extract number of files to read and store filenames in vecFiles
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
	unsigned int counter = 1;
	string filename = "";
	do {
		stringstream ss;
		filename = "";
		
		ss << "METEOFILE" << counter;
		cfg.getValue(ss.str(), "Input", filename, ConfigReader::nothrow);

		if (filename != ""){
			if (!IOUtils::validFileName(filename)) //Check whether filename is valid
				throw InvalidFileNameException(filename, AT);

			vecFiles.push_back(filename);
		}
		counter++;
	} while (filename != "");

219
	//Parse output section: extract info on whether to write ASCII or BINARY format, gzipped or not
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
	outpath = "";
	outputIsAscii = true; 
	outputIsGzipped = false;

	vector<string> vecArgs;
	cfg.getValue("METEOPATH", "Output", outpath, ConfigReader::nothrow);
	cfg.getValue("METEOPARAM", "Output", vecArgs, ConfigReader::nothrow); //"ASCII|BINARY GZIP"

	if (outpath == "")
		return;

	if (vecArgs.size() == 0)
		vecArgs.push_back("ASCII");

	if (vecArgs.size() > 2)
		throw InvalidFormatException("Too many values for key METEOPARAM", AT);

	if (vecArgs[0] == "BINARY")
		outputIsAscii = false;
	else if (vecArgs[0] == "ASCII")
		outputIsAscii = true;
	else 
		throw InvalidFormatException("The first value for key METEOPARAM may only be ASCII or BINARY", AT);

	if (vecArgs.size() == 2){
		if (vecArgs[1] != "GZIP")
			throw InvalidFormatException("The second value for key METEOPARAM may only be GZIP", AT);

		outputIsGzipped = true;
	}
}

252
void SMETIO::readMeteoData(const Date& dateStart, const Date& dateEnd,
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
                            std::vector< std::vector<MeteoData> >& vecMeteo, 
                            std::vector< std::vector<StationData> >& vecStation,
                            const unsigned int& stationindex)
{
	//Make sure that vecMeteo/vecStation have the correct dimension and stationindex is valid
	unsigned int startindex=0, endindex=vecFiles.size();	
	if (stationindex != IOUtils::npos){
		if ((stationindex < vecFiles.size()) || (stationindex < vecMeteo.size()) || (stationindex < vecStation.size())){
			startindex = stationindex;
			endindex = stationindex+1;
		} else {
			throw IndexOutOfBoundsException("Invalid stationindex", AT);
		} 

		vecMeteo[stationindex].clear();
		vecStation[stationindex].clear();
	} else {
		vecMeteo.clear();
		vecStation.clear();
		
		vecMeteo = vector< vector<MeteoData> >(vecFiles.size());
		vecStation = vector< vector<StationData> >(vecFiles.size());
	}

	//Now loop through all requested stations, open the respective files and parse them
	for (unsigned int ii=startindex; ii<endindex; ii++){
		bool isAscii = true;
		string filename = vecFiles.at(ii); //filename of current station
		
		if (!IOUtils::fileExists(filename))
			throw FileNotFoundException(filename, AT);

		fin.clear();
		fin.open (filename.c_str(), ios::in);
		if (fin.fail())
			throw FileAccessException(filename, AT);

		char eoln = IOUtils::getEoln(fin); //get the end of line character for the file

		//Go through file, save key value pairs
		string line="";
		std::vector<std::string> tmpvec, vecDataSequence;
		double timezone = 0.0;
		bool locationInHeader = false;
		StationData sd;

		try {
			//1. Read signature
			getline(fin, line, eoln); //read complete signature line
			IOUtils::stripComments(line);
			IOUtils::readLineToVec(line, tmpvec);
			checkSignature(tmpvec, filename, isAscii);

			//2. Read Header
			readHeader(eoln, filename, locationInHeader, timezone, sd, vecDataSequence);
308
			SMETIO::checkColumnNames(vecDataSequence, locationInHeader);
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

			//3. Read DATA
			if (isAscii){
				readDataAscii(eoln, filename, timezone, sd, vecDataSequence, dateStart, dateEnd,
						    vecMeteo[ii], vecStation[ii]);
			} else {
				streampos currpos = fin.tellg();
				fin.close();
				fin.open (filename.c_str(), ios::in|ios::binary);				
				if (fin.fail()) throw FileAccessException(filename, AT);
				fin.seekg(currpos); //jump to binary data section

				readDataBinary(eoln, filename, timezone, sd, vecDataSequence, dateStart, dateEnd,
							vecMeteo[ii], vecStation[ii]);
			}
			cleanup();
		} catch(std::exception& e) {
			cleanup();
			throw;
		}
	}
}

332
void SMETIO::readDataBinary(const char&, const std::string&, const double& timezone,
333
334
335
336
337
338
339
340
341
342
343
344
345
346
					    const StationData& sd, const std::vector<std::string>& vecDataSequence,
					    const Date& dateStart, const Date& dateEnd,
					    std::vector<MeteoData>& vecMeteo, std::vector<StationData>& vecStation)
{
	const unsigned int nrOfColumns = vecDataSequence.size();

	while (!fin.eof()){
		MeteoData md;
		StationData tmpsd = sd;
		double lat=IOUtils::nodata, lon=IOUtils::nodata, alt=IOUtils::nodata;
		unsigned int poscounter = 0;

		for (unsigned int ii=0; ii<nrOfColumns; ii++){
			if (vecDataSequence[ii] == "timestamp"){
347
348
349
350
				double tmpval;
				fin.read(reinterpret_cast < char * > (&tmpval), sizeof(double));

				md.date.setDate(tmpval);
351
352
353
354
355
356
357
358
359

				if ((timezone != IOUtils::nodata) && (timezone != 0.0))
					md.date.setTimeZone(timezone);

				if (md.date < dateStart)
					continue;
				if (md.date > dateEnd)
					break;
			} else {
360
361
362
363
364
365
366
367
368
369
370
371
372
373
				float tmpval;
				fin.read(reinterpret_cast < char * > (&tmpval), sizeof(float));			
				double val = (double)tmpval;

				if (vecDataSequence[ii] == "latitude"){
					lat = val;
					poscounter++;
				} else if (vecDataSequence[ii] == "longitude"){
					lon = val;
					poscounter++;
				} else if (vecDataSequence[ii] == "altitude"){
					alt = val;
					poscounter++;
				} else {
374
					SMETIO::getParameter(vecDataSequence[ii], md) = val;
375
				}
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
			}
		}

		char c;
		fin.read(&c, sizeof(char));
		if (c != '\n')
			throw InvalidFormatException("Corrupted data in section [DATA]", AT);

		if (poscounter == 3)
			tmpsd.position.setLatLon(lat, lon, alt);

		//cout << "===" << endl;
		//cout << sd << endl;
		//cout << md.date.toString(Date::ISO) << endl;

		vecMeteo.push_back(md);
		vecStation.push_back(tmpsd);
	}	
}

396
void SMETIO::readDataAscii(const char& eoln, const std::string& filename, const double& timezone,
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
					   const StationData& sd, const std::vector<std::string>& vecDataSequence,
					   const Date& dateStart, const Date& dateEnd,
					   std::vector<MeteoData>& vecMeteo, std::vector<StationData>& vecStation)
{
	string line = "";
	vector<string> tmpvec;
	const unsigned int nrOfColumns = vecDataSequence.size();

	while (!fin.eof()){
		getline(fin, line, eoln);
		IOUtils::stripComments(line);
		IOUtils::trim(line);
		if (line == "") continue; //Pure comment lines and empty lines are ignored

		unsigned int ncols = IOUtils::readLineToVec(line, tmpvec);

		if (ncols != nrOfColumns)
			throw InvalidFormatException("In "+ filename + ": Invalid amount of data in data line", AT);

		MeteoData md;
		StationData tmpsd = sd;
		double lat, lon, alt;
		unsigned int poscounter = 0;
		for (unsigned int ii=0; ii<nrOfColumns; ii++){
			if (vecDataSequence[ii] == "timestamp"){
				if (!IOUtils::convertString(md.date, tmpvec[ii]))
					throw InvalidFormatException("In "+filename+": Timestamp invalid in data line", AT);

				if ((timezone != IOUtils::nodata) && (timezone != 0.0))
					md.date.setTimeZone(timezone);

				if (md.date < dateStart)
					continue;
				if (md.date > dateEnd)
					break;

			} else if (vecDataSequence[ii] == "latitude"){
				if (!IOUtils::convertString(lat, tmpvec[ii])) 
					throw InvalidFormatException("In "+filename+": Latitude invalid", AT);
				poscounter++;
			} else if (vecDataSequence[ii] == "longitude"){
				if (!IOUtils::convertString(lon, tmpvec[ii])) 
					throw InvalidFormatException("In "+filename+": Longitude invalid", AT);
				poscounter++;
			} else if (vecDataSequence[ii] == "altitude"){
				if (!IOUtils::convertString(alt, tmpvec[ii])) 
					throw InvalidFormatException("In "+filename+": Altitude invalid", AT);
				poscounter++;
			} else {
446
				if (!IOUtils::convertString(SMETIO::getParameter(vecDataSequence[ii], md), tmpvec[ii]))
447
448
449
450
451
452
453
454
455
456
457
458
					throw InvalidFormatException("In "+filename+": Invalid value for param", AT);
			}
		}

		if (poscounter == 3)
			tmpsd.position.setLatLon(lat, lon, alt);

		vecMeteo.push_back(md);
		vecStation.push_back(tmpsd);
	}
}

459
void SMETIO::readHeader(const char& eoln, const std::string& filename, bool& locationInHeader,
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
                         double& timezone, StationData& sd, std::vector<std::string>& vecDataSequence)
{
	string line="";
	while (!fin.eof() && (fin.peek() != '['))
		getline(fin, line, eoln);
	
	getline(fin, line, eoln);
	IOUtils::stripComments(line);
	IOUtils::trim(line);
	IOUtils::toUpper(line);

	if (line != "[HEADER]")
		throw InvalidFormatException("Section " + line + " in "+ filename + " invalid", AT);

	std::map<std::string,std::string> mapHeader;
	while (!fin.eof() && (fin.peek() != '[')){
		getline(fin, line, eoln);

		IOUtils::stripComments(line);
		IOUtils::trim(line);

481
		if (line != "") {
482
483
			if (!IOUtils::readKeyValuePair(line, "=", mapHeader))
				throw InvalidFormatException("Invalid key value pair in section [Header]", AT);
484
		}
485
486
487
488
489
490
491
	}

	//Now extract info from mapHeader
	IOUtils::getValueForKey(mapHeader, "station_id", sd.stationID);
	IOUtils::getValueForKey(mapHeader, "station_name", sd.stationName, IOUtils::nothrow);
	IOUtils::getValueForKey(mapHeader, "tz", timezone, IOUtils::nothrow);

492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	//trying to read easting/northing
	double easting=IOUtils::nodata, northing=IOUtils::nodata, alt=IOUtils::nodata;
	short int epsg=IOUtils::snodata;
	IOUtils::getValueForKey(mapHeader, "easting", easting, IOUtils::nothrow);
	if (easting != IOUtils::nodata){ //HACK
		IOUtils::getValueForKey(mapHeader, "northing", northing);
		IOUtils::getValueForKey(mapHeader, "altitude", alt);
		IOUtils::getValueForKey(mapHeader, "epsg", epsg);
		sd.position.setEPSG(epsg);
		sd.position.setXY(easting, northing, alt);
		locationInHeader = true;
	} else {
		locationInHeader = false;
	}

	//now trying to read lat/long (second, so that it has precedence over east/north coordinates)
	double lat=IOUtils::nodata, lon=IOUtils::nodata;
509
510
511
512
513
514
515
516
517
	IOUtils::getValueForKey(mapHeader, "latitude", lat, IOUtils::nothrow);
	if (lat != IOUtils::nodata){ //HACK
		IOUtils::getValueForKey(mapHeader, "longitude", lon);
		IOUtils::getValueForKey(mapHeader, "altitude", alt);
		sd.position.setLatLon(lat, lon, alt);
		locationInHeader = true;
	}

	IOUtils::getValueForKey(mapHeader, "fields", vecDataSequence);
518
519
	//IOUtils::getValueForKey(mapHeader, "units_offset", vecUnitsOffset, IOUtils::nothrow);
	//IOUtils::getValueForKey(mapHeader, "units_multiplier", vecUnitsMultiplier, IOUtils::nothrow);
520
521
522
523
524
525
526
527
528
529
530

	//Read [DATA] section tag
	getline(fin, line, eoln);
	IOUtils::stripComments(line);
	IOUtils::trim(line);
	IOUtils::toUpper(line);

	if (line != "[DATA]")
		throw InvalidFormatException("Section " + line + " in "+ filename + " invalid, expected [DATA]", AT);
}

531
void SMETIO::checkSignature(const std::vector<std::string>& vecSignature, const std::string& filename, bool& isAscii)
532
{
533
	if ((vecSignature.size() != 3) || (vecSignature[0] != "SMET"))
534
535
		throw InvalidFormatException("The signature of file " + filename + " is invalid", AT);

536
	std::string version = vecSignature[1];
537
	if ((version != "0.9") && (version != "0.95") && (version != smet_version))
538
539
		throw InvalidFormatException("Unsupported file format version for file " + filename, AT);

540
541
	const std::string type = vecSignature[2];
	if (type == "ASCII")
542
		isAscii = true;
543
	else if (type == "BINARY")
544
545
		isAscii = false;
	else 
546
		throw InvalidFormatException("The 3rd column in the signature of file " + filename + " must be either ASCII or BINARY", AT);
547
548
}

549
void SMETIO::writeMeteoData(const std::vector< std::vector<MeteoData> >& vecMeteo,
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
					    const std::vector< std::vector<StationData> >& vecStation,
					    const std::string&)
{

	//Loop through all stations
	for (unsigned int ii=0; ii<vecMeteo.size(); ii++){
		//1. check consitency of station data position -> write location in header or data section
		StationData sd;
		bool isConsistent = checkConsistency(vecStation.at(ii), sd);
		
		if (sd.stationID == ""){
			stringstream ss;
			ss << "Station" << ii+1;

			sd.stationID = ss.str();
		}

567
		string filename = outpath + "/" + sd.stationID + ".smet";
568
569
570
571
572
573
574
		if (!IOUtils::validFileName(filename)) //Check whether filename is valid
			throw InvalidFileNameException(filename, AT);

		try {
			fout.open(filename.c_str());
			if (fout.fail()) throw FileAccessException(filename.c_str(), AT);

575
			fout << "SMET " << smet_version << " ";
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
			if (outputIsAscii)
				fout << "ASCII" << endl;
			else 
				fout << "BINARY" << endl;

			//2. write header, but first check which meteo parameter fields are actually in use
			vector<bool> vecParamInUse = vector<bool>(MeteoData::nrOfParameters, false); 
			double timezone = IOUtils::nodata;
			checkForUsedParameters(vecMeteo[ii], timezone, vecParamInUse);
			writeHeaderSection(isConsistent, sd, timezone, vecParamInUse);
			
			//3. write data depending on ASCII/BINARY
			if (outputIsAscii) {
				writeDataAscii(isConsistent, vecMeteo[ii], vecStation[ii], vecParamInUse);
			} else {
				fout << "[DATA]" << endl;
				fout.close();
				fout.open(filename.c_str(), ios::out | ios::app | ios::binary); //reopen as binary file
				if (fout.fail()) throw FileAccessException(filename.c_str(), AT);
				writeDataBinary(isConsistent, vecMeteo[ii], vecStation[ii], vecParamInUse);
			}
			
			cleanup();

			//4. gzip file or not
		} catch (exception& e){
			cleanup();
			throw;
		}
	}
}

608
void SMETIO::writeDataBinary(const bool& writeLocationInHeader, const std::vector<MeteoData>& vecMeteo,
609
610
611
612
613
                              const std::vector<StationData>& vecStation, const std::vector<bool>& vecParamInUse)
{
	char eoln = '\n';

	for (unsigned int ii=0; ii<vecMeteo.size(); ii++){
614
615
616
617
		float val = 0;
		double julian = vecMeteo[ii].date.getJulianDate();
		
		fout.write((char*)&julian, sizeof(double));
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637

		if (!writeLocationInHeader){ //Meta data changes
			val = (float)vecStation[ii].position.getLat();
			fout.write((char*)&val, sizeof(float));
			val = (float)vecStation[ii].position.getLon();
			fout.write((char*)&val, sizeof(float));
			val = (float)vecStation[ii].position.getAltitude();
			fout.write((char*)&val, sizeof(float));
		}

		for (unsigned int jj=0; jj<MeteoData::nrOfParameters; jj++){
			if (vecParamInUse[jj]){
				val = (float)vecMeteo[ii].param(jj);
				fout.write((char*)&val, sizeof(float));
			}
		}
		fout.write((char*)&eoln, sizeof(char));
	}
}

638
void SMETIO::writeDataAscii(const bool& writeLocationInHeader, const std::vector<MeteoData>& vecMeteo,
639
640
641
                             const std::vector<StationData>& vecStation, const std::vector<bool>& vecParamInUse)
{
	fout << "[DATA]" << endl;
642
643
	fout.fill(' ');
	fout << right;
644
645
646
647
	for (unsigned int ii=0; ii<vecMeteo.size(); ii++){
		fout << vecMeteo[ii].date.toString(Date::ISO);

		if (!writeLocationInHeader){ //Meta data changes
648
649
650
			fout << " " << setw(12) << setprecision(6) << vecStation[ii].position.getLat();
			fout << " " << setw(12) << setprecision(6) << vecStation[ii].position.getLon();
			fout << " " << setw(8)  << setprecision(2) << vecStation[ii].position.getAltitude();
651
652
653
		}

		for (unsigned int jj=0; jj<MeteoData::nrOfParameters; jj++){
654
655
656
657
658
659
660
			fout << " ";
			if (vecParamInUse[jj]){
				setFormatting(MeteoData::Parameters(jj));
				if (vecMeteo[ii].param(jj) == IOUtils::nodata)
					fout << setprecision(0);
				fout << vecMeteo[ii].param(jj);
			}
661
662
663
664
665
		}
		fout << endl;
	}
}

666
void SMETIO::setFormatting(const MeteoData::Parameters& paramindex)
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
{
	if ((paramindex == MeteoData::TA) || (paramindex == MeteoData::TSS) || (paramindex == MeteoData::TSG))
		fout << setw(8) << setprecision(2);
	else if (paramindex == MeteoData::VW)
		fout << setw(6) << setprecision(1);
	else if (paramindex == MeteoData::DW)
		fout << setw(5) << setprecision(0);
	else if ((paramindex == MeteoData::ISWR) || (paramindex == MeteoData::RSWR) || (paramindex == MeteoData::ILWR))
		fout << setw(6) << setprecision(0);
	else if (paramindex == MeteoData::HNW)
		fout << setw(6) << setprecision(3);
	else if (paramindex == MeteoData::HS)
		fout << setw(8) << setprecision(3);
	else if (paramindex == MeteoData::RH)
		fout << setw(7) << setprecision(3);
}

684
void SMETIO::writeHeaderSection(const bool& writeLocationInHeader, const StationData& sd,
685
686
687
                                 const double& timezone, const std::vector<bool>& vecParamInUse)
{
	fout << "[HEADER]" << endl;
688
	fout << "station_id   = " << sd.getStationID() << endl;
689
690
691
692
	if (sd.getStationName() != "")
		fout << "station_name = " << sd.getStationName() << endl;
	
	if (writeLocationInHeader){
693
		fout << fixed;
694
695
696
697
698
699
		fout << "latitude     = " << setw(14) << setprecision(6) << sd.position.getLat() << "\n";
		fout << "longitude    = " << setw(14) << setprecision(6) << sd.position.getLon() << "\n";
		fout << "altitude     = " << setw(9)  << setprecision(1) << sd.position.getAltitude() << "\n";
		fout << "easting      = " << setw(14) << setprecision(6) << sd.position.getEasting() << "\n";
		fout << "northing     = " << setw(14) << setprecision(6) << sd.position.getNorthing() << "\n";
		fout << "epsg         = " << setw(7)  << setprecision(0) << sd.position.getEPSG() << "\n";
700
701
	}

702
	fout << "nodata       = " << setw(7) << setprecision(0) << IOUtils::nodata << "\n";
703
704
	
	if ((timezone != IOUtils::nodata) && (timezone != 0.0))
705
		fout << "tz           = " << setw(7)  << setprecision(0) << timezone << "\n";
706

707
	fout << "fields       = timestamp";
708
709
710
711
712
713

	if (!writeLocationInHeader){
		fout << " latitude longitude altitude";
	}

	for (unsigned int ii=0; ii<MeteoData::nrOfParameters; ii++){
714
715
716
717
718
719
		if (vecParamInUse[ii]) {
			std::string column=MeteoData::getParameterName(ii);
			if(column=="RSWR") column="OSWR";
			if(column=="HNW") column="PSUM";
			fout << " " << column;
		}
720
721
722
723
724
	}
	fout << endl;
}


725
void SMETIO::checkForUsedParameters(const std::vector<MeteoData>& vecMeteo, double& timezone,
726
727
728
729
730
731
732
733
734
735
736
737
738
739
                                     std::vector<bool>& vecParamInUse)
{
	for (unsigned int ii=0; ii<vecMeteo.size(); ii++){
		for (unsigned int jj=0; jj<MeteoData::nrOfParameters; jj++){
			if (!vecParamInUse[jj])
				if (vecMeteo[ii].param(jj) != IOUtils::nodata)
					vecParamInUse[jj] = true;
		}
	}	

	if (vecMeteo.size() > 0)
		timezone = vecMeteo[0].date.getTimeZone();
}

740
bool SMETIO::checkConsistency(const std::vector<StationData>& vecStation, StationData& sd)
741
742
743
744
745
746
747
748
749
750
751
752
{
	for (unsigned int ii=1; ii<vecStation.size(); ii++){
		if (vecStation[ii].position != vecStation[ii-1].position)
			return false;
	}

	if (vecStation.size() > 0)
		sd = vecStation[0];

	return true;
}

753
void SMETIO::readSpecialPoints(std::vector<Coords>&)
754
755
756
757
758
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

759
void SMETIO::write2DGrid(const Grid2DObject& /*grid_in*/, const std::string& /*name*/)
760
761
762
763
764
765
766
767
768
769
770
771
772
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}


#ifndef _METEOIO_JNI
extern "C"
{
	void deleteObject(void* obj) {
		delete reinterpret_cast<PluginObject*>(obj);
	}

773
	void* loadObject(const string& classname, const ConfigReader& cfg) {
774
		if(classname == "SMETIO") {
775
			//cerr << "Creating dynamic handle for " << classname << endl;
776
			return new SMETIO(deleteObject, cfg);
777
778
779
780
781
782
783
784
		}
		//cerr << "Could not load " << classname << endl;
		return NULL;
	}
}
#endif

} //namespace