WSL/SLF GitLab Repository

ImisIO.cc 45.9 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
369
		vecMeteo.clear();
		vecMeteo.insert(vecMeteo.begin(), vecStationMetaData.size(), vector<MeteoData>());
370

371
372
		if ((env == NULL) || (conn == NULL))
			openDBConnection(env, conn);
373
		stmt = conn->createStatement();
374

375
		//read the "raw" station data from db (ie pure imis data)
376
		for (size_t ii=0; ii<vecStationMetaData.size(); ii++) { //loop through relevant stations
377
			readData(dateStart, dateEnd, vecMeteo, ii, vecStationMetaData, env, stmt);
Fierz's avatar
Fierz committed
378
		}
379

Fierz's avatar
Fierz committed
380
		if (useAnetz) { //Important: we don't care about the metadata for ANETZ stations
381
382
383
384
385
386
387
388
389
390
391
392
393
			std::vector<StationData> vecAnetzStation;       //holds the unique ANETZ stations that need to be read
			std::map<string, size_t> mapAnetzNames;   //associates an ANETZ station with an index within vecMeteoAnetz
			findAnetzStations(mapAnetzNames, vecAnetzStation);

			//read Anetz Data, convert it to PSUMs at XX:00 and XX:30
			std::vector< std::vector< std::pair<Date, double> > > vecPsum( vecAnetzStation.size() );
			vector< vector<MeteoData> > vecMeteoAnetz( vecAnetzStation.size() ); //holds the meteo data of the ANETZ stations
			const Date AnetzStart( dateStart-1./24. ); //to be sure that we can resample the ANETZ data
			const Date AnetzEnd( dateEnd+1./24. );
			for (size_t ii=0; ii<vecAnetzStation.size(); ii++) {
				readData(AnetzStart, AnetzEnd, vecMeteoAnetz, ii, vecAnetzStation, env, stmt);
				computeAnetzPSUM(vecMeteoAnetz[ii], vecPsum[ii]);
			}
394

395
396
			for (size_t ii=0; ii<vecStationMetaData.size(); ii++){ //loop through relevant stations
				const map<string,AnetzData>::const_iterator it = mapAnetz.find( vecStationMetaData.at(ii).getStationID() );
397
				if (it != mapAnetz.end())
398
					assimilateAnetzData(it->second, mapAnetzNames, vecPsum, ii, vecMeteo);
399
			}
400
401
		}

402
		if (use_psum_snowpack) {
403
			for (size_t ii=0; ii<vecStationMetaData.size(); ii++) { //loop through relevant stations
404
				readSWE(dateStart, dateEnd, vecMeteo, ii, vecStationMetaData, env, stmt);
405
406
407
			}
		}

408
		conn->terminateStatement(stmt);
409
		closeDBConnection(env, conn);
410
	} catch (const exception& e){
411
		closeDBConnection(env, conn);
412
		throw IOException("Oracle Error when reading stations' data: " + string(e.what()), AT); //Translation of OCCI exception to IOException
413
414
415
	}
}

416
417
418
419
//using the XX:00 and XX:30 Anetz precipi sums (in vecPsum), compute the regression for each timestep in vecMeteo for a given station
void ImisIO::assimilateAnetzData(const AnetzData& ad,
                                 const std::map<std::string, size_t>& mapAnetzNames, const std::vector< std::vector< std::pair<Date, double> > > &vecPsum,
                                 const size_t& stationindex, std::vector< std::vector<MeteoData> >& vecMeteo)
420
{
421
422
423
424
425
426
	std::vector<size_t> vecAnetz( ad.nrOfAnetzStations ); //this will contain the index in vecMeteoAnetz
	for (size_t jj=0; jj<ad.nrOfAnetzStations; jj++) { //loop over all associated anetz stations
		const map<string, size_t>::const_iterator it = mapAnetzNames.find( ad.anetzstations[jj] );
		if (it==mapAnetzNames.end())
			throw NotFoundException("The ANETZ station '"+ad.anetzstations[jj]+"' could not be found", AT);
		vecAnetz[jj] = (it->second);
427
428
	}

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
	std::vector<size_t> last_found( vecAnetz.size(), 0 ); //index of last found timestep in vecPsum
	for (size_t ii=0; ii<vecMeteo[stationindex].size(); ii++){ //loop over all timesteps for the current station
		const Date current_date( vecMeteo[stationindex][ii].date );

		//collect the ANETZ psums for this station and timestep
		std::vector<double> psum( vecAnetz.size(), IOUtils::nodata );
		for (size_t jj=0; jj<vecAnetz.size(); jj++) { //loop over all contributing anetz stations
			//find the current timestep in vecPsum
			for (size_t kk=last_found[jj]; kk<vecPsum[vecAnetz[jj]].size(); kk++) {
				const Date &anetz_date = vecPsum[vecAnetz[jj]][kk].first;
				if (anetz_date >= current_date) { //time step was found
					if (anetz_date == current_date) {
						last_found[jj]=kk;
						psum[jj] = vecPsum[vecAnetz[jj]][kk].second;
					}
					break;
				}
446
			}
447
448
		}

449
450
451
452
453
454
455
456
457
		//compute regression for the current point using the contributing stations
		double sum = 0.;
		if (ad.nrOfAnetzStations == ad.nrOfCoefficients){ //1, 2, or 3 ANETZ stations without interaction
			for (size_t jj=0; jj<vecAnetz.size(); jj++){
				if (psum[jj]==IOUtils::nodata) {
					sum = IOUtils::nodata;
					break;
				}
				sum += ad.coeffs[jj] * psum[jj];
458
			}
459
460
461
462
463
464
465
466
		} else { // Exactly two ANETZ stations with one interaction term
			if (ad.nrOfCoefficients != 3)
				throw IOException("Misconfiguration in ANETZ data", AT);

			if (psum[0]==IOUtils::nodata || psum[1]==IOUtils::nodata)
				sum = IOUtils::nodata;
			else {
				sum =ad.coeffs[0] * psum[0] + ad.coeffs[1] * psum[1] + ad.coeffs[2] * psum[0] * psum[1];
467
468
469
			}
		}

470
471
472
473
		//replace by ANETZ psum if there is no own value measured
		double& md_psum = vecMeteo[stationindex][ii](MeteoData::PSUM);
		if ((md_psum == IOUtils::nodata) || (IOUtils::checkEpsilonEquality(md_psum, 0.0, 0.001)))
			md_psum = sum;
474
	}
475
}
476

477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
//we compute PSUM at XX:30 and (XX+1):30 from the XX:40 sums from Anetz
void ImisIO::computeAnetzPSUM(std::vector<MeteoData> &vecMeteo, std::vector< std::pair<Date, double> > &vecPsum)
{
	const size_t nr_meteo = vecMeteo.size();
	for (size_t ii=0; ii<nr_meteo; ii++) {
		//generate sum at XX:30
		const double prev_psum = vecMeteo[ii](MeteoData::PSUM);
		const Date datum_halfhour = Date::rnd(vecMeteo[ii].date, 1800, Date::DOWN);
		if (prev_psum!=IOUtils::nodata)
			vecPsum.push_back( std::make_pair(datum_halfhour, prev_psum*.5) ); //30 minute sum fully contained in the XX:40 sum
		else
			vecPsum.push_back( std::make_pair(datum_halfhour, IOUtils::nodata) );

		//generate sum at (XX+1):00
		const double next_psum = (ii<(nr_meteo-1))? vecMeteo[ii+1](MeteoData::PSUM) : IOUtils::nodata;
		const Date datum = Date::rnd(vecMeteo[ii].date, 3600, Date::UP);
		if (prev_psum!=IOUtils::nodata && next_psum!=IOUtils::nodata)
			vecPsum.push_back( std::make_pair(datum, (prev_psum+next_psum*2.)/6.) );
		else
			vecPsum.push_back( std::make_pair(datum, IOUtils::nodata) );
497
	}
498
499
}

500
void ImisIO::findAnetzStations(std::map<std::string, size_t>& mapAnetzNames,
Fierz's avatar
Fierz committed
501
                               std::vector<StationData>& vecAnetzStation)
502
{
503
	std::set<std::string> uniqueStations;
Fierz's avatar
Fierz committed
504

505
506
	for (size_t ii=0; ii<vecStationMetaData.size(); ii++){ //loop through stations
		const map<string, AnetzData>::const_iterator it = mapAnetz.find( vecStationMetaData.at(ii).getStationID() );
507
		if (it != mapAnetz.end()){
508
			for (size_t jj=0; jj<it->second.nrOfAnetzStations; jj++){
509
				uniqueStations.insert( it->second.anetzstations[jj] );
510
511
512
513
			}
		}
	}

514
	size_t pp = 0;
515
516
517
	for (set<string>::const_iterator ii=uniqueStations.begin(); ii!=uniqueStations.end(); ii++){
		mapAnetzNames[*ii] = pp;
		pp++;
518
519
520

		StationData sd;
		sd.stationID = *ii;
521
		vecAnetzStation.push_back( sd );
522
	}
523
524
525
526
}

