ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/loadEPW.c
Revision: 2.1
Committed: Wed Feb 26 20:39:28 2025 UTC (2 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
feat(gendaymtx): Added ability to read dew point from EPW input data

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /*
5 * Load an EPW (or WEA) file, one data point at a time
6 *
7 * G. Ward, Feb 2025
8 */
9
10 #include "rtio.h"
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include "loadEPW.h"
14
15 const char WDname[7][10] = {
16 "Sunday", "Monday", "Tuesday", "Wednesday",
17 "Thursday", "Friday", "Saturday"
18 };
19
20 const char MOname[12][10] = {
21 "January", "February", "March", "April", "June", "July",
22 "August", "September", "October", "November", "December"
23 };
24
25 #define EPWDATE_INIT {.0f,0,0,0}
26
27 static const struct DataPeriod EPWperiodInit = {
28 "DEFAULT", 1, Sunday, {.0f, 1, 0, 0}, {24.f, 31, 11, 0}
29 };
30
31 const EPWrecord EPWrecInit = {
32 EPWDATE_INIT, "", 99.9f, 99.9f, 999.f, 999999.f, 9999.f, 9999.f, 9999.f,
33 9999.f, 9999.f, 9999.f, 999999.f, 999999.f, 999999.f, 9999.f, 999.f, 999.f,
34 99.f, 99.f, 9999e3f, 99999.f, 999e-3f, 999e-3f, 999e-2f, 99,
35 .0f, 1.5e-3f, .0f
36 };
37
38 #define EPWdateInit (EPWrecInit.date)
39
40 static const short mo_da[13] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
41
42 /* Get day-of-week from name (may be abbreviated) */
43 static int
44 get_day(const char dnm[])
45 {
46 int n = strlen(dnm);
47 int i;
48
49 if (n < 3)
50 return(-1);
51
52 for (i = 0; i < 7; i++)
53 if (!strncasecmp(dnm, WDname[i], n))
54 return(i);
55 return(-1);
56 }
57
58 /* Hour difference calculator dt1 - dt2 (crude) */
59 static double
60 hour_diff(const EPWdate *dt1, const EPWdate *dt2)
61 {
62 double hrdiff = dt1->hour - dt2->hour;
63
64 hrdiff += 24.*(mo_da[dt1->month] + dt1->day - mo_da[dt2->month] - dt2->day);
65
66 if ((dt1->year > 0) & (dt2->year > 0))
67 hrdiff += 365.*24.*(dt1->year - dt2->year);
68
69 return(hrdiff);
70 }
71
72 /* Check that a date/time is legal */
73 static int
74 date_OK(const EPWdate *dt)
75 {
76 if ((0 > dt->month) | (dt->month > 11) |
77 (0 > dt->hour) | (dt->hour > 24) | (dt->day < 1))
78 return(0);
79
80 return(dt->day <= (dt->month==1 ? 29 :
81 mo_da[dt->month+1] - mo_da[dt->month]));
82 }
83
84 /* Parse date (less hour) */
85 static int
86 get_date(EPWdate *dt, const char date[])
87 {
88 int mo, da, yr;
89 int nf;
90
91 *dt = EPWdateInit;
92 switch (sscanf(date, "%d/%d/%d", &mo, &da, &yr)) {
93 case 1:
94 da = mo; /* jdate */
95 if (da <= 0)
96 return(0);
97 for (mo = 0; mo_da[mo+1] < da; mo++)
98 if (mo >= 11)
99 return(0);
100 dt->day = da - mo_da[dt->month = mo];
101 return(1);
102 case 3: /* month/day/year */
103 dt->year = yr;
104 /* fall through */
105 case 2: /* month/day */
106 dt->month = mo-1;
107 dt->day = da;
108 return(date_OK(dt));
109 }
110 return(0);
111 }
112
113 /* Check that site data is sensible */
114 static int
115 bad_location(const struct Location *lp)
116 {
117 if ((-90. > lp->latitude) | (lp->latitude > 90.)) {
118 fputs("Bad latitude in ", stderr);
119 return(1);
120 }
121 if ((-180. > lp->longitude) | (lp->longitude > 180.)) {
122 fputs("Bad longitude in ", stderr);
123 return(2);
124 }
125 if ((-12. > lp->timezone) | (lp->timezone > 12.)) {
126 fputs("Bad time zone in ", stderr);
127 return(3);
128 }
129 if ((-1000. > lp->elevation) | (lp->elevation > 9999.9)) {
130 fputs("Bad elevation in ", stderr);
131 return(4);
132 }
133 return(0);
134 }
135
136 /* Copy word to next comma in string */
137 static char *
138 tocomma(char *dst, char *src)
139 {
140 while (*src && *src != ',')
141 *dst++ = *src++;
142 src += (*src == ',');
143 *dst = '\0';
144 return(src);
145 }
146
147 /* Use fscanf() to load next date and time from input */
148 static int
149 scan_date(EPWheader *epw)
150 {
151 int hour;
152 float minute;
153
154 ++epw->lino;
155 if (epw->isWEA) { /* simpler for WEA input */
156 epw->dtpos = EPWdateInit;
157 if (fscanf(epw->fp, "%hd %hd %f", &epw->dtpos.month, &epw->dtpos.day,
158 &epw->dtpos.hour) != 3)
159 goto scanerr;
160 epw->dtpos.month--;
161 } else {
162 /* EPW input line */
163 if (fscanf(epw->fp, "%hd,%hd,%hd,%d,%f,", &epw->dtpos.year,
164 &epw->dtpos.month, &epw->dtpos.day, &hour, &minute) != 5)
165 goto scanerr;
166 epw->dtpos.hour = hour - minute*(0.5/60.);
167 epw->dtpos.month--;
168 }
169 /* check date/time */
170 if (!date_OK(&epw->dtpos)) {
171 fputs("Illegal date/time in ", stderr);
172 return(0);
173 }
174 return(1);
175 scanerr:
176 if (!feof(epw->fp))
177 fputs("Unable to scan date in ", stderr);
178 return(0);
179 }
180
181 /* Open input file and load header info. */
182 EPWheader *
183 EPWopen(const char *fname)
184 {
185 char linbuf[1024], wbuf[64];
186 char *cp;
187 int n;
188 EPWheader *hdr = (EPWheader *)calloc(1, sizeof(EPWheader));
189
190 if (hdr == NULL)
191 goto memerr;
192 if (fname == NULL || !*fname) {
193 fname = "<stdin>";
194 hdr->fp = stdin;
195 } else if ((hdr->fp = fopen(fname, "r")) == NULL) {
196 perror(fname);
197 free(hdr);
198 return(NULL);
199 }
200 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
201 goto readerr;
202 ++hdr->lino;
203 if (!strncasecmp(linbuf, "place ", 6))
204 hdr->isWEA = 1;
205 else if (strncasecmp(linbuf, "LOCATION,", 9))
206 goto badformat;
207 if (hdr->isWEA) { /* getting WEA header */
208 cp = linbuf+6;
209 if (sscanf(cp, "%[^_]_%[^\r\n]q",
210 hdr->loc.city, hdr->loc.country) != 2)
211 goto badformat;
212 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
213 goto readerr;
214 ++hdr->lino;
215 if (sscanf(linbuf, "latitude %lf", &hdr->loc.latitude) != 1)
216 goto badformat;
217 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
218 goto readerr;
219 ++hdr->lino;
220 if (sscanf(linbuf, "longitude %lf", &hdr->loc.longitude) != 1)
221 goto badformat;
222 hdr->loc.longitude *= -1.;
223 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
224 goto readerr;
225 ++hdr->lino;
226 if (sscanf(linbuf, "time_zone %f", &hdr->loc.timezone) != 1)
227 goto badformat;
228 hdr->loc.timezone *= -1./15.;
229 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
230 goto readerr;
231 ++hdr->lino;
232 if (sscanf(linbuf, "site_elevation %f", &hdr->loc.elevation) != 1)
233 goto badformat;
234 if (bad_location(&hdr->loc))
235 goto badformat;
236 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
237 goto readerr;
238 ++hdr->lino;
239 if (sscanf(linbuf, "weather_data_file_units %hd", &hdr->isWEA) != 1)
240 goto badformat;
241 hdr->nperiods = 1;
242 hdr->period[0] = EPWperiodInit;
243 hdr->dstart = (int)ftell(hdr->fp);
244 hdr->lin0 = hdr->lino;
245 if (!scan_date(hdr)) /* get date */
246 goto badformat;
247 return(hdr);
248 } /* else EPW header */
249 cp = linbuf+9;
250 cp = tocomma(hdr->loc.city, cp);
251 if (!*cp) goto badformat;
252 cp = tocomma(hdr->loc.state, cp);
253 if (!*cp) goto badformat;
254 cp = tocomma(hdr->loc.country, cp);
255 if (!*cp) goto badformat;
256 cp = tocomma(hdr->loc.source, cp);
257 if (!*cp) goto badformat;
258 cp = tocomma(hdr->loc.wmo, cp);
259 if (sscanf(cp, "%lf,%lf,%f,%f", &hdr->loc.latitude, &hdr->loc.longitude,
260 &hdr->loc.timezone, &hdr->loc.elevation) != 4)
261 goto badformat;
262 if (bad_location(&hdr->loc))
263 goto badformat;
264 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
265 goto readerr;
266 ++hdr->lino;
267 if (strncasecmp(linbuf, "DESIGN CONDITIONS,", 18))
268 goto badformat;
269 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
270 goto readerr;
271 ++hdr->lino;
272 if (strncasecmp(linbuf, "TYPICAL/EXTREME PERIODS,", 24))
273 goto badformat;
274 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
275 goto readerr;
276 ++hdr->lino;
277 if (strncasecmp(linbuf, "GROUND TEMPERATURES,", 20))
278 goto badformat;
279 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
280 goto readerr;
281 ++hdr->lino;
282 if (strncasecmp(linbuf, "HOLIDAYS/DAYLIGHT SAVINGS,", 26))
283 goto badformat;
284 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
285 goto readerr;
286 ++hdr->lino;
287 if (strncasecmp(linbuf, "COMMENTS 1,", 11))
288 goto badformat;
289 n = strlen(linbuf+11);
290 if (n > 1) {
291 hdr->comments1 = (char *)malloc(n);
292 if (hdr->comments1 == NULL)
293 goto memerr;
294 memcpy(hdr->comments1, linbuf+11, n);
295 hdr->comments1[n] = '\0';
296 }
297 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
298 goto readerr;
299 ++hdr->lino;
300 if (strncasecmp(linbuf, "COMMENTS 2,", 11))
301 goto badformat;
302 n = strlen(linbuf+11);
303 if (n > 1) {
304 hdr->comments2 = (char *)malloc(n);
305 if (hdr->comments2 == NULL)
306 goto memerr;
307 memcpy(hdr->comments2, linbuf+11, n);
308 hdr->comments2[n] = '\0';
309 }
310 if (!fgets(linbuf, sizeof(linbuf), hdr->fp))
311 goto readerr;
312 ++hdr->lino;
313 if (strncasecmp(linbuf, "DATA PERIODS,", 13))
314 goto badformat;
315 hdr->nperiods = 1; /* XXX one for now */
316 if (atoi(linbuf+13) != 1)
317 fprintf(stderr, "%s: warning - ignoring data periods after first\n",
318 fname);
319 cp = strchr(linbuf+13, ',');
320 if (!cp++) goto badformat;
321 if ((hdr->period[0].nperhour = atoi(cp)) <= 0)
322 goto badformat;
323 cp = strchr(cp, ',');
324 if (!cp++) goto badformat;
325 cp = tocomma(hdr->period[0].name, cp);
326 if (!*cp) goto badformat;
327 cp = tocomma(wbuf, cp);
328 if ((hdr->period[0].startday = get_day(wbuf)) < 0)
329 goto badformat;
330 if (!*cp) goto badformat;
331 cp = tocomma(wbuf, cp);
332 if (!get_date(&hdr->period[0].firstdate, wbuf))
333 goto badformat;
334 if (!*cp) goto badformat;
335 cp = tocomma(wbuf, cp);
336 if (!get_date(&hdr->period[0].lastdate, wbuf))
337 goto badformat;
338 hdr->period[0].lastdate.hour = 24.f;
339 hdr->dstart = (int)ftell(hdr->fp);
340 hdr->lin0 = hdr->lino;
341 if (!scan_date(hdr)) /* and get/check date */
342 goto badformat;
343 if ((hdr->dtpos.month != hdr->period[0].firstdate.month) |
344 (hdr->dtpos.day != hdr->period[0].firstdate.day))
345 fprintf(stderr, "%s: warning - starting date does not match first record\n",
346 fname);
347 return(hdr); /* seems we're good! */
348 memerr:
349 perror("malloc");
350 if (hdr) {
351 if (hdr->fp != stdin) fclose(hdr->fp);
352 free(hdr);
353 }
354 return(NULL);
355 readerr:
356 fprintf(stderr, "%s: header read error at line %d\n", fname, hdr->lino);
357 EPWclose(hdr);
358 return(NULL);
359 badformat:
360 fprintf(stderr, "%s: header format error in %s file at line %d\n",
361 fname, hdr->isWEA ? "WEA" : "EPW", hdr->lino);
362 EPWclose(hdr);
363 return(NULL);
364 }
365
366 /* Seek to a particular data record if we can */
367 int
368 EPWseek(EPWheader *epw, const EPWdate *dt)
369 {
370 if (!epw | !dt || !epw->fp || !date_OK(dt))
371 return(EOF);
372 /* need to back up? */
373 if (feof(epw->fp) || hour_diff(&epw->dtpos, dt) > 0.99) {
374 if (epw->dstart < 0 || fseek(epw->fp, epw->dstart, SEEK_SET) < 0) {
375 if (epw->fp == stdin)
376 fputs("Cannot seek on standard input\n", stderr);
377 else
378 fprintf(stderr, "Seek error on %s input file\n",
379 epw->isWEA ? "WEA" : "EPW");
380 return(EOF);
381 }
382 epw->lino = epw->lin0;
383 scan_date(epw); /* assume this much works! */
384 }
385 /* step through earlier records */
386 while (hour_diff(&epw->dtpos, dt) < -.99) {
387 int c;
388 while ((c = getc(epw->fp)) != EOF)
389 if (c == '\n') /* skip record data */
390 break;
391 if (scan_date(epw)) /* load next date/time */
392 continue;
393 if (feof(epw->fp))
394 fputs("Requested date/time not found in ", stderr);
395 fputs(epw->isWEA ? "WEA" : "EPW", stderr);
396 fputs(" input\n", stderr);
397 return(0);
398 }
399 return(1);
400 }
401
402 /* Read the next data record from input */
403 int
404 EPWread(EPWheader *epw, EPWrecord *rp)
405 {
406 char linbuf[1024];
407 char *cp;
408
409 if (!epw | !rp || feof(epw->fp))
410 return(EOF);
411
412 *rp = EPWrecInit; /* initialize to defaults */
413 rp->date = epw->dtpos; /* date already read in */
414 if (!fgets(linbuf, sizeof(linbuf), epw->fp)) {
415 fputs("Unexpected EOF on input\n", stderr);
416 return(0);
417 }
418 switch (epw->isWEA) { /* check for WEA input */
419 case WEAnot: /* nope */
420 break;
421 case WEAradnorm: /* radiometric w/ direct normal */
422 if (sscanf(linbuf, "%f %f", &rp->dirirrad,
423 &rp->horizdiffirrad) != 2)
424 goto badformat;
425 break;
426 case WEAradhoriz: /* radiometric w/ direct horizontal */
427 if (sscanf(linbuf, "%f %f", &rp->globhorizirrad,
428 &rp->horizdiffirrad) != 2)
429 goto badformat;
430 rp->globhorizirrad += rp->horizdiffirrad;
431 break;
432 case WEAphotnorm: /* photometric w/ direct normal */
433 if (sscanf(linbuf, "%f %f", &rp->dirillum,
434 &rp->diffillum) != 2)
435 goto badformat;
436 break;
437 default:
438 fputs("Illegal WEA data type\n", stderr);
439 return(0);
440 }
441 if (epw->isWEA) {
442 if (sscanf(linbuf, "%*f %*f %f %f",
443 &rp->optdepth, &rp->skycover) == 2) {
444 rp->optdepth *= 1e-3;
445 }
446 if (!scan_date(epw) && !feof(epw->fp))
447 goto badformat;
448 return(1);
449 }
450 /* continue here if EPW file */
451 cp = tocomma(rp->uncert, linbuf);
452 if (!*cp) goto badformat;
453 if (*cp != ',') {
454 rp->dbtemp = atof(cp);
455 cp = strchr(cp, ',');
456 }
457 if (!cp++) goto badformat;
458 if (*cp != ',') {
459 rp->dptemp = atof(cp);
460 cp = strchr(cp, ',');
461 }
462 if (!cp++) goto badformat;
463 if (*cp != ',') {
464 rp->humidity = atof(cp);
465 cp = strchr(cp, ',');
466 }
467 if (!cp++) goto badformat;
468 if (*cp != ',') {
469 rp->atmospressure = atof(cp);
470 cp = strchr(cp, ',');
471 }
472 if (!cp++) goto badformat;
473 if (*cp != ',') {
474 rp->exthorizirrad = atof(cp);
475 cp = strchr(cp, ',');
476 }
477 if (!cp++) goto badformat;
478 if (*cp != ',') {
479 rp->extdirirrad = atof(cp);
480 cp = strchr(cp, ',');
481 }
482 if (!cp++) goto badformat;
483 if (*cp != ',') {
484 rp->horizirrad_ir = atof(cp);
485 cp = strchr(cp, ',');
486 }
487 if (!cp++) goto badformat;
488 if (*cp != ',') {
489 rp->globhorizirrad = atof(cp);
490 cp = strchr(cp, ',');
491 }
492 if (!cp++) goto badformat;
493 if (*cp != ',') {
494 rp->dirirrad = atof(cp);
495 cp = strchr(cp, ',');
496 }
497 if (!cp++) goto badformat;
498 if (*cp != ',') {
499 rp->horizdiffirrad = atof(cp);
500 cp = strchr(cp, ',');
501 }
502 if (!cp++) goto badformat;
503 if (*cp != ',') {
504 rp->globhorizillum = atof(cp);
505 if (rp->globhorizillum >= 999900.f)
506 rp->globhorizillum = EPWrecInit.globhorizillum;
507 cp = strchr(cp, ',');
508 }
509 if (!cp++) goto badformat;
510 if (*cp != ',') {
511 rp->diffillum = atof(cp);
512 if (rp->diffillum >= 999900.f)
513 rp->diffillum = EPWrecInit.diffillum;
514 cp = strchr(cp, ',');
515 }
516 if (!cp++) goto badformat;
517 if (*cp != ',') {
518 rp->dirillum = atof(cp);
519 if (rp->dirillum >= 999900.f)
520 rp->dirillum = EPWrecInit.dirillum;
521 cp = strchr(cp, ',');
522 }
523 if (!cp++) goto badformat;
524 if (*cp != ',') {
525 rp->zenlum = atof(cp);
526 if (rp->zenlum >= 9999.f)
527 rp->zenlum = EPWrecInit.zenlum;
528 cp = strchr(cp, ',');
529 }
530 if (!cp++) goto badformat;
531 if (*cp != ',') {
532 rp->windirection = atof(cp);
533 cp = strchr(cp, ',');
534 }
535 if (!cp++) goto badformat;
536 if (*cp != ',') {
537 rp->windspeed = atof(cp);
538 cp = strchr(cp, ',');
539 }
540 if (!cp++) goto badformat;
541 if (*cp != ',') {
542 rp->skycover = atof(cp) * 0.1;
543 cp = strchr(cp, ',');
544 }
545 if (!cp++) goto badformat;
546 if (*cp != ',') {
547 rp->opskycover = atof(cp) * 0.1;
548 cp = strchr(cp, ',');
549 }
550 if (!cp++) goto badformat;
551 if (*cp != ',') {
552 rp->visibility = atof(cp) * 1000.;
553 cp = strchr(cp, ',');
554 }
555 if (!cp++) goto badformat;
556 if (*cp != ',') {
557 rp->ceilheight = atof(cp);
558 cp = strchr(cp, ',');
559 }
560 if (!cp++) goto badformat;
561 cp = strchr(cp, ',');
562 if (!cp++) goto badformat;
563 cp = strchr(cp, ',');
564 if (!cp++) goto badformat;
565 if (*cp != ',') {
566 rp->precip = atof(cp) * 1e-3;
567 cp = strchr(cp, ',');
568 }
569 if (!cp++) goto badformat;
570 if (*cp != ',') {
571 rp->optdepth = atof(cp) * 1e-3;
572 cp = strchr(cp, ',');
573 }
574 if (!cp++) goto badformat;
575 if (*cp != ',') {
576 rp->snowdepth = atof(cp) * 1e-2;
577 cp = strchr(cp, ',');
578 }
579 if (!cp++) goto badformat;
580 if (*cp != ',') {
581 rp->nosnowdays = atoi(cp);
582 cp = strchr(cp, ',');
583 }
584 if (!cp++) goto badformat;
585 if (*cp != ',') {
586 rp->albedo = atof(cp);
587 cp = strchr(cp, ',');
588 }
589 if (!cp++) goto badformat;
590 if (*cp != ',') {
591 rp->liqpdepth = atof(cp) * 1e-3;
592 cp = strchr(cp, ',');
593 }
594 if (!cp++) goto badformat;
595 if ((*cp != ',') & (*cp != '\n'))
596 rp->liqhours = atof(cp);
597 if (scan_date(epw) || feof(epw->fp))
598 return(1); /* normal return (even if next is EOF) */
599 badformat:
600 fprintf(stderr, "%s file, format error at line %d\n",
601 epw->isWEA ? "WEA" : "EPW", epw->lino);
602 return(0);
603 }
604
605 /* Close input and free header data */
606 void
607 EPWclose(EPWheader *epw)
608 {
609 if (!epw) return;
610 if (epw->fp != stdin) fclose(epw->fp);
611 if (epw->comments1) free(epw->comments1);
612 if (epw->comments2) free(epw->comments2);
613 free(epw);
614 return;
615 }
616
617 #ifdef TEST_MAIN
618 int
619 main(int argc, char *argv[])
620 {
621 EPWheader *epw = EPWopen(argv[1]);
622 EPWrecord erec;
623 int rval;
624
625 if (!epw) return(1);
626
627 printf("Weather input file type is %d\n", epw->isWEA);
628 printf("Location is %s, %s\n", epw->loc.city, epw->loc.country);
629 printf("Time zone is %.2f hours from GMT\n", epw->loc.timezone);
630 printf("Latitude, longitude is (%.8f,%.8f) degrees (N,E)\n",
631 epw->loc.latitude, epw->loc.longitude);
632 printf("Elevation is %.0f meters\n", epw->loc.elevation);
633 printf("'%s' starts %d/%d on a %s and ends %d/%d\n", epw->period[0].name,
634 epw->period[0].firstdate.month+1, epw->period[0].firstdate.day,
635 WDname[epw->period[0].startday],
636 epw->period[0].lastdate.month+1, epw->period[0].lastdate.day);
637 while ((rval = EPWread(epw, &erec)) > 0) {
638 printf("Weather record for %d/%d/%d @ %.2f hours:\n", erec.date.month+1,
639 erec.date.day, erec.date.year, erec.date.hour);
640 if (EPWisset(&erec,dbtemp))
641 printf("\tDry bulb temp: %.1f °C\n", erec.dbtemp);
642 if (EPWisset(&erec,dptemp))
643 printf("\tDew point temp: %.1f °C\n", erec.dptemp);
644 if (EPWisset(&erec,humidity))
645 printf("\tHumidity: %.1f%%\n", erec.humidity);
646 if (EPWisset(&erec,atmospressure))
647 printf("\tAtmospheric pressure: %.0f Pa\n", erec.atmospressure);
648 if (EPWisset(&erec,exthorizirrad))
649 printf("\tExtraterrestrial horiz irrad: %.1f w/m2\n", erec.exthorizirrad);
650 if (EPWisset(&erec,horizirrad_ir))
651 printf("\tInfrared direct normal irrad: %.1f w/m2\n", erec.horizirrad_ir);
652 if (EPWisset(&erec,globhorizirrad))
653 printf("\tGlobal horiz irrad: %.1f w/m2\n", erec.globhorizirrad);
654 if (EPWisset(&erec,dirirrad))
655 printf("\tDirect normal irrad: %.1f w/m2\n", erec.dirirrad);
656 if (EPWisset(&erec,horizdiffirrad))
657 printf("\tHorizontal diffuse irrad: %.1f w/m2\n", erec.horizdiffirrad);
658 if (EPWisset(&erec,globhorizillum))
659 printf("\tGlobal horizontal illuminance: %.0f lux\n", erec.globhorizillum);
660 if (EPWisset(&erec,diffillum))
661 printf("\tDiffuse horizontal illuminance: %.0f lux\n", erec.diffillum);
662 if (EPWisset(&erec,dirillum))
663 printf("\tDirect normal illuminance: %.0f lux\n", erec.dirillum);
664 if (EPWisset(&erec,zenlum))
665 printf("\tZenith luminance: %.0f nits\n", erec.zenlum);
666 if (EPWisset(&erec,windirection))
667 printf("\tWind direction: %.1f °E of S\n", erec.windirection);
668 if (EPWisset(&erec,windspeed))
669 printf("\tWind speed: %.2f m/s\n", erec.windspeed);
670 if (EPWisset(&erec,skycover))
671 printf("\tSky cover fraction: %.3f\n", erec.skycover);
672 if (EPWisset(&erec,opskycover))
673 printf("\tOpaque sky cover fraction: %.3f\n", erec.opskycover);
674 if (EPWisset(&erec,visibility))
675 printf("\tVisibility: %.0f meters\n", erec.visibility);
676 if (EPWisset(&erec,ceilheight))
677 printf("\tCloud ceiling height: %.0f meters\n", erec.ceilheight);
678 if (EPWisset(&erec,precip))
679 printf("\tPrecipitation: %f meters\n", erec.precip);
680 if (EPWisset(&erec,optdepth))
681 printf("\tAerosol optical depth: %.4f\n", erec.optdepth);
682 if (EPWisset(&erec,snowdepth))
683 printf("\tSnow depth: %.2f meters\n", erec.snowdepth);
684 if (EPWisset(&erec,nosnowdays))
685 printf("\tDays since last snow: %d\n", erec.nosnowdays);
686 if (EPWisset(&erec,albedo))
687 printf("\tAlbedo: %.4f\n", erec.albedo);
688 if (EPWisset(&erec,liqpdepth))
689 printf("\tLiquid precipitation depth: %.6f meters\n", erec.liqpdepth);
690 if (EPWisset(&erec,liqhours))
691 printf("\tLiquid precipitation time: %.1f hours\n", erec.liqhours);
692 }
693 EPWclose(epw);
694 return(!rval);
695 }
696 #endif /* TEST_MAIN */