WSL/SLF GitLab Repository

ImisIO.cc 47 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/***********************************************************************************/
/*  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/>.
*/
18
#include <meteoio/plugins/ImisIO.h>
19
20
#include <meteoio/IOUtils.h>
#include <meteoio/IOExceptions.h>
21
#include <meteoio/meteoLaws/Meteoconst.h>
22
#include <meteoio/meteoLaws/Atmosphere.h> //for p_sea to p_local conversion
23
#include <meteoio/MathOptim.h>
24

25
26
27
28
29
#include <sstream>
#include <set>
#include <iostream>
#include <ctime>

30
31
32
using namespace std;
using namespace oracle;
using namespace oracle::occi;
Fierz's avatar
Fierz committed
33
using namespace mio;
34
35
36
37
38

namespace mio {
/**
 * @page imis IMIS
 * @section imis_format Format
39
 * This plugin reads data directly from the IMIS network database (Oracle database).
40
 * It retrieves standard IMIS data as well as ENETZ and ANETZ data.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 *
 * @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
 * - STATION#: station code for the given number #
60
 * - USEANETZ: use ANETZ stations to provide precipitations for normal IMIS stations. Almost each IMIS station is associated with one or two ANETZ stations and does a weighted average to get what should be its local precipitations if no local precipitation has been found (either nodata or 0).
61
62
 * - USE_IMIS_PSUM: if set to false (default), all IMIS precipitation will be deleted (since IMIS stations don't have heated rain gauges, their precipitation measurements are not good in winter conditions). If set to true, the precipitation measurements will be accepted from IMIS stations. In this case, it is strongly advised to apply the filter FilterUnheatedPSUM to detect snow melting in the rain gauge.
 * - USE_SNOWPACK_PSUM: if set to true, the SNOWPACK simulated Snow Water Equivalent from the database will be used to compute PSUM. Data gaps greater than 3 hours on SWE will lead to unchanged psum while all data that can properly be computed will <b>overwrite</b> psum. (default=false)
63
 *
64
65
 * It is possible to use both USE_IMIS_PSUM and USE_SNOWPACK_PSUM to create composite PSUM (from SNOWPACK in the snow season and from IMIS otherwise).
 * In such a case, as soon as SNOWPACK SWE > 0, all previous PSUM data will be deleted (ie those potentially coming from IMIS_PSUM).
66
 * But if there is no SNOWPACK data, the IMIS measurements will be kept.
67
68
 */

Fierz's avatar
Fierz committed
69
70
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;-)
71

Fierz's avatar
Fierz committed
72
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
73

74
const string ImisIO::sqlQueryStationMetaData = "SELECT stao_name, stao_x, stao_y, stao_h FROM station2.v_station_standort WHERE stat_abk LIKE :1 AND stao_nr=:2"; ///< Snow station meta data
75

76
const string ImisIO::sqlQuerySensorDepths = "SELECT hts1_1, hts1_2, hts1_3 FROM station2.v_station_standort WHERE stat_abk LIKE :1 AND stao_nr=:2"; ///< Sensor depths at station
77

78
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, a.ap, 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]
Fierz's avatar
Fierz committed
79

80
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, ap, 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
81

82
const string ImisIO::sqlQuerySWEData = "SELECT TO_CHAR(datum, 'YYYY-MM-DD HH24:MI') AS thedate, swe FROM snowpack.ams_pmod WHERE stat_abk=:1 AND stao_nr=:2 AND datum>=:3 AND datum<=:4 ORDER BY thedate ASC"; ///< Query SWE as calculated by SNOWPACK to feed into PSUM
83

84
85
86
87
88
89
std::map<std::string, AnetzData> ImisIO::mapAnetz;
const bool ImisIO::__init = ImisIO::initStaticData();

bool ImisIO::initStaticData()
{
	//Associate string with AnetzData
90
	//map[station ID] = (#stations, STA1, STA2, STA3, #coeffs, coeff1, coeff2, coeff3)
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
166
167
168
169
170
171
172
173
174
175
176
	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);
177
	mapAnetz["WFJ2"] = AnetzData(1,"*WFJ","","",1,1.,IOUtils::nodata,IOUtils::nodata);
178
179
180
181
182
183
184
	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;
}

