27#include "jurassic_unified_library.h"
48 const obs_t * obs_test,
49 const obs_t * obs_ref,
74 ERRMSG(
"Missing or invalid command-line arguments.\n\n"
75 "Usage: formod <ctl> <obs> <atm> <rad> [KEY VALUE ...]\n\n"
76 "Use -h for full help.");
89 read_obs(NULL, argv[2], &ctl, &obs, 0);
93 read_atm(NULL, argv[3], &ctl, &atm, 0);
97 jur_unified_init(argc, argv);
98 jur_unified_formod_multiple_packages(&atm, &obs, 1, NULL);
106 char dirlist[
LEN], obsref[
LEN], task[
LEN];
114 scan_ctl(argc, argv,
"TASK", -1,
"-", task);
118 scan_ctl(argc, argv,
"DIRLIST", -1,
"-", dirlist);
122 scan_ctl(argc, argv,
"OBSREF", -1,
"-", obsref);
125 if (dirlist[0] ==
'-')
126 call_formod(&ctl, tbl, NULL, argv[2], argv[3], argv[4], task, obsref);
133 if (!(in = fopen(dirlist,
"r")))
134 ERRMSG(
"Cannot open directory list!");
138 while (fscanf(in,
"%4999s", wrkdir) != EOF) {
141 LOG(1,
"\nWorking directory: %s", wrkdir);
144 call_formod(&ctl, tbl, wrkdir, argv[2], argv[3], argv[4], task, obsref);
166 printf(
"\nJURASSIC forward model.\n\n");
168 (
"Compute simulated radiances or transmittances for the configured\n");
170 (
"channels from observation geometry, atmospheric state, and control\n");
171 printf(
"settings.\n\n");
173 printf(
" formod <ctl> <obs> <atm> <rad> [KEY VALUE ...]\n\n");
174 printf(
"Arguments:\n");
175 printf(
" <ctl> Control file.\n");
176 printf(
" <obs> Observation geometry input file.\n");
177 printf(
" <atm> Atmospheric state input file.\n");
178 printf(
" <rad> Output file for simulated radiances or transmittances.\n");
179 printf(
" [KEY VALUE] Optional control parameters.\n\n");
180 printf(
"Tool-specific control parameters:\n");
181 printf(
" TASK <name> Select the operation mode.\n");
183 (
" - or omitted: regular forward-model simulation.\n");
185 (
" c: write separate outputs for individual emitter and\n");
186 printf(
" extinction contributions.\n");
188 (
" p: process observation profiles one ray at a time,\n");
189 printf(
" matching atmospheric profiles by time.\n");
191 (
" s: analyze sensitivity to ray-tracing step sizes.\n");
193 (
" t: run the built-in runtime benchmark using randomly\n");
195 (
" perturbed versions of the input atmosphere.\n");
197 (
" DIRLIST <file> Read working directories from <file> and run one case\n");
199 (
" per directory using the same <obs>, <atm>, and <rad>\n");
200 printf(
" filenames relative to each listed directory.\n");
202 (
" OBSREF <file> Read reference observations from <file> and print\n");
204 (
" relative-error diagnostics against the simulated output.\n");
206 printf(
"Common control parameters:\n");
208 (
" TBLBASE, TBLFMT Lookup-table base name and format.\n");
210 (
" ATMFMT, OBSFMT Atmospheric and observation file formats.\n");
211 printf(
" NG, EMITTER[i] Active emitters.\n");
212 printf(
" ND, NU[i], NW, WINDOW[i] Spectral channels and windows.\n");
214 (
" NCL, CLNU[i], NSF, SFNU[i] Cloud and surface spectral grids.\n");
216 (
" WRITE_BBT, FORMOD Output units and forward-model selection.\n");
217 printf(
" CTM_*, REFRAC Continua and refractivity.\n");
219 (
" RAYDS, RAYDZ, FOV Ray tracing and field of view.\n\n");
220 printf(
"Further information:\n");
221 printf(
" Manual: https://slcs-jsc.github.io/jurassic/\n");
234 const char *obsref) {
236 static atm_t atm, atm2;
237 static obs_t obs, obs2;
241 read_atm(wrkdir, atmfile, ctl, &atm, 0);
245 read_obs(wrkdir, obsfile, ctl, &obs, 0);
248 if (task[0] ==
'p' || task[0] ==
'P') {
253 for (
int ir = 0; ir < obs.
nr; ir++) {
257 for (
int ip = 0; ip < atm.
np; ip++)
260 atm2.
z[atm2.
np] = atm.
z[ip];
263 atm2.
p[atm2.
np] = atm.
p[ip];
264 atm2.
t[atm2.
np] = atm.
t[ip];
265 for (
int ig = 0; ig < ctl->
ng; ig++)
266 atm2.
q[ig][atm2.
np] = atm.
q[ig][ip];
267 for (
int iw = 0; iw < ctl->
nw; iw++)
268 atm2.
k[iw][atm2.
np] = atm.
k[iw][ip];
275 obs2.
vpz[0] = obs.
vpz[ir];
286 formod(ctl, tbl, &atm2, &obs2);
289 for (
int id = 0;
id < ctl->
nd;
id++) {
290 obs.
rad[id][ir] = obs2.
rad[id][0];
291 obs.
tau[id][ir] = obs2.
tau[id][0];
298 write_obs(wrkdir, radfile, ctl, &obs, 0);
306 formod(ctl, tbl, &atm, &obs);
310 write_obs(wrkdir, radfile, ctl, &obs, 0);
313 if (obsref[0] !=
'-') {
318 read_obs(wrkdir, obsref, ctl, &obs2, 0);
321 double mre[
ND], sdre[
ND], minre[
ND], maxre[
ND];
325 for (
int id = 0;
id < ctl->
nd;
id++)
327 (
"EVAL: nu= %.4f cm^-1 | MRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
328 ctl->
nu[
id], mre[
id], sdre[
id], minre[
id], maxre[
id]);
332 if (task[0] ==
'c' || task[0] ==
'C') {
345 for (
int ig = 0; ig < ctl->
ng; ig++) {
351 for (
int iw = 0; iw < ctl->
nw; iw++)
352 for (
int ip = 0; ip < atm2.
np; ip++)
356 for (
int ig2 = 0; ig2 < ctl->
ng; ig2++)
358 for (
int ip = 0; ip < atm2.
np; ip++)
362 formod(ctl, tbl, &atm2, &obs);
365 sprintf(filename,
"%s.%s", radfile, ctl->
emitter[ig]);
366 write_obs(wrkdir, filename, ctl, &obs, 0);
373 for (
int ig = 0; ig < ctl->
ng; ig++)
374 for (
int ip = 0; ip < atm2.
np; ip++)
378 formod(ctl, tbl, &atm2, &obs);
381 sprintf(filename,
"%s.EXTINCT", radfile);
382 write_obs(wrkdir, filename, ctl, &obs, 0);
386 if (task[0] ==
't' || task[0] ==
'T') {
389 double t_min = 0, t_max = 0, t_mean = 0, t_sd = 0;
394 gsl_rng *rng = gsl_rng_alloc(gsl_rng_default);
401 double dtemp = 40. * (gsl_rng_uniform(rng) - 0.5);
402 double dpress = 1. - 0.1 * gsl_rng_uniform(rng);
404 for (
int ig = 0; ig < ctl->
ng; ig++)
405 dq[ig] = 0.8 + 0.4 * gsl_rng_uniform(rng);
406 for (
int ip = 0; ip < atm2.
np; ip++) {
408 atm2.
p[ip] *= dpress;
409 for (
int ig = 0; ig < ctl->
ng; ig++)
410 atm2.
q[ig][ip] *= dq[ig];
415 double t0 = omp_get_wtime();
416 formod(ctl, tbl, &atm2, &obs);
417 double dt = omp_get_wtime() - t0;
422 if (n == 0 || dt < t_min)
424 if (n == 0 || dt > t_max)
428 }
while (t_mean < 10.0);
431 t_mean /= (double) n;
432 t_sd = sqrt(t_sd / (
double) n -
POW2(t_mean));
433 printf(
"RUNTIME: mean= %g s | stddev= %g s | min= %g s | max= %g s\n",
434 t_mean, t_sd, t_min, t_max);
441 if (task[0] ==
's' || task[0] ==
'S') {
448 formod(ctl, tbl, &atm, &obs);
452 for (
double dz = 0.01; dz <= 2; dz *= 1.1)
453 for (
double ds = 0.1; ds <= 50; ds *= 1.1) {
460 double t0 = omp_get_wtime();
461 formod(ctl, tbl, &atm, &obs);
462 double dt = omp_get_wtime() - t0;
465 double mre[
ND], sdre[
ND], minre[
ND], maxre[
ND];
469 for (
int id = 0;
id < ctl->
nd;
id++)
471 (
"STEPSIZE: ds= %.4f km | dz= %g km | t= %g s | nu= %.4f cm^-1"
472 " | MRE= %g %% | SDRE= %g %% | MinRE= %g %% | MaxRE= %g %%\n",
473 ds, dz, dt, ctl->
nu[
id], mre[
id], sdre[
id], minre[
id],
484 const obs_t *obs_test,
485 const obs_t *obs_ref,
492 for (
int id = 0;
id < ctl->
nd;
id++) {
494 double sum = 0, sum2 = 0;
500 for (
int ir = 0; ir < obs_test->
nr; ir++) {
503 if (obs_ref->
rad[
id][ir] == 0)
507 double err = 100.0 * (obs_test->
rad[id][ir] - obs_ref->
rad[id][ir])
508 / obs_ref->
rad[
id][ir];
522 sdre[id] = sqrt(sum2 / n - mre[
id] * mre[
id]);
void tbl_free(const ctl_t *ctl, tbl_t *tbl)
Free lookup table and all internally allocated memory.
void read_ctl(int argc, char *argv[], ctl_t *ctl)
Read model control parameters from command-line and configuration input.
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.
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.
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.
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.
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.
void formod(const ctl_t *ctl, const tbl_t *tbl, atm_t *atm, obs_t *obs)
Execute the selected forward model.
tbl_t * read_tbl(const ctl_t *ctl)
Read emissivity lookup tables from disk.
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.
JURASSIC library declarations.
#define LEN
Maximum length of ASCII data lines.
#define POW2(x)
Compute the square of a value.
#define SELECT_TIMER(id, group)
Switch to a named aggregated timer.
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
#define USAGE
Print usage information on -h or --help.
#define ND
Maximum number of radiance channels.
#define PRINT_TIMERS
Print aggregated timer statistics.
#define NG
Maximum number of emitters.
#define LOG(level,...)
Print a log message with a specified logging level.
Atmospheric profile data.
double time[NP]
Time (seconds since 2000-01-01T00:00Z).
double k[NW][NP]
Extinction [km^-1].
double lat[NP]
Latitude [deg].
double lon[NP]
Longitude [deg].
double t[NP]
Temperature [K].
int np
Number of data points.
double z[NP]
Altitude [km].
double q[NG][NP]
Volume mixing ratio [ppv].
double p[NP]
Pressure [hPa].
int nw
Number of spectral windows.
double nu[ND]
Centroid wavenumber of each channel [cm^-1].
int ctm_co2
Compute CO2 continuum (0=no, 1=yes).
int ctm_n2
Compute N2 continuum (0=no, 1=yes).
int ctm_h2o
Compute H2O continuum (0=no, 1=yes).
int ng
Number of emitters.
int nd
Number of radiance channels.
int ctm_o2
Compute O2 continuum (0=no, 1=yes).
char emitter[NG][LEN]
Name of each emitter.
double rayds
Maximum step length for raytracing [km].
double raydz
Vertical step length for raytracing [km].
Observation geometry and radiance data.
double tau[ND][NR]
Transmittance of ray path.
double rad[ND][NR]
Radiance [W/(m^2 sr cm^-1)].
double vpz[NR]
View point altitude [km].
double vplat[NR]
View point latitude [deg].
double obslon[NR]
Observer longitude [deg].
double obslat[NR]
Observer latitude [deg].
double obsz[NR]
Observer altitude [km].
double vplon[NR]
View point longitude [deg].
double time[NR]
Time (seconds since 2000-01-01T00:00Z).
int nr
Number of ray paths.
Emissivity look-up tables.