/**
 * @brief A meta function to read meteo data for one specific station (specified by the stationindex)
Fierz's avatar
Fierz committed
527
528
529
530
531
532
533
 * @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
534
535
 */
void ImisIO::readData(const Date& dateStart, const Date& dateEnd, std::vector< std::vector<MeteoData> >& vecMeteo,
536
                      const size_t& stationindex, const std::vector<StationData>& vecStationIDs,
537
                      oracle::occi::Environment*& env, oracle::occi::Statement*& stmt)
538
539
540
{
	vecMeteo.at(stationindex).clear();

541
	std::string stat_abk, stao_nr;
542
543
	vector< vector<string> > vecResult;

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

Fierz's avatar
Fierz committed
549
	//get data for one specific station
550
	std::vector<std::string> vecHTS1;
Fierz's avatar
Fierz committed
551
	parseStationID(vecStationIDs.at(stationindex).getStationID(), stat_abk, stao_nr);
552
553
	getSensorDepths(stat_abk, stao_nr, sqlQuerySensorDepths, vecHTS1, stmt);
	bool fullStation = getStationData(stat_abk, stao_nr, dateS, dateE, vecHTS1, vecResult, env, stmt);
554
555

	MeteoData tmpmd;
Fierz's avatar
Fierz committed
556
	tmpmd.meta = vecStationIDs.at(stationindex);
557
	for (size_t ii=0; ii<vecResult.size(); ii++){
Fierz's avatar
Fierz committed
558
		parseDataSet(vecResult[ii], tmpmd, fullStation);
559
		convertUnits(tmpmd);
560

561
		//For IMIS stations the psum value is a rate (kg m-2 h-1), therefore we need to
562
		//divide it by two to conjure the accumulated value for the half hour
563
		if (tmpmd.meta.stationID.length() > 0){
564
			if (tmpmd.meta.stationID[0] != '*') { //only consider IMIS stations (ie: not ANETZ)
565
				if (use_imis_psum==false) {
566
					tmpmd(MeteoData::PSUM) = IOUtils::nodata;
567
				} else {
568
					double& psum = tmpmd(MeteoData::PSUM);
569
					if (psum!=IOUtils::nodata) {
570
						psum *= .5; //half hour accumulated value for IMIS stations only
571
					}
572
573
				}
			}
574
		}
575

576
		vecMeteo.at(stationindex).push_back(tmpmd); //Now insert tmpmd
577
578
579
	}
}

580
/**
581
 * @brief Read simulated SWE from the database, compute Delta(SWE) and use it as PSUM for one specific station (specified by the stationindex)
582
583
584
585
586
587
588
589
590
591
 * @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,
592
                      oracle::occi::Environment*& env, oracle::occi::Statement*& stmt)
593
{
594
595
596
	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
597
598
599
600
601
602
603

	// 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
604
	std::string stat_abk, stao_nr;
605
606
	parseStationID(vecStationIDs.at(stationindex).getStationID(), stat_abk, stao_nr);

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

609
610
	//query
	try {
611
		stmt->setSQL(sqlQuerySWEData);
612
		stmt->setPrefetchRowCount(max_row);
613
614

		// construct the oracle specific Date object: year, month, day, hour, minutes
615
616
617
618
619
		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);
620
621
622
623
624
		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)

625
		ResultSet *rs = stmt->executeQuery(); // execute the statement stmt
626
		const vector<MetaData> cols( rs->getColumnListMetaData() );
627

628
		double prev_swe = IOUtils::nodata;
629
		Date prev_date;
630
		size_t ii_serie = 0; //index in meteo time serie
631
		const size_t serie_len = vecMeteo[stationindex].size();
632
		double accumulator = 0.;
633
634

		while (rs->next() == true) { //loop over timesteps
635
			if (cols.size()!=2) {
636
				ostringstream ss;
637
638
639
640
				ss << "For station " << vecStationIDs.at(stationindex).getStationID() << ", ";
				ss << "snowpack SWE query returned " << cols.size() << " columns, while 2 were expected";
				throw UnknownValueException(ss.str(), AT);
			}
641
642
			Date curr_date;
			IOUtils::convertString(curr_date, rs->getString(1), 1.);
643
644
			double curr_swe;
			IOUtils::convertString(curr_swe, rs->getString(2));
645
646
			if (curr_swe==IOUtils::nodata || curr_swe<0.) continue;

647
			//looking for matching timestamp in the vecMeteo
648
649
650
651
652
653
654
655
656
657
658
			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;
			}

659
660
			const double measurement_interval = curr_date.getJulian() - prev_date.getJulian();
			if (measurement_interval<=max_interval && curr_swe>0.) { //keep previous PSUM if no snow on the ground
661
				vecMeteo[stationindex][ii_serie](MeteoData::PSUM) = 0.;
662
663
				//data not too far apart, so we accept it for Delta SWE
				if (vecMeteo[stationindex][ii_serie].date==curr_date) {
664
665
666
667
					//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;
668
						if (accumulator>=swe_threshold) {
669
							vecMeteo[stationindex][ii_serie](MeteoData::PSUM) = accumulator;
670
671
							accumulator = 0.;
						}
672
673
674
					}
				}
				prev_swe = curr_swe;
675
676
				prev_date = curr_date;
			} else {
677
				//data points in SWE too far apart, we could not use it for psum but we reset our prev_swe to this new point
678
679
				prev_swe = curr_swe;
				prev_date = curr_date;
680
681
682
683
684
			}
		}

		stmt->closeResultSet(rs);
	} catch (const exception& e){
685
		throw IOException("Oracle Error when SWE data: " + string(e.what()), AT); //Translation of OCCI exception to IOException
686
687
688
689
	}
}


690
691
/**
 * @brief Puts the data that has been retrieved from the database into a MeteoData object
Fierz's avatar
Fierz committed
692
 * @param i_meteo a row of meteo data from the database (NOTE order important, matches SQL query, see also MeteoData.[cch])
693
 * @param md     the object to copy the data to
Fierz's avatar
Fierz committed
694
695
696
 * @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)
697
 */
