ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/gendaylit.c
Revision: 2.1
Committed: Sat Jun 6 20:18:32 2009 UTC (14 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Added Jean-Jacques Delaunay's gendaylit program to distribution

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
3 #endif
4 /* Copyright (c) 1994 *Fraunhofer Institut for Solar Energy Systems
5 * Oltmannstr 5, D-79100 Freiburg, Germany
6 * *Agence de l'Environnement et de la Maitrise de l'Energie
7 * Centre de Valbonne, 500 route des Lucioles, 06565 Sophia Antipolis Cedex, France
8 * *BOUYGUES
9 * 1 Avenue Eugene Freyssinet, Saint-Quentin-Yvelines, France
10 */
11
12
13
14 /*
15 * gendaylit.c program to generate the angular distribution of the daylight.
16 * Our zenith is along the Z-axis, the X-axis
17 * points east, and the Y-axis points north.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23 #include <stdlib.h>
24
25 #include "rtio.h"
26 #include "fvect.h"
27 #include "color.h"
28 #include "paths.h"
29
30 extern int jdate(int month, int day);
31 extern double stadj(int jd);
32 extern double sdec(int jd);
33 extern double salt(double sd, double st);
34 extern double sazi(double sd, double st);
35
36 double normsc();
37
38 #define DATFILE "coeff_perez.dat"
39
40
41
42 /* Perez sky parametrization : epsilon and delta calculations from the direct and diffuse irradiances */
43 double sky_brightness();
44 double sky_clearness();
45
46 /* calculation of the direct and diffuse components from the Perez parametrization */
47 double diffus_irradiance_from_sky_brightness();
48 double direct_irradiance_from_sky_clearness();
49
50
51 /* Perez global horizontal, diffuse horizontal and direct normal luminous efficacy models : input w(cm)=2cm, solar zenith angle(degrees); output efficacy(lm/W) */
52 double glob_h_effi_PEREZ();
53 double glob_h_diffuse_effi_PEREZ();
54 double direct_n_effi_PEREZ();
55 /*likelihood check of the epsilon, delta, direct and diffuse components*/
56 void check_parametrization();
57 void check_irradiances();
58 void check_illuminances();
59 void illu_to_irra_index();
60
61
62 /* Perez sky luminance model */
63 int lect_coeff_perez(char *filename,float **coeff_perez);
64 double calc_rel_lum_perez(double dzeta,double gamma,double Z,
65 double epsilon,double Delta,float *coeff_perez);
66 /* coefficients for the sky luminance perez model */
67 void coeff_lum_perez(double Z, double epsilon, double Delta, float *coeff_perez);
68 double radians(double degres);
69 double degres(double radians);
70 void theta_phi_to_dzeta_gamma(double theta,double phi,double *dzeta,double *gamma, double Z);
71 double integ_lv(float *lv,float *theta);
72 float *theta_ordered(char *filename);
73 float *phi_ordered(char *filename);
74
75
76
77 /* astronomy and geometry*/
78 double get_eccentricity();
79 double air_mass();
80 double get_angle_sun_direction(double sun_zenith, double sun_azimut, double direction_zenith, double direction_azimut);
81
82
83 /* date*/
84 int jdate(int month, int day);
85
86
87
88
89
90 /* sun calculation constants */
91 extern double s_latitude;
92 extern double s_longitude;
93 extern double s_meridian;
94
95 const double AU = 149597890E3;
96 const double solar_constant_e = 1367; /* solar constant W/m^2 */
97 const double solar_constant_l = 127.5; /* solar constant klux */
98
99 const double half_sun_angle = 0.2665;
100 const double half_direct_angle = 2.85;
101
102 const double skyclearinf = 1.000; /* limitations for the variation of the Perez parameters */
103 const double skyclearsup = 12.1;
104 const double skybriginf = 0.01;
105 const double skybrigsup = 0.6;
106
107
108
109 /* required values */
110 int month, day; /* date */
111 double hour; /* time */
112 int tsolar; /* 0=standard, 1=solar */
113 double altitude, azimuth; /* or solar angles */
114
115
116
117 /* definition of the sky conditions through the Perez parametrization */
118 double skyclearness, skybrightness;
119 double solarradiance; /*radiance of the sun disk and of the circumsolar area*/
120 double diffusilluminance, directilluminance, diffusirradiance, directirradiance;
121 double sunzenith, daynumber=150, atm_preci_water=2;
122
123 double diffnormalization, dirnormalization;
124 double *c_perez;
125
126 int output=0; /*define the unit of the output (sky luminance or radiance): visible watt=0, solar watt=1, lumen=2*/
127 int input=0; /*define the input for the calulation*/
128
129 /* default values */
130 int cloudy = 0; /* 1=standard, 2=uniform */
131 int dosun = 1;
132 double zenithbr = -1.0;
133 double betaturbidity = 0.1;
134 double gprefl = 0.2;
135 int S_INTER=0;
136
137 /* computed values */
138 double sundir[3];
139 double groundbr;
140 double F2;
141 double solarbr = 0.0;
142 int u_solar = 0; /* -1=irradiance, 1=radiance */
143
144 char *progname;
145 char errmsg[128];
146
147
148 main(argc, argv)
149 int argc;
150 char *argv[];
151 {
152 int i;
153
154 progname = argv[0];
155 if (argc == 2 && !strcmp(argv[1], "-defaults")) {
156 printdefaults();
157 exit(0);
158 }
159 if (argc < 4)
160 userror("arg count");
161 if (!strcmp(argv[1], "-ang")) {
162 altitude = atof(argv[2]) * (M_PI/180);
163 azimuth = atof(argv[3]) * (M_PI/180);
164 month = 0;
165 } else {
166 month = atoi(argv[1]);
167 if (month < 1 || month > 12)
168 userror("bad month");
169 day = atoi(argv[2]);
170 if (day < 1 || day > 31)
171 userror("bad day");
172 hour = atof(argv[3]);
173 if (hour < 0 || hour >= 24)
174 userror("bad hour");
175 tsolar = argv[3][0] == '+';
176 }
177 for (i = 4; i < argc; i++)
178 if (argv[i][0] == '-' || argv[i][0] == '+')
179 switch (argv[i][1]) {
180 case 's':
181 cloudy = 0;
182 dosun = argv[i][0] == '+';
183 break;
184 case 'r':
185 case 'R':
186 u_solar = argv[i][1] == 'R' ? -1 : 1;
187 solarbr = atof(argv[++i]);
188 break;
189 case 'c':
190 cloudy = argv[i][0] == '+' ? 2 : 1;
191 dosun = 0;
192 break;
193 case 't':
194 betaturbidity = atof(argv[++i]);
195 break;
196 case 'b':
197 zenithbr = atof(argv[++i]);
198 break;
199 case 'g':
200 gprefl = atof(argv[++i]);
201 break;
202 case 'a':
203 s_latitude = atof(argv[++i]) * (M_PI/180);
204 break;
205 case 'o':
206 s_longitude = atof(argv[++i]) * (M_PI/180);
207 break;
208 case 'm':
209 s_meridian = atof(argv[++i]) * (M_PI/180);
210 break;
211
212
213 case 'O':
214 output = atof(argv[++i]); /*define the unit of the output of the program :
215 sky and sun luminance/radiance (0==W visible, 1==W solar radiation, 2==lm)
216 default is set to 0*/
217 break;
218
219 case 'P':
220 input = 0; /* Perez parameters: epsilon, delta */
221 skyclearness = atof(argv[++i]);
222 skybrightness = atof(argv[++i]);
223 break;
224
225 case 'W': /* direct normal Irradiance [W/m^2] */
226 input = 1; /* diffuse horizontal Irrad. [W/m^2] */
227 directirradiance = atof(argv[++i]);
228 diffusirradiance = atof(argv[++i]);
229 break;
230
231 case 'L': /* direct normal Illuminance [Lux] */
232 input = 2; /* diffuse horizontal Ill. [Lux] */
233 directilluminance = atof(argv[++i]);
234 diffusilluminance = atof(argv[++i]);
235 break;
236
237 case 'G': /* direct horizontal Irradiance [W/m^2] */
238 input = 3; /* diffuse horizontal Irrad. [W/m^2] */
239 directirradiance = atof(argv[++i]);
240 diffusirradiance = atof(argv[++i]);
241 break;
242
243
244 default:
245 sprintf(errmsg, "unknown option: %s", argv[i]);
246 userror(errmsg);
247 }
248 else
249 userror("bad option");
250
251 if (fabs(s_meridian-s_longitude) > 30*M_PI/180)
252 fprintf(stderr,
253 "%s: warning: %.1f hours btwn. standard meridian and longitude\n",
254 progname, (s_longitude-s_meridian)*12/M_PI);
255
256
257 /* allocation dynamique de memoire pour les pointeurs */
258 if ( (c_perez = malloc(5*sizeof(double))) == NULL )
259 {
260 fprintf(stderr,"Out of memory error in function main !");
261 exit(1);
262 }
263
264
265 printhead(argc, argv);
266
267 computesky();
268 printsky();
269
270 exit(0);
271 }
272
273
274 computesky() /* compute sky parameters */
275 {
276
277 /* new variables */
278 int j, i;
279 float *lv_mod; /* 145 luminance values*/
280 /* 145 directions for the calculation of the normalization coefficient, coefficient Perez model */
281 float *theta_o, *phi_o, *coeff_perez;
282 double dzeta, gamma;
283 double diffusion;
284 double normfactor;
285
286
287
288 /* compute solar direction */
289
290 if (month) { /* from date and time */
291 int jd;
292 double sd, st;
293
294 jd = jdate(month, day); /* Julian date */
295 sd = sdec(jd); /* solar declination */
296 if (tsolar) /* solar time */
297 st = hour;
298 else
299 st = hour + stadj(jd);
300 altitude = salt(sd, st);
301 azimuth = sazi(sd, st);
302
303 daynumber = (double)jdate(month, day);
304
305 }
306 if (!cloudy && altitude > 87.*M_PI/180.) {
307 fprintf(stderr,
308 "%s: warning - sun too close to zenith, reducing altitude to 87 degrees\n",
309 progname);
310 printf(
311 "# warning - sun too close to zenith, reducing altitude to 87 degrees\n");
312 altitude = 87.*M_PI/180.;
313 }
314 sundir[0] = -sin(azimuth)*cos(altitude);
315 sundir[1] = -cos(azimuth)*cos(altitude);
316 sundir[2] = sin(altitude);
317
318
319 /* calculation for the new functions */
320 sunzenith = 90 - altitude*180/M_PI;
321
322
323
324 /* compute the inputs for the calculation of the light distribution over the sky*/
325 if (input==0)
326 {
327 check_parametrization();
328 diffusirradiance = diffus_irradiance_from_sky_brightness(); /*diffuse horizontal irradiance*/
329 directirradiance = direct_irradiance_from_sky_clearness();
330 check_irradiances();
331
332 if (output==0 || output==2)
333 {
334 diffusilluminance = diffusirradiance*glob_h_diffuse_effi_PEREZ();/*diffuse horizontal illuminance*/
335 directilluminance = directirradiance*direct_n_effi_PEREZ();
336 check_illuminances();
337 }
338 }
339
340
341 else if (input==1)
342 {
343 check_irradiances();
344 skybrightness = sky_brightness();
345 skyclearness = sky_clearness();
346 check_parametrization();
347
348 if (output==0 || output==2)
349 {
350 diffusilluminance = diffusirradiance*glob_h_diffuse_effi_PEREZ();/*diffuse horizontal illuminance*/
351 directilluminance = directirradiance*direct_n_effi_PEREZ();
352 check_illuminances();
353 }
354
355 }
356
357
358 else if (input==2)
359 {
360 check_illuminances();
361 illu_to_irra_index();
362 check_parametrization();
363 }
364
365
366 else if (input==3)
367 {
368 if (altitude<=0)
369 {
370 fprintf(stderr, "solar zenith angle larger than 90� \n the models used are not more valid\n");
371 exit(1);
372 }
373
374 directirradiance=directirradiance/sin(altitude);
375 check_irradiances();
376 skybrightness = sky_brightness();
377 skyclearness = sky_clearness();
378 check_parametrization();
379
380 if (output==0 || output==2)
381 {
382 diffusilluminance = diffusirradiance*glob_h_diffuse_effi_PEREZ();/*diffuse horizontal illuminance*/
383 directilluminance = directirradiance*direct_n_effi_PEREZ();
384 check_illuminances();
385 }
386
387 }
388
389
390 else {fprintf(stderr,"error in giving the input arguments"); exit(1);}
391
392
393
394 /* normalization factor for the relative sky luminance distribution, diffuse part*/
395
396 /* allocation dynamique de memoire pour les pointeurs */
397 if ( (coeff_perez = malloc(8*20*sizeof(float))) == NULL )
398 {
399 fprintf(stderr,"Out of memory error in function main !");
400 exit(1);
401 }
402
403 /* read the coefficients for the Perez sky luminance model */
404 if (lect_coeff_perez(DATFILE, &coeff_perez) > 0)
405 {
406 fprintf(stderr,"lect_coeff_perez does not work\n");
407 exit(2);
408 }
409
410 if ( (lv_mod = malloc(145*sizeof(float))) == NULL)
411 {
412 fprintf(stderr,"Out of memory in function main");
413 exit(1);
414 }
415
416 /* read the angles */
417 theta_o = theta_ordered("defangle.dat");
418 phi_o = phi_ordered("defangle.dat");
419
420 /* parameters for the perez model */
421 coeff_lum_perez(radians(sunzenith), skyclearness, skybrightness, coeff_perez);
422
423 /*calculation of the modelled luminance */
424 for (j=0;j<145;j++)
425 {
426 theta_phi_to_dzeta_gamma(radians(*(theta_o+j)),radians(*(phi_o+j)),&dzeta,&gamma,radians(sunzenith));
427 *(lv_mod+j) = calc_rel_lum_perez(dzeta,gamma,radians(sunzenith),skyclearness,skybrightness,coeff_perez);
428 /*printf("theta, phi, lv_mod %lf\t %lf\t %lf\n", *(theta_o+j),*(phi_o+j),*(lv_mod+j));*/
429 }
430
431 /* integration of luminance for the normalization factor, diffuse part of the sky*/
432 diffnormalization = integ_lv(lv_mod, theta_o);
433 /*printf("perez integration %lf\n", diffnormalization);*/
434
435
436
437
438 /*normalization coefficient in lumen or in watt*/
439 if (output==0)
440 {
441 diffnormalization = diffusilluminance/diffnormalization/WHTEFFICACY;
442 }
443 else if (output==1)
444 {
445 diffnormalization = diffusirradiance/diffnormalization;
446 }
447 else if (output==2)
448 {
449 diffnormalization = diffusilluminance/diffnormalization;
450 }
451
452 else {fprintf(stderr,"output argument : wrong number"); exit(1);}
453
454
455
456
457 /* calculation for the solar source */
458 if (output==0)
459 solarradiance = directilluminance/(2*M_PI*(1-cos(half_sun_angle*M_PI/180)))/WHTEFFICACY;
460
461 else if (output==1)
462 solarradiance = directirradiance/(2*M_PI*(1-cos(half_sun_angle*M_PI/180)));
463
464 else
465 solarradiance = directilluminance/(2*M_PI*(1-cos(half_sun_angle*M_PI/180)));
466
467
468
469
470 /* Compute the ground radiance */
471 zenithbr=calc_rel_lum_perez(0.0,radians(sunzenith),radians(sunzenith),skyclearness,skybrightness,coeff_perez);
472 zenithbr*=diffnormalization;
473 fprintf(stderr, "gendaylit : the actual zenith radiance(W/m^2/sr) or luminance(cd/m^2) is : %.0lf\n", zenithbr);
474
475 if (skyclearness==1)
476 normfactor = 0.777778;
477
478 if (skyclearness>=6)
479 {
480 F2 = 0.274*(0.91 + 10.0*exp(-3.0*(M_PI/2.0-altitude)) + 0.45*sundir[2]*sundir[2]);
481 normfactor = normsc()/F2/M_PI;
482 }
483
484 if ( (skyclearness>1) && (skyclearness<6) )
485 {
486 S_INTER=1;
487 F2 = (2.739 + .9891*sin(.3119+2.6*altitude)) * exp(-(M_PI/2.0-altitude)*(.4441+1.48*altitude));
488 normfactor = normsc()/F2/M_PI;
489 }
490
491 groundbr = zenithbr*normfactor;
492 printf("# Ground ambient level: %.1f\n", groundbr);
493
494 if (dosun&&(skyclearness>1))
495 groundbr += 6.8e-5/M_PI*solarradiance*sundir[2];
496
497 groundbr *= gprefl;
498
499
500
501 return;
502 }
503
504
505
506
507
508
509
510 printsky() /* print out sky */
511 {
512 if (dosun&&(skyclearness>1))
513 {
514 printf("\nvoid light solar\n");
515 printf("0\n0\n");
516 printf("3 %.3e %.3e %.3e\n", solarradiance, solarradiance, solarradiance);
517 printf("\nsolar source sun\n");
518 printf("0\n0\n");
519 printf("4 %f %f %f %f\n", sundir[0], sundir[1], sundir[2], 2*half_sun_angle);
520 }
521
522 if (dosun&&(skyclearness==1))
523 {
524 printf("\nvoid light solar\n");
525 printf("0\n0\n");
526 printf("3 0.0 0.0 0.0\n");
527 printf("\nsolar source sun\n");
528 printf("0\n0\n");
529 printf("4 %f %f %f %f\n", sundir[0], sundir[1], sundir[2], 2*half_sun_angle);
530 }
531
532
533 printf("\nvoid brightfunc skyfunc\n");
534 printf("2 skybright perezlum.cal\n");
535 printf("0\n");
536 printf("10 %.3e %.3e %lf %lf %lf %lf %lf %f %f %f \n", diffnormalization, groundbr,
537 *(c_perez+0),*(c_perez+1),*(c_perez+2),*(c_perez+3),*(c_perez+4),
538 sundir[0], sundir[1], sundir[2]);
539 }
540
541
542 printdefaults() /* print default values */
543 {
544 printf("-g %f\t\t\t# Ground plane reflectance\n", gprefl);
545 if (zenithbr > 0.0)
546 printf("-b %f\t\t\t# Zenith radiance (watts/ster/m^2\n", zenithbr);
547 else
548 printf("-t %f\t\t\t# Atmospheric betaturbidity\n", betaturbidity);
549 printf("-a %f\t\t\t# Site latitude (degrees)\n", s_latitude*(180/M_PI));
550 printf("-o %f\t\t\t# Site longitude (degrees)\n", s_longitude*(180/M_PI));
551 printf("-m %f\t\t\t# Standard meridian (degrees)\n", s_meridian*(180/M_PI));
552 }
553
554
555 userror(msg) /* print usage error and quit */
556 char *msg;
557 {
558 if (msg != NULL)
559 fprintf(stderr, "%s: Use error - %s\n", progname, msg);
560 fprintf(stderr, "Usage: %s month day hour [-P|-W|-L] direct_value diffus_value [options]\n", progname);
561 fprintf(stderr, "or : %s -ang altitude azimuth [-P|-W|-L] direct_value diffus_value [options]\n", progname);
562 fprintf(stderr, " -P epsilon delta (these are the Perez parameters) \n");
563 fprintf(stderr, " -W direct-normal-irradiance diffuse-horizontal-irradiance (W/m^2)\n");
564 fprintf(stderr, " -L direct-normal-illuminance diffuse-horizontal-illuminance (lux)\n");
565 fprintf(stderr, " -G direct-horizontal-irradiance diffuse-horizontal-irradiance (W/m^2)\n");
566 fprintf(stderr, " -O [0|1|2] (0=output in W/m^2/sr visible, 1=output in W/m^2/sr solar, 2=output in candela/m^2), default is 0 \n");
567 exit(1);
568 }
569
570
571
572 double
573 normsc() /* compute normalization factor (E0*F2/L0) */
574 {
575 static double nfc[2][5] = {
576 /* clear sky approx. */
577 {2.766521, 0.547665, -0.369832, 0.009237, 0.059229},
578 /* intermediate sky approx. */
579 {3.5556, -2.7152, -1.3081, 1.0660, 0.60227},
580 };
581 register double *nf;
582 double x, nsc;
583 register int i;
584 /* polynomial approximation */
585 nf = nfc[S_INTER];
586 x = (altitude - M_PI/4.0)/(M_PI/4.0);
587 nsc = nf[i=4];
588 while (i--)
589 nsc = nsc*x + nf[i];
590
591 return(nsc);
592 }
593
594
595
596 printhead(ac, av) /* print command header */
597 register int ac;
598 register char **av;
599 {
600 putchar('#');
601 while (ac--) {
602 putchar(' ');
603 fputs(*av++, stdout);
604 }
605 putchar('\n');
606 }
607
608
609
610
611
612
613
614
615
616
617
618
619 /* Perez models */
620
621 /* Perez global horizontal luminous efficacy model */
622 double glob_h_effi_PEREZ()
623 {
624
625 double value;
626 double category_bounds[10], a[10], b[10], c[10], d[10];
627 int category_total_number, category_number, i;
628
629
630 if (skyclearness<skyclearinf || skyclearness>skyclearsup || skybrightness<=skybriginf || skybrightness>skybrigsup)
631 fprintf(stderr, "Warning : skyclearness or skybrightness out of range ; \n Check your input parameters\n");
632
633 /* initialize category bounds (clearness index bounds) */
634
635 category_total_number = 8;
636
637 category_bounds[1] = 1;
638 category_bounds[2] = 1.065;
639 category_bounds[3] = 1.230;
640 category_bounds[4] = 1.500;
641 category_bounds[5] = 1.950;
642 category_bounds[6] = 2.800;
643 category_bounds[7] = 4.500;
644 category_bounds[8] = 6.200;
645 category_bounds[9] = 12.01;
646
647
648 /* initialize model coefficients */
649 a[1] = 96.63;
650 a[2] = 107.54;
651 a[3] = 98.73;
652 a[4] = 92.72;
653 a[5] = 86.73;
654 a[6] = 88.34;
655 a[7] = 78.63;
656 a[8] = 99.65;
657
658 b[1] = -0.47;
659 b[2] = 0.79;
660 b[3] = 0.70;
661 b[4] = 0.56;
662 b[5] = 0.98;
663 b[6] = 1.39;
664 b[7] = 1.47;
665 b[8] = 1.86;
666
667 c[1] = 11.50;
668 c[2] = 1.79;
669 c[3] = 4.40;
670 c[4] = 8.36;
671 c[5] = 7.10;
672 c[6] = 6.06;
673 c[7] = 4.93;
674 c[8] = -4.46;
675
676 d[1] = -9.16;
677 d[2] = -1.19;
678 d[3] = -6.95;
679 d[4] = -8.31;
680 d[5] = -10.94;
681 d[6] = -7.60;
682 d[7] = -11.37;
683 d[8] = -3.15;
684
685
686
687
688 for (i=1; i<=category_total_number; i++)
689 {
690 if ( (skyclearness >= category_bounds[i]) && (skyclearness < category_bounds[i+1]) )
691 category_number = i;
692 }
693
694 value = a[category_number] + b[category_number]*atm_preci_water +
695 c[category_number]*cos(sunzenith*M_PI/180) + d[category_number]*log(skybrightness);
696
697 return(value);
698 }
699
700
701 /* global horizontal diffuse efficacy model, according to PEREZ */
702 double glob_h_diffuse_effi_PEREZ()
703 {
704 double value;
705 double category_bounds[10], a[10], b[10], c[10], d[10];
706 int category_total_number, category_number, i;
707
708
709 if (skyclearness<skyclearinf || skyclearness>skyclearsup || skybrightness<=skybriginf || skybrightness>skybrigsup)
710 fprintf(stderr, "Warning : skyclearness or skybrightness out of range ; \n Check your input parameters\n");
711
712 /* initialize category bounds (clearness index bounds) */
713
714 category_total_number = 8;
715
716 category_bounds[1] = 1;
717 category_bounds[2] = 1.065;
718 category_bounds[3] = 1.230;
719 category_bounds[4] = 1.500;
720 category_bounds[5] = 1.950;
721 category_bounds[6] = 2.800;
722 category_bounds[7] = 4.500;
723 category_bounds[8] = 6.200;
724 category_bounds[9] = 12.01;
725
726
727 /* initialize model coefficients */
728 a[1] = 97.24;
729 a[2] = 107.22;
730 a[3] = 104.97;
731 a[4] = 102.39;
732 a[5] = 100.71;
733 a[6] = 106.42;
734 a[7] = 141.88;
735 a[8] = 152.23;
736
737 b[1] = -0.46;
738 b[2] = 1.15;
739 b[3] = 2.96;
740 b[4] = 5.59;
741 b[5] = 5.94;
742 b[6] = 3.83;
743 b[7] = 1.90;
744 b[8] = 0.35;
745
746 c[1] = 12.00;
747 c[2] = 0.59;
748 c[3] = -5.53;
749 c[4] = -13.95;
750 c[5] = -22.75;
751 c[6] = -36.15;
752 c[7] = -53.24;
753 c[8] = -45.27;
754
755 d[1] = -8.91;
756 d[2] = -3.95;
757 d[3] = -8.77;
758 d[4] = -13.90;
759 d[5] = -23.74;
760 d[6] = -28.83;
761 d[7] = -14.03;
762 d[8] = -7.98;
763
764
765
766
767 for (i=1; i<=category_total_number; i++)
768 {
769 if ( (skyclearness >= category_bounds[i]) && (skyclearness < category_bounds[i+1]) )
770 category_number = i;
771 }
772
773 value = a[category_number] + b[category_number]*atm_preci_water + c[category_number]*cos(sunzenith*M_PI/180) +
774 d[category_number]*log(skybrightness);
775
776 return(value);
777 }
778
779
780 /* direct normal efficacy model, according to PEREZ */
781
782 double direct_n_effi_PEREZ()
783
784 {
785 double value;
786 double category_bounds[10], a[10], b[10], c[10], d[10];
787 int category_total_number, category_number, i;
788
789
790 if (skyclearness<skyclearinf || skyclearness>skyclearsup || skybrightness<=skybriginf || skybrightness>skybrigsup)
791 fprintf(stderr, "Warning : skyclearness or skybrightness out of range ; \n Check your input parameters\n");
792
793
794 /* initialize category bounds (clearness index bounds) */
795
796 category_total_number = 8;
797
798 category_bounds[1] = 1;
799 category_bounds[2] = 1.065;
800 category_bounds[3] = 1.230;
801 category_bounds[4] = 1.500;
802 category_bounds[5] = 1.950;
803 category_bounds[6] = 2.800;
804 category_bounds[7] = 4.500;
805 category_bounds[8] = 6.200;
806 category_bounds[9] = 12.1;
807
808
809 /* initialize model coefficients */
810 a[1] = 57.20;
811 a[2] = 98.99;
812 a[3] = 109.83;
813 a[4] = 110.34;
814 a[5] = 106.36;
815 a[6] = 107.19;
816 a[7] = 105.75;
817 a[8] = 101.18;
818
819 b[1] = -4.55;
820 b[2] = -3.46;
821 b[3] = -4.90;
822 b[4] = -5.84;
823 b[5] = -3.97;
824 b[6] = -1.25;
825 b[7] = 0.77;
826 b[8] = 1.58;
827
828 c[1] = -2.98;
829 c[2] = -1.21;
830 c[3] = -1.71;
831 c[4] = -1.99;
832 c[5] = -1.75;
833 c[6] = -1.51;
834 c[7] = -1.26;
835 c[8] = -1.10;
836
837 d[1] = 117.12;
838 d[2] = 12.38;
839 d[3] = -8.81;
840 d[4] = -4.56;
841 d[5] = -6.16;
842 d[6] = -26.73;
843 d[7] = -34.44;
844 d[8] = -8.29;
845
846
847
848 for (i=1; i<=category_total_number; i++)
849 {
850 if ( (skyclearness >= category_bounds[i]) && (skyclearness < category_bounds[i+1]) )
851 category_number = i;
852 }
853
854 value = a[category_number] + b[category_number]*atm_preci_water + c[category_number]*exp(5.73*sunzenith*M_PI/180 - 5) + d[category_number]*skybrightness;
855
856 if (value < 0) value = 0;
857
858 return(value);
859 }
860
861
862 /*check the range of epsilon and delta indexes of the perez parametrization*/
863 void check_parametrization()
864 {
865 if (skyclearness<skyclearinf || skyclearness>skyclearsup || skybrightness<=skybriginf || skybrightness>skybrigsup)
866 {
867 fprintf(stderr,"sky clearness or sky brightness out of range %lf\t %lf\n", skyclearness, skybrightness);
868 exit(1);
869 }
870 else return;
871 }
872
873
874 /* likelihood of the direct and diffuse components */
875 void check_illuminances()
876 {
877 if (!( (directilluminance>=0) && (directilluminance<=solar_constant_l*1000) && (diffusilluminance>0) ))
878 {
879 fprintf(stderr,"direct or diffuse illuminances out of range\n");
880 exit(1);
881 }
882 return;
883 }
884
885
886 void check_irradiances()
887 {
888 if (!( (directirradiance>=0) && (directirradiance<=solar_constant_e) && (diffusirradiance>0) ))
889 {
890 fprintf(stderr,"direct or diffuse irradiances out of range\n");
891 exit(1);
892 }
893 return;
894 }
895
896
897
898 /* Perez sky's brightness */
899 double sky_brightness()
900 {
901 double value;
902
903 value = diffusirradiance * air_mass() / ( solar_constant_e*get_eccentricity());
904
905 return(value);
906 }
907
908
909 /* Perez sky's clearness */
910 double sky_clearness()
911 {
912 double value;
913
914 value = ( (diffusirradiance + directirradiance)/(diffusirradiance) + 1.041*sunzenith*M_PI/180*sunzenith*M_PI/180*sunzenith*M_PI/180 ) / (1 + 1.041*sunzenith*M_PI/180*sunzenith*M_PI/180*sunzenith*M_PI/180) ;
915
916 return(value);
917 }
918
919
920
921 /* diffus horizontal irradiance from Perez sky's brightness */
922 double diffus_irradiance_from_sky_brightness()
923 {
924 double value;
925
926 value = skybrightness / air_mass() * ( solar_constant_e*get_eccentricity());
927
928 return(value);
929 }
930
931
932 /* direct normal irradiance from Perez sky's clearness */
933 double direct_irradiance_from_sky_clearness()
934 {
935 double value;
936
937 value = diffus_irradiance_from_sky_brightness();
938 value = value * ( (skyclearness-1) * (1+1.041*sunzenith*M_PI/180*sunzenith*M_PI/180*sunzenith*M_PI/180) );
939
940 return(value);
941 }
942
943
944 void illu_to_irra_index(void)
945 {
946 double test1=0.1, test2=0.1;
947 int counter=0;
948
949 diffusirradiance = diffusilluminance*solar_constant_e/(solar_constant_l*1000);
950 directirradiance = directilluminance*solar_constant_e/(solar_constant_l*1000);
951 skyclearness = sky_clearness();
952 skybrightness = sky_brightness();
953 if (skyclearness>12) skyclearness=12;
954 if (skybrightness<0.05) skybrightness=0.01;
955
956
957 while ( ((fabs(diffusirradiance-test1)>10) || (fabs(directirradiance-test2)>10)
958 || skyclearness>skyclearinf || skyclearness<skyclearsup
959 || skybrightness>skybriginf || skybrightness<skybrigsup )
960 && !(counter==5) )
961 {
962 /*fprintf(stderr, "conversion illuminance into irradiance %lf\t %lf\n", diffusirradiance, directirradiance);*/
963
964 test1=diffusirradiance;
965 test2=directirradiance;
966 counter++;
967
968 diffusirradiance = diffusilluminance/glob_h_diffuse_effi_PEREZ();
969 directirradiance = directilluminance/direct_n_effi_PEREZ();
970 /*fprintf(stderr, "conversion illuminance into irradiance %lf\t %lf\n", diffusirradiance, directirradiance);*/
971
972 skybrightness = sky_brightness();
973 skyclearness = sky_clearness();
974 if (skyclearness>12) skyclearness=12;
975 if (skybrightness<0.05) skybrightness=0.01;
976
977 /*fprintf(stderr, "%lf\t %lf\n", skybrightness, skyclearness);*/
978
979 }
980
981
982 return;
983 }
984
985
986 int lect_coeff_perez(char *filename,float **coeff_perez)
987 {
988 FILE *fcoeff_perez;
989 float temp;
990 int i,j;
991
992 if ((fcoeff_perez = frlibopen(filename)) == NULL)
993 {
994 fprintf(stderr,"file %s cannot be opened\n", filename);
995 return 1; /* il y a un probleme de fichier */
996 }
997 else
998 {
999 /*printf("file %s open\n", filename);*/
1000 }
1001
1002 rewind(fcoeff_perez); /* on se place en debut de fichier */
1003
1004 for (i=0;i<8;i++)
1005 for (j=0;j<20;j++)
1006 {
1007 fscanf(fcoeff_perez,"%f",&temp);
1008 *(*coeff_perez+i*20+j) = temp;
1009 }
1010 fclose(fcoeff_perez);
1011
1012 return 0; /* tout est OK */
1013 }
1014
1015
1016
1017 /* sky luminance perez model */
1018 double calc_rel_lum_perez(double dzeta,double gamma,double Z,
1019 double epsilon,double Delta,float *coeff_perez)
1020 {
1021 float x[5][4];
1022 int i,j,num_lin;
1023 double c_perez[5];
1024
1025 if ( (epsilon < skyclearinf) || (epsilon >= skyclearsup) )
1026 {
1027 fprintf(stderr,"Epsilon out of range in function calc_rel_lum_perez !\n");
1028 exit(1);
1029 }
1030
1031 /* correction de modele de Perez solar energy ...*/
1032 if ( (epsilon > 1.065) && (epsilon < 2.8) )
1033 {
1034 if ( Delta < 0.2 ) Delta = 0.2;
1035 }
1036
1037 if ( (epsilon >= 1.000) && (epsilon < 1.065) ) num_lin = 0;
1038 if ( (epsilon >= 1.065) && (epsilon < 1.230) ) num_lin = 1;
1039 if ( (epsilon >= 1.230) && (epsilon < 1.500) ) num_lin = 2;
1040 if ( (epsilon >= 1.500) && (epsilon < 1.950) ) num_lin = 3;
1041 if ( (epsilon >= 1.950) && (epsilon < 2.800) ) num_lin = 4;
1042 if ( (epsilon >= 2.800) && (epsilon < 4.500) ) num_lin = 5;
1043 if ( (epsilon >= 4.500) && (epsilon < 6.200) ) num_lin = 6;
1044 if ( (epsilon >= 6.200) && (epsilon < 14.00) ) num_lin = 7;
1045
1046 for (i=0;i<5;i++)
1047 for (j=0;j<4;j++)
1048 {
1049 x[i][j] = *(coeff_perez + 20*num_lin + 4*i +j);
1050 /* printf("x %d %d vaut %f\n",i,j,x[i][j]); */
1051 }
1052
1053
1054 if (num_lin)
1055 {
1056 for (i=0;i<5;i++)
1057 c_perez[i] = x[i][0] + x[i][1]*Z + Delta * (x[i][2] + x[i][3]*Z);
1058 }
1059 else
1060 {
1061 c_perez[0] = x[0][0] + x[0][1]*Z + Delta * (x[0][2] + x[0][3]*Z);
1062 c_perez[1] = x[1][0] + x[1][1]*Z + Delta * (x[1][2] + x[1][3]*Z);
1063 c_perez[4] = x[4][0] + x[4][1]*Z + Delta * (x[4][2] + x[4][3]*Z);
1064 c_perez[2] = exp( pow(Delta*(x[2][0]+x[2][1]*Z),x[2][2])) - x[2][3];
1065 c_perez[3] = -exp( Delta*(x[3][0]+x[3][1]*Z) )+x[3][2]+Delta*x[3][3];
1066 }
1067
1068
1069 return (1 + c_perez[0]*exp(c_perez[1]/cos(dzeta)) ) *
1070 (1 + c_perez[2]*exp(c_perez[3]*gamma) +
1071 c_perez[4]*cos(gamma)*cos(gamma) );
1072 }
1073
1074
1075
1076 /* coefficients for the sky luminance perez model */
1077 void coeff_lum_perez(double Z, double epsilon, double Delta, float *coeff_perez)
1078 {
1079 float x[5][4];
1080 int i,j,num_lin;
1081
1082 if ( (epsilon < skyclearinf) || (epsilon >= skyclearsup) )
1083 {
1084 fprintf(stderr,"Epsilon out of range in function calc_rel_lum_perez !\n");
1085 exit(1);
1086 }
1087
1088 /* correction du modele de Perez solar energy ...*/
1089 if ( (epsilon > 1.065) && (epsilon < 2.8) )
1090 {
1091 if ( Delta < 0.2 ) Delta = 0.2;
1092 }
1093
1094 if ( (epsilon >= 1.000) && (epsilon < 1.065) ) num_lin = 0;
1095 if ( (epsilon >= 1.065) && (epsilon < 1.230) ) num_lin = 1;
1096 if ( (epsilon >= 1.230) && (epsilon < 1.500) ) num_lin = 2;
1097 if ( (epsilon >= 1.500) && (epsilon < 1.950) ) num_lin = 3;
1098 if ( (epsilon >= 1.950) && (epsilon < 2.800) ) num_lin = 4;
1099 if ( (epsilon >= 2.800) && (epsilon < 4.500) ) num_lin = 5;
1100 if ( (epsilon >= 4.500) && (epsilon < 6.200) ) num_lin = 6;
1101 if ( (epsilon >= 6.200) && (epsilon < 14.00) ) num_lin = 7;
1102
1103 for (i=0;i<5;i++)
1104 for (j=0;j<4;j++)
1105 {
1106 x[i][j] = *(coeff_perez + 20*num_lin + 4*i +j);
1107 /* printf("x %d %d vaut %f\n",i,j,x[i][j]); */
1108 }
1109
1110
1111 if (num_lin)
1112 {
1113 for (i=0;i<5;i++)
1114 *(c_perez+i) = x[i][0] + x[i][1]*Z + Delta * (x[i][2] + x[i][3]*Z);
1115
1116 }
1117 else
1118 {
1119 *(c_perez+0) = x[0][0] + x[0][1]*Z + Delta * (x[0][2] + x[0][3]*Z);
1120 *(c_perez+1) = x[1][0] + x[1][1]*Z + Delta * (x[1][2] + x[1][3]*Z);
1121 *(c_perez+4) = x[4][0] + x[4][1]*Z + Delta * (x[4][2] + x[4][3]*Z);
1122 *(c_perez+2) = exp( pow(Delta*(x[2][0]+x[2][1]*Z),x[2][2])) - x[2][3];
1123 *(c_perez+3) = -exp( Delta*(x[3][0]+x[3][1]*Z) )+x[3][2]+Delta*x[3][3];
1124
1125
1126 }
1127
1128
1129 return;
1130 }
1131
1132
1133 /* degrees into radians */
1134 double radians(double degres)
1135 {
1136 return degres*M_PI/180.0;
1137 }
1138
1139 /* radian into degrees */
1140 double degres(double radians)
1141 {
1142 return radians/M_PI*180.0;
1143 }
1144
1145 /* calculation of the angles dzeta and gamma */
1146 void theta_phi_to_dzeta_gamma(double theta,double phi,double *dzeta,double *gamma, double Z)
1147 {
1148 *dzeta = theta; /* dzeta = phi */
1149 if ( (cos(Z)*cos(theta)+sin(Z)*sin(theta)*cos(phi)) > 1 && (cos(Z)*cos(theta)+sin(Z)*sin(theta)*cos(phi) < 1.1 ) )
1150 *gamma = 0;
1151 else if ( (cos(Z)*cos(theta)+sin(Z)*sin(theta)*cos(phi)) > 1.1 )
1152 {
1153 printf("error in calculation of gamma (angle between point and sun");
1154 exit(3);
1155 }
1156 else
1157 *gamma = acos(cos(Z)*cos(theta)+sin(Z)*sin(theta)*cos(phi));
1158 }
1159
1160
1161 /********************************************************************************/
1162 /* Fonction: theta_ordered */
1163 /* */
1164 /* In: char *filename */
1165 /* */
1166 /* Out: float * */
1167 /* */
1168 /* Update: 29/08/93 */
1169 /* */
1170 /* Rem: theta en degres */
1171 /* */
1172 /* But: fournit les valeurs de theta du fichier d'entree a la memoire */
1173 /* */
1174 /********************************************************************************/
1175 float *theta_ordered(char *filename)
1176 {
1177 int i;
1178 float buffer,*ptr;
1179 FILE *file_in;
1180
1181 if ( (file_in = frlibopen(filename)) == NULL )
1182 {
1183 fprintf(stderr,"Cannot open file %s in function theta_ordered\n",filename);
1184 exit(1);
1185 }
1186
1187 rewind(file_in);
1188
1189 if ( (ptr = malloc(145*sizeof(float))) == NULL )
1190 {
1191 fprintf(stderr,"Out of memory in function theta_ordered\n");
1192 exit(1);
1193 }
1194
1195 for (i=0;i<145;i++)
1196 {
1197 fscanf(file_in,"%f",&buffer);
1198 *(ptr+i) = buffer;
1199 fscanf(file_in,"%f",&buffer);
1200 }
1201
1202 fclose(file_in);
1203 return ptr;
1204 }
1205
1206
1207 /********************************************************************************/
1208 /* Fonction: phi_ordered */
1209 /* */
1210 /* In: char *filename */
1211 /* */
1212 /* Out: float * */
1213 /* */
1214 /* Update: 29/08/93 */
1215 /* */
1216 /* Rem: valeurs de Phi en DEGRES */
1217 /* */
1218 /* But: mettre les angles contenus dans le fichier d'entree dans la memoire */
1219 /* */
1220 /********************************************************************************/
1221 float *phi_ordered(char *filename)
1222 {
1223 int i;
1224 float buffer,*ptr;
1225 FILE *file_in;
1226
1227 if ( (file_in = frlibopen(filename)) == NULL )
1228 {
1229 fprintf(stderr,"Cannot open file %s in function phi_ordered\n",filename);
1230 exit(1);
1231 }
1232
1233 rewind(file_in);
1234
1235 if ( (ptr = malloc(145*sizeof(float))) == NULL )
1236 {
1237 fprintf(stderr,"Out of memory in function phi_ordered");
1238 exit(1);
1239 }
1240
1241 for (i=0;i<145;i++)
1242 {
1243 fscanf(file_in,"%f",&buffer);
1244 fscanf(file_in,"%f",&buffer);
1245 *(ptr+i) = buffer;
1246 }
1247
1248 fclose(file_in);
1249 return ptr;
1250 }
1251
1252
1253 /********************************************************************************/
1254 /* Fonction: integ_lv */
1255 /* */
1256 /* In: float *lv,*theta */
1257 /* int sun_pos */
1258 /* */
1259 /* Out: double */
1260 /* */
1261 /* Update: 29/08/93 */
1262 /* */
1263 /* Rem: */
1264 /* */
1265 /* But: calcul l'integrale de luminance relative sans la dir. du soleil */
1266 /* */
1267 /********************************************************************************/
1268 double integ_lv(float *lv,float *theta)
1269 {
1270 int i;
1271 double buffer=0.0;
1272
1273 for (i=0;i<145;i++)
1274 buffer += (*(lv+i))*cos(radians(*(theta+i)));
1275
1276 return buffer*2*M_PI/144;
1277
1278 }
1279
1280
1281
1282
1283
1284
1285 /* enter day number(double), return E0 = square(R0/R): eccentricity correction factor */
1286
1287 double get_eccentricity()
1288 {
1289 double day_angle;
1290 double E0;
1291
1292 day_angle = 2*M_PI*(daynumber - 1)/365;
1293 E0 = 1.00011+0.034221*cos(day_angle)+0.00128*sin(day_angle)+
1294 0.000719*cos(2*day_angle)+0.000077*sin(2*day_angle);
1295
1296 return (E0);
1297
1298 }
1299
1300
1301 /* enter sunzenith angle (degrees) return relative air mass (double) */
1302 double air_mass()
1303 {
1304 double m;
1305
1306 if (sunzenith>90)
1307 {
1308 fprintf(stderr, "solar zenith angle larger than 90� in fuction air_mass():\n the models used are not more valid\n");
1309 exit(1);
1310 }
1311
1312 m = 1/( cos(sunzenith*M_PI/180)+0.15*exp( log(93.885-sunzenith)*(-1.253) ) );
1313 return(m);
1314 }
1315
1316
1317 double get_angle_sun_direction(double sun_zenith, double sun_azimut, double direction_zenith, double direction_azimut)
1318
1319 {
1320
1321 double angle;
1322
1323
1324 if (sun_zenith == 0)
1325 puts("WARNING: zenith_angle = 0 in function get_angle_sun_vert_plan");
1326
1327 angle = acos( cos(sun_zenith*M_PI/180)*cos(direction_zenith*M_PI/180) + sin(sun_zenith*M_PI/180)*sin(direction_zenith*M_PI/180)*cos((sun_azimut-direction_azimut)*M_PI/180) );
1328 angle = angle*180/M_PI;
1329 return(angle);
1330 }
1331
1332
1333
1334
1335
1336
1337
1338