OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
sssref.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <unistd.h>
3 
4 /* ============================================================================ */
5 /* module sssref.c - retrieve salinity from WOA climatology */
6 /* ============================================================================ */
7 
8 #include "l12_proto.h"
9 #include "h5io.h"
10 
11 static float sssbad = BAD_FLT;
12 static int32_t format = -1;
13 
14 
15 /* ----------------------------------------------------------------------------------- */
16 /* get_woasssclim() - read and interpolate WOA salinity climatology */
17 /* ----------------------------------------------------------------------------------- */
18 
19 #define WOASSSNX 360
20 #define WOASSSNY 180
21 
22 float get_woasssclim(char *sssfile, float lon, float lat, int day) {
23  static int firstCall = 1;
24  static int nx = WOASSSNX;
25  static int ny = WOASSSNY;
26  static float dx = 360.0 / WOASSSNX;
27  static float dy = 180.0 / WOASSSNY;
28 
29  typedef float sssref_t[WOASSSNX + 2];
30  static sssref_t* sssref;
31  static sssref_t* sss_sav;
32  //static float sssref[WOASSSNY+2][WOASSSNX+2];
33  //static float sss_sav[WOASSSNY+2][WOASSSNX+2];
34 
35  float sss = sssbad;
36  int i, j, ii;
37  float xx, yy;
38  float t, u;
39 
40  if (firstCall) {
41  sssref = (sssref_t*) malloc((WOASSSNY + 2) * sizeof (sssref_t));
42  sss_sav = (sssref_t*) malloc((WOASSSNY + 2) * sizeof (sssref_t));
43 
44  float ssstmp[WOASSSNY][WOASSSNX];
45  char name [H4_MAX_NC_NAME] = "";
46  char sdsname[H4_MAX_NC_NAME] = "";
47  int32 sd_id;
48  int32 sds_id;
49  int32 rank;
50  int32 nt;
51  int32 dims[H4_MAX_VAR_DIMS];
52  int32 nattrs;
53  int32 start[4] = {0, 0, 0, 0};
54  int32 status, ix, iy, ct;
55  int32 lymin, lxmin, lymax, lxmax;
56  float sum;
57 
58  int16 mon = (int) day / 31 + 1; // month of year (no need for perfection)
59 
60  firstCall = 0;
61 
62  printf("Loading SSS reference from Climatology file: %s\n", sssfile);
63  printf("\n");
64 
65  /* Open the file */
66  sd_id = SDstart(sssfile, DFACC_RDONLY);
67  if (sd_id == FAIL) {
68  fprintf(stderr, "-E- %s line %d: error reading %s.\n",
69  __FILE__, __LINE__, sssfile);
70  exit(1);
71  }
72 
73  /* Get the SDS index */
74  sprintf(sdsname, "sss%2.2i", mon);
75  sds_id = SDselect(sd_id, SDnametoindex(sd_id, sdsname));
76  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
77  status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) & ssstmp[0][0]);
78  if (status != 0) {
79  fprintf(stderr, "-E- %s Line %d: Error reading SDS %s from %s.\n",
80  __FILE__, __LINE__, sdsname, sssfile);
81  exit(1);
82  }
83  status = SDendaccess(sds_id);
84  status = SDend(sd_id);
85 
86  /* rotate 180-deg and add wrapping border to simplify interpolation */
87  /* new grid is -180.5,180.5 in i=0,361 and -90.5,90.5 in j=0,181 */
88 
89  for (j = 0; j < ny; j++) {
90  for (i = 0; i < nx; i++) {
91  ii = (i < nx / 2) ? i + nx / 2 : i - nx / 2;
92  if (ssstmp[j][i] > 0)
93  sssref[j + 1][ii + 1] = ssstmp[j][i];
94  else
95  sssref[j + 1][ii + 1] = sssbad;
96  }
97  sssref[j + 1][0] = sssref[j + 1][nx];
98  sssref[j + 1][nx + 1] = sssref[j + 1][1];
99  }
100  for (i = 0; i < nx + 2; i++) {
101  sssref[0] [i] = sssref[1][i];
102  sssref[ny + 1][i] = sssref[ny][i];
103  }
104  /*
105  * Extend the grid by 1 point (use only full grid boxes later)
106  */
107  memcpy(sss_sav, sssref,
108  (WOASSSNY + 2) * (WOASSSNX + 2) * sizeof ( float));
109  for (iy = 0; iy < ny + 2; iy++) {
110  lymin = (iy == 0) ? 0 : iy - 1;
111  lymax = (iy == ny + 1) ? ny + 1 : iy + 1;
112 
113  for (ix = 0; ix < nx + 2; ix++) {
114  if (sssref[iy][ix] < sssbad + 1) {
115  lxmin = (ix == 0) ? 0 : ix - 1;
116  lxmax = (ix == nx + 1) ? nx + 1 : ix + 1;
117 
118  sum = 0.;
119  ct = 0;
120  for (j = lymin; j < lymax + 1; j++)
121  for (i = lxmin; i < lxmax + 1; i++) {
122  if (sss_sav[j][i] > sssbad + 1) {
123  sum += sss_sav[j][i];
124  ct++;
125  }
126  }
127  if (ct > 0)
128  sssref[iy][ix] = sum / ct;
129  }
130  }
131  }
132  } /* end 1-time grid set up */
133 
134  /* locate LL position within reference grid */
135  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), WOASSSNX + 1), 0);
136  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), WOASSSNY + 1), 0);
137 
138  /* compute longitude and latitude of that grid element */
139  xx = i * dx - 180.0 - dx / 2;
140  yy = j * dy - 90.0 - dy / 2;
141 
142  /* bilinearly interpolate, only using full grid boxes */
143  t = (lon - xx) / dx;
144  u = (lat - yy) / dy;
145 
146  if ((sssref[j][i] > sssbad + 1) && (sssref[j][i + 1] > sssbad + 1) &&
147  (sssref[j + 1][i] > sssbad + 1) && (sssref[j + 1][i + 1] > sssbad + 1)) {
148 
149  sss = (1 - t)*(1 - u) * sssref[j ][i ]
150  + t * (1 - u) * sssref[j ][i + 1]
151  + t * u * sssref[j + 1][i + 1]
152  + (1 - t) * u * sssref[j + 1][i ];
153 
154  } else
155  sss = sssbad;
156 
157  return (sss);
158 }
159 
160 /*
161  * for the HYCOM file usage...
162  */
163 #define HYCOMNX 1440
164 #define HYCOMNY 720
165 
166 float get_hycom_sss(char *sssfile, float lon, float lat, float *sss)
167 /*******************************************************************
168 
169  get_hycom_sss
170 
171  purpose: read in the daiy HYCOM sss and give the interpolated value
172  for the input lat, lon
173 
174  Returns type: int - return status: 0 is good, 1 if any other error
175  will fail with -1 status if an h5 io error found (not associated with
176  the file not being h5 or correct format of h5)
177 
178  Parameters: (in calling order)
179  Type Name I/O Description
180  ---- ---- --- -----------
181  char * sssfile I sss file name
182  float lon I longitude: -180 -> 180
183  float lat I latitude: -90 -> 90
184  float * sss O sss found - will be sssbad
185  if over land or otherwise
186  bad value
187 
188  Modification history:
189  Programmer Date Description of change
190  ---------- ---- ---------------------
191  W. Robinson, SAIC 12 Oct 2012 adapted from get_woasssclim in this file
192  W. Robinson, SAIC 16 Oct 2012 this version 2 will interpolate using
193  0 for any missing data
194 
195  Note that the HYCOM file only contains a dataset of salinity, so
196  the size of 1440, 720 probably should be an ID requirement as is the
197  existance of the dataset name 'salinity'
198 
199  *******************************************************************/ {
200  static int firstCall = 1;
201  static int nx = HYCOMNX;
202  static int ny = HYCOMNY;
203  static float dx = 360.0 / HYCOMNX;
204  static float dy = 180.0 / HYCOMNY;
205 
206  typedef float sssref_t[ HYCOMNX + 2 ];
207  static sssref_t* sssref;
208  static sssref_t* sss_sav;
209  //static float sssref[ HYCOMNY + 2 ][ HYCOMNX + 2 ];
210  //static float sss_sav[ HYCOMNY + 2 ][ HYCOMNX + 2 ];
211 
212  int i, j, iter_ct, iter_max;
213  float t, u, xx, yy;
214 
215  *sss = sssbad;
216  if (firstCall) {
217  sssref = (sssref_t*) malloc((HYCOMNY + 2) * sizeof (sssref_t));
218  sss_sav = (sssref_t*) malloc((HYCOMNY + 2) * sizeof (sssref_t));
219  float ssstmp[ny][nx], sum;
220  h5io_str fid, dsid, grpid;
221  int nobj, *types, ndim, dim_siz[10], sto_len, ix, iy, ct;
222  int lymin, lxmin, lymax, lxmax;
223  char **o_names;
224  H5T_class_t class;
225  hid_t native_typ;
226 
227  firstCall = 0;
228 
229  printf("Loading SSS reference from HYCOM file: %s\n", sssfile);
230  printf("\n");
231 
232  /*
233  * check the file to see that it is correct - just return to caller if
234  * not right format, but exit if something that should be performed can't be
235  */
236  if (h5io_openr(sssfile, 0, &fid) != 0)
237  return 1;
238  /* the group may need setting to work, see if '/' will do */
239  if (h5io_set_grp(&fid, "/", &grpid) != 0) {
240  fprintf(stderr, "-E- %s, %d: Failed to set trivial group\n",
241  __FILE__, __LINE__);
242  exit(-1);
243  }
244  if (h5io_grp_contents(&grpid, &nobj, &o_names, &types) != 0) {
245  fprintf(stderr, "-E- %s, %d: Failed to find contents of sss file\n",
246  __FILE__, __LINE__);
247  exit(-1);
248  }
249  /* first name should be salinity */
250  if (strcmp(o_names[0], "salinity") != 0)
251  return 1;
252 
253  /* set to the salinity dataset and get info */
254  if (h5io_set_ds(&fid, "salinity", &dsid) != 0)
255  return 1;
256  if (h5io_info(&dsid, NULL, &class, &native_typ, &ndim, dim_siz,
257  &sto_len) != 0) {
258  fprintf(stderr, "-E- %s, %d: Failed to find info on salinity dataset\n",
259  __FILE__, __LINE__);
260  exit(-1);
261  }
262 
263  if ((ndim != 2) || (dim_siz[0] != 720) || (dim_siz[1] != 1440))
264  return 1;
265  /*
266  * at this point, we have identified the salinity file, just read
267  * the dataset now
268  */
269  if (h5io_rd_ds(&dsid, (void *) ssstmp) != 0) {
270  fprintf(stderr, "-E- %s, %d: Failed to read salinity dataset\n",
271  __FILE__, __LINE__);
272  exit(-1);
273  }
274  /* close and go */
275  h5io_close(&dsid);
276  h5io_close(&fid);
277 
278  /* add wrapping border to simplify interpolation */
279  /* new grid is -180.125,180.125 in i=0,1441 and -90.125,90.125 in j=0,721 */
280  for (j = 0; j < ny; j++) {
281  for (i = 0; i < nx; i++) {
282  if ((ssstmp[j][i] > 0) && (ssstmp[j][i] <= 1000.))
283  sssref[j + 1][i + 1] = ssstmp[j][i];
284  else
285  sssref[j + 1][i + 1] = sssbad;
286  }
287  sssref[j + 1][0] = sssref[j + 1][nx];
288  sssref[j + 1][nx + 1] = sssref[j + 1][1];
289  }
290  for (i = 0; i < nx + 2; i++) {
291  sssref[0] [i] = sssref[1][i];
292  sssref[ny + 1][i] = sssref[ny][i];
293  }
294  /*
295  * extend data to have good interpolation points at edge = coast
296  */
297  iter_ct = 0;
298  iter_max = 4;
299  do {
300  iter_ct++;
301  memcpy(sss_sav, sssref,
302  (HYCOMNY + 2) * (HYCOMNX + 2) * sizeof ( float));
303  for (iy = 0; iy < ny + 2; iy++) {
304  lymin = (iy == 0) ? 0 : iy - 1;
305  lymax = (iy == ny + 1) ? ny + 1 : iy + 1;
306 
307  for (ix = 0; ix < nx + 2; ix++) {
308  if (sssref[iy][ix] < sssbad + 1) {
309  lxmin = (ix == 0) ? 0 : ix - 1;
310  lxmax = (ix == nx + 1) ? nx + 1 : ix + 1;
311 
312  sum = 0.;
313  ct = 0;
314  for (j = lymin; j < lymax + 1; j++)
315  for (i = lxmin; i < lxmax + 1; i++) {
316  if (sss_sav[j][i] > sssbad + 1) {
317  sum += sss_sav[j][i];
318  ct++;
319  }
320  }
321  if (ct > 0)
322  sssref[iy][ix] = sum / ct;
323  }
324  }
325  }
326  } while (iter_ct < iter_max);
327  /* and end set up */
328  }
329 
330  /* locate LL position within reference grid */
331  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), nx + 1), 0);
332  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), ny + 1), 0);
333 
334  /* compute longitude and latitude of that grid element */
335  xx = i * dx - 180.0 - dx / 2;
336  yy = j * dy - 90.0 - dy / 2;
337 
338  /* bilinearly interpolate, replacing missing (land) values with
339  average of valid values in box */
340  t = (lon - xx) / dx;
341  u = (lat - yy) / dy;
342 
343  if ((sssref[j][i] > sssbad + 1) && (sssref[j][i + 1] > sssbad + 1) &&
344  (sssref[j + 1][i] > sssbad + 1) && (sssref[j + 1][i + 1] > sssbad + 1))
345  *sss = (1 - t)*(1 - u) * sssref[j ][i ]
346  + t * (1 - u) * sssref[j ][i + 1]
347  + t * u * sssref[j + 1][i + 1]
348  + (1 - t) * u * sssref[j + 1][i ];
349  else
350  *sss = sssbad;
351 
352  return 0;
353 }
354 
355 /* ----------------------------------------------------------------------------------- */
356 /* get_sssref() - retrieves reference sea surface salinity . */
357 /* ----------------------------------------------------------------------------------- */
358 #define WOACLIM 1
359 
360 float get_sssref(char *sssfile, float lon, float lat, int day) {
361  float sss = sssbad;
362  int32_t sd_id;
363 
364  if (format < 0) {
365 
366  /* Does the file exist? */
367  if (access(sssfile, F_OK) || access(sssfile, R_OK)) {
368  printf("-E- %s: SSS input file '%s' does not exist or cannot open.\n",
369  __FILE__, sssfile);
370  exit(1);
371  }
372 
373  /* What is it? */
374  sd_id = SDstart(sssfile, DFACC_RDONLY);
375  if (sd_id != FAIL) {
376  /* Format is HDF-like */
377  char title[255] = "";
378  if (SDreadattr(sd_id, SDfindattr(sd_id, "Title"), (VOIDP) title) == 0) {
379  if (strstr(title, "WOA Sea Surface Salinity Monthly Climatology") != NULL) {
380  format = WOACLIM;
381  }
382  } else {
383  printf("-E- %s: unable to read SSS input file %s.\n", __FILE__, sssfile);
384  exit(1);
385  }
386  SDend(sd_id);
387  }
388  else {
389  if (get_hycom_sss(sssfile, lon, lat, &sss) == 0)
390  format = 2;
391  }
392  }
393 
394  switch (format) {
395  case WOACLIM:
396  sss = get_woasssclim(sssfile, lon, lat, day);
397  break;
398  case 2:
399  get_hycom_sss(sssfile, lon, lat, &sss);
400  break;
401  default:
402  printf("-E- %s: unknown SSS input file format for %s.\n", __FILE__, sssfile);
403  exit(1);
404  break;
405  }
406 
407  // assume fresh water if no data
408 
409  if (sss < 0.0) {
410  sss = 0.0;
411  }
412 
413  return (sss);
414 }
415 
416 
#define MAX(A, B)
Definition: swl0_utils.h:26
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
float get_woasssclim(char *sssfile, float lon, float lat, int day)
Definition: sssref.c:22
int j
Definition: decode_rs.h:73
int32_t day
int status
Definition: l1_czcs_hdf.c:32
int h5io_openr(char *file, int opt, h5io_str *id)
Definition: h5io.c:4
#define FAIL
Definition: ObpgReadGrid.h:18
#define NULL
Definition: decode_rs.h:63
int h5io_info(h5io_str *id, char *attr_name, H5T_class_t *class, hid_t *native_typ, int *ndim, int *dim_siz, int *sto_len)
Definition: h5io.c:173
float * lat
int h5io_close(h5io_str *id)
Definition: h5io.c:115
int h5io_set_grp(h5io_str *id, char *path_name, h5io_str *grp_id)
Definition: h5io.c:369
#define WOASSSNX
Definition: sssref.c:19
int h5io_set_ds(h5io_str *id, char *path_name, h5io_str *ds_id)
Definition: h5io.c:324
#define WOACLIM
Definition: sssref.c:358
int h5io_grp_contents(h5io_str *id, int *n_obj, char ***o_names, int **types)
Definition: h5io.c:1506
float get_hycom_sss(char *sssfile, float lon, float lat, float *sss)
Definition: sssref.c:166
#define BAD_FLT
Definition: jplaeriallib.h:19
data_t u
Definition: decode_rs.h:74
Extra metadata that will be written to the HDF4 file l2prod rank
#define HYCOMNX
Definition: sssref.c:163
#define WOASSSNY
Definition: sssref.c:20
float * lon
#define HYCOMNY
Definition: sssref.c:164
float get_sssref(char *sssfile, float lon, float lat, int day)
Definition: sssref.c:360
int h5io_rd_ds(h5io_str *ds_id, void *data)
Definition: h5io.c:505
int i
Definition: decode_rs.h:71