OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
get_mld.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include "l12_proto.h"
3 #include <sys/types.h>
4 #include <netcdf>
5 #include <vector>
6 #include <algorithm>
7 
8 // module get_mld.c - retrieve mixed layer depth from ancillary data
9 
10 static float mldbad = BAD_FLT;
11 
12 #define MLDXANC 360
13 #define MLDYANC 180
14 
16  char *ocdataroot;
17  char *filepath = (char*) malloc(sizeof(char) * FILENAME_MAX);
18  if ((ocdataroot = getenv("OCDATAROOT")) == NULL) {
19  printf("-E- OCDATAROOT environment variable is not defined.\n");
20  exit(EXIT_FAILURE);
21  }
22  sprintf(filepath, "%s/common/mld_climatology_woa1994.hdf", ocdataroot);
23  return filepath;
24 }
25 
26 /* This program opens the World Ocean Atlas Climatology hdf4 file
27  and extracts mixed layer depth information. */
28 
29 /* :Title = "WOA Mixed Layer Depth Monthly Climatology"
30  :Description = "World Ocean Atlas 1994, Mixed Layer Depth, Monthly"
31  :Reference = "http://www.nodc.noaa.gov/OC5/WOA94/mix.html"
32  */
33 
34 float get_mld_hdf(float lon, float lat, int day) {
35  static int firstCall = 1;
36  static int mldx = MLDXANC;
37  static int mldy = MLDYANC;
38  static float dx = 360.0 / MLDXANC;
39  static float dy = 180.0 / MLDYANC;
40 
41  typedef float ref_t[MLDXANC + 2];
42  static ref_t* mldref;
43  static ref_t* mld_sav;
44 
45  float mld = mldbad;
46  int i, j, ii;
47  float xx, yy;
48  float t, u;
49 
50  if (firstCall) {
51 
52  float mldtmp[MLDYANC][MLDXANC];
53  char name[H4_MAX_NC_NAME];
54  char sdsname[H4_MAX_NC_NAME];
55  int32 sd_id;
56  int32 sds_id;
57  int32 rank;
58  int32 status;
59  int32 sds_index;
60  int32 nt;
61  int32 dims[H4_MAX_VAR_DIMS];
62  int32 nattrs;
63  int32 start[2] = {0, 0};
64  int32 ix, iy, ct;
65  int32 lymin, lxmin, lymax, lxmax;
66  float sum;
67 
68  char mldclimatology_file[FILENAME_MAX];
69  char mldmonth[7];
70 
71  firstCall = 0;
72 
73  // allocate data
74  mldref = (ref_t*) allocateMemory((MLDYANC + 2) * sizeof (ref_t), "mldref");
75  mld_sav = (ref_t*) allocateMemory((MLDYANC + 2) * sizeof (ref_t), "mld_sav");
76 
77  strcpy(mldclimatology_file, mldclimatology_path());
78  sd_id = SDstart(mldclimatology_file, DFACC_RDONLY);
79  if (sd_id == -1) {
80  printf("-E- %s: Error opening MLD climatology file %s.\n",
81  __FILE__, mldclimatology_file);
82  exit(EXIT_FAILURE);
83  }
84  printf("Opening MLD climatology file %s\n\n", mldclimatology_file);
85 
86  /* calculate the correct date and day of the month using yd2md utility. */
87  int16 mon = (int) day / 31 + 1; // month of year
88  // (no need for perfection..at least according to the sea surface salinity reference algorithm)
89 
90  sprintf(mldmonth, "mld%02i", mon);
91 
92  /* Get the SDS index */
93  strcpy(sdsname, mldmonth);
94  sds_index = SDnametoindex(sd_id, sdsname);
95  if (sds_index == -1) {
96  printf("-E- %s: Error seeking %s SDS from %s.\n", __FILE__,
97  sdsname, mldclimatology_file);
98  exit(EXIT_FAILURE);
99  }
100  sds_id = SDselect(sd_id, sds_index);
101 
102  status = SDgetinfo(sds_id, name, &rank, dims, &nt, &nattrs);
103  if (status != 0) {
104  printf("-E- %s: Error reading SDS info for %s from %s.\n",
105  __FILE__, sdsname, mldclimatology_file);
106  exit(EXIT_FAILURE);
107  }
108  status = SDreaddata(sds_id, start, NULL, dims, (VOIDP) & mldtmp[0][0]);
109  if (status != 0) {
110  printf("-E- %s: Error reading SDS %s from %s.\n", __FILE__,
111  sdsname, mldclimatology_file);
112  exit(EXIT_FAILURE);
113  }
114 
115  status = SDendaccess(sds_id);
116  status = SDend(sd_id);
117 
118  /* rotate 180-deg and add wrapping border to simplify interpolation */
119  /* new grid is -180.5,180.5 in i=0,361 and -90.5,90.5 in j=0,181 */
120  for (j = 0; j < mldy; j++) {
121  for (i = 0; i < mldx; i++) {
122  ii = (i < mldx / 2) ? i + mldx / 2 : i - mldx / 2;
123  if (mldtmp[j][i] > 0)
124  mldref[j + 1][ii + 1] = mldtmp[j][i];
125  else
126  mldref[j + 1][ii + 1] = mldbad;
127  }
128  mldref[j + 1][0] = mldref[j + 1][mldx];
129  mldref[j + 1][mldx + 1] = mldref[j + 1][1];
130  }
131  for (i = 0; i < mldx + 2; i++) {
132  mldref[0][i] = mldref[1][i];
133  mldref[mldy + 1][i] = mldref[mldy][i];
134  }
135 
136  /*
137  * Extend the grid by 1 point (use only full grid boxes later)
138  */
139  memcpy(mld_sav, mldref,
140  (MLDYANC + 2) * (MLDXANC + 2) * sizeof (float));
141  for (iy = 0; iy < mldy + 2; iy++) {
142  lymin = (iy == 0) ? 0 : iy - 1;
143  lymax = (iy == mldy + 1) ? mldy + 1 : iy + 1;
144 
145  for (ix = 0; ix < mldx + 2; ix++) {
146  if (mldref[iy][ix] < mldbad + 1) {
147  lxmin = (ix == 0) ? 0 : ix - 1;
148  lxmax = (ix == mldx + 1) ? mldx + 1 : ix + 1;
149 
150  sum = 0.;
151  ct = 0;
152  for (j = lymin; j < lymax + 1; j++)
153  for (i = lxmin; i < lxmax + 1; i++) {
154  if (mld_sav[j][i] > mldbad + 1) {
155  sum += mld_sav[j][i];
156  ct++;
157  }
158  }
159  if (ct > 0)
160  mldref[iy][ix] = sum / ct;
161  }
162  }
163  }
164 
165  } /* end 1-time grid set up */
166 
167  /* locate LL position within reference grid */
168  i = MAX(MIN((int) ((lon + 180.0 + dx / 2) / dx), MLDXANC + 1), 0);
169  j = MAX(MIN((int) ((lat + 90.0 + dy / 2) / dy), MLDYANC + 1), 0);
170 
171  /* compute longitude and latitude of that grid element */
172  xx = i * dx - 180.0 - dx / 2;
173  yy = j * dy - 90.0 - dy / 2;
174 
175  /* Bilinearly interpolate, only using full grid boxes */
176  t = (lon - xx) / dx;
177  u = (lat - yy) / dy;
178 
179  if ((mldref[j][i] > mldbad + 1) && (mldref[j][i + 1] > mldbad + 1)
180  && (mldref[j + 1][i] > mldbad + 1)
181  && (mldref[j + 1][i + 1] > mldbad + 1)) {
182 
183  mld = (1 - t) * (1 - u) * mldref[j][i] + t * (1 - u) * mldref[j][i + 1]
184  + t * u * mldref[j + 1][i + 1] + (1 - t) * u * mldref[j + 1][i];
185 
186  } else
187  mld = mldbad;
188 
189  return (mld);
190 }
191 
192 /*******************************************************************************/
193 
194 using namespace std;
195 using namespace netCDF;
196 using namespace netCDF::exceptions;
197 
198 int closest_index(vector<float> const& refvals, const float value) {
199  // assumes refvals is sorted
200 
201  if (value < refvals.front() ||
202  value > refvals.back())
203  return -1;
204  auto head = refvals.begin();
205  auto tail = refvals.end();
206 
207  // iterator to first element with value not less than input (<=)
208  auto next = lower_bound(head, tail, value);
209  if (next == head) return next - head;
210 
211  // iterator to last element with value less than input (<)
212  auto prev = next;
213  --prev;
214  if (prev == tail) return prev - head;
215 
216  // return index of element closer to value
217  return (*next - value) < (value - *prev) ? next - head : prev - head;
218 }
219 
220 float wrap(const float val, const float lo, const float hi) {
221  const float width = hi - lo;
222  const float offset = val - lo;
223  return (offset - (floor(offset / width) * width)) + lo;
224 }
225 
226 typedef struct mld_info_struct {
227  NcVar mldvar;
228  vector<float> lon;
229  vector<float> lat;
230 } mld_info;
231 
232 vector<float> get_coords(NcFile* ncid, vector<string> varnames) {
233  NcDim Dim;
234  NcVar Var;
235  for (auto name = varnames.begin(); name != varnames.end(); ++name) {
236  ncid->getCoordVar(*name, Dim, Var);
237  if (!Dim.isNull()) {
238  uint nvar = Dim.getSize();
239  vector<float> var(nvar);
240  Var.getVar(&var[0]);
241  return var;
242  }
243  }
244  // if we got this far, the coordinate variable wasn't found.
245  return {};
246 }
247 
248 int init_mld_nc(char* mldfile, mld_info* mldinfo) {
249  try {
250  NcFile* ncid = new NcFile(mldfile, NcFile::read);
251  string varname;
252 
253  // get MLD info
254  varname = "mixed_layer_thickness";
255  mldinfo->mldvar = ncid->getVar(varname);
256 
257  // read longitude and latitude
258  vector<string> lonnames { "lon", "Longitude", "longitude" };
259  mldinfo->lon = get_coords(ncid, lonnames);
260  if (mldinfo->lon.size() == 0) {
261  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
262  << "No Longitude coordinate variable in " << mldfile << endl;
263  exit(EXIT_FAILURE);
264  }
265 
266  vector<string> latnames { "lat", "Latitude", "latitude" };
267  mldinfo->lat = get_coords(ncid, latnames);
268  if (mldinfo->lat.size() == 0) {
269  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
270  << "No Latitude coordinate variable in " << mldfile << endl;
271  exit(EXIT_FAILURE);
272  }
273 
274  // check that lat, lon arrays are sorted
275  vector<float> sorted;
276  sorted = mldinfo->lon;
277  sort(sorted.begin(), sorted.end());
278  if (mldinfo->lon != sorted) {
279  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
280  << "Longitude array is not monotonically increasing\n";
281  exit(EXIT_FAILURE);
282  }
283  sorted = mldinfo->lat;
284  sort(sorted.begin(), sorted.end());
285  if (mldinfo->lat != sorted) {
286  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
287  << "Latitude array is not monotonically increasing\n";
288  exit(EXIT_FAILURE);
289  }
290 
291  } catch (NcException const & e) {
292  return 1;
293  } catch (exception const & e) {
294  e.what();
295  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
296  << e.what() << endl;
297  exit(EXIT_FAILURE);
298  }
299 
300  return 0;
301 }
302 
303 float get_mld_nc(char* mldfile, float lon, float lat) {
304  static int firstCall = 1;
305  static mld_info mldinfo;
306  float mld;
307 
308  // initial file setups
309  if (firstCall) {
310  firstCall = 0;
311  if (init_mld_nc(mldfile, &mldinfo)) {
312  return (BAD_FLT);
313  }
314  }
315 
316  // normalize input coords and find closest index
317  float keeplon = lon;
318  lon = wrap(lon, // put into same range as input lon
319  mldinfo.lon.front(),
320  mldinfo.lon.front() + 360);
321  int ilon = closest_index(mldinfo.lon, lon);
322  int ilat = closest_index(mldinfo.lat, lat);
323  lon = keeplon;
324 
325  // look up mld value
326  if ((ilon < 0) || (ilat < 0)) {
327  mld = BAD_FLT;
328  } else {
329  try {
330  vector<size_t> index = { 0, (size_t) ilat, (size_t) ilon };
331  mldinfo.mldvar.getVar(index, &mld);
332 
333  } catch (exception const & e) {
334  e.what();
335  cerr << "-X- " << __FILE__ " line " << __LINE__ << ": "
336  << e.what()
337  << endl;
338  exit(EXIT_FAILURE);
339  }
340  }
341 
342  return (mld);
343 }
344 
345 /*******************************************************************************/
346 
347 float get_mld(char* mldfile, float lon, float lat, int day) {
348  static int netcdf_mld;
349  static int firstCall = 1;
350  int badval = 0;
351  float mld;
352 
353  // initial file tests
354  if (firstCall) {
355  firstCall = 0;
356 
357  if (mldfile != NULL && mldfile[0] != 0) {
358  // if the file is an HDF4 file, we will assume for now it is the climatology
359  if (!Hishdf(mldfile)) {
360  mld = get_mld_nc(mldfile, lon, lat);
361  netcdf_mld = (mld != BAD_FLT); // is it valid format?
362  if (netcdf_mld) {
363  printf("Opening mixed layer depth file: %s\n", mldfile);
364  } else {
365  printf("Failed to read the specified mixed layer depth file: %s\n", mldfile);
366  exit(EXIT_FAILURE);
367  }
368  }
369  } else {
370  printf("Reading mixed layer depth info from default climatology\n");
371  strcpy(mldfile, mldclimatology_path());
372  netcdf_mld = 0;
373  }
374  } // firstCall done
375 
376  // try reading from netcdf file; check result
377  if (netcdf_mld) {
378  mld = get_mld_nc(mldfile, lon, lat);
379  badval = (mld == BAD_FLT);
380  }
381 
382  // read from climatology file as needed
383  if (!netcdf_mld || badval) {
384  mld = get_mld_hdf(lon, lat, day);
385  }
386 
387  return (mld);
388 }
an array had not been initialized Several spelling and grammar corrections were which is read from the appropriate MCF the above metadata values were hard coded A problem calculating the average background DN for SWIR bands when the moon is in the space view port was corrected The new algorithm used to calculate the average background DN for all reflective bands when the moon is in the space view port is now the same as the algorithm employed by the thermal bands For non SWIR changes in the averages are typically less than Also for non SWIR the black body DNs remain a backup in case the SV DNs are not available For SWIR the changes in computed averages were larger because the old which used the black body suffered from contamination by the micron leak As a consequence of the if SV DNs are not available for the SWIR the EV pixels will not be the granule time is used to identify the appropriate tables within the set given for one LUT the first two or last two tables respectively will be used for the interpolation If there is only one LUT in the set of it will be treated as a constant LUT The manner in which Earth View data is checked for saturation was changed Previously the raw Earth View DNs and Space View DNs were checked against the lookup table values contained in the table dn_sat The change made is to check the raw Earth and Space View DNs to be sure they are less than the maximum saturation value and to check the Space View subtracted Earth View dns against a set of values contained in the new lookup table dn_sat_ev The metadata configuration and ASSOCIATEDINSTRUMENTSHORTNAME from the MOD02HKM product The same metatdata with extensions and were removed from the MOD021KM and MOD02OBC products ASSOCIATEDSENSORSHORTNAME was set to MODIS in all products These changes are reflected in new File Specification which users may consult for exact the pow functions were eliminated in Emissive_Cal and Emissive bands replaced by more efficient code Other calculations throughout the code were also made more efficient Aside from a few round off there was no difference to the product The CPU time decreased by about for a day case and for a night case A minor bug in calculating the uncertainty index for emissive bands was corrected The frame index(0-based) was previously being used the frame number(1-based) should have been used. There were only a few minor changes to the uncertainty index(maximum of 1 digit). 3. Some inefficient arrays(Sigma_RVS_norm_sq) were eliminated and some code lines in Preprocess_L1A_Data were moved into Process_OBCEng_Emiss. There were no changes to the product. Required RAM was reduced by 20 MB. Now
#define MAX(A, B)
Definition: swl0_utils.h:26
integer, parameter int16
Definition: cubeio.f90:3
int32 value
Definition: Granule.c:1235
#define MIN(x, y)
Definition: rice.h:169
data_t t[NROOTS+1]
Definition: decode_rs.h:77
float get_mld(char *mldfile, float lon, float lat, int day)
Definition: get_mld.cpp:347
int j
Definition: decode_rs.h:73
int32_t day
int status
Definition: l1_czcs_hdf.c:32
int init_mld_nc(char *mldfile, mld_info *mldinfo)
Definition: get_mld.cpp:248
vector< float > lon
Definition: get_mld.cpp:228
void * allocateMemory(size_t numBytes, const char *name)
Definition: allocateMemory.c:7
#define NULL
Definition: decode_rs.h:63
@ head
Definition: dataday.h:37
float * lat
char * mldclimatology_path()
Definition: get_mld.cpp:15
void sort(unsigned long n, float arr[])
const char * ocdataroot
float get_mld_hdf(float lon, float lat, int day)
Definition: get_mld.cpp:34
int closest_index(vector< float > const &refvals, const float value)
Definition: get_mld.cpp:198
#define MLDYANC
Definition: get_mld.cpp:13
@ tail
Definition: dataday.h:37
string filepath
Definition: color_dtdb.py:207
vector< float > lat
Definition: get_mld.cpp:229
#define BAD_FLT
Definition: jplaeriallib.h:19
data_t u
Definition: decode_rs.h:74
float wrap(const float val, const float lo, const float hi)
Definition: get_mld.cpp:220
Extra metadata that will be written to the HDF4 file l2prod rank
float get_mld_nc(char *mldfile, float lon, float lat)
Definition: get_mld.cpp:303
float * lon
l2prod offset
#define MLDXANC
Definition: get_mld.cpp:12
int i
Definition: decode_rs.h:71
msiBandIdx val
Definition: l1c_msi.cpp:34
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
vector< float > get_coords(NcFile *ncid, vector< string > varnames)
Definition: get_mld.cpp:232