185
186
187
188
189
void ImisIO::getDBParameters()
{
	cfg.getValue("DBNAME", "Input", oracleDBName_in);
	cfg.getValue("DBUSER", "Input", oracleUserName_in);
	cfg.getValue("DBPASS", "Input", oraclePassword_in);
190

191
	cfg.getValue("USEANETZ", "Input", useAnetz, IOUtils::nothrow);
192
193
	cfg.getValue("USE_IMIS_PSUM", "Input", use_imis_psum, IOUtils::nothrow);
	cfg.getValue("USE_SNOWPACK_PSUM", "Input", use_psum_snowpack, IOUtils::nothrow);
194
195
}

196
197
ImisIO::ImisIO(const std::string& configfile)
        : cfg(configfile), coordin(), coordinparam(), coordout(), coordoutparam(), vecStationMetaData(), mapDriftStation(),
198
          oracleUserName_in(), oraclePassword_in(), oracleDBName_in(), useAnetz(false), use_imis_psum(false), use_psum_snowpack(false)
199
200
201
202
203
{
	IOUtils::getProjectionParameters(cfg, coordin, coordinparam, coordout, coordoutparam);
	getDBParameters();
}

204
205
ImisIO::ImisIO(const Config& cfgreader)
        : cfg(cfgreader), coordin(), coordinparam(), coordout(), coordoutparam(), vecStationMetaData(), mapDriftStation(),
206
          oracleUserName_in(), oraclePassword_in(), oracleDBName_in(), useAnetz(false), use_imis_psum(false), use_psum_snowpack(false)
207
208
209
210
211
{
	IOUtils::getProjectionParameters(cfg, coordin, coordinparam, coordout, coordoutparam);
	getDBParameters();
}

212
213
214
215
216
217
218
219
220
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 {
221
222
		if (conn != NULL)
			env->terminateConnection(conn);
223
		Environment::terminateEnvironment(env); // static OCCI function
224
	} catch (const exception&){
225
226
227
228
		Environment::terminateEnvironment(env); // static OCCI function
	}
}

229
230
231
232
void ImisIO::readStationData(const Date&, std::vector<StationData>& vecStation)
{
	vecStation.clear();

233
	if (vecStationMetaData.empty()){//Imis station meta data cannot change between time steps
234
235
236
237
238
		Environment *env = NULL;
		Connection *conn = NULL;

		try {
			openDBConnection(env, conn);
Fierz's avatar
Fierz committed
239
			readStationMetaData(conn); //reads all the station meta data into the vecStationMetaData (member vector)
240
			closeDBConnection(env, conn);
241
		} catch (const exception& e){
242
			closeDBConnection(env, conn);
243
			throw IOException("Oracle Error when reading stations' metedata: " + string(e.what()), AT); //Translation of OCCI exception to IOException
244
245
		}
	}
246

Fierz's avatar
Fierz committed
247
	vecStation = vecStationMetaData; //vecStationMetaData is a global vector holding all meta data
248
249
250
}

/**
251
 * @brief A meta function that extracts all station names from the Config,
Fierz's avatar
Fierz committed
252
 *        parses them and retrieves all meta data from SDB
253
 */
254
void ImisIO::readStationMetaData(oracle::occi::Connection*& conn)
255
{
256
	std::vector<std::string> vecStationID;
Fierz's avatar
Fierz committed
257
258
	readStationIDs(vecStationID);

259
	Statement *stmt = conn->createStatement();
260
	for (size_t ii=0; ii<vecStationID.size(); ii++) {
Fierz's avatar
Fierz committed
261
		// Retrieve the station IDs - this only needs to be done once per instance
262
		std::string stat_abk, stao_nr, station_name;
Fierz's avatar
Fierz committed
263
		parseStationID(vecStationID[ii], stat_abk, stao_nr);
264
265
		
		//Retrieve the drift station - this only needs to be done once per instance
266
267
		std::vector<std::string> stnDrift;
		std::string drift_stat_abk, drift_stao_nr;
268
269
270
271
		getStationIDs(vecStationID[ii], sqlQueryStationIDs, stnDrift, stmt);
		IOUtils::convertString(station_name, stnDrift.at(0));
		IOUtils::convertString(drift_stat_abk, stnDrift.at(1));
		IOUtils::convertString(drift_stao_nr, stnDrift.at(2));
272
		const std::string drift_stationID( drift_stat_abk + drift_stao_nr );
273
		if (!drift_stationID.empty())
274
			mapDriftStation[vecStationID[ii]] = drift_stationID;
275
276
		else
			std::cerr << "[W] No drift station for station " << stat_abk << stao_nr << "\n";
277

Fierz's avatar
Fierz committed
278
		// Retrieve the station meta data - this only needs to be done once per instance
279
280
		std::vector<std::string> stationMetaData;
		std::string stao_name;
281
		getStationMetaData(stat_abk, stao_nr, sqlQueryStationMetaData, stationMetaData, stmt);
282
		double east, north, alt;
283
284
285
286
		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);
287

288
		//obtain a valid station_name w/o spaces within
289
290
		if (station_name.empty()) {
			if (!stao_name.empty()) {
Fierz's avatar
Fierz committed
291
292
293
294
295
296
297
				station_name += vecStationID[ii] + ":" + stao_name;
			} else {
				station_name += vecStationID[ii];
			}
		} else {
			vector<string> tmpname;
			IOUtils::readLineToVec(station_name, tmpname, ' ');
298
			size_t jj=1;
Fierz's avatar
Fierz committed
299
300
301
302
303
304
305
306
307
308
309
310
			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);
		}
