/[ascend]/trunk/models/johnpye/datareader/tmy3.c
ViewVC logotype

Contents of /trunk/models/johnpye/datareader/tmy3.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2596 - (show annotations) (download) (as text)
Sat Apr 14 06:06:41 2012 UTC (10 years, 2 months ago) by jpye
File MIME type: text/x-csrc
File size: 9223 byte(s)
testing TMY3 reader.
1 /* ASCEND modelling environment
2 Copyright (C) 2012 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20 Data Reader implementation for the TMY3 weather data format.
21
22 File format description:
23 http://www.nrel.gov/docs/fy08osti/43156.pdf
24
25 Data available for download:
26 http://rredc.nrel.gov/solar/old_data/nsrdb/1991-2005/tmy3/
27
28 Header fields (first line):
29 1. site USAF code
30 2. station name (quoted)
31 3. station US state (two-letter abbrev)
32 4. site timezone (hours from greenwich, west negative)
33 5. site latitude (deg, with decimal fraction)
34 6. site longitude (deg, with decimal fraction)
35 7. site elevation (m)
36
37 Second line of the file contains the field names with units of measurement.
38
39 Key fields (not all listed here):
40 1. date (MM/DD/YYYY -- NB american style!)
41 2. time (HH:MM in local STANDARD time -- no daylight savings applied)
42 5. GHI (Wh/m^2) integrated for the hour leading UP TO the timestamp
43 7. % uncertainty in GHI
44 8. DNI (Wh/m^2) integrated for the hour leading UP TO the timestamp
45 10. % uncertainty in DNI
46 11. diffuse horizontal irradiance (Wh/m2) in hour leading to timestamp
47 26. fraction of sky totally covered with cloud (tenths) at indicated time
48 32. dry bulb temperature (0.1 ��C) at the indicated time
49 38. relative humidity (%) at the indicated time
50 41. air pressure (mbar) at the indicated time
51 44. wind direction (10��) assumed to be measured eastward? from north=0 at indic time.
52 47. wind speed (0.1m/s)
53 65. amount of rain (mm), see next field
54 66. duration over which rain was measured (1hr), -9900 if missing.
55 *//*
56 by John Pye, April 2012.
57 */
58
59 #include "tmy3.h"
60 #include "sun.h"
61
62 #include <stdio.h>
63
64 #include <ascend/general/ascMalloc.h>
65 #include <ascend/utilities/error.h>
66
67 #include "parse/parse.h"
68
69 #define TMY3_DEBUG 1
70
71 /**
72 Data extracted from the E/E data file, doesn't have to included everything,
73 only the stuff we actually think we will want to use.
74 */
75 typedef struct Tmy3Point_struct{
76 double t;
77 float T; ///< dry bulb temperature, K.
78 float p; ///< atmospheric pressure, Pa.
79 float rh; /// relative humidity, fraction 0<rh<1.
80 float DNI; ///< direct normal irradiance Wh/m��
81 float GHI; ///< diffuse horizontal irradiance Wh/m��
82 float d_wind; ///< wind direction, rad, N = 0, E = pi/2, W = 3pi/2, S = pi. Range 0<=d<2pi
83 float v_wind; ///< wind speed, m/s.
84 } Tmy3Point;
85
86 typedef struct Tmy3Data_struct{
87 Tmy3Point *rows;
88 parse *p; /* parse object, non-null during file read */
89 } Tmy3Data;
90
91 #define DATA(D) ((Tmy3Data *)(D->data))
92
93 typedef struct Tmy3Location_struct{
94 char stationcode[101];
95 char stationname[101];
96 char state[20];
97 double timezone; // in hours, rel to GMT
98 double latitude; // in degrees, + is north
99 double longitude; // in degrees, + is east
100 double elevation; // in metres
101 } Tmy3Location;
102
103 //example header line:
104 //723815,"DAGGETT BARSTOW-DAGGETT AP",CA,-8.0,34.850,-116.800,586
105 int parseLocation(parse *p, Tmy3Location *loc){
106 return
107 (parseStrExcept(p,",",loc->stationcode,100)
108 && parseThisString(p,",\"")
109 && parseStrExcept(p,"\"",loc->stationname,100)
110 && parseThisString(p,"\",")
111 && parseStrExcept(p,",",loc->state,100)
112 && parseThisString(p,",")
113 && parseDouble(p,&(loc->timezone))
114 && parseThisString(p,",")
115 && parseDouble(p,&(loc->latitude))
116 && parseThisString(p,",")
117 && parseDouble(p,&(loc->longitude))
118 && parseThisString(p,",")
119 && parseDouble(p,&(loc->elevation))
120 && parseEOL(p)
121 ) || parseError(p,"Error in header line (line 1)")
122 ;
123 }
124
125 /**
126 @return 0 on success
127 */
128 int datareader_tmy3_header(DataReader *d){
129 Tmy3Location loc;
130 d->data = ASC_NEW(Tmy3Data);
131 DATA(d)->p = parseCreateFile(d->f);
132 parse *p = DATA(d)->p;
133 char rubbish[2049];
134
135 if(!(
136 parseLocation(p,&loc)
137 && parseStrExcept(p,"\r\n",rubbish,2048)
138 && parseEOL(p)
139 )){
140 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Parser error in header part of file");
141 }
142
143 CONSOLE_DEBUG("TMY3 file for '%s' at (%.2fN,%.2fE)",loc.stationname,loc.latitude,loc.longitude);
144
145 // set the value of some of the Data Reader parameters
146 d->i = 0;
147 d->ninputs = 1;
148 d->ndata = 8760; // FIXME
149 d->nmaxoutputs = 7; // FIXME
150
151 DATA(d)->rows = ASC_NEW_ARRAY(Tmy3Point,d->ndata);
152
153 /* set the number of inputs and outputs */
154 d->ninputs = 1;
155 d->noutputs = 7;
156 return 0;
157 }
158
159 int datareader_tmy3_eof(DataReader *d){
160 parse *p = DATA(d)->p;
161 if(parseEnd(p)){
162 CONSOLE_DEBUG("REACHED END OF FILE");
163 if(d->i < d->ndata){
164 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Incomplete data set found (%d rows < %d expected",d->i, d->ndata);
165 }
166 d->ndata=d->i;
167 int i;double tmin = +0.5*DBL_MAX,tmax = -0.5*DBL_MAX;
168 for(i=0; i<d->ndata; ++i){
169 double t = DATA(d)->rows[i].t;
170 if(t < tmin)tmin = t;
171 if(t > tmax)tmax = t;
172 }
173 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"Read %d rows, t in range [%f,%f] d",d->ndata,tmin/3600./24.,tmax/3600./24.);
174 return 1; /* yes, end of file */
175 }
176 return 0; /* no, more data still */
177 }
178
179 /**
180 Read a line of data and store in d.
181 @return 0 on success
182 */
183 int datareader_tmy3_data(DataReader *d){
184 //CONSOLE_DEBUG("Reading data, i = %d",d->i);
185 unsigned year,month,day,hour,minute;
186 Tmy3Point row;
187
188 // in the following 'C' are char fiels, 'I' are integer fields;
189 // the suffix 'e' means error/uncertainty and 's' means source of data.
190 #define NUMFIELDS(C,I,X) I(3_EGHI) X I(4_EDNI) \
191 X I(5_GHI) X C(6_GHIs) X I(7_GHIe) \
192 X I(8_DNI) X C(9_DNIs) X I(10_DNIe) \
193 X I(11_DiffHI) X C(12_DiffHIs) X I(13_DiffHIe) \
194 X I(14_GHIll) X C(15_GHIlls) X I(16_GHIlle) \
195 X I(17_DNIll) X C(18_DNIlls) X I(19_DNIlle) \
196 X I(20_DiffHIll) X C(21_DiffHIlls) X I(22_DiffHIlle) \
197 X I(23_ZenLum) X C(24_ZenLums) X I(25_ZenLume) \
198 X I(26_TotCov) X C(27_TotCovs) X C(28_TotCove) \
199 X I(29_OpaqCov) X C(30_OpaqCovs) X C(31_OpenCove) \
200 X I(32_T) X C(33_Ts) X C(34_Te) \
201 X I(35_Tdew) X C(36_Tdews) X C(37_Tdewe) \
202 X I(38_RH) X C(39_RHs) X C(40_RHe) \
203 X I(41_P) X C(42_Ps) X C(43_Pe) \
204 X I(44_WD) X C(45_WDs) X C(46_WDe) \
205 X I(47_WS) X C(48_WSs) X C(49_WSe) \
206 X I(50_HViz) X C(51_HVizs) X C(52_HVize) \
207 X I(53_HViz) X C(54_HVizs) X C(55_HVize) \
208 X I(56_HViz) X C(57_HVizs) X C(58_HVize) \
209 X I(59_HViz) X C(60_HVizs) X C(61_HVize) \
210 X I(62_HViz) X C(63_HVizs) X C(64_HVize) \
211 X I(65_RainDepth) X I(66_RainDuration) X C(67_Rains) X C(68_Raine)
212
213 #define CHARDECL(NAME) char tmy3_field_##NAME;
214 #define NUMDECL(NAME) double tmy3_field_##NAME;
215 #define NUTHIN_HERE
216 NUMFIELDS(CHARDECL,NUMDECL,NUTHIN_HERE);
217 #undef CHARDECL
218 #undef NUMDECL
219 #undef NUTHIN_HERE
220
221 // TODO what to do with 'missing' values??
222 parse *p = DATA(d)->p;
223
224 #define PARSEINT(NAME) parseDouble(p,&tmy3_field_##NAME)
225 #define PARSECHAR(NAME) parseAChar(p,&tmy3_field_##NAME)
226 #define ANDTHEN && parseThisString(p,",") &&
227
228 // example row:
229 // 01/25/1988,12:00,821,1411,530,1,13,580,1,9,192,1,13,565,1,13,593,1,9,219,1,13,442,1,21,10,A,7,4,A,7,13.3,A,7,-8.9,A,7,21,A,7,960,A,7,60,A,7,3.6,A,7,80500,A,7,77777,A,7,0.5,E,8,0.030,F,8,-9900.000,?,0,-9900,-9900,?,0
230
231 if(!(
232 (( /* parse the date and time first... */
233 parseNumber(p,&month)
234 && parseThisString(p,"/")
235 && parseNumber(p,&day)
236 && parseThisString(p,"/")
237 && parseNumber(p,&year)
238 && parseThisString(p,",")
239 && parseNumber(p,&hour)
240 && parseThisString(p,":")
241 && parseNumber(p,&minute)
242 && parseThisString(p,",")
243 /* then come the data fields */
244 && NUMFIELDS(PARSECHAR,PARSEINT,ANDTHEN)
245 ) || parseError(p,"Missing/incorrect data field")
246 ) && (
247 parseEOL(p) || parseError(p,"Expected end-of-line")
248 )
249 )){
250 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Failed to parse E/E data file");
251 return 1;
252 };
253 #undef ANDTHEN
254 #undef PARSEINT
255 #undef PARSECHAR
256
257 // TODO add check for data for Feb 29... just in case?
258 row.t = ((day_of_year_specific(day,month,year) - 1)*24.0 + (hour - 1))*3600.0 + minute*60.;
259 row.T = tmy3_field_32_T * 0.1;
260 row.p = tmy3_field_41_P * 100.;
261 row.rh = tmy3_field_38_RH * 0.01;
262 row.DNI = tmy3_field_8_DNI * 1.;
263 row.GHI = tmy3_field_5_GHI * 1.;
264 row.v_wind = tmy3_field_47_WS * 0.1;
265 row.d_wind = tmy3_field_44_WD * 3.14159265358 / 180. ;
266
267 DATA(d)->rows[d->i] = row;
268
269 //CONSOLE_DEBUG("Read i = %d, t = %f d, T = %.1f��C, rh = %.1f %",d->i,row.t / 3600. / 24., T, row.rh*100);
270
271 d->i++;
272 return 0;
273 }
274
275 int datareader_tmy3_time(DataReader *d, double *t){
276 *t = DATA(d)->rows[d->i].t;
277 return 0;
278 }
279
280 #define ROW DATA(d)->rows[d->i]
281
282 int datareader_tmy3_vals(DataReader *d, double *v){
283 #if TMY3_DEBUG
284 CONSOLE_DEBUG("At t=%f d, T = %lf, DNI = %f Wh/m2"
285 ,(ROW.t / 3600. / 24.),ROW.T, ROW.DNI
286 );
287 #endif
288 v[0]=ROW.T;
289 v[1]=ROW.p;
290 v[2]=ROW.rh;
291 v[3]=ROW.DNI;
292 v[4]=ROW.GHI;
293 v[5]=ROW.d_wind;
294 v[6]=ROW.v_wind;
295 return 0;
296 }
297
298

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22