JURASSIC
Functions
formod.c File Reference

JURASSIC forward model. More...

#include <limits.h>
#include "jurassic.h"

Go to the source code of this file.

Functions

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. More...
 
char parse_task_mode (const char *task)
 Parse the formod task selector and map aliases to an internal task code. More...
 
int parse_formod_scalar (int argc, char *argv[])
 Parse the formod execution selector. More...
 
int parse_formod_batch_size (int argc, char *argv[])
 Parse the benchmark batch size. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
void usage (void)
 Print command-line help. More...
 
int main (int argc, char *argv[])
 

Detailed Description

JURASSIC forward model.

Definition in file formod.c.

Function Documentation

◆ call_formod()

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 at line 777 of file formod.c.

787 {
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}
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 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 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 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 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
#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
Atmospheric profile data.
Definition: jurassic.h:1406
Line-of-sight data.
Definition: jurassic.h:1626
Observation geometry and radiance data.
Definition: jurassic.h:1688
Here is the call graph for this function:

◆ parse_task_mode()

char parse_task_mode ( const char *  task)

Parse the formod task selector and map aliases to an internal task code.

Definition at line 345 of file formod.c.

346 {
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}

◆ parse_formod_scalar()

int parse_formod_scalar ( int  argc,
char *  argv[] 
)

Parse the formod execution selector.

Definition at line 368 of file formod.c.

370 {
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}
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
#define LEN
Maximum length of ASCII data lines.
Definition: jurassic.h:276
Here is the call graph for this function:

◆ parse_formod_batch_size()

int parse_formod_batch_size ( int  argc,
char *  argv[] 
)

Parse the benchmark batch size.

Definition at line 386 of file formod.c.

388 {
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}
Here is the call graph for this function:

◆ exec_formod_single()

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 at line 401 of file formod.c.

408 {
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}
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
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
@ FORMOD_STATUS_OK
Definition: jurassic.h:159
Here is the call graph for this function:

◆ exec_formod_batch_setup()

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 at line 567 of file formod.c.

573 {
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}
#define ALLOC(ptr, type, n)
Allocate memory for an array.
Definition: jurassic.h:426
#define NG
Maximum number of emitters.
Definition: jurassic.h:306
double t[NP]
Temperature [K].
Definition: jurassic.h:1427
int np
Number of data points.
Definition: jurassic.h:1409
double p[NP]
Pressure [hPa].
Definition: jurassic.h:1424
int ng
Number of emitters.
Definition: jurassic.h:1462

◆ compute_rel_errors()

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 at line 847 of file formod.c.

854 {
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}
int nd
Number of radiance channels.
Definition: jurassic.h:1480
double rad[ND][NR]
Radiance [W/(m^2 sr cm^-1)].
Definition: jurassic.h:1727
int nr
Number of ray paths.
Definition: jurassic.h:1691

◆ compute_abs_errors()

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 at line 898 of file formod.c.

905 {
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}

◆ exec_formod_profiles()

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 at line 425 of file formod.c.

436 {
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}
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 z[NP]
Altitude [km].
Definition: jurassic.h:1415
double q[NG][NP]
Volume mixing ratio [ppv].
Definition: jurassic.h:1430
int nw
Number of spectral windows.
Definition: jurassic.h:1486
double tau[ND][NR]
Transmittance of ray path.
Definition: jurassic.h:1724
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
Here is the call graph for this function:

◆ eval_formod_results()

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 at line 484 of file formod.c.

489 {
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}
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
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
#define ND
Maximum number of radiance channels.
Definition: jurassic.h:296
double nu[ND]
Centroid wavenumber of each channel [cm^-1].
Definition: jurassic.h:1483
Here is the call graph for this function:

◆ exec_formod_contributions()

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 at line 512 of file formod.c.

522 {
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}
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 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 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
Here is the call graph for this function:

◆ exec_formod_benchmark()

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 at line 622 of file formod.c.

631 {
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}
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
#define POW2(x)
Compute the square of a value.
Definition: jurassic.h:1049
Here is the call graph for this function:

◆ exec_formod_stepsize()

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 at line 735 of file formod.c.

743 {
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}
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
double rayds
Maximum step length for raytracing [km].
Definition: jurassic.h:1543
double raydz
Vertical step length for raytracing [km].
Definition: jurassic.h:1546
Here is the call graph for this function:

◆ usage()

static void usage ( void  )

Print command-line help.

Definition at line 273 of file formod.c.

274 {
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}

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 168 of file formod.c.

170 {
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}
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 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
int parse_formod_scalar(int argc, char *argv[])
Parse the formod execution selector.
Definition: formod.c:368
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
tbl_t * read_tbl(const ctl_t *ctl)
Read emissivity lookup tables from disk.
Definition: jurassic.c:6333
#define USAGE
Print usage information on -h or --help.
Definition: jurassic.h:1237
#define PRINT_TIMERS
Print aggregated timer statistics.
Definition: jurassic.h:1199
#define LOG(level,...)
Print a log message with a specified logging level.
Definition: jurassic.h:1286
Control parameters.
Definition: jurassic.h:1459
Emissivity look-up tables.
Definition: jurassic.h:1876
Here is the call graph for this function: