OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
acq_sfc_albedo.c
Go to the documentation of this file.
1 #include "l12_proto.h"
2 #include <string.h>
3 
4 int init_cld_dat( l1str *l1rec )
5 /*******************************************************************
6 
7  init_cld_dat
8 
9  purpose: initialize the cloud structure portion of the l1rec
10 
11  Returns type: int32_t - status 0 is good
12 
13  Parameters: (in calling order)
14  Type Name I/O Description
15  ---- ---- --- -----------
16  l1str * l1rec I/O all L1 line info
17 
18  Modification history:
19  Programmer Date Description of change
20  ---------- ---- ---------------------
21  W. Robinson 3 Apr 2020 Original development
22 
23 *******************************************************************/ {
24  int32_t npix;
25 
26  npix = l1rec->npix;
27 
28  if( ( l1rec->cld_dat = malloc( sizeof( cld_struc ) ) ) == NULL )
29  {
30  printf( "-E- %s, %d: Failure to allocate cloud albedo data structure\n",
31  __FILE__, __LINE__ );
32  return -1;
33  }
34  if( ( ( l1rec->cld_dat->sfc_albedo_659 = (float *)
35  malloc( npix * sizeof( float ) ) ) == NULL ) ||
36  ( ( l1rec->cld_dat->sfc_albedo_858 = (float *)
37  malloc( npix * sizeof( float ) ) ) == NULL ) ||
38  ( ( l1rec->cld_dat->sfc_albedo_1240 = (float *)
39  malloc( npix * sizeof( float ) ) ) == NULL ) ||
40  ( ( l1rec->cld_dat->sfc_albedo_1640 = (float *)
41  malloc( npix * sizeof( float ) ) ) == NULL ) ||
42  ( ( l1rec->cld_dat->sfc_albedo_2130 = (float *)
43  malloc( npix * sizeof( float ) ) ) == NULL ) )
44  {
45  printf( "-E- %s, %d: Failure to allocate cloud albedo data structures\n",
46  __FILE__, __LINE__ );
47  return -1;
48  }
49  return 0;
50  }
51 
52 int read_albedo( int32_t d_np, int32_t d_nl, int32_t st_lin, int32_t ix_clim,
53  int ncid, int *d_id, unsigned char ***alb_dat )
54 /*******************************************************************
55 
56  read_albedo
57 
58  purpose: get the sfc albedo read from the albedo file
59 
60  Returns type: int32_t - status 0 is good
61 
62  Parameters: (in calling order)
63  Type Name I/O Description
64  ---- ---- --- -----------
65  int32_t d_np I albedo data # pixels
66  int32_t d_nl I albedo data # lines
67  int32_t st_lin I start line to readfrom albedo
68  file
69  int32_t ix_clim I time to read -1 for no time
70  (not climatology) else time
71  index
72  int ncid I albedo file id
73  int * d_id I ids of albedo band datasets
74  unsigned char *** alb_dat O final data buffer
75 
76  Modification history:
77  Programmer Date Description of change
78  ---------- ---- ---------------------
79  W. Robinson 30 Mar 2020 Original development
80  *******************************************************************/ {
81  int32_t iwav, i_np, i_nl;
82  size_t start[] = {0,0,0}, count[] = {0,0,0};
83  int32_t ilat;
84  unsigned char *xfr_arr, **alb_lcl;
85 
86  alb_lcl = *alb_dat;
87  /* free permanent storage if needed */
88  if( alb_lcl[0] != NULL )
89  {
90  for( iwav = 0; iwav < 5; iwav++)
91  free( alb_lcl[iwav] );
92  }
93  /* allocate the transfer array and the data arrays */
94  if( ( xfr_arr = (unsigned char *) malloc( d_np * d_nl *
95  sizeof( unsigned char ) ) ) == NULL )
96  {
97  printf( "-E- %s, %d: Error allocating albedo read storage\n",
98  __FILE__, __LINE__ );
99  return -1;
100  }
101 
102  i_np = d_np + 1;
103  i_nl = d_nl + 1;
104 
105  /* get the data from the file to the albedo data array */
106  for( iwav = 0; iwav < 5; iwav++)
107  {
108  if( ( alb_lcl[iwav] = (unsigned char *)
109  malloc( i_np * i_nl * sizeof( unsigned char ) ) ) == NULL )
110  {
111  printf( "-E- %s, %d: Error allocating albedo read storage\n",
112  __FILE__, __LINE__ );
113  return -1;
114  }
115  /* Read data to the transfer array */
116  if( ix_clim < 0 )
117  {
118  /* not a climate dataset */
119  start[0] = st_lin;
120  start[1] = 0;
121  count[0] = d_nl;
122  count[1] = d_np;
123  }
124  else
125  {
126  /* climate dataset */
127  start[0] = st_lin;
128  start[1] = 0;
129  start[2] = ix_clim;
130  count[0] = d_nl;
131  count[1] = d_np;
132  count[2] = 1;
133  }
134  if( nc_get_vara_uchar( ncid, d_id[iwav], start, count, xfr_arr ) !=
135  NC_NOERR )
136  {
137  printf( "-E- %s, %d: Error reading albedo\n",
138  __FILE__, __LINE__ );
139  return -1;
140  }
141 
142  /* place it in the final data array */
143  for( ilat = 0; ilat < d_nl; ilat++ )
144  {
145  memcpy( ( alb_lcl[iwav] + ilat * i_np + 1 ),
146  ( xfr_arr + ilat * d_np ), d_np );
147  /* note that first lon will be copied from the end to get to -180 */
148  *( alb_lcl[iwav] + ilat * i_np ) =
149  *( xfr_arr + ilat * d_np + ( d_np - 1 ) );
150  }
151  /* repeat the last line - only of interest at 90 */
152  memcpy( ( alb_lcl[iwav] + ( i_nl - 1 ) * i_np ),
153  ( alb_lcl[iwav] + ( i_nl - 2 ) * i_np ), i_np );
154  }
155  free( xfr_arr );
156  return 0;
157  }
158 
160 /*******************************************************************
161 
162  acq__sfc_albedo
163 
164  purpose: retrieve the surface albedo for the scan line
165 
166  Returns type: int32_t - status 0 is good
167 
168  Parameters: (in calling order)
169  Type Name I/O Description
170  ---- ---- --- -----------
171  l1str * l1rec I/O all L1 line info
172 
173  Modification history:
174  Programmer Date Description of change
175  ---------- ---- ---------------------
176  W. Robinson 26 Mar 2020 Original development
177 
178  Note that this differs from the anc_acq... 1: only 1 file is read for the
179  data, and 2: the albedo is so large that provision is made to only read
180  in a portion of the albedo data. Also, at this time, all longitudes are
181  read to limit routine complexity.
182 
183  *******************************************************************/ {
184  static int32_t firstcall = 0, is_clim;
185  static int32_t subset_read = 0, scan_npix;
186  static float bdy_siz = 5.;
187  static float scale[5];
188  static float lat_min, lon_min, res1, res2;
189  static double lat_res, lon_res, alb_st_lat, alb_lat_rng[2] = { 900., -900. };
190  static unsigned char **alb_dat, fillv[5];
191  static int32_t ix_clim = -1, sub_nl;
192  static size_t d_np, d_nl, d_nt, i_np;
193  int32_t iwav, ipx, sub_st, good_nav, ix_lat, ix_lon;
194  int32_t n_done, ip, il;
195  float dat_sub[2][2], fin_val, sum;
196  float lat_rng[2] = { 900., -900. };
197  int16_t year, doy;
198  double sec, frac_lat, frac_lon, lat, lon;
199  char *alb_file;
200  char tit_clim[] = "MODIS/TERRA+Aqua BRDF/Albedo Gap-Filled Snow-Free 8-Day climatology";
201  char tit_daily[] = "MODIS/TERRA+Aqua BRDF/Albedo Gap-Filled Snow-Free data";
202  char str_tit[FILENAME_MAX];
203  static int ncid, d_id[5], dim_id, dim_id2;
204  nc_type att_typ;
205  char attr_buf[1024];
206  char *alb_wav_names[5] = { "Albedo_Map_0.659", "Albedo_Map_0.858",
207  "Albedo_Map_1.24", "Albedo_Map_1.64", "Albedo_Map_2.13" };
208  int nc1, nc2;
209 
210  if( firstcall == 0 )
211  {
212  firstcall = 1;
213  alb_file = input->sfc_albedo;
214  //open the file
215  if (nc_open(alb_file, 0, &ncid) != NC_NOERR) {
216  fprintf(stderr,
217  "-E- %s %d: file: %s is not netcdf, not acceptable albedo file\n",
218  __FILE__, __LINE__, alb_file);
219  return -1;
220  }
221  //read the 'title', one of 2 possibilities:
222  nc_get_att_text(ncid, NC_GLOBAL, "title", str_tit);
223  if( strncmp( str_tit, tit_daily, strlen(tit_daily) ) == 0 )
224  {
225  printf( "%s, %d: TEMP: we found the daily file: %s\n",
226  __FILE__, __LINE__, str_tit );
227  is_clim = 0;
228  }
229  else if( strncmp( str_tit, tit_clim, strlen(tit_clim) ) == 0 )
230  {
231  printf( "%s, %d: TEMP: we found the clim file: %s\n", __FILE__,
232  __LINE__, str_tit );
233  is_clim = 1;
234  /* get the data day -> index to correct time in file */
235  unix2yds( l1rec->scantime, &year, &doy, &sec);
236  ix_clim = ( doy - 1 ) / 8; // day 1 - 8 is index 0 etc
237  printf( "-I- %s, %d: Using climate doy # %d, index: %d\n", __FILE__,
238  __LINE__, doy, ix_clim );
239  }
240  else
241  {
242  printf( "-E- %s, %d: Incorrect title in albedo dataset: %s\n",
243  __FILE__, __LINE__, alb_file);
244  return -1;
245  }
246 
247  /* read the geospatial_lat_min etc to get data reolution, start */
248  if( ( nc_get_att_float(ncid, NC_GLOBAL, "geospatial_lat_min", &lat_min )
249  != NC_NOERR ) ||
250  ( nc_get_att_float(ncid, NC_GLOBAL, "geospatial_lon_min", &lon_min )
251  != NC_NOERR ) )
252  {
253  printf( "-E- %s, %d: Unable to read geolocation information for albedo file: %s\n",
254  __FILE__, __LINE__, alb_file);
255  return -1;
256  }
257 
258  /* break out the geospatial_lat_resolution, geospatial_lon_resolution
259  to have flexability for formats */
260  nc_inq_atttype( ncid, NC_GLOBAL, "geospatial_lat_resolution", &att_typ );
261  if( att_typ == NC_FLOAT ) {
262  nc1 = nc_get_att_float(ncid, NC_GLOBAL, "geospatial_lat_resolution",
263  &res1 );
264  } else {
265  nc1 = nc_get_att(ncid, NC_GLOBAL, "geospatial_lat_resolution",
266  attr_buf );
267  res1 = str2resolution(attr_buf);
268  res1 /= 111000; // as the above gives meters
269  }
270 
271  nc_inq_atttype( ncid, NC_GLOBAL, "geospatial_lon_resolution", &att_typ );
272  if( att_typ == NC_FLOAT ) {
273  nc2 = nc_get_att_float(ncid, NC_GLOBAL, "geospatial_lon_resolution",
274  &res2 );
275  } else {
276  nc1 = nc_get_att(ncid, NC_GLOBAL, "geospatial_lon_resolution",
277  attr_buf );
278  res2 = str2resolution(attr_buf);
279  res2 /= 111321; // as the above gives meters, NOTE assume km at equator!
280  }
281  if( ( nc1 != NC_NOERR ) || ( nc2 != NC_NOERR ) )
282  {
283  printf( "-E- %s, %d: Unable to read geolocation information for albedo file: %s\n",
284  __FILE__, __LINE__, alb_file);
285  return -1;
286  }
287 
288  lat_res = res1;
289  lon_res = res2;
290 
291  scan_npix = l1rec->npix;
292  // get the dimension sizes
293  if ((nc_inq_dimid(ncid, "lat", &dim_id) != NC_NOERR) ||
294  (nc_inq_dimid(ncid, "lon", &dim_id2) != NC_NOERR) )
295  {
296  printf( "-E- %s, %d: Error retrieving the lat/lon size\n",
297  __FILE__, __LINE__ );
298  return -1;
299  }
300  if ( ( nc_inq_dimlen(ncid, dim_id, &d_nl ) != NC_NOERR) ||
301  ( nc_inq_dimlen(ncid, dim_id2, &d_np ) != NC_NOERR) )
302  {
303  printf( "-E- %s, %d: Error retrieving the lat/lon size\n",
304  __FILE__, __LINE__ );
305  return -1;
306  }
307  if( is_clim == 1 )
308  {
309  if (nc_inq_dimid(ncid, "doy", &dim_id) != NC_NOERR)
310  {
311  printf( "-E- %s, %d: Error retrieving the doy size\n",
312  __FILE__, __LINE__ );
313  return -1;
314  }
315  if ( nc_inq_dimlen(ncid, dim_id, &d_nt ) != NC_NOERR)
316  {
317  printf( "-E- %s, %d: Error retrieving the doy size\n",
318  __FILE__, __LINE__ );
319  return -1;
320  }
321  }
322  i_np = d_np + 1;
323  /* allocate the 5 wavelength slots in alb_dat */
324  alb_dat = (unsigned char **) malloc( 5 * sizeof( unsigned char * ) );
325  alb_dat[0] = NULL;
326  /* if there are not too many values to read, allocate all the
327  data space here
328  */
329  subset_read = 1;
330  if( (long)d_np * (long)d_nl < 4000000 ) subset_read = 0;
331 
332  /* loop through the 5 bands */
333  for( iwav = 0; iwav < 5; iwav++ )
334  {
335 
336  /* get the data id for the band */
337  if( nc_inq_varid(ncid, alb_wav_names[iwav], ( d_id + iwav ) ) != NC_NOERR)
338  {
339  printf( "-E- %s, %d: Error retrieving the band id\n",
340  __FILE__, __LINE__ );
341  return -1;
342  }
343  /* get the fill and scale values */
344  if( ( nc_get_att_uchar( ncid, d_id[iwav], "_FillValue",
345  ( fillv + iwav ) ) != NC_NOERR ) ||
346  ( nc_get_att_float( ncid, d_id[iwav], "scale_factor",
347  ( scale + iwav ) ) != NC_NOERR ) )
348  {
349  printf( "-E- %s, %d: Error retrieving the fill or scale value\n",
350  __FILE__, __LINE__ );
351  return -1;
352  }
353  }
354  if( subset_read == 0 )
355  {
356  if( read_albedo( d_np, d_nl, 0, ix_clim, ncid, d_id, &alb_dat ) != 0 )
357  return -1;
358  }
359  alb_st_lat = -90.;
360  }
361  /* initialization is complete and all data is read in if possible */
362 
363  /* get the cld_dat structure set if needed */
364  if( l1rec->cld_dat == NULL )
365  {
366  //printf( "\n\n\n-T- %s, %d: setting up the cld_dat in l1rec again\n\n\n",
367  //__FILE__, __LINE__ );
368  // allocate the l1rec albedo struct
369  if( init_cld_dat( l1rec ) != 0 ) return -1;
370  }
371  /* in the case where only a portion of the data is read in based on the
372  latitude range, compute that range and read in that portion if needed */
373 
374  if( subset_read == 1 )
375  {
376  /* find the lat range of the scan */
377  for( ipx = 0; ipx < scan_npix; ipx++ )
378  {
379  lat = l1rec->lat[ipx];
380  if( ( lat >= -90. ) && ( lat <= 90. ) )
381  {
382  if( lat < lat_rng[0] ) lat_rng[0] = lat;
383  if( lat > lat_rng[1] ) lat_rng[1] = lat;
384  }
385  }
386  /* see if we need to read a new range */
387  if( ( alb_lat_rng[0] > lat_rng[0] ) || ( alb_lat_rng[1] < lat_rng[1] ) )
388  {
389  /* read in with added boundary */
390  alb_lat_rng[0] = lat_rng[0] - bdy_siz;
391  if( alb_lat_rng[0] < -90. )
392  alb_lat_rng[0] = -90.;
393  else{
394  // make sure the range falls on the grid points
395  sub_st = ( alb_lat_rng[0] + 90. ) / lat_res;
396  alb_lat_rng[0] = ( sub_st * lat_res ) - 90.;
397  }
398  alb_lat_rng[1] = lat_rng[1] + bdy_siz;
399  if( alb_lat_rng[1] > 90. )
400  alb_lat_rng[1] = 90.;
401  else{
402  sub_st = ( alb_lat_rng[1] + 90. ) / lat_res;
403  alb_lat_rng[1] = ( sub_st * lat_res ) - 90.;
404  }
405  alb_st_lat = alb_lat_rng[0];
406 
407  // printf( "\n\n\n-T- %s, %d: Reading the albedo data for new range:\n",
408  // __FILE__, __LINE__ );
409  printf( "Latitude: %f - %f\n\n\n",
410  alb_lat_rng[0], alb_lat_rng[1] );
411  sub_nl = ( alb_lat_rng[1] - alb_lat_rng[0] + lat_res/2. ) / lat_res;
412  sub_st = ( alb_st_lat + 90. ) / lat_res;
413  if( read_albedo( d_np, sub_nl, sub_st, ix_clim, ncid, d_id,
414  &alb_dat ) != 0 )
415  return -1;
416  }
417  }
418  /* the grid is ready, for each scan point, get the interpolated albedo */
419  for( ipx = 0; ipx < scan_npix; ipx++ )
420  {
421  fin_val = BAD_FLT;
422  lat = l1rec->lat[ipx];
423  lon = l1rec->lon[ipx];
424  good_nav = 0;
425  /* find grid box and position inside the box */
426  if( ( lat >= -90. ) && ( lat <= 90. )
427  && ( lon >= -180. ) && (lon <= 180. ) )
428  {
429  good_nav = 1;
430  frac_lat = ( lat - alb_st_lat ) / lat_res;
431  frac_lon = ( lon + 180 ) / lon_res;
432  ix_lat = (int32_t) frac_lat;
433  ix_lon = (int32_t) frac_lon;
434  frac_lat = frac_lat - (float) ix_lat; /* get remainder */
435  frac_lon = frac_lon - (float) ix_lon;
436  }
437  /* for the wavelengths, get the interpolated value */
438  for( iwav = 0; iwav < 5; iwav++ )
439  {
440  if( good_nav == 1 )
441  {
442  /* get bounding box values */
443  n_done = 0;
444  sum = 0;
445  for( ip = 0; ip < 2; ip++ )
446  {
447  for( il = 0; il < 2; il++ )
448  {
449  if( ix_lat + il >= sub_nl )
450  dat_sub[ip][il] = fillv[iwav];
451  else
452  dat_sub[ip][il] = *( alb_dat[iwav] + ( ix_lon + ip ) +
453  i_np * ( ix_lat + il ) );
454  if( dat_sub[ip][il] != fillv[iwav] )
455  {
456  sum += dat_sub[ip][il] * scale[iwav];
457  n_done++;
458  }
459  }
460  }
461  if( n_done == 0 )
462  {
463  fin_val = BAD_FLT;
464  }
465  else
466  {
467  sum /= n_done;
468  for( ip = 0; ip < 2; ip++ )
469  for( il = 0; il < 2; il++ )
470  {
471  if( dat_sub[ip][il] == fillv[iwav] )
472  dat_sub[ip][il] = sum;
473  else
474  dat_sub[ip][il] *= scale[iwav];
475  }
476  /* get the weighted average */
477  fin_val = ( 1 - frac_lon ) * ( ( dat_sub[0][0] * ( 1 - frac_lat ) ) +
478  ( dat_sub[0][1] * frac_lat ) ) +
479  frac_lon * ( ( dat_sub[1][0] * ( 1 - frac_lat ) ) +
480  ( dat_sub[1][1] * frac_lat ) );
481  }
482  }
483  /* place the final value */
484  switch( iwav )
485  {
486  case 0: l1rec->cld_dat->sfc_albedo_659[ipx] = fin_val;
487  break;
488  case 1: l1rec->cld_dat->sfc_albedo_858[ipx] = fin_val;
489  break;
490  case 2: l1rec->cld_dat->sfc_albedo_1240[ipx] = fin_val;
491  break;
492  case 3: l1rec->cld_dat->sfc_albedo_1640[ipx] = fin_val;
493  break;
494  case 4: l1rec->cld_dat->sfc_albedo_2130[ipx] = fin_val;
495  }
496  }
497  }
498  /* and finish the line */
499  return 0;
500  }
int read_albedo(int32_t d_np, int32_t d_nl, int32_t st_lin, int32_t ix_clim, int ncid, int *d_id, unsigned char ***alb_dat)
#define NULL
Definition: decode_rs.h:63
read l1rec
float * lat
instr * input
void unix2yds(double usec, short *year, short *day, double *secs)
#define BAD_FLT
Definition: jplaeriallib.h:19
float * lon
int acq_sfc_albedo(l1str *l1rec)
int init_cld_dat(l1str *l1rec)
Definition: acq_sfc_albedo.c:4
int npix
Definition: get_cmp.c:27
double str2resolution(char const *resolutionStr)
Pixel resolution string to meters.
int count
Definition: decode_rs.h:79