311
312
		Coords myCoord(coordin, coordinparam);
		myCoord.setXY(east, north, alt);
313
		vecStationMetaData.push_back( StationData(myCoord, vecStationID[ii], station_name) );
314
	}
315
	conn->terminateStatement(stmt);
316
317
318
}

/**
319
320
 * @brief This function breaks up the station name into two components (a string and a number e.g. KLO2 -> "KLO","2"). For 
 * Enet stations (such as *WFJ), the numeric part is asusmed to be 1 (ie: the automatic station).
Fierz's avatar
Fierz committed
321
 * @param stationID The full name of the station (e.g. "KLO2")
322
323
324
 * @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
325
void ImisIO::parseStationID(const std::string& stationID, std::string& stat_abk, std::string& stao_nr)
326
{
Fierz's avatar
Fierz committed
327
328
	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
329
	if (!std::isdigit(stao_nr[0])) {
330
		//the station is one of these non-imis stations that don't contain a number...
Fierz's avatar
Fierz committed
331
		stat_abk = stationID;
332
		stao_nr = "1";
333
	}
334
335
336
}

/**
337
 * @brief This function extracts all info about the stations that are to be used from global Config object
Fierz's avatar
Fierz committed
338
 * @param vecStationID A vector that will hold all relevant stations as std::strings
339
 */
Fierz's avatar
Fierz committed
340
void ImisIO::readStationIDs(std::vector<std::string>& vecStationID)
341
{
Fierz's avatar
Fierz committed
342
	vecStationID.clear();
343
	cfg.getValues("STATION", "INPUT", vecStationID);
344

345
	if (vecStationID.empty()) {
346
347
		cerr << "\tNo stations specified for IMISIO... is this what you want?\n";
	}
348
349
}

Fierz's avatar
Fierz committed
350
void ImisIO::readMeteoData(const Date& dateStart, const Date& dateEnd,
351
                           std::vector< std::vector<MeteoData> >& vecMeteo)
