11 #define _XOPEN_SOURCE_EXTENDED
18 #undef _XOPEN_SOURCE_EXTENDED
20 #define SCAN_TIME_INTERVAL 1.4771
23 #define TRYMEM(file,line,memstat) { \
24 if (memstat == NULL) { \
26 "-E- %s line %d: Memory allocation error.\n", \
47 static const sdslist SDSLIST_REF[] = {
66 static const sdslist SDSLIST_GEO[] = {
81 static const char* geo_coeff[] = {
94 static sdslist SDSLIST_1KM[] = {
95 {
RSB_250, 1,
"EV_250_Aggr1km_RefSB"},
96 {
RSB_500, 1,
"EV_500_Aggr1km_RefSB"},
99 {
TEB_1KM, 1,
"EV_1KM_Emissive"},
102 static sdslist SDSLIST_HKM[] = {
103 {
RSB_250, 1,
"EV_250_Aggr500_RefSB"},
107 static sdslist SDSLIST_QKM[] = {
119 static const char* l1b_coeff[] = {
120 "reflectance_scales",
121 "reflectance_offsets",
132 char shortname[FILENAME_MAX];
176 static modis_file file_geo, file_1km, file_hkm, file_qkm;
182 int modpath_1km(
const char *oldpath,
const char* newchars,
char* newpath) {
190 strcpy(newpath, dirname(tmpbuf));
191 strcat(newpath,
"/");
203 "Input file %s does not follow the standard name convention;"
204 " can't find \"%s\" file.\n",
213 strcat(newpath, newchars);
214 strcat(newpath, ptr + strlen(newchars));
219 strcat(newpath,
"_");
220 strcat(newpath, newchars);
221 strcat(newpath, ptr + strlen(newchars) + 3);
233 char result[FILENAME_MAX];
245 if ((strcmp(
result,
"MYD021KM") == 0) ||
246 (strcmp(
result,
"MOD021KM") == 0)) {
248 file_content = SDSLIST_1KM;
249 }
else if ((strcmp(
result,
"MYD02HKM") == 0) ||
250 (strcmp(
result,
"MOD02HKM") == 0)) {
252 file_content = SDSLIST_HKM;
253 }
else if ((strcmp(
result,
"MYD02QKM") == 0) ||
254 (strcmp(
result,
"MOD02QKM") == 0)) {
256 file_content = SDSLIST_QKM;
259 "Input file %s has type %s; "
260 "does not contain MODIS calibrated radiances.\n",
268 while (file_content[l1bfile->
n_sds].
name)
270 TRYMEM(__FILE__, __LINE__,
271 (l1bfile->
sds = calloc(l1bfile->
n_sds, sizeof (sds_struct))));
272 for (
i = 0;
i < l1bfile->
n_sds;
i++)
301 "Error reading %s; please specify a valid Level 1B file.\n",
310 "Input file %s has %dm resolution; "
311 "please specify a 1km-resolution Level 1B file.\n",
317 switch (*max_resolution) {
325 fprintf(
stderr,
"File not found: %s\n", file_qkm.
file);
327 "Processing at %im resolution requires a QKM file to be "
328 "present in the same directory as the 1KM L1B file.\n",
340 fprintf(
stderr,
"File not found: %s\n", file_hkm.
file);
342 "Processing at %im resolution requires a HKM file to be "
343 "present in the same directory as the 1KM L1B file.\n",
350 *max_resolution = 1000;
358 fprintf(
stderr,
"Invalid resolution %i; ", *max_resolution);
359 fprintf(
stderr,
"must be 1000, 500 or 250 m.\n");
373 if (*max_resolution < 1000) {
380 if (*max_resolution < 500) {
389 : l1b[
i].sds.dimlen[0];
394 TRYMEM(__FILE__, __LINE__,
409 char result[FILENAME_MAX];
420 if ((strcmp(
result,
"MYD03") == 0) ||
421 (strcmp(
result,
"MOD03") == 0)) {
423 fprintf(
stderr,
"Input file %s has type %s; "
424 "does not contain MODIS geolocation.\n",
432 TRYMEM(__FILE__, __LINE__,
456 "Error reading %s; please specify a valid geolocation file.\n",
473 TRYMEM(__FILE__, __LINE__,
499 if (sds->id !=
FAIL) {
502 TRYMEM(__FILE__, __LINE__,
503 (
start = malloc(sds->ndims * sizeof (int32_t))));
504 TRYMEM(__FILE__, __LINE__,
505 (
edges = malloc(sds->ndims * sizeof (int32_t))));
506 for (
i = 0;
i < sds->ndims;
i++) {
518 if (sds->data ==
NULL)
519 TRYMEM(__FILE__, __LINE__,
520 (sds->data = malloc(
nvals * DFKNTsize(sds->ntype))));
536 #define MIN_BAD_SI 65500
537 #define MAX_ATTERR 0.017453293
538 #define LOOPI for (i = 0; i < nvals; i++)
541 static int32_t spixl = 0;
547 static float radoff[][10] = {
548 {-0.000972, 0.014200, 0.000022, 0.000238, -0.000003,
549 0.003760, 0.002337, 0.000084, 0.008848, 0.005050},
550 {-0.002300, 0.000600, 0.000236, -0.000280, -0.000003,
551 0.002798, 0.003496, 0.018035, 0.002942, 0.001787},
552 {-0.003833, 0.003657, 0.002118, 0.000798, -0.000003,
553 0.000208, 0.000399, 0.000553, 0.000258, 0.021128},
554 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
555 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
556 {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
557 {-0.000423, -0.000242, -0.000330, -0.000065, -0.000001,
558 -0.000006, 0.000064, 0.000398, 0.000362, 0.000322},
559 {-0.000433, -0.000246, -0.000222, -0.000148, -0.000001,
560 0.000068, 0.000221, 0.000221, 0.000437, 0.000303}
562 static float mfact[] = {0.0, 0.0, 0.0005, 0.0, 0.0, 0.0, 0.0028, 0.00278};
576 static const bandinfo BANDLIST[] = {
586 {
RSB_1KM, 5, 230, 667,
"13lo"},
587 {
RSB_1KM, 7, 250, 678,
"14lo"},
590 {
RSB_1KM, 10, 280, 869,
"16"},
595 {
TEB_1KM, 0, 330, 3750,
"20"},
596 {
TEB_1KM, 2, 350, 3959,
"22"},
597 {
TEB_1KM, 3, 360, 4050,
"23"},
598 {
TEB_1KM, 6, 390, 6715,
"27"},
599 {
TEB_1KM, 7, 400, 7325,
"28"},
600 {
TEB_1KM, 8, 410, 8550,
"29"},
601 {
TEB_1KM, 10, 430, 11000,
"31"},
602 {
TEB_1KM, 11, 440, 12000,
"32"},
617 char datetime[32] =
"";
630 for (
i = 0;
i < file_1km.
n_sds;
i++) {
631 if (strcmp(file_1km.
sds[
i].name,
"EV_250_Aggr1km_RefSB") == 0) {
632 if (SDfindattr(file_1km.
sds[
i].id,
"Rescaled Ocean R") !=
FAIL) {
634 "This L1B file contains only the ocean band subset.\n"
635 "Processing is no longer supported; exiting.\n");
655 printf(
"Processing at %d meter resolution.\n",
resolution);
656 printf(
" 1000-meter file: %s\n", file_1km.
file);
658 printf(
" 500-meter file: %s\n", file_hkm.
file);
660 printf(
" 250-meter file: %s\n", file_qkm.
file);
670 if (
read_att(file_geo.
id,
"CoreMetadata.0", geometa)) {
672 "-E- %s line %d: Error reading CoreMetadata.0 from %s.\n",
673 __FILE__, __LINE__, file_geo.
file);
687 strcat(datetime,
"T");
695 strcat(datetime,
"T");
701 if (
read_att(file_geo.
id,
"Cumulated gflags", gflags))
702 fprintf(
stderr,
"-W- %s line %d: Error reading gflags from %s.\n",
703 __FILE__, __LINE__, file_geo.
file);
705 l1file->terrain_corrected = (((int32_t*) gflags)[5] == 0);
715 if (
read_att(file_1km.
id,
"Extract Pixel Count", &intval) == 0
717 int32_t sline, nline, npixl;
719 read_att(file_1km.
id,
"Extract Pixel Offset", &intval);
721 read_att(file_1km.
id,
"Extract Line Offset", &intval);
726 "File was generated from L1A extract of size %d x %d\n",
728 fprintf(
stdout,
" Pixels %d - %d\n", spixl + 1, spixl + npixl);
729 fprintf(
stdout,
" Lines %d - %d\n", sline + 1, sline + nline);
777 scan.nbands =
sizeof (BANDLIST) /
sizeof (BANDLIST[0]);
787 TRYMEM(__FILE__, __LINE__,
804 char file[FILENAME_MAX] =
"";
808 int32_t iband, isf, nsf, irad, nrad;
812 double radiance,
SI, radiance2, SI2, rad_corr[4];
815 if ((dataroot = getenv(
"OCDATAROOT")) ==
NULL) {
816 printf(
"OCDATAROOT environment variable is not defined.\n");
823 printf(
"\nLoading subframe correction tables:\n");
824 for (iband = 0; iband <
scan.nbands; iband++) {
838 atts = l1b[isds].
sds.atts;
847 sprintf(
file,
"%s/%s/%s/cal/subframecor_%s_%d.dat",
854 printf(
" %s\n",
file);
855 if ((fp = fopen(
file,
"r")) ==
NULL) {
857 "-E- %s line %d: unable to open %s for reading\n",
858 __FILE__, __LINE__,
file);
863 while (fgets(
line, 80, fp))
864 if (strncmp(
line,
"Number of radiance levels", 25) == 0) {
865 sscanf(
line,
"Number of radiance levels: %d", &nrad);
866 TRYMEM(__FILE__, __LINE__,
867 (sfcorr[iband].SI_val =
868 malloc(nrad *
sizeof (*sfcorr[iband].SI_val))));
869 TRYMEM(__FILE__, __LINE__,
870 (sfcorr[iband].corr =
871 malloc(nrad * 4 *
sizeof (*sfcorr[iband].corr))));
874 while (fgets(
line, 80, fp))
875 if (strncmp(
line,
"/end_header", 11) == 0)
879 for (irad = 0; irad < nrad; irad++) {
882 "-E- %s line %d: File %s contains only %d data records\n",
883 __FILE__, __LINE__,
file, irad);
886 sscanf(
line,
"%lf %lf %lf %lf %lf", &radiance,
887 &rad_corr[0], &rad_corr[1], &rad_corr[2], &rad_corr[3]);
896 for (isf = 0; isf < 4; isf++) {
897 radiance2 = radiance / rad_corr[isf];
899 sfcorr[iband].
corr[4 * irad + isf] = SI2 /
SI;
906 sfcorr[iband].
nrad = nrad;
907 sfcorr[iband].
nsf = nsf;
912 printf(
"Subframe destriping corrections enabled.\n\n");
923 int32_t idet, iframe, isf, ip;
930 if (sfcorr ==
NULL) {
931 TRYMEM(__FILE__, __LINE__,
932 (sfcorr = malloc(
scan.nbands * sizeof (*sfcorr))));
938 if ((lut.
nsf > 1) && (lut.
nrad > 0) && (lut.
nsf == mds.
nsf)) {
939 for (idet = 0; idet < mds.
ndets; idet++)
940 for (iframe = 0; iframe < mds.
nframes; iframe++)
941 for (isf = 0; isf < mds.
nsf; isf++) {
942 ip = (idet * mds.
nframes + iframe) * mds.
nsf + isf;
949 for (
i = 0;
i < lut.
nrad - 1;
i++) {
955 if (
i == 0 ||
i == (lut.
nrad - 1))
956 y = lut.
corr[4 *
i + isf];
962 double y0 = lut.
corr[4 * (
i - 1) + isf];
963 double y1 = lut.
corr[4 *
i + isf];
964 y = y0 + (
x - x0) * (y1 - y0) / (x1 - x0);
984 int32_t isds, iband, idet, i0, x0, x1;
988 if (
read_att(file_1km.
id,
"Dead Detector List", dead)) {
990 "-E- %s line %d: Error reading \"Dead Detector List\" from %s.\n",
991 __FILE__, __LINE__, file_1km.
file);
996 for (iband = 0; iband <
scan.nbands; iband++) {
1007 fill[iband].
ndets = ndets;
1010 TRYMEM(__FILE__, __LINE__,
1011 (fill[iband].prev = malloc(ndets *
sizeof (*fill->
prev))));
1012 TRYMEM(__FILE__, __LINE__,
1013 (fill[iband].next = malloc(ndets *
sizeof (*fill->
next))));
1026 for (idet = 0; idet < ndets; idet++) {
1028 while ((x0 > -1) && dead[i0 + x0]) x0--;
1029 fill[iband].
prev[idet] = x0;
1031 while ((x1 < ndets) && dead[i0 + x1]) x1++;
1032 fill[iband].
next[idet] = x1;
1040 int32_t idet, ndets, ipix,
npix;
1043 int32_t *prev, *next;
1052 TRYMEM(__FILE__, __LINE__, (fill = malloc(
scan.nbands * sizeof (*fill))));
1057 ndets = fill[iband].
ndets;
1058 if (ndets == mds.
ndets) {
1060 prev = fill[iband].
prev;
1061 next = fill[iband].
next;
1063 nbytes =
npix *
sizeof (*data);
1066 for (idet = 0; idet < ndets; idet++) {
1067 if (prev[idet] != next[idet]) {
1070 if ((prev[idet] > -1) && (next[idet] < ndets)) {
1071 dx = next[idet] - prev[idet];
1073 for (ipix = 0; ipix <
npix; ipix++) {
1074 x = idet *
npix + ipix;
1075 x0 = prev[idet] *
npix + ipix;
1076 x1 = next[idet] *
npix + ipix;
1083 data[
x] = y0 + (idet - prev[idet]) * (dy / dx);
1095 else if ((prev[idet] == -1) && (next[idet] < ndets))
1099 else if ((prev[idet] > -1) && (next[idet] == ndets))
1112 return (1 - dy) * (
val[0] * (1 - dx) +
val[1] * dx)
1113 + dy * (
val[2] * (1 - dx) +
val[3] * dx);
1117 int32_t
i, ngood = 0;
1123 for (
i = 0;
i < 4;
i++) {
1125 sum_val = sum_val +
val[
i];
1128 if (
val[
i] > max_val)
1144 result = sum_val / ngood;
1152 double min_val, max_val;
1155 min_val = max_val =
val[0];
1156 for (
i = 1;
i < 4;
i++) {
1157 if (
val[
i] < min_val)
1159 else if (
val[
i] > max_val)
1162 if (max_val > 180.0 + min_val) {
1163 for (
i = 0;
i < 4;
i++) {
1174 const int32_t sdsband,
1175 const int32_t newres,
1179 int32_t ny =
s.ndets;
1180 int32_t nx =
s.nframes *
s.nsf;
1181 int32_t
nvals = ny * nx;
1182 int32_t oldres =
s.resolution;
1184 int32_t nxnew, nynew;
1185 int32_t ixnew, iynew;
1187 int32_t x0, y0, x1, y1;
1192 double factor, xoffset, yoffset;
1195 int32_t sdsoffset =
nvals * sdsband;
1199 alloc_old = (olddata ==
NULL);
1201 TRYMEM(__FILE__, __LINE__, (olddata = malloc(
nvals *
sizeof (*olddata))));
1203 switch (
s.sds.ntype) {
1205 LOOPI olddata[
i] = (
double) ((
float*)
s.sds.data)[sdsoffset +
i];
1208 LOOPI olddata[
i] = (
double) ((int16_t*)
s.sds.data)[sdsoffset +
i];
1211 LOOPI olddata[
i] = (
double) ((uint16_t*)
s.sds.data)[sdsoffset +
i];
1215 "-E- %s line %d: Cannot interpolate type code: %d\n",
1216 __FILE__, __LINE__,
s.sds.ntype);
1223 if (strncmp(
s.sds.name,
"EV_", 3) == 0)
1225 else if (strcmp(
s.sds.name,
"Longitude") == 0)
1231 factor = (
double) newres / (
double) oldres;
1233 yoffset = 0.5 * (1.0 - factor);
1237 nxnew = nx * oldres / newres;
1238 nynew = ny * oldres / newres;
1241 for (iynew = 0; iynew < nynew; iynew++) {
1242 fy = factor * iynew - yoffset;
1243 y0 =
MIN(
MAX((int32_t) floor(fy), 0), ny - maxi);
1244 y1 =
MIN(y0 + 1, ny - 1);
1247 for (ixnew = 0; ixnew < nxnew; ixnew++) {
1248 fx = factor * ixnew - xoffset;
1249 x0 =
MIN(
MAX((int32_t) floor(fx), 0), nx - maxi);
1250 x1 =
MIN(x0 + 1, nx - 1);
1254 val[0] = olddata[nx * y0 + x0];
1255 val[1] = olddata[nx * y0 + x1];
1256 val[2] = olddata[nx * y1 + x0];
1257 val[3] = olddata[nx * y1 + x1];
1279 int32_t isds, iband;
1280 int32_t
i, i1, i2, nold;
1281 static int32_t
nvals = 0;
1282 double *olddata =
NULL;
1283 double *newdata =
NULL;
1292 TRYMEM(__FILE__, __LINE__, (newdata = malloc(
nvals *
sizeof (*newdata))));
1338 for (iband = 0; iband <
scan.nbands; iband++) {
1340 nold =
s.ndets *
s.nframes *
s.nsf;
1345 TRYMEM(__FILE__, __LINE__, (olddata = malloc(nold *
sizeof (*olddata))));
1346 for (
i = 0;
i < nold;
i++)
1347 olddata[
i] = (
double) ((uint16_t*)
s.sds.data)[i1 +
i];
1359 BANDLIST[iband].bandindex,
1374 for (
i = 0;
i < 3;
i++) {
1390 static double lastTAIsec = -1;
1391 int16_t badatt, badmside;
1392 double TAIsec, dsec;
1398 badmside = (
l1rec->mside < 0);
1409 for (
i = 0;
i <
l1rec->npix;
i++) {
1411 l1rec->navfail[
i] = badmside;
1412 l1rec->navwarn[
i] = badatt;
1416 TAIsec =
scan.taisec;
1418 fprintf(
stderr,
"-W- %s: Bad time for scan %d; ", __FILE__,
iscan);
1420 fprintf(
stderr,
"using granule start time.\n");
1423 fprintf(
stderr,
"extrapolating from last good scan.\n");
1428 lastTAIsec = TAIsec;
1432 int32_t
msec = (int32_t) (dsec * 1000.0);
1433 int32_t yr = (int32_t)
year;
1434 int32_t dy = (int32_t)
day;
1451 static int32_t prev_scan = -1;
1452 int32_t iband,
iscan, idet, ndets;
1454 size_t detoffset, dataptr;
1456 size_t irsb, iteb, ical;
1463 idet =
line % ndets;
1466 if (
iscan != prev_scan) {
1474 l1rec->detnum = (int32_t) idet;
1480 detoffset = idet *
scan.npix + spixl;
1484 memcpy(
l1rec->lon, &
scan.lon[detoffset], nbytes);
1485 memcpy(
l1rec->lat, &
scan.lat[detoffset], nbytes);
1486 memcpy(
l1rec->height, &
scan.hgt[detoffset], nbytes);
1487 memcpy(
l1rec->solz, &
scan.solz[detoffset], nbytes);
1488 memcpy(
l1rec->sola, &
scan.sola[detoffset], nbytes);
1489 memcpy(
l1rec->senz, &
scan.senz[detoffset], nbytes);
1490 memcpy(
l1rec->sena, &
scan.sena[detoffset], nbytes);
1502 for (iband = 0; iband <
scan.nbands; iband++) {
1509 dataptr = iband *
scan.nvals + detoffset;
1512 if (BANDLIST[iband].sdsindex ==
TEB_1KM) {
1516 for (ip = 0; ip <
l1rec->npix; ip++) {
1520 SI_val =
scan.allbands[dataptr + ip];
1529 value *= (1.0 - radoff[iteb][idet / (ndets / 10)]);
1530 if (
l1rec->mside == 1)
1531 value *= (1.0 + mfact[iteb]);
1544 ipb = ip *
l1rec->l1file->nbandsir + iteb;
1552 else if (BANDLIST[iband].sdsindex ==
CIR_1KM) {
1556 for (ip = 0; ip <
l1rec->npix; ip++) {
1560 SI_val =
scan.allbands[dataptr + ip];
1579 for (ip = 0; ip <
l1rec->npix; ip++) {
1583 if (SOLZNIGHT < l1rec->
solz[ip])
1587 SI_val =
scan.allbands[dataptr + ip];
1595 switch ((int32_t) SI_val) {
1597 l1rec->navfail[ip] = 1;
1603 l1rec->hilt[ip] = 1;
1610 ipb = ip *
l1rec->l1file->nbands + irsb;
1644 for (
i = 0;
i < file_geo.
n_sds;
i++)
1649 for (
i = 0;
i < file_1km.
n_sds;
i++)
1654 for (
i = 0;
i < file_hkm.
n_sds;
i++)
1659 for (
i = 0;
i < file_qkm.
n_sds;
i++)
1665 if (file_geo.
id) SDend(file_geo.
id);
1666 if (file_1km.
id) SDend(file_1km.
id);
1667 if (file_hkm.
id) SDend(file_hkm.
id);
1668 if (file_qkm.
id) SDend(file_qkm.
id);
1669 file_geo.
id = file_1km.
id = file_hkm.
id = file_qkm.
id = 0;
1679 static float *lonscan =
NULL;
1680 static float *latscan =
NULL;
1684 int32_t
nvals = ndets * npixl;
1687 double *newdata =
NULL;
1688 static int32_t prev_scan = -1;
1690 size_t detoffset, nbytes;
1693 if (lonscan ==
NULL) {
1694 TRYMEM(__FILE__, __LINE__, (lonscan = malloc(
nvals *
sizeof (*lonscan))));
1695 TRYMEM(__FILE__, __LINE__, (latscan = malloc(
nvals *
sizeof (*latscan))));
1700 idet =
line % ndets;
1703 if (
iscan != prev_scan) {
1718 memcpy(lonscan, geo[
GEO_LON].sds.data,
nvals * sizeof (*lonscan));
1719 memcpy(latscan, geo[
GEO_LAT].sds.data,
nvals * sizeof (*latscan));
1723 TRYMEM(__FILE__, __LINE__,
1724 (newdata = malloc(
nvals *
sizeof (*newdata))));
1735 detoffset = idet * npixl + spixl;
1737 memcpy(
l1rec->lon, &lonscan[detoffset], nbytes);
1738 memcpy(
l1rec->lat, &latscan[detoffset], nbytes);