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

# User Rev Content
1 greg 2.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