352
{
353
354
	Environment *env = NULL;
	Connection *conn = NULL;
355
	Statement *stmt = NULL;
356

357
	try {
358
		if (vecStationMetaData.empty()) {
359
			openDBConnection(env, conn);
Fierz's avatar
Fierz committed
360
			readStationMetaData(conn); //reads all the station meta data into the vecStationMetaData (member vector)
361
		}
362

363
		if (vecStationMetaData.empty()) { //if there are no stations -> return
364
365
366
			if ((env != NULL) || (conn != NULL)) closeDBConnection(env, conn);
			return;
		}
367

368
		size_t indexStart=0, indexEnd=vecStationMetaData.size();
369

370
		//The following part decides whether all the stations are rebuffered or just one station
371
372
		vecMeteo.clear();
		vecMeteo.insert(vecMeteo.begin(), vecStationMetaData.size(), vector<MeteoData>());
373

374
375
		if ((env == NULL) || (conn == NULL))
			openDBConnection(env, conn);
376
		stmt = conn->createStatement();
377

378
		for (size_t ii=indexStart; ii<indexEnd; ii++) { //loop through relevant stations
379
			readData(dateStart, dateEnd, vecMeteo, ii, vecStationMetaData, env, stmt);
Fierz's avatar
Fierz committed
380
		}
381

Fierz's avatar
Fierz committed
382
		if (useAnetz) { //Important: we don't care about the metadata for ANETZ stations
383
384
			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
385
			map<string, size_t> mapAnetzNames;   //associates an ANETZ station with an index within vecMeteoAnetz
386

387
388
389
			findAnetzStations(indexStart, indexEnd, mapAnetzNames, vecAnetzStation);
			vecMeteoAnetz.insert(vecMeteoAnetz.begin(), vecAnetzStation.size(), vector<MeteoData>());

390
			//date_anetz_start/end must be changed to be a multiple of 6h before the original dateStart, dateEnd
391
			Date date_anetz_start = Date(floor(dateStart.getJulian(true) * 4.0) / 4.0, 0.);
392
			date_anetz_start.setTimeZone(in_tz);
393
			Date date_anetz_end   = Date(floor(dateEnd.getJulian(true) * 4.0) / 4.0, 0.);
394
			date_anetz_end.setTimeZone(in_tz);
395
396

			//read Anetz Data
397
			for (size_t ii=0; ii<vecAnetzStation.size(); ii++)
398
				readData(date_anetz_start, dateEnd, vecMeteoAnetz, ii, vecAnetzStation, env, stmt);
399

400
			//We got all the data, now calc psum for all ANETZ stations
401
			vector< vector<double> > vec_of_psums; //6 hour accumulations of psum
402
403
			calculatePsum(date_anetz_start, date_anetz_end, vecMeteoAnetz, vec_of_psums);

404
			for (size_t ii=indexStart; ii<indexEnd; ii++){ //loop through relevant stations
405
				const map<string,AnetzData>::const_iterator it = mapAnetz.find(vecStationMetaData.at(ii).getStationID());
406
407
408
				if (it != mapAnetz.end())
					assimilateAnetzData(date_anetz_start, it->second, vec_of_psums, mapAnetzNames, ii, vecMeteo);
			}
409
410
		}

411
		if (use_psum_snowpack) {
412
			for (size_t ii=indexStart; ii<indexEnd; ii++) { //loop through relevant stations
413
				readSWE(dateStart, dateEnd, vecMeteo, ii, vecStationMetaData, env, stmt);
414
415
416
			}
		}

417
		conn->terminateStatement(stmt);
418
		closeDBConnection(env, conn);
419
	} catch (const exception& e){
420
		closeDBConnection(env, conn);
421
		throw IOException("Oracle Error when reading stations' data: " + string(e.what()), AT); //Translation of OCCI exception to IOException
422
423
424
	}
}

425
void ImisIO::assimilateAnetzData(const Date& dateStart, const AnetzData& ad,
426
                                 const std::vector< std::vector<double> > vec_of_psums,
427
                                 const std::map<std::string, size_t>& mapAnetzNames, const size_t& stationindex,
428
                                 std::vector< std::vector<MeteoData> >& vecMeteo)
429
{
430
	//Do coefficient calculation (getPSUM) for every single station and data point
431
	vector<double> current_station_psum;
432
	getAnetzPSUM(ad, mapAnetzNames, vec_of_psums, current_station_psum);
433

434
	size_t counter = 0;
435
	Date current_slice_date = dateStart;
436
	current_slice_date.setTimeZone(in_tz);
437
	for (size_t jj=0; jj<vecMeteo[stationindex].size(); jj++){
438
		while (vecMeteo[stationindex][jj].date > (current_slice_date+0.2485)){
439
			counter++;
440
			const double julian = floor((current_slice_date.getJulian(true) +0.25001) * 4.0) / 4.0;
441
442
			current_slice_date = Date(julian, 0.);
			current_slice_date.setTimeZone(in_tz);
443
		}
444

445
		if (counter >= current_station_psum.size()) { break; } //should never happen
446

447
448
		double& psum = vecMeteo[stationindex][jj](MeteoData::PSUM);
		if ((psum == IOUtils::nodata) || (IOUtils::checkEpsilonEquality(psum, 0.0, 0.001))){
449
			//replace by psum if there is no own value measured
450
			psum = current_station_psum.at(counter);
451
452
453
454
		}
	}
}

455
void ImisIO::getAnetzPSUM(const AnetzData& ad, const std::map<std::string, size_t>& mapAnetzNames,
456
                         const std::vector< std::vector<double> >& vec_of_psums, std::vector<double>& psum)
