ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/genssky.c
Revision: 2.9
Committed: Fri Jul 11 18:12:25 2025 UTC (2 weeks, 6 days ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad6R0, HEAD
Changes since 2.8: +811 -574 lines
Log Message:
fix(genssky,gensdaymtx): Spectral data ordering was reversed in output HSR's (TW)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: genssky.c,v 2.8 2025/06/07 05:09:45 greg Exp $";
3 #endif
4 /* Main function for generating spectral sky */
5 /* Cloudy sky computed as weight average of clear and cie overcast sky */
6
7 #include "atmos.h"
8 #include "copyright.h"
9 #include "color.h"
10 #include "paths.h"
11 #include "resolu.h"
12 #include "rtio.h"
13 #include <ctype.h>
14 #ifdef _WIN32
15 #include <windows.h>
16 #else
17 #include <errno.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #endif
21
22 const double ARCTIC_LAT = 67.;
23 const double TROPIC_LAT = 23.;
24 const int SUMMER_START = 4;
25 const int SUMMER_END = 9;
26 const double GNORM = 0.777778;
27
28 const double D65EFF = 203.; /* standard illuminant D65 */
29
30 /* Mean normalized relative daylight spectra where CCT = 6415K for overcast; */
31 const double D6415[NSSAMP] = {0.63231, 1.06171, 1.00779, 1.36423, 1.34133,
32 1.27258, 1.26276, 1.26352, 1.22201, 1.13246,
33 1.0434, 1.05547, 0.98212, 0.94445, 0.9722,
34 0.82387, 0.87853, 0.82559, 0.75111, 0.78925};
35
36 /* European and North American zones */
37 struct
38 {
39 char zname[8]; /* time zone name (all caps) */
40 float zmer; /* standard meridian */
41 } tzone[] = {{"YST", 135}, {"YDT", 120}, {"PST", 120}, {"PDT", 105},
42 {"MST", 105}, {"MDT", 90}, {"CST", 90}, {"CDT", 75},
43 {"EST", 75}, {"EDT", 60}, {"AST", 60}, {"ADT", 45},
44 {"NST", 52.5}, {"NDT", 37.5}, {"GMT", 0}, {"BST", -15},
45 {"CET", -15}, {"CEST", -30}, {"EET", -30}, {"EEST", -45},
46 {"AST", -45}, {"ADT", -60}, {"GST", -60}, {"GDT", -75},
47 {"IST", -82.5}, {"IDT", -97.5}, {"JST", -135}, {"NDT", -150},
48 {"NZST", -180}, {"NZDT", -195}, {"", 0}};
49
50 static int
51 make_directory
52 (
53 const char *path
54 )
55 {
56 #ifdef _WIN32
57 if (CreateDirectory(path, NULL) || GetLastError() == ERROR_ALREADY_EXISTS) {
58 return 1;
59 }
60 return 0;
61
62 #else
63 if (mkdir(path, 0777) == 0 || errno == EEXIST) {
64 return 1;
65 }
66 return 0;
67
68 #endif
69 }
70
71 inline static float
72 deg2rad
73 (
74 float deg
75 )
76 {
77 return deg * (PI / 180.);
78 }
79
80 static int
81 cvthour
82 (
83 char *hs,
84 int *tsolar,
85 double *hour
86 )
87 {
88 char *cp = hs;
89 int i, j;
90
91 if ((*tsolar = *cp == '+')) {
92 cp++; /* solar time? */
93 }
94 while (isdigit(*cp)) {
95 cp++;
96 }
97 if (*cp == ':') {
98 *hour = atoi(hs) + atoi(++cp) / 60.0;
99 }else{
100 *hour = atof(hs);
101 if (*cp == '.') {
102 cp++;
103 }
104 }
105 while (isdigit(*cp)) {
106 cp++;
107 }
108 if (!*cp) {
109 return (0);
110 }
111 if (*tsolar || !isalpha(*cp)) {
112 fprintf(stderr, "%s: bad time format: %s\n", progname, hs);
113 exit(1);
114 }
115 i = 0;
116 do {
117 for (j = 0; cp[j]; j++) {
118 if (toupper(cp[j]) != tzone[i].zname[j]) {
119 break;
120 }
121 }
122 if (!cp[j] && !tzone[i].zname[j]) {
123 s_meridian = tzone[i].zmer * (PI / 180);
124 return (1);
125 }
126 } while (tzone[i++].zname[0]);
127
128 fprintf(stderr, "%s: unknown time zone: %s\n", progname, cp);
129 fprintf(stderr, "Known time zones:\n\t%s", tzone[0].zname);
130 for (i = 1; tzone[i].zname[0]; i++) {
131 fprintf(stderr, " %s", tzone[i].zname);
132 }
133 putc('\n', stderr);
134 exit(1);
135 }
136
137 static void
138 basename
139 (
140 const char *path,
141 char *output,
142 size_t outsize
143 )
144 {
145 const char *last_slash = strrchr(path, '/');
146 const char *last_backslash = strrchr(path, '\\');
147 const char *filename = path;
148 const char *last_dot;
149
150 if (last_slash && last_backslash) {
151 filename =
152 (last_slash > last_backslash) ? last_slash + 1 : last_backslash + 1;
153 } else if (last_slash) {
154 filename = last_slash + 1;
155 } else if (last_backslash) {
156 filename = last_backslash + 1;
157 }
158
159 last_dot = strrchr(filename, '.');
160 if (last_dot) {
161 size_t length = last_dot - filename;
162 if (length < outsize) {
163 strncpy(output, filename, length);
164 output[length] = '\0';
165 } else {
166 strncpy(output, filename, outsize - 1);
167 output[outsize - 1] = '\0';
168 }
169 }
170 }
171
172 static char *
173 join_paths
174 (
175 const char *path1,
176 const char *path2
177 )
178 {
179 size_t len1 = strlen(path1);
180 size_t len2 = strlen(path2);
181 int need_separator = (path1[len1 - 1] != DIRSEP);
182
183 char *result = malloc(len1 + len2 + (need_separator ? 2 : 1));
184 if (!result) {
185 return NULL;
186 }
187
188 strcpy(result, path1);
189 if (need_separator) {
190 result[len1] = DIRSEP;
191 len1++;
192 }
193 strcpy(result + len1, path2);
194
195 return result;
196 }
197
198 static inline double
199 wmean2
200 (
201 const double a,
202 const double b,
203 const double x
204 )
205 {
206 return a * (1 - x) + b * x;
207 }
208
209 static inline double
210 wmean
211 (
212 const double a,
213 const double x,
214 const double b,
215 const double y
216 )
217 {
218 return (a * x + b * y) / (a + b);
219 }
220
221 static double
222 get_overcast_zenith_brightness
223 (
224 const double sundir[3]
225 )
226 {
227 double zenithbr;
228 if (sundir[2] < 0) {
229 zenithbr = 0;
230 } else {
231 zenithbr = (8.6 * sundir[2] + .123) * 1000.0 / D65EFF;
232 }
233 return zenithbr;
234 }
235
236 /* from gensky.c */
237 static double
238 get_overcast_brightness
239 (
240 const double dz,
241 const double zenithbr
242 )
243 {
244 double groundbr = zenithbr * GNORM;
245 return wmean(
246 pow(dz + 1.01, 10),
247 zenithbr * (1 + 2 * dz) / 3,
248 pow(dz + 1.01, -10),
249 groundbr);
250 }
251
252 static void
253 write_header
254 (
255 const int argc,
256 char **argv,
257 const double cloud_cover,
258 const double grefl,
259 const int res
260 )
261 {
262 int i;
263 printf("# ");
264 for (i = 0; i < argc; i++) {
265 printf("%s ", argv[i]);
266 }
267 printf("\n");
268 printf(
269 "#Cloud cover: %g\n#Ground reflectance: %g\n#Sky map resolution: "
270 "%d\n\n",
271 cloud_cover,
272 grefl,
273 res);
274 }
275
276 static void
277 write_rad
278 (
279 const double *sun_radiance,
280 const double intensity,
281 const FVECT sundir,
282 const char *ddir,
283 const char *skyfile
284 )
285 {
286 if (sundir[2] > 0) {
287 printf("void spectrum sunrad\n0\n0\n22 380 780 ");
288 int i;
289 for (i = 0; i < NSSAMP; ++i) {
290 printf("%.3f ", sun_radiance[i]);
291 }
292 printf(
293 "\n\nsunrad light solar\n0\n0\n3 %.1f %.1f %.1f\n\n",
294 intensity,
295 intensity,
296 intensity);
297 printf(
298 "solar source sun\n0\n0\n4 %f %f %f 0.533\n\n",
299 sundir[0],
300 sundir[1],
301 sundir[2]);
302 }
303 printf(
304 "void specpict skyfunc\n5 noop %s . 'Atan2(Dy,Dx)/PI+1' "
305 "'1-Acos(Dz)/PI'\n0\n0\n\n",
306 skyfile);
307 }
308
309 static void
310 write_hsr_header
311 (
312 FILE *fp,
313 RESOLU *res
314 )
315 {
316 newheader("RADIANCE", fp);
317 fputncomp(NSSAMP, fp);
318 fputwlsplit(WLPART, fp);
319 fputformat(SPECFMT, fp);
320 fputc('\n', fp);
321 fputsresolu(res, fp);
322 }
323
324 static void
325 reverse_array_float
326 (
327 float arr[],
328 int size
329 )
330 {
331 int start = 0;
332 int end = size - 1;
333
334 while (start < end) {
335 float temp = arr[start];
336 arr[start] = arr[end];
337 arr[end] = temp;
338 start++;
339 end--;
340 }
341 }
342
343 int
344 gen_spect_sky
345 (
346 DATARRAY *tau_clear,
347 DATARRAY *scat_clear,
348 DATARRAY *scat1m_clear,
349 DATARRAY *irrad_clear,
350 const double cloud_cover,
351 const FVECT sundir,
352 const double grefl,
353 const int res,
354 const char *outname,
355 const char *ddir,
356 const double dirnorm,
357 const double difhor
358 )
359 {
360 char skyfile[PATH_MAX];
361 if (!snprintf(
362 skyfile, sizeof(skyfile), "%s%c%s_sky.hsr", ddir, DIRSEP, outname)) {
363 fprintf(stderr, "Error setting sky file name\n");
364 return 0;
365 }
366 ;
367 int xres = res;
368 int yres = xres / 2;
369 RESOLU rs = {PIXSTANDARD, xres, yres};
370 FILE *skyfp = fopen(skyfile, "w");
371 write_hsr_header(skyfp, &rs);
372
373 CNDX[3] = NSSAMP;
374
375 FVECT view_point = {0, 0, ER + 10};
376 const double radius = VLEN(view_point);
377 const double sun_ct = fdot(view_point, sundir) / radius;
378
379 double overcast_zenithbr = get_overcast_zenith_brightness(sundir);
380 double overcast_grndbr = overcast_zenithbr * GNORM;
381
382 double dif_ratio = 1;
383 if (difhor > 0) {
384 DATARRAY *indirect_irradiance_clear =
385 get_indirect_irradiance(irrad_clear, radius, sun_ct);
386 double overcast_ghi = overcast_zenithbr * 7.0 * PI / 9.0;
387 double diffuse_irradiance = 0;
388 int l;
389 for (l = 0; l < NSSAMP; ++l) {
390 diffuse_irradiance +=
391 indirect_irradiance_clear->arr.d[l] * 20; /* 20nm interval */
392 }
393 free(indirect_irradiance_clear);
394 diffuse_irradiance =
395 wmean2(diffuse_irradiance, overcast_ghi, cloud_cover);
396 if (diffuse_irradiance > 0) {
397 dif_ratio =
398 difhor / WHTEFFICACY / diffuse_irradiance / 1.15; /* fudge */
399 }
400 }
401 int i, j, k;
402 for (j = 0; j < yres; ++j) {
403 for (i = 0; i < xres; ++i) {
404 SCOLOR radiance = {0};
405 SCOLR sky_sclr = {0};
406
407 float px = i / (xres - 1.0);
408 float py = j / (yres - 1.0);
409 float lambda = ((1 - py) * PI) - (PI / 2.0);
410 float phi = (px * 2.0 * PI) - PI;
411
412 FVECT rdir = {
413 cos(lambda) * cos(phi), cos(lambda) * sin(phi), sin(lambda)
414 };
415
416 const double mu = fdot(view_point, rdir) / radius;
417 const double nu = fdot(rdir, sundir);
418
419 /* hit ground */
420 if (rdir[2] < 0) {
421 get_ground_radiance(
422 tau_clear,
423 scat_clear,
424 scat1m_clear,
425 irrad_clear,
426 view_point,
427 rdir,
428 radius,
429 mu,
430 sun_ct,
431 nu,
432 grefl,
433 sundir,
434 radiance);
435 } else {
436 get_sky_radiance(
437 scat_clear, scat1m_clear, radius, mu, sun_ct, nu, radiance);
438 }
439
440 for (k = 0; k < NSSAMP; ++k) {
441 radiance[k] *= WVLSPAN;
442 }
443
444 if (cloud_cover > 0) {
445 double skybr =
446 get_overcast_brightness(rdir[2], overcast_zenithbr);
447 if (rdir[2] < 0) {
448 for (k = 0; k < NSSAMP; ++k) {
449 radiance[k] = wmean2(
450 radiance[k],
451 overcast_grndbr * D6415[k],
452 cloud_cover);
453 }
454 } else {
455 for (k = 0; k < NSSAMP; ++k) {
456 radiance[k] =
457 wmean2(radiance[k], skybr * D6415[k], cloud_cover);
458 }
459 }
460 }
461
462 for (k = 0; k < NSSAMP; ++k) {
463 radiance[k] *= dif_ratio;
464 }
465
466 reverse_array_float(radiance, NSSAMP);
467
468 scolor2scolr(sky_sclr, radiance, NSSAMP);
469 putbinary(sky_sclr, LSCOLR, 1, skyfp);
470 }
471 }
472 fclose(skyfp);
473
474 /* Get solar radiance */
475 double sun_radiance[NSSAMP] = {0};
476 get_solar_radiance(
477 tau_clear,
478 scat_clear,
479 scat1m_clear,
480 sundir,
481 radius,
482 sun_ct,
483 sun_radiance);
484 if (cloud_cover > 0) {
485 double skybr = get_overcast_brightness(sundir[2], overcast_zenithbr);
486 int i;
487 for (i = 0; i < NSSAMP; ++i) {
488 sun_radiance[i] = wmean2(
489 sun_radiance[i], D6415[i] * skybr / WVLSPAN, cloud_cover);
490 }
491 }
492
493 /* Normalize */
494 double sum = 0.0;
495 for (i = 0; i < NSSAMP; ++i) {
496 sum += sun_radiance[i];
497 }
498 double mean = sum / NSSAMP;
499 for (i = 0; i < NSSAMP; ++i) {
500 sun_radiance[i] /= mean;
501 }
502 double intensity = mean * WVLSPAN;
503 if (dirnorm > 0) {
504 intensity = dirnorm / SOLOMG / WHTEFFICACY;
505 }
506
507 write_rad(sun_radiance, intensity, sundir, ddir, skyfile);
508 return 1;
509 }
510
511 static DpPaths
512 get_dppaths
513 (
514 const char *dir,
515 const double aod,
516 const char *mname,
517 const char *tag
518 )
519 {
520 DpPaths paths;
521
522 snprintf(
523 paths.tau,
524 PATH_MAX,
525 "%s%ctau_%s_%s_%.2f.dat",
526 dir,
527 DIRSEP,
528 tag,
529 mname,
530 aod);
531 snprintf(
532 paths.scat,
533 PATH_MAX,
534 "%s%cscat_%s_%s_%.2f.dat",
535 dir,
536 DIRSEP,
537 tag,
538 mname,
539 aod);
540 snprintf(
541 paths.scat1m,
542 PATH_MAX,
543 "%s%cscat1m_%s_%s_%.2f.dat",
544 dir,
545 DIRSEP,
546 tag,
547 mname,
548 aod);
549 snprintf(
550 paths.irrad,
551 PATH_MAX,
552 "%s%cirrad_%s_%s_%.2f.dat",
553 dir,
554 DIRSEP,
555 tag,
556 mname,
557 aod);
558
559 return paths;
560 }
561
562 static void
563 set_rayleigh_density_profile
564 (
565 Atmosphere *atmos,
566 char *tag,
567 const int is_summer,
568 const double s_latitude
569 )
570 {
571 if (fabs(s_latitude * 180.0 / PI) > ARCTIC_LAT) {
572 tag[0] = 's';
573 if (is_summer) {
574 tag[1] = 's';
575 atmos->rayleigh_density.layers[0].exp_scale = -1.0 / HR_SS;
576 atmos->beta_r0 = BR0_SS;
577 } else {
578 tag[1] = 'w';
579 atmos->rayleigh_density.layers[0].exp_scale = -1.0 / HR_SW;
580 atmos->beta_r0 = BR0_SW;
581 }
582 } else if (fabs(s_latitude * 180.0 / PI) > TROPIC_LAT) {
583 tag[0] = 'm';
584 if (is_summer) {
585 tag[1] = 's';
586 atmos->rayleigh_density.layers[0].exp_scale = -1.0 / HR_MS;
587 atmos->beta_r0 = BR0_MS;
588 } else {
589 tag[1] = 'w';
590 atmos->rayleigh_density.layers[0].exp_scale = -1.0 / HR_MW;
591 atmos->beta_r0 = BR0_MW;
592 }
593 } else {
594 tag[0] = 't';
595 tag[1] = 'r';
596 atmos->rayleigh_density.layers[0].exp_scale = -1.0 / HR_T;
597 atmos->beta_r0 = BR0_T;
598 }
599 tag[2] = '\0';
600 }
601
602 static Atmosphere
603 init_atmos
604 (
605 const double aod,
606 const double grefl
607 )
608 {
609 Atmosphere atmos = {
610 .ozone_density =
611 {.layers =
612 {
613 {.width = 25000.0,
614 .exp_term = 0.0,
615 .exp_scale = 0.0,
616 .linear_term = 1.0 / 15000.0,
617 .constant_term = -2.0 / 3.0},
618 {.width = AH,
619 .exp_term = 0.0,
620 .exp_scale = 0.0,
621 .linear_term = -1.0 / 15000.0,
622 .constant_term = 8.0 / 3.0},
623 }},
624 .rayleigh_density =
625 {.layers =
626 {
627 {.width = AH,
628 .exp_term = 1.0,
629 .exp_scale = -1.0 / HR_MS,
630 .linear_term = 0.0,
631 .constant_term = 0.0},
632 }},
633 .beta_r0 = BR0_MS,
634 .beta_scale = aod / AOD0_CA,
635 .beta_m = NULL,
636 .grefl = grefl
637 };
638 return atmos;
639 }
640
641 int
642 main
643 (
644 int argc,
645 char *argv[]
646 )
647 {
648 int month, day;
649 double hour;
650 FVECT sundir;
651 int num_threads = 1;
652 int sorder = 4;
653 int year = 0;
654 int tsolar = 0;
655 int got_meridian = 0;
656 double grefl = 0.2;
657 double ccover = 0.0;
658 int res = 64;
659 double aod = AOD0_CA;
660 char *outname = "out";
661 char *mie_path = getpath("mie_ca.dat", getrlibpath(), R_OK);
662 char mie_name[20] = "mie_ca";
663 char lstag[3];
664 char *ddir = ".";
665 int i;
666 double dirnorm = 0; /* direct normal illuminance */
667 double difhor = 0; /* diffuse horizontal illuminance */
668
669 fixargv0(argv[0]);
670 if (argc == 2 && !strcmp(argv[1], "-defaults")) {
671 printf("-i %d\t\t\t\t#scattering order\n", sorder);
672 printf("-g %f\t\t\t#ground reflectance\n", grefl);
673 printf("-c %f\t\t\t#cloud cover\n", ccover);
674 printf("-r %d\t\t\t\t#image resolution\n", res);
675 printf("-d %f\t\t\t#broadband aerosol optical depth\n", AOD0_CA);
676 printf("-f %s\t\t\t\t#output name (-f)\n", outname);
677 printf("-p %s\t\t\t\t#atmos data directory\n", ddir);
678 exit(0);
679 }
680
681 if (argc < 4) {
682 fprintf(
683 stderr,
684 "Usage: %s month day hour -y year -a lat -o lon -m tz -d aod "
685 "-r "
686 "res -n nproc -c ccover -l mie -L dirnorm_illum difhor_illum "
687 "-g grefl -f outpath\n",
688 argv[0]);
689 return 0;
690 }
691
692 month = atoi(argv[1]);
693 if (month < 1 || month > 12) {
694 fprintf(stderr, "bad month");
695 exit(1);
696 }
697 day = atoi(argv[2]);
698 if (day < 1 || day > 31) {
699 fprintf(stderr, "bad month");
700 exit(1);
701 }
702 got_meridian = cvthour(argv[3], &tsolar, &hour);
703
704 if (!compute_sundir(year, month, day, hour, tsolar, sundir)) {
705 fprintf(stderr, "Cannot compute solar angle\n");
706 exit(1);
707 }
708
709 for (i = 4; i < argc; i++) {
710 if (argv[i][0] == '-') {
711 switch (argv[i][1]) {
712 case 'a':
713 s_latitude = atof(argv[++i]) * (PI / 180.0);
714 break;
715 case 'c':
716 ccover = atof(argv[++i]);
717 break;
718 case 'd':
719 aod = atof(argv[++i]);
720 break;
721 case 'f':
722 outname = argv[++i];
723 break;
724 case 'g':
725 grefl = atof(argv[++i]);
726 break;
727 case 'i':
728 sorder = atoi(argv[++i]);
729 break;
730 case 'l':
731 mie_path = argv[++i];
732 basename(mie_path, mie_name, sizeof(mie_name));
733 break;
734 case 'm':
735 if (got_meridian) {
736 ++i;
737 break;
738 }
739 s_meridian = atof(argv[++i]) * (PI / 180.0);
740 break;
741 case 'n':
742 num_threads = atoi(argv[++i]);
743 break;
744 case 'o':
745 s_longitude = atof(argv[++i]) * (PI / 180.0);
746 break;
747 case 'L':
748 dirnorm = atof(argv[++i]);
749 difhor = atof(argv[++i]);
750 break;
751 case 'p':
752 ddir = argv[++i];
753 break;
754 case 'r':
755 res = atoi(argv[++i]);
756 break;
757 case 'y':
758 year = atoi(argv[++i]);
759 break;
760 default:
761 fprintf(stderr, "Unknown option %s\n", argv[i]);
762 exit(1);
763 }
764 }
765 }
766 if (year && (year < 1950) | (year > 2050)) {
767 fprintf(
768 stderr,
769 "%s: warning - year should be in range 1950-2050\n",
770 progname);
771 }
772 if (month && !tsolar && fabs(s_meridian - s_longitude) > 45 * PI / 180) {
773 fprintf(
774 stderr,
775 "%s: warning - %.1f hours btwn. standard meridian and "
776 "longitude\n",
777 progname,
778 (s_longitude - s_meridian) * 12 / PI);
779 }
780
781 Atmosphere clear_atmos = init_atmos(aod, grefl);
782
783 int is_summer = (month >= SUMMER_START && month <= SUMMER_END);
784 if (s_latitude < 0) {
785 is_summer = !is_summer;
786 }
787 set_rayleigh_density_profile(&clear_atmos, lstag, is_summer, s_latitude);
788
789 /* Load mie density data */
790 DATARRAY *mie_dp = getdata(mie_path);
791 if (mie_dp == NULL) {
792 fprintf(stderr, "Error reading mie data\n");
793 return 0;
794 }
795 clear_atmos.beta_m = mie_dp;
796
797 char gsdir[PATH_MAX];
798 size_t siz = strlen(ddir);
799 if (ISDIRSEP(ddir[siz - 1])) {
800 ddir[siz - 1] = '\0';
801 }
802 snprintf(gsdir, PATH_MAX, "%s%catmos_data", ddir, DIRSEP);
803 if (!make_directory(gsdir)) {
804 fprintf(stderr, "Failed creating atmos_data directory");
805 exit(1);
806 }
807 DpPaths clear_paths = get_dppaths(gsdir, aod, mie_name, lstag);
808
809 if (getpath(clear_paths.tau, ".", R_OK) == NULL ||
810 getpath(clear_paths.scat, ".", R_OK) == NULL ||
811 getpath(clear_paths.scat1m, ".", R_OK) == NULL ||
812 getpath(clear_paths.irrad, ".", R_OK) == NULL) {
813 printf("# Pre-computing...\n");
814 if (!precompute(sorder, clear_paths, &clear_atmos, num_threads)) {
815 fprintf(stderr, "Pre-compute failed\n");
816 return 0;
817 }
818 }
819
820 DATARRAY *tau_clear_dp = getdata(clear_paths.tau);
821 DATARRAY *irrad_clear_dp = getdata(clear_paths.irrad);
822 DATARRAY *scat_clear_dp = getdata(clear_paths.scat);
823 DATARRAY *scat1m_clear_dp = getdata(clear_paths.scat1m);
824
825 write_header(argc, argv, ccover, grefl, res);
826
827 if (!gen_spect_sky(
828 tau_clear_dp,
829 scat_clear_dp,
830 scat1m_clear_dp,
831 irrad_clear_dp,
832 ccover,
833 sundir,
834 grefl,
835 res,
836 outname,
837 ddir,
838 dirnorm,
839 difhor)) {
840 fprintf(stderr, "gen_spect_sky failed\n");
841 exit(1);
842 }
843
844 freedata(mie_dp);
845 freedata(tau_clear_dp);
846 freedata(scat_clear_dp);
847 freedata(irrad_clear_dp);
848 freedata(scat1m_clear_dp);
849
850 return 1;
851 }