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(" the simulated output.\n");
319 printf
320 (" EXECUTION <mode> Select execution backend: batch (default) or scalar.\n");
321 printf
322 (" BATCH_SIZE <n> Batch size for TASK=time with EXECUTION=batch.\n");
323 printf("\n");
324 printf("Common control parameters:\n");
325 printf
326 (" TBLBASE, TBLFMT Lookup-table base name and format.\n");
327 printf
328 (" ATMFMT, OBSFMT Atmospheric and observation file formats.\n");
329 printf(" NG, EMITTER[i] Active emitters.\n");
330 printf(" ND, NU[i], NW, WINDOW[i] Spectral channels and windows.\n");
331 printf
332 (" NCL, CLNU[i], NSF, SFNU[i] Cloud and surface spectral grids.\n");
333 printf
334 (" WRITE_BBT, FORMOD Output units and forward-model selection.\n");
335 printf(" CTM_*, REFRAC Continua and refractivity.\n");
336 printf
337 (" RAYDS, RAYDZ, FOV Ray tracing and field of view.\n\n");
338 printf("Further information:\n");
339 printf(" Manual: https://slcs-jsc.github.io/jurassic/\n");
340}
341
342/*****************************************************************************/
343
345 const char *task) {
346
347 if (task[0] == '-' || strcmp(task, "forward") == 0)
348 return 'f';
349 if (task[0] == 'c' || strcmp(task, "contrib") == 0
350 || strcmp(task, "contributions") == 0)
351 return 'c';
352 if (task[0] == 'p' || strcmp(task, "profile") == 0
353 || strcmp(task, "profiles") == 0)
354 return 'p';
355 if (task[0] == 's' || strcmp(task, "stepsize") == 0)
356 return 's';
357 if (task[0] == 't' || strcmp(task, "time") == 0
358 || strcmp(task, "benchmark") == 0)
359 return 't';
360
361 ERRMSG("Unknown TASK '%s'!", task);
362 return 'f';
363}
364
365/*****************************************************************************/
366
368 int argc,
369 char *argv[]) {
370
371 char execution[LEN];
372 scan_ctl(argc, argv, "EXECUTION", -1, "batch", execution);
373
374 if (strcmp(execution, "batch") == 0)
375 return 0;
376 if (strcmp(execution, "scalar") == 0)
377 return 1;
378
379 ERRMSG("Unknown EXECUTION '%s'!", execution);
380 return 0;
381}
382
383/*****************************************************************************/
384
386 int argc,
387 char *argv[]) {
388
389 const int batch_size =
390 (int) scan_ctl(argc, argv, "BATCH_SIZE", -1, "1", NULL);
391
392 if (batch_size < 1)
393 ERRMSG("BATCH_SIZE must be positive!");
394
395 return batch_size;
396}
397
398/*****************************************************************************/
399
401 const ctl_t *ctl,
402 const tbl_t *tbl,
403 atm_t *atm,
404 obs_t *obs,
405 los_t *los_scratch,
406 obs_t *obs_scratch,
407 int formod_scalar) {
408
409 if (formod_scalar) {
410 const int status = formod(ctl, tbl, atm, obs, los_scratch, obs_scratch);
411 if (status != FORMOD_STATUS_OK)
412 ERRMSG("Forward model failed with status code %d!", status);
413 return;
414 }
415
416 int status[1];
417 formod_batch(ctl, tbl, atm, obs, 1, status, los_scratch, obs_scratch);
418 if (status[0] != FORMOD_STATUS_OK)
419 ERRMSG("Forward model failed with status code %d!", status[0]);
420}
421
422/*****************************************************************************/
423
425 ctl_t *ctl,
426 const tbl_t *tbl,
427 const char *wrkdir,
428 const char *radfile,
429 const atm_t *atm,
430 obs_t *obs,
431 atm_t *atm_scratch,
432 obs_t *obs_single,
433 los_t *los_scratch,
434 obs_t *obs_scratch,
435 int formod_scalar) {
436
437 SELECT_TIMER("FORMOD_PROFILE_LOOP", "FORWARD");
438
439 for (int ir = 0; ir < obs->nr; ir++) {
440
441 atm_scratch->np = 0;
442 for (int ip = 0; ip < atm->np; ip++)
443 if (atm->time[ip] == obs->time[ir]) {
444 atm_scratch->time[atm_scratch->np] = atm->time[ip];
445 atm_scratch->z[atm_scratch->np] = atm->z[ip];
446 atm_scratch->lon[atm_scratch->np] = atm->lon[ip];
447 atm_scratch->lat[atm_scratch->np] = atm->lat[ip];
448 atm_scratch->p[atm_scratch->np] = atm->p[ip];
449 atm_scratch->t[atm_scratch->np] = atm->t[ip];
450 for (int ig = 0; ig < ctl->ng; ig++)
451 atm_scratch->q[ig][atm_scratch->np] = atm->q[ig][ip];
452 for (int iw = 0; iw < ctl->nw; iw++)
453 atm_scratch->k[iw][atm_scratch->np] = atm->k[iw][ip];
454 atm_scratch->np++;
455 }
456
457 obs_single->nr = 1;
458 obs_single->time[0] = obs->time[ir];
459 obs_single->vpz[0] = obs->vpz[ir];
460 obs_single->vplon[0] = obs->vplon[ir];
461 obs_single->vplat[0] = obs->vplat[ir];
462 obs_single->obsz[0] = obs->obsz[ir];
463 obs_single->obslon[0] = obs->obslon[ir];
464 obs_single->obslat[0] = obs->obslat[ir];
465
466 if (atm_scratch->np > 0) {
467 exec_formod_single(ctl, tbl, atm_scratch, obs_single, los_scratch,
468 obs_scratch, formod_scalar);
469
470 for (int id = 0; id < ctl->nd; id++) {
471 obs->rad[id][ir] = obs_single->rad[id][0];
472 obs->tau[id][ir] = obs_single->tau[id][0];
473 }
474 }
475 }
476
477 SELECT_TIMER("WRITE_OBS", "OUTPUT");
478 write_obs(wrkdir, radfile, ctl, obs, 0);
479}
480
481/*****************************************************************************/
482
484 const ctl_t *ctl,
485 const char *wrkdir,
486 const char *obsref,
487 const obs_t *obs,
488 obs_t *obs_ref) {
489
490 SELECT_TIMER("EVAL", "OUTPUT");
491
492 read_obs(wrkdir, obsref, ctl, obs_ref, 0);
493
494 double mre[ND], sdre[ND], minre[ND], maxre[ND];
495 double meanae[ND], sdae[ND], minae[ND], maxae[ND];
496 compute_rel_errors(ctl, obs, obs_ref, mre, sdre, minre, maxre);
497 compute_abs_errors(ctl, obs, obs_ref, meanae, sdae, minae, maxae);
498
499 for (int id = 0; id < ctl->nd; id++) {
500 printf
501 ("EVAL: nu= %.4f cm^-1 | MeanRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
502 ctl->nu[id], mre[id], sdre[id], minre[id], maxre[id]);
503 printf
504 ("EVAL: nu= %.4f cm^-1 | MeanAE= %g | SDAE= %g | MinAE= %g | MaxAE= %g\n",
505 ctl->nu[id], meanae[id], sdae[id], minae[id], maxae[id]);
506 }
507}
508
509/*****************************************************************************/
510
512 ctl_t *ctl,
513 const tbl_t *tbl,
514 const char *wrkdir,
515 const char *radfile,
516 const atm_t *atm,
517 obs_t *obs,
518 atm_t *atm_scratch,
519 los_t *los_scratch,
520 obs_t *obs_scratch,
521 int formod_scalar) {
522
523 char filename[LEN];
524
525 SELECT_TIMER("CONTRIBUTIONS", "FORWARD");
526
527 ctl->ctm_co2 = 0;
528 ctl->ctm_h2o = 0;
529 ctl->ctm_n2 = 0;
530 ctl->ctm_o2 = 0;
531
532 for (int ig = 0; ig < ctl->ng; ig++) {
533 copy_atm(ctl, atm_scratch, atm, 0);
534
535 for (int iw = 0; iw < ctl->nw; iw++)
536 for (int ip = 0; ip < atm_scratch->np; ip++)
537 atm_scratch->k[iw][ip] = 0;
538
539 for (int ig2 = 0; ig2 < ctl->ng; ig2++)
540 if (ig2 != ig)
541 for (int ip = 0; ip < atm_scratch->np; ip++)
542 atm_scratch->q[ig2][ip] = 0;
543
544 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch,
545 obs_scratch, formod_scalar);
546
547 sprintf(filename, "%s.%s", radfile, ctl->emitter[ig]);
548 write_obs(wrkdir, filename, ctl, obs, 0);
549 }
550
551 copy_atm(ctl, atm_scratch, atm, 0);
552
553 for (int ig = 0; ig < ctl->ng; ig++)
554 for (int ip = 0; ip < atm_scratch->np; ip++)
555 atm_scratch->q[ig][ip] = 0;
556
557 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch, obs_scratch,
558 formod_scalar);
559
560 sprintf(filename, "%s.EXTINCT", radfile);
561 write_obs(wrkdir, filename, ctl, obs, 0);
562}
563
564/*****************************************************************************/
565
567 const ctl_t *ctl,
568 const atm_t *atm,
569 const obs_t *obs,
570 int batch_size,
571 atm_t *atm_batch,
572 obs_t *obs_batch) {
573
574 double *dtemp, *dpress, *dq;
575 ALLOC(dtemp, double,
576 batch_size);
577 ALLOC(dpress, double,
578 batch_size);
579 ALLOC(dq, double,
580 batch_size * NG);
581
582 /* Draw perturbations (the first case stays unperturbed)... */
583 gsl_rng_env_setup();
584 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
585 gsl_rng_set(rng, 0UL);
586 for (int ib = 0; ib < batch_size; ib++) {
587 dtemp[ib] = 0;
588 dpress[ib] = 1;
589 for (int ig = 0; ig < ctl->ng; ig++)
590 dq[ib * NG + ig] = 1;
591 if (ib == 0)
592 continue;
593 dtemp[ib] = 40.0 * (gsl_rng_uniform(rng) - 0.5);
594 dpress[ib] = 1.0 - 0.1 * gsl_rng_uniform(rng);
595 for (int ig = 0; ig < ctl->ng; ig++)
596 dq[ib * NG + ig] = 0.8 + 0.4 * gsl_rng_uniform(rng);
597 }
598 gsl_rng_free(rng);
599
600 /* Apply perturbations... */
601#pragma omp parallel for schedule(static)
602 for (int ib = 0; ib < batch_size; ib++) {
603 atm_batch[ib] = *atm;
604 obs_batch[ib] = *obs;
605 for (int ip = 0; ip < atm_batch[ib].np; ip++) {
606 atm_batch[ib].t[ip] += dtemp[ib];
607 atm_batch[ib].p[ip] *= dpress[ib];
608 for (int ig = 0; ig < ctl->ng; ig++)
609 atm_batch[ib].q[ig][ip] *= dq[ib * NG + ig];
610 }
611 }
612
613 /* Free... */
614 free(dtemp);
615 free(dpress);
616 free(dq);
617}
618
619/*****************************************************************************/
620
622 const ctl_t *ctl,
623 const tbl_t *tbl,
624 const atm_t *atm,
625 obs_t *obs,
626 atm_t *atm_scratch,
627 los_t *los_scratch,
628 obs_t *obs_scratch,
629 int formod_scalar,
630 int batch_size) {
631
632 double t_min = 0, t_max = 0, t_mean = 0, t_sd = 0;
633 int n = 0;
634
635 gsl_rng_env_setup();
636 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
637
638 if (formod_scalar && batch_size > 1)
639 ERRMSG("BATCH_SIZE > 1 cannot be combined with EXECUTION scalar!");
640
641 /* Set up the batch and run it once untimed (warm-up)... */
642 atm_t *atm_batch = NULL;
643 obs_t *obs_batch = NULL;
644 int *status = NULL;
645 los_t *los_batch = NULL;
646 obs_t *obs_scratch_batch = NULL;
647 if (batch_size > 1) {
648 ALLOC(atm_batch, atm_t, batch_size);
649 ALLOC(obs_batch, obs_t, batch_size);
650 ALLOC(los_batch, los_t, batch_size);
651 ALLOC(obs_scratch_batch, obs_t, batch_size);
652 ALLOC(status, int,
653 batch_size);
654
655 SELECT_TIMER("BENCHMARK_SETUP", "OVERHEAD");
656 exec_formod_batch_setup(ctl, atm, obs, batch_size, atm_batch, obs_batch);
657 formod_batch(ctl, tbl, atm_batch, obs_batch, batch_size, status,
658 los_batch, obs_scratch_batch);
659 }
660
661 /* Stop after JURASSIC_MAX_ITER samples or JURASSIC_TIME_BUDGET seconds... */
662 const char *env_max_iter = getenv("JURASSIC_MAX_ITER");
663 const int max_iter = env_max_iter ? atoi(env_max_iter) : INT_MAX;
664 const char *env_budget = getenv("JURASSIC_TIME_BUDGET");
665 const double t_budget = env_budget ? atof(env_budget) : 10.0;
666
667 do {
668 SELECT_TIMER("BENCHMARK_SAMPLE", "ANALYSIS");
669 double dt;
670
671 if (batch_size > 1) {
672 const double t0 = omp_get_wtime();
673 formod_batch(ctl, tbl, atm_batch, obs_batch, batch_size, status,
674 los_batch, obs_scratch_batch);
675 dt = omp_get_wtime() - t0;
676 for (int ib = 0; ib < batch_size; ib++)
677 if (status[ib] != FORMOD_STATUS_OK)
678 ERRMSG("Batch benchmark failed with status %d at element %d!",
679 status[ib], ib);
680 } else {
681 copy_atm(ctl, atm_scratch, atm, 0);
682 const double dtemp = 40. * (gsl_rng_uniform(rng) - 0.5);
683 const double dpress = 1. - 0.1 * gsl_rng_uniform(rng);
684 double dq[NG];
685 for (int ig = 0; ig < ctl->ng; ig++)
686 dq[ig] = 0.8 + 0.4 * gsl_rng_uniform(rng);
687 for (int ip = 0; ip < atm_scratch->np; ip++) {
688 atm_scratch->t[ip] += dtemp;
689 atm_scratch->p[ip] *= dpress;
690 for (int ig = 0; ig < ctl->ng; ig++)
691 atm_scratch->q[ig][ip] *= dq[ig];
692 }
693
694 const double t0 = omp_get_wtime();
695 exec_formod_single(ctl, tbl, atm_scratch, obs, los_scratch,
696 obs_scratch, formod_scalar);
697 dt = omp_get_wtime() - t0;
698 }
699
700 t_mean += dt;
701 t_sd += POW2(dt);
702 if (n == 0 || dt < t_min)
703 t_min = dt;
704 if (n == 0 || dt > t_max)
705 t_max = dt;
706 n++;
707
708 } while (t_mean < t_budget && n < max_iter);
709
710 /* Free... */
711 if (batch_size > 1) {
712 free(status);
713 free(obs_scratch_batch);
714 free(los_batch);
715 free(obs_batch);
716 free(atm_batch);
717 }
718
719 /* Write results... */
720 t_mean /= (double) n;
721 t_sd = sqrt(t_sd / (double) n - POW2(t_mean));
722 printf("RUNTIME: execution= %s | threads= %d | batch_size= %d | mean= %g s"
723 " | stddev= %g s | min= %g s | max= %g s | per_model= %g s"
724 " | throughput= %g models/s | samples= %d\n",
725 formod_scalar ? "scalar" : "batch", omp_get_max_threads(),
726 batch_size, t_mean, t_sd, t_min, t_max,
727 t_mean / batch_size, batch_size / t_mean, n);
728
729 gsl_rng_free(rng);
730}
731
732/*****************************************************************************/
733
735 ctl_t *ctl,
736 const tbl_t *tbl,
737 atm_t *atm,
738 obs_t *obs,
739 obs_t *obs_ref,
740 los_t *los_scratch,
741 obs_t *obs_scratch,
742 int formod_scalar) {
743
744 SELECT_TIMER("STEP_ANALYSIS", "ANALYSIS");
745
746 ctl->rayds = 0.1;
747 ctl->raydz = 0.01;
748 exec_formod_single(ctl, tbl, atm, obs, los_scratch, obs_scratch,
749 formod_scalar);
750 copy_obs(ctl, obs_ref, obs, 0);
751
752 for (double dz = 0.01; dz <= 2; dz *= 1.1)
753 for (double ds = 0.1; ds <= 50; ds *= 1.1) {
754 ctl->rayds = ds;
755 ctl->raydz = dz;
756
757 double t0 = omp_get_wtime();
758 exec_formod_single(ctl, tbl, atm, obs, los_scratch,
759 obs_scratch, formod_scalar);
760 double dt = omp_get_wtime() - t0;
761
762 double mre[ND], sdre[ND], minre[ND], maxre[ND];
763 compute_rel_errors(ctl, obs, obs_ref, mre, sdre, minre, maxre);
764
765 for (int id = 0; id < ctl->nd; id++)
766 printf
767 ("STEPSIZE: ds= %.4f km | dz= %g km | t= %g s | nu= %.4f cm^-1"
768 " | MeanRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
769 ds, dz, dt, ctl->nu[id], mre[id], sdre[id], minre[id], maxre[id]);
770 }
771}
772
773/*****************************************************************************/
774
776 ctl_t *ctl,
777 const tbl_t *tbl,
778 const char *wrkdir,
779 const char *obsfile,
780 const char *atmfile,
781 const char *radfile,
782 char task_mode,
783 const char *obsref,
784 int formod_scalar,
785 int batch_size) {
786
787 static atm_t atm, atm2;
788 static obs_t obs, obs2, obs_ref, obs_scratch;
789 static los_t los_scratch;
790
791 /* Read atmospheric data... */
792 SELECT_TIMER("READ_ATM", "INPUT");
793 read_atm(wrkdir, atmfile, ctl, &atm, 0);
794
795 /* Read observation geometry... */
796 SELECT_TIMER("READ_OBS", "INPUT");
797 read_obs(wrkdir, obsfile, ctl, &obs, 0);
798
799 /* Compute multiple profiles... */
800 if (task_mode == 'p') {
801 exec_formod_profiles(ctl, tbl, wrkdir, radfile, &atm, &obs, &atm2, &obs2,
802 &los_scratch, &obs_scratch, formod_scalar);
803 }
804
805 /* Compute single profile... */
806 else {
807
808 if (task_mode != 't' && batch_size > 1)
809 ERRMSG("BATCH_SIZE > 1 is only supported for TASK=time!");
810
811 if (task_mode == 't') {
812 SELECT_TIMER("FORMOD_REFERENCE", "FORWARD");
813 } else {
814 SELECT_TIMER("FORMOD", "FORWARD");
815 }
816 exec_formod_single(ctl, tbl, &atm, &obs, &los_scratch, &obs_scratch,
817 formod_scalar);
818 SELECT_TIMER("WRITE_OBS", "OUTPUT");
819 write_obs(wrkdir, radfile, ctl, &obs, 0);
820
821 if (obsref[0] != '-') {
822 eval_formod_results(ctl, wrkdir, obsref, &obs, &obs_ref);
823 }
824
825 if (task_mode == 'c') {
826 exec_formod_contributions(ctl, tbl, wrkdir, radfile, &atm, &obs, &atm2,
827 &los_scratch, &obs_scratch, formod_scalar);
828 }
829
830 if (task_mode == 't') {
831 exec_formod_benchmark(ctl, tbl, &atm, &obs, &atm2, &los_scratch,
832 &obs_scratch, formod_scalar, batch_size);
833 }
834
835 if (task_mode == 's') {
836 exec_formod_stepsize(ctl, tbl, &atm, &obs, &obs_ref, &los_scratch,
837 &obs_scratch, formod_scalar);
838 }
839 }
840}
841
842/*****************************************************************************/
843
845 const ctl_t *ctl,
846 const obs_t *obs_test,
847 const obs_t *obs_ref,
848 double *mre,
849 double *sdre,
850 double *minre,
851 double *maxre) {
852
853 /* Loop over channels... */
854 for (int id = 0; id < ctl->nd; id++) {
855
856 double sum = 0, sum2 = 0;
857 minre[id] = +1e9;
858 maxre[id] = -1e9;
859 int n = 0;
860
861 /* Loop over ray paths... */
862 for (int ir = 0; ir < obs_test->nr; ir++) {
863
864 /* Skip invalid pairs and zero references... */
865 if (!isfinite(obs_test->rad[id][ir])
866 || !isfinite(obs_ref->rad[id][ir])
867 || obs_ref->rad[id][ir] == 0)
868 continue;
869
870 /* Calculate relative error... */
871 double err = 100.0 * (obs_test->rad[id][ir] - obs_ref->rad[id][ir])
872 / obs_ref->rad[id][ir];
873
874 /* Get statistics... */
875 sum += err;
876 sum2 += err * err;
877 if (err > maxre[id])
878 maxre[id] = err;
879 if (err < minre[id])
880 minre[id] = err;
881 n++;
882 }
883
884 /* Get mean and standard deviation... */
885 if (n > 0) {
886 mre[id] = sum / n;
887 sdre[id] = sqrt(fmax(0, sum2 / n - mre[id] * mre[id]));
888 } else
889 mre[id] = sdre[id] = minre[id] = maxre[id] = NAN;
890 }
891}
892
893/*****************************************************************************/
894
896 const ctl_t *ctl,
897 const obs_t *obs_test,
898 const obs_t *obs_ref,
899 double *meanae,
900 double *sdae,
901 double *minae,
902 double *maxae) {
903
904 /* Loop over channels... */
905 for (int id = 0; id < ctl->nd; id++) {
906
907 double sum = 0, sum2 = 0;
908 minae[id] = +1e100;
909 maxae[id] = -1e100;
910 int n = 0;
911
912 /* Loop over ray paths... */
913 for (int ir = 0; ir < obs_test->nr; ir++) {
914
915 /* Skip invalid pairs... */
916 if (!isfinite(obs_test->rad[id][ir])
917 || !isfinite(obs_ref->rad[id][ir]))
918 continue;
919
920 /* Calculate signed absolute error in the observation output units... */
921 double err = obs_test->rad[id][ir] - obs_ref->rad[id][ir];
922
923 /* Get statistics... */
924 sum += err;
925 sum2 += err * err;
926 if (err > maxae[id])
927 maxae[id] = err;
928 if (err < minae[id])
929 minae[id] = err;
930 n++;
931 }
932
933 /* Get mean and standard deviation... */
934 if (n > 0) {
935 meanae[id] = sum / n;
936 sdae[id] = sqrt(fmax(0, sum2 / n - meanae[id] * meanae[id]));
937 } else
938 meanae[id] = sdae[id] = minae[id] = maxae[id] = NAN;
939 }
940}
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:483
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:895
int parse_formod_batch_size(int argc, char *argv[])
Parse the benchmark batch size.
Definition: formod.c:385
char parse_task_mode(const char *task)
Parse the formod task selector and map aliases to an internal task code.
Definition: formod.c:344
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:621
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:775
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:566
int parse_formod_scalar(int argc, char *argv[])
Parse the formod execution selector.
Definition: formod.c:367
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:400
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:734
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:424
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:511
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:844
void tbl_free(const ctl_t *ctl, tbl_t *tbl)
Free lookup table and all internally allocated memory.
Definition: jurassic.c:7739
void read_ctl(int argc, char *argv[], ctl_t *ctl)
Read model control parameters from command-line and configuration input.
Definition: jurassic.c:6271
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:6568
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:9012
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:5948
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:3884
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:4036
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:7349
tbl_t * read_tbl(const ctl_t *ctl)
Read emissivity lookup tables from disk.
Definition: jurassic.c:7069
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:3834
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:3985
JURASSIC library declarations.
#define LEN
Maximum length of ASCII data lines.
Definition: jurassic.h:335
@ FORMOD_STATUS_OK
Definition: jurassic.h:159
#define POW2(x)
Compute the square of a value.
Definition: jurassic.h:1143
#define SELECT_TIMER(id, group)
Switch to a named aggregated timer.
Definition: jurassic.h:1283
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
Definition: jurassic.h:1450
#define USAGE
Print usage information on -h or --help.
Definition: jurassic.h:1331
#define ND
Maximum number of radiance channels.
Definition: jurassic.h:355
#define ALLOC(ptr, type, n)
Allocate memory for an array.
Definition: jurassic.h:502
#define PRINT_TIMERS
Print aggregated timer statistics.
Definition: jurassic.h:1293
#define NG
Maximum number of emitters.
Definition: jurassic.h:365
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: jurassic.h:1380
Atmospheric profile data.
Definition: jurassic.h:1500
double time[NP]
Time (seconds since 2000-01-01T00:00Z).
Definition: jurassic.h:1506
double k[NW][NP]
Extinction [km^-1].
Definition: jurassic.h:1527
double lat[NP]
Latitude [deg].
Definition: jurassic.h:1515
double lon[NP]
Longitude [deg].
Definition: jurassic.h:1512
double t[NP]
Temperature [K].
Definition: jurassic.h:1521
int np
Number of data points.
Definition: jurassic.h:1503
double z[NP]
Altitude [km].
Definition: jurassic.h:1509
double q[NG][NP]
Volume mixing ratio [ppv].
Definition: jurassic.h:1524
double p[NP]
Pressure [hPa].
Definition: jurassic.h:1518
Control parameters.
Definition: jurassic.h:1592
int nw
Number of spectral windows.
Definition: jurassic.h:1619
double nu[ND]
Centroid wavenumber of each channel [cm^-1].
Definition: jurassic.h:1616
int ctm_co2
Compute CO2 continuum (0=no, 1=yes).
Definition: jurassic.h:1664
int ctm_n2
Compute N2 continuum (0=no, 1=yes).
Definition: jurassic.h:1670
int ctm_h2o
Compute H2O continuum (0=no, 1=yes).
Definition: jurassic.h:1667
int ng
Number of emitters.
Definition: jurassic.h:1595
int nd
Number of radiance channels.
Definition: jurassic.h:1613
int ctm_o2
Compute O2 continuum (0=no, 1=yes).
Definition: jurassic.h:1673
char emitter[NG][LEN]
Name of each emitter.
Definition: jurassic.h:1598
double rayds
Maximum step length for raytracing [km].
Definition: jurassic.h:1679
double raydz
Vertical step length for raytracing [km].
Definition: jurassic.h:1682
Line-of-sight data.
Definition: jurassic.h:1762
Observation geometry and radiance data.
Definition: jurassic.h:1824
double tau[ND][NR]
Transmittance of ray path.
Definition: jurassic.h:1860
double rad[ND][NR]
Radiance [W/(m^2 sr cm^-1)].
Definition: jurassic.h:1863
double vpz[NR]
View point altitude [km].
Definition: jurassic.h:1842
double vplat[NR]
View point latitude [deg].
Definition: jurassic.h:1848
double obslon[NR]
Observer longitude [deg].
Definition: jurassic.h:1836
double obslat[NR]
Observer latitude [deg].
Definition: jurassic.h:1839
double obsz[NR]
Observer altitude [km].
Definition: jurassic.h:1833
double vplon[NR]
View point longitude [deg].
Definition: jurassic.h:1845
double time[NR]
Time (seconds since 2000-01-01T00:00Z).
Definition: jurassic.h:1830
int nr
Number of ray paths.
Definition: jurassic.h:1827
Emissivity look-up tables.
Definition: jurassic.h:2012