WSL/SLF GitLab Repository

ImisIO.cc 42.6 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
/***********************************************************************************/
/*  Copyright 2009, 2010 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/>.
*/
#include "ImisIO.h"

using namespace std;
using namespace oracle;
using namespace oracle::occi;
Fierz's avatar
Fierz committed
23
using namespace mio;
24
25
26
27
28

namespace mio {
/**
 * @page imis IMIS
 * @section imis_format Format
29
30
 * This plugin reads data directly from the IMIS network database (Oracle database). 
 * It retrieves standard IMIS data as well as ENETZ and ANETZ data.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 *
 * @section imis_units Units
 * The units are assumed to be the following:
 * - temperatures in celsius
 * - relative humidity in %
 * - wind speed in m/s
 * - precipitations in mm/h
 * - radiation in W/m²
 *
 * @section imis_keywords Keywords
 * This plugin uses the following keywords:
 * - COORDSYS: input coordinate system (see Coords) specified in the [Input] section
 * - COORDPARAM: extra input coordinates parameters (see Coords) specified in the [Input] section
 * - COORDSYS: output coordinate system (see Coords) specified in the [Output] section
 * - COORDPARAM: extra output coordinates parameters (see Coords) specified in the [Output] section
 * - DBNAME: name of the database to use (exemple: sdbo)
 * - DBUSER: user name to use when connecting to the database
 * - DBPASS: password to use when connecting to the database
 * - NROFSTATIONS: total number of stations listed for use
 * - STATION#: station code for the given number #
51
 * - USEANETZ: use ANETZ stations to provide precipitations for normal IMIS stations. Each IMIS station is associated with one or two ANETZ stations and does a weighted average to get what should be its local precipitations
52
53
 */

Fierz's avatar
Fierz committed
54
55
const double ImisIO::plugin_nodata = -999.; ///< plugin specific nodata value
const double ImisIO::in_tz = 1.; ///< All IMIS data is in gmt+1, that is UTC+1 (a quelques secondes près;-)
56

Fierz's avatar
Fierz committed
57
const string ImisIO::sqlQueryStationIDs = "SELECT station_name, drift_stat_abk, drift_stao_nr FROM station2.v_snow_drift_standort WHERE application_code='snowpack' AND station_code=:1"; ///< Wind drift station meta data
58

Fierz's avatar
Fierz committed
59
const string ImisIO::sqlQueryStationMetaData = "SELECT stao_name, stao_x, stao_y, stao_h FROM station2.standort WHERE stat_abk LIKE :1 AND stao_nr=:2"; ///< Snow station meta data
60

Fierz's avatar
Fierz committed
61
const string ImisIO::sqlQuerySensorDepths = "SELECT hts1_1, hts1_2, hts1_3 FROM station2.standort WHERE stat_abk LIKE :1 AND stao_nr=:2"; ///< Sensor depths at station
62

Fierz's avatar
Fierz committed
63
64
const string ImisIO::sqlQueryMeteoDataDrift = "SELECT TO_CHAR(a.datum, 'YYYY-MM-DD HH24:MI') AS thedate, a.ta, a.iswr, a.vw, a.dw, a.vw_max, a.rh, a.ilwr, a.hnw, a.tsg, a.tss, a.hs, a.rswr, b.vw AS vw_drift, b.dw AS dw_drift, a.ts1, a.ts2, a.ts3 FROM (SELECT * FROM ams.v_ams_raw WHERE stat_abk=:1 AND stao_nr=:2 AND datum>=:3 AND datum<=:4) a LEFT OUTER JOIN (SELECT case when to_char(datum,'MI')=40 then trunc(datum,'HH24')+0.5/24 else datum end as datum, vw, dw FROM ams.v_ams_raw WHERE stat_abk=:5 AND stao_nr=:6 AND datum>=:3 AND datum<=:4) b ON a.datum=b.datum ORDER BY thedate"; ///< C. Marty's Data query with wind drift station; gets wind from enet stations for imis snow station too! [2010-02-24]

65
const string ImisIO::sqlQueryMeteoData = "SELECT TO_CHAR(datum, 'YYYY-MM-DD HH24:MI') AS thedate, ta, iswr, vw, dw, vw_max, rh, ilwr, hnw, tsg, tss, hs, rswr, ts1, ts2, ts3 FROM ams.v_ams_raw WHERE stat_abk=:1 AND stao_nr=:2 AND datum>=:3 AND datum<=:4 ORDER BY thedate ASC"; ///< Data query without wind drift station
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
std::map<std::string, AnetzData> ImisIO::mapAnetz;
const bool ImisIO::__init = ImisIO::initStaticData();

bool ImisIO::initStaticData()
{
	//Associate string with AnetzData
	mapAnetz["AMD2"] = AnetzData(2,"*GLA","*SAE","",3,1.2417929,0.548411708,-0.0692799);
	mapAnetz["ANV2"] = AnetzData(2,"*EVO","*MVE","",2,0.7920454,0.771111962,IOUtils::nodata);
	mapAnetz["ANV3"] = AnetzData(1,"*EVO","","",1,1.6468,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["ARO2"] = AnetzData(2,"*EVO","*GSB","",2,0.9692294,0.218384531,IOUtils::nodata);
	mapAnetz["ARO3"] = AnetzData(2,"*EVO","*ZER","",3,1.0748285,1.649860092,-0.0728015);
	mapAnetz["BED2"] = AnetzData(2,"*PIO","*ULR","",3,0.9934869,1.047586006,-0.05489259);
	mapAnetz["BED3"] = AnetzData(2,"*PIO","*ULR","",2,0.6999,0.4122,IOUtils::nodata);
	mapAnetz["BER2"] = AnetzData(2,"*ROB","*COV","",3,1.4454061,0.558775717,-0.05063568);
	mapAnetz["BER3"] = AnetzData(2,"*ROB","*COV","",2,0.378476,0.817976734,IOUtils::nodata);
	mapAnetz["BEV2"] = AnetzData(2,"*SAM","*COV","",3,1.8237643,0.853292298,-0.33642156);
	mapAnetz["BOG2"] = AnetzData(1,"*ROE","","",1,1.0795,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["BOR2"] = AnetzData(1,"*VIS","","",1,1.0662264,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["BOV2"] = AnetzData(2,"*GSB","*EVO","",2,0.3609309,0.934922978,IOUtils::nodata);
	mapAnetz["CAM2"] = AnetzData(2,"*PIO","*COM","",2,0.750536,0.426864157,IOUtils::nodata);
	mapAnetz["CHA2"] = AnetzData(2,"*AIG","*SIO","",2,0.7107216,0.99869915,IOUtils::nodata);
	mapAnetz["CON2"] = AnetzData(2,"*SIO","*MVE","",3,3.5344378,1.952708399,-0.74509918);
	mapAnetz["DAV2"] = AnetzData(2,"*WFJ","*DAV","",3,0.594108,1.091565634,-0.12150025);
	mapAnetz["DAV3"] = AnetzData(2,"*WFJ","*DAV","",3,0.9266618,0.815816241,-0.06248703);
	mapAnetz["DAV4"] = AnetzData(2,"*WFJ","*DAV","",3,0.9266618,0.815816241,-0.06248703);
	mapAnetz["DAV5"] = AnetzData(2,"*WFJ","*DAV","",3,0.9266618,0.815816241,-0.06248703);
	mapAnetz["DTR2"] = AnetzData(2,"*PIO","*COM","",2,0.0384,0.9731,IOUtils::nodata);
	mapAnetz["DVF2"] = AnetzData(1,"*WFJ","","",1,1,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["ELM2"] = AnetzData(1,"*GLA","","",1,1.4798048,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["ELS2"] = AnetzData(2,"*ABO","*INT","",3,1.0886792,0.568730457,-0.07758286);
	mapAnetz["FAE2"] = AnetzData(1,"*ABO","","",1,2.1132038,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["FIR2"] = AnetzData(2,"*INT","*GRH","",3,1.2416838,0.243226327,-0.02392287);
	mapAnetz["FIS2"] = AnetzData(1,"*ABO","","",1,1.1991,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["FNH2"] = AnetzData(2,"*AIG","*GSB","",2,1.3949428,0.297933922,IOUtils::nodata);
	mapAnetz["FOU2"] = AnetzData(1,"*GSB","","",1,0.8448844,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["FUL2"] = AnetzData(2,"*FEY","*AIG","",2,1.070156,0.587972864,IOUtils::nodata);
	mapAnetz["FUS2"] = AnetzData(1,"*PIO","","",1,1.3557753,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["GAD2"] = AnetzData(2,"*ENG","*GUE","",3,0.9764334,0.814293499,-0.07074082);
	mapAnetz["GAN2"] = AnetzData(2,"*ABO","*VIS","",2,0.520224,0.825813298,IOUtils::nodata);
	mapAnetz["GLA2"] = AnetzData(1,"*GLA","","",1,1.7186314,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["GOM2"] = AnetzData(2,"*ULR","*GRH","",2,0.4413,0.4235,IOUtils::nodata);
	mapAnetz["GOM3"] = AnetzData(2,"*ULR","*GRH","",2,0.3269755,0.62995601,IOUtils::nodata);
	mapAnetz["GUT2"] = AnetzData(2,"*GRH","*ENG","",2,0.3977985,0.463100458,IOUtils::nodata);
	mapAnetz["GUT3"] = AnetzData(2,"*GRH","*ENG","",2,0.3977985,0.463100458,IOUtils::nodata);
	mapAnetz["HTR2"] = AnetzData(2,"*HIR","*COM","",2,0.8668,0.5939,IOUtils::nodata);
	mapAnetz["HTR3"] = AnetzData(2,"*SBE","*COM","",2,1.3023275,-0.663411226,IOUtils::nodata);
	mapAnetz["ILI2"] = AnetzData(1,"*AIG","","",1,1.2341516,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["JUL2"] = AnetzData(2,"*COV","*SAM","",2,0.4900961,0.871078269,IOUtils::nodata);
	mapAnetz["KES2"] = AnetzData(2,"*SAM","*DAV","",2,0.847596,1.112635571,IOUtils::nodata);
	mapAnetz["KLO2"] = AnetzData(1,"*DAV","","",1,1.585,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["KLO3"] = AnetzData(2,"*DAV","*WFJ","",3,0.8352,0.9493,-0.0526);
	mapAnetz["LAU2"] = AnetzData(2,"*ABO","*SIO","",2,0.3037172,0.791695555,IOUtils::nodata);
	mapAnetz["LUK2"] = AnetzData(2,"*DIS","*PIO","",3,0.8593029,0.378261758,0.85930291);
	mapAnetz["MEI2"] = AnetzData(3,"*ENG","*GUE","*ALT",3,0.3882119,0.399244859,0.3298324);
	mapAnetz["MES2"] = AnetzData(2,"*HIR","*COM","",2,1.3552818,-0.393843912,IOUtils::nodata);
	mapAnetz["MUN2"] = AnetzData(1,"*VIS","","",1,0.8624804,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["NAR2"] = AnetzData(2,"*PIO","*COM","",3,0.4089981,0.873419792,-0.028464);
	mapAnetz["NEN2"] = AnetzData(2,"*SIO","*EVO","",3,0.9352699,1.312867984,-0.14543389);
	mapAnetz["OBM2"] = AnetzData(2,"*AIG","*MLS","",3,1.9413387,1.64250639,-0.37210579);
	mapAnetz["OBW2"] = AnetzData(2,"*GRH","*ULR","",3,0.2471352,1.219258485,-0.02153657);
	mapAnetz["OBW3"] = AnetzData(2,"*GRH","*ULR","",2,0.5274,0.4815,IOUtils::nodata);
	mapAnetz["OFE2"] = AnetzData(1,"*SCU","","",1,1.8758744,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["ORT2"] = AnetzData(1,"*GLA","","",1,1.6214,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["OTT2"] = AnetzData(1,"*ABO","","",1,1.3759903,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["PAR2"] = AnetzData(1,"*WFJ","","",1,1.6252986,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["PUZ2"] = AnetzData(2,"*DIS","*GUE","",2,0.9481811,0.1490937,IOUtils::nodata);
	mapAnetz["ROA2"] = AnetzData(2,"*INT","*NAP","",3,1.748338,0.574491521,-0.1670437);
	mapAnetz["SAA2"] = AnetzData(2,"*ZER","*VIS","",3,0.6316695,1.210149675,-0.11760175);
	mapAnetz["SAA3"] = AnetzData(1,"*VIS","","",1,1.2905,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["SCA2"] = AnetzData(2,"*ALT","*DIS","",2,0.8118627,0.360141586,IOUtils::nodata);
	mapAnetz["SCA3"] = AnetzData(2,"*ALT","*GLA","",2,0.4768725,0.819642544,IOUtils::nodata);
	mapAnetz["SCB2"] = AnetzData(2,"*ENG","*INT","",3,1.0535332,1.21234263,-0.1307221);
	mapAnetz["SCH2"] = AnetzData(1,"*INT","","",1,1.54557,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["SHE2"] = AnetzData(1,"*INT","","",1,1.1065938,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["SIM2"] = AnetzData(2,"*COM","*SBE","",2,0.6861131,0.296215066,IOUtils::nodata);
	mapAnetz["SLF2"] = AnetzData(1,"*WFJ","","",1,0.9585787,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["SMN2"] = AnetzData(1,"*SCU","","",1,0.6979953,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["SPN2"] = AnetzData(2,"*VIS","*ZER","",2,1.1049,1.4598,IOUtils::nodata);
	mapAnetz["SPN3"] = AnetzData(1,"*VIS","","",1,1.0244902,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["STH2"] = AnetzData(2,"*PLF","*ABO","",3,1.1252659,0.893324895,-0.13194965);
	mapAnetz["STN2"] = AnetzData(2,"*EVO","*MVE","",2,0.9042348,0.687519213,IOUtils::nodata);
	mapAnetz["TAM2"] = AnetzData(2,"*VAD","*GLA","",2,0.6304286,0.738150034,IOUtils::nodata);
	mapAnetz["TAM3"] = AnetzData(2,"*VAD","*GLA","",3,1.5515584,0.407868299,-0.0800763);
	mapAnetz["TRU2"] = AnetzData(2,"*MVE","*VIS","",2,1.1359,0.6577,IOUtils::nodata);
	mapAnetz["TUJ2"] = AnetzData(2,"*GUE","*DIS","",2,0.3636322,0.591777057,IOUtils::nodata);
	mapAnetz["TUJ3"] = AnetzData(2,"*GUE","*DIS","",2,0.4742,0.7791,IOUtils::nodata);
	mapAnetz["TUM2"] = AnetzData(1,"*DIS","","",1,1.752091,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["URS2"] = AnetzData(2,"*GUE","*GRH","",3,0.6847615,0.277707092,-0.03085219);
	mapAnetz["VAL2"] = AnetzData(2,"*PIO","*GUE","",3,1.2130704,0.508735389,-0.02905053);
	mapAnetz["VDS2"] = AnetzData(1,"*MVE","","",1,1.8282525,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["VIN2"] = AnetzData(1,"*SCU","","",1,0.8245,IOUtils::nodata,IOUtils::nodata);
	mapAnetz["VLS2"] = AnetzData(2,"*DIS","*HIR","",2,0.5764952,0.613916765,IOUtils::nodata);
	mapAnetz["ZER2"] = AnetzData(2,"*ZER","*EVO","",2,0.8707182,0.988158355,IOUtils::nodata);
	mapAnetz["ZER4"] = AnetzData(2,"*ZER","*EVO","",2,0.8707182,0.988158355,IOUtils::nodata);
	mapAnetz["ZNZ2"] = AnetzData(1,"*WFJ","","",1,0.9980525,IOUtils::nodata,IOUtils::nodata);

	return true;
}

166
167
168
169
170
void ImisIO::getDBParameters()
{
	cfg.getValue("DBNAME", "Input", oracleDBName_in);
	cfg.getValue("DBUSER", "Input", oracleUserName_in);
	cfg.getValue("DBPASS", "Input", oraclePassword_in);
171

172
173
	useAnetz = false;
	cfg.getValue("USEANETZ", "Input", useAnetz, Config::nothrow);
174

175
176
177
178
179
	/*cfg.getValue("DBNAME", "Output", oracleDBName_out);
	cfg.getValue("DBUSER", "Output", oracleUserName_out);
	cfg.getValue("DBPASS", "Output", oraclePassword_out);*/
}

180
ImisIO::ImisIO(void (*delObj)(void*), const Config& i_cfg) : IOInterface(delObj), cfg(i_cfg)
181
182
183
184
185
186
187
188
189
190
191
{
	IOUtils::getProjectionParameters(cfg, coordin, coordinparam, coordout, coordoutparam);
	getDBParameters();
}

ImisIO::ImisIO(const std::string& configfile) : IOInterface(NULL), cfg(configfile)
{
	IOUtils::getProjectionParameters(cfg, coordin, coordinparam, coordout, coordoutparam);
	getDBParameters();
}

192
ImisIO::ImisIO(const Config& cfgreader) : IOInterface(NULL), cfg(cfgreader)
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
244
245
{
	IOUtils::getProjectionParameters(cfg, coordin, coordinparam, coordout, coordoutparam);
	getDBParameters();
}

ImisIO::~ImisIO() throw()
{
	cleanup();
}

void ImisIO::read2DGrid(Grid2DObject&, const std::string&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::readDEM(DEMObject&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::readLanduse(Grid2DObject&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::readAssimilationData(const Date&, Grid2DObject&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::readSpecialPoints(std::vector<Coords>&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::write2DGrid(const Grid2DObject&, const std::string&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

void ImisIO::writeMeteoData(const std::vector< std::vector<MeteoData> >&,
                            const std::string&)
{
	//Nothing so far
	throw IOException("Nothing implemented here", AT);
}

246
247
248
249
250
251
252
253
254
void ImisIO::openDBConnection(oracle::occi::Environment*& env, oracle::occi::Connection*& conn)
{
	env  = Environment::createEnvironment();// static OCCI function
	conn = env->createConnection(oracleUserName_in, oraclePassword_in, oracleDBName_in);
}

void ImisIO::closeDBConnection(oracle::occi::Environment*& env, oracle::occi::Connection*& conn)
{
	try {
255
256
		if (conn != NULL)
			env->terminateConnection(conn);
257
258
259
260
261
262
		Environment::terminateEnvironment(env); // static OCCI function
	} catch (exception& e){
		Environment::terminateEnvironment(env); // static OCCI function
	}
}

Fierz's avatar
Fierz committed
263
// HACK Deprecated ??
264
265
266
267
void ImisIO::readStationData(const Date&, std::vector<StationData>& vecStation)
{
	vecStation.clear();

Fierz's avatar
Fierz committed
268
	if (vecStationMetaData.size() == 0){//Imis station meta data cannot change between time steps
269
270
271
272
273
274
		Environment *env = NULL;
		Connection *conn = NULL;

		try {
			openDBConnection(env, conn);

Fierz's avatar
Fierz committed
275
			readStationMetaData(conn); //reads all the station meta data into the vecStationMetaData (member vector)
276
277
278
279
280
281
282

			closeDBConnection(env, conn);
		} catch (exception& e){
			closeDBConnection(env, conn);
			throw IOException("Oracle Error: " + string(e.what()), AT); //Translation of OCCI exception to IOException
		}
	}
283

Fierz's avatar
Fierz committed
284
	vecStation = vecStationMetaData; //vecStationMetaData is a global vector holding all meta data
285
286
287
}

/**
288
 * @brief A meta function that extracts all station names from the Config,
Fierz's avatar
Fierz committed
289
 *        parses them and retrieves all meta data from SDB
290
 */
291
void ImisIO::readStationMetaData(oracle::occi::Connection*& conn)
292
{
Fierz's avatar
Fierz committed
293
294
295
296
297
298
299
	vector<string> vecStationID;
	readStationIDs(vecStationID);

	for (unsigned int ii=0; ii<vecStationID.size(); ii++) {
		// Retrieve the station IDs - this only needs to be done once per instance
		string stat_abk = "", stao_nr = "", station_name = "";
		parseStationID(vecStationID[ii], stat_abk, stao_nr);
300
301
302
303
304
305
306
307
308
309
310
311
312
		vector<string> stnIDs;
		string drift_stat_abk = "", drift_stao_nr = "";
		getStationIDs(vecStationID[ii], sqlQueryStationIDs, stnIDs, conn);
		if(stnIDs.size()<3)
			throw ConversionFailedException("Error while converting station IDs for station "+stat_abk+stao_nr, AT);
		IOUtils::convertString(station_name, stnIDs.at(0));
		IOUtils::convertString(drift_stat_abk, stnIDs.at(1));
		IOUtils::convertString(drift_stao_nr, stnIDs.at(2));
		const string drift_stationID = drift_stat_abk + drift_stao_nr;
		if (drift_stationID != "") {
			mapDriftStation[vecStationID[ii]] = drift_stationID;
		} else {
			throw ConversionFailedException("Error! No drift station for station "+stat_abk+stao_nr, AT);
Fierz's avatar
Fierz committed
313
		}
314

Fierz's avatar
Fierz committed
315
316
		// Retrieve the station meta data - this only needs to be done once per instance
		vector<string> stationMetaData;
317
		double east, north, alt;
Fierz's avatar
Fierz committed
318
319
		string stao_name = "";
		getStationMetaData(stat_abk, stao_nr, sqlQueryStationMetaData, stationMetaData, conn);
320
		if(stationMetaData.size()<4)
Fierz's avatar
Fierz committed
321
			throw ConversionFailedException("Error while converting station meta data for station "+stat_abk+stao_nr, AT);
322
323
324
325
		IOUtils::convertString(stao_name, stationMetaData.at(0));
		IOUtils::convertString(east, stationMetaData.at(1), std::dec);
		IOUtils::convertString(north, stationMetaData.at(2), std::dec);
		IOUtils::convertString(alt, stationMetaData.at(3), std::dec);
326

Fierz's avatar
Fierz committed
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
		// HACK to obtain a valid station_name w/o spaces within
		if (station_name == "") {
			if (stao_name != "") {
				station_name += vecStationID[ii] + ":" + stao_name;
			} else {
				station_name += vecStationID[ii];
			}
		} else {
			vector<string> tmpname;
			IOUtils::readLineToVec(station_name, tmpname, ' ');
			unsigned int jj=1;
			while (jj < tmpname.size()) {
				if (tmpname.at(jj) != "-") {
					tmpname.at(0) += "_" + tmpname.at(jj);
				} else {
					tmpname.at(0) += ":";
					if (jj < tmpname.size()-1)
						tmpname.at(0) += tmpname.at(++jj);
				}
				jj++;
			}
			station_name = tmpname.at(0);
		}
350
351
		Coords myCoord(coordin, coordinparam);
		myCoord.setXY(east, north, alt);
Fierz's avatar
Fierz committed
352
		vecStationMetaData.push_back(StationData(myCoord, vecStationID[ii], station_name));
353
354
355
356
357
	}
}

/**
 * @brief This function breaks up the station name into two components (a string and a number e.g. KLO2 -> "KLO","2")
Fierz's avatar
Fierz committed
358
 * @param stationID The full name of the station (e.g. "KLO2")
359
360
361
 * @param stName      The string part of the name  (e.g. "KLO")
 * @param stNumber    The integer part of the name (e.g. "2")
 */
Fierz's avatar
Fierz committed
362
void ImisIO::parseStationID(const std::string& stationID, std::string& stat_abk, std::string& stao_nr)
363
{
Fierz's avatar
Fierz committed
364
365
366
	stat_abk = stationID.substr(0, stationID.length()-1); //The station name: e.g. KLO
	stao_nr = stationID.substr(stationID.length()-1, 1); //The station number: e.g. 2
	if(!std::isdigit(stao_nr[0])) {
367
		//the station is one of these non-imis stations that don't contain a number...
Fierz's avatar
Fierz committed
368
369
		stat_abk = stationID;
		stao_nr = "0";
370
	}
371
372
373
}

/**
374
 * @brief This function extracts all info about the stations that are to be used from global Config object
Fierz's avatar
Fierz committed
375
 * @param vecStationID A vector that will hold all relevant stations as std::strings
376
 */
Fierz's avatar
Fierz committed
377
void ImisIO::readStationIDs(std::vector<std::string>& vecStationID)
378
{
Fierz's avatar
Fierz committed
379
	vecStationID.clear();
380

Fierz's avatar
Fierz committed
381
	//Read in the StationIDs
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
	string xmlpath="", str_stations="";
	unsigned int stations=0;

	cfg.getValue("NROFSTATIONS", "Input", str_stations);

	if (str_stations == "")
		throw ConversionFailedException("Error while reading value for NROFSTATIONS", AT);

	if (!IOUtils::convertString(stations, str_stations, std::dec))
		throw ConversionFailedException("Error while reading value for NROFSTATIONS", AT);

	for (unsigned int ii=0; ii<stations; ii++) {
		stringstream tmp_stream;
		string stationname="", tmp_file="";

		tmp_stream << (ii+1); //needed to construct key name
		cfg.getValue(string("STATION"+tmp_stream.str()), "Input", stationname);
		std::cout << "\tRead io.ini stationname: '" << stationname << "'" << std::endl;
400
401
402
403
404
		if (!isdigit(stationname[0])) {
			vecStationID.push_back(stationname);
		} else {
			std::cout << "\t ==> discarded as neither IMIS, nor ENET, nor ANETZ station!" << std::endl;
		}
405
406
407
	}
}

Fierz's avatar
Fierz committed
408
409
void ImisIO::readMeteoData(const Date& dateStart, const Date& dateEnd,
                           std::vector< std::vector<MeteoData> >& vecMeteo, const unsigned int& stationindex)
410
{
411
412
	Environment *env = NULL;
	Connection *conn = NULL;
413

414
	try {
Fierz's avatar
Fierz committed
415
		if (vecStationMetaData.size() == 0) {
416
			openDBConnection(env, conn);
Fierz's avatar
Fierz committed
417
			readStationMetaData(conn); //reads all the station meta data into the vecStationMetaData (member vector)
418
		}
419

Fierz's avatar
Fierz committed
420
		if (vecStationMetaData.size() == 0) { //if there are no stations -> return
421
422
423
			if ((env != NULL) || (conn != NULL)) closeDBConnection(env, conn);
			return;
		}
424

Fierz's avatar
Fierz committed
425
		unsigned int indexStart=0, indexEnd=vecStationMetaData.size();
426

427
		//The following part decides whether all the stations are rebuffered or just one station
Fierz's avatar
Fierz committed
428
		if (stationindex == IOUtils::npos) {
429
			vecMeteo.clear();
Fierz's avatar
Fierz committed
430
			vecMeteo.insert(vecMeteo.begin(), vecStationMetaData.size(), vector<MeteoData>());
431
		} else {
Fierz's avatar
Fierz committed
432
			if (stationindex < vecMeteo.size()) {
433
434
435
436
437
				indexStart = stationindex;
				indexEnd   = stationindex+1;
			} else {
				throw IndexOutOfBoundsException("You tried to access a stationindex in readMeteoData that is out of bounds", AT);
			}
438
439
		}

440
441
		if ((env == NULL) || (conn == NULL))
			openDBConnection(env, conn);
442

Fierz's avatar
Fierz committed
443
444
445
		for (unsigned int ii=indexStart; ii<indexEnd; ii++) { //loop through relevant stations
			readData(dateStart, dateEnd, vecMeteo, ii, vecStationMetaData, env, conn);
		}
446

Fierz's avatar
Fierz committed
447
		if (useAnetz) { //Important: we don't care about the metadata for ANETZ stations
448
449
450
			vector<StationData> vecAnetzStation;       //holds the unique ANETZ stations that need to be read
			vector< vector<MeteoData> > vecMeteoAnetz; //holds the meteo data of the ANETZ stations
			map<string, unsigned int> mapAnetzNames;   //associates an ANETZ station with an index within vecMeteoAnetz
451

452
453
454
			findAnetzStations(indexStart, indexEnd, mapAnetzNames, vecAnetzStation);
			vecMeteoAnetz.insert(vecMeteoAnetz.begin(), vecAnetzStation.size(), vector<MeteoData>());

455
			//date_anetz_start/end must be changed to be a multiple of 6h before the original dateStart, dateEnd
456
457
458
459
			Date date_anetz_start = Date(floor(dateStart.getJulianDate(true) * 4.0) / 4.0, 0.);
			date_anetz_start.setTimeZone(in_tz);
			Date date_anetz_end   = Date(floor(dateEnd.getJulianDate(true) * 4.0) / 4.0, 0.);
			date_anetz_end.setTimeZone(in_tz);
460
461
462

			//read Anetz Data
			for (unsigned int ii=0; ii<vecAnetzStation.size(); ii++)
463
				readData(date_anetz_start, dateEnd, vecMeteoAnetz, ii, vecAnetzStation, env, conn);
464

465
466
467
468
469
			//We got all the data, now calc psum for all ANETZ stations
			vector< vector<double> > vec_of_psums; //6 hour accumulations of hnw
			calculatePsum(date_anetz_start, date_anetz_end, vecMeteoAnetz, vec_of_psums);

			for (unsigned int ii=indexStart; ii<indexEnd; ii++){ //loop through relevant stations
Fierz's avatar
Fierz committed
470
				map<string,AnetzData>::const_iterator it = mapAnetz.find(vecStationMetaData.at(ii).getStationID());
471
472
473
				if (it != mapAnetz.end())
					assimilateAnetzData(date_anetz_start, it->second, vec_of_psums, mapAnetzNames, ii, vecMeteo);
			}
474
475
476
477
478
479
		}

		closeDBConnection(env, conn);
	} catch (exception& e){
		closeDBConnection(env, conn);		
		throw IOException("Oracle Error: " + string(e.what()), AT); //Translation of OCCI exception to IOException
480
481
482
	}
}

483
void ImisIO::assimilateAnetzData(const Date& dateStart, const AnetzData& ad,
484
                                 const std::vector< std::vector<double> > vec_of_psums,
485
486
                                 const std::map<std::string, unsigned int>& mapAnetzNames, const unsigned int& stationindex,
                                 std::vector< std::vector<MeteoData> >& vecMeteo)
487
{
488
489
490
491
492
493
	//Do coefficient calculation (getHNW) for every single station and data point
	vector<double> current_station_psum;
	getAnetzHNW(ad, mapAnetzNames, vec_of_psums, current_station_psum);

	unsigned int counter = 0;
	Date current_slice_date = dateStart;
494
	current_slice_date.setTimeZone(in_tz);
495
	for (unsigned int jj=0; jj<vecMeteo[stationindex].size(); jj++){
496
		while (vecMeteo[stationindex][jj].date > (current_slice_date+0.2485)){
497
			counter++;
498
499
500
			double julian = floor((current_slice_date.getJulianDate(true) +0.25001) * 4.0) / 4.0;
			current_slice_date = Date(julian, 0.);
			current_slice_date.setTimeZone(in_tz);
501
		}
502

503
504
505
506
507
508
509
510
511
512
		if (counter >= current_station_psum.size()) { break; } //should never happen
		
		//cout << "Current slice date: " << current_slice_date.toString(Date::ISO) 
		//	<< "  value: " << current_station_psum.at(counter) << endl;
		
		double& hnw = vecMeteo[stationindex][jj].hnw;
		//cout << vecMeteo[stationindex][jj].date.toString(Date::ISO) << ": " << hnw;
		if ((hnw == IOUtils::nodata) || (IOUtils::checkEpsilonEquality(hnw, 0.0, 0.001))){
			//replace by psum if there is no own value measured
			hnw = current_station_psum.at(counter);
513
		}
514
		//cout << "  ---> " << hnw << endl;
515
516
517
	}
}

518
519
void ImisIO::getAnetzHNW(const AnetzData& ad, const std::map<std::string, unsigned int>& mapAnetzNames,
                         const std::vector< std::vector<double> >& vec_of_psums, std::vector<double>& psum)
520
521
522
{
	map<string, unsigned int>::const_iterator it;

523
524
525
526
527
528
	vector<unsigned int> vecIndex; //this vector will hold up to three indexes for the Anetz stations (position in vec_of_psums)
	for (unsigned int ii=0; ii<ad.nrOfAnetzStations; ii++){
		it = mapAnetzNames.find(ad.anetzstations[ii]);
		vecIndex.push_back(it->second);
	}

529
530
	if (ad.nrOfAnetzStations == ad.nrOfCoefficients){
		//1, 2, or 3 ANETZ stations without interaction
531
532
533
534
535
536
537
538
		for (unsigned int kk=0; kk<vec_of_psums.at(vecIndex.at(0)).size(); kk++){
			double sum = 0.0;
			for (unsigned int ii=0; ii<ad.nrOfCoefficients; ii++){
				sum += ad.coeffs[ii] * vec_of_psums.at(vecIndex[ii])[kk]; 
			}
			psum.push_back(sum/12.0);

			//cout << kk << " --> sum: " << sum/12 << endl;
539
540
541
542
543
544
		}
	} else {
		if (ad.nrOfCoefficients != 3)
			throw IOException("Misconfiguration in ANETZ data", AT);

		// Exactly two ANETZ stations with one interaction term
545
546
547
548
549
550
551
552
553
554
555
556
557
558
		for (unsigned int kk=0; kk<vec_of_psums.at(vecIndex.at(0)).size(); kk++){
			double sum = 0.0;
			const double& hnw0 = vec_of_psums.at(vecIndex.at(0))[kk];
			const double& hnw1 = vec_of_psums.at(vecIndex.at(1))[kk];
			//cout << "0: Using " << ad.anetzstations[0] << " with hnw: " << hnw0 << endl;
			//cout << "1: Using " << ad.anetzstations[1] << " with hnw: " << hnw1 << endl;
			sum += ad.coeffs[0] * hnw0;
			sum += ad.coeffs[1] * hnw1;
			sum += ad.coeffs[2] * hnw0 * hnw1;

			psum.push_back(sum/12.0);
		}
	}
}
559

560
561
void ImisIO::calculatePsum(const Date& dateStart, const Date& dateEnd,
                           const std::vector< std::vector<MeteoData> >& vecMeteoAnetz,
Mathias Bavay's avatar
Mathias Bavay committed
562
                           std::vector< std::vector<double> >& vec_of_psums)
563
{
564
	const unsigned int nr_of_slices = (unsigned int)((dateEnd.getJulianDate(true) - dateStart.getJulianDate(true) + 0.00001) * 4.0) + 1;
565

566
567
568
	for (unsigned int ii=0; ii<vecMeteoAnetz.size(); ii++){
		double tmp_psum = 0.0;
		Date current_date = dateStart;
569
		current_date.setTimeZone(in_tz);
570
571
572
573
574
575
576

		vector<double> vec_current_station;
		unsigned int counter_of_elements = 0;
		for (unsigned int jj=0; jj<vecMeteoAnetz[ii].size(); jj++){
			const Date& anetzdate = vecMeteoAnetz[ii][jj].date;
			const double& hnw = vecMeteoAnetz[ii][jj].hnw;

577
			if ((current_date < anetzdate) && ((current_date+0.25) > anetzdate)){
578
579
580
581
582
583
				;
			} else {
				if ((counter_of_elements > 0) && (counter_of_elements < 6)) //this is mystical, but kind of a guess of the future
					tmp_psum = tmp_psum * 6.0 / (double)counter_of_elements;

				vec_current_station.push_back(tmp_psum);
584

585
				current_date += 0.25;
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
				tmp_psum = 0.0;
				counter_of_elements = 0;
			}

			if (hnw != IOUtils::nodata){
				tmp_psum += hnw;
				counter_of_elements++;
			}

		}

		if ((counter_of_elements > 0) && (counter_of_elements < 6)) //this is mystical, but kind of a guess of the future
			tmp_psum = tmp_psum*6/counter_of_elements;

		vec_current_station.push_back(tmp_psum);
601
602
603
604
605
606

		for (unsigned int jj=vec_current_station.size(); jj<nr_of_slices; jj++){ //To fill up the vector
			vec_current_station.push_back(0.0);
		}

		vec_of_psums.push_back(vec_current_station);
607
	}
608

609
610
611
612
	for (unsigned int ii=1; ii<vec_of_psums.size(); ii++){
		if (vec_of_psums[ii].size() != vec_of_psums[ii-1].size())
			throw IOException("Error while summing up the precipitation data for the ANETZ stations", AT);
	}
613
614
}

615
void ImisIO::findAnetzStations(const unsigned int& indexStart, const unsigned int& indexEnd,
Fierz's avatar
Fierz committed
616
617
                               std::map<std::string, unsigned int>& mapAnetzNames,
                               std::vector<StationData>& vecAnetzStation)
618
619
{
	set<string> uniqueStations;
Fierz's avatar
Fierz committed
620

621
	for (unsigned int ii=indexStart; ii<indexEnd; ii++){ //loop through stations
Fierz's avatar
Fierz committed
622
		map<string, AnetzData>::const_iterator it = mapAnetz.find(vecStationMetaData.at(ii).getStationID());
623
624
625
626
627
628
629
630
631
632
633
		if (it != mapAnetz.end()){
			for (unsigned int jj=0; jj<it->second.nrOfAnetzStations; jj++){
				uniqueStations.insert(it->second.anetzstations[jj]);
			}
		}
	}

	unsigned int pp = 0;
	for (set<string>::const_iterator ii=uniqueStations.begin(); ii!=uniqueStations.end(); ii++){
		mapAnetzNames[*ii] = pp;
		pp++;
634
635
636
637

		StationData sd;
		sd.stationID = *ii;
		vecAnetzStation.push_back(sd);
638
	}
639
640
641
642
}

/**
 * @brief A meta function to read meteo data for one specific station (specified by the stationindex)
Fierz's avatar
Fierz committed
643
644
645
646
647
648
649
 * @param dateStart     The beginning of the interval to retrieve data for
 * @param dateEnd       The end of the interval to retrieve data for
 * @param vecMeteo      The vector that will hold all MeteoData for each station
 * @param stationindex  The index of the station as specified in the Config
 * @param vecStationIDs Vector of station IDs
 * @param env           Create Oracle environnment
 * @param conn          Create connection to SDB
650
651
 */
void ImisIO::readData(const Date& dateStart, const Date& dateEnd, std::vector< std::vector<MeteoData> >& vecMeteo,
Fierz's avatar
Fierz committed
652
                      const unsigned int& stationindex, const std::vector<StationData>& vecStationIDs,
653
                      oracle::occi::Environment*& env, oracle::occi::Connection*& conn)
654
655
656
{
	vecMeteo.at(stationindex).clear();

Fierz's avatar
Fierz committed
657
	string stat_abk="", stao_nr="";
658
659
660
661
	vector< vector<string> > vecResult;
	vector<int> datestart = vector<int>(5);
	vector<int> dateend   = vector<int>(5);

662
663
	//IMIS is in TZ=+1, so moving back to this timezone
	Date dateS(dateStart), dateE(dateEnd);
664
665
	dateS.setTimeZone(in_tz);
	dateE.setTimeZone(in_tz);
666
667
	dateS.getDate(datestart[0], datestart[1], datestart[2], datestart[3], datestart[4]);
	dateE.getDate(dateend[0], dateend[1], dateend[2], dateend[3], dateend[4]);
668

Fierz's avatar
Fierz committed
669
670
671
672
673
	//get data for one specific station
	std::vector<std::string> vecHts1;
	parseStationID(vecStationIDs.at(stationindex).getStationID(), stat_abk, stao_nr);
	getSensorDepths(stat_abk, stao_nr, sqlQuerySensorDepths, vecHts1, conn);
	bool fullStation = getStationData(stat_abk, stao_nr, datestart, dateend, vecHts1, vecResult, env, conn);
674
675

	MeteoData tmpmd;
Fierz's avatar
Fierz committed
676
	tmpmd.meta = vecStationIDs.at(stationindex);
677
	for (unsigned int ii=0; ii<vecResult.size(); ii++){
Fierz's avatar
Fierz committed
678
		parseDataSet(vecResult[ii], tmpmd, fullStation);
679
		convertUnits(tmpmd);
680

Fierz's avatar
Fierz committed
681
		//For IMIS stations the hnw value is a rate (kg m-2 h-1), therefore we need to
682
		//divide it by two to conjure the accumulated value for the half hour
683
684
		if (tmpmd.meta.stationID.length() > 0){
			if (tmpmd.meta.stationID[0] != '*') //excludes ANETZ stations, they come in hourly sampling
685
686
687
				if (tmpmd.hnw != IOUtils::nodata)
					tmpmd.hnw /= 2; //half hour accumulated value for IMIS stations only
		}
688

689
		vecMeteo.at(stationindex).push_back(tmpmd); //Now insert tmpmd 
690
691
692
693
694
	}
}

/**
 * @brief Puts the data that has been retrieved from the database into a MeteoData object
Fierz's avatar
Fierz committed
695
 * @param i_meteo a row of meteo data from the database (NOTE order important, matches SQL query, see also MeteoData.[cch])
696
 * @param md     the object to copy the data to
Fierz's avatar
Fierz committed
697
698
699
 * @param fullstation
 * 	- true if it is a combined snow_drift station (station2.v_snow_drift_standort)
 * 	- false if it is a "conventional" station, for example an ANETZ-station (station2.standort)
700
 */
Fierz's avatar
Fierz committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
void ImisIO::parseDataSet(const std::vector<std::string>& i_meteo, MeteoData& md, bool& fullStation)
{
	IOUtils::convertString(md.date, i_meteo.at(0), in_tz, dec);
	IOUtils::convertString(md.param(MeteoData::TA),     i_meteo.at(1),  std::dec);
	IOUtils::convertString(md.param(MeteoData::ISWR),   i_meteo.at(2),  std::dec);
	IOUtils::convertString(md.param(MeteoData::VW),     i_meteo.at(3),  std::dec);
	IOUtils::convertString(md.param(MeteoData::DW),     i_meteo.at(4),  std::dec);
	IOUtils::convertString(md.param(MeteoData::VW_MAX), i_meteo.at(5),  std::dec);
	IOUtils::convertString(md.param(MeteoData::RH),     i_meteo.at(6),  std::dec);
	IOUtils::convertString(md.param(MeteoData::ILWR),   i_meteo.at(7),  std::dec);
	IOUtils::convertString(md.param(MeteoData::HNW),    i_meteo.at(8),  std::dec);
	IOUtils::convertString(md.param(MeteoData::TSG),    i_meteo.at(9),  std::dec);
	IOUtils::convertString(md.param(MeteoData::TSS),    i_meteo.at(10),  std::dec);
	IOUtils::convertString(md.param(MeteoData::HS),     i_meteo.at(11), std::dec);
	IOUtils::convertString(md.param(MeteoData::RSWR),   i_meteo.at(12), std::dec);

	unsigned int ii = 13;
	if (fullStation) {
719
		if (!md.param_exists("VW_DRIFT")) md.addParameter("VW_DRIFT");
Fierz's avatar
Fierz committed
720
		IOUtils::convertString(md.param("VW_DRIFT"), i_meteo.at(ii++), std::dec);
721
		if (!md.param_exists("DW_DRIFT")) md.addParameter("DW_DRIFT");
Fierz's avatar
Fierz committed
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
		IOUtils::convertString(md.param("DW_DRIFT"), i_meteo.at(ii++), std::dec);
	}

	// additional snow station parameters
	if (!md.param_exists("ts1")) md.addParameter("ts1");
	IOUtils::convertString(md.param("ts1"), i_meteo.at(ii++), std::dec);
	if (!md.param_exists("ts2")) md.addParameter("ts2");
	IOUtils::convertString(md.param("ts2"), i_meteo.at(ii++), std::dec);
	if (!md.param_exists("ts3")) md.addParameter("ts3");
	IOUtils::convertString(md.param("ts3"), i_meteo.at(ii++), std::dec);
	if (fullStation) {
		if (!md.param_exists("hts1_1")) md.addParameter("hts1_1");
		IOUtils::convertString(md.param("hts1_1"), i_meteo.at(ii++), std::dec);
		if (!md.param_exists("hts1_2")) md.addParameter("hts1_2");
		IOUtils::convertString(md.param("hts1_2"), i_meteo.at(ii++), std::dec);
		if (!md.param_exists("hts1_3")) md.addParameter("hts1_3");
		IOUtils::convertString(md.param("hts1_3"), i_meteo.at(ii++), std::dec);
739
	}
740
741
742
}

/**
Fierz's avatar
Fierz committed
743
744
745
746
747
 * @brief This function gets IDs from table station2.v_snow_drift_standort and fills vecStationIDs
 * @param station_code  a string key corresponding to stationID
 * @param vecStationIDs string vector in which data will be filled
 * @param conn          create connection to SDB
 * @param return number of columns retrieved
748
 */
Fierz's avatar
Fierz committed
749
750
751
unsigned int ImisIO::getStationIDs(const std::string& station_code, const std::string& sqlQuery,
                                   std::vector<std::string>& vecStationIDs,
                                   oracle::occi::Connection*& conn)
752
{
Fierz's avatar
Fierz committed
753
	vecStationIDs.clear();
754
755

	try {
Fierz's avatar
Fierz committed
756
		Statement *stmt = conn->createStatement(sqlQuery);
757
758
		ResultSet *rs = NULL;

Fierz's avatar
Fierz committed
759
760
761
762
763
764
765
766
767
768
769
		stmt->setString(1, station_code); // set 1st variable's value

		rs = stmt->executeQuery();    // execute the statement stmt
		vector<MetaData> cols = rs->getColumnListMetaData();

		while (rs->next() == true) {
			for (unsigned int ii=1; ii<=cols.size(); ii++) {
				vecStationIDs.push_back(rs->getString(ii));
			}
		}

770
771
772
773
774
775
776
777
		if (vecStationIDs.size() < 3) {
			string stat_abk="", stao_nr="";
			parseStationID(station_code, stat_abk, stao_nr);
			vecStationIDs.push_back(station_code);
			vecStationIDs.push_back(stat_abk);
			vecStationIDs.push_back(stao_nr);
		}

Fierz's avatar
Fierz committed
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
		stmt->closeResultSet(rs);
		conn->terminateStatement(stmt);
		return cols.size();
	} catch (exception& e){
		throw IOException(string(e.what()), AT); //Translation of OCCI exception to IOException
	}
}

/**
 * @brief This function gets IDs from table station2.v_snow_drift_standort and fills vecStationIDs
 * @param stat_abk a string key of table station2
 * @param stao_nr  a string key of table station2
 * @param veHts1   vector of string to retieve sensor depths
 * @param conn     create connection to SDB
 * @param return number of columns retrieved
 */
unsigned int ImisIO::getSensorDepths(const std::string& stat_abk, const std::string& stao_nr,
                                     const std::string& sqlQuery, std::vector<std::string>& vecHts1,
                                     oracle::occi::Connection*& conn)
{
	vecHts1.clear();

	try {
		Statement *stmt = conn->createStatement(sqlQuery);
		ResultSet *rs = NULL;
		
804
805
		stmt->setString(1, stat_abk); // set 1st variable's value
		stmt->setString(2, stao_nr);  // set 2nd variable's value
Fierz's avatar
Fierz committed
806

807
		rs = stmt->executeQuery();    // execute the statement stmt
Fierz's avatar
Fierz committed
808
		vector<MetaData> cols = rs->getColumnListMetaData();
809
810

		while (rs->next() == true) {
Fierz's avatar
Fierz committed
811
812
			for (unsigned int ii=1; ii<=cols.size(); ii++) {
				vecHts1.push_back(rs->getString(ii));
813
814
815
816
817
			}
		}

		stmt->closeResultSet(rs);
		conn->terminateStatement(stmt);
Fierz's avatar
Fierz committed
818
		return cols.size();
819
	} catch (exception& e){
820
		throw IOException(string(e.what()), AT); //Translation of OCCI exception to IOException
821
822
823
824
	}
}

/**
Fierz's avatar
Fierz committed
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
 * @brief This function gets meta data from table station2.standort and fills vecStationMetaData
 * @param stat_abk           a string key of table
 * @param stao_nr            a string key of table
 * @param sqlQuery           the query to execute
 * @param vecStationMetaData string vector in which data will be filled
 * @param conn               create connection to SDB
 * @param return             number of columns retrieved
 */
unsigned int ImisIO::getStationMetaData(const std::string& stat_abk, const std::string& stao_nr,
                                        const std::string& sqlQuery, std::vector<std::string>& vecStationMetaData,
                                        oracle::occi::Connection*& conn)
{
	vecStationMetaData.clear();

	try {
		Statement *stmt = conn->createStatement(sqlQuery);
		ResultSet *rs = NULL;

		stmt->setString(1, stat_abk); // set 1st variable's value
		stmt->setString(2, stao_nr);  // set 2nd variable's value

		rs = stmt->executeQuery();    // execute the statement stmt
		vector<MetaData> cols = rs->getColumnListMetaData();

		while (rs->next() == true) {
			for (unsigned int ii=1; ii<=cols.size(); ii++) {
				vecStationMetaData.push_back(rs->getString(ii));
			}
		}

		stmt->closeResultSet(rs);
		conn->terminateStatement(stmt);
		return cols.size();
	} catch (exception& e){
		throw IOException(string(e.what()), AT); //Translation of OCCI exception to IOException
	}
}

/**
 * @brief Gets data from ams.v_ams_raw which is a table of SDB and
 * retrieves the temperature sensor depths from station2.standort \n
 * Each record returned are vector of strings which are pushed back in vecMeteoData.
 * @param stat_abk :     a string key of ams.v_ams_raw
 * @param stao_nr :      a string key of ams.v_ams_raw
869
870
871
 * @param datestart :    a vector of five(5) integer corresponding to the recording date
 * @param dateend :      a vector of five(5) integer corresponding to the recording date
 * @param vecMeteoData : a vector of vector of string in which data will be filled
Fierz's avatar
Fierz committed
872
 * @param return number of columns retrieved
873
 */
Fierz's avatar
Fierz committed
874
875
876
877
878
bool ImisIO::getStationData(const std::string& stat_abk, const std::string& stao_nr,
                            const std::vector<int>& datestart, const std::vector<int>& dateend,
                            const std::vector<std::string>& vecHts1,
                            std::vector< std::vector<std::string> >& vecMeteoData,
                            oracle::occi::Environment*& env, oracle::occi::Connection*& conn)
879
880
{
	vecMeteoData.clear();
Fierz's avatar
Fierz committed
881
	bool fullStation = true;
882

883
884
885
	try {
		Statement *stmt = NULL;
		ResultSet *rs = NULL;
Fierz's avatar
Fierz committed
886
887
888

		map<string, string>::const_iterator it = mapDriftStation.find(stat_abk+stao_nr);
		if (it != mapDriftStation.end()) {
889
			stmt = conn->createStatement(sqlQueryMeteoDataDrift);
Fierz's avatar
Fierz committed
890
891
892
893
894
895
896
			string drift_stat_abk="", drift_stao_nr="";
			parseStationID(it->second, drift_stat_abk, drift_stao_nr);
			stmt->setString(5, drift_stat_abk);
			stmt->setString(6, drift_stao_nr);
		} else {
			stmt = conn->createStatement(sqlQueryMeteoData);
			fullStation = false;
897
		}
898
899
900
901
902
903
904

		// construct the oracle specific Date object: year, month, day, hour, minutes
		occi::Date begindate(env, datestart[0], datestart[1], datestart[2], datestart[3], datestart[4]);
		occi::Date enddate(env, dateend[0], dateend[1], dateend[2], dateend[3], dateend[4]);
		stmt->setString(1, stat_abk); // set 1st variable's value (station name)
		stmt->setString(2, stao_nr);  // set 2nd variable's value (station number)
		stmt->setDate(3, begindate);  // set 3rd variable's value (begin date)
Fierz's avatar
Fierz committed
905
		stmt->setDate(4, enddate);    // set 4th variable's value (end date)
906

907
		rs = stmt->executeQuery(); // execute the statement stmt
Fierz's avatar
Fierz committed
908
		vector<MetaData> cols = rs->getColumnListMetaData();
909

Fierz's avatar
Fierz committed
910
		vector<string> vecData;
911
		while (rs->next() == true) {
Fierz's avatar
Fierz committed
912
913
914
			vecData.clear();
			for (unsigned int ii=1; ii<=cols.size(); ii++) {
				vecData.push_back(rs->getString(ii));
915
			}
Fierz's avatar
Fierz committed
916
917
918
919
920
921
			if (fullStation) {
				for (unsigned int ii=0; ii<vecHts1.size(); ii++) {
					vecData.push_back(vecHts1.at(ii));
				}
			}
			vecMeteoData.push_back(vecData);
922
923
924
925
		}

		stmt->closeResultSet(rs);
		conn->terminateStatement(stmt);
Fierz's avatar
Fierz committed
926
		return fullStation;
927
	} catch (exception& e){
928
		throw IOException(string(e.what()), AT); //Translation of OCCI exception to IOException
929
930
931
	}
}

Fierz's avatar
Fierz committed
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
void ImisIO::convertSnowTemperature(MeteoData& meteo, const std::string& parameter)
{
	if (meteo.param_exists(parameter)) {
		const unsigned int idx = meteo.getParameterIndex(parameter);
		if(meteo.param(idx)!=IOUtils::nodata)
			meteo.param(idx) += Cst::t_water_freezing_pt; //C_TO_K
	}
}

void ImisIO::convertSensorDepth(MeteoData& meteo, const std::string& parameter)
{
	if (meteo.param_exists(parameter)) {
		const unsigned int idx = meteo.getParameterIndex(parameter);
		if(meteo.param(idx)!=IOUtils::nodata)
			meteo.param(idx) /= 100.; // centimetre to metre
	}
}

950
951
952
953
void ImisIO::convertUnits(MeteoData& meteo)
{
	meteo.standardizeNodata(plugin_nodata);

Fierz's avatar
Fierz committed
954
	//converts degC to kelvin, converts ilwr to ea, converts RH to [0,1], cm to m
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
	if(meteo.ta!=IOUtils::nodata) {
		meteo.ta=C_TO_K(meteo.ta);
	}

	if(meteo.tsg!=IOUtils::nodata) {
		meteo.tsg=C_TO_K(meteo.tsg);
	}

	if(meteo.tss!=IOUtils::nodata) {
		meteo.tss=C_TO_K(meteo.tss);
	}

	if(meteo.rh!=IOUtils::nodata) {
		meteo.rh /= 100.;
	}
970
971
972

	if(meteo.hs!=IOUtils::nodata)
		meteo.hs /= 100.0;
973

Fierz's avatar
Fierz committed
974
975
976
977
978
979
980
	//convert extra parameters (if present) //HACK TODO: find a dynamic way...
	convertSnowTemperature(meteo, "ts1");
	convertSnowTemperature(meteo, "ts2");
	convertSnowTemperature(meteo, "ts3");
	convertSensorDepth(meteo, "hts1_1");
	convertSensorDepth(meteo, "hts1_2");
	convertSensorDepth(meteo, "hts1_3");
981
982
983
984
985
986
987
988
989
}

void ImisIO::cleanup() throw()
{
}

#ifndef _METEOIO_JNI
extern "C"
{
990
991
992
#define COMPILE_PLUGIN
#include "exports.h"

993
	//using namespace MeteoIO;
994
	METEOIO_EXPORT void deleteObject(void* obj) {
995
996
997
		delete reinterpret_cast<PluginObject*>(obj);
	}

998
	METEOIO_EXPORT void* loadObject(const string& classname, const Config& cfg) {
999
1000
		if(classname == "ImisIO") {
			//cerr << "Creating dynamic handle for " << classname << endl;
For faster browsing, not all history is shown. View entire blame