JURASSIC
formod.c
Go to the documentation of this file.
1/*
2 This file is part of JURASSIC.
3
4 JURASSIC is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 JURASSIC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with JURASSIC. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright (C) 2003-2026 Forschungszentrum Juelich GmbH
18*/
19
25#include <limits.h>
26#include "jurassic.h"
27#ifdef UNIFIED
28#include "jurassic_unified_library.h"
29#endif
30
31/* ------------------------------------------------------------
32 Functions...
33 ------------------------------------------------------------ */
34
36void call_formod(
37 ctl_t * ctl,
38 const tbl_t * tbl,
39 const char *wrkdir,
40 const char *obsfile,
41 const char *atmfile,
42 const char *radfile,
43 char task_mode,
44 const char *obsref,
45 int formod_scalar,
46 int batch_size);
47
50 const char * task);
51
54 int argc,
55 char *argv[]);
56
59 int argc,
60 char *argv[]);
61
65 const ctl_t * ctl,
66 const tbl_t * tbl,
67 atm_t * atm,
68 obs_t * obs,
69 los_t * los_scratch,
70 obs_t * obs_scratch,
71 int formod_scalar);
72
75 const ctl_t * ctl,
76 const atm_t * atm,
77 const obs_t * obs,
78 int batch_size,
79 atm_t * atm_batch,
80 obs_t * obs_batch);
81
84 const ctl_t * ctl,
85 const obs_t * obs_test,
86 const obs_t * obs_ref,
87 double *mre,
88 double *sdre,
89 double *minre,
90 double *maxre);
91
94 const ctl_t * ctl,
95 const obs_t * obs_test,
96 const obs_t * obs_ref,
97 double *meanae,
98 double *sdae,
99 double *minae,
100 double *maxae);
101
104 ctl_t * ctl,
105 const tbl_t * tbl,
106 const char *wrkdir,
107 const char *radfile,
108 const atm_t * atm,
109 obs_t * obs,
110 atm_t * atm_scratch,
111 obs_t * obs_single,
112 los_t * los_scratch,
113 obs_t * obs_scratch,
114 int formod_scalar);
115
118 const ctl_t * ctl,
119 const char *wrkdir,
120 const char *obsref,
121 const obs_t * obs,
122 obs_t * obs_ref);
123
126 ctl_t * ctl,
127 const tbl_t * tbl,
128 const char *wrkdir,
129 const char *radfile,
130 const atm_t * atm,
131 obs_t * obs,
132 atm_t * atm_scratch,
133 los_t * los_scratch,
134 obs_t * obs_scratch,
135 int formod_scalar);
136
139 const ctl_t * ctl,
140 const tbl_t * tbl,
141 const atm_t * atm,
142 obs_t * obs,
143 atm_t * atm_scratch,
144 los_t * los_scratch,
145 obs_t * obs_scratch,
146 int formod_scalar,
147 int batch_size);
148
151 ctl_t * ctl,
152 const tbl_t * tbl,
153 atm_t * atm,
154 obs_t * obs,
155 obs_t * obs_ref,
156 los_t * los_scratch,
157 obs_t * obs_scratch,
158 int formod_scalar);
159
161void usage(
162 void);
163
164/* ------------------------------------------------------------
165 Main...
166 ------------------------------------------------------------ */
167
169 int argc,
170 char *argv[]) {
171
172 static ctl_t ctl;
173
174 /* Print usage information... */
175 USAGE;
176
177 /* Check arguments... */
178 if (argc < 5)
179 ERRMSG("Missing or invalid command-line arguments.\n\n"
180 "Usage: formod <ctl> <obs> <atm> <rad> [KEY VALUE ...]\n\n"
181 "Use -h for full help.");
182
183 /* Read control parameters... */
184 SELECT_TIMER("READ_CTL", "INPUT");
185 read_ctl(argc, argv, &ctl);
186
187#ifdef UNIFIED
188
189 static atm_t atm;
190 static obs_t obs;
191
192 /* Read observation geometry... */
193 SELECT_TIMER("READ_OBS", "INPUT");
194 read_obs(NULL, argv[2], &ctl, &obs, 0);
195
196 /* Read atmospheric data... */
197 SELECT_TIMER("READ_ATM", "INPUT");
198 read_atm(NULL, argv[3], &ctl, &atm, 0);
199
200 /* Call forward model... */
201 SELECT_TIMER("FORMOD_UNIFIED", "FORWARD");
202 jur_unified_init(argc, argv);
203 jur_unified_formod_multiple_packages(&atm, &obs, 1, NULL);
204
205 /* Save radiance data... */
206 SELECT_TIMER("WRITE_OBS", "OUTPUT");
207 write_obs(NULL, argv[4], &ctl, &obs, 0);
208
209#else
210
211 char dirlist[LEN], obsref[LEN], task[LEN];
212 const int formod_scalar = parse_formod_scalar(argc, argv);
213 const int batch_size = parse_formod_batch_size(argc, argv);
214
215 /* Initialize look-up tables... */
216 SELECT_TIMER("READ_TBL", "INPUT");
217 tbl_t *tbl = read_tbl(&ctl);
218
219 /* Get task... */
220 SELECT_TIMER("READ_TASK", "INPUT");
221 scan_ctl(argc, argv, "TASK", -1, "forward", task);
222 const char task_mode = parse_task_mode(task);
223
224 /* Get dirlist... */
225 SELECT_TIMER("READ_DIRLIST", "INPUT");
226 scan_ctl(argc, argv, "DIRLIST", -1, "-", dirlist);
227
228 /* Get reference data... */
229 SELECT_TIMER("READ_OBSREF", "INPUT");
230 scan_ctl(argc, argv, "OBSREF", -1, "-", obsref);
231
232 /* Single forward calculation... */
233 if (dirlist[0] == '-')
234 call_formod(&ctl, tbl, NULL, argv[2], argv[3], argv[4], task_mode, obsref,
235 formod_scalar, batch_size);
236
237 /* Work on directory list... */
238 else {
239
240 /* Open directory list... */
241 FILE *in;
242 if (!(in = fopen(dirlist, "r")))
243 ERRMSG("Cannot open directory list!");
244
245 /* Loop over directories... */
246 char wrkdir[LEN];
247 while (fscanf(in, "%4999s", wrkdir) != EOF) {
248
249 /* Write info... */
250 LOG(1, "\nWorking directory: %s", wrkdir);
251
252 /* Call forward model... */
253 call_formod(&ctl, tbl, wrkdir, argv[2], argv[3], argv[4], task_mode,
254 obsref, formod_scalar, batch_size);
255 }
256
257 /* Close dirlist... */
258 fclose(in);
259 }
260
261#endif
262
263 /* Free... */
264 SELECT_TIMER("FINALIZE", "OVERHEAD");
265 tbl_free(&ctl, tbl);
267
268 return EXIT_SUCCESS;
269}
270
271/*****************************************************************************/
272
273void usage(
274 void) {
275
276 printf("\nJURASSIC forward model.\n\n");
277 printf
278 ("Compute simulated radiances or transmittances for the configured\n");
279 printf
280 ("channels from observation geometry, atmospheric state, and control\n");
281 printf("settings.\n\n");
282 printf("Usage:\n");
283 printf(" formod <ctl> <obs> <atm> <rad> [KEY VALUE ...]\n\n");
284 printf("Arguments:\n");
285 printf(" <ctl> Control file.\n");
286 printf(" <obs> Observation geometry input file.\n");
287 printf(" <atm> Atmospheric state input file.\n");
288 printf(" <rad> Output file for simulated radiances or transmittances.\n");
289 printf(" [KEY VALUE] Optional control parameters.\n\n");
290 printf("Tool-specific control parameters:\n");
291 printf(" TASK <name> Select the operation mode.\n");
292 printf
293 (" forward or omitted: regular forward-model simulation.\n");
294 printf
295 (" contrib: write separate outputs for individual emitter\n");
296 printf(" extinction contributions.\n");
297 printf
298 (" profiles: process observation data profile by profile,\n");
299 printf
300 (" matching each profile to the corresponding\n");
301 printf(" atmospheric profile by time.\n");
302 printf
303 (" stepsize: analyze sensitivity to ray-tracing step\n");
304 printf(" sizes.\n");
305 printf
306 (" time: run the built-in runtime benchmark using\n");
307 printf
308 (" perturbed versions of the input atmosphere.\n");
309 printf
310 (" DIRLIST <file> Read working directories from <file> and run one case\n");
311 printf
312 (" per directory using the same <obs>, <atm>, and <rad>\n");
313 printf(" filenames relative to each listed directory.\n");
314 printf
315 (" OBSREF <file> Read reference observations from <file> and print\n");
316 printf
317 (" relative and signed absolute-error diagnostics against\n");
318 printf
319 (" the simulated output.\n");
320 printf
321 (" EXECUTION <mode> Select execution backend: batch (default) or scalar.\n");
322 printf
323 (" BATCH_SIZE <n> Batch size for TASK=time with EXECUTION=batch.\n");
324 printf("\n");
325 printf("Common control parameters:\n");
326 printf
327 (" TBLBASE, TBLFMT Lookup-table base name and format.\n");
328 printf
329 (" ATMFMT, OBSFMT Atmospheric and observation file formats.\n");
330 printf(" NG, EMITTER[i] Active emitters.\n");
331 printf(" ND, NU[i], NW, WINDOW[i] Spectral channels and windows.\n");
332 printf
333 (" NCL, CLNU[i], NSF, SFNU[i] Cloud and surface spectral grids.\n");
334 printf
335 (" WRITE_BBT, FORMOD Output units and forward-model selection.\n");
336 printf(" CTM_*, REFRAC Continua and refractivity.\n");
337 printf
338 (" RAYDS, RAYDZ, FOV Ray tracing and field of view.\n\n");
339 printf("Further information:\n");
340 printf(" Manual: https://slcs-jsc.github.io/jurassic/\n");
341}
342
343/*****************************************************************************/
344
346 const char *task) {
347
348 if (task[0] == '-' || strcmp(task, "forward") == 0)
349 return 'f';
350 if (task[0] == 'c' || strcmp(task, "contrib") == 0
351 || strcmp(task, "contributions") == 0)
352 return 'c';
353 if (task[0] == 'p' || strcmp(task, "profile") == 0
354 || strcmp(task, "profiles") == 0)
355 return 'p';
356 if (task[0] == 's' || strcmp(task, "stepsize") == 0)
357 return 's';
358 if (task[0] == 't' || strcmp(task, "time") == 0
359 || strcmp(task, "benchmark") == 0)
360 return 't';
361
362 ERRMSG("Unknown TASK '%s'!", task);
363 return 'f';
364}
365
366/*****************************************************************************/
367
369 int argc,
370 char *argv[]) {
371
372 char execution[LEN];
373 scan_ctl(argc, argv, "EXECUTION", -1, "batch", execution);
374
375 if (strcmp(execution, "batch") == 0)
376 return 0;
377 if (strcmp(execution, "scalar") == 0)
378 return 1;
379
380 ERRMSG("Unknown EXECUTION '%s'!", execution);
381 return 0;
382}
383
384/*****************************************************************************/
385
387 int argc,
388 char *argv[]) {
389
390 const int batch_size =
391 (int) scan_ctl(argc, argv, "BATCH_SIZE", -1, "1", NULL);
392
393 if (batch_size < 1)
394 ERRMSG("BATCH_SIZE must be positive!");
395
396 return batch_size;
397}
398
399/*****************************************************************************/
400
402 const ctl_t *ctl,
403 const tbl_t *tbl,
404 atm_t *atm,
405 obs_t *obs,
406 los_t *los_scratch,
407 obs_t *obs_scratch,
408 int formod_scalar) {
409
410 if (formod_scalar) {
411 const int status = formod(ctl, tbl, atm, obs, los_scratch, obs_scratch);
412 if (status != FORMOD_STATUS_OK)
413 ERRMSG("Forward model failed with status code %d!", status);
414 return;
415 }
416
417 int status[1];
418 formod_batch(ctl, tbl, atm, obs, 1, status, los_scratch, obs_scratch);
419 if (status[0] != FORMOD_STATUS_OK)
420 ERRMSG("Forward model failed with status code %d!", status[0]);
421}
422
423/*****************************************************************************/
424
426 ctl_t *ctl,
427 const tbl_t *tbl,
428 const char *wrkdir,
429 const char *radfile,
430 const atm_t *atm,
431 obs_t *obs,
432 atm_t *atm_scratch,
433 obs_t *obs_single,
434 los_t *los_scratch,
435 obs_t *obs_scratch,
436 int formod_scalar) {
437
438 SELECT_TIMER("FORMOD_PROFILE_LOOP", "FORWARD");
439
440 for (int ir = 0; ir < obs->nr; ir++) {
441
442 atm_scratch->np = 0;
443 for (int ip = 0; ip < atm->np; ip++)
444 if (atm->time[ip] == obs->time[ir]) {
445 atm_scratch->time[atm_scratch->np] = atm->time[ip];
446 atm_scratch->z[atm_scratch->np] = atm->z[ip];
447 atm_scratch->lon[atm_scratch->np] = atm->lon[ip];
448 atm_scratch->lat[atm_scratch->np] = atm->lat[ip];
449 atm_scratch->p[atm_scratch->np] = atm->p[ip];
450 atm_scratch->t[atm_scratch->np] = atm->t[ip];
451 for (int ig = 0; ig < ctl->ng; ig++)
452 atm_scratch->q[ig][atm_scratch->np] = atm->q[ig][ip];
453 for (int iw = 0; iw < ctl->nw; iw++)
454 atm_scratch->k[iw][atm_scratch->np] = atm->k[iw][ip];
455 atm_scratch->np++;
456 }
457
458 obs_single->nr = 1;
459 obs_single->time[0] = obs->time[ir];
460 obs_single->vpz[0] = obs->vpz[ir];
461 obs_single->vplon[0] = obs->vplon[ir];
462 obs_single->vplat[0] = obs->vplat[ir];
463 obs_single->obsz[0] = obs->obsz[ir];
464 obs_single->obslon[0] = obs->obslon[ir];
465 obs_single->obslat[0] = obs->obslat[ir];
466
467 if (atm_scratch->np > 0) {
468 exec_formod_single(ctl, tbl, atm_scratch, obs_single, los_scratch,
469 obs_scratch, formod_scalar);
470
471 for (int id = 0; id < ctl->nd; id++) {
472 obs->rad[id][ir] = obs_single->rad[id][0];
473 obs->tau[id][ir] = obs_single->tau[id][0];
474 }
475 }
476 }
477
478 SELECT_TIMER("WRITE_OBS", "OUTPUT");
479 write_obs(wrkdir, radfile, ctl, obs, 0);
480}
481
482/*****************************************************************************/
483
485 const ctl_t *ctl,
486 const char *wrkdir,
487 const char *obsref,
488 const obs_t *obs,
489 obs_t *obs_ref) {
490
491 SELECT_TIMER("EVAL", "OUTPUT");
492
493 read_obs(wrkdir, obsref, ctl, obs_ref, 0);
494
495 double mre[ND], sdre[ND], minre[ND], maxre[ND];
496 double meanae[ND], sdae[ND], minae[ND], maxae[ND];
497 compute_rel_errors(ctl, obs, obs_ref, mre, sdre, minre, maxre);
498 compute_abs_errors(ctl, obs, obs_ref, meanae, sdae, minae, maxae);
499
500 for (int id = 0; id < ctl->nd; id++) {
501 printf
502 ("EVAL: nu= %.4f cm^-1 | MeanRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
503 ctl->nu[id], mre[id], sdre[id], minre[id], maxre[id]);
504 printf
505 ("EVAL: nu= %.4f cm^-1 | MeanAE= %g | SDAE= %g | MinAE= %g | MaxAE= %g\n",
506 ctl->nu[id], meanae[id], sdae[id], minae[id], maxae[id]);
507 }
508}
509
510/*****************************************************************************/
511
513 ctl_t *ctl,
514 const tbl_t *tbl,
515 const char *wrkdir,
516 const char *radfile,
517 const atm_t *atm,
518 obs_t *obs,
519 atm_t *atm_scratch,
520 los_t *los_scratch,
521 obs_t *obs_scratch,
522 int formod_scalar) {
523
524 char filename[LEN];
525
526 SELECT_TIMER("CONTRIBUTIONS", "FORWARD");
527
528 ctl->ctm_co2 = 0;
529 ctl->ctm_h2o = 0;
530 ctl->ctm_n2 = 0;
531 ctl->ctm_o2 = 0;
532
533 for (int ig = 0; ig < ctl->ng; ig++) {
534 copy_atm(ctl, atm_scratch, atm, 0);
535
536 for (int iw = 0; iw < ctl->nw; iw++)
537 for (int ip = 0; ip < atm_scratch->np; ip++)
538 atm_scratch->k[iw][ip] = 0;
539
540 for (int ig2 = 0; ig2 < ctl->ng; ig2++)
541 if (ig2 != ig)
542 for (int ip = 0; ip < atm_scratch->np; ip++)
543 atm_scratch->q[ig2][ip] = 0;
544
545 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch,
546 obs_scratch, formod_scalar);
547
548 sprintf(filename, "%s.%s", radfile, ctl->emitter[ig]);
549 write_obs(wrkdir, filename, ctl, obs, 0);
550 }
551
552 copy_atm(ctl, atm_scratch, atm, 0);
553
554 for (int ig = 0; ig < ctl->ng; ig++)
555 for (int ip = 0; ip < atm_scratch->np; ip++)
556 atm_scratch->q[ig][ip] = 0;
557
558 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch, obs_scratch,
559 formod_scalar);
560
561 sprintf(filename, "%s.EXTINCT", radfile);
562 write_obs(wrkdir, filename, ctl, obs, 0);
563}
564
565/*****************************************************************************/
566
568 const ctl_t *ctl,
569 const atm_t *atm,
570 const obs_t *obs,
571 int batch_size,
572 atm_t *atm_batch,
573 obs_t *obs_batch) {
574
575 double *dtemp, *dpress, *dq;
576 ALLOC(dtemp, double,
577 batch_size);
578 ALLOC(dpress, double,
579 batch_size);
580 ALLOC(dq, double,
581 batch_size * NG);
582
583 /* Draw perturbations (the first case stays unperturbed)... */
584 gsl_rng_env_setup();
585 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
586 gsl_rng_set(rng, 0UL);
587 for (int ib = 0; ib < batch_size; ib++) {
588 dtemp[ib] = 0;
589 dpress[ib] = 1;
590 for (int ig = 0; ig < ctl->ng; ig++)
591 dq[ib * NG + ig] = 1;
592 if (ib == 0)
593 continue;
594 dtemp[ib] = 40.0 * (gsl_rng_uniform(rng) - 0.5);
595 dpress[ib] = 1.0 - 0.1 * gsl_rng_uniform(rng);
596 for (int ig = 0; ig < ctl->ng; ig++)
597 dq[ib * NG + ig] = 0.8 + 0.4 * gsl_rng_uniform(rng);
598 }
599 gsl_rng_free(rng);
600
601 /* Apply perturbations... */
602#pragma omp parallel for schedule(static)
603 for (int ib = 0; ib < batch_size; ib++) {
604 atm_batch[ib] = *atm;
605 obs_batch[ib] = *obs;
606 for (int ip = 0; ip < atm_batch[ib].np; ip++) {
607 atm_batch[ib].t[ip] += dtemp[ib];
608 atm_batch[ib].p[ip] *= dpress[ib];
609 for (int ig = 0; ig < ctl->ng; ig++)
610 atm_batch[ib].q[ig][ip] *= dq[ib * NG + ig];
611 }
612 }
613
614 /* Free... */
615 free(dtemp);
616 free(dpress);
617 free(dq);
618}
619
620/*****************************************************************************/
621
623 const ctl_t *ctl,
624 const tbl_t *tbl,
625 const atm_t *atm,
626 obs_t *obs,
627 atm_t *atm_scratch,
628 los_t *los_scratch,
629 obs_t *obs_scratch,
630 int formod_scalar,
631 int batch_size) {
632
633 double t_min = 0, t_max = 0, t_mean = 0, t_sd = 0;
634 int n = 0;
635
636 gsl_rng_env_setup();
637 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
638
639 if (formod_scalar && batch_size > 1)
640 ERRMSG("BATCH_SIZE > 1 cannot be combined with EXECUTION scalar!");
641
642 /* Set up the batch and run it once untimed (warm-up)... */
643 atm_t *atm_batch = NULL;
644 obs_t *obs_batch = NULL;
645 int *status = NULL;
646 los_t *los_batch = NULL;
647 obs_t *obs_scratch_batch = NULL;
648 if (batch_size > 1) {
649 ALLOC(atm_batch, atm_t, batch_size);
650 ALLOC(obs_batch, obs_t, batch_size);
651 ALLOC(los_batch, los_t, batch_size);
652 ALLOC(obs_scratch_batch, obs_t, batch_size);
653 ALLOC(status, int,
654 batch_size);
655
656 SELECT_TIMER("BENCHMARK_SETUP", "OVERHEAD");
657 exec_formod_batch_setup(ctl, atm, obs, batch_size, atm_batch, obs_batch);
658 formod_batch(ctl, tbl, atm_batch, obs_batch, batch_size, status,
659 los_batch, obs_scratch_batch);
660 }
661
662 /* Stop after JURASSIC_MAX_ITER samples or JURASSIC_TIME_BUDGET seconds... */
663 const char *env_max_iter = getenv("JURASSIC_MAX_ITER");
664 const int max_iter = env_max_iter ? atoi(env_max_iter) : INT_MAX;
665 const char *env_budget = getenv("JURASSIC_TIME_BUDGET");
666 const double t_budget = env_budget ? atof(env_budget) : 10.0;
667
668 do {
669 SELECT_TIMER("BENCHMARK_SAMPLE", "ANALYSIS");
670 double dt;
671
672 if (batch_size > 1) {
673 const double t0 = omp_get_wtime();
674 formod_batch(ctl, tbl, atm_batch, obs_batch, batch_size, status,
675 los_batch, obs_scratch_batch);
676 dt = omp_get_wtime() - t0;
677 for (int ib = 0; ib < batch_size; ib++)
678 if (status[ib] != FORMOD_STATUS_OK)
679 ERRMSG("Batch benchmark failed with status %d at element %d!",
680 status[ib], ib);
681 } else {
682 copy_atm(ctl, atm_scratch, atm, 0);
683 const double dtemp = 40. * (gsl_rng_uniform(rng) - 0.5);
684 const double dpress = 1. - 0.1 * gsl_rng_uniform(rng);
685 double dq[NG];
686 for (int ig = 0; ig < ctl->ng; ig++)
687 dq[ig] = 0.8 + 0.4 * gsl_rng_uniform(rng);
688 for (int ip = 0; ip < atm_scratch->np; ip++) {
689 atm_scratch->t[ip] += dtemp;
690 atm_scratch->p[ip] *= dpress;
691 for (int ig = 0; ig < ctl->ng; ig++)
692 atm_scratch->q[ig][ip] *= dq[ig];
693 }
694
695 const double t0 = omp_get_wtime();
696 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch,
697 obs_scratch, formod_scalar);
698 dt = omp_get_wtime() - t0;
699 }
700
701 t_mean += dt;
702 t_sd += POW2(dt);
703 if (n == 0 || dt < t_min)
704 t_min = dt;
705 if (n == 0 || dt > t_max)
706 t_max = dt;
707 n++;
708
709 } while (t_mean < t_budget && n < max_iter);
710
711 /* Free... */
712 if (batch_size > 1) {
713 free(status);
714 free(obs_scratch_batch);
715 free(los_batch);
716 free(obs_batch);
717 free(atm_batch);
718 }
719
720 /* Write results... */
721 t_mean /= (double) n;
722 t_sd = sqrt(t_sd / (double) n - POW2(t_mean));
723 printf("RUNTIME: execution= %s | threads= %d | batch_size= %d | mean= %g s"
724 " | stddev= %g s | min= %g s | max= %g s | per_model= %g s"
725 " | throughput= %g models/s | samples= %d\n",
726 formod_scalar ? "scalar" : "batch", omp_get_max_threads(),
727 batch_size, t_mean, t_sd, t_min, t_max,
728 t_mean / batch_size, batch_size / t_mean, n);
729
730 gsl_rng_free(rng);
731}
732
733/*****************************************************************************/
734
736 ctl_t *ctl,
737 const tbl_t *tbl,
738 atm_t *atm,
739 obs_t *obs,
740 obs_t *obs_ref,
741 los_t *los_scratch,
742 obs_t *obs_scratch,
743 int formod_scalar) {
744
745 SELECT_TIMER("STEP_ANALYSIS", "ANALYSIS");
746
747 ctl->rayds = 0.1;
748 ctl->raydz = 0.01;
749 exec_formod_single(ctl, tbl, atm, obs, los_scratch, obs_scratch,
750 formod_scalar);
751 copy_obs(ctl, obs_ref, obs, 0);
752
753 for (double dz = 0.01; dz <= 2; dz *= 1.1)
754 for (double ds = 0.1; ds <= 50; ds *= 1.1) {
755 ctl->rayds = ds;
756 ctl->raydz = dz;
757
758 double t0 = omp_get_wtime();
759 exec_formod_single(ctl, tbl, atm, obs, los_scratch,
760 obs_scratch, formod_scalar);
761 double dt = omp_get_wtime() - t0;
762
763 double mre[ND], sdre[ND], minre[ND], maxre[ND];
764 compute_rel_errors(ctl, obs, obs_ref, mre, sdre, minre, maxre);
765
766 for (int id = 0; id < ctl->nd; id++)
767 printf
768 ("STEPSIZE: ds= %.4f km | dz= %g km | t= %g s | nu= %.4f cm^-1"
769 " | MeanRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
770 ds, dz, dt, ctl->nu[id], mre[id], sdre[id], minre[id],
771 maxre[id]);
772 }
773}
774
775/*****************************************************************************/
776
778 ctl_t *ctl,
779 const tbl_t *tbl,
780 const char *wrkdir,
781 const char *obsfile,
782 const char *atmfile,
783 const char *radfile,
784 char task_mode,
785 const char *obsref,
786 int formod_scalar,
787 int batch_size) {
788
789 static atm_t atm, atm2;
790 static obs_t obs, obs2, obs_ref, obs_scratch;
791 static los_t los_scratch;
792
793 /* Read atmospheric data... */
794 SELECT_TIMER("READ_ATM", "INPUT");
795 read_atm(wrkdir, atmfile, ctl, &atm, 0);
796
797 /* Read observation geometry... */
798 SELECT_TIMER("READ_OBS", "INPUT");
799 read_obs(wrkdir, obsfile, ctl, &obs, 0);
800
801 /* Compute multiple profiles... */
802 if (task_mode == 'p') {
803 exec_formod_profiles(ctl, tbl, wrkdir, radfile, &atm, &obs, &atm2, &obs2,
804 &los_scratch, &obs_scratch, formod_scalar);
805 }
806
807 /* Compute single profile... */
808 else {
809
810 if (task_mode != 't' && batch_size > 1)
811 ERRMSG("BATCH_SIZE > 1 is only supported for TASK=time!");
812
813 if (task_mode == 't') {
814 SELECT_TIMER("FORMOD_REFERENCE", "FORWARD");
815 }
816 else {
817 SELECT_TIMER("FORMOD", "FORWARD");
818 }
819 exec_formod_single(ctl, tbl, &atm, &obs, &los_scratch, &obs_scratch,
820 formod_scalar);
821 SELECT_TIMER("WRITE_OBS", "OUTPUT");
822 write_obs(wrkdir, radfile, ctl, &obs, 0);
823
824 if (obsref[0] != '-') {
825 eval_formod_results(ctl, wrkdir, obsref, &obs, &obs_ref);
826 }
827
828 if (task_mode == 'c') {
829 exec_formod_contributions(ctl, tbl, wrkdir, radfile, &atm, &obs, &atm2,
830 &los_scratch, &obs_scratch, formod_scalar);
831 }
832
833 if (task_mode == 't') {
834 exec_formod_benchmark(ctl, tbl, &atm, &obs, &atm2, &los_scratch,
835 &obs_scratch, formod_scalar, batch_size);
836 }
837
838 if (task_mode == 's') {
839 exec_formod_stepsize(ctl, tbl, &atm, &obs, &obs_ref, &los_scratch,
840 &obs_scratch, formod_scalar);
841 }
842 }
843}
844
845/*****************************************************************************/
846
848 const ctl_t *ctl,
849 const obs_t *obs_test,
850 const obs_t *obs_ref,
851 double *mre,
852 double *sdre,
853 double *minre,
854 double *maxre) {
855
856 /* Loop over channels... */
857 for (int id = 0; id < ctl->nd; id++) {
858
859 double sum = 0, sum2 = 0;
860 minre[id] = +1e9;
861 maxre[id] = -1e9;
862 int n = 0;
863
864 /* Loop over ray paths... */
865 for (int ir = 0; ir < obs_test->nr; ir++) {
866
867 /* Skip invalid pairs and zero references... */
868 if (!isfinite(obs_test->rad[id][ir])
869 || !isfinite(obs_ref->rad[id][ir])
870 || obs_ref->rad[id][ir] == 0)
871 continue;
872
873 /* Calculate relative error... */
874 double err = 100.0 * (obs_test->rad[id][ir] - obs_ref->rad[id][ir])
875 / obs_ref->rad[id][ir];
876
877 /* Get statistics... */
878 sum += err;
879 sum2 += err * err;
880 if (err > maxre[id])
881 maxre[id] = err;
882 if (err < minre[id])
883 minre[id] = err;
884 n++;
885 }
886
887 /* Get mean and standard deviation... */
888 if (n > 0) {
889 mre[id] = sum / n;
890 sdre[id] = sqrt(fmax(0, sum2 / n - mre[id] * mre[id]));
891 } else
892 mre[id] = sdre[id] = minre[id] = maxre[id] = NAN;
893 }
894}
895
896/*****************************************************************************/
897
899 const ctl_t *ctl,
900 const obs_t *obs_test,
901 const obs_t *obs_ref,
902 double *meanae,
903 double *sdae,
904 double *minae,
905 double *maxae) {
906
907 /* Loop over channels... */
908 for (int id = 0; id < ctl->nd; id++) {
909
910 double sum = 0, sum2 = 0;
911 minae[id] = +1e100;
912 maxae[id] = -1e100;
913 int n = 0;
914
915 /* Loop over ray paths... */
916 for (int ir = 0; ir < obs_test->nr; ir++) {
917
918 /* Skip invalid pairs... */
919 if (!isfinite(obs_test->rad[id][ir])
920 || !isfinite(obs_ref->rad[id][ir]))
921 continue;
922
923 /* Calculate signed absolute error in the observation output units... */
924 double err = obs_test->rad[id][ir] - obs_ref->rad[id][ir];
925
926 /* Get statistics... */
927 sum += err;
928 sum2 += err * err;
929 if (err > maxae[id])
930 maxae[id] = err;
931 if (err < minae[id])
932 minae[id] = err;
933 n++;
934 }
935
936 /* Get mean and standard deviation... */
937 if (n > 0) {
938 meanae[id] = sum / n;
939 sdae[id] = sqrt(fmax(0, sum2 / n - meanae[id] * meanae[id]));
940 } else
941 meanae[id] = sdae[id] = minae[id] = maxae[id] = NAN;
942 }
943}
int main(int argc, char *argv[])
Definition: formod.c:168
void eval_formod_results(const ctl_t *ctl, const char *wrkdir, const char *obsref, const obs_t *obs, obs_t *obs_ref)
Print relative-error diagnostics against reference observations.
Definition: formod.c:484
void compute_abs_errors(const ctl_t *ctl, const obs_t *obs_test, const obs_t *obs_ref, double *meanae, double *sdae, double *minae, double *maxae)
Calculate signed absolute errors in the observation output units.
Definition: formod.c:898
int parse_formod_batch_size(int argc, char *argv[])
Parse the benchmark batch size.
Definition: formod.c:386
char parse_task_mode(const char *task)
Parse the formod task selector and map aliases to an internal task code.
Definition: formod.c:345
void exec_formod_benchmark(const ctl_t *ctl, const tbl_t *tbl, const atm_t *atm, obs_t *obs, atm_t *atm_scratch, los_t *los_scratch, obs_t *obs_scratch, int formod_scalar, int batch_size)
Run the built-in runtime benchmark.
Definition: formod.c:622
void call_formod(ctl_t *ctl, const tbl_t *tbl, const char *wrkdir, const char *obsfile, const char *atmfile, const char *radfile, char task_mode, const char *obsref, int formod_scalar, int batch_size)
Perform forward model calculations in a single directory.
Definition: formod.c:777
void exec_formod_batch_setup(const ctl_t *ctl, const atm_t *atm, const obs_t *obs, int batch_size, atm_t *atm_batch, obs_t *obs_batch)
Build a batch of randomly perturbed copies of the input atmosphere.
Definition: formod.c:567
int parse_formod_scalar(int argc, char *argv[])
Parse the formod execution selector.
Definition: formod.c:368
void exec_formod_single(const ctl_t *ctl, const tbl_t *tbl, atm_t *atm, obs_t *obs, los_t *los_scratch, obs_t *obs_scratch, int formod_scalar)
Execute a single forward model call via the default batch path or the scalar debug path.
Definition: formod.c:401
void exec_formod_stepsize(ctl_t *ctl, const tbl_t *tbl, atm_t *atm, obs_t *obs, obs_t *obs_ref, los_t *los_scratch, obs_t *obs_scratch, int formod_scalar)
Analyze sensitivity to ray-tracing step sizes.
Definition: formod.c:735
void exec_formod_profiles(ctl_t *ctl, const tbl_t *tbl, const char *wrkdir, const char *radfile, const atm_t *atm, obs_t *obs, atm_t *atm_scratch, obs_t *obs_single, los_t *los_scratch, obs_t *obs_scratch, int formod_scalar)
Process observation data profile by profile using time-based matching.
Definition: formod.c:425
void usage(void)
Print command-line help.
Definition: formod.c:273
void exec_formod_contributions(ctl_t *ctl, const tbl_t *tbl, const char *wrkdir, const char *radfile, const atm_t *atm, obs_t *obs, atm_t *atm_scratch, los_t *los_scratch, obs_t *obs_scratch, int formod_scalar)
Write emitter and extinction contribution outputs.
Definition: formod.c:512
void compute_rel_errors(const ctl_t *ctl, const obs_t *obs_test, const obs_t *obs_ref, double *mre, double *sdre, double *minre, double *maxre)
Calculate relative errors.
Definition: formod.c:847
void tbl_free(const ctl_t *ctl, tbl_t *tbl)
Free lookup table and all internally allocated memory.
Definition: jurassic.c:7003
void read_ctl(int argc, char *argv[], ctl_t *ctl)
Read model control parameters from command-line and configuration input.
Definition: jurassic.c:5542
void read_obs(const char *dirname, const char *filename, const ctl_t *ctl, obs_t *obs, int profile)
Read observation data from an input file.
Definition: jurassic.c:5836
void write_obs(const char *dirname, const char *filename, const ctl_t *ctl, const obs_t *obs, int profile)
Write observation data to an output file in ASCII or binary format.
Definition: jurassic.c:8276
void read_atm(const char *dirname, const char *filename, const ctl_t *ctl, atm_t *atm, int profile)
Read atmospheric input data from a file.
Definition: jurassic.c:5219
void copy_obs(const ctl_t *ctl, obs_t *obs_dest, const obs_t *obs_src, const int init)
Copy or initialize observation geometry and radiance data.
Definition: jurassic.c:3164
void formod_batch(const ctl_t *ctl, const tbl_t *tbl, atm_t *atm, obs_t *obs, const int nbatch, int *status, los_t *los_scratch, obs_t *obs_scratch)
Execute the forward model for a batch of independent cases.
Definition: jurassic.c:3316
double scan_ctl(int argc, char *argv[], const char *varname, const int arridx, const char *defvalue, char *value)
Scan control file or command-line arguments for a configuration variable.
Definition: jurassic.c:6613
tbl_t * read_tbl(const ctl_t *ctl)
Read emissivity lookup tables from disk.
Definition: jurassic.c:6333
void copy_atm(const ctl_t *ctl, atm_t *atm_dest, const atm_t *atm_src, const int init)
Copy or initialize atmospheric profile data.
Definition: jurassic.c:3114
int formod(const ctl_t *ctl, const tbl_t *tbl, atm_t *atm, obs_t *obs, los_t *los_scratch, obs_t *obs_scratch)
Execute one complete forward-model calculation.
Definition: jurassic.c:3265
JURASSIC library declarations.
#define LEN
Maximum length of ASCII data lines.
Definition: jurassic.h:276
@ FORMOD_STATUS_OK
Definition: jurassic.h:159
#define POW2(x)
Compute the square of a value.
Definition: jurassic.h:1049
#define SELECT_TIMER(id, group)
Switch to a named aggregated timer.
Definition: jurassic.h:1189
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: jurassic.h:1356
#define USAGE
Print usage information on -h or --help.
Definition: jurassic.h:1237
#define ND
Maximum number of radiance channels.
Definition: jurassic.h:296
#define ALLOC(ptr, type, n)
Allocate memory for an array.
Definition: jurassic.h:426
#define PRINT_TIMERS
Print aggregated timer statistics.
Definition: jurassic.h:1199
#define NG
Maximum number of emitters.
Definition: jurassic.h:306
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: jurassic.h:1286
Atmospheric profile data.
Definition: jurassic.h:1406
double time[NP]
Time (seconds since 2000-01-01T00:00Z).
Definition: jurassic.h:1412
double k[NW][NP]
Extinction [km^-1].
Definition: jurassic.h:1433
double lat[NP]
Latitude [deg].
Definition: jurassic.h:1421
double lon[NP]
Longitude [deg].
Definition: jurassic.h:1418
double t[NP]
Temperature [K].
Definition: jurassic.h:1427
int np
Number of data points.
Definition: jurassic.h:1409
double z[NP]
Altitude [km].
Definition: jurassic.h:1415
double q[NG][NP]
Volume mixing ratio [ppv].
Definition: jurassic.h:1430
double p[NP]
Pressure [hPa].
Definition: jurassic.h:1424
Control parameters.
Definition: jurassic.h:1459
int nw
Number of spectral windows.
Definition: jurassic.h:1486
double nu[ND]
Centroid wavenumber of each channel [cm^-1].
Definition: jurassic.h:1483
int ctm_co2
Compute CO2 continuum (0=no, 1=yes).
Definition: jurassic.h:1528
int ctm_n2
Compute N2 continuum (0=no, 1=yes).
Definition: jurassic.h:1534
int ctm_h2o
Compute H2O continuum (0=no, 1=yes).
Definition: jurassic.h:1531
int ng
Number of emitters.
Definition: jurassic.h:1462
int nd
Number of radiance channels.
Definition: jurassic.h:1480
int ctm_o2
Compute O2 continuum (0=no, 1=yes).
Definition: jurassic.h:1537
char emitter[NG][LEN]
Name of each emitter.
Definition: jurassic.h:1465
double rayds
Maximum step length for raytracing [km].
Definition: jurassic.h:1543
double raydz
Vertical step length for raytracing [km].
Definition: jurassic.h:1546
Line-of-sight data.
Definition: jurassic.h:1626
Observation geometry and radiance data.
Definition: jurassic.h:1688
double tau[ND][NR]
Transmittance of ray path.
Definition: jurassic.h:1724
double rad[ND][NR]
Radiance [W/(m^2 sr cm^-1)].
Definition: jurassic.h:1727
double vpz[NR]
View point altitude [km].
Definition: jurassic.h:1706
double vplat[NR]
View point latitude [deg].
Definition: jurassic.h:1712
double obslon[NR]
Observer longitude [deg].
Definition: jurassic.h:1700
double obslat[NR]
Observer latitude [deg].
Definition: jurassic.h:1703
double obsz[NR]
Observer altitude [km].
Definition: jurassic.h:1697
double vplon[NR]
View point longitude [deg].
Definition: jurassic.h:1709
double time[NR]
Time (seconds since 2000-01-01T00:00Z).
Definition: jurassic.h:1694
int nr
Number of ray paths.
Definition: jurassic.h:1691
Emissivity look-up tables.
Definition: jurassic.h:1876