ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/gendaylit.c
Revision: 2.5
Committed: Wed Aug 10 22:30:31 2011 UTC (12 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +2 -1 lines
Log Message:
Minor bug fix

File Contents

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