OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
GEO_aggregate.c
Go to the documentation of this file.
1 #include "GEO_geo.h"
2 #include "GEO_earth.h"
3 #include "GEO_output.h"
4 #include "GEO_product.h"
5 #include "GEO_global_arrays.h"
6 #include "PGS_MODIS_35251.h"
7 #include "PGS_SMF.h"
8 #include "PGS_CSC.h"
9 #include "smfio.h"
10 
11 /* Revision History:
12 $Log: GEO_aggregate.c,v $
13 Revision 6.8 2011/02/21 19:57:16 kuyper
14 In order to resolve feature-request Bug 3446, changed to aggregate landsea
15  mask, and to create new waterpresent array.
16 
17 Revision 6.7 2010/12/14 22:01:14 kuyper
18 Moved responsibility for conversion from height above ellipsoid to height
19  above geoid into this module.
20 
21 Revision 6.6 2010/06/28 19:17:05 kuyper
22 Corrected QFL_IDXS loop conditions.
23 
24 Revision 6.5 2010/05/27 17:50:26 kuyper
25 Corrected dimensions of frame_quality.
26 Removed references to quality flag values that could not be present.
27 
28 Revision 6.4 2010/04/02 21:35:41 kuyper
29 Helped resolve Bug 2472 by aggregating ephemeris/attitude quality flags.
30 Dropped unused parameter.
31 
32 James Kuyper james.kuyper@sigmaspace.com
33 
34 Revision 6.3 2009/05/31 23:08:54 kuyper
35 Corrected to use DETECTORS_1KM as loop limit.
36 Corrected order of arguments to PGS_CSC_GEOtoECR().
37 
38 Revision 6.2 2009/05/22 17:01:25 kuyper
39 Corrected some misuses of N_samp.
40 Corrected error messages.
41 
42 Revision 6.1 2009/05/19 16:59:16 kuyper
43 Initial revision.
44 
45 James Kuyper James.R.Kuyper@nasa.gov
46 */
47 
48 static int GEO_aggregate_lw(
49  int const lwmask_count[],
50  uint8 *water
51 )
107 {
108  /* Treat Coastal pixels as land */
109  int land = lwmask_count[DRYLAND] + lwmask_count[COAST];
110  int inland = lwmask_count[SHALLOW_INLAND] + lwmask_count[DEEP_INLAND];
111  int ocean = lwmask_count[SHALLOW_OCEAN] + lwmask_count[CONTINENTAL] +
112  lwmask_count[DEEP_OCEAN];
113  int moderate = lwmask_count[DEEP_INLAND] + lwmask_count[CONTINENTAL];
114  int lwmask_sum;
115  *water = inland + ocean + lwmask_count[EPHEMERAL];
116  lwmask_sum = land + *water;
117 
118  if(lwmask_count[EPHEMERAL] > lwmask_sum / 2)
119  return EPHEMERAL;
120 
121  if(land + lwmask_count[EPHEMERAL] > lwmask_sum / 2)
122  return DRYLAND; /* GEO_aggregate will convert to COAST if *water>0. */
123  else
124  {
125  int shallow = lwmask_count[EPHEMERAL] + lwmask_count[SHALLOW_INLAND]
126  + lwmask_count[SHALLOW_OCEAN];
127 
128  if(shallow > *water/2)
129  {
130  if(inland > *water/2)
131  return SHALLOW_INLAND;
132  else
133  return SHALLOW_OCEAN;
134  }
135  if(inland > *water/2)
136  return DEEP_INLAND;
137 
138  /* Redefine "shallow" downwards: */
139  shallow += moderate;
140  if(shallow > *water/2)
141  return CONTINENTAL;
142  else
143  return DEEP_OCEAN;
144  }
145 }
146 
147 PGSt_SMF_status GEO_aggregate(
148  int32 EV_frames,
149  uint16 N_samp,
150  double hires_scale,
151  unsigned char sample_flags[][MAX_PADDED],
152  double ecr_sample_position[][MAX_PADDED][3],
153  double ecr_sc_sample_position[][3],
154  double terrain_sample_position[][MAX_PADDED][3],
155  uint32 sample_quality[][QFL_IDXS],
156  uint8 sample_landsea[][MAX_PADDED],
157  double ecr_frame_position[][MAX_FRAMES][3],
158  double terrain_frame_position[][MAX_FRAMES][3],
159  uint8 frame_flags[][MAX_FRAMES],
160  double ecr_sc_frame_position[MAX_FRAMES][3],
161  int8 hires_offsets[][DETECTORS_QKM][SAMPLES_QKM],
162  uint32 frame_quality[][MAX_FRAMES],
163  uint8 frame_landsea[][MAX_FRAMES],
164  uint8 frame_waterpresent[][MAX_FRAMES]
165 )
239 {
240  int frame, efat; /* Loop counters */
241  char filefunc[] = __FILE__ ", GEO_aggregate";
242  char msgbuf[PGS_SMF_MAX_MSGBUF_SIZE];
243 
244  if(!sample_flags || !ecr_sample_position || !ecr_sc_sample_position ||
245  !terrain_sample_position || !ecr_frame_position ||
246  !terrain_frame_position || !frame_flags || !ecr_sc_frame_position ||
247  !hires_offsets)
248  {
249 
250  sprintf(msgbuf, "sample_flags:%p ecr_sample_position:%p\n"
251  "ecr_sc_sample_position:%p terrain_sample_position:%p\n"
252  "sample_quality:%p ecr_frame_position:%p\n"
253  "terrain_frame_position:%p frame_flags:%p\n"
254  "ecr_sc_frame_position:%p hires_offsets:%p frame_quality:%p",
255  (void*)sample_flags, (void*)ecr_sample_position,
256  (void*)ecr_sc_sample_position, (void*)terrain_sample_position,
257  (void*)sample_quality, (void*)ecr_frame_position,
258  (void*)terrain_frame_position, (void*)frame_flags,
259  (void*)ecr_sc_frame_position, (void*)hires_offsets,
260  (void*)frame_quality);
261  modsmf(MODIS_E_BAD_INPUT_ARG, msgbuf, filefunc);
262 
263  return MODIS_E_BAD_INPUT_ARG;
264  }
265 
266  for(frame = 0; frame < EV_frames; frame++)
267  {
268  int det, off;
269  /* Subsample the spacecraft positions. */
270  memcpy(ecr_sc_frame_position[frame],
271  ecr_sc_sample_position[N_samp * (frame + 1) - 1],
272  sizeof *ecr_sc_frame_position);
273 
274  for(efat=EPH_IDX; efat<QFL_IDXS; efat++)
275  {
276  frame_quality[efat][frame] = sample_quality[frame*N_samp][efat];
277 
278  for(off=1; off < 2*N_samp-1; off++)
279  frame_quality[efat][frame] |=
280  sample_quality[frame*N_samp+off][efat];
281  }
282  for(det = 0; det < DETECTORS_1KM; det++)
283  {
284  int idet, ind;
285  double latitude, longitude, altitude, height=0.0;
286  PGSt_double posecr[3]; /* position in ECR coordinates. */
287  int lwmask_count[NUM_LWMASK]={0};
288 
289  for(ind = 0; ind < 3; ind++)
290  ecr_frame_position[det][frame][ind] = 0.0;
291  frame_flags[det][frame] = 0;
292 
293  if(N_samp == 1)
294  { /* No aggregation is needed */
295  frame_flags[det][frame] = sample_flags[det][frame];
296  memcpy( ecr_frame_position[det][frame],
297  ecr_sample_position[det][frame],
298  sizeof ecr_frame_position[det][frame]);
299  memcpy( terrain_frame_position[det][frame],
300  terrain_sample_position[det][frame],
301  sizeof terrain_frame_position[det][frame]);
302  continue;
303  }
304 
305  for(idet = N_samp*det; idet < N_samp*(det+1); idet++)
306  {
307  for(off = 0; off < 2*N_samp-1; off++)
308  {
309  /* Weighting factors along the scan direction for N_samp
310  * from 1 to 4. The factors that would apply for N_samp==3
311  * are included, even though they won't be used, to
312  * simplify use of this table.
313  */
314  static const double weight[4][7]= {
315  {1.0},
316  {1.0/8.0, 2.0/8.0, 1.0/8.0},
317  {1.0/27.0, 2.0/27.0, 3.0/27.0, 2.0/27.0, 1.0/27.0},
318  {1.0/64.0, 2.0/64.0, 3.0/64.0, 4.0/64.0, 3.0/64.0,
319  2.0/64.0, 1.0/64.0}
320  };
321 
322  /* Aggregate the frame flags */
323  frame_flags[det][frame] |=
324  sample_flags[idet][frame*N_samp+off];
325 
326  /* Count the landsea_mask values. */
327  if(sample_landsea[idet][frame*N_samp+off] < NUM_LWMASK)
328  lwmask_count[sample_landsea[idet][frame*N_samp+off]]
329  += (int)(N_samp*N_samp*N_samp*weight[N_samp-1][off]);
330 
331  /* Calculate the weighted average position */
332  for(ind = 0; ind < 3; ind++)
333  ecr_frame_position[det][frame][ind] +=
334  weight[N_samp-1][off] *
335  ecr_sample_position[idet][frame*N_samp+off][ind];
336 
337  /* Calculate the weighted average height above the
338  * ellipsoid */
339  height += weight[N_samp-1][off]*
340  terrain_sample_position[idet][frame*N_samp+off][HT_IDX];
341  }
342  }
343 
344  /* Determine aggregated landsea_mask. */
345  frame_landsea[det][frame] = GEO_aggregate_lw(lwmask_count,
346  frame_waterpresent[det]+frame);
347 
348  if(frame_flags[det][frame] >= NO_ELLIPSE_INTERSECT)
349  {
350  for(ind = 0; ind < 3; ind++)
351  ecr_frame_position[det][frame][ind] = GEO_DOUBLE_FILLVALUE;
352  continue;
353  }
354 
355  for(ind = 0; ind < 3; ind++)
356  posecr[ind] = ecr_frame_position[det][frame][ind];
357 
358  if(PGS_CSC_ECRtoGEO(posecr, EARTH_MODEL, &longitude, &latitude,
359  &altitude) != PGS_S_SUCCESS)
360  {
361  frame_flags[det][frame] = INVALID_INPUT_DATA;
362  continue;
363  }
364 
365  terrain_frame_position[det][frame][LAT_IDX] = latitude;
366  terrain_frame_position[det][frame][LON_IDX] = longitude;
367 
368  /* Note that the altitude of the weighted average ECR position will
369  * be systematically biased on the order of 0.1 m lower than the
370  * average height, due to the curvature of the earth. Therefore we
371  * use the average height.
372  */
373  terrain_frame_position[det][frame][HT_IDX] = height;
374 
375  /* Which means we need to correct the ECR coordinates: */
376  if(PGS_CSC_GEOtoECR(longitude, latitude, height, EARTH_MODEL,
377  posecr) != PGS_S_SUCCESS)
378  {
379  frame_flags[det][frame] = INVALID_INPUT_DATA;
380  continue;
381  }
382 
383  for(ind = 0; ind < 3; ind++)
384  ecr_frame_position[det][frame][ind] = posecr[ind];
385 
386  /* Convert to height above geoid. */
387  terrain_frame_position[det][frame][HT_IDX]
389  /* Note: can only get here if GEO_read_DEM() has already
390  * successfully called GEO_get_geoid(). Therefore, this call
391  * is guaranteed to not return BAD_GEOID.
392  */
393  }
394  }
395 
396  /* Set coastlines for frame_landsea. */
397  for(frame = 0; frame < EV_frames; frame++)
398  {
399  int det;
400 
401  for(det = 0; det < DETECTORS_1KM; det++)
402  {
403  if(frame_landsea[det][frame] == DRYLAND)
404  {
405  int min_det = det - 1;
406  int max_det = det + 2;
407  int min_frame = frame - 1;
408  int max_frame = frame + 2;
409  int d;
410 
411  if(min_det < 0)
412  min_det = 0;
413  else if(max_det > DETECTORS_1KM)
414  max_det = DETECTORS_1KM;
415  if(min_frame < 0)
416  min_frame = 0;
417  else if(max_frame > EV_frames)
418  max_frame = EV_frames;
419 
420  for(d=min_det; d<max_det; d++)
421  {
422  int f;
423 
424  for(f=min_frame; f<max_frame; f++)
425  {
426  if(frame_waterpresent[d][f])
427  {
428  frame_landsea[det][frame] = COAST;
429  break;
430  }
431  }
432  if(f<max_frame)
433  break; /* the pixel is coastal. */
434  }
435  }
436  }
437  }
438 
439 
440  /* Fix up frame flags for internal consistency */
441  for(frame=0; frame<EV_frames; frame++)
442  {
443  for(efat=EPH_IDX; efat<QFL_IDXS; efat++)
444  {
445  if(frame_quality[efat][frame] & (uint32)PGSd_NO_DATA)
446  frame_quality[efat][frame] = (uint32)PGSd_NO_DATA;
447 
448  if(frame_quality[efat][frame] & EPH_LONG_PRECEED)
449  frame_quality[efat][frame] &= ~EPH_SHORT_PRECEED;
450 
451  if(frame_quality[efat][frame] & EPH_LONG_FOLLOW)
452  frame_quality[efat][frame] &= ~EPH_SHORT_FOLLOW;
453  }
454  }
455 
456  if(N_samp > 1 && GEO_hires(N_samp, N_samp * EV_frames + N_samp - 1,
457  hires_scale, terrain_sample_position, ecr_sample_position,
458  ecr_frame_position, sample_flags, frame_flags, hires_offsets)
459  != PGS_S_SUCCESS)
460  {
461  sprintf(msgbuf, "GEO_hires(%d, %d, %f)", (int)N_samp,
462  (int)(N_samp * EV_frames + N_samp - 1), hires_scale);
463  modsmf(MODIS_E_GEO, msgbuf, filefunc);
464 
465  return MODIS_E_GEO;
466  }
467 
468  return PGS_S_SUCCESS;
469 }
@ SHALLOW_OCEAN
Definition: GEO_geo.h:128
PGSt_SMF_status GEO_aggregate(int32 EV_frames, uint16 N_samp, double hires_scale, unsigned char sample_flags[][MAX_PADDED], double ecr_sample_position[][MAX_PADDED][3], double ecr_sc_sample_position[][3], double terrain_sample_position[][MAX_PADDED][3], uint32 sample_quality[][QFL_IDXS], uint8 sample_landsea[][MAX_PADDED], double ecr_frame_position[][MAX_FRAMES][3], double terrain_frame_position[][MAX_FRAMES][3], uint8 frame_flags[][MAX_FRAMES], double ecr_sc_frame_position[MAX_FRAMES][3], int8 hires_offsets[][DETECTORS_QKM][SAMPLES_QKM], uint32 frame_quality[][MAX_FRAMES], uint8 frame_landsea[][MAX_FRAMES], uint8 frame_waterpresent[][MAX_FRAMES])
@ SHALLOW_INLAND
Definition: GEO_geo.h:128
@ NUM_LWMASK
Definition: GEO_geo.h:129
real(single), dimension(:,:), allocatable longitude
@ CONTINENTAL
Definition: GEO_geo.h:129
#define MODIS_E_BAD_INPUT_ARG
#define MAX_FRAMES
Definition: GEO_geo.h:79
@ DRYLAND
Definition: GEO_geo.h:128
const unsigned char NO_ELLIPSE_INTERSECT
#define EPH_LONG_FOLLOW
Definition: GEO_product.h:203
real(single), dimension(:,:), allocatable latitude
#define MAX_PADDED
Definition: GEO_geo.h:84
@ HT_IDX
@ DEEP_OCEAN
Definition: GEO_geo.h:129
#define MODIS_E_GEO
#define GEO_DOUBLE_FILLVALUE
Definition: GEO_output.h:106
@ DEEP_INLAND
Definition: GEO_geo.h:128
double precision function f(R1)
Definition: tmd.lp.f:1454
@ EPHEMERAL
Definition: GEO_geo.h:128
#define EPH_SHORT_FOLLOW
Definition: GEO_product.h:204
#define DETECTORS_1KM
Definition: GEO_geo.h:85
@ LON_IDX
#define EPH_SHORT_PRECEED
Definition: GEO_product.h:205
#define EARTH_MODEL
Definition: GEO_earth.h:118
@ LAT_IDX
@ COAST
Definition: GEO_geo.h:128
int GEO_get_geoid(double latitude, double longitude)
Definition: GEO_get_geoid.c:10
@ QFL_IDXS
subroutine water(twat, pdv, watr, ppod, ht, nm, ndv, tauw)
Definition: afrt_rt1.f:1168
@ EPH_IDX
#define EPH_LONG_PRECEED
Definition: GEO_product.h:206
const unsigned char INVALID_INPUT_DATA
PGSt_SMF_status GEO_hires(uint16 N_samp, int padded_samples, double hires_scale, double terrain_sample_position[][MAX_PADDED][3], double ecr_sample_position[][MAX_PADDED][3], double ecr_frame_position[][MAX_FRAMES][3], uint8 sample_flags[][MAX_PADDED], uint8 frame_flags[][MAX_FRAMES], int8 hires_offsets[][DETECTORS_QKM][SAMPLES_QKM])
Definition: GEO_hires.c:205
#define SAMPLES_QKM
Definition: GEO_geo.h:83
#define DETECTORS_QKM
Definition: GEO_geo.h:87