89 |
|
#include "color.h" |
90 |
|
#include "sun.h" |
91 |
|
|
92 |
< |
char *progname; /* Program name */ |
93 |
< |
char errmsg[128]; /* Error message buffer */ |
92 |
> |
char *progname; /* Program name */ |
93 |
|
const double DC_SolarConstantE = 1367.0; /* Solar constant W/m^2 */ |
94 |
|
const double DC_SolarConstantL = 127.5; /* Solar constant klux */ |
95 |
|
|
134 |
|
/* Radiuans into degrees */ |
135 |
|
#define RadToDeg(rad) ((rad)*(180./PI)) |
136 |
|
|
138 |
– |
|
137 |
|
/* Perez sky model coefficients */ |
138 |
|
|
139 |
|
/* Reference: Perez, R., R. Seals, and J. Michalsky, 1993. "All- */ |
250 |
|
#define NSUNPATCH 4 /* max. # patches to spread sun into */ |
251 |
|
#endif |
252 |
|
|
253 |
+ |
#define SUN_ANG_DEG 0.533 /* sun full-angle in degrees */ |
254 |
+ |
|
255 |
|
int nsuns = NSUNPATCH; /* number of sun patches to use */ |
256 |
|
double fixed_sun_sa = -1; /* fixed solid angle per sun? */ |
257 |
|
|
270 |
|
float *rh_pazi; /* sky patch azimuths (radians) */ |
271 |
|
float *rh_dom; /* sky patch solid angle (sr) */ |
272 |
|
|
273 |
< |
#define vector(v,alt,azi) ( (v)[1] = tcos(alt), \ |
274 |
< |
(v)[0] = (v)[1]*tsin(azi), \ |
275 |
< |
(v)[1] *= tcos(azi), \ |
276 |
< |
(v)[2] = tsin(alt) ) |
273 |
> |
#define vector(v,alt,azi) ( (v)[1] = cos(alt), \ |
274 |
> |
(v)[0] = (v)[1]*sin(azi), \ |
275 |
> |
(v)[1] *= cos(azi), \ |
276 |
> |
(v)[2] = sin(alt) ) |
277 |
|
|
278 |
|
#define rh_vector(v,i) vector(v,rh_palt[i],rh_pazi[i]) |
279 |
|
|
280 |
|
#define rh_cos(i) tsin(rh_palt[i]) |
281 |
|
|
282 |
+ |
#define solar_minute(jd,hr) ((24*60)*((jd)-1)+(int)((hr)*60.+.5)) |
283 |
+ |
|
284 |
|
extern int rh_init(void); |
285 |
|
extern float * resize_dmatrix(float *mtx_data, int nsteps, int npatch); |
286 |
+ |
extern void OutputSun(int id, int goodsun, FILE *fp, FILE *mfp); |
287 |
|
extern void AddDirect(float *parr); |
288 |
|
|
289 |
|
|
309 |
|
int doheader = 1; /* output header? */ |
310 |
|
double rotation = 0; /* site rotation (degrees) */ |
311 |
|
double elevation; /* site elevation (meters) */ |
312 |
+ |
int leap_day = 0; /* add leap day? */ |
313 |
+ |
int sun_hours_only = 0; /* only output sun hours? */ |
314 |
|
int dir_is_horiz; /* direct is meas. on horizontal? */ |
315 |
|
FILE *sunsfp = NULL; /* output file for individual suns */ |
316 |
+ |
FILE *modsfp = NULL; /* modifier output file */ |
317 |
|
float *mtx_data = NULL; /* our matrix data */ |
318 |
|
int avgSky = 0; /* compute average sky r.t. matrix? */ |
319 |
|
int ntsteps = 0; /* number of time steps */ |
374 |
|
skycolor[1] = atof(argv[++i]); |
375 |
|
skycolor[2] = atof(argv[++i]); |
376 |
|
break; |
377 |
+ |
case 'D': /* output suns to file */ |
378 |
+ |
if (strcmp(argv[++i], "-")) { |
379 |
+ |
sunsfp = fopen(argv[i], "w"); |
380 |
+ |
if (sunsfp == NULL) { |
381 |
+ |
fprintf(stderr, |
382 |
+ |
"%s: cannot open '%s' for output\n", |
383 |
+ |
progname, argv[i]); |
384 |
+ |
exit(1); |
385 |
+ |
} |
386 |
+ |
break; /* still may output matrix */ |
387 |
+ |
} |
388 |
+ |
sunsfp = stdout; /* sending to stdout, so... */ |
389 |
+ |
/* fall through */ |
390 |
|
case 'n': /* no matrix output */ |
391 |
|
avgSky = -1; |
392 |
|
rhsubdiv = 1; |
395 |
|
skycolor[0] = skycolor[1] = skycolor[2] = 0; |
396 |
|
grefl[0] = grefl[1] = grefl[2] = 0; |
397 |
|
break; |
398 |
< |
case 'D': /* output suns to file */ |
399 |
< |
sunsfp = fopen(argv[++i], "w"); |
381 |
< |
if (!sunsfp) { |
398 |
> |
case 'M': /* send sun modifiers to file */ |
399 |
> |
if ((modsfp = fopen(argv[++i], "w")) == NULL) { |
400 |
|
fprintf(stderr, "%s: cannot open '%s' for output\n", |
401 |
< |
argv[0], argv[i]); |
401 |
> |
progname, argv[i]); |
402 |
|
exit(1); |
403 |
|
} |
386 |
– |
fixed_sun_sa = PI/360.*0.533; |
387 |
– |
fixed_sun_sa *= PI*fixed_sun_sa; |
404 |
|
break; |
405 |
|
case 's': /* sky only (no direct) */ |
406 |
|
suncolor[0] = suncolor[1] = suncolor[2] = 0; |
407 |
|
break; |
408 |
+ |
case 'u': /* solar hours only */ |
409 |
+ |
sun_hours_only = 1; |
410 |
+ |
break; |
411 |
|
case 'r': /* rotate distribution */ |
412 |
|
if (argv[i][2] && argv[i][2] != 'z') |
413 |
|
goto userr; |
418 |
|
fixed_sun_sa = PI/360.*atof(argv[++i]); |
419 |
|
if (fixed_sun_sa <= 0) { |
420 |
|
fprintf(stderr, "%s: missing solar disk size argument for '-5' option\n", |
421 |
< |
argv[0]); |
421 |
> |
progname); |
422 |
|
exit(1); |
423 |
|
} |
424 |
|
fixed_sun_sa *= fixed_sun_sa*PI; |
436 |
|
progname, argv[i]); |
437 |
|
exit(1); |
438 |
|
} |
439 |
+ |
if ((modsfp != NULL) & (sunsfp == NULL)) |
440 |
+ |
fprintf(stderr, "%s: warning -M output will be empty without -D\n", |
441 |
+ |
progname); |
442 |
|
if (verbose) { |
443 |
|
if (i == argc-1) |
444 |
|
fprintf(stderr, "%s: reading weather tape '%s'\n", |
481 |
|
fprintf(stderr, "%s: location '%s'\n", progname, buf); |
482 |
|
fprintf(stderr, "%s: (lat,long)=(%.1f,%.1f) degrees north, west\n", |
483 |
|
progname, s_latitude, s_longitude); |
484 |
< |
fprintf(stderr, "%s: %d sky patches per time step\n", |
485 |
< |
progname, nskypatch); |
484 |
> |
if (avgSky >= 0) |
485 |
> |
fprintf(stderr, "%s: %d sky patches\n", |
486 |
> |
progname, nskypatch); |
487 |
> |
if (sunsfp) |
488 |
> |
fprintf(stderr, "%s: outputting suns to file\n", |
489 |
> |
progname); |
490 |
|
if (rotation != 0) |
491 |
|
fprintf(stderr, "%s: rotating output %.0f degrees\n", |
492 |
|
progname, rotation); |
500 |
|
/* process each time step in tape */ |
501 |
|
while (scanf("%d %d %lf %lf %lf\n", &mo, &da, &hr, &dir, &dif) == 5) { |
502 |
|
double sda, sta; |
503 |
+ |
int sun_in_sky; |
504 |
+ |
/* compute solar position */ |
505 |
+ |
if ((mo == 2) & (da == 29)) { |
506 |
+ |
julian_date = 60; |
507 |
+ |
leap_day = 1; |
508 |
+ |
} else |
509 |
+ |
julian_date = jdate(mo, da) + leap_day; |
510 |
+ |
sda = sdec(julian_date); |
511 |
+ |
sta = stadj(julian_date); |
512 |
+ |
altitude = salt(sda, hr+sta); |
513 |
+ |
sun_in_sky = (altitude > -DegToRad(SUN_ANG_DEG/2.)); |
514 |
+ |
if (sun_hours_only && !sun_in_sky) |
515 |
+ |
continue; /* skipping nighttime points */ |
516 |
+ |
azimuth = sazi(sda, hr+sta) + PI - DegToRad(rotation); |
517 |
|
|
518 |
|
mtx_offset = 3*nskypatch*nstored; |
519 |
|
nstored += !avgSky | !nstored; |
523 |
|
mtx_data = resize_dmatrix(mtx_data, tstorage, nskypatch); |
524 |
|
} |
525 |
|
ntsteps++; /* keep count of time steps */ |
526 |
< |
if (dif <= 1e-4) { |
526 |
> |
|
527 |
> |
if (dir+dif <= 1e-4) { /* effectively nighttime? */ |
528 |
|
if (!avgSky | !mtx_offset) |
529 |
< |
memset(mtx_data+mtx_offset, 0, sizeof(float)*3*nskypatch); |
529 |
> |
memset(mtx_data+mtx_offset, 0, |
530 |
> |
sizeof(float)*3*nskypatch); |
531 |
> |
/* output black sun? */ |
532 |
> |
if (sunsfp && sun_in_sky) |
533 |
> |
OutputSun(solar_minute(julian_date,hr), 0, |
534 |
> |
sunsfp, modsfp); |
535 |
|
continue; |
536 |
|
} |
537 |
< |
/* compute solar position */ |
538 |
< |
julian_date = jdate(mo, da); |
539 |
< |
sda = sdec(julian_date); |
540 |
< |
sta = stadj(julian_date); |
495 |
< |
altitude = salt(sda, hr+sta); |
496 |
< |
azimuth = sazi(sda, hr+sta) + PI - DegToRad(rotation); |
537 |
> |
if (!sun_in_sky && dir > (input==1 ? 20. : 20.*WHTEFFICACY)) |
538 |
> |
fprintf(stderr, |
539 |
> |
"%s: warning - unusually bright at %.1f on %d-%d\n", |
540 |
> |
progname, hr, mo, da); |
541 |
|
/* convert measured values */ |
542 |
< |
if (dir_is_horiz && altitude > 0.) |
542 |
> |
if (dir_is_horiz && altitude > FTINY) |
543 |
|
dir /= sin(altitude); |
544 |
|
if (input == 1) { |
545 |
|
dir_irrad = dir; |
550 |
|
} |
551 |
|
/* compute sky patch values */ |
552 |
|
ComputeSky(mtx_data+mtx_offset); |
553 |
< |
/* output sun if indicated */ |
554 |
< |
if (sunsfp && (altitude > 0) & (dir_illum > 1e-4)) { |
555 |
< |
double srad = dir_illum/(WHTEFFICACY * fixed_sun_sa); |
556 |
< |
FVECT sv; |
557 |
< |
vector(sv, altitude, azimuth); |
514 |
< |
fprintf(sunsfp, "\nvoid light solar%d\n0\n0\n", ntsteps); |
515 |
< |
fprintf(sunsfp, "3 %.3e %.3e %.3e\n", srad*suncolor[0], |
516 |
< |
srad*suncolor[1], srad*suncolor[2]); |
517 |
< |
fprintf(sunsfp, "\nsolar%d source sun%d\n0\n0\n", ntsteps, ntsteps); |
518 |
< |
fprintf(sunsfp, "4 %.6f %.6f %.6f 0.533\n", sv[0], sv[1], sv[2]); |
519 |
< |
} |
553 |
> |
/* output sun if requested */ |
554 |
> |
if (sunsfp && sun_in_sky) |
555 |
> |
OutputSun(solar_minute(julian_date,hr), 1, |
556 |
> |
sunsfp, modsfp); |
557 |
> |
|
558 |
|
if (avgSky < 0) /* no matrix? */ |
559 |
|
continue; |
560 |
|
|
566 |
|
if (verbose && mo != last_monthly) |
567 |
|
fprintf(stderr, "%s: stepping through month %d...\n", |
568 |
|
progname, last_monthly=mo); |
569 |
+ |
/* note whether leap-day was given */ |
570 |
|
} |
571 |
|
if (!ntsteps) { |
572 |
|
fprintf(stderr, "%s: no valid time steps on input\n", progname); |
653 |
|
fprintf(stderr, "%s: done.\n", progname); |
654 |
|
exit(0); |
655 |
|
userr: |
656 |
< |
fprintf(stderr, "Usage: %s [-v][-h][-A][-d|-s|-n][-D file][-r deg][-m N][-g r g b][-c r g b][-o{f|d}][-O{0|1}] [tape.wea]\n", |
656 |
> |
fprintf(stderr, "Usage: %s [-v][-h][-A][-d|-s|-n][-u][-D file [-M modfile]][-r deg][-m N][-g r g b][-c r g b][-o{f|d}][-O{0|1}] [tape.wea]\n", |
657 |
|
progname); |
658 |
|
exit(1); |
659 |
|
fmterr: |
815 |
|
*pdest++ += val_add*suncolor[1]; |
816 |
|
*pdest++ += val_add*suncolor[2]; |
817 |
|
} |
818 |
+ |
} |
819 |
+ |
|
820 |
+ |
/* Output a sun to indicated file if appropriate for this time step */ |
821 |
+ |
void |
822 |
+ |
OutputSun(int id, int goodsun, FILE *fp, FILE *mfp) |
823 |
+ |
{ |
824 |
+ |
double srad; |
825 |
+ |
FVECT sv; |
826 |
+ |
|
827 |
+ |
srad = DegToRad(SUN_ANG_DEG/2.); |
828 |
+ |
srad = goodsun ? dir_illum/(WHTEFFICACY * PI*srad*srad) : 0; |
829 |
+ |
vector(sv, altitude, azimuth); |
830 |
+ |
fprintf(fp, "\nvoid light solar%d\n0\n0\n", id); |
831 |
+ |
fprintf(fp, "3 %.3e %.3e %.3e\n", srad*suncolor[0], |
832 |
+ |
srad*suncolor[1], srad*suncolor[2]); |
833 |
+ |
fprintf(fp, "\nsolar%d source sun%d\n0\n0\n", id, id); |
834 |
+ |
fprintf(fp, "4 %.6f %.6f %.6f %.4f\n", sv[0], sv[1], sv[2], SUN_ANG_DEG); |
835 |
+ |
|
836 |
+ |
if (mfp != NULL) /* saving modifier IDs? */ |
837 |
+ |
fprintf(mfp, "solar%d\n", id); |
838 |
|
} |
839 |
|
|
840 |
|
/* Initialize Reinhart sky patch positions (GW) */ |