457
{
458
459
	vector<size_t> vecIndex; //this vector will hold up to three indexes for the Anetz stations (position in vec_of_psums)
	for (size_t ii=0; ii<ad.nrOfAnetzStations; ii++){
460
		const map<string, size_t>::const_iterator it = mapAnetzNames.find(ad.anetzstations[ii]);
461
462
463
		vecIndex.push_back(it->second);
	}

464
465
	if (ad.nrOfAnetzStations == ad.nrOfCoefficients){
		//1, 2, or 3 ANETZ stations without interaction
466
		for (size_t kk=0; kk<vec_of_psums.at(vecIndex.at(0)).size(); kk++){
467
			double sum = 0.0;
468
			for (size_t ii=0; ii<ad.nrOfCoefficients; ii++){
469
				sum += ad.coeffs[ii] * vec_of_psums.at(vecIndex[ii])[kk];
470
471
			}
			psum.push_back(sum/12.0);
472
473
474
475
476
477
		}
	} else {
		if (ad.nrOfCoefficients != 3)
			throw IOException("Misconfiguration in ANETZ data", AT);

		// Exactly two ANETZ stations with one interaction term
478
		for (size_t kk=0; kk<vec_of_psums.at(vecIndex.at(0)).size(); kk++){
479
			double sum = 0.0;
480
481
482
483
484
			const double& psum0 = vec_of_psums.at(vecIndex.at(0))[kk];
			const double& psum1 = vec_of_psums.at(vecIndex.at(1))[kk];
			sum += ad.coeffs[0] * psum0;
			sum += ad.coeffs[1] * psum1;
			sum += ad.coeffs[2] * psum0 * psum1;
485
486
487
488
489

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

491
492
void ImisIO::calculatePsum(const Date& dateStart, const Date& dateEnd,
                           const std::vector< std::vector<MeteoData> >& vecMeteoAnetz,
Mathias Bavay's avatar
Mathias Bavay committed
493
                           std::vector< std::vector<double> >& vec_of_psums)
494
{
495
	const unsigned int nr_of_slices = (unsigned int)((dateEnd.getJulian(true) - dateStart.getJulian(true) + 0.00001) * 4.0) + 1;
496

497
	for (size_t ii=0; ii<vecMeteoAnetz.size(); ii++){
498
499
		double tmp_psum = 0.0;
		Date current_date = dateStart;
500
		current_date.setTimeZone(in_tz);
501
502

		vector<double> vec_current_station;
503
504
		size_t counter_of_elements = 0;
		for (size_t jj=0; jj<vecMeteoAnetz[ii].size(); jj++){
505
			const Date& anetzdate = vecMeteoAnetz[ii][jj].date;
506
			const double& psum = vecMeteoAnetz[ii][jj](MeteoData::PSUM);
507

508
			if ((current_date < anetzdate) && ((current_date+0.25) > anetzdate)){
509
510
511
512
513
514
				;
			} 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);
515

516
				current_date += 0.25;
517
518
519
520
				tmp_psum = 0.0;
				counter_of_elements = 0;
			}

521
522
			if (psum != IOUtils::nodata){
				tmp_psum += psum;
523
524
525
526
527
528
				counter_of_elements++;
			}

		}

		if ((counter_of_elements > 0) && (counter_of_elements < 6)) //this is mystical, but kind of a guess of the future
Mathias Bavay's avatar
Mathias Bavay committed
529
			tmp_psum = tmp_psum*6./static_cast<double>(counter_of_elements);
530
531

		vec_current_station.push_back(tmp_psum);
532

533
		for (size_t jj=vec_current_station.size(); jj<nr_of_slices; jj++){ //To fill up the vector
534
535
536
537
			vec_current_station.push_back(0.0);
		}

		vec_of_psums.push_back(vec_current_station);
538
	}
539

540
	for (size_t ii=1; ii<vec_of_psums.size(); ii++){
541
542
543
		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);
	}
544
545
}

546
547
void ImisIO::findAnetzStations(const size_t& indexStart, const size_t& indexEnd,
                               std::map<std::string, size_t>& mapAnetzNames,
Fierz's avatar
Fierz committed
548
                               std::vector<StationData>& vecAnetzStation)
