OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
ice_mask.c
Go to the documentation of this file.
1 #include "l12_proto.h"
2 
3 #define ICE_TYPE_OLD 0
4 #define ICE_TYPE_NSIDC 1
5 #define ICE_TYPE_OISST 2
6 
7 static int ice_initalized = 0;
8 static int ice_file_type = ICE_TYPE_OLD;
9 static float ice_threshold = 0;
10 
11 /***********************************************
12  *
13  * global variabls for the old ice mask
14  *
15  ***********************************************/
16 
17 #define NX 4096
18 #define NY 2048
19 
20 typedef char ice_t[NX];
21 static ice_t* ice;
22 
23 
24 /***********************************************
25  *
26  * global variables for NSIDC ice data
27  *
28  ***********************************************/
29 
30 #define NAMING_CONVENTION_REFERENCE \
31 "http://nsidc.org/data/docs/daac/nsidc0051_gsfc_seaice.gd.html#namingconvention"
32 
33 #define NROWS 448
34 #define NCOLS 304
35 #define SROWS 332
36 #define SCOLS 316
37 
38 #define RE 6378.273 /* Earth's equatorial radius */
39 #define EC 0.081816153 /* Eccentricity */
40 #define E2 0.006693883 /* Eccentricity squared */
41 #define SLAT 70.0 /* Standard latitude */
42 #define CELL 25.0 /* Stereographic pixel dimension (km) */
43 #define NODATA -1.0
44 
45 typedef unsigned char north_t[NCOLS];
46 static north_t* north;
47 
48 typedef unsigned char south_t[SCOLS];
49 static south_t* south;
50 
51 static double slat = 0.0, sinslat, tc, mc;
52 
53 
54 /***********************************************
55  *
56  * global variables for NSIDC the OISST ice data file.
57  *
58  ***********************************************/
59 
60 static size_t OI4NX = 1440;
61 static size_t OI4NY = 720;
62 
63 //typedef float iceref_t[OI4NX + 2];
64 static float **iceref;
65 
75 int ice_mask_init_old(char *file, int day, int32 sd_id) {
76  int32 sds_id;
77  int32 status;
78  int32 sds_index;
79  int32 rank;
80  int32 nt;
81  int32 dims[H4_MAX_VAR_DIMS];
82  int32 nattrs;
83  int32 start[2];
84  int32 edges[2];
85  char name[H4_MAX_NC_NAME];
86 
87  int16 ice_data[NX];
88  int16 mon = (int) day / 31; /* month of year (no need for perfection) */
89  int16 bit = pow(2, mon); /* bit mask associated with this month */
90  int16 i, j;
91 
92  // allocate ice global data
93  ice = (ice_t*) allocateMemory(NY * sizeof (ice_t), "ice");
94 
95  /* Get the SDS index */
96  sds_index = SDnametoindex(sd_id, "ice_mask");
97  if (sds_index == -1) {
98  printf("-E- %s: Error seeking ice_mask SDS from %s.\n",
99  __FILE__, file);
100  return (1);
101  }
102 
103  /* Select the SDS */
104  sds_id = SDselect(sd_id, sds_index);
105 
106  /* Verify the characteristics of the array */
107  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
108  if (status != 0) {
109  printf("-E- %s: Error reading SDS info for ice_mask from %s.\n",
110  __FILE__, file);
111  return (1);
112  }
113  if (dims[0] != NY || dims[1] != NX) {
114  printf("-E- %s: Dimension mis-match in ice_mask file %s.\n Expecting %d x %d\n Reading %d x %d\n",
115  __FILE__, file, NX, NY, (int) dims[1], (int) dims[0]);
116  return (1);
117  }
118 
119  for (j = 0; j < NY; j++) {
120 
121  /* Read one row from the array */
122  start[0] = j; /* row offset */
123  start[1] = 0; /* col offset */
124  edges[0] = 1; /* row count */
125  edges[1] = dims[1]; /* col count */
126 
127  status = SDreaddata(sds_id, start, NULL, edges, (VOIDP) ice_data);
128  if (status != 0) {
129  printf("-E- %s: Error reading SDS ice_mask from %s.\n",
130  __FILE__, file);
131  return (1);
132  }
133 
134  /* Set byte array for if monthly bit set in ice data */
135  for (i = 0; i < NX; i++)
136  ice[j][i] = (ice_data[i] & bit) > 0;
137  }
138 
139  /* Terminate access to the array */
140  status = SDendaccess(sds_id);
141 
142  printf("Loaded old ice climatology HDF file.\n");
143  return (0);
144 }
145 
146 char ice_mask_old(float lon, float lat) {
147  int16 i, j;
148 
149  i = MAX(MIN((int16) ((lon + 180.0) / 360.0 * NX), NX - 1), 0);
150  j = MAX(MIN((int16) ((90.0 - lat) / 180.0 * NY), NY - 1), 0);
151  return (ice[j][i]);
152 }
153 
154 float get_icefrac_old(float lon, float lat) {
155  if (ice_mask_old(lon, lat))
156  return 1.0;
157 
158  return 0.0;
159 }
160 
161 
162 #define COPYNAME(orig,copy){ \
163 (copy) = (char *)strdup( orig ); \
164 if( (copy) == NULL ){ \
165  fprintf(stderr,"-E- %s line %d: Memory allocation error\n", \
166  __FILE__,__LINE__); \
167  exit(EXIT_FAILURE); \
168 } \
169 }
170 
171 #define READIT(file,handle,rows,cols,array){ \
172 if( ( (handle) = fopen((file),"rb")) == NULL ){ \
173  fprintf(stderr,"-E- %s line %d: Could not open file, \"%s\" .\n", \
174  __FILE__,__LINE__,(file)); \
175  perror(""); \
176  exit(EXIT_FAILURE); \
177 } \
178 if( fseek( (handle) ,300,SEEK_SET) == -1 ){ \
179  fprintf(stderr, \
180  "-E- %s line %d: Could not skip header of file, \"%s\" .\n", \
181  __FILE__,__LINE__,(file)); \
182  perror(""); \
183  exit(EXIT_FAILURE); \
184 } \
185 if( \
186 fread((array), sizeof(unsigned char), (rows)*(cols), handle) \
187 != (rows)*(cols) \
188 ){ \
189  fprintf(stderr,"-E- %s line %d: Error reading file, \"%s\" .\n", \
190  __FILE__,__LINE__,(file)); \
191  perror(""); \
192  exit(EXIT_FAILURE); \
193 } \
194 }
195 
197 
198  /*
199  Read ice data from the north and south pole files the first time
200  this function is called and whenever the icefile name changes.
201  Subsequent calls just refer to ice values stored in static arrays.
202  */
203 
204  char *nfile, *sfile, *p;
205  FILE *fh;
206 
207  COPYNAME(file, nfile);
208  COPYNAME(file, sfile);
209 
210  // allocate global arrays
211  north = (north_t*) allocateMemory(NROWS * sizeof (north_t), "ice north");
212  south = (south_t*) allocateMemory(SROWS * sizeof (south_t), "ice south");
213 
214  /*
215  According to the file naming convention, the filename for the
216  north polar file has an 'n' immediately befor the last '.' in
217  the name; the south polar file has an 's' in the same position
218  with all other characters being the same. Both files are expected
219  to be present in the same directory.
220  */
221  p = strrchr(nfile, '.');
222  if (p == NULL || p <= nfile || (*(p - 1) != 'n' && *(p - 1) != 's')) {
223  printf("-E- %s line %d: ", __FILE__, __LINE__);
224  printf("File, \"%s\", doesn't follow naming convention described at %s .\n",
226  return 1;
227  }
228  --p;
229  *p = 'n';
230  p = strrchr(sfile, '.');
231  --p;
232  *p = 's';
233 
234  READIT(nfile, fh, NROWS, NCOLS, north);
235  fclose(fh);
236  free(nfile);
237 
238  READIT(sfile, fh, SROWS, SCOLS, south);
239  fclose(fh);
240  free(sfile);
241 
242  printf("Loaded raw NSIDC ice files.\n");
243  return 0;
244 }
245 
246 int ice_mask_init_monthly(char *file, int year, int day, int32 sd_id) {
247  int32 sds_id;
248  int32 status;
249  int32 sds_index;
250  int32 rank;
251  int32 nt;
252  int32 dims[H4_MAX_VAR_DIMS];
253  int32 nattrs;
254  int32 start[2];
255  int32 edges[2];
256  char name[H4_MAX_NC_NAME];
257  int32 startYear;
258  int32 endYear;
259 
260  int16 month, dom;
261 
262  char northName[32];
263  char southName[32];
264 
265  // allocate global arrays
266  north = (north_t*) allocateMemory(NROWS * sizeof (north_t), "ice north");
267  south = (south_t*) allocateMemory(SROWS * sizeof (south_t), "ice south");
268 
269  /* Find the file attribute named "start_year". */
270  if (SDreadattr(sd_id, SDfindattr(sd_id, "start_year"), (VOIDP) (&startYear))) {
271  printf("-E- %s: Error reading start_year from monthly file %s.\n",
272  __FILE__, file);
273  return 1;
274  }
275 
276  /* Find the file attribute named "end_year". */
277  if (SDreadattr(sd_id, SDfindattr(sd_id, "end_year"), (VOIDP) (&endYear))) {
278  printf("-E- %s: Error reading end_year from monthly file %s.\n",
279  __FILE__, file);
280  return 1;
281  }
282 
283  // if the requested year is not in the monthly file
284  // use the closest year avaliable
285 
286  if (year < startYear)
287  year = startYear;
288  if (year > endYear)
289  year = endYear;
290 
291  // create the data set name for the monthly data
292  yd2md(year, day, &month, &dom);
293  sprintf(northName, "ice_%d_%02d_north", year, month);
294  sprintf(southName, "ice_%d_%02d_south", year, month);
295 
296  //
297  // read north array
298  //
299 
300  /* Get the SDS index */
301  sds_index = SDnametoindex(sd_id, northName);
302  if (sds_index == -1) {
303  printf("-E- %s: Error seeking %s SDS from %s.\n",
304  __FILE__, northName, file);
305  return (1);
306  }
307 
308  /* Select the SDS */
309  sds_id = SDselect(sd_id, sds_index);
310 
311  /* Verify the characteristics of the array */
312  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
313  if (status != 0) {
314  printf("-E- %s: Error reading SDS info for %s from %s.\n",
315  __FILE__, northName, file);
316  return (1);
317  }
318  if (dims[0] != NROWS || dims[1] != NCOLS) {
319  printf("-E- %s: Dimension mis-match in %s file %s.\n",
320  __FILE__, northName, file);
321  printf(" Expecting %d x %d\n", NROWS, NCOLS);
322  printf(" Reading %d x %d\n", (int) dims[0], (int) dims[1]);
323  return (1);
324  }
325 
326  // read the north array
327  start[0] = 0; /* row offset */
328  start[1] = 0; /* col offset */
329  edges[0] = dims[0]; /* row count */
330  edges[1] = dims[1]; /* col count */
331 
332  status = SDreaddata(sds_id, start, NULL, edges, (VOIDP) north);
333  if (status != 0) {
334  printf("-E- %s: Error reading SDS %s from %s.\n",
335  __FILE__, northName, file);
336  return (1);
337  }
338 
339  /* Terminate access to the north array */
340  status = SDendaccess(sds_id);
341 
342  //
343  // read south array
344  //
345 
346  /* Get the SDS index */
347  sds_index = SDnametoindex(sd_id, southName);
348  if (sds_index == -1) {
349  printf("-E- %s: Error seeking %s SDS from %s.\n",
350  __FILE__, southName, file);
351  return (1);
352  }
353 
354  /* Select the SDS */
355  sds_id = SDselect(sd_id, sds_index);
356 
357  /* Verify the characteristics of the array */
358  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
359  if (status != 0) {
360  printf("-E- %s: Error reading SDS info for %s from %s.\n",
361  __FILE__, southName, file);
362  return (1);
363  }
364  if (dims[0] != SROWS || dims[1] != SCOLS) {
365  printf("-E- %s: Dimension mis-match in %s file %s.\n",
366  __FILE__, southName, file);
367  printf(" Expecting %d x %d\n", SROWS, SCOLS);
368  printf(" Reading %d x %d\n", (int) dims[0], (int) dims[1]);
369  return (1);
370  }
371 
372  // read the south array
373  start[0] = 0; /* row offset */
374  start[1] = 0; /* col offset */
375  edges[0] = dims[0]; /* row count */
376  edges[1] = dims[1]; /* col count */
377 
378  status = SDreaddata(sds_id, start, NULL, edges, (VOIDP) south);
379  if (status != 0) {
380  printf("-E- %s: Error reading SDS %s from %s.\n",
381  __FILE__, southName, file);
382  return (1);
383  }
384 
385  /* Terminate access to the south array */
386  status = SDendaccess(sds_id);
387 
388  printf("Loaded monthly NSIDC ice climatology HDF file.\n");
389  return 0;
390 }
391 
392 int ice_mask_init_daily(char *file, int year, int day, int32 sd_id) {
393  int32 sds_id;
394  int32 status;
395  int32 sds_index;
396  int32 rank;
397  int32 nt;
398  int32 dims[H4_MAX_VAR_DIMS];
399  int32 nattrs;
400  int32 start[2];
401  int32 edges[2];
402  char name[H4_MAX_NC_NAME];
403 
404  // allocate global arrays
405  north = (north_t*) allocateMemory(NROWS * sizeof (north_t), "ice north");
406  south = (south_t*) allocateMemory(SROWS * sizeof (south_t), "ice south");
407 
408  //
409  // read north array
410  //
411 
412  /* Get the SDS index */
413  sds_index = SDnametoindex(sd_id, "north");
414  if (sds_index == -1) {
415  printf("-E- %s: Error seeking north SDS from %s.\n", __FILE__, file);
416  return (1);
417  }
418 
419  /* Select the SDS */
420  sds_id = SDselect(sd_id, sds_index);
421 
422  /* Verify the characteristics of the array */
423  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
424  if (status != 0) {
425  printf("-E- %s: Error reading SDS info for north from %s.\n",
426  __FILE__, file);
427  return (1);
428  }
429  if (dims[0] != NROWS || dims[1] != NCOLS) {
430  printf("-E- %s: Dimension mis-match in north file %s.\n",
431  __FILE__, file);
432  printf(" Expecting %d x %d\n", NROWS, NCOLS);
433  printf(" Reading %d x %d\n", (int) dims[0], (int) dims[1]);
434  return (1);
435  }
436 
437  // read the north array
438  start[0] = 0; /* row offset */
439  start[1] = 0; /* col offset */
440  edges[0] = dims[0]; /* row count */
441  edges[1] = dims[1]; /* col count */
442 
443  status = SDreaddata(sds_id, start, NULL, edges, (VOIDP) north);
444  if (status != 0) {
445  printf("-E- %s: Error reading SDS north from %s.\n",
446  __FILE__, file);
447  return (1);
448  }
449 
450  /* Terminate access to the north array */
451  status = SDendaccess(sds_id);
452 
453  //
454  // read south array
455  //
456 
457  /* Get the SDS index */
458  sds_index = SDnametoindex(sd_id, "south");
459  if (sds_index == -1) {
460  printf("-E- %s: Error seeking south SDS from %s.\n", __FILE__, file);
461  return (1);
462  }
463 
464  /* Select the SDS */
465  sds_id = SDselect(sd_id, sds_index);
466 
467  /* Verify the characteristics of the array */
468  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
469  if (status != 0) {
470  printf("-E- %s: Error reading SDS info for south from %s.\n",
471  __FILE__, file);
472  return (1);
473  }
474  if (dims[0] != SROWS || dims[1] != SCOLS) {
475  printf("-E- %s: Dimension mis-match in south file %s.\n",
476  __FILE__, file);
477  printf(" Expecting %d x %d\n", SROWS, SCOLS);
478  printf(" Reading %d x %d\n", (int) dims[0], (int) dims[1]);
479  return (1);
480  }
481 
482  // read the south array
483  start[0] = 0; /* row offset */
484  start[1] = 0; /* col offset */
485  edges[0] = dims[0]; /* row count */
486  edges[1] = dims[1]; /* col count */
487 
488  status = SDreaddata(sds_id, start, NULL, edges, (VOIDP) south);
489  if (status != 0) {
490  printf("-E- %s: Error reading SDS south from %s.\n",
491  __FILE__, file);
492  return (1);
493  }
494 
495  /* Terminate access to the south array */
496  status = SDendaccess(sds_id);
497 
498  printf("Loaded near real time NSIDC ice HDF file.\n");
499  return 0;
500 }
501 
502 float get_icefrac_nsidc(float lon, float lat) {
503 
504  double sinlat, t, rho, x, y, ii, jj, i, j, u, v, d[4], sum, interp;
505  float delta, xdist, ydist;
506  int sgn, rows, cols, ix, jy, cnt, n;
507  unsigned char *data;
508 
509 
510  if (lat >= 90 || lat <= -90) {
511  return 0.0;
512  }
513 
514  /*
515  The north polar stereographic projection has the 45 West meridian
516  running vertically from pole to bottom center; the south polar
517  stereographic projection has the 0 meridian running vertically
518  from pole to top center.
519  */
520  if (lat >= 0) {
521  delta = 45;
522  sgn = 1;
523  xdist = 3850.0; /* distance from pole to left edge */
524  ydist = 5350.0; /* distance from pole to bottom edge */
525  rows = NROWS;
526  cols = NCOLS;
527  data = &north[0][0];
528  } else {
529  delta = 0;
530  sgn = -1;
531  lat = -lat;
532  xdist = 3950.0; /* distance from pole to left edge */
533  ydist = 3950.0; /* distance from pole to bottom edge */
534  rows = SROWS;
535  cols = SCOLS;
536  data = &south[0][0];
537  }
538 
539  while (lon < 0) lon += 360;
540  while (lon > 360) lon -= 360;
541 
542  lon += delta;
543 
544  /* Convert input coordinates to radians. */
545  lat *= PI / 180;
546  lon *= PI / 180;
547 
548  sinlat = sin((double) lat);
549 
550  /*
551  The FORTRAN routines from the sidads.colorado.edu site use the
552  ellipsoidal form of the stereographic projection equations, so
553  I use them here as well; however, I think this may be a bit of
554  overkill at 25-kilometer resolution.
555  */
556 
557  /*
558  Equation 15-9 from page 161 of
559  Map Projections -- A Working Manual
560  John P. Snyder
561  U.S. Geological Survey Professional Paper 1395
562  Fourth Printing 1997
563  */
564  t = tan((double) (PI / 4 - lat / 2))
565  / pow((double) ((1 - EC * sinlat) / (1 + EC * sinlat)), (double) (EC / 2));
566 
567  /*
568  The variables, tc and mc, are derived from the latitude of true
569  scale, slat, and do not depend on the input parameters, so I only
570  need to compute them once. Actually, I could just replace these
571  by constants, but the following lines make it clearer where the
572  constants come from.
573  */
574  if (slat == 0.0) {
575  slat = SLAT * PI / 180;
576  sinslat = sin(slat);
577 
578  /*
579  Equation 15-9 from page 161 of aforementioned publication.
580  */
581  tc = tan((double) (PI / 4 - slat / 2))
582  / pow((double) ((1 - EC * sinslat) / (1 + EC * sinslat)), (double) (EC / 2));
583 
584  /*
585  Equation 14-15 from page 101 of aforementioned publication.
586  */
587  mc = cos((double) slat) / sqrt((double) (1 - E2 * sinslat * sinslat));
588  }
589 
590  /*
591  Equation 21-34 from page 161 of aforementioned publication.
592  */
593  rho = RE * mc * t / tc;
594 
595  /*
596  Equations 21-30 and 21-31 from page 161 of aforementioned publication.
597  */
598  x = rho * sgn * sin((double) (sgn * lon));
599  y = -rho * sgn * cos((double) (sgn * lon));
600 
601  ii = (x + xdist - CELL / 2) / (CELL);
602  jj = rows - (y + ydist - CELL / 2) / (CELL);
603 
604  /*
605  Interpolate data from ice-cover files to get ice fraction
606  at the specified coordinate. Make sure to handle cases
607  where data is flagged as missing (value > 250) for one
608  reason or another. Also handle cases where input coordinate
609  maps outside of the area covered by the ice data files.
610  */
611 
612  if (ii < 0 || ii > cols || jj < 0 || jj > rows) {
613  /*
614  The input coordinate pair was outside of the areas
615  represented by the northern and southern data files.
616  */
617  return 0;
618  }
619 
620  d[0] = *(data + (int) jj * cols + (int) ii);
621  if (d[0] > 250) {
622  /*
623  The input coordinate pair mapped to a pixel that
624  is marked as something other than an ice fraction.
625  */
626  return 0.0;
627  }
628 
629  /*
630  Choose the 4 pixels whose centers mark the corners of a
631  square that encloses the user's specified input coordinate.
632  Put the values of the 4 pixels in the array, d.
633  */
634  u = modf(ii, &i);
635  v = modf(jj, &j);
636 
637  if (u < 0.5) {
638  i--;
639  u += 0.5;
640  } else {
641  u -= 0.5;
642  }
643  if (v < 0.5) {
644  j--;
645  v += 0.5;
646  } else {
647  v -= 0.5;
648  }
649  sum = 0;
650  cnt = 0;
651  n = 0;
652  for (jy = j; jy < j + 2; jy++) {
653  for (ix = i; ix < i + 2; ix++) {
654  if (ix >= 0 && ix < cols && jy >= 0 && jy < rows) {
655 
656  /*
657  This pixel is within the bounds of the
658  reference array, so store its value.
659  */
660  d[n] = *(data + jy * cols + ix);
661 
662  if (d[n] <= 250) {
663  /*
664  This is a valid value so include it in the mean that
665  will be used to fill in flagged or out-of-bound pixels.
666  */
667  sum += d[n];
668  cnt++;
669  }
670  } else {
671  /*
672  Use a flag value of 255 to indicate
673  that this pixel is out of bounds.
674  */
675  d[n] = 255;
676  }
677  n++;
678  }
679  }
680  for (n = 0; n < 4; n++) {
681  /*
682  Replace missing values with mean of other non-missing values.
683  This only affects pixels adjacent to the one the actually
684  contains the desired Earth coordinate. If the desired coordinate
685  did not fall within a valid ice pixel, then this function already
686  returned a NODATA value higher up in the code.
687  */
688  if (d[n] > 250) {
689  d[n] = sum / cnt;
690  }
691  }
692 
693  /* Bi-linear interpolation. */
694  interp = (1 - u)*(1 - v) * d[0]
695  + u * (1 - v) * d[1]
696  + (1 - u) * v * d[2]
697  + u * v * d[3];
698 
699  return (float) (interp / 250.0);
700 }
701 
702 char ice_mask_nsidc(float lon, float lat) {
703  if (get_icefrac_nsidc(lon, lat) > ice_threshold)
704  return 1;
705  else
706  return 0;
707 }
708 
709 /* ------------------------------------------------------------------ *
710  * read and interpolate Reynolds 0.25-deg daily V2 netcdf OI files
711  *
712  * return 0 if OK or 1 if error *
713  * ------------------------------------------------------------------ */
714 int ice_init_oisst(char *icefile) {
715 
716  int i, j, ii;
717  char* varName = "ice";
718  int ncid, ndims, nvars, ngatts, unlimdimid;
719  int rotateLon = 1;
720  int varid;
721  size_t length;
722  float slope;
723  float offset;
724 
725 
726  if (nc_open(icefile, NC_NOWRITE, &ncid) != NC_NOERR) {
727  return 1;
728  }
729 
730  if (nc_inq(ncid, &ndims, &nvars, &ngatts, &unlimdimid) != NC_NOERR) {
731  nc_close(ncid);
732  return 1;
733  }
734 
735  if (nc_inq_attlen(ncid, NC_GLOBAL, "title", &length) != NC_NOERR) {
736  nc_close(ncid);
737  return 1;
738  }
739  char titleStr[length + 2];
740  if (nc_get_att_text(ncid, NC_GLOBAL, "title", titleStr) != NC_NOERR) {
741  nc_close(ncid);
742  return 1;
743  }
744  titleStr[length] = 0;
745 
746  if (strstr(titleStr, "Daily-OI") ||
747  strstr(titleStr, "NOAA/NCEI 1/4 Degree Daily Optimum Interpolation Sea Surface Temperature (OISST) Analysis")) {
748  printf("Loading Daily V2 0.25-deg OISST Ice field from %s\n\n", icefile);
749  } else if (strstr(titleStr, "CMC")) {
750  varName = "sea_ice_fraction";
751  rotateLon = 0;
752  int XdimID, YdimID;
753  nc_inq_dimid(ncid, "lat", &YdimID);
754  nc_inq_dimlen(ncid, YdimID, &OI4NY);
755  nc_inq_dimid(ncid, "lon", &XdimID);
756  nc_inq_dimlen(ncid, XdimID, &OI4NX);
757  printf("Loading Daily CMC Ice field from %s\n\n", icefile);
758  } else {
759  nc_close(ncid);
760  return 1;
761  }
762 
763  if (nc_inq_varid(ncid, varName, &varid) != NC_NOERR) {
764  nc_close(ncid);
765  return 1;
766  }
767 
768  // Allocate space for the ice data array
769  static short **icetmp;
770  if (iceref == NULL){
771  iceref = allocate2d_float(OI4NY+2, OI4NX+2);
772  icetmp = allocate2d_short(OI4NY, OI4NX);
773  }
774 // typedef int16 icetmp_t[OI4NX];
775 // icetmp_t *icetmp;
776 // icetmp = (icetmp_t*) malloc(OI4NY * sizeof (icetmp_t));
777 
778  /* Read the data. */
779  if (nc_get_var_short(ncid, varid, &icetmp[0][0]) != NC_NOERR) {
780  fprintf(stderr, "-E- %s line %d: Error reading %s from %s.\n",
781  __FILE__, __LINE__, varName, icefile);
782  exit(EXIT_FAILURE);
783  }
784 
785  if (nc_get_att_float(ncid, varid, "scale_factor", &slope) != NC_NOERR) {
786  fprintf(stderr, "-E- %s line %d: error reading scale factor.\n",
787  __FILE__, __LINE__);
788  exit(EXIT_FAILURE);
789  }
790 
791  if (nc_get_att_float(ncid, varid, "add_offset", &offset) != NC_NOERR) {
792  fprintf(stderr, "-E- %s line %d: error reading scale offset.\n",
793  __FILE__, __LINE__);
794  exit(EXIT_FAILURE);
795  }
796  nc_close(ncid);
797 
798  /* rotate 180-deg and add wrapping border to simplify interpolation */
799  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
800  for (j = 0; j < OI4NY; j++) {
801  for (i = 0; i < OI4NX; i++) {
802  if (rotateLon) {
803  ii = (i < OI4NX / 2) ? i + OI4NX / 2 : i - OI4NX / 2;
804  } else {
805  ii = i;
806  }
807  if (icetmp[j][i] > -999)
808  iceref[j + 1][ii + 1] = icetmp[j][i] * slope + offset;
809  else
810  iceref[j + 1][ii + 1] = BAD_FLT;
811  }
812  iceref[j + 1][0] = iceref[j + 1][OI4NX];
813  iceref[j + 1][OI4NX + 1] = iceref[j + 1][1];
814  }
815  for (i = 0; i < OI4NX + 2; i++) {
816  iceref[0][i] = iceref[1][i];
817  iceref[OI4NY + 1][i] = iceref[OI4NY][i];
818  }
819 
820  free2d_short(icetmp);
821  return 0;
822 }
823 
824 float get_icefrac_oisst(float lon, float lat) {
825  float dx = 360.0 / OI4NX;
826  float dy = 180.0 / OI4NY;
827 
828  float ice = 0;
829  int i, j;
830  int ntmp;
831  float xx, yy;
832  float t, u;
833  float reftmp[2][2];
834  float ftmp;
835 
836 
837  /* locate LL position within reference grid */
838  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), OI4NX + 1), 0);
839  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), OI4NY + 1), 0);
840 
841  /* compute longitude and latitude of that grid element */
842  xx = i * dx - 180.0 - dx / 2;
843  yy = j * dy - 90.0 - dy / 2;
844 
845  /* bilinearly interpolate, replacing missing (land) values with average of valid values in box */
846  t = (lon - xx) / dx;
847  u = (lat - yy) / dy;
848 
849  ftmp = 0.0;
850  ntmp = 0;
851  if (iceref[j ][i ] > BAD_FLT + 1) {
852  ftmp += iceref[j ][i ];
853  ntmp++;
854  }
855  if (iceref[j ][i + 1] > BAD_FLT + 1) {
856  ftmp += iceref[j ][i + 1];
857  ntmp++;
858  }
859  if (iceref[j + 1][i + 1] > BAD_FLT + 1) {
860  ftmp += iceref[j + 1][i + 1];
861  ntmp++;
862  }
863  if (iceref[j + 1][i ] > BAD_FLT + 1) {
864  ftmp += iceref[j + 1][i ];
865  ntmp++;
866  }
867  if (ntmp > 0) {
868  ftmp /= ntmp;
869  reftmp[0][0] = (iceref[j ][i ] > BAD_FLT + 1 ? iceref[j ][i ] : ftmp);
870  reftmp[0][1] = (iceref[j ][i + 1] > BAD_FLT + 1 ? iceref[j ][i + 1] : ftmp);
871  reftmp[1][1] = (iceref[j + 1][i + 1] > BAD_FLT + 1 ? iceref[j + 1][i + 1] : ftmp);
872  reftmp[1][0] = (iceref[j + 1][i ] > BAD_FLT + 1 ? iceref[j + 1][i ] : ftmp);
873 
874  ice = (1 - t)*(1 - u) * reftmp[0][0] + t * (1 - u) * reftmp[0][1] + t * u * reftmp[1][1] + (1 - t) * u * reftmp[1][0];
875 
876  } else
877  ice = 0;
878 
879  return (ice);
880 }
881 
882 char ice_mask_oisst(float lon, float lat) {
883  if (get_icefrac_oisst(lon, lat) > ice_threshold)
884  return 1;
885  else
886  return 0;
887 }
888 
889 /*************************************************************
890  * init the ice mask functions.
891  *
892  * file - file name of the ice data file
893  * year - year of the ice file
894  * day - day of year
895  * threshold - ice fraction above which the ice mask returns 1
896  *
897  * return 0 if OK or 1 if error
898  *
899  *************************************************************/
900 int ice_mask_init(char *file, int year, int day, float threshold) {
901  int32 sd_id;
902  int32 attr_index;
903  int32 status;
904  int result = 1;
905  char titleStr[256] = "";
906 
907  ice_initalized = 0;
908  ice_file_type = ICE_TYPE_OLD;
909 
910  // set the threshold global variable
911  ice_threshold = threshold;
912 
913  if (Hishdf(file)) {
914  /* Open the file and initiate the SD interface */
915  sd_id = SDstart(file, DFACC_RDONLY);
916  if (sd_id == -1) {
917  fprintf(stderr, "-E- %s line %d: Could not open %s as an HDF file.\n",
918  __FILE__, __LINE__, file);
919  return (HDF_FUNCTION_ERROR);
920  }
921  // look for the global attribute "Title"
922  attr_index = SDfindattr(sd_id, "Title");
923  if (attr_index == -1) {
924 
925  // Title not found, assume it is an old ice HDF climatolgy file
926  result = ice_mask_init_old(file, day, sd_id);
927  if (result == 0) {
928  ice_initalized = 1;
929  ice_file_type = ICE_TYPE_OLD;
930  }
931  SDend(sd_id);
932  return (result);
933  }
934 
935  // Read the attribute data.
936  status = SDreadattr(sd_id, attr_index, titleStr);
937  if (status == FAIL) {
938  fprintf(stderr, "-E- %s line %d: Could not read the global attribute \"Title\" from, %s .\n",
939  __FILE__, __LINE__, file);
940  SDend(sd_id);
941  return (1);
942  }
943 
944  // check title to which type of file it is
945  if (strcmp(titleStr, "Sea Ice Concentration Daily") == 0) {
946  result = ice_mask_init_daily(file, year, day, sd_id);
947  ice_file_type = ICE_TYPE_NSIDC;
948  } else if (strcmp(titleStr, "Sea Ice Concentration Monthly") == 0) {
950  ice_file_type = ICE_TYPE_NSIDC;
951  } else {
952  fprintf(stderr, "-E- %s line %d: Global attribute \"Title\" not valid from, %s .\n",
953  __FILE__, __LINE__, file);
954  result = 1;
955  }
956 
957  if (result == 0)
958  ice_initalized = 1;
959  SDend(sd_id);
960  return result;
961  } // is HDF
962 
963  /* try netCDF */
964  int ncid;
965  if (nc_open(file, NC_NOWRITE, &ncid) == NC_NOERR) {
966  nc_close(ncid);
968  if (result == 0) {
969  ice_initalized = 1;
970  ice_file_type = ICE_TYPE_OISST;
971  }
972  return result;
973  }
974 
975  // if the file is not an HDF or NetCDF file then try to open it
976  // as a raw NSIDC file
978  if (result == 0) {
979  ice_initalized = 1;
980  ice_file_type = ICE_TYPE_NSIDC;
981  }
982  return ( result);
983 
984 }
985 
993 char ice_mask(float lon, float lat) {
994  if (!ice_initalized)
995  return 0;
996 
997  switch (ice_file_type) {
998  case ICE_TYPE_OLD:
999  return ice_mask_old(lon, lat);
1000  case ICE_TYPE_NSIDC:
1001  return ice_mask_nsidc(lon, lat);
1002  case ICE_TYPE_OISST:
1003  return ice_mask_oisst(lon, lat);
1004  default:
1005  fprintf(stderr, "-E- %s line %d: Ice file type=%d is invalid.\n",
1006  __FILE__, __LINE__, ice_file_type);
1007  exit(EXIT_FAILURE);
1008  }
1009 }
1010 
1018 float ice_fraction(float lon, float lat) {
1019  if (!ice_initalized)
1020  return NODATA;
1021 
1022  switch (ice_file_type) {
1023  case ICE_TYPE_OLD:
1024  return get_icefrac_old(lon, lat);
1025  case ICE_TYPE_NSIDC:
1026  return get_icefrac_nsidc(lon, lat);
1027  case ICE_TYPE_OISST:
1028  return get_icefrac_oisst(lon, lat);
1029  default:
1030  fprintf(stderr, "-E- %s line %d: Ice file type=%d is invalid.\n",
1031  __FILE__, __LINE__, ice_file_type);
1032  exit(EXIT_FAILURE);
1033  }
1034 }
1035 
char ice_mask_old(float lon, float lat)
Definition: ice_mask.c:146
void interp(double *ephemPtr, int startLoc, double *inTime, int numCoefs, int numCom, int numSets, int velFlag, double *posvel)
#define MAX(A, B)
Definition: swl0_utils.h:26
int ice_mask_init_daily(char *file, int year, int day, int32 sd_id)
Definition: ice_mask.c:392
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
unsigned char north_t[NCOLS]
Definition: ice_mask.c:45
#define NROWS
Definition: ice_mask.c:33
int j
Definition: decode_rs.h:73
float get_icefrac_oisst(float lon, float lat)
Definition: ice_mask.c:824
int32_t day
int status
Definition: l1_czcs_hdf.c:32
#define SLAT
Definition: ice_mask.c:41
#define ICE_TYPE_OLD
Definition: ice_mask.c:3
#define FAIL
Definition: ObpgReadGrid.h:18
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define NCOLS
Definition: ice_mask.c:34
#define NULL
Definition: decode_rs.h:63
#define COPYNAME(orig, copy)
Definition: ice_mask.c:162
int ice_mask_init_old(char *file, int day, int32 sd_id)
Definition: ice_mask.c:75
#define ICE_TYPE_OISST
Definition: ice_mask.c:5
int ice_mask_init_nsidc_raw(char *file)
Definition: ice_mask.c:196
#define NX
Definition: ice_mask.c:17
#define OI4NY
Definition: sstref.c:1197
float * lat
#define CELL
Definition: ice_mask.c:42
float get_icefrac_nsidc(float lon, float lat)
Definition: ice_mask.c:502
#define RE
Definition: ice_mask.c:38
void free2d_short(short **p)
Free a two-dimensional array created by allocate2d_short.
Definition: allocate2d.c:114
float get_icefrac_old(float lon, float lat)
Definition: ice_mask.c:154
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
#define PI
Definition: l3_get_org.c:6
#define EC
Definition: ice_mask.c:39
void yd2md(int16_t year, int16_t doy, int16_t *month, int16_t *dom)
Definition: yd2md.c:6
char ice_mask_nsidc(float lon, float lat)
Definition: ice_mask.c:702
int ice_mask_init(char *file, int year, int day, float threshold)
Definition: ice_mask.c:900
#define NY
Definition: ice_mask.c:18
#define SCOLS
Definition: ice_mask.c:36
#define SROWS
Definition: ice_mask.c:35
#define E2
Definition: ice_mask.c:40
float32 slope[]
Definition: l2lists.h:30
int ice_init_oisst(char *icefile)
Definition: ice_mask.c:714
const double delta
char ice_mask(float lon, float lat)
Definition: ice_mask.c:993
#define READIT(file, handle, rows, cols, array)
Definition: ice_mask.c:171
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
unsigned char south_t[SCOLS]
Definition: ice_mask.c:48
#define BAD_FLT
Definition: jplaeriallib.h:19
size_t n
Definition: gsm.c:67
float ice_fraction(float lon, float lat)
Definition: ice_mask.c:1018
data_t u
Definition: decode_rs.h:74
int ice_mask_init_monthly(char *file, int year, int day, int32 sd_id)
Definition: ice_mask.c:246
Extra metadata that will be written to the HDF4 file l2prod rank
float * lon
#define NODATA
Definition: ice_mask.c:43
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
l2prod offset
#define ICE_TYPE_NSIDC
Definition: ice_mask.c:4
int i
Definition: decode_rs.h:71
#define NAMING_CONVENTION_REFERENCE
Definition: ice_mask.c:30
#define OI4NX
Definition: sstref.c:1196
char ice_t[NX]
Definition: ice_mask.c:20
#define HDF_FUNCTION_ERROR
Definition: passthebuck.h:7
float p[MODELMAX]
Definition: atrem_corl1.h:131
char ice_mask_oisst(float lon, float lat)
Definition: ice_mask.c:882