27#define LOOP_ALL(ntrack) \
28 for (int track = 0; track < ntrack; track++) \
29 for (int xtrack = 0; xtrack < L1_NXTRACK; xtrack++) \
30 for (int ifov = 0; ifov < L1_NFOV; ifov++)
33#define WRITE_FIELD(expr, varid) do { \
35 LOOP_ALL(pert_4mu->ntrack) \
37 NC(nc_put_var_double(ncid, (varid), help)); \
50 static pert_t *pert_4mu, *pert_15mu_low, *pert_15mu_high;
52 const double var_dh2 = 100. * 100.;
57 const int list_4mu[
N4]
58 = { 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283,
59 284, 285, 286, 288, 289, 291, 292, 294, 295, 296, 297, 298, 299, 300,
60 302, 303, 304, 305, 306, 307, 318, 319, 321, 322, 323, 324, 325, 326,
61 328, 330, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341
64 const int list_15mu_low[
N15_LOW]
65 = { 5, 8, 10, 13, 15, 17, 23, 34, 36, 39, 41, 44, 46, 49, 51 };
67 const int list_15mu_high[
N15_HIGH] = { 31 };
69 const int list_8mu[
N8] = { 36 };
71 const int list_10mu[
N10] = { 502 };
73 const int dtrack = 3, dxtrack = 3;
75 static int dimid[3], n, ncid, track0,
76 time_varid, lon_varid, lat_varid, bt_4mu_varid, init,
77 bt_4mu_pt_varid, bt_4mu_var_varid, bt_8mu_varid, bt_10mu_varid,
78 bt_15mu_low_varid, bt_15mu_low_pt_varid, bt_15mu_low_var_varid,
79 bt_15mu_high_varid, bt_15mu_high_pt_varid, bt_15mu_high_var_varid;
83 ERRMSG(
"Give parameters: <ctl> <pert.nc> <l1b_file1> [<l1b_file2> ...]");
86 const int apo = (int)
scan_ctl(argc, argv,
"APO", -1,
"0", NULL);
87 const int bias = (int)
scan_ctl(argc, argv,
"BIAS", -1,
"1", NULL);
88 const double dtmed =
scan_ctl(argc, argv,
"DTMED", -1,
"10.0", NULL);
100 for (
int iarg = 3; iarg < argc; iarg++) {
111 LOG(2,
"4.3 micron channels:");
114 for (
int i = 0; i <
N4; i++) {
115 nu += l1.
nu_sw[list_4mu[i]];
117 LOG(2,
" count= %2d | channel index= SW_%03d | nu= %.4f cm^-1", n,
118 list_4mu[i], l1.
nu_sw[list_4mu[i]]);
120 LOG(2,
" nu_mean= %.4f cm^-1", nu / n);
123 LOG(2,
"15 micron low channels:");
126 for (
int i = 0; i <
N15_LOW; i++) {
127 nu += l1.
nu_lw[list_15mu_low[i]];
129 LOG(2,
" count= %2d | channel index= LW_%03d | nu= %.4f cm^-1", n,
130 list_15mu_low[i], l1.
nu_lw[list_15mu_low[i]]);
132 LOG(2,
" nu_mean= %.4f cm^-1", nu / n);
135 LOG(2,
"15 micron high channels:");
138 for (
int i = 0; i <
N15_HIGH; i++) {
139 nu += l1.
nu_lw[list_15mu_high[i]];
141 LOG(2,
" count= %2d | channel index= LW_%03d | nu= %.4f cm^-1", n,
142 list_15mu_high[i], l1.
nu_lw[list_15mu_high[i]]);
144 LOG(2,
" nu_mean= %.4f cm^-1", nu / n);
147 LOG(2,
"8.1 micron channels:");
150 for (
int i = 0; i <
N8; i++) {
151 nu += l1.
nu_mw[list_8mu[i]];
153 LOG(2,
" count= %2d | channel index= MW_%03d | nu= %.4f cm^-1", n,
154 list_8mu[i], l1.
nu_mw[list_8mu[i]]);
156 LOG(2,
" nu_mean= %.4f cm^-1", nu / n);
159 LOG(2,
"10.4 micron channels:");
162 for (
int i = 0; i <
N10; i++) {
163 nu += l1.
nu_lw[list_10mu[i]];
165 LOG(2,
" count= %2d | channel index= LW_%03d | nu= %.4f cm^-1", n,
166 list_10mu[i], l1.
nu_lw[list_10mu[i]]);
168 LOG(2,
" nu_mean= %.4f cm^-1", nu / n);
174 ERRMSG(
"Too many granules!");
177 ERRMSG(
"Too many tracks!");
180 ERRMSG(
"Too many field of views!");
182 pert_4mu->
time[track0 + track][xtrack][ifov]
183 = l1.
time[track][xtrack] - 220838400.;
184 pert_4mu->
lon[track0 + track][xtrack][ifov]
185 = l1.
lon[track][xtrack][ifov];
186 pert_4mu->
lat[track0 + track][xtrack][ifov]
187 = l1.
lat[track][xtrack][ifov];
192 pert_4mu->
dc[track0 + track][xtrack][ifov]
193 =
BRIGHT(l1.
rad_mw[track][xtrack][ifov][list_8mu[0]] * 1e-3,
194 l1.
nu_mw[list_8mu[0]]);
198 pert_15mu_high->
dc[track0 + track][xtrack][ifov]
199 =
BRIGHT(l1.
rad_lw[track][xtrack][ifov][list_10mu[0]] * 1e-3,
200 l1.
nu_lw[list_10mu[0]]);
206 for (
int i = 0; i <
N4; i++)
207 if (gsl_finite(l1.
rad_sw[track][xtrack][ifov][list_4mu[i]])) {
208 rad += l1.
rad_sw[track][xtrack][ifov][list_4mu[i]] * 1e-3;
209 nu += l1.
nu_sw[list_4mu[i]];
213 pert_4mu->
bt[track0 + track][xtrack][ifov] =
BRIGHT(rad / n, nu / n);
215 pert_4mu->
bt[track0 + track][xtrack][ifov] = GSL_NAN;
222 for (
int i = 0; i <
N15_LOW; i++)
223 if (gsl_finite(l1.
rad_lw[track][xtrack][ifov][list_15mu_low[i]])) {
224 rad += l1.
rad_lw[track][xtrack][ifov][list_15mu_low[i]] * 1e-3;
225 nu += l1.
nu_lw[list_15mu_low[i]];
229 pert_15mu_low->
bt[track0 + track][xtrack][ifov] =
232 pert_15mu_low->
bt[track0 + track][xtrack][ifov] = GSL_NAN;
240 if (gsl_finite(l1.
rad_lw[track][xtrack][ifov][list_15mu_high[i]])) {
241 rad += l1.
rad_lw[track][xtrack][ifov][list_15mu_high[i]] * 1e-3;
242 nu += l1.
nu_lw[list_15mu_high[i]];
246 pert_15mu_high->
bt[track0 + track][xtrack][ifov] =
249 pert_15mu_high->
bt[track0 + track][xtrack][ifov] = GSL_NAN;
261 LOG(1,
"Outlier filter...");
264#define OUTLIER_FILTER(BT, DTMED) \
266 for (int track = 0; track < (BT)->ntrack; track++) \
267 for (int xtrack = 0; xtrack < L1_NXTRACK; xtrack++) { \
269 size_t nf = 0, outlier_count = 0; \
270 double xf[L1_NFOV]; \
273 for (int ifov = 0; ifov < L1_NFOV; ifov++) { \
274 double v = (BT)->bt[track][xtrack][ifov]; \
275 if (isfinite(v)) xf[nf++] = v; \
277 if (nf < 2) continue; \
278 double median = gsl_stats_median(xf, 1, nf); \
281 for (int ifov = 0; ifov < L1_NFOV; ifov++) { \
282 double v = (BT)->bt[track][xtrack][ifov]; \
283 if (!isfinite(v)) continue; \
284 if (fabs(v - median) >= (DTMED)) \
289 if (outlier_count > 0 && outlier_count <= 2) { \
290 for (int ifov = 0; ifov < L1_NFOV; ifov++) { \
291 double v = (BT)->bt[track][xtrack][ifov]; \
292 if (!isfinite(v)) continue; \
293 if (fabs(v - median) >= (DTMED)) { \
294 LOG(2, "outlier: track=%d | xtrack=%d | ifov=%d | " \
295 "bt_" #BT "=%g K | median=%g K", \
296 track, xtrack, ifov, v, median); \
297 (BT)->bt[track][xtrack][ifov] = NAN; \
314 LOG(1,
"Calculate perturbations...");
317 for (
int track = 0; track < pert_4mu->
ntrack; track++)
318 for (
int ifov = 0; ifov <
L1_NFOV; ifov++) {
321 pert_4mu->
dc[track][0][ifov] = GSL_NAN;
323 pert_15mu_high->
dc[track][0][ifov] = GSL_NAN;
324 pert_15mu_high->
dc[track][
L1_NXTRACK - 1][ifov] = GSL_NAN;
325 pert_4mu->
bt[track][0][ifov] = GSL_NAN;
327 pert_15mu_low->
bt[track][0][ifov] = GSL_NAN;
328 pert_15mu_low->
bt[track][
L1_NXTRACK - 1][ifov] = GSL_NAN;
329 pert_15mu_high->
bt[track][0][ifov] = GSL_NAN;
330 pert_15mu_high->
bt[track][
L1_NXTRACK - 1][ifov] = GSL_NAN;
333 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++) {
334 x[xtrack] = (double) xtrack;
335 y[xtrack] = pert_4mu->
bt[track][xtrack][ifov];
338 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++)
339 pert_4mu->
pt[track][xtrack][ifov] =
340 pert_4mu->
bt[track][xtrack][ifov] - y[xtrack];
343 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++) {
344 x[xtrack] = (double) xtrack;
345 y[xtrack] = pert_15mu_low->
bt[track][xtrack][ifov];
348 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++)
349 pert_15mu_low->
pt[track][xtrack][ifov] =
350 pert_15mu_low->
bt[track][xtrack][ifov] - y[xtrack];
353 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++) {
354 x[xtrack] = (double) xtrack;
355 y[xtrack] = pert_15mu_high->
bt[track][xtrack][ifov];
358 for (
int xtrack = 0; xtrack <
L1_NXTRACK; xtrack++)
359 pert_15mu_high->
pt[track][xtrack][ifov] =
360 pert_15mu_high->
bt[track][xtrack][ifov] - y[xtrack];
371 LOG(1,
"Calculate bias correction...");
374 const int radius = 25;
377 const double sigma = 11.0;
378 const double inv2sigma2 = 1.0 / (2.0 * sigma * sigma);
381#define APPLY_BIAS_CORR(pert) \
383 LOOP_ALL((pert)->ntrack) { \
384 const int idx = (track * L1_NXTRACK + xtrack) * L1_NFOV + ifov; \
387 for (int dtrack2 = -radius; dtrack2 <= radius; ++dtrack2) { \
388 int t2 = track + dtrack2; \
389 if (t2 < 0 || t2 >= (pert)->ntrack) \
391 if (!isfinite((pert)->pt[t2][xtrack][ifov])) \
393 const double w = exp(-(double)(dtrack2 * dtrack2) * inv2sigma2); \
394 help[idx] += w * (pert)->pt[t2][xtrack][ifov]; \
397 if (wsum > 0.0) help[idx] /= wsum; \
399 LOOP_ALL((pert)->ntrack) { \
400 const int idx = (track * L1_NXTRACK + xtrack) * L1_NFOV + ifov; \
401 (pert)->pt[track][xtrack][ifov] -= help[idx]; \
416 LOG(1,
"Calculate variances...");
423 pert_4mu->
lat[track][xtrack][ifov], x0);
426 int n_4mu = 0, n_15mu_low = 0, n_15mu_high = 0;
427 double mean_4mu = 0, mean_15mu_low = 0, mean_15mu_high = 0;
428 double var_4mu = 0, var_15mu_low = 0, var_15mu_high = 0;
431 for (
int track2 = track - dtrack; track2 <= track + dtrack; track2++)
432 for (
int xtrack2 = xtrack - dxtrack; xtrack2 <= xtrack + dxtrack;
434 for (
int ifov2 = 0; ifov2 <
L1_NFOV; ifov2++)
435 if (track2 >= 0 && track2 < pert_4mu->ntrack
439 geo2cart(0.0, pert_4mu->
lon[track2][xtrack2][ifov2],
440 pert_4mu->
lat[track2][xtrack2][ifov2], x1);
441 if (
DIST2(x0, x1) > var_dh2)
445 if (gsl_finite(pert_4mu->
pt[track2][xtrack2][ifov2])) {
446 mean_4mu += pert_4mu->
pt[track2][xtrack2][ifov2];
447 var_4mu += gsl_pow_2(pert_4mu->
pt[track2][xtrack2][ifov2]);
451 if (gsl_finite(pert_15mu_low->
pt[track2][xtrack2][ifov2])) {
452 mean_15mu_low += pert_15mu_low->
pt[track2][xtrack2][ifov2];
454 gsl_pow_2(pert_15mu_low->
pt[track2][xtrack2][ifov2]);
458 if (gsl_finite(pert_15mu_high->
pt[track2][xtrack2][ifov2])) {
459 mean_15mu_high += pert_15mu_high->
pt[track2][xtrack2][ifov2];
461 gsl_pow_2(pert_15mu_high->
pt[track2][xtrack2][ifov2]);
467 if (n_4mu > 0 && xtrack > 0 && xtrack <
L1_NXTRACK - 1)
468 pert_4mu->
var[track][xtrack][ifov] =
469 var_4mu / n_4mu - gsl_pow_2(mean_4mu / n_4mu);
471 pert_4mu->
var[track][xtrack][ifov] = GSL_NAN;
473 if (n_15mu_low > 0 && xtrack > 0 && xtrack <
L1_NXTRACK - 1)
474 pert_15mu_low->
var[track][xtrack][ifov] =
475 var_15mu_low / n_15mu_low - gsl_pow_2(mean_15mu_low / n_15mu_low);
477 pert_15mu_low->
var[track][xtrack][ifov] = GSL_NAN;
479 if (n_15mu_high > 0 && xtrack > 0 && xtrack <
L1_NXTRACK - 1)
480 pert_15mu_high->
var[track][xtrack][ifov] =
481 var_15mu_high / n_15mu_high - gsl_pow_2(mean_15mu_high / n_15mu_high);
483 pert_15mu_high->
var[track][xtrack][ifov] = GSL_NAN;
491 LOG(1,
"Write perturbation data file: %s", argv[2]);
494 NC(nc_create(argv[2], NC_CLOBBER, &ncid));
497 NC(nc_def_dim(ncid,
"NTRACK", (
size_t) pert_4mu->
ntrack, &dimid[0]));
499 NC(nc_def_dim(ncid,
"NFOV",
L1_NFOV, &dimid[2]));
502 NC(nc_def_var(ncid,
"time", NC_DOUBLE, 3, dimid, &time_varid));
503 add_att(ncid, time_varid,
"s",
"time (seconds since 2000-01-01T00:00Z)");
504 NC(nc_def_var(ncid,
"lon", NC_DOUBLE, 3, dimid, &lon_varid));
505 add_att(ncid, lon_varid,
"deg",
"footprint longitude");
506 NC(nc_def_var(ncid,
"lat", NC_DOUBLE, 3, dimid, &lat_varid));
507 add_att(ncid, lat_varid,
"deg",
"footprint latitude");
509 NC(nc_def_var(ncid,
"bt_8mu", NC_FLOAT, 3, dimid, &bt_8mu_varid));
510 add_att(ncid, bt_8mu_varid,
"K",
"brightness temperature at 8.1 micron");
512 NC(nc_def_var(ncid,
"bt_10mu", NC_FLOAT, 3, dimid, &bt_10mu_varid));
513 add_att(ncid, bt_10mu_varid,
"K",
"brightness temperature at 10.4 micron");
515 NC(nc_def_var(ncid,
"bt_4mu", NC_FLOAT, 3, dimid, &bt_4mu_varid));
516 add_att(ncid, bt_4mu_varid,
"K",
"brightness temperature" " at 4.3 micron");
517 NC(nc_def_var(ncid,
"bt_4mu_pt", NC_FLOAT, 3, dimid, &bt_4mu_pt_varid));
518 add_att(ncid, bt_4mu_pt_varid,
"K",
"brightness temperature perturbation"
520 NC(nc_def_var(ncid,
"bt_4mu_var", NC_FLOAT, 3, dimid, &bt_4mu_var_varid));
521 add_att(ncid, bt_4mu_var_varid,
"K^2",
"brightness temperature variance"
524 NC(nc_def_var(ncid,
"bt_15mu_low", NC_FLOAT, 3, dimid, &bt_15mu_low_varid));
525 add_att(ncid, bt_15mu_low_varid,
"K",
"brightness temperature"
526 " at 15 micron (low altitudes)");
527 NC(nc_def_var(ncid,
"bt_15mu_low_pt", NC_FLOAT, 3, dimid,
528 &bt_15mu_low_pt_varid));
529 add_att(ncid, bt_15mu_low_pt_varid,
"K",
530 "brightness temperature perturbation"
531 " at 15 micron (low altitudes)");
533 (ncid,
"bt_15mu_low_var", NC_FLOAT, 3, dimid, &bt_15mu_low_var_varid));
534 add_att(ncid, bt_15mu_low_var_varid,
"K^2",
535 "brightness temperature variance" " at 15 micron (low altitudes)");
537 NC(nc_def_var(ncid,
"bt_15mu_high", NC_FLOAT, 3, dimid,
538 &bt_15mu_high_varid));
539 add_att(ncid, bt_15mu_high_varid,
"K",
"brightness temperature"
540 " at 15 micron (high altitudes)");
541 NC(nc_def_var(ncid,
"bt_15mu_high_pt", NC_FLOAT, 3, dimid,
542 &bt_15mu_high_pt_varid));
543 add_att(ncid, bt_15mu_high_pt_varid,
"K",
544 "brightness temperature perturbation"
545 " at 15 micron (high altitudes)");
547 (ncid,
"bt_15mu_high_var", NC_FLOAT, 3, dimid, &bt_15mu_high_var_varid));
548 add_att(ncid, bt_15mu_high_var_varid,
"K^2",
549 "brightness temperature variance" " at 15 micron (high altitudes)");
558 WRITE_FIELD(pert_4mu->
dc[track][xtrack][ifov], bt_8mu_varid);
559 WRITE_FIELD(pert_15mu_high->
dc[track][xtrack][ifov], bt_10mu_varid);
560 WRITE_FIELD(pert_4mu->
bt[track][xtrack][ifov], bt_4mu_varid);
561 WRITE_FIELD(pert_4mu->
pt[track][xtrack][ifov], bt_4mu_pt_varid);
562 WRITE_FIELD(pert_4mu->
var[track][xtrack][ifov], bt_4mu_var_varid);
563 WRITE_FIELD(pert_15mu_low->
bt[track][xtrack][ifov], bt_15mu_low_varid);
564 WRITE_FIELD(pert_15mu_low->
pt[track][xtrack][ifov], bt_15mu_low_pt_varid);
565 WRITE_FIELD(pert_15mu_low->
var[track][xtrack][ifov], bt_15mu_low_var_varid);
566 WRITE_FIELD(pert_15mu_high->
bt[track][xtrack][ifov], bt_15mu_high_varid);
567 WRITE_FIELD(pert_15mu_high->
pt[track][xtrack][ifov], bt_15mu_high_pt_varid);
569 bt_15mu_high_var_varid);
577 free(pert_15mu_high);
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 geo2cart(const double z, const double lon, const double lat, double *x)
Converts geographic coordinates (longitude, latitude, altitude) to Cartesian coordinates.
#define BRIGHT(rad, nu)
Compute brightness temperature from radiance.
#define ERRMSG(...)
Print an error message with contextual information and terminate the program.
#define ALLOC(ptr, type, n)
Allocate memory for an array.
#define LOG(level,...)
Print a log message with a specified logging level.
#define DIST2(a, b)
Compute squared distance between two 3D vectors.
void background_poly_help(const double *xx, double *yy, const int n, const int dim)
Get background based on polynomial fits.
int read_cris_l1(char *filename, cris_l1_t *l1, int apo)
Read CrIS Level-1 data.
void add_att(const int ncid, const int varid, const char *unit, const char *long_name)
Add variable attributes to netCDF file.
#define NC(cmd)
Execute netCDF library command and check result.
#define PERT_NXTRACK
Across-track size of perturbation data.
#define L1_NXTRACK
Across-track size of CrIS radiance granule.
#define L1_NTRACK
Along-track size of CrIS radiance granule.
#define L1_NFOV
Number of field of views of CrIS radiance granule.
#define PERT_NTRACK
Along-track size of perturbation data.
#define PERT_NFOV
Number of field of views of perturbation data.
int main(int argc, char *argv[])
#define OUTLIER_FILTER(BT, DTMED)
#define N15_LOW
Number of 15 micron low channels:
#define N10
Number of 10.4 micron channels:
#define WRITE_FIELD(expr, varid)
#define APPLY_BIAS_CORR(pert)
#define N4
Number of 4.3 micron channels:
#define N8
Number of 8.1 micron channels:
#define N15_HIGH
Number of 15 micron high channels:
#define LOOP_ALL(ntrack)
Loop over all footprints.
double nu_sw[L1_NCHAN_SW]
Shortwave channel frequencies [cm^-1].
float rad_mw[L1_NTRACK][L1_NXTRACK][L1_NFOV][L1_NCHAN_MW]
Midwave radiance [W/(m^2 sr cm^-1)].
double nu_mw[L1_NCHAN_MW]
Midwave channel frequencies [cm^-1].
float rad_sw[L1_NTRACK][L1_NXTRACK][L1_NFOV][L1_NCHAN_SW]
Shortwave radiance [W/(m^2 sr cm^-1)].
double lon[L1_NTRACK][L1_NXTRACK][L1_NFOV]
Footprint longitude [deg].
float rad_lw[L1_NTRACK][L1_NXTRACK][L1_NFOV][L1_NCHAN_LW]
Longwave radiance [W/(m^2 sr cm^-1)].
double time[L1_NTRACK][L1_NXTRACK]
Time (seconds since 2000-01-01T00:00Z).
double nu_lw[L1_NCHAN_LW]
Longwave channel frequencies [cm^-1].
double lat[L1_NTRACK][L1_NXTRACK][L1_NFOV]
Footprint latitude [deg].
double dc[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Brightness temperature (cloud channel) [K].
double lat[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Latitude [deg].
int nfov
Number of field of views.
double pt[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Brightness temperature perturbation (4 or 15 micron) [K].
int ntrack
Number of along-track values.
double var[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Brightness temperature variance (4 or 15 micron) [K].
double time[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Time (seconds since 2000-01-01T00:00Z).
double bt[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Brightness temperature (4.3 or 15 micron) [K].
int nxtrack
Number of across-track values.
double lon[PERT_NTRACK][PERT_NXTRACK][PERT_NFOV]
Longitude [deg].