549
550
{
	set<string> uniqueStations;
Fierz's avatar
Fierz committed
551

552
	for (size_t ii=indexStart; ii<indexEnd; ii++){ //loop through stations
553
		const map<string, AnetzData>::const_iterator it = mapAnetz.find(vecStationMetaData.at(ii).getStationID());
554
		if (it != mapAnetz.end()){
555
			for (size_t jj=0; jj<it->second.nrOfAnetzStations; jj++){
556
557
558
559
560
				uniqueStations.insert(it->second.anetzstations[jj]);
			}
		}
	}

561
	size_t pp = 0;
562
563
564
	for (set<string>::const_iterator ii=uniqueStations.begin(); ii!=uniqueStations.end(); ii++){
		mapAnetzNames[*ii] = pp;
		pp++;
565
566
567
568

		StationData sd;
		sd.stationID = *ii;
		vecAnetzStation.push_back(sd);
569
	}
570
571
572
573
}

/**
 * @brief A meta function to read meteo data for one specific station (specified by the stationindex)
Fierz's avatar
Fierz committed
574
575
576
577
578
579
580
 * @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
581
582
 */
void ImisIO::readData(const Date& dateStart, const Date& dateEnd, std::vector< std::vector<MeteoData> >& vecMeteo,
583
                      const size_t& stationindex, const std::vector<StationData>& vecStationIDs,
584
                      oracle::occi::Environment*& env, oracle::occi::Statement*& stmt)
585
586
587
{
	vecMeteo.at(stationindex).clear();

588
	string stat_abk, stao_nr;
589
590
	vector< vector<string> > vecResult;

591
	// Moving back to the IMIS timezone (UTC+1)
592
	Date dateS(dateStart), dateE(dateEnd);
593
594
	dateS.setTimeZone(in_tz);
	dateE.setTimeZone(in_tz);
595

Fierz's avatar
Fierz committed
596
	//get data for one specific station
597
	std::vector<std::string> vecHTS1;
Fierz's avatar
Fierz committed
598
	parseStationID(vecStationIDs.at(stationindex).getStationID(), stat_abk, stao_nr);
599
600
	getSensorDepths(stat_abk, stao_nr, sqlQuerySensorDepths, vecHTS1, stmt);
	bool fullStation = getStationData(stat_abk, stao_nr, dateS, dateE, vecHTS1, vecResult, env, stmt);
601
602

	MeteoData tmpmd;
Fierz's avatar
Fierz committed
603
	tmpmd.meta = vecStationIDs.at(stationindex);
604
	for (size_t ii=0; ii<vecResult.size(); ii++){
Fierz's avatar
Fierz committed
605
		parseDataSet(vecResult[ii], tmpmd, fullStation);
606
		convertUnits(tmpmd);
607

608
		//For IMIS stations the psum value is a rate (kg m-2 h-1), therefore we need to
609
		//divide it by two to conjure the accumulated value for the half hour
610
		if (tmpmd.meta.stationID.length() > 0){
611
			if (tmpmd.meta.stationID[0] != '*') { //only consider IMIS stations (ie: not ANETZ)
612
				if (use_imis_psum==false) {
613
					tmpmd(MeteoData::PSUM) = IOUtils::nodata;
614
				} else {
615
					double& psum = tmpmd(MeteoData::PSUM);
616
					if (psum!=IOUtils::nodata) {
617
						psum /= 2.; //half hour accumulated value for IMIS stations only
618
					}
619
620
				}
			}
621
		}
622

623
		vecMeteo.at(stationindex).push_back(tmpmd); //Now insert tmpmd
624
625
626
	}
}

627
/**
628
 * @brief Read simulated SWE from the database, compute Delta(SWE) and use it as PSUM for one specific station (specified by the stationindex)
629
630
631
632
633
634
635
636
637
638
 * @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
 */
void ImisIO::readSWE(const Date& dateStart, const Date& dateEnd, std::vector< std::vector<MeteoData> >& vecMeteo,
                      const size_t& stationindex, const std::vector<StationData>& vecStationIDs,
639
                      oracle::occi::Environment*& env, oracle::occi::Statement*& stmt)
