OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
sstref.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <unistd.h>
3 
4 /* ============================================================================ */
5 /* module sstref.c - retrieve sst reference temperature from ancillary file */
6 /* */
7 /* Written By: B. Franz, NASA/SIMBIOS, August 2003. */
8 /* */
9 /* ============================================================================ */
10 
11 /*
12  * hardcoded the minatsrcnt value to 1 so I could eliminate the input parameter.
13  * Only used for get_atsr anyway, and thus only valid for 2006-2009...
14  */
15 #include "l12_proto.h"
16 #include <netcdf.h>
17 #include "l12_parms.h"
18 #include "l1_aci_hdf.h"
19 #define PATHCLIM 1
20 #define OISSTBIN 2
21 #define OISSTV2D 3
22 #define AMSRE3DAY 4
23 #define AMSREDAY 5
24 #define ATSR 6
25 #define NTEV2 7
26 #define AMSRE3DN 8
27 #define ATSRDAY 9
28 #define WINDSAT3DAY 10
29 #define WINDSATDAY 11
30 #define WINDSAT3DN 12
31 #define CMC 13
32 
33 #define CtoK 273.15 /* conversion between degree C and Kelvin*/
34 static float sstbad = BAD_FLT;
35 static int32_t format = -1;
36 
37 static int MiddleOfMonth[2][12] = {
38  {15, 45, 74, 105, 135, 166, 196, 227, 258, 288, 319, 349},
39  {15, 45, 75, 106, 136, 167, 197, 228, 259, 289, 320, 350}};
40 
41 
42 /* ----------------------------------------------------------------------------------- */
43 /* get_oisstv2d() - read and interpolate Reynolds 0.25-deg daily V2 netcdf OI files */
44 /* */
45 /* B. Franz, SAIC, July 2008. */
46 /* ----------------------------------------------------------------------------------- */
47 
48 #define OI4NX 1440
49 #define OI4NY 720
50 
51 float get_oisstv2d(char *sstfile, float lon, float lat) {
52  static int firstCall = 1;
53  static int nx = OI4NX;
54  static int ny = OI4NY;
55  static float dx = 360.0 / OI4NX;
56  static float dy = 180.0 / OI4NY;
57 
58  typedef float sstref_t[OI4NX + 2];
59  static sstref_t* sstref;
60  //static float sstref[OI4NY+2][OI4NX+2];
61 
62  float sst = sstbad;
63  int i, j, ii;
64  int ntmp;
65  float xx, yy;
66  float t, u;
67  float reftmp[2][2];
68  float ftmp;
69 
70  if (firstCall) {
71  sstref = (sstref_t*) malloc((OI4NY + 2) * sizeof (sstref_t));
72 
73  typedef int16 ssttmp_t[OI4NX];
74  ssttmp_t *ssttmp;
75  ssttmp = (ssttmp_t*) malloc(OI4NY * sizeof (ssttmp_t));
76 
77  char name [H4_MAX_NC_NAME] = "";
78  char sdsname[H4_MAX_NC_NAME] = "";
79  int ncid, ndims, nvars, ngatts, unlimdimid;
80  int32 sd_id;
81  int32 sds_id;
82  int32 rank;
83  int32 nt;
84  int32 dims[H4_MAX_VAR_DIMS];
85  int32 nattrs;
86  int32 start[4] = {0, 0, 0, 0};
87  int32 status;
88  float slope;
89  float offset;
90 
91  firstCall = 0;
92 
93  printf("Loading Daily V2 0.25-deg OI Reynolds SST reference from %s\n", sstfile);
94  printf("\n");
95 
96  /* Open the file */
97  strcpy(sdsname, "sst");
98 
99  /* Try HDF first... */
100 
101  // SDstart seg faults on the mac, so need to protect the
102  // call with Hishdf()
103  if (Hishdf(sstfile))
104  sd_id = SDstart(sstfile, DFACC_RDONLY);
105  else
106  sd_id = FAIL;
107 
108  if (sd_id != FAIL) {
109 
110  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
111  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
112  status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) & ssttmp[0][0]);
113  if (status != 0) {
114  fprintf(stderr, "-E- %s Line %d: Error reading SDS %s from %s.\n",
115  __FILE__, __LINE__, sdsname, sstfile);
116  exit(1);
117  }
118  if (getHDFattr(sd_id, "scale_factor", sdsname, (VOIDP) & slope) != 0) {
119  fprintf(stderr, "-E- %s line %d: error reading scale factor.\n",
120  __FILE__, __LINE__);
121  exit(1);
122  }
123  if (getHDFattr(sd_id, "add_offset", sdsname, (VOIDP) & offset) != 0) {
124  fprintf(stderr, "-E- %s line %d: error reading scale offset.\n",
125  __FILE__, __LINE__);
126  exit(1);
127  }
128  status = SDendaccess(sds_id);
129  status = SDend(sd_id);
130  } else {
131 
132  /* try netCDF */
133  if (nc_open(sstfile, NC_NOWRITE, &ncid) == NC_NOERR) {
134 
135  status = nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid);
136  status = nc_inq_varid(ncid, sdsname, &sds_id);
137 
138  /* Read the data. */
139  if (nc_get_var(ncid, sds_id, &ssttmp[0][0]) != NC_NOERR) {
140  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
141  __FILE__, __LINE__, sdsname, sstfile);
142  exit(1);
143  }
144 
145  if (nc_get_att_float(ncid, sds_id, "scale_factor", &slope) != NC_NOERR) {
146  fprintf(stderr, "-E- %s line %d: error reading scale factor.\n",
147  __FILE__, __LINE__);
148  exit(1);
149  }
150 
151  if (nc_get_att_float(ncid, sds_id, "add_offset", &offset) != NC_NOERR) {
152  fprintf(stderr, "-E- %s line %d: error reading scale offset.\n",
153  __FILE__, __LINE__);
154  exit(1);
155  }
156  /* Close the file */
157  if (nc_close(ncid) != NC_NOERR) {
158  fprintf(stderr, "-E- %s line %d: error closing %s.\n",
159  __FILE__, __LINE__, sstfile);
160  exit(1);
161  }
162 
163  } else {
164  fprintf(stderr, "-E- %s line %d: error reading %s.\n",
165  __FILE__, __LINE__, sstfile);
166  exit(1);
167  }
168  }
169 
170  /* rotate 180-deg and add wrapping border to simplify interpolation */
171  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
172 
173  for (j = 0; j < ny; j++) {
174  for (i = 0; i < nx; i++) {
175  ii = (i < nx / 2) ? i + nx / 2 : i - nx / 2;
176  if (ssttmp[j][i] > -999)
177  sstref[j + 1][ii + 1] = ssttmp[j][i] * slope + offset;
178  else
179  sstref[j + 1][ii + 1] = sstbad;
180  }
181  sstref[j + 1][0] = sstref[j + 1][nx];
182  sstref[j + 1][nx + 1] = sstref[j + 1][1];
183  }
184  for (i = 0; i < nx + 2; i++) {
185  sstref[0] [i] = sstref[1][i];
186  sstref[ny + 1][i] = sstref[ny][i];
187  }
188 
189  free(ssttmp);
190  }
191 
192 
193  /* locate LL position within reference grid */
194  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OI4NX + 1), 0);
195  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OI4NY + 1), 0);
196 
197  /* compute longitude and latitude of that grid element */
198  xx = i * dx - 180.0 - dx / 2;
199  yy = j * dy - 90.0 - dy / 2;
200 
201  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
202  t = (lon - xx) / dx;
203  u = (lat - yy) / dy;
204 
205  ftmp = 0.0;
206  ntmp = 0;
207  if (sstref[j ][i ] > sstbad + 1) {
208  ftmp += sstref[j ][i ];
209  ntmp++;
210  }
211  if (sstref[j ][i + 1] > sstbad + 1) {
212  ftmp += sstref[j ][i + 1];
213  ntmp++;
214  }
215  if (sstref[j + 1][i + 1] > sstbad + 1) {
216  ftmp += sstref[j + 1][i + 1];
217  ntmp++;
218  }
219  if (sstref[j + 1][i ] > sstbad + 1) {
220  ftmp += sstref[j + 1][i ];
221  ntmp++;
222  }
223  if (ntmp > 0) {
224  ftmp /= ntmp;
225  reftmp[0][0] = (sstref[j ][i ] > sstbad + 1 ? sstref[j ][i ] : ftmp);
226  reftmp[0][1] = (sstref[j ][i + 1] > sstbad + 1 ? sstref[j ][i + 1] : ftmp);
227  reftmp[1][1] = (sstref[j + 1][i + 1] > sstbad + 1 ? sstref[j + 1][i + 1] : ftmp);
228  reftmp[1][0] = (sstref[j + 1][i ] > sstbad + 1 ? sstref[j + 1][i ] : ftmp);
229 
230  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
231 
232  } else
233  sst = sstbad;
234 
235  return (sst);
236 }
237 
238 /* ----------------------------------------------------------------------------------- */
239 /* get_cmcsst() - read and interpolate CMC SST netcdf files v2 and v3 */
240 /* ----------------------------------------------------------------------------------- */
241 float get_cmcsst(char *sstfile, float lon, float lat) {
242  static int firstCall = 1;
243  static size_t nx = 0;
244  static size_t ny = 0;
245  static float dx = 0.1;
246  static float dy = 0.1;
247 
248  static float **sstref;
249  static float *latitudes;
250  static float *longitudes;
251 
252  float sst = sstbad;
253  int i, j;
254  int ntmp;
255  float xx, yy;
256  float t, u;
257  float reftmp[2][2];
258  float ftmp;
259 
260  if (firstCall) {
261  short **ssttmp;
262 
263  char sdsname[H4_MAX_NC_NAME] = "";
264  int32_t ncid, ndims, nvars, ngatts, unlimdimid;
265  int32_t latDimID, lonDimID;
266  int32 sds_id;
267  float slope;
268  float offset;
269 
270  firstCall = 0;
271 
272  printf("Loading Daily CMC SST reference from %s\n", sstfile);
273  printf("\n");
274 
275  /* Open the file */
276  if (nc_open(sstfile, NC_NOWRITE, &ncid) == NC_NOERR) {
277  nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid);
278 
279  strcpy(sdsname, "analysed_sst");
280  nc_inq_varid(ncid, sdsname, &sds_id);
281 
282  if (nc_inq_dimid(ncid, "lat", &latDimID) != NC_NOERR) {
283  printf("Whoops! something is wrong reading the CMC SST reference file: %s\n", sstfile);
284  exit(EXIT_FAILURE);
285  }
286  nc_inq_dimlen(ncid, latDimID, &ny);
287  dy = 180.0 / ny;
288  if (nc_inq_dimid(ncid, "lon", &lonDimID) != NC_NOERR) {
289  printf("Whoops! something is wrong reading the CMC SST reference file: %s\n", sstfile);
290  exit(EXIT_FAILURE);
291  }
292  nc_inq_dimlen(ncid, lonDimID, &nx);
293  dx = 360.0 / nx;
294 
295  /* size the arrays */
296  ssttmp = allocate2d_short(ny, nx);
297  sstref = allocate2d_float(ny+2, nx+2);
298 
299  latitudes = (float *) calloc(ny,sizeof(float));
300  longitudes = (float *) calloc(nx,sizeof(float));
301 
302  /* Read the data. */
303  if (nc_get_var_short(ncid, sds_id, &ssttmp[0][0]) != NC_NOERR) {
304  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
305  __FILE__, __LINE__, sdsname, sstfile);
306  exit(1);
307  }
308 
309  if (nc_get_att_float(ncid, sds_id, "scale_factor", &slope) != NC_NOERR) {
310  fprintf(stderr, "-E- %s line %d: error reading scale factor.\n",
311  __FILE__, __LINE__);
312  exit(1);
313  }
314 
315  if (nc_get_att_float(ncid, sds_id, "add_offset", &offset) != NC_NOERR) {
316  fprintf(stderr, "-E- %s line %d: error reading scale offset.\n",
317  __FILE__, __LINE__);
318  exit(1);
319  }
320  strcpy(sdsname, "lat");
321  nc_inq_varid(ncid, sdsname, &sds_id);
322  if (nc_get_var_float(ncid, sds_id, latitudes) != NC_NOERR) {
323  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
324  __FILE__, __LINE__, sdsname, sstfile);
325  exit(1);
326  }
327  strcpy(sdsname, "lon");
328  nc_inq_varid(ncid, sdsname, &sds_id);
329  if (nc_get_var_float(ncid, sds_id, longitudes) != NC_NOERR) {
330  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
331  __FILE__, __LINE__, sdsname, sstfile);
332  exit(1);
333  }
334  /* Close the file */
335  if (nc_close(ncid) != NC_NOERR) {
336  fprintf(stderr, "-E- %s line %d: error closing %s.\n",
337  __FILE__, __LINE__, sstfile);
338  exit(1);
339  }
340  } else {
341  fprintf(stderr, "-E- %s line %d: error opening %s.\n",
342  __FILE__, __LINE__, sstfile);
343  exit(1);
344  }
345 
346  for (j = ny-1; j >= 0; j--) {
347  for (i = 0; i < nx; i++) {
348  if (ssttmp[j][i] > -999)
349  sstref[j + 1][i + 1] = ssttmp[j][i] * slope + offset;
350  else
351  sstref[j + 1][i + 1] = sstbad;
352  }
353  sstref[j + 1][0] = sstref[j + 1][nx];
354  sstref[j + 1][nx + 1] = sstref[j + 1][1];
355  }
356  for (i = 0; i < nx + 2; i++) {
357  sstref[0] [i] = sstref[1][i];
358  sstref[ny + 1][i] = sstref[ny][i];
359  }
360 
361  free2d_short(ssttmp);
362  }
363 
364  /* locate position within reference grid */
365  float sdiff = 999.0;
366  int lonidx = 0;
367  for (i=0; i < nx; i++){
368  float cdiff = fabs(longitudes[i] - lon);
369  if (cdiff > sdiff)
370  break;
371  if (cdiff < sdiff){
372  sdiff = cdiff;
373  lonidx = i;
374  }
375  }
376  sdiff = 999.0;
377  int latidx = 0;
378  for (i=0; i < ny; i++){
379  float cdiff = fabs(latitudes[i] - lat);
380  if (cdiff > sdiff)
381  break;
382  if (cdiff < sdiff){
383  sdiff = cdiff;
384  latidx = i;
385  }
386  }
387 
388  /* compute longitude and latitude of that grid element */
389  xx = longitudes[lonidx];
390  yy = latitudes[latidx];
391 
392  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
393  t = (lon - xx) / dx;
394  u = (lat - yy) / dy;
395 
396  ftmp = 0.0;
397  ntmp = 0;
398  if (sstref[latidx ][lonidx ] > sstbad + 1) {
399  ftmp += sstref[latidx ][lonidx ];
400  ntmp++;
401  }
402  if (sstref[latidx][lonidx + 1] > sstbad + 1) {
403  ftmp += sstref[latidx ][lonidx + 1];
404  ntmp++;
405  }
406  if (sstref[latidx + 1][lonidx + 1] > sstbad + 1) {
407  ftmp += sstref[latidx + 1][lonidx + 1];
408  ntmp++;
409  }
410  if (sstref[latidx + 1][lonidx ] > sstbad + 1) {
411  ftmp += sstref[latidx + 1][lonidx ];
412  ntmp++;
413  }
414  if (ntmp > 0) {
415  ftmp /= ntmp;
416  reftmp[0][0] = (sstref[latidx ][lonidx ] > sstbad + 1 ? sstref[latidx ][lonidx ] : ftmp);
417  reftmp[0][1] = (sstref[latidx ][lonidx + 1] > sstbad + 1 ? sstref[latidx ][lonidx + 1] : ftmp);
418  reftmp[1][1] = (sstref[latidx + 1][lonidx + 1] > sstbad + 1 ? sstref[latidx + 1][lonidx + 1] : ftmp);
419  reftmp[1][0] = (sstref[latidx + 1][lonidx ] > sstbad + 1 ? sstref[latidx + 1][lonidx ] : ftmp);
420 
421  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0] - CtoK;
422 
423  } else
424  sst = sstbad;
425 
426  return (sst);
427 }
428 
429 
430 /* ----------------------------------------------------------------------------------- */
431 /* get_oisst() - read and interpolate flat binary Reynolds OI SST */
432 /* */
433 /* The files were written in IEEE binary (big-endian). Each file contains four FORTRAN */
434 /* records described as follows: */
435 /* */
436 /* rec 1: date and version number (8 4-byte integer words) */
437 /* rec 2: gridded sst values in degC (360*180 4-byte real words) */
438 /* rec 3: normalized error variance (360*180 4-byte real words) */
439 /* rec 4: gridded ice concentration (360*180 1-byte integer words) */
440 /* */
441 /* B. Franz, SAIC, May 2004. */
442 /* ----------------------------------------------------------------------------------- */
443 
444 #define OINX 360
445 #define OINY 180
446 
447 float get_oisst(char *sstfile, float lon, float lat) {
448  static int firstCall = 1;
449  static int nx = OINX;
450  static int ny = OINY;
451  static float dx = 360.0 / OINX;
452  static float dy = 180.0 / OINY;
453 
454  typedef float sstref_t[OINX + 2];
455  static sstref_t* sstref;
456  //static float sstref[OINY+2][OINX+2];
457 
458  float sst = BAD_FLT;
459  int i, j, ii;
460  float xx, yy;
461  float t, u;
462 
463  if (firstCall) {
464  sstref = (sstref_t*) malloc((OINY + 2) * sizeof (sstref_t));
465 
466  typedef float ssttmp_t[OINX];
467  ssttmp_t *ssttmp = (ssttmp_t*) malloc(OINY * sizeof (ssttmp_t));
468  //float ssttmp[OINY][OINX];
469 
470  FILE *fp = NULL;
471 
472  int32_t syear, smon, sday;
473  int32_t eyear, emon, eday;
474  int32_t ndays, version;
475 
476  firstCall = 0;
477 
478  if ((fp = fopen(sstfile, "r")) == NULL) {
479  printf("Error opening SST reference file %s for reading.\n", sstfile);
480  exit(1);
481  }
482 
483  if (fseek(fp, 4, SEEK_SET) < 0) {
484  printf("Error reading SST reference file %s.\n", sstfile);
485  exit(1);
486  }
487  if (fread(&syear, sizeof (int32_t), 1, fp) != 1) {
488  printf("Error reading SST reference file %s.\n", sstfile);
489  exit(1);
490  }
491  fread(&smon, sizeof (int32_t), 1, fp);
492  fread(&sday, sizeof (int32_t), 1, fp);
493  fread(&eyear, sizeof (int32_t), 1, fp);
494  fread(&emon, sizeof (int32_t), 1, fp);
495  fread(&eday, sizeof (int32_t), 1, fp);
496  fread(&ndays, sizeof (int32_t), 1, fp);
497  fread(&version, sizeof (int32_t), 1, fp);
498  fseek(fp, 4, SEEK_CUR);
499 
500  if (endianess() == 1) {
501  swapc_bytes((char *) &syear, sizeof (int32_t), 1);
502  swapc_bytes((char *) &smon, sizeof (int32_t), 1);
503  swapc_bytes((char *) &sday, sizeof (int32_t), 1);
504  swapc_bytes((char *) &eyear, sizeof (int32_t), 1);
505  swapc_bytes((char *) &emon, sizeof (int32_t), 1);
506  swapc_bytes((char *) &eday, sizeof (int32_t), 1);
507  swapc_bytes((char *) &ndays, sizeof (int32_t), 1);
508  swapc_bytes((char *) &version, sizeof (int32_t), 1);
509  }
510 
511  printf("Loading Weekly 1-degree OI Reynolds SST reference from %s\n", sstfile);
512  printf(" file start date (y/m/d): %d / %d / %d\n", syear, smon, sday);
513  printf(" file end date (y/m/d): %d / %d / %d\n", eyear, emon, eday);
514  printf(" days composited: %d\n", ndays);
515  printf(" file version: %d\n", version);
516  printf("\n");
517 
518  if (fseek(fp, 4, SEEK_CUR) < 0) {
519  printf("Error reading SST reference file %s.\n", sstfile);
520  exit(1);
521  }
522  if (fread(&ssttmp[0][0], sizeof (float), nx * ny, fp) != nx * ny) {
523  printf("Error reading SST reference file %s.\n", sstfile);
524  exit(1);
525  }
526  fclose(fp);
527 
528  if (endianess() == 1)
529  swapc_bytes((char *) &ssttmp[0][0], 4, nx * ny);
530 
531  /* rotate 180-deg and add wrapping border to simplify interpolation */
532  /* new grid is -180.5,180.5 in i=0,361 and -90.5,90.5 in j=0,181 */
533 
534  for (j = 0; j < ny; j++) {
535  for (i = 0; i < nx; i++) {
536  ii = (i < nx / 2) ? i + nx / 2 : i - nx / 2;
537  sstref[j + 1][ii + 1] = ssttmp[j][i];
538  }
539  sstref[j + 1][0] = sstref[j + 1][nx];
540  sstref[j + 1][nx + 1] = sstref[j + 1][1];
541  }
542  for (i = 0; i < nx + 2; i++) {
543  sstref[0] [i] = sstref[1][i];
544  sstref[ny + 1][i] = sstref[ny][i];
545  }
546  free(ssttmp);
547  }
548 
549 
550  /* locate LL position within reference grid */
551  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OINX + 1), 0);
552  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OINY + 1), 0);
553 
554  /* compute longitude and latitude of that grid element */
555  xx = i * dx - 180.0 - dx / 2;
556  yy = j * dy - 90.0 - dy / 2;
557 
558  /* bilinearly interpolate */
559  t = (lon - xx) / dx;
560  u = (lat - yy) / dy;
561 
562  sst = (1 - t)*(1 - u) * sstref[j ][i ]
563  + t * (1 - u) * sstref[j ][i + 1]
564  + t * u * sstref[j + 1][i + 1]
565  + (1 - t) * u * sstref[j + 1][i ];
566 
567  /*
568  sst = sstref[j][i];
569  */
570 
571  return (sst);
572 }
573 
574 /* ----------------------------------------------------------------------------------- */
575 /* get_ntev2() - read and interpolate Reynolds 0.25-deg daily NTEV2 file */
576 /* */
577 /* B. Franz, SAIC, July 2008. */
578 /* ----------------------------------------------------------------------------------- */
579 
580 #define OI4NX 1440
581 #define OI4NY 720
582 
583 float get_ntev2(char *sstfile, float lon, float lat, int32_t year, int32_t day) {
584  static int firstCall = 1;
585  static int nx = OI4NX;
586  static int ny = OI4NY;
587  static float dx = 360.0 / OI4NX;
588  static float dy = 180.0 / OI4NY;
589 
590  typedef float sstref_t[OI4NX + 2];
591  static sstref_t* sstref;
592  //static float sstref[OI4NY+2][OI4NX+2];
593  //static float ssttmp[OI4NY][OI4NX];
594 
595 
596  float sst = sstbad;
597  int i, j, ii;
598  int ntmp;
599  int32_t syear, smon, sday;
600  float xx, yy;
601  float t, u;
602  float reftmp[2][2];
603  float ftmp;
604 
605  if (firstCall) {
606  sstref = (sstref_t*) malloc((OI4NY + 2) * sizeof (sstref_t));
607 
608  typedef float ssttmp_t[OI4NX];
609  ssttmp_t *ssttmp;
610  ssttmp = (ssttmp_t*) malloc(OI4NY * sizeof (ssttmp_t));
611 
612  /* daily file for years 2006..2009, 1440x720 */
613  FILE *fp = NULL;
614  firstCall = 0;
615 
616  /* just need first 1440x720 real*4 array of data from the daily file */
617  /* iyr,imo,ida,refval */
618 
619  if (year < 2006 || year > 2009) {
620  printf("ntev2 data only for years 2006 to 2009, not %d\n", year);
621  exit(1);
622  }
623  printf("Loading ntev2 daily field from %s\n", sstfile);
624  printf("\n");
625 
626  /* Open the file */
627  if ((fp = fopen(sstfile, "r")) == NULL) {
628  printf("-E- %s line %d: error opening SST reference file %s for reading.\n",
629  __FILE__, __LINE__, sstfile);
630  exit(1);
631  }
632 
633  if (fseek(fp, 4, SEEK_SET) < 0) {
634  printf("Error seeking SST NTEV2 reference file %s.\n", sstfile);
635  exit(1);
636  }
637  if (fread(&syear, sizeof (int32_t), 1, fp) != 1) {
638  printf("Error reading SST NTEV2 reference file %s.\n", sstfile);
639  exit(1);
640  }
641  fread(&smon, sizeof (int32_t), 1, fp);
642  fread(&sday, sizeof (int32_t), 1, fp);
643 
644  if (fread(&ssttmp[0][0], sizeof (float), nx * ny, fp) != nx * ny) {
645  printf("Error reading SST NTEV2 reference file %s.\n", sstfile);
646  exit(1);
647  }
648  fclose(fp);
649 
650  if (endianess() == 1) {
651  swapc_bytes((char *) &syear, sizeof (int32_t), 1);
652  swapc_bytes((char *) &smon, sizeof (int32_t), 1);
653  swapc_bytes((char *) &sday, sizeof (int32_t), 1);
654  swapc_bytes((char *) &ssttmp[0][0], sizeof (float), nx * ny);
655  }
656 
657  printf("Loading Daily 0.25 Deg NTEV2 Reynolds SST reference from %s\n", sstfile);
658  printf(" file date (y/m/d): %d / %d / %d\n", syear, smon, sday);
659  printf("\n");
660 
661 
662  /* rotate 180-deg and add wrapping border to simplify later interpolation between points */
663  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
664 
665  for (j = 0; j < ny; j++) {
666  for (i = 0; i < nx; i++) {
667  ii = (i < nx / 2) ? i + nx / 2 : i - nx / 2;
668  sstref[j + 1][ii + 1] = ssttmp[j][i];
669  }
670  sstref[j + 1][0] = sstref[j + 1][nx];
671  sstref[j + 1][nx + 1] = sstref[j + 1][1];
672  }
673  for (i = 0; i < nx + 2; i++) {
674  sstref[0] [i] = sstref[1][i];
675  sstref[ny + 1][i] = sstref[ny][i];
676  }
677  free(ssttmp);
678  }
679 
680 
681  /* locate LL position within reference grid */
682  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OI4NX + 1), 0);
683  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OI4NY + 1), 0);
684 
685  /* compute longitude and latitude of that grid element */
686  xx = i * dx - 180.0 - dx / 2;
687  yy = j * dy - 90.0 - dy / 2;
688 
689  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
690  t = (lon - xx) / dx;
691  u = (lat - yy) / dy;
692 
693  ftmp = 0.0;
694  ntmp = 0;
695  if (sstref[j ][i ] > sstbad + 1) {
696  ftmp += sstref[j ][i ];
697  ntmp++;
698  }
699  if (sstref[j ][i + 1] > sstbad + 1) {
700  ftmp += sstref[j ][i + 1];
701  ntmp++;
702  }
703  if (sstref[j + 1][i + 1] > sstbad + 1) {
704  ftmp += sstref[j + 1][i + 1];
705  ntmp++;
706  }
707  if (sstref[j + 1][i ] > sstbad + 1) {
708  ftmp += sstref[j + 1][i ];
709  ntmp++;
710  }
711  if (ntmp > 0) {
712  ftmp /= ntmp;
713  reftmp[0][0] = (sstref[j ][i ] > sstbad + 1 ? sstref[j ][i ] : ftmp);
714  reftmp[0][1] = (sstref[j ][i + 1] > sstbad + 1 ? sstref[j ][i + 1] : ftmp);
715  reftmp[1][1] = (sstref[j + 1][i + 1] > sstbad + 1 ? sstref[j + 1][i + 1] : ftmp);
716  reftmp[1][0] = (sstref[j + 1][i ] > sstbad + 1 ? sstref[j + 1][i ] : ftmp);
717 
718  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
719 
720  } else
721  sst = sstbad;
722 
723  return (sst);
724 }
725 
726 /* ----------------------------------------------------------------------------------- */
727 /* get_astr() - read and interpolate Reynolds 0.25-deg monthly ATSR file */
728 /* */
729 /* B. Franz, SAIC, July 2008. */
730 /* ----------------------------------------------------------------------------------- */
731 
732 #define OI4NX 1440
733 #define OI4NY 720
734 
735 float get_atsr(char *sstfile, float lon, float lat, int32_t year, int32_t day, int32_t minatsrcnt) {
736  static int firstCall = 1;
737  static int nx = OI4NX;
738  static int ny = OI4NY;
739  static int month;
740  static float dx = 360.0 / OI4NX;
741  static float dy = 180.0 / OI4NY;
742 
743  typedef float sstref_t[OI4NX + 2];
744  static sstref_t* sstref;
745  //static float sstref[OI4NY+2][OI4NX+2];
746  //static float ssttmpb[2][OI4NY][OI4NX];
747  //static float sstcnt[2][OI4NY][OI4NX];
748 
749  float sst = sstbad;
750  int i, j, ii;
751  int ntmp;
752  float xx, yy;
753  float t, u;
754  float reftmp[2][2];
755  float ftmp;
756 
757  if (firstCall) {
758  sstref = (sstref_t*) malloc((OI4NY + 2) * sizeof (sstref_t));
759 
760  typedef float ssttmp_t[OI4NY][OI4NX];
761  ssttmp_t* ssttmpb = (ssttmp_t*) malloc(2 * sizeof (ssttmp_t));
762  ssttmp_t* sstcnt = (ssttmp_t*) malloc(2 * sizeof (ssttmp_t));
763 
764  /* years 2006..2009, months 1..12, 1440x720 */
765  FILE *fp = NULL;
766  int otherleap;
767  int endofyear;
768  int numdays;
769  int32_t foff[2];
770  int32 status;
771  int leap, day1, day2;
772  int32_t reclen;
773  float w1, w2;
774  firstCall = 0;
775 
776  /* 4*12*3*(4+4+4+4+(4*1440*720)+4) */
777  /* years 2006..2009; months 1..12; mean,std,count */
778  /* 4 bytes of fortran record length; year,month,count (3 integers) */
779  /* floats 1440x720 data; 4 byte fortran record end */
780  /* use seek_set to find first month wanted? */
781  /* use seek_cur to jump to next months mean? */
782 
783  if (year < 2006 || year > 2009) {
784  printf("ATSR data only for years 2006 to 2009, not %d\n", year);
785  exit(1);
786  }
787  printf("Loading ATSR monthly fields from %s\n", sstfile);
788  printf("\n");
789  leap = (isleap(year) == TRUE ? 1 : 0);
790  for (month = 11; month >= 0; month--) {
791  if (day > MiddleOfMonth[leap][month]) {
792  break;
793  }
794  }
795  /* each "record" is recbeg,iyr,imo,ndct,data,recend */
796  /* which is 4+4+4+4+4*1440*720+4 = 4147220 bytes */
797  /* years go from 2006 to 2009; months from 1 to 12 */
798  /* mean is first of 3 data records so read one,skip two,read one */
799  /* Jan 2006 mean is record 1, Feb 2006 mean is record 4, ... */
800 
801  /* read in two months and interpolate */
802  reclen = 4147220; /* number of bytes in one record */
803 
804  /* linearly interpolate the reference values from the two months around day */
805  /* w1 is the weight to use with the ref value from the earlier month */
806  /* w2 is the weight to use with the ref value from the later month */
807  /* The next months mean is in the next record after the previous months counts so set the 2nd offset */
808  /* to skip the fortran end of record byte count, beg of rec byte count, year, month, count before the means */
809  /* foff[1] will be set to -1 when day is in the first half of the first month or the */
810  /* last half of the last month and therefore there is no previous or next month to read */
811  foff[1] = 0; /* last read is now counts, so next mean is next */
812  if (month == -1) {
813  /* day is in first half of Jan, interpolate with previous Dec */
814  if (year == 2006) {
815  /* There is no "previous Dec." so use first set as is */
816  w1 = 1.0;
817  w2 = 0.0;
818  /* foff[0] is offset to means for first month whose center is before day */
819  /* in this case it's the first data record so no offset */
820  /* except the beg,year,mon,count that's before the data */
821  foff[0] = 0;
822  /* there is no previous month so set 2nd offset to be zero so no read is done */
823  foff[1] = -1;
824  } else {
825  /* day is in first half of Jan, interpolate with previous Dec */
826  otherleap = (isleap(year - 1) == TRUE ? 1 : 0);
827  endofyear = (otherleap == 1 ? 366 : 365);
828  numdays = ((endofyear - MiddleOfMonth[otherleap][11]) +
829  MiddleOfMonth[leap][0]);
830  w1 = (float) (MiddleOfMonth[leap][0] - day) / (float) numdays;
831  w2 = 1.0 - w1;
832  /* foff[0] is offset to means for first month whose center is before day */
833  /* in this case it's Dec of the previous year */
834  /* data is after 16 bytes of beg+year+month+count */
835  foff[0] = ((year - 1 - 2006)*12 + 11) * reclen * 3;
836  }
837  } else if (month == 11) {
838  /* day is in last half of Dec, interpolate with next Jan */
839  if (year == 2009) {
840  /* there is no "next Jan." so just use Dec. coeffs as is */
841  w1 = 1.0;
842  w2 = 0.0;
843  /* foff[0] is offset to means for first month whose center is before day */
844  /* in this case it's Dec of the last year, so there is no next month */
845  /* plus the stuff at the beginning of each record: beg,year,month,count */
846  foff[0] = ((year - 2006)*12 + 11) * reclen * 3;
847  foff[1] = -1;
848  } else {
849  /* day is in last half of Dec, interpolate with next Jan */
850  otherleap = (isleap(year + 1) == TRUE ? 1 : 0);
851  endofyear = (leap == 1 ? 366 : 365);
852  numdays = ((endofyear - MiddleOfMonth[leap][11]) +
853  MiddleOfMonth[otherleap][0]);
854  w2 = (float) (day - MiddleOfMonth[leap][11]) / (float) numdays;
855  w1 = 1.0 - w2;
856  /* foff[0] is offset to means for first month whose center is before day */
857  /* in this case the first month to read is this Dec */
858  /* plus fortran record count,year,month,count=16 bytes before data starts */
859  foff[0] = ((year - 2006)*12 + 11) * reclen * 3;
860  }
861  } else {
862  /* interpolate with next month */
863  day1 = MiddleOfMonth[leap][month];
864  day2 = MiddleOfMonth[leap][month + 1];
865  w2 = (float) (day - day1) / (float) (day2 - day1);
866  w1 = 1.0 - w2;
867  /* foff[0] is offset to means for first month whose center is before day */
868  /* in this case it's a "normal" month in the "middle" of a year */
869  /* plus fortran record count,year,month,count=16 bytes before data starts */
870  foff[0] = ((year - 2006)*12 + month) * reclen * 3;
871  }
872  /* Open the file */
873  if ((fp = fopen(sstfile, "r")) == NULL) {
874  printf("-E- %s line %d: error opening SST reference file %s for reading.\n",
875  __FILE__, __LINE__, sstfile);
876  exit(1);
877  }
878  /* skip to the first month (and skip fortran begin record count,year,month,and day count) */
879  if (fseek(fp, foff[0] + 16, SEEK_SET) < 0) {
880  printf("Error seeking SST reference file %s.\n", sstfile);
881  exit(1);
882  }
883 
884  if ((status = fread(&ssttmpb[0][0][0], sizeof (float), nx * ny, fp)) != nx * ny) {
885  printf("Wrong atsr data read size: want %d got %d\n", nx*ny, status);
886  exit(1);
887  }
888  /* skip fortran end of record, std. dev., fortran beg of record to read counts,year,month,day count */
889  if (fseek(fp, 4 + reclen + 16, SEEK_CUR) < 0) {
890  printf("Error seeking first counts from SST reference file %s.\n", sstfile);
891  exit(1);
892  }
893  if ((status = fread(&sstcnt[0][0][0], sizeof (float), nx * ny, fp)) != nx * ny) {
894  printf("Wrong atsr counts data read size: want %d got %d\n", nx*ny, status);
895  exit(1);
896  }
897  if (foff[1] == 0) {
898  /* read next months mean */
899  /* skip fortran end of record count, begin of record count,year,month, and day count */
900  fseek(fp, 20, SEEK_CUR);
901  if ((status = fread(&ssttmpb[1][0][0], sizeof (float), nx * ny, fp)) != nx * ny) {
902  printf("Wrong 2nd atsr data read size: want %d got %d\n", nx*ny, status);
903  exit(1);
904  }
905  /* skip fortran end of record count for means, std. dev., begin of record count,year,month,day count to read counts */
906  if (fseek(fp, 4 + reclen + 16, SEEK_CUR) < 0) {
907  printf("Error seek to second counts from SST reference file %s.\n", sstfile);
908  exit(1);
909  }
910  if ((status = fread(&sstcnt[1][0][0], sizeof (float), nx * ny, fp)) != nx * ny) {
911  printf("Wrong 2nd atsr counts data read size: want %d got %d\n", nx*ny, status);
912  exit(1);
913  }
914  }
915 
916  if (endianess() == 1) {
917  swapc_bytes((char *) &ssttmpb[0][0][0], sizeof (float), 2 * nx * ny);
918  swapc_bytes((char *) &sstcnt[0][0][0], sizeof (float), 2 * nx * ny);
919  }
920 
921  fclose(fp);
922  /* interpolate between the two months in ssttmpb */
923  /* rotate 180-deg and add wrapping border to simplify later interpolation between points */
924  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
925 
926  for (j = 0; j < ny; j++) {
927  for (i = 0; i < nx; i++) {
928  ii = (i < nx / 2) ? i + nx / 2 : i - nx / 2;
929  if (ssttmpb[0][j][i] > -999.0 && ssttmpb[1][j][i] > -999.0 &&
930  sstcnt[0][j][i] >= minatsrcnt && sstcnt[1][j][i] >= minatsrcnt)
931  sstref[j + 1][ii + 1] = w1 * ssttmpb[0][j][i] + w2 * ssttmpb[1][j][i];
932  else {
933  if (ssttmpb[0][j][i] > -999.0 && sstcnt[0][j][i] >= minatsrcnt)
934  sstref[j + 1][ii + 1] = ssttmpb[0][j][i];
935  else if (ssttmpb[1][j][i] > -999.0 && sstcnt[1][j][i] >= minatsrcnt)
936  sstref[j + 1][ii + 1] = ssttmpb[1][j][i];
937  else
938  sstref[j + 1][ii + 1] = sstbad;
939  }
940  }
941  sstref[j + 1][0] = sstref[j + 1][nx];
942  sstref[j + 1][nx + 1] = sstref[j + 1][1];
943  }
944  for (i = 0; i < nx + 2; i++) {
945  sstref[0] [i] = sstref[1][i];
946  sstref[ny + 1][i] = sstref[ny][i];
947  }
948  free(ssttmpb);
949  free(sstcnt);
950  }
951 
952 
953  /* locate LL position within reference grid */
954  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OI4NX + 1), 0);
955  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OI4NY + 1), 0);
956 
957  /* compute longitude and latitude of that grid element */
958  xx = i * dx - 180.0 - dx / 2;
959  yy = j * dy - 90.0 - dy / 2;
960 
961  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
962  t = (lon - xx) / dx;
963  u = (lat - yy) / dy;
964 
965  ftmp = 0.0;
966  ntmp = 0;
967  if (sstref[j ][i ] > sstbad + 1) {
968  ftmp += sstref[j ][i ];
969  ntmp++;
970  }
971  if (sstref[j ][i + 1] > sstbad + 1) {
972  ftmp += sstref[j ][i + 1];
973  ntmp++;
974  }
975  if (sstref[j + 1][i + 1] > sstbad + 1) {
976  ftmp += sstref[j + 1][i + 1];
977  ntmp++;
978  }
979  if (sstref[j + 1][i ] > sstbad + 1) {
980  ftmp += sstref[j + 1][i ];
981  ntmp++;
982  }
983  if (ntmp > 0) {
984  ftmp /= ntmp;
985  reftmp[0][0] = (sstref[j ][i ] > sstbad + 1 ? sstref[j ][i ] : ftmp);
986  reftmp[0][1] = (sstref[j ][i + 1] > sstbad + 1 ? sstref[j ][i + 1] : ftmp);
987  reftmp[1][1] = (sstref[j + 1][i + 1] > sstbad + 1 ? sstref[j + 1][i + 1] : ftmp);
988  reftmp[1][0] = (sstref[j + 1][i ] > sstbad + 1 ? sstref[j + 1][i ] : ftmp);
989 
990  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
991 
992  } else
993  sst = sstbad;
994 
995  return (sst);
996 }
997 
998 /* ----------------------------------------------------------------------------------- */
999 /* get_amsre() - read and interpolate AMSR-E data from SSMI */
1000 /* */
1001 /* S. Walsh, RSMAS, Aug 2010. */
1002 /* ----------------------------------------------------------------------------------- */
1003 
1004 #define OI4NX 1440
1005 #define OI4NY 720
1006 
1007 float get_amsre(char *sstfile, float lon, float lat, float solz, int32_t xsatid, int32_t sensorID) {
1008  static int firstCall = 1;
1009  static int nx = OI4NX;
1010  static int ny = OI4NY;
1011  static float dx = 360.0 / OI4NX;
1012  static float dy = 180.0 / OI4NY;
1013 
1014  typedef float sstref_t[OI4NX + 2][2];
1015  static sstref_t* sstref;
1016  //static float sstref[OI4NY+2][OI4NX+2][2];
1017 
1018  // char dbgfile[FILENAME_MAX] = "./sstref.dbg.file";
1019 
1020  float sst = sstbad;
1021  int jj, ii, kk, ij;
1022  int ad;
1023  int kkmax;
1024  int ntmp;
1025  int32_t foff[2];
1026  float xx, yy;
1027  float t, u;
1028  float reftmp[2][2];
1029  float ftmp;
1030 
1031  if (firstCall) {
1032  sstref = (sstref_t*) malloc((OI4NY + 2) * sizeof (sstref_t));
1033 
1034  FILE *fp = NULL;
1035  unsigned char ssttmp[OI4NX];
1036  int32 status;
1037 
1038  firstCall = 0;
1039 
1040  if (format == AMSRE3DAY)
1041  printf("Loading 3-Day 0.25-deg AMSR-E SST reference from %s\n", sstfile);
1042  else if (format == AMSRE3DN)
1043  printf("Loading 3-Day Day or Night 0.25-deg AMSR-E SST reference from %s\n", sstfile);
1044  else
1045  printf("Loading Daily 0.25-deg AMSR-E SST reference from %s\n", sstfile);
1046  printf("\n");
1047 
1048  /* Open the file */
1049  if ((fp = fopen(sstfile, "r")) == NULL) {
1050  printf("-E- %s line %d: error opening SST reference file %s for reading.\n",
1051  __FILE__, __LINE__, sstfile);
1052  exit(1);
1053  }
1054 
1055  if (format == AMSRE3DAY) {
1056  /* 3-Day - first field is 3 day avg of sst asc and dsc */
1057  foff[0] = 0;
1058  /* only one set for both ascending and descending */
1059  kkmax = 1;
1060  } else if (format == AMSRE3DN) {
1061  /* 3-Day - Day or Night - first field is 3 day avg of sst asc (day for aqua/amsr) and 2nd field is dsc night */
1062  foff[0] = 0;
1063  foff[1] = (int32_t) (nx * ny);
1064  /* one set of data for ascending, and one set for descending */
1065  kkmax = 2;
1066  } else {
1067  /* Daily - second field is 3 day avg of sst asc and dsc */
1068  /* v5 has 6 fields for day and 6 for night so fields 2 and 8 are sst */
1069  /* v7 has 7 fields for day and 7 for night so fields 2 and 9 are sst */
1070  foff[0] = (int32_t) (nx * ny);
1071  foff[1] = (int32_t) (nx * ny * 8); /* was 7 for v5 */
1072  /* one set of data for ascending, and one set for descending */
1073  kkmax = 2;
1074  }
1075 
1076  for (kk = 0; kk < kkmax; kk = kk + 1) {
1077  /* only read sst */
1078  /* ascending (day) is first, then descending (night) */
1079  if (fseek(fp, foff[kk], SEEK_SET) < 0) {
1080  fprintf(stderr, "-E- %s line %d: error reading SST reference file %s.\n",
1081  __FILE__, __LINE__, sstfile);
1082  exit(1);
1083  }
1084  for (jj = 0; jj < ny; jj = jj + 1) {
1085  if ((status = fread(&ssttmp[0], sizeof (char), nx, fp)) != nx) {
1086  printf("Wrong AMSR-E data read size: want %d got %d\n", nx, status);
1087  exit(1);
1088  }
1089  /* 0-250 are valid values */
1090  for (ii = 0; ii < nx; ii = ii + 1) {
1091  /* rotate 180-deg and add wrapping border to simplify interpolation */
1092  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
1093 
1094  ij = (ii < nx / 2) ? ii + nx / 2 : ii - nx / 2;
1095  if (ssttmp[ii] <= 250) {
1096  sstref[jj + 1][ij + 1][kk] = ssttmp[ii] * 0.15 - 3.0;
1097  } else {
1098  sstref[jj + 1][ij + 1][kk] = sstbad;
1099  }
1100  /* if d3d file put values in both asc and dsc slots */
1101  if (kkmax == 1) {
1102  sstref[jj + 1][ij + 1][1] = sstref[jj + 1][ij + 1][0];
1103  }
1104  }
1105 
1106  /* wrap edges */
1107  sstref[jj + 1][0] [kk] = sstref[jj + 1][nx][kk];
1108  sstref[jj + 1][nx + 1][kk] = sstref[jj + 1][1] [kk];
1109  }
1110  /* copy edges for interpolation */
1111  for (ii = 0; ii < nx + 2; ii = ii + 1) {
1112  sstref[0] [ii][kk] = sstref[1] [ii][kk];
1113  sstref[ny + 1][ii][kk] = sstref[ny][ii][kk];
1114  }
1115  }
1116  fclose(fp);
1117 
1118  }
1119 
1120  if (solz < 90.0) {
1121  ad = 0; /* day - ascending for amsr on aqua */
1122  } else {
1123  ad = 1; /* night - descending for amsr on aqua */
1124  }
1125 
1126  // morning satellites, daytime pixels use night amsr
1127  // afternoon satellites, daytime pixels use day amsr
1128 
1129  // /* some day may want to swap day/night for satellites that
1130  // * descend in the daytime so that the swath are the same direction
1131  // * amsr was on aqua so day is 1:30 pm local time, afternoon, lots of daytime warming
1132  // * so morning satellites, whose "day" pixels are before daytime warning,
1133  // * should use amsr night for their reference field instead of amsr (afternoon) day
1134  // */
1135 
1136  if ((format == AMSREDAY || format == AMSRE3DAY || format == AMSRE3DN) &&
1137  ((sensorID == MODIST ||
1138  (sensorID == AVHRR && (xsatid == NO06 || xsatid == NO08 ||
1139  xsatid == NO10 || xsatid == NO12 || xsatid == NO15 || xsatid == NO17))))) {
1140  /* These satellites descend in day, opposite of aqua */
1141  /* and their "day" pixels are 9:30 am, before daytime warming, so use amsr night field */
1142  ad = 1 - ad;
1143  }
1144 
1145  /* locate LL position within reference grid */
1146  ii = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), nx + 1), 0);
1147  jj = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), ny + 1), 0);
1148 
1149  /* compute longitude and latitude of that grid element */
1150  xx = ii * dx - 180.0 - dx / 2;
1151  yy = jj * dy - 90.0 - dy / 2;
1152 
1153  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
1154  t = (lon - xx) / dx;
1155  u = (lat - yy) / dy;
1156 
1157  ftmp = 0.0;
1158  ntmp = 0;
1159  if (sstref[jj ][ii ][ad] > sstbad + 1) {
1160  ftmp += sstref[jj ][ii ][ad];
1161  ntmp++;
1162  }
1163  if (sstref[jj ][ii + 1][ad] > sstbad + 1) {
1164  ftmp += sstref[jj ][ii + 1][ad];
1165  ntmp++;
1166  }
1167  if (sstref[jj + 1][ii + 1][ad] > sstbad + 1) {
1168  ftmp += sstref[jj + 1][ii + 1][ad];
1169  ntmp++;
1170  }
1171  if (sstref[jj + 1][ii ][ad] > sstbad + 1) {
1172  ftmp += sstref[jj + 1][ii ][ad];
1173  ntmp++;
1174  }
1175  if (ntmp > 0) {
1176  ftmp /= ntmp;
1177  reftmp[0][0] = (sstref[jj ][ii ][ad] > sstbad + 1 ? sstref[jj ][ii ][ad] : ftmp);
1178  reftmp[0][1] = (sstref[jj ][ii + 1][ad] > sstbad + 1 ? sstref[jj ][ii + 1][ad] : ftmp);
1179  reftmp[1][1] = (sstref[jj + 1][ii + 1][ad] > sstbad + 1 ? sstref[jj + 1][ii + 1][ad] : ftmp);
1180  reftmp[1][0] = (sstref[jj + 1][ii ][ad] > sstbad + 1 ? sstref[jj + 1][ii ][ad] : ftmp);
1181 
1182  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
1183 
1184  } else
1185  sst = sstbad;
1186 
1187  return (sst);
1188 }
1189 
1190 /* ----------------------------------------------------------------------------------- */
1191 /* get_windsat() - read and interpolate WindSat data from SSMI */
1192 /* */
1193 /* S. Walsh, RSMAS, Aug 2010. */
1194 /* ----------------------------------------------------------------------------------- */
1195 
1196 #define OI4NX 1440
1197 #define OI4NY 720
1198 
1199 float get_windsat(char *sstfile, float lon, float lat, float solz, int32_t xsatid, int32_t sensorID) {
1200  static int firstCall = 1;
1201  static int nx = OI4NX;
1202  static int ny = OI4NY;
1203  static float dx = 360.0 / OI4NX;
1204  static float dy = 180.0 / OI4NY;
1205 
1206  typedef float sstref_t[OI4NX + 2][2];
1207  static sstref_t* sstref;
1208  //static float sstref[OI4NY+2][OI4NX+2][2];
1209 
1210  // char dbgfile[FILENAME_MAX] = "./sstref.dbg.file";
1211 
1212  float sst = sstbad;
1213  int jj, ii, kk, ij;
1214  int ad;
1215  int kkmax;
1216  int ntmp;
1217  int32_t foff[2];
1218  float xx, yy;
1219  float t, u;
1220  float reftmp[2][2];
1221  float ftmp;
1222 
1223  if (firstCall) {
1224  sstref = (sstref_t*) malloc((OI4NY + 2) * sizeof (sstref_t));
1225 
1226  FILE *fp = NULL;
1227  unsigned char ssttmp[OI4NX];
1228  float fssttmp[OI4NX];
1229  int32 status;
1230 
1231  firstCall = 0;
1232 
1233  if (format == WINDSAT3DAY)
1234  printf("Loading 3-Day 0.25-deg WindSat SST reference from %s\n", sstfile);
1235  else if (format == WINDSAT3DN)
1236  printf("Loading 3-Day Day or Night 0.25-deg WindSat SST reference from %s\n", sstfile);
1237  else
1238  printf("Loading Daily 0.25-deg WindSat SST reference from %s\n", sstfile);
1239  printf("\n");
1240 
1241  /* Open the file */
1242  if ((fp = fopen(sstfile, "r")) == NULL) {
1243  printf("-E- %s line %d: error opening SST reference file %s for reading.\n",
1244  __FILE__, __LINE__, sstfile);
1245  exit(1);
1246  }
1247 
1248  if (format == WINDSAT3DAY) {
1249  /* 3-Day - first field is 3 day avg of sst dsc (day) and asc (night) */
1250  foff[0] = 0;
1251  /* only one set for both descending and ascending */
1252  kkmax = 1;
1253  } else if (format == WINDSAT3DN) {
1254  /* 3-Day - Day or Night - first field is 3 day avg of sst dsc and 2nd field is asc night */
1255  /* values are floats */
1256  foff[0] = 0;
1257  foff[1] = (int32_t) (nx * ny * sizeof (float));
1258  /* one set of data for descending, and one set for ascending */
1259  kkmax = 2;
1260  } else {
1261  /* Daily - second field is 3 day avg of sst desc and asc */
1262  /* 9 fields for desc, 9 for asc, sst's are bands 2 and 11 (one based) */
1263  /* values are bytes */
1264  foff[0] = (int32_t) (nx * ny);
1265  foff[1] = (int32_t) (nx * ny * 10);
1266  /* seek_set starts at 0 each time, so skip fields 1..10 */
1267  /* one set of data for descending, and one set for ascending */
1268  kkmax = 2;
1269  }
1270 
1271  for (kk = 0; kk < kkmax; kk = kk + 1) {
1272  /* only read sst */
1273  /* descending (morning) is first, then ascending (evening) */
1274  if (fseek(fp, foff[kk], SEEK_SET) < 0) {
1275  fprintf(stderr, "-E- %s line %d: error reading SST reference file %s.\n",
1276  __FILE__, __LINE__, sstfile);
1277  exit(1);
1278  }
1279  for (jj = 0; jj < ny; jj = jj + 1) {
1280  if (format == WINDSAT3DN) {
1281  if ((status = fread(&fssttmp[0], sizeof (float), nx, fp)) != nx) {
1282  printf("Wrong WINDSAT data read size: want %d got %d\n", nx, status);
1283  exit(1);
1284  }
1285  // if (jj == 0) {
1286  // printf(" first windsat values: %f %f %f %f %f %f %f\n", fssttmp[0],fssttmp[1],fssttmp[2],fssttmp[3],fssttmp[4],fssttmp[5],fssttmp[6]);
1287  // }
1288  if (endianess() == 1) {
1289  swapc_bytes((char *) &fssttmp[0], sizeof (float), nx);
1290  }
1291  // if (jj == 220) {
1292  // printf(" fssttmp[1164]=%f fssttmp[1165]=%f\n",fssttmp[1164],fssttmp[1165]);
1293  // printf(" fssttmp[444]=%f fssttmp[445]=%f\n",fssttmp[444],fssttmp[445]);
1294  // }
1295  // if (jj == 0) {
1296  // printf(" first windsat values: %f %f %f %f %f %f %f\n", fssttmp[0],fssttmp[1],fssttmp[2],fssttmp[3],fssttmp[4],fssttmp[5],fssttmp[6]);
1297  // }
1298  } else {
1299  if ((status = fread(&ssttmp[0], sizeof (char), nx, fp)) != nx) {
1300  printf("Wrong WINDSAT data read size: want %d got %d\n", nx, status);
1301  exit(1);
1302  }
1303  }
1304  /* 0-250 are valid values */
1305  for (ii = 0; ii < nx; ii = ii + 1) {
1306  /* rotate 180-deg and add wrapping border to simplify interpolation */
1307  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
1308 
1309  ij = (ii < nx / 2) ? ii + nx / 2 : ii - nx / 2;
1310  if (format == WINDSAT3DN) {
1311  /* for our 3 day average, bad values are -9999.0 */
1312  if (fssttmp[ii] > -9998.0) {
1313  sstref[jj + 1][ij + 1][kk] = fssttmp[ii];
1314  } else {
1315  sstref[jj + 1][ij + 1][kk] = sstbad;
1316  }
1317  } else {
1318  if (ssttmp[ii] <= 250) {
1319  sstref[jj + 1][ij + 1][kk] = ssttmp[ii] * 0.15 - 3.0;
1320  } else {
1321  sstref[jj + 1][ij + 1][kk] = sstbad;
1322  }
1323  }
1324  /* if d3d file put values in both asc and dsc slots */
1325  if (kkmax == 1) {
1326  sstref[jj + 1][ij + 1][1] = sstref[jj + 1][ij + 1][0];
1327  }
1328  }
1329 
1330  /* wrap edges */
1331  sstref[jj + 1][0] [kk] = sstref[jj + 1][nx][kk];
1332  sstref[jj + 1][nx + 1][kk] = sstref[jj + 1][1] [kk];
1333  }
1334  /* copy edges for interpolation */
1335  for (ii = 0; ii < nx + 2; ii = ii + 1) {
1336  sstref[0] [ii][kk] = sstref[1] [ii][kk];
1337  sstref[ny + 1][ii][kk] = sstref[ny][ii][kk];
1338  }
1339  }
1340  fclose(fp);
1341 
1342 
1343  }
1344 
1345  /* default is for afternoon satellites whose day pixels are around 1:30 pm local time */
1346  /* their day pixels should be compared to windsat evening pixels, and their night to windsat morning */
1347  if (solz < 90.0) {
1348  ad = 1; /* day pixel, use windsat evening - aescending */
1349  } else {
1350  ad = 0; /* night pixel, use windsat morning - descending */
1351  }
1352 
1353  // windsat fields are morning, descending (08:45) and evening, ascending (20:45)
1354  // viirs is descending at 13:45 and ascending at 01:45
1355  // so for viirs descending day, use evening ascending windsat
1356  // morning fields are best for night pixels from afternoon satellites because no daytime warming has occurred yet
1357  // evening fields are best for afternoon daytime pixels
1358 
1359  // morning satellites, daytime pixels use morning windsat
1360  // afternoon satellites, daytime pixels use evening windsat
1361 
1362  // /* some day may want to swap day/night for satellites that
1363  // * descend in the daytime so that the swath are the same direction
1364  // */
1365  if ((format == WINDSATDAY || format == WINDSAT3DAY || format == WINDSAT3DN) &&
1366  ((sensorID == MODIST ||
1367  (sensorID == AVHRR && (xsatid == NO06 || xsatid == NO08 ||
1368  xsatid == NO10 || xsatid == NO12 || xsatid == NO15 || xsatid == NO17))))) {
1369  /* These satellites descend in day, opposite of aqua */
1370  /* and their "day" pixels are 9:30 am, before daytime warming, so use amsr night field */
1371  ad = 1 - ad;
1372  }
1373 
1374  /* locate LL position within reference grid */
1375  ii = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), nx + 1), 0);
1376  jj = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), ny + 1), 0);
1377 
1378  /* compute longitude and latitude of that grid element */
1379  xx = ii * dx - 180.0 - dx / 2;
1380  yy = jj * dy - 90.0 - dy / 2;
1381 
1382  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
1383  t = (lon - xx) / dx;
1384  u = (lat - yy) / dy;
1385 
1386  ftmp = 0.0;
1387  ntmp = 0;
1388  if (sstref[jj ][ii ][ad] > sstbad + 1) {
1389  ftmp += sstref[jj ][ii ][ad];
1390  ntmp++;
1391  }
1392  if (sstref[jj ][ii + 1][ad] > sstbad + 1) {
1393  ftmp += sstref[jj ][ii + 1][ad];
1394  ntmp++;
1395  }
1396  if (sstref[jj + 1][ii + 1][ad] > sstbad + 1) {
1397  ftmp += sstref[jj + 1][ii + 1][ad];
1398  ntmp++;
1399  }
1400  if (sstref[jj + 1][ii ][ad] > sstbad + 1) {
1401  ftmp += sstref[jj + 1][ii ][ad];
1402  ntmp++;
1403  }
1404  if (ntmp > 0) {
1405  ftmp /= ntmp;
1406  reftmp[0][0] = (sstref[jj ][ii ][ad] > sstbad + 1 ? sstref[jj ][ii ][ad] : ftmp);
1407  reftmp[0][1] = (sstref[jj ][ii + 1][ad] > sstbad + 1 ? sstref[jj ][ii + 1][ad] : ftmp);
1408  reftmp[1][1] = (sstref[jj + 1][ii + 1][ad] > sstbad + 1 ? sstref[jj + 1][ii + 1][ad] : ftmp);
1409  reftmp[1][0] = (sstref[jj + 1][ii ][ad] > sstbad + 1 ? sstref[jj + 1][ii ][ad] : ftmp);
1410 
1411  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
1412 
1413  } else
1414  sst = sstbad;
1415 
1416  return (sst);
1417 }
1418 
1419 /* ----------------------------------------------------------------------------------- */
1420 /* get_atsrday() - read and interpolate ATSR 0.1-deg daily netcdf files */
1421 /* */
1422 /* S. Walsh, RSMAS, Feb 2011. */
1423 /* ----------------------------------------------------------------------------------- */
1424 
1425 #define OI1NX 3600
1426 #define OI1NY 1800
1427 
1428 float get_atsrday(char *sstfile, float lon, float lat) {
1429  static int firstCall = 1;
1430  static int nx = OI1NX;
1431  static int ny = OI1NY;
1432  static int32_t slen = 0;
1433  static float *sref = NULL;
1434  static float dx = 360.0 / OI1NX;
1435  static float dy = 180.0 / OI1NY;
1436 
1437  float sst = sstbad;
1438  int i, j, jl, nl;
1439  int ntmp;
1440  float xx, yy;
1441  float t, u;
1442  float reftmp[2][2];
1443  float ftmp;
1444 
1445  if (firstCall) {
1446 
1447  char name [H4_MAX_NC_NAME] = "";
1448  char sdsname[H4_MAX_NC_NAME] = "";
1449  int ll, jj, jjl;
1450  int32 sd_id;
1451  int32 sds_id;
1452  int32 rank;
1453  int32 nt;
1454  int32 dims[H4_MAX_VAR_DIMS];
1455  int32 nattrs;
1456  int32 start[4] = {0, 0, 0, 0};
1457  int32 status;
1458  int32_t stlen = 0;
1459  float *stmp = NULL;
1460 
1461  firstCall = 0;
1462 
1463  printf("Loading Daily 0.1-deg ATSR SST reference from %s\n", sstfile);
1464  printf("\n");
1465 
1466  /* allocate arrays */
1467  slen = (OI1NY + 2) * (OI1NX + 2);
1468  if ((sref = (float *) malloc(slen * sizeof (float))) == NULL) {
1469  fprintf(stderr, "-E- %s line %d: Unable to allocate sstref array.\n",
1470  __FILE__, __LINE__);
1471  exit(1);
1472  }
1473 
1474  stlen = OI1NY * OI1NX;
1475  if ((stmp = (float *) malloc(stlen * sizeof (float))) == NULL) {
1476  fprintf(stderr, "-E- %s line %d: Unable to allocate ssttmp array.\n",
1477  __FILE__, __LINE__);
1478  exit(1);
1479  }
1480 
1481  /* Open the file */
1482  sd_id = SDstart(sstfile, DFACC_RDONLY);
1483  if (sd_id == FAIL) {
1484  fprintf(stderr, "-E- %s line %d: error reading %s.\n",
1485  __FILE__, __LINE__, sstfile);
1486  exit(1);
1487  }
1488 
1489  strcpy(sdsname, "sst_skin");
1490  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
1491  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
1492  status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) stmp);
1493  if (status != 0) {
1494  fprintf(stderr, "-E- %s Line %d: Error reading SDS %s from %s.\n",
1495  __FILE__, __LINE__, sdsname, sstfile);
1496  exit(1);
1497  }
1498  status = SDendaccess(sds_id);
1499  status = SDend(sd_id);
1500 
1501  /* ATSR grid is lon centers -179.95..179.95 in 1..3600; lat centers 89.95..-89.95 */
1502  /* first pix represents -180..-179.9,90..89.9 */
1503  /* flip and add wrapping border to simplify interpolation */
1504  /* new grid is -180.1,180.1 in i=0,3601 and -90.1,90.1 in j=0,1801 */
1505 
1506  for (j = 0; j < ny; j++) {
1507  /* stmp points to ny x nx array read in from file */
1508  jl = j * (nx + 2); /* offset to line j in stmp */
1509  /* sref points to ny+2 * nx+2 array */
1510  /* flip so need to calculate line in sref */
1511  /* stmp line 0 goes into sref line ny */
1512  /* stmp line ny-1 goes into sref line 1 */
1513  jj = ny - j;
1514  jjl = jj * (nx + 2); /* offset to line jj in sref */
1515  for (i = 0; i < nx; i++) {
1516  if (stmp[jl + i] > -998.0) {
1517  sref[jjl + i + 1] = stmp[jl + i];
1518  } else {
1519  sref[jjl + i + 1] = sstbad;
1520  }
1521  }
1522  sref[jl] = sref[jl + nx];
1523  sref[jl + nx + 2 + nx + 1] = sref[jl + nx + 2 + 1];
1524  }
1525  ll = (ny + 1)*(nx + 2); /* start of last line */
1526  nl = ny * (nx + 2); /* start of next to last line */
1527  for (i = 0; i < nx + 2; i++) {
1528  sref[i] = sref[nx + 2 + i];
1529  sref[ll + i] = sref[nl + i];
1530  }
1531  free(stmp);
1532  }
1533 
1534 
1535  /* locate LL position within reference grid */
1536  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OI1NX + 1), 0);
1537  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OI1NY + 1), 0);
1538 
1539  /* compute longitude and latitude of that grid element */
1540  xx = i * dx - 180.0 - dx / 2;
1541  yy = j * dy - 90.0 - dy / 2;
1542 
1543  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
1544  t = (lon - xx) / dx;
1545  u = (lat - yy) / dy;
1546 
1547  ftmp = 0.0;
1548  ntmp = 0;
1549  jl = (j - 1)*(nx + 2); /* offset to start of line j */
1550  nl = j * (nx + 2); /* offset to start of line j+1 */
1551  if (sref[jl + i ] > sstbad + 1) {
1552  ftmp += sref[jl + i ];
1553  ntmp++;
1554  }
1555  if (sref[jl + i + 1] > sstbad + 1) {
1556  ftmp += sref[jl + i + 1];
1557  ntmp++;
1558  }
1559  if (sref[nl + i + 1] > sstbad + 1) {
1560  ftmp += sref[nl + i + 1];
1561  ntmp++;
1562  }
1563  if (sref[nl + i ] > sstbad + 1) {
1564  ftmp += sref[nl + i ];
1565  ntmp++;
1566  }
1567  if (ntmp > 0) {
1568  ftmp /= ntmp;
1569  reftmp[0][0] = (sref[jl + i ] > sstbad + 1 ? sref[jl + i ] : ftmp);
1570  reftmp[0][1] = (sref[jl + i + 1] > sstbad + 1 ? sref[jl + i + 1] : ftmp);
1571  reftmp[1][1] = (sref[nl + i + 1] > sstbad + 1 ? sref[nl + i + 1] : ftmp);
1572  reftmp[1][0] = (sref[nl + i ] > sstbad + 1 ? sref[nl + i ] : ftmp);
1573 
1574  sst = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
1575 
1576  } else
1577  sst = sstbad;
1578 
1579  return (sst);
1580 }
1581 
1582 /* ------------------------------------------------------------------------------------ */
1583 /* get_sstref() - retrieves reference sea surface temperature */
1584 /* ssttype has to be set for each pixel because climatology could be used */
1585 /* instead of sstfile */
1586 /* */
1587 /* B. Franz, SAIC, May 2004. */
1588 /* ---------------------------------------------------------------------------------------------- */
1589 #include "smi_climatology.h"
1590 #include "l1.h"
1591 
1592 float get_sstref(short reftyp, char *sstfile, l1str *l1rec, int32_t ip) {
1593  float lon = l1rec->lon[ip];
1594  float lat = l1rec->lat[ip];
1595  float solz = l1rec->solz[ip];
1596  int32_t xsatid = l1rec->l1file->subsensorID;
1597  int32_t sensorID = l1rec->l1file->sensorID;
1598  int16_t yr, dy;
1599  double sec;
1600 
1601  unix2yds(l1rec->scantime, &yr, &dy, &sec);
1602  int32_t year = (int32_t) yr;
1603  int32_t day = (int32_t) dy;
1604  float sst = sstbad;
1605  int32_t sd_id;
1606 
1607  if (format < 0) {
1608 
1609  /* Does the file exist? */
1610  if (access(sstfile, F_OK) || access(sstfile, R_OK)) {
1611  printf("-E- %s line %d: SST input file '%s' does not exist or cannot open.\n",
1612  __FILE__, __LINE__, sstfile);
1613  exit(1);
1614  }
1615 
1616  /* What is it? */
1617  if (reftyp == 8) {
1618  /* It's a 3-day Day or Night WindSat file from avgwindsat */
1619  format = WINDSAT3DN;
1620 
1621  } else if (reftyp == 7) {
1622  /* It's a 3-day WindSat file from SSMI */
1623  format = WINDSAT3DAY;
1624 
1625  } else if (reftyp == 6) {
1626  /* It's a daily WindSat file from SSMI */
1627  format = WINDSATDAY;
1628 
1629  } else if (reftyp == 5) {
1630  /* It's a 3-day Day or Night AMSR-E file from SSMI */
1631  format = AMSRE3DN;
1632 
1633  } else if (reftyp == 4) {
1634  /* It's a Daily NTEV2 file from Reynolds */
1635  format = NTEV2;
1636 
1637  } else if (reftyp == 3) {
1638  /* It's a Monthly ATSR file from Reynolds */
1639  format = ATSR;
1640 
1641  } else if (reftyp == 2) {
1642  /* It's a 3-day AMSR-E file from SSMI */
1643  format = AMSRE3DAY;
1644 
1645  } else if (reftyp == 1) {
1646  /* It's a daily AMSR-E file from SSMI */
1647  format = AMSREDAY;
1648 
1649  } else {
1650 
1651  char title[255] = "";
1652 
1653  // SDstart seg faults on the mac, so need to protect the
1654  // call with Hishdf()
1655  if (Hishdf(sstfile))
1656  sd_id = SDstart(sstfile, DFACC_RDONLY);
1657  else
1658  sd_id = FAIL;
1659 
1660  if (sd_id != FAIL) {
1661  /* Format is HDF-like */
1662  char title[255] = "";
1663  if (SDreadattr(sd_id, SDfindattr(sd_id, "title"), (VOIDP) title) == 0) {
1664  if (strstr(title, "Daily-OI-V2") != NULL) {
1665  format = OISSTV2D;
1666  } else if (strstr(title, "ARC Sea Surface Temperature") != NULL) {
1667  format = ATSRDAY;
1668 
1669  } else {
1670  printf("-E- %s line %d: Unable to initialize SST file\n", __FILE__, __LINE__);
1671  printf("%s %d\n", sstfile, day);
1672  exit(1);
1673  }
1674  } else if (SDreadattr(sd_id, SDfindattr(sd_id, "Title"), (VOIDP) title) == 0) {
1675  if (strstr(title, "SST Climatology") != NULL) {
1676  format = PATHCLIM;
1677  if (smi_climatology_init(sstfile, day, SST) != 0) {
1678  printf("-E- %s line %d: Unable to initialize SST file\n", __FILE__, __LINE__);
1679  printf("%s %d\n", sstfile, day);
1680  exit(1);
1681  }
1682  }
1683  }
1684  SDend(sd_id);
1685 
1686  } else {
1687  if (nc_open(sstfile, NC_NOWRITE, &sd_id) == NC_NOERR) {
1688  /* Format is netCDF */
1689  if (nc_get_att_text(sd_id, NC_GLOBAL, "title", title) == NC_NOERR) {
1690  if (strstr(title, "Daily-OI") ||
1691  strstr(title, "NOAA/NCEI 1/4 Degree Daily Optimum Interpolation Sea Surface Temperature (OISST) Analysis")) {
1692  format = OISSTV2D;
1693  } else if (strstr(title, "CMC") != NULL) {
1694  format = CMC;
1695  } else {
1696  printf("-E- %s : Unable to initialize SST file\n", __FILE__);
1697  printf("%s %d\n", sstfile, day);
1698  exit(1);
1699  }
1700  }
1701  nc_close(sd_id);
1702  } else {
1703 
1704  /* Format is not HDF or netCDF. Assuming OISST Binary. */
1705  format = OISSTBIN;
1706  }
1707  }
1708  }
1709 
1710  /* need a back-up climatology for NRT products */
1711  if (format != PATHCLIM) {
1712  char *tmp_str;
1713  char file [FILENAME_MAX] = "";
1714  if ((tmp_str = getenv("OCDATAROOT")) == NULL) {
1715  printf("OCDATAROOT environment variable is not defined.\n");
1716  exit(1);
1717  }
1718  strcpy(file, tmp_str);
1719  strcat(file, "/common/sst_climatology.hdf");
1720  if (smi_climatology_init(file, day, SST) != 0) {
1721  printf("-E- %s line %d: Unable to initialize SST file\n", __FILE__, __LINE__);
1722  printf("%s %d\n", file, day);
1723  exit(1);
1724  }
1725  }
1726  }
1727 
1728  switch (format) {
1729  case PATHCLIM:
1730  sst = smi_climatology(lon, lat, SST);
1731  l1rec->ssttype[ip] = 0; /* SST Climatology */
1732  /* don't know if this is skin or bulk, but sst doesn't use these so don't care */
1733  break;
1734  case OISSTBIN:
1735  sst = get_oisst(sstfile, lon, lat);
1736  l1rec->ssttype[ip] = 1; /* Reynolds Weekly 1 deg OI */
1737  /* All Reynolds reference fields are bulk, sst calculation needs skin */
1738  sst = sst - 0.17;
1739  break;
1740  case OISSTV2D:
1741  sst = get_oisstv2d(sstfile, lon, lat);
1742  l1rec->ssttype[ip] = 2; /* Reynolds Daily 0.25-deg OI */
1743  /* All Reynolds reference fields are bulk, sst calculation needs skin */
1744  sst = sst - 0.17;
1745  break;
1746  case AMSRE3DAY:
1747  sst = get_amsre(sstfile, lon, lat, solz, xsatid, sensorID);
1748  l1rec->ssttype[ip] = 3; /* AMSR-E 3-Day 0.25-deg */
1749  /* AMSR is microwave skin, needs correction to skin */
1750  sst = sst - 0.15;
1751  break;
1752  case AMSREDAY:
1753  sst = get_amsre(sstfile, lon, lat, solz, xsatid, sensorID);
1754  l1rec->ssttype[ip] = 4; /* AMSR-E Daily 0.25-deg */
1755  /* AMSR is microwave skin, needs correction to skin */
1756  sst = sst - 0.15;
1757  break;
1758  case ATSR:
1759  sst = get_atsr(sstfile, lon, lat, year, day, 1);
1760  l1rec->ssttype[ip] = 5; /* ATSR Monthly 0.25-deg */
1761  /* atsr is skin, no correction needed */
1762  break;
1763  case NTEV2:
1764  sst = get_ntev2(sstfile, lon, lat, year, day);
1765  l1rec->ssttype[ip] = 6; /* NTEV2 Daily 0.25-deg */
1766  /* All Reynolds reference fields are bulk, sst calculation needs skin */
1767  sst = sst - 0.17;
1768  break;
1769  case AMSRE3DN:
1770  sst = get_amsre(sstfile, lon, lat, solz, xsatid, sensorID);
1771  l1rec->ssttype[ip] = 7; /* AMSR-E 3-Day Day or Night 0.25-deg */
1772  /* AMSR is microwave skin, needs correction to skin */
1773  if (sst > sstbad + 1) {
1774  sst = sst - 0.15;
1775  }
1776  break;
1777  case ATSRDAY:
1778  sst = get_atsrday(sstfile, lon, lat);
1779  l1rec->ssttype[ip] = 8; /* ATSR Daily 0.1-deg */
1780  /* We use the sst_skin value from the ATSR files */
1781  /* convert Kelvin to C */
1782  sst = sst - 273.15;
1783  break;
1784  case WINDSAT3DAY:
1785  sst = get_windsat(sstfile, lon, lat, solz, xsatid, sensorID);
1786  l1rec->ssttype[ip] = 9; /* WindSat 3-Day 0.25-deg */
1787  /* WindSat is microwave skin, needs correction to skin */
1788  sst = sst - 0.15;
1789  break;
1790  case WINDSATDAY:
1791  sst = get_windsat(sstfile, lon, lat, solz, xsatid, sensorID);
1792  l1rec->ssttype[ip] = 10; /* WindSat Daily 0.25-deg */
1793  /* WindSat is microwave skin, needs correction to skin */
1794  sst = sst - 0.15;
1795  break;
1796  case WINDSAT3DN:
1797  sst = get_windsat(sstfile, lon, lat, solz, xsatid, sensorID);
1798  l1rec->ssttype[ip] = 11; /* WindSat 3-Day Day or Night 0.25-deg */
1799  /* WindSat is microwave skin, needs correction to skin */
1800  if (sst > sstbad + 1) {
1801  sst = sst - 0.15;
1802  }
1803  break;
1804  case CMC:
1805  sst = get_cmcsst(sstfile, lon, lat);
1806  l1rec->ssttype[ip] = 12; /* CMC analyzed SST */
1807  /* CMC analyzed SST fields are "foundation" i.e. bulk, sst calculation needs skin correction*/
1808  sst = sst - 0.17;
1809  break;
1810  default:
1811  printf("-E- %s line %d: unknown SST input file format for %s.\n", __FILE__, __LINE__, sstfile);
1812  break;
1813  }
1814 
1815  if (sst < (sstbad + 1)) {
1816  sst = smi_climatology(lon, lat, SST);
1817  l1rec->ssttype[ip] = 0; /* SST Climatology */
1818  /* don't know if this is skin or bulk, but sst doesn't use these so don't care */
1819  }
1820 
1821  return (sst);
1822 }
#define OINX
Definition: sstref.c:444
#define MAX(A, B)
Definition: swl0_utils.h:26
#define WINDSATDAY
Definition: sstref.c:29
integer, parameter int16
Definition: cubeio.f90:3
#define MIN(x, y)
Definition: rice.h:169
data_t t[NROOTS+1]
Definition: decode_rs.h:77
int16 eday
Definition: l1_czcs_hdf.c:17
int smi_climatology_init(char *file, int day, int prodID)
#define NO17
Definition: l1_aci_hdf.h:15
int j
Definition: decode_rs.h:73
int32_t day
int status
Definition: l1_czcs_hdf.c:32
int32_t nl
Definition: atrem_corl1.h:132
#define AVHRR
Definition: sensorDefs.h:15
#define OINY
Definition: sstref.c:445
#define CMC
Definition: sstref.c:31
float get_windsat(char *sstfile, float lon, float lat, float solz, int32_t xsatid, int32_t sensorID)
Definition: sstref.c:1199
#define FAIL
Definition: ObpgReadGrid.h:18
#define NULL
Definition: decode_rs.h:63
read l1rec
#define AMSRE3DAY
Definition: sstref.c:22
#define NO08
Definition: l1_aci_hdf.h:7
#define OI4NY
Definition: sstref.c:1197
#define TRUE
Definition: rice.h:165
float * lat
#define MODIST
Definition: sensorDefs.h:18
float get_sstref(short reftyp, char *sstfile, l1str *l1rec, int32_t ip)
Definition: sstref.c:1592
#define WINDSAT3DAY
Definition: sstref.c:28
int16 eyear
Definition: l1_czcs_hdf.c:17
int syear
Definition: l1_czcs_hdf.c:15
void free2d_short(short **p)
Free a two-dimensional array created by allocate2d_short.
Definition: allocate2d.c:114
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed file
Definition: HISTORY.txt:413
int endianess(void)
determine endianess
Definition: endianess.c:10
int swapc_bytes(char *in, int nbyte, int ntime)
Definition: swapc_bytes.c:4
float get_oisstv2d(char *sstfile, float lon, float lat)
Definition: sstref.c:51
float get_atsrday(char *sstfile, float lon, float lat)
Definition: sstref.c:1428
int sday
Definition: l1_czcs_hdf.c:15
#define NO06
Definition: l1_aci_hdf.h:5
#define NO10
Definition: l1_aci_hdf.h:9
#define PATHCLIM
Definition: sstref.c:19
#define OI1NY
Definition: sstref.c:1426
#define ATSR
Definition: sstref.c:24
#define NO12
Definition: l1_aci_hdf.h:11
#define OISSTV2D
Definition: sstref.c:21
float get_oisst(char *sstfile, float lon, float lat)
Definition: sstref.c:447
#define ATSRDAY
Definition: sstref.c:27
#define NTEV2
Definition: sstref.c:25
#define CtoK
Definition: sstref.c:33
float32 slope[]
Definition: l2lists.h:30
float get_atsr(char *sstfile, float lon, float lat, int32_t year, int32_t day, int32_t minatsrcnt)
Definition: sstref.c:735
int getHDFattr(int32_t fileID, const char attrname[], const char sdsname[], void *data)
#define NO15
Definition: l1_aci_hdf.h:13
void unix2yds(double usec, short *year, short *day, double *secs)
int isleap(int year)
Definition: isleap.c:3
#define WINDSAT3DN
Definition: sstref.c:30
float get_cmcsst(char *sstfile, float lon, float lat)
Definition: sstref.c:241
#define BAD_FLT
Definition: jplaeriallib.h:19
float smi_climatology(float lon, float lat, int prodID)
data_t u
Definition: decode_rs.h:74
#define OISSTBIN
Definition: sstref.c:20
#define SST
#define fabs(a)
Definition: misc.h:93
Extra metadata that will be written to the HDF4 file l2prod rank
#define AMSREDAY
Definition: sstref.c:23
#define AMSRE3DN
Definition: sstref.c:26
float * lon
short ** allocate2d_short(size_t h, size_t w)
Allocate a two-dimensional array of type short of a given size.
Definition: allocate2d.c:97
float ** allocate2d_float(size_t h, size_t w)
Allocate a two-dimensional array of type float of a given size.
Definition: allocate2d.c:125
float get_ntev2(char *sstfile, float lon, float lat, int32_t year, int32_t day)
Definition: sstref.c:583
l2prod offset
logical function leap(YEAR)
Definition: leap.f:10
int i
Definition: decode_rs.h:71
float get_amsre(char *sstfile, float lon, float lat, float solz, int32_t xsatid, int32_t sensorID)
Definition: sstref.c:1007
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int32_t sensorID[MAXNFILES]
Definition: l2bin.cpp:97
#define OI4NX
Definition: sstref.c:1196
version
Definition: setup.py:15
#define OI1NX
Definition: sstref.c:1425