Fierz's avatar
Fierz committed
698
699
700
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);
701
702
703
704
705
706
707
	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);
708
	IOUtils::convertString(md(MeteoData::PSUM),    i_meteo.at(8),  std::dec);
709
710
711
712
	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);
713
	IOUtils::convertString(md(MeteoData::P),   i_meteo.at(13), std::dec);
Fierz's avatar
Fierz committed
714

715
	unsigned int ii = 14;
Fierz's avatar
Fierz committed
716
	if (fullStation) {
717
		if (!md.param_exists("VW_DRIFT")) md.addParameter("VW_DRIFT");
718
		IOUtils::convertString(md("VW_DRIFT"), i_meteo.at(ii++), std::dec);
719
		if (!md.param_exists("DW_DRIFT")) md.addParameter("DW_DRIFT");
720
		IOUtils::convertString(md("DW_DRIFT"), i_meteo.at(ii++), std::dec);
Fierz's avatar
Fierz committed
721
722
723
	}

	// additional snow station parameters
724
	if (!md.param_exists("TS1")) md.addParameter("TS1");
725
	IOUtils::convertString(md("TS1"), i_meteo.at(ii++), std::dec);
726
	if (!md.param_exists("TS2")) md.addParameter("TS2");
727
	IOUtils::convertString(md("TS2"), i_meteo.at(ii++), std::dec);
728
	if (!md.param_exists("TS3")) md.addParameter("TS3");
729
	IOUtils::convertString(md("TS3"), i_meteo.at(ii++), std::dec);
Fierz's avatar
Fierz committed
730
	if (fullStation) {
731
		if (!md.param_exists("HTS1")) md.addParameter("HTS1");
732
		IOUtils::convertString(md("HTS1"), i_meteo.at(ii++), std::dec);
733
		if (!md.param_exists("HTS2")) md.addParameter("HTS2");
734
		IOUtils::convertString(md("HTS2"), i_meteo.at(ii++), std::dec);
735
		if (!md.param_exists("HTS3")) md.addParameter("HTS3");
736
		IOUtils::convertString(md("HTS3"), i_meteo.at(ii++), std::dec);
737
	}
738
739
740
}

/**
Fierz's avatar
Fierz committed
741
742
743
744
745
 * @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
746
 */
747
size_t ImisIO::getStationIDs(const std::string& station_code, const std::string& sqlQuery,
Fierz's avatar
Fierz committed
748
                                   std::vector<std::string>& vecStationIDs,
749
                                   oracle::occi::Statement*& stmt)