640
{
641
642
643
	const double max_interval = 3./24.; //max hours between two SWE values
	const double swe_threshold = 1.5; //precip less than this are delayed until its sum gets greater
	const double eps_swe = 0.1; //very small variations on SWE are simply ignored
644
645
646
647
648
649
650

	// Moving back to the IMIS timezone (UTC+1)
	Date dateS(dateStart), dateE(dateEnd);
	dateS.setTimeZone(in_tz);
	dateE.setTimeZone(in_tz);

	//build stat_abk and stao_nr from station name
651
	string stat_abk, stao_nr;
652
653
	parseStationID(vecStationIDs.at(stationindex).getStationID(), stat_abk, stao_nr);

Mathias Bavay's avatar
Mathias Bavay committed
654
	const unsigned int max_row = static_cast<unsigned int>( Optim::ceil( (dateE.getJulian()-dateS.getJulian())*24.*2. ) ); //for prefetching
655

656
657
	//query
	try {
658
		stmt->setSQL(sqlQuerySWEData);
659
		stmt->setPrefetchRowCount(max_row);
660
661

		// construct the oracle specific Date object: year, month, day, hour, minutes
662
663
664
665
666
		int year, month, day, hour, minutes, seconds;
		dateS.getDate(year, month, day, hour, minutes, seconds);
		const occi::Date begindate(env, year, month, day, hour, minutes, seconds);
		dateE.getDate(year, month, day, hour, minutes, seconds);
		const occi::Date enddate(env, year, month, day, hour, minutes, seconds);
667
668
669
670
671
		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)
		stmt->setDate(4, enddate);    // set 4th variable's value (end date)

672
673
		ResultSet *rs = stmt->executeQuery(); // execute the statement stmt
		const vector<MetaData> cols = rs->getColumnListMetaData();
674

675
		double prev_swe = IOUtils::nodata;
676
		Date prev_date;
677
		size_t ii_serie = 0; //index in meteo time serie
678
		const size_t serie_len = vecMeteo[stationindex].size();
679
		double accumulator = 0.;
680
681

		while (rs->next() == true) { //loop over timesteps
682
			if (cols.size()!=2) {
683
				ostringstream ss;
684
685
686
687
				ss << "For station " << vecStationIDs.at(stationindex).getStationID() << ", ";
				ss << "snowpack SWE query returned " << cols.size() << " columns, while 2 were expected";
				throw UnknownValueException(ss.str(), AT);
			}
688
689
			Date curr_date;
			IOUtils::convertString(curr_date, rs->getString(1), 1.);
690
691
			double curr_swe;
			IOUtils::convertString(curr_swe, rs->getString(2));
692
693
			if (curr_swe==IOUtils::nodata || curr_swe<0.) continue;

694
			//looking for matching timestamp in the vecMeteo
695
696
697
698
699
700
701
702
703
704
705
706
			while (ii_serie<serie_len && vecMeteo[stationindex][ii_serie].date<curr_date) ii_serie++;
			if (ii_serie>=serie_len) return;


			if (prev_swe==IOUtils::nodata) {
				 //this looks like the first valid data point that we find
				prev_swe = curr_swe;
				prev_date = curr_date;
				continue;
			}

			if ((curr_date.getJulian()-prev_date.getJulian())<=max_interval || curr_swe==0.) {
707
				vecMeteo[stationindex][ii_serie](MeteoData::PSUM) = 0.;
708
709
				//data not too far apart, so we accept it for Delta SWE
				if (vecMeteo[stationindex][ii_serie].date==curr_date) {
710
711
712
713
					//we found the matching timestamp -> writing Delta(SWE) as psum
					const double new_psum_sum = curr_swe - prev_swe;
					if (new_psum_sum>eps_swe) {
						accumulator += new_psum_sum;
714
						if (accumulator>=swe_threshold) {
715
							vecMeteo[stationindex][ii_serie](MeteoData::PSUM) = accumulator;
716
717
							accumulator = 0.;
						}
718
719
720
					}
				}
				prev_swe = curr_swe;
721
722
				prev_date = curr_date;
			} else {
723
				//data points in SWE too far apart, we could not use it for psum but we reset our prev_swe to this new point
724
725
				prev_swe = curr_swe;
				prev_date = curr_date;
726
727
728
729
730
			}
		}

		stmt->closeResultSet(rs);
	} catch (const exception& e){
731
		throw IOException("Oracle Error when SWE data: " + string(e.what()), AT); //Translation of OCCI exception to IOException
732
733
734
735
	}
}


736
737
/**
 * @brief Puts the data that has been retrieved from the database into a MeteoData object
Fierz's avatar
Fierz committed
738
 * @param i_meteo a row of meteo data from the database (NOTE order important, matches SQL query, see also MeteoData.[cch])
739
 * @param md     the object to copy the data to
Fierz's avatar
Fierz committed
740
741
742
 * @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)
743
 */
Fierz's avatar
Fierz committed
744
745
746
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);
747
748
749
750
751
752
753
	IOUtils::convertString(md(MeteoData::TA),     i_meteo.at(1),  std::dec);
	IOUtils::convertString(md(MeteoData::ISWR),   i_meteo.at(2),  std::dec);
	IOUtils::convertString(md(MeteoData::VW),     i_meteo.at(3),  std::dec);
	IOUtils::convertString(md(MeteoData::DW),     i_meteo.at(4),  std::dec);
	IOUtils::convertString(md(MeteoData::VW_MAX), i_meteo.at(5),  std::dec);
	IOUtils::convertString(md(MeteoData::RH),     i_meteo.at(6),  std::dec);
	IOUtils::convertString(md(MeteoData::ILWR),   i_meteo.at(7),  std::dec);
754
	IOUtils::convertString(md(MeteoData::PSUM),    i_meteo.at(8),  std::dec);
755
756
757
758
	IOUtils::convertString(md(MeteoData::TSG),    i_meteo.at(9),  std::dec);
	IOUtils::convertString(md(MeteoData::TSS),    i_meteo.at(10), std::dec);
	IOUtils::convertString(md(MeteoData::HS),     i_meteo.at(11), std::dec);
	IOUtils::convertString(md(MeteoData::RSWR),   i_meteo.at(12), std::dec);
759
	IOUtils::convertString(md(MeteoData::P),   i_meteo.at(13), std::dec);
Fierz's avatar
Fierz committed
760

761
	unsigned int ii = 14;
Fierz's avatar
Fierz committed
762
	if (fullStation) {
763
		if (!md.param_exists("VW_DRIFT")) md.addParameter("VW_DRIFT");
764
		IOUtils::convertString(md("VW_DRIFT"), i_meteo.at(ii++), std::dec);
765
		if (!md.param_exists("DW_DRIFT")) md.addParameter("DW_DRIFT");
766
		IOUtils::convertString(md("DW_DRIFT"), i_meteo.at(ii++), std::dec);
Fierz's avatar
Fierz committed
767
768
769
	}

	// additional snow station parameters
770
	if (!md.param_exists("TS1")) md.addParameter("TS1");
771
	IOUtils::convertString(md("TS1"), i_meteo.at(ii++), std::dec);
772
	if (!md.param_exists("TS2")) md.addParameter("TS2");
773
	IOUtils::convertString(md("TS2"), i_meteo.at(ii++), std::dec);
774
	if (!md.param_exists("TS3")) md.addParameter("TS3");
775
	IOUtils::convertString(md("TS3"), i_meteo.at(ii++), std::dec);
Fierz's avatar
Fierz committed
776
	if (fullStation) {
777
		if (!md.param_exists("HTS1")) md.addParameter("HTS1");
778
		IOUtils::convertString(md("HTS1"), i_meteo.at(ii++), std::dec);
779
		if (!md.param_exists("HTS2")) md.addParameter("HTS2");
780
		IOUtils::convertString(md("HTS2"), i_meteo.at(ii++), std::dec);
781
		if (!md.param_exists("HTS3")) md.addParameter("HTS3");
782
		IOUtils::convertString(md("HTS3"), i_meteo.at(ii++), std::dec);
783
	}
784
785
786
}

/**
Fierz's avatar
Fierz committed
787
788
789
790
791
 * @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
792
 */
793
size_t ImisIO::getStationIDs(const std::string& station_code, const std::string& sqlQuery,
Fierz's avatar
Fierz committed
794
                                   std::vector<std::string>& vecStationIDs,
795
                                   oracle::occi::Statement*& stmt)
796
{
Fierz's avatar
Fierz committed
797
	vecStationIDs.clear();
798
799

	try {
800
		stmt->setSQL( sqlQuery );
Fierz's avatar
Fierz committed
801
802
		stmt->setString(1, station_code); // set 1st variable's value

803
		ResultSet *rs = stmt->executeQuery();    // execute the statement stmt
804
		const std::vector<MetaData> cols( rs->getColumnListMetaData() );
Fierz's avatar
Fierz committed
805
806

		while (rs->next() == true) {
Mathias Bavay's avatar
Mathias Bavay committed
807
			for (unsigned int ii=1; ii<=static_cast<unsigned int>(cols.size()); ii++) {
808
				vecStationIDs.push_back( rs->getString(ii) );
Fierz's avatar
Fierz committed
809
810
811
			}
		}

812
		if (vecStationIDs.size() < 3) { //if the station has not been found
813
			std::string stat_abk, stao_nr;