750
{
Fierz's avatar
Fierz committed
751
	vecStationIDs.clear();
752
753

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

757
		ResultSet *rs = stmt->executeQuery();    // execute the statement stmt
758
		const std::vector<MetaData> cols( rs->getColumnListMetaData() );
Fierz's avatar
Fierz committed
759
760

		while (rs->next() == true) {
Mathias Bavay's avatar
Mathias Bavay committed
761
			for (unsigned int ii=1; ii<=static_cast<unsigned int>(cols.size()); ii++) {
762
				vecStationIDs.push_back( rs->getString(ii) );
Fierz's avatar
Fierz committed
763
764
765
			}
		}

766
		if (vecStationIDs.size() < 3) { //if the station has not been found
767
			std::string stat_abk, stao_nr;
768
769
770
771
772
773
			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
774
775
		stmt->closeResultSet(rs);
		return cols.size();
776
	} catch (const exception& e){
777
		throw IOException("Oracle Error when reading stations' id: " + string(e.what()), AT); //Translation of OCCI exception to IOException
Fierz's avatar
Fierz committed
778
779
780
781
782
783
784
	}
}

/**
 * @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
785
 * @param vecHTS1   vector of string to retieve sensor depths
Fierz's avatar
Fierz committed
786
787
788
 * @param conn     create connection to SDB
 * @param return number of columns retrieved
 */
789
size_t ImisIO::getSensorDepths(const std::string& stat_abk, const std::string& stao_nr,
790
                                     const std::string& sqlQuery, std::vector<std::string>& vecHTS1,
791
                                     oracle::occi::Statement*& stmt)
Fierz's avatar
Fierz committed
792
{
793
	vecHTS1.clear();
Fierz's avatar
Fierz committed
794
795

	try {
796
		stmt->setSQL(sqlQuery);
797
798
		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
799

800
		ResultSet *rs = stmt->executeQuery();    // execute the statement stmt
801
		const std::vector<MetaData> cols( rs->getColumnListMetaData() );
802
803

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

		stmt->closeResultSet(rs);
Fierz's avatar
Fierz committed
810
		return cols.size();
811
	} catch (const exception& e){
812
		throw IOException("Oracle Error when reading sensors' depths: " + string(e.what()), AT); //Translation of OCCI exception to IOException
813
814
815
816
	}
}

/**
817
818
 * @brief This function gets meta data from table station2.standort and fills vecStationMetaData.
 * This is also the moment to take the opportunity to check if the station really does exist.
Fierz's avatar
Fierz committed
819
820
821
822
823
 * @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
824
 * @param return             number of metadata read (ie. retrieve and not NULL)
Fierz's avatar
Fierz committed
825
 */
826
size_t ImisIO::getStationMetaData(const std::string& stat_abk, const std::string& stao_nr,
827
                                        const std::string& sqlQuery, std::vector<std::string>& vecMetaData,
828
                                        oracle::occi::Statement*& stmt)
Fierz's avatar
Fierz committed
829
{
830
	vecMetaData.clear();
Fierz's avatar
Fierz committed
831
832

	try {
833
		stmt->setSQL(sqlQuery);
Fierz's avatar
Fierz committed
834
835
836
		stmt->setString(1, stat_abk); // set 1st variable's value
		stmt->setString(2, stao_nr);  // set 2nd variable's value

837
		ResultSet *rs = stmt->executeQuery();    // execute the statement stmt
838
		const std::vector<MetaData> cols( rs->getColumnListMetaData() );
Fierz's avatar
Fierz committed
839
840

		while (rs->next() == true) {
Mathias Bavay's avatar
Mathias Bavay committed
841
			for (unsigned int ii=1; ii<=static_cast<unsigned int>(cols.size()); ii++) {
842
				vecMetaData.push_back( rs->getString(ii) );
Fierz's avatar
Fierz committed
843
844
845
846
			}
		}

		stmt->closeResultSet(rs);
847
	} catch (const exception& e){
848
		throw IOException("Oracle Error when reading stations' metadata: " + string(e.what()), AT); //Translation of OCCI exception to IOException
Fierz's avatar
Fierz committed
849
	}
850
851

	const size_t nr_metadata = vecMetaData.size();
852
	if (nr_metadata==0)
853
			throw NoDataException("Station " + stat_abk+stao_nr + " not found in the database", AT);
854
	if (nr_metadata<4)
855
856
			throw ConversionFailedException("Error while converting station meta data for station "+stat_abk+stao_nr, AT);
	return nr_metadata;
Fierz's avatar
Fierz committed
857
858
859
860
}

/**
 * @brief Gets data from ams.v_ams_raw which is a table of SDB and
861
 * retrieves the temperature sensor depths from station2.standort.
Fierz's avatar
Fierz committed
862
863
864
 * 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